7 changed files with 594 additions and 85 deletions
-
9src/api/order/poOrder.js
-
172src/views/modules/order/com_poOrderAdvancedQuery.vue
-
144src/views/modules/order/poOrder.vue
-
89src/views/modules/order/poOrderAdvancedQueryConfig.js
-
72src/views/modules/order/poOrderAdvancedQueryHelper.js
-
57src/views/modules/order/poOrderStatusOptions.js
-
136src/views/modules/order/poOrder_search.vue
@ -0,0 +1,172 @@ |
|||||
|
<template> |
||||
|
<!-- |
||||
|
【AI 维护】高级查询弹窗(poOrder / poOrder_search 共用) |
||||
|
样式参考:com_part_SpecParams.vue 属性填写表格 + .rq 紧凑行高 |
||||
|
--> |
||||
|
<el-dialog |
||||
|
title="高级查询" |
||||
|
:visible.sync="dialogVisible" |
||||
|
width="900px" |
||||
|
top="3vh" |
||||
|
:close-on-click-modal="false" |
||||
|
v-drag |
||||
|
append-to-body |
||||
|
custom-class="po-advanced-query-dialog" |
||||
|
@open="handleOpen" |
||||
|
@close="handleClose"> |
||||
|
<div class="rq po-advanced-query-body"> |
||||
|
<el-table |
||||
|
:height="tableHeight" |
||||
|
:data="advancedQueryData.rows" |
||||
|
border |
||||
|
style="width: 100%;"> |
||||
|
<el-table-column |
||||
|
prop="label" |
||||
|
label="字段" |
||||
|
header-align="center" |
||||
|
align="left" |
||||
|
min-width="200" |
||||
|
show-overflow-tooltip /> |
||||
|
<el-table-column |
||||
|
label="运算符" |
||||
|
header-align="center" |
||||
|
align="center" |
||||
|
width="120"> |
||||
|
<template slot-scope="{ row }"> |
||||
|
<el-select v-model="row.operator" style="width: 100%;"> |
||||
|
<el-option |
||||
|
v-for="op in getOperatorsByDataType(row.dataType)" |
||||
|
:key="op.value" |
||||
|
:label="op.label" |
||||
|
:value="op.value" /> |
||||
|
</el-select> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column |
||||
|
label="值" |
||||
|
header-align="center" |
||||
|
align="left" |
||||
|
min-width="220"> |
||||
|
<template slot-scope="{ row }"> |
||||
|
<el-input v-model="row.value" clearable placeholder="留空则不参与筛选" /> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
<el-footer style="height:25px;margin-top: 10px;text-align:center"> |
||||
|
<el-button @click="handleReset">重置</el-button> |
||||
|
<el-button @click="dialogVisible = false">取消</el-button> |
||||
|
<el-button type="primary" @click="handleQuery">查询</el-button> |
||||
|
</el-footer> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { getOperatorsByDataType } from './poOrderAdvancedQueryConfig.js' |
||||
|
import { resetAdvancedQueryData } from './poOrderAdvancedQueryHelper.js' |
||||
|
|
||||
|
export default { |
||||
|
name: 'PoOrderAdvancedQuery', |
||||
|
props: { |
||||
|
visible: { |
||||
|
type: Boolean, |
||||
|
default: false |
||||
|
}, |
||||
|
advancedQueryData: { |
||||
|
type: Object, |
||||
|
required: true |
||||
|
} |
||||
|
}, |
||||
|
data () { |
||||
|
return { |
||||
|
tableHeight: 400 |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
dialogVisible: { |
||||
|
get () { |
||||
|
return this.visible |
||||
|
}, |
||||
|
set (val) { |
||||
|
this.$emit('update:visible', val) |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
beforeDestroy () { |
||||
|
window.removeEventListener('resize', this.calcTableHeight) |
||||
|
}, |
||||
|
methods: { |
||||
|
getOperatorsByDataType, |
||||
|
handleOpen () { |
||||
|
this.calcTableHeight() |
||||
|
window.addEventListener('resize', this.calcTableHeight) |
||||
|
}, |
||||
|
calcTableHeight () { |
||||
|
this.$nextTick(() => { |
||||
|
const vh = window.innerHeight || 800 |
||||
|
// 预留:dialog 顶距 + 标题栏 + 底栏按钮 + 内边距 |
||||
|
const reserved = 130 |
||||
|
this.tableHeight = Math.max(260, Math.min(Math.floor(vh * 0.72) - reserved, 560)) |
||||
|
}) |
||||
|
}, |
||||
|
handleReset () { |
||||
|
resetAdvancedQueryData(this.advancedQueryData) |
||||
|
this.$emit('reset') |
||||
|
}, |
||||
|
handleQuery () { |
||||
|
window.removeEventListener('resize', this.calcTableHeight) |
||||
|
this.dialogVisible = false |
||||
|
this.$emit('query') |
||||
|
}, |
||||
|
handleClose () { |
||||
|
window.removeEventListener('resize', this.calcTableHeight) |
||||
|
this.$emit('update:visible', false) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.po-advanced-query-body { |
||||
|
padding: 0 2px; |
||||
|
} |
||||
|
|
||||
|
.po-advanced-query-footer { |
||||
|
height: 40px; |
||||
|
margin-top: 12px; |
||||
|
padding: 0; |
||||
|
text-align: center; |
||||
|
line-height: 40px; |
||||
|
} |
||||
|
|
||||
|
/* 与产品清单属性填写 com_part_SpecParams 一致的紧凑表格行高 */ |
||||
|
.rq.po-advanced-query-body /deep/ .el-table .cell { |
||||
|
line-height: 28px; |
||||
|
font-size: 12px; |
||||
|
height: 28px; |
||||
|
padding: 2px 4px; |
||||
|
} |
||||
|
|
||||
|
.rq.po-advanced-query-body /deep/ .el-input__inner { |
||||
|
height: 26px; |
||||
|
line-height: 26px; |
||||
|
font-size: 12px; |
||||
|
} |
||||
|
|
||||
|
.rq.po-advanced-query-body /deep/ .el-input__icon { |
||||
|
line-height: 26px; |
||||
|
} |
||||
|
|
||||
|
.rq.po-advanced-query-body /deep/ .el-table td, |
||||
|
.rq.po-advanced-query-body /deep/ .el-table th { |
||||
|
padding: 2px 0; |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
|
<style lang="scss"> |
||||
|
/* 弹窗 body 不出现双滚动条,表格区域单独滚动 */ |
||||
|
.po-advanced-query-dialog .el-dialog__body { |
||||
|
padding: 10px 16px 12px; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,89 @@ |
|||||
|
/** |
||||
|
* ============================================================================= |
||||
|
* 【高级查询静态配置 - AI 维护说明】 |
||||
|
* |
||||
|
* ⚠️ 修改以下任一内容时,必须同步重新生成 PO_ADVANCED_QUERY_FIELD_CONFIG: |
||||
|
* 1. poOrder_search.vue → columnList(columnProp / columnLabel / 顺序) |
||||
|
* 2. PODetailMapper.xml → myPage / myPageAdvanced 的 SELECT 字段及别名 |
||||
|
* 3. 运算符规则(ADVANCED_QUERY_OPERATOR_OPTIONS / getOperatorsByDataType) |
||||
|
* |
||||
|
* 生成规则: |
||||
|
* - field = columnProp(与 columnList 完全一致) |
||||
|
* - label = columnLabel |
||||
|
* - sortOrder = columnList 顺序(从 1 开始) |
||||
|
* - sqlColumn = myPage SELECT 中可用于 WHERE 的完整 SQL 表达式(含表别名、函数) |
||||
|
* 例:poh.c_enquiry、ss.supplier_name、COALESCE(pod.inspect_approve_qty, 0) |
||||
|
* - dataType = string | number | date |
||||
|
* |
||||
|
* 同步修改后端白名单(必须与 sqlColumn 完全一致): |
||||
|
* PoDetailAdvancedQuerySupport.java → FIELD_SQL_MAP |
||||
|
* |
||||
|
* 最后更新:2026-06-25 |
||||
|
* 对照:poOrder_search.vue columnList + PODetailMapper.xml#myPage SELECT |
||||
|
* ============================================================================= |
||||
|
*/ |
||||
|
|
||||
|
/** 运算符:前端 value → 后端 operator(条件之间固定 AND) */ |
||||
|
export const ADVANCED_QUERY_OPERATOR_OPTIONS = [ |
||||
|
{ label: '等于', value: 'eq' }, |
||||
|
{ label: '包含', value: 'contains' }, |
||||
|
{ label: '大于', value: 'gt' }, |
||||
|
{ label: '小于', value: 'lt' }, |
||||
|
{ label: '大于等于', value: 'gte' }, |
||||
|
{ label: '小于等于', value: 'lte' } |
||||
|
] |
||||
|
|
||||
|
/** 按 dataType 过滤可用运算符(number/date 不提供「包含」) */ |
||||
|
export function getOperatorsByDataType (dataType) { |
||||
|
if (dataType === 'string') { |
||||
|
return ADVANCED_QUERY_OPERATOR_OPTIONS |
||||
|
} |
||||
|
return ADVANCED_QUERY_OPERATOR_OPTIONS.filter(o => o.value !== 'contains') |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 高级查询字段配置 — 顺序与 poOrder_search.vue / poOrder.vue 表格 columnList 一致 |
||||
|
* sqlColumn:多表关联完整表达式,计算列写函数表达式 |
||||
|
*/ |
||||
|
export const PO_ADVANCED_QUERY_FIELD_CONFIG = [ |
||||
|
{ sortOrder: 1, field: 'customer', label: 'Customer', sqlColumn: 'poh.c_customer', dataType: 'string' }, |
||||
|
{ sortOrder: 2, field: 'buyer', label: 'Buyer', sqlColumn: 'poh.buyer', dataType: 'string' }, |
||||
|
{ sortOrder: 3, field: 'supplierName', label: 'Vendor Name', sqlColumn: 'ss.supplier_name', dataType: 'string' }, |
||||
|
{ sortOrder: 4, field: 'shortOffice', label: 'V_Short_Office', sqlColumn: 'ss.c_short_office', dataType: 'string' }, |
||||
|
{ sortOrder: 5, field: 'shortNpc', label: 'V_Short_NPC', sqlColumn: 'ss.c_short_npc', dataType: 'string' }, |
||||
|
{ sortOrder: 6, field: 'poNo', label: 'PO_No', sqlColumn: 'poh.po_no', dataType: 'string' }, |
||||
|
{ sortOrder: 7, field: 'partNo', label: 'Item', sqlColumn: 'pod.part_no', dataType: 'string' }, |
||||
|
{ sortOrder: 8, field: 'category', label: 'Category', sqlColumn: 'p.category', dataType: 'string' }, |
||||
|
{ sortOrder: 9, field: 'sku', label: 'SKU', sqlColumn: 'p.sku', dataType: 'string' }, |
||||
|
{ sortOrder: 10, field: 'price', label: 'Unit Price', sqlColumn: 'pod.price', dataType: 'number' }, |
||||
|
{ sortOrder: 11, field: 'qty', label: 'PO Qty', sqlColumn: 'pod.qty', dataType: 'number' }, |
||||
|
{ sortOrder: 12, field: 'value', label: 'PO Value', sqlColumn: 'pod.c_value', dataType: 'number' }, |
||||
|
{ sortOrder: 13, field: 'shipQty', label: 'A-Qty', sqlColumn: 'pod.c_ship_qty', dataType: 'number' }, |
||||
|
{ sortOrder: 14, field: 'sumPrice', label: 'A-Value', sqlColumn: 'pod.c_sum_price', dataType: 'number' }, |
||||
|
{ sortOrder: 15, field: 'departure', label: 'Departure Port', sqlColumn: 'poh.c_departure', dataType: 'string' }, |
||||
|
{ sortOrder: 16, field: 'destination', label: 'Destination Port', sqlColumn: 'poh.c_destination', dataType: 'string' }, |
||||
|
{ sortOrder: 17, field: 'shipVia', label: 'Method', sqlColumn: 'poh.ship_via', dataType: 'string' }, |
||||
|
{ sortOrder: 18, field: 'orderDate', label: 'Buyer Release Date', sqlColumn: 'poh.order_date', dataType: 'date' }, |
||||
|
{ sortOrder: 19, field: 'enquiry', label: 'Planner Release Date', sqlColumn: 'poh.c_enquiry', dataType: 'date' }, |
||||
|
{ sortOrder: 20, field: 'status', label: 'Status', sqlColumn: 'pod.status', dataType: 'string' }, |
||||
|
{ sortOrder: 21, field: 'confirmed', label: 'PI Confirmed Date', sqlColumn: 'poh.c_confirmed', dataType: 'date' }, |
||||
|
{ sortOrder: 22, field: 'wantReceiveDate', label: 'Original Arrival Date', sqlColumn: 'pod.want_receive_date', dataType: 'date' }, |
||||
|
{ sortOrder: 23, field: 'narrival', label: 'Final Confirmed Arrival Date', sqlColumn: 'pod.c_narrival', dataType: 'date' }, |
||||
|
{ sortOrder: 24, field: 'crd', label: 'PI Confirmed CRD', sqlColumn: 'pod.c_crd', dataType: 'date' }, |
||||
|
{ sortOrder: 25, field: 'inspection', label: 'Inspection Date', sqlColumn: 'pod.c_inspection', dataType: 'date' }, |
||||
|
{ sortOrder: 26, field: 'realCrd', label: 'Actual Completion Date', sqlColumn: 'pod.c_real_crd', dataType: 'date' }, |
||||
|
{ sortOrder: 27, field: 'eta', label: 'ETA', sqlColumn: 'pod.c_eta', dataType: 'date' }, |
||||
|
{ sortOrder: 28, field: 'flexid', label: 'Flexport Id', sqlColumn: 'pod.c_flexid', dataType: 'string' }, |
||||
|
{ sortOrder: 29, field: 'obd', label: 'On Board Date', sqlColumn: 'pod.c_obd', dataType: 'date' }, |
||||
|
{ sortOrder: 30, field: 'docSent', label: 'Doc Sent', sqlColumn: 'pod.c_doc_sent', dataType: 'string' }, |
||||
|
{ sortOrder: 31, field: 'telexRelease', label: 'Telex Release', sqlColumn: 'pod.c_telex_release', dataType: 'string' }, |
||||
|
{ sortOrder: 32, field: 'advancePayment', label: 'Advance Payment', sqlColumn: 'pod.c_advance_payment', dataType: 'string' }, |
||||
|
{ sortOrder: 33, field: 'advancePaid', label: 'Advanc Paid', sqlColumn: 'pod.c_advance_paid', dataType: 'string' }, |
||||
|
{ sortOrder: 34, field: 'createTime', label: 'Create Date', sqlColumn: 'pod.create_time', dataType: 'date' }, |
||||
|
{ sortOrder: 35, field: 'planner', label: 'M-Planner', sqlColumn: 'pod.c_planner', dataType: 'string' }, |
||||
|
{ sortOrder: 36, field: 'edit', label: 'Edit Date', sqlColumn: 'pod.c_edit', dataType: 'string' }, |
||||
|
{ sortOrder: 37, field: 'endPlanner', label: 'Last Editor', sqlColumn: 'pod.c_end_planner', dataType: 'string' }, |
||||
|
{ sortOrder: 38, field: 'remarkDelay', label: 'Remark Delay', sqlColumn: 'pod.c_remark_delay', dataType: 'string' }, |
||||
|
{ sortOrder: 39, field: 'remark', label: 'Comments', sqlColumn: 'pod.remark', dataType: 'string' }, |
||||
|
{ sortOrder: 40, field: 'inspectionCompletedQty', label: 'Inspection Completed Qty', sqlColumn: 'COALESCE(pod.inspect_approve_qty, 0)', dataType: 'number' } |
||||
|
] |
||||
@ -0,0 +1,72 @@ |
|||||
|
import { PO_ADVANCED_QUERY_FIELD_CONFIG } from './poOrderAdvancedQueryConfig.js' |
||||
|
|
||||
|
/** |
||||
|
* 【AI 维护】高级查询状态对象工厂 |
||||
|
* advancedQueryData 为页面级唯一对象,查询/导出均读取此对象 |
||||
|
*/ |
||||
|
export function createAdvancedQueryData () { |
||||
|
return { |
||||
|
rows: PO_ADVANCED_QUERY_FIELD_CONFIG.map(item => ({ |
||||
|
field: item.field, |
||||
|
label: item.label, |
||||
|
dataType: item.dataType, |
||||
|
sqlColumn: item.sqlColumn, |
||||
|
operator: item.dataType === 'string' ? 'contains' : 'eq', |
||||
|
value: '' |
||||
|
})) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** 重置高级查询(仅弹窗内「重置」按钮调用,外部重置不清空) */ |
||||
|
export function resetAdvancedQueryData (advancedQueryData) { |
||||
|
advancedQueryData.rows = createAdvancedQueryData().rows |
||||
|
} |
||||
|
|
||||
|
/** 收集有效高级条件(AND,空 value 跳过) */ |
||||
|
export function getActiveAdvancedConditions (advancedQueryData) { |
||||
|
if (!advancedQueryData || !advancedQueryData.rows) { |
||||
|
return [] |
||||
|
} |
||||
|
return advancedQueryData.rows |
||||
|
.filter(r => r.value != null && String(r.value).trim() !== '') |
||||
|
.map(r => ({ |
||||
|
field: r.field, |
||||
|
operator: r.operator, |
||||
|
value: String(r.value).trim() |
||||
|
})) |
||||
|
} |
||||
|
|
||||
|
export function hasActiveAdvancedConditions (advancedQueryData) { |
||||
|
return getActiveAdvancedConditions(advancedQueryData).length > 0 |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 组装查询/导出参数 |
||||
|
* - 有高级条件时走 advancedPage,并附带 searchData 基础字段 |
||||
|
* - 无高级条件时走原 page |
||||
|
*/ |
||||
|
export function buildPoOrderQueryParams ({ searchData, advancedQueryData, page, limit }) { |
||||
|
const conditions = getActiveAdvancedConditions(advancedQueryData) |
||||
|
const baseParams = { |
||||
|
site: searchData.site, |
||||
|
page, |
||||
|
limit, |
||||
|
customer: searchData.customer || '', |
||||
|
buyer: searchData.buyer || '', |
||||
|
poNo: searchData.poNo || '', |
||||
|
sku: searchData.sku || '', |
||||
|
status: searchData.status || '', |
||||
|
supplierName: searchData.supplierName || '', |
||||
|
partNo: searchData.partNo || '' |
||||
|
} |
||||
|
if (conditions.length > 0) { |
||||
|
return { |
||||
|
params: { ...baseParams, conditions }, |
||||
|
useAdvanced: true |
||||
|
} |
||||
|
} |
||||
|
return { |
||||
|
params: { ...searchData, page, limit }, |
||||
|
useAdvanced: false |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,57 @@ |
|||||
|
/** |
||||
|
* PO 订单行状态选项(静态数据,查询下拉用,不查库) |
||||
|
*/ |
||||
|
export const PO_ORDER_STATUS_OPTIONS = [ |
||||
|
{ label: '已下达', value: '已下达' }, |
||||
|
{ label: '待验货', value: '待验货' }, |
||||
|
{ label: '验货中', value: '验货中' }, |
||||
|
{ label: '验货完成', value: '验货完成' }, |
||||
|
{ label: '已取消', value: '已取消' }, |
||||
|
{ label: '已关闭', value: '已关闭' } |
||||
|
] |
||||
|
|
||||
|
/** 是否可「关闭」 */ |
||||
|
export function canClosePoOrder (status) { |
||||
|
return !!status && status !== '已关闭' && status !== '已取消' |
||||
|
} |
||||
|
|
||||
|
/** 是否可「打开」(仅已关闭) */ |
||||
|
export function canOpenPoOrder (status) { |
||||
|
return status === '已关闭' |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 打开时根据验货数量推算恢复状态(与后端 PoDetailStatusSupport 规则一致) |
||||
|
*/ |
||||
|
export function resolvePoOrderStatusByInspectQty (row) { |
||||
|
const toInspect = Number(row.toInspectQty != null ? row.toInspectQty : 0) |
||||
|
const approve = Number(row.inspectApproveQty != null ? row.inspectApproveQty : (row.inspectionCompletedQty != null ? row.inspectionCompletedQty : 0)) |
||||
|
const qty = Number(row.qty != null ? row.qty : 0) |
||||
|
|
||||
|
if (toInspect === 0) { |
||||
|
return '已下达' |
||||
|
} |
||||
|
if (toInspect > 0 && approve === 0) { |
||||
|
return '待验货' |
||||
|
} |
||||
|
if (qty > 0 && approve === qty) { |
||||
|
return '验货完成' |
||||
|
} |
||||
|
if (approve > 0 && (qty === 0 || approve < qty)) { |
||||
|
return '验货中' |
||||
|
} |
||||
|
if (approve > 0 && qty > 0 && approve >= qty) { |
||||
|
return '验货完成' |
||||
|
} |
||||
|
return '待验货' |
||||
|
} |
||||
|
|
||||
|
/** 关闭/打开接口入参(id 为空时用 orderNo+site+itemNo 定位) */ |
||||
|
export function buildPoDetailActionParams (row, site) { |
||||
|
return { |
||||
|
id: row.id != null && row.id !== '' ? row.id : undefined, |
||||
|
orderNo: row.orderNo, |
||||
|
site: row.site || site, |
||||
|
itemNo: row.itemNo |
||||
|
} |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue