Procházet zdrojové kódy

fix(user): user manager

Lind před 3 roky
rodič
revize
57333610a9

+ 2 - 0
config/proxy.ts

@@ -11,6 +11,8 @@ export default {
     '/jetlinks': {
       target: 'http://192.168.33.222:8844/',
       ws: 'ws://192.168.33.222:8844/',
+      // target: 'http://192.168.32.44:8844/',
+      // ws: 'ws://192.168.32.44:8844/',
       // ws: 'ws://demo.jetlinks.cn/jetlinks',
       // target: 'http://demo.jetlinks.cn/jetlinks',
       changeOrigin: true,

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

@@ -16,6 +16,7 @@ export const CurdModel = model<Option>({
   },
 
   update(current: any) {
+    console.log('触发编辑');
     Store.set(SystemConst.BASE_CURD_MODEL, 'edit');
     Store.set(SystemConst.BASE_CURD_MODAL_VISIBLE, true);
     Store.set(SystemConst.BASE_CURD_CURRENT, current);

+ 9 - 1
src/pages/system/Role/index.tsx

@@ -1,5 +1,5 @@
 import { PageContainer } from '@ant-design/pro-layout';
-import React, { useRef } from 'react';
+import React, { useEffect, useRef } from 'react';
 import { EditOutlined, KeyOutlined, MinusOutlined, UserAddOutlined } from '@ant-design/icons';
 import { Drawer, message, Modal, Popconfirm, Tooltip } from 'antd';
 import type { ProColumns, ActionType } from '@jetlinks/pro-table';
@@ -12,6 +12,7 @@ import autzModel from '@/components/Authorization/autz';
 import Authorization from '@/components/Authorization';
 import { BindModel } from '@/components/BindUser/model';
 import BindUser from '@/components/BindUser';
+// import { useParams } from 'umi';
 
 const service = new BaseService<RoleItem>('dimension');
 
@@ -221,6 +222,13 @@ const Role: React.FC = observer(() => {
     },
   };
 
+  // const params = useParams<{ tag: boolean }>({ tag: false });
+  useEffect(() => {
+    // console.log(params.tag);
+    // if (params.tag) {
+    //   CurdModel.add();
+    // }
+  });
   return (
     <PageContainer>
       <BaseCrud<RoleItem>

+ 258 - 0
src/pages/system/User/Save/index.tsx

@@ -0,0 +1,258 @@
+import { message, Modal } from 'antd';
+import { useIntl } from 'umi';
+import type { Field } from '@formily/core';
+import { createForm } from '@formily/core';
+import { createSchemaField } from '@formily/react';
+import React, { useEffect, useState } from 'react';
+import * as ICONS from '@ant-design/icons';
+import { Form, FormItem, Input, Password, Select, Switch } from '@formily/antd';
+import type { ISchema } from '@formily/json-schema';
+import { PlusOutlined } from '@ant-design/icons';
+import { action } from '@formily/reactive';
+import type { Response } from '@/utils/typings';
+import { service } from '@/pages/system/User';
+
+interface Props {
+  model: 'add' | 'edit' | 'query';
+  data: Partial<UserItem>;
+  close: () => void;
+}
+
+const Save = (props: Props) => {
+  const { model } = props;
+  const intl = useIntl();
+
+  const [data, setData] = useState<Partial<UserItem>>(props.data);
+
+  const getRole = () => service.queryRoleList();
+
+  const getOrg = () => service.queryOrgList();
+
+  const useAsyncDataSource = (api: any) => (field: Field) => {
+    field.loading = true;
+    api(field).then(
+      action.bound!((resp: Response<any>) => {
+        field.dataSource = resp.result?.map((item: Record<string, unknown>) => ({
+          label: item.name,
+          value: item.id,
+        }));
+        field.loading = false;
+      }),
+    );
+  };
+
+  const getUser = async () => {
+    if (props.data.id) {
+      console.log('id');
+      const response: Response<UserItem> = await service.queryDetail(props.data?.id);
+      if (response.status === 200) {
+        const temp = response.result as UserItem;
+        temp.orgIdList = (temp.orgList as { id: string; name: string }[]).map((item) => item.id);
+        temp.roleIdList = (temp.roleList as { id: string; name: string }[]).map((item) => item.id);
+        setData(temp);
+      }
+    }
+  };
+  useEffect(() => {
+    if (model === 'edit') {
+      getUser();
+    } else {
+      setData({});
+    }
+  }, [props.data, props.model]);
+
+  const form = createForm({
+    validateFirst: true,
+    initialValues: data,
+  });
+
+  const SchemaField = createSchemaField({
+    components: {
+      FormItem,
+      Input,
+      Password,
+      Switch,
+      Select,
+    },
+    scope: {
+      icon(name: any) {
+        return React.createElement(ICONS[name]);
+      },
+    },
+  });
+
+  const schema: ISchema = {
+    type: 'object',
+    properties: {
+      name: {
+        title: intl.formatMessage({
+          id: 'pages.system.name',
+          defaultMessage: '姓名',
+        }),
+        type: 'string',
+        'x-decorator': 'FormItem',
+        'x-component': 'Input',
+        'x-component-props': {},
+        'x-decorator-props': {},
+        name: 'name',
+        required: true,
+      },
+      username: {
+        title: intl.formatMessage({
+          id: 'pages.system.username',
+          defaultMessage: '用户名',
+        }),
+        type: 'string',
+        'x-decorator': 'FormItem',
+        'x-component': 'Input',
+        'x-component-props': {
+          disabled: model === 'edit',
+        },
+        'x-decorator-props': {},
+        name: 'username',
+        required: true,
+      },
+      password: {
+        type: 'string',
+        title: intl.formatMessage({
+          id: 'pages.system.password',
+          defaultMessage: '密码',
+        }),
+        'x-decorator': 'FormItem',
+        'x-component': 'Password',
+        'x-component-props': {
+          checkStrength: true,
+          placeholder: '********',
+        },
+        required: model === 'add',
+        'x-reactions': [
+          {
+            dependencies: ['.confirmPassword'],
+            fulfill: {
+              state: {
+                selfErrors:
+                  '{{$deps[0] && $self.value && $self.value !==$deps[0] ? "确认密码不匹配" : ""}}',
+              },
+            },
+          },
+        ],
+        'x-decorator-props': {},
+        name: 'password',
+      },
+      confirmPassword: {
+        type: 'string',
+        title: intl.formatMessage({
+          id: 'pages.system.confirmPassword',
+          defaultMessage: '确认密码?',
+        }),
+        'x-decorator': 'FormItem',
+        'x-component': 'Password',
+        'x-component-props': {
+          checkStrength: true,
+          placeholder: '********',
+        },
+        'x-reactions': [
+          {
+            dependencies: ['.password'],
+            fulfill: {
+              state: {
+                selfErrors:
+                  '{{$deps[0] && $self.value && $self.value !== $deps[0] ? "确认密码不匹配" : ""}}',
+              },
+            },
+          },
+        ],
+        'x-decorator-props': {},
+        name: 'confirmPassword',
+        required: model === 'add',
+      },
+      roleIdList: {
+        title: '角色',
+        'x-decorator': 'FormItem',
+        'x-component': 'Select',
+        'x-component-props': {
+          mode: 'multiple',
+        },
+        'x-reactions': ['{{useAsyncDataSource(getRole)}}'],
+        'x-decorator-props': {
+          addonAfter: (
+            <a
+              // href={`${origin}/#/system/role`}
+              // target='_blank'
+              // rel='noreferrer'
+              onClick={() => {
+                // const test = window.open(`${origin}/#/system/role`);
+                // test!.onSuccess1 = (data: any) => {
+                //   form.setFieldState('role', state => {
+                //     state.dataSource = [...testEnum, { label: '测试数据A', value: 'testA' }];
+                //   });
+                // console.log(JSON.stringify(data));
+                // testEnum.push({label:'测试数据A',value:'testA'});
+                // setTestEnum([...testEnum, { label: '测试数据A', value: 'testA' }]);
+                // };
+              }}
+            >
+              <PlusOutlined />
+            </a>
+          ),
+        },
+      },
+      orgIdList: {
+        title: '部门',
+        'x-decorator': 'FormItem',
+        'x-component': 'Select',
+        'x-component-props': {
+          mode: 'multiple',
+          showArrow: true,
+        },
+        'x-decorator-props': {
+          addonAfter: (
+            <a>
+              <PlusOutlined />
+            </a>
+          ),
+        },
+        'x-reactions': ['{{useAsyncDataSource(getOrg)}}'],
+      },
+    },
+  };
+
+  const save = async () => {
+    const value = await form.submit<UserItem>();
+    const temp: any = {};
+    temp.id = value.id;
+    temp.user = value;
+    temp.orgIdList = value.orgIdList;
+    temp.roleIdList = value.roleIdList;
+    const response = await service.saveUser(temp, model);
+    if (response.status === 200) {
+      message.success(
+        intl.formatMessage({
+          id: 'pages.data.option.success',
+          defaultMessage: '操作成功',
+        }),
+      );
+    } else {
+      message.error('操作失败!');
+    }
+    props.close();
+  };
+
+  return (
+    <Modal
+      title={intl.formatMessage({
+        id: `pages.data.option.${model}`,
+        defaultMessage: '编辑',
+      })}
+      maskClosable={false}
+      visible={model !== 'query'}
+      onCancel={props.close}
+      onOk={save}
+    >
+      <Form form={form} labelCol={4} wrapperCol={18}>
+        <SchemaField schema={schema} scope={{ useAsyncDataSource, getRole, getOrg }} />
+      </Form>
+    </Modal>
+  );
+};
+export default Save;

+ 55 - 149
src/pages/system/User/index.tsx

@@ -1,36 +1,42 @@
+import Service from '@/pages/system/User/serivce';
 import { PageContainer } from '@ant-design/pro-layout';
-import { useEffect, useRef, useState } from 'react';
+import SearchComponent from '@/components/SearchComponent';
+import type { ActionType, ProColumns } from '@jetlinks/pro-table';
+import ProTable from '@jetlinks/pro-table';
+import { Button, Card, message, Popconfirm, Tooltip } from 'antd';
 import {
+  CloseCircleOutlined,
   EditOutlined,
   KeyOutlined,
-  CloseCircleOutlined,
   PlayCircleOutlined,
+  PlusOutlined,
 } from '@ant-design/icons';
-import { Tooltip, Popconfirm, message, Drawer } from 'antd';
-import type { ProColumns, ActionType } from '@jetlinks/pro-table';
-import BaseCrud from '@/components/BaseCrud';
-import { CurdModel } from '@/components/BaseCrud/model';
-import BaseService from '@/utils/BaseService';
-import { observer } from '@formily/react';
-import { Store } from 'jetlinks-store';
-import SystemConst from '@/utils/const';
-import { useIntl } from '@@/plugin-locale/localeExports';
-import type { ISchema } from '@formily/json-schema';
-import Authorization from '@/components/Authorization';
 import autzModel from '@/components/Authorization/autz';
-// import SearchComponent from '@/components/SearchComponent';
+import { useIntl } from '@@/plugin-locale/localeExports';
+import { useRef, useState } from 'react';
+import Save from './Save';
+import { observer } from '@formily/react';
+
+export const service = new Service('user');
 
-export const service = new BaseService<UserItem>('user');
 const User = observer(() => {
   const intl = useIntl();
   const actionRef = useRef<ActionType>();
 
-  const [model1, setModel] = useState(CurdModel.model);
-
-  useEffect(() => {
-    const modelSubscription = Store.subscribe(SystemConst.BASE_CURD_MODEL, setModel);
-    return () => modelSubscription.unsubscribe();
-  }, [CurdModel.model]);
+  const [model, setMode] = useState<'add' | 'edit' | 'query'>('query');
+  const [current, setCurrent] = useState<Partial<UserItem>>({});
+  const edit = async (record: UserItem) => {
+    setMode('edit');
+    setCurrent(record);
+    // const response: Response<UserItem> = await service.queryDetail(record.id);
+    // if (response.status === 200) {
+    //   const temp = response.result as UserItem;
+    //   temp.orgIdList = (temp.orgList as { id: string, name: string }[]).map((item) => item.id);
+    //   temp.roleIdList = (temp.roleList as { id: string, name: string }[]).map(item => item.id);
+    //   state.model = 'edit';
+    //   state.current = temp;
+    // }
+  };
 
   const columns: ProColumns<UserItem>[] = [
     {
@@ -133,14 +139,7 @@ const User = observer(() => {
       align: 'center',
       width: 200,
       render: (text, record) => [
-        <a
-          key="editable"
-          onClick={() => {
-            CurdModel.update(record);
-            CurdModel.model = 'edit';
-            setModel('edit');
-          }}
-        >
+        <a key="editable" onClick={() => edit(record)}>
           <Tooltip
             title={intl.formatMessage({
               id: 'pages.data.option.edit',
@@ -201,132 +200,39 @@ const User = observer(() => {
     },
   ];
 
-  const schema: ISchema = {
-    type: 'object',
-    properties: {
-      username: {
-        title: intl.formatMessage({
-          id: 'pages.system.username',
-          defaultMessage: '用户名',
-        }),
-        type: 'string',
-        'x-decorator': 'FormItem',
-        'x-component': 'Input',
-        'x-component-props': {
-          disabled: model1 === 'edit',
-        },
-        'x-decorator-props': {},
-        name: 'username',
-        required: true,
-      },
-      name: {
-        title: intl.formatMessage({
-          id: 'pages.system.name',
-          defaultMessage: '姓名',
-        }),
-        type: 'string',
-        'x-decorator': 'FormItem',
-        'x-component': 'Input',
-        'x-component-props': {},
-        'x-decorator-props': {},
-        name: 'name',
-        required: true,
-      },
-      password: {
-        type: 'string',
-        title: intl.formatMessage({
-          id: 'pages.system.password',
-          defaultMessage: '密码',
-        }),
-        'x-decorator': 'FormItem',
-        'x-component': 'Password',
-        'x-component-props': {
-          checkStrength: true,
-        },
-        // 'x-hidden': model === 'edit',
-        'x-reactions': [
-          {
-            dependencies: ['.confirmPassword'],
-            fulfill: {
-              state: {
-                errors:
-                  '{{$deps[0] && $self.value && $self.value !==$deps[0] ? "确认密码不匹配" : ""}}',
-              },
-            },
-          },
-        ],
-        'x-decorator-props': {},
-        name: 'password',
-        required: false,
-      },
-      confirmPassword: {
-        type: 'string',
-        title: intl.formatMessage({
-          id: 'pages.system.confirmPassword',
-          defaultMessage: '确认密码?',
-        }),
-        'x-decorator': 'FormItem',
-        'x-component': 'Password',
-        // 'x-hidden': model === 'edit',
-        'x-component-props': {
-          checkStrength: true,
-        },
-        'x-reactions': [
-          {
-            dependencies: ['.password'],
-            fulfill: {
-              state: {
-                errors:
-                  '{{$deps[0] && $self.value && $self.value !== $deps[0] ? "确认密码不匹配" : ""}}',
-              },
-            },
-          },
-        ],
-        'x-decorator-props': {},
-        name: 'confirmPassword',
-        required: false,
-      },
-    },
-  };
-
-  intl.formatMessage({
-    id: 'pages.system.user',
-    defaultMessage: '默认值',
-  });
+  const [param, setParam] = useState({});
   return (
     <PageContainer>
-      <BaseCrud<UserItem>
-        actionRef={actionRef}
+      <Card style={{ marginBottom: '20px' }}>
+        <SearchComponent
+          field={columns}
+          onSearch={(data) => setParam({ terms: data })}
+          target="user"
+        />
+      </Card>
+      <ProTable<UserItem>
+        params={param}
         columns={columns}
         search={false}
-        service={service}
-        title={intl.formatMessage({
-          id: 'pages.system.user',
-          defaultMessage: '用户管理',
-        })}
-        moduleName="user"
-        schema={schema}
+        request={async (params = {}) => service.query(params)}
+        toolBarRender={() => [
+          <Button
+            onClick={() => {
+              setMode('add');
+            }}
+            key="button"
+            icon={<PlusOutlined />}
+            type="primary"
+          >
+            {intl.formatMessage({
+              id: 'pages.data.option.add',
+              defaultMessage: '新增',
+            })}
+          </Button>,
+        ]}
       />
-      <Drawer
-        title={intl.formatMessage({
-          id: 'pages.data.option.authorize',
-          defaultMessage: '授权',
-        })}
-        width="50vw"
-        visible={autzModel.visible}
-        onClose={() => {
-          autzModel.visible = false;
-        }}
-      >
-        <Authorization
-          close={() => {
-            autzModel.visible = false;
-          }}
-          target={autzModel.autzTarget}
-        />
-      </Drawer>
+      <Save model={model} close={() => setMode('query')} data={current} />
     </PageContainer>
   );
 });
-
 export default User;

+ 41 - 0
src/pages/system/User/serivce.ts

@@ -0,0 +1,41 @@
+import BaseService from '@/utils/BaseService';
+import { request } from 'umi';
+import SystemConst from '@/utils/const';
+
+class Service extends BaseService<UserItem> {
+  queryRoleList = (params?: any) =>
+    request(`${SystemConst.API_BASE}/role/_query/no-paging?paging=false`, {
+      method: 'GET',
+      params,
+    });
+
+  queryOrgList = (params?: any) =>
+    request(`${SystemConst.API_BASE}/organization/_all/tree`, {
+      method: 'GET',
+      params,
+    });
+
+  queryDetail = (id: string) =>
+    request(`/${SystemConst.API_BASE}/user/detail/${id}`, {
+      method: 'GET',
+    });
+
+  saveUser = (data: UserItem, type: 'add' | 'edit' | 'query') => {
+    const map = {
+      add: {
+        api: '_create',
+        method: 'POST',
+      },
+      edit: {
+        api: `${data.id}/_update`,
+        method: 'PUT',
+      },
+    };
+    return request(`/${SystemConst.API_BASE}/user/detail/${map[type].api}`, {
+      method: map[type].method,
+      data,
+    });
+  };
+}
+
+export default Service;

+ 5 - 0
src/pages/system/User/typings.d.ts

@@ -8,4 +8,9 @@ type UserItem = {
   telephone?: string;
   avatar?: string;
   description?: string;
+
+  orgList?: { id: string; name: string }[] | string[];
+  roleList?: { id: string; name: string }[] | string[];
+  orgIdList?: string[];
+  roleIdList?: string[];
 };