Files
avue/packages/element-plus/crud/dialog/dialog-form.vue
2025-08-26 09:15:51 +08:00

353 lines
9.9 KiB
Vue

<template>
<component
v-if="boxVisible"
:is="dialogType"
:draggable="validData(crud.tableOption.dialogDrag, config.dialogDrag)"
:class="[
'avue-dialog',
b('dialog'),
this.crud.tableOption.dialogCustomClass,
]"
:append-to-body="validData(crud.tableOption.dialogAppendToBody, true)"
:top="dialogTop"
:title="dialogTitle"
:close-on-press-escape="crud.tableOption.dialogEscape"
:close-on-click-modal="validData(crud.tableOption.dialogClickModal, false)"
:modal="crud.tableOption.dialogModal"
:modal-penetrable="crud.tableOption.modalPenetrable"
:show-close="crud.tableOption.dialogCloseBtn"
:header-class="crud.tableOption.headerClass"
:body-class="crud.tableOption.bodyClass"
:footer-class="crud.tableOption.footerClass"
v-model="boxVisible"
v-bind="params"
:before-close="hide"
>
<template #header>
<div :class="b('dialog__header')">
<span class="el-dialog__title">{{ dialogTitle }}</span>
<div :class="b('dialog__menu')">
<el-icon class="el-dialog__close" @click="handleFullScreen">
<component
:is="fullscreen ? 'el-icon-copy-document' : 'el-icon-full-screen'"
/>
</el-icon>
</div>
</div>
</template>
<avue-form
v-model="crud.tableForm"
v-model:status="disabled"
ref="tableForm"
@change="handleChange"
@submit="handleSubmit"
@reset-change="hide"
@tab-click="handleTabClick"
@error="handleError"
v-bind="$uploadFun(null, crud)"
v-loading="loading"
:element-loading-text="crud.tableOption.loadingText"
:element-loading-spinner="crud.tableOption.loadingSpinner"
:element-loading-svg="crud.tableOption.loadingSvg"
:element-loading-background="crud.tableOption.loadingBackground"
:option="option"
>
<!-- 循环form表单卡槽 -->
<template v-for="item in crud.formSlot" #[getSlotName(item)]="scope">
<slot
:name="item"
v-bind="Object.assign(scope, { type: boxType })"
></slot>
</template>
</avue-form>
<span
class="avue-dialog__footer"
:class="'avue-dialog__footer--' + dialogMenuPosition"
>
<slot name="menu-form-before" v-bind="menuParams()"></slot>
<el-button
type="primary"
@click="($refs.tableForm || {}).handleMock"
:loading="disabled || loading"
:size="crud.size"
:icon="option.mockIcon"
v-if="validData(option.mockBtn, false) && !isView"
>
{{ option.mockText }}
</el-button>
<el-button
v-if="validData(option.submitBtn, true) && !isView"
@click="submit"
:loading="disabled || loading"
:size="crud.size"
:icon="option.submitIcon"
type="primary"
>{{ option.submitText }}</el-button
>
<el-button
v-if="validData(option.emptyBtn, true) && !isView"
@click="reset"
:disabled="disabled || loading"
:size="crud.size"
:icon="option.emptyIcon"
>{{ option.emptyText }}</el-button
>
<slot name="menu-form" v-bind="menuParams()"></slot>
</span>
</component>
</template>
<script>
import create from "core/create";
import locale from "core/locale";
import config from "../config";
import { filterParams } from "utils/util";
export default create({
name: "crud",
mixins: [locale],
emits: ["update:modelValue", "change"],
inject: ["crud"],
data() {
return {
loading: false,
disabled: false,
config: config,
boxType: "",
fullscreen: false,
boxVisible: false,
};
},
props: {
modelValue: {
type: Object,
default: () => {
return {};
},
},
},
computed: {
isView() {
return this.boxType === "view";
},
isAdd() {
return this.boxType === "add";
},
isEdit() {
return this.boxType === "edit";
},
width() {
let dialogWidth = this.crud.tableOption.dialogWidth + "";
let defaultWidth = this.crud.isMobile ? "100%" : config.dialogWidth;
let result = this.validData(dialogWidth, defaultWidth);
return this.setPx(result);
},
dialogType() {
return this.isDrawer ? "elDrawer" : "elDialog";
},
dialogTop() {
return !this.isDrawer && !this.fullscreen
? this.crud.tableOption.dialogTop
: "0";
},
isDrawer() {
return this.crud.tableOption.dialogType === "drawer";
},
params() {
let result = this.isDrawer
? {
size: this.fullscreen ? "100%" : this.width,
direction: this.crud.tableOption.dialogDirection,
}
: {
width: this.width,
fullscreen: this.fullscreen,
};
return Object.assign(result, this.$uploadFun({}, this.crud));
},
option() {
let option = this.deepClone(this.crud.tableOption);
option.boxType = this.boxType;
option.column = this.deepClone(this.crud.propOption);
option.column.forEach((ele) => {
delete ele.render;
if (ele.renderForm) ele.render = ele.renderForm;
});
option.menuBtn = false;
if (this.isAdd) {
option.submitBtn = option.saveBtn;
option.submitText = this.crud.menuIcon("saveBtn");
option.submitIcon = this.crud.getBtnIcon("saveBtn");
} else if (this.isEdit) {
option.submitBtn = option.updateBtn;
option.submitText = this.crud.menuIcon("updateBtn");
option.submitIcon = this.crud.getBtnIcon("updateBtn");
} else if (this.isView) {
option.detail = true;
}
option.mockIcon = this.crud.getBtnIcon("mockBtn");
option.mockText = this.crud.menuIcon("mockBtn");
option.emptyBtn = option.cancelBtn;
option.emptyIcon = this.crud.getBtnIcon("cancelBtn");
option.emptyText = this.crud.menuIcon("cancelBtn");
//不分组的表单不加载字典
if (!this.crud.isGroup) {
option.dicFlag = false;
option.dicData = this.crud.DIC;
}
if (!this.validatenull(option.dicFlag)) {
option.column.forEach((ele) => {
ele.boxType = this.boxType;
ele.dicFlag = ele.dicFlag || option.dicFlag;
});
}
return option;
},
dialogTitle() {
const key = `${this.boxType}`;
if (!this.validatenull(this.boxType)) {
return (
this.crud.tableOption[key + "Title"] || this.t(`crud.${key}Title`)
);
}
},
dialogMenuPosition() {
return this.crud.tableOption.dialogMenuPosition || "right";
},
},
methods: {
menuParams() {
return {
disabled: this.disabled,
size: this.crud.size,
type: this.boxType,
};
},
submit() {
this.$refs.tableForm.submit();
},
reset() {
this.$refs.tableForm.resetForm(false);
},
getSlotName(item) {
return item.replace("-form", "");
},
handleChange() {
this.crud.setVal();
},
handleTabClick(tab, event) {
this.crud.$emit("tab-click", tab, event);
},
handleFullScreen() {
if (this.fullscreen) {
this.fullscreen = false;
} else {
this.fullscreen = true;
}
},
handleError(error) {
this.crud.$emit("error", error);
},
handleSubmit(form, hide) {
if (this.isAdd) {
this.rowSave(hide);
} else if (this.isEdit) {
this.rowUpdate(hide);
}
},
initFun() {
["clearValidate", "validate", "resetForm", "validateField"].forEach(
(ele) => {
this.crud[ele] = this.$refs.tableForm[ele];
}
);
},
// 保存
rowSave(hide) {
this.crud.$emit(
"row-save",
filterParams(this.crud.tableForm, ["$"]),
this.closeDialog,
hide
);
},
// 更新
rowUpdate(hide) {
this.crud.$emit(
"row-update",
filterParams(this.crud.tableForm, ["$"]),
this.crud.tableIndex,
this.closeDialog,
hide
);
},
closeDialog(row, index) {
row = this.deepClone(row);
const callback = () => {
if (this.isEdit) {
let { parentList, index } = this.crud.findData(row[this.crud.rowKey]);
if (parentList) {
const oldRow = parentList.splice(index, 1)[0];
row[this.crud.childrenKey] = oldRow[this.crud.childrenKey];
parentList.splice(index, 0, row);
}
} else if (this.isAdd) {
let { item } = this.crud.findData(row[this.crud.rowParentKey]);
if (item) {
if (!item[this.crud.childrenKey]) {
item[this.crud.childrenKey] = [];
}
if (this.crud.tableOption.lazy) {
item[this.crud.hasChildrenKey] = true;
}
item[this.crud.childrenKey].push(row);
} else {
this.crud.list.push(row);
}
}
};
if (row) callback();
this.hide();
},
// 隐藏表单
hide(done) {
const callback = () => {
done && done();
this.crud.tableIndex = -1;
this.crud.tableForm = {};
this.crud.setVal();
this.boxVisible = false;
};
if (typeof this.crud.beforeClose === "function") {
this.crud.beforeClose(callback, this.boxType);
} else {
callback();
}
},
// 显示表单
show(type) {
this.boxType = type;
const callback = (fn) => {
this.fullscreen = this.crud.tableOption.dialogFullscreen;
this.boxVisible = true;
this.loading = false;
this.$nextTick(() => {
this.initFun();
fn && fn();
});
};
const loading = () => {
callback(() => {
this.loading = true;
});
};
if (typeof this.crud.beforeOpen === "function") {
this.crud.beforeOpen(callback, this.boxType, loading);
} else {
callback();
}
},
},
});
</script>