初始化
This commit is contained in:
498
src/pages/dicmanage/index.vue
Normal file
498
src/pages/dicmanage/index.vue
Normal file
@@ -0,0 +1,498 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user