<template>
|
<el-dialog
|
title="当天分时行情K线设置"
|
:close-on-click-modal="false"
|
:visible.sync="visible"
|
width="1200px"
|
@close="handClose"
|
>
|
<el-form
|
:model="dataForm"
|
:rules="dataRule"
|
ref="dataForm"
|
@keyup.enter.native="dataFormSubmit()"
|
label-width="120px"
|
>
|
<el-form-item prop="">
|
<div class="green">请先生成K线,才能保存行情配置</div>
|
</el-form-item>
|
|
<el-row>
|
<el-col :span="7">
|
<el-form-item label="开始时间" prop="openTimeTs">
|
<el-date-picker
|
v-model="dataForm.openTimeTs"
|
type="date"
|
value-format="yyyy-MM-dd"
|
:picker-options="startPickerOptions"
|
@change="handleStartTimeChange"
|
placeholder="选择日期时间"
|
>
|
</el-date-picker>
|
</el-form-item>
|
</el-col>
|
<el-col :span="7">
|
<el-form-item label="结束时间" prop="closeTimeTs">
|
<el-date-picker
|
v-model="dataForm.closeTimeTs"
|
disabled
|
type="date"
|
value-format="yyyy-MM-dd"
|
:picker-options="endPickerOptions"
|
placeholder="选择日期时间"
|
>
|
</el-date-picker>
|
</el-form-item>
|
</el-col>
|
<el-col :span="5">
|
<el-form-item label="交易对" prop="symbol">
|
<el-select
|
v-model="options.symbol"
|
placeholder="请选择"
|
@change="changeVal()"
|
>
|
<el-option
|
v-for="item in options"
|
:key="item.symbol"
|
:label="item.symbol"
|
:value="item.symbol"
|
>
|
</el-option>
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="5">
|
<el-form-item label="">
|
<el-button type="primary" @click="dataFormSubmitOne()"
|
>生成K线</el-button
|
>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row>
|
<el-col :span="7">
|
<el-form-item label="今日开盘价" prop="openPrice">
|
<el-input
|
v-model="dataForm.openPrice"
|
placeholder="今日开盘价"
|
></el-input>
|
</el-form-item>
|
</el-col>
|
<el-col :span="7">
|
<el-form-item label="今日收盘价" prop="closePrice">
|
<el-input
|
v-model="dataForm.closePrice"
|
placeholder="今日收盘价"
|
></el-input>
|
</el-form-item>
|
</el-col>
|
<el-col :span="5">
|
<el-form-item label="控盘策略">
|
<el-select
|
v-model="langug.value"
|
placeholder="请选择"
|
@change="changeVal()"
|
>
|
<el-option
|
v-for="item in langug"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
>
|
</el-option>
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row>
|
<el-col :span="7">
|
<el-form-item label="今日最低价格" prop="low">
|
<el-input
|
v-model="dataForm.low"
|
placeholder="今日最低价格"
|
></el-input>
|
</el-form-item>
|
</el-col>
|
<el-col :span="7">
|
<el-form-item label="今日最高价格" prop="high">
|
<el-input
|
v-model="dataForm.high"
|
placeholder="今日最高价格"
|
></el-input>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row>
|
<el-col :span="5">
|
<el-form-item label="今日总成交量" prop="turnoverLow">
|
<el-input
|
v-model="dataForm.turnoverLow"
|
placeholder="最低"
|
></el-input>
|
</el-form-item>
|
</el-col>
|
<el-col :span="1">
|
<el-form-item label="" prop="">
|
<el-input disabled placeholder="~" class="spann"></el-input>
|
</el-form-item>
|
</el-col>
|
<el-col :span="5">
|
<el-form-item label="" prop="turnoverHigh">
|
<el-input
|
v-model="dataForm.turnoverHigh"
|
placeholder="最高"
|
></el-input>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-form-item label="" prop="">
|
<el-button @click="visible = false">取消</el-button>
|
<el-button type="primary" v-if="isShow" @click="dataFormSubmit()"
|
>保存</el-button
|
>
|
</el-form-item>
|
</el-form>
|
|
<div class="mod-subscribe-general">
|
<avue-crud
|
ref="crud"
|
:page.sync="page"
|
:data="dataList"
|
:option="tableOption"
|
@on-load="getDataList"
|
>
|
<!-- <template slot="menuLeft">
|
<el-button
|
type="primary"
|
icon="el-icon-plus"
|
size="small"
|
v-if="isAuth('sys:user:save')"
|
@click.stop="addOrUpdateHandle(options)"
|
>新增</el-button
|
>
|
</template> -->
|
<template slot-scope="scope" slot="openTimeTss">
|
<span>{{ formatTimestamm(scope.row.openTimeTs) }}</span>
|
</template>
|
<template slot-scope="scope" slot="closeTimeTss">
|
<span>{{ formatTimestamm(scope.row.closeTimeTs) }}</span>
|
</template>
|
<template slot-scope="scope" slot="menu">
|
<!-- <el-button
|
type="primary"
|
icon="el-icon-edit"
|
size="small"
|
v-if="isAuth('sys:user:delete')"
|
@click.stop="addOrUpdateHandle(options,scope.row)"
|
>编辑</el-button
|
> -->
|
<el-button
|
type="danger"
|
icon="el-icon-delete"
|
size="small"
|
@click.stop="deleteHandle(scope.row.uuid)"
|
>删除</el-button
|
>
|
</template>
|
</avue-crud>
|
<!-- 新增删除 -->
|
<linKeAdd
|
v-if="linKeAddVisible"
|
ref="linKeAdd"
|
@refreshDataList="getDataList"
|
></linKeAdd>
|
</div>
|
<echarts ref="addOrUpdate"> </echarts>
|
<span slot="footer" class="dialog-footer">
|
<el-button @click="visible = false">取消</el-button>
|
<el-button type="primary" @click="visible = false">确定</el-button>
|
</span>
|
</el-dialog>
|
</template>
|
|
<script>
|
import { tableOption } from "@/crud/etf-spots/market-linek";
|
import linKeAdd from "./linKen-add-or-undata";
|
import { treeDataTranslate } from "@/utils";
|
import { Debounce } from "@/utils/debounce";
|
import { encrypt } from "@/utils/crypto";
|
import echarts from "./echats_One.vue";
|
export default {
|
data() {
|
return {
|
visible: false,
|
linKeAddVisible: false,
|
menuList: [],
|
dateRange: [],
|
isShow: false,
|
menuListTreeProps: {
|
label: "name",
|
children: "children",
|
},
|
startPickerOptions: {
|
disabledDate: this.disabledStartDate, // 禁用不满足条件的开始日期
|
disabledHours: this.disabledStartHours, // 禁用不满足条件的开始小时
|
disabledMinutes: this.disabledStartMinutes, // 禁用不满足条件的开始分钟
|
shortcuts: [
|
{
|
text: "明天",
|
onClick: () => {
|
const tomorrow = new Date();
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
tomorrow.setHours(4, 0, 0, 0);
|
this.dataForm.openTimeTs = tomorrow;
|
this.handleStartTimeChange();
|
},
|
},
|
],
|
},
|
endPickerOptions: {
|
disabledDate: this.disabledEndDate, // 禁用不满足条件的结束日期
|
},
|
tableOption: tableOption,
|
page: {
|
total: 0, // 总页数
|
currentPage: 1, // 当前页数
|
pageSize: 10, // 每页显示多少条
|
},
|
dataList: [],
|
row: "", //forex->外汇,commodities->大宗商品,指数/ETF->indices, A-stocks->A股, HK-stocks->港股.US-stocks->美股,cryptos->虚拟货币
|
options: [],
|
linArr: [], //K线数组
|
timeArr: [],
|
langug: [
|
{
|
label: "跟随大盘",
|
value: "1",
|
},
|
{
|
label: "自定义趋势",
|
value: "2",
|
},
|
], // 控盘策略
|
dataForm: {
|
closePrice: "",
|
closeTimeTs: "",
|
createBy: "",
|
createDate: "",
|
createTime: "",
|
high: "",
|
low: "",
|
openPrice: "",
|
openTimeTs: "",
|
robot_model_uuid: "",
|
strategy: "",
|
symbol: "",
|
turnoverHigh: "",
|
turnoverLow: "",
|
updateBy: "",
|
updateDate: "",
|
updateTime: "",
|
uuid: "",
|
},
|
dataRule: {
|
openTimeTs: [
|
{ required: true, message: "开始时间不能为空", trigger: "blur" },
|
],
|
closeTimeTs: [
|
{ required: true, message: "结束时间不能为空", trigger: "blur" },
|
],
|
openPrice: [
|
{ required: true, message: "今日开盘价不能为空", trigger: "blur" },
|
],
|
closePrice: [
|
{ required: true, message: "今日收盘价不能为空", trigger: "blur" },
|
],
|
low: [
|
{ required: true, message: "今日最低价不能为空", trigger: "blur" },
|
],
|
high: [
|
{ required: true, message: "今日最高价不能为空", trigger: "blur" },
|
],
|
turnoverLow: [
|
{ required: true, message: "最低不能为空", trigger: "blur" },
|
],
|
turnoverHigh: [
|
{ required: true, message: "最高不能为空", trigger: "blur" },
|
],
|
quoteCurrency: [
|
{ required: true, message: "结算币种不能为空", trigger: "blur" },
|
],
|
unitFee: [
|
{ required: true, message: "手续费不能为空", trigger: "blur" },
|
],
|
// sorted: [{ required: true, message: "排序不能为空", trigger: "blur" }],
|
// sorted: [{ required: true, message: "排序不能为空", trigger: "blur" }],
|
// sorted: [{ required: true, message: "排序不能为空", trigger: "blur" }],
|
},
|
tempKey: -666666, // 临时key, 用于解决tree半选中状态项不能传给后台接口问题. # 待优化
|
};
|
},
|
components: {
|
echarts,
|
linKeAdd,
|
},
|
methods: {
|
init(arr) {
|
this.options = arr || [];
|
this.options.symbol = this.options[0].symbol;
|
this.langug.value = this.langug[0].value;
|
this.visible = true;
|
},
|
changeVal(val) {
|
this.$forceUpdate();
|
},
|
addOrUpdateHandle(arr, row) {
|
this.linKeAddVisible = true;
|
this.$nextTick(() => {
|
this.$refs.linKeAdd.init(arr, row);
|
});
|
},
|
disabledStartDate(time) {
|
const today = new Date();
|
today.setHours(0, 0, 0, 0);
|
return time.getTime() <= today.getTime(); // 开始时间只能选择明天及以后的日期
|
},
|
disabledStartHours() {
|
const currentHour = new Date().getHours();
|
return Array.from({ length: 24 }, (_, i) => i).filter(
|
(hour) => hour < 4 || hour > 21 || (hour === 21 && currentHour >= 30) // 开始时间的小时部分只能选择凌晨4点到晚上21点半
|
);
|
},
|
disabledStartMinutes(hour) {
|
const currentHour = new Date().getHours();
|
if (hour === 4 && currentHour < 30) {
|
// 如果选择的小时是4点且当前小时小于30,则禁用分钟选择
|
return Array.from({ length: 60 }, (_, i) => i).filter(
|
(minute) => minute !== 0
|
);
|
} else if (hour === 21 && currentHour >= 30) {
|
// 如果选择的小时是21点且当前小时大于等于30,则禁用分钟选择
|
return Array.from({ length: 60 }, (_, i) => i).filter(
|
(minute) => minute !== 0
|
);
|
} else {
|
// 其他情况不禁用分钟选择
|
return [];
|
}
|
},
|
disabledEndDate(time) {
|
return true; // 禁用结束时间选择
|
},
|
handleStartTimeChange() {
|
// 设置默认的结束时间为开始时间的后一天
|
const startDate = new Date(this.dataForm.openTimeTs);
|
const endDate = new Date(startDate.getTime() + 8.64e7); // 一天的毫秒数
|
this.dataForm.closeTimeTs = endDate;
|
},
|
handClose() {
|
this.$data.dataForm = JSON.parse(
|
JSON.stringify(this.$options.data().dataForm)
|
);
|
this.$nextTick(() => {
|
this.$refs["dataForm"].clearValidate(); // 清除表单验证
|
});
|
this.langug.value = "";
|
this.options.value = "";
|
this.isShow = false;
|
},
|
// 删除
|
deleteHandle(id) {
|
var ids = id
|
? [id]
|
: this.dataListSelections.map((item) => {
|
return item.orderId;
|
});
|
this.$confirm(`确定进行[${id ? "删除" : "批量删除"}]操作?`, "提示", {
|
confirmButtonText: "确定",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(() => {
|
this.$http({
|
url: this.$http.adornUrl(`/etf/klineConfig/delete?ids=` + ids),
|
method: "delete",
|
data: this.$http.adornData(ids, false),
|
}).then(({ data }) => {
|
this.$message({
|
message: "操作成功",
|
type: "success",
|
duration: 1500,
|
onClose: () => {
|
this.getDataList(this.page);
|
},
|
});
|
});
|
})
|
.catch(() => {});
|
},
|
// 获取数据列表
|
getDataList(page, params, done) {
|
this.dataListLoading = true;
|
this.$http({
|
url: this.$http.adornUrl("/etf/klineConfig/pageList"),
|
method: "get",
|
params: this.$http.adornParams(
|
Object.assign(
|
{
|
type: "indices", //type:'forex', //forex->外汇,commodities->大宗商品,指数/ETF->indices, A-stocks->A股, HK-stocks->港股.US-stocks->美股,cryptos->虚拟货币
|
// itemId: this.dataForm.id,
|
current: page == null ? this.page.currentPage : page.currentPage,
|
size: page == null ? this.page.pageSize : page.pageSize,
|
},
|
params
|
)
|
),
|
}).then(({ data }) => {
|
if (data.code == 0) {
|
console.log("data => " + data);
|
this.dataList = data.data.records;
|
this.page.total = data.data.total;
|
} else {
|
this.$message({
|
message: data.msg,
|
type: "error",
|
duration: 1000,
|
onClose: () => {},
|
});
|
}
|
|
this.dataListLoading = false;
|
if (done) {
|
done();
|
}
|
});
|
},
|
|
formatTimestamp(timestamp) {
|
const date = new Date(timestamp);
|
const year = date.getFullYear();
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
const day = String(date.getDate()).padStart(2, "0");
|
const hours = String(date.getHours()).padStart(2, "0");
|
const minutes = String(date.getMinutes()).padStart(2, "0");
|
const seconds = String(date.getSeconds()).padStart(2, "0");
|
const milliseconds = String(date.getMilliseconds()).padStart(3, "0");
|
|
const formattedDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds} ${milliseconds}`;
|
return formattedDate;
|
},
|
formatTimestamm(timestamp) {
|
const date = new Date(timestamp);
|
const year = date.getFullYear();
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
const day = String(date.getDate()).padStart(2, "0");
|
const hours = String(date.getHours()).padStart(2, "0");
|
const minutes = String(date.getMinutes()).padStart(2, "0");
|
const seconds = String(date.getSeconds()).padStart(2, "0");
|
const milliseconds = String(date.getMilliseconds()).padStart(3, "0");
|
|
const formattedDate = `${year}-${month}-${day}`;
|
return formattedDate;
|
},
|
// K线
|
dataFormSubmitOne: Debounce(function () {
|
this.$refs["dataForm"].validate((valid) => {
|
let a = new Date(this.dataForm.openTimeTs);
|
let b = new Date(this.dataForm.closeTimeTs);
|
let aa = a.getTime();
|
let bb = b.getTime();
|
if (valid) {
|
this.$http({
|
// 生成K线
|
url: this.$http.adornUrl(`/etf/klineConfig/init`),
|
method: "post",
|
data: this.$http.adornData({
|
closePrice: this.dataForm.closePrice,
|
// closeTimeTs: bb,
|
high: this.dataForm.high,
|
low: this.dataForm.low,
|
openPrice: this.dataForm.openPrice,
|
openTimeTs: aa,
|
symbol: this.options.symbol,
|
turnoverHigh: this.dataForm.turnoverHigh,
|
turnoverLow: this.dataForm.turnoverLow,
|
strategy: this.langug.value,
|
// uuid: ""
|
}),
|
}).then(({ data }) => {
|
if (data.code == 0) {
|
this.dataForm.uuid = data.data.modelId;
|
this.timeArr = Object.values(
|
data.data.klineList.reduce((res, item) => {
|
//res[item.ts] = [item.ts];
|
res[item.ts] = [this.formatTimestamp(item.ts)];
|
return res;
|
}, [])
|
);
|
this.linArr = Object.values(
|
data.data.klineList.reduce((res, item) => {
|
let arr = [item.open, item.close, item.low, item.high];
|
res.push(arr);
|
return res;
|
}, [])
|
);
|
this.$nextTick(() => {
|
this.$refs.addOrUpdate.init(this.timeArr, this.linArr);
|
});
|
this.$message({
|
message: "操作成功",
|
type: "success",
|
duration: 1500,
|
onClose: () => {},
|
});
|
this.isShow = true;
|
} else {
|
this.$message({
|
message: data.msg,
|
type: "error",
|
duration: 1500,
|
onClose: () => {},
|
});
|
}
|
});
|
}
|
});
|
}),
|
|
// 表单提交
|
dataFormSubmit: Debounce(function () {
|
this.$refs["dataForm"].validate((valid) => {
|
let a = new Date(this.dataForm.openTimeTs);
|
let b = new Date(this.dataForm.closeTimeTs);
|
let aa = a.getTime();
|
let bb = b.getTime();
|
if (valid) {
|
this.$http({
|
// 修改
|
url: this.$http.adornUrl(`/etf/klineConfig/save`),
|
method: "post",
|
data: this.$http.adornData({
|
closePrice: this.dataForm.closePrice,
|
// closeTimeTs: bb,
|
high: this.dataForm.high,
|
low: this.dataForm.low,
|
openPrice: this.dataForm.openPrice,
|
openTimeTs: aa,
|
symbol: this.options.symbol,
|
turnoverHigh: this.dataForm.turnoverHigh,
|
turnoverLow: this.dataForm.turnoverLow,
|
strategy: this.langug.value,
|
robot_model_uuid: this.dataForm.uuid,
|
}),
|
}).then(({ data }) => {
|
if (data.code == 0) {
|
this.$message({
|
message: "操作成功",
|
type: "success",
|
duration: 1500,
|
onClose: () => {
|
this.getDataList();
|
this.$emit("refreshDataList");
|
},
|
});
|
} else {
|
this.$message({
|
message: data.msg,
|
type: "error",
|
duration: 1500,
|
onClose: () => {},
|
});
|
}
|
});
|
}
|
});
|
}),
|
},
|
};
|
</script>
|
<style scoped>
|
.spann {
|
width: 40px;
|
margin-left: -60px;
|
}
|
</style>
|