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.
- package/.browserslistrc +3 -0
- package/.versionrc.json +36 -0
- package/CHANGELOG.md +232 -0
- package/LICENSE +201 -0
- package/README.md +46 -0
- package/babel.config.js +12 -0
- package/build/alias.js +10 -0
- package/build/build.js +52 -0
- package/build/config.js +70 -0
- package/deploy.bat +14 -0
- package/docs/.vuepress/components/button/base.vue +88 -0
- package/docs/.vuepress/components/common/code-format.vue +331 -0
- package/docs/.vuepress/components/commonConfig/presetCodeTemplate/base.vue +68 -0
- package/docs/.vuepress/components/commonConfig/presetCodeTemplate/customParams.vue +73 -0
- package/docs/.vuepress/components/commonConfig/renderType/component.vue +160 -0
- package/docs/.vuepress/components/commonConfig/renderType/formatter.vue +49 -0
- package/docs/.vuepress/components/commonConfig/renderType/render.vue +91 -0
- package/docs/.vuepress/components/commonConfig/renderType/slot.vue +63 -0
- package/docs/.vuepress/components/crud/baseUse/baseUse.vue +98 -0
- package/docs/.vuepress/components/crud/baseUse/columnAction.vue +72 -0
- package/docs/.vuepress/components/crud/baseUse/columnWidth.vue +107 -0
- package/docs/.vuepress/components/crud/baseUse/handleRow.vue +65 -0
- package/docs/.vuepress/components/crud/baseUse/height.vue +82 -0
- package/docs/.vuepress/components/crud/baseUse/index.vue +54 -0
- package/docs/.vuepress/components/crud/baseUse/loading.vue +70 -0
- package/docs/.vuepress/components/crud/baseUse/pagination.vue +108 -0
- package/docs/.vuepress/components/crud/baseUse/selection.vue +114 -0
- package/docs/.vuepress/components/crud/baseUse/summaryMethod.vue +118 -0
- package/docs/.vuepress/components/crud/baseUse/title.vue +54 -0
- package/docs/.vuepress/components/crud/baseUse/toolbar.vue +69 -0
- package/docs/.vuepress/components/crud/buttons/common.vue +115 -0
- package/docs/.vuepress/components/crud/buttons/fast.vue +82 -0
- package/docs/.vuepress/components/crud/contextMenu/base.vue +72 -0
- package/docs/.vuepress/components/crud/copy.vue +52 -0
- package/docs/.vuepress/components/crud/crudEvents/api.vue +157 -0
- package/docs/.vuepress/components/crud/crudEvents/deleteTip.vue +93 -0
- package/docs/.vuepress/components/crud/crudEvents/events.vue +188 -0
- package/docs/.vuepress/components/crud/dataSort/base.vue +142 -0
- package/docs/.vuepress/components/crud/genDynamicColumns/base.vue +53 -0
- package/docs/.vuepress/components/crud/genDynamicColumns/dynamicAndFixed.vue +111 -0
- package/docs/.vuepress/components/crud/genDynamicColumns/treeDynamic.vue +68 -0
- package/docs/.vuepress/components/crud/handleBar/handleRow.vue +65 -0
- package/docs/.vuepress/components/crud/handleBar/toolbar.vue +69 -0
- package/docs/.vuepress/components/crud/renderType/1.vue +57 -0
- package/docs/.vuepress/components/crud/renderType/2.vue +63 -0
- package/docs/.vuepress/components/crud/renderType/3.vue +105 -0
- package/docs/.vuepress/components/crud/renderType/5.vue +91 -0
- package/docs/.vuepress/components/crud/search/1.vue +90 -0
- package/docs/.vuepress/components/crud/search/2.vue +78 -0
- package/docs/.vuepress/components/crud/search/3.vue +107 -0
- package/docs/.vuepress/components/crud/search/base.vue +123 -0
- package/docs/.vuepress/components/crud/search/localSearch.vue +124 -0
- package/docs/.vuepress/components/crud/search/special.vue +148 -0
- package/docs/.vuepress/components/crud/selection/events.vue +47 -0
- package/docs/.vuepress/components/crud/selection/pagination.vue +94 -0
- package/docs/.vuepress/components/crud/selection/singleSelection.vue +64 -0
- package/docs/.vuepress/components/crud/span/base.vue +69 -0
- package/docs/.vuepress/components/crud/span/special.vue +75 -0
- package/docs/.vuepress/components/crud/summary/base.vue +99 -0
- package/docs/.vuepress/components/crud/tableEdit/addDeleteBtn.vue +174 -0
- package/docs/.vuepress/components/crud/tableEdit/cellEdit.vue +194 -0
- package/docs/.vuepress/components/crud/tableEdit/controlEdit.vue +219 -0
- package/docs/.vuepress/components/crud/tableEdit/dialog.vue +172 -0
- package/docs/.vuepress/components/crud/tableEdit/free.vue +88 -0
- package/docs/.vuepress/components/crud/tableEdit/freeColumn.vue +82 -0
- package/docs/.vuepress/components/crud/tableEdit/methods.vue +154 -0
- package/docs/.vuepress/components/crud/tableEdit/rowAction.vue +107 -0
- package/docs/.vuepress/components/crud/tableEdit/rowBatch.vue +116 -0
- package/docs/.vuepress/components/crud/tableEdit/rowClick.vue +98 -0
- package/docs/.vuepress/components/crud/validate/base.vue +122 -0
- package/docs/.vuepress/components/crud/validate/custom.vue +82 -0
- package/docs/.vuepress/components/crud/validate/regulars.vue +88 -0
- package/docs/.vuepress/components/crud/validate/relation.vue +91 -0
- package/docs/.vuepress/components/crud/validate/tree.vue +82 -0
- package/docs/.vuepress/components/dialog/baseUse/base.vue +92 -0
- package/docs/.vuepress/components/dialog/baseUse/beforeConfirm.vue +78 -0
- package/docs/.vuepress/components/dialog/baseUse/control.vue +79 -0
- package/docs/.vuepress/components/dialog/baseUse/drawer.vue +59 -0
- package/docs/.vuepress/components/dialog/baseUse/footer.vue +87 -0
- package/docs/.vuepress/components/dialog/baseUse/insertSlot.vue +79 -0
- package/docs/.vuepress/components/dict/DictLinkage.vue +91 -0
- package/docs/.vuepress/components/dict/baseUse.vue +72 -0
- package/docs/.vuepress/components/dict/component.vue +82 -0
- package/docs/.vuepress/components/dict/localDict.vue +68 -0
- package/docs/.vuepress/components/form/baseUse/base.vue +48 -0
- package/docs/.vuepress/components/form/baseUse/dataFormat.vue +92 -0
- package/docs/.vuepress/components/form/baseUse/deep.vue +57 -0
- package/docs/.vuepress/components/form/baseUse/gridLayout.vue +47 -0
- package/docs/.vuepress/components/form/baseUse/group.vue +66 -0
- package/docs/.vuepress/components/form/baseUse/hidden.vue +40 -0
- package/docs/.vuepress/components/form/baseUse/inlineLayout.vue +48 -0
- package/docs/.vuepress/components/form/baseUse/label.vue +51 -0
- package/docs/.vuepress/components/form/baseUse/tooltip.vue +40 -0
- package/docs/.vuepress/components/form/baseUse/validate.vue +52 -0
- package/docs/.vuepress/components/form/detail/base.vue +78 -0
- package/docs/.vuepress/components/form/detail/border.vue +90 -0
- package/docs/.vuepress/components/form/detail/singleDetail.vue +72 -0
- package/docs/.vuepress/components/formatData/baseUse.vue +131 -0
- package/docs/.vuepress/components/mock/index.js +347 -0
- package/docs/.vuepress/components/mockData/custom.vue +69 -0
- package/docs/.vuepress/components/mockData/example.vue +290 -0
- package/docs/.vuepress/components/positionSlot/base.vue +24 -0
- package/docs/.vuepress/components/positionSlot/form.vue +71 -0
- package/docs/.vuepress/components/positionSlot/table.vue +85 -0
- package/docs/.vuepress/components/tabs/base.vue +57 -0
- package/docs/.vuepress/components/temp.js +195 -0
- package/docs/.vuepress/config.js +146 -0
- package/docs/.vuepress/enhanceApp.js +142 -0
- package/docs/.vuepress/public/favicon.ico +0 -0
- package/docs/.vuepress/public/super.png +0 -0
- package/docs/.vuepress/styles/index.styl +25 -0
- package/docs/.vuepress/styles/palette.styl +6 -0
- package/docs/README.md +14 -0
- package/docs/guide/button/base.md +31 -0
- package/docs/guide/commonConfig/jsx.md +166 -0
- package/docs/guide/commonConfig/presetCodeTemplate.md +68 -0
- package/docs/guide/commonConfig/renderType.md +181 -0
- package/docs/guide/crud/baseUse.md +120 -0
- package/docs/guide/crud/buttons.md +18 -0
- package/docs/guide/crud/config.md +217 -0
- package/docs/guide/crud/contextMenu.md +18 -0
- package/docs/guide/crud/dataSort.md +66 -0
- package/docs/guide/crud/genDynamicColumns.md +145 -0
- package/docs/guide/crud/handleBar.md +26 -0
- package/docs/guide/crud/renderType.md +4 -0
- package/docs/guide/crud/search.md +150 -0
- package/docs/guide/crud/selection.md +73 -0
- package/docs/guide/crud/span.md +98 -0
- package/docs/guide/crud/summary.md +167 -0
- package/docs/guide/crud/tableEdit.md +377 -0
- package/docs/guide/crud/validate.md +158 -0
- package/docs/guide/dialog/baseUse.md +81 -0
- package/docs/guide/dict/baseUse.md +174 -0
- package/docs/guide/dict/component.md +88 -0
- package/docs/guide/dict/config.md +44 -0
- package/docs/guide/form/baseUse.md +142 -0
- package/docs/guide/form/detail.md +38 -0
- package/docs/guide/formatData/baseUse.md +98 -0
- package/docs/guide/formatData/config.md +142 -0
- package/docs/guide/mockData/base.md +26 -0
- package/docs/guide/positionSlot/base.md +41 -0
- package/docs/guide/question/base.md +44 -0
- package/docs/guide/start/base.md +30 -0
- package/docs/guide/tabs/base.md +63 -0
- package/examples/App.vue +52 -0
- package/examples/Layout/components/AppMain.vue +40 -0
- package/examples/Layout/components/Item.vue +29 -0
- package/examples/Layout/components/Link.vue +44 -0
- package/examples/Layout/components/SidebarItem.vue +93 -0
- package/examples/Layout/index.vue +69 -0
- package/examples/assets/logo.png +0 -0
- package/examples/favicon.ico +0 -0
- package/examples/index.html +18 -0
- package/examples/main.js +54 -0
- package/examples/router/index.js +140 -0
- package/examples/store/index.js +0 -0
- package/examples/styles/index.scss +63 -0
- package/examples/styles/sidebar.scss +226 -0
- package/examples/styles/transition.scss +48 -0
- package/examples/styles/variables.scss +25 -0
- package/examples/views/crud/base.vue +68 -0
- package/examples/views/crud/handleRow.vue +84 -0
- package/examples/views/crud/search.vue +116 -0
- package/examples/views/dashboard/index.vue +244 -0
- package/examples/views/dashboard/index1.vue +234 -0
- package/examples/views/dashboard/test.vue +9 -0
- package/examples/views/formTest/index.vue +168 -0
- package/examples/views/nested/menu1/index.vue +7 -0
- package/examples/views/nested/menu1/menu1-1/index.vue +7 -0
- package/examples/views/nested/menu1/menu1-2/index.vue +7 -0
- package/examples/views/nested/menu1/menu1-2/menu1-2-1/index.vue +5 -0
- package/examples/views/nested/menu1/menu1-2/menu1-2-2/index.vue +5 -0
- package/examples/views/nested/menu1/menu1-3/index.vue +5 -0
- package/examples/views/nested/menu2/index.vue +5 -0
- package/gulpfile.js +84 -0
- package/lib/index.css +1 -0
- package/lib/super-crud.min.js +15 -0
- package/package.json +66 -0
- package/packages/button/index.vue +189 -0
- package/packages/core/components/comp.vue +223 -0
- package/packages/core/components/position.vue +135 -0
- package/packages/core/components/render.vue +460 -0
- package/packages/core/configManager.js +302 -0
- package/packages/core/create.js +8 -0
- package/packages/core/defaultRender.js +64 -0
- package/packages/core/dict/global.js +10 -0
- package/packages/core/dict/index.js +432 -0
- package/packages/core/dict/mixin.js +94 -0
- package/packages/core/event.js +60 -0
- package/packages/core/index.js +6 -0
- package/packages/core/init.js +122 -0
- package/packages/core/mock/genConfig.js +228 -0
- package/packages/core/mock/genData.js +422 -0
- package/packages/core/mock/index.js +4 -0
- package/packages/core/rules.js +111 -0
- package/packages/crud/column.vue +205 -0
- package/packages/crud/columnAction.vue +207 -0
- package/packages/crud/columnCell.vue +146 -0
- package/packages/crud/defaultColumn.vue +130 -0
- package/packages/crud/drawerColumn.vue +225 -0
- package/packages/crud/form.vue +69 -0
- package/packages/crud/index.vue +564 -0
- package/packages/crud/menuBar.vue +298 -0
- package/packages/crud/mixins/cacheHandler.js +36 -0
- package/packages/crud/mixins/calcColumnWidth.js +79 -0
- package/packages/crud/mixins/calcHeight.js +105 -0
- package/packages/crud/mixins/columnHandler.js +128 -0
- package/packages/crud/mixins/contextMenu.js +98 -0
- package/packages/crud/mixins/dataProcessor.js +202 -0
- package/packages/crud/mixins/dialog.js +109 -0
- package/packages/crud/mixins/excelHandler.js +150 -0
- package/packages/crud/mixins/exposeMethods.js +107 -0
- package/packages/crud/mixins/generateDynamicColumns.js +250 -0
- package/packages/crud/mixins/props.js +38 -0
- package/packages/crud/mixins/searchHandler.js +151 -0
- package/packages/crud/mixins/select.js +359 -0
- package/packages/crud/mixins/spanMethod.js +288 -0
- package/packages/crud/mixins/summary.js +177 -0
- package/packages/crud/mixins/tableEdit.js +547 -0
- package/packages/crud/mixins/validate.js +219 -0
- package/packages/crud/pagination.vue +110 -0
- package/packages/crud/search.vue +119 -0
- package/packages/crud/searchHeader.vue +231 -0
- package/packages/crud/selectBanner.vue +138 -0
- package/packages/crud/utils/EditState.js +319 -0
- package/packages/crud/utils/excelExport.js +112 -0
- package/packages/crud/utils/excelImport.js +112 -0
- package/packages/crud/utils/index.js +98 -0
- package/packages/dialog/dialog.js +233 -0
- package/packages/dialog/dialog.vue +15 -0
- package/packages/dialog/index.js +22 -0
- package/packages/dict/cascadeFormat.vue +179 -0
- package/packages/dict/dateFormat.vue +40 -0
- package/packages/dict/form/cascade.vue +61 -0
- package/packages/dict/form/checkbox.vue +90 -0
- package/packages/dict/form/extendMethod.js +22 -0
- package/packages/dict/form/input-base.js +31 -0
- package/packages/dict/form/input.js +20 -0
- package/packages/dict/form/radio.vue +69 -0
- package/packages/dict/form/select.vue +118 -0
- package/packages/dict/form/switch.vue +75 -0
- package/packages/dict/valueFormat.vue +188 -0
- package/packages/directive/dialog/drag.js +86 -0
- package/packages/directive/dialog/dragSize.js +42 -0
- package/packages/directive/index.js +9 -0
- package/packages/directive/insertSlot.js +10 -0
- package/packages/form/contextMenu.js +192 -0
- package/packages/form/draftDrawer.vue +391 -0
- package/packages/form/formAction.vue +97 -0
- package/packages/form/formItem.vue +259 -0
- package/packages/form/index.vue +451 -0
- package/packages/form/props.js +15 -0
- package/packages/grid/cell.vue +65 -0
- package/packages/grid/index.vue +130 -0
- package/packages/group/index.vue +96 -0
- package/packages/tabs/index.vue +290 -0
- package/packages/tooltip/index.js +9 -0
- package/packages/tooltip/tooltip.vue +32 -0
- package/packages/tooltip/tooltipComponent.js +38 -0
- package/packages/verifyInput/index.vue +131 -0
- package/src/config/common.js +88 -0
- package/src/config/crud.js +567 -0
- package/src/config/dialog.js +87 -0
- package/src/config/form.js +215 -0
- package/src/config/index.js +9 -0
- package/src/constants/index.js +72 -0
- package/src/index.js +67 -0
- package/src/template/btn/crud.js +6 -0
- package/src/template/btn/dialog.js +1 -0
- package/src/template/btn/form.js +3 -0
- package/src/template/btn/index.js +9 -0
- package/src/template/dicts.js +1 -0
- package/src/template/formatData.js +507 -0
- package/src/template/index.js +19 -0
- package/src/template/render.js +124 -0
- package/src/template/rules.js +53 -0
- package/src/utils/bem.js +49 -0
- package/src/utils/cache.js +77 -0
- package/src/utils/getType.js +34 -0
- package/src/utils/index.js +212 -0
- package/src/utils/mergeTemp.js +124 -0
- package/styles/button.scss +3 -0
- package/styles/crud.scss +425 -0
- package/styles/dialog.scss +95 -0
- package/styles/form.scss +532 -0
- package/styles/group.scss +78 -0
- package/styles/index.scss +94 -0
- package/styles/tabs.scss +139 -0
- package/styles/verifyInput.scss +56 -0
- package/vue-jsx-sync.js +90 -0
- package/vue.config.js +54 -0
@@ -0,0 +1,228 @@
|
|
1
|
+
export function getComponentConfig(vnode) {
|
2
|
+
const instance = getRealComponent(vnode);
|
3
|
+
if (!instance) return null;
|
4
|
+
|
5
|
+
const name = instance.$options.name;
|
6
|
+
const props = instance.$props || {};
|
7
|
+
|
8
|
+
// 公共配置
|
9
|
+
const commonConfig = {
|
10
|
+
...props,
|
11
|
+
disabled: !!instance.disabled,
|
12
|
+
};
|
13
|
+
|
14
|
+
// 特殊配置组件
|
15
|
+
const specialConfig = {
|
16
|
+
ElInput: {
|
17
|
+
type: "input",
|
18
|
+
subtype: props.type || "text",
|
19
|
+
},
|
20
|
+
ElInputNumber: {
|
21
|
+
type: "number",
|
22
|
+
},
|
23
|
+
ElSelect: {
|
24
|
+
type: "select",
|
25
|
+
options: getSelectOptions(instance),
|
26
|
+
},
|
27
|
+
ElDatePicker: {
|
28
|
+
type: "date",
|
29
|
+
pickerType: props.type || "date",
|
30
|
+
},
|
31
|
+
ElRadioGroup: {
|
32
|
+
type: "radio",
|
33
|
+
options: getRadioOptions(instance),
|
34
|
+
},
|
35
|
+
ElRadio: {
|
36
|
+
type: "radio",
|
37
|
+
options: [
|
38
|
+
{
|
39
|
+
label: instance.label,
|
40
|
+
value: instance.value ?? instance.label,
|
41
|
+
},
|
42
|
+
],
|
43
|
+
},
|
44
|
+
ElRadioButton: {
|
45
|
+
type: "radio",
|
46
|
+
options: [
|
47
|
+
{
|
48
|
+
label: instance.label,
|
49
|
+
value: instance.value ?? instance.label,
|
50
|
+
},
|
51
|
+
],
|
52
|
+
},
|
53
|
+
ElCheckboxGroup: {
|
54
|
+
type: "checkbox",
|
55
|
+
options: getCheckboxOptions(instance),
|
56
|
+
},
|
57
|
+
};
|
58
|
+
|
59
|
+
// 简单组件配置
|
60
|
+
const simpleTypes = {
|
61
|
+
ElTimePicker: "time",
|
62
|
+
ElTimeSelect: "time",
|
63
|
+
ElCheckbox: "checkbox",
|
64
|
+
ElCascader: "cascader",
|
65
|
+
ElSlider: "slider",
|
66
|
+
ElRate: "rate",
|
67
|
+
ElTransfer: "transfer",
|
68
|
+
ElSwitch: "switch",
|
69
|
+
};
|
70
|
+
|
71
|
+
if (specialConfig[name]) {
|
72
|
+
return {
|
73
|
+
...commonConfig,
|
74
|
+
...specialConfig[name],
|
75
|
+
};
|
76
|
+
}
|
77
|
+
|
78
|
+
if (simpleTypes[name]) {
|
79
|
+
return {
|
80
|
+
...commonConfig,
|
81
|
+
type: simpleTypes[name],
|
82
|
+
};
|
83
|
+
}
|
84
|
+
|
85
|
+
return null;
|
86
|
+
}
|
87
|
+
|
88
|
+
/**
|
89
|
+
* 获取选择器的选项
|
90
|
+
*/
|
91
|
+
function getSelectOptions(instance) {
|
92
|
+
return findChildComponents(instance, {
|
93
|
+
name: "ElOption",
|
94
|
+
multiple: true,
|
95
|
+
}).map((option) => ({
|
96
|
+
label: option.label,
|
97
|
+
value: option.value ?? option.label,
|
98
|
+
disabled: !!option.disabled,
|
99
|
+
}));
|
100
|
+
}
|
101
|
+
|
102
|
+
/**
|
103
|
+
* 获取单选框组的选项
|
104
|
+
*/
|
105
|
+
function getRadioOptions(instance) {
|
106
|
+
return findChildComponents(instance, {
|
107
|
+
name: ["ElRadio", "ElRadioButton"],
|
108
|
+
multiple: true,
|
109
|
+
}).map((radio) => ({
|
110
|
+
label: radio.label,
|
111
|
+
value: radio.value ?? radio.label,
|
112
|
+
disabled: !!radio.disabled,
|
113
|
+
}));
|
114
|
+
}
|
115
|
+
|
116
|
+
/**
|
117
|
+
* 获取复选框组的选项
|
118
|
+
*/
|
119
|
+
function getCheckboxOptions(instance) {
|
120
|
+
return findChildComponents(instance, {
|
121
|
+
name: "ElCheckbox",
|
122
|
+
multiple: true,
|
123
|
+
}).map((checkbox) => ({
|
124
|
+
label: checkbox.label,
|
125
|
+
value: checkbox.value ?? checkbox.label,
|
126
|
+
disabled: !!checkbox.disabled,
|
127
|
+
}));
|
128
|
+
}
|
129
|
+
|
130
|
+
/**
|
131
|
+
* 获取真实组件实例
|
132
|
+
*/
|
133
|
+
function getRealComponent(vnode) {
|
134
|
+
if (!vnode?.componentInstance) return;
|
135
|
+
|
136
|
+
let instance = vnode.componentInstance;
|
137
|
+
let name = instance.$options.name;
|
138
|
+
|
139
|
+
// el表单组件
|
140
|
+
const formComponents = [
|
141
|
+
"ElInput",
|
142
|
+
"ElInputNumber",
|
143
|
+
"ElSelect",
|
144
|
+
"ElDatePicker",
|
145
|
+
"ElTimePicker",
|
146
|
+
"ElTimeSelect",
|
147
|
+
"ElRadioGroup",
|
148
|
+
"ElRadio",
|
149
|
+
"ElCheckboxGroup",
|
150
|
+
"ElCheckbox",
|
151
|
+
"ElCascader",
|
152
|
+
"ElSwitch",
|
153
|
+
"ElSlider",
|
154
|
+
"ElRate",
|
155
|
+
"ElColorPicker",
|
156
|
+
"ElUpload",
|
157
|
+
"ElTransfer",
|
158
|
+
];
|
159
|
+
|
160
|
+
while (instance && !formComponents.includes(name)) {
|
161
|
+
const children = instance.$children || [];
|
162
|
+
const childInstance = children[0];
|
163
|
+
if (!childInstance) break;
|
164
|
+
instance = childInstance;
|
165
|
+
name = instance.$options.name;
|
166
|
+
}
|
167
|
+
|
168
|
+
return instance;
|
169
|
+
}
|
170
|
+
|
171
|
+
/**
|
172
|
+
* 查找特定子组件
|
173
|
+
* @param {Object} instance - 组件实例
|
174
|
+
* @param {Object} options - 查找选项
|
175
|
+
* @param {String} options.name - 组件名称
|
176
|
+
* @param {Function} options.filter - 自定义过滤函数
|
177
|
+
* @param {Boolean} options.deep - 是否深度查找,默认true
|
178
|
+
* @param {Boolean} options.multiple - 是否查找多个,默认false
|
179
|
+
* @returns {Array|Object|null} - 返回找到的组件实例
|
180
|
+
*/
|
181
|
+
export function findChildComponents(instance, options = {}) {
|
182
|
+
const { name, filter, deep = true, multiple = false } = options;
|
183
|
+
|
184
|
+
if (!instance?.$children) {
|
185
|
+
return multiple ? [] : null;
|
186
|
+
}
|
187
|
+
|
188
|
+
// 处理名称匹配逻辑
|
189
|
+
const matchName = (componentName) => {
|
190
|
+
if (!name) return true;
|
191
|
+
if (Array.isArray(name)) {
|
192
|
+
return name.includes(componentName);
|
193
|
+
}
|
194
|
+
return componentName === name;
|
195
|
+
};
|
196
|
+
|
197
|
+
const result = [];
|
198
|
+
|
199
|
+
// 查找逻辑
|
200
|
+
function find(children) {
|
201
|
+
for (const child of children) {
|
202
|
+
// 检查组件是否匹配
|
203
|
+
const nameMatch = matchName(child.$options.name);
|
204
|
+
const isMatch = nameMatch && (filter ? filter(child) : true);
|
205
|
+
|
206
|
+
if (isMatch) {
|
207
|
+
result.push(child);
|
208
|
+
// 如果不需要多个结果且已找到,则提前返回
|
209
|
+
if (!multiple) {
|
210
|
+
return true;
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
// 深度查找
|
215
|
+
if (deep && child.$children?.length) {
|
216
|
+
const found = find(child.$children);
|
217
|
+
if (found && !multiple) {
|
218
|
+
return true;
|
219
|
+
}
|
220
|
+
}
|
221
|
+
}
|
222
|
+
return false;
|
223
|
+
}
|
224
|
+
|
225
|
+
find(instance.$children);
|
226
|
+
|
227
|
+
return multiple ? result : result[0] || null;
|
228
|
+
}
|
@@ -0,0 +1,422 @@
|
|
1
|
+
import Mock from "mockjs";
|
2
|
+
const Random = Mock.Random;
|
3
|
+
|
4
|
+
/**
|
5
|
+
* 预设的数据生成规则
|
6
|
+
*/
|
7
|
+
const PRESET_RULES = {
|
8
|
+
// 数字相关
|
9
|
+
integer: (min = 1, max = 100) => Random.integer(min, max), // 整数
|
10
|
+
float: (min = 1, max = 100, precision = 2) =>
|
11
|
+
Random.float(min, max, 0, precision), // 浮点数
|
12
|
+
|
13
|
+
// 文本相关
|
14
|
+
chinese: (min = 2, max = 4) => Random.cword(min, max), // 中文字符
|
15
|
+
english: (min = 3, max = 8) => Random.word(min, max), // 英文字符
|
16
|
+
paragraph: (min = 1, max = 3) => Random.cparagraph(min, max), // 中文段落
|
17
|
+
sentence: (min = 3, max = 8) => Random.csentence(min, max), // 中文句子
|
18
|
+
|
19
|
+
// 特殊格式
|
20
|
+
email: () => Random.email(), // 邮箱
|
21
|
+
phone: () => Mock.mock(/^1[3-9]\d{9}$/), // 手机号
|
22
|
+
id: () => Mock.mock(/^\d{18}$/), // 18位数字
|
23
|
+
date: (format = "yyyy-MM-dd") => Random.date(format), // 日期
|
24
|
+
time: (format = "HH:mm:ss") => Random.time(format), // 时间
|
25
|
+
datetime: (format = "yyyy-MM-dd HH:mm:ss") => Random.datetime(format), // 日期时间
|
26
|
+
timestamp: () => Random.datetime("T"), // 时间戳
|
27
|
+
|
28
|
+
// 列表生成
|
29
|
+
array: (generator, length = 1) => {
|
30
|
+
const count =
|
31
|
+
typeof length === "number"
|
32
|
+
? length
|
33
|
+
: Random.integer(length[0], length[1]);
|
34
|
+
return Array.from({ length: count }, () =>
|
35
|
+
typeof generator === "function" ? generator() : generator
|
36
|
+
);
|
37
|
+
},
|
38
|
+
|
39
|
+
// 图片相关
|
40
|
+
image: (width = 100, height = 100) => Random.image(`${width}x${height}`),
|
41
|
+
imageUrl: (seed = 1, width = 100, height = 100) =>
|
42
|
+
`https://picsum.photos/seed/${seed}/${width}/${height}`,
|
43
|
+
url: () => Random.url(),
|
44
|
+
|
45
|
+
// 其他
|
46
|
+
pick: (arr) => Random.pick(arr), // 从数组中随机选择
|
47
|
+
uuid: () => Random.guid(), // 唯一标识
|
48
|
+
};
|
49
|
+
|
50
|
+
export function generateCustomMockData(m, scope) {
|
51
|
+
if (typeof m === "function") {
|
52
|
+
return m(
|
53
|
+
{
|
54
|
+
Random,
|
55
|
+
Mock,
|
56
|
+
Preset: PRESET_RULES,
|
57
|
+
},
|
58
|
+
scope
|
59
|
+
);
|
60
|
+
}
|
61
|
+
return m;
|
62
|
+
}
|
63
|
+
|
64
|
+
const typeGenerators = {
|
65
|
+
input: generateInputValue,
|
66
|
+
number: generateNumberValue,
|
67
|
+
select: generateSelectValue,
|
68
|
+
date: generateDateValue,
|
69
|
+
time: generateTimeValue,
|
70
|
+
radio: generateRadioValue,
|
71
|
+
checkbox: generateCheckboxValue,
|
72
|
+
cascader: generateCascaderValue,
|
73
|
+
switch: generateSwitchValue,
|
74
|
+
slider: generateSliderValue,
|
75
|
+
rate: generateRateValue,
|
76
|
+
transfer: generateTransferValue,
|
77
|
+
};
|
78
|
+
|
79
|
+
/**
|
80
|
+
* 根据配置生成 mock 数据
|
81
|
+
*/
|
82
|
+
export function generateMockData(config, options = {}) {
|
83
|
+
if (!config) return null;
|
84
|
+
|
85
|
+
const { yearRange = 1, pattern } = options;
|
86
|
+
|
87
|
+
if (config.disabled) {
|
88
|
+
return undefined;
|
89
|
+
}
|
90
|
+
|
91
|
+
if (pattern) {
|
92
|
+
return Mock.mock(pattern);
|
93
|
+
}
|
94
|
+
|
95
|
+
const generator = typeGenerators[config.type];
|
96
|
+
if (generator) {
|
97
|
+
return generator(config, { yearRange });
|
98
|
+
}
|
99
|
+
|
100
|
+
return undefined;
|
101
|
+
}
|
102
|
+
|
103
|
+
function generateInputValue(config) {
|
104
|
+
const { subtype, maxLength = 10, minLength = 1 } = config;
|
105
|
+
|
106
|
+
switch (subtype) {
|
107
|
+
case "email":
|
108
|
+
return Random.email();
|
109
|
+
case "url":
|
110
|
+
return Random.url();
|
111
|
+
case "number":
|
112
|
+
return Random.string("number", minLength, maxLength);
|
113
|
+
case "tel":
|
114
|
+
case "phone":
|
115
|
+
return Mock.mock(/^1[3-9]\d{9}$/);
|
116
|
+
case "textarea":
|
117
|
+
return Random.cparagraph(1, 3);
|
118
|
+
default:
|
119
|
+
return Random.cword(minLength, maxLength);
|
120
|
+
}
|
121
|
+
}
|
122
|
+
|
123
|
+
function generateNumberValue(config) {
|
124
|
+
const { min = 1, max = 100, precision = 0 } = config;
|
125
|
+
const factor = Math.pow(10, precision);
|
126
|
+
return Math.round(Random.float(min, max) * factor) / factor;
|
127
|
+
}
|
128
|
+
|
129
|
+
function generateSelectValue(config) {
|
130
|
+
const { options = [], multiple, multipleLimit = 3 } = config;
|
131
|
+
|
132
|
+
if (!options.length) return multiple ? [] : undefined;
|
133
|
+
|
134
|
+
if (multiple) {
|
135
|
+
const availableOptions = options.filter((opt) => !opt.disabled);
|
136
|
+
const maxCount = multipleLimit || availableOptions.length;
|
137
|
+
const count = Random.integer(1, maxCount);
|
138
|
+
const values = Random.pick(
|
139
|
+
availableOptions.map((opt) => opt.value),
|
140
|
+
count
|
141
|
+
);
|
142
|
+
return Array.isArray(values) ? values : [values];
|
143
|
+
}
|
144
|
+
|
145
|
+
const availableOptions = options.filter((opt) => !opt.disabled);
|
146
|
+
if (!availableOptions.length) return undefined;
|
147
|
+
|
148
|
+
const option = Random.pick(availableOptions);
|
149
|
+
return option.value;
|
150
|
+
}
|
151
|
+
|
152
|
+
function generateDateValue(config, options = {}) {
|
153
|
+
const { pickerType, valueFormat } = config;
|
154
|
+
const { yearRange = 1 } = options;
|
155
|
+
|
156
|
+
// 计算日期范围
|
157
|
+
const now = new Date();
|
158
|
+
const minDate = new Date(now);
|
159
|
+
minDate.setFullYear(now.getFullYear() - yearRange);
|
160
|
+
|
161
|
+
// 如果配置中有指定范围,则使用配置的范围
|
162
|
+
const startDate = config.min ? new Date(config.min) : minDate;
|
163
|
+
const endDate = config.max ? new Date(config.max) : now;
|
164
|
+
|
165
|
+
// 辅助函数:生成指定范围内的随机日期
|
166
|
+
function getRandomDate() {
|
167
|
+
const timestamp =
|
168
|
+
startDate.getTime() +
|
169
|
+
Math.random() * (endDate.getTime() - startDate.getTime());
|
170
|
+
const date = new Date(timestamp);
|
171
|
+
if (valueFormat) {
|
172
|
+
return formatDate(date, valueFormat);
|
173
|
+
}
|
174
|
+
return date.toISOString().split("T")[0];
|
175
|
+
}
|
176
|
+
|
177
|
+
// 辅助函数:格式化日期
|
178
|
+
function formatDate(date, format) {
|
179
|
+
const year = date.getFullYear();
|
180
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
181
|
+
const day = String(date.getDate()).padStart(2, "0");
|
182
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
183
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
184
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
185
|
+
|
186
|
+
return format
|
187
|
+
.replace(/yyyy/g, year)
|
188
|
+
.replace(/MM/g, month)
|
189
|
+
.replace(/dd/g, day)
|
190
|
+
.replace(/HH/g, hours)
|
191
|
+
.replace(/mm/g, minutes)
|
192
|
+
.replace(/ss/g, seconds);
|
193
|
+
}
|
194
|
+
|
195
|
+
switch (pickerType) {
|
196
|
+
case "datetime": {
|
197
|
+
const date = new Date(
|
198
|
+
startDate.getTime() +
|
199
|
+
Math.random() * (endDate.getTime() - startDate.getTime())
|
200
|
+
);
|
201
|
+
return valueFormat ? formatDate(date, valueFormat) : date.toISOString();
|
202
|
+
}
|
203
|
+
|
204
|
+
case "daterange":
|
205
|
+
case "datetimerange": {
|
206
|
+
const date1 = getRandomDate();
|
207
|
+
let date2;
|
208
|
+
do {
|
209
|
+
date2 = getRandomDate();
|
210
|
+
} while (date2 <= date1);
|
211
|
+
return [date1, date2];
|
212
|
+
}
|
213
|
+
|
214
|
+
case "month": {
|
215
|
+
const date = new Date(
|
216
|
+
startDate.getTime() +
|
217
|
+
Math.random() * (endDate.getTime() - startDate.getTime())
|
218
|
+
);
|
219
|
+
return valueFormat
|
220
|
+
? formatDate(date, valueFormat)
|
221
|
+
: `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(
|
222
|
+
2,
|
223
|
+
"0"
|
224
|
+
)}`;
|
225
|
+
}
|
226
|
+
|
227
|
+
case "year": {
|
228
|
+
const startYear = startDate.getFullYear();
|
229
|
+
const endYear = endDate.getFullYear();
|
230
|
+
const year =
|
231
|
+
startYear + Math.floor(Math.random() * (endYear - startYear + 1));
|
232
|
+
return valueFormat
|
233
|
+
? formatDate(new Date(year, 0, 1), valueFormat)
|
234
|
+
: String(year);
|
235
|
+
}
|
236
|
+
|
237
|
+
case "dates": {
|
238
|
+
const count = Random.integer(1, 3);
|
239
|
+
const dates = new Set();
|
240
|
+
while (dates.size < count) {
|
241
|
+
dates.add(getRandomDate());
|
242
|
+
}
|
243
|
+
return Array.from(dates).sort();
|
244
|
+
}
|
245
|
+
|
246
|
+
default:
|
247
|
+
return getRandomDate();
|
248
|
+
}
|
249
|
+
}
|
250
|
+
|
251
|
+
function generateTimeValue(config) {
|
252
|
+
const {
|
253
|
+
isRange,
|
254
|
+
valueFormat = "HH:mm:ss",
|
255
|
+
format = "HH:mm:ss",
|
256
|
+
min = "01:00:00",
|
257
|
+
max = "23:59:59",
|
258
|
+
step = 1,
|
259
|
+
} = config;
|
260
|
+
|
261
|
+
// 辅助函数:生成随机时间
|
262
|
+
function generateTime() {
|
263
|
+
const [minHour, minMinute, minSecond = "00"] = min.split(":").map(Number);
|
264
|
+
const [maxHour, maxMinute, maxSecond = "59"] = max.split(":").map(Number);
|
265
|
+
|
266
|
+
const minTotal = minHour * 3600 + minMinute * 60 + minSecond;
|
267
|
+
const maxTotal = maxHour * 3600 + maxMinute * 60 + maxSecond;
|
268
|
+
|
269
|
+
let totalSeconds = Random.integer(minTotal, maxTotal);
|
270
|
+
totalSeconds = Math.floor(totalSeconds / step) * step;
|
271
|
+
|
272
|
+
const hours = Math.floor(totalSeconds / 3600);
|
273
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
274
|
+
const seconds = totalSeconds % 60;
|
275
|
+
|
276
|
+
const timeStr = [hours, minutes, seconds]
|
277
|
+
.map((num) => String(num).padStart(2, "0"))
|
278
|
+
.join(":");
|
279
|
+
|
280
|
+
return valueFormat.includes("ss") ? timeStr : timeStr.slice(0, 5);
|
281
|
+
}
|
282
|
+
|
283
|
+
if (isRange) {
|
284
|
+
const time1 = generateTime();
|
285
|
+
let time2;
|
286
|
+
do {
|
287
|
+
time2 = generateTime();
|
288
|
+
} while (time2 <= time1);
|
289
|
+
return [time1, time2];
|
290
|
+
}
|
291
|
+
|
292
|
+
return generateTime();
|
293
|
+
}
|
294
|
+
|
295
|
+
function generateRadioValue(config) {
|
296
|
+
const { options = [] } = config;
|
297
|
+
if (!options.length) return undefined;
|
298
|
+
|
299
|
+
const availableOptions = options.filter((opt) => !opt.disabled);
|
300
|
+
if (!availableOptions.length) return undefined;
|
301
|
+
|
302
|
+
const option = Random.pick(availableOptions);
|
303
|
+
return option.value;
|
304
|
+
}
|
305
|
+
|
306
|
+
function generateCheckboxValue(config) {
|
307
|
+
if (config.trueLabel !== undefined) {
|
308
|
+
return Random.boolean() ? config.trueLabel : config.falseLabel;
|
309
|
+
}
|
310
|
+
|
311
|
+
const { options = [], min = 1, max = options.length } = config;
|
312
|
+
if (!options.length) return [];
|
313
|
+
|
314
|
+
const availableOptions = options.filter((opt) => !opt.disabled);
|
315
|
+
const count = Random.integer(min, Math.min(max, availableOptions.length));
|
316
|
+
|
317
|
+
const values = Random.pick(
|
318
|
+
availableOptions.map((opt) => opt.value),
|
319
|
+
count
|
320
|
+
);
|
321
|
+
return Array.isArray(values) ? values : [values];
|
322
|
+
}
|
323
|
+
|
324
|
+
function generateCascaderValue(config) {
|
325
|
+
const { options = [], props = {} } = config;
|
326
|
+
|
327
|
+
// 获取完整的路径(直到叶子节点)
|
328
|
+
function getFullPath(items, currentPath = []) {
|
329
|
+
if (!items?.length) return currentPath;
|
330
|
+
|
331
|
+
const item = Random.pick(items);
|
332
|
+
currentPath.push(item[props.value || "value"]);
|
333
|
+
|
334
|
+
const children = item[props.children || "children"];
|
335
|
+
if (!children?.length) return currentPath;
|
336
|
+
|
337
|
+
// 如果不是任意级别选择,必须选到最后一级
|
338
|
+
if (!props.checkStrictly) {
|
339
|
+
return getFullPath(children, currentPath);
|
340
|
+
}
|
341
|
+
|
342
|
+
// 如果是任意级别选择,随机决定是否继续选择子级
|
343
|
+
return Math.random() < 0.5
|
344
|
+
? currentPath
|
345
|
+
: getFullPath(children, currentPath);
|
346
|
+
}
|
347
|
+
|
348
|
+
// 获取随机路径
|
349
|
+
function getRandomPath(items) {
|
350
|
+
if (!items?.length) return [];
|
351
|
+
return getFullPath(items);
|
352
|
+
}
|
353
|
+
|
354
|
+
if (props.multiple) {
|
355
|
+
// 生成1-3个路径
|
356
|
+
const count = Random.integer(1, 3);
|
357
|
+
const paths = new Set(); // 使用Set避免重复路径
|
358
|
+
|
359
|
+
while (paths.size < count) {
|
360
|
+
const path = getRandomPath(options);
|
361
|
+
paths.add(JSON.stringify(path)); // 转成字符串以便Set去重
|
362
|
+
}
|
363
|
+
|
364
|
+
return Array.from(paths).map((path) => JSON.parse(path));
|
365
|
+
}
|
366
|
+
|
367
|
+
return getRandomPath(options);
|
368
|
+
}
|
369
|
+
|
370
|
+
function generateSwitchValue(config) {
|
371
|
+
const { activeValue = true, inactiveValue = false } = config;
|
372
|
+
return Random.boolean() ? activeValue : inactiveValue;
|
373
|
+
}
|
374
|
+
|
375
|
+
function generateSliderValue(config) {
|
376
|
+
const { min = 1, max = 100, step = 1, range = false } = config;
|
377
|
+
|
378
|
+
// 根据step调整值
|
379
|
+
const adjustValueByStep = (value) => {
|
380
|
+
if (!step || step === 1) return value;
|
381
|
+
// 计算最接近的合法值
|
382
|
+
return Math.round(value / step) * step;
|
383
|
+
};
|
384
|
+
|
385
|
+
if (range) {
|
386
|
+
// 生成范围值
|
387
|
+
const value1 = adjustValueByStep(Random.integer(min, max - step));
|
388
|
+
const value2 = adjustValueByStep(Random.integer(value1 + step, max));
|
389
|
+
return [value1, value2];
|
390
|
+
}
|
391
|
+
|
392
|
+
// 生成单个值
|
393
|
+
return adjustValueByStep(Random.integer(min, max));
|
394
|
+
}
|
395
|
+
|
396
|
+
function generateRateValue(config) {
|
397
|
+
const { max = 5, allowHalf = false } = config;
|
398
|
+
|
399
|
+
if (allowHalf) {
|
400
|
+
// 生成0.5的倍数
|
401
|
+
const value = Random.integer(1, max * 2) / 2;
|
402
|
+
return value;
|
403
|
+
}
|
404
|
+
return Random.integer(1, max);
|
405
|
+
}
|
406
|
+
|
407
|
+
function generateTransferValue(config) {
|
408
|
+
const { data = [] } = config;
|
409
|
+
|
410
|
+
if (!data.length) return [];
|
411
|
+
|
412
|
+
// 随机选择1-3个可用的值
|
413
|
+
const availableValues = data
|
414
|
+
.filter((item) => !item.disabled)
|
415
|
+
.map((item) => item.key || item.value);
|
416
|
+
|
417
|
+
const count = Random.integer(1, Math.min(3, availableValues.length));
|
418
|
+
const selectedValues = Random.pick(availableValues, count);
|
419
|
+
|
420
|
+
// 如果是数组则返回数组,否则返回单个值
|
421
|
+
return Array.isArray(selectedValues) ? selectedValues : [selectedValues];
|
422
|
+
}
|