vue-super-crud 1.7.1

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 (291) hide show
  1. package/.browserslistrc +3 -0
  2. package/.versionrc.json +36 -0
  3. package/CHANGELOG.md +232 -0
  4. package/LICENSE +201 -0
  5. package/README.md +46 -0
  6. package/babel.config.js +12 -0
  7. package/build/alias.js +10 -0
  8. package/build/build.js +52 -0
  9. package/build/config.js +70 -0
  10. package/deploy.bat +14 -0
  11. package/docs/.vuepress/components/button/base.vue +88 -0
  12. package/docs/.vuepress/components/common/code-format.vue +331 -0
  13. package/docs/.vuepress/components/commonConfig/presetCodeTemplate/base.vue +68 -0
  14. package/docs/.vuepress/components/commonConfig/presetCodeTemplate/customParams.vue +73 -0
  15. package/docs/.vuepress/components/commonConfig/renderType/component.vue +160 -0
  16. package/docs/.vuepress/components/commonConfig/renderType/formatter.vue +49 -0
  17. package/docs/.vuepress/components/commonConfig/renderType/render.vue +91 -0
  18. package/docs/.vuepress/components/commonConfig/renderType/slot.vue +63 -0
  19. package/docs/.vuepress/components/crud/baseUse/baseUse.vue +98 -0
  20. package/docs/.vuepress/components/crud/baseUse/columnAction.vue +72 -0
  21. package/docs/.vuepress/components/crud/baseUse/columnWidth.vue +107 -0
  22. package/docs/.vuepress/components/crud/baseUse/handleRow.vue +65 -0
  23. package/docs/.vuepress/components/crud/baseUse/height.vue +82 -0
  24. package/docs/.vuepress/components/crud/baseUse/index.vue +54 -0
  25. package/docs/.vuepress/components/crud/baseUse/loading.vue +70 -0
  26. package/docs/.vuepress/components/crud/baseUse/pagination.vue +108 -0
  27. package/docs/.vuepress/components/crud/baseUse/selection.vue +114 -0
  28. package/docs/.vuepress/components/crud/baseUse/summaryMethod.vue +118 -0
  29. package/docs/.vuepress/components/crud/baseUse/title.vue +54 -0
  30. package/docs/.vuepress/components/crud/baseUse/toolbar.vue +69 -0
  31. package/docs/.vuepress/components/crud/buttons/common.vue +115 -0
  32. package/docs/.vuepress/components/crud/buttons/fast.vue +82 -0
  33. package/docs/.vuepress/components/crud/contextMenu/base.vue +72 -0
  34. package/docs/.vuepress/components/crud/copy.vue +52 -0
  35. package/docs/.vuepress/components/crud/crudEvents/api.vue +157 -0
  36. package/docs/.vuepress/components/crud/crudEvents/deleteTip.vue +93 -0
  37. package/docs/.vuepress/components/crud/crudEvents/events.vue +188 -0
  38. package/docs/.vuepress/components/crud/dataSort/base.vue +142 -0
  39. package/docs/.vuepress/components/crud/genDynamicColumns/base.vue +53 -0
  40. package/docs/.vuepress/components/crud/genDynamicColumns/dynamicAndFixed.vue +111 -0
  41. package/docs/.vuepress/components/crud/genDynamicColumns/treeDynamic.vue +68 -0
  42. package/docs/.vuepress/components/crud/handleBar/handleRow.vue +65 -0
  43. package/docs/.vuepress/components/crud/handleBar/toolbar.vue +69 -0
  44. package/docs/.vuepress/components/crud/renderType/1.vue +57 -0
  45. package/docs/.vuepress/components/crud/renderType/2.vue +63 -0
  46. package/docs/.vuepress/components/crud/renderType/3.vue +105 -0
  47. package/docs/.vuepress/components/crud/renderType/5.vue +91 -0
  48. package/docs/.vuepress/components/crud/search/1.vue +90 -0
  49. package/docs/.vuepress/components/crud/search/2.vue +78 -0
  50. package/docs/.vuepress/components/crud/search/3.vue +107 -0
  51. package/docs/.vuepress/components/crud/search/base.vue +123 -0
  52. package/docs/.vuepress/components/crud/search/localSearch.vue +124 -0
  53. package/docs/.vuepress/components/crud/search/special.vue +148 -0
  54. package/docs/.vuepress/components/crud/selection/events.vue +47 -0
  55. package/docs/.vuepress/components/crud/selection/pagination.vue +94 -0
  56. package/docs/.vuepress/components/crud/selection/singleSelection.vue +64 -0
  57. package/docs/.vuepress/components/crud/span/base.vue +69 -0
  58. package/docs/.vuepress/components/crud/span/special.vue +75 -0
  59. package/docs/.vuepress/components/crud/summary/base.vue +99 -0
  60. package/docs/.vuepress/components/crud/tableEdit/addDeleteBtn.vue +174 -0
  61. package/docs/.vuepress/components/crud/tableEdit/cellEdit.vue +194 -0
  62. package/docs/.vuepress/components/crud/tableEdit/controlEdit.vue +219 -0
  63. package/docs/.vuepress/components/crud/tableEdit/dialog.vue +172 -0
  64. package/docs/.vuepress/components/crud/tableEdit/free.vue +88 -0
  65. package/docs/.vuepress/components/crud/tableEdit/freeColumn.vue +82 -0
  66. package/docs/.vuepress/components/crud/tableEdit/methods.vue +154 -0
  67. package/docs/.vuepress/components/crud/tableEdit/rowAction.vue +107 -0
  68. package/docs/.vuepress/components/crud/tableEdit/rowBatch.vue +116 -0
  69. package/docs/.vuepress/components/crud/tableEdit/rowClick.vue +98 -0
  70. package/docs/.vuepress/components/crud/validate/base.vue +122 -0
  71. package/docs/.vuepress/components/crud/validate/custom.vue +82 -0
  72. package/docs/.vuepress/components/crud/validate/regulars.vue +88 -0
  73. package/docs/.vuepress/components/crud/validate/relation.vue +91 -0
  74. package/docs/.vuepress/components/crud/validate/tree.vue +82 -0
  75. package/docs/.vuepress/components/dialog/baseUse/base.vue +92 -0
  76. package/docs/.vuepress/components/dialog/baseUse/beforeConfirm.vue +78 -0
  77. package/docs/.vuepress/components/dialog/baseUse/control.vue +79 -0
  78. package/docs/.vuepress/components/dialog/baseUse/drawer.vue +59 -0
  79. package/docs/.vuepress/components/dialog/baseUse/footer.vue +87 -0
  80. package/docs/.vuepress/components/dialog/baseUse/insertSlot.vue +79 -0
  81. package/docs/.vuepress/components/dict/DictLinkage.vue +91 -0
  82. package/docs/.vuepress/components/dict/baseUse.vue +72 -0
  83. package/docs/.vuepress/components/dict/component.vue +82 -0
  84. package/docs/.vuepress/components/dict/localDict.vue +68 -0
  85. package/docs/.vuepress/components/form/baseUse/base.vue +48 -0
  86. package/docs/.vuepress/components/form/baseUse/dataFormat.vue +92 -0
  87. package/docs/.vuepress/components/form/baseUse/deep.vue +57 -0
  88. package/docs/.vuepress/components/form/baseUse/gridLayout.vue +47 -0
  89. package/docs/.vuepress/components/form/baseUse/group.vue +66 -0
  90. package/docs/.vuepress/components/form/baseUse/hidden.vue +40 -0
  91. package/docs/.vuepress/components/form/baseUse/inlineLayout.vue +48 -0
  92. package/docs/.vuepress/components/form/baseUse/label.vue +51 -0
  93. package/docs/.vuepress/components/form/baseUse/tooltip.vue +40 -0
  94. package/docs/.vuepress/components/form/baseUse/validate.vue +52 -0
  95. package/docs/.vuepress/components/form/detail/base.vue +78 -0
  96. package/docs/.vuepress/components/form/detail/border.vue +90 -0
  97. package/docs/.vuepress/components/form/detail/singleDetail.vue +72 -0
  98. package/docs/.vuepress/components/formatData/baseUse.vue +131 -0
  99. package/docs/.vuepress/components/mock/index.js +347 -0
  100. package/docs/.vuepress/components/mockData/custom.vue +69 -0
  101. package/docs/.vuepress/components/mockData/example.vue +290 -0
  102. package/docs/.vuepress/components/positionSlot/base.vue +24 -0
  103. package/docs/.vuepress/components/positionSlot/form.vue +71 -0
  104. package/docs/.vuepress/components/positionSlot/table.vue +85 -0
  105. package/docs/.vuepress/components/tabs/base.vue +57 -0
  106. package/docs/.vuepress/components/temp.js +195 -0
  107. package/docs/.vuepress/config.js +146 -0
  108. package/docs/.vuepress/enhanceApp.js +142 -0
  109. package/docs/.vuepress/public/favicon.ico +0 -0
  110. package/docs/.vuepress/public/super.png +0 -0
  111. package/docs/.vuepress/styles/index.styl +25 -0
  112. package/docs/.vuepress/styles/palette.styl +6 -0
  113. package/docs/README.md +14 -0
  114. package/docs/guide/button/base.md +31 -0
  115. package/docs/guide/commonConfig/jsx.md +166 -0
  116. package/docs/guide/commonConfig/presetCodeTemplate.md +68 -0
  117. package/docs/guide/commonConfig/renderType.md +181 -0
  118. package/docs/guide/crud/baseUse.md +120 -0
  119. package/docs/guide/crud/buttons.md +18 -0
  120. package/docs/guide/crud/config.md +217 -0
  121. package/docs/guide/crud/contextMenu.md +18 -0
  122. package/docs/guide/crud/dataSort.md +66 -0
  123. package/docs/guide/crud/genDynamicColumns.md +145 -0
  124. package/docs/guide/crud/handleBar.md +26 -0
  125. package/docs/guide/crud/renderType.md +4 -0
  126. package/docs/guide/crud/search.md +150 -0
  127. package/docs/guide/crud/selection.md +73 -0
  128. package/docs/guide/crud/span.md +98 -0
  129. package/docs/guide/crud/summary.md +167 -0
  130. package/docs/guide/crud/tableEdit.md +377 -0
  131. package/docs/guide/crud/validate.md +158 -0
  132. package/docs/guide/dialog/baseUse.md +81 -0
  133. package/docs/guide/dict/baseUse.md +174 -0
  134. package/docs/guide/dict/component.md +88 -0
  135. package/docs/guide/dict/config.md +44 -0
  136. package/docs/guide/form/baseUse.md +142 -0
  137. package/docs/guide/form/detail.md +38 -0
  138. package/docs/guide/formatData/baseUse.md +98 -0
  139. package/docs/guide/formatData/config.md +142 -0
  140. package/docs/guide/mockData/base.md +26 -0
  141. package/docs/guide/positionSlot/base.md +41 -0
  142. package/docs/guide/question/base.md +44 -0
  143. package/docs/guide/start/base.md +30 -0
  144. package/docs/guide/tabs/base.md +63 -0
  145. package/examples/App.vue +52 -0
  146. package/examples/Layout/components/AppMain.vue +40 -0
  147. package/examples/Layout/components/Item.vue +29 -0
  148. package/examples/Layout/components/Link.vue +44 -0
  149. package/examples/Layout/components/SidebarItem.vue +93 -0
  150. package/examples/Layout/index.vue +69 -0
  151. package/examples/assets/logo.png +0 -0
  152. package/examples/favicon.ico +0 -0
  153. package/examples/index.html +18 -0
  154. package/examples/main.js +54 -0
  155. package/examples/router/index.js +140 -0
  156. package/examples/store/index.js +0 -0
  157. package/examples/styles/index.scss +63 -0
  158. package/examples/styles/sidebar.scss +226 -0
  159. package/examples/styles/transition.scss +48 -0
  160. package/examples/styles/variables.scss +25 -0
  161. package/examples/views/crud/base.vue +68 -0
  162. package/examples/views/crud/handleRow.vue +84 -0
  163. package/examples/views/crud/search.vue +116 -0
  164. package/examples/views/dashboard/index.vue +244 -0
  165. package/examples/views/dashboard/index1.vue +234 -0
  166. package/examples/views/dashboard/test.vue +9 -0
  167. package/examples/views/formTest/index.vue +168 -0
  168. package/examples/views/nested/menu1/index.vue +7 -0
  169. package/examples/views/nested/menu1/menu1-1/index.vue +7 -0
  170. package/examples/views/nested/menu1/menu1-2/index.vue +7 -0
  171. package/examples/views/nested/menu1/menu1-2/menu1-2-1/index.vue +5 -0
  172. package/examples/views/nested/menu1/menu1-2/menu1-2-2/index.vue +5 -0
  173. package/examples/views/nested/menu1/menu1-3/index.vue +5 -0
  174. package/examples/views/nested/menu2/index.vue +5 -0
  175. package/gulpfile.js +84 -0
  176. package/lib/index.css +1 -0
  177. package/lib/super-crud.min.js +15 -0
  178. package/package.json +66 -0
  179. package/packages/button/index.vue +189 -0
  180. package/packages/core/components/comp.vue +223 -0
  181. package/packages/core/components/position.vue +135 -0
  182. package/packages/core/components/render.vue +460 -0
  183. package/packages/core/configManager.js +302 -0
  184. package/packages/core/create.js +8 -0
  185. package/packages/core/defaultRender.js +64 -0
  186. package/packages/core/dict/global.js +10 -0
  187. package/packages/core/dict/index.js +432 -0
  188. package/packages/core/dict/mixin.js +94 -0
  189. package/packages/core/event.js +60 -0
  190. package/packages/core/index.js +6 -0
  191. package/packages/core/init.js +122 -0
  192. package/packages/core/mock/genConfig.js +228 -0
  193. package/packages/core/mock/genData.js +422 -0
  194. package/packages/core/mock/index.js +4 -0
  195. package/packages/core/rules.js +111 -0
  196. package/packages/crud/column.vue +205 -0
  197. package/packages/crud/columnAction.vue +207 -0
  198. package/packages/crud/columnCell.vue +146 -0
  199. package/packages/crud/defaultColumn.vue +130 -0
  200. package/packages/crud/drawerColumn.vue +225 -0
  201. package/packages/crud/form.vue +69 -0
  202. package/packages/crud/index.vue +564 -0
  203. package/packages/crud/menuBar.vue +298 -0
  204. package/packages/crud/mixins/cacheHandler.js +36 -0
  205. package/packages/crud/mixins/calcColumnWidth.js +79 -0
  206. package/packages/crud/mixins/calcHeight.js +105 -0
  207. package/packages/crud/mixins/columnHandler.js +128 -0
  208. package/packages/crud/mixins/contextMenu.js +98 -0
  209. package/packages/crud/mixins/dataProcessor.js +202 -0
  210. package/packages/crud/mixins/dialog.js +109 -0
  211. package/packages/crud/mixins/excelHandler.js +150 -0
  212. package/packages/crud/mixins/exposeMethods.js +107 -0
  213. package/packages/crud/mixins/generateDynamicColumns.js +250 -0
  214. package/packages/crud/mixins/props.js +38 -0
  215. package/packages/crud/mixins/searchHandler.js +151 -0
  216. package/packages/crud/mixins/select.js +359 -0
  217. package/packages/crud/mixins/spanMethod.js +288 -0
  218. package/packages/crud/mixins/summary.js +177 -0
  219. package/packages/crud/mixins/tableEdit.js +547 -0
  220. package/packages/crud/mixins/validate.js +219 -0
  221. package/packages/crud/pagination.vue +110 -0
  222. package/packages/crud/search.vue +119 -0
  223. package/packages/crud/searchHeader.vue +231 -0
  224. package/packages/crud/selectBanner.vue +138 -0
  225. package/packages/crud/utils/EditState.js +319 -0
  226. package/packages/crud/utils/excelExport.js +112 -0
  227. package/packages/crud/utils/excelImport.js +112 -0
  228. package/packages/crud/utils/index.js +98 -0
  229. package/packages/dialog/dialog.js +233 -0
  230. package/packages/dialog/dialog.vue +15 -0
  231. package/packages/dialog/index.js +22 -0
  232. package/packages/dict/cascadeFormat.vue +179 -0
  233. package/packages/dict/dateFormat.vue +40 -0
  234. package/packages/dict/form/cascade.vue +61 -0
  235. package/packages/dict/form/checkbox.vue +90 -0
  236. package/packages/dict/form/extendMethod.js +22 -0
  237. package/packages/dict/form/input-base.js +31 -0
  238. package/packages/dict/form/input.js +20 -0
  239. package/packages/dict/form/radio.vue +69 -0
  240. package/packages/dict/form/select.vue +118 -0
  241. package/packages/dict/form/switch.vue +75 -0
  242. package/packages/dict/valueFormat.vue +188 -0
  243. package/packages/directive/dialog/drag.js +86 -0
  244. package/packages/directive/dialog/dragSize.js +42 -0
  245. package/packages/directive/index.js +9 -0
  246. package/packages/directive/insertSlot.js +10 -0
  247. package/packages/form/contextMenu.js +192 -0
  248. package/packages/form/draftDrawer.vue +391 -0
  249. package/packages/form/formAction.vue +97 -0
  250. package/packages/form/formItem.vue +259 -0
  251. package/packages/form/index.vue +451 -0
  252. package/packages/form/props.js +15 -0
  253. package/packages/grid/cell.vue +65 -0
  254. package/packages/grid/index.vue +130 -0
  255. package/packages/group/index.vue +96 -0
  256. package/packages/tabs/index.vue +290 -0
  257. package/packages/tooltip/index.js +9 -0
  258. package/packages/tooltip/tooltip.vue +32 -0
  259. package/packages/tooltip/tooltipComponent.js +38 -0
  260. package/packages/verifyInput/index.vue +131 -0
  261. package/src/config/common.js +88 -0
  262. package/src/config/crud.js +567 -0
  263. package/src/config/dialog.js +87 -0
  264. package/src/config/form.js +215 -0
  265. package/src/config/index.js +9 -0
  266. package/src/constants/index.js +72 -0
  267. package/src/index.js +67 -0
  268. package/src/template/btn/crud.js +6 -0
  269. package/src/template/btn/dialog.js +1 -0
  270. package/src/template/btn/form.js +3 -0
  271. package/src/template/btn/index.js +9 -0
  272. package/src/template/dicts.js +1 -0
  273. package/src/template/formatData.js +507 -0
  274. package/src/template/index.js +19 -0
  275. package/src/template/render.js +124 -0
  276. package/src/template/rules.js +53 -0
  277. package/src/utils/bem.js +49 -0
  278. package/src/utils/cache.js +77 -0
  279. package/src/utils/getType.js +34 -0
  280. package/src/utils/index.js +212 -0
  281. package/src/utils/mergeTemp.js +124 -0
  282. package/styles/button.scss +3 -0
  283. package/styles/crud.scss +425 -0
  284. package/styles/dialog.scss +95 -0
  285. package/styles/form.scss +532 -0
  286. package/styles/group.scss +78 -0
  287. package/styles/index.scss +94 -0
  288. package/styles/tabs.scss +139 -0
  289. package/styles/verifyInput.scss +56 -0
  290. package/vue-jsx-sync.js +90 -0
  291. package/vue.config.js +54 -0
@@ -0,0 +1,219 @@
1
+ import { debounce, get, omit } from "lodash-es";
2
+ import { findTreeNodePath } from "../utils";
3
+ export default {
4
+ data() {
5
+ return {
6
+ errorContent: "",
7
+ errorMap: new Map(), // 存储错误信息
8
+ };
9
+ },
10
+ created() {
11
+ this.activateTooltip = debounce(
12
+ (tooltip) => tooltip.handleShowPopper(),
13
+ 50
14
+ );
15
+ },
16
+ methods: {
17
+ handleValidateError(fullProp, msg, isValid = true) {
18
+ const cell = this.$el
19
+ .querySelector(".el-table__body")
20
+ .querySelector(`[data-full-prop="${fullProp}"]`);
21
+ if (!cell) return;
22
+
23
+ // 向上查找父元素直到找到 el-table__cell
24
+ let targetCell = cell;
25
+ let loopCount = 0;
26
+ const maxLoops = 5;
27
+
28
+ while (
29
+ targetCell &&
30
+ !targetCell.classList.contains("el-table__cell") &&
31
+ loopCount < maxLoops
32
+ ) {
33
+ targetCell = targetCell.parentElement;
34
+ loopCount++;
35
+ }
36
+
37
+ if (!targetCell || loopCount >= maxLoops) return;
38
+
39
+ if (!isValid) {
40
+ // 添加错误状态
41
+ targetCell.classList.add("error-badge");
42
+ this.errorMap.set(fullProp, msg);
43
+ this.showErrorTooltip(cell);
44
+ } else {
45
+ // 移除错误状态
46
+ targetCell.classList.remove("error-badge");
47
+ this.errorMap.delete(fullProp);
48
+ this.cellMouseLeave();
49
+ }
50
+ },
51
+ createListError(prop, valid, msg) {
52
+ this.handleValidateError(prop, msg, valid);
53
+ },
54
+ clearErrorMsg(row, prop) {
55
+ const targetPath =
56
+ "list." +
57
+ findTreeNodePath(this.list, (node) => node === row, "children") +
58
+ "." +
59
+ prop;
60
+ this.handleValidateError(targetPath, "", true);
61
+ },
62
+ cellMouseEnter(row, column, cell, event) {
63
+ const el = cell.querySelector("[data-full-prop]");
64
+ if (!el) return;
65
+ this.showErrorTooltip(el);
66
+ },
67
+ showErrorTooltip(el) {
68
+ const targetPath = el.getAttribute("data-full-prop");
69
+ this.errorContent = this.errorMap.get(targetPath);
70
+ const tooltip = this.$refs.tooltip;
71
+ tooltip.referenceElm = el;
72
+ tooltip.$refs.popper && (tooltip.$refs.popper.style.display = "none");
73
+ tooltip.doDestroy();
74
+ if (!this.errorContent) return;
75
+ tooltip.setExpectedState(true);
76
+ this.activateTooltip(tooltip);
77
+ },
78
+ cellMouseLeave() {
79
+ const tooltip = this.$refs.tooltip;
80
+ if (tooltip) {
81
+ tooltip.setExpectedState(false);
82
+ tooltip.handleClosePopper();
83
+ }
84
+ },
85
+ validate(callBack) {
86
+ return new Promise((resolve, reject) => {
87
+ this.$refs.tableFormRef.validate((valid, obj) => {
88
+ if (!valid) {
89
+ reject(obj);
90
+ if (Object.keys(obj).length) {
91
+ this.tbodyWrapEl = this.$el.querySelector(
92
+ ".el-table__body-wrapper"
93
+ );
94
+ this.tbodyEl = this.tbodyWrapEl.querySelector("tbody");
95
+ const tableListEl = this.tbodyEl.childNodes;
96
+ const index = Object.keys(obj)[0].split(".")[1];
97
+ tableListEl[index].scrollIntoView({
98
+ behavior: "smooth",
99
+ block: "center",
100
+ });
101
+ // 校验信息是否提示
102
+ if (this.crudOptions.validateMsg && this.errorMap.size) {
103
+ const firstErrorKey = Array.from(this.errorMap.keys())[0];
104
+ const msg = this.errorMap.get(firstErrorKey);
105
+ msg && this.$message.error(msg);
106
+ }
107
+ }
108
+ } else {
109
+ callBack && callBack(this.list);
110
+ resolve({ list: this.list });
111
+ }
112
+ });
113
+ });
114
+ },
115
+ validateField(params) {
116
+ const options = typeof params === "number" ? { index: params } : params;
117
+ return this._validateField(options);
118
+ },
119
+ _validateField(options = {}) {
120
+ return new Promise((resolve, reject) => {
121
+ const { index, id, row, prop } = options;
122
+
123
+ // 查找目标行的路径
124
+ let targetPath = null;
125
+
126
+ if (index !== undefined) {
127
+ // 通过索引直接定位
128
+ targetPath = `list.${index}`;
129
+ } else if (id) {
130
+ // 通过 ID 查找路径
131
+ targetPath =
132
+ "list." +
133
+ findTreeNodePath(
134
+ this.list,
135
+ (node) => node[this.valueKey] === id,
136
+ "children"
137
+ );
138
+ } else if (row) {
139
+ // 通过对象引用查找路径
140
+ targetPath =
141
+ "list." +
142
+ findTreeNodePath(this.list, (node) => node === row, "children");
143
+ }
144
+
145
+ if (!targetPath) {
146
+ reject(new Error("未找到目标行"));
147
+ return;
148
+ }
149
+
150
+ // 获取需要校验的字段
151
+ const fields = this.$refs.tableFormRef.fields.filter((field) => {
152
+ const fieldPath = field.prop.split(".");
153
+
154
+ // 如果指定了具体字段,则只校验该字段
155
+ if (prop) {
156
+ return field.prop === `${targetPath}.${prop}`;
157
+ }
158
+
159
+ // 否则校验该行所有字段
160
+ return fieldPath.slice(0, -1).join(".") === targetPath;
161
+ });
162
+
163
+ if (fields.length === 0) {
164
+ resolve();
165
+ return;
166
+ }
167
+
168
+ // 执行校验
169
+ const validates = [];
170
+ const errors = [];
171
+
172
+ const validatePromises = fields.map((field) => {
173
+ return new Promise((fieldResolve) => {
174
+ field.validate("", (errorMsg) => {
175
+ if (errorMsg) {
176
+ validates.push(false);
177
+ errors.push({
178
+ field: field.prop.split(".").pop(),
179
+ message: errorMsg,
180
+ });
181
+ } else {
182
+ validates.push(true);
183
+ }
184
+ fieldResolve();
185
+ });
186
+ });
187
+ });
188
+
189
+ // 等待所有字段校验完成
190
+ Promise.all(validatePromises).then(() => {
191
+ if (validates.every((v) => v)) {
192
+ resolve({
193
+ valid: true,
194
+ path: targetPath,
195
+ });
196
+ } else {
197
+ reject({
198
+ valid: false,
199
+ path: targetPath,
200
+ errors: errors,
201
+ });
202
+ }
203
+ });
204
+ });
205
+ },
206
+ clearValidate() {
207
+ this.$refs.tableFormRef.clearValidate();
208
+ this.errorMap.clear();
209
+ this.errorContent = "";
210
+ const cells =
211
+ this.$el
212
+ .querySelector(".el-table__body")
213
+ .querySelectorAll(".error-badge") || [];
214
+ cells.forEach((c) => {
215
+ c.classList.remove("error-badge");
216
+ });
217
+ },
218
+ },
219
+ };
@@ -0,0 +1,110 @@
1
+ <template>
2
+ <el-pagination
3
+ :class="b()"
4
+ :style="{
5
+ 'text-align': pagination.align,
6
+ }"
7
+ v-show="showPagination"
8
+ :current-page.sync="pageNum"
9
+ :page-size.sync="pageSize"
10
+ :total="total"
11
+ :disabled="ctx.loadingStatus"
12
+ @size-change="handleSizeChange"
13
+ @current-change="handleCurrentChange"
14
+ v-bind="pagination"
15
+ v-on="paginationOn"
16
+ />
17
+ </template>
18
+
19
+ <script>
20
+ import create from "core/create";
21
+ import { checkVisibility } from "utils";
22
+ export default create({
23
+ name: "crud-pagination",
24
+ inject: ["ctx"],
25
+ computed: {
26
+ showPagination() {
27
+ return checkVisibility(this.pagination, null, this.total > 0);
28
+ },
29
+ pagination() {
30
+ return this.ctx.crudOptions.pagination;
31
+ },
32
+ paginationOn() {
33
+ return this.pagination?.on;
34
+ },
35
+ props() {
36
+ return this.ctx.crudOptions.props;
37
+ },
38
+ pageNum: {
39
+ get() {
40
+ return this.ctx.query[this.props.pageNum];
41
+ },
42
+ set(val) {
43
+ this.ctx.query[this.props.pageNum] = val;
44
+ },
45
+ },
46
+ pageSize: {
47
+ get() {
48
+ return this.ctx.query[this.props.pageSize];
49
+ },
50
+ set(val) {
51
+ this.ctx.query[this.props.pageSize] = val;
52
+ },
53
+ },
54
+ total() {
55
+ if (this.ctx.localFilteredData !== undefined) {
56
+ return this.ctx.localFilteredData?.length || 0;
57
+ }
58
+ if (this.ctx.crudOptions.localPagination) {
59
+ return this.ctx.data.length;
60
+ }
61
+ return this.ctx.total;
62
+ },
63
+ },
64
+ watch: {
65
+ total(total) {
66
+ //如果当前页面删除没数据了调用第一页
67
+ if (total === (this.pageNum - 1) * this.pageSize && total != 0) {
68
+ this.pageNum = this.pageNum - 1;
69
+ }
70
+ },
71
+ },
72
+ created() {
73
+ this.initPage();
74
+ },
75
+ methods: {
76
+ initPage() {
77
+ this.$set(
78
+ this.ctx.query,
79
+ this.props.pageNum,
80
+ this.ctx.search[this.props.pageNum] || 1
81
+ );
82
+ this.$set(
83
+ this.ctx.query,
84
+ this.props.pageSize,
85
+ this.ctx.setOptions.pageSize || this.ctx.search[this.props.pageSize]
86
+ );
87
+ },
88
+ handleSizeChange(val) {
89
+ if (this.pageNum * val > this.total) {
90
+ this.pageNum = 1;
91
+ }
92
+ this.ctx.setOptions.pageSize = val;
93
+ this.ctx.saveLocalCache(false);
94
+ this.handleDataChange();
95
+ },
96
+ handleCurrentChange(val) {
97
+ this.handleDataChange();
98
+ },
99
+ handleDataChange() {
100
+ if (this.ctx.crudOptions.localPagination) {
101
+ this.$nextTick(() => {
102
+ this.ctx.updateSelection();
103
+ });
104
+ } else {
105
+ this.ctx.getList();
106
+ }
107
+ },
108
+ },
109
+ });
110
+ </script>
@@ -0,0 +1,119 @@
1
+ <template>
2
+ <scForm
3
+ :class="[b({ 'show-search': ctx.showSearch })]"
4
+ ref="searchForm"
5
+ :autoFill="true"
6
+ v-model="ctx.query"
7
+ :options="options"
8
+ :loading="ctx.loadingStatus"
9
+ ></scForm>
10
+ </template>
11
+
12
+ <script>
13
+ import create from "core/create";
14
+ import scForm from "../form/index.vue";
15
+ import { merge, isFunction } from "lodash-es";
16
+ import defaultRender from "core/defaultRender";
17
+ import { filterColumns } from "utils";
18
+ export default create({
19
+ name: "crud-search",
20
+ inject: ["ctx"],
21
+ components: { scForm },
22
+ computed: {
23
+ searchForm() {
24
+ const opt = this.ctx.crudOptions.searchForm;
25
+ return {
26
+ ...opt,
27
+ renderColumns: filterColumns(this.ctx.getRenderColumns("search")),
28
+ };
29
+ },
30
+ options() {
31
+ return merge(
32
+ {
33
+ size: this.ctx.crudOptions.size,
34
+ shrinkLabel: false,
35
+ columnWidth: "300px",
36
+ action: {
37
+ fill: false,
38
+ search: {
39
+ label: "查询",
40
+ icon: "el-icon-search",
41
+ type: "primary",
42
+ onClick: this.ctx.handleSearch,
43
+ },
44
+ reset: {
45
+ icon: "el-icon-refresh",
46
+ label: "重置",
47
+ onClick: () => this.ctx.handleReset(),
48
+ },
49
+ },
50
+ slots: this.ctx.extendsScopedSlots,
51
+ mode: "search",
52
+ defaultRender: (h, scope) => {
53
+ if (isFunction(this.searchForm.defaultRender)) {
54
+ return this.searchForm.defaultRender(h, scope);
55
+ }
56
+ return defaultRender.input(h, scope);
57
+ },
58
+ },
59
+ this.searchForm
60
+ );
61
+ },
62
+ },
63
+ watch: {
64
+ "ctx.query": {
65
+ handler(val) {
66
+ this.queryChange = true;
67
+ this.ctx.$emit("update:search", val);
68
+ this.$nextTick(() => {
69
+ this.queryChange = false;
70
+ });
71
+ },
72
+ deep: true,
73
+ },
74
+ "ctx.search": {
75
+ handler(val) {
76
+ if (this.queryChange) return;
77
+ this.$nextTick(() => {
78
+ this.ctx.query = { ...this.ctx.query, ...val };
79
+ });
80
+ },
81
+ deep: true,
82
+ immediate: true,
83
+ },
84
+ },
85
+ created() {
86
+ // this.saveInitSearch();
87
+ if (
88
+ (this.searchForm && this.searchForm.initShow) ||
89
+ this.ctx.crudOptions?.expandSearch
90
+ ) {
91
+ this.ctx.showSearch = true;
92
+ }
93
+ },
94
+ methods: {
95
+ saveInitSearch() {
96
+ // 保存初始搜索参数
97
+ if (this.ctx.search) {
98
+ this._search = { ...this.ctx.search };
99
+ }
100
+ },
101
+ setInitSearch() {
102
+ // 表单加载完成后再设置初始搜索参数,防止重置残留初始搜索参数
103
+ if (this._search) {
104
+ setTimeout(() => {
105
+ Object.keys(this._search).forEach((key) => {
106
+ this.$set(this.ctx.query, key, this._search[key]);
107
+ });
108
+ }, 0);
109
+ }
110
+ },
111
+ resetField(prop) {
112
+ this.$refs.searchForm.resetField(prop);
113
+ },
114
+ resetFields() {
115
+ this.$refs.searchForm.resetFields();
116
+ },
117
+ },
118
+ });
119
+ </script>
@@ -0,0 +1,231 @@
1
+ <script>
2
+ import { isEmptyData } from "utils";
3
+ import { create } from "core";
4
+ import Render from "core/components/render";
5
+ import { isFunction, merge, isPlainObject, get } from "lodash-es";
6
+ export default create({
7
+ name: "crud-search-header",
8
+ props: {
9
+ item: {},
10
+ },
11
+ mixins: [],
12
+ inject: ["ctx"],
13
+ provide() {
14
+ return {
15
+ searchHeader: this,
16
+ };
17
+ },
18
+ data() {
19
+ return {
20
+ active: false,
21
+ };
22
+ },
23
+ created() {
24
+ this.$emit("update:isSearch", this.isSearch());
25
+ this.ctx.$on("closeSearchPopover", (prop) => {
26
+ if (prop === this.item.prop) return;
27
+ this.closePopover();
28
+ });
29
+ this.$watch(
30
+ () =>
31
+ this.item.validateProp
32
+ ? get(this.ctx.query, this.item.validateProp)
33
+ : this.ctx.query[this.item.prop],
34
+ (val) => {
35
+ this.$emit("update:isSearch", this.isSearch());
36
+ },
37
+ {
38
+ deep: true,
39
+ }
40
+ );
41
+ },
42
+ computed: {
43
+ searchHeader() {
44
+ return this.ctx.crudOptions.searchHeader;
45
+ },
46
+ mergeConfig() {
47
+ let mergeConfig = merge({}, this.searchHeader, this.item);
48
+ if (mergeConfig && typeof mergeConfig.width === "string") {
49
+ mergeConfig.width = parseInt(mergeConfig.width);
50
+ }
51
+ return mergeConfig;
52
+ },
53
+ componentStrategy() {
54
+ return [
55
+ {
56
+ rule: "*input",
57
+ comp: {
58
+ nativeOn: {
59
+ keyup: (e) => {
60
+ if (e.keyCode === 13) {
61
+ this.search();
62
+ }
63
+ },
64
+ },
65
+ on: {
66
+ clear: () => {
67
+ this.search();
68
+ },
69
+ },
70
+ },
71
+ },
72
+ {
73
+ rule: "*select",
74
+ comp: {
75
+ on: {
76
+ change: (val) => {
77
+ this.isChange = true;
78
+ },
79
+ "visible-change": (val) => {
80
+ if (!val && this.isChange) {
81
+ this.isChange = false;
82
+ this.search();
83
+ }
84
+ },
85
+ },
86
+ },
87
+ },
88
+ {
89
+ rule: "*cascader",
90
+ comp: {
91
+ on: {
92
+ change: (val) => {
93
+ this.isChange = true;
94
+ },
95
+ "visible-change": (val) => {
96
+ if (!val && this.isChange) {
97
+ this.isChange = false;
98
+ this.search();
99
+ }
100
+ },
101
+ },
102
+ },
103
+ },
104
+ {
105
+ rule: "*date-picker",
106
+ comp: {
107
+ on: {
108
+ change: (val) => {
109
+ this.search();
110
+ },
111
+ },
112
+ },
113
+ },
114
+ ];
115
+ },
116
+ },
117
+ methods: {
118
+ closePopover() {
119
+ this.$refs.popover && this.$refs.popover.doClose();
120
+ },
121
+ search(val) {
122
+ if (this.justSearched) return;
123
+ this.justSearched = true;
124
+ this.ctx.handleSearch();
125
+ this.closePopover();
126
+ setTimeout(() => {
127
+ this.justSearched = false;
128
+ }, 200);
129
+ },
130
+ reset() {
131
+ if (isFunction(this.item.reset)) this.item.reset();
132
+ this.ctx.handleReset(this.item.prop);
133
+ this.closePopover();
134
+ },
135
+ popClick(e) {
136
+ e.stopPropagation();
137
+ },
138
+ isSearch() {
139
+ const value = this.item.validateProp
140
+ ? get(this.ctx.query, this.item.validateProp)
141
+ : this.ctx.query[this.item.prop];
142
+ if (Array.isArray(value) && value.length) {
143
+ return value.every((item) => !isEmptyData(item));
144
+ }
145
+ if (isPlainObject(value) && Object.keys(value).length) {
146
+ return Object.values(value).every((item) => !isEmptyData(item));
147
+ }
148
+ return !isEmptyData(value);
149
+ },
150
+ },
151
+ render(h) {
152
+ const contentRender = () => {
153
+ return (
154
+ <Render
155
+ props={this.item}
156
+ item={this.item}
157
+ slots={this.ctx.extendsScopedSlots}
158
+ scope={{
159
+ row: this.ctx.query,
160
+ }}
161
+ mode="searchHeader"
162
+ size={this.ctx.crudOptions.size}
163
+ compStrategy={this.componentStrategy}
164
+ commonCompStrategy={{
165
+ mounted: (scope, ref) => {
166
+ this.instance = ref;
167
+ },
168
+ }}
169
+ defaultComp={{
170
+ name: "el-input",
171
+ props: {
172
+ clearable: true,
173
+ },
174
+ }}
175
+ ></Render>
176
+ );
177
+ };
178
+ const footer = () => {
179
+ return (
180
+ <div style="display: flex; align-items: center;">
181
+ {this.mergeConfig.searchBtn && (
182
+ <el-button
183
+ icon="el-icon-search"
184
+ type="primary"
185
+ onClick={this.search}
186
+ style="margin-left: 10px;"
187
+ ></el-button>
188
+ )}
189
+ {this.mergeConfig.resetBtn && (
190
+ <el-button
191
+ icon="el-icon-refresh-right"
192
+ onClick={this.reset}
193
+ style="margin-left: 10px;"
194
+ ></el-button>
195
+ )}
196
+ </div>
197
+ );
198
+ };
199
+ return (
200
+ <el-popover
201
+ popper-class={this.b()}
202
+ ref="popover"
203
+ placement="bottom"
204
+ trigger="click"
205
+ props={this.mergeConfig}
206
+ onShow={() => {
207
+ this.ctx.$emit("closeSearchPopover", this.item.prop);
208
+ this.ctx.showPopperNum++;
209
+ this.$nextTick(() => {
210
+ this.instance?.$el.querySelector("input")?.focus();
211
+ });
212
+ }}
213
+ onHide={() => {
214
+ this.isSearch && this.search();
215
+ if (this.ctx.showPopperNum > 0) {
216
+ this.ctx.showPopperNum--;
217
+ }
218
+ }}
219
+ scopedSlots={{
220
+ reference: () => (
221
+ <i class="el-icon-search search-btn" onClick={this.popClick}></i>
222
+ ),
223
+ }}
224
+ >
225
+ {contentRender()}
226
+ {footer()}
227
+ </el-popover>
228
+ );
229
+ },
230
+ });
231
+ </script>