提交
This commit is contained in:
1 parent
4a00f21bfb
commit
edf88dc016
1503 files changed
+329728
-41987
No files matched your search
@@ -59,7 +59,11 @@
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="服务订单" prop="channelServiceOrderId" class="form-col-span-2-cols">
|
||||
<el-form-item
|
||||
label="服务订单"
|
||||
prop="channelServiceOrderId"
|
||||
class="form-col-span-2-cols"
|
||||
>
|
||||
<div class="field-with-action">
|
||||
<el-select
|
||||
v-model="formData.channelServiceOrderId"
|
||||
@@ -227,7 +231,9 @@
|
||||
</template>
|
||||
</div>
|
||||
<div class="attachment-footer">
|
||||
<span class="attachment-name" :title="file.fileName">{{ file.fileName }}</span>
|
||||
<span class="attachment-name" :title="file.fileName">{{
|
||||
file.fileName
|
||||
}}</span>
|
||||
<div class="attachment-actions">
|
||||
<el-icon class="action-btn" @click.stop="downloadFile(file)">
|
||||
<Download />
|
||||
@@ -305,10 +311,7 @@
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<template #label>疗程间隔<span class="form-label-tip">(月)</span></template>
|
||||
<el-input
|
||||
v-model="infusionPlan.courseInterval"
|
||||
placeholder="请输入疗程间隔"
|
||||
/>
|
||||
<el-input v-model="infusionPlan.courseInterval" placeholder="请输入疗程间隔" />
|
||||
</el-form-item>
|
||||
<el-form-item label="输注开始日期">
|
||||
<el-date-picker
|
||||
@@ -353,7 +356,24 @@
|
||||
<div class="schedule-header" @click="toggleScheduleExpand(sIdx)">
|
||||
<span class="schedule-chevron">▶</span>
|
||||
<span class="schedule-title">输注计划 #{{ sIdx + 1 }}</span>
|
||||
<el-tag
|
||||
v-if="schedule.infusionStatus"
|
||||
:type="infusionStatusTagType(normalizeInfusionStatusCode(schedule.infusionStatus))"
|
||||
size="small"
|
||||
class="schedule-status-tag"
|
||||
>
|
||||
{{ infusionStatusLabel(normalizeInfusionStatusCode(schedule.infusionStatus)) }}
|
||||
</el-tag>
|
||||
<el-tag
|
||||
v-if="schedule.scheduleStatus && isEdit"
|
||||
:type="scheduleStatusTagType(schedule.scheduleStatus)"
|
||||
size="small"
|
||||
class="schedule-status-tag"
|
||||
>
|
||||
{{ scheduleStatusLabel(schedule.scheduleStatus) }}
|
||||
</el-tag>
|
||||
<el-button
|
||||
v-if="canDeleteSchedule(schedule)"
|
||||
link
|
||||
type="danger"
|
||||
size="small"
|
||||
@@ -373,6 +393,7 @@
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="自动计算,可修改"
|
||||
clearable
|
||||
:disabled="!isScheduleEditable(schedule)"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
@@ -380,6 +401,7 @@
|
||||
<el-input
|
||||
v-model="schedule.infusionLocation"
|
||||
placeholder="请输入输注地点"
|
||||
:disabled="!isScheduleEditable(schedule)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="输注方式">
|
||||
@@ -388,6 +410,7 @@
|
||||
clearable
|
||||
filterable
|
||||
placeholder="请选择输注方式"
|
||||
:disabled="!isScheduleEditable(schedule)"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
@@ -407,7 +430,7 @@
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
:disabled="!canAddCellProduct"
|
||||
:disabled="!canAddCellProduct || !isScheduleEditable(schedule)"
|
||||
@click="addCellProduct(sIdx)"
|
||||
>
|
||||
<el-icon><Plus /></el-icon>
|
||||
@@ -428,10 +451,8 @@
|
||||
clearable
|
||||
placeholder="选择项目"
|
||||
class="cell-product-table__control"
|
||||
:disabled="!canAddCellProduct"
|
||||
@change="
|
||||
onCellProductSelect(sIdx, pIdx, $event)
|
||||
"
|
||||
:disabled="!canAddCellProduct || !isScheduleEditable(schedule)"
|
||||
@change="onCellProductSelect(sIdx, pIdx, $event)"
|
||||
>
|
||||
<el-option
|
||||
v-for="p in getCellProductPriceOptions(sIdx, pIdx)"
|
||||
@@ -442,16 +463,8 @@
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="cellTypeName"
|
||||
label="细胞类型"
|
||||
min-width="100"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="specText"
|
||||
label="规格"
|
||||
min-width="100"
|
||||
/>
|
||||
<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">
|
||||
<template #default="{ row }">
|
||||
<span class="cell-product-price-text">
|
||||
@@ -465,6 +478,7 @@
|
||||
v-model="row.actualPrice"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:disabled="!isScheduleEditable(schedule)"
|
||||
controls-position="right"
|
||||
class="cell-product-table__control"
|
||||
/>
|
||||
@@ -475,6 +489,7 @@
|
||||
<el-input-number
|
||||
v-model="row.quantity"
|
||||
:min="1"
|
||||
:disabled="!isScheduleEditable(schedule)"
|
||||
controls-position="right"
|
||||
class="cell-product-table__control"
|
||||
/>
|
||||
@@ -485,18 +500,27 @@
|
||||
<el-input
|
||||
v-model="row.remark"
|
||||
placeholder="备注"
|
||||
:disabled="!isScheduleEditable(schedule)"
|
||||
class="cell-product-table__control"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag size="small" type="info">{{ row.status }}</el-tag>
|
||||
<el-tag
|
||||
:type="infusionStatusTagType(normalizeInfusionStatusCode(row.status))"
|
||||
size="small"
|
||||
>
|
||||
{{
|
||||
infusionStatusLabel(normalizeInfusionStatusCode(row.status))
|
||||
}}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" min-width="60" align="center">
|
||||
<template #default="{ $index: pIdx }">
|
||||
<el-button
|
||||
v-if="isScheduleEditable(schedule)"
|
||||
link
|
||||
type="danger"
|
||||
size="small"
|
||||
@@ -622,15 +646,45 @@
|
||||
class="list-table inner-table"
|
||||
max-height="360"
|
||||
>
|
||||
<el-table-column type="index" label="序号" min-width="68" align="center" header-align="center" />
|
||||
<el-table-column prop="projectName" label="项目名称" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
min-width="68"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="projectName"
|
||||
label="项目名称"
|
||||
min-width="150"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column prop="cellType" label="细胞类型" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="specText" label="规格文本" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column label="协议单价(元)" min-width="130" align="right" header-align="center">
|
||||
<template #default="{ row }">¥{{ formatOrderBalance(row.agreementUnitPrice) }}</template>
|
||||
<el-table-column
|
||||
label="协议单价(元)"
|
||||
min-width="130"
|
||||
align="right"
|
||||
header-align="center"
|
||||
>
|
||||
<template #default="{ row }"
|
||||
>¥{{ formatOrderBalance(row.agreementUnitPrice) }}</template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column prop="currentQty" label="当前持有" min-width="100" align="center" header-align="center" />
|
||||
<el-table-column prop="totalBuyQty" label="累计购买" min-width="100" align="center" header-align="center" />
|
||||
<el-table-column
|
||||
prop="currentQty"
|
||||
label="当前持有"
|
||||
min-width="100"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="totalBuyQty"
|
||||
label="累计购买"
|
||||
min-width="100"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="totalUnsubscribeQty"
|
||||
label="累计退订"
|
||||
@@ -668,12 +722,38 @@
|
||||
class="list-table inner-table"
|
||||
max-height="360"
|
||||
>
|
||||
<el-table-column type="index" label="序号" min-width="68" align="center" header-align="center" />
|
||||
<el-table-column prop="projectName" label="项目名称" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="projectCode" label="项目编码" min-width="110" show-overflow-tooltip />
|
||||
<el-table-column prop="cellTypeName" label="细胞类型" min-width="110" show-overflow-tooltip />
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
min-width="68"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="projectName"
|
||||
label="项目名称"
|
||||
min-width="140"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="projectCode"
|
||||
label="项目编码"
|
||||
min-width="110"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="cellTypeName"
|
||||
label="细胞类型"
|
||||
min-width="110"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column prop="specText" label="规格" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="协议单价(元)" min-width="130" align="right" header-align="center">
|
||||
<el-table-column
|
||||
label="协议单价(元)"
|
||||
min-width="130"
|
||||
align="right"
|
||||
header-align="center"
|
||||
>
|
||||
<template #default="{ row }">¥{{ formatOrderBalance(row.unitPrice) }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -685,7 +765,17 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { Plus, Delete, Close, Check, Download, Document, VideoPlay, Loading, View } from '@element-plus/icons-vue'
|
||||
import {
|
||||
Plus,
|
||||
Delete,
|
||||
Close,
|
||||
Check,
|
||||
Download,
|
||||
Document,
|
||||
VideoPlay,
|
||||
Loading,
|
||||
View
|
||||
} from '@element-plus/icons-vue'
|
||||
import {
|
||||
savePilotApplication,
|
||||
fetchPilotApplicationDetail,
|
||||
@@ -702,7 +792,9 @@
|
||||
import { fetchUploadAttachment } from '@/api/business'
|
||||
import { fetchAllPagedRecords } from '@/utils/fetch-paged-list'
|
||||
import DialogFormBody from '@/components/business/dialog-form-body/index.vue'
|
||||
import SystemViewDialog, { type ViewSection } from '@/components/business/system-view-dialog/index.vue'
|
||||
import SystemViewDialog, {
|
||||
type ViewSection
|
||||
} from '@/components/business/system-view-dialog/index.vue'
|
||||
import ServiceOrderTxnTable from '@/views/pilot-service/channel-service-order/ServiceOrderTxnTable.vue'
|
||||
import {
|
||||
channelServiceOrderTypeLabel,
|
||||
@@ -714,7 +806,11 @@
|
||||
agreementStatusLabel,
|
||||
agreementStatusTagType,
|
||||
settlementTypeLabel,
|
||||
settlementTypeTagType
|
||||
settlementTypeTagType,
|
||||
infusionStatusLabel,
|
||||
infusionStatusTagType,
|
||||
scheduleStatusLabel,
|
||||
scheduleStatusTagType
|
||||
} from '@/utils/status-tag-registry'
|
||||
import { formatMoneyDisplay } from '@/utils/money-format'
|
||||
|
||||
@@ -1250,7 +1346,11 @@
|
||||
const remoteSearchCustomers = async (keyword: string) => {
|
||||
customerLoading.value = true
|
||||
try {
|
||||
const res: any = await fetchCustomerList({ page: 1, pageSize: 50, keyword: keyword || undefined })
|
||||
const res: any = await fetchCustomerList({
|
||||
page: 1,
|
||||
pageSize: 50,
|
||||
keyword: keyword || undefined
|
||||
})
|
||||
const data = res?.data ?? res
|
||||
customerOptions.value = data?.list ?? data?.records ?? []
|
||||
} catch {
|
||||
@@ -1381,7 +1481,7 @@
|
||||
fileSize: file.size,
|
||||
fileSizeDisplay: `${(file.size / 1024).toFixed(1)} KB`,
|
||||
fileType: file.type || '',
|
||||
_uploading: true,
|
||||
_uploading: true
|
||||
})
|
||||
const idx = diagnosisFileList.value.length - 1
|
||||
|
||||
@@ -1397,7 +1497,7 @@
|
||||
fileSize: res.fileSize || file.size,
|
||||
fileSizeDisplay: res.fileSizeDisplay || `${(file.size / 1024).toFixed(1)} KB`,
|
||||
fileType: res.fileType || file.type || '',
|
||||
_uploading: false,
|
||||
_uploading: false
|
||||
}
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.message || '上传失败')
|
||||
@@ -1423,12 +1523,40 @@
|
||||
|
||||
// ── 输注方案(inline,一个申请单一个方案) ──────────────────────────────
|
||||
const infusionPlan = reactive({
|
||||
id: '' as string,
|
||||
totalCourseCount: 0,
|
||||
courseInterval: '',
|
||||
infusionStartDate: '',
|
||||
channelAgreementId: ''
|
||||
})
|
||||
|
||||
const INFUSION_STATUS_CN_TO_CODE: Record<string, string> = {
|
||||
待输注: 'dtz',
|
||||
已用户确认: 'yrqr',
|
||||
已取消: 'yqx',
|
||||
已完成: 'ywc'
|
||||
}
|
||||
|
||||
function normalizeInfusionStatusCode(raw: unknown): string {
|
||||
const s = String(raw ?? '').trim()
|
||||
if (!s) return ''
|
||||
return INFUSION_STATUS_CN_TO_CODE[s] || s
|
||||
}
|
||||
|
||||
/** 待输注 / 已用户确认:可编辑时间与细胞产品 */
|
||||
function isScheduleEditable(schedule: Record<string, any>): boolean {
|
||||
if (!isEdit.value) return true
|
||||
const st = normalizeInfusionStatusCode(schedule.infusionStatus)
|
||||
return st === 'dtz' || st === 'yrqr'
|
||||
}
|
||||
|
||||
/** 仅待输注可删疗程 */
|
||||
function canDeleteSchedule(schedule: Record<string, any>): boolean {
|
||||
if (!isEdit.value) return true
|
||||
if (!schedule.id) return true
|
||||
return normalizeInfusionStatusCode(schedule.infusionStatus) === 'dtz'
|
||||
}
|
||||
|
||||
// 输注计划列表
|
||||
let scheduleSeq = 0
|
||||
const infusionSchedules = ref<any[]>([])
|
||||
@@ -1574,6 +1702,11 @@
|
||||
}
|
||||
|
||||
const removeSchedule = (idx: number) => {
|
||||
const s = infusionSchedules.value[idx]
|
||||
if (s && !canDeleteSchedule(s)) {
|
||||
ElMessage.warning('当前疗程不可删除(仅待输注且未开始生产的计划可删)')
|
||||
return
|
||||
}
|
||||
infusionSchedules.value.splice(idx, 1)
|
||||
recalcAllScheduleTimes()
|
||||
syncTotalCourseCountWithSchedules()
|
||||
@@ -1583,6 +1716,10 @@
|
||||
const addCellProduct = (scheduleIdx: number) => {
|
||||
const s = infusionSchedules.value[scheduleIdx]
|
||||
if (!s) return
|
||||
if (!isScheduleEditable(s)) {
|
||||
ElMessage.warning('当前疗程状态不允许修改细胞产品')
|
||||
return
|
||||
}
|
||||
const usedKeys = new Set(
|
||||
(s.cellProducts || []).map((cp: any) => getCellProductProjectKey(cp)).filter(Boolean)
|
||||
)
|
||||
@@ -1605,13 +1742,17 @@
|
||||
actualPrice: 0,
|
||||
quantity: 1,
|
||||
remark: '',
|
||||
status: '待输注'
|
||||
status: 'dtz'
|
||||
})
|
||||
}
|
||||
|
||||
const removeCellProduct = (scheduleIdx: number, productIdx: number) => {
|
||||
const s = infusionSchedules.value[scheduleIdx]
|
||||
if (!s) return
|
||||
if (!isScheduleEditable(s)) {
|
||||
ElMessage.warning('当前疗程状态不允许修改细胞产品')
|
||||
return
|
||||
}
|
||||
s.cellProducts.splice(productIdx, 1)
|
||||
}
|
||||
|
||||
@@ -1701,6 +1842,7 @@
|
||||
patientForm.clinicalDiagnosis = ''
|
||||
patientForm.needCheckup = 0
|
||||
diagnosisFileList.value = []
|
||||
infusionPlan.id = ''
|
||||
infusionPlan.totalCourseCount = 0
|
||||
infusionPlan.courseInterval = ''
|
||||
infusionPlan.infusionStartDate = ''
|
||||
@@ -1775,7 +1917,7 @@
|
||||
fileSize: 0,
|
||||
fileSizeDisplay: '',
|
||||
fileType: '',
|
||||
_uploading: false,
|
||||
_uploading: false
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1788,6 +1930,7 @@
|
||||
try {
|
||||
if (detail.infusionPlan) {
|
||||
const ip = detail.infusionPlan
|
||||
infusionPlan.id = ip.id || ''
|
||||
infusionPlan.totalCourseCount = ip.totalCourseCount || 0
|
||||
infusionPlan.courseInterval = ip.courseInterval || ''
|
||||
infusionPlan.infusionStartDate = ip.infusionStartDate || ''
|
||||
@@ -1795,12 +1938,16 @@
|
||||
}
|
||||
if (detail.infusionSchedules && Array.isArray(detail.infusionSchedules)) {
|
||||
infusionSchedules.value = detail.infusionSchedules.map((s: any, i: number) => ({
|
||||
id: s.id || '',
|
||||
_localId: ++scheduleSeq,
|
||||
infusionTime: s.infusionTime || '',
|
||||
infusionLocation: s.infusionLocation || '',
|
||||
infusionMethod: s.infusionMethod || '',
|
||||
infusionStatus: normalizeInfusionStatusCode(s.infusionStatus) || 'dtz',
|
||||
scheduleStatus: s.scheduleStatus || 'dsc',
|
||||
_expanded: i === 0,
|
||||
cellProducts: (s.cellProducts || []).map((cp: any) => ({
|
||||
id: cp.id || '',
|
||||
_localId: ++scheduleSeq,
|
||||
priceId: cp.priceId || '',
|
||||
projectCode: cp.projectCode || '',
|
||||
@@ -1811,7 +1958,7 @@
|
||||
actualPrice: cp.actualPrice ?? 0,
|
||||
quantity: cp.quantity || 1,
|
||||
remark: cp.remark || '',
|
||||
status: cp.status || '待输注'
|
||||
status: normalizeInfusionStatusCode(cp.status) || 'dtz'
|
||||
}))
|
||||
}))
|
||||
}
|
||||
@@ -1856,21 +2003,28 @@
|
||||
emergencyContact: patientForm.emergencyContact || undefined,
|
||||
emergencyPhone: patientForm.emergencyPhone || undefined,
|
||||
clinicalDiagnosis: patientForm.clinicalDiagnosis || undefined,
|
||||
diagnosisAttachments: diagnosisFileList.value.map((f) => f.fileUrl).filter(Boolean).join(',') || undefined,
|
||||
diagnosisAttachments:
|
||||
diagnosisFileList.value
|
||||
.map((f) => f.fileUrl)
|
||||
.filter(Boolean)
|
||||
.join(',') || undefined,
|
||||
needCheckup: patientForm.needCheckup
|
||||
},
|
||||
infusionPlan: {
|
||||
id: infusionPlan.id || undefined,
|
||||
totalCourseCount: infusionPlan.totalCourseCount,
|
||||
courseInterval: infusionPlan.courseInterval || undefined,
|
||||
infusionStartDate: infusionPlan.infusionStartDate || undefined,
|
||||
channelAgreementId: infusionPlan.channelAgreementId || undefined
|
||||
},
|
||||
infusionSchedules: infusionSchedules.value.map((s, idx) => ({
|
||||
id: s.id || undefined,
|
||||
sortNo: idx + 1,
|
||||
infusionTime: s.infusionTime || undefined,
|
||||
infusionLocation: s.infusionLocation || undefined,
|
||||
infusionMethod: s.infusionMethod || undefined,
|
||||
cellProducts: (s.cellProducts || []).map((cp: any) => ({
|
||||
id: cp.id || undefined,
|
||||
priceId: cp.priceId || undefined,
|
||||
projectCode: cp.projectCode || undefined,
|
||||
projectName: cp.projectName || undefined,
|
||||
@@ -1879,8 +2033,7 @@
|
||||
agreementPrice: cp.agreementPrice ?? undefined,
|
||||
actualPrice: cp.actualPrice ?? undefined,
|
||||
quantity: cp.quantity || 1,
|
||||
remark: cp.remark || undefined,
|
||||
status: cp.status || '待输注'
|
||||
remark: cp.remark || undefined
|
||||
}))
|
||||
}))
|
||||
}
|
||||
@@ -2370,6 +2523,10 @@
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.schedule-status-tag {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.schedule-delete-btn {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user