23 Commits

Author SHA1 Message Date
ae3a01fb7b revert: 回退全局响应结果处理器(遗漏项) 2024-01-26 22:21:10 +08:00
5ee430cbfa docs: 完善 README 文档 2023-12-03 00:13:44 +08:00
1fc76a4123 refactor: 优化部分注解使用 2023-11-30 22:14:19 +08:00
2146605a86 revert: 回退全局响应结果处理器
1.影响 API 文档生成
2.其他已知及未知影响
2023-11-30 22:09:44 +08:00
cde515b186 !8 回退全局响应结果处理器
Merge pull request !8 from Yoofff/1.3.x
2023-11-30 14:05:50 +00:00
Bull-BCLS
d668620bfe refactor: 回退全局响应结果处理器
1.影响 API 文档生成
2.其他已知及未知影响
2023-11-29 23:34:00 +08:00
27d401f44b docs: 完善 README 文档 2023-11-20 20:12:06 +08:00
a8aa9f28f6 chore: 移除 XML 文件头部的协议信息 2023-11-19 18:15:48 +08:00
2930619964 chore: 新增 idea 图标 2023-11-19 18:13:37 +08:00
11b3b87337 fix: 修复保存生成配置校验失效的问题,并优化部分提示效果 2023-11-16 21:18:01 +08:00
0eddbfb978 refactor: 优化菜单标题校验 2023-11-16 21:13:10 +08:00
adf6d900f3 chore: 更新版本号 2023-11-16 21:12:59 +08:00
3f8f4e2bf4 release: v1.3.1 2023-11-15 21:12:04 +08:00
3fcdb54442 fix: sms4j 3.0.3 => 3.0.4
修复发送容联云短信错误
2023-11-15 20:57:04 +08:00
5d159c6ab3 fix: 发送消息增加事务处理 2023-11-15 20:55:27 +08:00
39969ebf61 chore: 完善 Redis 部署配置 2023-11-12 00:21:04 +08:00
47a5746794 fix: 修复仪表盘访问趋势区块 y 轴数值过大时无法展示的问题
增加 y 轴单位转换逻辑
2023-11-11 00:09:18 +08:00
8820c1dfc8 refactor: 优化 401 状态处理逻辑
1.退出接口增加登录校验
2.前端获取用户信息失败,自动清理客户端信息并跳转回登录页
2023-11-07 19:53:29 +08:00
712eedba1b refactor: 优化超时登录处理逻辑 2023-11-06 22:12:27 +08:00
47a8160d70 fix: 修复控制台报错 Please use theme before using plugins
1.由 v-md-editor 使用方式不佳引起
2023-11-05 23:23:54 +08:00
b63d7d725d fix: 修复 Swagger 分组接口缺失 2023-11-05 21:11:34 +08:00
f15494d348 style: 优化部分变量命名 2023-11-05 17:36:41 +08:00
91ea4ed685 chore: 更新版本号 2023-11-05 17:30:23 +08:00
42 changed files with 200 additions and 355 deletions

1
.gitignore vendored
View File

@@ -15,6 +15,7 @@ target/
### IntelliJ IDEA ###
.idea
!.idea/icon.png
*.iws
*.iml
*.ipr

BIN
.idea/icon.png generated Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -1,3 +1,20 @@
## [v1.3.1](https://github.com/Charles7c/continew-admin/compare/v1.3.0...v1.3.1) (2023-11-15)
### 💎 功能优化
- 完善 Redis 部署配置 ([39969eb](https://github.com/Charles7c/continew-admin/commit/39969ebf6173fc379dc3501e9204a344d1cf62cf))
- 优化 401 状态处理逻辑 ([8820c1d](https://github.com/Charles7c/continew-admin/commit/8820c1dfc858b9ef9df470e90dfe9ba4b1166e29))
- 优化超时登录处理逻辑 ([712eedb](https://github.com/Charles7c/continew-admin/commit/712eedba1be0ec371119745d4596cd35c2ce25d6))
- 优化部分变量命名 ([f15494d](https://github.com/Charles7c/continew-admin/commit/f15494d34823ded87efc396d98e2eb0108f74a3d))
### 🐛 问题修复
- sms4j 3.0.3 => 3.0.4 ([3fcdb54](https://github.com/Charles7c/continew-admin/commit/3fcdb54442b380e76838478fa46e8dfb70a2759b))
- 发送消息增加事务处理 ([5d159c6](https://github.com/Charles7c/continew-admin/commit/5d159c6ab337a9432419d84cf246cff506500567))
- 修复仪表盘访问趋势区块 y 轴数值过大时无法展示的问题 ([47a5746](https://github.com/Charles7c/continew-admin/commit/47a5746794e552faf9c41fbcc21af091a878eb95))
- 修复控制台报错 Please use theme before using plugins ([47a8160](https://github.com/Charles7c/continew-admin/commit/47a8160d70862a5ee7284c165004cece2714a10f))
- 修复 Swagger 分组接口缺失 ([b63d7d7](https://github.com/Charles7c/continew-admin/commit/b63d7d725da5e9e9b2db9fd59bd140d64b50040c))
## [v1.3.0](https://github.com/Charles7c/continew-admin/compare/v1.2.0...v1.3.0) (2023-11-04)
### ✨ 新特性

View File

@@ -4,7 +4,7 @@
<img src="https://img.shields.io/badge/License-Apache--2.0-blue.svg" alt="License" />
</a>
<a href="https://github.com/Charles7c/continew-admin" target="_blank">
<img src="https://img.shields.io/badge/RELEASE-v1.3.0-%23ff3f59.svg" alt="Release" />
<img src="https://img.shields.io/badge/SNAPSHOT-v1.3.2-%23ff3f59.svg" alt="Release" />
</a>
<a href="https://github.com/Charles7c/continew-admin" target="_blank">
<img src="https://img.shields.io/github/stars/Charles7c/continew-admin?style=social" alt="GitHub stars" />
@@ -18,12 +18,14 @@
<a href="https://gitee.com/Charles7c/continew-admin" target="_blank">
<img src="https://gitee.com/Charles7c/continew-admin/badge/fork.svg?theme=white" alt="Gitee forks" />
</a>
<img src="https://img.shields.io/badge/Spring Boot-2.7.16-%236CB52D.svg" alt="Release" />
<img src="https://img.shields.io/badge/Java-8-%236CB52D.svg" alt="Release" />
📚 [在线文档](https://doc.charles7c.top) | ✨ [提交需求](https://doc.charles7c.top/require.html) | 🚀 [演示地址](https://cnadmin.charles7c.top)(账号/密码admin/admin123
## 简介
ContiNew Admin Continue New Admin中后台管理框架/脚手架持续以最新流行技术栈构建拥抱变化迭代优化。在社区贡献者的支持和参与下持续发展并源源不断地为企业级项目开发提供助力。当前采用的技术栈Vue3、Spring Boot3、TypeScript、Arco Design Vue、Undertow、Sa-Token、JWT、MariaDB、MyBatis Plus、Redis、Redisson、Easy Excel、Hutool 等。
ContiNew Admin Continue New Admin中后台管理框架/脚手架持续以最新流行技术栈构建拥抱变化迭代优化。在社区贡献者的支持和参与下持续发展并源源不断地为企业级项目开发提供助力。当前采用的技术栈Vue3、**Spring Boot 2.7.xJDK8** 、TypeScript、Arco Design Vue、Undertow、Sa-Token、JWT、MariaDB、MyBatis Plus、Redis、Redisson、Easy Excel、Hutool 等。
## 项目源码
@@ -32,30 +34,9 @@ ContiNew Admin Continue New Admin中后台管理框架/脚手架,持续
| GitHub | https://github.com/Charles7c/continew-admin |
| Gitee码云 | https://gitee.com/Charles7c/continew-admin |
<img src="https://repobeats.axiom.co/api/embed/be43df158b86ce201cd2b7e0e6c8a85740149b7e.svg" alt="Alt" title="Repobeats github analytics image" />
## 反馈交流
💬 欢迎各位小伙伴儿扫描下方二维码加好友,备注 `cnadmin`,拉你进群,探讨技术、提提需求~
加入交流群后,你将会:
- 第一时间收到框架动态
- 第一时间收到框架更新通知
- 第一时间收到框架 Bug 通知
- 和众多大佬互相 (huá shuǐ) 交流 (mō yú)
<div align="left">
<img src=".image/qrcode.jpg" alt="二维码" width="230px" />
</div>
<details>
<summary>无加群意愿</summary>
💬 如无加群意愿,欢迎在 <a href="https://github.com/Charles7c/continew-admin/discussions" target="_blank">Discussions</a> 中进行交流探讨~ 🍻
</details>
## 主要特性
- :fire: 在 2.x 及以上版本中,下方部分通用基础能力及配置,已抽取到 [ContiNew Starter](https://github.com/Charles7c/continew-starter) 项目,现已发布到 Maven 中央仓库,为 Spring Boot Web 项目开发提供更灵活的助力
- 精选技术栈:使用综合考虑成熟度、流行性、发展潜力较佳的技术栈,包括 Spring Boot、MyBatis Plus、Sa-Token、Hutool 等
- 高效率开发:后端提供了 CRUD 组件,在 Controller 中只需添加一个注解,即可自动生成增、删、改、查、分页、列表、树列表等 API
- 提供代码生成功能,根据用户提供的项目信息和配置,自动生成前后端项目结构、代码文件和部分逻辑代码,提高开发效率
@@ -222,8 +203,8 @@ pnpm dev
## 核心技术栈
| 名称 | 版本 | 简介 |
| :----------------------------------------------------------- | :----------- | :----------------------------------------------------------- |
| 名称 | 版本 | 简介 |
| :----------------------------------------------------------- |:-------------| :----------------------------------------------------------- |
| <a href="https://cn.vuejs.org/" target="_blank">Vue</a> | 3.3.4 | 渐进式 JavaScript 框架,易学易用,性能出色,适用场景丰富的 Web 前端框架。 |
| <a href="https://www.typescriptlang.org/zh/" target="_blank">TypeScript</a> | 4.9.5 | TypeScript 是微软开发的一个开源的编程语言,通过在 JavaScript 的基础上添加静态类型定义构建而成。 |
| <a href="https://arco.design/vue/docs/start" target="_blank">Arco Design Vue</a> | 2.52.0 | 字节跳动推出的前端 UI 框架,年轻化的色彩和组件设计。 |
@@ -239,7 +220,7 @@ pnpm dev
| <a href="https://github.com/liquibase/liquibase" target="_blank">Liquibase</a> | 4.9.1 | 用于管理数据库版本,跟踪、管理和应用数据库变化。 |
| <a href="https://redis.io/" target="_blank">Redis</a> | 6.2.7 | 高性能的 key-value 数据库。 |
| <a href="https://github.com/redisson/redisson/wiki/Redisson%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D" target="_blank">Redisson</a> | 3.20.1 | 不仅仅是一个 Redis Java 客户端,同其他 Redis Java 客户端有着很大的区别,相比之下其他客户端提供的功能还仅仅停留在作为数据库驱动层面上,比如仅针对 Redis 提供连接方式,发送命令和处理返回结果等。而 Redisson 充分的利用了 Redis 键值数据库提供的一系列优势,基于 Java 实用工具包中常用接口,为使用者提供了一系列具有分布式特性的常用工具类。使得原本作为协调单机多线程并发程序的工具包获得了协调分布式多机多线程并发系统的能力,大大降低了设计和研发大规模分布式系统的难度。同时结合各富特色的分布式服务,更进一步简化了分布式环境中程序相互之间的协作。 |
| <a href="https://sms4j.com/" target="_blank">SMS4J</a> | 3.0.3 | 短信聚合框架,轻松集成多家短信服务,解决接入多个短信 SDK 的繁琐流程。 |
| <a href="https://sms4j.com/" target="_blank">SMS4J</a> | 3.0.4 | 短信聚合框架,轻松集成多家短信服务,解决接入多个短信 SDK 的繁琐流程。 |
| <a href="https://justauth.cn/" target="_blank">Just Auth</a> | 1.16.5 | 开箱即用的整合第三方登录的开源组件,脱离繁琐的第三方登录 SDK让登录变得 So easy |
| <a href="https://easyexcel.opensource.alibaba.com/" target="_blank">Easy Excel</a> | 3.3.2 | 一个基于 Java 的、快速、简洁、解决大文件内存溢出的 Excel 处理工具。 |
| Easy Captcha | 1.6.2 | Java 图形验证码,支持 gif、中文、算术等类型可用于 Java Web、JavaSE 等项目。 |
@@ -481,11 +462,31 @@ ContiNew Admin 的分支目前分为下个大版本的开发分支和上个大
> 2. 在提交代码前,请按照 [Angular 提交规范](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular) 编写 commit 的 message建议在 IntelliJ IDEA 中下载并安装 Git Commit Template 插件,以便按照规范进行 commit
> 3. 提交代码之前,请关闭所有代码窗口,执行 mvn compile 命令(项目已配置代码格式化插件,编译通过的同时也会自动进行代码格式化),编译通过后,不要再打开查看任何代码窗口,直接提交即可,以免不同的 IDE 配置会自动进行代码格式化
## 反馈交流
💬 欢迎各位小伙伴儿扫描下方二维码加好友,备注 `cnadmin`,拉你进群,探讨技术、提提需求~
加入交流群后,你将会:
- 第一时间收到框架动态
- 第一时间收到框架更新通知
- 第一时间收到框架 Bug 通知
- 和众多大佬互相 (huá shuǐ) 交流 (mō yú)
<div align="left">
<img src=".image/qrcode.jpg" alt="二维码" width="230px" />
</div>
<details>
<summary>无加群意愿</summary>
💬 如无加群意愿,欢迎在 <a href="https://github.com/Charles7c/continew-admin/issues" target="_blank">Issues</a> 中反馈交流~ 🍻
</details>
## 鸣谢
### 鸣谢
感谢参与贡献的每一位小伙伴!(以下排名不分先后)
感谢参与贡献的每一位小伙伴🥰
<a href="https://github.com/Charles7c/continew-admin/graphs/contributors">
<img src="https://opencollective.com/continew-admin/contributors.svg?width=890&button=false" alt="contributors" />
@@ -496,7 +497,11 @@ ContiNew Admin 的分支目前分为下个大版本的开发分支和上个大
- 感谢 <a href="https://www.jetbrains.com/" target="_blank">JetBrains</a> 提供的 <a href="https://www.jetbrains.com/shop/eform/opensource" target="_blank">非商业开源软件开发授权</a>
- 感谢 <a href="http://pro.arco.design/" target="_blank">Arco Design Pro</a> 开箱即用的中后台前端解决方案
- 感谢 <a href="https://github.com/baomidou/mybatis-plus" target="_blank">MyBatis Plus</a><a href="https://github.com/dromara/sa-token" target="_blank">Sa-Token</a><a href="https://github.com/alibaba/easyexcel" target="_blank">Easy Excel</a><a href="https://github.com/xiaoymin/knife4j" target="_blank">Knife4j</a><a href="https://github.com/dromara/hutool" target="_blank">Hutool</a> 等国产开源组件作者为国内开源世界作出的贡献
- 感谢 <a href="https://github.com/elunez/eladmin" target="_blank">ELADMIN</a><a href="https://github.com/dromara/RuoYi-Vue-Plus" target="_blank">RuoYi-Vue-Plus</a><a href="https://github.com/yangzongzhuan/RuoYi-Vue3" target="_blank">RuoYi-Vue3</a> 提供的诸多成熟方案,致敬各位作者为开源脚手架领域作出的贡献
- 感谢 <a href="https://github.com/elunez/eladmin" target="_blank">ELADMIN</a><a href="https://github.com/yangzongzhuan/RuoYi-Vue3" target="_blank">RuoYi-Vue3</a><a href="https://github.com/dromara/RuoYi-Vue-Plus" target="_blank">RuoYi-Vue-Plus</a>,致敬各位作者为开源脚手架领域作出的贡献
- e.g. 脱胎于 ELADMIN 项目开源的 QueryHelper 组件
- e.g. 参考 RuoYi-Vue3 前端项目的 Vue3 编码风格和规范
- e.g. 使用 RuoYi-Vue-Plus 项目封装的 SaToken 相关认证鉴权配置等
- 感谢项目使用或未使用到的每一款开源组件,致敬各位开源先驱 :fire:
## License

View File

@@ -1,19 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--
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.
-->
<!-- 生成当前格式化配置文件参照https://github.com/diffplug/spotless/blob/main/ECLIPSE_SCREENSHOTS.md -->
<profiles version="12">
<profile kind="CodeFormatterProfile" name="P3C-CodeStyle" version="13">

View File

@@ -1,19 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

View File

@@ -1,32 +0,0 @@
/*
* 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.common.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 响应拦截忽略注解
*
* @author BULL_BCLS
* @since 2023/10/8 20:44
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NoResponseAdvice {}

View File

@@ -37,7 +37,6 @@ import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.StrUtil;
import top.charles7c.cnadmin.common.annotation.CrudRequestMapping;
import top.charles7c.cnadmin.common.annotation.NoResponseAdvice;
import top.charles7c.cnadmin.common.constant.StringConsts;
import top.charles7c.cnadmin.common.model.query.PageQuery;
import top.charles7c.cnadmin.common.model.query.SortQuery;
@@ -78,9 +77,9 @@ public abstract class BaseController<S extends BaseService<L, D, Q, C>, L, D, Q,
@Operation(summary = "分页查询列表", description = "分页查询列表")
@ResponseBody
@GetMapping
public PageDataResp<L> page(Q query, @Validated PageQuery pageQuery) {
public R<PageDataResp<L>> page(Q query, @Validated PageQuery pageQuery) {
this.checkPermission(Api.LIST);
return baseService.page(query, pageQuery);
return R.ok(baseService.page(query, pageQuery));
}
/**
@@ -95,9 +94,9 @@ public abstract class BaseController<S extends BaseService<L, D, Q, C>, L, D, Q,
@Operation(summary = "查询树列表", description = "查询树列表")
@ResponseBody
@GetMapping("/tree")
public List<Tree<Long>> tree(Q query, SortQuery sortQuery) {
public R<List<Tree<Long>>> tree(Q query, SortQuery sortQuery) {
this.checkPermission(Api.LIST);
return baseService.tree(query, sortQuery, false);
return R.ok(baseService.tree(query, sortQuery, false));
}
/**
@@ -112,9 +111,9 @@ public abstract class BaseController<S extends BaseService<L, D, Q, C>, L, D, Q,
@Operation(summary = "查询列表", description = "查询列表")
@ResponseBody
@GetMapping("/list")
public List<L> list(Q query, SortQuery sortQuery) {
public R<List<L>> list(Q query, SortQuery sortQuery) {
this.checkPermission(Api.LIST);
return baseService.list(query, sortQuery);
return R.ok(baseService.list(query, sortQuery));
}
/**
@@ -128,9 +127,9 @@ public abstract class BaseController<S extends BaseService<L, D, Q, C>, L, D, Q,
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@ResponseBody
@GetMapping("/{id}")
public D get(@PathVariable Long id) {
public R<D> get(@PathVariable Long id) {
this.checkPermission(Api.LIST);
return baseService.get(id);
return R.ok(baseService.get(id));
}
/**
@@ -196,7 +195,6 @@ public abstract class BaseController<S extends BaseService<L, D, Q, C>, L, D, Q,
* 响应对象
*/
@Operation(summary = "导出数据", description = "导出数据")
@NoResponseAdvice
@GetMapping("/export")
public void export(Q query, SortQuery sortQuery, HttpServletResponse response) {
this.checkPermission(Api.EXPORT);

View File

@@ -1,70 +0,0 @@
/*
* 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.common.handler;
import lombok.RequiredArgsConstructor;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.hutool.core.util.StrUtil;
import top.charles7c.cnadmin.common.annotation.NoResponseAdvice;
import top.charles7c.cnadmin.common.model.resp.R;
/**
* 全局响应结果处理器
*
* @author BULL_BCLS
* @since 2023/10/8 20:19
*/
@RestControllerAdvice
@RequiredArgsConstructor
public class GlobalResponseBodyAdviceHandler implements ResponseBodyAdvice<Object> {
private static final String[] EXCLUDE = {"MultipleOpenApiWebMvcResource", "SwaggerConfigResource",};
private final ObjectMapper objectMapper;
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> converterType) {
return !methodParameter.getParameterType().isAssignableFrom(R.class)
&& !methodParameter.hasMethodAnnotation(NoResponseAdvice.class)
&& !StrUtil.equalsAny(methodParameter.getDeclaringClass().getSimpleName(), EXCLUDE);
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
if (String.class.equals(returnType.getGenericParameterType())) {
try {
return objectMapper.writeValueAsString(R.ok(body));
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
return R.ok(body);
}
}

View File

@@ -1,19 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

View File

@@ -139,10 +139,9 @@ public class LogServiceImpl implements LogService {
public SystemLogDetailResp get(Long id) {
LogDO logDO = logMapper.selectById(id);
CheckUtils.throwIfNotExists(logDO, "LogDO", "ID", id);
SystemLogDetailResp detailVO = BeanUtil.copyProperties(logDO, SystemLogDetailResp.class);
this.fill(detailVO);
return detailVO;
SystemLogDetailResp detail = BeanUtil.copyProperties(logDO, SystemLogDetailResp.class);
this.fill(detail);
return detail;
}
@Override

View File

@@ -1,19 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

View File

@@ -19,7 +19,6 @@ package top.charles7c.cnadmin.system.model.req;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import lombok.Data;
@@ -28,7 +27,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
import org.hibernate.validator.constraints.Length;
import top.charles7c.cnadmin.common.base.BaseReq;
import top.charles7c.cnadmin.common.constant.RegexConsts;
import top.charles7c.cnadmin.common.enums.DisEnableStatusEnum;
import top.charles7c.cnadmin.common.enums.MenuTypeEnum;
@@ -63,7 +61,7 @@ public class MenuReq extends BaseReq {
*/
@Schema(description = "菜单标题", example = "用户管理")
@NotBlank(message = "菜单标题不能为空")
@Pattern(regexp = RegexConsts.GENERAL_NAME, message = "菜单标题长度为 2 到 30 位,可以包含中文、字母、数字、下划线,短横线")
@Length(max = 30, message = "菜单标题长度不能超过 {max} 个字符")
private String title;
/**

View File

@@ -68,6 +68,7 @@ public class MessageServiceImpl implements MessageService {
}
@Override
@Transactional(rollbackFor = Exception.class)
public void add(MessageReq req, List<Long> userIdList) {
CheckUtils.throwIf(() -> CollUtil.isEmpty(userIdList), "消息接收人不能为空");
MessageDO message = BeanUtil.copyProperties(req, MessageDO.class);

View File

@@ -135,16 +135,16 @@ public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleRes
public void fillDetail(Object detailObj) {
super.fillDetail(detailObj);
if (detailObj instanceof RoleDetailResp) {
RoleDetailResp detailVO = (RoleDetailResp)detailObj;
Long roleId = detailVO.getId();
if (SysConsts.ADMIN_ROLE_CODE.equals(detailVO.getCode())) {
RoleDetailResp detail = (RoleDetailResp)detailObj;
Long roleId = detail.getId();
if (SysConsts.ADMIN_ROLE_CODE.equals(detail.getCode())) {
List<MenuResp> list = menuService.list(null, null);
List<Long> menuIds = list.stream().map(MenuResp::getId).collect(Collectors.toList());
detailVO.setMenuIds(menuIds);
detail.setMenuIds(menuIds);
} else {
detailVO.setMenuIds(roleMenuService.listMenuIdByRoleIds(CollUtil.newArrayList(roleId)));
detail.setMenuIds(roleMenuService.listMenuIdByRoleIds(CollUtil.newArrayList(roleId)));
}
detailVO.setDeptIds(roleDeptService.listDeptIdByRoleId(roleId));
detail.setDeptIds(roleDeptService.listDeptIdByRoleId(roleId));
}
}

View File

@@ -153,11 +153,11 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
public void fillDetail(Object detailObj) {
super.fillDetail(detailObj);
if (detailObj instanceof UserDetailResp) {
UserDetailResp detailVO = (UserDetailResp)detailObj;
detailVO.setDeptName(ExceptionUtils.exToNull(() -> deptService.get(detailVO.getDeptId()).getName()));
List<Long> roleIdList = userRoleService.listRoleIdByUserId(detailVO.getId());
detailVO.setRoleIds(roleIdList);
detailVO.setRoleNames(String.join(StringConsts.CHINESE_COMMA, roleService.listNameByIds(roleIdList)));
UserDetailResp detail = (UserDetailResp)detailObj;
detail.setDeptName(ExceptionUtils.exToNull(() -> deptService.get(detail.getDeptId()).getName()));
List<Long> roleIdList = userRoleService.listRoleIdByUserId(detail.getId());
detail.setRoleIds(roleIdList);
detail.setRoleNames(String.join(StringConsts.CHINESE_COMMA, roleService.listNameByIds(roleIdList)));
}
}

View File

@@ -20,6 +20,7 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@@ -45,6 +46,7 @@ public class GenConfigReq implements Serializable {
/**
* 字段配置信息
*/
@Valid
@Schema(description = "字段配置信息")
@NotEmpty(message = "字段配置不能为空")
private List<FieldConfigDO> fieldConfigs = new ArrayList<>();
@@ -52,6 +54,7 @@ public class GenConfigReq implements Serializable {
/**
* 生成配置信息
*/
@Valid
@Schema(description = "生成配置信息")
@NotNull(message = "生成配置不能为空")
private GenConfigDO genConfig;

View File

@@ -1,7 +1,7 @@
{
"name": "continew-admin-ui",
"description": "ContiNew Admin 中后台管理框架Continue New Admin持续以最新流行技术栈构建拥抱变化迭代优化。",
"version": "1.3.0",
"version": "1.3.2-SNAPSHOT",
"private": true,
"author": "Charles7c",
"license": "Apache-2.0",

View File

@@ -40,17 +40,17 @@ import App from './App.vue';
import '@/assets/style/global.less';
import '@/utils/request';
VueMarkdownEditor.use(createEmojiPlugin());
VueMarkdownEditor.use(createCopyCodePlugin());
VueMarkdownEditor.use(createTodoListPlugin());
hljs.registerLanguage('json', json);
hljs.registerLanguage('java', java);
VueMarkdownEditor.use(githubTheme, {
Hljs: hljs,
});
VMdPreview.use(githubTheme, {
Hljs: hljs,
});
VueMarkdownEditor.use(createEmojiPlugin());
VueMarkdownEditor.use(createCopyCodePlugin());
VueMarkdownEditor.use(createTodoListPlugin());
hljs.registerLanguage('json', json);
hljs.registerLanguage('java', java);
const app = createApp(App);
// 全局方法挂载

View File

@@ -23,7 +23,7 @@ export default function setupUserLoginInfoGuard(router: Router) {
await userStore.getInfo();
next();
} catch (error) {
await userStore.logout();
await userStore.logoutCallBack();
next({
name: 'login',
query: {

View File

@@ -22,8 +22,11 @@ const setTimer = (timer: number) => {
};
const clearTimer = () => {
clearInterval(Number(localStorage.getItem(TIMER_KEY)));
localStorage.removeItem(TIMER_KEY);
const timer = localStorage.getItem(TIMER_KEY);
if (timer) {
clearInterval(Number(timer));
localStorage.removeItem(TIMER_KEY);
}
};
export { isLogin, getToken, setToken, clearToken, setTimer, clearTimer };

View File

@@ -1,7 +1,7 @@
import axios from 'axios';
import type { AxiosRequestConfig, AxiosResponse } from 'axios';
import { useUserStore } from '@/store';
import { getToken } from '@/utils/auth';
import { getToken, clearTimer } from '@/utils/auth';
import modalErrorWrapper from '@/utils/modal-error-wrapper';
import messageErrorWrapper from '@/utils/message-error-wrapper';
@@ -51,8 +51,7 @@ axios.interceptors.response.use(
return res;
}
if ([401].includes(res.code) && response.config.url !== '/auth/user/info') {
const userStore = useUserStore();
userStore.logout();
clearTimer();
modalErrorWrapper({
title: '确认退出',
content: res.msg,
@@ -60,6 +59,8 @@ axios.interceptors.response.use(
escToClose: false,
okText: '重新登录',
async onOk() {
const userStore = useUserStore();
userStore.logoutCallBack();
window.location.reload();
},
});

View File

@@ -60,7 +60,7 @@
const { chartOption } = useChartOption((isDark) => {
return {
grid: {
left: '30',
left: '38',
right: '0',
top: '10',
bottom: '50',
@@ -114,6 +114,9 @@
axisLabel: {
formatter(value: any, idx: number) {
if (idx === 0) return value;
if (value >= 1000) {
return `${value / 1000}k`;
}
return `${value}`;
},
},

View File

@@ -145,13 +145,17 @@
ellipsis
tooltip
/>
<a-table-column
title="类型"
data-index="fieldType"
:width="95"
ellipsis
tooltip
/>
<a-table-column title="类型" :width="95" ellipsis tooltip>
<template #cell="{ record }">
<span v-if="record.fieldType">{{ record.fieldType }}</span>
<a-tooltip v-else content="请检查 generator.properties 配置">
<icon-exclamation-circle-fill
size="large"
style="color: #f53f3f"
/>
</a-tooltip>
</template>
</a-table-column>
<a-table-column title="描述" :width="170">
<template #cell="{ record }">
<a-input v-model="record.comment" />

View File

@@ -1,19 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

View File

@@ -41,6 +41,7 @@ import top.charles7c.cnadmin.auth.model.resp.UserInfoResp;
import top.charles7c.cnadmin.auth.service.LoginService;
import top.charles7c.cnadmin.common.constant.CacheConsts;
import top.charles7c.cnadmin.common.model.dto.LoginUser;
import top.charles7c.cnadmin.common.model.resp.R;
import top.charles7c.cnadmin.common.util.ExceptionUtils;
import top.charles7c.cnadmin.common.util.RedisUtils;
import top.charles7c.cnadmin.common.util.SecureUtils;
@@ -69,7 +70,7 @@ public class AuthController {
@SaIgnore
@Operation(summary = "账号登录", description = "根据账号和密码进行登录认证")
@PostMapping("/account")
public LoginResp accountLogin(@Validated @RequestBody AccountLoginReq loginReq) {
public R<LoginResp> accountLogin(@Validated @RequestBody AccountLoginReq loginReq) {
String captchaKey = RedisUtils.formatKey(CacheConsts.CAPTCHA_KEY_PREFIX, loginReq.getUuid());
String captcha = RedisUtils.getCacheObject(captchaKey);
ValidationUtils.throwIfBlank(captcha, "验证码已失效");
@@ -79,13 +80,13 @@ public class AuthController {
String rawPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(loginReq.getPassword()));
ValidationUtils.throwIfBlank(rawPassword, "密码解密失败");
String token = loginService.accountLogin(loginReq.getUsername(), rawPassword);
return LoginResp.builder().token(token).build();
return R.ok(LoginResp.builder().token(token).build());
}
@SaIgnore
@Operation(summary = "邮箱登录", description = "根据邮箱和验证码进行登录认证")
@PostMapping("/email")
public LoginResp emailLogin(@Validated @RequestBody EmailLoginReq loginReq) {
public R<LoginResp> emailLogin(@Validated @RequestBody EmailLoginReq loginReq) {
String email = loginReq.getEmail();
String captchaKey = RedisUtils.formatKey(CacheConsts.CAPTCHA_KEY_PREFIX, email);
String captcha = RedisUtils.getCacheObject(captchaKey);
@@ -93,13 +94,13 @@ public class AuthController {
ValidationUtils.throwIfNotEqualIgnoreCase(loginReq.getCaptcha(), captcha, "验证码错误");
RedisUtils.deleteCacheObject(captchaKey);
String token = loginService.emailLogin(email);
return LoginResp.builder().token(token).build();
return R.ok(LoginResp.builder().token(token).build());
}
@SaIgnore
@Operation(summary = "手机号登录", description = "根据手机号和验证码进行登录认证")
@PostMapping("/phone")
public LoginResp phoneLogin(@Validated @RequestBody PhoneLoginReq loginReq) {
public R<LoginResp> phoneLogin(@Validated @RequestBody PhoneLoginReq loginReq) {
String phone = loginReq.getPhone();
String captchaKey = RedisUtils.formatKey(CacheConsts.CAPTCHA_KEY_PREFIX, phone);
String captcha = RedisUtils.getCacheObject(captchaKey);
@@ -107,35 +108,35 @@ public class AuthController {
ValidationUtils.throwIfNotEqualIgnoreCase(loginReq.getCaptcha(), captcha, "验证码错误");
RedisUtils.deleteCacheObject(captchaKey);
String token = loginService.phoneLogin(phone);
return LoginResp.builder().token(token).build();
return R.ok(LoginResp.builder().token(token).build());
}
@SaIgnore
@Operation(summary = "用户退出", description = "注销用户的当前登录")
@Parameter(name = "Authorization", description = "令牌", required = true, example = "Bearer xxxx-xxxx-xxxx-xxxx",
in = ParameterIn.HEADER)
@PostMapping("/logout")
public void logout() {
public R logout() {
StpUtil.logout();
return R.ok();
}
@Log(ignore = true)
@Operation(summary = "获取用户信息", description = "获取登录用户信息")
@GetMapping("/user/info")
public UserInfoResp getUserInfo() {
public R<UserInfoResp> getUserInfo() {
LoginUser loginUser = LoginHelper.getLoginUser();
UserDetailResp userDetailResp = userService.get(loginUser.getId());
UserInfoResp userInfoResp = BeanUtil.copyProperties(userDetailResp, UserInfoResp.class);
userInfoResp.setPermissions(loginUser.getPermissions());
userInfoResp.setRoles(loginUser.getRoleCodes());
return userInfoResp;
return R.ok(userInfoResp);
}
@Log(ignore = true)
@Operation(summary = "获取路由信息", description = "获取登录用户的路由信息")
@GetMapping("/route")
public List<RouteResp> listRoute() {
public R<List<RouteResp>> listRoute() {
Long userId = LoginHelper.getUserId();
return loginService.buildRouteTree(userId);
return R.ok(loginService.buildRouteTree(userId));
}
}

View File

@@ -71,7 +71,7 @@ public class SocialAuthController {
@Operation(summary = "三方账号登录", description = "三方账号登录")
@Parameter(name = "source", description = "来源", example = "gitee", in = ParameterIn.PATH)
@PostMapping("/{source}")
public LoginResp login(@PathVariable String source, @RequestBody AuthCallback callback) {
public R<LoginResp> login(@PathVariable String source, @RequestBody AuthCallback callback) {
if (StpUtil.isLogin()) {
StpUtil.logout();
}
@@ -80,7 +80,7 @@ public class SocialAuthController {
ValidationUtils.throwIf(!response.ok(), response.getMsg());
AuthUser authUser = response.getData();
String token = loginService.socialLogin(authUser);
return LoginResp.builder().token(token).build();
return R.ok(LoginResp.builder().token(token).build());
}
private AuthRequest getAuthRequest(String source) {

View File

@@ -76,7 +76,7 @@ public class CaptchaController {
@Operation(summary = "获取图片验证码", description = "获取图片验证码Base64编码带图片格式data:image/gif;base64")
@GetMapping("/img")
public CaptchaResp getImageCaptcha() {
public R<CaptchaResp> getImageCaptcha() {
// 生成验证码
CaptchaProperties.CaptchaImage captchaImage = captchaProperties.getImage();
Captcha captcha = captchaImage.getCaptcha();
@@ -85,7 +85,7 @@ public class CaptchaController {
String captchaKey = RedisUtils.formatKey(CacheConsts.CAPTCHA_KEY_PREFIX, uuid);
RedisUtils.setCacheObject(captchaKey, captcha.text(),
Duration.ofMinutes(captchaImage.getExpirationInMinutes()));
return CaptchaResp.builder().uuid(uuid).img(captcha.toBase64()).build();
return R.ok(CaptchaResp.builder().uuid(uuid).img(captcha.toBase64()).build());
}
@Operation(summary = "获取邮箱验证码", description = "发送验证码到指定邮箱")

View File

@@ -97,39 +97,39 @@ public class CommonController {
@Operation(summary = "查询部门树", description = "查询树结构的部门列表")
@GetMapping("/tree/dept")
public List<Tree<Long>> listDeptTree(DeptQuery query, SortQuery sortQuery) {
return deptService.tree(query, sortQuery, true);
public R<List<Tree<Long>>> listDeptTree(DeptQuery query, SortQuery sortQuery) {
return R.ok(deptService.tree(query, sortQuery, true));
}
@Operation(summary = "查询菜单树", description = "查询树结构的菜单列表")
@GetMapping("/tree/menu")
public List<Tree<Long>> listMenuTree(MenuQuery query, SortQuery sortQuery) {
return menuService.tree(query, sortQuery, true);
public R<List<Tree<Long>>> listMenuTree(MenuQuery query, SortQuery sortQuery) {
return R.ok(menuService.tree(query, sortQuery, true));
}
@Operation(summary = "查询角色字典", description = "查询角色字典列表")
@GetMapping("/dict/role")
public List<LabelValueResp<Long>> listRoleDict(RoleQuery query, SortQuery sortQuery) {
public R<List<LabelValueResp<Long>>> listRoleDict(RoleQuery query, SortQuery sortQuery) {
List<RoleResp> list = roleService.list(query, sortQuery);
return roleService.buildDict(list);
return R.ok(roleService.buildDict(list));
}
@Operation(summary = "查询字典", description = "查询字典列表")
@Parameter(name = "code", description = "字典编码", example = "announcement_type", in = ParameterIn.PATH)
@GetMapping("/dict/{code}")
@Cacheable(key = "#code", cacheNames = CacheConsts.DICT_KEY_PREFIX)
public List<LabelValueResp> listDict(@PathVariable String code) {
public R<List<LabelValueResp>> listDict(@PathVariable String code) {
Optional<Class<?>> enumClass = this.getEnumClassByName(code);
return enumClass.map(this::listEnumDict).orElseGet(() -> dictItemService.listByDictCode(code));
return R.ok(enumClass.map(this::listEnumDict).orElseGet(() -> dictItemService.listByDictCode(code)));
}
@SaIgnore
@Operation(summary = "查询参数", description = "查询参数")
@GetMapping("/option")
@Cacheable(cacheNames = CacheConsts.OPTION_KEY_PREFIX)
public List<LabelValueResp> listOption(@Validated OptionQuery query) {
return optionService.list(query).stream().map(option -> new LabelValueResp(option.getCode(),
StrUtil.nullToDefault(option.getValue(), option.getDefaultValue()))).collect(Collectors.toList());
public R<List<LabelValueResp>> listOption(@Validated OptionQuery query) {
return R.ok(optionService.list(query).stream().map(option -> new LabelValueResp(option.getCode(),
StrUtil.nullToDefault(option.getValue(), option.getDefaultValue()))).collect(Collectors.toList()));
}
/**

View File

@@ -31,6 +31,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.charles7c.cnadmin.common.model.resp.R;
import top.charles7c.cnadmin.common.util.validate.ValidationUtils;
import top.charles7c.cnadmin.monitor.annotation.Log;
import top.charles7c.cnadmin.monitor.model.resp.DashboardAccessTrendResp;
@@ -58,33 +59,33 @@ public class DashboardController {
@Operation(summary = "查询总计信息", description = "查询总计信息")
@GetMapping("/total")
public DashboardTotalResp getTotal() {
return dashboardService.getTotal();
public R<DashboardTotalResp> getTotal() {
return R.ok(dashboardService.getTotal());
}
@Operation(summary = "查询访问趋势信息", description = "查询访问趋势信息")
@Parameter(name = "days", description = "日期数", example = "30", in = ParameterIn.PATH)
@GetMapping("/access/trend/{days}")
public List<DashboardAccessTrendResp> listAccessTrend(@PathVariable Integer days) {
public R<List<DashboardAccessTrendResp>> listAccessTrend(@PathVariable Integer days) {
ValidationUtils.throwIf(7 != days && 30 != days, "仅支持查询近 7/30 天访问趋势信息");
return dashboardService.listAccessTrend(days);
return R.ok(dashboardService.listAccessTrend(days));
}
@Operation(summary = "查询热门模块列表", description = "查询热门模块列表")
@GetMapping("/popular/module")
public List<DashboardPopularModuleResp> listPopularModule() {
return dashboardService.listPopularModule();
public R<List<DashboardPopularModuleResp>> listPopularModule() {
return R.ok(dashboardService.listPopularModule());
}
@Operation(summary = "查询访客地域分布信息", description = "查询访客地域分布信息")
@GetMapping("/geo/distribution")
public DashboardGeoDistributionResp getGeoDistribution() {
return dashboardService.getGeoDistribution();
public R<DashboardGeoDistributionResp> getGeoDistribution() {
return R.ok(dashboardService.getGeoDistribution());
}
@Operation(summary = "查询公告列表", description = "查询公告列表")
@GetMapping("/announcement")
public List<DashboardAnnouncementResp> listAnnouncement() {
return dashboardService.listAnnouncement();
public R<List<DashboardAnnouncementResp>> listAnnouncement() {
return R.ok(dashboardService.listAnnouncement());
}
}

View File

@@ -31,6 +31,7 @@ import org.springframework.web.bind.annotation.RestController;
import top.charles7c.cnadmin.common.model.query.PageQuery;
import top.charles7c.cnadmin.common.model.resp.PageDataResp;
import top.charles7c.cnadmin.common.model.resp.R;
import top.charles7c.cnadmin.monitor.annotation.Log;
import top.charles7c.cnadmin.monitor.model.query.LoginLogQuery;
import top.charles7c.cnadmin.monitor.model.query.OperationLogQuery;
@@ -58,29 +59,29 @@ public class LogController {
@Log(module = "登录日志")
@Operation(summary = "分页查询登录日志列表", description = "分页查询登录日志列表")
@GetMapping("/login")
public PageDataResp<LoginLogResp> page(LoginLogQuery query, @Validated PageQuery pageQuery) {
return logService.page(query, pageQuery);
public R<PageDataResp<LoginLogResp>> page(LoginLogQuery query, @Validated PageQuery pageQuery) {
return R.ok(logService.page(query, pageQuery));
}
@Log(module = "操作日志")
@Operation(summary = "分页查询操作日志列表", description = "分页查询操作日志列表")
@GetMapping("/operation")
public PageDataResp<OperationLogResp> page(OperationLogQuery query, @Validated PageQuery pageQuery) {
return logService.page(query, pageQuery);
public R<PageDataResp<OperationLogResp>> page(OperationLogQuery query, @Validated PageQuery pageQuery) {
return R.ok(logService.page(query, pageQuery));
}
@Log(module = "系统日志")
@Operation(summary = "分页查询系统日志列表", description = "分页查询系统日志列表")
@GetMapping("/system")
public PageDataResp<SystemLogResp> page(SystemLogQuery query, @Validated PageQuery pageQuery) {
return logService.page(query, pageQuery);
public R<PageDataResp<SystemLogResp>> page(SystemLogQuery query, @Validated PageQuery pageQuery) {
return R.ok(logService.page(query, pageQuery));
}
@Log(module = "系统日志")
@Operation(summary = "查看系统日志详情", description = "查看系统日志详情")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@GetMapping("/system/{id}")
public SystemLogDetailResp get(@PathVariable Long id) {
return logService.get(id);
public R<SystemLogDetailResp> get(@PathVariable Long id) {
return R.ok(logService.get(id));
}
}

View File

@@ -54,8 +54,8 @@ public class OnlineUserController {
@Operation(summary = "分页查询列表", description = "分页查询列表")
@SaCheckPermission("monitor:online:user:list")
@GetMapping
public PageDataResp<OnlineUserResp> page(OnlineUserQuery query, @Validated PageQuery pageQuery) {
return onlineUserService.page(query, pageQuery);
public R<PageDataResp<OnlineUserResp>> page(OnlineUserQuery query, @Validated PageQuery pageQuery) {
return R.ok(onlineUserService.page(query, pageQuery));
}
@Operation(summary = "强退在线用户", description = "强退在线用户")

View File

@@ -16,8 +16,6 @@
package top.charles7c.cnadmin.webapi.controller.system;
import static top.charles7c.cnadmin.common.annotation.CrudRequestMapping.Api;
import java.time.LocalDateTime;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -46,8 +44,7 @@ import top.charles7c.cnadmin.system.service.AnnouncementService;
*/
@Tag(name = "公告管理 API")
@RestController
@CrudRequestMapping(value = "/system/announcement",
api = {Api.PAGE, Api.GET, Api.ADD, Api.UPDATE, Api.DELETE, Api.EXPORT})
@CrudRequestMapping("/system/announcement")
public class AnnouncementController extends
BaseController<AnnouncementService, AnnouncementResp, AnnouncementDetailResp, AnnouncementQuery, AnnouncementReq> {

View File

@@ -16,8 +16,6 @@
package top.charles7c.cnadmin.webapi.controller.system;
import static top.charles7c.cnadmin.common.annotation.CrudRequestMapping.Api;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
@@ -38,5 +36,5 @@ import top.charles7c.cnadmin.system.service.DictService;
*/
@Tag(name = "字典管理 API")
@RestController
@CrudRequestMapping(value = "/system/dict", api = {Api.PAGE, Api.GET, Api.ADD, Api.UPDATE, Api.DELETE, Api.EXPORT})
@CrudRequestMapping("/system/dict")
public class DictController extends BaseController<DictService, DictResp, DictDetailResp, DictQuery, DictReq> {}

View File

@@ -56,9 +56,9 @@ public class MessageController {
@Operation(summary = "分页查询列表", description = "分页查询列表")
@GetMapping
public PageDataResp<MessageResp> page(MessageQuery query, @Validated PageQuery pageQuery) {
public R<PageDataResp<MessageResp>> page(MessageQuery query, @Validated PageQuery pageQuery) {
query.setUserId(LoginHelper.getUserId());
return baseService.page(query, pageQuery);
return R.ok(baseService.page(query, pageQuery));
}
@Operation(summary = "删除数据", description = "删除数据")
@@ -72,15 +72,16 @@ public class MessageController {
@Operation(summary = "标记已读", description = "将消息标记为已读状态")
@Parameter(name = "ids", description = "消息ID列表", example = "1,2", in = ParameterIn.QUERY)
@PatchMapping("/read")
public void readMessage(@RequestParam(required = false) List<Long> ids) {
public R readMessage(@RequestParam(required = false) List<Long> ids) {
messageUserService.readMessage(ids);
return R.ok();
}
@Log(ignore = true)
@Operation(summary = "查询未读消息数量", description = "查询当前用户的未读消息数量")
@Parameter(name = "isDetail", description = "是否查询详情", example = "true", in = ParameterIn.QUERY)
@GetMapping("/unread")
public MessageUnreadResp countUnreadMessage(@RequestParam(required = false) Boolean detail) {
return messageUserService.countUnreadMessageByUserId(LoginHelper.getUserId(), detail);
public R<MessageUnreadResp> countUnreadMessage(@RequestParam(required = false) Boolean detail) {
return R.ok(messageUserService.countUnreadMessageByUserId(LoginHelper.getUserId(), detail));
}
}

View File

@@ -28,6 +28,7 @@ import org.springframework.web.bind.annotation.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import top.charles7c.cnadmin.common.model.resp.R;
import top.charles7c.cnadmin.system.model.query.OptionQuery;
import top.charles7c.cnadmin.system.model.req.OptionReq;
import top.charles7c.cnadmin.system.model.req.OptionResetValueReq;
@@ -51,21 +52,23 @@ public class OptionController {
@Operation(summary = "查询参数列表", description = "查询参数列表")
@SaCheckPermission("system:config:list")
@GetMapping
public List<OptionResp> list(@Validated OptionQuery query) {
return optionService.list(query);
public R<List<OptionResp>> list(@Validated OptionQuery query) {
return R.ok(optionService.list(query));
}
@Operation(summary = "修改参数", description = "修改参数")
@SaCheckPermission("system:config:update")
@PatchMapping
public void update(@Validated @RequestBody List<OptionReq> req) {
public R update(@Validated @RequestBody List<OptionReq> req) {
optionService.update(req);
return R.ok();
}
@Operation(summary = "重置参数", description = "重置参数")
@SaCheckPermission("system:config:reset")
@PatchMapping("/value")
public void resetValue(@Validated @RequestBody OptionResetValueReq req) {
public R resetValue(@Validated @RequestBody OptionResetValueReq req) {
optionService.resetValue(req);
return R.ok();
}
}

View File

@@ -139,15 +139,15 @@ public class UserCenterController {
@Operation(summary = "查询绑定的三方账号", description = "查询绑定的三方账号")
@GetMapping("/social")
public List<UserSocialBindResp> listSocialBind() {
public R<List<UserSocialBindResp>> listSocialBind() {
List<UserSocialDO> userSocialList = userSocialService.listByUserId(LoginHelper.getUserId());
return userSocialList.stream().map(userSocial -> {
return R.ok(userSocialList.stream().map(userSocial -> {
String source = userSocial.getSource();
UserSocialBindResp userSocialBind = new UserSocialBindResp();
userSocialBind.setSource(source);
userSocialBind.setDescription(SocialSourceEnum.valueOf(source).getDescription());
return userSocialBind;
}).collect(Collectors.toList());
}).collect(Collectors.toList()));
}
@Operation(summary = "绑定三方账号", description = "绑定三方账号")

View File

@@ -62,8 +62,8 @@ public class GeneratorController {
@Operation(summary = "分页查询数据表", description = "分页查询数据表")
@SaCheckPermission("tool:generator:list")
@GetMapping("/table")
public PageDataResp<TableResp> pageTable(TableQuery query, @Validated PageQuery pageQuery) throws SQLException {
return generatorService.pageTable(query, pageQuery);
public R<PageDataResp<TableResp>> pageTable(TableQuery query, @Validated PageQuery pageQuery) throws SQLException {
return R.ok(generatorService.pageTable(query, pageQuery));
}
@Operation(summary = "查询字段配置列表", description = "查询字段配置列表")
@@ -71,17 +71,17 @@ public class GeneratorController {
@Parameter(name = "requireSync", description = "是否需要同步", example = "false", in = ParameterIn.QUERY)
@SaCheckPermission("tool:generator:list")
@GetMapping("/field/{tableName}")
public List<FieldConfigDO> listFieldConfig(@PathVariable String tableName,
public R<List<FieldConfigDO>> listFieldConfig(@PathVariable String tableName,
@RequestParam(required = false, defaultValue = "false") Boolean requireSync) {
return generatorService.listFieldConfig(tableName, requireSync);
return R.ok(generatorService.listFieldConfig(tableName, requireSync));
}
@Operation(summary = "查询生成配置信息", description = "查询生成配置信息")
@Parameter(name = "tableName", description = "表名称", required = true, example = "sys_user", in = ParameterIn.PATH)
@SaCheckPermission("tool:generator:list")
@GetMapping("/config/{tableName}")
public GenConfigDO getGenConfig(@PathVariable String tableName) throws SQLException {
return generatorService.getGenConfig(tableName);
public R<GenConfigDO> getGenConfig(@PathVariable String tableName) throws SQLException {
return R.ok(generatorService.getGenConfig(tableName));
}
@Operation(summary = "保存配置信息", description = "保存配置信息")

View File

@@ -5,7 +5,7 @@ project:
# 应用名称
appName: continew-admin
# 版本
version: 1.3.0
version: 1.3.2-SNAPSHOT
# 描述
description: ContiNew Admin 中后台管理框架/脚手架Continue New Admin持续以最新流行技术栈构建拥抱变化迭代优化。
# 基本包
@@ -58,7 +58,9 @@ springdoc:
packages-to-scan: ${project.basePackage}.webapi.controller
- group: 'auth'
display-name: '系统认证'
paths-to-match: '/auth/**'
paths-to-match:
- '/auth/**'
- '/oauth/**'
packages-to-scan: ${project.basePackage}.webapi.controller.auth
- group: 'common'
display-name: '通用接口'

View File

@@ -28,7 +28,7 @@ services:
- /docker/redis/conf/redis.conf:/usr/local/redis/config/redis.conf
- /docker/redis/data:/data
- /docker/redis/logs:/logs
command: 'redis-server /usr/local/redis/config/redis.conf --appendonly yes --requirepass 123456'
command: 'redis-server /usr/local/redis/config/redis.conf --appendonly yes --requirepass 你的 Redis 密码'
continew-admin-server:
build: ./continew-admin
restart: always
@@ -67,5 +67,5 @@ services:
volumes:
- /docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf
- /docker/nginx/cert:/etc/nginx/cert
- /docker/continew-admin/web:/usr/share/nginx/html
- /docker/nginx/logs:/var/log/nginx
- /docker/continew-admin/web:/usr/share/nginx/html

View File

@@ -1,6 +1,6 @@
bind 0.0.0.0
# redis 密码
requirepass 123456
requirepass 你的 Redis 密码
# key 监听器配置
# notify-keyspace-events Ex

33
pom.xml
View File

@@ -1,24 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.16</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>top.charles7c</groupId>
<artifactId>continew-admin</artifactId>
<version>${revision}</version>
@@ -36,13 +28,6 @@ limitations under the License.
<module>continew-admin-common</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.16</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<sa-token.version>1.36.0</sa-token.version>
@@ -52,7 +37,7 @@ limitations under the License.
<p6spy.version>3.9.1</p6spy.version>
<!-- ### 工具库相关 ### -->
<sms4j.version>3.0.3</sms4j.version>
<sms4j.version>3.0.4</sms4j.version>
<justauth.version>1.16.5</justauth.version>
<easyexcel.version>3.3.2</easyexcel.version>
<ip2region.version>2.7.15</ip2region.version>
@@ -62,7 +47,7 @@ limitations under the License.
<hutool.version>5.8.22</hutool.version>
<!-- ### 基础环境相关 ### -->
<revision>1.3.0</revision>
<revision>1.3.2-SNAPSHOT</revision>
<java.version>1.8</java.version>
<spotless.version>2.30.0</spotless.version>
<maven.compiler.source>8</maven.compiler.source>