Compare commits
61 Commits
responsive
...
hot-fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4b2343ac9 | ||
|
|
5665ae0fda | ||
|
|
76b77dbf18 | ||
|
|
8ffa4324d3 | ||
|
|
7442516c07 | ||
|
|
f04ea3a9e8 | ||
|
|
ea86342a0f | ||
|
|
3d48ae9119 | ||
|
|
fa580a5dd4 | ||
|
|
87d288c58e | ||
|
|
772ad547bf | ||
|
|
ca42fbbda9 | ||
|
|
28eed04823 | ||
|
|
5306e24aa2 | ||
|
|
621170b347 | ||
|
|
ea10b156e3 | ||
|
|
7b8ef54e7b | ||
|
|
7e1940e459 | ||
|
|
567223eac3 | ||
|
|
1995985750 | ||
|
|
fe3ebdf931 | ||
|
|
f011086fcf | ||
|
|
d9853ef8d0 | ||
|
|
dc7780e0a8 | ||
|
|
c64f2eb0f6 | ||
|
|
f559e4cde3 | ||
|
|
ab72508408 | ||
|
|
219b4f40a6 | ||
|
|
bb9cd2e529 | ||
|
|
8a8588588f | ||
|
|
ac6c50ff28 | ||
|
|
a00c3e129f | ||
|
|
81b02e68e7 | ||
|
|
79d4ced364 | ||
|
|
a30d63ebdd | ||
|
|
f65349f246 | ||
|
|
2324bcaa13 | ||
|
|
4f35b256e6 | ||
|
|
24f379857a | ||
|
|
17200ec6d1 | ||
|
|
5068e7ff58 | ||
|
|
45c921fa24 | ||
|
|
db02af8677 | ||
|
|
56e92b2cb8 | ||
|
|
39c91a971b | ||
|
|
a1752df1ed | ||
|
|
df3862d496 | ||
|
|
bdf9da7eed | ||
|
|
d4a34e7b52 | ||
|
|
a982942153 | ||
|
|
f53db08c25 | ||
|
|
2210348d3b | ||
|
|
690228cb42 | ||
|
|
d5801b3b50 | ||
|
|
27529ee70c | ||
|
|
50a1bc65ef | ||
|
|
54201aa0f0 | ||
|
|
07e590dc2d | ||
|
|
34e0d3d8e7 | ||
|
|
ad5b20d3c5 | ||
|
|
dba64a38f2 |
23
README.md
@@ -34,21 +34,27 @@
|
|||||||
|
|
||||||
## 🥝 产品社群
|
## 🥝 产品社群
|
||||||
|
|
||||||
**加 QQ 群,获取一键部署脚本(包含数据库 Redis 消息队列等所有中间件!)**
|
**加 QQ 群或微信群立送以下装备,瞬间秒杀全服!!**
|
||||||
|
1. 一键部署脚本(包含数据库 Redis 消息队列等所有中间件!)
|
||||||
|
2. 永久免费的 Https 证书
|
||||||
|
3. 永久免费的分布式对象存储
|
||||||
|
4. 永久免费的 AI 模型
|
||||||
|
5. 永久免费的 Node、Docker、Maven 国内镜像仓库
|
||||||
|
|
||||||
- QQ群:638254979 (获取部署脚本)
|

|
||||||
|
|
||||||
[](https://qm.qq.com/q/9mvVC57jPO)
|
[](https://qm.qq.com/q/9mvVC57jPO)
|
||||||
|
|
||||||
实在没有 QQ 的可以加微信
|
|
||||||
|
|
||||||
- 微信:Chuck9996
|
- QQ群:638254979(目前人较多)
|
||||||
|
- 微信:Chuck9996(若微信群已过期可以加我 vx)
|
||||||
|
|
||||||
|
|
||||||
## 🍅 相关课程
|
## 🍅 相关课程
|
||||||
|
|
||||||
已上线:
|
已上线:
|
||||||
|
|
||||||
- [《重构方法论与单元测试的艺术》](https://www.bilibili.com/cheese/play/ep1615343)
|
- [《国内首个无幻觉式 AI 编程指南》](https://www.bilibili.com/cheese/play/ep1615343)
|
||||||
|
|
||||||
敬请期待:(加群获取)
|
敬请期待:(加群获取)
|
||||||
|
|
||||||
@@ -70,11 +76,8 @@
|
|||||||
|
|
||||||
用户通过和知路智能体对话,便可完成所有核心业务操作,不再需要再去学习操作复杂的前端页面。使你在任何时间都可享受运筹帷幄,指点江山的人生乐趣!
|
用户通过和知路智能体对话,便可完成所有核心业务操作,不再需要再去学习操作复杂的前端页面。使你在任何时间都可享受运筹帷幄,指点江山的人生乐趣!
|
||||||
|
|
||||||
**企业问答**
|

|
||||||

|

|
||||||
|
|
||||||
**操作业务功能**
|
|
||||||

|
|
||||||
|
|
||||||
**更多功能正在锐意制作中,敬请期待。。。**
|
**更多功能正在锐意制作中,敬请期待。。。**
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 185 KiB |
BIN
assets/action1.png
Normal file
|
After Width: | Height: | Size: 298 KiB |
BIN
assets/action2.png
Normal file
|
After Width: | Height: | Size: 426 KiB |
BIN
assets/group.png
Normal file
|
After Width: | Height: | Size: 575 KiB |
BIN
assets/wechat.png
Normal file
|
After Width: | Height: | Size: 164 KiB |
@@ -15,3 +15,11 @@ ALLOWED_ORIGINS=http://localhost,https://localhost,http://localhost:8080,http://
|
|||||||
ALLOWED_METHODS=*
|
ALLOWED_METHODS=*
|
||||||
ALLOWED_HEADERS=*
|
ALLOWED_HEADERS=*
|
||||||
ALLOWED_EXPOSE_HEADERS=*
|
ALLOWED_EXPOSE_HEADERS=*
|
||||||
|
# minio
|
||||||
|
MINIO_ENDPOINT=http://host.docker.internal:9000
|
||||||
|
MINIO_EXPOSE_PORT=9000
|
||||||
|
MINIO_WEB_PORT=9001
|
||||||
|
MINIO_STORE=~/docker/store/mjga/minio/data
|
||||||
|
MINIO_ROOT_USER=minio
|
||||||
|
MINIO_ROOT_PASSWORD=minio123
|
||||||
|
MINIO_DEFAULT_BUCKETS=zhilu
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ sourceSets {
|
|||||||
group = "com.zl.mjga"
|
group = "com.zl.mjga"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
description = "make java great again!"
|
description = "make java great again!"
|
||||||
java.sourceCompatibility = JavaVersion.VERSION_17
|
java.sourceCompatibility = JavaVersion.VERSION_21
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
compileOnly {
|
compileOnly {
|
||||||
@@ -53,6 +53,7 @@ dependencies {
|
|||||||
implementation("org.apache.commons:commons-lang3:3.17.0")
|
implementation("org.apache.commons:commons-lang3:3.17.0")
|
||||||
implementation("org.apache.commons:commons-collections4:4.4")
|
implementation("org.apache.commons:commons-collections4:4.4")
|
||||||
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0")
|
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0")
|
||||||
|
implementation("io.minio:minio:8.5.17")
|
||||||
implementation("org.jooq:jooq-meta:$jooqVersion")
|
implementation("org.jooq:jooq-meta:$jooqVersion")
|
||||||
implementation("com.auth0:java-jwt:4.4.0")
|
implementation("com.auth0:java-jwt:4.4.0")
|
||||||
implementation("org.flywaydb:flyway-core:$flywayVersion")
|
implementation("org.flywaydb:flyway-core:$flywayVersion")
|
||||||
|
|||||||
@@ -9,9 +9,11 @@
|
|||||||
</description>
|
</description>
|
||||||
<rule ref="category/java/bestpractices.xml">
|
<rule ref="category/java/bestpractices.xml">
|
||||||
<exclude name="GuardLogStatement"/>
|
<exclude name="GuardLogStatement"/>
|
||||||
|
<exclude name="AvoidReassigningParameters"/>
|
||||||
</rule>
|
</rule>
|
||||||
<rule ref="category/java/errorprone.xml">
|
<rule ref="category/java/errorprone.xml">
|
||||||
<exclude name="AvoidLiteralsInIfCondition"/>
|
<exclude name="AvoidLiteralsInIfCondition"/>
|
||||||
</rule>
|
<exclude name="AvoidDuplicateLiterals"/>
|
||||||
|
|
||||||
</ruleset>
|
</rule>
|
||||||
|
</ruleset>
|
||||||
@@ -2,8 +2,8 @@ rootProject.name = "backend"
|
|||||||
|
|
||||||
pluginManagement {
|
pluginManagement {
|
||||||
repositories {
|
repositories {
|
||||||
maven { url = uri("https://mirrors.cloud.tencent.com/nexus/repository/maven-public/") }
|
// maven { url = uri("https://mirrors.cloud.tencent.com/nexus/repository/maven-public/") }
|
||||||
maven { url = uri("https://mirrors.cloud.tencent.com/nexus/repository/gradle-plugin/") }
|
// maven { url = uri("https://mirrors.cloud.tencent.com/nexus/repository/gradle-plugin/") }
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
@@ -11,8 +11,8 @@ pluginManagement {
|
|||||||
|
|
||||||
dependencyResolutionManagement {
|
dependencyResolutionManagement {
|
||||||
repositories {
|
repositories {
|
||||||
maven { url = uri("https://mirrors.cloud.tencent.com/nexus/repository/maven-public/") }
|
// maven { url = uri("https://mirrors.cloud.tencent.com/nexus/repository/maven-public/") }
|
||||||
maven { url = uri("https://mirrors.cloud.tencent.com/nexus/repository/apache-snapshots/") }
|
// maven { url = uri("https://mirrors.cloud.tencent.com/nexus/repository/apache-snapshots/") }
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.zl.mjga.service.DepartmentService;
|
|||||||
import dev.langchain4j.agent.tool.P;
|
import dev.langchain4j.agent.tool.P;
|
||||||
import dev.langchain4j.agent.tool.Tool;
|
import dev.langchain4j.agent.tool.Tool;
|
||||||
import dev.langchain4j.model.output.structured.Description;
|
import dev.langchain4j.model.output.structured.Description;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jooq.generated.mjga.tables.pojos.Department;
|
import org.jooq.generated.mjga.tables.pojos.Department;
|
||||||
@@ -21,37 +22,65 @@ public class DepartmentOperatorTool {
|
|||||||
|
|
||||||
@Tool(value = "创建部门")
|
@Tool(value = "创建部门")
|
||||||
void createDepartment(
|
void createDepartment(
|
||||||
@P(value = "部门名称") String departmentName,
|
@P(value = "部门名称") @Size(min = 2, max = 15) String name,
|
||||||
@P(value = "上级部门名称", required = false) String parentDepartmentName) {
|
@P(value = "上级部门名称", required = false) @Size(min = 2, max = 15) String parentName) {
|
||||||
Department exist = departmentRepository.fetchOneByName(departmentName);
|
Department exist = departmentRepository.fetchOneByName(name);
|
||||||
|
Department department = new Department(null, name, null);
|
||||||
if (exist != null) {
|
if (exist != null) {
|
||||||
throw new BusinessException("当前部门已存在");
|
throw new BusinessException("当前部门已存在");
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotEmpty(parentDepartmentName)) {
|
if (StringUtils.isNotEmpty(parentName)) {
|
||||||
Department parent = departmentRepository.fetchOneByName(parentDepartmentName);
|
Department parent = departmentRepository.fetchOneByName(parentName);
|
||||||
if (parent == null) {
|
if (parent == null) {
|
||||||
throw new BusinessException("上级部门不存在");
|
throw new BusinessException("指定的上级部门不存在");
|
||||||
|
} else {
|
||||||
|
department.setParentId(parent.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
departmentService.upsertDepartment(new Department(null, departmentName, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Tool(value = "更新部门/绑定上级部门/解绑上级部门")
|
|
||||||
void updateDepartment(
|
|
||||||
@P(value = "部门名称") String departmentName,
|
|
||||||
@P(value = "上级部门名称", required = false) String parentDepartmentName) {
|
|
||||||
Department exist = departmentRepository.fetchOneByName(departmentName);
|
|
||||||
if (exist == null) {
|
|
||||||
throw new BusinessException("不存在的部门");
|
|
||||||
}
|
|
||||||
Department department = new Department(null, departmentName, null);
|
|
||||||
if (StringUtils.isNotEmpty(parentDepartmentName)) {
|
|
||||||
Department parent = departmentRepository.fetchOneByName(parentDepartmentName);
|
|
||||||
if (parent == null) {
|
|
||||||
throw new BusinessException("上级部门不存在");
|
|
||||||
}
|
|
||||||
department.setParentId(parent.getId());
|
|
||||||
}
|
|
||||||
departmentService.upsertDepartment(department);
|
departmentService.upsertDepartment(department);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Tool(value = {"更新部门信息"})
|
||||||
|
void updateDepartment(@P(value = "部门名称") String name) {
|
||||||
|
Department exist = departmentRepository.fetchOneByName(name);
|
||||||
|
if (exist == null) {
|
||||||
|
throw new BusinessException("不存在的部门");
|
||||||
|
}
|
||||||
|
exist.setName(name);
|
||||||
|
departmentService.upsertDepartment(exist);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tool(value = {"给指定部门绑定/分配上级部门"})
|
||||||
|
void bindParentDepartment(
|
||||||
|
@P(value = "部门名称") String name, @P(value = "上级部门名称") String parentName) {
|
||||||
|
Department exist = departmentRepository.fetchOneByName(name);
|
||||||
|
if (exist == null) {
|
||||||
|
throw new BusinessException("不存在的部门");
|
||||||
|
}
|
||||||
|
Department parent = departmentRepository.fetchOneByName(parentName);
|
||||||
|
if (parent == null) {
|
||||||
|
throw new BusinessException("上级部门不存在");
|
||||||
|
}
|
||||||
|
exist.setParentId(parent.getId());
|
||||||
|
departmentService.upsertDepartment(exist);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tool(value = {"给指定部门解绑/撤销上级部门"})
|
||||||
|
void unbindParentDepartment(@P(value = "部门名称") String name) {
|
||||||
|
Department exist = departmentRepository.fetchOneByName(name);
|
||||||
|
if (exist == null) {
|
||||||
|
throw new BusinessException("不存在的部门");
|
||||||
|
}
|
||||||
|
exist.setParentId(null);
|
||||||
|
departmentService.upsertDepartment(exist);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tool(value = "删除指定部门")
|
||||||
|
void deleteDepartment(@P(value = "部门名称") String name) {
|
||||||
|
Department exist = departmentRepository.fetchOneByName(name);
|
||||||
|
if (exist == null) {
|
||||||
|
throw new BusinessException("不存在的部门");
|
||||||
|
}
|
||||||
|
departmentRepository.deleteById(exist.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ import com.zl.mjga.repository.PositionRepository;
|
|||||||
import dev.langchain4j.agent.tool.P;
|
import dev.langchain4j.agent.tool.P;
|
||||||
import dev.langchain4j.agent.tool.Tool;
|
import dev.langchain4j.agent.tool.Tool;
|
||||||
import dev.langchain4j.model.output.structured.Description;
|
import dev.langchain4j.model.output.structured.Description;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.jooq.generated.mjga.tables.pojos.Position;
|
import org.jooq.generated.mjga.tables.pojos.Position;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
|
||||||
@Description("和岗位管理有关的操作工具")
|
@Description("和岗位管理有关的操作工具")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Component
|
@Component
|
||||||
@@ -16,17 +18,17 @@ public class PositionOperatorTool {
|
|||||||
private final PositionRepository positionRepository;
|
private final PositionRepository positionRepository;
|
||||||
|
|
||||||
@Tool(value = "创建岗位")
|
@Tool(value = "创建岗位")
|
||||||
void createPosition(@P("岗位名称") String positionName) {
|
void createPosition(@P("岗位名称") @Size(min = 2, max = 15) String name) {
|
||||||
Position position = positionRepository.fetchOneByName(positionName);
|
Position position = positionRepository.fetchOneByName(name);
|
||||||
if (position != null) {
|
if (position != null) {
|
||||||
throw new BusinessException("岗位已存在");
|
throw new BusinessException("岗位已存在");
|
||||||
}
|
}
|
||||||
positionRepository.merge(new Position(null, positionName));
|
positionRepository.merge(new Position(null, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "删除岗位")
|
@Tool(value = "删除岗位")
|
||||||
void deletePosition(@P("岗位名称") String positionName) {
|
void deletePosition(@P("岗位名称") String name) {
|
||||||
Position position = positionRepository.fetchOneByName(positionName);
|
Position position = positionRepository.fetchOneByName(name);
|
||||||
if (position == null) {
|
if (position == null) {
|
||||||
throw new BusinessException("岗位不存在");
|
throw new BusinessException("岗位不存在");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
package com.zl.mjga.component;
|
package com.zl.mjga.component;
|
||||||
|
|
||||||
|
import com.zl.mjga.dto.department.DepartmentBindDto;
|
||||||
|
import com.zl.mjga.dto.position.PositionBindDto;
|
||||||
import com.zl.mjga.dto.urp.PermissionUpsertDto;
|
import com.zl.mjga.dto.urp.PermissionUpsertDto;
|
||||||
import com.zl.mjga.dto.urp.RoleUpsertDto;
|
import com.zl.mjga.dto.urp.RoleUpsertDto;
|
||||||
import com.zl.mjga.dto.urp.UserUpsertDto;
|
import com.zl.mjga.dto.urp.UserUpsertDto;
|
||||||
import com.zl.mjga.exception.BusinessException;
|
import com.zl.mjga.exception.BusinessException;
|
||||||
import com.zl.mjga.repository.PermissionRepository;
|
import com.zl.mjga.repository.*;
|
||||||
import com.zl.mjga.repository.RoleRepository;
|
|
||||||
import com.zl.mjga.repository.UserRepository;
|
|
||||||
import com.zl.mjga.service.IdentityAccessService;
|
import com.zl.mjga.service.IdentityAccessService;
|
||||||
import dev.langchain4j.agent.tool.P;
|
import dev.langchain4j.agent.tool.P;
|
||||||
import dev.langchain4j.agent.tool.Tool;
|
import dev.langchain4j.agent.tool.Tool;
|
||||||
import dev.langchain4j.model.output.structured.Description;
|
import dev.langchain4j.model.output.structured.Description;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jooq.generated.mjga.tables.pojos.Permission;
|
import org.jooq.generated.mjga.tables.pojos.*;
|
||||||
import org.jooq.generated.mjga.tables.pojos.Role;
|
|
||||||
import org.jooq.generated.mjga.tables.pojos.User;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Description("和用户管理有关的操作工具")
|
@Description("和用户管理有关的操作工具")
|
||||||
|
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Component
|
@Component
|
||||||
public class UserRolePermissionOperatorTool {
|
public class UserRolePermissionOperatorTool {
|
||||||
@@ -28,14 +28,16 @@ public class UserRolePermissionOperatorTool {
|
|||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
private final RoleRepository roleRepository;
|
private final RoleRepository roleRepository;
|
||||||
private final PermissionRepository permissionRepository;
|
private final PermissionRepository permissionRepository;
|
||||||
|
private final DepartmentRepository departmentRepository;
|
||||||
|
private final PositionRepository positionRepository;
|
||||||
|
|
||||||
@Tool(value = "创建用户或注册用户")
|
@Tool(value = {"创建用户", "入职申请", "开通账号"})
|
||||||
void createUser(@P(value = "用户名") String username) {
|
void createUser(@P(value = "用户名") @Size(min = 1, max = 15) String name) {
|
||||||
User user = userRepository.fetchOneByUsername(username);
|
User user = userRepository.fetchOneByUsername(name);
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
throw new BusinessException("用户已存在");
|
throw new BusinessException("用户已存在");
|
||||||
}
|
}
|
||||||
identityAccessService.upsertUser(new UserUpsertDto(null, username, username, true));
|
identityAccessService.upsertUser(new UserUpsertDto(null, name, name, true, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "删除用户")
|
@Tool(value = "删除用户")
|
||||||
@@ -43,34 +45,86 @@ public class UserRolePermissionOperatorTool {
|
|||||||
userRepository.deleteByUsername(username);
|
userRepository.deleteByUsername(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "编辑/更新/更改用户")
|
@Tool(value = {"编辑用户", "更新用户", "更改用户"})
|
||||||
void updateUser(
|
void updateUser(
|
||||||
@P(value = "用户名") String username,
|
@P(value = "用户名") String name,
|
||||||
@P(value = "密码", required = false) String password,
|
@P(value = "密码", required = false) String password,
|
||||||
@P(value = "是否开启", required = false) Boolean enable) {
|
@P(value = "是否开启", required = false) Boolean enable) {
|
||||||
identityAccessService.upsertUser(new UserUpsertDto(null, username, password, enable));
|
identityAccessService.upsertUser(new UserUpsertDto(null, name, password, enable, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "给用户绑定/分配角色")
|
@Tool(value = {"给用户绑定角色", "给用户分配角色"})
|
||||||
void bindRoleToUser(
|
void bindRoleToUser(
|
||||||
@P(value = "用户名") String username, @P(value = "角色名称") List<String> roleNames) {
|
@P(value = "用户名") String username, @P(value = "角色名称") List<String> roleNames) {
|
||||||
User user = userRepository.fetchOneByUsername(username);
|
User user = checkUserExistBy(username);
|
||||||
if (user == null) {
|
|
||||||
throw new BusinessException("指定用户不存在");
|
|
||||||
}
|
|
||||||
List<Long> bindRoleIds = getRoleIdsBy(roleNames);
|
List<Long> bindRoleIds = getRoleIdsBy(roleNames);
|
||||||
identityAccessService.bindRoleToUser(user.getId(), bindRoleIds);
|
identityAccessService.bindRoleToUser(user.getId(), bindRoleIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "给用户解绑/撤销角色")
|
@Tool(value = {"给用户解绑角色", "给用户撤销角色"})
|
||||||
void unbindRoleToUser(
|
void unbindRoleToUser(
|
||||||
@P(value = "用户名") String username, @P(value = "角色名称") List<String> roleNames) {
|
@P(value = "用户名") String username, @P(value = "角色名称") List<String> roleNames) {
|
||||||
|
User user = checkUserExistBy(username);
|
||||||
|
List<Long> bindRoleIds = getRoleIdsBy(roleNames);
|
||||||
|
identityAccessService.unBindRoleToUser(user.getId(), bindRoleIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tool(value = {"给用户绑定部门", "给用户分配部门"})
|
||||||
|
void bindDepartmentToUser(
|
||||||
|
@P(value = "用户名") String username, @P(value = "部门名称列表") List<String> departmentNames) {
|
||||||
|
User user = checkUserExistBy(username);
|
||||||
|
List<Department> departments =
|
||||||
|
departmentRepository.fetchByName(departmentNames.toArray(String[]::new));
|
||||||
|
if (departments.isEmpty()) {
|
||||||
|
throw new BusinessException("指定部门不存在");
|
||||||
|
}
|
||||||
|
identityAccessService.bindDepartmentBy(
|
||||||
|
new DepartmentBindDto(user.getId(), departments.stream().map(Department::getId).toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tool(value = {"给用户解绑部门", "给用户撤销部门"})
|
||||||
|
void unbindDepartmentToUser(
|
||||||
|
@P(value = "用户名") String username, @P(value = "部门名称列表") List<String> departmentNames) {
|
||||||
|
User user = checkUserExistBy(username);
|
||||||
|
List<Department> departments =
|
||||||
|
departmentRepository.fetchByName(departmentNames.toArray(String[]::new));
|
||||||
|
if (departments.isEmpty()) {
|
||||||
|
throw new BusinessException("指定部门不存在");
|
||||||
|
}
|
||||||
|
identityAccessService.unBindDepartmentBy(
|
||||||
|
new DepartmentBindDto(user.getId(), departments.stream().map(Department::getId).toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private User checkUserExistBy(String username) {
|
||||||
User user = userRepository.fetchOneByUsername(username);
|
User user = userRepository.fetchOneByUsername(username);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
throw new BusinessException("指定用户不存在");
|
throw new BusinessException("指定用户不存在");
|
||||||
}
|
}
|
||||||
List<Long> bindRoleIds = getRoleIdsBy(roleNames);
|
return user;
|
||||||
identityAccessService.unBindRoleToUser(user.getId(), bindRoleIds);
|
}
|
||||||
|
|
||||||
|
@Tool(value = {"给用户绑定岗位", "给用户分配岗位"})
|
||||||
|
void bindPositionToUser(
|
||||||
|
@P(value = "用户名") String username, @P(value = "岗位名称列表") List<String> positionNames) {
|
||||||
|
User user = checkUserExistBy(username);
|
||||||
|
List<Position> positions = positionRepository.fetchByName(positionNames.toArray(String[]::new));
|
||||||
|
if (positions.isEmpty()) {
|
||||||
|
throw new BusinessException("指定岗位不存在");
|
||||||
|
}
|
||||||
|
identityAccessService.bindPositionBy(
|
||||||
|
new PositionBindDto(user.getId(), positions.stream().map(Position::getId).toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tool(value = {"给用户解绑岗位", "给用户撤销岗位"})
|
||||||
|
void unbindPositionToUser(
|
||||||
|
@P(value = "用户名") String username, @P(value = "岗位名称列表") List<String> positionNames) {
|
||||||
|
User user = checkUserExistBy(username);
|
||||||
|
List<Position> positions = positionRepository.fetchByName(positionNames.toArray(String[]::new));
|
||||||
|
if (positions.isEmpty()) {
|
||||||
|
throw new BusinessException("指定岗位不存在");
|
||||||
|
}
|
||||||
|
identityAccessService.unBindPositionBy(
|
||||||
|
new PositionBindDto(user.getId(), positions.stream().map(Position::getId).toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Long> getRoleIdsBy(List<String> roleNames) {
|
private List<Long> getRoleIdsBy(List<String> roleNames) {
|
||||||
@@ -81,33 +135,31 @@ public class UserRolePermissionOperatorTool {
|
|||||||
return roles.stream().map(Role::getId).toList();
|
return roles.stream().map(Role::getId).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "创建角色")
|
@Tool(value = {"创建角色", "创建系统角色"})
|
||||||
void createRole(
|
void createRole(
|
||||||
@P(value = "角色名称") String roleName, @P(value = "角色编码", required = false) String roleCode) {
|
@P(value = "角色名称") String name, @P(value = "角色编码", required = false) String code) {
|
||||||
if (StringUtils.isEmpty(roleCode)) {
|
if (StringUtils.isEmpty(code)) {
|
||||||
roleCode = roleName;
|
code = name;
|
||||||
}
|
}
|
||||||
if (identityAccessService.isRoleDuplicate(roleCode, roleName)) {
|
if (identityAccessService.isRoleDuplicate(code, name)) {
|
||||||
throw new BusinessException("角色已存在");
|
throw new BusinessException("角色已存在");
|
||||||
}
|
}
|
||||||
identityAccessService.upsertRole(new RoleUpsertDto(null, roleName, roleCode));
|
identityAccessService.upsertRole(new RoleUpsertDto(null, name, code));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "更新角色")
|
@Tool(value = "更新角色")
|
||||||
void updateRole(@P(value = "角色名称") String roleName, @P(value = "角色编码") String roleCode) {
|
void updateRole(@P(value = "角色名称") String name, @P(value = "角色编码") String code) {
|
||||||
identityAccessService.upsertRole(new RoleUpsertDto(null, roleName, roleCode));
|
identityAccessService.upsertRole(new RoleUpsertDto(null, name, code));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "更新权限")
|
@Tool(value = "更新权限")
|
||||||
void updatePermission(
|
void updatePermission(@P(value = "权限名称") String name, @P(value = "权限编码") String code) {
|
||||||
@P(value = "权限名称") String permissionName, @P(value = "权限编码") String permissionCode) {
|
identityAccessService.upsertPermission(new PermissionUpsertDto(null, name, code));
|
||||||
identityAccessService.upsertPermission(
|
|
||||||
new PermissionUpsertDto(null, permissionName, permissionCode));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "删除角色")
|
@Tool(value = "删除角色")
|
||||||
void deleteRole(@P(value = "角色名称") String roleName) {
|
void deleteRole(@P(value = "角色名称") String name) {
|
||||||
Role role = roleRepository.fetchOneByName(roleName);
|
Role role = roleRepository.fetchOneByName(name);
|
||||||
if (role == null) {
|
if (role == null) {
|
||||||
throw new BusinessException("指定角色不存在");
|
throw new BusinessException("指定角色不存在");
|
||||||
}
|
}
|
||||||
@@ -115,15 +167,15 @@ public class UserRolePermissionOperatorTool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "删除权限")
|
@Tool(value = "删除权限")
|
||||||
void deletePermission(@P(value = "权限名称") String permissionName) {
|
void deletePermission(@P(value = "权限名称") String name) {
|
||||||
Permission permission = permissionRepository.fetchOneByName(permissionName);
|
Permission permission = permissionRepository.fetchOneByName(name);
|
||||||
if (permission == null) {
|
if (permission == null) {
|
||||||
throw new BusinessException("指定权限不存在");
|
throw new BusinessException("指定权限不存在");
|
||||||
}
|
}
|
||||||
permissionRepository.deleteById(permission.getId());
|
permissionRepository.deleteById(permission.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "给角色绑定/分配权限")
|
@Tool(value = {"给角色绑定权限", "给用户分配权限"})
|
||||||
void bindPermissionToRole(
|
void bindPermissionToRole(
|
||||||
@P(value = "角色名称") String roleName, @P(value = "权限名称") List<String> permissionNames) {
|
@P(value = "角色名称") String roleName, @P(value = "权限名称") List<String> permissionNames) {
|
||||||
Role role = roleRepository.fetchOneByName(roleName);
|
Role role = roleRepository.fetchOneByName(roleName);
|
||||||
@@ -139,7 +191,7 @@ public class UserRolePermissionOperatorTool {
|
|||||||
role.getId(), permissions.stream().map(Permission::getId).toList());
|
role.getId(), permissions.stream().map(Permission::getId).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "给角色解绑/撤销权限")
|
@Tool(value = {"给角色解绑权限", "给角色撤销权限"})
|
||||||
void unBindPermissionToRole(
|
void unBindPermissionToRole(
|
||||||
@P(value = "角色名称") String roleName, @P(value = "权限名称") List<String> permissionNames) {
|
@P(value = "角色名称") String roleName, @P(value = "权限名称") List<String> permissionNames) {
|
||||||
Role role = roleRepository.fetchOneByName(roleName);
|
Role role = roleRepository.fetchOneByName(roleName);
|
||||||
@@ -157,15 +209,13 @@ public class UserRolePermissionOperatorTool {
|
|||||||
|
|
||||||
@Tool(value = "创建权限")
|
@Tool(value = "创建权限")
|
||||||
void createPermission(
|
void createPermission(
|
||||||
@P(value = "权限名称") String permissionName,
|
@P(value = "权限名称") String name, @P(value = "权限编码", required = false) String code) {
|
||||||
@P(value = "权限编码", required = false) String permissionCode) {
|
if (StringUtils.isEmpty(code)) {
|
||||||
if (StringUtils.isEmpty(permissionCode)) {
|
code = name;
|
||||||
permissionCode = permissionName;
|
|
||||||
}
|
}
|
||||||
if (identityAccessService.isPermissionDuplicate(permissionName, permissionName)) {
|
if (identityAccessService.isPermissionDuplicate(name, name)) {
|
||||||
throw new BusinessException("权限已存在");
|
throw new BusinessException("权限已存在");
|
||||||
}
|
}
|
||||||
identityAccessService.upsertPermission(
|
identityAccessService.upsertPermission(new PermissionUpsertDto(null, name, code));
|
||||||
new PermissionUpsertDto(null, permissionName, permissionCode));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.zl.mjga.component.PositionOperatorTool;
|
|||||||
import com.zl.mjga.component.UserRolePermissionOperatorTool;
|
import com.zl.mjga.component.UserRolePermissionOperatorTool;
|
||||||
import dev.langchain4j.community.model.zhipu.ZhipuAiStreamingChatModel;
|
import dev.langchain4j.community.model.zhipu.ZhipuAiStreamingChatModel;
|
||||||
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
|
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
|
||||||
|
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
|
||||||
import dev.langchain4j.service.AiServices;
|
import dev.langchain4j.service.AiServices;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@@ -28,4 +29,14 @@ public class ToolsInitializer {
|
|||||||
.tools(userRolePermissionOperatorTool, departmentOperatorTool, positionOperatorTool)
|
.tools(userRolePermissionOperatorTool, departmentOperatorTool, positionOperatorTool)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@DependsOn("flywayInitializer")
|
||||||
|
public SystemToolAssistant deepSeekToolAssistant(OpenAiStreamingChatModel deepSeekChatModel) {
|
||||||
|
return AiServices.builder(SystemToolAssistant.class)
|
||||||
|
.streamingChatModel(deepSeekChatModel)
|
||||||
|
.chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(10))
|
||||||
|
.tools(userRolePermissionOperatorTool, departmentOperatorTool, positionOperatorTool)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.zl.mjga.config.minio;
|
||||||
|
|
||||||
|
import io.minio.MinioClient;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@ConfigurationProperties(prefix = "minio")
|
||||||
|
@Slf4j
|
||||||
|
public class MinIoConfig {
|
||||||
|
private String endpoint;
|
||||||
|
private String accessKey;
|
||||||
|
private String secretKey;
|
||||||
|
private String defaultBucket;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MinioClient minioClient() {
|
||||||
|
return MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,8 +5,7 @@ import com.zl.mjga.dto.PageResponseDto;
|
|||||||
import com.zl.mjga.dto.ai.LlmQueryDto;
|
import com.zl.mjga.dto.ai.LlmQueryDto;
|
||||||
import com.zl.mjga.dto.ai.LlmVm;
|
import com.zl.mjga.dto.ai.LlmVm;
|
||||||
import com.zl.mjga.exception.BusinessException;
|
import com.zl.mjga.exception.BusinessException;
|
||||||
import com.zl.mjga.repository.DepartmentRepository;
|
import com.zl.mjga.repository.*;
|
||||||
import com.zl.mjga.repository.UserRepository;
|
|
||||||
import com.zl.mjga.service.AiChatService;
|
import com.zl.mjga.service.AiChatService;
|
||||||
import com.zl.mjga.service.EmbeddingService;
|
import com.zl.mjga.service.EmbeddingService;
|
||||||
import com.zl.mjga.service.LlmService;
|
import com.zl.mjga.service.LlmService;
|
||||||
@@ -20,9 +19,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jooq.generated.mjga.enums.LlmCodeEnum;
|
import org.jooq.generated.mjga.enums.LlmCodeEnum;
|
||||||
import org.jooq.generated.mjga.tables.pojos.AiLlmConfig;
|
import org.jooq.generated.mjga.tables.pojos.*;
|
||||||
import org.jooq.generated.mjga.tables.pojos.Department;
|
|
||||||
import org.jooq.generated.mjga.tables.pojos.User;
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
@@ -41,23 +38,35 @@ public class AiController {
|
|||||||
private final EmbeddingService embeddingService;
|
private final EmbeddingService embeddingService;
|
||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
private final DepartmentRepository departmentRepository;
|
private final DepartmentRepository departmentRepository;
|
||||||
|
private final PositionRepository positionRepository;
|
||||||
|
private final RoleRepository repository;
|
||||||
|
private final PermissionRepository permissionRepository;
|
||||||
|
private final RoleRepository roleRepository;
|
||||||
|
|
||||||
@PostMapping(value = "/action/execute", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
@PostMapping(value = "/action/execute", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||||
public Flux<String> actionExecute(Principal principal, @RequestBody String userMessage) {
|
public Flux<String> actionExecute(Principal principal, @RequestBody String userMessage) {
|
||||||
Sinks.Many<String> sink = Sinks.many().unicast().onBackpressureBuffer();
|
Sinks.Many<String> sink = Sinks.many().unicast().onBackpressureBuffer();
|
||||||
TokenStream chat = aiChatService.actionExecuteWithZhiPu(principal.getName(), userMessage);
|
TokenStream chat = aiChatService.actionPrecedenceExecuteWith(principal.getName(), userMessage);
|
||||||
chat.onPartialResponse(
|
chat.onPartialResponse(
|
||||||
text ->
|
(text) -> {
|
||||||
sink.tryEmitNext(
|
log.debug("ai action partialResponse: {}", text);
|
||||||
StringUtils.isNotEmpty(text) ? text.replace(" ", "␣").replace("\t", "⇥") : ""))
|
sink.tryEmitNext(
|
||||||
|
StringUtils.isNotEmpty(text) ? text.replace(" ", "␣").replace("\t", "⇥") : "");
|
||||||
|
})
|
||||||
.onToolExecuted(
|
.onToolExecuted(
|
||||||
toolExecution -> log.debug("当前请求 {} 成功执行函数调用: {}", userMessage, toolExecution))
|
toolExecution -> log.debug("当前请求 {} 成功执行函数调用: {}", userMessage, toolExecution))
|
||||||
.onCompleteResponse(
|
.onCompleteResponse(
|
||||||
r -> {
|
r -> {
|
||||||
|
log.debug("ai action completeResponse: {}", r);
|
||||||
|
sink.tryEmitComplete();
|
||||||
|
sink.emitComplete(Sinks.EmitFailureHandler.FAIL_FAST);
|
||||||
|
})
|
||||||
|
.onError(
|
||||||
|
(e) -> {
|
||||||
|
sink.tryEmitError(e);
|
||||||
sink.tryEmitComplete();
|
sink.tryEmitComplete();
|
||||||
sink.emitComplete(Sinks.EmitFailureHandler.FAIL_FAST);
|
sink.emitComplete(Sinks.EmitFailureHandler.FAIL_FAST);
|
||||||
})
|
})
|
||||||
.onError(sink::tryEmitError)
|
|
||||||
.start();
|
.start();
|
||||||
return sink.asFlux().timeout(Duration.ofSeconds(120));
|
return sink.asFlux().timeout(Duration.ofSeconds(120));
|
||||||
}
|
}
|
||||||
@@ -116,7 +125,7 @@ public class AiController {
|
|||||||
userRepository.deleteByUsername(username);
|
userRepository.deleteByUsername(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_DEPARTMENT_PERMISSION)")
|
||||||
@DeleteMapping("/action/department")
|
@DeleteMapping("/action/department")
|
||||||
void deleteDepartment(@RequestParam String name) {
|
void deleteDepartment(@RequestParam String name) {
|
||||||
Department department = departmentRepository.fetchOneByName(name);
|
Department department = departmentRepository.fetchOneByName(name);
|
||||||
@@ -125,4 +134,39 @@ public class AiController {
|
|||||||
}
|
}
|
||||||
departmentRepository.deleteByName(name);
|
departmentRepository.deleteByName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_POSITION_PERMISSION)")
|
||||||
|
@DeleteMapping("/action/position")
|
||||||
|
void deletePosition(@RequestParam String name) {
|
||||||
|
Position position = positionRepository.fetchOneByName(name);
|
||||||
|
if (position == null) {
|
||||||
|
throw new BusinessException("该岗位不存在");
|
||||||
|
}
|
||||||
|
positionRepository.deleteById(position.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
|
@DeleteMapping("/action/role")
|
||||||
|
void deleteRole(@RequestParam String name) {
|
||||||
|
Role role = roleRepository.fetchOneByName(name);
|
||||||
|
if (role == null) {
|
||||||
|
throw new BusinessException("该角色不存在");
|
||||||
|
}
|
||||||
|
roleRepository.deleteById(role.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
|
@DeleteMapping("/action/permission")
|
||||||
|
void deletePermission(@RequestParam String name) {
|
||||||
|
Permission permission = permissionRepository.fetchOneByName(name);
|
||||||
|
if (permission == null) {
|
||||||
|
throw new BusinessException("该权限不存在");
|
||||||
|
}
|
||||||
|
permissionRepository.deleteById(permission.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/chat/refresh")
|
||||||
|
void createNewConversation(Principal principal) {
|
||||||
|
aiChatService.evictChatMemory(principal.getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.zl.mjga.dto.PageRequestDto;
|
|||||||
import com.zl.mjga.dto.PageResponseDto;
|
import com.zl.mjga.dto.PageResponseDto;
|
||||||
import com.zl.mjga.dto.department.DepartmentQueryDto;
|
import com.zl.mjga.dto.department.DepartmentQueryDto;
|
||||||
import com.zl.mjga.dto.department.DepartmentRespDto;
|
import com.zl.mjga.dto.department.DepartmentRespDto;
|
||||||
|
import com.zl.mjga.dto.department.DepartmentWithParentDto;
|
||||||
import com.zl.mjga.repository.DepartmentRepository;
|
import com.zl.mjga.repository.DepartmentRepository;
|
||||||
import com.zl.mjga.service.DepartmentService;
|
import com.zl.mjga.service.DepartmentService;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -37,6 +38,12 @@ public class DepartmentController {
|
|||||||
return departmentService.queryAvailableParentDepartmentsBy(id);
|
return departmentService.queryAvailableParentDepartmentsBy(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).READ_DEPARTMENT_PERMISSION)")
|
||||||
|
@GetMapping("/query-sub")
|
||||||
|
List<DepartmentWithParentDto> querySubDepartment(@RequestParam(required = false) Long id) {
|
||||||
|
return departmentService.queryDepartmentAndSubsBy(id);
|
||||||
|
}
|
||||||
|
|
||||||
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_DEPARTMENT_PERMISSION)")
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_DEPARTMENT_PERMISSION)")
|
||||||
@DeleteMapping()
|
@DeleteMapping()
|
||||||
void deleteDepartment(@RequestParam Long id) {
|
void deleteDepartment(@RequestParam Long id) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.zl.mjga.controller;
|
package com.zl.mjga.controller;
|
||||||
|
|
||||||
|
import com.zl.mjga.config.minio.MinIoConfig;
|
||||||
import com.zl.mjga.dto.PageRequestDto;
|
import com.zl.mjga.dto.PageRequestDto;
|
||||||
import com.zl.mjga.dto.PageResponseDto;
|
import com.zl.mjga.dto.PageResponseDto;
|
||||||
import com.zl.mjga.dto.department.DepartmentBindDto;
|
import com.zl.mjga.dto.department.DepartmentBindDto;
|
||||||
@@ -12,17 +13,25 @@ import com.zl.mjga.repository.PermissionRepository;
|
|||||||
import com.zl.mjga.repository.RoleRepository;
|
import com.zl.mjga.repository.RoleRepository;
|
||||||
import com.zl.mjga.repository.UserRepository;
|
import com.zl.mjga.repository.UserRepository;
|
||||||
import com.zl.mjga.service.IdentityAccessService;
|
import com.zl.mjga.service.IdentityAccessService;
|
||||||
|
import io.minio.MinioClient;
|
||||||
|
import io.minio.PutObjectArgs;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jooq.generated.mjga.tables.pojos.User;
|
import org.jooq.generated.mjga.tables.pojos.User;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.security.authentication.DisabledException;
|
import org.springframework.security.authentication.DisabledException;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/iam")
|
@RequestMapping("/iam")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@@ -32,6 +41,50 @@ public class IdentityAccessController {
|
|||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
private final RoleRepository roleRepository;
|
private final RoleRepository roleRepository;
|
||||||
private final PermissionRepository permissionRepository;
|
private final PermissionRepository permissionRepository;
|
||||||
|
private final MinioClient minioClient;
|
||||||
|
private final MinIoConfig minIoConfig;
|
||||||
|
|
||||||
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
|
@PostMapping(
|
||||||
|
value = "/avatar/upload",
|
||||||
|
consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
|
||||||
|
produces = MediaType.TEXT_PLAIN_VALUE)
|
||||||
|
public String uploadAvatar(@RequestPart("file") MultipartFile multipartFile) throws Exception {
|
||||||
|
String originalFilename = multipartFile.getOriginalFilename();
|
||||||
|
if (StringUtils.isEmpty(originalFilename)) {
|
||||||
|
throw new BusinessException("文件名不能为空");
|
||||||
|
}
|
||||||
|
String contentType = multipartFile.getContentType();
|
||||||
|
String extension = "";
|
||||||
|
if ("image/jpeg".equals(contentType)) {
|
||||||
|
extension = ".jpg";
|
||||||
|
} else if ("image/png".equals(contentType)) {
|
||||||
|
extension = ".png";
|
||||||
|
}
|
||||||
|
String objectName =
|
||||||
|
String.format(
|
||||||
|
"/avatar/%d%s%s",
|
||||||
|
Instant.now().toEpochMilli(),
|
||||||
|
RandomStringUtils.insecure().nextAlphabetic(6),
|
||||||
|
extension);
|
||||||
|
if (multipartFile.isEmpty()) {
|
||||||
|
throw new BusinessException("上传的文件不能为空");
|
||||||
|
}
|
||||||
|
long size = multipartFile.getSize();
|
||||||
|
if (size > 200 * 1024) {
|
||||||
|
throw new BusinessException("头像文件大小不能超过200KB");
|
||||||
|
}
|
||||||
|
BufferedImage img = ImageIO.read(multipartFile.getInputStream());
|
||||||
|
if (img == null) {
|
||||||
|
throw new BusinessException("非法的上传文件");
|
||||||
|
}
|
||||||
|
minioClient.putObject(
|
||||||
|
PutObjectArgs.builder().bucket(minIoConfig.getDefaultBucket()).object(objectName).stream(
|
||||||
|
multipartFile.getInputStream(), size, -1)
|
||||||
|
.contentType(multipartFile.getContentType())
|
||||||
|
.build());
|
||||||
|
return objectName;
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/me")
|
@GetMapping("/me")
|
||||||
UserRolePermissionDto currentUser(Principal principal) {
|
UserRolePermissionDto currentUser(Principal principal) {
|
||||||
@@ -66,9 +119,6 @@ public class IdentityAccessController {
|
|||||||
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
@DeleteMapping("/user")
|
@DeleteMapping("/user")
|
||||||
void deleteUser(@RequestParam Long userId) {
|
void deleteUser(@RequestParam Long userId) {
|
||||||
if (userId == 1) {
|
|
||||||
throw new BusinessException("演示系统不允许操作管理员角色");
|
|
||||||
}
|
|
||||||
userRepository.deleteById(userId);
|
userRepository.deleteById(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,15 +131,12 @@ public class IdentityAccessController {
|
|||||||
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
@DeleteMapping("/role")
|
@DeleteMapping("/role")
|
||||||
void deleteRole(@RequestParam Long roleId) {
|
void deleteRole(@RequestParam Long roleId) {
|
||||||
if (roleId == 1) {
|
|
||||||
throw new BusinessException("演示系统不允许删除管理员角色");
|
|
||||||
}
|
|
||||||
roleRepository.deleteById(roleId);
|
roleRepository.deleteById(roleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
@GetMapping("/role")
|
@GetMapping("/role")
|
||||||
RoleDto queryRoleWithPermission(@RequestParam Long roleId) {
|
RoleRespDto queryRoleWithPermission(@RequestParam Long roleId) {
|
||||||
return identityAccessService.queryUniqueRoleWithPermission(roleId);
|
return identityAccessService.queryUniqueRoleWithPermission(roleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,9 +149,6 @@ public class IdentityAccessController {
|
|||||||
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
@DeleteMapping("/permission")
|
@DeleteMapping("/permission")
|
||||||
void deletePermission(@RequestParam Long permissionId) {
|
void deletePermission(@RequestParam Long permissionId) {
|
||||||
if (permissionId < 10) {
|
|
||||||
throw new BusinessException("演示系统不允许删除原有权限");
|
|
||||||
}
|
|
||||||
permissionRepository.deleteById(permissionId);
|
permissionRepository.deleteById(permissionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +163,7 @@ public class IdentityAccessController {
|
|||||||
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).READ_USER_ROLE_PERMISSION)")
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).READ_USER_ROLE_PERMISSION)")
|
||||||
@GetMapping("/roles")
|
@GetMapping("/roles")
|
||||||
@ResponseStatus(HttpStatus.OK)
|
@ResponseStatus(HttpStatus.OK)
|
||||||
PageResponseDto<List<RoleDto>> queryRoles(
|
PageResponseDto<List<RoleRespDto>> queryRoles(
|
||||||
@ModelAttribute PageRequestDto pageRequestDto, @ModelAttribute RoleQueryDto roleQueryDto) {
|
@ModelAttribute PageRequestDto pageRequestDto, @ModelAttribute RoleQueryDto roleQueryDto) {
|
||||||
return identityAccessService.pageQueryRole(pageRequestDto, roleQueryDto);
|
return identityAccessService.pageQueryRole(pageRequestDto, roleQueryDto);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ public class PageRequestDto {
|
|||||||
.sort(SortOrder.valueOf(entry.getValue().getKeyword())))
|
.sort(SortOrder.valueOf(entry.getValue().getKeyword())))
|
||||||
.toList();
|
.toList();
|
||||||
if (sortFields.isEmpty()) {
|
if (sortFields.isEmpty()) {
|
||||||
return List.of(field(name("id")).sort(SortOrder.ASC));
|
return List.of(field(name("id")).sort(SortOrder.DESC));
|
||||||
} else {
|
} else {
|
||||||
return sortFields;
|
return sortFields;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import lombok.*;
|
|||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
public class PermissionRespDto {
|
public class PermissionRespDto {
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
private String code;
|
private String code;
|
||||||
private String name;
|
private String name;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.zl.mjga.dto.urp;
|
package com.zl.mjga.dto.urp;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
@@ -8,10 +9,18 @@ import lombok.*;
|
|||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
public class RoleDto {
|
public class RoleRespDto {
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String code;
|
private String code;
|
||||||
|
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private Boolean isBound;
|
private Boolean isBound;
|
||||||
|
|
||||||
@Builder.Default List<PermissionRespDto> permissions = new LinkedList<>();
|
@Builder.Default List<PermissionRespDto> permissions = new LinkedList<>();
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.zl.mjga.dto.urp;
|
package com.zl.mjga.dto.urp;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@@ -7,4 +8,6 @@ import lombok.*;
|
|||||||
@Data
|
@Data
|
||||||
public class UserQueryDto {
|
public class UserQueryDto {
|
||||||
private String username;
|
private String username;
|
||||||
|
private OffsetDateTime startDate;
|
||||||
|
private OffsetDateTime endDate;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.zl.mjga.dto.urp;
|
package com.zl.mjga.dto.urp;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -13,15 +14,24 @@ import lombok.*;
|
|||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
public class UserRolePermissionDto {
|
public class UserRolePermissionDto {
|
||||||
|
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String username;
|
private String username;
|
||||||
|
|
||||||
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
|
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
private Boolean enable;
|
private String avatar;
|
||||||
@Builder.Default private List<RoleDto> roles = new LinkedList<>();
|
|
||||||
|
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private Boolean enable;
|
||||||
|
|
||||||
|
@Builder.Default private List<RoleRespDto> roles = new LinkedList<>();
|
||||||
|
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private OffsetDateTime createTime;
|
private OffsetDateTime createTime;
|
||||||
|
|
||||||
public Set<PermissionRespDto> getPermissions() {
|
public Set<PermissionRespDto> getPermissions() {
|
||||||
|
|||||||
@@ -14,4 +14,5 @@ public class UserUpsertDto {
|
|||||||
@NotEmpty private String username;
|
@NotEmpty private String username;
|
||||||
private String password;
|
private String password;
|
||||||
@NotNull private Boolean enable;
|
@NotNull private Boolean enable;
|
||||||
|
private String avatar;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,15 @@ import lombok.Getter;
|
|||||||
@Getter
|
@Getter
|
||||||
public enum Actions {
|
public enum Actions {
|
||||||
CREATE_USER("CREATE_USER", "创建用户"),
|
CREATE_USER("CREATE_USER", "创建用户"),
|
||||||
CREATE_DEPARTMENT("CREATE_DEPARTMENT", "创建部门"),
|
|
||||||
DELETE_USER("DELETE_USER", "删除用户"),
|
DELETE_USER("DELETE_USER", "删除用户"),
|
||||||
DELETE_DEPARTMENT("DELETE_DEPARTMENT", "删除部门");
|
CREATE_DEPARTMENT("CREATE_DEPARTMENT", "创建部门"),
|
||||||
|
DELETE_DEPARTMENT("DELETE_DEPARTMENT", "删除部门"),
|
||||||
|
CREATE_POSITION("CREATE_POSITION", "创建岗位"),
|
||||||
|
DELETE_POSITION("DELETE_POSITION", "删除岗位"),
|
||||||
|
CREATE_ROLE("CREATE_ROLE", "创建角色"),
|
||||||
|
DELETE_ROLE("CREATE_ROLE", "删除角色"),
|
||||||
|
CREATE_PERMISSION("CREATE_PERMISSION", "创建权限"),
|
||||||
|
DELETE_PERMISSION("DELETE_PERMISSION", "删除权限");
|
||||||
public static final String INDEX_KEY = "action";
|
public static final String INDEX_KEY = "action";
|
||||||
private final String code;
|
private final String code;
|
||||||
private final String content;
|
private final String content;
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ public class DepartmentRepository extends DepartmentDao {
|
|||||||
DEPARTMENT.PARENT_ID,
|
DEPARTMENT.PARENT_ID,
|
||||||
DEPARTMENT.NAME.cast(VARCHAR))
|
DEPARTMENT.NAME.cast(VARCHAR))
|
||||||
.from(DEPARTMENT)
|
.from(DEPARTMENT)
|
||||||
.where(DEPARTMENT.ID.eq(id))
|
.where(id == null ? noCondition() : DEPARTMENT.ID.eq(id))
|
||||||
|
.and(DEPARTMENT.PARENT_ID.isNull())
|
||||||
.unionAll(
|
.unionAll(
|
||||||
select(
|
select(
|
||||||
DEPARTMENT.ID,
|
DEPARTMENT.ID,
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package com.zl.mjga.repository;
|
package com.zl.mjga.repository;
|
||||||
|
|
||||||
import static org.jooq.generated.mjga.Tables.*;
|
|
||||||
import static org.jooq.generated.mjga.tables.User.USER;
|
import static org.jooq.generated.mjga.tables.User.USER;
|
||||||
import static org.jooq.impl.DSL.*;
|
import static org.jooq.impl.DSL.*;
|
||||||
|
|
||||||
import com.zl.mjga.dto.PageRequestDto;
|
import com.zl.mjga.dto.PageRequestDto;
|
||||||
import com.zl.mjga.dto.urp.PermissionRespDto;
|
import com.zl.mjga.dto.urp.PermissionRespDto;
|
||||||
import com.zl.mjga.dto.urp.RoleDto;
|
import com.zl.mjga.dto.urp.RoleRespDto;
|
||||||
import com.zl.mjga.dto.urp.UserQueryDto;
|
import com.zl.mjga.dto.urp.UserQueryDto;
|
||||||
import com.zl.mjga.dto.urp.UserRolePermissionDto;
|
import com.zl.mjga.dto.urp.UserRolePermissionDto;
|
||||||
|
import java.util.List;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jooq.*;
|
import org.jooq.*;
|
||||||
import org.jooq.Record;
|
import org.jooq.Record;
|
||||||
@@ -36,6 +36,7 @@ public class UserRepository extends UserDao {
|
|||||||
value(user.getId()).as("id"),
|
value(user.getId()).as("id"),
|
||||||
value(user.getUsername()).as("username"),
|
value(user.getUsername()).as("username"),
|
||||||
value(user.getPassword()).as("password"),
|
value(user.getPassword()).as("password"),
|
||||||
|
value(user.getAvatar()).as("avatar"),
|
||||||
value(user.getEnable()).as("enable"))
|
value(user.getEnable()).as("enable"))
|
||||||
.asTable("newUser"))
|
.asTable("newUser"))
|
||||||
.on(USER.ID.eq(DSL.field(DSL.name("newUser", "id"), Long.class)))
|
.on(USER.ID.eq(DSL.field(DSL.name("newUser", "id"), Long.class)))
|
||||||
@@ -46,16 +47,18 @@ public class UserRepository extends UserDao {
|
|||||||
StringUtils.isNotEmpty(user.getPassword())
|
StringUtils.isNotEmpty(user.getPassword())
|
||||||
? DSL.field(DSL.name("newUser", "password"), String.class)
|
? DSL.field(DSL.name("newUser", "password"), String.class)
|
||||||
: USER.PASSWORD)
|
: USER.PASSWORD)
|
||||||
|
.set(USER.AVATAR, DSL.field(DSL.name("newUser", "avatar"), String.class))
|
||||||
.set(USER.ENABLE, DSL.field(DSL.name("newUser", "enable"), Boolean.class))
|
.set(USER.ENABLE, DSL.field(DSL.name("newUser", "enable"), Boolean.class))
|
||||||
.whenNotMatchedThenInsert(USER.USERNAME, USER.PASSWORD, USER.ENABLE)
|
.whenNotMatchedThenInsert(USER.USERNAME, USER.PASSWORD, USER.AVATAR, USER.ENABLE)
|
||||||
.values(
|
.values(
|
||||||
DSL.field(DSL.name("newUser", "username"), String.class),
|
DSL.field(DSL.name("newUser", "username"), String.class),
|
||||||
DSL.field(DSL.name("newUser", "password"), String.class),
|
DSL.field(DSL.name("newUser", "password"), String.class),
|
||||||
|
DSL.field(DSL.name("newUser", "avatar"), String.class),
|
||||||
DSL.field(DSL.name("newUser", "enable"), Boolean.class))
|
DSL.field(DSL.name("newUser", "enable"), Boolean.class))
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result<Record> pageFetchBy(PageRequestDto pageRequestDto, UserQueryDto userQueryDto) {
|
public SelectConditionStep<Record> selectBy(UserQueryDto userQueryDto) {
|
||||||
return ctx()
|
return ctx()
|
||||||
.select(asterisk(), DSL.count().over().as("total_user"))
|
.select(asterisk(), DSL.count().over().as("total_user"))
|
||||||
.from(USER)
|
.from(USER)
|
||||||
@@ -63,6 +66,22 @@ public class UserRepository extends UserDao {
|
|||||||
userQueryDto.getUsername() != null
|
userQueryDto.getUsername() != null
|
||||||
? USER.USERNAME.like("%" + userQueryDto.getUsername() + "%")
|
? USER.USERNAME.like("%" + userQueryDto.getUsername() + "%")
|
||||||
: noCondition())
|
: noCondition())
|
||||||
|
.and(
|
||||||
|
userQueryDto.getStartDate() != null
|
||||||
|
? USER.CREATE_TIME.ge(userQueryDto.getStartDate())
|
||||||
|
: noCondition())
|
||||||
|
.and(
|
||||||
|
userQueryDto.getEndDate() != null
|
||||||
|
? USER.CREATE_TIME.le(userQueryDto.getEndDate())
|
||||||
|
: noCondition());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<User> fetchBy(UserQueryDto userQueryDto) {
|
||||||
|
return selectBy(userQueryDto).fetchInto(User.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<Record> pageFetchBy(PageRequestDto pageRequestDto, UserQueryDto userQueryDto) {
|
||||||
|
return selectBy(userQueryDto)
|
||||||
.orderBy(pageRequestDto.getSortFields())
|
.orderBy(pageRequestDto.getSortFields())
|
||||||
.limit(pageRequestDto.getSize())
|
.limit(pageRequestDto.getSize())
|
||||||
.offset(pageRequestDto.getOffset())
|
.offset(pageRequestDto.getOffset())
|
||||||
@@ -83,7 +102,7 @@ public class UserRepository extends UserDao {
|
|||||||
r -> r.map((record) -> record.into(PermissionRespDto.class)))
|
r -> r.map((record) -> record.into(PermissionRespDto.class)))
|
||||||
.as("permissions"))
|
.as("permissions"))
|
||||||
.from(USER.role()))
|
.from(USER.role()))
|
||||||
.convertFrom(r -> r.map((record) -> record.into(RoleDto.class)))
|
.convertFrom(r -> r.map((record) -> record.into(RoleRespDto.class)))
|
||||||
.as("roles"))
|
.as("roles"))
|
||||||
.from(USER)
|
.from(USER)
|
||||||
.where(USER.ID.eq(userId))
|
.where(USER.ID.eq(userId))
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ public class AiChatService {
|
|||||||
private final AiChatAssistant deepSeekChatAssistant;
|
private final AiChatAssistant deepSeekChatAssistant;
|
||||||
private final AiChatAssistant zhiPuChatAssistant;
|
private final AiChatAssistant zhiPuChatAssistant;
|
||||||
private final SystemToolAssistant zhiPuToolAssistant;
|
private final SystemToolAssistant zhiPuToolAssistant;
|
||||||
|
private final SystemToolAssistant deepSeekToolAssistant;
|
||||||
private final LlmService llmService;
|
private final LlmService llmService;
|
||||||
|
|
||||||
public TokenStream chatWithDeepSeek(String sessionIdentifier, String userMessage) {
|
public TokenStream chatWithDeepSeek(String sessionIdentifier, String userMessage) {
|
||||||
@@ -29,8 +30,13 @@ public class AiChatService {
|
|||||||
return zhiPuChatAssistant.chat(sessionIdentifier, userMessage);
|
return zhiPuChatAssistant.chat(sessionIdentifier, userMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TokenStream actionExecuteWithZhiPu(String sessionIdentifier, String userMessage) {
|
public TokenStream actionPrecedenceExecuteWith(String sessionIdentifier, String userMessage) {
|
||||||
return zhiPuToolAssistant.ask(sessionIdentifier, userMessage);
|
LlmCodeEnum code = getPrecedenceLlmCode();
|
||||||
|
return switch (code) {
|
||||||
|
case ZHI_PU -> zhiPuToolAssistant.ask(sessionIdentifier, userMessage);
|
||||||
|
case DEEP_SEEK -> deepSeekToolAssistant.ask(sessionIdentifier, userMessage);
|
||||||
|
default -> throw new BusinessException(String.format("无效的模型代码 %s", code));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public TokenStream chatPrecedenceLlmWith(String sessionIdentifier, String userMessage) {
|
public TokenStream chatPrecedenceLlmWith(String sessionIdentifier, String userMessage) {
|
||||||
@@ -47,4 +53,11 @@ public class AiChatService {
|
|||||||
AiLlmConfig aiLlmConfig = precedenceLlmBy.orElseThrow(() -> new BusinessException("没有开启的大模型"));
|
AiLlmConfig aiLlmConfig = precedenceLlmBy.orElseThrow(() -> new BusinessException("没有开启的大模型"));
|
||||||
return aiLlmConfig.getCode();
|
return aiLlmConfig.getCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void evictChatMemory(String sessionIdentifier) {
|
||||||
|
deepSeekChatAssistant.evictChatMemory(sessionIdentifier);
|
||||||
|
zhiPuChatAssistant.evictChatMemory(sessionIdentifier);
|
||||||
|
zhiPuToolAssistant.evictChatMemory(sessionIdentifier);
|
||||||
|
deepSeekToolAssistant.evictChatMemory(sessionIdentifier);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,17 +80,17 @@ public class IdentityAccessService {
|
|||||||
return userRepository.fetchUniqueUserDtoWithNestedRolePermissionBy(userId);
|
return userRepository.fetchUniqueUserDtoWithNestedRolePermissionBy(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PageResponseDto<List<RoleDto>> pageQueryRole(
|
public PageResponseDto<List<RoleRespDto>> pageQueryRole(
|
||||||
PageRequestDto pageRequestDto, RoleQueryDto roleQueryDto) {
|
PageRequestDto pageRequestDto, RoleQueryDto roleQueryDto) {
|
||||||
Result<Record> roleRecords = roleRepository.pageFetchBy(pageRequestDto, roleQueryDto);
|
Result<Record> roleRecords = roleRepository.pageFetchBy(pageRequestDto, roleQueryDto);
|
||||||
if (roleRecords.isEmpty()) {
|
if (roleRecords.isEmpty()) {
|
||||||
return PageResponseDto.empty();
|
return PageResponseDto.empty();
|
||||||
}
|
}
|
||||||
List<RoleDto> roleDtoList =
|
List<RoleRespDto> roleRespDtoList =
|
||||||
roleRecords.stream()
|
roleRecords.stream()
|
||||||
.map(
|
.map(
|
||||||
record -> {
|
record -> {
|
||||||
return RoleDto.builder()
|
return RoleRespDto.builder()
|
||||||
.id(record.getValue("id", Long.class))
|
.id(record.getValue("id", Long.class))
|
||||||
.code(record.getValue("code", String.class))
|
.code(record.getValue("code", String.class))
|
||||||
.name(record.getValue("name", String.class))
|
.name(record.getValue("name", String.class))
|
||||||
@@ -103,17 +103,17 @@ public class IdentityAccessService {
|
|||||||
})
|
})
|
||||||
.toList();
|
.toList();
|
||||||
return new PageResponseDto<>(
|
return new PageResponseDto<>(
|
||||||
roleRecords.get(0).getValue("total_role", Integer.class), roleDtoList);
|
roleRecords.get(0).getValue("total_role", Integer.class), roleRespDtoList);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable RoleDto queryUniqueRoleWithPermission(Long roleId) {
|
public @Nullable RoleRespDto queryUniqueRoleWithPermission(Long roleId) {
|
||||||
Result<Record> roleWithPermissionRecords = roleRepository.fetchUniqueRoleWithPermission(roleId);
|
Result<Record> roleWithPermissionRecords = roleRepository.fetchUniqueRoleWithPermission(roleId);
|
||||||
if (roleWithPermissionRecords.isEmpty()) {
|
if (roleWithPermissionRecords.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
RoleDto roleDto = createRbacDtoRolePart(roleWithPermissionRecords);
|
RoleRespDto roleRespDto = createRbacDtoRolePart(roleWithPermissionRecords);
|
||||||
setCurrentRolePermission(roleDto, roleWithPermissionRecords);
|
setCurrentRolePermission(roleRespDto, roleWithPermissionRecords);
|
||||||
return roleDto;
|
return roleRespDto;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PageResponseDto<List<PermissionRespDto>> pageQueryPermission(
|
public PageResponseDto<List<PermissionRespDto>> pageQueryPermission(
|
||||||
@@ -199,12 +199,12 @@ public class IdentityAccessService {
|
|||||||
.toList());
|
.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCurrentRolePermission(RoleDto roleDto, List<Record> roleResult) {
|
private void setCurrentRolePermission(RoleRespDto roleRespDto, List<Record> roleResult) {
|
||||||
if (roleResult.get(0).getValue(PERMISSION.ID) != null) {
|
if (roleResult.get(0).getValue(PERMISSION.ID) != null) {
|
||||||
roleResult.forEach(
|
roleResult.forEach(
|
||||||
(record) -> {
|
(record) -> {
|
||||||
PermissionRespDto permissionRespDto = createRbacDtoPermissionPart(record);
|
PermissionRespDto permissionRespDto = createRbacDtoPermissionPart(record);
|
||||||
roleDto.getPermissions().add(permissionRespDto);
|
roleRespDto.getPermissions().add(permissionRespDto);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,12 +217,12 @@ public class IdentityAccessService {
|
|||||||
return permissionRespDto;
|
return permissionRespDto;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RoleDto createRbacDtoRolePart(List<Record> roleResult) {
|
private RoleRespDto createRbacDtoRolePart(List<Record> roleResult) {
|
||||||
RoleDto roleDto = new RoleDto();
|
RoleRespDto roleRespDto = new RoleRespDto();
|
||||||
roleDto.setId(roleResult.get(0).getValue(ROLE.ID));
|
roleRespDto.setId(roleResult.get(0).getValue(ROLE.ID));
|
||||||
roleDto.setCode(roleResult.get(0).getValue(ROLE.CODE));
|
roleRespDto.setCode(roleResult.get(0).getValue(ROLE.CODE));
|
||||||
roleDto.setName(roleResult.get(0).getValue(ROLE.NAME));
|
roleRespDto.setName(roleResult.get(0).getValue(ROLE.NAME));
|
||||||
return roleDto;
|
return roleRespDto;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRoleDuplicate(String roleCode, String name) {
|
public boolean isRoleDuplicate(String roleCode, String name) {
|
||||||
|
|||||||
@@ -27,9 +27,18 @@ spring:
|
|||||||
enabled: true
|
enabled: true
|
||||||
locations: classpath:db/migration
|
locations: classpath:db/migration
|
||||||
default-schema: ${DATABASE_DEFAULT_SCHEMA}
|
default-schema: ${DATABASE_DEFAULT_SCHEMA}
|
||||||
|
servlet:
|
||||||
|
multipart:
|
||||||
|
max-file-size: 1MB
|
||||||
|
max-request-size: 10MB
|
||||||
springdoc:
|
springdoc:
|
||||||
swagger-ui:
|
swagger-ui:
|
||||||
path: /swagger-ui.html
|
path: /swagger-ui.html
|
||||||
jwt:
|
jwt:
|
||||||
secret: ${JWT_SECRET:secret}
|
secret: ${JWT_SECRET:secret}
|
||||||
expiration-min: ${JWT_EXPIRATION_MIN:100}
|
expiration-min: ${JWT_EXPIRATION_MIN:100}
|
||||||
|
minio:
|
||||||
|
endpoint: ${MINIO_ENDPOINT}
|
||||||
|
access-key: ${MINIO_ROOT_USER}
|
||||||
|
secret-key: ${MINIO_ROOT_PASSWORD}
|
||||||
|
default-bucket: ${MINIO_DEFAULT_BUCKETS}
|
||||||
@@ -3,7 +3,8 @@ CREATE SCHEMA IF NOT EXISTS mjga;
|
|||||||
CREATE TABLE mjga.user (
|
CREATE TABLE mjga.user (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
username VARCHAR NOT NULL UNIQUE,
|
username VARCHAR NOT NULL UNIQUE,
|
||||||
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
avatar VARCHAR,
|
||||||
|
create_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
password VARCHAR NOT NULL,
|
password VARCHAR NOT NULL,
|
||||||
enable BOOLEAN NOT NULL DEFAULT TRUE
|
enable BOOLEAN NOT NULL DEFAULT TRUE
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
|
|||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
import com.zl.mjga.config.minio.MinIoConfig;
|
||||||
import com.zl.mjga.config.security.HttpFireWallConfig;
|
import com.zl.mjga.config.security.HttpFireWallConfig;
|
||||||
import com.zl.mjga.controller.IdentityAccessController;
|
import com.zl.mjga.controller.IdentityAccessController;
|
||||||
import com.zl.mjga.dto.PageRequestDto;
|
import com.zl.mjga.dto.PageRequestDto;
|
||||||
@@ -15,6 +16,7 @@ import com.zl.mjga.repository.PermissionRepository;
|
|||||||
import com.zl.mjga.repository.RoleRepository;
|
import com.zl.mjga.repository.RoleRepository;
|
||||||
import com.zl.mjga.repository.UserRepository;
|
import com.zl.mjga.repository.UserRepository;
|
||||||
import com.zl.mjga.service.IdentityAccessService;
|
import com.zl.mjga.service.IdentityAccessService;
|
||||||
|
import io.minio.MinioClient;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -34,6 +36,8 @@ public class JacksonAnnotationMvcTest {
|
|||||||
@MockBean private UserRepository userRepository;
|
@MockBean private UserRepository userRepository;
|
||||||
@MockBean private RoleRepository roleRepository;
|
@MockBean private RoleRepository roleRepository;
|
||||||
@MockBean private PermissionRepository permissionRepository;
|
@MockBean private PermissionRepository permissionRepository;
|
||||||
|
@MockBean private MinioClient minioClient;
|
||||||
|
@MockBean private MinIoConfig minIoConfig;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@WithMockUser
|
@WithMockUser
|
||||||
@@ -46,7 +50,7 @@ public class JacksonAnnotationMvcTest {
|
|||||||
stubUserRolePermissionDto.setUsername(stubUsername);
|
stubUserRolePermissionDto.setUsername(stubUsername);
|
||||||
stubUserRolePermissionDto.setPassword(stubPassword);
|
stubUserRolePermissionDto.setPassword(stubPassword);
|
||||||
when(identityAccessService.pageQueryUser(
|
when(identityAccessService.pageQueryUser(
|
||||||
PageRequestDto.of(1, 5), new UserQueryDto(stubUsername)))
|
PageRequestDto.of(1, 5), new UserQueryDto(stubUsername, null, null)))
|
||||||
.thenReturn(new PageResponseDto<>(1, List.of(stubUserRolePermissionDto)));
|
.thenReturn(new PageResponseDto<>(1, List.of(stubUserRolePermissionDto)));
|
||||||
mockMvc
|
mockMvc
|
||||||
.perform(
|
.perform(
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.zl.mjga.config.minio.MinIoConfig;
|
||||||
import com.zl.mjga.config.security.HttpFireWallConfig;
|
import com.zl.mjga.config.security.HttpFireWallConfig;
|
||||||
import com.zl.mjga.controller.IdentityAccessController;
|
import com.zl.mjga.controller.IdentityAccessController;
|
||||||
import com.zl.mjga.dto.PageRequestDto;
|
import com.zl.mjga.dto.PageRequestDto;
|
||||||
@@ -16,6 +17,7 @@ import com.zl.mjga.repository.PermissionRepository;
|
|||||||
import com.zl.mjga.repository.RoleRepository;
|
import com.zl.mjga.repository.RoleRepository;
|
||||||
import com.zl.mjga.repository.UserRepository;
|
import com.zl.mjga.repository.UserRepository;
|
||||||
import com.zl.mjga.service.IdentityAccessService;
|
import com.zl.mjga.service.IdentityAccessService;
|
||||||
|
import io.minio.MinioClient;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.jooq.generated.mjga.tables.pojos.User;
|
import org.jooq.generated.mjga.tables.pojos.User;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -36,6 +38,8 @@ class UserRolePermissionMvcTest {
|
|||||||
@MockBean private UserRepository userRepository;
|
@MockBean private UserRepository userRepository;
|
||||||
@MockBean private RoleRepository roleRepository;
|
@MockBean private RoleRepository roleRepository;
|
||||||
@MockBean private PermissionRepository permissionRepository;
|
@MockBean private PermissionRepository permissionRepository;
|
||||||
|
@MockBean private MinioClient minioClient;
|
||||||
|
@MockBean private MinIoConfig minIoConfig;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@WithMockUser
|
@WithMockUser
|
||||||
@@ -59,7 +63,7 @@ class UserRolePermissionMvcTest {
|
|||||||
@Test
|
@Test
|
||||||
@WithMockUser
|
@WithMockUser
|
||||||
void deleteUser_givenValidHttpRequest_shouldSucceedWith200() throws Exception {
|
void deleteUser_givenValidHttpRequest_shouldSucceedWith200() throws Exception {
|
||||||
Long stubUserId = 1L;
|
Long stubUserId = 2L;
|
||||||
mockMvc
|
mockMvc
|
||||||
.perform(
|
.perform(
|
||||||
delete(String.format("/iam/user?userId=%s", stubUserId))
|
delete(String.format("/iam/user?userId=%s", stubUserId))
|
||||||
@@ -152,7 +156,7 @@ class UserRolePermissionMvcTest {
|
|||||||
stubUserRolePermissionDto.setId(1L);
|
stubUserRolePermissionDto.setId(1L);
|
||||||
stubUserRolePermissionDto.setUsername(stubUsername);
|
stubUserRolePermissionDto.setUsername(stubUsername);
|
||||||
when(identityAccessService.pageQueryUser(
|
when(identityAccessService.pageQueryUser(
|
||||||
PageRequestDto.of(1, 5), new UserQueryDto(stubUsername)))
|
PageRequestDto.of(1, 5), new UserQueryDto(stubUsername, null, null)))
|
||||||
.thenReturn(new PageResponseDto<>(1, List.of(stubUserRolePermissionDto)));
|
.thenReturn(new PageResponseDto<>(1, List.of(stubUserRolePermissionDto)));
|
||||||
mockMvc
|
mockMvc
|
||||||
.perform(
|
.perform(
|
||||||
@@ -174,14 +178,14 @@ class UserRolePermissionMvcTest {
|
|||||||
stubRoleQueryDto.setRoleId(stubRoleId);
|
stubRoleQueryDto.setRoleId(stubRoleId);
|
||||||
stubRoleQueryDto.setRoleCode(stubRoleCode);
|
stubRoleQueryDto.setRoleCode(stubRoleCode);
|
||||||
stubRoleQueryDto.setRoleName(stubRoleName);
|
stubRoleQueryDto.setRoleName(stubRoleName);
|
||||||
RoleDto stubRoleDto = new RoleDto();
|
RoleRespDto stubRoleRespDto = new RoleRespDto();
|
||||||
stubRoleDto.setId(1L);
|
stubRoleRespDto.setId(1L);
|
||||||
stubRoleDto.setName(stubRoleName);
|
stubRoleRespDto.setName(stubRoleName);
|
||||||
stubRoleDto.setCode(stubRoleCode);
|
stubRoleRespDto.setCode(stubRoleCode);
|
||||||
stubRoleDto.setPermissions(
|
stubRoleRespDto.setPermissions(
|
||||||
List.of(new PermissionRespDto(1L, "9VWU1nmU89zEVH", "9VWU1nmU89zEVH", false)));
|
List.of(new PermissionRespDto(1L, "9VWU1nmU89zEVH", "9VWU1nmU89zEVH", false)));
|
||||||
when(identityAccessService.pageQueryRole(PageRequestDto.of(1, 5), stubRoleQueryDto))
|
when(identityAccessService.pageQueryRole(PageRequestDto.of(1, 5), stubRoleQueryDto))
|
||||||
.thenReturn(new PageResponseDto<>(1, List.of(stubRoleDto)));
|
.thenReturn(new PageResponseDto<>(1, List.of(stubRoleRespDto)));
|
||||||
|
|
||||||
mockMvc
|
mockMvc
|
||||||
.perform(
|
.perform(
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import org.testcontainers.junit.jupiter.Testcontainers;
|
|||||||
public class AbstractDataAccessLayerTest {
|
public class AbstractDataAccessLayerTest {
|
||||||
|
|
||||||
public static PostgreSQLContainer<?> postgres =
|
public static PostgreSQLContainer<?> postgres =
|
||||||
new PostgreSQLContainer<>("postgres:17.3-alpine").withDatabaseName("mjga");
|
new PostgreSQLContainer<>("pgvector/pgvector:pg17").withDatabaseName("mjga");
|
||||||
|
|
||||||
@DynamicPropertySource
|
@DynamicPropertySource
|
||||||
static void postgresProperties(DynamicPropertyRegistry registry) {
|
static void postgresProperties(DynamicPropertyRegistry registry) {
|
||||||
|
|||||||
@@ -32,11 +32,11 @@ public class SortByDALTest extends AbstractDataAccessLayerTest {
|
|||||||
"INSERT INTO mjga.user (id, username,password) VALUES (3, 'testC','qFVVFvPqs291k10')",
|
"INSERT INTO mjga.user (id, username,password) VALUES (3, 'testC','qFVVFvPqs291k10')",
|
||||||
})
|
})
|
||||||
void userPageFetchWithNoSort() {
|
void userPageFetchWithNoSort() {
|
||||||
UserQueryDto rbacQueryDto = new UserQueryDto("test");
|
UserQueryDto rbacQueryDto = new UserQueryDto("test", null, null);
|
||||||
Result<Record> records = userRepository.pageFetchBy(PageRequestDto.of(1, 10), rbacQueryDto);
|
Result<Record> records = userRepository.pageFetchBy(PageRequestDto.of(1, 10), rbacQueryDto);
|
||||||
assertThat(records.get(0).get(USER.ID)).isEqualTo(1);
|
assertThat(records.get(2).get(USER.ID)).isEqualTo(1);
|
||||||
assertThat(records.get(1).get(USER.ID)).isEqualTo(2);
|
assertThat(records.get(1).get(USER.ID)).isEqualTo(2);
|
||||||
assertThat(records.get(2).get(USER.ID)).isEqualTo(3);
|
assertThat(records.get(0).get(USER.ID)).isEqualTo(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -48,7 +48,7 @@ public class SortByDALTest extends AbstractDataAccessLayerTest {
|
|||||||
"INSERT INTO mjga.user (id, username,password) VALUES (4, 'testD','3')",
|
"INSERT INTO mjga.user (id, username,password) VALUES (4, 'testD','3')",
|
||||||
})
|
})
|
||||||
void userPageFetchWithSort() {
|
void userPageFetchWithSort() {
|
||||||
UserQueryDto rbacQueryDto = new UserQueryDto("test");
|
UserQueryDto rbacQueryDto = new UserQueryDto("test", null, null);
|
||||||
HashMap<String, PageRequestDto.Direction> sortByIdDesc = new HashMap<>();
|
HashMap<String, PageRequestDto.Direction> sortByIdDesc = new HashMap<>();
|
||||||
sortByIdDesc.put("id", PageRequestDto.Direction.DESC);
|
sortByIdDesc.put("id", PageRequestDto.Direction.DESC);
|
||||||
Result<Record> records =
|
Result<Record> records =
|
||||||
|
|||||||
@@ -96,12 +96,12 @@ public class UserRolePermissionDALTest extends AbstractDataAccessLayerTest {
|
|||||||
"INSERT INTO mjga.user (id, username,password) VALUES (2, 'testB','NTjRCeUq2EqCy')",
|
"INSERT INTO mjga.user (id, username,password) VALUES (2, 'testB','NTjRCeUq2EqCy')",
|
||||||
})
|
})
|
||||||
void user_pageFetchBy() {
|
void user_pageFetchBy() {
|
||||||
UserQueryDto rbacQueryDto = new UserQueryDto("test");
|
UserQueryDto rbacQueryDto = new UserQueryDto("test", null, null);
|
||||||
Result<Record> records = userRepository.pageFetchBy(PageRequestDto.of(1, 10), rbacQueryDto);
|
Result<Record> records = userRepository.pageFetchBy(PageRequestDto.of(1, 10), rbacQueryDto);
|
||||||
assertThat(records.size()).isEqualTo(2);
|
assertThat(records.size()).isEqualTo(2);
|
||||||
|
|
||||||
assertThat(records.get(0).get(USER.ID)).isEqualTo(1);
|
assertThat(records.get(1).get(USER.ID)).isEqualTo(1);
|
||||||
assertThat(records.get(1).get(USER.ID)).isEqualTo(2);
|
assertThat(records.get(0).get(USER.ID)).isEqualTo(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -142,8 +142,8 @@ public class UserRolePermissionDALTest extends AbstractDataAccessLayerTest {
|
|||||||
roleQueryDto.setBindState(BindState.ALL);
|
roleQueryDto.setBindState(BindState.ALL);
|
||||||
Result<Record> records = roleRepository.pageFetchBy(PageRequestDto.of(1, 10), roleQueryDto);
|
Result<Record> records = roleRepository.pageFetchBy(PageRequestDto.of(1, 10), roleQueryDto);
|
||||||
assertThat(records.get(0).getValue("total_role")).isEqualTo(2);
|
assertThat(records.get(0).getValue("total_role")).isEqualTo(2);
|
||||||
assertThat(records.get(0).getValue(ROLE.NAME)).isEqualTo("testRoleA");
|
assertThat(records.get(1).getValue(ROLE.NAME)).isEqualTo("testRoleA");
|
||||||
assertThat(records.get(1).getValue(ROLE.NAME)).isEqualTo("testRoleB");
|
assertThat(records.get(0).getValue(ROLE.NAME)).isEqualTo("testRoleB");
|
||||||
|
|
||||||
roleQueryDto = new RoleQueryDto();
|
roleQueryDto = new RoleQueryDto();
|
||||||
roleQueryDto.setRoleCode("testRoleA");
|
roleQueryDto.setRoleCode("testRoleA");
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import static org.springframework.security.test.web.servlet.request.SecurityMock
|
|||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
import com.zl.mjga.config.minio.MinIoConfig;
|
||||||
import com.zl.mjga.config.security.HttpFireWallConfig;
|
import com.zl.mjga.config.security.HttpFireWallConfig;
|
||||||
import com.zl.mjga.config.security.Jwt;
|
import com.zl.mjga.config.security.Jwt;
|
||||||
import com.zl.mjga.config.security.UserDetailsServiceImpl;
|
import com.zl.mjga.config.security.UserDetailsServiceImpl;
|
||||||
@@ -19,6 +20,7 @@ import com.zl.mjga.repository.RoleRepository;
|
|||||||
import com.zl.mjga.repository.UserRepository;
|
import com.zl.mjga.repository.UserRepository;
|
||||||
import com.zl.mjga.service.IdentityAccessService;
|
import com.zl.mjga.service.IdentityAccessService;
|
||||||
import com.zl.mjga.service.SignService;
|
import com.zl.mjga.service.SignService;
|
||||||
|
import io.minio.MinioClient;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -49,6 +51,8 @@ public class AuthenticationAndAuthorityTest {
|
|||||||
@MockBean private UserRepository userRepository;
|
@MockBean private UserRepository userRepository;
|
||||||
@MockBean private RoleRepository roleRepository;
|
@MockBean private RoleRepository roleRepository;
|
||||||
@MockBean private PermissionRepository permissionRepository;
|
@MockBean private PermissionRepository permissionRepository;
|
||||||
|
@MockBean private MinioClient minioClient;
|
||||||
|
@MockBean private MinIoConfig minIoConfig;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenRequestOnPublicService_shouldSucceedWith200() throws Exception {
|
public void givenRequestOnPublicService_shouldSucceedWith200() throws Exception {
|
||||||
|
|||||||
@@ -112,19 +112,19 @@ class UserRolePermissionUnitTest {
|
|||||||
DSL.field("total_user", Integer.class))
|
DSL.field("total_user", Integer.class))
|
||||||
.values(stubUserId2, stubUserName2, stubUserPassword2, true, null, 2));
|
.values(stubUserId2, stubUserName2, stubUserPassword2, true, null, 2));
|
||||||
UserRolePermissionDto mockUserRolePermissionDto1 = new UserRolePermissionDto();
|
UserRolePermissionDto mockUserRolePermissionDto1 = new UserRolePermissionDto();
|
||||||
RoleDto mockRoleDto = new RoleDto();
|
RoleRespDto mockRoleRespDto = new RoleRespDto();
|
||||||
mockRoleDto.setId(stubRoleId);
|
mockRoleRespDto.setId(stubRoleId);
|
||||||
mockRoleDto.setCode(stubRoleCode);
|
mockRoleRespDto.setCode(stubRoleCode);
|
||||||
mockRoleDto.setName(stubRoleName);
|
mockRoleRespDto.setName(stubRoleName);
|
||||||
PermissionRespDto permissionRespDto = new PermissionRespDto();
|
PermissionRespDto permissionRespDto = new PermissionRespDto();
|
||||||
permissionRespDto.setId(stubPermissionId);
|
permissionRespDto.setId(stubPermissionId);
|
||||||
permissionRespDto.setCode(stubPermissionCode);
|
permissionRespDto.setCode(stubPermissionCode);
|
||||||
permissionRespDto.setName(stubPermissionName);
|
permissionRespDto.setName(stubPermissionName);
|
||||||
mockRoleDto.getPermissions().add(permissionRespDto);
|
mockRoleRespDto.getPermissions().add(permissionRespDto);
|
||||||
mockUserRolePermissionDto1.setId(stubUserId1);
|
mockUserRolePermissionDto1.setId(stubUserId1);
|
||||||
mockUserRolePermissionDto1.setUsername(stubUserName1);
|
mockUserRolePermissionDto1.setUsername(stubUserName1);
|
||||||
mockUserRolePermissionDto1.setPassword(stubUserPassword1);
|
mockUserRolePermissionDto1.setPassword(stubUserPassword1);
|
||||||
mockUserRolePermissionDto1.getRoles().add(mockRoleDto);
|
mockUserRolePermissionDto1.getRoles().add(mockRoleRespDto);
|
||||||
|
|
||||||
UserRolePermissionDto mockUserRolePermissionDto2 = new UserRolePermissionDto();
|
UserRolePermissionDto mockUserRolePermissionDto2 = new UserRolePermissionDto();
|
||||||
mockUserRolePermissionDto2.setId(stubUserId2);
|
mockUserRolePermissionDto2.setId(stubUserId2);
|
||||||
@@ -143,7 +143,7 @@ class UserRolePermissionUnitTest {
|
|||||||
// action
|
// action
|
||||||
PageResponseDto<List<UserRolePermissionDto>> result =
|
PageResponseDto<List<UserRolePermissionDto>> result =
|
||||||
identityAccessService.pageQueryUser(
|
identityAccessService.pageQueryUser(
|
||||||
PageRequestDto.of(1, 10), new UserQueryDto(stubUserName2));
|
PageRequestDto.of(1, 10), new UserQueryDto(stubUserName2, null, null));
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
List<UserRolePermissionDto> userRolePermissionDtoList = result.getData();
|
List<UserRolePermissionDto> userRolePermissionDtoList = result.getData();
|
||||||
@@ -173,7 +173,7 @@ class UserRolePermissionUnitTest {
|
|||||||
.thenReturn(mockResult);
|
.thenReturn(mockResult);
|
||||||
PageResponseDto<List<UserRolePermissionDto>> result =
|
PageResponseDto<List<UserRolePermissionDto>> result =
|
||||||
identityAccessService.pageQueryUser(
|
identityAccessService.pageQueryUser(
|
||||||
PageRequestDto.of(1, 10), new UserQueryDto("agydCO1Yi99a"));
|
PageRequestDto.of(1, 10), new UserQueryDto("agydCO1Yi99a", null, null));
|
||||||
assertThat(result.getTotal()).isEqualTo(0);
|
assertThat(result.getTotal()).isEqualTo(0);
|
||||||
assertThat(result.getData()).isNull();
|
assertThat(result.getData()).isNull();
|
||||||
}
|
}
|
||||||
@@ -202,7 +202,7 @@ class UserRolePermissionUnitTest {
|
|||||||
mockResult.setId(stubRoleId);
|
mockResult.setId(stubRoleId);
|
||||||
mockResult.setRoles(
|
mockResult.setRoles(
|
||||||
List.of(
|
List.of(
|
||||||
new RoleDto(
|
new RoleRespDto(
|
||||||
stubRoleId,
|
stubRoleId,
|
||||||
stubRoleName,
|
stubRoleName,
|
||||||
stubRoleCode,
|
stubRoleCode,
|
||||||
@@ -245,12 +245,12 @@ class UserRolePermissionUnitTest {
|
|||||||
when(roleRepository.pageFetchBy(any(PageRequestDto.class), any(RoleQueryDto.class)))
|
when(roleRepository.pageFetchBy(any(PageRequestDto.class), any(RoleQueryDto.class)))
|
||||||
.thenReturn(mockRoleResult);
|
.thenReturn(mockRoleResult);
|
||||||
RoleQueryDto roleQueryDto = new RoleQueryDto();
|
RoleQueryDto roleQueryDto = new RoleQueryDto();
|
||||||
PageResponseDto<List<RoleDto>> pageResult =
|
PageResponseDto<List<RoleRespDto>> pageResult =
|
||||||
identityAccessService.pageQueryRole(PageRequestDto.of(1, 5), roleQueryDto);
|
identityAccessService.pageQueryRole(PageRequestDto.of(1, 5), roleQueryDto);
|
||||||
assertThat(pageResult.getTotal()).isEqualTo(0L);
|
assertThat(pageResult.getTotal()).isEqualTo(0L);
|
||||||
|
|
||||||
roleQueryDto.setUserId(1L);
|
roleQueryDto.setUserId(1L);
|
||||||
PageResponseDto<List<RoleDto>> pageResult2 =
|
PageResponseDto<List<RoleRespDto>> pageResult2 =
|
||||||
identityAccessService.pageQueryRole(PageRequestDto.of(1, 5), roleQueryDto);
|
identityAccessService.pageQueryRole(PageRequestDto.of(1, 5), roleQueryDto);
|
||||||
assertThat(pageResult2.getTotal()).isEqualTo(0L);
|
assertThat(pageResult2.getTotal()).isEqualTo(0L);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ CREATE SCHEMA IF NOT EXISTS mjga;
|
|||||||
CREATE TABLE mjga.user (
|
CREATE TABLE mjga.user (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
username VARCHAR NOT NULL UNIQUE,
|
username VARCHAR NOT NULL UNIQUE,
|
||||||
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
avatar VARCHAR,
|
||||||
|
create_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
password VARCHAR NOT NULL,
|
password VARCHAR NOT NULL,
|
||||||
enable BOOLEAN NOT NULL DEFAULT TRUE
|
enable BOOLEAN NOT NULL DEFAULT TRUE
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,9 +3,12 @@ VITE_SOURCE_MAP=true
|
|||||||
# mock
|
# mock
|
||||||
#VITE_ENABLE_MOCK=true
|
#VITE_ENABLE_MOCK=true
|
||||||
#VITE_BASE_URL=http://localhost:5173
|
#VITE_BASE_URL=http://localhost:5173
|
||||||
|
#VITE_STATIC_URL=http://localhost:9000/zhilu
|
||||||
# local
|
# local
|
||||||
VITE_ENABLE_MOCK=false
|
VITE_ENABLE_MOCK=false
|
||||||
VITE_BASE_URL=http://localhost:8080
|
VITE_BASE_URL=http://localhost:8080
|
||||||
|
VITE_STATIC_URL=http://localhost:9000/zhilu
|
||||||
# dev
|
# dev
|
||||||
#VITE_ENABLE_MOCK=false
|
#VITE_ENABLE_MOCK=false
|
||||||
#VITE_BASE_URL=https://localhost/api
|
#VITE_BASE_URL=https://localhost/api
|
||||||
|
#VITE_STATIC_URL=https://localhost/static
|
||||||
|
|||||||
@@ -30,5 +30,18 @@
|
|||||||
"formatter": {
|
"formatter": {
|
||||||
"quoteStyle": "double"
|
"quoteStyle": "double"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"include": ["*.vue"],
|
||||||
|
"linter": {
|
||||||
|
"rules": {
|
||||||
|
"style": {
|
||||||
|
"useConst": "off",
|
||||||
|
"useImportType": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
1
frontend/env.d.ts
vendored
@@ -9,6 +9,7 @@ interface ImportMetaEnv {
|
|||||||
readonly VITE_ENABLE_MOCK: "true" | "false";
|
readonly VITE_ENABLE_MOCK: "true" | "false";
|
||||||
readonly VITE_BACKEND_PORT: string;
|
readonly VITE_BACKEND_PORT: string;
|
||||||
readonly VITE_BASE_URL: string;
|
readonly VITE_BASE_URL: string;
|
||||||
|
readonly VITE_STATIC_URL: string;
|
||||||
readonly VITE_SOURCE_MAP: "true" | "false";
|
readonly VITE_SOURCE_MAP: "true" | "false";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
55
frontend/package-lock.json
generated
@@ -10,8 +10,10 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@microsoft/fetch-event-source": "^2.0.1",
|
"@microsoft/fetch-event-source": "^2.0.1",
|
||||||
"@tailwindcss/vite": "^4.0.14",
|
"@tailwindcss/vite": "^4.0.14",
|
||||||
|
"@vuepic/vue-datepicker": "^11.0.2",
|
||||||
"@vueuse/core": "^13.0.0",
|
"@vueuse/core": "^13.0.0",
|
||||||
"apexcharts": "^3.46.0",
|
"apexcharts": "^3.46.0",
|
||||||
|
"compressorjs": "^1.2.1",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"dompurify": "^3.2.6",
|
"dompurify": "^3.2.6",
|
||||||
"flowbite": "^3.1.2",
|
"flowbite": "^3.1.2",
|
||||||
@@ -2691,6 +2693,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@vuepic/vue-datepicker": {
|
||||||
|
"version": "11.0.2",
|
||||||
|
"resolved": "http://mirrors.tencent.com/npm/@vuepic/vue-datepicker/-/vue-datepicker-11.0.2.tgz",
|
||||||
|
"integrity": "sha512-uHh78mVBXCEjam1uVfTzZ/HkyDwut/H6b2djSN9YTF+l/EA+XONfdCnOVSi1g+qVGSy65DcQAwyBNidAssnudQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"date-fns": "^4.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.12.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": ">=3.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@vueuse/core": {
|
"node_modules/@vueuse/core": {
|
||||||
"version": "13.1.0",
|
"version": "13.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-13.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-13.1.0.tgz",
|
||||||
@@ -2885,6 +2902,12 @@
|
|||||||
"url": "https://github.com/sponsors/antfu"
|
"url": "https://github.com/sponsors/antfu"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/blueimp-canvas-to-blob": {
|
||||||
|
"version": "3.29.0",
|
||||||
|
"resolved": "http://mirrors.tencent.com/npm/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.29.0.tgz",
|
||||||
|
"integrity": "sha512-0pcSSGxC0QxT+yVkivxIqW0Y4VlO2XSDPofBAqoJ1qJxgH9eiUDLv50Rixij2cDuEfx4M6DpD9UGZpRhT5Q8qg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||||
@@ -3150,6 +3173,16 @@
|
|||||||
"node": ">=14"
|
"node": ">=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/compressorjs": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "http://mirrors.tencent.com/npm/compressorjs/-/compressorjs-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-+geIjeRnPhQ+LLvvA7wxBQE5ddeLU7pJ3FsKFWirDw6veY3s9iLxAQEw7lXGHnhCJvBujEQWuNnGzZcvCvdkLQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"blueimp-canvas-to-blob": "^3.29.0",
|
||||||
|
"is-blob": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/config-chain": {
|
"node_modules/config-chain": {
|
||||||
"version": "1.1.13",
|
"version": "1.1.13",
|
||||||
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
|
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
|
||||||
@@ -3237,6 +3270,16 @@
|
|||||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/date-fns": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "http://mirrors.tencent.com/npm/date-fns/-/date-fns-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/kossnocorp"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dayjs": {
|
"node_modules/dayjs": {
|
||||||
"version": "1.11.13",
|
"version": "1.11.13",
|
||||||
"resolved": "http://mirrors.tencent.com/npm/dayjs/-/dayjs-1.11.13.tgz",
|
"resolved": "http://mirrors.tencent.com/npm/dayjs/-/dayjs-1.11.13.tgz",
|
||||||
@@ -3893,6 +3936,18 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/is-blob": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "http://mirrors.tencent.com/npm/is-blob/-/is-blob-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-SZ/fTft5eUhQM6oF/ZaASFDEdbFVe89Imltn9uZr03wdKMcWNVYSMjQPFtg05QuNkt5l5c135ElvXEQG0rk4tw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-core-module": {
|
"node_modules/is-core-module": {
|
||||||
"version": "2.16.1",
|
"version": "2.16.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
||||||
|
|||||||
@@ -20,8 +20,10 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@microsoft/fetch-event-source": "^2.0.1",
|
"@microsoft/fetch-event-source": "^2.0.1",
|
||||||
"@tailwindcss/vite": "^4.0.14",
|
"@tailwindcss/vite": "^4.0.14",
|
||||||
|
"@vuepic/vue-datepicker": "^11.0.2",
|
||||||
"@vueuse/core": "^13.0.0",
|
"@vueuse/core": "^13.0.0",
|
||||||
"apexcharts": "^3.46.0",
|
"apexcharts": "^3.46.0",
|
||||||
|
"compressorjs": "^1.2.1",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"dompurify": "^3.2.6",
|
"dompurify": "^3.2.6",
|
||||||
"flowbite": "^3.1.2",
|
"flowbite": "^3.1.2",
|
||||||
|
|||||||
BIN
frontend/public/ai-tdd.png
Normal file
|
After Width: | Height: | Size: 576 KiB |
50
frontend/public/logo.svg
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<svg width="32" height="33" viewBox="0 0 32 33" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M24.5194 13.4429C24.4453 13.9533 24.1087 14.6468 23.7226 15.2497C23.2354 16.0105 22.4622 16.5433 21.5774 16.7283L17.6797 17.5434C17.0533 17.6744 16.4852 18.0022 16.0587 18.479L13.503 21.3357C13.0227 21.8725 12.687 21.7445 12.687 21.0244C12.6812 21.0511 11.4186 24.3072 14.7646 26.2371C16.0502 26.9787 17.9009 26.7122 19.1865 25.9707L25.9983 22.0416C28.5458 20.5722 30.3445 18.0863 30.9424 15.2089C30.966 15.095 30.9843 14.9808 31.004 14.8667L24.5194 13.4429Z" fill="url(#paint0_linear_2484_3243)" />
|
||||||
|
<path d="M22.7528 9.51774C24.0384 10.2593 24.5637 11.3633 24.5637 12.8464C24.5637 13.0477 24.5479 13.2466 24.5194 13.4425L27.2641 14.6215L31.004 14.8663C31.4829 12.0948 30.5444 9.24202 28.862 6.97445C27.5959 5.268 25.9667 3.78714 24.0081 2.65738C22.417 1.73966 20.7636 1.13501 19.1025 0.803223L17.2361 3.22023L16.6465 5.99559L22.7528 9.51774Z" fill="url(#paint1_linear_2484_3243)" />
|
||||||
|
<path d="M0.783597 11.5518C0.782899 11.554 0.784832 11.5546 0.78556 11.5524C0.929583 11.1205 1.11018 10.6385 1.33564 10.1237C2.51334 7.4343 4.78286 5.64062 7.57492 4.72608C10.367 3.81156 13.4155 4.13212 15.9601 5.59988L16.6465 5.99578L19.1025 0.803412C11.291 -0.756765 3.30728 3.83253 0.793528 11.5217C0.792327 11.5254 0.787957 11.5382 0.783597 11.5518Z" fill="url(#paint2_linear_2484_3243)" />
|
||||||
|
<path d="M18.9199 25.9704C17.6343 26.712 16.0503 26.712 14.7647 25.9704C14.5902 25.8697 14.4257 25.7566 14.2701 25.634L12.0091 27.1885L10.0603 30.3376C12.2233 32.1377 15.0321 32.7164 17.839 32.3945C19.9513 32.1523 22.0495 31.4832 24.0082 30.3534C25.5992 29.4357 26.9501 28.3075 28.0682 27.0361L26.9063 24.2128L25.0262 22.4482L18.9199 25.9704Z" fill="url(#paint3_linear_2484_3243)" />
|
||||||
|
<path d="M14.2701 25.6341C13.2796 24.8539 12.6872 23.6572 12.6872 22.3754V22.2476V11.5724C12.6872 10.9687 12.865 10.8661 13.3884 11.168C12.5823 10.703 10.7203 9.10701 8.42118 10.4331C7.13557 11.1747 6.0769 12.8116 6.0769 14.2946V22.1529C6.0769 25.0917 7.59906 28.1573 9.79448 30.1133C9.88132 30.1906 9.97122 30.2636 10.0603 30.3377L14.2701 25.6341Z" fill="url(#paint4_linear_2484_3243)" />
|
||||||
|
<path d="M27.9105 5.8123C27.909 5.8106 27.9075 5.81197 27.909 5.81368C28.2114 6.15428 28.5389 6.5515 28.8725 7.00399C30.6149 9.36765 31.2659 12.3613 30.6627 15.2343C30.0594 18.1072 28.2573 20.5846 25.7126 22.0523L25.0262 22.4482L28.0683 27.0361C33.3265 21.0576 33.3401 11.8554 27.9316 5.83594C27.9291 5.83306 27.9201 5.82287 27.9105 5.8123Z" fill="url(#paint5_linear_2484_3243)" />
|
||||||
|
<path d="M6.34355 14.2944C6.34354 12.8113 7.13552 11.4408 8.42113 10.6993C8.59565 10.5986 8.77601 10.5129 8.96002 10.4395L8.74304 7.70603L7.21862 4.57861C4.57671 5.55005 2.4397 7.55766 1.31528 10.1471C0.469097 12.0957 9.792e-06 14.2458 0 16.5052C0 18.3407 0.302549 20.0735 0.845533 21.6767L3.87391 22.083L6.34355 21.3387V14.2944V14.2944Z" fill="url(#paint6_linear_2484_3243)" />
|
||||||
|
<path d="M8.96003 10.4395C10.1316 9.97264 11.4652 10.0584 12.5763 10.6993L12.6871 10.7632L21.5825 15.8941C22.2065 16.254 22.1498 16.6082 21.4445 16.7557L21.9577 16.6484C22.6329 16.5072 23.2498 16.1621 23.7216 15.6592C24.5327 14.7946 24.8305 13.7515 24.8305 12.8463C24.8304 11.3632 24.0385 9.99274 22.7529 9.2512L15.941 5.32209C13.3935 3.85267 10.3394 3.53934 7.5461 4.46083C7.4356 4.49727 7.32744 4.5386 7.21863 4.57861L8.96003 10.4395Z" fill="url(#paint7_linear_2484_3243)" />
|
||||||
|
<path d="M19.3222 32.1523C19.3245 32.1518 19.3241 32.1498 19.3218 32.1503C18.8753 32.2417 18.3673 32.3264 17.8083 32.3888C14.8881 32.7145 11.9676 31.781 9.77876 29.8225C7.58999 27.8641 6.3436 25.0662 6.3436 22.1307L6.34359 21.3389L0.845581 21.6769C3.39893 29.2156 11.369 33.8285 19.2912 32.1588C19.295 32.158 19.3083 32.1553 19.3222 32.1523Z" fill="url(#paint8_linear_2484_3243)" />
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="paint0_linear_2484_3243" x1="20.0599" y1="24.2701" x2="23.2075" y2="13.307" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#1724C9" />
|
||||||
|
<stop offset="1" stop-color="#1C64F2" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_2484_3243" x1="27.3093" y1="10.9001" x2="19.0297" y2="2.64962" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#1C64F2" />
|
||||||
|
<stop offset="1" stop-color="#0092FF" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_2484_3243" x1="16.1645" y1="5.52115" x2="3.67432" y2="6.3104" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#0092FF" />
|
||||||
|
<stop offset="1" stop-color="#45B2FF" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint3_linear_2484_3243" x1="15.3198" y1="29.1626" x2="26.5366" y2="26.1359" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#1C64F2" />
|
||||||
|
<stop offset="1" stop-color="#0092FF" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint4_linear_2484_3243" x1="7.26881" y1="16.1827" x2="15.2325" y2="24.4347" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#1724C9" />
|
||||||
|
<stop offset="1" stop-color="#1C64F2" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint5_linear_2484_3243" x1="25.4505" y1="22.1356" x2="31.007" y2="10.9345" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#0092FF" />
|
||||||
|
<stop offset="1" stop-color="#45B2FF" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint6_linear_2484_3243" x1="5.36387" y1="9.63067" x2="2.39054" y2="20.8063" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#1C64F2" />
|
||||||
|
<stop offset="1" stop-color="#0092FF" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint7_linear_2484_3243" x1="20.5431" y1="9.09912" x2="9.67768" y2="11.8044" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#1724C9" />
|
||||||
|
<stop offset="1" stop-color="#1C64F2" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint8_linear_2484_3243" x1="6.40679" y1="21.8566" x2="13.3326" y2="32.2745" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#0092FF" />
|
||||||
|
<stop offset="1" stop-color="#45B2FF" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 6.0 KiB |
@@ -1,11 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { RouterLink, RouterView } from "vue-router";
|
import { RouterView } from "vue-router";
|
||||||
import Alert from "./components/Alert.vue";
|
import Alert from "./components/ui/Alert.vue";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<RouterView />
|
<RouterView />
|
||||||
<Alert/>
|
<Alert />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import createClient, { type Middleware } from "openapi-fetch";
|
import createClient, { type Middleware } from "openapi-fetch";
|
||||||
import useAuthStore from "../composables/store/useAuthStore";
|
import useAuthStore from "../composables/store/useAuthStore";
|
||||||
|
import type { paths } from "./types/schema"; // generated by openapi-typescript
|
||||||
import {
|
import {
|
||||||
ForbiddenError,
|
ForbiddenError,
|
||||||
RequestError,
|
RequestError,
|
||||||
UnAuthError,
|
UnAuthError,
|
||||||
InternalServerError,
|
InternalServerError,
|
||||||
} from "../types/error";
|
} from "@/types/ErrorTypes";
|
||||||
import type { paths } from "./types/schema"; // generated by openapi-typescript
|
|
||||||
|
|
||||||
const myMiddleware: Middleware = {
|
const myMiddleware: Middleware = {
|
||||||
onRequest({ request, options }) {
|
onRequest({ request, options }) {
|
||||||
|
|||||||
@@ -15,10 +15,13 @@ export default [
|
|||||||
}),
|
}),
|
||||||
http.post("/ai/action/search", () => {
|
http.post("/ai/action/search", () => {
|
||||||
const response = HttpResponse.json({
|
const response = HttpResponse.json({
|
||||||
action: "CREATE_USER",
|
action: "DELETE_USER",
|
||||||
});
|
});
|
||||||
return response;
|
return response;
|
||||||
}),
|
}),
|
||||||
|
http.delete("/ai/action/user", () => {
|
||||||
|
return HttpResponse.json({ success: true });
|
||||||
|
}),
|
||||||
http.get("/ai/llm/page-query", () => {
|
http.get("/ai/llm/page-query", () => {
|
||||||
const generateLlm = () => ({
|
const generateLlm = () => ({
|
||||||
id: faker.number.int({ min: 1, max: 100 }),
|
id: faker.number.int({ min: 1, max: 100 }),
|
||||||
@@ -26,6 +29,7 @@ export default [
|
|||||||
modelName: faker.lorem.word(),
|
modelName: faker.lorem.word(),
|
||||||
apiKey: faker.string.uuid(),
|
apiKey: faker.string.uuid(),
|
||||||
url: faker.internet.url(),
|
url: faker.internet.url(),
|
||||||
|
type: faker.helpers.arrayElement(["CHAT", "EMBEDDING"]),
|
||||||
enable: faker.datatype.boolean(),
|
enable: faker.datatype.boolean(),
|
||||||
priority: faker.number.int({ min: 1, max: 10 }),
|
priority: faker.number.int({ min: 1, max: 10 }),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,13 +3,17 @@ import { http, HttpResponse } from "msw";
|
|||||||
|
|
||||||
export default [
|
export default [
|
||||||
http.get("/department/page-query", () => {
|
http.get("/department/page-query", () => {
|
||||||
const generateDepartment = () => ({
|
const generateDepartment = () => {
|
||||||
id: faker.number.int({ min: 1, max: 100 }),
|
// 20% 的概率生成 parentId 为 null 的数据
|
||||||
name: faker.company.name(),
|
const hasParent = faker.datatype.boolean(0.8);
|
||||||
parentId: faker.number.int({ min: 1, max: 100 }),
|
return {
|
||||||
isBound: faker.datatype.boolean(),
|
id: faker.number.int({ min: 1, max: 100 }),
|
||||||
parentName: faker.company.name(),
|
name: faker.company.name(),
|
||||||
});
|
parentId: hasParent ? faker.number.int({ min: 1, max: 100 }) : null,
|
||||||
|
isBound: faker.datatype.boolean(),
|
||||||
|
parentName: hasParent ? faker.company.name() : null,
|
||||||
|
};
|
||||||
|
};
|
||||||
const mockData = {
|
const mockData = {
|
||||||
data: faker.helpers.multiple(generateDepartment, { count: 10 }),
|
data: faker.helpers.multiple(generateDepartment, { count: 10 }),
|
||||||
total: 30,
|
total: 30,
|
||||||
@@ -17,21 +21,41 @@ export default [
|
|||||||
return HttpResponse.json(mockData);
|
return HttpResponse.json(mockData);
|
||||||
}),
|
}),
|
||||||
http.get("/department/query-available", () => {
|
http.get("/department/query-available", () => {
|
||||||
const generateDepartment = () => ({
|
const generateDepartment = () => {
|
||||||
id: faker.number.int({ min: 1, max: 30 }),
|
// 20% 的概率生成 parentId 为 null 的数据
|
||||||
name: faker.company.name(),
|
const hasParent = faker.datatype.boolean(0.8);
|
||||||
parentId: faker.number.int({ min: 1, max: 30 }),
|
return {
|
||||||
parentName: faker.company.name(),
|
id: faker.number.int({ min: 1, max: 30 }),
|
||||||
});
|
name: faker.company.name(),
|
||||||
|
parentId: hasParent ? faker.number.int({ min: 1, max: 30 }) : null,
|
||||||
|
parentName: hasParent ? faker.company.name() : null,
|
||||||
|
};
|
||||||
|
};
|
||||||
const mockData = faker.helpers.multiple(generateDepartment, { count: 30 });
|
const mockData = faker.helpers.multiple(generateDepartment, { count: 30 });
|
||||||
|
|
||||||
return HttpResponse.json(mockData);
|
return HttpResponse.json(mockData);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
http.post("/department", () => {
|
http.post("/department", () => {
|
||||||
console.log("Captured department upsert");
|
console.log("Captured department upsert");
|
||||||
return HttpResponse.json();
|
return HttpResponse.json();
|
||||||
}),
|
}),
|
||||||
|
http.get("/department/query-sub", ({ request }) => {
|
||||||
|
const generateDepartment = () => {
|
||||||
|
// 20% 的概率生成 parentId 为 null 的数据
|
||||||
|
const hasParent = faker.datatype.boolean(0.8);
|
||||||
|
return {
|
||||||
|
id: faker.number.int({ min: 1, max: 30 }),
|
||||||
|
name: faker.company.name(),
|
||||||
|
parentId: hasParent ? faker.number.int({ min: 1, max: 30 }) : null,
|
||||||
|
parentName: hasParent ? faker.company.name() : null,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
const mockData = faker.helpers.multiple(generateDepartment, {
|
||||||
|
count: 30,
|
||||||
|
});
|
||||||
|
|
||||||
|
return HttpResponse.json(mockData);
|
||||||
|
}),
|
||||||
http.delete("/department", () => {
|
http.delete("/department", () => {
|
||||||
console.log("Captured department delete");
|
console.log("Captured department delete");
|
||||||
return HttpResponse.json();
|
return HttpResponse.json();
|
||||||
|
|||||||