feat(web): 更新请求列表、差旅报销创建、差旅请求详情页面及对应的业务脚本逻辑
This commit is contained in:
@@ -244,35 +244,8 @@
|
||||
</summary>
|
||||
|
||||
<div class="review-disclosure-body">
|
||||
<div v-if="buildReviewAlertChips(message.reviewPayload).length" class="review-alert-chip-row subtle">
|
||||
<span
|
||||
v-for="item in buildReviewAlertChips(message.reviewPayload)"
|
||||
:key="`${message.id}-${item.key}`"
|
||||
class="review-alert-chip"
|
||||
:class="item.tone"
|
||||
>
|
||||
<i :class="item.tone === 'danger' ? 'mdi mdi-alert-circle' : item.tone === 'success' ? 'mdi mdi-check-circle' : 'mdi mdi-alert'"></i>
|
||||
{{ item.label }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-if="resolveReviewRiskBriefs(message.reviewPayload).length" class="review-risk-brief-list">
|
||||
<article
|
||||
v-for="item in resolveReviewRiskBriefs(message.reviewPayload)"
|
||||
:key="`${message.id}-${item.title}`"
|
||||
class="review-risk-brief"
|
||||
:class="item.level || 'info'"
|
||||
>
|
||||
<strong>{{ item.title }}</strong>
|
||||
<p>{{ item.content }}</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="review-section-head review-flow-head">
|
||||
<strong>{{ buildReviewTodoSectionTitle(message.reviewPayload) }}</strong>
|
||||
<span>{{ buildReviewTodoSectionMeta(message.reviewPayload) }}</span>
|
||||
</div>
|
||||
<div class="review-pending-list plain">
|
||||
<!-- 待补充信息项 -->
|
||||
<article
|
||||
v-for="item in buildReviewTodoItems(message.reviewPayload)"
|
||||
:key="`${message.id}-${item.key}`"
|
||||
@@ -321,16 +294,6 @@
|
||||
>
|
||||
{{ message.reviewPayload.document_cards?.length ? '继续上传票据' : '上传票据' }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
v-if="message.draftPayload?.claim_no"
|
||||
type="button"
|
||||
class="review-footer-btn"
|
||||
:disabled="submitting || reviewActionBusy"
|
||||
@click="queryDraftByClaimNo(message.draftPayload.claim_no)"
|
||||
>
|
||||
查看当前报销信息
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -484,13 +447,46 @@
|
||||
<span class="intent-pill" :class="currentInsight.intent">{{ currentIntentLabel }}</span>
|
||||
</div>
|
||||
<div v-else class="review-insight-title-row">
|
||||
<h3>报销识别核对</h3>
|
||||
<span class="insight-head-badge">实时意图分析</span>
|
||||
<div class="review-insight-title-copy">
|
||||
<h3>{{ reviewDrawerTitle }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<h3 v-if="!activeReviewPayload">{{ currentInsight.title }}</h3>
|
||||
<p v-if="!activeReviewPayload">{{ currentInsight.summary }}</p>
|
||||
</div>
|
||||
|
||||
<div v-if="activeReviewPayload" class="review-insight-tools">
|
||||
<button
|
||||
type="button"
|
||||
class="review-insight-switch-icon-btn"
|
||||
:class="{
|
||||
available: reviewDocumentDrawerAvailable,
|
||||
active: reviewDocumentDrawerAvailable && isReviewDocumentDrawer
|
||||
}"
|
||||
:disabled="!reviewDocumentDrawerAvailable || submitting || reviewActionBusy"
|
||||
:title="reviewDocumentDrawerLabel"
|
||||
:aria-label="reviewDocumentDrawerLabel"
|
||||
@click="toggleReviewDocumentDrawer"
|
||||
>
|
||||
<i :class="reviewDocumentDrawerIcon"></i>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="review-insight-switch-icon-btn risk"
|
||||
:class="{
|
||||
available: reviewRiskDrawerAvailable,
|
||||
active: reviewRiskDrawerAvailable && isReviewRiskDrawer
|
||||
}"
|
||||
:disabled="!reviewRiskDrawerAvailable || submitting || reviewActionBusy"
|
||||
:title="reviewRiskDrawerLabel"
|
||||
:aria-label="reviewRiskDrawerLabel"
|
||||
@click="toggleReviewRiskDrawer"
|
||||
>
|
||||
<i :class="reviewRiskDrawerIcon"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="confidence-card" v-if="!activeReviewPayload">
|
||||
<span>{{ currentInsight.metricLabel }}</span>
|
||||
<strong>{{ currentInsight.metricValue }}</strong>
|
||||
@@ -498,7 +494,7 @@
|
||||
</div>
|
||||
|
||||
<Transition name="insight-switch" mode="out-in">
|
||||
<div :key="`${activeSessionType}-${currentInsight.intent}-${currentInsight.title}`" class="insight-body">
|
||||
<div :key="`${activeSessionType}-${currentInsight.intent}-${currentInsight.title}-${reviewDrawerMode}`" class="insight-body">
|
||||
<template v-if="isKnowledgeSession">
|
||||
<section class="insight-card knowledge-hot-card">
|
||||
<div class="card-head">
|
||||
@@ -528,286 +524,296 @@
|
||||
|
||||
<template v-else-if="currentInsight.intent === 'agent' && currentInsight.agent">
|
||||
<template v-if="activeReviewPayload">
|
||||
<section class="review-side-card review-side-overview-card">
|
||||
<div class="review-side-intent-row">
|
||||
<i class="mdi mdi-account-outline"></i>
|
||||
<span>用户意图:</span>
|
||||
<strong>{{ reviewIntentText }}</strong>
|
||||
</div>
|
||||
<section class="review-side-grid compact">
|
||||
<article
|
||||
v-for="item in reviewFactCards"
|
||||
:key="item.key"
|
||||
class="review-side-metric-card"
|
||||
:class="{
|
||||
editable: item.editor,
|
||||
editing: reviewInlineEditorKey === item.key,
|
||||
invalid: Boolean(reviewInlineErrors[item.key])
|
||||
}"
|
||||
@click="openInlineReviewEditor(item.key)"
|
||||
>
|
||||
<span class="review-side-metric-icon">
|
||||
<i :class="item.icon"></i>
|
||||
</span>
|
||||
<div class="review-side-metric-copy">
|
||||
<small>{{ item.label }}</small>
|
||||
<template v-if="reviewInlineEditorKey === item.key && item.editor === 'date'">
|
||||
<input
|
||||
v-model="reviewInlineForm[item.modelKey]"
|
||||
class="review-inline-input"
|
||||
:class="{ invalid: Boolean(reviewInlineErrors[item.key]) }"
|
||||
type="text"
|
||||
:placeholder="`仅支持 ${DATE_INPUT_FORMAT}`"
|
||||
@click.stop
|
||||
@input="clearInlineReviewFieldError(item.key)"
|
||||
@blur="commitInlineReviewEditor"
|
||||
@keydown.enter.prevent="commitInlineReviewEditor"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="reviewInlineEditorKey === item.key && item.editor === 'amount'">
|
||||
<input
|
||||
v-model="reviewInlineForm[item.modelKey]"
|
||||
class="review-inline-input"
|
||||
:class="{ invalid: Boolean(reviewInlineErrors[item.key]) }"
|
||||
type="text"
|
||||
:placeholder="item.placeholder"
|
||||
@click.stop
|
||||
@input="clearInlineReviewFieldError(item.key)"
|
||||
@blur="commitInlineReviewEditor"
|
||||
@keydown.enter.prevent="commitInlineReviewEditor"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="reviewInlineEditorKey === item.key && item.editor === 'text'">
|
||||
<input
|
||||
v-model="reviewInlineForm[item.modelKey]"
|
||||
class="review-inline-input"
|
||||
:class="{ invalid: Boolean(reviewInlineErrors[item.key]) }"
|
||||
type="text"
|
||||
:placeholder="item.placeholder"
|
||||
@click.stop
|
||||
@input="clearInlineReviewFieldError(item.key)"
|
||||
@blur="commitInlineReviewEditor"
|
||||
@keydown.enter.prevent="commitInlineReviewEditor"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="reviewInlineEditorKey === item.key && item.editor === 'select'">
|
||||
<div class="review-inline-select-list" @click.stop>
|
||||
<button
|
||||
v-for="scene in REVIEW_SCENE_OPTIONS"
|
||||
:key="scene"
|
||||
type="button"
|
||||
class="review-inline-select-option"
|
||||
:class="{ active: reviewInlineForm.scene_label === scene }"
|
||||
@click.stop="selectInlineScene(scene)"
|
||||
>
|
||||
{{ scene }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
<strong v-else :title="item.value">{{ item.value }}</strong>
|
||||
<span v-if="reviewInlineErrors[item.key]" class="review-inline-error">
|
||||
{{ reviewInlineErrors[item.key] }}
|
||||
<template v-if="!isReviewDocumentDrawer && !isReviewRiskDrawer">
|
||||
<section class="review-side-card review-side-overview-card">
|
||||
<div class="review-side-intent-row">
|
||||
<i class="mdi mdi-account-outline"></i>
|
||||
<span>用户意图:</span>
|
||||
<strong>{{ reviewIntentText }}</strong>
|
||||
</div>
|
||||
<section class="review-side-grid compact">
|
||||
<article
|
||||
v-for="item in reviewFactCards"
|
||||
:key="item.key"
|
||||
class="review-side-metric-card"
|
||||
:class="{
|
||||
editable: item.editor,
|
||||
editing: reviewInlineEditorKey === item.key,
|
||||
invalid: Boolean(reviewInlineErrors[item.key])
|
||||
}"
|
||||
@click="openInlineReviewEditor(item.key)"
|
||||
>
|
||||
<span class="review-side-metric-icon">
|
||||
<i :class="item.icon"></i>
|
||||
</span>
|
||||
</div>
|
||||
<span v-if="item.key !== 'attachments'" class="review-side-edit-hint">修改</span>
|
||||
<span v-else class="review-side-edit-hint upload">{{ reviewInlinePendingFiles.length ? '已选择' : '上传' }}</span>
|
||||
</article>
|
||||
<div class="review-side-metric-copy">
|
||||
<small>{{ item.label }}</small>
|
||||
<template v-if="reviewInlineEditorKey === item.key && item.editor === 'date'">
|
||||
<input
|
||||
v-model="reviewInlineForm[item.modelKey]"
|
||||
class="review-inline-input"
|
||||
:class="{ invalid: Boolean(reviewInlineErrors[item.key]) }"
|
||||
type="text"
|
||||
:placeholder="`仅支持 ${DATE_INPUT_FORMAT}`"
|
||||
@click.stop
|
||||
@input="clearInlineReviewFieldError(item.key)"
|
||||
@blur="commitInlineReviewEditor"
|
||||
@keydown.enter.prevent="commitInlineReviewEditor"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="reviewInlineEditorKey === item.key && item.editor === 'amount'">
|
||||
<input
|
||||
v-model="reviewInlineForm[item.modelKey]"
|
||||
class="review-inline-input"
|
||||
:class="{ invalid: Boolean(reviewInlineErrors[item.key]) }"
|
||||
type="text"
|
||||
:placeholder="item.placeholder"
|
||||
@click.stop
|
||||
@input="clearInlineReviewFieldError(item.key)"
|
||||
@blur="commitInlineReviewEditor"
|
||||
@keydown.enter.prevent="commitInlineReviewEditor"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="reviewInlineEditorKey === item.key && item.editor === 'text'">
|
||||
<input
|
||||
v-model="reviewInlineForm[item.modelKey]"
|
||||
class="review-inline-input"
|
||||
:class="{ invalid: Boolean(reviewInlineErrors[item.key]) }"
|
||||
type="text"
|
||||
:placeholder="item.placeholder"
|
||||
@click.stop
|
||||
@input="clearInlineReviewFieldError(item.key)"
|
||||
@blur="commitInlineReviewEditor"
|
||||
@keydown.enter.prevent="commitInlineReviewEditor"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="reviewInlineEditorKey === item.key && item.editor === 'select'">
|
||||
<div class="review-inline-select-list" @click.stop>
|
||||
<button
|
||||
v-for="scene in REVIEW_SCENE_OPTIONS"
|
||||
:key="scene"
|
||||
type="button"
|
||||
class="review-inline-select-option"
|
||||
:class="{ active: reviewInlineForm.scene_label === scene }"
|
||||
@click.stop="selectInlineScene(scene)"
|
||||
>
|
||||
{{ scene }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
<strong v-else :title="item.value">{{ item.value }}</strong>
|
||||
<span v-if="reviewInlineErrors[item.key]" class="review-inline-error">
|
||||
{{ reviewInlineErrors[item.key] }}
|
||||
</span>
|
||||
</div>
|
||||
<span v-if="item.key !== 'attachments'" class="review-side-edit-hint">修改</span>
|
||||
<span v-else class="review-side-edit-hint upload">{{ reviewInlinePendingFiles.length ? '已选择' : '上传' }}</span>
|
||||
</article>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="review-side-card">
|
||||
<div class="review-side-head">
|
||||
<strong>报销分类</strong>
|
||||
<span class="review-side-confidence">置信度 {{ reviewPanelConfidence }}</span>
|
||||
</div>
|
||||
<div class="review-side-category-grid">
|
||||
<button
|
||||
v-for="item in reviewCategoryOptions"
|
||||
:key="item.key"
|
||||
type="button"
|
||||
class="review-side-category-card"
|
||||
:class="{ active: item.active }"
|
||||
@click="selectReviewCategory(item)"
|
||||
>
|
||||
<div class="review-side-category-copy">
|
||||
<strong>{{ item.label }}</strong>
|
||||
<p>{{ item.is_other && reviewSelectedOtherCategory ? reviewSelectedOtherCategory : item.caption }}</p>
|
||||
</div>
|
||||
<i v-if="item.active" class="mdi mdi-check-circle review-side-group-check"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="reviewOtherCategoryOpen" class="review-other-category-popover">
|
||||
<button
|
||||
v-for="item in reviewOtherCategoryOptions"
|
||||
:key="item.key"
|
||||
type="button"
|
||||
class="review-other-category-option"
|
||||
:class="{ active: reviewSelectedOtherCategory === item.label }"
|
||||
@click="selectReviewOtherCategory(item)"
|
||||
>
|
||||
{{ item.label }} · {{ item.confidenceLabel }}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="review-side-card review-side-risk-card">
|
||||
<div class="review-side-head">
|
||||
<strong>合规提醒 / 风险评分</strong>
|
||||
<span class="review-side-risk-score" :class="{ empty: reviewRiskScore === null }">
|
||||
{{ reviewRiskScore === null ? '无' : `${reviewRiskScore}/100` }}
|
||||
</span>
|
||||
</div>
|
||||
<p class="review-side-risk-summary">{{ reviewRiskSummary }}</p>
|
||||
<ul v-if="reviewRiskItems.length" class="review-side-risk-list">
|
||||
<li v-for="item in reviewRiskItems" :key="item">{{ item }}</li>
|
||||
</ul>
|
||||
<div v-else-if="reviewRiskEmpty" class="review-side-empty">
|
||||
<span class="review-side-empty-icon">
|
||||
<i class="mdi mdi-shield-check-outline"></i>
|
||||
</span>
|
||||
<strong>暂无风险评分</strong>
|
||||
<p>当前版本还没有返回结构化风险评分结果,这里先不展示虚拟分数。</p>
|
||||
</div>
|
||||
<button
|
||||
v-if="reviewRiskActionAvailable"
|
||||
type="button"
|
||||
class="review-side-link"
|
||||
:disabled="submitting || reviewActionBusy"
|
||||
@click="explainCurrentReviewRisk"
|
||||
>
|
||||
查看全部风险项
|
||||
<i class="mdi mdi-chevron-right"></i>
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<section v-if="reviewDocumentCount" class="review-side-card review-document-switch-card">
|
||||
<div class="review-side-head review-document-switch-head">
|
||||
<div class="review-side-head-copy">
|
||||
<strong>票据识别结果卡片</strong>
|
||||
<p>逐张查看 OCR 结果,可直接修正后再继续提交。</p>
|
||||
<section class="review-side-card">
|
||||
<div class="review-side-head">
|
||||
<strong>报销分类</strong>
|
||||
<span class="review-side-confidence">置信度 {{ reviewPanelConfidence }}</span>
|
||||
</div>
|
||||
<div class="review-document-nav">
|
||||
<div class="review-side-category-grid">
|
||||
<button
|
||||
v-for="item in reviewCategoryOptions"
|
||||
:key="item.key"
|
||||
type="button"
|
||||
class="review-document-nav-btn"
|
||||
:disabled="activeReviewDocumentIndex === 0"
|
||||
aria-label="上一张票据"
|
||||
@click="goReviewDocument(-1)"
|
||||
class="review-side-category-card"
|
||||
:class="{ active: item.active }"
|
||||
@click="selectReviewCategory(item)"
|
||||
>
|
||||
<i class="mdi mdi-chevron-left"></i>
|
||||
</button>
|
||||
<span>{{ activeReviewDocumentIndex + 1 }} / {{ reviewDocumentCount }}</span>
|
||||
<button
|
||||
type="button"
|
||||
class="review-document-nav-btn"
|
||||
:disabled="activeReviewDocumentIndex >= reviewDocumentCount - 1"
|
||||
aria-label="下一张票据"
|
||||
@click="goReviewDocument(1)"
|
||||
>
|
||||
<i class="mdi mdi-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="activeReviewDocument" class="review-document-stage">
|
||||
<div class="review-document-stage-head">
|
||||
<div class="review-document-stage-copy">
|
||||
<span class="review-document-index-chip">票据 {{ activeReviewDocument.index }}</span>
|
||||
<strong :title="activeReviewDocument.filename">{{ activeReviewDocument.filename }}</strong>
|
||||
</div>
|
||||
<button
|
||||
v-if="canPreviewActiveReviewDocument"
|
||||
type="button"
|
||||
class="review-side-link"
|
||||
:disabled="submitting || reviewActionBusy"
|
||||
@click="openActiveReviewDocumentPreview"
|
||||
>
|
||||
查看原图
|
||||
<i class="mdi mdi-arrow-top-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="review-document-meta-chip-row">
|
||||
<span class="review-document-meta-chip">{{ activeReviewDocument.documentTypeLabel }}</span>
|
||||
<span class="review-document-meta-chip">{{ activeReviewDocument.expenseTypeLabel }}</span>
|
||||
<span class="review-document-meta-chip confidence">{{ activeReviewDocument.confidenceLabel }}</span>
|
||||
</div>
|
||||
|
||||
<div class="review-document-scroll">
|
||||
<div class="review-document-preview-card" :class="activeReviewDocumentPreview?.kind || 'file'">
|
||||
<img
|
||||
v-if="activeReviewDocumentPreview?.kind === 'image' && activeReviewDocumentPreview?.url"
|
||||
:src="activeReviewDocumentPreview.url"
|
||||
:alt="activeReviewDocument.filename"
|
||||
/>
|
||||
<div v-else-if="activeReviewDocumentPreview?.kind === 'pdf'" class="review-document-preview-placeholder">
|
||||
<i class="mdi mdi-file-pdf-box"></i>
|
||||
<strong>PDF 原件可预览</strong>
|
||||
<p>点击右上角“查看原图”可查看完整 PDF。</p>
|
||||
</div>
|
||||
<div v-else class="review-document-preview-placeholder">
|
||||
<i class="mdi mdi-file-search-outline"></i>
|
||||
<strong>当前无可预览原图</strong>
|
||||
<p>这张票据仍可继续修改识别结果。</p>
|
||||
<div class="review-side-category-copy">
|
||||
<strong>{{ item.label }}</strong>
|
||||
<p>{{ item.is_other && reviewSelectedOtherCategory ? reviewSelectedOtherCategory : item.caption }}</p>
|
||||
</div>
|
||||
<i v-if="item.active" class="mdi mdi-check-circle review-side-group-check"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="reviewOtherCategoryOpen" class="review-other-category-popover">
|
||||
<button
|
||||
v-for="item in reviewOtherCategoryOptions"
|
||||
:key="item.key"
|
||||
type="button"
|
||||
class="review-other-category-option"
|
||||
:class="{ active: reviewSelectedOtherCategory === item.label }"
|
||||
@click="selectReviewOtherCategory(item)"
|
||||
>
|
||||
{{ item.label }} · {{ item.confidenceLabel }}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</template>
|
||||
|
||||
<template v-else-if="isReviewDocumentDrawer">
|
||||
<section class="review-side-card review-document-switch-card review-ticket-drawer">
|
||||
<div class="review-side-head review-document-switch-head">
|
||||
<div class="review-side-head-copy">
|
||||
<strong>票据识别结果卡片</strong>
|
||||
<p>逐张查看 OCR 结果,可直接修正后再切回核对滑窗。</p>
|
||||
</div>
|
||||
|
||||
<label class="review-document-edit-field summary">
|
||||
<span>票据摘要</span>
|
||||
<textarea
|
||||
v-model="activeReviewDocument.summary"
|
||||
rows="3"
|
||||
:disabled="submitting || reviewActionBusy"
|
||||
placeholder="可根据原图修正 OCR 摘要"
|
||||
></textarea>
|
||||
</label>
|
||||
|
||||
<label class="review-document-edit-field">
|
||||
<span>票据场景</span>
|
||||
<input
|
||||
v-model="activeReviewDocument.scene_label"
|
||||
type="text"
|
||||
:disabled="submitting || reviewActionBusy"
|
||||
placeholder="例如:业务招待费 / 差旅费"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<div v-if="activeReviewDocument.fields.length" class="review-document-edit-grid">
|
||||
<label
|
||||
v-for="field in activeReviewDocument.fields"
|
||||
:key="`${activeReviewDocument.filename}-${field.label}`"
|
||||
class="review-document-edit-field"
|
||||
<div class="review-document-nav">
|
||||
<button
|
||||
type="button"
|
||||
class="review-document-nav-btn"
|
||||
:disabled="activeReviewDocumentIndex === 0"
|
||||
aria-label="上一张票据"
|
||||
@click="goReviewDocument(-1)"
|
||||
>
|
||||
<span>{{ field.label }}</span>
|
||||
<i class="mdi mdi-chevron-left"></i>
|
||||
</button>
|
||||
<span>{{ activeReviewDocumentIndex + 1 }} / {{ reviewDocumentCount }}</span>
|
||||
<button
|
||||
type="button"
|
||||
class="review-document-nav-btn"
|
||||
:disabled="activeReviewDocumentIndex >= reviewDocumentCount - 1"
|
||||
aria-label="下一张票据"
|
||||
@click="goReviewDocument(1)"
|
||||
>
|
||||
<i class="mdi mdi-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="activeReviewDocument" class="review-document-stage">
|
||||
<div class="review-document-stage-head">
|
||||
<div class="review-document-stage-copy">
|
||||
<strong :title="activeReviewDocument.filename">{{ activeReviewDocument.filename }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="review-document-meta-chip-row">
|
||||
<span class="review-document-meta-chip">{{ activeReviewDocument.documentTypeLabel }}</span>
|
||||
<span class="review-document-meta-chip">{{ activeReviewDocument.expenseTypeLabel }}</span>
|
||||
<span class="review-document-meta-chip confidence">{{ activeReviewDocument.confidenceLabel }}</span>
|
||||
</div>
|
||||
|
||||
<div class="review-document-scroll">
|
||||
<div
|
||||
class="review-document-preview-card"
|
||||
:class="[
|
||||
activeReviewDocumentPreview?.kind || 'file',
|
||||
{ clickable: canPreviewActiveReviewDocument }
|
||||
]"
|
||||
:role="canPreviewActiveReviewDocument ? 'button' : null"
|
||||
:tabindex="canPreviewActiveReviewDocument ? 0 : null"
|
||||
@click="canPreviewActiveReviewDocument ? openActiveReviewDocumentPreview() : null"
|
||||
@keydown.enter.prevent="canPreviewActiveReviewDocument ? openActiveReviewDocumentPreview() : null"
|
||||
@keydown.space.prevent="canPreviewActiveReviewDocument ? openActiveReviewDocumentPreview() : null"
|
||||
>
|
||||
<img
|
||||
v-if="activeReviewDocumentPreview?.kind === 'image' && activeReviewDocumentPreview?.url"
|
||||
:src="activeReviewDocumentPreview.url"
|
||||
:alt="activeReviewDocument.filename"
|
||||
/>
|
||||
<div v-else-if="activeReviewDocumentPreview?.kind === 'pdf'" class="review-document-preview-placeholder">
|
||||
<i class="mdi mdi-file-pdf-box"></i>
|
||||
<strong>PDF 票据文件</strong>
|
||||
<p>当前文件还没有生成图片预览,可先核对下方识别字段。</p>
|
||||
</div>
|
||||
<div v-else class="review-document-preview-placeholder">
|
||||
<i class="mdi mdi-file-search-outline"></i>
|
||||
<strong>当前无可预览票据</strong>
|
||||
<p>这张票据还没有可用预览,可先核对下方识别字段。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label class="review-document-edit-field summary">
|
||||
<span>票据摘要</span>
|
||||
<textarea
|
||||
v-model="activeReviewDocument.summary"
|
||||
rows="3"
|
||||
:disabled="submitting || reviewActionBusy"
|
||||
placeholder="可根据票据图片修正 OCR 摘要"
|
||||
></textarea>
|
||||
</label>
|
||||
|
||||
<label class="review-document-edit-field">
|
||||
<span>票据场景</span>
|
||||
<input
|
||||
v-model="field.value"
|
||||
v-model="activeReviewDocument.scene_label"
|
||||
type="text"
|
||||
:disabled="submitting || reviewActionBusy"
|
||||
:placeholder="`修正 ${field.label}`"
|
||||
placeholder="例如:业务招待费 / 差旅费"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div v-else class="review-side-empty compact">
|
||||
<span class="review-side-empty-icon">
|
||||
<i class="mdi mdi-text-recognition"></i>
|
||||
</span>
|
||||
<strong>暂无结构化字段</strong>
|
||||
<p>当前只返回了摘要信息,你仍然可以直接修改上面的票据摘要。</p>
|
||||
</div>
|
||||
|
||||
<div v-if="activeReviewDocument.warnings?.length" class="review-document-warning-list">
|
||||
<article
|
||||
v-for="warning in activeReviewDocument.warnings"
|
||||
:key="`${activeReviewDocument.filename}-${warning}`"
|
||||
class="review-document-warning-item"
|
||||
>
|
||||
<i class="mdi mdi-alert-circle-outline"></i>
|
||||
<span>{{ warning }}</span>
|
||||
</article>
|
||||
<div v-if="activeReviewDocument.fields.length" class="review-document-edit-grid">
|
||||
<label
|
||||
v-for="field in activeReviewDocument.fields"
|
||||
:key="`${activeReviewDocument.filename}-${field.label}`"
|
||||
class="review-document-edit-field"
|
||||
>
|
||||
<span>{{ field.label }}</span>
|
||||
<input
|
||||
v-model="field.value"
|
||||
type="text"
|
||||
:disabled="submitting || reviewActionBusy"
|
||||
:placeholder="`修正 ${field.label}`"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div v-else class="review-side-empty compact">
|
||||
<span class="review-side-empty-icon">
|
||||
<i class="mdi mdi-text-recognition"></i>
|
||||
</span>
|
||||
<strong>暂无结构化字段</strong>
|
||||
<p>当前只返回了摘要信息,你仍然可以直接修改上面的票据摘要。</p>
|
||||
</div>
|
||||
|
||||
<div v-if="activeReviewDocument.warnings?.length" class="review-document-warning-list">
|
||||
<article
|
||||
v-for="warning in activeReviewDocument.warnings"
|
||||
:key="`${activeReviewDocument.filename}-${warning}`"
|
||||
class="review-document-warning-item"
|
||||
>
|
||||
<i class="mdi mdi-alert-circle-outline"></i>
|
||||
<span>{{ warning }}</span>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<template v-else-if="isReviewRiskDrawer">
|
||||
<section class="review-side-card review-side-risk-card">
|
||||
<div class="review-side-head">
|
||||
<div class="review-side-head-copy">
|
||||
<strong>合规提醒 / 风险评分</strong>
|
||||
<p>结合本体附件要求和识别结果,集中查看当前票据风险。</p>
|
||||
</div>
|
||||
<span class="review-side-risk-score" :class="{ empty: reviewRiskScore === null }">
|
||||
{{ reviewRiskScore === null ? '无' : `${reviewRiskScore}/100` }}
|
||||
</span>
|
||||
</div>
|
||||
<p class="review-side-risk-summary">{{ reviewRiskSummary }}</p>
|
||||
<ul v-if="reviewRiskItems.length" class="review-side-risk-list">
|
||||
<li v-for="item in reviewRiskItems" :key="item">{{ item }}</li>
|
||||
</ul>
|
||||
<div v-else-if="reviewRiskEmpty" class="review-side-empty">
|
||||
<span class="review-side-empty-icon">
|
||||
<i class="mdi mdi-shield-check-outline"></i>
|
||||
</span>
|
||||
<strong>暂无风险评分</strong>
|
||||
<p>当前版本还没有返回结构化风险评分结果,这里先不展示虚拟分数。</p>
|
||||
</div>
|
||||
<button
|
||||
v-if="reviewRiskActionAvailable"
|
||||
type="button"
|
||||
class="review-side-link"
|
||||
:disabled="submitting || reviewActionBusy"
|
||||
@click="explainCurrentReviewRisk"
|
||||
>
|
||||
查看全部风险项
|
||||
<i class="mdi mdi-chevron-right"></i>
|
||||
</button>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<button
|
||||
v-if="reviewHasUnsavedChanges"
|
||||
|
||||
Reference in New Issue
Block a user