提交
This commit is contained in:
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
|
||||
|
||||
Reference in new issue
Block a user