feat: 初始化项目并完成基础功能开发

- 完成项目初始化
- 实现用户注册、登录功能
- 完成用户管理与权限管理模块
- 开发后端 Tracker 服务器项目管理接口
- 实现日志管理接口
Change-Id: Ia4bde1c9ff600352a7ff0caca0cc50b02cad1af7
diff --git a/react-ui/src/pages/System/User/components/AuthRole.tsx b/react-ui/src/pages/System/User/components/AuthRole.tsx
new file mode 100644
index 0000000..120d966
--- /dev/null
+++ b/react-ui/src/pages/System/User/components/AuthRole.tsx
@@ -0,0 +1,81 @@
+import React, { useEffect } from 'react';
+import { Form, Modal } from 'antd';
+import { useIntl } from '@umijs/max';
+import { ProForm, ProFormSelect } from '@ant-design/pro-components';
+
+/* *
+ *
+ * @author whiteshader@163.com
+ * @datetime  2023/02/06
+ * 
+ * */
+
+export type FormValueType = any & Partial<API.System.Dept>;
+
+export type AuthRoleFormProps = {
+    onCancel: (flag?: boolean, formVals?: FormValueType) => void;
+    onSubmit: (values: FormValueType) => Promise<void>;
+    open: boolean;
+    roleIds: number[];
+    roles: string[];
+};
+
+const AuthRoleForm: React.FC<AuthRoleFormProps> = (props) => {
+    const [form] = Form.useForm();
+
+    useEffect(() => {
+        form.resetFields();
+        form.setFieldValue( 'roleIds', props.roleIds);
+    });
+
+    const intl = useIntl();
+    const handleOk = () => {
+        form.submit();
+    };
+    const handleCancel = () => {
+        props.onCancel();
+    };
+    const handleFinish = async (values: Record<string, any>) => {
+        props.onSubmit(values as FormValueType);
+    };
+
+    return (
+        <Modal
+            width={640}
+            title={intl.formatMessage({
+                id: 'system.user.auth.role',
+                defaultMessage: '分配角色',
+            })}
+            open={props.open}
+            destroyOnClose
+            forceRender
+            onOk={handleOk}
+            onCancel={handleCancel}
+        >
+            <ProForm
+                form={form}
+                grid={true}
+                layout="horizontal"
+                onFinish={handleFinish}
+                initialValues={{
+                    login_password: '',
+                    confirm_password: '',
+                }}
+            >
+                <ProFormSelect
+                    name="roleIds"
+                    mode="multiple"
+                    label={intl.formatMessage({
+                        id: 'system.user.role',
+                        defaultMessage: '角色',
+                    })}
+                    options={props.roles}
+                    placeholder="请选择角色"
+                    rules={[{ required: true, message: '请选择角色!' }]}
+                />
+            </ProForm>
+        </Modal>
+    );
+};
+
+export default AuthRoleForm;
diff --git a/react-ui/src/pages/System/User/components/DeptTree.tsx b/react-ui/src/pages/System/User/components/DeptTree.tsx
new file mode 100644
index 0000000..d1a085c
--- /dev/null
+++ b/react-ui/src/pages/System/User/components/DeptTree.tsx
@@ -0,0 +1,69 @@
+import React, { useState, useEffect } from 'react';
+import { Tree, message } from 'antd';
+import { getDeptTree } from '@/services/system/user';
+
+const { DirectoryTree } = Tree;
+
+/* *
+ *
+ * @author whiteshader@163.com
+ * @datetime  2023/02/06
+ * 
+ * */
+
+
+export type TreeProps = {
+  onSelect: (values: any) => Promise<void>;
+};
+
+const DeptTree: React.FC<TreeProps> = (props) => {
+  const [treeData, setTreeData] = useState<any>([]);
+  const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
+  const [autoExpandParent, setAutoExpandParent] = useState<boolean>(true);
+
+  const fetchDeptList = async () => {
+    const hide = message.loading('正在查询');
+    try {
+      await getDeptTree({}).then((res: any) => {
+        const exKeys = [];
+        exKeys.push('1');
+        setTreeData(res);
+        exKeys.push(res[0].children[0].id);
+        setExpandedKeys(exKeys);
+        props.onSelect(res[0].children[0]);
+      });
+      hide();
+      return true;
+    } catch (error) {
+      hide();
+      return false;
+    }
+  };
+
+  useEffect(() => {
+    fetchDeptList();
+  }, []);
+
+  const onSelect = (keys: React.Key[], info: any) => {
+    props.onSelect(info.node);
+  };
+
+  const onExpand = (expandedKeysValue: React.Key[]) => {
+    setExpandedKeys(expandedKeysValue);
+    setAutoExpandParent(false);
+  };
+
+  return (
+    <DirectoryTree
+      // multiple
+      defaultExpandAll
+      onExpand={onExpand}
+      expandedKeys={expandedKeys}
+      autoExpandParent={autoExpandParent}
+      onSelect={onSelect}
+      treeData={treeData}
+    />
+  );
+};
+
+export default DeptTree;
diff --git a/react-ui/src/pages/System/User/components/ResetPwd.tsx b/react-ui/src/pages/System/User/components/ResetPwd.tsx
new file mode 100644
index 0000000..5523cd6
--- /dev/null
+++ b/react-ui/src/pages/System/User/components/ResetPwd.tsx
@@ -0,0 +1,95 @@
+import React from 'react';
+import { Form, Modal } from 'antd';
+import { useIntl } from '@umijs/max';
+import { ProForm, ProFormText } from '@ant-design/pro-components';
+
+/* *
+ *
+ * @author whiteshader@163.com
+ * @datetime  2023/02/06
+ * 
+ * */
+
+export type FormValueType = any & Partial<API.System.User>;
+
+export type UpdateFormProps = {
+  onCancel: (flag?: boolean, formVals?: FormValueType) => void;
+  onSubmit: (values: FormValueType) => Promise<void>;
+  open: boolean;
+  values: Partial<API.System.User>;
+};
+
+const UpdateForm: React.FC<UpdateFormProps> = (props) => {
+  const [form] = Form.useForm();
+  const loginPassword = Form.useWatch('password', form);
+  const userId = props.values.userId;
+
+  const intl = useIntl();
+  const handleOk = () => {
+    form.submit();
+  };
+  const handleCancel = () => {
+    props.onCancel();
+  };
+  const handleFinish = async (values: Record<string, any>) => {
+    props.onSubmit({ ...values, userId } as FormValueType);
+  };
+
+  const checkPassword = (rule: any, value: string) => {
+    if (value === loginPassword) {
+      // 校验条件自定义
+      return Promise.resolve();
+    }
+    return Promise.reject(new Error('两次密码输入不一致'));
+  };
+
+  return (
+    <Modal
+      width={640}
+      title={intl.formatMessage({
+        id: 'system.user.reset.password',
+        defaultMessage: '密码重置',
+      })}
+      open={props.open}
+      destroyOnClose
+      onOk={handleOk}
+      onCancel={handleCancel}
+    >
+      <ProForm
+        grid={true}
+        form={form}
+        layout="horizontal"
+        onFinish={handleFinish}
+        initialValues={{
+          password: '',
+          confirm_password: '',
+        }}
+      >
+        <p>请输入用户{props.values.userName}的新密码!</p>
+        <ProFormText.Password
+          name="password"
+          label="登录密码"
+          rules={[
+            {
+              required: true,
+              message: '登录密码不可为空。',
+            },
+          ]}
+        />
+        <ProFormText.Password
+          name="confirm_password"
+          label="确认密码"
+          rules={[
+            {
+              required: true,
+              message: "确认密码",
+            },
+            { validator: checkPassword },
+          ]}
+        />
+      </ProForm>
+    </Modal>
+  );
+};
+
+export default UpdateForm;