AddTable.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  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. TreeSelect,
  19. } from "antd";
  20. import LangInput from "@/components/LangInput";
  21. import LangInputTextarea from "@/components/LangInputTextarea";
  22. import { TableType } from "@/enum";
  23. import { createColumn, createTable } from "@/utils";
  24. import { TableItemType } from "@/type";
  25. import { useModel, useRequest } from "umi";
  26. import {
  27. // GetAllDesignTables,
  28. // GetAllBusinessTableColumns,
  29. // GetBusinessTablesByTableId,
  30. // ListLangByKey,
  31. GetCanUseTableList,
  32. ImportFromBusinessTables,
  33. } from "@/api";
  34. import { validateTableCode, validateAliasName } from "@/utils/validator";
  35. import { pick } from "lodash-es";
  36. import CustomColorPicker from "@/components/CustomColorPicker";
  37. export default forwardRef(function AddTable(
  38. props: {
  39. onChange: (tables: TableItemType[]) => void;
  40. },
  41. ref
  42. ) {
  43. const [open, setOpen] = useState(false);
  44. const tableItemRef = useRef<TableItemType>();
  45. const { project, graph } = useModel("erModel");
  46. const [tabActiveKey, setTabActiveKey] = useState("1");
  47. const [form] = Form.useForm();
  48. const [form1] = Form.useForm();
  49. const [formModel, setFormModel] = useState<TableItemType["table"]>();
  50. const [hideAddTab, setHideAddTab] = useState(false);
  51. const [color, setColor] = useState<string>();
  52. useImperativeHandle(ref, () => ({
  53. open: () => {
  54. // 获取当前模型类型
  55. tableItemRef.current = createTable(project.type, project.id);
  56. setFormModel(tableItemRef.current.table);
  57. setOpen(true);
  58. setColor(undefined);
  59. },
  60. openImportMode: () => {
  61. setTabActiveKey("2");
  62. run({ type: project?.type });
  63. setHideAddTab(true);
  64. setOpen(true);
  65. },
  66. close: () => {
  67. setOpen(false);
  68. },
  69. }));
  70. const { data, loading, run } = useRequest(GetCanUseTableList, {
  71. manual: true,
  72. });
  73. // 可引入表列表
  74. const treeData = useMemo(() => {
  75. const tableMap: Record<string, any> = {};
  76. data?.result
  77. ?.filter(
  78. (item: any) =>
  79. // 过滤当前数据表类型及存在相同schemaName、aliasName的表
  80. item?.type == project?.type
  81. // && !project.tables.find(
  82. // (tableItem) =>
  83. // tableItem.table.schemaName === item.schemaName ||
  84. // tableItem.table.aliasName === item.aliasName
  85. // )
  86. )
  87. ?.forEach((item: any) => {
  88. // 判断是否存在已引入的表
  89. const hasTable = project.tables.find(
  90. (tableItem: TableItemType) =>
  91. tableItem.table.schemaName === item.schemaName ||
  92. tableItem.table.aliasName === item.aliasName
  93. );
  94. const option = {
  95. key: item.id,
  96. title: `${item?.schemaName}(${item.name})`,
  97. value: item?.id,
  98. disabled: hasTable,
  99. selectable: !item.parentBusinessTableId,
  100. };
  101. // 子表
  102. if (item.parentBusinessTableId) {
  103. if (tableMap[item.parentBusinessTableId]) {
  104. tableMap[item.parentBusinessTableId].children.push(option);
  105. } else {
  106. tableMap[item.parentBusinessTableId] = {
  107. children: [option],
  108. };
  109. }
  110. } else {
  111. // 主表
  112. if (tableMap[item.id]) {
  113. tableMap[item.id] = {
  114. ...tableMap[item.parentBusinessTableId],
  115. ...option,
  116. };
  117. } else {
  118. tableMap[item.id] = {
  119. ...option,
  120. children: [],
  121. };
  122. }
  123. }
  124. return;
  125. });
  126. return Object.keys(tableMap).map((key) => tableMap[key]);
  127. }, [data]);
  128. const items: TabsProps["items"] = [
  129. {
  130. key: "1",
  131. label: `新建`,
  132. children: (
  133. <div>
  134. <Form labelCol={{ span: 8 }} form={form}>
  135. <Row gutter={16}>
  136. <Col span={12}>
  137. <Form.Item
  138. label="编码"
  139. name="schemaName"
  140. rules={[
  141. { required: true, message: "请输入编码" },
  142. validateTableCode,
  143. ]}
  144. tooltip="包含字母、下划线、数字, 必须小写字母开头,且必须有下划线! 如:user_info"
  145. >
  146. <Input
  147. placeholder="请输入"
  148. value={formModel?.schemaName}
  149. onChange={(e) => handleChange("schemaName", e.target.value)}
  150. />
  151. </Form.Item>
  152. </Col>
  153. <Col span={12}>
  154. <Form.Item label="表类型" name="type">
  155. <Input
  156. placeholder="请输入"
  157. value={
  158. formModel?.type == TableType.BusinessTable
  159. ? "业务表"
  160. : "视图表"
  161. }
  162. disabled
  163. />
  164. </Form.Item>
  165. </Col>
  166. </Row>
  167. <Row gutter={16}>
  168. <Col span={12}>
  169. <Form.Item
  170. label="别名"
  171. name="aliasName"
  172. rules={[
  173. { required: true, message: "请输入别名" },
  174. validateAliasName,
  175. ]}
  176. tooltip="包含字母、数字, 必须小写字母开头! 如:userinfo"
  177. >
  178. <Input
  179. placeholder="请输入"
  180. value={formModel?.aliasName}
  181. onChange={(e) => handleChange("aliasName", e.target.value)}
  182. />
  183. </Form.Item>
  184. </Col>
  185. <Col span={12}>
  186. <Form.Item label="表名" name="langNameList">
  187. <LangInput
  188. value={formModel?.langNameList}
  189. onChange={(lang) => handleChange("langNameList", lang)}
  190. />
  191. </Form.Item>
  192. </Col>
  193. </Row>
  194. <Row gutter={16}>
  195. <Col span={24}>
  196. <Form.Item
  197. label="描述"
  198. labelCol={{ span: 4 }}
  199. name="langDescriptionList"
  200. >
  201. <LangInputTextarea
  202. value={formModel?.langDescriptionList}
  203. onChange={(lang) =>
  204. handleChange("langDescriptionList", lang)
  205. }
  206. />
  207. </Form.Item>
  208. </Col>
  209. </Row>
  210. </Form>
  211. </div>
  212. ),
  213. },
  214. {
  215. key: "2",
  216. label: `引入`,
  217. children: (
  218. <div>
  219. <Form labelCol={{ span: 4 }} form={form1}>
  220. <Form.Item
  221. label="选择表"
  222. name="table"
  223. rules={[{ required: true, message: "请选择表" }]}
  224. >
  225. <TreeSelect
  226. multiple
  227. treeCheckable
  228. allowClear
  229. placeholder="请选择"
  230. loading={loading}
  231. treeData={treeData}
  232. />
  233. </Form.Item>
  234. <Form.Item label="颜色" name="color">
  235. <CustomColorPicker onChange={setColor}>
  236. {color ? (
  237. <div
  238. className="rounded-4px cus-btn w-32px h-32px bg-#eee flex-none cursor-pointer shadow-inner"
  239. style={{ background: color || "#eee" }}
  240. ></div>
  241. ) : (
  242. <span className="bg-#eee px-5px py-3px rounded-4px cursor-pointer text-12px text-#666">
  243. 随机生成,点击可选择颜色
  244. </span>
  245. )}
  246. </CustomColorPicker>
  247. </Form.Item>
  248. </Form>
  249. </div>
  250. ),
  251. },
  252. ];
  253. const handleChange = (key: string, value: any) => {
  254. formModel &&
  255. setFormModel({
  256. ...formModel,
  257. [key]: value,
  258. });
  259. };
  260. const [loadingColumns, setLoadingColumns] = useState(false);
  261. const handleOk = () => {
  262. // 新建
  263. if (tabActiveKey === "1") {
  264. form.validateFields().then(() => {
  265. if (tableItemRef.current && formModel) {
  266. props.onChange([
  267. {
  268. ...tableItemRef.current,
  269. table: formModel,
  270. },
  271. ]);
  272. }
  273. form.resetFields();
  274. setOpen(false);
  275. });
  276. }
  277. // 引入
  278. if (tabActiveKey === "2") {
  279. form1.validateFields().then(async () => {
  280. // 加载表格字段
  281. const values = form1.getFieldsValue();
  282. try {
  283. setLoadingColumns(true);
  284. if (values.table.length === 0) {
  285. message.error("请选择要引入的表");
  286. return;
  287. }
  288. const businessTables =
  289. data?.result
  290. ?.filter((item: any) => values.table.includes(item.id))
  291. ?.map((item: any) => {
  292. return pick(item, [
  293. "aliasName",
  294. "schemaName",
  295. "id",
  296. "parentBusinessTableId",
  297. ]);
  298. }) || [];
  299. const res = await ImportFromBusinessTables({
  300. dataModelId: project.id,
  301. color,
  302. businessTables,
  303. });
  304. console.log("导入结果:", res);
  305. const rect = graph?.getAllCellsBBox();
  306. // 计算起始位置 默认往最后加
  307. const startY = (rect?.height || 0) + (rect?.y || 0) + 20;
  308. props.onChange(res.result?.map((item: any) => {
  309. item.table.style = JSON.parse(item.table.style || '{}');
  310. item.table.style.y = startY;
  311. return item
  312. }));
  313. form1.resetFields();
  314. setOpen(false);
  315. } catch (err) {
  316. console.error(err);
  317. message.warning("引入失败");
  318. } finally {
  319. setLoadingColumns(false);
  320. }
  321. });
  322. }
  323. };
  324. const handleChangeTableActiveKey = (key: string) => {
  325. setTabActiveKey(key);
  326. if (key === "2") {
  327. run({ type: project.type });
  328. }
  329. };
  330. return (
  331. <Modal
  332. open={open}
  333. title="添加表"
  334. okText={loadingColumns ? "加载中..." : "确定"}
  335. cancelText="取消"
  336. onCancel={() => setOpen(false)}
  337. onOk={handleOk}
  338. okButtonProps={{
  339. loading: loadingColumns,
  340. }}
  341. >
  342. <Tabs
  343. items={items.filter((item) => (hideAddTab ? item.key === "2" : true))}
  344. activeKey={tabActiveKey}
  345. onChange={handleChangeTableActiveKey}
  346. />
  347. </Modal>
  348. );
  349. });