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
44 changed files with 11787 additions and 837 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

7891
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -29,6 +29,7 @@
},
"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

@@ -19,7 +19,7 @@ export default function Authenticationbtn({ permission, children }: any) {
})
setVisible(hasPermission)
}
if(visible) return children
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

@@ -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,4 +1,4 @@
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

@@ -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

@@ -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";

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

@@ -1,5 +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() {
return(
<div>1</div>
)
}
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

@@ -1,5 +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() {
return(
<div>2</div>
)
}
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>
);
}