Commit 8a0c5cbbbb7f57aef07082cb34388ecdee7360ee

Authored by 刘汉宸
1 parent 4ae177c1

feat: 修改SchemaPage组件支持抽屉

examples/views/docs/component/schema-page.md
... ... @@ -365,7 +365,7 @@ export default {
365 365  
366 366 :::
367 367  
368   -## 弹窗类型
  368 +## 自定义弹窗
369 369  
370 370 除了本组件内置的`new`、`edit`、`detail`三种弹出框模式之外,还可以通过任意插槽打开任意自定义弹出框。也支持重新定义原有的三种弹框,同时也需要重新自定义表单校验和提交等逻辑。
371 371  
... ... @@ -485,6 +485,115 @@ export default {
485 485  
486 486 :::
487 487  
  488 +## 弹窗类型
  489 +
  490 +弹出框组件默认为`el-dialog`,使用自定义弹窗时,可以设置为`el-drawer`。
  491 +
  492 +::: snippet 通过`openDialog`的config参数配置`is: 'el-drawer'`即可改为抽屉式弹窗,`dialog-xxx-footer`可以设置抽屉固定的footer
  493 +
  494 +```html
  495 +<template>
  496 + <z-schema-page :schema="schema" :value-table.sync="tableModel">
  497 + <template #action-button="{ size, openDialog }">
  498 + <el-button :size="size" @click="openDialog('bill', '账单', { is: 'el-drawer', width: '70%' })">账单</el-button>
  499 + </template>
  500 + <template #operation-button="{ openDialog, row }">
  501 + <el-button type="text" @click="openDialog('load', `配置-${row.name}`, { is: 'el-drawer', width: '400px' })">配载</el-button>
  502 + </template>
  503 + <template #table-cell-name="{ value, row, openDetail }">
  504 + <el-link type="primary" @click="openDetail(row)">{{ value }}</el-link>
  505 + </template>
  506 + <template #dialog-bill="{ closeDialog }">
  507 + <div style="background: #f5f5f5; height: 90vh; display: flex; align-items: center; justify-content: center">一段很长的内容</div>
  508 + <z-schema-table v-model="billData" :schema="billSchema"></z-schema-table>
  509 + </template>
  510 + <template #dialog-bill-footer="{ closeDialog }">
  511 + <el-button plain @click="closeDialog">关闭</el-button>
  512 + </template>
  513 + <template #dialog-load="{ closeDialog }">
  514 + <el-alert title="这里是一段自定义信息" type="error" show-icon style="margin-bottom: 20px"></el-alert>
  515 + <z-schema-form v-model="loadModel" :schema="loadSchema"></z-schema-form>
  516 + <el-button type="primary" @click="closeDialog">关闭弹出框</el-button>
  517 + </template>
  518 + </z-schema-page>
  519 +</template>
  520 +
  521 +<script>
  522 +export default {
  523 + data() {
  524 + return {
  525 + schema: {
  526 + filter: {
  527 + items: [
  528 + { is: 'el-input', prop: 'name', label: '姓名' },
  529 + ]
  530 + },
  531 + table: {
  532 + props: { size: 'mini', border: true } ,
  533 + items: [
  534 + { prop: 'name', label: '姓名' },
  535 + { prop: 'age', label: '年龄' },
  536 + { prop: 'address', label: '地址' },
  537 + { prop: 'status', label: '状态', render: (value, row, h) => h('el-tag', { props: { size: 'mini', type: 'info' } }, value) },
  538 + ]
  539 + },
  540 + form: {
  541 + props: { labelWidth: '70px', size: 'small', span: 12 },
  542 + items: [
  543 + { is: 'el-input', prop: 'name', label: '姓名', rules: [{ required: true, message: '请输入姓名' }] },
  544 + { is: 'el-input-number', prop: 'age', label: '年龄', rules: [{ required: true, message: '请输入有效年龄' }] },
  545 + { is: 'el-input', props: { type: 'textarea' }, prop: 'address', label: '住址', span: 24 },
  546 + ]
  547 + },
  548 + operation: { width: 120 }
  549 + },
  550 + tableModel: [
  551 + { id: '0', name: '李饼', age: 32, address: '地址0', status: '正常' },
  552 + { id: '1', name: '陈拾', age: 20, address: '地址1', status: '正常' },
  553 + { id: '3', name: '王七', age: 26, address: '地址3', status: '正常' },
  554 + { id: '4', name: '崔倍', age: 27, address: '地址4', status: '正常' },
  555 + { id: '5', name: '孙豹', age: 38, address: '地址5', status: '正常' },
  556 + ],
  557 + loadModel: {
  558 + name: '',
  559 + count: 1,
  560 + packages: []
  561 + },
  562 + loadSchema: {
  563 + props: { 'label-width': '70px', size: 'small' },
  564 + items: [
  565 + { is: 'el-input', prop: 'name', label: '名称' },
  566 + { is: 'el-input-number', prop: 'count', label: '数量' },
  567 + {
  568 + is: 'el-checkbox-group',
  569 + prop: 'packages',
  570 + label: '包裹',
  571 + children: [
  572 + { is: 'el-checkbox', props: { label: '零食' } },
  573 + { is: 'el-checkbox', props: { label: '手机' } },
  574 + { is: 'el-checkbox', props: { label: '电脑' } },
  575 + ],
  576 + },
  577 + ]
  578 + },
  579 + billData: [
  580 + { billno: 'B20210401000001', amount: '18750' },
  581 + { billno: 'B20210401000002', amount: '637' },
  582 + ],
  583 + billSchema: {
  584 + items: [
  585 + { label: '单号', prop: 'billno' },
  586 + { label: '金额', prop: 'amount' },
  587 + ]
  588 + }
  589 + }
  590 + },
  591 +}
  592 +</script>
  593 +```
  594 +
  595 +:::
  596 +
488 597 ## 按钮权限
489 598  
490 599 本组件不包含自定义业务逻辑,因此配置项不包含权限判断,如果需要按钮的权限判断,可以通过`action`插槽和`operation`插槽将渲染逻辑暴露在视图模板中,然后进行自定义判断。
... ...
packages/schema-page/index.scss
... ... @@ -96,4 +96,30 @@
96 96 margin-top: 10px;
97 97 }
98 98 }
  99 +}
  100 +
  101 +.z-schema-page__drawer {
  102 + .el-drawer__header {
  103 + padding-bottom: 10px;
  104 + margin-bottom: 0;
  105 + border-bottom: 1px solid #DCDFE6;
  106 + }
  107 + .el-drawer__body {
  108 + box-sizing: border-box;
  109 + height: calc(100vh - 55px);
  110 + }
  111 + &-content {
  112 + padding: 20px;
  113 + overflow-y: auto;
  114 + }
  115 + &-footer {
  116 + height: 60px;
  117 + display: flex;
  118 + align-items: center;
  119 + justify-content: center;
  120 + box-sizing: border-box;
  121 + padding: 10px;
  122 + background: #fff;
  123 + border-top: 1px solid #DCDFE6;
  124 + }
99 125 }
100 126 \ No newline at end of file
... ...
packages/schema-page/index.vue
... ... @@ -75,19 +75,32 @@
75 75 </slot>
76 76 </div>
77 77 <!-- 弹出框 -->
78   - <el-dialog :title="elDialogTitle" :visible.sync="visible" v-bind="_dialogProps" @update:visible="onVisibleUpdate" @close="onDialogClose" @closed="onDialogClosed">
  78 + <el-drawer :visible="_modalComponent === 'el-drawer' && visible" v-bind="_drawerProps" v-on="_modalListeners">
  79 + <template v-for="item in getSlotKeys('dialog-')" #[item.name]="slotScope">
  80 + <slot :name="item.slot" v-bind="{ ..._slotScope, ...slotScope }"></slot>
  81 + </template>
  82 + <template v-if="_modalComponent === 'el-drawer' && modalRender">
  83 + <div v-loading="dialogLoading" class="z-schema-page__drawer-content" :style="`height: calc(100vh - ${getSlot(`dialog-${modalType}-footer`) ? 115 : 55}px);`">
  84 + <slot :name="`dialog-${modalType}`" v-bind="_slotScope"></slot>
  85 + </div>
  86 + <div v-if="getSlot(`dialog-${modalType}-footer`)" class="z-schema-page__drawer-footer">
  87 + <slot :name="`dialog-${modalType}-footer`" v-bind="_slotScope"></slot>
  88 + </div>
  89 + </template>
  90 + </el-drawer>
  91 + <el-dialog :visible="_modalComponent === 'el-dialog' && visible" v-bind="_dialogProps" v-on="_modalListeners">
79 92 <template v-for="item in getSlotKeys('dialog-')" #[item.name]="slotScope">
80 93 <slot :name="item.slot" v-bind="{ ..._slotScope, ...slotScope }"></slot>
81 94 </template>
82 95 <!-- 弹出框内容渲染状态,用于关闭时销毁已渲染的内容 -->
83   - <template v-if="elDialogRender">
  96 + <div v-if="_modalComponent === 'el-dialog' && modalRender" v-loading="dialogLoading">
84 97 <!-- 自定义弹出框内容 -->
85   - <slot v-if="getSlot(`dialog-${elDialogType}`)" :name="`dialog-${elDialogType}`" v-bind="_slotScope"></slot>
86   - <div v-else v-loading="dialogLoading">
  98 + <slot v-if="getSlot(`dialog-${modalType}`)" :name="`dialog-${modalType}`" v-bind="_slotScope"></slot>
  99 + <template v-else>
87 100 <!-- 新增/修改弹出框内容 -->
88   - <template v-if="['new', 'edit'].includes(elDialogType)">
  101 + <template v-if="['new', 'edit'].includes(modalType)">
89 102 <z-schema-form
90   - :key="`form-${elDialogType}`"
  103 + :key="`form-${modalType}`"
91 104 ref="form"
92 105 :value="valueForm"
93 106 @input="e => $emit('update:value-form', e)"
... ... @@ -107,15 +120,15 @@
107 120 </z-schema-form>
108 121 </template>
109 122 <!-- 详情弹出框内容 -->
110   - <template v-else-if="elDialogType === 'detail'">
  123 + <template v-else-if="modalType === 'detail'">
111 124 <z-schema-form key="form-detail" ref="form" v-model="detail" :schema="schema.detail || detailSchema">
112 125 <template v-for="item in getSlotKeys('detail-')" #[item.name]="slotScope">
113 126 <slot :name="item.slot" v-bind="{ ..._slotScope, ...slotScope }"></slot>
114 127 </template>
115 128 </z-schema-form>
116 129 </template>
117   - </div>
118   - </template>
  130 + </template>
  131 + </div>
119 132 </el-dialog>
120 133 </div>
121 134 </template>
... ... @@ -169,10 +182,10 @@ export default {
169 182 layout: get(this.schema, 'pagination.layout') || 'total, sizes, prev, pager, next, jumper',
170 183 total: get(this.schema, 'pagination.total') || 0,
171 184 visible: this.dialogVisible,
172   - elDialogRender: true,
173   - elDialogType: this.dialogType || 'none',
174   - elDialogTitle: this.dialogTitle || '',
175   - elDialogProps: {},
  185 + modalRender: true,
  186 + modalType: this.dialogType || 'none',
  187 + modalTitle: this.dialogTitle || '',
  188 + modalProps: {},
176 189 detailSchema: filterout(cloneDeep(this.schema.form), ['is', 'rules']),
177 190 detail: this.valueDetail || {},
178 191 tableData: this.valueTable || [],
... ... @@ -201,15 +214,15 @@ export default {
201 214 this.$emit('update:dialog-visible', val);
202 215 },
203 216 dialogType(val) {
204   - this.elDialogType = val;
  217 + this.modalType = val;
205 218 },
206   - elDialogType(val) {
  219 + modalType(val) {
207 220 this.$emit('update:dialog-type', val);
208 221 },
209 222 dialogTitle(val) {
210   - this.elDialogTitle = val;
  223 + this.modalTitle = val;
211 224 },
212   - elDialogTitle(val) {
  225 + modalTitle(val) {
213 226 this.$emit('update:dialog-title', val);
214 227 },
215 228 valueTable(val) {
... ... @@ -238,13 +251,41 @@ export default {
238 251 }, defaultScope);
239 252 },
240 253 _dialogProps() {
  254 + const { is, ...other } = this.modalProps || {};
241 255 return {
242   - 'destroy-on-close': true,
243   - 'append-to-body': true,
  256 + title: this.modalTitle,
244 257 'lock-scroll': false,
  258 + 'append-to-body': true,
  259 + 'destroy-on-close': true,
245 260 'close-on-click-modal': false,
246 261 ...(this.schema.dialog || {}),
247   - ...this.elDialogProps,
  262 + ...other,
  263 + };
  264 + },
  265 + _drawerProps() {
  266 + const { is, ...other } = this.modalProps || {};
  267 + return {
  268 + title: this.modalTitle,
  269 + size: '50%',
  270 + 'append-to-body': true,
  271 + 'destroy-on-close': true,
  272 + 'close-on-click-modal': false,
  273 + 'custom-class': 'z-schema-page__drawer',
  274 + ...(this.schema.drawer || {}),
  275 + ...other,
  276 + };
  277 + },
  278 + _modalComponent() {
  279 + if (this.modalProps.is === 'el-drawer') {
  280 + return 'el-drawer';
  281 + }
  282 + return 'el-dialog';
  283 + },
  284 + _modalListeners() {
  285 + return {
  286 + 'update:visible': this.onVisibleUpdate,
  287 + close: this.onDialogClose,
  288 + closed: this.onDialogClosed,
248 289 };
249 290 },
250 291 },
... ... @@ -300,12 +341,12 @@ export default {
300 341 } else {
301 342 this.submitting = true;
302 343 let submitAPI = this.apiSubmit || this.emptyPromise;
303   - if (this.elDialogType === 'new') {
  344 + if (this.modalType === 'new') {
304 345 submitAPI = this.apiNew || this.apiSubmit || this.emptyPromise;
305   - } else if (this.elDialogType === 'edit') {
  346 + } else if (this.modalType === 'edit') {
306 347 submitAPI = this.apiEdit || this.apiSubmit || this.emptyPromise;
307 348 }
308   - submitAPI(this.valueForm, { type: this.elDialogType })
  349 + submitAPI(this.valueForm, { type: this.modalType })
309 350 .then(() => {
310 351 if (this.$listeners['submit-success']) {
311 352 this.$emit('submit-success');
... ... @@ -365,10 +406,10 @@ export default {
365 406 },
366 407 // 打开弹出框
367 408 openDialog(type, title, config) {
368   - this.elDialogRender = true;
369   - this.elDialogType = type;
370   - this.elDialogTitle = title;
371   - this.elDialogProps = config || {};
  409 + this.modalRender = true;
  410 + this.modalType = type;
  411 + this.modalTitle = title;
  412 + this.modalProps = config || {};
372 413 this.visible = true;
373 414 this.$emit('dialog-change', type);
374 415 },
... ... @@ -382,7 +423,7 @@ export default {
382 423 },
383 424 // 弹出框关闭
384 425 onDialogClose() {
385   - this.elDialogType = 'none';
  426 + this.modalType = 'none';
386 427 this.$emit('dialog-change', 'none');
387 428 },
388 429 // 弹出框关闭动画结束
... ... @@ -390,8 +431,8 @@ export default {
390 431 if (this.$refs.form) {
391 432 this.$refs.form.resetFields();
392 433 }
393   - this.elDialogRender = false;
394   - this.elDialogProps = {};
  434 + this.modalRender = false;
  435 + this.modalProps = {};
395 436 this.$emit('update:value-form', this.cloneDeep(this.originProps).valueForm);
396 437 this.$emit('update:value-detail', this.cloneDeep(this.originProps).detailValue);
397 438 },
... ...