@happy-table/vue3
Version:
A high-performance Vue 3 table component for B2B systems with TypeScript support
1,556 lines • 307 kB
JavaScript
var Al = Object.defineProperty;
var zl = (l, t, e) => t in l ? Al(l, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : l[t] = e;
var Q = (l, t, e) => zl(l, typeof t != "symbol" ? t + "" : t, e);
import { defineComponent as ce, createElementBlock as N, openBlock as B, createElementVNode as V, toDisplayString as Z, createCommentVNode as te, ref as K, normalizeStyle as _e, normalizeClass as re, createBlock as ue, createVNode as $e, renderSlot as he, computed as T, unref as _, mergeProps as ht, watch as ee, onUnmounted as Ne, nextTick as me, onMounted as xe, withCtx as Ce, withDirectives as ve, vModelSelect as pt, withKeys as nt, vModelText as He, vModelCheckbox as lt, Fragment as we, renderList as Oe, onBeforeUnmount as bn, Teleport as Ol, withModifiers as Bl, reactive as Je, h as ct, vModelDynamic as Vl, toRef as pe, resolveDynamicComponent as Ll, createTextVNode as ut, onScopeDispose as Sn, readonly as Ee, shallowRef as Wl, normalizeProps as ql, guardReactiveProps as Hl } from "vue";
import { Icon as Nl } from "@iconify/vue";
const Kl = { class: "table-error-boundary" }, Ul = { class: "error-content" }, jl = { class: "error-title" }, Yl = { class: "error-message" }, Gl = /* @__PURE__ */ ce({
__name: "TableErrorBoundary",
props: {
error: {},
title: { default: "表格渲染错误" },
retryText: { default: "重试" }
},
emits: ["retry"],
setup(l, { emit: t }) {
const e = t, n = () => {
e("retry");
};
return (a, o) => (B(), N("div", Kl, [
V("div", Ul, [
V("h3", jl, Z(a.title), 1),
V("p", Yl, Z(a.error.message), 1),
V("button", {
class: "error-retry-btn",
onClick: n
}, Z(a.retryText), 1)
])
]));
}
}), de = (l, t) => {
const e = l.__vccOpts || l;
for (const [n, a] of t)
e[n] = a;
return e;
}, Ql = /* @__PURE__ */ de(Gl, [["__scopeId", "data-v-2c488903"]]), Xl = { class: "table-loading" }, Jl = { class: "loading-text" }, Zl = /* @__PURE__ */ ce({
__name: "TableLoadingState",
props: {
loadingText: { default: "加载中..." }
},
setup(l) {
return (t, e) => (B(), N("div", Xl, [
e[0] || (e[0] = V("div", { class: "loading-spinner" }, null, -1)),
V("p", Jl, Z(t.loadingText), 1)
]));
}
}), ea = /* @__PURE__ */ de(Zl, [["__scopeId", "data-v-2d5eba26"]]), ta = {
key: 0,
class: "table-toolbar-placeholder"
}, na = { class: "toolbar-title" }, la = /* @__PURE__ */ ce({
__name: "TableToolbar",
props: {
config: {}
},
setup(l) {
const t = l, e = () => t.config?.title ? typeof t.config.title == "string" ? t.config.title : t.config.title.text || "" : "";
return (n, a) => n.config ? (B(), N("div", ta, [
V("div", na, Z(e()), 1)
])) : te("", !0);
}
}), aa = /* @__PURE__ */ de(la, [["__scopeId", "data-v-9b351fa2"]]), oa = ["data-theme", "tabindex"], ia = {
key: 2,
class: "table-content"
}, sa = /* @__PURE__ */ ce({
__name: "TableContainer",
props: {
config: {},
error: { default: null },
isLoading: { type: Boolean, default: !1 },
containerClasses: {},
containerStyle: {},
currentTheme: {},
isDarkTheme: { type: Boolean },
toolbarConfig: {},
tableWrapperStyle: {},
processedColumns: {},
visibleColumns: {},
isHorizontalVirtualEnabled: { type: Boolean },
processedData: {},
paginationConfig: {},
paginationState: {},
isExcelMode: { type: Function, default: () => !1 }
},
emits: ["retry", "keydown", "keyup"],
setup(l, { expose: t, emit: e }) {
const n = e, a = K(null), o = () => {
n("retry");
}, i = (g) => {
n("keydown", g);
}, v = (g) => {
n("keyup", g);
};
return t({
tableContainer: a
}), (g, d) => (B(), N("div", {
ref_key: "tableContainer",
ref: a,
class: re(["vue-table-container", [
g.containerClasses,
{
dark: g.isDarkTheme,
"table-excel-mode": g.isExcelMode
}
]]),
"data-theme": g.currentTheme,
style: _e(g.containerStyle),
tabindex: g.isExcelMode() ? 0 : -1,
"data-no-password-manager": "true",
"data-form": "false",
"data-1p-ignore": "",
"data-lpignore": "true",
"data-bwignore": "true",
onKeydown: i,
onKeyup: v
}, [
g.error ? (B(), ue(Ql, {
key: 0,
error: g.error,
onRetry: o
}, null, 8, ["error"])) : g.isLoading ? (B(), ue(ea, { key: 1 })) : (B(), N("div", ia, [
$e(aa, { config: g.toolbarConfig }, null, 8, ["config"]),
he(g.$slots, "table-content", {
tableWrapperStyle: g.tableWrapperStyle,
processedColumns: g.processedColumns,
visibleColumns: g.visibleColumns,
isHorizontalVirtualEnabled: g.isHorizontalVirtualEnabled,
processedData: g.processedData,
paginationConfig: g.paginationConfig,
paginationState: g.paginationState
}, void 0, !0),
he(g.$slots, "pagination", {
paginationConfig: g.paginationConfig,
paginationState: g.paginationState
}, void 0, !0)
]))
], 46, oa));
}
}), ra = /* @__PURE__ */ de(sa, [["__scopeId", "data-v-949bbf2e"]]), ca = /* @__PURE__ */ ce({
name: "AppIcon",
inheritAttrs: !1,
__name: "Icon",
props: {
icon: {},
size: { default: "default" },
color: { default: "current" },
class: {}
},
setup(l) {
const t = l, e = {
// 排序图标
"sort-asc": "lucide:arrow-up",
"sort-desc": "lucide:arrow-down",
"sort-both": "lucide:arrow-down-up",
// 分页图标
first: "lucide:chevrons-left",
prev: "lucide:chevron-left",
next: "lucide:chevron-right",
last: "lucide:chevrons-right",
// 通用图标
empty: "lucide:inbox",
expand: "lucide:chevron-right",
collapse: "lucide:chevron-down",
// 主题切换图标
light: "lucide:sun",
dark: "lucide:moon",
auto: "lucide:monitor",
// 工具栏图标
create: "lucide:plus",
edit: "lucide:edit-3",
delete: "lucide:trash-2",
"bulk-delete": "lucide:trash-2",
search: "lucide:search",
filter: "lucide:filter",
"filter-filled": "lucide:funnel-x",
refresh: "lucide:refresh-cw",
settings: "lucide:settings",
export: "lucide:download",
fullscreen: "lucide:maximize",
"fullscreen-exit": "lucide:minimize",
more: "lucide:more-horizontal"
}, n = {
xs: "w-3 h-3",
sm: "w-4 h-4",
default: "w-5 h-5",
md: "w-6 h-6",
lg: "w-7 h-7",
xl: "w-8 h-8",
"2xl": "w-10 h-10"
}, a = T(() => t?.icon?.includes(":") ? t.icon : e[t.icon] || t.icon), o = T(() => {
const v = [];
return typeof t.size == "string" && v.push(n[t.size] || n.default), t.color && t.color !== "current" && v.push(`text-${t.color}`), t.class && v.push(t.class), v.join(" ");
}), i = T(() => {
const v = {};
return typeof t.size == "number" && (v.width = `${t.size}px`, v.height = `${t.size}px`), v;
});
return (v, g) => (B(), ue(_(Nl), ht({
icon: a.value,
class: o.value,
style: i.value
}, v.$attrs), null, 16, ["icon", "class", "style"]));
}
}), qe = /* @__PURE__ */ de(ca, [["__scopeId", "data-v-2713a348"]]);
function hr(l, t, e, n = {}) {
const {
config: a = { enabled: !0, mode: "auto", updateDelay: 50 },
onCascadeUpdate: o,
onCascadeInfoChange: i
} = n, v = K(a.enabled), g = K(null), d = T(() => {
if (!v.value)
return Ze(t.value, l).map((S) => ({
value: S,
label: Rt(S),
count: Tt(t.value, l, S),
available: !0,
disabled: !1
}));
const c = Object.fromEntries(
Object.entries(e.value).filter(([S]) => S !== l)
);
if (Object.keys(c).length === 0)
return Ze(t.value, l).map((u) => ({
value: u,
label: Rt(u),
count: Tt(t.value, l, u),
available: !0,
disabled: !1
}));
const r = Object.entries(c).reduce((S, [u, C]) => ua(S, u, C), t.value), s = Ze(r, l);
return Ze(t.value, l).map((S) => {
const u = s.includes(S);
return {
value: S,
label: Rt(S),
count: Tt(u ? r : t.value, l, S),
available: u,
disabled: !u
};
});
}), w = T(() => {
const c = Ze(t.value, l), s = d.value.filter((u) => u.available).length, p = Object.keys(e.value).filter((u) => u !== l);
return {
total: c.length,
available: s,
filtered: c.length - s,
hasActiveFilters: p.length > 0,
appliedFilters: p
};
}), b = () => {
g.value && clearTimeout(g.value), g.value = setTimeout(() => {
const c = d.value, r = w.value;
o?.(l, c), i?.(l, r), g.value = null;
}, a.updateDelay || 50);
}, h = (c) => {
v.value = c, me(() => {
b();
});
};
ee(
e,
(c, r) => {
const s = Object.keys({ ...c, ...r }).filter(
(p) => p !== l
);
s.length > 0 && s.some((S) => {
const u = c[S], C = r?.[S];
return JSON.stringify(u) !== JSON.stringify(C);
}) && b();
},
{ deep: !0 }
), ee(
t,
() => {
b();
},
{ deep: !0 }
), ee(
w,
(c) => {
i?.(l, c);
},
{ deep: !0 }
);
const f = () => {
g.value && (clearTimeout(g.value), g.value = null);
};
return Ne(f), mt(f), {
availableOptions: d,
cascadeInfo: w,
refreshOptions: b,
enableCascade: h,
isCascadeEnabled: v
};
}
function Ze(l, t) {
return [
...new Set(
l.map((e) => e[t]).filter((e) => e != null)
)
];
}
function Rt(l) {
return l == null ? "(空值)" : typeof l == "boolean" ? l ? "是" : "否" : l instanceof Date ? l.toLocaleDateString() : String(l);
}
function Tt(l, t, e) {
return l.filter((n) => n[t] === e).length;
}
function ua(l, t, e) {
if (!e) return l;
if (Array.isArray(e))
return l.filter((n) => e.includes(n[t]));
if (typeof e == "object" && "operator" in e && "value" in e) {
const { operator: n, value: a, caseSensitive: o } = e;
return l.filter((i) => {
const v = o ? String(i[t]) : String(i[t]).toLowerCase(), g = o ? String(a) : String(a).toLowerCase();
switch (n) {
case "contains":
return v.includes(g);
case "notContains":
return !v.includes(g);
case "equals":
return v === g;
case "notEquals":
return v !== g;
case "startsWith":
return v.startsWith(g);
case "endsWith":
return v.endsWith(g);
default:
return !0;
}
});
}
if (typeof e == "object" && ("min" in e || "max" in e)) {
const { min: n, max: a } = e;
return l.filter((o) => {
const i = parseFloat(o[t]);
return isNaN(i) ? !1 : (n === void 0 || i >= n) && (a === void 0 || i <= a);
});
}
if (typeof e == "object" && ("startDate" in e || "endDate" in e)) {
const { startDate: n, endDate: a } = e;
return l.filter((o) => {
const i = new Date(o[t]);
return isNaN(i.getTime()) ? !1 : (!n || i >= new Date(n)) && (!a || i <= new Date(a));
});
}
if (typeof e == "object" && "value" in e) {
const { value: n } = e;
return n === null ? l : l.filter((a) => !!a[t] == !!n);
}
return l.filter((n) => n[t] === e);
}
class da {
constructor(t = 100) {
Q(this, "updateQueues", /* @__PURE__ */ new Map());
Q(this, "batchTimeout", null);
Q(this, "batchDelay");
this.batchDelay = t;
}
// 添加更新任务到队列
scheduleUpdate(t, e) {
this.updateQueues.has(t) || this.updateQueues.set(t, /* @__PURE__ */ new Set()), this.updateQueues.get(t).add(e), this.batchTimeout || (this.batchTimeout = setTimeout(() => {
this.flushUpdates();
}, this.batchDelay));
}
// 立即刷新指定列的更新
flushColumn(t) {
const e = this.updateQueues.get(t);
e && (e.forEach((n) => {
try {
n();
} catch {
}
}), e.clear());
}
// 刷新所有待更新的列
flushUpdates() {
this.updateQueues.forEach((t, e) => {
this.flushColumn(e);
}), this.updateQueues.clear(), this.batchTimeout && (clearTimeout(this.batchTimeout), this.batchTimeout = null);
}
// 清理所有待更新任务
clear() {
this.updateQueues.clear(), this.batchTimeout && (clearTimeout(this.batchTimeout), this.batchTimeout = null);
}
// 获取待更新的列数量
getPendingCount() {
return this.updateQueues.size;
}
}
const wn = new da(), Mt = /* @__PURE__ */ new Set();
function mt(l) {
Mt.add(l);
}
function sn() {
try {
wn.clear(), Mt.forEach((l) => {
try {
l();
} catch {
}
}), Mt.clear();
} catch {
}
}
function fa() {
typeof window < "u" && (window.addEventListener("beforeunload", sn, { passive: !0 }), window.addEventListener("pagehide", sn, { passive: !0 }), document.addEventListener(
"visibilitychange",
() => {
document.visibilityState === "hidden" && wn.clear();
},
{ passive: !0 }
));
}
typeof window < "u" && !window.process?.env?.NODE_ENV?.includes("test") && fa();
const xn = {
sampleSize: 100,
dateFormats: ["YYYY-MM-DD", "MM/DD/YYYY", "DD/MM/YYYY", "YYYY/MM/DD", "MM-DD-YYYY", "DD-MM-YYYY"],
booleanValues: [
!0,
!1,
"true",
"false",
"True",
"False",
"TRUE",
"FALSE",
1,
0,
"1",
"0",
"yes",
"no",
"Yes",
"No",
"YES",
"NO",
"on",
"off",
"On",
"Off",
"ON",
"OFF",
"是",
"否",
"启用",
"禁用",
"开启",
"关闭"
],
selectThreshold: 10,
// 唯一值少于10个且占比小于80%时识别为选择类型
confidenceThreshold: 0.6
// 最小置信度阈值
}, it = /* @__PURE__ */ new Map();
function ga(l = {}) {
const t = { ...xn, ...l.config }, e = l.cache !== !1, n = (d, w) => a(d, w).type, a = (d, w) => {
if (d.filter && typeof d.filter == "object" && "type" in d.filter && d.filter.type !== "auto")
return {
type: d.filter.type,
confidence: 1,
sampleSize: 0,
reasoning: "显式配置的筛选类型"
};
const b = pa(d.key, w);
if (e && it.has(b))
return it.get(b);
const h = o(d.key, w);
return e && h.confidence >= t.confidenceThreshold && it.set(b, h), h;
}, o = (d, w) => {
const b = va(w, d, t.sampleSize);
if (b.length === 0)
return {
type: "text",
confidence: 0.5,
sampleSize: 0,
reasoning: "无可用数据样本,默认为文本类型"
};
const h = [
ma(b),
Ca(b, t.dateFormats),
// 日期检测优先级高于数字
ya(b),
ba(b, w.length, t.selectThreshold),
Sa(b)
// 文本类型作为兜底
], f = h.filter(
(r) => r.confidence >= t.confidenceThreshold
);
return f.length > 0 ? f.sort((s, p) => p.confidence - s.confidence)[0] : h.sort((r, s) => s.confidence - r.confidence)[0] || {
type: "text",
confidence: 0.5,
sampleSize: b.length,
reasoning: "所有检测结果置信度不足,默认为文本类型"
};
}, i = () => {
it.clear();
}, v = () => ({ ...t }), g = (d) => {
Object.assign(t, d), i();
};
return mt(i), {
detectType: n,
detectWithDetails: a,
analyzeColumn: o,
clearCache: i,
getConfig: v,
updateConfig: g
};
}
function ha(l, t) {
const n = ga().detectType(l, t);
return n && n !== "auto" ? n : "text";
}
function va(l, t, e) {
return l.slice(0, e).map((n) => n[t]).filter((n) => n != null && n !== "");
}
function pa(l, t) {
const e = t.length > 0 ? JSON.stringify(t.slice(0, 10).map((n) => n[l])) : "empty";
return `${l}_${e.length}_${t.length}`;
}
function ma(l) {
if (l.length === 0)
return { type: "boolean", confidence: 0, sampleSize: 0, reasoning: "无样本数据" };
const t = new Set(xn.booleanValues), e = l.filter((a) => t.has(a)).length;
return {
type: "boolean",
confidence: e / l.length,
sampleSize: l.length,
reasoning: `${e}/${l.length} 个值为布尔类型值`
};
}
function ya(l) {
if (l.length === 0)
return { type: "number", confidence: 0, sampleSize: 0, reasoning: "无样本数据" };
const t = l.filter((n) => {
if (typeof n == "number") return !0;
if (typeof n == "string") {
const a = parseFloat(n);
return !isNaN(a) && isFinite(a);
}
return !1;
}).length;
return {
type: "number",
confidence: t / l.length,
sampleSize: l.length,
reasoning: `${t}/${l.length} 个值为数值类型`
};
}
function Ca(l, t) {
if (l.length === 0)
return { type: "date", confidence: 0, sampleSize: 0, reasoning: "无样本数据" };
const e = l.filter((a) => {
if (a instanceof Date) return !isNaN(a.getTime());
if (typeof a == "string") {
if (t.some((i) => wa(a, i))) return !0;
const o = new Date(a);
if (!isNaN(o.getTime()))
return !(/^\d+$/.test(a) || !/[-/\s:]/.test(a));
}
if (typeof a == "number" && a > 9466848e5 && a < 41024448e5) {
const o = new Date(a);
return !isNaN(o.getTime());
}
return !1;
}).length;
return {
type: "date",
confidence: e / l.length,
sampleSize: l.length,
reasoning: `${e}/${l.length} 个值为日期类型`
};
}
function ba(l, t, e) {
if (l.length === 0)
return { type: "select", confidence: 0, sampleSize: 0, reasoning: "无样本数据" };
const a = new Set(l).size, o = a / l.length;
return {
type: "select",
confidence: a <= e && o < 0.8 && // 放宽唯一值比例限制
a > 1 ? Math.min(0.8, 1 - o + (e - a) / e) : 0,
sampleSize: l.length,
reasoning: `唯一值数量: ${a}, 占比: ${(o * 100).toFixed(1)}%, 阈值: ${e}`
};
}
function Sa(l) {
return {
type: "text",
confidence: 0.6,
// 文本作为兜底类型,置信度适中
sampleSize: l.length,
reasoning: "默认文本类型,适用于所有字符串数据"
};
}
function wa(l, t) {
const n = {
"YYYY-MM-DD": /^\d{4}-\d{2}-\d{2}$/,
"MM/DD/YYYY": /^\d{2}\/\d{2}\/\d{4}$/,
"DD/MM/YYYY": /^\d{2}\/\d{2}\/\d{4}$/,
"YYYY/MM/DD": /^\d{4}\/\d{2}\/\d{2}$/,
"MM-DD-YYYY": /^\d{2}-\d{2}-\d{4}$/,
"DD-MM-YYYY": /^\d{2}-\d{2}-\d{4}$/
}[t];
if (!n || !n.test(l)) return !1;
const a = new Date(l);
return !isNaN(a.getTime());
}
function Ke(l, t) {
return t.split(".").reduce((e, n) => e && e[n] !== void 0 ? e[n] : void 0, l);
}
const xa = /[¥$€£,\s]/g;
function Me(l, t = {}) {
const { strict: e = !1, currencyPattern: n = xa } = t;
if (typeof l == "number")
return isNaN(l) ? null : l;
if (e && typeof l != "number")
return null;
if (typeof l == "string") {
const o = l.trim();
if (o === "") return null;
const i = o.replace(n, "").trim();
if (i.match(/^-?\d+(\.\d+)?$/)) {
const g = parseFloat(i);
return isNaN(g) ? null : g;
}
return null;
}
if (l == null)
return null;
const a = Number(l);
return isNaN(a) ? null : a;
}
function ka(l, t, e = {}) {
const { includeNulls: n = !1 } = e, a = [];
for (const o of l) {
const i = Ke(o, t), v = Me(i, e);
v !== null ? a.push(v) : n && i == null && a.push(0);
}
return a;
}
function Ea(l, t, e = {}) {
const n = ka(l, t, e);
if (n.length === 0)
return { min: 0, max: 0, avg: 0 };
const a = Math.min(...n), o = Math.max(...n), i = n.reduce((v, g) => v + g, 0) / n.length;
return { min: a, max: o, avg: i };
}
const Ra = { class: "column-filter-panel" }, Ta = { class: "filter-header" }, Da = { class: "filter-title" }, Fa = { class: "filter-content" }, Ma = { class: "filter-actions" }, Pa = { class: "preview-info" }, $a = {
key: 0,
class: "preview-count"
}, Ia = { class: "action-buttons" }, _a = ["disabled"], Aa = ["disabled"], za = /* @__PURE__ */ ce({
__name: "BaseColumnFilter",
props: {
column: {},
value: {},
cascadeEnabled: { type: Boolean, default: !0 },
totalRecordsCount: { default: 0 },
previewCount: { default: null },
canApply: { type: Boolean, default: !0 }
},
emits: ["apply", "close", "reset"],
setup(l, { emit: t }) {
const e = l, n = t, a = T(() => e.value !== null && e.value !== void 0), o = T(() => !!e.canApply), i = () => {
n("reset");
}, v = () => {
n("apply", e.value);
};
return (g, d) => (B(), N("div", Ra, [
V("div", Ta, [
V("h4", Da, Z(g.column.title), 1),
he(g.$slots, "header-extra", {}, void 0, !0),
V("button", {
class: "close-btn",
title: "关闭",
onClick: d[0] || (d[0] = (w) => g.$emit("close"))
}, " × ")
]),
V("div", Fa, [
he(g.$slots, "default", {}, void 0, !0)
]),
V("div", Ma, [
V("div", Pa, [
g.previewCount !== null ? (B(), N("span", $a, Z(g.previewCount) + " 条记录 ", 1)) : te("", !0)
]),
V("div", Ia, [
V("button", {
class: "reset-btn",
disabled: !a.value,
onClick: i
}, " 重置 ", 8, _a),
V("button", {
class: "apply-btn",
disabled: !o.value,
onClick: v
}, " 应用 ", 8, Aa)
])
])
]));
}
}), at = /* @__PURE__ */ de(za, [["__scopeId", "data-v-17fee5eb"]]), Oa = { class: "main-filter-row" }, Ba = ["placeholder"], Va = {
key: 0,
class: "preview-count ultra-compact"
}, La = { class: "auxiliary-row" }, Wa = { class: "case-option" }, qa = /* @__PURE__ */ ce({
__name: "TextColumnFilter",
props: {
config: { default: () => ({
operators: ["contains", "notContains", "equals", "notEquals", "startsWith", "endsWith"],
caseSensitive: !1
}) },
column: {},
value: {},
availableOptions: {},
onPreview: {}
},
emits: ["apply", "preview", "close"],
setup(l, { emit: t }) {
const e = l, n = t, a = K(), o = K({
operator: "contains",
value: "",
caseSensitive: e.config?.caseSensitive || !1
}), i = K(null), v = T(() => o.value.value.trim().length > 0), g = () => {
const r = e.column.title || "内容";
switch (o.value.operator) {
case "contains":
case "notContains":
return `输入要包含的${r}...`;
case "equals":
case "notEquals":
return `输入完整的${r}...`;
case "startsWith":
return `输入${r}开头...`;
case "endsWith":
return `输入${r}结尾...`;
default:
return `请输入${r}...`;
}
}, d = () => {
h();
}, w = () => {
h();
}, b = () => {
h();
}, h = () => {
try {
if (!v.value) {
i.value = null;
return;
}
const r = { ...o.value };
e.onPreview && (i.value = e.onPreview(r)), n("preview", r);
} catch {
i.value = null;
}
}, f = () => {
try {
if (!v.value) return;
const r = { ...o.value };
n("apply", r);
} catch {
}
}, c = () => {
try {
o.value = {
operator: "contains",
value: "",
caseSensitive: e.config?.caseSensitive || !1
}, i.value = null, n("apply", null);
} catch {
}
};
return xe(async () => {
try {
if (e.value && typeof e.value == "object" && "operator" in e.value) {
const r = e.value;
o.value = { ...r }, h();
}
await me(), a.value && a.value.focus();
} catch {
}
}), ee(
() => e.value,
(r) => {
try {
if (r && typeof r == "object" && "operator" in r) {
const s = r;
o.value = { ...s }, h();
} else r || (o.value = {
operator: "contains",
value: "",
caseSensitive: e.config?.caseSensitive || !1
}, i.value = null);
} catch {
}
},
{ deep: !0, immediate: !1 }
), (r, s) => (B(), ue(at, {
class: "text-filter-panel ultra-compact",
column: r.column,
value: o.value,
"can-apply": v.value,
onClose: s[3] || (s[3] = (p) => r.$emit("close")),
onReset: c,
onApply: f
}, {
default: Ce(() => [
V("div", Oa, [
ve(V("select", {
"onUpdate:modelValue": s[0] || (s[0] = (p) => o.value.operator = p),
class: "operator-select ultra-compact",
onChange: d
}, [...s[4] || (s[4] = [
V("option", { value: "contains" }, "包含", -1),
V("option", { value: "notContains" }, "不包含", -1),
V("option", { value: "equals" }, "等于", -1),
V("option", { value: "notEquals" }, "不等于", -1),
V("option", { value: "startsWith" }, "开头", -1),
V("option", { value: "endsWith" }, "结尾", -1)
])], 544), [
[pt, o.value.operator]
]),
ve(V("input", {
ref_key: "inputRef",
ref: a,
"onUpdate:modelValue": s[1] || (s[1] = (p) => o.value.value = p),
type: "text",
placeholder: g(),
class: "filter-input ultra-compact",
onInput: w,
onKeyup: nt(f, ["enter"])
}, null, 40, Ba), [
[He, o.value.value]
]),
i.value !== null ? (B(), N("div", Va, Z(i.value), 1)) : te("", !0)
]),
V("div", La, [
V("label", Wa, [
ve(V("input", {
"onUpdate:modelValue": s[2] || (s[2] = (p) => o.value.caseSensitive = p),
type: "checkbox",
class: "case-checkbox",
onChange: b
}, null, 544), [
[lt, o.value.caseSensitive]
]),
s[5] || (s[5] = V("span", { class: "case-label" }, "Aa", -1))
])
])
]),
_: 1
}, 8, ["column", "value", "can-apply"]));
}
}), Ha = /* @__PURE__ */ de(qa, [["__scopeId", "data-v-fb937b9b"]]), Na = { class: "mode-tabs" }, Ka = {
key: 0,
class: "filter-main compact"
}, Ua = ["step"], ja = {
key: 0,
class: "preview-count compact"
}, Ya = {
key: 1,
class: "filter-main compact"
}, Ga = ["step"], Qa = ["step"], Xa = {
key: 0,
class: "preview-count compact"
}, Ja = {
key: 2,
class: "filter-options-row"
}, Za = {
key: 0,
class: "quick-filters compact"
}, eo = ["title", "onClick"], to = {
key: 1,
class: "data-range-info compact"
}, no = /* @__PURE__ */ ce({
__name: "NumberColumnFilter",
props: {
config: { default: () => ({
mode: "both",
quickFilters: ["top10%", "bottom10%", "aboveAvg", "belowAvg"],
precision: 2
}) },
dataRange: {},
calculateDataRange: {},
column: {},
value: {},
availableOptions: {},
onPreview: {}
},
emits: ["apply", "preview", "close"],
setup(l, { emit: t }) {
const e = l, n = t, a = K({
mode: "range",
precision: e.config?.precision || 2
}), o = K(null), i = K({
min: 0,
max: 0,
avg: 0
}), v = T(() => a.value.mode === "compare" ? a.value.compareValue !== void 0 && a.value.compareValue !== null && typeof a.value.operator == "string" && a.value.operator.length > 0 : a.value.minValue !== void 0 && a.value.minValue !== null || a.value.maxValue !== void 0 && a.value.maxValue !== null), g = T(() => e.config?.quickFilters && e.config.quickFilters.length > 0 && i.value && (i.value.min !== 0 || i.value.max !== 0)), d = T(() => {
if (!e.config?.quickFilters || !i.value) return [];
const C = [];
return e.config.quickFilters.includes("top10%") && C.push({
key: "top10%",
label: "Top 10%",
description: "最高的 10% 数值",
apply: (m) => ({
mode: "range",
minValue: b(m.min + (m.max - m.min) * 0.9),
maxValue: b(m.max)
})
}), e.config.quickFilters.includes("bottom10%") && C.push({
key: "bottom10%",
label: "Bottom 10%",
description: "最低的 10% 数值",
apply: (m) => ({
mode: "range",
minValue: b(m.min),
maxValue: b(m.min + (m.max - m.min) * 0.1)
})
}), e.config.quickFilters.includes("aboveAvg") && C.push({
key: "aboveAvg",
label: "平均值以上",
description: "大于平均值的数据",
apply: (m) => ({
mode: "compare",
operator: ">=",
compareValue: b(m.avg)
})
}), e.config.quickFilters.includes("belowAvg") && C.push({
key: "belowAvg",
label: "平均值以下",
description: "小于平均值的数据",
apply: (m) => ({
mode: "compare",
operator: "<",
compareValue: b(m.avg)
})
}), C;
}), w = () => {
const C = a.value.precision || 2;
return C === 0 ? 1 : (1 / Math.pow(10, C)).toString();
}, b = (C) => {
const m = a.value.precision || 2;
return m === 0 ? Math.round(C) : Number(C.toFixed(m));
}, h = (C) => {
const m = a.value.precision || 2;
return e.config?.format ? new Intl.NumberFormat("zh-CN", e.config.format).format(C) : C.toFixed(m);
}, f = (C) => {
a.value.mode = C, C === "range" ? (a.value.operator = void 0, a.value.compareValue = void 0) : (a.value.minValue = void 0, a.value.maxValue = void 0, a.value.operator || (a.value.operator = ">")), r();
}, c = () => {
r();
}, r = () => {
if (!v.value) {
o.value = null;
return;
}
const C = { ...a.value };
e.onPreview && (o.value = e.onPreview(C)), n("preview", C);
}, s = () => {
if (!v.value) return;
const C = { ...a.value };
n("apply", C);
}, p = () => {
a.value = {
mode: "range",
precision: e.config?.precision || 2
}, o.value = null, n("apply", null);
}, S = () => {
if (e.calculateDataRange)
try {
i.value = e.calculateDataRange();
return;
} catch {
}
if (e.dataRange && (e.dataRange.min !== 0 || e.dataRange.max !== 0 || e.dataRange.avg !== 0)) {
i.value = { ...e.dataRange };
return;
}
i.value = {
min: 5e3,
max: 15e3,
avg: 1e4
};
}, u = (C) => {
const m = i.value;
if (m.min === 0 && m.max === 0 && m.avg === 0)
return;
const R = C.apply(m);
a.value = {
...a.value,
...R
}, r();
};
return xe(() => {
if (S(), e.value && typeof e.value == "object") {
const C = e.value;
a.value = { ...a.value, ...C }, r();
}
a.value.mode === "compare" && !a.value.operator && (a.value.operator = ">");
}), (C, m) => (B(), ue(at, {
class: "number-filter-panel compact",
column: C.column,
value: a.value,
"can-apply": v.value,
onClose: m[6] || (m[6] = (R) => C.$emit("close")),
onReset: p,
onApply: s
}, {
"header-extra": Ce(() => [
V("div", Na, [
V("button", {
class: re(["mode-tab", { active: a.value.mode === "range" }]),
onClick: m[0] || (m[0] = (R) => f("range"))
}, " 范围 ", 2),
V("button", {
class: re(["mode-tab", { active: a.value.mode === "compare" }]),
onClick: m[1] || (m[1] = (R) => f("compare"))
}, " 条件 ", 2)
])
]),
default: Ce(() => [
a.value.mode === "compare" ? (B(), N("div", Ka, [
ve(V("select", {
"onUpdate:modelValue": m[2] || (m[2] = (R) => a.value.operator = R),
class: "operator-select compact",
onChange: c
}, [...m[7] || (m[7] = [
V("option", { value: ">" }, ">", -1),
V("option", { value: "<" }, "<", -1),
V("option", { value: "=" }, "=", -1),
V("option", { value: "!=" }, "≠", -1),
V("option", { value: ">=" }, ">=", -1),
V("option", { value: "<=" }, "<=", -1)
])], 544), [
[pt, a.value.operator]
]),
ve(V("input", {
"onUpdate:modelValue": m[3] || (m[3] = (R) => a.value.compareValue = R),
type: "number",
step: w(),
class: "number-input compact",
placeholder: "输入数值",
onInput: c,
onKeyup: nt(s, ["enter"])
}, null, 40, Ua), [
[
He,
a.value.compareValue,
void 0,
{ number: !0 }
]
]),
o.value !== null ? (B(), N("div", ja, Z(o.value) + " 条 ", 1)) : te("", !0)
])) : te("", !0),
a.value.mode === "range" ? (B(), N("div", Ya, [
ve(V("input", {
"onUpdate:modelValue": m[4] || (m[4] = (R) => a.value.minValue = R),
type: "number",
step: w(),
class: "number-input compact range-input",
placeholder: "最小值",
onInput: c,
onKeyup: nt(s, ["enter"])
}, null, 40, Ga), [
[
He,
a.value.minValue,
void 0,
{ number: !0 }
]
]),
m[8] || (m[8] = V("span", { class: "range-separator" }, "-", -1)),
ve(V("input", {
"onUpdate:modelValue": m[5] || (m[5] = (R) => a.value.maxValue = R),
type: "number",
step: w(),
class: "number-input compact range-input",
placeholder: "最大值",
onInput: c,
onKeyup: nt(s, ["enter"])
}, null, 40, Qa), [
[
He,
a.value.maxValue,
void 0,
{ number: !0 }
]
]),
o.value !== null ? (B(), N("div", Xa, Z(o.value) + " 条 ", 1)) : te("", !0)
])) : te("", !0),
g.value || C.dataRange ? (B(), N("div", Ja, [
g.value && d.value.length > 0 ? (B(), N("div", Za, [
(B(!0), N(we, null, Oe(d.value, (R) => (B(), N("button", {
key: R.key,
class: "quick-filter-btn compact",
title: R.description,
onClick: (P) => u(R)
}, Z(R.label), 9, eo))), 128))
])) : te("", !0),
i.value && (i.value.min !== 0 || i.value.max !== 0) ? (B(), N("div", to, " 范围: " + Z(h(i.value.min)) + " - " + Z(h(i.value.max)), 1)) : te("", !0)
])) : te("", !0)
]),
_: 1
}, 8, ["column", "value", "can-apply"]));
}
}), lo = /* @__PURE__ */ de(no, [["__scopeId", "data-v-fb632363"]]), ao = {
key: 0,
class: "quick-section"
}, oo = { class: "quick-options compact" }, io = ["onClick"], so = { class: "date-range-row" }, ro = {
key: 0,
class: "preview-count compact"
}, co = {
key: 1,
class: "relative-options-row"
}, uo = { class: "checkbox-option compact" }, fo = { class: "checkbox-option compact" }, go = { class: "checkbox-option compact" }, ho = {
key: 2,
class: "date-range-display compact"
}, vo = /* @__PURE__ */ ce({
__name: "DateColumnFilter",
props: {
config: { default: () => ({
quickOptions: ["today", "yesterday", "thisWeek", "thisMonth", "last7days", "last30days"],
relative: !0
}) },
column: {},
value: {},
availableOptions: {},
onPreview: {}
},
emits: ["apply", "preview", "close"],
setup(l, { emit: t }) {
const e = l, n = t, a = K({
includeToday: !1,
weekdaysOnly: !1,
weekendsOnly: !1
}), o = K(null), i = T(() => !!(a.value.startDate || a.value.endDate)), v = T(() => e.config?.quickOptions && e.config.quickOptions.length > 0), g = T(() => {
if (!e.config?.quickOptions) return [];
const u = /* @__PURE__ */ new Date(), C = [];
if (e.config.quickOptions.includes("today") && C.push({
key: "today",
label: "今天",
description: "今天的数据",
apply: () => ({
startDate: d(u),
endDate: d(u)
})
}), e.config.quickOptions.includes("yesterday")) {
const m = new Date(u);
m.setDate(u.getDate() - 1), C.push({
key: "yesterday",
label: "昨天",
description: "昨天的数据",
apply: () => ({
startDate: d(m),
endDate: d(m)
})
});
}
if (e.config.quickOptions.includes("thisWeek")) {
const m = new Date(u), R = u.getDay(), P = u.getDate() - R + (R === 0 ? -6 : 1);
m.setDate(P), C.push({
key: "thisWeek",
label: "本周",
description: "本周的数据",
apply: () => ({
startDate: d(m),
endDate: d(u)
})
});
}
if (e.config.quickOptions.includes("thisMonth")) {
const m = new Date(u.getFullYear(), u.getMonth(), 1);
C.push({
key: "thisMonth",
label: "本月",
description: "本月的数据",
apply: () => ({
startDate: d(m),
endDate: d(u)
})
});
}
if (e.config.quickOptions.includes("last7days")) {
const m = new Date(u);
m.setDate(u.getDate() - 7), C.push({
key: "last7days",
label: "过去7天",
description: "过去7天的数据",
apply: () => ({
startDate: d(m),
endDate: d(u)
})
});
}
if (e.config.quickOptions.includes("last30days")) {
const m = new Date(u);
m.setDate(u.getDate() - 30), C.push({
key: "last30days",
label: "过去30天",
description: "过去30天的数据",
apply: () => ({
startDate: d(m),
endDate: d(u)
})
});
}
if (e.config.quickOptions.includes("thisQuarter")) {
const m = Math.floor(u.getMonth() / 3), R = new Date(u.getFullYear(), m * 3, 1);
C.push({
key: "thisQuarter",
label: "本季度",
description: "本季度的数据",
apply: () => ({
startDate: d(R),
endDate: d(u)
})
});
}
if (e.config.quickOptions.includes("thisYear")) {
const m = new Date(u.getFullYear(), 0, 1);
C.push({
key: "thisYear",
label: "今年",
description: "今年的数据",
apply: () => ({
startDate: d(m),
endDate: d(u)
})
});
}
return C;
}), d = (u) => u.toISOString().split("T")[0], w = (u) => {
if (!u) return "";
const C = typeof u == "string" ? new Date(u) : u;
return e.config?.format ? new Intl.DateTimeFormat("zh-CN", e.config.format).format(C) : C.toLocaleDateString("zh-CN");
}, b = () => {
const { startDate: u, endDate: C } = a.value;
return u && C ? u === C ? w(u) : `${w(u)} - ${w(C)}` : u ? `从 ${w(u)}` : C ? `到 ${w(C)}` : "";
}, h = (u) => a.value.quickOption === u.key, f = () => {
a.value.quickOption = void 0, r();
}, c = () => {
a.value.weekdaysOnly && a.value.weekendsOnly && (a.value.weekdaysOnly ? a.value.weekendsOnly = !1 : a.value.weekdaysOnly = !1), r();
}, r = () => {
if (!i.value) {
o.value = null;
return;
}
const u = { ...a.value };
e.onPreview && (o.value = e.onPreview(u)), n("preview", u);
}, s = () => {
if (!i.value) return;
const u = { ...a.value };
n("apply", u);
}, p = () => {
a.value = {
includeToday: !1,
weekdaysOnly: !1,
weekendsOnly: !1
}, o.value = null, n("apply", null);
}, S = (u) => {
const C = u.apply();
a.value = {
...a.value,
...C,
quickOption: u.key
}, r();
};
return xe(() => {
if (e.value && typeof e.value == "object") {
const u = e.value;
a.value = { ...a.value, ...u }, r();
}
}), (u, C) => (B(), ue(at, {
class: "date-filter-panel compact",
column: u.column,
value: a.value,
"can-apply": i.value,
onClose: C[5] || (C[5] = (m) => u.$emit("close")),
onReset: p,
onApply: s
}, {
default: Ce(() => [
v.value ? (B(), N("div", ao, [
V("div", oo, [
(B(!0), N(we, null, Oe(g.value, (m) => (B(), N("button", {
key: m.key,
class: re(["quick-option-btn compact", { active: h(m) }]),
onClick: (R) => S(m)
}, Z(m.label), 11, io))), 128))
])
])) : te("", !0),
V("div", so, [
ve(V("input", {
"onUpdate:modelValue": C[0] || (C[0] = (m) => a.value.startDate = m),
type: "date",
class: "date-input compact",
placeholder: "开始日期",
onChange: f
}, null, 544), [
[He, a.value.startDate]
]),
C[6] || (C[6] = V("span", { class: "date-separator" }, "-", -1)),
ve(V("input", {
"onUpdate:modelValue": C[1] || (C[1] = (m) => a.value.endDate = m),
type: "date",
class: "date-input compact",
placeholder: "结束日期",
onChange: f
}, null, 544), [
[He, a.value.endDate]
]),
o.value !== null ? (B(), N("div", ro, Z(o.value) + " 条 ", 1)) : te("", !0)
]),
u.config?.relative ? (B(), N("div", co, [
V("label", uo, [
ve(V("input", {
"onUpdate:modelValue": C[2] || (C[2] = (m) => a.value.includeToday = m),
type: "checkbox",
onChange: c
}, null, 544), [
[lt, a.value.includeToday]
]),
C[7] || (C[7] = V("span", null, "含今天", -1))
]),
V("label", fo, [
ve(V("input", {
"onUpdate:modelValue": C[3] || (C[3] = (m) => a.value.weekdaysOnly = m),
type: "checkbox",
onChange: c
}, null, 544), [
[lt, a.value.weekdaysOnly]
]),
C[8] || (C[8] = V("span", null, "工作日", -1))
]),
V("label", go, [
ve(V("input", {
"onUpdate:modelValue": C[4] || (C[4] = (m) => a.value.weekendsOnly = m),
type: "checkbox",
onChange: c
}, null, 544), [
[lt, a.value.weekendsOnly]
]),
C[9] || (C[9] = V("span", null, "周末", -1))
])
])) : te("", !0),
a.value.startDate || a.value.endDate ? (B(), N("div", ho, Z(b()), 1)) : te("", !0)
]),
_: 1
}, 8, ["column", "value", "can-apply"]));
}
}), po = /* @__PURE__ */ de(vo, [["__scopeId", "data-v-61f6da0d"]]), mo = { class: "boolean-options-row" }, yo = {
key: 0,
class: "stats-row"
}, Co = { class: "stat-item" }, bo = { class: "stat-item" }, So = /* @__PURE__ */ ce({
__name: "BooleanColumnFilter",
props: {
config: { default: () => ({
labels: ["是", "否"],
showStats: !0
}) },
statistics: {},
column: {},
value: {},
availableOptions: {},
onPreview: {}
},
emits: ["apply", "preview", "close"],
setup(l, { emit: t }) {
const e = l, n = t, a = K({
value: null
}), o = K(null), i = T(() => e.config?.showStats !== !1 && e.statistics), v = T(() => !0), g = () => e.config?.labels?.[0] || "是", d = () => e.config?.labels?.[1] || "否", w = (c) => {
a.value.value = c, b();
}, b = () => {
const c = a.value.value === null ? null : { ...a.value };
e.onPreview && (o.value = e.onPreview(c)), n("preview", c);
}, h = () => {
const c = a.value.value === null ? null : { ...a.value };
n("apply", c);
}, f = () => {
a.value = { value: null }, o.value = null, n("apply", null);
};
return xe(() => {
if (e.value && typeof e.value == "object" && "value" in e.value) {
const c = e.value;
a.value = { ...c }, b();
}
b();
}), (c, r) => (B(), ue(at, {
column: c.column,
value: a.value,
"preview-count": o.value,
"can-apply": v.value,
onClose: r[3] || (r[3] = (s) => c.$emit("close")),
onReset: f,
onApply: h
}, {
default: Ce(() => [
V("div", mo, [
V("button", {
class: re(["boolean-option-btn", { active: a.value.value === null }]),
onClick: r[0] || (r[0] = (s) => w(null))
}, " 全部 ", 2),
V("button", {
class: re(["boolean-option-btn", { active: a.value.value === !0 }]),
onClick: r[1] || (r[1] = (s) => w(!0))
}, Z(g()), 3),
V("button", {
class: re(["boolean-option-btn", { active: a.value.value === !1 }]),
onClick: r[2] || (r[2] = (s) => w(!1))
}, Z(d()), 3)
]),
i.value && c.statistics ? (B(), N("div", yo, [
V("span", Co, Z(g()) + ": " + Z(c.statistics.trueCount) + "条 (" + Z(c.statistics.truePercentage) + "%) ", 1),
r[4] || (r[4] = V("span", { class: "stat-separator" }, "|", -1)),
V("span", bo, Z(d()) + ": " + Z(c.statistics.falseCount) + "条 (" + Z(c.statistics.falsePercentage) + "%) ", 1)
])) : te("", !0)
]),
_: 1
}, 8, ["column", "value", "preview-count", "can-apply"]));
}
}), wo = /* @__PURE__ */ de(So, [["__scopeId", "data-v-1c51fc74"]]), xo = {
key: 0,
class: "search-input-compact"
}, ko = ["placeholder"], Eo = {
key: 0,
class: "cascade-hint compact"
}, Ro = { class: "quick-actions-row" }, To = { class: "selection-count" }, Do = ["value", "disabled"], Fo = { class: "option-label" }, Mo = {
key: 0,
class: "option-count compact"
}, Po = {
key: 0,
class: "empty-state compact"
}, $o = {
key: 1,
class: "cascade-status compact"
}, Io = /* @__PURE__ */ ce({
__name: "SelectColumnFilter",
props: {
cascadeEnabled: { type: Boolean, default: !0 },
totalRecordsCount: { default: 0 },
config: { default: () => ({
search: !0,
quickActions: !0,
maxHeight: 300
}) },
availableOptions: { default: () => [] },
cascadeInfo: {},
column: {},
value: {},
onPreview: {}
},
emits: ["apply", "preview", "close"],
setup(l, { emit: t }) {
const e = l, n = t, a = K([]), o = K(""), i = K(null), v = T(() => e.config?.search !== !1), g = T(() => e.cascadeEnabled), d = T(() => e.config?.maxHeight || 300), w = T(() => `在${e.column.title}中搜索...`), b = T(() => e.cascadeEnabled && e.cascadeInfo && e.cascadeInfo.hasActiveFilters && e.cascadeInfo.appliedFilters.length > 0), h = T(() => {
let m = e.availableOptions || [];
if (o.value.trim()) {
const R = o.value.toLowerCase();
m = m.filter((P) => P.label.toLowerCase().includes(R));
}
return m.sort((R, P) => e.cascadeEnabled && R.available !== P.available ? R.available ? -1 : 1 : R.label.localeCompare(P.label));
}), f = () => {
}, c = () => {
o.value = "";
}, r = () => {
const m = h.value.filter((R) => R.available !== !1 && !R.disabled).map((R) => R.value);
a.value = [.../* @__PURE__ */ new Set([...a.value, ...m])], p();
}, s = () => {
a.value = [], p();
}, p = () => {
S();
}, S = () => {
const m = a.value.length > 0 ? a.value : null;
e.onPreview && (i.value = e.onPreview(m)), n("preview", m);
}, u = () => {
const m = a.value.length > 0 ? [...a.value] : null;
n("apply", m);
}, C = () => {
a.value = [], i.value = null, o.value = "", n("apply", null);
};
return ee(
() => e.availableOptions,
() => {
if (e.cascadeEnabled && a.value.length > 0) {
const m = new Set(
(e.availableOptions || []).filter((P) => P.available !== !1).map((P) => P.value)
), R = a.value.filter((P) => m.has(P));
R.length !== a.value.length && (a.value = R, S());
}
},
{ deep: !0 }
), xe(() => {
e.value && Array.isArray(e.value) && (a.value = [...e.value], S()), (!e.value || Array.isArray(e.value) && e.value.length === 0) && S();
}), (m, R) => (B(), ue(at, {
class: "select-filter-panel compact",
column: m.column,
value: a.value,
onClose: R[2] || (R[2] = (P) => m.$emit("close")),
onReset: C,
onApply: u
}, {
"header-extra": Ce(() => [
v.value ? (B(), N("div", xo, [
ve(V("input", {
"onUpdate:modelValue": R[0] || (R[0] = (P) => o.value = P),
type: "text",
placeholder: w.value,
class: "search-input",
onInput: f
}, null, 40, ko), [
[He, o.value]
]),
o.value ? (B(), N("button", {
key: 0,
class: "clear-search-btn",
onClick: c
}, " × ")) : te("", !0)
])) : te("", !0)
]),
default: Ce(() => [
b.value ? (B(), N("div", Eo, " 📊 共 " + Z(m.totalRecordsCount) + " 条," + Z(m.cascadeInfo?.appliedFilters.length || 0) + " 个筛选生效 ", 1)) : te("", !0),
V("div", Ro, [
V("div", { class: "quick-actions compact" }, [
V("button", {
class: "quick-action-btn compact",
onClick: r
}, " 全选 "),
V("button", {
class: "quick-action-btn compact",
onClick: s
}, " 清除 ")
]),
V("div", To, Z(a.value.length) + "/" + Z(h.value.length), 1)
]),
V("div", {
class: "options-list compact",
style: _e({ maxHeight: d.value + "px" })
}, [
(B(!0), N(we, null, Oe(h.value, (P) => (B(), N("label", {
key: String(P.value),
class: re(["option-item compact", {
disabled: P.disabled,
unavailable: !P.available && m.cascadeEnabled
}])
}, [
ve(V("input", {
"onUpdate:modelValue": R[1] || (R[1] = (M) => a.value = M),
type: "checkbox",
value: P.value,
disabled: P.disabled,
class: "option-checkbox",
onChange: p
}, null, 40, Do), [
[lt, a.value]
]),
V("span", Fo, Z(P.label), 1),
g.value && P.count !== void 0 ? (B(), N("span", Mo, Z(P.count), 1)) : te("", !0)
], 2))), 128)),
h.value.length === 0 ? (B(), N("div", Po, " 🔍 " + Z(o.value ? "无匹配项" : "无可用选项"), 1)) : te("", !0)
], 4),
m.cascadeInfo && m.cascadeInfo.hasActiveFilters ? (B(), N("div", $o, " 可用: " + Z(m.cascadeInfo.available) + "/"