华西海圻ELN前端工程
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

494 lines
19 KiB

<template>
<div>
<LineLabel v-if="label" :label = "label"/>
<div v-for="(item, index) in formConfig" :key="index">
<template v-if="item.type === 'cardItem'">
<div class="grid-container">
<div v-for="(sItem, key) in item.config" class="form-item" :class="sItem.span == 1 ? 'full-row' : ''"
:key="key">
<template v-if="sItem.type === 'input'">
<div class="form-title">{{ sItem.label }}</div>
<HandleFormItem @blur="onBlur(key, $event)" :item="sItem" v-model="formFields[key]"
@copy="onCopy(sItem, key)" />
</template>
<template v-else-if="sItem.type === 'inputNumber'">
<div class="form-title">{{ sItem.label }}</div>
<HandleFormItem type = "inputNumber" @blur="onBlur(key, $event)" :item="sItem" @input = "onInputNumberChange(key, $event)" v-model="formFields[key]"
@copy="onCopy(sItem, key)" />
</template>
</div>
</div>
</template>
<template v-else-if="item.type === 'conditionItem'">
<div class="form-item ">
<div class="form-title fs-16" v-if="item.label">{{ item.label }}</div>
<div v-for="(sItem, key) in item.config" class="c-Item grid-container">
<div class="p-r-20">
<div class="form-title">{{ sItem.label }}</div>
<div class="flex ">
<HandleFormItem type="select" :item="sItem" v-model="formFields[key]"
@copy="onCopy(sItem, key)" @change="onSelectChange(key, $event)" />
</div>
</div>
<div class="p-l-20">
<div v-show="isShowOther(formFields[key])">
<div class="form-title">其他</div>
<div class="flex">
<HandleFormItem @blur="onBlur(key, $event)" :item="getOtherItem(sItem)" v-model="formFields[sItem.otherCode]"
@copy="onCopy(sItem, key)" />
</div>
</div>
</div>
</div>
</div>
</template>
<template v-else-if="item.type === 'cellItem'">
<div class="form-item ">
<div class="form-title fs-16" v-if="item.label">{{ item.label }}</div>
<div class="grid-container gap2">
<div v-for="(sItem, key) in item.config" class="c-Item" :class="getSpanClass(sItem)"
:key="key">
<div class="form-title" v-if="sItem.label">{{ sItem.label }}</div>
<div v-if="sItem.type === 'dateTime'" class="flex1">
<HandleFormItem type="dateTime" :item="sItem" v-model="formFields[key]"
@copy="onCopy(sItem, key)" />
</div>
<div v-else-if="sItem.type === 'select'">
<HandleFormItem type="select" :item="sItem" v-model="formFields[key]"
@copy="onCopy(sItem, key)" @change="onSelectChange(key, $event)" />
</div>
<div v-else-if="sItem.type === 'input'">
<HandleFormItem @blur="onBlur(key, $event)" :item="sItem" v-model="formFields[key]"
@copy="onCopy(sItem, key)" />
</div>
<div v-else-if="sItem.type === 'textarea'">
<HandleFormItem @blur="onBlur(key, $event)" type="textarea" :item="sItem" v-model="formFields[key]"
@copy="onCopy(sItem, key)" />
</div>
</div>
</div>
</div>
</template>
<template v-else-if="item.type === 'step'">
<div class="grid-container gap2">
<div v-for="(sItem, key) in item.config" class="c-Item flex item-center" :class="getSpanClass(sItem)"
:key="key">
<div class="step-form-title" v-if="sItem.label">{{ sItem.label }}</div>
<div v-if="sItem.type === 'dateTime'" class="flex1">
<HandleFormItem type="dateTime" :item="sItem" v-model="formFields[key]"
@copy="onCopy(sItem, key)" />
</div>
<div v-else-if="sItem.type === 'select'" class="flex flex1">
<HandleFormItem type="select" :item="sItem" style="width: auto;flex:1" v-model="formFields[key]"
@copy="onCopy(sItem, key)" @change="onSelectChange(key, $event)" />
<div v-show="isShowOther(formFields[key])" class="flex flex1">
<div class="other-title">其他</div>
<div class="flex">
<HandleFormItem @blur="onBlur(key, $event)" class="sub-select" :item="getOtherItem(sItem)" v-model="formFields[sItem.otherCode]"
@copy="onCopy(sItem, key)" />
</div>
</div>
</div>
<div v-else-if="sItem.type === 'input'" class="flex flex1">
<HandleFormItem @blur="onBlur(key, $event)" class="flex1" :item="sItem" v-model="formFields[key]"
@copy="onCopy(sItem, key)" />
<HandleFormItem v-if="sItem.subType === 'select'" type="select" class="sub-select" :item="getSubItem(sItem)" v-model="formFields[sItem.subKey]"
@copy="onCopy(sItem, key)" @change="onSelectChange(sItem.subKey, $event)" />
<div v-else-if="sItem.subType === 'span'">{{ formFields[sItem.subKey] }}</div>
<HandleFormItem v-else-if="sItem.subType === 'clickable'" type="clickable" @clickable="handleClickable(sItem,$event)" class="sub-select" :item="getClickableItem(sItem)" :value="formFields[sItem.subKey]"
/>
<!-- <div class="clickable" :class="getFillType(sItem.subFillType)" v-else-if = "sItem.subType ==='clickable'" @click="handleClickable(sItem,$event)">
<span v-if="formFields[sItem.subKey]">{{ formFields[sItem.subKey] }}</span>
<span v-else class="default-placeholder-text">请选择</span>
</div> -->
</div>
<div v-else-if="sItem.type === 'inputNumber'" class="flex flex1">
<HandleFormItem type = "inputNumber" @blur="onBlur(key, $event)" class="flex1" :item="sItem" @input = "onInputNumberChange(key, $event)" :value = "formFields[key]"
@copy="onCopy(sItem, key)" />
<HandleFormItem v-if="sItem.subType === 'select'" type="select" class="sub-select" :item="getSubItem(sItem)" v-model="formFields[sItem.subKey]"
@copy="onCopy(sItem, key)" @change="onSelectChange(sItem.subKey, $event)" />
<div v-else-if="sItem.subType === 'span'">{{ formFields[sItem.subKey] }}</div>
<HandleFormItem v-else-if="sItem.subType === 'clickable'" @clickable="handleClickable(sItem,$event)" type="clickable" class="sub-select" :item="getClickableItem(sItem)" :value="formFields[sItem.subKey]"
/>
<!-- <div class="clickable" :class="getFillType(sItem.subFillType)" v-else-if = "sItem.subType ==='clickable'" @click="handleClickable(sItem,$event)">
<span v-if="formFields[sItem.subKey]">{{ formFields[sItem.subKey] }}</span>
<span v-else class="default-placeholder-text">请选择</span>
</div> -->
</div>
</div>
</div>
</template>
</div>
</div>
</template>
<script>
import HandleFormItem from "./HandleFormItem.vue";
import LineLabel from "./LineLabel.vue";
export default {
components: {
HandleFormItem,
LineLabel
},
props: {
label:{//当前表单的标题
type: String,
default: "",
},
formConfig: {
type: Array,
value: () => [],
},
formData: {
type: Object,
value: () => ({})
}
},
data() {
return {
formFields: {},//表单绑定字段
allFieldsConfig: {},//包含config的所有字段,主要用于校验表单是否填写
};
},
watch: {
formData: {
immediate: true,
deep: true, // 深度监听,以便检测嵌套对象变化
handler(v) {
if(v){
this.handleFormField();
}
}
},
formConfig: {
immediate: true,
deep: true, // 深度监听,以便检测嵌套对象变化
handler(v) {
this.handleFormField();
}
}
},
mounted() {
this.handleFormField();
},
methods: {
getFillType(type) {
const typeObj = {
actFill: "orange-border",//实际填写的边框颜色
green: "green-border",
preFill: "blue-border",//预填写的边框颜色
}
return typeObj[type] || ""
},
onInputNumberChange(key, val){
this.formFields[key] = val;
},
updateFormData(key, value){
this.formFields[key] = value;
},
batchUpdateFormData(data){
Object.keys(data).forEach(key => {
this.formFields[key] = data[key];
})
},
handleClickable(sItem,event){
if(this.fillType !== 'actFill'){
return
}
this.$emit("clickable",sItem)
},
//根据span判断一行显示几列
getSpanClass(sItem){
const spanArr = ["full-row","","three-row"]
if(sItem.span){
return spanArr[sItem.span-1]
}
return ""
},
//获取其他下拉框的配置
getOtherItem(sItem){
return {
label:"其他",
fillType: sItem.fillType,
maxlength: sItem.otherMaxlength || 50,
}
},
getClickableItem(sItem){
return {
label: "",
type: "clickable",
fillType: sItem.subFillType || sItem.fillType,
}
},
getSubItem(sItem){
return {
label: "",
options: sItem.subOptions || [],
fillType: sItem.subFillType || sItem.fillType,
}
},
isShowOther(v = []) {
// 确保v是数组类型,以避免类型错误
const arr = Array.isArray(v) ? v : [v];
//和凡哥商量,只要value为负数都显示其他
return arr.some(item => item<0);
},
// 根据formConfig回填form表单数据
handleFormField() {
const result = {};
let config = {};
const { formConfig, formData, formFields } = this;
// 遍历配置
formConfig.forEach((item) => {
if (item.config) {
// 合并配置项
config = { ...config, ...item.config }
// 处理每个配置项
Object.keys(item.config).forEach(key => {
const currentConfig = item.config[key];
let value = formData[key];
// 如果formFields中已经有值,保持原值(用户输入或之前设置的值)
if (formFields[key] !== null &&
formFields[key] !== undefined &&
formFields[key] !== ''&&
typeof formFields[key] !== 'object'
) {
console.log(key,formData,formFields[key],"kkk")
// 保留原值,不使用formData中的值
result[key] = formFields[key];
} else {
// 使用formData中的值
result[key] = value;
}
// 处理特殊字段 - "其他"字段
if (currentConfig.otherCode) {
const { otherCode } = currentConfig;
result[otherCode] = formData[otherCode] || '';
config[otherCode] = { label: "其他", type: "input" }
}
if (currentConfig.subKey) {
const { subKey } = currentConfig;
result[subKey] = formData[subKey] || '';
config[subKey] = { label: currentConfig.label, type: currentConfig.subType }
}
});
// 处理可能存在的直接otherCode字段
if (item.config?.otherCode) {
config[item.config?.otherCode] = item.config?.otherCode;
}
}
});
console.log(result,"initResult")
// 更新表单字段
this.formFields = result;
this.allFieldsConfig = config;
console.log(config,"config")
},
//判断是否禁用
getDisabled() {
const { item } = this;
const { fillType } = item;
if (item.hasOwnProperty("disabled")) {
return item.disabled
} else {
const { templateStatus } = this.$store.state.template;
if (fillType === "actFill") {//当模板状态是实际填写时,只有当fillType是actFill时才能填写
return templateStatus !== "actFill"
} else if (fillType === "preFill") {//当模板状态是预填写时,只有当fillType是preFill才能填写
return templateStatus !== "preFill"
} else {
return true
}
}
},
getFormData() {
const { formFields, allFieldsConfig } = this;
const { templateStatus } = this.$store.state.template;
return new Promise((resolve,reject)=>{
for (const key in formFields) {
console.log(key,formFields[key])
if (!formFields[key]) {
const o = allFieldsConfig[key];
if (o.fillType == templateStatus && !o.disabled) {
let prefix = "";
if (o.type === "input" || o.type === "inputNumber" || o.type === "textarea") {
prefix = "填写"
} else {
prefix = "选择"
}
this.$message.error(`${o.label}还未${prefix}请${prefix}后再提交`);
reject(`${o.label}还未${prefix}`);
return;
}
}
}
resolve(formFields)
})
},
getFormDataByKey(key){
return this.formFields[key];
},
onBlur(key, val) {
this.$emit("blur", { key, value: val ,...this.formFields});
},
onSelectChange(key, val) {
// 获取对应的配置
const currentConfig = this.allFieldsConfig[key];
// // 确保多选下拉框的值是数组类型
// if (currentConfig && currentConfig.multiple) {
// // 多选情况,确保值为数组类型
// this.formFields[key] = Array.isArray(val) ? val : (val ? [val] : []);
// } else {
// 单选情况
this.formFields[key] = val;
// }
this.$emit("select", { key, value: val });
},
//复制
onCopy(config, key) {
const { formFields } = this;
if (config.copyFrom) {
formFields[key] = formFields[config.copyFrom]
}
},
},
}
</script>
<style lang="scss">
.grid-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
/* 默认2列 */
gap: 0 20px;
}
.gap2{
gap:0 64px;
}
.w-100 {
width: 100%;
}
.form-item {
background: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
margin-top: 20px;
padding: 20px;
border-radius: 5px 5px;
}
/* 或者使用 span 语法 */
.full-row {
grid-column: span 2;
}
.three-row {
grid-column: span 3;
}
.c-Item {
&:not(:last-child) {
margin-bottom: 16px;
}
}
.eo{
&:nth-child(even) {
padding-left: 20px;
}
&:nth-child(odd) {
padding-right: 20px;
}
}
.default-placeholder-text{
color: #C0C4CC;
}
.form-title {
margin-bottom: 12px;
font-size: 14px;
font-weight: normal;
color: #606266;
}
.step-form-title{
font-size: 14px;
font-weight: normal;
color: #606266;
width: 150px;
text-align: right;
padding-right: 10px;
}
.p-r-20{
padding-right: 20px;
}
.p-l-20{
padding-left: 20px;
}
.fs-16 {
font-size: 0.96rem;
font-weight: bold;
color: #464647
}
.flex1 {
flex: 1;
}
.flex {
display: flex;
}
.other-title{
width: 50px;
text-align: right;
margin: 0 10px;
}
.mr-24 {
margin-right: 24px;
}
.sub-select{
width: auto;
margin-left: 10px;
}
.clickable{
cursor: pointer;
width: auto;
margin-left: 10px;
min-width: 100px;
height: 28px;
border-radius: 4px;
border:1px solid #4ea2ff;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: normal;
color: #606266;
}
.orange-border {
border-color: #f9c588;
}
.green-border {
border-color: green;
}
.blue-border {
border-color: #4ea2ff;
}
</style>