UNPKG

d-render

Version:

基于 Element Plus 二次封装的数据驱动渲染组件库 - 表单、搜索表单、表格配置化渲染

594 lines (591 loc) 21.4 kB
import { defineComponent, ref, computed, reactive, provide, onMounted, watch, createVNode, mergeProps, nextTick, h, createTextVNode } from 'vue'; import { ElTable, ElTableColumn, ElRadio, ElTooltip, ElIcon } from 'element-plus'; import TableSelectionColumn from './table-column-selection'; import { useCipConfig, useCipPageConfig, cipTableKey, getUsingConfig, getFieldValue, isNotEmpty, isEmpty, isArray, setFieldValue } from '@d-render/shared'; import { CipButtonCollapse, CipButtonText } from '@xdp/button'; import { tableProps } from './table-props'; import ColumnInput from './column-input'; import { EmptyStatus, Hint } from './icons-vue'; import { handleColumnWidthMap, dateColumnWidthMap } from './config'; import { calculateCurrentWidth, analyseData, getPropertyKeyByPath } from './util'; import { collectFilterableColumns, modelToTableFilteredValues, mergeTableFilterModel, tableFilteredValuesToModel } from './filter-util'; import { resolveRowKeyGetter, createRowMatcher, flattenTreeRows } from './selection-util'; import { useLocale } from '../hooks/use-locale'; var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __objRest = (source, exclude) => { var target = {}; for (var prop in source) if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0) target[prop] = source[prop]; if (source != null && __getOwnPropSymbols) for (var prop of __getOwnPropSymbols(source)) { if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop)) target[prop] = source[prop]; } return target; }; var index = /* @__PURE__ */ defineComponent({ name: "CipTable", inheritAttrs: false, props: tableProps, emits: ["sort", "filter-change", "update:filterModel", "update:data", "update:selectColumns", "mainFieldClick", "update:selectRadio", "row-click"], setup(props, context) { const cipConfig = useCipConfig(); const cipPageConfig = useCipPageConfig(); const { t } = useLocale(); const cipTableRef = ref(); const tableUsingConfig = (key, defaultValue) => { const configKey = `table.${key}`; return getUsingConfig(getFieldValue(props, key), getFieldValue(cipPageConfig, configKey), getFieldValue(cipConfig, configKey), defaultValue); }; const _size = computed(() => { return tableUsingConfig("size", "default"); }); const _border = computed(() => { return tableUsingConfig("border"); }); const showDisabledButtonBridge = computed(() => { return tableUsingConfig("showDisabledButton"); }); const dangerButtonBridge = computed(() => { return tableUsingConfig("dangerButton", false); }); const _defaultAlign = computed(() => { return tableUsingConfig("defaultAlign", "left"); }); const _filterIcon = computed(() => { return tableUsingConfig("filterIcon"); }); const filterableColumns = computed(() => collectFilterableColumns(props.columns)); const tableFilteredValues = computed(() => { if (props.filterModel === void 0) return void 0; return modelToTableFilteredValues(props.filterModel, filterableColumns.value); }); const calculateCurrentWidthFn = computed(() => { var _a; const customTransform = (_a = cipConfig.table) == null ? void 0 : _a.transformPx; if (typeof customTransform === "function") { return (width) => customTransform(width) + addBorderWidth.value; } if (props.size) return (width) => width + addBorderWidth.value; const { sizeStandard = "default", size = "default" } = cipConfig.table || {}; return (width) => calculateCurrentWidth(size, sizeStandard, width) + addBorderWidth.value; }); const cipTable = reactive({ size: _size, showDisabledButton: showDisabledButtonBridge, dangerButton: dangerButtonBridge }); provide(cipTableKey, cipTable); const lastEmittedSelection = ref(void 0); const lastSyncedData = ref(void 0); const emitSelectColumns = (val) => { lastEmittedSelection.value = val; context.emit("update:selectColumns", val); }; const removeSelection = (rows) => { const table = cipTableRef.value; if (!table) return; const list = Array.isArray(rows) ? rows : [rows]; const rowKeyGetter = resolveRowKeyGetter(props.rowKey); const currentSelection = table.getSelectionRows(); list.forEach((target) => { const matched = currentSelection.includes(target) ? target : rowKeyGetter && currentSelection.find((r) => rowKeyGetter(r) === rowKeyGetter(target)) || target; table.toggleRowSelection(matched, false); }); emitSelectColumns(table.getSelectionRows()); }; const isSyncingSelection = ref(false); const syncSelectionFromModel = () => { if (props.selectType !== "checkbox") return; if (props.selectColumns === void 0) return; const isOwnEcho = props.data === lastSyncedData.value && props.selectColumns === lastEmittedSelection.value; lastSyncedData.value = props.data; if (isOwnEcho) return; const table = cipTableRef.value; if (!table) return; const model = props.selectColumns || []; isSyncingSelection.value = true; if (model.length === 0) { table.clearSelection(); } else { const rowKeyGetter = resolveRowKeyGetter(props.rowKey); const isMatched = createRowMatcher(model, rowKeyGetter); const currentlySelected = new Set(table.getSelectionRows()); flattenTreeRows(props.data, props.treeProps).forEach((row) => { const shouldSelect = isMatched(row); if (shouldSelect === currentlySelected.has(row)) return; table.toggleRowSelection(row, shouldSelect); }); } nextTick(() => { isSyncingSelection.value = false; }); }; onMounted(() => { watch(() => [props.selectColumns, props.data], syncSelectionFromModel, { immediate: true, flush: "post" }); }); context.expose({ cipTableRef, removeSelection }); const updateData = (val, index) => { const dataIndexed = analyseData(props.data, props.treeProps); const path = dataIndexed[index]; const propertyKey = getPropertyKeyByPath(path, props.treeProps); const data = props.data; setFieldValue(data, propertyKey, val, true); context.emit("update:data", data); }; const onSortChange = ({ prop, order }) => { context.emit("sort", { prop, order }); }; const onFilterChange = (filters) => { if (props.filterModel !== void 0) { context.emit("update:filterModel", mergeTableFilterModel(props.filterModel, tableFilteredValuesToModel(filters, filterableColumns.value), filterableColumns.value)); } context.emit("filter-change", filters); }; const onSelectionChange = (val) => { if (isSyncingSelection.value) return; emitSelectColumns(val); }; const addBorderWidth = computed(() => { return _border.value ? 1 : 0; }); const transformWidth = (widthStr) => { const applyPx = calculateCurrentWidthFn.value; if (typeof widthStr === "number") return Math.ceil(applyPx(widthStr)); if (widthStr.indexOf("px") > -1) return `${Math.ceil(applyPx(Number(widthStr.replace(/px$/, ""))))}px`; return widthStr; }; const renderTableColumn = ({ key, config } = { key: "", config: {} }) => { var _b; const _a = config, { children, type, formatter, columnType, textLevel, tableFormatter, filters, filter, filterPlacement, filterMultiple, filterMethod, filteredValue, columnKey: configColumnKey } = _a, tableColumnConfig = __objRest(_a, [ "children", "type", "formatter", "columnType", "textLevel", "tableFormatter", "filters", "filter", "filterPlacement", "filterMultiple", "filterMethod", "filteredValue", "columnKey" ]); const resolvedColumnKey = configColumnKey != null ? configColumnKey : key; const columnConfigRecord = config; const columnFilterProps = {}; if (filters !== void 0) columnFilterProps.filters = filters; const resolvedFilterPlacement = filterPlacement != null ? filterPlacement : typeof filter === "string" ? filter : void 0; if (resolvedFilterPlacement !== void 0) columnFilterProps.filterPlacement = resolvedFilterPlacement; const resolvedFilterMultiple = filterMultiple != null ? filterMultiple : columnConfigRecord["filter-multiple"]; if (resolvedFilterMultiple !== void 0) columnFilterProps.filterMultiple = resolvedFilterMultiple; const resolvedFilterMethod = filterMethod != null ? filterMethod : columnConfigRecord["filter-method"]; if (resolvedFilterMethod !== void 0) columnFilterProps.filterMethod = resolvedFilterMethod; if (tableFilteredValues.value !== void 0) { if (filters !== void 0) { columnFilterProps.filteredValue = (_b = tableFilteredValues.value[key]) != null ? _b : []; } } else { const resolvedFilteredValue = filteredValue != null ? filteredValue : columnConfigRecord["filtered-value"]; if (resolvedFilteredValue !== void 0) columnFilterProps.filteredValue = resolvedFilteredValue; } if (!tableColumnConfig.width) { if (config.type === "date" && config.viewType === "datetime") { tableColumnConfig.width = dateColumnWidthMap[_size.value]; } } else { tableColumnConfig.width = transformWidth(tableColumnConfig.width); } if (tableColumnConfig.minWidth) { tableColumnConfig.minWidth = transformWidth(tableColumnConfig.minWidth); } const headerSlots = ({ column, $index }) => { var _a2; if ((_a2 = config.slots) == null ? void 0 : _a2.header) { return config.slots.header({ column, $index, config, key }); } const result = [config.label]; if (config.description) { const descriptionComp = createVNode(ElTooltip, { "effect": config.descriptionEffect || "light", "placement": "top" }, { content: () => config.description, default: () => createVNode(ElIcon, { "style": "", "class": "cip-table__header-hint" }, { default: () => [createVNode(Hint, null, null)] }) }); result.push(descriptionComp); } if (config.required === true && config.writable === true) { const requiredAsterisk = createVNode("span", { "class": ["cip-danger-color"], "style": { marginRight: "4px" } }, [createTextVNode("*")]); result.unshift(requiredAsterisk); } return createVNode("div", { "class": "cip-table__header-cell" }, [result]); }; let dataIndexed; if (props.rowKey) { dataIndexed = analyseData(props.data, props.treeProps); } if (columnType === "checkbox") { const { trueLabel, falseLabel, selectable } = tableColumnConfig; return createVNode(TableSelectionColumn, { "trueLabel": trueLabel, "falseLabel": falseLabel, "selectable": selectable, "prop": key, "data": props.data, "label": config.label }, null); } const textLevelClass = textLevel ? `text-${textLevel}` : columnType === "mainField" ? "text-primary" : void 0; return h(ElTableColumn, __spreadValues(__spreadValues({ prop: key, align: config.type === "number" ? "right" : _defaultAlign.value, // 针对数字类型进行居右优化 style: "display: flex;", className: textLevelClass, formatter: tableFormatter, columnKey: resolvedColumnKey }, tableColumnConfig), columnFilterProps), { header: headerSlots, "filter-icon": _filterIcon.value, default: ({ row, $index, column }) => { if (isArray(config.children) && config.children.length > 0) { return renderTableColumns(config.children); } else { if ($index < 0) return null; if (!["default", "append", "prepend", "expand", "_handler", "$handler"].includes(key) && context.slots[key]) { return context.slots[key]({ row, $index, column }); } if (context.slots[`${key}Slot`]) { return context.slots[`${key}Slot`]({ row, $index, column }); } let propertyKey = $index; if (dataIndexed) { const path = dataIndexed[$index]; if (path) { propertyKey = (path == null ? void 0 : path.length) > 1 ? getPropertyKeyByPath(path, props.treeProps) : path[0]; } } const inputProps = { config, // 去除$render fieldKey: props.fieldKey || "", index: $index, model: row, key, tableRuleKey: props.ruleKey, propertyKey, columnKey: resolvedColumnKey, tableDependOnValues: props.dependOnValues, tableData: props.data, rowEdit: props.editType === "row" ? editRowIdx.value === $index : true, updateData }; if (typeof config.__render === "function") { return config.__render(__spreadProps(__spreadValues({}, inputProps), { row, $index, $position: "table" })); } if (columnType === "mainField") { return h(CipButtonText, { onClick: () => { context.emit("mainFieldClick", { row, $index }); } // @ts-ignore }, () => h(ColumnInput, inputProps)); } return h(ColumnInput, inputProps); } } }); }; const editRowIdx = ref(-1); const handlerOutClick = () => { editRowIdx.value = -1; document.removeEventListener("click", handlerOutClick); }; const onRowClick = (row, column, event) => { if (event) { event.stopPropagation(); } document.addEventListener("click", handlerOutClick); const idx = props.data.findIndex((v) => v === row); editRowIdx.value = idx; context.emit("row-click", row, column, event); }; const renderTableColumns = (columns = []) => { if (!isArray(columns)) { throw new Error("function renderTableColumns param columns must be array"); } return columns.filter((column) => !column.config.hideItem).map((column) => renderTableColumn(column)); }; const TableColumns = () => { var _a; const slots = renderTableColumns(props.columns); if (isNotEmpty(props.offset) && props.offset > -1 && !props.hideIndex) { const indexColumn = h(ElTableColumn, { label: props.seqLabel || t("dr.table.index"), fixed: props.indexFixed ? "left" : "", align: _defaultAlign.value, width: transformWidth(isEmpty(props.rowKey) ? 55 : 75) }, { default: ({ $index }) => `${$index + 1 + props.offset}` }); slots.unshift(indexColumn); } if (props.selectType === "checkbox") { const option = { type: "selection", width: transformWidth(45), fixed: "left" }; if (isNotEmpty(props.selectable)) { option.selectable = (row, index) => props.selectable(row || {}, index); } if (props.reserveSelection) { if (!props.rowKey) { console.warn("[CipTable] reserveSelection \u9700\u8981\u914D\u5408 rowKey \u4E00\u8D77\u4F7F\u7528\uFF0C\u5426\u5219\u8DE8\u9875\u9009\u4E2D\u65E0\u6CD5\u751F\u6548"); } else { option.reserveSelection = true; } } const selectionColumn = h(ElTableColumn, option); slots.unshift(selectionColumn); } if (props.selectType === "radio") { const selectionColumn = h(ElTableColumn, { width: transformWidth(45), fixed: "left" }, { default: ({ row }) => { var _a2; return h(ElRadio, { label: (_a2 = props.selectLabel && row[props.selectLabel]) != null ? _a2 : row.id, modelValue: props.selectRadio, "onUpdate:modelValue": (val) => context.emit("update:selectRadio", val), disabled: props.selectable && !props.selectable(row) }, { default: () => "" }); } }); slots.unshift(selectionColumn); } if (context.slots.expand) { const expendColumn = h(ElTableColumn, { type: "expand", width: transformWidth(32), fixed: "left" }, { default: ({ row, index }) => context.slots.expand({ row, index }) }); slots.unshift(expendColumn); } if (props.withTableHandle && (context.slots._handler || context.slots.$handler)) { const handlerSlot = context.slots._handler || context.slots.$handler; const handlerColumn = h(ElTableColumn, { label: t("dr.table.handler"), fixed: "right", align: (_a = props.handlerAlign) != null ? _a : _defaultAlign.value, headerAlign: props.handlerHeaderAlign, width: props.handlerWidth ? transformWidth(props.handlerWidth) : handleColumnWidthMap[_size.value] + addBorderWidth.value }, { default: ({ row, $index }) => h(CipButtonCollapse, { limit: props.handlerLimit, row }, { default: () => handlerSlot({ row, $index }) }) }); slots.push(handlerColumn); } if (context.slots.default) { slots.push(context.slots.default()); } if (context.slots.prepend) { const prependSlots = context.slots.prepend(); if (isArray(prependSlots)) { slots.unshift(...prependSlots); } else { slots.unshift(prependSlots); } } if (context.slots.append) { const appendSlots = context.slots.append(); if (isArray(appendSlots)) { slots.push(...appendSlots); } else { slots.push(appendSlots); } } if (props.tableHeaderLabel) return h(ElTableColumn, { label: props.tableHeaderLabel, align: "center" }, { default: () => slots }); return slots; }; const EmptyBlock = () => { return createVNode("div", { "class": "cip-table__empty" }, [createVNode(EmptyStatus, { "class": "cip-table__empty__svg" }, null), createVNode("div", { "class": "cip-table__empty__text" }, [t("dr.table.emptyText")])]); }; return () => createVNode(ElTable, mergeProps({ "ref": cipTableRef, "size": _size.value }, context.attrs, { "class": "cip-table", "border": _border.value, "data": props.data, "height": props.height, "rowKey": props.rowKey, "treeProps": props.treeProps, "defaultExpandAll": props.defaultExpendAll, "onSort-change": onSortChange, "onFilter-change": onFilterChange, "onSelection-change": onSelectionChange, "onRow-click": onRowClick }), { default: () => TableColumns(), empty: () => createVNode(EmptyBlock, null, null) }); } }); export { index as default };