34 Commits

Author SHA1 Message Date
Lhk0001
78aeee5871 雷闳焜:完成富文本编辑器的部分,由于下载引入老出问题,暂时用云调用 2023-11-23 16:59:07 +08:00
Lhk0001
912d6b2a7e Merge branch 'leeiNew' of http://git.feashow.cn/wenhua/fateverse-react into leeiNew 2023-11-23 13:35:22 +08:00
Lhk0001
a6b6c20ffe 完成大致富文本编辑器(因为本地下载引入一直出错,暂时先用云加载) 2023-11-23 13:24:15 +08:00
wenhua
5651213a6b Merge pull request 'dev' (#25) from dev into leeiNew
Reviewed-on: http://git.feashow.cn/wenhua/fateverse-react/pulls/25
2023-11-20 13:27:36 +00:00
wenhua
f87666b1de Merge pull request '唐简:提交新分支' (#24) from tangjian_new into dev
Reviewed-on: http://git.feashow.cn/wenhua/fateverse-react/pulls/24
2023-11-20 13:25:22 +00:00
Jim__TT
f6889ac3df 唐简:提交新分支 2023-11-20 21:24:43 +08:00
wenhua
c1ae6a9e31 Merge pull request '修改api路径问题,以及部分没用变量注释(有一个暂时不敢动)' (#23) from leeiNew into dev
Reviewed-on: http://git.feashow.cn/wenhua/fateverse-react/pulls/23
2023-11-20 12:54:56 +00:00
Lhk0001
95b5604801 修改api路径问题,以及部分没用变量注释(有一个暂时不敢动) 2023-11-20 20:52:43 +08:00
wenhua
9a6bd457b0 Merge pull request 'leeiNew' (#22) from leeiNew into dev
Reviewed-on: http://git.feashow.cn/wenhua/fateverse-react/pulls/22
2023-11-20 12:00:28 +00:00
wenhua
3995318ff8 修复问题文件 2023-11-18 14:50:05 +08:00
Lhk0001
add8a9524d 雷的新建分支 2023-11-18 14:37:29 +08:00
clay
2b2a5c65aa ci: 测试ci 2023-11-11 17:25:38 +08:00
clay
d6b9d4baca ci: 测试ci 2023-11-11 17:25:30 +08:00
clay
3c4f562e17 ci: 测试ci 2023-11-11 17:18:44 +08:00
wenhua
b59c94fbd3 Merge pull request '11' (#17) from dev_wenhua_plus into dev
Reviewed-on: http://git.feashow.cn/wenhua/fateverse-react/pulls/17
2023-11-11 09:17:05 +00:00
wenhua
4315e42521 11 2023-11-11 17:16:03 +08:00
clay
ae8e8cd9c0 ci: 测试ci 2023-11-11 17:13:56 +08:00
clay
f86a49d1e8 Merge pull request 'ci : 测试ci运行' (#14) from clay into dev
Reviewed-on: http://git.feashow.cn/wenhua/fateverse-react/pulls/14
2023-11-11 08:56:05 +00:00
wenhua
ca4bc80156 Merge pull request 'feat: 新增菜单图标, 搜索组件' (#13) from dev_wenhua_plus into dev
Reviewed-on: http://git.feashow.cn/wenhua/fateverse-react/pulls/13
2023-11-10 06:32:29 +00:00
wenhua
ff24a5cec9 feat: 新增菜单图标, 搜索组件 2023-11-10 14:31:25 +08:00
clay
7dbb60d774 ci : 测试ci运行 2023-11-01 22:43:52 +08:00
clay
2eeaf31cf4 Merge pull request 'ci : 测试ci运行' (#10) from clay into dev
Reviewed-on: http://git.feashow.cn/wenhua/fateverse-react/pulls/10
2023-11-01 14:35:36 +00:00
clay
20c98c6ed2 ci : 测试ci运行 2023-11-01 22:34:55 +08:00
clay
0e828bd15f Merge pull request 'ci : 测试ci运行' (#9) from clay into dev
Reviewed-on: http://git.feashow.cn/wenhua/fateverse-react/pulls/9
2023-11-01 14:34:18 +00:00
clay
460a5bd060 ci : 测试ci运行 2023-11-01 22:33:49 +08:00
clay
a1d8629dbe Merge pull request 'ci : 测试ci运行' (#8) from clay into dev
Reviewed-on: http://git.feashow.cn/wenhua/fateverse-react/pulls/8
2023-11-01 14:32:40 +00:00
clay
e489bfa89c ci : 测试ci运行 2023-11-01 22:31:49 +08:00
wenhua
23cebffc12 温华:暂时修复打包失败问题 2023-11-01 11:30:19 +08:00
wenhua
1e768b147f 温华: 添加authstore并对数据做终端缓存 2023-10-16 14:29:50 +08:00
wenhua
4bf63e1306 温华: 添加404路由到常驻路由表 2023-10-16 14:28:58 +08:00
wenhua
72392e9571 温华: 精简Layout文件 2023-10-16 14:28:05 +08:00
wenhua
28047d7061 温华: 修改按钮权限组件为无权限移除节点 2023-10-16 14:27:35 +08:00
wenhua
60788d7090 温华: 迁移路由请求和用户信息请求到路由拦截处 2023-10-16 14:26:37 +08:00
wenhua
730b12c2e4 温华: 登录用户信息api 2023-10-16 14:25:15 +08:00
88 changed files with 9693 additions and 1370 deletions

View File

@@ -7,36 +7,18 @@ steps:
volumes:
- name: cache
path: /drone/src/node_modules
- name: build
path: /app/build
commands:
- export CI=false
- mkdir -p /app/build/$DRONE_REPO_NAME
- rm -rf /app/build/$DRONE_REPO_NAME/*
- cp deployment.yml /app/build/$DRONE_REPO_NAME/
- cp Dockerfile /app/build/$DRONE_REPO_NAME/
- cp .dockerignore /app/build/$DRONE_REPO_NAME/
- cp default.conf /app/build/$DRONE_REPO_NAME/
- cp docker.sh /app/build/$DRONE_REPO_NAME/
- cp nginx.conf /app/build/$DRONE_REPO_NAME/
- npm -v
- mkdir -p ./node_modules
- export NODE_MODULES_PATH=`pwd`/node_modules
- npm config set registry https://registry.npm.taobao.org
- set NODE_OPTIONS=--openssl-legacy-provider
- npm install
- npm run build
- ls /app/build/$DRONE_REPO_NAME/
- echo $NODE_MODULES_PATH
- cp -r dist /app/build/$DRONE_REPO_NAME
- name: build-docker # 制作docker镜像
image: docker # 使用官方docker镜像
volumes: # 将容器内目录挂载到宿主机
- name: build
path: /app/build
- name: docker
path: /var/run/docker.sock # 挂载宿主机的docker
- name: config
@@ -51,14 +33,10 @@ steps:
REGISTRY_NAMESPACE:
from_secret: registry_namespace
commands: # 定义在Docker容器中执行的shell命令
- cd /app/build/$DRONE_REPO_NAME/
- cat Dockerfile
- sed -i 's/$REGISTRY/'"$REGISTRY"'/' deployment.yml
- sed -i 's/$REGISTRY_NAMESPACE/'"$REGISTRY_NAMESPACE"'/' deployment.yml
- sed -i 's/$DRONE_REPO_NAME/'"$DRONE_REPO_NAME"'/' deployment.yml
- sed -i 's/$DRONE_COMMIT/'"$DRONE_COMMIT"'/' deployment.yml
# - sed -i 's/$DRONE_COMMIT/'"$DRONE_COMMIT"'/' docker.sh
# - sed -i 's/$DRONE_REPO_NAME/'"$DRONE_REPO_NAME"'/' docker.sh
# docker登录,不能在脚本中登录,并且不能使用docker login -u -p
- echo $DOCKER_PASSWORD | docker login $REGISTRY --username $DOCKER_USERNAME --password-stdin
- chmod +x docker.sh
@@ -67,29 +45,19 @@ steps:
# 执行完脚本删除本次制作的docker镜像,避免多次后当前runner空间不足
- docker rmi -f $(docker images | grep $DRONE_REPO_NAME | awk '{print $3}')
- name: drone-rancher # rancher运行
image: registry.cn-chengdu.aliyuncs.com/claywang/kubectl #阿里云的kubectl镜像,里面包含kubectl命令行工具
volumes: # 将容器内目录挂载到宿主机
- name: build
path: /app/build # 将应用打包好的Jar和执行脚本挂载出来
- name: config
path: /app/config # 将kubectl 配置文件挂载出来
commands: # 定义在Docker容器中执行的shell命令
- cd /app/build/$DRONE_REPO_NAME/
# 将deployment中定义的变量替换为drone中的内置变量
- cat deployment.yml
# 通过kubectl指令运行deployment.yml,并指定授权文件kubectl_conf.yml
# - kubectl apply -f deployment.yml -n $DRONE_COMMIT_BRANCH --kubeconfig=/app/config/kubectl_conf.yml
- kubectl apply -f deployment.yml -n dev --kubeconfig=/app/config/hcy-text-kubectl.yml
volumes:
- name: build
host:
path: /home/build
- name: cache
host:
path: /home/npm/cache
path: /home/npm/fateverse-react
- name: config # k8s对接的配置文件
host:
path: /home/kubect
@@ -102,6 +70,7 @@ volumes:
trigger:
branch:
- prod
# - prod
- dev
event:
- push
- push

6099
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -16,6 +16,7 @@
"babel-plugin-import": "^1.13.8",
"echarts": "^5.4.3",
"js-cookie": "^3.0.5",
"moment": "^2.29.4",
"nprogress": "^0.2.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
@@ -23,10 +24,12 @@
"react-router-dom": "^6.15.0",
"redux-persist": "^6.0.0",
"sass": "^1.64.2",
"vite-plugin-imp": "^2.4.0"
"vite-plugin-imp": "^2.4.0",
"vite-plugin-svg-icons": "^2.0.1"
},
"devDependencies": {
"@types/js-cookie": "^3.0.3",
"@types/node": "^20.9.0",
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@typescript-eslint/eslint-plugin": "^6.0.0",

View File

@@ -5,7 +5,7 @@ import ParentView from './ParentView'
import Loading from './Loading'
import currentRouter from './router'
import RouteInterception from './router/RouteInterception'
import { useDispatch, useSelector } from 'react-redux'
import { useSelector } from 'react-redux'
import { Suspense, lazy, useEffect, useState } from 'react'
const Views = import.meta.glob('./view/**/*.tsx')
const transferReactNode = (comp: string) => {

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import { useEffect, useState } from "react";
import NProgress from './mynprogress'
import { Spin } from "antd";

View File

@@ -1,5 +1,5 @@
import { Button, Form, Input, Image, message } from "antd";
import React, { useEffect, useState } from "react";
import { useEffect, useState } from "react";
import './assets/styles/login.scss'
import { getCaptchaApi, loginApi } from "./api/login";
import { useNavigate } from "react-router-dom";

View File

@@ -1,4 +1,4 @@
import React from 'react'
export default function Notfound() {
return <div>404</div>

View File

@@ -1,4 +1,4 @@
import React from 'react'
import { Outlet } from 'react-router-dom'
export default function ParentView() {

8
src/api/auth.ts Normal file
View File

@@ -0,0 +1,8 @@
import request from "../utils/request";
export const getAuthInfoApi = () => {
return request({
url: '/auth/info',
method: 'get'
})
}

59
src/api/system/dept.ts Normal file
View File

@@ -0,0 +1,59 @@
import request from "@/utils/request";
interface queryParamsType {
deptName?: string;
state?: number;
}
interface addParamsType {
deptName: string;
leader:string;
leaderId:number;
parentId?:number;
ancestors?:string
delFlag?:string
deptId?:number
email?:string
phone?:string
state?:string
}
export const getDatasAPI = (params: queryParamsType) => {
console.log(params);
return request({
url: "/admin/dept",
method: "get",
params: params,
});
};
export const editDataAPI = (params: addParamsType) => {
console.log(params);
params.leaderId=0
return request({
url: "/admin/dept",
method: "put",
data:params
});
};
export const delDataAPI=(deptId:number)=>{
console.log(deptId);
return request({
url:`admin/dept/${deptId}`,
method:'delete'
})
}
export const addDataAPI=(dept:addParamsType)=>{
console.log(dept);
dept.leaderId=0
return request({
url:`admin/dept`,
method:'post',
data:dept
})
}
export const getDataAPI=(deptId:number)=>{
return request({
url:`/admin/dept/${deptId}`,
method:'get'
})
}

23
src/api/system/notice.ts Normal file
View File

@@ -0,0 +1,23 @@
import request from "../../utils/request";
export const getNoticeListApi = (params: any) => {
return request({
url: "/notice/notify",
method: "get",
params,
});
};
export const getNoticeInfoApi = (id: number) => {
return request({
url: "/notice/notify/" + id,
method: "get",
});
};
export const deleteNoticeInfoApi = (id: number) => {
return request({
url: "/notice/notify/" + id,
method: "delete",
});
};

51
src/api/system/post.ts Normal file
View File

@@ -0,0 +1,51 @@
import request from "../../utils/request";
interface postListParams {
postCode?: string;
postName?: string;
state?: string;
pageNum?: string;
pageSize?: string;
}
export const getPostListApi = (data: postListParams) => {
const { postCode, postName, state, pageNum } = data;
const params = data
? {
postCode,
postName,
state,
pageNum,
pageSize: 500,
}
: undefined;
return request({
url: "/admin/post",
method: "get",
params,
});
};
export const addPostApi = (data: any) => {
return request({
url: "/admin/post",
method: "post",
data,
});
};
export const editPostApi = (data: any) => {
return request({
url: "/admin/post",
method: "put",
data,
});
};
export const deletePostApi = (postId: any) => {
return request({
url: "/admin/post/" + postId,
method: "delete",
});
};

67
src/api/system/publish.ts Normal file
View File

@@ -0,0 +1,67 @@
import request from "@/utils/request";
interface paramsType {
cluster?: string;
contentType?: string;
noticeTitle?: string;
noticeType?: string;
publishId?: number;
sendType?: string;
pageNum?: number;
pageSize?: number;
}
interface addParamsType {
action?: string;
cluster?: string;
contentType?: string;
noticeContent?: string;
noticeTitle?: string;
noticeType?: string;
remark?: string;
sendType?: string;
senderIds?: number[];
}
export const getDataListAPI = (params: paramsType) => {
return request({
url: "/notice/notice",
method: "get",
params: params,
});
};
export const getUserListAPI = () => {
return request({
url: "/admin/user",
method: "get",
});
};
export const getRolesListAPI = () => {
return request({
url: "/admin/role",
method: "get",
});
};
export const getDeptsListAPI = () => {
return request({
url: "/admin/dept",
method: "get",
});
};
export const addDataAPI = (addParams: addParamsType) => {
return request({
url: `/notice/notice`,
method: "post",
data: addParams,
});
};
export const deleteDataAPI = (noticeId: number) => {
return request({
url: `/notice/notice/${noticeId}`,
method: "delete",
});
};
export const getDataAPI = (noticeId: number) => {
return request({
url: `/notice/notice/${noticeId}`,
method: "get",
});
};

75
src/api/system/role.ts Normal file
View File

@@ -0,0 +1,75 @@
import request from "@/utils/request";
interface paramsType {
createTime?: string;
dataScope?: string;
deptIds?: any[];
menuIds?: any[];
roleId?: number;
roleKey?: string;
roleName?: string;
state?: string;
endTime?: string;
startTime?: string;
pageNum?: number;
pageSize?: number;
}
export const getRolesDataAPI = (params: paramsType) => {
const { endTime, roleKey, roleName, startTime, state, pageNum, pageSize } =
params;
// console.log('API',params);
return request({
url: "/admin/role",
method: "get",
params: {
endTime,
roleKey,
roleName,
startTime,
state,
pageNum,
pageSize,
},
});
};
export const delRoleAPI = (roleId: paramsType) => {
// console.log(roleId);
return request({
url: `/admin/role/${roleId}`,
method: "delete",
});
};
export const getMenuLiseAPI = () => {
return request({
url: "/admin/menu",
method: "get",
});
};
export const addRoleAPI = (data: any) => {
// console.log('addAPI',data);
return request({
url: `/admin/role`,
method: "post",
data,
});
};
export const getRoleAPI = (params: paramsType) => {
const { roleId } = params;
return request({
url: `/admin/role/${roleId}`,
method: "get",
});
};
export const setRoleDataAPI = (data: any) => {
// data.menuIds=[]
// const {roleId}=params
console.log("修改", data);
return request({
url: `/admin/role`,
method: "put",
data: data,
});
};

86
src/api/system/users.ts Normal file
View File

@@ -0,0 +1,86 @@
import request from "../../utils/request";
interface userListParams {
deptId?: string;
userName?: string;
phoneNumber?: string;
state?: string;
startTime?: string;
endTime?: string;
pageNum?: number;
pageSize?: number;
}
export const getDeptTreeApi = () => {
return request({
url: "/admin/dept",
method: "get",
});
};
export const getUserInfoApi = (userId: string) => {
return request({
url: "/admin/user/info/" + userId,
method: "get",
});
};
export const getRoleListApi = () => {
return request({
url: "/admin/role",
method: "get",
});
};
export const getPostListApi = () => {
return request({
url: "/admin/post",
method: "get",
});
};
export const getUserListApi = (data: userListParams) => {
const { deptId, userName, phoneNumber, state, startTime, endTime, pageNum } =
data;
const params = data
? {
deptId,
userName,
phoneNumber,
state,
startTime,
endTime,
pageNum,
pageSize: 500,
}
: undefined;
return request({
url: "/admin/user",
method: "get",
params,
});
};
export const addUserApi = (data: any) => {
return request({
url: "/admin/user",
method: "post",
data,
});
};
export const editUserApi = (data: any) => {
return request({
url: "/admin/user",
method: "put",
data,
});
};
export const deleteUserApi = (userId: any) => {
return request({
url: "/admin/user/" + userId,
method: "delete",
});
};

View File

@@ -3,4 +3,5 @@
height: calc(100vh - 64px);
padding: 20px;
box-sizing: border-box;
overflow: auto;
}

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689263020512" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2369" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M704 128 704 192 832 192 832 320 896 320 896 192 896 128Z" p-id="2370"></path><path d="M832 832 704 832 704 896 896 896 896 832 896 704 832 704Z" p-id="2371"></path><path d="M192 704 128 704 128 832 128 896 320 896 320 832 192 832Z" p-id="2372"></path><path d="M192 192 320 192 320 128 128 128 128 192 128 320 192 320Z" p-id="2373"></path><path d="M256 319.808l0 384.384C256 739.008 284.544 768 319.808 768l384.384 0C739.008 768 768 739.456 768 704.192L768 319.808C768 284.992 739.456 256 704.192 256L319.808 256C284.992 256 256 284.544 256 319.808zM320 320l384 0 0 384L320 704 320 320z" p-id="2374"></path></svg>

After

Width:  |  Height:  |  Size: 944 B

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M258.133333 128A106.666667 106.666667 0 0 0 362.666667 213.333333h298.666666a106.666667 106.666667 0 0 0 104.533334-85.333333h87.424A128 128 0 0 1 981.333333 255.744v597.845333A127.872 127.872 0 0 1 853.290667 981.333333H170.666667A128 128 0 0 1 42.666667 853.589333V255.744A127.872 127.872 0 0 1 170.709333 128H258.133333zM298.666667 384a42.666667 42.666667 0 1 0 0 85.333333h256a42.666667 42.666667 0 0 0 0-85.333333H298.666667z m0 170.666667a42.666667 42.666667 0 0 0 0 85.333333h426.666666a42.666667 42.666667 0 0 0 0-85.333333H298.666667z m0 170.666666a42.666667 42.666667 0 0 0 0 85.333334h256a42.666667 42.666667 0 0 0 0-85.333334H298.666667zM362.666667 42.666667h298.666666a64 64 0 0 1 0 128h-298.666666a64 64 0 0 1 0-128z" /></svg>

After

Width:  |  Height:  |  Size: 1020 B

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M186.4 478.4c-44-0.8-80 33.6-81.6 77.6v128H63.2C30.4 683.2 3.2 708.8 2.4 742.4v170.4c0.8 32.8 28 58.4 60.8 57.6h165.6c32.8 0.8 60-24.8 60.8-58.4V742.4c-0.8-32.8-28-59.2-60.8-58.4h-54.4V545.6h302.4v139.2h-48c-32.8-0.8-60 24.8-61.6 58.4v170.4c0.8 32.8 28 58.4 61.6 57.6h166.4c32.8 0.8 60-24.8 60.8-58.4V742.4c-0.8-32.8-28-59.2-60.8-58.4h-48V545.6h302.4v139.2h-54.4c-32.8-0.8-60 24.8-60.8 58.4v170.4c0.8 32.8 28 58.4 60.8 57.6h166.4c32.8 0.8 60-24.8 60.8-58.4V742.4c-0.8-32.8-28-59.2-61.6-58.4h-41.6v-128c-0.8-44-37.6-78.4-81.6-77.6H186.4z m20.8 272.8c7.2 0 12.8 5.6 12.8 12v128.8c0 7.2-5.6 12-12.8 12H84.8c-7.2 0-12.8-5.6-12.8-12V763.2c0-7.2 5.6-12 12.8-12h122.4z m366.4 0c7.2 0 12.8 5.6 12.8 12v128.8c0 7.2-5.6 12-12.8 12H450.4c-7.2 0-12.8-5.6-12.8-12V763.2c0-7.2 5.6-12 12.8-12h123.2z m378.4 140.8c0 7.2-5.6 12-12.8 12h-122.4c-7.2 0-12.8-5.6-12.8-12V763.2c0-7.2 5.6-12 12.8-12h122.4c7.2 0 12.8 5.6 12.8 12v128.8zM671.2 251.2c-4.8-6.4-4.8-15.2 0-21.6l37.6-45.6-4-10.4-4.8-10.4c-3.2-8-6.4-15.2-9.6-20-4.8-10.4-11.2-20-19.2-28l-7.2-7.2-57.6 8c-8.8 0.8-16.8-4.8-20-12.8L568 50.4l-11.2-1.6c-28.8-6.4-57.6-6.4-86.4 0l-9.6 1.6-20 54.4c-3.2 7.2-10.4 11.2-18.4 11.2h-1.6l-56.8-9.6-8 8c-15.2 18.4-27.2 39.2-35.2 61.6l-4 9.6 37.6 45.6c4.8 5.6 4.8 14.4 0 20.8L315.2 296l4 9.6c3.2 12.8 8.8 24.8 15.2 35.2 4.8 9.6 11.2 18.4 18.4 26.4l7.2 7.2 59.2-9.6c8-0.8 15.2 3.2 18.4 11.2l19.2 54.4 11.2 1.6c28.8 6.4 59.2 6.4 88 0l9.6-2.4 20-56c3.2-7.2 10.4-12 18.4-11.2l57.6 9.6 8-7.2c15.2-17.6 26.4-37.6 34.4-60l4-9.6-36.8-44z m-157.6 71.2c-45.6 0-82.4-36.8-82.4-82.4 0-45.6 36.8-82.4 82.4-82.4 45.6 0 82.4 36.8 82.4 82.4 0 45.6-36.8 81.6-82.4 82.4z" /></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689758652423" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2526" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M245.333333 341.333333c-17.066667 0-32 14.933333-32 32s14.933333 32 32 32h320c17.066667 0 32-14.933333 32-32s-14.933333-32-32-32h-320zM480 490.666667h-234.666667c-17.066667 0-32 14.933333-32 32s14.933333 32 32 32h234.666667c17.066667 0 32-14.933333 32-32s-14.933333-32-32-32zM394.666667 704c17.066667 0 32-14.933333 32-32s-14.933333-32-32-32h-149.333334c-17.066667 0-32 14.933333-32 32s14.933333 32 32 32h149.333334zM974.933333 650.666667L883.2 490.666667c-8.533333-12.8-21.333333-21.333333-36.266667-21.333334H661.333333c-14.933333 0-29.866667 8.533333-36.266666 21.333334L533.333333 650.666667c-8.533333 12.8-8.533333 29.866667 0 42.666666l91.733334 160c8.533333 12.8 21.333333 21.333333 36.266666 21.333334h185.6c14.933333 0 29.866667-8.533333 36.266667-21.333334l91.733333-160c8.533333-12.8 8.533333-29.866667 0-42.666666zM834.133333 810.666667h-160l-81.066666-138.666667 81.066666-138.666667h160l81.066667 138.666667-81.066667 138.666667z" p-id="2527"></path><path d="M791.466667 625.066667c-2.133333-4.266667-6.4-6.4-10.666667-6.4h-46.933333c-4.266667 0-8.533333 2.133333-10.666667 6.4l-23.466667 40.533333c-2.133333 4.266667-2.133333 8.533333 0 12.8l23.466667 40.533333c2.133333 4.266667 6.4 6.4 10.666667 6.4h46.933333c4.266667 0 8.533333-2.133333 10.666667-6.4l23.466666-40.533333c2.133333-4.266667 2.133333-8.533333 0-12.8l-23.466666-40.533333zM480 810.666667H106.666667V213.333333h597.333333v160c0 17.066667 14.933333 32 32 32s32-14.933333 32-32V192c0-23.466667-19.2-42.666667-42.666667-42.666667H85.333333c-23.466667 0-42.666667 19.2-42.666666 42.666667v640c0 23.466667 19.2 42.666667 42.666666 42.666667h394.666667c17.066667 0 32-14.933333 32-32s-14.933333-32-32-32z" p-id="2528"></path></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M758.969877 1017.428352H58.739777a35.205133 35.205133 0 0 1-35.205134-35.205134V154.902586a35.205133 35.205133 0 0 1 35.205134-35.205133h700.2301a35.205133 35.205133 0 0 1 35.205134 35.205133v177.609898a35.205133 35.205133 0 0 1-70.410267 0V190.10772H93.94491v756.910365h629.819834V805.376099a35.205133 35.205133 0 0 1 70.410267 0V982.223218a35.205133 35.205133 0 0 1-35.205134 35.205134zM503.321935 70.410267v45.766673h-188.934216V70.410267h188.934216m0-70.410267h-188.934216a70.410267 70.410267 0 0 0-70.410266 70.410267v45.766673a70.410267 70.410267 0 0 0 70.410266 70.410266h188.934216a70.410267 70.410267 0 0 0 70.410266-70.410266V70.410267a70.410267 70.410267 0 0 0-70.410266-70.410267zM402.400553 428.329122h-199.495756a35.205133 35.205133 0 1 1 0-70.410267h199.495756a35.205133 35.205133 0 0 1 0 70.410267zM369.542428 603.181283h-166.637631a35.205133 35.205133 0 0 1 0-70.410266h166.637631a35.205133 35.205133 0 0 1 0 70.410266zM627.713406 778.033445h-424.808609a35.205133 35.205133 0 0 1 0-70.410266h424.808609a35.205133 35.205133 0 0 1 0 70.410266zM893.488692 1023.999977a107.187896 107.187896 0 0 1-96.415125-60.200778l-82.473893-169.137196h-3.344487a251.787113 251.787113 0 0 1-225.993486-141.219524 249.275814 249.275814 0 0 1-21.017464-157.00316 253.383079 253.383079 0 0 1 74.482327-136.04437 35.205133 35.205133 0 0 1 55.788401 10.197754L663.094564 511.272416l52.479119-25.582397L646.947143 345.010306a35.205133 35.205133 0 0 1 26.33344-50.237725 253.559105 253.559105 0 0 1 153.09539 25.12473 249.240609 249.240609 0 0 1 110.731879 113.278384 251.810583 251.810583 0 0 1-30.006509 267.641158l82.509098 169.184136a107.070545 107.070545 0 0 1-96.121749 153.998988zM735.933985 722.855266a35.205133 35.205133 0 0 1 31.625945 19.785285l92.800731 190.354156a36.672014 36.672014 0 0 0 65.88054-32.130552l-92.706851-190.36589a35.205133 35.205133 0 0 1 6.571625-40.145587 181.200821 181.200821 0 0 0 33.761722-206.325551 180.097727 180.097727 0 0 0-139.377122-100.31116l59.848726 122.7603a35.205133 35.205133 0 0 1-16.217831 47.080998l-115.766213 56.433829a35.205133 35.205133 0 0 1-47.092734-16.217832l-59.848726-122.795505a181.118676 181.118676 0 0 0 176.471598 272.11221 36.378638 36.378638 0 0 1 4.04859-0.234701z" /></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

1
src/assets/svg/chart.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1690337061706" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2298" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M888 792H200V168c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v688c0 4.4 3.6 8 8 8h752c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8z" p-id="2299"></path><path d="M288 712h56c4.4 0 8-3.6 8-8V560c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v144c0 4.4 3.6 8 8 8zM440 712h56c4.4 0 8-3.6 8-8V384c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v320c0 4.4 3.6 8 8 8zM592 712h56c4.4 0 8-3.6 8-8V462c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v242c0 4.4 3.6 8 8 8zM744 712h56c4.4 0 8-3.6 8-8V304c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v400c0 4.4 3.6 8 8 8z" p-id="2300"></path></svg>

After

Width:  |  Height:  |  Size: 858 B

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689752871415" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2396" width="48" height="48" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M896 64H128c-35.296 0-64 28.704-64 64v768c0 35.296 28.704 64 64 64h592a32 32 0 1 0 0-64H128V128h768v592a32 32 0 1 0 64 0V128c0-35.296-28.704-64-64-64z" p-id="2397"></path><path d="M791.744 746.496A206.752 206.752 0 0 0 832 624c0-114.688-93.312-208-208-208S416 509.312 416 624s93.312 208 208 208a206.752 206.752 0 0 0 122.496-40.256l110.88 110.88a31.904 31.904 0 0 0 45.248 0 31.968 31.968 0 0 0 0-45.248l-110.88-110.88zM480 624c0-79.392 64.608-144 144-144s144 64.608 144 144-64.608 144-144 144-144-64.608-144-144zM800 264a32 32 0 0 0-32-32H256a32 32 0 0 0 0 64h512a32 32 0 0 0 32-32zM256 422.656a32 32 0 0 0 0 64h96a32 32 0 0 0 0-64H256z" p-id="2398"></path></svg>

After

Width:  |  Height:  |  Size: 995 B

1
src/assets/svg/clear.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689262997739" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1907" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M987.428571 268.190476h-950.857142a36.571429 36.571429 0 0 1 0-73.142857H243.809524V73.142857a73.142857 73.142857 0 0 1 73.142857-73.142857h390.095238a73.142857 73.142857 0 0 1 73.142857 73.142857v121.904762h207.238095a36.571429 36.571429 0 0 1 0 73.142857zM707.047619 121.904762a48.761905 48.761905 0 0 0-48.761905-48.761905H365.714286a48.761905 48.761905 0 0 0-48.761905 48.761905v73.142857h390.095238V121.904762zM341.333333 816.761905v-390.095238a36.571429 36.571429 0 0 1 73.142857 0v390.095238a36.571429 36.571429 0 0 1-73.142857 0z m268.190477 0v-390.095238a36.571429 36.571429 0 0 1 73.142857 0v390.095238a36.571429 36.571429 0 0 1-73.142857 0zM158.47619 316.952381a36.254476 36.254476 0 0 1 34.133334 24.380952H195.047619v560.761905a48.761905 48.761905 0 0 0 48.761905 48.761905h536.380952a48.761905 48.761905 0 0 0 48.761905-48.761905V341.333333h2.438095a36.059429 36.059429 0 0 1 68.266667 0h2.438095v609.52381a73.142857 73.142857 0 0 1-73.142857 73.142857H195.047619a73.142857 73.142857 0 0 1-73.142857-73.142857V341.333333h2.438095a36.254476 36.254476 0 0 1 34.133333-24.380952z" fill="#333333" p-id="1908"></path></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

1
src/assets/svg/copy.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689263581410" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2531" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M746.932 698.108" fill="#A9B7B7" p-id="2532"></path><path d="M925.731 288.698c-1.261-1.18-3.607-3.272-6.902-6.343-5.486-5.112-11.615-10.758-18.236-16.891-18.921-17.526-38.003-35.028-56.046-51.397-2.038-1.848-2.038-1.835-4.077-3.682-24.075-21.795-44.156-39.556-58.996-52.076-8.682-7.325-15.517-12.807-20.539-16.426-3.333-2.402-6.043-4.13-8.715-5.396-3.365-1.595-6.48-2.566-10.905-2.483C729.478 134.227 720 143.77 720 155.734l0 42.475 0 42.475 0 84.95L720 347l21.205 0L890 347l0 595L358.689 942C323.429 942 295 913.132 295 877.922L295 177l361.205 0c11.736 0 21.25-9.771 21.25-21.5s-9.514-21.5-21.25-21.5l-382.5 0L252 134l0 21.734L252 813l-52.421 0C166.646 813 140 786.928 140 754.678L140 72l566.286 0C739.29 72 766 98.154 766 130.404L766 134l40 0 0-3.596C806 76.596 761.271 33 706.286 33L119.958 33 100 33l0 19.506 0 702.172C100 808.463 144.642 852 199.579 852L252 852l0 25.922C252 936.612 299.979 984 358.689 984l552.515 0L932 984l0-21.237L932 325.635 932 304l0.433 0C932.432 299 930.196 292.878 925.731 288.698zM762 304l0-63.315L762 198.21l0-0.273c14 11.479 30.3 26.369 49.711 43.942 2.022 1.832 2.136 1.832 4.157 3.665 17.923 16.259 36.957 33.492 55.779 50.926 2.878 2.666 5.713 5.531 8.391 7.531L762 304.001z" fill="#272636" p-id="2533"></path><path d="M816.936 436 407.295 436c-10.996 0-19.91 8.727-19.91 19.5 0 10.77 8.914 19.5 19.91 19.5l409.641 0c11 0 19.914-8.73 19.914-19.5C836.85 444.727 827.936 436 816.936 436z" fill="#272636" p-id="2534"></path><path d="M816.936 553 407.295 553c-10.996 0-19.91 8.727-19.91 19.5 0 10.774 8.914 19.5 19.91 19.5l409.641 0c11 0 19.914-8.726 19.914-19.5C836.85 561.727 827.936 553 816.936 553z" fill="#272636" p-id="2535"></path><path d="M816.936 689 407.295 689c-10.996 0-19.91 8.729-19.91 19.503 0 10.769 8.914 19.497 19.91 19.497l409.641 0c11 0 19.914-8.729 19.914-19.497C836.85 697.729 827.936 689 816.936 689z" fill="#272636" p-id="2536"></path></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M768.7 719H255.3c-43.2 0-78.3-35.1-78.3-78.3V267.3c0-43.2 35.1-78.3 78.3-78.3h513.5c43.2 0 78.3 35.1 78.3 78.3v373.5c-0.1 43.1-35.2 78.2-78.4 78.2zM255.3 239c-15.6 0-28.3 12.7-28.3 28.3v373.5c0 15.6 12.7 28.3 28.3 28.3h513.5c15.6 0 28.3-12.7 28.3-28.3V267.3c0-15.6-12.7-28.3-28.3-28.3H255.3zM847 785H177c-13.8 0-25 11.2-25 25s11.2 25 25 25h670c13.8 0 25-11.2 25-25s-11.2-25-25-25zM701.8 564.5H532.2c-13.8 0-25 11.2-25 25s11.2 25 25 25h169.6c13.8 0 25-11.2 25-25s-11.2-25-25-25zM455.2 300.4c-6.4 0-12.8 2.4-17.7 7.3L303.2 442.1c-9.8 9.8-9.8 25.6 0 35.4l134.4 134.4c4.9 4.9 11.3 7.3 17.7 7.3s12.8-2.4 17.7-7.3c9.8-9.8 9.8-25.6 0-35.4L356.2 459.8l116.7-116.7c9.8-9.8 9.8-25.6 0-35.4-4.9-4.8-11.3-7.3-17.7-7.3z" /></svg>

After

Width:  |  Height:  |  Size: 996 B

1
src/assets/svg/data.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689756990510" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1866" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M887.808 137.92c21.312 21.312 32.256 47.68 32.832 79.168v593.28c-0.576 31.488-11.52 57.856-32.832 79.168s-47.68 32.256-79.168 32.832h-593.28c-31.488-0.576-57.92-11.52-79.168-32.832-21.312-21.312-32.256-47.68-32.832-79.168v-593.28c0.576-31.488 11.52-57.856 32.832-79.168s47.68-32.256 79.168-32.832h593.28c31.488 0.64 57.856 11.584 79.168 32.832zM383.36 564.48c0-14.592-4.224-26.56-12.672-35.904-8.448-9.344-21.12-14.016-38.08-14.016-16.896 0-30.208 4.672-39.808 14.016s-12.992 21.312-10.048 35.904v128.64c0 14.016 4.8 25.792 14.464 35.456s21.568 14.464 35.904 14.464c14.272 0 26.112-4.8 35.456-14.464 9.344-9.6 14.272-21.44 14.848-35.456V564.48z m173.248-230.08c0-14.016-4.8-25.792-14.464-35.456s-21.568-14.464-35.904-14.464c-14.272 0-26.112 4.8-35.456 14.464-9.344 9.6-14.272 21.44-14.848 35.456v358.72c0.576 14.016 5.568 25.792 14.848 35.456 9.344 9.6 21.12 14.464 35.456 14.464 14.272 0 26.24-4.8 35.904-14.464s14.464-21.44 14.464-35.456V334.4zM736 508.48c-0.576-14.592-6.4-26.56-17.472-35.904s-23.936-14.016-38.528-14.016c-14.592 0-26.24 4.672-35.008 14.016s-11.968 21.312-9.6 35.904v184.64c0 14.016 4.8 25.792 14.464 35.456s21.568 14.464 35.904 14.464c14.272 0 26.112-4.8 35.456-14.464 9.344-9.6 14.272-21.44 14.848-35.456V508.48z" p-id="1867"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689753422872" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5415" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M489.6 727.2h421.1c26.9 0 49.3 22.4 49.3 53.8v80.6c0 26.9-22.4 53.8-49.3 53.8H489.6c-26.9 0-49.3-22.4-49.3-53.8v-9H158.1c-17.9 0-31.4-13.4-31.4-31.4v-524h-13.4c-26.9 0-49.3-26.9-49.3-53.8v-80.6c0-31.4 22.4-53.8 49.3-53.8h85.1c26.9 0 49.3 22.4 49.3 53.8v80.6c0 26.9-22.4 53.8-49.3 53.8H185v188.2h250.9v-9c0-26.9 22.4-53.8 49.3-53.8h421.1c26.9 0 49.3 22.4 49.3 53.8V557c0 26.9-22.4 53.8-49.3 53.8H485.1c-26.9 0-49.3-22.4-49.3-53.8v-9H185v246.4h250.9V781c-0.1-26.9 22.3-53.8 53.7-53.8z m421.1-430h-551c-31.4 0-53.8-26.9-53.8-53.8v-80.6c0-31.4 22.4-53.8 53.8-53.8h551c26.9 0 49.3 22.4 49.3 53.8v80.6c0 26.9-22.4 53.8-49.3 53.8z" p-id="5416" fill="#ffffff"></path></svg>

After

Width:  |  Height:  |  Size: 996 B

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M525.158 921.6a283.351 283.351 0 0 0 55.296 51.2H145.06a93.02 93.02 0 0 1-93.86-92.16V143.36a93.02 93.02 0 0 1 93.86-92.16h682.675a93.025 93.025 0 0 1 93.865 92.16v381.798a281.795 281.795 0 0 0-51.2-33.638V324.27h-768v555.52a42.24 42.24 0 0 0 42.66 41.81h380.098zM870.4 273.065v-128.87a42.24 42.24 0 0 0-42.665-41.795H145.06a42.24 42.24 0 0 0-42.66 41.795v128.87h768z m-358.4-51.2a34.135 34.135 0 1 1 34.13-34.135A34.13 34.13 0 0 1 512 221.865z m119.465 0A34.135 34.135 0 1 1 665.6 187.73a34.13 34.13 0 0 1-34.135 34.135z m119.47 0a34.135 34.135 0 1 1 34.13-34.135 34.13 34.13 0 0 1-34.13 34.135zM449.418 441.283L302.592 569.088a30.136 30.136 0 0 1-41.938 0l-59.684-51.779a28.001 28.001 0 0 1-3.236-38.83v-1.618a25.912 25.912 0 0 1 37.12-3.246l46.777 40.448 135.516-116.475h1.618a27.648 27.648 0 0 1 37.12 4.864c8.043 12.934 6.436 30.72-6.467 38.83z m-3.65 224.558L298.952 793.656a30.136 30.136 0 0 1-41.928 0l-59.694-51.768a28.001 28.001 0 0 1-3.251-38.83v-1.618a25.928 25.928 0 0 1 37.125-3.246l46.781 40.474 135.522-116.501h1.607a27.617 27.617 0 0 1 37.12 4.864c8.054 12.933 6.441 30.72-6.466 38.825zM742.4 972.8a230.4 230.4 0 1 1 230.4-230.4 230.4 230.4 0 0 1-230.4 230.4z m0-51.2a179.2 179.2 0 1 0-179.2-179.2 179.2 179.2 0 0 0 179.2 179.2z m-8.704-170.21l93.952-1.3a25.242 25.242 0 1 1 0.886 50.473l-119.742 1.654a27.832 27.832 0 0 1-26.112-27.515V656.983a25.513 25.513 0 1 1 51.026 0v94.413z m0 0" /></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

1
src/assets/svg/fabu.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1690372430043" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2365" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M682.47 101c72.01 0 130.041 59.663 131.194 133.157l0.018 2.231v467.066c0 16.519-13.383 29.91-29.891 29.91-16.273 0-29.509-13.012-29.883-29.204l-0.009-0.706V236.388c0-41.574-31.608-74.895-70.255-75.557l-1.174-0.01H202.212c-38.787 0-70.784 32.905-71.42 74.31l-0.01 1.257v601.224c0 41.574 31.609 74.895 70.256 75.557l1.174 0.01h642.917c21.34 0 38.686-17.111 39.082-38.37l0.007-0.743V199.292c0-16.52 13.382-29.91 29.89-29.91 16.273 0 29.509 13.01 29.892 29.204v675.48c0 54.093-43.385 98.047-97.236 98.92l-1.635 0.014H202.212c-72.01 0-130.041-59.663-131.195-133.157L71 837.612V236.388c0-73.768 57.311-134.17 129.034-135.37l2.178-0.018H682.47z m-78.027 616.612c12.7 0 22.994 10.301 22.994 23.008 0 12.492-9.949 22.658-22.35 23l-0.644 0.008H289.436c-12.699 0-22.993-10.301-22.993-23.008 0-12.491 9.948-22.658 22.35-22.999l0.643-0.009h315.007z m0-138.047c12.7 0 22.994 10.3 22.994 23.008 0 12.491-9.949 22.658-22.35 22.999l-0.644 0.008H289.436c-12.699 0-22.993-10.3-22.993-23.007 0-12.492 9.948-22.658 22.35-23l0.643-0.008h315.007z m0-138.048c12.7 0 22.994 10.301 22.994 23.008 0 12.492-9.949 22.658-22.35 23l-0.644 0.008H289.436c-12.699 0-22.993-10.301-22.993-23.008 0-12.491 9.948-22.658 22.35-22.999l0.643-0.009h315.007z m-75.876-132.181c12.7 0 22.994 10.3 22.994 23.008 0 12.491-9.949 22.658-22.35 22.999l-0.644 0.009H366.343c-12.699 0-22.993-10.301-22.993-23.008 0-12.492 9.948-22.658 22.35-23l0.643-0.008h162.224z" fill="#333333" p-id="2366"></path></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

1
src/assets/svg/fit.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689263007214" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2215" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M597.333333 405.376c0-0.128 0.085333-0.256 0.085333-0.384C597.418667 404.821333 597.333333 404.650667 597.333333 404.522667L597.333333 192.768C597.333333 180.522667 606.933333 170.538667 618.666667 170.666667c11.733333-0.042667 21.376 9.813333 21.376 22.144L640.042667 384l191.189333 0c12.16 0 22.186667 9.6 22.101333 21.333333 0 11.733333-9.813333 21.333333-22.186667 21.333333l-211.754667 0c-0.128 0-0.256-0.085333-0.384-0.085333S618.837333 426.666667 618.709333 426.666667c-4.821333 0-9.045333-1.962667-12.629333-4.736-0.853333-0.64-1.749333-0.981333-2.432-1.706667-0.213333-0.213333-0.298667-0.469333-0.512-0.725333C599.68 415.744 597.333333 410.837333 597.333333 405.376zM362.666667 170.666667C350.933333 170.624 341.290667 180.48 341.290667 192.810667L341.290667 384 150.101333 384C137.898667 384 127.914667 393.6 128 405.333333 128 417.066667 137.813333 426.666667 150.186667 426.666667l211.754667 0c0.128 0 0.256-0.085333 0.384-0.085333S362.496 426.666667 362.624 426.666667c4.821333 0 9.045333-1.962667 12.629333-4.736 0.853333-0.64 1.749333-0.981333 2.432-1.706667 0.213333-0.213333 0.298667-0.469333 0.512-0.725333C381.653333 415.744 384 410.837333 384 405.376c0-0.128-0.085333-0.256-0.085333-0.384C383.914667 404.821333 384 404.650667 384 404.522667L384 192.768C384 180.522667 374.4 170.538667 362.666667 170.666667zM831.146667 640l-211.754667 0c-0.128 0-0.256 0.085333-0.384 0.085333S618.837333 640 618.709333 640c-4.821333 0-9.088 2.005333-12.672 4.778667-0.810667 0.597333-1.706667 0.938667-2.389333 1.664-0.213333 0.213333-0.298667 0.469333-0.512 0.725333C599.68 650.922667 597.333333 655.829333 597.333333 661.290667c0 0.128 0.085333 0.256 0.085333 0.384 0 0.170667-0.085333 0.341333-0.085333 0.469333l0 211.797333c0 12.202667 9.6 22.229333 21.333333 22.101333 11.733333 0.042667 21.376-9.813333 21.376-22.144L640.042667 682.666667l191.189333 0c12.16 0 22.186667-9.6 22.101333-21.333333C853.333333 649.6 843.52 640 831.146667 640zM378.154667 647.168c-0.213333-0.256-0.298667-0.512-0.512-0.725333-0.682667-0.725333-1.578667-1.066667-2.389333-1.664C371.712 642.005333 367.445333 640 362.624 640c-0.128 0-0.213333 0.085333-0.341333 0.085333S362.026667 640 361.898667 640L150.186667 640C137.813333 640 128 649.6 128 661.333333 127.914667 673.066667 137.898667 682.666667 150.101333 682.666667l191.189333 0 0 191.189333c0 12.288 9.642667 22.186667 21.376 22.144C374.4 896.128 384 886.144 384 873.898667l0-211.797333c0-0.128-0.085333-0.298667-0.085333-0.469333C383.914667 661.546667 384 661.418667 384 661.290667 384 655.829333 381.653333 650.922667 378.154667 647.168zM490.666667 469.333333c-35.328 0-64 28.672-64 64s28.672 64 64 64 64-28.672 64-64S525.994667 469.333333 490.666667 469.333333z" fill="#020202" p-id="2216"></path></svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M136.3 410.2h70v150.2h-70zM206.3 851.3V733.8h-70v117.5c0 40.7 31.5 73.9 70.2 73.9h206.1v-70H207.5c-0.5-0.6-1.2-1.9-1.2-3.9zM206.3 139c0-2 0.7-3.3 1.1-3.9h619.8c0.5 0.6 1.1 1.8 1.1 3.9v151.1h70V139c0-40.7-31.5-73.9-70.2-73.9H206.5c-38.7 0-70.2 33.1-70.2 73.9v97.9h70V139zM886.8 677.2c-20-20-43-35.9-68-47.2 19.2-22.2 30.9-51.2 30.9-82.8 0-69.9-56.8-126.7-126.7-126.7s-126.7 56.8-126.7 126.7c0 31.6 11.7 60.6 30.9 82.8-25 11.4-48 27.2-68 47.2-43.8 43.8-67.9 101.9-67.9 163.8 0 6.1 0.2 12.2 0.7 18.2l69.8-5.5c-0.3-4.2-0.5-8.5-0.5-12.7 0-89.1 72.5-161.6 161.6-161.6S884.6 751.9 884.6 841c0 4.3-0.2 8.6-0.5 12.7l69.8 5.5c0.5-6 0.7-12.1 0.7-18.2 0-61.9-24.1-120-67.8-163.8zM723 490.5c31.3 0 56.7 25.4 56.7 56.7s-25.4 56.7-56.7 56.7-56.7-25.4-56.7-56.7 25.4-56.7 56.7-56.7zM93.9 288.5h154.8v70H93.9zM93.9 612.1h154.8v70H93.9z" /></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M564.906667 534.613333a216.746667 216.746667 0 1 1 216.746666-216.746666 217.173333 217.173333 0 0 1-216.746666 216.746666z m0-366.506666a149.76 149.76 0 1 0 149.76 149.76 150.186667 150.186667 0 0 0-149.76-149.76z" /><path fill="#ffffff" d="M216.32 896a33.706667 33.706667 0 0 1-33.28-33.706667c0-185.6 157.866667-392.96 384-392.96a33.706667 33.706667 0 0 1 0 66.986667c-181.76 0-317.866667 170.666667-317.866667 325.973333a33.706667 33.706667 0 0 1-32.853333 33.706667zM316.586667 488.96c-56.32 0-125.013333-72.106667-125.013334-156.586667A157.013333 157.013333 0 0 1 256 207.36 33.28 33.28 0 0 1 301.226667 213.333333a32.853333 32.853333 0 0 1-6.826667 47.36 87.893333 87.893333 0 0 0-35.84 71.68 97.28 97.28 0 0 0 58.026667 89.6 33.706667 33.706667 0 0 1 33.28 33.706667 33.28 33.28 0 0 1-33.28 33.28z" /><path fill="#ffffff" d="M115.2 725.333333a33.28 33.28 0 0 1-33.28-33.28c0-128 102.4-271.786667 234.666667-271.786666a33.706667 33.706667 0 0 1 0 66.986666c-90.453333 0-167.68 112.213333-167.68 204.8a33.706667 33.706667 0 0 1-33.706667 33.28zM810.666667 779.093333a128 128 0 1 1 130.133333-128 128 128 0 0 1-130.133333 128z m0-192.853333a63.146667 63.146667 0 1 0 63.146666 63.146667A63.146667 63.146667 0 0 0 810.666667 586.24z" /><path fill="#ffffff" d="M773.973333 724.906667m32.426667 0l4.266667 0q32.426667 0 32.426666 32.426666l0 145.493334q0 32.426667-32.426666 32.426666l-4.266667 0q-32.426667 0-32.426667-32.426666l0-145.493334q0-32.426667 32.426667-32.426666Z" /><path fill="#ffffff" d="M912.64 809.813333m0 34.56l0 0q0 34.56-34.56 34.56l-69.973333 0q-34.56 0-34.56-34.56l0 0q0-34.56 34.56-34.56l69.973333 0q34.56 0 34.56 34.56Z" /></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M591.644444 574.577778l-85.333333 85.333333-136.533333-136.533333 79.644444-79.644445-39.822222-39.822222-79.644444 79.644445-79.644445-79.644445-96.711111 96.711111a261.688889 261.688889 0 0 0-22.755556 347.022222L0 984.177778l39.822222 39.822222L170.666667 893.155556c45.511111 39.822222 102.4 56.888889 159.288889 56.888888 68.266667 0 136.533333-28.444444 187.733333-79.644444l96.711111-96.711111-73.955556-73.955556 85.333334-85.333333-34.133334-39.822222z m-113.777777 250.311111c-39.822222 39.822222-91.022222 62.577778-142.222223 62.577778-51.2 0-102.4-17.066667-136.533333-56.888889l-5.688889-5.688889c-73.955556-73.955556-73.955556-199.111111 5.688889-278.755556l51.2-51.2 278.755556 278.755556-51.2 51.2zM978.488889 91.022222l-39.822222-39.822222L813.511111 170.666667c-45.511111-39.822222-102.4-56.888889-159.288889-56.888889-68.266667 0-136.533333 28.444444-187.733333 79.644444L369.777778 284.444444l369.777778 369.777778 91.022222-91.022222a261.688889 261.688889 0 0 0 22.755555-347.022222l125.155556-125.155556z m-193.422222 426.666667l-45.511111 45.511111L460.8 284.444444l45.511111-45.511111c39.822222-39.822222 91.022222-62.577778 142.222222-62.577777 51.2 0 102.4 17.066667 136.533334 56.888888l5.688889 5.688889c79.644444 73.955556 73.955556 199.111111-5.688889 278.755556z" /></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M790.528 464h2.944a232 232 0 1 0-2.944 0zM793.472 64a168 168 0 0 1 0 336h-2.944A168 168 0 1 1 793.472 64zM425.6 560H38.4A38.432 38.432 0 0 0 0 598.4v387.2A38.464 38.464 0 0 0 38.4 1024h387.2a38.464 38.464 0 0 0 38.4-38.4V598.4a38.432 38.432 0 0 0-38.4-38.4zM400 960H64V624h336zM985.6 560H598.4a38.432 38.432 0 0 0-38.4 38.4v387.2a38.464 38.464 0 0 0 38.4 38.4h387.2a38.464 38.464 0 0 0 38.4-38.4V598.4a38.432 38.432 0 0 0-38.4-38.4zM960 960H624V624H960zM425.6 0H38.4A38.432 38.432 0 0 0 0 38.4v387.2a38.464 38.464 0 0 0 38.4 38.4h387.2a38.464 38.464 0 0 0 38.4-38.4V38.4A38.432 38.432 0 0 0 425.6 0z m-25.6 400H64V64h336z" /></svg>

After

Width:  |  Height:  |  Size: 912 B

1
src/assets/svg/paste.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689263685428" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3855" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M426.666667 896H170.666667a128 128 0 0 1-128-128V213.333333a128 128 0 0 1 128-128h85.333333a42.666667 42.666667 0 0 1 42.666667 42.666667v42.666667h170.666666V128a42.666667 42.666667 0 0 1 42.666667-42.666667h85.333333a128 128 0 0 1 128 128v170.666667a42.666667 42.666667 0 0 1-85.333333 0V213.333333a42.666667 42.666667 0 0 0-42.666667-42.666666h-42.666666v42.666666a42.666667 42.666667 0 0 1-42.666667 42.666667H256a42.666667 42.666667 0 0 1-42.666667-42.666667V170.666667H170.666667a42.666667 42.666667 0 0 0-42.666667 42.666666v554.666667a42.666667 42.666667 0 0 0 42.666667 42.666667h256a42.666667 42.666667 0 0 1 0 85.333333z" p-id="3856"></path><path d="M512 256H256a42.666667 42.666667 0 0 1-42.666667-42.666667V42.666667a42.666667 42.666667 0 0 1 42.666667-42.666667h256a42.666667 42.666667 0 0 1 42.666667 42.666667v170.666666a42.666667 42.666667 0 0 1-42.666667 42.666667zM298.666667 170.666667h170.666666V85.333333H298.666667zM853.333333 1024h-341.333333a128 128 0 0 1-128-128V469.333333a128 128 0 0 1 128-128h341.333333a128 128 0 0 1 128 128v426.666667a128 128 0 0 1-128 128z m-341.333333-597.333333a42.666667 42.666667 0 0 0-42.666667 42.666666v426.666667a42.666667 42.666667 0 0 0 42.666667 42.666667h341.333333a42.666667 42.666667 0 0 0 42.666667-42.666667V469.333333a42.666667 42.666667 0 0 0-42.666667-42.666666z" p-id="3857"></path><path d="M768 597.333333h-170.666667a42.666667 42.666667 0 0 1 0-85.333333h170.666667a42.666667 42.666667 0 0 1 0 85.333333zM768 725.333333h-170.666667a42.666667 42.666667 0 0 1 0-85.333333h170.666667a42.666667 42.666667 0 0 1 0 85.333333zM768 853.333333h-170.666667a42.666667 42.666667 0 0 1 0-85.333333h170.666667a42.666667 42.666667 0 0 1 0 85.333333z" p-id="3858"></path></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M448 128l128 96h384v704H64V128h384z m-21.312 64H128v672h768v-576H554.688l-128-96zM512 448a64 64 0 0 1 32.064 119.424L544 704h-64V567.424A64 64 0 0 1 512 448z" /></svg>

After

Width:  |  Height:  |  Size: 448 B

1
src/assets/svg/redo.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689263778560" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1632" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M765.013333 509.013333C487.253333 235.392 67.968 391.466667 65.792 697.941333l7.765333 2.645334c176.853333-218.112 417.024-291.84 605.866667-106.453334 1.706667 1.706667 1.792 4.608 0.085333 6.314667L561.92 718.08a4.266667 4.266667 0 0 0 2.986667 7.296h326.826666a4.266667 4.266667 0 0 0 4.266667-4.266667V394.24a4.224 4.224 0 0 0-7.253333-2.986667l-117.76 117.76a4.096 4.096 0 0 1-5.888 0z" fill="#8a8a8a" p-id="1633"></path></svg>

After

Width:  |  Height:  |  Size: 763 B

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689263027132" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2527" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M0 585.142857h73.142857v73.142857H0v-73.142857z m0 365.714286h73.142857v-73.142857H0v73.142857z m0-146.285714h73.142857v-73.142858H0v73.142858z m0-292.571429h73.142857v-73.142857H0v73.142857zM0 73.142857h73.142857V0H0v73.142857z m0 292.571429h73.142857v-73.142857H0v73.142857z m0-146.285715h73.142857v-73.142857H0v73.142857z m877.714286 438.857143h73.142857v-73.142857h-73.142857v73.142857z m73.142857-219.428571h-73.142857v73.142857h73.142857v-73.142857zM804.571429 0h-73.142858v73.142857h73.142858V0z m146.285714 0h-73.142857v73.142857h73.142857V0z m0 146.285714h-73.142857v73.142857h73.142857v-73.142857z m0 146.285715h-73.142857v73.142857h73.142857v-73.142857zM292.571429 73.142857h73.142857V0h-73.142857v73.142857z m585.142857 950.857143h73.142857v-73.142857h-73.142857v73.142857zM585.142857 73.142857h73.142857V0h-73.142857v73.142857z m146.285714 804.571429v73.142857h146.285715v-73.142857H731.428571z m219.428572-146.285715h-73.142857v146.285715h73.142857V731.428571z m0 146.285715v73.142857h73.142857v-73.142857h-73.142857z m-658.285714 73.142857h73.142857v-73.142857h-73.142857v73.142857z m-146.285715 0h73.142857v-73.142857h-73.142857v73.142857z m0-877.714286h73.142857V0h-73.142857v73.142857z m438.857143 877.714286h73.142857v-73.142857h-73.142857v73.142857zM438.857143 73.142857h73.142857V0h-73.142857v73.142857z m0 877.714286h73.142857v-73.142857h-73.142857v73.142857z" p-id="2528"></path></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M65.6 674.88v49.28c0 34.24 27.52 62.08 62.08 62.4h769.92c34.24 0 62.08-27.52 62.4-62.08v-49.6H65.6zM706.56 882.24h-52.48l-25.28-123.84c-3.2-14.72-16-25.28-30.72-25.28h-170.88c-14.72 0-27.84 10.56-30.72 25.28l-25.92 123.84h-51.2c-17.28 0-31.36 14.08-31.36 31.36s14.08 31.36 31.36 31.36h387.2c17.28-0.64 31.36-14.08 31.36-31.36s-14.08-31.36-31.36-31.36z m-271.36-0.64l17.92-86.4h119.68l17.92 86.4H435.2zM897.92 160H128c-34.24 0-62.08 27.52-62.4 62.08v407.36H960V222.4C960 187.84 932.48 160 897.92 160z m-489.6 399.36c-0.32 7.68-10.56 14.08-23.04 14.08h-22.72c-12.48 0-22.72-6.4-22.72-14.08v-68.48l68.48-31.68v100.16z m102.08 0c0 7.68-10.88 14.08-24.64 14.08h-24.64c-13.44 0-24.64-6.4-24.64-14.08v-142.4l23.04-9.92 50.56 22.08v130.24z m69.76 14.08h-20.8c-11.52 0-20.8-6.4-20.8-14.08V470.4l0.64 0.32c2.56 0.64 5.12 0.96 7.68 0.96 2.88-0.32 5.76-0.64 8-1.6 0.96-0.32 1.6-0.64 2.56-0.96 1.28-0.64 2.56-0.96 3.52-1.6l39.68-27.2 0.32 119.04c0 7.68-9.28 14.08-20.8 14.08z m115.2-16.32c0 7.68-10.56 13.76-23.36 13.76h-23.36c-13.12 0-23.36-6.08-23.36-13.76v-169.6l70.4-41.28v210.88z m-40.96-267.2l-118.08 101.76-85.76-72.64-77.44 68.48-42.88-31.68 119.36-103.68 84.8 70.08 78.4-70.08L580.16 224h115.2l0.32 96.64-41.28-30.72z" /></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689758652423" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2526" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M245.333333 341.333333c-17.066667 0-32 14.933333-32 32s14.933333 32 32 32h320c17.066667 0 32-14.933333 32-32s-14.933333-32-32-32h-320zM480 490.666667h-234.666667c-17.066667 0-32 14.933333-32 32s14.933333 32 32 32h234.666667c17.066667 0 32-14.933333 32-32s-14.933333-32-32-32zM394.666667 704c17.066667 0 32-14.933333 32-32s-14.933333-32-32-32h-149.333334c-17.066667 0-32 14.933333-32 32s14.933333 32 32 32h149.333334zM974.933333 650.666667L883.2 490.666667c-8.533333-12.8-21.333333-21.333333-36.266667-21.333334H661.333333c-14.933333 0-29.866667 8.533333-36.266666 21.333334L533.333333 650.666667c-8.533333 12.8-8.533333 29.866667 0 42.666666l91.733334 160c8.533333 12.8 21.333333 21.333333 36.266666 21.333334h185.6c14.933333 0 29.866667-8.533333 36.266667-21.333334l91.733333-160c8.533333-12.8 8.533333-29.866667 0-42.666666zM834.133333 810.666667h-160l-81.066666-138.666667 81.066666-138.666667h160l81.066667 138.666667-81.066667 138.666667z" p-id="2527" fill="#ffffff"></path><path d="M791.466667 625.066667c-2.133333-4.266667-6.4-6.4-10.666667-6.4h-46.933333c-4.266667 0-8.533333 2.133333-10.666667 6.4l-23.466667 40.533333c-2.133333 4.266667-2.133333 8.533333 0 12.8l23.466667 40.533333c2.133333 4.266667 6.4 6.4 10.666667 6.4h46.933333c4.266667 0 8.533333-2.133333 10.666667-6.4l23.466666-40.533333c2.133333-4.266667 2.133333-8.533333 0-12.8l-23.466666-40.533333zM480 810.666667H106.666667V213.333333h597.333333v160c0 17.066667 14.933333 32 32 32s32-14.933333 32-32V192c0-23.466667-19.2-42.666667-42.666667-42.666667H85.333333c-23.466667 0-42.666667 19.2-42.666666 42.666667v640c0 23.466667 19.2 42.666667 42.666666 42.666667h394.666667c17.066667 0 32-14.933333 32-32s-14.933333-32-32-32z" p-id="2528" fill="#ffffff"></path></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

1
src/assets/svg/sql.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1691830095931" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4048" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M776.533333 755.456H598.903467c-14.421333 0-26.112 12.475733-26.112 27.869867v168.618666h28.433066L776.533333 760.439467v-4.983467zM776.533333 699.733333v-88.183466c0-15.189333 11.4688-27.477333 25.6-27.477334s25.6 12.288 25.6 27.477334v160.136533c0 7.2192-2.645333 14.1312-7.338666 19.285333L630.2208 998.7072a24.746667 24.746667 0 0 1-18.261333 8.226133H228.693333C163.669333 1006.933333 110.933333 950.306133 110.933333 880.452267V143.530667C110.933333 73.693867 163.669333 17.066667 228.693333 17.066667h481.28C774.997333 17.066667 827.733333 73.693867 827.733333 143.547733v48.930134c0 15.189333-11.4688 27.477333-25.6 27.477333s-25.6-12.288-25.6-27.477333V143.530667c0-39.4752-29.7984-71.492267-66.56-71.492267H228.693333c-36.7616 0-66.56 32.017067-66.56 71.509333v736.887467c0 39.4752 29.7984 71.492267 66.56 71.492267H520.533333v-168.618667C520.533333 737.160533 555.6224 699.733333 598.903467 699.733333H776.533333zM367.7696 280.576c27.272533 0 47.530667 5.512533 60.416 16.896 13.687467 11.997867 19.1488 30.8224 16.093867 56.149333h-37.666134c-0.238933-14.2848-4.215467-24.6784-11.3664-30.839466-7.0656-6.485333-19.456-9.4208-36.317866-9.4208-14.609067 0-26.0608 1.9456-34.747734 6.178133-10.752 4.864-17.015467 12.970667-19.336533 24.0128-2.048 9.745067 1.4336 17.8688 11.246933 23.722667 4.317867 2.577067 16.605867 7.458133 36.608 14.267733 29.44 9.728 47.9232 17.527467 55.927467 22.7328 17.578667 12.014933 24.1664 28.5696 19.6608 50.005333-4.369067 20.770133-15.9744 37.3248-34.730667 49.322667-18.688 11.690667-43.042133 17.8688-72.584533 17.8688-28.5696 0-49.8176-5.5296-63.402667-16.554667-16.605867-13.653333-22.801067-35.072-18.210133-64.6144h37.666133c-1.092267 17.527467 2.389333 30.208 10.888534 37.666134 7.7312 6.485333 20.9408 10.069333 40.106666 10.069333 16.878933 0 31.112533-2.935467 42.018134-8.448 10.973867-5.8368 17.749333-13.312 19.797333-23.04 2.594133-12.356267-2.833067-22.084267-15.616-29.2352-4.061867-2.269867-17.902933-7.458133-41.915733-15.2576-26.658133-9.079467-43.144533-15.581867-49.152-19.473067-15.581867-10.717867-21.077333-26.299733-16.776534-46.762666 4.3008-20.445867 16.162133-36.676267 36.164267-48.366934 18.602667-11.3664 40.226133-16.878933 65.2288-16.878933z m249.122133 0c35.3792 0 60.910933 11.3664 76.509867 34.4064 14.8992 21.76 18.568533 50.653867 11.042133 86.357333-7.304533 34.747733-22.664533 62.976-45.346133 84.411734 6.109867 11.042133 12.424533 22.7328 18.261333 35.072l-29.184 21.418666a712.5504 712.5504 0 0 0-18.1248-35.703466c-18.944 9.728-40.482133 14.933333-63.863466 14.933333-35.703467 0-61.166933-11.690667-76.509867-34.423467-14.848-22.0672-18.244267-50.6368-10.8544-85.7088 7.441067-35.3792 22.869333-63.9488 47.0016-86.016 25.0368-23.381333 55.3472-34.747733 91.067733-34.747733z m-7.048533 33.450667c-24.0128 0-44.2368 8.106667-60.962133 24.337066-15.940267 15.581867-26.4704 36.352-32.085334 62.976-5.5296 26.299733-3.7376 47.086933 5.649067 62.6688 9.642667 15.906133 26.760533 24.029867 50.7904 24.029867a90.794667 90.794667 0 0 0 41.2672-9.4208c-8.704-14.2848-17.066667-26.948267-25.378133-38.314667l26.5728-21.418666a704.085333 704.085333 0 0 1 25.838933 37.649066c11.451733-14.2848 19.899733-32.785067 24.610133-55.1936 5.7344-27.255467 3.754667-48.6912-5.632-64.273066-9.710933-15.581867-26.624-23.04-50.670933-23.04z m171.434667-28.910934h37.666133l-41.949867 199.338667h125.320534l-6.826667 32.477867h-162.986667l48.776534-231.816534z" fill="#ffffff" p-id="4049"></path></svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

1
src/assets/svg/table.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M960 64H64v224h1v164h-1v64h1v160h-1v64h1v219.7h275v0.3h64v-0.3h216v0.3h64v-0.3h275V288h1V64zM620 452H404V288h216v164z m0 224H404V516h216v160z m64-160h211v160H684V516zM129 288h211v164H129V288z m0 228h211v160H129V516z m0 379.7V740h211v155.7H129z m275 0V740h216v155.7H404z m280 0V740h211v155.7H684zM895 452H684V288h211v164z" /></svg>

After

Width:  |  Height:  |  Size: 611 B

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M928 768a160 160 0 1 1-192-156.8V544h-448v67.2a160 160 0 1 1-64 0V480h256v-64h-64a128 128 0 0 1-128-128v-64a128 128 0 0 1 128-128h192a128 128 0 0 1 128 128v64a128 128 0 0 1-128 128h-64v64h256v131.2a160 160 0 0 1 128 156.8zM256 672A96 96 0 1 0 352 768 96 96 0 0 0 256 672z m352-320a64 64 0 0 0 64-64v-64a64 64 0 0 0-64-64h-192a64 64 0 0 0-64 64v64a64 64 0 0 0 64 64h192z m160 320a96 96 0 1 0 96 96 96 96 0 0 0-96-96z" /></svg>

After

Width:  |  Height:  |  Size: 706 B

1
src/assets/svg/undo.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689262813730" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1753" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M533.333333 341.333333c-113.066667 0-215.466667 42.24-294.4 110.933334L85.333333 298.666667v384h384l-154.453333-154.453334c59.306667-49.493333 134.826667-80.213333 218.453333-80.213333 151.04 0 279.466667 98.56 324.266667 234.666667l101.12-33.28C899.413333 470.613333 731.733333 341.333333 533.333333 341.333333z" fill="#8a8a8a" p-id="1754"></path></svg>

After

Width:  |  Height:  |  Size: 685 B

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M792.14 905.5H244.66a39.46 39.46 0 0 1-39.41-39.41V294.16a39.46 39.46 0 0 1 39.41-39.41h114.75V308H258.46v544.28h519.87V308H675.56v-53.25h116.58a39.46 39.46 0 0 1 39.41 39.41v571.93a39.46 39.46 0 0 1-39.41 39.41zM476.56 735.49L355.58 608l38.6-36.63 83.57 88.05 165.62-163.98 37.44 37.82-204.25 202.23zM679.71 367.17H357.25V198.54h322.46zM410.47 314h216v-62.2h-216z" /></svg>

After

Width:  |  Height:  |  Size: 654 B

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689757664262" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2575" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M800.529 853.171c16.521 0 29.914 13.393 29.914 29.915 0 16.52-13.393 29.914-29.914 29.914H163.77c-16.521 0-29.914-13.393-29.914-29.914 0-16.522 13.393-29.915 29.914-29.915h636.759zM784.464 80C863.184 80 927 143.875 927 222.669v375.08c0 78.793-63.816 142.668-142.536 142.668H177.536C98.816 740.417 35 676.542 35 597.75v-375.08C35 143.875 98.816 80 177.536 80h606.928z m-90.181 152.253l-0.39 0.416-160.43 174.128-110.091-83.862-0.393-0.294c-12.863-9.494-29.72-7.109-40.246 5.695l-0.317 0.391-159.56 199.719-0.356 0.453c-11.52 14.898-10.787 37.753 1.659 51.612l0.38 0.417 0.39 0.414c12.824 13.384 32.497 12.531 44.425-1.927l0.36-0.443L410.9 402.25l108.507 82.656 0.37 0.279c12.157 8.986 27.996 7.408 38.657-3.854l0.322-0.344 178.78-194.045 0.383-0.423c12.53-14.048 13.084-37.228 1.153-52.065-11.932-14.837-31.876-15.768-44.79-2.2z" fill="#ffffff" p-id="2576"></path></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M569.6 750.933333l-19.2-68.266666H42.666667v106.666666c0 46.933333 38.4 85.333333 85.333333 85.333334h448l-4.266667-4.266667c-32-34.133333-34.133333-85.333333-2.133333-119.466667zM266.666667 810.666667h-106.666667c-17.066667 0-32-14.933333-32-32S142.933333 746.666667 160 746.666667h106.666667c17.066667 0 32 14.933333 32 32s-14.933333 32-32 32zM573.866667 565.333333l138.666666-138.666666H42.666667v192h503.466666c4.266667-19.2 12.8-38.4 27.733334-53.333334zM266.666667 554.666667h-106.666667c-17.066667 0-32-14.933333-32-32S142.933333 490.666667 160 490.666667h106.666667c17.066667 0 32 14.933333 32 32s-14.933333 32-32 32zM789.333333 256c0-46.933333-38.4-85.333333-85.333333-85.333333H128c-46.933333 0-85.333333 38.4-85.333333 85.333333v106.666667h746.666666v-106.666667z m-522.666666 42.666667h-106.666667c-17.066667 0-32-14.933333-32-32S142.933333 234.666667 160 234.666667h106.666667c17.066667 0 32 14.933333 32 32s-14.933333 32-32 32z m298.666666 0c-17.066667 0-32-14.933333-32-32s14.933333-32 32-32 32 14.933333 32 32-14.933333 32-32 32z m106.666667 0c-17.066667 0-32-14.933333-32-32s14.933333-32 32-32 32 14.933333 32 32-14.933333 32-32 32zM964.266667 629.333333l-121.6-121.6c-17.066667-17.066667-42.666667-17.066667-59.733334 0l-29.866666 29.866667-29.866667-29.866667-102.4 102.4c-10.666667 10.666667-14.933333 27.733333-10.666667 42.666667l34.133334 117.333333-25.6 25.6c-8.533333 8.533333-8.533333 21.333333 0 29.866667l29.866666 29.866667c8.533333 8.533333 21.333333 8.533333 29.866667 0l25.6-25.6 117.333333 34.133333c14.933333 4.266667 32 0 42.666667-10.666667l102.4-102.4-29.866667-29.866666 29.866667-29.866667c14.933333-19.2 14.933333-46.933333-2.133333-61.866667z m-136.533334-14.933333l-29.866666-29.866667 29.866666-29.866666 29.866667 29.866666-29.866667 29.866667z m61.866667 59.733333l-29.866667-29.866666 29.866667-29.866667 29.866667 29.866667-29.866667 29.866666z" /></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689757603554" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2420" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M844.7 124.4H489c-13.8 0-25 11.2-25 25s11.2 25 25 25h355.7c9 0 16.3 7.3 16.3 16.3v329.8c0 9-7.3 16.3-16.3 16.3H489c-13.8 0-25 11.2-25 25s11.2 25 25 25h355.7c36.6 0 66.3-29.8 66.3-66.3V190.8c0-36.6-29.7-66.4-66.3-66.4z" p-id="2421"></path><path d="M648 515.4c1.9 0 3.8-0.2 5.7-0.7 9.1-2.1 16.2-9.1 18.5-18.1l24.2-93.6 40.2 38.1c6.6 6.3 16.2 8.5 24.9 5.7s15.2-10.1 16.9-19.1l36.1-190c2.6-13.6-6.3-26.6-19.9-29.2-13.6-2.6-26.6 6.3-29.2 19.9l-27.5 145-37.7-35.8c-6.4-6.1-15.6-8.3-24.1-5.9-8.5 2.4-15.1 9.2-17.3 17.8l-22.9 88.4-13.3-15.5c-9-10.5-24.8-11.7-35.3-2.6-10.5 9-11.7 24.8-2.6 35.3l44.5 51.7c4.7 5.4 11.6 8.6 18.8 8.6zM282.4 337.4c60.2 0 109.2-49 109.2-109.2S342.6 119 282.4 119s-109.2 49-109.2 109.2 49 109.2 109.2 109.2z m0-168.4c32.6 0 59.2 26.5 59.2 59.2s-26.5 59.2-59.2 59.2-59.2-26.5-59.2-59.2 26.6-59.2 59.2-59.2zM551.6 413.7c0-33.2-27-60.2-60.2-60.2H167c-14.8 0-28.6 5.9-38.9 16.5-10.3 10.6-15.6 24.6-15.1 39.4l6.9 197c0.6 17.1 9.4 33.1 23.6 42.8l29.4 20c1 0.7 1.6 1.8 1.7 3l14.2 165.6c1.6 18.4 9.9 35.4 23.5 47.8 13.6 12.5 31.2 19.3 49.7 19.3h40.5c37.8 0 69.2-28.4 73.1-66L410 503.7c0.2-1.6 1.3-3 2.8-3.5l96-29c25.6-7.6 42.8-30.8 42.8-57.5z m-57.3 9.8l-96 29c-20.9 6.3-35.9 24.5-38.1 46.2L325.8 834c-1.2 12-11.3 21.1-23.3 21.1H262c-12.3 0-22.3-9.2-23.4-21.5L224.4 668c-1.4-16.2-9.9-30.8-23.4-40l-29.4-20c-1.1-0.7-1.7-1.9-1.8-3.2l-6.9-197c0-1.4 0.6-2.4 1.1-2.9 0.5-0.6 1.5-1.2 2.9-1.2h324.4c5.6 0 10.2 4.6 10.2 10.2 0.1 4.3-2.8 8.3-7.2 9.6z" p-id="2422"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M519.868669 583.569892A291.784946 291.784946 0 1 1 811.653615 291.784946 292.115269 292.115269 0 0 1 519.868669 583.569892z m0-528.516129A236.731183 236.731183 0 1 0 756.599852 291.784946 236.951398 236.951398 0 0 0 519.868669 55.053763zM35.395551 1024A27.526882 27.526882 0 0 1 7.868669 996.473118C7.868669 738.491183 237.55297 528.516129 519.868669 528.516129A546.463656 546.463656 0 0 1 745.589099 576.082581a27.526882 27.526882 0 1 1-22.021505 50.209032A492.84129 492.84129 0 0 0 519.868669 583.569892C267.942648 583.569892 62.922433 768.770753 62.922433 996.473118A27.526882 27.526882 0 0 1 35.395551 1024zM571.839422 854.874839a26.866237 26.866237 0 0 1-8.808602-1.431398 27.526882 27.526882 0 0 1-17.396989-34.793979 247.852043 247.852043 0 0 1 468.947957-2.972903 27.526882 27.526882 0 1 1-51.970753 18.167742 192.688172 192.688172 0 0 0-364.676129 2.312258 27.636989 27.636989 0 0 1-26.095484 18.71828zM652.548239 916.094624a27.196559 27.196559 0 0 1-11.891613-2.202151 27.636989 27.636989 0 0 1-12.88258-36.775914 170.446452 170.446452 0 0 1 152.719139-96.013763A168.574624 168.574624 0 0 1 932.771895 875.685161a27.526882 27.526882 0 1 1-49.43828 24.223656 113.851183 113.851183 0 0 0-102.950537-64.302795 115.062366 115.062366 0 0 0-103.060645 64.853333 27.747097 27.747097 0 0 1-24.774194 15.635269zM780.162863 962.670108m-52.190968 0a52.190968 52.190968 0 1 0 104.381936 0 52.190968 52.190968 0 1 0-104.381936 0Z" /></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M192 384h-64v512a64 64 0 0 0 64 64h512v-64H192zM544 288h-96v320h96c88.22 0 160-71.78 160-160s-71.78-160-160-160z" /><path fill="#ffffff" d="M832 64H320a64.19 64.19 0 0 0-64 64v640a64.19 64.19 0 0 0 64 64h512a64.19 64.19 0 0 0 64-64V128a64.19 64.19 0 0 0-64-64zM702.39 606.39A222.53 222.53 0 0 1 544 672H384V224h160a224 224 0 0 1 158.39 382.39z" /></svg>

After

Width:  |  Height:  |  Size: 635 B

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689263495822" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1180" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M463.238095 146.285714c175.055238 0 316.952381 141.897143 316.952381 316.952381 0 77.775238-28.038095 149.040762-74.532571 204.214857l188.440381 194.535619-55.247238 57.002667-191.536762-197.705143A315.489524 315.489524 0 0 1 463.238095 780.190476c-175.055238 0-316.952381-141.897143-316.952381-316.952381S288.182857 146.285714 463.238095 146.285714z m0 73.142857C328.582095 219.428571 219.428571 328.582095 219.428571 463.238095s109.153524 243.809524 243.809524 243.809524a242.883048 242.883048 0 0 0 161.889524-61.513143l25.551238-26.355809A242.834286 242.834286 0 0 0 707.047619 463.238095c0-134.656-109.153524-243.809524-243.809524-243.809524z m36.571429 97.52381v109.714286H609.52381v73.142857h-109.714286V609.52381h-73.142857v-109.738667L316.952381 499.809524v-73.142857l109.714286-0.024381V316.952381h73.142857z" p-id="1181"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689263030318" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2681" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M463.238095 146.285714c175.055238 0 316.952381 141.897143 316.952381 316.952381 0 77.775238-28.038095 149.040762-74.532571 204.214857l188.440381 194.535619-55.247238 57.002667-191.536762-197.705143A315.489524 315.489524 0 0 1 463.238095 780.190476c-175.055238 0-316.952381-141.897143-316.952381-316.952381S288.182857 146.285714 463.238095 146.285714z m0 73.142857C328.582095 219.428571 219.428571 328.582095 219.428571 463.238095s109.153524 243.809524 243.809524 243.809524a242.883048 242.883048 0 0 0 161.889524-61.513143l25.551238-26.355809A242.834286 242.834286 0 0 0 707.047619 463.238095c0-134.656-109.153524-243.809524-243.809524-243.809524z m152.210286 219.428572v73.142857H316.952381v-73.142857h298.496z" p-id="2682"></path></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="30.12px" viewBox="0 0 1088 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M960 832H128c-70.4 0-128-57.6-128-128V128C0 57.6 57.6 0 128 0h832c70.4 0 128 57.6 128 128v576c0 70.4-57.6 128-128 128zM128 64c-38.4 0-64 25.6-64 64v576c0 38.4 25.6 64 64 64h832c38.4 0 64-25.6 64-64V128c0-38.4-25.6-64-64-64H128z" /><path fill="#ffffff" d="M160 672s-6.4 0 0 0c-25.6-6.4-32-19.2-32-38.4 0-6.4 6.4-19.2 121.6-224 6.4-6.4 12.8-12.8 25.6-19.2 12.8 0 19.2 6.4 25.6 12.8l89.6 134.4 160-332.8c6.4-12.8 12.8-19.2 32-19.2 12.8 0 25.6 6.4 25.6 19.2L768 550.4l96-147.2c6.4-12.8 32-19.2 44.8-12.8 12.8 6.4 19.2 32 12.8 44.8l-128 198.4c-6.4 12.8-19.2 19.2-32 12.8-12.8 0-19.2-6.4-25.6-19.2L576 288l-153.6 320c-6.4 12.8-12.8 19.2-25.6 19.2s-25.6-6.4-32-12.8L268.8 473.6C224 550.4 185.6 627.2 179.2 640c6.4 25.6-6.4 32-19.2 32zM544 1024c-19.2 0-32-12.8-32-32v-192c0-19.2 12.8-32 32-32s32 12.8 32 32v192c0 19.2-12.8 32-32 32z" /><path fill="#ffffff" d="M736 1024h-384c-19.2 0-32-12.8-32-32s12.8-32 32-32h384c19.2 0 32 12.8 32 32s-12.8 32-32 32z" /></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,4 +1,4 @@
import React, { useState } from "react";
import { useState } from "react";
/**
* @author {温华}
@@ -7,7 +7,7 @@ import React, { useState } from "react";
* @param {permission: string[]}
*/
export default function Authenticationbtn({ permission }: any) {
export default function Authenticationbtn({ permission, children }: any) {
// 还需从缓存中获取用户权限数组
const [visible, setVisible] = useState(true)
const allPermission: string = "*:*:*"
@@ -20,5 +20,6 @@ export default function Authenticationbtn({ permission }: any) {
setVisible(hasPermission)
}
return <div style={{display: visible ? 'block' : 'none'}}></div>
if(visible) return <div>{children}</div>
return null
}

View File

@@ -1,5 +1,5 @@
import React from "react";
// import React from "react";
export default function ConfirmModel() {
// export default function ConfirmModel() {
}
// }

View File

@@ -0,0 +1,143 @@
import { Fragment, useState } from "react";
import {Button, DatePicker, Form, Input, Select} from 'antd'
import { useForm } from "antd/es/form/Form";
import { formatDate } from "@/utils/tool";
const { RangePicker } = DatePicker
interface IItemConfig {
name: string,
type: string,
key: string,
options?: Array<any>,
placeholder?: string,
picker?: any,
showTime?: boolean,
showHour?: boolean,
showMinute?: boolean,
showSecond?: boolean,
showNow?: boolean
}
export interface ISearchformConfig {
config: {
name: string,
formItem: Array<IItemConfig>
},
submit: (val: object)=>void
}
interface ISubmitVal {
[x: string]: any
}
export default function Fvsearchform(props: ISearchformConfig) {
const [val, setVal] = useState<object>()
const [form] = useForm()
const {config, submit} = props
const handleSubmit = (value: ISubmitVal) => {
if(Object.keys(value).length) {
config.formItem.forEach(item => {
for (const key in value) {
if ( item.type == 'date' && item.key == key ) {
value[key] && (value[key] = formatDate(value[key].$d))
}
if(item.type == 'rangedate' && item.key == key) {
value[key] && (value[key] = value[key]?.map((date: any)=>date = formatDate(date.$d)))
}
}
})
}
setVal({...val, ...value})
submit(value)
}
const handleReset = () => {
form.resetFields()
}
return(
<Fragment>
<Form
name={config?.name}
form={form}
onFinish={handleSubmit}
layout="inline"
>
{
config?.formItem.map((item:IItemConfig) => {
if(item) {
if(item.type === 'input') {
return(
<Form.Item
key={item.key}
label={item.name}
name={item.key}
>
<Input placeholder={item?.placeholder || '请输入'} allowClear></Input>
</Form.Item>
)
}
if(item.type === 'select') {
return(
<Form.Item
key={item.key}
label={item.name}
name={item.key}
>
<Select
options={item?.options}
placeholder={item?.placeholder || '请选择'}
allowClear
/>
</Form.Item>
)
}
if(item.type === 'date') {
return(
<Form.Item
key={item.key}
label={item.name}
name={item.key}
>
<DatePicker
picker={item.picker}
showTime={item?.showTime}
showNow={item?.showNow}
format="YYYY-MM-DD HH:mm:ss"
allowClear
/>
</Form.Item>
)
}
if(item.type === 'rangedate') {
return(
<Form.Item
key={item.key}
label={item.name}
name={item.key}
>
<RangePicker
showTime={item?.showTime}
showHour={item?.showHour}
showMinute={item?.showMinute}
showSecond={item?.showSecond}
showNow={item?.showNow}
picker={item.picker}
format="YYYY-MM-DD HH:mm:ss"
allowClear
/>
</Form.Item>
)
}
}
})
}
<Form.Item>
<Button htmlType="submit" type="primary" ></Button>
</Form.Item>
<Form.Item>
<Button onClick={handleReset} htmlType="submit"></Button>
</Form.Item>
</Form>
</Fragment>
)
}

View File

@@ -1,5 +1,5 @@
import { useState, useEffect } from "react";
// import { useState, useEffect } from "react";
export default function useDemo() {
// export default function useDemo() {
}
// }

View File

@@ -1,5 +1,4 @@
import React from "react";
import '../../assets/styles/appmain.scss'
import '@/assets/styles/appmain.scss'
import { Outlet } from "react-router-dom";
export default function AppMain() {

View File

@@ -1,4 +1,4 @@
import React, { useEffect } from "react";
import { useEffect } from "react";
import { Layout } from 'antd'
import { useDispatch, useSelector } from 'react-redux'
import SideBar from "./sidebar";

View File

@@ -3,7 +3,7 @@ import {
MenuFoldOutlined,
MenuUnfoldOutlined,
} from '@ant-design/icons';
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { setCollapsed } from '../../stores/sidebar';

View File

@@ -0,0 +1,19 @@
import { useMemo } from "react"
interface IMenuIconProps {
prefix?: string
name: string
color?: string,
size?: number | string
}
export default function Menuicon(props: IMenuIconProps) {
const { prefix = 'icon', name, color, size = 16 } = props
const symbolId = useMemo(() => `#${prefix}-${name}`, [prefix, name])
return (
<span className="anticon">
<svg aria-hidden="true" width={size} height={size} fill={color} >
<use href={symbolId} fill={color} />
</svg>
</span>
)
}

View File

@@ -1,6 +1,6 @@
import { Menu } from 'antd'
import React, {Fragment, useEffect, useState} from 'react'
import { useDispatch, useSelector } from 'react-redux';
import {Fragment, useEffect, useState} from 'react'
import { useSelector } from 'react-redux';
import { generateMenu } from '../../permission';
import { useLocation, useNavigate } from 'react-router-dom';
@@ -8,7 +8,7 @@ export default function SideBar() {
const navigate = useNavigate()
const location = useLocation()
const routes: [] = useSelector((store: any)=>store.permission)
const dispatch = useDispatch()
// const dispatch = useDispatch()
const [menuItem, setMenuItem] = useState<Array<any>>([{
key: '/',
label: '首页',
@@ -24,7 +24,7 @@ export default function SideBar() {
const goPage = (val: any) => {
console.log(val);
navigate(val.key)
navigate(val.key, { replace: true })
}
useEffect(()=>{
getMenu()
@@ -36,6 +36,7 @@ export default function SideBar() {
theme="dark"
mode="inline"
defaultSelectedKeys={[location.pathname]}
selectedKeys={[location.pathname]}
items={menuItem}
onClick={goPage}
/>

View File

@@ -3,6 +3,9 @@ import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'
import { BrowserRouter } from 'react-router-dom'
import { ConfigProvider } from 'antd'
import zhCn from 'antd/locale/zh_CN'
import 'virtual:svg-icons-register'
// redux toolkit
import { Provider } from 'react-redux'
@@ -13,7 +16,9 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
<Provider store={store}>
<PersistGate loading={null} persistor={persistor} >
<BrowserRouter>
<App />
<ConfigProvider locale={zhCn}>
<App />
</ConfigProvider>
</BrowserRouter>
</PersistGate>
</Provider>

View File

@@ -1,3 +1,4 @@
import Menuicon from "./layout/sidebar/Menuicon"
import { IRouter } from "./stores/permission"
// 生成菜单
@@ -11,7 +12,7 @@ export const generateMenu = (routes: IRouter): Array<any> => {
if(item.meta) {
item.title = item.meta?.title
item.label = item.meta?.title
item.icon = item.meta?.icon
item.icon = <Svgicon name={item.meta?.icon} />
}
if(item.children && item.children?.length) {
item.children = generateChildMenu(item.children)
@@ -29,11 +30,15 @@ const generateChildMenu = (routes: any): Array<any> => {
if(item.meta) {
item.title = item.meta?.title
item.label = item.meta?.title
item.icon = item.meta?.icon
item.icon = <Svgicon name={item.meta?.icon} />
}
if(item.children && item.children?.length) {
generateChildMenu(item.children)
}
return true
})
}
function Svgicon({name}:any) {
return <Menuicon name={name} />
}

View File

@@ -1,5 +1,4 @@
import { Navigate } from "react-router-dom"
import Notfound from "../Notfound"
import { getToken } from "../utils/auth"
const Views = import.meta.glob('../view/**/*.tsx')
@@ -13,17 +12,17 @@ const hasMapFile = (filePath: string): boolean => {
* @description 路由拦截组件
* @param {children: ReactDOM, filePath: string(文件路径)}
*/
export default function RouteInterception ({children, filePath=""}: any) {
if(getToken()) {
if(filePath!=="") {
if(hasMapFile(filePath)) {
export default function RouteInterception({ children, filePath = "" }: any) {
if (getToken()) {
if (filePath !== "") {
if (hasMapFile(filePath)) {
return children
} else {
return <Notfound />
return <Navigate to='/404' />
}
}
return children
} else {
return <Navigate to='/login' />
return <Navigate to='/login' replace={true} />
}
}

View File

@@ -1,13 +1,12 @@
import { getToken } from '../utils/auth'
import LayOut from '../layout/index'
import Home from '../view/home'
import { Suspense, lazy } from 'react'
import Loading from '../Loading'
import RouteInterception from './RouteInterception'
interface Meta {
title: string,
redirect?: boolean
}
import Notfound from '../Notfound'
// interface Meta {
// title: string,
// redirect?: boolean
// }
type route = {
path: string,
@@ -21,6 +20,10 @@ const lazyLoad = (viewName: string) => {
const LoginView = lazy(()=>import('../Login'))
return <LoginView />
}
if(viewName === 'home') {
const Home = lazy(()=>import('../view/home'))
return <Home />
}
const View = lazy(()=>import(`../view/${viewName}.tsx`))
return <View/>
}
@@ -29,11 +32,15 @@ const lazyLoad = (viewName: string) => {
const currentRouter: Array<route> = [
{
path: '/',
element: <RouteInterception><Suspense fallback={<Loading />}><LayOut /></Suspense></RouteInterception>,
element: <RouteInterception><LayOut /></RouteInterception>,
children: [
{
path: "", //登录后默认跳转路径
element : <Home/>
element : <Suspense fallback={<Loading />}>{lazyLoad('home')}</Suspense>
},
{
path: "*",
element: <Notfound />
}
]
},

53
src/stores/auth.ts Normal file
View File

@@ -0,0 +1,53 @@
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
import { getAuthInfoApi } from '../api/auth'
export interface IAuthInfo {
permissions: Array<string>,
roles: Array<string>
user: object
}
const initAuthInfo = new Object() as IAuthInfo
export const getAuthInfo = createAsyncThunk('/auth/info',
async () => {
try {
const {code, data} = await getAuthInfoApi()
if(code === 1000) {
return data
}
} catch (err) {
return Promise.reject(err)
}
}
)
export const authInfoSlice = createSlice({
name: 'authinfo',
initialState: initAuthInfo,
reducers: {
addAuthInfo(state, {payload}) {
state = {...payload}
return state
}
},
extraReducers(builder) {
builder
.addCase(getAuthInfo.pending, (state) => {
console.log(state);
console.log('正在请求登录用户信息')
})
.addCase(getAuthInfo.fulfilled, (state, {payload}) => {
console.log(state);
return payload
})
.addCase(getAuthInfo.rejected, (state, err) => {
console.log(state);
console.log(err, 'rejected')
})
}
})
export const { addAuthInfo } = authInfoSlice.actions
export default authInfoSlice.reducer

View File

@@ -1,10 +1,10 @@
import { createSlice } from '@reduxjs/toolkit'
type CacheKey = string
// type CacheKey = string
type CacheVal = any
// type CacheVal = any
const initCache = new Map<CacheKey, CacheVal>([])
// const initCache = new Map<CacheKey, CacheVal>([])
// 创建一个slice
export const cacheSlice = createSlice({

View File

@@ -4,6 +4,7 @@ import storage from "redux-persist/lib/storage";
import cacheSlice from "./cache";
import sidebarSlice from "./sidebar";
import permissionSlice from "./permission";
import authInfoSlice from "./auth"
const persistConfig = {
key: 'root',
@@ -14,7 +15,8 @@ const persistConfig = {
const reducers = combineReducers({
cache: cacheSlice,
sidebar: sidebarSlice,
permission: permissionSlice
permission: permissionSlice,
auth: authInfoSlice
})
// configureStore创建一个redux数据

View File

@@ -46,13 +46,16 @@ export const permissionSlice = createSlice({
extraReducers(builder) {
builder
.addCase(getAsyncRouters.pending, (state) => {
console.log(state);
console.log('正在请求路由');
})
.addCase(getAsyncRouters.fulfilled, (state, { payload }) => {
console.log(state);
// 请求成功后处理路由
return payload
})
.addCase(getAsyncRouters.rejected, (state, err) => {
console.log(state);
console.log(err,'rejected');
})

View File

@@ -6,13 +6,13 @@ export interface IResponse<T=any> {
}
// 定义请求方式枚举
enum EMethod {
GET = 'get',
POST = 'post',
PUT = 'put',
DELETE = 'delete',
PATCH = 'patch'
}
// enum EMethod {
// GET = 'get',
// POST = 'post',
// PUT = 'put',
// DELETE = 'delete',
// PATCH = 'patch'
// }
// 用户token类型定义
export type IToken = string

View File

@@ -1,6 +1,5 @@
import { IResponse, IToken } from "@/type";
import axios, { InternalAxiosRequestConfig, AxiosInstance, AxiosRequestConfig } from "axios";
import Cookie from 'js-cookie'
import { getToken, removeToken } from "./auth";
import { message } from "antd";

5
src/utils/tool.ts Normal file
View File

@@ -0,0 +1,5 @@
import moment from 'moment'
export function formatDate(date: Date, format='YYYY-MM-DD HH:mm:ss'): string {
return moment(date).format(format)
}

View File

@@ -1,5 +1,3 @@
import React from 'react'
export default function Home() {
return(
<div>home</div>

View File

@@ -0,0 +1,48 @@
.deptBox{
background: white;
padding: 20px;
.tablebox{
table{
thead{
th::before{
}
tr{
.ant-table-cell{
background: white;
color:#909399
}
}
}
tbody{
tr{
.ant-table-cell{
background: white;
color:#606266
}
}
}
}
.ant-table-cell{
button:focus
{
outline: none;
}
button:hover
{
border: 0px rgb(250, 250, 250);
}
}
}
.newAdd{
display: flex;
margin-top: 15px;
button{
margin-left: 15px;
}
}
}

View File

@@ -1,7 +1,575 @@
import React from "react";
import { useState,useEffect } from "react";
import {
Button,
Input,
Select,
message,
Table,
Tag,
Modal,
Form,
InputNumber,
Radio,
ConfigProvider,
TreeSelect,
Row,
Col,
// Icon
} from "antd";
import type { ColumnsType } from "antd/es/table";
import {
SyncOutlined,
SearchOutlined,
ExclamationCircleFilled,
SwapOutlined,
} from "@ant-design/icons";
import zh_CN from "antd/es/locale/zh_CN";
import "dayjs/locale/zh-cn";
// import 'moment/locale/zh-cn';
import {
getDatasAPI,
delDataAPI,
addDataAPI,
editDataAPI,
getDataAPI,
} from "../../../api/system/dept";
import "./index.scss";
// import { useForm } from "antd/es/form/Form";
interface searchValueType {
deptName: string | undefined;
state: string | undefined;
}
//表格单项数据类型
interface TableDataType {
children: number[];
createTime: string;
deptId: number;
deptName: string;
orderNum: string;
state: string;
}
let thisDept = {};
let treeData: any = [];
let isTreeAnyId = false;
export default function Dept() {
return(
<div>dept</div>
)
const { confirm } = Modal;
//提示组件
const [messageApi, contextHolder] = message.useMessage();
const [isAllExpend, setIsAllExpend] = useState(true);
//搜索框内所有内容
let [searchValue, setSearchValue] = useState<searchValueType>({
deptName: undefined,
state: undefined,
});
// const is
//树列表数据
// const [isTreeAnyId,setIsTreeAnyId]=useState(false)
const [treeAnyId, setTreeAnyId] = useState<number[]>([]);
const [expandedRowKeys, setExpandedRowKeys] = useState<number[]>([]);
//Modal
const [isModalOpen, setIsModalOpen] = useState(false);
const [modalTitle, setModalTitle] = useState('');
//表单区域
const [isDisbaled, setIsDisbaled] = useState<boolean>(false);
//serach
const [formSearch] = Form.useForm();
const [formModal] = Form.useForm();
//当前页面页数
//表格内数据
let [tableData, setTableData] = useState<TableDataType[]>([]);
//表格格式
const columns: ColumnsType<TableDataType> = [
{
title: "部门名称",
dataIndex: "deptName",
key: "deptName",
},
{
title: "排序",
dataIndex: "orderNum",
key: "orderNum",
},
{
title: "状态",
key: "state",
dataIndex: "state",
render: (text) => (
<>
{text === "0" ? (
<Tag color="success"></Tag>
) : (
<Tag color="error"></Tag>
)}
</>
),
},
{
title: "创建时间",
key: "createTime",
dataIndex: "createTime",
},
{
title: "操作",
key: "",
dataIndex: "",
render: (text) => (
<>
<Button type="link" onClick={() => handleNewAdd(text.deptId)}>
{"新增"}
</Button>
{/* <Button type='link' danger onClick={() => handleClickDel(text)}>{'删除'}</Button> */}
<Button type="link" onClick={() => handleEdit(text)}>
{"修改"}
</Button>
{text.parentId !== 0 ? (
<Button type="link" onClick={() => handleDelete(text)}>
{"删除"}
</Button>
) : null}
</>
),
},
];
//请求表格内容参数
let [queryTableDataParams, setQueryTableDataParams] = useState<any>({
deptName: undefined,
state: undefined,
});
const handleDelete = (dept: any) => {
confirm({
title: "系统提示",
icon: <ExclamationCircleFilled />,
content: `确定删除部门名称为${dept.deptName}的数据吗`,
okText: "确定",
okType: "danger",
cancelText: "取消",
onOk() {
(async () => {
try {
let { code } = await delDataAPI(dept.deptId);
if (code === 1000) {
console.log("del", dept.deptId);
messageApi.open({
type: "success",
content: "操作成功",
});
getDatas({});
}
} catch (error) {
console.log(error);
}
})();
},
onCancel() {
console.log("Cancel");
},
});
};
const handleSerach = () => {
searchValue = formSearch.getFieldsValue();
setSearchValue(searchValue)
console.log(searchValue);
setQueryTableDataParams({ ...searchValue });
};
const handleReset = () => {
formSearch.resetFields();
searchValue = formSearch.getFieldsValue();
setSearchValue(searchValue)
setQueryTableDataParams({ ...searchValue });
};
const handleEdit = async (dept: any) => {
if (dept.parentId === 0) {
setIsDisbaled(true);
formModal.setFieldsValue({ ...thisDept, parentId: dept.deptName });
} else {
setIsDisbaled(false);
// formModal.setFieldsValue({...thisDept});
}
await getData(dept.deptId);
if (dept.parentId === 0) {
setIsDisbaled(true);
formModal.setFieldsValue({ ...thisDept, parentId: dept.deptName });
} else {
setIsDisbaled(false);
formModal.setFieldsValue({ ...thisDept });
}
console.log(thisDept);
setModalTitle("修改部门");
setIsModalOpen(true);
};
const handleNewAdd = (deptId?: string) => {
setModalTitle("新增部门");
setIsModalOpen(true);
if (deptId) {
formModal.setFieldsValue({
parentId: deptId,
deptName: '',
orderNum: 0,
leader: '',
phone: '',
email: '',
state: "0",
});
} else
formModal.setFieldsValue({
parentId: undefined,
deptName: undefined,
orderNum: 0,
leader: undefined,
phone: undefined,
email: undefined,
state: "0",
});
};
const handleModalOk = () => {
formModal
.validateFields()
.then((values) => {
console.log("add", values);
if (modalTitle == "新增部门") {
console.log(values);
postAdd(values);
} else if (modalTitle == "修改部门") {
editData(values);
}
})
.catch((info) => {
console.log("Validate Failed:", info);
});
};
//遍历菜单树获取所有节点ID
const getTree = function (tree: any) {
tree.title = tree.deptName;
tree.value = tree.deptId;
if (!isTreeAnyId) {
treeAnyId.push(tree.deptId);
setTreeAnyId([...treeAnyId]);
}
if (tree.children) {
for (let child of tree.children) {
getTree(child);
}
}
setExpandedRowKeys([...treeAnyId])
};
const handleModalCanle = () => {
setIsModalOpen(false);
};
//获取详细数据
const getData = async (deptId: number) => {
try {
const { code, data } = await getDataAPI(deptId);
if (code === 1000) {
thisDept = data;
// console.log(thisDept);
}
} catch (error) {}
};
//修改数据
const editData = async (dept: any) => {
try {
const { code } = await editDataAPI({ ...thisDept, ...dept });
if (code === 1000) {
messageApi.open({
type: "success",
content: "操作成功",
});
setIsModalOpen(false);
getDatas(queryTableDataParams);
} else {
messageApi.open({
type: "error",
content: "操作失败",
});
}
} catch (error) {}
};
//获取部门数据
const getDatas = async (queryTableDataParams: any) => {
console.log("参数:", queryTableDataParams);
try {
const { code, data } = await getDatasAPI(queryTableDataParams);
console.log(data);
if (code === 1000) {
console.log(isTreeAnyId);
for (let child of data) {
getTree(child);
}
console.log(treeAnyId);
setExpandedRowKeys([...treeAnyId]);
// console.log(treeAnyId);
console.log(data);
setTableData(data);
treeData = data;
console.log(treeData);
// setTotal(data.total);
}
} catch (err: any) {
console.log("555", err);
}
isTreeAnyId = true;
};
//新增
const postAdd = async (dept: any) => {
try {
let { code } = await addDataAPI(dept);
console.log(code);
if (code === 1000) {
console.log("success");
messageApi.open({
type: "success",
content: "操作成功",
});
formModal.setFieldsValue({});
getDatas({ ...queryTableDataParams });
setIsModalOpen(false);
} else {
messageApi.open({
type: "error",
content: "部门名称已存在",
});
}
} catch (error) {}
};
useEffect(() => {
queryTableDataParams = {
...queryTableDataParams,
};
getDatas(queryTableDataParams);
return ()=>{
setIsAllExpend(true),
isTreeAnyId=false
}
}, [queryTableDataParams]);
return (
<ConfigProvider locale={zh_CN}>
<div className="deptBox">
<Form
layout="inline"
initialValues={undefined}
form={formSearch}
onFinish={handleSerach}
style={{ fontWeight: "700" }}
>
<Form.Item
label="部门名称"
name="deptName"
style={{ width: 300 + "px", marginTop: "10px" }}
>
<Input placeholder="请输入部门名称" allowClear />
</Form.Item>
<Form.Item
label="状态"
name="state"
wrapperCol={{ span: 22 }}
style={{ marginTop: "10px" }}
>
<Select
style={{ width: 300 + "px",textAlign:"left" }}
allowClear
showSearch
placeholder="请选择部门状态"
optionFilterProp="lable"
options={[
{
value: 0,
label: "正常",
},
{
value: 1,
label: "停用",
},
]}
/>
</Form.Item>
<Form.Item style={{ marginTop: "10px" }}>
<Button
type="primary"
htmlType="submit"
style={{ marginLeft: 20 + "px" }}
onClick={() => handleSerach()}
>
<SearchOutlined />
</Button>
</Form.Item>
<Form.Item style={{ marginTop: "10px" }}>
<Button onClick={() => handleReset()}>
<SyncOutlined />
</Button>
</Form.Item>
</Form>
{/* 新增 */}
<div className="newAdd">
<Button type="primary" onClick={() => handleNewAdd()}>
+
</Button>
<Button
type="primary"
style={{ backgroundColor: "rgb(144,147,153)" }}
onClick={() => {
setIsAllExpend(!isAllExpend);
if (isAllExpend) {
setExpandedRowKeys([]);
} else setExpandedRowKeys(treeAnyId);
}}
>
<SwapOutlined rotate={90} />
{isAllExpend ? "全部收起" : "全部展开"}
</Button>
</div>
{/* 弹出 */}
<Modal
open={isModalOpen}
title={modalTitle}
okText="确定"
cancelText="取消"
onCancel={handleModalCanle}
onOk={handleModalOk}
width={"700px"}
>
<Form
form={formModal}
// layout="inline"
name="form_in_modal"
initialValues={{ state: "0" }}
labelAlign="right"
// labelCol={{span:12}}
wrapperCol={{ span: 16 }}
>
<Row>
<Col span={24}>
<Form.Item
name="parentId"
label="上级部门"
rules={[{ required: true, message: "请选择上级部门" }]}
// style={{ width: 100 + "%" }}
>
<TreeSelect
disabled={isDisbaled}
// showSearch
style={{ width: "559px" }}
// value={value}
dropdownStyle={{ maxHeight: 400, overflow: "auto" }}
placeholder="请选择上级部门"
allowClear
// treeDefaultExpandAll
// onChange={onChange}
treeData={treeData}
//
/>
</Form.Item>
</Col>
</Row>
<Row>
<Col span={12}>
<Form.Item
name="deptName"
label="部门名称"
rules={[{ required: true, message: "请输入部门名称" }]}
// style={{ width: 45 + "%", marginTop: "20px" }}
>
<Input placeholder="请输入部门名称" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
required
name="orderNum"
label="显示顺序"
rules={[{ required: true, message: "请输入部门显示顺序" }]}
// style={{ width: 40 + "%", marginTop: "20px" }}
>
<InputNumber min={0} controls={true} />
</Form.Item>
</Col>
</Row>
<Row style={{translate:'25px'}}>
<Col span={12}>
<Form.Item
name="leader"
label="负责人"
// style={{ width: 40 + "%", marginTop: "20px", marginLeft: "10px" }}
>
<Input placeholder="请输入负责人" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="phone"
label="联系电话"
// style={{ width: 40 + "%", marginTop: "20px" }}
>
<Input placeholder="请输入联系电话" />
</Form.Item>
</Col>
</Row>
<Row style={{translate:'38px'}}>
<Col span={12}>
<Form.Item
name="email"
label="邮箱"
// style={{ width: 40 + "%", marginTop: "20px", marginLeft: "10px" }}
>
<Input placeholder="请输入邮箱" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="state"
label="状态"
className="collection-create-form_last-form-item"
// style={{ width: 40 + "%", marginTop: "20px", marginLeft: "10px" }}
>
<Radio.Group>
<Radio defaultChecked={true} value="0">
</Radio>
<Radio value="1"></Radio>
</Radio.Group>
</Form.Item>
</Col>
</Row>
</Form>
</Modal>
{/* 表格 */}
<div className="tablebox">
{contextHolder}
<Table
expandedRowKeys={expandedRowKeys}
onExpand={(expanded, record) => {
// console.log(expanded, record);
if (expanded) {
setExpandedRowKeys([record.deptId, ...expandedRowKeys]);
} else {
const newEx = expandedRowKeys.filter((element) => {
return element != record.deptId;
});
// console.log(expandedRowKeys);
setExpandedRowKeys(newEx);
}
console.log(expandedRowKeys);
}}
columns={columns}
rowKey={"deptId"}
dataSource={tableData}
pagination={false}
/>
</div>
</div>
</ConfigProvider>
);
}

View File

@@ -0,0 +1,60 @@
#content {
display: flex;
border-top: 1px solid black;
.dept-content {
flex: 20%;
padding: 35px 12px 0 0;
height: calc(100vh - 85px);
}
.left-dept {
flex: 20%;
padding: 35px 12px 0 0;
height: calc(100vh - 85px);
border: 1px solid red;
border-top: 1px solid black;
}
.right {
flex: 80%;
height: 190px;
display: flex;
flex-direction: column;
.search-content {
display: flex;
width: 500px;
justify-content: space-around;
padding: 35px 12px 0 0;
margin-left: 20px;
}
}
.table-content {
margin: 12px 0 0 12px;
.ant-table-thead > tr > th {
color: #909399;
text-align: center;
}
.ant-table-tbody > tr > td {
text-align: center;
}
}
.add-content {
display: flex;
margin-left: 12px;
margin-top: 20px;
button:focus,
button:focus-visible {
outline: none;
}
}
.user-mid-button {
display: flex;
margin-left: 12px;
margin-top: 20px;
button:focus,
button:focus-visible {
outline: none;
}
}
}

View File

@@ -0,0 +1,242 @@
import "./index.scss";
import { Select, Button, Table, Space, Tag, message, Modal } from "antd";
import {
EditOutlined,
DeleteOutlined,
ExclamationCircleFilled,
} from "@ant-design/icons";
import {
getNoticeListApi,
deleteNoticeInfoApi,
} from "../../../../api/system/notice";
import { useEffect, useState } from "react";
import { SearchOutlined, RedoOutlined } from "@ant-design/icons";
export default function Inform() {
const [noticeInfo, setNoticeInfo] = useState<string>("");
const [isNoticeOpen, setIsNoticeOpen] = useState<boolean>(false);
const [listData, setListData] = useState([]);
const [messageApi, contextHolder] = message.useMessage();
const [queryParams, setQueryParams] = useState<QueryParamsType>({
state: undefined,
pageSize: undefined,
pageNum: undefined,
});
const columns = [
{
title: "序号",
dataIndex: "noticeId",
key: "noticeId",
render: (text: string) => <>{text ? text : "null"}</>,
},
{
title: "公告标题",
dataIndex: "noticeTitle",
key: "noticeTitle",
render: (text: string) => <>{text ? text : "null"}</>,
},
{
title: "阅读状态",
key: "state",
dataIndex: "state",
render: (text: string) => (
<>
{text === "1" ? (
<Tag color="warning"></Tag>
) : (
<Tag color="error"></Tag>
)}
</>
),
},
{
title: "操作",
key: "operate",
dataIndex: "operate",
render: (_: string, record: object) => (
<div style={{ color: "#58aaff" }}>
<Space>
<EditOutlined />
<a
href="#"
onClick={() => handleInfo(record)}
style={{ color: " #58aaff" }}
>
</a>
<DeleteOutlined />
<a
href="#"
onClick={() => handleDel(record)}
style={{ color: " #58aaff" }}
>
</a>
</Space>
</div>
),
},
];
interface QueryParamsType {
state?: string;
pageSize?: number;
pageNum?: number;
}
const getList = async (newQueryParams: object) => {
try {
const { code, data } = await getNoticeListApi(newQueryParams);
if (code === 1000) {
setListData(data.rows);
}
} catch (err) {
console.error(err);
}
};
const handleReset = async () => {
setQueryParams({});
getList({});
};
const handleSearch = () => {
getList(queryParams);
};
const handleInfo = (record: any) => {
setIsNoticeOpen(true);
setNoticeInfo(record.noticeTitle);
};
const handleInfoOk = () => {
setIsNoticeOpen(false);
};
const handleInfoCancel = () => {
setIsNoticeOpen(false);
};
const handleDel = async (record: any) => {
Modal.confirm({
title: `确定删除Id为-${record.noticeId}-, 名称为-${record.noticeTitle}-的岗位吗?`,
icon: <ExclamationCircleFilled />,
async onOk() {
const { code } = await deleteNoticeInfoApi(record.noticeId);
try {
if (code === 1000) {
messageApi.open({
type: "success",
content: "删除成功",
});
getList({});
} else {
messageApi.open({
type: "error",
content: "删除失败",
});
}
} catch (err) {
console.log(err);
}
},
onCancel() {
messageApi.open({
type: "warning",
content: "取消成功",
});
},
});
};
const handlePageChange = (page: number) => {
setQueryParams({
...queryParams,
pageNum: page,
});
};
useEffect(() => {
getList(queryParams);
}, []);
return (
<div id="content">
<>
<div className="right">
<div className="search-content">
<>
<Space>
<div></div>
<Select
style={{ width: 220 }}
placeholder="请选择状态"
allowClear
options={[
{ value: "1", label: "已读" },
{ value: "0", label: "未读" },
]}
value={queryParams.state}
onChange={(value: any) =>
setQueryParams({
...queryParams,
state: value,
})
}
/>
</Space>
<Space>
<div className="search-button">
<Button type="primary" onClick={handleSearch}>
<SearchOutlined />
</Button>
</div>
</Space>
<Space>
<div className="reset-button" onClick={handleReset}>
<Button>
<RedoOutlined />
</Button>
</div>
</Space>
</>
</div>
<Modal
title="通知弹框"
open={isNoticeOpen}
onOk={handleInfoOk}
onCancel={handleInfoCancel}
footer={null}
>
<h1>{noticeInfo}</h1>
</Modal>
<div className="table-content">
<>
{contextHolder}
<Table
columns={columns}
dataSource={listData}
className="article-table"
pagination={{
onChange: handlePageChange,
locale: {
jump_to: "跳至",
page: "页",
},
showQuickJumper: true,
showTotal: (total, range) =>
`${range[0]}-${range[1]} 条,共 ${total}`,
}}
/>
</>
</div>
</div>
</>
</div>
);
}

View File

@@ -0,0 +1,64 @@
.Box{
width: 100%;
height: 100%;
background-color: white;
padding: 15px;
.tablebox{
table{
thead{
th::before{
}
tr{
.ant-table-cell{
background: white;
color:#909399
}
}
}
tbody{
tr{
.ant-table-cell{
background: white;
color:#606266
}
}
}
}
.ant-table-cell{
button:focus
{
outline: none;
}
button:hover
{
border: 0px rgb(250, 250, 250);
}
}
}
.newadd{
width: 60px;
height: 40px;
margin-top: 15px;
}
}
.myTree{
margin-top: 10px;
border: 1px solid rgb(173, 131, 131);
width: 250px;
}
.checkBox{
margin-top: 5px;
width: 250px;
display: flex;
label{
height: 20px;
margin-right: 10px;
}
}
.tox-tinymce{
width: 700px;
}

View File

@@ -0,0 +1,858 @@
import { useState, useEffect } from "react";
import {
Button,
Input,
Select,
message,
Table,
Tag,
Modal,
Pagination,
Form,
Radio,
ConfigProvider,
Row,
Col,
TreeSelect,
} from "antd";
import { Editor } from "@tinymce/tinymce-react";
import type { ColumnsType } from "antd/es/table";
import {
SyncOutlined,
SearchOutlined,
ExclamationCircleFilled,
} from "@ant-design/icons";
import zh_CN from "antd/es/locale/zh_CN";
import "dayjs/locale/zh-cn";
import "./index.scss";
import {
getDataListAPI,
getUserListAPI,
getRolesListAPI,
getDeptsListAPI,
addDataAPI,
deleteDataAPI,
getDataAPI,
} from "../../../../api/system/publish";
interface searchValueType {
dateTime: string[] | undefined;
roleName: string | undefined;
roleKey: string | undefined;
state: string | undefined;
startTime: string | undefined;
endTime: string | undefined;
}
//表格单项数据类型
interface TableDataType {
createTime: string;
dataScope: string;
deptIds: any[];
menuIds: any[];
roleId: number;
roleKey: string;
roleName: string;
roleSort: string;
state: string;
updateTime: string;
key?: number;
total?: number;
}
interface dataType {
senders: string[];
cluster?: string | null;
createBy?: string | null;
contentType?: string | null;
noticeContent: string;
noticeId?: number | null;
noticeTitle?: string | null;
noticeType?: string | null;
sendType?: string | null;
state?: string | null;
}
//当前选择的角色信息
interface queryParamsType {
cluster?: string;
contentType?: string;
noticeTitle?: string;
noticeType?: string;
publishId?: number;
sendType?: string;
pageNum?: number;
pageSize?: number;
}
let thisrole: any = {};
export default function Inform() {
const editorInit = {
language: "zh_CN",
min_height: 400,
plugins:
"print preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template code codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount imagetools textpattern help emoticons autosave bdmap indent2em autoresize formatpainter axupimgs",
toolbar:
["code undo redo restoredraft | cut copy paste pastetext | forecolor backcolor bold italic underline strikethrough link | anchor | alignleft aligncenter alignright alignjustify outdent indent | \
styleselect formatselect fontselect fontsizeselect | bullist numlist | blockquote subscript superscript removeformat | \
table image media charmap emoticons hr pagebreak insertdatetime print preview | fullscreen | bdmap indent2em lineheight formatpainter axupimgs"],
importcss_append: true,
//自定义文件选择器的回调内容
// file_picker_callback: function (callback, value, meta) {
// if (meta.filetype === 'file') {
// callback('https://www.baidu.com/img/bd_logo1.png', { text: 'My text' });
// }
// if (meta.filetype === 'image') {
// callback('https://www.baidu.com/img/bd_logo1.png', { alt: 'My alt text' });
// }
// if (meta.filetype === 'media') {
// callback('movie.mp4', { source2: 'alt.ogg', poster: 'https://www.baidu.com/img/bd_logo1.png' });
// }
// }
};
const { confirm } = Modal;
//提示组件
const [messageApi, contextHolder] = message.useMessage();
//搜索框内所有内容
let [searchValue, setSearchValue] = useState<searchValueType>({
dateTime: undefined,
roleName: undefined,
roleKey: undefined,
startTime: undefined,
state: undefined,
endTime: undefined,
});
const [thisNotice, setThisNotice] = useState<dataType>({
noticeContent: "",
senders: [],
});
const [allDisplay,setAllDisplay]=useState('block')
//Modal
const [isModalOpen, setIsModalOpen] = useState(false);
const [isDetailModalOpen, setIsDetailModalOpen] = useState(false);
const [modalTitle, setModalTitle] = useState("");
//表单区域
const [addForm] = Form.useForm();
const [detailForm] = Form.useForm();
//serach
const [formSearch] = Form.useForm();
//当前页面页数
let [count, setCount] = useState(1);
//表格内数据
let [tableData, setTableData] = useState<TableDataType[]>([]);
//发送对象数据
const [senderIds, setSenderIds] = useState<any>(undefined);
const [editorValue,setEditorValue]=useState('')
//表格数据总条数
let [total, setTotal] = useState<number>(0);
//表格格式
const columns: ColumnsType<TableDataType> = [
{
title: "序号",
dataIndex: "key",
key: "key",
},
{
title: "公告标题",
dataIndex: "noticeTitle",
key: "noticeTitle",
},
{
title: "公告类型",
dataIndex: "noticeType",
key: "noticeType",
render: (text) => {
switch (text) {
case "1":
return <Tag color="processing"></Tag>;
case "2":
return <Tag color="processing"></Tag>;
}
},
},
{
title: "内容类型",
key: "contentType",
dataIndex: "contentType",
render: (text) => {
switch (text) {
case "text":
return <Tag color=""></Tag>;
case "html":
return <Tag color="success"></Tag>;
}
},
},
{
title: "发送类型",
key: "sendType",
dataIndex: "sendType",
render: (text) => {
switch (text) {
case "user":
return <></>;
case "role":
return <></>;
case "dept":
return <></>;
case "all":
return <></>;
}
},
},
{
title: "创建时间",
key: "createTime",
dataIndex: "createTime",
},
{
title: "操作",
key: "",
dataIndex: "",
render: (text) => (
<>
<Button type="link" onClick={() => handleDetail(text)}>
{"详情"}
</Button>
<Button type="link" danger onClick={() => handleDelete(text)}>
{"删除"}
</Button>
</>
),
},
];
//请求表格内容参数
let [queryTableDataParams, setQueryTableDataParams] = useState<any>({
cluster: undefined,
contentType: undefined,
noticeTitle: undefined,
noticeType: undefined,
publishId: undefined,
sendType: undefined,
pageSize: undefined,
pageNum: undefined,
});
const onSendTypeChange = (value: string) => {
console.log(value);
if (value === "user") {
getUserList();
setAllDisplay('block')
} else if (value === "role") {
getRolesList();
setAllDisplay('block')
} else if (value === "dept") {
getDeptsList();
setAllDisplay('block')
}
else {
setAllDisplay('none')
}
};
const onEditorChange=(Value:string)=>{
setEditorValue(Value)
}
// let thisrole: any = {roleId:'s'};
const handleDetail = (text: any) => {
getData(text.noticeId);
// console.log(thisNotice.);
setIsDetailModalOpen(true);
};
const handleDelete = (text: any) => {
console.log(text);
confirm({
title: "系统提示",
icon: <ExclamationCircleFilled />,
content: `确定删除部门名称为${text.noticeTitle}的数据吗`,
okText: "确定",
okType: "danger",
cancelText: "取消",
onOk() {
(async () => {
try {
let { code } = await deleteDataAPI(text.noticeId);
if (code === 1000) {
messageApi.open({
type: "success",
content: "操作成功",
});
getDataList({});
}
} catch (error) {
console.log(error);
}
})();
},
onCancel() {
console.log("Cancel");
},
});
};
const handleSerach = () => {
searchValue = formSearch.getFieldsValue();
setSearchValue(searchValue);
count = 1;
setQueryTableDataParams({ ...searchValue });
};
const handleReset = () => {
formSearch.resetFields();
searchValue = formSearch.getFieldsValue();
setSearchValue(searchValue);
setQueryTableDataParams({ ...searchValue });
};
//Modal区域
const handleModalOk = () => {
addForm
.validateFields()
.then((values) => {
// form.resetFields();
if (modalTitle == "新增公告") {
if(values.sendType==='all') values.senderIds=['0']
console.log(values);
postAdd({ ...values, cluster: "notice", action: "SEND" ,noticeContent:editorValue});
}
})
.catch((info) => {
console.log("Validate Failed:", info);
});
console.log("modal thisrole", thisrole);
};
const handleModalCanle = () => {
setIsModalOpen(false);
};
const handleDetailCanle = () => {
setIsDetailModalOpen(false);
};
//新增
const handleNewAdd = () => {
setModalTitle("新增公告");
addForm.setFieldsValue({
noticeTitle: undefined,
noticeType: "1",
sendType: undefined,
senderIds: undefined,
contentType: "html",
});
setAllDisplay('block');
setEditorValue('')
setIsModalOpen(true);
};
const filterOption = (
input: string,
option?: { label: string; value: string }
) => (option?.label ?? "").toLowerCase().includes(input.toLowerCase());
//表格函数
//从服务器获取数据
//页码改变
const pageChange = (page: number, pageSize: number) => {
console.log(page, pageSize);
queryTableDataParams = { ...queryTableDataParams, pageNum: page, pageSize };
// setQueryParams({...queryParams,pageNum:page,pageSize})
console.log(queryTableDataParams);
getDataList(queryTableDataParams);
setCount(page);
};
//新增请求
const postAdd = async (value: any) => {
try {
let { code } = await addDataAPI(value);
if (code === 1000) {
console.log("success");
messageApi.open({
type: "success",
content: "操作成功",
});
addForm.setFieldsValue({
noticeTitle: undefined,
noticeType: "1",
sendType: undefined,
senderIds: undefined,
contentType: "html",
});
getDataList({ ...queryTableDataParams, pageNum: count });
setIsModalOpen(false);
} else {
messageApi.open({
type: "error",
content: "角色名称已存在",
});
}
} catch (error) {}
};
const getData = async (noticeId: number) => {
try {
const { data, code } = await getDataAPI(noticeId);
if (code === 1000) {
setThisNotice({ ...data });
}
} catch (error) {
console.log(error);
}
};
const getTree = function (tree: any) {
tree.title = tree.deptName;
tree.value = tree.deptId;
if (tree.children) {
for (let child of tree.children) {
getTree(child);
}
}
};
const getUserList = async () => {
try {
const { code, data } = await getUserListAPI();
if (code === 1000) {
let userIds: any = [];
console.log(data.rows);
data.rows.forEach((item: any) => {
userIds.push({ value: item.userId, label: item.userName });
});
setSenderIds([...userIds]);
}
} catch (error) {
console.log(error);
}
};
const getRolesList = async () => {
try {
const { code, data } = await getRolesListAPI();
if (code === 1000) {
let RolesIds: any = [];
console.log(data.rows);
data.rows.forEach((item: any) => {
RolesIds.push({ value: item.roleId, label: item.roleName });
});
setSenderIds([...RolesIds]);
}
} catch (error) {
console.log(error);
}
};
const getDeptsList = async () => {
try {
const { code, data } = await getDeptsListAPI();
if (code === 1000) {
for (let child of data) {
getTree(child);
}
console.log(data);
setSenderIds([...data]);
}
} catch (err: any) {
console.log("555", err);
}
};
const getDataList = async (queryTableDataParams: queryParamsType) => {
console.log("参数:", queryTableDataParams);
try {
const { code, data } = await getDataListAPI(queryTableDataParams);
if (code === 1000) {
const sortData = data.rows.sort(
(a: TableDataType, b: TableDataType) =>
parseInt(a.roleSort) - parseInt(b.roleSort)
);
sortData.forEach((element: TableDataType, i: number) => {
element.key = i + 1;
});
setTableData(sortData);
setTotal(data.total);
}
} catch (err: any) {
console.log("555", err);
}
};
useEffect(() => {
// setQueryParams({...queryParams,...valueSch})
queryTableDataParams = {
...queryTableDataParams,
// ...searchValue,
pageNum: count,
};
getDataList(queryTableDataParams);
// console.log(queryParams);
}, [queryTableDataParams]);
return (
<ConfigProvider locale={zh_CN}>
<div className="Box">
<Form
layout="inline"
initialValues={undefined}
form={formSearch}
onFinish={handleSerach}
style={{ fontWeight: "700" }}
>
<Form.Item
label="公告标题"
name="noticeTitle"
style={{ width: 350 + "px", marginTop: "10px" }}
>
<Input placeholder="请输入公告标题" allowClear />
</Form.Item>
<Form.Item
label="公告类型"
name="noticeType"
style={{ width: 350 + "px", marginTop: "10px" }}
>
<Select
style={{ textAlign: "left" }}
allowClear
showSearch
placeholder="请选择公告类型"
optionFilterProp="lable"
filterOption={filterOption}
options={[
{
value: "1",
label: "通知",
},
{
value: "2",
label: "公告",
},
]}
/>
</Form.Item>
<Form.Item
label="内容类型"
name="contentType"
style={{ width: 350 + "px", marginTop: "10px" }}
>
<Select
style={{ textAlign: "left" }}
allowClear
showSearch
placeholder="请选择内容类型"
optionFilterProp="lable"
filterOption={filterOption}
options={[
{
value: "text",
label: "文本",
},
{
value: "html",
label: "富文本",
},
]}
/>
</Form.Item>
<Form.Item
label="发送类型"
name="sendType"
style={{ width: 350 + "px", marginTop: "10px" }}
>
<Select
style={{ textAlign: "left" }}
allowClear
showSearch
placeholder="请选择发送类型"
optionFilterProp="lable"
filterOption={filterOption}
options={[
{
value: "user",
label: "用户",
},
{
value: "role",
label: "角色",
},
{
value: "dept",
label: "部门",
},
{
value: "all",
label: "全发",
},
]}
/>
</Form.Item>
<Form.Item style={{ marginTop: "10px" }}>
<Button
type="primary"
htmlType="submit"
style={{ marginLeft: 20 + "px" }}
onClick={() => handleSerach()}
>
<SearchOutlined />
</Button>
</Form.Item>
<Form.Item style={{ marginTop: "10px" }}>
<Button onClick={() => handleReset()}>
<SyncOutlined />
</Button>
</Form.Item>
</Form>
{/* 新增 */}
<div className="newadd">
<Button type="primary" onClick={handleNewAdd}>
+
</Button>
</div>
{/* 弹出 */}
<Modal
open={isModalOpen}
title={modalTitle}
width={800}
okText="确定"
cancelText="取消"
onCancel={handleModalCanle}
onOk={handleModalOk}
>
<Form
form={addForm}
layout="horizontal"
name="form_in_modal"
initialValues={{ noticeType: "1", contentType: "1" }}
labelAlign="right"
wrapperCol={{ span: 16 }}
>
<Row>
<Col span={12}>
<Form.Item
name="noticeTitle"
label="公告标题"
rules={[{ required: true, message: "请输入公告标题" }]}
>
<Input placeholder="请输入公告标题" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="noticeType"
label="公告类型"
rules={[{ required: true }]}
>
<Radio.Group>
<Radio defaultChecked={true} value="1">
</Radio>
<Radio value="2"></Radio>
</Radio.Group>
</Form.Item>
</Col>
</Row>
<Row>
<Col span={12}>
<Form.Item
required
name="sendType"
label="发送类型"
rules={[{ required: true, message: "选择发送类型" }]}
>
<Select
style={{ textAlign: "left" }}
allowClear
showSearch
placeholder="请选择发送类型"
optionFilterProp="lable"
filterOption={filterOption}
onChange={(value) => onSendTypeChange(value)}
options={[
{
value: "user",
label: "用户",
},
{
value: "role",
label: "角色",
},
{
value: "dept",
label: "部门",
},
{
value: "all",
label: "全发",
},
]}
/>
</Form.Item>
</Col>
<Col span={12}>{
allDisplay==='block'?<Form.Item
name="senderIds"
label="发送对象"
rules={[{ required: true, message: "选择发送对象" }]}
>
{senderIds === undefined ? (
<Select
mode="multiple"
style={{ textAlign: "left" }}
allowClear
showSearch
placeholder="请选择发送对象"
optionFilterProp="lable"
filterOption={filterOption}
/>
) : senderIds[0].children === undefined ? (
<Select
mode="multiple"
style={{ textAlign: "left" }}
allowClear
showSearch
placeholder="请选择发送对象"
optionFilterProp="lable"
filterOption={filterOption}
options={senderIds}
/>
) : (
<TreeSelect
multiple
style={{ textAlign: "left" }}
dropdownStyle={{ maxHeight: 400, overflow: "auto" }}
placeholder="请选择发送对象"
allowClear
treeData={senderIds}
//
/>
)}
</Form.Item>
:null
}
</Col>
</Row>
<Row>
<Form.Item
name="contentType"
label="内容类型"
rules={[{ required: true, message: "选择发送类型" }]}
>
<Radio.Group>
<Radio defaultChecked={true} value="html">
</Radio>
<Radio value="text"></Radio>
</Radio.Group>
</Form.Item>
</Row>
<Form.Item name="noticeContent" label="公告内容">
<Row>
<div>
<Editor
apiKey="v4zo4n22oanvco29ws5drh0pecuf3gh53clx53cccj3grjwg"
initialValue=""
init={editorInit}
value={editorValue}
onEditorChange={(Value)=>onEditorChange(Value)}
></Editor></div>
</Row>
</Form.Item>
</Form>
</Modal>
<Modal
open={isDetailModalOpen}
title={"公告详情"}
width={1200}
footer={null}
onCancel={handleDetailCanle}
>
<Form
form={detailForm}
layout="horizontal"
name="form_in_modal"
initialValues={{}}
labelAlign="right"
wrapperCol={{ span: 16 }}
>
<Row>
<Col span={8}>
<Form.Item
name="noticeTitle"
label="公告标题"
// initialValue={'ssss'}
>
<span> {thisNotice.noticeTitle}</span>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="sendType"
label="发送类型"
// initialValue={'ssss'}
>
<span>
{" "}
{thisNotice.sendType === "user"
? "用户"
: thisNotice.sendType === "role"
? "角色"
: thisNotice.sendType === "dept"
? "部门"
: "全发"}
</span>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="sendIds" label="发送对象">
<span>{thisNotice.senders.join("")}</span>
</Form.Item>
</Col>
</Row>
<Row>
<Col span={8}>
<Form.Item name="noticeType" label="公告类型">
<span>
{thisNotice.noticeType === "1" ? (
<Tag color="processing"></Tag>
) : (
<Tag color="processing"></Tag>
)}
</span>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="contentType" label="内容类型">
<span>
{thisNotice.contentType === "html" ? (
<Tag color="success"></Tag>
) : (
<Tag></Tag>
)}
</span>
</Form.Item>
</Col>
</Row>
<Row>
<Form.Item name="noticeContent" label="公告内容">
<span
dangerouslySetInnerHTML={{ __html: thisNotice.noticeContent }}
></span>
</Form.Item>
</Row>
</Form>
</Modal>
{/* 表格 */}
<div className="tablebox">
{contextHolder}
<Table columns={columns} dataSource={tableData} pagination={false} />
<Pagination
style={{
float: "right",
marginTop: "10px",
}}
total={total}
current={count}
showSizeChanger
showQuickJumper
onChange={(page, pageSize) => pageChange(page, pageSize)}
showTotal={(total) => `${total}`}
/>
</div>
</div>
</ConfigProvider>
);
}

View File

@@ -0,0 +1,103 @@
#content {
display: flex;
border-top: 1px solid black;
.dept-content {
flex: 20%;
padding: 35px 12px 0 0;
height: calc(100vh - 85px);
}
.left-dept {
flex: 20%;
padding: 35px 12px 0 0;
height: calc(100vh - 85px);
border: 1px solid red;
border-top: 1px solid black;
}
.right {
flex: 80%;
height: 190px;
display: flex;
flex-direction: column;
.search-content {
display: flex;
flex-direction: column;
padding: 35px 12px 0 0;
.content-top {
display: flex;
.input-item {
display: flex;
align-items: center;
margin-right: 20px;
width: 270px;
div {
width: 120px;
font-weight: bold;
}
}
:nth-child(3) {
div {
margin-right: -30px;
}
}
}
.content-bottom {
display: flex;
margin-left: 12px;
margin-top: 20px;
div {
margin-right: 10px;
}
.time-selector {
display: flex;
align-items: center;
div {
width: 120px;
font-weight: bold;
}
.time-picker {
width: 400px;
text-align: center;
margin-left: -30px;
margin-right: 25px;
}
}
button:focus,
button:focus-visible {
outline: none;
}
}
}
.table-content {
margin: 12px 0 0 12px;
.ant-table-thead > tr > th {
color: #909399;
text-align: center;
}
.ant-table-tbody > tr > td {
text-align: center;
}
}
.add-content {
display: flex;
margin-left: 12px;
margin-top: 20px;
button:focus,
button:focus-visible {
outline: none;
}
}
.user-mid-button {
display: flex;
margin-left: 12px;
margin-top: 20px;
button:focus,
button:focus-visible {
outline: none;
}
}
}
}

View File

@@ -0,0 +1,472 @@
import "./index.scss";
import {
Input,
Select,
Button,
Table,
Space,
Tag,
message,
Modal,
Form,
Row,
Col,
Radio,
InputNumber,
} from "antd";
import {
EditOutlined,
DeleteOutlined,
ExclamationCircleFilled,
} from "@ant-design/icons";
import {
getPostListApi,
addPostApi,
editPostApi,
deletePostApi,
} from "../../../api/system/post";
import { useEffect, useState } from "react";
import { SearchOutlined, RedoOutlined, PlusOutlined } from "@ant-design/icons";
export default function Post() {
const [form] = Form.useForm();
const [echoData, setEchoData] = useState<QueryParamsType>({});
const [listData, setListData] = useState([]);
const [radioValue, setRadioValue] = useState(1);
const [messageApi, contextHolder] = message.useMessage();
const [modalTitle, setModalTitle] = useState<string>("");
const [buttonType, setButtonType] = useState<string>("");
const [isShowModal, setIsShowModal] = useState<boolean>(false);
const [queryParams, setQueryParams] = useState<QueryParamsType>({
postName: undefined,
postCode: undefined,
state: undefined,
postSort: undefined,
pageSize: undefined,
pageNum: undefined,
});
const columns = [
{
title: "序号",
dataIndex: "postId",
key: "Id",
render: (text: string) => <>{text ? text : "null"}</>,
},
{
title: "岗位名称",
dataIndex: "postName",
key: "postName",
render: (text: string) => <>{text ? text : "null"}</>,
},
{
title: "岗位编码",
dataIndex: "postCode",
key: "postCode",
render: (text: string) => <>{text ? text : "null"}</>,
},
{
title: "排序",
key: "postSort",
dataIndex: "postSort",
render: (text: string) => <>{text ? text : "--"}</>,
},
{
title: "状态",
key: "state",
dataIndex: "state",
render: (text: string) => (
<>
{text === "0" ? (
<Tag color="processing"></Tag>
) : (
<Tag color="processing"></Tag>
)}
</>
),
},
{
title: "创建时间",
key: "createTime",
dataIndex: "createTime",
render: (text: string) => <>{text ? text : "null"}</>,
},
{
title: "操作",
key: "operate",
dataIndex: "operate",
render: (_: string, record: object) => (
<div style={{ color: "#58aaff" }}>
<Space>
<EditOutlined />
<a
href="#"
onClick={() => handleEdit(record)}
style={{ color: " #58aaff" }}
>
</a>
<DeleteOutlined />
<a
href="#"
onClick={() => handleDel(record)}
style={{ color: " #58aaff" }}
>
</a>
</Space>
</div>
),
},
];
interface QueryParamsType {
postName?: string;
postCode?: string;
state?: string;
postSort?: string;
postId?: string;
pageSize?: number;
pageNum?: number;
}
const getPostList = async (newQueryParams: object) => {
try {
const { code, data } = await getPostListApi(newQueryParams);
if (code === 1000) {
setListData(data.rows);
}
} catch (err) {
console.error(err);
}
};
const handleAdd = () => {
setModalTitle("新增用户");
setButtonType("ADD");
setIsShowModal(true);
};
const handleEdit = (data: any) => {
setModalTitle("修改用户");
setButtonType("EDIT");
setIsShowModal(true);
console.log(data);
setEchoData({
postId: data.postId,
});
handleEcho(data);
};
const handleConfirm = () => {
form.validateFields().then((values) => {
console.log(values);
console.log(buttonType);
if (buttonType === "ADD") {
handleConfirmAdd(values);
} else if (buttonType === "EDIT") {
handleConfirmEdit(values);
} else {
messageApi.open({
type: "error",
content: "系统异常,请刷新后重试",
});
}
});
};
const handleConfirmAdd = async (data: object) => {
console.log(data);
const { code } = await addPostApi(data);
try {
if (code === 1000) {
messageApi.open({
type: "success",
content: "创建成功",
});
setQueryParams({});
handleClear();
} else {
messageApi.open({
type: "error",
content: "岗位名称已经存在",
});
}
} catch (err) {
console.log(err);
}
};
const handleConfirmEdit = async (data: object) => {
const editData = {
...data,
postId: echoData.postId,
};
console.log(editData);
const { code } = await editPostApi(editData);
try {
if (code === 1000) {
messageApi.open({
type: "success",
content: "修改成功",
});
setQueryParams({});
handleClear();
} else {
messageApi.open({
type: "error",
content: "修改失败",
});
}
} catch (err) {
console.log(err);
}
};
const handleReset = async () => {
setQueryParams({});
getPostList({});
};
const handleSearch = () => {
getPostList(queryParams);
};
const handleDel = async (record: any) => {
Modal.confirm({
title: `确定删除Id为-${record.postId}-, 岗位名称为-${record.postName}-的岗位吗?`,
icon: <ExclamationCircleFilled />,
async onOk() {
const { code } = await deletePostApi(record.postId);
try {
if (code === 1000) {
messageApi.open({
type: "success",
content: "删除成功",
});
setQueryParams({});
} else {
messageApi.open({
type: "error",
content: "删除失败",
});
}
} catch (err) {
console.log(err);
}
},
onCancel() {
messageApi.open({
type: "warning",
content: "取消成功",
});
},
});
};
const handleSearchValues = (e: any) => {
const { name, value } = e.target;
setQueryParams({ ...queryParams, [name]: value });
};
const handlePageChange = (page: number) => {
setQueryParams({
...queryParams,
pageNum: page,
});
};
const handleEcho = (data: any) => {
const { postName, postCode, state, postSort } = data;
form.setFieldsValue({
postName,
postCode,
state,
postSort,
});
};
const handleCancel = () => {
handleClear();
};
const handleClear = () => {
form.resetFields();
setIsShowModal(false);
};
const onRadio = (e: any) => {
setRadioValue(e.target.value);
};
useEffect(() => {
getPostList(queryParams);
}, []);
return (
<div id="content">
<>
<div className="right">
<div className="search-content">
<>
<div className="content-top">
<div className="input-item">
<div></div>
<Input
placeholder="请输入岗位名称"
name="postName"
allowClear
value={queryParams.postName}
onChange={handleSearchValues}
/>
</div>
<div className="input-item">
<div></div>
<Input
placeholder="请输入岗位编码"
name="postCode"
allowClear
value={queryParams.postCode}
onChange={handleSearchValues}
/>
</div>
<div className="input-item">
<div></div>
<Select
style={{ width: 120 }}
placeholder="用户状态"
allowClear
options={[
{ value: "1", label: "正常" },
{ value: "0", label: "停用" },
]}
value={queryParams.state}
onChange={(value: any) =>
setQueryParams({
...queryParams,
state: value,
})
}
/>
</div>
</div>
<div className="content-bottom">
<div className="search-button">
<Button type="primary" onClick={handleSearch}>
<SearchOutlined />
</Button>
</div>
<div className="reset-button" onClick={handleReset}>
<Button>
<RedoOutlined />
</Button>
</div>
</div>
</>
</div>
<div className="add-content">
<>
<Button type="primary" onClick={handleAdd}>
<PlusOutlined />
</Button>
</>
</div>
<div className="table-content">
<>
{contextHolder}
<Table
columns={columns}
dataSource={listData}
className="article-table"
pagination={{
onChange: handlePageChange,
locale: {
jump_to: "跳至",
page: "页",
},
showQuickJumper: true,
showTotal: (total, range) =>
`${range[0]}-${range[1]} 条,共 ${total}`,
}}
/>
</>
</div>
<>
{contextHolder}
<Modal
title={modalTitle}
width={600}
okText="确认"
cancelText="取消"
open={isShowModal}
onOk={handleConfirm}
onCancel={handleCancel}
>
<Form
form={form}
name="basic"
initialValues={{ remember: true }}
onFinish={handleConfirm}
labelCol={{ span: 4 }}
autoComplete="off"
className="modal-form"
>
<Row>
<Col span={24}>
<Form.Item
label="岗位名称"
name="postName"
rules={[{ required: true, message: "请输入岗位名称" }]}
>
<Input defaultValue={""} placeholder="请输入岗位名称" />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item
label="岗位编码"
name="postCode"
rules={[{ required: true, message: "请输入岗位编码" }]}
>
<Input defaultValue={""} placeholder="请输入岗位编码" />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item
label="显示顺序"
name="postSort"
rules={[{ required: false }]}
>
<InputNumber />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item
label="状态"
name="state"
rules={[
{
required: false,
},
]}
>
<Radio.Group onChange={onRadio} value={radioValue}>
<Radio value="1"></Radio>
<Radio value="0"></Radio>
</Radio.Group>
</Form.Item>
</Col>
</Row>
</Form>
</Modal>
</>
</div>
</>
</div>
);
}

View File

@@ -0,0 +1,103 @@
.roleBox{
width: 100%;
height: 100%;
background-color: white;
padding: 15px;
// display: flex;
// flex-wrap: wrap;
// .SearchBox{
// display: flex;
// flex-wrap: wrap;
// .ipt{
// margin-top: 10px;
// margin-right: 10px;
// height: 32px;
// line-height: 32px;
// display: flex;
// span{
// font-weight: 700;
// // line-height: 32px;
// padding-right: 12px;
// // color: #606266;
// }
// .item,input{
// flex: 1;
// font-weight: 400;
// // width: 300px;
// margin-right: 40px;
// .ant-space-item{
// // margin-left: 500px;
// width: 500px;
// }
// }
// }
// .btn{
// button{
// margin-right: 15px;
// }
// margin-top: 10px;
// }
// }
// .btn{
// button{
// margin-right: 15px;
// }
// margin-top: 10px;
// }
.tablebox{
table{
thead{
th::before{
}
tr{
.ant-table-cell{
background: white;
color:#909399
}
}
}
tbody{
tr{
.ant-table-cell{
background: white;
color:#606266
}
}
}
}
.ant-table-cell{
button:focus
{
outline: none;
}
button:hover
{
border: 0px rgb(250, 250, 250);
}
}
}
.newadd{
width: 60px;
height: 40px;
margin-top: 15px;
}
}
.myTree{
margin-top: 10px;
border: 1px solid rgb(173, 131, 131);
width: 250px;
}
.checkBox{
margin-top: 5px;
width: 250px;
display: flex;
label{
height: 20px;
margin-right: 10px;
}
}

View File

@@ -0,0 +1,715 @@
import { useState, useEffect } from "react";
import {
Button,
Input,
Select,
DatePicker,
Space,
message,
Table,
Tag,
Modal,
Pagination,
Form,
Checkbox,
InputNumber,
Radio,
Tree,
ConfigProvider,
} from "antd";
import type { CheckboxChangeEvent } from "antd/es/checkbox";
import type { DatePickerProps, RangePickerProps } from "antd/es/date-picker";
import type { ColumnsType } from "antd/es/table";
import {
SyncOutlined,
SearchOutlined,
ExclamationCircleFilled,
} from "@ant-design/icons";
import zh_CN from "antd/es/locale/zh_CN";
import dataLocale from "antd/es/date-picker/locale/zh_CN";
import "dayjs/locale/zh-cn";
import "./index.scss";
import {
getRolesDataAPI,
delRoleAPI,
getRoleAPI,
addRoleAPI,
setRoleDataAPI,
getMenuLiseAPI,
} from "../../../api/system/role";
// import { useForm } from "antd/es/form/Form";
interface searchValueType {
dateTime: string[] | undefined;
roleName: string | undefined;
roleKey: string | undefined;
state: string | undefined;
startTime: string | undefined;
endTime: string | undefined;
}
//表格单项数据类型
interface TableDataType {
createTime: string;
dataScope: string;
deptIds: any[];
menuIds: any[];
roleId: number;
roleKey: string;
roleName: string;
roleSort: string;
state: string;
updateTime: string;
key?: number;
total?: number;
}
//当前选择的角色信息
const fieldNames = {
title: "menuName",
key: "menuId",
children: "children",
};
let thisrole: any = {};
let treeIds: number[] = [];
export default function Role() {
const { confirm } = Modal;
const { RangePicker } = DatePicker;
//提示组件
const [messageApi, contextHolder] = message.useMessage();
//搜索框内所有内容
let [searchValue, setSearchValue] = useState<searchValueType>({
dateTime: undefined,
roleName: undefined,
roleKey: undefined,
startTime: undefined,
state: undefined,
endTime: undefined,
});
//树列表数据
const [menuTreeData, setMenuTreeData] = useState([]);
//父子联动
const [checkStrictly, setCheckStrictly] = useState(false);
//树所有节点IDs
//树是否自动展开
const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
const [checkedKeys, setCheckedKeys] = useState<React.Key[]>([]);
const [selectedKeys, setSelectedKeys] = useState<React.Key[]>([]);
//Modal
const [isModalOpen, setIsModalOpen] = useState(false);
const [modalTitle, setModalTitle] = useState("");
//表单区域
const [form] = Form.useForm();
//serach
const [formSearch] = Form.useForm();
//当前页面页数
let [count, setCount] = useState(1);
//表格内数据
let [tableData, setTableData] = useState<TableDataType[]>([]);
//表格数据总条数
let [total, setTotal] = useState<number>(0);
//表格格式
const columns: ColumnsType<TableDataType> = [
{
title: "序号",
dataIndex: "key",
key: "key",
},
{
title: "角色名称",
dataIndex: "roleName",
key: "roleName",
},
{
title: "角色权限",
dataIndex: "roleKey",
key: "roleKey",
},
{
title: "数据范围",
key: "dataScope",
dataIndex: "dataScope",
render: (text) => {
switch (text) {
case "1":
return <></>;
case "2":
return <></>;
case "3":
return <></>;
default:
return <></>;
}
},
},
{
title: "显示顺序",
key: "roleSort",
dataIndex: "roleSort",
},
{
title: "状态",
key: "state",
dataIndex: "state",
render: (text) => (
<>
{text === "0" ? (
<Tag color="success"></Tag>
) : (
<Tag color="error"></Tag>
)}
</>
),
},
{
title: "创建时间",
key: "createTime",
dataIndex: "createTime",
},
{
title: "操作",
key: "",
dataIndex: "",
render: (text) => (
<>
<Button type="link" onClick={() => handleEdit(text)}>
{"修改"}
</Button>
{/* <Button type='link' danger onClick={() => handleClickDel(text)}>{'删除'}</Button> */}
<Button type="link" danger onClick={() => handleDelete(text)}>
{"删除"}
</Button>
<Button type="link">{"分配用户"}</Button>
</>
),
},
];
//请求表格内容参数
let [queryTableDataParams, setQueryTableDataParams] = useState<any>({
roleKey: undefined,
roleName: undefined,
state: undefined,
endTime: undefined,
startTime: undefined,
pageNum: undefined,
pageSize: undefined,
});
const [allChecked, setAllChecked] = useState(false);
const onTreeExpand = (expandedKeysValue: React.Key[]) => {
// console.log("onExpand", expandedKeysValue);
setExpandedKeys(expandedKeysValue);
};
const onCheckExpand = (e: CheckboxChangeEvent) => {
console.log(`checked = ${e.target.checked}`);
console.log(treeIds);
if (e.target.checked) setExpandedKeys(treeIds);
else setExpandedKeys([]);
console.log(expandedKeys);
};
const onCheckAll = (e: CheckboxChangeEvent) => {
console.log(`checked = ${e.target.checked}`);
setAllChecked(!allChecked);
if (!allChecked) setCheckedKeys(treeIds);
else setCheckedKeys([]);
};
const onCheckFaSon = (e: CheckboxChangeEvent) => {
console.log(`checked = ${e.target.checked}`);
setCheckStrictly(!e.target.checked);
};
const onTreeCheck = (checkedKeysValue: any) => {
// console.log("onCheck", checkedKeysValue.checked);
console.log("onCheck", checkedKeysValue);
console.log("treeIds", treeIds);
if (checkedKeysValue.length != treeIds.length) {
setAllChecked(false);
} else {
setAllChecked(true);
}
if (checkStrictly === false) {
form.setFieldsValue({ menuIds: checkedKeysValue });
setCheckedKeys(checkedKeysValue);
} else {
form.setFieldsValue({ menuIds: checkedKeysValue.checked });
setCheckedKeys(checkedKeysValue.checked);
}
};
const onTreeSelect = (selectedKeysValue: React.Key[], info: any) => {
console.log("onSelect", info);
// setExpandedKeys([...expandedKeys,...selectedKeysValue])
setSelectedKeys(selectedKeysValue);
};
//当前角色的数据
// let thisrole: any = {roleId:'s'};
const handleEdit = async (role: any) => {
await getRoleData(role);
setModalTitle("修改角色");
// setCheckedKeys(role)
setIsModalOpen(true);
};
const handleDelete = (role: any) => {
console.log(role);
confirm({
title: "系统提示",
icon: <ExclamationCircleFilled />,
content: `确定删除角色名称为${role.roleName}的数据吗`,
okText: "确定",
okType: "danger",
cancelText: "取消",
onOk() {
handleClickDel(role);
},
onCancel() {
console.log("Cancel");
},
});
};
const handleSerach = () => {
searchValue = formSearch.getFieldsValue();
if (typeof searchValue.dateTime !== "undefined") {
searchValue.startTime = (searchValue.dateTime as string[])[0];
searchValue.endTime = (searchValue.dateTime as string[])[1];
}
setSearchValue(searchValue);
count = 1;
setQueryTableDataParams({ ...searchValue });
};
const handleReset = () => {
formSearch.resetFields();
searchValue = formSearch.getFieldsValue();
setSearchValue(searchValue);
setQueryTableDataParams({ ...searchValue });
// setSearchValue({ ...searchValue });
// setCount(1)
};
//Modal区域
const handleModalOk = () => {
form
.validateFields()
.then((values) => {
// form.resetFields();
console.log("add", values);
if (modalTitle == "新增角色") {
postAdd({ ...values, menuIds: checkedKeys });
} else if (modalTitle == "修改角色") {
console.log(thisrole);
console.log(checkedKeys);
console.log("now", { ...thisrole, ...values, menuIds: checkedKeys });
// console.log({ ...thisrole, ...values,menuIds:setCheckedKeys });
thisrole = { ...thisrole, ...values, menuIds: checkedKeys };
editRoleData({ ...thisrole });
}
})
.catch((info) => {
console.log("Validate Failed:", info);
});
console.log("modal thisrole", thisrole);
};
const handleModalCanle = () => {
setIsModalOpen(false);
};
//新增
const handleNewAdd = () => {
setModalTitle("新增角色");
form.setFieldsValue({
roleName: "",
roleKey: "",
state: "0",
dataScope: "1",
roleSort: "0",
});
setCheckedKeys([]);
setIsModalOpen(true);
};
const onDateChange = (
valueDate: DatePickerProps["value"] | RangePickerProps["value"],
dateString: [string, string] | string
) => {
// setSelectedDate(valueDate)
console.log(valueDate);
searchValue.startTime = dateString[0];
searchValue.endTime = dateString[1];
formSearch.setFieldsValue({ dateTime: [dateString[0], dateString[1]] });
setSearchValue(searchValue);
// setSearchValue({ ...searchValue })
};
const filterOption = (
input: string,
option?: { label: string; value: string }
) => (option?.label ?? "").toLowerCase().includes(input.toLowerCase());
//表格函数
//从服务器获取数据
//页码改变
const pageChange = (page: number, pageSize: number) => {
console.log(page, pageSize);
queryTableDataParams = { ...queryTableDataParams, pageNum: page, pageSize };
// setQueryParams({...queryParams,pageNum:page,pageSize})
console.log(queryTableDataParams);
getRolesData(queryTableDataParams);
setCount(page);
};
//删除单项
const handleClickDel = (role: TableDataType) => {
console.log(role);
let { roleId } = role;
del(roleId);
};
//遍历菜单树获取所有节点ID
const getTreeIds = function (tree: any) {
// console.log('Ids:',tree);
tree.forEach((item: any) => {
// console.log(item);
treeIds.push(item.menuId);
if (item.children != null) getTreeIds(item.children);
});
};
//获取单个角色详细信息
const getRoleData = async (role: any) => {
// const {roleId,roleKey,roleName,roleSort,dataScope,state,meunIds}=role
// thisrole=role
try {
let { code, data } = await getRoleAPI(role);
if (code === 1000) {
console.log("role:", data);
thisrole = data;
console.log("thisrole", thisrole);
form.setFieldsValue(thisrole);
setCheckedKeys(data.menuIds);
}
} catch (error) {
console.log(error);
}
// setOpen(true);
};
//获取菜单权限树
const getMenuList = async () => {
try {
let menul = await getMenuLiseAPI();
console.log("tree", menul.data);
if (treeIds.length == 0) getTreeIds(menul.data);
console.log(treeIds);
setMenuTreeData(menul.data);
// treeData = menul.data
// setMenulist(menul.data)
} catch (error) {
console.log(error);
}
};
//新增请求
const postAdd = async (value: any) => {
try {
let { code } = await addRoleAPI(value);
console.log(code);
if (code === 1000) {
console.log("success");
messageApi.open({
type: "success",
content: "操作成功",
});
form.setFieldsValue({
roleName: "",
roleKey: "",
state: "0",
dataScope: "1",
});
getRolesData({ ...queryTableDataParams, pageNum: count });
setIsModalOpen(false);
} else {
messageApi.open({
type: "error",
content: "角色名称已存在",
});
}
} catch (error) {}
};
const getRolesData = async (queryTableDataParams: any) => {
console.log("参数:", queryTableDataParams);
try {
const { code, data } = await getRolesDataAPI(queryTableDataParams);
if (code === 1000) {
const sortData = data.rows.sort(
(a: TableDataType, b: TableDataType) =>
parseInt(a.roleSort) - parseInt(b.roleSort)
);
sortData.forEach((element: TableDataType, i: number) => {
element.key = i + 1;
});
setTableData(sortData);
setTotal(data.total);
}
} catch (err: any) {
console.log("555", err);
}
};
//服务器删除角色
const del = async (roleId: number) => {
try {
let { code } = await delRoleAPI({ roleId });
if (code === 1000) {
console.log("del", roleId);
messageApi.open({
type: "success",
content: "操作成功",
});
getRolesData({ pageNum: count });
}
} catch (error) {
console.log(error);
}
};
//修改角色信息
const editRoleData = async (role: any) => {
console.log(role);
try {
let { code, data } = await setRoleDataAPI(thisrole);
// let a = await setRoleDataAPI(role);
if (code === 1000) {
thisrole = { ...thisrole, ...data };
getRolesData({ ...queryTableDataParams, pageNum: count });
messageApi.open({
type: "success",
content: "操作成功",
});
setIsModalOpen(false);
form.setFieldsValue({
roleName: "",
roleKey: "",
state: "0",
dataScope: "1",
});
} else {
messageApi.open({
type: "error",
content: "角色名称已存在!",
});
}
} catch (error) {
messageApi.open({
type: "error",
content: "系统未知错误",
});
console.log(error);
}
};
useEffect(() => {
// setQueryParams({...queryParams,...valueSch})
queryTableDataParams = {
...queryTableDataParams,
// ...searchValue,
pageNum: count,
};
getRolesData(queryTableDataParams);
// console.log(queryParams);
}, [queryTableDataParams]);
useEffect(() => {
getMenuList();
}, []);
return (
<ConfigProvider locale={zh_CN}>
<div className="roleBox">
<Form
layout="inline"
initialValues={undefined}
form={formSearch}
onFinish={handleSerach}
style={{ fontWeight: "700" }}
>
<Form.Item
label="角色名称"
name="roleName"
style={{ width: 300 + "px", marginTop: "10px" }}
>
<Input placeholder="请输入角色名称" allowClear />
</Form.Item>
<Form.Item
label="权限字符"
name="roleKey"
style={{ width: 300 + "px", marginTop: "10px" }}
>
<Input allowClear placeholder="请输入权限字符" />
</Form.Item>
<Form.Item
label="状态:"
name="state"
wrapperCol={{ span: 22 }}
style={{ marginTop: "10px" }}
>
<Select
style={{ width: 300 + "px", textAlign: "left" }}
allowClear
showSearch
placeholder="请选择角色状态"
optionFilterProp="lable"
// onChange={onStateChange}
// onSearch={onSearch}
filterOption={filterOption}
// value={searchValue.state}
options={[
{
value: "0",
label: "正常",
},
{
value: "1",
label: "停用",
},
]}
/>
</Form.Item>
<Form.Item
label="登陆时间"
name="dateTime"
style={{ marginTop: "10px" }}
>
<Space direction="vertical" style={{ width: 400 + "px" }}>
<RangePicker
locale={dataLocale}
showTime
format="YYYY-MM-DD HH:mm:ss"
onChange={onDateChange}
/>
</Space>
</Form.Item>
<Form.Item style={{ marginTop: "10px" }}>
<Button
type="primary"
htmlType="submit"
style={{ marginLeft: 20 + "px" }}
onClick={() => handleSerach()}
>
<SearchOutlined />
</Button>
</Form.Item>
<Form.Item style={{ marginTop: "10px" }}>
<Button onClick={() => handleReset()}>
<SyncOutlined />
</Button>
</Form.Item>
</Form>
{/* 新增 */}
<div className="newadd">
<Button type="primary" onClick={handleNewAdd}>
+
</Button>
</div>
{/* 弹出 */}
<Modal
open={isModalOpen}
title={modalTitle}
okText="确定"
cancelText="取消"
onCancel={handleModalCanle}
onOk={handleModalOk}
>
<Form
form={form}
layout="horizontal"
name="form_in_modal"
initialValues={{ dataScope: "1", state: "0" }}
>
<Form.Item
name="roleName"
label="角色名称"
rules={[{ required: true, message: "请输入角色名称" }]}
>
<Input placeholder="请输入角色名称" />
</Form.Item>
<Form.Item
name="roleKey"
label="角色权限"
rules={[{ required: true, message: "请输入角色权限" }]}
>
<Input placeholder="请输入角色权限" />
</Form.Item>
<Form.Item
required
name="roleSort"
label="显示顺序"
rules={[{ required: true, message: "请输入角色显示顺序" }]}
>
<InputNumber min={0} max={10} controls={true} />
</Form.Item>
<Form.Item name="dataScope" label="数据范围">
<Radio.Group>
<Radio value="1" defaultChecked={true}>
</Radio>
<Radio value="2"></Radio>
<Radio value="3"></Radio>
<Radio value="4"></Radio>
</Radio.Group>
</Form.Item>
<Form.Item
name="state"
label="状态"
className="collection-create-form_last-form-item"
>
<Radio.Group>
<Radio defaultChecked={true} value="0">
</Radio>
<Radio value="1"></Radio>
</Radio.Group>
</Form.Item>
<Form.Item
name="menuIds"
label="菜单权限"
className="collection-create-form_last-form-item"
>
{/* <input type="text" /> */}
<div className="checkBox">
<Checkbox onChange={onCheckExpand}></Checkbox>
<Checkbox onChange={onCheckAll} checked={allChecked}>
</Checkbox>
<Checkbox onChange={onCheckFaSon}></Checkbox>
</div>
<div
className="myTree"
style={{ maxHeight: "250px", overflowY: "auto" }}
>
<Tree
fieldNames={fieldNames}
checkable
onExpand={onTreeExpand}
expandedKeys={expandedKeys}
autoExpandParent={true}
onCheck={onTreeCheck}
checkedKeys={checkedKeys}
checkStrictly={checkStrictly}
onSelect={onTreeSelect}
selectedKeys={selectedKeys}
treeData={menuTreeData}
/>
</div>
</Form.Item>
</Form>
</Modal>
{/* 表格 */}
<div className="tablebox">
{contextHolder}
<Table columns={columns} dataSource={tableData} pagination={false} />
<Pagination
style={{
float: "right",
marginTop: "10px",
}}
total={total}
current={count}
showSizeChanger
showQuickJumper
onChange={(page, pageSize) => pageChange(page, pageSize)}
showTotal={(total) => `${total}`}
/>
</div>
</div>
</ConfigProvider>
);
}

View File

@@ -0,0 +1,104 @@
#content {
display: flex;
border-top: 1px solid black;
.dept-content {
flex: 20%;
padding: 35px 12px 0 0;
height: calc(100vh - 85px);
}
.left-dept {
flex: 20%;
padding: 35px 12px 0 0;
height: calc(100vh - 85px);
border: 1px solid red;
border-top: 1px solid black;
}
.right-user {
flex: 80%;
height: 190px;
display: flex;
flex-direction: column;
.search-content {
display: flex;
flex-direction: column;
padding: 35px 12px 0 0;
.content-top {
display: flex;
.input-item {
display: flex;
align-items: center;
margin-right: 20px;
width: 270px;
div {
width: 120px;
font-weight: bold;
}
}
:nth-child(3) {
div {
margin-right: -30px;
}
}
}
.content-bottom {
display: flex;
margin-left: -20px;
margin-top: 20px;
div {
margin-right: 10px;
}
.time-selector {
display: flex;
align-items: center;
div {
width: 120px;
font-weight: bold;
}
.time-picker {
width: 400px;
text-align: center;
margin-left: -30px;
margin-right: 25px;
}
}
button:focus,
button:focus-visible {
outline: none;
}
}
}
.table-content {
margin: 12px 0 0 12px;
.ant-table-thead > tr > th {
color: #909399;
text-align: center;
}
.ant-table-tbody > tr > td {
text-align: center;
}
}
.add-content {
display: flex;
margin-left: 12px;
margin-top: 20px;
button:focus,
button:focus-visible {
outline: none;
}
}
.user-mid-button {
display: flex;
margin-left: 12px;
margin-top: 20px;
button:focus,
button:focus-visible {
outline: none;
}
}
}
}

View File

@@ -1,7 +1,807 @@
import React from 'react'
import "./index.scss";
import {
Input,
Tree,
Select,
DatePicker,
Button,
Table,
Space,
Tag,
message,
Modal,
Form,
Row,
Col,
TreeSelect,
Radio,
} from "antd";
import {
EditOutlined,
DeleteOutlined,
ExclamationCircleFilled,
} from "@ant-design/icons";
import {
getUserListApi,
deleteUserApi,
getDeptTreeApi,
addUserApi,
getRoleListApi,
getUserInfoApi,
editUserApi,
} from "../../../api/system/users";
import dataLocale from "antd/es/date-picker/locale/zh_CN";
import React, { useEffect, useState, useMemo } from "react";
import { SearchOutlined, PlusOutlined } from "@ant-design/icons";
export default function User() {
return(
<div>user</div>
)
}
const postIdList: number[] = [];
const [form] = Form.useForm();
const [searchForm] = Form.useForm();
const [echoId, setEchoId] = useState<any>();
const [myTreeData, setMyTreeData] = useState<[]>([]);
const [listData, setListData] = useState([]);
const [radioValue, setRadioValue] = useState(1);
const [searchTreeValue, setSearchTreeValue] = useState("");
const [roleList, setRoleList] = useState<any[]>([]);
const [messageApi, contextHolder] = message.useMessage();
const [modalTitle, setModalTitle] = useState<string>("");
const [buttonType, setButtonType] = useState<string>("");
const [isShowModal, setIsShowModal] = useState<boolean>(false);
const [autoExpandParent, setAutoExpandParent] = useState(true);
const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([
100, 102, 101, 104,
]);
const [treeValue, setTreeValue] = useState<string>();
const fieldNames = {
label: "deptName",
title: "deptName",
value: "deptId",
key: "deptName",
};
const [queryParams, setQueryParams] = useState<QueryParamsType>({
deptId: undefined,
userName: undefined,
phoneNumber: undefined,
state: undefined,
startTime: undefined,
endTime: undefined,
pageNum: undefined,
pageSize: undefined,
});
const columns = [
{
title: "序号",
dataIndex: "userId",
key: "Id",
render: (text: string) => <>{text ? text : "null"}</>,
},
{
title: "用户名称",
dataIndex: "userName",
key: "userName",
render: (text: string) => <>{text ? text : "null"}</>,
},
{
title: "用户昵称",
dataIndex: "nickName",
key: "nikeName",
render: (text: string) => <>{text ? text : "null"}</>,
},
{
title: "部门",
key: "deptId",
dataIndex: "deptName",
render: (text: string) => <>{text ? text : "--"}</>,
},
{
title: "手机号码",
key: "phoneNumber",
dataIndex: "phoneNumber",
render: (text: string) => <>{text ? text : "--"}</>,
},
{
title: "状态",
key: "state",
dataIndex: "state",
render: (text: string) => (
<>
{text === "0" ? (
<Tag color="processing"></Tag>
) : (
<Tag color="processing"></Tag>
)}
</>
),
},
{
title: "创建时间",
key: "createTime",
dataIndex: "createTime",
render: (text: string) => <>{text ? text : "null"}</>,
},
{
title: "操作",
key: "operate",
dataIndex: "operate",
render: (_: string, record: object) => (
<div style={{ color: "#58aaff" }}>
<Space>
<EditOutlined />
<a
href="#"
onClick={() => handleEdit(record)}
style={{ color: " #58aaff" }}
>
</a>
<DeleteOutlined />
<a
href="#"
onClick={() => handleDel(record)}
style={{ color: " #58aaff" }}
>
</a>
</Space>
</div>
),
},
];
interface AddUserType {
email: string;
nickName: string;
password: string;
phoneNumber: string;
postIds: number[];
roleIds: number[];
sex: string;
state: string;
userName: string;
}
interface QueryParamsType {
deptId?: number;
userName?: string;
phoneNumber?: string;
state?: string;
startTime?: string | any;
endTime?: string | any;
pageNum?: number;
pageSize?: number;
}
let addUserParams: AddUserType = {
email: "",
nickName: "",
password: "",
phoneNumber: "",
postIds: [],
roleIds: [],
sex: "",
state: "",
userName: "",
};
const getDeptTreeData = async () => {
try {
const { code, data } = await getDeptTreeApi();
if (code === 1000) {
setMyTreeData(data);
handleLoopPostList(data);
setExpandedKeys(postIdList);
}
} catch (error) {
console.error(error);
}
};
const getUserList = async (newQueryParams: object) => {
try {
const { code, data } = await getUserListApi(newQueryParams);
if (code === 1000) {
setListData(data.rows);
}
} catch (err) {
console.error(err);
}
};
const getUserInfo = async () => {
try {
const { code, data } = await getUserInfoApi(echoId);
if (code === 1000) {
handleEcho(data);
}
} catch (error) {
console.error(error);
}
};
const getRoleList = async () => {
try {
const { code, data } = await getRoleListApi();
if (code === 1000) {
setRoleList(data.rows);
}
} catch (err) {
console.log(err);
}
};
const handleAdd = () => {
setModalTitle("新增用户");
setButtonType("ADD");
setIsShowModal(true);
};
const handleEdit = (echoData: any) => {
setModalTitle("修改用户");
setButtonType("EDIT");
setIsShowModal(true);
setEchoId(echoData.userId);
};
const handleConfirm = () => {
form.validateFields().then((values) => {
Object.keys(values).forEach(
(key) => values[key] === undefined && delete values[key]
);
addUserParams = {
...addUserParams,
...values,
userId: echoId,
};
if (buttonType === "ADD") {
handleAddUser();
} else if (buttonType === "EDIT") {
handleEditUser();
} else {
messageApi.open({
type: "error",
content: "系统异常,请刷新后重试",
});
}
});
};
const handleAddUser = async () => {
const { code } = await addUserApi(addUserParams);
try {
if (code === 1000) {
messageApi.open({
type: "success",
content: "创建成功",
});
setQueryParams({});
handleClear();
} else {
messageApi.open({
type: "error",
content: "用户名已经存在",
});
}
} catch (err) {
console.log(err);
}
};
const handleEditUser = async () => {
const { code } = await editUserApi(addUserParams);
try {
if (code === 1000) {
messageApi.open({
type: "success",
content: "修改成功",
});
setQueryParams({});
handleClear();
} else {
messageApi.open({
type: "error",
content: "修改失败",
});
}
} catch (err) {
console.log(err);
}
};
const handleReset = async () => {
searchForm.resetFields();
setQueryParams({});
getUserList({});
};
const handleSearch = () => {
getUserList(queryParams);
};
const handleDel = async (record: any) => {
Modal.confirm({
title: `确定删除Id为-${record.userId}-, 用户名为-${record.userName}-的用户吗?`,
icon: <ExclamationCircleFilled />,
async onOk() {
const { code } = await deleteUserApi(record.userId);
try {
if (code === 1000) {
messageApi.open({
type: "success",
content: "删除成功",
});
setQueryParams({});
} else {
messageApi.open({
type: "error",
content: "删除失败",
});
}
} catch (err) {
console.log(err);
}
},
onCancel() {
messageApi.open({
type: "warning",
content: "取消成功",
});
},
});
};
const handleTimePikerValue = (_: any, dates: string[]) => {
setQueryParams({
...queryParams,
startTime: dates[0],
endTime: dates[1],
});
searchForm.setFieldsValue({ dataTime: [dates[0], dates[1]] });
};
const handleSearchValues = (e: any) => {
const { name, value } = e.target;
setQueryParams({ ...queryParams, [name]: value });
};
const handlePageChange = (page: number) => {
setQueryParams({
...queryParams,
pageNum: page,
});
};
const handleTreeSelect = (deptId: any) => {
console.log(queryParams);
getUserList({
...queryParams,
deptId: deptId[0],
});
};
const handleEcho = (data: any) => {
const { userName, nickName, sex, state, phoneNumber, deptId, email } =
data.user;
const { postIds, roleIds } = data;
form.setFieldsValue({
userName,
nickName,
state,
phoneNumber,
sex,
deptId,
email,
postIds,
roleIds,
});
};
const handleCancel = () => {
handleClear();
};
const handleClear = () => {
form.resetFields();
setIsShowModal(false);
};
const handleExpandKeys = (key: string, data: object[]) => {
const filterRes = new RegExp(key, "i");
data.forEach((item: any) => {
if (filterRes.test(item?.title?.props?.children)) {
postIdList.push(item.key);
}
item.children ? handleExpandKeys(key, item.children) : "";
});
};
const handleLoopPostList = (loopData: object[]) => {
loopData.forEach((item: any) => {
if (item?.deptId) {
const flag = postIdList.some((someItem) => {
someItem === item.deptId;
});
if (!flag) {
postIdList.push(item.deptId);
}
}
item.children ? handleLoopPostList(item.children) : "";
});
};
const onRadio = (e: any) => {
setRadioValue(e.target.value);
};
const onTreeSelect = (newValue: string) => {
setTreeValue(newValue);
};
const onTreeSearch = (e?: any) => {
const { value } = e.target ? e.target : null;
setSearchTreeValue(value);
handleExpandKeys(value, treeData);
setExpandedKeys(postIdList);
setAutoExpandParent(true);
};
const onExpand = (newExpandedKeys: React.Key[]) => {
console.log(newExpandedKeys);
setExpandedKeys(newExpandedKeys);
setAutoExpandParent(false);
};
const treeData = useMemo(() => {
const loop = (data: any[]): any[] =>
data.map((item) => {
const strTitle = item.deptName as string;
const index = strTitle.indexOf(searchTreeValue);
const beforeStr = strTitle.substring(0, index);
const afterStr = strTitle.slice(index + searchTreeValue.length);
const title =
index > -1 ? (
<span>
{beforeStr}
<span className="site-tree-search-value">{searchTreeValue}</span>
{afterStr}
</span>
) : (
<span>{strTitle}</span>
);
if (item.children) {
return { title, key: item.deptId, children: loop(item.children) };
}
return {
title,
key: item.deptId,
};
});
return loop(myTreeData);
}, [myTreeData]);
useEffect(() => {
getDeptTreeData();
getRoleList();
getUserInfo();
}, [echoId]);
useEffect(() => {
getUserList({});
}, []);
return (
<div id="content">
<div className="dept-content">
<Input
allowClear
style={{ marginBottom: 8 }}
prefix={<SearchOutlined />}
placeholder="请输入部门名称"
onChange={onTreeSearch}
/>
<Tree
onExpand={onExpand}
defaultExpandAll={true}
expandedKeys={expandedKeys}
autoExpandParent={autoExpandParent}
treeData={treeData}
onSelect={handleTreeSelect}
/>
</div>
<>
<div className="right-user">
<Form
layout="inline"
form={searchForm}
onFinish={handleSearch}
style={{ fontWeight: "700", marginLeft: 12, marginTop: 23 }}
>
<Form.Item
label="用户名称"
name="userName"
style={{ width: 300 + "px", marginTop: "10px" }}
>
<Input
placeholder="请输入用户名称"
name="userName"
allowClear
value={queryParams.userName}
onChange={handleSearchValues}
/>
</Form.Item>
<Form.Item
label="手机号码"
name="phoneNumber"
style={{ width: 300 + "px", marginTop: "10px" }}
>
<Input
placeholder="请输入手机号码"
name="phoneNumber"
allowClear
value={queryParams.phoneNumber}
onChange={handleSearchValues}
/>
</Form.Item>
<Form.Item label="状态" name="state" style={{ marginTop: "10px" }}>
<Select
style={{ width: 250 }}
placeholder="用户状态"
allowClear
options={[
{ value: "1", label: "正常" },
{ value: "0", label: "停用" },
]}
value={queryParams.state}
onChange={(value: any) =>
setQueryParams({
...queryParams,
state: value,
})
}
/>
</Form.Item>
<Form.Item
label="创建时间"
name="dateTime"
style={{ marginTop: "10px" }}
>
<DatePicker.RangePicker
locale={dataLocale}
showTime
format="YYYY-MM-DD HH:mm:ss"
onChange={handleTimePikerValue}
/>
</Form.Item>
<Form.Item style={{ marginTop: "10px" }}>
<Button
type="primary"
htmlType="submit"
style={{ marginLeft: 20 + "px" }}
>
</Button>
</Form.Item>
<Form.Item style={{ marginTop: "10px" }}>
<Button onClick={handleReset}></Button>
</Form.Item>
</Form>
<div className="add-content">
<>
<Button type="primary" onClick={handleAdd}>
<PlusOutlined />
</Button>
</>
</div>
<div className="table-content">
<>
{contextHolder}
<Table
columns={columns}
dataSource={listData}
className="article-table"
pagination={{
onChange: handlePageChange,
locale: {
jump_to: "跳至",
page: "页",
},
showQuickJumper: true,
showTotal: (total, range) =>
`${range[0]}-${range[1]} 条,共 ${total}`,
}}
/>
</>
</div>
<>
{contextHolder}
<Modal
title={modalTitle}
width={700}
okText="确认"
cancelText="取消"
open={isShowModal}
onOk={handleConfirm}
onCancel={handleCancel}
>
<Form
form={form}
name="basic"
initialValues={{ remember: true }}
labelCol={{ span: 6 }}
onFinish={handleConfirm}
autoComplete="off"
className="modal-form"
>
<Row>
<Col span={12}>
<Form.Item
label="用户名称"
name="userName"
rules={[{ required: true, message: "请输入用户名称" }]}
>
<Input defaultValue={""} placeholder="请输入用户名称" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="用户昵称"
name="nickName"
rules={[{ required: true, message: "请输入用户昵称" }]}
>
<Input defaultValue={""} placeholder="请输入用户昵称" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="用户性别"
name="sex"
rules={[{ required: false }]}
>
<Select
placeholder="请选择用户性别"
options={[
{ value: "0", label: "男" },
{ value: "1", label: "女" },
{ value: "2", label: "未知" },
]}
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="用户密码"
name="password"
rules={[{ required: true, message: "请输入用户密码" }]}
>
<Input.Password
defaultValue={""}
placeholder="请输入密码"
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="归属部门"
name="deptId"
rules={[{ required: false }]}
>
<TreeSelect
showSearch
style={{ width: "100%" }}
value={treeValue}
dropdownStyle={{ maxHeight: 400, overflow: "auto" }}
placeholder="请选择"
allowClear
fieldNames={fieldNames}
treeDefaultExpandAll
onChange={onTreeSelect}
treeData={myTreeData}
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="手机号码"
name="phoneNumber"
rules={[{ required: false }]}
>
<Input placeholder="请输入手机号码" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="邮箱"
name="email"
rules={[{ required: false }]}
>
<Input defaultValue={""} placeholder="请输入邮箱" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="状态"
name="state"
rules={[
{
required: false,
message: "Please input your password!",
},
]}
>
<Radio.Group onChange={onRadio} value={radioValue}>
<Radio value="1"></Radio>
<Radio value="0"></Radio>
</Radio.Group>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="岗位"
name="postIds"
rules={[
{
required: false,
message: "Please input your password!",
},
]}
>
<Select
mode="multiple"
defaultValue={[]}
options={[
{ value: "董事长", label: "董事长" },
{ value: "项目经理", label: "项目经理" },
{ value: "人力资源", label: "人力资源" },
{ value: "普通员工", label: "普通员工" },
]}
placeholder="请选择岗位"
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="角色"
name="roleIds"
rules={[
{
required: false,
message: "Please input your password!",
},
]}
>
<Select mode="multiple" placeholder="请选择角色">
{roleList.map((item) => (
<Select.Option key={item.roleId} value={item.roleId}>
{item.roleName}
</Select.Option>
))}
</Select>
</Form.Item>
</Col>
<Col span={24}>
<Form.Item
label="备注"
labelCol={{ span: 3 }}
rules={[
{
required: false,
message: "Please input your password!",
},
]}
>
<Input.TextArea placeholder="请输入内容" />
</Form.Item>
</Col>
</Row>
</Form>
</Modal>
</>
</div>
</>
</div>
);
}

View File

@@ -1,15 +1,21 @@
import { defineConfig } from 'vite'
import path from 'path'
import react from '@vitejs/plugin-react'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
// https://vitejs.dev/config/
export default defineConfig({
base: './',
plugins: [
react(),
createSvgIconsPlugin({
iconDirs: [path.resolve(process.cwd(),'src/assets/svg')],
symbolId: 'icon-[dir]-[name]'
})
],
resolve: {
alias: {
'@': 'src/'
'@': path.resolve(__dirname, 'src')
}
},
build: {