UNPKG

@farris/ui-vue

Version:

Farris Vue, a Farris Design based Vue3 component library.

1,766 lines 110 kB
import { defineComponent as _, ref as k, watch as G, nextTick as J, createVNode as v, createTextVNode as X, computed as M, onMounted as Y, onUnmounted as me, reactive as ee, inject as xe, withDirectives as ve, vModelText as Re, resolveDirective as qe, Fragment as ie, mergeProps as $e, vModelSelect as We, watchEffect as Ge } from "vue"; import je, { FButtonEdit as Ue } from "../button-edit/index.esm.js"; import { useResizeObserver as Ke, useTouchMomentum as ze, useTouch as _e, useCommonUtils as oe, useBem as we, useFarrisConfig as Ye, FormSchemaEntityFieldType$Type as ae, EVENT_PROPERTY_TAB_IDS as De, withInstall as Ee, useTextBox as Je, useClear as Xe } from "../common/index.esm.js"; import { LocaleService as ue } from "../locale/index.esm.js"; import { resolveAppearance as Ze, createPropsResolver as Qe, getPropsResolverGenerator as et } from "../dynamic-resolver/index.esm.js"; import tt from "../list-view/index.esm.js"; import { isUndefined as lt, flatten as nt } from "lodash-es"; import "bignumber.js"; import at from "../../designer/button-edit/index.esm.js"; import { InputBaseProperty as it } from "../property-panel/index.esm.js"; import { useDesignerComponent as ot } from "../designer-canvas/index.esm.js"; import { useNumber as ut, useFormat as rt, useSpinner as st, useTextBox as dt, getSpinnerRender as ct, getNumberTextBoxRender as ft, FNumberSpinner as ce } from "../number-spinner/index.esm.js"; import { useInputExpand as mt } from "../common/index.esm.js/text-box/use-input-expand"; import { FSwitch as vt } from "../switch/index.esm.js"; import { FDatePicker as Ce } from "../components/index.esm.js"; import { FRadioGroup as ht } from "../radio-group/index.esm.js"; import { FCheckboxGroup as yt } from "../checkbox-group/index.esm.js"; const gt = { /** * 字段列表 * @default [] */ fields: { type: Array, default: [] }, defaultValue: { type: Object, default: null } }; var P = /* @__PURE__ */ ((e) => (e[e.Equal = 0] = "Equal", e[e.NotEqual = 1] = "NotEqual", e[e.Greater = 2] = "Greater", e[e.GreaterEqual = 3] = "GreaterEqual", e[e.Less = 4] = "Less", e[e.LessEqual = 5] = "LessEqual", e[e.Contains = 6] = "Contains", e[e.NotContains = 9] = "NotContains", e[e.IsEmpty = 12] = "IsEmpty", e[e.IsNotEmpty = 13] = "IsNotEmpty", e))(P || {}), q = /* @__PURE__ */ ((e) => (e[e.Empty = 0] = "Empty", e[e.And = 1] = "And", e[e.Or = 2] = "Or", e))(q || {}); const Se = [ { label: "包含", value: 6 /* Contains */ }, { label: "不包含", value: 9 /* NotContains */ }, { label: "等于", value: 0 /* Equal */ }, { label: "不等于", value: 1 /* NotEqual */ } ], pt = /* @__PURE__ */ _({ name: "SearchFieldsPanel", props: { fields: Array, searchValue: { type: String, default: "" }, maxWidth: { type: Number, default: 300 }, activeIndex: { type: Number, default: -1 }, locales: Object }, emits: ["fieldSelected"], setup(e, t) { const l = k(e.fields || []), n = k(null); G(() => e.fields, (h) => { l.value = h || []; }), G(() => e.activeIndex, (h) => { h >= 0 && n.value && J(() => { var S; const d = (S = n.value) == null ? void 0 : S.querySelectorAll(".search-fields-list-item"); d && d[h] && d[h].scrollIntoView({ block: "nearest" }); }); }); function a(h, d) { d.dataType === "boolean" ? d.value = { value: null, isEmpty: null } : e.searchValue ? d.value = { compare: P.Contains, value: e.searchValue } : d.value = { value: null, isEmpty: null, compare: void 0 }, t.emit("fieldSelected", d); } function f() { return e.searchValue.trim().split(" ").join('<span class="text-muted" style="margin: 0 5px;"> 或 </span>'); } const o = (h) => { var y, m, F, E; const d = " " + (((m = (y = e.locales) == null ? void 0 : y.operators) == null ? void 0 : m.contains) || "包含") + " ", S = " " + ((E = (F = e.locales) == null ? void 0 : F.relation) == null ? void 0 : E.or) || "或 "; return h.title + (e.searchValue ? d + e.searchValue.trim().split(" ").join(S) : ""); }; return () => { var h; return v("div", { class: "search-fields-list p-2", style: { maxWidth: e.maxWidth + "px" } }, [v("span", { style: "font-weight: bold;" }, [((h = e.locales) == null ? void 0 : h.chooseField) || "选择搜索字段", X(":")]), v("div", { class: "search-fields-list-content mt-2" }, [v("ul", { ref: n }, [l.value.map((d, S) => { var E, w; const y = o(d), F = S === e.activeIndex ? " active" : ""; return e.searchValue ? v("li", { class: "search-fields-list-item d-flex flex-row" + F, attr_field: d.field, title: y, onClick: (I) => a(I, d) }, [v("span", { class: "search-field-title", title: d.title }, [d.title]), v("span", { class: "mx-2 text-muted" }, [((w = (E = e.locales) == null ? void 0 : E.operators) == null ? void 0 : w.contains) || "包含"]), v("div", { class: "f-utils-fill text-primary search-box-keyword", style: "text-overflow: ellipsis;", innerHTML: f() }, null)]) : v("li", { class: "search-fields-list-item" + F, attr_field: d.field, title: y, onClick: (I) => a(I, d) }, [d.title]); })])])]); }; } }), bt = /* @__PURE__ */ _({ name: "SearchInput", props: { placeholder: String, fields: Array, popoverOffsetWidth: Number, beforeOpenFieldsPanel: Function, locales: Object }, emits: ["fieldSelected", "inputKeydown", "valueChange"], setup(e, t) { const l = k(), n = k(), a = k(""), f = k(e.popoverOffsetWidth || 20), o = k(), h = M(() => { var i; const p = (i = l.value) == null ? void 0 : i.popoverRef; return p ? p.shown : !1; }), d = k(-1); G(a, () => { d.value = -1; }), G(() => e.fields, () => { d.value = -1; }), G(h, (p) => { p || (d.value = -1); }); function S(p) { var c, g; const i = !!a.value; (c = l.value) == null || c.clear(), (g = l.value) == null || g.hidePopup(), d.value = -1, t.emit("fieldSelected", p, i); } function y() { var p, i; (p = l.value) == null || p.getTextbox().focus(), (i = l.value) == null || i.showPopup(); } const m = (p) => { var c, g, r, u, s, x, C, O, A; const i = ((c = e.fields) == null ? void 0 : c.length) || 0; if (p.keyCode === 38 || p.keyCode === 40) { if (p.preventDefault(), !h.value) { (g = l.value) == null || g.showPopup(), d.value = p.keyCode === 40 ? 0 : Math.max(i - 1, 0); return; } p.keyCode === 40 ? d.value = d.value + 1 >= i ? 0 : d.value + 1 : d.value = d.value - 1 < 0 ? i - 1 : d.value - 1; return; } if (p.keyCode === 13 && h.value) { p.preventDefault(), p.stopPropagation(); const R = d.value >= 0 ? d.value : 0, U = (r = n.value) == null ? void 0 : r.$el; if (U) { const z = U.querySelectorAll(".search-fields-list-item"); z && z[R] && (z[R].click(), (s = (u = l.value) == null ? void 0 : u.getTextbox()) == null || s.blur(), a.value && J(() => { var T; (T = l.value) == null || T.clear(); })); } return; } if (p.keyCode === 27) { h.value && (p.stopPropagation(), p.preventDefault(), (x = l.value) == null || x.hidePopup()); return; } if (p.keyCode === 8 && !a.value) (C = l.value) == null || C.hidePopup(), t.emit("inputKeydown", { key: p.keyCode === 8 ? "backspace" : "enter", event: p }); else if (!((O = e.fields) != null && O.length)) { (A = l.value) == null || A.clear(), p.preventDefault(); return; } }, F = (p) => { a.value = p.trim().replace(/\s+/g, " "), t.emit("valueChange", a.value), h.value || y(); }, E = k(300); let w = null; function I(p) { E.value = window.innerWidth - p.getBoundingClientRect().left - f.value; } return Y(() => { var i, c; const p = (i = l.value) == null ? void 0 : i.getTextbox(); p ? (I(p), w = Ke(p, () => { I(p); })) : (c = o.value) == null || c.focus(); }), me(() => { w && w(); }), t.expose({ showPopover: h, focus: () => { var p; return (p = l.value) == null ? void 0 : p.getTextbox().focus(); }, focusAndShow: y }), () => { var p; return (p = e.fields) != null && p.length ? v(Ue, { ref: l, readonly: !1, editable: !0, placeholder: e.placeholder, enableClear: !1, maxLength: 100, inputType: "text", popupOnClick: !0, placement: "auto", popupMinWidth: 180, showAppendButton: !1, keepWidthWithReference: !1, popupClass: "search-fields-panel", beforeOpen: e.beforeOpenFieldsPanel, onKeydown: m, onChange: F, popupOffsetY: -4 }, { default: () => [h.value && v(pt, { maxWidth: E.value, ref: n, locales: e.locales, fields: e.fields, searchValue: a.value, activeIndex: d.value, onFieldSelected: (i) => S(i) }, null)] }) : v("input", { type: "text", class: "form-control", onKeydown: m, ref: o, onInput: (i) => { i.target.value = "", i.preventDefault(); }, placeholder: "" }, null); }; } }), Be = /* @__PURE__ */ new Map([ ["appearance", Ze] ]), xt = "https://json-schema.org/draft/2020-12/schema", Ct = "https://farris-design.gitee.io/combo-list.schema.json", St = "combo-list", Ft = "A Farris Input Component", Tt = "object", wt = { 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-list" }, appearance: { description: "", type: "object", properties: { class: { type: "string" }, style: { type: "string" } }, default: {} }, binding: { description: "", type: "object", default: {} }, disabled: { description: "", type: "boolean", default: !1 }, enableClear: { description: "", type: "boolean", default: !1 }, editable: { description: "", type: "boolean", default: !1 }, enableLinkLabel: { description: "", type: "boolean", default: !1 }, label: { description: "", type: "string", default: "" }, lableWidth: { description: "", type: "number" }, placeholder: { description: "", type: "string", default: "请选择" }, idField: { description: "", type: "string", default: "id" }, valueField: { description: "", type: "string", default: "id" }, titleField: { description: "", type: "string", default: "name" }, textField: { description: "", type: "string", default: "name" }, dataSourceType: { description: "", type: "string", default: "static" }, data: { description: "", type: "array" }, dataSource: { description: "", type: "string" }, remote: { description: "", type: "string" }, 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" }, multiSelect: { description: "", type: "boolean", default: !1 }, maxLength: { description: "", type: "number", default: null }, visible: { description: "", type: "boolean", default: !0 }, onBlur: { description: "", type: "string", default: "" }, onClickLinkLabel: { description: "", type: "string", default: "" }, maxHeight: { description: "", type: "number", default: 350 }, minPanelWidth: { description: "", type: "number", default: 160 }, popupOnClick: { description: "", type: "boolean", default: !0 }, separator: { description: "", type: "string", default: "," }, viewType: { description: "", type: "string", default: "tag" }, enableSearch: { description: "启用搜索", type: "boolean", default: !0 }, enableHighlightSearch: { description: "启用高亮搜索", type: "boolean", default: !1 }, beforeOpen: { description: "打开下拉面板前回调", type: "string" }, beforeHide: { description: "关闭下拉面板前回调", type: "string" }, onShown: { description: "面板打开事件", type: "string" }, onHidden: { description: "面板关闭事件", type: "string" }, onChange: { description: "值变化事件", type: "string", default: "" }, onInput: { description: "输入事件", type: "string", default: "" }, onClear: { description: "清空事件", type: "string", default: "" }, onDataChanged: { description: "清空事件", type: "string", default: "" }, hideDisabledItems: { description: "隐藏禁用项", type: "boolean", default: !1 }, expandable: { description: "", type: "boolean", default: !1 }, expandMode: { description: "", type: "string", default: "text" }, expandContent: { description: "", type: "string", default: "" }, expandDisabled: { description: "", type: "boolean", default: !1 }, onExpandClick: { description: "", type: "string", default: "" }, showSelectAll: { description: "", type: "boolean", default: !1 } }, Et = [ "type" ], Bt = [ "id", "appearance", "binding", "visible" ], kt = { onClear: "清空事件", onShown: "面板打开事件", onHidden: "面板关闭事件", onChange: "值变化事件", beforeOpen: "打开面板前事件", beforeHide: "关闭面板前事件" }, ke = { $schema: xt, $id: Ct, title: St, description: Ft, type: Tt, properties: wt, required: Et, ignore: Bt, events: kt }; function Ve(e, t, l) { return t; } function Vt() { function e(t, l, n) { const a = {}; return a.beforeOpen = (f) => l.call("beforeOpen", t, [f, t], n), a; } return { resolve: e }; } const re = { /** * 组件唯一标识。 */ id: { type: String }, /** * 下拉列表数据源。 * * @default [] */ data: { type: Array, default: [] }, /** * 是否禁用组件。 * * @default false */ disabled: { default: !1, type: Boolean }, /** * 下拉按钮图标 HTML 字符串。 * * @default '<span class="f-icon f-icon-arrow-chevron-down"></span>' */ dropDownIcon: { type: String, default: '<span class="f-icon f-icon-arrow-chevron-down"></span>' }, /** * 是否允许在输入框中直接编辑文本。 * * @default false */ editable: { default: !1, type: Boolean }, /** * 是否启用清空按钮。 * * @default true */ enableClear: { default: !0, type: Boolean }, /** * 是否启用下拉面板搜索。 * * @default false */ enableSearch: { type: Boolean, default: !1 }, /** * 鼠标悬停时是否显示控件值提示。 * * @default true */ enableTitle: { default: !0, type: Boolean }, /** * 是否自适应编辑器宽度。 * * @default false */ fitEditor: { default: !1, type: Boolean }, /** * 是否在禁用或只读状态下强制显示占位符。 * * @default false */ forcePlaceholder: { default: !1, type: Boolean }, /** * 清空值时是否隐藏下拉面板。 * * @default true */ hidePanelOnClear: { default: !0, type: Boolean }, /** * 数据源中作为唯一标识的字段名。 * * @default 'id' */ idField: { default: "id", type: String }, /** * 字段映射配置。 */ mapFields: { type: Object }, /** * 下拉面板最大高度,单位 px。 * * @default 350 */ maxHeight: { default: 350, type: Number }, /** * 可编辑状态下的最大输入长度。 */ maxLength: { type: Number }, /** * 是否支持多选。 * * @default false */ multiSelect: { type: Boolean, default: !1 }, /** * 可选,多选模式下是否显示全选复选框 * 默认`false` */ showSelectAll: { type: Boolean, default: !1 }, /** * 绑定值 * 组件绑定值。 * * @default '' */ modelValue: { type: String, default: "" }, /** * 值为空时的占位符文本。 * * @default '请选择' */ placeholder: { type: String, default: "请选择" }, /** * 下拉面板展示位置。 * * @default Placement.auto */ placement: { type: String, default: "auto" /* auto */ }, /** * 是否只读。 * * @default false */ readonly: { default: !1, type: Boolean }, /** * 远端数据源配置,设置后将优先从远端加载数据。 * * @default null */ remote: { default: null, type: Object }, /** * 是否支持远端过滤搜索。 * * @default false */ remoteSearch: { default: !1, type: Boolean }, /** * 多选时多个值之间的分隔符。 * * @default ',' */ separator: { default: ",", type: String }, /** * 组件的 tab 索引。 * * @default -1 */ tabIndex: { type: Number, default: -1 }, /** * 数据源中作为显示文本的字段名。 * * @default 'name' */ textField: { default: "name", type: String }, /** * 数据源中作为 title 提示的字段名。 * * @default 'name' */ titleField: { default: "name", type: String }, /** * 数据源中作为绑定值的字段名。 * * @default 'id' */ valueField: { default: "id", type: String }, /** * 多选时选中值在输入框中的展示方式。 * * @remarks * 支持 `text`(文本)和 `tag`(标签)两种模式。 * * @default 'tag' */ viewType: { default: "tag", type: String }, /** * 值变化回调函数。 * * @default () => {} */ change: { type: Function, default: () => { } }, /** * 作为内嵌编辑器创建后是否自动获得焦点。 * * @default false */ focusOnCreated: { type: Boolean, default: !1 }, /** * 作为内嵌编辑器创建后是否默认选中文本。 * * @default false */ selectOnCreated: { type: Boolean, default: !1 }, /** * 是否根据内容自动计算高度。 * * @deprecated 该属性已废弃。 * @default true */ autoHeight: { type: Boolean, default: !0 }, /** * 下拉面板打开前的回调函数,返回 false 可阻止打开。 * * @default null */ beforeOpen: { type: Function, default: null }, /** * 自定义远端数据加载函数,返回 Promise。 */ load: { type: Function }, /** * 搜索过滤配置,可传入布尔值或自定义过滤函数。 * * @default false */ searchOption: { type: [Boolean, Function], default: !1 }, /** * 搜索时是否高亮匹配文本。 * * @default true */ enableHighlightSearch: { type: Boolean, default: !0 }, /** * 下拉面板最小宽度,单位 px。 * * @default 160 */ minPanelWidth: { type: Number, default: 160 }, /** * 是否在点击输入框时弹出下拉面板。 * * @default true */ popupOnClick: { type: Boolean, default: !0 }, /** * 是否可扩展(显示扩展按钮/文本)。 * * @default false */ expandable: { type: Boolean, default: !1 }, /** * 扩展模式,可选 `text` 或 `button`。 * * @default 'text' */ expandMode: { type: String, default: "text" }, /** * 扩展区域显示的文本内容。 * * @default '' */ expandContent: { type: String, default: "" }, /** * 扩展按钮是否禁用。 * * @default false */ expandDisabled: { type: Boolean, default: !1 }, /** * 下拉面板的自定义 CSS 类名。 * * @default '' */ popupClass: { type: String, default: "" }, /** * 是否隐藏禁用的数据项。 * * @remarks * 默认 `false`,禁用项显示为置灰状态;设置为 `true` 时禁用项不显示。 * * @default false */ hideDisabledItems: { type: Boolean, default: !1 } }, It = Object.assign({}, re, { readonly: {} }); Qe(re, ke, Be, Ve); const Ie = et( re, ke, Be, Ve ), Pt = Vt(), At = { dataSource: { type: Array, default: [] }, enableSearch: { type: Boolean, default: !1 }, idField: { type: String, default: "id" }, multiSelect: { type: Boolean, default: !1 }, /** 多选模式下是否显示全选复选框 */ showSelectAll: { type: Boolean, default: !1 }, selectedValues: { type: String, default: "" }, separator: { type: String, default: "," }, textField: { type: String, default: "name" }, titleField: { type: String, default: "name" }, width: { type: Number }, maxHeight: { type: Number }, valueField: { type: String, default: "id" }, /** 值变化事件 */ onSelectionChange: { type: Function, default: () => { } }, searchOption: { type: [Boolean, Function], default: !1 }, // 搜索启用高亮 enableHighlightSearch: { type: Boolean, default: !0 } }, Lt = /* @__PURE__ */ _({ name: "FComboListContainer", props: At, emits: ["selectionChange"], setup(e, t) { const l = k(), n = k(e.dataSource), a = k(e.dataSource), f = k([]), o = k(e.separator), h = k(e.width), d = k(e.maxHeight), S = M(() => e.multiSelect), y = k(e.multiSelect ? String(e.selectedValues).split(o.value) : [e.selectedValues]), m = M(() => ({ enableSelectRow: !0, multiSelect: e.multiSelect, multiSelectMode: "OnCheckAndClick", showCheckbox: S.value, showSelectAll: e.showSelectAll, showSelection: !0 })); G(e.dataSource, () => { n.value = e.dataSource, a.value = e.dataSource; }), M(() => e.enableSearch ? "SearchBar" : "ContentHeader"); const F = M(() => { const i = {}; return h.value !== void 0 && (i.width = `${h.value}px`), d.value !== void 0 && d.value > 0 && (i.maxHeight = `${d.value}px`), i; }); function E(i) { l.value.search(i); } function w(i) { f.value = i.map((c) => Object.assign({}, c)), y.value = i.map((c) => c[e.idField]), t.emit("selectionChange", f.value); } function I(i) { if (e.enableHighlightSearch) return; let c = []; const { searchOption: g } = e; typeof g == "function" ? c = n.value.filter((r) => g(i, r)) : c = n.value.filter((r) => r[e.valueField].indexOf(i) > -1 || r[e.textField].indexOf(i) > -1), l.value.updateDataSource(c); } G([() => e.selectedValues], ([i]) => { e.multiSelect ? i === null ? y.value = [] : y.value = i.split(o.value) : i === null ? y.value = [] : y.value = [i]; }); function p(i) { l.value.activeRowById(i); } return Y(() => { var i, c; if (!e.multiSelect) { const g = (i = y.value) == null ? void 0 : i[0]; let r = g; const u = n.value.map((s) => s[e.valueField || e.idField]); if (!lt(g) && u.includes(g)) { const s = typeof g, x = typeof ((c = n.value[0]) == null ? void 0 : c[e.valueField || e.idField]); x === "number" && s !== x && (r = Number(g)), x === "boolean" && s !== x && (r = g === "true" ? !0 : g === "false" ? !1 : g), p(r); } } }), t.expose({ search: E, activeRowById: p }), () => v("div", { class: "f-combo-list-container", style: F.value }, [v(tt, { ref: l, size: "small", itemClass: "f-combo-list-item", itemContentClass: "text-truncate", header: "ContentHeader", headerClass: "f-combo-list-search-box", data: n.value, idField: e.idField, textField: e.textField, titleField: e.titleField, multiSelect: e.multiSelect, selection: m.value, enableHighlightSearch: e.enableHighlightSearch, selectionValues: y.value, onSelectionUpdate: w, onAfterSearch: I }, null)]); } }), Fe = { property: "all", duration: 0.3, timingFunction: "cubic-bezier(0.17, 0.89, 0.45, 1)", delay: 0 }, Mt = (e, t) => { const l = e.lineHeight / 2, n = ze({ maxOverflowY: 44 }), a = ee({ ...Fe }), f = (r) => { t.emit("change", r); }, o = ee({ value: 0, max: 0, min: 0, start: 0, index: 0, currentItem: void 0, active: !1 }), h = () => { o.max = e.visiableOptionCount / 2 * e.lineHeight; const r = e.column.length * e.lineHeight; o.min = o.max - r + e.lineHeight; }, d = (r = 0) => { h(), o.index = r, o.value = o.max - r * e.lineHeight, o.currentItem = e.column[r]; }, S = (r) => { const u = e.column.length - 1, s = Math.min(o.index, u), x = e.column.findIndex((C) => C[e.valueField] === r); return x >= 0 ? x : s; }, y = (r) => { const u = e.column.length - 1; return o.index > u ? e.column[u] : e.column[r]; }, m = (r) => { r && (o.currentItem = r, a.duration = 0); const u = o.currentItem[e.valueField], s = S(u), x = y(o.index)[e.valueField]; d(s), u !== x && setTimeout(() => { f(o.currentItem); }, a.duration * 1e3); }, F = () => { const r = Array.isArray(e.value) ? e.value[0] : e.value; d(S(r)); }; F(), G(() => e.value, () => { e.multiSelect || F(); }), G(() => e.column, () => m()); const E = (r, u = o.max, s = o.min) => { const x = o.start + r; o.value = x > l ? Math.min(x, u) : Math.max(x, s), o.index = Math.round((o.max - o.value) / e.lineHeight), o.currentItem = y(o.index); }, w = _e(), I = (r) => { w.start(r), o.active = !0, o.start = o.value, n.start(o.start), a.duration = 0; }, p = (r) => { r.preventDefault(), w.move(r), E( w.deltaY.value, o.max + e.lineHeight, o.min - e.lineHeight ), n.move(w.deltaY.value), a.duration = Fe.duration; }, i = (r) => { const u = r < 0, s = r % e.lineHeight > l ? 1 : 0, x = Math.floor(r / e.lineHeight); return (u ? x - s : x + s) * e.lineHeight + l; }; return { translateY: o, transition: a, onTouchStart: I, onTouchMove: p, onTouchEnd: () => { o.start = 0; const r = n.end(); let u = 0; if (r) { const { destination: s, duration: x } = n.get(o.value, o.min, o.max); u = s, a.duration = x / 1e3; } else u = o.value; E(i(u)), f(o.currentItem); }, onTransitionend: () => { o.active = !1; }, updateTranslate: m }; }, Ot = { column: { type: Array, default: () => [] }, valueField: { type: String, default: "value" }, textField: { type: String, default: "text" }, value: { type: [Array, String, Number], default: () => [] }, multiSelect: { type: Boolean, default: !1 }, showIcon: { type: Boolean, default: !1 }, lineHeight: { type: Number, default: 0 }, visiableOptionCount: { type: Number, default: 5 } }, Ht = /* @__PURE__ */ _({ props: Ot, emits: ["change", "click"], setup(e, t) { const { addUnit: l } = oe(), { bem: n } = we("FComboTouchList"), { translateY: a, transition: f, onTouchStart: o, onTouchMove: h, onTouchEnd: d, onTransitionend: S } = Mt(e, t), y = (E) => { t.emit("click", E); }, m = M(() => ({ transform: `translateY(${l(a.value)})`, transition: `all ${a.active ? f.duration : 0}s ${f.timingFunction} 0s` })), F = (E) => e.showIcon ? Array.isArray(e.value) && e.value.includes(E[e.valueField]) : !1; return () => v("div", { class: n("column"), style: m.value, onTouchstart: o, onTouchmove: h, onTouchend: d, onTransitionend: S }, [e.column.map((E) => v("div", { class: n("column-item"), onClick: () => y(E) }, [v("span", null, [E[e.textField]]), F(E) && v("span", { class: `f-icon f-icon-check ${n("column-item-icon")}` }, null)]))]); } }), Nt = { modelValue: { type: [String, Array], default: "" }, columns: { type: Array, default: () => [] }, title: { type: String, default: "" }, valueField: { type: String, default: "value" }, textField: { type: String, default: "text" }, childrenField: { type: String, default: "children" }, multiSelect: { type: Boolean, default: !1 }, lineHeight: { type: Number, default: 44 }, cancelText: { type: String, default: "取消" }, confirmText: { type: String, default: "确定" }, optionFormatter: { type: Function, default: void 0 }, visiableOptionCount: { type: Number, default: 5 }, showToolbar: { type: Boolean, default: !0 }, separator: { type: String, default: "," } }, Rt = (e, t) => { const { finalValue: l, initValue: n, setSelectedByIndex: a, getSelectedValueByIndex: f } = t, { isArray: o, isFunction: h, isObject: d } = oe(), S = (u) => u && u[0], y = M(() => { var u; return ((u = e.columns) == null ? void 0 : u.length) > 0 && o(e.columns[0]); }), m = (u) => { if ((u == null ? void 0 : u.length) === 0) return !1; const s = S(u); return s && o(s[e.childrenField]); }, F = (u, s) => { const x = S(u), C = f(s); let O = u.find((R) => R[e.valueField] === C); O = O || x; const A = O[e.childrenField] || []; if (m(A)) { const R = F(A, s + 1); return [A, ...R]; } return [A]; }, E = () => { const u = e.columns, s = F(u, 0); return [u, ...s]; }, w = (u, s) => { const x = u[e.textField]; return h(e.optionFormatter) ? e.optionFormatter(s, u) : x; }, I = (u, s) => u.map((x) => { const C = d(x) ? x : { [e.valueField]: x, [e.textField]: x }; return C[e.textField] = w(C, s), C; }), p = M(() => { let u = []; return y.value ? u = e.columns : m(e.columns) ? u = E() : u = [e.columns], u.map(I); }), i = () => p.value.map((u, s) => { const x = l.value[s]; return u.find((O) => O[e.valueField] === x); }).filter((u) => u), c = () => i().map((u) => u[e.valueField]), g = () => i().map((u) => u[e.textField]).join("-"), r = () => { p.value.forEach((u, s) => { if (e.multiSelect) l.value[s].forEach((C) => { const O = u.find((A) => A[e.valueField] === C); O && a(s, O); }); else { const x = l.value[s], C = u.find((O) => O[e.valueField] === x); C ? a(s, C) : a(s, S(u)); } }); }; return G( () => e.modelValue, () => { n(e.modelValue), r(); }, { immediate: !0 } ), { columns: p, getPickeds: i, getValue: c, getTextValue: g }; }, qt = (e) => { const { isArray: t, isMultiArray: l, isString: n, isDef: a } = oe(), f = (i) => { let c = []; return t(i) ? c = i : n(i) ? c = i.split(e.separator) : a(i) && (c = [i]), e.multiSelect ? l(c) ? c : [c] : c; }, o = k([]), h = (i) => { o.value = f(i); }, d = ee([]), S = M(() => d.map((i) => i[e.valueField])), y = ee([]), m = M(() => y.map((i) => i.map((c) => c[e.valueField]))); return { finalValue: o, initValue: h, getSelected: () => e.multiSelect ? y : d, getSelectedValue: () => e.multiSelect ? m.value : S.value, setSelectedByIndex: (i, c) => { if (e.multiSelect) { const g = y[i] || []; g.includes(c) ? y[i] = g.filter((r) => r !== c) : y[i] = [...g, c]; } else d[i] = c; }, getSelectedByIndex: (i) => e.multiSelect ? y[i] : d[i], getSelectedValueByIndex: (i) => e.multiSelect ? m.value[i] : S.value[i] }; }, $t = /* @__PURE__ */ _({ props: Nt, emits: ["change", "confirm", "cancel", "update:modelValue"], setup(e, t) { const { emit: l } = t, { addUnit: n } = oe(), a = qt(e), { finalValue: f, getSelectedValue: o, getSelectedValueByIndex: h, getSelected: d, setSelectedByIndex: S } = a, { columns: y } = Rt(e, a), m = (g, r = !0) => { const { value: u, index: s } = g; (r && !e.multiSelect || !r && e.multiSelect) && (l("change", g), S(s, u)); }, F = () => { f.value = o(), l("confirm", d()), l("update:modelValue", f.value); }, E = () => { l("cancel"); }, { bem: w } = we("FComboTouchList"), I = () => v("div", { class: w("toolbar") }, [v("div", { class: w("toolbar-left"), onClick: E }, [v("span", null, [e.cancelText])]), v("div", { class: w("toolbar-title") }, [v("span", null, [e.title])]), v("div", { class: w("toolbar-right"), onClick: F }, [v("span", null, [e.confirmText])])]), p = M(() => { const g = (e.visiableOptionCount + 1) * e.lineHeight; return { height: n(g) }; }), i = M(() => { const g = e.visiableOptionCount * e.lineHeight / 2; return { backgroundSize: `100% ${n(g)}` }; }), c = () => v("div", { class: w("content") }, [v("div", { class: w("columns"), style: p.value }, [y.value.map((g, r) => v(Ht, { column: g, value: h(r), showIcon: e.multiSelect, textField: e.textField, multiSelect: e.multiSelect, valueField: e.valueField, lineHeight: e.lineHeight, visiableOptionCount: e.visiableOptionCount, onChange: (u) => m({ value: u, index: r }), onClick: (u) => m({ value: u, index: r }, !1) }, null)), !e.multiSelect && v("div", { class: w("mask"), style: i.value }, null), v("div", { class: w("frame") }, null)])]); return () => v("div", { class: w("") }, [e.showToolbar && I(), c()]); } }); function Wt(e, t) { const l = k(""), n = k(e.modelValue), a = k(e.data || []), f = k(e.editable), o = M(() => e.hideDisabledItems ? a.value.filter((i) => !i.disabled) : a.value); function h(i) { const c = e.multiSelect ? String(i).split(e.separator) : [String(i)], g = c.map((s) => [s, !0]), r = new Map(g); return a.value.filter((s) => r.has(String(s[e.valueField]))).sort((s, x) => { const C = c.indexOf(s[e.valueField]), O = c.indexOf(x[e.valueField]); return C - O; }); } function d(i) { const c = h(i).map((g) => g[e.textField]).join(e.separator); l.value = f.value ? c || i : c; } function S(i) { if (e.multiSelect) { const c = i.split(e.separator).map((r) => [r, !0]), g = new Map(c); return a.value.filter((r) => g.has(r[e.textField])); } return a.value.filter((c) => "" + c[e.textField] === i); } function y(i) { const c = {}; return c[e.idField] = i, c[e.textField] = i, [c]; } function m(i) { let c = S(i); const g = c && c.length > 0; return f.value && !g && (c = y(i)), c; } function F() { const { url: i, method: c = "GET", headers: g = { "Content-Type": "application/json;charset=utf-8;" }, body: r = null } = e.remote; if (!i) return; const { basePath: u } = Ye().value, s = c.toLowerCase() === "get" ? { method: c, headers: g } : { method: c, headers: g, body: r }; let x = !1; fetch(new Request(u + i, s)).then((C) => { var A, R; if (C.status === 200) return x = !!((R = (A = C.headers) == null ? void 0 : A.get("content-type")) != null && R.includes("application/json")), x ? C.text() : C.json(); throw C.status === 405 ? new Error(ue.getLocaleValue("comboList.remoteError")) : new Error(C.statusText); }).then((C) => { C.length && (a.value = x ? JSON.parse(C) : C, n.value && d(n.value)); }).catch((C) => { console.warn(C); }); } e.remote && (e.load ? e.load().then((i) => { a.value = i; }).catch((i) => { console.log(i); }) : F()), G(() => e.data, () => { a.value = e.data; }), G([a], ([i], [c]) => { if (e.modelValue != null && !e.multiSelect) { const g = i.find((r) => r[e.valueField] === n.value); g ? g[e.valueField] !== n.value ? (n.value = g[e.valueField], l.value = g[e.textField], t.emit("update:modelValue", g[e.valueField]), t.emit("change", [g], g[e.valueField])) : l.value !== g[e.textField] && (l.value = g[e.textField]) : n.value !== "" && (n.value = "", l.value = "", t.emit("update:modelValue", ""), t.emit("change", [], "")); } }), G(() => e.modelValue, (i, c) => { c !== i && (n.value = i, d(i)); }); function E(i) { a.value = i, t.emit("dataChanged", i); } function w() { return a.value; } function I() { return l.value; } async function p() { const i = typeof e.beforeOpen == "function"; return !e.beforeOpen || !i ? Promise.resolve(!0) : Promise.resolve().then(() => e.beforeOpen({ instance: { updateDataSource: E, getData: w, getDisplayText: I } })).then((c) => typeof (c == null ? void 0 : c.canOpen) == "boolean" ? c == null ? void 0 : c.canOpen : !0); } return d(e.modelValue), { dataSource: a, filteredDataSource: o, displayText: l, editable: f, modelValue: n, beforeOpenList: p, getItemsByDisplayText: S, getItemsByValue: h, getSelectedItemsByDisplayText: m }; } const Gt = ["moz", "ms", "webkit"]; function jt() { let e = 0; return (t) => { const l = (/* @__PURE__ */ new Date()).getTime(), n = Math.max(0, 16 - (l - e)), a = setTimeout(() => { t(l + n); }, n); return e = l + n, a; }; } function Ut() { if (typeof window > "u") return () => 0; if (window.requestAnimationFrame) return window.requestAnimationFrame.bind(window); const e = Gt.filter((t) => `${t}RequestAnimationFrame` in window)[0]; return e ? window[`${e}RequestAnimationFrame`] : jt(); } Ut(); k(""); function fe() { if (typeof window > "u" || typeof navigator > "u") return !1; const e = navigator.userAgent || navigator.vendor || window.opera, t = [ /iPhone/i, /iPod/i, /Android.*Mobile/i, // Android 手机通常包含 "Mobile" 字样,而平板不包含 /webOS/i, /BlackBerry/i, /IEMobile/i, /Opera Mini/i, /Harmony/i ], l = [ /iPad/i, /Android(?!.*Mobile)/i, // Android 平板通常不含 "Mobile" /Tablet/i, /PlayBook/i, /Kindle/i, /Silk/i ]; for (const d of l) if (d.test(e)) return !1; for (const d of t) if (d.test(e)) return !0; if (typeof screen > "u") return !1; const n = "ontouchstart" in window || navigator.maxTouchPoints > 0, a = screen.width, f = screen.height, o = Math.min(a, f); return !!(n && o <= 768); } function Kt() { const e = fe(); return e && document.body.classList.add("f-mobile"), e; } typeof document < "u" && Kt(); const te = /* @__PURE__ */ _({ name: "FComboList", props: re, emits: ["clear", "update:modelValue", "change", "input", "dataChanged", "expandClick", "hidden", "shown"], setup(e, t) { const l = k(), n = k(), a = k(e.disabled || e.readonly), f = k(e.enableClear), o = k(e.enableSearch), h = k(e.readonly), { dataSource: d, displayText: S, editable: y, modelValue: m, filteredDataSource: F, getItemsByDisplayText: E, getItemsByValue: w, beforeOpenList: I } = Wt(e, t), p = k(e.dropDownIcon); p.value === '<span class="f-icon f-icon-arrow-chevron-down"></span>' && (p.value = '<span id="' + e.id + '-icon-dropdown" class="f-icon f-icon-arrow-chevron-down"></span>'); const i = M(() => e.multiSelect), c = M(() => n.value ? n.value.elementRef.getBoundingClientRect().width : 0); function g() { !i.value && n.value && n.value.hidePopup(); } function r(V) { S.value = V.map((j) => j[e.textField]).join(e.separator) || m.value; let L = ""; V.length === 1 ? L = V[0][e.valueField] : L = V.map((j) => j[e.valueField]).join(e.separator), m.value !== L && (m.value = L, t.emit("update:modelValue", m.value), t.emit("change", V, m.value)); } function u() { const V = w(m.value); r(V); } function s() { h.value || S.value; } function x(V) { var L; m.value = "", (L = l.value) == null || L.activeRowById(""), t.emit("clear"); } function C(V) { var L, j; e.enableSearch && e.enableHighlightSearch && ((L = l.value) == null || L.search(V)), (j = l.value) == null || j.activeRowById(V), t.emit("change", [m.value], m.value); } function O(V) { if (e.multiSelect) { const L = E(V); e.viewType; const K = L.map((D) => D[e.idField || e.valueField]).join(e.separator); m.value !== K && (m.value = K, t.emit("update:modelValue", m.value), t.emit("change", L, m.value)); } else V !== m.value && (m.value = V, t.emit("update:modelValue", m.value), t.emit("change", [], V)); } function A() { return S.value; } function R(V) { const { value: L } = V.target; C(L), t.emit("input", L); } function U() { n.value.hidePopup(); } function z(V) { d.value = V; } function T() { return d.value; } const H = { getDisplayText: A, hidePopup: U, updateDataSource: z, getData: T }; t.expose(H), G([() => e.disabled, () => e.editable, () => e.enableClear, () => e.enableSearch, () => e.readonly], ([V, L, j, K, D]) => { a.value = V, y.value = L, f.value = j, o.value = K, h.value = D; }); const $ = () => { t.emit("expandClick"); }; return () => v(je, { ref: n, id: e.id, disable: a.value, readonly: h.value, forcePlaceholder: e.forcePlaceholder, editable: y.value, buttonContent: p.value, placeholder: e.placeholder === "请选择" ? ue.getLocaleValue("comboList.placeholder") : e.placeholder, enableClear: f.value, maxLength: e.maxLength, tabIndex: e.tabIndex, enableTitle: e.enableTitle, multiSelect: e.multiSelect, inputType: e.multiSelect ? e.viewType : "text", modelValue: S.value, "onUpdate:modelValue": (V) => S.value = V, focusOnCreated: e.focusOnCreated, selectOnCreated: e.selectOnCreated, onClear: x, onClick: s, onChange: O, onBlur: u, onInput: R, beforeOpen: I, placement: fe() ? "bottom" : e.placement, popupMinWidth: e.minPanelWidth, popupClass: "f-combo-list-wrapper", popupOnClick: e.popupOnClick, limitContentBySpace: !0, expandable: e.expandable, expandMode: e.expandMode, expandContent: e.expandContent, expandDisabled: e.expandDisabled, onExpandClick: $, onHidden: () => t.emit("hidden"), onShown: () => t.emit("shown") }, { default: () => [fe() ? v($t, { modelValue: m.value, valueField: e.valueField, textField: e.textField, columns: d.value, multiSelect: e.multiSelect, separator: e.separator, onConfirm: (V) => { const L = e.multiSelect ? V[0] || [] : V; r(L), n == null || n.value.hidePopup(); }, onCancel: () => { n == null || n.value.hidePopup(); } }, null) : v(Lt, { class: e.popupClass, ref: l, idField: e.idField, valueField: e.valueField, textField: e.textField, titleField: e.titleField, dataSource: F.value, selectedValues: m.value, separator: e.separator, multiSelect: e.multiSelect, showSelectAll: e.showSelectAll, enableSearch: o.value, maxHeight: e.maxHeight, enableHighlightSearch: e.enableHighlightSearch, width: e.fitEditor ? c.value : void 0, onSelectionChange: (V) => { r(V), g(); } }, null)] }); } }), Te = { convertFrom: (e, t) => (e.editor.remote || {})[t], convertTo: (e, t, l) => { e.editor.remote = e.editor.remote || {}, e.editor.remote[t] = l; } }; class zt extends it { constructor(t, l) { super(t, l); } getCommonEditorProperties(t) { var l, n, a, f; return { showSelectAll: { visible: !!((l = t.editor) != null && l.multiSelect), description: "多选模式下是否显示全选复选框", title: "启用全选", type: "boolean", default: !1, refreshPanelAfterChanged: !0 }, viewType: { visible: !!((n = t.editor) != null && n.multiSelect), description: "数据展示类型,有标签和文本两种方式", title: "数据展示类型", type: "enum", editor: { data: [ { id: "tag", name: "标签" }, { id: "text", name: "文本" } ] }, refreshPanelAfterChanged: !0 }, separator: { visible: !!((a = t.editor) != null && a.multiSelect) && ((f = t.editor) == null ? void 0 : f.viewType) === "text", description: "下拉列表启用多选且数据展示类型为文本时的分隔符", title: "分隔符", type: "enum", editor: { data: [ { id: ",", name: "逗号(,)" }, { id: "#", name: "井号(#)" }, { id: ".", name: "句号(.)" }, { id: "|", name: "竖线(|)" } ] } }, editable: { description: "", title: "允许编辑", type: "boolean", refreshPanelAfterChanged: !0, readonly: !0 // readonly: !!propertyData.editor?.multiSelect && (propertyData.editor?.viewType === 'tag' || !propertyData.editor!.viewType) }, hideDisabledItems: { description: "当数据项禁用时,隐藏数据项", title: "隐藏禁用项", type: "boolean", refreshPanelAfterChanged: !0 } // enableHighlightSearch: { // visible: !!propertyData.editor?.editable, // description: "编辑状态下启用高亮搜索", // title: "启用高亮搜索", // type: "boolean" // }, }; } getEditorProperties(t) { var d, S, y, m, F, E, w, I, p, i, c, g, r; const l = this; let n = ""; if (((d = t == null ? void 0 : t.binding) == null ? void 0 : d.type) === "Form") { const u = this.schemaService.getFieldByIDAndVMID(t.binding.field, this.viewModelId); (S = u == null ? void 0 : u.schemaField) != null && S.type && (n = u.schemaField.type.$type); } const a = this.getPropertyEditorParams(t, ["Variable"]), f = !t.editor.dataSourceType || t.editor.dataSourceType === "static", o = (((m = (y = this.designViewModelField) == null ? void 0 : y.type) == null ? void 0 : m.$type) === ae.StringType || !!this.formRule && ((F = this.designerHostService.schemaService.getFieldByID(t.binding.field)) == null ? void 0 : F.type.$type) === ae.StringType) && ((E = t.editor) == null ? void 0 : E.type) === "combo-list" && ((w = t.editor) == null ? void 0 : w.dataSourceType) === "dynamic" && !((p = (I = t.editor) == null ? void 0 : I.remote) != null && p.url) && !((i = t.editor) != null && i.multiSelect); return l.getComponentConfig( t, { type: "combo-list" }, { // enableSearch: { // description: "编辑状态下启用搜索", // title: "允许编辑", // type: "boolean", // }, enableClear: { description: "是否显示清除按钮", title: "启用清除按钮", type: "boolean" }, dataSourceType: { description: "", title: "数据源类型", type: "enum", editor: { default: "static", data: [ { id: "static", name: "静态" }, { id: "dynamic", name: "动态" } ] }, refreshPanelAfterChanged: !0 }, dataSource: { description: "动态数据源绑定变量", visible: o, title: "数据", editor: { ...a, controlName: "", enableClear: !0 }, refreshPanelAfterChanged: !0 }, data: { description: "", title: "数据", type: "array", visible: f, ...l.getItemCollectionEditor(t, t.editor.valueField, t.editor.textField), // 这个属性,标记当属性变更得时候触发重新更新属性 refreshPanelAfterChanged: !0 }, url: { visible: t.editor.dataSourceType === "dynamic" && !((c = t.editor) != null && c.dataSource), $converter: Te, description: "", title: "服务端API", type: "string", refreshPanelAfterChanged: !0 }, // method: { // visible: propertyData.editor.dataSourceType === "dynamic", // $converter: comboListRemoteConverter, // description: "", // title: "服务端API类型", // type: "enum", // editor: { // default: "GET", // data: [ // { id: "GET", name: "GET" }, // { id: "PUT", name: "PUT" }, // { id: "POST", name: "POST" } // ] // }, // }, body: { visible: !1, $converter: Te, description: "", title: "服务端API参数", type: "string" }, textField: { description: "", title: "数据源显示字段", type: "string", readonly: t.editor.dataSourceType !== "dynamic" }, valueField: { description: "", title: "数据源值字段", type: "string", readonly: t.editor.dataSourceType !== "dynamic" }, multiSelect: { description: "", title: "启用多选", visible: !n || n === "StringType", readonly: ((g = t.editor) == null ? void 0 : g.dataSourceType) === "dynamic" && !!((r = t.editor) != null && r.dataSource), type: "boolean", refreshPanelAfterChanged: !0 }, maxLength: { description: "", title: "最大输入长度", type: "number", editor: { nullable: !0, min: 0, useThousands: !1, needValid: !0 } }, ...this.getCommonEditorProperties(t) }, (u, s) => { if (!u || !s.editor) return; const x = this; switch (u.propertyID) { case "dataSourceType": { u.propertyValue === "static" ? (s.editor.valueField = "value", s.editor.textField = "name", s.editor.remote = null) : u.propertyValue === "dynamic" && (s.editor.remote = { method: "GET" }, s.editor.valueField = "value", s.editor.textField = "name"); break; } case "data": { !x.checkEnumDataReadonly(s) && s.formatter && (s.formatter.data = [...u.propertyValue]); break; } case "viewType": { u.propertyValue === "tag" && (s.editor.editable = !1); break; } case "dataSource": x.afterMutilEditorChanged(s, u); break; } } ); } getGridFieldEdtiorProperties(t, l) { var d, S,