UNPKG

@farris/ui-vue

Version:

Farris Vue, a Farris Design based Vue3 component library.

675 lines (674 loc) 18.4 kB
import { withInstall as U } from "../common/index.esm.js"; import { defineComponent as j, ref as c, watch as w, inject as W, computed as I, onMounted as q, createVNode as T } from "vue"; import { debounce as z, cloneDeep as O } from "lodash-es"; import G from "../button-edit/index.esm.js"; import { resolveAppearance as _, createPropsResolver as J } from "../dynamic-resolver/index.esm.js"; import K from "../tree-view/index.esm.js"; import { FInputGroup as Q } from "../input-group/index.esm.js"; const X = /* @__PURE__ */ new Map([ ["appearance", _] ]), Y = "https://json-schema.org/draft/2020-12/schema", Z = "https://farris-design.gitee.io/combo-list.schema.json", ee = "combo-tree", te = "A Farris Input Component", ae = "object", le = { id: { description: "The unique identifier for a combo list", type: "string" }, type: { description: "The type string of number combo list component", type: "string", default: "combo-tree" }, appearance: { description: "", type: "object", properties: { class: { type: "string" }, style: { type: "string" } }, default: {} }, binding: { description: "", type: "object", default: {} }, editable: { description: "", type: "boolean", default: !0 }, enableLinkLabel: { description: "", type: "boolean", default: !1 }, label: { description: "", type: "string", default: "" }, lableWidth: { description: "", type: "number" }, placeholder: { description: "", type: "string", default: "" }, valueField: { description: "", type: "string", default: "id" }, titleField: { description: "", type: "string", default: "name" }, textField: { description: "", type: "string", default: "name" }, data: { description: "", type: "array" }, readonly: { description: "", type: "boolean", default: !1 }, required: { description: "", type: "boolean", default: !1 }, tabindex: { description: "", type: "number", default: -1 }, textAlign: { description: "", type: "string", enum: [ "left", "middle", "right" ], default: "left" }, visible: { description: "", type: "boolean", default: !0 }, onBlur: { description: "", type: "string", default: "" }, onClickLinkLabel: { description: "", type: "string", default: "" }, formatter: { type: "object", default: null }, customRowStatus: { type: "object", default: null }, minPanelWidth: { description: "", type: "number", default: 160 }, idField: { description: "", type: "string", default: "id" }, multiSelect: { description: "", type: "boolean", default: !1 }, viewType: { description: "", type: "string", default: "text" }, searchFields: { description: "", type: "array", default: [] }, enableSearch: { description: "", type: "boolean", default: !1 }, displayFormatter: { type: "object", default: null }, enableClear: { description: "", type: "boolean", default: !0 } }, ne = [ "id", "type" ], ie = { $schema: Y, $id: Z, title: ee, description: te, type: ae, properties: le, required: ne }; function oe(e, r, s) { return r; } var ue = /* @__PURE__ */ ((e) => (e.Text = "text", e.Tag = "tag", e))(ue || {}), de = /* @__PURE__ */ ((e) => (e.top = "top", e.bottom = "bottom", e.auto = "auto", e))(de || {}); const k = { /** * 组件标识 */ id: { type: String }, /** * 下拉数据源 */ data: { type: Array, default: [] }, /** * 可选,展示文本 * 默认为空字符串 */ displayText: { type: String, default: "" }, /** * 可选,是否禁用 * 默认为`false` */ disabled: { type: Boolean, default: !1 }, /** * 可选,下拉图标 * 默认为'<span class="f-icon f-icon-arrow-60-down"></span>' */ dropDownIcon: { type: String, default: '<span class="f-icon f-icon-arrow-chevron-down"></span>' }, /** * 可选,是否可编辑 * 默认`false` */ editable: { type: Boolean, default: !1 }, /** * 可选,是否启用清空 * 默认启用 */ enableClear: { type: Boolean, default: !0 }, /** * 可选,启用搜索 * 默认为`false` */ enableSearch: { type: Boolean, default: !1 }, /** * 可选,鼠标悬停时是否显示控件值 * 默认显示 */ enableTitle: { type: Boolean, default: !0 }, fitEditor: { type: Boolean, default: !1 }, /** * 可选,强制显示占位符 * 默认`false` */ forcePlaceholder: { type: Boolean, default: !1 }, /** * 可选,清空值时隐藏面板 * 默认`true` */ hidePanelOnClear: { type: Boolean, default: !0 }, /** * 可选,数据源id字段 * 默认为`id` */ idField: { type: String, default: "id" }, /** * 可选,字段映射 */ mapFields: { type: Object }, /** * 可选,最大高度 * 默认`350` */ maxHeight: { type: Number, default: 350 }, /** * 最大输入长度 */ maxLength: { type: Number }, /** * 可选,是否支持多选 * 默认`false` */ multiSelect: { type: Boolean, default: !1 }, /** * 绑定值 */ modelValue: { type: String, default: "" }, /** * 占位符 */ placeholder: { type: String }, /** * 可选,下拉面板展示位置 * 默认为`auto` */ placement: { type: String, default: "auto" /* auto */ }, /** * 可选,是否只读 * 默认为`false` */ readonly: { type: Boolean, default: !1 }, /** * 可选,是否支持远端过滤 * 默认`false` */ remoteSearch: { type: Boolean, default: !1 }, /** * 可选,分隔符 * 默认`,` */ separator: { type: String, default: "," }, /** * tabIndex */ tabIndex: { type: Number, default: -1 }, /** * 可选,数据源显示字段 * 默认为`name` */ textField: { type: String, default: "name" }, /** * 可选,数据源的title * 默认为`name` */ titleField: { type: String, default: "name" }, /** * 可选,数据源值字段 * 默认为`id` */ valueField: { type: String, default: "id" }, /** * 可选,下拉列表值展示方式 * 支持text | tag,即文本或标签,默认为`ViewType.Text`,即文本方式`text` */ viewType: { type: String, default: "text" /* Text */ }, /** * 作为内嵌编辑器被创建后默认获得焦点 */ focusOnCreated: { type: Boolean, default: !1 }, /** * 作为内嵌编辑器被创建后默认选中文本 */ selectOnCreated: { type: Boolean, default: !1 }, /** * 树表展示格式化函数 */ formatter: { type: Function, default: null }, /** * 显示文本格式化函数 */ displayFormatter: { type: Function, default: null }, editorParams: { type: Object }, repositoryToken: { type: Symbol, default: null }, /** 自定义行状态 */ customRowStatus: { type: Object, default: null }, minPanelWidth: { type: Number, default: 160 }, /** 查询字段集合 */ searchFields: { type: Array, default: ["name"] } }, re = J(k, ie, X, oe), ce = { data: { type: Array, default: [] }, enableSearch: { type: Boolean, default: !1 }, idField: { type: String, default: "id" }, multiSelect: { default: !1, type: Boolean }, selectedValues: { type: String, default: "" }, separator: { type: String, default: "," }, textField: { type: String, default: "name" }, titleField: { type: String, default: "name" }, width: { type: Number }, height: { type: Number, default: 350 }, valueField: { type: String, default: "id" }, formatter: { type: Function }, maxHeight: { type: Number, default: 350 }, repositoryToken: { type: Symbol, default: null }, editorParams: { type: Object }, customRowStatus: { type: Object, default: null }, searchHandler: { type: Function, default: () => { } } }, se = /* @__PURE__ */ j({ name: "FComboTreeContainer", props: ce, emits: ["selectionChange", "selectItem", "unSelectItem"], setup(e, r) { const s = c(e.data), f = c([]), g = c(e.separator), p = c(e.width), S = c(e.height), F = c(e.maxHeight), h = c(String(e.selectedValues).split(g.value)), v = c(), C = { customRowStatus: e.customRowStatus }; w(() => e.selectedValues, (t) => { h.value = String(t).split(g.value); }), w(() => e.data, (t) => { var m; s.value = t, (m = v.value) == null || m.updateDataSource(t); }); const n = { enableSelectRow: !0, multiSelect: e.multiSelect, showCheckbox: e.multiSelect, multiSelectMode: "OnCheckAndClick" }; let o = null; e.repositoryToken && (o = W(e.repositoryToken)); const d = I(() => [{ field: e.textField, title: "", dataType: "string", formatter: e.formatter }]), a = I(() => { const t = {}; return p.value !== void 0 && (t.width = `${p.value}px`), S.value !== void 0 && (t.height = `${S.value}px`), F.value !== void 0 && F.value > 0 && (t.maxHeight = `${F.value}px`, t.overflow = "auto"), s.value.length === 0 && (t.height = "200px"), t.position = "relative", t; }); function l(t = []) { t && t.length > 0 ? (f.value = [...t], h.value = f.value.map((m) => m[e.idField])) : (f.value = [], h.value = []), r.emit("selectionChange", f.value); } q(() => { o && o.getData(e.editorParams).then((t) => { s.value = t; }), h.value && v.value.activeRowById(h.value[0]); }); const i = (t) => { v.value.selectItemByIds(t); }; return r.expose({ treeInstance: v, checkItems: i }), () => T("div", { class: "f-combo-tree-container d-flex flex-column", style: a.value }, [e.enableSearch && T("div", { class: "p-2", style: "position: sticky;top:0;z-index: 2; background:white", onMousedown: (t) => t.stopPropagation() }, [T(Q, { buttonContent: '<i class="f-icon f-icon-search"></i>', enableClear: !0, placeholder: "请输入搜索内容", onClear: () => r.emit("clearSearch"), onInput: (t, m) => e.searchHandler(m) }, null)]), T(K, { ref: v, fit: !0, data: s.value, idField: e.idField, columns: d.value, "selection-values": h.value, onSelectionUpdate: l, columnOption: { fitColumns: !0, fitMode: "expand" }, rowOption: C, selection: n, rowNumber: { enable: !1 }, onSelectItem: (t) => r.emit("selectItem", t.raw), onUnSelectItem: (t) => r.emit("unSelectItem", t.raw) }, null)]); } }); function fe(e) { const r = c(""), s = c(e.modelValue), f = c(e.data || []), g = c(e.editable); function p(n, o = []) { return n = n || [], n.reduce((d, a) => (a.id = a.id || a.data[e.idField], d.push(a), a.children && a.children.length && p(a.children, d), d), o); } function S(n) { const o = String(n).split(e.separator).map((i, t) => [i, t]), d = new Map(o), a = []; return p(f.value, a), a.filter((i) => { const t = i.data ? String(i.data[e.valueField]) : String(i[e.valueField]); return d.has(t); }).map((i) => i.data ? i.data : i).sort((i, t) => { const m = d.get(String(i[e.valueField])) || 0, x = d.get(String(t[e.valueField])) || 0; return m - x; }); } function F(n) { const o = S(n), d = e.displayFormatter ? e.displayFormatter(o) : o.map((a) => a[e.textField]).join(e.separator); r.value = g.value ? d || n : d; } function h(n) { const o = n.split(e.separator).map((l) => [l, !0]), d = new Map(o); let a = []; return f.value[0].data ? p(f.value, a) : a = f.value, a = a.map((l) => l.data ? l.data : l), a.filter((l) => d.has(l[e.textField]) || d.has(l[e.valueField])); } function v(n) { const o = {}; return o[e.idField] = n, o[e.textField] = n, [o]; } function C(n) { let o = h(n); const d = o && o.length > 0; return g.value && !d && (o = v(n)), o; } return w(() => e.data, () => { f.value = e.data; }), w([f], ([n]) => { if (e.modelValue) { const o = n.find((d) => d[e.valueField] === e.modelValue); o && (r.value = o[e.textField]); } }), w(() => e.modelValue, (n, o) => { n !== o && (s.value = n, F(n)); }), F(e.modelValue), { dataSource: f, displayText: r, editable: g, modelValue: s, getItemsByDisplayText: h, getItemsByValue: S, getSelectedItemsByDisplayText: C, flatTreeNodes: p }; } function me(e, r) { const { comboEditorRef: s, dataSource: f, searchFields: g, originalValue: p, showPopover: S, flatTreeNodes: F } = e; function h(a, l) { a.forEach((i) => { const t = l.find((m) => m.id === i.id); i.selectable = t.selectable != null ? !!t.selectable : !0, i.children && h(i.children, l); }); } function v(a, l) { const i = (a.children || []).map((m) => v(m, l)).filter((m) => m !== null); return g.value.some((m) => { var x; return (x = a.data[m]) == null ? void 0 : x.toString().toLowerCase().includes(l.toLowerCase()); }) ? { data: { ...a.data }, children: a.children, // 注意这里保留原始子节点 id: a.data[r] } : i.length > 0 ? { data: { ...a.data }, children: i, id: a.data[r] } : null; } function C() { p.value = O(f.value); } function n(a) { var i; if (S.value || (i = s.value) == null || i.showPopup(), !a) { C(); return; } const l = f.value.map((t) => v(t, a)).filter((t) => t !== null); if (l.length) { const t = []; F(f.value, t), h(l, t); } p.value = O(l); } const o = z((a) => { var i; const l = (i = a.target) == null ? void 0 : i.value; n(l); }, 200); function d(a) { var i; let l = (i = a.target) == null ? void 0 : i.value; l !== "" && (l = l.trim()), a.target._value !== l && o(a); } return { onValueChange: d, resetDataSource: C }; } const P = /* @__PURE__ */ j({ name: "FComboTree", props: k, emits: ["clear", "update:modelValue", "change", "search"], setup(e, r) { const s = c(), f = c(e.disabled), g = c(e.enableClear), p = c(e.enableSearch), S = c(e.readonly), F = c(e.searchFields || [e.textField]), h = c(), v = c(), C = c(!0); let n = {}; const { dataSource: o, displayText: d, editable: a, modelValue: l, flatTreeNodes: i } = fe(e), t = I(() => e.multiSelect); I(() => s.value ? s.value.elementRef.getBoundingClientRect().width : 0); const m = I(() => { var y; const u = (y = s.value) == null ? void 0 : y.popoverRef; return u ? u.shown : !1; }), { onValueChange: x, resetDataSource: M } = me({ comboEditorRef: s, dataSource: o, searchFields: F, originalValue: h, showPopover: m, flatTreeNodes: i }, e.idField); function D() { !t.value && s.value && C.value && s.value.hidePopup(); } const R = (u) => { const y = u == null ? void 0 : u.map((b) => b.data || b); return e.displayFormatter ? e.displayFormatter(y) : y.map((b) => b[e.textField]).join(e.separator); }; function V(u = []) { if (!t.value) d.value = R(u), l.value = u.map((y) => y.data ? y.data[e.valueField] : y[e.valueField]).join(e.separator), r.emit("update:modelValue", l.value), r.emit("change", u, l.value); else { const y = Object.keys(n), b = Object.values(n); d.value = R(b), l.value = y.join(e.separator), r.emit("update:modelValue", l.value), r.emit("change", b, l.value); } D(); } function N(u) { var y; l.value = "", n = {}, m.value && ((y = s.value) == null || y.hidePopup()), r.emit("update:modelValue", ""), r.emit("change", null, l.value), r.emit("clear"); } function H(u) { t.value && (delete n[u.id], V()); } function A(u) { t.value && (n[u.id] = u, V()); } w([() => e.disabled, () => e.editable, () => e.enableClear, () => e.enableSearch, () => e.readonly], ([u, y, b, B, E]) => { f.value = u, a.value = y, g.value = b, p.value = B, S.value = E; }); const L = () => { if (h.value = O(o.value), t.value && l.value) { const u = []; i(o.value, u), l.value.split(e.separator).reduce((y, b) => (y[b] = u.find((B) => B.id === b), y), n); } }; function $() { C.value = !1, M(), setTimeout(() => { var u; (u = v.value) == null || u.checkItems(l.value.split(e.separator)), C.value = !0; }, 10); } return () => T(G, { ref: s, id: e.id, disable: f.value, readonly: S.value, forcePlaceholder: e.forcePlaceholder, editable: a.value && !e.multiSelect, buttonContent: e.dropDownIcon, placeholder: e.placeholder, enableClear: g.value, maxLength: e.maxLength, tabIndex: e.tabIndex, enableTitle: e.enableTitle, inputType: e.viewType, popupOnClick: !0, modelValue: d.value, "onUpdate:modelValue": (u) => d.value = u, onClear: N, onInput: x, focusOnCreated: e.focusOnCreated, selectOnCreated: e.selectOnCreated, beforeOpen: L, placement: e.placement, popupMinWidth: e.minPanelWidth }, { default: () => [m.value && T(se, { ref: v, maxHeight: e.maxHeight, multiSelect: e.multiSelect, enableSearch: e.enableSearch, idField: e.idField, valueField: e.valueField, textField: e.textField, titleField: e.titleField, data: h.value, selectedValues: l.value, onSelectionChange: V, formatter: e.formatter, editorParams: e.editorParams, repositoryToken: e.repositoryToken, customRowStatus: e.customRowStatus, searchHandler: x, onUnSelectItem: H, onSelectItem: A, onClearSearch: $ }, null)] }); } }); P.register = (e, r, s, f) => { e["combo-tree"] = P, r["combo-tree"] = re; }; const Fe = U(P); export { P as FComboTree, de as Placement, ue as ViewType, k as comboTreeProps, Fe as default, re as propsResolver };