UNPKG

@farris/ui-vue

Version:

Farris Vue, a Farris Design based Vue3 component library.

956 lines (955 loc) 27 kB
import { defineComponent as E, ref as y, computed as V, watch as B, onMounted as O, createVNode as I, inject as k } from "vue"; import { useI18n as M } from "vue-i18n"; import U from "../button-edit/index.esm.js"; import { resolveAppearance as z, createPropsResolver as K } from "../dynamic-resolver/index.esm.js"; import { isUndefined as Q } from "lodash-es"; import X from "../list-view/index.esm.js"; import Y from "../../designer/button-edit/index.esm.js"; import { useDesignerComponent as Z } from "../designer-canvas/index.esm.js"; import { FormSchemaEntityFieldType$Type as _, withInstall as D } from "../common/index.esm.js"; import { InputBaseProperty as ee } from "../property-panel/index.esm.js"; const te = /* @__PURE__ */ new Map([ ["appearance", z] ]), ie = "https://json-schema.org/draft/2020-12/schema", le = "https://farris-design.gitee.io/combo-list.schema.json", ne = "combo-list", ae = "A Farris Input Component", oe = "object", de = { 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" }, 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: "sting", 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 } }, re = [ "type" ], ue = [ "id", "appearance", "binding", "visible" ], ce = { $schema: ie, $id: le, title: ne, description: ae, type: oe, properties: de, required: re, ignore: ue }; function se(e, t, i) { return t; } var fe = /* @__PURE__ */ ((e) => (e.top = "top", e.bottom = "bottom", e.auto = "auto", e))(fe || {}); const H = { /** * 组件标识 */ id: { type: String }, /** * 下拉数据源 */ data: { type: Array, default: [] }, /** * 可选,展示文本 * 默认为空字符串 -----内部需要根据value重新生成展示文本,此属性不生效 * displayText: { type: String, default: '' }, */ /** * 可选,是否禁用 * 默认为`false` */ disabled: { default: !1, type: Boolean }, /** * 可选,下拉图标 * 默认为'<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: { default: !1, type: Boolean }, /** * 可选,是否启用清空 * 默认启用 */ enableClear: { default: !0, type: Boolean }, /** * 可选,启用搜索 * 默认为`false` */ enableSearch: { type: Boolean, default: !1 }, /** * 可选,鼠标悬停时是否显示控件值 * 默认显示 */ enableTitle: { default: !0, type: Boolean }, fitEditor: { default: !1, type: Boolean }, /** * 可选,强制显示占位符 * 默认`false` */ forcePlaceholder: { default: !1, type: Boolean }, /** * 可选,清空值时隐藏面板 * 默认`true` */ hidePanelOnClear: { default: !0, type: Boolean }, /** * 可选,数据源id字段 * 默认为`id` */ idField: { default: "id", type: String }, /** * 可选,字段映射 */ mapFields: { type: Object }, /** * 可选,最大高度 * 默认`350` */ maxHeight: { default: 350, type: Number }, /** * 最大输入长度 */ maxLength: { type: Number }, /** * 可选,是否支持多选 * 默认`false` */ multiSelect: { type: Boolean, default: !1 }, /** * 绑定值 */ modelValue: {}, /** * 占位符 */ placeholder: { type: String, default: "请选择" }, /** * 可选,下拉面板展示位置 * 默认为`auto` */ placement: { type: String, default: "auto" /* auto */ }, /** * 可选,是否只读 * 默认为`false` */ readonly: { default: !1, type: Boolean }, /** * 远端数据源信息 */ remote: { default: null, type: Object }, /** * 可选,是否支持远端过滤 * 默认`false` */ remoteSearch: { default: !1, type: Boolean }, /** * 可选,分隔符 * 默认`,` */ separator: { default: ",", type: String }, /** * tabIndex */ tabIndex: { type: Number, default: -1 }, /** * 可选,数据源显示字段 * 默认为`name` */ textField: { default: "name", type: String }, /** * 可选,数据源的title * 默认为`name` */ titleField: { default: "name", type: String }, /** * 可选,数据源值字段 * 默认为`id` */ valueField: { default: "id", type: String }, /** * 可选,启用多选下,下拉列表值在输入框中的展示方式 * 支持text | tag * 因为ButtonEdit内部处理类型只有在批量的情况下才会有展示类型区分 */ viewType: { default: "tag", type: String }, /** * 值变化事件 */ change: { type: Function, default: () => { } }, /** * 作为内嵌编辑器被创建后默认获得焦点 */ focusOnCreated: { type: Boolean, default: !1 }, /** * 作为内嵌编辑器被创建后默认选中文本 */ selectOnCreated: { type: Boolean, default: !1 }, /** * 此属性废弃 */ autoHeight: { type: Boolean, default: !0 }, /** * 打开前 */ beforeOpen: { type: Function, default: null }, searchOption: { type: [Boolean, Function], default: !1 }, // 搜索启用高亮 enableHighlightSearch: { type: Boolean, default: !0 }, minPanelWidth: { type: Number, default: 160 }, popupOnClick: { type: Boolean, default: !0 } }, me = Object.assign({}, H, { readonly: {} }), $ = K(H, ce, te, se), he = { dataSource: { type: Array, default: [] }, enableSearch: { type: Boolean, default: !1 }, idField: { type: String, default: "id" }, multiSelect: { 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 } }, ye = /* @__PURE__ */ E({ name: "FComboListContainer", props: he, emits: ["selectionChange"], setup(e, t) { const i = y(), a = y(e.dataSource), n = y([]), s = y(e.separator), g = y(e.width), f = y(e.maxHeight), r = y(String(e.selectedValues).split(s.value)), C = V(() => e.multiSelect), m = V(() => ({ enableSelectRow: !0, multiSelect: e.multiSelect, multiSelectMode: "OnCheckAndClick", showCheckbox: C.value, showSelectAll: !1, showSelection: !0 })); B(e.dataSource, () => { a.value = e.dataSource; }), V(() => e.enableSearch ? "SearchBar" : "ContentHeader"); const p = V(() => { const c = {}; return g.value !== void 0 && (c.width = `${g.value}px`), f.value !== void 0 && f.value > 0 && (c.maxHeight = `${f.value}px`), c; }); function l(c) { i.value.search(c); } function o(c) { n.value = c.map((h) => Object.assign({}, h)), r.value = c.map((h) => h[e.idField]), t.emit("selectionChange", n.value); } function v(c) { if (e.enableHighlightSearch) return; let h = []; const { searchOption: d } = e; typeof d == "function" ? h = a.value.filter((F) => d(c, F)) : h = a.value.filter((F) => F[e.valueField].indexOf(c) > -1 || F[e.textField].indexOf(c) > -1), i.value.updateDataSource(h); } B([() => e.selectedValues], ([c]) => { e.multiSelect ? r.value = c.split(s.value) : r.value = [c]; }); function S(c) { i.value.activeRowById(c); } return O(() => { var c, h; if (!e.multiSelect) { const d = (c = r.value) == null ? void 0 : c[0]; let F = d; if (!Q(d)) { const x = typeof d, w = typeof ((h = a.value[0]) == null ? void 0 : h[e.valueField || e.idField]); w === "number" && x !== w && (F = Number(d)), w === "boolean" && x !== w && (F = d === "true" ? !0 : d === "false" ? !1 : d), S(F); } } }), t.expose({ search: l, activeRowById: S }), () => I("div", { class: "f-combo-list-container", style: p.value }, [I(X, { ref: i, size: "small", itemClass: "f-combo-list-item", itemContentClass: "text-truncate", header: "ContentHeader", headerClass: "f-combo-list-search-box", data: a.value, idField: e.idField, textField: e.textField, titleField: e.titleField, multiSelect: e.multiSelect, selection: m.value, enableHighlightSearch: e.enableHighlightSearch, selectionValues: r.value, onSelectionChange: o, onAfterSearch: v }, null)]); } }); function ge(e) { const { t } = M(), i = y(""), a = y(e.modelValue), n = y(e.data || []), s = y(e.editable); function g(l) { const o = e.multiSelect ? String(l).split(e.separator) : [String(l)], v = o.map((h) => [h, !0]), S = new Map(v); return n.value.filter((h) => S.has(String(h[e.valueField]))).sort((h, d) => { const F = o.indexOf(h[e.valueField]), x = o.indexOf(d[e.valueField]); return F - x; }); } function f(l) { const o = g(l).map((v) => v[e.textField]).join(e.separator); i.value = s.value ? o || l : o; } function r(l) { if (e.multiSelect) { const o = l.split(e.separator).map((S) => [S, !0]), v = new Map(o); return n.value.filter((S) => v.has(S[e.textField])); } return n.value.filter((o) => "" + o[e.textField] === l); } function C(l) { const o = {}; return o[e.idField] = l, o[e.textField] = l, [o]; } function m(l) { let o = r(l); const v = o && o.length > 0; return s.value && !v && (o = C(l)), o; } function p() { const { url: l, method: o = "GET", headers: v = { "Content-Type": "application/json;charset=utf-8;" }, body: S = null } = e.remote, c = o.toLowerCase() === "get" ? { method: o, headers: v } : { method: o, headers: v, body: S }; let h = !1; fetch(new Request(l, c)).then((d) => { var x, w; if (d.status === 200) return h = !!((w = (x = d.headers) == null ? void 0 : x.get("content-type")) != null && w.includes("application/json")), h ? d.text() : d.json(); throw d.status === 405 ? new Error(t("comboList.remoteError")) : new Error(d.statusText); }).then((d) => { d.length && (n.value = h ? JSON.parse(d) : d); }).catch((d) => { console.warn(d); }); } return e.remote && p(), B(() => e.data, () => { n.value = e.data; }), B([n], ([l]) => { if (e.modelValue != null) { const o = l.find((v) => v[e.valueField] === e.modelValue); o && (i.value = o[e.textField]); } }), B(() => e.modelValue, (l) => { a.value = l, f(l); }), f(e.modelValue), { dataSource: n, displayText: i, editable: s, modelValue: a, getItemsByDisplayText: r, getItemsByValue: g, getSelectedItemsByDisplayText: m }; } const L = /* @__PURE__ */ E({ name: "FComboList", props: H, emits: ["clear", "update:modelValue", "change", "input"], setup(e, t) { const { t: i } = M(), a = y(), n = y(), s = y(e.disabled || e.readonly), g = y(e.enableClear), f = y(e.enableSearch), r = y(e.readonly), { dataSource: C, displayText: m, editable: p, modelValue: l, getSelectedItemsByDisplayText: o, getItemsByDisplayText: v } = ge(e), S = y(e.dropDownIcon); S.value === '<span class="f-icon f-icon-arrow-chevron-down"></span>' && (S.value = '<span id="' + e.id + '-icon-dropdown" class="f-icon f-icon-arrow-chevron-down"></span>'); const c = V(() => e.multiSelect), h = V(() => n.value ? n.value.elementRef.getBoundingClientRect().width : 0); function d() { !c.value && n.value && n.value.hidePopup(); } function F(u) { m.value = u.map((T) => T[e.textField]).join(e.separator); let b = ""; u.length === 1 ? b = u[0][e.valueField] : b = u.map((T) => T[e.valueField]).join(e.separator), l.value !== b && (l.value = b, t.emit("update:modelValue", l.value), t.emit("change", u, l.value)); } function x() { const u = o(m.value); F(u); } function w() { r.value || m.value; } function N(u) { var b; l.value = "", (b = a.value) == null || b.activeRowById(""), t.emit("update:modelValue", ""), t.emit("change", [], ""), t.emit("clear"); } function j(u) { var b, T; e.enableSearch ? ((b = a.value) == null || b.search(u), (T = a.value) == null || T.activeRowById(u)) : (l.value = u, m.value = u, t.emit("update:modelValue", l.value), t.emit("change", [u], u)); } function q(u) { if (e.multiSelect) { const b = v(u), P = b.map((R) => R[e.idField || e.valueField]).join(e.separator); l.value !== P && (l.value = P, t.emit("update:modelValue", l.value), t.emit("change", b, l.value)); } } function G() { return m.value; } function W(u) { const { value: b } = u.target; j(b), t.emit("input", b); } function J() { n.value.hidePopup(); } return t.expose({ getDisplayText: G, hidePopup: J }), B([() => e.disabled, () => e.editable, () => e.enableClear, () => e.enableSearch, () => e.readonly], ([u, b, T, P, R]) => { s.value = u, p.value = b, g.value = T, f.value = P, r.value = R; }), () => I(U, { ref: n, id: e.id, disable: s.value, readonly: r.value, forcePlaceholder: e.forcePlaceholder, editable: p.value, buttonContent: S.value, placeholder: e.placeholder === "请选择" ? i("comboList.placeholder") : e.placeholder, enableClear: g.value, maxLength: e.maxLength, tabIndex: e.tabIndex, enableTitle: e.enableTitle, multiSelect: e.multiSelect, inputType: e.multiSelect ? e.viewType : "text", modelValue: m.value, "onUpdate:modelValue": (u) => m.value = u, focusOnCreated: e.focusOnCreated, selectOnCreated: e.selectOnCreated, onClear: N, onClick: w, onChange: q, onBlur: x, onInput: W, beforeOpen: e.beforeOpen, placement: e.placement, popupMinWidth: e.minPanelWidth, popupClass: "f-combo-list-wrapper", popupOnClick: e.popupOnClick, limitContentBySpace: !0 }, { default: () => [I(ye, { ref: a, idField: e.idField, valueField: e.valueField, textField: e.textField, titleField: e.titleField, dataSource: C.value, selectedValues: l.value, separator: e.separator, multiSelect: e.multiSelect, enableSearch: f.value, maxHeight: e.maxHeight, enableHighlightSearch: e.enableHighlightSearch, width: e.fitEditor ? h.value : void 0, onSelectionChange: (u) => { F(u), d(); } }, null)] }); } }), A = { convertFrom: (e, t) => (e.editor.remote || {})[t], convertTo: (e, t, i) => { e.editor.remote = e.editor.remote || {}, e.editor.remote[t] = i; } }; class be extends ee { constructor(t, i) { super(t, i); } getCommonEditorProperties(t) { var i, a, n, s; return { separator: { visible: !!((i = t.editor) != null && i.multiSelect) && ((a = t.editor) == null ? void 0 : a.viewType) === "text", description: "下拉列表启用多选且数据展示类型为文本时的分隔符", title: "分隔符", type: "string" }, viewType: { visible: !!((n = t.editor) != null && n.multiSelect), description: "数据展示类型,有标签和文本两种方式", title: "数据展示类型", type: "enum", editor: { data: [ { id: "tag", name: "标签" }, { id: "text", name: "文本" } ] }, refreshPanelAfterChanged: !0 }, editable: { description: "", title: "允许编辑", type: "boolean", refreshPanelAfterChanged: !0 // readonly: propertyData.editor.type === 'combo-list' }, enableHighlightSearch: { visible: !!((s = t.editor) != null && s.editable), description: "编辑状态下启用高亮搜索", title: "启用高亮搜索", type: "boolean" } }; } getEditorProperties(t) { var s, g; const i = this; let a = ""; if (((s = t == null ? void 0 : t.binding) == null ? void 0 : s.type) === "Form") { const f = this.schemaService.getFieldByIDAndVMID(t.binding.field, this.viewModelId); (g = f == null ? void 0 : f.schemaField) != null && g.type && (a = f.schemaField.type.$type); } return i.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 }, data: { description: "", title: "数据", type: "array", visible: !t.editor.dataSourceType || t.editor.dataSourceType === "static", ...i.getItemCollectionEditor(t, t.editor.valueField, t.editor.textField), // 这个属性,标记当属性变更得时候触发重新更新属性 refreshPanelAfterChanged: !0 }, url: { visible: t.editor.dataSourceType === "dynamic", $converter: A, description: "", title: "服务端API", type: "string" }, // 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: t.editor.dataSourceType === "dynamic", $converter: A, 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: !a || a === "StringType", type: "boolean", refreshPanelAfterChanged: !0 }, maxLength: { description: "", title: "最大输入长度", type: "number", editor: { nullable: !0, min: 0, useThousands: !1 } }, ...this.getCommonEditorProperties(t) }, (f, r) => { if (!f || !r.editor) return; const C = this; switch (f.propertyID) { case "dataSourceType": { f.propertyValue === "static" ? (r.editor.valueField = "value", r.editor.textField = "name", r.editor.remote = null) : f.propertyValue === "dynamic" && (r.editor.remote = { method: "GET" }, r.editor.valueField = "value", r.editor.textField = "name"); break; } case "data": { !C.checkEnumDataReadonly(r) && r.formatter && (r.formatter.data = [...f.propertyValue]); break; } } }); } getGridFieldEdtiorProperties(t, i) { var g, f, r, C; const a = this; let n = ""; if (((g = t == null ? void 0 : t.binding) == null ? void 0 : g.type) === "Form") { const m = this.schemaService.getFieldByIDAndVMID(t.binding.field, this.viewModelId); (f = m == null ? void 0 : m.schemaField) != null && f.type && (n = m.schemaField.type.$type); } return a.getComponentConfig(t, { type: "combo-list" }, { // editable: { // description: "", // title: "允许编辑", // type: "boolean", // readonly: propertyData.editor?.type === 'combo-list' // }, enableClear: { description: "", title: "启用清空", type: "boolean" }, data: { description: "", title: "数据", type: "array", visible: !0, ...a.getItemCollectionEditor(t, (r = t.editor) == null ? void 0 : r.valueField, (C = t.editor) == null ? void 0 : C.textField), // 这个属性,标记当属性变更得时候触发重新更新属性 refreshPanelAfterChanged: !0 }, textField: { description: "", title: "数据源显示字段", type: "string", readonly: !0 }, valueField: { description: "", title: "数据源值字段", type: "string", readonly: !0 }, multiSelect: { description: "", title: "启用多选", visible: n === "StringType", type: "boolean", refreshPanelAfterChanged: !0 }, maxLength: { description: "", title: "最大输入长度", type: "number", editor: { nullable: !0, min: 0, useThousands: !1 } }, ...this.getCommonEditorProperties(t) }, (m, p) => { if (!m || !p.editor) return; const l = this; switch (m.propertyID) { case "dataSourceType": { m.propertyValue === "static" ? (p.editor.valueField = "value", p.editor.textField = "name", p.editor.remote = null) : m.propertyValue === "dynamic" && (p.editor.remote = { method: "GET" }); break; } case "data": { !l.checkEnumDataReadonly(p) && p.formatter && (p.formatter.data = [...m.propertyValue]); break; } } }); } setEditorPropertyRelates(t, i, a) { if (!t || !i.editor) return; const n = this; switch (t.propertyID) { case "dataSourceType": { t.propertyValue === "static" && (i.editor.valueField = "value", i.editor.textField = "name", i.editor.remote = {}); break; } case "data": { !n.checkEnumDataReadonly(i) && i.formatter && (i.formatter.data = [...t.propertyValue]); break; } } } /** * 切换绑定属性 */ changeBindingField(t, i, a) { var s; super.changeBindingField(t, i); const n = a; t.editor && ((s = n == null ? void 0 : n.type) == null ? void 0 : s.$type) === _.EnumType && (t.editor.data = n.type.enumValues || []); } } function ve(e, t) { const i = e.schema; function a(n, s) { return new be(n, t).getPropertyConfig(i, s); } return { getPropsConfig: a }; } const pe = /* @__PURE__ */ E({ name: "FComboListDesign", props: me, emits: ["clear", "update:modelValue", "change"], setup(e, t) { const i = y(), a = k("designer-host-service"), n = k("design-item-context"), s = ve(n, a), g = Z(i, n, s); return O(() => { i.value.componentInstance = g; }), t.expose(g.value), () => I(Y, { ref: i, buttonContent: e.dropDownIcon, readonly: !0, editable: !1, forcePlaceholder: !0, placeholder: e.placeholder, enableClear: !0 }, null); } }); L.register = (e, t, i, a) => { e["combo-list"] = L, t["combo-list"] = $; }; L.registerDesigner = (e, t, i) => { e["combo-list"] = pe, t["combo-list"] = $; }; const Le = D(L); export { L as FComboList, fe as Placement, me as comboListDesignProps, H as comboListProps, Le as default, $ as propsResolver };