@utogether/udp-core 1.0.1-beta.1 → 1.0.1-beta.3

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 (93) hide show
  1. package/build/plugins.ts +6 -1
  2. package/dist/{403-Dp617CWX.js → 403-BuP9jvH9.js} +1 -1
  3. package/dist/{404-Cz_Axb6Y.js → 404-DfQk8kKl.js} +1 -1
  4. package/dist/{500-BGCtRNse.js → 500-OgROWdiZ.js} +1 -1
  5. package/dist/{AuthorityInfo-DGGfm7IS.js → AuthorityInfo-q2ksfkWH.js} +1 -1
  6. package/dist/{AuthorityInfo.vue_vue_type_style_index_0_lang-BqccGW7v.js → AuthorityInfo.vue_vue_type_style_index_0_lang-Bwsf6lMH.js} +1 -1
  7. package/dist/{Company-IV3GTnzY.js → Company-DgqowAxc.js} +3 -3
  8. package/dist/{CompanyPanel-qV-_VtoL.js → CompanyPanel-BNb1rUhD.js} +16 -16
  9. package/dist/{Department-B3W-OxW8.js → Department-Cl8CROSU.js} +3 -3
  10. package/dist/{DepartmentPanel-Cw3OWxE7.js → DepartmentPanel-D5VkqKeP.js} +1 -1
  11. package/dist/{DesignPanel-BFxR2fHJ.js → DesignPanel-BGvEusHC.js} +1 -1
  12. package/dist/{DesignPanel.vue_vue_type_style_index_0_lang-DljbeFba.js → DesignPanel.vue_vue_type_style_index_0_lang-BQF1uQ7w.js} +2 -2
  13. package/dist/{DictView-C-i7e4hZ.js → DictView-BnxfaOBv.js} +13 -12
  14. package/dist/InvOrganization-5y79ZLdY.js +66 -0
  15. package/dist/{Org-CA7vTDIF.js → Org-2oBAXN2r.js} +1 -1
  16. package/dist/{Preview-BlDMmpdR.js → Preview-BaGmXH7r.js} +1 -1
  17. package/dist/{ReportDefine-Cub_85LA.js → ReportDefine-DkQdBErt.js} +1 -1
  18. package/dist/{ReportDesign-hFhq5UVE.js → ReportDesign-DzB_A_G6.js} +2 -2
  19. package/dist/{ReportQuery-ChkWEyxT.js → ReportQuery-DRcMb6ya.js} +1 -1
  20. package/dist/{ReportQueryFrom-KVyD_8Dj.js → ReportQueryFrom-CeA9xhR4.js} +1 -1
  21. package/dist/{ReportQueryFrom.vue_vue_type_style_index_0_lang-CLNODquq.js → ReportQueryFrom.vue_vue_type_style_index_0_lang-CgGtcs5V.js} +1 -1
  22. package/dist/{ReportTemplate-ag9NDvh2.js → ReportTemplate-qaiTMQuT.js} +1 -1
  23. package/dist/{Role-_q3lQ8CZ.js → Role-DsFulAjq.js} +3 -3
  24. package/dist/{RoleAssign-DZb9IRsm.js → RoleAssign-DMRdocpa.js} +3 -3
  25. package/dist/{RolePanel-CsLsz-Ds.js → RolePanel-B9POS_pg.js} +1 -1
  26. package/dist/{RolePanel-BQb1LlhD.js → RolePanel-wXVysDHM.js} +1 -1
  27. package/dist/{RolePanel.vue_vue_type_script_setup_true_lang-BrnRgHEk.js → RolePanel.vue_vue_type_script_setup_true_lang-CleVvkcY.js} +3 -3
  28. package/dist/{RolePanel.vue_vue_type_script_setup_true_lang-cmW7zBLu.js → RolePanel.vue_vue_type_script_setup_true_lang-t6S_0zmJ.js} +1 -1
  29. package/dist/{ScrollPanel.vue_vue_type_style_index_0_lang-CaFKRwXu.js → ScrollPanel.vue_vue_type_style_index_0_lang-DlXUs0j9.js} +1 -1
  30. package/dist/{Staff-BSf9Ypbk.js → Staff-Cq4V7ruC.js} +3 -3
  31. package/dist/{StaffInfo-BNKasyMF.js → StaffInfo-CJDKMbud.js} +1 -1
  32. package/dist/{StaffInfo.vue_vue_type_script_setup_true_lang-DDZ7ukd0.js → StaffInfo.vue_vue_type_script_setup_true_lang-DQ4DL1KY.js} +1 -1
  33. package/dist/{StaffPanel-Bpq0WVlH.js → StaffPanel-CG-uggdr.js} +1 -1
  34. package/dist/{StaffPanel.vue_vue_type_script_setup_true_lang-BhiJ0Q-Q.js → StaffPanel.vue_vue_type_script_setup_true_lang-DAgN7zN2.js} +2 -2
  35. package/dist/{SysUser-FAABuNti.js → SysUser-kwnzRNdD.js} +2 -2
  36. package/dist/{SysUserPanel-PxJeOgHm.js → SysUserPanel-DTlZf3vk.js} +1 -1
  37. package/dist/{SysUserPanel.vue_vue_type_script_setup_true_lang-njefUln5.js → SysUserPanel.vue_vue_type_script_setup_true_lang-BW6PlGjM.js} +1 -1
  38. package/dist/{SystemMenu-C-7NAGon.js → SystemMenu-BVT0n-L2.js} +21 -21
  39. package/dist/{UserInfo-ClXKtyGo.js → UserInfo-BbTQ9Zat.js} +1 -1
  40. package/dist/{UserInfo.vue_vue_type_style_index_0_lang-8N7P4Hl7.js → UserInfo.vue_vue_type_style_index_0_lang-D_bpYDmI.js} +1 -1
  41. package/dist/{childView-C_HmDQNd.js → childView-BJbIhjmf.js} +1 -1
  42. package/dist/{childView-uUlBcTza.js → childView-DCsGFrG-.js} +1 -1
  43. package/dist/{childView.vue_vue_type_style_index_0_lang-y0sDvYx5.js → childView.vue_vue_type_style_index_0_lang-BCDxpVoD.js} +1 -1
  44. package/dist/{childView.vue_vue_type_style_index_0_lang-Ckjmw6wJ.js → childView.vue_vue_type_style_index_0_lang-CDtsalCm.js} +1 -1
  45. package/dist/{code-rule-AgCVDKFy.js → code-rule-DePU6cdp.js} +1 -1
  46. package/dist/core.es.js +1 -1
  47. package/dist/{cron-task-C6FgQxTi.js → cron-task-DUM1SIGL.js} +1 -1
  48. package/dist/{frameView-BDgISK7N.js → frameView-CEUTDtSm.js} +1 -1
  49. package/dist/img/l_img.svg +1 -1
  50. package/dist/img/minicolors.png +0 -0
  51. package/dist/img/v_img.svg +1 -1
  52. package/dist/{index-DzOzUkf6.js → index-ZdgOD7cF.js} +59 -48
  53. package/dist/{layoutView-yb3DV2DQ.js → layoutView-PCjwVwkX.js} +109 -108
  54. package/dist/{login-RRpljbkm.js → login-B1CjWVKu.js} +2 -2
  55. package/dist/{lov-view-C9-rjzZR.js → lov-view-D8wwkxFJ.js} +2 -2
  56. package/dist/{menuInfo-CzPQyFhp.js → menuInfo-B5JKVwrB.js} +1 -1
  57. package/dist/{menuInfo.vue_vue_type_style_index_0_lang-BumXunCg.js → menuInfo.vue_vue_type_style_index_0_lang-CcM9WX4n.js} +97 -96
  58. package/dist/{pda-app-Dvy3U-b6.js → pda-app-DIa1p1Ww.js} +1 -1
  59. package/dist/{resource-Fy0lFkSV.js → resource-CCQ7Dd-5.js} +1 -1
  60. package/dist/{su-welcome-DYvSCUST.js → su-welcome-CLp9YaJa.js} +1 -1
  61. package/dist/{sys-config-DJ1vNQTy.js → sys-config-BBmf_SqF.js} +1 -1
  62. package/dist/udp-core.css +2 -2
  63. package/dist/{utogether-CjmJiHoE.js → utogether-Bkptx2lB.js} +1 -1
  64. package/package.json +18 -18
  65. package/src/App.vue +70 -70
  66. package/src/components/udp/form-upload.vue +71 -20
  67. package/src/components/udp/grid.vue +500 -0
  68. package/src/components/udp/index.ts +7 -4
  69. package/src/components/udp/lov.vue +410 -0
  70. package/src/components/udp/modal-form.vue +2 -2
  71. package/src/components/udp/modal-grid.vue +297 -0
  72. package/src/components/udp/utils.ts +379 -40
  73. package/src/layout/components/lay-navbar/index.vue +1 -1
  74. package/src/layout/components/lay-panel/index.vue +150 -150
  75. package/src/layout/components/lay-sidebar/breadCrumb.vue +1 -1
  76. package/src/layout/components/lay-tag/index.vue +625 -625
  77. package/src/layout/layoutView.vue +215 -215
  78. package/src/main.ts +4 -3
  79. package/src/plugins/i18n/en.ts +291 -289
  80. package/src/plugins/i18n/zh.ts +338 -337
  81. package/src/plugins/vxe-table/index.ts +53 -46
  82. package/src/plugins/vxe-table/render.tsx +4 -2
  83. package/src/style/button.scss +85 -78
  84. package/src/style/tailwind.css +1 -68
  85. package/src/style/vxetable.scss +258 -256
  86. package/src/views/organization/company/CompanyPanel.vue +259 -259
  87. package/src/views/organization/inv-org/InvOrganization.vue +2 -3
  88. package/src/views/system/menu/SystemMenu.vue +197 -197
  89. package/src/views/system/menu/menuInfo.vue +372 -371
  90. package/src/views/udev/dict/DictView.vue +106 -106
  91. package/src/views/udev/lov/lov-view.vue +91 -91
  92. package/vite.config.ts +4 -1
  93. package/dist/InvOrganization-cfT6riGU.js +0 -260
@@ -0,0 +1,410 @@
1
+ <template>
2
+ <div class="ut-lov-wrapper">
3
+ <vxe-modal
4
+ v-if="mode === 'vxe'"
5
+ v-model="showLovModal"
6
+ :width="modalWidth"
7
+ :destroy-on-close="false"
8
+ :title="lovTitle"
9
+ :transfer="transfer"
10
+ height="66%"
11
+ resize
12
+ esc-closable
13
+ show-footer
14
+ :className="className"
15
+ :before-hide-method="beforeHideMethod"
16
+ >
17
+ <template #default>
18
+ <vxe-grid ref="xgrid" v-bind="data" resizable @cell-dblclick="onCellClick" />
19
+ </template>
20
+ <template #footer>
21
+ <vxe-button
22
+ :content="$t('message.btn.cancel')"
23
+ icon="ri-close-line"
24
+ status="warning"
25
+ @click="onClose"
26
+ />
27
+ <vxe-button
28
+ :content="$t('message.btn.confirm')"
29
+ icon="ri-save-3-line"
30
+ status="primary"
31
+ @click="onConfirm"
32
+ />
33
+ </template>
34
+ </vxe-modal>
35
+ <el-dialog
36
+ v-else
37
+ v-model="showLovModal"
38
+ :width="modalWidth"
39
+ :show-close="false"
40
+ :title="lovTitle"
41
+ :append-to-body="transfer"
42
+ draggable
43
+ destroy-on-close
44
+ close-on-press-escape
45
+ >
46
+ <template #default>
47
+ <div style="height: 360px">
48
+ <vxe-grid ref="xgrid" v-bind="data" resizable @cell-dblclick="onCellClick" />
49
+ </div>
50
+ </template>
51
+ <template #footer>
52
+ <vxe-button
53
+ :content="$t('message.btn.cancel')"
54
+ icon="ri-close-line"
55
+ status="warning"
56
+ @click="onClose"
57
+ />
58
+ <vxe-button
59
+ :content="$t('message.btn.confirm')"
60
+ icon="ri-save-3-line"
61
+ status="primary"
62
+ @click="onConfirm"
63
+ />
64
+ </template>
65
+ </el-dialog>
66
+ <vxe-input
67
+ v-model="record[displayName || field]"
68
+ :clearable="!disabled && clearable"
69
+ :disabled="disabled"
70
+ :readonly="readonly"
71
+ :placeholder="placeholder"
72
+ style="width: 100%"
73
+ type="search"
74
+ size="mini"
75
+ @search-click="onSeach"
76
+ @clear="onClear"
77
+ />
78
+ </div>
79
+ </template>
80
+
81
+ <script lang="ts">
82
+ export default {
83
+ name: 'UtLov'
84
+ };
85
+ </script>
86
+
87
+ <script setup lang="ts">
88
+ // @ts-nocheck
89
+ import { ref, reactive, getCurrentInstance } from 'vue';
90
+ import { VxeGridProps } from 'vxe-table';
91
+ import to from 'await-to-js';
92
+ import { clone, toDateString, isEmpty } from 'xe-utils';
93
+ import { useRender, cookies, delay } from '@utogether/utils';
94
+ // import type { IFormItemProps, IRecord } from '../../types';
95
+
96
+ export interface IProps {
97
+ record: object;
98
+ defaultParams?: object;
99
+ code: string;
100
+ field: string;
101
+ displayName?: string;
102
+ placeholder?: string;
103
+ mode?: string;
104
+ clearable?: boolean;
105
+ multiple?: boolean;
106
+ disabled?: boolean;
107
+ autoLoad?: boolean;
108
+ readonly?: boolean;
109
+ transfer?: boolean;
110
+ }
111
+ const props = withDefaults(defineProps<IProps>(), {
112
+ record: () => {
113
+ return {};
114
+ },
115
+ defaultParams: () => {
116
+ return {};
117
+ },
118
+ mode: 'vxe',
119
+ placeholder: '请选择',
120
+ clearable: true,
121
+ multiple: false,
122
+ disabled: false,
123
+ readonly: true,
124
+ autoLoad: true
125
+ });
126
+
127
+ const instance = getCurrentInstance()!;
128
+ const serviceApi = instance.appContext.config.globalProperties.$serviceApi;
129
+
130
+ const minWidth = 600;
131
+ const showLovModal = ref(false);
132
+ const modalWidth = ref(minWidth);
133
+ const lovTitle = ref('');
134
+ const className = ref('vxe-table--ignore-clear');
135
+
136
+ const data = reactive<VxeGridProps>({
137
+ loading: false,
138
+ border: true,
139
+ pagerConfig: {},
140
+ formConfig: { titleWidth: 90, titleAlign: 'right', items: [] },
141
+ height: 'auto',
142
+ editConfig: {},
143
+ rowConfig: { keyField: '_X_ROW_KEY' },
144
+ proxyConfig: {
145
+ form: true, // 查询是需要启用表单代理
146
+ autoLoad: false,
147
+ response: {
148
+ result: 'list',
149
+ total: 'total'
150
+ },
151
+ ajax: {
152
+ query: ({ page, form }) => {
153
+ const commonParam = cookies.get('kCookies_param')
154
+ ? JSON.parse(cookies.get('kCookies_param'))
155
+ : {};
156
+ let queryParams = Object.assign({}, form, commonParam, props.defaultParams);
157
+ queryParams.pageNum = page?.currentPage || 1;
158
+ queryParams.pageSize = page?.pageSize || 20;
159
+ if (!props.readonly) {
160
+ const { field, displayName } = props;
161
+ // 非只读时,意味着可录入文本,此时查询是需要加上录入的文本内容作为条件
162
+ queryParams[displayName || field] = props.record[displayName || field];
163
+ }
164
+ // console.log(queryParams);
165
+ queryParams = formatterParam(queryParams);
166
+ if (lovData.lovType !== 'url') {
167
+ queryParams.lovCode = props.code;
168
+ return serviceApi.get('/upfm/v1/lovViewHeader/listBySql', queryParams);
169
+ }
170
+ return serviceApi.get(lovData.lovUrl, queryParams);
171
+ }
172
+ }
173
+ },
174
+ checkboxConfig: {},
175
+ columns: []
176
+ });
177
+
178
+ // const displayName = ref(null);
179
+ let lovData = undefined;
180
+ let dataList = [];
181
+
182
+ const formatterParam = params => {
183
+ const columns = dataList.filter(col => ['date', 'month'].includes(col.fieldType) && col.isSearch);
184
+ columns.forEach(col => {
185
+ if (col.fieldType === 'date') {
186
+ params[col.field] = toDateString(params[col.field], 'yyyy-MM-dd 00:00:00');
187
+ } else if (col.fieldType === 'month') {
188
+ params[col.field] = toDateString(params[col.field], 'yyyy-MM');
189
+ }
190
+ });
191
+ return params;
192
+ };
193
+ // 查询字段
194
+ const getFormItem = () => {
195
+ const items = clone(dataList, true).filter(col => col.isSearch === 'Y');
196
+ if (!items.length) return;
197
+ // console.log(items);
198
+ const isCollapse = items.length > 2;
199
+ const forItems: IFormItemProps[] = items
200
+ .sort((a, b) => a.seqNo - b.seqNo)
201
+ .map((item: IRecord, idx) => {
202
+ return {
203
+ field: item.colField,
204
+ title: item.colTitle,
205
+ span: 8,
206
+ folding: idx > 1,
207
+ itemRender: getItemRender(item)
208
+ };
209
+ });
210
+ searchBtn.collapseNode = isCollapse;
211
+ if (isCollapse) {
212
+ // 按钮设置为 折叠节点并将搜索按钮插入到第一列的最后
213
+ forItems.splice(2, 0, searchBtn);
214
+ } else {
215
+ forItems.push(searchBtn);
216
+ }
217
+ data.formConfig.items = forItems;
218
+ };
219
+ const searchBtn: IFormItemProps = {
220
+ span: 8,
221
+ align: 'right',
222
+ collapseNode: false,
223
+ itemRender: {
224
+ name: 'VxeButtonGroup',
225
+ options: [
226
+ {
227
+ type: 'submit',
228
+ submit: 'submit',
229
+ content: 'message.btn.search',
230
+ status: 'primary',
231
+ icon: 'ri-search-line'
232
+ // props: {
233
+ // },
234
+ },
235
+ {
236
+ type: 'reset',
237
+ name: 'reset',
238
+ content: 'message.btn.reset',
239
+ status: 'info',
240
+ icon: 'ri-refresh-line'
241
+ // props: {
242
+ // },
243
+ }
244
+ ]
245
+ }
246
+ };
247
+
248
+ // console.log("useRender", useRender);
249
+ const renderHook = useRender();
250
+
251
+ const getItemRender = item => {
252
+ if (['date', 'month'].includes(item.fieldType)) {
253
+ const valueFormat = item.fieldType === 'date' ? 'yyyy-MM-dd HH:mm:ss' : 'yyyy-MM';
254
+ return renderHook.renderDate({ type: item.fieldType, valueFormat });
255
+ } else if (item.fieldType === 'dictCode') {
256
+ return renderHook.renderDict(item.dictCode);
257
+ }
258
+ return { name: 'VxeInput' };
259
+ };
260
+
261
+ // 获取columns
262
+ const getColumns = () => {
263
+ const columns = clone(dataList, true).filter((col: IRecord) => col.isCol === 'Y');
264
+ const colWidth = columns.reduce((curv, prev: IRecord) => curv + +prev.colWidth, 65);
265
+ modalWidth.value = colWidth < minWidth ? minWidth : colWidth > 900 ? 900 : colWidth;
266
+ data.columns = columns
267
+ .sort((a, b) => a.seqNo - b.seqNo)
268
+ .map(col => {
269
+ const fieldType = col.fieldType;
270
+ const dictCode = ['formatDict', col.dictCode];
271
+ return {
272
+ field: col.colField,
273
+ title: col.colTitle,
274
+ minWidth: col.colWidth,
275
+ formatter: fieldType === 'date' ? ['formatDate'] : col.fieldType === 'dictCode' ? dictCode : null
276
+ };
277
+ });
278
+ if (props.multiple) {
279
+ data.columns.unshift({ type: 'checkbox', width: 45, align: 'center' });
280
+ } else {
281
+ data.columns.unshift({ type: 'radio', width: 45, align: 'center' });
282
+ }
283
+ };
284
+
285
+ // 获取grid配置
286
+ const xgrid = ref(null);
287
+
288
+ const getGridConfig = async () => {
289
+ console.log('88888');
290
+ data.loading = true;
291
+ const url = '/upfm/v1/lovViewHeader/detailByViewCode';
292
+ const [err, res]: [Error, any] = await to(serviceApi.get(url, { lovCode: props.code }));
293
+ data.loading = false;
294
+ if (err) onClose();
295
+ lovTitle.value = res?.lovTitle || res.lovName;
296
+ dataList = res.lineList;
297
+ lovData = res;
298
+ props.autoLoad && xgrid.value.commitProxy('query');
299
+ getColumns();
300
+ getFormItem();
301
+ };
302
+
303
+ const onSeach = async () => {
304
+ if (props.disabled) return;
305
+ getGridConfig();
306
+ await delay(64);
307
+ showLovModal.value = true;
308
+ };
309
+
310
+ const onClear = () => {
311
+ emit('clear', '');
312
+ };
313
+
314
+ // 双击
315
+ const onCellClick = ({ row }) => {
316
+ const record = !props.multiple ? row : [row];
317
+ emit('change', record, lovData.valueField);
318
+ onClose();
319
+ };
320
+
321
+ const onConfirm = () => {
322
+ const grid = xgrid.value;
323
+ const record = !props.multiple ? grid.getRadioRecord() : grid.getCheckboxRecords();
324
+ !isEmpty(record) && emit('change', record, lovData.valueField);
325
+ onClose();
326
+ };
327
+ /** 输入框显示值 */
328
+ // const setDisplayLabel = row => {
329
+ // let value = row[lovData.valueField];
330
+ // if (props.multiple) {
331
+ // value = row.map(m => m[lovData.valueField]).join();
332
+ // }
333
+ // Object.assign(props.record, { [props.field]: value });
334
+ // };
335
+
336
+ // 关闭Lov
337
+ const onClose = () => {
338
+ dataList.length = 0;
339
+ showLovModal.value = false;
340
+ };
341
+
342
+ const beforeHideMethod = ({ type }) => {
343
+ // console.log("cccc", type);
344
+ };
345
+
346
+ const emit = defineEmits<{
347
+ (e: 'clear', str: ''): void;
348
+ (e: 'change', record: any, field: string): void;
349
+ }>();
350
+ </script>
351
+
352
+ <style lang="scss">
353
+ .ut-lov-wrapper {
354
+ .vxe-pager .vxe-pager--sizes {
355
+ display: inline-block;
356
+ width: 7em !important;
357
+ text-align: center;
358
+ cursor: pointer;
359
+ }
360
+
361
+ .el-dialog__header {
362
+ padding: 0.6em 4.6em 0.6em 1em;
363
+ margin-right: 0;
364
+ background-color: #f8f8f8;
365
+ border-bottom: 1px solid #ebeef5;
366
+
367
+ .el-dialog__title {
368
+ font-size: 1.1em;
369
+ font-weight: 600;
370
+ color: #000 !important;
371
+ }
372
+ }
373
+
374
+ .el-dialog__body {
375
+ padding: 5px 6px;
376
+ }
377
+
378
+ .el-dialog__footer {
379
+ padding: 5px 6px;
380
+ }
381
+
382
+ .vxe-grid {
383
+ .vxe-form {
384
+ .vxe-form--item {
385
+ .vxe-form--item-title-label {
386
+ font-weight: 500 !important;
387
+ color: #000 !important;
388
+ }
389
+
390
+ .vxe-input--date-picker-suffix {
391
+ color: #000 !important;
392
+ }
393
+ }
394
+ }
395
+
396
+ .vxe-cell {
397
+ .vxe-cell--label {
398
+ font-weight: 500 !important;
399
+ color: #000 !important;
400
+ }
401
+ }
402
+ }
403
+
404
+ .vxe-input {
405
+ i[class*='vxe-icon-'] {
406
+ color: #6a6a6a !important;
407
+ }
408
+ }
409
+ }
410
+ </style>
@@ -49,9 +49,9 @@ export default {
49
49
  <script lang="ts" setup>
50
50
  import { onBeforeMount, ref, computed, getCurrentInstance, useAttrs } from 'vue';
51
51
  import { useI18n } from 'vue-i18n';
52
- import { getAttrs, formatItems } from './utils';
52
+ import { getAttrs } from './utils';
53
53
  import to from 'await-to-js';
54
- import { formatRules, successMessage } from '@utogether/utils';
54
+ import { formatRules, successMessage, formatItems } from '@utogether/utils';
55
55
 
56
56
  // import type { IRecord, IFormItemProps } from '../../types';
57
57
 
@@ -0,0 +1,297 @@
1
+ <!--
2
+ * @Author: wei.li
3
+ * @Date: 2021-11-24 17:53:49
4
+ * @LastEditors: levi7754 levi7754@163.com
5
+ * @LastEditTime: 2025-07-22 11:42:46
6
+ * @Description: 共用弹框
7
+ -->
8
+ <template>
9
+ <div>
10
+ <vxe-modal
11
+ v-model="showModal"
12
+ :title="title"
13
+ :width="width"
14
+ :height="height"
15
+ :loading="data.loading"
16
+ :show-footer="showFooter"
17
+ resize
18
+ destroy-on-close
19
+ @close="close"
20
+ >
21
+ <template #default>
22
+ <slot />
23
+ <vxe-grid
24
+ ref="xGrid"
25
+ v-bind="data"
26
+ resizable
27
+ v-on="attrs.events || {}"
28
+ @edit-activated="onEditActived"
29
+ @toolbarButtonClick="toolbarButtonClick"
30
+ @toolbarToolClick="toolbarButtonClick"
31
+ @cell-click="cellClick"
32
+ />
33
+ </template>
34
+ <template #footer>
35
+ <slot name="bottom" />
36
+ <ut-button icon="ri-close-line" status="warning" content="cancel" @tap="close" />
37
+ <ut-button icon="ri-save-3-line" content="confirm" @tap="onConfirm" />
38
+ </template>
39
+ </vxe-modal>
40
+ </div>
41
+ </template>
42
+ <script lang="ts">
43
+ export default {
44
+ name: 'UtModalGrid'
45
+ };
46
+ </script>
47
+ <script lang="ts" setup>
48
+ // @ts-nocheck
49
+ import { onBeforeMount, reactive, ref, toRaw, getCurrentInstance, useAttrs } from 'vue';
50
+ import { useI18n } from 'vue-i18n';
51
+ import { VxeGridProps } from 'vxe-table';
52
+ import { formatGridItems, i18nColums, formatRules, successMessage, warnMessage } from '@utogether/utils';
53
+ import { clone, isFunction } from 'xe-utils';
54
+ import {
55
+ queryAll,
56
+ query,
57
+ del,
58
+ save,
59
+ footerSumMethod,
60
+ getToolBarConfig,
61
+ onCheckMethod,
62
+ getAttrs
63
+ } from './utils';
64
+
65
+ // import type { IRecord, IFormItemProps, ITableColProps } from '../../types';
66
+
67
+ export interface IProps {
68
+ checkMethod?: Function;
69
+ columns: Array<ITableColProps>; // 列表行
70
+ defaultValue?: IRecord;
71
+ defaultParams?: IRecord;
72
+ gridOptions?: IRecord;
73
+ auth?: IRecord;
74
+ url?: string; // 查询服务路径
75
+ submitUrl?: string; // 确认
76
+ checkRowKeys?: Array<string>; // 默认选中列表
77
+ items?: Array<IFormItemProps>; // 查询条件
78
+ title?: string; // 标题
79
+ width?: number | string;
80
+ height?: number;
81
+ editable?: boolean; // 可编辑
82
+ needExport?: boolean; // 是否需要导出
83
+ showFooter?: boolean; // 显示底部按钮
84
+ addChild?: boolean; // 可编辑
85
+ autoClose?: boolean; // 组件自主关闭
86
+ autoLoad?: boolean; // 是否自动加载查询数据
87
+ }
88
+ const attrs: IRecord = getAttrs(useAttrs());
89
+
90
+ const props = withDefaults(defineProps<IProps>(), {
91
+ gridOptions: () => {
92
+ return {};
93
+ },
94
+ items: () => [],
95
+ columns: () => [],
96
+ checkRowKeys: () => [],
97
+ addChild: false,
98
+ editable: true,
99
+ showFooter: false,
100
+ autoLoad: true,
101
+ needExport: true,
102
+ autoClose: true,
103
+ width: '520',
104
+ height: 420,
105
+ title: '数据记录',
106
+ url: '',
107
+ submitUrl: ''
108
+ });
109
+
110
+ const showModal = ref(false);
111
+
112
+ const xGrid = ref(null);
113
+ const instance = getCurrentInstance()!;
114
+
115
+ const hasAuthority = instance.appContext.config.globalProperties.$hasAuthority;
116
+ const serviceApi = instance.appContext.config.globalProperties.$serviceApi;
117
+ const $mode = instance.appContext.config.globalProperties.$mode;
118
+
119
+ const { t } = useI18n();
120
+
121
+ /**
122
+ * @description: colum 统一添加国家化
123
+ */
124
+ const getColumns = () => {
125
+ const col = props.columns.map(m => {
126
+ if (!props.editable) {
127
+ m.editRender = { enabled: false };
128
+ } else if (!m.type && !m.editRender && props.editable && !!m.editable) {
129
+ m.editRender = { name: 'VxeInput' };
130
+ }
131
+ return m;
132
+ });
133
+ return i18nColums(col);
134
+ };
135
+
136
+ const getItems = () => {
137
+ if (!props.items.length) return props.items;
138
+ return formatGridItems(clone(props.items, true));
139
+ };
140
+
141
+ /**
142
+ * @description: 根据items 获取必填选
143
+ */
144
+ const getRules = () => {
145
+ if (!props.columns.length) return {};
146
+ return formatRules(props.columns, t);
147
+ };
148
+
149
+ const data = reactive<VxeGridProps>({
150
+ loading: false,
151
+ border: true,
152
+ pagerConfig: {},
153
+ formConfig: {},
154
+ toolbarConfig: { enabled: false },
155
+ height: 'auto',
156
+ editConfig: {},
157
+ rowConfig: { keyField: '_X_ROW_KEY' },
158
+ editRules: getRules(),
159
+ proxyConfig: {
160
+ form: true, // 查询是需要启用表单代理
161
+ autoLoad: props.autoLoad,
162
+ ajax: {
163
+ queryAll: ({ form }) => queryAll(props, serviceApi, form),
164
+ query: ({ page, form }) => query(props, form, page, serviceApi, $mode),
165
+ delete: ({ body: { removeRecords } }) => del(serviceApi, removeRecords, props),
166
+ save: ({ body }) => Promise.all(save(serviceApi, body, props))
167
+ }
168
+ },
169
+ checkboxConfig: {
170
+ checkMethod: ({ row }) => onCheckMethod(row, props),
171
+ checkRowKeys: props.checkRowKeys
172
+ },
173
+ columns: getColumns(),
174
+ ...props.gridOptions
175
+ });
176
+
177
+ // 确认数据
178
+ const onConfirm = async () => {
179
+ let records = null;
180
+ const type = props.columns[0].type;
181
+ if (type === 'checkbox') {
182
+ records = xGrid.value.getCheckboxRecords();
183
+ } else if (type === 'radio') {
184
+ records = xGrid.value.getRadioRecord();
185
+ } else {
186
+ records = xGrid.value.getTableData().fullData;
187
+ }
188
+ if (type === 'checkbox' && !records.length && !props.addChild) {
189
+ return warnMessage(t('message.selectedRecord'));
190
+ } else if (type === 'radio' && !records) {
191
+ return warnMessage(t('message.selectedRecord'));
192
+ }
193
+ if (isFunction(attrs.beforeConfirm) && !attrs.beforeConfirm(records)) return;
194
+ const { submitUrl } = props;
195
+ // 服务submitUrl
196
+ if (submitUrl) {
197
+ showLoading();
198
+ let res;
199
+ try {
200
+ records.forEach(record => Object.assign(record, props.defaultParams));
201
+ res = await serviceApi.post(submitUrl, records);
202
+ } finally {
203
+ res && emit('confirm', res);
204
+ res && successMessage(t('message.operateSuccess'));
205
+ close();
206
+ hiddenLoading();
207
+ }
208
+ } else {
209
+ props.autoClose && close();
210
+ emit('confirm', records);
211
+ }
212
+ };
213
+ // 请求数据
214
+ const refreshData = () => {
215
+ xGrid.value.commitProxy('query');
216
+ };
217
+ const refreshColumn = () => {
218
+ data.editRules = getRules();
219
+ xGrid.value.refreshColumn();
220
+ };
221
+ const getInstance = () => {
222
+ return toRaw(xGrid.value);
223
+ };
224
+ const cellClick = ({ row }) => {
225
+ const type = props.columns[0].type;
226
+ if (type === 'checkbox') {
227
+ xGrid.value.setCheckboxRow(row, true);
228
+ } else if (type === 'radio') {
229
+ xGrid.value.setRadioRow(row);
230
+ }
231
+ };
232
+ // 单元格被激活编辑激活回调
233
+ const onEditActived = data => {
234
+ emit('actived', data);
235
+ };
236
+ const toolbarButtonClick = ({ code }) => {
237
+ emit('buttonClick', code);
238
+ };
239
+ const showLoading = () => {
240
+ data.loading = true;
241
+ };
242
+ const hiddenLoading = () => {
243
+ data.loading = false;
244
+ };
245
+ const emit = defineEmits<{
246
+ (e: 'close'): void;
247
+ (e: 'confirm', record: any): void;
248
+ (e: 'actived', record: any): void;
249
+ (e: 'buttonClick', code: string): void;
250
+ }>();
251
+ // 关闭弹框
252
+ const close = () => {
253
+ if (isFunction(attrs.beforeClose) && !attrs.beforeClose()) return;
254
+ showModal.value = false;
255
+ emit('close');
256
+ };
257
+
258
+ /**
259
+ * @description: 设置grid参数
260
+ */
261
+
262
+ const setGridConfig = () => {
263
+ // 查询
264
+ if (props.items.length) {
265
+ data.formConfig = {
266
+ titleWidth: 100,
267
+ titleAlign: 'right',
268
+ items: getItems(),
269
+ rules: formatRules(props.items, t),
270
+ validConfig: { showMessage: false }
271
+ };
272
+ }
273
+ // tool bar
274
+ const obj = getToolBarConfig(data, props, attrs, hasAuthority);
275
+ Object.assign(data, obj);
276
+
277
+ // 合计方法
278
+ if (attrs.mergeFooter) {
279
+ data.showFooter = true;
280
+ data.footerMethod = ({ columns, data }) => footerSumMethod({ columns, data }, attrs.mergeFooter);
281
+ }
282
+ };
283
+
284
+ // 子组件需对外暴露方法
285
+ defineExpose({
286
+ refreshData,
287
+ refreshColumn,
288
+ getInstance,
289
+ showLoading,
290
+ hiddenLoading,
291
+ close
292
+ });
293
+ onBeforeMount(() => {
294
+ showModal.value = true;
295
+ setGridConfig();
296
+ });
297
+ </script>