From c9dcda4fed7a32355e5c62c974477dc45ff5ff62 Mon Sep 17 00:00:00 2001 From: "Ray.Hao" <1490493387@qq.com> Date: Sat, 26 Sep 2026 07:35:49 +0800 Subject: [PATCH] =?UTF-8?q?feat(dict):=20=E5=AD=97=E5=85=B8=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=94=AF=E6=8C=81=E6=A0=87=E7=AD=BE=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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: 保存失败提示后端返回的错误信息 --- src/api/dict.ts | 38 ++++++++++++++++++++-- src/subPages/work/dict/index.vue | 6 +++- src/subPages/work/dict/item/index.vue | 46 ++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 5 deletions(-) diff --git a/src/api/dict.ts b/src/api/dict.ts index 395ec77..02b0148 100644 --- a/src/api/dict.ts +++ b/src/api/dict.ts @@ -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 = { + 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({ 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; } diff --git a/src/subPages/work/dict/index.vue b/src/subPages/work/dict/index.vue index 03f3eeb..3d1a56e 100644 --- a/src/subPages/work/dict/index.vue +++ b/src/subPages/work/dict/index.vue @@ -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)); diff --git a/src/subPages/work/dict/item/index.vue b/src/subPages/work/dict/item/index.vue index deb8e2e..b24b136 100644 --- a/src/subPages/work/dict/item/index.vue +++ b/src/subPages/work/dict/item/index.vue @@ -14,7 +14,10 @@ - {{ item.label }} + + {{ item.label }} + + {{ item.label }} 字典值:{{ item.value }} · 排序:{{ item.sort }} @@ -58,6 +61,18 @@ + + + 无 + + {{ option.label }} + + + @@ -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 = { + 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({ ...initialFormData }); const rules = toFormSchema({ @@ -202,6 +243,9 @@ function submitItemForm() { closeItemDialog(); loadItemList(); }) + .catch((error) => { + toast.error(getErrorMessage(error, "保存失败")); + }) .finally(() => { isSubmitting.value = false; });