Browse Source
feat(order): 新增PO订单管理页面
feat(order): 新增PO订单管理页面
- 实现PO订单查询功能,支持按客户、采购员、订单号、SKU、状态筛选 - 创建表格组件显示PO订单详细信息,包括供应商、商品类别、数量金额等字段 - 集成编辑模式功能,支持下拉选择、数值输入等不同类型的单元格编辑 - 添加分页功能支持,配置多种页面大小选项 - 实现列配置管理,支持动态显示隐藏表格列 - 集成模拟数据源,预设多个PO订单样本数据用于测试 - 添加响应式布局适配不同屏幕尺寸master
4 changed files with 1520 additions and 0 deletions
-
12src/api/quickQuery/quickQueryField.js
-
1193src/views/modules/order/poOrder.vue
-
254src/views/modules/quickQuery/components/QuickQueryFilter.vue
-
61src/views/modules/quickQuery/utils/quickQueryMatch.js
@ -0,0 +1,12 @@ |
|||
import { createAPI } from '@/utils/httpRequest.js' |
|||
|
|||
// 快捷查询字段配置 - rqrq
|
|||
|
|||
export const listQuickQueryFieldsByTableId = data => |
|||
createAPI('/quickQuery/field/listByTableId', 'post', data) |
|||
|
|||
export const saveQuickQueryField = data => |
|||
createAPI('/quickQuery/field/save', 'post', data) |
|||
|
|||
export const deleteQuickQueryField = data => |
|||
createAPI('/quickQuery/field/delete', 'post', data) |
|||
1193
src/views/modules/order/poOrder.vue
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,254 @@ |
|||
<template> |
|||
<span class="quick-query-filter-wrap"> |
|||
<el-button type="primary" @click="openDialog">{{ buttonText }}</el-button> |
|||
<el-dialog |
|||
:title="dialogTitle" |
|||
:visible.sync="visible" |
|||
:close-on-click-modal="false" |
|||
v-drag |
|||
width="720px" |
|||
@open="onDialogOpen"> |
|||
<div style="margin-bottom: 10px;"> |
|||
<el-button type="primary" size="small" @click="addRow">新增</el-button> |
|||
</div> |
|||
<el-table :data="rows" border size="small" max-height="360"> |
|||
<el-table-column label="字段" min-width="160" header-align="center"> |
|||
<template slot-scope="scope"> |
|||
<el-select |
|||
v-model="scope.row.fieldName" |
|||
placeholder="选择字段" |
|||
size="mini" |
|||
style="width: 100%" |
|||
filterable |
|||
@change="onFieldChange(scope.row)"> |
|||
<el-option |
|||
v-for="f in fieldMetaList" |
|||
:key="f.fieldName" |
|||
:label="f.fieldLabel" |
|||
:value="f.fieldName"> |
|||
</el-option> |
|||
</el-select> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="条件" min-width="120" header-align="center" align="center"> |
|||
<template slot-scope="scope"> |
|||
<el-select |
|||
v-model="scope.row.operator" |
|||
placeholder="条件" |
|||
size="mini" |
|||
style="width: 100%" |
|||
:disabled="!scope.row.dataType"> |
|||
<el-option |
|||
v-for="op in operatorsForRow(scope.row)" |
|||
:key="op.value" |
|||
:label="op.label" |
|||
:value="op.value"> |
|||
</el-option> |
|||
</el-select> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="值" min-width="200" header-align="center"> |
|||
<template slot-scope="scope"> |
|||
<el-date-picker |
|||
v-if="scope.row.dataType === 'DATETIME'" |
|||
v-model="scope.row.value" |
|||
type="date" |
|||
size="mini" |
|||
style="width: 100%" |
|||
value-format="yyyy-MM-dd" |
|||
placeholder="选择日期"> |
|||
</el-date-picker> |
|||
<el-input |
|||
v-else-if="scope.row.dataType === 'NUMBER'" |
|||
v-model="scope.row.value" |
|||
type="number" |
|||
size="mini" |
|||
placeholder="数字"> |
|||
</el-input> |
|||
<el-input |
|||
v-else |
|||
v-model="scope.row.value" |
|||
size="mini" |
|||
placeholder="文本" |
|||
:disabled="!scope.row.fieldName"> |
|||
</el-input> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="操作" width="70" header-align="center" align="center"> |
|||
<template slot-scope="scope"> |
|||
<el-button type="text" size="small" @click="removeRow(scope.$index)">删</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<span slot="footer" class="dialog-footer"> |
|||
<el-button type="primary" @click="apply" :loading="applyLoading">应用</el-button> |
|||
<el-button @click="visible = false">取消</el-button> |
|||
</span> |
|||
</el-dialog> |
|||
</span> |
|||
</template> |
|||
|
|||
<script> |
|||
import { listQuickQueryFieldsByTableId } from '@/api/quickQuery/quickQueryField.js' |
|||
|
|||
/** |
|||
* 快捷查询:根据 tableId 拉取后端可查询字段,拼条件 JSON 字符串交给业务回调 - rqrq |
|||
* |
|||
* @prop {String} tableId - 与库表 srm_quick_query_field.table_id 一致 |
|||
* @prop {String} site - 可选,工厂;与库 site 匹配(含全局 site 空串) |
|||
* @prop {Function} applyHandler - (conditionJsonString) => void,入参为条件 JSON 数组字符串 |
|||
*/ |
|||
export default { |
|||
name: 'QuickQueryFilter', |
|||
props: { |
|||
tableId: { |
|||
type: String, |
|||
required: true |
|||
}, |
|||
site: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
buttonText: { |
|||
type: String, |
|||
default: '快捷查询' |
|||
}, |
|||
dialogTitle: { |
|||
type: String, |
|||
default: '快捷查询' |
|||
}, |
|||
applyHandler: { |
|||
type: Function, |
|||
required: true |
|||
} |
|||
}, |
|||
data () { |
|||
return { |
|||
visible: false, |
|||
loadingMeta: false, |
|||
fieldMetaList: [], |
|||
rows: [], |
|||
applyLoading: false |
|||
} |
|||
}, |
|||
methods: { |
|||
openDialog () { |
|||
this.visible = true |
|||
}, |
|||
onDialogOpen () { |
|||
this.loadFieldMeta() |
|||
}, |
|||
loadFieldMeta () { |
|||
this.loadingMeta = true |
|||
listQuickQueryFieldsByTableId({ |
|||
tableId: this.tableId, |
|||
site: this.site || '' |
|||
}).then(({ data }) => { |
|||
if (data && data.code === 0) { |
|||
this.fieldMetaList = data.rows || [] |
|||
if (!this.fieldMetaList.length) { |
|||
this.$message.warning('未配置可查询字段,请在库表 srm_quick_query_field 中维护') |
|||
} |
|||
} else { |
|||
this.$alert((data && data.msg) || '加载字段失败', '错误', { confirmButtonText: '确定' }) |
|||
} |
|||
}).catch(() => { |
|||
this.$message.error('加载字段失败') |
|||
}).finally(() => { |
|||
this.loadingMeta = false |
|||
}) |
|||
}, |
|||
addRow () { |
|||
this.rows.push({ |
|||
_key: `${Date.now()}_${Math.random()}`, |
|||
fieldName: '', |
|||
fieldLabel: '', |
|||
dataType: '', |
|||
operator: '', |
|||
value: '' |
|||
}) |
|||
}, |
|||
removeRow (index) { |
|||
this.rows.splice(index, 1) |
|||
}, |
|||
onFieldChange (row) { |
|||
const meta = this.fieldMetaList.find(f => f.fieldName === row.fieldName) |
|||
if (meta) { |
|||
row.fieldLabel = meta.fieldLabel |
|||
row.dataType = (meta.dataType || '').toUpperCase() |
|||
} else { |
|||
row.fieldLabel = '' |
|||
row.dataType = '' |
|||
} |
|||
row.operator = '' |
|||
row.value = '' |
|||
}, |
|||
operatorsForRow (row) { |
|||
const t = (row.dataType || '').toUpperCase() |
|||
if (t === 'NUMBER') { |
|||
return [ |
|||
{ label: '大于', value: 'GT' }, |
|||
{ label: '小于', value: 'LT' }, |
|||
{ label: '等于', value: 'EQ' } |
|||
] |
|||
} |
|||
if (t === 'TEXT') { |
|||
return [ |
|||
{ label: '等于', value: 'EQ' }, |
|||
{ label: '包含', value: 'CONTAINS' } |
|||
] |
|||
} |
|||
if (t === 'DATETIME') { |
|||
return [ |
|||
{ label: '大于', value: 'GT' }, |
|||
{ label: '小于', value: 'LT' } |
|||
] |
|||
} |
|||
return [] |
|||
}, |
|||
apply () { |
|||
const built = [] |
|||
for (const r of this.rows) { |
|||
if (!r.fieldName) continue |
|||
if (!r.operator) { |
|||
this.$message.warning(`请为字段「${r.fieldLabel || r.fieldName}」选择条件`) |
|||
return |
|||
} |
|||
if (r.value === '' || r.value === null || r.value === undefined) { |
|||
this.$message.warning(`请填写「${r.fieldLabel || r.fieldName}」的值`) |
|||
return |
|||
} |
|||
built.push({ |
|||
fieldName: r.fieldName, |
|||
fieldLabel: r.fieldLabel, |
|||
dataType: r.dataType, |
|||
operator: r.operator, |
|||
value: r.value |
|||
}) |
|||
} |
|||
if (!built.length) { |
|||
this.$message.warning('请至少新增一行完整条件') |
|||
return |
|||
} |
|||
const jsonStr = JSON.stringify(built) |
|||
this.applyLoading = true |
|||
try { |
|||
if (typeof this.applyHandler === 'function') { |
|||
this.applyHandler(jsonStr, built) |
|||
} |
|||
this.$emit('apply', jsonStr, built) |
|||
this.visible = false |
|||
} finally { |
|||
this.applyLoading = false |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.quick-query-filter-wrap { |
|||
display: inline-block; |
|||
margin-left: 6px; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,61 @@ |
|||
/** |
|||
* 快捷查询条件:解析 JSON + 单行数据是否满足(纯函数,供列表页与后端约定一致) - rqrq |
|||
* |
|||
* 条件项结构:{ fieldName, fieldLabel?, dataType, operator, value } |
|||
* operator: GT | LT | EQ | CONTAINS |
|||
* dataType: NUMBER | TEXT | DATETIME |
|||
*/ |
|||
|
|||
/** |
|||
* @param {string} conditionJsonString - QuickQueryFilter 提交的 JSON 字符串 |
|||
* @returns {{ ok: true, conditions: Array } | { ok: false, error: string }} |
|||
*/ |
|||
export function parseQuickQueryJson (conditionJsonString) { |
|||
if (conditionJsonString == null || conditionJsonString === '') { |
|||
return { ok: true, conditions: [] } |
|||
} |
|||
try { |
|||
const parsed = JSON.parse(conditionJsonString) |
|||
if (!Array.isArray(parsed)) { |
|||
return { ok: false, error: '条件必须是数组' } |
|||
} |
|||
return { ok: true, conditions: parsed } |
|||
} catch (e) { |
|||
return { ok: false, error: '条件格式错误' } |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 判断一行数据是否满足全部快捷条件(AND) |
|||
* @param {Object} row - 行数据 |
|||
* @param {Array|null|undefined} conditions - parseQuickQueryJson 得到的 conditions;null/空则恒为 true |
|||
* @returns {boolean} |
|||
*/ |
|||
export function matchQuickQueryRow (row, conditions) { |
|||
if (!conditions || !conditions.length) return true |
|||
for (const c of conditions) { |
|||
const raw = row[c.fieldName] |
|||
const target = c.value |
|||
const op = c.operator |
|||
const dt = (c.dataType || '').toUpperCase() |
|||
if (dt === 'TEXT') { |
|||
const sv = String(raw == null ? '' : raw) |
|||
const tv = String(target == null ? '' : target) |
|||
if (op === 'EQ' && sv !== tv) return false |
|||
if (op === 'CONTAINS' && !sv.toLowerCase().includes(tv.toLowerCase())) return false |
|||
} else if (dt === 'NUMBER') { |
|||
const nv = parseFloat(raw) |
|||
const nt = parseFloat(target) |
|||
if (Number.isNaN(nv) || Number.isNaN(nt)) return false |
|||
if (op === 'GT' && !(nv > nt)) return false |
|||
if (op === 'LT' && !(nv < nt)) return false |
|||
if (op === 'EQ' && nv !== nt) return false |
|||
} else if (dt === 'DATETIME') { |
|||
const dv = String(raw == null ? '' : raw).slice(0, 10) |
|||
const dtarget = String(target == null ? '' : target).slice(0, 10) |
|||
if (op === 'GT' && !(dv > dtarget)) return false |
|||
if (op === 'LT' && !(dv < dtarget)) return false |
|||
} |
|||
} |
|||
return true |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue