UNPKG

sunmao-sdk

Version:

榫卯-开箱即用赋能-sdk

621 lines (585 loc) 18.3 kB
import React, { useState, useEffect, useRef } from "react"; import lodash from "lodash"; import TR from "./../component/TR"; import ModalFactory from "./../component/ModalFactory"; import CustomHeaderModal from "./../component/CustomHeaderModal"; import { handleAppParams, postNew } from "./../net/request"; import * as formUtils from "./../utils/formUtils"; import * as commonUtils from "./../utils/commonUtils"; import { setObject } from "./../utils/localStorageUtils"; import { CP } from ".."; import { aclCheckPermissions, getHsfHost } from "../net/api"; const displayName = "CpTable"; const CpTable = props => { const { customKey, schema, api = {}, tableProps, initData, filterParams, filterColumns, refreshColumns, filterTableBtn, filterRowBtn, getCheckboxProps, rowSelectionProps, widgets, tableTitle, searchResponse, ...otherProps } = props; const requestFunc = CP.getCPInfo().requestFunc || postNew; const apis = { ...api }; const tableRef = useRef(); const hasPageSchema = useRef(false); const pageInfo = useRef(formUtils.defaultPageInfo()); const [tableConfig, setTableConfig] = useState(null); // 自定义查询、表头 const [showCustomColumns, setShowCustomColumns] = useState(false); const [showCustomSearch, setShowCustomSearch] = useState(false); const customColumnsInfo = useRef({}); const customSearchInfo = useRef({}); useEffect(() => { if (schema) { try { pageInfo.current = schema; hasPageSchema.current = true; resetTableConfig(initData); } catch (e) { commonUtils.log(e); } } }, [schema]); useEffect(() => { if ( tableRef.current && hasPageSchema.current && !commonUtils.isEmptyObj(initData) ) { const search = { ...tableRef.current.getState().search, ...initData }; tableRef.current.setState({ search }); setTimeout(() => { tableRef.current.refresh(); }, 100); } }, [initData]); useEffect(() => { if (tableRef.current && refreshColumns) { resetTableConfig(tableRef.current.getState().search); } }, [refreshColumns]); useEffect(() => { if (tableRef.current) { tableRef.current.setTitle(tableTitle); } }, [tableTitle]); const resetTableConfig = async (search = {}) => { const { table, form, url, tableBtn, handle, tab, autoSearch } = pageInfo.current; const { btn: tableHandle, acl: tableAcl, openCustomColumns } = formUtils.getTableBtn(tableBtn?.handleItems); const { btn: rowHandle, acl: rowAcl } = formUtils.getTableHandle( handle?.handleItems ); const listAction = `$func.${url ? "onSdkSearch" : "getList"}`; const { btn: tabHandle, acl: tabAcl } = formUtils.getTableTab( // TODO 缺少tab的权限控制 tab?.handleItems, listAction ); const permissionNames = Array.from( new Set([...tableAcl, ...rowAcl, ...tabAcl]) ); let aclCheckPermissionResults = []; // 自定义表列宽度 const resizeColumns = formUtils.getDicTrue(tableBtn?.resizeColumns); // 自定义表头控制 const customColumns = openCustomColumns || formUtils.getDicTrue(tableBtn?.customColumns); // 自定义查询项 const customSearch = formUtils.getDicTrue(tableBtn?.customSearch); // 表查询 const searchList = form?.formItems || []; // 显示查询list // 获取缓存查询list user+页面标识+类型(search/columns) let lastSearchList = CP.customConfigMap[customKey + "search"]; if (customSearch) { // 查询list 新旧merge // 有缓存信息时,根据用户信息处理 const defaultList = searchList.filter( item => item.type !== "gudingcanshu_yincangbuxianshi" // 隐藏传参,不展示 ; 但需放置from表单中 ); lastSearchList = mergeList(lastSearchList, defaultList, "key"); // 弹框默认信息 customSearchInfo.current = { defaultList, cacheList: lastSearchList }; } // 初始化查询值 let initialValue = { // ...(commonUtils.isObj(initTmpData) ? initTmpData : {}), // initTmpData 通过search传入,则注释 ...search }; // 是否多选 const rowSelection = formUtils.getDicTrue(tableBtn?.rowSelection); // 枚举 赋值 const _columns = await formUtils.getTableColumns(table?.columnItems); // 显示表列list // 获取缓存表列list user+页面标识+类型(search/columns) let lastColumnList = CP.customConfigMap[customKey + "columns"]; // if (customColumns) { // 不管有没有,都赋值数据, // 查询list 新旧merge // 有缓存信息时,根据用户信息处理 lastColumnList = mergeList(lastColumnList, _columns, "dataIndex"); // 弹框默认信息 customColumnsInfo.current = { defaultList: _columns, cacheList: lastColumnList }; // } const filterSchema = commonUtils.getFunc(form?.filterSchemaFunc, apis); // frSchema 支持混合开发 const _frSchema = formUtils.listTranslSchema( customSearch ? lastSearchList : searchList, 4, initialValue ); // 第二个参数需配置 const frSchema = filterSchema ? filterSchema(_frSchema) : _frSchema; // 混合开发后组装initialValue initialValue = { ...formUtils.getFRInitData(frSchema), ...initialValue }; // 获取隐藏固定传参 const defaultFormData = formUtils.getDefaultInitData(searchList); // merge初始值 frSchema.formData = { ...defaultFormData, ...initialValue }; // 结合用户缓存过滤 columns const showColumns = customColumns ? lastColumnList.filter(i => i.isSelected ?? true) : _columns || []; // 结合自定义函数 混合开发 过滤 columns const lastColumns = filterColumns ? filterColumns(showColumns, initialValue) : showColumns; // 对长column首项定位left处理 lastColumns.length > 8 && (lastColumns[0].fixed = "left"); // 生成schema const schema = { rowKey: tableBtn?.rowKey || "id", columns: lastColumns, tableConfig: { resizeColumns, customColumns: customColumns && !openCustomColumns, customSearch, setShowCustomColumns, setShowCustomSearch, resizeTable: columns => { // 开启自定义才有缓存功能 保存最新表头宽度数据 if (customColumns) { // 将变更后数据转为Map const newMap = commonUtils.arrayKeyToMap(columns, "dataIndex"); // 将宽度缓存 lastColumnList = lastColumnList.map(item => { if (newMap.has(item.dataIndex)) { item.width = newMap.get(item.dataIndex).width; } return item; }); // 保存表头,存入缓存 CP.customConfigMap[customKey + "columns"] = lastColumnList; setObject("sunmao_customConfigMap", CP.customConfigMap); setTimeout(() => { commonUtils.behaviorLog("滑动设置表列宽度"); }, 1); } }, rowSelection, getCheckboxProps, rowSelectionProps }, searchConfig: { searchTopRender: commonUtils.getFunc(form?.searchTopRender, apis), autoSearch: formUtils.getDicTrue( autoSearch || "5fb8b91ae2559fcd82cad4d2" ), // || (!commonUtils.isEmptyObj(initTmpData) && !tableRef.current), // 自动搜索,功能单一化,故注释 initialValue, // 恢复默认传参 ,表单级参数 initData: { ...initData, ...defaultFormData }, // 为页面级参数、可被search覆盖,不可缺失 schema: frSchema, tab: tabHandle ? 0 : -1, api: tabHandle || { text: "", action: listAction } }, actionConfig: { showCount: parseInt(handle?.showCount || "2"), fixed: "right" }, buttonMenu: filterTableBtn ? filterTableBtn(tableHandle) : tableHandle, actionList: filterRowBtn ? filterRowBtn(rowHandle) : rowHandle, scroll: { x: formUtils.getTableWidth(lastColumns) }, aclCheckPermissionResults: [], tableTitle, ...tableProps }; setTableConfig(schema); if (permissionNames.length) { postNew( getHsfHost() + aclCheckPermissions, { userId: CP.getCPInfo().extParams?.bucId, permissionNames }, "checkPermissionResults", {}, "[object Array]" ).then(res => { aclCheckPermissionResults = res.data; setTableConfig({ ...schema, aclCheckPermissionResults }); }); } }; /** * merge 缓存与线上数据 * @param {缓存数据} cacheList * @param {实时数据} newList * @param {数据key} primaryKey * @returns merge后数据 */ const mergeList = (cacheList, newList, primaryKey) => { let lastList = []; try { // 将最新数据转为Map const newMap = commonUtils.arrayKeyToMap(newList, primaryKey); // 删除无效item // 更新item最新信息,非必选项保留用户配置 let tmpItem; // 顺序优先缓存 cacheList.forEach(c => { // 最新对象 tmpItem = newMap.get(c[primaryKey]); if (tmpItem) { // item未失效 lastList.push({ ...tmpItem, width: c?.width, isSelected: formUtils.getDicTrue(tmpItem.isRequired) || c.isSelected, // 必选则必选中,再者为缓存情况(存在从非必选->必选 场景) selectedIndex: lastList.length }); } }); // 将最新有效缓存数据转为Map const cacheMap = commonUtils.arrayKeyToMap(lastList, primaryKey); // 将新增item依次插入尾部 newList.forEach(n => { if (!cacheMap.has(n[primaryKey])) { // 缓存不存在时(新增),加入list尾部 lastList.push({ isSelected: formUtils.getDicTrue( n.selectTrue || "5fb8b91ae2559fcd82cad4d2" ), // 默认支持配置 且默认选中 ...n, selectedIndex: lastList.length }); } }); } catch (e) { // 无缓存则初始化处理 commonUtils.log(e); lastList = newList.map((i, index) => ({ isSelected: formUtils.getDicTrue( i.selectTrue || "5fb8b91ae2559fcd82cad4d2" ), ...i, selectedIndex: index })); } return lastList; }; /** * 必备函数 * 表格请求函数 * 暂支持post请求,因get用长度限制,避免过多参数 * @param params 搜索项信息 */ const onSdkSearch = params => { const { url, okPath = "data", totalPath } = pageInfo.current; const { current, pageSize } = params; // 例如: 服务器返回数据结构 sdk所需数据结构 const handleRes = ({ data = [], total = 0, pageSize = 10, ...rest }) => ({ data, pageSize, total, ...rest }); return requestFunc( commonUtils.getUrl(url), handleAppParams(params, filterParams), okPath ) .then(res => { if (!res) throw new Error( "请求错误,自行处理,该请求可自行设计,只要返回正确数据格式即可!" ); const data = { current, pageSize }; // 兼容索引处理 精确处理 let list = commonUtils.getFirstList(res.exactData); if (list) data.data = list; else data.data = commonUtils.getFirstList(res.data) || []; // 数量总数 data.total = lodash.get(res, totalPath || "data.count", 0) || lodash.get(res, "data.total", 0); const endData = handleRes(data); searchResponse && searchResponse(endData); return endData; }) .catch(err => { console.error("err", err, displayName); }); }; const getList = () => { return new Promise((resolve, reject) => { try { const list = JSON.parse(pageInfo.current.table.mockColumn); resolve({ data: list, total: list.length }); } catch { reject("mock失败!"); } }); }; /** * 表格列操作区-暂为弹框操作 * @param record 行数据 * @param refresh 表格刷新函数 * @param handleInfo 操作信息 */ const onSdkTableHandle = (record, refresh, handleInfo) => { const { content, funcType } = handleInfo; const { formItems, name, url, okPath, okFunc, filterSchemaFunc, displayType } = content || {}; const apiUrl = commonUtils.getUrl(url); const params = { rowInfo: record, ...record }; switch (funcType) { case "34": // 直接请求 case "35": // 二次确认请求 reqHandle( apiUrl, okPath, commonUtils.getFunc(okFunc, apis), refresh, params ); break; case "36": // 表单弹框请求 const filterSchema = commonUtils.getFunc(filterSchemaFunc, apis); const listTranslSchema = formUtils.listTranslSchema( formItems, 2, record ); if (formUtils.getDicTrue(displayType)) listTranslSchema.displayType = "column"; formHandle( filterSchema ? filterSchema(listTranslSchema) : listTranslSchema, name, apiUrl, okPath, commonUtils.getFunc(okFunc, apis), refresh, params ); break; default: break; } }; /** * 表头操作区-暂为弹框操作 * @param data 表格数据 * @param refresh 表格刷新函数 * @param selectedKeys 选中行key数据,如id * @param selectedRows 选中行数据 * @param handleInfo 操作信息 */ const onSdkTableBtn = ({ data, refresh, selectedKeys, selectedRows, handleInfo, search }) => { const { content, funcType } = handleInfo; const { formItems, name, url, okPath, okFunc, filterSchemaFunc, displayType } = content || {}; const apiUrl = commonUtils.getUrl(url); const params = { selectedKeys, ...search }; try { // 自定义 多选查询 key params[pageInfo.current?.tableBtn?.rowSelectionCustomKey] = selectedKeys; } catch {} switch (funcType) { case "34": // 直接请求 case "35": // 二次确认请求 reqHandle( apiUrl, okPath, commonUtils.getFunc(okFunc, apis), refresh, filterParams ? filterParams(params, handleInfo) : params ); break; case "36": // 表单弹框请求 const filterSchema = commonUtils.getFunc(filterSchemaFunc, apis); const listTranslSchema = formUtils.listTranslSchema(formItems, 2); if (formUtils.getDicTrue(displayType)) { listTranslSchema.displayType = "column"; } formHandle( filterSchema ? filterSchema(listTranslSchema) : listTranslSchema, name, apiUrl, okPath, commonUtils.getFunc(okFunc, apis), refresh, params ); break; case "38": // 自定义表头配置 setShowCustomColumns(true); break; default: break; } }; const reqHandle = async (url, okPath, okFunc, refresh, params) => { let loading = ModalFactory.loading(); return requestFunc( url, handleAppParams(params), okPath, {}, false, loading ).then(res => { try { loading.destroy(); } catch {} if (okFunc) okFunc(res, refresh, commonUtils.splitParams(params)); else refresh && refresh(); }); }; /** * 按键事件 - 表单弹框 * @param formSchema 表单内容 * @param title 表单名称 * @param okPath 自定义请求成功标示 * @param url 请求url * @param okFunc 自定义成功调用函数 * @param refresh 表格刷新函数 */ const formHandle = ( formSchema, title, url, okPath, okFunc, refresh, params ) => ModalFactory.showModalForm({ formSchema, widgets, width: 1000, title, request: { okPath, url, params, handleOk: (formData, validate) => { if (validate.length) return false; return true; }, onSuccess: (res, formData) => { if (okFunc) okFunc(res, refresh, params, formData); else refresh && refresh(); } } }); return tableConfig ? ( <> <CustomHeaderModal fieldNames={{ behaviorName: "自定义表列展示", customKey: customKey + "columns", key: "dataIndex", label: "label" }} show={showCustomColumns} handleCancel={() => setShowCustomColumns(false)} onChange={() => { setShowCustomColumns(false); resetTableConfig(tableRef.current.getState().search); }} {...customColumnsInfo.current} /> <CustomHeaderModal fieldNames={{ behaviorName: "自定义查询展示", customKey: customKey + "search", key: "key", label: "label" }} show={showCustomSearch} handleCancel={() => setShowCustomSearch(false)} onChange={() => { setShowCustomSearch(false); resetTableConfig(tableRef.current.getState().search); }} {...customSearchInfo.current} /> <TR customKey={customKey} ref={tableRef} schema={tableConfig} api={{ getList, ...apis, onSdkTableHandle, onSdkTableBtn, onSdkSearch }} widgets={widgets} {...otherProps} /> </> ) : null; }; export default React.memo(CpTable);