94 lines
3.5 KiB
TypeScript
94 lines
3.5 KiB
TypeScript
/**
|
|
* 列头动态 facet(搜选项 + 勾选)选项加载。
|
|
* 与 useServerColumnFilters 配合:defs 中目标列 type=enum,打开漏斗时拉去重可选值。
|
|
* 可选 getContextParams:附带列表上下文(固定条件 + 顶部筛选 + 列头),并排除本列条件(Excel 级联)。
|
|
*/
|
|
import { reactive } from 'vue'
|
|
import { ElMessage } from 'element-plus'
|
|
import type { ColumnFilterDef } from '@/composables/useClientColumnFilters'
|
|
import { stripSelfColumnParams } from '@/composables/columnFacetContext'
|
|
|
|
export type FacetOption = { value: string; label: string; count: number }
|
|
|
|
export function useColumnFacetOptions(options: {
|
|
/** 需要动态拉可选值的列 prop(与 defs.prop 一致,亦作为 field 传给接口) */
|
|
facetFields: string[]
|
|
/** 请求可选值;应返回 { list: FacetOption[] } 或已解包的 list 结构 */
|
|
fetchFacet: (payload: {
|
|
field: string
|
|
keyword?: string
|
|
limit?: number
|
|
[key: string]: unknown
|
|
}) => Promise<unknown>
|
|
/** 非 facet 的静态 enum(字典等)回退;亦用于剥离本列 query 键 */
|
|
columnFilterDefs?: ColumnFilterDef[]
|
|
/** 当前列表查询上下文(固定条件 + 顶部筛选 + 列头);打开漏斗时会排除本列键 */
|
|
getContextParams?: () => Record<string, unknown>
|
|
limit?: number
|
|
}) {
|
|
const facetFieldSet = new Set(options.facetFields)
|
|
const facetOptionsMap = reactive<Record<string, FacetOption[]>>({})
|
|
const facetLoadingMap = reactive<Record<string, boolean>>({})
|
|
const limit = options.limit ?? 500
|
|
|
|
function enumOptionsFor(prop: string): FacetOption[] {
|
|
if (Object.prototype.hasOwnProperty.call(facetOptionsMap, prop)) {
|
|
return facetOptionsMap[prop]
|
|
}
|
|
const def = options.columnFilterDefs?.find((d) => d.prop === prop)
|
|
return (def?.enumOptions || []).map((o) => ({
|
|
value: String(o.value),
|
|
label: o.label,
|
|
count: (o as any).count ?? 0
|
|
}))
|
|
}
|
|
|
|
function optionsLoadingFor(prop: string) {
|
|
return Boolean(facetLoadingMap[prop])
|
|
}
|
|
|
|
async function onFilterOpen(prop: string) {
|
|
if (!facetFieldSet.has(prop)) return
|
|
facetLoadingMap[prop] = true
|
|
// 上下文(含审批 scope)变化时避免短暂展示上一轮可选值
|
|
facetOptionsMap[prop] = []
|
|
try {
|
|
const rawContext = options.getContextParams?.() || {}
|
|
const context = options.columnFilterDefs?.length
|
|
? stripSelfColumnParams(rawContext, prop, options.columnFilterDefs)
|
|
: { ...rawContext }
|
|
// 排序与导出无关字段不传给 facet
|
|
delete context.sortField
|
|
delete context.sortOrder
|
|
delete context.includeDocumentAttachments
|
|
delete context.includeArrangeCopyFlags
|
|
delete context.exportFormat
|
|
delete context.page
|
|
delete context.pageSize
|
|
|
|
const res = await options.fetchFacet({ ...context, field: prop, limit })
|
|
const data = (res as any)?.list ? res : (res as any)?.data || res || {}
|
|
const list = (data as any).list || []
|
|
facetOptionsMap[prop] = (Array.isArray(list) ? list : []).map((item: any) => ({
|
|
value: String(item?.value ?? ''),
|
|
label: String(item?.label ?? item?.value ?? ''),
|
|
count: Number(item?.count ?? 0)
|
|
}))
|
|
} catch (e: any) {
|
|
facetOptionsMap[prop] = []
|
|
ElMessage.error(e?.message || '加载可选值失败')
|
|
} finally {
|
|
facetLoadingMap[prop] = false
|
|
}
|
|
}
|
|
|
|
return {
|
|
facetOptionsMap,
|
|
facetLoadingMap,
|
|
enumOptionsFor,
|
|
optionsLoadingFor,
|
|
onFilterOpen,
|
|
isFacetField: (prop: string) => facetFieldSet.has(prop)
|
|
}
|
|
}
|