pms-aomei/src/components/DialogJustForm.vue
2023-02-01 17:02:14 +08:00

316 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-dialog
class="dialog-just-form"
:visible.sync="selfVisible"
@closed="resetForm"
:distory-on-close="true"
:close-on-click-modal="configs.clickModalToClose ?? true"
>
<!-- title -->
<div slot="title" class="dialog-title">
<h1 class="">
{{ detailMode ? "查看详情" : dataForm.id ? "编辑" : "新增" }}
</h1>
</div>
<!-- form -->
<el-form ref="dataForm" :model="dataForm" v-loading="loadingStatus">
<el-row v-for="(row, rowIndex) in configs.form.rows" :key="'row_' + rowIndex" :gutter="20">
<el-col v-for="(col, colIndex) in row" :key="colIndex" :span="24 / row.length">
<!-- 通过多个 col === null 可以控制更灵活的 span 大小 -->
<el-form-item v-if="col !== null" :label="col.label" :prop="col.prop" :rules="col.rules || null">
<el-input v-if="col.input" v-model="dataForm[col.prop]" clearable :disabled="detailMode" v-bind="col.elparams" />
<el-select
v-if="col.select"
v-model="dataForm[col.prop]"
clearable
:disabled="detailMode"
v-bind="col.elparams"
@change="handleSelectChange(col, $event)"
>
<el-option v-for="(opt, optIdx) in col.options" :key="'option_' + optIdx" :label="opt.label" :value="opt.value" />
</el-select>
<el-switch
v-if="col.switch"
v-model="dataForm[col.prop]"
:active-value="col.activeValue ?? 1"
:inactive-value="col.activeValue ?? 0"
@change="handleSwitchChange"
:disabled="detailMode"
/>
<el-input v-if="col.textarea" type="textarea" v-model="dataForm[col.prop]" :disabled="detailMode" v-bind="col.elparams" />
<div class="" v-if="col.component" style="margin: 42px 0 0">
<!-- 下面这个 component 几乎是为 富文本 quill 定制的了... TODO后续可能会根据业务需求创建新的版本 -->
<component
:is="col.component"
:key="'component_' + col.prop"
@update:modelValue="handleComponentModelUpdate(col.prop, $event)"
:modelValue="dataForm[col.prop]"
:mode="detailMode ? 'detail' : dataForm.id ? 'edit' : 'create'"
/>
</div>
<!-- add more... -->
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- footer -->
<div slot="footer">
<template v-for="(operate, index) in configs.form.operations">
<el-button v-if="showButton(operate)" :key="'operation_' + index" :type="operate.type" @click="handleBtnClick(operate)">{{
operate.label
}}</el-button>
</template>
<el-button @click="handleBtnClick({ name: 'cancel' })">取消</el-button>
</div>
</el-dialog>
</template>
<script>
import { pick as __pick } from "@/utils/filters";
function reConstructTreeData(listObj) {
// O(2n)
// 数据重排
Object.keys(listObj).map((key) => {
const currentNode = listObj[key];
if (currentNode.parentId === "0") return // return { label: currentNode.name, value: currentNode.id, children: currentNode.children ?? [] };
const parentNode = listObj[currentNode.parentId];
if (!parentNode.children) {
parentNode.children = [];
}
parentNode.children.push(currentNode);
});
// 数据整理
function recursive(list) {
// TODO: 2023.2.2
list.forEach(item => {
if (item.children) recursive(item.children)
})
}
return Object.keys(listObj).map(key => {
const currentNode = listObj[key];
if (currentNode.children) recursive(currentNode.children)
})
}
export default {
name: "DialogJustForm",
props: {
configs: {
type: Object,
default: () => ({
clickModalToClose: true,
forms: null,
}),
},
},
inject: ["urls"],
data() {
const dataForm = {};
this.configs.form.rows.forEach((row) => {
row.forEach((col) => {
dataForm[col.prop] = col.default ?? null;
if (col.fetchData)
col.fetchData().then(({ data: res }) => {
console.log("[Fetch Data]", res.data.list);
if (res.code === 0 && res.data.list) {
this.$set(
col,
"options",
res.data.list.map((i) => ({ label: i.name, value: i.id }))
);
// col.options = res.data.list;
} else {
col.options.splice(0);
}
// dataForm[col.prop] = col.default ?? null; // not perfect!
});
else if (col.fetchTreeData)
// 获取设备类型时触发的用于前端构建属性结构约定parentId 为0时是顶级节点
col.fetchTreeData().then(({ data: res }) => {
console.log("[Fetch Tree Data]", res.data.list);
if (res.code === 0 && res.data.list) {
// 先把数据先重构成一个对象
const obj = {};
res.data.list.map((item) => {
obj[item.id] = item;
});
// 再过滤这个对象
let filteredList = reConstructTreeData(obj);
// 最后设置 options
this.$set(col, "options", filteredList);
} else {
col.options.splice(0);
}
});
});
});
return {
loadingStatus: false,
dataForm,
detailMode: false,
selfVisible: false,
baseDialogConfig: null,
};
},
created() {
// console.log('[dialog] created!!! wouldn\'t create again...')
},
methods: {
/** utitilities */
showButton(operate) {
const notDetailMode = !this.detailMode;
const showAlways = operate.showAlways ?? false;
const editMode = operate.showOnEdit && this.dataForm.id;
const addMode = !operate.showOnEdit && !this.dataForm.id;
const permission = operate.permission ? this.$hasPermission(operate.permission) : true;
return notDetailMode && (showAlways || ((editMode || addMode) && permission));
},
resetForm(excludeId = false, immediate = false) {
setTimeout(
() => {
console.log("[Dialog Just Form] clearing form...");
Object.keys(this.dataForm).forEach((key) => {
if (excludeId && key === "id") return;
this.dataForm[key] = null;
});
console.log("[Dialog Just Form] cleared form...", this.dataForm);
this.$refs.dataForm.clearValidate();
},
immediate ? 0 : 100
);
},
/** init **/
init(id, detailMode) {
this.selfVisible = true;
if (this.$refs.dataForm) {
console.log("[dialog REUSE] clearing form validation...");
// 当不是首次渲染dialog的时候一开始就清空验证信息本组件的循环里只有一个 dataForm 所以只用取 [0] 即可
this.$refs.dataForm.clearValidate();
}
console.log("[Dialog Just Form] init():", id, detailMode);
this.detailMode = detailMode ?? false;
this.$nextTick(() => {
this.dataForm.id = id || null;
if (this.dataForm.id) {
// 如果是编辑
this.loadingStatus = true;
this.$http.get(this.urls.base + `/${this.dataForm.id}`).then(({ data: res }) => {
if (res && res.code === 0) {
const dataFormKeys = Object.keys(this.dataForm);
console.log("keys ===> ", dataFormKeys);
// console.log('data form keys: ', dataFormKeys, pick(res.data, dataFormKeys))
this.dataForm = __pick(res.data, dataFormKeys);
console.log("pick(res.data, dataFormKeys) ===> ", __pick(res.data, dataFormKeys));
}
this.loadingStatus = false;
});
} else {
// 如果不是编辑
this.selfVisible = true;
}
});
},
/** handlers */
handleSelectChange(col, eventValue) {
// console.log("[dialog] select change: ", col, eventValue);
this.$forceUpdate();
},
handleSwitchChange(val) {
console.log("[dialog] switch change: ", val, this.dataForm);
},
handleComponentModelUpdate(propName, { subject, payload: { data } }) {
this.dataForm[propName] = JSON.stringify(data);
console.log("[DialogJustForm] handleComponentModelUpdate", this.dataForm[propName]);
},
handleBtnClick(payload) {
console.log("btn click payload: ", payload);
if ("name" in payload) {
switch (payload.name) {
case "cancel":
this.handleClose();
break;
case "reset":
this.resetForm(true, true); // true means exclude id, immediate execution
break;
case "add":
case "update": {
this.$refs.dataForm.validate((passed, result) => {
if (passed) {
// 如果通过验证
this.loadingStatus = true;
const method = payload.name === "add" ? "POST" : "PUT";
this.$http({
url: this.urls.base,
method,
data: this.dataForm,
})
.then(({ data: res }) => {
console.log("[add&update] res is: ", res);
if (res.code === 0) {
this.$message.success(payload.name === "add" ? "添加成功" : "更新成功");
this.$emit("refreshDataList");
this.loadingStatus = false;
this.handleClose();
}
})
.catch((errMsg) => {
this.$message.error("参数错误:" + errMsg);
if (this.loadingStatus) this.loadingStatus = false;
});
} else {
// 没有通过验证
// this.$message.error(JSON.stringify(result));
this.$message.error("请核查字段信息");
}
});
}
}
} else {
console.log("[x] 不是这么用的! 缺少name属性");
}
},
handleClose() {
// this.resetForm();
this.selfVisible = false;
},
},
};
</script>
<style scoped>
.dialog-just-form >>> .el-dialog__body {
/* padding-top: 16px !important;
padding-bottom: 16px !important; */
padding-top: 0 !important;
padding-bottom: 0 !important;
}
.el-select {
width: 100% !important;
}
.dialog-just-form >>> .el-dialog__header {
padding: 10px 20px 10px;
/* background: linear-gradient(to bottom, rgba(0, 0, 0, 0.25), white); */
}
</style>