@jzt-packages/components 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 (145) hide show
  1. package/package.json +68 -0
  2. package/src/JztBackTop/index.vue +255 -0
  3. package/src/JztButtonList/index.vue +88 -0
  4. package/src/JztChart/index.vue +95 -0
  5. package/src/JztCharts/index.vue +317 -0
  6. package/src/JztClassTabs/index.vue +156 -0
  7. package/src/JztDateSelect/dateSelect.vue +186 -0
  8. package/src/JztDateSelect/dateType.vue +54 -0
  9. package/src/JztDateSelect/index.ts +135 -0
  10. package/src/JztDateSelect/interface/index.ts +13 -0
  11. package/src/JztDialog/index.vue +249 -0
  12. package/src/JztEllipsisTooltip/index.vue +61 -0
  13. package/src/JztEmpty/index.vue +45 -0
  14. package/src/JztErrorPage/403.vue +30 -0
  15. package/src/JztErrorPage/404.vue +19 -0
  16. package/src/JztErrorPage/500.vue +18 -0
  17. package/src/JztErrorPage/assets/401.png +0 -0
  18. package/src/JztErrorPage/assets/403.png +0 -0
  19. package/src/JztErrorPage/assets/404.png +0 -0
  20. package/src/JztErrorPage/assets/500.png +0 -0
  21. package/src/JztErrorPage/index.scss +35 -0
  22. package/src/JztErrorPage/index.vue +35 -0
  23. package/src/JztFilePreview/components/pdfViewer.vue +221 -0
  24. package/src/JztFilePreview/hooks/useImageMethod.ts +256 -0
  25. package/src/JztFilePreview/index.scss +171 -0
  26. package/src/JztFilePreview/index.vue +68 -0
  27. package/src/JztFilePreview/interface/index.ts +18 -0
  28. package/src/JztFilePreview/previewFile.vue +371 -0
  29. package/src/JztFormGrid/README.md +520 -0
  30. package/src/JztFormGrid/components/formItem.vue +209 -0
  31. package/src/JztFormGrid/components/formItemValue.vue +384 -0
  32. package/src/JztFormGrid/components/showDetailForm.vue +172 -0
  33. package/src/JztFormGrid/index.scss +60 -0
  34. package/src/JztFormGrid/index.vue +513 -0
  35. package/src/JztFormGrid/interface/index.ts +106 -0
  36. package/src/JztGrid/components/GridItem.vue +68 -0
  37. package/src/JztGrid/index.vue +179 -0
  38. package/src/JztGrid/interface/index.ts +6 -0
  39. package/src/JztImportExcel/assets/delete.png +0 -0
  40. package/src/JztImportExcel/index.scss +46 -0
  41. package/src/JztImportExcel/index.vue +430 -0
  42. package/src/JztImportExcel/interface/index.ts +25 -0
  43. package/src/JztLabelTitle/index.vue +65 -0
  44. package/src/JztLeftRightMode/components/CollapseButton.vue +80 -0
  45. package/src/JztLeftRightMode/components/LeftCard.vue +203 -0
  46. package/src/JztLeftRightMode/components/LeftLayout.vue +173 -0
  47. package/src/JztLeftRightMode/components/RightHeader.vue +186 -0
  48. package/src/JztLeftRightMode/components/RightLayout.vue +235 -0
  49. package/src/JztLeftRightMode/components/RightTableHeader.vue +43 -0
  50. package/src/JztLeftRightMode/hooks/useCollapse.ts +17 -0
  51. package/src/JztLeftRightMode/hooks/useDefaultProps.ts +19 -0
  52. package/src/JztLeftRightMode/hooks/useLeftLayout.ts +201 -0
  53. package/src/JztLeftRightMode/hooks/useMode.ts +20 -0
  54. package/src/JztLeftRightMode/hooks/usePrevNext.ts +60 -0
  55. package/src/JztLeftRightMode/hooks/useRightLayout.ts +215 -0
  56. package/src/JztLeftRightMode/hooks/useSlots.ts +15 -0
  57. package/src/JztLeftRightMode/index.ts +3 -0
  58. package/src/JztLeftRightMode/index.vue +494 -0
  59. package/src/JztLeftRightMode/types/index.ts +457 -0
  60. package/src/JztLoading/fullScreen.ts +45 -0
  61. package/src/JztLoading/index.scss +67 -0
  62. package/src/JztLoading/index.vue +18 -0
  63. package/src/JztLogin/components/LoginFooter.vue +17 -0
  64. package/src/JztLogin/components/LoginForm.vue +99 -0
  65. package/src/JztLogin/hooks/useLogin.ts +186 -0
  66. package/src/JztLogin/index.scss +142 -0
  67. package/src/JztLogin/index.vue +31 -0
  68. package/src/JztLogin/interface/index.ts +47 -0
  69. package/src/JztNumericalRange/index.vue +81 -0
  70. package/src/JztPageCard/comm/datePicker.vue +151 -0
  71. package/src/JztPageCard/comm/details.vue +60 -0
  72. package/src/JztPageCard/comm/export.vue +24 -0
  73. package/src/JztPageCard/comm/tabs.vue +94 -0
  74. package/src/JztPageCard/comm/tooltip.vue +31 -0
  75. package/src/JztPageCard/index.vue +287 -0
  76. package/src/JztPagination/index.vue +70 -0
  77. package/src/JztProductInfo/components/imagePreview.vue +275 -0
  78. package/src/JztProductInfo/components/qxUnique.vue +101 -0
  79. package/src/JztProductInfo/components/records.vue +265 -0
  80. package/src/JztProductInfo/hooks/useParams.ts +143 -0
  81. package/src/JztProductInfo/hooks/useQxUnique.tsx +466 -0
  82. package/src/JztProductInfo/images/defaultProduct.png +0 -0
  83. package/src/JztProductInfo/index.ts +116 -0
  84. package/src/JztProductInfo/index.vue +108 -0
  85. package/src/JztProductInfo/interface/index.ts +15 -0
  86. package/src/JztQueryDetailTable/index.scss +100 -0
  87. package/src/JztQueryDetailTable/index.vue +400 -0
  88. package/src/JztQueryDetailTable/interface/index.ts +10 -0
  89. package/src/JztQueryTable/QueryTable /345/212/237/350/203/275.md" +1580 -0
  90. package/src/JztQueryTable/README.md +567 -0
  91. package/src/JztQueryTable/components/ColSetting.vue +67 -0
  92. package/src/JztQueryTable/components/ColumnsSetting.vue +404 -0
  93. package/src/JztQueryTable/components/ColumnsSetting1.vue +220 -0
  94. package/src/JztQueryTable/components/DeployToAccountLevelSetting.vue +351 -0
  95. package/src/JztQueryTable/components/Pagination.vue +54 -0
  96. package/src/JztQueryTable/components/TableColumn.vue +109 -0
  97. package/src/JztQueryTable/const.ts +1 -0
  98. package/src/JztQueryTable/hooks/useQueryTable.ts +194 -0
  99. package/src/JztQueryTable/hooks/useSelection.ts +47 -0
  100. package/src/JztQueryTable/hooks/useTableSetting.ts +197 -0
  101. package/src/JztQueryTable/hooks/useTemplate.ts +127 -0
  102. package/src/JztQueryTable/index.scss +91 -0
  103. package/src/JztQueryTable/index.vue +1445 -0
  104. package/src/JztQueryTable/interface/index.ts +185 -0
  105. package/src/JztRegionSelect/index.vue +134 -0
  106. package/src/JztSearchForm/components/SearchFormItem.vue +473 -0
  107. package/src/JztSearchForm/index.vue +530 -0
  108. package/src/JztSearchForm/interface/index.ts +100 -0
  109. package/src/JztSelectFilter/index.scss +63 -0
  110. package/src/JztSelectFilter/index.vue +110 -0
  111. package/src/JztSelectTable/index.vue +257 -0
  112. package/src/JztTable/index.scss +72 -0
  113. package/src/JztTable/index.vue +353 -0
  114. package/src/JztTable/interface/index.ts +1 -0
  115. package/src/JztTime/comm/agencySelect.vue +112 -0
  116. package/src/JztTime/comm/collapseRow.vue +132 -0
  117. package/src/JztTime/comm/dateSelect.vue +292 -0
  118. package/src/JztTime/comm/deptSelect.vue +193 -0
  119. package/src/JztTime/comm/typeSelect.vue +97 -0
  120. package/src/JztTime/index.ts +216 -0
  121. package/src/JztTime/index.vue +303 -0
  122. package/src/JztTime/interface/index.ts +23 -0
  123. package/src/JztTreeFilter/index.scss +44 -0
  124. package/src/JztTreeFilter/index.vue +177 -0
  125. package/src/JztUploadFile/interface/index.ts +21 -0
  126. package/src/JztUploadFile/multiple.scss +215 -0
  127. package/src/JztUploadFile/multiple.vue +318 -0
  128. package/src/JztUploadFile/single.scss +226 -0
  129. package/src/JztUploadFile/single.vue +274 -0
  130. package/src/JztUploadImg/Img.vue +294 -0
  131. package/src/JztUploadImg/Imgs.vue +411 -0
  132. package/src/JztUploadImg/index.scss +138 -0
  133. package/src/JztUploadImg/interface/index.ts +22 -0
  134. package/src/SelectIcon/index.scss +39 -0
  135. package/src/SelectIcon/index.vue +106 -0
  136. package/src/SvgIcon/index.vue +22 -0
  137. package/src/hooks/useAuthButtons.ts +58 -0
  138. package/src/hooks/useFormByUserType.ts +90 -0
  139. package/src/hooks/useTableEvents.ts +30 -0
  140. package/src/hooks/useUploadFileHook.ts +262 -0
  141. package/src/index.ts +91 -0
  142. package/src/typings/global.d.ts +101 -0
  143. package/src/utils/index.ts +107 -0
  144. package/src/utils/tree.ts +57 -0
  145. package/tsconfig.json +45 -0
@@ -0,0 +1,143 @@
1
+ import { ref, nextTick, computed } from 'vue'
2
+ import { getProductByProductCode, getMEProductByProductCode, getConfigByModuleAndKey } from '@jzt-spd/utils/commonApi'
3
+ const dialogVisible = ref(false)
4
+ const previewFileRef = ref()
5
+ const tabActive = ref('records')
6
+ const openFold = ref(false)
7
+ interface ProductInfoProps {
8
+ productCode: string
9
+ productClassName: string
10
+ }
11
+ const productInfo = ref<ProductInfoProps>({
12
+ productCode: '',
13
+ productClassName: ''
14
+ }) // 产品信息
15
+ const tabsList = ref([
16
+ {
17
+ name: 'records',
18
+ label: 'SPD产品档案',
19
+ isShow: true
20
+ },
21
+ {
22
+ name: 'qxUnique',
23
+ label: '医疗器械唯一标识数据库档案',
24
+ isShow: computed(() => productInfo.value?.productClassName && productInfo.value?.productClassName.includes('高值'))
25
+ },
26
+ {
27
+ name: 'instruction',
28
+ label: '产品说明书',
29
+ isShow: true
30
+ }
31
+ ])
32
+
33
+ const productSpecList = ref<string[]>([]) // 产品说明书
34
+ const productPictureList = ref<string[]>([]) // 产品图片
35
+ const loading = ref(false)
36
+
37
+ export const useParams = () => {
38
+ return {
39
+ dialogVisible,
40
+ tabActive,
41
+ tabsList,
42
+ previewFileRef,
43
+ productInfo,
44
+ loading,
45
+ productPictureList,
46
+ openFold,
47
+ medicalType
48
+ }
49
+ }
50
+ // 获取产品信息的接口
51
+ const GetProductFn = {
52
+ medical: getMEProductByProductCode // 医共体环境
53
+ }
54
+ // 当前的类型
55
+ const medicalType = ref<string>('')
56
+ export const useEvents = () => {
57
+ /**
58
+ * @description 打开预览弹框
59
+ * @param requestApi 查询接口
60
+ * */
61
+ //
62
+ const getDetailByCode = async (params: object, type?: string) => {
63
+ dialogVisible.value = true
64
+ if (!params) return
65
+ openFold.value = true
66
+ medicalType.value = type || ''
67
+ if (medicalType.value !== 'medical') {
68
+ // 医共体不需要查询配置
69
+ getShowImgApi()
70
+ }
71
+ try {
72
+ loading.value = true
73
+ // 医共体地址不一样
74
+ const getProductFn = type ? GetProductFn[type] : getProductByProductCode
75
+ // let params = {}
76
+ // if (typeof paramsValue === 'string') {
77
+ // params = { productCode: paramsValue }
78
+ // } else {
79
+ // params = paramsValue
80
+ // }
81
+ const res = await getProductFn(params)
82
+ if (res && res.result) {
83
+ getInformation(res.result)
84
+ }
85
+ } finally {
86
+ loading.value = false
87
+ }
88
+ }
89
+ // 处理接口内部的数据
90
+ const getInformation = async result => {
91
+ if (!result) return
92
+ try {
93
+ productInfo.value = result
94
+ const { productSpecification, productPicture } = result
95
+ if (productSpecification) {
96
+ // 产品说明书
97
+ productSpecList.value = JSON.parse(productSpecification) || []
98
+ }
99
+ if (productPicture) {
100
+ // 产品图片
101
+ productPictureList.value = JSON.parse(productPicture) || []
102
+ }
103
+ } catch (error) {
104
+ productInfo.value = { productCode: '', productClassName: '' }
105
+ productPictureList.value = []
106
+ productSpecList.value = []
107
+ }
108
+ }
109
+
110
+ // 获取配置项,是都默认展开图片
111
+ const getShowImgApi = async () => {
112
+ openFold.value = false
113
+ if (!getConfigByModuleAndKey) {
114
+ return
115
+ }
116
+ const { result } = await getConfigByModuleAndKey({
117
+ module: '产品信息管理',
118
+ key: 'IsShowImg'
119
+ })
120
+ if (result && result.configValue) {
121
+ openFold.value = JSON.parse(result.configValue) || false
122
+ }
123
+ }
124
+ // 关闭弹框
125
+ const closeDialog = () => {
126
+ dialogVisible.value = false
127
+ tabActive.value = 'records'
128
+ productInfo.value = { productCode: '', productClassName: '' }
129
+ productSpecList.value = []
130
+ productPictureList.value = []
131
+ }
132
+ //切换tab
133
+ const handleTabChange = val => {
134
+ if (val == 'instruction') {
135
+ nextTick(() => {
136
+ // previewFileRef.value.setFileInfo(list);
137
+ previewFileRef.value.setFileInfo(productSpecList.value)
138
+ })
139
+ }
140
+ }
141
+
142
+ return { getDetailByCode, closeDialog, handleTabChange }
143
+ }
@@ -0,0 +1,466 @@
1
+ import { watchEffect, ref, reactive } from "vue";
2
+ import type { FormItemsProps } from "../../JztFormGrid/interface";
3
+ const colSpan = 8;
4
+
5
+ // 产品标识基本信息
6
+ const baseSignFrom = reactive<FormItemsProps[]>([
7
+ {
8
+ groupTitle: "产品标识基本信息",
9
+ prop: "group",
10
+ collapse: false,
11
+ children: [
12
+ {
13
+ label: "最小销售单元产品标识",
14
+ prop: "",
15
+ el: "el-input",
16
+ span: colSpan,
17
+ },
18
+ {
19
+ label: "产品编码体系名称",
20
+ prop: "",
21
+ el: "el-input",
22
+ span: colSpan,
23
+ },
24
+ {
25
+ label: "产品标识发布日期",
26
+ prop: "",
27
+ el: "el-input",
28
+ span: colSpan,
29
+ },
30
+ {
31
+ label: "最小销售单元中使用单元的数量",
32
+ prop: "",
33
+ el: "el-input",
34
+ span: colSpan,
35
+ },
36
+ {
37
+ label: "使用单元产品标识",
38
+ prop: "",
39
+ el: "el-input",
40
+ span: colSpan,
41
+ },
42
+ {
43
+ label: "是否有本体标识",
44
+ prop: "",
45
+ el: "el-input",
46
+ span: colSpan,
47
+ },
48
+ ],
49
+ },
50
+ ]);
51
+ // 产品基本信息
52
+ const basicInfoFrom = reactive<FormItemsProps[]>([
53
+ {
54
+ groupTitle: "产品基本信息",
55
+ prop: "group",
56
+ collapse: false,
57
+ children: [
58
+ {
59
+ label: "产品名称/通用名称",
60
+ prop: "otherName",
61
+ el: "el-input",
62
+ span: colSpan,
63
+ },
64
+ {
65
+ label: "商品名称",
66
+ prop: "productName",
67
+ el: "el-input",
68
+ span: colSpan,
69
+ },
70
+ {
71
+ label: "型号规格/包装规格",
72
+ prop: "specification",
73
+ el: "el-input",
74
+ span: colSpan,
75
+ },
76
+ {
77
+ label: "是否为包类/组装类产品",
78
+ prop: "",
79
+ el: "el-input",
80
+ span: colSpan,
81
+ },
82
+ {
83
+ label: "产品描述",
84
+ prop: "",
85
+ el: "el-input",
86
+ span: colSpan,
87
+ },
88
+ {
89
+ label: "产品货号或编号",
90
+ prop: "",
91
+ el: "el-input",
92
+ span: colSpan,
93
+ },
94
+ {
95
+ label: "原器械目录代码",
96
+ prop: "",
97
+ el: "el-input",
98
+ span: colSpan,
99
+ },
100
+ {
101
+ label: "器械类别",
102
+ prop: "",
103
+ el: "el-input",
104
+ span: colSpan,
105
+ },
106
+ {
107
+ label: "分类编码",
108
+ prop: "",
109
+ el: "el-input",
110
+ span: colSpan,
111
+ },
112
+ {
113
+ label: "医疗器械注册人/备案人名称",
114
+ prop: "grade",
115
+ el: "el-input",
116
+ span: colSpan,
117
+ },
118
+ {
119
+ label: "医疗器械注册人/备案人英文名称",
120
+ prop: "grade",
121
+ el: "el-input",
122
+ span: colSpan,
123
+ },
124
+ {
125
+ label: "统一社会信用代码",
126
+ prop: "grade",
127
+ el: "el-input",
128
+ span: colSpan,
129
+ },
130
+ {
131
+ label: "注册证编号或者备案凭证编号",
132
+ prop: "grade",
133
+ el: "el-input",
134
+ span: colSpan,
135
+ },
136
+ {
137
+ label: "医保耗材分类编码",
138
+ prop: "grade",
139
+ el: "el-input",
140
+ span: colSpan,
141
+ },
142
+ {
143
+ label: "产品类别",
144
+ prop: "grade",
145
+ el: "el-input",
146
+ span: colSpan,
147
+ },
148
+ {
149
+ label: "磁共振(MR)安全相关信息",
150
+ prop: "grade",
151
+ el: "el-input",
152
+ span: colSpan,
153
+ },
154
+ {
155
+ label: "是否标记为一次性使用",
156
+ prop: "grade",
157
+ el: "el-input",
158
+ span: colSpan,
159
+ },
160
+ {
161
+ label: "最大重复使用次数",
162
+ prop: "grade",
163
+ el: "el-input",
164
+ span: colSpan,
165
+ },
166
+ {
167
+ label: "是否为无菌包装",
168
+ prop: "grade",
169
+ el: "el-input",
170
+ span: colSpan,
171
+ },
172
+ {
173
+ label: "使用前是否需要进行灭菌",
174
+ prop: "grade",
175
+ el: "el-input",
176
+ span: colSpan,
177
+ },
178
+ {
179
+ label: "灭菌方式",
180
+ prop: "grade",
181
+ el: "el-input",
182
+ span: colSpan,
183
+ },
184
+ {
185
+ label: "其他信息的网址链接",
186
+ prop: "grade",
187
+ el: "el-input",
188
+ span: 24,
189
+ },
190
+ ],
191
+ },
192
+ ]);
193
+ // 生产标识信息
194
+ const productSignInfo = reactive<FormItemsProps[]>([
195
+ {
196
+ groupTitle: "生产标识信息",
197
+ prop: "group",
198
+ collapse: true,
199
+ children: [
200
+ {
201
+ label: "最小销售单元中使用单元的数量",
202
+ prop: "name",
203
+ el: "el-input",
204
+ span: 12,
205
+ },
206
+ {
207
+ label: "使用单元产品标识",
208
+ prop: "age",
209
+ el: "el-input",
210
+ span: 12,
211
+ },
212
+ ],
213
+ },
214
+ ]);
215
+ // 包装标识信息
216
+ const packageInfo = reactive<FormItemsProps[]>([
217
+ {
218
+ groupTitle: "包装标识信息",
219
+ prop: "group",
220
+ collapse: true,
221
+ children: [
222
+ {
223
+ // label: "",
224
+ prop: "packageTable",
225
+ span: 24,
226
+ el: "JztTable",
227
+ props: {
228
+ tableConfig: {
229
+ columns: [
230
+ {
231
+ label: "包装产品标识",
232
+ prop: "packageId",
233
+ minWidth: 160,
234
+ },
235
+ {
236
+ label: "产品包装级别",
237
+ prop: "packageId",
238
+ minWidth: 160,
239
+ },
240
+ {
241
+ label: "本级包装内含小一级相同产品标识的包装数量",
242
+ prop: "packageId",
243
+ minWidth: 220,
244
+ },
245
+ {
246
+ label: "包含内含小一级包装产品标识",
247
+ prop: "packageId",
248
+ minWidth: 160,
249
+ },
250
+ ],
251
+ },
252
+ },
253
+ },
254
+ ],
255
+ },
256
+ ]);
257
+ // 存储或操作信息
258
+ const storeOrManipulate = reactive<FormItemsProps[]>([
259
+ {
260
+ groupTitle: "存储或操作信息",
261
+ prop: "group",
262
+ collapse: true,
263
+ children: [
264
+ {
265
+ // label: "",
266
+ prop: "packageTable",
267
+ span: 24,
268
+ el: "JztTable",
269
+ props: {
270
+ tableConfig: {
271
+ columns: [
272
+ {
273
+ label: "存储或操作条件",
274
+ prop: "packageId",
275
+ minWidth: 200,
276
+ },
277
+ {
278
+ label: "最低值",
279
+ prop: "packageId",
280
+ minWidth: 140,
281
+ },
282
+ {
283
+ label: "最高值",
284
+ prop: "packageId",
285
+ minWidth: 140,
286
+ },
287
+ {
288
+ label: "计量单位",
289
+ prop: "packageId",
290
+ minWidth: 200,
291
+ },
292
+ ],
293
+ },
294
+ },
295
+ },
296
+ {
297
+ label: "特殊存储或操作条件",
298
+ prop: "name",
299
+ el: "el-input",
300
+ span: 24,
301
+ },
302
+ ],
303
+ },
304
+ ]);
305
+ // 床使用尺寸信息
306
+ const sizeInfo = reactive<FormItemsProps[]>([
307
+ {
308
+ groupTitle: "临床使用尺寸信息",
309
+ prop: "group",
310
+ collapse: true,
311
+ children: [
312
+ {
313
+ // label: "",
314
+ prop: "packageTable",
315
+ span: 24,
316
+ el: "JztTable",
317
+ props: {
318
+ tableConfig: {
319
+ columns: [
320
+ {
321
+ label: "临床使用尺寸类型",
322
+ prop: "packageId",
323
+ minWidth: 200,
324
+ },
325
+ {
326
+ label: "尺寸值",
327
+ prop: "packageId",
328
+ minWidth: 200,
329
+ },
330
+ {
331
+ label: "尺寸单位",
332
+ prop: "packageId",
333
+ minWidth: 200,
334
+ },
335
+ ],
336
+ },
337
+ },
338
+ },
339
+ ],
340
+ },
341
+ ]);
342
+ // 版本信息
343
+ const versionInfo = reactive<FormItemsProps[]>([
344
+ {
345
+ groupTitle: "版本信息",
346
+ prop: "group",
347
+ collapse: true,
348
+ children: [
349
+ {
350
+ label: "主键编号",
351
+ prop: "name",
352
+ el: "el-input",
353
+ span: 8,
354
+ },
355
+ {
356
+ label: "公开版本号",
357
+ prop: "age",
358
+ el: "el-input",
359
+ span: 8,
360
+ },
361
+ {
362
+ label: "版本的发布日期",
363
+ prop: "age",
364
+ el: "el-input",
365
+ span: 8,
366
+ },
367
+ {
368
+ label: "版本状态",
369
+ prop: "age",
370
+ el: "el-input",
371
+ span: 8,
372
+ },
373
+ {
374
+ label: "变更备注",
375
+ prop: "age",
376
+ el: "el-input",
377
+ span: 8,
378
+ },
379
+ {
380
+ label: "退市日期",
381
+ prop: "age",
382
+ el: "el-input",
383
+ span: 8,
384
+ },
385
+ ],
386
+ },
387
+ ]);
388
+ // 纠错信息
389
+ const errorInfo = reactive<FormItemsProps[]>([
390
+ {
391
+ groupTitle: "纠错信息",
392
+ prop: "group",
393
+ collapse: true,
394
+ children: [
395
+ {
396
+ label: "最小销售单元中使用单元的数量",
397
+ prop: "name",
398
+ el: "el-input",
399
+ span: 12,
400
+ },
401
+ {
402
+ label: "使用单元产品标识",
403
+ prop: "age",
404
+ el: "el-input",
405
+ span: 12,
406
+ },
407
+ ],
408
+ },
409
+ ]);
410
+ // 企业联系信息
411
+ const enterpriseInfo = reactive<FormItemsProps[]>([
412
+ {
413
+ groupTitle: "企业联系信息",
414
+ prop: "group",
415
+ collapse: true,
416
+ children: [
417
+ {
418
+ // label: "",
419
+ prop: "packageTable",
420
+ span: 24,
421
+ el: "JztTable",
422
+ props: {
423
+ tableConfig: {
424
+ columns: [
425
+ {
426
+ label: "联系人邮箱",
427
+ prop: "packageId",
428
+ minWidth: 200,
429
+ },
430
+ {
431
+ label: "联系人电话",
432
+ prop: "packageId",
433
+ minWidth: 200,
434
+ },
435
+ {
436
+ label: "联系人传真",
437
+ prop: "packageId",
438
+ minWidth: 200,
439
+ },
440
+ ],
441
+ },
442
+ },
443
+ },
444
+ ],
445
+ },
446
+ ]);
447
+
448
+ const uniqueForm = reactive([
449
+ baseSignFrom,
450
+ basicInfoFrom,
451
+ productSignInfo,
452
+ packageInfo,
453
+ storeOrManipulate,
454
+ sizeInfo,
455
+ versionInfo,
456
+ errorInfo,
457
+ enterpriseInfo,
458
+ ]);
459
+ export const useParams = () => {
460
+ return {
461
+ uniqueForm,
462
+ };
463
+ };
464
+ export const useEvents = () => {
465
+ return {};
466
+ };
@@ -0,0 +1,116 @@
1
+ import { Component, createApp, h, nextTick, ref, Ref, Teleport, VNodeProps } from 'vue'
2
+ import JztProductInfo from './index.vue'
3
+ import type { ProductInfoRef } from './interface'
4
+
5
+ /**
6
+ * 以命令式方式调用 JztProductInfo 弹窗
7
+ * @param props 透传至组件的 props
8
+ */
9
+ export const useJztProductInfo = (props?: Record<string, any>) => {
10
+ // 创建通用挂载逻辑
11
+ const { state, cleanup, mount } = createFunctional<ProductInfoRef>(JztProductInfo, 'onClosed', 'jzt-product-info')
12
+
13
+ // 缓存用户传入的 props
14
+ state.props = props
15
+
16
+ /**
17
+ * 显示弹窗
18
+ * @param value 要展示的商品编码
19
+ */
20
+ const show = async (value: string) => {
21
+ // 若未挂载,则先挂载
22
+ if (!state.isMounted) {
23
+ mount()
24
+ await nextTick()
25
+ }
26
+
27
+ try {
28
+ // 调用组件实例方法打开弹窗
29
+ state.instanceRef.value?.openDialog(value)
30
+ } catch (error) {
31
+ console.error('JztProductInfo 打开弹窗失败:', error)
32
+ cleanup()
33
+ }
34
+ }
35
+
36
+ return { show, cleanup }
37
+ }
38
+
39
+ /** 通用状态结构 */
40
+ type BaseState<T> = {
41
+ app: ReturnType<typeof createApp> | null
42
+ instanceRef: Ref<T | null>
43
+ mountNode: HTMLDivElement | null
44
+ isMounted: boolean
45
+ props?: Record<string, any>
46
+ }
47
+
48
+ /**
49
+ * 创建可复用的“挂载-卸载”逻辑
50
+ * @param Component 待挂载的 Vue 组件
51
+ * @param closeEvent 组件关闭时触发的事件名
52
+ * @param componentName 组件唯一标识,用于日志与 data-attribute
53
+ */
54
+ export function createFunctional<T>(
55
+ Component: Component,
56
+ closeEvent: string = 'onClosed',
57
+ componentName: string = 'anonymous-component'
58
+ ) {
59
+ const state: BaseState<T> = {
60
+ app: null,
61
+ instanceRef: ref<T | null>(null) as Ref<T | null>,
62
+ mountNode: null,
63
+ isMounted: false,
64
+ props: undefined
65
+ }
66
+
67
+ /** 卸载组件并清理 DOM */
68
+ const cleanup = () => {
69
+ if (state.app) {
70
+ state.app.unmount()
71
+ state.app = null
72
+ }
73
+ if (state.mountNode?.parentElement) {
74
+ state.mountNode.parentElement.removeChild(state.mountNode)
75
+ state.mountNode = null
76
+ }
77
+ state.instanceRef.value = null
78
+ state.isMounted = false
79
+ state.props = undefined
80
+ }
81
+
82
+ /** 挂载组件到 body */
83
+ const mount = () => {
84
+ if (state.isMounted || state.app) return
85
+
86
+ try {
87
+ // 创建挂载节点
88
+ state.mountNode = document.createElement('div')
89
+ state.mountNode.dataset.component = componentName
90
+
91
+ // 合并 props:透传 + 关闭回调 + ref 绑定
92
+ const mergedProps: VNodeProps = {
93
+ ...state.props,
94
+ ref: (el: any) => (state.instanceRef.value = el as T),
95
+ [closeEvent]: cleanup
96
+ }
97
+
98
+ // 通过 Teleport 渲染到 body 下
99
+ state.app = createApp({
100
+ render: () => h(Teleport, { to: 'body' }, h(Component, mergedProps))
101
+ })
102
+ state.app.mount(state.mountNode)
103
+ state.isMounted = true
104
+ } catch (error) {
105
+ console.error(`${componentName} 挂载失败:`, error)
106
+ cleanup()
107
+ }
108
+ }
109
+
110
+ return {
111
+ state,
112
+ cleanup,
113
+ mount,
114
+ nextTick
115
+ }
116
+ }