feat: 完善对话功能,自动设置默认模型账户并优化界面布局
This commit is contained in:
@@ -550,7 +550,10 @@ contextBridge.exposeInMainWorld('api', {
|
|||||||
#### 4.5.2 Chat 页面移除模型选择器
|
#### 4.5.2 Chat 页面移除模型选择器
|
||||||
- 从 `ChatBox.vue` 中移除 `ModelSelector` 组件及其引用;
|
- 从 `ChatBox.vue` 中移除 `ModelSelector` 组件及其引用;
|
||||||
- 对话功能直接使用 provider 管理中「设置为默认」的模型账户;
|
- 对话功能直接使用 provider 管理中「设置为默认」的模型账户;
|
||||||
- 若未设置默认模型,提示用户前往模型管理页面配置。
|
- 对话页面 `onMounted` 时主动调用 `providerStore.init()` 加载模型配置。
|
||||||
|
|
||||||
|
#### 4.5.3 自动默认模型兜底
|
||||||
|
当 `providerStore.init()` 初始化后发现用户已存在 provider accounts 但未设置 `defaultAccountId` 时,自动将第一个 account 设为默认,确保用户无需手动点击"设为默认"即可直接开始对话。若用户没有任何账户,则保持原有提示行为。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta
|
<meta
|
||||||
http-equiv="Content-Security-Policy"
|
http-equiv="Content-Security-Policy"
|
||||||
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' http://8.138.234.141 https://one-feel-bucket.oss-cn-guangzhou.aliyuncs.com; connect-src 'self' http://8.138.234.141 https://api.iconify.design wss://onefeel.brother7.cn"
|
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: http://8.138.234.141 https://one-feel-bucket.oss-cn-guangzhou.aliyuncs.com; connect-src 'self' http://8.138.234.141 https://api.iconify.design wss://onefeel.brother7.cn"
|
||||||
/>
|
/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -5,17 +5,10 @@ export interface taskCenterItem {
|
|||||||
desc: string,
|
desc: string,
|
||||||
id: string,
|
id: string,
|
||||||
icon: string,
|
icon: string,
|
||||||
type: 'sale' | 'close' | 'open' | 'channel'
|
type?: 'channel'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const taskCenterList: taskCenterItem[] = [
|
export const taskCenterList: taskCenterItem[] = [
|
||||||
{
|
|
||||||
title: '每日销售数据',
|
|
||||||
desc: '分析用于销售渠道每日数据汇总及简要展示',
|
|
||||||
id: uuidv4(),
|
|
||||||
icon: '销',
|
|
||||||
type: 'sale'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: '一键打开各渠道',
|
title: '一键打开各渠道',
|
||||||
desc: '人工账号登录,为自动化操作做好准备',
|
desc: '人工账号登录,为自动化操作做好准备',
|
||||||
@@ -24,17 +17,9 @@ export const taskCenterList: taskCenterItem[] = [
|
|||||||
type: 'channel'
|
type: 'channel'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '关渠道房型',
|
title: '渠道房型',
|
||||||
desc: '关闭销售渠道下的指定房型',
|
desc: '销售渠道下的指定房型,管理开关房型',
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
icon: '关',
|
icon: '房'
|
||||||
type: 'close'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '开渠道房型',
|
|
||||||
desc: '开启销售渠道下的指定房型',
|
|
||||||
id: uuidv4(),
|
|
||||||
icon: '开',
|
|
||||||
type: 'open'
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@@ -1,12 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col h-full py-6 px-6 overflow-hidden">
|
<div class="flex flex-col flex-1 py-6 px-6 overflow-hidden">
|
||||||
<!-- 空状态 -->
|
<!-- 空状态 -->
|
||||||
<template v-if="isEmpty">
|
<template v-if="isEmpty">
|
||||||
<ChatEmpty @click-tag="onQuickTag">
|
<ChatEmpty @click-tag="onQuickTag" />
|
||||||
<template #task-center>
|
|
||||||
<TaskCenter />
|
|
||||||
</template>
|
|
||||||
</ChatEmpty>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 消息列表 -->
|
<!-- 消息列表 -->
|
||||||
@@ -35,11 +31,6 @@
|
|||||||
|
|
||||||
<!-- 输入区 -->
|
<!-- 输入区 -->
|
||||||
<div class="flex flex-col gap-3 mt-4">
|
<div class="flex flex-col gap-3 mt-4">
|
||||||
<div class="flex items-center gap-3">
|
|
||||||
<div class="inline-flex items-center justify-center w-[108px] px-3 py-1.5 rounded-2xl border border-[#E5E8EE] text-[13px] text-[#333] cursor-pointer hover:bg-[#2B7FFF] hover:text-[#fff] hover:border-[#2B7FFF]">
|
|
||||||
智能问数
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ChatInput
|
<ChatInput
|
||||||
v-model="inputMessage"
|
v-model="inputMessage"
|
||||||
:is-sending="chatStore.sending"
|
:is-sending="chatStore.sending"
|
||||||
@@ -69,7 +60,6 @@ import ChatEmpty from './components/chat/ChatEmpty.vue'
|
|||||||
import ChatErrorBar from './components/chat/ChatErrorBar.vue'
|
import ChatErrorBar from './components/chat/ChatErrorBar.vue'
|
||||||
import ChatTypingIndicator from './components/chat/ChatTypingIndicator.vue'
|
import ChatTypingIndicator from './components/chat/ChatTypingIndicator.vue'
|
||||||
import ChatActivityIndicator from './components/chat/ChatActivityIndicator.vue'
|
import ChatActivityIndicator from './components/chat/ChatActivityIndicator.vue'
|
||||||
import TaskCenter from './TaskCenter.vue'
|
|
||||||
|
|
||||||
const chatStore = useChatStore()
|
const chatStore = useChatStore()
|
||||||
const inputMessage = ref('')
|
const inputMessage = ref('')
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="h-full">
|
<div :class="['h-full transition-all duration-300', sidebarCollapsed ? 'w-16' : 'w-50']">
|
||||||
<aside :class="['h-full box-border flex flex-col transition-all duration-300', sidebarCollapsed ? 'w-16' : 'w-50']">
|
<aside class="h-full box-border flex flex-col w-full">
|
||||||
<div class="flex items-center justify-center m-2">
|
<div class="flex items-center justify-center m-2">
|
||||||
<img v-if="!sidebarCollapsed" class="w-10 h-10 rounded-md" src="@assets/images/login/white_logo.png" />
|
<img v-if="!sidebarCollapsed" class="w-10 h-10 rounded-md" src="@assets/images/login/white_logo.png" />
|
||||||
<div v-if="!sidebarCollapsed" class="font-bold text-gray-80">YINIAN</div>
|
<div v-if="!sidebarCollapsed" class="font-bold text-gray-80">YINIAN</div>
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex-1 pb-6">
|
<div class="pl-6 pr-6 pb-6">
|
||||||
<div class="flex justify-between items-center py-4">
|
<div class="flex justify-between items-center pb-4">
|
||||||
<h3 class="text-base font-semibold">任务中心</h3>
|
<h3 class="text-base font-semibold">任务中心</h3>
|
||||||
<!-- <a class="text-[#3b82f6] text-[13px] cursor-pointer">
|
|
||||||
编辑
|
|
||||||
</a> -->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-2 gap-4 max-[800px]:grid-cols-1">
|
<div class="grid grid-cols-2 gap-4 max-[800px]:grid-cols-1">
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-auto">
|
<div class="mt-auto">
|
||||||
<slot name="task-center" />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
<!-- Markdown text -->
|
<!-- Markdown text -->
|
||||||
<div
|
<div
|
||||||
v-if="markdownHtml"
|
v-if="markdownHtml"
|
||||||
class="bg-[#f7f9fc] rounded-md px-3 py-2 prose prose-sm max-w-none"
|
class="bg-[#f7f9fc] rounded-md px-3 py-2 prose prose-sm"
|
||||||
v-html="markdownHtml"
|
v-html="markdownHtml"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<layout>
|
<layout>
|
||||||
<div class="flex h-full w-full flex-col md:flex-row">
|
<div class="flex h-full w-full flex-col md:flex-row">
|
||||||
<ChatHistory class="flex-none w-50" @new-chat="handleNewChat" @select-chat="handleSelectChat" />
|
<ChatHistory class="flex-none" @new-chat="handleNewChat" @select-chat="handleSelectChat" />
|
||||||
<div class="flex-1 mr-2 overflow-hidden bg-white rounded-xl">
|
<div class="flex-1 mr-2 overflow-hidden bg-white rounded-xl flex flex-col">
|
||||||
<ChatBox />
|
<ChatBox class="flex-1" />
|
||||||
|
<TaskCenter />
|
||||||
</div>
|
</div>
|
||||||
<TaskList />
|
<TaskList />
|
||||||
</div>
|
</div>
|
||||||
@@ -18,20 +19,23 @@ import TaskList from '@src/components/TaskList/index.vue'
|
|||||||
import TaskOperationDialog from './components/TaskOperationDialog.vue'
|
import TaskOperationDialog from './components/TaskOperationDialog.vue'
|
||||||
import ChatHistory from './ChatHistory.vue'
|
import ChatHistory from './ChatHistory.vue'
|
||||||
import ChatBox from './ChatBox.vue'
|
import ChatBox from './ChatBox.vue'
|
||||||
|
import TaskCenter from './TaskCenter.vue'
|
||||||
import { useChatStore } from '@store/chat'
|
import { useChatStore } from '@store/chat'
|
||||||
|
import { useProviderStore } from '@store/providers'
|
||||||
import emitter from '@src/utils/emitter'
|
import emitter from '@src/utils/emitter'
|
||||||
|
|
||||||
const chatStore = useChatStore()
|
const chatStore = useChatStore()
|
||||||
|
const providerStore = useProviderStore()
|
||||||
const taskOperationDialog = ref()
|
const taskOperationDialog = ref()
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
|
await providerStore.init()
|
||||||
chatStore.loadSessions()
|
chatStore.loadSessions()
|
||||||
chatStore.initConnection()
|
chatStore.subscribeToGateway()
|
||||||
})
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
chatStore.cleanupEmptySession()
|
chatStore.cleanupEmptySession()
|
||||||
chatStore.closeConnection()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleNewChat = () => {
|
const handleNewChat = () => {
|
||||||
|
|||||||
@@ -323,13 +323,14 @@ export async function stageBuffer(base64: string, fileName: string, mimeType: st
|
|||||||
if (result && result.stagedPath) return result
|
if (result && result.stagedPath) return result
|
||||||
} catch { /* fallback */ }
|
} catch { /* fallback */ }
|
||||||
|
|
||||||
|
const dataUrl = `data:${mimeType};base64,${base64}`
|
||||||
return {
|
return {
|
||||||
id: crypto.randomUUID(),
|
id: crypto.randomUUID(),
|
||||||
fileName,
|
fileName,
|
||||||
mimeType,
|
mimeType,
|
||||||
fileSize: Math.ceil(base64.length * 0.75),
|
fileSize: Math.ceil(base64.length * 0.75),
|
||||||
stagedPath: '',
|
stagedPath: dataUrl,
|
||||||
preview: mimeType.startsWith('image/') ? `data:${mimeType};base64,${base64}` : null,
|
preview: mimeType.startsWith('image/') ? dataUrl : null,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,15 @@ export const useProviderStore = defineStore('providers', () => {
|
|||||||
|
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
await refreshProviderSnapshot();
|
await refreshProviderSnapshot();
|
||||||
|
|
||||||
|
// 自动兜底:如果有账户但没设默认,自动将第一个设为默认
|
||||||
|
if (accounts.value.length > 0 && !defaultAccountId.value) {
|
||||||
|
try {
|
||||||
|
await setDefaultAccount(accounts.value[0].id);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Auto-set default account failed:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshProviderSnapshot = async () => {
|
const refreshProviderSnapshot = async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user