st-comp 0.0.21 → 0.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,533 +1,539 @@
1
1
  <!-- 单品种多周期K线组件-Demo -->
2
2
  <script setup lang="ts">
3
- import { RefreshRight } from '@element-plus/icons-vue'
4
- import { ref, onMounted, onUnmounted, watch } from 'vue'
5
- import dayjs from 'dayjs'
6
- import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'
7
- import { ElMessage } from 'element-plus'
8
- import 'element-plus/dist/index.css'
9
- import { formatValue } from '../../../../packages/Kline/utils'
10
- import { getSingleCycleSingleVariety, getDict } from '../api.ts'
11
- import { mainIndicatorList } from 'st-func'
3
+ import { RefreshRight } from "@element-plus/icons-vue";
4
+ import { ref, onMounted, onUnmounted, watch } from "vue";
5
+ import dayjs from "dayjs";
6
+ import isSameOrAfter from "dayjs/plugin/isSameOrAfter";
7
+ import { ElMessage } from "element-plus";
8
+ import "element-plus/dist/index.css";
9
+ import { formatValue } from "../../../../packages/Kline/utils";
10
+ import { getSingleCycleSingleVariety, getDict } from "../api.ts";
11
+ import { mainIndicatorList } from "st-func";
12
12
 
13
- dayjs.extend(isSameOrAfter)
13
+ dayjs.extend(isSameOrAfter);
14
14
 
15
- const props = defineProps({
16
- deBugValue: {
17
- type: Number,
18
- },
19
- })
15
+ const props = defineProps({
16
+ deBugValue: {
17
+ type: Number,
18
+ },
19
+ });
20
20
 
21
- // K线组件数组[多周期]
22
- interface multiCycleKlineType {
23
- loading: boolean
24
- cycle: string // 周期
25
- cycleName: string // 周期名称
26
- sellBuyType: number // 开平/买卖类型
27
- sellBuyTypeName: string // 开平/买卖
28
- klineData: any[] // K线接口数据
29
- markData: any[] // 点位接口数据
30
- netWorkErrorMsg: string
31
- indicatorName: string
32
- indicator: object
33
- }
34
- const multiCycleKline = ref<multiCycleKlineType[]>([])
21
+ // K线组件数组[多周期]
22
+ interface multiCycleKlineType {
23
+ loading: boolean;
24
+ isSelect: boolean;
25
+ cycle: string; // 周期
26
+ cycleName: string; // 周期名称
27
+ sellBuyType: number; // 开平/买卖类型
28
+ sellBuyTypeName: string; // 开平/买卖
29
+ klineData: any[]; // K线接口数据
30
+ markData: any[]; // 点位接口数据
31
+ netWorkErrorMsg: string;
32
+ indicatorName: string;
33
+ indicator: object;
34
+ }
35
+ const multiCycleKline = ref<multiCycleKlineType[]>([]);
35
36
 
36
- // 筛选条件相关参数
37
- const sellBuyTypeOptions = ref<any>([
38
- { label: '开平', value: 1 },
39
- { label: '买卖', value: 2 },
40
- ])
37
+ // 筛选条件相关参数
38
+ const sellBuyTypeOptions = ref<any>([
39
+ { label: "开平", value: 1 },
40
+ { label: "买卖", value: 2 },
41
+ ]);
41
42
 
42
- // 接口原生-点位数据
43
- const originPointData = ref<any>([])
43
+ // 接口原生-点位数据
44
+ const originPointData = ref<any>([]);
44
45
 
45
- // K线组件统一入参
46
- const lineData = ref<any>([])
47
- const brushRange = ref<any>(['2024-01-04 10:10:00', '2024-01-04 21:40:00'])
48
- const defaultMenuData = ref([
49
- {
50
- label: '画线预警',
51
- callBack: (echartsInstance: any, cursorPenVisible: any) => createWarning(echartsInstance, cursorPenVisible),
52
- },
53
- ])
54
- const config = ref({
55
- totalBarCount: 1900,
56
- preBarCount: 100,
57
- })
46
+ // K线组件统一入参
47
+ const lineData = ref<any>([]);
48
+ const brushRange = ref<any>(["2024-01-04 10:10:00", "2024-01-04 21:40:00"]);
49
+ const defaultMenuData = ref([
50
+ {
51
+ label: "画线预警",
52
+ callBack: (echartsInstance: any, cursorPenVisible: any) => createWarning(echartsInstance, cursorPenVisible),
53
+ },
54
+ ]);
55
+ const config = ref({
56
+ totalBarCount: 1900,
57
+ preBarCount: 100,
58
+ dynamicLoadConfig: {
59
+ historyVisible: false,
60
+ historyLoadCallBack: () => {},
61
+ futureVisible: false,
62
+ },
63
+ });
58
64
 
59
- onMounted(() => {
60
- console.log('---------单品种多周期组件: onMounted挂载成功---------')
61
- })
65
+ onMounted(() => {
66
+ console.log("---------单品种多周期组件: onMounted挂载成功---------");
67
+ });
62
68
 
63
- // 初始化
64
- const componentInit = async () => {
65
- try {
66
- await getDictCycle()
67
- await getKlineData()
68
- await getKlineExtendData()
69
- } catch (error) {
70
- console.log(error)
71
- }
69
+ // 初始化
70
+ const componentInit = async () => {
71
+ try {
72
+ await getDictCycle();
73
+ await getKlineData();
74
+ await getKlineExtendData();
75
+ } catch (error) {
76
+ console.log(error);
72
77
  }
78
+ };
73
79
 
74
- /**
75
- * @description: 获取通用字典[周期],初始化多周期结构
76
- */
77
- const getDictCycle = async () => {
78
- const params = {
79
- dictIds: [1002],
80
- }
81
- const res = await getDict(params)
82
- multiCycleKline.value = res.data.body[1002].map((item: any) => {
83
- return {
84
- loading: true,
85
- cycle: Number(item.dictCode),
86
- cycleName: item.dictName,
87
- sellBuyType: 1,
88
- sellBuyTypeName: '开平',
89
- klineData: [],
90
- markData: [],
91
- netWorkErrorMsg: '',
92
- indicator: mainIndicatorList.find((i: any) => i.value === 'DKX_EMA'),
93
- indicatorName: 'DKX_EMA',
94
- }
95
- })
96
- }
97
- /**
98
- * @description: 获取K线数据 / 点位数据
99
- */
100
- const getKlineData = async () => {
101
- multiCycleKline.value.forEach(async (item: any) => {
102
- item.loading = true
103
-
104
- // ---------K线数据逻辑----------
105
- const params = {
106
- right: 1, // 复权方式
107
- variety: 'au8888', // 品种
108
- cycle: item.cycle, // 周期
109
- endTime: '2024-01-04 23:59:59', // 结束时间
110
- limit: config.value.totalBarCount + config.value.preBarCount, // 总条数
111
- queryType: 1, // 0-按时间,1-按结束时间,2-按开始时间
112
- }
113
- const res = await getSingleCycleSingleVariety(params)
114
- item.klineData = res.data.body
115
- // ---------点位数据逻辑---------
116
- const resultApi = [
117
- {
118
- key: 'sellBuy',
119
- data: [
120
- {
121
- tradeAction: '开', // 交易动作
122
- direction: '多', // 交易方向
123
- tradeType: '开多', // 交易类型
124
- amount: 2, // 手数
125
- part: 2, // 份数
126
- time: '2024-01-04 22:30:00', // 交易时间
127
- tooltip: '<div>买卖点1</div>',
128
- },
129
- {
130
- tradeAction: '平', // 交易动作
131
- direction: '空', // 交易方向
132
- tradeType: '平空', // 交易类型
133
- amount: 2, // 手数
134
- part: 2, // 份数
135
- time: '2024-01-04 22:40:00', // 交易时间
136
- tooltip: '<div>买卖点2</div>',
137
- },
138
- {
139
- tradeAction: '开', // 交易动作
140
- direction: '空', // 交易方向
141
- tradeType: '开空', // 交易类型
142
- amount: 2, // 手数
143
- part: 2, // 份数
144
- time: '2024-01-04 23:50:00', // 交易时间
145
- tooltip: '<div>买卖点3</div>',
146
- },
147
- ],
148
- },
149
- {
150
- key: 'openClose',
151
- data: [
152
- {
153
- tradeAction: '开', // 交易动作
154
- direction: '多', // 交易方向
155
- tradeType: '开多', // 交易类型
156
- amount: 2, // 手数
157
- part: 2, // 份数
158
- time: '2024-01-04 22:30:00', // 交易时间
159
- tooltip: '<div>开平点1</div>',
160
- },
161
- {
162
- tradeAction: '平', // 交易动作
163
- direction: '空', // 交易方向
164
- tradeType: '平空', // 交易类型
165
- amount: 2, // 手数
166
- part: 2, // 份数
167
- time: '2024-01-04 22:40:00', // 交易时间
168
- tooltip: '<div>开平点2</div>',
169
- },
170
- {
171
- tradeAction: '开', // 交易动作
172
- direction: '空', // 交易方向
173
- tradeType: '开空', // 交易类型
174
- amount: 2, // 手数
175
- part: 2, // 份数
176
- time: '2024-01-04 23:50:00', // 交易时间
177
- tooltip: '<div>买卖点3</div>',
178
- },
179
- ],
180
- },
181
- {
182
- key: 'signal',
183
- data: [],
184
- },
185
- ]
186
- const klineTimeAry = item.klineData.map((item: any) => item[0])
187
- originPointData.value = resultApi.reduce((result: any, next) => {
188
- const { data } = next
189
- result.push({
190
- key: next.key,
191
- data: data.map((i: any) => {
192
- const time = klineTimeAry.find((klineTime: string) => dayjs(klineTime).isSameOrAfter(i.time))
193
- return {
194
- ...i,
195
- time,
196
- }
197
- }),
198
- })
199
- return result
200
- }, [])
201
- sellBuyTypeChange(item)
202
-
203
- item.loading = false
204
- })
205
- }
206
- /**
207
- * @description: 获取K线额外画线数据
208
- */
209
- const getKlineExtendData = async () => {
210
- lineData.value = [
211
- {
212
- key: 'warning',
213
- data: [
214
- {
215
- value: 479,
216
- text: 479,
217
- // 自定义信息
218
- info: {},
219
- // 自定义配置
220
- config: {
221
- draggable: true,
222
- },
223
- },
224
- ],
225
- ondragstart: (params: any, info: any) => {
226
- console.log('拖拽开始', params, info)
227
- },
228
- ondragend: (params: any, info: any, yAxisValue: number) => {
229
- console.log('拖拽结束', params, info, yAxisValue)
230
- ElMessage.success('预警线修改更新成功!')
231
- },
232
- oncontextmenu: (params: any, info: any, menuData: any) => {
233
- console.log('右击了', params, info)
234
- menuData.value = [
235
- {
236
- label: '删除画线',
237
- callBack: () => ElMessage.success('预警线删除成功!'),
238
- },
239
- {
240
- label: '修改画线',
241
- callBack: () => ElMessage.success('预警线修改成功!'),
242
- },
243
- ]
244
- },
245
- },
246
- {
247
- key: 'position',
248
- data: [
249
- {
250
- value: 480,
251
- text: '持仓:192.14万(1份) 数量:4手 方向:多 浮动盈亏:-1280.00',
252
- // 自定义信息
253
- info: {},
254
- // 自定义配置
255
- config: {},
256
- },
257
- ],
258
- },
259
- {
260
- key: 'condition',
261
- data: [
262
- {
263
- value: 482,
264
- text: '[多损][多盈] 开多↓2269 1份(22手)',
265
- profitValue: 483,
266
- profitText: '上破484',
267
- lossValue: 481,
268
- lossText: '下破482',
269
- // 自定义信息
270
- info: {},
271
- // 自定义配置
272
- config: {},
273
- },
274
- ],
275
- },
276
- ]
277
- }
278
- /**
279
- * @description: 买卖点,开平点切换
280
- */
281
- const sellBuyTypeChange = (item: any) => {
282
- if (sellBuyTypeOptions.value.length > 0) {
283
- item.sellBuyTypeName = sellBuyTypeOptions.value.find((i: any) => i.value === item.sellBuyType).label ?? null
284
- }
285
- if (item.sellBuyType === 1) {
286
- item.markData = originPointData.value.filter((i: any) => {
287
- return i.key !== 'sellBuy'
288
- })
289
- } else {
290
- item.markData = originPointData.value.filter((i: any) => {
291
- return i.key !== 'openClose'
292
- })
293
- }
294
- }
295
- /**
296
- * @description: 切换指标
297
- */
298
- const indicatorChange = (item: any) => {
299
- item.indicator = mainIndicatorList.find((i: any) => i.value === item.indicatorName)
300
- }
301
-
302
- // 画线预警
303
- const createWarning = (echartsInstance: any, cursorPenVisible: any) => {
304
- // 1.打开画笔模式,并修改指示器样式[画预览线]
305
- cursorPenVisible.value = true
306
- const echartsOptions = echartsInstance.getOption()
307
- const oldTooltip = (echartsOptions.tooltip as Array<any>)[0]
308
- echartsInstance.setOption({
309
- ...echartsOptions,
310
- // 指示器样式
311
- tooltip: {
312
- ...oldTooltip,
313
- // 坐标轴指示器
314
- axisPointer: {
315
- // 保留原有部分配置
316
- ...oldTooltip.axisPointer,
317
- // X轴指示线的宽度
318
- lineStyle: {
319
- width: 0,
320
- },
321
- // Y轴指示线的宽度
322
- crossStyle: {
323
- width: 2,
324
- },
325
- // 文本标签
326
- label: {
327
- // 保留原有部分配置
328
- ...oldTooltip.axisPointer.label,
329
- // 颜色改为透明
330
- backgroundColor: 'transparent',
331
- // 仅显示Y轴值
332
- formatter: (data: any) => {
333
- const { axisDimension, value } = data
334
- if (axisDimension === 'y') {
335
- return String(formatValue(value))
336
- }
337
- return ''
338
- },
339
- },
340
- },
341
- },
342
- })
343
- // 2.获取当前列数据并发送请求至后端记录
344
- const handleClick = (el: any) => {
345
- // 关闭画笔模式,并移除echarts点击事件
346
- cursorPenVisible.value = false
347
- echartsInstance.getZr().off('mousedown', handleClick)
348
- const yAxisValue = echartsInstance.convertFromPixel({ yAxisIndex: 0 }, el.offsetY)
349
- const newWarnPrice = Math.round(yAxisValue * 1000) / 1000
350
- // 3.恢复指示器样式
351
- echartsInstance.setOption({
352
- ...echartsOptions,
353
- // 指示器样式
354
- tooltip: {
355
- ...oldTooltip,
356
- axisPointer: {
357
- ...oldTooltip.axisPointer,
358
- lineStyle: {
359
- width: 1,
360
- },
361
- crossStyle: {
362
- width: 1,
363
- },
364
- label: {
365
- ...oldTooltip.axisPointer.label,
366
- backgroundColor: null,
367
- },
368
- },
369
- },
370
- })
371
- // 4.发送保存预警线请求
372
- lineData.value[0].data.push({
373
- value: newWarnPrice,
374
- text: newWarnPrice,
375
- // 自定义信息
376
- info: {},
377
- // 自定义配置
378
- config: {
379
- draggable: true,
380
- },
381
- })
382
- ElMessage.success('画线预警成功!')
383
- }
384
- // 绑定echarts点击事件
385
- echartsInstance.getZr().on('mousedown', handleClick)
386
- }
387
-
388
- watch(
389
- () => props.deBugValue,
390
- (newValue: any) => {
391
- if (newValue === 1) {
392
- // 正常模式
393
- componentInit()
394
- } else {
395
- multiCycleKline.value.forEach((item: any) => {
396
- if (newValue === 2) {
397
- // 网络故障
398
- item.loading = true
399
- setTimeout(() => {
400
- item.netWorkErrorMsg = '网络加载失败,请刷新重试'
401
- item.loading = false
402
- }, 1000)
403
- } else if (newValue === 3) {
404
- // 空数据
405
- item.netWorkErrorMsg = ''
406
- item.loading = true
407
- setTimeout(() => {
408
- item.klineData = []
409
- item.loading = false
410
- }, 1000)
411
- }
412
- })
413
- }
414
- },
415
- {
416
- immediate: true,
417
- }
418
- )
419
-
420
- onUnmounted(() => {
421
- console.log('---------单品种多周期组件: onUnmounted卸载成功---------')
422
- })
423
-
424
- const reFresh = async (item: any) => {
425
- item.netWorkErrorMsg = ''
426
- item.loading = true
80
+ /**
81
+ * @description: 获取通用字典[周期],初始化多周期结构
82
+ */
83
+ const getDictCycle = async () => {
84
+ const params = {
85
+ dictIds: [1002],
86
+ };
87
+ const res = await getDict(params);
88
+ multiCycleKline.value = res.data.body[1002].map((item: any) => {
89
+ return {
90
+ loading: true,
91
+ cycle: Number(item.dictCode),
92
+ cycleName: item.dictName,
93
+ sellBuyType: 1,
94
+ sellBuyTypeName: "开平",
95
+ klineData: [],
96
+ markData: [],
97
+ netWorkErrorMsg: "",
98
+ indicator: mainIndicatorList.find((i: any) => i.value === "DKX_EMA"),
99
+ indicatorName: "DKX_EMA",
100
+ };
101
+ });
102
+ };
103
+ /**
104
+ * @description: 获取K线数据 / 点位数据
105
+ */
106
+ const getKlineData = async () => {
107
+ multiCycleKline.value.forEach(async (item: any) => {
108
+ item.loading = true;
427
109
 
428
110
  // ---------K线数据逻辑----------
429
111
  const params = {
430
112
  right: 1, // 复权方式
431
- variety: 'au8888', // 品种
113
+ variety: "au8888", // 品种
432
114
  cycle: item.cycle, // 周期
433
- endTime: '2024-01-04 23:59:59', // 结束时间
115
+ endTime: "2024-01-04 23:59:59", // 结束时间
434
116
  limit: config.value.totalBarCount + config.value.preBarCount, // 总条数
435
117
  queryType: 1, // 0-按时间,1-按结束时间,2-按开始时间
436
- }
437
- const res = await getSingleCycleSingleVariety(params)
438
- item.klineData = res.data.body
118
+ };
119
+ const res = await getSingleCycleSingleVariety(params);
120
+ item.klineData = res.data.body;
439
121
  // ---------点位数据逻辑---------
440
122
  const resultApi = [
441
123
  {
442
- key: 'sellBuy',
124
+ key: "sellBuy",
443
125
  data: [
444
126
  {
445
- tradeAction: '', // 交易动作
446
- direction: '', // 交易方向
447
- tradeType: '开多', // 交易类型
127
+ tradeAction: "", // 交易动作
128
+ direction: "", // 交易方向
129
+ tradeType: "开多", // 交易类型
448
130
  amount: 2, // 手数
449
131
  part: 2, // 份数
450
- time: '2024-01-04 22:30:00', // 交易时间
451
- tooltip: '<div>买卖点1</div>',
132
+ time: "2024-01-04 22:30:00", // 交易时间
133
+ tooltip: "<div>买卖点1</div>",
452
134
  },
453
135
  {
454
- tradeAction: '', // 交易动作
455
- direction: '', // 交易方向
456
- tradeType: '平空', // 交易类型
136
+ tradeAction: "", // 交易动作
137
+ direction: "", // 交易方向
138
+ tradeType: "平空", // 交易类型
457
139
  amount: 2, // 手数
458
140
  part: 2, // 份数
459
- time: '2024-01-04 22:40:00', // 交易时间
460
- tooltip: '<div>买卖点2</div>',
141
+ time: "2024-01-04 22:40:00", // 交易时间
142
+ tooltip: "<div>买卖点2</div>",
461
143
  },
462
144
  {
463
- tradeAction: '', // 交易动作
464
- direction: '', // 交易方向
465
- tradeType: '开空', // 交易类型
145
+ tradeAction: "", // 交易动作
146
+ direction: "", // 交易方向
147
+ tradeType: "开空", // 交易类型
466
148
  amount: 2, // 手数
467
149
  part: 2, // 份数
468
- time: '2024-01-04 23:50:00', // 交易时间
469
- tooltip: '<div>买卖点3</div>',
150
+ time: "2024-01-04 23:50:00", // 交易时间
151
+ tooltip: "<div>买卖点3</div>",
470
152
  },
471
153
  ],
472
154
  },
473
155
  {
474
- key: 'openClose',
156
+ key: "openClose",
475
157
  data: [
476
158
  {
477
- tradeAction: '', // 交易动作
478
- direction: '', // 交易方向
479
- tradeType: '开多', // 交易类型
159
+ tradeAction: "", // 交易动作
160
+ direction: "", // 交易方向
161
+ tradeType: "开多", // 交易类型
480
162
  amount: 2, // 手数
481
163
  part: 2, // 份数
482
- time: '2024-01-04 22:30:00', // 交易时间
483
- tooltip: '<div>开平点1</div>',
164
+ time: "2024-01-04 22:30:00", // 交易时间
165
+ tooltip: "<div>开平点1</div>",
484
166
  },
485
167
  {
486
- tradeAction: '', // 交易动作
487
- direction: '', // 交易方向
488
- tradeType: '平空', // 交易类型
168
+ tradeAction: "", // 交易动作
169
+ direction: "", // 交易方向
170
+ tradeType: "平空", // 交易类型
489
171
  amount: 2, // 手数
490
172
  part: 2, // 份数
491
- time: '2024-01-04 22:40:00', // 交易时间
492
- tooltip: '<div>开平点2</div>',
173
+ time: "2024-01-04 22:40:00", // 交易时间
174
+ tooltip: "<div>开平点2</div>",
493
175
  },
494
176
  {
495
- tradeAction: '', // 交易动作
496
- direction: '', // 交易方向
497
- tradeType: '开空', // 交易类型
177
+ tradeAction: "", // 交易动作
178
+ direction: "", // 交易方向
179
+ tradeType: "开空", // 交易类型
498
180
  amount: 2, // 手数
499
181
  part: 2, // 份数
500
- time: '2024-01-04 23:50:00', // 交易时间
501
- tooltip: '<div>买卖点3</div>',
182
+ time: "2024-01-04 23:50:00", // 交易时间
183
+ tooltip: "<div>买卖点3</div>",
502
184
  },
503
185
  ],
504
186
  },
505
187
  {
506
- key: 'signal',
188
+ key: "signal",
507
189
  data: [],
508
190
  },
509
- ]
510
- const klineTimeAry = item.klineData.map((item: any) => item[0])
191
+ ];
192
+ const klineTimeAry = item.klineData.map((item: any) => item[0]);
511
193
  originPointData.value = resultApi.reduce((result: any, next) => {
512
- const { data } = next
194
+ const { data } = next;
513
195
  result.push({
514
196
  key: next.key,
515
197
  data: data.map((i: any) => {
516
- const time = klineTimeAry.find((klineTime: string) => dayjs(klineTime).isSameOrAfter(i.time))
198
+ const time = klineTimeAry.find((klineTime: string) => dayjs(klineTime).isSameOrAfter(i.time));
517
199
  return {
518
200
  ...i,
519
201
  time,
520
- }
202
+ };
521
203
  }),
522
- })
523
- return result
524
- }, [])
525
- sellBuyTypeChange(item)
204
+ });
205
+ return result;
206
+ }, []);
207
+ sellBuyTypeChange(item);
208
+
209
+ item.loading = false;
210
+ });
211
+ };
212
+ /**
213
+ * @description: 获取K线额外画线数据
214
+ */
215
+ const getKlineExtendData = async () => {
216
+ lineData.value = [
217
+ {
218
+ key: "warning",
219
+ data: [
220
+ {
221
+ value: 479,
222
+ text: 479,
223
+ // 自定义信息
224
+ info: {},
225
+ // 自定义配置
226
+ config: {
227
+ draggable: true,
228
+ },
229
+ },
230
+ ],
231
+ ondragstart: (params: any, info: any) => {
232
+ console.log("拖拽开始", params, info);
233
+ },
234
+ ondragend: (params: any, info: any, yAxisValue: number) => {
235
+ console.log("拖拽结束", params, info, yAxisValue);
236
+ ElMessage.success("预警线修改更新成功!");
237
+ },
238
+ oncontextmenu: (params: any, info: any, menuData: any) => {
239
+ console.log("右击了", params, info);
240
+ menuData.value = [
241
+ {
242
+ label: "删除画线",
243
+ callBack: () => ElMessage.success("预警线删除成功!"),
244
+ },
245
+ {
246
+ label: "修改画线",
247
+ callBack: () => ElMessage.success("预警线修改成功!"),
248
+ },
249
+ ];
250
+ },
251
+ },
252
+ {
253
+ key: "position",
254
+ data: [
255
+ {
256
+ value: 480,
257
+ text: "持仓:192.14万(1份) 数量:4手 方向:多 浮动盈亏:-1280.00",
258
+ // 自定义信息
259
+ info: {},
260
+ // 自定义配置
261
+ config: {},
262
+ },
263
+ ],
264
+ },
265
+ {
266
+ key: "condition",
267
+ data: [
268
+ {
269
+ value: 482,
270
+ text: "[多损][多盈] 开多↓2269 1份(22手)",
271
+ profitValue: 483,
272
+ profitText: "上破484",
273
+ lossValue: 481,
274
+ lossText: "下破482",
275
+ // 自定义信息
276
+ info: {},
277
+ // 自定义配置
278
+ config: {},
279
+ },
280
+ ],
281
+ },
282
+ ];
283
+ };
284
+ /**
285
+ * @description: 买卖点,开平点切换
286
+ */
287
+ const sellBuyTypeChange = (item: any) => {
288
+ if (sellBuyTypeOptions.value.length > 0) {
289
+ item.sellBuyTypeName = sellBuyTypeOptions.value.find((i: any) => i.value === item.sellBuyType).label ?? null;
290
+ }
291
+ if (item.sellBuyType === 1) {
292
+ item.markData = originPointData.value.filter((i: any) => {
293
+ return i.key !== "sellBuy";
294
+ });
295
+ } else {
296
+ item.markData = originPointData.value.filter((i: any) => {
297
+ return i.key !== "openClose";
298
+ });
299
+ }
300
+ };
301
+ /**
302
+ * @description: 切换指标
303
+ */
304
+ const indicatorChange = (item: any) => {
305
+ item.indicator = mainIndicatorList.find((i: any) => i.value === item.indicatorName);
306
+ };
526
307
 
527
- item.loading = false
308
+ // 画线预警
309
+ const createWarning = (echartsInstance: any, cursorPenVisible: any) => {
310
+ // 1.打开画笔模式,并修改指示器样式[画预览线]
311
+ cursorPenVisible.value = true;
312
+ const echartsOptions = echartsInstance.getOption();
313
+ const oldTooltip = (echartsOptions.tooltip as Array<any>)[0];
314
+ echartsInstance.setOption({
315
+ ...echartsOptions,
316
+ // 指示器样式
317
+ tooltip: {
318
+ ...oldTooltip,
319
+ // 坐标轴指示器
320
+ axisPointer: {
321
+ // 保留原有部分配置
322
+ ...oldTooltip.axisPointer,
323
+ // X轴指示线的宽度
324
+ lineStyle: {
325
+ width: 0,
326
+ },
327
+ // Y轴指示线的宽度
328
+ crossStyle: {
329
+ width: 2,
330
+ },
331
+ // 文本标签
332
+ label: {
333
+ // 保留原有部分配置
334
+ ...oldTooltip.axisPointer.label,
335
+ // 颜色改为透明
336
+ backgroundColor: "transparent",
337
+ // 仅显示Y轴值
338
+ formatter: (data: any) => {
339
+ const { axisDimension, value } = data;
340
+ if (axisDimension === "y") {
341
+ return String(formatValue(value));
342
+ }
343
+ return "";
344
+ },
345
+ },
346
+ },
347
+ },
348
+ });
349
+ // 2.获取当前列数据并发送请求至后端记录
350
+ const handleClick = (el: any) => {
351
+ // 关闭画笔模式,并移除echarts点击事件
352
+ cursorPenVisible.value = false;
353
+ echartsInstance.getZr().off("mousedown", handleClick);
354
+ const yAxisValue = echartsInstance.convertFromPixel({ yAxisIndex: 0 }, el.offsetY);
355
+ const newWarnPrice = Math.round(yAxisValue * 1000) / 1000;
356
+ // 3.恢复指示器样式
357
+ echartsInstance.setOption({
358
+ ...echartsOptions,
359
+ // 指示器样式
360
+ tooltip: {
361
+ ...oldTooltip,
362
+ axisPointer: {
363
+ ...oldTooltip.axisPointer,
364
+ lineStyle: {
365
+ width: 1,
366
+ },
367
+ crossStyle: {
368
+ width: 1,
369
+ },
370
+ label: {
371
+ ...oldTooltip.axisPointer.label,
372
+ backgroundColor: null,
373
+ },
374
+ },
375
+ },
376
+ });
377
+ // 4.发送保存预警线请求
378
+ lineData.value[0].data.push({
379
+ value: newWarnPrice,
380
+ text: newWarnPrice,
381
+ // 自定义信息
382
+ info: {},
383
+ // 自定义配置
384
+ config: {
385
+ draggable: true,
386
+ },
387
+ });
388
+ ElMessage.success("画线预警成功!");
389
+ };
390
+ // 绑定echarts点击事件
391
+ echartsInstance.getZr().on("mousedown", handleClick);
392
+ };
528
393
 
529
- getKlineExtendData()
394
+ watch(
395
+ () => props.deBugValue,
396
+ (newValue: any) => {
397
+ if (newValue === 1) {
398
+ // 正常模式
399
+ componentInit();
400
+ } else {
401
+ multiCycleKline.value.forEach((item: any) => {
402
+ if (newValue === 2) {
403
+ // 网络故障
404
+ item.loading = true;
405
+ setTimeout(() => {
406
+ item.netWorkErrorMsg = "网络加载失败,请刷新重试";
407
+ item.loading = false;
408
+ }, 1000);
409
+ } else if (newValue === 3) {
410
+ // 空数据
411
+ item.netWorkErrorMsg = "";
412
+ item.loading = true;
413
+ setTimeout(() => {
414
+ item.klineData = [];
415
+ item.loading = false;
416
+ }, 1000);
417
+ }
418
+ });
419
+ }
420
+ },
421
+ {
422
+ immediate: true,
530
423
  }
424
+ );
425
+
426
+ onUnmounted(() => {
427
+ console.log("---------单品种多周期组件: onUnmounted卸载成功---------");
428
+ });
429
+
430
+ const reFresh = async (item: any) => {
431
+ item.netWorkErrorMsg = "";
432
+ item.loading = true;
433
+
434
+ // ---------K线数据逻辑----------
435
+ const params = {
436
+ right: 1, // 复权方式
437
+ variety: "au8888", // 品种
438
+ cycle: item.cycle, // 周期
439
+ endTime: "2024-01-04 23:59:59", // 结束时间
440
+ limit: config.value.totalBarCount + config.value.preBarCount, // 总条数
441
+ queryType: 1, // 0-按时间,1-按结束时间,2-按开始时间
442
+ };
443
+ const res = await getSingleCycleSingleVariety(params);
444
+ item.klineData = res.data.body;
445
+ // ---------点位数据逻辑---------
446
+ const resultApi = [
447
+ {
448
+ key: "sellBuy",
449
+ data: [
450
+ {
451
+ tradeAction: "开", // 交易动作
452
+ direction: "多", // 交易方向
453
+ tradeType: "开多", // 交易类型
454
+ amount: 2, // 手数
455
+ part: 2, // 份数
456
+ time: "2024-01-04 22:30:00", // 交易时间
457
+ tooltip: "<div>买卖点1</div>",
458
+ },
459
+ {
460
+ tradeAction: "平", // 交易动作
461
+ direction: "空", // 交易方向
462
+ tradeType: "平空", // 交易类型
463
+ amount: 2, // 手数
464
+ part: 2, // 份数
465
+ time: "2024-01-04 22:40:00", // 交易时间
466
+ tooltip: "<div>买卖点2</div>",
467
+ },
468
+ {
469
+ tradeAction: "开", // 交易动作
470
+ direction: "空", // 交易方向
471
+ tradeType: "开空", // 交易类型
472
+ amount: 2, // 手数
473
+ part: 2, // 份数
474
+ time: "2024-01-04 23:50:00", // 交易时间
475
+ tooltip: "<div>买卖点3</div>",
476
+ },
477
+ ],
478
+ },
479
+ {
480
+ key: "openClose",
481
+ data: [
482
+ {
483
+ tradeAction: "开", // 交易动作
484
+ direction: "多", // 交易方向
485
+ tradeType: "开多", // 交易类型
486
+ amount: 2, // 手数
487
+ part: 2, // 份数
488
+ time: "2024-01-04 22:30:00", // 交易时间
489
+ tooltip: "<div>开平点1</div>",
490
+ },
491
+ {
492
+ tradeAction: "平", // 交易动作
493
+ direction: "空", // 交易方向
494
+ tradeType: "平空", // 交易类型
495
+ amount: 2, // 手数
496
+ part: 2, // 份数
497
+ time: "2024-01-04 22:40:00", // 交易时间
498
+ tooltip: "<div>开平点2</div>",
499
+ },
500
+ {
501
+ tradeAction: "开", // 交易动作
502
+ direction: "空", // 交易方向
503
+ tradeType: "开空", // 交易类型
504
+ amount: 2, // 手数
505
+ part: 2, // 份数
506
+ time: "2024-01-04 23:50:00", // 交易时间
507
+ tooltip: "<div>买卖点3</div>",
508
+ },
509
+ ],
510
+ },
511
+ {
512
+ key: "signal",
513
+ data: [],
514
+ },
515
+ ];
516
+ const klineTimeAry = item.klineData.map((item: any) => item[0]);
517
+ originPointData.value = resultApi.reduce((result: any, next) => {
518
+ const { data } = next;
519
+ result.push({
520
+ key: next.key,
521
+ data: data.map((i: any) => {
522
+ const time = klineTimeAry.find((klineTime: string) => dayjs(klineTime).isSameOrAfter(i.time));
523
+ return {
524
+ ...i,
525
+ time,
526
+ };
527
+ }),
528
+ });
529
+ return result;
530
+ }, []);
531
+ sellBuyTypeChange(item);
532
+
533
+ item.loading = false;
534
+
535
+ getKlineExtendData();
536
+ };
531
537
  </script>
532
538
 
533
539
  <template>
@@ -535,6 +541,8 @@
535
541
  <template v-if="multiCycleKline.length">
536
542
  <div
537
543
  v-for="(item, index) in multiCycleKline"
544
+ @mousemove="item.isSelect = true"
545
+ @mouseout="item.isSelect = false"
538
546
  :key="index"
539
547
  class="st-Kline"
540
548
  v-loading="item.loading"
@@ -551,11 +559,7 @@
551
559
  <!-- 指标展示 + 选择 -->
552
560
  <div class="kline-header-item sellBuySelect">
553
561
  <span>{{ item.indicatorName }}</span>
554
- <el-select
555
- v-model="item.indicatorName"
556
- popper-class="element-dark"
557
- @change="indicatorChange(item)"
558
- >
562
+ <el-select v-model="item.indicatorName" popper-class="element-dark" @change="indicatorChange(item)">
559
563
  <el-option
560
564
  v-for="(item, index) in mainIndicatorList"
561
565
  :key="index"
@@ -567,11 +571,7 @@
567
571
  <!-- 开平/买卖展示 + 选择 -->
568
572
  <div class="kline-header-item sellBuySelect">
569
573
  <span>{{ item.sellBuyTypeName }}</span>
570
- <el-select
571
- v-model="item.sellBuyType"
572
- popper-class="element-dark"
573
- @change="sellBuyTypeChange(item)"
574
- >
574
+ <el-select v-model="item.sellBuyType" popper-class="element-dark" @change="sellBuyTypeChange(item)">
575
575
  <el-option
576
576
  v-for="(item, index) in sellBuyTypeOptions"
577
577
  :key="index"
@@ -591,26 +591,16 @@
591
591
  :lineData="lineData"
592
592
  :brushRange="brushRange"
593
593
  :defaultMenuData="defaultMenuData"
594
+ :isSelect="item.isSelect"
594
595
  :config="config"
595
596
  />
596
597
  <!-- 网络请求错误时 -->
597
- <div
598
- v-if="item.netWorkErrorMsg"
599
- class="netWorkError"
600
- >
598
+ <div v-if="item.netWorkErrorMsg" class="netWorkError">
601
599
  <span>{{ item.netWorkErrorMsg }}</span>
602
- <el-button
603
- size="small"
604
- @click="reFresh(item)"
605
- :icon="RefreshRight"
606
- >刷新</el-button
607
- >
600
+ <el-button size="small" @click="reFresh(item)" :icon="RefreshRight">刷新</el-button>
608
601
  </div>
609
602
  <!-- 空数据时 -->
610
- <div
611
- class="empty"
612
- v-else-if="!item.loading && item.klineData.length === 0"
613
- >
603
+ <div class="empty" v-else-if="!item.loading && item.klineData.length === 0">
614
604
  <el-empty description="暂无数据" />
615
605
  </div>
616
606
  </div>
@@ -619,93 +609,93 @@
619
609
  </template>
620
610
 
621
611
  <style lang="scss" scoped>
622
- #single-cycle-single-variety {
623
- margin: auto;
624
- width: 100%;
625
- height: 100%;
626
- display: grid;
627
- grid-template-columns: repeat(3, 33%);
628
- grid-template-rows: repeat(6, 33%);
629
- grid-gap: 4px;
630
- overflow: hidden;
631
- .st-Kline {
612
+ #single-cycle-single-variety {
613
+ margin: auto;
614
+ width: 100%;
615
+ height: 100%;
616
+ display: grid;
617
+ grid-template-columns: repeat(3, 33%);
618
+ grid-template-rows: repeat(6, 33%);
619
+ grid-gap: 4px;
620
+ overflow: hidden;
621
+ .st-Kline {
622
+ display: flex;
623
+ flex-direction: column;
624
+ border-radius: 2px;
625
+ box-sizing: border-box;
626
+ background-color: black;
627
+ color-scheme: dark;
628
+ --el-mask-color: rgba(0, 0, 0, 0.8);
629
+ .kline-header {
630
+ font-size: 12px;
632
631
  display: flex;
633
- flex-direction: column;
634
- border-radius: 2px;
635
- box-sizing: border-box;
636
- background-color: black;
637
- color-scheme: dark;
638
- --el-mask-color: rgba(0, 0, 0, 0.8);
639
- .kline-header {
640
- font-size: 12px;
632
+ align-items: center;
633
+ color: white;
634
+ border-bottom: 1px solid rgb(153, 153, 153);
635
+ .kline-header-item {
641
636
  display: flex;
642
637
  align-items: center;
643
- color: white;
644
- border-bottom: 1px solid rgb(153, 153, 153);
645
- .kline-header-item {
646
- display: flex;
647
- align-items: center;
648
- border-right: 1px solid rgb(153, 153, 153);
649
- padding: 6px;
650
- box-sizing: border-box;
651
- }
652
- // 功能区: 开平/买卖
653
- .sellBuySelect {
654
- :deep(.el-select) {
655
- margin-left: 6px;
638
+ border-right: 1px solid rgb(153, 153, 153);
639
+ padding: 6px;
640
+ box-sizing: border-box;
641
+ }
642
+ // 功能区: 开平/买卖
643
+ .sellBuySelect {
644
+ :deep(.el-select) {
645
+ margin-left: 6px;
646
+ width: 12px;
647
+ .el-input__wrapper {
648
+ height: 12px;
649
+ padding: 0;
650
+ border-radius: 50%;
651
+ background-color: #ccc;
652
+ }
653
+ .el-input__inner {
654
+ width: 0;
655
+ }
656
+ .el-select__icon {
657
+ color: black;
656
658
  width: 12px;
657
- .el-input__wrapper {
658
- height: 12px;
659
- padding: 0;
660
- border-radius: 50%;
661
- background-color: #ccc;
662
- }
663
- .el-input__inner {
664
- width: 0;
665
- }
666
- .el-select__icon {
667
- color: black;
668
- width: 12px;
669
- height: 12px;
670
- margin-left: 0;
671
- }
659
+ height: 12px;
660
+ margin-left: 0;
672
661
  }
673
662
  }
674
663
  }
675
- .kline {
676
- flex: 1;
677
- }
678
- .netWorkError {
664
+ }
665
+ .kline {
666
+ flex: 1;
667
+ }
668
+ .netWorkError {
669
+ color: white;
670
+ font-weight: 600;
671
+ display: flex;
672
+ flex-direction: column;
673
+ align-items: center;
674
+ justify-content: center;
675
+ width: 100%;
676
+ height: 100%;
677
+ font-size: 18px;
678
+ .el-button {
679
+ margin-top: 10px;
680
+ background-color: rgb(0, 0, 0);
679
681
  color: white;
680
- font-weight: 600;
681
- display: flex;
682
- flex-direction: column;
683
- align-items: center;
684
- justify-content: center;
685
- width: 100%;
686
- height: 100%;
687
- font-size: 18px;
688
- .el-button {
689
- margin-top: 10px;
690
- background-color: rgb(0, 0, 0);
691
- color: white;
692
- }
693
682
  }
694
- .empty {
695
- color: white;
696
- font-weight: 600;
697
- display: flex;
698
- flex-direction: column;
699
- align-items: center;
700
- justify-content: center;
701
- width: 100%;
702
- height: 100%;
703
- :deep(.el-empty__image) {
704
- svg {
705
- width: 100px;
706
- }
683
+ }
684
+ .empty {
685
+ color: white;
686
+ font-weight: 600;
687
+ display: flex;
688
+ flex-direction: column;
689
+ align-items: center;
690
+ justify-content: center;
691
+ width: 100%;
692
+ height: 100%;
693
+ :deep(.el-empty__image) {
694
+ svg {
695
+ width: 100px;
707
696
  }
708
697
  }
709
698
  }
710
699
  }
700
+ }
711
701
  </style>