Commit 4ae177c1c3a0608311f573b0061c1b0f13bdbbd2

Authored by 刘汉宸
1 parent 57f06f4f

feat: 修改SchemaPage组件

examples/views/docs/component/schema-page.md
@@ -29,7 +29,7 @@ export default { @@ -29,7 +29,7 @@ export default {
29 { prop: 'name', label: '姓名' }, 29 { prop: 'name', label: '姓名' },
30 { prop: 'age', label: '年龄' }, 30 { prop: 'age', label: '年龄' },
31 { prop: 'address', label: '地址' }, 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 form: { 35 form: {
@@ -89,7 +89,7 @@ export default { @@ -89,7 +89,7 @@ export default {
89 { prop: 'name', label: '姓名' }, 89 { prop: 'name', label: '姓名' },
90 { prop: 'age', label: '年龄' }, 90 { prop: 'age', label: '年龄' },
91 { prop: 'address', label: '地址' }, 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 form: { 95 form: {
@@ -122,7 +122,7 @@ export default { @@ -122,7 +122,7 @@ export default {
122 122
123 本组件预置了增删改查逻辑,因此分别对应`api-search`、`api-new`、`api-edit`、`api-get`、`api-delete`五个基本接口。 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 ```html 127 ```html
128 <template> 128 <template>
@@ -159,7 +159,7 @@ export default { @@ -159,7 +159,7 @@ export default {
159 { prop: 'name', label: '姓名' }, 159 { prop: 'name', label: '姓名' },
160 { prop: 'age', label: '年龄' }, 160 { prop: 'age', label: '年龄' },
161 { prop: 'address', label: '地址' }, 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 form: { 165 form: {
@@ -187,10 +187,7 @@ export default { @@ -187,10 +187,7 @@ export default {
187 { id: '4', name: '崔倍', age: 27, address: '地址4', status: '正常' }, 187 { id: '4', name: '崔倍', age: 27, address: '地址4', status: '正常' },
188 { id: '5', name: '孙豹', age: 38, address: '地址5', status: '正常' }, 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 }, 500); 191 }, 500);
195 }); 192 });
196 }, 193 },
@@ -279,7 +276,7 @@ export default { @@ -279,7 +276,7 @@ export default {
279 { prop: 'name', label: '姓名' }, 276 { prop: 'name', label: '姓名' },
280 { prop: 'age', label: '年龄' }, 277 { prop: 'age', label: '年龄' },
281 { prop: 'address', label: '地址' }, 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 form: { 282 form: {
@@ -317,10 +314,7 @@ export default { @@ -317,10 +314,7 @@ export default {
317 { id: '4', name: '崔倍', age: 27, address: '地址4', status: '正常' }, 314 { id: '4', name: '崔倍', age: 27, address: '地址4', status: '正常' },
318 { id: '5', name: '孙豹', age: 38, address: '地址5', status: '正常' }, 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 }, 500); 318 }, 500);
325 }); 319 });
326 }, 320 },
@@ -431,7 +425,7 @@ export default { @@ -431,7 +425,7 @@ export default {
431 { prop: 'name', label: '姓名' }, 425 { prop: 'name', label: '姓名' },
432 { prop: 'age', label: '年龄' }, 426 { prop: 'age', label: '年龄' },
433 { prop: 'address', label: '地址' }, 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 form: { 431 form: {
@@ -535,7 +529,7 @@ export default { @@ -535,7 +529,7 @@ export default {
535 { prop: 'name', label: '姓名' }, 529 { prop: 'name', label: '姓名' },
536 { prop: 'age', label: '年龄' }, 530 { prop: 'age', label: '年龄' },
537 { prop: 'address', label: '地址' }, 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 form: { 535 form: {
packages/schema-page/index copy.scss
@@ -1,72 +0,0 @@ @@ -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 \ No newline at end of file 0 \ No newline at end of file
packages/schema-page/index copy.vue
@@ -1,649 +0,0 @@ @@ -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,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 &__footer { 42 &__footer {
49 margin-top: 10px; 43 margin-top: 10px;
50 text-align: right; 44 text-align: right;
packages/schema-page/index.vue
@@ -4,6 +4,10 @@ @@ -4,6 +4,10 @@
4 4
5 <template> 5 <template>
6 <div class="z-schema-page"> 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 <div v-if="schema.filter" class="z-schema-page__filter"> 12 <div v-if="schema.filter" class="z-schema-page__filter">
9 <z-schema-filter :schema="schema.filter" :value="valueFilter" @input="e => $emit('update:value-filter', e)" :loading="loading" @search="onSearch"> 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,23 +59,32 @@
55 <span>项</span> 59 <span>项</span>
56 </div> 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 </slot> 75 </slot>
70 </div> 76 </div>
  77 + <!-- 弹出框 -->
71 <el-dialog :title="elDialogTitle" :visible.sync="visible" v-bind="_dialogProps" @update:visible="onVisibleUpdate" @close="onDialogClose" @closed="onDialogClosed"> 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 <template v-if="elDialogRender"> 83 <template v-if="elDialogRender">
  84 + <!-- 自定义弹出框内容 -->
73 <slot v-if="getSlot(`dialog-${elDialogType}`)" :name="`dialog-${elDialogType}`" v-bind="_slotScope"></slot> 85 <slot v-if="getSlot(`dialog-${elDialogType}`)" :name="`dialog-${elDialogType}`" v-bind="_slotScope"></slot>
74 <div v-else v-loading="dialogLoading"> 86 <div v-else v-loading="dialogLoading">
  87 + <!-- 新增/修改弹出框内容 -->
75 <template v-if="['new', 'edit'].includes(elDialogType)"> 88 <template v-if="['new', 'edit'].includes(elDialogType)">
76 <z-schema-form 89 <z-schema-form
77 :key="`form-${elDialogType}`" 90 :key="`form-${elDialogType}`"
@@ -93,6 +106,7 @@ @@ -93,6 +106,7 @@
93 </template> 106 </template>
94 </z-schema-form> 107 </z-schema-form>
95 </template> 108 </template>
  109 + <!-- 详情弹出框内容 -->
96 <template v-else-if="elDialogType === 'detail'"> 110 <template v-else-if="elDialogType === 'detail'">
97 <z-schema-form key="form-detail" ref="form" v-model="detail" :schema="schema.detail || detailSchema"> 111 <z-schema-form key="form-detail" ref="form" v-model="detail" :schema="schema.detail || detailSchema">
98 <template v-for="item in getSlotKeys('detail-')" #[item.name]="slotScope"> 112 <template v-for="item in getSlotKeys('detail-')" #[item.name]="slotScope">
@@ -265,9 +279,9 @@ export default { @@ -265,9 +279,9 @@ export default {
265 const searchAPI = this.apiSearch || this.emptyPromise; 279 const searchAPI = this.apiSearch || this.emptyPromise;
266 searchAPI(params) 280 searchAPI(params)
267 .then(res => { 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 .finally(() => { 286 .finally(() => {
273 this.loading = false; 287 this.loading = false;