字典类型管理+字典数据管理

This commit is contained in:
Lxq
2026-01-05 13:07:30 +08:00
parent bdd50a498b
commit 5f6808b2a4
4 changed files with 617 additions and 8 deletions

View File

@@ -201,6 +201,55 @@
</template>
</el-drawer>
<!-- 下拉框选项配置对话框 -->
<el-dialog
v-model="selectOptionsDialogVisible"
:title="`[${currentSelectParam?.paramName || ''}]下拉框选项列表配置`"
width="600px"
:before-close="handleSelectOptionsDialogClose"
>
<div class="select-options-container">
<!-- 输入区域 -->
<div class="select-options-input-area">
<span class="input-label">选项数据</span>
<el-input
v-model="selectOptionInput"
placeholder="请输入选项数据"
clearable
style="flex: 1; margin-right: 8px"
@keyup.enter="handleAddSelectOption"
/>
<el-button type="primary" @click="handleAddSelectOption">添加</el-button>
</div>
<!-- 选项卡片列表 -->
<div class="select-options-cards">
<div
v-for="option in selectOptionsList"
:key="option.id"
class="select-option-card"
>
<span class="option-text">{{ option.dicValue }}</span>
<el-icon
class="option-delete-icon"
@click="handleDeleteSelectOption(option)"
>
<Close />
</el-icon>
</div>
<div v-if="selectOptionsList.length === 0" class="empty-tip">
暂无选项数据请添加
</div>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleSelectOptionsDialogClose">取消</el-button>
<el-button type="primary" @click="handleSaveSelectOptions">保存</el-button>
</div>
</template>
</el-dialog>
<!-- 参数配置对话框 -->
<el-dialog
v-model="paramDialogVisible"
@@ -276,7 +325,7 @@
</el-table-column>
<!-- 表单控件 -->
<el-table-column label="表单控件" min-width="120">
<el-table-column label="表单控件" min-width="120" align="left">
<template #default="{ row }">
<el-select
v-if="row.isEditing"
@@ -292,7 +341,17 @@
:value="form.value"
/>
</el-select>
<span v-else>{{ row.formType || '暂无' }}</span>
<el-button
v-else-if="row.formType === 'select'"
type="success"
size="small"
link
class="form-type-select-btn"
@click="handleConfigSelectOptions(row)"
>
下拉框
</el-button>
<span v-else>{{ getFormTypeLabel(row.formType) || '暂无' }}</span>
</template>
</el-table-column>
@@ -353,7 +412,7 @@
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, Edit, Delete, Setting, Check } from '@element-plus/icons-vue'
import { Plus, Edit, Delete, Setting, Check, Close } from '@element-plus/icons-vue'
import {
devInfoadd,
devInfodel,
@@ -369,6 +428,8 @@ import {
devparamlist,
devparambyid,
} from '@/api/tb/devparam'
import { dictypeadd, dictypelist } from '@/api/system/dictype'
import { dicdataadd, dicdatadel, dicdatabydicid } from '@/api/system/dicdata'
// 加载状态
const loading = ref(false)
@@ -769,6 +830,12 @@ const getParamIndex = (index: number) => {
return (paramPagination.pageNum - 1) * paramPagination.pageSize + index + 1
}
// 获取表单控件标签
const getFormTypeLabel = (formType: string) => {
const option = formTypeOptions.find((item) => item.value === formType)
return option ? option.label : formType
}
// 打开参数配置对话框
const handleConfigParams = async (row: any) => {
currentDevice.value = row
@@ -935,6 +1002,37 @@ const handleSaveParam = async (row: any) => {
if (wasNew) {
await getParamList()
}
// 如果表单控件是下拉框,检查是否已配置过选项,只有未配置时才弹出配置对话框
if (row.formType === 'select') {
// 查找对应的字典类型
const dicTypeListRes: any = await dictypelist({
pageNum: 1,
pageSize: 1000,
})
const dicTypeData = dicTypeListRes?.data ?? dicTypeListRes ?? {}
const dicTypeRecords = dicTypeData.records || dicTypeData.list || dicTypeData.rows || []
const dicType = dicTypeRecords.find(
(item: any) => item.dicName === row.paramName
)
if (dicType) {
// 检查是否已有选项数据
const optionsRes: any = await dicdatabydicid(dicType.id)
const optionsData = optionsRes?.data ?? optionsRes ?? {}
const optionsRecords = Array.isArray(optionsData) ? optionsData : (optionsData.records || optionsData.list || optionsData.rows || [])
// 只有没有选项数据时才弹出配置对话框
if (optionsRecords.length === 0) {
await handleCreateDicTypeAndShowConfig(row)
}
} else {
// 如果字典类型不存在,创建并弹出配置对话框
await handleCreateDicTypeAndShowConfig(row)
}
}
} else {
ElMessage.error(res?.message || res?.msg || (row.isNew ? '新增失败' : '更新失败'))
}
@@ -946,6 +1044,87 @@ const handleSaveParam = async (row: any) => {
}
}
// 创建字典类型并显示配置对话框
const handleCreateDicTypeAndShowConfig = async (row: any) => {
try {
// 检查是否已存在该字典类型
const dicTypeListRes: any = await dictypelist({
pageNum: 1,
pageSize: 1000,
})
const dicTypeData = dicTypeListRes?.data ?? dicTypeListRes ?? {}
const dicTypeRecords = dicTypeData.records || dicTypeData.list || dicTypeData.rows || []
// 查找是否已存在相同名称的字典类型
const existingDicType = dicTypeRecords.find(
(item: any) => item.dicName === row.paramName
)
let dicTypeId: number | undefined
if (existingDicType) {
// 如果已存在使用现有的ID
dicTypeId = existingDicType.id
} else {
// 如果不存在,创建新的字典类型
const dicTypeRes: any = await dictypeadd({
dicName: row.paramName,
})
if (dicTypeRes?.code === '0' || dicTypeRes?.code === 0 || dicTypeRes?.success) {
// 获取新创建的字典类型ID
const newDicTypeData = dicTypeRes?.data ?? dicTypeRes ?? {}
dicTypeId = newDicTypeData.id
// 如果返回的数据中没有ID重新查询
if (!dicTypeId) {
const refreshListRes: any = await dictypelist({
pageNum: 1,
pageSize: 1000,
})
const refreshData = refreshListRes?.data ?? refreshListRes ?? {}
const refreshRecords = refreshData.records || refreshData.list || refreshData.rows || []
const newDicType = refreshRecords.find(
(item: any) => item.dicName === row.paramName
)
dicTypeId = newDicType?.id
}
} else {
ElMessage.error('创建字典类型失败')
return
}
}
// 打开配置对话框
if (dicTypeId) {
// 先加载选项列表,检查是否已有选项数据
await loadSelectOptions(dicTypeId)
// 如果还没有选项数据,才弹出提示
if (selectOptionsList.value.length === 0) {
await ElMessageBox.alert('请编辑下拉框选项列表内容', '提示', {
confirmButtonText: '确定',
type: 'info',
})
}
currentSelectParam.value = {
...row,
dicTypeId: dicTypeId,
}
selectOptionsDialogVisible.value = true
} else {
ElMessage.error('无法获取字典类型ID')
}
} catch (error: any) {
if (error !== 'cancel') {
console.error('创建字典类型失败:', error)
ElMessage.error('创建字典类型失败')
}
}
}
// 删除参数
const handleDeleteParam = async (row: any) => {
try {
@@ -1001,6 +1180,156 @@ const handleParamDialogClose = () => {
currentDevice.value = null
}
// 下拉框选项配置相关
const selectOptionsDialogVisible = ref(false)
const currentSelectParam = ref<any>(null)
const selectOptionInput = ref('')
const selectOptionsList = ref<any[]>([])
// 打开下拉框选项配置对话框
const handleConfigSelectOptions = async (row: any) => {
try {
// 查找对应的字典类型
const dicTypeListRes: any = await dictypelist({
pageNum: 1,
pageSize: 1000,
})
const dicTypeData = dicTypeListRes?.data ?? dicTypeListRes ?? {}
const dicTypeRecords = dicTypeData.records || dicTypeData.list || dicTypeData.rows || []
const dicType = dicTypeRecords.find(
(item: any) => item.dicName === row.paramName
)
if (!dicType) {
ElMessage.warning('未找到对应的字典类型,请先保存参数')
return
}
currentSelectParam.value = {
...row,
dicTypeId: dicType.id,
}
selectOptionsDialogVisible.value = true
await loadSelectOptions(dicType.id)
} catch (error) {
console.error('打开下拉框配置失败:', error)
ElMessage.error('打开下拉框配置失败')
}
}
// 加载下拉框选项列表
const loadSelectOptions = async (dicId: number) => {
try {
const res: any = await dicdatabydicid(dicId)
const data = res?.data ?? res ?? {}
const records = Array.isArray(data) ? data : (data.records || data.list || data.rows || [])
selectOptionsList.value = records
} catch (error) {
console.error('加载下拉框选项失败:', error)
ElMessage.error('加载下拉框选项失败')
selectOptionsList.value = []
}
}
// 添加下拉框选项
const handleAddSelectOption = async () => {
if (!selectOptionInput.value || selectOptionInput.value.trim() === '') {
ElMessage.warning('请输入选项数据')
return
}
if (!currentSelectParam.value?.dicTypeId) {
ElMessage.error('字典类型ID不存在')
return
}
try {
const res: any = await dicdataadd({
dicId: currentSelectParam.value.dicTypeId,
dicLabel: currentSelectParam.value.paramType || '',
dicValue: selectOptionInput.value.trim(),
})
if (res?.code === '0' || res?.code === 0 || res?.success) {
ElMessage.success('添加成功')
selectOptionInput.value = ''
// 重新加载选项列表
await loadSelectOptions(currentSelectParam.value.dicTypeId)
} else {
ElMessage.error(res?.message || res?.msg || '添加失败')
}
} catch (error) {
console.error('添加下拉框选项失败:', error)
ElMessage.error('添加下拉框选项失败')
}
}
// 删除下拉框选项
const handleDeleteSelectOption = async (option: any) => {
try {
await ElMessageBox.confirm(
`确定要删除"${option.dicValue || '该选项'}"吗?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
const res: any = await dicdatadel(option.id)
if (res?.code === '0' || res?.code === 0 || res?.success) {
ElMessage.success('删除成功')
// 重新加载选项列表
if (currentSelectParam.value?.dicTypeId) {
await loadSelectOptions(currentSelectParam.value.dicTypeId)
}
} else {
ElMessage.error(res?.message || res?.msg || '删除失败')
}
} catch (error: any) {
if (error !== 'cancel') {
console.error('删除下拉框选项失败:', error)
ElMessage.error('删除下拉框选项失败')
}
}
}
// 保存下拉框选项配置
const handleSaveSelectOptions = async () => {
if (!currentSelectParam.value) {
return
}
if (selectOptionsList.value.length === 0) {
await ElMessageBox.alert(
`${currentSelectParam.value.paramName}的下拉框选项列表还未配置,请先完成配置`,
'提示',
{
confirmButtonText: '确定',
type: 'warning',
}
)
return
}
selectOptionsDialogVisible.value = false
ElMessage.success(`${currentSelectParam.value.paramName}下拉框选项列表保存成功!`)
}
// 关闭下拉框选项配置对话框
const handleSelectOptionsDialogClose = () => {
selectOptionsDialogVisible.value = false
selectOptionInput.value = ''
selectOptionsList.value = []
currentSelectParam.value = null
}
// 初始化
onMounted(() => {
getIslandList().then(() => {
@@ -1063,5 +1392,97 @@ onMounted(() => {
display: flex;
justify-content: flex-end;
}
.select-options-container {
display: flex;
flex-direction: column;
gap: 16px;
}
.select-options-input-area {
display: flex;
align-items: center;
gap: 8px;
}
.input-label {
min-width: 80px;
font-weight: 500;
font-size: 16px;
}
.select-options-cards {
display: flex;
flex-wrap: wrap;
gap: 20px;
min-height: 100px;
max-height: 300px;
overflow-y: auto;
padding: 20px;
background: linear-gradient(135deg, #e3f2fd 0%, #f0f2f5 100%);
border-radius: 4px;
background-image:
linear-gradient(rgba(64, 158, 255, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(64, 158, 255, 0.03) 1px, transparent 1px);
background-size: 20px 20px;
}
.select-option-card {
position: relative;
padding: 16px 20px;
background-color: #fff;
border: 1px solid rgba(64, 158, 255, 0.1);
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
cursor: default;
transition: all 0.3s;
min-width: 120px;
font-size: 16px;
}
.select-option-card:hover {
box-shadow: 0 4px 16px rgba(64, 158, 255, 0.2);
transform: translateY(-4px);
border-color: rgba(64, 158, 255, 0.3);
}
.option-text {
font-size: 1.2em;
color: #303133;
font-weight: bold;
}
.option-delete-icon {
position: absolute;
top: 10px;
right: 10px;
font-size: 16px;
color: #909399;
cursor: pointer;
transition: color 0.3s;
padding: 4px;
}
.option-delete-icon:hover {
color: #f56c6c;
}
.empty-tip {
width: 100%;
text-align: center;
color: #909399;
font-size: 16px;
padding: 20px 0;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
}
.form-type-select-btn {
font-size: inherit;
}
</style>