Files
workspace/code/fms/fms-vue/src/components/fms-module-common/queryUtils.js
T
2026-09-04 17:31:36 +08:00

134 lines
3.9 KiB
JavaScript

// 模块数据驱动列表的「查询条件」工具:构建查询 SQL 片段、解析查询输入/默认值。
// 供 fms-module-list / fms-module-edit 等按模块元数据渲染的组件共用;
// 展示格式化(parseOptions / formatDateValue)见 fieldUtils.js。
export const identifierRe = /^[A-Za-z_][A-Za-z0-9_]*$/
export function escapeSqlText(value) {
return String(value).replaceAll("'", "''")
}
export function requireModuleId(value) {
const id = String(value ?? '')
if (!/^\d+$/.test(id)) throw new Error('模块 ID 格式不正确')
return id
}
export function isEmptyValue(value) {
return value === undefined || value === null || value === ''
}
export function isRangeQuery(item) {
return (
item.config.b_operator === 'between' ||
item.config.b_component === 'number-range' ||
item.field.b_type === 'datetime'
)
}
export function isNumericField(item) {
return item.field.b_type === 'number' || item.field.b_type === 'money'
}
export function isDateQuery(item) {
return (
item.config.b_component === 'date-picker' ||
item.field.b_type === 'date' ||
item.field.b_type === 'datetime'
)
}
export function emptyQueryValue(item) {
if (item.field.b_type === 'checkbox') return ''
if (isRangeQuery(item) || item.config.b_operator === 'in') return []
return undefined
}
export function defaultQueryValue(item) {
const value = item.config.b_default_value
if (value === null || value === undefined || value === '') return emptyQueryValue(item)
if (isRangeQuery(item) || item.config.b_operator === 'in') {
try {
const parsed = JSON.parse(value)
if (Array.isArray(parsed)) return parsed
} catch {
// 非 JSON 默认值继续按逗号分隔处理。
}
return String(value)
.split(',')
.map((part) => part.trim())
.filter(Boolean)
}
if (isNumericField(item)) {
const number = Number(value)
return Number.isFinite(number) ? number : undefined
}
return value
}
export function sqlLiteral(value, field, endOfRange = false) {
if (isEmptyValue(value)) return null
if (field.b_type === 'number' || field.b_type === 'money') {
const number = Number(value)
return Number.isFinite(number) ? String(number) : null
}
if (field.b_type === 'checkbox') {
return value === true || Number(value) === 1 ? '1' : '0'
}
let normalized = String(value)
const isDate = field.b_type === 'date' || field.b_type === 'datetime'
if (isDate && value && typeof value.format === 'function') {
normalized = value.format('YYYY-MM-DD')
} else if (isDate) {
normalized = String(value).slice(0, 10)
}
if (field.b_type === 'datetime') {
normalized += endOfRange ? ' 23:59:59' : ' 00:00:00'
}
return `N'${escapeSqlText(normalized)}'`
}
export function buildQueryCondition(item, value) {
const fieldName = item.field.b_field
if (!identifierRe.test(fieldName)) return ''
const field = `[${fieldName}]`
if (isRangeQuery(item)) {
const values = Array.isArray(value) ? value : []
const start = sqlLiteral(values[0], item.field)
const end = sqlLiteral(values[1], item.field, true)
if (start && end) return `${field} BETWEEN ${start} AND ${end}`
if (start) return `${field} >= ${start}`
if (end) return `${field} <= ${end}`
return ''
}
if (item.config.b_operator === 'in') {
let values = value
if (!Array.isArray(values)) {
values = String(value ?? '')
.split(',')
.map((part) => part.trim())
.filter(Boolean)
}
const literals = []
for (const entry of values) {
const literal = sqlLiteral(entry, item.field)
if (literal) literals.push(literal)
}
return literals.length ? `${field} IN (${literals.join(', ')})` : ''
}
const literal = sqlLiteral(value, item.field)
if (!literal) return ''
if (item.config.b_operator === 'like') {
return `${field} LIKE N'%${escapeSqlText(String(value))}%'`
}
return `${field} = ${literal}`
}