Преглед на файлове

feat: 添加节点属性

liaojiaxing преди 5 месеца
родител
ревизия
87f9ad9084

+ 5 - 1
apps/designer/.umirc.ts

@@ -7,7 +7,7 @@ export default defineConfig({
     '/favicon.ico'
   ],
   styles: [
-    '//at.alicdn.com/t/c/font_4676747_iugzj0fa06f.css'
+    '//at.alicdn.com/t/c/font_4676747_rdn63brs09d.css'
   ],
   metas: [
     { name: 'viewport', content: 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' }
@@ -21,7 +21,11 @@ export default defineConfig({
     require.resolve('@umijs/plugins/dist/unocss'),
     require.resolve('@umijs/plugins/dist/model'),
     require.resolve('@umijs/plugins/dist/initial-state'),
+    require.resolve('@umijs/plugins/dist/request'),
   ],
+  request: {
+    dataField: '',
+  },
   model: {},
   unocss: {
     watch: ['src/**/*.tsx']

+ 134 - 0
apps/designer/src/api/index.ts

@@ -0,0 +1,134 @@
+import { request } from "umi";
+
+type commonParams = {
+  currentPage: number;
+  pageSize: number;
+  orderByProperty: string;
+  Ascending: boolean;
+  totalPage: number;
+  totalCount: number;
+  filters: any[];
+};
+
+/**
+ * 查询多语言
+ * @param data {maxCount: number, searchKey: string, searchLan: "zh-CN" | "en"}
+ * @returns
+ */
+export const ListLangBySearchKey = (data: {
+  maxCount: number;
+  searchKey: string;
+  searchLan: "zh-CN" | "en";
+}) => {
+  return request("/api/system/ListLangBySearchKey", {
+    method: "POST",
+    data,
+  });
+};
+
+/**
+ * 场景查询
+ * @param data 
+ * @returns 
+ * {
+    "currentPage": 1,
+    "pageSize": 10,
+    "orderByProperty": "Id",
+    "Ascending": false,
+    "totalPage": 1,
+    "totalCount": 1,
+    "filters": [
+        {
+            "name": "EnterpriseId"
+        }
+    ]
+}
+ */
+export const GetAllWfScene = (data: commonParams) => {
+  return request("/api/wfScene/GetAllWfScene", {
+    method: "POST",
+    data,
+  });
+};
+
+/**
+ * 流程查询
+ * @param data 
+ * @returns 
+ * {
+    "currentPage": 1,
+    "pageSize": 10,
+    "orderByProperty": "Id",
+    "Ascending": false,
+    "totalPage": 1,
+    "totalCount": 1,
+    "filters": [
+        {
+            "name": "EnterpriseId"
+        }
+    ]
+}
+ */
+export const GetAllWorkflows = (data: commonParams) => {
+  return request("/api/workflow/GetAllWorkflows", {
+    method: "POST",
+    data,
+  });
+};
+
+/**
+ * 获取全部页面
+ * @param data
+ * @returns
+ */
+export const GetAllPage = () => {
+  return request<{
+    codeItemCount: number;
+    description: string;
+    directory: string;
+    fileName: string;
+    id: string;
+    isFavourite: boolean;
+    is_page_load_from_localhost: boolean;
+    langDescription: string;
+    langName: string;
+    menuLinkUrl: string;
+    name: string;
+    processStatus: string;
+    randerType: number;
+    reportType: number;
+    type: number;
+  }>("/api/bpm/GetAllPage", {
+    method: "POST",
+  });
+};
+
+/**
+ * 获取全部视图和表
+ * @param data
+ * @returns
+ */
+export const GetAllTablesAndViews = () => {
+  return request<{
+    appBusinessTables: {
+      aliasName: string;
+      description: string;
+      id: string;
+      isLatest: boolean;
+      latest: boolean;
+      name: string;
+      schemaName: string;
+      type: number;
+    }[];
+    bpmViewTables: {
+      description: string;
+      directory: string;
+      id: string;
+      name: string;
+      schemaName: string;
+      type: number;
+    }[];
+  }>("/api/table/GetAllTablesAndViews", {
+    method: "POST",
+  });
+};

+ 41 - 0
apps/designer/src/app.ts

@@ -0,0 +1,41 @@
+import { message } from 'antd';
+import type { RequestConfig } from 'umi';
+
+export const request: RequestConfig = {
+  timeout: 10000,
+  // other axios options you want
+  errorConfig: {
+    errorHandler(){
+    },
+    errorThrower(){
+    }
+  },
+  requestInterceptors: [
+    (url, options) => {
+      const baseUrl = 'https://edesign.shalu.com'
+      const token = localStorage.getItem('token')
+      if(token) {
+        if(!options.headers) {
+          options.headers = {}
+        }
+        options.headers.Authorization = token
+      }
+
+      return {
+        url: baseUrl + url,
+        options
+      }
+    }
+  ],
+  responseInterceptors: [
+    (response) => {
+      const {data = {} as any, config} = response;
+      if(data?.error) {
+        message.error(data.error);
+        return Promise.reject(data.error);
+      }
+      
+      return response;
+    }
+  ]
+};

+ 2 - 0
apps/designer/src/components/CustomInput.tsx

@@ -2,6 +2,7 @@ import React, { useEffect, useMemo, useRef } from "react";
 import { Input, InputRef } from "antd";
 import { Node } from "@antv/x6";
 import { useSafeState } from "ahooks";
+import FlowExtra from "./FlowExtra";
 export default function CustomInput(props: {
   value: string;
   styles: React.CSSProperties & {
@@ -70,6 +71,7 @@ export default function CustomInput(props: {
 
   return (
     <div className="absolute w-full h-full w-full" style={txtStyle}>
+      <FlowExtra node={node}/>
       {isEditing ? (
         <Input.TextArea
           ref={inputRef}

+ 1 - 0
apps/designer/src/components/ExportImage.tsx

@@ -24,6 +24,7 @@ const ExportComponent = ({
   const graphRef = useRef<HTMLDivElement>(null);
   const printGraph = useRef<Graph>();
   const data = graph.toJSON();
+  console.log(data)
   data.cells = data.cells.filter((cell) => !cell?.data?.isPage);
   data.cells.forEach((cell) => {
     if(cell.data) {

+ 84 - 0
apps/designer/src/components/FlowExtra.tsx

@@ -0,0 +1,84 @@
+import React from "react";
+import { Node } from "@antv/x6";
+import { Tooltip } from "antd";
+import linkConfig from "@/config/linkConfig";
+import { CorrelationType } from "@/enum";
+export default function FlowExtra({ node }: { node: Node }) {
+  const { attrs } = node.getData();
+
+  const enterpriseCode = localStorage.getItem("enterpriseCode");
+  const token = localStorage.getItem("token");
+
+  function objectToUrlParams(obj: Record<string, any>) {
+    const params = new URLSearchParams();
+    for (const [key, value] of Object.entries(obj)) {
+      params.append(key, value);
+    }
+    return params.toString();
+  }
+
+  const linkTypeMap = {
+    [CorrelationType.scene]: {
+      name: "场景",
+      url: linkConfig.scene,
+      param: objectToUrlParams({
+        enterpriseCode,
+        token,
+        id: attrs?.linkValue?.value
+      })
+    },
+    [CorrelationType.flow]: {
+      name: "流程",
+      url: linkConfig.flow,
+      param: `enterpriseCode=${enterpriseCode}#/${attrs?.linkValue?.value}`
+    },
+    [CorrelationType.page]: {
+      name: "页面",
+      url: linkConfig.page,
+      param: objectToUrlParams({
+        token,
+        pageId: attrs?.linkValue?.value
+      })
+    },
+    [CorrelationType.table]: {
+      name: "数据表",
+      url: linkConfig.table,
+      param: objectToUrlParams({
+        enterpriseCode,
+        id: attrs?.linkValue?.value,
+        isSvg: true,
+        type: 16
+      })
+    },
+    [CorrelationType.view]: {
+      name: "视图",
+      url: linkConfig.view,
+      param: objectToUrlParams({
+        enterpriseCode,
+        id: attrs?.linkValue?.value,
+        isSvg: true,
+        type: 16
+      })
+    },
+  };
+
+  const handleOpenLink = () => {
+    console.log(attrs);
+    const url = linkTypeMap[attrs.linkType as CorrelationType]?.url;
+    const param = linkTypeMap[attrs.linkType as CorrelationType]?.param;
+    if (!url) return;
+    window.open(url + '?' + param, "_blank");
+  }
+
+  return (
+    <div className="absolute w-full h-full text-14px">
+      {attrs?.linkValue && (
+        <Tooltip
+          title={`关联${linkTypeMap[attrs.linkType as CorrelationType].name}`}
+        >
+          <i className="iconfont icon-lianjie color-#239edd cursor-pointer text-24px absolute right-0px bottom-0px rotate-45deg" onClick={handleOpenLink}/>
+        </Tooltip>
+      )}
+    </div>
+  );
+}

+ 418 - 0
apps/designer/src/components/NodeAttrs.tsx

@@ -0,0 +1,418 @@
+import { Cell } from "@antv/x6";
+import { Select, Form, Input, Divider, AutoComplete } from "antd";
+import { useEffect, useState } from "react";
+import {
+  ListLangBySearchKey,
+  GetAllPage,
+  GetAllTablesAndViews,
+  GetAllWfScene,
+  GetAllWorkflows,
+} from "@/api";
+import { useRequest } from "umi";
+import SelectModal from "./SelectModal";
+import { CorrelationType } from "@/enum";
+
+interface LanItem {
+  en: string;
+  key: string;
+  ["zh-CN"]: string;
+}
+export default function NodeAttrs({
+  cell,
+  onChange,
+}: {
+  cell?: Cell;
+  onChange?: (data: any) => void;
+}) {
+  const defaultModel = {
+    "zh-CN": "",
+    en: "",
+    langText: "",
+    desc: "",
+    linkType: CorrelationType.scene,
+    linkValue: {
+      value: undefined,
+      label: undefined,
+    },
+    remember: "",
+    recordTime: "",
+    recordUser: "",
+    recordConent: "",
+  };
+
+  const [lanOptions, setLanOptions] = useState<any[]>([]);
+  const [formModel, setFormModel] = useState(cell?.data?.attrs || defaultModel);
+
+  useEffect(() => {
+    if(cell) {
+      setFormModel(cell?.data?.attrs || defaultModel);
+    }
+  }, [cell]);
+
+  const { run } = useRequest(ListLangBySearchKey, {
+    manual: true,
+    onSuccess(data, params) {
+      setLanOptions(
+        (data.result || []).map((item: LanItem) => ({
+          ...item,
+          label: `${item.en || ""}[zh-CN:${item["zh-CN"]}]`,
+          value: item[params[0].searchLan],
+        }))
+      );
+    },
+  });
+
+  useEffect(() => {
+    onChange?.(formModel);
+  }, [formModel]);
+
+  const handleSearch = (serchKey: string, searchLan: "en" | "zh-CN") => {
+    run({
+      maxCount: 10,
+      searchKey: serchKey,
+      searchLan,
+    });
+  };
+
+  const handleChange = (key: string, value: any) => {
+    setFormModel({
+      ...formModel,
+      langText: "",
+      [key]: value,
+    });
+  };
+
+  const handleSelectLang = (option: LanItem) => {
+    setFormModel(() => {
+      return {
+        ...formModel,
+        langText: option.key,
+        en: option?.en,
+        ["zh-CN"]: option?.["zh-CN"],
+      };
+    });
+  };
+
+  return (
+    <div>
+      <Divider style={{ margin: "0" }}>基本</Divider>
+      <section className="px-16px">
+        <Form.Item
+          label="中文"
+          labelCol={{ span: 10 }}
+          labelAlign="left"
+          className="mb-8px"
+          colon={false}
+          layout="vertical"
+        >
+          <AutoComplete
+            allowClear
+            placeholder="请输入"
+            options={lanOptions}
+            onSearch={(val) => handleSearch(val, "zh-CN")}
+            value={formModel["zh-CN"]}
+            onChange={(val) => handleChange("zh-CN", val)}
+            onSelect={(_val, opt) => handleSelectLang(opt)}
+            disabled={!cell}
+          />
+        </Form.Item>
+        <Form.Item
+          label="English"
+          labelCol={{ span: 10 }}
+          labelAlign="left"
+          className="mb-8px"
+          colon={false}
+          layout="vertical"
+        >
+          <AutoComplete
+            allowClear
+            style={{ width: "100%" }}
+            placeholder="请输入"
+            options={lanOptions}
+            onSearch={(val) => handleSearch(val, "en")}
+            value={formModel.en}
+            onChange={(val) => handleChange("en", val)}
+            onSelect={(_val, opt) => handleSelectLang(opt)}
+            disabled={!cell}
+          />
+        </Form.Item>
+        <Form.Item
+          label="节点描述"
+          labelCol={{ span: 10 }}
+          labelAlign="left"
+          className="mb-8px"
+          colon={false}
+        >
+          <Input.TextArea
+            placeholder="请输入"
+            value={formModel.desc}
+            onChange={(e) => handleChange("desc", e.target.value)}
+            disabled={!cell}
+          />
+        </Form.Item>
+        <Form.Item
+          label="关联类型"
+          labelCol={{ span: 10 }}
+          labelAlign="left"
+          className="mb-8px"
+          colon={false}
+        >
+          <Select
+            placeholder="请选择"
+            disabled={!cell}
+            options={[
+              { value: CorrelationType.scene, label: "场景" },
+              { value: CorrelationType.flow, label: "流程" },
+              { value: CorrelationType.page, label: "页面" },
+              { value: CorrelationType.table, label: "数据表" },
+              { value: CorrelationType.view, label: "视图" },
+            ]}
+            value={formModel.linkType}
+            onChange={(val) => {
+              setFormModel({
+                ...formModel,
+                linkType: val,
+                linkValue: {
+                  label: undefined,
+                  value: undefined,
+                },
+              });
+            }}
+          />
+        </Form.Item>
+        <Form.Item
+          labelCol={{ span: 10 }}
+          labelAlign="left"
+          className="mb-8px"
+          colon={false}
+        >
+          {formModel.linkType === CorrelationType.scene && (
+            <SelectModal
+              key="1"
+              value={formModel.linkValue}
+              api={GetAllWfScene}
+              disabled={!cell}
+              onSuccess={(data) => {
+                return data?.result?.model || [];
+              }}
+              columns={[
+                { title: "名称", dataIndex: "name" },
+                { title: "描述", dataIndex: "memo" },
+              ]}
+              onChange={(rows) => {
+                const item = rows[0];
+                item &&
+                  handleChange("linkValue", {
+                    value: item.id,
+                    label: item.name,
+                  });
+              }}
+              defaultParams={[
+                {
+                  currentPage: 1,
+                  pageSize: 10,
+                  orderByProperty: "Id",
+                  Ascending: false,
+                  filters: [
+                    {
+                      name: "EnterpriseId",
+                    },
+                  ],
+                },
+              ]}
+            />
+          )}
+          {formModel.linkType === CorrelationType.flow && (
+            <SelectModal
+              key="2"
+              value={formModel.linkValue}
+              api={GetAllWorkflows}
+              disabled={!cell}
+              onSuccess={(data) => {
+                return data?.result || [];
+              }}
+              columns={[
+                { title: "名称", dataIndex: "name" },
+                { title: "描述", dataIndex: "memo" },
+              ]}
+              onChange={(rows) => {
+                const item = rows[0];
+                item &&
+                  handleChange("linkValue", {
+                    value: item.id,
+                    label: item.name,
+                  });
+              }}
+              defaultParams={[
+                {
+                  currentPage: 1,
+                  pageSize: 10,
+                  orderByProperty: "Id",
+                  Ascending: false,
+                  filters: [
+                    {
+                      name: "EnterpriseId",
+                    },
+                  ],
+                },
+              ]}
+            />
+          )}
+          {formModel.linkType === CorrelationType.page && (
+            <SelectModal
+              key="3"
+              value={formModel.linkValue}
+              api={GetAllPage}
+              disabled={!cell}
+              onSuccess={(data) => {
+                return data?.result || [];
+              }}
+              columns={[
+                {
+                  title: "名称",
+                  dataIndex: "name",
+                  render: (_val, record) => (
+                    <span>
+                      {record.name}({record.fileName})
+                    </span>
+                  ),
+                },
+                { title: "描述", dataIndex: "description" },
+              ]}
+              onChange={(rows) => {
+                const item = rows[0];
+                item &&
+                  handleChange("linkValue", {
+                    value: item.id,
+                    label: item.name,
+                  });
+              }}
+            />
+          )}
+          {formModel.linkType === CorrelationType.table && (
+            <SelectModal
+              key="4"
+              value={formModel.linkValue}
+              api={GetAllTablesAndViews}
+              disabled={!cell}
+              onSuccess={(data) => {
+                return data?.result?.appBusinessTables || [];
+              }}
+              columns={[
+                {
+                  title: "名称",
+                  dataIndex: "name",
+                  render: (val, record) => (
+                    <span>
+                      {record.name}({record.schemaName})
+                    </span>
+                  ),
+                },
+                { title: "描述", dataIndex: "description" },
+              ]}
+              onChange={(rows) => {
+                const item = rows[0];
+                item &&
+                  handleChange("linkValue", {
+                    value: item.id,
+                    label: item.name,
+                  });
+              }}
+            />
+          )}
+          {formModel.linkType === CorrelationType.view && (
+            <SelectModal
+              key="5"
+              value={formModel.linkValue}
+              api={GetAllTablesAndViews}
+              disabled={!cell}
+              onSuccess={(data) => {
+                return data?.result?.bpmViewTables || [];
+              }}
+              columns={[
+                {
+                  title: "名称",
+                  dataIndex: "name",
+                  render: (val, record) => (
+                    <span>
+                      {record.name}({record.schemaName})
+                    </span>
+                  ),
+                },
+                { title: "描述", dataIndex: "description" },
+              ]}
+              onChange={(rows) => {
+                const item = rows[0];
+                item &&
+                  handleChange("linkValue", {
+                    value: item.id,
+                    label: item.name,
+                  });
+              }}
+            />
+          )}
+        </Form.Item>
+      </section>
+      <Divider style={{ margin: "0" }}>需求</Divider>
+      <section className="px-16px">
+        <Form.Item
+          label="参与人"
+          labelCol={{ span: 10 }}
+          labelAlign="left"
+          className="mb-8px"
+          colon={false}
+        >
+          <Input
+            placeholder="请输入"
+            value={formModel.remember}
+            onChange={(e) => handleChange("remember", e.target.value)}
+            disabled={!cell}
+          />
+        </Form.Item>
+        <Form.Item
+          label="记录时间"
+          labelCol={{ span: 10 }}
+          labelAlign="left"
+          className="mb-8px"
+          colon={false}
+        >
+          <Input
+            placeholder="请输入"
+            value={formModel.recordTime}
+            onChange={(e) => handleChange("recordTime", e.target.value)}
+            disabled={!cell}
+          />
+        </Form.Item>
+        <Form.Item
+          label="记录人"
+          labelCol={{ span: 10 }}
+          labelAlign="left"
+          className="mb-8px"
+          colon={false}
+        >
+          <Input.TextArea
+            placeholder="请输入"
+            value={formModel.recordUser}
+            onChange={(e) => handleChange("recordUser", e.target.value)}
+            disabled={!cell}
+          />
+        </Form.Item>
+        <Form.Item
+          label="内容"
+          labelCol={{ span: 10 }}
+          labelAlign="left"
+          className="mb-8px"
+          colon={false}
+        >
+          <Input.TextArea
+            rows={5}
+            placeholder="请输入"
+            value={formModel.recordConent}
+            onChange={(e) => handleChange("recordConent", e.target.value)}
+            disabled={!cell}
+          />
+        </Form.Item>
+      </section>
+    </div>
+  );
+}

+ 119 - 0
apps/designer/src/components/SelectModal.tsx

@@ -0,0 +1,119 @@
+import {
+  Input,
+  Modal,
+  Table,
+  TableColumnsType,
+  TablePaginationConfig,
+  Button,
+  Select,
+} from "antd";
+import React, { useRef, useState } from "react";
+import { useRequest } from "ahooks";
+import { SearchOutlined } from "@ant-design/icons";
+
+export default function SelectModal({
+  api,
+  columns,
+  onSuccess,
+  onChange,
+  defaultParams,
+  value,
+  disabled,
+}: {
+  api: (params: any) => Promise<any>;
+  columns: TableColumnsType<any>;
+  onSuccess: (data: any, params: any[]) => any[];
+  onChange: (selectedRows: any[]) => void;
+  defaultParams?: [params: any];
+  value: any;
+  disabled: boolean;
+}) {
+  const [open, setOpen] = React.useState(false);
+  const [searchKey, setSearchKey] = useState("");
+  const [selectedRowRows, setSelectedRowRows] = React.useState<any[]>([]);
+  const [dataSource, setDataSource] = React.useState<any[]>([]);
+  const [pagination, setPagination] = useState<TablePaginationConfig>({
+    current: 1,
+    pageSize: 10,
+    pageSizeOptions: ["10", "20", "30", "40"],
+  });
+  const dataRef = useRef<any[]>([]);
+
+  const { loading, run } = useRequest(api, {
+    defaultParams,
+    onSuccess(data, params) {
+      const result = onSuccess(data, params);
+      setDataSource(result);
+      dataRef.current = result;
+    },
+  });
+  const handleSlected = (_keys: React.Key[], rows: any[]) => {
+    setSelectedRowRows(rows);
+  };
+
+  const handleChange = (pagination: TablePaginationConfig) => {
+    setPagination(pagination);
+    if (defaultParams) {
+      run({
+        currentPage: pagination.current,
+        pageSize: pagination.pageSize,
+      });
+    }
+  };
+
+  const handleSearch = () => {
+    setDataSource(dataRef.current.filter((item) => item.name.includes(searchKey)))
+  }
+
+  const handleOk = () => {
+    onChange(selectedRowRows);
+    setOpen(false);
+  };
+  return (
+    <>
+      <Modal
+        open={open}
+        title="请选择"
+        footer={
+          <div>
+            <Button className="m-r-8px" onClick={() => setOpen(false)}>
+              取消
+            </Button>
+            <Button type="primary" onClick={handleOk}>
+              确定
+            </Button>
+          </div>
+        }
+        closable={false}
+      >
+        <Input
+          suffix={<SearchOutlined />}
+          placeholder="关键字搜索"
+          value={searchKey}
+          onChange={(e) => setSearchKey(e.target.value)}
+          onBlur={handleSearch}
+          onPressEnter={handleSearch}
+        />
+        <Table
+          dataSource={dataSource}
+          columns={columns}
+          rowKey={"id"}
+          rowSelection={{
+            type: "radio",
+            onChange: handleSlected,
+          }}
+          pagination={pagination}
+          loading={loading}
+          onChange={handleChange}
+        />
+      </Modal>
+      <Select
+        dropdownStyle={{ display: "none" }}
+        placeholder="请选择"
+        onClick={() => !disabled && setOpen(true)}
+        value={value.label}
+        disabled={disabled}
+      />
+    </>
+  );
+}

+ 19 - 7
apps/designer/src/components/mindMap/Text.tsx

@@ -18,12 +18,14 @@ export default function Text(props: {
   const [isEditing, setIsEditing] = useSafeState(false);
   const inputRef = useRef<InputRef>(null);
 
-  const style = useMemo(() => {
+  const style = useMemo((): React.CSSProperties => {
     return {
       ...styles,
       fontWeight: styles.bold ? "bold" : undefined,
       fontStyle: styles.italic ? "italic" : undefined,
       minHeight: "12px",
+      padding: 0,
+      wordBreak: "break-all",
     };
   }, [styles]);
 
@@ -59,21 +61,31 @@ export default function Text(props: {
 
   return (
     <div style={txtStyle}>
-      {isEditing ? (
+      <div
+        style={{
+          ...style,
+          opacity: isEditing ? 0 : 1,
+        }}
+        onDoubleClick={() => handleSetEditing(true)}
+      >
+        {value}
+      </div>
+      {isEditing && (
         <Input.TextArea
           ref={inputRef}
           placeholder={placeholder}
           value={value}
           variant="borderless"
-          style={style}
+          style={{
+            ...style,
+            position: "absolute",
+            left: 0,
+            top: 0
+          }}
           onChange={(e) => handleChange(e.target.value)}
           onBlur={() => handleSetEditing(false)}
           autoSize
         />
-      ) : (
-        <div style={style} onDoubleClick={() => handleSetEditing(true)}>
-          {value}
-        </div>
       )}
     </div>
   );

+ 12 - 0
apps/designer/src/config/linkConfig.ts

@@ -0,0 +1,12 @@
+export default {
+  // 页面地址 ?pageId=0f985d5d-06c2-4099-88ea-e939b7e42a2b&token=designer_token_bpm_backend_1313160145143861248#/
+  page: "https://edesign.shalu.com/App/SysDesigner/vue/page/index.html",
+  // 流程地址 ?enterpriseCode=PartnerBpmDemo#/610f7849-ccaf-44ba-a9a9-29c7ff198230
+  flow: "https://edesign.shalu.com/App/SysDesigner/Layout.html",
+  // 场景地址 ?enterpriseCode=PartnerBpmDemo#/5d60f968-cf72-4783-bd78-8487b9a52524
+  scene: "https://edesign.shalu.com/App/SceneDesigner/Layout.html",
+  // 数据表地址 ?enterpriseCode=PartnerBpmDemo&id=011aacca-5df7-416f-80f4-246f183ebcc8&isSvg=true&type=16
+  table: "https://edesign.shalu.com/Views/Design/er.html",
+  // 视图地址
+  view: ""
+}

+ 9 - 0
apps/designer/src/enum/index.ts

@@ -22,6 +22,15 @@ export enum LineType {
   dashdot = "5,5,1,5",
 }
 
+// 关联类型
+export enum CorrelationType {
+  page,
+  flow,
+  scene,
+  table,
+  view
+}
+
 // 边框圆角大小
 export enum BorderSize {
   none = 0,

+ 15 - 0
apps/designer/src/layouts/index.tsx

@@ -1,7 +1,22 @@
 import { Outlet } from 'umi';
 import './index.less';
+import { useSearchParams } from 'umi';
+import { useEffect } from 'react';
 
 export default function Layout() {
+  const [searchParams] = useSearchParams();
+
+  useEffect(() => {
+    const token = searchParams.get('token');
+    const enterpriseCode = searchParams.get('enterpriseCode');
+    
+    if(token) {
+      localStorage.setItem('token', token);
+    }
+    if(enterpriseCode) {
+      localStorage.setItem('enterpriseCode', enterpriseCode);
+    }
+  }, [searchParams]);
   return (
     <Outlet />
   );

+ 0 - 112
apps/designer/src/pages/flow/components/Config/NodeAttrs.tsx

@@ -1,112 +0,0 @@
-import {
-  Select,
-  Form,
-  Input,
-  Divider,
-} from "antd";
-import { useModel } from "umi";
-
-export default function NodeAttrs() {
-  const { pageState, onChangePageSettings } = useModel("appModel");
-
-  return (
-    <div>
-      <Divider style={{margin: '0'}}>基本</Divider>
-      <section className="px-16px">
-        <Form.Item
-          label="中文"
-          labelCol={{ span: 10 }}
-          labelAlign="left"
-          className="mb-8px"
-          colon={false}
-        >
-          <Input placeholder="请输入" />
-        </Form.Item>
-        <Form.Item
-          label="English"
-          labelCol={{ span: 10 }}
-          labelAlign="left"
-          className="mb-8px"
-          colon={false}
-        >
-          <Input placeholder="请输入" />
-        </Form.Item>
-        <Form.Item
-          label="节点描述"
-          labelCol={{ span: 10 }}
-          labelAlign="left"
-          className="mb-8px"
-          colon={false}
-        >
-          <Input.TextArea placeholder="请输入" />
-        </Form.Item>
-        <Form.Item
-          label="关联类型"
-          labelCol={{ span: 10 }}
-          labelAlign="left"
-          className="mb-8px"
-          colon={false}
-        >
-          <Select placeholder="请选择" options={[
-            { value: "1", label: "场景" },
-            { value: "2", label: "流程" },
-            { value: "3", label: "页面" },
-            { value: "4", label: "数据表" },
-          ]}/>
-        </Form.Item>
-        <Form.Item
-          labelCol={{ span: 10 }}
-          labelAlign="left"
-          className="mb-8px"
-          colon={false}
-        >
-          <Select placeholder="请选择" options={[
-            { value: "1", label: "场景" },
-            { value: "2", label: "流程" },
-            { value: "3", label: "页面" },
-            { value: "4", label: "数据表" },
-          ]}/>
-        </Form.Item>
-      </section>
-      <Divider style={{margin: '0'}}>需求</Divider>
-      <section className="px-16px">
-        <Form.Item
-          label="参与人"
-          labelCol={{ span: 10 }}
-          labelAlign="left"
-          className="mb-8px"
-          colon={false}
-        >
-          <Input placeholder="请输入" />
-        </Form.Item>
-        <Form.Item
-          label="记录时间"
-          labelCol={{ span: 10 }}
-          labelAlign="left"
-          className="mb-8px"
-          colon={false}
-        >
-          <Input placeholder="请输入" />
-        </Form.Item>
-        <Form.Item
-          label="记录人"
-          labelCol={{ span: 10 }}
-          labelAlign="left"
-          className="mb-8px"
-          colon={false}
-        >
-          <Input.TextArea placeholder="请输入" />
-        </Form.Item>
-        <Form.Item
-          label="内容"
-          labelCol={{ span: 10 }}
-          labelAlign="left"
-          className="mb-8px"
-          colon={false}
-        >
-          <Input.TextArea rows={5} placeholder="请输入" />
-        </Form.Item>
-      </section>
-    </div>
-  );
-}

+ 22 - 10
apps/designer/src/pages/flow/components/Config/index.tsx

@@ -1,8 +1,8 @@
 import { ConfigProvider, Tabs } from "antd";
-import React, { useEffect, useState } from "react";
+import React, { useEffect, useMemo } from "react";
 import PageStyle from "./PageStyle";
 import GraphStyle from "./GraphStyle";
-import NodeAttrs from "./NodeAttrs";
+import NodeAttrs from "@/components/NodeAttrs";
 import { useModel } from "umi";
 import InsetCss from "insert-css";
 
@@ -21,6 +21,18 @@ export default function Config() {
   const { selectedCell } = useModel("graphModel");
   const { rightPanelTabActiveKey, setRightPanelTabActiveKey } =
     useModel("appModel");
+
+  const firstNode = useMemo(() => {
+    return selectedCell.find(cell => cell.isNode());
+  }, [selectedCell]);
+
+  // 设置节点属性
+  const handleSetNodeAttr = (attrs: any) => {
+    firstNode?.setData({
+      attrs
+    });
+  }
+
   const tabItems = [
     {
       key: "1",
@@ -65,18 +77,18 @@ export default function Config() {
         },
       }}
     >
-      <NodeAttrs />
+      <NodeAttrs cell={firstNode} onChange={handleSetNodeAttr}/>
     </ConfigProvider>,
     },
   ];
 
-  useEffect(() => {
-    if (selectedCell?.length) {
-      setRightPanelTabActiveKey("2");
-    } else {
-      setRightPanelTabActiveKey("1");
-    }
-  }, [selectedCell]);
+  // useEffect(() => {
+  //   if (selectedCell?.length) {
+  //     setRightPanelTabActiveKey("2");
+  //   } else {
+  //     setRightPanelTabActiveKey("1");
+  //   }
+  // }, [selectedCell]);
 
   return (
     <Tabs

+ 5 - 1
apps/designer/src/pages/mindmap/components/HeaderToolbar/index.tsx

@@ -1,4 +1,4 @@
-import React, { useMemo, useState } from "react";
+import React, { useEffect, useMemo, useState } from "react";
 import { Button, Input, Dropdown, Tooltip, MenuProps, Divider } from "antd";
 import { LeftOutlined, MenuOutlined } from "@ant-design/icons";
 import logo from "@/assets/logo.png";
@@ -28,6 +28,10 @@ export default function index() {
 
   const [title, setTitle] = useState<string>(mindProjectInfo?.name || "");
 
+  useEffect(() => {
+    setTitle(mindProjectInfo?.name || "");
+  }, [mindProjectInfo?.name])
+
   const handleChangeTitle = () => {
     mindProjectInfo && setMindProjectInfo({
       ...mindProjectInfo,

+ 29 - 20
apps/designer/src/types.d.ts

@@ -5,7 +5,7 @@ export interface CompoundedComponent {
   name: string;
   icon: string;
   node: Node.Metadata;
-};
+}
 
 export interface LaneItem {
   width: number;
@@ -89,7 +89,16 @@ export type TopicItem = {
    */
   extraModules?: {
     type: "image" | "code";
-    data: Record<string, any>;
+    data:
+      | {
+          code: string;
+          language: string;
+        }
+      | {
+          imageUrl: string;
+          width: number;
+          height: number;
+        };
   };
   /**
    * 图标
@@ -98,7 +107,7 @@ export type TopicItem = {
   /**
    * 标签
    */
-  tags?: string[];
+  tags?: { name: string; color: string }[];
   /**
    * 备注
    */
@@ -132,7 +141,7 @@ export type TopicItem = {
   edge?: {
     color: string;
     width: number;
-  }
+  };
   /**
    * 折叠子节点
    */
@@ -155,13 +164,13 @@ export type TopicItem = {
   border?: {
     line: {
       width: number;
-      style: 'solid' | 'dashed',
+      style: "solid" | "dashed";
       color: string;
     };
     fill: string;
     type: TopicBorderType;
     label: string;
-  }
+  };
   /**
    * 概要
    */
@@ -176,10 +185,10 @@ export type TopicItem = {
         color: string;
       };
       type: TopicBorderType;
-    }
-  }
+    };
+  };
 } & cellStyle;
-export interface MindMapProjectInfo{
+export interface MindMapProjectInfo {
   name: string;
   desc: string;
   version: string;
@@ -187,16 +196,16 @@ export interface MindMapProjectInfo{
   theme: string;
   structure: StructureType;
   pageSetting: {
-    fillType: 'color' | 'image',
-    fill: string,
-    fillImageUrl: string,
-    branchY: number,
-    branchX: number,
-    subTopicY: number,
-    subTopicX: number,
-    alignSameTopic: boolean,
-    showWatermark: boolean,
-    watermark: string,
+    fillType: "color" | "image";
+    fill: string;
+    fillImageUrl: string;
+    branchY: number;
+    branchX: number;
+    subTopicY: number;
+    subTopicX: number;
+    alignSameTopic: boolean;
+    showWatermark: boolean;
+    watermark: string;
   };
   topics: any[];
-}
+}