AddTable.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. import {
  2. forwardRef,
  3. useImperativeHandle,
  4. useMemo,
  5. useRef,
  6. useState,
  7. } from "react";
  8. import {
  9. Col,
  10. Form,
  11. Input,
  12. message,
  13. Modal,
  14. Row,
  15. Select,
  16. Tabs,
  17. TabsProps,
  18. } from "antd";
  19. import LangInput from "@/components/LangInput";
  20. import LangInputTextarea from "@/components/LangInputTextarea";
  21. import { TableType } from "@/enum";
  22. import { createColumn, createTable } from "@/utils";
  23. import { TableItemType } from "@/type";
  24. import { useModel, useRequest } from "umi";
  25. import {
  26. GetAllDesignTables,
  27. GetAllBusinessTableColumns,
  28. GetBusinessTablesByTableId,
  29. ListLangByKey,
  30. } from "@/api";
  31. import { validateTableCode, validateAliasName } from "@/utils/validator";
  32. import { pick } from "lodash-es";
  33. import CustomColorPicker from "@/components/CustomColorPicker";
  34. export default forwardRef(function AddTable(
  35. props: {
  36. onChange: (tables: TableItemType[]) => void;
  37. },
  38. ref
  39. ) {
  40. const [open, setOpen] = useState(false);
  41. const tableItemRef = useRef<TableItemType>();
  42. const { project, graph } = useModel("erModel");
  43. const [tabActiveKey, setTabActiveKey] = useState("1");
  44. const [form] = Form.useForm();
  45. const [form1] = Form.useForm();
  46. const [formModel, setFormModel] = useState<TableItemType["table"]>();
  47. const [hideAddTab, setHideAddTab] = useState(false);
  48. const [color, setColor] = useState<string>();
  49. useImperativeHandle(ref, () => ({
  50. open: () => {
  51. // 获取当前模型类型
  52. tableItemRef.current = createTable(project.type, project.id);
  53. setFormModel(tableItemRef.current.table);
  54. setOpen(true);
  55. setColor(undefined);
  56. },
  57. openImportMode: () => {
  58. setTabActiveKey("2");
  59. run();
  60. setHideAddTab(true);
  61. setOpen(true);
  62. },
  63. close: () => {
  64. setOpen(false);
  65. },
  66. }));
  67. const { data, loading, run } = useRequest(() => GetAllDesignTables(), {
  68. manual: true,
  69. });
  70. const tableOptions = useMemo(() => {
  71. const options =
  72. data?.result?.appBusinessTables
  73. ?.filter(
  74. (item: any) =>
  75. // 过滤当前数据表类型及存在相同schemaName、aliasName的表
  76. item?.type == project?.type
  77. // && !project.tables.find(
  78. // (tableItem) =>
  79. // tableItem.table.schemaName === item.schemaName ||
  80. // tableItem.table.aliasName === item.aliasName
  81. // )
  82. )
  83. ?.map((item: any) => {
  84. // 判断是否存在已引入的表
  85. const hasTable = project.tables.find(
  86. (tableItem: TableItemType) =>
  87. tableItem.table.schemaName === item.schemaName ||
  88. tableItem.table.aliasName === item.aliasName
  89. );
  90. return {
  91. label: `${item?.schemaName}(${item.name})`,
  92. value: item?.id,
  93. disabled: hasTable,
  94. };
  95. }) || [];
  96. return options;
  97. }, [data]);
  98. const items: TabsProps["items"] = [
  99. {
  100. key: "1",
  101. label: `新建`,
  102. children: (
  103. <div>
  104. <Form labelCol={{ span: 8 }} form={form}>
  105. <Row gutter={16}>
  106. <Col span={12}>
  107. <Form.Item
  108. label="编码"
  109. name="schemaName"
  110. rules={[
  111. { required: true, message: "请输入编码" },
  112. validateTableCode,
  113. ]}
  114. tooltip="包含字母、下划线、数字, 必须小写字母开头,且必须有下划线! 如:user_info"
  115. >
  116. <Input
  117. placeholder="请输入"
  118. value={formModel?.schemaName}
  119. onChange={(e) => handleChange("schemaName", e.target.value)}
  120. />
  121. </Form.Item>
  122. </Col>
  123. <Col span={12}>
  124. <Form.Item label="表类型" name="type">
  125. <Input
  126. placeholder="请输入"
  127. value={
  128. formModel?.type == TableType.BusinessTable
  129. ? "业务表"
  130. : "视图表"
  131. }
  132. disabled
  133. />
  134. </Form.Item>
  135. </Col>
  136. </Row>
  137. <Row gutter={16}>
  138. <Col span={12}>
  139. <Form.Item
  140. label="别名"
  141. name="aliasName"
  142. rules={[
  143. { required: true, message: "请输入别名" },
  144. validateAliasName,
  145. ]}
  146. tooltip="包含字母、数字, 必须小写字母开头! 如:userinfo"
  147. >
  148. <Input
  149. placeholder="请输入"
  150. value={formModel?.aliasName}
  151. onChange={(e) => handleChange("aliasName", e.target.value)}
  152. />
  153. </Form.Item>
  154. </Col>
  155. <Col span={12}>
  156. <Form.Item label="表名" name="langNameList">
  157. <LangInput
  158. value={formModel?.langNameList}
  159. onChange={(lang) => handleChange("langNameList", lang)}
  160. />
  161. </Form.Item>
  162. </Col>
  163. </Row>
  164. <Row gutter={16}>
  165. <Col span={24}>
  166. <Form.Item
  167. label="描述"
  168. labelCol={{ span: 4 }}
  169. name="langDescriptionList"
  170. >
  171. <LangInputTextarea
  172. value={formModel?.langDescriptionList}
  173. onChange={(lang) =>
  174. handleChange("langDescriptionList", lang)
  175. }
  176. />
  177. </Form.Item>
  178. </Col>
  179. </Row>
  180. </Form>
  181. </div>
  182. ),
  183. },
  184. {
  185. key: "2",
  186. label: `引入`,
  187. children: (
  188. <div>
  189. <Form labelCol={{ span: 4 }} form={form1}>
  190. <Form.Item
  191. label="选择表"
  192. name="table"
  193. rules={[{ required: true, message: "请选择表" }]}
  194. >
  195. <Select
  196. mode="multiple"
  197. placeholder="请选择"
  198. loading={loading}
  199. options={tableOptions}
  200. />
  201. </Form.Item>
  202. <Form.Item label="颜色" name="color">
  203. <CustomColorPicker onChange={setColor}>
  204. {color ? (
  205. <div
  206. className="rounded-4px cus-btn w-32px h-32px bg-#eee flex-none cursor-pointer shadow-inner"
  207. style={{ background: color || "#eee" }}
  208. ></div>
  209. ) : (
  210. <span className="bg-#eee px-5px py-3px rounded-4px cursor-pointer text-12px text-#666">
  211. 随机生成,点击可选择颜色
  212. </span>
  213. )}
  214. </CustomColorPicker>
  215. </Form.Item>
  216. </Form>
  217. </div>
  218. ),
  219. },
  220. ];
  221. const handleChange = (key: string, value: any) => {
  222. formModel &&
  223. setFormModel({
  224. ...formModel,
  225. [key]: value,
  226. });
  227. };
  228. // 获取引入的表转换成模型表
  229. const getNewTableByTable = async (
  230. tableData: any,
  231. columns: any[],
  232. tableOther: Record<string, any> = {}
  233. ): Promise<TableItemType> => {
  234. const newTable = createTable(project.type, project.id);
  235. const langKeyList: string[] = [];
  236. if (tableData.langName) {
  237. langKeyList.push(tableData.langName);
  238. }
  239. if (tableData.langDescription) {
  240. langKeyList.push(tableData.langDescription);
  241. }
  242. columns.forEach((item) => {
  243. if (item.langName) {
  244. langKeyList.push(item.langName);
  245. }
  246. });
  247. // 获取全部多语言数据
  248. const langList = await Promise.all(
  249. [...new Set(langKeyList)].map((key) =>
  250. ListLangByKey({ key }).then((res) => res.result)
  251. )
  252. );
  253. const langName = langList.find((item) => item.key === tableData.langName);
  254. const descName = langList.find(
  255. (item) => item.key === tableData.langDescription
  256. );
  257. return {
  258. isTable: true,
  259. // 表格数据
  260. table: {
  261. ...newTable.table,
  262. ...pick(tableData, ["schemaName", "aliasName", "isDeleted"]),
  263. langNameList: [
  264. { name: "zh-CN", value: langName?.["zh-CN"] || "" },
  265. { name: "en", value: langName?.["en"] || "" },
  266. ],
  267. langDescriptionList: [
  268. { name: "zh-CN", value: descName?.["zh-CN"] || "" },
  269. { name: "en", value: descName?.["en"] || "" },
  270. ],
  271. ...tableOther,
  272. },
  273. // 字段数据
  274. tableColumnList: columns.map((item) => {
  275. const column = createColumn(newTable.table.id);
  276. const langName = langList.find((lang) => lang.key === item.langName);
  277. return {
  278. ...column,
  279. ...pick(item, Object.keys(column)),
  280. langNameList: [
  281. { name: "zh-CN", value: langName?.["zh-CN"] || "" },
  282. { name: "en", value: langName?.["en"] || "" },
  283. ],
  284. };
  285. }),
  286. };
  287. };
  288. const [loadingColumns, setLoadingColumns] = useState(false);
  289. const handleOk = () => {
  290. // 新建
  291. if (tabActiveKey === "1") {
  292. form.validateFields().then(() => {
  293. if (tableItemRef.current && formModel) {
  294. props.onChange([
  295. {
  296. ...tableItemRef.current,
  297. table: formModel,
  298. },
  299. ]);
  300. }
  301. form.resetFields();
  302. setOpen(false);
  303. });
  304. }
  305. // 引入
  306. if (tabActiveKey === "2") {
  307. form1.validateFields().then(async () => {
  308. // 加载表格字段
  309. const values = form1.getFieldsValue();
  310. try {
  311. setLoadingColumns(true);
  312. const requestList = values.table.map((tableId: string) => [
  313. GetBusinessTablesByTableId(tableId),
  314. GetAllBusinessTableColumns({
  315. currentPage: 1,
  316. pageSize: 2000,
  317. orderByProperty: "isPreDefined DESC, DisplayOrder",
  318. Ascending: true,
  319. totalPage: 1,
  320. totalCount: 1,
  321. filters: [
  322. {
  323. name: "BusinessTableId",
  324. value: tableId,
  325. },
  326. ],
  327. }),
  328. ]);
  329. if (requestList.length === 0) {
  330. message.error("请选择要引入的表");
  331. return;
  332. }
  333. const resArr = await Promise.allSettled(
  334. (requestList as Promise<any>[]).flat(1)
  335. );
  336. const tableMap: Record<string, any> = {};
  337. resArr.forEach((res) => {
  338. if (res.status === "fulfilled") {
  339. const value = res.value?.result;
  340. // 表格数据
  341. if (Array.isArray(value) && value[0]) {
  342. tableMap[value[0].id] = {
  343. table: value[0],
  344. tableColumnList: [],
  345. };
  346. } else {
  347. // 字段数据
  348. const model = res.value?.result?.model;
  349. const tableId = model?.[0]?.businessTableId;
  350. if (tableId) {
  351. if (tableMap[tableId]) {
  352. tableMap[tableId].tableColumnList = model;
  353. } else {
  354. tableMap[tableId] = {
  355. table: {},
  356. tableColumnList: model,
  357. };
  358. }
  359. }
  360. }
  361. }
  362. });
  363. const rect = graph?.getAllCellsBBox();
  364. // 计算起始位置 默认往最后加
  365. const startY = (rect?.height || 0) + (rect?.y || 0) + 20;
  366. const result = Object.keys(tableMap).map(async (key, index) => {
  367. const table = await getNewTableByTable(
  368. tableMap[key].table,
  369. tableMap[key].tableColumnList
  370. );
  371. table.table.style.y = startY;
  372. table.table.style.x =
  373. 100 + index * (project.setting.tableWidth + 20);
  374. if (color) {
  375. table.table.style.color = color;
  376. }
  377. return table;
  378. });
  379. const newTables = await Promise.all(result);
  380. props.onChange(newTables);
  381. form1.resetFields();
  382. setOpen(false);
  383. } catch (err) {
  384. console.error(err);
  385. message.warning("引入失败");
  386. } finally {
  387. setLoadingColumns(false);
  388. }
  389. });
  390. }
  391. };
  392. const handleChangeTableActiveKey = (key: string) => {
  393. setTabActiveKey(key);
  394. if (key === "2") {
  395. run();
  396. }
  397. };
  398. return (
  399. <Modal
  400. open={open}
  401. title="添加表"
  402. okText={loadingColumns ? "加载中..." : "确定"}
  403. cancelText="取消"
  404. onCancel={() => setOpen(false)}
  405. onOk={handleOk}
  406. okButtonProps={{
  407. loading: loadingColumns,
  408. }}
  409. >
  410. <Tabs
  411. items={items.filter((item) => (hideAddTab ? item.key === "2" : true))}
  412. activeKey={tabActiveKey}
  413. onChange={handleChangeTableActiveKey}
  414. />
  415. </Modal>
  416. );
  417. });