Compare commits
5 Commits
6d05b3b95d
...
616d55d1a7
Author | SHA1 | Date | |
---|---|---|---|
616d55d1a7 | |||
e17a63b96d | |||
ac6e89af79 | |||
9a8890996f | |||
c9fd364428 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -43,4 +43,6 @@ build/
|
|||||||
*.cache
|
*.cache
|
||||||
*.diff
|
*.diff
|
||||||
*.patch
|
*.patch
|
||||||
*.tmp
|
*.tmp
|
||||||
|
|
||||||
|
!docker/zayac-admin/Dockerfile
|
@ -1,62 +1,15 @@
|
|||||||
version: '3'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
mysql:
|
|
||||||
image: mysql:8.0.33
|
|
||||||
restart: always
|
|
||||||
container_name: mysql-master
|
|
||||||
ports:
|
|
||||||
- '3306:3306'
|
|
||||||
environment:
|
|
||||||
TZ: Asia/Shanghai
|
|
||||||
MYSQL_ROOT_PASSWORD: TMrmNY839KtZfpHb
|
|
||||||
# 初始化数据库(后续的初始化 SQL 会在这个库执行)
|
|
||||||
MYSQL_DATABASE: zayac_admin
|
|
||||||
#MYSQL_USER: 你的数据库用户名
|
|
||||||
#MYSQL_PASSWORD: 你的数据库密码
|
|
||||||
volumes:
|
|
||||||
- /docker/mysql/conf/:/etc/mysql/conf.d/
|
|
||||||
- /docker/mysql/data/:/var/lib/mysql/
|
|
||||||
command:
|
|
||||||
--default-authentication-plugin=mysql_native_password
|
|
||||||
--character-set-server=utf8mb4
|
|
||||||
--collation-server=utf8mb4_general_ci
|
|
||||||
--explicit_defaults_for_timestamp=true
|
|
||||||
--lower_case_table_names=1
|
|
||||||
redis:
|
|
||||||
image: redis:7.2.3
|
|
||||||
restart: always
|
|
||||||
container_name: redis
|
|
||||||
ports:
|
|
||||||
- '6379:6379'
|
|
||||||
environment:
|
|
||||||
TZ: Asia/Shanghai
|
|
||||||
volumes:
|
|
||||||
- /docker/redis/conf/redis.conf:/usr/local/redis/config/redis.conf
|
|
||||||
- /docker/redis/data/:/data/
|
|
||||||
- /docker/redis/logs/:/logs/
|
|
||||||
command: 'redis-server /usr/local/redis/config/redis.conf --appendonly yes --requirepass 你的 Redis 密码'
|
|
||||||
continew-admin-server:
|
continew-admin-server:
|
||||||
build: ./zayac-admin
|
build: ./zayac-admin
|
||||||
restart: always
|
restart: always
|
||||||
container_name: continew-admin-server
|
container_name: zayac-admin-server
|
||||||
ports:
|
ports:
|
||||||
- '18000:18000'
|
- '18000:18000'
|
||||||
environment:
|
environment:
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
DB_HOST: 172.17.0.1
|
|
||||||
DB_PORT: 3306
|
|
||||||
DB_USER: 你的数据库用户名
|
|
||||||
DB_PWD: 你的数据库密码
|
|
||||||
DB_NAME: continew_admin
|
|
||||||
REDIS_HOST: 172.17.0.1
|
|
||||||
REDIS_PORT: 6379
|
|
||||||
REDIS_PWD: 你的 Redis 密码
|
|
||||||
REDIS_DB: 0
|
|
||||||
volumes:
|
volumes:
|
||||||
- /docker/continew-admin/config/:/app/config/
|
- /docker/zayac-admin/config/:/app/config/
|
||||||
- /docker/continew-admin/data/file/:/app/data/file/
|
- /docker/zayac-admin/data/file/:/app/data/file/
|
||||||
- /docker/continew-admin/logs/:/app/logs/
|
- /docker/zayac-admin/logs/:/app/logs/
|
||||||
- /docker/continew-admin/lib/:/app/lib/
|
- /docker/zayac-admin/lib/:/app/lib/
|
||||||
depends_on:
|
|
||||||
- redis
|
|
||||||
- mysql
|
|
||||||
|
@ -1,14 +1,22 @@
|
|||||||
|
# 使用 OpenJDK 17 作为基础镜像
|
||||||
FROM openjdk:17
|
FROM openjdk:17
|
||||||
|
|
||||||
MAINTAINER Charles7c charles7c@126.com
|
# 维护者信息
|
||||||
|
MAINTAINER zayac stupidzayac@gmail.com
|
||||||
|
|
||||||
ARG JAR_FILE=./bin/*.jar
|
# 复制 JAR 文件和配置文件到容器中
|
||||||
COPY ${JAR_FILE} /app/bin/app.jar
|
COPY ./bin/zayac-admin.jar /app/bin/app.jar
|
||||||
|
|
||||||
|
# 设置工作目录
|
||||||
WORKDIR /app/bin
|
WORKDIR /app/bin
|
||||||
|
|
||||||
|
# 暴露应用运行的端口
|
||||||
|
EXPOSE 18000
|
||||||
|
|
||||||
|
# 运行应用
|
||||||
ENTRYPOINT ["java", \
|
ENTRYPOINT ["java", \
|
||||||
"-jar", \
|
"-jar", \
|
||||||
"-XX:+UseZGC", \
|
"-XX:+UseZGC", \
|
||||||
"-Djava.security.egd=file:/dev/./urandom", \
|
"-Djava.security.egd=file:/dev/./urandom", \
|
||||||
"-Dspring.profiles.active=prod", \
|
"-Dspring.profiles.active=prod", \
|
||||||
"app.jar"]
|
"/app/bin/app.jar"]
|
||||||
|
108
docker/zayac-admin/config/application-generator.yml
Normal file
108
docker/zayac-admin/config/application-generator.yml
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
--- ### 代码生成器配置
|
||||||
|
generator:
|
||||||
|
# 排除数据表
|
||||||
|
excludeTables:
|
||||||
|
- DATABASECHANGELOG
|
||||||
|
- DATABASECHANGELOGLOCK
|
||||||
|
- gen_config
|
||||||
|
- gen_field_config
|
||||||
|
## 类型映射
|
||||||
|
typeMappings:
|
||||||
|
MYSQL:
|
||||||
|
Integer:
|
||||||
|
- int
|
||||||
|
- tinyint
|
||||||
|
- smallint
|
||||||
|
- mediumint
|
||||||
|
- integer
|
||||||
|
String:
|
||||||
|
- varchar
|
||||||
|
- char
|
||||||
|
- text
|
||||||
|
- mediumtext
|
||||||
|
- longtext
|
||||||
|
- tinytext
|
||||||
|
- json
|
||||||
|
LocalDate:
|
||||||
|
- date
|
||||||
|
LocalDateTime:
|
||||||
|
- datetime
|
||||||
|
- timestamp
|
||||||
|
Long:
|
||||||
|
- bigint
|
||||||
|
Float:
|
||||||
|
- float
|
||||||
|
Double:
|
||||||
|
- double
|
||||||
|
BigDecimal:
|
||||||
|
- decimal
|
||||||
|
Boolean:
|
||||||
|
- bit
|
||||||
|
## 模板配置
|
||||||
|
templateConfigs:
|
||||||
|
DO:
|
||||||
|
# 模板路径
|
||||||
|
templatePath: backend/Entity.ftl
|
||||||
|
# 包名称
|
||||||
|
packageName: model.entity
|
||||||
|
# 排除字段
|
||||||
|
excludeFields:
|
||||||
|
- id
|
||||||
|
- createUser
|
||||||
|
- createTime
|
||||||
|
- updateUser
|
||||||
|
- updateTime
|
||||||
|
Query:
|
||||||
|
templatePath: backend/Query.ftl
|
||||||
|
packageName: model.query
|
||||||
|
Req:
|
||||||
|
templatePath: backend/Req.ftl
|
||||||
|
packageName: model.req
|
||||||
|
Resp:
|
||||||
|
templatePath: backend/Resp.ftl
|
||||||
|
packageName: model.resp
|
||||||
|
excludeFields:
|
||||||
|
- id
|
||||||
|
- createUser
|
||||||
|
- createTime
|
||||||
|
DetailResp:
|
||||||
|
templatePath: backend/DetailResp.ftl
|
||||||
|
packageName: model.resp
|
||||||
|
excludeFields:
|
||||||
|
- id
|
||||||
|
- createUser
|
||||||
|
- createTime
|
||||||
|
- updateUser
|
||||||
|
- updateTime
|
||||||
|
Mapper:
|
||||||
|
templatePath: backend/Mapper.ftl
|
||||||
|
packageName: mapper
|
||||||
|
Service:
|
||||||
|
templatePath: backend/Service.ftl
|
||||||
|
packageName: service
|
||||||
|
ServiceImpl:
|
||||||
|
templatePath: backend/ServiceImpl.ftl
|
||||||
|
packageName: service.impl
|
||||||
|
Controller:
|
||||||
|
templatePath: backend/Controller.ftl
|
||||||
|
packageName: controller
|
||||||
|
api:
|
||||||
|
templatePath: frontend/api.ftl
|
||||||
|
packageName: src/apis
|
||||||
|
extension: .ts
|
||||||
|
backend: false
|
||||||
|
index:
|
||||||
|
templatePath: frontend/index.ftl
|
||||||
|
packageName: src/views
|
||||||
|
extension: .vue
|
||||||
|
backend: false
|
||||||
|
AddModal:
|
||||||
|
templatePath: frontend/AddModal.ftl
|
||||||
|
packageName: src/views
|
||||||
|
extension: .vue
|
||||||
|
backend: false
|
||||||
|
DetailDrawer:
|
||||||
|
templatePath: frontend/DetailDrawer.ftl
|
||||||
|
packageName: src/views
|
||||||
|
extension: .vue
|
||||||
|
backend: false
|
284
docker/zayac-admin/config/application-prod.yml
Normal file
284
docker/zayac-admin/config/application-prod.yml
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
--- ### 项目配置
|
||||||
|
project:
|
||||||
|
# URL(跨域配置默认放行此 URL,第三方登录回调默认使用此 URL 为前缀,请注意更改为你实际的前端 URL)
|
||||||
|
url: http://localhost:5173
|
||||||
|
# 是否为生产环境
|
||||||
|
production: true
|
||||||
|
|
||||||
|
--- ### 服务器配置
|
||||||
|
server:
|
||||||
|
# HTTP 端口(默认 8080)
|
||||||
|
port: 8000
|
||||||
|
|
||||||
|
--- ### 数据源配置
|
||||||
|
spring.datasource:
|
||||||
|
type: com.zaxxer.hikari.HikariDataSource
|
||||||
|
## 动态数据源配置(可配多主多从:m1、s1...;纯粹多库:mysql、oracle...;混合配置:m1、s1、oracle...)
|
||||||
|
dynamic:
|
||||||
|
# 是否启用 P6Spy(SQL 性能分析组件,该插件有性能损耗,不建议生产环境使用)
|
||||||
|
p6spy: false
|
||||||
|
# 设置默认的数据源或者数据源组(默认:master)
|
||||||
|
primary: master
|
||||||
|
# 严格匹配数据源(true:未匹配到指定数据源时抛异常;false:使用默认数据源;默认 false)
|
||||||
|
strict: false
|
||||||
|
datasource:
|
||||||
|
# 主库配置(可配多个,构成多主)
|
||||||
|
master:
|
||||||
|
url: jdbc:mysql://${DB_HOST:45.89.233.228}:${DB_PORT:3306}/${DB_NAME:zayac_admin}?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true&autoReconnect=true&maxReconnects=10&failOverReadOnly=false
|
||||||
|
username: ${DB_USER:zayac_admin}
|
||||||
|
password: ${DB_PWD:2hMtBRzZrDAkRynX}
|
||||||
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
|
type: ${spring.datasource.type}
|
||||||
|
# 从库配置(可配多个,构成多从)
|
||||||
|
slave_1:
|
||||||
|
url: jdbc:mysql://${DB_HOST:38.6.218.29}:${DB_PORT:3306}/${DB_NAME:zayac_admin}?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true&autoReconnect=true&maxReconnects=10&failOverReadOnly=false
|
||||||
|
username: zayac_admin
|
||||||
|
password: PxkF52eGTz48izZG
|
||||||
|
lazy: true
|
||||||
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
|
type: ${spring.datasource.type}
|
||||||
|
# # PostgreSQL 库配置
|
||||||
|
# postgresql:
|
||||||
|
# url: jdbc:postgresql://${DB_HOST:127.0.0.1}:${DB_PORT:5432}/${DB_NAME:continew_admin}?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true&autoReconnect=true&maxReconnects=10&failOverReadOnly=false
|
||||||
|
# username: ${DB_USER:root}
|
||||||
|
# password: ${DB_PWD:123456}
|
||||||
|
# driver-class-name: org.postgresql.Driver
|
||||||
|
# type: ${spring.datasource.type}
|
||||||
|
# Hikari 连接池配置(完整配置请参阅:https://github.com/brettwooldridge/HikariCP)
|
||||||
|
hikari:
|
||||||
|
# 最大连接数量(默认 10,根据实际环境调整)
|
||||||
|
# 注意:当连接达到上限,并且没有空闲连接可用时,获取连接将在超时前阻塞最多 connectionTimeout 毫秒
|
||||||
|
max-pool-size: 20
|
||||||
|
# 获取连接超时时间(默认 30000 毫秒,30 秒)
|
||||||
|
connection-timeout: 30000
|
||||||
|
# 空闲连接最大存活时间(默认 600000 毫秒,10 分钟)
|
||||||
|
idle-timeout: 600000
|
||||||
|
# 保持连接活动的频率,以防止它被数据库或网络基础设施超时。该值必须小于 maxLifetime(默认 0,禁用)
|
||||||
|
keepaliveTime: 30000
|
||||||
|
# 连接最大生存时间(默认 1800000 毫秒,30 分钟)
|
||||||
|
max-lifetime: 1800000
|
||||||
|
## Liquibase 配置
|
||||||
|
spring.liquibase:
|
||||||
|
# 是否启用
|
||||||
|
enabled: false
|
||||||
|
# 配置文件路径
|
||||||
|
change-log: classpath:/db/changelog/db.changelog-master.yaml
|
||||||
|
|
||||||
|
--- ### 缓存配置
|
||||||
|
spring.data:
|
||||||
|
## Redis 配置(单机模式)
|
||||||
|
redis:
|
||||||
|
# 地址
|
||||||
|
host: ${REDIS_HOST:38.6.218.29}
|
||||||
|
# 端口(默认 6379)
|
||||||
|
port: ${REDIS_PORT:6379}
|
||||||
|
# 密码(未设置密码时可为空或注释掉)
|
||||||
|
password: ${REDIS_PWD:jhkdjhkjdhsIUTYURTU_mWHmDY}
|
||||||
|
# 数据库索引
|
||||||
|
database: ${REDIS_DB:0}
|
||||||
|
# 连接超时时间
|
||||||
|
timeout: 10s
|
||||||
|
# 是否开启 SSL
|
||||||
|
ssl:
|
||||||
|
enabled: false
|
||||||
|
## Redisson 配置
|
||||||
|
redisson:
|
||||||
|
enabled: true
|
||||||
|
mode: SINGLE
|
||||||
|
## JetCache 配置
|
||||||
|
jetcache:
|
||||||
|
# 统计间隔(默认 0,表示不统计)
|
||||||
|
statIntervalMinutes: 0
|
||||||
|
## 本地/进程级/一级缓存配置
|
||||||
|
local:
|
||||||
|
default:
|
||||||
|
# 缓存类型
|
||||||
|
type: caffeine
|
||||||
|
# key 转换器的全局配置
|
||||||
|
keyConvertor: jackson
|
||||||
|
# 以毫秒为单位指定超时时间的全局配置
|
||||||
|
expireAfterWriteInMillis: 7200000
|
||||||
|
# 每个缓存实例的最大元素的全局配置,仅 local 类型的缓存需要指定
|
||||||
|
limit: 1000
|
||||||
|
## 远程/分布式/二级缓存配置
|
||||||
|
remote:
|
||||||
|
default:
|
||||||
|
# 缓存类型
|
||||||
|
type: redisson
|
||||||
|
# key 转换器的全局配置(用于将复杂的 KEY 类型转换为缓存实现可以接受的类型)
|
||||||
|
keyConvertor: jackson
|
||||||
|
# 以毫秒为单位指定超时时间的全局配置
|
||||||
|
expireAfterWriteInMillis: 7200000
|
||||||
|
# 2.7+ 支持两级缓存更新以后失效其他 JVM 中的 local cache,但多个服务共用 Redis 同一个 channel 可能会造成广播风暴,需要在这里指定channel。
|
||||||
|
# 你可以决定多个不同的服务是否共用同一个 channel,如果没有指定则不开启。
|
||||||
|
broadcastChannel: ${spring.application.name}
|
||||||
|
# 序列化器的全局配置,仅 remote 类型的缓存需要指定
|
||||||
|
valueEncoder: java
|
||||||
|
valueDecoder: java
|
||||||
|
|
||||||
|
--- ### 验证码配置
|
||||||
|
continew-starter.captcha:
|
||||||
|
## 行为验证码
|
||||||
|
behavior:
|
||||||
|
enabled: true
|
||||||
|
cache-type: REDIS
|
||||||
|
water-mark: ${project.app-name}
|
||||||
|
## 图形验证码
|
||||||
|
graphic:
|
||||||
|
# 类型
|
||||||
|
type: SPEC
|
||||||
|
# 内容长度
|
||||||
|
length: 4
|
||||||
|
# 过期时间
|
||||||
|
expirationInMinutes: 2
|
||||||
|
## 其他验证码配置
|
||||||
|
captcha:
|
||||||
|
## 邮箱验证码配置
|
||||||
|
mail:
|
||||||
|
# 内容长度
|
||||||
|
length: 6
|
||||||
|
# 过期时间
|
||||||
|
expirationInMinutes: 5
|
||||||
|
# 限制时间
|
||||||
|
limitInSeconds: 60
|
||||||
|
# 模板路径
|
||||||
|
templatePath: mail/captcha.ftl
|
||||||
|
## 短信验证码配置
|
||||||
|
sms:
|
||||||
|
# 内容长度
|
||||||
|
length: 4
|
||||||
|
# 过期时间
|
||||||
|
expirationInMinutes: 5
|
||||||
|
# 模板 ID
|
||||||
|
templateId: 1
|
||||||
|
|
||||||
|
--- ### 日志配置
|
||||||
|
continew-starter.log:
|
||||||
|
# 是否打印日志,开启后可打印访问日志(类似于 Nginx access log)
|
||||||
|
is-print: false
|
||||||
|
## 项目日志配置(配置重叠部分,优先级高于 logback-spring.xml 中的配置)
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
top.continew: INFO
|
||||||
|
file:
|
||||||
|
path: ../logs
|
||||||
|
|
||||||
|
--- ### 跨域配置
|
||||||
|
continew-starter.web.cors:
|
||||||
|
enabled: true
|
||||||
|
# 配置允许跨域的域名
|
||||||
|
allowed-origins:
|
||||||
|
- ${project.url}
|
||||||
|
# 配置允许跨域的请求方式
|
||||||
|
allowed-methods: '*'
|
||||||
|
# 配置允许跨域的请求头
|
||||||
|
allowed-headers: '*'
|
||||||
|
# 配置允许跨域的响应头
|
||||||
|
exposed-headers: '*'
|
||||||
|
|
||||||
|
--- ### 接口文档配置
|
||||||
|
springdoc:
|
||||||
|
swagger-ui:
|
||||||
|
enabled: false
|
||||||
|
## 接口文档增强配置
|
||||||
|
knife4j:
|
||||||
|
# 开启生产环境屏蔽
|
||||||
|
production: true
|
||||||
|
|
||||||
|
--- ### 短信配置
|
||||||
|
sms:
|
||||||
|
# 从 YAML 读取配置
|
||||||
|
config-type: YAML
|
||||||
|
is-print: false
|
||||||
|
blends:
|
||||||
|
cloopen:
|
||||||
|
# 短信厂商
|
||||||
|
supplier: cloopen
|
||||||
|
base-url: https://app.cloopen.com:8883/2013-12-26
|
||||||
|
access-key-id: 你的Access Key
|
||||||
|
access-key-secret: 你的Access Key Secret
|
||||||
|
sdk-app-id: 你的应用ID
|
||||||
|
|
||||||
|
--- ### 邮件配置
|
||||||
|
spring.mail:
|
||||||
|
# 根据需要更换
|
||||||
|
host: smtp.126.com
|
||||||
|
port: 465
|
||||||
|
username: 你的邮箱
|
||||||
|
password: 你的邮箱授权码
|
||||||
|
properties:
|
||||||
|
mail:
|
||||||
|
smtp:
|
||||||
|
auth: true
|
||||||
|
socketFactory:
|
||||||
|
class: javax.net.ssl.SSLSocketFactory
|
||||||
|
port: 465
|
||||||
|
|
||||||
|
--- ### Just Auth 配置
|
||||||
|
justauth:
|
||||||
|
enabled: true
|
||||||
|
type:
|
||||||
|
GITEE:
|
||||||
|
client-id: 5d271b7f638941812aaf8bfc2e2f08f06d6235ef934e0e39537e2364eb8452c4
|
||||||
|
client-secret: 1f7d08**********5b7**********29e
|
||||||
|
redirect-uri: ${project.url}/social/callback?source=gitee
|
||||||
|
GITHUB:
|
||||||
|
client-id: 38080dad08cfbdfacca9
|
||||||
|
client-secret: 1f7d08**********5b7**********29e
|
||||||
|
redirect-uri: ${project.url}/social/callback?source=github
|
||||||
|
cache:
|
||||||
|
type: REDIS
|
||||||
|
|
||||||
|
--- ### Sa-Token 扩展配置
|
||||||
|
sa-token.extension:
|
||||||
|
# 安全配置:排除(放行)路径配置
|
||||||
|
security.excludes:
|
||||||
|
- /error
|
||||||
|
# 静态资源
|
||||||
|
- /*.html
|
||||||
|
- /*/*.html
|
||||||
|
- /*/*.css
|
||||||
|
- /*/*.js
|
||||||
|
- /webSocket/**
|
||||||
|
# 本地存储资源
|
||||||
|
- /file/**
|
||||||
|
|
||||||
|
--- ### 字段加/解密配置
|
||||||
|
continew-starter.security:
|
||||||
|
crypto:
|
||||||
|
enabled: true
|
||||||
|
# 对称加密算法密钥
|
||||||
|
password: abcdefghijklmnop
|
||||||
|
# 非对称加密算法密钥(在线生成 RSA 密钥对:http://web.chacuo.net/netrsakeypair)
|
||||||
|
public-key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAM51dgYtMyF+tTQt80sfFOpSV27a7t9uaUVeFrdGiVxscuizE7H8SMntYqfn9lp8a5GH5P1/GGehVjUD2gF/4kcCAwEAAQ==
|
||||||
|
private-key: MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAznV2Bi0zIX61NC3zSx8U6lJXbtru325pRV4Wt0aJXGxy6LMTsfxIye1ip+f2WnxrkYfk/X8YZ6FWNQPaAX/iRwIDAQABAkEAk/VcAusrpIqA5Ac2P5Tj0VX3cOuXmyouaVcXonr7f+6y2YTjLQuAnkcfKKocQI/juIRQBFQIqqW/m1nmz1wGeQIhAO8XaA/KxzOIgU0l/4lm0A2Wne6RokJ9HLs1YpOzIUmVAiEA3Q9DQrpAlIuiT1yWAGSxA9RxcjUM/1kdVLTkv0avXWsCIE0X8woEjK7lOSwzMG6RpEx9YHdopjViOj1zPVH61KTxAiBmv/dlhqkJ4rV46fIXELZur0pj6WC3N7a4brR8a+CLLQIhAMQyerWl2cPNVtE/8tkziHKbwW3ZUiBXU24wFxedT9iV
|
||||||
|
|
||||||
|
--- ### 密码编码器配置
|
||||||
|
continew-starter.security:
|
||||||
|
password:
|
||||||
|
enabled: true
|
||||||
|
# BCryptPasswordEncoder
|
||||||
|
encoding-id: bcrypt
|
||||||
|
|
||||||
|
--- ### 文件上传配置
|
||||||
|
spring.servlet:
|
||||||
|
multipart:
|
||||||
|
enabled: true
|
||||||
|
# 单文件上传大小限制
|
||||||
|
max-file-size: 10MB
|
||||||
|
# 单次总上传文件大小限制
|
||||||
|
max-request-size: 20MB
|
||||||
|
## 头像支持格式配置
|
||||||
|
avatar:
|
||||||
|
support-suffix: jpg,jpeg,png,gif
|
||||||
|
|
||||||
|
webclient:
|
||||||
|
max-concurrent-requests: 60
|
||||||
|
|
||||||
|
spring:
|
||||||
|
rabbitmq:
|
||||||
|
host: 45.89.233.228
|
||||||
|
port: 5672
|
||||||
|
username: bot
|
||||||
|
password: xiaomi@123
|
||||||
|
|
239
docker/zayac-admin/config/application.yml
Normal file
239
docker/zayac-admin/config/application.yml
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
--- ### 项目配置
|
||||||
|
project:
|
||||||
|
# 名称
|
||||||
|
name: Zayac Admin
|
||||||
|
# 应用名称
|
||||||
|
app-name: zayac-admin
|
||||||
|
# 版本
|
||||||
|
version: 3.1.0-SNAPSHOT
|
||||||
|
# 描述
|
||||||
|
description: 持续迭代优化的前后端分离中后台管理系统框架,开箱即用,持续提供舒适的开发体验。
|
||||||
|
# 基本包
|
||||||
|
base-package: com.zayac.admin
|
||||||
|
## 作者信息配置
|
||||||
|
contact:
|
||||||
|
name: zayac
|
||||||
|
email: stupidzayac@gmail.com
|
||||||
|
url: https://blog.charles7c.top/about/me
|
||||||
|
## 许可协议信息配置
|
||||||
|
license:
|
||||||
|
name: Apache-2.0
|
||||||
|
url: https://github.com/Charles7c/continew-admin/blob/dev/LICENSE
|
||||||
|
|
||||||
|
--- ### 日志配置
|
||||||
|
continew-starter.log:
|
||||||
|
# 包含信息
|
||||||
|
includes:
|
||||||
|
- DESCRIPTION
|
||||||
|
- MODULE
|
||||||
|
- REQUEST_HEADERS
|
||||||
|
- REQUEST_BODY
|
||||||
|
- IP_ADDRESS
|
||||||
|
- BROWSER
|
||||||
|
- OS
|
||||||
|
- RESPONSE_HEADERS
|
||||||
|
- RESPONSE_BODY
|
||||||
|
## 项目日志配置
|
||||||
|
logging:
|
||||||
|
config: classpath:logback-spring.xml
|
||||||
|
|
||||||
|
--- ### 链路跟踪配置
|
||||||
|
continew-starter.web:
|
||||||
|
trace:
|
||||||
|
enabled: true
|
||||||
|
header-name: traceId
|
||||||
|
## TLog 配置
|
||||||
|
tlog:
|
||||||
|
enable-invoke-time-print: false
|
||||||
|
pattern: '[$spanId][$traceId]'
|
||||||
|
mdc-enable: false
|
||||||
|
|
||||||
|
--- ### 线程池配置
|
||||||
|
continew-starter.thread-pool:
|
||||||
|
enabled: true
|
||||||
|
# 队列容量
|
||||||
|
queue-capacity: 128
|
||||||
|
# 活跃时间(单位:秒)
|
||||||
|
keep-alive-seconds: 300
|
||||||
|
|
||||||
|
--- ### 接口文档配置
|
||||||
|
springdoc:
|
||||||
|
# 设置对象型参数的展示形式(设为 true 表示将对象型参数平展开,即对象内的属性直接作为参数展示而不是嵌套在对象内,默认 false)
|
||||||
|
# 如果不添加该全局配置,可以在需要如此处理的对象参数类上使用 @ParameterObject
|
||||||
|
default-flat-param-object: true
|
||||||
|
# 分组配置
|
||||||
|
group-configs:
|
||||||
|
- group: all
|
||||||
|
paths-to-match: /**
|
||||||
|
paths-to-exclude:
|
||||||
|
- /error
|
||||||
|
- group: auth
|
||||||
|
display-name: 系统认证
|
||||||
|
packages-to-scan: ${project.base-package}.webapi.auth
|
||||||
|
- group: common
|
||||||
|
display-name: 通用接口
|
||||||
|
packages-to-scan: ${project.base-package}.webapi.common
|
||||||
|
- group: system
|
||||||
|
display-name: 系统管理
|
||||||
|
packages-to-scan: ${project.base-package}.webapi.system
|
||||||
|
- group: monitor
|
||||||
|
display-name: 系统监控
|
||||||
|
packages-to-scan: ${project.base-package}.webapi.monitor
|
||||||
|
## 组件配置
|
||||||
|
components:
|
||||||
|
# 鉴权配置
|
||||||
|
security-schemes:
|
||||||
|
Authorization:
|
||||||
|
type: HTTP
|
||||||
|
in: HEADER
|
||||||
|
name: ${sa-token.token-name}
|
||||||
|
scheme: ${sa-token.token-prefix}
|
||||||
|
## 接口文档增强配置
|
||||||
|
knife4j:
|
||||||
|
enable: true
|
||||||
|
setting:
|
||||||
|
# 是否显示默认的 footer(默认 true,显示)
|
||||||
|
enable-footer: false
|
||||||
|
# 是否自定义 footer(默认 false,非自定义)
|
||||||
|
enable-footer-custom: true
|
||||||
|
# 自定义 footer 内容,支持 Markdown 语法
|
||||||
|
footer-custom-content: 'Copyright © 2022-present [${project.contact.name}](${project.contact.url}) ⋅ [${project.name}](${project.url}) v${project.version}'
|
||||||
|
|
||||||
|
--- ### Sa-Token 配置
|
||||||
|
sa-token:
|
||||||
|
# token 名称(同时也是 cookie 名称)
|
||||||
|
token-name: Authorization
|
||||||
|
# token 有效期(单位:秒,默认 30 天,-1 代表永不过期)
|
||||||
|
timeout: 86400
|
||||||
|
# token 最低活跃频率(单位:秒,默认 -1,代表不限制,永不冻结。如果 token 超过此时间没有访问系统就会被冻结)
|
||||||
|
active-timeout: 1800
|
||||||
|
# 是否打开自动续签(如果此值为 true,框架会在每次直接或间接调用 getLoginId() 时进行一次过期检查与续签操作)
|
||||||
|
auto-renew: true
|
||||||
|
# 是否允许同一账号多地同时登录(为 true 时允许一起登录,为 false 时新登录挤掉旧登录)
|
||||||
|
is-concurrent: true
|
||||||
|
# 在多人登录同一账号时,是否共用一个 token(为 true 时所有登录共用一个 token,为 false 时每次登录新建一个 token)
|
||||||
|
is-share: false
|
||||||
|
# 是否输出操作日志
|
||||||
|
is-log: false
|
||||||
|
# JWT 秘钥
|
||||||
|
jwt-secret-key: asdasdasifhueuiwyurfewbfjsdafjk
|
||||||
|
## 扩展配置
|
||||||
|
extension:
|
||||||
|
enabled: true
|
||||||
|
enableJwt: true
|
||||||
|
# 持久层配置
|
||||||
|
dao.type: REDIS
|
||||||
|
|
||||||
|
--- ### MyBatis Plus 配置
|
||||||
|
mybatis-plus:
|
||||||
|
# Mapper XML 文件目录配置
|
||||||
|
mapper-locations: classpath*:/mapper/**/*Mapper.xml
|
||||||
|
# 类型别名扫描包配置
|
||||||
|
type-aliases-package: ${project.base-package}.**.model
|
||||||
|
configuration:
|
||||||
|
# MyBatis 自动映射策略
|
||||||
|
# NONE:不启用 PARTIAL:只对非嵌套 resultMap 自动映射 FULL:对所有 resultMap 自动映射
|
||||||
|
auto-mapping-behavior: PARTIAL
|
||||||
|
global-config:
|
||||||
|
banner: true
|
||||||
|
db-config:
|
||||||
|
# 主键类型(默认 assign_id,表示自行赋值)
|
||||||
|
# auto 代表使用数据库自增策略(需要在表中设置好自增约束)
|
||||||
|
id-type: ASSIGN_ID
|
||||||
|
# 逻辑删除字段
|
||||||
|
logic-delete-field: isDeleted
|
||||||
|
# 逻辑删除全局值(默认 1,表示已删除)
|
||||||
|
logic-delete-value: 1
|
||||||
|
# 逻辑未删除全局值(默认 0,表示未删除)
|
||||||
|
logic-not-delete-value: 0
|
||||||
|
## 扩展配置
|
||||||
|
extension:
|
||||||
|
enabled: true
|
||||||
|
# Mapper 接口扫描包配置
|
||||||
|
mapper-package: ${project.base-package}.**.mapper
|
||||||
|
# ID 生成器配置
|
||||||
|
id-generator:
|
||||||
|
type: COSID
|
||||||
|
# 数据权限配置
|
||||||
|
data-permission:
|
||||||
|
enabled: true
|
||||||
|
# 分页插件配置
|
||||||
|
pagination:
|
||||||
|
enabled: true
|
||||||
|
db-type: MYSQL
|
||||||
|
|
||||||
|
--- ### CosId 配置
|
||||||
|
cosid:
|
||||||
|
namespace: ${spring.application.name}
|
||||||
|
machine:
|
||||||
|
enabled: true
|
||||||
|
# 机器号分配器
|
||||||
|
distributor:
|
||||||
|
type: REDIS
|
||||||
|
guarder:
|
||||||
|
# 开启机器号守护
|
||||||
|
enabled: true
|
||||||
|
snowflake:
|
||||||
|
enabled: true
|
||||||
|
zone-id: Asia/Shanghai
|
||||||
|
epoch: 1577203200000
|
||||||
|
share:
|
||||||
|
# 开启时钟回拨同步
|
||||||
|
clock-sync: true
|
||||||
|
friendly: true
|
||||||
|
provider:
|
||||||
|
safe-js:
|
||||||
|
machine-bit: 3
|
||||||
|
sequence-bit: 9
|
||||||
|
|
||||||
|
--- ### 服务器配置
|
||||||
|
server:
|
||||||
|
servlet:
|
||||||
|
# 应用访问路径
|
||||||
|
context-path: /
|
||||||
|
## Undertow 服务器配置
|
||||||
|
undertow:
|
||||||
|
# HTTP POST 请求内容的大小上限(默认 -1,不限制)
|
||||||
|
max-http-post-size: -1
|
||||||
|
# 以下的配置会影响 buffer,这些 buffer 会用于服务器连接的 IO 操作,有点类似 Netty 的池化内存管理
|
||||||
|
# 每块 buffer的空间大小(越小的空间被利用越充分,不要设置太大,以免影响其他应用,合适即可)
|
||||||
|
buffer-size: 512
|
||||||
|
# 是否分配的直接内存(NIO 直接分配的堆外内存)
|
||||||
|
direct-buffers: true
|
||||||
|
threads:
|
||||||
|
# 设置 IO 线程数,它主要执行非阻塞的任务,它们会负责多个连接(默认每个 CPU 核心一个线程)
|
||||||
|
io: 8
|
||||||
|
# 阻塞任务线程池,当执行类似 Servlet 请求阻塞操作,Undertow 会从这个线程池中取得线程(它的值设置取决于系统的负载)
|
||||||
|
worker: 256
|
||||||
|
|
||||||
|
--- ### Spring 配置
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: ${project.app-name}
|
||||||
|
## 环境配置
|
||||||
|
profiles:
|
||||||
|
# 启用的环境
|
||||||
|
active: dev
|
||||||
|
include:
|
||||||
|
- generator
|
||||||
|
main:
|
||||||
|
# 允许定义重名的 bean 对象覆盖原有的 bean
|
||||||
|
allow-bean-definition-overriding: true
|
||||||
|
# 允许循环依赖
|
||||||
|
allow-circular-references: true
|
||||||
|
|
||||||
|
--- ### 健康检查配置
|
||||||
|
management.health:
|
||||||
|
mail:
|
||||||
|
# 关闭邮箱健康检查(邮箱配置错误或邮箱服务器不可用时,健康检查会报错)
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
webclient:
|
||||||
|
max-concurrent-requests: 60
|
||||||
|
|
||||||
|
spring:
|
||||||
|
rabbitmq:
|
||||||
|
host: 45.89.233.228
|
||||||
|
port: 5672
|
||||||
|
username: bot
|
||||||
|
password: xiaomi@123
|
@ -1,12 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.mapper;
|
package com.zayac.admin.agent.mapper;
|
||||||
|
|
||||||
import top.continew.starter.data.mybatis.plus.base.BaseMapper;
|
import top.continew.starter.data.mybatis.plus.base.BaseMapper;
|
||||||
import com.zayac.admin.agent.model.entity.StatsDO;
|
import com.zayac.admin.agent.model.entity.StatsDO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 代理每日数据 Mapper
|
* 代理每日数据 Mapper
|
||||||
*
|
*
|
||||||
* @author zayac
|
* @author zayac
|
||||||
* @since 2024/06/04 17:10
|
* @since 2024/06/04 17:10
|
||||||
*/
|
*/
|
||||||
public interface DailyStatsMapper extends BaseMapper<StatsDO> {}
|
public interface DailyStatsMapper extends BaseMapper<StatsDO> {}
|
@ -1,12 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.mapper;
|
package com.zayac.admin.agent.mapper;
|
||||||
|
|
||||||
import top.continew.starter.data.mybatis.plus.base.BaseMapper;
|
import top.continew.starter.data.mybatis.plus.base.BaseMapper;
|
||||||
import com.zayac.admin.agent.model.entity.FinanceDO;
|
import com.zayac.admin.agent.model.entity.FinanceDO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 代理线财务报 Mapper
|
* 代理线财务报 Mapper
|
||||||
*
|
*
|
||||||
* @author zayac
|
* @author zayac
|
||||||
* @since 2024/06/04 17:14
|
* @since 2024/06/04 17:14
|
||||||
*/
|
*/
|
||||||
public interface FinanceMapper extends BaseMapper<FinanceDO> {}
|
public interface FinanceMapper extends BaseMapper<FinanceDO> {}
|
@ -1,12 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.mapper;
|
package com.zayac.admin.agent.mapper;
|
||||||
|
|
||||||
import top.continew.starter.data.mybatis.plus.base.BaseMapper;
|
import top.continew.starter.data.mybatis.plus.base.BaseMapper;
|
||||||
import com.zayac.admin.agent.model.entity.FinanceSumDO;
|
import com.zayac.admin.agent.model.entity.FinanceSumDO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 财务报汇总 Mapper
|
* 财务报汇总 Mapper
|
||||||
*
|
*
|
||||||
* @author zayac
|
* @author zayac
|
||||||
* @since 2024/06/04 17:10
|
* @since 2024/06/04 17:10
|
||||||
*/
|
*/
|
||||||
public interface FinanceSumMapper extends BaseMapper<FinanceSumDO> {}
|
public interface FinanceSumMapper extends BaseMapper<FinanceSumDO> {}
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.model.entity;
|
package com.zayac.admin.agent.model.entity;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.model.entity;
|
package com.zayac.admin.agent.model.entity;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.model.entity;
|
package com.zayac.admin.agent.model.entity;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
@ -1,9 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.model.query;
|
package com.zayac.admin.agent.model.query;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
@ -1,17 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.model.query;
|
package com.zayac.admin.agent.model.query;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
import top.continew.starter.data.core.annotation.Query;
|
|
||||||
import top.continew.starter.data.core.enums.QueryType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 财务报汇总查询条件
|
* 财务报汇总查询条件
|
||||||
*
|
*
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.model.query;
|
package com.zayac.admin.agent.model.query;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.model.req;
|
package com.zayac.admin.agent.model.req;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
@ -5,14 +21,10 @@ import java.time.LocalDate;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
import jakarta.validation.constraints.*;
|
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
import org.hibernate.validator.constraints.Length;
|
|
||||||
|
|
||||||
import top.continew.starter.extension.crud.model.req.BaseReq;
|
import top.continew.starter.extension.crud.model.req.BaseReq;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,16 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.model.req;
|
package com.zayac.admin.agent.model.req;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
import org.hibernate.validator.constraints.Length;
|
|
||||||
|
|
||||||
import top.continew.starter.extension.crud.model.req.BaseReq;
|
import top.continew.starter.extension.crud.model.req.BaseReq;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.model.req;
|
package com.zayac.admin.agent.model.req;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.model.resp;
|
package com.zayac.admin.agent.model.resp;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.model.resp;
|
package com.zayac.admin.agent.model.resp;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.model.resp;
|
package com.zayac.admin.agent.model.resp;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.model.resp;
|
package com.zayac.admin.agent.model.resp;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.model.resp;
|
package com.zayac.admin.agent.model.resp;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.model.resp;
|
package com.zayac.admin.agent.model.resp;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.service;
|
package com.zayac.admin.agent.service;
|
||||||
|
|
||||||
import com.zayac.admin.agent.model.entity.FinanceDO;
|
import com.zayac.admin.agent.model.entity.FinanceDO;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.service;
|
package com.zayac.admin.agent.service;
|
||||||
|
|
||||||
import top.continew.starter.extension.crud.service.BaseService;
|
import top.continew.starter.extension.crud.service.BaseService;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.service;
|
package com.zayac.admin.agent.service;
|
||||||
|
|
||||||
import com.zayac.admin.agent.model.entity.StatsDO;
|
import com.zayac.admin.agent.model.entity.StatsDO;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.service.impl;
|
package com.zayac.admin.agent.service.impl;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
@ -1,6 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.service.impl;
|
package com.zayac.admin.agent.service.impl;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -25,7 +40,7 @@ import java.util.List;
|
|||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class FinanceServiceImpl extends BaseServiceImpl<FinanceMapper, FinanceDO, FinanceResp, FinanceDetailResp, FinanceQuery, FinanceReq> implements FinanceService {
|
public class FinanceServiceImpl extends BaseServiceImpl<FinanceMapper, FinanceDO, FinanceResp, FinanceDetailResp, FinanceQuery, FinanceReq> implements FinanceService {
|
||||||
public void addAll(List<FinanceDO> financeReqList){
|
public void addAll(List<FinanceDO> financeReqList) {
|
||||||
baseMapper.insertBatch(financeReqList);
|
baseMapper.insertBatch(financeReqList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.agent.service.impl;
|
package com.zayac.admin.agent.service.impl;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.config;
|
package com.zayac.admin.config;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.req;
|
package com.zayac.admin.req;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.req.team;
|
package com.zayac.admin.req.team;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.resp.team;
|
package com.zayac.admin.resp.team;
|
||||||
|
|
||||||
import com.zayac.admin.resp.Pagination;
|
import com.zayac.admin.resp.Pagination;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.resp.team;
|
package com.zayac.admin.resp.team;
|
||||||
|
|
||||||
import com.zayac.admin.resp.Venue;
|
import com.zayac.admin.resp.Venue;
|
||||||
@ -7,6 +23,7 @@ import lombok.NoArgsConstructor;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.resp.team;
|
package com.zayac.admin.resp.team;
|
||||||
|
|
||||||
import com.zayac.admin.resp.Pagination;
|
import com.zayac.admin.resp.Pagination;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.resp.team;
|
package com.zayac.admin.resp.team;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
@ -16,20 +16,17 @@
|
|||||||
|
|
||||||
package com.zayac.admin.schedule;
|
package com.zayac.admin.schedule;
|
||||||
|
|
||||||
import com.zayac.admin.common.enums.DisEnableStatusEnum;
|
|
||||||
import com.zayac.admin.req.team.TeamInfoReq;
|
import com.zayac.admin.req.team.TeamInfoReq;
|
||||||
import com.zayac.admin.resp.team.Team;
|
import com.zayac.admin.resp.team.Team;
|
||||||
import com.zayac.admin.resp.team.TeamAccount;
|
import com.zayac.admin.resp.team.TeamAccount;
|
||||||
import com.zayac.admin.service.*;
|
import com.zayac.admin.service.*;
|
||||||
import com.zayac.admin.system.model.entity.RoleDO;
|
|
||||||
import com.zayac.admin.system.model.entity.UserDO;
|
|
||||||
import com.zayac.admin.system.model.resp.AccountResp;
|
import com.zayac.admin.system.model.resp.AccountResp;
|
||||||
import com.zayac.admin.system.service.AccountService;
|
import com.zayac.admin.system.model.resp.DeptUsersResp;
|
||||||
import com.zayac.admin.system.service.RoleService;
|
import com.zayac.admin.system.model.resp.UserWithRolesAndAccountsResp;
|
||||||
import com.zayac.admin.system.service.UserRoleService;
|
import com.zayac.admin.system.service.*;
|
||||||
import com.zayac.admin.system.service.UserService;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.annotation.Profile;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -37,6 +34,7 @@ import java.time.LocalDate;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.time.temporal.TemporalAdjusters;
|
import java.time.temporal.TemporalAdjusters;
|
||||||
|
import java.util.AbstractMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
@ -51,13 +49,11 @@ import java.util.stream.Collectors;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@Profile("prod")
|
||||||
public class CheckRegAndDep {
|
public class CheckRegAndDep {
|
||||||
|
|
||||||
private final UserService userService;
|
|
||||||
private final AccountService accountService;
|
|
||||||
private final TeamService teamService;
|
private final TeamService teamService;
|
||||||
private final RoleService roleService;
|
private final DeptService deptService;
|
||||||
private final UserRoleService userRoleService;
|
|
||||||
private final RegistrationService registrationService;
|
private final RegistrationService registrationService;
|
||||||
private final DepositService depositService;
|
private final DepositService depositService;
|
||||||
private final Executor asyncTaskExecutor;
|
private final Executor asyncTaskExecutor;
|
||||||
@ -66,37 +62,56 @@ public class CheckRegAndDep {
|
|||||||
private static final long FIXED_DELAY = 60000L;
|
private static final long FIXED_DELAY = 60000L;
|
||||||
|
|
||||||
@Scheduled(fixedDelay = FIXED_DELAY)
|
@Scheduled(fixedDelay = FIXED_DELAY)
|
||||||
public void CheckRegistrationAndNewDeposit() {
|
public void checkRegistrationAndNewDeposit() {
|
||||||
LocalDate nowDate = LocalDate.now();
|
LocalDate nowDate = LocalDate.now();
|
||||||
LocalDateTime nowDateTime = LocalDateTime.now();
|
LocalDateTime nowDateTime = LocalDateTime.now();
|
||||||
RoleDO minister = roleService.getByCode(MINISTER_ROLE_CODE);
|
//查询用户角色为部长的部门所有用户
|
||||||
List<Long> userIds = userRoleService.listUserIdByRoleId(minister.getId());
|
List<DeptUsersResp> deptWithUsersAndAccounts = deptService.getDeptWithUsersAndAccounts(MINISTER_ROLE_CODE);
|
||||||
userIds.forEach(userId -> {
|
deptWithUsersAndAccounts.forEach(dept -> {
|
||||||
processUser(userService.getById(userId), nowDate, nowDateTime).join();
|
//根据用户角色对部门用户进行分组
|
||||||
|
Map<String, List<UserWithRolesAndAccountsResp>> usersByRole = dept.getUsers()
|
||||||
|
.stream()
|
||||||
|
.flatMap(user -> user.getRoles()
|
||||||
|
.stream()
|
||||||
|
.map(role -> new AbstractMap.SimpleEntry<>(role.getCode(), user)))
|
||||||
|
.collect(Collectors.groupingByConcurrent(Map.Entry::getKey, Collectors
|
||||||
|
.mapping(Map.Entry::getValue, Collectors.toList())));
|
||||||
|
// 获取所有账号的username与用户的映射
|
||||||
|
Map<String, UserWithRolesAndAccountsResp> accountUsernameToUserMap = dept.getUsers()
|
||||||
|
.stream()
|
||||||
|
.flatMap(user -> user.getAccounts()
|
||||||
|
.stream()
|
||||||
|
.map(account -> new AbstractMap.SimpleEntry<>(account.getUsername(), user)))
|
||||||
|
.collect(Collectors.toConcurrentMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||||
|
|
||||||
|
var ministerUser = usersByRole.get(MINISTER_ROLE_CODE).get(0);
|
||||||
|
processUser(ministerUser, accountUsernameToUserMap, nowDate, nowDateTime).join();
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletableFuture<Void> processUser(UserDO minister, LocalDate nowDate, LocalDateTime nowDateTime) {
|
private CompletableFuture<Void> processUser(UserWithRolesAndAccountsResp minister,
|
||||||
List<AccountResp> accounts = accountService.getAccountsByUserId(minister.getId(), DisEnableStatusEnum.ENABLE)
|
Map<String, UserWithRolesAndAccountsResp> accountUsernameToUserMap,
|
||||||
.stream()
|
LocalDate nowDate,
|
||||||
.filter(AccountResp::getIsTeam)
|
LocalDateTime nowDateTime) {
|
||||||
.toList();
|
//根据总线用户的账号查询数据
|
||||||
|
List<AccountResp> accounts = minister.getAccounts();
|
||||||
List<CompletableFuture<Void>> futures = accounts.stream()
|
List<CompletableFuture<Void>> futures = accounts.stream()
|
||||||
.map(account -> processTeamAccount(minister, account, nowDate, nowDateTime))
|
.map(account -> processTeamAccount(minister, accountUsernameToUserMap, account, nowDate, nowDateTime))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletableFuture<Void> processTeamAccount(UserDO minister,
|
private CompletableFuture<Void> processTeamAccount(UserWithRolesAndAccountsResp minister,
|
||||||
|
Map<String, UserWithRolesAndAccountsResp> accountUsernameToUserMap,
|
||||||
AccountResp account,
|
AccountResp account,
|
||||||
LocalDate nowDate,
|
LocalDate nowDate,
|
||||||
LocalDateTime nowDateTime) {
|
LocalDateTime nowDateTime) {
|
||||||
TeamInfoReq teamInfoReq = TeamInfoReq.builder()
|
TeamInfoReq teamInfoReq = TeamInfoReq.builder()
|
||||||
.startDate(nowDateTime.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN))
|
.startDate(nowDateTime.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN))
|
||||||
.endDate(nowDateTime.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX))
|
.endDate(nowDateTime.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX))
|
||||||
.build();
|
.build();
|
||||||
CompletableFuture<Team> teamFuture = teamService.getLatestTeamInfoAsync(account, teamInfoReq);
|
CompletableFuture<Team> teamFuture = teamService.getLatestTeamInfoAsync(account, teamInfoReq);
|
||||||
Team prevTeamInfo = teamService.getPreviousTeamInfo(account);
|
Team prevTeamInfo = teamService.getPreviousTeamInfo(account);
|
||||||
|
|
||||||
@ -104,22 +119,21 @@ public class CheckRegAndDep {
|
|||||||
log.info("Previous Team Info: {}", prevTeamInfo);
|
log.info("Previous Team Info: {}", prevTeamInfo);
|
||||||
log.info("Current Team Info: {}", currentTeamInfo);
|
log.info("Current Team Info: {}", currentTeamInfo);
|
||||||
Map<String, TeamAccount> teamAccountMap = currentTeamInfo.getList()
|
Map<String, TeamAccount> teamAccountMap = currentTeamInfo.getList()
|
||||||
.stream()
|
.stream()
|
||||||
.collect(Collectors.toMap(TeamAccount::getAgentName, Function.identity()));
|
.collect(Collectors.toMap(TeamAccount::getAgentName, Function.identity()));
|
||||||
|
|
||||||
CompletableFuture<Void> registrationProcess = registrationService
|
CompletableFuture<Void> registrationProcess = registrationService
|
||||||
.processRegistration(minister, account, currentTeamInfo, prevTeamInfo, nowDate, teamAccountMap, asyncTaskExecutor)
|
.processRegistration(minister, account, accountUsernameToUserMap, teamAccountMap, currentTeamInfo, prevTeamInfo, nowDate, asyncTaskExecutor)
|
||||||
.thenRunAsync(() -> log.info("Registration process completed"), asyncTaskExecutor);
|
.thenRunAsync(() -> log.info("Registration process completed"), asyncTaskExecutor);
|
||||||
|
|
||||||
CompletableFuture<Void> depositProcess = depositService
|
CompletableFuture<Void> depositProcess = depositService
|
||||||
.processDeposits(minister, account, currentTeamInfo, prevTeamInfo, nowDate, nowDateTime, asyncTaskExecutor)
|
.processDeposits(minister, accountUsernameToUserMap, account, currentTeamInfo, prevTeamInfo, nowDate, nowDateTime, asyncTaskExecutor)
|
||||||
.thenRunAsync(() -> log.info("Deposit process completed"), asyncTaskExecutor);
|
.thenRunAsync(() -> log.info("Deposit process completed"), asyncTaskExecutor);
|
||||||
|
|
||||||
return CompletableFuture.allOf(registrationProcess, depositProcess)
|
return CompletableFuture.allOf(registrationProcess, depositProcess).thenRunAsync(() -> {
|
||||||
.thenRunAsync(() -> {
|
teamService.updateTeamInfo(account, currentTeamInfo);
|
||||||
teamService.updateTeamInfo(account, currentTeamInfo);
|
log.info("Team info updated");
|
||||||
log.info("Team info updated");
|
}, asyncTaskExecutor);
|
||||||
}, asyncTaskExecutor);
|
|
||||||
}, asyncTaskExecutor);
|
}, asyncTaskExecutor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package com.zayac.admin.schedule;
|
package com.zayac.admin.schedule;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.zayac.admin.agent.model.entity.FinanceDO;
|
import com.zayac.admin.agent.model.entity.FinanceDO;
|
||||||
import com.zayac.admin.agent.model.entity.StatsDO;
|
import com.zayac.admin.agent.model.entity.StatsDO;
|
||||||
@ -34,13 +35,14 @@ import com.zayac.admin.req.team.TeamMemberReq;
|
|||||||
import com.zayac.admin.resp.*;
|
import com.zayac.admin.resp.*;
|
||||||
import com.zayac.admin.resp.team.*;
|
import com.zayac.admin.resp.team.*;
|
||||||
import com.zayac.admin.service.*;
|
import com.zayac.admin.service.*;
|
||||||
import com.zayac.admin.system.model.entity.RoleDO;
|
|
||||||
import com.zayac.admin.system.model.entity.UserDO;
|
|
||||||
import com.zayac.admin.system.model.resp.AccountResp;
|
import com.zayac.admin.system.model.resp.AccountResp;
|
||||||
|
import com.zayac.admin.system.model.resp.DeptUsersResp;
|
||||||
|
import com.zayac.admin.system.model.resp.UserWithRolesAndAccountsResp;
|
||||||
import com.zayac.admin.system.service.*;
|
import com.zayac.admin.system.service.*;
|
||||||
import com.zayac.admin.utils.TableFormatter;
|
import com.zayac.admin.utils.TableFormatter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.annotation.Profile;
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@ -60,12 +62,10 @@ import java.util.stream.Collectors;
|
|||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@Profile("prod")
|
||||||
public class DailyReport {
|
public class DailyReport {
|
||||||
private final UserService userService;
|
|
||||||
private final TeamService teamService;
|
private final TeamService teamService;
|
||||||
private final RoleService roleService;
|
private final DeptService deptService;
|
||||||
private final UserRoleService userRoleService;
|
|
||||||
private final AccountService accountService;
|
|
||||||
private final TelegramMessageService telegramMessageService;
|
private final TelegramMessageService telegramMessageService;
|
||||||
private final AgentDataVisualListService agentDataVisualListService;
|
private final AgentDataVisualListService agentDataVisualListService;
|
||||||
private final StatsService statsService;
|
private final StatsService statsService;
|
||||||
@ -76,20 +76,93 @@ public class DailyReport {
|
|||||||
private final Executor asyncTaskExecutor;
|
private final Executor asyncTaskExecutor;
|
||||||
|
|
||||||
private static final String MINISTER_ROLE_CODE = "minister";
|
private static final String MINISTER_ROLE_CODE = "minister";
|
||||||
|
private static final String SEO_TEAM_LEADER_ROLE_CODE = "seo_team_leader";
|
||||||
|
private static final String ASSISTANT_ROLE_CODE = "assistant";
|
||||||
|
private static final String SEO_ROLE_CODE = "seo";
|
||||||
|
|
||||||
@Scheduled(cron = "0 40 11,14,17,21 * * ?")
|
@Scheduled(cron = "0 40 11,14,17,21 * * ?")
|
||||||
public void teamAccountDailyReport() {
|
public void teamAccountDailyReport() {
|
||||||
LocalDateTime nowDateTime = LocalDateTime.now();
|
LocalDateTime nowDateTime = LocalDateTime.now();
|
||||||
LocalDate nowDate = LocalDate.now();
|
LocalDate nowDate = LocalDate.now();
|
||||||
sendDailyReport(nowDate, nowDate.atStartOfDay(), nowDateTime);
|
//查询部门下的所有用户
|
||||||
|
List<DeptUsersResp> deptWithUsersAndAccounts = deptService.getDeptWithUsersAndAccounts(MINISTER_ROLE_CODE);
|
||||||
|
deptWithUsersAndAccounts.forEach(dept -> {
|
||||||
|
//根据用户角色对部门用户进行分组
|
||||||
|
Map<String, List<UserWithRolesAndAccountsResp>> usersByRole = dept.getUsers()
|
||||||
|
.stream()
|
||||||
|
.flatMap(user -> user.getRoles()
|
||||||
|
.stream()
|
||||||
|
.map(role -> new AbstractMap.SimpleEntry<>(role.getCode(), user)))
|
||||||
|
.collect(Collectors.groupingByConcurrent(Map.Entry::getKey, Collectors
|
||||||
|
.mapping(Map.Entry::getValue, Collectors.toList())));
|
||||||
|
|
||||||
|
var ministerUser = usersByRole.get(MINISTER_ROLE_CODE).get(0);
|
||||||
|
//获取账号不为空的用户
|
||||||
|
var deptUsers = dept.getUsers().stream().filter(user -> CollUtil.isNotEmpty(user.getAccounts())).toList();
|
||||||
|
var assistants = usersByRole.get(ASSISTANT_ROLE_CODE);
|
||||||
|
sendDailyReport(nowDate, nowDate.atStartOfDay(), nowDateTime, ministerUser, assistants, deptUsers);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(cron = "0 15 0 * * ?")
|
@Scheduled(cron = "0 15 0 * * ?")
|
||||||
public void dailySummarize() {
|
public void dailySummarize() {
|
||||||
LocalDate yesterday = LocalDate.now().minusDays(1);
|
LocalDate yesterday = LocalDate.now().minusDays(1);
|
||||||
sendDailyReport(yesterday, yesterday.atStartOfDay(), LocalDateTime.of(yesterday, LocalTime.MAX));
|
//查询部门下的所有用户
|
||||||
getPayFailedMember(yesterday);
|
List<DeptUsersResp> deptWithUsersAndAccounts = deptService.getDeptWithUsersAndAccounts(MINISTER_ROLE_CODE);
|
||||||
saveData(yesterday);
|
|
||||||
|
deptWithUsersAndAccounts.forEach(dept -> {
|
||||||
|
//根据用户角色对部门用户进行分组
|
||||||
|
Map<String, List<UserWithRolesAndAccountsResp>> usersByRole = dept.getUsers()
|
||||||
|
.stream()
|
||||||
|
.flatMap(user -> user.getRoles()
|
||||||
|
.stream()
|
||||||
|
.map(role -> new AbstractMap.SimpleEntry<>(role.getCode(), user)))
|
||||||
|
.collect(Collectors.groupingByConcurrent(Map.Entry::getKey, Collectors
|
||||||
|
.mapping(Map.Entry::getValue, Collectors.toList())));
|
||||||
|
// 获取所有账号的username与用户的映射
|
||||||
|
Map<String, UserWithRolesAndAccountsResp> accountUsernameToUserMap = dept.getUsers()
|
||||||
|
.stream()
|
||||||
|
.flatMap(user -> user.getAccounts()
|
||||||
|
.stream()
|
||||||
|
.map(account -> new AbstractMap.SimpleEntry<>(account.getUsername(), user)))
|
||||||
|
.collect(Collectors.toConcurrentMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||||
|
|
||||||
|
var ministerUser = usersByRole.get(MINISTER_ROLE_CODE).get(0);
|
||||||
|
//获取账号不为空的用户
|
||||||
|
var deptUsers = dept.getUsers().stream().filter(user -> CollUtil.isNotEmpty(user.getAccounts())).toList();
|
||||||
|
var assistants = usersByRole.get(ASSISTANT_ROLE_CODE);
|
||||||
|
|
||||||
|
sendDailyReport(yesterday, yesterday.atStartOfDay(), LocalDateTime
|
||||||
|
.of(yesterday, LocalTime.MAX), ministerUser, assistants, deptUsers);
|
||||||
|
getPayFailedMember(ministerUser, accountUsernameToUserMap, yesterday);
|
||||||
|
saveData(ministerUser, deptUsers, yesterday);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 一小时发送一次
|
||||||
|
@Scheduled(cron = "0 0 * * * ?")
|
||||||
|
//@Scheduled(fixedDelay = 6000L)
|
||||||
|
public void generateTeamReportTask() {
|
||||||
|
LocalDateTime nowDateTime = LocalDateTime.now();
|
||||||
|
LocalDate nowDate = LocalDate.now();
|
||||||
|
//查询部门下的所有用户
|
||||||
|
List<DeptUsersResp> deptWithUsersAndAccounts = deptService.getDeptWithUsersAndAccounts(MINISTER_ROLE_CODE);
|
||||||
|
|
||||||
|
deptWithUsersAndAccounts.forEach(dept -> {
|
||||||
|
//根据用户角色对部门用户进行分组
|
||||||
|
Map<String, List<UserWithRolesAndAccountsResp>> usersByRole = dept.getUsers()
|
||||||
|
.stream()
|
||||||
|
.flatMap(user -> user.getRoles()
|
||||||
|
.stream()
|
||||||
|
.map(role -> new AbstractMap.SimpleEntry<>(role.getCode(), user)))
|
||||||
|
.collect(Collectors.groupingByConcurrent(Map.Entry::getKey, Collectors
|
||||||
|
.mapping(Map.Entry::getValue, Collectors.toList())));
|
||||||
|
|
||||||
|
var userWithRolesAndAccountsResps = usersByRole.get(MINISTER_ROLE_CODE);
|
||||||
|
userWithRolesAndAccountsResps.forEach(ministerUser -> generateAndSendTeamReport(ministerUser, nowDate
|
||||||
|
.atStartOfDay(), nowDateTime, null));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,137 +170,131 @@ public class DailyReport {
|
|||||||
*
|
*
|
||||||
* @param date 日期
|
* @param date 日期
|
||||||
*/
|
*/
|
||||||
private void getPayFailedMember(LocalDate date) {
|
private void getPayFailedMember(UserWithRolesAndAccountsResp ministerUser,
|
||||||
RoleDO minister = roleService.getByCode(MINISTER_ROLE_CODE);
|
Map<String, UserWithRolesAndAccountsResp> accountUsernameToUserMap,
|
||||||
List<Long> userIds = userRoleService.listUserIdByRoleId(minister.getId());
|
LocalDate date) {
|
||||||
|
|
||||||
TeamMemberReq memberListReq = TeamMemberReq.builder()
|
TeamMemberReq memberListReq = TeamMemberReq.builder()
|
||||||
.registerStartDate(date)
|
.registerStartDate(date)
|
||||||
.registerEndDate(date)
|
.registerEndDate(date)
|
||||||
.startDate(date)
|
.startDate(date)
|
||||||
.endDate(date)
|
.endDate(date)
|
||||||
.registerSort(1)
|
.registerSort(1)
|
||||||
.status(1)
|
.status(1)
|
||||||
.pageSize(100)
|
.pageSize(100)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
userIds.forEach(userId -> {
|
List<CompletableFuture<List<TeamMember>>> futureList = new ArrayList<>();
|
||||||
List<CompletableFuture<List<TeamMember>>> futureList = new ArrayList<>();
|
ministerUser.getAccounts().forEach(account -> {
|
||||||
UserDO ministerUser = userService.getById(userId);
|
CompletableFuture<MemberPagination<List<TeamMember>>> memberPaginationCompletableFuture = completableFutureWebClientService
|
||||||
List<AccountResp> accounts = accountService.getAccountsByUserId(userId, DisEnableStatusEnum.ENABLE)
|
.fetchDataForAccount(account, ApiPathConstants.MEMBER_TEAM_LIST_URL, memberListReq, new ParameterizedTypeReference<>() {
|
||||||
.stream()
|
|
||||||
.filter(AccountResp::getIsTeam)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
accounts.forEach(account -> {
|
|
||||||
CompletableFuture<MemberPagination<List<TeamMember>>> memberPaginationCompletableFuture = completableFutureWebClientService
|
|
||||||
.fetchDataForAccount(account, ApiPathConstants.MEMBER_TEAM_LIST_URL, memberListReq, new ParameterizedTypeReference<>() {
|
|
||||||
});
|
|
||||||
|
|
||||||
CompletableFuture<List<TeamMember>> teamMembersFuture = memberPaginationCompletableFuture.thenApply(MemberPagination::getList)
|
|
||||||
.thenApplyAsync(members -> members.stream()
|
|
||||||
.filter(member -> member.getDeposit() != null && member.getDeposit().compareTo(BigDecimal.ZERO) == 0)
|
|
||||||
.collect(Collectors.toList()), asyncTaskExecutor)
|
|
||||||
.thenComposeAsync(membersWithoutDep -> {
|
|
||||||
List<CompletableFuture<TeamMember>> memberFutures = membersWithoutDep.stream()
|
|
||||||
.map(memberWithoutDep -> {
|
|
||||||
PayRecordListReq req = PayRecordListReq.builder()
|
|
||||||
.startDate(date)
|
|
||||||
.endDate(date)
|
|
||||||
.pageSize(100)
|
|
||||||
.id(memberWithoutDep.getId())
|
|
||||||
.build();
|
|
||||||
CompletableFuture<PayRecordList<List<PayRecord>>> completableFuture = completableFutureWebClientService
|
|
||||||
.fetchDataForAccount(account, ApiPathConstants.PAY_RECORD_LIST_URL, req, new ParameterizedTypeReference<>() {
|
|
||||||
});
|
|
||||||
return completableFuture.thenApplyAsync(pagination -> {
|
|
||||||
if (pagination.getOrderAmountTotal().compareTo(BigDecimal.ZERO) > 0
|
|
||||||
&& pagination.getScoreAmountTotal().compareTo(BigDecimal.ZERO) == 0) {
|
|
||||||
return memberWithoutDep;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}, asyncTaskExecutor);
|
|
||||||
}).toList();
|
|
||||||
|
|
||||||
return CompletableFuture.allOf(memberFutures.toArray(new CompletableFuture[0]))
|
|
||||||
.thenApply(v -> memberFutures.stream()
|
|
||||||
.map(CompletableFuture::join)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.collect(Collectors.toList()));
|
|
||||||
}, asyncTaskExecutor)
|
|
||||||
.thenApplyAsync(membersWithoutDep -> {
|
|
||||||
// 发送给每个account关联的user用户
|
|
||||||
if (!membersWithoutDep.isEmpty()) {
|
|
||||||
Map<String, List<TeamMember>> groupByTopAgentName = membersWithoutDep.stream()
|
|
||||||
.collect(Collectors.groupingBy(TeamMember::getTopAgentName));
|
|
||||||
groupByTopAgentName.forEach((accountName, accountMembers) -> {
|
|
||||||
String notification = telegramMessageService
|
|
||||||
.buildFailedPayMessage(accountName, accountMembers);
|
|
||||||
UserDO currUser = accountService.getUserByAccountUsername(accountName);
|
|
||||||
if (currUser != null && DisEnableStatusEnum.ENABLE.equals(currUser.getNeedNotify())) {
|
|
||||||
String botToken = StrUtil.isEmpty(currUser.getBotToken()) ? ministerUser.getBotToken() : currUser.getBotToken();
|
|
||||||
telegramMessageService.sendMessage(botToken, currUser.getRegAndDepIds(), notification);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return membersWithoutDep;
|
|
||||||
}, asyncTaskExecutor);
|
|
||||||
|
|
||||||
futureList.add(teamMembersFuture);
|
|
||||||
});
|
|
||||||
|
|
||||||
CompletableFuture<Void> allFutures = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0]));
|
|
||||||
allFutures.thenRunAsync(() -> {
|
|
||||||
// 主线下的所有的存款失败用户
|
|
||||||
List<TeamMember> allTeamMembers = futureList.stream()
|
|
||||||
.map(CompletableFuture::join)
|
|
||||||
.flatMap(List::stream)
|
|
||||||
.toList();
|
|
||||||
Map<String, List<TeamMember>> groupByTopAgentName = new TreeMap<>(allTeamMembers.stream()
|
|
||||||
.collect(Collectors.groupingBy(TeamMember::getTopAgentName)));
|
|
||||||
StringBuilder combinedNotification = new StringBuilder();
|
|
||||||
groupByTopAgentName.forEach((accountName, accountMembers) -> {
|
|
||||||
String notification = telegramMessageService
|
|
||||||
.buildFailedPayMessage(accountName, accountMembers);
|
|
||||||
combinedNotification.append(notification).append("\n");
|
|
||||||
});
|
});
|
||||||
telegramMessageService
|
|
||||||
.sendMessage("6013830443:AAHUOS4v6Ln19ziZkH-L28-HZQLJrGcvhto", 6054562838L, combinedNotification.toString());
|
|
||||||
if (ministerUser != null && DisEnableStatusEnum.ENABLE.equals(ministerUser.getNeedNotify())) {
|
|
||||||
telegramMessageService.sendMessage(ministerUser.getBotToken(), ministerUser.getReportIds(), combinedNotification.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
}, asyncTaskExecutor).exceptionally(ex -> {
|
CompletableFuture<List<TeamMember>> teamMembersFuture = memberPaginationCompletableFuture
|
||||||
log.error("Error collecting and processing data", ex);
|
.thenApply(MemberPagination::getList)
|
||||||
return null;
|
.thenApplyAsync(members -> members.stream()
|
||||||
});
|
.filter(member -> member.getDeposit() != null && member.getDeposit()
|
||||||
|
.compareTo(BigDecimal.ZERO) == 0)
|
||||||
|
.collect(Collectors.toList()), asyncTaskExecutor)
|
||||||
|
.thenComposeAsync(membersWithoutDep -> {
|
||||||
|
List<CompletableFuture<TeamMember>> memberFutures = membersWithoutDep.stream()
|
||||||
|
.map(memberWithoutDep -> {
|
||||||
|
PayRecordListReq req = PayRecordListReq.builder()
|
||||||
|
.startDate(date)
|
||||||
|
.endDate(date)
|
||||||
|
.pageSize(100)
|
||||||
|
.id(memberWithoutDep.getId())
|
||||||
|
.build();
|
||||||
|
CompletableFuture<PayRecordList<List<PayRecord>>> completableFuture = completableFutureWebClientService
|
||||||
|
.fetchDataForAccount(account, ApiPathConstants.PAY_RECORD_LIST_URL, req, new ParameterizedTypeReference<>() {
|
||||||
|
});
|
||||||
|
return completableFuture.thenApplyAsync(pagination -> {
|
||||||
|
if (pagination.getOrderAmountTotal().compareTo(BigDecimal.ZERO) > 0 && pagination
|
||||||
|
.getScoreAmountTotal()
|
||||||
|
.compareTo(BigDecimal.ZERO) == 0) {
|
||||||
|
return memberWithoutDep;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, asyncTaskExecutor);
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
return CompletableFuture.allOf(memberFutures.toArray(new CompletableFuture[0]))
|
||||||
|
.thenApply(v -> memberFutures.stream()
|
||||||
|
.map(CompletableFuture::join)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}, asyncTaskExecutor)
|
||||||
|
.thenApplyAsync(membersWithoutDep -> {
|
||||||
|
// 发送给每个account关联的user用户
|
||||||
|
if (!membersWithoutDep.isEmpty()) {
|
||||||
|
Map<String, List<TeamMember>> groupByTopAgentName = membersWithoutDep.stream()
|
||||||
|
.collect(Collectors.groupingBy(TeamMember::getTopAgentName));
|
||||||
|
groupByTopAgentName.forEach((accountName, accountMembers) -> {
|
||||||
|
String notification = telegramMessageService
|
||||||
|
.buildFailedPayMessage(accountName, accountMembers);
|
||||||
|
UserWithRolesAndAccountsResp currUser = accountUsernameToUserMap.get(accountName);
|
||||||
|
if (DisEnableStatusEnum.ENABLE.equals(currUser.getNeedNotify())) {
|
||||||
|
String botToken = StrUtil.isEmpty(currUser.getBotToken())
|
||||||
|
? ministerUser.getBotToken()
|
||||||
|
: currUser.getBotToken();
|
||||||
|
telegramMessageService.sendMessage(botToken, currUser.getRegAndDepIds(), notification);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return membersWithoutDep;
|
||||||
|
}, asyncTaskExecutor);
|
||||||
|
|
||||||
|
futureList.add(teamMembersFuture);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
|
CompletableFuture<Void> allFutures = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0]));
|
||||||
private void sendDailyReport(LocalDate reportDate, LocalDateTime startDateTime, LocalDateTime endDateTime) {
|
allFutures.thenRunAsync(() -> {
|
||||||
RoleDO minister = roleService.getByCode(MINISTER_ROLE_CODE);
|
// 主线下的所有的存款失败用户
|
||||||
List<Long> userIds = userRoleService.listUserIdByRoleId(minister.getId());
|
List<TeamMember> allTeamMembers = futureList.stream()
|
||||||
|
.map(CompletableFuture::join)
|
||||||
userIds.forEach(userId -> {
|
.flatMap(List::stream)
|
||||||
UserDO ministerUser = userService.getById(userId);
|
.toList();
|
||||||
List<UserDO> deptUsers = userService.getByDeptId(DisEnableStatusEnum.ENABLE, ministerUser.getDeptId());
|
Map<String, List<TeamMember>> groupByTopAgentName = new TreeMap<>(allTeamMembers.stream()
|
||||||
|
.collect(Collectors.groupingBy(TeamMember::getTopAgentName)));
|
||||||
List<CompletableFuture<Void>> tasks = new ArrayList<>();
|
StringBuilder combinedNotification = new StringBuilder();
|
||||||
|
groupByTopAgentName.forEach((accountName, accountMembers) -> {
|
||||||
if (ministerUser.getNeedNotify() == DisEnableStatusEnum.ENABLE) {
|
String notification = telegramMessageService.buildFailedPayMessage(accountName, accountMembers);
|
||||||
tasks.add(generateAndSendTeamReport(ministerUser, startDateTime, endDateTime));
|
combinedNotification.append(notification).append("\n");
|
||||||
|
});
|
||||||
|
telegramMessageService
|
||||||
|
.sendMessage("6013830443:AAHUOS4v6Ln19ziZkH-L28-HZQLJrGcvhto", 6054562838L, combinedNotification
|
||||||
|
.toString());
|
||||||
|
if (DisEnableStatusEnum.ENABLE.equals(ministerUser.getNeedNotify())) {
|
||||||
|
telegramMessageService.sendMessage(ministerUser.getBotToken(), ministerUser
|
||||||
|
.getReportIds(), combinedNotification.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
AgentDataVisualListReq agentDataVisualListReq = AgentDataVisualListReq.builder()
|
}, asyncTaskExecutor).exceptionally(ex -> {
|
||||||
.monthDate(reportDate)
|
log.error("Error collecting and processing data", ex);
|
||||||
.build();
|
return null;
|
||||||
|
|
||||||
deptUsers.forEach(deptUser -> tasks.add(processDeptUser(deptUser, agentDataVisualListReq, reportDate, ministerUser)));
|
|
||||||
|
|
||||||
CompletableFuture<Void> allTasks = CompletableFuture.allOf(tasks.toArray(new CompletableFuture[0]));
|
|
||||||
allTasks.join();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendDailyReport(LocalDate reportDate,
|
||||||
|
LocalDateTime startDateTime,
|
||||||
|
LocalDateTime endDateTime,
|
||||||
|
UserWithRolesAndAccountsResp ministerUser,
|
||||||
|
List<UserWithRolesAndAccountsResp> assistants,
|
||||||
|
List<UserWithRolesAndAccountsResp> deptUsers) {
|
||||||
|
|
||||||
|
List<CompletableFuture<Void>> tasks = new ArrayList<>();
|
||||||
|
tasks.add(generateAndSendTeamReport(ministerUser, startDateTime, endDateTime, assistants));
|
||||||
|
|
||||||
|
AgentDataVisualListReq agentDataVisualListReq = AgentDataVisualListReq.builder().monthDate(reportDate).build();
|
||||||
|
|
||||||
|
deptUsers.forEach(deptUser -> tasks
|
||||||
|
.add(processDeptUser(deptUser, ministerUser, agentDataVisualListReq, reportDate)));
|
||||||
|
|
||||||
|
CompletableFuture<Void> allTasks = CompletableFuture.allOf(tasks.toArray(new CompletableFuture[0]));
|
||||||
|
allTasks.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -239,44 +306,57 @@ public class DailyReport {
|
|||||||
* @return CompletableFuture<Void>
|
* @return CompletableFuture<Void>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private CompletableFuture<Void> generateAndSendTeamReport(UserDO ministerUser, LocalDateTime
|
private CompletableFuture<Void> generateAndSendTeamReport(UserWithRolesAndAccountsResp ministerUser,
|
||||||
startDateTime, LocalDateTime endDateTime) {
|
LocalDateTime startDateTime,
|
||||||
|
LocalDateTime endDateTime,
|
||||||
|
List<UserWithRolesAndAccountsResp> assistants) {
|
||||||
return CompletableFuture.runAsync(() -> {
|
return CompletableFuture.runAsync(() -> {
|
||||||
List<String[]> rows = new ArrayList<>();
|
List<String[]> rows = new ArrayList<>();
|
||||||
rows.add(new String[]{"平台", "注册", "新增", "转化率"});
|
List<AccountResp> accounts = ministerUser.getAccounts();
|
||||||
rows.add(new String[]{"----", "----", "----", "----"});
|
|
||||||
|
|
||||||
List<AccountResp> accounts = accountService.getAccountsByUserId(ministerUser.getId(), DisEnableStatusEnum.ENABLE)
|
|
||||||
.stream()
|
|
||||||
.filter(AccountResp::getIsTeam)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
int[] totals = {0, 0};
|
int[] totals = {0, 0};
|
||||||
TeamInfoReq teamInfoReq = TeamInfoReq.builder().startDate(startDateTime).endDate(endDateTime).build();
|
TeamInfoReq teamInfoReq = TeamInfoReq.builder().startDate(startDateTime).endDate(endDateTime).build();
|
||||||
|
|
||||||
List<CompletableFuture<Void>> futures = accounts.stream()
|
List<CompletableFuture<Void>> futures = accounts.stream()
|
||||||
.map(accountResp -> teamService.getLatestTeamInfoAsync(accountResp, teamInfoReq)
|
.map(accountResp -> teamService.getLatestTeamInfoAsync(accountResp, teamInfoReq)
|
||||||
.thenAcceptAsync(team -> {
|
.thenAcceptAsync(team -> {
|
||||||
int totalNewMember = team.getList().stream().mapToInt(TeamAccount::getSubMemberNum).sum();
|
int totalNewMember = team.getList().stream().mapToInt(TeamAccount::getSubMemberNum).sum();
|
||||||
int totalNewFirstDeposit = team.getList().stream().mapToInt(TeamAccount::getFirstDepositNum).sum();
|
int totalNewFirstDeposit = team.getList()
|
||||||
synchronized (totals) {
|
.stream()
|
||||||
totals[0] += totalNewMember;
|
.mapToInt(TeamAccount::getFirstDepositNum)
|
||||||
totals[1] += totalNewFirstDeposit;
|
.sum();
|
||||||
}
|
synchronized (totals) {
|
||||||
String percent = getPercent(totalNewFirstDeposit, totalNewMember);
|
totals[0] += totalNewMember;
|
||||||
synchronized (rows) {
|
totals[1] += totalNewFirstDeposit;
|
||||||
rows.add(new String[]{accountResp.getPlatformName(), String.valueOf(totalNewMember), String.valueOf(totalNewFirstDeposit), percent});
|
}
|
||||||
}
|
String percent = getPercent(totalNewFirstDeposit, totalNewMember);
|
||||||
}, asyncTaskExecutor)
|
synchronized (rows) {
|
||||||
)
|
rows.add(new String[] {accountResp.getPlatformName(), String.valueOf(totalNewMember), String
|
||||||
.toList();
|
.valueOf(totalNewFirstDeposit), percent});
|
||||||
|
}
|
||||||
|
}, asyncTaskExecutor))
|
||||||
|
.toList();
|
||||||
|
|
||||||
CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
||||||
allFutures.join();
|
allFutures.join();
|
||||||
|
// 对 rows 列表进行排序
|
||||||
|
rows.sort(Comparator.comparing((String[] row) -> row[0].length()).thenComparing(row -> row[0]));
|
||||||
|
|
||||||
rows.add(new String[]{"总注册", String.valueOf(totals[0]), String.valueOf(totals[1]), getPercent(totals[1], totals[0])});
|
rows.add(new String[] {"总计", String.valueOf(totals[0]), String.valueOf(totals[1]),
|
||||||
|
getPercent(totals[1], totals[0])});
|
||||||
String message = TableFormatter.formatTableAsHtml(rows);
|
String message = TableFormatter.formatTableAsHtml(rows);
|
||||||
telegramMessageService.sendMessage(ministerUser.getBotToken(), ministerUser.getReportIds(), message);
|
if (ministerUser.getNeedNotify() == DisEnableStatusEnum.ENABLE) {
|
||||||
|
telegramMessageService.sendMessage(ministerUser.getBotToken(), ministerUser.getReportIds(), message);
|
||||||
|
}
|
||||||
|
telegramMessageService.sendMessage("6013830443:AAHUOS4v6Ln19ziZkH-L28-HZQLJrGcvhto", 6054562838L, message);
|
||||||
|
//发送消息给助理
|
||||||
|
if (!CollUtil.isEmpty(assistants)) {
|
||||||
|
assistants.forEach(assistant -> {
|
||||||
|
if (assistant.getNeedNotify() == DisEnableStatusEnum.ENABLE) {
|
||||||
|
telegramMessageService.sendMessage(assistant.getBotToken(), assistant.getReportIds(), message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}, asyncTaskExecutor).exceptionally(ex -> {
|
}, asyncTaskExecutor).exceptionally(ex -> {
|
||||||
log.error("Error generating and sending team report", ex);
|
log.error("Error generating and sending team report", ex);
|
||||||
return null;
|
return null;
|
||||||
@ -292,48 +372,46 @@ public class DailyReport {
|
|||||||
* @param ministerUser 上级
|
* @param ministerUser 上级
|
||||||
* @return CompletableFuture<Void>
|
* @return CompletableFuture<Void>
|
||||||
*/
|
*/
|
||||||
private CompletableFuture<Void> processDeptUser(UserDO deptUser, AgentDataVisualListReq
|
private CompletableFuture<Void> processDeptUser(UserWithRolesAndAccountsResp deptUser,
|
||||||
agentDataVisualListReq, LocalDate reportDate, UserDO ministerUser) {
|
UserWithRolesAndAccountsResp ministerUser,
|
||||||
|
AgentDataVisualListReq agentDataVisualListReq,
|
||||||
|
LocalDate reportDate) {
|
||||||
return CompletableFuture.runAsync(() -> {
|
return CompletableFuture.runAsync(() -> {
|
||||||
List<AccountResp> currUserAccounts = accountService.getAccountsByUserId(deptUser.getId(), DisEnableStatusEnum.ENABLE)
|
List<AccountResp> currUserAccounts = deptUser.getAccounts();
|
||||||
.stream()
|
|
||||||
.filter(accountResp -> !accountResp.getIsTeam())
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
List<CompletableFuture<Statics>> futures = currUserAccounts.stream()
|
List<CompletableFuture<Statics>> futures = currUserAccounts.stream()
|
||||||
.map(currAccount -> agentDataVisualListService.getAgentDataVisualList(currAccount, agentDataVisualListReq)
|
.map(currAccount -> agentDataVisualListService
|
||||||
.thenApplyAsync(agentData -> agentData.getCurData()
|
.getAgentDataVisualList(currAccount, agentDataVisualListReq)
|
||||||
.stream()
|
.thenApplyAsync(agentData -> agentData.getCurData()
|
||||||
.filter(data -> data.getStaticsDate().equals(reportDate))
|
.stream()
|
||||||
.findFirst()
|
.filter(data -> data.getStaticsDate().equals(reportDate))
|
||||||
.orElseThrow(() -> new BusinessException("No data found for report date"))
|
.findFirst()
|
||||||
)
|
.orElseThrow(() -> new BusinessException("No data found for report date")))
|
||||||
.exceptionally(ex -> {
|
.exceptionally(ex -> {
|
||||||
log.error("Error fetching data for account {}: {}", currAccount.getId(), ex.getMessage());
|
log.error("Error fetching data for account {}: {}", currAccount.getId(), ex.getMessage());
|
||||||
return null;
|
return null;
|
||||||
})
|
}))
|
||||||
)
|
.toList();
|
||||||
.toList();
|
|
||||||
|
|
||||||
CompletableFuture<Void> userStaticsFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
CompletableFuture<Void> userStaticsFuture = CompletableFuture.allOf(futures
|
||||||
|
.toArray(new CompletableFuture[0]));
|
||||||
userStaticsFuture.thenRunAsync(() -> {
|
userStaticsFuture.thenRunAsync(() -> {
|
||||||
List<Statics> agentDataList = futures.stream()
|
List<Statics> agentDataList = futures.stream().map(future -> {
|
||||||
.map(future -> {
|
try {
|
||||||
try {
|
return future.join();
|
||||||
return future.join();
|
} catch (Exception ex) {
|
||||||
} catch (Exception ex) {
|
log.error("Error joining future", ex);
|
||||||
log.error("Error joining future", ex);
|
return null;
|
||||||
return null;
|
}
|
||||||
}
|
}).filter(Objects::nonNull).collect(Collectors.toList());
|
||||||
})
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
// 构造消息体
|
// 构造消息体
|
||||||
String message = telegramMessageService.buildDailyReportMessage(agentDataList);
|
String message = telegramMessageService.buildDailyReportMessage(agentDataList);
|
||||||
|
|
||||||
if (StrUtil.isNotBlank(message) && deptUser.getNeedNotify() == DisEnableStatusEnum.ENABLE) {
|
if (StrUtil.isNotBlank(message) && deptUser.getNeedNotify() == DisEnableStatusEnum.ENABLE) {
|
||||||
String botToken = StrUtil.isEmpty(deptUser.getBotToken()) ? ministerUser.getBotToken() : deptUser.getBotToken();
|
String botToken = StrUtil.isEmpty(deptUser.getBotToken())
|
||||||
|
? ministerUser.getBotToken()
|
||||||
|
: deptUser.getBotToken();
|
||||||
telegramMessageService.sendMessage(botToken, deptUser.getReportIds(), message);
|
telegramMessageService.sendMessage(botToken, deptUser.getReportIds(), message);
|
||||||
}
|
}
|
||||||
}, asyncTaskExecutor).exceptionally(ex -> {
|
}, asyncTaskExecutor).exceptionally(ex -> {
|
||||||
@ -346,8 +424,9 @@ public class DailyReport {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void saveData(UserWithRolesAndAccountsResp ministerUser,
|
||||||
private void saveData(LocalDate reportDate) {
|
List<UserWithRolesAndAccountsResp> deptUsers,
|
||||||
|
LocalDate reportDate) {
|
||||||
// 获取传入年月
|
// 获取传入年月
|
||||||
YearMonth inputYearMonth = YearMonth.from(reportDate);
|
YearMonth inputYearMonth = YearMonth.from(reportDate);
|
||||||
|
|
||||||
@ -356,95 +435,90 @@ public class DailyReport {
|
|||||||
YearMonth previousYearMonth = currentYearMonth.minusMonths(1);
|
YearMonth previousYearMonth = currentYearMonth.minusMonths(1);
|
||||||
|
|
||||||
if (inputYearMonth.equals(currentYearMonth) || inputYearMonth.equals(previousYearMonth)) {
|
if (inputYearMonth.equals(currentYearMonth) || inputYearMonth.equals(previousYearMonth)) {
|
||||||
RoleDO minister = roleService.getByCode(MINISTER_ROLE_CODE);
|
|
||||||
List<Long> userIds = userRoleService.listUserIdByRoleId(minister.getId());
|
|
||||||
|
|
||||||
List<CompletableFuture<Void>> tasks = new ArrayList<>();
|
List<CompletableFuture<Void>> tasks = new ArrayList<>();
|
||||||
|
|
||||||
userIds.forEach(userId -> {
|
TeamFinanceReq teamFinanceReq = TeamFinanceReq.builder()
|
||||||
UserDO ministerUser = userService.getById(userId);
|
.pageNum(1)
|
||||||
List<UserDO> deptUsers = userService.getByDeptId(DisEnableStatusEnum.ENABLE, ministerUser.getDeptId());
|
.pageSize(999)
|
||||||
TeamFinanceReq teamFinanceReq = TeamFinanceReq.builder()
|
.commissionDate(reportDate)
|
||||||
.pageNum(1)
|
.build();
|
||||||
.pageSize(999)
|
|
||||||
.commissionDate(reportDate)
|
// 异步处理 ministerUserAccounts
|
||||||
.build();
|
CompletableFuture<Void> ministerAccountsFuture = CompletableFuture.runAsync(() -> {
|
||||||
List<AccountResp> ministerUserAccounts = accountService.getAccountsByUserId(ministerUser.getId(), DisEnableStatusEnum.ENABLE)
|
List<CompletableFuture<Void>> accountFutures = ministerUser.getAccounts()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(AccountResp::getIsTeam)
|
.map(accountResp -> completableFutureFinanceService.getTeamFinance(accountResp, teamFinanceReq)
|
||||||
|
.thenAcceptAsync(financePagination -> {
|
||||||
|
List<FinanceDO> financeReqList = financePagination.getList().stream().map(finance -> {
|
||||||
|
FinanceDO financeDO = new FinanceDO();
|
||||||
|
BeanUtil.copyProperties(finance, financeDO);
|
||||||
|
return financeDO;
|
||||||
|
}).toList();
|
||||||
|
financeService.addAll(financeReqList);
|
||||||
|
FinanceSumReq financeSumReq = new FinanceSumReq();
|
||||||
|
BeanUtil.copyProperties(financePagination.getTotalSumVo(), financeSumReq);
|
||||||
|
financeSumService.add(financeSumReq);
|
||||||
|
}, asyncTaskExecutor)
|
||||||
|
.exceptionally(ex -> {
|
||||||
|
log.error("Error processing minister accounts for account {}", accountResp
|
||||||
|
.getUsername(), ex);
|
||||||
|
return null;
|
||||||
|
}))
|
||||||
|
.toList();
|
||||||
|
CompletableFuture.allOf(accountFutures.toArray(new CompletableFuture[0])).join();
|
||||||
|
}, asyncTaskExecutor).exceptionally(ex -> {
|
||||||
|
log.error("Error processing minister accounts", ex);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
tasks.add(ministerAccountsFuture);
|
||||||
|
|
||||||
|
// 异步处理 deptUsers
|
||||||
|
AgentDataVisualListReq agentDataVisualListReq = AgentDataVisualListReq.builder()
|
||||||
|
.monthDate(reportDate)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
deptUsers.forEach(deptUser -> {
|
||||||
|
CompletableFuture<Void> deptUserFuture = CompletableFuture.runAsync(() -> {
|
||||||
|
List<AccountResp> currUserAccounts = deptUser.getAccounts();
|
||||||
|
List<CompletableFuture<StatsDO>> futures = currUserAccounts.stream()
|
||||||
|
.map(currAccount -> agentDataVisualListService
|
||||||
|
.getAgentDataVisualList(currAccount, agentDataVisualListReq)
|
||||||
|
.thenApplyAsync(agentData -> {
|
||||||
|
Statics statics = agentData.getCurData()
|
||||||
|
.stream()
|
||||||
|
.filter(data -> data.getStaticsDate().equals(reportDate))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new BusinessException("No data found for report date"));
|
||||||
|
StatsDO statsDO = new StatsDO();
|
||||||
|
BeanUtil.copyProperties(statics, statsDO);
|
||||||
|
return statsDO;
|
||||||
|
}, asyncTaskExecutor)
|
||||||
|
.exceptionally(ex -> {
|
||||||
|
log.error("Error fetching data for account {}: {}", currAccount.getId(), ex
|
||||||
|
.getMessage());
|
||||||
|
return null;
|
||||||
|
}))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
// 异步处理 ministerUserAccounts
|
List<StatsDO> list = futures.stream()
|
||||||
CompletableFuture<Void> ministerAccountsFuture = CompletableFuture.runAsync(() ->
|
.map(CompletableFuture::join)
|
||||||
ministerUserAccounts.parallelStream().forEach(accountResp -> {
|
.filter(Objects::nonNull)
|
||||||
TeamFinancePagination<List<TeamAccountFinance>> financePagination = completableFutureFinanceService.getTeamFinance(accountResp, teamFinanceReq).join();
|
.collect(Collectors.toList());
|
||||||
List<FinanceDO> financeReqList = financePagination.getList().stream().map(finance -> {
|
|
||||||
FinanceDO financeDO = new FinanceDO();
|
|
||||||
BeanUtil.copyProperties(finance, financeDO);
|
|
||||||
return financeDO;
|
|
||||||
}).toList();
|
|
||||||
financeService.addAll(financeReqList);
|
|
||||||
FinanceSumReq financeSumReq = new FinanceSumReq();
|
|
||||||
BeanUtil.copyProperties(financePagination.getTotalSumVo(), financeSumReq);
|
|
||||||
financeSumService.add(financeSumReq);
|
|
||||||
}), asyncTaskExecutor)
|
|
||||||
.exceptionally(ex -> {
|
|
||||||
log.error("Error processing minister accounts", ex);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
tasks.add(ministerAccountsFuture);
|
|
||||||
|
|
||||||
// 异步处理 deptUsers
|
statsService.addAll(list);
|
||||||
AgentDataVisualListReq agentDataVisualListReq = AgentDataVisualListReq.builder()
|
}, asyncTaskExecutor).exceptionally(ex -> {
|
||||||
.monthDate(reportDate)
|
log.error("Error processing dept user accounts", ex);
|
||||||
.build();
|
return null;
|
||||||
|
|
||||||
deptUsers.forEach(deptUser -> {
|
|
||||||
CompletableFuture<Void> deptUserFuture = CompletableFuture.runAsync(() -> {
|
|
||||||
List<AccountResp> currUserAccounts = accountService.getAccountsByUserId(deptUser.getId(), DisEnableStatusEnum.ENABLE)
|
|
||||||
.stream()
|
|
||||||
.filter(accountResp -> !accountResp.getIsTeam())
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
List<CompletableFuture<StatsDO>> futures = currUserAccounts.stream()
|
|
||||||
.map(currAccount -> agentDataVisualListService.getAgentDataVisualList(currAccount, agentDataVisualListReq)
|
|
||||||
.thenApplyAsync(agentData -> {
|
|
||||||
Statics statics = agentData.getCurData()
|
|
||||||
.stream()
|
|
||||||
.filter(data -> data.getStaticsDate().equals(reportDate))
|
|
||||||
.findFirst()
|
|
||||||
.orElseThrow(() -> new BusinessException("No data found for report date"));
|
|
||||||
StatsDO statsDO = new StatsDO();
|
|
||||||
BeanUtil.copyProperties(statics, statsDO);
|
|
||||||
return statsDO;
|
|
||||||
}, asyncTaskExecutor)
|
|
||||||
.exceptionally(ex -> {
|
|
||||||
log.error("Error fetching data for account {}: {}", currAccount.getId(), ex.getMessage());
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
).toList();
|
|
||||||
|
|
||||||
List<StatsDO> list = futures.stream()
|
|
||||||
.map(CompletableFuture::join)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
statsService.addAll(list);
|
|
||||||
}, asyncTaskExecutor).exceptionally(ex -> {
|
|
||||||
log.error("Error processing dept user accounts", ex);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
tasks.add(deptUserFuture);
|
|
||||||
});
|
});
|
||||||
|
tasks.add(deptUserFuture);
|
||||||
});
|
});
|
||||||
|
|
||||||
CompletableFuture<Void> allTasks = CompletableFuture.allOf(tasks.toArray(new CompletableFuture[0]));
|
CompletableFuture<Void> allTasks = CompletableFuture.allOf(tasks.toArray(new CompletableFuture[0]));
|
||||||
allTasks.join();
|
allTasks.join();
|
||||||
} else {
|
} else {
|
||||||
throw new BusinessException("只允许查询当月以及上个月的数据");
|
throw new BusinessException("只允许查询当月以及上个月的数据");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public static String getPercent(int x, int y) {
|
public static String getPercent(int x, int y) {
|
||||||
double d1 = x * 1.0;
|
double d1 = x * 1.0;
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.service;
|
package com.zayac.admin.service;
|
||||||
|
|
||||||
import com.zayac.admin.constant.ApiPathConstants;
|
import com.zayac.admin.constant.ApiPathConstants;
|
||||||
@ -17,7 +33,8 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
public class CompletableFutureFinanceService {
|
public class CompletableFutureFinanceService {
|
||||||
private final CompletableFutureWebClientService completableFutureWebClientService;
|
private final CompletableFutureWebClientService completableFutureWebClientService;
|
||||||
|
|
||||||
public CompletableFuture<TeamFinancePagination<List<TeamAccountFinance>>> getTeamFinance(AccountResp account, TeamFinanceReq teamFinanceReq) {
|
public CompletableFuture<TeamFinancePagination<List<TeamAccountFinance>>> getTeamFinance(AccountResp account,
|
||||||
|
TeamFinanceReq teamFinanceReq) {
|
||||||
//设置一个超大的分页参数 确保一次查询到所有的代理线
|
//设置一个超大的分页参数 确保一次查询到所有的代理线
|
||||||
if (teamFinanceReq.getPageSize() == 0) {
|
if (teamFinanceReq.getPageSize() == 0) {
|
||||||
teamFinanceReq.setPageSize(100);
|
teamFinanceReq.setPageSize(100);
|
||||||
@ -27,7 +44,7 @@ public class CompletableFutureFinanceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return completableFutureWebClientService
|
return completableFutureWebClientService
|
||||||
.fetchDataForAccount(account, ApiPathConstants.TEAM_FINANCE_EXCEL, teamFinanceReq, new ParameterizedTypeReference<>() {
|
.fetchDataForAccount(account, ApiPathConstants.TEAM_FINANCE_EXCEL, teamFinanceReq, new ParameterizedTypeReference<>() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,43 +69,43 @@ public class CompletableFutureWebClientService {
|
|||||||
ParameterizedTypeReference<ApiResponse<T>> typeRef,
|
ParameterizedTypeReference<ApiResponse<T>> typeRef,
|
||||||
AccountResp account) {
|
AccountResp account) {
|
||||||
return Mono.fromCallable(() -> {
|
return Mono.fromCallable(() -> {
|
||||||
if (!semaphore.tryAcquire(10, TimeUnit.SECONDS)) {
|
if (!semaphore.tryAcquire(10, TimeUnit.SECONDS)) {
|
||||||
throw new RuntimeException("Unable to acquire a permit");
|
throw new RuntimeException("Unable to acquire a permit");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}).subscribeOn(Schedulers.boundedElastic()).then(this.webClient.post().uri(url).headers(httpHeaders -> {
|
}).subscribeOn(Schedulers.boundedElastic()).then(this.webClient.post().uri(url).headers(httpHeaders -> {
|
||||||
try {
|
try {
|
||||||
Map<String, String> headerMap = JSONUtil.toBean(headers, new TypeReference<>() {
|
Map<String, String> headerMap = JSONUtil.toBean(headers, new TypeReference<>() {
|
||||||
}, true);
|
}, true);
|
||||||
headerMap.forEach(httpHeaders::add);
|
headerMap.forEach(httpHeaders::add);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Header conversion exception: " + e.getMessage());
|
log.warn("Header conversion exception: " + e.getMessage());
|
||||||
throw new BusinessException("Header conversion failed", e);
|
throw new BusinessException("Header conversion failed", e);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.body(params != null ? BodyInserters.fromValue(params) : BodyInserters.empty())
|
.body(params != null ? BodyInserters.fromValue(params) : BodyInserters.empty())
|
||||||
.retrieve()
|
.retrieve()
|
||||||
.onStatus(HttpStatusCode::isError, response -> Mono.error(new BusinessException("API call failed")))
|
.onStatus(HttpStatusCode::isError, response -> Mono.error(new BusinessException("API call failed")))
|
||||||
.bodyToMono(String.class)
|
.bodyToMono(String.class)
|
||||||
.doOnNext(resStr -> {
|
.doOnNext(resStr -> {
|
||||||
log.info("request url:{}", url);
|
log.debug("request url:{}", url);
|
||||||
log.info("request headers :{}", headers);
|
log.debug("request headers :{}", headers);
|
||||||
log.info("request params:{}", params);
|
log.debug("request params:{}", params);
|
||||||
log.info("response {}", resStr);
|
log.debug("response {}", resStr);
|
||||||
})
|
})
|
||||||
.flatMap(body -> {
|
.flatMap(body -> {
|
||||||
try {
|
try {
|
||||||
ApiResponse<T> apiResponse = objectMapper.readValue(body, objectMapper.getTypeFactory()
|
ApiResponse<T> apiResponse = objectMapper.readValue(body, objectMapper.getTypeFactory()
|
||||||
.constructType(typeRef.getType()));
|
.constructType(typeRef.getType()));
|
||||||
return Mono.justOrEmpty(apiResponse);
|
return Mono.justOrEmpty(apiResponse);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("JSON parsing exception: " + e.getMessage());
|
log.warn("JSON parsing exception: " + e.getMessage());
|
||||||
return Mono.just(new ApiResponse<T>(null, "Decoding error", 6008));
|
return Mono.just(new ApiResponse<T>(null, "Decoding error", 6008));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.flatMap(response -> respHandler(response, account))
|
.flatMap(response -> respHandler(response, account))
|
||||||
.retryWhen(Retry.backoff(3, Duration.ofSeconds(3)).filter(this::isRetryableException)))
|
.retryWhen(Retry.backoff(3, Duration.ofSeconds(3)).filter(this::isRetryableException)))
|
||||||
.doFinally(signal -> semaphore.release());
|
.doFinally(signal -> semaphore.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isRetryableException(Throwable throwable) {
|
private boolean isRetryableException(Throwable throwable) {
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.service;
|
package com.zayac.admin.service;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
@ -14,9 +30,8 @@ import com.zayac.admin.resp.PayRecord;
|
|||||||
import com.zayac.admin.resp.team.Team;
|
import com.zayac.admin.resp.team.Team;
|
||||||
import com.zayac.admin.resp.team.TeamAccount;
|
import com.zayac.admin.resp.team.TeamAccount;
|
||||||
import com.zayac.admin.resp.team.TeamAccountWithChange;
|
import com.zayac.admin.resp.team.TeamAccountWithChange;
|
||||||
import com.zayac.admin.system.model.entity.UserDO;
|
|
||||||
import com.zayac.admin.system.model.resp.AccountResp;
|
import com.zayac.admin.system.model.resp.AccountResp;
|
||||||
import com.zayac.admin.system.service.AccountService;
|
import com.zayac.admin.system.model.resp.UserWithRolesAndAccountsResp;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
@ -27,8 +42,6 @@ import java.time.LocalDate;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
@ -40,9 +53,12 @@ import java.util.stream.Collectors;
|
|||||||
public class DepositService {
|
public class DepositService {
|
||||||
private final CompletableFutureWebClientService completableFutureWebClientService;
|
private final CompletableFutureWebClientService completableFutureWebClientService;
|
||||||
private final TelegramMessageService telegramMessageService;
|
private final TelegramMessageService telegramMessageService;
|
||||||
private final AccountService accountService;
|
|
||||||
|
|
||||||
public CompletableFuture<Void> processDeposits(UserDO minister,
|
private static final String BOT_TOKEN = "6013830443:AAHUOS4v6Ln19ziZkH-L28-HZQLJrGcvhto";
|
||||||
|
private static final Long TELEGRAM_CHAT_ID = 6054562838L;
|
||||||
|
|
||||||
|
public CompletableFuture<Void> processDeposits(UserWithRolesAndAccountsResp ministerUser,
|
||||||
|
Map<String, UserWithRolesAndAccountsResp> accountUsernameToUserMap,
|
||||||
AccountResp account,
|
AccountResp account,
|
||||||
Team currentTeam,
|
Team currentTeam,
|
||||||
Team previousTeam,
|
Team previousTeam,
|
||||||
@ -53,159 +69,177 @@ public class DepositService {
|
|||||||
return CompletableFuture.completedFuture(null);
|
return CompletableFuture.completedFuture(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return processDepositRecords(minister, account, currentTeam, previousTeam, nowDate, nowDateTime, asyncTaskExecutor);
|
return processDepositRecords(ministerUser, accountUsernameToUserMap, account, currentTeam, previousTeam, nowDate, nowDateTime, asyncTaskExecutor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletableFuture<Void> processDepositRecords(UserDO minister,
|
private CompletableFuture<Void> processDepositRecords(UserWithRolesAndAccountsResp ministerUser,
|
||||||
|
Map<String, UserWithRolesAndAccountsResp> accountUsernameToUserMap,
|
||||||
AccountResp account,
|
AccountResp account,
|
||||||
Team currentTeam,
|
Team currentTeam,
|
||||||
Team previousTeam,
|
Team previousTeam,
|
||||||
LocalDate nowDate,
|
LocalDate nowDate,
|
||||||
LocalDateTime nowDateTime,
|
LocalDateTime nowDateTime,
|
||||||
Executor asyncTaskExecutor) {
|
Executor asyncTaskExecutor) {
|
||||||
PayRecordsListReq req = PayRecordsListReq.builder()
|
List<TeamAccountWithChange> hasNewDepositAccounts = findChangedTeamAccount(previousTeam, currentTeam).stream()
|
||||||
.startDate(nowDate)
|
.filter(teamAccountWithChange -> teamAccountWithChange.getNewDepositNum() > 0)
|
||||||
.endDate(nowDate)
|
.toList();
|
||||||
.pageSize(100)
|
|
||||||
.payState(2)
|
List<CompletableFuture<Void>> allTasks = hasNewDepositAccounts.stream()
|
||||||
.build();
|
.map(accountWithChange -> processAccountChanges(accountWithChange, ministerUser, accountUsernameToUserMap, account, nowDate, nowDateTime, asyncTaskExecutor))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
return CompletableFuture.allOf(allTasks.toArray(new CompletableFuture[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<Void> processAccountChanges(TeamAccountWithChange accountWithChange,
|
||||||
|
UserWithRolesAndAccountsResp ministerUser,
|
||||||
|
Map<String, UserWithRolesAndAccountsResp> accountUsernameToUserMap,
|
||||||
|
AccountResp account,
|
||||||
|
LocalDate nowDate,
|
||||||
|
LocalDateTime nowDateTime,
|
||||||
|
Executor asyncTaskExecutor) {
|
||||||
|
PayRecordsListReq req = createPayRecordsListReq(accountWithChange.getAgentName(), nowDate);
|
||||||
CompletableFuture<Pagination<List<PayRecord>>> paginationCompletableFuture = completableFutureWebClientService
|
CompletableFuture<Pagination<List<PayRecord>>> paginationCompletableFuture = completableFutureWebClientService
|
||||||
.fetchDataForAccount(account, ApiPathConstants.PAY_RECORDS_LIST_URL, req, new ParameterizedTypeReference<>() {
|
.fetchDataForAccount(account, ApiPathConstants.PAY_RECORDS_LIST_URL, req, new ParameterizedTypeReference<>() {
|
||||||
});
|
});
|
||||||
List<TeamAccountWithChange> changedTeamAccounts = findChangedTeamAccount(previousTeam, currentTeam);
|
|
||||||
Set<String> changedAgentNames = changedTeamAccounts.stream()
|
|
||||||
.filter(teamAccountWithChange -> teamAccountWithChange.getNewDepositNum() > 0)
|
|
||||||
.map(TeamAccountWithChange::getAgentName)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
return paginationCompletableFuture.thenApplyAsync(Pagination::getList, asyncTaskExecutor)
|
|
||||||
.thenComposeAsync(payRecords ->
|
|
||||||
processPayRecords(payRecords, changedTeamAccounts, changedAgentNames, minister, account, nowDateTime, asyncTaskExecutor), asyncTaskExecutor)
|
|
||||||
.exceptionally(ex -> {
|
|
||||||
log.error("Error processing deposits for account {}: {}", account.getId(), ex.getMessage());
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private CompletableFuture<Void> processPayRecords(List<PayRecord> payRecords,
|
|
||||||
List<TeamAccountWithChange> changedTeamAccounts,
|
|
||||||
Set<String> changedAgentNames,
|
|
||||||
UserDO minister,
|
|
||||||
AccountResp account,
|
|
||||||
LocalDateTime nowDateTime,
|
|
||||||
Executor asyncTaskExecutor) {
|
|
||||||
Map<String, List<String>> agentNameWithNames = payRecords.stream()
|
|
||||||
.filter(record -> record.getCreatedAt().isAfter(nowDateTime.minusHours(1)) && changedAgentNames
|
|
||||||
.contains(record.getAgentName()))
|
|
||||||
.collect(Collectors.groupingBy(PayRecord::getAgentName, Collectors
|
|
||||||
.mapping(PayRecord::getName, Collectors.collectingAndThen(Collectors
|
|
||||||
.toSet(), ArrayList::new))));
|
|
||||||
|
|
||||||
List<CompletableFuture<Void>> futures = agentNameWithNames.entrySet().stream()
|
|
||||||
.map(entry -> processAgentRecords(entry.getKey(), entry.getValue(), changedTeamAccounts, payRecords, minister, account, asyncTaskExecutor))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
private CompletableFuture<Void> processAgentRecords(String agentName,
|
|
||||||
List<String> names,
|
|
||||||
List<TeamAccountWithChange> changedTeamAccounts,
|
|
||||||
List<PayRecord> payRecords,
|
|
||||||
UserDO minister,
|
|
||||||
AccountResp account,
|
|
||||||
Executor asyncTaskExecutor) {
|
|
||||||
StringBuilder depositResults = new StringBuilder();
|
StringBuilder depositResults = new StringBuilder();
|
||||||
AtomicInteger depositCounter = new AtomicInteger(0);
|
AtomicInteger depositCounter = new AtomicInteger(0);
|
||||||
|
|
||||||
TeamAccountWithChange targetTeamAccount = changedTeamAccounts.stream()
|
return paginationCompletableFuture.thenApply(Pagination::getList)
|
||||||
.filter(teamAccount -> StrUtil.equals(teamAccount.getAgentName(), agentName))
|
.thenComposeAsync(payRecords -> processPayRecords(payRecords, accountWithChange, account, nowDate, nowDateTime, depositResults, depositCounter, asyncTaskExecutor), asyncTaskExecutor)
|
||||||
.findFirst()
|
.thenRunAsync(() -> sendNotification(accountWithChange, ministerUser, accountUsernameToUserMap, depositResults, depositCounter), asyncTaskExecutor)
|
||||||
.orElseThrow(() -> new BusinessException(String.format("can not find agent name %s", agentName)));
|
.exceptionally(ex -> {
|
||||||
|
log.error("Error processing account changes for agent {}: {}", accountWithChange.getAgentName(), ex
|
||||||
List<CompletableFuture<Void>> fetchFutures = names.stream()
|
.getMessage());
|
||||||
.map(name -> fetchMemberDetails(account, name, LocalDate.now(), asyncTaskExecutor).thenAcceptAsync(member ->
|
return null;
|
||||||
payRecords.stream()
|
});
|
||||||
.filter(record -> record.getCreatedAt().equals(member.getFirstPayAt()))
|
|
||||||
.findFirst()
|
|
||||||
.ifPresent(record -> {
|
|
||||||
if (depositCounter.getAndIncrement() < targetTeamAccount.getNewDepositNum()) {
|
|
||||||
depositResults.append(telegramMessageService
|
|
||||||
.buildDepositResultsMessage(member.getName(), record.getScoreAmount()));
|
|
||||||
}
|
|
||||||
}), asyncTaskExecutor).exceptionally(ex -> {
|
|
||||||
log.error("Error fetching details for member {}: {}", name, ex.getMessage());
|
|
||||||
return null;
|
|
||||||
}))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
CompletableFuture<Void> allFetches = CompletableFuture.allOf(fetchFutures.toArray(new CompletableFuture[0]));
|
|
||||||
|
|
||||||
return allFetches.thenRunAsync(() -> {
|
|
||||||
if (!depositResults.isEmpty()) {
|
|
||||||
String notification = telegramMessageService.buildDepositMessage(agentName, targetTeamAccount.getNewDepositNum(),
|
|
||||||
depositResults.toString(), targetTeamAccount.getFirstDepositNum());
|
|
||||||
UserDO currUser = accountService.getUserByAccountUsername(agentName);
|
|
||||||
if (currUser != null && DisEnableStatusEnum.ENABLE.equals(currUser.getNeedNotify())) {
|
|
||||||
String botToken = StrUtil.isEmpty(currUser.getBotToken()) ? minister.getBotToken() : currUser.getBotToken();
|
|
||||||
telegramMessageService.sendMessage(botToken, currUser.getRegAndDepIds(), notification);
|
|
||||||
}
|
|
||||||
telegramMessageService.sendMessage("6013830443:AAHUOS4v6Ln19ziZkH-L28-HZQLJrGcvhto", 6054562838L, notification);
|
|
||||||
}
|
|
||||||
}, asyncTaskExecutor).exceptionally(ex -> {
|
|
||||||
log.error("Error sending notification for account {}: {}", account.getUsername(), ex.getMessage());
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletableFuture<Member> fetchMemberDetails(AccountResp account, String name, LocalDate nowDate, Executor asyncTaskExecutor) {
|
private PayRecordsListReq createPayRecordsListReq(String agentName, LocalDate nowDate) {
|
||||||
|
return PayRecordsListReq.builder()
|
||||||
|
.startDate(nowDate)
|
||||||
|
.endDate(nowDate)
|
||||||
|
.pageSize(100)
|
||||||
|
.payState(2)
|
||||||
|
.agentName(agentName)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<Void> processPayRecords(List<PayRecord> payRecords,
|
||||||
|
TeamAccountWithChange accountWithChange,
|
||||||
|
AccountResp account,
|
||||||
|
LocalDate nowDate,
|
||||||
|
LocalDateTime nowDateTime,
|
||||||
|
StringBuilder depositResults,
|
||||||
|
AtomicInteger depositCounter,
|
||||||
|
Executor asyncTaskExecutor) {
|
||||||
|
Map<String, PayRecord> earliestPayRecords = payRecords.stream()
|
||||||
|
.filter(record -> record.getCreatedAt().isAfter(nowDateTime.minusHours(1)))
|
||||||
|
.collect(Collectors.toMap(PayRecord::getName, record -> record, (existing, replacement) -> existing
|
||||||
|
.getCreatedAt()
|
||||||
|
.isBefore(replacement.getCreatedAt()) ? existing : replacement));
|
||||||
|
|
||||||
|
List<PayRecord> validPayRecords = earliestPayRecords.values().stream().toList();
|
||||||
|
|
||||||
|
List<CompletableFuture<Void>> fetchMemberFutures = validPayRecords.stream()
|
||||||
|
.map(payRecord -> fetchMemberDetails(account, payRecord.getName(), nowDate, asyncTaskExecutor)
|
||||||
|
.thenAcceptAsync(member -> processMemberDetails(member, payRecord, accountWithChange, depositResults, depositCounter), asyncTaskExecutor)
|
||||||
|
.exceptionally(ex -> {
|
||||||
|
log.error("Error fetching details for member {}: {}", payRecord.getName(), ex.getMessage());
|
||||||
|
return null;
|
||||||
|
}))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
return CompletableFuture.allOf(fetchMemberFutures.toArray(new CompletableFuture[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processMemberDetails(Member member,
|
||||||
|
PayRecord payRecord,
|
||||||
|
TeamAccountWithChange accountWithChange,
|
||||||
|
StringBuilder depositResults,
|
||||||
|
AtomicInteger depositCounter) {
|
||||||
|
if (payRecord.getCreatedAt().equals(member.getFirstPayAt()) && depositCounter
|
||||||
|
.getAndIncrement() < accountWithChange.getNewDepositNum()) {
|
||||||
|
depositResults.append(telegramMessageService.buildDepositResultsMessage(member.getName(), payRecord
|
||||||
|
.getScoreAmount()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendNotification(TeamAccountWithChange accountWithChange,
|
||||||
|
UserWithRolesAndAccountsResp ministerUser,
|
||||||
|
Map<String, UserWithRolesAndAccountsResp> accountUsernameToUserMap,
|
||||||
|
StringBuilder depositResults,
|
||||||
|
AtomicInteger depositCounter) {
|
||||||
|
if (depositCounter.get() > 0) {
|
||||||
|
String notification = telegramMessageService.buildDepositMessage(accountWithChange
|
||||||
|
.getAgentName(), accountWithChange.getNewDepositNum(), depositResults.toString(), accountWithChange
|
||||||
|
.getFirstDepositNum());
|
||||||
|
var currUser = accountUsernameToUserMap.get(accountWithChange.getAgentName());
|
||||||
|
if (currUser != null && DisEnableStatusEnum.ENABLE.equals(currUser.getNeedNotify())) {
|
||||||
|
String botToken = StrUtil.isEmpty(currUser.getBotToken())
|
||||||
|
? ministerUser.getBotToken()
|
||||||
|
: currUser.getBotToken();
|
||||||
|
telegramMessageService.sendMessage(botToken, currUser.getRegAndDepIds(), notification);
|
||||||
|
}
|
||||||
|
telegramMessageService.sendMessage(BOT_TOKEN, TELEGRAM_CHAT_ID, notification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<Member> fetchMemberDetails(AccountResp account,
|
||||||
|
String name,
|
||||||
|
LocalDate nowDate,
|
||||||
|
Executor asyncTaskExecutor) {
|
||||||
TeamMemberListReq memberListReq = TeamMemberListReq.builder()
|
TeamMemberListReq memberListReq = TeamMemberListReq.builder()
|
||||||
.name(name)
|
.name(name)
|
||||||
.startDate(nowDate)
|
.startDate(nowDate)
|
||||||
.endDate(nowDate)
|
.endDate(nowDate)
|
||||||
.status(1)
|
.status(1)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
CompletableFuture<MemberPagination<List<Member>>> memberFuture = completableFutureWebClientService
|
CompletableFuture<MemberPagination<List<Member>>> memberFuture = completableFutureWebClientService
|
||||||
.fetchDataForAccount(account, ApiPathConstants.MEMBER_TEAM_LIST_URL, memberListReq, new ParameterizedTypeReference<>() {
|
.fetchDataForAccount(account, ApiPathConstants.MEMBER_TEAM_LIST_URL, memberListReq, new ParameterizedTypeReference<>() {
|
||||||
});
|
});
|
||||||
|
|
||||||
return memberFuture.thenApplyAsync(MemberPagination::getList, asyncTaskExecutor)
|
return memberFuture.thenApplyAsync(MemberPagination::getList, asyncTaskExecutor)
|
||||||
.thenApplyAsync(list -> list.stream().findFirst().orElseThrow(() -> new RuntimeException("没有找到匹配的成员信息")), asyncTaskExecutor)
|
.thenApplyAsync(list -> list.stream()
|
||||||
.thenComposeAsync(member -> fetchDetailedMemberInfo(account, member.getId(), nowDate), asyncTaskExecutor);
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new BusinessException("没有找到匹配的成员信息")), asyncTaskExecutor)
|
||||||
|
.thenComposeAsync(member -> fetchDetailedMemberInfo(account, member.getId(), nowDate), asyncTaskExecutor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletableFuture<Member> fetchDetailedMemberInfo(AccountResp account, Long memberId, LocalDate nowDate) {
|
private CompletableFuture<Member> fetchDetailedMemberInfo(AccountResp account, Long memberId, LocalDate nowDate) {
|
||||||
MemberDetailsReq detailsReq = MemberDetailsReq.builder()
|
MemberDetailsReq detailsReq = MemberDetailsReq.builder()
|
||||||
.id(memberId)
|
.id(memberId)
|
||||||
.startDate(nowDate)
|
.startDate(nowDate)
|
||||||
.endDate(nowDate)
|
.endDate(nowDate)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
return completableFutureWebClientService
|
return completableFutureWebClientService
|
||||||
.fetchDataForAccount(account, ApiPathConstants.MEMBER_DETAIL_URL, detailsReq, new ParameterizedTypeReference<>() {
|
.fetchDataForAccount(account, ApiPathConstants.MEMBER_DETAIL_URL, detailsReq, new ParameterizedTypeReference<>() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<TeamAccountWithChange> findChangedTeamAccount(Team prevTeam, Team currTeam) {
|
private List<TeamAccountWithChange> findChangedTeamAccount(Team prevTeam, Team currTeam) {
|
||||||
Map<Long, TeamAccount> team2AccountMap = currTeam.getList()
|
Map<Long, TeamAccount> team2AccountMap = currTeam.getList()
|
||||||
.stream()
|
.stream()
|
||||||
.collect(Collectors.toMap(TeamAccount::getId, account -> account));
|
.collect(Collectors.toMap(TeamAccount::getId, account -> account));
|
||||||
|
|
||||||
return prevTeam.getList()
|
return prevTeam.getList()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(account1 -> team2AccountMap.containsKey(account1.getId()))
|
.filter(account1 -> team2AccountMap.containsKey(account1.getId()))
|
||||||
.map(account1 -> {
|
.map(account1 -> {
|
||||||
TeamAccount account2 = team2AccountMap.get(account1.getId());
|
TeamAccount account2 = team2AccountMap.get(account1.getId());
|
||||||
TeamAccountWithChange changedAccount = new TeamAccountWithChange();
|
TeamAccountWithChange changedAccount = new TeamAccountWithChange();
|
||||||
BeanUtil.copyProperties(account2, changedAccount);
|
BeanUtil.copyProperties(account2, changedAccount);
|
||||||
if (account1.getFirstDepositNum() != account2.getFirstDepositNum()) {
|
if (account1.getFirstDepositNum() != account2.getFirstDepositNum()) {
|
||||||
changedAccount.setNewDepositNum(account2.getFirstDepositNum() - account1.getFirstDepositNum());
|
changedAccount.setNewDepositNum(account2.getFirstDepositNum() - account1.getFirstDepositNum());
|
||||||
}
|
}
|
||||||
if (account1.getSubMemberNum() != account2.getSubMemberNum()) {
|
if (account1.getSubMemberNum() != account2.getSubMemberNum()) {
|
||||||
changedAccount.setNewRegisterNum(account2.getSubMemberNum() - account1.getSubMemberNum());
|
changedAccount.setNewRegisterNum(account2.getSubMemberNum() - account1.getSubMemberNum());
|
||||||
}
|
}
|
||||||
return changedAccount;
|
return changedAccount;
|
||||||
})
|
})
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.zayac.admin.service;
|
package com.zayac.admin.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.zayac.admin.common.enums.DisEnableStatusEnum;
|
import com.zayac.admin.common.enums.DisEnableStatusEnum;
|
||||||
import com.zayac.admin.constant.ApiPathConstants;
|
import com.zayac.admin.constant.ApiPathConstants;
|
||||||
@ -24,9 +25,8 @@ import com.zayac.admin.resp.MemberPagination;
|
|||||||
import com.zayac.admin.resp.team.Team;
|
import com.zayac.admin.resp.team.Team;
|
||||||
import com.zayac.admin.resp.team.TeamAccount;
|
import com.zayac.admin.resp.team.TeamAccount;
|
||||||
import com.zayac.admin.resp.team.TeamMember;
|
import com.zayac.admin.resp.team.TeamMember;
|
||||||
import com.zayac.admin.system.model.entity.UserDO;
|
|
||||||
import com.zayac.admin.system.model.resp.AccountResp;
|
import com.zayac.admin.system.model.resp.AccountResp;
|
||||||
import com.zayac.admin.system.service.AccountService;
|
import com.zayac.admin.system.model.resp.UserWithRolesAndAccountsResp;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
@ -48,46 +48,50 @@ import java.util.stream.Collectors;
|
|||||||
public class RegistrationService {
|
public class RegistrationService {
|
||||||
private final CompletableFutureWebClientService completableFutureWebClientService;
|
private final CompletableFutureWebClientService completableFutureWebClientService;
|
||||||
private final TelegramMessageService telegramMessageService;
|
private final TelegramMessageService telegramMessageService;
|
||||||
private final AccountService accountService;
|
|
||||||
|
|
||||||
public CompletableFuture<Void> processRegistration(UserDO minister,
|
public CompletableFuture<Void> processRegistration(UserWithRolesAndAccountsResp minister,
|
||||||
AccountResp account,
|
AccountResp account,
|
||||||
|
Map<String, UserWithRolesAndAccountsResp> accountUsernameToUserMap,
|
||||||
|
Map<String, TeamAccount> teamAccountMap,
|
||||||
Team currentTeamInfo,
|
Team currentTeamInfo,
|
||||||
Team prevTeamInfo,
|
Team prevTeamInfo,
|
||||||
LocalDate nowDate,
|
LocalDate nowDate,
|
||||||
Map<String, TeamAccount> teamAccountMap,
|
|
||||||
Executor asyncTaskExecutor) {
|
Executor asyncTaskExecutor) {
|
||||||
if (prevTeamInfo != null && currentTeamInfo.getSubMemberCount() > prevTeamInfo.getSubMemberCount()) {
|
if (prevTeamInfo != null && currentTeamInfo.getSubMemberCount() > prevTeamInfo.getSubMemberCount()) {
|
||||||
int registerCount = currentTeamInfo.getSubMemberCount() - prevTeamInfo.getSubMemberCount();
|
int registerCount = currentTeamInfo.getSubMemberCount() - prevTeamInfo.getSubMemberCount();
|
||||||
TeamMemberReq memberListReq = TeamMemberReq.builder()
|
TeamMemberReq memberListReq = TeamMemberReq.builder()
|
||||||
.registerStartDate(nowDate)
|
.registerStartDate(nowDate)
|
||||||
.registerEndDate(nowDate)
|
.registerEndDate(nowDate)
|
||||||
.startDate(nowDate)
|
.startDate(nowDate)
|
||||||
.endDate(nowDate)
|
.endDate(nowDate)
|
||||||
.registerSort(1)
|
.registerSort(1)
|
||||||
.pageSize(registerCount)
|
.pageSize(registerCount)
|
||||||
.build();
|
.build();
|
||||||
CompletableFuture<MemberPagination<List<TeamMember>>> memberPaginationCompletableFuture = completableFutureWebClientService
|
CompletableFuture<MemberPagination<List<TeamMember>>> memberPaginationCompletableFuture = completableFutureWebClientService
|
||||||
.fetchDataForAccount(account, ApiPathConstants.MEMBER_TEAM_LIST_URL, memberListReq, new ParameterizedTypeReference<>() {
|
.fetchDataForAccount(account, ApiPathConstants.MEMBER_TEAM_LIST_URL, memberListReq, new ParameterizedTypeReference<>() {
|
||||||
});
|
});
|
||||||
return memberPaginationCompletableFuture.thenApplyAsync(MemberPagination::getList, asyncTaskExecutor).thenAcceptAsync(members -> {
|
return memberPaginationCompletableFuture.thenApplyAsync(MemberPagination::getList, asyncTaskExecutor)
|
||||||
log.info("Successfully get [{}] new registered members", members.size());
|
.thenAcceptAsync(members -> {
|
||||||
if (!members.isEmpty()) {
|
log.info("Successfully get [{}] new registered members", members.size());
|
||||||
Map<String, List<TeamMember>> groupByTopAgentName = members.stream()
|
if (CollUtil.isNotEmpty(members)) {
|
||||||
|
Map<String, List<TeamMember>> groupByTopAgentName = members.stream()
|
||||||
.collect(Collectors.groupingBy(TeamMember::getTopAgentName));
|
.collect(Collectors.groupingBy(TeamMember::getTopAgentName));
|
||||||
groupByTopAgentName.forEach((accountName, accountMembers) -> {
|
groupByTopAgentName.forEach((accountName, accountMembers) -> {
|
||||||
String notification = telegramMessageService
|
String notification = telegramMessageService
|
||||||
.buildRegistrationMessage(accountName, accountMembers, teamAccountMap.get(accountName));
|
.buildRegistrationMessage(accountName, accountMembers, teamAccountMap.get(accountName));
|
||||||
UserDO currUser = accountService.getUserByAccountUsername(accountName);
|
var currUser = accountUsernameToUserMap.get(accountName);
|
||||||
if (currUser != null && DisEnableStatusEnum.ENABLE.equals(currUser.getNeedNotify())) {
|
if (currUser != null && DisEnableStatusEnum.ENABLE.equals(currUser.getNeedNotify())) {
|
||||||
String botToken = StrUtil.isEmpty(currUser.getBotToken()) ? minister.getBotToken() : currUser.getBotToken();
|
String botToken = StrUtil.isEmpty(currUser.getBotToken())
|
||||||
telegramMessageService.sendMessage(botToken, currUser.getRegAndDepIds(), notification);
|
? minister.getBotToken()
|
||||||
}
|
: currUser.getBotToken();
|
||||||
telegramMessageService
|
telegramMessageService.sendMessage(botToken, currUser.getRegAndDepIds(), notification);
|
||||||
|
}
|
||||||
|
telegramMessageService
|
||||||
.sendMessage("6013830443:AAHUOS4v6Ln19ziZkH-L28-HZQLJrGcvhto", 6054562838L, notification);
|
.sendMessage("6013830443:AAHUOS4v6Ln19ziZkH-L28-HZQLJrGcvhto", 6054562838L, notification);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, asyncTaskExecutor);
|
}, asyncTaskExecutor);
|
||||||
}
|
}
|
||||||
return CompletableFuture.completedFuture(null);
|
return CompletableFuture.completedFuture(null);
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,4 @@ public class TeamService {
|
|||||||
// Method intentionally left empty, used only for cache update
|
// Method intentionally left empty, used only for cache update
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,6 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class TelegramMessageService {
|
public class TelegramMessageService {
|
||||||
@ -53,13 +52,12 @@ public class TelegramMessageService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void sendMessage(String botToken, List<Long> targetIds, String message) {
|
public void sendMessage(String botToken, List<Long> targetIds, String message) {
|
||||||
targetIds.parallelStream()
|
targetIds.parallelStream().forEach(targetId -> this.sendMessage(botToken, targetId, message));
|
||||||
.forEach(targetId -> this.sendMessage(botToken, targetId, message));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendMessage(String botToken, String targetIds, String message) {
|
public void sendMessage(String botToken, String targetIds, String message) {
|
||||||
convertStringToList(targetIds).parallelStream()
|
convertStringToList(targetIds).parallelStream()
|
||||||
.forEach(targetId -> this.sendMessage(botToken, targetId, message));
|
.forEach(targetId -> this.sendMessage(botToken, targetId, message));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Long> convertStringToList(String str) {
|
public static List<Long> convertStringToList(String str) {
|
||||||
@ -71,7 +69,7 @@ public class TelegramMessageService {
|
|||||||
private static String escapeMarkdown(String text) {
|
private static String escapeMarkdown(String text) {
|
||||||
|
|
||||||
List<Character> escapeChars = Arrays
|
List<Character> escapeChars = Arrays
|
||||||
.asList('_', '[', ']', '(', ')', '~', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!');
|
.asList('_', '[', ']', '(', ')', '~', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!');
|
||||||
for (Character charItem : escapeChars) {
|
for (Character charItem : escapeChars) {
|
||||||
text = text.replace(charItem.toString(), "\\" + charItem);
|
text = text.replace(charItem.toString(), "\\" + charItem);
|
||||||
}
|
}
|
||||||
@ -88,7 +86,7 @@ public class TelegramMessageService {
|
|||||||
TeamAccount teamAccount) {
|
TeamAccount teamAccount) {
|
||||||
String memberNames = accountMembers.stream().map(TeamMember::getName).collect(Collectors.joining(", "));
|
String memberNames = accountMembers.stream().map(TeamMember::getName).collect(Collectors.joining(", "));
|
||||||
return String.format("👏 %s 注册: %d 用户: `%s` 总数:*%d*", accountName, accountMembers
|
return String.format("👏 %s 注册: %d 用户: `%s` 总数:*%d*", accountName, accountMembers
|
||||||
.size(), memberNames, teamAccount.getSubMemberNum());
|
.size(), memberNames, teamAccount.getSubMemberNum());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String buildDepositMessage(String agentName, int newDepositNum, String depositResults, int firstDepositNum) {
|
public String buildDepositMessage(String agentName, int newDepositNum, String depositResults, int firstDepositNum) {
|
||||||
@ -99,23 +97,16 @@ public class TelegramMessageService {
|
|||||||
return String.format("用户: `%s`, 首存金额: *%s*\n", name, scoreAmount);
|
return String.format("用户: `%s`, 首存金额: *%s*\n", name, scoreAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String buildFailedPayMessage(String accountName,
|
public String buildFailedPayMessage(String accountName, List<TeamMember> accountMembers) {
|
||||||
List<TeamMember> accountMembers) {
|
|
||||||
String memberNames = accountMembers.stream().map(TeamMember::getName).collect(Collectors.joining("\n"));
|
String memberNames = accountMembers.stream().map(TeamMember::getName).collect(Collectors.joining("\n"));
|
||||||
return String.format("%s\n%s\n", accountName, memberNames);
|
return String.format("%s\n%s\n", accountName, memberNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String buildDailyReportMessage(List<Statics> statics) {
|
public String buildDailyReportMessage(List<Statics> statics) {
|
||||||
StringBuilder message = new StringBuilder();
|
StringBuilder message = new StringBuilder();
|
||||||
statics.forEach(stat -> {
|
statics.forEach(stat -> {
|
||||||
String formattedStat = String.format(
|
String formattedStat = String.format("%s\n注册: %s\n新增: %d\n日活: %d\n\n", stat.getAgentName(), stat
|
||||||
"%s\n注册: %s\n新增: %d\n日活: %d\n\n",
|
.getIsNew(), stat.getFirstCount(), stat.getCountBets());
|
||||||
stat.getAgentName(),
|
|
||||||
stat.getIsNew(),
|
|
||||||
stat.getFirstCount(),
|
|
||||||
stat.getCountBets()
|
|
||||||
);
|
|
||||||
message.append(formattedStat);
|
message.append(formattedStat);
|
||||||
});
|
});
|
||||||
return message.toString();
|
return message.toString();
|
||||||
|
@ -54,19 +54,19 @@ public class WebClientService {
|
|||||||
try {
|
try {
|
||||||
semaphore.acquire(); // 尝试获取许可
|
semaphore.acquire(); // 尝试获取许可
|
||||||
return this.webClient.post().uri(url).headers(httpHeaders -> {
|
return this.webClient.post().uri(url).headers(httpHeaders -> {
|
||||||
Map<String, String> headerMap = JSONUtil.toBean(headers, new TypeReference<>() {
|
Map<String, String> headerMap = JSONUtil.toBean(headers, new TypeReference<>() {
|
||||||
}, true);
|
}, true);
|
||||||
headerMap.forEach(httpHeaders::add);
|
headerMap.forEach(httpHeaders::add);
|
||||||
})
|
})
|
||||||
.body(params != null ? BodyInserters.fromValue(params) : BodyInserters.empty())
|
.body(params != null ? BodyInserters.fromValue(params) : BodyInserters.empty())
|
||||||
.retrieve()
|
.retrieve()
|
||||||
.onStatus(status -> status.is4xxClientError() || status.is5xxServerError(), response -> response
|
.onStatus(status -> status.is4xxClientError() || status.is5xxServerError(), response -> response
|
||||||
.bodyToMono(String.class)
|
.bodyToMono(String.class)
|
||||||
.map(body -> new BusinessException("Error response: " + body)))
|
.map(body -> new BusinessException("Error response: " + body)))
|
||||||
.bodyToMono(typeRef)
|
.bodyToMono(typeRef)
|
||||||
.flatMap(this::respHandler)
|
.flatMap(this::respHandler)
|
||||||
.retryWhen(Retry.backoff(3, Duration.ofSeconds(3)))
|
.retryWhen(Retry.backoff(3, Duration.ofSeconds(3)))
|
||||||
.block(); // 遇到网络问题,每三秒重试一次
|
.block(); // 遇到网络问题,每三秒重试一次
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
throw new BusinessException("Failed to acquire semaphore", e);
|
throw new BusinessException("Failed to acquire semaphore", e);
|
||||||
@ -82,24 +82,24 @@ public class WebClientService {
|
|||||||
System.out.println(Thread.currentThread().getName());
|
System.out.println(Thread.currentThread().getName());
|
||||||
System.out.println(Thread.currentThread().getId());
|
System.out.println(Thread.currentThread().getId());
|
||||||
return Mono.fromCallable(() -> {
|
return Mono.fromCallable(() -> {
|
||||||
semaphore.acquire(); // 尝试获取许可
|
semaphore.acquire(); // 尝试获取许可
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
.subscribeOn(Schedulers.boundedElastic())
|
.subscribeOn(Schedulers.boundedElastic())
|
||||||
.flatMap(acquired -> this.webClient.post().uri(url).headers(httpHeaders -> {
|
.flatMap(acquired -> this.webClient.post().uri(url).headers(httpHeaders -> {
|
||||||
Map<String, String> headerMap = JSONUtil.toBean(headers, new TypeReference<>() {
|
Map<String, String> headerMap = JSONUtil.toBean(headers, new TypeReference<>() {
|
||||||
}, true);
|
}, true);
|
||||||
headerMap.forEach(httpHeaders::add);
|
headerMap.forEach(httpHeaders::add);
|
||||||
})
|
})
|
||||||
.body(params != null ? BodyInserters.fromValue(params) : BodyInserters.empty())
|
.body(params != null ? BodyInserters.fromValue(params) : BodyInserters.empty())
|
||||||
.retrieve()
|
.retrieve()
|
||||||
.onStatus(status -> status.is4xxClientError() || status.is5xxServerError(), response -> response
|
.onStatus(status -> status.is4xxClientError() || status.is5xxServerError(), response -> response
|
||||||
.bodyToMono(String.class)
|
.bodyToMono(String.class)
|
||||||
.map(body -> new BusinessException("Error response: " + body)))
|
.map(body -> new BusinessException("Error response: " + body)))
|
||||||
.bodyToMono(typeRef)
|
.bodyToMono(typeRef)
|
||||||
.flatMap(this::monoRespHandler)
|
.flatMap(this::monoRespHandler)
|
||||||
.retryWhen(Retry.backoff(3, Duration.ofSeconds(3)))
|
.retryWhen(Retry.backoff(3, Duration.ofSeconds(3)))
|
||||||
.doFinally(signal -> semaphore.release()));
|
.doFinally(signal -> semaphore.release()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> Mono<T> monoRespHandler(ApiResponse<T> apiResponse) {
|
private <T> Mono<T> monoRespHandler(ApiResponse<T> apiResponse) {
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.zayac.admin.utils;
|
package com.zayac.admin.utils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -28,6 +44,8 @@ public class TableFormatter {
|
|||||||
public static String formatTableAsHtml(List<String[]> rows) {
|
public static String formatTableAsHtml(List<String[]> rows) {
|
||||||
int[] colWidths = calculateColumnWidths(rows);
|
int[] colWidths = calculateColumnWidths(rows);
|
||||||
StringBuilder table = new StringBuilder("<pre>\n");
|
StringBuilder table = new StringBuilder("<pre>\n");
|
||||||
|
rows.add(0, new String[] {"平台", "注册", "新增", "转化率"});
|
||||||
|
rows.add(1, new String[] {"----", "----", "----", "----"});
|
||||||
for (String[] row : rows) {
|
for (String[] row : rows) {
|
||||||
table.append(formatRow(row, colWidths)).append("\n");
|
table.append(formatRow(row, colWidths)).append("\n");
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package com.zayac.admin.common.config.mybatis;
|
package com.zayac.admin.common.config.mybatis;
|
||||||
|
|
||||||
import cn.dev33.satoken.exception.NotLoginException;
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||||
import com.zayac.admin.common.util.helper.LoginHelper;
|
import com.zayac.admin.common.util.helper.LoginHelper;
|
||||||
|
@ -71,6 +71,11 @@ public class CacheConstants {
|
|||||||
*/
|
*/
|
||||||
public static final String ENABLED_ACCOUNTS_KEY_PREFIX = "ENABLED_ACCOUNTS" + DELIMITER;
|
public static final String ENABLED_ACCOUNTS_KEY_PREFIX = "ENABLED_ACCOUNTS" + DELIMITER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户角色查询所有用户角色账号缓存前缀
|
||||||
|
*/
|
||||||
|
public static final String DEPT_USERS_ROLES_ACCOUNTS_KEY_PREFIX = "DEPT_USERS_ROLES_ACCOUNTS" + DELIMITER;
|
||||||
|
|
||||||
private CacheConstants() {
|
private CacheConstants() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,11 @@ public class RegexConstants {
|
|||||||
*/
|
*/
|
||||||
public static final String USERNAME = "^[a-zA-Z][a-zA-Z0-9_]{3,64}$";
|
public static final String USERNAME = "^[a-zA-Z][a-zA-Z0-9_]{3,64}$";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码正则严格版(长度为 8 到 32 位,包含至少1个大写字母、1个小写字母、1个数字,1个特殊字符)
|
||||||
|
*/
|
||||||
|
public static final String PASSWORD_STRICT = "^\\S*(?=\\S{8,32})(?=\\S*\\d)(?=\\S*[A-Z])(?=\\S*[a-z])(?=\\S*[!@#$%^&*? ])\\S*$";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 密码正则(长度为 6 到 32 位,可以包含字母、数字、下划线,特殊字符,同时包含字母和数字)
|
* 密码正则(长度为 6 到 32 位,可以包含字母、数字、下划线,特殊字符,同时包含字母和数字)
|
||||||
*/
|
*/
|
||||||
|
@ -38,6 +38,9 @@ public class GeneratePreviewResp implements Serializable {
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "生成的文件路径", example = "continew-admin\\continew-admin\\continew-admin-generator\\src\\main\\java\\top\\continew\\admin\\generator\\service")
|
||||||
|
private String path;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件名
|
* 文件名
|
||||||
*/
|
*/
|
||||||
|
@ -63,6 +63,13 @@ import java.util.*;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代码生成业务实现
|
||||||
|
*
|
||||||
|
* @author Charles7c
|
||||||
|
* @since 2023/4/12 23:58
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 代码生成业务实现
|
* 代码生成业务实现
|
||||||
*
|
*
|
||||||
@ -248,10 +255,38 @@ public class GeneratorServiceImpl implements GeneratorService {
|
|||||||
genConfigMap.put("fieldConfigs", fieldConfigList);
|
genConfigMap.put("fieldConfigs", fieldConfigList);
|
||||||
generatePreview.setContent(TemplateUtils.render(templateConfig.getTemplatePath(), genConfigMap));
|
generatePreview.setContent(TemplateUtils.render(templateConfig.getTemplatePath(), genConfigMap));
|
||||||
}
|
}
|
||||||
|
setPreviewPath(generatePreview, genConfig, templateConfig);
|
||||||
}
|
}
|
||||||
return generatePreviewList;
|
return generatePreviewList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setPreviewPath(GeneratePreviewResp generatePreview,
|
||||||
|
GenConfigDO genConfig,
|
||||||
|
GeneratorProperties.TemplateConfig templateConfig) {
|
||||||
|
// 获取前后端基础路径
|
||||||
|
String backendBasicPackagePath = this.buildBackendBasicPackagePath(genConfig);
|
||||||
|
String frontendBasicPackagePath = String.join(File.separator, projectProperties.getAppName(), projectProperties
|
||||||
|
.getAppName() + "-ui");
|
||||||
|
String packageName = genConfig.getPackageName();
|
||||||
|
String moduleName = StrUtil.subSuf(packageName, StrUtil
|
||||||
|
.lastIndexOfIgnoreCase(packageName, StringConstants.DOT) + 1);
|
||||||
|
String packagePath;
|
||||||
|
if (generatePreview.isBackend()) {
|
||||||
|
// 例如:continew-admin/continew-system/src/main/java/top/continew/admin/system/service/impl
|
||||||
|
packagePath = String.join(File.separator, backendBasicPackagePath, templateConfig.getPackageName()
|
||||||
|
.replace(StringConstants.DOT, File.separator));
|
||||||
|
} else {
|
||||||
|
// 例如:continew-admin/continew-admin-ui/src/views/system
|
||||||
|
packagePath = String.join(File.separator, frontendBasicPackagePath, templateConfig.getPackageName()
|
||||||
|
.replace(StringConstants.SLASH, File.separator), moduleName);
|
||||||
|
// 例如:continew-admin/continew-admin-ui/src/views/system/user
|
||||||
|
packagePath = ".vue".equals(templateConfig.getExtension())
|
||||||
|
? packagePath + File.separator + StrUtil.lowerFirst(genConfig.getClassNamePrefix())
|
||||||
|
: packagePath;
|
||||||
|
}
|
||||||
|
generatePreview.setPath(packagePath);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generate(List<String> tableNames, HttpServletRequest request, HttpServletResponse response) {
|
public void generate(List<String> tableNames, HttpServletRequest request, HttpServletResponse response) {
|
||||||
try {
|
try {
|
||||||
@ -282,37 +317,11 @@ public class GeneratorServiceImpl implements GeneratorService {
|
|||||||
* @param genConfig 生成配置
|
* @param genConfig 生成配置
|
||||||
*/
|
*/
|
||||||
private void generateCode(List<GeneratePreviewResp> generatePreviewList, GenConfigDO genConfig) {
|
private void generateCode(List<GeneratePreviewResp> generatePreviewList, GenConfigDO genConfig) {
|
||||||
// 获取前后端基础路径
|
|
||||||
String backendBasicPackagePath = this.buildBackendBasicPackagePath(genConfig);
|
|
||||||
String frontendBasicPackagePath = SystemUtil.getUserInfo().getTempDir() + String
|
|
||||||
.join(File.separator, projectProperties.getAppName(), projectProperties.getAppName() + "-ui");
|
|
||||||
String packageName = genConfig.getPackageName();
|
|
||||||
String moduleName = StrUtil.subSuf(packageName, StrUtil
|
|
||||||
.lastIndexOfIgnoreCase(packageName, StringConstants.DOT) + 1);
|
|
||||||
// 生成代码
|
|
||||||
Map<String, GeneratorProperties.TemplateConfig> templateConfigMap = generatorProperties.getTemplateConfigs();
|
|
||||||
for (GeneratePreviewResp generatePreview : generatePreviewList) {
|
for (GeneratePreviewResp generatePreview : generatePreviewList) {
|
||||||
// 获取对应模板配置
|
|
||||||
GeneratorProperties.TemplateConfig templateConfig = templateConfigMap.getOrDefault(StrUtil
|
|
||||||
.subBefore(generatePreview.getFileName(), StringConstants.DOT, true)
|
|
||||||
.replace(genConfig.getClassNamePrefix(), StringConstants.EMPTY), templateConfigMap.get("api"));
|
|
||||||
String packagePath;
|
|
||||||
if (generatePreview.isBackend()) {
|
|
||||||
// 例如:continew-admin/continew-system/src/main/java/top/continew/admin/system/service/impl
|
|
||||||
packagePath = String.join(File.separator, backendBasicPackagePath, templateConfig.getPackageName()
|
|
||||||
.replace(StringConstants.DOT, File.separator));
|
|
||||||
} else {
|
|
||||||
// 例如:continew-admin/continew-admin-ui/src/views/system
|
|
||||||
packagePath = String.join(File.separator, frontendBasicPackagePath, templateConfig.getPackageName()
|
|
||||||
.replace(StringConstants.SLASH, File.separator), moduleName);
|
|
||||||
// 例如:continew-admin/continew-admin-ui/src/views/system/user
|
|
||||||
packagePath = ".vue".equals(templateConfig.getExtension())
|
|
||||||
? packagePath + File.separator + StrUtil.lowerFirst(genConfig.getClassNamePrefix())
|
|
||||||
: packagePath;
|
|
||||||
}
|
|
||||||
// 后端:continew-admin/continew-system/src/main/java/top/continew/admin/system/service/impl/XxxServiceImpl.java
|
// 后端:continew-admin/continew-system/src/main/java/top/continew/admin/system/service/impl/XxxServiceImpl.java
|
||||||
// 前端:continew-admin/continew-admin-ui/src/views/system/user/index.vue
|
// 前端:continew-admin/continew-admin-ui/src/views/system/user/index.vue
|
||||||
File file = new File(packagePath, generatePreview.getFileName());
|
File file = new File(SystemUtil.getUserInfo().getTempDir() + generatePreview.getPath(), generatePreview
|
||||||
|
.getFileName());
|
||||||
// 如果已经存在,且不允许覆盖,则跳过
|
// 如果已经存在,且不允许覆盖,则跳过
|
||||||
if (!file.exists() || Boolean.TRUE.equals(genConfig.getIsOverride())) {
|
if (!file.exists() || Boolean.TRUE.equals(genConfig.getIsOverride())) {
|
||||||
FileUtil.writeUtf8String(generatePreview.getContent(), file);
|
FileUtil.writeUtf8String(generatePreview.getContent(), file);
|
||||||
@ -328,9 +337,8 @@ public class GeneratorServiceImpl implements GeneratorService {
|
|||||||
*/
|
*/
|
||||||
private String buildBackendBasicPackagePath(GenConfigDO genConfig) {
|
private String buildBackendBasicPackagePath(GenConfigDO genConfig) {
|
||||||
// 例如:continew-admin/continew-system/src/main/java/top/continew/admin/system
|
// 例如:continew-admin/continew-system/src/main/java/top/continew/admin/system
|
||||||
return SystemUtil.getUserInfo().getTempDir() + String.join(File.separator, projectProperties
|
return String.join(File.separator, projectProperties.getAppName(), projectProperties.getAppName(), genConfig
|
||||||
.getAppName(), projectProperties.getAppName(), genConfig.getModuleName(), "src", "main", "java", genConfig
|
.getModuleName(), "src", "main", "java", genConfig.getPackageName()
|
||||||
.getPackageName()
|
|
||||||
.replace(StringConstants.DOT, File.separator));
|
.replace(StringConstants.DOT, File.separator));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,4 +395,4 @@ public class GeneratorServiceImpl implements GeneratorService {
|
|||||||
String subPackageName = templateConfig.getPackageName();
|
String subPackageName = templateConfig.getPackageName();
|
||||||
genConfigMap.put("subPackageName", subPackageName);
|
genConfigMap.put("subPackageName", subPackageName);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -98,6 +98,12 @@ public class UserInfoResp implements Serializable {
|
|||||||
@Schema(description = "最后一次修改密码时间", example = "2023-08-08 08:08:08", type = "string")
|
@Schema(description = "最后一次修改密码时间", example = "2023-08-08 08:08:08", type = "string")
|
||||||
private LocalDateTime pwdResetTime;
|
private LocalDateTime pwdResetTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码是否已过期
|
||||||
|
*/
|
||||||
|
@Schema(description = "密码是否已过期", example = "true")
|
||||||
|
private Boolean pwdExpired;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建时间
|
* 创建时间
|
||||||
*/
|
*/
|
||||||
|
@ -20,12 +20,11 @@ import cn.hutool.core.bean.BeanUtil;
|
|||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.lang.tree.Tree;
|
import cn.hutool.core.lang.tree.Tree;
|
||||||
import cn.hutool.core.lang.tree.TreeNodeConfig;
|
import cn.hutool.core.lang.tree.TreeNodeConfig;
|
||||||
import cn.hutool.core.util.IdUtil;
|
import cn.hutool.core.util.*;
|
||||||
import cn.hutool.core.util.RandomUtil;
|
|
||||||
import cn.hutool.core.util.ReUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import com.zayac.admin.auth.model.resp.RouteResp;
|
import com.zayac.admin.auth.model.resp.RouteResp;
|
||||||
|
import com.zayac.admin.common.constant.CacheConstants;
|
||||||
|
import com.zayac.admin.system.enums.OptionCodeEnum;
|
||||||
import com.zayac.admin.system.service.*;
|
import com.zayac.admin.system.service.*;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
@ -49,11 +48,13 @@ import com.zayac.admin.system.model.entity.UserSocialDO;
|
|||||||
import com.zayac.admin.system.model.req.MessageReq;
|
import com.zayac.admin.system.model.req.MessageReq;
|
||||||
import com.zayac.admin.system.model.resp.MenuResp;
|
import com.zayac.admin.system.model.resp.MenuResp;
|
||||||
import com.zayac.admin.system.service.*;
|
import com.zayac.admin.system.service.*;
|
||||||
|
import top.continew.starter.cache.redisson.util.RedisUtils;
|
||||||
import top.continew.starter.core.autoconfigure.project.ProjectProperties;
|
import top.continew.starter.core.autoconfigure.project.ProjectProperties;
|
||||||
import top.continew.starter.core.util.validate.CheckUtils;
|
import top.continew.starter.core.util.validate.CheckUtils;
|
||||||
import top.continew.starter.extension.crud.annotation.TreeField;
|
import top.continew.starter.extension.crud.annotation.TreeField;
|
||||||
import top.continew.starter.extension.crud.util.TreeUtils;
|
import top.continew.starter.extension.crud.util.TreeUtils;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@ -77,16 +78,41 @@ public class LoginServiceImpl implements LoginService {
|
|||||||
private final UserSocialService userSocialService;
|
private final UserSocialService userSocialService;
|
||||||
private final MessageService messageService;
|
private final MessageService messageService;
|
||||||
private final PasswordEncoder passwordEncoder;
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
private final OptionService optionService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String accountLogin(String username, String password) {
|
public String accountLogin(String username, String password) {
|
||||||
UserDO user = userService.getByUsername(username);
|
UserDO user = userService.getByUsername(username);
|
||||||
CheckUtils.throwIfNull(user, "用户名或密码不正确");
|
boolean isError = ObjectUtil.isNull(user) || !passwordEncoder.matches(password, user.getPassword());
|
||||||
CheckUtils.throwIf(!passwordEncoder.matches(password, user.getPassword()), "用户名或密码不正确");
|
isPasswordLocked(username, isError);
|
||||||
|
CheckUtils.throwIf(isError, "用户名或密码错误");
|
||||||
this.checkUserStatus(user);
|
this.checkUserStatus(user);
|
||||||
return this.login(user);
|
return this.login(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测用户是否被密码锁定
|
||||||
|
*
|
||||||
|
* @param username 用户名
|
||||||
|
*/
|
||||||
|
private void isPasswordLocked(String username, boolean isError) {
|
||||||
|
// 不锁定账户
|
||||||
|
int maxErrorCount = optionService.getValueByCode2Int(OptionCodeEnum.PASSWORD_ERROR_COUNT);
|
||||||
|
if (maxErrorCount <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String key = CacheConstants.USER_KEY_PREFIX + "PASSWORD-ERROR:" + username;
|
||||||
|
Long currentErrorCount = RedisUtils.get(key);
|
||||||
|
currentErrorCount = currentErrorCount == null ? 0 : currentErrorCount;
|
||||||
|
int lockMinutes = optionService.getValueByCode2Int(OptionCodeEnum.PASSWORD_LOCK_MINUTES);
|
||||||
|
if (isError) {
|
||||||
|
// 密码错误自增次数,并重置时间
|
||||||
|
currentErrorCount = currentErrorCount + 1;
|
||||||
|
RedisUtils.set(key, currentErrorCount, Duration.ofMinutes(lockMinutes));
|
||||||
|
}
|
||||||
|
CheckUtils.throwIf(currentErrorCount >= maxErrorCount, "密码错误已达 {} 次,账户锁定 {} 分钟", maxErrorCount, lockMinutes);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String phoneLogin(String phone) {
|
public String phoneLogin(String phone) {
|
||||||
UserDO user = userService.getByPhone(phone);
|
UserDO user = userService.getByPhone(phone);
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.zayac.admin.system.enums;/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数枚举
|
||||||
|
*
|
||||||
|
* @author Kils
|
||||||
|
* @since 2024/05/09 11:25
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public enum OptionCodeEnum {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码是否允许包含正反序帐户名
|
||||||
|
*/
|
||||||
|
PASSWORD_CONTAIN_NAME("password_contain_name", "密码不允许包含正反序帐户名"),
|
||||||
|
/**
|
||||||
|
* 密码错误锁定帐户次数
|
||||||
|
*/
|
||||||
|
PASSWORD_ERROR_COUNT("password_error_count", "密码错误锁定帐户次数"),
|
||||||
|
/**
|
||||||
|
* 密码有效期
|
||||||
|
*/
|
||||||
|
PASSWORD_EXPIRATION_DAYS("password_expiration_days", "密码有效期"),
|
||||||
|
/**
|
||||||
|
* 密码是否允许包含正反序帐户名
|
||||||
|
*/
|
||||||
|
PASSWORD_LOCK_MINUTES("password_lock_minutes", "密码错误锁定帐户的时间"),
|
||||||
|
/**
|
||||||
|
* 密码最小长度
|
||||||
|
*/
|
||||||
|
PASSWORD_MIN_LENGTH("password_min_length", "密码最小长度"),
|
||||||
|
/**
|
||||||
|
* 密码是否必须包含特殊字符
|
||||||
|
*/
|
||||||
|
PASSWORD_SPECIAL_CHAR("password_special_char", "密码是否必须包含特殊字符"),
|
||||||
|
/**
|
||||||
|
* 修改密码最短间隔
|
||||||
|
*/
|
||||||
|
PASSWORD_UPDATE_INTERVAL("password_update_interval", "修改密码最短间隔");
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
private final String description;
|
||||||
|
}
|
@ -17,12 +17,17 @@
|
|||||||
package com.zayac.admin.system.mapper;
|
package com.zayac.admin.system.mapper;
|
||||||
|
|
||||||
import com.zayac.admin.system.model.entity.AccountDO;
|
import com.zayac.admin.system.model.entity.AccountDO;
|
||||||
|
import com.zayac.admin.system.model.resp.AccountResp;
|
||||||
import top.continew.starter.data.mybatis.plus.base.BaseMapper;
|
import top.continew.starter.data.mybatis.plus.base.BaseMapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 账号 Mapper
|
* 账号 Mapper
|
||||||
*
|
*
|
||||||
* @author zayac
|
* @author zayac
|
||||||
* @since 2024/05/10 20:44
|
* @since 2024/05/10 20:44
|
||||||
*/
|
*/
|
||||||
public interface AccountMapper extends BaseMapper<AccountDO> {}
|
public interface AccountMapper extends BaseMapper<AccountDO> {
|
||||||
|
List<AccountResp> selectAccountsByUserIds(List<Long> userIds);
|
||||||
|
}
|
@ -17,8 +17,12 @@
|
|||||||
package com.zayac.admin.system.mapper;
|
package com.zayac.admin.system.mapper;
|
||||||
|
|
||||||
import com.zayac.admin.system.model.entity.DeptDO;
|
import com.zayac.admin.system.model.entity.DeptDO;
|
||||||
|
import com.zayac.admin.system.model.resp.DeptUsersResp;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
import top.continew.starter.data.mybatis.plus.base.BaseMapper;
|
import top.continew.starter.data.mybatis.plus.base.BaseMapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 部门 Mapper
|
* 部门 Mapper
|
||||||
*
|
*
|
||||||
@ -26,4 +30,11 @@ import top.continew.starter.data.mybatis.plus.base.BaseMapper;
|
|||||||
* @since 2023/1/22 17:56
|
* @since 2023/1/22 17:56
|
||||||
*/
|
*/
|
||||||
public interface DeptMapper extends BaseMapper<DeptDO> {
|
public interface DeptMapper extends BaseMapper<DeptDO> {
|
||||||
|
/**
|
||||||
|
* 查询指定指定角色下的所有所属部门用户
|
||||||
|
*
|
||||||
|
* @param roleCode 角色列表
|
||||||
|
* @return 部门用户列表
|
||||||
|
*/
|
||||||
|
List<DeptUsersResp> selectDeptUsersByRoleCode(@Param("roleCode") String roleCode);
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.zayac.admin.system.mapper;
|
package com.zayac.admin.system.mapper;
|
||||||
|
|
||||||
|
import com.zayac.admin.system.model.entity.RoleDO;
|
||||||
import com.zayac.admin.system.model.entity.RoleDeptDO;
|
import com.zayac.admin.system.model.entity.RoleDeptDO;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.apache.ibatis.annotations.Select;
|
import org.apache.ibatis.annotations.Select;
|
||||||
@ -39,4 +40,6 @@ public interface RoleDeptMapper extends BaseMapper<RoleDeptDO> {
|
|||||||
*/
|
*/
|
||||||
@Select("SELECT dept_id FROM sys_role_dept WHERE role_id = #{roleId}")
|
@Select("SELECT dept_id FROM sys_role_dept WHERE role_id = #{roleId}")
|
||||||
List<Long> selectDeptIdByRoleId(@Param("roleId") Long roleId);
|
List<Long> selectDeptIdByRoleId(@Param("roleId") Long roleId);
|
||||||
|
|
||||||
|
List<RoleDO> selectRolesByDeptIds(List<Long> deptIds);
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,8 @@ import com.zayac.admin.system.model.entity.UserDO;
|
|||||||
import top.continew.starter.data.mybatis.plus.datapermission.DataPermission;
|
import top.continew.starter.data.mybatis.plus.datapermission.DataPermission;
|
||||||
import top.continew.starter.security.crypto.annotation.FieldEncrypt;
|
import top.continew.starter.security.crypto.annotation.FieldEncrypt;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户 Mapper
|
* 用户 Mapper
|
||||||
*
|
*
|
||||||
@ -96,4 +98,13 @@ public interface UserMapper extends DataPermissionMapper<UserDO> {
|
|||||||
* @return 用户数量
|
* @return 用户数量
|
||||||
*/
|
*/
|
||||||
Long selectCountByPhone(@FieldEncrypt @Param("phone") String phone, @Param("id") Long id);
|
Long selectCountByPhone(@FieldEncrypt @Param("phone") String phone, @Param("id") Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据部门id查询直系用户
|
||||||
|
*
|
||||||
|
* @param deptIds 部门id
|
||||||
|
* @return 直系用户列表
|
||||||
|
*/
|
||||||
|
List<UserDO> selectUsersByDeptIds(@Param("deptIds") List<Long> deptIds);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.zayac.admin.system.mapper;
|
package com.zayac.admin.system.mapper;
|
||||||
|
|
||||||
|
import com.zayac.admin.system.model.entity.RoleDO;
|
||||||
import com.zayac.admin.system.model.entity.UserRoleDO;
|
import com.zayac.admin.system.model.entity.UserRoleDO;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.apache.ibatis.annotations.Select;
|
import org.apache.ibatis.annotations.Select;
|
||||||
@ -48,4 +49,6 @@ public interface UserRoleMapper extends BaseMapper<UserRoleDO> {
|
|||||||
*/
|
*/
|
||||||
@Select("SELECT user_id FROM sys_user_role WHERE role_id = #{roleId}")
|
@Select("SELECT user_id FROM sys_user_role WHERE role_id = #{roleId}")
|
||||||
List<Long> selectUserIdByRoleId(@Param("roleId") Long roleId);
|
List<Long> selectUserIdByRoleId(@Param("roleId") Long roleId);
|
||||||
|
|
||||||
|
List<RoleDO> selectRolesByUserIds(List<Long> userIds);
|
||||||
}
|
}
|
||||||
|
@ -78,9 +78,4 @@ public class AccountDO extends BaseDO {
|
|||||||
* 是否为团队账号
|
* 是否为团队账号
|
||||||
*/
|
*/
|
||||||
private Boolean isTeam;
|
private Boolean isTeam;
|
||||||
|
|
||||||
// /**
|
|
||||||
// * 消息通知对象IDs
|
|
||||||
// */
|
|
||||||
// private String receiverIds;
|
|
||||||
}
|
}
|
@ -26,7 +26,6 @@ import top.continew.starter.security.crypto.annotation.FieldEncrypt;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户实体
|
* 用户实体
|
||||||
|
@ -45,7 +45,7 @@ public class UserEmailUpdateRequest implements Serializable {
|
|||||||
@Schema(description = "新邮箱", example = "123456789@qq.com")
|
@Schema(description = "新邮箱", example = "123456789@qq.com")
|
||||||
@NotBlank(message = "新邮箱不能为空")
|
@NotBlank(message = "新邮箱不能为空")
|
||||||
@Pattern(regexp = RegexPool.EMAIL, message = "邮箱格式错误")
|
@Pattern(regexp = RegexPool.EMAIL, message = "邮箱格式错误")
|
||||||
private String newEmail;
|
private String email;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证码
|
* 验证码
|
||||||
@ -60,5 +60,5 @@ public class UserEmailUpdateRequest implements Serializable {
|
|||||||
*/
|
*/
|
||||||
@Schema(description = "当前密码(加密)", example = "SYRLSszQGcMv4kP2Yolou9zf28B9GDakR9u91khxmR7V++i5A384kwnNZxqgvT6bjT4zqpIDuMFLWSt92hQJJA==")
|
@Schema(description = "当前密码(加密)", example = "SYRLSszQGcMv4kP2Yolou9zf28B9GDakR9u91khxmR7V++i5A384kwnNZxqgvT6bjT4zqpIDuMFLWSt92hQJJA==")
|
||||||
@NotBlank(message = "当前密码不能为空")
|
@NotBlank(message = "当前密码不能为空")
|
||||||
private String currentPassword;
|
private String oldPassword;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ public class UserPhoneUpdateReq implements Serializable {
|
|||||||
@Schema(description = "新手机号", example = "13811111111")
|
@Schema(description = "新手机号", example = "13811111111")
|
||||||
@NotBlank(message = "新手机号不能为空")
|
@NotBlank(message = "新手机号不能为空")
|
||||||
@Pattern(regexp = RegexPool.MOBILE, message = "手机号格式错误")
|
@Pattern(regexp = RegexPool.MOBILE, message = "手机号格式错误")
|
||||||
private String newPhone;
|
private String phone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证码
|
* 验证码
|
||||||
@ -60,5 +60,5 @@ public class UserPhoneUpdateReq implements Serializable {
|
|||||||
*/
|
*/
|
||||||
@Schema(description = "当前密码(加密)", example = "SYRLSszQGcMv4kP2Yolou9zf28B9GDakR9u91khxmR7V++i5A384kwnNZxqgvT6bjT4zqpIDuMFLWSt92hQJJA==")
|
@Schema(description = "当前密码(加密)", example = "SYRLSszQGcMv4kP2Yolou9zf28B9GDakR9u91khxmR7V++i5A384kwnNZxqgvT6bjT4zqpIDuMFLWSt92hQJJA==")
|
||||||
@NotBlank(message = "当前密码不能为空")
|
@NotBlank(message = "当前密码不能为空")
|
||||||
private String currentPassword;
|
private String oldPassword;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.zayac.admin.system.model.resp;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class DeptUsersResp implements Serializable {
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private Long deptId;
|
||||||
|
private String deptName;
|
||||||
|
private List<UserWithRolesAndAccountsResp> users;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.zayac.admin.system.model.resp;
|
||||||
|
|
||||||
|
import com.zayac.admin.common.enums.DisEnableStatusEnum;
|
||||||
|
import com.zayac.admin.system.model.entity.RoleDO;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class UserWithRolesAndAccountsResp {
|
||||||
|
private Long userId;
|
||||||
|
private String username;
|
||||||
|
private String nickname;
|
||||||
|
private DisEnableStatusEnum needNotify;
|
||||||
|
private String botToken;
|
||||||
|
private String telegramIds;
|
||||||
|
private String regAndDepIds;
|
||||||
|
private String reportIds;
|
||||||
|
private Long deptId;
|
||||||
|
private String deptName;
|
||||||
|
private List<RoleDO> roles;
|
||||||
|
private List<AccountResp> accounts;
|
||||||
|
}
|
@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package com.zayac.admin.system.service;
|
package com.zayac.admin.system.service;
|
||||||
|
|
||||||
import com.zayac.admin.common.enums.DisEnableStatusEnum;
|
|
||||||
import com.zayac.admin.system.model.entity.UserDO;
|
|
||||||
import com.zayac.admin.system.model.query.AccountQuery;
|
import com.zayac.admin.system.model.query.AccountQuery;
|
||||||
import com.zayac.admin.system.model.req.AccountReq;
|
import com.zayac.admin.system.model.req.AccountReq;
|
||||||
import com.zayac.admin.system.model.resp.AccountDetailResp;
|
import com.zayac.admin.system.model.resp.AccountDetailResp;
|
||||||
@ -33,9 +31,8 @@ import java.util.List;
|
|||||||
* @since 2024/05/10 20:44
|
* @since 2024/05/10 20:44
|
||||||
*/
|
*/
|
||||||
public interface AccountService extends BaseService<AccountResp, AccountDetailResp, AccountQuery, AccountReq> {
|
public interface AccountService extends BaseService<AccountResp, AccountDetailResp, AccountQuery, AccountReq> {
|
||||||
List<AccountResp> getAccountsByUserId(Long id, DisEnableStatusEnum status);
|
|
||||||
|
|
||||||
UserDO getUserByAccountUsername(String username);
|
|
||||||
|
|
||||||
void updateHeaders(String headers, Long id);
|
void updateHeaders(String headers, Long id);
|
||||||
|
|
||||||
|
List<AccountResp> getAccountsByUserIds(List<Long> userIds);
|
||||||
}
|
}
|
@ -20,6 +20,7 @@ import com.zayac.admin.system.model.entity.DeptDO;
|
|||||||
import com.zayac.admin.system.model.query.DeptQuery;
|
import com.zayac.admin.system.model.query.DeptQuery;
|
||||||
import com.zayac.admin.system.model.req.DeptReq;
|
import com.zayac.admin.system.model.req.DeptReq;
|
||||||
import com.zayac.admin.system.model.resp.DeptResp;
|
import com.zayac.admin.system.model.resp.DeptResp;
|
||||||
|
import com.zayac.admin.system.model.resp.DeptUsersResp;
|
||||||
import top.continew.starter.data.mybatis.plus.service.IService;
|
import top.continew.starter.data.mybatis.plus.service.IService;
|
||||||
import top.continew.starter.extension.crud.service.BaseService;
|
import top.continew.starter.extension.crud.service.BaseService;
|
||||||
|
|
||||||
@ -41,5 +42,5 @@ public interface DeptService extends BaseService<DeptResp, DeptResp, DeptQuery,
|
|||||||
*/
|
*/
|
||||||
List<DeptDO> listChildren(Long id);
|
List<DeptDO> listChildren(Long id);
|
||||||
|
|
||||||
List<DeptDO> getByName(String name);
|
List<DeptUsersResp> getDeptWithUsersAndAccounts(String roleCode);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,9 @@
|
|||||||
package com.zayac.admin.system.service;
|
package com.zayac.admin.system.service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import com.zayac.admin.system.enums.OptionCodeEnum;
|
||||||
import com.zayac.admin.system.model.query.OptionQuery;
|
import com.zayac.admin.system.model.query.OptionQuery;
|
||||||
import com.zayac.admin.system.model.req.OptionReq;
|
import com.zayac.admin.system.model.req.OptionReq;
|
||||||
import com.zayac.admin.system.model.req.OptionResetValueReq;
|
import com.zayac.admin.system.model.req.OptionResetValueReq;
|
||||||
@ -52,4 +54,21 @@ public interface OptionService {
|
|||||||
* @param req 重置信息
|
* @param req 重置信息
|
||||||
*/
|
*/
|
||||||
void resetValue(OptionResetValueReq req);
|
void resetValue(OptionResetValueReq req);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据code获取int参数值
|
||||||
|
*
|
||||||
|
* @param code code
|
||||||
|
* @return 参数值
|
||||||
|
*/
|
||||||
|
int getValueByCode2Int(OptionCodeEnum code);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据code获取参数值
|
||||||
|
*
|
||||||
|
* @param code code
|
||||||
|
* @param mapper 类型转换 ex:value -> Integer.parseInt(value)
|
||||||
|
* @return 参数值
|
||||||
|
*/
|
||||||
|
<T> T getValueByCode(OptionCodeEnum code, Function<String, T> mapper);
|
||||||
}
|
}
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.zayac.admin.system.service;
|
package com.zayac.admin.system.service;
|
||||||
|
|
||||||
|
import com.zayac.admin.system.model.entity.RoleDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,4 +58,6 @@ public interface RoleDeptService {
|
|||||||
* @return 部门 ID 列表
|
* @return 部门 ID 列表
|
||||||
*/
|
*/
|
||||||
List<Long> listDeptIdByRoleId(Long roleId);
|
List<Long> listDeptIdByRoleId(Long roleId);
|
||||||
|
|
||||||
|
List<RoleDO> getRolesByDeptIds(List<Long> deptIds);
|
||||||
}
|
}
|
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package com.zayac.admin.system.service;
|
package com.zayac.admin.system.service;
|
||||||
|
|
||||||
|
import com.zayac.admin.system.model.entity.RoleDO;
|
||||||
|
import com.zayac.admin.system.model.entity.UserDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,5 +61,7 @@ public interface UserRoleService {
|
|||||||
*/
|
*/
|
||||||
boolean isRoleIdExists(List<Long> roleIds);
|
boolean isRoleIdExists(List<Long> roleIds);
|
||||||
|
|
||||||
List<Long> listUserIdByRoleId(Long roleId);
|
List<UserDO> getsUserByRoleCode(String roleCode);
|
||||||
|
|
||||||
|
List<RoleDO> getRolesByUserIds(List<Long> collect);
|
||||||
}
|
}
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package com.zayac.admin.system.service;
|
package com.zayac.admin.system.service;
|
||||||
|
|
||||||
import com.zayac.admin.common.enums.DisEnableStatusEnum;
|
|
||||||
import com.zayac.admin.common.model.resp.LabelValueResp;
|
import com.zayac.admin.common.model.resp.LabelValueResp;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import com.zayac.admin.system.model.entity.UserDO;
|
import com.zayac.admin.system.model.entity.UserDO;
|
||||||
@ -30,6 +29,7 @@ import com.zayac.admin.system.model.resp.UserResp;
|
|||||||
import top.continew.starter.extension.crud.service.BaseService;
|
import top.continew.starter.extension.crud.service.BaseService;
|
||||||
import top.continew.starter.data.mybatis.plus.service.IService;
|
import top.continew.starter.data.mybatis.plus.service.IService;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,20 +77,20 @@ public interface UserService extends BaseService<UserResp, UserDetailResp, UserQ
|
|||||||
/**
|
/**
|
||||||
* 修改手机号
|
* 修改手机号
|
||||||
*
|
*
|
||||||
* @param newPhone 新手机号
|
* @param newPhone 新手机号
|
||||||
* @param currentPassword 当前密码
|
* @param oldPassword 当前密码
|
||||||
* @param id ID
|
* @param id ID
|
||||||
*/
|
*/
|
||||||
void updatePhone(String newPhone, String currentPassword, Long id);
|
void updatePhone(String newPhone, String oldPassword, Long id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改邮箱
|
* 修改邮箱
|
||||||
*
|
*
|
||||||
* @param newEmail 新邮箱
|
* @param newEmail 新邮箱
|
||||||
* @param currentPassword 当前密码
|
* @param oldPassword 当前密码
|
||||||
* @param id ID
|
* @param id ID
|
||||||
*/
|
*/
|
||||||
void updateEmail(String newEmail, String currentPassword, Long id);
|
void updateEmail(String newEmail, String oldPassword, Long id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重置密码
|
* 重置密码
|
||||||
@ -140,6 +140,14 @@ public interface UserService extends BaseService<UserResp, UserDetailResp, UserQ
|
|||||||
*/
|
*/
|
||||||
Long countByDeptIds(List<Long> deptIds);
|
Long countByDeptIds(List<Long> deptIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码是否已过期
|
||||||
|
*
|
||||||
|
* @param pwdResetTime 上次重置密码时间
|
||||||
|
* @return 是否过期
|
||||||
|
*/
|
||||||
|
Boolean isPasswordExpired(LocalDateTime pwdResetTime);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建字典
|
* 构建字典
|
||||||
*
|
*
|
||||||
@ -148,16 +156,4 @@ public interface UserService extends BaseService<UserResp, UserDetailResp, UserQ
|
|||||||
*/
|
*/
|
||||||
List<LabelValueResp<Long>> buildDict(List<UserResp> list);
|
List<LabelValueResp<Long>> buildDict(List<UserResp> list);
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询所有的可用用户
|
|
||||||
*
|
|
||||||
* @return 用户列表
|
|
||||||
*/
|
|
||||||
List<UserDO> getAllEnabledUsers();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询所有部门用户
|
|
||||||
*/
|
|
||||||
List<UserDO> getByDeptId(DisEnableStatusEnum status, Long deptId);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,19 +16,13 @@
|
|||||||
|
|
||||||
package com.zayac.admin.system.service.impl;
|
package com.zayac.admin.system.service.impl;
|
||||||
|
|
||||||
import com.alicp.jetcache.anno.CacheType;
|
|
||||||
import com.alicp.jetcache.anno.Cached;
|
|
||||||
import com.zayac.admin.common.constant.CacheConstants;
|
|
||||||
import com.zayac.admin.common.enums.DisEnableStatusEnum;
|
|
||||||
import com.zayac.admin.system.mapper.AccountMapper;
|
import com.zayac.admin.system.mapper.AccountMapper;
|
||||||
import com.zayac.admin.system.model.entity.AccountDO;
|
import com.zayac.admin.system.model.entity.AccountDO;
|
||||||
import com.zayac.admin.system.model.entity.UserDO;
|
|
||||||
import com.zayac.admin.system.model.query.AccountQuery;
|
import com.zayac.admin.system.model.query.AccountQuery;
|
||||||
import com.zayac.admin.system.model.req.AccountReq;
|
import com.zayac.admin.system.model.req.AccountReq;
|
||||||
import com.zayac.admin.system.model.resp.AccountDetailResp;
|
import com.zayac.admin.system.model.resp.AccountDetailResp;
|
||||||
import com.zayac.admin.system.model.resp.AccountResp;
|
import com.zayac.admin.system.model.resp.AccountResp;
|
||||||
import com.zayac.admin.system.service.AccountService;
|
import com.zayac.admin.system.service.AccountService;
|
||||||
import com.zayac.admin.system.service.UserService;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -46,30 +40,14 @@ import java.util.List;
|
|||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class AccountServiceImpl extends BaseServiceImpl<AccountMapper, AccountDO, AccountResp, AccountDetailResp, AccountQuery, AccountReq> implements AccountService {
|
public class AccountServiceImpl extends BaseServiceImpl<AccountMapper, AccountDO, AccountResp, AccountDetailResp, AccountQuery, AccountReq> implements AccountService {
|
||||||
private final UserService userService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Cached(cacheType = CacheType.LOCAL, key = "#userId", name = CacheConstants.ENABLED_ACCOUNTS_KEY_PREFIX, localExpire = 300, expire = 300)
|
|
||||||
public List<AccountResp> getAccountsByUserId(Long id, DisEnableStatusEnum status) {
|
|
||||||
AccountQuery accountQuery = new AccountQuery();
|
|
||||||
accountQuery.setStatus(status.getValue());
|
|
||||||
accountQuery.setUserId(id);
|
|
||||||
return list(accountQuery, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Cached(cacheType = CacheType.LOCAL, key = "#username", name = CacheConstants.ENABLED_ACCOUNTS_KEY_PREFIX, localExpire = 300, expire = 300)
|
|
||||||
public UserDO getUserByAccountUsername(String username) {
|
|
||||||
return baseMapper.lambdaQuery()
|
|
||||||
.eq(AccountDO::getUsername, username)
|
|
||||||
.eq(AccountDO::getStatus, DisEnableStatusEnum.ENABLE)
|
|
||||||
.oneOpt()
|
|
||||||
.map(account -> userService.getById(account.getUserId()))
|
|
||||||
.orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateHeaders(String headers, Long id) {
|
public void updateHeaders(String headers, Long id) {
|
||||||
baseMapper.lambdaUpdate().set(AccountDO::getHeaders, headers).eq(AccountDO::getId, id).update();
|
baseMapper.lambdaUpdate().set(AccountDO::getHeaders, headers).eq(AccountDO::getId, id).update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AccountResp> getAccountsByUserIds(List<Long> userIds) {
|
||||||
|
return baseMapper.selectAccountsByUserIds(userIds);
|
||||||
|
}
|
||||||
}
|
}
|
@ -19,10 +19,12 @@ package com.zayac.admin.system.service.impl;
|
|||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.extra.spring.SpringUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
|
import com.alicp.jetcache.anno.CacheType;
|
||||||
|
import com.alicp.jetcache.anno.Cached;
|
||||||
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
||||||
import com.zayac.admin.system.service.DeptService;
|
import com.zayac.admin.common.constant.CacheConstants;
|
||||||
import com.zayac.admin.system.service.RoleDeptService;
|
import com.zayac.admin.system.model.resp.DeptUsersResp;
|
||||||
import com.zayac.admin.system.service.UserService;
|
import com.zayac.admin.system.service.*;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -37,9 +39,7 @@ import top.continew.starter.data.core.enums.DatabaseType;
|
|||||||
import top.continew.starter.data.core.util.MetaUtils;
|
import top.continew.starter.data.core.util.MetaUtils;
|
||||||
import top.continew.starter.extension.crud.service.impl.BaseServiceImpl;
|
import top.continew.starter.extension.crud.service.impl.BaseServiceImpl;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 部门业务实现
|
* 部门业务实现
|
||||||
@ -54,6 +54,7 @@ public class DeptServiceImpl extends BaseServiceImpl<DeptMapper, DeptDO, DeptRes
|
|||||||
@Resource
|
@Resource
|
||||||
private UserService userService;
|
private UserService userService;
|
||||||
private final RoleDeptService roleDeptService;
|
private final RoleDeptService roleDeptService;
|
||||||
|
private final DeptMapper baseMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<DeptDO> listChildren(Long id) {
|
public List<DeptDO> listChildren(Long id) {
|
||||||
@ -62,11 +63,6 @@ public class DeptServiceImpl extends BaseServiceImpl<DeptMapper, DeptDO, DeptRes
|
|||||||
return baseMapper.lambdaQuery().apply(databaseType.findInSet(id, "ancestors")).list();
|
return baseMapper.lambdaQuery().apply(databaseType.findInSet(id, "ancestors")).list();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<DeptDO> getByName(String name) {
|
|
||||||
return baseMapper.lambdaQuery().eq(DeptDO::getName, name).list();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void beforeAdd(DeptReq req) {
|
protected void beforeAdd(DeptReq req) {
|
||||||
String name = req.getName();
|
String name = req.getName();
|
||||||
@ -202,4 +198,10 @@ public class DeptServiceImpl extends BaseServiceImpl<DeptMapper, DeptDO, DeptRes
|
|||||||
}
|
}
|
||||||
baseMapper.updateBatchById(list);
|
baseMapper.updateBatchById(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cached(key = "#roleCode", cacheType = CacheType.LOCAL, name = CacheConstants.DEPT_USERS_ROLES_ACCOUNTS_KEY_PREFIX, localExpire = 360)
|
||||||
|
public List<DeptUsersResp> getDeptWithUsersAndAccounts(String roleCode) {
|
||||||
|
return baseMapper.selectDeptUsersByRoleCode(roleCode);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,11 @@
|
|||||||
package com.zayac.admin.system.service.impl;
|
package com.zayac.admin.system.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
|
import com.zayac.admin.system.enums.OptionCodeEnum;
|
||||||
import com.zayac.admin.system.service.OptionService;
|
import com.zayac.admin.system.service.OptionService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -29,9 +34,11 @@ import com.zayac.admin.system.model.req.OptionResetValueReq;
|
|||||||
import com.zayac.admin.system.model.resp.OptionResp;
|
import com.zayac.admin.system.model.resp.OptionResp;
|
||||||
import top.continew.starter.cache.redisson.util.RedisUtils;
|
import top.continew.starter.cache.redisson.util.RedisUtils;
|
||||||
import top.continew.starter.core.constant.StringConstants;
|
import top.continew.starter.core.constant.StringConstants;
|
||||||
|
import top.continew.starter.core.util.validate.CheckUtils;
|
||||||
import top.continew.starter.data.mybatis.plus.query.QueryWrapperHelper;
|
import top.continew.starter.data.mybatis.plus.query.QueryWrapperHelper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 参数业务实现
|
* 参数业务实现
|
||||||
@ -61,4 +68,27 @@ public class OptionServiceImpl implements OptionService {
|
|||||||
RedisUtils.deleteByPattern(CacheConstants.OPTION_KEY_PREFIX + StringConstants.ASTERISK);
|
RedisUtils.deleteByPattern(CacheConstants.OPTION_KEY_PREFIX + StringConstants.ASTERISK);
|
||||||
baseMapper.lambdaUpdate().set(OptionDO::getValue, null).in(OptionDO::getCode, req.getCode()).update();
|
baseMapper.lambdaUpdate().set(OptionDO::getValue, null).in(OptionDO::getCode, req.getCode()).update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getValueByCode2Int(OptionCodeEnum code) {
|
||||||
|
return this.getValueByCode(code, Integer::parseInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T getValueByCode(OptionCodeEnum code, Function<String, T> mapper) {
|
||||||
|
String value = RedisUtils.get(CacheConstants.OPTION_KEY_PREFIX + code.getValue());
|
||||||
|
if (StrUtil.isNotBlank(value)) {
|
||||||
|
return mapper.apply(value);
|
||||||
|
}
|
||||||
|
LambdaQueryWrapper<OptionDO> queryWrapper = Wrappers.<OptionDO>lambdaQuery()
|
||||||
|
.eq(OptionDO::getCode, code.getValue())
|
||||||
|
.select(OptionDO::getValue, OptionDO::getDefaultValue);
|
||||||
|
OptionDO optionDO = baseMapper.selectOne(queryWrapper);
|
||||||
|
CheckUtils.throwIf(ObjUtil.isEmpty(optionDO), "配置 [{}] 不存在", code);
|
||||||
|
value = StrUtil.nullToDefault(optionDO.getValue(), optionDO.getDefaultValue());
|
||||||
|
CheckUtils.throwIf(StrUtil.isBlank(value), "配置 [{}] 不存在", code);
|
||||||
|
RedisUtils.set(CacheConstants.OPTION_KEY_PREFIX + code.getValue(), value);
|
||||||
|
return mapper.apply(value);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -19,6 +19,7 @@ package com.zayac.admin.system.service.impl;
|
|||||||
import cn.crane4j.annotation.ContainerMethod;
|
import cn.crane4j.annotation.ContainerMethod;
|
||||||
import cn.crane4j.annotation.MappingType;
|
import cn.crane4j.annotation.MappingType;
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import com.zayac.admin.system.model.entity.RoleDO;
|
||||||
import com.zayac.admin.system.service.RoleDeptService;
|
import com.zayac.admin.system.service.RoleDeptService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -74,6 +75,11 @@ public class RoleDeptServiceImpl implements RoleDeptService {
|
|||||||
baseMapper.lambdaUpdate().in(RoleDeptDO::getDeptId, deptIds).remove();
|
baseMapper.lambdaUpdate().in(RoleDeptDO::getDeptId, deptIds).remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<RoleDO> getRolesByDeptIds(List<Long> deptIds) {
|
||||||
|
return baseMapper.selectRolesByDeptIds(deptIds);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ContainerMethod(namespace = ContainerConstants.ROLE_DEPT_ID_LIST, type = MappingType.ORDER_OF_KEYS)
|
@ContainerMethod(namespace = ContainerConstants.ROLE_DEPT_ID_LIST, type = MappingType.ORDER_OF_KEYS)
|
||||||
public List<Long> listDeptIdByRoleId(Long roleId) {
|
public List<Long> listDeptIdByRoleId(Long roleId) {
|
||||||
|
@ -19,6 +19,8 @@ package com.zayac.admin.system.service.impl;
|
|||||||
import cn.crane4j.annotation.ContainerMethod;
|
import cn.crane4j.annotation.ContainerMethod;
|
||||||
import cn.crane4j.annotation.MappingType;
|
import cn.crane4j.annotation.MappingType;
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import com.zayac.admin.system.model.entity.RoleDO;
|
||||||
|
import com.zayac.admin.system.model.entity.UserDO;
|
||||||
import com.zayac.admin.system.service.UserRoleService;
|
import com.zayac.admin.system.service.UserRoleService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -74,14 +76,18 @@ public class UserRoleServiceImpl implements UserRoleService {
|
|||||||
return baseMapper.selectRoleIdByUserId(userId);
|
return baseMapper.selectRoleIdByUserId(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@ContainerMethod(namespace = ContainerConstants.ROLE_USER_ID_LIST, type = MappingType.ORDER_OF_KEYS)
|
|
||||||
public List<Long> listUserIdByRoleId(Long roleId) {
|
|
||||||
return baseMapper.selectUserIdByRoleId(roleId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isRoleIdExists(List<Long> roleIds) {
|
public boolean isRoleIdExists(List<Long> roleIds) {
|
||||||
return baseMapper.lambdaQuery().in(UserRoleDO::getRoleId, roleIds).exists();
|
return baseMapper.lambdaQuery().in(UserRoleDO::getRoleId, roleIds).exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<UserDO> getsUserByRoleCode(String roleCode) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<RoleDO> getRolesByUserIds(List<Long> userIds) {
|
||||||
|
return baseMapper.selectRolesByUserIds(userIds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,10 @@ package com.zayac.admin.system.service.impl;
|
|||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.hutool.core.io.file.FileNameUtil;
|
import cn.hutool.core.io.file.FileNameUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.core.util.ReUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.alicp.jetcache.anno.CacheInvalidate;
|
import com.alicp.jetcache.anno.CacheInvalidate;
|
||||||
import com.alicp.jetcache.anno.CacheType;
|
import com.alicp.jetcache.anno.CacheType;
|
||||||
@ -27,6 +29,7 @@ import com.alicp.jetcache.anno.CacheUpdate;
|
|||||||
import com.alicp.jetcache.anno.Cached;
|
import com.alicp.jetcache.anno.Cached;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.zayac.admin.common.constant.RegexConstants;
|
||||||
import com.zayac.admin.common.model.resp.LabelValueResp;
|
import com.zayac.admin.common.model.resp.LabelValueResp;
|
||||||
import com.zayac.admin.system.mapper.UserMapper;
|
import com.zayac.admin.system.mapper.UserMapper;
|
||||||
import com.zayac.admin.system.service.*;
|
import com.zayac.admin.system.service.*;
|
||||||
@ -52,9 +55,9 @@ import com.zayac.admin.system.model.req.UserReq;
|
|||||||
import com.zayac.admin.system.model.req.UserRoleUpdateReq;
|
import com.zayac.admin.system.model.req.UserRoleUpdateReq;
|
||||||
import com.zayac.admin.system.model.resp.UserDetailResp;
|
import com.zayac.admin.system.model.resp.UserDetailResp;
|
||||||
import com.zayac.admin.system.model.resp.UserResp;
|
import com.zayac.admin.system.model.resp.UserResp;
|
||||||
import com.zayac.admin.system.service.*;
|
|
||||||
import top.continew.starter.core.constant.StringConstants;
|
import top.continew.starter.core.constant.StringConstants;
|
||||||
import top.continew.starter.core.util.validate.CheckUtils;
|
import top.continew.starter.core.util.validate.CheckUtils;
|
||||||
|
import top.continew.starter.core.util.validate.ValidationUtils;
|
||||||
import top.continew.starter.extension.crud.model.query.PageQuery;
|
import top.continew.starter.extension.crud.model.query.PageQuery;
|
||||||
import top.continew.starter.extension.crud.model.resp.PageResp;
|
import top.continew.starter.extension.crud.model.resp.PageResp;
|
||||||
import top.continew.starter.extension.crud.service.CommonUserService;
|
import top.continew.starter.extension.crud.service.CommonUserService;
|
||||||
@ -64,6 +67,8 @@ import java.time.LocalDateTime;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static com.zayac.admin.system.enums.OptionCodeEnum.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户业务实现
|
* 用户业务实现
|
||||||
*
|
*
|
||||||
@ -80,6 +85,7 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
|||||||
private final FileService fileService;
|
private final FileService fileService;
|
||||||
private final FileStorageService fileStorageService;
|
private final FileStorageService fileStorageService;
|
||||||
private final PasswordEncoder passwordEncoder;
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
private final OptionService optionService;
|
||||||
@Resource
|
@Resource
|
||||||
private DeptService deptService;
|
private DeptService deptService;
|
||||||
@Value("${avatar.support-suffix}")
|
@Value("${avatar.support-suffix}")
|
||||||
@ -192,16 +198,74 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
|||||||
if (StrUtil.isNotBlank(password)) {
|
if (StrUtil.isNotBlank(password)) {
|
||||||
CheckUtils.throwIf(!passwordEncoder.matches(oldPassword, password), "当前密码错误");
|
CheckUtils.throwIf(!passwordEncoder.matches(oldPassword, password), "当前密码错误");
|
||||||
}
|
}
|
||||||
|
// 校验密码合法性
|
||||||
|
checkPassword(newPassword, user);
|
||||||
// 更新密码和密码重置时间
|
// 更新密码和密码重置时间
|
||||||
user.setPassword(newPassword);
|
user.setPassword(newPassword);
|
||||||
user.setPwdResetTime(LocalDateTime.now());
|
user.setPwdResetTime(LocalDateTime.now());
|
||||||
baseMapper.updateById(user);
|
baseMapper.updateById(user);
|
||||||
|
onlineUserService.cleanByUserId(user.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测修改密码合法性
|
||||||
|
*
|
||||||
|
* @param password 密码
|
||||||
|
* @param user 用户
|
||||||
|
*/
|
||||||
|
private void checkPassword(String password, UserDO user) {
|
||||||
|
// 密码最小长度
|
||||||
|
int passwordMinLength = optionService.getValueByCode2Int(PASSWORD_MIN_LENGTH);
|
||||||
|
ValidationUtils.throwIf(StrUtil.length(password) < passwordMinLength, PASSWORD_MIN_LENGTH
|
||||||
|
.getDescription() + "为 {}", passwordMinLength);
|
||||||
|
// 密码是否允许包含正反序用户名
|
||||||
|
int passwordContainName = optionService.getValueByCode2Int(PASSWORD_CONTAIN_NAME);
|
||||||
|
if (passwordContainName == 1) {
|
||||||
|
String username = user.getUsername();
|
||||||
|
ValidationUtils.throwIf(StrUtil.containsIgnoreCase(password, username) || StrUtil
|
||||||
|
.containsIgnoreCase(password, StrUtil.reverse(username)), PASSWORD_CONTAIN_NAME.getDescription());
|
||||||
|
}
|
||||||
|
// 密码是否必须包含特殊字符
|
||||||
|
int passwordSpecialChar = optionService.getValueByCode2Int(PASSWORD_SPECIAL_CHAR);
|
||||||
|
String match = RegexConstants.PASSWORD;
|
||||||
|
String desc = "密码长度为 6 到 32 位,可以包含字母、数字、下划线,特殊字符,同时包含字母和数字";
|
||||||
|
if (passwordSpecialChar == 1) {
|
||||||
|
match = RegexConstants.PASSWORD_STRICT;
|
||||||
|
desc = "密码长度为 8 到 32 位,包含至少1个大写字母、1个小写字母、1个数字,1个特殊字符";
|
||||||
|
}
|
||||||
|
ValidationUtils.throwIf(!ReUtil.isMatch(match, password), desc);
|
||||||
|
// 密码修改间隔
|
||||||
|
if (ObjectUtil.isNull(user.getPwdResetTime())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int passwordUpdateInterval = optionService.getValueByCode2Int(PASSWORD_UPDATE_INTERVAL);
|
||||||
|
if (passwordUpdateInterval <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LocalDateTime lastResetTime = user.getPwdResetTime();
|
||||||
|
LocalDateTime limitUpdateTime = lastResetTime.plusMinutes(passwordUpdateInterval);
|
||||||
|
ValidationUtils.throwIf(LocalDateTime.now().isBefore(limitUpdateTime), "上次修改于:{},下次可修改时间:{}", LocalDateTimeUtil
|
||||||
|
.formatNormal(lastResetTime), LocalDateTimeUtil.formatNormal(limitUpdateTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updatePhone(String newPhone, String currentPassword, Long id) {
|
public Boolean isPasswordExpired(LocalDateTime pwdResetTime) {
|
||||||
|
// 永久有效
|
||||||
|
int passwordExpirationDays = optionService.getValueByCode2Int(PASSWORD_EXPIRATION_DAYS);
|
||||||
|
if (passwordExpirationDays <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 初始密码也提示修改
|
||||||
|
if (pwdResetTime == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return pwdResetTime.plusDays(passwordExpirationDays).isBefore(LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updatePhone(String newPhone, String oldPassword, Long id) {
|
||||||
UserDO user = super.getById(id);
|
UserDO user = super.getById(id);
|
||||||
CheckUtils.throwIf(!passwordEncoder.matches(currentPassword, user.getPassword()), "当前密码错误");
|
CheckUtils.throwIf(!passwordEncoder.matches(oldPassword, user.getPassword()), "当前密码错误");
|
||||||
CheckUtils.throwIf(this.isPhoneExists(newPhone, id), "手机号已绑定其他账号,请更换其他手机号");
|
CheckUtils.throwIf(this.isPhoneExists(newPhone, id), "手机号已绑定其他账号,请更换其他手机号");
|
||||||
CheckUtils.throwIfEqual(newPhone, user.getPhone(), "新手机号不能与当前手机号相同");
|
CheckUtils.throwIfEqual(newPhone, user.getPhone(), "新手机号不能与当前手机号相同");
|
||||||
// 更新手机号
|
// 更新手机号
|
||||||
@ -209,9 +273,9 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateEmail(String newEmail, String currentPassword, Long id) {
|
public void updateEmail(String newEmail, String oldPassword, Long id) {
|
||||||
UserDO user = super.getById(id);
|
UserDO user = super.getById(id);
|
||||||
CheckUtils.throwIf(!passwordEncoder.matches(currentPassword, user.getPassword()), "当前密码错误");
|
CheckUtils.throwIf(!passwordEncoder.matches(oldPassword, user.getPassword()), "当前密码错误");
|
||||||
CheckUtils.throwIf(this.isEmailExists(newEmail, id), "邮箱已绑定其他账号,请更换其他邮箱");
|
CheckUtils.throwIf(this.isEmailExists(newEmail, id), "邮箱已绑定其他账号,请更换其他邮箱");
|
||||||
CheckUtils.throwIfEqual(newEmail, user.getEmail(), "新邮箱不能与当前邮箱相同");
|
CheckUtils.throwIfEqual(newEmail, user.getEmail(), "新邮箱不能与当前邮箱相同");
|
||||||
// 更新邮箱
|
// 更新邮箱
|
||||||
@ -254,19 +318,6 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
|||||||
return baseMapper.lambdaQuery().in(UserDO::getDeptId, deptIds).count();
|
return baseMapper.lambdaQuery().in(UserDO::getDeptId, deptIds).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<LabelValueResp<Long>> buildDict(List<UserResp> list) {
|
|
||||||
if (CollUtil.isEmpty(list)) {
|
|
||||||
return new ArrayList<>(0);
|
|
||||||
}
|
|
||||||
return list.stream().map(r -> new LabelValueResp<>(r.getUsername(), r.getId())).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserDO> getAllEnabledUsers() {
|
|
||||||
return baseMapper.lambdaQuery().eq(UserDO::getStatus, DisEnableStatusEnum.ENABLE.getValue()).list();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Cached(key = "#id", cacheType = CacheType.BOTH, name = CacheConstants.USER_KEY_PREFIX, syncLocal = true)
|
@Cached(key = "#id", cacheType = CacheType.BOTH, name = CacheConstants.USER_KEY_PREFIX, syncLocal = true)
|
||||||
public String getNicknameById(Long id) {
|
public String getNicknameById(Long id) {
|
||||||
@ -303,20 +354,6 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
|||||||
userRoleService.add(req.getRoleIds(), userId);
|
userRoleService.add(req.getRoleIds(), userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserDO> getByDeptId(DisEnableStatusEnum status, Long deptId) {
|
|
||||||
QueryWrapper<UserDO> wrapper = new QueryWrapper<UserDO>().eq(null != status, "status", status.getValue())
|
|
||||||
.and(q -> {
|
|
||||||
List<Long> deptIdList = deptService.listChildren(deptId)
|
|
||||||
.stream()
|
|
||||||
.map(DeptDO::getId)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
deptIdList.add(deptId);
|
|
||||||
q.in("dept_id", deptIdList);
|
|
||||||
});
|
|
||||||
return baseMapper.selectList(wrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建 QueryWrapper
|
* 构建 QueryWrapper
|
||||||
*
|
*
|
||||||
@ -380,4 +417,12 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
|||||||
Long count = baseMapper.selectCountByPhone(phone, id);
|
Long count = baseMapper.selectCountByPhone(phone, id);
|
||||||
return null != count && count > 0;
|
return null != count && count > 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public List<LabelValueResp<Long>> buildDict(List<UserResp> list) {
|
||||||
|
if (CollUtil.isEmpty(list)) {
|
||||||
|
return new ArrayList<>(0);
|
||||||
|
}
|
||||||
|
return list.stream().map(r -> new LabelValueResp<>(r.getUsername(), r.getId())).toList();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
|
|
||||||
|
|
||||||
|
<mapper namespace="com.zayac.admin.system.mapper.AccountMapper">
|
||||||
|
<select id="selectAccountsByUserIds" resultType="com.zayac.admin.system.model.resp.AccountResp">
|
||||||
|
SELECT
|
||||||
|
id, username, nickname, status, platform_id, is_team, user_id
|
||||||
|
FROM sys_account
|
||||||
|
WHERE user_id IN
|
||||||
|
<foreach item="userIds" collection="list" open="(" separator="," close=")">
|
||||||
|
#{userIds}
|
||||||
|
</foreach>;
|
||||||
|
</select>
|
||||||
|
</mapper>
|
@ -1,4 +1,88 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
|
|
||||||
<mapper namespace="com.zayac.admin.system.mapper.DeptMapper">
|
<mapper namespace="com.zayac.admin.system.mapper.DeptMapper">
|
||||||
</mapper>
|
<select id="selectDeptUsersByRoleCode" resultMap="DeptUserResultMap">
|
||||||
|
WITH RECURSIVE dept_hierarchy AS (SELECT d.id,
|
||||||
|
d.parent_id,
|
||||||
|
d.name,
|
||||||
|
d.id AS top_level_dept_id,
|
||||||
|
d.name AS top_level_dept_name
|
||||||
|
FROM sys_dept d
|
||||||
|
JOIN sys_user u ON u.dept_id = d.id
|
||||||
|
JOIN sys_user_role ur ON ur.user_id = u.id
|
||||||
|
JOIN sys_role r ON ur.role_id = r.id
|
||||||
|
WHERE d.status = 1
|
||||||
|
AND r.code = #{roleCode}
|
||||||
|
UNION ALL
|
||||||
|
SELECT d.id, d.parent_id, d.name, dh.top_level_dept_id, dh.top_level_dept_name
|
||||||
|
FROM sys_dept d
|
||||||
|
INNER JOIN dept_hierarchy dh ON d.parent_id = dh.id)
|
||||||
|
SELECT u.id AS user_id,
|
||||||
|
u.username,
|
||||||
|
u.nickname,
|
||||||
|
u.need_notify,
|
||||||
|
u.bot_token,
|
||||||
|
u.telegram_ids,
|
||||||
|
u.reg_and_dep_ids,
|
||||||
|
u.report_ids,
|
||||||
|
r.id AS role_id,
|
||||||
|
r.code AS role_code,
|
||||||
|
r.name AS role_name,
|
||||||
|
a.id AS account_id,
|
||||||
|
a.nickname AS account_nickname,
|
||||||
|
a.username AS account_username,
|
||||||
|
a.status AS account_status,
|
||||||
|
a.headers AS account_headers,
|
||||||
|
a.platform_id AS account_platform_id,
|
||||||
|
p.name AS platform_name,
|
||||||
|
p.url AS platform_url,
|
||||||
|
d.id AS dept_id,
|
||||||
|
d.name AS dept_name,
|
||||||
|
dh.top_level_dept_id,
|
||||||
|
dh.top_level_dept_name
|
||||||
|
FROM sys_user u
|
||||||
|
LEFT JOIN sys_user_role ur ON u.id = ur.user_id
|
||||||
|
LEFT JOIN sys_role r ON ur.role_id = r.id
|
||||||
|
LEFT JOIN sys_account a ON u.id = a.user_id AND a.status = 1
|
||||||
|
LEFT JOIN sys_platform p ON a.platform_id = p.id
|
||||||
|
LEFT JOIN sys_dept d ON u.dept_id = d.id
|
||||||
|
LEFT JOIN dept_hierarchy dh ON d.id = dh.id
|
||||||
|
WHERE u.status = 1
|
||||||
|
AND d.id IN (SELECT id FROM dept_hierarchy)
|
||||||
|
ORDER BY dh.top_level_dept_id, u.id, r.id, a.id;
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<resultMap id="DeptUserResultMap" type="com.zayac.admin.system.model.resp.DeptUsersResp">
|
||||||
|
<id column="top_level_dept_id" property="deptId"/>
|
||||||
|
<result column="top_level_dept_name" property="deptName"/>
|
||||||
|
<collection property="users" ofType="com.zayac.admin.system.model.resp.UserWithRolesAndAccountsResp"
|
||||||
|
javaType="java.util.List">
|
||||||
|
<id column="user_id" property="userId"/>
|
||||||
|
<result column="username" property="username"/>
|
||||||
|
<result column="nickname" property="nickname"/>
|
||||||
|
<result column="need_notify" property="needNotify"/>
|
||||||
|
<result column="bot_token" property="botToken"/>
|
||||||
|
<result column="telegram_ids" property="telegramIds"/>
|
||||||
|
<result column="reg_and_dep_ids" property="regAndDepIds"/>
|
||||||
|
<result column="report_ids" property="reportIds"/>
|
||||||
|
<result column="dept_id" property="deptId"/>
|
||||||
|
<result column="dept_name" property="deptName"/>
|
||||||
|
<collection property="roles" ofType="com.zayac.admin.system.model.entity.RoleDO">
|
||||||
|
<id column="role_id" property="id"/>
|
||||||
|
<id column="role_code" property="code"/>
|
||||||
|
<result column="role_name" property="name"/>
|
||||||
|
</collection>
|
||||||
|
<collection property="accounts" ofType="com.zayac.admin.system.model.resp.AccountResp">
|
||||||
|
<id column="account_id" property="id"/>
|
||||||
|
<result column="account_nickname" property="nickname"/>
|
||||||
|
<result column="account_username" property="username"/>
|
||||||
|
<result column="account_status" property="status"/>
|
||||||
|
<result column="account_headers" property="headers"/>
|
||||||
|
<result column="account_platform_id" property="platformId"/>
|
||||||
|
<result column="platform_name" property="platformName"/>
|
||||||
|
<result column="platform_url" property="platformUrl"/>
|
||||||
|
</collection>
|
||||||
|
</collection>
|
||||||
|
</resultMap>
|
||||||
|
</mapper>
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
|
|
||||||
|
|
||||||
|
<mapper namespace="com.zayac.admin.system.mapper.RoleDeptMapper">
|
||||||
|
<select id="selectRolesByDeptIds" resultType="com.zayac.admin.system.model.entity.RoleDO">
|
||||||
|
SELECT
|
||||||
|
rd.dept_id AS deptId,
|
||||||
|
r.id,
|
||||||
|
r.name,
|
||||||
|
r.code
|
||||||
|
FROM sys_role_dept rd
|
||||||
|
JOIN sys_role r ON rd.role_id = r.id
|
||||||
|
WHERE rd.dept_id IN
|
||||||
|
<foreach item="deptId" collection="deptIds" open="(" separator="," close=")">
|
||||||
|
#{deptId}
|
||||||
|
</foreach>;
|
||||||
|
</select>
|
||||||
|
</mapper>
|
@ -1,4 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
<mapper namespace="com.zayac.admin.system.mapper.RoleMapper">
|
<mapper namespace="com.zayac.admin.system.mapper.RoleMapper">
|
||||||
|
<select id="selectRolesByUserIds" resultType="com.zayac.admin.system.model.entity.RoleDO">
|
||||||
|
SELECT
|
||||||
|
r.id, r.name, r.code, ur.user_id AS userId
|
||||||
|
FROM sys_role r
|
||||||
|
JOIN sys_user_role ur ON r.id = ur.role_id
|
||||||
|
WHERE ur.user_id IN
|
||||||
|
<foreach item="userId" collection="userIds" open="(" separator="," close=")">
|
||||||
|
#{userId}
|
||||||
|
</foreach>;
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
@ -5,17 +5,17 @@
|
|||||||
<select id="selectUserPage" resultType="com.zayac.admin.system.model.entity.UserDO">
|
<select id="selectUserPage" resultType="com.zayac.admin.system.model.entity.UserDO">
|
||||||
SELECT t1.*
|
SELECT t1.*
|
||||||
FROM sys_user AS t1
|
FROM sys_user AS t1
|
||||||
LEFT JOIN sys_dept AS t2 ON t2.id = t1.dept_id
|
LEFT JOIN sys_dept AS t2 ON t2.id = t1.dept_id
|
||||||
${ew.customSqlSegment}
|
${ew.customSqlSegment}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectCountByEmail" resultType="java.lang.Long">
|
<select id="selectCountByEmail" resultType="java.lang.Long">
|
||||||
SELECT count(*)
|
SELECT count(*)
|
||||||
FROM sys_user
|
FROM sys_user
|
||||||
WHERE email = #{email}
|
WHERE email = #{email}
|
||||||
<if test="id != null">
|
<if test="id != null">
|
||||||
AND id != #{id}
|
AND id != #{id}
|
||||||
</if>
|
</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectCountByPhone" resultType="java.lang.Long">
|
<select id="selectCountByPhone" resultType="java.lang.Long">
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
|
|
||||||
|
|
||||||
|
<mapper namespace="com.zayac.admin.system.mapper.UserRoleMapper">
|
||||||
|
<select id="selectRolesByUserIds" resultType="com.zayac.admin.system.model.entity.RoleDO">
|
||||||
|
SELECT
|
||||||
|
r.id, r.name, r.code, ur.user_id AS userId
|
||||||
|
FROM sys_role r
|
||||||
|
JOIN sys_user_role ur ON r.id = ur.role_id
|
||||||
|
WHERE ur.user_id IN
|
||||||
|
<foreach item="userId" collection="userIds" open="(" separator="," close=")">
|
||||||
|
#{userId}
|
||||||
|
</foreach>;
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
@ -15,7 +15,7 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<!-- ### 打包配置相关 ### -->
|
<!-- ### 打包配置相关 ### -->
|
||||||
<!-- 启动类 -->
|
<!-- 启动类 -->
|
||||||
<main-class>zayac.admin.ContiNewAdminApplication</main-class>
|
<main-class>com.zayac.admin.ZayacAdminApplication</main-class>
|
||||||
<!-- 程序 jar 输出目录 -->
|
<!-- 程序 jar 输出目录 -->
|
||||||
<bin-path>bin</bin-path>
|
<bin-path>bin</bin-path>
|
||||||
<!-- 配置文件输出目录 -->
|
<!-- 配置文件输出目录 -->
|
||||||
|
@ -127,6 +127,7 @@ public class AuthController {
|
|||||||
UserInfoResp userInfoResp = BeanUtil.copyProperties(userDetailResp, UserInfoResp.class);
|
UserInfoResp userInfoResp = BeanUtil.copyProperties(userDetailResp, UserInfoResp.class);
|
||||||
userInfoResp.setPermissions(loginUser.getPermissions());
|
userInfoResp.setPermissions(loginUser.getPermissions());
|
||||||
userInfoResp.setRoles(loginUser.getRoleCodes());
|
userInfoResp.setRoles(loginUser.getRoleCodes());
|
||||||
|
userInfoResp.setPwdExpired(userService.isPasswordExpired(userDetailResp.getPwdResetTime()));
|
||||||
return R.ok(userInfoResp);
|
return R.ok(userInfoResp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,30 +104,30 @@ public class UserCenterController {
|
|||||||
@Operation(summary = "修改手机号", description = "修改手机号")
|
@Operation(summary = "修改手机号", description = "修改手机号")
|
||||||
@PatchMapping("/phone")
|
@PatchMapping("/phone")
|
||||||
public R<Void> updatePhone(@Validated @RequestBody UserPhoneUpdateReq updateReq) {
|
public R<Void> updatePhone(@Validated @RequestBody UserPhoneUpdateReq updateReq) {
|
||||||
String rawCurrentPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq
|
String rawOldPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq
|
||||||
.getCurrentPassword()));
|
.getOldPassword()));
|
||||||
ValidationUtils.throwIfBlank(rawCurrentPassword, DECRYPT_FAILED);
|
ValidationUtils.throwIfBlank(rawOldPassword, DECRYPT_FAILED);
|
||||||
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + updateReq.getNewPhone();
|
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + updateReq.getPhone();
|
||||||
String captcha = RedisUtils.get(captchaKey);
|
String captcha = RedisUtils.get(captchaKey);
|
||||||
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
|
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
|
||||||
ValidationUtils.throwIfNotEqualIgnoreCase(updateReq.getCaptcha(), captcha, "验证码错误");
|
ValidationUtils.throwIfNotEqualIgnoreCase(updateReq.getCaptcha(), captcha, "验证码错误");
|
||||||
RedisUtils.delete(captchaKey);
|
RedisUtils.delete(captchaKey);
|
||||||
userService.updatePhone(updateReq.getNewPhone(), rawCurrentPassword, LoginHelper.getUserId());
|
userService.updatePhone(updateReq.getPhone(), rawOldPassword, LoginHelper.getUserId());
|
||||||
return R.ok("修改成功");
|
return R.ok("修改成功");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "修改邮箱", description = "修改用户邮箱")
|
@Operation(summary = "修改邮箱", description = "修改用户邮箱")
|
||||||
@PatchMapping("/email")
|
@PatchMapping("/email")
|
||||||
public R<Void> updateEmail(@Validated @RequestBody UserEmailUpdateRequest updateReq) {
|
public R<Void> updateEmail(@Validated @RequestBody UserEmailUpdateRequest updateReq) {
|
||||||
String rawCurrentPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq
|
String rawOldPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq
|
||||||
.getCurrentPassword()));
|
.getOldPassword()));
|
||||||
ValidationUtils.throwIfBlank(rawCurrentPassword, DECRYPT_FAILED);
|
ValidationUtils.throwIfBlank(rawOldPassword, DECRYPT_FAILED);
|
||||||
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + updateReq.getNewEmail();
|
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + updateReq.getEmail();
|
||||||
String captcha = RedisUtils.get(captchaKey);
|
String captcha = RedisUtils.get(captchaKey);
|
||||||
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
|
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
|
||||||
ValidationUtils.throwIfNotEqualIgnoreCase(updateReq.getCaptcha(), captcha, "验证码错误");
|
ValidationUtils.throwIfNotEqualIgnoreCase(updateReq.getCaptcha(), captcha, "验证码错误");
|
||||||
RedisUtils.delete(captchaKey);
|
RedisUtils.delete(captchaKey);
|
||||||
userService.updateEmail(updateReq.getNewEmail(), rawCurrentPassword, LoginHelper.getUserId());
|
userService.updateEmail(updateReq.getEmail(), rawOldPassword, LoginHelper.getUserId());
|
||||||
return R.ok("修改成功");
|
return R.ok("修改成功");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
--- ### 项目配置
|
--- ### 项目配置
|
||||||
project:
|
project:
|
||||||
# URL
|
# URL(跨域配置默认放行此 URL,第三方登录回调默认使用此 URL 为前缀,请注意更改为你实际的前端 URL)
|
||||||
url: http://localhost:5173
|
url: http://localhost:5173
|
||||||
|
|
||||||
--- ### 服务器配置
|
--- ### 服务器配置
|
||||||
@ -58,7 +58,7 @@ spring.datasource:
|
|||||||
## Liquibase 配置
|
## Liquibase 配置
|
||||||
spring.liquibase:
|
spring.liquibase:
|
||||||
# 是否启用
|
# 是否启用
|
||||||
enabled: true
|
enabled: false
|
||||||
# 配置文件路径
|
# 配置文件路径
|
||||||
change-log: classpath:/db/changelog/db.changelog-master.yaml
|
change-log: classpath:/db/changelog/db.changelog-master.yaml
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
--- ### 项目配置
|
--- ### 项目配置
|
||||||
project:
|
project:
|
||||||
# URL(跨域配置默认放行此 URL,请注意更改为你实际的前端 URL)
|
# URL(跨域配置默认放行此 URL,第三方登录回调默认使用此 URL 为前缀,请注意更改为你实际的前端 URL)
|
||||||
url: http://localhost:5173
|
url: http://localhost:5173
|
||||||
# 是否为生产环境
|
# 是否为生产环境
|
||||||
production: true
|
production: true
|
||||||
|
@ -114,7 +114,14 @@ VALUES
|
|||||||
'Copyright © 2022-present <a href="https://blog.charles7c.top/about/me" target="_blank" rel="noopener">Charles7c</a> <span>⋅</span> <a href="https://github.com/Charles7c/continew-admin" target="_blank" rel="noopener">ContiNew Admin</a> <span>⋅</span> <a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">津ICP备2022005864号-2</a>',
|
'Copyright © 2022-present <a href="https://blog.charles7c.top/about/me" target="_blank" rel="noopener">Charles7c</a> <span>⋅</span> <a href="https://github.com/Charles7c/continew-admin" target="_blank" rel="noopener">ContiNew Admin</a> <span>⋅</span> <a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">津ICP备2022005864号-2</a>',
|
||||||
'用于显示登录页面的底部版权信息。', NULL, NULL),
|
'用于显示登录页面的底部版权信息。', NULL, NULL),
|
||||||
('系统LOGO(16*16)', 'site_favicon', NULL, '/favicon.ico', '用于显示浏览器地址栏的系统LOGO。', NULL, NULL),
|
('系统LOGO(16*16)', 'site_favicon', NULL, '/favicon.ico', '用于显示浏览器地址栏的系统LOGO。', NULL, NULL),
|
||||||
('系统LOGO(33*33)', 'site_logo', NULL, '/logo.svg', '用于显示登录页面的系统LOGO。', NULL, NULL);
|
('系统LOGO(33*33)', 'site_logo', NULL, '/logo.svg', '用于显示登录页面的系统LOGO。', NULL, NULL),
|
||||||
|
('密码是否允许包含正反序帐户名', 'password_contain_name', NULL, '0', '', NULL, NULL),
|
||||||
|
('密码错误锁定帐户次数', 'password_error_count', NULL, '5', '0表示不限制。', NULL, NULL),
|
||||||
|
('密码有效期', 'password_expiration_days', NULL, '0', '取值范围为0-999,0表示永久有效。', NULL, NULL),
|
||||||
|
('密码错误锁定帐户的时间', 'password_lock_minutes', NULL, '5', '0表示不解锁。', NULL, NULL),
|
||||||
|
('密码最小长度', 'password_min_length', NULL, '8', '取值范围为8-32。', NULL, NULL),
|
||||||
|
('密码是否必须包含特殊字符', 'password_special_char', NULL, '0', '', NULL, NULL),
|
||||||
|
('修改密码最短间隔', 'password_update_interval', NULL, '5', '取值范围为0-9999,0表示不限制。', NULL, NULL);
|
||||||
|
|
||||||
-- 初始化默认字典
|
-- 初始化默认字典
|
||||||
INSERT INTO `sys_dict`
|
INSERT INTO `sys_dict`
|
||||||
|
@ -114,7 +114,14 @@ VALUES
|
|||||||
'Copyright © 2022-present <a href="https://blog.charles7c.top/about/me" target="_blank" rel="noopener">Charles7c</a> <span>⋅</span> <a href="https://github.com/Charles7c/continew-admin" target="_blank" rel="noopener">ContiNew Admin</a> <span>⋅</span> <a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">津ICP备2022005864号-2</a>',
|
'Copyright © 2022-present <a href="https://blog.charles7c.top/about/me" target="_blank" rel="noopener">Charles7c</a> <span>⋅</span> <a href="https://github.com/Charles7c/continew-admin" target="_blank" rel="noopener">ContiNew Admin</a> <span>⋅</span> <a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">津ICP备2022005864号-2</a>',
|
||||||
'用于显示登录页面的底部版权信息。', NULL, NULL),
|
'用于显示登录页面的底部版权信息。', NULL, NULL),
|
||||||
('系统LOGO(16*16)', 'site_favicon', NULL, '/favicon.ico', '用于显示浏览器地址栏的系统LOGO。', NULL, NULL),
|
('系统LOGO(16*16)', 'site_favicon', NULL, '/favicon.ico', '用于显示浏览器地址栏的系统LOGO。', NULL, NULL),
|
||||||
('系统LOGO(33*33)', 'site_logo', NULL, '/logo.svg', '用于显示登录页面的系统LOGO。', NULL, NULL);
|
('系统LOGO(33*33)', 'site_logo', NULL, '/logo.svg', '用于显示登录页面的系统LOGO。', NULL, NULL),
|
||||||
|
('密码是否允许包含正反序帐户名', 'password_contain_name', NULL, '0', '', NULL, NULL),
|
||||||
|
('密码错误锁定帐户次数', 'password_error_count', NULL, '5', '0表示不限制。', NULL, NULL),
|
||||||
|
('密码有效期', 'password_expiration_days', NULL, '0', '取值范围为0-999,0表示永久有效。', NULL, NULL),
|
||||||
|
('密码错误锁定帐户的时间', 'password_lock_minutes', NULL, '5', '0表示不解锁。', NULL, NULL),
|
||||||
|
('密码最小长度', 'password_min_length', NULL, '8', '取值范围为8-32。', NULL, NULL),
|
||||||
|
('密码是否必须包含特殊字符', 'password_special_char', NULL, '0', '', NULL, NULL),
|
||||||
|
('修改密码最短间隔', 'password_update_interval', NULL, '5', '取值范围为0-9999,0表示不限制。', NULL, NULL);
|
||||||
|
|
||||||
-- 初始化默认字典
|
-- 初始化默认字典
|
||||||
INSERT INTO "sys_dict"
|
INSERT INTO "sys_dict"
|
||||||
@ -125,8 +132,8 @@ VALUES
|
|||||||
INSERT INTO "sys_dict_item"
|
INSERT INTO "sys_dict_item"
|
||||||
("id", "label", "value", "color", "sort", "description", "status", "dict_id", "create_user", "create_time", "update_user", "update_time")
|
("id", "label", "value", "color", "sort", "description", "status", "dict_id", "create_user", "create_time", "update_user", "update_time")
|
||||||
VALUES
|
VALUES
|
||||||
(547889649658363951, '通知', '1', 'blue', 1, NULL, 547889614262632491, 1, 1, NOW(), NULL, NULL),
|
(547889649658363951, '通知', '1', 'blue', 1, NULL, 1, 547889614262632491, 1, NOW(), NULL, NULL),
|
||||||
(547890124537462835, '活动', '2', 'orangered', 2, NULL, 547889614262632491, 1, 1, NOW(), NULL, NULL);
|
(547890124537462835, '活动', '2', 'orangered', 2, NULL, 1, 547889614262632491, 1, NOW(), NULL, NULL);
|
||||||
|
|
||||||
-- 初始化默认用户和角色关联数据
|
-- 初始化默认用户和角色关联数据
|
||||||
INSERT INTO "sys_user_role"
|
INSERT INTO "sys_user_role"
|
||||||
|
@ -16,13 +16,31 @@
|
|||||||
|
|
||||||
package com.zayac.admin;
|
package com.zayac.admin;
|
||||||
|
|
||||||
|
import com.zayac.admin.schedule.CheckRegAndDep;
|
||||||
|
import com.zayac.admin.system.service.DeptService;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
class ContiNewAdminApplicationTests {
|
class ZayacAdminApplicationTests {
|
||||||
|
@Autowired
|
||||||
|
private CheckRegAndDep checkRegAndDep;
|
||||||
|
@Autowired
|
||||||
|
private DeptService deptService;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void contextLoads() {
|
void contextLoads() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSchedule() {
|
||||||
|
checkRegAndDep.checkRegistrationAndNewDeposit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testQuery() {
|
||||||
|
var users = deptService.getDeptWithUsersAndAccounts("minister");
|
||||||
|
System.out.println(users);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user