feat(web-admin): add qc material month import template UI
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
e4dcb43d77
commit
6957952b4c
4 files changed
+764
-1
No files matched your search
@@ -0,0 +1,83 @@
|
||||
import request from '@/utils/http'
|
||||
|
||||
export interface QcMonthTemplateRow {
|
||||
id: string
|
||||
materialId?: string
|
||||
materialCode: string
|
||||
materialName: string
|
||||
specModel?: string
|
||||
unit?: string
|
||||
catalogNo: string
|
||||
batchNo: string
|
||||
manufacturer: string
|
||||
unitPrice: number
|
||||
amount: number
|
||||
inQty: number
|
||||
expireDate: string
|
||||
orderNum?: number
|
||||
remark?: string
|
||||
}
|
||||
|
||||
export interface QcMonthImportPreviewLine {
|
||||
templateId?: string
|
||||
materialId?: string
|
||||
materialCode: string
|
||||
materialName: string
|
||||
specModel?: string
|
||||
unit?: string
|
||||
stockInNo: string
|
||||
stockInDate: string
|
||||
expireDate: string
|
||||
catalogNo: string
|
||||
batchNo: string
|
||||
manufacturer: string
|
||||
unitPrice: number
|
||||
amount: number
|
||||
qty: number
|
||||
remark?: string
|
||||
}
|
||||
|
||||
export function fetchQcMonthTemplateList() {
|
||||
return request.get<QcMonthTemplateRow[]>({
|
||||
url: '/web/admin/qc-material-month-templates'
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchCreateQcMonthTemplate(data: Record<string, any>) {
|
||||
return request.post<QcMonthTemplateRow>({
|
||||
url: '/web/admin/qc-material-month-templates',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchUpdateQcMonthTemplate(id: string, data: Record<string, any>) {
|
||||
return request.put<QcMonthTemplateRow>({
|
||||
url: `/web/admin/qc-material-month-templates/${id}`,
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchDeleteQcMonthTemplate(id: string) {
|
||||
return request.delete<void>({
|
||||
url: `/web/admin/qc-material-month-templates/${id}`
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchPreviewQcMonthImport(stockInDate: string) {
|
||||
return request.post<QcMonthImportPreviewLine[]>({
|
||||
url: '/web/admin/qc-material-month-templates/preview',
|
||||
data: { stockInDate }
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchConfirmQcMonthImport(data: {
|
||||
stockInDate: string
|
||||
items: QcMonthImportPreviewLine[]
|
||||
remark?: string
|
||||
stockInTime?: string
|
||||
}) {
|
||||
return request.post<{ count: number }>({
|
||||
url: '/web/admin/qc-material-month-templates/confirm',
|
||||
data
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
<!-- 质检物料库 · 月初导入预览确认 -->
|
||||
<!-- eslint-disable vue/no-v-model-argument -->
|
||||
<template>
|
||||
<el-dialog
|
||||
:model-value="modelValue"
|
||||
title="月初导入"
|
||||
width="1080px"
|
||||
class="dialog-form-layout material-batch-stock-dialog"
|
||||
align-center
|
||||
append-to-body
|
||||
modal-class="protocol-dialog-mask"
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
@open="handleOpen"
|
||||
>
|
||||
<el-form label-position="top">
|
||||
<div class="form-grid-2 batch-stock-move-head">
|
||||
<el-form-item label="本次入库日期">
|
||||
<el-date-picker
|
||||
v-model="stockInDate"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="选择入库日期"
|
||||
style="width: 100%"
|
||||
@change="reloadPreview"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input
|
||||
v-model="remark"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="可选,未填写行备注时将作为默认备注"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<div class="batch-stock-move-lines-head" style="margin-bottom: 12px">
|
||||
<div class="batch-stock-move-lines-head-left">
|
||||
<span class="batch-stock-move-lines-title">入库明细</span>
|
||||
<span class="batch-stock-move-lines-hint">
|
||||
共 {{ lines.length }} 项,可改字段后确认;删除行仅影响本次
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-loading="loading">
|
||||
<div v-if="lines.length" class="batch-in-line-list">
|
||||
<div v-for="(row, index) in lines" :key="index" class="batch-in-line-card">
|
||||
<div class="batch-in-line-card-head">
|
||||
<span class="batch-in-line-card-index">{{ index + 1 }}</span>
|
||||
<el-button link type="danger" size="small" @click="lines.splice(index, 1)">
|
||||
<el-icon><Delete /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="batch-in-line-grid batch-in-line-card-body">
|
||||
<el-form-item label="物料" class="batch-in-col-span-2">
|
||||
<el-input
|
||||
:model-value="`${row.materialName}(${row.materialCode})`"
|
||||
size="small"
|
||||
disabled
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="入库编号">
|
||||
<el-input v-model="row.stockInNo" size="small" placeholder="必填" />
|
||||
</el-form-item>
|
||||
<el-form-item label="过期日期">
|
||||
<el-date-picker
|
||||
v-model="row.expireDate"
|
||||
type="date"
|
||||
size="small"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="货号">
|
||||
<el-input v-model="row.catalogNo" size="small" />
|
||||
</el-form-item>
|
||||
<el-form-item label="批号">
|
||||
<el-input v-model="row.batchNo" size="small" />
|
||||
</el-form-item>
|
||||
<el-form-item label="厂家">
|
||||
<el-input v-model="row.manufacturer" size="small" />
|
||||
</el-form-item>
|
||||
<el-form-item label="数量">
|
||||
<el-input-number
|
||||
v-model="row.qty"
|
||||
size="small"
|
||||
:min="0.0001"
|
||||
:precision="4"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
@change="() => recalcAmount(row)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="单价">
|
||||
<el-input-number
|
||||
v-model="row.unitPrice"
|
||||
size="small"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
@change="() => recalcAmount(row)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="金额">
|
||||
<el-input-number
|
||||
v-model="row.amount"
|
||||
size="small"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
@change="() => markAmountTouched(row)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" class="batch-in-col-span-2">
|
||||
<el-input v-model="row.remark" size="small" placeholder="可选" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-else description="暂无预览明细" :image-size="56" />
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button class="btn-ghost" @click="emit('update:modelValue', false)">
|
||||
<el-icon><Close /></el-icon>
|
||||
取消
|
||||
</el-button>
|
||||
<el-button class="btn-main" type="primary" :loading="submitting" @click="handleConfirm">
|
||||
<el-icon><Check /></el-icon>
|
||||
确认入库
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Check, Close, Delete } from '@element-plus/icons-vue'
|
||||
import {
|
||||
fetchConfirmQcMonthImport,
|
||||
fetchPreviewQcMonthImport,
|
||||
type QcMonthImportPreviewLine
|
||||
} from '@/api/qc-material-month-template'
|
||||
|
||||
defineOptions({ name: 'QcMaterialMonthImportDialog' })
|
||||
|
||||
defineProps<{ modelValue: boolean }>()
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', val: boolean): void
|
||||
(e: 'success'): void
|
||||
}>()
|
||||
|
||||
const loading = ref(false)
|
||||
const submitting = ref(false)
|
||||
const stockInDate = ref('')
|
||||
const remark = ref('')
|
||||
const lines = ref<QcMonthImportPreviewLine[]>([])
|
||||
const amountTouchedMap = ref<Record<number, boolean>>({})
|
||||
|
||||
function todayStr() {
|
||||
const d = new Date()
|
||||
const m = `${d.getMonth() + 1}`.padStart(2, '0')
|
||||
const day = `${d.getDate()}`.padStart(2, '0')
|
||||
return `${d.getFullYear()}-${m}-${day}`
|
||||
}
|
||||
|
||||
async function handleOpen() {
|
||||
stockInDate.value = todayStr()
|
||||
remark.value = ''
|
||||
amountTouchedMap.value = {}
|
||||
await reloadPreview()
|
||||
}
|
||||
|
||||
async function reloadPreview() {
|
||||
if (!stockInDate.value) {
|
||||
ElMessage.warning('请选择入库日期')
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
lines.value = (await fetchPreviewQcMonthImport(stockInDate.value)) || []
|
||||
amountTouchedMap.value = {}
|
||||
} catch {
|
||||
lines.value = []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function markAmountTouched(row: QcMonthImportPreviewLine) {
|
||||
const idx = lines.value.indexOf(row)
|
||||
if (idx >= 0) amountTouchedMap.value[idx] = true
|
||||
}
|
||||
|
||||
function recalcAmount(row: QcMonthImportPreviewLine) {
|
||||
const idx = lines.value.indexOf(row)
|
||||
if (idx >= 0 && amountTouchedMap.value[idx]) return
|
||||
const price = Number(row.unitPrice) || 0
|
||||
const qty = Number(row.qty) || 0
|
||||
row.amount = Number((price * qty).toFixed(2))
|
||||
}
|
||||
|
||||
async function handleConfirm() {
|
||||
if (!stockInDate.value) {
|
||||
ElMessage.warning('请选择入库日期')
|
||||
return
|
||||
}
|
||||
if (!lines.value.length) {
|
||||
ElMessage.warning('请至少保留一条入库明细')
|
||||
return
|
||||
}
|
||||
for (let i = 0; i < lines.value.length; i++) {
|
||||
const line = lines.value[i]
|
||||
if (!line.stockInNo?.trim()) {
|
||||
ElMessage.warning(`第 ${i + 1} 行请填写入库编号`)
|
||||
return
|
||||
}
|
||||
if (!line.expireDate) {
|
||||
ElMessage.warning(`第 ${i + 1} 行请选择过期日期`)
|
||||
return
|
||||
}
|
||||
if (!line.catalogNo?.trim() || !line.batchNo?.trim() || !line.manufacturer?.trim()) {
|
||||
ElMessage.warning(`第 ${i + 1} 行货号/批号/厂家不能为空`)
|
||||
return
|
||||
}
|
||||
if (!(Number(line.qty) > 0)) {
|
||||
ElMessage.warning(`第 ${i + 1} 行数量必须大于0`)
|
||||
return
|
||||
}
|
||||
}
|
||||
submitting.value = true
|
||||
try {
|
||||
const res = await fetchConfirmQcMonthImport({
|
||||
stockInDate: stockInDate.value,
|
||||
remark: remark.value?.trim() || undefined,
|
||||
items: lines.value.map((l) => ({
|
||||
...l,
|
||||
materialId: l.materialId || undefined,
|
||||
stockInNo: l.stockInNo.trim(),
|
||||
catalogNo: l.catalogNo.trim(),
|
||||
batchNo: l.batchNo.trim(),
|
||||
manufacturer: l.manufacturer.trim(),
|
||||
qty: Number(l.qty),
|
||||
unitPrice: Number(l.unitPrice),
|
||||
amount: Number(l.amount)
|
||||
}))
|
||||
})
|
||||
ElMessage.success(`月初导入成功,共 ${res?.count ?? lines.value.length} 项`)
|
||||
emit('update:modelValue', false)
|
||||
emit('success')
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,379 @@
|
||||
<!-- 质检物料库 · 维护月初入库模板 -->
|
||||
<!-- eslint-disable vue/no-v-model-argument -->
|
||||
<template>
|
||||
<div class="qc-month-template-dialogs">
|
||||
<el-dialog
|
||||
:model-value="modelValue"
|
||||
title="维护月初模板"
|
||||
width="1080px"
|
||||
class="dialog-form-layout material-batch-stock-dialog"
|
||||
align-center
|
||||
append-to-body
|
||||
modal-class="protocol-dialog-mask"
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
@open="handleOpen"
|
||||
>
|
||||
<div class="batch-stock-move-lines-head" style="margin-bottom: 12px">
|
||||
<div class="batch-stock-move-lines-head-left">
|
||||
<span class="batch-stock-move-lines-title">模板明细</span>
|
||||
<span class="batch-stock-move-lines-hint">共 {{ rows.length }} 项,保存后供「月初导入」使用</span>
|
||||
</div>
|
||||
<el-button class="btn-ghost" @click="openEdit()">
|
||||
<el-icon><Plus /></el-icon>
|
||||
新增一行
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="loading" :data="rows" class="list-table" stripe max-height="420">
|
||||
<el-table-column label="物料编码" prop="materialCode" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="物料名称" prop="materialName" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="货号" prop="catalogNo" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="批号" prop="batchNo" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="厂家" prop="manufacturer" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="数量" prop="inQty" min-width="80" align="right" />
|
||||
<el-table-column label="过期日期" prop="expireDate" min-width="110" />
|
||||
<el-table-column label="操作" fixed="right" min-width="160">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="openEdit(row)">
|
||||
<el-icon><Edit /></el-icon>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button link type="danger" @click="handleDelete(row)">
|
||||
<el-icon><Delete /></el-icon>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<el-empty description="暂无模板,请点击「新增一行」" :image-size="64" />
|
||||
</template>
|
||||
</el-table>
|
||||
|
||||
<template #footer>
|
||||
<el-button class="btn-ghost" @click="emit('update:modelValue', false)">
|
||||
<el-icon><Close /></el-icon>
|
||||
关闭
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="editVisible"
|
||||
:title="editForm.id ? '编辑模板行' : '新增模板行'"
|
||||
width="720px"
|
||||
class="dialog-form-layout"
|
||||
align-center
|
||||
append-to-body
|
||||
modal-class="protocol-dialog-mask"
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form
|
||||
ref="editFormRef"
|
||||
:model="editForm"
|
||||
:rules="editRules"
|
||||
label-position="top"
|
||||
scroll-to-error
|
||||
:scroll-into-view-options="{ behavior: 'smooth', block: 'center' }"
|
||||
>
|
||||
<div class="form-grid-2">
|
||||
<el-form-item label="关联物资" class="form-col-span-2">
|
||||
<el-select
|
||||
v-model="editForm.materialId"
|
||||
filterable
|
||||
clearable
|
||||
placeholder="可选;不选则可手填编码名称,导入时自动创建"
|
||||
style="width: 100%"
|
||||
:loading="materialOptionsLoading"
|
||||
@change="onMaterialChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="opt in materialOptions"
|
||||
:key="opt.id"
|
||||
:label="`${opt.materialName}(${opt.materialCode})`"
|
||||
:value="opt.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="物料编码" prop="materialCode">
|
||||
<el-input v-model="editForm.materialCode" placeholder="必填" />
|
||||
</el-form-item>
|
||||
<el-form-item label="物料名称" prop="materialName">
|
||||
<el-input v-model="editForm.materialName" placeholder="必填" />
|
||||
</el-form-item>
|
||||
<el-form-item label="规格型号">
|
||||
<el-input v-model="editForm.specModel" placeholder="可选" />
|
||||
</el-form-item>
|
||||
<el-form-item label="单位">
|
||||
<el-input v-model="editForm.unit" placeholder="可选" />
|
||||
</el-form-item>
|
||||
<el-form-item label="货号" prop="catalogNo">
|
||||
<el-input v-model="editForm.catalogNo" placeholder="必填" />
|
||||
</el-form-item>
|
||||
<el-form-item label="批号" prop="batchNo">
|
||||
<el-input v-model="editForm.batchNo" placeholder="必填" />
|
||||
</el-form-item>
|
||||
<el-form-item label="厂家" prop="manufacturer">
|
||||
<el-input v-model="editForm.manufacturer" placeholder="必填" />
|
||||
</el-form-item>
|
||||
<el-form-item label="过期日期" prop="expireDate">
|
||||
<el-date-picker
|
||||
v-model="editForm.expireDate"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="选择过期日期"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="单价(元)" prop="unitPrice">
|
||||
<el-input-number
|
||||
v-model="editForm.unitPrice"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
@change="onPriceOrQtyChange"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="数量" prop="inQty">
|
||||
<el-input-number
|
||||
v-model="editForm.inQty"
|
||||
:min="0.0001"
|
||||
:precision="4"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
@change="onPriceOrQtyChange"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="金额(元)" prop="amount">
|
||||
<el-input-number
|
||||
v-model="editForm.amount"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
@change="amountTouched = true"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" class="form-col-span-2">
|
||||
<el-input v-model="editForm.remark" type="textarea" :rows="2" placeholder="可选" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button class="btn-ghost" @click="editVisible = false">
|
||||
<el-icon><Close /></el-icon>
|
||||
取消
|
||||
</el-button>
|
||||
<el-button class="btn-main" type="primary" :loading="saving" @click="handleSave">
|
||||
<el-icon><Check /></el-icon>
|
||||
保存
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus'
|
||||
import { Check, Close, Delete, Edit, Plus } from '@element-plus/icons-vue'
|
||||
import { fetchQcMaterialOptions, type QcMaterialOption } from '@/api/qc-material'
|
||||
import {
|
||||
fetchCreateQcMonthTemplate,
|
||||
fetchDeleteQcMonthTemplate,
|
||||
fetchQcMonthTemplateList,
|
||||
fetchUpdateQcMonthTemplate,
|
||||
type QcMonthTemplateRow
|
||||
} from '@/api/qc-material-month-template'
|
||||
|
||||
defineOptions({ name: 'QcMaterialMonthTemplateDialog' })
|
||||
|
||||
defineProps<{ modelValue: boolean }>()
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', val: boolean): void
|
||||
(e: 'saved'): void
|
||||
}>()
|
||||
|
||||
const loading = ref(false)
|
||||
const saving = ref(false)
|
||||
const rows = ref<QcMonthTemplateRow[]>([])
|
||||
const materialOptions = ref<QcMaterialOption[]>([])
|
||||
const materialOptionsLoading = ref(false)
|
||||
|
||||
const editVisible = ref(false)
|
||||
const editFormRef = ref<FormInstance>()
|
||||
const amountTouched = ref(false)
|
||||
const editForm = reactive({
|
||||
id: '',
|
||||
materialId: '',
|
||||
materialCode: '',
|
||||
materialName: '',
|
||||
specModel: '',
|
||||
unit: '',
|
||||
catalogNo: '',
|
||||
batchNo: '',
|
||||
manufacturer: '',
|
||||
unitPrice: 0,
|
||||
amount: 0,
|
||||
inQty: 1,
|
||||
expireDate: '',
|
||||
remark: ''
|
||||
})
|
||||
|
||||
const editRules: FormRules = {
|
||||
materialCode: [{ required: true, message: '请输入物料编码', trigger: 'blur' }],
|
||||
materialName: [{ required: true, message: '请输入物料名称', trigger: 'blur' }],
|
||||
catalogNo: [{ required: true, message: '请输入货号', trigger: 'blur' }],
|
||||
batchNo: [{ required: true, message: '请输入批号', trigger: 'blur' }],
|
||||
manufacturer: [{ required: true, message: '请输入厂家', trigger: 'blur' }],
|
||||
expireDate: [{ required: true, message: '请选择过期日期', trigger: 'change' }],
|
||||
unitPrice: [{ required: true, message: '请输入单价', trigger: 'blur' }],
|
||||
amount: [{ required: true, message: '请输入金额', trigger: 'blur' }],
|
||||
inQty: [{ required: true, message: '请输入数量', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
async function loadRows() {
|
||||
loading.value = true
|
||||
try {
|
||||
rows.value = (await fetchQcMonthTemplateList()) || []
|
||||
} catch {
|
||||
rows.value = []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function loadMaterialOptions() {
|
||||
materialOptionsLoading.value = true
|
||||
try {
|
||||
materialOptions.value = (await fetchQcMaterialOptions()) || []
|
||||
} catch {
|
||||
materialOptions.value = []
|
||||
} finally {
|
||||
materialOptionsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleOpen() {
|
||||
await Promise.all([loadRows(), loadMaterialOptions()])
|
||||
}
|
||||
|
||||
function resetEditForm() {
|
||||
editForm.id = ''
|
||||
editForm.materialId = ''
|
||||
editForm.materialCode = ''
|
||||
editForm.materialName = ''
|
||||
editForm.specModel = ''
|
||||
editForm.unit = ''
|
||||
editForm.catalogNo = ''
|
||||
editForm.batchNo = ''
|
||||
editForm.manufacturer = ''
|
||||
editForm.unitPrice = 0
|
||||
editForm.amount = 0
|
||||
editForm.inQty = 1
|
||||
editForm.expireDate = ''
|
||||
editForm.remark = ''
|
||||
amountTouched.value = false
|
||||
}
|
||||
|
||||
function openEdit(row?: QcMonthTemplateRow) {
|
||||
resetEditForm()
|
||||
if (row) {
|
||||
editForm.id = row.id
|
||||
editForm.materialId = row.materialId || ''
|
||||
editForm.materialCode = row.materialCode || ''
|
||||
editForm.materialName = row.materialName || ''
|
||||
editForm.specModel = row.specModel || ''
|
||||
editForm.unit = row.unit || ''
|
||||
editForm.catalogNo = row.catalogNo || ''
|
||||
editForm.batchNo = row.batchNo || ''
|
||||
editForm.manufacturer = row.manufacturer || ''
|
||||
editForm.unitPrice = Number(row.unitPrice) || 0
|
||||
editForm.amount = Number(row.amount) || 0
|
||||
editForm.inQty = Number(row.inQty) || 1
|
||||
editForm.expireDate = row.expireDate || ''
|
||||
editForm.remark = row.remark || ''
|
||||
amountTouched.value = true
|
||||
}
|
||||
editVisible.value = true
|
||||
}
|
||||
|
||||
function onMaterialChange(id: string) {
|
||||
const opt = materialOptions.value.find((o) => o.id === id)
|
||||
if (!opt) return
|
||||
editForm.materialId = opt.id
|
||||
editForm.materialCode = opt.materialCode || ''
|
||||
editForm.materialName = opt.materialName || ''
|
||||
editForm.specModel = opt.specModel || ''
|
||||
editForm.unit = opt.unit || ''
|
||||
}
|
||||
|
||||
function onPriceOrQtyChange() {
|
||||
if (amountTouched.value) return
|
||||
const price = Number(editForm.unitPrice) || 0
|
||||
const qty = Number(editForm.inQty) || 0
|
||||
editForm.amount = Number((price * qty).toFixed(2))
|
||||
}
|
||||
|
||||
async function handleSave() {
|
||||
const form = editFormRef.value
|
||||
if (!form) return
|
||||
try {
|
||||
await form.validate()
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
if (!(Number(editForm.inQty) > 0)) {
|
||||
ElMessage.warning('数量必须大于0')
|
||||
return
|
||||
}
|
||||
saving.value = true
|
||||
try {
|
||||
const payload = {
|
||||
materialId: editForm.materialId || undefined,
|
||||
materialCode: editForm.materialCode.trim(),
|
||||
materialName: editForm.materialName.trim(),
|
||||
specModel: editForm.specModel?.trim() || undefined,
|
||||
unit: editForm.unit?.trim() || undefined,
|
||||
catalogNo: editForm.catalogNo.trim(),
|
||||
batchNo: editForm.batchNo.trim(),
|
||||
manufacturer: editForm.manufacturer.trim(),
|
||||
unitPrice: Number(editForm.unitPrice),
|
||||
amount: Number(editForm.amount),
|
||||
inQty: Number(editForm.inQty),
|
||||
expireDate: editForm.expireDate,
|
||||
remark: editForm.remark?.trim() || undefined
|
||||
}
|
||||
if (editForm.id) {
|
||||
await fetchUpdateQcMonthTemplate(editForm.id, payload)
|
||||
ElMessage.success('更新成功')
|
||||
} else {
|
||||
await fetchCreateQcMonthTemplate(payload)
|
||||
ElMessage.success('新增成功')
|
||||
}
|
||||
editVisible.value = false
|
||||
await loadRows()
|
||||
emit('saved')
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDelete(row: QcMonthTemplateRow) {
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定删除模板「${row.materialName}」吗?`, '删除确认', {
|
||||
type: 'warning',
|
||||
confirmButtonText: '删除',
|
||||
cancelButtonText: '取消'
|
||||
})
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
await fetchDeleteQcMonthTemplate(row.id)
|
||||
ElMessage.success('删除成功')
|
||||
await loadRows()
|
||||
emit('saved')
|
||||
}
|
||||
</script>
|
||||
@@ -88,6 +88,14 @@
|
||||
<el-icon><CircleClose /></el-icon>
|
||||
批量废弃
|
||||
</el-button>
|
||||
<el-button class="btn-ghost" @click="handleMonthImport">
|
||||
<el-icon><Calendar /></el-icon>
|
||||
月初导入
|
||||
</el-button>
|
||||
<el-button class="btn-ghost" @click="monthTemplateVisible = true">
|
||||
<el-icon><Setting /></el-icon>
|
||||
维护月初模板
|
||||
</el-button>
|
||||
<ArtExcelExport
|
||||
type="default"
|
||||
:data="batchExportData"
|
||||
@@ -1213,6 +1221,11 @@
|
||||
:batch="attachmentBatch"
|
||||
@saved="loadData"
|
||||
/>
|
||||
<QcMaterialMonthTemplateDialog v-model="monthTemplateVisible" />
|
||||
<QcMaterialMonthImportDialog
|
||||
v-model="monthImportVisible"
|
||||
@success="handleMonthImportSuccess"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-show="activeTab === 'usage'" class="panel-track-pane">
|
||||
@@ -1242,7 +1255,9 @@
|
||||
Edit,
|
||||
Delete,
|
||||
CircleClose,
|
||||
Paperclip
|
||||
Paperclip,
|
||||
Calendar,
|
||||
Setting
|
||||
} from '@element-plus/icons-vue'
|
||||
import SystemViewDialog from '@/components/business/system-view-dialog/index.vue'
|
||||
import AmountInput from '@/components/common/amount-input/index.vue'
|
||||
@@ -1269,6 +1284,9 @@
|
||||
import QcMaterialUsageTab from './QcMaterialUsageTab.vue'
|
||||
import QcMaterialStockCheckTab from './QcMaterialStockCheckTab.vue'
|
||||
import QcMaterialBatchAttachmentDialog from './QcMaterialBatchAttachmentDialog.vue'
|
||||
import QcMaterialMonthTemplateDialog from './QcMaterialMonthTemplateDialog.vue'
|
||||
import QcMaterialMonthImportDialog from './QcMaterialMonthImportDialog.vue'
|
||||
import { fetchQcMonthTemplateList } from '@/api/qc-material-month-template'
|
||||
import { useMenuPerm } from '@/hooks/core/useMenuPerm'
|
||||
|
||||
defineOptions({ name: 'QualityInspectionQcMaterial' })
|
||||
@@ -1279,6 +1297,9 @@
|
||||
/** 暂时隐藏批量入库入口,恢复时改为 true */
|
||||
const batchStockInButtonVisible = false
|
||||
|
||||
const monthTemplateVisible = ref(false)
|
||||
const monthImportVisible = ref(false)
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const QC_MATERIAL_TABS = [
|
||||
@@ -2317,6 +2338,25 @@
|
||||
batchStockInFormRef.value?.clearValidate?.()
|
||||
}
|
||||
|
||||
async function handleMonthImport() {
|
||||
try {
|
||||
const list = (await fetchQcMonthTemplateList()) || []
|
||||
if (!list.length) {
|
||||
ElMessage.warning('请先维护月初模板')
|
||||
monthTemplateVisible.value = true
|
||||
return
|
||||
}
|
||||
monthImportVisible.value = true
|
||||
} catch {
|
||||
/* request 层已提示 */
|
||||
}
|
||||
}
|
||||
|
||||
async function handleMonthImportSuccess() {
|
||||
monthImportVisible.value = false
|
||||
await loadData()
|
||||
}
|
||||
|
||||
async function handleBatchStockInSubmit() {
|
||||
await batchStockInFormRef.value?.validate?.()
|
||||
if (!batchStockInLines.value.length) {
|
||||
|
||||
Reference in new issue
Block a user