From db313f4aa65d5dca664a58be72ffd677f95bb259 Mon Sep 17 00:00:00 2001 From: Vicky <10212746+haifeng-jiang@user.noreply.gitee.com> Date: Fri, 16 Oct 2026 16:33:22 +0800 Subject: [PATCH 01/59] =?UTF-8?q?feat(admin):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=95=86=E5=93=81=E9=85=8D=E7=BD=AE=E4=B8=8E=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E5=85=AC=E5=91=8A=E4=B8=A4=E4=B8=AA=E5=90=8E=E5=8F=B0=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - src/api/admin/product.ts、src/api/admin/notice.ts 对齐后端新接口 - ProductManagementView:列表/筛选/新建编辑/上下架/删除,新建默认下架有提示 - NoticeManagementView:列表/筛选/新建编辑/发布下架/删除 - 状态列一律用接口返回的 statusText,不在前端写死中文 - id 按字符串处理(雪花 id 超过 JS 安全整数范围,数字会被四舍五入) --- src/api/admin/notice.ts | 66 +++ src/api/admin/product.ts | 85 ++++ src/views/commerce/ProductManagementView.vue | 463 +++++++++++++++++++ src/views/operation/NoticeManagementView.vue | 354 ++++++++++++++ 4 files changed, 968 insertions(+) create mode 100644 src/api/admin/notice.ts create mode 100644 src/api/admin/product.ts create mode 100644 src/views/commerce/ProductManagementView.vue create mode 100644 src/views/operation/NoticeManagementView.vue diff --git a/src/api/admin/notice.ts b/src/api/admin/notice.ts new file mode 100644 index 0000000..d95d23d --- /dev/null +++ b/src/api/admin/notice.ts @@ -0,0 +1,66 @@ +// Author: fruit.com.cn + +import request from '@/axios' +import type { PageResult } from './types' + +/** 系统公告:字段与 /admin/notices 的响应一一对应 */ +export interface NoticeItem { + /** 雪花 id,后端以字符串下发(超过 JS 安全整数范围),原样回传即可 */ + id: string + title: string + content: string + /** ALL / USER / CREATOR */ + target: string + targetText: string + /** SYSTEM / AUDIT / PAYMENT / ACTIVITY */ + type: string + typeText: string + /** 1 已发布 / 0 已下架 */ + status: number + statusText: string + publishAt?: string + expireAt?: string + createdAt?: string +} + +export interface NoticePageParams { + pageIndex?: number + pageSize?: number + status?: number + target?: string + type?: string + keyword?: string +} + +export interface NoticeSaveData { + title: string + content: string + target: string + type: string + publishAt?: string | null + expireAt?: string | null +} + +export const pageNoticesApi = (params: NoticePageParams) => { + return request.get>({ url: '/admin/notices/page', params }) +} + +export const getNoticeApi = (id: string | number) => { + return request.get({ url: `/admin/notices/${id}` }) +} + +export const createNoticeApi = (data: NoticeSaveData) => { + return request.post({ url: '/admin/notices', data }) +} + +export const updateNoticeApi = (id: string | number, data: NoticeSaveData) => { + return request.put({ url: `/admin/notices/${id}`, data }) +} + +export const updateNoticeStatusApi = (id: string | number, status: number) => { + return request.put({ url: `/admin/notices/${id}/status`, params: { status } }) +} + +export const deleteNoticeApi = (id: string | number) => { + return request.delete({ url: `/admin/notices/${id}` }) +} diff --git a/src/api/admin/product.ts b/src/api/admin/product.ts new file mode 100644 index 0000000..391bcea --- /dev/null +++ b/src/api/admin/product.ts @@ -0,0 +1,85 @@ +// Author: fruit.com.cn + +import request from '@/axios' +import type { PageResult } from './types' + +/** 商品(金币包):字段与 /admin/products 的响应一一对应 */ +export interface ProductItem { + /** 雪花 id,后端以字符串下发(超过 JS 安全整数范围),原样回传即可 */ + id: string + code: string + name: string + /** COIN_PACK / VIP */ + type: string + typeText: string + /** ALL / GOOGLE / APPLE */ + platform: string + storeProductId: string + coinAmount: number + bonusCoin: number + /** coinAmount + bonusCoin,服务端算好,前端不再自己加 */ + totalCoin: number + priceAmount: number + currency: string + displayPrice: string + regionCodes: string + vipDays: number + sort: number + /** 1 已上架 / 0 已下架 */ + status: number + statusText: string + effectiveAt?: string + expireAt?: string + createdAt?: string +} + +export interface ProductPageParams { + pageIndex?: number + pageSize?: number + type?: string + status?: number + platform?: string + keyword?: string +} + +export interface ProductSaveData { + code: string + name: string + type: string + platform: string + storeProductId: string + coinAmount: number + bonusCoin: number + priceAmount: number + currency: string + displayPrice: string + regionCodes: string + vipDays: number + sort: number + effectiveAt?: string | null + expireAt?: string | null +} + +export const pageProductsApi = (params: ProductPageParams) => { + return request.get>({ url: '/admin/products/page', params }) +} + +export const getProductApi = (id: string | number) => { + return request.get({ url: `/admin/products/${id}` }) +} + +export const createProductApi = (data: ProductSaveData) => { + return request.post({ url: '/admin/products', data }) +} + +export const updateProductApi = (id: string | number, data: ProductSaveData) => { + return request.put({ url: `/admin/products/${id}`, data }) +} + +export const updateProductStatusApi = (id: string | number, status: number) => { + return request.put({ url: `/admin/products/${id}/status`, params: { status } }) +} + +export const deleteProductApi = (id: string | number) => { + return request.delete({ url: `/admin/products/${id}` }) +} diff --git a/src/views/commerce/ProductManagementView.vue b/src/views/commerce/ProductManagementView.vue new file mode 100644 index 0000000..26ba5e6 --- /dev/null +++ b/src/views/commerce/ProductManagementView.vue @@ -0,0 +1,463 @@ + + + + + diff --git a/src/views/operation/NoticeManagementView.vue b/src/views/operation/NoticeManagementView.vue new file mode 100644 index 0000000..6b775a1 --- /dev/null +++ b/src/views/operation/NoticeManagementView.vue @@ -0,0 +1,354 @@ + + + + + From 3ec9ea6717846fe0ae73a0ed5f93751f00cbd0c4 Mon Sep 17 00:00:00 2001 From: Vicky <10212746+haifeng-jiang@user.noreply.gitee.com> Date: Fri, 16 Oct 2026 16:44:19 +0800 Subject: [PATCH 02/59] =?UTF-8?q?fix(web):=20=E9=80=82=E9=85=8D=E5=90=8E?= =?UTF-8?q?=E7=AB=AF=20ID=20=E5=AD=97=E7=AC=A6=E4=B8=B2=E5=8C=96=EF=BC=88?= =?UTF-8?q?=E9=9B=AA=E8=8A=B1=20id=20=E4=B8=8D=E8=83=BD=E8=BF=87=20Number?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 后端 J1 起所有 Long id 以字符串下发,审计出 4 处把 id 当数字用的地方: - utils/creatorImpersonation.ts:代看创作者 id 曾 Number(raw) 存 localStorage, 19 位 id 会被四舍五入导致 X-Creator-Id 头带错 id;改为全程字符串 - contentManagement/EpisodeManagementView.vue:Number(route.query.drama) 与 item.id 比较, 从短剧管理带 ?drama= 跳过来会选不中;改为字符串比较 - creator-center/composables/useDramaEdit.js:Number(route.params.id) 同上,作品编辑打不开 - permission/composables/useMenuManagement.js:顶级菜单哨兵 0 与接口的 "0" 类型不一致, 下拉回显会变裸 0;统一成字符串 '0' 核过不需要改:分页 total 后端保持数字;role.id === selectedRoleId 等两侧都来自接口; formatCount 内部 Number() 吃字符串;全局无 id 算术/下标/a.id-b.id。 --- src/utils/creatorImpersonation.ts | 19 ++++++++++++------- .../EpisodeManagementView.vue | 3 ++- .../composables/useDramaEdit.js | 3 ++- .../composables/useMenuManagement.js | 10 ++++++---- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/utils/creatorImpersonation.ts b/src/utils/creatorImpersonation.ts index f3f9955..b6d698a 100644 --- a/src/utils/creatorImpersonation.ts +++ b/src/utils/creatorImpersonation.ts @@ -11,17 +11,22 @@ import { ref } from 'vue' */ const STORAGE_KEY = 'creator-center:impersonate-id' -function readStored(): number | null { +/** + * 代看目标按**字符串**存:创作者 id 是雪花 id(19 位), + * 用 Number 过一遍会被 JS 四舍五入,请求头就会带一个不存在的 id(见 api-phase1.md §0)。 + */ +function readStored(): string | null { const raw = localStorage.getItem(STORAGE_KEY) - const value = raw ? Number(raw) : NaN - return Number.isFinite(value) && value > 0 ? value : null + const value = (raw || '').trim() + return value && value !== '0' ? value : null } -export const impersonateCreatorId = ref(readStored()) +export const impersonateCreatorId = ref(readStored()) -export function setImpersonateCreatorId(id: number | null) { - impersonateCreatorId.value = id - if (id) localStorage.setItem(STORAGE_KEY, String(id)) +export function setImpersonateCreatorId(id: string | number | null) { + const value = id === null || id === undefined || id === '' ? null : String(id) + impersonateCreatorId.value = value + if (value) localStorage.setItem(STORAGE_KEY, value) else localStorage.removeItem(STORAGE_KEY) } diff --git a/src/views/contentManagement/EpisodeManagementView.vue b/src/views/contentManagement/EpisodeManagementView.vue index fb67003..5db5f08 100644 --- a/src/views/contentManagement/EpisodeManagementView.vue +++ b/src/views/contentManagement/EpisodeManagementView.vue @@ -55,7 +55,8 @@ const selectedDrama = computed(() => dramas.value.find((item) => item.id === sel async function loadDramas() { const res = await pageDramasApi({ pageIndex: 1, pageSize: 200 }) dramas.value = res.data?.list || [] - const fromQuery = Number(route.query.drama) + // 剧 id 是字符串(雪花 id 过 Number 会被四舍五入),这里按字符串比较 + const fromQuery = route.query.drama ? String(route.query.drama) : '' if (fromQuery && dramas.value.some((item) => item.id === fromQuery)) { selectedDramaId.value = fromQuery } else if (!selectedDramaId.value && dramas.value.length) { diff --git a/src/views/creator-center/composables/useDramaEdit.js b/src/views/creator-center/composables/useDramaEdit.js index efe7b08..9dbcbb4 100644 --- a/src/views/creator-center/composables/useDramaEdit.js +++ b/src/views/creator-center/composables/useDramaEdit.js @@ -42,7 +42,8 @@ function writeSession(key, value) { export function useDramaEdit() { const { ensureAccess, impersonating } = useCreatorAccess() const route = useRoute() - const dramaId = Number(route.params.id) + // 作品 id 是字符串(雪花 id 过 Number 会被四舍五入),按字符串比对 + const dramaId = route.params.id ? String(route.params.id) : '' const loading = ref(false) const drama = ref(null) diff --git a/src/views/permission/composables/useMenuManagement.js b/src/views/permission/composables/useMenuManagement.js index 1bf197d..f45b3bd 100644 --- a/src/views/permission/composables/useMenuManagement.js +++ b/src/views/permission/composables/useMenuManagement.js @@ -47,7 +47,9 @@ export function useMenuManagement() { const treeData = computed(() => mapNodes(menuTree.value)) const parentOptions = computed(() => { - const options = [{ id: 0, label: '顶级菜单' }] + // 顶级菜单哨兵跟接口的 parentId 一样用字符串 "0":菜单 id 是字符串, + // 数字 0 会在下拉里对不上、回显成裸 "0" + const options = [{ id: '0', label: '顶级菜单' }] const walk = (nodes, depth) => { ;(nodes || []).forEach((node) => { if (node.type !== 'BUTTON') { @@ -73,7 +75,7 @@ export function useMenuManagement() { } } - function resetForm(parentId = 0) { + function resetForm(parentId = '0') { Object.assign(form, { id: null, parentId, @@ -94,7 +96,7 @@ export function useMenuManagement() { const raw = node.raw || {} Object.assign(form, { id: raw.id, - parentId: raw.parentId ?? 0, + parentId: raw.parentId ?? '0', title: raw.meta?.title || '', routePath: raw.path || '', routeName: raw.name || '', @@ -114,7 +116,7 @@ export function useMenuManagement() { return ElMessage.warning('请填写对应路由') } const payload = { - parentId: form.parentId || 0, + parentId: form.parentId || '0', title: form.title.trim(), routePath: form.routePath.trim(), routeName: form.routeName.trim(), From 54db082ffb66833f9d091b232cd294d818f413bf Mon Sep 17 00:00:00 2001 From: Zhou Weidong <502333560@qq.com> Date: Sat, 17 Oct 2026 23:28:40 +0800 Subject: [PATCH 03/59] =?UTF-8?q?feat(admin):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E9=99=90=E6=B5=81=E9=85=8D=E7=BD=AE=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/systemManagement/SettingsView.vue | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/views/systemManagement/SettingsView.vue b/src/views/systemManagement/SettingsView.vue index 15d6892..fac6141 100644 --- a/src/views/systemManagement/SettingsView.vue +++ b/src/views/systemManagement/SettingsView.vue @@ -12,12 +12,19 @@ const loading = ref(false) const saving = ref(false) const workspaceName = ref('') const defaultStatus = ref('draft') +const registerMaxPerIp = ref(5) +const registerMaxPerDevice = ref(3) const statusOptions = [ { code: 'draft', text: '草稿' }, { code: 'reviewing', text: '待审核' } ] +const parseRegisterLimit = (value, fallback) => { + const parsed = Number.parseInt(value ?? '', 10) + return Number.isFinite(parsed) ? parsed : fallback +} + async function load() { loading.value = true try { @@ -25,6 +32,8 @@ async function load() { const map = Object.fromEntries((res.data || []).map((item) => [item.key, item.value])) workspaceName.value = map['workspace.name'] || '' defaultStatus.value = map['content.default-status'] || 'draft' + registerMaxPerIp.value = parseRegisterLimit(map['app.register.max-per-ip-per-day'], 5) + registerMaxPerDevice.value = parseRegisterLimit(map['app.register.max-per-device-per-day'], 3) } finally { loading.value = false } @@ -35,7 +44,9 @@ async function save() { try { await updateConfigsApi({ 'workspace.name': workspaceName.value, - 'content.default-status': defaultStatus.value + 'content.default-status': defaultStatus.value, + 'app.register.max-per-ip-per-day': String(registerMaxPerIp.value), + 'app.register.max-per-device-per-day': String(registerMaxPerDevice.value) }) ElMessage.success('设置已保存') } finally { @@ -62,6 +73,11 @@ onMounted(load) :key="item.code" :label="item.text" :value="item.code" />注册频控保存设置 Date: Mon, 19 Oct 2026 11:12:28 +0800 Subject: [PATCH 04/59] =?UTF-8?q?style(web):=20=E7=BB=9F=E4=B8=80=E5=90=8E?= =?UTF-8?q?=E5=8F=B0=E5=9B=BE=E6=A0=87=E4=B8=8E=E5=85=A8=E5=B1=80=E8=A7=86?= =?UTF-8?q?=E8=A7=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/login/types.ts | 1 - src/assets/imgs/brand-mark.png | Bin 0 -> 6007 bytes src/components/AppIcon/index.ts | 5 + src/components/AppIcon/src/AppIcon.vue | 40 ++ src/components/Breadcrumb/src/Breadcrumb.vue | 8 +- src/components/Collapse/src/Collapse.vue | 5 +- .../ContentWrap/src/ContentWrap.vue | 3 +- .../ContextMenu/src/ContextMenu.vue | 2 +- .../Descriptions/src/Descriptions.vue | 9 +- src/components/Dialog/src/Dialog.vue | 9 +- src/components/Icon/src/Icon.vue | 8 +- .../LocaleDropdown/src/LocaleDropdown.vue | 5 +- src/components/Logo/src/Logo.vue | 4 +- .../src/components/useRenderMenuTitle.tsx | 6 +- src/components/Screenfull/src/Screenfull.vue | 7 +- .../Search/src/components/ActionButton.vue | 7 +- src/components/Setting/src/Setting.vue | 22 +- .../src/components/ColorRadioPicker.vue | 3 +- .../src/components/LayoutRadioPicker.vue | 22 +- .../SizeDropdown/src/SizeDropdown.vue | 3 +- src/components/TabMenu/src/TabMenu.vue | 7 +- src/components/Table/src/Table.vue | 5 +- .../Table/src/components/ColumnSetting.vue | 11 +- .../Table/src/components/TableActions.vue | 15 +- src/components/TagsView/src/TagsView.vue | 59 ++- .../ThemeSwitch/src/ThemeSwitch.vue | 28 +- src/components/UserInfo/src/UserInfo.vue | 21 +- .../UserInfo/src/components/LockDialog.vue | 23 +- .../UserInfo/src/components/LockPage.vue | 30 +- .../src/VideoPlayerViewer.vue | 5 +- src/components/index.ts | 2 + src/constants/icons.ts | 103 ++++ src/hooks/web/useIcon.ts | 5 +- src/layout/components/ToolHeader.vue | 26 +- src/locales/en.ts | 2 + src/locales/zh-CN.ts | 2 + src/store/modules/app.ts | 8 +- src/store/modules/user.ts | 16 +- src/styles/business/banner-management.css | 6 +- src/styles/business/console.css | 2 +- src/styles/business/creator-center.css | 8 +- src/styles/business/dark.css | 41 +- src/styles/business/drama-management.css | 22 +- src/styles/business/operation-log.css | 2 +- src/styles/business/style.css | 463 ++++-------------- src/styles/business/theme.css | 160 ++---- src/styles/business/typography.css | 2 +- src/styles/var.css | 17 +- src/views/Login/Login.vue | 89 +++- src/views/Login/components/LoginForm.vue | 14 +- src/views/commerce/ProductManagementView.vue | 4 +- src/views/common/DashboardView.vue | 16 +- .../BannerManagementView.vue | 4 +- .../CategoryManagementView.vue | 4 +- .../contentManagement/DramaManagementView.vue | 9 +- .../EpisodeManagementView.vue | 4 +- src/views/creator-center/DramaEditView.vue | 8 +- src/views/creator-center/WorkspaceView.vue | 7 +- src/views/creator/CreatorAuditView.vue | 7 +- src/views/operation/NoticeManagementView.vue | 4 +- src/views/permission/MenuManagementView.vue | 4 +- src/views/permission/RoleCategoriesView.vue | 4 +- src/views/permission/RoleManagementView.vue | 4 +- .../composables/useMenuManagement.js | 16 +- .../systemManagement/OperationLogView.vue | 7 +- src/views/userManagement/AdminUsersView.vue | 9 +- src/views/userManagement/AppUsersView.vue | 7 +- 67 files changed, 737 insertions(+), 744 deletions(-) create mode 100644 src/assets/imgs/brand-mark.png create mode 100644 src/components/AppIcon/index.ts create mode 100644 src/components/AppIcon/src/AppIcon.vue create mode 100644 src/constants/icons.ts diff --git a/src/api/login/types.ts b/src/api/login/types.ts index 0584f6e..6c26ed6 100644 --- a/src/api/login/types.ts +++ b/src/api/login/types.ts @@ -2,7 +2,6 @@ export type UserLoginType = { username: string - password: string } export type UserType = { diff --git a/src/assets/imgs/brand-mark.png b/src/assets/imgs/brand-mark.png new file mode 100644 index 0000000000000000000000000000000000000000..d6f5dc1428f6699146c6a85cdb811e683e9d27cb GIT binary patch literal 6007 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 Q33cF#w!T&|-sbUt0nW?M#sB~S literal 0 HcmV?d00001 diff --git a/src/components/AppIcon/index.ts b/src/components/AppIcon/index.ts new file mode 100644 index 0000000..dca3e15 --- /dev/null +++ b/src/components/AppIcon/index.ts @@ -0,0 +1,5 @@ +// Author: fruit.com.cn + +import AppIcon from './src/AppIcon.vue' + +export { AppIcon } diff --git a/src/components/AppIcon/src/AppIcon.vue b/src/components/AppIcon/src/AppIcon.vue new file mode 100644 index 0000000..9b67c80 --- /dev/null +++ b/src/components/AppIcon/src/AppIcon.vue @@ -0,0 +1,40 @@ + + + + + + + diff --git a/src/components/Breadcrumb/src/Breadcrumb.vue b/src/components/Breadcrumb/src/Breadcrumb.vue index 307574b..fe2f78a 100644 --- a/src/components/Breadcrumb/src/Breadcrumb.vue +++ b/src/components/Breadcrumb/src/Breadcrumb.vue @@ -9,7 +9,7 @@ import { filterBreadcrumb } from './helper' import { filter, treeToList } from '@/utils/tree' import type { RouteLocationNormalizedLoaded, RouteMeta } from 'vue-router' import { useI18n } from '@/hooks/web/useI18n' -import { Icon } from '@/components/Icon' +import { AppIcon } from '@/components/AppIcon' import { useAppStore } from '@/store/modules/app' import { useDesign } from '@/hooks/web/useDesign' @@ -54,7 +54,7 @@ export default defineComponent({ {meta?.icon && breadcrumbIcon.value ? ( <> - {t(v?.meta?.title)} + {t(v?.meta?.title)} ) : ( t(v?.meta?.title) @@ -117,10 +117,10 @@ export default defineComponent({ :deep(&__item):last-child { .@{prefix-cls}__inner { - color: var(--el-text-color-placeholder); + color: var(--el-text-color-regular); &:hover { - color: var(--el-text-color-placeholder); + color: var(--el-color-primary); } } } diff --git a/src/components/Collapse/src/Collapse.vue b/src/components/Collapse/src/Collapse.vue index a07a348..3f655ea 100644 --- a/src/components/Collapse/src/Collapse.vue +++ b/src/components/Collapse/src/Collapse.vue @@ -5,6 +5,7 @@ import { computed, unref } from 'vue' import { useAppStore } from '@/store/modules/app' import { propTypes } from '@/utils/propTypes' import { useDesign } from '@/hooks/web/useDesign' +import { AppIcons } from '@/constants/icons' const { getPrefixCls } = useDesign() @@ -26,9 +27,9 @@ const toggleCollapse = () => { diff --git a/src/components/ContextMenu/src/ContextMenu.vue b/src/components/ContextMenu/src/ContextMenu.vue index 144f8f6..c40e137 100644 --- a/src/components/ContextMenu/src/ContextMenu.vue +++ b/src/components/ContextMenu/src/ContextMenu.vue @@ -66,7 +66,7 @@ defineExpose({ :disabled="item.disabled" :command="item" > - {{ t(item.label) }} + {{ t(item.label) }} diff --git a/src/components/Descriptions/src/Descriptions.vue b/src/components/Descriptions/src/Descriptions.vue index 33bc95d..e1d3c83 100644 --- a/src/components/Descriptions/src/Descriptions.vue +++ b/src/components/Descriptions/src/Descriptions.vue @@ -7,8 +7,9 @@ import { propTypes } from '@/utils/propTypes' import { ref, unref, PropType, computed, defineComponent } from 'vue' import { useAppStore } from '@/store/modules/app' import { DescriptionsSchema } from './types' -import { Icon } from '@/components/Icon' +import { AppIcon } from '@/components/AppIcon' import { get } from 'lodash-es' +import { AppIcons } from '@/constants/icons' const appStore = useAppStore() @@ -94,12 +95,14 @@ export default defineComponent({ {props.title} {props.message ? ( - + ) : null} - {props.collapse ? : null} + {props.collapse ? ( + + ) : null} ) : null} diff --git a/src/components/Dialog/src/Dialog.vue b/src/components/Dialog/src/Dialog.vue index 0de4ca9..5d5c7ba 100644 --- a/src/components/Dialog/src/Dialog.vue +++ b/src/components/Dialog/src/Dialog.vue @@ -5,6 +5,7 @@ import { ElDialog, ElScrollbar } from 'element-plus' import { propTypes } from '@/utils/propTypes' import { computed, useAttrs, ref, unref, useSlots, watch, nextTick } from 'vue' import { isNumber } from '@/utils/is' +import { AppIcons } from '@/constants/icons' const slots = useSlots() @@ -77,17 +78,17 @@ const dialogStyle = computed(() => {
- - props.icon.startsWith('svg-icon:')) +const normalizedIcon = computed(() => normalizeAppIcon(props.icon)) const symbolId = computed(() => { - return unref(isLocal) ? `#icon-${props.icon.split('svg-icon:')[1]}` : props.icon + return unref(isLocal) ? `#icon-${props.icon.split('svg-icon:')[1]}` : unref(normalizedIcon) }) // 是否使用在线图标 @@ -48,8 +50,8 @@ const getIconifyStyle = computed(() => { diff --git a/src/components/LocaleDropdown/src/LocaleDropdown.vue b/src/components/LocaleDropdown/src/LocaleDropdown.vue index b64d649..a219e4c 100644 --- a/src/components/LocaleDropdown/src/LocaleDropdown.vue +++ b/src/components/LocaleDropdown/src/LocaleDropdown.vue @@ -7,6 +7,7 @@ import { useLocaleStore } from '@/store/modules/locale' import { useLocale } from '@/hooks/web/useLocale' import { propTypes } from '@/utils/propTypes' import { useDesign } from '@/hooks/web/useDesign' +import { AppIcons } from '@/constants/icons' const { getPrefixCls } = useDesign() @@ -36,9 +37,9 @@ const setLang = (lang: LocaleType) => {