This commit is contained in:
zlwu committed 2026-06-15 11:43:16 +08:00
1 parent 427bcb1551
commit 31b04575e2
247 files changed
+39284 -20367

No files matched your search

@@ -89,8 +89,14 @@
<el-select
v-model="row.materialId"
filterable
placeholder="搜索并选择物料"
remote
reserve-keyword
clearable
placeholder="输入物料名称检索"
:loading="materialOptionsLoading"
:remote-method="remoteSearchMaterials"
class="inner-cell-input"
@visible-change="(visible) => visible && remoteSearchMaterials('')"
@change="(v) => onMaterialSelect($index, v)"
>
<el-option
@@ -399,7 +405,7 @@
} from '@element-plus/icons-vue'
import { fetchUploadAttachment } from '@/api/business'
import { fetchCellProductList } from '@/api/cell-product'
import { fetchQcMaterialOptions, type QcMaterialOption } from '@/api/qc-material'
import { fetchQcMaterialList, type QcMaterialOption } from '@/api/qc-material'
import type { OutboundReleaseCellRow } from '@/api/outbound-release-review'
import { downloadAttachmentFile } from '@/utils/download-attachment'
import { cellProductStatusLabel, cellProductStatusTagType } from '@/utils/status-tag-registry'
@@ -455,6 +461,7 @@
const materialRows = ref<MaterialRow[]>([])
const paperRows = ref<PaperRow[]>([])
const materialOptions = ref<QcMaterialOption[]>([])
const materialOptionsLoading = ref(false)
const cellSelectVisible = ref(false)
const cellSearchKeyword = ref('')
@@ -508,6 +515,54 @@
)
}
function mapMaterialListToOptions(list: Array<Record<string, any>>): QcMaterialOption[] {
return (list || []).map((m) => ({
id: String(m.id || ''),
label: `${m.materialName || ''}${m.materialCode ? ` (${m.materialCode})` : ''}`.trim(),
materialCode: String(m.materialCode || ''),
materialName: String(m.materialName || ''),
specModel: String(m.specModel || ''),
unit: String(m.unit || ''),
stockQty: Number(m.stockQty ?? 0)
}))
}
function ensureMaterialsInOptions(rows: MaterialRow[]) {
const merged = [...materialOptions.value]
for (const row of rows) {
const id = String(row.materialId || '')
if (!id || merged.some((o) => o.id === id)) continue
merged.push({
id,
label: row.materialName || id,
materialCode: '',
materialName: row.materialName || '',
specModel: row.specModel || '',
unit: row.unit || '',
stockQty: 0
})
}
materialOptions.value = merged
}
async function remoteSearchMaterials(query: string) {
materialOptionsLoading.value = true
try {
const res = await fetchQcMaterialList({
page: 1,
pageSize: 100,
keyword: query?.trim() || undefined
})
materialOptions.value = mapMaterialListToOptions(res.list || [])
ensureMaterialsInOptions(materialRows.value)
} catch {
materialOptions.value = []
ensureMaterialsInOptions(materialRows.value)
} finally {
materialOptionsLoading.value = false
}
}
function stockQtyDisplay(materialId: string) {
const opt = materialOptions.value.find((o) => o.id === materialId)
if (!opt || opt.stockQty == null) return '—'
@@ -713,15 +768,7 @@
remark: m.remark || ''
}))
paperRows.value = mapPaperRowsFromApi(data.paperMaterials, data.paperAttachments)
}
async function ensureMaterialOptions() {
if (materialOptions.value.length) return
try {
materialOptions.value = (await fetchQcMaterialOptions()) || []
} catch {
materialOptions.value = []
}
await remoteSearchMaterials('')
}
function validateMaterial() {
@@ -779,7 +826,7 @@
}
onMounted(() => {
ensureMaterialOptions()
void remoteSearchMaterials('')
})
function resetState() {
@@ -840,7 +887,7 @@
resetState,
validateMaterial,
buildSavePayload,
ensureMaterialOptions
remoteSearchMaterials
})
</script>
@@ -83,7 +83,7 @@
<dt>退费金额(元)</dt>
<dd>{{ formatPaymentAmount(detail?.refundAmount) }}</dd>
</div>
<div v-if="detail?.refundRemark" class="view-kv view-kv-span-2">
<div class="view-kv view-kv-span-3">
<dt>退费备注</dt>
<dd>{{ dash(detail?.refundRemark) }}</dd>
</div>
@@ -235,6 +235,16 @@
grid-column: 1 / -1;
}
.view-kv-span-3 {
grid-column: span 3;
}
@media (max-width: 719px) {
.view-kv-span-3 {
grid-column: 1 / -1;
}
}
.view-field-block__label {
font-size: 12px;
color: var(--mint-text-muted, #64748b);
@@ -42,7 +42,7 @@
<template #default="{ row }">{{ row.collectAmount ?? '—' }}</template>
</el-table-column>
<el-table-column label="单位" min-width="72" align="center" header-align="center">
<template #default="{ row }">{{ unitName(row.unitId) }}</template>
<template #default="{ row }">{{ displayUnitName(row) }}</template>
</el-table-column>
<el-table-column
v-if="showPrice"
@@ -101,7 +101,7 @@
</el-table-column>
<el-table-column
label="操作"
min-width="160"
min-width="260"
fixed="right"
align="center"
header-align="center"
@@ -143,8 +143,15 @@
<el-form-item label="样本类型">
<el-select
v-model="sampleDraft.sampleTypeId"
placeholder="选择类型"
placeholder="输入类型检索"
filterable
remote
reserve-keyword
clearable
:loading="sampleTypeOptionsLoading"
:remote-method="handleRemoteSearchSampleType"
style="width: 100%"
@visible-change="onSampleTypeSelectVisible"
@change="onSampleTypeChange(sampleDraft)"
>
<el-option
@@ -158,9 +165,15 @@
<el-form-item label="样本编码">
<el-select
v-model="sampleDraft.sampleCodeId"
placeholder="选择编码"
placeholder="输入编码检索"
filterable
remote
reserve-keyword
clearable
:loading="sampleCodeOptionsLoading"
:remote-method="handleRemoteSearchSampleCode"
style="width: 100%"
@visible-change="onSampleCodeSelectVisible"
@change="onSampleCodeChange(sampleDraft)"
>
<el-option
@@ -184,9 +197,16 @@
<el-form-item label="单位">
<el-select
v-model="sampleDraft.unitId"
placeholder="单位"
placeholder="输入单位检索"
filterable
remote
reserve-keyword
clearable
:loading="unitOptionsLoading"
:remote-method="handleRemoteSearchUnit"
style="width: 100%"
@visible-change="onUnitSelectVisible"
@change="onSampleUnitChange"
>
<el-option v-for="u in unitOptions" :key="u.id" :label="u.unitName" :value="u.id" />
</el-select>
@@ -273,10 +293,15 @@
<el-form-item label="目的站点">
<el-select
v-model="batchTransport.destSiteId"
placeholder="选择站点"
placeholder="输入站点检索"
filterable
remote
reserve-keyword
clearable
:loading="siteOptionsLoading"
:remote-method="handleRemoteSearchSite"
style="width: 100%"
@visible-change="onSiteSelectVisible"
>
<el-option
v-for="site in siteOptions"
@@ -301,10 +326,15 @@
<el-form-item label="快递公司">
<el-select
v-model="batchTransport.expressCompanyId"
placeholder="选择快递公司"
placeholder="输入快递公司检索"
filterable
remote
reserve-keyword
clearable
:loading="expressCompanyOptionsLoading"
:remote-method="handleRemoteSearchExpressCompany"
style="width: 100%"
@visible-change="onExpressCompanySelectVisible"
>
<el-option
v-for="ec in expressCompanyOptions"
@@ -379,13 +409,31 @@
expressCompanyOptions: Api.ExpressCompany.ExpressCompanyItem[]
showPrice?: boolean
sampleCodeUsedKey?: 'usedInProtocol'
sampleCodeOptionsLoading?: boolean
sampleTypeOptionsLoading?: boolean
unitOptionsLoading?: boolean
siteOptionsLoading?: boolean
expressCompanyOptionsLoading?: boolean
}>(),
{ showPrice: false, sampleCodeUsedKey: 'usedInProtocol' }
{
showPrice: false,
sampleCodeUsedKey: 'usedInProtocol',
sampleCodeOptionsLoading: false,
sampleTypeOptionsLoading: false,
unitOptionsLoading: false,
siteOptionsLoading: false,
expressCompanyOptionsLoading: false
}
)
const emit = defineEmits<{
(e: 'update:samples', val: Array<Record<string, any>>): void
(e: 'price-change'): void
(e: 'search-sample-code', query: string): void
(e: 'search-sample-type', query: string): void
(e: 'search-unit', query: string): void
(e: 'search-site', query: string): void
(e: 'search-express-company', query: string): void
}>()
type SampleTransportForm = {
@@ -474,9 +522,21 @@
if (fromType != null) row.originalPrice = fromType
}
function displayUnitName(row: Record<string, any>) {
const id = String(row.unitId || '')
const rowName = String(row.unitName || '').trim()
if (rowName && rowName !== id) return rowName
if (!id) return '—'
const optName = props.unitOptions.find((x) => x.id === id)?.unitName
if (optName && optName !== id) return optName
return '—'
}
function unitName(id: string) {
if (!id) return '—'
return props.unitOptions.find((x) => x.id === id)?.unitName || '—'
const name = props.unitOptions.find((x) => x.id === id)?.unitName
if (!name || name === id) return '—'
return name
}
function siteName(id: string) {
@@ -524,6 +584,57 @@
return props.samples.some((s) => s !== row && String(s.sampleCodeId || '') === sc.id)
}
function handleRemoteSearchSampleCode(query: string) {
emit('search-sample-code', query)
}
function onSampleCodeSelectVisible(visible: boolean) {
if (visible) emit('search-sample-code', '')
}
function handleRemoteSearchSampleType(query: string) {
emit('search-sample-type', query)
}
function onSampleTypeSelectVisible(visible: boolean) {
if (visible) emit('search-sample-type', '')
}
function handleRemoteSearchUnit(query: string) {
emit('search-unit', query)
}
function onUnitSelectVisible(visible: boolean) {
if (visible) emit('search-unit', '')
}
function handleRemoteSearchSite(query: string) {
emit('search-site', query)
}
function onSiteSelectVisible(visible: boolean) {
if (visible) emit('search-site', '')
}
function handleRemoteSearchExpressCompany(query: string) {
emit('search-express-company', query)
}
function onExpressCompanySelectVisible(visible: boolean) {
if (visible) emit('search-express-company', '')
}
function refreshSampleDialogOptions() {
emit('search-sample-type', '')
emit('search-sample-code', '')
emit('search-unit', '')
}
function refreshBatchTransportOptions() {
emit('search-site', '')
emit('search-express-company', '')
}
function onSampleCodeChange(row: Record<string, any>) {
const sc = props.sampleCodeOptions.find((x) => x.id === row.sampleCodeId)
if (sc) {
@@ -543,6 +654,15 @@
}
}
function onSampleUnitChange(unitId: string | null | undefined) {
if (!unitId) {
sampleDraft.unitName = ''
return
}
const u = props.unitOptions.find((x) => x.id === unitId)
sampleDraft.unitName = u?.unitName || ''
}
function onSampleStatusChange(row: Record<string, any>) {
if (row.sampleStatus == null) {
row.sampleStatus = ''
@@ -560,6 +680,7 @@
}
Object.assign(batchTransport, createEmptyTransport())
batchTransportVisible.value = true
refreshBatchTransportOptions()
}
function confirmBatchTransportApply() {
@@ -600,6 +721,7 @@
)
)
sampleDialogVisible.value = true
refreshSampleDialogOptions()
}
function openEditSampleDialog(row: Record<string, any>, index: number) {
@@ -607,8 +729,13 @@
sampleDialogIndex.value = index
const draft = normalizeSampleRow({ ...row, transport: { ...row.transport } }, index)
ensureSampleOriginalPrice(draft)
if (!draft.unitName && draft.unitId) {
const u = props.unitOptions.find((x) => x.id === draft.unitId)
if (u?.unitName && u.unitName !== u.id) draft.unitName = u.unitName
}
Object.assign(sampleDraft, draft)
sampleDialogVisible.value = true
refreshSampleDialogOptions()
}
function confirmSampleDialog() {
@@ -626,6 +753,10 @@
{ ...sampleDraft },
sampleDialogIndex.value >= 0 ? sampleDialogIndex.value : next.length
)
if (!normalized.unitName && normalized.unitId) {
const u = props.unitOptions.find((x) => x.id === normalized.unitId)
if (u?.unitName && u.unitName !== u.id) normalized.unitName = u.unitName
}
if (sampleDialogMode.value === 'add') {
next.push(normalized)
} else {
@@ -195,8 +195,8 @@
{
width: '720px',
gridColumns: 2,
appendToBody: false,
modalClass: '',
appendToBody: true,
modalClass: 'protocol-dialog-mask',
dialogClass: '',
compact: false,
loading: false