st-comp 0.0.159 → 0.0.161

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.
Files changed (82) hide show
  1. package/components.d.ts +1 -0
  2. package/es/ChartLayout.js +3 -3
  3. package/es/Dialog.js +12 -12
  4. package/es/FactorWarning.cjs +1 -1
  5. package/es/FactorWarning.js +27 -27
  6. package/es/Kline.js +16 -16
  7. package/es/KlineBasic.cjs +1 -1
  8. package/es/KlineBasic.js +248 -251
  9. package/es/KlineNew.js +14 -14
  10. package/es/MonacoEditor.cjs +1 -1
  11. package/es/MonacoEditor.js +7 -2
  12. package/es/Pagination.cjs +1 -1
  13. package/es/Pagination.js +18 -18
  14. package/es/PasswordPrompt.js +3 -3
  15. package/es/Table.cjs +1 -1
  16. package/es/Table.js +196 -347
  17. package/es/User.cjs +1 -1
  18. package/es/User.js +21 -21
  19. package/es/VarietySearch.cjs +3 -1
  20. package/es/VarietySearch.js +4265 -1071
  21. package/es/VirtualTable.js +12 -12
  22. package/es/_commonjsHelpers-10dfc225.js +8 -0
  23. package/es/_commonjsHelpers-87b0abe8.cjs +1 -0
  24. package/es/{_initCloneObject-e3d8a9ab.js → _initCloneObject-7f4a9bd7.js} +3 -3
  25. package/es/{base-19787dfb.js → base-113d028b.js} +7 -7
  26. package/es/{castArray-8405000b.js → castArray-2b3f27ef.js} +1 -1
  27. package/es/{config-provider-0f6672af.js → config-provider-3ffe8f8f.js} +3 -3
  28. package/es/{debounce-6cb0781f.js → debounce-3517a4c7.js} +1 -1
  29. package/es/{dropdown-17b3ef6a.js → dropdown-ee1240ff.js} +4 -4
  30. package/es/{el-button-0bf1d532.js → el-button-de89fb60.js} +4 -4
  31. package/es/{el-checkbox-group-d53bc316.js → el-checkbox-group-17e4156a.js} +2 -2
  32. package/es/{el-empty-bd5343a7.js → el-empty-546e4106.js} +2 -2
  33. package/es/{el-form-item-05c0e335.js → el-form-item-73ecd9af.js} +8 -8
  34. package/es/{el-input-1e309239.js → el-input-c715d419.js} +9 -8
  35. package/es/{el-input-6a3805c5.cjs → el-input-cb340042.cjs} +1 -1
  36. package/es/{el-input-number-60ebc58f.js → el-input-number-02db11f6.js} +13 -13
  37. package/es/{el-input-number-96ff2e47.cjs → el-input-number-0f194f3f.cjs} +1 -1
  38. package/es/{el-menu-item-6c6236a1.js → el-menu-item-67fac653.js} +8 -8
  39. package/es/{el-message-7d927756.js → el-message-2eae949c.js} +7 -7
  40. package/es/{el-overlay-26bf0945.js → el-overlay-f94c4f3b.js} +8 -8
  41. package/es/{el-popover-17e2e66c.js → el-popconfirm-029f2c00.js} +12 -12
  42. package/es/{el-popover-7bd8a7c3.cjs → el-popconfirm-86503f8a.cjs} +1 -1
  43. package/es/{el-popper-b6527ae2.js → el-popper-b34ec18f.js} +9 -9
  44. package/es/{el-scrollbar-29bcab5f.js → el-scrollbar-c463eaff.js} +7 -7
  45. package/es/{el-select-7395562b.js → el-select-b77506ca.js} +13 -13
  46. package/es/{el-table-column-47d80736.js → el-table-column-4aea6b31.js} +12 -12
  47. package/es/{el-tag-7414e0c7.js → el-tag-1cf8487e.js} +3 -3
  48. package/es/index-2da94fd7.js +159 -0
  49. package/es/{index-273822d1.js → index-440d64f2.js} +7 -7
  50. package/es/{index-75cce588.js → index-496e80be.js} +2 -2
  51. package/es/index-58521b9e.cjs +1 -0
  52. package/es/{index-621b092b.js → index-7125c109.js} +1 -1
  53. package/es/{index-dc22ffe4.js → index-a777a57a.js} +2 -2
  54. package/es/{index-72151b24.js → index-dd5d4ae9.js} +6 -6
  55. package/es/{index-c066fe0d.js → index-f393f2d4.js} +3 -3
  56. package/es/{index-70372cdb.js → index-f905d74d.js} +1 -1
  57. package/es/{index-ad9f40cd.cjs → index.vue_vue_type_script_setup_true_lang-4024853c.cjs} +3 -3
  58. package/es/{index-015c420d.js → index.vue_vue_type_script_setup_true_lang-745718ff.js} +5 -9
  59. package/es/{python-81655341.cjs → python-6a3f6816.cjs} +2 -2
  60. package/es/{python-be1bd6d2.js → python-7fcad568.js} +1 -1
  61. package/es/{raf-a532c514.js → raf-5d53429d.js} +1 -1
  62. package/es/{scroll-d787d648.js → scroll-9ec370f4.js} +1 -1
  63. package/es/style.css +1 -1
  64. package/es/{use-form-common-props-5ff2f51b.js → use-form-common-props-d20ca09c.js} +8 -8
  65. package/es/{vnode-6a0c7411.js → vnode-2d8e2f0e.js} +1 -1
  66. package/es/{zh-cn-f37255ae.js → zh-cn-4d2bbda7.js} +2 -2
  67. package/lib/bundle.js +1 -1
  68. package/lib/bundle.umd.cjs +222 -220
  69. package/lib/{index-819ef426.js → index-c0cfb828.js} +45519 -42330
  70. package/lib/{python-4c5a7f20.js → python-4a34bda1.js} +1 -1
  71. package/lib/style.css +1 -1
  72. package/package.json +2 -1
  73. package/packages/VarietySearch/components/CommonIndicator/index.vue +98 -54
  74. package/packages/VarietySearch/components/FactorScreen/ScriptSelect.vue +300 -0
  75. package/packages/VarietySearch/components/FactorScreen/VarietySelect.vue +78 -0
  76. package/packages/VarietySearch/components/FactorScreen/index.vue +123 -21
  77. package/packages/VarietySearch/config.js +49 -0
  78. package/packages/VarietySearch/index.vue +24 -13
  79. package/src/pages/VarietySearch/api.js +70 -0
  80. package/src/pages/VarietySearch/index.vue +83 -109
  81. package/vitePlugins/createExportFile.ts +0 -101
  82. package/vitePlugins/testRelese.ts +0 -67
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "st-comp",
3
3
  "public": true,
4
- "version": "0.0.159",
4
+ "version": "0.0.161",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
@@ -18,6 +18,7 @@
18
18
  "dayjs": "^1.11.10",
19
19
  "echarts": "^5.4.3",
20
20
  "element-plus": "^2.9.4",
21
+ "interactjs": "^1.10.27",
21
22
  "monaco-editor": "0.47.0",
22
23
  "pinia": "^2.1.6",
23
24
  "st-func": "^0.0.59",
@@ -3,12 +3,18 @@
3
3
  import { ref, watch, computed } from "vue";
4
4
 
5
5
  const perVolumnRadioOptions = [
6
- { label: '近2周', value: '1' },
7
- { label: '近1个月', value: '2' },
8
- { label: '近3个月', value: '3' },
9
- { label: '近6个月', value: '4' },
10
- { label: '近1年', value: '5' },
11
- ]
6
+ { label: "近2周", value: "1" },
7
+ { label: "近1个月", value: "2" },
8
+ { label: "近3个月", value: "3" },
9
+ { label: "近6个月", value: "4" },
10
+ { label: "近1年", value: "5" },
11
+ ];
12
+ const auditOpinionTypeRadioOptions = [
13
+ { label: "无保留意见", value: 1 },
14
+ { label: "保留意见", value: 2 },
15
+ { label: "否定意见", value: 3 },
16
+ { label: "无法表示意见", value: 4 },
17
+ ];
12
18
 
13
19
  const data = defineModel("data", { default: [] });
14
20
  const props = defineProps({
@@ -18,8 +24,8 @@ const props = defineProps({
18
24
  });
19
25
  const visible = ref(false);
20
26
  const rankKey = computed(() => {
21
- return props.data.find(i => i.radioType === '1')?.key;
22
- })
27
+ return props.data.find((i) => i.radioType === "1")?.key;
28
+ });
23
29
 
24
30
  // 常用指标项数据源 [受到: 品种市场, 常用选项影响]
25
31
  const commonIndicatorOptions = computed(() => {
@@ -106,19 +112,24 @@ const clickIndicator = (item) => {
106
112
  case "mainFlow": {
107
113
  indicatorValue.value = {
108
114
  ...baseParams,
109
- radioType: '0',
115
+ radioType: "0",
110
116
  rankRange: [null, null],
111
117
  };
112
118
  break;
113
119
  }
120
+ // 年报审计意见
121
+ case "auditOpinionType": {
122
+ indicatorValue.value = { ...baseParams, enumType: null };
123
+ break;
124
+ }
114
125
  // 其它的通用处理
115
126
  default: {
116
127
  indicatorValue.value = {
117
128
  ...baseParams,
118
129
  range: [null, null],
119
130
  unit: item.defaultUnit.length ? [...item.defaultUnit] : [null, null],
120
- radioType: rankKey.value && rankKey.value !== item.key ? '0' : item.defaultRadioType, // 0数值 1排名
121
- rankRange: item.defaultRankRange || [null, null],// 默认排名
131
+ radioType: rankKey.value && rankKey.value !== item.key ? "0" : item.defaultRadioType, // 0数值 1排名
132
+ rankRange: item.defaultRankRange || [null, null], // 默认排名
122
133
  };
123
134
  }
124
135
  }
@@ -182,68 +193,69 @@ const submitDialog = () => {
182
193
  if (!radio) return ElMessage.warning("格式错误: 请选择时间");
183
194
  if (!levels?.length) return ElMessage.warning("格式错误: 请选择分位");
184
195
  // 格式化文案
185
- indicatorValue.value.tagText = `${label}: ${
186
- perVolumnRadioOptions.find(item => item.value === radio)?.label
187
- }${
188
- levels.map(i => `${i}分位`).join('、')
189
- }`;
196
+ indicatorValue.value.tagText = `${label}: ${perVolumnRadioOptions.find((item) => item.value === radio)?.label}${levels.map((i) => `${i}分位`).join("、")}`;
190
197
  break;
191
198
  }
192
199
  // 主力净流入资金
193
200
  case "mainFlow": {
194
201
  const { label, radioType, radio, rankRange } = indicatorValue.value;
195
202
  const checkNumber = (val) => {
196
- if (val === '' || val === null || val === undefined) return false;
197
- const num = Number(val)
203
+ if (val === "" || val === null || val === undefined) return false;
204
+ const num = Number(val);
198
205
  if (isNaN(num)) return false;
199
- return true
200
- }
206
+ return true;
207
+ };
201
208
  // 校验
202
209
  if (!radio) return ElMessage.warning("格式错误: 请选择时间");
203
210
  if (!checkNumber(rankRange[0]) && !checkNumber(rankRange[1])) {
204
- return ElMessage.warning(`格式错误: 请填写${radioType === '0' ? '涨幅范围' : '排名范围'}`);
211
+ return ElMessage.warning(`格式错误: 请填写${radioType === "0" ? "涨幅范围" : "排名范围"}`);
205
212
  }
206
213
  // 格式化文案
207
214
  if (!["", null].includes(rankRange[0]) && !["", null].includes(rankRange[1])) {
208
- indicatorValue.value.tagText = `${label}: ${radio}日${
209
- radioType === '0' ? '涨幅范围' : '排名范围'
210
- }: ${rankRange[0]}${radioType === '0' ? '%' : ''} ~ ${rankRange[1]}${radioType === '0' ? '%' : ''}`;
215
+ indicatorValue.value.tagText = `${label}: ${radio}日${radioType === "0" ? "涨幅范围" : "排名范围"}: ${rankRange[0]}${radioType === "0" ? "%" : ""} ~ ${rankRange[1]}${
216
+ radioType === "0" ? "%" : ""
217
+ }`;
211
218
  } else if (!["", null].includes(rankRange[0])) {
212
- indicatorValue.value.tagText = `${label}: ${radio}日${
213
- radioType === '0' ? '涨幅范围' : '排名范围'
214
- }: ≥${rankRange[0]}${radioType === '0' ? '%' : ''}`;
219
+ indicatorValue.value.tagText = `${label}: ${radio}日${radioType === "0" ? "涨幅范围" : "排名范围"}: ≥${rankRange[0]}${radioType === "0" ? "%" : ""}`;
215
220
  } else {
216
- indicatorValue.value.tagText = `${label}: ${radio}日${
217
- radioType === '0' ? '涨幅范围' : '排名范围'
218
- }: ≤${rankRange[1]}${radioType === '0' ? '%' : ''}`;
221
+ indicatorValue.value.tagText = `${label}: ${radio}日${radioType === "0" ? "涨幅范围" : "排名范围"}: ≤${rankRange[1]}${radioType === "0" ? "%" : ""}`;
219
222
  }
220
223
  break;
221
224
  }
225
+ // 年报审计意见
226
+ case "auditOpinionType": {
227
+ const { label, enumType } = indicatorValue.value;
228
+ // 校验
229
+ if (enumType === null) return ElMessage.warning("格式错误: 请至少选择一个值");
230
+ // 格式化文案
231
+ indicatorValue.value.tagText = `${label}: ${auditOpinionTypeRadioOptions.find((item) => item.value === enumType)?.label}`;
232
+ break;
233
+ }
222
234
  // 其它的通用处理
223
235
  default: {
224
236
  const { label, unit, radioType } = indicatorValue.value;
225
- const range = radioType === '1' ? indicatorValue.value.rankRange : indicatorValue.value.range;
237
+ const range = radioType === "1" ? indicatorValue.value.rankRange : indicatorValue.value.range;
226
238
  // 校验
227
239
  if (["", null].includes(range[0]) && ["", null].includes(range[1])) {
228
240
  return ElMessage.warning("格式错误: 请至少填写一个值");
229
241
  }
230
242
  // 排名校验
231
- if (radioType === '1') {
232
- const rangeLeft = Number(range[0])
233
- const rangeRight = Number(range[1])
243
+ if (radioType === "1") {
244
+ const rangeLeft = Number(range[0]);
245
+ const rangeRight = Number(range[1]);
234
246
  if (isNaN(rangeLeft) || isNaN(rangeRight)) return ElMessage.warning("格式错误: 请填写数字");
235
247
  if (rangeLeft < 0 || rangeRight < 0) return ElMessage.warning("格式错误: 请填写大于0的数字");
236
248
  if (rangeLeft > rangeRight) return ElMessage.warning("格式错误: 请填写正确的排名范围");
237
249
  }
238
- const unitLeft = radioType === '1' ? "" : (unit[0] ?? "")
239
- const unitRight = radioType === '1' ? "" : (unit[1] ?? "")
250
+ const unitLeft = radioType === "1" ? "" : unit[0] ?? "";
251
+ const unitRight = radioType === "1" ? "" : unit[1] ?? "";
240
252
  // 格式化文案
241
253
  if (!["", null].includes(range[0]) && !["", null].includes(range[1])) {
242
- indicatorValue.value.tagText = `${label}${radioType === '1' ? '排名' : ''}: ${range[0]}${unitLeft} ~ ${range[1]}${unitRight}`;
254
+ indicatorValue.value.tagText = `${label}${radioType === "1" ? "排名" : ""}: ${range[0]}${unitLeft} ~ ${range[1]}${unitRight}`;
243
255
  } else if (!["", null].includes(range[0])) {
244
- indicatorValue.value.tagText = `${label}${radioType === '1' ? '排名' : ''}: ≥${range[0]}${unitLeft}`;
256
+ indicatorValue.value.tagText = `${label}${radioType === "1" ? "排名" : ""}: ≥${range[0]}${unitLeft}`;
245
257
  } else {
246
- indicatorValue.value.tagText = `${label}${radioType === '1' ? '排名' : ''}: ≤${range[1]}${unitRight}`;
258
+ indicatorValue.value.tagText = `${label}${radioType === "1" ? "排名" : ""}: ≤${range[1]}${unitRight}`;
247
259
  }
248
260
  }
249
261
  }
@@ -331,7 +343,7 @@ watch(
331
343
  const changeMainFlowRadioType = () => {
332
344
  indicatorValue.value.radio = null;
333
345
  indicatorValue.value.rankRange = [null, null];
334
- }
346
+ };
335
347
  </script>
336
348
 
337
349
  <template>
@@ -380,28 +392,48 @@ const changeMainFlowRadioType = () => {
380
392
  align-center
381
393
  destroy-on-close
382
394
  >
383
- <template #header v-if="nowIndicator.showRankType">
384
- <span style="font-size: 18px;">{{ nowIndicator.label }}</span>
395
+ <template
396
+ #header
397
+ v-if="nowIndicator.showRankType"
398
+ >
399
+ <span style="font-size: 18px">{{ nowIndicator.label }}</span>
385
400
  <el-radio-group
386
401
  v-model="indicatorValue.radioType"
387
- style="vertical-align: 4px; margin-left: 12px;"
402
+ style="vertical-align: 4px; margin-left: 12px"
388
403
  >
389
- <el-radio-button label="数值" value="0" />
390
- <el-radio-button :disabled="rankKey && rankKey !== nowIndicator.key" label="排名" value="1" />
404
+ <el-radio-button
405
+ label="数值"
406
+ value="0"
407
+ />
408
+ <el-radio-button
409
+ :disabled="rankKey && rankKey !== nowIndicator.key"
410
+ label="排名"
411
+ value="1"
412
+ />
391
413
  </el-radio-group>
392
414
  </template>
393
- <template #header v-else-if="nowIndicator.key === 'mainFlow'">
394
- <span style="font-size: 18px;">{{ nowIndicator.label }}</span>
415
+ <template
416
+ #header
417
+ v-else-if="nowIndicator.key === 'mainFlow'"
418
+ >
419
+ <span style="font-size: 18px">{{ nowIndicator.label }}</span>
395
420
  <el-radio-group
396
421
  v-model="indicatorValue.radioType"
397
- style="vertical-align: 4px; margin-left: 12px;"
422
+ style="vertical-align: 4px; margin-left: 12px"
398
423
  @change="changeMainFlowRadioType"
399
424
  >
400
- <el-radio-button label="涨幅范围" value="0" />
401
- <el-radio-button :disabled="rankKey && rankKey !== nowIndicator.key" label="排名范围" value="1" />
425
+ <el-radio-button
426
+ label="涨幅范围"
427
+ value="0"
428
+ />
429
+ <el-radio-button
430
+ :disabled="rankKey && rankKey !== nowIndicator.key"
431
+ label="排名范围"
432
+ value="1"
433
+ />
402
434
  </el-radio-group>
403
435
  </template>
404
-
436
+
405
437
  <template v-if="nowIndicator.type === undefined && indicatorValue.radioType === '1'">
406
438
  <!-- 输入框区域 -->
407
439
  <div class="out-box">
@@ -584,7 +616,8 @@ const changeMainFlowRadioType = () => {
584
616
  v-for="item in perVolumnRadioOptions"
585
617
  :key="item.value"
586
618
  :value="item.value"
587
- >{{ item.label }}</el-radio>
619
+ >{{ item.label }}</el-radio
620
+ >
588
621
  </el-radio-group>
589
622
  <el-select
590
623
  v-model="indicatorValue.levels"
@@ -609,8 +642,8 @@ const changeMainFlowRadioType = () => {
609
642
  <el-radio value="10">10日</el-radio>
610
643
  <el-radio value="20">20日</el-radio>
611
644
  </el-radio-group>
612
- <div style="display: flex; align-items: center;">
613
- <span>{{ indicatorValue.radioType === '0' ? '涨幅范围' : '排名范围' }}:&nbsp;</span>
645
+ <div style="display: flex; align-items: center">
646
+ <span>{{ indicatorValue.radioType === "0" ? "涨幅范围" : "排名范围" }}:&nbsp;</span>
614
647
  <el-input
615
648
  v-model="indicatorValue.rankRange[0]"
616
649
  style="flex: 1"
@@ -622,6 +655,17 @@ const changeMainFlowRadioType = () => {
622
655
  />
623
656
  </div>
624
657
  </div>
658
+ <!-- 年报审计意见 -->
659
+ <div v-if="nowIndicator.key === 'auditOpinionType'">
660
+ <el-radio-group v-model="indicatorValue.enumType">
661
+ <el-radio
662
+ v-for="(item, index) in auditOpinionTypeRadioOptions"
663
+ :key="index"
664
+ :label="item.label"
665
+ :value="item.value"
666
+ />
667
+ </el-radio-group>
668
+ </div>
625
669
  </template>
626
670
  <!-- 确定 -->
627
671
  <template #footer>
@@ -0,0 +1,300 @@
1
+ <script setup>
2
+ import interact from "interactjs";
3
+ import { computed, onMounted, ref, inject } from "vue";
4
+ import { Close, InfoFilled } from "@element-plus/icons-vue";
5
+ import VarietySelect from './VarietySelect.vue'
6
+
7
+ const stConfig = inject("stConfig");
8
+
9
+ const dialogRef = ref(null); // 弹窗主体Ref
10
+ const dialogTop = ref((window.innerHeight - 542) / 2 - 220 > 0 ? (window.innerHeight - 542) / 2 - 220 : 0);
11
+ const dialogRight = ref((window.innerWidth - 1000) / 2 > 0 ? (window.innerWidth - 1000) / 2 : 0);
12
+
13
+ const editorRef = ref(null); // 编辑器Ref
14
+ const visible = ref(false);
15
+
16
+ const varName = ref(null);
17
+ const varList = ref([]);
18
+ const formatList = computed(() => {
19
+ return varList.value.find((item) => item.varName === varName.value)?.formatList ?? [];
20
+ });
21
+
22
+ // 格式化配置项的下拉框数据源
23
+ const handleOptionsStrToArray = (str) => {
24
+ const trimmedStr = str.replace(/^\[|\]$/g, "");
25
+ // 分割字符串为多个数组项
26
+ const items = trimmedStr.split("],[");
27
+
28
+ return items.map((item) => {
29
+ // 移除每个项两端的方括号(如果有)
30
+ const cleanItem = item.replace(/\[|\]/g, "");
31
+ // 分割标签和值
32
+ const [label, value] = cleanItem.split(",");
33
+
34
+ return {
35
+ label: label.trim(),
36
+ value: value.trim(),
37
+ };
38
+ });
39
+ };
40
+
41
+ // 插入变量值
42
+ const handleInsetVarContent = (configList) => {
43
+ // 1.校验是否填写完整 + 生成输出值
44
+ const result = [];
45
+ for (let index = 0; index < configList.length; index++) {
46
+ const item = configList[index];
47
+ console.log(item)
48
+ switch (item.vtype) {
49
+ case "text": {
50
+ result.push(item.param);
51
+ break;
52
+ }
53
+ default: {
54
+ if (!item.modelValue) return ElMessage.error("请检查插入格式内是否填写完整");
55
+ result.push(item.suffix ? `${item.modelValue}${item.suffix}` : `${item.modelValue}`);
56
+ break;
57
+ }
58
+ }
59
+ }
60
+ // 2.插入内容
61
+ const content = result.join("_");
62
+
63
+ const editorIns = editorRef.value.getInstance();
64
+ const position = editorIns.getPosition();
65
+
66
+ const currentValue = editorRef.value.getValue();
67
+ const lines = currentValue.split("\n");
68
+ // 如果光标位置有效
69
+ if (position.lineNumber <= lines.length) {
70
+ const lineIndex = position.lineNumber - 1;
71
+ const line = lines[lineIndex];
72
+
73
+ // 在光标位置插入内容
74
+ const newLine = line.substring(0, position.column - 1) + content + line.substring(position.column - 1);
75
+ lines[lineIndex] = newLine;
76
+
77
+ // 更新编辑器内容
78
+ const newValue = lines.join("\n");
79
+ editorRef.value.setValue(newValue);
80
+
81
+ // 将光标移动到插入内容之后
82
+ const newColumn = position.column + content.length;
83
+ editorIns.setPosition({
84
+ lineNumber: position.lineNumber,
85
+ column: newColumn,
86
+ });
87
+ editorIns.focus();
88
+ }
89
+ };
90
+
91
+ onMounted(async () => {
92
+ const { body } = await stConfig.request.post('/common/conf/queryAllBackVariables', { useCase: "2" });
93
+ varList.value = body;
94
+ });
95
+ defineExpose({
96
+ open: (editor) => {
97
+ editorRef.value = editor;
98
+ visible.value = true;
99
+ // 支持拖拽
100
+ const dragArea = document.querySelector("body");
101
+ interact(dialogRef.value).draggable({
102
+ allowFrom: ".custom-header", // 只有 .custom-header 元素可以触发拖拽
103
+ // 限制拖拽范围
104
+ modifiers: [
105
+ interact.modifiers.restrictRect({
106
+ restriction: dragArea, // 限制在拖拽区域内
107
+ endOnly: false, // 实时限制
108
+ }),
109
+ ],
110
+ listeners: {
111
+ move(event) {
112
+ dialogRight.value -= event.dx;
113
+ dialogTop.value += event.dy;
114
+ },
115
+ },
116
+ });
117
+ },
118
+ close: () => {
119
+ visible.value = false;
120
+ }
121
+ });
122
+ </script>
123
+
124
+ <template>
125
+ <div
126
+ v-show="visible"
127
+ class="var-select-dialog"
128
+ ref="dialogRef"
129
+ :style="{ right: `${dialogRight}px`, top: `${dialogTop}px` }"
130
+ >
131
+ <div class="custom-header">
132
+ <div class="left">
133
+ <span> 选择变量 </span>
134
+ <el-select
135
+ v-model="varName"
136
+ placeholder="选择变量"
137
+ filterable
138
+ clearable
139
+ >
140
+ <el-option
141
+ v-for="(item, index) in varList"
142
+ :key="index"
143
+ :label="item.varName"
144
+ :value="item.varName"
145
+ />
146
+ </el-select>
147
+ </div>
148
+ <div class="right">
149
+ <el-icon
150
+ class="el-icon--left"
151
+ @click="visible = false"
152
+ >
153
+ <Close />
154
+ </el-icon>
155
+ </div>
156
+ </div>
157
+ <div class="custom-body">
158
+ <template v-if="formatList.length">
159
+ <div
160
+ class="format-item"
161
+ v-for="(formatItem, formatIndex) in formatList"
162
+ :key="formatIndex"
163
+ >
164
+ <span>格式{{ formatIndex + 1 }}:</span>
165
+
166
+ <!-- 配置项 -->
167
+ <div class="config-list">
168
+ <template v-for="(config, configIndex) in formatItem.configList">
169
+ <div class="config-item">
170
+ <!-- 类型: 固定值 -->
171
+ <template v-if="config.vtype === 'text'">
172
+ <span>{{ config.param }}</span>
173
+ </template>
174
+ <template v-if="config.vtype === 'inputVariety'">
175
+ <VarietySelect
176
+ size="small"
177
+ :placeholder="config.param"
178
+ :selectClearEnable="false"
179
+ :labelShowEnable="false"
180
+ @select="({ name, code }) => (config.modelValue = code)"
181
+ @change="(value) => (config.modelValue = value)"
182
+ style="width: 100px"
183
+ />
184
+ </template>
185
+ <template v-if="config.vtype === 'input'">
186
+ <el-input
187
+ v-model="config.modelValue"
188
+ :placeholder="config.param"
189
+ size="small"
190
+ />
191
+ <span v-if="config.suffix">{{ config.suffix }}</span>
192
+ </template>
193
+ <template v-if="config.vtype === 'select'">
194
+ <el-select
195
+ v-model="config.modelValue"
196
+ :placeholder="config.param"
197
+ clearable
198
+ size="small"
199
+ >
200
+ <el-option
201
+ v-for="item in handleOptionsStrToArray(config.optionsStr)"
202
+ :key="item.value"
203
+ :label="item.label"
204
+ :value="item.value"
205
+ />
206
+ </el-select>
207
+ </template>
208
+ </div>
209
+ <span v-if="configIndex !== formatItem.configList.length - 1">_</span>
210
+ </template>
211
+ </div>
212
+ <!-- 插入变量 -->
213
+ <el-button
214
+ type="primary"
215
+ plain
216
+ size="small"
217
+ @click="handleInsetVarContent(formatItem.configList)"
218
+ >
219
+ 插入变量
220
+ </el-button>
221
+ <!-- Tip示例 -->
222
+ <el-tooltip
223
+ effect="dark"
224
+ :content="formatItem.tip"
225
+ placement="top-start"
226
+ >
227
+ <el-icon><InfoFilled /></el-icon>
228
+ </el-tooltip>
229
+ </div>
230
+ </template>
231
+ </div>
232
+ </div>
233
+ </template>
234
+
235
+ <style lang="scss" scoped>
236
+ .var-select-dialog {
237
+ min-width: 660px;
238
+ max-width: 1000px;
239
+ border-radius: 4px;
240
+ box-sizing: border-box;
241
+ box-shadow: var(--el-box-shadow-light);
242
+ background-color: var(--el-bg-color);
243
+ z-index: 2006;
244
+ position: fixed;
245
+ .custom-header {
246
+ display: flex;
247
+ align-items: center;
248
+ justify-content: space-between;
249
+ padding: 10px;
250
+ .left {
251
+ display: flex;
252
+ align-items: center;
253
+ flex: 1;
254
+ span {
255
+ margin-right: 10px;
256
+ }
257
+ .el-select {
258
+ width: 140px;
259
+ }
260
+ }
261
+ .right {
262
+ display: flex;
263
+ align-items: center;
264
+ .el-button {
265
+ margin-right: 10px;
266
+ }
267
+ .el-icon {
268
+ cursor: pointer;
269
+ &:hover {
270
+ color: var(--el-color-primary);
271
+ }
272
+ }
273
+ }
274
+ }
275
+ .custom-body {
276
+ min-height: 160px;
277
+ box-sizing: border-box;
278
+ border-top: var(--el-border);
279
+ padding: 20px 10px;
280
+ .format-item {
281
+ font-size: 12px;
282
+ display: flex;
283
+ align-items: center;
284
+ flex-wrap: wrap;
285
+ gap: 10px;
286
+ margin-bottom: 10px;
287
+ .config-list {
288
+ display: flex;
289
+ align-items: center;
290
+ .el-input {
291
+ width: 100px;
292
+ }
293
+ .el-select {
294
+ width: 100px;
295
+ }
296
+ }
297
+ }
298
+ }
299
+ }
300
+ </style>
@@ -0,0 +1,78 @@
1
+ <!-- 组件: 品种自动补全搜索 -->
2
+ <script setup>
3
+ import { ref, inject } from "vue";
4
+ import { getUserData } from "st-func";
5
+
6
+ const stConfig = inject("stConfig");
7
+
8
+ const emit = defineEmits(["select", "change"]);
9
+ const props = defineProps({
10
+ size: { type: String, default: "default" },
11
+ placeholder: { type: String, default: "请输入品种名称或代码" },
12
+ labelShowEnable: { type: Boolean, default: true }, // 是否开启展示label
13
+ selectClearEnable: { type: Boolean, default: true }, // 是否开启选择回调后清除输入框值
14
+ });
15
+
16
+ const inputValue = ref("");
17
+ const fetchSuggestions = async (value, callback) => {
18
+ if (value === "" || value === "null") {
19
+ callback([]);
20
+ } else {
21
+ const params = {
22
+ keyWord: value,
23
+ pageNum: 1,
24
+ pageSize: 999,
25
+ userId: getUserData("id"),
26
+ hotSearchFlag: 1,
27
+ };
28
+ const { body } = await stConfig.request.post("/common/qt/getFeatureInfosByPage", params);
29
+ const result = body.list.map(({ code, featureName }) => ({
30
+ label: `${code}\xa0\xa0\xa0${featureName}`,
31
+ value: code,
32
+ }));
33
+ callback(result);
34
+ }
35
+ };
36
+ const handleSelect = ({ label, value }) => {
37
+ const name = label.split("\xa0").at(-1);
38
+ const code = value;
39
+ emit("select", { name, code });
40
+ if (props.selectClearEnable) inputValue.value = "";
41
+ };
42
+ const handleChange = (value) => {
43
+ emit("change", value);
44
+ }
45
+ </script>
46
+
47
+ <template>
48
+ <div class="variety-auto-complete">
49
+ <span v-if="labelShowEnable">品种搜索:</span>
50
+ <el-autocomplete
51
+ v-model="inputValue"
52
+ clearable
53
+ :size="props.size"
54
+ :placeholder="props.placeholder"
55
+ :fetch-suggestions="fetchSuggestions"
56
+ @select="handleSelect"
57
+ @change="handleChange"
58
+ >
59
+ <template #default="{ item }">
60
+ <div class="label">{{ item.label }}</div>
61
+ </template>
62
+ </el-autocomplete>
63
+ </div>
64
+ </template>
65
+
66
+ <style lang="scss" scoped>
67
+ .variety-auto-complete {
68
+ width: 100%;
69
+ display: flex;
70
+ align-items: center;
71
+ span {
72
+ width: 80px;
73
+ }
74
+ .el-autocomplete {
75
+ flex: 1;
76
+ }
77
+ }
78
+ </style>