更新生产计划、销售订单、工作订单和仓库发料功能

This commit is contained in:
panchengyong
2026-03-13 11:11:37 +08:00
parent 34cbf08144
commit 099e01e518
30 changed files with 681 additions and 185 deletions

View File

@@ -140,3 +140,20 @@ export function revokeIssue(mbomId: number): Promise<void> {
export function calcBom(planId: number): Promise<void> {
return request.put(`/erp/mp/plan/bom-calculate/${planId}`)
}
// 齐套检查:查询物料清单的子件库存情况
export interface StockCheckItem {
itemCode: string
itemName: string
unitName?: string
requiredQty: number
availableQty: number
shortage: number
isShortage: boolean
}
export function checkMbomStock(mbomId: number): Promise<StockCheckItem[]> {
return request.get(`/erp/mp/mbom/stock-check/${mbomId}`).then((res: any) => {
return res.data ?? res.rows ?? res ?? []
})
}

View File

@@ -57,6 +57,12 @@ export interface ProductionPlan {
slaveList?: PlanLine[]
/** 部门名称(单据视图) */
deptName?: string
/** 客户ID从关联销售订单带入 */
clientId?: number
/** 客户编码(从关联销售订单带入) */
clientCode?: string
/** 客户名称(从关联销售订单带入) */
clientName?: string
/** 物料清单BOM运算结果详情页只读 */
mbomList?: MbomLine[]
/** 补料清单(详情页只读) */
@@ -187,6 +193,7 @@ export const PLAN_STATUS_MAP: Record<string, { label: string; type: string }> =
export const BUSINESS_STATUS_OPTIONS = [
{ value: 'NORMAL', label: '正常' },
{ value: 'BOM_CALCULATED', label: '已运算' },
{ value: 'PAUSE', label: '暂停' },
{ value: 'CANCEL', label: '取消' }
]
@@ -295,7 +302,7 @@ export function getImportOrderList(params?: {
return request.get('/erp/sl/order/list', {
params: {
...params,
orderStatus: '审核',
status: 'APPROVED',
pageNum: 1,
pageSize: 100
}
@@ -306,9 +313,9 @@ export function getImportOrderList(params?: {
orderId: row.orderId,
orderCode: row.orderCode,
orderDate: row.orderDate,
userId: row.salesmanId,
userName: row.salesmanName,
salesmanName: row.salesmanName,
userId: row.salesUserId ?? row.salesmanId,
userName: row.salesUserName ?? row.salesmanName,
salesmanName: row.salesUserName ?? row.salesmanName,
clientName: row.clientName,
deliveryDate: row.deliveryDate,
deliveryStatus: row.deliveryDate && new Date(row.deliveryDate) < new Date() ? '超期' : '预计',

View File

@@ -122,11 +122,12 @@ export interface SalesOrderDetailListResponse {
// ============ 状态映射 ============
export const ORDER_STATUS_MAP: Record<string, { label: string; type: string }> = {
'DRAFT': { label: '草稿', type: 'info' },
'开立': { label: '开立', type: '' },
'审核': { label: '审核', type: 'success' },
'退回': { label: '退回', type: 'warning' },
'关闭': { label: '关闭', type: 'danger' }
'DRAFT': { label: '草稿', type: 'info' },
'PREPARE': { label: '开立', type: '' },
'APPROVED': { label: '审核', type: 'success' },
'REJECTED': { label: '退回', type: 'warning' },
'FINISHED': { label: '已完成', type: 'info' },
'CANCELED': { label: '关闭', type: 'danger' },
}
export const SALES_TYPE_OPTIONS = [
@@ -162,9 +163,10 @@ const BASE = '/erp/sl/order'
function normalizeOrderRow(row: any): any {
return {
...row,
orderStatus: row.orderStatus ?? row.status ?? '',
salesmanId: row.salesmanId ?? row.salesUserId,
salesmanName: row.salesmanName ?? row.salesUserName ?? '',
salesType: row.salesType ?? row.saleType ?? '',
salesType: row.salesType ?? row.orderType ?? row.saleType ?? '',
}
}
@@ -197,11 +199,13 @@ export function getSalesOrderDetail(orderId: number): Promise<SalesOrder> {
// 后端返回 salesUserId/salesUserName前端表单使用 salesmanId/salesmanName便于下拉回显
if (data.salesUserId !== undefined) data.salesmanId = data.salesUserId
if (data.salesUserName !== undefined) data.salesmanName = data.salesUserName
// 审核信息字段别名映射(后端可能使用 checkBy/checkDate 等命名)
// 审核信息字段别名映射
// 使用 == null 而非 ! 判断,避免 auditorId=0 或 auditorName='' 被误判为缺失
if (data.auditorId == null) data.auditorId = data.checkUserId ?? data.checkById ?? data.auditById
if (data.auditorName == null) data.auditorName = data.checkUserName ?? data.checkByName ?? data.auditByName ?? data.auditUser
if (data.auditDate == null) data.auditDate = data.checkDate ?? data.auditTime ?? data.checkTime
if (data.auditorId == null) data.auditorId = data.approverId ?? data.checkUserId ?? data.checkById ?? data.auditById
if (data.auditorName == null) data.auditorName = data.approverName ?? data.checkUserName ?? data.checkByName ?? data.auditByName ?? data.auditUser
if (data.auditDate == null) data.auditDate = data.approveDate ?? data.checkDate ?? data.auditTime ?? data.checkTime
// 统一状态字段
if (data.orderStatus == null) data.orderStatus = data.status ?? ''
return data
})
}
@@ -216,6 +220,10 @@ function buildOrderPayload(data: Partial<SalesOrder>): Record<string, unknown> {
// 后端实体为 salesUserId / salesUserName前端表单为 salesmanId / salesmanName此处统一发给后端
if (payload.salesmanId !== undefined) payload.salesUserId = payload.salesmanId
if (payload.salesmanName !== undefined) payload.salesUserName = payload.salesmanName
// 后端实体用 orderType 存储销售类型,前端表单用 salesType
if (payload.salesType !== undefined) payload.orderType = payload.salesType
// 前端用 orderStatus后端实体字段为 status
if (payload.orderStatus !== undefined) payload.status = payload.orderStatus
return payload
}

View File

@@ -208,6 +208,7 @@
<el-table
:data="formData.lines"
class="order-lines-table"
stripe
border
style="width: 100%"
@@ -225,7 +226,6 @@
:min="0"
:precision="2"
:controls="false"
size="small"
style="width: 100%"
/>
<span v-else>{{ formatNumber(row.quantity) }}</span>
@@ -236,7 +236,6 @@
<el-input
v-if="!isView"
v-model="row.qualityReq"
size="small"
placeholder="质量要求"
/>
<span v-else>{{ row.qualityReq || '-' }}</span>
@@ -247,7 +246,6 @@
<el-input
v-if="!isView"
v-model="row.remark"
size="small"
placeholder="备注"
/>
<span v-else>{{ row.remark || '-' }}</span>
@@ -291,17 +289,14 @@
<span v-else>{{ row.mbomCode || '' }}</span>
</template>
</el-table-column>
<el-table-column prop="mbomStatus" label="单据状态" width="80" />
<el-table-column prop="businessType" label="业务类型" width="100" />
<el-table-column prop="issueStatus" label="状态" width="90">
<el-table-column prop="mbomStatus" label="单据状态" width="100">
<template #default="{ row }">
<el-switch
v-if="canEditMbom"
:model-value="row.issueStatus === 'ISSUED'"
:loading="mbomSaveLoading[row.mbomId!]"
@change="(val: boolean) => handleMbomIssueToggle(row, val)"
/>
<span v-else>{{ row.issueStatus === 'ISSUED' ? '已下发' : (row.issueStatus || '') }}</span>
{{ getMbomStatusLabel(row.mbomStatus) }}
</template>
</el-table-column>
<el-table-column prop="businessType" label="业务类型" width="100">
<template #default="{ row }">
{{ getBusinessTypeLabel(row.businessType) }}
</template>
</el-table-column>
<el-table-column prop="itemCode" label="物料编码" width="140" show-overflow-tooltip />
@@ -334,9 +329,9 @@
{{ formatNumber(row.productionQty) }}
</template>
</el-table-column>
<el-table-column prop="workshopName" label="下发车间" width="160">
<el-table-column label="下发车间" width="230">
<template #default="{ row }">
<template v-if="canEditMbom">
<div v-if="canEditMbom" style="display: flex; flex-direction: column; gap: 4px;">
<el-select
v-model="row.workshopId"
placeholder="下发车间"
@@ -353,24 +348,29 @@
:value="w.workshopId!"
/>
</el-select>
</template>
<span v-else>{{ row.workshopName || '' }}</span>
</template>
</el-table-column>
<el-table-column prop="issueDate" label="下发时间" width="130">
<template #default="{ row }">
<el-date-picker
v-if="canEditMbom"
v-model="row.issueDate"
type="date"
placeholder="选择日期"
value-format="YYYY-MM-DD"
size="small"
style="width: 100%"
:disabled="row.issueStatus === 'ISSUED'"
@change="(val: string) => handleMbomIssueDateChange(row, val)"
/>
<span v-else>{{ row.issueDate || '' }}</span>
<div style="display: flex; gap: 4px; align-items: center;">
<el-date-picker
v-model="row.issueDate"
type="date"
placeholder="下发日期"
value-format="YYYY-MM-DD"
size="small"
style="flex: 1"
:disabled="row.issueStatus === 'ISSUED'"
@change="(val: string) => handleMbomIssueDateChange(row, val)"
/>
<el-switch
:model-value="row.issueStatus === 'ISSUED'"
:loading="mbomSaveLoading[row.mbomId!]"
size="small"
@change="(val: boolean) => handleMbomIssueToggle(row, val)"
/>
</div>
</div>
<div v-else>
<div>{{ row.workshopName || '—' }}</div>
<div style="font-size: 12px; color: #909399;">{{ row.issueDate || '—' }} / {{ row.issueStatus === 'ISSUED' ? '已下发' : '未下发' }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="操作" width="220" align="center" fixed="right">
@@ -400,7 +400,7 @@
>
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="supCode" label="单据编码" width="140" show-overflow-tooltip />
<el-table-column prop="supStatus" label="单据状态" width="80" />
<el-table-column prop="supStatus" label="单据状态" width="100" show-overflow-tooltip />
<el-table-column prop="businessType" label="业务类型" width="100" />
<el-table-column prop="issueStatus" label="状态" width="80" />
<el-table-column prop="itemCode" label="物料编码" width="140" show-overflow-tooltip />
@@ -645,6 +645,46 @@
<el-button @click="showEbomViewDialog = false">关闭</el-button>
</template>
</el-dialog>
<!-- 齐套检查弹窗 -->
<el-dialog
v-model="showStockCheckDialog"
title="齐套检查"
width="800px"
destroy-on-close
>
<div v-loading="stockCheckLoading">
<el-table :data="stockCheckData" border size="small" max-height="400">
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="itemCode" label="物料编码" width="140" show-overflow-tooltip />
<el-table-column prop="itemName" label="物料名称" min-width="180" show-overflow-tooltip />
<el-table-column prop="unitName" label="主计量" width="80" />
<el-table-column prop="requiredQty" label="需求量" width="100" align="right">
<template #default="{ row }">
{{ formatNumber(row.requiredQty) }}
</template>
</el-table-column>
<el-table-column prop="availableQty" label="可用量" width="100" align="right">
<template #default="{ row }">
{{ formatNumber(row.availableQty) }}
</template>
</el-table-column>
<el-table-column prop="shortage" label="缺料量" width="100" align="right">
<template #default="{ row }">
<span :style="{ color: row.isShortage ? '#f56c6c' : '#67c23a' }">
{{ formatNumber(row.shortage) }}
</span>
</template>
</el-table-column>
</el-table>
<div v-if="stockCheckData.length === 0 && !stockCheckLoading" style="text-align: center; padding: 40px; color: #909399;">
暂无数据
</div>
</div>
<template #footer>
<el-button @click="showStockCheckDialog = false">关闭</el-button>
</template>
</el-dialog>
</div>
</template>
@@ -669,7 +709,7 @@ import {
type MbomLine,
type ImportOrder
} from '@/api/productionPlan'
import { calcBom, updateMbom, issueToWorkshop, revokeIssue, getMbomLines, type MbomLine as ApiMbomLine } from '@/api/mbom'
import { calcBom, updateMbom, issueToWorkshop, revokeIssue, getMbomLines, checkMbomStock, type MbomLine as ApiMbomLine, type StockCheckItem } from '@/api/mbom'
import { listEbom, getEbom, type EbomHeader, type EbomLine } from '@/api/rd/ebom'
import { listWorkshop, type Workshop } from '@/api/masterdata/workshop'
@@ -767,6 +807,11 @@ const ebomViewData = ref<EbomHeader | null>(null)
const ebomViewLines = ref<EbomLine[]>([])
const ebomViewLoading = ref(false)
/** 齐套检查弹窗 */
const showStockCheckDialog = ref(false)
const stockCheckData = ref<StockCheckItem[]>([])
const stockCheckLoading = ref(false)
/** 供应方式选项(生产/加工/装配/采购/委外) */
const SUPPLY_TYPE_OPTIONS = [
{ value: 'SELF_MADE', label: '生产' },
@@ -877,8 +922,24 @@ async function handleBomCalculate() {
}
/** 物料清单 - 齐套检查(占位,后续对接接口) */
function handleMbomStockCheck(_row: any) {
ElMessage.info('齐套检查功能待对接后端接口')
async function handleMbomStockCheck(row: any) {
if (!row.mbomId) {
ElMessage.warning('物料清单ID不存在')
return
}
stockCheckLoading.value = true
showStockCheckDialog.value = true
stockCheckData.value = []
try {
const data = await checkMbomStock(row.mbomId)
stockCheckData.value = data
} catch (error: any) {
ElMessage.error('齐套检查失败:' + (error.message || '未知错误'))
} finally {
stockCheckLoading.value = false
}
}
/** 物料清单 - BOM补料占位后续对接接口 */
@@ -900,6 +961,29 @@ function getSupplyTypeLabel(supplyType?: string): string {
return labelMap[supplyType] ?? supplyType
}
/** MBOM 单据状态映射 */
function getMbomStatusLabel(status?: string): string {
if (!status) return '—'
const labelMap: Record<string, string> = {
'PREPARE': '开立',
'DRAFT': '开立',
'APPROVED': '审核',
'CLOSED': '关闭'
}
return labelMap[status] ?? status
}
/** MBOM 业务类型映射 */
function getBusinessTypeLabel(businessType?: string): string {
if (!businessType) return '—'
const labelMap: Record<string, string> = {
'BOM_CALC': 'BOM运算',
'BOM_SUPPLEMENT': 'BOM补料',
'PRODUCTION_SUPPLEMENT': '生产补料'
}
return labelMap[businessType] ?? businessType
}
/** 打开物料清单汇总弹窗PRD 6.3.10:标题「计划单号-产品编码-产品名称-数量」- 物料清单表格为MBOM明细 */
function openMbomSummaryDialog() {
const planCode = formData.planCode || '计划单'
@@ -1554,4 +1638,13 @@ onMounted(async () => {
color: #909399;
font-size: 12px;
}
.order-lines-table :deep(.el-table__body .el-table__cell) {
padding: 8px 0;
}
.order-lines-table :deep(.el-input__wrapper),
.order-lines-table :deep(.el-input-number .el-input__wrapper) {
min-height: 36px;
}
</style>

View File

@@ -214,6 +214,13 @@
</template>
</el-table-column>
<el-table-column prop="planDate" label="单据日期" width="110" />
<el-table-column label="操作" width="120" fixed="right" align="center">
<template #default="{ row }">
<el-button link type="primary" @click="handleView(row)">
查看
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 单据视图表格无序号复选框单据编码单据日期单据状态业务类型业务部门业务人员业务状态审核日期操作 -->
@@ -241,9 +248,9 @@
</el-tag>
</template>
</el-table-column>
<el-table-column prop="businessType" label="业务类型" width="100" show-overflow-tooltip />
<el-table-column prop="deptName" label="业务部门" width="100" show-overflow-tooltip />
<el-table-column prop="operatorName" label="业务人员" width="100" show-overflow-tooltip>
<el-table-column prop="businessType" label="业务类型" min-width="100" show-overflow-tooltip />
<el-table-column prop="deptName" label="业务部门" min-width="100" show-overflow-tooltip />
<el-table-column prop="operatorName" label="业务人员" min-width="100" show-overflow-tooltip>
<template #default="{ row }">
{{ row.operatorName || row.salesUserName || '-' }}
</template>
@@ -253,8 +260,12 @@
{{ getBusinessStatusLabel(row.businessStatus) }}
</template>
</el-table-column>
<el-table-column prop="approveDate" label="审核日期" width="120" />
<el-table-column label="操作" width="160" fixed="right">
<el-table-column prop="approveDate" label="审核日期" width="120">
<template #default="{ row }">
{{ row.approveDate ? row.approveDate.slice(0, 10) : '' }}
</template>
</el-table-column>
<el-table-column label="操作" width="160" fixed="right" align="center">
<template #default="{ row }">
<el-button type="success" link @click="handleView(row)">查看</el-button>
<el-button
@@ -387,11 +398,11 @@ const queryParams = reactive<PlanQuery>({
const quickFilter = ref('')
const quickFilterTags = [
{ label: '全部', value: '' },
{ label: '胶带', value: '胶带' },
{ label: '机柜', value: '机柜' },
{ label: '电脑', value: '电脑' },
{ label: '纸杯机', value: '纸杯机' },
{ label: '配套机', value: '配套机' }
{ label: '模具', value: '模具' },
{ label: '注塑件', value: '注塑件' },
{ label: '塑料件', value: '塑料件' },
{ label: '橡胶件', value: '橡胶件' },
{ label: '五金件', value: '五金件' }
]
/** 单据视图数据 */

View File

@@ -81,42 +81,17 @@
:disabled="isView"
label-width="90px"
>
<!-- 表头表单区5列布局 -->
<!-- 表头表单区4列布局 -->
<el-collapse v-model="activeCollapse">
<el-collapse-item title="生产订单" name="basic">
<el-row :gutter="12">
<!-- 第1列 -->
<el-col :span="5">
<!-- Row 1 -->
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="单据编码">
<el-input v-model="formData.workorderCode" disabled placeholder="系统自动生成" />
</el-form-item>
<el-form-item label="单据日期">
<el-date-picker
v-model="formData.orderDate"
type="date"
placeholder="选择日期"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="单据状态">
<el-tag :type="getStatusType(formData.status)">
{{ getStatusLabel(formData.status) }}
</el-tag>
</el-form-item>
<el-form-item label="业务状态">
<el-select v-model="formData.businessStatus" placeholder="请选择" style="width: 100%">
<el-option
v-for="opt in BUSINESS_STATUS_OPTIONS"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</el-select>
</el-form-item>
</el-col>
<!-- 第2列 -->
<el-col :span="5">
<el-col :span="6">
<el-form-item label="业务类型">
<el-select v-model="formData.businessType" placeholder="请选择" style="width: 100%">
<el-option
@@ -127,18 +102,8 @@
/>
</el-select>
</el-form-item>
<el-form-item label="操作员">
<el-input v-model="formData.operatorName" disabled placeholder="当前用户" />
</el-form-item>
<el-form-item label="审核员">
<el-input v-model="formData.approverName" disabled placeholder="-" />
</el-form-item>
<el-form-item label="审核日期">
<el-input v-model="formData.approveDate" disabled placeholder="-" />
</el-form-item>
</el-col>
<!-- 第3列 -->
<el-col :span="5">
<el-col :span="6">
<el-form-item label="计划单号" prop="sourceCode">
<el-input
:model-value="formData.sourceCode || ''"
@@ -151,15 +116,19 @@
</template>
</el-input>
</el-form-item>
<el-form-item label="跟单编号">
<el-input v-model="formData.salesOrderCode" disabled placeholder="-" />
</el-col>
<el-col :span="6">
<el-form-item label="物料编码">
<el-input v-model="formData.productCode" disabled placeholder="选择计划单后带入" />
</el-form-item>
<el-form-item label="订单交期">
<el-input v-model="formData.deliveryDate" disabled placeholder="-" />
</el-form-item>
<el-form-item label="需求日期">
</el-col>
</el-row>
<!-- Row 2 -->
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="单据日期">
<el-date-picker
v-model="formData.requestDate"
v-model="formData.orderDate"
type="date"
placeholder="选择日期"
value-format="YYYY-MM-DD"
@@ -167,14 +136,42 @@
/>
</el-form-item>
</el-col>
<!-- 第4列 -->
<el-col :span="5">
<el-form-item label="物料编码">
<el-input v-model="formData.productCode" disabled placeholder="选择计划单后带入" />
<el-col :span="6">
<el-form-item label="操作员">
<el-input v-model="formData.operatorName" disabled placeholder="当前用户" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="跟单编号">
<el-input v-model="formData.salesOrderCode" disabled placeholder="-" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="物料名称">
<el-input v-model="formData.productName" disabled placeholder="选择计划单后带入" />
</el-form-item>
</el-col>
</el-row>
<!-- Row 3 -->
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="单据状态">
<el-tag :type="getStatusType(formData.status)">
{{ getStatusLabel(formData.status) }}
</el-tag>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="审核员">
<el-input v-model="formData.approverName" disabled placeholder="-" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="订单交期">
<el-input v-model="formData.deliveryDate" disabled placeholder="-" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="生产总数" prop="quantity">
<div style="display: flex; align-items: center; gap: 4px; width: 100%">
<el-input-number
@@ -187,15 +184,39 @@
<span style="white-space: nowrap; color: #909399;">{{ formData.unitOfMeasure || '台' }}</span>
</div>
</el-form-item>
<el-form-item label="备注信息">
<el-input v-model="formData.remark" placeholder="备注" />
</el-col>
</el-row>
<!-- Row 4 -->
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="业务状态">
<el-select v-model="formData.businessStatus" placeholder="请选择" style="width: 100%">
<el-option
v-for="opt in BUSINESS_STATUS_OPTIONS"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</el-select>
</el-form-item>
</el-col>
<!-- 第5列 -->
<el-col :span="4">
<el-form-item label="图纸号">
<el-input v-model="formData.drawingNo" placeholder="图纸号" />
<el-col :span="6">
<el-form-item label="审核日期">
<el-input v-model="formData.approveDate" disabled placeholder="-" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="需求日期">
<el-date-picker
v-model="formData.requestDate"
type="date"
placeholder="选择日期"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="工艺路线">
<el-input
:model-value="formData.routeName || ''"
@@ -208,9 +229,21 @@
</template>
</el-input>
</el-form-item>
</el-col>
</el-row>
<!-- Row 5 -->
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="图纸号">
<el-input v-model="formData.drawingNo" placeholder="图纸号" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="生产线">
<el-input v-model="formData.productionLine" placeholder="生产线" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="生产日期" prop="productionDate">
<el-date-picker
v-model="formData.productionDate"
@@ -220,6 +253,8 @@
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="加工时长">
<div style="display: flex; align-items: center; gap: 4px; width: 100%">
<el-input-number
@@ -233,6 +268,14 @@
</el-form-item>
</el-col>
</el-row>
<!-- Row 6 -->
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="备注信息">
<el-input v-model="formData.remark" placeholder="备注" />
</el-form-item>
</el-col>
</el-row>
</el-collapse-item>
</el-collapse>
</el-form>
@@ -588,6 +631,9 @@ function confirmPlanSelect() {
formData.orderSource = 'PLAN'
formData.salesOrderCode = plan.salesOrderCode || ''
formData.deliveryDate = plan.deliveryDate || ''
if (plan.clientId) formData.clientId = plan.clientId
if (plan.clientCode) formData.clientCode = plan.clientCode
if (plan.clientName) formData.clientName = plan.clientName
const firstLine = plan.lines?.[0]
if (firstLine) {
formData.productId = firstLine.itemId
@@ -858,4 +904,8 @@ onMounted(() => {
.dialog-search { margin-bottom: 16px; display: flex; align-items: center; }
.empty-hint { padding: 24px 0; text-align: center; color: #909399; font-size: 13px; }
.material-section :deep(.el-table__header th .cell) {
white-space: nowrap;
}
</style>

View File

@@ -146,7 +146,7 @@
</template>
</el-table-column>
<el-table-column prop="workorderName" label="工单名称" min-width="200" show-overflow-tooltip />
<el-table-column prop="workorderType" label="工单类型" width="80" align="center">
<el-table-column prop="workorderType" label="工单类型" width="80" align="center" show-overflow-tooltip>
<template #default="{ row }">
{{ getWorkorderTypeLabel(row.workorderType) }}
</template>
@@ -156,18 +156,18 @@
<el-table-column prop="productCode" label="产品编号" width="140" show-overflow-tooltip />
<el-table-column prop="productName" label="产品名称" min-width="200" show-overflow-tooltip />
<el-table-column prop="productSpc" label="规格型号" width="150" show-overflow-tooltip />
<el-table-column prop="unitOfMeasure" label="单位" width="60" align="center" />
<el-table-column prop="quantity" label="生产数量" width="100" align="right">
<el-table-column prop="unitOfMeasure" label="单位" width="60" align="center" show-overflow-tooltip />
<el-table-column prop="quantity" label="生产数量" width="100" align="right" show-overflow-tooltip>
<template #default="{ row }">
{{ formatQuantity(row.quantity) }}
</template>
</el-table-column>
<el-table-column prop="quantityProduced" label="已生产" width="100" align="right">
<el-table-column prop="quantityProduced" label="已生产" width="100" align="right" show-overflow-tooltip>
<template #default="{ row }">
{{ formatQuantity(row.quantityProduced) }}
</template>
</el-table-column>
<el-table-column prop="quantityScheduled" label="已排产" width="100" align="right">
<el-table-column prop="quantityScheduled" label="已排产" width="100" align="right" show-overflow-tooltip>
<template #default="{ row }">
{{ formatQuantity(row.quantityScheduled) }}
</template>
@@ -178,7 +178,7 @@
{{ row.productionDate ? String(row.productionDate).slice(0, 10) : '-' }}
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="80" align="center">
<el-table-column prop="status" label="状态" width="80" align="center" show-overflow-tooltip>
<template #default="{ row }">
<el-tag :type="getStatusType(row.status)">
{{ getStatusLabel(row.status) }}
@@ -543,4 +543,8 @@ onMounted(() => {
font-weight: bold;
margin: 0 4px;
}
.table-card :deep(.el-table__header th .cell) {
white-space: nowrap;
}
</style>

View File

@@ -11,7 +11,7 @@
<el-button type="primary" @click="handleSave" :loading="saveLoading">
<el-icon><Check /></el-icon>保存
</el-button>
<el-button v-if="isEdit && formData.orderStatus === '开立'" @click="handleWithdraw">
<el-button v-if="isEdit && formData.orderStatus === 'PREPARE'" @click="handleWithdraw">
撤回
</el-button>
</template>
@@ -601,7 +601,7 @@ const formData = reactive<SalesOrder>({
orderId: undefined,
orderCode: '',
orderDate: new Date().toISOString().split('T')[0],
orderStatus: '开立',
orderStatus: 'PREPARE',
bizType: 'sales_order',
bizStatus: 'normal',
salesType: 'factory',
@@ -688,13 +688,13 @@ const totalAmount = computed(() => {
/** 是否可审核 */
const canAudit = computed(() => {
return (isEdit.value || isView.value) &&
formData.orderStatus === '开立' &&
formData.orderStatus === 'PREPARE' &&
(formData.lines?.length || 0) > 0
})
/** 是否可反审核 */
const canUnaudit = computed(() => {
return (isEdit.value || isView.value) && formData.orderStatus === '审核'
return (isEdit.value || isView.value) && formData.orderStatus === 'APPROVED'
})
// ============ 方法 ============
@@ -1093,7 +1093,7 @@ async function handleWithdraw() {
}
try {
await ElMessageBox.confirm('确认撤回此订单吗?', '提示', { type: 'warning' })
formData.orderStatus = '草稿'
formData.orderStatus = 'PREPARE'
await updateSalesOrder(formData)
ElMessage.success('撤回成功')
loadOrderData()

View File

@@ -235,7 +235,7 @@
type="primary"
link
@click="handleEdit(row)"
:disabled="row.orderStatus === '审核'"
:disabled="row.orderStatus === 'APPROVED'"
>
编辑
</el-button>
@@ -244,7 +244,7 @@
<el-button
type="danger"
link
:disabled="row.orderStatus === '审核'"
:disabled="row.orderStatus === 'APPROVED'"
>
删除
</el-button>
@@ -341,13 +341,13 @@ const salesTypeOptions = SALES_TYPE_OPTIONS
/** 是否可以审核(选中了开立状态的订单) */
const canAudit = computed(() => {
return selectedRows.value.length > 0 &&
selectedRows.value.every(row => row.orderStatus === '开立')
selectedRows.value.every(row => row.orderStatus === 'PREPARE')
})
/** 是否可以反审核(选中了审核状态的订单) */
const canUnaudit = computed(() => {
return selectedRows.value.length > 0 &&
selectedRows.value.every(row => row.orderStatus === '审核')
selectedRows.value.every(row => row.orderStatus === 'APPROVED')
})
// ============ 方法 ============

View File

@@ -433,7 +433,9 @@
<el-table-column prop="quantity" label="生产数量" width="100" align="right" />
<el-table-column prop="status" label="状态" width="80" align="center">
<template #default="{ row }">
{{ row.status || '-' }}
<el-tag :type="WORKORDER_STATUS_MAP[row.status]?.type || 'info'" size="small">
{{ WORKORDER_STATUS_MAP[row.status]?.label || row.status || '-' }}
</el-tag>
</template>
</el-table-column>
</el-table>
@@ -586,6 +588,7 @@ import {
STATUS_MAP,
type IssueHeader
} from '@/api/warehouse/issue'
import { STATUS_MAP as WORKORDER_STATUS_MAP, getWorkOrderBomList } from '@/api/workOrder'
import PrintDialog from '@/components/print/PrintDialog.vue'
import type { PrintConfig } from '@/components/print/types'
import {
@@ -656,7 +659,7 @@ const formRules = {
trigger: 'blur'
}
],
issueName: [{ required: true, message: '领料单名称不能为空', trigger: 'blur' }]
issueName: [{ required: false }]
}
// ============ 领料行状态 ============
@@ -751,11 +754,28 @@ const selectedItem = ref<any>(null)
async function loadItems() {
itemLoading.value = true
try {
const res = await getItemSelectList({
itemCode: itemSearch.itemCode || undefined,
itemName: itemSearch.itemName || undefined
})
itemList.value = res.rows
if (formData.workorderId) {
const bomItems = await getWorkOrderBomList(formData.workorderId)
const keyword = (itemSearch.itemCode || itemSearch.itemName || '').toLowerCase()
const mapped = bomItems.map(b => ({
itemId: b.itemId,
itemCode: b.itemCode || '',
itemName: b.itemName || '',
specification: b.itemSpc || '',
unitOfMeasure: b.unitOfMeasure || '',
unitName: b.unitName || '',
itemTypeName: ''
}))
itemList.value = keyword
? mapped.filter(m => m.itemCode.toLowerCase().includes(keyword) || m.itemName.toLowerCase().includes(keyword))
: mapped
} else {
const res = await getItemSelectList({
itemCode: itemSearch.itemCode || undefined,
itemName: itemSearch.itemName || undefined
})
itemList.value = res.rows
}
} catch (error) {
console.error('加载物料失败:', error)
} finally {
@@ -1188,6 +1208,12 @@ async function handleSave() {
try {
await formRef.value?.validate()
if (!formData.issueName?.trim()) {
const now = new Date()
const pad = (n: number) => String(n).padStart(2, '0')
formData.issueName = `领料单-${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`
}
saveLoading.value = true
// 保存表头

View File

@@ -127,24 +127,24 @@
<el-table-column prop="taskCode" label="任务编码" width="140" show-overflow-tooltip />
<el-table-column prop="workstationName" label="工作站" width="120" show-overflow-tooltip />
<el-table-column prop="clientName" label="客户名称" width="150" show-overflow-tooltip />
<el-table-column prop="issueDate" label="领料日期" width="120" align="center">
<el-table-column prop="issueDate" label="领料日期" width="120" align="center" show-overflow-tooltip>
<template #default="{ row }">
{{ row.issueDate ? String(row.issueDate).slice(0, 10) : '-' }}
</template>
</el-table-column>
<el-table-column prop="requiredTime" label="需求时间" width="150" align="center">
<el-table-column prop="requiredTime" label="需求时间" width="150" align="center" show-overflow-tooltip>
<template #default="{ row }">
{{ row.requiredTime ? String(row.requiredTime).slice(0, 16) : '-' }}
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="80" align="center">
<el-table-column prop="status" label="状态" width="80" align="center" show-overflow-tooltip>
<template #default="{ row }">
<el-tag :type="getStatusType(row.status)">
{{ getStatusLabel(row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200" fixed="right" align="center">
<el-table-column label="操作" width="280" fixed="right" align="center">
<template #default="{ row }">
<!-- 所有状态查看 -->
<el-button type="success" link @click="handleView(row)">查看</el-button>
@@ -457,4 +457,8 @@ onMounted(() => {
font-weight: bold;
margin: 0 4px;
}
.table-card :deep(.el-table__header th .cell) {
white-space: nowrap;
}
</style>