refactor(views): 将主页面组件拆分为独立的子组件
将原 index.vue 中的大型单文件组件按功能模块拆分为多个独立的子组件: - 提取 GlobalHeader 为独立组件 - 提取 SidebarNav 为独立组件 - 提取 DashboardView 为独立组件 - 提取 StrategyView 为独立组件 - 提取 MonitorView 为独立组件 通过组件化提高代码的可维护性和复用性,使主文件结构更清晰
This commit is contained in:
172
247_Contry/src/views/index/components/DashboardView.vue
Normal file
172
247_Contry/src/views/index/components/DashboardView.vue
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
<template>
|
||||||
|
<div class="h-full flex flex-col gap-6 overflow-y-auto pr-2">
|
||||||
|
<div class="grid grid-cols-4 gap-6">
|
||||||
|
<div class="glass-panel rounded-2xl p-5 relative overflow-hidden group">
|
||||||
|
<div class="absolute right-0 top-0 p-4 opacity-10 group-hover:opacity-20 transition-opacity"><i class="ph-fill ph-currency-yen text-6xl text-primary"></i></div>
|
||||||
|
<div class="text-slate-400 text-xs font-bold tracking-wider uppercase mb-1">本周 GMV 预估</div>
|
||||||
|
<div class="text-3xl font-bold text-white mb-2">¥245,600</div>
|
||||||
|
<div class="flex items-center gap-2 text-xs">
|
||||||
|
<span class="text-emerald-400 bg-emerald-400/10 px-1.5 py-0.5 rounded flex items-center gap-1"><i class="ph-bold ph-trend-up"></i> 1.2%</span>
|
||||||
|
<span class="text-slate-500">转化率 (目标 1%)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="glass-panel rounded-2xl p-5 relative overflow-hidden group">
|
||||||
|
<div class="absolute right-0 top-0 p-4 opacity-10 group-hover:opacity-20 transition-opacity"><i class="ph-fill ph-users-three text-6xl text-secondary"></i></div>
|
||||||
|
<div class="text-slate-400 text-xs font-bold tracking-wider uppercase mb-1">当前并发接待</div>
|
||||||
|
<div class="text-3xl font-bold text-white mb-2">842 <span class="text-sm font-normal text-slate-500">人</span></div>
|
||||||
|
<div class="flex items-center gap-2 text-xs">
|
||||||
|
<span class="text-secondary bg-secondary/10 px-1.5 py-0.5 rounded">AI 负载: 42%</span>
|
||||||
|
<span class="text-slate-500">系统健康</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="glass-panel rounded-2xl p-5 relative overflow-hidden group">
|
||||||
|
<div class="absolute right-0 top-0 p-4 opacity-10 group-hover:opacity-20 transition-opacity"><i class="ph-fill ph-robot text-6xl text-accent"></i></div>
|
||||||
|
<div class="text-slate-400 text-xs font-bold tracking-wider uppercase mb-1">节省人力折算</div>
|
||||||
|
<div class="text-3xl font-bold text-white mb-2">34.5 <span class="text-sm font-normal text-slate-500">人/天</span></div>
|
||||||
|
<div class="flex items-center gap-2 text-xs">
|
||||||
|
<span class="text-accent bg-accent/10 px-1.5 py-0.5 rounded">≈ 4个销售组</span>
|
||||||
|
<span class="text-slate-500">效能提升</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="glass-panel rounded-2xl p-5 relative overflow-hidden group">
|
||||||
|
<div class="absolute right-0 top-0 p-4 opacity-10 group-hover:opacity-20 transition-opacity"><i class="ph-fill ph-warning-octagon text-6xl text-error"></i></div>
|
||||||
|
<div class="text-slate-400 text-xs font-bold tracking-wider uppercase mb-1">人工干预率</div>
|
||||||
|
<div class="text-3xl font-bold text-white mb-2">4.8%</div>
|
||||||
|
<div class="flex items-center gap-2 text-xs">
|
||||||
|
<span class="text-error bg-error/10 px-1.5 py-0.5 rounded">异议/退费</span>
|
||||||
|
<span class="text-slate-500">主要原因</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 h-[420px]">
|
||||||
|
<div class="lg:col-span-1 glass-panel rounded-2xl p-6 flex flex-col">
|
||||||
|
<div class="flex justify-between items-center mb-6">
|
||||||
|
<h3 class="font-bold text-white flex items-center gap-2"><i class="ph-fill ph-funnel text-primary"></i> 销售漏斗监控</h3>
|
||||||
|
<button class="btn btn-xs btn-ghost text-slate-400"><i class="ph-bold ph-dots-three"></i></button>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 flex flex-col justify-center gap-4">
|
||||||
|
<div v-for="(item, index) in funnelData" :key="index" class="relative group cursor-default">
|
||||||
|
<div class="flex justify-between text-xs mb-1.5">
|
||||||
|
<span class="text-slate-300 font-medium">{{ item.stage }}</span>
|
||||||
|
<span class="text-slate-400 font-mono">{{ item.count }} <span class="opacity-50">/</span> <span :class="item.rate < 10 ? 'text-primary' : 'text-slate-400'">{{ item.rate }}%</span></span>
|
||||||
|
</div>
|
||||||
|
<div class="w-full bg-slate-800/50 rounded-full h-2.5 overflow-hidden border border-slate-700/50">
|
||||||
|
<div
|
||||||
|
class="h-full rounded-full transition-all duration-1000 relative overflow-hidden"
|
||||||
|
:class="index > 4 ? 'bg-gradient-to-r from-primary to-accent' : 'bg-slate-600'"
|
||||||
|
:style="{ width: item.rate + '%' }"
|
||||||
|
>
|
||||||
|
<div class="absolute inset-0 bg-white/20 w-full h-full animate-[shimmer_2s_infinite] translate-x-[-100%]" v-if="index > 4"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lg:col-span-2 glass-panel rounded-2xl p-6 flex flex-col relative overflow-hidden">
|
||||||
|
<div class="flex justify-between items-start mb-4 z-10">
|
||||||
|
<div>
|
||||||
|
<h3 class="font-bold text-white flex items-center gap-2">
|
||||||
|
<i class="ph-fill ph-waves text-blue-400"></i> 流量潮汐实时监控
|
||||||
|
</h3>
|
||||||
|
<p class="text-xs text-slate-500 mt-1">洋葱模型预测:当前处于爬坡期,预计 20:00 达到峰值</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<div class="badge badge-primary badge-outline text-xs gap-1"><i class="ph-bold ph-lightning"></i> AI 响应: 1.2s</div>
|
||||||
|
<div class="badge badge-secondary badge-outline text-xs gap-1"><i class="ph-bold ph-coin"></i> Token: $14.2/h</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 flex items-end justify-between gap-1 z-10 px-1 pt-4 border-b border-slate-700/50">
|
||||||
|
<div v-for="(h, i) in trafficData" :key="i"
|
||||||
|
class="w-full bg-blue-500/20 rounded-t-sm hover:bg-blue-500/60 transition-all duration-300 relative group"
|
||||||
|
:style="{ height: h + '%' }">
|
||||||
|
<div class="absolute -top-10 left-1/2 -translate-x-1/2 bg-slate-800 text-white text-[10px] px-2 py-1 rounded border border-slate-600 opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none whitespace-nowrap z-20 shadow-xl">
|
||||||
|
QPS: {{ Math.round(h * 3.5) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between text-[10px] text-slate-600 font-mono mt-2 z-10">
|
||||||
|
<span>14:00</span>
|
||||||
|
<span>14:15</span>
|
||||||
|
<span>14:30</span>
|
||||||
|
<span>14:45</span>
|
||||||
|
<span>15:00</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="absolute inset-0 z-0 bg-gradient-to-t from-blue-500/5 to-transparent pointer-events-none"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="glass-panel rounded-2xl p-6 flex-1 min-h-[300px]">
|
||||||
|
<div class="flex justify-between items-center mb-4">
|
||||||
|
<h3 class="font-bold text-white flex items-center gap-2"><i class="ph-fill ph-list-dashes text-slate-400"></i> 系统事件日志</h3>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<span class="loading loading-dots loading-xs text-slate-500"></span>
|
||||||
|
<span class="text-xs text-slate-500 font-mono">LIVE</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="table table-xs table-pin-rows">
|
||||||
|
<thead>
|
||||||
|
<tr class="text-slate-500 border-b border-slate-700/50">
|
||||||
|
<th>TIMESTAMP</th>
|
||||||
|
<th>EVENT TYPE</th>
|
||||||
|
<th>CUSTOMER</th>
|
||||||
|
<th>AI DECISION & ACTION</th>
|
||||||
|
<th>STATUS</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="font-mono">
|
||||||
|
<tr v-for="log in eventLogs" :key="log.id" class="hover:bg-slate-800/30 transition-colors border-slate-800/30 group">
|
||||||
|
<td class="text-slate-500">{{ log.time }}</td>
|
||||||
|
<td>
|
||||||
|
<span class="badge badge-ghost badge-xs gap-1 border-slate-700 text-slate-300">
|
||||||
|
{{ log.type }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="font-medium text-slate-300">{{ log.user }}</td>
|
||||||
|
<td class="max-w-md truncate text-slate-400 group-hover:text-slate-200 transition-colors">
|
||||||
|
<span class="text-primary mr-2">[{{log.model}}]</span>
|
||||||
|
{{ log.action }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span v-if="log.status === 'success'" class="text-emerald-400 flex items-center gap-1"><i class="ph-fill ph-check-circle"></i> OK</span>
|
||||||
|
<span v-else-if="log.status === 'warning'" class="text-orange-400 flex items-center gap-1"><i class="ph-fill ph-warning"></i> MANUAL</span>
|
||||||
|
<span v-else class="text-blue-400 flex items-center gap-1"><i class="ph-bold ph-spinner animate-spin"></i> RUNNING</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
type FunnelItem = {
|
||||||
|
stage: string;
|
||||||
|
count: number;
|
||||||
|
rate: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type EventLog = {
|
||||||
|
id: number;
|
||||||
|
time: string;
|
||||||
|
type: string;
|
||||||
|
user: string;
|
||||||
|
model: string;
|
||||||
|
action: string;
|
||||||
|
status: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
funnelData: FunnelItem[];
|
||||||
|
trafficData: number[];
|
||||||
|
eventLogs: EventLog[];
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
40
247_Contry/src/views/index/components/GlobalHeader.vue
Normal file
40
247_Contry/src/views/index/components/GlobalHeader.vue
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<template>
|
||||||
|
<header class="h-16 glass-panel border-b-0 flex items-center justify-between px-6 z-50">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="w-9 h-9 rounded-xl bg-gradient-to-br from-primary to-accent flex items-center justify-center shadow-lg shadow-primary/20">
|
||||||
|
<i class="ph-bold ph-brain text-white text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1 class="font-bold text-lg tracking-wide leading-tight text-white">247<span class="text-primary">控制中台</span></h1>
|
||||||
|
<div class="text-[10px] text-slate-400 font-mono tracking-wider">SALES PILOT V1.0</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-6">
|
||||||
|
<div class="flex items-center gap-3 px-4 py-1.5 rounded-full bg-slate-800/80 border border-slate-700/50 backdrop-blur-sm">
|
||||||
|
<div class="flex flex-col items-end leading-none">
|
||||||
|
<span class="text-[10px] text-slate-400">TRAFFIC TIDE</span>
|
||||||
|
<span class="text-xs font-bold text-green-400">LOAD: LOW</span>
|
||||||
|
</div>
|
||||||
|
<span class="relative flex h-3 w-3">
|
||||||
|
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
|
||||||
|
<span class="relative inline-flex rounded-full h-3 w-3 bg-green-500"></span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="divider divider-horizontal mx-0 h-8"></div>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="text-right hidden sm:block">
|
||||||
|
<div class="text-xs font-bold text-slate-200">Admin User</div>
|
||||||
|
<div class="text-[10px] text-slate-500">Super Admin</div>
|
||||||
|
</div>
|
||||||
|
<div class="avatar placeholder cursor-pointer">
|
||||||
|
<div class="bg-gradient-to-tr from-slate-700 to-slate-600 text-white rounded-full w-9 ring ring-primary ring-offset-base-100 ring-offset-2">
|
||||||
|
<span class="text-xs">PM</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</template>
|
||||||
140
247_Contry/src/views/index/components/MonitorView.vue
Normal file
140
247_Contry/src/views/index/components/MonitorView.vue
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
<template>
|
||||||
|
<div class="h-full flex gap-6">
|
||||||
|
<div class="w-80 glass-panel rounded-2xl flex flex-col overflow-hidden">
|
||||||
|
<div class="p-4 border-b border-slate-700/50 bg-slate-900/30">
|
||||||
|
<h3 class="font-bold text-white text-sm mb-3">实时活跃会话</h3>
|
||||||
|
<div class="relative">
|
||||||
|
<i class="ph ph-magnifying-glass absolute left-3 top-2.5 text-slate-500"></i>
|
||||||
|
<input class="input input-sm w-full bg-slate-950 border-slate-700 pl-9 text-xs focus:border-primary" placeholder="搜索家长姓名/ID..." />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 overflow-y-auto p-2 space-y-2">
|
||||||
|
<div v-for="user in activeUsers" :key="user.id"
|
||||||
|
class="p-3 rounded-xl cursor-pointer transition-all border border-transparent hover:border-slate-700"
|
||||||
|
:class="user.active ? 'bg-primary/10 border-primary/30' : 'bg-slate-800/30 hover:bg-slate-800/80'"
|
||||||
|
>
|
||||||
|
<div class="flex justify-between items-start mb-1">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 rounded-full" :class="user.risk ? 'bg-red-500 animate-pulse' : 'bg-green-500'"></div>
|
||||||
|
<span class="font-bold text-sm text-slate-200">{{ user.name }}</span>
|
||||||
|
</div>
|
||||||
|
<span class="text-[10px] text-slate-500">{{ user.time }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-slate-400 truncate mb-2">{{ user.lastMsg }}</div>
|
||||||
|
<div class="flex flex-wrap gap-1">
|
||||||
|
<div class="badge badge-xs border-0 text-white" :class="getStageBadge(user.stage)">{{ user.stage }}</div>
|
||||||
|
<div v-if="user.risk" class="badge badge-xs badge-error gap-1"><i class="ph-bold ph-warning"></i> 需人工</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 flex flex-col glass-panel rounded-2xl overflow-hidden relative">
|
||||||
|
<div class="h-16 border-b border-slate-700/50 flex justify-between items-center px-6 bg-slate-900/50 backdrop-blur-md z-10">
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="font-bold text-lg text-white">王梓涵妈妈</span>
|
||||||
|
<div class="badge badge-primary badge-outline badge-xs">ID: 883921</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2 mt-0.5">
|
||||||
|
<span class="relative flex h-2 w-2">
|
||||||
|
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
|
||||||
|
<span class="relative inline-flex rounded-full h-2 w-2 bg-green-500"></span>
|
||||||
|
</span>
|
||||||
|
<span class="text-xs text-slate-400">AI 托管中 | 策略模型: Claude-3 Opus</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<button class="btn btn-error btn-xs" @click="emit('toggleManual')">
|
||||||
|
<i class="ph-bold ph-hand-palm"></i> 强制接管
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-neutral btn-xs border-slate-600">
|
||||||
|
<i class="ph ph-file-text"></i> 画像
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 p-4 sm:p-6 overflow-y-auto space-y-8 bg-slate-950/50" ref="chatBox">
|
||||||
|
<div v-for="msg in chatHistory" :key="msg.id" class="flex gap-4 group" :class="msg.role === 'user' ? 'flex-row-reverse' : ''">
|
||||||
|
|
||||||
|
<div class="flex-shrink-0 mt-1">
|
||||||
|
<div class="w-9 h-9 rounded-full border border-slate-700/50 p-1 flex items-center justify-center shadow-lg transition-transform group-hover:scale-105"
|
||||||
|
:class="msg.role === 'ai' ? 'bg-indigo-600' : 'bg-slate-800'">
|
||||||
|
<i v-if="msg.role === 'ai'" class="ph-bold ph-robot text-lg text-white"></i>
|
||||||
|
<i v-else class="ph-bold ph-user text-lg text-white"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col max-w-[85%] sm:max-w-[75%]" :class="msg.role === 'user' ? 'items-end' : 'items-start'">
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2 mb-1.5 text-[10px] text-slate-500">
|
||||||
|
<span class="font-bold text-slate-400">{{ msg.role === 'ai' ? 'Nexus AI Agent' : '家长' }}</span>
|
||||||
|
<time class="opacity-50 font-mono">{{ msg.time }}</time>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="msg.role === 'ai' && msg.thought" class="mb-3 w-full animate-in fade-in slide-in-from-top-2 duration-500">
|
||||||
|
<div class="p-3 bg-yellow-500/5 border border-yellow-700/20 rounded-lg text-xs text-yellow-500/80 font-mono shadow-sm relative overflow-hidden">
|
||||||
|
<div class="absolute left-0 top-0 bottom-0 w-0.5 bg-yellow-600/40"></div>
|
||||||
|
<div class="flex items-center gap-1.5 mb-1.5 opacity-90 font-bold uppercase tracking-wider text-[9px]">
|
||||||
|
<i class="ph-bold ph-cpu"></i> 决策链路: {{ msg.stage }}
|
||||||
|
</div>
|
||||||
|
<div class="leading-relaxed opacity-80 break-words whitespace-pre-wrap">> {{ msg.thought }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-3.5 rounded-2xl shadow-xl text-sm leading-relaxed break-words relative group-hover:shadow-2xl transition-shadow"
|
||||||
|
:class="msg.role === 'ai'
|
||||||
|
? 'bg-indigo-600 text-white rounded-tl-sm'
|
||||||
|
: 'bg-slate-800 text-slate-200 rounded-tr-sm'">
|
||||||
|
{{ msg.content }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="msg.role === 'ai'" class="mt-1.5 flex items-center gap-3 text-[9px] text-slate-600 font-mono opacity-0 group-hover:opacity-100 transition-opacity">
|
||||||
|
<span class="flex items-center gap-1"><i class="ph-bold ph-lightning"></i> Claude-3 Opus</span>
|
||||||
|
<span class="flex items-center gap-1"><i class="ph-bold ph-clock"></i> 420ms</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-4 bg-slate-900 border-t border-slate-700/50">
|
||||||
|
<div class="relative">
|
||||||
|
<input type="text" placeholder="输入内容以进行人工干预 (AI 将暂停响应)..." class="input input-bordered w-full bg-slate-950 border-slate-700 focus:border-primary pr-12 text-sm" />
|
||||||
|
<button class="absolute right-1 top-1 btn btn-sm btn-primary rounded-lg aspect-square p-0"><i class="ph-bold ph-paper-plane-right text-lg"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
type ActiveUser = {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
time: string;
|
||||||
|
lastMsg: string;
|
||||||
|
stage: string;
|
||||||
|
risk: boolean;
|
||||||
|
active: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ChatMessage = {
|
||||||
|
id: number;
|
||||||
|
role: 'ai' | 'user';
|
||||||
|
content: string;
|
||||||
|
time: string;
|
||||||
|
stage: string;
|
||||||
|
thought: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
activeUsers: ActiveUser[];
|
||||||
|
chatHistory: ChatMessage[];
|
||||||
|
getStageBadge: (stage: string) => string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'toggleManual'): void;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
45
247_Contry/src/views/index/components/SidebarNav.vue
Normal file
45
247_Contry/src/views/index/components/SidebarNav.vue
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<template>
|
||||||
|
<aside class="w-64 glass-panel border-t-0 border-l-0 border-b-0 flex flex-col justify-between py-6 z-40">
|
||||||
|
<ul class="menu w-full px-3 gap-2">
|
||||||
|
<li v-for="item in navItems" :key="item.id">
|
||||||
|
<a
|
||||||
|
@click="emit('select', item.id)"
|
||||||
|
:class="{'active bg-primary text-white shadow-lg shadow-primary/30': currentView === item.id, 'text-slate-400 hover:text-slate-100 hover:bg-slate-800': currentView !== item.id}"
|
||||||
|
class="rounded-lg font-medium transition-all py-3"
|
||||||
|
>
|
||||||
|
<i :class="['ph text-xl', item.icon, currentView === item.id ? 'ph-fill' : '']"></i>
|
||||||
|
{{ item.label }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="px-4 mb-4">
|
||||||
|
<div class="p-4 rounded-xl bg-gradient-to-br from-red-900/40 to-slate-900 border border-red-500/20 relative overflow-hidden group cursor-pointer hover:border-red-500/40 transition-all">
|
||||||
|
<div class="absolute -right-2 -top-2 w-16 h-16 bg-red-500/10 rounded-full blur-xl group-hover:bg-red-500/20 transition-all"></div>
|
||||||
|
<div class="flex items-center gap-2 text-red-400 mb-1">
|
||||||
|
<i class="ph-fill ph-warning-circle animate-pulse"></i>
|
||||||
|
<span class="text-xs font-bold uppercase tracking-wider">Intervention</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold text-white mb-1">3 <span class="text-sm font-normal text-slate-400">Waitings</span></div>
|
||||||
|
<div class="text-[10px] text-slate-500">人工接管队列 (异议/退费)</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
type NavItem = {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
icon: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
navItems: NavItem[];
|
||||||
|
currentView: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'select', id: string): void;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
128
247_Contry/src/views/index/components/StrategyView.vue
Normal file
128
247_Contry/src/views/index/components/StrategyView.vue
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
<template>
|
||||||
|
<div class="h-full flex flex-col gap-6">
|
||||||
|
<div class="flex justify-between items-end pb-2 border-b border-slate-800">
|
||||||
|
<div>
|
||||||
|
<h2 class="text-2xl font-bold text-white mb-1 flex items-center gap-2">
|
||||||
|
SOP 智能编排中心
|
||||||
|
<div class="badge badge-primary badge-outline text-xs">v2.4.0</div>
|
||||||
|
</h2>
|
||||||
|
<p class="text-slate-400 text-xs">配置全链路各阶段的模型参数、提示词及上下文逻辑。</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-3">
|
||||||
|
<button class="btn btn-neutral btn-sm border-slate-700 text-slate-300 hover:text-white"><i class="ph ph-clock-counter-clockwise"></i> 历史版本</button>
|
||||||
|
<button class="btn btn-primary btn-sm shadow-lg shadow-primary/20" @click="emit('saveConfig', $event)"><i class="ph ph-floppy-disk"></i> 发布策略配置</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-1 gap-6 overflow-hidden">
|
||||||
|
<div class="w-1/4 glass-panel rounded-2xl overflow-y-auto p-2 no-scrollbar">
|
||||||
|
<div class="px-4 py-3 text-xs font-bold text-slate-500 uppercase tracking-widest">Sales Pipeline</div>
|
||||||
|
<ul class="steps steps-vertical w-full gap-2">
|
||||||
|
<li
|
||||||
|
v-for="(stage, index) in salesStages"
|
||||||
|
:key="stage.id"
|
||||||
|
class="step cursor-pointer transition-all duration-300"
|
||||||
|
:class="currentStageId === stage.id ? 'step-primary' : 'step-neutral'"
|
||||||
|
@click="emit('update:currentStageId', stage.id)"
|
||||||
|
:data-content="index + 1"
|
||||||
|
>
|
||||||
|
<div class="w-full text-left ml-3 p-3 rounded-xl border transition-all duration-200 group"
|
||||||
|
:class="currentStageId === stage.id ? 'bg-primary/10 border-primary shadow-[0_0_15px_rgba(99,102,241,0.2)]' : 'bg-slate-900/50 border-slate-700/50 hover:bg-slate-800 hover:border-slate-600'">
|
||||||
|
<div class="font-bold text-sm text-slate-200 group-hover:text-white">{{ stage.name }}</div>
|
||||||
|
<div class="text-[10px] text-slate-500 mt-1 line-clamp-1 group-hover:text-slate-400">{{ stage.desc }}</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 glass-panel rounded-2xl p-6 flex flex-col gap-6 overflow-y-auto pr-4">
|
||||||
|
<div class="grid grid-cols-2 gap-6 p-4 bg-slate-900/50 rounded-xl border border-slate-800">
|
||||||
|
<div class="form-control w-full">
|
||||||
|
<label class="label pt-0"><span class="label-text font-bold text-slate-300 text-xs uppercase">Execution Model</span></label>
|
||||||
|
<select class="select select-bordered select-sm w-full bg-slate-950 border-slate-700 text-slate-200" v-model="currentConfig.model">
|
||||||
|
<option value="gpt-4-turbo">GPT-4 Turbo (高精度/逻辑强)</option>
|
||||||
|
<option value="deepseek-chat">DeepSeek V3 (高性价比/中文优)</option>
|
||||||
|
<option value="claude-3-opus">Claude 3 Opus (情感/共情强)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-control w-full">
|
||||||
|
<label class="label pt-0">
|
||||||
|
<span class="label-text font-bold text-slate-300 text-xs uppercase">Temperature: {{ currentConfig.temp }}</span>
|
||||||
|
<span class="label-text-alt text-[10px] text-slate-500">{{ currentConfig.temp > 0.7 ? '感性/发散' : '理性/收敛' }}</span>
|
||||||
|
</label>
|
||||||
|
<input type="range" min="0" max="1" step="0.1" v-model="currentConfig.temp" class="range range-xs range-primary" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 flex flex-col min-h-[400px]">
|
||||||
|
<div class="flex justify-between items-center mb-2">
|
||||||
|
<label class="label p-0"><span class="label-text font-bold text-slate-300 text-xs uppercase flex items-center gap-2"><i class="ph-fill ph-code"></i> System Prompt</span></label>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<div class="badge badge-outline badge-accent text-[10px] h-5">Jinja2 Supported</div>
|
||||||
|
<div class="badge badge-outline text-slate-500 text-[10px] h-5">{{ currentConfig.prompt.length }} chars</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="relative flex-1 rounded-xl overflow-hidden border border-slate-700/50 bg-[#0d1117] group focus-within:border-primary/50 transition-colors">
|
||||||
|
<div class="absolute left-0 top-0 bottom-0 w-8 bg-slate-900/50 border-r border-slate-800 flex flex-col items-end pt-4 pr-2 text-slate-600 font-mono text-xs select-none leading-relaxed">
|
||||||
|
<span v-for="n in 20" :key="n">{{n}}</span>
|
||||||
|
</div>
|
||||||
|
<textarea
|
||||||
|
v-model="currentConfig.prompt"
|
||||||
|
class="absolute inset-0 w-full h-full bg-transparent text-emerald-400 p-4 pl-10 font-mono text-sm resize-none focus:outline-none leading-relaxed selection:bg-emerald-900/50"
|
||||||
|
spellcheck="false"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="collapse collapse-arrow bg-slate-900/50 border border-slate-800 rounded-xl">
|
||||||
|
<input type="checkbox" />
|
||||||
|
<div class="collapse-title text-sm font-bold text-slate-300 flex items-center gap-2">
|
||||||
|
<i class="ph-fill ph-wrench text-accent"></i> Function Calling (Tools)
|
||||||
|
</div>
|
||||||
|
<div class="collapse-content">
|
||||||
|
<div class="flex flex-wrap gap-4 pt-2">
|
||||||
|
<label class="cursor-pointer flex items-center gap-2 p-2 rounded hover:bg-slate-800 border border-slate-700/50 hover:border-primary/50 transition-all">
|
||||||
|
<input type="checkbox" class="checkbox checkbox-primary checkbox-xs" checked />
|
||||||
|
<span class="label-text text-xs text-slate-300">CRM档案查询</span>
|
||||||
|
</label>
|
||||||
|
<label class="cursor-pointer flex items-center gap-2 p-2 rounded hover:bg-slate-800 border border-slate-700/50 hover:border-primary/50 transition-all">
|
||||||
|
<input type="checkbox" class="checkbox checkbox-primary checkbox-xs" />
|
||||||
|
<span class="label-text text-xs text-slate-300">生成个性化报告</span>
|
||||||
|
</label>
|
||||||
|
<label class="cursor-pointer flex items-center gap-2 p-2 rounded hover:bg-slate-800 border border-slate-700/50 hover:border-primary/50 transition-all">
|
||||||
|
<input type="checkbox" class="checkbox checkbox-primary checkbox-xs" checked />
|
||||||
|
<span class="label-text text-xs text-slate-300">知识库检索 (RAG)</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
type SalesStage = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
desc: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Config = {
|
||||||
|
model: string;
|
||||||
|
temp: number;
|
||||||
|
prompt: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
salesStages: SalesStage[];
|
||||||
|
currentStageId: string;
|
||||||
|
currentConfig: Config;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:currentStageId', id: string): void;
|
||||||
|
(e: 'saveConfig', event: Event): void;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
@@ -1,469 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="h-screen flex flex-col grid-bg text-slate-100 bg-slate-900 font-sans overflow-hidden">
|
<div class="h-screen flex flex-col grid-bg text-slate-100 bg-slate-900 font-sans overflow-hidden">
|
||||||
<!-- 1. 顶部导航 (Global Header) -->
|
<GlobalHeader />
|
||||||
<header class="h-16 glass-panel border-b-0 flex items-center justify-between px-6 z-50">
|
|
||||||
<!-- Logo -->
|
|
||||||
<div class="flex items-center gap-3">
|
|
||||||
<div class="w-9 h-9 rounded-xl bg-gradient-to-br from-primary to-accent flex items-center justify-center shadow-lg shadow-primary/20">
|
|
||||||
<i class="ph-bold ph-brain text-white text-xl"></i>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h1 class="font-bold text-lg tracking-wide leading-tight text-white">247<span class="text-primary">控制中台</span></h1>
|
|
||||||
<div class="text-[10px] text-slate-400 font-mono tracking-wider">SALES PILOT V1.0</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 全局状态栏 -->
|
|
||||||
<div class="flex items-center gap-6">
|
|
||||||
<!-- 流量潮汐指示器 (核心业务点) -->
|
|
||||||
<div class="flex items-center gap-3 px-4 py-1.5 rounded-full bg-slate-800/80 border border-slate-700/50 backdrop-blur-sm">
|
|
||||||
<div class="flex flex-col items-end leading-none">
|
|
||||||
<span class="text-[10px] text-slate-400">TRAFFIC TIDE</span>
|
|
||||||
<span class="text-xs font-bold text-green-400">LOAD: LOW</span>
|
|
||||||
</div>
|
|
||||||
<span class="relative flex h-3 w-3">
|
|
||||||
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
|
|
||||||
<span class="relative inline-flex rounded-full h-3 w-3 bg-green-500"></span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="divider divider-horizontal mx-0 h-8"></div>
|
|
||||||
|
|
||||||
<!-- 用户头像 -->
|
|
||||||
<div class="flex items-center gap-3">
|
|
||||||
<div class="text-right hidden sm:block">
|
|
||||||
<div class="text-xs font-bold text-slate-200">Admin User</div>
|
|
||||||
<div class="text-[10px] text-slate-500">Super Admin</div>
|
|
||||||
</div>
|
|
||||||
<div class="avatar placeholder cursor-pointer">
|
|
||||||
<div class="bg-gradient-to-tr from-slate-700 to-slate-600 text-white rounded-full w-9 ring ring-primary ring-offset-base-100 ring-offset-2">
|
|
||||||
<span class="text-xs">PM</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="flex flex-1 overflow-hidden">
|
<div class="flex flex-1 overflow-hidden">
|
||||||
<!-- 2. 侧边栏导航 (Sidebar) -->
|
<SidebarNav :nav-items="navItems" :current-view="currentView" @select="currentView = $event" />
|
||||||
<aside class="w-64 glass-panel border-t-0 border-l-0 border-b-0 flex flex-col justify-between py-6 z-40">
|
|
||||||
<ul class="menu w-full px-3 gap-2">
|
|
||||||
<li v-for="item in navItems" :key="item.id">
|
|
||||||
<a
|
|
||||||
@click="currentView = item.id"
|
|
||||||
:class="{'active bg-primary text-white shadow-lg shadow-primary/30': currentView === item.id, 'text-slate-400 hover:text-slate-100 hover:bg-slate-800': currentView !== item.id}"
|
|
||||||
class="rounded-lg font-medium transition-all py-3"
|
|
||||||
>
|
|
||||||
<i :class="['ph text-xl', item.icon, currentView === item.id ? 'ph-fill' : '']"></i>
|
|
||||||
{{ item.label }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<!-- 底部警告卡片 -->
|
|
||||||
<div class="px-4 mb-4">
|
|
||||||
<div class="p-4 rounded-xl bg-gradient-to-br from-red-900/40 to-slate-900 border border-red-500/20 relative overflow-hidden group cursor-pointer hover:border-red-500/40 transition-all">
|
|
||||||
<div class="absolute -right-2 -top-2 w-16 h-16 bg-red-500/10 rounded-full blur-xl group-hover:bg-red-500/20 transition-all"></div>
|
|
||||||
<div class="flex items-center gap-2 text-red-400 mb-1">
|
|
||||||
<i class="ph-fill ph-warning-circle animate-pulse"></i>
|
|
||||||
<span class="text-xs font-bold uppercase tracking-wider">Intervention</span>
|
|
||||||
</div>
|
|
||||||
<div class="text-2xl font-bold text-white mb-1">3 <span class="text-sm font-normal text-slate-400">Waitings</span></div>
|
|
||||||
<div class="text-[10px] text-slate-500">人工接管队列 (异议/退费)</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
<!-- 3. 主内容区域 (Main Content) -->
|
|
||||||
<main class="flex-1 overflow-hidden relative bg-slate-950/50 p-6">
|
<main class="flex-1 overflow-hidden relative bg-slate-950/50 p-6">
|
||||||
<transition name="fade" mode="out-in">
|
<transition name="fade" mode="out-in">
|
||||||
|
<DashboardView v-if="currentView === 'dashboard'" :funnel-data="funnelData" :traffic-data="trafficData" :event-logs="eventLogs" />
|
||||||
<!-- View A: 全景看板 (Dashboard) -->
|
<StrategyView v-else-if="currentView === 'strategy'" :sales-stages="salesStages" v-model:current-stage-id="currentStageId" :current-config="currentConfig" @saveConfig="saveConfig" />
|
||||||
<div v-if="currentView === 'dashboard'" class="h-full flex flex-col gap-6 overflow-y-auto pr-2">
|
<MonitorView v-else-if="currentView === 'monitor'" :active-users="activeUsers" :chat-history="chatHistory" :get-stage-badge="getStageBadge" @toggleManual="toggleManual" />
|
||||||
<!-- 核心指标卡片 -->
|
|
||||||
<div class="grid grid-cols-4 gap-6">
|
|
||||||
<div class="glass-panel rounded-2xl p-5 relative overflow-hidden group">
|
|
||||||
<div class="absolute right-0 top-0 p-4 opacity-10 group-hover:opacity-20 transition-opacity"><i class="ph-fill ph-currency-yen text-6xl text-primary"></i></div>
|
|
||||||
<div class="text-slate-400 text-xs font-bold tracking-wider uppercase mb-1">本周 GMV 预估</div>
|
|
||||||
<div class="text-3xl font-bold text-white mb-2">¥245,600</div>
|
|
||||||
<div class="flex items-center gap-2 text-xs">
|
|
||||||
<span class="text-emerald-400 bg-emerald-400/10 px-1.5 py-0.5 rounded flex items-center gap-1"><i class="ph-bold ph-trend-up"></i> 1.2%</span>
|
|
||||||
<span class="text-slate-500">转化率 (目标 1%)</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="glass-panel rounded-2xl p-5 relative overflow-hidden group">
|
|
||||||
<div class="absolute right-0 top-0 p-4 opacity-10 group-hover:opacity-20 transition-opacity"><i class="ph-fill ph-users-three text-6xl text-secondary"></i></div>
|
|
||||||
<div class="text-slate-400 text-xs font-bold tracking-wider uppercase mb-1">当前并发接待</div>
|
|
||||||
<div class="text-3xl font-bold text-white mb-2">842 <span class="text-sm font-normal text-slate-500">人</span></div>
|
|
||||||
<div class="flex items-center gap-2 text-xs">
|
|
||||||
<span class="text-secondary bg-secondary/10 px-1.5 py-0.5 rounded">AI 负载: 42%</span>
|
|
||||||
<span class="text-slate-500">系统健康</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="glass-panel rounded-2xl p-5 relative overflow-hidden group">
|
|
||||||
<div class="absolute right-0 top-0 p-4 opacity-10 group-hover:opacity-20 transition-opacity"><i class="ph-fill ph-robot text-6xl text-accent"></i></div>
|
|
||||||
<div class="text-slate-400 text-xs font-bold tracking-wider uppercase mb-1">节省人力折算</div>
|
|
||||||
<div class="text-3xl font-bold text-white mb-2">34.5 <span class="text-sm font-normal text-slate-500">人/天</span></div>
|
|
||||||
<div class="flex items-center gap-2 text-xs">
|
|
||||||
<span class="text-accent bg-accent/10 px-1.5 py-0.5 rounded">≈ 4个销售组</span>
|
|
||||||
<span class="text-slate-500">效能提升</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="glass-panel rounded-2xl p-5 relative overflow-hidden group">
|
|
||||||
<div class="absolute right-0 top-0 p-4 opacity-10 group-hover:opacity-20 transition-opacity"><i class="ph-fill ph-warning-octagon text-6xl text-error"></i></div>
|
|
||||||
<div class="text-slate-400 text-xs font-bold tracking-wider uppercase mb-1">人工干预率</div>
|
|
||||||
<div class="text-3xl font-bold text-white mb-2">4.8%</div>
|
|
||||||
<div class="flex items-center gap-2 text-xs">
|
|
||||||
<span class="text-error bg-error/10 px-1.5 py-0.5 rounded">异议/退费</span>
|
|
||||||
<span class="text-slate-500">主要原因</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 漏斗与流量图表 -->
|
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 h-[420px]">
|
|
||||||
<!-- 左侧:销售漏斗 -->
|
|
||||||
<div class="lg:col-span-1 glass-panel rounded-2xl p-6 flex flex-col">
|
|
||||||
<div class="flex justify-between items-center mb-6">
|
|
||||||
<h3 class="font-bold text-white flex items-center gap-2"><i class="ph-fill ph-funnel text-primary"></i> 销售漏斗监控</h3>
|
|
||||||
<button class="btn btn-xs btn-ghost text-slate-400"><i class="ph-bold ph-dots-three"></i></button>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1 flex flex-col justify-center gap-4">
|
|
||||||
<div v-for="(item, index) in funnelData" :key="index" class="relative group cursor-default">
|
|
||||||
<div class="flex justify-between text-xs mb-1.5">
|
|
||||||
<span class="text-slate-300 font-medium">{{ item.stage }}</span>
|
|
||||||
<span class="text-slate-400 font-mono">{{ item.count }} <span class="opacity-50">/</span> <span :class="item.rate < 10 ? 'text-primary' : 'text-slate-400'">{{ item.rate }}%</span></span>
|
|
||||||
</div>
|
|
||||||
<div class="w-full bg-slate-800/50 rounded-full h-2.5 overflow-hidden border border-slate-700/50">
|
|
||||||
<div
|
|
||||||
class="h-full rounded-full transition-all duration-1000 relative overflow-hidden"
|
|
||||||
:class="index > 4 ? 'bg-gradient-to-r from-primary to-accent' : 'bg-slate-600'"
|
|
||||||
:style="{ width: item.rate + '%' }"
|
|
||||||
>
|
|
||||||
<div class="absolute inset-0 bg-white/20 w-full h-full animate-[shimmer_2s_infinite] translate-x-[-100%]" v-if="index > 4"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 右侧:流量潮汐监控 (CSS Chart) -->
|
|
||||||
<div class="lg:col-span-2 glass-panel rounded-2xl p-6 flex flex-col relative overflow-hidden">
|
|
||||||
<div class="flex justify-between items-start mb-4 z-10">
|
|
||||||
<div>
|
|
||||||
<h3 class="font-bold text-white flex items-center gap-2">
|
|
||||||
<i class="ph-fill ph-waves text-blue-400"></i> 流量潮汐实时监控
|
|
||||||
</h3>
|
|
||||||
<p class="text-xs text-slate-500 mt-1">洋葱模型预测:当前处于爬坡期,预计 20:00 达到峰值</p>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<div class="badge badge-primary badge-outline text-xs gap-1"><i class="ph-bold ph-lightning"></i> AI 响应: 1.2s</div>
|
|
||||||
<div class="badge badge-secondary badge-outline text-xs gap-1"><i class="ph-bold ph-coin"></i> Token: $14.2/h</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 动态柱状图 -->
|
|
||||||
<div class="flex-1 flex items-end justify-between gap-1 z-10 px-1 pt-4 border-b border-slate-700/50">
|
|
||||||
<div v-for="(h, i) in trafficData" :key="i"
|
|
||||||
class="w-full bg-blue-500/20 rounded-t-sm hover:bg-blue-500/60 transition-all duration-300 relative group"
|
|
||||||
:style="{ height: h + '%' }">
|
|
||||||
<!-- Hover Tooltip -->
|
|
||||||
<div class="absolute -top-10 left-1/2 -translate-x-1/2 bg-slate-800 text-white text-[10px] px-2 py-1 rounded border border-slate-600 opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none whitespace-nowrap z-20 shadow-xl">
|
|
||||||
QPS: {{ Math.round(h * 3.5) }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- 底部时间轴 -->
|
|
||||||
<div class="flex justify-between text-[10px] text-slate-600 font-mono mt-2 z-10">
|
|
||||||
<span>14:00</span>
|
|
||||||
<span>14:15</span>
|
|
||||||
<span>14:30</span>
|
|
||||||
<span>14:45</span>
|
|
||||||
<span>15:00</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 背景装饰 -->
|
|
||||||
<div class="absolute inset-0 z-0 bg-gradient-to-t from-blue-500/5 to-transparent pointer-events-none"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 底部日志 -->
|
|
||||||
<div class="glass-panel rounded-2xl p-6 flex-1 min-h-[300px]">
|
|
||||||
<div class="flex justify-between items-center mb-4">
|
|
||||||
<h3 class="font-bold text-white flex items-center gap-2"><i class="ph-fill ph-list-dashes text-slate-400"></i> 系统事件日志</h3>
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<span class="loading loading-dots loading-xs text-slate-500"></span>
|
|
||||||
<span class="text-xs text-slate-500 font-mono">LIVE</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="overflow-x-auto">
|
|
||||||
<table class="table table-xs table-pin-rows">
|
|
||||||
<thead>
|
|
||||||
<tr class="text-slate-500 border-b border-slate-700/50">
|
|
||||||
<th>TIMESTAMP</th>
|
|
||||||
<th>EVENT TYPE</th>
|
|
||||||
<th>CUSTOMER</th>
|
|
||||||
<th>AI DECISION & ACTION</th>
|
|
||||||
<th>STATUS</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody class="font-mono">
|
|
||||||
<tr v-for="log in eventLogs" :key="log.id" class="hover:bg-slate-800/30 transition-colors border-slate-800/30 group">
|
|
||||||
<td class="text-slate-500">{{ log.time }}</td>
|
|
||||||
<td>
|
|
||||||
<span class="badge badge-ghost badge-xs gap-1 border-slate-700 text-slate-300">
|
|
||||||
{{ log.type }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td class="font-medium text-slate-300">{{ log.user }}</td>
|
|
||||||
<td class="max-w-md truncate text-slate-400 group-hover:text-slate-200 transition-colors">
|
|
||||||
<span class="text-primary mr-2">[{{log.model}}]</span>
|
|
||||||
{{ log.action }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span v-if="log.status === 'success'" class="text-emerald-400 flex items-center gap-1"><i class="ph-fill ph-check-circle"></i> OK</span>
|
|
||||||
<span v-else-if="log.status === 'warning'" class="text-orange-400 flex items-center gap-1"><i class="ph-fill ph-warning"></i> MANUAL</span>
|
|
||||||
<span v-else class="text-blue-400 flex items-center gap-1"><i class="ph-bold ph-spinner animate-spin"></i> RUNNING</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- View B: SOP 编排中心 (Strategy) -->
|
|
||||||
<div v-else-if="currentView === 'strategy'" class="h-full flex flex-col gap-6">
|
|
||||||
<!-- 头部工具栏 -->
|
|
||||||
<div class="flex justify-between items-end pb-2 border-b border-slate-800">
|
|
||||||
<div>
|
|
||||||
<h2 class="text-2xl font-bold text-white mb-1 flex items-center gap-2">
|
|
||||||
SOP 智能编排中心
|
|
||||||
<div class="badge badge-primary badge-outline text-xs">v2.4.0</div>
|
|
||||||
</h2>
|
|
||||||
<p class="text-slate-400 text-xs">配置全链路各阶段的模型参数、提示词及上下文逻辑。</p>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-3">
|
|
||||||
<button class="btn btn-neutral btn-sm border-slate-700 text-slate-300 hover:text-white"><i class="ph ph-clock-counter-clockwise"></i> 历史版本</button>
|
|
||||||
<button class="btn btn-primary btn-sm shadow-lg shadow-primary/20" @click="saveConfig"><i class="ph ph-floppy-disk"></i> 发布策略配置</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-1 gap-6 overflow-hidden">
|
|
||||||
<!-- 左侧:阶段选择器 -->
|
|
||||||
<div class="w-1/4 glass-panel rounded-2xl overflow-y-auto p-2 no-scrollbar">
|
|
||||||
<div class="px-4 py-3 text-xs font-bold text-slate-500 uppercase tracking-widest">Sales Pipeline</div>
|
|
||||||
<ul class="steps steps-vertical w-full gap-2">
|
|
||||||
<li
|
|
||||||
v-for="(stage, index) in salesStages"
|
|
||||||
:key="stage.id"
|
|
||||||
class="step cursor-pointer transition-all duration-300"
|
|
||||||
:class="currentStageId === stage.id ? 'step-primary' : 'step-neutral'"
|
|
||||||
@click="currentStageId = stage.id"
|
|
||||||
:data-content="index + 1"
|
|
||||||
>
|
|
||||||
<div class="w-full text-left ml-3 p-3 rounded-xl border transition-all duration-200 group"
|
|
||||||
:class="currentStageId === stage.id ? 'bg-primary/10 border-primary shadow-[0_0_15px_rgba(99,102,241,0.2)]' : 'bg-slate-900/50 border-slate-700/50 hover:bg-slate-800 hover:border-slate-600'">
|
|
||||||
<div class="font-bold text-sm text-slate-200 group-hover:text-white">{{ stage.name }}</div>
|
|
||||||
<div class="text-[10px] text-slate-500 mt-1 line-clamp-1 group-hover:text-slate-400">{{ stage.desc }}</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 右侧:Prompt 编辑器 -->
|
|
||||||
<div class="flex-1 glass-panel rounded-2xl p-6 flex flex-col gap-6 overflow-y-auto pr-4">
|
|
||||||
<!-- 模型参数配置 -->
|
|
||||||
<div class="grid grid-cols-2 gap-6 p-4 bg-slate-900/50 rounded-xl border border-slate-800">
|
|
||||||
<div class="form-control w-full">
|
|
||||||
<label class="label pt-0"><span class="label-text font-bold text-slate-300 text-xs uppercase">Execution Model</span></label>
|
|
||||||
<select class="select select-bordered select-sm w-full bg-slate-950 border-slate-700 text-slate-200" v-model="currentConfig.model">
|
|
||||||
<option value="gpt-4-turbo">GPT-4 Turbo (高精度/逻辑强)</option>
|
|
||||||
<option value="deepseek-chat">DeepSeek V3 (高性价比/中文优)</option>
|
|
||||||
<option value="claude-3-opus">Claude 3 Opus (情感/共情强)</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-control w-full">
|
|
||||||
<label class="label pt-0">
|
|
||||||
<span class="label-text font-bold text-slate-300 text-xs uppercase">Temperature: {{ currentConfig.temp }}</span>
|
|
||||||
<span class="label-text-alt text-[10px] text-slate-500">{{ currentConfig.temp > 0.7 ? '感性/发散' : '理性/收敛' }}</span>
|
|
||||||
</label>
|
|
||||||
<input type="range" min="0" max="1" step="0.1" v-model="currentConfig.temp" class="range range-xs range-primary" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 代码编辑器 -->
|
|
||||||
<div class="flex-1 flex flex-col min-h-[400px]">
|
|
||||||
<div class="flex justify-between items-center mb-2">
|
|
||||||
<label class="label p-0"><span class="label-text font-bold text-slate-300 text-xs uppercase flex items-center gap-2"><i class="ph-fill ph-code"></i> System Prompt</span></label>
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<div class="badge badge-outline badge-accent text-[10px] h-5">Jinja2 Supported</div>
|
|
||||||
<div class="badge badge-outline text-slate-500 text-[10px] h-5">{{ currentConfig.prompt.length }} chars</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="relative flex-1 rounded-xl overflow-hidden border border-slate-700/50 bg-[#0d1117] group focus-within:border-primary/50 transition-colors">
|
|
||||||
<!-- 简单的行号模拟 -->
|
|
||||||
<div class="absolute left-0 top-0 bottom-0 w-8 bg-slate-900/50 border-r border-slate-800 flex flex-col items-end pt-4 pr-2 text-slate-600 font-mono text-xs select-none leading-relaxed">
|
|
||||||
<span v-for="n in 20" :key="n">{{n}}</span>
|
|
||||||
</div>
|
|
||||||
<textarea
|
|
||||||
v-model="currentConfig.prompt"
|
|
||||||
class="absolute inset-0 w-full h-full bg-transparent text-emerald-400 p-4 pl-10 font-mono text-sm resize-none focus:outline-none leading-relaxed selection:bg-emerald-900/50"
|
|
||||||
spellcheck="false"
|
|
||||||
></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 工具挂载 -->
|
|
||||||
<div class="collapse collapse-arrow bg-slate-900/50 border border-slate-800 rounded-xl">
|
|
||||||
<input type="checkbox" />
|
|
||||||
<div class="collapse-title text-sm font-bold text-slate-300 flex items-center gap-2">
|
|
||||||
<i class="ph-fill ph-wrench text-accent"></i> Function Calling (Tools)
|
|
||||||
</div>
|
|
||||||
<div class="collapse-content">
|
|
||||||
<div class="flex flex-wrap gap-4 pt-2">
|
|
||||||
<label class="cursor-pointer flex items-center gap-2 p-2 rounded hover:bg-slate-800 border border-slate-700/50 hover:border-primary/50 transition-all">
|
|
||||||
<input type="checkbox" class="checkbox checkbox-primary checkbox-xs" checked />
|
|
||||||
<span class="label-text text-xs text-slate-300">CRM档案查询</span>
|
|
||||||
</label>
|
|
||||||
<label class="cursor-pointer flex items-center gap-2 p-2 rounded hover:bg-slate-800 border border-slate-700/50 hover:border-primary/50 transition-all">
|
|
||||||
<input type="checkbox" class="checkbox checkbox-primary checkbox-xs" />
|
|
||||||
<span class="label-text text-xs text-slate-300">生成个性化报告</span>
|
|
||||||
</label>
|
|
||||||
<label class="cursor-pointer flex items-center gap-2 p-2 rounded hover:bg-slate-800 border border-slate-700/50 hover:border-primary/50 transition-all">
|
|
||||||
<input type="checkbox" class="checkbox checkbox-primary checkbox-xs" checked />
|
|
||||||
<span class="label-text text-xs text-slate-300">知识库检索 (RAG)</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- View C: 会话监控 (Monitor) -->
|
|
||||||
<div v-else-if="currentView === 'monitor'" class="h-full flex gap-6">
|
|
||||||
<!-- 用户列表 -->
|
|
||||||
<div class="w-80 glass-panel rounded-2xl flex flex-col overflow-hidden">
|
|
||||||
<div class="p-4 border-b border-slate-700/50 bg-slate-900/30">
|
|
||||||
<h3 class="font-bold text-white text-sm mb-3">实时活跃会话</h3>
|
|
||||||
<div class="relative">
|
|
||||||
<i class="ph ph-magnifying-glass absolute left-3 top-2.5 text-slate-500"></i>
|
|
||||||
<input class="input input-sm w-full bg-slate-950 border-slate-700 pl-9 text-xs focus:border-primary" placeholder="搜索家长姓名/ID..." />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1 overflow-y-auto p-2 space-y-2">
|
|
||||||
<div v-for="user in activeUsers" :key="user.id"
|
|
||||||
class="p-3 rounded-xl cursor-pointer transition-all border border-transparent hover:border-slate-700"
|
|
||||||
:class="user.active ? 'bg-primary/10 border-primary/30' : 'bg-slate-800/30 hover:bg-slate-800/80'"
|
|
||||||
>
|
|
||||||
<div class="flex justify-between items-start mb-1">
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<div class="w-2 h-2 rounded-full" :class="user.risk ? 'bg-red-500 animate-pulse' : 'bg-green-500'"></div>
|
|
||||||
<span class="font-bold text-sm text-slate-200">{{ user.name }}</span>
|
|
||||||
</div>
|
|
||||||
<span class="text-[10px] text-slate-500">{{ user.time }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="text-xs text-slate-400 truncate mb-2">{{ user.lastMsg }}</div>
|
|
||||||
<div class="flex flex-wrap gap-1">
|
|
||||||
<div class="badge badge-xs border-0 text-white" :class="getStageBadge(user.stage)">{{ user.stage }}</div>
|
|
||||||
<div v-if="user.risk" class="badge badge-xs badge-error gap-1"><i class="ph-bold ph-warning"></i> 需人工</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 聊天窗口 -->
|
|
||||||
<div class="flex-1 flex flex-col glass-panel rounded-2xl overflow-hidden relative">
|
|
||||||
<!-- Chat Header -->
|
|
||||||
<div class="h-16 border-b border-slate-700/50 flex justify-between items-center px-6 bg-slate-900/50 backdrop-blur-md z-10">
|
|
||||||
<div>
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<span class="font-bold text-lg text-white">王梓涵妈妈</span>
|
|
||||||
<div class="badge badge-primary badge-outline badge-xs">ID: 883921</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center gap-2 mt-0.5">
|
|
||||||
<span class="relative flex h-2 w-2">
|
|
||||||
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
|
|
||||||
<span class="relative inline-flex rounded-full h-2 w-2 bg-green-500"></span>
|
|
||||||
</span>
|
|
||||||
<span class="text-xs text-slate-400">AI 托管中 | 策略模型: Claude-3 Opus</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<button class="btn btn-error btn-xs" @click="toggleManual">
|
|
||||||
<i class="ph-bold ph-hand-palm"></i> 强制接管
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-neutral btn-xs border-slate-600">
|
|
||||||
<i class="ph ph-file-text"></i> 画像
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Chat Content -->
|
|
||||||
<div class="flex-1 p-4 sm:p-6 overflow-y-auto space-y-8 bg-slate-950/50" ref="chatBox">
|
|
||||||
<div v-for="msg in chatHistory" :key="msg.id" class="flex gap-4 group" :class="msg.role === 'user' ? 'flex-row-reverse' : ''">
|
|
||||||
|
|
||||||
<!-- Avatar -->
|
|
||||||
<div class="flex-shrink-0 mt-1">
|
|
||||||
<div class="w-9 h-9 rounded-full border border-slate-700/50 p-1 flex items-center justify-center shadow-lg transition-transform group-hover:scale-105"
|
|
||||||
:class="msg.role === 'ai' ? 'bg-indigo-600' : 'bg-slate-800'">
|
|
||||||
<i v-if="msg.role === 'ai'" class="ph-bold ph-robot text-lg text-white"></i>
|
|
||||||
<i v-else class="ph-bold ph-user text-lg text-white"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Message Body -->
|
|
||||||
<div class="flex flex-col max-w-[85%] sm:max-w-[75%]" :class="msg.role === 'user' ? 'items-end' : 'items-start'">
|
|
||||||
|
|
||||||
<!-- Header -->
|
|
||||||
<div class="flex items-center gap-2 mb-1.5 text-[10px] text-slate-500">
|
|
||||||
<span class="font-bold text-slate-400">{{ msg.role === 'ai' ? 'Nexus AI Agent' : '家长' }}</span>
|
|
||||||
<time class="opacity-50 font-mono">{{ msg.time }}</time>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Thought Chain (AI Only) -->
|
|
||||||
<div v-if="msg.role === 'ai' && msg.thought" class="mb-3 w-full animate-in fade-in slide-in-from-top-2 duration-500">
|
|
||||||
<div class="p-3 bg-yellow-500/5 border border-yellow-700/20 rounded-lg text-xs text-yellow-500/80 font-mono shadow-sm relative overflow-hidden">
|
|
||||||
<div class="absolute left-0 top-0 bottom-0 w-0.5 bg-yellow-600/40"></div>
|
|
||||||
<div class="flex items-center gap-1.5 mb-1.5 opacity-90 font-bold uppercase tracking-wider text-[9px]">
|
|
||||||
<i class="ph-bold ph-cpu"></i> 决策链路: {{ msg.stage }}
|
|
||||||
</div>
|
|
||||||
<div class="leading-relaxed opacity-80 break-words whitespace-pre-wrap">> {{ msg.thought }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Bubble -->
|
|
||||||
<div class="p-3.5 rounded-2xl shadow-xl text-sm leading-relaxed break-words relative group-hover:shadow-2xl transition-shadow"
|
|
||||||
:class="msg.role === 'ai'
|
|
||||||
? 'bg-indigo-600 text-white rounded-tl-sm'
|
|
||||||
: 'bg-slate-800 text-slate-200 rounded-tr-sm'">
|
|
||||||
{{ msg.content }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Footer (AI Only) -->
|
|
||||||
<div v-if="msg.role === 'ai'" class="mt-1.5 flex items-center gap-3 text-[9px] text-slate-600 font-mono opacity-0 group-hover:opacity-100 transition-opacity">
|
|
||||||
<span class="flex items-center gap-1"><i class="ph-bold ph-lightning"></i> Claude-3 Opus</span>
|
|
||||||
<span class="flex items-center gap-1"><i class="ph-bold ph-clock"></i> 420ms</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Input Area -->
|
|
||||||
<div class="p-4 bg-slate-900 border-t border-slate-700/50">
|
|
||||||
<div class="relative">
|
|
||||||
<input type="text" placeholder="输入内容以进行人工干预 (AI 将暂停响应)..." class="input input-bordered w-full bg-slate-950 border-slate-700 focus:border-primary pr-12 text-sm" />
|
|
||||||
<button class="absolute right-1 top-1 btn btn-sm btn-primary rounded-lg aspect-square p-0"><i class="ph-bold ph-paper-plane-right text-lg"></i></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</transition>
|
</transition>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
@@ -472,6 +18,11 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
|
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
|
||||||
|
import GlobalHeader from './components/GlobalHeader.vue';
|
||||||
|
import SidebarNav from './components/SidebarNav.vue';
|
||||||
|
import DashboardView from './components/DashboardView.vue';
|
||||||
|
import StrategyView from './components/StrategyView.vue';
|
||||||
|
import MonitorView from './components/MonitorView.vue';
|
||||||
|
|
||||||
const currentView = ref('dashboard');
|
const currentView = ref('dashboard');
|
||||||
|
|
||||||
@@ -508,6 +59,15 @@ interface Config {
|
|||||||
prompt: string;
|
prompt: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ChatMessage {
|
||||||
|
id: number;
|
||||||
|
role: 'ai' | 'user';
|
||||||
|
content: string;
|
||||||
|
time: string;
|
||||||
|
stage: string;
|
||||||
|
thought: string;
|
||||||
|
}
|
||||||
|
|
||||||
const configs = ref<Record<string, Config>>({
|
const configs = ref<Record<string, Config>>({
|
||||||
'deep_connect': {
|
'deep_connect': {
|
||||||
model: 'claude-3-opus',
|
model: 'claude-3-opus',
|
||||||
@@ -548,7 +108,7 @@ const currentConfig = computed((): Config => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 3. 聊天记录 Mock
|
// 3. 聊天记录 Mock
|
||||||
const chatHistory = ref([
|
const chatHistory = ref<ChatMessage[]>([
|
||||||
{ id: 1, role: 'user', content: '孩子最近回家都不说话,一问成绩就发脾气,我真的不知道该怎么办了...', time: '10:23 AM', stage: '', thought: '' },
|
{ id: 1, role: 'user', content: '孩子最近回家都不说话,一问成绩就发脾气,我真的不知道该怎么办了...', time: '10:23 AM', stage: '', thought: '' },
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
|
|||||||
Reference in New Issue
Block a user