This commit is contained in:
zlwu committed 2026-05-28 13:05:46 +08:00
1 parent f1f5d24eff
commit 3c7a47981a
138 files changed
+18654 -12092

No files matched your search

+6 -5
View File
@@ -167,16 +167,17 @@ export function fetchClinicalPaymentDetail(id: string) {
})
}
export function submitClinicalReceipt(id: string) {
export function submitClinicalReceipt(id: string, data?: Record<string, unknown>) {
return request.post({
url: `/web/admin/clinical-payments/${id}/submit-receipt`
url: `/web/admin/clinical-payments/${id}/submit-receipt`,
params: data
})
}
export function batchSubmitClinicalReceipt(ids: string[]) {
export function batchSubmitClinicalReceipt(ids: string[], data?: Record<string, unknown>) {
return request.post({
url: '/web/admin/clinical-payments/submit-receipt-batch',
params: { ids }
params: { paymentIds: ids, ...data }
})
}
@@ -197,7 +198,7 @@ export function submitClinicalRefund(id: string, data: any) {
export function batchSubmitClinicalRefund(ids: string[], data: any) {
return request.post({
url: '/web/admin/clinical-payments/submit-refund-batch',
params: { ...data, ids }
params: { ...data, paymentIds: ids }
})
}
@@ -158,6 +158,8 @@ export function fetchOutboundReleaseReviewList(params?: {
reviewConclusion?: string
qcStatus?: string
keyword?: string
/** pilot_service | clinical_application */
bizType?: string
}) {
return request.get<PageList<OutboundReleaseReview>>({
url: '/web/admin/pilot-release-reviews',
@@ -0,0 +1,208 @@
<!-- 临床应用缴费/退费提交信息只读展示 -->
<template>
<div class="clinical-payment-submit-readonly">
<h4 v-if="title" class="detail-block-title">{{ title }}</h4>
<dl class="view-kv-grid view-kv-grid--4">
<div class="view-kv">
<dt>申请单号</dt>
<dd>{{ dash(detail?.applicationNo) }}</dd>
</div>
<div class="view-kv">
<dt>患者姓名</dt>
<dd>{{ dash(detail?.patientName) }}</dd>
</div>
<div class="view-kv">
<dt>渠道名称</dt>
<dd>{{ dash(detail?.channelName) }}</dd>
</div>
<div class="view-kv">
<dt>细胞类型/规格</dt>
<dd>{{ dash(detail?.cellTypeSpec) }}</dd>
</div>
<div class="view-kv">
<dt>输注时间</dt>
<dd>{{ dash(detail?.infusionTime) }}</dd>
</div>
<div v-if="showPayStatus" class="view-kv">
<dt>缴费状态</dt>
<dd>
<el-tag :type="payStatusTagType(String(detail?.payStatus || ''))" size="small">
{{ payStatusLabel(String(detail?.payStatus || '')) }}
</el-tag>
</dd>
</div>
<template v-if="mode === 'refund'">
<div class="view-kv">
<dt>缴费金额(元)</dt>
<dd>{{ formatAmount(detail?.paymentAmount ?? detail?.amount) }}</dd>
</div>
</template>
<template v-if="mode === 'receipt' || mode === 'full'">
<div class="view-kv">
<dt>缴费金额(元)</dt>
<dd>{{ formatAmount(detail?.paymentAmount ?? detail?.amount) }}</dd>
</div>
<div v-if="detail?.remark" class="view-kv view-kv-span-2">
<dt>备注</dt>
<dd>{{ dash(detail?.remark) }}</dd>
</div>
<div class="view-field-block view-kv-span-2 clinical-payment-submit-readonly__attachments">
<div class="view-field-block__label">转账凭证</div>
<ProtocolAttachmentReadonly
:files="receiptAttachmentFiles"
@preview="(f) => emit('preview', f)"
@download="(f) => emit('download', f)"
/>
</div>
</template>
<template v-if="mode === 'refund' || (mode === 'full' && hasRefundInfo)">
<div class="view-kv">
<dt>退费金额(元)</dt>
<dd>{{ formatAmount(detail?.refundAmount) }}</dd>
</div>
<div v-if="detail?.refundRemark" class="view-kv view-kv-span-2">
<dt>退费备注</dt>
<dd>{{ dash(detail?.refundRemark) }}</dd>
</div>
<div class="view-field-block view-kv-span-2 clinical-payment-submit-readonly__attachments">
<div class="view-field-block__label">退费附件</div>
<ProtocolAttachmentReadonly
:files="refundAttachmentFiles"
@preview="(f) => emit('preview', f)"
@download="(f) => emit('download', f)"
/>
</div>
</template>
</dl>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import ProtocolAttachmentReadonly from '@/views/cell-storage/protocol/ProtocolAttachmentReadonly.vue'
import { formatMoneyDisplay } from '@/utils/money-format'
import { payStatusLabel, payStatusTagType } from '@/utils/status-tag-registry'
const props = withDefaults(
defineProps<{
detail?: Record<string, unknown> | null
title?: string
mode?: 'receipt' | 'refund' | 'full'
showPayStatus?: boolean
}>(),
{ mode: 'receipt', showPayStatus: false }
)
const emit = defineEmits<{
(e: 'preview', file: Record<string, unknown>): void
(e: 'download', file: Record<string, unknown>): void
}>()
function dash(v: unknown) {
if (v == null || v === '') return '—'
return String(v)
}
function formatAmount(v: unknown) {
if (v == null || v === '') return '—'
return '¥' + formatMoneyDisplay(v)
}
function urlsToFiles(urlField: unknown) {
const urls = String(urlField || '')
if (!urls.trim()) return []
return urls
.split(',')
.map((u, i) => {
const url = u.trim()
if (!url) return null
const name = url.includes('/') ? url.split('/').pop() || `附件${i + 1}` : url
return { id: `url_${i}`, fileUrl: url, fileName: name }
})
.filter(Boolean) as Array<Record<string, unknown>>
}
const receiptAttachmentFiles = computed(() => urlsToFiles(props.detail?.transferAttachments))
const refundAttachmentFiles = computed(() => urlsToFiles(props.detail?.refundAttachments))
const hasRefundInfo = computed(() => {
const d = props.detail
if (!d) return false
return (
d.refundAmount != null ||
Boolean(d.refundRemark) ||
Boolean(String(d.refundAttachments || '').trim())
)
})
</script>
<style scoped lang="scss">
.clinical-payment-submit-readonly {
width: 100%;
}
.detail-block-title {
margin: 0 0 12px;
font-size: 14px;
font-weight: 600;
color: var(--mint-text, #334155);
line-height: 1.4;
}
.view-kv-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px 20px;
margin: 0;
}
.view-kv-grid--4 {
@media (min-width: 720px) {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
}
.view-kv {
min-width: 0;
dt {
margin: 0 0 4px;
font-size: 12px;
color: var(--mint-text-muted, #64748b);
font-weight: 500;
}
dd {
margin: 0;
font-size: 14px;
color: var(--mint-text, #334155);
line-height: 1.5;
word-break: break-word;
}
}
.view-kv-span-2 {
grid-column: 1 / -1;
}
.view-field-block__label {
font-size: 12px;
color: var(--mint-text-muted, #64748b);
font-weight: 500;
margin-bottom: 8px;
}
.clinical-payment-submit-readonly__attachments {
margin-top: 4px;
}
.form-section-divider--inner {
height: 1px;
margin: 16px 0;
background: var(--mint-border, #e2e8f0);
}
</style>
@@ -0,0 +1,729 @@
<!-- 临床应用 · 输注计划缴费明细(查看态,对齐 ProtocolViewDialog 缴费明细) -->
<template>
<div
class="payment-detail-card"
:class="{
'payment-detail-card--refunded': payStatus === 'ytf',
'payment-detail-card--refund-pending': payStatus === 'tfqrz'
}"
>
<div class="pdc-header">
<div class="pdc-header-left" :class="payDetailColorClass(payStatus)">
缴费明细 ·
<span class="pdc-header-amount" :class="payDetailColorClass(payStatus)">
{{ fmtMoney(planAmount) }}
</span>
</div>
<el-tag :type="payStatusTagType(payStatus)" size="small">
{{ payStatusLabel(payStatus) }}
</el-tag>
</div>
<div class="pdc-info-row">
<div class="pdc-info-item">
<span class="info-label">应缴费金额(元)</span>
<span class="info-value">{{ fmtMoney(planAmount) }}</span>
</div>
<div class="pdc-info-item">
<span class="info-label">实缴金额(元)</span>
<span class="info-value">{{ fmtMoney(payment?.transferAmount ?? planAmount) }}</span>
</div>
<div v-if="payment?.remark" class="pdc-info-item">
<span class="info-label">备注</span>
<span class="info-value">{{ dash(payment?.remark) }}</span>
</div>
<div v-if="payStatus !== 'dfj' && payment?.updateTime" class="pdc-info-item">
<span class="info-label">提交时间</span>
<span class="info-value">{{ dash(payment?.updateTime) }}</span>
</div>
</div>
<div v-if="transferAttachmentFiles.length" class="pdc-attachments-row">
<div class="data-label">转账凭证</div>
<ProtocolAttachmentReadonly
:files="transferAttachmentFiles"
@preview="(f) => emit('preview', f)"
@download="(f) => emit('download', f)"
/>
</div>
<template v-if="flowSteps.length">
<div class="flow-section">
<div class="mini-flow">
<template v-for="(step, sIdx) in flowSteps" :key="`c-${step.key}`">
<div
v-if="step.connectorToNext"
class="mini-flow-connector"
:class="step.connectorToNext"
:style="miniFlowConnectorStyle(flowSteps.length, sIdx)"
/>
</template>
<div v-for="step in flowSteps" :key="step.key" class="mini-flow-step">
<div class="mini-flow-dot" :class="step.dotClass">{{ step.dotIcon }}</div>
<div class="mini-flow-label" :class="step.labelClass">{{ step.label }}</div>
</div>
</div>
<div class="flow-detail-cards">
<template v-for="step in flowSteps" :key="`d-${step.key}`">
<div
v-if="step.hasDetailCard"
class="flow-detail-card"
:class="'flow-detail-card--' + step.dotClass"
>
<div class="flow-detail-card__header">
<span class="flow-detail-card__dot" :class="step.dotClass">{{
step.dotIcon
}}</span>
<span class="flow-detail-card__title" :class="step.labelClass">{{
step.label
}}</span>
</div>
<div class="flow-detail-card__body">
<template v-if="step.key === 'pay'">
<div class="flow-detail-card__kv">
<span class="flow-detail-card__label">确认状态</span>
<span class="flow-detail-card__value">
<el-tag type="success" size="small">已提交</el-tag>
</span>
</div>
<div v-if="payment?.remark" class="flow-detail-card__kv">
<span class="flow-detail-card__label">备注</span>
<span class="flow-detail-card__value">{{ payment.remark }}</span>
</div>
<div v-if="transferAttachmentFiles.length" class="flow-detail-card__kv">
<span class="flow-detail-card__label">转账凭证</span>
<ProtocolAttachmentReadonly
:files="transferAttachmentFiles"
@preview="(f) => emit('preview', f)"
@download="(f) => emit('download', f)"
/>
</div>
</template>
<template v-else-if="step.key === 'receipt-finance'">
<div class="flow-detail-card__kv">
<span class="flow-detail-card__label">确认状态</span>
<span class="flow-detail-card__value">
<el-tag v-if="isReceiptFinanceConfirmed" type="success" size="small"
>已确认</el-tag
>
<el-tag v-else type="warning" size="small">待确认</el-tag>
</span>
</div>
<div
v-if="isReceiptFinanceConfirmed && receiptFinanceTime"
class="flow-detail-card__kv"
>
<span class="flow-detail-card__label">确认时间</span>
<span class="flow-detail-card__value">{{ receiptFinanceTime }}</span>
</div>
<div
v-if="isReceiptFinanceConfirmed && payment?.financeRemark"
class="flow-detail-card__kv"
>
<span class="flow-detail-card__label">财务备注</span>
<span class="flow-detail-card__value">{{ payment.financeRemark }}</span>
</div>
<div
v-if="isReceiptFinanceConfirmed && financeAttachmentFiles.length"
class="flow-detail-card__kv"
>
<span class="flow-detail-card__label">财务附件</span>
<ProtocolAttachmentReadonly
:files="financeAttachmentFiles"
@preview="(f) => emit('preview', f)"
@download="(f) => emit('download', f)"
/>
</div>
</template>
<template v-else-if="step.key === 'refund-apply'">
<div class="flow-detail-card__kv">
<span class="flow-detail-card__label">退费金额(元)</span>
<span class="flow-detail-card__value" :class="payDetailColorClass(payStatus)">{{
fmtMoney(payment?.refundAmount)
}}</span>
</div>
<div v-if="payment?.refundRemark" class="flow-detail-card__kv">
<span class="flow-detail-card__label">退费备注</span>
<span class="flow-detail-card__value">{{ payment.refundRemark }}</span>
</div>
<div v-if="refundAttachmentFiles.length" class="flow-detail-card__kv">
<span class="flow-detail-card__label">退费附件</span>
<ProtocolAttachmentReadonly
:files="refundAttachmentFiles"
@preview="(f) => emit('preview', f)"
@download="(f) => emit('download', f)"
/>
</div>
</template>
<template v-else-if="step.key === 'refund-finance'">
<div class="flow-detail-card__kv">
<span class="flow-detail-card__label">确认状态</span>
<span class="flow-detail-card__value">
<el-tag type="danger" size="small">已退费</el-tag>
</span>
</div>
<div v-if="refundFinanceTime" class="flow-detail-card__kv">
<span class="flow-detail-card__label">确认时间</span>
<span class="flow-detail-card__value">{{ refundFinanceTime }}</span>
</div>
<div v-if="payment?.refundFinanceRemark" class="flow-detail-card__kv">
<span class="flow-detail-card__label">财务备注</span>
<span class="flow-detail-card__value">{{ payment.refundFinanceRemark }}</span>
</div>
<div v-if="refundFinanceAttachmentFiles.length" class="flow-detail-card__kv">
<span class="flow-detail-card__label">财务附件</span>
<ProtocolAttachmentReadonly
:files="refundFinanceAttachmentFiles"
@preview="(f) => emit('preview', f)"
@download="(f) => emit('download', f)"
/>
</div>
</template>
</div>
</div>
</template>
</div>
</div>
</template>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import ProtocolAttachmentReadonly from '@/views/cell-storage/protocol/ProtocolAttachmentReadonly.vue'
import { formatMoneyDisplay } from '@/utils/money-format'
import { payStatusLabel, payStatusTagType } from '@/utils/status-tag-registry'
const props = defineProps<{
payment?: Record<string, any> | null
}>()
const emit = defineEmits<{
(e: 'preview', file: Record<string, unknown>): void
(e: 'download', file: Record<string, unknown>): void
}>()
interface MiniFlowStep {
key: string
label: string
dotClass: string
dotIcon: string
labelClass: string
connectorToNext?: string
hasDetailCard?: boolean
}
const payStatus = computed(() => String(props.payment?.payStatus || 'dfj'))
const planAmount = computed(
() => props.payment?.paymentAmount ?? props.payment?.amount ?? null
)
const isReceiptFinanceConfirmed = computed(() => {
const s = payStatus.value
return s !== 'jfqrz' && s !== 'dfj'
})
const receiptFinanceTime = computed(
() => props.payment?.financeConfirmTime || props.payment?.updateTime || ''
)
const refundFinanceTime = computed(
() => props.payment?.refundFinanceConfirmTime || props.payment?.updateTime || ''
)
const transferAttachmentFiles = computed(() =>
urlsToAttachmentFiles(String(props.payment?.transferAttachments || ''))
)
const financeAttachmentFiles = computed(() =>
urlsToAttachmentFiles(String(props.payment?.financeConfirmAttachments || ''))
)
const refundAttachmentFiles = computed(() =>
urlsToAttachmentFiles(String(props.payment?.refundAttachments || ''))
)
const refundFinanceAttachmentFiles = computed(() =>
urlsToAttachmentFiles(String(props.payment?.refundFinanceConfirmAttachments || ''))
)
const flowSteps = computed(() => buildMiniFlowSteps(props.payment || {}))
function dash(v: unknown) {
if (v == null || v === '') return '—'
return String(v)
}
function fmtMoney(v: unknown) {
if (v == null || v === '') return '—'
return '¥' + formatMoneyDisplay(v)
}
function urlsToAttachmentFiles(urls: string) {
if (!urls.trim()) return []
return urls
.split(',')
.map((u, i) => {
const url = u.trim()
if (!url) return null
const name = url.includes('/') ? url.split('/').pop() || `附件${i + 1}` : url
return { id: `url_${i}`, fileUrl: url, fileName: name, fileSize: 0 }
})
.filter(Boolean) as Array<Record<string, unknown>>
}
function payDetailColorClass(status: string) {
if (status === 'ytf') return 'red'
if (status === 'tfqrz') return 'amber'
return 'green'
}
function buildMiniFlowSteps(detail: Record<string, any>): MiniFlowStep[] {
const s = String(detail.payStatus || '')
if (s === 'dfj') return []
const steps: MiniFlowStep[] = []
steps.push({
key: 'pay',
label: '缴费确认',
dotClass: 'done',
dotIcon: '✓',
labelClass: 'done',
connectorToNext: 'done',
hasDetailCard: true
})
if (s === 'jfqrz') {
steps.push({
key: 'receipt-finance',
label: '财务确认',
dotClass: 'current-amber',
dotIcon: '●',
labelClass: 'current-amber',
hasDetailCard: true
})
} else {
steps.push({
key: 'receipt-finance',
label: '财务确认',
dotClass: 'done',
dotIcon: '✓',
labelClass: 'done',
connectorToNext: s === 'yjf' ? undefined : 'done',
hasDetailCard: true
})
}
if (s === 'tfqrz' || s === 'ytf') {
steps.push({
key: 'refund-apply',
label: '退费申请',
dotClass: s === 'tfqrz' ? 'current-amber' : 'done',
dotIcon: s === 'tfqrz' ? '●' : '✓',
labelClass: s === 'tfqrz' ? 'current-amber' : 'done',
connectorToNext: s === 'tfqrz' ? 'pending-gray' : 'done-red',
hasDetailCard: true
})
}
if (s === 'tfqrz') {
steps.push({
key: 'refund-finance',
label: '退费确认',
dotClass: 'pending-gray',
dotIcon: '○',
labelClass: 'pending-gray',
hasDetailCard: false
})
} else if (s === 'ytf') {
steps.push({
key: 'refund-finance',
label: '退费确认',
dotClass: 'done-red',
dotIcon: '✓',
labelClass: 'done-red',
hasDetailCard: true
})
}
if (steps.length) {
delete steps[steps.length - 1].connectorToNext
}
return steps
}
function miniFlowConnectorStyle(total: number, index: number) {
const leftPct = ((index + 0.5) / total) * 100
const widthPct = 100 / total
return `left: calc(${leftPct}% + 12px); width: calc(${widthPct}% - 12px);`
}
</script>
<style scoped lang="scss">
.payment-detail-card {
background: #fff;
border-radius: 8px;
padding: 14px 16px;
border: 1px solid #e2e8f0;
&--refunded {
border-left: 3px solid #dc2626;
border-color: #e2e8f0;
border-left-color: #dc2626;
}
&--refund-pending {
border-left: 3px solid #d97706;
border-color: #e2e8f0;
border-left-color: #d97706;
}
}
.pdc-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
padding-bottom: 10px;
border-bottom: 1px solid #f1f5f9;
}
.pdc-header-left {
display: flex;
align-items: center;
gap: 6px;
font-size: 14px;
font-weight: 600;
color: #1e293b;
&::before {
content: '';
width: 2px;
height: 14px;
border-radius: 1px;
flex-shrink: 0;
}
&.green::before {
background: #10b981;
}
&.red::before {
background: #dc2626;
}
&.amber::before {
background: #d97706;
}
}
.pdc-header-amount {
font-size: 14px;
font-weight: 700;
margin-left: 4px;
&.green {
color: #059669;
}
&.red {
color: #dc2626;
}
&.amber {
color: #d97706;
}
}
.pdc-info-row {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 14px 20px;
margin-bottom: 12px;
}
.pdc-info-item {
display: flex;
flex-direction: column;
gap: 2px;
.info-label {
font-size: 11px;
color: #94a3b8;
}
.info-value {
font-size: 13px;
color: #1e293b;
font-weight: 500;
}
}
.pdc-attachments-row {
margin-bottom: 8px;
padding-top: 8px;
border-top: 1px dashed #e2e8f0;
display: flex;
flex-direction: column;
gap: 4px;
.data-label {
font-size: 11px;
color: #94a3b8;
font-weight: 500;
}
}
.flow-section {
margin-top: 12px;
}
.mini-flow {
display: flex;
align-items: center;
gap: 0;
margin: 12px 0;
padding: 10px 14px;
background: #f8fafc;
border-radius: 8px;
position: relative;
}
.mini-flow-step {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
flex: 1;
z-index: 1;
}
.mini-flow-dot {
width: 24px;
height: 24px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: 700;
z-index: 1;
&.done {
background: #10b981;
color: #fff;
box-shadow: 0 0 0 3px rgb(16 185 129 / 15%);
}
&.done-red {
background: #dc2626;
color: #fff;
box-shadow: 0 0 0 3px rgb(220 38 38 / 15%);
}
&.current-amber {
background: #fff;
border: 2px solid #d97706;
color: #d97706;
box-shadow: 0 0 0 3px rgb(217 119 6 / 15%);
}
&.pending-gray {
background: #f1f5f9;
color: #94a3b8;
border: 2px solid #e2e8f0;
}
}
.mini-flow-label {
font-size: 10px;
margin-top: 6px;
text-align: center;
max-width: 80px;
line-height: 1.3;
&.done {
color: #059669;
font-weight: 600;
}
&.done-red {
color: #dc2626;
font-weight: 600;
}
&.current-amber {
color: #d97706;
font-weight: 600;
}
&.pending-gray {
color: #94a3b8;
}
}
.mini-flow-connector {
position: absolute;
top: 22px;
height: 2px;
z-index: 0;
&.done {
background: #10b981;
}
&.done-red {
background: #dc2626;
}
&.pending-gray {
background: #e2e8f0;
}
}
.flow-detail-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 12px;
margin-top: 14px;
}
.flow-detail-card {
border: 1px solid #e2e8f0;
border-radius: 8px;
overflow: hidden;
&--current-amber {
border-color: #fde68a;
background: #fffbeb;
}
&--done-red {
border-left: 3px solid #dc2626;
background: #fff;
}
&--pending-gray {
border-style: dashed;
background: #f8fafc;
}
}
.flow-detail-card__header {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 14px;
border-bottom: 1px solid #f1f5f9;
background: #f8fafc;
.flow-detail-card--done-red & {
background: #fef2f2;
border-bottom-color: #fecaca;
}
.flow-detail-card--current-amber & {
background: #fffbeb;
border-bottom-color: #fde68a;
}
}
.flow-detail-card__dot {
width: 20px;
height: 20px;
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 10px;
font-weight: 700;
flex-shrink: 0;
&.done {
background: #10b981;
color: #fff;
}
&.done-red {
background: #dc2626;
color: #fff;
}
&.current-amber {
background: #fff;
border: 2px solid #d97706;
color: #d97706;
}
&.pending-gray {
background: #f1f5f9;
border: 2px solid #e2e8f0;
color: #94a3b8;
}
}
.flow-detail-card__title {
font-size: 13px;
font-weight: 600;
color: #1e293b;
&.done {
color: #059669;
}
&.done-red {
color: #dc2626;
}
&.current-amber {
color: #d97706;
}
}
.flow-detail-card__body {
padding: 12px 14px;
display: flex;
flex-direction: column;
gap: 8px;
}
.flow-detail-card__kv {
display: flex;
flex-direction: column;
gap: 2px;
}
.flow-detail-card__label {
font-size: 11px;
color: #94a3b8;
}
.flow-detail-card__value {
font-size: 13px;
color: #1e293b;
font-weight: 500;
word-break: break-word;
&.red {
color: #dc2626;
}
&.amber {
color: #d97706;
}
&.green {
color: #059669;
}
}
@media (max-width: 768px) {
.pdc-info-row {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
</style>
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_taskexecutiondialog_vue", "label": "TaskExecutionDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_confirm_refundconfirmtab_vue", "label": "RefundConfirmTab.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L1"}, {"id": "clinical_payment_confirm_refundconfirmtab_formatamount", "label": "formatAmount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L397"}, {"id": "clinical_payment_confirm_refundconfirmtab_fullfileurl", "label": "fullFileUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L402"}, {"id": "clinical_payment_confirm_refundconfirmtab_isimageurl", "label": "isImageUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L408"}, {"id": "clinical_payment_confirm_refundconfirmtab_loaddata", "label": "loadData()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L434"}, {"id": "clinical_payment_confirm_refundconfirmtab_handlestatustabchange", "label": "handleStatusTabChange()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L453"}, {"id": "clinical_payment_confirm_refundconfirmtab_handlesearch", "label": "handleSearch()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L458"}, {"id": "clinical_payment_confirm_refundconfirmtab_handlereset", "label": "handleReset()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L463"}, {"id": "clinical_payment_confirm_refundconfirmtab_openconfirm", "label": "openConfirm()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L469"}, {"id": "clinical_payment_confirm_refundconfirmtab_openviewconfirm", "label": "openViewConfirm()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L477"}, {"id": "clinical_payment_confirm_refundconfirmtab_handlerowdblclick", "label": "handleRowDblClick()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L482"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_confirm_refundconfirmtab_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L347", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_confirm_refundconfirmtab_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L348", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_confirm_refundconfirmtab_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L359", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_confirm_refundconfirmtab_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L364", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_confirm_refundconfirmtab_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_clinical_payment_submit_readonly_index_vue", "relation": "imports_from", "confidence": "EXTRLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_workordertasksublist_vue", "label": "WorkOrderTaskSubList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_infusion_schedule_management_scheduleviewdialog_vue", "label": "ScheduleViewDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/infusion-schedule-management/ScheduleViewDialog.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_api_outbound_release_review_ts", "label": "outbound-release-review.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts", "source_location": "L1"}, {"id": "api_outbound_release_review_fetchoutboundreleasereviewlist", "label": "fetchOutboundReleaseReviewList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts", "source_location": "L154"}, {"id": "api_outbound_release_review_fetchoutboundreleasereviewdetail", "label": "fetchOutboundReleaseReviewDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts", "source_location": "L170"}, {"id": "api_outbound_release_review_submitoutboundreleasereview", "label": "submitOutboundReleaseReview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts", "source_location": "L176"}, {"id": "api_outbound_release_review_batchreviewoutboundrelease", "label": "batchReviewOutboundRelease()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts", "source_location": "L190"}, {"id": "api_outbound_release_review_fetchoutboundreleasematerial", "label": "fetchOutboundReleaseMaterial()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts", "source_location": "L202"}, {"id": "api_outbound_release_review_fetchreleasereviewlist", "label": "fetchReleaseReviewList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts", "source_location": "L208"}, {"id": "api_outbound_release_review_updatereleasereview", "label": "updateReleaseReview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts", "source_location": "L214"}, {"id": "api_outbound_release_review_deletereleasereview", "label": "deleteReleaseReview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts", "source_location": "L221"}, {"id": "api_outbound_release_review_saveoutboundreleasematerial", "label": "saveOutboundReleaseMaterial()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts", "source_location": "L227"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_outbound_release_review_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_http", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_outbound_release_review_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_outbound_release_review_ts", "target": "api_outbound_release_review_fetchoutboundreleasereviewlist", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts", "source_location": "L154", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_outbound_release_review_ts", "target": "api_outbound_release_review_fetchoutboundreleasereviewdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts", "source_location": "L170", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_outbound_release_review_ts", "target": "api_outbound_release_review_submitoutboundreleasereview", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts", "source_location": "L176", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_outbound_release_review_ts", "target": "api_outbound_release_review_batchreviewoutboundrelease", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts", "source_location": "L190", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_outbound_release_review_ts", "target": "api_outbound_release_review_fetchoutboundreleasematerial", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts", "source_location": "L202", "wLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_material_qcmaterialusagetab_vue", "label": "QcMaterialUsageTab.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-material/QcMaterialUsageTab.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "label": "DispatchTaskDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L1"}, {"id": "production_work_order_dispatchtaskdialog_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L291"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "production_work_order_dispatchtaskdialog_if", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L291", "weight": 1.0}], "raw_calls": [{"caller_nid": "production_work_order_dispatchtaskdialog_if", "callee": "initEditor", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L295"}]}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_confirm_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_pilot_application_checkupmanagementtab_vue", "label": "CheckupManagementTab.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L1"}, {"id": "pilot_application_checkupmanagementtab_isrowselectable", "label": "isRowSelectable()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L319"}, {"id": "pilot_application_checkupmanagementtab_handleselectionchange", "label": "handleSelectionChange()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L321"}, {"id": "pilot_application_checkupmanagementtab_loaddata", "label": "loadData()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L337"}, {"id": "pilot_application_checkupmanagementtab_loadinstitutions", "label": "loadInstitutions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L358"}, {"id": "pilot_application_checkupmanagementtab_handlesearch", "label": "handleSearch()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L368"}, {"id": "pilot_application_checkupmanagementtab_handlereset", "label": "handleReset()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L373"}, {"id": "pilot_application_checkupmanagementtab_canfillcheckupinfo", "label": "canFillCheckupInfo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L384"}, {"id": "pilot_application_checkupmanagementtab_canmarkchecked", "label": "canMarkChecked()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L388"}, {"id": "pilot_application_checkupmanagementtab_caneditcheckup", "label": "canEditCheckup()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L391"}, {"id": "pilot_application_checkupmanagementtab_hasprimarycheckupactions", "label": "hasPrimaryCheckupActions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L394"}, {"id": "pilot_application_checkupmanagementtab_hasmorecheckupactions", "label": "hasMoreCheckupActions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L398"}, {"id": "pilot_application_checkupmanagementtab_handledropdowncommand", "label": "handleDropdownCommand()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L405"}, {"id": "pilot_application_checkupmanagementtab_handlefill", "label": "handleFill()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L416"}, {"id": "pilot_application_checkupmanagementtab_handleedit", "label": "handleEdit()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L423"}, {"id": "pilot_application_checkupmanagementtab_onfillsuccess", "label": "onFillSuccess()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L430"}, {"id": "pilot_application_checkupmanagementtab_handleview", "label": "handleView()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L435"}, {"id": "pilot_application_checkupmanagementtab_handlebatchreservefromlist", "label": "handleBatchReserveFromList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L440"}, {"id": "pilot_aLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_pilot_application_infusionscheduletab_vue", "label": "InfusionScheduleTab.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/InfusionScheduleTab.vue", "source_location": "L1"}, {"id": "pilot_application_infusionscheduletab_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/InfusionScheduleTab.vue", "source_location": "L582"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_pilot_application_infusionscheduletab_vue", "target": "pilot_application_infusionscheduletab_if", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/InfusionScheduleTab.vue", "source_location": "L582", "weight": 1.0}], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_taskinputenhancedtable_vue", "label": "TaskInputEnhancedTable.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskInputEnhancedTable.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_refund_confirm_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-refund-confirm/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_pilot_application_pilotapplicationtab_vue", "label": "PilotApplicationTab.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L1"}, {"id": "pilot_application_pilotapplicationtab_loaddata", "label": "loadData()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L367"}, {"id": "pilot_application_pilotapplicationtab_handlesearch", "label": "handleSearch()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L390"}, {"id": "pilot_application_pilotapplicationtab_handlereset", "label": "handleReset()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L395"}, {"id": "pilot_application_pilotapplicationtab_handleview", "label": "handleView()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L407"}, {"id": "pilot_application_pilotapplicationtab_handlecreate", "label": "handleCreate()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L416"}, {"id": "pilot_application_pilotapplicationtab_caneditapplication", "label": "canEditApplication()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L422"}, {"id": "pilot_application_pilotapplicationtab_canvoidapplication", "label": "canVoidApplication()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L425"}, {"id": "pilot_application_pilotapplicationtab_hasprimarystatusactions", "label": "hasPrimaryStatusActions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L428"}, {"id": "pilot_application_pilotapplicationtab_hasmoreactions", "label": "hasMoreActions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L432"}, {"id": "pilot_application_pilotapplicationtab_handledropdowncommand", "label": "handleDropdownCommand()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L434"}, {"id": "pilot_application_pilotapplicationtab_handleedit", "label": "handleEdit()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L448"}, {"id": "pilot_application_pilotapplicationtab_onformsaved", "label": "onFormSaved()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L453"}, {"id": "pilot_application_pilotapplicationtab_handledelete", "label": "handleDelete()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L458"}, {"id": "pilot_application_pilotapplicationtab_runbatchstatusaction", "label": "runBatchStatusAction()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L478"}, {"id": "pilot_application_pilotapplicationtab_handlebatchstart", "label": "handleBatchStart()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L546"}, {"id": "pilot_application_pilotapplicationtab_handlebatchcomplete", "label": "handleBatchComplete()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L555"}, {"id": "pilot_application_pilotapplicationtab_handlebatchvoid", "label": "handleBatchVoid()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue", "source_location": "L564"}, {"id": "pilot_application_pilotapplicationtab_handlestart", "label": "handleStarLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_clinical_payment_submit_readonly_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/clinical-payment-submit-readonly/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordertasksublist_vue", "label": "QcWorkOrderTaskSubList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L1"}, {"id": "qc_work_order_qcworkordertasksublist_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L512"}, {"id": "qc_work_order_qcworkordertasksublist_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L517"}, {"id": "qc_work_order_qcworkordertasksublist_nextmaterialrowkey", "label": "nextMaterialRowKey()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L560"}, {"id": "qc_work_order_qcworkordertasksublist_canfillresult", "label": "canFillResult()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L570"}, {"id": "qc_work_order_qcworkordertasksublist_canstarttask", "label": "canStartTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L581"}, {"id": "qc_work_order_qcworkordertasksublist_hasprimarytaskactions", "label": "hasPrimaryTaskActions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L586"}, {"id": "qc_work_order_qcworkordertasksublist_candeletetask", "label": "canDeleteTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L591"}, {"id": "qc_work_order_qcworkordertasksublist_hasmoretaskactions", "label": "hasMoreTaskActions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L596"}, {"id": "qc_work_order_qcworkordertasksublist_handledropdowncommand", "label": "handleDropdownCommand()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L603"}, {"id": "qc_work_order_qcworkordertasksublist_clearmaterialrow", "label": "clearMaterialRow()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L626"}, {"id": "qc_work_order_qcworkordertasksublist_ismaterialoptiondisabled", "label": "isMaterialOptionDisabled()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L633"}, {"id": "qc_work_order_qcworkordertasksublist_isduplicatematerial", "label": "isDuplicateMaterial()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L638"}, {"id": "qc_work_order_qcworkordertasksublist_handlereceptionattachmentdownload", "label": "handleReceptionAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L808"}, {"id": "qc_work_order_qcworkordertasksublist_normalizeresultparams", "label": "normalizeResultParams()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L812"}, {"id": "qc_work_order_qcworkordertasksublist_toresultnumber", "label": "toResultNumber()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L820"}, {"id": "qc_work_order_qcworkordertasksublist_setresultnumber", "label": "setResultNumber()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L826"}, {"id": "qc_work_order_qcworkordertasksublist_hasresultvalue", "label": "hasResultValue()", "file_type": "code", "source_file": "/UserLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L1"}, {"id": "production_work_order_index_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L557"}, {"id": "production_work_order_index_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L562"}, {"id": "production_work_order_index_shouldshowtempemptyfield", "label": "shouldShowTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L569"}, {"id": "production_work_order_index_formattempemptyfield", "label": "formatTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L572"}, {"id": "production_work_order_index_formatoutboundschedulesortno", "label": "formatOutboundScheduleSortNo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L576"}, {"id": "production_work_order_index_formatoutboundscheduletotalcount", "label": "formatOutboundScheduleTotalCount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L582"}, {"id": "production_work_order_index_handleadd", "label": "handleAdd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L631"}, {"id": "production_work_order_index_handletypetabchange", "label": "handleTypeTabChange()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L640"}, {"id": "production_work_order_index_submitadd", "label": "submitAdd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L646"}, {"id": "production_work_order_index_handlereceptionattachmentpreview", "label": "handleReceptionAttachmentPreview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L911"}, {"id": "production_work_order_index_handlereceptionattachmentdownload", "label": "handleReceptionAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L915"}, {"id": "production_work_order_index_appstatuslabel", "label": "appStatusLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L1029"}, {"id": "production_work_order_index_appstatustagtype", "label": "appStatusTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L1038"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L515", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L516", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L517", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order", "relation": "imports_from", "confidence": "EXTRACTLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_pilot_application_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_outbound_release_review_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/index.vue", "source_location": "L1"}, {"id": "outbound_release_review_index_handleselectionchange", "label": "handleSelectionChange()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/index.vue", "source_location": "L279"}, {"id": "outbound_release_review_index_loaddata", "label": "loadData()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/index.vue", "source_location": "L285"}, {"id": "outbound_release_review_index_handlesearch", "label": "handleSearch()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/index.vue", "source_location": "L302"}, {"id": "outbound_release_review_index_handlereset", "label": "handleReset()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/index.vue", "source_location": "L307"}, {"id": "outbound_release_review_index_handleview", "label": "handleView()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/index.vue", "source_location": "L317"}, {"id": "outbound_release_review_index_openreviewdialog", "label": "openReviewDialog()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/index.vue", "source_location": "L325"}, {"id": "outbound_release_review_index_onreviewsubmitted", "label": "onReviewSubmitted()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/index.vue", "source_location": "L335"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_outbound_release_review_index_vue", "target": "outbound_release_review_index_handleselectionchange", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/index.vue", "source_location": "L279", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_outbound_release_review_index_vue", "target": "outbound_release_review_index_loaddata", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/index.vue", "source_location": "L285", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_outbound_release_review_index_vue", "target": "outbound_release_review_index_handlesearch", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/index.vue", "source_location": "L302", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_outbound_release_review_index_vue", "target": "outbound_release_review_index_handlereset", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/index.vue", "source_location": "L307", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_outbound_release_review_index_vue", "target": "outbound_release_review_index_handleview", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/index.vue", "source_location": "L317", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_outbound_release_review_index_vue", "target": "outbound_release_review_index_openreviewdialog", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/index.vue", "source_location": "L325", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_outbound_release_review_index_vue", "target": "outbound_release_review_index_onreviewsubmitted", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/index.vue", "source_location": "L335", "weight": 1.0}, {"source": "outbound_release_review_index_handlesearch", "target": "outbound_release_review_index_loaddata", "relation": "calls", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_checkup_management_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_types_import_components_d_ts", "label": "components.d.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_pilot_application_applicationformdialog_vue", "label": "ApplicationFormDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationFormDialog.vue", "source_location": "L1"}, {"id": "pilot_application_applicationformdialog_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationFormDialog.vue", "source_location": "L1067"}, {"id": "pilot_application_applicationformdialog_loadclinicalcellproductprices", "label": "loadClinicalCellProductPrices()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationFormDialog.vue", "source_location": "L1928"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_pilot_application_applicationformdialog_vue", "target": "pilot_application_applicationformdialog_if", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationFormDialog.vue", "source_location": "L1067", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_pilot_application_applicationformdialog_vue", "target": "pilot_application_applicationformdialog_loadclinicalcellproductprices", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationFormDialog.vue", "source_location": "L1928", "weight": 1.0}], "raw_calls": [{"caller_nid": "pilot_application_applicationformdialog_if", "callee": "warning", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationFormDialog.vue", "source_location": "L1068"}, {"caller_nid": "pilot_application_applicationformdialog_loadclinicalcellproductprices", "callee": "loadEditData", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationFormDialog.vue", "source_location": "L1931"}]}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_router_guards_beforeeach_ts", "label": "beforeEach.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L1"}, {"id": "guards_beforeeach_getpendingloading", "label": "getPendingLoading()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L75"}, {"id": "guards_beforeeach_resetpendingloading", "label": "resetPendingLoading()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L82"}, {"id": "guards_beforeeach_getrouteinitfailed", "label": "getRouteInitFailed()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L89"}, {"id": "guards_beforeeach_resetrouteinitstate", "label": "resetRouteInitState()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L96"}, {"id": "guards_beforeeach_setupbeforeeachguard", "label": "setupBeforeEachGuard()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L104"}, {"id": "guards_beforeeach_closeloading", "label": "closeLoading()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L128"}, {"id": "guards_beforeeach_handlerouteguard", "label": "handleRouteGuard()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L140"}, {"id": "guards_beforeeach_handleloginstatus", "label": "handleLoginStatus()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L204"}, {"id": "guards_beforeeach_isstaticroute", "label": "isStaticRoute()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L232"}, {"id": "guards_beforeeach_handledynamicroutes", "label": "handleDynamicRoutes()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L262"}, {"id": "guards_beforeeach_fetchuserinfo", "label": "fetchUserInfo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L376"}, {"id": "guards_beforeeach_resetrouterstate", "label": "resetRouterState()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L387"}, {"id": "guards_beforeeach_handlerootpathredirect", "label": "handleRootPathRedirect()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L405"}, {"id": "guards_beforeeach_isunauthorizederror", "label": "isUnauthorizedError()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L422"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_router_guards_beforeeach_ts", "target": "vue_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L38", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_router_guards_beforeeach_ts", "target": "vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L39", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_router_guards_beforeeach_ts", "target": "nprogress", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L40", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_router_guards_beforeeach_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_store_modules_setting", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L41", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_router_guards_beforeeach_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_store_modules_user", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/guards/beforeEach.ts", "source_location": "L42", "weight": 1.0}, {"source": "users_wuzilong_work_00Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_auth_login_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/auth/login/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_types_import_components_d_ts", "label": "components.d.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_confirm_refundconfirmtab_vue", "label": "RefundConfirmTab.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L1"}, {"id": "clinical_payment_confirm_refundconfirmtab_formatamount", "label": "formatAmount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L396"}, {"id": "clinical_payment_confirm_refundconfirmtab_fullfileurl", "label": "fullFileUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L401"}, {"id": "clinical_payment_confirm_refundconfirmtab_isimageurl", "label": "isImageUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L407"}, {"id": "clinical_payment_confirm_refundconfirmtab_loaddata", "label": "loadData()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L433"}, {"id": "clinical_payment_confirm_refundconfirmtab_handlestatustabchange", "label": "handleStatusTabChange()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L452"}, {"id": "clinical_payment_confirm_refundconfirmtab_handlesearch", "label": "handleSearch()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L457"}, {"id": "clinical_payment_confirm_refundconfirmtab_handlereset", "label": "handleReset()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L462"}, {"id": "clinical_payment_confirm_refundconfirmtab_openconfirm", "label": "openConfirm()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L468"}, {"id": "clinical_payment_confirm_refundconfirmtab_openviewconfirm", "label": "openViewConfirm()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L476"}, {"id": "clinical_payment_confirm_refundconfirmtab_handlerowdblclick", "label": "handleRowDblClick()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L481"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_confirm_refundconfirmtab_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L347", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_confirm_refundconfirmtab_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L348", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_confirm_refundconfirmtab_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L358", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_confirm_refundconfirmtab_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue", "source_location": "L363", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_confirm_refundconfirmtab_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_clinical_payment_submit_readonly_index_vue", "relation": "imports_from", "confidence": "EXTRLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_store_modules_user_ts", "label": "user.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/user.ts", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_store_modules_user_ts", "target": "pinia", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/user.ts", "source_location": "L15", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_store_modules_user_ts", "target": "vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/user.ts", "source_location": "L16", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_store_modules_user_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_enums_appenum", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/user.ts", "source_location": "L17", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_store_modules_user_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/user.ts", "source_location": "L18", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_store_modules_user_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_store_modules_worktab", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/user.ts", "source_location": "L19", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_store_modules_user_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_types_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/user.ts", "source_location": "L20", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_store_modules_user_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_router_guards_beforeeach", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/user.ts", "source_location": "L21", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_store_modules_user_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_store_modules_menu", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/user.ts", "source_location": "L22", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_store_modules_user_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_storage_storage_config", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/user.ts", "source_location": "L23", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_store_modules_user_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_auth", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/user.ts", "source_location": "L24", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_store_modules_user_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_router_routesalias", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/user.ts", "source_location": "L25", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_store_modules_user_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/user.ts", "source_location": "L26", "weight": 1.0}], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_clinical_payment_submit_readonly_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/clinical-payment-submit-readonly/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_edittaskinfodialog_vue", "label": "EditTaskInfoDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue", "source_location": "L1"}, {"id": "production_work_order_edittaskinfodialog_loadtaskdetail", "label": "loadTaskDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue", "source_location": "L81"}, {"id": "production_work_order_edittaskinfodialog_handleclose", "label": "handleClose()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue", "source_location": "L93"}, {"id": "production_work_order_edittaskinfodialog_handlesubmit", "label": "handleSubmit()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue", "source_location": "L100"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_edittaskinfodialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue", "source_location": "L55", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_edittaskinfodialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_task", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue", "source_location": "L56", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_edittaskinfodialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue", "source_location": "L57", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_edittaskinfodialog_vue", "target": "production_work_order_edittaskinfodialog_loadtaskdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue", "source_location": "L81", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_edittaskinfodialog_vue", "target": "production_work_order_edittaskinfodialog_handleclose", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue", "source_location": "L93", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_edittaskinfodialog_vue", "target": "production_work_order_edittaskinfodialog_handlesubmit", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue", "source_location": "L100", "weight": 1.0}, {"source": "production_work_order_edittaskinfodialog_handlesubmit", "target": "production_work_order_edittaskinfodialog_handleclose", "relation": "calls", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue", "source_location": "L113", "weight": 1.0}], "raw_calls": [{"caller_nid": "production_work_order_edittaskinfodialog_loadtaskdetail", "callee": "fetchProductionTaskDetail", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue", "source_location": "L84"}, {"caller_nid": "production_work_order_edittaskinfodialog_handlesubmit", "callee": "validate", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue", "source_location": "L102"}, {"caller_nid": "production_work_order_edittaskinfodialog_handlesubmit", "callee": "fetchUpdateProductionTask", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue", "source_location": "L106"}, {"caller_nid": "production_work_order_edittaskinfodialog_handlesubmit", "callee": "success", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue", "source_location": "L111"}, {"caller_nid": "production_work_order_edittaskinfodialLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_task_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_info_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-info/index.vue", "source_location": "L1"}, {"id": "clinical_payment_info_index_formatamount", "label": "formatAmount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-info/index.vue", "source_location": "L622"}, {"id": "clinical_payment_info_index_fullfileurl", "label": "fullFileUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-info/index.vue", "source_location": "L627"}, {"id": "clinical_payment_info_index_isimageurl", "label": "isImageUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-info/index.vue", "source_location": "L633"}, {"id": "clinical_payment_info_index_handledownloadfile", "label": "handleDownloadFile()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-info/index.vue", "source_location": "L637"}, {"id": "clinical_payment_info_index_handleselectionchange", "label": "handleSelectionChange()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-info/index.vue", "source_location": "L643"}, {"id": "clinical_payment_info_index_loaddata", "label": "loadData()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-info/index.vue", "source_location": "L647"}, {"id": "clinical_payment_info_index_handlestatustabchange", "label": "handleStatusTabChange()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-info/index.vue", "source_location": "L663"}, {"id": "clinical_payment_info_index_resetreceiptform", "label": "resetReceiptForm()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-info/index.vue", "source_location": "L669"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_info_index_vue", "target": "clinical_payment_info_index_formatamount", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-info/index.vue", "source_location": "L622", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_info_index_vue", "target": "clinical_payment_info_index_fullfileurl", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-info/index.vue", "source_location": "L627", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_info_index_vue", "target": "clinical_payment_info_index_isimageurl", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-info/index.vue", "source_location": "L633", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_info_index_vue", "target": "clinical_payment_info_index_handledownloadfile", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-info/index.vue", "source_location": "L637", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_info_index_vue", "target": "clinical_payment_info_index_handleselectionchange", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-info/index.vue", "source_location": "L643", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_info_index_vue", "target": "clinical_payment_info_index_loaddata", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-info/index.vue", "source_location": "L647", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_info_index_vue", "target": "clinical_payment_info_index_handlestatustabchange", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-info/index.vue", "source_location": "L663", "weight": 1.0}, {"source": "users_wuzilong_work_0Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_infusion_schedule_management_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/infusion-schedule-management/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_taskinputenhancedtable_vue", "label": "TaskInputEnhancedTable.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskInputEnhancedTable.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_router_modules_sqxp_ts", "label": "sqxp.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/modules/sqxp.ts", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_router_modules_sqxp_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_types_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/modules/sqxp.ts", "source_location": "L1", "weight": 1.0}], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_clinical_payment_confirm_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_taskoutputproductdialog_vue", "label": "TaskOutputProductDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskOutputProductDialog.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_router_ts", "label": "router.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L1"}, {"id": "utils_router_configurenprogress", "label": "configureNProgress()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L24"}, {"id": "utils_router_setpagetitle", "label": "setPageTitle()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L37"}, {"id": "utils_router_formatmenutitle", "label": "formatMenuTitle()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L51"}, {"id": "utils_router_resolvesaferedirecttarget", "label": "resolveSafeRedirectTarget()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L70"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_router_ts", "target": "vue_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L8", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_router_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_config", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_router_ts", "target": "nprogress", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L10", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_router_ts", "target": "nprogress_css", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L11", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_router_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_locales", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L12", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_router_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_router_routesalias", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L13", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_router_ts", "target": "utils_router_configurenprogress", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L24", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_router_ts", "target": "utils_router_setpagetitle", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L37", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_router_ts", "target": "utils_router_formatmenutitle", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L51", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_router_ts", "target": "utils_router_resolvesaferedirecttarget", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L70", "weight": 1.0}], "raw_calls": [{"caller_nid": "utils_router_configurenprogress", "callee": "configure", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L25"}, {"caller_nid": "utils_router_setpagetitle", "callee": "setTimeout", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L40"}, {"caller_nid": "utils_router_formatmenutitle", "callee": "startsWith", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L53"}, {"caller_nid": "utils_router_formatmenutitle", "callee": "te", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L55"}, {"caller_nid": "utils_router_formatmenutitle", "callee": "$t", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts", "source_location": "L56"}, {"caller_nid": "utils_router_formatmenutitle", "callee": "pop", "Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business_ts", "label": "business.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L1"}, {"id": "api_business_fetchorderlist", "label": "fetchOrderList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L7"}, {"id": "api_business_fetchorderdetail", "label": "fetchOrderDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L33"}, {"id": "api_business_fetchassigndelivery", "label": "fetchAssignDelivery()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L39"}, {"id": "api_business_fetchreviewcancel", "label": "fetchReviewCancel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L55"}, {"id": "api_business_fetchcancelorder", "label": "fetchCancelOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L62"}, {"id": "api_business_fetchorderadjusts", "label": "fetchOrderAdjusts()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L78"}, {"id": "api_business_fetchadjustorder", "label": "fetchAdjustOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L84"}, {"id": "api_business_fetchorderitems", "label": "fetchOrderItems()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L109"}, {"id": "api_business_fetchpriceversiondetail", "label": "fetchPriceVersionDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L115"}, {"id": "api_business_fetchuploadattachment", "label": "fetchUploadAttachment()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L121"}, {"id": "api_business_fetchattachmentdownloadurl", "label": "fetchAttachmentDownloadUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L135"}, {"id": "api_business_fetchuploadproductimage", "label": "fetchUploadProductImage()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L142"}, {"id": "api_business_fetchsystemconfig", "label": "fetchSystemConfig()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L149"}, {"id": "api_business_fetchclinicalpayments", "label": "fetchClinicalPayments()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L157"}, {"id": "api_business_fetchclinicalpaymentdetail", "label": "fetchClinicalPaymentDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L164"}, {"id": "api_business_submitclinicalreceipt", "label": "submitClinicalReceipt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L170"}, {"id": "api_business_batchsubmitclinicalreceipt", "label": "batchSubmitClinicalReceipt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L177"}, {"id": "api_business_confirmclinicalreceipt", "label": "confirmClinicalReceipt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L184"}, {"id": "api_business_submitclinicalrefund", "label": "submitClinicalRefund()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L191"}, {"id": "api_business_batchsubmitclinicalrefund", "label": "batchSubmitClinicalRefund()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L198"}, {"id": "api_business_confirmclinicalrefund", "label": "confirmClinicalRefund()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L205"}, {"id": "api_business_fetchclinicalreceiptpending", "label": "fetchClinicalReceiptPending()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/business.ts", "source_location": "L212"}, {"id": "api_business_fetchclinicalreceiptconfirmed", "label": "fetchClinicalReceiptConfirmed()", "file_type": "code", "source_file": "/Users/wuzilong/work/0Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1"}, {"id": "qc_work_order_index_formattempcellproductfield", "label": "formatTempCellProductField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L839"}, {"id": "qc_work_order_index_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L862"}, {"id": "qc_work_order_index_handlereceptionattachmentpreview", "label": "handleReceptionAttachmentPreview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1212"}, {"id": "qc_work_order_index_handlereceptionattachmentdownload", "label": "handleReceptionAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1217"}, {"id": "qc_work_order_index_taskattachmentfullurl", "label": "taskAttachmentFullUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1221"}, {"id": "qc_work_order_index_handletaskattachmentpreview", "label": "handleTaskAttachmentPreview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1228"}, {"id": "qc_work_order_index_handletaskattachmentdownload", "label": "handleTaskAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1233"}, {"id": "qc_work_order_index_formatconfiguredlabitems", "label": "formatConfiguredLabItems()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1249"}, {"id": "qc_work_order_index_formatconfiguredthirditems", "label": "formatConfiguredThirdItems()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1255"}, {"id": "qc_work_order_index_buildtasktypesections", "label": "buildTaskTypeSections()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1266"}, {"id": "qc_work_order_index_buildconfiguredonlysection", "label": "buildConfiguredOnlySection()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1355"}, {"id": "qc_work_order_index_formatdetectmethods", "label": "formatDetectMethods()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1373"}, {"id": "qc_work_order_index_formatmetric", "label": "formatMetric()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1380"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_formattempcellproductfield", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L839", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_if", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L862", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_handlereceptionattachmentpreview", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1212", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_handlereceptionattachmentdownload", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_types_import_components_d_ts", "label": "components.d.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_outbound_release_review_outboundreleaseviewdialog_vue", "label": "OutboundReleaseViewDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/OutboundReleaseViewDialog.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_pilot_application_applicationviewdialog_vue", "label": "ApplicationViewDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationViewDialog.vue", "source_location": "L1"}, {"id": "pilot_application_applicationviewdialog_for", "label": "for()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationViewDialog.vue", "source_location": "L966"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_pilot_application_applicationviewdialog_vue", "target": "pilot_application_applicationviewdialog_for", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationViewDialog.vue", "source_location": "L966", "weight": 1.0}], "raw_calls": [{"caller_nid": "pilot_application_applicationviewdialog_for", "callee": "trim", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationViewDialog.vue", "source_location": "L967"}, {"caller_nid": "pilot_application_applicationviewdialog_for", "callee": "Number", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationViewDialog.vue", "source_location": "L970"}, {"caller_nid": "pilot_application_applicationviewdialog_for", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationViewDialog.vue", "source_location": "L971"}, {"caller_nid": "pilot_application_applicationviewdialog_for", "callee": "set", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationViewDialog.vue", "source_location": "L973"}]}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_router_modules_sqxp_ts", "label": "sqxp.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/modules/sqxp.ts", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_router_modules_sqxp_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_types_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/modules/sqxp.ts", "source_location": "L1", "weight": 1.0}], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_clinical_schedule_payment_detail_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/clinical-schedule-payment-detail/index.vue", "source_location": "L1"}, {"id": "clinical_schedule_payment_detail_index_dash", "label": "dash()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/clinical-schedule-payment-detail/index.vue", "source_location": "L254"}, {"id": "clinical_schedule_payment_detail_index_fmtmoney", "label": "fmtMoney()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/clinical-schedule-payment-detail/index.vue", "source_location": "L259"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_clinical_schedule_payment_detail_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolattachmentreadonly_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/clinical-schedule-payment-detail/index.vue", "source_location": "L194", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_clinical_schedule_payment_detail_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_money_format", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/clinical-schedule-payment-detail/index.vue", "source_location": "L195", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_clinical_schedule_payment_detail_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_status_tag_registry", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/clinical-schedule-payment-detail/index.vue", "source_location": "L196", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_clinical_schedule_payment_detail_index_vue", "target": "clinical_schedule_payment_detail_index_dash", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/clinical-schedule-payment-detail/index.vue", "source_location": "L254", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_clinical_schedule_payment_detail_index_vue", "target": "clinical_schedule_payment_detail_index_fmtmoney", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/clinical-schedule-payment-detail/index.vue", "source_location": "L259", "weight": 1.0}], "raw_calls": [{"caller_nid": "clinical_schedule_payment_detail_index_dash", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/clinical-schedule-payment-detail/index.vue", "source_location": "L256"}, {"caller_nid": "clinical_schedule_payment_detail_index_fmtmoney", "callee": "formatMoneyDisplay", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/clinical-schedule-payment-detail/index.vue", "source_location": "L261"}]}
@@ -206,6 +206,12 @@ function handleLoginStatus(
userStore: ReturnType<typeof useUserStore>,
next: NavigationGuardNext
): boolean {
// 已登录用户访问登录页时,进入系统首页(由动态路由守卫解析具体落点)
if (userStore.isLogin && to.path === RoutesAlias.Login) {
next({ path: '/', replace: true })
return false
}
// 已登录或访问登录页或静态路由,直接放行
if (userStore.isLogin || to.path === RoutesAlias.Login || isStaticRoute(to.path)) {
return true
+18 -10
View File
@@ -40,7 +40,7 @@ export const sqxpAdminRoutes: AppRouteRecord[] = [
path: 'protocol-audit',
component: '/cell-storage/protocol-audit/index',
meta: {
title: '采集协议单管理',
title: '采集协议单',
keepAlive: true,
menuCode: 'biz:cellStorageProtocolAudit:list'
}
@@ -175,7 +175,7 @@ export const sqxpAdminRoutes: AppRouteRecord[] = [
path: 'audit',
component: '/research-donation/audit/index',
meta: {
title: '捐赠协议单管理',
title: '捐赠协议单',
keepAlive: true,
menuCode: 'biz:researchDonationAudit:list'
}
@@ -207,7 +207,8 @@ export const sqxpAdminRoutes: AppRouteRecord[] = [
title: '中试服务申请单',
keepAlive: true,
menuCode: 'pilot-service:pilot-application:list'
}
},
props: { bizType: 'pilot_service' }
},
{
id: 'PIL00000000000000000000000000002',
@@ -219,7 +220,8 @@ export const sqxpAdminRoutes: AppRouteRecord[] = [
keepAlive: false,
isHide: true,
menuCode: 'pilot-service:checkup-management:list'
}
},
props: { bizType: 'pilot_service' }
},
{
id: 'PIL00000000000000000000000000003',
@@ -231,7 +233,8 @@ export const sqxpAdminRoutes: AppRouteRecord[] = [
keepAlive: false,
isHide: true,
menuCode: 'pilot-service:infusion-schedule-management:list'
}
},
props: { bizType: 'pilot_service' }
},
{
id: 'PIL00000000000000000000000000004',
@@ -242,7 +245,8 @@ export const sqxpAdminRoutes: AppRouteRecord[] = [
title: '出库放行审核',
keepAlive: true,
menuCode: 'pilot-service:outbound-release-review:list'
}
},
props: { bizType: 'pilot_service' }
}
]
},
@@ -282,6 +286,7 @@ export const sqxpAdminRoutes: AppRouteRecord[] = [
meta: {
title: '体检管理',
keepAlive: true,
isHide: true,
menuCode: 'clinical-application:checkup-management:list'
},
props: { bizType: 'clinical_application' }
@@ -293,7 +298,8 @@ export const sqxpAdminRoutes: AppRouteRecord[] = [
component: '/pilot-service/infusion-schedule-management/index',
meta: {
title: '输注计划管理',
keepAlive: true,
keepAlive: false,
isHide: true,
menuCode: 'clinical-application:infusion-schedule-management:list'
},
props: { bizType: 'clinical_application' }
@@ -305,7 +311,8 @@ export const sqxpAdminRoutes: AppRouteRecord[] = [
component: '/pilot-service/clinical-payment-info/index',
meta: {
title: '缴费信息',
keepAlive: true,
keepAlive: false,
isHide: true,
menuCode: 'clinical-application:payment-info:list'
}
},
@@ -315,7 +322,7 @@ export const sqxpAdminRoutes: AppRouteRecord[] = [
path: 'clinical-payment-confirm',
component: '/pilot-service/clinical-payment-confirm/index',
meta: {
title: '缴费确认(财务)',
title: '缴退费财务确认',
keepAlive: true,
menuCode: 'clinical-application:payment-confirm:list'
}
@@ -327,7 +334,8 @@ export const sqxpAdminRoutes: AppRouteRecord[] = [
component: '/pilot-service/clinical-refund-confirm/index',
meta: {
title: '退费确认(财务)',
keepAlive: true,
keepAlive: false,
isHide: true,
menuCode: 'clinical-application:refund-confirm:list'
}
},
+6 -2
View File
@@ -18,11 +18,12 @@ import { LanguageEnum } from '@/enums/appEnum'
import { router } from '@/router'
import { useWorktabStore } from './worktab'
import { AppRouteRecord } from '@/types/router'
import { setPageTitle } from '@/utils/router'
import { resetRouterState } from '@/router/guards/beforeEach'
import { useMenuStore } from './menu'
import { StorageConfig } from '@/utils/storage/storage-config'
import { fetchLogout } from '@/api/auth'
import { RoutesAlias } from '@/router/routesAlias'
import { resolveSafeRedirectTarget } from '@/utils/router'
/**
* 用户状态管理
@@ -135,7 +136,10 @@ export const useUserStore = defineStore(
resetRouterState(500)
// 跳转到登录页,携带当前路由作为 redirect 参数
const currentRoute = router.currentRoute.value
const redirect = currentRoute.path !== '/login' ? currentRoute.fullPath : undefined
const redirect =
currentRoute.path !== RoutesAlias.Login
? resolveSafeRedirectTarget(currentRoute.fullPath, '')
: ''
router.push({
name: 'Login',
query: redirect ? { redirect } : undefined
+19
View File
@@ -10,6 +10,10 @@ import AppConfig from '@/config'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import i18n, { $t } from '@/locales'
import { RoutesAlias } from '@/router/routesAlias'
/** 历史遗留登录路径(与 RoutesAlias.Login 等价) */
const LEGACY_LOGIN_PATHS = new Set([RoutesAlias.Login, '/login'])
/** 扩展的路由配置类型 */
export type AppRouteRecordRaw = RouteRecordRaw & {
@@ -59,3 +63,18 @@ export const formatMenuTitle = (title: string): string => {
}
return ''
}
/**
* 解析登录后的安全跳转地址,避免 redirect 指回登录页导致无法进入系统
*/
export function resolveSafeRedirectTarget(redirect: unknown, fallback = '/'): string {
const raw = typeof redirect === 'string' ? redirect.trim() : ''
if (!raw) return fallback
const pathOnly = raw.split('?')[0].split('#')[0]
const normalized = pathOnly.startsWith('/') ? pathOnly : `/${pathOnly}`
if (LEGACY_LOGIN_PATHS.has(normalized)) {
return fallback
}
return raw
}
+6 -3
View File
@@ -86,6 +86,8 @@
<script setup lang="ts">
import { useUserStore } from '@/store/modules/user'
import { fetchLogin } from '@/api/auth'
import { resetRouteInitState } from '@/router/guards/beforeEach'
import { resolveSafeRedirectTarget } from '@/utils/router'
import { ElNotification, type FormInstance, type FormRules } from 'element-plus'
import { ElMessage } from 'element-plus'
import { User, Lock } from '@element-plus/icons-vue'
@@ -143,9 +145,10 @@
message: `欢迎回来,${userInfo.realName || userInfo.username}!`
})
// 获取 redirect 参数,如果存在则跳转到指定页面,否则跳转到首页
const redirect = route.query.redirect as string
router.push(redirect || '/')
// 避免 redirect 指回登录页(如登出时误写入 /auth/login)
resetRouteInitState()
const target = resolveSafeRedirectTarget(route.query.redirect)
await router.push(target)
} catch (error: any) {
ElMessage.error(error?.message || '登录失败,请稍后重试')
} finally {
@@ -6,7 +6,7 @@
<div class="panel-top">
<h2>体检记录</h2>
</div>
<CheckupManagementTab />
<CheckupManagementTab :biz-type="bizType" />
</section>
</div>
</template>
@@ -16,6 +16,7 @@
defineOptions({ name: 'CheckupManagement' })
const props = defineProps<{ bizType?: string }>()
const router = useRouter()
const route = useRoute()
const isPilotRedirect = computed(() => route.name === 'PilotCheckupManagement')
@@ -0,0 +1,701 @@
<!-- 缴退费财务确认 · 退费 Tab(临床应用) -->
<!-- eslint-disable vue/no-v-model-argument -->
<template>
<div class="refund-confirm-tab">
<el-tabs
v-model="activeTab"
class="work-order-type-tabs"
@tab-change="handleStatusTabChange"
>
<el-tab-pane label="待确认" name="pending" />
<el-tab-pane label="已确认" name="confirmed" />
</el-tabs>
<div class="refund-confirm-body">
<div class="filter-block">
<el-form :model="searchForm" class="filter-form" label-position="top" @submit.prevent>
<div class="filter-grid">
<el-form-item label="关键词">
<el-input
v-model="searchForm.keyword"
placeholder="申请单号/患者姓名"
clearable
@keyup.enter="handleSearch"
/>
</el-form-item>
</div>
<div class="filter-actions-row">
<span class="filter-hint">支持按申请单号、患者姓名模糊检索。</span>
<div class="filter-actions-end">
<el-button class="btn-ghost" @click="handleReset">
<el-icon><RefreshLeft /></el-icon>重置
</el-button>
<el-button class="btn-main" type="primary" @click="handleSearch">
<el-icon><Search /></el-icon>搜索
</el-button>
</div>
</div>
</el-form>
</div>
<div class="list-body list-wrap refund-confirm-table-wrap">
<el-table
class="list-table"
:data="tableData"
v-loading="loading"
stripe
row-key="id"
@row-dblclick="handleRowDblClick"
>
<el-table-column
type="index"
label="序号"
min-width="68"
align="center"
header-align="center"
:index="(index) => (pagination.page - 1) * pagination.pageSize + index + 1"
/>
<el-table-column
prop="applicationNo"
label="申请单号"
min-width="140"
align="center"
header-align="center"
/>
<el-table-column
prop="patientName"
label="患者姓名"
min-width="100"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.patientName || '-' }}</template>
</el-table-column>
<el-table-column
prop="channelName"
label="渠道名称"
min-width="120"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.channelName || '-' }}</template>
</el-table-column>
<el-table-column
prop="cellTypeSpec"
label="细胞类型/规格"
min-width="130"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.cellTypeSpec || '-' }}</template>
</el-table-column>
<el-table-column
prop="infusionTime"
label="输注时间"
min-width="130"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.infusionTime || '-' }}</template>
</el-table-column>
<el-table-column
prop="paymentAmount"
label="缴费金额(元)"
min-width="130"
align="center"
header-align="center"
>
<template #default="{ row }">
<span class="amount-text">{{ formatAmount(row.paymentAmount) }}</span>
</template>
</el-table-column>
<el-table-column
prop="refundAmount"
label="退费金额(元)"
min-width="130"
align="center"
header-align="center"
>
<template #default="{ row }">
<span class="amount-text">{{ formatAmount(row.refundAmount) }}</span>
</template>
</el-table-column>
<el-table-column
prop="payStatus"
label="状态"
min-width="110"
align="center"
header-align="center"
>
<template #default>
<el-tag :type="activeTab === 'pending' ? 'warning' : 'success'" size="small">
{{ activeTab === 'pending' ? '退费确认中' : '已退费' }}
</el-tag>
</template>
</el-table-column>
<el-table-column
v-if="activeTab === 'confirmed'"
prop="updateTime"
label="确认时间"
min-width="170"
align="center"
header-align="center"
/>
<el-table-column
v-if="activeTab === 'confirmed'"
prop="refundFinanceRemark"
label="财务备注"
min-width="120"
align="center"
header-align="center"
show-overflow-tooltip
>
<template #default="{ row }">{{ row.refundFinanceRemark || '-' }}</template>
</el-table-column>
<el-table-column
v-if="activeTab === 'pending'"
prop="createTime"
label="创建时间"
min-width="170"
align="center"
header-align="center"
/>
<el-table-column
label="操作"
min-width="140"
fixed="right"
align="center"
header-align="center"
>
<template #default="{ row }">
<el-button
v-if="activeTab === 'pending'"
class="btn-op-item primary"
@click="openConfirm(row)"
>
<el-icon><Check /></el-icon>确认退费
</el-button>
<el-button v-else class="btn-op-item" @click="openViewConfirm(row)">
<el-icon><View /></el-icon>查看确认信息
</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination list-pager-bar">
<el-pagination
:current-page="pagination.page"
:page-size="pagination.pageSize"
:total="pagination.total"
:page-sizes="[10, 20, 50]"
layout="total, sizes, prev, pager, next"
@size-change="(val) => ((pagination.page = 1), (pagination.pageSize = val), loadData())"
@current-change="(val) => ((pagination.page = val), loadData())"
/>
</div>
</div>
<!-- 确认退费弹窗 -->
<el-dialog
v-model="dialogVisible"
title="确认退费"
width="900px"
class="dialog-form-layout"
align-center
destroy-on-close
:close-on-click-modal="false"
>
<ClinicalPaymentSubmitReadonly
:detail="confirmRow"
mode="refund"
title="退费申请信息(请核对)"
@download="handleDownloadFile"
/>
<div class="form-section-divider" />
<h4 class="detail-section-title">财务确认</h4>
<el-form
ref="confirmFormRef"
:model="confirmForm"
label-position="top"
class="biz-dialog-form"
>
<div class="form-grid-2">
<el-form-item label="财务确认退费备注" class="form-col-span-2">
<el-input
v-model="confirmForm.financeRemark"
type="textarea"
:rows="3"
placeholder="选填"
/>
</el-form-item>
<el-form-item label="附件" class="form-col-span-2">
<div class="attachment-upload">
<div class="attachment-list">
<el-upload
:auto-upload="false"
:show-file-list="false"
:multiple="true"
accept="image/*,video/*,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.zip,.rar"
@change="handleConfirmAttachmentChange"
>
<div class="upload-card">
<el-icon :size="22" color="#10b981"><Plus /></el-icon>
<span class="upload-card-text">上传附件</span>
</div>
</el-upload>
<div
v-for="(file, fIdx) in confirmForm.attachments"
:key="file.id || fIdx"
class="attachment-item"
:class="{ 'is-uploading': file._uploading }"
>
<div class="attachment-preview">
<template v-if="file.fileUrl && isImageUrl(file.fileUrl)">
<img :src="fullFileUrl(file.fileUrl)" :alt="file.fileName" />
</template>
<template v-else>
<div class="attachment-preview__icon attachment-preview__icon--doc">
<el-icon :size="28"><Document /></el-icon>
</div>
</template>
</div>
<div class="attachment-footer">
<span class="attachment-name" :title="file.fileName">{{
file.fileName
}}</span>
<el-icon
class="action-btn"
title="删除"
@click="removeConfirmAttachment(fIdx)"
>
<Delete />
</el-icon>
</div>
</div>
</div>
<p class="form-tip">支持图片、文档等,多个附件将一并提交。</p>
</div>
</el-form-item>
</div>
</el-form>
<template #footer>
<el-button class="btn-ghost" @click="dialogVisible = false">
<el-icon><Close /></el-icon>
取消
</el-button>
<el-button
class="btn-main"
type="primary"
:loading="submitLoading"
@click="submitConfirm"
>
<el-icon><Check /></el-icon>
确认
</el-button>
</template>
</el-dialog>
<!-- 查看确认信息弹窗 -->
<el-dialog
v-model="viewDialogVisible"
title="确认退费信息"
width="900px"
class="dialog-form-layout"
align-center
destroy-on-close
>
<ClinicalPaymentSubmitReadonly
:detail="viewRow"
mode="refund"
title="退费申请信息"
@download="handleDownloadFile"
/>
<div class="form-section-divider" />
<h4 class="detail-section-title">财务确认信息</h4>
<el-form label-position="top" class="biz-dialog-form view-confirm-form">
<div class="form-grid-2">
<el-form-item label="确认时间" class="form-col-span-2">
<span class="view-field-text">{{
viewRow?.refundFinanceConfirmTime || viewRow?.updateTime || '—'
}}</span>
</el-form-item>
<el-form-item label="财务备注" class="form-col-span-2">
<span class="view-field-text view-field-text--multiline">{{
viewRow?.refundFinanceRemark || '—'
}}</span>
</el-form-item>
<el-form-item label="财务确认附件" class="form-col-span-2">
<ProtocolAttachmentReadonly
:files="viewAttachmentFiles"
@download="handleDownloadFile"
/>
</el-form-item>
</div>
</el-form>
<template #footer>
<el-button class="btn-ghost" @click="viewDialogVisible = false">
<el-icon><Close /></el-icon>
关闭
</el-button>
</template>
</el-dialog>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue'
import { ElMessage } from 'element-plus'
import {
Close,
Check,
RefreshLeft,
Search,
View,
Plus,
Document,
Delete
} from '@element-plus/icons-vue'
import {
confirmClinicalRefund,
fetchClinicalRefundPending,
fetchClinicalRefundConfirmed
} from '@/api/business'
import { fetchUploadAttachment } from '@/api/business'
import ClinicalPaymentSubmitReadonly from '@/components/business/clinical-payment-submit-readonly/index.vue'
import ProtocolAttachmentReadonly from '@/views/cell-storage/protocol/ProtocolAttachmentReadonly.vue'
import { formatMoneyDisplay } from '@/utils/money-format'
defineOptions({ name: 'ClinicalRefundConfirmTab' })
const activeTab = ref('pending')
const searchForm = reactive({ keyword: '' })
const tableData = ref<Record<string, unknown>[]>([])
const loading = ref(false)
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
const dialogVisible = ref(false)
const viewDialogVisible = ref(false)
const submitLoading = ref(false)
const currentDetailId = ref<string | null>(null)
const confirmRow = ref<Record<string, unknown> | null>(null)
const viewRow = ref<Record<string, unknown> | null>(null)
const confirmFormRef = ref()
const confirmForm = reactive({
financeRemark: '',
attachments: [] as Array<{
id: string
fileName: string
fileUrl: string
_uploading?: boolean
}>
})
const minioBaseUrl = (import.meta.env.VITE_MINIO_BASE_URL || '').replace(/\/$/, '')
function formatAmount(v: unknown): string {
if (v == null || v === '') return '-'
return '¥' + formatMoneyDisplay(v)
}
function fullFileUrl(url: string) {
if (!url) return ''
if (/^https?:\/\//i.test(url)) return url
return minioBaseUrl ? `${minioBaseUrl}/${url.replace(/^\//, '')}` : url
}
function isImageUrl(url: string) {
return /\.(png|jpe?g|gif|webp|bmp|svg)(\?.*)?$/i.test(url)
}
const viewAttachmentFiles = computed(() => {
const row = viewRow.value
if (!row) return []
const urls = String(row.refundFinanceConfirmAttachments || '')
if (!urls.trim()) return []
return urls
.split(',')
.map((u, i) => {
const url = u.trim()
if (!url) return null
const name = url.includes('/') ? url.split('/').pop() || `附件${i + 1}` : url
return { id: `url_${i}`, fileUrl: url, fileName: name }
})
.filter(Boolean) as Array<Record<string, unknown>>
})
function handleDownloadFile(file: Record<string, unknown>) {
const url = String(file.fileUrl || '')
if (!url) return
window.open(fullFileUrl(url), '_blank')
}
async function loadData() {
loading.value = true
try {
const params = {
page: pagination.page,
pageSize: pagination.pageSize,
keyword: searchForm.keyword || undefined
}
const res =
activeTab.value === 'pending'
? await fetchClinicalRefundPending(params)
: await fetchClinicalRefundConfirmed(params)
tableData.value = res.list || []
pagination.total = res.total ?? 0
} finally {
loading.value = false
}
}
function handleStatusTabChange() {
pagination.page = 1
loadData()
}
function handleSearch() {
pagination.page = 1
loadData()
}
function handleReset() {
searchForm.keyword = ''
pagination.page = 1
loadData()
}
function openConfirm(row: Record<string, unknown>) {
currentDetailId.value = String(row.id)
confirmRow.value = row
confirmForm.financeRemark = ''
confirmForm.attachments = []
dialogVisible.value = true
}
function openViewConfirm(row: Record<string, unknown>) {
viewRow.value = row
viewDialogVisible.value = true
}
function handleRowDblClick(row: Record<string, unknown>) {
if (activeTab.value !== 'pending') openViewConfirm(row)
}
async function handleConfirmAttachmentChange(uploadFile: { raw?: File }) {
const file = uploadFile.raw
if (!file) return
const tempId = `temp_${Date.now()}`
confirmForm.attachments.push({
id: tempId,
fileName: file.name,
fileUrl: '',
_uploading: true
})
const idx = confirmForm.attachments.length - 1
try {
const fd = new FormData()
fd.append('folder', 'clinical-finance-refund')
fd.append('file', file)
const res = await fetchUploadAttachment(fd)
confirmForm.attachments[idx] = {
id: res.id || tempId,
fileName: file.name || res.fileName,
fileUrl: res.fileUrl,
_uploading: false
}
} catch {
ElMessage.error('文件上传失败')
confirmForm.attachments.splice(idx, 1)
}
}
function removeConfirmAttachment(index: number) {
confirmForm.attachments.splice(index, 1)
}
function confirmAttachmentsToUrls() {
return confirmForm.attachments
.filter((f) => f.fileUrl && !f._uploading)
.map((f) => f.fileUrl)
.join(',')
}
async function submitConfirm() {
if (!currentDetailId.value) return
if (confirmForm.attachments.some((f) => f._uploading)) {
ElMessage.warning('附件上传中,请稍候')
return
}
submitLoading.value = true
try {
await confirmClinicalRefund(currentDetailId.value, {
refundFinanceConfirmAttachments: confirmAttachmentsToUrls() || undefined,
refundFinanceRemark: confirmForm.financeRemark.trim() || undefined
})
dialogVisible.value = false
loadData()
} finally {
submitLoading.value = false
}
}
watchDebounced(
[searchForm],
() => {
pagination.page = 1
loadData()
},
{ debounce: 300, deep: true }
)
onMounted(() => {
loadData()
})
</script>
<style scoped lang="scss">
.work-order-type-tabs {
padding: 0 16px;
margin-bottom: 4px;
}
.filter-form :deep(.el-form-item) {
margin-bottom: 0;
min-width: 0;
}
.filter-form :deep(.el-form-item__label) {
font-size: 13px;
font-weight: 500;
color: var(--mint-text-muted, #64748b);
padding: 0 0 4px;
line-height: 1.2;
}
.refund-confirm-table-wrap {
overflow-x: auto;
}
.form-section-divider {
height: 1px;
margin: 20px 0;
background: var(--mint-border, #e2e8f0);
}
.detail-section-title {
margin: 0 0 16px;
font-size: 14px;
font-weight: 600;
color: var(--mint-text, #334155);
line-height: 1.4;
}
.attachment-upload {
width: 100%;
}
.attachment-list {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.upload-card {
width: 120px;
height: 96px;
border: 1px dashed #a7f3d0;
border-radius: 8px;
background: #f0fdf4;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 6px;
cursor: pointer;
&:hover {
border-color: #10b981;
background: #ecfdf5;
}
}
.upload-card-text {
font-size: 12px;
color: #10b981;
font-weight: 500;
}
.attachment-item {
width: 120px;
border: 1px solid var(--mint-border, #e2e8f0);
border-radius: 8px;
overflow: hidden;
background: #fff;
&.is-uploading {
opacity: 0.6;
pointer-events: none;
}
}
.attachment-preview {
height: 96px;
display: flex;
align-items: center;
justify-content: center;
background: #f8fafc;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.attachment-preview__icon--doc {
color: #64748b;
}
.attachment-footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 4px;
padding: 6px 8px;
font-size: 12px;
}
.attachment-name {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.action-btn {
cursor: pointer;
color: #94a3b8;
&:hover {
color: #ef4444;
}
}
.view-confirm-form :deep(.el-form-item) {
margin-bottom: 0;
}
.view-field-text {
display: block;
font-size: 14px;
color: var(--mint-text, #334155);
line-height: 1.5;
word-break: break-word;
&--multiline {
white-space: pre-wrap;
}
}
</style>
@@ -1,28 +1,49 @@
<!-- 缴费确认(财务)- 临床应用 -->
<!-- 缴退费财务确认 - 临床应用:缴费确认 + 退费确认 -->
<!-- eslint-disable vue/no-v-model-argument -->
<template>
<div class="page-container">
<div class="region-tabs region-tab-strip">
<div class="tab-button-group region-tab-group">
<el-button
v-for="tab in tabs"
:key="tab.key"
class="region-tab-btn"
:type="activeTab === tab.key ? 'primary' : 'default'"
@click="switchTab(tab.key)"
>
<span class="region-tab-inner">
<span class="region-tab-name">{{ tab.label }}</span>
</span>
</el-button>
</div>
</div>
<section class="panel">
<div class="panel-top">
<h2>缴费确认列表</h2>
<div class="panel-entity-switch" role="tablist" aria-label="视图类型">
<button
type="button"
class="entity-switch-card"
:class="{ 'is-active': mainTab === 'payment' }"
role="tab"
:aria-selected="mainTab === 'payment'"
@click="mainTab = 'payment'"
>
<span class="entity-switch-card__icon"><el-icon><Wallet /></el-icon></span>
<span class="entity-switch-card__main">
<span class="entity-switch-card__title">缴费确认</span>
<span class="entity-switch-card__desc">缴费记录确认与附件审核</span>
</span>
</button>
<button
type="button"
class="entity-switch-card"
:class="{ 'is-active': mainTab === 'refund' }"
role="tab"
:aria-selected="mainTab === 'refund'"
@click="mainTab = 'refund'"
>
<span class="entity-switch-card__icon"><el-icon><Refresh /></el-icon></span>
<span class="entity-switch-card__main">
<span class="entity-switch-card__title">退费确认</span>
<span class="entity-switch-card__desc">退费记录确认与附件审核</span>
</span>
</button>
</div>
<div v-show="mainTab === 'payment'" class="panel-entity-body">
<el-tabs
v-model="activeTab"
class="work-order-type-tabs"
@tab-change="handleStatusTabChange"
>
<el-tab-pane label="待确认" name="pending" />
<el-tab-pane label="已确认" name="confirmed" />
</el-tabs>
<div class="filter-block">
<el-form :model="searchForm" class="filter-form" label-position="top" @submit.prevent>
<div class="filter-grid">
@@ -49,7 +70,7 @@
</el-form>
</div>
<div class="list-body list-wrap">
<div class="list-body list-wrap payment-confirm-table-wrap">
<el-table
class="list-table"
:data="tableData"
@@ -122,19 +143,27 @@
</el-table-column>
<el-table-column
prop="payStatus"
label="缴费状态"
min-width="120"
label="状态"
min-width="110"
align="center"
header-align="center"
>
<template #default>
<el-tag :type="activeTab === 'jfqrz' ? 'warning' : 'success'" size="small">
{{ activeTab === 'jfqrz' ? '缴费确认中' : '已缴费' }}
<el-tag :type="activeTab === 'pending' ? 'warning' : 'success'" size="small">
{{ activeTab === 'pending' ? '缴费确认中' : '已缴费' }}
</el-tag>
</template>
</el-table-column>
<el-table-column
v-if="activeTab === 'yjf'"
v-if="activeTab === 'confirmed'"
prop="updateTime"
label="确认时间"
min-width="170"
align="center"
header-align="center"
/>
<el-table-column
v-if="activeTab === 'confirmed'"
prop="financeRemark"
label="财务备注"
min-width="120"
@@ -145,9 +174,9 @@
<template #default="{ row }">{{ row.financeRemark || '-' }}</template>
</el-table-column>
<el-table-column
v-if="activeTab === 'yjf'"
prop="updateTime"
label="确认时间"
v-if="activeTab === 'pending'"
prop="createTime"
label="创建时间"
min-width="170"
align="center"
header-align="center"
@@ -161,7 +190,7 @@
>
<template #default="{ row }">
<el-button
v-if="activeTab === 'jfqrz'"
v-if="activeTab === 'pending'"
class="btn-op-item primary"
@click="openConfirm(row)"
>
@@ -190,12 +219,20 @@
<el-dialog
v-model="dialogVisible"
title="确认收款"
width="640px"
class="dialog-form-layout"
width="900px"
class="dialog-form-layout payment-confirm-dialog"
align-center
destroy-on-close
:close-on-click-modal="false"
>
<ClinicalPaymentSubmitReadonly
:detail="confirmRow"
mode="receipt"
title="缴费明细(请核对)"
@download="handleDownloadFile"
/>
<div class="form-section-divider" />
<h4 class="detail-section-title">财务确认</h4>
<el-form
ref="confirmFormRef"
:model="confirmForm"
@@ -283,24 +320,25 @@
<el-dialog
v-model="viewDialogVisible"
title="确认收款信息"
width="640px"
class="dialog-form-layout"
width="900px"
class="dialog-form-layout payment-confirm-dialog"
align-center
destroy-on-close
>
<ClinicalPaymentSubmitReadonly
:detail="viewRow"
mode="receipt"
title="缴费明细"
@download="handleDownloadFile"
/>
<div class="form-section-divider" />
<h4 class="detail-section-title">财务确认信息</h4>
<el-form label-position="top" class="biz-dialog-form view-confirm-form">
<div class="form-grid-2">
<el-form-item label="申请单号" class="form-col-span-2">
<span class="view-field-text">{{ viewRow?.applicationNo || '-' }}</span>
</el-form-item>
<el-form-item label="患者姓名">
<span class="view-field-text">{{ viewRow?.patientName || '-' }}</span>
</el-form-item>
<el-form-item label="缴费金额(元)">
<span class="view-field-text">{{ formatAmount(viewRow?.paymentAmount) }}</span>
</el-form-item>
<el-form-item label="确认时间" class="form-col-span-2">
<span class="view-field-text">{{ viewRow?.updateTime || '-' }}</span>
<span class="view-field-text">{{
viewRow?.financeConfirmTime || viewRow?.updateTime || '—'
}}</span>
</el-form-item>
<el-form-item label="财务备注" class="form-col-span-2">
<span class="view-field-text view-field-text--multiline">{{
@@ -308,40 +346,10 @@
}}</span>
</el-form-item>
<el-form-item label="财务确认附件" class="form-col-span-2">
<div v-if="viewAttachmentFiles.length" class="attachment-list">
<div
v-for="(file, fIdx) in viewAttachmentFiles"
:key="fIdx"
class="attachment-item"
>
<div class="attachment-preview">
<template v-if="isImageUrl(String(file.fileUrl || ''))">
<img
:src="fullFileUrl(String(file.fileUrl || ''))"
:alt="String(file.fileName || '')"
/>
</template>
<template v-else>
<div class="attachment-preview__icon attachment-preview__icon--doc">
<el-icon :size="28"><Document /></el-icon>
</div>
</template>
</div>
<div class="attachment-footer">
<span class="attachment-name" :title="String(file.fileName || '')">{{
file.fileName
}}</span>
<el-icon
class="action-btn"
title="下载"
@click="handleDownloadFile(file)"
>
<Download />
</el-icon>
</div>
</div>
</div>
<span v-else class="view-field-text">—</span>
<ProtocolAttachmentReadonly
:files="viewAttachmentFiles"
@download="handleDownloadFile"
/>
</el-form-item>
</div>
</el-form>
@@ -352,6 +360,9 @@
</el-button>
</template>
</el-dialog>
</div>
<RefundConfirmTab v-if="mainTab === 'refund'" />
</section>
</div>
</template>
@@ -368,10 +379,13 @@
Plus,
Document,
Delete,
Download
Wallet,
Refresh
} from '@element-plus/icons-vue'
import RefundConfirmTab from './RefundConfirmTab.vue'
import ClinicalPaymentSubmitReadonly from '@/components/business/clinical-payment-submit-readonly/index.vue'
import ProtocolAttachmentReadonly from '@/views/cell-storage/protocol/ProtocolAttachmentReadonly.vue'
import {
fetchClinicalPayments,
confirmClinicalReceipt,
fetchClinicalReceiptPending,
fetchClinicalReceiptConfirmed
@@ -381,12 +395,10 @@
defineOptions({ name: 'ClinicalPaymentConfirm' })
const tabs = [
{ key: 'jfqrz', label: '待确认' },
{ key: 'yjf', label: '已确认' }
]
const route = useRoute()
const mainTab = ref<'payment' | 'refund'>('payment')
const activeTab = ref('jfqrz')
const activeTab = ref('pending')
const searchForm = reactive({ keyword: '' })
const tableData = ref<Record<string, unknown>[]>([])
const loading = ref(false)
@@ -396,6 +408,7 @@
const viewDialogVisible = ref(false)
const submitLoading = ref(false)
const currentDetailId = ref<string | null>(null)
const confirmRow = ref<Record<string, unknown> | null>(null)
const viewRow = ref<Record<string, unknown> | null>(null)
const confirmFormRef = ref()
@@ -458,7 +471,7 @@
keyword: searchForm.keyword || undefined
}
const res =
activeTab.value === 'jfqrz'
activeTab.value === 'pending'
? await fetchClinicalReceiptPending(params)
: await fetchClinicalReceiptConfirmed(params)
tableData.value = res.list || []
@@ -468,9 +481,7 @@
}
}
function switchTab(key: string) {
if (activeTab.value === key) return
activeTab.value = key
function handleStatusTabChange() {
pagination.page = 1
loadData()
}
@@ -488,6 +499,7 @@
function openConfirm(row: Record<string, unknown>) {
currentDetailId.value = String(row.id)
confirmRow.value = row
confirmForm.financeRemark = ''
confirmForm.attachments = []
dialogVisible.value = true
@@ -499,7 +511,7 @@
}
function handleRowDblClick(row: Record<string, unknown>) {
if (activeTab.value !== 'jfqrz') openViewConfirm(row)
if (activeTab.value !== 'pending') openViewConfirm(row)
}
async function handleConfirmAttachmentChange(uploadFile: { raw?: File }) {
@@ -570,37 +582,108 @@
)
onMounted(() => {
loadData()
const tab = String(route.query.tab || '')
if (tab === 'refund') {
mainTab.value = 'refund'
} else {
loadData()
}
})
watch(mainTab, (tab) => {
if (tab === 'payment') {
loadData()
}
})
</script>
<style scoped lang="scss">
.region-tabs {
margin-bottom: 16px;
.panel-entity-switch {
display: flex;
justify-content: center;
gap: 12px;
padding: 16px 16px 12px;
}
.region-tab-btn {
position: relative;
min-width: 108px;
padding: 0 12px;
.entity-switch-card {
display: flex;
align-items: center;
gap: 12px;
min-width: 220px;
max-width: 280px;
flex: 1;
padding: 14px 18px;
border: 1px solid var(--mint-border, #d9e8e2);
border-radius: 10px;
background: var(--surface, #fff);
cursor: pointer;
text-align: left;
transition:
border-color 0.2s ease,
background-color 0.2s ease,
box-shadow 0.2s ease;
:deep(.el-icon) {
display: none;
&:hover:not(.is-active) {
border-color: #a7f3d0;
background: #f8fafc;
}
&.is-active {
border-color: var(--primary, #10b981);
background: var(--primary-bg, #ecfdf5);
box-shadow: 0 0 0 1px rgb(16 185 129 / 12%);
}
}
.region-tab-btn.el-button > :deep(span) {
position: static !important;
display: inline-flex;
width: 100%;
justify-content: center;
}
.region-tab-inner {
display: inline-flex;
.entity-switch-card__icon {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
width: 40px;
height: 40px;
flex-shrink: 0;
border-radius: 8px;
background: #f1f5f9;
color: #64748b;
font-size: 20px;
.entity-switch-card.is-active & {
background: #fff;
color: var(--primary-dark, #059669);
}
}
.entity-switch-card__main {
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
}
.entity-switch-card__title {
font-size: 14px;
font-weight: 600;
color: var(--text, #1e293b);
line-height: 1.4;
.entity-switch-card.is-active & {
color: var(--primary-dark, #059669);
}
}
.entity-switch-card__desc {
font-size: 12px;
color: var(--mint-text-muted, #64748b);
line-height: 1.4;
}
.panel-entity-body {
min-width: 0;
}
.work-order-type-tabs {
padding: 0 16px;
margin-bottom: 4px;
}
.filter-form :deep(.el-form-item) {
@@ -616,6 +699,16 @@
line-height: 1.2;
}
.payment-confirm-table-wrap {
overflow-x: auto;
}
.payment-confirm-dialog {
:deep(.el-dialog__body) {
padding-top: 16px;
}
}
.attachment-upload {
width: 100%;
}
@@ -723,4 +816,18 @@
white-space: pre-wrap;
}
}
.form-section-divider {
height: 1px;
margin: 20px 0;
background: var(--mint-border, #e2e8f0);
}
.detail-section-title {
margin: 0 0 16px;
font-size: 14px;
font-weight: 600;
color: var(--mint-text, #334155);
line-height: 1.4;
}
</style>
@@ -1,707 +1,18 @@
<!-- 缴费信息(临床应用) -->
<!-- eslint-disable vue/no-v-model-argument -->
<!-- 旧「缴费信息」菜单入口:重定向至临床申请单 · 缴费信息 Tab -->
<template>
<div class="page-container">
<div class="region-tabs region-tab-strip">
<div class="tab-button-group region-tab-group">
<el-button
v-for="tab in tabs"
:key="tab.key"
class="region-tab-btn"
:type="activeTab === tab.key ? 'primary' : 'default'"
@click="switchTab(tab.key)"
>
<span class="region-tab-inner">
<span class="region-tab-name">{{ tab.label }}</span>
</span>
</el-button>
</div>
</div>
<section class="panel">
<div class="panel-top">
<h2>缴费信息列表</h2>
</div>
<div class="filter-block">
<el-form :model="searchForm" class="filter-form" label-position="top" @submit.prevent>
<div class="filter-grid">
<el-form-item label="关键词">
<el-input
v-model="searchForm.keyword"
placeholder="申请单号"
clearable
@keyup.enter="handleSearch"
/>
</el-form-item>
<el-form-item label="缴费状态">
<el-select v-model="searchForm.payStatus" placeholder="全部" clearable>
<el-option label="全部" value="" />
<el-option label="待缴费" value="dfj" />
<el-option label="缴费确认中" value="jfqrz" />
<el-option label="已缴费" value="yjf" />
<el-option label="退费确认中" value="tfqrz" />
<el-option label="已退费" value="ytf" />
</el-select>
</el-form-item>
</div>
<div class="filter-actions-row">
<span class="filter-hint">支持按申请单号模糊检索。</span>
<div class="filter-actions-end">
<el-button class="btn-ghost" @click="handleReset">
<el-icon><RefreshLeft /></el-icon>重置
</el-button>
<el-button class="btn-main" type="primary" @click="handleSearch">
<el-icon><Search /></el-icon>搜索
</el-button>
</div>
</div>
</el-form>
</div>
<div class="list-toolbar">
<div class="list-toolbar-row">
<div class="list-toolbar-selected">
已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
</div>
<el-button
v-if="activeTab === 'dfj'"
class="btn-main"
type="primary"
:disabled="!selectedRows.length"
@click="handleBatchSubmitReceipt"
>
<el-icon><Check /></el-icon>批量缴费确认
</el-button>
<el-button
v-if="activeTab === 'yjf'"
class="btn-main"
type="primary"
:disabled="!selectedRows.length"
@click="handleBatchRefund"
>
<el-icon><RefreshLeft /></el-icon>批量退费确认
</el-button>
</div>
</div>
<div class="list-body list-wrap">
<el-table
class="list-table"
:data="tableData"
v-loading="loading"
stripe
row-key="id"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" min-width="55" align="center" header-align="center" />
<el-table-column
type="index"
label="序号"
min-width="68"
align="center"
header-align="center"
:index="(index) => (pagination.page - 1) * pagination.pageSize + index + 1"
/>
<el-table-column
prop="applicationNo"
label="申请单号"
min-width="140"
align="center"
header-align="center"
/>
<el-table-column
prop="patientName"
label="患者姓名"
min-width="100"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.patientName || '-' }}</template>
</el-table-column>
<el-table-column
prop="channelName"
label="渠道名称"
min-width="120"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.channelName || '-' }}</template>
</el-table-column>
<el-table-column
prop="cellTypeSpec"
label="细胞类型/规格"
min-width="130"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.cellTypeSpec || '-' }}</template>
</el-table-column>
<el-table-column
prop="infusionTime"
label="输注时间"
min-width="130"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.infusionTime || '-' }}</template>
</el-table-column>
<el-table-column
prop="paymentAmount"
label="缴费金额(元)"
min-width="130"
align="center"
header-align="center"
>
<template #default="{ row }">
<span class="amount-text">{{ formatAmount(row.paymentAmount) }}</span>
</template>
</el-table-column>
<el-table-column
prop="payStatus"
label="缴费状态"
min-width="120"
align="center"
header-align="center"
>
<template #default="{ row }">
<el-tag :type="payStatusTagType(String(row.payStatus || ''))" size="small">
{{ payStatusLabel(String(row.payStatus || '')) }}
</el-tag>
</template>
</el-table-column>
<el-table-column
label="操作"
min-width="260"
fixed="right"
align="center"
header-align="center"
>
<template #default="{ row }">
<el-button
v-if="activeTab === 'dfj'"
class="btn-op-item primary"
@click="handleSubmitReceipt(row)"
>
<el-icon><Check /></el-icon>缴费确认
</el-button>
<el-button
v-if="activeTab === 'yjf'"
class="btn-op-item primary"
@click="openRefundDialog(row)"
>
<el-icon><RefreshLeft /></el-icon>退费确认
</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination list-pager-bar">
<el-pagination
:current-page="pagination.page"
:page-size="pagination.pageSize"
:total="pagination.total"
:page-sizes="[10, 20, 50]"
layout="total, sizes, prev, pager, next"
@size-change="(val) => ((pagination.page = 1), (pagination.pageSize = val), loadData())"
@current-change="(val) => ((pagination.page = val), loadData())"
/>
</div>
</div>
<el-dialog
v-model="refundDialogVisible"
title="退费确认"
width="640px"
class="dialog-form-layout"
align-center
destroy-on-close
:close-on-click-modal="false"
>
<el-form
ref="refundFormRef"
:model="refundForm"
:rules="refundFormRules"
label-position="top"
class="biz-dialog-form"
>
<div class="form-grid-2">
<el-form-item label="退费金额(元)" prop="refundAmount" class="form-col-span-2">
<el-input-number
v-model="refundForm.refundAmount"
:min="0.01"
:step="100"
:precision="2"
controls-position="right"
placeholder="请输入退费金额"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="退费备注" prop="refundRemark" class="form-col-span-2">
<el-input
v-model="refundForm.refundRemark"
type="textarea"
:rows="3"
placeholder="选填"
/>
</el-form-item>
<el-form-item label="退费附件" class="form-col-span-2">
<div class="attachment-upload">
<div class="attachment-list">
<el-upload
:auto-upload="false"
:show-file-list="false"
:multiple="true"
accept="image/*,video/*,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.zip,.rar"
@change="handleRefundAttachmentChange"
>
<div class="upload-card">
<el-icon :size="22" color="#10b981"><Plus /></el-icon>
<span class="upload-card-text">上传附件</span>
</div>
</el-upload>
<div
v-for="(file, fIdx) in refundForm.attachments"
:key="file.id || fIdx"
class="attachment-item"
:class="{ 'is-uploading': file._uploading }"
>
<div class="attachment-preview">
<template v-if="file.fileUrl && isImageUrl(file.fileUrl)">
<img :src="fullFileUrl(file.fileUrl)" :alt="file.fileName" />
</template>
<template v-else>
<div class="attachment-preview__icon attachment-preview__icon--doc">
<el-icon :size="28"><Document /></el-icon>
</div>
</template>
</div>
<div class="attachment-footer">
<span class="attachment-name" :title="file.fileName">{{
file.fileName
}}</span>
<el-icon
class="action-btn"
title="删除"
@click="removeRefundAttachment(fIdx)"
>
<Delete />
</el-icon>
</div>
</div>
</div>
<p class="form-tip">支持图片、文档等,多个附件将一并提交。</p>
</div>
</el-form-item>
</div>
</el-form>
<template #footer>
<el-button class="btn-ghost" @click="refundDialogVisible = false">
<el-icon><Close /></el-icon>
取消
</el-button>
<el-button
class="btn-main"
type="primary"
:loading="refundSubmitLoading"
@click="submitRefund"
>
<el-icon><Check /></el-icon>
确认提交
</el-button>
</template>
</el-dialog>
</section>
</div>
<div />
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus'
import {
RefreshLeft,
Search,
Plus,
Document,
Delete,
Close,
Check
} from '@element-plus/icons-vue'
import {
fetchClinicalPayments,
submitClinicalReceipt,
batchSubmitClinicalReceipt,
submitClinicalRefund,
batchSubmitClinicalRefund
} from '@/api/business'
import { fetchUploadAttachment } from '@/api/business'
import { formatMoneyDisplay } from '@/utils/money-format'
import { payStatusLabel, payStatusTagType } from '@/utils/status-tag-registry'
defineOptions({ name: 'ClinicalPaymentInfo' })
const tabs = [
{ key: 'dfj', label: '待缴费' },
{ key: 'yjf', label: '已缴费' }
]
const activeTab = ref('dfj')
const searchForm = reactive({ keyword: '', payStatus: '' })
const tableData = ref<Record<string, unknown>[]>([])
const selectedRows = ref<Record<string, unknown>[]>([])
const loading = ref(false)
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
const refundDialogVisible = ref(false)
const refundSubmitLoading = ref(false)
const refundTargetIds = ref<string[]>([])
const refundFormRef = ref<FormInstance>()
const refundForm = reactive({
refundAmount: null as number | null,
refundRemark: '',
attachments: [] as Array<{
id: string
fileName: string
fileUrl: string
_uploading?: boolean
}>
})
const refundFormRules: FormRules = {
refundAmount: [{ required: true, message: '请填写退费金额', trigger: 'blur' }]
}
const minioBaseUrl = (import.meta.env.VITE_MINIO_BASE_URL || '').replace(/\/$/, '')
function formatAmount(v: unknown): string {
if (v == null || v === '') return '-'
return '¥' + formatMoneyDisplay(v)
}
function fullFileUrl(url: string) {
if (!url) return ''
if (/^https?:\/\//i.test(url)) return url
return minioBaseUrl ? `${minioBaseUrl}/${url.replace(/^\//, '')}` : url
}
function isImageUrl(url: string) {
return /\.(png|jpe?g|gif|webp|bmp|svg)(\?.*)?$/i.test(url)
}
function handleSelectionChange(rows: Record<string, unknown>[]) {
selectedRows.value = rows
}
async function loadData() {
loading.value = true
try {
const res = await fetchClinicalPayments({
page: pagination.page,
pageSize: pagination.pageSize,
payStatus: activeTab.value,
keyword: searchForm.keyword || undefined
})
tableData.value = res.list || []
pagination.total = res.total ?? 0
} finally {
loading.value = false
}
}
function switchTab(key: string) {
if (activeTab.value === key) return
activeTab.value = key
selectedRows.value = []
pagination.page = 1
loadData()
}
async function handleSubmitReceipt(row: Record<string, unknown>) {
const id = String(row.id || '')
if (!id) return
try {
await ElMessageBox.confirm(
'确认对该缴费明细进行缴费确认?提交后状态变为「缴费确认中」。',
'缴费确认',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
)
await submitClinicalReceipt(id)
loadData()
} catch {
/* cancel */
}
}
async function handleBatchSubmitReceipt() {
if (!selectedRows.value.length) return
const ids = selectedRows.value.map((r) => String(r.id || '')).filter(Boolean)
if (!ids.length) return
try {
await ElMessageBox.confirm(
`确认将选中的 ${ids.length} 条待缴费明细批量缴费确认?`,
'批量缴费确认',
{ confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }
)
await batchSubmitClinicalReceipt(ids)
selectedRows.value = []
loadData()
} catch {
/* cancel */
}
}
function resetRefundForm(defaultAmount?: number) {
refundForm.refundAmount = defaultAmount ?? null
refundForm.refundRemark = ''
refundForm.attachments = []
refundFormRef.value?.clearValidate()
}
function openRefundDialog(row?: Record<string, unknown>, batchIds?: string[]) {
const ids = batchIds?.length ? batchIds : row?.id ? [String(row.id)] : []
if (!ids.length) return
refundTargetIds.value = ids
const defaultAmount =
!batchIds?.length && row?.paymentAmount != null ? Number(row.paymentAmount) : undefined
resetRefundForm(
defaultAmount != null && !Number.isNaN(defaultAmount) ? defaultAmount : undefined
)
refundDialogVisible.value = true
}
function handleBatchRefund() {
if (!selectedRows.value.length) return
const ids = selectedRows.value.map((r) => String(r.id || '')).filter(Boolean)
if (!ids.length) return
openRefundDialog(undefined, ids)
}
function refundAttachmentsToUrls() {
return refundForm.attachments
.filter((f) => f.fileUrl && !f._uploading)
.map((f) => f.fileUrl)
.join(',')
}
async function handleRefundAttachmentChange(uploadFile: { raw?: File }) {
const file = uploadFile.raw
if (!file) return
const tempId = `temp_${Date.now()}`
refundForm.attachments.push({
id: tempId,
fileName: file.name,
fileUrl: '',
_uploading: true
})
const idx = refundForm.attachments.length - 1
try {
const fd = new FormData()
fd.append('folder', 'clinical-payment-refund')
fd.append('file', file)
const res = await fetchUploadAttachment(fd)
refundForm.attachments[idx] = {
id: res.id || tempId,
fileName: file.name || res.fileName,
fileUrl: res.fileUrl,
_uploading: false
}
} catch {
ElMessage.error('文件上传失败')
refundForm.attachments.splice(idx, 1)
}
}
function removeRefundAttachment(index: number) {
refundForm.attachments.splice(index, 1)
}
async function submitRefund() {
if (!refundTargetIds.value.length) return
const valid = await refundFormRef.value?.validate().catch(() => false)
if (!valid) return
if (refundForm.attachments.some((f) => f._uploading)) {
ElMessage.warning('附件上传中,请稍候')
return
}
const payload = {
refundAmount: Number(refundForm.refundAmount),
refundRemark: refundForm.refundRemark?.trim() || undefined,
refundAttachments: refundAttachmentsToUrls() || undefined
}
refundSubmitLoading.value = true
try {
if (refundTargetIds.value.length === 1) {
await submitClinicalRefund(refundTargetIds.value[0], payload)
} else {
await batchSubmitClinicalRefund(refundTargetIds.value, payload)
}
refundDialogVisible.value = false
selectedRows.value = []
loadData()
} finally {
refundSubmitLoading.value = false
}
}
function handleSearch() {
pagination.page = 1
loadData()
}
function handleReset() {
searchForm.keyword = ''
searchForm.payStatus = ''
pagination.page = 1
loadData()
}
watchDebounced(
[searchForm],
() => {
pagination.page = 1
loadData()
},
{ debounce: 300, deep: true }
)
const router = useRouter()
const route = useRoute()
onMounted(() => {
loadData()
router.replace({
name: 'ClinicalApplicationList',
query: { ...route.query, tab: 'payment' }
})
})
</script>
<style scoped lang="scss">
.region-tabs {
margin-bottom: 16px;
}
.region-tab-btn {
position: relative;
min-width: 108px;
padding: 0 12px;
:deep(.el-icon) {
display: none;
}
}
.region-tab-btn.el-button > :deep(span) {
position: static !important;
display: inline-flex;
width: 100%;
justify-content: center;
}
.region-tab-inner {
display: inline-flex;
align-items: center;
justify-content: center;
width: 100%;
}
.filter-form :deep(.el-form-item) {
margin-bottom: 0;
min-width: 0;
}
.filter-form :deep(.el-form-item__label) {
font-size: 13px;
font-weight: 500;
color: var(--mint-text-muted, #64748b);
padding: 0 0 4px;
line-height: 1.2;
}
.attachment-upload {
width: 100%;
}
.attachment-list {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.upload-card {
width: 120px;
height: 96px;
border: 1px dashed #a7f3d0;
border-radius: 8px;
background: #f0fdf4;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 6px;
cursor: pointer;
&:hover {
border-color: #10b981;
background: #ecfdf5;
}
}
.upload-card-text {
font-size: 12px;
color: #10b981;
font-weight: 500;
}
.attachment-item {
width: 120px;
border: 1px solid var(--mint-border, #e2e8f0);
border-radius: 8px;
overflow: hidden;
background: #fff;
&.is-uploading {
opacity: 0.6;
pointer-events: none;
}
}
.attachment-preview {
height: 96px;
display: flex;
align-items: center;
justify-content: center;
background: #f8fafc;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.attachment-preview__icon--doc {
color: #64748b;
}
.attachment-footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 4px;
padding: 6px 8px;
font-size: 12px;
}
.attachment-name {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.action-btn {
cursor: pointer;
color: #94a3b8;
&:hover {
color: #ef4444;
}
}
</style>
@@ -1,804 +1,18 @@
<!-- 退费确认(财务)- 临床应用 -->
<!-- eslint-disable vue/no-v-model-argument -->
<!-- 退费确认已融入「缴退费财务确认」页内 Tab,本路由仅做重定向 -->
<template>
<div class="page-container">
<div class="region-tabs region-tab-strip">
<div class="tab-button-group region-tab-group">
<el-button
v-for="tab in tabs"
:key="tab.key"
class="region-tab-btn"
:type="activeTab === tab.key ? 'primary' : 'default'"
@click="switchTab(tab.key)"
>
<span class="region-tab-inner">
<span class="region-tab-name">{{ tab.label }}</span>
</span>
</el-button>
</div>
</div>
<section class="panel">
<div class="panel-top">
<h2>退费确认列表</h2>
</div>
<div class="filter-block">
<el-form :model="searchForm" class="filter-form" label-position="top" @submit.prevent>
<div class="filter-grid">
<el-form-item label="关键词">
<el-input
v-model="searchForm.keyword"
placeholder="申请单号/患者姓名"
clearable
@keyup.enter="handleSearch"
/>
</el-form-item>
</div>
<div class="filter-actions-row">
<span class="filter-hint">支持按申请单号、患者姓名模糊检索。</span>
<div class="filter-actions-end">
<el-button class="btn-ghost" @click="handleReset">
<el-icon><RefreshLeft /></el-icon>重置
</el-button>
<el-button class="btn-main" type="primary" @click="handleSearch">
<el-icon><Search /></el-icon>搜索
</el-button>
</div>
</div>
</el-form>
</div>
<div class="list-body list-wrap">
<el-table
class="list-table"
:data="tableData"
v-loading="loading"
stripe
row-key="id"
@row-dblclick="handleRowDblClick"
>
<el-table-column
type="index"
label="序号"
min-width="68"
align="center"
header-align="center"
:index="(index) => (pagination.page - 1) * pagination.pageSize + index + 1"
/>
<el-table-column
prop="applicationNo"
label="申请单号"
min-width="140"
align="center"
header-align="center"
/>
<el-table-column
prop="patientName"
label="患者姓名"
min-width="100"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.patientName || '-' }}</template>
</el-table-column>
<el-table-column
prop="channelName"
label="渠道名称"
min-width="120"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.channelName || '-' }}</template>
</el-table-column>
<el-table-column
prop="cellTypeSpec"
label="细胞类型/规格"
min-width="130"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.cellTypeSpec || '-' }}</template>
</el-table-column>
<el-table-column
prop="infusionTime"
label="输注时间"
min-width="130"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.infusionTime || '-' }}</template>
</el-table-column>
<el-table-column
prop="paymentAmount"
label="缴费金额(元)"
min-width="130"
align="center"
header-align="center"
>
<template #default="{ row }">
<span class="amount-text">{{ formatAmount(row.paymentAmount) }}</span>
</template>
</el-table-column>
<el-table-column
prop="refundAmount"
label="退费金额(元)"
min-width="130"
align="center"
header-align="center"
>
<template #default="{ row }">
<span class="amount-text">{{ formatAmount(row.refundAmount) }}</span>
</template>
</el-table-column>
<el-table-column
prop="payStatus"
label="缴费状态"
min-width="120"
align="center"
header-align="center"
>
<template #default>
<el-tag :type="activeTab === 'tfqrz' ? 'warning' : 'danger'" size="small">
{{ activeTab === 'tfqrz' ? '退费确认中' : '已退费' }}
</el-tag>
</template>
</el-table-column>
<el-table-column
v-if="activeTab === 'tfqrz'"
prop="refundRemark"
label="退费备注"
min-width="120"
align="center"
header-align="center"
show-overflow-tooltip
>
<template #default="{ row }">{{ row.refundRemark || '-' }}</template>
</el-table-column>
<el-table-column
v-if="activeTab === 'ytf'"
prop="refundFinanceRemark"
label="财务备注"
min-width="120"
align="center"
header-align="center"
show-overflow-tooltip
>
<template #default="{ row }">{{ row.refundFinanceRemark || '-' }}</template>
</el-table-column>
<el-table-column
v-if="activeTab === 'ytf'"
prop="updateTime"
label="确认时间"
min-width="170"
align="center"
header-align="center"
/>
<el-table-column
label="操作"
min-width="140"
fixed="right"
align="center"
header-align="center"
>
<template #default="{ row }">
<el-button
v-if="activeTab === 'tfqrz'"
class="btn-op-item primary"
@click="openConfirm(row)"
>
<el-icon><Check /></el-icon>确认退费
</el-button>
<el-button v-else class="btn-op-item" @click="openViewConfirm(row)">
<el-icon><View /></el-icon>查看确认信息
</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination list-pager-bar">
<el-pagination
:current-page="pagination.page"
:page-size="pagination.pageSize"
:total="pagination.total"
:page-sizes="[10, 20, 50]"
layout="total, sizes, prev, pager, next"
@size-change="(val) => ((pagination.page = 1), (pagination.pageSize = val), loadData())"
@current-change="(val) => ((pagination.page = val), loadData())"
/>
</div>
</div>
<!-- 确认退费弹窗 -->
<el-dialog
v-model="dialogVisible"
title="确认退费"
width="640px"
class="dialog-form-layout"
align-center
destroy-on-close
:close-on-click-modal="false"
>
<div class="refund-apply-section">
<h4 class="detail-section-title">退费申请信息</h4>
<el-form label-position="top" class="biz-dialog-form view-confirm-form">
<div class="form-grid-2">
<el-form-item label="申请单号">
<span class="view-field-text">{{ confirmRow?.applicationNo || '-' }}</span>
</el-form-item>
<el-form-item label="患者姓名">
<span class="view-field-text">{{ confirmRow?.patientName || '-' }}</span>
</el-form-item>
<el-form-item label="缴费金额(元)">
<span class="view-field-text">{{ formatAmount(confirmRow?.paymentAmount) }}</span>
</el-form-item>
<el-form-item label="退费金额(元)">
<span class="view-field-text">{{ formatAmount(confirmRow?.refundAmount) }}</span>
</el-form-item>
<el-form-item label="退费备注" class="form-col-span-2">
<span class="view-field-text view-field-text--multiline">{{
confirmRow?.refundRemark || '—'
}}</span>
</el-form-item>
</div>
</el-form>
</div>
<div class="form-section-divider" />
<h4 class="detail-section-title">财务确认</h4>
<el-form
ref="confirmFormRef"
:model="confirmForm"
label-position="top"
class="biz-dialog-form"
>
<div class="form-grid-2">
<el-form-item label="财务确认退费备注" class="form-col-span-2">
<el-input
v-model="confirmForm.financeRemark"
type="textarea"
:rows="3"
placeholder="选填"
/>
</el-form-item>
<el-form-item label="附件" class="form-col-span-2">
<div class="attachment-upload">
<div class="attachment-list">
<el-upload
:auto-upload="false"
:show-file-list="false"
:multiple="true"
accept="image/*,video/*,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.zip,.rar"
@change="handleConfirmAttachmentChange"
>
<div class="upload-card">
<el-icon :size="22" color="#10b981"><Plus /></el-icon>
<span class="upload-card-text">上传附件</span>
</div>
</el-upload>
<div
v-for="(file, fIdx) in confirmForm.attachments"
:key="file.id || fIdx"
class="attachment-item"
:class="{ 'is-uploading': file._uploading }"
>
<div class="attachment-preview">
<template v-if="file.fileUrl && isImageUrl(file.fileUrl)">
<img :src="fullFileUrl(file.fileUrl)" :alt="file.fileName" />
</template>
<template v-else>
<div class="attachment-preview__icon attachment-preview__icon--doc">
<el-icon :size="28"><Document /></el-icon>
</div>
</template>
</div>
<div class="attachment-footer">
<span class="attachment-name" :title="file.fileName">{{
file.fileName
}}</span>
<el-icon
class="action-btn"
title="删除"
@click="removeConfirmAttachment(fIdx)"
>
<Delete />
</el-icon>
</div>
</div>
</div>
<p class="form-tip">支持图片、文档等,多个附件将一并提交。</p>
</div>
</el-form-item>
</div>
</el-form>
<template #footer>
<el-button class="btn-ghost" @click="dialogVisible = false">
<el-icon><Close /></el-icon>
取消
</el-button>
<el-button
class="btn-main"
type="primary"
:loading="submitLoading"
@click="submitConfirm"
>
<el-icon><Check /></el-icon>
确认
</el-button>
</template>
</el-dialog>
<!-- 查看确认信息弹窗 -->
<el-dialog
v-model="viewDialogVisible"
title="确认退费信息"
width="640px"
class="dialog-form-layout"
align-center
destroy-on-close
>
<div class="refund-apply-section">
<h4 class="detail-section-title">退费申请信息</h4>
<el-form label-position="top" class="biz-dialog-form view-confirm-form">
<div class="form-grid-2">
<el-form-item label="申请单号">
<span class="view-field-text">{{ viewRow?.applicationNo || '-' }}</span>
</el-form-item>
<el-form-item label="患者姓名">
<span class="view-field-text">{{ viewRow?.patientName || '-' }}</span>
</el-form-item>
<el-form-item label="缴费金额(元)">
<span class="view-field-text">{{ formatAmount(viewRow?.paymentAmount) }}</span>
</el-form-item>
<el-form-item label="退费金额(元)">
<span class="view-field-text">{{ formatAmount(viewRow?.refundAmount) }}</span>
</el-form-item>
<el-form-item label="退费备注" class="form-col-span-2">
<span class="view-field-text view-field-text--multiline">{{
viewRow?.refundRemark || '—'
}}</span>
</el-form-item>
</div>
</el-form>
</div>
<div class="form-section-divider" />
<h4 class="detail-section-title">财务确认信息</h4>
<el-form label-position="top" class="biz-dialog-form view-confirm-form">
<div class="form-grid-2">
<el-form-item label="确认时间" class="form-col-span-2">
<span class="view-field-text">{{ viewRow?.updateTime || '-' }}</span>
</el-form-item>
<el-form-item label="财务备注" class="form-col-span-2">
<span class="view-field-text view-field-text--multiline">{{
viewRow?.refundFinanceRemark || '—'
}}</span>
</el-form-item>
<el-form-item label="财务确认附件" class="form-col-span-2">
<div v-if="viewAttachmentFiles.length" class="attachment-list">
<div
v-for="(file, fIdx) in viewAttachmentFiles"
:key="fIdx"
class="attachment-item"
>
<div class="attachment-preview">
<template v-if="isImageUrl(String(file.fileUrl || ''))">
<img
:src="fullFileUrl(String(file.fileUrl || ''))"
:alt="String(file.fileName || '')"
/>
</template>
<template v-else>
<div class="attachment-preview__icon attachment-preview__icon--doc">
<el-icon :size="28"><Document /></el-icon>
</div>
</template>
</div>
<div class="attachment-footer">
<span class="attachment-name" :title="String(file.fileName || '')">{{
file.fileName
}}</span>
<el-icon
class="action-btn"
title="下载"
@click="handleDownloadFile(file)"
>
<Download />
</el-icon>
</div>
</div>
</div>
<span v-else class="view-field-text">—</span>
</el-form-item>
</div>
</el-form>
<template #footer>
<el-button class="btn-ghost" @click="viewDialogVisible = false">
<el-icon><Close /></el-icon>
关闭
</el-button>
</template>
</el-dialog>
</section>
</div>
<div />
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue'
import { ElMessage } from 'element-plus'
import {
Close,
Check,
RefreshLeft,
Search,
View,
Plus,
Document,
Delete,
Download
} from '@element-plus/icons-vue'
import {
confirmClinicalRefund,
fetchClinicalRefundPending,
fetchClinicalRefundConfirmed
} from '@/api/business'
import { fetchUploadAttachment } from '@/api/business'
import { formatMoneyDisplay } from '@/utils/money-format'
defineOptions({ name: 'ClinicalRefundConfirmRedirect' })
defineOptions({ name: 'ClinicalRefundConfirm' })
const tabs = [
{ key: 'tfqrz', label: '待确认' },
{ key: 'ytf', label: '已确认' }
]
const activeTab = ref('tfqrz')
const searchForm = reactive({ keyword: '' })
const tableData = ref<Record<string, unknown>[]>([])
const loading = ref(false)
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
const dialogVisible = ref(false)
const viewDialogVisible = ref(false)
const submitLoading = ref(false)
const currentDetailId = ref<string | null>(null)
const confirmRow = ref<Record<string, unknown> | null>(null)
const viewRow = ref<Record<string, unknown> | null>(null)
const confirmFormRef = ref()
const confirmForm = reactive({
financeRemark: '',
attachments: [] as Array<{
id: string
fileName: string
fileUrl: string
_uploading?: boolean
}>
})
const minioBaseUrl = (import.meta.env.VITE_MINIO_BASE_URL || '').replace(/\/$/, '')
function formatAmount(v: unknown): string {
if (v == null || v === '') return '-'
return '¥' + formatMoneyDisplay(v)
}
function fullFileUrl(url: string) {
if (!url) return ''
if (/^https?:\/\//i.test(url)) return url
return minioBaseUrl ? `${minioBaseUrl}/${url.replace(/^\//, '')}` : url
}
function isImageUrl(url: string) {
return /\.(png|jpe?g|gif|webp|bmp|svg)(\?.*)?$/i.test(url)
}
const viewAttachmentFiles = computed(() => {
const row = viewRow.value
if (!row) return []
const urls = String(row.refundFinanceConfirmAttachments || '')
if (!urls.trim()) return []
return urls
.split(',')
.map((u, i) => {
const url = u.trim()
if (!url) return null
const name = url.includes('/') ? url.split('/').pop() || `附件${i + 1}` : url
return { id: `url_${i}`, fileUrl: url, fileName: name }
})
.filter(Boolean) as Array<Record<string, unknown>>
})
function handleDownloadFile(file: Record<string, unknown>) {
const url = String(file.fileUrl || '')
if (!url) return
window.open(fullFileUrl(url), '_blank')
}
async function loadData() {
loading.value = true
try {
const params = {
page: pagination.page,
pageSize: pagination.pageSize,
keyword: searchForm.keyword || undefined
}
const res =
activeTab.value === 'tfqrz'
? await fetchClinicalRefundPending(params)
: await fetchClinicalRefundConfirmed(params)
tableData.value = res.list || []
pagination.total = res.total ?? 0
} finally {
loading.value = false
}
}
function switchTab(key: string) {
if (activeTab.value === key) return
activeTab.value = key
pagination.page = 1
loadData()
}
function handleSearch() {
pagination.page = 1
loadData()
}
function handleReset() {
searchForm.keyword = ''
pagination.page = 1
loadData()
}
function openConfirm(row: Record<string, unknown>) {
currentDetailId.value = String(row.id)
confirmRow.value = row
confirmForm.financeRemark = ''
confirmForm.attachments = []
dialogVisible.value = true
}
function openViewConfirm(row: Record<string, unknown>) {
viewRow.value = row
viewDialogVisible.value = true
}
function handleRowDblClick(row: Record<string, unknown>) {
if (activeTab.value !== 'tfqrz') openViewConfirm(row)
}
async function handleConfirmAttachmentChange(uploadFile: { raw?: File }) {
const file = uploadFile.raw
if (!file) return
const tempId = `temp_${Date.now()}`
confirmForm.attachments.push({
id: tempId,
fileName: file.name,
fileUrl: '',
_uploading: true
})
const idx = confirmForm.attachments.length - 1
try {
const fd = new FormData()
fd.append('folder', 'clinical-finance-refund')
fd.append('file', file)
const res = await fetchUploadAttachment(fd)
confirmForm.attachments[idx] = {
id: res.id || tempId,
fileName: file.name || res.fileName,
fileUrl: res.fileUrl,
_uploading: false
}
} catch {
ElMessage.error('文件上传失败')
confirmForm.attachments.splice(idx, 1)
}
}
function removeConfirmAttachment(index: number) {
confirmForm.attachments.splice(index, 1)
}
function confirmAttachmentsToUrls() {
return confirmForm.attachments
.filter((f) => f.fileUrl && !f._uploading)
.map((f) => f.fileUrl)
.join(',')
}
async function submitConfirm() {
if (!currentDetailId.value) return
if (confirmForm.attachments.some((f) => f._uploading)) {
ElMessage.warning('附件上传中,请稍候')
return
}
submitLoading.value = true
try {
await confirmClinicalRefund(currentDetailId.value, {
refundFinanceConfirmAttachments: confirmAttachmentsToUrls() || undefined,
refundFinanceRemark: confirmForm.financeRemark.trim() || undefined
})
dialogVisible.value = false
loadData()
} finally {
submitLoading.value = false
}
}
watchDebounced(
[searchForm],
() => {
pagination.page = 1
loadData()
},
{ debounce: 300, deep: true }
)
const router = useRouter()
const route = useRoute()
onMounted(() => {
loadData()
router.replace({
name: 'ClinicalPaymentConfirm',
query: { ...route.query, tab: 'refund' }
})
})
</script>
<style scoped lang="scss">
.region-tabs {
margin-bottom: 16px;
}
.region-tab-btn {
position: relative;
min-width: 108px;
padding: 0 12px;
:deep(.el-icon) {
display: none;
}
}
.region-tab-btn.el-button > :deep(span) {
position: static !important;
display: inline-flex;
width: 100%;
justify-content: center;
}
.region-tab-inner {
display: inline-flex;
align-items: center;
justify-content: center;
width: 100%;
}
.filter-form :deep(.el-form-item) {
margin-bottom: 0;
min-width: 0;
}
.filter-form :deep(.el-form-item__label) {
font-size: 13px;
font-weight: 500;
color: var(--mint-text-muted, #64748b);
padding: 0 0 4px;
line-height: 1.2;
}
.form-section-divider {
height: 1px;
margin: 20px 0;
background: var(--mint-border, #e2e8f0);
}
.detail-section-title {
margin: 0 0 16px;
font-size: 14px;
font-weight: 600;
color: var(--mint-text, #334155);
line-height: 1.4;
}
.attachment-upload {
width: 100%;
}
.attachment-list {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.upload-card {
width: 120px;
height: 96px;
border: 1px dashed #a7f3d0;
border-radius: 8px;
background: #f0fdf4;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 6px;
cursor: pointer;
&:hover {
border-color: #10b981;
background: #ecfdf5;
}
}
.upload-card-text {
font-size: 12px;
color: #10b981;
font-weight: 500;
}
.attachment-item {
width: 120px;
border: 1px solid var(--mint-border, #e2e8f0);
border-radius: 8px;
overflow: hidden;
background: #fff;
&.is-uploading {
opacity: 0.6;
pointer-events: none;
}
}
.attachment-preview {
height: 96px;
display: flex;
align-items: center;
justify-content: center;
background: #f8fafc;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.attachment-preview__icon--doc {
color: #64748b;
}
.attachment-footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 4px;
padding: 6px 8px;
font-size: 12px;
}
.attachment-name {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.action-btn {
cursor: pointer;
color: #94a3b8;
&:hover {
color: #ef4444;
}
}
.view-confirm-form :deep(.el-form-item) {
margin-bottom: 0;
}
.view-field-text {
display: block;
font-size: 14px;
color: var(--mint-text, #334155);
line-height: 1.5;
word-break: break-word;
&--multiline {
white-space: pre-wrap;
}
}
</style>
@@ -141,6 +141,18 @@
</div>
</template>
<template #payment-info>
<div class="view-section-slot payment-info-view">
<ClinicalSchedulePaymentDetailView
v-if="detail?.payment"
:payment="detail.payment"
@preview="handleAttachmentPreview"
@download="handleAttachmentDownload"
/>
<el-empty v-else description="暂无缴费记录" :image-size="48" />
</div>
</template>
<template #review-attachments>
<div class="view-section-slot">
<ProtocolAttachmentReadonly
@@ -188,6 +200,7 @@
import SampleProductionInfoCards from '@/components/business/sample-production-info-cards/index.vue'
import SampleQcInfoCards from '@/components/business/sample-qc-info-cards/index.vue'
import ProtocolAttachmentReadonly from '@/views/cell-storage/protocol/ProtocolAttachmentReadonly.vue'
import ClinicalSchedulePaymentDetailView from '@/components/business/clinical-schedule-payment-detail/index.vue'
import { fetchInfusionScheduleMgmtDetail } from '@/api/admin'
import {
applicationStatusLabel,
@@ -251,6 +264,12 @@
const products = computed(() => detail.value?.products || [])
const isClinicalApplication = computed(
() =>
detail.value?.application?.bizType === 'clinical_application' ||
detail.value?.bizType === 'clinical_application'
)
const outboundMaterial = computed(() => detail.value?.outboundMaterial || null)
const outboundMaterialCells = computed(() => outboundMaterial.value?.cells || [])
const outboundMaterialQcRows = computed(() => outboundMaterial.value?.qcMaterials || [])
@@ -473,6 +492,15 @@
fields: [],
slot: 'products'
},
...(isClinicalApplication.value
? [
{
title: '缴费明细',
fields: [],
slot: 'payment-info'
}
]
: []),
{
title: '出库生产工单 + 任务',
slot: 'production-info',
@@ -626,6 +654,10 @@
</script>
<style lang="scss" scoped>
.payment-info-view {
width: 100%;
}
.view-inner-table-wrap.list-body.list-wrap {
margin-top: 4px;
border: 1px solid var(--mint-border, #e2e8f0);
@@ -1,6 +1,6 @@
<!-- 输注计划管理(临床独立页 / 中试重定向) -->
<template>
<div v-if="isPilotRedirect" />
<div v-if="isPilotRedirect || isClinicalRedirect" />
<div v-else class="page-container">
<section class="panel">
<div class="panel-top">
@@ -21,12 +21,21 @@
const router = useRouter()
const route = useRoute()
const isPilotRedirect = computed(() => route.name === 'PilotInfusionSchedule')
const isClinicalRedirect = computed(() => route.name === 'ClinicalInfusionSchedule')
onMounted(() => {
if (!isPilotRedirect.value) return
router.replace({
name: 'PilotApplication',
query: { ...route.query, tab: 'infusion' }
})
if (isPilotRedirect.value) {
router.replace({
name: 'PilotApplication',
query: { ...route.query, tab: 'infusion' }
})
return
}
if (isClinicalRedirect.value) {
router.replace({
name: 'ClinicalApplicationList',
query: { ...route.query, tab: 'infusion' }
})
}
})
</script>
@@ -253,6 +253,15 @@
defineOptions({ name: 'PilotServiceOutboundReleaseReview' })
const props = defineProps<{
/** 路由传入:仅列出对应业务线的申请单关联输注计划 */
bizType?: string
}>()
const isClinical = computed(() => props.bizType === 'clinical_application')
const effectiveBizType = computed(
() => props.bizType || (isClinical.value ? 'clinical_application' : 'pilot_service')
)
const reviewConclusionOptions = [
{ value: 'tg', label: '通过' },
{ value: 'btg', label: '不通过' }
@@ -280,7 +289,8 @@
page: pagination.page,
pageSize: pagination.pageSize,
reviewConclusion: searchForm.reviewConclusion || undefined,
keyword: searchForm.keyword || undefined
keyword: searchForm.keyword || undefined,
bizType: effectiveBizType.value
})
tableData.value = res.list || []
pagination.total = res.total ?? 0
@@ -37,7 +37,10 @@
<div class="section-title">
<div class="section-title-left"><h3>申请单信息</h3></div>
</div>
<div class="form-grid form-grid--col4">
<div
class="form-grid form-grid--col4"
:class="{ 'clinical-application-info-grid': isClinical }"
>
<el-form-item label="申请单名称" prop="applicationName">
<el-input v-model="formData.applicationName" placeholder="请输入申请单名称" />
</el-form-item>
@@ -59,6 +62,18 @@
/>
</el-select>
</el-form-item>
<el-form-item
v-if="isClinical"
label="备注"
class="clinical-application-remark"
>
<el-input
v-model="formData.remark"
type="textarea"
placeholder="请输入备注"
:rows="2"
/>
</el-form-item>
<el-form-item
v-if="!isClinical"
label="服务订单"
@@ -92,7 +107,7 @@
</el-button>
</div>
</el-form-item>
<el-form-item label="备注" class="form-col-full">
<el-form-item v-if="!isClinical" label="备注" class="form-col-full">
<el-input
v-model="formData.remark"
type="textarea"
@@ -173,7 +188,12 @@
<el-form-item label="紧急联系人电话" prop="emergencyPhone">
<el-input v-model="patientForm.emergencyPhone" placeholder="请输入紧急联系人电话" />
</el-form-item>
<el-form-item label="是否需要体检" prop="needCheckup" class="patient-checkup-field">
<el-form-item
v-if="!isClinical"
label="是否需要体检"
prop="needCheckup"
class="patient-checkup-field"
>
<el-switch
v-model="patientForm.needCheckup"
:active-value="1"
@@ -266,7 +286,7 @@
请先在「申请单信息」中选择渠道与服务订单,系统将按订单类型加载协议与可选细胞产品。
</p>
<p v-if="isClinical" class="section-title-hint">
请先在「申请单信息」中选择渠道,系统将加载可选细胞产品。
请先选择渠道并添加输注计划;细胞项目从「细胞价格体系」加载(与渠道协议无关)。
</p>
</div>
</div>
@@ -479,7 +499,11 @@
</el-table-column>
<el-table-column prop="cellTypeName" label="细胞类型" min-width="100" />
<el-table-column prop="specText" label="规格" min-width="100" />
<el-table-column label="协议单价(元)" min-width="130" align="right">
<el-table-column
:label="isClinical ? '参考单价(元)' : '协议单价(元)'"
min-width="130"
align="right"
>
<template #default="{ row }">
<span class="cell-product-price-text">
¥{{ formatOrderBalance(row.agreementPrice) }}
@@ -799,6 +823,7 @@
fetchPilotPatient,
fetchChannelAgreements,
fetchChannelAgreementPrices,
fetchCellProductPriceList,
fetchDictDataOptions,
fetchCustomerList,
fetchCreateCustomer
@@ -935,15 +960,20 @@
const onChannelChange = async (channelId: string) => {
formData.channelServiceOrderId = ''
serviceOrderOptions.value = []
resetInfusionOrderContext()
if (!channelId) return
if (isClinical.value) {
// 临床模式:直接加载渠道协议,无需服务订单
await loadAgreements(channelId)
// 临床:价格池与渠道无关;切换渠道时勿清空 agreementPriceOptions(否则「添加细胞产品」会失效)
clearScheduleCellProducts()
if (!channelId) return
if (!agreementPriceOptions.value.length) {
await loadClinicalCellProductPrices()
}
return
}
resetInfusionOrderContext()
if (!channelId) return
serviceOrderLoading.value = true
try {
serviceOrderOptions.value = await fetchAllPagedRecords((page, pageSize) =>
@@ -1089,7 +1119,6 @@
const canAddCellProduct = computed(() => {
if (isClinical.value) {
// 临床模式:需要渠道和协议价格
return !!formData.channelId && agreementPriceOptions.value.length > 0
}
return !!selectedServiceOrder.value && agreementPriceOptions.value.length > 0
@@ -1662,6 +1691,41 @@
}))
}
const normalizeCellProductPriceRows = (rows: any[]) => {
return (Array.isArray(rows) ? rows : []).map((p) => ({
priceId: p.id,
projectCode: p.projectCode || '',
projectName: p.projectName || '',
cellTypeCode: p.cellTypeCode || '',
cellTypeName: p.cellTypeName || '',
specText: p.specText || '',
unitPrice: p.unitPrice ?? 0,
source: 'cell_price' as const
}))
}
/** 临床申请单:从细胞价格体系(biz_cell_product_price)加载可选项目 */
const loadClinicalCellProductPrices = async () => {
agreementPriceLoading.value = true
try {
const rows = await fetchAllPagedRecords(async (page, pageSize) => {
const data: any = await fetchCellProductPriceList({ page, pageSize })
return {
list: data?.list ?? [],
total: data?.total ?? 0
}
})
agreementPriceOptions.value = normalizeCellProductPriceRows(rows)
if (!agreementPriceOptions.value.length) {
ElMessage.warning('细胞价格体系暂无数据,请先在「细胞产品基础信息」中维护价格')
}
} catch {
agreementPriceOptions.value = []
} finally {
agreementPriceLoading.value = false
}
}
// 疗程数变化 → 自动增减输注计划 + 自动计算输注时间
const computeScheduleTime = (index: number): string => {
if (!infusionPlan.infusionStartDate || !infusionPlan.courseInterval) return ''
@@ -1860,6 +1924,9 @@
loadChannels()
loadInfusionMethodOptions()
remoteSearchCustomers('')
if (isClinical.value) {
loadClinicalCellProductPrices()
}
if (isEdit.value && props.editId) {
loadEditData(props.editId)
}
@@ -2002,10 +2069,12 @@
}))
}))
}
if (formData.channelId) {
if (formData.channelId && !isClinical.value) {
await loadAgreements(formData.channelId)
}
if (!isClinical.value && formData.channelServiceOrderId) {
if (isClinical.value) {
await loadClinicalCellProductPrices()
} else if (formData.channelServiceOrderId) {
await onServiceOrderChange(formData.channelServiceOrderId, { preserveCellProducts: true })
} else if (infusionPlan.channelAgreementId) {
await onAgreementChange(infusionPlan.channelAgreementId)
@@ -2031,7 +2100,10 @@
try {
const payload: Record<string, any> = {
applicationName: formData.applicationName || undefined,
channelServiceOrderId: formData.channelServiceOrderId || undefined,
channelId: formData.channelId || undefined,
channelServiceOrderId: isClinical.value
? undefined
: formData.channelServiceOrderId || undefined,
remark: formData.remark || undefined,
bizType: props.bizType || undefined,
patient: {
@@ -2049,7 +2121,7 @@
.map((f) => f.fileUrl)
.filter(Boolean)
.join(',') || undefined,
needCheckup: patientForm.needCheckup
needCheckup: isClinical.value ? 0 : patientForm.needCheckup
},
infusionPlan: {
id: infusionPlan.id || undefined,
@@ -2154,6 +2226,10 @@
grid-column: span 2;
}
.clinical-application-remark {
grid-column: span 2;
}
:deep(.el-form-item) {
margin-bottom: 0;
}
@@ -558,15 +558,26 @@
</el-table>
</div>
<el-empty v-else description="暂无细胞产品" :image-size="32" />
<div
v-if="isYfkOrder && schedule.cellProducts?.length"
class="schedule-amount-summary"
>
本次输注计划金额:
<span class="schedule-amount-summary__value">
¥{{ formatOrderBalance(calcScheduleAmount(schedule)) }}
</span>
</div>
<div
v-if="isYfkOrder && schedule.cellProducts?.length"
class="schedule-amount-summary"
>
本次输注计划金额:
<span class="schedule-amount-summary__value">
¥{{ formatOrderBalance(calcScheduleAmount(schedule)) }}
</span>
</div>
</div>
<div v-if="isClinicalApplication" class="schedule-payment-block">
<div class="section-subtitle">缴费明细</div>
<ClinicalSchedulePaymentDetailView
v-if="schedule.payment"
:payment="schedule.payment"
@preview="openPreview"
@download="downloadFile"
/>
<el-empty v-else description="暂无缴费记录" :image-size="32" />
</div>
<InfusionScheduleOutboundChainView
@@ -773,6 +784,7 @@
} from '@/components/business/system-view-dialog/index.vue'
import ServiceOrderTxnTable from '@/views/pilot-service/channel-service-order/ServiceOrderTxnTable.vue'
import InfusionScheduleOutboundChainView from '@/components/business/infusion-schedule-outbound-chain-view/index.vue'
import ClinicalSchedulePaymentDetailView from '@/components/business/clinical-schedule-payment-detail/index.vue'
import {
fetchPilotApplicationDetail,
fetchPilotPatient,
@@ -874,6 +886,9 @@
const isYfkOrder = computed(() => serviceOrderDetail.value?.orderType === 'yfk')
const isGmcpOrder = computed(() => serviceOrderDetail.value?.orderType === 'gmcp')
const isClinicalApplication = computed(
() => applicationDetail.value?.bizType === 'clinical_application'
)
const settlementModeLabel = computed(() => {
const t = serviceOrderDetail.value?.orderType
@@ -1582,6 +1597,12 @@
gap: 8px;
}
.schedule-payment-block {
margin-top: 16px;
padding-top: 16px;
border-top: 1px dashed #e2e8f0;
}
.checkup-block-gap {
height: 16px;
}
@@ -296,6 +296,9 @@
defineOptions({ name: 'CheckupManagementTab' })
const props = defineProps<{ bizType?: string }>()
const isClinical = computed(() => props.bizType === 'clinical_application')
// ── 搜索 ─────────────────────────────
const searchForm = reactive({
keyword: '',
@@ -339,7 +342,9 @@
pageSize: pagination.pageSize,
keyword: searchForm.keyword || undefined,
checkupStatus: searchForm.checkupStatus || undefined,
checkupInstitutionId: searchForm.checkupInstitutionId || undefined
checkupInstitutionId: searchForm.checkupInstitutionId || undefined,
bizType:
props.bizType || (isClinical.value ? 'clinical_application' : 'pilot_service')
})
tableData.value = res?.list ?? []
pagination.total = res?.pagination?.total ?? 0
File diff suppressed because it is too large. Load diff
@@ -453,7 +453,8 @@
keyword: searchForm.keyword || undefined,
infusionStatus: searchForm.infusionStatus || undefined,
qcStatus: searchForm.qcStatus || undefined,
bizType: props.bizType || undefined
bizType:
props.bizType || (isClinical.value ? 'clinical_application' : 'pilot_service')
}
if (searchForm.infusionTimeRange?.length === 2) {
params.infusionTimeStart = searchForm.infusionTimeRange[0]
@@ -374,7 +374,8 @@
if (searchForm.keyword) params.keyword = searchForm.keyword
if (searchForm.channelId) params.channelId = searchForm.channelId
if (searchForm.applicationStatus) params.applicationStatus = searchForm.applicationStatus
if (props.bizType) params.bizType = props.bizType
params.bizType =
props.bizType || (isClinical.value ? 'clinical_application' : 'pilot_service')
const res: any = await fetchPilotApplicationList(params)
tableData.value = res?.list ?? res?.records ?? []
@@ -1,12 +1,56 @@
<!-- 中试服务申请单(申请单 / 体检 / 输注计划) -->
<!-- 中试服务申请单(申请单 / 体检 / 输注计划);临床申请单(申请单 / 输注计划 / 缴费信息) -->
<template>
<div class="page-container">
<section class="panel">
<template v-if="isClinical">
<div class="panel-top">
<h2 class="title-bar-heading">临床申请单</h2>
<div class="panel-entity-switch" role="tablist" aria-label="视图类型">
<button
type="button"
class="entity-switch-card"
:class="{ 'is-active': activeTab === 'application' }"
role="tab"
:aria-selected="activeTab === 'application'"
@click="activeTab = 'application'"
>
<span class="entity-switch-card__icon"><el-icon><Document /></el-icon></span>
<span class="entity-switch-card__main">
<span class="entity-switch-card__title">临床申请单</span>
<span class="entity-switch-card__desc">申请单录入、审核与跟踪</span>
</span>
</button>
<button
type="button"
class="entity-switch-card"
:class="{ 'is-active': activeTab === 'infusion' }"
role="tab"
:aria-selected="activeTab === 'infusion'"
@click="activeTab = 'infusion'"
>
<span class="entity-switch-card__icon"><el-icon><Operation /></el-icon></span>
<span class="entity-switch-card__main">
<span class="entity-switch-card__title">输注计划管理</span>
<span class="entity-switch-card__desc">输注计划安排与执行</span>
</span>
</button>
<button
type="button"
class="entity-switch-card"
:class="{ 'is-active': activeTab === 'payment' }"
role="tab"
:aria-selected="activeTab === 'payment'"
@click="activeTab = 'payment'"
>
<span class="entity-switch-card__icon"><el-icon><Wallet /></el-icon></span>
<span class="entity-switch-card__main">
<span class="entity-switch-card__title">缴费信息</span>
<span class="entity-switch-card__desc">缴费提交与状态跟踪</span>
</span>
</button>
</div>
<PilotApplicationTab :biz-type="bizType" />
<PilotApplicationTab v-if="activeTab === 'application'" :biz-type="effectiveBizType" />
<InfusionScheduleTab v-else-if="activeTab === 'infusion'" :biz-type="effectiveBizType" />
<ClinicalPaymentTab v-else-if="activeTab === 'payment'" />
</template>
<template v-else>
@@ -55,36 +99,49 @@
</button>
</div>
<PilotApplicationTab v-if="activeTab === 'application'" />
<CheckupManagementTab v-else-if="activeTab === 'checkup'" />
<InfusionScheduleTab v-else-if="activeTab === 'infusion'" />
<PilotApplicationTab v-if="activeTab === 'application'" :biz-type="effectiveBizType" />
<CheckupManagementTab v-else-if="activeTab === 'checkup'" :biz-type="effectiveBizType" />
<InfusionScheduleTab v-else-if="activeTab === 'infusion'" :biz-type="effectiveBizType" />
</template>
</section>
</div>
</template>
<script setup lang="ts">
import { Document, Calendar, Operation } from '@element-plus/icons-vue'
import { Document, Calendar, Operation, Wallet } from '@element-plus/icons-vue'
import PilotApplicationTab from './PilotApplicationTab.vue'
import CheckupManagementTab from './CheckupManagementTab.vue'
import InfusionScheduleTab from './InfusionScheduleTab.vue'
import ClinicalPaymentTab from './ClinicalPaymentTab.vue'
defineOptions({ name: 'PilotApplicationManagement' })
const props = defineProps<{ bizType?: string }>()
const isClinical = computed(() => props.bizType === 'clinical_application')
/** 中试菜单固定 pilot_service;临床由路由传入 clinical_application */
const effectiveBizType = computed(
() => props.bizType || (isClinical.value ? 'clinical_application' : 'pilot_service')
)
const VALID_TABS = ['application', 'checkup', 'infusion'] as const
type EntityTabKey = (typeof VALID_TABS)[number]
const PILOT_TABS = ['application', 'checkup', 'infusion'] as const
const CLINICAL_TABS = ['application', 'infusion', 'payment'] as const
type PilotTabKey = (typeof PILOT_TABS)[number]
type ClinicalTabKey = (typeof CLINICAL_TABS)[number]
type EntityTabKey = PilotTabKey | ClinicalTabKey
const route = useRoute()
const activeTab = ref<EntityTabKey>('application')
onMounted(() => {
if (isClinical.value) return
const tab = String(route.query.tab || '')
if (VALID_TABS.includes(tab as EntityTabKey)) {
activeTab.value = tab as EntityTabKey
if (isClinical.value) {
if (CLINICAL_TABS.includes(tab as ClinicalTabKey)) {
activeTab.value = tab as ClinicalTabKey
}
return
}
if (PILOT_TABS.includes(tab as PilotTabKey)) {
activeTab.value = tab as PilotTabKey
}
})
</script>
File diff suppressed because it is too large. Load diff