新增:新增系统管理/部门管理/查询列表功能,并将所有描述字段名从 notes 调整为 description,将部分前端方法名前缀从 query 调整为 get,以及去除部分冗余代码

This commit is contained in:
Charles7c 2023-01-23 19:00:47 +08:00
parent 6bd6d1eb39
commit bdf8eeb1b4
40 changed files with 820 additions and 42 deletions

View File

@ -197,6 +197,7 @@ continew-admin # 全局通用项目配置及依赖版本管理
│ │ ├─ mapper # 系统管理相关 Mapper
│ │ ├─ model # 系统管理相关模型
│ │ │ ├─ entity # 系统管理相关实体对象
│ │ │ ├─ query # 系统管理相关查询条件
│ │ │ ├─ request # 系统管理相关请求对象
│ │ │ └─ vo # 系统管理相关 VOView Object
│ │ └─ service # 系统管理相关业务接口及实现类
@ -268,6 +269,7 @@ continew-admin
│ │ │ │ └─ system # 系统日志
│ │ │ └─ online # 在线用户
│ │ └─ system # 系统管理模块
│ │ ├─ dept # 部门管理
│ │ └─ user # 用户模块
│ │ └─ center # 个人中心
│ ├─ App.vue # 视图入口

View File

@ -70,9 +70,9 @@ public class LoginUser implements Serializable {
private String avatar;
/**
* 备注
* 描述
*/
private String notes;
private String description;
/**
* 最后一次修改密码的时间

View File

@ -46,7 +46,7 @@ public class LoginLogQuery implements Serializable {
* 登录状态1成功 2失败
*/
@Schema(description = "登录状态1成功 2失败")
@Query(type = Query.Type.EQUAL)
@Query
private Integer status;
/**

View File

@ -62,7 +62,7 @@ public class OperationLogQuery implements Serializable {
* 操作状态1成功 2失败
*/
@Schema(description = "操作状态1成功 2失败")
@Query(type = Type.EQUAL)
@Query
private Integer status;
/**

View File

@ -87,10 +87,10 @@ public class UserInfoVO implements Serializable {
private String avatar;
/**
* 备注
* 描述
*/
@Schema(description = "备注")
private String notes;
@Schema(description = "描述")
private String description;
/**
* 最后一次修改密码的时间

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.charles7c.cnadmin.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import top.charles7c.cnadmin.system.model.entity.SysDept;
/**
* 部门 Mapper
*
* @author Charles7c
* @since 2023/1/22 17:56
*/
public interface DeptMapper extends BaseMapper<SysDept> {}

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.charles7c.cnadmin.system.model.entity;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import top.charles7c.cnadmin.common.enums.DisEnableStatusEnum;
import top.charles7c.cnadmin.common.model.entity.BaseEntity;
/**
* 部门实体
*
* @author Charles7c
* @since 2023/1/22 13:50
*/
@Data
@TableName("sys_dept")
public class SysDept extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 部门 ID
*/
@TableId
private Long deptId;
/**
* 部门名称
*/
private String deptName;
/**
* 上级部门 ID
*/
private Long parentId;
/**
* 部门排序
*/
private Integer deptSort;
/**
* 描述
*/
private String description;
/**
* 状态1启用 2禁用
*/
private DisEnableStatusEnum status;
}

View File

@ -81,9 +81,9 @@ public class SysUser extends BaseEntity {
private String avatar;
/**
* 备注
* 描述
*/
private String notes;
private String description;
/**
* 状态1启用 2禁用

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.charles7c.cnadmin.system.model.query;
import java.io.Serializable;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springdoc.api.annotations.ParameterObject;
import top.charles7c.cnadmin.common.annotation.Query;
/**
* 部门查询条件
*
* @author Charles7c
* @since 2023/1/22 17:52
*/
@Data
@ParameterObject
@Schema(description = "部门查询条件")
public class DeptQuery implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 部门名称
*/
@Schema(description = "部门名称")
@Query(type = Query.Type.INNER_LIKE)
private String deptName;
/**
* 状态1启用 2禁用
*/
@Schema(description = "状态1启用 2禁用")
@Query
private Integer status;
}

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.charles7c.cnadmin.system.model.vo;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import lombok.Data;
import lombok.experimental.Accessors;
import io.swagger.v3.oas.annotations.media.Schema;
import com.fasterxml.jackson.annotation.JsonIgnore;
import top.charles7c.cnadmin.common.enums.DisEnableStatusEnum;
/**
* 部门信息
*
* @author Charles7c
* @since 2023/1/22 13:53
*/
@Data
@Accessors(chain = true)
@Schema(description = "部门信息")
public class DeptVO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 部门 ID
*/
@Schema(description = "部门 ID")
private Long deptId;
/**
* 部门名称
*/
@Schema(description = "部门名称")
private String deptName;
/**
* 上级部门 ID
*/
@Schema(description = "上级部门 ID")
private Long parentId;
/**
* 部门排序
*/
@Schema(description = "部门排序")
private Integer deptSort;
/**
* 描述
*/
@Schema(description = "描述")
private String description;
/**
* 状态1启用 2禁用
*/
@Schema(description = "状态1启用 2禁用")
private DisEnableStatusEnum status;
/**
* 修改人
*/
@JsonIgnore
private Long updateUser;
/**
* 修改人昵称
*/
@Schema(description = "修改人昵称")
private String updateUserString;
/**
* 修改时间
*/
@Schema(description = "修改时间")
private LocalDateTime updateTime;
/**
* 子部门列表
*/
@Schema(description = "子部门列表")
private List<DeptVO> children;
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.charles7c.cnadmin.system.service;
import java.util.List;
import top.charles7c.cnadmin.system.model.query.DeptQuery;
import top.charles7c.cnadmin.system.model.vo.DeptVO;
/**
* 部门业务接口
*
* @author Charles7c
* @since 2023/1/22 17:54
*/
public interface DeptService {
/**
* 查询列表
*
* @param query
* 查询条件
* @return 列表数据
*/
List<DeptVO> list(DeptQuery query);
}

View File

@ -0,0 +1,137 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.charles7c.cnadmin.system.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import top.charles7c.cnadmin.common.util.ExceptionUtils;
import top.charles7c.cnadmin.common.util.helper.QueryHelper;
import top.charles7c.cnadmin.system.mapper.DeptMapper;
import top.charles7c.cnadmin.system.model.entity.SysDept;
import top.charles7c.cnadmin.system.model.query.DeptQuery;
import top.charles7c.cnadmin.system.model.vo.DeptVO;
import top.charles7c.cnadmin.system.service.DeptService;
import top.charles7c.cnadmin.system.service.UserService;
/**
* 部门业务实现类
*
* @author Charles7c
* @since 2023/1/22 17:55
*/
@Service
@RequiredArgsConstructor
public class DeptServiceImpl implements DeptService {
private final DeptMapper deptMapper;
private final UserService userService;
@Override
public List<DeptVO> list(DeptQuery query) {
QueryWrapper<SysDept> queryWrapper = QueryHelper.build(query);
queryWrapper.lambda().orderByAsc(SysDept::getParentId).orderByAsc(SysDept::getDeptSort)
.orderByDesc(SysDept::getUpdateTime);
List<SysDept> list = deptMapper.selectList(queryWrapper);
List<DeptVO> voList = BeanUtil.copyToList(list, DeptVO.class);
voList.forEach(this::fill);
return buildTree(voList);
}
/**
* 填充数据
*
* @param vo
* VO
*/
private void fill(DeptVO vo) {
Long updateUser = vo.getUpdateUser();
if (updateUser == null) {
return;
}
vo.setUpdateUserString(ExceptionUtils.exToNull(() -> userService.getById(vo.getUpdateUser())).getNickname());
}
/**
* 构建树
*
* @param list
* 原始列表数据
* @return 树列表
*/
private List<DeptVO> buildTree(List<DeptVO> list) {
if (CollUtil.isEmpty(list)) {
return new ArrayList<>();
}
// 去重
List<DeptVO> deDuplicationDeptList = deDuplication(list);
return deDuplicationDeptList.stream().map(d -> d.setChildren(this.getChildren(d, list)))
.collect(Collectors.toList());
}
/**
* 数据去重去除重复子部门列表
*
* @param list
* 部门列表
* @return 去重后部门列表
*/
private List<DeptVO> deDuplication(List<DeptVO> list) {
List<DeptVO> deptList = new ArrayList<>();
for (DeptVO outerDept : list) {
boolean flag = true;
for (DeptVO innerDept : list) {
// 忽略重复子列表
if (innerDept.getDeptId().equals(outerDept.getParentId())) {
flag = false;
break;
}
}
if (flag) {
deptList.add(outerDept);
}
}
return deptList;
}
/**
* 获取指定部门的子部门列表
*
* @param dept
* 指定部门
* @param list
* 部门列表
* @return 子部门列表
*/
private List<DeptVO> getChildren(DeptVO dept, List<DeptVO> list) {
return list.stream().filter(d -> Objects.equals(d.getParentId(), dept.getDeptId()))
.map(d -> d.setChildren(this.getChildren(d, list))).collect(Collectors.toList());
}
}

View File

@ -24,6 +24,7 @@ declare module '@vue/runtime-core' {
ACol: typeof import('@arco-design/web-vue')['Col']
AConfigProvider: typeof import('@arco-design/web-vue')['ConfigProvider']
ADescriptions: typeof import('@arco-design/web-vue')['Descriptions']
ADescriptionsItem: typeof import('@arco-design/web-vue')['DescriptionsItem']
ADivider: typeof import('@arco-design/web-vue')['Divider']
ADoption: typeof import('@arco-design/web-vue')['Doption']
ADrawer: typeof import('@arco-design/web-vue')['Drawer']
@ -46,6 +47,7 @@ declare module '@vue/runtime-core' {
AListItemMeta: typeof import('@arco-design/web-vue')['ListItemMeta']
AMenu: typeof import('@arco-design/web-vue')['Menu']
AMenuItem: typeof import('@arco-design/web-vue')['MenuItem']
AModal: typeof import('@arco-design/web-vue')['Modal']
AOption: typeof import('@arco-design/web-vue')['Option']
APopover: typeof import('@arco-design/web-vue')['Popover']
ARadio: typeof import('@arco-design/web-vue')['Radio']

View File

@ -47,7 +47,7 @@ export interface LoginLogListRes {
list: LoginLogRecord[];
total: number;
}
export function queryLoginLogList(params: LoginLogParams) {
export function getLoginLogList(params: LoginLogParams) {
return axios.get<LoginLogListRes>('/monitor/log/login', {
params,
paramsSerializer: (obj) => {
@ -66,7 +66,7 @@ export interface OperationLogListRes {
list: OperationLogRecord[];
total: number;
}
export function queryOperationLogList(params: OperationLogParams) {
export function getOperationLogList(params: OperationLogParams) {
return axios.get<OperationLogListRes>('/monitor/log/operation', {
params,
paramsSerializer: (obj) => {
@ -85,7 +85,7 @@ export interface SystemLogListRes {
list: SystemLogRecord[];
total: number;
}
export function querySystemLogList(params: SystemLogParams) {
export function getSystemLogList(params: SystemLogParams) {
return axios.get<SystemLogListRes>('/monitor/log/system', {
params,
paramsSerializer: (obj) => {
@ -94,6 +94,6 @@ export function querySystemLogList(params: SystemLogParams) {
});
}
export function querySystemLogDetail(logId: string) {
export function getSystemLogDetail(logId: string) {
return axios.get<SystemLogDetailRecord>(`/monitor/log/system/${logId}`);
}

View File

@ -21,7 +21,7 @@ export interface OnlineUserListRes {
total: number;
}
export function queryOnlineUserList(params: OnlineUserParams) {
export function getOnlineUserList(params: OnlineUserParams) {
return axios.get<OnlineUserListRes>('/monitor/online/user', {
params,
paramsSerializer: (obj) => {

View File

@ -0,0 +1,30 @@
import axios from 'axios';
import qs from 'query-string';
export interface DeptRecord {
deptId: string;
deptName: string;
parentId: string;
deptSort: number;
description: string;
status: number;
updateUserString: string;
updateTime: string;
children: Array<DeptRecord>,
}
export interface DeptParams extends Partial<DeptRecord> {
page: number;
size: number;
sort: Array<string>;
}
export function getDeptList(params: DeptParams) {
return axios.get<DeptRecord[]>('/system/dept', {
params,
paramsSerializer: (obj) => {
return qs.stringify(obj);
},
});
}

View File

@ -8,6 +8,8 @@ import localeMonitor from '@/views/dashboard/monitor/locale/en-US';
import localeDataAnalysis from '@/views/visualization/data-analysis/locale/en-US';
import localeMultiDAnalysis from '@/views/visualization/multi-dimension-data-analysis/locale/en-US';
import localeDept from '@/views/system/dept/locale/en-US';
import localeOnlineUser from '@/views/monitor/online/locale/en-US';
import localeLoginLog from '@/views/monitor/log/login/locale/en-US';
import localeOperationLog from '@/views/monitor/log/operation/locale/en-US';
@ -39,6 +41,7 @@ export default {
'menu.server.workplace': 'Workplace-Server',
'menu.server.monitor': 'Monitor-Server',
'menu.visualization': 'Data Visualization',
'menu.system': 'System management',
'menu.monitor': 'Monitor',
'menu.list': 'List',
'menu.form': 'Form',
@ -58,6 +61,8 @@ export default {
...localeDataAnalysis,
...localeMultiDAnalysis,
...localeDept,
...localeOnlineUser,
...localeLoginLog,
...localeOperationLog,

View File

@ -8,6 +8,8 @@ import localeMonitor from '@/views/dashboard/monitor/locale/zh-CN';
import localeDataAnalysis from '@/views/visualization/data-analysis/locale/zh-CN';
import localeMultiDAnalysis from '@/views/visualization/multi-dimension-data-analysis/locale/zh-CN';
import localeDept from '@/views/system/dept/locale/zh-CN';
import localeOnlineUser from '@/views/monitor/online/locale/zh-CN';
import localeLoginLog from '@/views/monitor/log/login/locale/zh-CN';
import localeOperationLog from '@/views/monitor/log/operation/locale/zh-CN';
@ -39,6 +41,7 @@ export default {
'menu.server.workplace': '工作台-服务端',
'menu.server.monitor': '实时监控-服务端',
'menu.visualization': '数据可视化',
'menu.system': '系统管理',
'menu.monitor': '系统监控',
'menu.list': '列表页',
'menu.form': '表单页',
@ -58,6 +61,8 @@ export default {
...localeDataAnalysis,
...localeMultiDAnalysis,
...localeDept,
...localeOnlineUser,
...localeLoginLog,
...localeOperationLog,

View File

@ -9,7 +9,7 @@ const EXCEPTION: AppRouteRecordRaw = {
locale: 'menu.exception',
requiresAuth: true,
icon: 'icon-exclamation-circle',
order: 7,
order: 8,
},
children: [
{

View File

@ -9,7 +9,7 @@ const FORM: AppRouteRecordRaw = {
locale: 'menu.form',
icon: 'icon-settings',
requiresAuth: true,
order: 4,
order: 5,
},
children: [
{

View File

@ -9,7 +9,7 @@ const LIST: AppRouteRecordRaw = {
locale: 'menu.list',
requiresAuth: true,
icon: 'icon-list',
order: 3,
order: 4,
},
children: [
{

View File

@ -9,7 +9,7 @@ const Monitor: AppRouteRecordRaw = {
locale: 'menu.monitor',
requiresAuth: true,
icon: 'icon-computer',
order: 2,
order: 3,
},
children: [
{

View File

@ -9,7 +9,7 @@ const PROFILE: AppRouteRecordRaw = {
locale: 'menu.profile',
requiresAuth: true,
icon: 'icon-file',
order: 5,
order: 6,
},
children: [
{

View File

@ -9,7 +9,7 @@ const RESULT: AppRouteRecordRaw = {
locale: 'menu.result',
icon: 'icon-check-circle',
requiresAuth: true,
order: 6,
order: 7,
},
children: [
{

View File

@ -0,0 +1,28 @@
import { DEFAULT_LAYOUT } from '../base';
import { AppRouteRecordRaw } from '../types';
const System: AppRouteRecordRaw = {
path: '/system',
name: 'system',
component: DEFAULT_LAYOUT,
meta: {
locale: 'menu.system',
requiresAuth: true,
icon: 'icon-settings',
order: 2,
},
children: [
{
path: '/system/dept',
name: 'Dept',
component: () => import('@/views/system/dept/index.vue'),
meta: {
locale: 'menu.system.dept.list',
requiresAuth: true,
roles: ['*'],
},
},
],
};
export default System;

View File

@ -9,7 +9,7 @@ const USER: AppRouteRecordRaw = {
locale: 'menu.user',
icon: 'icon-user',
requiresAuth: true,
order: 8,
order: 9,
},
children: [
{

View File

@ -20,7 +20,7 @@ const useLoginStore = defineStore('user', {
phone: undefined,
email: '',
avatar: undefined,
notes: undefined,
description: undefined,
pwdResetTime: undefined,
registrationDate: undefined,

View File

@ -7,7 +7,7 @@ export interface UserState {
phone?: string;
email: string;
avatar?: string;
notes?: string;
description?: string;
pwdResetTime?: string;
registrationDate?: string;

View File

@ -71,7 +71,7 @@
<script lang="ts" setup>
import { computed, ref, reactive } from 'vue';
import useLoading from '@/hooks/loading';
import { queryLoginLogList, LoginLogRecord, LoginLogParams } from '@/api/monitor/log';
import { getLoginLogList, LoginLogRecord, LoginLogParams } from '@/api/monitor/log';
import { Pagination } from '@/types/global';
import { PaginationProps } from '@arco-design/web-vue';
import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
@ -171,7 +171,7 @@
) => {
setLoading(true);
try {
const { data } = await queryLoginLogList(params);
const { data } = await getLoginLogList(params);
renderData.value = data.list;
pagination.current = params.page;
pagination.total = data.total;

View File

@ -80,7 +80,7 @@
<script lang="ts" setup>
import { computed, ref, reactive } from 'vue';
import useLoading from '@/hooks/loading';
import { queryOperationLogList, OperationLogRecord, OperationLogParams } from '@/api/monitor/log';
import { getOperationLogList, OperationLogRecord, OperationLogParams } from '@/api/monitor/log';
import { Pagination } from '@/types/global';
import { PaginationProps } from '@arco-design/web-vue';
import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
@ -181,7 +181,7 @@
) => {
setLoading(true);
try {
const { data } = await queryOperationLogList(params);
const { data } = await getOperationLogList(params);
renderData.value = data.list;
pagination.current = params.page;
pagination.total = data.total;

View File

@ -227,9 +227,9 @@
import { computed, ref, reactive } from 'vue';
import useLoading from '@/hooks/loading';
import {
querySystemLogDetail,
getSystemLogDetail,
SystemLogDetailRecord,
querySystemLogList,
getSystemLogList,
SystemLogRecord,
SystemLogParams,
} from '@/api/monitor/log';
@ -352,7 +352,7 @@
) => {
setLoading(true);
try {
const { data } = await querySystemLogList(params);
const { data } = await getSystemLogList(params);
renderData.value = data.list;
pagination.current = params.page;
pagination.total = data.total;
@ -373,7 +373,7 @@
visible.value = true;
detailLoading.value = true;
try {
const { data } = await querySystemLogDetail(logId);
const { data } = await getSystemLogDetail(logId);
renderDetailData.value = data;
} finally {
detailLoading.value = false;

View File

@ -71,7 +71,7 @@
import { computed, ref, reactive } from 'vue';
import useLoading from '@/hooks/loading';
import { Message } from '@arco-design/web-vue';
import { queryOnlineUserList, OnlineUserRecord, OnlineUserParams, kickout } from '@/api/monitor/online';
import { getOnlineUserList, OnlineUserRecord, OnlineUserParams, kickout } from '@/api/monitor/online';
import { Pagination } from '@/types/global';
import { PaginationProps } from '@arco-design/web-vue';
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
@ -83,7 +83,6 @@
const queryFormRef = ref<FormInstance>();
const queryFormData = ref({
nickname: '',
status: undefined,
loginTime: [],
});
@ -159,7 +158,7 @@
) => {
setLoading(true);
try {
const { data } = await queryOnlineUserList(params);
const { data } = await getOnlineUserList(params);
renderData.value = data.list;
pagination.current = params.page;
pagination.total = data.total;

View File

@ -0,0 +1,182 @@
<template>
<div class="container">
<Breadcrumb :items="['menu.system', 'menu.system.dept.list']" />
<a-card class="general-card">
<a-row :gutter="20">
<a-col>
<!-- 工具栏 -->
<div class="head-container">
<a-form ref="queryFormRef" :model="queryFormData" layout="inline">
<a-form-item field="deptName" hide-label>
<a-input
v-model="queryFormData.deptName"
placeholder="输入部门名称搜索"
allow-clear
style="width: 150px;"
@press-enter="toQuery"
/>
</a-form-item>
<a-form-item field="status" hide-label>
<a-select
v-model="queryFormData.status"
:options="statusOptions"
placeholder="状态搜索"
allow-clear
style="width: 150px;"
/>
</a-form-item>
<a-button type="primary" @click="toQuery">
<template #icon>
<icon-search />
</template>
查询
</a-button>
<a-button @click="resetQuery">
<template #icon>
<icon-refresh />
</template>
重置
</a-button>
</a-form>
</div>
<!-- 表格渲染 -->
<a-table
:columns="columns"
:data="renderData"
:pagination="false"
:default-expand-all-rows="true"
:hide-expand-button-on-empty="true"
ref="tableRef"
row-key="deptId"
:bordered="false"
:stripe="true"
:loading="loading"
size="large"
>
<template #status="{ record }">
<a-switch v-model="record.status" :checked-value="1" :unchecked-value="2" />
</template>
</a-table>
</a-col>
</a-row>
</a-card>
</div>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';
import useLoading from '@/hooks/loading';
import { Message, TableInstance } from '@arco-design/web-vue';
import { getDeptList, DeptRecord, DeptParams } from '@/api/system/dept';
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
import { FormInstance } from '@arco-design/web-vue/es/form';
import { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
const { loading, setLoading } = useLoading(true);
const tableRef = ref<TableInstance>();
const queryFormRef = ref<FormInstance>();
const queryFormData = ref({
deptName: '',
status: undefined,
});
const statusOptions = computed<SelectOptionData[]>(() => [
{
label: '启用',
value: 1,
},
{
label: '禁用',
value: 2,
},
]);
//
const toQuery = () => {
fetchData({
...queryFormData.value,
} as unknown as DeptParams);
};
//
const resetQuery = async () => {
await queryFormRef.value?.resetFields();
await fetchData();
};
const renderData = ref<DeptRecord[]>([]);
const columns = computed<TableColumnData[]>(() => [
{
title: '部门名称',
dataIndex: 'deptName',
},
{
title: '部门排序',
dataIndex: 'deptSort',
align: 'center',
},
{
title: '状态',
dataIndex: 'status',
slotName: 'status',
align: 'center',
},
{
title: '描述',
dataIndex: 'description',
},
{
title: '修改人',
dataIndex: 'updateUserString',
},
{
title: '修改时间',
dataIndex: 'updateTime',
},
]);
//
const fetchData = async (
params: DeptParams = { page: 1, size: 10, sort: ['parentId,asc', 'deptSort,asc', 'createTime,desc'] }
) => {
setLoading(true);
try {
const { data } = await getDeptList(params);
renderData.value = data;
} finally {
setLoading(false);
}
setTimeout(function() {
tableRef.value?.expandAll();
}, 0);
};
fetchData();
</script>
<script lang="ts">
export default {
name: 'Dept',
};
</script>
<style scoped lang="less">
.container {
padding: 0 20px 20px 20px;
}
.general-card {
padding-top: 25px;
}
.head-container {
margin-bottom: 15px;
}
:deep(.arco-table-th) {
&:last-child {
.arco-table-th-item-title {
margin-left: 16px;
}
}
}
</style>

View File

@ -0,0 +1,3 @@
export default {
'menu.system.dept.list': 'Department management',
};

View File

@ -0,0 +1,3 @@
export default {
'menu.system.dept.list': '部门管理',
};

View File

@ -46,7 +46,7 @@
import { computed, ref, reactive } from 'vue';
import useLoading from '@/hooks/loading';
import { useLoginStore } from '@/store';
import { queryOperationLogList, OperationLogRecord, OperationLogParams } from '@/api/monitor/log';
import { getOperationLogList, OperationLogRecord, OperationLogParams } from '@/api/monitor/log';
import { Pagination } from '@/types/global';
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
import { PaginationProps } from "@arco-design/web-vue";
@ -109,7 +109,7 @@
) => {
setLoading(true);
try {
const { data } = await queryOperationLogList(params);
const { data } = await getOperationLogList(params);
renderData.value = data.list;
pagination.current = params.page;
pagination.total = data.total;

View File

@ -171,7 +171,7 @@
captchaBtnNameKey.value = t('userCenter.securitySettings.updateEmail.form.reSendCaptcha');
captchaDisable.value = false;
}
}, 1000)
}, 1000);
}
} catch (err) {
resetCaptcha();

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.charles7c.cnadmin.webapi.controller.system;
import java.util.List;
import lombok.RequiredArgsConstructor;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.charles7c.cnadmin.common.model.vo.R;
import top.charles7c.cnadmin.system.model.query.DeptQuery;
import top.charles7c.cnadmin.system.model.vo.DeptVO;
import top.charles7c.cnadmin.system.service.DeptService;
/**
* 部门管理 API
*
* @author Charles7c
* @since 2023/1/22 17:50
*/
@Tag(name = "部门管理 API")
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/system/dept", produces = MediaType.APPLICATION_JSON_VALUE)
public class DeptController {
private final DeptService deptService;
@Operation(summary = "查询部门列表")
@GetMapping
public R<List<DeptVO>> list(@Validated DeptQuery query) {
List<DeptVO> list = deptService.list(query);
return R.ok(list);
}
}

View File

@ -1,6 +1,16 @@
-- liquibase formatted sql
-- changeset Charles7c:1
-- 初始化默认用户admin/123456test/123456
-- 初始化默认部门
INSERT IGNORE INTO `sys_dept` VALUES (1, 'Xxx科技有限公司', 0, 1, NULL, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (2, '天津总部', 1, 1, NULL, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (3, '研发部', 2, 1, NULL, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (4, 'UI部', 2, 2, NULL, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (5, '测试部', 2, 3, NULL, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (6, '运维部', 2, 4, NULL, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (7, '研发一组', 3, 1, NULL, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (8, '研发二组', 3, 2, NULL, 2, 1, NOW(), 1, NOW());
-- 初始化默认用户admin/admin123test/123456
INSERT IGNORE INTO `sys_user` VALUES (1, 'admin', '超级管理员', '9802815bcc5baae7feb1ae0d0566baf2', 1, '18888888888', 'charles7c@126.com', NULL, NULL, 1, NOW(), 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_user` VALUES (2, 'test', '测试员', '8e114197e1b33783a00542ad67e80516', 0, NULL, NULL, NULL, NULL, 2, NOW(), 1, NOW(), 1, NOW());

View File

@ -1,6 +1,23 @@
-- liquibase formatted sql
-- changeset Charles7c:1
CREATE TABLE IF NOT EXISTS `sys_dept` (
`dept_id` bigint(20) unsigned AUTO_INCREMENT COMMENT '部门ID',
`dept_name` varchar(255) NOT NULL COMMENT '部门名称',
`parent_id` bigint(20) unsigned DEFAULT 0 COMMENT '上级部门ID',
`dept_sort` int(11) unsigned DEFAULT 999 COMMENT '部门排序',
`description` varchar(512) DEFAULT NULL COMMENT '描述',
`status` tinyint(1) unsigned DEFAULT 1 COMMENT '状态1启用 2禁用',
`create_user` bigint(20) unsigned NOT NULL COMMENT '创建人',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_user` bigint(20) unsigned NOT NULL COMMENT '修改人',
`update_time` datetime NOT NULL COMMENT '修改时间',
PRIMARY KEY (`dept_id`) USING BTREE,
INDEX `idx_parent_id`(`parent_id`) USING BTREE,
INDEX `idx_create_user`(`create_user`) USING BTREE,
INDEX `idx_update_user`(`update_user`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='部门表';
CREATE TABLE IF NOT EXISTS `sys_user` (
`user_id` bigint(20) unsigned AUTO_INCREMENT COMMENT '用户ID',
`username` varchar(255) NOT NULL COMMENT '用户名',
@ -10,7 +27,7 @@ CREATE TABLE IF NOT EXISTS `sys_user` (
`phone` varchar(255) DEFAULT NULL COMMENT '手机号码',
`email` varchar(255) DEFAULT NULL COMMENT '邮箱',
`avatar` varchar(255) DEFAULT NULL COMMENT '头像地址',
`notes` varchar(512) DEFAULT NULL COMMENT '备注',
`description` varchar(512) DEFAULT NULL COMMENT '描述',
`status` tinyint(1) unsigned DEFAULT 1 COMMENT '状态1启用 2禁用',
`pwd_reset_time` datetime DEFAULT NULL COMMENT '最后一次修改密码的时间',
`create_user` bigint(20) unsigned NOT NULL COMMENT '创建人',
@ -20,8 +37,8 @@ CREATE TABLE IF NOT EXISTS `sys_user` (
PRIMARY KEY (`user_id`) USING BTREE,
UNIQUE INDEX `uk_username`(`username`) USING BTREE,
UNIQUE INDEX `uk_email`(`email`) USING BTREE,
INDEX `idx_createUser`(`create_user`) USING BTREE,
INDEX `idx_updateUser`(`update_user`) USING BTREE
INDEX `idx_create_user`(`create_user`) USING BTREE,
INDEX `idx_update_user`(`update_user`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
CREATE TABLE IF NOT EXISTS `sys_log` (