Lind 4 lat temu
rodzic
commit
03baa12f1f

+ 1 - 0
src/components/BaseCrud/model.ts

@@ -20,6 +20,7 @@ export const CurdModel = model<Option>({
     Store.set(SystemConst.BASE_CURD_MODAL_VISIBLE, true);
     Store.set(SystemConst.BASE_CURD_MODAL_VISIBLE, true);
     Store.set(SystemConst.BASE_CURD_CURRENT, current);
     Store.set(SystemConst.BASE_CURD_CURRENT, current);
     this.model = 'edit';
     this.model = 'edit';
+    this.current = current;
   },
   },
 
 
   close() {
   close() {

+ 2 - 0
src/components/BaseCrud/save/index.tsx

@@ -1,6 +1,7 @@
 import React, { useEffect, useState } from 'react';
 import React, { useEffect, useState } from 'react';
 import { message, Modal } from 'antd';
 import { message, Modal } from 'antd';
 import {
 import {
+  NumberPicker,
   Editable,
   Editable,
   Form,
   Form,
   FormItem,
   FormItem,
@@ -70,6 +71,7 @@ const Save = <T extends Record<string, any>>(props: Props<T>) => {
       Switch,
       Switch,
       FormGrid,
       FormGrid,
       Editable,
       Editable,
+      NumberPicker,
     },
     },
     scope: {
     scope: {
       icon(name: any) {
       icon(name: any) {

+ 148 - 149
src/pages/document.ejs

@@ -1,209 +1,208 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
 <html lang="en">
 <html lang="en">
-  <head>
-    <meta charset="UTF-8" />
-    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<head>
+    <meta charset="UTF-8"/>
+    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
     <meta
     <meta
-      name="keywords"
-      content="antd,umi,umijs,ant design,Scaffolding, layout, Ant Design, project, Pro, admin, console, homepage, out-of-the-box, middle and back office, solution, component library"
+            name="keywords"
+            content="antd,umi,umijs,ant design,Scaffolding, layout, Ant Design, project, Pro, admin, jetlinks"
     />
     />
     <meta
     <meta
-      name="description"
-      content="
-    An out-of-box UI solution for enterprise applications as a React boilerplate."
+            name="description"
+            content="Jetlinks"
     />
     />
     <meta
     <meta
-      name="description"
-      content="
-      Out-of-the-box mid-stage front-end/design solution."
+            name="viewport"
+            content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
     />
     />
-    <meta
-      name="viewport"
-      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
-    />
-    <title>Ant Design Pro</title>
-    <link rel="icon" href="<%= context.config.publicPath +'favicon.ico'%>" type="image/x-icon" />
-  </head>
-  <body>
-    <noscript>
-      <div class="noscript-container">
+    <title>Jetlinks</title>
+    <link rel="icon" href="<%= context.config.publicPath + 'favicon.ico' %>" type="image/x-icon"/>
+</head>
+<body>
+<noscript>
+    <div class="noscript-container">
         Hi there! Please
         Hi there! Please
         <div class="noscript-enableJS">
         <div class="noscript-enableJS">
-          <a href="https://www.enablejavascript.io/en" target="_blank" rel="noopener noreferrer">
-            <b>enable Javascript</b>
-          </a>
+            <a href="https://www.enablejavascript.io/en" target="_blank" rel="noopener noreferrer">
+                <b>enable Javascript</b>
+            </a>
         </div>
         </div>
         in your browser to use Ant Design, Out-of-the-box mid-stage front/design solution!
         in your browser to use Ant Design, Out-of-the-box mid-stage front/design solution!
-      </div>
-    </noscript>
-    <div id="root">
-      <style>
+    </div>
+</noscript>
+<div id="root">
+    <style>
         html,
         html,
         body,
         body,
         #root {
         #root {
-          height: 100%;
-          margin: 0;
-          padding: 0;
+            height: 100%;
+            margin: 0;
+            padding: 0;
         }
         }
+
         #root {
         #root {
-          background-repeat: no-repeat;
-          background-size: 100% auto;
+            background-repeat: no-repeat;
+            background-size: 100% auto;
         }
         }
+
         .noscript-container {
         .noscript-container {
-          display: flex;
-          align-content: center;
-          justify-content: center;
-          margin-top: 90px;
-          font-size: 20px;
-          font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode',
+            display: flex;
+            align-content: center;
+            justify-content: center;
+            margin-top: 90px;
+            font-size: 20px;
+            font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode',
             Geneva, Verdana, sans-serif;
             Geneva, Verdana, sans-serif;
         }
         }
+
         .noscript-enableJS {
         .noscript-enableJS {
-          padding-right: 3px;
-          padding-left: 3px;
+            padding-right: 3px;
+            padding-left: 3px;
         }
         }
+
         .page-loading-warp {
         .page-loading-warp {
-          display: flex;
-          align-items: center;
-          justify-content: center;
-          padding: 98px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            padding: 98px;
         }
         }
+
         .ant-spin {
         .ant-spin {
-          position: absolute;
-          display: none;
-          -webkit-box-sizing: border-box;
-          box-sizing: border-box;
-          margin: 0;
-          padding: 0;
-          color: rgba(0, 0, 0, 0.65);
-          color: #1890ff;
-          font-size: 14px;
-          font-variant: tabular-nums;
-          line-height: 1.5;
-          text-align: center;
-          list-style: none;
-          opacity: 0;
-          -webkit-transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
-          transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
-          transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
-          transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
+            position: absolute;
+            display: none;
+            -webkit-box-sizing: border-box;
+            box-sizing: border-box;
+            margin: 0;
+            padding: 0;
+            color: rgba(0, 0, 0, 0.65);
+            color: #1890ff;
+            font-size: 14px;
+            font-variant: tabular-nums;
+            line-height: 1.5;
+            text-align: center;
+            list-style: none;
+            opacity: 0;
+            -webkit-transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
+            transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
+            transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
+            transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
             -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
             -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
-          -webkit-font-feature-settings: 'tnum';
-          font-feature-settings: 'tnum';
+            -webkit-font-feature-settings: 'tnum';
+            font-feature-settings: 'tnum';
         }
         }
 
 
         .ant-spin-spinning {
         .ant-spin-spinning {
-          position: static;
-          display: inline-block;
-          opacity: 1;
+            position: static;
+            display: inline-block;
+            opacity: 1;
         }
         }
 
 
         .ant-spin-dot {
         .ant-spin-dot {
-          position: relative;
-          display: inline-block;
-          width: 20px;
-          height: 20px;
-          font-size: 20px;
+            position: relative;
+            display: inline-block;
+            width: 20px;
+            height: 20px;
+            font-size: 20px;
         }
         }
 
 
         .ant-spin-dot-item {
         .ant-spin-dot-item {
-          position: absolute;
-          display: block;
-          width: 9px;
-          height: 9px;
-          background-color: #1890ff;
-          border-radius: 100%;
-          -webkit-transform: scale(0.75);
-          -ms-transform: scale(0.75);
-          transform: scale(0.75);
-          -webkit-transform-origin: 50% 50%;
-          -ms-transform-origin: 50% 50%;
-          transform-origin: 50% 50%;
-          opacity: 0.3;
-          -webkit-animation: antspinmove 1s infinite linear alternate;
-          animation: antSpinMove 1s infinite linear alternate;
+            position: absolute;
+            display: block;
+            width: 9px;
+            height: 9px;
+            background-color: #1890ff;
+            border-radius: 100%;
+            -webkit-transform: scale(0.75);
+            -ms-transform: scale(0.75);
+            transform: scale(0.75);
+            -webkit-transform-origin: 50% 50%;
+            -ms-transform-origin: 50% 50%;
+            transform-origin: 50% 50%;
+            opacity: 0.3;
+            -webkit-animation: antspinmove 1s infinite linear alternate;
+            animation: antSpinMove 1s infinite linear alternate;
         }
         }
 
 
         .ant-spin-dot-item:nth-child(1) {
         .ant-spin-dot-item:nth-child(1) {
-          top: 0;
-          left: 0;
+            top: 0;
+            left: 0;
         }
         }
 
 
         .ant-spin-dot-item:nth-child(2) {
         .ant-spin-dot-item:nth-child(2) {
-          top: 0;
-          right: 0;
-          -webkit-animation-delay: 0.4s;
-          animation-delay: 0.4s;
+            top: 0;
+            right: 0;
+            -webkit-animation-delay: 0.4s;
+            animation-delay: 0.4s;
         }
         }
 
 
         .ant-spin-dot-item:nth-child(3) {
         .ant-spin-dot-item:nth-child(3) {
-          right: 0;
-          bottom: 0;
-          -webkit-animation-delay: 0.8s;
-          animation-delay: 0.8s;
+            right: 0;
+            bottom: 0;
+            -webkit-animation-delay: 0.8s;
+            animation-delay: 0.8s;
         }
         }
 
 
         .ant-spin-dot-item:nth-child(4) {
         .ant-spin-dot-item:nth-child(4) {
-          bottom: 0;
-          left: 0;
-          -webkit-animation-delay: 1.2s;
-          animation-delay: 1.2s;
+            bottom: 0;
+            left: 0;
+            -webkit-animation-delay: 1.2s;
+            animation-delay: 1.2s;
         }
         }
 
 
         .ant-spin-dot-spin {
         .ant-spin-dot-spin {
-          -webkit-transform: rotate(45deg);
-          -ms-transform: rotate(45deg);
-          transform: rotate(45deg);
-          -webkit-animation: antrotate 1.2s infinite linear;
-          animation: antRotate 1.2s infinite linear;
+            -webkit-transform: rotate(45deg);
+            -ms-transform: rotate(45deg);
+            transform: rotate(45deg);
+            -webkit-animation: antrotate 1.2s infinite linear;
+            animation: antRotate 1.2s infinite linear;
         }
         }
 
 
         .ant-spin-lg .ant-spin-dot {
         .ant-spin-lg .ant-spin-dot {
-          width: 32px;
-          height: 32px;
-          font-size: 32px;
+            width: 32px;
+            height: 32px;
+            font-size: 32px;
         }
         }
 
 
         .ant-spin-lg .ant-spin-dot i {
         .ant-spin-lg .ant-spin-dot i {
-          width: 14px;
-          height: 14px;
+            width: 14px;
+            height: 14px;
         }
         }
 
 
         @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
         @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
-          .ant-spin-blur {
-            background: #fff;
-            opacity: 0.5;
-          }
+            .ant-spin-blur {
+                background: #fff;
+                opacity: 0.5;
+            }
         }
         }
 
 
         @-webkit-keyframes antSpinMove {
         @-webkit-keyframes antSpinMove {
-          to {
-            opacity: 1;
-          }
+            to {
+                opacity: 1;
+            }
         }
         }
 
 
         @keyframes antSpinMove {
         @keyframes antSpinMove {
-          to {
-            opacity: 1;
-          }
+            to {
+                opacity: 1;
+            }
         }
         }
 
 
         @-webkit-keyframes antRotate {
         @-webkit-keyframes antRotate {
-          to {
-            -webkit-transform: rotate(405deg);
-            transform: rotate(405deg);
-          }
+            to {
+                -webkit-transform: rotate(405deg);
+                transform: rotate(405deg);
+            }
         }
         }
 
 
         @keyframes antRotate {
         @keyframes antRotate {
-          to {
-            -webkit-transform: rotate(405deg);
-            transform: rotate(405deg);
-          }
-        }
-      </style>
-      <div
-        style="
+            to {
+                -webkit-transform: rotate(405deg);
+                transform: rotate(405deg);
+            }
+        }
+    </style>
+    <div
+            style="
           display: flex;
           display: flex;
           flex-direction: column;
           flex-direction: column;
           align-items: center;
           align-items: center;
@@ -211,25 +210,25 @@
           height: 100%;
           height: 100%;
           min-height: 420px;
           min-height: 420px;
         "
         "
-      >
-        <img src="<%= context.config.publicPath +'pro_icon.svg'%>" alt="logo" width="256" />
+    >
+        <img src="<%= context.config.publicPath + 'pro_icon.svg' %>" alt="logo" width="256"/>
         <div class="page-loading-warp">
         <div class="page-loading-warp">
-          <div class="ant-spin ant-spin-lg ant-spin-spinning">
+            <div class="ant-spin ant-spin-lg ant-spin-spinning">
             <span class="ant-spin-dot ant-spin-dot-spin"
             <span class="ant-spin-dot ant-spin-dot-spin"
-              ><i class="ant-spin-dot-item"></i><i class="ant-spin-dot-item"></i
-              ><i class="ant-spin-dot-item"></i><i class="ant-spin-dot-item"></i
-            ></span>
-          </div>
+            ><i class="ant-spin-dot-item"></i><i class="ant-spin-dot-item"></i
+                ><i class="ant-spin-dot-item"></i><i class="ant-spin-dot-item"></i
+                ></span>
+            </div>
         </div>
         </div>
         <div style="display: flex; align-items: center; justify-content: center">
         <div style="display: flex; align-items: center; justify-content: center">
-          <img
-            src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"
-            width="32"
-            style="margin-right: 8px"
-          />
-          Ant Design
+            <img
+                    src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"
+                    width="32"
+                    style="margin-right: 8px"
+            />
+            Jetlinks
         </div>
         </div>
-      </div>
     </div>
     </div>
-  </body>
+</div>
+</body>
 </html>
 </html>

+ 29 - 18
src/pages/system/Org/Save/index.tsx

@@ -1,24 +1,27 @@
-import { Modal } from 'antd';
+import { message, Modal } from 'antd';
 import { createForm } from '@formily/core';
 import { createForm } from '@formily/core';
 import { createSchemaField, observer } from '@formily/react';
 import { createSchemaField, observer } from '@formily/react';
-import { Form, Input, FormItem } from '@formily/antd';
+import { NumberPicker, Form, Input, FormItem } from '@formily/antd';
 import React from 'react';
 import React from 'react';
-import type { ObsModel } from '@/pages/system/Org/typings';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import { useIntl } from '@@/plugin-locale/localeExports';
+import OrgModel from '@/pages/system/Org/model';
+import { service } from '@/pages/system/Org';
 
 
 interface Props {
 interface Props {
-  obs: ObsModel;
+  refresh: () => void;
 }
 }
 
 
-const Save: React.FC<Props> = observer((props) => {
+const Save: React.FC<Props> = observer((props: Props) => {
   const intl = useIntl();
   const intl = useIntl();
-  const { obs } = props;
-  const form = createForm({});
+  const form = createForm({
+    initialValues: OrgModel.current,
+  });
 
 
   const SchemaField = createSchemaField({
   const SchemaField = createSchemaField({
     components: {
     components: {
       FormItem,
       FormItem,
       Input,
       Input,
+      NumberPicker,
     },
     },
   });
   });
 
 
@@ -33,8 +36,6 @@ const Save: React.FC<Props> = observer((props) => {
         type: 'string',
         type: 'string',
         'x-decorator': 'FormItem',
         'x-decorator': 'FormItem',
         'x-component': 'Input',
         'x-component': 'Input',
-        'x-component-props': {},
-        'x-decorator-props': {},
         name: 'id',
         name: 'id',
         required: true,
         required: true,
       },
       },
@@ -46,21 +47,17 @@ const Save: React.FC<Props> = observer((props) => {
         type: 'string',
         type: 'string',
         'x-decorator': 'FormItem',
         'x-decorator': 'FormItem',
         'x-component': 'Input',
         'x-component': 'Input',
-        'x-component-props': {},
-        'x-decorator-props': {},
         name: 'name',
         name: 'name',
         required: true,
         required: true,
       },
       },
-      sort: {
+      sortIndex: {
         title: intl.formatMessage({
         title: intl.formatMessage({
           id: 'pages.system.org.add.orderNumber',
           id: 'pages.system.org.add.orderNumber',
           defaultMessage: '序号',
           defaultMessage: '序号',
         }),
         }),
         type: 'string',
         type: 'string',
         'x-decorator': 'FormItem',
         'x-decorator': 'FormItem',
-        'x-component': 'Input',
-        'x-component-props': {},
-        'x-decorator-props': {},
+        'x-component': 'NumberPicker',
         name: 'name',
         name: 'name',
         required: true,
         required: true,
       },
       },
@@ -72,15 +69,29 @@ const Save: React.FC<Props> = observer((props) => {
         type: 'string',
         type: 'string',
         'x-decorator': 'FormItem',
         'x-decorator': 'FormItem',
         'x-component': 'Input.TextArea',
         'x-component': 'Input.TextArea',
-        'x-component-props': {},
-        'x-decorator-props': {},
         name: 'describe',
         name: 'describe',
       },
       },
     },
     },
   };
   };
 
 
+  const save = async () => {
+    const data: Record<string, unknown> = await form.submit!();
+    await service.update({ ...data, parentId: OrgModel.parentId });
+    message.success('保存成功');
+    OrgModel.closeEdit();
+    props.refresh();
+  };
+
   return (
   return (
-    <Modal title="编辑" visible={obs.edit} onCancel={obs.closeEdit}>
+    <Modal
+      onOk={save}
+      title={`${OrgModel.parentId ? '添加下级' : '编辑'}`}
+      visible={OrgModel.edit}
+      onCancel={() => {
+        OrgModel.closeEdit();
+        props.refresh();
+      }}
+    >
       <Form form={form} labelCol={5} wrapperCol={16}>
       <Form form={form} labelCol={5} wrapperCol={16}>
         <SchemaField schema={schema} />
         <SchemaField schema={schema} />
       </Form>
       </Form>

+ 27 - 64
src/pages/system/Org/index.tsx

@@ -3,50 +3,20 @@ import OrganizationChart from '@dabeng/react-orgchart';
 import styles from './index.less';
 import styles from './index.less';
 import { Drawer, Menu, message, Modal } from 'antd';
 import { Drawer, Menu, message, Modal } from 'antd';
 import NodeTemplate from '@/pages/system/Org/NodeTemplate';
 import NodeTemplate from '@/pages/system/Org/NodeTemplate';
-import { model } from '@formily/reactive';
 import { observer } from '@formily/react';
 import { observer } from '@formily/react';
-import { useEffect } from 'react';
+import React, { useEffect } from 'react';
 import Service from '@/pages/system/Org/service';
 import Service from '@/pages/system/Org/service';
 import encodeQuery from '@/utils/encodeQuery';
 import encodeQuery from '@/utils/encodeQuery';
-import type { ObsModel, OrgItem } from '@/pages/system/Org/typings';
 import Save from '@/pages/system/Org/Save';
 import Save from '@/pages/system/Org/Save';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import autzModel from '@/components/Authorization/autz';
 import autzModel from '@/components/Authorization/autz';
 import Authorization from '@/components/Authorization';
 import Authorization from '@/components/Authorization';
 import { BindModel } from '@/components/BindUser/model';
 import { BindModel } from '@/components/BindUser/model';
 import BindUser from '@/components/BindUser';
 import BindUser from '@/components/BindUser';
+import OrgModel from '@/pages/system/Org/model';
 
 
-const obs = model<ObsModel>({
-  edit: false,
-  parentId: '',
-  data: {},
-  current: {},
-  authorize: true,
-
-  update(data: Partial<OrgItem>) {
-    this.current = data;
-    this.edit = true;
-    this.parentId = undefined;
-  },
-
-  addNext(parentData: Partial<OrgItem>) {
-    this.parentId = parentData.id;
-    this.edit = true;
-    this.current = {};
-  },
-
-  authorized(data: Partial<OrgItem>) {
-    this.current = data;
-    this.authorize = true;
-  },
-  closeEdit() {
-    this.current = {};
-    this.edit = false;
-  },
-});
-
-const service = new Service('organization');
-const Org = observer(() => {
+export const service = new Service('organization');
+const Org: React.FC = observer(() => {
   const intl = useIntl();
   const intl = useIntl();
   const hitCenter = () => {
   const hitCenter = () => {
     const orgChart = document.getElementsByClassName('orgchart-container')[0];
     const orgChart = document.getElementsByClassName('orgchart-container')[0];
@@ -61,7 +31,7 @@ const Org = observer(() => {
         terms: { typeId: 'org' },
         terms: { typeId: 'org' },
       }),
       }),
     );
     );
-    obs.data = {
+    OrgModel.data = {
       id: null,
       id: null,
       name: intl.formatMessage({
       name: intl.formatMessage({
         id: 'pages.system.org',
         id: 'pages.system.org',
@@ -71,11 +41,12 @@ const Org = observer(() => {
       children: response.result,
       children: response.result,
     };
     };
     hitCenter();
     hitCenter();
-    return obs;
+    return OrgModel;
   };
   };
 
 
   const remove = async (id: string) => {
   const remove = async (id: string) => {
     await service.remove(id);
     await service.remove(id);
+    await query();
     message.success(
     message.success(
       intl.formatMessage({
       intl.formatMessage({
         id: 'pages.data.option.success',
         id: 'pages.data.option.success',
@@ -88,26 +59,25 @@ const Org = observer(() => {
   }, []);
   }, []);
 
 
   const menu = (nodeData: any) => {
   const menu = (nodeData: any) => {
+    const addNext = (
+      <Menu.Item key="addNext">
+        <a key="addNext" onClick={() => OrgModel.addNext(nodeData)}>
+          {intl.formatMessage({
+            id: 'pages.system.org.option.add',
+            defaultMessage: '添加下级',
+          })}
+        </a>
+      </Menu.Item>
+    );
     return nodeData.id === null ? (
     return nodeData.id === null ? (
-      <Menu>
-        <Menu.Item>
-          <a target="_blank" rel="noopener noreferrer" onClick={() => obs.addNext(nodeData)}>
-            {intl.formatMessage({
-              id: 'pages.system.org.option.add',
-              defaultMessage: '添加下级',
-            })}
-          </a>
-        </Menu.Item>
-      </Menu>
+      <Menu>{addNext}</Menu>
     ) : (
     ) : (
       <Menu>
       <Menu>
-        <Menu.Item>
+        <Menu.Item key="edit">
           <a
           <a
             key="edit"
             key="edit"
             onClick={() => {
             onClick={() => {
-              // setParentId(null);
-              // setCurrent(nodeData);
-              // setEdit(true);
+              OrgModel.update(nodeData);
             }}
             }}
           >
           >
             {intl.formatMessage({
             {intl.formatMessage({
@@ -116,15 +86,8 @@ const Org = observer(() => {
             })}
             })}
           </a>
           </a>
         </Menu.Item>
         </Menu.Item>
-        <Menu.Item>
-          <a key="addNext" onClick={() => obs.addNext(nodeData)}>
-            {intl.formatMessage({
-              id: 'pages.system.org.option.add',
-              defaultMessage: '添加下级',
-            })}
-          </a>
-        </Menu.Item>
-        <Menu.Item>
+        {addNext}
+        <Menu.Item key="autz">
           <a
           <a
             key="autz"
             key="autz"
             onClick={() => {
             onClick={() => {
@@ -139,7 +102,7 @@ const Org = observer(() => {
             })}
             })}
           </a>
           </a>
         </Menu.Item>
         </Menu.Item>
-        <Menu.Item>
+        <Menu.Item key="bindUser">
           <a
           <a
             key="bindUser"
             key="bindUser"
             onClick={() => {
             onClick={() => {
@@ -157,8 +120,8 @@ const Org = observer(() => {
             })}
             })}
           </a>
           </a>
         </Menu.Item>
         </Menu.Item>
-        <Menu.Item>
-          <a target="_blank" rel="noopener noreferrer" onClick={() => remove(nodeData.id)}>
+        <Menu.Item key="delete">
+          <a key="delete" onClick={() => remove(nodeData.id)}>
             {intl.formatMessage({
             {intl.formatMessage({
               id: 'pages.data.option.remove',
               id: 'pages.data.option.remove',
               defaultMessage: '删除',
               defaultMessage: '删除',
@@ -172,14 +135,14 @@ const Org = observer(() => {
     <PageContainer>
     <PageContainer>
       <div className={styles.orgContainer}>
       <div className={styles.orgContainer}>
         <OrganizationChart
         <OrganizationChart
-          datasource={obs.data}
+          datasource={OrgModel.data}
           pan={true}
           pan={true}
           NodeTemplate={(nodeData: any) => (
           NodeTemplate={(nodeData: any) => (
             <NodeTemplate data={nodeData.nodeData} action={menu(nodeData.nodeData)} />
             <NodeTemplate data={nodeData.nodeData} action={menu(nodeData.nodeData)} />
           )}
           )}
         />
         />
       </div>
       </div>
-      <Save obs={obs} />
+      <Save refresh={query} />
       <Modal
       <Modal
         visible={BindModel.visible}
         visible={BindModel.visible}
         closable={false}
         closable={false}

+ 33 - 0
src/pages/system/Org/model.ts

@@ -0,0 +1,33 @@
+import { model } from '@formily/reactive';
+import type { OrgItem, OrgModelType } from '@/pages/system/Org/typings';
+
+const OrgModel = model<OrgModelType>({
+  edit: false,
+  parentId: '',
+  data: {},
+  current: {},
+  authorize: true,
+
+  update(data: Partial<OrgItem>) {
+    this.current = data;
+    this.edit = true;
+    this.parentId = undefined;
+  },
+
+  addNext(parentData: Partial<OrgItem>) {
+    this.parentId = parentData.id;
+    this.edit = true;
+    this.current = {};
+  },
+
+  authorized(data: Partial<OrgItem>) {
+    this.current = data;
+    this.authorize = true;
+  },
+  closeEdit() {
+    this.current = {};
+    this.edit = false;
+  },
+});
+
+export default OrgModel;

+ 2 - 2
src/pages/system/Org/typings.d.ts

@@ -1,6 +1,6 @@
 export type OrgItem = {
 export type OrgItem = {
   id: string;
   id: string;
-  parentId: string;
+  parentId: string | undefined;
   path: string;
   path: string;
   sortIndex: number;
   sortIndex: number;
   level: number;
   level: number;
@@ -14,7 +14,7 @@ export type OrgItem = {
   children?: OrgItem[];
   children?: OrgItem[];
 };
 };
 
 
-export type ObsModel = {
+export type OrgModelType = {
   data: Partial<{
   data: Partial<{
     id: null;
     id: null;
     name: string;
     name: string;

+ 3 - 3
src/utils/BaseService.ts

@@ -24,15 +24,15 @@ class BaseService<T> implements IBaseService<T> {
     return request(`${this.uri}/_query/`, { params, method: 'GET' });
     return request(`${this.uri}/_query/`, { params, method: 'GET' });
   }
   }
 
 
-  queryNoPaging(params: any): Promise<any> {
+  queryNoPaging(params: any): Promise<unknown> {
     return request(`${this.uri}/_query/no-paging?paging=false`, { params, method: 'GET' });
     return request(`${this.uri}/_query/no-paging?paging=false`, { params, method: 'GET' });
   }
   }
 
 
-  remove(id: string): Promise<any> {
+  remove(id: string): Promise<unknown> {
     return request(`${this.uri}/${id}`, { method: 'DELETE' });
     return request(`${this.uri}/${id}`, { method: 'DELETE' });
   }
   }
 
 
-  save(data: T): Promise<any> {
+  save(data: T): Promise<unknown> {
     return request(this.uri, { data, method: 'POST' });
     return request(this.uri, { data, method: 'POST' });
   }
   }