yanyan 1 month ago
parent
commit
35a5152fe9
  1. 12
      src/api/quickQuery/quickQueryField.js
  2. 1226
      src/views/modules/order/poOrder.vue
  3. 254
      src/views/modules/quickQuery/components/QuickQueryFilter.vue
  4. 61
      src/views/modules/quickQuery/utils/quickQueryMatch.js

12
src/api/quickQuery/quickQueryField.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)

1226
src/views/modules/order/poOrder.vue
File diff suppressed because it is too large
View File

254
src/views/modules/quickQuery/components/QuickQueryFilter.vue

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

61
src/views/modules/quickQuery/utils/quickQueryMatch.js

@ -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 得到的 conditionsnull/空则恒为 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
}
Loading…
Cancel
Save