st-comp 0.0.57 → 0.0.59

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,85 +1,298 @@
1
- <template>
2
- <div class="st-VarietySearch">
3
- <div
4
- v-for="item in formConfig"
5
- :key="item.key"
6
- class="st-VarietySearch-item"
7
- >
8
- <CheckBox
9
- v-if="item.type === 'checkbox' && (item.show === true || item.show === undefined)"
10
- :formData="formData"
11
- :config="item"
12
- @change="change"
13
- />
14
- <FactorFilter
15
- v-else-if="item.type === 'factorFilter' && (item.show === true || item.show === undefined)"
16
- :formData="formData"
17
- :config="item"
18
- @change="change"
19
- />
20
- <ModelSearch
21
- v-else-if="item.type === 'queryList' && (item.show === true || item.show === undefined)"
22
- :formData="formData"
23
- :config="item"
24
- @change="change"
25
- />
26
- </div>
27
- </div>
28
- </template>
29
-
30
- <script setup>
31
- import { computed } from "vue"
32
- import CheckBox from './components/CheckBox/index.vue'
33
- import FactorFilter from './components/FactorFilter/index.vue'
34
- import ModelSearch from './components/ModelSearch/index.vue'
35
-
36
- const emit = defineEmits(['update:modelValue', 'change']);
1
+ <script setup name="VarietySearch">
2
+ import { watch, computed } from "vue";
3
+ import defaultConfig from "./config.js";
4
+ import FactorScreen from "./components/FactorScreen/index.vue";
5
+ import CommonIndicator from "./components/CommonIndicator/index.vue";
37
6
 
38
7
  const props = defineProps({
39
- modelValue: {
40
- type: Object,
41
- require: true,
42
- },
43
- config: {
44
- type: Object,
45
- require: true,
46
- },
8
+ // 配置项
9
+ config: { type: Object, default: {} },
47
10
  });
48
-
49
- const formData = computed({
50
- get() {
51
- return props.modelValue;
52
- },
53
- set(val) {
54
- emit("update:modelValue", val);
11
+ const searchData = defineModel("searchData", {
12
+ default: {
13
+ varietyMarket: null, // 品种市场[单选]
14
+ commonOption: [], // 常用选项[多选]
15
+ customTag: [], // 自定标签[多选]
16
+ factorScreen: [], // 因子筛选
17
+ commonIndicator: [], // 常用指标
55
18
  },
56
19
  });
57
20
 
58
- // 另设表单数据源,避免直接使用传入数据源导致非主动的子影响父
59
- const formConfig = computed(() => {
60
- return Object.keys(props.config).map((key) => {
61
- return {
62
- key,
63
- ...props.config[key],
64
- show:
65
- props.config[key].show === undefined ? true : props.config[key].show, // 默认展示
66
- };
21
+ // 整理合并后的配置项
22
+ const config = computed(() => {
23
+ const result = {};
24
+ Object.keys(defaultConfig).forEach((key) => {
25
+ const oldObj = defaultConfig[key];
26
+ const newObj = props.config[key] ?? {};
27
+ const mergeObj = { ...oldObj, ...newObj };
28
+ result[key] = mergeObj;
67
29
  });
30
+ return result;
31
+ });
32
+ // 选项数据源: 品种市场
33
+ const varietyMarketDict = computed(() => {
34
+ return config.value.varietyMarket.options;
35
+ });
36
+ // 选项数据源: 常用选项
37
+ const commonOptionDict = computed(() => {
38
+ const { varietyMarket } = searchData.value;
39
+ // 如果已选品种市场,仅展示对应子级下的
40
+ if (varietyMarket) {
41
+ const memo = varietyMarketDict.value.find(({ value }) => value === varietyMarket).memo;
42
+ return config.value.commonOption.options.filter(({ value }) => memo.includes(value));
43
+ }
44
+ // 如果未选品种市场,则展示全部
45
+ else {
46
+ return config.value.commonOption.options;
47
+ }
48
+ });
49
+ watch(
50
+ () => commonOptionDict.value,
51
+ (newValue) => {
52
+ // 如果常用选项已经进行了勾选, 则只保留常用选项中存在的值
53
+ if (searchData.value.commonOption.length) {
54
+ searchData.value.commonOption = searchData.value.commonOption.filter((id) => {
55
+ return newValue.find(({ value }) => value === id);
56
+ });
57
+ }
58
+ }
59
+ );
60
+ // 选项数据源: 自定标签
61
+ const customTagDict = computed(() => {
62
+ return config.value.customTag.options;
68
63
  });
69
64
 
70
- const change = (key, value) => {
71
- formData.value = {
72
- ...formData.value,
73
- [key]: value,
65
+ // 函数: 不限
66
+ const clearRow = (key) => {
67
+ if (["commonOption", "customTag", "factorScreen", "commonIndicator"].includes(key)) searchData.value[key] = [];
68
+ else searchData.value[key] = null;
69
+ };
70
+ // 函数: 将组件里面的参数格式化成后端接口所需的入参工具函数
71
+ const formatData = (data) => {
72
+ const params = {};
73
+ // 1.品种市场
74
+ if (data.varietyMarket) {
75
+ params.exchangeId = String(data.varietyMarket);
74
76
  }
75
- emit('change', key, value)
76
- }
77
+ // 2.常用选项
78
+ if (data.commonOption && data.commonOption.length) {
79
+ params.optionId = data.commonOption.join(",");
80
+ }
81
+ // 3.自定标签
82
+ if (data.customTag && data.customTag.length) {
83
+ params.tagIds = data.customTag;
84
+ }
85
+ // 4.因子筛选
86
+ if (data.factorScreen && data.factorScreen.length) {
87
+ params.tbFeatureFactorScores = data.factorScreen.map((item) => {
88
+ return {
89
+ freqId: item.cycle,
90
+ factorId: item.factor,
91
+ startScore: item.score[0],
92
+ endScore: item.score[1],
93
+ };
94
+ });
95
+ }
96
+ // =====================常用指标相关参数处理=====================
97
+ const QIQUANKYES = [
98
+ "expireDays",
99
+ "virtualRealDegree",
100
+ "yearProfitRate",
101
+ "impliedVolatility",
102
+ "levelMultiplier",
103
+ "turnover",
104
+ "volume",
105
+ "openInterest",
106
+ "optionsCpType",
107
+ ];
108
+ // 1.常用指标-基本面( 表中 type: undefined 的指标, [期权]的常用指标不计入基本面)
109
+ const query = data.commonIndicator.reduce((result, item) => {
110
+ const { key, type, range, unit } = item;
111
+ if (type === undefined && !QIQUANKYES.includes(key)) {
112
+ let [start, end] = range;
113
+ if (!["", null].includes(start)) {
114
+ switch (unit[0]) {
115
+ case "亿":
116
+ start = start * 100000000;
117
+ break;
118
+ case "千万":
119
+ start = start * 10000000;
120
+ break;
121
+ default:
122
+ start = start;
123
+ break;
124
+ }
125
+ }
126
+ if (!["", null].includes(end)) {
127
+ switch (unit[1]) {
128
+ case "亿":
129
+ end = end * 100000000;
130
+ break;
131
+ case "千万":
132
+ end = end * 10000000;
133
+ break;
134
+ default:
135
+ end = end;
136
+ break;
137
+ }
138
+ }
139
+ result.push({
140
+ column: item.key,
141
+ start,
142
+ end,
143
+ });
144
+ }
145
+ return result;
146
+ }, []);
147
+ if (query.length) {
148
+ params.query = query;
149
+ }
150
+ // 2.常用指标-是否ST
151
+ const stIndicator = data.commonIndicator.find(({ key }) => key === "st");
152
+ if (stIndicator) {
153
+ params.st = stIndicator.st;
154
+ }
155
+ // 3.常用指标-净利润
156
+ const netProfitQueryDto = data.commonIndicator.find(({ key }) => key === "tFeaturelncomes");
157
+ if (netProfitQueryDto) {
158
+ params.netProfitQueryDto = { ...netProfitQueryDto, netProfit: netProfitQueryDto.netProfit * 100000000.0 };
159
+ }
160
+ // 4.常用指标-期权相关参数
161
+ const searchOptionDto = {};
162
+ data.commonIndicator.forEach((item) => {
163
+ const { key } = item;
164
+ switch (key) {
165
+ // 过期时间
166
+ case "expireDays":
167
+ searchOptionDto.minExpireDays = item.range[0];
168
+ searchOptionDto.maxExpireDays = item.range[1];
169
+ break;
170
+ // 虚实度
171
+ case "virtualRealDegree":
172
+ searchOptionDto.minVirtualRealDegree = item.range[0] / 100;
173
+ searchOptionDto.maxVirtualRealDegree = item.range[1] / 100;
174
+ break;
175
+ // 年化收益率
176
+ case "yearProfitRate":
177
+ searchOptionDto.minYearProfitRate = item.range[0] / 100;
178
+ searchOptionDto.maxYearProfitRate = item.range[1] / 100;
179
+ break;
180
+ // 隐含波动率
181
+ case "impliedVolatility":
182
+ searchOptionDto.minImpliedVolatility = item.range[0] / 100;
183
+ searchOptionDto.maxImpliedVolatility = item.range[1] / 100;
184
+ break;
185
+ // 杠杆率
186
+ case "levelMultiplier":
187
+ searchOptionDto.minLevelMultiplier = item.range[0];
188
+ searchOptionDto.maxLevelMultiplier = item.range[1];
189
+ break;
190
+ // 成交额(期权)
191
+ case "turnover":
192
+ searchOptionDto.minTurnover = item.range[0] * 10000;
193
+ searchOptionDto.maxTurnover = item.range[1] * 10000;
194
+ break;
195
+ // 成交量
196
+ case "volume":
197
+ searchOptionDto.minVolume = item.range[0];
198
+ searchOptionDto.maxVolume = item.range[1];
199
+ break;
200
+ // 持仓量
201
+ case "openInterest":
202
+ searchOptionDto.minOpenInterest = item.range[0];
203
+ searchOptionDto.maxOpenInterest = item.range[1];
204
+ break;
205
+ // 认沽认购
206
+ case "optionsCpType":
207
+ searchOptionDto.optionsCpType = item.optionsCpType;
208
+ break;
209
+ }
210
+ });
211
+ if (Object.keys(searchOptionDto).length) {
212
+ params.searchOptionDto = searchOptionDto;
213
+ }
214
+ return params;
215
+ };
216
+
217
+ defineExpose({ formatData });
77
218
  </script>
78
219
 
220
+ <template>
221
+ <div class="variety-search">
222
+ <!-- 品种市场 -->
223
+ <div v-if="config.varietyMarket?.show" class="variety-search-row">
224
+ <div class="title">
225
+ <span>品种市场: </span>
226
+ <span @click="clearRow('varietyMarket')">不限</span>
227
+ </div>
228
+ <el-radio-group v-model="searchData.varietyMarket" size="small">
229
+ <el-radio v-for="{ label, value } in varietyMarketDict" :label="value" :key="value">{{ label }}</el-radio>
230
+ </el-radio-group>
231
+ </div>
232
+ <!-- 常用选项 -->
233
+ <div v-if="config.commonOption?.show && commonOptionDict.length" class="variety-search-row">
234
+ <div class="title">
235
+ <span>常用选项: </span>
236
+ <span @click="clearRow('commonOption')">不限</span>
237
+ </div>
238
+ <el-checkbox-group v-model="searchData.commonOption" size="small">
239
+ <el-checkbox v-for="{ label, value } in commonOptionDict" :label="value" :key="value">{{ label }}</el-checkbox>
240
+ </el-checkbox-group>
241
+ </div>
242
+ <!-- 自定标签 -->
243
+ <div v-if="config.customTag?.show && customTagDict.length" class="variety-search-row">
244
+ <div class="title">
245
+ <span>自定标签: </span>
246
+ <span @click="clearRow('customTag')">不限</span>
247
+ </div>
248
+ <el-checkbox-group v-model="searchData.customTag" size="small">
249
+ <el-checkbox v-for="{ label, value } in customTagDict" :label="value" :key="value">{{ label }}</el-checkbox>
250
+ </el-checkbox-group>
251
+ </div>
252
+ <!-- 因子筛选 -->
253
+ <div v-if="config.factorScreen?.show" class="variety-search-row">
254
+ <div class="title">
255
+ <span>因子筛选: </span>
256
+ <span @click="clearRow('factorScreen')">不限</span>
257
+ </div>
258
+ <FactorScreen v-model:data="searchData.factorScreen" :config="config.factorScreen" />
259
+ </div>
260
+ <!-- 常用指标 -->
261
+ <CommonIndicator
262
+ v-model:data="searchData.commonIndicator"
263
+ :varietyMarket="searchData.varietyMarket"
264
+ :commonOption="searchData.commonOption"
265
+ :config="config.commonIndicator"
266
+ />
267
+ </div>
268
+ </template>
269
+
79
270
  <style lang="scss" scoped>
80
- .st-VarietySearch {
81
- &-item {
82
- margin-bottom: 5px;
271
+ .variety-search {
272
+ .variety-search-row {
273
+ display: flex;
274
+ .title {
275
+ height: 24px;
276
+ min-width: 100px;
277
+ font-size: 12px;
278
+ line-height: 24px;
279
+ display: flex;
280
+ align-items: center;
281
+ span:nth-child(1) {
282
+ width: 60px;
283
+ }
284
+ span:nth-child(2) {
285
+ cursor: pointer;
286
+ color: var(--el-color-primary);
287
+ }
288
+ }
289
+ .el-radio {
290
+ margin-right: 20px;
291
+ }
292
+ .el-checkbox {
293
+ min-width: 80px;
294
+ margin-right: 20px;
295
+ }
83
296
  }
84
297
  }
85
298
  </style>
@@ -1,69 +1,56 @@
1
1
  <template>
2
- <div style="width: 100%; height: 100%;">
3
- <st-varietySearch
4
- v-model="searchParams"
5
- :config="searchConfig"
6
- @change="changeVarietySearch"
7
- />
2
+ <div style="width: 100%; height: 100%">
3
+ <st-varietySearch ref="varietySearchRef" v-model:searchData="varietySearchData" :config="varietySearchConfig" />
8
4
  </div>
9
5
  </template>
10
6
 
11
7
  <script setup>
12
8
  import { ref, watch, reactive } from "vue";
13
9
 
14
- const searchParams = ref({
15
- exchangeId: [],
16
- optionId: [],
17
- factorscores: [],
18
- queryList: [],
10
+ const varietySearchRef = ref(null);
11
+ const varietySearchData = ref({
12
+ varietyMarket: null, // 品种市场[单选]
13
+ commonOption: [], // 常用选项[多选]
14
+ customTag: [], // 自定标签[多选]
15
+ factorScreen: [], // 因子筛选
16
+ commonIndicator: [], // 常用指标
19
17
  });
20
- const searchConfig = reactive({
21
- exchangeId: {
22
- label: '品种市场',
23
- type: 'checkbox',
24
- options: [
25
- { label: 'A股', value: '0' },
26
- { label: 'ETF', value: '1' },
27
- { label: '期货', value: '2' },
28
- ]
18
+ const varietySearchConfig = ref({
19
+ // 品种市场
20
+ varietyMarket: {
21
+ show: true,
22
+ },
23
+ // 常用选项
24
+ commonOption: {
25
+ show: true,
29
26
  },
30
- optionId: {
31
- label: '常用选项',
32
- type: 'checkbox',
27
+ // 自定标签
28
+ customTag: {
29
+ show: true,
33
30
  options: [
34
- { label: '常用选项1', value: '0' },
35
- { label: '常用选项2', value: '1' },
36
- { label: '常用选项3', value: '2' },
37
- ]
31
+ { label: "自定标签一", value: 1 },
32
+ { label: "自定标签二", value: 2 },
33
+ ],
38
34
  },
39
- factorscores: {
40
- label: '因子筛选',
41
- type: 'factorFilter',
42
- freqList: [
43
- { label: '周期1', value: '0' },
44
- { label: '周期2', value: '1' },
45
- { label: '周期3', value: '2' },
35
+ // 因子筛选
36
+ factorScreen: {
37
+ show: true,
38
+ // cycleDefault: 1,
39
+ cycleOptions: [
40
+ { label: "周期一", value: 1 },
41
+ { label: "周期二", value: 2 },
42
+ ],
43
+ // cycleShow: true,
44
+ factorOptions: [
45
+ { label: "因子一", value: 1 },
46
+ { label: "因子二", value: 2 },
46
47
  ],
47
- factorList: [
48
- { label: '因子1', value: '0' },
49
- { label: '因子2', value: '1' },
50
- { label: '因子3', value: '2' },
51
- ]
52
48
  },
53
- queryList: {
54
- label: '常用指标',
55
- type: 'queryList',
56
- }
57
- })
58
-
59
- // 用于品种联动
60
- const changeVarietySearch = () => {
61
- if (searchParams.value.exchangeId.includes('2')) {
62
- searchConfig.queryList.show = false
63
- } else {
64
- searchConfig.queryList.show = true
65
- }
66
- }
49
+ // 常用指标
50
+ commonIndicator: {
51
+ show: true,
52
+ },
53
+ });
67
54
  </script>
68
55
 
69
56
  <style lang="scss" scoped></style>
@@ -1,77 +0,0 @@
1
- <template>
2
- <div class="st-VarietySearch-checkBox">
3
- <div class="st-VarietySearch-checkBox-label">
4
- {{ config.label }}:
5
- <el-button
6
- text
7
- size="small"
8
- type="primary"
9
- @click="checkList = []"
10
- >
11
- 不限
12
- </el-button>
13
- </div>
14
- <div class="st-VarietySearch-checkBox-content">
15
- <el-checkbox-group
16
- size="small"
17
- v-model="checkList"
18
- >
19
- <el-checkbox
20
- v-for="item in config.options"
21
- :key="item.value"
22
- :label="item.value"
23
- >
24
- {{ item.label }}
25
- </el-checkbox>
26
- </el-checkbox-group>
27
- </div>
28
- </div>
29
- </template>
30
-
31
- <script setup>
32
- import { ref, watch } from 'vue'
33
-
34
- const emit = defineEmits(['change']);
35
- const props = defineProps({
36
- config: {
37
- type: Object,
38
- require: true,
39
- default: () => ({}),
40
- },
41
- formData: {
42
- type: Object,
43
- require: true,
44
- },
45
- })
46
-
47
- const checkList = ref([])
48
-
49
- watch(() => props.formData, () => {
50
- checkList.value = props.formData[props.config.key] || []
51
- }, { deep: true })
52
-
53
- watch(checkList, () => {
54
- emit('change', props.config.key, checkList.value)
55
- })
56
- </script>
57
-
58
- <style lang="scss" scoped>
59
- .st-VarietySearch-checkBox {
60
- &-label {
61
- display: inline-block;
62
- vertical-align: top;
63
- width: 120px;
64
- height: 24px;
65
- line-height: 22px;
66
- font-size: 12px;
67
- &-clear {
68
- color: #409eff;
69
- }
70
- }
71
- &-content {
72
- vertical-align: top;
73
- width: calc(100% - 120px);
74
- display: inline-block;
75
- }
76
- }
77
- </style>