From 6cbed955c31d6be0a7d6c4898369c270cd2d24a3 Mon Sep 17 00:00:00 2001 From: Ethan-Zhang Date: Sat, 18 Oct 2025 11:49:51 +0800 Subject: [PATCH] =?UTF-8?q?Fear:=20=E5=AE=8C=E5=96=84=E7=94=A8=E6=88=B7Pop?= =?UTF-8?q?over&=E7=94=A8=E6=88=B7=E4=BF=A1=E6=81=AFLocalStorage=E5=AE=8C?= =?UTF-8?q?=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/paths/account.ts | 31 +- src/apis/tools.ts | 1 + src/store/account.ts | 4 +- src/store/index.ts | 1 + src/store/userPreferences.ts | 113 +++++++ src/views/dialogue/Copilot.vue | 31 ++ src/views/dialogue/components/TitleBar.vue | 334 ++++++++++++++++++++- src/views/dialogue/dialogueView.vue | 6 + 8 files changed, 507 insertions(+), 14 deletions(-) create mode 100644 src/store/userPreferences.ts diff --git a/src/apis/paths/account.ts b/src/apis/paths/account.ts index c465a147..7947e341 100644 --- a/src/apis/paths/account.ts +++ b/src/apis/paths/account.ts @@ -20,7 +20,7 @@ export const authorizeUser = (): Promise< ( | FcResponse<{ user_sub: string; - username: string; + user_name: string; organization: string; revision_number: string | null; is_admin: boolean; @@ -143,9 +143,32 @@ export const getUserPreferences = (): Promise< any, ( | FcResponse<{ - reasoningModelPreference?: any; - embeddingModelPreference?: any; - rerankerPreference?: any; + reasoningModelPreference?: { + llmId: string; + icon?: string; + openaiBaseUrl: string; + openaiApiKey: string; + modelName: string; + maxTokens: number; + isEditable?: boolean; + }; + embeddingModelPreference?: { + llmId: string; + modelName: string; + icon?: string; + type: string; + endpoint: string; + apiKey: string; + }; + rerankerPreference?: { + llmId: string; + modelName: string; + icon?: string; + type: string; + endpoint?: string; + apiKey?: string; + name?: string; + }; chainOfThoughtPreference?: boolean; }> | undefined diff --git a/src/apis/tools.ts b/src/apis/tools.ts index 2a2c9c5f..6f78ef7f 100644 --- a/src/apis/tools.ts +++ b/src/apis/tools.ts @@ -64,6 +64,7 @@ async function toAuthorization() { const postMessageListener = async (event: MessageEvent) => { // 期望 event.data = { type: 'auth_success', sessionId: 'xxxx' } + console.log(event); const { sessionId, type } = event.data || {}; if (type === 'auth_success' && sessionId) { window.removeEventListener('message', postMessageListener); diff --git a/src/store/account.ts b/src/store/account.ts index 581ab943..0c3dac1c 100644 --- a/src/store/account.ts +++ b/src/store/account.ts @@ -97,8 +97,8 @@ export const useAccountStore = defineStore('account', () => { const getUserInfo = async (): Promise => { const [_, res] = await api.authorizeUser(); if (!_ && res) { - const { organization, username, revision_number, user_sub } = res.result; - userinfo.username = username; + const { organization, user_name, revision_number, user_sub } = res.result; + userinfo.username = user_name; userinfo.user_sub = user_sub; userinfo.organization = organization; userinfo.revsionNumber = revision_number; diff --git a/src/store/index.ts b/src/store/index.ts index bb8159da..454d9894 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -12,3 +12,4 @@ export * from './conversation'; export * from './historySession'; export * from './lang'; export * from './theme'; +export * from './userPreferences'; diff --git a/src/store/userPreferences.ts b/src/store/userPreferences.ts new file mode 100644 index 00000000..f771060f --- /dev/null +++ b/src/store/userPreferences.ts @@ -0,0 +1,113 @@ +// Copyright (c) Huawei Technologies Co., Ltd. 2023-2025. All rights reserved. +// licensed under the Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN 'AS IS' BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +// PURPOSE. +// See the Mulan PSL v2 for more details. +import { defineStore } from 'pinia'; +import { reactive, ref } from 'vue'; +import { api } from 'src/apis'; + +export interface ReasoningModelPreference { + llmId: string; + icon?: string; + openaiBaseUrl: string; + openaiApiKey: string; + modelName: string; + maxTokens: number; + isEditable?: boolean; +} + +export interface EmbeddingModelPreference { + llmId: string; + modelName: string; + icon?: string; + type: string; + endpoint: string; + apiKey: string; +} + +export interface RerankerModelPreference { + llmId: string; + modelName: string; + icon?: string; + type: string; + endpoint?: string; + apiKey?: string; + name?: string; +} + +export interface UserPreferences { + reasoningModelPreference?: ReasoningModelPreference; + embeddingModelPreference?: EmbeddingModelPreference; + rerankerPreference?: RerankerModelPreference; + chainOfThoughtPreference?: boolean; +} + +export const useUserPreferencesStore = defineStore('userPreferences', () => { + // 用户偏好设置 + const preferences = reactive({ + reasoningModelPreference: undefined, + embeddingModelPreference: undefined, + rerankerPreference: undefined, + chainOfThoughtPreference: undefined, + }); + + // 加载状态 + const loading = ref(false); + + /** + * 获取用户偏好设置 + */ + const getUserPreferences = async (): Promise => { + loading.value = true; + try { + const [_, res] = await api.getUserPreferences(); + if (!_ && res) { + Object.assign(preferences, res.result); + return true; + } + return false; + } finally { + loading.value = false; + } + }; + + /** + * 更新用户偏好设置 + */ + const updateUserPreferences = async (newPreferences: Partial): Promise => { + loading.value = true; + try { + const [_, res] = await api.updateUserPreferences(newPreferences); + if (!_ && res) { + Object.assign(preferences, newPreferences); + return true; + } + return false; + } finally { + loading.value = false; + } + }; + + /** + * 重置偏好设置 + */ + const resetPreferences = () => { + preferences.reasoningModelPreference = undefined; + preferences.embeddingModelPreference = undefined; + preferences.rerankerPreference = undefined; + preferences.chainOfThoughtPreference = undefined; + }; + + return { + preferences, + loading, + getUserPreferences, + updateUserPreferences, + resetPreferences, + }; +}); diff --git a/src/views/dialogue/Copilot.vue b/src/views/dialogue/Copilot.vue index 1164d4cf..e5d1f914 100644 --- a/src/views/dialogue/Copilot.vue +++ b/src/views/dialogue/Copilot.vue @@ -113,6 +113,37 @@ onMounted(async () => { top: 0, left: 0, }); + + // 检查是否是登录回调 + const urlParams = new URLSearchParams(window.location.search); + const code = urlParams.get('code'); + + // 如果存在授权码且当前窗口是弹窗(有opener),则处理登录 + if (code && window.opener) { + try { + // 直接调用登录API + const [_, res] = await api.login(code); + if (!_ && res) { + // 设置CSRF token到sessionStorage + sessionStorage.setItem('csrftk', res.result.csrf_token); + + // 设置CSRF token到cookie,这是API请求需要的 + document.cookie = `_csrf_tk=${res.result.csrf_token}; path=/; SameSite=Strict`; + + // 通知父窗口登录成功,使用现有的消息格式 + window.opener.postMessage({ + type: 'auth_success', + sessionId: res.result.csrf_token + }, '*'); + + // 关闭当前登录窗口 + window.close(); + } + } catch (error) { + console.error('登录失败:', error); + // 可以在这里添加错误处理,比如显示错误消息 + } + } });