syntec3-0-ui-components-test 1.0.0

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 (99) hide show
  1. package/README.md +5 -0
  2. package/dist/S3_0UC_main.csv +4 -0
  3. package/dist/S3_0UC_sub.csv +2 -0
  4. package/dist/globalVariableS3_0UC.json +1 -0
  5. package/dist/style.css +1 -0
  6. package/dist/syntec3-0-ui-components.es.js +19518 -0
  7. package/dist/syntec3-0-ui-components.es.js.map +1 -0
  8. package/dist/syntec3-0-ui-components.umd.js +23 -0
  9. package/dist/syntec3-0-ui-components.umd.js.map +1 -0
  10. package/dist/vite.svg +1 -0
  11. package/dist/web.config +17 -0
  12. package/package.json +137 -0
  13. package/src/App.vue +31 -0
  14. package/src/assets/fonts/genYoGothicTW-normal.js +7 -0
  15. package/src/assets/image/defaultImage.png +0 -0
  16. package/src/assets/vue.svg +1 -0
  17. package/src/components/Layout/modules/fullPageGlobal.vue +113 -0
  18. package/src/components/Layout/modules/viewFile/config.js +65 -0
  19. package/src/components/Layout/modules/viewFile/createView.vue +1000 -0
  20. package/src/components/Layout/modules/viewFile/filterCriteria.vue +816 -0
  21. package/src/components/Layout/modules/viewFile/viewList.vue +291 -0
  22. package/src/components/Layout/modules/viewFile/viewManageTool.js +271 -0
  23. package/src/components/Layout/modules/viewFile/viewRecord.vue +472 -0
  24. package/src/components/Layout/modules/viewFile/viewTabs.vue +542 -0
  25. package/src/components/Layout/tools/GlobalDialog.vue +115 -0
  26. package/src/components/Pagination.vue +139 -0
  27. package/src/components/columnConfigNext.vue +273 -0
  28. package/src/components/customFilter/customFilter.vue +492 -0
  29. package/src/components/customFilter/filterCriteria.vue +769 -0
  30. package/src/components/customTable/components/headerOperation/index.vue +136 -0
  31. package/src/components/customTable/components/headerTabs/index.vue +171 -0
  32. package/src/components/customTable/components/tableContent/index.vue +440 -0
  33. package/src/components/customTable/index.vue +305 -0
  34. package/src/components/dialog.vue +85 -0
  35. package/src/components/pageContent.vue +48 -0
  36. package/src/components/popover.vue +402 -0
  37. package/src/configFiles/apiFile/baseApiList.json +11 -0
  38. package/src/configFiles/apiFile/coreApiList.json +24 -0
  39. package/src/configFiles/apiFile/mesApiList.json +4 -0
  40. package/src/configFiles/apiFile/mmsApiList.json +3 -0
  41. package/src/configFiles/errorCode.json +291 -0
  42. package/src/configFiles/version.js +2 -0
  43. package/src/i18n/lang/en-us.json +2060 -0
  44. package/src/i18n/lang/errorCodeTranslate.mjs +847 -0
  45. package/src/i18n/lang/zh-cn.json +2062 -0
  46. package/src/i18n/lang/zh-tw.json +2059 -0
  47. package/src/index.js +115 -0
  48. package/src/main.js +51 -0
  49. package/src/plugins/excel.js +88 -0
  50. package/src/router/index.js +41 -0
  51. package/src/scriptFiles/apiConfig/baseApis.js +10 -0
  52. package/src/scriptFiles/apiConfig/mesApis.js +10 -0
  53. package/src/scriptFiles/apiConfig/mmsApis.js +10 -0
  54. package/src/scriptFiles/apiConfig/privateCloudCoreApis.js +13 -0
  55. package/src/scriptFiles/apiConfig/serviceRoute.js +23 -0
  56. package/src/scriptFiles/apis/baseApiFunction.js +63 -0
  57. package/src/scriptFiles/apis/mesApiFunction.js +15 -0
  58. package/src/scriptFiles/apis/mmsApiFunction.js +9 -0
  59. package/src/scriptFiles/apis/privateCloudCoreApiFunction.js +101 -0
  60. package/src/scriptFiles/backendApiFunction.js +11 -0
  61. package/src/scriptFiles/checkApiErrorMechanism.js +137 -0
  62. package/src/scriptFiles/common/objectDataProcessing.js +65 -0
  63. package/src/scss/base/commom.scss +1068 -0
  64. package/src/scss/base/dialog.scss +45 -0
  65. package/src/scss/base/index.scss +3 -0
  66. package/src/scss/base/table.scss +28 -0
  67. package/src/store/index.js +25 -0
  68. package/src/store/module/langStore.js +116 -0
  69. package/src/style.css +52 -0
  70. package/src/utils/excel.js +86 -0
  71. package/src/utils/formula.js +69 -0
  72. package/src/utils/https.js +13 -0
  73. package/src/utils/i18n.js +42 -0
  74. package/src/utils/shiftSelect.js +164 -0
  75. package/src/utils/summation.js +77 -0
  76. package/src/utils/tableWidth.js +29 -0
  77. package/src/utils/toolFun.js +93 -0
  78. package/src/views/productionWorkOrder/components/columnConfig.vue +242 -0
  79. package/src/views/productionWorkOrder/components/docCustomFieldForm.vue +739 -0
  80. package/src/views/productionWorkOrder/components/filePreview.vue +148 -0
  81. package/src/views/productionWorkOrder/components/querySearch.vue +363 -0
  82. package/src/views/productionWorkOrder/configFiles/excelImportErrorCode.json +94 -0
  83. package/src/views/productionWorkOrder/configFiles/pdfDefaultConfig.js +933 -0
  84. package/src/views/productionWorkOrder/configFiles/planMakingScript.js +600 -0
  85. package/src/views/productionWorkOrder/configFiles/productionRelatedScript.js +368 -0
  86. package/src/views/productionWorkOrder/configFiles/rulse.js +23 -0
  87. package/src/views/productionWorkOrder/configFiles/status.js +50 -0
  88. package/src/views/productionWorkOrder/index.vue +2174 -0
  89. package/src/views/productionWorkOrder/productionFlowLabel/component/addCirculationLabel.vue +394 -0
  90. package/src/views/productionWorkOrder/productionFlowLabel/component/circulationLabelTable.vue +124 -0
  91. package/src/views/productionWorkOrder/productionFlowLabel/component/materialPartFilePreview.vue +167 -0
  92. package/src/views/productionWorkOrder/productionFlowLabel/component/workOrderInformation.vue +28 -0
  93. package/src/views/productionWorkOrder/productionFlowLabel/index.vue +604 -0
  94. package/src/views/production_work_order/components/priorityTooltip.vue +53 -0
  95. package/src/views/production_work_order/index.vue +1307 -0
  96. package/src/views/review_record/components/materialInfo.vue +50 -0
  97. package/src/views/review_record/components/rootCause.vue +42 -0
  98. package/src/views/review_record/components/workDetail.vue +115 -0
  99. package/src/views/review_record/index.vue +884 -0
@@ -0,0 +1,291 @@
1
+ <template>
2
+ <el-drawer
3
+ v-model="visible"
4
+ body-class="drawer_body_class"
5
+ style="margin-bottom: 0"
6
+ :z-index="2000"
7
+ size="45%"
8
+ :with-header="false"
9
+ :append-to-body="false"
10
+ :close-on-press-escape="false"
11
+ :before-close="closeViewListDrawer"
12
+ data-test-id="EL-DRAWER-jasb7C"
13
+ >
14
+ <template #default>
15
+ <div class="drawer_header_class_content" data-test-id="DIV-rXpQmF">
16
+ <div class="drawer_title" data-test-id="DIV-zQlq1H">
17
+ <span class="mdi mdi-list-box-outline" data-test-id="SPAN-HFpXUh" />
18
+ <span class="title_text" data-test-id="SPAN-0Iut9t">
19
+ {{ t('viewList') }}
20
+ </span>
21
+ <el-tooltip effect="dark" :content="t('viewListTips')" placement="right" data-test-id="EL-TOOLTIP-hHb1YY">
22
+ <span class="mdi mdi-help-circle-outline title_text_right_icon" data-test-id="SPAN-UENqYR" />
23
+ </el-tooltip>
24
+ </div>
25
+ <el-button link type="primary" data-test-id="EL-BUTTON-4ZFjLQ" @click="addView">
26
+ <el-icon class="mdi mdi-plus" style="margin-right: 0.5rem; font-size: 18px" data-test-id="EL-ICON-0ylmiQ">
27
+ </el-icon>
28
+ {{ t('createView') }}
29
+ </el-button>
30
+ </div>
31
+ <div class="list-body" data-test-id="DIV-Xmx3qv">
32
+ <VueDraggable
33
+ ref="draggableRef"
34
+ v-model="allViews"
35
+ :target="target"
36
+ :handle="handle"
37
+ data-test-id="VUEDRAGGABLE-dL4IT9"
38
+ @end="handleDragEnd"
39
+ >
40
+ <el-table
41
+ :data="allViews"
42
+ border
43
+ class="commonTable sort-target"
44
+ header-cell-class-name="tableHeaderCell"
45
+ header-row-class-name="tableHeader"
46
+ height="100%"
47
+ data-test-id="EL-TABLE-jJswcP"
48
+ >
49
+ <el-table-column :width="50" align="center" data-test-id="EL-TABLE-COLUMN-gVOhBD">
50
+ <template #default>
51
+ <el-icon class="mdi mdi-drag dragindicator" style="cursor: move" data-test-id="EL-ICON-XVO0RZ" />
52
+ </template>
53
+ </el-table-column>
54
+ <el-table-column label="#" :width="70" align="center" data-test-id="EL-TABLE-COLUMN-EGE1qk">
55
+ <template #default="{ $index }">
56
+ {{ $index + 1 }}
57
+ </template>
58
+ </el-table-column>
59
+ <el-table-column
60
+ :label="t('viewName')"
61
+ prop="name"
62
+ show-overflow-tooltip
63
+ data-test-id="EL-TABLE-COLUMN-BX8fIe"
64
+ >
65
+ <template #default="scope">
66
+ <el-icon
67
+ class="mdi mdi-book-open-blank-variant"
68
+ :style="{ color: iconType(Number(scope.row.meta)).color }"
69
+ data-test-id="EL-ICON-IJLII3"
70
+ />
71
+ {{
72
+ scope.row.id < 0 && (scope.row.viewName === '全部' || scope.row.viewName === 'all')
73
+ ? t('all')
74
+ : scope.row.viewName
75
+ }}
76
+ </template>
77
+ </el-table-column>
78
+ <el-table-column :label="t('action')" :width="150" align="center" data-test-id="EL-TABLE-COLUMN-15WeBo">
79
+ <template #default="scope">
80
+ <el-tooltip :content="t('edit')" placement="top" :enterable="false" data-test-id="EL-TOOLTIP-NGVisW">
81
+ <el-button link type="primary" data-test-id="EL-BUTTON-VVS5A0" @click="editFun(scope.row)">
82
+ <v-icon class="mdi mdi-pencil" style="font-size: 1.2rem" data-test-id="V-ICON-8OzEal" />
83
+ </el-button>
84
+ </el-tooltip>
85
+ <el-tooltip :content="t('copy')" placement="top" :enterable="false" data-test-id="EL-TOOLTIP-Ima4Dj">
86
+ <el-button link type="primary" data-test-id="EL-BUTTON-NQswpy" @click="copyItem(scope.row)">
87
+ <el-icon class="mdi mdi-content-copy" style="font-size: 1.2rem" data-test-id="EL-ICON-e2uFy4" />
88
+ </el-button>
89
+ </el-tooltip>
90
+ <el-tooltip :content="t('delete')" placement="top" :enterable="false" data-test-id="EL-TOOLTIP-WlX0wi">
91
+ <el-button link type="primary" data-test-id="EL-BUTTON-v6dR6f" @click="deleteItem(scope.row)">
92
+ <el-icon class="mdi mdi-trash-can" style="font-size: 1.2rem" data-test-id="EL-ICON-TRfu6F" />
93
+ </el-button>
94
+ </el-tooltip>
95
+ </template>
96
+ </el-table-column>
97
+ </el-table>
98
+ </VueDraggable>
99
+ </div>
100
+ <createView
101
+ ref="createViewRef"
102
+ :permission-data="props.permissionData"
103
+ :select-options="props.selectOptions"
104
+ :default-create-time-string="defaultCreateTimeString"
105
+ data-test-id="CREATEVIEW-cCI5u5"
106
+ @updataView="getViewTabList('update')"
107
+ />
108
+ </template>
109
+ </el-drawer>
110
+ </template>
111
+
112
+ <script setup>
113
+ import { ref } from 'vue';
114
+ import { useI18n } from 'vue-i18n';
115
+ import { VueDraggable } from 'vue-draggable-plus';
116
+ import createView from './createView.vue';
117
+ import apiFunction from '@/scriptFiles/checkApiErrorMechanism.js';
118
+ import { ElMessage, ElMessageBox } from 'element-plus';
119
+ import { iconType } from './viewManageTool.js';
120
+ const props = defineProps({
121
+ permissionData: Object,
122
+ selectOptions: {
123
+ type: Object,
124
+ default: () => ({}),
125
+ },
126
+ defaultCreateTimeString: {
127
+ type: String,
128
+ default: 'createTime',
129
+ },
130
+ });
131
+ const { t } = useI18n();
132
+ const emit = defineEmits(['updateViewTabs']);
133
+ const visible = ref(false); // 视图窗口
134
+ const createViewRef = ref(null);
135
+ const draggableRef = ref(null);
136
+ const fieldSetting = ref([]);
137
+ // 定义所有视图数据
138
+ const allViews = ref([]);
139
+ const idFromList = ref(null);
140
+ //获取页面的视图列表
141
+ async function getViewTabList(type) {
142
+ await apiFunction
143
+ .getViewList({
144
+ startIndex: 0,
145
+ count: 20,
146
+ permissionCode: props.permissionData.permissionCode,
147
+ })
148
+ .then((res) => {
149
+ if (res.data.code === 0) {
150
+ allViews.value = [...res.data.content.data];
151
+ if (type === 'update') {
152
+ emit('updateViewTabs', [...allViews.value], idFromList.value); //更新tab页面
153
+ }
154
+ } else {
155
+ ElMessage.error(t(res.data.message));
156
+ }
157
+ })
158
+ .catch(() => {
159
+ ElMessage.error(t('apiError'));
160
+ });
161
+ }
162
+ /**
163
+ * 添加视图
164
+ */
165
+ function addView() {
166
+ createViewRef.value.open(null, 1);
167
+ }
168
+ /**
169
+ * 编辑视图
170
+ */
171
+ const editFun = (row) => {
172
+ const viewId = typeof row === 'object' && row.id !== undefined ? row.id : row;
173
+ idFromList.value = viewId;
174
+ createViewRef.value.open(viewId, 0, props.selectOptions);
175
+ };
176
+ const copyItem = (row) => {
177
+ const viewId = typeof row === 'object' && row.id !== undefined ? row.id : row;
178
+ idFromList.value = viewId;
179
+ createViewRef.value.open(viewId, 2, props.selectOptions);
180
+ };
181
+ // 定义拖拽相关配置
182
+ const target = ref('.list-body tbody');
183
+ const handle = ref('.dragindicator');
184
+ /**
185
+ * 拖拽结束事件
186
+ */
187
+ const handleDragEnd = async () => {
188
+ try {
189
+ const res = await apiFunction.viewSortList({ viewJson: allViews.value });
190
+ if (res.data.code === 0) {
191
+ emit('updateViewTabs', [...allViews.value]);
192
+ } else {
193
+ ElMessage.error(t(res.data.message));
194
+ }
195
+ } catch (error) {
196
+ ElMessage.error(t('apiError'));
197
+ }
198
+ };
199
+
200
+ // 删除视图
201
+ async function doDeleteOperation(id) {
202
+ await apiFunction
203
+ .deleteView(id)
204
+ .then((res) => {
205
+ if (res.data?.code === 0) {
206
+ getViewTabList('update');
207
+ } else {
208
+ ElMessage.error(t(res.data.message));
209
+ }
210
+ })
211
+ .catch(() => {
212
+ ElMessage.error(t('apiError'));
213
+ });
214
+ }
215
+ const deleteItem = (row) => {
216
+ let dialogTitle = t('delReminder');
217
+ let dialogAlertDetail = `${t('viewDeleteTip')}`;
218
+ ElMessageBox.confirm(dialogAlertDetail, dialogTitle, {
219
+ confirmButtonText: t('confirm'),
220
+ cancelButtonText: t('cancel'),
221
+ type: 'warning',
222
+ })
223
+ .then(async () => {
224
+ await doDeleteOperation(row.id);
225
+ })
226
+ .catch(() => {
227
+ return;
228
+ });
229
+ };
230
+ /**
231
+ * 打开视图列表抽屉
232
+ */
233
+ const open = async () => {
234
+ visible.value = true;
235
+ getViewTabList();
236
+ };
237
+
238
+ /**
239
+ * 打开视图列表抽屉并执行编辑或复制操作
240
+ */
241
+ const openDrawer = async (data, type) => {
242
+ visible.value = true;
243
+ await getViewTabList();
244
+ if (type === 0) {
245
+ editFun(data, props.selectOptions);
246
+ } else if (type === 2) {
247
+ copyItem(data, props.selectOptions);
248
+ }
249
+ };
250
+
251
+ /**
252
+ * 关闭视图列表抽屉
253
+ */
254
+ const closeViewListDrawer = () => {
255
+ visible.value = false;
256
+ fieldSetting.value = [];
257
+ allViews.value = [];
258
+ };
259
+ defineExpose({
260
+ open,
261
+ openDrawer,
262
+ });
263
+ </script>
264
+
265
+ <style scoped lang="scss">
266
+ ::v-deep(.drawer_body_class) {
267
+ margin: 0;
268
+ padding: 5px;
269
+ }
270
+ .drawer_header_class_content {
271
+ display: flex;
272
+ justify-content: space-between;
273
+ align-items: center;
274
+ }
275
+ .drawer_title {
276
+ display: flex;
277
+ align-items: center;
278
+ }
279
+ .title_text_right_icon {
280
+ color: #909399;
281
+ font-size: 1rem;
282
+ }
283
+ .title_text {
284
+ color: #165389;
285
+ font-weight: bold;
286
+ margin: 0 0.5rem;
287
+ }
288
+ .list-body {
289
+ height: calc(100% - 40px);
290
+ }
291
+ </style>
@@ -0,0 +1,271 @@
1
+ import { ref } from 'vue';
2
+ // 递归收集所有人员ID
3
+ export function getAllPersonIds(opts) {
4
+ const ids = [];
5
+ opts.forEach((option) => {
6
+ // 如果有子项,说明是部门,递归收集子项
7
+ if (option.children && option.children.length > 0) {
8
+ ids.push(...getAllPersonIds(option.children));
9
+ } else if (option.value !== '-1') {
10
+ // 排除"所有人"自身
11
+ ids.push(option.value);
12
+ }
13
+ });
14
+ return ids;
15
+ }
16
+ // 收集指定部门下的所有人员ID
17
+ export function getDeptPersonIds(deptId, opts) {
18
+ const ids = [];
19
+ const findDept = (options) => {
20
+ for (const opt of options) {
21
+ if (opt.value === deptId && opt.children) {
22
+ // 收集当前部门下的所有人员
23
+ opt.children.forEach((child) => ids.push(child.value));
24
+ return true;
25
+ }
26
+ if (opt.children && findDept(opt.children)) {
27
+ return true;
28
+ }
29
+ }
30
+ return false;
31
+ };
32
+ findDept(opts);
33
+ return ids;
34
+ }
35
+
36
+ // 导出回显相关工具函数
37
+ export const echoUtils = {
38
+ // 1. 初始化部门-人员映射表
39
+ initDeptMap(opts) {
40
+ const deptPersonMap = {};
41
+ const traverse = (options) => {
42
+ options.forEach((opt) => {
43
+ if (opt.children && opt.children.length > 0) {
44
+ // 记录部门下所有人员ID
45
+ deptPersonMap[opt.value] = opt.children.map((child) => child.value);
46
+ traverse(opt.children); // 递归处理子部门
47
+ }
48
+ });
49
+ };
50
+ traverse(opts);
51
+ return deptPersonMap;
52
+ },
53
+
54
+ // 2. 初始化独立人员ID列表(无下级的非"所有人"选项)
55
+ initPersonIds(opts) {
56
+ const personIds = [];
57
+ const traverse = (options) => {
58
+ options.forEach((opt) => {
59
+ if (opt.value !== '-1' && (!opt.children || opt.children.length === 0)) {
60
+ personIds.push(opt.value);
61
+ } else if (opt.children && opt.children.length > 0) {
62
+ traverse(opt.children);
63
+ }
64
+ });
65
+ };
66
+ traverse(opts);
67
+ return personIds;
68
+ },
69
+
70
+ // 3. 递归收集所有人员ID(用于判断全量人员)
71
+ getAllPersonIds(opts) {
72
+ const ids = [];
73
+ opts.forEach((option) => {
74
+ if (option.children && option.children.length > 0) {
75
+ ids.push(...this.getAllPersonIds(option.children));
76
+ } else if (option.value !== '-1') {
77
+ // 排除"所有人"
78
+ ids.push(option.value);
79
+ }
80
+ });
81
+ return ids;
82
+ },
83
+
84
+ getEchoValues(personIdList, options) {
85
+ // 1. 将后端返回的数字ID转为字符串(关键修复)
86
+ const stringIdList = personIdList.map((id) => String(id));
87
+
88
+ // 2. 初始化依赖数据(全量人员ID是字符串)
89
+ const deptPersonMap = this.initDeptMap(options);
90
+ const allPersons = this.getAllPersonIds(options); // 如 ["8", "1", "11", "10", "9"]
91
+
92
+ // 3. 修正:用转换后的字符串ID列表判断全量
93
+ if (stringIdList.length === allPersons.length && stringIdList.every((id) => allPersons.includes(id))) {
94
+ return ['-1']; // 此时会正确触发“所有人”回显
95
+ }
96
+
97
+ const echoValues = [];
98
+ const remainingIds = [...stringIdList]; // 用转换后的ID处理后续逻辑
99
+
100
+ // 剩余逻辑不变...
101
+ Object.entries(deptPersonMap).forEach(([deptId, deptPersons]) => {
102
+ const allIncluded = deptPersons.every((personId) => remainingIds.includes(personId));
103
+ if (allIncluded) {
104
+ echoValues.push(deptId);
105
+ deptPersons.forEach((id) => {
106
+ const index = remainingIds.indexOf(id);
107
+ if (index > -1) remainingIds.splice(index, 1);
108
+ });
109
+ }
110
+ });
111
+
112
+ echoValues.push(...remainingIds);
113
+ return echoValues;
114
+ },
115
+ };
116
+ // 图标类型 颜色映射
117
+ export function iconType(type) {
118
+ const colorMap = {
119
+ 0: '#125088',
120
+ 1: '#FF0000',
121
+ 2: '#F0D155',
122
+ 3: '#99C0E4',
123
+ 4: '#FF7A21',
124
+ 5: '#323338',
125
+ 6: '#34AA1A',
126
+ };
127
+ return { color: colorMap[type] || '#909399' };
128
+ }
129
+
130
+ // 获取图标颜色数组
131
+
132
+ export function iconColors() {
133
+ return ref(['#125088', '#FF0000', '#F0D155', '#99C0E4', '#FF7A21', '#323338', '#34AA1A']);
134
+ }
135
+
136
+ /**
137
+ * 转换筛选条件列表为 popover显示的筛选过滤条件 格式
138
+ * @param {Array} list - 后端返回的筛选条件数组
139
+ * @returns {Array} 转换后的模板字符串数组
140
+ */
141
+ /**
142
+ * 转换筛选条件列表为目标格式
143
+ * @param {Array} list - 后端返回的筛选条件数组(可能为null/undefined)
144
+ * @returns {Array} 转换后的模板字符串数组(默认返回空数组)
145
+ */
146
+ // 操作符选项映射表(内置)
147
+ const operatorOptions = [
148
+ { label: 'greaterThan', value: 1 },
149
+ { label: 'greaterThanOrEqualTo', value: 2 },
150
+ { label: 'lessThan', value: 3 },
151
+ { label: 'lessThanOrEqualTo', value: 4 },
152
+ { label: 'equalTo', value: 5 },
153
+ { label: 'notEqualTo', value: 6 },
154
+ { label: 'contains', value: 7 },
155
+ { label: 'notContains', value: 8 },
156
+ { label: 'yesEmpty', value: 9 },
157
+ { label: 'notEmpty', value: 10 },
158
+ { label: 'selectRange', value: 11 },
159
+ { label: 'dynamicFiltering', value: 12 },
160
+ { label: 'inRange', value: 13 },
161
+ { label: 'notInRange', value: 14 },
162
+ { label: 'isOneOf', value: 15 },
163
+ { label: 'notAnyOf', value: 16 },
164
+ ];
165
+
166
+ /**
167
+ * 根据value获取operatorOptions中对应的label
168
+ * @param {number} value - 操作符的value(如1、12、15等)
169
+ * @returns {string} 对应的label,若未找到则返回空字符串
170
+ */
171
+ export function getOperatorLabel(value) {
172
+ // 查找匹配的选项
173
+ const option = operatorOptions.find((item) => item.value === value);
174
+ // 存在则返回label,否则返回空字符串
175
+ return option ? option.label : '';
176
+ }
177
+ export function processFilterData(editableTabs) {
178
+ // 校验入参是否为数组
179
+ if (!Array.isArray(editableTabs)) {
180
+ console.error('processFilterData:入参必须是数组');
181
+ return [];
182
+ }
183
+
184
+ return editableTabs.map((item) => {
185
+ try {
186
+ // 1. 校验filterString是否为有效字符串
187
+ if (!item?.filterString || typeof item.filterString !== 'string') {
188
+ return { ...item, parsedFilter: null };
189
+ }
190
+
191
+ // 2. 解析JSON字符串
192
+ const parsedArray = JSON.parse(item.filterString);
193
+
194
+ // 3. 确保解析结果是数组
195
+ if (!Array.isArray(parsedArray)) {
196
+ console.warn(`processFilterData:id为${item.id || '未知'}的filterString解析结果非数组`);
197
+ return { ...item, parsedFilter: null };
198
+ }
199
+
200
+ // 4. 转换为二维数组(按逗号分割子项)
201
+ const twoDimensionalArray = parsedArray.map((subItem) => {
202
+ if (typeof subItem !== 'string') {
203
+ return [subItem]; // 非字符串子项包裹为单元素数组
204
+ }
205
+ // 分割并去除首尾空格
206
+ return subItem.split(',').map((part) => part.trim());
207
+ });
208
+
209
+ return { ...item, parsedFilter: twoDimensionalArray };
210
+ } catch (error) {
211
+ console.error(`processFilterData:解析id为${item.id || '未知'}的filterString失败:`, error);
212
+ return { ...item, parsedFilter: null };
213
+ }
214
+ });
215
+ }
216
+
217
+ // 通用工具函数:从parsedFilter中查找目标项
218
+ export function findTargetItem(parsedFilter, field) {
219
+ return Array.isArray(parsedFilter) ? parsedFilter.find((item) => Array.isArray(item) && item.includes(field)) : null;
220
+ }
221
+ // 1. 输入类型字段处理函数(取第三项,控制禁用)
222
+ export function handleInputField(parsedFilter, field, valueRef, disabledRef) {
223
+ const targetItem = findTargetItem(parsedFilter, field);
224
+ const thirdItem = targetItem?.[2] ?? '';
225
+ valueRef.value = thirdItem;
226
+ disabledRef.value = !!thirdItem;
227
+ }
228
+
229
+ // 2. 下拉选择类型字段处理函数(取第三项及以后,映射value)
230
+ export function handleSelectField(parsedFilter, field, valueRef, disabledRef, mapList) {
231
+ const targetItem = findTargetItem(parsedFilter, field);
232
+ const afterThirdItems = Array.isArray(targetItem) ? targetItem.slice(2) : [];
233
+ const mappedValues = afterThirdItems
234
+ .map((text) => mapList.find((item) => item.text === text)?.value ?? null)
235
+ .filter((val) => val !== null);
236
+ valueRef.value = mappedValues;
237
+ disabledRef.value = mappedValues.length > 0;
238
+ }
239
+
240
+ // 3. 新增:时间范围类型处理函数(含selectRange,取最后两项并转换时间戳)
241
+ export function handleDateRangeField(parsedFilter, field, valueRef, disabledRef) {
242
+ const targetItem = findTargetItem(parsedFilter, field);
243
+ // 校验:目标项存在且包含selectRange,且至少有5项(确保最后两项是时间)
244
+ const isValid = Array.isArray(targetItem) && targetItem.includes('selectRange') && targetItem.length >= 5;
245
+
246
+ if (isValid) {
247
+ // 取最后两项(开始时间、结束时间)
248
+ const [startStr, endStr] = targetItem.slice(-2);
249
+ // 转换为时间戳(结束时间默认补到当天23:59:59)
250
+ const startTimestamp = new Date(startStr).getTime();
251
+ const endDate = new Date(endStr);
252
+ endDate.setHours(23, 59, 59, 999); // 补全结束时间到当天最后一刻
253
+ const endTimestamp = endDate.getTime();
254
+
255
+ valueRef.value = [startTimestamp, endTimestamp];
256
+ disabledRef.value = true; // 有效时禁用
257
+ } else {
258
+ valueRef.value = [];
259
+ disabledRef.value = false; // 无效时不禁用
260
+ }
261
+ }
262
+ //处理下拉 key value 不一致问题 统一转为 text value
263
+ export function transformToTextValue(array, textField, valueField) {
264
+ // 容错处理:原始数组为空或非数组时返回空数组
265
+ if (!Array.isArray(array)) return [];
266
+
267
+ return array.map((item) => ({
268
+ text: item?.[textField] ?? '',
269
+ value: item?.[valueField] ?? '',
270
+ }));
271
+ }