From 9ad818e05431cff82eb137c597b8ae39d65a4371 Mon Sep 17 00:00:00 2001 From: Ethan-Zhang Date: Tue, 30 Sep 2025 17:22:19 +0800 Subject: [PATCH] =?UTF-8?q?Feat:=20=E6=96=B0=E5=A2=9E=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E9=80=9A=E7=9F=A5=EF=BC=8C=E5=B9=B6=E5=AE=8C=E6=88=90=E8=81=94?= =?UTF-8?q?=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/index.ts | 2 + src/apis/paths/index.ts | 1 + src/apis/paths/userMessage.ts | 109 ++++ src/apis/server.ts | 40 ++ src/assets/styles/icon-common.scss | 116 ++++ src/assets/svgs/clean_messages.svg | 4 + src/assets/svgs/clean_messages_focus.svg | 4 + src/assets/svgs/default_avatar.svg | 22 + src/assets/svgs/message_default.svg | 4 + src/assets/svgs/message_focus.svg | 4 + src/assets/svgs/message_hover.svg | 4 + src/assets/svgs/nodata_message.svg | 61 +++ src/components/common/IconWrapper.vue | 59 +++ src/i18n/lang/en.ts | 17 + src/i18n/lang/zh-cn.ts | 17 + src/main.ts | 1 + src/views/app/style.scss | 29 +- .../dialogue/components/AppInitalPreview.vue | 17 +- .../dialogue/components/DialogueAside.vue | 25 +- .../dialogue/components/DialogueSession.vue | 26 +- src/views/dialogue/components/InitalPanel.vue | 4 +- .../dialogue/components/InterPreview.vue | 4 +- .../dialogue/components/MessageDetail.vue | 496 ++++++++++++++++++ src/views/dialogue/components/MessageItem.vue | 251 +++++++++ .../dialogue/components/MultiSelectTags.vue | 4 +- src/views/dialogue/components/TitleBar.vue | 301 +++++++++-- src/views/dialogue/dialogueView.vue | 51 +- src/views/tools/index.vue | 54 ++ vite.config.ts | 10 +- 29 files changed, 1654 insertions(+), 83 deletions(-) create mode 100644 src/apis/paths/userMessage.ts create mode 100644 src/assets/styles/icon-common.scss create mode 100644 src/assets/svgs/clean_messages.svg create mode 100644 src/assets/svgs/clean_messages_focus.svg create mode 100644 src/assets/svgs/default_avatar.svg create mode 100644 src/assets/svgs/message_default.svg create mode 100644 src/assets/svgs/message_focus.svg create mode 100644 src/assets/svgs/message_hover.svg create mode 100644 src/assets/svgs/nodata_message.svg create mode 100644 src/components/common/IconWrapper.vue create mode 100644 src/views/dialogue/components/MessageDetail.vue create mode 100644 src/views/dialogue/components/MessageItem.vue diff --git a/src/apis/index.ts b/src/apis/index.ts index f6e27f0..99739f6 100644 --- a/src/apis/index.ts +++ b/src/apis/index.ts @@ -19,6 +19,7 @@ import { mcpApi, llmApi, documentApi, + userMessageApi, } from './paths'; import { workFlowApi } from './workFlow'; import { appCenterApi, promptApi, kbApi } from './appCenter'; @@ -39,4 +40,5 @@ export const api = { ...documentApi, ...promptApi, ...kbApi, + ...userMessageApi, }; diff --git a/src/apis/paths/index.ts b/src/apis/paths/index.ts index 2b70594..5a7d524 100644 --- a/src/apis/paths/index.ts +++ b/src/apis/paths/index.ts @@ -18,3 +18,4 @@ export * from './model'; export * from './mcp'; export * from './llm'; export * from './document'; +export * from './userMessage'; diff --git a/src/apis/paths/userMessage.ts b/src/apis/paths/userMessage.ts new file mode 100644 index 0000000..36da1f3 --- /dev/null +++ b/src/apis/paths/userMessage.ts @@ -0,0 +1,109 @@ +// Copyright (c) Huawei Technologies Co., Ltd. 2023-2025. All rights reserved. +import { witchainDPost, witchainDGet, witchainDDel, witchainDPut } from 'src/apis/server'; +import type { FcResponse } from 'src/apis/server'; + +// 用户消息状态枚举 +export enum UserMessageStatus { + UNREAD = 'unread', + ACCEPTED = 'accepted', + REJECTED = 'rejected', + DELETED = 'deleted' +} + +// 用户消息类型枚举 +export enum UserMessageType { + INVITATION = 'invitation', + APPLICATION = 'application' +} + +// 用户消息数据结构 +export interface UserMsg { + teamId: string; + teamName: string; + msgId: string; + senderId: string | null; + senderName: string | null; + msgStatusToSender: UserMessageStatus; + receiverId: string | null; + receiverName: string | null; + msgStatusToReceiver: UserMessageStatus; + msgType: UserMessageType; + isEditable: boolean; + createdTime: string; +} + +// 列表请求参数 +export interface ListUserMessageRequest { + msgType?: UserMessageType | null; + page?: number; + pageSize?: number; +} + +// 列表响应数据结构 +export interface ListUserMessageMsg { + total: number; + userMessages: UserMsg[]; +} + +// 列表响应结构 +export interface ListUserMessageResponse { + code: number; + message: string; + result: ListUserMessageMsg; +} + +// 更新响应结构 +export interface UpdateUserMessageResponse { + code: number; + message: string; + result: string | null; +} + +// 删除响应结构 +export interface DeleteUserMessageResponse { + code: number; + message: string; + result: string | null; +} + +/** + * 获取用户消息列表 + * @param params 请求参数 + * @returns Promise<[any, FcResponse | undefined]> + */ +export const listUserMessages = ( + params: ListUserMessageRequest +): Promise<[any, FcResponse | undefined]> => { + return witchainDPost('/wtd/usr_msg/list', params as any); +}; + +/** + * 更新用户消息状态 + * @param msgId 消息ID + * @param msgStatus 消息状态 + * @returns Promise<[any, FcResponse | undefined]> + */ +export const updateUserMessage = ( + msgId: string, + msgStatus: UserMessageStatus +): Promise<[any, FcResponse | undefined]> => { + return witchainDPut('/wtd/usr_msg', {}, { msgId, msgStatus }); +}; + +/** + * 删除用户消息 + * @param msgId 消息ID + * @returns Promise<[any, FcResponse | undefined]> + */ +export const deleteUserMessage = ( + msgId: string +): Promise<[any, FcResponse | undefined]> => { + return witchainDDel('/wtd/usr_msg', {}, { msgId }); +}; + +// 导出用户消息API +export const userMessageApi = { + listUserMessages, + updateUserMessage, + deleteUserMessage, +}; diff --git a/src/apis/server.ts b/src/apis/server.ts index cb78356..8febecd 100644 --- a/src/apis/server.ts +++ b/src/apis/server.ts @@ -241,6 +241,46 @@ export const witchainDPost = async ( } }; +/** + * request with put for WitchainD + * @param url + * @param data + * @param params + * @constructor + */ +export const witchainDPut = async ( + url: string, + data: IAnyObj = {}, + params: IAnyObj = {}, +): Promise<[IError, FcResponse | undefined]> => { + try { + const result = await witchainDServer.put(url, data, { params: params }); + return [null, result.data as FcResponse]; + } catch (error) { + return [error as IError, undefined]; + } +}; + +/** + * request with delete for WitchainD + * @param url + * @param data + * @param params + * @constructor + */ +export const witchainDDel = async ( + url: string, + data: IAnyObj = {}, + params: IAnyObj = {}, +): Promise<[IError, FcResponse | undefined]> => { + try { + const result = await witchainDServer.delete(url, { data, params: params }); + return [null, result.data as FcResponse]; + } catch (error) { + return [error as IError, undefined]; + } +}; + /** * 获取 WitchainD axios 实例(用于更复杂的请求) */ diff --git a/src/assets/styles/icon-common.scss b/src/assets/styles/icon-common.scss new file mode 100644 index 0000000..8492198 --- /dev/null +++ b/src/assets/styles/icon-common.scss @@ -0,0 +1,116 @@ +// 统一的图标样式规范 +// 所有使用 el-icon 包裹的 img 图标的通用样式 + +.el-icon { + // 基础图标样式 + &.icon-wrapper { + display: inline-flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.2s ease-in-out; + border-radius: 4px; + + img { + transition: all 0.2s ease-in-out; + } + + // 默认状态 + color: var(--o-text-color-regular); + + // 悬停状态 + &:hover { + color: var(--o-color-primary); + background-color: var(--o-fill-color-light); + } + + // 激活状态 + &.active, + &--active { + color: var(--o-color-primary); + background-color: var(--o-color-primary-light-9); + } + } + + // 具体尺寸规范 - 让el-icon的size属性生效 + &.size-small { + font-size: 14px; + } + + &.size-medium { + font-size: 16px; + } + + &.size-large { + font-size: 20px; + } + + &.size-extra-large { + font-size: 24px; + } + + // 通用img样式 - 不强制设置具体尺寸,让el-icon控制 + img { + display: block; + max-width: 100%; + max-height: 100%; + } + + // 特定功能图标样式 + &.bell-icon { + cursor: pointer; + + &:hover { + color: var(--o-color-primary); + } + + &--active { + color: var(--o-color-primary); + } + } + + &.clear-icon { + cursor: pointer; + + &:hover { + color: var(--o-color-danger); + } + } + + &.language-icon, + &.theme-icon { + &:hover { + color: var(--o-color-primary); + } + } + + &.create-button__icon { + margin-right: 4px; + } + + &.search-input__icon { + color: var(--o-text-color-secondary); + } + + // 特定功能图标不再需要特殊的img样式 + // 统一使用上面的通用img样式 +} + +// 包装器样式 +.icon-wrapper { + display: inline-flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.2s ease-in-out; + border-radius: 4px; + padding: 4px; + + &:hover { + background-color: var(--o-fill-color-light); + } + + &:active { + background-color: var(--o-fill-color-extra-light); + } +} diff --git a/src/assets/svgs/clean_messages.svg b/src/assets/svgs/clean_messages.svg new file mode 100644 index 0000000..13dac64 --- /dev/null +++ b/src/assets/svgs/clean_messages.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/clean_messages_focus.svg b/src/assets/svgs/clean_messages_focus.svg new file mode 100644 index 0000000..6cb25da --- /dev/null +++ b/src/assets/svgs/clean_messages_focus.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/default_avatar.svg b/src/assets/svgs/default_avatar.svg new file mode 100644 index 0000000..6bfbe09 --- /dev/null +++ b/src/assets/svgs/default_avatar.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/svgs/message_default.svg b/src/assets/svgs/message_default.svg new file mode 100644 index 0000000..758f235 --- /dev/null +++ b/src/assets/svgs/message_default.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/message_focus.svg b/src/assets/svgs/message_focus.svg new file mode 100644 index 0000000..bce5acc --- /dev/null +++ b/src/assets/svgs/message_focus.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/message_hover.svg b/src/assets/svgs/message_hover.svg new file mode 100644 index 0000000..c769a19 --- /dev/null +++ b/src/assets/svgs/message_hover.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/nodata_message.svg b/src/assets/svgs/nodata_message.svg new file mode 100644 index 0000000..5fc2704 --- /dev/null +++ b/src/assets/svgs/nodata_message.svg @@ -0,0 +1,61 @@ + + + Created with Pixso. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/common/IconWrapper.vue b/src/components/common/IconWrapper.vue new file mode 100644 index 0000000..503462a --- /dev/null +++ b/src/components/common/IconWrapper.vue @@ -0,0 +1,59 @@ + + + + + + diff --git a/src/i18n/lang/en.ts b/src/i18n/lang/en.ts index f3ac758..71f5f94 100644 --- a/src/i18n/lang/en.ts +++ b/src/i18n/lang/en.ts @@ -1329,5 +1329,22 @@ export default { save_final_data: 'Save final data:', operator_mapping_not_found: 'Operator mapping not found:' } + }, + // Message notification related + message: { + notification: 'Notification', + todo: 'To-do', + invitation: 'Invitation', + application: 'Application', + approve: 'Approve', + reject: 'Reject', + accepted: 'Accepted', + rejected: 'Rejected', + clear_all: 'Clear All', + clear_all_tooltip: 'Clear All', + loading: 'Loading...', + no_notification_message: 'No notification messages', + no_todo_message: 'No to-do messages', + empty_message: 'No {type} messages' } }; \ No newline at end of file diff --git a/src/i18n/lang/zh-cn.ts b/src/i18n/lang/zh-cn.ts index 2e82ec0..280905d 100644 --- a/src/i18n/lang/zh-cn.ts +++ b/src/i18n/lang/zh-cn.ts @@ -1359,5 +1359,22 @@ export default { save_final_data: '保存的最终数据:', operator_mapping_not_found: '未找到操作符映射:' } + }, + // 消息通知相关 + message: { + notification: '通知', + todo: '待办', + invitation: '邀请', + application: '申请', + approve: '同意', + reject: '拒绝', + accepted: '已同意', + rejected: '已拒绝', + clear_all: '清除全部', + clear_all_tooltip: '一键清除', + loading: '加载中...', + no_notification_message: '暂无通知消息', + no_todo_message: '暂无待办消息', + empty_message: '暂无{type}消息' } }; \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 7afec0d..1183db3 100644 --- a/src/main.ts +++ b/src/main.ts @@ -17,6 +17,7 @@ import 'highlight.js/styles/github-dark.css'; import 'src/assets/base.css'; import 'src/assets/styles/main.scss'; import 'src/assets/styles/element/index.scss'; +import 'src/assets/styles/icon-common.scss'; import opendesign2 from '@computing/opendesign2'; import '@computing/opendesign2/themes/es/css'; import zhCn from 'element-plus/es/locale/lang/zh-cn'; diff --git a/src/views/app/style.scss b/src/views/app/style.scss index ea779e0..3f8f376 100644 --- a/src/views/app/style.scss +++ b/src/views/app/style.scss @@ -234,6 +234,33 @@ color: var(--o-color-white) !important; } } + +// 深色主题下的应用类型样式 +body[theme='dark'] { + .appCenterBox { + .appCenterMain { + .appCenterCardContainer { + .appCenterCardBox { + .appCenterCardSingle { + .appCenterCardTop { + .appCenterCardContent { + .appType { + .appTypeName__flow { + color: rgb(159, 134, 255); // 更浅的紫色,在深色背景下更易读 + } + .appTypeName__agent { + color: rgb(255, 168, 92); // 更浅的橙色,在深色背景下更易读 + } + } + } + } + } + } + } + } + } +} + // 应用中心删除二次提示样式 .el-message-box { min-width: 400px; @@ -257,4 +284,4 @@ height: 24px; } } -} +} \ No newline at end of file diff --git a/src/views/dialogue/components/AppInitalPreview.vue b/src/views/dialogue/components/AppInitalPreview.vue index c674c5b..3358e8f 100644 --- a/src/views/dialogue/components/AppInitalPreview.vue +++ b/src/views/dialogue/components/AppInitalPreview.vue @@ -17,15 +17,20 @@ multiple src="@/assets/svgs/upload_light.svg" /> - - + + + +
- + + +
diff --git a/src/views/dialogue/components/DialogueAside.vue b/src/views/dialogue/components/DialogueAside.vue index e62ddab..131fe4b 100644 --- a/src/views/dialogue/components/DialogueAside.vue +++ b/src/views/dialogue/components/DialogueAside.vue @@ -403,13 +403,17 @@ watch(
- + + + {{ $t('history.new_chat') }}
- + + + {{ t('history.myApp') }}
@@ -524,11 +528,14 @@ watch(
- - + + + + {{ $t('history.no_chat_history') }}
@@ -549,7 +556,9 @@ watch( align-center >
- + + + {{ $t('history.confirmation_content1') }} {{ selectedSessionIds.length }} diff --git a/src/views/dialogue/components/DialogueSession.vue b/src/views/dialogue/components/DialogueSession.vue index a273291..3dc3d43 100644 --- a/src/views/dialogue/components/DialogueSession.vue +++ b/src/views/dialogue/components/DialogueSession.vue @@ -976,7 +976,9 @@ const getFormatFileList = (ConversationItem, str) => { class="preTop" >
- + + +
{{ appList?.filter((item) => item.appId === user_selected_app)[0] @@ -1047,12 +1049,14 @@ const getFormatFileList = (ConversationItem, str) => { class="dialogue-panel__stop" @click="handlePauseAndReGenerate(Number(conversationList.length))" > - - + + + +
{{ $t('feedback.stop') }}
@@ -1067,7 +1071,9 @@ const getFormatFileList = (ConversationItem, str) => { @visible-change="isDropdownOpen = $event" > {{ file?.documentName }}
diff --git a/src/views/dialogue/components/InitalPanel.vue b/src/views/dialogue/components/InitalPanel.vue index 66f1ac6..a970396 100644 --- a/src/views/dialogue/components/InitalPanel.vue +++ b/src/views/dialogue/components/InitalPanel.vue @@ -89,7 +89,9 @@ onMounted(() => { :key="item.key" :style="item.style" > - + + +
- + + +
{{ interPreviewInfo.name }}
diff --git a/src/views/dialogue/components/MessageDetail.vue b/src/views/dialogue/components/MessageDetail.vue new file mode 100644 index 0000000..3ab758a --- /dev/null +++ b/src/views/dialogue/components/MessageDetail.vue @@ -0,0 +1,496 @@ + + + + + diff --git a/src/views/dialogue/components/MessageItem.vue b/src/views/dialogue/components/MessageItem.vue new file mode 100644 index 0000000..7ea9684 --- /dev/null +++ b/src/views/dialogue/components/MessageItem.vue @@ -0,0 +1,251 @@ + + + + + diff --git a/src/views/dialogue/components/MultiSelectTags.vue b/src/views/dialogue/components/MultiSelectTags.vue index 431c599..ac06ba4 100644 --- a/src/views/dialogue/components/MultiSelectTags.vue +++ b/src/views/dialogue/components/MultiSelectTags.vue @@ -209,7 +209,9 @@ const checkTagsOverflow = () => { class="search-input" >
    diff --git a/src/views/dialogue/components/TitleBar.vue b/src/views/dialogue/components/TitleBar.vue index b09ad4c..2fd6010 100644 --- a/src/views/dialogue/components/TitleBar.vue +++ b/src/views/dialogue/components/TitleBar.vue @@ -11,6 +11,7 @@ import { import { computed, CSSProperties, ref, onMounted } from 'vue'; import { electronProcess, ipcRenderer } from '@/utils/electron'; import { getBaseUrl } from 'src/utils/tools'; +import MessageDetail from '@/views/dialogue/components/MessageDetail.vue'; const { language } = storeToRefs(useLangStore()); const { changeLanguage } = useLangStore(); @@ -70,6 +71,41 @@ const logoutHandler = () => { const apikeyVisible = ref(false); const KnowledgeVisible = ref(false); +// 消息图标激活状态 +const messageIconActive = ref(false); + +// 消息类型定义 +interface Message { + id: number; + type: 'notification' | 'todo'; + content: string; + time: string; +} + +// 消息相关数据 +const messageDetailRef = ref>(); +const totalMessageCount = ref(0); + +// 处理消息更新 +const handleMessageUpdate = () => { + // 消息更新后,重新计算总数 + // 这里可以通过MessageDetail组件暴露的方法获取最新的消息数量 + if (messageDetailRef.value) { + // 触发MessageDetail重新获取数据 + messageDetailRef.value.refreshMessages(); + } +}; + +// 处理消息数量变化 +const handleMessageCountChanged = (count: number) => { + totalMessageCount.value = count; +}; + +// 处理消息图标点击 +const handleMessageClick = () => { + messageIconActive.value = !messageIconActive.value; +}; + const headerStyles = computed(() => { const styles: CSSProperties = {}; if (!electronProcess) return styles; @@ -92,39 +128,99 @@ const headerStyles = computed(() => { @@ -150,11 +246,16 @@ const headerStyles = computed(() => { vertical-align: top; font-size: 16px; height: 48px; - img { - width: 24px; - height: 48px; - border-radius: 50%; + + .logo-icon { + img { + width: 24px; + height: 24px; + border-radius: 50%; + display: block; + } } + h4 { font-size: 18px; margin-left: 5px; @@ -162,17 +263,14 @@ const headerStyles = computed(() => { } } .avatar { - width: 24px; - height: 48px; border-radius: 50%; cursor: pointer; background-image: url('@/assets/svgs/user.svg'); - background-repeat: no-repeat; /* 防止重复 */ - background-position: center; /* 居中 */ - background-size: contain; /* 适应容器 */ + background-repeat: no-repeat; + background-position: center; + background-size: 24px 24px; //待替换icon资源 &:hover { - height: 48px; background-image: url('@/assets/svgs/user-hover.svg'); } &:active { @@ -182,14 +280,125 @@ const headerStyles = computed(() => { .header-right { -webkit-app-region: no-drag; display: flex; - .mode { + align-items: center; + + .header-icons { + display: flex; + align-items: center; + justify-content: flex-end; // 右对齐 + + .icon-item { + display: flex; + align-items: center; + justify-content: center; + height: 48px; + width: 44px; // 固定宽度,确保每个图标占用相同空间 + margin-left: 4px; // 统一的左边距 + margin-right: 4px; // 统一的右边距 + flex-shrink: 0; // 防止收缩 + position: relative; + + // 第一个图标(语言切换)的特殊间距 + &:first-child { + margin-left: 16px; + } + + // 最后一个图标(头像)的特殊间距 + &:last-child { + margin-right: 16px; + } + + .message-badge { + :deep(.el-badge__content) { + font-size: 10px; + min-width: 16px; + height: 16px; + line-height: 16px; + border-radius: 8px; + } + } + + .message-wrapper { + .bell-icon { + color: var(--o-text-color-regular); + transition: all 0.2s ease-in-out; + + img { + width: 24px; + height: 24px; + display: block; + object-fit: contain; + } + + &.bell-icon--active { + color: var(--o-color-primary); + } + } + } + + // 这个样式已经合并到下面的统一hover效果中 + } + } + + // 统一的图标包装器样式 + .icon-wrapper { + display: flex; + align-items: center; + justify-content: center; cursor: pointer; - margin-right: 18px; - margin-left: 18px; + transition: all 0.2s ease-in-out; + border-radius: 6px; + padding: 0; // 移除内边距,让父容器控制 + width: 100%; // 填充父容器 + height: 32px; + + &:hover { + background-color: var(--o-fill-color-light); + } + + &:active { + background-color: var(--o-fill-color-extra-light); + } + } + + // 具体图标样式 + .language-icon, + .theme-icon { + color: var(--o-text-color-regular); + transition: all 0.2s ease-in-out; + + img { + width: 24px; + height: 24px; + display: block; + object-fit: contain; + } + } + + // 统一的hover效果 - 适用于所有图标 + .icon-wrapper:hover { + .language-icon, + .theme-icon, + .bell-icon { + color: var(--o-color-primary); + } + } + + .logo-icon { + img { + width: 24px; + height: 24px; + display: block; + } + } + + // 头像图标特殊样式 + .icon-item .avatar { + width: 32px !important; + height: 32px !important; + border-radius: 50% !important; + margin: 0 !important; // 移除可能的外边距 } } } -.popper-class { - height: 44px !important; -} - + \ No newline at end of file diff --git a/src/views/dialogue/dialogueView.vue b/src/views/dialogue/dialogueView.vue index 0754b9d..f719f54 100644 --- a/src/views/dialogue/dialogueView.vue +++ b/src/views/dialogue/dialogueView.vue @@ -321,11 +321,14 @@ watch( ******************************
- - + + + + {{ i18n.global.t('apikey.no_apikey') }}
@@ -610,6 +613,18 @@ watch( flex-direction: column; align-items: center; justify-content: space-between; + + // 强制覆盖所有el-icon样式 + :deep(.el-icon) { + width: 40px !important; + height: 40px !important; + font-size: 40px !important; + + img { + width: 40px !important; + height: 40px !important; + } + } .menu-item { display: flex; font-style: none; @@ -623,8 +638,34 @@ watch( cursor: pointer; .menu-icon { align-items: center; + + // 强制覆盖el-icon的样式 + &.el-icon { + width: 40px !important; + height: 40px !important; + font-size: 40px !important; + + img { + width: 40px !important; + height: 40px !important; + } + } + + // 覆盖嵌套的el-icon + .el-icon { + width: 40px !important; + height: 40px !important; + font-size: 40px !important; + + img { + width: 40px !important; + height: 40px !important; + } + } + img { width: 40px; + height: 40px; } } .menu-text { diff --git a/src/views/tools/index.vue b/src/views/tools/index.vue index 7317341..2cff478 100644 --- a/src/views/tools/index.vue +++ b/src/views/tools/index.vue @@ -20,6 +20,8 @@ import { watch, onMounted, ref, nextTick } from 'vue'; import { useRouter } from 'vue-router'; import { getBaseUrl } from 'src/utils/tools'; +import { storeToRefs } from 'pinia'; +import { useLangStore, useChangeThemeStore } from '@/store'; const router = useRouter(); const iframeRef = ref(null); @@ -27,6 +29,10 @@ const isActive = ref(false); const isIframeLoaded = ref(false); const iframeTarget = ref(''); +// 获取store状态 +const { language } = storeToRefs(useLangStore()); +const { theme } = storeToRefs(useChangeThemeStore()); + // 生产环境URL处理 async function getIframeTarget() { const baseUrl = await getBaseUrl(); @@ -45,6 +51,10 @@ const handleIframeLoad = () => { } const token = localStorage.getItem('ECSESSION') ?? ''; sendTokenToIframe(token); + + // 同步当前的主题和语言状态到iframe + sendThemeToIframe(); + sendLanguageToIframe(); }; // 处理iframe错误 @@ -53,6 +63,44 @@ const handleIframeError = (error: Event) => { // 可以在这里添加重试逻辑 }; +// 同步主题到iframe +const sendThemeToIframe = async () => { + const iframe = iframeRef.value; + if (!iframe?.contentWindow || !iframeTarget.value) { + return; + } + + try { + const data = { + theme: theme.value, + type: 'changeTheme', + }; + iframe.contentWindow.postMessage(data, iframeTarget.value); + console.log('Theme synced to iframe:', theme.value); + } catch (error) { + console.error('send theme to iframe error:', error); + } +}; + +// 同步语言到iframe +const sendLanguageToIframe = async () => { + const iframe = iframeRef.value; + if (!iframe?.contentWindow || !iframeTarget.value) { + return; + } + + try { + const data = { + lang: language.value || 'zh', + type: 'changeLanguage', + }; + iframe.contentWindow.postMessage(data, iframeTarget.value); + console.log('Language synced to iframe:', language.value); + } catch (error) { + console.error('send language to iframe error:', error); + } +}; + // 发送消息到iframe const sendMessageToIframe = async (stopActive: boolean) => { const iframe = iframeRef.value; @@ -96,6 +144,12 @@ watch( sendMessageToIframe(!isWitchaindRoute); const token = localStorage.getItem('ECSESSION') ?? ''; sendTokenToIframe(token); + + // 当跳转到witchaind路由时,同步当前主题和语言状态 + if (isWitchaindRoute) { + sendThemeToIframe(); + sendLanguageToIframe(); + } } }, { immediate: true }, diff --git a/vite.config.ts b/vite.config.ts index e1ac6b0..95b04ec 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -85,16 +85,16 @@ export default ({ mode }): UserConfigExport => { credentials: true }, proxy: { - '/api': { - target: env.VITE_BASE_PROXY_URL, + // 代理 wtd API 接口到后端服务,重写为 /witchaind/api 开头(更具体的规则放在前面) + '/wtd': { + target: env.VITE_WITCHAIND_PROXY_URL, changeOrigin: true, secure: false, ws: false, - rewrite: (path: string) => path, + rewrite: (path: string) => path.replace(/^\/wtd/, '/witchaind/api'), cookieDomainRewrite: '.euler-copilot-master.test.osinfra.cn', }, - // 代理 wtd API 接口到后端服务(生产环境中 /wtd 对应原来的 /witchaind API) - '/wtd': { + '/api': { target: env.VITE_BASE_PROXY_URL, changeOrigin: true, secure: false, -- Gitee