st-comp 0.0.4 → 0.0.6
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.
- package/README.md +7 -16
- package/auto-imports.d.ts +9 -0
- package/components.d.ts +26 -0
- package/lib/bundle.js +11230 -1509
- package/lib/bundle.umd.cjs +30 -5
- package/lib/style.css +1 -0
- package/package.json +13 -3
- package/packages/Button/index.ts +8 -10
- package/packages/Button/index.vue +1 -1
- package/packages/Echarts/index.ts +8 -0
- package/packages/Echarts/index.vue +113 -0
- package/packages/Kline/components/Tips/index.vue +108 -0
- package/packages/Kline/formatKlineData.ts +197 -0
- package/packages/Kline/index.ts +8 -0
- package/packages/Kline/index.vue +215 -0
- package/packages/Kline/kline_theme_dark.json +30 -0
- package/packages/Kline/kline_theme_light.json +30 -0
- package/packages/Kline/type.d.ts +34 -0
- package/packages/Kline/utils.ts +272 -0
- package/packages/List/index.ts +8 -8
- package/packages/Table/components/Button/index.vue +54 -0
- package/packages/Table/components/Formatter/index.vue +26 -0
- package/packages/Table/index.d.ts +0 -0
- package/packages/Table/index.ts +8 -0
- package/packages/Table/index.vue +112 -0
- package/packages/index.ts +17 -10
- package/src/App.vue +79 -26
- package/src/components/Echarts/index.vue +31 -0
- package/src/components/Kline/index.vue +21 -0
- package/src/components/KlineGroup/index.vue +58 -0
- package/src/components/Table/index.vue +27 -0
- package/src/main.ts +5 -1
- package/src/pages/Button/index.vue +12 -0
- package/src/pages/Echarts/index.vue +12 -0
- package/src/pages/Kline/index.vue +12 -0
- package/src/pages/List/index.vue +12 -0
- package/src/pages/Table/index.vue +27 -0
- package/src/router/index.ts +9 -0
- package/src/router/routes.ts +27 -0
- package/src/style.css +3 -79
- package/src/vite-env.d.ts +7 -0
- package/vite.config.ts +31 -1
- package/vitePlugins/createExportFile.ts +97 -0
- package/src/components/HelloWorld.vue +0 -38
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="st-kline">
|
|
3
|
+
<!-- 顶部Tips -->
|
|
4
|
+
<div class="st-kline-header">
|
|
5
|
+
<Tips
|
|
6
|
+
:activeIndex="activeIndex"
|
|
7
|
+
:klineData="klineData"
|
|
8
|
+
:indicatorData="indicatorData"
|
|
9
|
+
:indicatorConfig="indicatorConfigList[indicator]"
|
|
10
|
+
/>
|
|
11
|
+
</div>
|
|
12
|
+
<!-- 图表 -->
|
|
13
|
+
<st-echarts
|
|
14
|
+
v-if="option"
|
|
15
|
+
:option="option"
|
|
16
|
+
:themeConfig="{
|
|
17
|
+
name: 'kline',
|
|
18
|
+
light: klineThemeLight,
|
|
19
|
+
dark: klineThemeDark,
|
|
20
|
+
}"
|
|
21
|
+
@highlight="highlight"
|
|
22
|
+
@afterInit="afterInit"
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<script setup lang="ts">
|
|
28
|
+
import dayjs from 'dayjs'
|
|
29
|
+
import { ref, onMounted } from 'vue'
|
|
30
|
+
import Tips from './components/Tips/index.vue'
|
|
31
|
+
import klineThemeDark from './kline_theme_dark.json'
|
|
32
|
+
import klineThemeLight from './kline_theme_light.json'
|
|
33
|
+
import type { EChartsType, EChartsOption } from 'echarts'
|
|
34
|
+
import type { KlineDataType, IndicatorDataType, IndicatorConfigType } from './type.d.ts'
|
|
35
|
+
import { getKline, getIndicator, getIndicatorConfigList, getOption } from './utils'
|
|
36
|
+
|
|
37
|
+
const props = defineProps({
|
|
38
|
+
// 品种代码
|
|
39
|
+
code: {
|
|
40
|
+
type: String,
|
|
41
|
+
required: true,
|
|
42
|
+
},
|
|
43
|
+
// 默认展示K线条数
|
|
44
|
+
defaultCount: {
|
|
45
|
+
type: Number,
|
|
46
|
+
default: () => 500,
|
|
47
|
+
},
|
|
48
|
+
// 结束时间
|
|
49
|
+
tradeDate: {
|
|
50
|
+
type: String,
|
|
51
|
+
required: true,
|
|
52
|
+
},
|
|
53
|
+
// 周期名称
|
|
54
|
+
frequency: {
|
|
55
|
+
type: String,
|
|
56
|
+
required: true,
|
|
57
|
+
},
|
|
58
|
+
// 指标线类型
|
|
59
|
+
indicator: {
|
|
60
|
+
type: String,
|
|
61
|
+
required: true,
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const option = ref<any>(null) // 图表配置
|
|
66
|
+
const klineData = ref<KlineDataType>([]) // K线数据
|
|
67
|
+
const indicatorData = ref<IndicatorDataType>([]) // 指标线具体数据
|
|
68
|
+
const indicatorConfigList = ref<IndicatorConfigType>({}) // 指标线配置项
|
|
69
|
+
const activeIndex = ref(0) // 当前鼠标激活的数据索引
|
|
70
|
+
|
|
71
|
+
// 获取K线数据
|
|
72
|
+
const getKlineData = async () => {
|
|
73
|
+
const { code, defaultCount, tradeDate, frequency } = props
|
|
74
|
+
const res = await getKline(code, defaultCount, tradeDate, frequency)
|
|
75
|
+
return res.data
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 获取指标线具体数据
|
|
79
|
+
const getIndicatorData = async (klineData: KlineDataType) => {
|
|
80
|
+
if (klineData.length === 0) return
|
|
81
|
+
const { code, frequency, indicator } = props
|
|
82
|
+
const start_date = dayjs(new Date(klineData[0][0] * 1000)).format('YYYY-MM-DD')
|
|
83
|
+
const end_date = dayjs(new Date(klineData[klineData.length - 1][0] * 1000)).format('YYYY-MM-DD')
|
|
84
|
+
const indicatorRes = await getIndicator(code, start_date, end_date, frequency, indicator)
|
|
85
|
+
// 格式处理,只格式化获取处于K线之中的指标线数据
|
|
86
|
+
return indicatorRes.data.datetime
|
|
87
|
+
? indicatorRes.data.datetime.reduce((res: IndicatorDataType, date: number, index: number) => {
|
|
88
|
+
if (date >= klineData[0][0] && date <= klineData[klineData.length - 1][0]) {
|
|
89
|
+
return [
|
|
90
|
+
...res,
|
|
91
|
+
{
|
|
92
|
+
...Object.keys(indicatorRes.data).reduce((keyRes, key) => {
|
|
93
|
+
return {
|
|
94
|
+
...keyRes,
|
|
95
|
+
[key]: indicatorRes.data[key][index],
|
|
96
|
+
}
|
|
97
|
+
}, {}),
|
|
98
|
+
},
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
return res
|
|
102
|
+
}, [])
|
|
103
|
+
: null
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 初始化
|
|
107
|
+
const init = async () => {
|
|
108
|
+
// 1.获取K线数据
|
|
109
|
+
klineData.value = await getKlineData()
|
|
110
|
+
// 2.默认Tips激活展示最后一条
|
|
111
|
+
activeIndex.value = klineData.value.length - 1
|
|
112
|
+
// 3.获取指标线具体数据
|
|
113
|
+
indicatorData.value = await getIndicatorData(klineData.value)
|
|
114
|
+
// 4.获取指标相关配置
|
|
115
|
+
indicatorConfigList.value = (await getIndicatorConfigList()).data
|
|
116
|
+
// 5.获取图表配置
|
|
117
|
+
option.value = await getOption({
|
|
118
|
+
kLineData: klineData.value,
|
|
119
|
+
indicatorData: indicatorData.value,
|
|
120
|
+
indicator: props.indicator,
|
|
121
|
+
indicatorConfigList: indicatorConfigList.value,
|
|
122
|
+
defaultShowBarCount: 200,
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// 图表高亮,用于记录当前高亮tooltip
|
|
127
|
+
const highlight = (data: any, chart: EChartsType) => {
|
|
128
|
+
if (data) {
|
|
129
|
+
// 图表内部移动
|
|
130
|
+
activeIndex.value =
|
|
131
|
+
typeof data?.batch[0]?.dataIndex === 'number' ? data?.batch[0]?.dataIndex : -1
|
|
132
|
+
} else {
|
|
133
|
+
// 移出图表
|
|
134
|
+
const chartOptions: EChartsOption = chart.getOption() as EChartsOption
|
|
135
|
+
if (chartOptions.dataZoom instanceof Array) {
|
|
136
|
+
activeIndex.value = chartOptions.dataZoom[0].endValue as number
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// 默认区域刷选
|
|
141
|
+
const afterInit = (chart: EChartsType) => {
|
|
142
|
+
/**
|
|
143
|
+
* 获取匹配用户选择的交易日期对应X轴的索引,用于刷选范围区域
|
|
144
|
+
* 匹配思路:
|
|
145
|
+
* 1.时间轴均转换为年月日字符串做对比,相等则算匹配成功
|
|
146
|
+
* 2.特殊周期K线需要特殊处理:
|
|
147
|
+
* [1w]:时间需要均转换成所处星期的星期五日期,判断它们星期五日期是否相等
|
|
148
|
+
* [1m,5m,15m,30m,60m]:包含前一交易日21点后的,排除掉交易日期21点后的
|
|
149
|
+
*/
|
|
150
|
+
const { tradeDate, frequency } = props
|
|
151
|
+
const xAxisData = option.value.xAxis.data
|
|
152
|
+
let brushXIndexList: Array<number> = []
|
|
153
|
+
// 长周期判断
|
|
154
|
+
xAxisData.forEach((xItem: number, index: number) => {
|
|
155
|
+
// X轴年月日
|
|
156
|
+
const xItemDate = dayjs(xItem * 1000).format('YYYY-MM-DD')
|
|
157
|
+
xItemDate === tradeDate && brushXIndexList.push(index)
|
|
158
|
+
// 如果是周线,则需要判断两者周五日期是否相等
|
|
159
|
+
if (frequency === '1w') {
|
|
160
|
+
dayjs(xItemDate).day(5).format('YYYY-MM-DD') ===
|
|
161
|
+
dayjs(tradeDate).day(5).format('YYYY-MM-DD') && brushXIndexList.push(index)
|
|
162
|
+
}
|
|
163
|
+
})
|
|
164
|
+
const shortFreq = ['1m', '5m', '15m', '30m', '60m']
|
|
165
|
+
// 短周期判断
|
|
166
|
+
if (shortFreq.includes(frequency)) {
|
|
167
|
+
// 拿到上一个交易日
|
|
168
|
+
const lastTradeDateIndex = brushXIndexList[0] - 1
|
|
169
|
+
const lastTradeDate = dayjs(xAxisData[lastTradeDateIndex] * 1000).format('YYYY-MM-DD')
|
|
170
|
+
// 包含了上一个交易日21点之后的数据索引数组
|
|
171
|
+
const lastTrade21List: Array<number> = []
|
|
172
|
+
xAxisData.forEach((xItem: number, index: number) => {
|
|
173
|
+
if (
|
|
174
|
+
dayjs(xItem * 1000).format('YYYY-MM-DD') === lastTradeDate &&
|
|
175
|
+
dayjs(xItem * 1000).isSameOrAfter(`${lastTradeDate} 21:00:00`)
|
|
176
|
+
) {
|
|
177
|
+
lastTrade21List.push(index)
|
|
178
|
+
}
|
|
179
|
+
})
|
|
180
|
+
// 排除匹配到交易日期21点之后的数据索引
|
|
181
|
+
const finallyDateIndex = brushXIndexList[brushXIndexList.length - 1]
|
|
182
|
+
const finallyDate = dayjs(xAxisData[finallyDateIndex] * 1000).format('YYYY-MM-DD 21:00:00')
|
|
183
|
+
brushXIndexList = [...lastTrade21List, ...brushXIndexList].filter(item => {
|
|
184
|
+
return dayjs(xAxisData[item] * 1000).isBefore(finallyDate)
|
|
185
|
+
})
|
|
186
|
+
}
|
|
187
|
+
chart.dispatchAction({
|
|
188
|
+
type: 'brush',
|
|
189
|
+
areas: [
|
|
190
|
+
{
|
|
191
|
+
brushType: 'lineX',
|
|
192
|
+
coordRange: [brushXIndexList[0], brushXIndexList.slice(-1)[0]],
|
|
193
|
+
xAxisIndex: 0,
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
})
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
onMounted(() => {
|
|
200
|
+
init()
|
|
201
|
+
})
|
|
202
|
+
</script>
|
|
203
|
+
|
|
204
|
+
<style lang="scss" scoped>
|
|
205
|
+
.st-kline {
|
|
206
|
+
width: 100%;
|
|
207
|
+
height: 100%;
|
|
208
|
+
background: #000;
|
|
209
|
+
position: relative;
|
|
210
|
+
&-header {
|
|
211
|
+
position: absolute;
|
|
212
|
+
padding: 2px 0 0 4px;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
</style>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
{
|
|
3
|
+
"candlestick": {
|
|
4
|
+
"itemStyle": {
|
|
5
|
+
"color": "transparent",
|
|
6
|
+
"color0": "#00FFFF",
|
|
7
|
+
"borderColor": "#FF0000",
|
|
8
|
+
"borderColor0": "#00FFFF",
|
|
9
|
+
"borderWidth": 1
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"categoryAxis": {
|
|
13
|
+
"splitLine": {
|
|
14
|
+
"lineStyle": {
|
|
15
|
+
"color": [
|
|
16
|
+
"#333"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"valueAxis": {
|
|
22
|
+
"splitLine": {
|
|
23
|
+
"lineStyle": {
|
|
24
|
+
"color": [
|
|
25
|
+
"#333"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
{
|
|
3
|
+
"candlestick": {
|
|
4
|
+
"itemStyle": {
|
|
5
|
+
"color": "transparent",
|
|
6
|
+
"color0": "#00FFFF",
|
|
7
|
+
"borderColor": "#FF0000",
|
|
8
|
+
"borderColor0": "#00FFFF",
|
|
9
|
+
"borderWidth": 1
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"categoryAxis": {
|
|
13
|
+
"splitLine": {
|
|
14
|
+
"lineStyle": {
|
|
15
|
+
"color": [
|
|
16
|
+
"#333"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"valueAxis": {
|
|
22
|
+
"splitLine": {
|
|
23
|
+
"lineStyle": {
|
|
24
|
+
"color": [
|
|
25
|
+
"#333"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// K线数据类型
|
|
2
|
+
export type KlineDataItem = [number, number, number, number, number, number, number, number, number]
|
|
3
|
+
export type KlineDataType = Array<KlineDataItem>
|
|
4
|
+
|
|
5
|
+
// 指标线数据类型
|
|
6
|
+
export interface IndicatorDataItem {
|
|
7
|
+
datetime: number;
|
|
8
|
+
[key: string]: number;
|
|
9
|
+
}
|
|
10
|
+
export type IndicatorDataType = Array<IndicatorDataItem>
|
|
11
|
+
|
|
12
|
+
export interface InOption {
|
|
13
|
+
kLineData: KlineDataItem[];
|
|
14
|
+
indicatorData: IndicatorDataItem[];
|
|
15
|
+
indicator: string;
|
|
16
|
+
indicatorList: any;
|
|
17
|
+
defaultShowBarCount: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 指标线配置项数据类型
|
|
21
|
+
export interface IndicatorConfigType {
|
|
22
|
+
[key: string]: {
|
|
23
|
+
[key: string]: string
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// 获取图表配置项入参类型
|
|
28
|
+
export interface InOption {
|
|
29
|
+
kLineData: KlineDataType;
|
|
30
|
+
indicatorData: IndicatorDataType;
|
|
31
|
+
indicator: string;
|
|
32
|
+
indicatorConfigList: any;
|
|
33
|
+
defaultShowBarCount: number;
|
|
34
|
+
}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import axios from 'axios'
|
|
2
|
+
import dayjs from 'dayjs'
|
|
3
|
+
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'
|
|
4
|
+
import type { KlineDataItem, IndicatorDataItem, InOption } from './type.d.ts'
|
|
5
|
+
dayjs.extend(isSameOrAfter)
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @description: 获取固定间隔后的交易日
|
|
9
|
+
* @param {string} currentDate 初始交易日期
|
|
10
|
+
* @param {number | undefined} days 间隔天数
|
|
11
|
+
* @return {*}
|
|
12
|
+
*/
|
|
13
|
+
const getTradeByAddDays = (currentDate: string, days: number | undefined) => {
|
|
14
|
+
return axios({
|
|
15
|
+
headers: {
|
|
16
|
+
Token: '8c9e48f3bfff810c3403829233f76515',
|
|
17
|
+
},
|
|
18
|
+
method: 'post',
|
|
19
|
+
url: '/proxy/review/review/getTradeByAddDays',
|
|
20
|
+
data: {
|
|
21
|
+
currentDate,
|
|
22
|
+
days,
|
|
23
|
+
},
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @description: 获取K线数据
|
|
29
|
+
* @param {string} code 品种代码
|
|
30
|
+
* @param {number} bar_count 请求数据条数
|
|
31
|
+
* @param {string} tradeDate 交易日期
|
|
32
|
+
* @param {string} frequency 周期
|
|
33
|
+
* @return {*}
|
|
34
|
+
*/
|
|
35
|
+
export const getKline = async (
|
|
36
|
+
code: string,
|
|
37
|
+
bar_count: number,
|
|
38
|
+
tradeDate: string,
|
|
39
|
+
frequency: string
|
|
40
|
+
) => {
|
|
41
|
+
// 周期对应的间隔交易日
|
|
42
|
+
const timeIntervalMap = new Map([
|
|
43
|
+
['1m', 1],
|
|
44
|
+
['5m', 1],
|
|
45
|
+
['15m', 4],
|
|
46
|
+
['30m', 8],
|
|
47
|
+
['60m', 16],
|
|
48
|
+
['1d', 80],
|
|
49
|
+
['1w', 80],
|
|
50
|
+
])
|
|
51
|
+
// 根据周期判断逻辑请求到对应的间隔末尾交易日
|
|
52
|
+
const interval = timeIntervalMap.get(frequency)
|
|
53
|
+
const res = await getTradeByAddDays(tradeDate, interval)
|
|
54
|
+
const nowDate = dayjs().format('YYYY-MM-DD')
|
|
55
|
+
const resDate = res.data.body.tradeDate.split(' ')[0]
|
|
56
|
+
let dt: null | string = null
|
|
57
|
+
// 判断接口获取到的交易日是否大于等于今日,如果为真,则以今日日期为末尾
|
|
58
|
+
if (dayjs(resDate).isSameOrAfter(nowDate)) {
|
|
59
|
+
dt = dayjs().format('YYYY-MM-DD HH:mm:ss')
|
|
60
|
+
} else {
|
|
61
|
+
dt = `${resDate} 23:59:59`
|
|
62
|
+
}
|
|
63
|
+
return axios(
|
|
64
|
+
`http://116.62.161.92:8005/history_kline?code=${code}&bar_count=${bar_count}&dt=${dt}&frequency=${frequency}`
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @description: 获取指标线下拉列表类型数据以及相关样式配置
|
|
70
|
+
* @return {*}
|
|
71
|
+
*/
|
|
72
|
+
export const getIndicatorConfigList = () => {
|
|
73
|
+
return axios('http://116.62.161.92:8005/get_indicator')
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @description: 获取指标线具体数据
|
|
78
|
+
* @param {string} code 品种代码
|
|
79
|
+
* @param {string} start_date 开始日期
|
|
80
|
+
* @param {string} end_date 结束日期
|
|
81
|
+
* @param {string} frequency 周期
|
|
82
|
+
* @param {string} indicator 指标类型
|
|
83
|
+
* @return {*}
|
|
84
|
+
*/
|
|
85
|
+
export const getIndicator = (
|
|
86
|
+
code: string,
|
|
87
|
+
start_date: string,
|
|
88
|
+
end_date: string,
|
|
89
|
+
frequency: string,
|
|
90
|
+
indicator: string
|
|
91
|
+
) => {
|
|
92
|
+
return axios(
|
|
93
|
+
`http://116.62.161.92:8005/realtime_indicator?code=${code}&start_date=${start_date}&end_date=${end_date}&indicator=${indicator}&frequency=${frequency}`
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @description: 格式化数字:保留后三位小数
|
|
99
|
+
* @param {number} value
|
|
100
|
+
* @return {*}
|
|
101
|
+
*/
|
|
102
|
+
export const formatValue = (value: number) => {
|
|
103
|
+
return value || value === 0 ? Math.round(value * 1000) / 1000 : null
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @description: 格式化价格:万 || 亿 || 万亿
|
|
108
|
+
* @param {number} value
|
|
109
|
+
* @return {*}
|
|
110
|
+
*/
|
|
111
|
+
export const formatPrice = (value: number) => {
|
|
112
|
+
if (value >= 1000000000000) {
|
|
113
|
+
return `${(value / 1000000000000).toFixed(2)}万亿`
|
|
114
|
+
} else if (value >= 100000000) {
|
|
115
|
+
return `${(value / 100000000).toFixed(2)}亿`
|
|
116
|
+
} else if (value >= 10000) {
|
|
117
|
+
return `${(value / 10000).toFixed(2)}万`
|
|
118
|
+
} else {
|
|
119
|
+
return value.toFixed(2)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @description: 格式化K线图配置项
|
|
125
|
+
* @param {InOption} data
|
|
126
|
+
* @return {*}
|
|
127
|
+
*/
|
|
128
|
+
export const getOption = async (data: InOption) => {
|
|
129
|
+
const { kLineData, indicatorData, indicator, indicatorConfigList, defaultShowBarCount } = data
|
|
130
|
+
// 处理k线数据,x轴数据
|
|
131
|
+
const candlestickData: any[] = [] // k线数据
|
|
132
|
+
const xAxisData: number[] = [] // x轴数据
|
|
133
|
+
const kLineLength = kLineData.length // k线条数
|
|
134
|
+
|
|
135
|
+
kLineData.forEach((item: KlineDataItem) => {
|
|
136
|
+
candlestickData.push([
|
|
137
|
+
formatValue(item[1]),
|
|
138
|
+
formatValue(item[4]),
|
|
139
|
+
formatValue(item[3]),
|
|
140
|
+
formatValue(item[2]),
|
|
141
|
+
])
|
|
142
|
+
xAxisData.push(item[0])
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
// 处理指标线数据
|
|
146
|
+
const indicatorInfo = indicatorConfigList[indicator]
|
|
147
|
+
const lineSeries = indicatorData
|
|
148
|
+
? Object.keys(indicatorData[0])
|
|
149
|
+
.filter(i => i !== 'datetime')
|
|
150
|
+
.map((key: string) => {
|
|
151
|
+
let color = 'rgba(238, 238, 238, 0.5)'
|
|
152
|
+
if (indicatorInfo && indicatorInfo[key]) {
|
|
153
|
+
color = `#${indicatorInfo[key].split('#')[1]}`
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
name: key,
|
|
157
|
+
type: 'line',
|
|
158
|
+
symbol: 'none',
|
|
159
|
+
data: indicatorData.map(i => i[key]),
|
|
160
|
+
lineStyle: {
|
|
161
|
+
width: 1,
|
|
162
|
+
},
|
|
163
|
+
itemStyle: {
|
|
164
|
+
color,
|
|
165
|
+
},
|
|
166
|
+
}
|
|
167
|
+
})
|
|
168
|
+
: []
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
dataset: {
|
|
172
|
+
id: 'data',
|
|
173
|
+
source: {
|
|
174
|
+
kLineData,
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
grid: {
|
|
178
|
+
left: '50px',
|
|
179
|
+
top: '50px',
|
|
180
|
+
right: '30px',
|
|
181
|
+
bottom: '30px',
|
|
182
|
+
},
|
|
183
|
+
tooltip: {
|
|
184
|
+
trigger: 'axis',
|
|
185
|
+
showContent: false,
|
|
186
|
+
axisPointer: {
|
|
187
|
+
type: 'cross',
|
|
188
|
+
label: {
|
|
189
|
+
formatter: (data: any) => {
|
|
190
|
+
const { axisDimension, value } = data
|
|
191
|
+
if (axisDimension === 'x') {
|
|
192
|
+
return dayjs(new Date(value * 1000)).format('YYYY-MM-DD HH:mm')
|
|
193
|
+
} else {
|
|
194
|
+
return String(formatValue(value))
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
xAxis: {
|
|
201
|
+
type: 'category',
|
|
202
|
+
data: xAxisData,
|
|
203
|
+
axisLine: {
|
|
204
|
+
lineStyle: {
|
|
205
|
+
color: 'red',
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
splitLine: {
|
|
209
|
+
show: true,
|
|
210
|
+
lineStyle: {
|
|
211
|
+
type: 'dotted',
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
axisLabel: {
|
|
215
|
+
show: true,
|
|
216
|
+
formatter: data => dayjs(new Date(data * 1000)).format('YYYY-MM-DD HH:mm'),
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
yAxis: [
|
|
220
|
+
{
|
|
221
|
+
index: 0,
|
|
222
|
+
min: 'dataMin',
|
|
223
|
+
axisLine: {
|
|
224
|
+
show: true,
|
|
225
|
+
lineStyle: {
|
|
226
|
+
color: 'red',
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
splitLine: {
|
|
230
|
+
show: true,
|
|
231
|
+
lineStyle: {
|
|
232
|
+
type: 'dotted',
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
axisLabel: {
|
|
236
|
+
formatter: (value: number) => formatValue(value),
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
dataZoom: [
|
|
241
|
+
{
|
|
242
|
+
type: 'inside',
|
|
243
|
+
xAxisIndex: [0, 0],
|
|
244
|
+
startValue: kLineLength >= defaultShowBarCount ? kLineLength - defaultShowBarCount : 0,
|
|
245
|
+
endValue: kLineLength - 1,
|
|
246
|
+
},
|
|
247
|
+
],
|
|
248
|
+
series: [
|
|
249
|
+
{
|
|
250
|
+
name: 'k线',
|
|
251
|
+
type: 'candlestick',
|
|
252
|
+
data: candlestickData,
|
|
253
|
+
},
|
|
254
|
+
...lineSeries,
|
|
255
|
+
],
|
|
256
|
+
toolbox: {
|
|
257
|
+
show: false,
|
|
258
|
+
},
|
|
259
|
+
brush: {
|
|
260
|
+
xAxisIndex: 'all',
|
|
261
|
+
brushLink: 'all',
|
|
262
|
+
transformable: false,
|
|
263
|
+
outOfBrush: {
|
|
264
|
+
colorAlpha: 1,
|
|
265
|
+
},
|
|
266
|
+
brushStyle: {
|
|
267
|
+
color: 'rgba(120,140,180,0)',
|
|
268
|
+
borderColor: 'rgba(255,255,255,0.4)',
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
}
|
|
272
|
+
}
|
package/packages/List/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { App } from "vue";
|
|
2
|
-
import StList from "./index.vue";
|
|
3
|
-
|
|
4
|
-
export default {
|
|
5
|
-
install(app: App) {
|
|
6
|
-
app.component("
|
|
7
|
-
},
|
|
8
|
-
}
|
|
1
|
+
import { App } from "vue";
|
|
2
|
+
import StList from "./index.vue";
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
install(app: App) {
|
|
6
|
+
app.component("st-list", StList);
|
|
7
|
+
},
|
|
8
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<template v-if="show">
|
|
3
|
+
<el-popconfirm
|
|
4
|
+
v-if="option.needCheck"
|
|
5
|
+
:title="option.needCheck.title"
|
|
6
|
+
@confirm="option.onClick(scope.row, scope.$index)"
|
|
7
|
+
>
|
|
8
|
+
<template #reference>
|
|
9
|
+
<el-button
|
|
10
|
+
:type="option.type"
|
|
11
|
+
:disabled="typeof option.disabled === 'function' ? option.disabled(scope.row, scope.$index) : option.disabled"
|
|
12
|
+
>
|
|
13
|
+
{{ typeof option.text === 'function' ? option.text(scope.row, scope.$index) : option.text }}
|
|
14
|
+
</el-button>
|
|
15
|
+
</template>
|
|
16
|
+
</el-popconfirm>
|
|
17
|
+
<el-button
|
|
18
|
+
v-else
|
|
19
|
+
:type="option.type"
|
|
20
|
+
:disabled="typeof option.disabled === 'function' ? option.disabled(scope.row, scope.$index) : option.disabled"
|
|
21
|
+
@click="option.onClick(scope.row, scope.$index)"
|
|
22
|
+
>
|
|
23
|
+
{{ typeof option.text === 'function' ? option.text(scope.row, scope.$index) : option.text }}
|
|
24
|
+
</el-button>
|
|
25
|
+
</template>
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<script setup lang="ts">
|
|
29
|
+
import { computed } from 'vue'
|
|
30
|
+
|
|
31
|
+
const props = defineProps({
|
|
32
|
+
option: {
|
|
33
|
+
type: Object,
|
|
34
|
+
required: true
|
|
35
|
+
},
|
|
36
|
+
scope: {
|
|
37
|
+
type: Object,
|
|
38
|
+
required: true
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const show = computed(() => {
|
|
43
|
+
const { option, scope } = props
|
|
44
|
+
if(typeof option.show === 'function') {
|
|
45
|
+
return option.show(scope.row, scope.$index)
|
|
46
|
+
} else if (option.show === false) {
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
return true
|
|
50
|
+
})
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<style lang="scss" scoped>
|
|
54
|
+
</style>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:style="typeof option.style === 'function' ? option.style(scope.row[option.prop], scope.row) : option.style"
|
|
4
|
+
>
|
|
5
|
+
{{
|
|
6
|
+
typeof option.formatter === 'function' ? option.formatter(scope.row[option.prop], scope.row) : scope.row[option.prop]
|
|
7
|
+
}}
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup lang="ts">
|
|
12
|
+
|
|
13
|
+
defineProps({
|
|
14
|
+
option: {
|
|
15
|
+
type: Object,
|
|
16
|
+
required: true,
|
|
17
|
+
},
|
|
18
|
+
scope: {
|
|
19
|
+
type: Object,
|
|
20
|
+
required: true,
|
|
21
|
+
},
|
|
22
|
+
})
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<style lang="scss" scoped>
|
|
26
|
+
</style>
|
|
File without changes
|