feat(dict): 字典数据支持标签样式

- src/api/dict.ts: 字典数据补 tagType 字段,历史单字母值归一为语义名
- src/subPages/work/dict/item/index.vue: 列表按标签样式渲染,表单新增标签类型选择
- src/subPages/work/dict/index.vue: 删除确认提示会同时删除字典数据
- src/subPages/work/dict/index.vue、dict/item/index.vue: 保存失败提示后端返回的错误信息
This commit is contained in:
Ray.Hao committed 2026-09-26 07:35:49 +08:00
1 parent 4402bf26bc
commit c9dcda4fed
3 files changed
+85 -5

No files matched your search

+35 -3
View File
@@ -2,6 +2,31 @@ import request from "@/utils/request";
const DICT_BASE_URL = "/api/v1/dicts";
/** 标签样式的语义名 */
const TAG_TYPE_NAMES = ["primary", "success", "warning", "danger", "info"];
/** 历史单字母标签样式对应的语义名 */
const LEGACY_TAG_TYPES: Record<string, string> = {
P: "primary",
S: "success",
W: "warning",
D: "danger",
I: "info",
};
/**
* 归一标签样式,把历史单字母值转成语义名
*
* 无样式或无法识别时返回空串
*/
function normalizeTagType(tagType?: string): string {
const name = String(tagType ?? "")
.trim()
.toLowerCase();
if (!name || name === "n" || name === "default") return "";
return TAG_TYPE_NAMES.includes(name) ? name : (LEGACY_TAG_TYPES[name.toUpperCase()] ?? "");
}
const DictAPI = {
/** 获取字典类型分页数据 */
getPage(queryParams: DictTypePageQuery) {
@@ -56,7 +81,10 @@ const DictAPI = {
url: `${DICT_BASE_URL}/${dictCode}/items`,
method: "GET",
data: queryParams,
});
}).then((data) => ({
...data,
list: (data.list ?? []).map((item) => ({ ...item, tagType: normalizeTagType(item.tagType) })),
}));
},
/** 获取字典数据表单数据 */
@@ -64,7 +92,7 @@ const DictAPI = {
return request<DictItemForm>({
url: `${DICT_BASE_URL}/${dictCode}/items/${id}/form`,
method: "GET",
});
}).then((data) => ({ ...data, tagType: normalizeTagType(data.tagType) }));
},
/** 新增字典数据 */
@@ -135,9 +163,11 @@ export interface DictItemForm {
dictCode?: string;
label?: string;
value?: string;
sort: number;
sort?: number;
status?: number;
remark?: string;
/** 标签样式(primary/success/warning/danger/info,空为无样式) */
tagType?: string;
}
/** 字典数据分页对象 */
@@ -149,4 +179,6 @@ export interface DictItem {
sort?: number;
status?: number;
remark?: string;
/** 标签样式(primary/success/warning/danger/info,空为无样式) */
tagType?: string;
}
+5 -1
View File
@@ -104,6 +104,7 @@ import { useActionSheet, type ActionMenuOption } from "@/composables/useActionSh
import { usePagedList } from "@/composables/usePagedList";
import DictAPI, { type DictTypeForm, type DictTypePageQuery, type DictTypeItem } from "@/api/dict";
import { hasPermission } from "@/utils/permission";
import { getErrorMessage } from "@/utils/error";
definePage({
name: "dict",
@@ -182,6 +183,9 @@ function submitDictForm() {
closeDictDialog();
loadDictTypeList();
})
.catch((error) => {
toast.error(getErrorMessage(error, "保存失败"));
})
.finally(() => {
isSubmitting.value = false;
});
@@ -207,7 +211,7 @@ function showDictActions(item: DictTypeItem) {
color: "var(--color-danger)",
handler: () =>
confirmAction({
msg: `确定要删除字典「${item.name}」吗?`,
msg: `删除字典「${item.name}」会同时删除其字典数据,确定继续吗?`,
action: async () => {
if (!item.id) return;
await DictAPI.deleteByIds(String(item.id));
+45 -1
View File
@@ -14,7 +14,10 @@
<view class="flex-start">
<view class="flex-1">
<view class="flex-start">
<text class="font-bold text-32rpx">{{ item.label }}</text>
<wd-tag v-if="tagComponentType(item.tagType)" :type="tagComponentType(item.tagType)">
{{ item.label }}
</wd-tag>
<text v-else class="font-bold text-32rpx">{{ item.label }}</text>
</view>
<text class="text-24rpx color-text-secondary">
字典值:{{ item.value }} · 排序:{{ item.sort }}
@@ -58,6 +61,18 @@
<wd-form-item prop="value" title="字典项值" required>
<wd-input v-model="formData.value" placeholder="请输入字典项值" />
</wd-form-item>
<wd-form-item prop="tagType" title="标签类型">
<wd-radio-group v-model="formData.tagType" size="small" type="button">
<wd-radio value="">无</wd-radio>
<wd-radio
v-for="option in TAG_TYPE_OPTIONS"
:key="option.value"
:value="option.value"
>
{{ option.label }}
</wd-radio>
</wd-radio-group>
</wd-form-item>
<wd-form-item prop="status" title="状态">
<wd-switch v-model="formData.status" :active-value="1" :inactive-value="0" />
</wd-form-item>
@@ -108,6 +123,8 @@ import { useActionSheet, type ActionMenuOption } from "@/composables/useActionSh
import { usePagedList } from "@/composables/usePagedList";
import DictAPI, { type DictItemForm, type DictItemPageQuery, type DictItem } from "@/api/dict";
import { hasPermission } from "@/utils/permission";
import { getErrorMessage } from "@/utils/error";
import type { TagType } from "@wot-ui/ui/components/wd-tag/types";
definePage({
name: "dict-item",
@@ -153,8 +170,32 @@ const initialFormData: DictItemForm = {
sort: 1,
status: 1,
remark: undefined,
tagType: "",
};
/** 标签类型选项,值为后端存储的语义名 */
const TAG_TYPE_OPTIONS = [
{ value: "primary", label: "主要" },
{ value: "success", label: "成功" },
{ value: "info", label: "信息" },
{ value: "warning", label: "警告" },
{ value: "danger", label: "危险" },
];
/** 语义名与 wd-tag 类型的对应关系,info 用默认样式呈现 */
const TAG_COMPONENT_TYPES: Record<string, TagType> = {
primary: "primary",
success: "success",
warning: "warning",
danger: "danger",
info: "default",
};
/** 字典项标签在 wd-tag 上的呈现类型,无标签类型时返回空串 */
function tagComponentType(tagType?: string): TagType | "" {
return TAG_COMPONENT_TYPES[tagType ?? ""] ?? "";
}
const formData = reactive<DictItemForm>({ ...initialFormData });
const rules = toFormSchema({
@@ -202,6 +243,9 @@ function submitItemForm() {
closeItemDialog();
loadItemList();
})
.catch((error) => {
toast.error(getErrorMessage(error, "保存失败"));
})
.finally(() => {
isSubmitting.value = false;
});