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,432 @@
1
+ import { isEmptyData } from "utils";
2
+ import { get } from "lodash-es";
3
+
4
+ const DictStatus = {
5
+ PENDING: "pending",
6
+ SUCCESS: "success",
7
+ ERROR: "error",
8
+ };
9
+
10
+ export class DictManager {
11
+ constructor(vue, options = {}) {
12
+ this.vue = vue;
13
+ this.vm = new vue();
14
+ this.loadTasks = {};
15
+ this.dictMeta = new Map();
16
+ this.dictWatch = new Map();
17
+ this.pendingPromises = new Set();
18
+ this.defaultMeta = this.createDefaultMeta(options);
19
+
20
+ // 创建响应式数据
21
+ this.state = vue.observable({
22
+ dictsData: {}, // 字典数据
23
+ dictStatus: {}, // 字典状态
24
+ dictsParams: {}, // 字典参数
25
+ });
26
+
27
+ // 创建代理
28
+ return new Proxy(this, {
29
+ get: (target, prop) => {
30
+ // 如果访问的是类的方法或其他属性,直接返回
31
+ if (prop in target) {
32
+ return target[prop];
33
+ }
34
+
35
+ // 如果字典数据不存在或为空,自动加载
36
+ if (!target.state.dictsData[prop]) {
37
+ target.get(prop).catch((err) => {
38
+ console.error(`加载字典 ${prop} 失败:`, err);
39
+ });
40
+ return target.enhanceDict([], prop); // 返回增强后的空数组
41
+ }
42
+
43
+ // 返回增强后的字典数据
44
+ return target.enhanceDict(target.state.dictsData[prop], prop);
45
+ },
46
+ });
47
+ }
48
+
49
+ // 创建默认字典元数据
50
+ createDefaultMeta(options) {
51
+ return {
52
+ request: () => {},
53
+ label: "label",
54
+ value: "value",
55
+ color: "color",
56
+ children: "children",
57
+ params: null, // 请求参数,支持函数
58
+ immediate: false, // 是否立即加载
59
+ cache: true, // 是否缓存
60
+ dataPath: "data", // 数据路径
61
+ transform: null, // 数据转换函数
62
+ noRepeat: false, // 是否重复加载
63
+ otherPath: null, // 其他路径
64
+ debounceTime: 300, // 防抖时间
65
+ ...options,
66
+ };
67
+ }
68
+
69
+ // 注册字典配置
70
+ register(key, config, override = false) {
71
+ if (this.dictMeta.get(key) && !override) {
72
+ return this;
73
+ }
74
+
75
+ const dictConfig = {
76
+ ...this.defaultMeta,
77
+ ...(typeof config === "function" ? { request: config } : config),
78
+ otherPath: Array.isArray(config.otherPath)
79
+ ? config.otherPath
80
+ : [config.otherPath],
81
+ isCustom: true,
82
+ };
83
+
84
+ // 将本地数据转换为字典管理
85
+ if (config.options) {
86
+ dictConfig.request = () => {
87
+ return new Promise((resolve) => {
88
+ resolve({
89
+ data: config.options,
90
+ });
91
+ });
92
+ };
93
+ return this;
94
+ }
95
+
96
+ this.dictMeta.set(key, dictConfig);
97
+
98
+ // 如果参数是函数,创建监听
99
+ if (typeof dictConfig.params === "function" && !this.dictWatch.get(key)) {
100
+ this.dictWatch.set(
101
+ key,
102
+ this.vm.$watch(
103
+ dictConfig.params,
104
+ (params) => {
105
+ this.get(key, params);
106
+ },
107
+ { deep: true, immediate: dictConfig.immediate }
108
+ )
109
+ );
110
+ }
111
+
112
+ // 如果配置了立即加载且参数不是函数,并且如果之前已经通过 get 获取过数据,立即使用新配置重新加载
113
+ if (
114
+ (dictConfig.immediate && typeof dictConfig.params !== "function") ||
115
+ this.state.dictsData[key] !== undefined
116
+ ) {
117
+ this.get(key, dictConfig.params);
118
+ }
119
+ return this;
120
+ }
121
+
122
+ // 检查参数是否相等
123
+ isParamsEqual(params1, params2) {
124
+ if (!params1 && !params2) return true;
125
+ if (!params1 || !params2) return false;
126
+ return JSON.stringify(params1) === JSON.stringify(params2);
127
+ }
128
+
129
+ // 批量注册
130
+ registerBatch(configs) {
131
+ Object.entries(configs).forEach(([key, config]) => {
132
+ this.register(key, config);
133
+ });
134
+ return this;
135
+ }
136
+
137
+ // 检查参数是否有效
138
+ isValidParams(params) {
139
+ if (!params) return false;
140
+ return Object.values(params).every(
141
+ (value) => value !== null && value !== undefined && value !== ""
142
+ );
143
+ }
144
+
145
+ // 字典数据扩展方法
146
+ enhanceDict(dictData, key) {
147
+ if (!Array.isArray(dictData) || dictData.findLabel) {
148
+ return dictData;
149
+ }
150
+
151
+ const meta = this.dictMeta.get(key) || this.defaultMeta;
152
+ const defineProperties = {
153
+ findLabel: {
154
+ value: (value) => dictData.find((i) => i.value === value)?.label || "",
155
+ configurable: true,
156
+ enumerable: false,
157
+ },
158
+ toMap: {
159
+ value: () => this.formatMap(dictData),
160
+ configurable: true,
161
+ enumerable: false,
162
+ },
163
+ values: {
164
+ value: () => dictData.map((i) => i.value),
165
+ configurable: true,
166
+ enumerable: false,
167
+ },
168
+ labels: {
169
+ value: () => dictData.map((i) => i.label),
170
+ configurable: true,
171
+ enumerable: false,
172
+ },
173
+ getOption: {
174
+ value: (value) => {
175
+ if (Array.isArray(value)) {
176
+ return value.map((i) => dictData.find((j) => j.value === i));
177
+ }
178
+ return dictData.find((i) => i.value === value);
179
+ },
180
+ configurable: true,
181
+ enumerable: false,
182
+ },
183
+ wait: {
184
+ value: () => this.waitFor(key),
185
+ configurable: true,
186
+ enumerable: false,
187
+ },
188
+ ready: {
189
+ value: this.isReady(key),
190
+ configurable: true,
191
+ enumerable: false,
192
+ },
193
+ };
194
+
195
+ // 获取其他路径的数据
196
+ const otherData = this.state.dictsData[`${key}_other`];
197
+ if (otherData) {
198
+ meta.otherPath.forEach((path) => {
199
+ defineProperties[path] = {
200
+ value: otherData[path],
201
+ configurable: true,
202
+ enumerable: false,
203
+ };
204
+ });
205
+ }
206
+
207
+ // 自定义扩展方法
208
+ if (meta.enhanceDict && Object.keys(meta.enhanceDict).length > 0) {
209
+ Object.keys(meta.enhanceDict).forEach((key) => {
210
+ if (typeof meta.enhanceDict[key] === "function") {
211
+ defineProperties[key] = {
212
+ value: (value) => meta.enhanceDict[key](value, key, dictData, meta),
213
+ configurable: true,
214
+ enumerable: false,
215
+ };
216
+ }
217
+ });
218
+ }
219
+
220
+ Object.defineProperties(dictData, defineProperties);
221
+ return dictData;
222
+ }
223
+
224
+ // 设置响应式数据的辅助方法
225
+ setState(key, value, stateKey = "dictsData") {
226
+ this.vue.set(this.state[stateKey], key, value);
227
+ }
228
+
229
+ setParams(key, params) {
230
+ this.vue.set(this.state.dictsParams, key, params);
231
+ }
232
+
233
+ // 获取字典数据
234
+ get(key, params) {
235
+ try {
236
+ const config = this.dictMeta.get(key) || this.defaultMeta;
237
+ const result = this.loadDict(key, config, false, params);
238
+ this.pendingPromises.add(result);
239
+
240
+ result.finally(() => {
241
+ this.pendingPromises.delete(result);
242
+ });
243
+ return result;
244
+ } catch (error) {
245
+ console.error("获取字典数据失败:", error);
246
+ return Promise.reject(error);
247
+ }
248
+ }
249
+
250
+ // 加载字典数据
251
+ loadDict(key, meta, force, params) {
252
+ if (!force && this.isValidCache(key, params)) {
253
+ return Promise.resolve({ key, data: this.state.dictsData[key] });
254
+ }
255
+
256
+ this.setState(key, DictStatus.PENDING, "dictStatus");
257
+ this.setState(key, [], "dictsData");
258
+
259
+ if (this.loadTasks[key] && meta.noRepeat) {
260
+ return this.loadTasks[key];
261
+ }
262
+ const { request } = meta;
263
+ if (!meta.request) {
264
+ const error = new Error(`${key} 字典缺少请求函数`);
265
+ this.handleDictError(key, error);
266
+ return Promise.reject(error);
267
+ }
268
+
269
+ this.loadTasks[key] = new Promise((resolve, reject) => {
270
+ const handleSuccess = (res) => {
271
+ let data = meta.dataPath ? get(res, meta.dataPath) : res;
272
+
273
+ // 处理 otherPath 数据
274
+ if (meta.otherPath) {
275
+ const paths = meta.otherPath;
276
+ const otherData = paths.reduce((acc, path) => {
277
+ acc[path] = get(res, path);
278
+ return acc;
279
+ }, {});
280
+ this.setState(`${key}_other`, otherData, "dictsData");
281
+ }
282
+
283
+ if (!data) {
284
+ resolve({ key, data: [] });
285
+ return;
286
+ }
287
+ if (!Array.isArray(data)) {
288
+ const error = new Error(`${key} 字典返回数据必须为数组`, data);
289
+ this.handleDictError(key, error);
290
+ reject(error);
291
+ return;
292
+ }
293
+ if (meta.transform && typeof meta.transform === "function") {
294
+ data = meta.transform(data);
295
+ data = this.formatDictData(meta, data);
296
+ } else {
297
+ data = this.formatDictData(meta, data);
298
+ }
299
+
300
+ this.setState(key, DictStatus.SUCCESS, "dictStatus");
301
+ this.setState(key, data, "dictsData");
302
+ resolve({ key, data });
303
+
304
+ // 清理任务
305
+ setTimeout(() => {
306
+ this.loadTasks[key] = null;
307
+ }, meta.debounceTime || 0);
308
+ };
309
+
310
+ const handleError = (error) => {
311
+ this.handleDictError(key, error);
312
+ reject(error);
313
+ };
314
+
315
+ try {
316
+ const actualParams = params || this.state.dictsParams[key];
317
+ actualParams && this.setState(key, actualParams, "dictsParams");
318
+ request(meta.isCustom ? actualParams : key)
319
+ .then(handleSuccess)
320
+ .catch(handleError);
321
+ } catch (error) {
322
+ handleError(error);
323
+ }
324
+ });
325
+
326
+ return this.loadTasks[key];
327
+ }
328
+
329
+ // 等待字典加载完成
330
+ async waitFor(key) {
331
+ if (this.isReady(key)) {
332
+ return this.enhanceDict(this.state.dictsData[key], key);
333
+ } else {
334
+ await this.get(key);
335
+ }
336
+
337
+ return this.enhanceDict(this.state.dictsData[key], key);
338
+ }
339
+
340
+ // 等待所有注册的字典加载完成
341
+ async waitAll() {
342
+ return new Promise((resolve, reject) => {
343
+ setTimeout(async () => {
344
+ try {
345
+ if (this.pendingPromises.size === 0) {
346
+ return resolve(this.state.dictsData);
347
+ }
348
+
349
+ await Promise.all(Array.from(this.pendingPromises));
350
+ return resolve(this.state.dictsData);
351
+ } catch (error) {
352
+ this.pendingPromises.clear();
353
+ console.error("等待字典加载失败:", error);
354
+ return reject(error);
355
+ }
356
+ }, 0);
357
+ });
358
+ }
359
+
360
+ wait(key) {
361
+ if (key) {
362
+ return this.waitFor(key);
363
+ }
364
+ return this.waitAll();
365
+ }
366
+
367
+ // 检查字典是否已加载完成
368
+ isReady(key) {
369
+ return this.state.dictStatus[key] === DictStatus.SUCCESS;
370
+ }
371
+
372
+ handleDictError(key, error) {
373
+ this.setState(key, DictStatus.ERROR, "dictStatus");
374
+ console.error(`Dict Error (${key}):`, error);
375
+ }
376
+
377
+ isValidCache(key, params) {
378
+ const config = this.dictMeta.get(key) || this.defaultMeta;
379
+ return (
380
+ !isEmptyData(this.state.dictsData[key]) &&
381
+ config?.cache !== false &&
382
+ this.state.dictStatus[key] === DictStatus.SUCCESS &&
383
+ this.isParamsEqual(this.state.dictsParams[key], params)
384
+ );
385
+ }
386
+
387
+ formatDictData(config, data) {
388
+ return data.map((item) => ({
389
+ color: item[config.color],
390
+ label: item[config.label],
391
+ value: item[config.value],
392
+ children: item[config.children]
393
+ ? this.formatDictData(config, item[config.children])
394
+ : null,
395
+ raw: item,
396
+ }));
397
+ }
398
+
399
+ formatMap(data) {
400
+ const dataMap = {};
401
+ data.forEach((item) => {
402
+ dataMap[item.value] = item;
403
+ if (item.children) {
404
+ this.formatMap(item.children, dataMap);
405
+ }
406
+ });
407
+ return dataMap;
408
+ }
409
+
410
+ clear(key) {
411
+ if (key) {
412
+ this.pendingPromises.delete(this.loadTasks[key]);
413
+ this.loadTasks[key] = null;
414
+ this.dictMeta.delete(key);
415
+ this.state.dictsData[key] = null;
416
+ this.state.dictStatus[key] = null;
417
+ this.state.dictsParams[key] = null;
418
+ const unwatch = this.dictWatch.get(key);
419
+ unwatch && unwatch();
420
+ this.dictWatch.delete(key);
421
+ } else {
422
+ this.pendingPromises.clear();
423
+ this.loadTasks = {};
424
+ this.dictMeta.clear();
425
+ this.state.dictsData = {};
426
+ this.state.dictStatus = {};
427
+ this.state.dictsParams = {};
428
+ this.dictWatch.forEach((unwatch) => unwatch());
429
+ this.dictWatch.clear();
430
+ }
431
+ }
432
+ }
@@ -0,0 +1,94 @@
1
+ import { isPlainObject } from "lodash-es";
2
+
3
+ export default {
4
+ props: {
5
+ // 字典配置
6
+ dict: [Object, String, Function],
7
+ scope: Object,
8
+ prop: String,
9
+ },
10
+ watch: {
11
+ dictConfig: {
12
+ immediate: true,
13
+ handler(val, oldVal) {
14
+ if (val) {
15
+ this.initLocalDict();
16
+ }
17
+ },
18
+ },
19
+ },
20
+
21
+ computed: {
22
+ dictData() {
23
+ if (this.dictConfig) {
24
+ if (isPlainObject(this.dictConfig)) {
25
+ return this.$scDict[this.getDictKey()];
26
+ }
27
+ if (typeof this.dictConfig === "string") {
28
+ return this.$scDict[this.dictConfig];
29
+ }
30
+ }
31
+ },
32
+ dictConfig() {
33
+ const dictConfig =
34
+ typeof this.dict === "function" ? this.dict(this.scope) : this.dict;
35
+ return dictConfig;
36
+ },
37
+ },
38
+
39
+ beforeDestroy() {
40
+ // 只有局部字典需要清理
41
+ if (this.dictConfig?.local) {
42
+ this.$scDict.clear(this.getDictKey());
43
+ }
44
+ },
45
+
46
+ methods: {
47
+ // 初始化局部字典
48
+ initLocalDict() {
49
+ const dict = this.dictConfig;
50
+ if (isPlainObject(dict)) {
51
+ if (dict.local) {
52
+ // 创建字典key
53
+ const dictKey = this.getDictKey();
54
+
55
+ // 注册字典配置
56
+ this.$scDict.register(dictKey, {
57
+ ...dict,
58
+ params:
59
+ typeof dict.params === "function"
60
+ ? () => dict.params(this.scope)
61
+ : dict.params,
62
+ load:
63
+ typeof dict.load === "function"
64
+ ? () => dict.load(this.scope)
65
+ : dict.load,
66
+ immediate: false,
67
+ cache: false, // 局部字典默认不缓存
68
+ });
69
+ } else {
70
+ this.$scDict.register(this.getDictKey(), {
71
+ ...dict,
72
+ params:
73
+ typeof dict.params === "function"
74
+ ? () => dict.params(this.scope)
75
+ : dict.params,
76
+ load:
77
+ typeof dict.load === "function"
78
+ ? () => dict.load(this.scope)
79
+ : dict.load,
80
+ });
81
+ }
82
+ }
83
+ },
84
+
85
+ // 获取字典唯一key
86
+ getDictKey() {
87
+ const dict = this.dictConfig;
88
+ if (dict?.local) {
89
+ return `${this._uid}_${dict?.key || this.prop}`;
90
+ }
91
+ return dict?.key || this.prop;
92
+ },
93
+ },
94
+ };
@@ -0,0 +1,60 @@
1
+ import { curry } from "lodash-es";
2
+ export default {
3
+ methods: {
4
+ /**
5
+ * 批量执行前置操作,支持传入公共参数和不同的特定参数。
6
+ * @param {Array|String} nameList - 前置操作的名称列表
7
+ * @param {Function} done - 前置操作完成后的回调
8
+ * @param {Object} params - 参数。
9
+ */
10
+ runBefore: curry(async function (nameList, done, ...rest) {
11
+ if (typeof nameList === "string") {
12
+ nameList = [nameList];
13
+ }
14
+ let response;
15
+ const promises = nameList.map((name, index) => {
16
+ const eventName = name;
17
+ if (this.$listeners[eventName]) {
18
+ // 存在事件,调用emit触发事件
19
+ return new Promise((resolve) => {
20
+ this.$emit(
21
+ eventName,
22
+ (res) => {
23
+ res && (response = res);
24
+ resolve();
25
+ },
26
+ ...rest
27
+ );
28
+ });
29
+ } else {
30
+ // 如果事件不存在,直接resolve
31
+ return Promise.resolve();
32
+ }
33
+ });
34
+
35
+ // 等待所有Promise完成
36
+ await Promise.all(promises);
37
+
38
+ // 所有操作完成后调用done
39
+ done(response);
40
+ }, 2),
41
+ runAfter(nameList, params, functionParams) {
42
+ if (typeof nameList === "string") {
43
+ nameList = [nameList];
44
+ }
45
+ nameList.forEach((name) => {
46
+ name = name + "After";
47
+ if (this.$listeners[name]) {
48
+ this.$nextTick(() => {
49
+ if (functionParams && typeof functionParams === "function") {
50
+ params = { ...params, ...functionParams() };
51
+ this.$emit(name, params);
52
+ } else {
53
+ this.$emit(name, params);
54
+ }
55
+ });
56
+ }
57
+ });
58
+ },
59
+ },
60
+ };
@@ -0,0 +1,6 @@
1
+ import create from "./create";
2
+ import defaultRender from "./defaultRender";
3
+ import init from "./init";
4
+ import event from "./event";
5
+ import { generateRules } from "./rules";
6
+ export { create, defaultRender, init, event, generateRules };
@@ -0,0 +1,122 @@
1
+ import { merge, cloneDeep, isFunction, isEqualWith, get } from "lodash-es";
2
+ import { mergeTemp, singleMerge, filterColumns } from "utils";
3
+ import configManager from "core/configManager";
4
+
5
+ export default (optionsKey, opts) => {
6
+ return {
7
+ props: {
8
+ scope: {}, // 防止scope携带vue实例导致的问题
9
+ options: {
10
+ type: Object,
11
+ default: () => ({}),
12
+ },
13
+ renderColumns: {
14
+ type: [Array, Function],
15
+ default: () => [],
16
+ },
17
+ },
18
+ data() {
19
+ return {
20
+ attrs: this.$attrs,
21
+ };
22
+ },
23
+ watch: {
24
+ $attrs(v) {
25
+ // 添加函数类型的特殊处理
26
+ const customizer = (a, b) => {
27
+ if (typeof a === "function" && typeof b === "function") {
28
+ return a.toString() === b.toString();
29
+ }
30
+ return undefined;
31
+ };
32
+ if (!isEqualWith(v, this.attrs, customizer)) {
33
+ this.attrs = v;
34
+ }
35
+ },
36
+ },
37
+ computed: {
38
+ initColumns() {
39
+ const columns = this.options.renderColumns || this.renderColumns;
40
+ return isFunction(columns) ? columns() : columns;
41
+ },
42
+ resultOptions() {
43
+ return configManager.getInstance().mergeConfig(
44
+ Object.assign(this.getUserOptions(), {
45
+ renderColumns: this.initColumns,
46
+ }),
47
+ {
48
+ type: optionsKey,
49
+ }
50
+ );
51
+ },
52
+ resultColumns() {
53
+ if (
54
+ this.resultOptions.renderColumns &&
55
+ Array.isArray(this.resultOptions.renderColumns)
56
+ ) {
57
+ return cloneDeep(this.resultOptions.renderColumns)
58
+ .map(this.handleInitColumn)
59
+ .sort((a, b) => a.order - b.order);
60
+ }
61
+ return [];
62
+ },
63
+ },
64
+ methods: {
65
+ getUserOptions() {
66
+ let userOptions = opts || this.options;
67
+ userOptions = cloneDeep(userOptions);
68
+ userOptions.size = userOptions.size || (this.$ELEMENT || {}).size;
69
+ return this.convertKeysToCamelCase(
70
+ Object.assign(userOptions, this.attrs)
71
+ );
72
+ },
73
+ handleInitColumn(col, index) {
74
+ let item = { ...col };
75
+ if (item.presetType) {
76
+ item = mergeTemp("render", item.presetType, item);
77
+ }
78
+ const formatData = get(item, "formatData.type") || item.formatData;
79
+ if (typeof formatData === "string") {
80
+ item.formatData = Object.assign(
81
+ {},
82
+ item.formatData,
83
+ singleMerge("formatData", formatData, item)
84
+ );
85
+ }
86
+ if (!item.prop) item.prop = "prop_" + index;
87
+ if (this.resultOptions.allColumn)
88
+ item = merge(cloneDeep(this.resultOptions.allColumn), item);
89
+ if (this.initColumn) this.initColumn(item, index);
90
+ if (item.children)
91
+ item.children = item.children.map(this.handleInitColumn);
92
+ return item;
93
+ },
94
+ // 继承ref的Method
95
+ extendMethod(ref, exclude = []) {
96
+ const refMethod = Object.entries(ref);
97
+ for (const [key, value] of refMethod) {
98
+ if (
99
+ !(key.includes("$") || key.includes("_")) &&
100
+ isFunction(value) &&
101
+ !this[key] &&
102
+ !exclude.includes(key)
103
+ ) {
104
+ this[key] = value;
105
+ }
106
+ }
107
+ },
108
+ convertKeysToCamelCase(obj) {
109
+ const result = {};
110
+ for (const key in obj) {
111
+ if (obj.hasOwnProperty(key)) {
112
+ const camelCaseKey = key.replace(/([-_][a-z])/gi, (match) =>
113
+ match.toUpperCase().replace("-", "").replace("_", "")
114
+ );
115
+ result[camelCaseKey] = obj[key];
116
+ }
117
+ }
118
+ return result;
119
+ },
120
+ },
121
+ };
122
+ };