@wp1001/ui 2.9.13
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/.env +6 -0
- package/@vant-D4fmGxs6.js +3891 -0
- package/index.js +8419 -0
- package/package.json +59 -0
- package/packages/assets/devtools-detector.js +2 -0
- package/packages/components/xarray/index.js +64 -0
- package/packages/components/xarray/xarray.vue +57 -0
- package/packages/components/xautorows/index.js +35 -0
- package/packages/components/xautorows/xautorows.vue +29 -0
- package/packages/components/xbutton/mobile.js +3 -0
- package/packages/components/xbutton/mobile.vue +9 -0
- package/packages/components/xbutton/pc.js +3 -0
- package/packages/components/xbutton/pc.vue +9 -0
- package/packages/components/xbuttons/mobile.js +51 -0
- package/packages/components/xbuttons/mobile.vue +12 -0
- package/packages/components/xbuttons/pc.js +51 -0
- package/packages/components/xbuttons/pc.vue +16 -0
- package/packages/components/xchart/constants.js +58 -0
- package/packages/components/xchart/index.js +263 -0
- package/packages/components/xchart/utils.js +121 -0
- package/packages/components/xchart/xchart.vue +173 -0
- package/packages/components/xcheckboxs/mobile.js +58 -0
- package/packages/components/xcheckboxs/mobile.vue +38 -0
- package/packages/components/xcheckboxs/pc.js +49 -0
- package/packages/components/xcheckboxs/pc.vue +42 -0
- package/packages/components/xcol/mobile.js +10 -0
- package/packages/components/xcol/mobile.vue +9 -0
- package/packages/components/xcol/pc.js +10 -0
- package/packages/components/xcol/pc.vue +9 -0
- package/packages/components/xdatepicker/mobile.js +71 -0
- package/packages/components/xdatepicker/mobile.vue +44 -0
- package/packages/components/xdatepicker/pc.js +9 -0
- package/packages/components/xdatepicker/pc.vue +12 -0
- package/packages/components/xdialog/mobile.js +60 -0
- package/packages/components/xdialog/mobile.vue +43 -0
- package/packages/components/xdialog/pc.js +64 -0
- package/packages/components/xdialog/pc.vue +51 -0
- package/packages/components/xdict/index.js +47 -0
- package/packages/components/xdict/xdict.vue +9 -0
- package/packages/components/xdistrictselect/mobile.js +79 -0
- package/packages/components/xdistrictselect/mobile.vue +28 -0
- package/packages/components/xdistrictselect/pc.js +127 -0
- package/packages/components/xdistrictselect/pc.vue +32 -0
- package/packages/components/xform/mobile.js +29 -0
- package/packages/components/xform/mobile.vue +43 -0
- package/packages/components/xform/pc.js +42 -0
- package/packages/components/xform/pc.vue +76 -0
- package/packages/components/xform/utils.js +95 -0
- package/packages/components/xformitem/mobile.js +56 -0
- package/packages/components/xformitem/mobile.vue +3 -0
- package/packages/components/xformitem/pc.js +72 -0
- package/packages/components/xformitem/pc.vue +10 -0
- package/packages/components/xformitem/utils.jsx +181 -0
- package/packages/components/xicon/mobile.js +35 -0
- package/packages/components/xicon/mobile.vue +9 -0
- package/packages/components/xicon/pc.js +35 -0
- package/packages/components/xicon/pc.vue +11 -0
- package/packages/components/xinfo/index.js +100 -0
- package/packages/components/xinfo/xinfo.vue +140 -0
- package/packages/components/xlooper/index.js +7 -0
- package/packages/components/xlooper/xlooper.vue +20 -0
- package/packages/components/xpagination/mobile.js +21 -0
- package/packages/components/xpagination/mobile.vue +31 -0
- package/packages/components/xpagination/pc.js +21 -0
- package/packages/components/xpagination/pc.vue +16 -0
- package/packages/components/xpicker/index.js +38 -0
- package/packages/components/xpicker/xpicker.vue +29 -0
- package/packages/components/xradios/mobile.js +40 -0
- package/packages/components/xradios/mobile.vue +22 -0
- package/packages/components/xradios/pc.js +53 -0
- package/packages/components/xradios/pc.vue +43 -0
- package/packages/components/xrow/mobile.js +9 -0
- package/packages/components/xrow/mobile.vue +23 -0
- package/packages/components/xrow/pc.js +9 -0
- package/packages/components/xrow/pc.vue +22 -0
- package/packages/components/xscan/mobile.js +24 -0
- package/packages/components/xscan/mobile.vue +21 -0
- package/packages/components/xscan/pc.js +20 -0
- package/packages/components/xscan/pc.vue +18 -0
- package/packages/components/xsearcher/index.js +198 -0
- package/packages/components/xsearcher/xsearcher.vue +170 -0
- package/packages/components/xselect/mobile.js +86 -0
- package/packages/components/xselect/mobile.vue +24 -0
- package/packages/components/xselect/pc.js +114 -0
- package/packages/components/xselect/pc.vue +55 -0
- package/packages/components/xselect/util.js +66 -0
- package/packages/components/xselectv2/index.js +91 -0
- package/packages/components/xselectv2/xselectv2.vue +46 -0
- package/packages/components/xtable/mobile.js +108 -0
- package/packages/components/xtable/mobile.vue +246 -0
- package/packages/components/xtable/pc.js +143 -0
- package/packages/components/xtable/pc.vue +421 -0
- package/packages/components/xtable/searcher.js +477 -0
- package/packages/components/xtable/searcher.jsx +330 -0
- package/packages/components/xtable/searcher.vue +133 -0
- package/packages/components/xtable/settings.js +80 -0
- package/packages/components/xtable/settings.vue +77 -0
- package/packages/components/xtable/utils.js +692 -0
- package/packages/components/xtabletools/mobile.js +25 -0
- package/packages/components/xtabletools/mobile.vue +126 -0
- package/packages/components/xtabletools/pc.js +18 -0
- package/packages/components/xtabletools/pc.vue +135 -0
- package/packages/components/xtablev2/index.js +53 -0
- package/packages/components/xtablev2/utils.jsx +214 -0
- package/packages/components/xtablev2/xtablev2.vue +147 -0
- package/packages/components/xtags/mobile.js +17 -0
- package/packages/components/xtags/mobile.vue +21 -0
- package/packages/components/xtags/pc.js +17 -0
- package/packages/components/xtags/pc.vue +22 -0
- package/packages/components/xtinymce/index.js +71 -0
- package/packages/components/xtinymce/xtinymce.vue +9 -0
- package/packages/components/xuploader/xfileuploader.js +48 -0
- package/packages/components/xuploader/xfileuploader.vue +54 -0
- package/packages/components/xuploader/ximageuploader.js +53 -0
- package/packages/components/xuploader/ximageuploader.vue +52 -0
- package/packages/comps.js +108 -0
- package/packages/controllers/BaseController.js +125 -0
- package/packages/controllers/CrudController.js +907 -0
- package/packages/controllers/TempCrudController.js +32 -0
- package/packages/controllers/index.js +15 -0
- package/packages/directives/el-table-infinite-scroll.js +55 -0
- package/packages/directives/index.js +5 -0
- package/packages/index.js +81 -0
- package/packages/index.scss +4 -0
- package/packages/layout/breadcrumb/breadcrumb.vue +31 -0
- package/packages/layout/breadcrumb/index.js +41 -0
- package/packages/layout/header/header.vue +281 -0
- package/packages/layout/header/inner.js +11 -0
- package/packages/layout/header/inner.vue +3 -0
- package/packages/layout/mobile-menu.vue +83 -0
- package/packages/layout/mobile-tabs.vue +54 -0
- package/packages/layout/pc.vue +85 -0
- package/packages/layout/screenlock/index.js +129 -0
- package/packages/layout/screenlock/screenlock.vue +85 -0
- package/packages/layout/sidebar/item.js +16 -0
- package/packages/layout/sidebar/item.vue +16 -0
- package/packages/layout/sidebar/menu.js +72 -0
- package/packages/layout/sidebar/menu.vue +106 -0
- package/packages/layout/sidebar/sidebar.vue +147 -0
- package/packages/layout/tagsview/ScrollPane.js +65 -0
- package/packages/layout/tagsview/ScrollPane.vue +24 -0
- package/packages/layout/tagsview/index.js +169 -0
- package/packages/layout/tagsview/index.vue +124 -0
- package/packages/plop/actions/make-fill-admin-partials-action.js +95 -0
- package/packages/plop/generators/make-admin-page.js +39 -0
- package/packages/plop/generators/make-database-admin-pages.js +84 -0
- package/packages/plop/generators/make-page-generator.js +52 -0
- package/packages/plop/generators/make-simple-page.js +20 -0
- package/packages/plop/plopfile.js +24 -0
- package/packages/plop/templates/admin_page/controller.js +3 -0
- package/packages/plop/templates/admin_page/model.js +24 -0
- package/packages/plop/templates/admin_page/{{snakeCase pagename}}-scoped.scss +3 -0
- package/packages/plop/templates/admin_page/{{snakeCase pagename}}.vue +11 -0
- package/packages/plop/templates/simple_page/controller.js +3 -0
- package/packages/plop/templates/simple_page/model.js +6 -0
- package/packages/plop/templates/simple_page/{{snakeCase pagename}}-scoped.scss +3 -0
- package/packages/plop/templates/simple_page/{{snakeCase pagename}}.vue +7 -0
- package/packages/plop/utils/index.js +168 -0
- package/packages/plop/utils/plop-utils.js +86 -0
- package/packages/styles/common.scss +137 -0
- package/packages/styles/element-ui.scss +142 -0
- package/packages/styles/vant.scss +133 -0
- package/packages/styles/variables.scss +23 -0
- package/packages/utils/crypt.js +24 -0
- package/packages/utils/decorators.js +67 -0
- package/packages/utils/disallowDevtools.js +53 -0
- package/packages/utils/effects.js +173 -0
- package/packages/utils/funcs.js +78 -0
- package/packages/utils/index.js +95 -0
- package/packages/utils/message.js +110 -0
- package/packages/utils/middlewares.js +86 -0
- package/packages/utils/model.js +71 -0
- package/packages/utils/modelUtils.js +203 -0
- package/packages/utils/request.js +57 -0
- package/packages/utils/site.js +33 -0
- package/packages/vite-plugins.js +141 -0
- package/publish.sh +12 -0
|
@@ -0,0 +1,907 @@
|
|
|
1
|
+
import { watch, nextTick } from 'vue'
|
|
2
|
+
import BaseController from './BaseController.js'
|
|
3
|
+
import { Message, Confirm, Prompt } from '../utils/message.js'
|
|
4
|
+
const { funcs, highdict, dates } = StardustJs
|
|
5
|
+
const { file, excel } = StardustBrowser
|
|
6
|
+
|
|
7
|
+
class CrudController extends BaseController {
|
|
8
|
+
constructor (props) {
|
|
9
|
+
super(props)
|
|
10
|
+
|
|
11
|
+
const { model, table, dialog, dbModelName = '', idField = 'id', listProp = 'data' } = props
|
|
12
|
+
|
|
13
|
+
this.table = table || model?.table
|
|
14
|
+
this.dialog = dialog || model?.dialog
|
|
15
|
+
this.dbModelName = dbModelName
|
|
16
|
+
this.idField = idField
|
|
17
|
+
this.listProp = listProp
|
|
18
|
+
|
|
19
|
+
// 是否在提交中
|
|
20
|
+
this._isSubmitting = false
|
|
21
|
+
// 上次查询条件,json 字符串
|
|
22
|
+
this._lastSearchParams = null
|
|
23
|
+
// 初始的 limit
|
|
24
|
+
this._initialLimit = this.table?.query?.limit
|
|
25
|
+
|
|
26
|
+
this._dbTable = null
|
|
27
|
+
|
|
28
|
+
this._unwatchs = []
|
|
29
|
+
|
|
30
|
+
nextTick(() => {
|
|
31
|
+
const { name } = this.route
|
|
32
|
+
const unwatch = watch(() => this.router.currentRoute, route => {
|
|
33
|
+
if (name !== route.name) {
|
|
34
|
+
this._unwatchs.forEach(un => un())
|
|
35
|
+
unwatch()
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
onInit () {
|
|
42
|
+
super.onInit()
|
|
43
|
+
this.table?.uid && this._initSearching()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
get dbTable () {
|
|
47
|
+
if (!this._dbTable) {
|
|
48
|
+
let [database, table] = this.dbModelName.split('.')
|
|
49
|
+
if (!table) {
|
|
50
|
+
database = ''
|
|
51
|
+
table = database
|
|
52
|
+
}
|
|
53
|
+
this._dbTable = new this.service.Table(database, table)
|
|
54
|
+
}
|
|
55
|
+
return this._dbTable
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
get form () {
|
|
59
|
+
if (this.model?.form && this.dialog?.form) throw 'conflict of model.form and dialog.form'
|
|
60
|
+
return this.model?.form || this.dialog?.form
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
_getMethods () {
|
|
64
|
+
return [
|
|
65
|
+
...super._getMethods(),
|
|
66
|
+
|
|
67
|
+
'handleKeywordsSearch',
|
|
68
|
+
'handleSearch',
|
|
69
|
+
'handleAdd',
|
|
70
|
+
'handleEdit',
|
|
71
|
+
'handleDelete',
|
|
72
|
+
'handleRowEdit',
|
|
73
|
+
'handleExport',
|
|
74
|
+
'handleSearchExport',
|
|
75
|
+
'handleImport',
|
|
76
|
+
'handleMultiDelete',
|
|
77
|
+
'handleSave',
|
|
78
|
+
'handleSubmit',
|
|
79
|
+
'handleCancel',
|
|
80
|
+
'handleSortChange',
|
|
81
|
+
'handleLoad',
|
|
82
|
+
|
|
83
|
+
'onSearch',
|
|
84
|
+
'onAdd',
|
|
85
|
+
'onEdit',
|
|
86
|
+
'onDelete',
|
|
87
|
+
'onSubmit',
|
|
88
|
+
'onCancel',
|
|
89
|
+
'onRowEdit',
|
|
90
|
+
'onCancelEdit',
|
|
91
|
+
'onExport',
|
|
92
|
+
'onSearchExport',
|
|
93
|
+
'onImport',
|
|
94
|
+
'onMultiDelete',
|
|
95
|
+
|
|
96
|
+
'search',
|
|
97
|
+
'add',
|
|
98
|
+
'update',
|
|
99
|
+
'remove',
|
|
100
|
+
|
|
101
|
+
'getSearchParams',
|
|
102
|
+
'getAddParams',
|
|
103
|
+
'getUpdateParams',
|
|
104
|
+
'getDeleteParams',
|
|
105
|
+
'getSearchExportParams',
|
|
106
|
+
|
|
107
|
+
'injectSearchParams',
|
|
108
|
+
'injectAddParams',
|
|
109
|
+
'injectUpdateParams',
|
|
110
|
+
'injectDeleteParams',
|
|
111
|
+
|
|
112
|
+
'beforeSearch',
|
|
113
|
+
'beforeAdd',
|
|
114
|
+
'beforeEdit',
|
|
115
|
+
'beforeDelete',
|
|
116
|
+
'afterSearch',
|
|
117
|
+
'afterAdd',
|
|
118
|
+
'afterEdit',
|
|
119
|
+
'afterDelete',
|
|
120
|
+
'afterSubmit',
|
|
121
|
+
|
|
122
|
+
'updatePartials',
|
|
123
|
+
|
|
124
|
+
'formatList',
|
|
125
|
+
'injectList',
|
|
126
|
+
'processExportingColumns',
|
|
127
|
+
'processExportingData',
|
|
128
|
+
'processExporting',
|
|
129
|
+
'processImportingData',
|
|
130
|
+
|
|
131
|
+
'_initSearching',
|
|
132
|
+
'_defaultFormatList',
|
|
133
|
+
'_fillRelatedField',
|
|
134
|
+
'_resetForm',
|
|
135
|
+
'_clearValidate',
|
|
136
|
+
'_trimForm',
|
|
137
|
+
'_validateForm',
|
|
138
|
+
'_checkAllNone',
|
|
139
|
+
'_showError',
|
|
140
|
+
'_focusDialogInput'
|
|
141
|
+
]
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async handleKeywordsSearch (keywords) {
|
|
145
|
+
this._lastSearchParams = null
|
|
146
|
+
keywords = keywords.replace(/,/g, ' ').split(' ').filter(k => k)
|
|
147
|
+
if (!keywords.length) return this.handleSearch({ page: 1 })
|
|
148
|
+
let { searchFields, columns } = this.table
|
|
149
|
+
if (!searchFields.length) {
|
|
150
|
+
searchFields = [...new Set(columns.filter(c => {
|
|
151
|
+
if (typeof c.canSearch === 'boolean') return c.canSearch
|
|
152
|
+
return c.prop && c.type !== 'number' && !c.comp && !c.virtual
|
|
153
|
+
}).map(c => c.prop))]
|
|
154
|
+
}
|
|
155
|
+
if (!searchFields.length) return this.handleSearch({ page: 1 })
|
|
156
|
+
const ands = keywords.map(k => {
|
|
157
|
+
const ors = []
|
|
158
|
+
searchFields.forEach(field => {
|
|
159
|
+
ors.push({ [field]: { '[Op.like]': '%' + k + '%' } })
|
|
160
|
+
})
|
|
161
|
+
return { '[Op.or]': ors }
|
|
162
|
+
})
|
|
163
|
+
return this.handleSearch({ page: 1, where: { '[Op.and]': ands } })
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async handleSearch (params, { isInfinite = false } = {}) {
|
|
167
|
+
if (params instanceof Event) params = null
|
|
168
|
+
this.table.isInfinite = isInfinite
|
|
169
|
+
if (this.table.loading || !(await this.beforeSearch(params))) return
|
|
170
|
+
params = this.getSearchParams(params)
|
|
171
|
+
this.injectSearchParams(params)
|
|
172
|
+
this.table.loading = true
|
|
173
|
+
const data = await this.search(params)
|
|
174
|
+
let list = highdict.get(data, this.listProp)
|
|
175
|
+
list = this.formatList(this._defaultFormatList(list, data), data)
|
|
176
|
+
list.forEach(this.injectList)
|
|
177
|
+
Object.assign(this.table, {
|
|
178
|
+
list,
|
|
179
|
+
total: data.total,
|
|
180
|
+
loading: false
|
|
181
|
+
})
|
|
182
|
+
this.afterSearch(list, params, data)
|
|
183
|
+
return data
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async handleAdd () {
|
|
187
|
+
if (!await this.beforeAdd()) return
|
|
188
|
+
this._resetForm()
|
|
189
|
+
Object.assign(this.dialog, {
|
|
190
|
+
visible: true,
|
|
191
|
+
isEditing: false
|
|
192
|
+
})
|
|
193
|
+
await nextTick()
|
|
194
|
+
await funcs.sleep(50)
|
|
195
|
+
this._clearValidate()
|
|
196
|
+
this._focusDialogInput()
|
|
197
|
+
this.afterAdd()
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async handleEdit ({ $index, row }) {
|
|
201
|
+
if (!await this.beforeEdit({ $index, row })) return
|
|
202
|
+
if (this.table?.isRowEdit) {
|
|
203
|
+
row.originData = JSON.stringify(row)
|
|
204
|
+
row.isEditing = true
|
|
205
|
+
} else {
|
|
206
|
+
this._resetForm()
|
|
207
|
+
const form = {
|
|
208
|
+
...this.dialog.form,
|
|
209
|
+
...row
|
|
210
|
+
}
|
|
211
|
+
this.dialog.formItems.forEach(item => {
|
|
212
|
+
if (item.seperator && typeof form[item.prop] === 'string') {
|
|
213
|
+
form[item.prop] = form[item.prop].split(item.seperator)
|
|
214
|
+
}
|
|
215
|
+
})
|
|
216
|
+
Object.assign(this.dialog, {
|
|
217
|
+
visible: true,
|
|
218
|
+
isEditing: true,
|
|
219
|
+
editingIndex: $index,
|
|
220
|
+
editingRow: row,
|
|
221
|
+
form
|
|
222
|
+
})
|
|
223
|
+
await nextTick()
|
|
224
|
+
this.dialog.formRef?.validate().catch(Function())
|
|
225
|
+
this._focusDialogInput()
|
|
226
|
+
}
|
|
227
|
+
this.afterEdit({ $index, row })
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async handleDelete ({ $index, row }) {
|
|
231
|
+
if (this.table.loading) return
|
|
232
|
+
if (!await this.beforeDelete({ $index, row })) return
|
|
233
|
+
const ok = await Confirm.w({ message: '确定要删除吗?', title: '警告' })
|
|
234
|
+
if (!ok) return
|
|
235
|
+
this.table.loading = true
|
|
236
|
+
const params = this.getDeleteParams(row)
|
|
237
|
+
this.injectDeleteParams(params)
|
|
238
|
+
const data = await this.remove(params, row)
|
|
239
|
+
this.table.loading = false
|
|
240
|
+
if (data.err) return
|
|
241
|
+
this.afterDelete(data)
|
|
242
|
+
this.handleSearch()
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async handleRowEdit ({ row }) {
|
|
246
|
+
if (row._loading) return
|
|
247
|
+
row._loading = true
|
|
248
|
+
const params = this.getUpdateParams(row)
|
|
249
|
+
this.injectUpdateParams(params)
|
|
250
|
+
if (!(await this._checkAllNone(params))) {
|
|
251
|
+
row._loading = false
|
|
252
|
+
return
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
await this.update(row[this.idField], params)
|
|
256
|
+
} catch (err) {
|
|
257
|
+
this._showError(err.data.err)
|
|
258
|
+
row._loading = false
|
|
259
|
+
return
|
|
260
|
+
}
|
|
261
|
+
delete row.originData
|
|
262
|
+
row.isEditing = false
|
|
263
|
+
row._loading = false
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async handleCancelEdit ({ row }) {
|
|
267
|
+
Object.assign(row, JSON.parse(row.originData))
|
|
268
|
+
delete row.originData
|
|
269
|
+
row.isEditing = false
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
async handleExport (type = this.exportType, filename) {
|
|
273
|
+
filename ||= this.table.ref.title || document.title
|
|
274
|
+
if (this.table.loading) return
|
|
275
|
+
if (type instanceof Event) type = ''
|
|
276
|
+
type = type || this.config.exportType || 'csv'
|
|
277
|
+
if (!['csv', 'excel'].includes(type)) {
|
|
278
|
+
Message('不支持的导出类型')
|
|
279
|
+
return
|
|
280
|
+
}
|
|
281
|
+
this.table.loading = true
|
|
282
|
+
const { list, selection, ref } = this.table
|
|
283
|
+
let data = selection.length > 0 ? selection : list
|
|
284
|
+
data = funcs.deepCopy(data)
|
|
285
|
+
data = this.processExportingData(data)
|
|
286
|
+
const cols = this.processExportingColumns(ref._visibleColumns, 'current')
|
|
287
|
+
const props = cols.map(col => col.prop)
|
|
288
|
+
const header = cols.map(col => col.label)
|
|
289
|
+
data = data.map(row => props.map(prop => row[prop]))
|
|
290
|
+
let func = null
|
|
291
|
+
if (type === 'csv') {
|
|
292
|
+
func = excel.export2Csv
|
|
293
|
+
} else {
|
|
294
|
+
func = excel.export2Excel
|
|
295
|
+
}
|
|
296
|
+
let options = { list, header, data, filename }
|
|
297
|
+
options = await this.processExporting(options)
|
|
298
|
+
func(options)
|
|
299
|
+
this.table.loading = false
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
async handleSearchExport (type = this.exportType, filename) {
|
|
303
|
+
filename ||= this.table.ref.title || document.title
|
|
304
|
+
if (this.table.loading) {
|
|
305
|
+
Message.w('导出中...')
|
|
306
|
+
return
|
|
307
|
+
}
|
|
308
|
+
type = type || this.config.exportType || 'csv'
|
|
309
|
+
if (!['csv', 'excel'].includes(type)) {
|
|
310
|
+
Message('不支持的导出类型')
|
|
311
|
+
return
|
|
312
|
+
}
|
|
313
|
+
this.table.loading = true
|
|
314
|
+
const res = await this.dbTable.search(this.getSearchExportParams())
|
|
315
|
+
let data = res.data
|
|
316
|
+
data = this.formatList(data, res)
|
|
317
|
+
data.forEach(this.injectList)
|
|
318
|
+
data = this.processExportingData(data, 'search')
|
|
319
|
+
const cols = this.processExportingColumns(this.table.ref._visibleColumns, 'search-export')
|
|
320
|
+
const props = cols.map(col => col.prop)
|
|
321
|
+
const header = cols.map(col => col.label)
|
|
322
|
+
data = data.map(row => props.map(prop => row[prop]))
|
|
323
|
+
let func = null
|
|
324
|
+
if (type === 'csv') {
|
|
325
|
+
func = excel.export2Csv
|
|
326
|
+
} else {
|
|
327
|
+
func = excel.export2Excel
|
|
328
|
+
}
|
|
329
|
+
let options = { list: res.data, header, data, filename }
|
|
330
|
+
options = await this.processExporting(options)
|
|
331
|
+
func(options)
|
|
332
|
+
this.table.loading = false
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
async handleImport () {
|
|
336
|
+
if (this.table.loading) return
|
|
337
|
+
const f = await file.select('.xlsx,.csv')
|
|
338
|
+
this.table.loading = true
|
|
339
|
+
const isCsv = f.name.toLowerCase().endsWith('.csv')
|
|
340
|
+
const content = await file.toType(f, isCsv ? 'text' : 'arraybuffer')
|
|
341
|
+
let data = []
|
|
342
|
+
if (isCsv) {
|
|
343
|
+
await window.DynamicLibs?.use('Papa')
|
|
344
|
+
data = window.Papa.parse(content, { header: true }).data
|
|
345
|
+
} else {
|
|
346
|
+
await window.DynamicLibs?.use('XLSX')
|
|
347
|
+
const workbook = window.XLSX.read(content, {})
|
|
348
|
+
const sheets = Object.values(workbook.Sheets)
|
|
349
|
+
data = XLSX.utils.sheet_to_json(sheets[0])
|
|
350
|
+
}
|
|
351
|
+
if (data.length > 0) {
|
|
352
|
+
const labelPropDict = {}
|
|
353
|
+
this.table.columns.forEach(col => labelPropDict[col.label] = col.prop)
|
|
354
|
+
const labels = Object.keys(data[0])
|
|
355
|
+
data = data.map(row => {
|
|
356
|
+
const ele = {}
|
|
357
|
+
labels.forEach(label => ele[labelPropDict[label]] = row[label])
|
|
358
|
+
return ele
|
|
359
|
+
})
|
|
360
|
+
}
|
|
361
|
+
data = this.processImportingData(data)
|
|
362
|
+
await this.dbTable.func(['bulkCreate', data])
|
|
363
|
+
Message.s('导入成功')
|
|
364
|
+
this.table.loading = false
|
|
365
|
+
this.handleSearch()
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
async handleMultiDelete () {
|
|
369
|
+
if (this.table.loading) return
|
|
370
|
+
const { selection } = this.table
|
|
371
|
+
if (!selection.length) {
|
|
372
|
+
Message.w('尚未选择要删除的数据')
|
|
373
|
+
return
|
|
374
|
+
}
|
|
375
|
+
const ok = await Confirm.w({ title: '警告', message: `确定删除选中的 ${selection.length} 条数据吗?` })
|
|
376
|
+
if (!ok) return
|
|
377
|
+
this.table.loading = true
|
|
378
|
+
const ids = selection.map(ele => ele[this.idField])
|
|
379
|
+
await this.dbTable.func(['destroy', {
|
|
380
|
+
where: {
|
|
381
|
+
[this.idField]: { '[Op.in]': ids }
|
|
382
|
+
}
|
|
383
|
+
}])
|
|
384
|
+
this.table.loading = false
|
|
385
|
+
this.handleSearch()
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
async handleSave (form) {
|
|
389
|
+
form = form instanceof Event ? this.form : form
|
|
390
|
+
if (this._isSubmitting) {
|
|
391
|
+
Message.w('正在保存...')
|
|
392
|
+
return
|
|
393
|
+
}
|
|
394
|
+
const formRef = this.model.formRef || this.dialog.formRef
|
|
395
|
+
if (!(await this._validateForm(formRef))) return
|
|
396
|
+
this._isSubmitting = true
|
|
397
|
+
const params = this.getAddParams(form)
|
|
398
|
+
this.injectAddParams(params)
|
|
399
|
+
if (!(await this._checkAllNone(params))) {
|
|
400
|
+
this._isSubmitting = false
|
|
401
|
+
return
|
|
402
|
+
}
|
|
403
|
+
let data = null
|
|
404
|
+
try {
|
|
405
|
+
if (form[this.idField]) {
|
|
406
|
+
data = await this.update(form[this.idField], params)
|
|
407
|
+
} else {
|
|
408
|
+
data = await this.add(params)
|
|
409
|
+
}
|
|
410
|
+
} catch (err) {
|
|
411
|
+
this._showError(err.data.err)
|
|
412
|
+
this._isSubmitting = false
|
|
413
|
+
return
|
|
414
|
+
}
|
|
415
|
+
this._isSubmitting = false
|
|
416
|
+
if (!data.err) Message.s('保存成功')
|
|
417
|
+
this.router.go(-1)
|
|
418
|
+
return data
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
async handleSubmit (params) {
|
|
422
|
+
params = params instanceof Event ? null : params
|
|
423
|
+
if (this._isSubmitting) {
|
|
424
|
+
Message.w('正在提交...')
|
|
425
|
+
return false
|
|
426
|
+
}
|
|
427
|
+
if (!this.dialog.visible) return false
|
|
428
|
+
this._isSubmitting = true
|
|
429
|
+
const form = params || this.form
|
|
430
|
+
if (!params) {
|
|
431
|
+
if (this.dialog.shouldTrim ?? true) {
|
|
432
|
+
Object.assign(form, this._trimForm(form))
|
|
433
|
+
}
|
|
434
|
+
if (!(await this._validateForm())) {
|
|
435
|
+
Message.w('请正确填写')
|
|
436
|
+
this._isSubmitting = false
|
|
437
|
+
return false
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
let data = null
|
|
441
|
+
try {
|
|
442
|
+
if (this.dialog.isEditing) {
|
|
443
|
+
const params = this.getUpdateParams(form)
|
|
444
|
+
this.injectUpdateParams(params)
|
|
445
|
+
if (!(await this._checkAllNone(params))) {
|
|
446
|
+
this._isSubmitting = false
|
|
447
|
+
return false
|
|
448
|
+
}
|
|
449
|
+
data = await this.update(this.dialog.editingRow[this.idField], params)
|
|
450
|
+
} else {
|
|
451
|
+
const params = this.getAddParams(form)
|
|
452
|
+
this.injectAddParams(params)
|
|
453
|
+
if (!(await this._checkAllNone(params))) {
|
|
454
|
+
this._isSubmitting = false
|
|
455
|
+
return false
|
|
456
|
+
}
|
|
457
|
+
data = await this.add(params)
|
|
458
|
+
}
|
|
459
|
+
} catch (err) {
|
|
460
|
+
this._showError(err.data.err)
|
|
461
|
+
this._isSubmitting = false
|
|
462
|
+
return false
|
|
463
|
+
}
|
|
464
|
+
this.dialog.visible = false
|
|
465
|
+
this._isSubmitting = false
|
|
466
|
+
|
|
467
|
+
if (!data.err) {
|
|
468
|
+
this.handleSearch()
|
|
469
|
+
}
|
|
470
|
+
this.afterSubmit(data)
|
|
471
|
+
return data
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
handleCancel () {
|
|
475
|
+
this.dialog.visible = false
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
handleSortChange (params) {
|
|
479
|
+
if (!params) {
|
|
480
|
+
this.table.query.order = []
|
|
481
|
+
} else if (Array.isArray(params)) {
|
|
482
|
+
this.table.query.order = params
|
|
483
|
+
} else {
|
|
484
|
+
const { prop, order } = params
|
|
485
|
+
this.table.query.order = (!prop || !order) ? [] : [
|
|
486
|
+
[prop, order.slice(0, -6)]
|
|
487
|
+
]
|
|
488
|
+
}
|
|
489
|
+
this.handleSearch()
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
async handleLoad () {
|
|
493
|
+
const { query } = this.table
|
|
494
|
+
if (!this.table.list.length) {
|
|
495
|
+
await this.handleSearch()
|
|
496
|
+
if (query.page * query.limit >= this.table.total) {
|
|
497
|
+
this.table.finished = true
|
|
498
|
+
}
|
|
499
|
+
return this.table.moreLoading = false
|
|
500
|
+
}
|
|
501
|
+
const { loading, total } = this.table
|
|
502
|
+
if (loading || !total || this.table.finished) {
|
|
503
|
+
return this.table.moreLoading = false
|
|
504
|
+
}
|
|
505
|
+
if (query.page * query.limit >= total) {
|
|
506
|
+
this.table.moreLoading = false
|
|
507
|
+
return this.table.finished = true
|
|
508
|
+
}
|
|
509
|
+
this.table.isInfinite = true
|
|
510
|
+
query.page ++
|
|
511
|
+
const list = this.table.list.slice()
|
|
512
|
+
await this.handleSearch({}, { isInfinite: true })
|
|
513
|
+
while (this.table.loading) {
|
|
514
|
+
await this.$sleep(20)
|
|
515
|
+
}
|
|
516
|
+
this.table.loading = true
|
|
517
|
+
await this.$sleep(50)
|
|
518
|
+
this.table.list = list.concat(this.table.list)
|
|
519
|
+
this.table.loading = false
|
|
520
|
+
this.table.moreLoading = false
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
get (id) {
|
|
524
|
+
return this.dbTable.get(id)
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
search (params) {
|
|
528
|
+
this._lastSearchParams = JSON.stringify(params)
|
|
529
|
+
if (this.table?.uid) {
|
|
530
|
+
const key = 'Settings[' + this.table.uid + ']'
|
|
531
|
+
const settings = this.$local.getJson(key, {})
|
|
532
|
+
if (settings.limit || params.limit !== this._initialLimit) {
|
|
533
|
+
settings.limit = params.limit
|
|
534
|
+
}
|
|
535
|
+
if (Object.keys(settings).length) {
|
|
536
|
+
this.$local.setJson(key, settings)
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
return this.dbTable.search(params)
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
add (params) {
|
|
543
|
+
return this.dbTable.add(params)
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
update (id, params) {
|
|
547
|
+
return this.dbTable.update(id, params)
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
remove (params, row) {
|
|
551
|
+
return this.dbTable.remove(params[this.idField])
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
getSearchParams (params, setQuery = true) {
|
|
555
|
+
if (setQuery) {
|
|
556
|
+
if (params?.page) this.table.query.page = params.page
|
|
557
|
+
if (params?.limit) this.table.query.limit = params.limit
|
|
558
|
+
}
|
|
559
|
+
return Object.assign({ where: {} }, JSON.parse(this._lastSearchParams), this.table.query, params)
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
getAddParams (params) {
|
|
563
|
+
const fields = Object.keys(this.dialog.initialForm)
|
|
564
|
+
const data = {}
|
|
565
|
+
if (!fields.length) {
|
|
566
|
+
Object.assign(data, params)
|
|
567
|
+
} else {
|
|
568
|
+
fields.forEach(field => data[field] = params[field])
|
|
569
|
+
}
|
|
570
|
+
this.dialog.formItems.forEach(item => {
|
|
571
|
+
if (!item.model && !item.prop || item.virtual) return
|
|
572
|
+
let value = data[item.model || item.prop]
|
|
573
|
+
if (item.type === 'number') {
|
|
574
|
+
value = this.uiUtils.formatPrecision(value, item.precision || 3) * 1
|
|
575
|
+
} else if (['ElDatePicker', 'el-date-picker', 'XDatePicker', 'x-date-picker'].includes(item.comp)) {
|
|
576
|
+
if (item.type === 'datetime') {
|
|
577
|
+
value = dates.format(value)
|
|
578
|
+
} else if (!item.type || item.type === 'date') {
|
|
579
|
+
value = dates.format(value, '', false)
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
if (Array.isArray(value)) {
|
|
583
|
+
const { seperator = ',' } = item
|
|
584
|
+
if (seperator) {
|
|
585
|
+
value = value.join(seperator)
|
|
586
|
+
}
|
|
587
|
+
} else if (value && typeof value === 'object') {
|
|
588
|
+
value = JSON.stringify(value, null, 4)
|
|
589
|
+
}
|
|
590
|
+
if (value === '') {
|
|
591
|
+
if (item.comp && !['ElInput', 'el-input'].includes(item.comp)) {
|
|
592
|
+
value = null
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
data[item.model || item.prop] = value
|
|
596
|
+
})
|
|
597
|
+
return data
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
getUpdateParams (params) {
|
|
601
|
+
return this.getAddParams(params)
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
getDeleteParams (row) {
|
|
605
|
+
return {
|
|
606
|
+
[this.idField]: row[this.idField]
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
getSearchExportParams () {
|
|
611
|
+
const params = this.getSearchParams()
|
|
612
|
+
this.injectSearchParams(params)
|
|
613
|
+
return Object.assign({}, params, {
|
|
614
|
+
page: 1,
|
|
615
|
+
limit: - 1,
|
|
616
|
+
attributes: this.processExportingColumns(this.table.ref._visibleColumns, 'search-attributes').map(col => col.prop)
|
|
617
|
+
})
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
injectSearchParams (params) { }
|
|
621
|
+
|
|
622
|
+
injectAddParams (params) { }
|
|
623
|
+
|
|
624
|
+
injectUpdateParams (params) {
|
|
625
|
+
this.injectAddParams(params)
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
injectDeleteParams (params) { }
|
|
629
|
+
|
|
630
|
+
beforeSearch (params) { return true }
|
|
631
|
+
|
|
632
|
+
beforeAdd () { return true }
|
|
633
|
+
|
|
634
|
+
beforeEdit ({ $index, row }) { return true }
|
|
635
|
+
|
|
636
|
+
beforeDelete ({ $index, row }) { return true }
|
|
637
|
+
|
|
638
|
+
afterSearch (list, params, data) {
|
|
639
|
+
const stringify = JSON.stringify(params)
|
|
640
|
+
if (this.table.query.count === false && this.table.needCount) {
|
|
641
|
+
if (stringify !== this._lastSearchParams) {
|
|
642
|
+
const { page, limit, order, count, ...others } = params
|
|
643
|
+
this.dbTable.func(['count', others]).then(data => this.table.total = data.data)
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
afterAdd () { }
|
|
649
|
+
|
|
650
|
+
afterEdit ({ $index, row }) { }
|
|
651
|
+
|
|
652
|
+
afterDelete (data) { }
|
|
653
|
+
|
|
654
|
+
afterSubmit (data) { }
|
|
655
|
+
|
|
656
|
+
async updatePartials ({ row }, fields = []) {
|
|
657
|
+
if (!fields.length) return
|
|
658
|
+
this.table.loading = true
|
|
659
|
+
const partials = {}
|
|
660
|
+
fields.forEach(f => partials[f] = row[f])
|
|
661
|
+
await this.update(row[this.idField], partials)
|
|
662
|
+
this.table.loading = false
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
_initSearching () {
|
|
666
|
+
this.table.loading = true
|
|
667
|
+
const params = {}
|
|
668
|
+
const settings = this.$local.getJson('Settings[' + this.table.uid + ']')
|
|
669
|
+
if (settings) {
|
|
670
|
+
if (settings.viewName) {
|
|
671
|
+
const searcher = this.table.ref.$refs.searcher
|
|
672
|
+
const view = searcher.views.find(v => v.name === settings.viewName)
|
|
673
|
+
searcher.setCurrentView(view)
|
|
674
|
+
try {
|
|
675
|
+
Object.assign(params, searcher.calcParams())
|
|
676
|
+
} catch {}
|
|
677
|
+
}
|
|
678
|
+
if (settings.limit) {
|
|
679
|
+
this.table.query.limit = settings.limit
|
|
680
|
+
params.limit = settings.limit
|
|
681
|
+
}
|
|
682
|
+
if (settings.order?.length) {
|
|
683
|
+
this.table.query.order = settings.order
|
|
684
|
+
params.order = settings.order
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
this.table.loading = false
|
|
688
|
+
this.handleSearch(params)
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
_defaultFormatList (list, res) {
|
|
692
|
+
const { columns, query } = this.table
|
|
693
|
+
const { page, limit } = query
|
|
694
|
+
list.forEach((ele, index) => {
|
|
695
|
+
ele._idx = index + 1
|
|
696
|
+
ele._index = (page - 1) * limit + index + 1
|
|
697
|
+
})
|
|
698
|
+
columns.forEach(col => {
|
|
699
|
+
let { prop, options, seperator } = col
|
|
700
|
+
const { format, autoFill } = col.tableAttrs || {}
|
|
701
|
+
const { modelName } = col.formAttrs || {}
|
|
702
|
+
if (modelName && autoFill) {
|
|
703
|
+
list.forEach(ele => ele[`_formatted_${prop}`] = '')
|
|
704
|
+
this._fillRelatedField(list, col)
|
|
705
|
+
} else {
|
|
706
|
+
if (Array.isArray(options) && format !== false) {
|
|
707
|
+
const update = (newVal, oldVal) => {
|
|
708
|
+
const rows = oldVal ? this.table.list : list
|
|
709
|
+
const kvMap = makeOptionsKvMap(col)
|
|
710
|
+
rows.forEach((ele, index) => {
|
|
711
|
+
const value = highdict.get(ele, prop)
|
|
712
|
+
ele[`_formatted_${prop}`] = kvMap[value] || value
|
|
713
|
+
})
|
|
714
|
+
}
|
|
715
|
+
const un = watch(() => col.options, update, { immediate: true, deep: true })
|
|
716
|
+
this._unwatchs.push(un)
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
if (seperator) {
|
|
720
|
+
list.forEach(ele => {
|
|
721
|
+
if (typeof ele[prop] === 'string') {
|
|
722
|
+
ele[prop] = ele[prop].split(seperator)
|
|
723
|
+
}
|
|
724
|
+
})
|
|
725
|
+
}
|
|
726
|
+
})
|
|
727
|
+
return list
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
async _fillRelatedField (list, column) {
|
|
731
|
+
const ids = [...new Set(list.map(ele => ele[column.prop]))]
|
|
732
|
+
if (!ids.length) return
|
|
733
|
+
const { modelName, text, value } = column.formAttrs
|
|
734
|
+
const data = await this.service.restful.search(modelName, {
|
|
735
|
+
limit: -1,
|
|
736
|
+
attributes: [text, value],
|
|
737
|
+
where: {
|
|
738
|
+
[value]: {
|
|
739
|
+
'[Op.in]': ids
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
})
|
|
743
|
+
if (!data.data.length) return
|
|
744
|
+
const dict = highdict.mapField(data.data, value, text)
|
|
745
|
+
this.table.list.forEach(ele => {
|
|
746
|
+
ele[`_formatted_${column.prop}`] = dict[ele[column.prop]]
|
|
747
|
+
})
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
formatList (list, res) {
|
|
751
|
+
return list
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
injectList (ele, index, list) { }
|
|
755
|
+
|
|
756
|
+
processExportingColumns (columns, mode = 'current') {
|
|
757
|
+
return columns.filter(col => {
|
|
758
|
+
return !['index', 'selection', 'expand', 'radio', '_index'].includes(col.type)
|
|
759
|
+
}).filter(col => {
|
|
760
|
+
return mode === 'search-export' ? true : !col.virtual
|
|
761
|
+
})
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
processExportingData (data, mode = 'current') {
|
|
765
|
+
if (!data.length) return data
|
|
766
|
+
const dict = {}
|
|
767
|
+
this.table.ref._visibleColumns.forEach(it => {
|
|
768
|
+
let { formatter = it.formatter, tagValues = it.tagValues, options = it.options } = it.tableAttrs || {}
|
|
769
|
+
if (!formatter && typeof tagValues === 'function') formatter = tagValues
|
|
770
|
+
dict[it.prop] = { formatter, tagValues, options }
|
|
771
|
+
})
|
|
772
|
+
const keys = [...new Set(Object.keys(data[0]).concat(this.table.ref._visibleColumns.map(c => c.prop).filter(p => p)))]
|
|
773
|
+
data.forEach(ele => {
|
|
774
|
+
keys.forEach(key => {
|
|
775
|
+
const value = ele[key]
|
|
776
|
+
if (ele.hasOwnProperty('_formatted_' + key)) return ele[key] = ele['_formatted_' + key]
|
|
777
|
+
if (dict[key]?.formatter) return ele[key] = dict[key].formatter(value, ele)
|
|
778
|
+
if (dict[key]?.tagValues) return ele[key] = dict[key].tagValues[value]
|
|
779
|
+
if (dict[key]?.options) return ele[key] = dict[key].options.find(o => o.value === ele[key])?.text ?? ele[key]
|
|
780
|
+
if (typeof value === 'boolean') {
|
|
781
|
+
ele[key] = value && 1 || 0
|
|
782
|
+
} else if (value instanceof Date) {
|
|
783
|
+
ele[key] = dates.format(value)
|
|
784
|
+
if (ele[key].endsWith(' 00:00:00')) {
|
|
785
|
+
ele[key] = ele[key].slice(0, -9)
|
|
786
|
+
}
|
|
787
|
+
} else if (value === undefined) {
|
|
788
|
+
ele[key] = highdict.get(ele, key)
|
|
789
|
+
}
|
|
790
|
+
})
|
|
791
|
+
})
|
|
792
|
+
data.forEach(ele => {
|
|
793
|
+
keys.forEach(key => {
|
|
794
|
+
if (ele[key] && typeof ele[key] === 'object') {
|
|
795
|
+
ele[key] = JSON.stringify(ele[key])
|
|
796
|
+
}
|
|
797
|
+
})
|
|
798
|
+
})
|
|
799
|
+
return data
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
processExporting (options) { return options }
|
|
803
|
+
|
|
804
|
+
processImportingData (data) {
|
|
805
|
+
data.forEach(ele => {
|
|
806
|
+
delete ele[this.idField]
|
|
807
|
+
delete ele._index
|
|
808
|
+
})
|
|
809
|
+
return data
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
_resetForm (host = this.dialog) {
|
|
813
|
+
host.form = JSON.parse(JSON.stringify(host.initialForm))
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
_trimForm (form) {
|
|
817
|
+
form ||= this.dialog.form
|
|
818
|
+
const trimed = {}
|
|
819
|
+
for (let key in form) {
|
|
820
|
+
if (form[key]?.trim) {
|
|
821
|
+
trimed[key] = form[key].trim()
|
|
822
|
+
} else {
|
|
823
|
+
trimed[key] = form[key]
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
return trimed
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
_validateForm (formRef) {
|
|
830
|
+
const ref = formRef || this.dialog.formRef
|
|
831
|
+
if (ref) {
|
|
832
|
+
return new Promise(resolve => {
|
|
833
|
+
if (this._isMobile) {
|
|
834
|
+
ref.validate().then(() => resolve(true)).catch(() => resolve(false))
|
|
835
|
+
} else {
|
|
836
|
+
ref.validate((ok) => resolve(ok)).catch(() => resolve(false))
|
|
837
|
+
}
|
|
838
|
+
})
|
|
839
|
+
}
|
|
840
|
+
return true
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
_clearValidate (ref = this.dialog.formRef) {
|
|
844
|
+
if (ref) {
|
|
845
|
+
this._isMobile ? ref.resetValidation() : ref.clearValidate()
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
async _checkAllNone (data) {
|
|
850
|
+
const nones = [null, undefined, '']
|
|
851
|
+
const hasValid = Object.values(data).some(v => !nones.includes(v))
|
|
852
|
+
if (hasValid) return true
|
|
853
|
+
return Confirm.w({ message: '表单所有数据都是空,确定要继续提交吗?', title: '警告' })
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
_showError (err) {
|
|
857
|
+
Message(typeof err === 'object' ? (err.message || err.err || err.toString()) : err)
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
_focusDialogInput () {
|
|
861
|
+
const node = document.querySelector('.el-dialog')
|
|
862
|
+
if (!node) return
|
|
863
|
+
let inputs = [...node.querySelectorAll('input')].filter(i => !i.disabled && !i.readonly)
|
|
864
|
+
let input = inputs.find(i => i.type === 'text' || i.type === 'number')
|
|
865
|
+
if (!input) {
|
|
866
|
+
inputs = [...node.querySelectorAll('textarea')].filter(i => !i.disabled && !i.readonly)
|
|
867
|
+
input = inputs[0]
|
|
868
|
+
}
|
|
869
|
+
input?.focus()
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
get _isMobile () {
|
|
873
|
+
const ref = this.table?.formRef || this.dialog?.formRef
|
|
874
|
+
if (ref) {
|
|
875
|
+
return ref.$.attrs.class.indexOf('mobile') >= 0
|
|
876
|
+
}
|
|
877
|
+
return window.isMobile
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
onKeywordsSearch (...props) { return this.handleKeywordsSearch(...props) }
|
|
881
|
+
onSearch (...props) { return this.handleSearch(...props) }
|
|
882
|
+
onAdd (...props) { return this.handleAdd(...props) }
|
|
883
|
+
onEdit (...props) { return this.handleEdit(...props) }
|
|
884
|
+
onDelete (...props) { return this.handleDelete(...props) }
|
|
885
|
+
onSubmit (...props) { return this.handleSubmit(...props) }
|
|
886
|
+
onCancel (...props) { return this.handleCancel(...props) }
|
|
887
|
+
onRowEdit (...props) { return this.handleRowEdit(...props) }
|
|
888
|
+
onCancelEdit (...props) { return this.handleCancelEdit(...props) }
|
|
889
|
+
onExport (...props) { return this.handleExport(...props) }
|
|
890
|
+
onSearchExport (...props) { return this.handleSearchExport(...props) }
|
|
891
|
+
onImport (...props) { return this.handleImport(...props) }
|
|
892
|
+
onMultiDelete (...props) { return this.handleMultiDelete(...props) }
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
const makeOptionsKvMap = (field) => {
|
|
896
|
+
const { options, formAttrs = {} } = field
|
|
897
|
+
const { text = 'text', value = 'value' } = formAttrs
|
|
898
|
+
const kvMap = {}
|
|
899
|
+
if (options && typeof options === 'object' && typeof options[0] === 'object') {
|
|
900
|
+
options.forEach(op => {
|
|
901
|
+
kvMap[op[value]] = op[text]
|
|
902
|
+
})
|
|
903
|
+
}
|
|
904
|
+
return kvMap
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
export default CrudController
|