/** * 列头动态 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 /** 非 facet 的静态 enum(字典等)回退;亦用于剥离本列 query 键 */ columnFilterDefs?: ColumnFilterDef[] /** 当前列表查询上下文(固定条件 + 顶部筛选 + 列头);打开漏斗时会排除本列键 */ getContextParams?: () => Record limit?: number }) { const facetFieldSet = new Set(options.facetFields) const facetOptionsMap = reactive>({}) const facetLoadingMap = reactive>({}) 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) } }