sohelp-eleplus 1.1.27 → 1.1.28

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 (202) hide show
  1. package/components.js +1 -0
  2. package/package.json +2 -2
  3. package/sohelp-ace-editor/README.md +32 -42
  4. package/sohelp-ace-editor/index.vue +166 -156
  5. package/sohelp-api-doc/README.md +36 -0
  6. package/sohelp-api-doc/index.vue +160 -0
  7. package/sohelp-application-select/README.md +9 -7
  8. package/sohelp-application-select/index.vue +10 -13
  9. package/sohelp-autocode/README.md +14 -26
  10. package/sohelp-calendar-view/README.md +9 -7
  11. package/sohelp-calendar-view/index.vue +10 -9
  12. package/sohelp-card/README.md +15 -17
  13. package/sohelp-card/index.vue +1 -1
  14. package/sohelp-card-view/README.md +9 -7
  15. package/sohelp-card-view/index.vue +10 -9
  16. package/sohelp-condition/README.md +29 -49
  17. package/sohelp-condition/index.vue +2 -1
  18. package/sohelp-country-select/README.md +15 -123
  19. package/sohelp-cry-input/README.md +19 -195
  20. package/sohelp-cry-input/index.vue +5 -1
  21. package/sohelp-date/README.md +12 -15
  22. package/sohelp-datetime/README.md +15 -17
  23. package/sohelp-datetime-picker/README.md +18 -18
  24. package/sohelp-datetime-picker/index.vue +11 -4
  25. package/sohelp-datetime-range/README.md +20 -23
  26. package/sohelp-demo-block/README.md +43 -0
  27. package/sohelp-demo-block/index.vue +229 -0
  28. package/sohelp-dict/README.md +28 -23
  29. package/sohelp-dict/index.vue +17 -17
  30. package/sohelp-drawer/README.md +28 -26
  31. package/sohelp-drop-card/README.md +29 -28
  32. package/sohelp-drop-card/index.vue +0 -1
  33. package/sohelp-dyn-select/README.md +31 -16
  34. package/sohelp-dyn-select/index.vue +65 -67
  35. package/sohelp-dyn-tree/README.md +26 -20
  36. package/sohelp-dyn-tree/index.vue +2 -2
  37. package/sohelp-dyn-tree-select/README.md +28 -19
  38. package/sohelp-dyn-tree-select/index.vue +23 -7
  39. package/sohelp-entity-form/README.md +65 -30
  40. package/sohelp-entity-form/index.vue +3 -2
  41. package/sohelp-entity-grid/README.md +13 -11
  42. package/sohelp-entity-grid/index.vue +1 -1
  43. package/sohelp-file-upload/README.md +25 -27
  44. package/sohelp-file-upload/index.vue +1 -1
  45. package/sohelp-filter-scheme/README.md +34 -30
  46. package/sohelp-filter-scheme/index.vue +2 -2
  47. package/sohelp-grid/README.md +52 -33
  48. package/sohelp-grid/index.vue +2217 -2210
  49. package/sohelp-grid/js/SohelpGridConfig.js +3 -3
  50. package/sohelp-grid/js/useSohelpGridConfig.js +641 -642
  51. package/sohelp-grid-select/README.md +32 -27
  52. package/sohelp-grid-select/index.vue +6 -5
  53. package/sohelp-grid-view/README.md +51 -22
  54. package/sohelp-grid-view-select/README.md +33 -25
  55. package/sohelp-grid-view-select/index.vue +2 -1
  56. package/sohelp-group-view/README.md +14 -4
  57. package/sohelp-group-view/index.vue +10 -9
  58. package/sohelp-icon-select/README.md +14 -12
  59. package/sohelp-image-upload/README.md +27 -27
  60. package/sohelp-image-upload/index.vue +2 -2
  61. package/sohelp-import/README.md +25 -24
  62. package/sohelp-input/README.md +27 -11
  63. package/sohelp-input/index.vue +15 -2
  64. package/sohelp-input-tag/README.md +53 -0
  65. package/sohelp-input-tag/index.vue +337 -0
  66. package/sohelp-modal/README.md +42 -16
  67. package/sohelp-modal/index.vue +21 -4
  68. package/sohelp-modal-select/README.md +745 -0
  69. package/sohelp-modal-select/index.vue +705 -0
  70. package/sohelp-module/README.md +24 -13
  71. package/sohelp-number-input/README.md +15 -8
  72. package/sohelp-number-input/index.vue +3 -0
  73. package/sohelp-number-range/README.md +22 -12
  74. package/sohelp-number-range/index.vue +3 -11
  75. package/sohelp-org-modal-select/README.md +47 -0
  76. package/sohelp-org-modal-select/index.vue +411 -0
  77. package/sohelp-org-select/README.md +23 -10
  78. package/sohelp-org-select/index.vue +41 -24
  79. package/sohelp-org-tree/README.md +19 -7
  80. package/sohelp-org-tree/index.vue +1 -2
  81. package/sohelp-org-tree-select/README.md +22 -11
  82. package/sohelp-org-tree-select/index.vue +1 -2
  83. package/sohelp-org-user-tree/README.md +19 -7
  84. package/sohelp-org-user-tree/index.vue +1 -2
  85. package/sohelp-org-user-tree-select/README.md +8 -3
  86. package/sohelp-org-user-tree-select/index.vue +8 -7
  87. package/sohelp-page/README.md +20 -11
  88. package/sohelp-page/index.vue +1 -1
  89. package/sohelp-pagination/README.md +14 -6
  90. package/sohelp-pagination/index.vue +1 -1
  91. package/sohelp-power/README.md +34 -19
  92. package/sohelp-power/index.vue +2 -2
  93. package/sohelp-pro-form/README.md +64 -21
  94. package/sohelp-pro-layout/README.md +10 -4
  95. package/sohelp-pro-layout/index.vue +8 -7
  96. package/sohelp-pro-table/README.md +30 -6
  97. package/sohelp-process/README.md +26 -13
  98. package/sohelp-process/index.vue +6 -6
  99. package/sohelp-rate/README.md +24 -12
  100. package/sohelp-rate/index.vue +5 -1
  101. package/sohelp-relation/README.md +10 -4
  102. package/sohelp-relation/index.vue +8 -7
  103. package/sohelp-relation-modal-select/README.md +41 -0
  104. package/sohelp-relation-modal-select/index.vue +70 -0
  105. package/sohelp-rich-text/README.md +29 -11
  106. package/sohelp-rich-text/index.vue +21 -20
  107. package/sohelp-richtext/README.md +12 -2
  108. package/sohelp-richtext/index.vue +8 -6
  109. package/sohelp-role-modal-select/README.md +45 -0
  110. package/sohelp-role-modal-select/index.vue +111 -0
  111. package/sohelp-role-select/README.md +18 -10
  112. package/sohelp-role-select/index.vue +36 -27
  113. package/sohelp-search/README.md +12 -4
  114. package/sohelp-search/index.vue +2 -2
  115. package/sohelp-search-pro-form/README.md +15 -1
  116. package/sohelp-search-pro-form/index.vue +2 -1
  117. package/sohelp-select/README.md +31 -30
  118. package/sohelp-select/index.vue +79 -84
  119. package/sohelp-split-panel/README.md +17 -18
  120. package/sohelp-switch/README.md +21 -19
  121. package/sohelp-switch/index.vue +34 -33
  122. package/sohelp-table/README.md +35 -27
  123. package/sohelp-table/index.vue +110 -109
  124. package/sohelp-table-select/README.md +55 -0
  125. package/sohelp-tenant-select/README.md +19 -18
  126. package/sohelp-tenant-select/index.vue +105 -109
  127. package/sohelp-text/README.md +16 -10
  128. package/sohelp-text/index.vue +5 -5
  129. package/sohelp-textarea-input/README.md +19 -12
  130. package/sohelp-time/README.md +11 -10
  131. package/sohelp-tree/README.md +24 -19
  132. package/sohelp-tree/index.vue +21 -23
  133. package/sohelp-tree-select/README.md +23 -10
  134. package/sohelp-user-modal-select/README.md +739 -0
  135. package/sohelp-user-modal-select/index.vue +87 -0
  136. package/sohelp-user-select/README.md +26 -15
  137. package/sohelp-user-select/index.vue +6 -2
  138. package/sohelp-user-tag/README.md +5 -7
  139. package/sohelp-user-tag/index.vue +8 -8
  140. package/sohelp-user-tree/README.md +5 -8
  141. package/sohelp-user-tree/index.vue +8 -7
  142. package/sohelp-vform-drawer/README.md +36 -18
  143. package/sohelp-vform-drawer/index.vue +2 -2
  144. package/sohelp-vform-eleplus/README.md +33 -31
  145. package/sohelp-vform-eleplus/index.vue +2 -2
  146. package/sohelp-vform-eleplus/tinymce/langs/zh_CN.js +461 -461
  147. package/sohelp-vform-eleplus/tinymce/langs/zh_TW.js +418 -418
  148. package/sohelp-vform-eleplus/tinymce/skins/content/dark/content.css +72 -72
  149. package/sohelp-vform-eleplus/tinymce/skins/content/dark/content.min.css +7 -7
  150. package/sohelp-vform-eleplus/tinymce/skins/content/default/content.css +67 -67
  151. package/sohelp-vform-eleplus/tinymce/skins/content/default/content.min.css +7 -7
  152. package/sohelp-vform-eleplus/tinymce/skins/content/document/content.css +72 -72
  153. package/sohelp-vform-eleplus/tinymce/skins/content/document/content.min.css +7 -7
  154. package/sohelp-vform-eleplus/tinymce/skins/content/writer/content.css +68 -68
  155. package/sohelp-vform-eleplus/tinymce/skins/content/writer/content.min.css +7 -7
  156. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.css +732 -732
  157. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.inline.css +726 -726
  158. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.inline.min.css +7 -7
  159. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.min.css +7 -7
  160. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.mobile.css +29 -29
  161. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.mobile.min.css +7 -7
  162. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.css +3047 -3047
  163. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.min.css +7 -7
  164. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.mobile.css +673 -673
  165. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.mobile.min.css +7 -7
  166. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.shadowdom.css +37 -37
  167. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.shadowdom.min.css +7 -7
  168. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.css +714 -714
  169. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.inline.css +726 -726
  170. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.inline.min.css +7 -7
  171. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.min.css +7 -7
  172. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.mobile.css +29 -29
  173. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.mobile.min.css +7 -7
  174. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.css +3047 -3047
  175. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.min.css +7 -7
  176. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.mobile.css +673 -673
  177. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.mobile.min.css +7 -7
  178. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.shadowdom.css +37 -37
  179. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css +7 -7
  180. package/sohelp-vform-modal/README.md +36 -18
  181. package/sohelp-vform-modal/index.vue +2 -2
  182. package/sohelp-vform-select/README.md +9 -7
  183. package/sohelp-vform-select/index.vue +8 -7
  184. package/sohelp-vxe-grid/DefaultGridOptions.js +5 -3
  185. package/sohelp-vxe-grid/DefaultProps.js +0 -1
  186. package/sohelp-vxe-grid/README.md +540 -35
  187. package/sohelp-vxe-grid/SohelpGridConfig.js +8 -6
  188. package/sohelp-vxe-grid/index.vue +141 -94
  189. package/sohelp-vxe-grid-select/README.md +41 -26
  190. package/sohelp-vxe-table/README.md +23 -20
  191. package/sohelp-vxe-table/index.vue +5 -4
  192. package/sohelp-workflow/README.md +21 -17
  193. package/sohelp-workflow/index.vue +25 -22
  194. package/sohelp-workflow-drawer/README.md +41 -28
  195. package/sohelp-workflow-drawer/components/table.vue +158 -158
  196. package/sohelp-workflow-drawer/index.vue +86 -71
  197. package/sohelp-workflow-drawer/js/index.js +15 -13
  198. package/style/index.scss +0 -0
  199. package/utils/safe-eval.js +89 -0
  200. package/sohelp-dyn-select/props.js +0 -67
  201. package/sohelp-user-select/index.vue~ +0 -53
  202. package/sohelp-user-select/props.js +0 -71
@@ -1,2210 +1,2217 @@
1
- <script setup>
2
- import { Filter, Search, Sort, SortDown, SortUp,Setting,Memo,Menu,Tickets,Postcard, Files, Grid, Refresh} from "@element-plus/icons-vue";
3
- import { useMobile } from "@/utils/use-mobile";
4
- import { usePermission } from "@/utils/use-permission";
5
- import DefaultProps from "./js/DefaultProps";
6
- import { computed, nextTick, reactive, ref, watch } from "vue";
7
- import DefaultGridOptions from "./js/DefaultGridOptions";
8
- import { calcSummary, switchGridValue } from "./js/SohelpGridConfig";
9
- import { EleMessage } from "@/components/ele-admin-plus/components";
10
- import { ElMessageBox } from "element-plus/es";
11
- import { useFormData } from "@/utils/use-form-data";
12
- import { resetCommonConfig, updateCommonConfig } from "../http/ModuleHttp.js";
13
- import CrudHttp from "../http/CrudHttp.js";
14
- import {merge, cloneDeep } from "lodash-es";
15
- import { uuid } from "../utils/core.js"
16
-
17
- import ApprovalModal from "../sohelp-workflow-drawer/components/approval-modal.vue";
18
- import WorkflowDrawer from "../sohelp-workflow-drawer/index.vue";
19
-
20
- import SohelpTextareaInput from "../sohelp-textarea-input/index.vue";
21
- import SohelpPower from "../sohelp-power/index.vue";
22
- import FilterConditionItem from "./components/filter-condition-item.vue";
23
- import { useSohelpGridConfig } from "./js/useSohelpGridConfig.js";
24
- import { useI18n } from "vue-i18n";
25
- import SohelpEntityForm from "../sohelp-entity-form/index.vue";
26
- import * as ElementPlusIcons from '@element-plus/icons-vue';
27
- import * as EleAdminPlusIcons from '@/components/icons';
28
- import { moduleCache } from "../cache/ModuleCache.js";
29
- import SohelpModal from "../sohelp-modal/index.vue";
30
- import SohelpImport from "../sohelp-import/index.vue";
31
- import { useUserStore } from '@/store/modules/user';
32
- import { Alert } from "vxe-pc-ui";
33
- const { initial, isConfigDone } = useSohelpGridConfig();
34
- const { t } = useI18n();
35
- const { mobile } = useMobile();
36
- const permission = usePermission();
37
- const props = defineProps({ ...JSON.parse(JSON.stringify(DefaultProps)) });
38
- const emit = defineEmits(["resetFilter", "checkboxAll", "checkboxChange","radioChange", "toolbarButtonClick", "operationButtonClick", "menuRightClick", "showFilter", "editClosed", "currentColumnChange"]);
39
- const drawerKey = ref(0);
40
- const todoDrawerRef = ref(null);
41
- const drawerVisible = ref(false);
42
- const drawerData = ref(null);
43
- const current = ref(null);
44
- const isPage = ref(false);
45
- const approvalModalVisible = ref(false);
46
- const approvalData = ref({});
47
- const userStore = useUserStore();
48
-
49
- //报表打印
50
- const currentReportValue = ref(null);
51
- const visibleReport = ref(false);
52
- const reportData = ref([]);
53
- const currentRow = ref(null);
54
-
55
- /** 自动生成ID */
56
- const getId = () => {
57
- return 'sohelp-grid-' + uuid();
58
- }
59
-
60
- /** 对齐方式映射 */
61
- const getAlign = (align) => {
62
- const alignMap = {
63
- 'left': 'flex-start',
64
- 'center': 'center',
65
- 'right': 'flex-end',
66
- '': 'flex-start'
67
- };
68
- return alignMap[align] || 'flex-start';
69
- }
70
-
71
- const loadReport = () => {
72
- SohelpHttp.get("/engine/web/report/list", { refid: props.refid }).then(res => {
73
- if (res.meta.success) {
74
- reportData.value = res.data.map(item => ({
75
- value: item.refid,
76
- refid: item.refid,
77
- name: item.name,
78
- createDate: item.createDate
79
- }));
80
- if (reportData.value.length > 0) {
81
- currentReportValue.value = reportData.value[0].refid;
82
- }
83
- } else {
84
- EleMessage.error(res.meta.message);
85
- }
86
- });
87
- };
88
-
89
- const designReport = () => {
90
- if (!currentReportValue.value || !currentRow?.value?.id) {
91
- EleMessage.error("请选择报表模板或报表数据!");
92
- return;
93
- }
94
- const baseURl = SohelpHttp.getBaseUrl();
95
- const url = baseURl.endsWith("/") ? baseURl : baseURl + "/";
96
- window.open(url + `ureport/designer?_u=${currentReportValue.value}&id=${currentRow?.value?.id}&refid=${currentReportValue?.value}`);
97
- };
98
- const openReport = () => {
99
- if (!currentReportValue.value || !currentRow?.value?.id) {
100
- EleMessage.error("请选择报表模板或报表数据!");
101
- return;
102
- }
103
- const baseURl = SohelpHttp.getBaseUrl();
104
- const url = baseURl.endsWith("/") ? baseURl : baseURl + "/";
105
- window.open(url + `ureport/preview?_u=${currentReportValue.value}&id=${currentRow?.value?.id}&refid=${currentReportValue?.value}`);
106
- };
107
- const closeReport = () => {
108
- visibleReport.value = false;
109
- };
110
-
111
- // 操作栏按钮配置
112
- const operationsButtons = reactive({});
113
-
114
- const loading = ref(false);
115
- //显示实体表单
116
- const visibleEntityForm = ref(false);
117
- //当前工具栏配置信息
118
- const toolbarButtonParams = ref({});
119
- const entityFormRef = ref(null);
120
- const entityFormData = ref({});
121
- const entityFormValue = ref({});
122
- const entityFormConfig = ref({});
123
- const closeEntityForm = () => {
124
- visibleEntityForm.value = false;
125
- };
126
-
127
- /**
128
- * 保存实体表单
129
- */
130
- const saveEntityForm = async () => {
131
- const v = await entityFormRef.value.validate();
132
- if(v){
133
- loading.value = true;
134
- entityFormRef.value.save(props.saveParams, (res) => {
135
- loading.value = false;
136
- if (res.meta.success) {
137
- refresh();
138
- visibleEntityForm.value = false;
139
- } else {
140
- EleMessage.error(res.meta.message);
141
- }
142
- });
143
- }
144
- };
145
-
146
- //配置加载状态
147
- // Grid配置
148
- const sohelpConfig = defineModel("config");
149
- // 过滤条件数据
150
- const filterValue = defineModel("filterValue", {
151
- type: Object,
152
- default: () => ({
153
- keywords: "",
154
- power: 0,
155
- filter: [],
156
- scheme: "",
157
- sort: "",
158
- order: ""
159
- })
160
- });
161
-
162
- // 属性映射
163
- const propertiesMap = defineModel("propertiesMap");
164
-
165
- // Grid实例
166
- const sohelpVxeGridRef = ref(null);
167
- // GridOptions配置
168
- const gridOptions = reactive(cloneDeep(DefaultGridOptions));
169
- const batchButtonsIndex = ref(2);
170
- const sortValue = ref("");
171
- /**
172
- * 缓存网格列表数据
173
- * @type {UnwrapNestedRefs<*[]>}
174
- */
175
- const gridData = reactive([]);
176
- /**
177
- * 记忆原始过虑条件数据
178
- * @type {Ref<UnwrapRef<string>>}
179
- */
180
- const originFilterValue = ref("");
181
-
182
- /**
183
- * 选中数据庥
184
- * @type {Ref<UnwrapRef<*[]>>}
185
- */
186
- const selections = ref([]);
187
- /**
188
- * 网格列表底部数据
189
- * @type {UnwrapNestedRefs<*[]>}
190
- */
191
- const footerData = reactive([]);
192
- /**
193
- * 定义计算公式
194
- * @type {UnwrapNestedRefs<{}>}
195
- */
196
- const formulaMap = reactive({});
197
- /**
198
- * 定义合计数据
199
- * @type {UnwrapNestedRefs<{}>}
200
- */
201
- const summaryData = reactive({});
202
-
203
- /**
204
- * 查看范围
205
- * @type 类型
206
- * @users 用户列表
207
- */
208
- const changePower = (type, users) => {
209
- filterValue.value.power = type;
210
- if (type == 9) {
211
- filterValue.value.powerUsers = users;
212
- }
213
- filter();
214
- };
215
-
216
-
217
- const getCellValue = (rowIndex, name) => {
218
- return (gridData[rowIndex] && gridData[rowIndex][name]) ? gridData[rowIndex][name] : "";
219
- };
220
-
221
- /**
222
- * 获取行原始数据
223
- */
224
- const getRowDataByField = (column, row) => {
225
- if(column.type === 'SohelpTableSelect'){
226
- const {field} = column;
227
- return gridData.find(item => item[field].id === row[field]) || row;
228
- } else{
229
- return row;
230
- }
231
- }
232
-
233
- /**
234
- * 获取关键字描述
235
- */
236
- const getKeywordsPlaceholder = computed(() => {
237
- if (sohelpConfig.value?.filter?.keywords?.length) {
238
- return t("grid.toolbar.keywords") + " [" + sohelpConfig.value.filter?.keywords?.filter(key => propertiesMap.value[key]).map(key => t(propertiesMap.value[key].i18n) || propertiesMap.value[key].label).join(",") + "]";
239
- }
240
- return t("grid.toolbar.keywords");
241
- });
242
-
243
-
244
- /**
245
- * SohelpTextareaInput弹窗标题
246
- */
247
- const getCurrentFieldLabel = computed(() => {
248
- return (propertiesMap.value[textareaState["field"]]?.label || "") + "修改";
249
- });
250
-
251
- const importVisible = ref(false);
252
- const importAuthority = computed(() => {
253
- const prefix = (props.refid || '').split('!')[0] || '';
254
- const authorityKey = prefix + ':batch.import';
255
- return sohelpConfig.value?.importConfig?.enabled && permission.hasPermission(authorityKey);
256
- });
257
- const exportAuthority = computed(() => {
258
- const prefix = (props.refid || '').split('!')[0] || '';
259
- const authorityKey = prefix + ':batch.export';
260
- return sohelpConfig.value?.exportConfig?.enabled && permission.hasPermission(authorityKey);
261
- });
262
-
263
- const openImport = () => {
264
- try {
265
- if (!props.refid) {
266
- EleMessage.error('列表地址缺失,无法打开导入');
267
- return;
268
- }
269
- importVisible.value = true;
270
- } catch (e) {
271
- EleMessage.error(typeof e === 'string' ? e : e?.message || '打开导入失败');
272
- }
273
- };
274
- const closeImport = () => {
275
- importVisible.value = false;
276
- };
277
- const exportData = async (dataRange) => {
278
- if (dataRange === 0) {
279
- const $grid = sohelpVxeGridRef.value;
280
- const selected = $grid?.getCheckboxRecords() || [];
281
- if (!selected.length) {
282
- EleMessage.error("请先勾选需要导出的记录");
283
- return;
284
- }
285
- const ids = selected.map((item) => item.id).filter((id) => id !== undefined && id !== null);
286
- if (!ids.length) {
287
- EleMessage.error("选中记录未包含可导出的ID");
288
- return;
289
- }
290
- let last = 0;
291
- let loadingTip = EleMessage.loading("导出中 0%");
292
- try {
293
- await SohelpHttp.download("/engine/web/export/download", {
294
- refid: props.refid,
295
- exportRange: dataRange,
296
- ...filterValue.value,
297
- ids: ids
298
- }, "导出数据.xlsx", (loaded, total) => {
299
- if (total > 0) {
300
- const p = Math.floor((loaded / total) * 100);
301
- if (p - last >= 5) {
302
- loadingTip.close();
303
- loadingTip = EleMessage.loading(`导出中 ${p}%`);
304
- last = p;
305
- }
306
- }
307
- });
308
- } catch (e) {
309
- EleMessage.error(typeof e === "string" ? e : e?.message || "导出失败");
310
- } finally {
311
- loadingTip.close();
312
- }
313
- return;
314
- }
315
- let last = 0;
316
- let loadingTip = EleMessage.loading("导出中 0%");
317
- try {
318
- await SohelpHttp.download("/engine/web/export/download", {
319
- refid: props.refid,
320
- exportRange: dataRange,
321
- filterValue: JSON.stringify(filterValue.value)
322
- }, "导出数据.xlsx", (loaded, total) => {
323
- if (total > 0) {
324
- const p = Math.floor((loaded / total) * 100);
325
- if (p - last >= 5) {
326
- loadingTip.close();
327
- loadingTip = EleMessage.loading(`导出中 ${p}%`);
328
- last = p;
329
- }
330
- }
331
- });
332
- } catch (e) {
333
- EleMessage.error(typeof e === "string" ? e : e?.message || "导出失败");
334
- } finally {
335
- loadingTip.close();
336
- }
337
- };
338
- const keywordsChange = (val) => {
339
- filterValue.value = {
340
- ...filterValue.value,
341
- keywords: val
342
- };
343
- };
344
-
345
- /**
346
- * 获取当前筛选
347
- * @param field
348
- */
349
- const getCurrentFilter = (field) => {
350
- return computed({
351
- get: () => {
352
- return filterValue.value.filter?.find(f => f.name === field);
353
- },
354
- set: (newValue) => {
355
- const newFilters = [...(filterValue.value.filter || [])];
356
- const index = newFilters.findIndex(f => f.name === field);
357
- if (index >= 0) {
358
- newFilters[index] = { ...newFilters[index], ...newValue };
359
- }
360
- filterValue.value = { ...filterValue.value, filter: newFilters };
361
- }
362
- });
363
- };
364
-
365
- /**
366
- *获取外键标签
367
- */
368
- const getTableSelectLabel = (val, index, field, column) => {
369
- if (!gridData[index] || !gridData[index][field]) {
370
- return "";
371
- }
372
- let obj = gridData[index][field];
373
- if (obj && typeof obj === "object") {
374
- if (!Array.isArray(obj)) {
375
- obj = [obj];
376
- }
377
- const { labelField = "label", valueField = "id" } = column.editRender;
378
- const arr = Array.isArray(val) ? val : [val];
379
- return obj.filter(item => arr.includes(item.id))?.map(row => row[labelField]).filter(Boolean).join(",");
380
-
381
- } else {
382
- return "";
383
- }
384
- };
385
-
386
- /**
387
- * 获取排序数据
388
- */
389
- const sortList = computed(() => {
390
- return sohelpConfig.value.filter?.sort?.map((field) => {
391
- let p = propertiesMap.value[field];
392
- return {
393
- title: p?.label || field,
394
- field: field
395
- };
396
- });
397
- });
398
-
399
- /**
400
- * 排序点击事件
401
- */
402
- const sortCommand = (field, order) => {
403
- if (sohelpVxeGridRef.value) {
404
- sohelpVxeGridRef.value.setSort({ field, order });
405
- }
406
- closeSortDropCard();
407
- };
408
-
409
- const isActiveSort = computed(() => {
410
- return (field, order) => {
411
- return sortValue.value === field + "!" + order ? "primary" : "";
412
- };
413
- });
414
-
415
- /**
416
- *
417
- * @param val 监听高级筛选值变化
418
- */
419
- const filterValueChange = (val) => {
420
- //console.log('v', val);
421
- };
422
-
423
- /**
424
- * 初始化数据
425
- */
426
- const loadConfig = (param = {}) => {
427
- initial(!props.isEntityGrid, props.refid)
428
- .then((config) => {
429
- /**配置刷新功能 */
430
- config.gridOptions = {
431
- ...config.gridOptions,
432
- params: gridOptions.params ?? {},
433
- toolbarConfig: {
434
- ...config.gridOptions?.toolbarConfig,
435
- refresh: true,
436
- zoom: true
437
- },
438
- proxyConfig: {
439
- autoLoad: false,
440
- ajax: {
441
- query: () => refresh()
442
- }
443
- }
444
- };
445
-
446
-
447
- //工具栏按钮权限
448
- Object.assign(formulaMap, config.formulaMap);
449
- Object.assign(gridOptions, config.gridOptions);
450
-
451
-
452
- // 过滤位置
453
- config.sohelpConfig.filter.config._visibleFilter = config.sohelpConfig?.filter.config.visibleFilter || false;
454
- sohelpConfig.value = { ...config.sohelpConfig };
455
-
456
- Object.assign(propertiesMap.value, config.propertiesMap);
457
-
458
- Object.assign(footerData, config.footerData);
459
- batchButtonsIndex.value = config.batchButtonsIndex;
460
- sohelpConfig.value.list = config.sohelpConfig.list;
461
-
462
-
463
-
464
- Object.assign(operationsButtons, config.operationsButtons);
465
-
466
- if (!filterValue.value.filter) {
467
- filterValue.value.filter = [];
468
- }
469
-
470
- Object.assign(filterValue.value.filter, config.sohelpConfig.filter?.field || []);
471
- //存储原始查询数据,用于重置
472
- originFilterValue.value = JSON.stringify(filterValue.value);
473
-
474
- nextTick(() => {
475
- if (sohelpVxeGridRef.value && props.autoLoad === true) {
476
- sohelpVxeGridRef.value.commitProxy("query");
477
- }
478
- });
479
- })
480
- .catch((e) => {
481
- console.error("Initial Configuration Error:", e);
482
- EleMessage.error(e.message);
483
- });
484
- };
485
-
486
-
487
- const gridValue = ref();
488
-
489
-
490
- const load = async (params = {}, callback) => {
491
- //清空选中
492
- selections.value = [];
493
- gridOptions.loading = true;
494
- gridOptions.params = params;
495
- await isConfigDone();
496
- const $grid = sohelpVxeGridRef.value;
497
-
498
- if ($grid) {
499
- const url = props.url || sohelpConfig.value.requestValue;
500
- if (sohelpConfig.value.requestType != "crud" && !url) {
501
- gridOptions.loading = false;
502
- return { results: [], total: 0 };
503
- }
504
-
505
-
506
- let pageConfig = {};
507
- // 是否分页
508
- if (gridOptions.pagerConfig?.enabled) {
509
- pageConfig.page = gridOptions.pagerConfig?.currentPage ?? 1;
510
- pageConfig.limit = gridOptions.pagerConfig?.pageSize ?? 50;
511
- }
512
-
513
- //过滤条件筛选
514
- params["filter"] = filterValue.value.filter?.filter(item => (item.comparison === "EMPTY" || item.comparison === "NOT_EMPTY") || item.value?.length > 0);
515
- const res = await SohelpHttp.get(url, {
516
- refid: props.refid,
517
- ...filterValue.value,
518
- ...params,
519
- ...pageConfig
520
- });
521
-
522
-
523
-
524
- if (res?.meta?.success) {
525
- if (res.data) {
526
- gridOptions.pagerConfig.total = Number(res.data?.total);
527
-
528
- const _data = res.data?.results || res.data || [];
529
- Object.assign(gridData, JSON.parse(JSON.stringify(_data)));
530
- gridValue.value = switchGridValue(_data);
531
- $grid.loadData(gridValue.value);
532
- Object.assign(summaryData, res.data?.summary || {});
533
- updateColumnsFilter();
534
- gridOptions.loading = false;
535
- //统计
536
- if (footerData.length > 0) {
537
- gridOptions.footerData = updateSummary(res.data.results, res.data?.summary || {});
538
- $grid?.refreshColumn();
539
- }
540
- }
541
- } else {
542
- EleMessage.error(res.meta.message);
543
- }
544
- gridOptions.loading = false;
545
- //回调方法
546
- if (callback && typeof callback === "function") {
547
- callback(res);
548
- }
549
- }
550
-
551
- emit('pageChange', gridOptions.pagerConfig);
552
- };
553
-
554
- /**
555
- * 重新加载数据
556
- */
557
- const reload = async (params = {}) => {
558
- Object.assign(gridOptions.params, params);
559
- await load(gridOptions.params);
560
- };
561
-
562
-
563
- /**
564
- * 单元格点击更新 表尾统计
565
- */
566
- const cellClick = () => {
567
- const data = sohelpVxeGridRef.value?.getFullData();
568
- gridOptions.footerData = updateSummary(data, summaryData);
569
- };
570
-
571
- /**
572
- * 统计
573
- */
574
- const updateSummary = (data, summaryMap = {}) => {
575
- const arr = footerData.map(item => {
576
- const field = data.map(f => {
577
- let val = Number(f[item.field]);
578
- return isNaN(val) ? 0 : val;
579
- });
580
-
581
- let value = calcSummary(field, item.type);
582
- if (item.type === "remotesum") {
583
- value = summaryMap[item.field] || "";
584
- }
585
-
586
- if (item.summaryRender) {
587
- try {
588
- const func = new Function("return " + item.summaryRender)();
589
- value = func.call(sohelpVxeGridRef, value);
590
- } catch (e) {
591
- console.error("函数执行错误:", e);
592
- }
593
- }
594
-
595
- return {
596
- [item.field]: value
597
- };
598
- });
599
-
600
- arr.unshift({ _seq: "统计" });
601
- return [Object.assign({}, ...arr)];
602
- };
603
-
604
-
605
- /**
606
- * 分页事件
607
- */
608
- const pageChangeEvent = async (page) => {
609
- isPage.value = true;
610
- gridOptions.pagerConfig.currentPage = page.currentPage;
611
- gridOptions.pagerConfig.pageSize = page.pageSize;
612
- await reload();
613
- emit('pageChange',gridOptions.pagerConfig)
614
- };
615
-
616
-
617
- /**
618
- * 获取Common类型操作栏 并根据flw_id判断是否显示
619
- * @param row
620
- */
621
- const getOperationButtonsByType = computed(() => {
622
- return (row, column, type = "common") => {
623
- const $grid = sohelpVxeGridRef.value;
624
- let common = operationsButtons?.[type] || [];
625
- if (common.length > 0) {
626
- if (row.hasOwnProperty("flw_id")) {
627
- const field = row.flw_id === "0" ? "workflow.view" : "workflow.submit";
628
- common = common.filter(f => f.code != field);
629
- } else {
630
- common = common.filter(f => (f.code != "workflow.submit" || f.code != "workflow.view"));
631
- }
632
- return common.map((button) => {
633
- // 创建新对象,避免修改原按钮配置
634
- const newButton = { ...button };
635
- if(newButton.render && newButton.render?.length > 0) {
636
- const func = new Function("$row","$button","$column","$grid", `return (async () => { ${newButton.render} })()`);
637
- func.call(undefined, row, newButton, column, $grid);
638
- }
639
- return newButton;
640
- });
641
- }
642
- return [];
643
- };
644
- })
645
-
646
- /**
647
- * 行操作栏点击事件
648
- * @param row
649
- * @param item
650
- */
651
- const operationHandler = ({ button, row, $grid }) => {
652
-
653
-
654
- //操作栏事件执行
655
- $grid.reload = reload;
656
- $grid.refresh = refresh;
657
- if (button.handler && typeof button.handler === "string") {
658
- try {
659
- const func = new Function("$row", "$grid", `return (async () => { ${button.handler} })()`);
660
- (async () => {
661
- const context = {
662
- $message: EleMessage,
663
- $SohelpModule: window.$SohelpModule,
664
- $SohelpHttp: window.$SohelpHttp,
665
- $confirm: (title, callback) => {
666
- ElMessageBox.confirm(title, "提示", {
667
- confirmButtonText: "确定",
668
- cancelButtonText: "取消",
669
- type: "warning"
670
- }).then(() => {
671
- callback && callback();
672
- }).catch(() => {
673
- });
674
- }
675
- };
676
- await func.call(context, row, $grid); // 显式传递所有参数
677
- })();
678
- } catch (e) {
679
- EleMessage.error(`操作栏事件出错:${e.message}`);
680
- }
681
- } else if (button.refid) {
682
- if (button.openType === "tab") {
683
- window.$SohelpModule.openTab(button.refid, { id: row.id }, button.params || {});
684
- } else if (button.openType === "drawer") {
685
- window.$SohelpModule.openDrawer(button.refid, { id: row.id }, button.params || {});
686
- } else {
687
- window.$SohelpModule.openModal(button.refid, { id: row.id }, button.params || {});
688
- }
689
- } else {
690
- switch (button.code) {
691
- case "row.delete":
692
- $grid?.remove(row)
693
- break;
694
- case "crud.edit":
695
- visibleEntityForm.value = true;
696
- toolbarButtonParams.value = button.params || {};
697
- if (!toolbarButtonParams.value["title"]) {
698
- toolbarButtonParams.value["title"] = t("grid.toolbar.edit");
699
- }
700
- loading.value = true;
701
- CrudHttp.detail(props.refid, { id: row.id }).then(res => {
702
- if (res.meta.success) {
703
- setTimeout(() => {
704
- entityFormRef.value.setFormData({...res.data});
705
- }, 10);
706
- } else {
707
- EleMessage.error(res.meta.message);
708
- }
709
- loading.value = false;
710
- }).catch(e => {
711
- loading.value = false;
712
- });
713
-
714
- break;
715
- case "crud.view":
716
- visibleEntityForm.value = true;
717
- toolbarButtonParams.value = button.params || {};
718
- if (!toolbarButtonParams.value["title"]) {
719
- toolbarButtonParams.value["title"] = t("grid.toolbar.view");
720
- }
721
- toolbarButtonParams.value["readonly"] = true;
722
- CrudHttp.detail(props.refid, { id: row.id }, (res) => {
723
- if (res.meta.success) {
724
- setTimeout(() => {
725
- entityFormRef.value.setFormData(res.data);
726
- }, 10);
727
- } else {
728
- EleMessage.error(res.meta.message);
729
- }
730
- });
731
- break;
732
- case "crud.delete" :
733
- remove({ id: [row.id] });
734
- break;
735
- case "row.pre-delete":
736
- $grid?.setPendingRow(row, true);
737
- break;
738
- case "workflow.submit":
739
- submitWorkflow({ id: [row.id] });
740
- break;
741
- case "workflow.view" :
742
- viewWorkflow(row.id);
743
- break;
744
- case "report.print" :
745
- visibleReport.value = true;
746
- currentRow.value = row;
747
- loadReport();
748
- break;
749
- default:
750
- break;
751
- }
752
- }
753
- emit("operationButtonClick", { button, row, $grid });
754
- };
755
-
756
-
757
- /**
758
- * 获取表格数据
759
- */
760
- const getTableData = () => {
761
- return sohelpVxeGridRef.value?.getTableData();
762
- };
763
-
764
- /**
765
- * 获取处理过的数据
766
- */
767
- const getData = () => {
768
- const { tableData } = getTableData();
769
- return tableData;
770
- };
771
-
772
- /**
773
- * 更新
774
- */
775
- const updateValue = () => {
776
- emit("update:modelValue", getData());
777
- emit("change", getData());
778
- };
779
- /**
780
- * 指定index位置插入数据
781
- * @param data
782
- * @param index
783
- */
784
- const insertField = (data, index = -1) => {
785
- if (sohelpVxeGridRef.value) {
786
- sohelpVxeGridRef.value.insertAt(data, index);
787
- sohelpVxeGridRef.value.clearEdit();
788
- }
789
- updateValue();
790
- };
791
-
792
-
793
- /**
794
- * 刷新列表
795
- */
796
- const refresh = () => {
797
- //取消选中
798
- selections.value = [];
799
- sohelpVxeGridRef.value?.clearCheckboxRow();
800
-
801
- if (!isPage.value) {
802
- if (gridOptions.pagerConfig && gridOptions.pagerConfig.enabled) {
803
- gridOptions.pagerConfig.currentPage = 1;
804
- }
805
- emit("refresh");
806
- }
807
- isPage.value = false;
808
- reload({ ...gridOptions.params });
809
- };
810
-
811
- /**
812
- * 列表头右键菜单事件
813
- * @param column
814
- */
815
- const headerCellMenu = ({ column }) => {
816
- if (column.editRender?.edit && gridOptions.menuConfig.header.options.length > 0) {
817
- // 只对特定类型的列显示菜单项
818
- const visible = column && (column.type === "SohelpSwitch" || column.type === "SohelpCheckbox");
819
- // 设置每个菜单项的可见性
820
- gridOptions.menuConfig.header.options[0].forEach(item => {
821
- item.visible = visible;
822
- });
823
- }
824
- };
825
-
826
- /**
827
- * 右键菜单点击事件
828
- * @param menu 菜单项
829
- * @param row 行数据
830
- * @param column 列配置
831
- * @param rowIndex 行索引
832
- */
833
- const menuRightClick = async ({ menu, row, column, rowIndex }) => {
834
- const $grid = sohelpVxeGridRef.value;
835
- if ($grid) {
836
- $grid.setCurrentRow(row);
837
- const { fullData } = $grid.getTableData();
838
- switch (menu.code) {
839
- case "insert":
840
- await $grid.insertAt({ role_name: "sales user" }, rowIndex);
841
- break;
842
- case "all-select":
843
- fullData.forEach(row => {
844
- row[column.field] = ["0", 0, "1", 1].includes(row[column.field]) ? 1 : true;
845
- });
846
- break;
847
- case "revert-select":
848
- fullData.forEach(row => {
849
- if (["0", 0, "1", 1].includes(row[column.field])) {
850
- row[column.field] = 1 - row[column.field];
851
- } else {
852
- row[column.field] = !row[column.field];
853
- }
854
- });
855
- break;
856
- default:
857
- break;
858
- }
859
- }
860
-
861
- // 执行右击事件
862
- emit("menuRightClick", { menu, row, column, rowIndex });
863
- };
864
-
865
- const sohelpSortRef = ref(null);
866
- const closeSortDropCard = () => {
867
- if (sohelpSortRef.value) {
868
- sohelpSortRef.value.close();
869
- }
870
- };
871
-
872
- /**
873
- * 获取用户数据源
874
- */
875
- const userDatasource = computed(async () => {
876
- return await SohelpHttp.get("/engine/web/user/list")
877
- .then((res) => {
878
- if (res.data) {
879
- return [...res.data];
880
- }
881
- })
882
- .catch((err) => {
883
- EleMessage.error(err.message || "error");
884
- });
885
- });
886
-
887
- /**
888
- * SohelpTextareaInput 弹窗
889
- */
890
- const [textareaState, resetTextareaState, setTextareaState] = useFormData({
891
- visible: false,
892
- value: "",
893
- row: null,
894
- field: ""
895
- });
896
-
897
- /**
898
- * 显示 SohelpTextareaInput 弹窗
899
- */
900
- const showTextareaModal = (column, field, row) => {
901
- if (column?.editRender?.enabled) {
902
- setTextareaState({
903
- visible: true,
904
- value: row[field],
905
- row,
906
- field
907
- });
908
- }
909
- };
910
-
911
- /**
912
- * 取消 SohelpTextareaInput 弹窗
913
- */
914
- const textareaCancel = () => {
915
- resetTextareaState();
916
- };
917
-
918
- /**
919
- * checkbox复选框
920
- */
921
- const onCheckboxChange = (checked, type) => {
922
- selections.value = sohelpVxeGridRef.value?.getCheckboxRecords() || [];
923
- emit("checkbox-change", selections.value, checked, type);
924
- };
925
-
926
- /**
927
- *
928
- */
929
- const radioChange = (config) => {
930
- emit('radio-change', config)
931
- }
932
-
933
-
934
- /**
935
- * 确定 SohelpTextareaInput 弹窗
936
- */
937
- const textareaConfirm = () => {
938
- const $grid = sohelpVxeGridRef.value;
939
- if ($grid) {
940
- $grid.setRow(textareaState.row, {
941
- ...textareaState.row,
942
- [textareaState.field]: textareaState.value
943
- });
944
- }
945
- textareaCancel();
946
- };
947
-
948
- /**
949
- * 获取组织数据源
950
- */
951
- const orgDatasource = computed(async () => {
952
- return await SohelpHttp.get("/engine/web/org/list")
953
- .then((res) => {
954
- if (res.data) {
955
- return [...res.data];
956
- }
957
- })
958
- .catch((err) => {
959
- EleMessage.error(err.message || "error");
960
- });
961
- });
962
- /**
963
- * 根据引擎表格获取更新数据
964
- * @returns {{inserted: {}, deleted: {}, updated: {}}}
965
- */
966
- const getCrudUpdater = () => {
967
- const $grid = sohelpVxeGridRef.value;
968
- const _delete = [...$grid?.getRemoveRecords()?.map(item => item.id),...$grid?.getPendingRecords()?.map(item => item.id)];
969
- return {
970
- "inserted": $grid?.getInsertRecords().map(item => {
971
- return { ...item };
972
- }) || [],
973
- "updated": $grid?.getUpdateRecords(),
974
- "deleted": _delete
975
- };
976
- };
977
-
978
- /**
979
- * 删除记录
980
- */
981
- const remove = (params) => {
982
- ElMessageBox.confirm("确定要删除吗?", "提示").then(() => {
983
- CrudHttp.delete(props.refid, params, (res) => {
984
- if (res.meta.success) {
985
- EleMessage.success(res.meta.message);
986
- refresh();
987
- } else {
988
- EleMessage.error(res.meta.message);
989
- }
990
- });
991
- }).catch(() => {
992
- });
993
- };
994
-
995
- /**
996
- *
997
- * @param handler
998
- */
999
- const executeToolbarCustomHandler = (button) => {
1000
- const $grid = sohelpVxeGridRef.value;
1001
- $grid.refresh = refresh;
1002
- $grid.reload = reload;
1003
- try {
1004
- let isRows = button.buttonType === 'batch';
1005
- const func = new Function(isRows ? "rows" : "row", "$grid", `return (async () => { ${button.handler} })()`);
1006
- (async () => {
1007
- const context = {
1008
- $message: EleMessage,
1009
- $SohelpModule: window.$SohelpModule,
1010
- $SohelpHttp: window.$SohelpHttp,
1011
- $confirm: (title, callback) => {
1012
- ElMessageBox.confirm(title, "提示", {
1013
- confirmButtonText: "确定",
1014
- cancelButtonText: "取消",
1015
- type: "warning"
1016
- }).then(() => {
1017
- callback && callback();
1018
- }).catch(() => {
1019
- });
1020
- },
1021
- $grid: $grid,
1022
- getCrudUpdater: getCrudUpdater
1023
- };
1024
- $grid.refresh = refresh;
1025
- await func.call(context, isRows ? selections.value : current, $grid); // 显式传递所有参数
1026
- })();
1027
- } catch (e) {
1028
- EleMessage.error(`${e.message}`);
1029
- }
1030
- };
1031
- /**
1032
- * 工具栏点击事件
1033
- * @param param0
1034
- */
1035
- const toolbarClick = async ({ button }) => {
1036
- const $grid = sohelpVxeGridRef.value;
1037
- let rowIndex = -1;
1038
- const row = {};
1039
-
1040
- const current = $grid?.getCurrentRecord();
1041
- if (current) {
1042
- rowIndex = $grid?.getVTRowIndex(current);
1043
- }
1044
-
1045
- //工具栏事件执行
1046
- if (button?.handler) {
1047
- executeToolbarCustomHandler(button);
1048
- } else if (button.refid) {
1049
- if (button.openType === "tab") {
1050
- window.$SohelpModule.openTab(button.refid, {}, button.params || {});
1051
- } else if (button.openType === "drawer") {
1052
- window.$SohelpModule.openDrawer(button.refid, {}, button.params || {});
1053
- } else {
1054
- window.$SohelpModule.openModal(button.refid, {}, button.params || {});
1055
- }
1056
- } else {
1057
- switch (button.code) {
1058
- case "row.add":
1059
- insertField(row, -1);
1060
- break;
1061
- case "row.copy":
1062
- if (current) {
1063
- Object.assign(row, { ...current });
1064
- if (row?.name) {
1065
- row.name = "";
1066
- }
1067
- delete row._X_ROW_KEY;
1068
- }
1069
- break;
1070
- case "row.insert":
1071
- rowIndex = getData()?.length > 0 ? rowIndex : -1;
1072
- insertField(row, rowIndex);
1073
- break;
1074
- case "row.delete":
1075
- $grid.removeCheckboxRow();
1076
- break;
1077
- case "crud.create":
1078
- visibleEntityForm.value = true;
1079
- toolbarButtonParams.value = button.params || {};
1080
- if (!toolbarButtonParams.value["title"]) {
1081
- toolbarButtonParams.value["title"] = t("grid.toolbar.create");
1082
- }
1083
-
1084
- const {title, ...params} = button.params;
1085
-
1086
- CrudHttp.initial(props.refid, { id: row.id }, (res) => {
1087
- if (res.meta.success) {
1088
- setTimeout(() => {
1089
- entityFormRef.value.setFormData({...res.data}, params);
1090
- }, 10);
1091
- } else {
1092
- EleMessage.error(res.meta.message);
1093
- }
1094
- });
1095
- break;
1096
- case "crud.save":
1097
- CrudHttp.save(props.refid, { "default": getCrudUpdater() }, (res) => {
1098
- if (res.meta.success) {
1099
- EleMessage.success(res.meta.message);
1100
- refresh();
1101
- } else {
1102
- EleMessage.error(res.meta.message);
1103
- }
1104
- });
1105
- break;
1106
- case "crud.view":
1107
- break;
1108
- case "crud.delete":
1109
- remove({ id: selections.value.map(item => item.id) });
1110
- break;
1111
- case "workflow.submit":
1112
- submitWorkflow({ id: selections.value.map(item => item.id) });
1113
- break;
1114
- case "report.print":
1115
- break;
1116
- case "batch.import":
1117
- break;
1118
- case "batch.delete":
1119
- break;
1120
- case "batch.export":
1121
- break;
1122
- case "batch.print":
1123
- break;
1124
- default:
1125
- break;
1126
- }
1127
-
1128
- }
1129
- };
1130
-
1131
- /**
1132
- * grid事件
1133
- * 排序
1134
- */
1135
- const gridEvents = {
1136
- sortChange({ field = "", order = "" }) {
1137
- if (!order) {
1138
- field = order = "";
1139
- }
1140
- sortValue.value = field + "!" + order;
1141
- filterValue.value.sort = field;
1142
- filterValue.value.order = order;
1143
- filter({});
1144
- },
1145
-
1146
- toolbarButtonClick(config) {
1147
- toolbarClick(config);
1148
- emit("toolbarButtonClick", config, selections.value);
1149
- },
1150
- };
1151
-
1152
- /**
1153
- * 查询
1154
- * param type:'filter' | 'column', default(filter) 区分是高级筛选,还是列筛选
1155
- */
1156
- const filter = (param = {}) => {
1157
- gridOptions.pagerConfig.currentPage = 1;
1158
- reload();
1159
- };
1160
-
1161
-
1162
- /**
1163
- * 重置
1164
- */
1165
- const resetFilter = () => {
1166
- filterValue.value = JSON.parse(originFilterValue.value);
1167
- //重置列筛选
1168
- if (sohelpVxeGridRef.value) {
1169
- sohelpVxeGridRef.value.clearFilter();
1170
- }
1171
- filter();
1172
- };
1173
-
1174
- /**
1175
- * 筛选弹窗
1176
- */
1177
- const showFilter = () => {
1178
- if (sohelpConfig.value.filter?.config.filterPosition === "NONE") {
1179
- sohelpConfig.value.filter.config.filterPosition = "TOP";
1180
- sohelpConfig.value.filter.config.visibleFilter = false;
1181
- }
1182
- emit("showFilter", sohelpConfig.value.filter.config.filterPosition);
1183
- };
1184
-
1185
-
1186
- /**
1187
- * 打开提交工作流界面
1188
- */
1189
- const submitWorkflow = (ids) => {
1190
- approvalData.value = {
1191
- refid: props.refid,
1192
- ...ids
1193
- };
1194
- approvalModalVisible.value = true;
1195
- };
1196
-
1197
- /**
1198
- * 查看工作流
1199
- * @param row
1200
- */
1201
- const viewWorkflow = (id) => {
1202
- drawerData.value = {
1203
- id: id,
1204
- refid: props.refid
1205
- };
1206
- drawerVisible.value = true;
1207
- };
1208
-
1209
- /**
1210
- * 筛选
1211
- */
1212
- const changeNameFilter = (option, val, column) => {
1213
- const $grid = sohelpVxeGridRef.value;
1214
- if ($grid) {
1215
- $grid.setFilter(column.field, [{
1216
- data: val?.value || "",
1217
- value: val.value || "",
1218
- checked: true
1219
- }]);
1220
- $grid.updateFilterOptionStatus(option, true);
1221
- }
1222
- };
1223
-
1224
- const filterVisible = ({ column, field, visible }) => {
1225
- if (visible) {
1226
- const hasField = filterValue.value.filter?.find(f => f.name === field);
1227
- if (!hasField) {
1228
- filterValue.value.filter = [...filterValue.value.filter, {
1229
- comparison: "LIKE",
1230
- name: field,
1231
- value: ""
1232
- }];
1233
- }
1234
- const $grid = sohelpVxeGridRef.value;
1235
- if ($grid) {
1236
- $grid.setFilter(field, [{
1237
- data: "",
1238
- value: "",
1239
- checked: true
1240
- }]);
1241
- }
1242
-
1243
- }
1244
- };
1245
-
1246
- /**
1247
- *列筛选
1248
- */
1249
- const handleFilterChange = ({ field, datas }) => {
1250
- filter();
1251
- //重置功能 重置要清空filterValue.filter对象的项
1252
- if (!datas?.length) {
1253
- const map = new Map(filterValue.value.filter?.map(item => [item.name, item]));
1254
- if (map.get(field)) {
1255
- map.get(field).value = "";
1256
- }
1257
- }
1258
- };
1259
-
1260
- /**
1261
- * 过滤掉对象中_开头的属性 _sqe、_checkbox、_operation
1262
- * @param obj
1263
- */
1264
- const filterUnderscoreProps = (obj = {}) => {
1265
- if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
1266
- return {};
1267
- }
1268
- return Object.entries(obj).reduce((acc, [key, value]) => {
1269
- const filterKey = ["_checkbox", "_seq"];
1270
- if (!filterKey.includes(key)) {
1271
- acc[key] = typeof value === "object" ? filterUnderscoreProps(value) : value;
1272
- }
1273
- return acc;
1274
- }, {});
1275
- };
1276
-
1277
-
1278
- /**
1279
- * 根据 obj 对象的值修改 properties 数组中对应项的指定属性
1280
- * @param {Object} obj
1281
- * @param {Array} properties
1282
- * @param {string} key
1283
- */
1284
- const updateProperties = (obj, properties, key, propertiesMap) => {
1285
- if (!obj || Object.keys(obj).length === 0) return;
1286
- const map = propertiesMap || new Map(properties.map((item, index) => [item.name, index]));
1287
- Object.entries(obj).forEach(([name, value]) => {
1288
- const index = map.get(name);
1289
- if (index !== undefined && properties[index]) {
1290
- properties[index][key] = value;
1291
- //fixed
1292
- if (key === "lockAlign") {
1293
- properties[index]["lock"] = value ? true : false;
1294
- }
1295
- }
1296
- });
1297
- };
1298
-
1299
-
1300
- /**
1301
- * 属性根据sortData排序
1302
- * @param {Array} properties
1303
- * @param {Object} sortData
1304
- */
1305
- const sortPropertiesInPlace = (properties, sortData) => {
1306
- const sortOrder = {};
1307
- Object.entries(sortData || {})
1308
- .sort((a, b) => a[1] - b[1])
1309
- .forEach(([key], index) => {
1310
- sortOrder[key] = index;
1311
- });
1312
-
1313
- properties.sort((a, b) => {
1314
- const aOrder = sortOrder[a.name];
1315
- const bOrder = sortOrder[b.name];
1316
-
1317
- if (aOrder !== undefined && bOrder !== undefined) {
1318
- return aOrder - bOrder;
1319
- }
1320
- if (aOrder !== undefined) return -1;
1321
- if (bOrder !== undefined) return 1;
1322
- return 0;
1323
- });
1324
- };
1325
-
1326
- /**
1327
- * 列设置操作
1328
- */
1329
- const handleCustom = async ({ type, $grid }) => {
1330
- // 恢复默认
1331
- if (type === "reset") {
1332
- const loading = EleMessage.loading("恢复默认中..");
1333
- const message = await resetCommonConfig({ refid: props.refid }).catch(err => {
1334
- EleMessage.error(err.message);
1335
- loading.close();
1336
- });
1337
- if (message) {
1338
- EleMessage.success(message);
1339
- }
1340
- loading.close();
1341
- }
1342
-
1343
- //确认
1344
- if (type === "confirm") {
1345
- //获取当前列配置
1346
- const { sortData, ...columnsData } = filterUnderscoreProps($grid?.getCustomStoreData());
1347
-
1348
- const properties = JSON.parse(JSON.stringify([...sohelpConfig.value.properties])).map(item => {
1349
- return {
1350
- ...item,
1351
- list: sohelpConfig.value.list.includes(item.name)
1352
- };
1353
- });
1354
-
1355
- const propertiesMap = new Map(properties.map((item, index) => [item.name, index]));
1356
-
1357
-
1358
- //修改对应的field
1359
- const fieldMapping = {
1360
- fixedData: "lockAlign",
1361
- resizableData: "width",
1362
- visibleData: "list"
1363
- };
1364
- // 修改属性
1365
- Object.entries(columnsData).forEach(([key, value]) => {
1366
- updateProperties(value, properties, fieldMapping[key], propertiesMap);
1367
- });
1368
- //根据sortData排序
1369
- sortPropertiesInPlace(properties, sortData);
1370
- const loading = EleMessage.loading("保存配置中..");
1371
-
1372
- const message = await updateCommonConfig({
1373
- refid: props.refid,
1374
- properties: properties.map(item => {
1375
- return {
1376
- name: item.name,
1377
- width: item.width,
1378
- list: item.list,
1379
- lockAlign: item.lockAlign,
1380
- lock: item.lock
1381
- };
1382
- })
1383
- }).catch(err => {
1384
- EleMessage.error(err.message);
1385
- loading.close();
1386
- });
1387
- if (message) {
1388
- EleMessage.success(message);
1389
- }
1390
-
1391
- //清除缓存
1392
- moduleCache?.clear();
1393
- loadConfig();
1394
-
1395
- localStorage.setItem("VXE_CUSTOM_STORE", "");
1396
- loading.close();
1397
- }
1398
- };
1399
-
1400
-
1401
- /**
1402
- * 更新columns过滤状态
1403
- */
1404
- const updateColumnsFilter = () => {
1405
- const $grid = sohelpVxeGridRef.value;
1406
- if ($grid && filterValue.value.filter?.length) {
1407
- filterValue.value.filter?.forEach((item) => {
1408
- $grid.setFilter(item.name, [
1409
- {
1410
- checked: item.value?.length > 0
1411
- }
1412
- ]);
1413
- });
1414
- }
1415
- };
1416
-
1417
-
1418
- /**
1419
- * 计算公式
1420
- * @param row
1421
- * @param column
1422
- */
1423
- const editClosed = (props) => {
1424
- const { row, column } = props;
1425
- Object.entries(formulaMap).forEach(([key, value]) => {
1426
- try {
1427
- const formulaValue = formulaMap[key]["formulaValue"];
1428
- if (formulaValue.indexOf(column.field) > 0) {
1429
- const str = formulaValue.replace(/\s+/g, "")
1430
- .replace(/\${/g, "row.")
1431
- .replace(/}/g, "");
1432
- const v = new Function("row", `return ${str}`)(row);
1433
- if (!Number.isNaN(v)) {
1434
- row[key] = v;
1435
- }
1436
- }
1437
- } catch (e) {
1438
- console.error("计算公式错误:", e);
1439
- EleMessage.error("计算公式错误:", e.message);
1440
- }
1441
- nextTick(() => {
1442
- if (row[column.property] && row[column.property].toString().trim() !== "") {
1443
- sohelpVxeGridRef.value?.clearValidate([column.property]);
1444
- }
1445
- });
1446
- });
1447
- emit("editClosed", props);
1448
- };
1449
-
1450
- const validate = async () => {
1451
- const $grid = sohelpVxeGridRef.value;
1452
- if ($grid) {
1453
- const errMap = await $grid.fullValidate(true);
1454
- return errMap || false;
1455
- }
1456
- };
1457
-
1458
- const currentColumnChange = (props) => {
1459
- emit("currentColumnChange", props);
1460
- };
1461
-
1462
- const columnCheckbox = ref(false);
1463
- const toggleAllEvent = () => {
1464
- const $grid = sohelpVxeGridRef.value
1465
- if ($grid) {
1466
- $grid.toggleCustomAllCheckbox()
1467
- }
1468
- }
1469
-
1470
- const settingClick = (command) => {
1471
- const baseUrl = SohelpHttp.getBaseUrl();
1472
- const { refid,extendEntity,name } = sohelpConfig.value;
1473
- if(refid && name){
1474
- const url = {
1475
- form: baseUrl + `/dev/index.html#/dev/form?datasource=default&name=${extendEntity}&refid=${refid}`,
1476
- entity: baseUrl + `/dev/index.html#/dev/module/entity?datasource=default&name=${extendEntity}`,
1477
- workflow: baseUrl + `/dev/index.html#/dev/form?datasource=default&name=${extendEntity}&refid=${refid}&tab=workflow`,
1478
- grid: baseUrl + `/dev/index.html#/dev/module/grid?refid=${refid}`,
1479
- module: baseUrl+`/dev/index.html#/dev/module?name=${refid}`,
1480
- }
1481
- if(command === 'module' && !extendEntity){
1482
- url.module = baseUrl+`/dev/index.html#/dev/module?name=${name}`;
1483
- }
1484
- window.open(url[command],'_blank');
1485
- }
1486
- }
1487
- /**
1488
- * 设置复选框行键
1489
- * @param row 行数据
1490
- * @param checked 是否选中
1491
- */
1492
- const setCheckboxRowKey = (row, checked) => {
1493
- nextTick(() => {
1494
- sohelpVxeGridRef.value?.setCheckboxRowKey(row, checked);
1495
- })
1496
- }
1497
-
1498
-
1499
- const setRadioRowKey = (key, checked) => {
1500
- nextTick(() => {
1501
- sohelpVxeGridRef.value?.setRadioRowKey(key, checked);
1502
- })
1503
- }
1504
-
1505
- /**
1506
- * 获取选中的记录
1507
- */
1508
- const getCheckboxRecords = () => {
1509
- return sohelpVxeGridRef.value?.getCheckboxRecords();
1510
- };
1511
- /**
1512
- * 获取保留的记录
1513
- */
1514
- const getCheckboxReserveRecords = (isFull="false") => {
1515
- return sohelpVxeGridRef.value?.getCheckboxReserveRecords(isFull);
1516
- }
1517
-
1518
-
1519
-
1520
-
1521
- /**
1522
- * 监听是否被选中,更新工具栏批量操作
1523
- */
1524
- watch(
1525
- () => selections.value,
1526
- (val) => {
1527
- const isDisabled = val.length < 1;
1528
- if (batchButtonsIndex.value?.length > 0) {
1529
- batchButtonsIndex.value.forEach(idx => {
1530
- gridOptions.toolbarConfig.buttons[idx].disabled = isDisabled;
1531
- });
1532
- }
1533
- }
1534
- );
1535
-
1536
- watch(
1537
- () => props.refid, (refid) => {
1538
- //加载列表配置
1539
- loadConfig();
1540
- }, {
1541
- immediate: true
1542
- });
1543
-
1544
-
1545
-
1546
- defineExpose({
1547
- getData,
1548
- getCrudUpdater,
1549
- resetFilter,
1550
- refresh,
1551
- loadConfig,
1552
- reload,
1553
- load,
1554
- validate,
1555
- setCheckboxRowKey,
1556
- getCheckboxRecords,
1557
- getCheckboxReserveRecords,
1558
- setRadioRowKey,
1559
- selections
1560
- });
1561
- </script>
1562
-
1563
- <template>
1564
- <vxe-grid
1565
- v-bind="gridOptions"
1566
- ref="sohelpVxeGridRef"
1567
- @menuClick="menuRightClick"
1568
-
1569
- @checkboxChange="({checked}) => onCheckboxChange(checked,'row')"
1570
- @checkboxAll="({checked}) => onCheckboxChange(checked,'all')"
1571
- @radioChange="radioChange"
1572
-
1573
- class="sohelp-grid-view"
1574
- :id="getId()"
1575
- v-on="gridEvents"
1576
- @filter-change="handleFilterChange"
1577
- @custom="handleCustom"
1578
- @cellClick="cellClick"
1579
- @editClosed="editClosed"
1580
- @header-cell-menu="headerCellMenu"
1581
- :key="sohelpConfig.uuid"
1582
- :keep-source="true"
1583
- @currentColumnChange="currentColumnChange"
1584
- @filter-visible="filterVisible"
1585
- >
1586
-
1587
- <!-- 自定义列设置 -->
1588
- <template #setting>
1589
- <div class="column-setting">
1590
- <vxe-checkbox @change="toggleAllEvent" v-model="columnCheckbox">全选</vxe-checkbox>
1591
- <vxe-pulldown trigger="click" :transfer="true" :show-popup-shadow="true" v-if="userStore.info.is_developer">
1592
- <template #default>
1593
- <el-link :icon="Setting" :underline="false"/>
1594
- </template>
1595
- <template #dropdown>
1596
- <ele-card shadow="always">
1597
- <el-space direction="vertical" :size="5" alignment="flex-start">
1598
- <el-link :title="sohelpConfig?.refid" :icon="Memo" @click="settingClick('grid')" :underline="false" style="font-size:12px;"><span style="padding:0 5px;">列表配置</span></el-link>
1599
- <el-link :title="sohelpConfig?.extendEntity" :icon="Menu" @click="settingClick('entity')" :underline="false" style="font-size: 12px;" v-if="sohelpConfig.extendEntity"><span style="padding:0 5px;">实体配置</span></el-link>
1600
- <el-link :title="sohelpConfig?.refid" :icon="Grid" @click="settingClick('module')" :underline="false" style="font-size: 12px;"><span style="padding:0 5px;">模块配置</span></el-link>
1601
- </el-space>
1602
- </ele-card>
1603
- </template>
1604
- </vxe-pulldown>
1605
- </div>
1606
- </template>
1607
-
1608
- <!--定义国际化I18n-->
1609
- <template
1610
- v-for="item in sohelpConfig?.properties?.map(item => item)"
1611
- #[`header_${item.name}`]="{ column, rowIndex }"
1612
- :key="item.name"
1613
- >
1614
- {{ item.i18n ? t(item.i18n) : item.label }}
1615
- </template>
1616
-
1617
- <!--自定义定义分页--->
1618
- <template #pager>
1619
- <vxe-pager
1620
- v-if="gridOptions.pagerConfig.enabled"
1621
- v-model:currentPage="gridOptions.pagerConfig.currentPage"
1622
- v-model:pageSize="gridOptions.pagerConfig.pageSize"
1623
- :total="gridOptions.pagerConfig.total"
1624
- @page-change="pageChangeEvent"/>
1625
- </template>
1626
-
1627
- <!-- 高级筛选 -->
1628
- <template
1629
- v-for="field in Object.values(propertiesMap).filter(item => item.query)" :key="field.name"
1630
- #[`filter_${field.name}`]="{ column }">
1631
- <div v-for="(option, index) in column.filters" :key="index" class="condition-box">
1632
- <filter-condition-item
1633
- :key="field.name"
1634
- v-model="getCurrentFilter(field.name).value"
1635
- :properties="propertiesMap[field.name]"
1636
- :teleported="false"
1637
- />
1638
- </div>
1639
- </template>
1640
-
1641
- <!-- 工具栏 -->
1642
- <template #toolbarTools>
1643
- <div class="toolbar-box">
1644
- <!-- 查看范围 -->
1645
- <div class="power-box">
1646
- <sohelp-power @change="changePower" v-if="sohelpConfig?.filter?.config?.visibleDataRange"/>
1647
- </div>
1648
-
1649
- <div class="search-box" v-if="sohelpConfig?.filter?.config?.visibleKeywords && sohelpConfig?.filter?.keywords.length>0 ">
1650
- <!-- 关键字 -->
1651
- <ele-tooltip :content="getKeywordsPlaceholder" placement="top" :offset="3">
1652
- <sohelp-input
1653
- :model-value="filterValue.keywords" @update:model-value="keywordsChange"
1654
- :placeholder="getKeywordsPlaceholder" clearable
1655
- @keyup.enter="filter" size="small" style="width: 160px;">
1656
- <template #append>
1657
- <el-button :icon="Search" @click="filter" size="small" />
1658
- </template>
1659
- </sohelp-input>
1660
- </ele-tooltip>
1661
- <el-button size="small" :icon="Refresh" @click="resetFilter">{{ t("grid.toolbar.reset") }}</el-button>
1662
- </div>
1663
-
1664
- <div class="tools-btns">
1665
- <sohelp-drop-card
1666
- :title="t('grid.toolbar.sort')" :icon="Sort" ref="sohelpSortRef"
1667
- v-if="sohelpConfig?.filter?.config?.visibleSort && sortList.length > 0">
1668
- <div class="sort-list">
1669
- <ele-card
1670
- v-for="item in sortList" :key="item.title" :header="item.title"
1671
- :bodyStyle="{padding: '0'}"
1672
- :headerStyle="{fontSize: '14px', fontWeight: 'normal', padding: '5px 0'}">
1673
- <template #extra>
1674
- <ele-text
1675
- :icon="SortUp" style="cursor: pointer;" :underline="false" size="sm"
1676
- @click="sortCommand(item.field,'asc')" plain :type="isActiveSort(item.field,'asc')">
1677
- {{ t("grid.toolbar.asc") }}
1678
- </ele-text>
1679
- <ele-text
1680
- :icon="SortDown" style="cursor: pointer;margin-left:5px!important" :underline="false"
1681
- size="sm" @click="sortCommand(item.field,'desc')" plain
1682
- :type="isActiveSort(item.field,'desc')">{{t("grid.toolbar.desc")}}
1683
- </ele-text>
1684
- </template>
1685
- </ele-card>
1686
- </div>
1687
- </sohelp-drop-card>
1688
- <el-button :icon="Filter" size="small"
1689
- @click="showFilter()"
1690
- plain
1691
- :type="(sohelpConfig?.filter?.config?.visibleFilter && sohelpConfig?.filter?.config?.filterPosition !== 'NONE')?'primary':''"
1692
- v-if="sohelpConfig?.filter?.config?._visibleFilter"/>
1693
- <ele-tooltip v-if="importAuthority" :content="'批量导入数据'" placement="top" :offset="3">
1694
- <el-button size="small" plain :icon="ElementPlusIcons.Upload" @click="openImport" />
1695
- </ele-tooltip>
1696
- <ele-tooltip v-if="exportAuthority" :content="'批量导出数据'" placement="top" :offset="3">
1697
- <el-dropdown @command="exportData">
1698
- <el-button size="small" plain :icon="ElementPlusIcons.Download"/>
1699
- <template #dropdown>
1700
- <el-dropdown-menu>
1701
- <el-dropdown-item :command="0" :disabled="!selections || selections.length === 0">
1702
- <el-icon><Memo /></el-icon>
1703
- <span style="margin-left:6px;">导出选中数据</span>
1704
- </el-dropdown-item>
1705
- <el-dropdown-item :command="1">
1706
- <el-icon><Files /></el-icon>
1707
- <span style="margin-left:6px;">当前页数据</span>
1708
- </el-dropdown-item>
1709
- <el-dropdown-item :command="2">
1710
- <el-icon><Grid /></el-icon>
1711
- <span style="margin-left:6px;">全部记录数据</span>
1712
- </el-dropdown-item>
1713
- </el-dropdown-menu>
1714
- </template>
1715
- </el-dropdown>
1716
- </ele-tooltip>
1717
- </div>
1718
- </div>
1719
- </template>
1720
-
1721
-
1722
- <!-- 未编辑状态 -->
1723
- <template
1724
- v-for="name in sohelpConfig?.properties?.map(item => item.name)"
1725
- #[`default_${name}`]="{ row, column, rowIndex }"
1726
- :key="name"
1727
- >
1728
- <div style=" display: flex; justify-content: right;" :style="{ justifyContent: getAlign(propertiesMap[name].align)}">
1729
-
1730
- <!-- 字典 -->
1731
- <sohelp-dict
1732
- type="text"
1733
- v-model="row[name]"
1734
- v-if="column.type === 'SohelpDict'"
1735
- v-bind="column.editRender"
1736
- />
1737
- <!-- 图片 -->
1738
- <sohelp-image-upload
1739
- v-else-if="column.type === 'SohelpImageUpload'"
1740
- v-model="row[name]"
1741
- v-bind="column.editRender"
1742
- :data="getCellValue(rowIndex,name)"
1743
- :readonly="!column.editRender.edit"
1744
- />
1745
- <!-- 附件 -->
1746
- <sohelp-file-upload
1747
- v-else-if="column.type === 'SohelpFileUpload'"
1748
- v-model="row[name]"
1749
- v-bind="column.editRender"
1750
- :data="getCellValue(rowIndex,name)"
1751
- :readonly="!column.editRender.edit"
1752
- />
1753
-
1754
- <!-- 下拉选择表格 -->
1755
- <div v-else-if="column.type === 'SohelpTableSelect' || column.type === 'ORG' || column.type ==='USER'">
1756
- <span>{{ getTableSelectLabel(row[name], rowIndex, name, column) }}</span>
1757
- </div>
1758
-
1759
- <!-- 评分 -->
1760
- <sohelp-rate
1761
- v-else-if="column.type==='SohelpRate'"
1762
- v-model="row[name]"
1763
- v-bind="column.editRender"
1764
- :disabled="!column.editRender.edit"
1765
- show-score
1766
- score-template="{value} 分"
1767
- style="min-width: 150px"
1768
- />
1769
-
1770
- <!-- 进度 -->
1771
- <sohelp-process
1772
- v-else-if="column.type==='SohelpProcess'"
1773
- v-model="row[name]"
1774
- v-bind="column.editRender"
1775
- style="width: 100%"
1776
- :readonly="!column.editRender.edit"
1777
- />
1778
-
1779
-
1780
- <!-- 下拉用户选择 -->
1781
- <div v-else-if="column.type === 'SohelpUserSelect'">
1782
- {{ gridData[rowIndex][name]?.["user_name"] }}
1783
- </div>
1784
-
1785
- <!-- 下拉组织选择 -->
1786
- <div v-else-if="column.type === 'SohelpOrgTreeSelect'">
1787
- {{ gridData[rowIndex][name]?.["org_name"] }}
1788
- </div>
1789
-
1790
- <!-- 开关 -->
1791
- <div v-else-if="column.type==='SohelpSwitch' || column.type === 'SohelpCheckbox'">
1792
- <span v-if="!column.editRender.edit">
1793
- {{ !!row[name] ? "V" : "" }}
1794
- </span>
1795
- <sohelp-switch
1796
- v-model="row[name]"
1797
- v-bind="column.editRender"
1798
- style="width: 100%;"
1799
- v-else
1800
- :activeValue="1"
1801
- :inactiveValue="0"
1802
- />
1803
- </div>
1804
-
1805
- <!-- 文本域 -->
1806
- <p
1807
- style="margin: 0;"
1808
- class="textarea-reference"
1809
- @click="showTextareaModal(column, name, row)"
1810
- v-bind="column.editRender"
1811
- v-else-if="column.type === 'SohelpTextarea'"
1812
- >{{ row[name] }}
1813
- </p>
1814
-
1815
- <!-- 外键关联 -->
1816
- <div v-else-if="column.type === 'RELATION' || column.type === 'SohelpTableSelect'">
1817
- {{ gridData[rowIndex][name]?.[column?.editRender?.labelField] || "" }}
1818
- </div>
1819
-
1820
- <!-- 富文本 -->
1821
- <div v-else-if="column.type === 'SohelpRichText'" v-html="row[name]"></div>
1822
-
1823
- <div v-else>
1824
- {{ row[name] }}
1825
- </div>
1826
- </div>
1827
- </template>
1828
-
1829
- <!-- 可编辑状态 -->
1830
- <template
1831
- v-for="name in sohelpConfig?.properties?.map(item => item.name)"
1832
- #[`edit_${name}`]="{ row, column, rowIndex }"
1833
- :key="name"
1834
- >
1835
- <div v-if="column.editRender.enabled">
1836
- <!-- 字典 -->
1837
- <sohelp-dict
1838
- v-model="row[name]"
1839
- :code="column.dict"
1840
- v-if="column.type === 'SohelpDict'"
1841
- v-bind="column.editRender"
1842
- style="width: 100%;"
1843
- :visible="true"
1844
- />
1845
-
1846
-
1847
- <!-- 下拉用户选择 -->
1848
- <sohelp-number-input
1849
- v-model="row[name]"
1850
- v-else-if="column.type==='SohelpInputNumber'"
1851
- v-bind="column.editRender"
1852
- style="width: 100%;"
1853
- />
1854
-
1855
- <!-- 日期、日期时间 -->
1856
- <sohelp-datetime
1857
- v-model="row[name]"
1858
- v-else-if="column.type==='SohelpDatetime' || column.type==='SohelpDate'"
1859
- v-bind="column.editRender"
1860
- style="width: 100%;"
1861
- :focus="true"
1862
- />
1863
-
1864
- <!-- 下拉用户选择 -->
1865
- <sohelp-user-select
1866
- v-else-if="column.type==='SohelpUserSelect'"
1867
- v-model="row[name]"
1868
- v-bind="column.editRender"
1869
- :datasource="userDatasource"
1870
- />
1871
-
1872
- <!-- 下拉组织机构 -->
1873
- <sohelp-org-tree-select
1874
- v-else-if="column.type==='SohelpOrgTreeSelect'"
1875
- v-model="row[name]"
1876
- v-bind="column.editRender"
1877
- :datasource="orgDatasource"
1878
- />
1879
-
1880
- <!-- 外键关联 -->
1881
- <sohelp-table-select v-else-if="column.type==='SohelpTableSelect'"
1882
- v-model="row[name]"
1883
- v-model:data="gridData[rowIndex][name]"
1884
- v-bind="column.editRender"
1885
- />
1886
-
1887
- <!-- 数值 -->
1888
- <sohelp-number-input
1889
- v-model="row[name]"
1890
- v-else-if="column.type==='SohelpNumberInput'"
1891
- v-bind="column.editRender"
1892
- style="width: 100%;"
1893
- :autoFocus="true"
1894
- />
1895
-
1896
- <!-- 其他 -->
1897
- <sohelp-input
1898
- v-model="row[name]"
1899
- v-bind="column.editRender"
1900
- :autoFocus="true"
1901
- v-else
1902
- style="width: 100%;"
1903
- :show-word-limit="false"
1904
- />
1905
- </div>
1906
- </template>
1907
-
1908
- <!-- 操作栏 -->
1909
- <template #_operation="{ row, column }">
1910
- <el-space :size="10">
1911
- <el-link
1912
- v-for="(item) in getOperationButtonsByType(row, column)"
1913
- :key="item.code"
1914
- :type="item.code === 'crud.delete' ? 'danger' : 'primary'"
1915
- v-bind="item.params"
1916
- @click="operationHandler({button:item, row:row,$grid:sohelpVxeGridRef})"
1917
- >
1918
- <el-icon v-if="item.icon" style="margin-right: 5px;">
1919
- <component :is="ElementPlusIcons[item.icon]" v-if="ElementPlusIcons[item.icon]" />
1920
- <component :is="EleAdminPlusIcons[item.icon]" v-else-if="EleAdminPlusIcons[item.icon]" />
1921
- <span :class="item.icon" v-else></span>
1922
- </el-icon>
1923
- {{ item.title }}
1924
- </el-link>
1925
- <!-- 更多 -->
1926
- <el-dropdown v-if="getOperationButtonsByType(row, column,'more')?.length > 0">
1927
- <el-link :underline="false">
1928
- <span>更多</span>
1929
- <el-icon style="margin-left: 4px;">
1930
- <arrow-down />
1931
- </el-icon>
1932
- </el-link>
1933
- <template #dropdown>
1934
- <el-dropdown-menu>
1935
- <el-dropdown-item
1936
- v-for="item in getOperationButtonsByType(row, column, 'more')" :key="item.code"
1937
- @click.stop="operationHandler({button:item, row:row,$grid:sohelpVxeGridRef})"
1938
- v-bind="item.props">
1939
- <el-icon v-if="item.icon">
1940
- <component :is="ElementPlusIcons[item.icon]" v-if="ElementPlusIcons[item.icon]" />
1941
- <component :is="EleAdminPlusIcons[item.icon]" v-else-if="EleAdminPlusIcons[item.icon]" />
1942
- <span :class="item.icon" v-else></span>
1943
- </el-icon>
1944
- {{ item.title }}
1945
- </el-dropdown-item>
1946
- </el-dropdown-menu>
1947
- </template>
1948
- </el-dropdown>
1949
- <slot name="_operation" :row="row"></slot>
1950
- </el-space>
1951
- </template>
1952
-
1953
- <!-- 统计 -->
1954
- <template
1955
- v-for="field in footerData"
1956
- #[`footer_${field["field"]}`]="{ row, column,rowIndex}"
1957
- :key="field['field']"
1958
- >
1959
- <div v-html="row[column.field]"></div>
1960
- </template>
1961
-
1962
- <!-- 验证 -->
1963
- <template #valid_slot="{content}">
1964
- {{ content }}
1965
- </template>
1966
-
1967
-
1968
- <template v-for="(_,name) in $slots" #[name]="{row, column}">
1969
- <slot :name="name" :row="getRowDataByField(column,row)" :column="column"></slot>
1970
- </template>
1971
-
1972
- </vxe-grid>
1973
-
1974
- <!-- workflow -->
1975
- <workflow-drawer
1976
- :data="drawerData"
1977
- v-model="drawerVisible"
1978
- :showOpera="false"
1979
- ref="todoDrawerRef"
1980
- :key="drawerKey"
1981
- />
1982
-
1983
- <!-- 提交审批 -->
1984
- <approval-modal
1985
- v-model="approvalModalVisible"
1986
- type="submit"
1987
- :data="approvalData"
1988
- @confirm="reload"
1989
- />
1990
-
1991
- <!-- SohelpTextareaInput 编辑弹窗 -->
1992
- <ele-modal :width="460" v-model="textareaState['visible']" :title="getCurrentFieldLabel">
1993
- <sohelp-textarea-input v-model="textareaState['value']" :rows="6"/>
1994
- <template #footer>
1995
- <el-button @click="textareaCancel">{{ t("common.cancel") }}</el-button>
1996
- <el-button type="primary" @click="textareaConfirm(row, column)">{{ t("common.save") }}</el-button>
1997
- </template>
1998
- </ele-modal>
1999
-
2000
- <!--实体表单-->
2001
- <sohelp-modal
2002
- :title="toolbarButtonParams?.title || ''"
2003
- :width="toolbarButtonParams?.width || 860"
2004
- :draggable="false"
2005
- v-model="visibleEntityForm" v-loading="loading">
2006
- <template #setting v-if="userStore.info.is_developer">
2007
- <ele-dropdown
2008
- :items="[
2009
- { title: '表单配置', command: 'form' , icon:Postcard},
2010
- { title: '实体配置', command: 'entity', icon:Tickets},
2011
- { title: '流程配置', command: 'workflow', icon:Files },
2012
- { title: '模块配置', command: 'module', icon:Grid }
2013
- ]"
2014
- @command="settingClick"
2015
- >
2016
- <el-link :icon="Setting" :underline="false"/>
2017
- </ele-dropdown>
2018
- </template>
2019
-
2020
-
2021
- <sohelp-entity-form ref="entityFormRef" :refid="props.refid.split('!')[0]" v-model="entityFormValue"
2022
- :data="entityFormData" :config="entityFormConfig" :readonly="toolbarButtonParams?.readonly" :saveParams="saveParams" />
2023
- <template #footer v-if="!toolbarButtonParams?.readonly">
2024
- <el-button @click="closeEntityForm()">{{ t("common.close") }}</el-button>
2025
- <el-button type="primary" @click="saveEntityForm()" v-loading="loading">{{ t("common.save") }}</el-button>
2026
- </template>
2027
- </sohelp-modal>
2028
- <!--打印报表-->
2029
- <ele-modal
2030
- :title="toolbarButtonParams?.title|| t('grid.report.title')" :width="toolbarButtonParams?.width|| 600"
2031
- v-model="visibleReport">
2032
-
2033
- <ele-check-card v-model="currentReportValue" :items="reportData" :row="{ gutter: 2 }">
2034
- <template #item="{ item }">
2035
- <ele-text size="md" style="padding:10px;">{{ item.name }}</ele-text>
2036
- </template>
2037
- </ele-check-card>
2038
-
2039
- <template #footer>
2040
- <el-button @click="closeReport()">{{ t("common.close") }}</el-button>
2041
- <el-button @click="designReport()" v-if="reportData && reportData.length>0">{{ t("common.design") }}</el-button>
2042
- <el-button type="primary" @click="openReport()" v-if="reportData && reportData.length>0">{{ t("common.print") }}
2043
- </el-button>
2044
- </template>
2045
- </ele-modal>
2046
- <!--数据导入-->
2047
- <sohelp-import
2048
- :model-value="importVisible"
2049
- :refid="props.refid"
2050
- :fields="sohelpConfig?.properties || []"
2051
- @update:modelValue="(v) => importVisible = v"
2052
- @close="closeImport"
2053
- />
2054
- </template>
2055
-
2056
- <style scoped lang="scss">
2057
- .sohelp-grid-view {
2058
- padding: 0px;
2059
- display: flex;
2060
- height: 100%;
2061
- flex-direction: column;
2062
-
2063
- :deep(.vxe-grid--table-wrapper) {
2064
- .vxe-table {
2065
- height: 100%;
2066
- }
2067
- }
2068
-
2069
-
2070
- .toolbar-box {
2071
- display: flex;
2072
- gap: 10px;
2073
- flex-wrap: wrap;
2074
-
2075
- .tools-btns {
2076
- display: flex;
2077
- gap: 10px;
2078
- margin-right: 10px;
2079
-
2080
- :deep(.el-button) {
2081
- margin-left: 0 !important;
2082
- }
2083
- }
2084
- }
2085
-
2086
- .ele-split-panel {
2087
- :deep(.ele-split-panel-side) {
2088
- border: none !important;
2089
- }
2090
- }
2091
-
2092
- .vxe-grid {
2093
- height: 100%;
2094
-
2095
- :deep(.vxe-grid--layout-body-content-wrapper) {
2096
- display: flex;
2097
- flex-direction: column;
2098
-
2099
- .vxe-grid--table-container {
2100
- flex: 1;
2101
- }
2102
- }
2103
-
2104
- :deep(.col--SohelpImageUpload) {
2105
- .vxe-cell--wrapper {
2106
- overflow: initial !important;
2107
- }
2108
- }
2109
-
2110
- :deep(.vxe-table--render-default) {
2111
- .vxe-body--row.row--stripe > .vxe-body--column {
2112
- // background-color: transparent;
2113
- }
2114
- }
2115
-
2116
- }
2117
- }
2118
-
2119
- .sort-list :deep(.el-button:focus),
2120
- .sort-list :deep(.el-button:hover) {
2121
- background-color: #e8f1ff !important;
2122
- color: #1677ff !important;
2123
- }
2124
-
2125
- .filter-header {
2126
- border-bottom: 1px solid #ddd;
2127
- display: flex;
2128
- width: 100%;
2129
- height: 35px;
2130
- line-height: 40px;
2131
- box-sizing: border-box;
2132
- margin: 0 0 0 10px;
2133
- }
2134
-
2135
- .sohelp-grid-view.right {
2136
- .ele-split-panel {
2137
- :deep(.ele-split-panel-side) {
2138
- height: 100% !important;
2139
- border: 0;
2140
- display: flex;
2141
- flex-direction: column;
2142
- border-left: 1px solid #ddd !important;
2143
- }
2144
- }
2145
- }
2146
-
2147
- :deep(.tooltip-btn) {
2148
- margin-left: 5px;
2149
- height: 22px;
2150
- line-height: 22px;
2151
- margin-top: 2px;
2152
- padding: 0px 5px !important;
2153
- }
2154
-
2155
- :deep(.vxe-cell--wrapper) {
2156
- height: 100%;
2157
- }
2158
-
2159
- .textarea-reference {
2160
- display: flex;
2161
- height: 100%;
2162
- }
2163
-
2164
- :deep(.ele-split-panel.is-vertical) {
2165
- .ele-split-panel-wrap > .ele-split-panel-space .ele-split-resize-line::after {
2166
- background: #eee;
2167
- }
2168
- }
2169
-
2170
- .condition-box {
2171
- padding: 10px;
2172
- }
2173
-
2174
- .sohelp-filter-card.right {
2175
- height: 100%;
2176
- overflow: hidden;
2177
-
2178
- :deep(.ele-card-header) {
2179
- min-width: 230px;
2180
- }
2181
-
2182
- :deep(.ele-card-body) {
2183
- height: 100% !important;
2184
- }
2185
- }
2186
-
2187
- .column-setting{
2188
- padding: 5px 10px;
2189
- display: flex;
2190
- align-items: center;
2191
- justify-content: space-between;
2192
- width: 100%;
2193
- }
2194
-
2195
-
2196
- .vxe-grid{
2197
- :deep(.vxe-grid--toolbar-wrapper){
2198
- .vxe-button--dropdown{
2199
- .vxe-button--dropdown-panel{
2200
- .vxe-button{
2201
- padding-left: 5px!important;
2202
- text-align: left;
2203
- }
2204
- }
2205
-
2206
- }
2207
- }
2208
- }
2209
-
2210
- </style>
1
+ <script>
2
+ export default {
3
+ name: "SohelpGrid"
4
+ }
5
+ </script>
6
+ <script setup>
7
+ import { Filter, Search, Sort, SortDown, SortUp,Setting,Memo,Menu,Tickets,Postcard, Files, Grid, Refresh} from "@element-plus/icons-vue";
8
+ import { useMobile } from "@/utils/use-mobile";
9
+ import { usePermission } from "@/utils/use-permission";
10
+ import DefaultProps from "./js/DefaultProps";
11
+ import { computed, nextTick, reactive, ref, watch } from "vue";
12
+ import DefaultGridOptions from "./js/DefaultGridOptions";
13
+ import { calcSummary, switchGridValue } from "./js/SohelpGridConfig";
14
+ import { EleMessage } from "@/components/ele-admin-plus/components";
15
+ import { ElMessageBox } from "element-plus/es";
16
+ import { safeEval, safeFunctionExec } from '../utils/safe-eval.js';
17
+ import { useFormData } from "@/utils/use-form-data";
18
+ import { sanitizeHtml } from "@/utils/sanitize-html";
19
+ import { resetCommonConfig, updateCommonConfig } from "../http/ModuleHttp.js";
20
+ import CrudHttp from "../http/CrudHttp.js";
21
+ import {merge, cloneDeep } from "lodash-es";
22
+ import { uuid } from "../utils/core.js"
23
+
24
+ import ApprovalModal from "../sohelp-workflow-drawer/components/approval-modal.vue";
25
+ import WorkflowDrawer from "../sohelp-workflow-drawer/index.vue";
26
+
27
+ import SohelpTextareaInput from "../sohelp-textarea-input/index.vue";
28
+ import SohelpPower from "../sohelp-power/index.vue";
29
+ import FilterConditionItem from "./components/filter-condition-item.vue";
30
+ import { useSohelpGridConfig } from "./js/useSohelpGridConfig.js";
31
+ import { useI18n } from "vue-i18n";
32
+ import SohelpEntityForm from "../sohelp-entity-form/index.vue";
33
+ import * as ElementPlusIcons from '@element-plus/icons-vue';
34
+ import * as EleAdminPlusIcons from '@/components/icons';
35
+ import { moduleCache } from "../cache/ModuleCache.js";
36
+ import SohelpModal from "../sohelp-modal/index.vue";
37
+ import SohelpImport from "../sohelp-import/index.vue";
38
+ import { useUserStore } from '@/store/modules/user';
39
+ import { Alert } from "vxe-pc-ui";
40
+ const { initial, isConfigDone } = useSohelpGridConfig();
41
+ const { t } = useI18n();
42
+ const { mobile } = useMobile();
43
+ const permission = usePermission();
44
+ const props = defineProps({ ...JSON.parse(JSON.stringify(DefaultProps)) });
45
+ const emit = defineEmits(["resetFilter", "checkboxAll", "checkboxChange","radioChange", "toolbarButtonClick", "operationButtonClick", "menuRightClick", "showFilter", "editClosed", "currentColumnChange"]);
46
+ const drawerKey = ref(0);
47
+ const todoDrawerRef = ref(null);
48
+ const drawerVisible = ref(false);
49
+ const drawerData = ref(null);
50
+ const current = ref(null);
51
+ const isPage = ref(false);
52
+ const approvalModalVisible = ref(false);
53
+ const approvalData = ref({});
54
+ const userStore = useUserStore();
55
+
56
+ //报表打印
57
+ const currentReportValue = ref(null);
58
+ const visibleReport = ref(false);
59
+ const reportData = ref([]);
60
+ const currentRow = ref(null);
61
+
62
+ /** 自动生成ID */
63
+ const getId = () => {
64
+ return 'sohelp-grid-' + uuid();
65
+ }
66
+
67
+ /** 对齐方式映射 */
68
+ const getAlign = (align) => {
69
+ const alignMap = {
70
+ 'left': 'flex-start',
71
+ 'center': 'center',
72
+ 'right': 'flex-end',
73
+ '': 'flex-start'
74
+ };
75
+ return alignMap[align] || 'flex-start';
76
+ }
77
+
78
+ const loadReport = () => {
79
+ SohelpHttp.get("/engine/web/report/list", { refid: props.refid }).then(res => {
80
+ if (res.meta.success) {
81
+ reportData.value = res.data.map(item => ({
82
+ value: item.refid,
83
+ refid: item.refid,
84
+ name: item.name,
85
+ createDate: item.createDate
86
+ }));
87
+ if (reportData.value.length > 0) {
88
+ currentReportValue.value = reportData.value[0].refid;
89
+ }
90
+ } else {
91
+ EleMessage.error(res.meta.message);
92
+ }
93
+ });
94
+ };
95
+
96
+ const designReport = () => {
97
+ if (!currentReportValue.value || !currentRow?.value?.id) {
98
+ EleMessage.error("请选择报表模板或报表数据!");
99
+ return;
100
+ }
101
+ const baseURl = SohelpHttp.getBaseUrl();
102
+ const url = baseURl.endsWith("/") ? baseURl : baseURl + "/";
103
+ window.open(url + `ureport/designer?_u=${currentReportValue.value}&id=${currentRow?.value?.id}&refid=${currentReportValue?.value}`);
104
+ };
105
+ const openReport = () => {
106
+ if (!currentReportValue.value || !currentRow?.value?.id) {
107
+ EleMessage.error("请选择报表模板或报表数据!");
108
+ return;
109
+ }
110
+ const baseURl = SohelpHttp.getBaseUrl();
111
+ const url = baseURl.endsWith("/") ? baseURl : baseURl + "/";
112
+ window.open(url + `ureport/preview?_u=${currentReportValue.value}&id=${currentRow?.value?.id}&refid=${currentReportValue?.value}`);
113
+ };
114
+ const closeReport = () => {
115
+ visibleReport.value = false;
116
+ };
117
+
118
+ // 操作栏按钮配置
119
+ const operationsButtons = reactive({});
120
+
121
+ const loading = ref(false);
122
+ //显示实体表单
123
+ const visibleEntityForm = ref(false);
124
+ //当前工具栏配置信息
125
+ const toolbarButtonParams = ref({});
126
+ const entityFormRef = ref(null);
127
+ const entityFormData = ref({});
128
+ const entityFormValue = ref({});
129
+ const entityFormConfig = ref({});
130
+ const closeEntityForm = () => {
131
+ visibleEntityForm.value = false;
132
+ };
133
+
134
+ /**
135
+ * 保存实体表单
136
+ */
137
+ const saveEntityForm = async () => {
138
+ const v = await entityFormRef.value.validate();
139
+ if(v){
140
+ loading.value = true;
141
+ entityFormRef.value.save(props.saveParams, (res) => {
142
+ loading.value = false;
143
+ if (res.meta.success) {
144
+ refresh();
145
+ visibleEntityForm.value = false;
146
+ } else {
147
+ EleMessage.error(res.meta.message);
148
+ }
149
+ });
150
+ }
151
+ };
152
+
153
+ //配置加载状态
154
+ // Grid配置
155
+ const sohelpConfig = defineModel("config");
156
+ // 过滤条件数据
157
+ const filterValue = defineModel("filterValue", {
158
+ type: Object,
159
+ default: () => ({
160
+ keywords: "",
161
+ power: 0,
162
+ filter: [],
163
+ scheme: "",
164
+ sort: "",
165
+ order: ""
166
+ })
167
+ });
168
+
169
+ // 属性映射
170
+ const propertiesMap = defineModel("propertiesMap");
171
+
172
+ // Grid实例
173
+ const sohelpVxeGridRef = ref(null);
174
+ // GridOptions配置
175
+ const gridOptions = reactive(cloneDeep(DefaultGridOptions));
176
+ const batchButtonsIndex = ref(2);
177
+ const sortValue = ref("");
178
+ /**
179
+ * 缓存网格列表数据
180
+ * @type {UnwrapNestedRefs<*[]>}
181
+ */
182
+ const gridData = reactive([]);
183
+ /**
184
+ * 记忆原始过虑条件数据
185
+ * @type {Ref<UnwrapRef<string>>}
186
+ */
187
+ const originFilterValue = ref("");
188
+
189
+ /**
190
+ * 选中数据庥
191
+ * @type {Ref<UnwrapRef<*[]>>}
192
+ */
193
+ const selections = ref([]);
194
+ /**
195
+ * 网格列表底部数据
196
+ * @type {UnwrapNestedRefs<*[]>}
197
+ */
198
+ const footerData = reactive([]);
199
+ /**
200
+ * 定义计算公式
201
+ * @type {UnwrapNestedRefs<{}>}
202
+ */
203
+ const formulaMap = reactive({});
204
+ /**
205
+ * 定义合计数据
206
+ * @type {UnwrapNestedRefs<{}>}
207
+ */
208
+ const summaryData = reactive({});
209
+
210
+ /**
211
+ * 查看范围
212
+ * @type 类型
213
+ * @users 用户列表
214
+ */
215
+ const changePower = (type, users) => {
216
+ filterValue.value.power = type;
217
+ if (type == 9) {
218
+ filterValue.value.powerUsers = users;
219
+ }
220
+ filter();
221
+ };
222
+
223
+
224
+ const getCellValue = (rowIndex, name) => {
225
+ return (gridData[rowIndex] && gridData[rowIndex][name]) ? gridData[rowIndex][name] : "";
226
+ };
227
+
228
+ /**
229
+ * 获取行原始数据
230
+ */
231
+ const getRowDataByField = (column, row) => {
232
+ if(column.type === 'SohelpTableSelect'){
233
+ const {field} = column;
234
+ return gridData.find(item => item[field].id === row[field]) || row;
235
+ } else{
236
+ return row;
237
+ }
238
+ }
239
+
240
+ /**
241
+ * 获取关键字描述
242
+ */
243
+ const getKeywordsPlaceholder = computed(() => {
244
+ if (sohelpConfig.value?.filter?.keywords?.length) {
245
+ return t("grid.toolbar.keywords") + " [" + sohelpConfig.value.filter?.keywords?.filter(key => propertiesMap.value[key]).map(key => t(propertiesMap.value[key].i18n) || propertiesMap.value[key].label).join(",") + "]";
246
+ }
247
+ return t("grid.toolbar.keywords");
248
+ });
249
+
250
+
251
+ /**
252
+ * SohelpTextareaInput弹窗标题
253
+ */
254
+ const getCurrentFieldLabel = computed(() => {
255
+ return (propertiesMap.value?.[textareaState["field"]]?.label || "") + "修改";
256
+ });
257
+
258
+ const importVisible = ref(false);
259
+ const importAuthority = computed(() => {
260
+ const prefix = (props.refid || '').split('!')[0] || '';
261
+ const authorityKey = prefix + ':batch.import';
262
+ return sohelpConfig.value?.importConfig?.enabled && permission.hasPermission(authorityKey);
263
+ });
264
+ const exportAuthority = computed(() => {
265
+ const prefix = (props.refid || '').split('!')[0] || '';
266
+ const authorityKey = prefix + ':batch.export';
267
+ return sohelpConfig.value?.exportConfig?.enabled && permission.hasPermission(authorityKey);
268
+ });
269
+
270
+ const openImport = () => {
271
+ try {
272
+ if (!props.refid) {
273
+ EleMessage.error('列表地址缺失,无法打开导入');
274
+ return;
275
+ }
276
+ importVisible.value = true;
277
+ } catch (e) {
278
+ EleMessage.error(typeof e === 'string' ? e : e?.message || '打开导入失败');
279
+ }
280
+ };
281
+ const closeImport = () => {
282
+ importVisible.value = false;
283
+ };
284
+ const exportData = async (dataRange) => {
285
+ if (dataRange === 0) {
286
+ const $grid = sohelpVxeGridRef.value;
287
+ const selected = $grid?.getCheckboxRecords() || [];
288
+ if (!selected.length) {
289
+ EleMessage.error("请先勾选需要导出的记录");
290
+ return;
291
+ }
292
+ const ids = selected.map((item) => item.id).filter((id) => id !== undefined && id !== null);
293
+ if (!ids.length) {
294
+ EleMessage.error("选中记录未包含可导出的ID");
295
+ return;
296
+ }
297
+ let last = 0;
298
+ let loadingTip = EleMessage.loading("导出中 0%");
299
+ try {
300
+ await SohelpHttp.download("/engine/web/export/download", {
301
+ refid: props.refid,
302
+ exportRange: dataRange,
303
+ ...filterValue.value,
304
+ ids: ids
305
+ }, "导出数据.xlsx", (loaded, total) => {
306
+ if (total > 0) {
307
+ const p = Math.floor((loaded / total) * 100);
308
+ if (p - last >= 5) {
309
+ loadingTip.close();
310
+ loadingTip = EleMessage.loading(`导出中 ${p}%`);
311
+ last = p;
312
+ }
313
+ }
314
+ });
315
+ } catch (e) {
316
+ EleMessage.error(typeof e === "string" ? e : e?.message || "导出失败");
317
+ } finally {
318
+ loadingTip.close();
319
+ }
320
+ return;
321
+ }
322
+ let last = 0;
323
+ let loadingTip = EleMessage.loading("导出中 0%");
324
+ try {
325
+ await SohelpHttp.download("/engine/web/export/download", {
326
+ refid: props.refid,
327
+ exportRange: dataRange,
328
+ filterValue: JSON.stringify(filterValue.value)
329
+ }, "导出数据.xlsx", (loaded, total) => {
330
+ if (total > 0) {
331
+ const p = Math.floor((loaded / total) * 100);
332
+ if (p - last >= 5) {
333
+ loadingTip.close();
334
+ loadingTip = EleMessage.loading(`导出中 ${p}%`);
335
+ last = p;
336
+ }
337
+ }
338
+ });
339
+ } catch (e) {
340
+ EleMessage.error(typeof e === "string" ? e : e?.message || "导出失败");
341
+ } finally {
342
+ loadingTip.close();
343
+ }
344
+ };
345
+ const keywordsChange = (val) => {
346
+ filterValue.value = {
347
+ ...filterValue.value,
348
+ keywords: val
349
+ };
350
+ };
351
+
352
+ /**
353
+ * 获取当前筛选
354
+ * @param field
355
+ */
356
+ const getCurrentFilter = (field) => {
357
+ return computed({
358
+ get: () => {
359
+ return filterValue.value.filter?.find(f => f.name === field);
360
+ },
361
+ set: (newValue) => {
362
+ const newFilters = [...(filterValue.value.filter || [])];
363
+ const index = newFilters.findIndex(f => f.name === field);
364
+ if (index >= 0) {
365
+ newFilters[index] = { ...newFilters[index], ...newValue };
366
+ }
367
+ filterValue.value = { ...filterValue.value, filter: newFilters };
368
+ }
369
+ });
370
+ };
371
+
372
+ /**
373
+ *获取外键标签
374
+ */
375
+ const getTableSelectLabel = (val, index, field, column) => {
376
+ if (!gridData[index] || !gridData[index][field]) {
377
+ return "";
378
+ }
379
+ let obj = gridData[index][field];
380
+ if (obj && typeof obj === "object") {
381
+ if (!Array.isArray(obj)) {
382
+ obj = [obj];
383
+ }
384
+ const { labelField = "label", valueField = "id" } = column.editRender;
385
+ const arr = Array.isArray(val) ? val : [val];
386
+ return obj.filter(item => arr.includes(item.id))?.map(row => row[labelField]).filter(Boolean).join(",");
387
+
388
+ } else {
389
+ return "";
390
+ }
391
+ };
392
+
393
+ /**
394
+ * 获取排序数据
395
+ */
396
+ const sortList = computed(() => {
397
+ return sohelpConfig.value.filter?.sort?.map((field) => {
398
+ let p = propertiesMap.value[field];
399
+ return {
400
+ title: p?.label || field,
401
+ field: field
402
+ };
403
+ });
404
+ });
405
+
406
+ /**
407
+ * 排序点击事件
408
+ */
409
+ const sortCommand = (field, order) => {
410
+ if (sohelpVxeGridRef.value) {
411
+ sohelpVxeGridRef.value.setSort({ field, order });
412
+ }
413
+ closeSortDropCard();
414
+ };
415
+
416
+ const isActiveSort = computed(() => {
417
+ return (field, order) => {
418
+ return sortValue.value === field + "!" + order ? "primary" : "";
419
+ };
420
+ });
421
+
422
+ /**
423
+ *
424
+ * @param val 监听高级筛选值变化
425
+ */
426
+ const filterValueChange = (val) => {
427
+ //console.log('v', val);
428
+ };
429
+
430
+ /**
431
+ * 初始化数据
432
+ */
433
+ const loadConfig = (param = {}) => {
434
+ initial(!props.isEntityGrid, props.refid)
435
+ .then((config) => {
436
+ /**配置刷新功能 */
437
+ config.gridOptions = {
438
+ ...config.gridOptions,
439
+ params: gridOptions.params ?? {},
440
+ toolbarConfig: {
441
+ ...config.gridOptions?.toolbarConfig,
442
+ refresh: true,
443
+ zoom: true
444
+ },
445
+ proxyConfig: {
446
+ autoLoad: false,
447
+ ajax: {
448
+ query: () => refresh()
449
+ }
450
+ }
451
+ };
452
+
453
+
454
+
455
+ //工具栏按钮权限
456
+ Object.assign(formulaMap, config.formulaMap);
457
+ Object.assign(gridOptions, config.gridOptions);
458
+
459
+
460
+ // 过滤位置
461
+ config.sohelpConfig.filter.config._visibleFilter = config.sohelpConfig?.filter.config.visibleFilter || false;
462
+ sohelpConfig.value = { ...config.sohelpConfig };
463
+
464
+ if (propertiesMap.value) {
465
+ Object.assign(propertiesMap.value, config.propertiesMap);
466
+ } else {
467
+ propertiesMap.value = config.propertiesMap;
468
+ }
469
+
470
+ Object.assign(footerData, config.footerData);
471
+ batchButtonsIndex.value = config.batchButtonsIndex;
472
+ sohelpConfig.value.list = config.sohelpConfig.list;
473
+
474
+
475
+
476
+ Object.assign(operationsButtons, config.operationsButtons);
477
+
478
+ if (!filterValue.value.filter) {
479
+ filterValue.value.filter = [];
480
+ }
481
+
482
+ Object.assign(filterValue.value.filter, config.sohelpConfig.filter?.field || []);
483
+ //存储原始查询数据,用于重置
484
+ originFilterValue.value = JSON.stringify(filterValue.value);
485
+
486
+ nextTick(() => {
487
+ if (sohelpVxeGridRef.value && props.autoLoad === true) {
488
+ sohelpVxeGridRef.value.commitProxy("query");
489
+ }
490
+ });
491
+ })
492
+ .catch((e) => {
493
+ console.error("Initial Configuration Error:", e);
494
+ EleMessage.error(e.message);
495
+ });
496
+ };
497
+
498
+
499
+ const gridValue = ref();
500
+
501
+
502
+ const load = async (params = {}, callback) => {
503
+ //清空选中
504
+ selections.value = [];
505
+ gridOptions.loading = true;
506
+ gridOptions.params = params;
507
+ await isConfigDone();
508
+ const $grid = sohelpVxeGridRef.value;
509
+
510
+ if ($grid) {
511
+ const url = props.url || sohelpConfig.value.requestValue;
512
+ if (sohelpConfig.value.requestType != "crud" && !url) {
513
+ gridOptions.loading = false;
514
+ return { results: [], total: 0 };
515
+ }
516
+
517
+
518
+ let pageConfig = {};
519
+ // 是否分页
520
+ if (gridOptions.pagerConfig?.enabled) {
521
+ pageConfig.page = gridOptions.pagerConfig?.currentPage ?? 1;
522
+ pageConfig.limit = gridOptions.pagerConfig?.pageSize ?? 50;
523
+ }
524
+
525
+ //过滤条件筛选
526
+ params["filter"] = filterValue.value.filter?.filter(item => (item.comparison === "EMPTY" || item.comparison === "NOT_EMPTY") || item.value?.length > 0);
527
+ const res = await SohelpHttp.get(url, {
528
+ refid: props.refid,
529
+ ...filterValue.value,
530
+ ...params,
531
+ ...pageConfig
532
+ });
533
+
534
+
535
+
536
+ if (res?.meta?.success) {
537
+ if (res.data) {
538
+ gridOptions.pagerConfig.total = Number(res.data?.total);
539
+
540
+ const _data = res.data?.results || res.data || [];
541
+ Object.assign(gridData, JSON.parse(JSON.stringify(_data)));
542
+ gridValue.value = switchGridValue(_data);
543
+ $grid.loadData(gridValue.value);
544
+ Object.assign(summaryData, res.data?.summary || {});
545
+ updateColumnsFilter();
546
+ gridOptions.loading = false;
547
+ //统计
548
+ if (footerData.length > 0) {
549
+ gridOptions.footerData = updateSummary(res.data.results, res.data?.summary || {});
550
+ $grid?.refreshColumn();
551
+ }
552
+ }
553
+ } else {
554
+ EleMessage.error(res.meta.message);
555
+ }
556
+ gridOptions.loading = false;
557
+ //回调方法
558
+ if (callback && typeof callback === "function") {
559
+ callback(res);
560
+ }
561
+ }
562
+
563
+ emit('pageChange', gridOptions.pagerConfig);
564
+ };
565
+
566
+ /**
567
+ * 重新加载数据
568
+ */
569
+ const reload = async (params = {}) => {
570
+ Object.assign(gridOptions.params, params);
571
+ await load(gridOptions.params);
572
+ };
573
+
574
+
575
+ /**
576
+ * 单元格点击更新 表尾统计
577
+ */
578
+ const cellClick = () => {
579
+ const data = sohelpVxeGridRef.value?.getFullData();
580
+ gridOptions.footerData = updateSummary(data, summaryData);
581
+ };
582
+
583
+ /**
584
+ * 统计
585
+ */
586
+ const updateSummary = (data, summaryMap = {}) => {
587
+ const arr = footerData.map(item => {
588
+ const field = data.map(f => {
589
+ let val = Number(f[item.field]);
590
+ return isNaN(val) ? 0 : val;
591
+ });
592
+
593
+ let value = calcSummary(field, item.type);
594
+ if (item.type === "remotesum") {
595
+ value = summaryMap[item.field] || "";
596
+ }
597
+
598
+ if (item.summaryRender) {
599
+ try {
600
+ value = safeEval(item.summaryRender, { value, $grid: sohelpVxeGridRef });
601
+ } catch (e) {
602
+ console.error("函数执行错误:", e);
603
+ }
604
+ }
605
+
606
+ return {
607
+ [item.field]: value
608
+ };
609
+ });
610
+
611
+ arr.unshift({ _seq: "统计" });
612
+ return [Object.assign({}, ...arr)];
613
+ };
614
+
615
+
616
+ /**
617
+ * 分页事件
618
+ */
619
+ const pageChangeEvent = async (page) => {
620
+ isPage.value = true;
621
+ gridOptions.pagerConfig.currentPage = page.currentPage;
622
+ gridOptions.pagerConfig.pageSize = page.pageSize;
623
+ await reload();
624
+ emit('pageChange',gridOptions.pagerConfig)
625
+ };
626
+
627
+
628
+ /**
629
+ * 获取Common类型操作栏 并根据flw_id判断是否显示
630
+ * @param row
631
+ */
632
+ const getOperationButtonsByType = computed(() => {
633
+ return (row, column, type = "common") => {
634
+ const $grid = sohelpVxeGridRef.value;
635
+ let common = operationsButtons?.[type] || [];
636
+ if (common.length > 0) {
637
+ if (Object.prototype.hasOwnProperty.call(row, "flw_id")) {
638
+ const field = row.flw_id === "0" ? "workflow.view" : "workflow.submit";
639
+ common = common.filter(f => f.code != field);
640
+ } else {
641
+ common = common.filter(f => !["workflow.submit", "workflow.view"].includes(f.code));
642
+ }
643
+ return common.map((button) => {
644
+ // 创建新对象,避免修改原按钮配置
645
+ const newButton = { ...button };
646
+ if(newButton.render && newButton.render?.length > 0) {
647
+ safeFunctionExec(newButton.render, ["$row","$button","$column","$grid"], [row, newButton, column, $grid]);
648
+ }
649
+ return newButton;
650
+ });
651
+ }
652
+ return [];
653
+ };
654
+ })
655
+
656
+ /**
657
+ * 行操作栏点击事件
658
+ * @param row
659
+ * @param item
660
+ */
661
+ const operationHandler = ({ button, row, $grid }) => {
662
+
663
+
664
+ //操作栏事件执行
665
+ $grid.reload = reload;
666
+ $grid.refresh = refresh;
667
+ if (button.handler && typeof button.handler === "string") {
668
+ try {
669
+ (async () => {
670
+ const context = {
671
+ $message: EleMessage,
672
+ $SohelpModule: window.$SohelpModule,
673
+ $SohelpHttp: window.$SohelpHttp,
674
+ $confirm: (title, callback) => {
675
+ ElMessageBox.confirm(title, "提示", {
676
+ confirmButtonText: "确定",
677
+ cancelButtonText: "取消",
678
+ type: "warning"
679
+ }).then(() => {
680
+ callback && callback();
681
+ }).catch(() => {
682
+ });
683
+ }
684
+ };
685
+ await safeFunctionExec(button.handler, ["$row", "$grid"], [row, $grid], context);
686
+ })();
687
+ } catch (e) {
688
+ EleMessage.error(`操作栏事件出错:${e.message}`);
689
+ }
690
+ } else if (button.refid) {
691
+ if (button.openType === "tab") {
692
+ window.$SohelpModule.openTab(button.refid, { id: row.id }, button.params || {});
693
+ } else if (button.openType === "drawer") {
694
+ window.$SohelpModule.openDrawer(button.refid, { id: row.id }, button.params || {});
695
+ } else {
696
+ window.$SohelpModule.openModal(button.refid, { id: row.id }, button.params || {});
697
+ }
698
+ } else {
699
+ switch (button.code) {
700
+ case "row.delete":
701
+ $grid?.remove(row)
702
+ break;
703
+ case "crud.edit":
704
+ visibleEntityForm.value = true;
705
+ toolbarButtonParams.value = button.params || {};
706
+ if (!toolbarButtonParams.value["title"]) {
707
+ toolbarButtonParams.value["title"] = t("grid.toolbar.edit");
708
+ }
709
+ loading.value = true;
710
+ CrudHttp.detail(props.refid, { id: row.id }).then(res => {
711
+ if (res.meta.success) {
712
+ setTimeout(() => {
713
+ entityFormRef.value.setFormData({...res.data});
714
+ }, 10);
715
+ } else {
716
+ EleMessage.error(res.meta.message);
717
+ }
718
+ loading.value = false;
719
+ }).catch(e => {
720
+ loading.value = false;
721
+ });
722
+
723
+ break;
724
+ case "crud.view":
725
+ visibleEntityForm.value = true;
726
+ toolbarButtonParams.value = button.params || {};
727
+ if (!toolbarButtonParams.value["title"]) {
728
+ toolbarButtonParams.value["title"] = t("grid.toolbar.view");
729
+ }
730
+ toolbarButtonParams.value["readonly"] = true;
731
+ CrudHttp.detail(props.refid, { id: row.id }, (res) => {
732
+ if (res.meta.success) {
733
+ setTimeout(() => {
734
+ entityFormRef.value.setFormData(res.data);
735
+ }, 10);
736
+ } else {
737
+ EleMessage.error(res.meta.message);
738
+ }
739
+ });
740
+ break;
741
+ case "crud.delete" :
742
+ remove({ id: [row.id] });
743
+ break;
744
+ case "row.pre-delete":
745
+ $grid?.setPendingRow(row, true);
746
+ break;
747
+ case "workflow.submit":
748
+ submitWorkflow({ id: [row.id] });
749
+ break;
750
+ case "workflow.view" :
751
+ viewWorkflow(row.id);
752
+ break;
753
+ case "report.print" :
754
+ visibleReport.value = true;
755
+ currentRow.value = row;
756
+ loadReport();
757
+ break;
758
+ default:
759
+ break;
760
+ }
761
+ }
762
+ emit("operationButtonClick", { button, row, $grid });
763
+ };
764
+
765
+
766
+ /**
767
+ * 获取表格数据
768
+ */
769
+ const getTableData = () => {
770
+ return sohelpVxeGridRef.value?.getTableData();
771
+ };
772
+
773
+ /**
774
+ * 获取处理过的数据
775
+ */
776
+ const getData = () => {
777
+ const { tableData } = getTableData();
778
+ return tableData;
779
+ };
780
+
781
+ /**
782
+ * 更新
783
+ */
784
+ const updateValue = () => {
785
+ emit("update:modelValue", getData());
786
+ emit("change", getData());
787
+ };
788
+ /**
789
+ * 指定index位置插入数据
790
+ * @param data
791
+ * @param index
792
+ */
793
+ const insertField = (data, index = -1) => {
794
+ if (sohelpVxeGridRef.value) {
795
+ sohelpVxeGridRef.value.insertAt(data, index);
796
+ sohelpVxeGridRef.value.clearEdit();
797
+ }
798
+ updateValue();
799
+ };
800
+
801
+
802
+ /**
803
+ * 刷新列表
804
+ */
805
+ const refresh = () => {
806
+ //取消选中
807
+ selections.value = [];
808
+ sohelpVxeGridRef.value?.clearCheckboxRow();
809
+
810
+ if (!isPage.value) {
811
+ if (gridOptions.pagerConfig && gridOptions.pagerConfig.enabled) {
812
+ gridOptions.pagerConfig.currentPage = 1;
813
+ }
814
+ emit("refresh");
815
+ }
816
+ isPage.value = false;
817
+ reload({ ...gridOptions.params });
818
+ };
819
+
820
+ /**
821
+ * 列表头右键菜单事件
822
+ * @param column
823
+ */
824
+ const headerCellMenu = ({ column }) => {
825
+ if (column.editRender?.edit && gridOptions.menuConfig.header.options.length > 0) {
826
+ // 只对特定类型的列显示菜单项
827
+ const visible = column && (column.type === "SohelpSwitch" || column.type === "SohelpCheckbox");
828
+ // 设置每个菜单项的可见性
829
+ gridOptions.menuConfig.header.options[0].forEach(item => {
830
+ item.visible = visible;
831
+ });
832
+ }
833
+ };
834
+
835
+ /**
836
+ * 右键菜单点击事件
837
+ * @param menu 菜单项
838
+ * @param row 行数据
839
+ * @param column 列配置
840
+ * @param rowIndex 行索引
841
+ */
842
+ const menuRightClick = async ({ menu, row, column, rowIndex }) => {
843
+ const $grid = sohelpVxeGridRef.value;
844
+ if ($grid) {
845
+ $grid.setCurrentRow(row);
846
+ const { fullData } = $grid.getTableData();
847
+ switch (menu.code) {
848
+ case "insert":
849
+ await $grid.insertAt({ role_name: "sales user" }, rowIndex);
850
+ break;
851
+ case "all-select":
852
+ fullData.forEach(row => {
853
+ row[column.field] = ["0", 0, "1", 1].includes(row[column.field]) ? 1 : true;
854
+ });
855
+ break;
856
+ case "revert-select":
857
+ fullData.forEach(row => {
858
+ if (["0", 0, "1", 1].includes(row[column.field])) {
859
+ row[column.field] = 1 - row[column.field];
860
+ } else {
861
+ row[column.field] = !row[column.field];
862
+ }
863
+ });
864
+ break;
865
+ default:
866
+ break;
867
+ }
868
+ }
869
+
870
+ // 执行右击事件
871
+ emit("menuRightClick", { menu, row, column, rowIndex });
872
+ };
873
+
874
+ const sohelpSortRef = ref(null);
875
+ const closeSortDropCard = () => {
876
+ if (sohelpSortRef.value) {
877
+ sohelpSortRef.value.close();
878
+ }
879
+ };
880
+
881
+ /**
882
+ * 获取用户数据源
883
+ */
884
+ const userDatasource = computed(async () => {
885
+ return await SohelpHttp.get("/engine/web/user/list")
886
+ .then((res) => {
887
+ if (res.data) {
888
+ return [...res.data];
889
+ }
890
+ })
891
+ .catch((err) => {
892
+ EleMessage.error(err.message || "error");
893
+ });
894
+ });
895
+
896
+ /**
897
+ * SohelpTextareaInput 弹窗
898
+ */
899
+ const [textareaState, resetTextareaState, setTextareaState] = useFormData({
900
+ visible: false,
901
+ value: "",
902
+ row: null,
903
+ field: ""
904
+ });
905
+
906
+ /**
907
+ * 显示 SohelpTextareaInput 弹窗
908
+ */
909
+ const showTextareaModal = (column, field, row) => {
910
+ if (column?.editRender?.enabled) {
911
+ setTextareaState({
912
+ visible: true,
913
+ value: row[field],
914
+ row,
915
+ field
916
+ });
917
+ }
918
+ };
919
+
920
+ /**
921
+ * 取消 SohelpTextareaInput 弹窗
922
+ */
923
+ const textareaCancel = () => {
924
+ resetTextareaState();
925
+ };
926
+
927
+ /**
928
+ * checkbox复选框
929
+ */
930
+ const onCheckboxChange = (checked, type) => {
931
+ selections.value = sohelpVxeGridRef.value?.getCheckboxRecords() || [];
932
+ emit("checkbox-change", selections.value, checked, type);
933
+ };
934
+
935
+ /**
936
+ *
937
+ */
938
+ const radioChange = (config) => {
939
+ emit('radio-change', config)
940
+ }
941
+
942
+
943
+ /**
944
+ * 确定 SohelpTextareaInput 弹窗
945
+ */
946
+ const textareaConfirm = () => {
947
+ const $grid = sohelpVxeGridRef.value;
948
+ if ($grid) {
949
+ $grid.setRow(textareaState.row, {
950
+ ...textareaState.row,
951
+ [textareaState.field]: textareaState.value
952
+ });
953
+ }
954
+ textareaCancel();
955
+ };
956
+
957
+ /**
958
+ * 获取组织数据源
959
+ */
960
+ const orgDatasource = computed(async () => {
961
+ return await SohelpHttp.get("/engine/web/org/list")
962
+ .then((res) => {
963
+ if (res.data) {
964
+ return [...res.data];
965
+ }
966
+ })
967
+ .catch((err) => {
968
+ EleMessage.error(err.message || "error");
969
+ });
970
+ });
971
+ /**
972
+ * 根据引擎表格获取更新数据
973
+ * @returns {{inserted: {}, deleted: {}, updated: {}}}
974
+ */
975
+ const getCrudUpdater = () => {
976
+ const $grid = sohelpVxeGridRef.value;
977
+ const _delete = [...$grid?.getRemoveRecords()?.map(item => item.id),...$grid?.getPendingRecords()?.map(item => item.id)];
978
+ return {
979
+ "inserted": $grid?.getInsertRecords().map(item => {
980
+ return { ...item };
981
+ }) || [],
982
+ "updated": $grid?.getUpdateRecords(),
983
+ "deleted": _delete
984
+ };
985
+ };
986
+
987
+ /**
988
+ * 删除记录
989
+ */
990
+ const remove = (params) => {
991
+ ElMessageBox.confirm("确定要删除吗?", "提示").then(() => {
992
+ CrudHttp.delete(props.refid, params, (res) => {
993
+ if (res.meta.success) {
994
+ EleMessage.success(res.meta.message);
995
+ refresh();
996
+ } else {
997
+ EleMessage.error(res.meta.message);
998
+ }
999
+ });
1000
+ }).catch(() => {
1001
+ });
1002
+ };
1003
+
1004
+ /**
1005
+ *
1006
+ * @param handler
1007
+ */
1008
+ const executeToolbarCustomHandler = (button) => {
1009
+ const $grid = sohelpVxeGridRef.value;
1010
+ $grid.refresh = refresh;
1011
+ $grid.reload = reload;
1012
+ try {
1013
+ let isRows = button.buttonType === 'batch';
1014
+ (async () => {
1015
+ const context = {
1016
+ $message: EleMessage,
1017
+ $SohelpModule: window.$SohelpModule,
1018
+ $SohelpHttp: window.$SohelpHttp,
1019
+ $confirm: (title, callback) => {
1020
+ ElMessageBox.confirm(title, "提示", {
1021
+ confirmButtonText: "确定",
1022
+ cancelButtonText: "取消",
1023
+ type: "warning"
1024
+ }).then(() => {
1025
+ callback && callback();
1026
+ }).catch(() => {
1027
+ });
1028
+ },
1029
+ $grid: $grid,
1030
+ getCrudUpdater: getCrudUpdater
1031
+ };
1032
+ $grid.refresh = refresh;
1033
+ await safeFunctionExec(button.handler, [isRows ? "rows" : "row", "$grid"], [isRows ? selections.value : current, $grid], context);
1034
+ })();
1035
+ } catch (e) {
1036
+ EleMessage.error(`${e.message}`);
1037
+ }
1038
+ };
1039
+ /**
1040
+ * 工具栏点击事件
1041
+ * @param param0
1042
+ */
1043
+ const toolbarClick = async ({ button }) => {
1044
+ const $grid = sohelpVxeGridRef.value;
1045
+ let rowIndex = -1;
1046
+ const row = {};
1047
+
1048
+ const current = $grid?.getCurrentRecord();
1049
+ if (current) {
1050
+ rowIndex = $grid?.getVTRowIndex(current);
1051
+ }
1052
+
1053
+ //工具栏事件执行
1054
+ if (button?.handler) {
1055
+ executeToolbarCustomHandler(button);
1056
+ } else if (button.refid) {
1057
+ if (button.openType === "tab") {
1058
+ window.$SohelpModule.openTab(button.refid, {}, button.params || {});
1059
+ } else if (button.openType === "drawer") {
1060
+ window.$SohelpModule.openDrawer(button.refid, {}, button.params || {});
1061
+ } else {
1062
+ window.$SohelpModule.openModal(button.refid, {}, button.params || {});
1063
+ }
1064
+ } else {
1065
+ switch (button.code) {
1066
+ case "row.add":
1067
+ insertField(row, -1);
1068
+ break;
1069
+ case "row.copy":
1070
+ if (current) {
1071
+ Object.assign(row, { ...current });
1072
+ if (row?.name) {
1073
+ row.name = "";
1074
+ }
1075
+ delete row._X_ROW_KEY;
1076
+ }
1077
+ break;
1078
+ case "row.insert":
1079
+ rowIndex = getData()?.length > 0 ? rowIndex : -1;
1080
+ insertField(row, rowIndex);
1081
+ break;
1082
+ case "row.delete":
1083
+ $grid.removeCheckboxRow();
1084
+ break;
1085
+ case "crud.create":
1086
+ visibleEntityForm.value = true;
1087
+ toolbarButtonParams.value = button.params || {};
1088
+ if (!toolbarButtonParams.value["title"]) {
1089
+ toolbarButtonParams.value["title"] = t("grid.toolbar.create");
1090
+ }
1091
+
1092
+ const {title, ...params} = button.params;
1093
+
1094
+ CrudHttp.initial(props.refid, { id: row.id }, (res) => {
1095
+ if (res.meta.success) {
1096
+ setTimeout(() => {
1097
+ entityFormRef.value.setFormData({...res.data}, params);
1098
+ }, 10);
1099
+ } else {
1100
+ EleMessage.error(res.meta.message);
1101
+ }
1102
+ });
1103
+ break;
1104
+ case "crud.save":
1105
+ CrudHttp.save(props.refid, { "default": getCrudUpdater() }, (res) => {
1106
+ if (res.meta.success) {
1107
+ EleMessage.success(res.meta.message);
1108
+ refresh();
1109
+ } else {
1110
+ EleMessage.error(res.meta.message);
1111
+ }
1112
+ });
1113
+ break;
1114
+ case "crud.view":
1115
+ break;
1116
+ case "crud.delete":
1117
+ remove({ id: selections.value.map(item => item.id) });
1118
+ break;
1119
+ case "workflow.submit":
1120
+ submitWorkflow({ id: selections.value.map(item => item.id) });
1121
+ break;
1122
+ case "report.print":
1123
+ break;
1124
+ case "batch.import":
1125
+ break;
1126
+ case "batch.delete":
1127
+ break;
1128
+ case "batch.export":
1129
+ break;
1130
+ case "batch.print":
1131
+ break;
1132
+ default:
1133
+ break;
1134
+ }
1135
+
1136
+ }
1137
+ };
1138
+
1139
+ /**
1140
+ * grid事件
1141
+ * 排序
1142
+ */
1143
+ const gridEvents = {
1144
+ sortChange({ field = "", order = "" }) {
1145
+ if (!order) {
1146
+ field = order = "";
1147
+ }
1148
+ sortValue.value = field + "!" + order;
1149
+ filterValue.value.sort = field;
1150
+ filterValue.value.order = order;
1151
+ filter({});
1152
+ },
1153
+
1154
+ toolbarButtonClick(config) {
1155
+ toolbarClick(config);
1156
+ emit("toolbarButtonClick", config, selections.value);
1157
+ },
1158
+ };
1159
+
1160
+ /**
1161
+ * 查询
1162
+ * param type:'filter' | 'column', default(filter) 区分是高级筛选,还是列筛选
1163
+ */
1164
+ const filter = (param = {}) => {
1165
+ gridOptions.pagerConfig.currentPage = 1;
1166
+ reload();
1167
+ };
1168
+
1169
+
1170
+ /**
1171
+ * 重置
1172
+ */
1173
+ const resetFilter = () => {
1174
+ filterValue.value = JSON.parse(originFilterValue.value);
1175
+ //重置列筛选
1176
+ if (sohelpVxeGridRef.value) {
1177
+ sohelpVxeGridRef.value.clearFilter();
1178
+ }
1179
+ filter();
1180
+ };
1181
+
1182
+ /**
1183
+ * 筛选弹窗
1184
+ */
1185
+ const showFilter = () => {
1186
+ if (sohelpConfig.value.filter?.config.filterPosition === "NONE") {
1187
+ sohelpConfig.value.filter.config.filterPosition = "TOP";
1188
+ sohelpConfig.value.filter.config.visibleFilter = false;
1189
+ }
1190
+ emit("showFilter", sohelpConfig.value.filter.config.filterPosition);
1191
+ };
1192
+
1193
+
1194
+ /**
1195
+ * 打开提交工作流界面
1196
+ */
1197
+ const submitWorkflow = (ids) => {
1198
+ approvalData.value = {
1199
+ refid: props.refid,
1200
+ ...ids
1201
+ };
1202
+ approvalModalVisible.value = true;
1203
+ };
1204
+
1205
+ /**
1206
+ * 查看工作流
1207
+ * @param row
1208
+ */
1209
+ const viewWorkflow = (id) => {
1210
+ drawerData.value = {
1211
+ id: id,
1212
+ refid: props.refid
1213
+ };
1214
+ drawerVisible.value = true;
1215
+ };
1216
+
1217
+ /**
1218
+ * 筛选
1219
+ */
1220
+ const changeNameFilter = (option, val, column) => {
1221
+ const $grid = sohelpVxeGridRef.value;
1222
+ if ($grid) {
1223
+ $grid.setFilter(column.field, [{
1224
+ data: val?.value || "",
1225
+ value: val.value || "",
1226
+ checked: true
1227
+ }]);
1228
+ $grid.updateFilterOptionStatus(option, true);
1229
+ }
1230
+ };
1231
+
1232
+ const filterVisible = ({ column, field, visible }) => {
1233
+ if (visible) {
1234
+ const hasField = filterValue.value.filter?.find(f => f.name === field);
1235
+ if (!hasField) {
1236
+ filterValue.value.filter = [...filterValue.value.filter, {
1237
+ comparison: "LIKE",
1238
+ name: field,
1239
+ value: ""
1240
+ }];
1241
+ }
1242
+ const $grid = sohelpVxeGridRef.value;
1243
+ if ($grid) {
1244
+ $grid.setFilter(field, [{
1245
+ data: "",
1246
+ value: "",
1247
+ checked: true
1248
+ }]);
1249
+ }
1250
+
1251
+ }
1252
+ };
1253
+
1254
+ /**
1255
+ *列筛选
1256
+ */
1257
+ const handleFilterChange = ({ field, datas }) => {
1258
+ filter();
1259
+ //重置功能 重置要清空filterValue.filter对象的项
1260
+ if (!datas?.length) {
1261
+ const map = new Map(filterValue.value.filter?.map(item => [item.name, item]));
1262
+ if (map.get(field)) {
1263
+ map.get(field).value = "";
1264
+ }
1265
+ }
1266
+ };
1267
+
1268
+ /**
1269
+ * 过滤掉对象中_开头的属性 _sqe、_checkbox、_operation
1270
+ * @param obj
1271
+ */
1272
+ const filterUnderscoreProps = (obj = {}) => {
1273
+ if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
1274
+ return {};
1275
+ }
1276
+ return Object.entries(obj).reduce((acc, [key, value]) => {
1277
+ const filterKey = ["_checkbox", "_seq"];
1278
+ if (!filterKey.includes(key)) {
1279
+ acc[key] = typeof value === "object" ? filterUnderscoreProps(value) : value;
1280
+ }
1281
+ return acc;
1282
+ }, {});
1283
+ };
1284
+
1285
+
1286
+ /**
1287
+ * 根据 obj 对象的值修改 properties 数组中对应项的指定属性
1288
+ * @param {Object} obj
1289
+ * @param {Array} properties
1290
+ * @param {string} key
1291
+ */
1292
+ const updateProperties = (obj, properties, key, propertiesMap) => {
1293
+ if (!obj || Object.keys(obj).length === 0) return;
1294
+ const map = propertiesMap || new Map(properties.map((item, index) => [item.name, index]));
1295
+ Object.entries(obj).forEach(([name, value]) => {
1296
+ const index = map.get(name);
1297
+ if (index !== undefined && properties[index]) {
1298
+ properties[index][key] = value;
1299
+ //fixed
1300
+ if (key === "lockAlign") {
1301
+ properties[index]["lock"] = value ? true : false;
1302
+ }
1303
+ }
1304
+ });
1305
+ };
1306
+
1307
+
1308
+ /**
1309
+ * 属性根据sortData排序
1310
+ * @param {Array} properties
1311
+ * @param {Object} sortData
1312
+ */
1313
+ const sortPropertiesInPlace = (properties, sortData) => {
1314
+ const sortOrder = {};
1315
+ Object.entries(sortData || {})
1316
+ .sort((a, b) => a[1] - b[1])
1317
+ .forEach(([key], index) => {
1318
+ sortOrder[key] = index;
1319
+ });
1320
+
1321
+ properties.sort((a, b) => {
1322
+ const aOrder = sortOrder[a.name];
1323
+ const bOrder = sortOrder[b.name];
1324
+
1325
+ if (aOrder !== undefined && bOrder !== undefined) {
1326
+ return aOrder - bOrder;
1327
+ }
1328
+ if (aOrder !== undefined) return -1;
1329
+ if (bOrder !== undefined) return 1;
1330
+ return 0;
1331
+ });
1332
+ };
1333
+
1334
+ /**
1335
+ * 列设置操作
1336
+ */
1337
+ const handleCustom = async ({ type, $grid }) => {
1338
+ // 恢复默认
1339
+ if (type === "reset") {
1340
+ const loading = EleMessage.loading("恢复默认中..");
1341
+ const message = await resetCommonConfig({ refid: props.refid }).catch(err => {
1342
+ EleMessage.error(err.message);
1343
+ loading.close();
1344
+ });
1345
+ if (message) {
1346
+ EleMessage.success(message);
1347
+ }
1348
+ loading.close();
1349
+ }
1350
+
1351
+ //确认
1352
+ if (type === "confirm") {
1353
+ //获取当前列配置
1354
+ const { sortData, ...columnsData } = filterUnderscoreProps($grid?.getCustomStoreData());
1355
+
1356
+ const properties = JSON.parse(JSON.stringify([...sohelpConfig.value.properties])).map(item => {
1357
+ return {
1358
+ ...item,
1359
+ list: sohelpConfig.value.list.includes(item.name)
1360
+ };
1361
+ });
1362
+
1363
+ const propertiesMap = new Map(properties.map((item, index) => [item.name, index]));
1364
+
1365
+
1366
+ //修改对应的field
1367
+ const fieldMapping = {
1368
+ fixedData: "lockAlign",
1369
+ resizableData: "width",
1370
+ visibleData: "list"
1371
+ };
1372
+ // 修改属性
1373
+ Object.entries(columnsData).forEach(([key, value]) => {
1374
+ updateProperties(value, properties, fieldMapping[key], propertiesMap);
1375
+ });
1376
+ //根据sortData排序
1377
+ sortPropertiesInPlace(properties, sortData);
1378
+ const loading = EleMessage.loading("保存配置中..");
1379
+
1380
+ const message = await updateCommonConfig({
1381
+ refid: props.refid,
1382
+ properties: properties.map(item => {
1383
+ return {
1384
+ name: item.name,
1385
+ width: item.width,
1386
+ list: item.list,
1387
+ lockAlign: item.lockAlign,
1388
+ lock: item.lock
1389
+ };
1390
+ })
1391
+ }).catch(err => {
1392
+ EleMessage.error(err.message);
1393
+ loading.close();
1394
+ });
1395
+ if (message) {
1396
+ EleMessage.success(message);
1397
+ }
1398
+
1399
+ //清除缓存
1400
+ moduleCache?.clear();
1401
+ loadConfig();
1402
+
1403
+ localStorage.setItem("VXE_CUSTOM_STORE", "");
1404
+ loading.close();
1405
+ }
1406
+ };
1407
+
1408
+
1409
+ /**
1410
+ * 更新columns过滤状态
1411
+ */
1412
+ const updateColumnsFilter = () => {
1413
+ const $grid = sohelpVxeGridRef.value;
1414
+ if ($grid && filterValue.value.filter?.length) {
1415
+ filterValue.value.filter?.forEach((item) => {
1416
+ $grid.setFilter(item.name, [
1417
+ {
1418
+ checked: item.value?.length > 0
1419
+ }
1420
+ ]);
1421
+ });
1422
+ }
1423
+ };
1424
+
1425
+
1426
+ /**
1427
+ * 计算公式
1428
+ * @param row
1429
+ * @param column
1430
+ */
1431
+ const editClosed = (props) => {
1432
+ const { row, column } = props;
1433
+ Object.entries(formulaMap).forEach(([key, value]) => {
1434
+ try {
1435
+ const formulaValue = formulaMap[key]["formulaValue"];
1436
+ if (formulaValue.indexOf(column.field) > 0) {
1437
+ const str = formulaValue.replace(/\s+/g, "")
1438
+ .replace(/\${/g, "row.")
1439
+ .replace(/}/g, "");
1440
+ const v = safeEval(str, { row });
1441
+ if (!Number.isNaN(v)) {
1442
+ row[key] = v;
1443
+ }
1444
+ }
1445
+ } catch (e) {
1446
+ console.error("计算公式错误:", e);
1447
+ EleMessage.error("计算公式错误:" + e.message);
1448
+ }
1449
+ nextTick(() => {
1450
+ if (row[column.property] && row[column.property].toString().trim() !== "") {
1451
+ sohelpVxeGridRef.value?.clearValidate([column.property]);
1452
+ }
1453
+ });
1454
+ });
1455
+ emit("editClosed", props);
1456
+ };
1457
+
1458
+ const validate = async () => {
1459
+ const $grid = sohelpVxeGridRef.value;
1460
+ if ($grid) {
1461
+ const errMap = await $grid.fullValidate(true);
1462
+ return errMap || false;
1463
+ }
1464
+ };
1465
+
1466
+ const currentColumnChange = (props) => {
1467
+ emit("currentColumnChange", props);
1468
+ };
1469
+
1470
+ const columnCheckbox = ref(false);
1471
+ const toggleAllEvent = () => {
1472
+ const $grid = sohelpVxeGridRef.value
1473
+ if ($grid) {
1474
+ $grid.toggleCustomAllCheckbox()
1475
+ }
1476
+ }
1477
+
1478
+ const settingClick = (command) => {
1479
+ const baseUrl = SohelpHttp.getBaseUrl();
1480
+ const { refid,extendEntity,name } = sohelpConfig.value;
1481
+ if(refid && name){
1482
+ const url = {
1483
+ form: baseUrl + `/dev/index.html#/dev/form?datasource=default&name=${extendEntity}&refid=${refid}`,
1484
+ entity: baseUrl + `/dev/index.html#/dev/module/entity?datasource=default&name=${extendEntity}`,
1485
+ workflow: baseUrl + `/dev/index.html#/dev/form?datasource=default&name=${extendEntity}&refid=${refid}&tab=workflow`,
1486
+ grid: baseUrl + `/dev/index.html#/dev/module/grid?refid=${refid}`,
1487
+ module: baseUrl+`/dev/index.html#/dev/module?name=${refid}`,
1488
+ }
1489
+ if(command === 'module' && !extendEntity){
1490
+ url.module = baseUrl+`/dev/index.html#/dev/module?name=${name}`;
1491
+ }
1492
+ window.open(url[command],'_blank');
1493
+ }
1494
+ }
1495
+ /**
1496
+ * 设置复选框行键
1497
+ * @param row 行数据
1498
+ * @param checked 是否选中
1499
+ */
1500
+ const setCheckboxRowKey = (row, checked) => {
1501
+ nextTick(() => {
1502
+ sohelpVxeGridRef.value?.setCheckboxRowKey(row, checked);
1503
+ })
1504
+ }
1505
+
1506
+
1507
+ const setRadioRowKey = (key, checked) => {
1508
+ nextTick(() => {
1509
+ sohelpVxeGridRef.value?.setRadioRowKey(key, checked);
1510
+ })
1511
+ }
1512
+
1513
+ /**
1514
+ * 获取选中的记录
1515
+ */
1516
+ const getCheckboxRecords = () => {
1517
+ return sohelpVxeGridRef.value?.getCheckboxRecords();
1518
+ };
1519
+ /**
1520
+ * 获取保留的记录
1521
+ */
1522
+ const getCheckboxReserveRecords = (isFull = false) => {
1523
+ return sohelpVxeGridRef.value?.getCheckboxReserveRecords(isFull);
1524
+ }
1525
+
1526
+
1527
+
1528
+
1529
+ /**
1530
+ * 监听是否被选中,更新工具栏批量操作
1531
+ */
1532
+ watch(
1533
+ () => selections.value,
1534
+ (val) => {
1535
+ const isDisabled = val.length < 1;
1536
+ if (batchButtonsIndex.value?.length > 0) {
1537
+ batchButtonsIndex.value.forEach(idx => {
1538
+ gridOptions.toolbarConfig.buttons[idx].disabled = isDisabled;
1539
+ });
1540
+ }
1541
+ }
1542
+ );
1543
+
1544
+ watch(
1545
+ () => props.refid, (refid) => {
1546
+ //加载列表配置
1547
+ loadConfig();
1548
+ }, {
1549
+ immediate: true
1550
+ });
1551
+
1552
+
1553
+
1554
+ defineExpose({
1555
+ getData,
1556
+ getCrudUpdater,
1557
+ resetFilter,
1558
+ refresh,
1559
+ loadConfig,
1560
+ reload,
1561
+ load,
1562
+ validate,
1563
+ setCheckboxRowKey,
1564
+ getCheckboxRecords,
1565
+ getCheckboxReserveRecords,
1566
+ setRadioRowKey,
1567
+ selections
1568
+ });
1569
+ </script>
1570
+
1571
+ <template>
1572
+ <vxe-grid
1573
+ v-bind="gridOptions"
1574
+ ref="sohelpVxeGridRef"
1575
+ @menuClick="menuRightClick"
1576
+
1577
+ @checkboxChange="({checked}) => onCheckboxChange(checked,'row')"
1578
+ @checkboxAll="({checked}) => onCheckboxChange(checked,'all')"
1579
+ @radioChange="radioChange"
1580
+
1581
+ class="sohelp-grid-view"
1582
+ :id="getId()"
1583
+ v-on="gridEvents"
1584
+ @filter-change="handleFilterChange"
1585
+ @custom="handleCustom"
1586
+ @cellClick="cellClick"
1587
+ @editClosed="editClosed"
1588
+ @header-cell-menu="headerCellMenu"
1589
+ :key="sohelpConfig?.uuid || getId()"
1590
+ :keep-source="true"
1591
+ @currentColumnChange="currentColumnChange"
1592
+ @filter-visible="filterVisible"
1593
+ >
1594
+
1595
+ <!-- 自定义列设置 -->
1596
+ <template #setting>
1597
+ <div class="column-setting">
1598
+ <vxe-checkbox @change="toggleAllEvent" v-model="columnCheckbox">全选</vxe-checkbox>
1599
+ <vxe-pulldown trigger="click" :transfer="true" :show-popup-shadow="true" v-if="userStore.info.is_developer">
1600
+ <template #default>
1601
+ <el-link :icon="Setting" :underline="false"/>
1602
+ </template>
1603
+ <template #dropdown>
1604
+ <ele-card shadow="always">
1605
+ <el-space direction="vertical" :size="5" alignment="flex-start">
1606
+ <el-link :title="sohelpConfig?.refid" :icon="Memo" @click="settingClick('grid')" :underline="false" style="font-size:12px;"><span style="padding:0 5px;">列表配置</span></el-link>
1607
+ <el-link :title="sohelpConfig?.extendEntity" :icon="Menu" @click="settingClick('entity')" :underline="false" style="font-size: 12px;" v-if="sohelpConfig.extendEntity"><span style="padding:0 5px;">实体配置</span></el-link>
1608
+ <el-link :title="sohelpConfig?.refid" :icon="Grid" @click="settingClick('module')" :underline="false" style="font-size: 12px;"><span style="padding:0 5px;">模块配置</span></el-link>
1609
+ </el-space>
1610
+ </ele-card>
1611
+ </template>
1612
+ </vxe-pulldown>
1613
+ </div>
1614
+ </template>
1615
+
1616
+ <!--定义国际化I18n-->
1617
+ <template
1618
+ v-for="item in sohelpConfig?.properties?.map(item => item)"
1619
+ #[`header_${item.name}`]="{ column, rowIndex }"
1620
+ :key="item.name"
1621
+ >
1622
+ {{ item.i18n ? t(item.i18n) : item.label }}
1623
+ </template>
1624
+
1625
+ <!--自定义定义分页--->
1626
+ <template #pager>
1627
+ <vxe-pager
1628
+ v-if="gridOptions.pagerConfig.enabled"
1629
+ v-model:currentPage="gridOptions.pagerConfig.currentPage"
1630
+ v-model:pageSize="gridOptions.pagerConfig.pageSize"
1631
+ :total="gridOptions.pagerConfig.total"
1632
+ @page-change="pageChangeEvent"/>
1633
+ </template>
1634
+
1635
+ <!-- 高级筛选 -->
1636
+ <template
1637
+ v-for="field in propertiesMap ? Object.values(propertiesMap)?.filter(item => item.query) : []" :key="field?.name"
1638
+ #[`filter_${field?.name}`]="{ column }">
1639
+ <div v-for="(option, index) in column.filters" :key="index" class="condition-box">
1640
+ <filter-condition-item
1641
+ :key="field.name"
1642
+ v-model="getCurrentFilter(field.name).value"
1643
+ :properties="propertiesMap[field.name]"
1644
+ :teleported="false"
1645
+ />
1646
+ </div>
1647
+ </template>
1648
+
1649
+ <!-- 工具栏 -->
1650
+ <template #toolbarTools>
1651
+ <div class="toolbar-box">
1652
+ <!-- 查看范围 -->
1653
+ <div class="power-box">
1654
+ <sohelp-power @change="changePower" v-if="sohelpConfig?.filter?.config?.visibleDataRange"/>
1655
+ </div>
1656
+
1657
+ <div class="search-box" v-if="sohelpConfig?.filter?.config?.visibleKeywords && sohelpConfig?.filter?.keywords.length>0 ">
1658
+ <!-- 关键字 -->
1659
+ <ele-tooltip :content="getKeywordsPlaceholder" placement="top" :offset="3">
1660
+ <sohelp-input
1661
+ :model-value="filterValue.keywords" @update:model-value="keywordsChange"
1662
+ :placeholder="getKeywordsPlaceholder" clearable
1663
+ @keyup.enter="filter" size="small" style="width: 160px;">
1664
+ <template #append>
1665
+ <el-button :icon="Search" @click="filter" size="small" />
1666
+ </template>
1667
+ </sohelp-input>
1668
+ </ele-tooltip>
1669
+ <el-button size="small" :icon="Refresh" @click="resetFilter">{{ t("grid.toolbar.reset") }}</el-button>
1670
+ </div>
1671
+
1672
+ <div class="tools-btns">
1673
+ <sohelp-drop-card
1674
+ :title="t('grid.toolbar.sort')" :icon="Sort" ref="sohelpSortRef"
1675
+ v-if="sohelpConfig?.filter?.config?.visibleSort && sortList.length > 0">
1676
+ <div class="sort-list">
1677
+ <ele-card
1678
+ v-for="item in sortList" :key="item.title" :header="item.title"
1679
+ :bodyStyle="{padding: '0'}"
1680
+ :headerStyle="{fontSize: '14px', fontWeight: 'normal', padding: '5px 0'}">
1681
+ <template #extra>
1682
+ <ele-text
1683
+ :icon="SortUp" style="cursor: pointer;" :underline="false" size="sm"
1684
+ @click="sortCommand(item.field,'asc')" plain :type="isActiveSort(item.field,'asc')">
1685
+ {{ t("grid.toolbar.asc") }}
1686
+ </ele-text>
1687
+ <ele-text
1688
+ :icon="SortDown" style="cursor: pointer;margin-left:5px!important" :underline="false"
1689
+ size="sm" @click="sortCommand(item.field,'desc')" plain
1690
+ :type="isActiveSort(item.field,'desc')">{{t("grid.toolbar.desc")}}
1691
+ </ele-text>
1692
+ </template>
1693
+ </ele-card>
1694
+ </div>
1695
+ </sohelp-drop-card>
1696
+ <el-button :icon="Filter" size="small"
1697
+ @click="showFilter()"
1698
+ plain
1699
+ :type="(sohelpConfig?.filter?.config?.visibleFilter && sohelpConfig?.filter?.config?.filterPosition !== 'NONE')?'primary':''"
1700
+ v-if="sohelpConfig?.filter?.config?._visibleFilter"/>
1701
+ <ele-tooltip v-if="importAuthority" :content="'批量导入数据'" placement="top" :offset="3">
1702
+ <el-button size="small" plain :icon="ElementPlusIcons.Upload" @click="openImport" />
1703
+ </ele-tooltip>
1704
+ <ele-tooltip v-if="exportAuthority" :content="'批量导出数据'" placement="top" :offset="3">
1705
+ <el-dropdown @command="exportData">
1706
+ <el-button size="small" plain :icon="ElementPlusIcons.Download"/>
1707
+ <template #dropdown>
1708
+ <el-dropdown-menu>
1709
+ <el-dropdown-item :command="0" :disabled="!selections || selections.length === 0">
1710
+ <el-icon><Memo /></el-icon>
1711
+ <span style="margin-left:6px;">导出选中数据</span>
1712
+ </el-dropdown-item>
1713
+ <el-dropdown-item :command="1">
1714
+ <el-icon><Files /></el-icon>
1715
+ <span style="margin-left:6px;">当前页数据</span>
1716
+ </el-dropdown-item>
1717
+ <el-dropdown-item :command="2">
1718
+ <el-icon><Grid /></el-icon>
1719
+ <span style="margin-left:6px;">全部记录数据</span>
1720
+ </el-dropdown-item>
1721
+ </el-dropdown-menu>
1722
+ </template>
1723
+ </el-dropdown>
1724
+ </ele-tooltip>
1725
+ </div>
1726
+ </div>
1727
+ </template>
1728
+
1729
+
1730
+ <!-- 未编辑状态 -->
1731
+ <template
1732
+ v-for="name in sohelpConfig?.properties?.map(item => item.name)"
1733
+ #[`default_${name}`]="{ row, column, rowIndex }"
1734
+ :key="name"
1735
+ >
1736
+ <div style=" display: flex; justify-content: right;" :style="{ justifyContent: getAlign(propertiesMap[name].align)}">
1737
+
1738
+ <!-- 字典 -->
1739
+ <sohelp-dict
1740
+ type="text"
1741
+ v-model="row[name]"
1742
+ v-if="column.type === 'SohelpDict'"
1743
+ v-bind="column.editRender"
1744
+ />
1745
+ <!-- 图片 -->
1746
+ <sohelp-image-upload
1747
+ v-else-if="column.type === 'SohelpImageUpload'"
1748
+ v-model="row[name]"
1749
+ v-bind="column.editRender"
1750
+ :data="getCellValue(rowIndex,name)"
1751
+ :readonly="!column.editRender.edit"
1752
+ />
1753
+ <!-- 附件 -->
1754
+ <sohelp-file-upload
1755
+ v-else-if="column.type === 'SohelpFileUpload'"
1756
+ v-model="row[name]"
1757
+ v-bind="column.editRender"
1758
+ :data="getCellValue(rowIndex,name)"
1759
+ :readonly="!column.editRender.edit"
1760
+ />
1761
+
1762
+ <!-- 下拉选择表格 -->
1763
+ <div v-else-if="column.type === 'SohelpTableSelect' || column.type === 'ORG' || column.type ==='USER'">
1764
+ <span>{{ getTableSelectLabel(row[name], rowIndex, name, column) }}</span>
1765
+ </div>
1766
+
1767
+ <!-- 评分 -->
1768
+ <sohelp-rate
1769
+ v-else-if="column.type==='SohelpRate'"
1770
+ v-model="row[name]"
1771
+ v-bind="column.editRender"
1772
+ :disabled="!column.editRender.edit"
1773
+ show-score
1774
+ score-template="{value} 分"
1775
+ style="min-width: 150px"
1776
+ />
1777
+
1778
+ <!-- 进度 -->
1779
+ <sohelp-process
1780
+ v-else-if="column.type==='SohelpProcess'"
1781
+ v-model="row[name]"
1782
+ v-bind="column.editRender"
1783
+ style="width: 100%"
1784
+ :readonly="!column.editRender.edit"
1785
+ />
1786
+
1787
+
1788
+ <!-- 下拉用户选择 -->
1789
+ <div v-else-if="column.type === 'SohelpUserSelect'">
1790
+ {{ gridData[rowIndex][name]?.["user_name"] }}
1791
+ </div>
1792
+
1793
+ <!-- 下拉组织选择 -->
1794
+ <div v-else-if="column.type === 'SohelpOrgTreeSelect'">
1795
+ {{ gridData[rowIndex][name]?.["org_name"] }}
1796
+ </div>
1797
+
1798
+ <!-- 开关 -->
1799
+ <div v-else-if="column.type==='SohelpSwitch' || column.type === 'SohelpCheckbox'">
1800
+ <span v-if="!column.editRender.edit">
1801
+ {{ !!row[name] ? "V" : "" }}
1802
+ </span>
1803
+ <sohelp-switch
1804
+ v-model="row[name]"
1805
+ v-bind="column.editRender"
1806
+ style="width: 100%;"
1807
+ v-else
1808
+ :activeValue="1"
1809
+ :inactiveValue="0"
1810
+ />
1811
+ </div>
1812
+
1813
+ <!-- 文本域 -->
1814
+ <p
1815
+ style="margin: 0;"
1816
+ class="textarea-reference"
1817
+ @click="showTextareaModal(column, name, row)"
1818
+ v-bind="column.editRender"
1819
+ v-else-if="column.type === 'SohelpTextarea'"
1820
+ >{{ row[name] }}
1821
+ </p>
1822
+
1823
+ <!-- 外键关联 -->
1824
+ <div v-else-if="column.type === 'RELATION' || column.type === 'SohelpTableSelect'">
1825
+ {{ gridData[rowIndex][name]?.[column?.editRender?.labelField] || "" }}
1826
+ </div>
1827
+
1828
+ <!-- 富文本 -->
1829
+ <div v-else-if="column.type === 'SohelpRichText'" v-html="sanitizeHtml(row[name])"></div>
1830
+
1831
+ <div v-else>
1832
+ {{ row[name] }}
1833
+ </div>
1834
+ </div>
1835
+ </template>
1836
+
1837
+ <!-- 可编辑状态 -->
1838
+ <template
1839
+ v-for="name in sohelpConfig?.properties?.map(item => item.name)"
1840
+ #[`edit_${name}`]="{ row, column, rowIndex }"
1841
+ :key="name"
1842
+ >
1843
+ <div v-if="column.editRender.enabled">
1844
+ <!-- 字典 -->
1845
+ <sohelp-dict
1846
+ v-model="row[name]"
1847
+ :code="column.dict"
1848
+ v-if="column.type === 'SohelpDict'"
1849
+ v-bind="column.editRender"
1850
+ style="width: 100%;"
1851
+ :visible="true"
1852
+ />
1853
+
1854
+
1855
+ <!-- 下拉用户选择 -->
1856
+ <sohelp-number-input
1857
+ v-model="row[name]"
1858
+ v-else-if="column.type==='SohelpInputNumber'"
1859
+ v-bind="column.editRender"
1860
+ style="width: 100%;"
1861
+ />
1862
+
1863
+ <!-- 日期、日期时间 -->
1864
+ <sohelp-datetime
1865
+ v-model="row[name]"
1866
+ v-else-if="column.type==='SohelpDatetime' || column.type==='SohelpDate'"
1867
+ v-bind="column.editRender"
1868
+ style="width: 100%;"
1869
+ :focus="true"
1870
+ />
1871
+
1872
+ <!-- 下拉用户选择 -->
1873
+ <sohelp-user-select
1874
+ v-else-if="column.type==='SohelpUserSelect'"
1875
+ v-model="row[name]"
1876
+ v-bind="column.editRender"
1877
+ :datasource="userDatasource"
1878
+ />
1879
+
1880
+ <!-- 下拉组织机构 -->
1881
+ <sohelp-org-tree-select
1882
+ v-else-if="column.type==='SohelpOrgTreeSelect'"
1883
+ v-model="row[name]"
1884
+ v-bind="column.editRender"
1885
+ :datasource="orgDatasource"
1886
+ />
1887
+
1888
+ <!-- 外键关联 -->
1889
+ <sohelp-table-select v-else-if="column.type==='SohelpTableSelect'"
1890
+ v-model="row[name]"
1891
+ v-model:data="gridData[rowIndex][name]"
1892
+ v-bind="column.editRender"
1893
+ />
1894
+
1895
+ <!-- 数值 -->
1896
+ <sohelp-number-input
1897
+ v-model="row[name]"
1898
+ v-else-if="column.type==='SohelpNumberInput'"
1899
+ v-bind="column.editRender"
1900
+ style="width: 100%;"
1901
+ :autoFocus="true"
1902
+ />
1903
+
1904
+ <!-- 其他 -->
1905
+ <sohelp-input
1906
+ v-model="row[name]"
1907
+ v-bind="column.editRender"
1908
+ :autoFocus="true"
1909
+ v-else
1910
+ style="width: 100%;"
1911
+ :show-word-limit="false"
1912
+ />
1913
+ </div>
1914
+ </template>
1915
+
1916
+ <!-- 操作栏 -->
1917
+ <template #_operation="{ row, column }">
1918
+ <el-space :size="10">
1919
+ <el-link
1920
+ v-for="(item) in getOperationButtonsByType(row, column)"
1921
+ :key="item.code"
1922
+ :type="item.code === 'crud.delete' ? 'danger' : 'primary'"
1923
+ v-bind="item.params"
1924
+ @click="operationHandler({button:item, row:row,$grid:sohelpVxeGridRef})"
1925
+ >
1926
+ <el-icon v-if="item.icon" style="margin-right: 5px;">
1927
+ <component :is="ElementPlusIcons[item.icon]" v-if="ElementPlusIcons[item.icon]" />
1928
+ <component :is="EleAdminPlusIcons[item.icon]" v-else-if="EleAdminPlusIcons[item.icon]" />
1929
+ <span :class="item.icon" v-else></span>
1930
+ </el-icon>
1931
+ {{ item.title }}
1932
+ </el-link>
1933
+ <!-- 更多 -->
1934
+ <el-dropdown v-if="getOperationButtonsByType(row, column,'more')?.length > 0">
1935
+ <el-link :underline="false">
1936
+ <span>更多</span>
1937
+ <el-icon style="margin-left: 4px;">
1938
+ <arrow-down />
1939
+ </el-icon>
1940
+ </el-link>
1941
+ <template #dropdown>
1942
+ <el-dropdown-menu>
1943
+ <el-dropdown-item
1944
+ v-for="item in getOperationButtonsByType(row, column, 'more')" :key="item.code"
1945
+ @click.stop="operationHandler({button:item, row:row,$grid:sohelpVxeGridRef})"
1946
+ v-bind="item.props">
1947
+ <el-icon v-if="item.icon">
1948
+ <component :is="ElementPlusIcons[item.icon]" v-if="ElementPlusIcons[item.icon]" />
1949
+ <component :is="EleAdminPlusIcons[item.icon]" v-else-if="EleAdminPlusIcons[item.icon]" />
1950
+ <span :class="item.icon" v-else></span>
1951
+ </el-icon>
1952
+ {{ item.title }}
1953
+ </el-dropdown-item>
1954
+ </el-dropdown-menu>
1955
+ </template>
1956
+ </el-dropdown>
1957
+ <slot name="_operation" :row="row"></slot>
1958
+ </el-space>
1959
+ </template>
1960
+
1961
+ <!-- 统计 -->
1962
+ <template
1963
+ v-for="field in footerData"
1964
+ #[`footer_${field["field"]}`]="{ row, column,rowIndex}"
1965
+ :key="field['field']"
1966
+ >
1967
+ <div v-html="sanitizeHtml(row[column.field])"></div>
1968
+ </template>
1969
+
1970
+ <!-- 验证 -->
1971
+ <template #valid_slot="{content}">
1972
+ {{ content }}
1973
+ </template>
1974
+
1975
+
1976
+ <template v-for="(_,name) in $slots" #[name]="{row, column}">
1977
+ <slot :name="name" :row="getRowDataByField(column,row)" :column="column"></slot>
1978
+ </template>
1979
+
1980
+ </vxe-grid>
1981
+
1982
+ <!-- workflow -->
1983
+ <workflow-drawer
1984
+ :data="drawerData"
1985
+ v-model="drawerVisible"
1986
+ ref="todoDrawerRef"
1987
+ :key="drawerKey"
1988
+ />
1989
+
1990
+ <!-- 提交审批 -->
1991
+ <approval-modal
1992
+ v-model="approvalModalVisible"
1993
+ type="submit"
1994
+ :data="approvalData"
1995
+ @confirm="reload"
1996
+ />
1997
+
1998
+ <!-- SohelpTextareaInput 编辑弹窗 -->
1999
+ <ele-modal :width="460" v-model="textareaState['visible']" :title="getCurrentFieldLabel">
2000
+ <sohelp-textarea-input v-model="textareaState['value']" :rows="6"/>
2001
+ <template #footer>
2002
+ <el-button @click="textareaCancel">{{ t("common.cancel") }}</el-button>
2003
+ <el-button type="primary" @click="textareaConfirm(row, column)">{{ t("common.save") }}</el-button>
2004
+ </template>
2005
+ </ele-modal>
2006
+
2007
+ <!--实体表单-->
2008
+ <sohelp-modal
2009
+ :title="toolbarButtonParams?.title || ''"
2010
+ :width="toolbarButtonParams?.width || 860"
2011
+ :draggable="false"
2012
+ v-model="visibleEntityForm" v-loading="loading">
2013
+ <template #setting v-if="userStore.info.is_developer">
2014
+ <ele-dropdown
2015
+ :items="[
2016
+ { title: '表单配置', command: 'form' , icon:Postcard},
2017
+ { title: '实体配置', command: 'entity', icon:Tickets},
2018
+ { title: '流程配置', command: 'workflow', icon:Files },
2019
+ { title: '模块配置', command: 'module', icon:Grid }
2020
+ ]"
2021
+ @command="settingClick"
2022
+ >
2023
+ <el-link :icon="Setting" :underline="false"/>
2024
+ </ele-dropdown>
2025
+ </template>
2026
+
2027
+
2028
+ <sohelp-entity-form ref="entityFormRef" :refid="props.refid.split('!')[0]" v-model="entityFormValue"
2029
+ :data="entityFormData" :config="entityFormConfig" :readonly="toolbarButtonParams?.readonly" :saveParams="saveParams" />
2030
+ <template #footer v-if="!toolbarButtonParams?.readonly">
2031
+ <el-button @click="closeEntityForm()">{{ t("common.close") }}</el-button>
2032
+ <el-button type="primary" @click="saveEntityForm()" v-loading="loading">{{ t("common.save") }}</el-button>
2033
+ </template>
2034
+ </sohelp-modal>
2035
+ <!--打印报表-->
2036
+ <ele-modal
2037
+ :title="toolbarButtonParams?.title|| t('grid.report.title')" :width="toolbarButtonParams?.width|| 600"
2038
+ v-model="visibleReport">
2039
+
2040
+ <ele-check-card v-model="currentReportValue" :items="reportData" :row="{ gutter: 2 }">
2041
+ <template #item="{ item }">
2042
+ <ele-text size="md" style="padding:10px;">{{ item.name }}</ele-text>
2043
+ </template>
2044
+ </ele-check-card>
2045
+
2046
+ <template #footer>
2047
+ <el-button @click="closeReport()">{{ t("common.close") }}</el-button>
2048
+ <el-button @click="designReport()" v-if="reportData && reportData.length>0">{{ t("common.design") }}</el-button>
2049
+ <el-button type="primary" @click="openReport()" v-if="reportData && reportData.length>0">{{ t("common.print") }}
2050
+ </el-button>
2051
+ </template>
2052
+ </ele-modal>
2053
+ <!--数据导入-->
2054
+ <sohelp-import
2055
+ :model-value="importVisible"
2056
+ :refid="props.refid"
2057
+ :fields="sohelpConfig?.properties || []"
2058
+ @update:modelValue="(v) => importVisible = v"
2059
+ @close="closeImport"
2060
+ />
2061
+ </template>
2062
+
2063
+ <style scoped lang="scss">
2064
+ .sohelp-grid-view {
2065
+ padding: 0px;
2066
+ display: flex;
2067
+ height: 100%;
2068
+ flex-direction: column;
2069
+
2070
+ :deep(.vxe-grid--table-wrapper) {
2071
+ .vxe-table {
2072
+ height: 100%;
2073
+ }
2074
+ }
2075
+
2076
+
2077
+ .toolbar-box {
2078
+ display: flex;
2079
+ gap: 10px;
2080
+ flex-wrap: wrap;
2081
+
2082
+ .tools-btns {
2083
+ display: flex;
2084
+ gap: 10px;
2085
+ margin-right: 10px;
2086
+
2087
+ :deep(.el-button) {
2088
+ margin-left: 0 !important;
2089
+ }
2090
+ }
2091
+ }
2092
+
2093
+ .ele-split-panel {
2094
+ :deep(.ele-split-panel-side) {
2095
+ border: none !important;
2096
+ }
2097
+ }
2098
+
2099
+ .vxe-grid {
2100
+ height: 100%;
2101
+
2102
+ :deep(.vxe-grid--layout-body-content-wrapper) {
2103
+ display: flex;
2104
+ flex-direction: column;
2105
+
2106
+ .vxe-grid--table-container {
2107
+ flex: 1;
2108
+ }
2109
+ }
2110
+
2111
+ :deep(.col--SohelpImageUpload) {
2112
+ .vxe-cell--wrapper {
2113
+ overflow: initial !important;
2114
+ }
2115
+ }
2116
+
2117
+ :deep(.vxe-table--render-default) {
2118
+ .vxe-body--row.row--stripe > .vxe-body--column {
2119
+ // background-color: transparent;
2120
+ }
2121
+ }
2122
+
2123
+ }
2124
+ }
2125
+
2126
+ .sort-list :deep(.el-button:focus),
2127
+ .sort-list :deep(.el-button:hover) {
2128
+ background-color: #e8f1ff !important;
2129
+ color: #1677ff !important;
2130
+ }
2131
+
2132
+ .filter-header {
2133
+ border-bottom: 1px solid #ddd;
2134
+ display: flex;
2135
+ width: 100%;
2136
+ height: 35px;
2137
+ line-height: 40px;
2138
+ box-sizing: border-box;
2139
+ margin: 0 0 0 10px;
2140
+ }
2141
+
2142
+ .sohelp-grid-view.right {
2143
+ .ele-split-panel {
2144
+ :deep(.ele-split-panel-side) {
2145
+ height: 100% !important;
2146
+ border: 0;
2147
+ display: flex;
2148
+ flex-direction: column;
2149
+ border-left: 1px solid #ddd !important;
2150
+ }
2151
+ }
2152
+ }
2153
+
2154
+ :deep(.tooltip-btn) {
2155
+ margin-left: 5px;
2156
+ height: 22px;
2157
+ line-height: 22px;
2158
+ margin-top: 2px;
2159
+ padding: 0px 5px !important;
2160
+ }
2161
+
2162
+ :deep(.vxe-cell--wrapper) {
2163
+ height: 100%;
2164
+ }
2165
+
2166
+ .textarea-reference {
2167
+ display: flex;
2168
+ height: 100%;
2169
+ }
2170
+
2171
+ :deep(.ele-split-panel.is-vertical) {
2172
+ .ele-split-panel-wrap > .ele-split-panel-space .ele-split-resize-line::after {
2173
+ background: #eee;
2174
+ }
2175
+ }
2176
+
2177
+ .condition-box {
2178
+ padding: 10px;
2179
+ }
2180
+
2181
+ .sohelp-filter-card.right {
2182
+ height: 100%;
2183
+ overflow: hidden;
2184
+
2185
+ :deep(.ele-card-header) {
2186
+ min-width: 230px;
2187
+ }
2188
+
2189
+ :deep(.ele-card-body) {
2190
+ height: 100% !important;
2191
+ }
2192
+ }
2193
+
2194
+ .column-setting{
2195
+ padding: 5px 10px;
2196
+ display: flex;
2197
+ align-items: center;
2198
+ justify-content: space-between;
2199
+ width: 100%;
2200
+ }
2201
+
2202
+
2203
+ .vxe-grid{
2204
+ :deep(.vxe-grid--toolbar-wrapper){
2205
+ .vxe-button--dropdown{
2206
+ .vxe-button--dropdown-panel{
2207
+ .vxe-button{
2208
+ padding-left: 5px!important;
2209
+ text-align: left;
2210
+ }
2211
+ }
2212
+
2213
+ }
2214
+ }
2215
+ }
2216
+
2217
+ </style>