|
|
@@ -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>
|