refactor(frontend): split large reimbursement and audit modules

This commit is contained in:
caoxiaozhu
2026-05-21 23:53:03 +08:00
parent 2908dda024
commit f6f787ff38
53 changed files with 15637 additions and 14179 deletions

View File

@@ -87,12 +87,17 @@
<strong>{{ message.role === 'assistant' ? (message.assistantName || ASSISTANT_DISPLAY_NAME) : '我' }}</strong>
<time>{{ message.time }}</time>
</header>
<p
v-if="message.text && (message.role !== 'assistant' || message.reviewPayload)"
:class="{ 'review-summary': message.role === 'assistant' && message.reviewPayload }"
>
{{ message.text }}
</p>
<div
v-if="message.text && message.role === 'assistant' && message.reviewPayload"
class="review-summary message-answer-content message-answer-markdown"
v-html="renderMarkdown(message.text)"
></div>
<div
v-else-if="message.text && message.role !== 'assistant'"
class="message-answer-content message-answer-markdown message-rich-text"
v-html="renderMarkdown(message.text)"
></div>
<div
v-else-if="message.text && message.role === 'assistant'"
@@ -288,88 +293,49 @@
</div>
<div v-if="message.role === 'assistant' && message.reviewPayload" class="message-detail-block review-message-block">
<div class="review-card-shell">
<div class="review-card-head">
<div class="review-card-head-main">
<span class="review-card-icon">
<i class="mdi mdi-shield-alert-outline"></i>
</span>
<div class="review-card-head-copy">
<strong>{{ buildReviewHeadline(message.reviewPayload, message.draftPayload) }}</strong>
<p>{{ buildReviewSubline(message.reviewPayload, message.draftPayload) }}</p>
</div>
</div>
<span class="review-card-state" :class="buildReviewStateTone(message.reviewPayload, message.draftPayload)">
{{ buildReviewStateLabel(message.reviewPayload, message.draftPayload) }}
</span>
</div>
<details
class="review-followup-panel"
:class="buildReviewStateTone(message.reviewPayload, message.draftPayload)"
:open="shouldOpenReviewDisclosure(message.reviewPayload)"
<div class="review-plain-followup">
<template
v-for="followup in [buildReviewPlainFollowupCopy(message.reviewPayload)]"
:key="`${message.id}-review-followup`"
>
<summary class="review-followup-head">
<div class="review-followup-head-main">
<span class="review-followup-mark">
<i :class="buildReviewStateTone(message.reviewPayload, message.draftPayload) === 'ready' ? 'mdi mdi-clipboard-check-outline' : 'mdi mdi-clipboard-text-clock-outline'"></i>
</span>
<div class="review-followup-title-copy">
<strong>{{ buildReviewTodoSectionTitle(message.reviewPayload) }}</strong>
<p>{{ buildReviewDisclosureHint(message.reviewPayload) }}</p>
<div class="review-followup-preview">
<span
v-for="item in buildReviewTodoItems(message.reviewPayload).slice(0, 2)"
:key="`${message.id}-preview-${item.key}`"
>
{{ item.title }}
</span>
<span v-if="buildReviewTodoItems(message.reviewPayload).length > 2">
+{{ buildReviewTodoItems(message.reviewPayload).length - 2 }}
</span>
</div>
</div>
</div>
<div class="review-followup-side">
<span class="review-followup-count">{{ buildReviewTodoSectionMeta(message.reviewPayload) }}</span>
<span class="review-followup-chevron">
<i class="mdi mdi-chevron-down"></i>
</span>
</div>
</summary>
<div class="review-followup-body">
<div class="review-followup-list">
<article
v-for="item in buildReviewTodoItems(message.reviewPayload)"
:key="`${message.id}-${item.key}`"
class="review-followup-item"
:class="item.tone"
>
<span class="review-followup-icon">
<i :class="item.icon"></i>
</span>
<div class="review-followup-copy">
<strong>{{ item.title }}</strong>
<p>{{ item.hint }}</p>
</div>
<span class="review-followup-status">{{ item.status }}</span>
</article>
</div>
<p v-if="buildReviewDecisionHint(message.reviewPayload)" class="review-followup-helper">
{{ buildReviewDecisionHint(message.reviewPayload) }}
</p>
</div>
</details>
<p class="review-plain-lead">{{ followup.lead }}</p>
<ul v-if="followup.items.length" class="review-plain-list">
<li
v-for="item in followup.items"
:key="`${message.id}-${item.key}`"
>
<span class="review-plain-label">{{ item.label }}</span>
<span>{{ item.text }}</span>
</li>
</ul>
<p
v-for="line in followup.notes"
:key="`${message.id}-note-${line}`"
class="review-plain-note"
>
{{ line }}
</p>
<p v-if="canUseInlineSaveDraft(message)" class="review-inline-save-copy">
请核查上面的关键信息您也可以暂时不处理上述的这些内容我可以帮你先保存为
<button
type="button"
class="review-inline-draft-link"
:disabled="submitting || reviewActionBusy || sessionSwitchBusy"
@click="handleInlineSaveDraft(message)"
>
草稿
</button>
</p>
</template>
<div
v-if="resolveReviewSubmitActions(message.reviewPayload).length || resolveReviewEditAction(message.reviewPayload) || message.draftPayload?.claim_no"
v-if="resolveReviewFooterActions(message.reviewPayload).length"
class="review-footer-actions"
>
<div class="review-footer-btn-row">
<button
v-for="action in resolveReviewSubmitActions(message.reviewPayload)"
v-for="action in resolveReviewFooterActions(message.reviewPayload)"
:key="`${message.id}-${action.action_type}`"
type="button"
:class="['review-footer-btn', action.emphasis === 'primary' ? 'primary' : '']"
@@ -378,26 +344,6 @@
>
{{ action.label || buildReviewPrimaryButtonLabel(message.reviewPayload, message.draftPayload) }}
</button>
<button
v-if="resolveReviewEditAction(message.reviewPayload)"
type="button"
:class="['review-footer-btn', resolveReviewEditAction(message.reviewPayload)?.emphasis === 'primary' ? 'primary' : '']"
:disabled="submitting || reviewActionBusy || sessionSwitchBusy"
@click="handleReviewAction(message, resolveReviewEditAction(message.reviewPayload))"
>
{{ resolveReviewEditAction(message.reviewPayload)?.label || '修改识别信息' }}
</button>
<button
v-if="shouldShowReviewUploadButton(message.reviewPayload)"
type="button"
class="review-footer-btn"
:disabled="submitting || reviewActionBusy"
@click="triggerFileUpload(message.reviewPayload.document_cards?.length ? 'composer-continue' : 'composer')"
>
{{ message.reviewPayload.document_cards?.length ? '继续上传票据' : '上传票据' }}
</button>
</div>
</div>
</div>
@@ -1328,22 +1274,6 @@
@confirm="confirmDeleteCurrentSession"
/>
<ConfirmDialog
:open="reviewCancelDialogOpen"
badge="取消核对"
badge-tone="warning"
title="确认放弃本次识别结果?"
description="关闭后将退出当前核对窗口,本次尚未确认的修改不会继续保留。"
cancel-text="返回继续核对"
confirm-text="确认取消"
busy-text="处理中..."
confirm-tone="danger"
confirm-icon="mdi mdi-close-circle-outline"
:busy="reviewActionBusy"
@close="closeCancelReviewDialog"
@confirm="confirmCancelReview"
/>
<Transition name="assistant-modal">
<div v-if="uploadDecisionDialogOpen" class="assistant-overlay review-overlay">
<section class="review-confirm-modal review-upload-decision-modal">
@@ -1404,57 +1334,12 @@
</div>
</Transition>
<Transition name="assistant-modal">
<div v-if="reviewEditDialogOpen" class="assistant-overlay review-overlay">
<section class="review-edit-modal">
<header class="review-edit-head">
<div>
<span class="assistant-badge">修改识别信息</span>
<h3>请按当前识别结果逐项修改</h3>
<p>修改会先保存到右侧核对信息提交下一步时再进行 AI 预审</p>
</div>
<button class="close-btn" type="button" aria-label="关闭修改面板" :disabled="reviewActionBusy" @click="closeEditReviewDialog">
<i class="mdi mdi-close"></i>
</button>
</header>
<div class="review-edit-form">
<label
v-for="item in reviewEditFields"
:key="item.key"
class="review-edit-field"
:class="item.group"
>
<span>{{ item.label }}<em v-if="item.required">*</em></span>
<textarea
v-if="item.field_type === 'textarea'"
v-model="item.value"
rows="3"
:placeholder="item.placeholder"
:disabled="reviewActionBusy"
></textarea>
<input
v-else
v-model="item.value"
type="text"
:placeholder="item.placeholder"
:disabled="reviewActionBusy"
/>
</label>
</div>
<div class="review-edit-actions">
<button type="button" class="secondary-dialog-btn" :disabled="reviewActionBusy" @click="closeEditReviewDialog">取消</button>
<button type="button" class="primary-dialog-btn" :disabled="reviewActionBusy" @click="applyEditedReview">
{{ reviewActionBusy ? '保存中...' : '确认修改' }}
</button>
</div>
</section>
</div>
</Transition>
</Teleport>
</template>
<script src="./scripts/TravelReimbursementCreateView.js"></script>
<style scoped src="../assets/styles/views/travel-reimbursement-create-view.css"></style>
<style scoped src="../assets/styles/views/travel-reimbursement-create-view-part2.css"></style>
<style scoped src="../assets/styles/views/travel-reimbursement-create-view-part3.css"></style>
<style scoped src="../assets/styles/views/travel-reimbursement-create-view-part4.css"></style>