st-comp 0.0.21 → 0.0.22

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.
@@ -0,0 +1,449 @@
1
+ <template>
2
+ <div>
3
+ <span>{{ props.label }}</span>
4
+ <el-button text type="primary" size="small" @click="clean">
5
+ 不限
6
+ </el-button>
7
+ <el-button
8
+ v-for="button in orderByInfoList"
9
+ :key="button.id"
10
+ size="small"
11
+ text
12
+ @click="
13
+ () => {
14
+ // 从新设置制空选中状态,在打开弹窗
15
+ button.children.forEach((item) => {
16
+ item.active = false;
17
+ });
18
+ openModal(button);
19
+ }
20
+ "
21
+ >
22
+ {{ button.dictName }}
23
+ </el-button>
24
+ <el-popover :visible="visible" :width="500" :show-arrow="false">
25
+ <div class="title">
26
+ {{ title }}
27
+ </div>
28
+ <div
29
+ v-if="visible"
30
+ :style="`width: 450px;margin: 20px auto;display: flex;flex-wrap: wrap;justify-content:flex-start;
31
+ ${
32
+ column !== 'tFeaturelncomes' ? 'justify-content:space-between;' : ''
33
+ } };`"
34
+ >
35
+ <el-button
36
+ v-for="formItem in orderByInfoObj.children"
37
+ :key="formItem.id"
38
+ class="btn"
39
+ :type="formItem.active ? 'primary' : ''"
40
+ :style="`margin-right:15px;width: ${
41
+ formItem.width ? formItem.width : 120
42
+ }px;}`"
43
+ @click="
44
+ () => {
45
+ ase = formItem.ase;
46
+ start = formItem.start;
47
+ end = formItem.end;
48
+ unitObj.startUnit = formItem.startUnit;
49
+ unitObj.endUnit = formItem.endUnit;
50
+ const list = orderByInfoObj.children.map((item) => ({
51
+ ...item,
52
+ active: item.id === formItem.id ? true : false,
53
+ }));
54
+ orderByInfoObj.children = list;
55
+ if (column === 'tFeaturelncomes') {
56
+ tFeaturelncomes.yearsCount = formItem.yearsCount;
57
+ tFeaturelncomes.netProfit = formItem.netProfit;
58
+ tFeaturelncomes.withFewYears = formItem.withFewYears;
59
+ tFeaturelncomes.rule = formItem.rule;
60
+ }
61
+ }
62
+ "
63
+ >
64
+ {{ formItem.btnText }}
65
+ </el-button>
66
+ <div v-if="column === 'st'">
67
+ <el-radio-group v-model="hasSt">
68
+ <el-radio :label="0"> 否 </el-radio>
69
+ <el-radio :label="1"> 是 </el-radio>
70
+ </el-radio-group>
71
+ </div>
72
+ <div v-if="column !== 'st' && column !== 'tFeaturelncomes'">
73
+ <el-space style="width: 100%; margin: 20px 0; text-align: start">
74
+ <span>自定义:</span>
75
+ <el-input
76
+ v-model="start"
77
+ style="width: 150px"
78
+ @input="
79
+ () => {
80
+ orderByInfoObj.children = orderByInfoObj.children.map(
81
+ (item) => ({
82
+ ...item,
83
+ active: false,
84
+ })
85
+ );
86
+ }
87
+ "
88
+ @change="
89
+ (val) => {
90
+ start = val.replace(/\D/g, '');
91
+ }
92
+ "
93
+ >
94
+ <template #append v-if="column !== 'pb' && column !== 'peTtm'">
95
+ <el-select
96
+ v-model="unitObj.startUnit"
97
+ :style="{ width: '75px' }"
98
+ placeholder=""
99
+ >
100
+ <el-option
101
+ v-for="item in unitOpt"
102
+ :key="item.value"
103
+ :label="item.label"
104
+ :value="item.value"
105
+ />
106
+ </el-select>
107
+ </template>
108
+ </el-input>
109
+ <span>~</span>
110
+ <el-input
111
+ v-model="end"
112
+ controls-position="right"
113
+ style="width: 150px"
114
+ @input="
115
+ () => {
116
+ orderByInfoObj.children = orderByInfoObj.children.map(
117
+ (item) => ({
118
+ ...item,
119
+ active: false,
120
+ })
121
+ );
122
+ }
123
+ "
124
+ @change="
125
+ (val) => {
126
+ end = val.replace(/\D/g, '');
127
+ }
128
+ "
129
+ >
130
+ <template #append v-if="column !== 'pb' && column !== 'peTtm'">
131
+ <el-select
132
+ v-model="unitObj.endUnit"
133
+ :style="{ width: '75px' }"
134
+ placeholder=""
135
+ >
136
+ <el-option
137
+ v-for="item in unitOpt"
138
+ :key="item.value"
139
+ :label="item.label"
140
+ :value="item.value"
141
+ />
142
+ </el-select>
143
+ </template>
144
+ </el-input>
145
+ </el-space>
146
+ </div>
147
+ <div v-if="column === 'tFeaturelncomes'" style="margin-top: 20px">
148
+ <span>自定义:</span>
149
+ <el-input-number
150
+ v-model="tFeaturelncomes.withFewYears"
151
+ size="small"
152
+ :min="-9999999"
153
+ :max="9999999"
154
+ controls-position="right"
155
+ style="width: 70px"
156
+ @change="
157
+ () => {
158
+ orderByInfoObj.children = orderByInfoObj.children.map(
159
+ (item) => ({ ...item, active: false })
160
+ );
161
+ }
162
+ "
163
+ />
164
+ <span> 年内 </span>
165
+ <el-input-number
166
+ v-model="tFeaturelncomes.yearsCount"
167
+ size="small"
168
+ :min="0"
169
+ :max="9999999"
170
+ controls-position="right"
171
+ style="width: 70px"
172
+ @change="
173
+ () => {
174
+ orderByInfoObj.children = orderByInfoObj.children.map(
175
+ (item) => ({ ...item, active: false })
176
+ );
177
+ }
178
+ "
179
+ />
180
+ <span> 年以上盈利超过 </span>
181
+ <el-input-number
182
+ v-model="tFeaturelncomes.netProfit"
183
+ size="small"
184
+ :min="0"
185
+ :max="9999999"
186
+ controls-position="right"
187
+ style="width: 80px"
188
+ @change="
189
+ () => {
190
+ orderByInfoObj.children = orderByInfoObj.children.map(
191
+ (item) => ({ ...item, active: false })
192
+ );
193
+ }
194
+ "
195
+ />
196
+ <span> 亿</span>
197
+ </div>
198
+ </div>
199
+ <div class="card-bottom">
200
+ <el-button style="margin-right: 15px" @click="closeModal">
201
+ 取消
202
+ </el-button>
203
+ <el-button type="primary" @click="confirmOk"> 确认 </el-button>
204
+ </div>
205
+ <template #reference>
206
+ <div />
207
+ </template>
208
+ </el-popover>
209
+ <slot>
210
+ <el-tag
211
+ v-for="(item, i) in queryList"
212
+ :key="item.id"
213
+ closable
214
+ type="info"
215
+ :disable-transitions="false"
216
+ @close="handleClose(item)"
217
+ style="margin-right: 5px"
218
+ >
219
+ <span>{{ item.dictName }}:</span>
220
+ <span v-if="item.column === 'st'">
221
+ {{ item.hasSt === 1 ? "是" : "否" }}
222
+ </span>
223
+ <span v-else-if="item.column === 'tFeaturelncomes'">
224
+ {{
225
+ item.btnText
226
+ ? item.btnText
227
+ : item.yearsCount
228
+ ? `${item.withFewYears}年内${
229
+ item.yearsCount || "-"
230
+ }年以上盈利超过${item.netProfit}亿`
231
+ : `${item.withFewYears}年内盈利超过${item.netProfit}亿`
232
+ }}
233
+ </span>
234
+ <span v-else>
235
+ {{
236
+ item.start !== null && item.end !== null
237
+ ? `${item.start}${item.startUnit} ~ ${item.end}${item.endUnit}`
238
+ : ""
239
+ }}
240
+ {{
241
+ item.start === null && item.end !== null
242
+ ? `< ${item.end}${item.endUnit}`
243
+ : ""
244
+ }}
245
+ {{
246
+ item.end === null && item.start !== null
247
+ ? `
248
+ ${item.start}${item.startUnit}>`
249
+ : ""
250
+ }}
251
+ {{ item.ase ? `从小到大` : "" }}
252
+ </span>
253
+ <el-text
254
+ style="font-size: 12px; cursor: pointer"
255
+ type="primary"
256
+ @click="() => openModal({ ...item, type: 1 })"
257
+ >
258
+ 修改
259
+ </el-text>
260
+ </el-tag>
261
+ </slot>
262
+ </div>
263
+ </template>
264
+
265
+ <script setup>
266
+ import { ref, computed, reactive, onMounted } from "vue";
267
+ import { orderByInfoFormatFn } from "./index.ts";
268
+ import { cloneDeep } from "lodash";
269
+ const emit = defineEmits(["updata", "update:modelValue"]);
270
+ const props = defineProps({
271
+ label: {
272
+ type: String,
273
+ default: "因子筛选",
274
+ },
275
+ orderByInfoList: {
276
+ type: Array,
277
+ default: [],
278
+ },
279
+ modelValue: {
280
+ type: Array,
281
+ default: [],
282
+ },
283
+ });
284
+
285
+ const orderByInfoList = computed({
286
+ get() {
287
+ return orderByInfoFormatFn(props.orderByInfoList);
288
+ },
289
+ });
290
+ const orderByInfoObj = ref({});
291
+ const visible = ref(false);
292
+ const ase = ref("");
293
+ const title = ref("");
294
+ const hasSt = ref("");
295
+ const start = ref(null);
296
+ const end = ref(null);
297
+ const column = ref("floatMarketCapital");
298
+ const tFeaturelncomes = ref({
299
+ yearsCount: null,
300
+ netProfit: null,
301
+ withFewYears: null,
302
+ rule: null,
303
+ });
304
+ const unitObj = ref({
305
+ startUnit: "亿",
306
+ endUnit: "亿",
307
+ });
308
+ const unitOpt = ref([]);
309
+ const queryList = computed({
310
+ get() {
311
+ return props.modelValue;
312
+ },
313
+ set(val) {
314
+ emit("update:modelValue", val);
315
+ },
316
+ });
317
+ // 打开弹窗
318
+ const openModal = (button) => {
319
+ title.value = button.dictName;
320
+ column.value = button?.key;
321
+ start.value = button.start;
322
+ end.value = button.end;
323
+ tFeaturelncomes.value = {
324
+ yearsCount: button.yearsCount,
325
+ netProfit: button.netProfit,
326
+ withFewYears: button.withFewYears,
327
+ rule: button.rule,
328
+ };
329
+ orderByInfoObj.value = button.type
330
+ ? queryList.value.find((item) => item.id === button.id)
331
+ : orderByInfoList.value.find((item) => item.id === button.id);
332
+ // 设置单位
333
+ if (
334
+ button.key === "turnoverRate" ||
335
+ button.key === "peTtm" ||
336
+ button.key === "pb" ||
337
+ button.key === "roe"
338
+ ) {
339
+ unitOpt.value = [{ id: 1, value: "%", label: "%" }];
340
+ unitObj.value = {
341
+ startUnit: "%",
342
+ endUnit: "%",
343
+ };
344
+ } else if (button.key === "eps") {
345
+ unitOpt.value = [{ id: 1, value: "元", label: "元" }];
346
+ unitObj.value.startUnit = "元";
347
+ unitObj.value.endUnit = "元";
348
+ } else {
349
+ unitOpt.value = [
350
+ { id: 1, value: "元", label: "元" },
351
+ { id: 2, value: "千万", label: "千万" },
352
+ { id: 3, value: "亿", label: "亿" },
353
+ ];
354
+ unitObj.value.startUnit = button.startUnit || "亿";
355
+ unitObj.value.endUnit = button.endUnit || "亿";
356
+ }
357
+ visible.value = true;
358
+ };
359
+ // 关闭
360
+ const closeModal = () => {
361
+ end.value = null;
362
+ start.value = null;
363
+ unitObj.value.startUnit = "亿";
364
+ unitObj.value.endUnit = "亿";
365
+ visible.value = false;
366
+ };
367
+ const confirmOk = () => {
368
+ let hasTFeaturelncomes = false;
369
+ if (column.value === "tFeaturelncomes") {
370
+ if (
371
+ tFeaturelncomes.value.netProfit === null ||
372
+ tFeaturelncomes.value.withFewYears === null
373
+ ) {
374
+ ElMessage.error("请输入必填项");
375
+ return;
376
+ }
377
+ hasTFeaturelncomes = true;
378
+ }
379
+ const data = {
380
+ column: column.value,
381
+ key: column.value,
382
+ id: orderByInfoObj.value.id,
383
+ dictCode: orderByInfoObj.value.id,
384
+ dictId: orderByInfoObj.value.id,
385
+ dictName: orderByInfoObj.value.dictName,
386
+ label: orderByInfoObj.value.dictName,
387
+ ase: ase.value,
388
+ hasSt: hasSt.value,
389
+ start: start.value,
390
+ startUnit: unitObj.value.startUnit,
391
+ end: end.value,
392
+ endUnit: unitObj.value.endUnit,
393
+ btnText: hasTFeaturelncomes ? tFeaturelncomes.value.btnText : null,
394
+ rule: hasTFeaturelncomes ? tFeaturelncomes.value.rule : 1,
395
+ yearsCount: hasTFeaturelncomes ? tFeaturelncomes.value.yearsCount : null,
396
+ netProfit: hasTFeaturelncomes ? tFeaturelncomes.value.netProfit : null,
397
+ withFewYears: hasTFeaturelncomes
398
+ ? tFeaturelncomes.value.withFewYears
399
+ : null,
400
+ children: cloneDeep(orderByInfoObj.value.children),
401
+ };
402
+ visible.value = false;
403
+ const row = queryList.value.find((item) => item.column === data.column);
404
+ if (row) {
405
+ queryList.value = [
406
+ ...queryList.value.filter((item) => item.column !== data.column),
407
+ data,
408
+ ];
409
+ } else {
410
+ queryList.value.push(data);
411
+ }
412
+ };
413
+
414
+ const clean = () => {
415
+ queryList.value = [];
416
+ };
417
+ const handleClose = (row) => {
418
+ queryList.value = queryList.value.filter((item) => item.key !== row.key);
419
+ };
420
+ </script>
421
+
422
+ <style lang="scss" scoped>
423
+ .title {
424
+ font-size: 16px;
425
+ padding-bottom: 5px;
426
+ margin-bottom: 5px;
427
+ border-bottom: 1px solid #6c6e72;
428
+ }
429
+
430
+ .list {
431
+ margin-top: 10px;
432
+ }
433
+
434
+ .card-bottom {
435
+ border-top: 1px solid #6c6e72;
436
+ padding-top: 10px;
437
+ margin-top: 0;
438
+ text-align: right;
439
+ }
440
+
441
+ .btn {
442
+ margin-bottom: 10px;
443
+ width: 120px;
444
+ }
445
+
446
+ .el-button + .el-button {
447
+ margin: 0;
448
+ }
449
+ </style>