feat(web): update Vue components and composables
- PersonalWorkbench.vue: update personal workbench component - useAppShell.js: update app shell composable - useChat.js: update chat composable with new features - AppShellRouteView.vue: update route view - ChatView.vue: update chat view with enhanced UI - TravelReimbursementCreateView.vue: update travel reimbursement form - ChatView.js: update chat view script logic - TravelReimbursementCreateView.js: update travel form script logic
This commit is contained in:
@@ -53,6 +53,51 @@
|
||||
</header>
|
||||
<p>{{ message.text }}</p>
|
||||
|
||||
<div v-if="message.role === 'assistant' && message.meta?.length" class="message-meta-row">
|
||||
<span v-for="item in message.meta" :key="item" class="message-meta-chip">{{ item }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="message.role === 'assistant' && message.riskFlags?.length" class="message-detail-block">
|
||||
<strong>风险标签</strong>
|
||||
<div class="message-detail-chip-row">
|
||||
<span v-for="item in message.riskFlags" :key="item" class="message-risk-chip">{{ item }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="message.role === 'assistant' && message.citations?.length" class="message-detail-block">
|
||||
<strong>引用依据</strong>
|
||||
<div class="message-citation-list">
|
||||
<article v-for="item in message.citations" :key="`${message.id}-${item.code}`" class="message-citation-card">
|
||||
<header>
|
||||
<span>{{ item.title }}</span>
|
||||
<small>{{ item.version || item.source_type }}</small>
|
||||
</header>
|
||||
<p>{{ item.excerpt || item.code }}</p>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="message.role === 'assistant' && message.suggestedActions?.length" class="message-detail-block">
|
||||
<strong>建议动作</strong>
|
||||
<div class="message-detail-chip-row">
|
||||
<span
|
||||
v-for="item in message.suggestedActions"
|
||||
:key="`${message.id}-${item.action_type}-${item.label}`"
|
||||
class="message-action-chip"
|
||||
>
|
||||
{{ item.label }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="message.role === 'assistant' && message.draftPayload" class="draft-preview">
|
||||
<header>
|
||||
<strong>{{ message.draftPayload.title }}</strong>
|
||||
<span>待人工确认</span>
|
||||
</header>
|
||||
<pre>{{ message.draftPayload.body }}</pre>
|
||||
</div>
|
||||
|
||||
<div v-if="message.attachments?.length" class="message-files">
|
||||
<span v-for="file in message.attachments" :key="file" class="file-chip">
|
||||
<i class="mdi mdi-paperclip"></i>
|
||||
@@ -78,6 +123,7 @@
|
||||
v-model="composerDraft"
|
||||
rows="3"
|
||||
:placeholder="composerPlaceholder"
|
||||
:disabled="submitting"
|
||||
@keydown.ctrl.enter.prevent="submitComposer"
|
||||
/>
|
||||
|
||||
@@ -90,14 +136,14 @@
|
||||
|
||||
<div class="composer-foot">
|
||||
<div class="composer-tools">
|
||||
<button type="button" class="tool-btn" aria-label="上传附件" @click="triggerFileUpload">
|
||||
<button type="button" class="tool-btn" :disabled="submitting" aria-label="上传附件" @click="triggerFileUpload">
|
||||
<i class="mdi mdi-paperclip"></i>
|
||||
</button>
|
||||
<span class="composer-tip">Ctrl + Enter 发送</span>
|
||||
</div>
|
||||
|
||||
<button class="send-btn" type="submit" :disabled="!canSubmit" aria-label="发送">
|
||||
<i class="mdi mdi-send"></i>
|
||||
<i :class="submitting ? 'mdi mdi-loading mdi-spin' : 'mdi mdi-send'"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -114,213 +160,132 @@
|
||||
</div>
|
||||
|
||||
<div class="confidence-card">
|
||||
<span>意图识别</span>
|
||||
<strong>{{ currentInsight.confidence }}%</strong>
|
||||
<span>{{ currentInsight.metricLabel }}</span>
|
||||
<strong>{{ currentInsight.metricValue }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Transition name="insight-switch" mode="out-in">
|
||||
<div :key="currentInsight.intent + currentInsight.title" class="insight-body">
|
||||
<template v-if="currentInsight.intent === 'approval'">
|
||||
<template v-if="currentInsight.intent === 'agent' && currentInsight.agent">
|
||||
<section class="insight-card primary">
|
||||
<div class="card-head">
|
||||
<h4>审批状态</h4>
|
||||
<span class="status-pill warning">{{ currentInsight.status.currentStatus }}</span>
|
||||
<h4>调度结果</h4>
|
||||
<span class="status-pill" :class="currentInsight.agent.statusTone">{{ currentInsight.agent.statusLabel }}</span>
|
||||
</div>
|
||||
<div class="metric-grid">
|
||||
<div class="metric-item">
|
||||
<span>单号</span>
|
||||
<strong>{{ currentInsight.status.requestId }}</strong>
|
||||
<span>运行 ID</span>
|
||||
<strong>{{ currentInsight.agent.runId }}</strong>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span>当前节点</span>
|
||||
<strong>{{ currentInsight.status.currentNode }}</strong>
|
||||
<span>执行 Agent</span>
|
||||
<strong>{{ currentInsight.agent.selectedAgent }}</strong>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span>下一处理人</span>
|
||||
<strong>{{ currentInsight.status.nextOwner }}</strong>
|
||||
<span>场景 / 意图</span>
|
||||
<strong>{{ currentInsight.agent.scenario }} / {{ currentInsight.agent.intent }}</strong>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span>预计完成</span>
|
||||
<strong>{{ currentInsight.status.eta }}</strong>
|
||||
<span>权限</span>
|
||||
<strong>{{ currentInsight.agent.permissionLevel }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="insight-card">
|
||||
<div class="card-head">
|
||||
<h4>流程节点</h4>
|
||||
<h4>运行明细</h4>
|
||||
</div>
|
||||
<div class="metric-grid">
|
||||
<div class="metric-item">
|
||||
<span>路由原因</span>
|
||||
<strong>{{ currentInsight.agent.routeReason }}</strong>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span>工具调用</span>
|
||||
<strong>{{ currentInsight.agent.toolCount }} / 失败 {{ currentInsight.agent.failedToolCount }}</strong>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span>确认要求</span>
|
||||
<strong>{{ currentInsight.agent.requiresConfirmation ? '需要人工确认' : '无需确认' }}</strong>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span>降级状态</span>
|
||||
<strong>{{ currentInsight.agent.degraded ? '已降级' : '正常' }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<ol class="timeline-list">
|
||||
<li
|
||||
v-for="step in currentInsight.status.timeline"
|
||||
:key="step.label"
|
||||
:class="step.state"
|
||||
>
|
||||
<span class="timeline-dot"></span>
|
||||
<div>
|
||||
<strong>{{ step.label }}</strong>
|
||||
<p>{{ step.time }}</p>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<section class="insight-card">
|
||||
<section v-if="currentInsight.agent.selectedCapabilityCodes?.length" class="insight-card">
|
||||
<div class="card-head">
|
||||
<h4>待处理提醒</h4>
|
||||
<h4>命中能力</h4>
|
||||
</div>
|
||||
<div class="capability-chip-row">
|
||||
<span v-for="item in currentInsight.agent.selectedCapabilityCodes" :key="item" class="capability-chip">
|
||||
{{ item }}
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section v-if="currentInsight.agent.fileNames?.length" class="insight-card">
|
||||
<div class="card-head">
|
||||
<h4>附件上下文</h4>
|
||||
</div>
|
||||
<ul class="bullet-list">
|
||||
<li v-for="item in currentInsight.status.actions" :key="item">{{ item }}</li>
|
||||
<li>本次对话已带入 {{ currentInsight.agent.fileNames.length }} 份附件名称。</li>
|
||||
<li v-for="item in currentInsight.agent.fileNames" :key="item">{{ item }}</li>
|
||||
</ul>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<template v-else-if="currentInsight.intent === 'recognition'">
|
||||
<section class="insight-card primary">
|
||||
<section v-if="currentInsight.agent.riskFlags?.length" class="insight-card">
|
||||
<div class="card-head">
|
||||
<h4>识别结果</h4>
|
||||
<span class="status-pill success">{{ currentInsight.recognition.state }}</span>
|
||||
<h4>风险标签</h4>
|
||||
</div>
|
||||
<div class="metric-grid">
|
||||
<div class="metric-item">
|
||||
<span>关联单号</span>
|
||||
<strong>{{ currentInsight.recognition.requestId }}</strong>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span>识别附件</span>
|
||||
<strong>{{ currentInsight.recognition.fileCount }} 份</strong>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span>建议金额</span>
|
||||
<strong>{{ currentInsight.recognition.amount }}</strong>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span>完整度</span>
|
||||
<strong>{{ currentInsight.recognition.completeness }}</strong>
|
||||
</div>
|
||||
<div class="capability-chip-row">
|
||||
<span v-for="item in currentInsight.agent.riskFlags" :key="item" class="risk-chip">{{ item }}</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="insight-card">
|
||||
<section v-if="currentInsight.agent.citations?.length" class="insight-card">
|
||||
<div class="card-head">
|
||||
<h4>票据明细</h4>
|
||||
<h4>引用依据</h4>
|
||||
</div>
|
||||
<div class="receipt-list">
|
||||
<article v-for="item in currentInsight.recognition.receipts" :key="item.name" class="receipt-row">
|
||||
<div class="citation-stack">
|
||||
<article v-for="item in currentInsight.agent.citations" :key="item.code" class="citation-card">
|
||||
<header>
|
||||
<strong>{{ item.title }}</strong>
|
||||
<span>{{ item.version || item.source_type }}</span>
|
||||
</header>
|
||||
<p>{{ item.excerpt || item.code }}</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section v-if="currentInsight.agent.suggestedActions?.length" class="insight-card">
|
||||
<div class="card-head">
|
||||
<h4>建议动作</h4>
|
||||
</div>
|
||||
<div class="action-list">
|
||||
<article v-for="item in currentInsight.agent.suggestedActions" :key="item.label" class="action-card">
|
||||
<div>
|
||||
<strong>{{ item.name }}</strong>
|
||||
<p>{{ item.type }}</p>
|
||||
</div>
|
||||
<div class="receipt-side">
|
||||
<strong>{{ item.amount }}</strong>
|
||||
<span>{{ item.confidence }}</span>
|
||||
<strong>{{ item.label }}</strong>
|
||||
<p>{{ item.description || item.action_type }}</p>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="insight-card">
|
||||
<section v-if="currentInsight.agent.draftPayload" class="insight-card">
|
||||
<div class="card-head">
|
||||
<h4>识别建议</h4>
|
||||
</div>
|
||||
<ul class="bullet-list">
|
||||
<li v-for="item in currentInsight.recognition.suggestions" :key="item">{{ item }}</li>
|
||||
</ul>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<template v-else-if="currentInsight.intent === 'note'">
|
||||
<section class="insight-card primary">
|
||||
<div class="card-head">
|
||||
<h4>补充说明</h4>
|
||||
<span class="status-pill note">{{ currentInsight.note.state }}</span>
|
||||
<h4>草稿内容</h4>
|
||||
</div>
|
||||
<div class="note-block">
|
||||
<span>关联单号</span>
|
||||
<strong>{{ currentInsight.note.requestId }}</strong>
|
||||
<p>{{ currentInsight.note.generatedNote }}</p>
|
||||
<span>{{ currentInsight.agent.draftPayload.draft_type }}</span>
|
||||
<strong>{{ currentInsight.agent.draftPayload.title }}</strong>
|
||||
<p>{{ currentInsight.agent.draftPayload.body }}</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="insight-card">
|
||||
<div class="card-head">
|
||||
<h4>影响范围</h4>
|
||||
</div>
|
||||
<ul class="bullet-list">
|
||||
<li v-for="item in currentInsight.note.impacts" :key="item">{{ item }}</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="insight-card">
|
||||
<div class="card-head">
|
||||
<h4>下一步</h4>
|
||||
</div>
|
||||
<div class="metric-grid single">
|
||||
<div class="metric-item">
|
||||
<span>当前处理人</span>
|
||||
<strong>{{ currentInsight.note.owner }}</strong>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span>建议动作</span>
|
||||
<strong>{{ currentInsight.note.nextAction }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<template v-else-if="currentInsight.intent === 'draft'">
|
||||
<section class="insight-card primary">
|
||||
<div class="card-head">
|
||||
<h4>报销草稿</h4>
|
||||
<span class="status-pill success">{{ currentInsight.draft.state }}</span>
|
||||
</div>
|
||||
<div class="metric-grid">
|
||||
<div class="metric-item">
|
||||
<span>单号</span>
|
||||
<strong>{{ currentInsight.draft.requestId }}</strong>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span>报销类型</span>
|
||||
<strong>{{ currentInsight.draft.type }}</strong>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span>预计金额</span>
|
||||
<strong>{{ currentInsight.draft.amount }}</strong>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span>当前进度</span>
|
||||
<strong>{{ currentInsight.draft.progress }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="insight-card">
|
||||
<div class="card-head">
|
||||
<h4>费用建议</h4>
|
||||
</div>
|
||||
<div class="receipt-list">
|
||||
<article v-for="item in currentInsight.draft.items" :key="item.name" class="receipt-row">
|
||||
<div>
|
||||
<strong>{{ item.name }}</strong>
|
||||
<p>{{ item.desc }}</p>
|
||||
</div>
|
||||
<div class="receipt-side">
|
||||
<strong>{{ item.amount }}</strong>
|
||||
<span>{{ item.tag }}</span>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="insight-card">
|
||||
<div class="card-head">
|
||||
<h4>待补信息</h4>
|
||||
</div>
|
||||
<ul class="bullet-list">
|
||||
<li v-for="item in currentInsight.draft.missing" :key="item">{{ item }}</li>
|
||||
</ul>
|
||||
</section>
|
||||
</template>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
Reference in New Issue
Block a user