Commit 4ae177c1c3a0608311f573b0061c1b0f13bdbbd2

Authored by 刘汉宸
1 parent 57f06f4f

feat: 修改SchemaPage组件

examples/views/docs/component/schema-page.md
... ... @@ -29,7 +29,7 @@ export default {
29 29 { prop: 'name', label: '姓名' },
30 30 { prop: 'age', label: '年龄' },
31 31 { prop: 'address', label: '地址' },
32   - { prop: 'status', label: '状态' },
  32 + { prop: 'status', label: '状态', render: (value, row, h) => h('el-tag', { props: { size: 'mini', type: 'info' } }, value) },
33 33 ]
34 34 },
35 35 form: {
... ... @@ -89,7 +89,7 @@ export default {
89 89 { prop: 'name', label: '姓名' },
90 90 { prop: 'age', label: '年龄' },
91 91 { prop: 'address', label: '地址' },
92   - { prop: 'status', label: '状态' },
  92 + { prop: 'status', label: '状态', render: (value, row, h) => h('el-tag', { props: { size: 'mini', type: 'info' } }, value) },
93 93 ]
94 94 },
95 95 form: {
... ... @@ -122,7 +122,7 @@ export default {
122 122  
123 123 本组件预置了增删改查逻辑,因此分别对应`api-search`、`api-new`、`api-edit`、`api-get`、`api-delete`五个基本接口。
124 124  
125   -::: snippet 接口格式为返回一个**Promise**对象的**Function**。其中,`api-search`的执行结果必须是{ list: [...], total: n }的格式,`api-get`的执行结果必须与`valur-form`相对应,`api-new`、`api-edit`、`api-delete`保持默认的**Promise**的resolve或reject逻辑即可,详情见示例。
  125 +::: snippet 接口格式为返回一个**Promise**对象的**Function**。其中,`api-search`的执行结果必须是[分页数据, 数据总数]的格式,`api-get`的执行结果必须与`valur-form`相对应,`api-new`、`api-edit`、`api-delete`保持默认的**Promise**的resolve或reject逻辑即可,详情见示例。
126 126  
127 127 ```html
128 128 <template>
... ... @@ -159,7 +159,7 @@ export default {
159 159 { prop: 'name', label: '姓名' },
160 160 { prop: 'age', label: '年龄' },
161 161 { prop: 'address', label: '地址' },
162   - { prop: 'status', label: '状态' },
  162 + { prop: 'status', label: '状态', render: (value, row, h) => h('el-tag', { props: { size: 'mini', type: 'info' } }, value) },
163 163 ]
164 164 },
165 165 form: {
... ... @@ -187,10 +187,7 @@ export default {
187 187 { id: '4', name: '崔倍', age: 27, address: '地址4', status: '正常' },
188 188 { id: '5', name: '孙豹', age: 38, address: '地址5', status: '正常' },
189 189 ]
190   - resolve({
191   - list,
192   - total: list.length
193   - });
  190 + resolve([list, 37]);
194 191 }, 500);
195 192 });
196 193 },
... ... @@ -279,7 +276,7 @@ export default {
279 276 { prop: 'name', label: '姓名' },
280 277 { prop: 'age', label: '年龄' },
281 278 { prop: 'address', label: '地址' },
282   - { prop: 'status', label: '状态' },
  279 + { prop: 'status', label: '状态', render: (value, row, h) => h('el-tag', { props: { size: 'mini', type: 'info' } }, value) },
283 280 ]
284 281 },
285 282 form: {
... ... @@ -317,10 +314,7 @@ export default {
317 314 { id: '4', name: '崔倍', age: 27, address: '地址4', status: '正常' },
318 315 { id: '5', name: '孙豹', age: 38, address: '地址5', status: '正常' },
319 316 ]
320   - resolve({
321   - list,
322   - total: list.length
323   - });
  317 + resolve([list, 37]);
324 318 }, 500);
325 319 });
326 320 },
... ... @@ -431,7 +425,7 @@ export default {
431 425 { prop: 'name', label: '姓名' },
432 426 { prop: 'age', label: '年龄' },
433 427 { prop: 'address', label: '地址' },
434   - { prop: 'status', label: '状态' },
  428 + { prop: 'status', label: '状态', render: (value, row, h) => h('el-tag', { props: { size: 'mini', type: 'info' } }, value) },
435 429 ]
436 430 },
437 431 form: {
... ... @@ -535,7 +529,7 @@ export default {
535 529 { prop: 'name', label: '姓名' },
536 530 { prop: 'age', label: '年龄' },
537 531 { prop: 'address', label: '地址' },
538   - { prop: 'status', label: '状态' },
  532 + { prop: 'status', label: '状态', render: (value, row, h) => h('el-tag', { props: { size: 'mini', type: 'info' } }, value) },
539 533 ]
540 534 },
541 535 form: {
... ...
packages/schema-page/index copy.scss
... ... @@ -1,72 +0,0 @@
1   -.z-schema {
2   - &__header {
3   - margin-bottom: 10px;
4   - }
5   - &__filter {
6   - border: 1px solid #ebeef5;
7   - padding-top: 10px;
8   - border-radius: 4px;
9   - margin-bottom: 10px;
10   - }
11   - &__action {
12   - display: flex;
13   - flex-wrap: wrap;
14   - align-items: center;
15   - justify-content: flex-start;
16   - line-height: 1;
17   - .el-button + .el-button {
18   - margin-left: 0;
19   - }
20   - .el-button {
21   - margin-right: 10px;
22   - margin-bottom: 10px;
23   - }
24   - }
25   - &__table {
26   - &-operation {
27   - display: flex;
28   - flex-wrap: wrap;
29   - align-items: center;
30   - justify-content: flex-start;
31   - .el-button + .el-button {
32   - margin-left: 0;
33   - }
34   - .el-button {
35   - margin-right: 10px;
36   - padding-top: 6px;
37   - padding-bottom: 6px;
38   - }
39   - }
40   - }
41   - &__dialog-button {
42   - display: flex;
43   - align-items: center;
44   - justify-content: center;
45   - padding-top: 10px;
46   - }
47   - &__footer {
48   - margin-top: 10px;
49   - text-align: right;
50   - display: flex;
51   - justify-content: space-between;
52   - align-items: center;
53   - .selection-info {
54   - word-break: break-all;
55   - white-space: nowrap;
56   - font-size: 12px;
57   - color: #606266;
58   - .num {
59   - color: #000;
60   - font-weight: bold;
61   - padding: 0 5px;
62   - font-size: 16px;
63   - }
64   - .el-button {
65   - margin-left: 5px;
66   - }
67   - }
68   - .el-pagination {
69   - flex: auto;
70   - }
71   - }
72   -}
73 0 \ No newline at end of file
packages/schema-page/index copy.vue
... ... @@ -1,649 +0,0 @@
1   -<style lang="scss">
2   -@import './index.scss';
3   -</style>
4   -
5   -<template>
6   - <div class="z-schema">
7   - <!-- 头部内容 -->
8   - <div v-if="$scopedSlots.header || $slots.header" class="z-schema__header">
9   - <slot name="header" :filterModel="filterModel" v-bind="_slotScope"></slot>
10   - </div>
11   - <!-- 筛选组件 -->
12   - <div v-if="filter" class="z-schema__filter">
13   - <z-schema-filter
14   - :value="_filterModel"
15   - :list="filterList || listMap.filter | noRulesFilter"
16   - :size="size"
17   - @input="onFilterInput"
18   - @search="onSearch"
19   - :loading="loading"
20   - v-bind="filterProps"
21   - :params="_slotScope"
22   - ></z-schema-filter>
23   - </div>
24   - <!-- 按钮区 -->
25   - <div v-if="action" class="z-schema__action">
26   - <slot v-if="hadSlot('action')" name="action" v-bind="_slotScope"></slot>
27   - <template v-else>
28   - <el-button :size="size" type="primary" @click="openNew">新增</el-button>
29   - <el-button :size="size" plain :disabled="selection.length === 0" @click="handleDeleteMul(selection)">删除</el-button>
30   - <slot name="button" v-bind="_slotScope"></slot>
31   - </template>
32   - </div>
33   - <!-- 表格内容 -->
34   - <div class="z-schema__table">
35   - <z-schema-table
36   - ref="table"
37   - v-model="tableData"
38   - v-loading="loading"
39   - :list="tableList || listMap.table"
40   - :tableProps="{ border: true, 'row-key': 'id', 'highlight-current-row': true, ...tableProps }"
41   - :size="size"
42   - @selection-change="onTableSelectionChange"
43   - @selection="onTableSelection"
44   - >
45   - <slot></slot>
46   - <!-- 表格列内容渲染 -->
47   - <template v-for="(item, index) in renderList">
48   - <template v-if="$scopedSlots[`cell-${item.fullKey}`]">
49   - <el-table-column :slot="item.fullKey" v-bind="item" :prop="item.agentKey || item.key" :key="`table-cell-${index}`">
50   - <template slot-scope="{ row, column, $index }">
51   - <slot :name="`cell-${item.fullKey}`" v-bind="{ ...item, ..._slotScope }" :row="row" :value="row[item.key]" :column="column" :index="$index"></slot>
52   - </template>
53   - </el-table-column>
54   - </template>
55   - <template v-else-if="$scopedSlots[`render-${item.fullKey}`]">
56   - <el-table-column :slot="item.fullKey" v-bind="item" :prop="item.agentKey || item.key" :key="`table-render-${index}`">
57   - <template slot-scope="{ row, column, $index }">
58   - <slot :name="`render-${item.fullKey}`" v-bind="{ ...item, ..._slotScope }" :row="row" :value="row[item.key]" :column="column" :index="$index"></slot>
59   - </template>
60   - </el-table-column>
61   - </template>
62   - </template>
63   - <slot slot="column-append" name="column-append" v-bind="_slotScope"></slot>
64   - <!-- 表格尾追加操作列 -->
65   - <template #column-end>
66   - <slot slot="column-end" name="column-end" v-bind="_slotScope"></slot>
67   - <el-table-column v-if="operation" prop="$operation" label="操作" v-bind="{ width: 100, fixed: 'right', ...operationProps }">
68   - <div class="z-schema__table-operation" slot-scope="slotScope">
69   - <slot name="operation-button" v-bind="{ ..._slotScope, slotScope }"></slot>
70   - <el-button type="text" icon="el-icon-edit" title="编辑" @click="openEdit(slotScope.row)"></el-button>
71   - <el-popconfirm confirmButtonText="确定" cancelButtonText="取消" title="确定删除吗?" placement="top" @confirm="handleDelete([slotScope.row])">
72   - <el-button slot="reference" type="text" icon="el-icon-delete" title="删除"></el-button>
73   - </el-popconfirm>
74   - <slot name="operation-button-append" v-bind="{ ..._slotScope, slotScope }"></slot>
75   - </div>
76   - </el-table-column>
77   - </template>
78   - </z-schema-table>
79   - </div>
80   - <!-- 底部区域 -->
81   - <div class="z-schema__footer">
82   - <div v-if="selection.length > 0" class="selection-info">
83   - <span>已选中</span>
84   - <span class="num">{{ selection.length }}</span>
85   - <span>项</span>
86   - <el-popconfirm confirmButtonText="确定" cancelButtonText="取消" title="确定清除吗?" placement="top" @confirm="clearSelection">
87   - <el-button slot="reference" :size="size" type="text">清除</el-button>
88   - </el-popconfirm>
89   - </div>
90   - <!-- 分页器 -->
91   - <el-pagination
92   - v-if="pagination"
93   - @size-change="handleSizeChange"
94   - @current-change="handleCurrentChange"
95   - :current-page="currentPage"
96   - :page-sizes="pageSizes"
97   - :page-size="pageSize"
98   - layout="total, sizes, prev, pager, next, jumper"
99   - :total="total"
100   - >
101   - </el-pagination>
102   - </div>
103   - <!-- 弹出框 -->
104   - <el-dialog
105   - :visible.sync="dialogVisible"
106   - :title="dialogTitle"
107   - destroy-on-close
108   - append-to-body
109   - :lock-scroll="false"
110   - :close-on-click-modal="false"
111   - @closed="onDialogClosed"
112   - @close="onDialogClose"
113   - v-bind="_dialogProps"
114   - >
115   - <div v-loading="dialogLoading">
116   - <!-- 自定义弹出框标题 -->
117   - <slot v-if="hadSlot('dialog-title')" slot="title" name="dialog-title" :dialogType="dialogType" v-bind="_slotScope"></slot>
118   - <template v-if="dialogRender">
119   - <!-- 自定义弹出框内容 -->
120   - <slot v-if="hadSlot(`dialog-${dialogType}`)" :name="`dialog-${dialogType}`" :model="_formModel" v-bind="_slotScope"></slot>
121   - <template v-else>
122   - <!-- 内置弹出框新增修改表单 -->
123   - <template v-if="['new', 'edit'].includes(dialogType)">
124   - <z-form
125   - ref="form"
126   - :value="_formModel"
127   - :list="formList || listMap.form"
128   - @input="onFormInput"
129   - @validate="onFormValidate"
130   - v-bind="{ span: 12, 'label-width': '110px', ...formProps }"
131   - :params="_slotScope"
132   - >
133   - <!-- 表单自定义插槽 -->
134   - <template v-for="item in renderList">
135   - <template v-if="$scopedSlots[`form-${item.fullKey}`]">
136   - <slot :slot="item.fullKey" :name="`form-${item.fullKey}`" :value="get(_formModel, item.fullKey)" :row="_formModel" :model="_formModel" v-bind="_slotScope"></slot>
137   - </template>
138   - </template>
139   - </z-form>
140   - </template>
141   - <!-- 内置弹出框详情表单 -->
142   - <template v-else>
143   - <z-form
144   - ref="form"
145   - class="z-schema__view"
146   - :value="_formModel"
147   - :list="viewList || listMap.form | viewTypeFilter | noRulesFilter"
148   - v-bind="{ span: 12, 'label-width': '110px', ...viewProps }"
149   - :params="_slotScope"
150   - >
151   - <!-- 详情自定义插槽渲染 -->
152   - <template v-for="item in renderList">
153   - <template v-if="$scopedSlots[`view-${item.fullKey}`]">
154   - <slot :slot="item.fullKey" :name="`view-${item.fullKey}`" :value="get(_formModel, item.fullKey)" :row="_formModel" :model="_formModel" v-bind="_slotScope"></slot>
155   - </template>
156   - <template v-else-if="$scopedSlots[`render-${item.fullKey}`]">
157   - <slot :slot="item.fullKey" :name="`render-${item.fullKey}`" :value="get(_formModel, item.fullKey)" :row="_formModel" :model="_formModel" v-bind="_slotScope"></slot>
158   - </template>
159   - </template>
160   - </z-form>
161   - </template>
162   - </template>
163   - <!-- 内置弹出框新增修改按钮 -->
164   - <div class="z-schema__dialog-button" v-if="['new', 'edit'].includes(dialogType)">
165   - <el-button :size="size" type="primary" @click="handleConfirm" :loading="submitting">确定</el-button>
166   - <el-button :size="size" plain @click="closeDialog">取消</el-button>
167   - </div>
168   - </template>
169   - </div>
170   - </el-dialog>
171   - </div>
172   -</template>
173   -
174   -<script>
175   -import { cloneDeep, get } from '../utils';
176   -import { clear } from '../utils/param';
177   -
178   -let propsMap = {};
179   -const propsKeys = ['tableProps', 'filterProps', 'formProps', 'viewProps', 'dialogProps', 'operationProps'];
180   -propsKeys.forEach(key => {
181   - propsMap[key] = {
182   - type: Object,
183   - default: () => ({}),
184   - };
185   -});
186   -const apiKeys = ['searchApi', 'submitApi', 'addApi', 'modifyApi', 'getApi', 'viewApi', 'deleteApi'];
187   -apiKeys.forEach(key => {
188   - propsMap[key] = {
189   - type: Function,
190   - };
191   -});
192   -const blockKeys = ['filter', 'action', 'pagination', 'operation'];
193   -blockKeys.forEach(key => {
194   - propsMap[key] = {
195   - type: Boolean,
196   - default: true,
197   - };
198   -});
199   -
200   -export default {
201   - name: 'SchemaPage',
202   - props: {
203   - ...propsMap,
204   - list: Array,
205   - filterList: Array,
206   - tableList: Array,
207   - formList: Array,
208   - viewList: Array,
209   - size: {
210   - type: String,
211   - default: 'mini',
212   - },
213   - formModel: Object,
214   - filterModel: Object,
215   - auto: Boolean,
216   - realSelection: Boolean,
217   - url: String, // 请求地址
218   - http: Function, // http库
219   - alias: Object, // 别名配置
220   - },
221   - data() {
222   - return {
223   - filterForm: {},
224   - editForm: {},
225   - dialogVisible: false,
226   - dialogRender: true,
227   - dialogType: 'none',
228   - dialogLoading: false,
229   - dialogTitle: '',
230   - dialogPropsHack: {},
231   - currentPage: 1,
232   - pageSize: 10,
233   - total: 0,
234   - pageSizes: [10, 20, 50],
235   - tableData: [],
236   - submitting: false,
237   - loading: false,
238   - selection: [],
239   - };
240   - },
241   - created() {
242   - if (this.auto) {
243   - this.search();
244   - }
245   - },
246   - filters: {
247   - // 无规则过滤器,过滤掉筛选条件表单中的必填规则等
248   - noRulesFilter(val = []) {
249   - let list = cloneDeep(val);
250   - const clearRules = list => {
251   - list.forEach(item => {
252   - if (item.list) {
253   - clearRules(item.list);
254   - } else {
255   - delete item.rules;
256   - }
257   - });
258   - };
259   - clearRules(list);
260   - return list;
261   - },
262   - // 详情类型过滤器
263   - viewTypeFilter(val = []) {
264   - let list = cloneDeep(val);
265   - const clearRules = list => {
266   - list.forEach(item => {
267   - item.type = (h, { model, config }) => h('span', config, model[item.key]);
268   - });
269   - };
270   - clearRules(list);
271   - return list;
272   - },
273   - },
274   - computed: {
275   - listMap() {
276   - // 默认作用域
277   - const LIST_SPACE = ['filter', 'form', 'table'];
278   - const array = {
279   - filter: [], // 筛选
280   - form: [], // 表单
281   - table: [], // 表格
282   - };
283   - this.list.forEach(item => {
284   - // 可以在列表中通过include或exclude设置当前配置的作用域
285   - const { include = LIST_SPACE, exclude = [] } = item;
286   - // 判断include
287   - let _inclue = [];
288   - if (include instanceof String || typeof include === 'string') {
289   - _inclue = [include];
290   - } else if (include instanceof Array && typeof include === 'object') {
291   - _inclue = include;
292   - }
293   - // 判断exclude转换为include的情况
294   - let _exclude_include = [];
295   - if (exclude instanceof String || typeof exclude === 'string') {
296   - _exclude_include = LIST_SPACE.filter(item => item !== exclude);
297   - } else if (exclude instanceof Array && typeof exclude === 'object') {
298   - _exclude_include = LIST_SPACE.filter(item => !exclude.includes(item));
299   - }
300   - // 作用域交集
301   - const _intersection = _inclue.filter(v => _exclude_include.includes(v));
302   - // 返回改配置项的作用域
303   - const _list_space = cloneDeep(_intersection);
304   - // 将配置项按需分配至各作用域下
305   - _list_space.forEach(name => {
306   - array[name].push({ ...item, ...(item[name] || {}) });
307   - });
308   - });
309   - return array;
310   - },
311   - renderList() {
312   - // 深度克隆传入的列表,避免原始值被修改
313   - const newList = cloneDeep(this.list);
314   - // 生成列表值的全路径key,即列表项为对象时,对象内的key与上一级的key合并作为全路径key
315   - const generateFullKey = (list, parentKey) => {
316   - list.forEach(item => {
317   - if (item.group && item.list) {
318   - if (item.group.key) {
319   - item.fullKey = `${parentKey ? `${parentKey}-${item.group.key}` : item.group.key}`;
320   - } else {
321   - item.fullKey = parentKey || item.key;
322   - }
323   - generateFullKey(item.list, item.fullKey);
324   - } else {
325   - item.fullKey = `${parentKey ? `${parentKey}-${item.key}` : item.key}`;
326   - }
327   - });
328   - };
329   - // 生成fullKey
330   - generateFullKey(newList);
331   - return newList;
332   - },
333   - _filterModel() {
334   - return this.filterModel || this.filterForm || {};
335   - },
336   - _formModel() {
337   - return this.formModel || this.editForm || {};
338   - },
339   - _slotScope() {
340   - return {
341   - handleSearch: this.search,
342   - openDialog: this.openDialog,
343   - closeDialog: this.closeDialog,
344   - openView: this.openView,
345   - openEdit: this.openEdit,
346   - openNew: this.openNew,
347   - handleDelete: this.handleDelete,
348   - handleDeleteMul: this.handleDeleteMul,
349   - size: this.size,
350   - dialogType: this.dialogType,
351   - selection: this.selection,
352   - };
353   - },
354   - _alias() {
355   - const alias = this.alias;
356   - const zAlias = this.zAlias;
357   - if (alias && zAlias) {
358   - return { ...zAlias, ...alias };
359   - }
360   - return this.alias || this.zAlias || {};
361   - },
362   - _dialogProps() {
363   - return {
364   - ...this.dialogProps,
365   - ...this.dialogPropsHack,
366   - };
367   - },
368   - },
369   - methods: {
370   - get,
371   - // 空Promise
372   - emptyPromise() {
373   - return new Promise(resolve => resolve());
374   - },
375   - // 设置表格选中行
376   - toggleRowSelection() {
377   - this.tableData.forEach(row => {
378   - if (this.selection.find(item => item.id === row.id)) {
379   - this.$refs.table && this.$refs.table.toggleRowSelection(row);
380   - }
381   - });
382   - },
383   - // 表格选中状态
384   - onTableSelectionChange(selection, type) {
385   - if (this.realSelection) {
386   - if (type === 'check') {
387   - const result = this.selection || [];
388   - selection.forEach(item => {
389   - if (!result.find(i => i.id === item.id)) {
390   - result.push(item);
391   - }
392   - });
393   - this.selection = result;
394   - } else if (type === 'uncheck') {
395   - selection.forEach(i => {
396   - this.selection = this.selection.filter(item => item.id !== i.id);
397   - });
398   - }
399   - }
400   - },
401   - // 表格选中
402   - onTableSelection(selection) {
403   - if (!this.realSelection) {
404   - this.selection = selection;
405   - }
406   - },
407   - // 清除表格选中
408   - clearSelection() {
409   - this.$refs.table && this.$refs.table.clearSelection();
410   - this.selection = [];
411   - },
412   - // 内置搜索接口
413   - _searchAPI(params) {
414   - if (this.url && (this.http || this.zHttp)) {
415   - const _http = this.http || this.zHttp;
416   - return _http({ url: `${clear(this.url)}/${this._alias.pageUrl || 'page'}`, params });
417   - }
418   - return undefined;
419   - },
420   - // 重置查询
421   - onSearch() {
422   - this.currentPage = 1;
423   - this.search();
424   - },
425   - // 搜索
426   - async search() {
427   - this.loading = true;
428   - const params = {
429   - ...this._filterModel,
430   - currentPage: this.currentPage,
431   - pageSize: this.pageSize,
432   - };
433   - const searchAPI = this.searchApi || this._searchAPI || this.emptyPromise;
434   - await searchAPI(params)
435   - .then(res => {
436   - const response = res || {};
437   - this.tableData = response[this._alias.list || 'list'] || [];
438   - this.total = response[this._alias.total || 'total'] || 0;
439   - this.$nextTick(this.toggleRowSelection);
440   - })
441   - .catch(() => {
442   - this.$message.error('查询失败');
443   - });
444   - this.loading = false;
445   - },
446   - // 更新筛选model
447   - onFilterInput(val) {
448   - this.filterForm = val || {};
449   - this.$emit('update:filterModel', val || {});
450   - },
451   - // 更新表单model
452   - onFormInput(val) {
453   - this.editForm = val || {};
454   - this.$emit('update:formModel', val || {});
455   - },
456   - // 内置新增保存接口
457   - _addAPI(data) {
458   - if (this.url && (this.http || this.zHttp)) {
459   - const _http = this.http || this.zHttp;
460   - return _http({ url: `${clear(this.url)}/${this._alias.addUrl || 'add'}`, method: 'post', data });
461   - }
462   - return undefined;
463   - },
464   - // 内置修改保存接口
465   - _modifyAPI(data) {
466   - if (this.url && (this.http || this.zHttp)) {
467   - const _http = this.http || this.zHttp;
468   - return _http({ url: `${clear(this.url)}/${this._alias.modifyUrl || 'modify'}`, method: 'post', data });
469   - }
470   - return undefined;
471   - },
472   - // 表单提交且通过校验
473   - async onFormValidate(valid, model) {
474   - if (valid) {
475   - this.submitting = true;
476   - let submitAPI = this.submitApi || this.emptyPromise;
477   - if (this.dialogType === 'new') {
478   - submitAPI = this.addApi || this.submitApi || this._addAPI || this.emptyPromise;
479   - } else if (this.dialogType === 'edit') {
480   - submitAPI = this.modifyApi || this.submitApi || this._modifyAPI || this.emptyPromise;
481   - }
482   - submitAPI(model, { type: this.dialogType })
483   - .then(() => {
484   - this.$message.success('保存成功');
485   - this.closeDialog();
486   - this.search();
487   - })
488   - .catch(() => {
489   - this.$message.error('保存失败');
490   - })
491   - .finally(() => {
492   - this.submitting = false;
493   - });
494   - }
495   - },
496   - // 表单按钮确定
497   - handleConfirm() {
498   - this.$refs.form && this.$refs.form.validate();
499   - },
500   - // 表单按钮取消
501   - handleCancel() {
502   - this.closeDialog();
503   - },
504   - // 查询是否有某个插槽
505   - hadSlot(name) {
506   - return !!this.$slots[name] || !!this.$scopedSlots[name];
507   - },
508   - // 打开新增弹出框
509   - openNew() {
510   - this.openDialog('new', '新增');
511   - },
512   - // 内置查询详情接口
513   - _getAPI(row) {
514   - if (this.url && (this.http || this.zHttp)) {
515   - const _http = this.http || this.zHttp;
516   - const _getKey = this._alias.getKey || this._alias.primaryKey || 'id';
517   - const _resultKey = this._alias.result || 'result';
518   - return _http({ url: `${clear(this.url)}/${this._alias.getUrl || 'queryById'}`, params: { [_getKey]: row[_getKey] } }).then(response => response[_resultKey] || {});
519   - }
520   - return undefined;
521   - },
522   - // 打开编辑弹出框
523   - openEdit(row) {
524   - this.dialogLoading = true;
525   - this.openDialog('edit', '编辑');
526   - const getRow = () =>
527   - new Promise(resolve => {
528   - resolve(row);
529   - });
530   - const getAPI = this.getApi || this._getAPI || getRow;
531   - getAPI(row)
532   - .then(result => {
533   - this.editForm = result;
534   - this.$emit('update:formModel', result || {});
535   - })
536   - .finally(() => {
537   - this.dialogLoading = false;
538   - });
539   - },
540   - // 内置查询详情接口
541   - _viewAPI(row) {
542   - if (this.url && (this.http || this.zHttp)) {
543   - const _http = this.http || this.zHttp;
544   - const _viewKey = this._alias.viewKey || this._alias.getKey || this._alias.primaryKey || 'id';
545   - const _resultKey = this._alias.result || 'result';
546   - return _http({ url: `${clear(this.url)}/${this._alias.getUrl || 'queryById'}`, params: { [_viewKey]: row[_viewKey] } }).then(response => response[_resultKey] || {});
547   - }
548   - return undefined;
549   - },
550   - // 打开详情弹出框
551   - openView(row) {
552   - this.dialogLoading = true;
553   - this.openDialog('view', '详情');
554   - const getRow = () =>
555   - new Promise(resolve => {
556   - resolve(row);
557   - });
558   - const viewAPI = this.viewApi || this.getApi || this._viewAPI || this._getAPI || getRow;
559   - viewAPI(row)
560   - .then(result => {
561   - this.editForm = result;
562   - this.$emit('update:formModel', result || {});
563   - })
564   - .finally(() => {
565   - this.dialogLoading = false;
566   - });
567   - },
568   - // 内置删除接口
569   - _deleteAPI(keys) {
570   - if (this.url && (this.http || this.zHttp)) {
571   - const _http = this.http || this.zHttp;
572   - return _http({ url: `${clear(this.url)}/${this._alias.modifyUrl || 'delete'}`, method: 'post', data: keys });
573   - }
574   - return undefined;
575   - },
576   - // 删除
577   - handleDelete(selection) {
578   - const loading = this.$loading({
579   - text: '处理中',
580   - spinner: 'el-icon-loading',
581   - background: 'rgba(255, 255, 255, 0.5)',
582   - });
583   - const deleteAPI = this.deleteApi || this._deleteAPI || this.emptyPromise;
584   - const _deleteKey = this._alias.deleteKey || this._alias.primaryKey || 'id';
585   - const keys = selection.map(i => i[_deleteKey]);
586   - deleteAPI(keys)
587   - .then(() => {
588   - this.search();
589   - this.$message.success('删除成功');
590   - })
591   - .finally(() => {
592   - loading.close();
593   - });
594   - },
595   - // 批量删除
596   - handleDeleteMul(selection) {
597   - this.$confirm(`是否删除这 [${selection.length}] 项?`, '提示', {
598   - confirmButtonText: '确定',
599   - cancelButtonText: '取消',
600   - type: 'warning',
601   - })
602   - .then(() => {
603   - this.handleDelete(selection);
604   - })
605   - .catch(() => {});
606   - },
607   - // 打开弹出框
608   - openDialog(type, title, config) {
609   - this.dialogVisible = true;
610   - this.dialogRender = true;
611   - this.dialogType = type;
612   - this.dialogTitle = title;
613   - this.dialogPropsHack = config || {};
614   - this.$emit('dialog-change', type);
615   - },
616   - // 关闭弹出框
617   - closeDialog() {
618   - this.dialogVisible = false;
619   - },
620   - // 清空表单
621   - clearEditForm() {
622   - this.editForm = {};
623   - this.$emit('update:formModel', {});
624   - },
625   - // 弹出框关闭
626   - onDialogClose() {
627   - this.dialogType = 'none';
628   - this.dialogRender = false;
629   - this.$emit('dialog-change', 'none');
630   - },
631   - // 弹出框关闭动画结束
632   - onDialogClosed() {
633   - this.clearEditForm();
634   - this.dialogPropsHack = {};
635   - },
636   - // 分页-每页个数
637   - handleSizeChange(val) {
638   - this.pageSize = val;
639   - this.currentPage = 1;
640   - this.$nextTick(this.search);
641   - },
642   - // 分页-当前页数
643   - handleCurrentChange(val) {
644   - this.currentPage = val;
645   - this.$nextTick(this.search);
646   - },
647   - },
648   -};
649   -</script>
packages/schema-page/index.scss
... ... @@ -39,12 +39,6 @@
39 39 }
40 40 }
41 41 }
42   - &__dialog-button {
43   - display: flex;
44   - align-items: center;
45   - justify-content: center;
46   - padding-top: 10px;
47   - }
48 42 &__footer {
49 43 margin-top: 10px;
50 44 text-align: right;
... ...
packages/schema-page/index.vue
... ... @@ -4,6 +4,10 @@
4 4  
5 5 <template>
6 6 <div class="z-schema-page">
  7 + <!-- 头部内容 -->
  8 + <div v-if="getSlot('header')" class="z-schema-page__header">
  9 + <slot name="header" v-bind="_slotScope"></slot>
  10 + </div>
7 11 <!-- 筛选组件 -->
8 12 <div v-if="schema.filter" class="z-schema-page__filter">
9 13 <z-schema-filter :schema="schema.filter" :value="valueFilter" @input="e => $emit('update:value-filter', e)" :loading="loading" @search="onSearch">
... ... @@ -55,23 +59,32 @@
55 59 <span>项</span>
56 60 </div>
57 61 <!-- 分页器 -->
58   - <el-pagination
59   - v-if="schema.pagination !== false"
60   - @size-change="onSizeChange"
61   - @current-change="onCurrentChange"
62   - :current-page="currentPage"
63   - :page-sizes="pageSizes"
64   - :page-size="pageSize"
65   - :layout="layout"
66   - :total="total"
67   - >
68   - </el-pagination>
  62 + <slot v-if="schema.pagination !== false" name="pagination" v-bind="_slotScope">
  63 + <el-pagination
  64 + @size-change="onSizeChange"
  65 + @current-change="onCurrentChange"
  66 + :current-page="currentPage"
  67 + :page-sizes="pageSizes"
  68 + :page-size="pageSize"
  69 + :layout="layout"
  70 + :total="total"
  71 + v-bind="schema.pagination"
  72 + >
  73 + </el-pagination>
  74 + </slot>
69 75 </slot>
70 76 </div>
  77 + <!-- 弹出框 -->
71 78 <el-dialog :title="elDialogTitle" :visible.sync="visible" v-bind="_dialogProps" @update:visible="onVisibleUpdate" @close="onDialogClose" @closed="onDialogClosed">
  79 + <template v-for="item in getSlotKeys('dialog-')" #[item.name]="slotScope">
  80 + <slot :name="item.slot" v-bind="{ ..._slotScope, ...slotScope }"></slot>
  81 + </template>
  82 + <!-- 弹出框内容渲染状态,用于关闭时销毁已渲染的内容 -->
72 83 <template v-if="elDialogRender">
  84 + <!-- 自定义弹出框内容 -->
73 85 <slot v-if="getSlot(`dialog-${elDialogType}`)" :name="`dialog-${elDialogType}`" v-bind="_slotScope"></slot>
74 86 <div v-else v-loading="dialogLoading">
  87 + <!-- 新增/修改弹出框内容 -->
75 88 <template v-if="['new', 'edit'].includes(elDialogType)">
76 89 <z-schema-form
77 90 :key="`form-${elDialogType}`"
... ... @@ -93,6 +106,7 @@
93 106 </template>
94 107 </z-schema-form>
95 108 </template>
  109 + <!-- 详情弹出框内容 -->
96 110 <template v-else-if="elDialogType === 'detail'">
97 111 <z-schema-form key="form-detail" ref="form" v-model="detail" :schema="schema.detail || detailSchema">
98 112 <template v-for="item in getSlotKeys('detail-')" #[item.name]="slotScope">
... ... @@ -265,9 +279,9 @@ export default {
265 279 const searchAPI = this.apiSearch || this.emptyPromise;
266 280 searchAPI(params)
267 281 .then(res => {
268   - const response = res || {};
269   - this.tableData = response[this.schema.listKey || 'list'] || [];
270   - this.total = response[this.schema.totalKey || 'total'] || 0;
  282 + const response = res || [];
  283 + this.tableData = response[0] || [];
  284 + this.total = response[1] || 0;
271 285 })
272 286 .finally(() => {
273 287 this.loading = false;
... ...