Files
Web_BLS_Vue_Prod/src/pages/dicmanage/index.vue

499 lines
14 KiB
Vue
Raw Normal View History

2025-11-20 14:12:37 +08:00
<template>
<div class="container">
<div class="header">
<div>字典名称</div>
<el-select v-model="currentVarName"
placeholder="请选择字典项"
@change="handleDictChange">
<el-option v-for="item in dictList"
:key="item.varName"
:label="item.varName"
:value="item.varName" />
</el-select>
</div>
<div>字典修改</div>
<!-- 区域字典特殊表格 -->
<el-table v-if="isRegionDict"
:data="regionData"
stripe
style="width: 777px">
<el-table-column prop="key" label="大区名称">
<template #default="{ row }">
<el-input v-model="row.key"
placeholder="请输入大区名称" />
</template>
</el-table-column>
<el-table-column prop="value" label="包含省份(点击修改省份/地区)" width="521">
<template #default="{ row }">
<el-button type="primary" @click="showProvinceDialog(row)"
link style="width: 100%; padding: 0; height: auto; min-height: 32px; white-space: normal; word-break: break-all; line-height: 1.5; display: inline-flex; align-items: center;">
<span style="text-align: left;">
{{ row.value.join('') || '点击选择省份' }}
</span>
</el-button>
</template>
</el-table-column>
<el-table-column label="操作" width="63">
<template #default="{ $index }">
<el-button type="danger"
:icon="Delete"
circle
@click="deleteRegion($index)" />
</template>
</el-table-column>
</el-table>
<!-- 普通字典表格 -->
<el-table v-else
:data="currentValues"
stripe
style="width: 777px">
<el-table-column prop="value" label="字典值">
<template #default="{ $index }">
<el-input v-model="currentValues[$index]" placeholder="请输入" />
</template>
</el-table-column>
<el-table-column label="操作" width="63">
<template #default="{ $index }">
<el-button type="danger"
:icon="Delete"
circle
@click="handleDelete($index)" />
</template>
</el-table-column>
</el-table>
<!-- 操作按钮区域 -->
<div class="footer">
<template v-if="isRegionDict">
<el-button type="primary"
:icon="Plus"
plain
round
@click="addNewRegion">
添加大区
</el-button>
</template>
<template v-else>
<el-button type="primary"
:icon="Plus"
plain
round
@click="handleAdd">
添加值
</el-button>
</template>
<el-button type="success"
:icon="FolderChecked"
@click="handleSave">
保存
</el-button>
</div>
<!-- 省份选择对话框 -->
<el-dialog v-model="provinceDialogVisible"
title="选择省份/地区"
width="50%">
<el-checkbox-group v-model="selectedProvinces">
<el-row :gutter="20">
<el-col v-for="province in allProvinces"
:key="province"
:span="8"
style="margin-bottom: 15px;">
<el-checkbox :label="province"
:value="province" />
</el-col>
</el-row>
</el-checkbox-group>
<template #footer>
<el-button @click="provinceDialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmProvinceSelection">
确定
</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, inject, computed } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { Plus, Delete, Edit, UploadFilled, RefreshLeft, Upload, EditPen, FolderChecked } from '@element-plus/icons-vue';
const $http = inject('$http')
const config = inject('config');
// 初始字典数据
const dictList = reactive([]);
// 新增响应式数据
const provinceDialogVisible = ref(false);
const selectedProvinces = ref([]);
const currentEditingRegion = ref(null);
const allProvinces = computed(() => {
const provinceDict = dictList.find(d => d.varName == '省份地区');
return provinceDict?.varValue || [];
});
// 获取字典
const getDic = async () => {
try {
const response = await $http.post('ConfigPY/GetConfigString');
const serverData = response.data.response || [];
//console.log(response);
// 清空原有数据
dictList.length = 0;
// 转换数据格式
serverData.forEach(item => {
dictList.push({
varName: item.varName,
varValue: tryParseJson(item.varValue) || []
});
});
//console.log(dictList);
// 默认选中第一个(如果存在)
if (dictList.length > 0) {
currentVarName.value = dictList[0].varName;
}
} catch (error) {
console.error('获取字典失败:', error);
ElMessage.error('字典数据加载失败');
}
};
// JSON安全解析方法
const tryParseJson = (str) => {
try {
return JSON.parse(str);
} catch {
return null;
}
};
const currentVarName = ref('');
const currentDict = computed(() =>
dictList.find(item => item.varName === currentVarName.value)
);
const currentValues = computed({
get: () => currentDict.value?.varValue || [],
set: (val) => {
if (currentDict.value) {
currentDict.value.varValue = val;
}
}
});
// 处理字典项变化
const handleDictChange = (val) => {
if (!val) return;
};
// 判断是否是区域字典
const isRegionDict = computed(() => currentVarName.value === '区域');
// 修改区域数据计算属性移除setter
const regionData = computed(() => {
if (!isRegionDict.value) return [];
const regionDict = dictList.find(d => d.varName === '区域');
return Object.entries(regionDict?.varValue || {}).map(([key, value]) => ({
key,
value: Array.isArray(value) ? value : [value]
}));
});
// 显示省份选择对话框
const showProvinceDialog = (row) => {
currentEditingRegion.value = row;
selectedProvinces.value = [...row.value];
provinceDialogVisible.value = true;
};
// 修改省份选择确认方法
const confirmProvinceSelection = async () => {
try {
if (!currentEditingRegion.value) return;
// 获取当前编辑的大区信息
const currentKey = currentEditingRegion.value.key;
const selectedProvincesList = selectedProvinces.value;
// 获取区域字典数据
const regionDict = dictList.find(d => d.varName === '区域');
if (!regionDict) return;
// 收集所有其他大区的省份映射
const provinceMap = new Map();
Object.entries(regionDict.varValue).forEach(([region, provinces]) => {
if (region !== currentKey) {
provinces.forEach(province => {
provinceMap.set(province, region);
});
}
});
// 检查重复省份
const duplicates = [];
selectedProvincesList.forEach(province => {
if (provinceMap.has(province)) {
duplicates.push({
province,
region: provinceMap.get(province)
});
}
});
// 如果有重复则提示
if (duplicates.length > 0) {
const confirmMessage = `
以下省份已在其他大区存在<br>
${duplicates.map(d => `${d.province}${d.region}`).join('<br>')}<br>
是否确认继续保存
`;
await ElMessageBox.confirm(confirmMessage, '重复省份警告', {
confirmButtonText: '强制保存',
cancelButtonText: '返回修改',
type: 'warning',
dangerouslyUseHTMLString: true
});
}
// 执行保存操作
regionDict.varValue = {
...regionDict.varValue,
[currentKey]: selectedProvincesList
};
provinceDialogVisible.value = false;
} catch (error) {
if (error !== 'cancel') {
console.error(error);
}
return; // 用户取消则中断流程
}
};
/* const confirmProvinceSelection = () => {
if (currentEditingRegion.value) {
const regionDict = dictList.find(d => d.varName === '区域');
if (regionDict) {
regionDict.varValue = {
...regionDict.varValue,
[currentEditingRegion.value.key]: selectedProvinces.value
};
}
}
provinceDialogVisible.value = false;
};*/
// 修改添加大区方法
const addNewRegion = () => {
const regionDict = dictList.find(d => d.varName === '区域');
if (!regionDict) return;
// 生成唯一键名
let newKey = "新增大区";
let counter = 1;
while (regionDict.varValue[newKey]) {
newKey = `新增大区${counter++}`;
}
// 直接修改原始数据
regionDict.varValue = {
...regionDict.varValue,
[newKey]: []
};
};
// 修改删除大区方法
const deleteRegion = (index) => {
ElMessageBox.confirm('确定要删除该大区吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const regionDict = dictList.find(d => d.varName === '区域');
if (!regionDict) return;
const keyToDelete = regionData.value[index].key;
const newValue = { ...regionDict.varValue };
delete newValue[keyToDelete];
regionDict.varValue = newValue;
});
};
// 添加行
const handleAdd = () => {
if (!currentDict.value) return;
currentDict.value.varValue.push('');
};
// 删除行
const handleDelete = (index) => {
ElMessageBox.confirm('确定要删除该行吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
currentDict.value.varValue.splice(index, 1);
});
};
// 保存字典
const saveDic = async (name, value) => {
try {
let filteredValue;
// 根据数据类型处理
if (Array.isArray(value)) {
// 处理普通数组格式
filteredValue = value
.map(item => String(item).trim())
.filter(item => item !== "");
if (filteredValue.length === 0) {
throw new Error("不能保存空字典项");
}
} else if (typeof value === 'object' && value !== null) {
// 处理区域字典的对象格式
filteredValue = Object.entries(value).reduce((acc, [key, values]) => {
const filtered = values
.map(item => String(item).trim())
.filter(item => item !== "");
// 保留key即使值为空数组如"其他"
if (key === '其他' || filtered.length > 0) {
acc[key] = filtered;
}
return acc;
}, {});
// 检查是否为空对象
if (Object.keys(filteredValue).length === 0) {
throw new Error("至少需要保留一个有效区域");
}
} else {
throw new Error("无效的字典格式");
}
const valueJs = JSON.stringify(filteredValue);
const rs = await $http.post('ConfigPY/SaveOrAddConfigString', {
VarName: name,
VarValue: valueJs
});
return filteredValue;
} catch (error) {
console.error(error);
throw error;
}
};
// 保存处理
const handleSave = async () => {
if (!currentDict.value) {
ElMessage.warning('请先选择要修改的字典项');
return;
}
try {
await ElMessageBox.confirm(
'此操作将永久修改字典数据,是否继续?',
'警告',
{
confirmButtonText: '确认保存',
cancelButtonText: '取消',
type: 'warning',
center: true,
dangerouslyUseHTMLString: true,
beforeClose: (action, instance, done) => {
if (action === 'confirm') {
instance.confirmButtonLoading = true;
saveDic(currentDict.value.varName, currentDict.value.varValue)
.then(() => {
done();
ElMessage.success('保存成功');
})
.catch(() => {
instance.confirmButtonLoading = false;
ElMessage.error('保存失败');
});
} else {
done();
}
}
}
);
// 处理区域字典的特殊结构
let saveData = currentDict.value.varValue;
if (isRegionDict.value) {
// 转换回原始对象格式
saveData = regionData.value.reduce((acc, cur) => {
acc[cur.key] = cur.value;
return acc;
}, {});
}
// 保存并获取处理后的数据
const filteredData = await saveDic(
currentDict.value.varName,
saveData
);
// 更新前端数据
currentDict.value.varValue = isRegionDict.value
? { ...filteredData } // 对象格式
: [...filteredData]; // 数组格式
} catch (error) {
if (error === 'cancel') {
//console.log('用户取消保存');
} else if (error.message === '不能保存空字典项') {
ElMessage.warning('字典项至少需要包含一个有效值');
} else {
ElMessage.error('保存失败: ' + error.message);
}
}
};
onMounted(() => {
getDic()
// 初始化选择第一个
if (dictList.length > 0) {
currentVarName.value = dictList[0].varName;
}
});
</script>
<style scoped>
.container {
display: block;
padding: 20px;
width: 100%;
}
.header {
width: 333px;
margin-bottom: 20px;
}
.footer {
width: 777px;
display: flex;
justify-content: space-between; /* 推荐方案 */
gap: 10px;
margin-top: 20px;
}
.el-message-box {
max-height: 70vh;
overflow-y: auto;
}
</style>