参与单位
This commit is contained in:
parent
32d4aff297
commit
d6f3960860
@ -1,32 +1,48 @@
|
||||
<template>
|
||||
<div class="step-units">
|
||||
<el-form ref="formRef" :model="localFormData" :rules="rules" label-position="right" label-width="0px">
|
||||
<el-table :data="localFormData.units" border stripe style="width: 100%">
|
||||
<el-table :data="unitList" border stripe style="width: 100%" row-key="tempId">
|
||||
<el-table-column label="序号" width="80" align="center">
|
||||
<template #default="{ $index }">{{ $index + 1 }}</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="单位类型" width="180" align="center">
|
||||
<el-table-column label="单位类型" width="200" align="center">
|
||||
<template #default="{ row, $index }">
|
||||
<el-form-item v-if="!readonly" :prop="`units.${$index}.unitType`" :rules="[{ required: true, message: '请选择单位类型', trigger: 'change' }]" style="margin: 0;width: 100%;">
|
||||
<el-select v-model="row.unitType" placeholder="请选择" style="width: 100%" :disabled="readonly">
|
||||
<!-- 编辑模式 -->
|
||||
<template v-if="!readonly">
|
||||
<!-- 自定义类型:显示文本输入框 -->
|
||||
<el-input
|
||||
v-if="shouldShowCustomInput(row)"
|
||||
v-model="row.customUnitType"
|
||||
placeholder="请输入单位类型"
|
||||
style="width: 100%"
|
||||
:disabled="readonly"
|
||||
@change="syncToParent"
|
||||
/>
|
||||
<!-- 固定类型:显示下拉框 -->
|
||||
<el-select
|
||||
v-else
|
||||
v-model="row.unitType"
|
||||
placeholder="请选择"
|
||||
style="width: 100%"
|
||||
:disabled="readonly"
|
||||
@change="syncToParent"
|
||||
>
|
||||
<el-option label="主办单位" :value="0" />
|
||||
<el-option label="承办单位" :value="1" />
|
||||
<el-option label="协办单位" :value="2" />
|
||||
<el-option label="赞助单位" :value="3" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<!-- 只读模式 -->
|
||||
<span v-else>
|
||||
{{ row.unitType === 0 ? '主办单位' : row.unitType === 1 ? '承办单位' : row.unitType === 2 ? '协办单位' : row.unitType === 3 ? '赞助单位' : '-' }}
|
||||
{{ row.customUnitType || getUnitTypeLabel(row.unitType) }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="单位名称" min-width="220" align="center">
|
||||
<template #default="{ row, $index }">
|
||||
<el-form-item v-if="!readonly" :prop="`units.${$index}.unitName`" :rules="[{ required: true, message: '请输入单位名称', trigger: 'blur' }]" style="margin: 0">
|
||||
<el-input v-model="row.unitName" placeholder="请输入单位名称" :disabled="readonly" />
|
||||
</el-form-item>
|
||||
<el-input v-if="!readonly" v-model="row.unitName" placeholder="请输入单位名称" :disabled="readonly" @change="syncToParent" />
|
||||
<span v-else>{{ row.unitName }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -43,27 +59,32 @@
|
||||
|
||||
<el-table-column label="排序" width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-input-number v-if="!readonly" v-model="row.sort" :min="0" :step="1" :disabled="readonly" />
|
||||
<el-input-number v-if="!readonly" v-model="row.sort" :min="0" :step="1" :disabled="readonly" @change="syncToParent" />
|
||||
<span v-else>{{ row.sort }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column v-if="!readonly" label="操作" width="120" align="center">
|
||||
<el-table-column v-if="!readonly" label="操作" width="150" align="center">
|
||||
<template #default="{ $index }">
|
||||
<el-button text type="danger" icon="ele-Delete" @click="remove($index)" :disabled="localFormData.units.length <= 1">删除</el-button>
|
||||
<el-button text type="primary" @click="toggleTypeMode($index)">
|
||||
{{ shouldShowCustomInput(unitList[$index]) ? '固定类型' : '自定义类型' }}
|
||||
</el-button>
|
||||
<el-button text type="danger" icon="ele-Delete" @click="remove($index)" :disabled="unitList.length <= 1">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div v-if="!readonly" style="display: flex; justify-content: center; margin-top: 16px">
|
||||
<el-button type="primary" plain icon="ele-Plus" @click="add">添加单位</el-button>
|
||||
<div v-if="!readonly" style="display: flex; justify-content: center; gap: 12px; margin-top: 16px">
|
||||
<el-button type="primary" plain icon="ele-Plus" @click="addPresetUnit">添加预设单位</el-button>
|
||||
<el-button type="success" plain icon="ele-Edit" @click="addCustomUnit">添加自定义单位</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import { ref, watch, nextTick } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { Plus } from '@element-plus/icons-vue';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: { type: Object, required: true },
|
||||
@ -71,53 +92,178 @@ const props = defineProps({
|
||||
});
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
||||
const formRef = ref(null);
|
||||
const localFormData = ref({ units: [] });
|
||||
const add = () => {
|
||||
localFormData.value.units.push({ unitType: '', unitName: '', logoUrl: '', sort: localFormData.value.units.length });
|
||||
const unitList = ref([]);
|
||||
const tempIdCounter = ref(0);
|
||||
|
||||
// 判断是否应该显示自定义输入框 - 只受 isCustomType 布尔值控制
|
||||
const shouldShowCustomInput = (row) => {
|
||||
if (!row) return false;
|
||||
// 完全只根据 isCustomType 布尔值判断,不受输入内容影响
|
||||
return row.isCustomType === true;
|
||||
};
|
||||
const setting = ref(false)
|
||||
|
||||
// 获取临时唯一 ID
|
||||
const getNextTempId = () => {
|
||||
return `unit_${Date.now()}_${tempIdCounter.value++}`;
|
||||
};
|
||||
|
||||
// 获取单位类型标签
|
||||
const getUnitTypeLabel = (type) => {
|
||||
const labels = {
|
||||
0: '主办单位',
|
||||
1: '承办单位',
|
||||
2: '协办单位',
|
||||
3: '赞助单位'
|
||||
};
|
||||
return labels[type] || '-';
|
||||
};
|
||||
|
||||
// 同步数据到父组件 - 立即同步
|
||||
const syncToParent = () => {
|
||||
// 移除临时标记,只保留业务字段
|
||||
const units = unitList.value.map(({ tempId, isCustomType, ...rest }) => rest);
|
||||
|
||||
emit('update:modelValue', {
|
||||
...props.modelValue,
|
||||
units
|
||||
});
|
||||
};
|
||||
|
||||
// 创建新单位对象
|
||||
const createUnitObj = (isCustom = false) => ({
|
||||
tempId: getNextTempId(),
|
||||
unitType: 0,
|
||||
unitName: '',
|
||||
logoUrl: '',
|
||||
sort: unitList.value.length,
|
||||
customUnitType: isCustom ? '' : undefined,
|
||||
isCustomType: isCustom
|
||||
});
|
||||
|
||||
// 添加预设单位(下拉选择)
|
||||
const addPresetUnit = () => {
|
||||
const newUnit = createUnitObj(false);
|
||||
unitList.value.push(newUnit);
|
||||
nextTick(() => {
|
||||
syncToParent();
|
||||
});
|
||||
};
|
||||
|
||||
// 添加自定义单位(文本输入)
|
||||
const addCustomUnit = () => {
|
||||
const newUnit = createUnitObj(true);
|
||||
unitList.value.push(newUnit);
|
||||
ElMessage.success('已添加自定义单位行,请填写信息');
|
||||
nextTick(() => {
|
||||
syncToParent();
|
||||
});
|
||||
};
|
||||
|
||||
// 切换输入模式
|
||||
const toggleTypeMode = (index) => {
|
||||
const unit = unitList.value[index];
|
||||
|
||||
if (shouldShowCustomInput(unit)) {
|
||||
// 切换到固定类型模式
|
||||
unit.isCustomType = false;
|
||||
// 如果有自定义类型文本,尝试匹配预设类型
|
||||
const typeMap = {
|
||||
'主办单位': 0,
|
||||
'承办单位': 1,
|
||||
'协办单位': 2,
|
||||
'赞助单位': 3
|
||||
};
|
||||
if (unit.customUnitType && typeMap[unit.customUnitType] !== undefined) {
|
||||
unit.unitType = typeMap[unit.customUnitType];
|
||||
}
|
||||
} else {
|
||||
// 切换到自定义类型模式
|
||||
unit.isCustomType = true;
|
||||
// 如果没有自定义类型文本,用当前预设类型作为默认值
|
||||
if (!unit.customUnitType) {
|
||||
unit.customUnitType = getUnitTypeLabel(unit.unitType);
|
||||
}
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
syncToParent();
|
||||
});
|
||||
};
|
||||
|
||||
// 删除单位
|
||||
const remove = (idx) => {
|
||||
unitList.value.splice(idx, 1);
|
||||
// 重新计算排序
|
||||
unitList.value.forEach((unit, index) => {
|
||||
unit.sort = index;
|
||||
});
|
||||
nextTick(() => {
|
||||
syncToParent();
|
||||
});
|
||||
};
|
||||
|
||||
// 初始化或重置数据
|
||||
const initData = (data) => {
|
||||
if (!data || !data.units || data.units.length === 0) {
|
||||
// 空数据,添加一个默认预设单位
|
||||
unitList.value = [createUnitObj(false)];
|
||||
} else {
|
||||
// 处理数据回显
|
||||
unitList.value = data.units.map(unit => {
|
||||
// 只根据是否存在 customUnitType 属性来判断,不考虑其值是否为空
|
||||
const isCustom = unit.customUnitType !== undefined && unit.customUnitType !== null;
|
||||
const newUnit = {
|
||||
...unit,
|
||||
tempId: getNextTempId(),
|
||||
isCustomType: isCustom
|
||||
};
|
||||
return newUnit;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 监听父组件传入的 modelValue 变化 - 总是响应,但要避免循环更新
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
async (v) => {
|
||||
if (!v) return;
|
||||
setting.value = true;
|
||||
localFormData.value.units = v.units;
|
||||
if (!localFormData.value.units.length ) add();
|
||||
setting.value = false;
|
||||
(newVal) => {
|
||||
const currentUnits = unitList.value.map(({ tempId, isCustomType, ...rest }) => rest);
|
||||
const newUnits = newVal?.units || [];
|
||||
|
||||
// 只有当数据真正不同时才更新
|
||||
if (JSON.stringify(currentUnits) !== JSON.stringify(newUnits)) {
|
||||
initData(newVal);
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
localFormData,
|
||||
(v) => {
|
||||
if(!setting.value){
|
||||
emit('update:modelValue', { ...props.modelValue, ...v })
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
|
||||
const handleAvatarSuccess = (response, index) => {
|
||||
console.log('handleAvatarSuccess', response,index);
|
||||
localFormData.value.units[index].logoUrl = response?.[0]?.url;
|
||||
};
|
||||
const remove = (idx) => localFormData.value.units.splice(idx, 1);
|
||||
|
||||
const rules = {
|
||||
units: [{ type: 'array', required: true, message: '请至少添加一个参与单位', trigger: 'change' }],
|
||||
if (unitList.value[index]) {
|
||||
unitList.value[index].logoUrl = response?.[0]?.url;
|
||||
nextTick(() => {
|
||||
syncToParent();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const validate = async () => {
|
||||
console.log('validate', formRef.value);
|
||||
if (!formRef.value) return false;
|
||||
if(!localFormData.value.units.length){
|
||||
if (!unitList.value || unitList.value.length === 0) {
|
||||
ElMessage.error('请至少添加一个参与单位');
|
||||
return false;
|
||||
}
|
||||
return await formRef.value.validate();
|
||||
|
||||
// 手动验证每个行的必填字段
|
||||
let isValid = true;
|
||||
for (let i = 0; i < unitList.value.length; i++) {
|
||||
const unit = unitList.value[i];
|
||||
if (!unit.unitName || unit.unitName.trim() === '') {
|
||||
ElMessage.error(`第${i + 1}行的单位名称不能为空`);
|
||||
isValid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return isValid;
|
||||
};
|
||||
|
||||
defineExpose({ validate });
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user