From 0932a05850633ce7b7d2a547a9e63e09bcdd9559 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Tue, 4 Aug 2026 19:20:10 -0600 Subject: [PATCH] =?UTF-8?q?feat(achievement):=20=E6=88=90=E5=B0=B1?= =?UTF-8?q?=E5=9B=BE=E6=A0=87=E6=94=B9=E7=94=A8=20iconify=20=E6=B8=B2?= =?UTF-8?q?=E6=9F=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 机房的老浏览器缺 emoji 字体,成就图标会渲染成方块。后端的 icon 字段 改存 iconify 图标名(noto 集),前端统一走新的 AchievementIcon 组件 渲染成 SVG。 组件按三种形态判断:图片 URL 走 img,含冒号走 Icon,其余当纯文本兜底, 所以存量的 emoji 数据不会瞎掉。 顺带修好解锁弹窗:题单奖章的 icon 是图片 URL,之前当文本渲染,会把 一串路径直接显示出来。 Co-Authored-By: Claude Opus 5 --- .../components/AchievementModal.vue | 31 +++++++++++- src/admin/achievement/list.vue | 8 ++- .../components/AchievementCard.vue | 5 +- src/oj/user/index.vue | 7 ++- src/shared/components/AchievementIcon.vue | 50 +++++++++++++++++++ src/shared/components/AchievementToast.vue | 5 +- 6 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 src/shared/components/AchievementIcon.vue diff --git a/src/admin/achievement/components/AchievementModal.vue b/src/admin/achievement/components/AchievementModal.vue index bab15b1..6db9ae1 100644 --- a/src/admin/achievement/components/AchievementModal.vue +++ b/src/admin/achievement/components/AchievementModal.vue @@ -6,6 +6,7 @@ import { type AdminAchievement, type MetricOption, } from "admin/api" +import AchievementIcon from "shared/components/AchievementIcon.vue" const props = defineProps<{ show: boolean @@ -21,7 +22,7 @@ function emptyForm() { return { name: "", description: "", - icon: "🏆", + icon: "noto:trophy", rarity: "bronze", hidden: false, metric: "", @@ -99,7 +100,22 @@ async function save() { /> - + + + +
+ +
+
+ + 填 iconify 图标名(推荐 noto: 开头的彩色 emoji 图标),右侧是实时 + 预览;预览不出来说明名字写错了。图标名可在 icon-sets.iconify.design + 搜索。 + +
+ + diff --git a/src/admin/achievement/list.vue b/src/admin/achievement/list.vue index 6c1f2f7..ffccbf4 100644 --- a/src/admin/achievement/list.vue +++ b/src/admin/achievement/list.vue @@ -5,6 +5,7 @@ import { getAdminAchievements, type AdminAchievement, } from "admin/api" +import AchievementIcon from "shared/components/AchievementIcon.vue" import AchievementModal from "./components/AchievementModal.vue" const message = useMessage() @@ -57,7 +58,12 @@ function remove(row: AdminAchievement) { } const columns: DataTableColumn[] = [ - { title: "图标", key: "icon", width: 60 }, + { + title: "图标", + key: "icon", + width: 60, + render: (row) => h(AchievementIcon, { icon: row.icon, size: 24 }), + }, { title: "名称", key: "name" }, { title: "稀有度", diff --git a/src/oj/achievement/components/AchievementCard.vue b/src/oj/achievement/components/AchievementCard.vue index bc4a7f6..946fc61 100644 --- a/src/oj/achievement/components/AchievementCard.vue +++ b/src/oj/achievement/components/AchievementCard.vue @@ -1,4 +1,5 @@ + + + + diff --git a/src/shared/components/AchievementToast.vue b/src/shared/components/AchievementToast.vue index 2e7c7e5..c3bff66 100644 --- a/src/shared/components/AchievementToast.vue +++ b/src/shared/components/AchievementToast.vue @@ -1,4 +1,5 @@