Browse Source

发货流程

master
常熟吴彦祖 2 weeks ago
parent
commit
d9b19df812
  1. 5
      src/api/order/poOrder.js
  2. 2
      src/views/demo/echarts.vue
  3. 488
      src/views/modules/order/com_poOrderDetail.vue
  4. 264
      src/views/modules/order/poOrder.vue
  5. 9
      src/views/modules/order/poOrderStatusOptions.js
  6. 4
      src/views/modules/order/poOrder_search.vue

5
src/api/order/poOrder.js

@ -25,7 +25,10 @@ export const openPoDetail = (data) => createAPI(`/pODetail/openPoDetail`, 'post'
/** 下达 PO 订单行(草稿 → 已下达) */
export const issuePoDetail = (data) => createAPI(`/pODetail/issuePoDetail`, 'post', data)
/** 发货 PO 订单行(验货完成 → 已发货) */
/** 发货弹窗预览(返回订单数量、可发货数量、默认本次发货数量) */
export const shipPoDetailPreview = (data) => createAPI(`/pODetail/shipPoDetailPreview`, 'post', data)
/** 提交发货(回写 qty/c_ship_qty,并按规则判定部分发货或已发货) */
export const shipPoDetail = (data) => createAPI(`/pODetail/shipPoDetail`, 'post', data)
// 根据PO订单查询验货申请明细

2
src/views/demo/echarts.vue

@ -9,7 +9,7 @@
</div>
</el-alert>
<el-row :gutter="20">
< :gutter="20">
<el-col :span="24">
<el-card>
<div id="J_chartLineBox" class="chart-box"></div>

488
src/views/modules/order/com_poOrderDetail.vue

@ -1,254 +1,20 @@
<template>
<div class="po-order-detail">
<!-- 查看模式 -->
<!--
订单详情动态渲染区按字段权限 schema 控制
规则
1) 普通字段固定 1 24 栅格中的 4=> 一行 6
2) Vendor Name 固定 2 8
3) Comments 固定全行24
-->
<el-form label-position="top" class="detail-form">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="Customer">
<el-input v-model="detailData.customer" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Buyer">
<el-input v-model="detailData.buyer" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Vendor Name">
<el-input v-model="detailData.supplierName" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="V_Short_Office">
<el-input v-model="detailData.shortOffice" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="4">
<el-form-item label="V_Short_NPC">
<el-input v-model="detailData.shortNpc" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="PO_No">
<el-input v-model="detailData.poNo" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Part No">
<el-input v-model="detailData.partNo" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Item">
<el-input v-model="detailData.item" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Category">
<el-input v-model="detailData.category" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="SKU">
<el-input v-model="detailData.sku" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Unit Price">
<el-input v-model="detailData.price" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="4">
<el-form-item label="PO Value">
<el-input v-model="detailData.value" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="A-Value">
<el-input v-model="detailData.sumPrice" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Departure Port">
<el-input v-model="detailData.departure" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Destination Port">
<el-input v-model="detailData.destination" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Method">
<el-input v-model="detailData.shipVia" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Buyer Release Date">
<el-input v-model="detailData.orderDate" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="4">
<el-form-item label="Planner Release Date">
<el-input v-model="detailData.enquiry" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Status">
<el-input v-model="detailData.status" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="PI Confirmed Date">
<el-input v-model="detailData.confirmed" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Original Arrival Date">
<el-input v-model="detailData.wantReceiveDate" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Final Confirmed Arrival Date">
<el-input v-model="detailData.narrival" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="PI Confirmed CRD">
<el-input v-model="detailData.crd" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="4">
<el-form-item label="Original CRD">
<el-input v-model="detailData.crdOri" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="4">
<el-form-item label="Inspection Date">
<el-input v-model="detailData.inspection" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Actual Completion Date">
<el-input v-model="detailData.realCrd" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="ETA">
<el-input v-model="detailData.eta" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Flexport Id">
<el-input v-model="detailData.flexid" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="On Board Date">
<el-input v-model="detailData.obd" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Doc Sent">
<el-input v-model="detailData.docSent" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="4">
<el-form-item label="Telex Release">
<el-input v-model="detailData.telexRelease" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Advance Payment">
<el-input v-model="detailData.advancePayment" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Advanc Paid">
<el-input v-model="detailData.advancePaid" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Create Date">
<el-input v-model="detailData.createTime" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="M-Planner">
<el-input v-model="detailData.planner" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Edit Date">
<el-input v-model="detailData.edit" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="4">
<el-form-item label="Last Editor">
<el-input v-model="detailData.endPlanner" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Remark Delay">
<el-input v-model="detailData.remarkDelay" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Comments">
<el-input v-model="detailData.remark" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label=" ">
<span></span>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="4">
<el-form-item label="PO Qty">
<el-input v-model="detailData.qty" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="A-Qty">
<el-input v-model="detailData.shipQty" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="已申请验货数量">
<el-input v-model="detailData.inspectingQty" disabled />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="验货完成数量">
<el-input v-model="detailData.inspectionCompletedQty" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label=" ">
<span></span>
<el-col
v-for="field in displayFields"
:key="getFieldKey(field)"
:span="getFieldSpan(field)">
<el-form-item :label="getFieldLabel(field)">
<el-input :value="getFieldDisplayValue(field)" disabled />
</el-form-item>
</el-col>
</el-row>
@ -257,18 +23,238 @@
</template>
<script>
import { formatPoOrderTypeLabel } from './poOrderTypeOptions.js'
export default {
name: 'PoOrderDetail',
props: {
detailData: {
type: Object,
default: () => ({})
},
schemaFields: {
type: Array,
default: () => []
}
},
data() {
return {}
computed: {
/**
* 详情页签显示字段基于权限 schema 动态决定
* 处理逻辑
* 1) 仅保留 visibleFlag=Y 的字段
* 2) 同一 field_code 去重防止异常配置导致重复渲染
* 3) sortNo 升序保证与列表页/权限配置顺序一致
* 返回值用于页面渲染的字段数组已过滤去重排序
* 边界处理schemaFields 非数组时直接返回空数组避免页面渲染报错
*/
displayFields () {
if (!Array.isArray(this.schemaFields)) {
return []
}
const seen = new Set()
const visible = this.schemaFields.filter(field => {
if (!field) {
return false
}
const visibleFlag = String(field.visibleFlag || 'Y').toUpperCase()
if (visibleFlag !== 'Y') {
return false
}
const key = this.getFieldKey(field)
if (!key || seen.has(key)) {
return false
}
seen.add(key)
return true
})
return visible.sort((a, b) => {
const left = Number(a && a.sortNo)
const right = Number(b && b.sortNo)
const la = Number.isFinite(left) ? left : Number.MAX_SAFE_INTEGER
const rb = Number.isFinite(right) ? right : Number.MAX_SAFE_INTEGER
if (la !== rb) {
return la - rb
}
return this.getFieldKey(a).localeCompare(this.getFieldKey(b))
})
}
},
methods: {}
methods: {
/**
* 生成字段唯一键
* 优先级fieldCode > fieldProp > fieldLabel
* 入参field单个字段 schema 对象允许为空
* 返回值稳定字符串 key若字段信息缺失则返回空字符串
* 边界处理字段为空时走空字符串回退避免 v-for key 异常
*/
getFieldKey (field) {
const code = this.getFieldCode(field)
if (code) {
return code
}
const prop = this.getFieldProp(field)
if (prop) {
return prop
}
return String((field && field.fieldLabel) || '').trim()
},
/**
* 解析字段编码snake_case
* 入参兼容
* 1) 后端直接返回 fieldCode
* 2) fieldCode 时由 fieldProp 反推 snake_case
* 入参field字段 schema 对象
* 返回值字段编码字符串无法解析时返回空字符串
* 边界处理field 为空或关键属性缺失时不抛错统一回空串
*/
getFieldCode (field) {
if (!field) {
return ''
}
const code = String(field.fieldCode || '').trim()
if (code) {
return code.toLowerCase()
}
const prop = String(field.fieldProp || '').trim()
return prop ? this.camelToSnake(prop) : ''
},
/**
* 解析字段属性camelCase用于读取当前行对象值
* 入参兼容
* 1) 后端直接返回 fieldProp
* 2) fieldProp 时由 fieldCode 反推 camelCase
* 入参field字段 schema 对象
* 返回值字段属性名无法解析时返回空字符串
* 边界处理field 为空或编码异常时统一回空串避免取值报错
*/
getFieldProp (field) {
if (!field) {
return ''
}
const prop = String(field.fieldProp || '').trim()
if (prop) {
return prop
}
const code = String(field.fieldCode || '').trim()
return code ? this.snakeToCamel(code) : ''
},
/**
* 获取展示标签
* 优先 fieldLabel若异常缺失则回退字段属性名避免出现空标签
* 入参field字段 schema 对象
* 返回值展示标签字符串
* 边界处理label/prop/code 都缺失时返回空串不中断渲染流程
*/
getFieldLabel (field) {
const label = String((field && field.fieldLabel) || '').trim()
if (label) {
return label
}
return this.getFieldProp(field) || this.getFieldCode(field)
},
/**
* 按业务布局规则计算栅格宽度
* - Vendor Namesupplier_name: 2 => span=8
* - Commentsremark: 全行 => span=24
* - 其他字段: 1 => span=4
* 入参field字段 schema 对象
* 返回值Element 栅格 span 数值
* 边界处理未匹配特殊字段时统一走默认 1 保证布局稳定
*/
getFieldSpan (field) {
const code = this.getFieldCode(field)
const label = this.getFieldLabel(field).trim().toLowerCase()
if (code === 'supplier_name' || label === 'vendor name') {
return 8
}
if (code === 'remark' || code === 'comments' || label === 'comments') {
return 24
}
return 4
},
/**
* 读取详情字段原始值
* 读取顺序
* 1) detailData[fieldProp]
* 2) detailData[fieldCode]兼容少量 snake_case 回传
* 3) detailData.extValues[fieldCode/fieldProp]兼容扩展字段
* 入参field字段 schema 对象
* 返回值原始字段值取不到值时返回空字符串
* 边界处理detailData/extValues 为空或结构异常时安全降级为空串
*/
getFieldRawValue (field) {
const row = this.detailData || {}
const prop = this.getFieldProp(field)
const code = this.getFieldCode(field)
if (prop && row[prop] !== undefined && row[prop] !== null) {
return row[prop]
}
if (code && row[code] !== undefined && row[code] !== null) {
return row[code]
}
const extValues = row.extValues && typeof row.extValues === 'object' ? row.extValues : null
if (extValues) {
if (code && extValues[code] !== undefined && extValues[code] !== null) {
return extValues[code]
}
if (prop && extValues[prop] !== undefined && extValues[prop] !== null) {
return extValues[prop]
}
}
return ''
},
/**
* 获取最终显示值
* 特殊处理
* 1) order_type/orderType 走统一枚举格式化
* 2) 其余字段按原值输出空值统一返回空字符串
* 入参field字段 schema 对象
* 返回值可直接绑定到输入框的展示值
* 边界处理空值统一归一为空串避免界面出现 undefined/null
*/
getFieldDisplayValue (field) {
const raw = this.getFieldRawValue(field)
const code = this.getFieldCode(field)
const prop = this.getFieldProp(field)
if (raw === null || raw === undefined) {
return ''
}
if (code === 'order_type' || prop === 'orderType') {
return formatPoOrderTypeLabel(raw)
}
return raw
},
/**
* snake_case camelCase
* 入参snake下划线字段名
* 返回值camelCase 字段名入参为空时原样返回
*/
snakeToCamel (snake) {
if (!snake || !snake.includes('_')) {
return snake
}
return snake.replace(/_([a-z0-9])/g, (_, c) => c.toUpperCase())
},
/**
* camelCase snake_case
* 入参camel驼峰字段名
* 返回值snake_case 字段名入参为空时返回空字符串
*/
camelToSnake (camel) {
if (!camel) {
return ''
}
return camel.replace(/([A-Z])/g, '_$1').toLowerCase()
}
}
}
</script>
@ -284,6 +270,7 @@ export default {
.el-form-item {
margin-bottom: 6px;
}
/deep/ .el-form-item__label {
font-size: 14px;
color: #606266;
@ -312,5 +299,4 @@ export default {
border-color: #409eff;
outline: none;
}
</style>

264
src/views/modules/order/poOrder.vue

@ -67,24 +67,26 @@
label="操作"
header-align="center"
align="center"
width="90">
width="170">
<template slot-scope="scope">
<el-link
v-if="canIssuePoOrder(scope.row.status)"
type="primary"
@click.stop="handleIssuePoOrder(scope.row)">下达</el-link>
<el-link
v-else-if="canShipPoOrder(scope.row.status)"
type="primary"
@click.stop="handleShipPoOrder(scope.row)">shipped</el-link>
<el-link
v-else-if="canClosePoOrder(scope.row.status)"
type="primary"
@click.stop="handleClosePoOrder(scope.row)">关闭</el-link>
<el-link
v-else-if="canOpenPoOrder(scope.row.status)"
type="primary"
@click.stop="handleOpenPoOrder(scope.row)">打开</el-link>
<div class="po-row-action-wrap">
<el-link
v-if="canIssuePoOrder(scope.row.status)"
type="primary"
@click.stop="handleIssuePoOrder(scope.row)">下达</el-link>
<el-link
v-if="canShipPoOrder(scope.row.status)"
type="primary"
@click.stop="handleShipPoOrder(scope.row)">shipped</el-link>
<el-link
v-if="canClosePoOrder(scope.row.status)"
type="primary"
@click.stop="handleClosePoOrder(scope.row)">关闭</el-link>
<el-link
v-if="canOpenPoOrder(scope.row.status)"
type="primary"
@click.stop="handleOpenPoOrder(scope.row)">打开</el-link>
</div>
</template>
</el-table-column>
<el-table-column
@ -243,7 +245,7 @@
关联状态
uploadDialogVisible / uploadFile / uploadPreviewList / uploadColumnMapping / uploadSkippedColumns
-->
<el-dialog title="PO订单数据导入" :visible.sync="uploadDialogVisible" :height="height" width="800px">
<el-dialog title="PO订单数据导入" v-drag :visible.sync="uploadDialogVisible" :height="height" width="800px">
<!-- 选择文件 -->
<div style="margin-bottom:15px;display:flex;align-items:center">
<span style="margin-right:10px">请选择文件</span>
@ -296,6 +298,55 @@
</div>
</el-dialog>
<!--
模态框发货确认shipped
交互规则
1) 第一行订单数量可编辑回写 qty
2) 第二行可发货数量inspect_approve_qty - c_ship_qty仅读
3) 第三行本次发货数量默认=可发货数量可修改
-->
<el-dialog
title="发货确认"
v-drag
:visible.sync="shipDialogVisible"
width="360px"
append-to-body
:close-on-click-modal="false"
@closed="resetShipDialog">
<el-form label-position="top" class="ship-dialog-form">
<el-row :gutter="10">
<el-col :span="12" >
<el-form-item label="订单数量">
<el-input
v-model="shipDialogForm.orderQty"
disabled
class="ship-dialog-input" />
</el-form-item>
</el-col>
<el-col :span="12" >
<el-form-item label="未发货数量">
<el-input
:value="formatShipDialogDisplay(shipDialogForm.canShipQty)"
disabled
class="ship-dialog-input" />
</el-form-item>
</el-col>
<el-col :span="12" >
<el-form-item label="本次发货数量">
<el-input
v-model="shipDialogForm.shipQty"
type="number"
class="ship-dialog-input" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer ship-dialog-footer">
<el-button type="primary" :loading="shipDialogSaving" @click="submitShipDialog">保存</el-button>
<el-button @click="shipDialogVisible = false">取消</el-button>
</div>
</el-dialog>
<ChooselistEam ref="eamList" @getBaseData="getEamData" />
<po-order-advanced-query
@ -511,6 +562,7 @@
-->
<el-dialog
title="选择供应商可供物料"
v-drag
:visible.sync="supplierPartDialogVisible"
width="820px"
top="6vh"
@ -548,6 +600,7 @@ import {
closePoDetail,
openPoDetail,
issuePoDetail,
shipPoDetailPreview,
shipPoDetail,
createPoOrder,
getPoCustomerOptions,
@ -793,6 +846,22 @@ export default {
addPriceLookupSeq: 0,
selectedCustomerScope: null,
// ===== =====
shipDialogVisible: false,
shipDialogSaving: false,
shipDialogForm: {
site: '',
orderNo: '',
itemNo: null,
status: '',
orderQty: 0,
inspectQty: 0,
inspectApproveQty: 0,
currentShipQty: 0,
canShipQty: 0,
shipQty: 0
},
// ===== =====
currentRow: null,
// select selectOptionsKey selectOptions - rqrq
@ -1182,7 +1251,8 @@ export default {
fixed: '',
columnWidth: 80,
showOverflowTooltip: true,
editAble: true,
// A-Qtyc_ship_qty
editAble: false,
editType: 'text',
selectOptionsKey: '',
selectOptions: null
@ -2430,26 +2500,137 @@ export default {
}).catch(() => {})
},
/**
* 生成发货弹窗默认模型
* 说明所有数量字段默认按 0 初始化避免出现 null 导致的显示/比较异常
*/
createEmptyShipDialogForm () {
return {
site: '',
orderNo: '',
itemNo: null,
status: '',
orderQty: 0,
inspectQty: 0,
inspectApproveQty: 0,
currentShipQty: 0,
canShipQty: 0,
shipQty: 0
}
},
/**
* 关闭发货弹窗时统一重置状态避免上一次缓存数据污染下一次操作
*/
resetShipDialog () {
this.shipDialogSaving = false
this.shipDialogForm = this.createEmptyShipDialogForm()
},
/**
* 发货弹窗只读数量显示格式化
* 规则null/空字符串显示为0其余保持原值避免出现 "undefined"
*/
formatShipDialogDisplay (value) {
if (value === null || value === undefined || value === '') {
return '0'
}
return String(value)
},
/**
* 将发货弹窗数值输入统一转换为 Number
* 规则空值返回 NaN便于后续统一走前端校验提示
*/
normalizeShipDialogNumber (value) {
if (value === '' || value === null || value === undefined) {
return Number.NaN
}
const num = Number(value)
return Number.isFinite(num) ? num : Number.NaN
},
/**
* 点击 shipped
* 1) 先按 site + orderNo + itemNo 查询后端实时快照
* 2) 弹出发货确认框并回填默认值本次发货数量=可发货数量
* 3) 由用户确认后再提交发货
*/
handleShipPoOrder (row) {
const params = buildPoDetailActionParams(row, this.$store.state.user.site)
if (!params.id && !(params.orderNo && params.site && params.itemNo != null)) {
if (!params.orderNo || !params.site || params.itemNo == null) {
this.$message.error('无法识别订单行,请刷新后重试')
return
}
const poLabel = row.poNo ? `PO ${row.poNo}` : '该订单'
const itemLabel = row.itemNo != null ? `${row.itemNo}` : ''
this.$confirm(`确定将${poLabel}${itemLabel}标记为已发货?`, '提示', { type: 'warning' }).then(() => {
shipPoDetail(params).then(({ data }) => {
if (data && data.code === 0) {
this.$message.success('发货成功')
this.getDataList()
} else {
this.$message.error((data && data.msg) || '发货失败')
}
}).catch(err => {
this.$message.error((err && err.message) || '发货失败')
})
}).catch(() => {})
shipPoDetailPreview({
site: params.site,
orderNo: params.orderNo,
itemNo: params.itemNo
}).then(({ data }) => {
if (!(data && data.code === 0 && data.data)) {
this.$message.error((data && data.msg) || '加载发货数据失败')
return
}
const preview = data.data
this.shipDialogForm = {
site: preview.site || params.site,
orderNo: preview.orderNo || params.orderNo,
itemNo: preview.itemNo != null ? preview.itemNo : params.itemNo,
status: preview.status || '',
orderQty: preview.orderQty != null ? Number(preview.orderQty) : 0,
inspectQty: preview.inspectQty != null ? Number(preview.inspectQty) : 0,
inspectApproveQty: preview.inspectApproveQty != null ? Number(preview.inspectApproveQty) : 0,
currentShipQty: preview.currentShipQty != null ? Number(preview.currentShipQty) : 0,
canShipQty: preview.canShipQty != null ? Number(preview.canShipQty) : 0,
shipQty: preview.shipQty != null ? Number(preview.shipQty) : 0
}
this.shipDialogVisible = true
}).catch(err => {
this.$message.error((err && err.message) || '加载发货数据失败')
})
},
/**
* 提交发货确认
* 1) 仅校验本次发货数量 > 0 <= 未发货数量
* 2) 提交后端回写 qty / c_ship_qty / status
* 3) 成功后关闭弹窗并刷新列表
*/
submitShipDialog () {
const orderQty = this.normalizeShipDialogNumber(this.shipDialogForm.orderQty)
const unshippedQty = this.normalizeShipDialogNumber(this.shipDialogForm.canShipQty)
const shipQty = this.normalizeShipDialogNumber(this.shipDialogForm.shipQty)
if (!Number.isFinite(shipQty) || shipQty <= 0) {
this.$message.error('本次发货数量必须大于0')
return
}
if (!Number.isFinite(unshippedQty) || shipQty > unshippedQty) {
this.$message.error('本次发货数量不能大于未发货数量')
return
}
const payload = {
site: this.shipDialogForm.site,
orderNo: this.shipDialogForm.orderNo,
itemNo: this.shipDialogForm.itemNo,
orderQty,
shipQty
}
this.shipDialogSaving = true
shipPoDetail(payload).then(({ data }) => {
this.shipDialogSaving = false
if (data && data.code === 0) {
this.$message.success('发货成功')
this.shipDialogVisible = false
this.getDataList()
} else {
this.$message.error((data && data.msg) || '发货失败')
}
}).catch(err => {
this.shipDialogSaving = false
this.$message.error((err && err.message) || '发货失败')
})
},
handleOpenPoOrder (row) {
@ -4135,6 +4316,21 @@ export default {
color: #606266;
}
.ship-dialog-form {
padding: 0 4px;
}
.ship-dialog-input {
width: 120px;
text-align: right;
}
.ship-dialog-footer {
text-align: center;
}
.el-table /deep/ .cell {
height: auto;
line-height: 1.5;

9
src/views/modules/order/poOrderStatusOptions.js

@ -7,6 +7,7 @@ export const PO_ORDER_STATUS_OPTIONS = [
{ label: '待验货', value: '待验货' },
{ label: '验货中', value: '验货中' },
{ label: '验货完成', value: '验货完成' },
{ label: '部分发货', value: '部分发货' },
{ label: '已发货', value: '已发货' },
{ label: '已取消', value: '已取消' },
{ label: '已关闭', value: '已关闭' }
@ -35,14 +36,14 @@ export function canEditPoColumnByStatus (status, columnProp) {
return true
}
/** 是否可「关闭」 */
/** 是否可「关闭」:除已关闭、已取消外显示关闭按钮(最终可否关闭以后端校验为准) */
export function canClosePoOrder (status) {
return !!status && status !== '草稿' && status !== '已关闭' && status !== '已取消' && status !== '已发货'
return !!status && status !== '已关闭' && status !== '已取消'
}
/** 是否可「shipped」(仅验货完成) */
/** 是否可「shipped」:验货中 / 验货完成 / 部分发货(兼容历史状态:部分验货)均允许发货弹窗入口 */
export function canShipPoOrder (status) {
return status === '验货完成'
return status === '验货中' || status === '验货完成' || status === '部分发货' || status === '部分验货'
}
/** 是否可「打开」(仅已关闭) */

4
src/views/modules/order/poOrder_search.vue

@ -92,7 +92,9 @@
<el-tabs v-model="activeTab" style="margin-top: 0px; width: 99%;" @tab-click="handleTabClick" class="customer-tab" type="border-card">
<!-- 订单详情 -->
<el-tab-pane label="订单详情" name="orderDetail">
<po-order-detail :detail-data="currentRow" />
<po-order-detail
:detail-data="currentRow"
:schema-fields="fieldSchemaFields" />
</el-tab-pane>
<!-- 物流信息 -->
<el-tab-pane label="物流" name="logistics">

Loading…
Cancel
Save