st-comp 0.0.210 → 0.0.212

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "st-comp",
3
3
  "public": true,
4
- "version": "0.0.210",
4
+ "version": "0.0.212",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
@@ -11,7 +11,11 @@ const props = defineProps({
11
11
  commonOption: { type: Array, default: () => [] }, // 已选常用选项
12
12
  });
13
13
  const visible = ref(false);
14
- const compositeOrderForm = ref({ name: null, value: "desc" });
14
+ const compositeOrderForm = ref({
15
+ id: null,
16
+ name: null, // 字段名
17
+ value: "desc", // 排序
18
+ });
15
19
 
16
20
  // 组合排序数据源 [受到: 品种市场, 常用选项影响]
17
21
  const compositeOrderOptions = computed(() => {
@@ -41,7 +45,7 @@ const handleAction = (action, index) => {
41
45
  switch (action) {
42
46
  // 新增
43
47
  case "add": {
44
- compositeOrderForm.value = { name: null, value: "desc" };
48
+ compositeOrderForm.value = { id: null, name: null, value: "desc" };
45
49
  visible.value = true;
46
50
  break;
47
51
  }
@@ -54,22 +58,37 @@ const handleAction = (action, index) => {
54
58
  }
55
59
  // 窗口确认
56
60
  case "submit": {
57
- if (!compositeOrderForm.value.name) return ElMessage.warning("请选择需要排序的条件");
58
- const { label } = compositeOrderOptions.value.find((item) => item.key === compositeOrderForm.value.name);
59
- const tagText = `${label}-${compositeOrderForm.value.value === "asc" ? "正序↑" : "降序↓"}`;
60
- // 判断data中是否已存在同字段条件, 是则替换, 否则push
61
- const keyIndex = data.value.findIndex(({ name }) => name === compositeOrderForm.value.name);
62
- if (keyIndex === -1) {
63
- data.value.push({ ...compositeOrderForm.value, tagText });
64
- } else {
65
- data.value.splice(keyIndex, 1, { ...compositeOrderForm.value, tagText });
61
+ const { id, name, value } = compositeOrderForm.value;
62
+ if (!name) return ElMessage.warning("请选择需要排序的条件");
63
+ const { label } = compositeOrderOptions.value.find((item) => item.key === name);
64
+ const tagText = `${label}-${value === "asc" ? "正序↑" : "降序↓"}`;
65
+
66
+ // 新增确认逻辑
67
+ if (id === null) {
68
+ // 判断data中是否已存在同字段条件, 是则替换, 否则push
69
+ const index = data.value.findIndex((item) => item.name === name);
70
+ if (index === -1) {
71
+ data.value.push({ ...compositeOrderForm.value, id: name, tagText });
72
+ } else {
73
+ data.value.splice(index, 1, { ...compositeOrderForm.value, id: name, tagText });
74
+ }
75
+ }
76
+ // 编辑确认逻辑
77
+ else if (compositeOrderForm.value.id) {
78
+ // 修改当前位置的内容, 并将其他相同name的删除掉
79
+ const index = data.value.findIndex((item) => item.name === id);
80
+ const index2 = data.value.findIndex((item) => item.name === name);
81
+ data.value[index] = { ...compositeOrderForm.value, id: name, tagText };
82
+ if (index2 !== -1 && index !== index2) data.value.splice(index2, 1);
66
83
  }
84
+
67
85
  visible.value = false;
68
86
  break;
69
87
  }
70
88
  // 删除
71
89
  case "delete": {
72
90
  data.value.splice(index, 1);
91
+ visible.value = false;
73
92
  break;
74
93
  }
75
94
  }
@@ -84,7 +103,7 @@ watch(
84
103
  return compositeOrderOptions.value.find((item) => item.key === name);
85
104
  });
86
105
  }
87
- }
106
+ },
88
107
  );
89
108
  </script>
90
109
 
@@ -1,11 +1,13 @@
1
1
  <!-- 因子筛选组件 -->
2
2
  <script setup name="FactorScreen">
3
- import { nextTick, ref, watch } from "vue";
4
- import { Close, Plus, CircleCloseFilled, InfoFilled } from "@element-plus/icons-vue";
3
+ import { nextTick, ref, watch, inject, reactive } from "vue";
4
+ import { Close, Plus, CircleCloseFilled, InfoFilled, Document } from "@element-plus/icons-vue";
5
5
  import { handleVerifyScore, extractConditionDetails, extractVariables } from "./tools.js";
6
6
  import FactorDescription from "./FactorDescription.vue";
7
7
  import MonacoEditor from "../../../MonacoEditor/index.vue";
8
8
 
9
+ const { request } = inject("stConfig"); // 组件库全局配置
10
+
9
11
  const props = defineProps({
10
12
  config: {
11
13
  type: Object,
@@ -29,10 +31,20 @@ const data = defineModel("data", {
29
31
 
30
32
  const monacoEditorRef = ref();
31
33
  const stVarSelectDialogRef = ref();
34
+
32
35
  // 弹窗开关
33
36
  const visible = ref(false);
34
37
  const visibleDescriptions = ref(false);
35
38
  const factorType = ref("脚本");
39
+ const scriptTestLoading = ref(false);
40
+ const scriptCopyLoading = ref(false);
41
+ const scriptTestLogVisible = ref(false);
42
+ const scriptTestResult = reactive({
43
+ result: null,
44
+ detail: "",
45
+ code: "",
46
+ });
47
+
36
48
  // 弹窗表单
37
49
  const dialogFormRef = ref(null);
38
50
  const dialogForm = ref({
@@ -227,7 +239,7 @@ const handleDeleteTag = (aciton, index) => {
227
239
  const open = () => {
228
240
  stVarSelectDialogRef.value.open(monacoEditorRef.value);
229
241
  };
230
- // 插入自定义函数
242
+ // 脚本: 插入自定义函数
231
243
  const handleInsertCustomFunction = (funcName, funcExpression) => {
232
244
  if (!monacoEditorRef.value) return ElMessage.error("未检测到编辑器实例");
233
245
  // 生成基础插入内容 (如果内含${}, 需提取出来, 作为变量)
@@ -288,6 +300,54 @@ const handleInsertCustomFunction = (funcName, funcExpression) => {
288
300
  editorIns.focus();
289
301
  }
290
302
  };
303
+ // 脚本: 复制
304
+ const handleScriptCopy = async () => {
305
+ try {
306
+ scriptCopyLoading.value = true;
307
+ const script = monacoEditorRef.value.getValue();
308
+ if (!script) return ElMessage.error("请输入脚本语句");
309
+ const { body } = await request.post("/common/qt/getFuncExpr", { factorSelectExpr: script });
310
+ if (!body) return ElMessage.error("脚本解析失败, 请检查脚本内容是否填写完整或者联系管理员");
311
+ // 复制内容到粘贴板
312
+ let txa = document.createElement("textarea");
313
+ txa.value = body;
314
+ document.body.appendChild(txa);
315
+ txa.select();
316
+ document.execCommand("copy");
317
+ document.body.removeChild(txa);
318
+ ElMessage.success("脚本内容已经成功复制到粘贴板");
319
+ } finally {
320
+ scriptCopyLoading.value = false;
321
+ }
322
+ };
323
+ // 脚本: 测试
324
+ const handleScriptTest = async () => {
325
+ try {
326
+ scriptTestLoading.value = true;
327
+ const script = monacoEditorRef.value.getValue();
328
+ if (!script) return ElMessage.error("请输入脚本语句");
329
+ const { body } = await request.post("/common/qt/getFuncExpr", { factorSelectExpr: script });
330
+ if (!body) return ElMessage.error("脚本解析失败, 请检查脚本内容是否填写完整或者联系管理员");
331
+ const testRes = await request.post("/common/qt/testFactorSelect", { factorSelectExpr: body });
332
+ const { result, detail } = testRes.body;
333
+ Object.assign(scriptTestResult, { result, detail, code: body });
334
+ if (result === 1) {
335
+ ElMessage.success("测试通过");
336
+ } else {
337
+ ElMessage.error("测试未能通过");
338
+ scriptTestLogVisible.value = true;
339
+ }
340
+ } finally {
341
+ scriptTestLoading.value = false;
342
+ }
343
+ };
344
+ // 脚本: 日志明细
345
+ const handleScriptLog = () => {
346
+ if (scriptTestResult.result === null) {
347
+ return ElMessage.warning("请先进行测试, 等待测试完成后可查看日志");
348
+ }
349
+ scriptTestLogVisible.value = true;
350
+ };
291
351
 
292
352
  // 监控: 窗口开关
293
353
  watch(
@@ -308,16 +368,21 @@ watch(
308
368
  factorType.value = "模版";
309
369
  }
310
370
  });
371
+ // 重置测试结果
372
+ Object.assign(scriptTestResult, {
373
+ result: null,
374
+ detail: "",
375
+ });
311
376
  break;
312
377
  }
313
378
  case false: {
314
379
  stVarSelectDialogRef.value.close();
380
+ scriptTestLogVisible.value = false;
315
381
  break;
316
382
  }
317
383
  }
318
- }
384
+ },
319
385
  );
320
-
321
386
  // 监控: 因子类型
322
387
  watch(
323
388
  () => factorType.value,
@@ -329,7 +394,7 @@ watch(
329
394
  });
330
395
  }
331
396
  },
332
- { deep: true }
397
+ { deep: true },
333
398
  );
334
399
  </script>
335
400
 
@@ -418,6 +483,7 @@ watch(
418
483
  >
419
484
  因子筛选
420
485
  </span>
486
+ <!-- 因子使用说明 -->
421
487
  <el-tooltip
422
488
  effect="dark"
423
489
  content="点击查看: 因子使用说明"
@@ -425,6 +491,7 @@ watch(
425
491
  >
426
492
  <el-icon @click="visibleDescriptions = true"><InfoFilled /></el-icon>
427
493
  </el-tooltip>
494
+ <!-- 因子模式 -->
428
495
  <el-radio-group
429
496
  v-model="factorType"
430
497
  size="small"
@@ -438,11 +505,37 @@ watch(
438
505
  value="脚本"
439
506
  />
440
507
  </el-radio-group>
441
- <st-customFunction
508
+ <!-- 脚本模式: 自定义函数插入新建, 脚本测试, 脚本复制 -->
509
+ <div
510
+ class="editor-tools"
442
511
  v-show="factorType === '脚本'"
443
- size="small"
444
- @insert="handleInsertCustomFunction"
445
- />
512
+ >
513
+ <st-customFunction
514
+ v-show="factorType === '脚本'"
515
+ size="small"
516
+ @insert="handleInsertCustomFunction"
517
+ />
518
+ <el-button
519
+ type="primary"
520
+ size="small"
521
+ :loading="scriptCopyLoading"
522
+ @click="handleScriptCopy"
523
+ >复制</el-button
524
+ >
525
+ <el-button
526
+ type="primary"
527
+ size="small"
528
+ :loading="scriptTestLoading"
529
+ @click="handleScriptTest"
530
+ >测试</el-button
531
+ >
532
+ <el-button
533
+ size="small"
534
+ :icon="Document"
535
+ @click="handleScriptLog"
536
+ >日志明细</el-button
537
+ >
538
+ </div>
446
539
  </div>
447
540
  <!-- 变量选择器 + 关闭 -->
448
541
  <div class="right">
@@ -719,6 +812,57 @@ watch(
719
812
  :factorType="factorType"
720
813
  :data="config.factorDescriptions?.filter((item) => [1, 3].includes(item.type))"
721
814
  />
815
+ <!-- 窗口: 日志明细 -->
816
+ <el-dialog
817
+ modal-class="log-dialog"
818
+ v-model="scriptTestLogVisible"
819
+ width="830"
820
+ align-center
821
+ append-to-body
822
+ draggable
823
+ overflow
824
+ :modal="false"
825
+ :modal-penetrable="true"
826
+ :show-close="false"
827
+ >
828
+ <template #header="{ titleId, titleClass }">
829
+ <div class="custom-header">
830
+ <div class="left">
831
+ <span
832
+ :id="titleId"
833
+ :class="titleClass"
834
+ >
835
+ 日志明细
836
+ </span>
837
+ </div>
838
+ <!-- 关闭 -->
839
+ <div class="right">
840
+ <el-icon @click="scriptTestLogVisible = false"><Close /></el-icon>
841
+ </div>
842
+ </div>
843
+ </template>
844
+ <div class="content">
845
+ <!-- 代码 -->
846
+ <el-scrollbar
847
+ class="code"
848
+ height="600px"
849
+ >
850
+ <pre>{{ scriptTestResult.code }}</pre>
851
+ </el-scrollbar>
852
+ <!-- 分割线 -->
853
+ <el-divider direction="vertical" />
854
+ <!-- 日志 -->
855
+ <el-scrollbar height="600px">
856
+ <pre :class="scriptTestResult.result === 1 ? 'success-log' : 'error-log'">{{ scriptTestResult.result === 1 ? "测试通过 √" : scriptTestResult.detail }}</pre>
857
+ </el-scrollbar>
858
+ </div>
859
+ <!-- 底部 -->
860
+ <template #footer>
861
+ <div class="dialog-footer">
862
+ <el-button @click="scriptTestLogVisible = false"> 关闭 </el-button>
863
+ </div>
864
+ </template>
865
+ </el-dialog>
722
866
  <!-- 变量选择器 -->
723
867
  <st-varSelectDialog ref="stVarSelectDialogRef" />
724
868
  </template>
@@ -738,6 +882,14 @@ watch(
738
882
  align-items: center;
739
883
  gap: 10px;
740
884
  }
885
+ .editor-tools {
886
+ display: flex;
887
+ align-items: center;
888
+ gap: 10px;
889
+ .el-button {
890
+ margin: 0;
891
+ }
892
+ }
741
893
  .el-icon {
742
894
  cursor: pointer;
743
895
  }
@@ -760,4 +912,49 @@ watch(
760
912
  }
761
913
  }
762
914
  }
915
+ .log-dialog {
916
+ .custom-header {
917
+ display: flex;
918
+ align-items: center;
919
+ justify-content: space-between;
920
+ .left,
921
+ .right {
922
+ display: flex;
923
+ align-items: center;
924
+ gap: 10px;
925
+ }
926
+ .el-icon {
927
+ cursor: pointer;
928
+ }
929
+ }
930
+ .content {
931
+ display: flex;
932
+ background-color: var(--el-color-black);
933
+ .el-scrollbar {
934
+ flex: 1;
935
+ box-sizing: border-box;
936
+ padding: 8px;
937
+ }
938
+ .el-divider {
939
+ margin: 0;
940
+ height: 616px;
941
+ }
942
+ .code {
943
+ color: var(--el-color-info);
944
+ }
945
+ .success-log {
946
+ color: var(--el-color-success);
947
+ }
948
+ .error-log {
949
+ color: var(--el-color-danger);
950
+ }
951
+ pre {
952
+ margin: 0;
953
+ line-height: 1.5;
954
+ white-space: pre-wrap;
955
+ word-break: break-all;
956
+ word-wrap: break-word;
957
+ }
958
+ }
959
+ }
763
960
  </style>