sunmao-sdk
Version:
榫卯-开箱即用赋能-sdk
621 lines (585 loc) • 18.3 kB
JSX
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);