import { Framework, handleComponentEvent, Page, RockInstanceContext, type Rock, type RockChildrenConfig, type RockConfig, type RockEvent, } from "@ruiapp/move-style"; import { renderRock, renderRockChildren } from "@ruiapp/react-renderer"; import RapidEntityListMeta from "./RapidEntityListMeta"; import type { RapidEntityListRockConfig, RapidEntityListState } from "./rapid-entity-list-types"; import { filter, findIndex, forEach, isArray, isEmpty, map, merge, reject, set, trim, uniq } from "lodash"; import rapidAppDefinition from "../../rapidAppDefinition"; import { generateRockConfigOfError } from "../../rock-generators/generateRockConfigOfError"; import type { RapidEntity, RapidField } from "@ruiapp/rapid-common"; import type { EntityStore, EntityStoreConfig } from "../../stores/entity-store"; import RapidExtensionSetting from "../../RapidExtensionSetting"; import { RapidEntityListFilterCache } from "../rapid-entity-search-form/RapidEntitySearchForm"; import { parseRockExpressionFunc } from "../../utils/parse-utility"; import { getExtensionLocaleStringResource, getMetaPropertyLocaleName } from "../../helpers/i18nHelper"; import { getEntityPropertyByFieldNames } from "../../helpers/metaHelper"; import { RapidTableColumnConfig } from "../rapid-table-column/rapid-table-column-types"; export function autoConfigTableColumnToRockConfig(context: RockInstanceContext, parentProps: any, column: RapidTableColumnConfig, mainEntity: RapidEntity) { const { framework, logger, page } = context; if (column.$exps) { page.interpreteComponentProperties(null, column as any, { $self: column, $parent: parentProps, }); } let cell: RockConfig | RockConfig[] | null = null; let columnTitle = column.title; let rpdField: RapidField | undefined; if (mainEntity) { const fieldName = column.fieldName || column.code || ""; const fieldNameParts = fieldName.split("."); const result = getEntityPropertyByFieldNames(rapidAppDefinition.getAppDefinition(), mainEntity, fieldNameParts); rpdField = result.property; if (!rpdField) { logger.warn(parentProps, `Unknown field name '${fieldName}'`); } else { if (!columnTitle) { columnTitle = getMetaPropertyLocaleName(framework, result.entity, rpdField); } } } if (column.children) { return { $type: "rapidTableColumn", title: columnTitle, children: map(column.children, (childColumn) => autoConfigTableColumnToRockConfig(context, parentProps, childColumn, mainEntity)), }; } if (column.cell) { cell = column.cell; } else if (column.type === "link") { const url: string | undefined = column.rendererProps?.url; const text: string | undefined = column.rendererProps?.text; if (url) { cell = { $type: "anchor", href: url, children: { $type: "text", $exps: { text: text ? `$rui.execVarText('${text}', $slot.record)` : "$slot.value", }, }, $exps: { href: `$rui.execVarText('${url}', $slot.record)`, ...(column.rendererProps?.$exps || {}), }, }; } } else { let fieldType = column.fieldType || rpdField?.type || "text"; let rendererType = column.rendererType || RapidExtensionSetting.getDefaultRendererTypeOfFieldType(fieldType); let defaultRendererProps: any = RapidExtensionSetting.getDefaultRendererProps(fieldType, rendererType); let fieldTypeRelatedRendererProps: any = {}; if (rpdField) { if (fieldType === "option" || fieldType === "option[]") { fieldTypeRelatedRendererProps = { dictionaryCode: rpdField.dataDictionary, }; } else if ((fieldType === "relation" || fieldType === "relation[]") && !column.rendererType) { if (rpdField.relation === "many") { rendererType = "rapidArrayRenderer"; } else { rendererType = "rapidObjectRenderer"; } const relationEntity = rapidAppDefinition.getEntityBySingularCode(rpdField.targetSingularCode); if (relationEntity?.displayPropertyCode) { fieldTypeRelatedRendererProps.format = `{{${relationEntity.displayPropertyCode}}}`; } } } cell = { $type: rendererType, ...defaultRendererProps, ...fieldTypeRelatedRendererProps, ...column.rendererProps, $exps: { value: "$slot.value", ...(column.rendererProps?.$exps || {}), }, }; } const tableColumnRock: RockConfig = { ...column, title: columnTitle, $type: "rapidTableColumn", cell, }; return tableColumnRock; } export default { onResolveState(props, state) { return { selectedIds: [], }; }, onInit(context, props) { if (props.dataSourceType === "dataSource") { return; } const entityCode = props.entityCode; if (!entityCode) { return; } const mainEntity = rapidAppDefinition.getEntityByCode(entityCode); if (!mainEntity) { return; } const storeScope = props.useStoreInPageScope ? context.page.scope : context.scope; const dataSourceCode = props.dataSourceCode || "list"; if (!storeScope.stores[dataSourceCode]) { const { columns, pageSize } = props; const properties: string[] = uniq( props.queryProperties || [ "id", ...map( filter(columns, (column) => !!column.code), (column) => column.code, ), ...(props.extraProperties || []), ], ); const listDataStoreConfig: EntityStoreConfig = { type: "entityStore", name: dataSourceCode, entityModel: mainEntity, fixedFilters: props.fixedFilters, keepNonPropertyFields: props.keepNonPropertyFields, includingSoftDeleted: props.includingSoftDeleted, properties, relations: props.relations, eventLog: props.eventLog, orderBy: props.orderBy || mainEntity.defaultOrderBy || [ { field: "id", }, ], pagination: pageSize > 0 ? { limit: pageSize, offset: ((props.pageNum || 1) - 1) * pageSize, } : undefined, }; // 启用高级查询参数缓存 & 获取并使用参数缓存 if (props.enabledFilterCache && props.filterCacheName) { if (isArray(props.cacheFilters) && !isEmpty(props.cacheFilters)) { set(listDataStoreConfig, "filters", props.cacheFilters); } } storeScope.addStore(listDataStoreConfig); } }, onReceiveMessage(message, state, props, rockInstance) { if (message.name === "refreshView") { if (props.dataSourceType === "dataSource") { return; } const scope = props.useStoreInPageScope ? rockInstance._context.page.scope : rockInstance._scope; scope.stores[props.dataSourceCode]?.loadData(); } }, Renderer(context, props, state) { const { framework, logger, page } = context; const entityCode = props.entityCode; let mainEntity: RapidEntity | undefined; if (entityCode) { mainEntity = rapidAppDefinition.getEntityByCode(entityCode); if (!mainEntity) { const errorRockConfig = generateRockConfigOfError(new Error(`Entitiy with code '${entityCode}' not found.`)); return renderRock({ context, rockConfig: errorRockConfig }); } } const dataSourceCode = props.dataSourceCode || "list"; const tableColumnRocks: RockConfig[] = []; const storeScopeVarExp = props.useStoreInPageScope ? "$page.scope" : "$scope"; if (props.showRowNumColumn) { const tableRowNumColumnRock: RockConfig = { $type: "rapidTableColumn", title: "#", code: "id", key: "_rowNum", width: "50px", align: "right", cell: { $type: "text", $exps: { text: `(((${storeScopeVarExp}.vars["${`stores-${dataSourceCode}-pageNum`}"] || 1) - 1) * ${props.pageSize} + $slot.index + 1).toString()`, }, }, }; tableColumnRocks.push(tableRowNumColumnRock); } props.columns.forEach((column) => { const tableColumnRock = autoConfigTableColumnToRockConfig(context, props, column, mainEntity); tableColumnRocks.push(tableColumnRock); }); if (!props.hideActionsColumn) { forEach(props.actions, (recordActionConfig) => { set(recordActionConfig, "$exps.record", "$slot.record"); set(recordActionConfig, "$exps.recordId", "$slot.record.id"); }); if (props.actions && props.actions.length) { const tableActionsColumnRock: RockConfig = { $type: "rapidTableColumn", title: getExtensionLocaleStringResource(framework, "operations"), code: "id", key: "_actions", width: props.actionsColumnWidth || "150px", fixed: "right", cell: props.actions, }; tableColumnRocks.push(tableActionsColumnRock); } } let rowSelection = props.rowSelection; const selectionMode = props.selectionMode || "multiple"; if (selectionMode !== "none") { rowSelection = { ...rowSelection, type: selectionMode === "multiple" ? "checkbox" : "radio", onChange: [ { $action: "setVars", $exps: { [`vars.${props.$id}-selectedIds`]: "$event.args[0]", [`vars.${props.$id}-selectedRecords`]: "$event.args[1]", }, }, { $action: "handleEvent", eventName: "onSelectedIdsChange", handlers: props.onSelectedIdsChange, $exps: { args: "[{selectedIds: $event.args[0], selectedRecords: $event.args[1]}]", }, }, ], }; } const dataSourceTotal = (props.dataSource || []).length; const scopeVarExp = "$scope"; let tableExps: Record = { pagination: props.pageSize > 0 ? `{pageSize: ${props.pageSize}, current: ${storeScopeVarExp}.vars["${`stores-${dataSourceCode}-pageNum`}"], total: ${dataSourceTotal} }` : "false", }; if (props.dataSourceType !== "dataSource") { tableExps = { dataSource: `${storeScopeVarExp}.stores.${dataSourceCode}?.data?.list`, pagination: props.pageSize > 0 ? `{pageSize: ${ props.pageSize }, current: ${storeScopeVarExp}.vars["${`stores-${dataSourceCode}-pageNum`}"], total: ${storeScopeVarExp}.stores.${dataSourceCode}?.data?.total}` : "false", }; } if (typeof props.getRowSelectionCheckboxProps === "string" && trim(props.getRowSelectionCheckboxProps)) { rowSelection = merge({}, rowSelection, { getCheckboxProps: (record) => { const adapter = parseRockExpressionFunc(props.getRowSelectionCheckboxProps, { record }, context); return adapter(); }, }); } const tableRockConfig: RockConfig = { $id: `${props.$id}-table`, $type: "rapidTable", $exps: { ...tableExps, ...(selectionMode !== "none" ? { "rowSelection.selectedRowKeys": `${scopeVarExp}.vars['${props.$id}-selectedIds']`, } : {}), }, tableAutoHeight: props.tableAutoHeight, size: "small", rowKey: "id", rowSelection, columns: tableColumnRocks, virtual: props.virtual, dataSource: props.dataSource, expandedRow: props.expandedRow, showHeader: props.showHeader, ...props.tableProps, convertListToTree: props.convertListToTree, dataSourceAdapter: props.dataSourceAdapter, beforeSubmitFormDataAdapter: props.beforeSubmitFormDataAdapter, listIdField: props.listIdField, listParentField: props.listParentField, treeChildrenField: props.treeChildrenField, treeTopParentValue: props.treeTopParentValue, onRowClick: props.selectOnClickRow ? [ { $action: "script", script: async (event: RockEvent) => { const { framework, page, scope } = event; const storeScope = props.useStoreInPageScope ? page.scope : scope; let nextSelectedIds = []; let nextSelectedRecords = []; const { record } = event.args[0]; const recordId = record.id; if (selectionMode === "single") { nextSelectedIds.push(recordId); nextSelectedRecords.push(record); } else if (selectionMode === "multiple") { const currentSelectedIds = scope.vars[`${props.$id}-selectedIds`] || []; const currentSelectedRecords = scope.vars[`${props.$id}-selectedRecords`] || []; if (findIndex(currentSelectedIds, (item) => item === recordId) === -1) { nextSelectedIds = [...currentSelectedIds, recordId]; nextSelectedRecords = [...currentSelectedRecords, record]; } else { nextSelectedIds = reject(currentSelectedIds, (item) => item === recordId); nextSelectedRecords = reject(currentSelectedRecords, (item) => item.id === recordId); } } scope.setVars({ [`${props.$id}-selectedIds`]: nextSelectedIds, [`${props.$id}-selectedRecords`]: nextSelectedRecords, }); handleComponentEvent("onSelectedIdsChange", framework, page as any, scope, props, props.onSelectedIdsChange, [ { selectedIds: nextSelectedIds, selectedRecords: nextSelectedRecords, }, ]); }, }, ] : null, onChange: [ { $action: "script", script: async (event: RockEvent) => { const [pagination] = event.args; const storeScope = props.useStoreInPageScope ? page.scope : event.scope; storeScope.setVars({ [`stores-${dataSourceCode}-pageNum`]: pagination.current, }); if (props.dataSourceType === "dataSource") { return; } // 启用高级查询参数缓存 & 设置参数缓存 if (props.enabledFilterCache && props.filterCacheName) { RapidEntityListFilterCache.set(props.filterCacheName, { pageNum: pagination.current || 1 }); } const store: EntityStore = storeScope.stores[dataSourceCode] as any; store.setPagination({ limit: props.pageSize, offset: ((pagination.current || 1) - 1) * props.pageSize, }); await store.loadData(); }, }, ], }; const rockChildrenConfig: RockChildrenConfig = [tableRockConfig]; return renderRockChildren({ context, rockChildrenConfig }); }, ...RapidEntityListMeta, } as Rock;