Compare commits
8 Commits
8e6eb5b382
...
codex/migr
| Author | SHA1 | Date | |
|---|---|---|---|
| 28088d43a8 | |||
| f1e4b26800 | |||
| 235672304a | |||
| ec4a7c09db | |||
| 5839a76f87 | |||
| fa0b446699 | |||
| f001047d0c | |||
| 09707d312e |
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": []
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(java:*)",
|
||||
"Bash(binrun.bat:*)",
|
||||
"Bash(mvn clean package:*)",
|
||||
"Bash(curl:*)",
|
||||
"Bash(pkill:*)",
|
||||
"Bash(bash:*)",
|
||||
"Bash(pip install:*)",
|
||||
"Bash(findstr:*)",
|
||||
"Bash(chcp:*)",
|
||||
"Bash(cmd.exe:*)",
|
||||
"Bash(powershell -Command:*)",
|
||||
"Bash(git add:*)",
|
||||
"Bash(cd:*)",
|
||||
"mcp__zai-mcp-server__extract_text_from_screenshot",
|
||||
"Bash(mvn test:*)",
|
||||
"Bash(mvn install:*)",
|
||||
"Bash(mvn clean install:*)",
|
||||
"mcp__web-reader__webReader",
|
||||
"Skill(superpowers:brainstorming)",
|
||||
"Skill(superpowers:writing-plans)",
|
||||
"Skill(superpowers:executing-plans)"
|
||||
],
|
||||
"additionalDirectories": [
|
||||
"d:\\利率定价\\loan-pricing-892\\loan-pricing-892-v2.0"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"paths": {
|
||||
"specs": ".claude/specs",
|
||||
"steering": ".claude/steering",
|
||||
"settings": ".claude/settings"
|
||||
},
|
||||
"views": {
|
||||
"specs": {
|
||||
"visible": true
|
||||
},
|
||||
"steering": {
|
||||
"visible": true
|
||||
},
|
||||
"mcp": {
|
||||
"visible": true
|
||||
},
|
||||
"hooks": {
|
||||
"visible": true
|
||||
},
|
||||
"settings": {
|
||||
"visible": false
|
||||
}
|
||||
}
|
||||
}
|
||||
89
.gitignore
vendored
89
.gitignore
vendored
@@ -1,51 +1,48 @@
|
||||
######################################################################
|
||||
# Build Tools
|
||||
|
||||
.gradle
|
||||
/build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
######################################################################
|
||||
# IDE
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### JRebel ###
|
||||
rebel.xml
|
||||
|
||||
### NetBeans ###
|
||||
nbproject/private/
|
||||
build/*
|
||||
nbbuild/
|
||||
dist/
|
||||
nbdist/
|
||||
.nb-gradle/
|
||||
|
||||
######################################################################
|
||||
# Build Tools
|
||||
|
||||
.gradle
|
||||
/build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
######################################################################
|
||||
# IDE
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### JRebel ###
|
||||
rebel.xml
|
||||
|
||||
### NetBeans ###
|
||||
nbproject/private/
|
||||
build/*
|
||||
nbbuild/
|
||||
dist/
|
||||
nbdist/
|
||||
.nb-gradle/
|
||||
|
||||
######################################################################
|
||||
# Others
|
||||
.DS_Store
|
||||
*.log
|
||||
*.xml.versionsBackup
|
||||
*.swp
|
||||
|
||||
!*/build/*.java
|
||||
!*/build/*.html
|
||||
!*/build/*.xml
|
||||
|
||||
|
||||
logs/
|
||||
ruoyi-ui/dist.zip
|
||||
|
||||
!*/build/*.java
|
||||
!*/build/*.html
|
||||
!*/build/*.xml
|
||||
|
||||
18
.playwright-cli/page-2026-04-11T07-16-36-054Z.yml
Normal file
18
.playwright-cli/page-2026-04-11T07-16-36-054Z.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
- generic [ref=e2]:
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- heading "上虞利率定价系统" [level=3] [ref=e5]
|
||||
- generic [ref=e8]:
|
||||
- textbox "账号" [ref=e9]
|
||||
- img [ref=e11]
|
||||
- generic [ref=e15]:
|
||||
- textbox "密码" [ref=e16]
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20] [cursor=pointer]:
|
||||
- generic [ref=e21]:
|
||||
- checkbox "记住密码"
|
||||
- generic [ref=e23]: 记住密码
|
||||
- button "登 录" [ref=e26] [cursor=pointer]:
|
||||
- generic [ref=e27]: 登 录
|
||||
- generic [ref=e28]: Copyright © 2018-2026 RuoYi. All Rights Reserved.
|
||||
- text:
|
||||
20
.playwright-cli/page-2026-04-11T07-17-14-786Z.yml
Normal file
20
.playwright-cli/page-2026-04-11T07-17-14-786Z.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
- generic [ref=e2]:
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- heading "上虞利率定价系统" [level=3] [ref=e5]
|
||||
- generic [ref=e8]:
|
||||
- textbox "账号" [ref=e9]: admin123admin
|
||||
- img [ref=e11]
|
||||
- generic [ref=e14]:
|
||||
- generic [ref=e15]:
|
||||
- textbox "密码" [ref=e16]
|
||||
- img [ref=e18]
|
||||
- generic [ref=e29]: 请输入您的密码
|
||||
- generic [ref=e20] [cursor=pointer]:
|
||||
- generic [ref=e21]:
|
||||
- checkbox "记住密码"
|
||||
- generic [ref=e23]: 记住密码
|
||||
- button "登 录" [active] [ref=e26] [cursor=pointer]:
|
||||
- generic [ref=e27]: 登 录
|
||||
- generic [ref=e28]: Copyright © 2018-2026 RuoYi. All Rights Reserved.
|
||||
- text:
|
||||
1
.playwright-cli/page-2026-04-11T07-18-09-957Z.yml
Normal file
1
.playwright-cli/page-2026-04-11T07-18-09-957Z.yml
Normal file
@@ -0,0 +1 @@
|
||||
- generic [ref=e2]:
|
||||
191
.playwright-cli/page-2026-04-11T07-18-43-284Z.yml
Normal file
191
.playwright-cli/page-2026-04-11T07-18-43-284Z.yml
Normal file
@@ -0,0 +1,191 @@
|
||||
- generic [ref=e2]:
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- link "上虞利率定价系统" [ref=e6] [cursor=pointer]:
|
||||
- /url: /
|
||||
- img [ref=e7]
|
||||
- heading "上虞利率定价系统" [level=1] [ref=e8]
|
||||
- menubar [ref=e12]:
|
||||
- link "流程列表" [ref=e14] [cursor=pointer]:
|
||||
- /url: /index
|
||||
- menuitem "流程列表" [ref=e15]:
|
||||
- img [ref=e16]
|
||||
- text: 流程列表
|
||||
- menuitem "系统管理 " [ref=e19]:
|
||||
- generic [ref=e20] [cursor=pointer]:
|
||||
- img [ref=e21]
|
||||
- text: 系统管理
|
||||
- generic [ref=e23]:
|
||||
- text:
|
||||
- generic [ref=e25]:
|
||||
- generic [ref=e26]:
|
||||
- generic [ref=e27]:
|
||||
- img [ref=e29] [cursor=pointer]
|
||||
- navigation "Breadcrumb" [ref=e31]:
|
||||
- generic:
|
||||
- generic [ref=e32]:
|
||||
- link "首页" [ref=e33]
|
||||
- text: /
|
||||
- generic [ref=e379]:
|
||||
- link "利率定价管理" [ref=e380]
|
||||
- text: /
|
||||
- link "流程列表" [ref=e382]
|
||||
- generic [ref=e36]:
|
||||
- img [ref=e38] [cursor=pointer]
|
||||
- img [ref=e41] [cursor=pointer]
|
||||
- button [ref=e44] [cursor=pointer]:
|
||||
- img [ref=e45]
|
||||
- button "若依" [ref=e48] [cursor=pointer]:
|
||||
- img [ref=e49]
|
||||
- text: 若依
|
||||
- generic [ref=e50]:
|
||||
- generic [ref=e53]:
|
||||
- generic [ref=e54] [cursor=pointer]: 流程列表
|
||||
- generic [ref=e383] [cursor=pointer]:
|
||||
- text: 流程详情
|
||||
- generic [ref=e384]:
|
||||
- text:
|
||||
- generic [ref=e385]:
|
||||
- generic [ref=e386]:
|
||||
- heading "流程详情" [level=2] [ref=e387]
|
||||
- button " 返回" [ref=e388] [cursor=pointer]:
|
||||
- generic [ref=e389]:
|
||||
- text: 返回
|
||||
- generic [ref=e391]:
|
||||
- generic [ref=e393]:
|
||||
- generic [ref=e396]: 关键信息
|
||||
- table [ref=e400]:
|
||||
- rowgroup [ref=e401]:
|
||||
- row "业务方流水号" [ref=e402]:
|
||||
- columnheader "业务方流水号" [ref=e403]
|
||||
- row "20260410150311114" [ref=e404]:
|
||||
- cell "20260410150311114" [ref=e405]
|
||||
- rowgroup [ref=e406]:
|
||||
- row "客户名称" [ref=e407]:
|
||||
- columnheader "客户名称" [ref=e408]
|
||||
- row "t***" [ref=e409]:
|
||||
- cell "t***" [ref=e410]
|
||||
- rowgroup [ref=e411]:
|
||||
- row "客户类型" [ref=e412]:
|
||||
- columnheader "客户类型" [ref=e413]
|
||||
- row "个人" [ref=e414]:
|
||||
- cell "个人" [ref=e415]
|
||||
- rowgroup [ref=e416]:
|
||||
- row "申请金额" [ref=e417]:
|
||||
- columnheader "申请金额" [ref=e418]
|
||||
- row "1000 元" [ref=e419]:
|
||||
- cell "1000 元" [ref=e420]
|
||||
- rowgroup [ref=e421]:
|
||||
- row "基准利率" [ref=e422]:
|
||||
- columnheader "基准利率" [ref=e423]
|
||||
- row "4.35 %" [ref=e424]:
|
||||
- cell "4.35 %" [ref=e425]
|
||||
- rowgroup [ref=e426]:
|
||||
- row "浮动BP" [ref=e427]:
|
||||
- columnheader "浮动BP" [ref=e428]
|
||||
- row "350" [ref=e429]:
|
||||
- cell "350" [ref=e430]
|
||||
- rowgroup [ref=e431]:
|
||||
- row "最终测算利率" [ref=e432]:
|
||||
- columnheader "最终测算利率" [ref=e433]
|
||||
- row "6.05 %" [ref=e434]:
|
||||
- cell "6.05 %" [ref=e435]
|
||||
- rowgroup [ref=e436]:
|
||||
- row "执行利率" [ref=e437]:
|
||||
- columnheader "执行利率" [ref=e438]
|
||||
- row "% 确定" [ref=e439]:
|
||||
- cell "% 确定" [ref=e440]:
|
||||
- generic [ref=e441]:
|
||||
- generic [ref=e442]:
|
||||
- textbox "请输入执行利率" [ref=e443]
|
||||
- generic [ref=e444]: "%"
|
||||
- button "确定" [ref=e445] [cursor=pointer]
|
||||
- generic [ref=e446]:
|
||||
- generic [ref=e447]:
|
||||
- generic [ref=e450]: 流程详情
|
||||
- generic [ref=e451]:
|
||||
- generic [ref=e452]:
|
||||
- heading "基本信息" [level=4] [ref=e453]
|
||||
- table [ref=e456]:
|
||||
- rowgroup [ref=e457]:
|
||||
- row "机构编码 892000 运行模式 1" [ref=e458]:
|
||||
- rowheader "机构编码" [ref=e459]
|
||||
- cell "892000" [ref=e460]
|
||||
- rowheader "运行模式" [ref=e461]
|
||||
- cell "1" [ref=e462]
|
||||
- rowgroup [ref=e463]:
|
||||
- row "客户内码 test 证件类型 身份证" [ref=e464]:
|
||||
- rowheader "客户内码" [ref=e465]
|
||||
- cell "test" [ref=e466]
|
||||
- rowheader "证件类型" [ref=e467]
|
||||
- cell "身份证" [ref=e468]
|
||||
- rowgroup [ref=e469]:
|
||||
- row "证件号码 ** 创建时间 2026-04-10 15:03:11" [ref=e470]:
|
||||
- rowheader "证件号码" [ref=e471]
|
||||
- cell "**" [ref=e472]
|
||||
- rowheader "创建时间" [ref=e473]
|
||||
- cell "2026-04-10 15:03:11" [ref=e474]
|
||||
- rowgroup [ref=e475]:
|
||||
- row "创建者 若依-admin" [ref=e476]:
|
||||
- rowheader "创建者" [ref=e477]
|
||||
- cell "若依-admin" [ref=e478]
|
||||
- generic [ref=e479]:
|
||||
- heading "业务信息" [level=4] [ref=e480]
|
||||
- table [ref=e483]:
|
||||
- rowgroup [ref=e484]:
|
||||
- row "担保方式 信用 申请金额 1000 元" [ref=e485]:
|
||||
- rowheader "担保方式" [ref=e486]
|
||||
- cell "信用" [ref=e487]
|
||||
- rowheader "申请金额" [ref=e488]
|
||||
- cell "1000 元" [ref=e489]
|
||||
- rowgroup [ref=e490]:
|
||||
- row "贷款用途 消费 借款期限 1" [ref=e491]:
|
||||
- rowheader "贷款用途" [ref=e492]
|
||||
- cell "消费" [ref=e493]
|
||||
- rowheader "借款期限" [ref=e494]
|
||||
- cell "1" [ref=e495]
|
||||
- rowgroup [ref=e496]:
|
||||
- row "是否有经营佐证 否 循环功能 否" [ref=e497]:
|
||||
- rowheader "是否有经营佐证" [ref=e498]
|
||||
- cell "否" [ref=e499]
|
||||
- rowheader "循环功能" [ref=e500]
|
||||
- cell "否" [ref=e501]
|
||||
- rowgroup [ref=e502]:
|
||||
- row "抵质押类型 - 抵质押物是否三方所有 否" [ref=e503]:
|
||||
- rowheader "抵质押类型" [ref=e504]
|
||||
- cell "-" [ref=e505]
|
||||
- rowheader "抵质押物是否三方所有" [ref=e506]
|
||||
- cell "否" [ref=e507]
|
||||
- generic [ref=e508]:
|
||||
- generic [ref=e511]: 模型输出
|
||||
- generic [ref=e513]:
|
||||
- generic [ref=e515]:
|
||||
- generic [ref=e517] [cursor=pointer]:
|
||||
- generic [ref=e519] [cursor=pointer]:
|
||||
- tablist [ref=e521]:
|
||||
- tab "基本信息" [selected] [ref=e523]
|
||||
- tab "忠诚度分析" [ref=e524]
|
||||
- tab "贡献度分析" [ref=e525]
|
||||
- tab "关联度分析" [ref=e526]
|
||||
- tab "贷款特征" [ref=e527]
|
||||
- tab "风险度分析" [ref=e528]
|
||||
- tab "测算结果" [ref=e529]
|
||||
- tabpanel "基本信息" [ref=e531]:
|
||||
- table [ref=e534]:
|
||||
- rowgroup [ref=e535]:
|
||||
- row "客户内码 CUST20260121001 客户名称 张*" [ref=e536]:
|
||||
- rowheader "客户内码" [ref=e537]
|
||||
- cell "CUST20260121001" [ref=e538]
|
||||
- rowheader "客户名称" [ref=e539]
|
||||
- cell "张*" [ref=e540]
|
||||
- rowgroup [ref=e541]:
|
||||
- row "证件类型 身份证 证件号码 3301********1234" [ref=e542]:
|
||||
- rowheader "证件类型" [ref=e543]
|
||||
- cell "身份证" [ref=e544]
|
||||
- rowheader "证件号码" [ref=e545]
|
||||
- cell "3301********1234" [ref=e546]
|
||||
- rowgroup [ref=e547]:
|
||||
- row "基准利率 4.35 %" [ref=e548]:
|
||||
- rowheader "基准利率" [ref=e549]
|
||||
- cell "4.35 %" [ref=e550]
|
||||
- text:
|
||||
18
.playwright-cli/page-2026-04-11T07-25-40-868Z.yml
Normal file
18
.playwright-cli/page-2026-04-11T07-25-40-868Z.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
- generic [ref=e2]:
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- heading "上虞利率定价系统" [level=3] [ref=e5]
|
||||
- generic [ref=e8]:
|
||||
- textbox "账号" [ref=e9]
|
||||
- img [ref=e11]
|
||||
- generic [ref=e15]:
|
||||
- textbox "密码" [ref=e16]
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20] [cursor=pointer]:
|
||||
- generic [ref=e21]:
|
||||
- checkbox "记住密码"
|
||||
- generic [ref=e23]: 记住密码
|
||||
- button "登 录" [ref=e26] [cursor=pointer]:
|
||||
- generic [ref=e27]: 登 录
|
||||
- generic [ref=e28]: Copyright © 2018-2026 RuoYi. All Rights Reserved.
|
||||
- text:
|
||||
1
.playwright-cli/page-2026-04-11T07-25-55-827Z.yml
Normal file
1
.playwright-cli/page-2026-04-11T07-25-55-827Z.yml
Normal file
@@ -0,0 +1 @@
|
||||
- generic [ref=e2]:
|
||||
1
.playwright-cli/page-2026-04-11T07-26-20-300Z.yml
Normal file
1
.playwright-cli/page-2026-04-11T07-26-20-300Z.yml
Normal file
@@ -0,0 +1 @@
|
||||
- generic [ref=e2]:
|
||||
1
.playwright-cli/page-2026-04-11T07-26-34-973Z.yml
Normal file
1
.playwright-cli/page-2026-04-11T07-26-34-973Z.yml
Normal file
@@ -0,0 +1 @@
|
||||
- generic [ref=e2]:
|
||||
28
.playwright-cli/page-2026-04-14T05-22-21-308Z.yml
Normal file
28
.playwright-cli/page-2026-04-14T05-22-21-308Z.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
- generic [active] [ref=e1]:
|
||||
- generic [ref=e2]:
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- heading "若依管理系统" [level=3] [ref=e5]
|
||||
- generic [ref=e8]:
|
||||
- textbox "账号" [ref=e9]: admin
|
||||
- img [ref=e11]
|
||||
- generic [ref=e15]:
|
||||
- textbox "密码" [ref=e16]: admin123
|
||||
- img [ref=e18]
|
||||
- generic [ref=e21]:
|
||||
- generic [ref=e22]:
|
||||
- textbox "验证码" [ref=e23]
|
||||
- img [ref=e25]
|
||||
- generic [ref=e27]:
|
||||
- img
|
||||
- generic [ref=e28] [cursor=pointer]:
|
||||
- generic [ref=e29]:
|
||||
- checkbox "记住密码"
|
||||
- generic [ref=e31]: 记住密码
|
||||
- button "登 录" [ref=e34] [cursor=pointer]:
|
||||
- generic [ref=e35]: 登 录
|
||||
- generic [ref=e36]: Copyright © 2018-2026 RuoYi. All Rights Reserved.
|
||||
- text:
|
||||
- alert [ref=e37]:
|
||||
- generic [ref=e38]:
|
||||
- paragraph [ref=e39]: 系统接口500异常
|
||||
18
.playwright-cli/page-2026-04-14T05-39-30-657Z.yml
Normal file
18
.playwright-cli/page-2026-04-14T05-39-30-657Z.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
- generic [ref=e2]:
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- heading "若依管理系统" [level=3] [ref=e5]
|
||||
- generic [ref=e8]:
|
||||
- textbox "账号" [ref=e9]: admin
|
||||
- img [ref=e11]
|
||||
- generic [ref=e15]:
|
||||
- textbox "密码" [ref=e16]: admin123
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20] [cursor=pointer]:
|
||||
- generic [ref=e21]:
|
||||
- checkbox "记住密码"
|
||||
- generic [ref=e23]: 记住密码
|
||||
- button "登 录" [ref=e26] [cursor=pointer]:
|
||||
- generic [ref=e27]: 登 录
|
||||
- generic [ref=e28]: Copyright © 2018-2026 RuoYi. All Rights Reserved.
|
||||
- text:
|
||||
33
README.md
33
README.md
@@ -1,11 +1,11 @@
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-d3d0a9303e11d522a06cd263f3079027715.png">
|
||||
</p>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.9.1</h1>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.9.2</h1>
|
||||
<h4 align="center">基于SpringBoot+Vue前后端分离的Java快速开发框架</h4>
|
||||
<p align="center">
|
||||
<a href="https://gitee.com/y_project/RuoYi-Vue/stargazers"><img src="https://gitee.com/y_project/RuoYi-Vue/badge/star.svg?theme=dark"></a>
|
||||
<a href="https://gitee.com/y_project/RuoYi-Vue"><img src="https://img.shields.io/badge/RuoYi-v3.9.1-brightgreen.svg"></a>
|
||||
<a href="https://gitee.com/y_project/RuoYi-Vue"><img src="https://img.shields.io/badge/RuoYi-v3.9.2-brightgreen.svg"></a>
|
||||
<a href="https://gitee.com/y_project/RuoYi-Vue/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
|
||||
</p>
|
||||
|
||||
@@ -13,16 +13,37 @@
|
||||
|
||||
若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。
|
||||
|
||||
* 本仓库为RuoYi-Vue的Spring Boot 2 的版本,保持同步更新。
|
||||
* 前端采用Vue、Element UI。
|
||||
* 后端采用Spring Boot、Spring Security、Redis & Jwt。
|
||||
* 权限认证使用Jwt,支持多终端认证系统。
|
||||
* 支持加载动态权限菜单,多方式轻松权限控制。
|
||||
* 高效率开发,使用代码生成器可以一键生成前后端代码。
|
||||
* 提供了技术栈([Vue3](https://v3.cn.vuejs.org) [Element Plus](https://element-plus.org/zh-CN) [Vite](https://cn.vitejs.dev))版本[RuoYi-Vue3](https://gitcode.com/yangzongzhuan/RuoYi-Vue3),保持同步更新。
|
||||
* 提供了单应用版本[RuoYi-Vue-fast](https://gitcode.com/yangzongzhuan/RuoYi-Vue-fast),Oracle版本[RuoYi-Vue-Oracle](https://gitcode.com/yangzongzhuan/RuoYi-Vue-Oracle),保持同步更新。
|
||||
* 不分离版本,请移步[RuoYi](https://gitee.com/y_project/RuoYi),微服务版本,请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud)
|
||||
* 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)
|
||||
|
||||
# 版本分支
|
||||
|
||||
RuoYi-Vue 后端项目提供 Spring Boot 2.x / 3.x / 4.x 多版本分支的并行维护。
|
||||
|
||||
| 名称 | 说明 | 地址 |
|
||||
| :---------------- | :------------------------ | :------------------------------------------------------ |
|
||||
| master 默认分支 | Spring Boot 4.x (JDK 17+) | https://gitee.com/y_project/RuoYi-Vue |
|
||||
| springboot3 分支 | Spring Boot 3.x (JDK 17+) | https://gitee.com/y_project/RuoYi-Vue/tree/springboot3 |
|
||||
| springboot2 分支 | Spring Boot 2.x (JDK 8+) | https://gitee.com/y_project/RuoYi-Vue/tree/springboot2 |
|
||||
|
||||
RuoYi-Vue 前端项目提供 Vue 2.x / 3.x / JavaScript TypeScript 版本均可混用搭配
|
||||
|
||||
| 项目名称 | **RuoYi-Vue** | **RuoYi-Vue3** | **RuoYi-Vue3-TypeScript** |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **前端框架** | Vue 2 | Vue 3 | Vue 3 |
|
||||
| **脚本语言** | JavaScript | JavaScript | TypeScript |
|
||||
| **构建工具** | Vue CLI | Vite | Vite |
|
||||
| **UI 组件库** | Element UI | Element Plus | Element Plus |
|
||||
| **状态管理** | Vuex | Pinia | Pinia |
|
||||
| **路由管理** | Vue Router 3 | Vue Router 4 | Vue Router 4 |
|
||||
| **核心特点** | 1. 技术栈经典稳定<br>2. 社区资料丰富<br>3. 当前维护重心已转移 | 1. 现代前端技术栈<br>2. 开发体验与性能更优<br>3. 官方主推的活跃版本 | 1. 类型加持,减少沟通成本<br>2. 开发时有提示,效率更高<br>3. 多人协作企业级开发项目 |
|
||||
| **仓库地址** | [RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) | [RuoYi-Vue3](https://gitcode.com/yangzongzhuan/RuoYi-Vue3) | [RuoYi-Vue3-TypeScript](https://gitcode.com/yangzongzhuan/RuoYi-Vue3/tree/typescript) |
|
||||
|
||||
## 内置功能
|
||||
|
||||
1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
|
||||
@@ -92,4 +113,4 @@
|
||||
|
||||
## 若依前后端分离交流群
|
||||
|
||||
QQ群: [](https://jq.qq.com/?_wv=1027&k=5bVB1og) [](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [](https://jq.qq.com/?_wv=1027&k=51G72yr) [](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) [](https://jq.qq.com/?_wv=1027&k=96Dkdq0k) [](https://jq.qq.com/?_wv=1027&k=0fsNiYZt) [](https://jq.qq.com/?_wv=1027&k=7xw4xUG1) [](https://jq.qq.com/?_wv=1027&k=eCx8eyoJ) [](https://jq.qq.com/?_wv=1027&k=SpyH2875) [](https://jq.qq.com/?_wv=1027&k=tKEt51dz) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=0vBbSb0ztbBgVtn3kJS-Q4HUNYwip89G&authKey=8irq5PhutrZmWIvsUsklBxhj57l%2F1nOZqjzigkXZVoZE451GG4JHPOqW7AW6cf0T&noverify=0&group_code=143961921) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=ZFAPAbp09S2ltvwrJzp7wGlbopsc0rwi&authKey=HB2cxpxP2yspk%2Bo3WKTBfktRCccVkU26cgi5B16u0KcAYrVu7sBaE7XSEqmMdFQp&noverify=0&group_code=174951577) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Fn2aF5IHpwsy8j6VlalNJK6qbwFLFHat&authKey=uyIT%2B97x2AXj3odyXpsSpVaPMC%2Bidw0LxG5MAtEqlrcBcWJUA%2FeS43rsF1Tg7IRJ&noverify=0&group_code=161281055) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XIzkm_mV2xTsUtFxo63bmicYoDBA6Ifm&authKey=dDW%2F4qsmw3x9govoZY9w%2FoWAoC4wbHqGal%2BbqLzoS6VBarU8EBptIgPKN%2FviyC8j&noverify=0&group_code=138988063) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=DkugnCg68PevlycJSKSwjhFqfIgrWWwR&authKey=pR1Pa5lPIeGF%2FFtIk6d%2FGB5qFi0EdvyErtpQXULzo03zbhopBHLWcuqdpwY241R%2F&noverify=0&group_code=151450850) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=F58bgRa-Dp-rsQJThiJqIYv8t4-lWfXh&authKey=UmUs4CVG5OPA1whvsa4uSespOvyd8%2FAr9olEGaWAfdLmfKQk%2FVBp2YU3u2xXXt76&noverify=0&group_code=224622315) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Nxb2EQ5qozWa218Wbs7zgBnjLSNk_tVT&authKey=obBKXj6SBKgrFTJZx0AqQnIYbNOvBB2kmgwWvGhzxR67RoRr84%2Bus5OadzMcdJl5&noverify=0&group_code=287842588) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=numtK1M_I4eVd2Gvg8qtbuL8JgX42qNh&authKey=giV9XWMaFZTY%2FqPlmWbkB9g3fi0Ev5CwEtT9Tgei0oUlFFCQLDp4ozWRiVIzubIm&noverify=0&group_code=187944233) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=G6r5KGCaa3pqdbUSXNIgYloyb8e0_L0D&authKey=4w8tF1eGW7%2FedWn%2FHAypQksdrML%2BDHolQSx7094Agm7Luakj9EbfPnSTxSi2T1LQ&noverify=0&group_code=228578329) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=GsOo-OLz53J8y_9TPoO6XXSGNRTgbFxA&authKey=R7Uy%2Feq%2BZsoKNqHvRKhiXpypW7DAogoWapOawUGHokJSBIBIre2%2FoiAZeZBSLuBc&noverify=0&group_code=191164766) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=PmYavuzsOthVqfdAPbo4uAeIbu7Ttjgc&authKey=p52l8%2FXa4PS1JcEmS3VccKSwOPJUZ1ZfQ69MEKzbrooNUljRtlKjvsXf04bxNp3G&noverify=0&group_code=174569686) 点击按钮入群。
|
||||
QQ群: [](https://jq.qq.com/?_wv=1027&k=5bVB1og) [](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [](https://jq.qq.com/?_wv=1027&k=51G72yr) [](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) [](https://jq.qq.com/?_wv=1027&k=96Dkdq0k) [](https://jq.qq.com/?_wv=1027&k=0fsNiYZt) [](https://jq.qq.com/?_wv=1027&k=7xw4xUG1) [](https://jq.qq.com/?_wv=1027&k=eCx8eyoJ) [](https://jq.qq.com/?_wv=1027&k=SpyH2875) [](https://jq.qq.com/?_wv=1027&k=tKEt51dz) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=0vBbSb0ztbBgVtn3kJS-Q4HUNYwip89G&authKey=8irq5PhutrZmWIvsUsklBxhj57l%2F1nOZqjzigkXZVoZE451GG4JHPOqW7AW6cf0T&noverify=0&group_code=143961921) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=ZFAPAbp09S2ltvwrJzp7wGlbopsc0rwi&authKey=HB2cxpxP2yspk%2Bo3WKTBfktRCccVkU26cgi5B16u0KcAYrVu7sBaE7XSEqmMdFQp&noverify=0&group_code=174951577) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Fn2aF5IHpwsy8j6VlalNJK6qbwFLFHat&authKey=uyIT%2B97x2AXj3odyXpsSpVaPMC%2Bidw0LxG5MAtEqlrcBcWJUA%2FeS43rsF1Tg7IRJ&noverify=0&group_code=161281055) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XIzkm_mV2xTsUtFxo63bmicYoDBA6Ifm&authKey=dDW%2F4qsmw3x9govoZY9w%2FoWAoC4wbHqGal%2BbqLzoS6VBarU8EBptIgPKN%2FviyC8j&noverify=0&group_code=138988063) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=DkugnCg68PevlycJSKSwjhFqfIgrWWwR&authKey=pR1Pa5lPIeGF%2FFtIk6d%2FGB5qFi0EdvyErtpQXULzo03zbhopBHLWcuqdpwY241R%2F&noverify=0&group_code=151450850) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=F58bgRa-Dp-rsQJThiJqIYv8t4-lWfXh&authKey=UmUs4CVG5OPA1whvsa4uSespOvyd8%2FAr9olEGaWAfdLmfKQk%2FVBp2YU3u2xXXt76&noverify=0&group_code=224622315) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Nxb2EQ5qozWa218Wbs7zgBnjLSNk_tVT&authKey=obBKXj6SBKgrFTJZx0AqQnIYbNOvBB2kmgwWvGhzxR67RoRr84%2Bus5OadzMcdJl5&noverify=0&group_code=287842588) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=numtK1M_I4eVd2Gvg8qtbuL8JgX42qNh&authKey=giV9XWMaFZTY%2FqPlmWbkB9g3fi0Ev5CwEtT9Tgei0oUlFFCQLDp4ozWRiVIzubIm&noverify=0&group_code=187944233) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=G6r5KGCaa3pqdbUSXNIgYloyb8e0_L0D&authKey=4w8tF1eGW7%2FedWn%2FHAypQksdrML%2BDHolQSx7094Agm7Luakj9EbfPnSTxSi2T1LQ&noverify=0&group_code=228578329) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=GsOo-OLz53J8y_9TPoO6XXSGNRTgbFxA&authKey=R7Uy%2Feq%2BZsoKNqHvRKhiXpypW7DAogoWapOawUGHokJSBIBIre2%2FoiAZeZBSLuBc&noverify=0&group_code=191164766) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=PmYavuzsOthVqfdAPbo4uAeIbu7Ttjgc&authKey=p52l8%2FXa4PS1JcEmS3VccKSwOPJUZ1ZfQ69MEKzbrooNUljRtlKjvsXf04bxNp3G&noverify=0&group_code=174569686) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=M9y5NjAl44lAL_Vh2crmEehZU_PMU6KS&authKey=ZSDz8hEREWSaPuxQV3gEwqGIaGjfRNnkB4rJjf0IvXhrSUGSGwQFmBA%2Boe8HFxyl&noverify=0&group_code=127358632) 点击按钮入群。
|
||||
BIN
bin/.DS_Store
vendored
BIN
bin/.DS_Store
vendored
Binary file not shown.
@@ -1,12 +1,12 @@
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 清理工程target生成路径。
|
||||
echo.
|
||||
|
||||
%~d0
|
||||
cd %~dp0
|
||||
|
||||
cd ..
|
||||
call mvn clean
|
||||
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 清理工程target生成路径。
|
||||
echo.
|
||||
|
||||
%~d0
|
||||
cd %~dp0
|
||||
|
||||
cd ..
|
||||
call mvn clean
|
||||
|
||||
pause
|
||||
@@ -1,12 +1,12 @@
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 打包Web工程,生成war/jar包文件。
|
||||
echo.
|
||||
|
||||
%~d0
|
||||
cd %~dp0
|
||||
|
||||
cd ..
|
||||
call mvn clean package -Dmaven.test.skip=true
|
||||
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 打包Web工程,生成war/jar包文件。
|
||||
echo.
|
||||
|
||||
%~d0
|
||||
cd %~dp0
|
||||
|
||||
cd ..
|
||||
call mvn clean package -Dmaven.test.skip=true
|
||||
|
||||
pause
|
||||
@@ -71,7 +71,16 @@ collect_backend_pids() {
|
||||
fi
|
||||
fi
|
||||
|
||||
marker_pids=$(pgrep -f "$BACKEND_MARKER" 2>/dev/null || true)
|
||||
marker_pids=$(ps -ef | awk -v marker="$BACKEND_MARKER" -v jar="$BACKEND_JAR" '
|
||||
index($0, "<defunct>") == 0 && index($0, marker) > 0 {
|
||||
for (i = 1; i < NF; i++) {
|
||||
if ($i == "-jar" && $(i + 1) == jar) {
|
||||
print $2
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
' | xargs 2>/dev/null || true)
|
||||
if [ -n "${marker_pids:-}" ]; then
|
||||
for pid in $marker_pids; do
|
||||
if is_managed_backend_pid "$pid"; then
|
||||
|
||||
8
bin/prod/restart_java_test.sh
Normal file → Executable file
8
bin/prod/restart_java_test.sh
Normal file → Executable file
@@ -44,8 +44,8 @@ EOF
|
||||
prepare_script_env() {
|
||||
work_dir="$1"
|
||||
|
||||
mkdir -p "$work_dir/env/java/bin" "$work_dir/loan-pricing/backend" "$work_dir/loan-pricing/logs" "$work_dir/loan-pricing/run"
|
||||
create_fake_java "$work_dir/env/java/bin/java"
|
||||
mkdir -p "$work_dir/env/jdk/bin" "$work_dir/loan-pricing/backend" "$work_dir/loan-pricing/logs" "$work_dir/loan-pricing/run"
|
||||
create_fake_java "$work_dir/env/jdk/bin/java"
|
||||
printf 'fake-jar\n' > "$work_dir/loan-pricing/backend/ruoyi-admin.jar"
|
||||
cp "$SCRIPT_UNDER_TEST" "$work_dir/restart_java.sh"
|
||||
perl -0pi -e "s#WEBAPP_ROOT=\"/home/webapp\"#WEBAPP_ROOT=\"$work_dir\"#" "$work_dir/restart_java.sh"
|
||||
@@ -67,8 +67,10 @@ cleanup_work_dir() {
|
||||
}
|
||||
|
||||
test_script_contract() {
|
||||
assert_grep 'JAVA_HOME="\$ENV_ROOT/java"' "$SCRIPT_UNDER_TEST"
|
||||
assert_grep 'JAVA_HOME="\$ENV_ROOT/jdk"' "$SCRIPT_UNDER_TEST"
|
||||
assert_grep '--spring\.profiles\.active=pro' "$SCRIPT_UNDER_TEST"
|
||||
assert_grep 'ps -ef' "$SCRIPT_UNDER_TEST"
|
||||
assert_not_grep 'pgrep' "$SCRIPT_UNDER_TEST"
|
||||
assert_not_grep 'mvn' "$SCRIPT_UNDER_TEST"
|
||||
assert_not_grep 'require_root' "$SCRIPT_UNDER_TEST"
|
||||
assert_not_grep '\b(ss|lsof|netstat)\b' "$SCRIPT_UNDER_TEST"
|
||||
|
||||
@@ -83,7 +83,16 @@ collect_pids() {
|
||||
fi
|
||||
fi
|
||||
|
||||
marker_pids=$(pgrep -f "$APP_MARKER" 2>/dev/null || true)
|
||||
marker_pids=$(ps -ef | awk -v marker="$APP_MARKER" -v jar="$JAR_NAME" '
|
||||
index($0, "<defunct>") == 0 && index($0, marker) > 0 {
|
||||
for (i = 1; i < NF; i++) {
|
||||
if ($i == "-jar" && $(i + 1) == jar) {
|
||||
print $2
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
' | xargs 2>/dev/null || true)
|
||||
if [ -n "${marker_pids:-}" ]; then
|
||||
for pid in $marker_pids; do
|
||||
if is_managed_backend_pid "$pid"; then
|
||||
@@ -225,7 +234,6 @@ restart_action() {
|
||||
main() {
|
||||
ensure_command mvn
|
||||
ensure_command lsof
|
||||
ensure_command pgrep
|
||||
ensure_command ps
|
||||
ensure_command tail
|
||||
|
||||
|
||||
42
bin/restart_java_backend_test.sh
Executable file
42
bin/restart_java_backend_test.sh
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
ROOT_DIR=$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)
|
||||
SCRIPT_UNDER_TEST="$ROOT_DIR/bin/restart_java_backend.sh"
|
||||
|
||||
fail() {
|
||||
printf 'FAIL: %s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
assert_grep() {
|
||||
pattern="$1"
|
||||
target="$2"
|
||||
if ! grep -Eq -- "$pattern" "$target"; then
|
||||
fail "expected pattern [$pattern] in $target"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_not_grep() {
|
||||
pattern="$1"
|
||||
target="$2"
|
||||
if grep -Eq -- "$pattern" "$target"; then
|
||||
fail "did not expect pattern [$pattern] in $target"
|
||||
fi
|
||||
}
|
||||
|
||||
test_script_contract() {
|
||||
assert_grep 'ps -ef' "$SCRIPT_UNDER_TEST"
|
||||
assert_not_grep 'pgrep' "$SCRIPT_UNDER_TEST"
|
||||
assert_grep 'APP_MARKER=' "$SCRIPT_UNDER_TEST"
|
||||
assert_grep 'status_backend\(\)' "$SCRIPT_UNDER_TEST"
|
||||
}
|
||||
|
||||
main() {
|
||||
[ -f "$SCRIPT_UNDER_TEST" ] || fail "script under test not found: $SCRIPT_UNDER_TEST"
|
||||
test_script_contract
|
||||
printf 'PASS: restart_java_backend tests\n'
|
||||
}
|
||||
|
||||
main "$@"
|
||||
26
bin/run.bat
26
bin/run.bat
@@ -1,14 +1,14 @@
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 使用Jar命令运行Web工程。
|
||||
echo.
|
||||
|
||||
cd %~dp0
|
||||
cd ../ruoyi-admin/target
|
||||
|
||||
set JAVA_OPTS=-Xms256m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
|
||||
|
||||
java -jar %JAVA_OPTS% ruoyi-admin.jar
|
||||
|
||||
cd bin
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 使用Jar命令运行Web工程。
|
||||
echo.
|
||||
|
||||
cd %~dp0
|
||||
cd ../ruoyi-admin/target
|
||||
|
||||
set JAVA_OPTS=-Xms256m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
|
||||
|
||||
java -jar %JAVA_OPTS% ruoyi-admin.jar
|
||||
|
||||
cd bin
|
||||
pause
|
||||
238
doc/2026-04-09-shangyu-retail-input-params-backend-plan.md
Normal file
238
doc/2026-04-09-shangyu-retail-input-params-backend-plan.md
Normal file
@@ -0,0 +1,238 @@
|
||||
# 上虞个人利率测算输入参数后端 Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 补齐个人创建 DTO、流程转换和模型调用参数,使个人模型请求完整覆盖 Excel 要求的输入字段。
|
||||
|
||||
**Architecture:** 维持现有“页面提交 -> DTO -> Workflow -> ModelInvokeDTO -> form-urlencoded 调用”的链路,只在个人创建与模型调用相关文件中补齐字段和转换规则。通过后端单元测试与真实接口联调覆盖必填、正常和分支场景。
|
||||
|
||||
**Tech Stack:** Spring Boot、MyBatis-Plus、Lombok、JUnit、Maven
|
||||
|
||||
---
|
||||
|
||||
## 后端模型输入参数确认
|
||||
|
||||
个人链路最终需要发给模型的 16 个参数如下:
|
||||
|
||||
- `serialNum`:服务层自动生成
|
||||
- `orgCode`:服务层默认值,当前代码为 `892000`
|
||||
- `runType`:服务层默认值 `1`
|
||||
- `custIsn`:页面输入透传
|
||||
- `custType`:个人链路固定 `个人`
|
||||
- `custName`:页面输入,调用模型前解密后透传
|
||||
- `idType`:页面输入透传
|
||||
- `idNum`:页面输入,调用模型前解密后透传
|
||||
- `guarType`:页面输入透传
|
||||
- `applyAmt`:页面输入透传
|
||||
- `loanPurpose`:页面输入透传
|
||||
- `loanTerm`:页面输入透传
|
||||
- `bizProof`:页面开关,调用模型前转 `0/1`
|
||||
- `loanLoop`:页面开关,调用模型前转 `0/1`
|
||||
- `collThirdParty`:页面开关,调用模型前转 `0/1`
|
||||
- `collType`:页面下拉透传
|
||||
|
||||
调用方式确认:
|
||||
|
||||
- 参数载体:`ModelInvokeDTO`
|
||||
- 组装方式:`BeanUtils.copyProperties(loanPricingWorkflow, modelInvokeDTO)`
|
||||
- 请求格式:`application/x-www-form-urlencoded`
|
||||
- 发送入口:`ModelService#invokeModel`
|
||||
|
||||
## 文件结构
|
||||
|
||||
- Modify: [ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/PersonalLoanPricingCreateDTO.java](/Users/wkc/Desktop/loan-pricing/loan-pricing/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/PersonalLoanPricingCreateDTO.java)
|
||||
- 增加 `loanPurpose`、`loanTerm`
|
||||
- Modify: [ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/util/LoanPricingConverter.java](/Users/wkc/Desktop/loan-pricing/loan-pricing/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/util/LoanPricingConverter.java)
|
||||
- 将新增字段映射到 `LoanPricingWorkflow`
|
||||
- Modify: [ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/ModelInvokeDTO.java](/Users/wkc/Desktop/loan-pricing/loan-pricing/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/ModelInvokeDTO.java)
|
||||
- 增加 `loanTerm`、`loanLoop`
|
||||
- Modify: [ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingModelService.java](/Users/wkc/Desktop/loan-pricing/loan-pricing/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingModelService.java)
|
||||
- 在个人模型调用前规范化 `0/1`
|
||||
- Create: [ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingModelServicePersonalParamsTest.java](/Users/wkc/Desktop/loan-pricing/loan-pricing/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingModelServicePersonalParamsTest.java)
|
||||
- 覆盖字段存在与值转换
|
||||
|
||||
### Task 1: 为新增字段补失败测试
|
||||
|
||||
**Files:**
|
||||
- Create: `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingModelServicePersonalParamsTest.java`
|
||||
|
||||
- [ ] **Step 1: 编写字段与转换测试**
|
||||
|
||||
```java
|
||||
@Test
|
||||
void shouldContainLoanPurposeLoanTermAndLoanLoop() {
|
||||
assertThat(ModelInvokeDTO.class.getDeclaredField("loanTerm")).isNotNull();
|
||||
assertThat(ModelInvokeDTO.class.getDeclaredField("loanLoop")).isNotNull();
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
@Test
|
||||
void shouldConvertPersonalBooleanFlagsToZeroOne() {
|
||||
// 构造个人流程对象,断言模型请求中的 bizProof/loanLoop/collThirdParty 为 1/0
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行测试并确认先失败**
|
||||
|
||||
Run: `mvn -pl ruoyi-loan-pricing -Dtest=LoanPricingModelServicePersonalParamsTest test`
|
||||
|
||||
Expected: FAIL,提示字段不存在或转换逻辑未实现
|
||||
|
||||
- [ ] **Step 3: 保持测试只覆盖本次改动相关链路**
|
||||
|
||||
```java
|
||||
// 仅断言 PersonalLoanPricingCreateDTO / LoanPricingConverter / ModelInvokeDTO / LoanPricingModelService
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 增加最终模型请求参数断言**
|
||||
|
||||
```java
|
||||
// 断言 requestBody 包含 serialNum、orgCode、runType、custIsn、custType、custName、
|
||||
// idType、idNum、guarType、applyAmt、loanPurpose、loanTerm、bizProof、
|
||||
// loanLoop、collThirdParty、collType
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 再次运行测试确认失败原因稳定**
|
||||
|
||||
Run: `mvn -pl ruoyi-loan-pricing -Dtest=LoanPricingModelServicePersonalParamsTest test`
|
||||
|
||||
Expected: FAIL,失败点与新增字段缺失一致
|
||||
|
||||
- [ ] **Step 6: 提交**
|
||||
|
||||
```bash
|
||||
git add ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingModelServicePersonalParamsTest.java
|
||||
git commit -m "新增个人测算输入参数后端测试"
|
||||
```
|
||||
|
||||
### Task 2: 补齐个人创建 DTO 与流程映射
|
||||
|
||||
**Files:**
|
||||
- Modify: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/PersonalLoanPricingCreateDTO.java`
|
||||
- Modify: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/util/LoanPricingConverter.java`
|
||||
|
||||
- [ ] **Step 1: 在个人 DTO 中增加 `loanPurpose`**
|
||||
|
||||
```java
|
||||
@NotBlank(message = "贷款用途不能为空")
|
||||
@Pattern(regexp = "^(consumer|business)$", message = "贷款用途必须是 consumer 或 business")
|
||||
private String loanPurpose;
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 在个人 DTO 中增加 `loanTerm`**
|
||||
|
||||
```java
|
||||
@NotBlank(message = "借款期限不能为空")
|
||||
private String loanTerm;
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 在转换器中映射新增字段**
|
||||
|
||||
```java
|
||||
entity.setLoanPurpose(dto.getLoanPurpose());
|
||||
entity.setLoanTerm(dto.getLoanTerm());
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 运行相关测试确认 DTO 与映射通过**
|
||||
|
||||
Run: `mvn -pl ruoyi-loan-pricing -Dtest=LoanPricingModelServicePersonalParamsTest test`
|
||||
|
||||
Expected: 仍可能 FAIL,但失败点已推进到模型调用层
|
||||
|
||||
- [ ] **Step 5: 提交**
|
||||
|
||||
```bash
|
||||
git add ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/PersonalLoanPricingCreateDTO.java ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/util/LoanPricingConverter.java
|
||||
git commit -m "补齐个人测算创建参数字段"
|
||||
```
|
||||
|
||||
### Task 3: 补齐模型调用 DTO 与个人参数规范化
|
||||
|
||||
**Files:**
|
||||
- Modify: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/ModelInvokeDTO.java`
|
||||
- Modify: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingModelService.java`
|
||||
|
||||
- [ ] **Step 1: 在模型调用 DTO 中增加缺失字段**
|
||||
|
||||
```java
|
||||
private String loanTerm;
|
||||
private String loanLoop;
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 在个人模型调用前做 `0/1` 转换**
|
||||
|
||||
```java
|
||||
if ("个人".equals(loanPricingWorkflow.getCustType())) {
|
||||
modelInvokeDTO.setBizProof(toZeroOne(modelInvokeDTO.getBizProof()));
|
||||
modelInvokeDTO.setLoanLoop(toZeroOne(modelInvokeDTO.getLoanLoop()));
|
||||
modelInvokeDTO.setCollThirdParty(toZeroOne(modelInvokeDTO.getCollThirdParty()));
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 抽出最小辅助方法,避免散落重复逻辑**
|
||||
|
||||
```java
|
||||
private String toZeroOne(String value) {
|
||||
if ("true".equals(value) || "1".equals(value)) return "1";
|
||||
if ("false".equals(value) || "0".equals(value)) return "0";
|
||||
return value;
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 运行测试确认通过**
|
||||
|
||||
Run: `mvn -pl ruoyi-loan-pricing -Dtest=LoanPricingModelServicePersonalParamsTest test`
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: 提交**
|
||||
|
||||
```bash
|
||||
git add ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/ModelInvokeDTO.java ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingModelService.java
|
||||
git commit -m "规范个人测算模型调用参数"
|
||||
```
|
||||
|
||||
### Task 4: 后端联调与接口验证
|
||||
|
||||
**Files:**
|
||||
- Verify: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/controller/LoanPricingWorkflowController.java`
|
||||
- Verify: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImpl.java`
|
||||
|
||||
- [ ] **Step 1: 重新编译并重启后端进程**
|
||||
|
||||
Run: `mvn -pl ruoyi-admin -am package -DskipTests`
|
||||
|
||||
Expected: 打包成功,随后重启运行中的后端服务使最新代码生效
|
||||
|
||||
- [ ] **Step 2: 验证正常场景**
|
||||
|
||||
Run: 调用 `POST /loanPricing/workflow/create/personal`
|
||||
|
||||
Expected:
|
||||
- 返回创建成功
|
||||
- 请求体包含 `loanPurpose`、`loanTerm`
|
||||
- 模型请求中完整带出 16 个参数
|
||||
- 其中 `bizProof`、`loanLoop`、`collThirdParty` 为 `0/1`
|
||||
|
||||
- [ ] **Step 3: 验证必填缺失场景**
|
||||
|
||||
Run: 缺少 `loanPurpose` 或 `loanTerm` 分别调用接口
|
||||
|
||||
Expected: 返回参数校验失败
|
||||
|
||||
- [ ] **Step 4: 验证分支场景**
|
||||
|
||||
Run: 以不同开关组合调用接口
|
||||
|
||||
Expected:
|
||||
- `bizProof=true` -> 模型入参 `1`
|
||||
- `bizProof=false` -> 模型入参 `0`
|
||||
- `loanLoop=true/false` 与 `collThirdParty=true/false` 同理
|
||||
|
||||
- [ ] **Step 5: 验证结束后停止后端进程并提交**
|
||||
|
||||
```bash
|
||||
git add ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/PersonalLoanPricingCreateDTO.java ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/util/LoanPricingConverter.java ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/ModelInvokeDTO.java ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingModelService.java ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingModelServicePersonalParamsTest.java
|
||||
git commit -m "完成个人测算输入参数后端联调"
|
||||
```
|
||||
322
doc/2026-04-09-shangyu-retail-input-params-design.md
Normal file
322
doc/2026-04-09-shangyu-retail-input-params-design.md
Normal file
@@ -0,0 +1,322 @@
|
||||
# 上虞个人利率测算输入参数对齐设计文档
|
||||
|
||||
## 1. 背景
|
||||
|
||||
根据 [doc/上虞利率测算接口文档.xlsx](/Users/wkc/Desktop/loan-pricing/loan-pricing/doc/上虞利率测算接口文档.xlsx) 的 `入参` sheet,个人利率测算模型当前要求的输入参数为:
|
||||
|
||||
- `serialNum`
|
||||
- `orgCode`
|
||||
- `runType`
|
||||
- `custIsn`
|
||||
- `custType`
|
||||
- `custName`
|
||||
- `idType`
|
||||
- `idNum`
|
||||
- `guarType`
|
||||
- `applyAmt`
|
||||
- `loanPurpose`
|
||||
- `loanTerm`
|
||||
- `bizProof`
|
||||
- `loanLoop`
|
||||
- `collThirdParty`
|
||||
- `collType`
|
||||
|
||||
现有个人新增弹窗与模型调用链路未完全覆盖该输入集合:
|
||||
|
||||
- 页面缺少 `loanPurpose`
|
||||
- 页面缺少 `loanTerm`
|
||||
- `collType` 选项与 Excel 不一致
|
||||
- 页面开关字段当前提交的是 `true/false`
|
||||
- 模型调用 DTO 当前缺少 `loanTerm`、`loanLoop`
|
||||
|
||||
本次目标是按 Excel 的个人输入参数定义,对齐个人新增弹窗输入项和模型调用入参,不扩展到企业链路,不引入兜底或兼容分支。
|
||||
|
||||
## 2. 已确认范围
|
||||
|
||||
- 仅处理个人新增弹窗
|
||||
- 仅处理个人创建流程到模型调用的入参链路
|
||||
- 保持现有页面交互结构,不新增系统字段输入区
|
||||
- `loanTerm` 使用固定年限下拉,选项按 Excel 定义
|
||||
- 系统字段继续自动生成或默认赋值
|
||||
- 不修改企业新增弹窗
|
||||
- 不修改模型计算规则
|
||||
|
||||
## 3. 输入参数获取方式整理
|
||||
|
||||
### 3.1 系统自动带值
|
||||
|
||||
以下字段不放到新增弹窗中,由现有服务链路自动提供:
|
||||
|
||||
- `serialNum`
|
||||
- 由 `LoanPricingWorkflowServiceImpl#createLoanPricing` 按时间戳生成
|
||||
- `orgCode`
|
||||
- 由 `LoanPricingWorkflowServiceImpl#createLoanPricing` 在空值时补默认值
|
||||
- `runType`
|
||||
- 由 `LoanPricingWorkflowServiceImpl#createLoanPricing` 在空值时补默认值 `1`
|
||||
- `custType`
|
||||
- 由 `LoanPricingConverter#toEntity(PersonalLoanPricingCreateDTO)` 固定写为 `个人`
|
||||
|
||||
### 3.2 用户直接输入
|
||||
|
||||
- 文本输入:
|
||||
- `custIsn`
|
||||
- `custName`
|
||||
- `idNum`
|
||||
- `applyAmt`
|
||||
- 下拉选择:
|
||||
- `idType`
|
||||
- `guarType`
|
||||
- `loanPurpose`
|
||||
- `loanTerm`
|
||||
- `collType`
|
||||
- 开关选择:
|
||||
- `bizProof`
|
||||
- `loanLoop`
|
||||
- `collThirdParty`
|
||||
|
||||
## 4. 现状分析
|
||||
|
||||
### 4.1 前端现状
|
||||
|
||||
[PersonalCreateDialog.vue](/Users/wkc/Desktop/loan-pricing/loan-pricing/ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue) 当前已经提供:
|
||||
|
||||
- `custIsn`
|
||||
- `custName`
|
||||
- `idType`
|
||||
- `idNum`
|
||||
- `guarType`
|
||||
- `applyAmt`
|
||||
- `bizProof`
|
||||
- `loanLoop`
|
||||
- `collType`
|
||||
- `collThirdParty`
|
||||
|
||||
当前缺失或不一致点:
|
||||
|
||||
- 缺少 `loanPurpose`
|
||||
- 缺少 `loanTerm`
|
||||
- `collType` 选项为 `一线/一类/二类`,与 Excel 的 `一类/二类/三类` 不一致
|
||||
- 开关字段提交值为 `true/false`
|
||||
|
||||
### 4.2 后端现状
|
||||
|
||||
[PersonalLoanPricingCreateDTO.java](/Users/wkc/Desktop/loan-pricing/loan-pricing/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/PersonalLoanPricingCreateDTO.java) 当前未定义:
|
||||
|
||||
- `loanPurpose`
|
||||
- `loanTerm`
|
||||
|
||||
[LoanPricingConverter.java](/Users/wkc/Desktop/loan-pricing/loan-pricing/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/util/LoanPricingConverter.java) 当前未把以上字段映射到 `LoanPricingWorkflow`。
|
||||
|
||||
[ModelInvokeDTO.java](/Users/wkc/Desktop/loan-pricing/loan-pricing/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/ModelInvokeDTO.java) 当前未定义:
|
||||
|
||||
- `loanTerm`
|
||||
- `loanLoop`
|
||||
|
||||
这意味着即使页面补齐字段,当前模型调用也无法完整带出 Excel 要求的个人入参。
|
||||
|
||||
## 5. 方案对比
|
||||
|
||||
### 方案一:页面补齐用户输入,系统字段继续自动带值
|
||||
|
||||
做法:
|
||||
|
||||
- 在个人新增弹窗新增 `loanPurpose` 下拉
|
||||
- 在个人新增弹窗新增 `loanTerm` 固定年限下拉
|
||||
- 修正 `collType` 选项
|
||||
- 后端 DTO、转换器、模型调用 DTO 同步补字段
|
||||
- 模型调用前统一将开关字段转换为 Excel 要求的 `0/1`
|
||||
|
||||
优点:
|
||||
|
||||
- 与现有个人/企业创建方式一致
|
||||
- 改动最小
|
||||
- 页面输入、流程入库、模型调用职责边界清晰
|
||||
|
||||
缺点:
|
||||
|
||||
- 需要同时修改前后端
|
||||
|
||||
### 方案二:前端少改,后端在模型调用前兜底补参数
|
||||
|
||||
做法:
|
||||
|
||||
- 页面只补部分字段
|
||||
- 其余由后端按默认逻辑拼接模型参数
|
||||
|
||||
优点:
|
||||
|
||||
- 页面改动更少
|
||||
|
||||
缺点:
|
||||
|
||||
- 页面输入和真实模型入参不一致
|
||||
- 后续排查问题时难以定位参数来源
|
||||
- 不符合本次“按现有输入方式整理字段获取方式”的要求
|
||||
|
||||
### 方案三:Excel 全量字段全部暴露到弹窗
|
||||
|
||||
做法:
|
||||
|
||||
- 把 `serialNum`、`orgCode`、`runType`、`custType` 也作为页面字段给用户填写
|
||||
|
||||
优点:
|
||||
|
||||
- 页面可见字段与 Excel 完全一一对应
|
||||
|
||||
缺点:
|
||||
|
||||
- 与当前产品交互方式不一致
|
||||
- 增加误填风险
|
||||
- 不符合最短路径要求
|
||||
|
||||
## 6. 设计结论
|
||||
|
||||
采用方案一。
|
||||
|
||||
### 6.1 页面设计
|
||||
|
||||
个人新增弹窗保留现有分组结构,在“贷款信息”区域补齐:
|
||||
|
||||
- `loanPurpose`
|
||||
- 下拉选项:`consumer`、`business`
|
||||
- `loanTerm`
|
||||
- 固定年限下拉
|
||||
- 选项固定为 `1/2/3/4/5/6`
|
||||
|
||||
同时修正:
|
||||
|
||||
- `collType` 选项改为 `一类/二类/三类`
|
||||
|
||||
### 6.2 参数来源设计
|
||||
|
||||
- 系统带值:
|
||||
- `serialNum`
|
||||
- `orgCode`
|
||||
- `runType`
|
||||
- `custType`
|
||||
- 页面透传:
|
||||
- `custIsn`
|
||||
- `custName`
|
||||
- `idType`
|
||||
- `idNum`
|
||||
- `guarType`
|
||||
- `applyAmt`
|
||||
- `loanPurpose`
|
||||
- `loanTerm`
|
||||
- `collType`
|
||||
- 页面开关,经模型调用层转换:
|
||||
- `bizProof`
|
||||
- `loanLoop`
|
||||
- `collThirdParty`
|
||||
|
||||
### 6.3 链路设计
|
||||
|
||||
1. 前端提交个人创建请求时,补齐 `loanPurpose`、`loanTerm`
|
||||
2. 后端个人创建 DTO 接收新增字段
|
||||
3. 转换器将新增字段写入 `LoanPricingWorkflow`
|
||||
4. 模型调用 DTO 增加 `loanPurpose`、`loanTerm`、`loanLoop`
|
||||
5. `LoanPricingModelService` 在调用模型前,将个人链路中的开关字段转换为 `0/1`
|
||||
6. `ModelService` 继续以 `application/x-www-form-urlencoded` 方式调用模型接口
|
||||
|
||||
### 6.3.1 后端模型调用输入参数确认
|
||||
|
||||
后端最终发给模型的个人入参,按 Excel 要求确认为以下 16 个字段:
|
||||
|
||||
- `serialNum`
|
||||
- 来源:`LoanPricingWorkflowServiceImpl#createLoanPricing` 自动生成
|
||||
- `orgCode`
|
||||
- 来源:`LoanPricingWorkflowServiceImpl#createLoanPricing` 默认赋值
|
||||
- 当前代码值:`892000`
|
||||
- `runType`
|
||||
- 来源:`LoanPricingWorkflowServiceImpl#createLoanPricing`
|
||||
- 当前值:`1`
|
||||
- `custIsn`
|
||||
- 来源:页面输入,经个人创建 DTO 和转换器透传
|
||||
- `custType`
|
||||
- 来源:`LoanPricingConverter#toEntity(PersonalLoanPricingCreateDTO)`
|
||||
- 当前值:固定 `个人`
|
||||
- `custName`
|
||||
- 来源:页面输入
|
||||
- 说明:入库时加密,调用模型前解密
|
||||
- `idType`
|
||||
- 来源:页面输入
|
||||
- `idNum`
|
||||
- 来源:页面输入
|
||||
- 说明:入库时加密,调用模型前解密
|
||||
- `guarType`
|
||||
- 来源:页面输入
|
||||
- `applyAmt`
|
||||
- 来源:页面输入
|
||||
- `loanPurpose`
|
||||
- 来源:页面输入
|
||||
- 当前状态:需补齐到个人 DTO、流程实体映射和模型 DTO
|
||||
- `loanTerm`
|
||||
- 来源:页面输入
|
||||
- 当前状态:需补齐到个人 DTO、流程实体映射和模型 DTO
|
||||
- `bizProof`
|
||||
- 来源:页面开关
|
||||
- 模型值:调用模型前统一转换为 `0/1`
|
||||
- `loanLoop`
|
||||
- 来源:页面开关
|
||||
- 当前状态:需补齐到模型 DTO
|
||||
- 模型值:调用模型前统一转换为 `0/1`
|
||||
- `collThirdParty`
|
||||
- 来源:页面开关
|
||||
- 模型值:调用模型前统一转换为 `0/1`
|
||||
- `collType`
|
||||
- 来源:页面下拉
|
||||
- 模型值:按 `一类/二类/三类` 直接透传
|
||||
|
||||
后端调用方式确认如下:
|
||||
|
||||
- 参数载体:`ModelInvokeDTO`
|
||||
- 参数来源:`BeanUtils.copyProperties(loanPricingWorkflow, modelInvokeDTO)`
|
||||
- 请求构造:`ModelService#entityToMap`
|
||||
- 请求格式:`application/x-www-form-urlencoded`
|
||||
- 发送入口:`ModelService#invokeModel`
|
||||
|
||||
### 6.4 展示闭环
|
||||
|
||||
为保证输入项可在详情页回看,个人详情页同步补齐:
|
||||
|
||||
- `loanPurpose`
|
||||
|
||||
`loanTerm` 详情展示已存在,不需要新增区域。
|
||||
|
||||
## 7. 校验与错误处理
|
||||
|
||||
- 前端新增 `loanPurpose` 必选校验
|
||||
- 前端新增 `loanTerm` 必选校验
|
||||
- `loanTerm` 只能通过固定下拉选择,不提供自由输入
|
||||
- 后端 DTO 对 `loanPurpose`、`loanTerm` 增加必填约束
|
||||
- 保持现有创建失败与模型调用失败的错误提示方式
|
||||
- 不新增兼容逻辑、兜底逻辑或补丁式分支
|
||||
|
||||
## 8. 验证设计
|
||||
|
||||
- 前端源码断言个人新增弹窗已出现 `loanPurpose`、`loanTerm`
|
||||
- 前端源码断言 `loanTerm` 为固定下拉、`collType` 选项为 `一类/二类/三类`
|
||||
- 后端测试或源码断言 `PersonalLoanPricingCreateDTO`、`LoanPricingConverter`、`ModelInvokeDTO` 已补齐字段
|
||||
- 后端测试或日志断言调用模型前最终请求参数完整包含以上 16 个字段
|
||||
- 重启后端后,覆盖以下接口验证:
|
||||
- 正常场景:完整参数创建成功
|
||||
- 必填缺失场景:缺少 `loanPurpose` 或 `loanTerm` 被拦截
|
||||
- 分支场景:`bizProof`、`loanLoop`、`collThirdParty` 开关不同组合能正确转换为 `0/1`
|
||||
- 启动前端页面并通过浏览器检查:
|
||||
- 新增弹窗展示正确
|
||||
- 提交流程后详情页能回显 `loanPurpose`、`loanTerm`
|
||||
- 验证完成后停止本次启动的前后端进程
|
||||
|
||||
## 9. 已确认项
|
||||
|
||||
- `orgCode` 统一为 `892000`
|
||||
- `ModelInvokeDTO` 注释已统一为 `892000`
|
||||
- 数据库 `loan_pricing_workflow.org_code` 默认值已统一为 `892000`
|
||||
- 存量 `loan_pricing_workflow.org_code` 数据已通过迁移脚本统一为 `892000`
|
||||
|
||||
## 10. 非目标
|
||||
|
||||
- 不调整企业新增弹窗
|
||||
- 不修改企业模型调用参数
|
||||
- 不修改流程列表逻辑
|
||||
- 不改模型返回字段映射逻辑
|
||||
212
doc/2026-04-09-shangyu-retail-input-params-frontend-plan.md
Normal file
212
doc/2026-04-09-shangyu-retail-input-params-frontend-plan.md
Normal file
@@ -0,0 +1,212 @@
|
||||
# 上虞个人利率测算输入参数前端 Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 按 Excel 补齐个人新增弹窗输入项,确保页面提交字段与个人模型入参要求一致。
|
||||
|
||||
**Architecture:** 仅修改个人创建弹窗和个人详情页,沿用当前 Element UI 表单结构,不新增页面层级。通过前端源码断言覆盖新增字段、选项和值转换,确保页面输入与现有交互方式保持一致。
|
||||
|
||||
**Tech Stack:** Vue 2、Element UI、RuoYi 前端请求封装、Node 源码断言脚本
|
||||
|
||||
---
|
||||
|
||||
## 文件结构
|
||||
|
||||
- 修改: [ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue](/Users/wkc/Desktop/loan-pricing/loan-pricing/ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue)
|
||||
- 补齐 `loanPurpose`、`loanTerm`
|
||||
- 修正 `collType` 选项
|
||||
- 调整个人开关字段提交值
|
||||
- 修改: [ruoyi-ui/src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue](/Users/wkc/Desktop/loan-pricing/loan-pricing/ruoyi-ui/src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue)
|
||||
- 补齐 `loanPurpose` 展示
|
||||
- 如有需要,扩展布尔格式化兼容 `0/1`
|
||||
- 新增: [ruoyi-ui/tests/personal-create-input-params.test.js](/Users/wkc/Desktop/loan-pricing/loan-pricing/ruoyi-ui/tests/personal-create-input-params.test.js)
|
||||
- 断言新增弹窗字段、选项和值转换逻辑
|
||||
- 修改: [ruoyi-ui/package.json](/Users/wkc/Desktop/loan-pricing/loan-pricing/ruoyi-ui/package.json)
|
||||
- 新增针对本次改动的测试命令
|
||||
|
||||
### Task 1: 为个人新增弹窗补失败断言
|
||||
|
||||
**Files:**
|
||||
- Create: `ruoyi-ui/tests/personal-create-input-params.test.js`
|
||||
- Modify: `ruoyi-ui/package.json`
|
||||
|
||||
- [ ] **Step 1: 编写失败断言脚本**
|
||||
|
||||
```js
|
||||
const requiredFields = ['form.loanPurpose', 'form.loanTerm']
|
||||
const requiredOptions = ['value="consumer"', 'value="business"', 'label="一类"', 'label="二类"', 'label="三类"']
|
||||
const requiredConversions = [
|
||||
"bizProof: this.form.bizProof ? '1' : '0'",
|
||||
"loanLoop: this.form.loanLoop ? '1' : '0'",
|
||||
"collThirdParty: this.form.collThirdParty ? '1' : '0'"
|
||||
]
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行断言并确认先失败**
|
||||
|
||||
Run: `npm --prefix ruoyi-ui run test:personal-create-input-params`
|
||||
|
||||
Expected: FAIL,提示缺少 `loanPurpose` 或 `loanTerm` 或值转换未按 `1/0`
|
||||
|
||||
- [ ] **Step 3: 在 `package.json` 注册测试命令**
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"test:personal-create-input-params": "node tests/personal-create-input-params.test.js"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 再次运行断言并确认仍处于失败态**
|
||||
|
||||
Run: `npm --prefix ruoyi-ui run test:personal-create-input-params`
|
||||
|
||||
Expected: FAIL,失败原因与新增字段缺失一致
|
||||
|
||||
- [ ] **Step 5: 提交**
|
||||
|
||||
```bash
|
||||
git add ruoyi-ui/tests/personal-create-input-params.test.js ruoyi-ui/package.json
|
||||
git commit -m "新增个人测算输入参数前端断言"
|
||||
```
|
||||
|
||||
### Task 2: 补齐个人新增弹窗字段与选项
|
||||
|
||||
**Files:**
|
||||
- Modify: `ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue`
|
||||
|
||||
- [ ] **Step 1: 增加 `loanPurpose` 表单项**
|
||||
|
||||
```vue
|
||||
<el-form-item label="贷款用途" prop="loanPurpose">
|
||||
<el-select v-model="form.loanPurpose" placeholder="请选择贷款用途" style="width: 100%">
|
||||
<el-option label="消费" value="consumer" />
|
||||
<el-option label="经营" value="business" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 增加 `loanTerm` 固定年限下拉**
|
||||
|
||||
```vue
|
||||
<el-form-item label="借款期限(年)" prop="loanTerm">
|
||||
<el-select v-model="form.loanTerm" placeholder="请选择借款期限" style="width: 100%">
|
||||
<el-option v-for="item in ['1', '2', '3', '4', '5', '6']" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 修正 `collType` 选项为 Excel 定义**
|
||||
|
||||
```vue
|
||||
<el-option label="一类" value="一类" />
|
||||
<el-option label="二类" value="二类" />
|
||||
<el-option label="三类" value="三类" />
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 为新增字段补表单状态与校验**
|
||||
|
||||
```js
|
||||
form: {
|
||||
loanPurpose: undefined,
|
||||
loanTerm: undefined
|
||||
},
|
||||
rules: {
|
||||
loanPurpose: [{ required: true, message: '请选择贷款用途', trigger: 'change' }],
|
||||
loanTerm: [{ required: true, message: '请选择借款期限', trigger: 'change' }]
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 提交**
|
||||
|
||||
```bash
|
||||
git add ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue
|
||||
git commit -m "补齐个人新增弹窗输入字段"
|
||||
```
|
||||
|
||||
### Task 3: 调整前端提交值与详情展示
|
||||
|
||||
**Files:**
|
||||
- Modify: `ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue`
|
||||
- Modify: `ruoyi-ui/src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue`
|
||||
|
||||
- [ ] **Step 1: 在提交逻辑中改为 `1/0` 值**
|
||||
|
||||
```js
|
||||
const data = {
|
||||
...this.form,
|
||||
bizProof: this.form.bizProof ? '1' : '0',
|
||||
loanLoop: this.form.loanLoop ? '1' : '0',
|
||||
collThirdParty: this.form.collThirdParty ? '1' : '0'
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 在详情页补齐 `loanPurpose` 展示**
|
||||
|
||||
```vue
|
||||
<el-descriptions-item label="贷款用途">{{ detailData.loanPurpose || '-' }}</el-descriptions-item>
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 兼容详情页 `0/1` 布尔展示**
|
||||
|
||||
```js
|
||||
if (value === 'true' || value === true || value === '1' || value === 1) return '是'
|
||||
if (value === 'false' || value === false || value === '0' || value === 0) return '否'
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 运行前端源码断言并确认通过**
|
||||
|
||||
Run: `npm --prefix ruoyi-ui run test:personal-create-input-params`
|
||||
|
||||
Expected: PASS,输出断言通过信息
|
||||
|
||||
- [ ] **Step 5: 提交**
|
||||
|
||||
```bash
|
||||
git add ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue ruoyi-ui/src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue
|
||||
git commit -m "调整个人测算前端提交与展示"
|
||||
```
|
||||
|
||||
### Task 4: 页面联调与回归验证
|
||||
|
||||
**Files:**
|
||||
- Verify: `ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue`
|
||||
- Verify: `ruoyi-ui/src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue`
|
||||
|
||||
- [ ] **Step 1: 启动前端开发服务**
|
||||
|
||||
Run: `npm --prefix ruoyi-ui run dev`
|
||||
|
||||
Expected: 成功启动并输出本地访问地址
|
||||
|
||||
- [ ] **Step 2: 打开流程页面验证新增弹窗**
|
||||
|
||||
Run: 在浏览器中进入 `/loanPricing/workflow`
|
||||
|
||||
Expected:
|
||||
- 出现 `贷款用途`
|
||||
- 出现 `借款期限(年)` 固定下拉
|
||||
- `抵质押类型` 选项为 `一类/二类/三类`
|
||||
|
||||
- [ ] **Step 3: 结合后端联调创建个人流程**
|
||||
|
||||
Run: 在页面中填写完整参数并提交
|
||||
|
||||
Expected: 创建成功,不出现参数缺失报错
|
||||
|
||||
- [ ] **Step 4: 打开详情页验证回显**
|
||||
|
||||
Run: 打开刚创建的个人流程详情
|
||||
|
||||
Expected:
|
||||
- 页面展示 `贷款用途`
|
||||
- 页面展示 `借款期限`
|
||||
- 开关字段显示为“是/否”
|
||||
|
||||
- [ ] **Step 5: 验证结束后停止前端进程并提交**
|
||||
|
||||
```bash
|
||||
git add ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue ruoyi-ui/src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue ruoyi-ui/tests/personal-create-input-params.test.js ruoyi-ui/package.json
|
||||
git commit -m "完成个人测算输入参数前端联调"
|
||||
```
|
||||
43
doc/2026-04-13-local-tomcat-remote-tongweb-backend-plan.md
Normal file
43
doc/2026-04-13-local-tomcat-remote-tongweb-backend-plan.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# 本地 Tomcat 与 TongWeb 打包并存后端实施计划
|
||||
|
||||
## 目标
|
||||
|
||||
- 恢复本地 `jar + 内嵌 Tomcat` 启动链路
|
||||
- 保留服务器 `war + TongWeb` 部署链路
|
||||
- 一次 `mvn package` 同时产出 `ruoyi-admin.jar` 和 `ruoyi-admin.war`
|
||||
|
||||
## 改动范围
|
||||
|
||||
- Maven 打包配置
|
||||
- 后端启动与部署脚本
|
||||
- 脚本测试
|
||||
- 相关运行文档和实施记录
|
||||
|
||||
## 实施步骤
|
||||
|
||||
1. 先修改脚本测试,重新定义目标行为
|
||||
- 本地测试脚本期望 `restart_java_backend.sh` 使用 `java -jar`
|
||||
- 生产测试脚本继续期望 TongWeb 使用 `war`
|
||||
2. 调整 Maven 打包配置
|
||||
- `ruoyi-admin` 恢复主产物 `jar`
|
||||
- 增加附加 `war` 产物
|
||||
- 恢复本地运行所需的内嵌 Tomcat 依赖
|
||||
3. 调整脚本
|
||||
- 本地脚本改回管理 `ruoyi-admin.jar`
|
||||
- 生产脚本继续管理 `ruoyi-admin.war`
|
||||
4. 更新文档
|
||||
- 更新运行说明
|
||||
- 新增本次实施记录
|
||||
5. 执行验证
|
||||
|
||||
## 验证要求
|
||||
|
||||
- `sh bin/restart_java_backend_test.sh`
|
||||
- `sh bin/prod/restart_java_test.sh`
|
||||
- `sh bin/prod/deploy_from_package_test.sh`
|
||||
- `sh -n bin/restart_java_backend.sh`
|
||||
- `sh -n bin/prod/restart_java.sh`
|
||||
- `sh -n bin/prod/deploy_from_package.sh`
|
||||
- `mvn -pl ruoyi-admin -am package -DskipTests`
|
||||
- 确认 `ruoyi-admin/target/ruoyi-admin.jar`
|
||||
- 确认 `ruoyi-admin/target/ruoyi-admin.war`
|
||||
147
doc/2026-04-13-local-tomcat-remote-tongweb-design.md
Normal file
147
doc/2026-04-13-local-tomcat-remote-tongweb-design.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# 本地 Tomcat 运行与 TongWeb 打包并存设计
|
||||
|
||||
## 背景
|
||||
|
||||
当前项目已经被调整为统一的 TongWeb `war` 交付模式,这会导致本地开发时也必须围绕 TongWeb 组织启动流程,不符合当前开发诉求。
|
||||
|
||||
本次目标是同时保留两条链路:
|
||||
|
||||
- 本地开发运行继续使用内嵌 Tomcat
|
||||
- 打包交付继续支持服务器上的 TongWeb
|
||||
|
||||
并且要求一次 `mvn package` 同时产出本地运行所需的 `jar` 和服务器部署所需的 `war`。
|
||||
|
||||
## 目标
|
||||
|
||||
- 保留 `IDEA`、`mvn spring-boot:run`、本地脚本直启后端的开发体验
|
||||
- 保留面向 TongWeb 的 `war` 交付方式
|
||||
- `mvn package` 后同时得到 `ruoyi-admin.jar` 与 `ruoyi-admin.war`
|
||||
- 本地不强依赖安装 TongWeb
|
||||
- 服务器部署脚本继续只消费 `war`
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不新增第二个后端启动模块
|
||||
- 不拆分额外的部署工程
|
||||
- 不修改前端构建方式
|
||||
- 不引入“兼容模式”“降级模式”之类额外分支逻辑
|
||||
|
||||
## 设计方案
|
||||
|
||||
### 1. 构建产物设计
|
||||
|
||||
`ruoyi-admin` 恢复为以 `jar` 为主产物的 Spring Boot 应用,用于本地开发运行。
|
||||
|
||||
在同一个 Maven 模块中补充 `war` 打包步骤,使一次 `mvn package` 后同时得到:
|
||||
|
||||
- `ruoyi-admin/target/ruoyi-admin.jar`
|
||||
- `ruoyi-admin/target/ruoyi-admin.war`
|
||||
|
||||
这样本地和服务器都从同一套源码构建,但消费不同产物:
|
||||
|
||||
- 本地消费 `jar`
|
||||
- 服务器消费 `war`
|
||||
|
||||
### 2. 依赖设计
|
||||
|
||||
为了保证本地可继续走内嵌 Tomcat:
|
||||
|
||||
- 恢复 Web 模块中的内嵌 Tomcat 依赖链
|
||||
- 保持 `spring-boot:run` 与 `java -jar` 均可正常工作
|
||||
|
||||
为了保证 TongWeb 外部容器部署:
|
||||
|
||||
- 打出的 `war` 不能把容器自身实现错误打包成部署冲突形式
|
||||
- `Servlet API` 继续按外部容器提供的思路处理
|
||||
|
||||
本质上,本地运行和 TongWeb 部署共享同一套业务代码,但运行容器不同。
|
||||
|
||||
### 3. 启动脚本设计
|
||||
|
||||
#### 本地脚本
|
||||
|
||||
`bin/restart_java_backend.sh` 恢复为本地开发脚本:
|
||||
|
||||
- 执行 Maven 打包
|
||||
- 使用 `ruoyi-admin.jar`
|
||||
- 通过 `java -jar` 管理本地后端进程
|
||||
|
||||
这条链路不再依赖 `TONGWEB_HOME`。
|
||||
|
||||
#### 生产脚本
|
||||
|
||||
以下脚本保持 TongWeb 交付模型:
|
||||
|
||||
- `bin/prod/restart_java.sh`
|
||||
- `bin/prod/deploy_from_package.sh`
|
||||
- `bin/prod/deploy_release.sh`
|
||||
|
||||
它们继续只处理 `ruoyi-admin.war`,不回退到 `jar`。
|
||||
|
||||
### 4. 本地与服务器联调设计
|
||||
|
||||
本地开发时不要求本机安装 TongWeb。
|
||||
|
||||
如果需要验证 TongWeb 运行环境,只通过两种方式完成:
|
||||
|
||||
- 打包后部署到服务器 TongWeb 验证
|
||||
- 本地系统直接调用服务器上已部署的 TongWeb 地址联调
|
||||
|
||||
这意味着:
|
||||
|
||||
- 本地开发链路只围绕 `jar + Tomcat`
|
||||
- 服务器部署链路只围绕 `war + TongWeb`
|
||||
|
||||
## 验证方案
|
||||
|
||||
### 构建验证
|
||||
|
||||
执行:
|
||||
|
||||
```sh
|
||||
mvn -pl ruoyi-admin -am package -DskipTests
|
||||
```
|
||||
|
||||
确认同时存在:
|
||||
|
||||
- `ruoyi-admin/target/ruoyi-admin.jar`
|
||||
- `ruoyi-admin/target/ruoyi-admin.war`
|
||||
|
||||
### 本地运行验证
|
||||
|
||||
执行:
|
||||
|
||||
```sh
|
||||
sh bin/restart_java_backend.sh restart
|
||||
```
|
||||
|
||||
确认本地以 `java -jar` 正常运行。
|
||||
|
||||
### TongWeb 脚本验证
|
||||
|
||||
执行:
|
||||
|
||||
```sh
|
||||
sh bin/prod/restart_java_test.sh
|
||||
sh bin/prod/deploy_from_package_test.sh
|
||||
```
|
||||
|
||||
确认 TongWeb 侧仍围绕 `war` 工作。
|
||||
|
||||
## 影响范围
|
||||
|
||||
- `ruoyi-admin` Maven 打包配置
|
||||
- Web 相关模块的容器依赖声明
|
||||
- 本地后端脚本
|
||||
- 生产 TongWeb 脚本
|
||||
- 运行文档与实施记录
|
||||
|
||||
## 结论
|
||||
|
||||
本方案采用最短路径实现“双产物、双运行链路并存”:
|
||||
|
||||
- 本地运行继续走内嵌 Tomcat
|
||||
- 服务器部署继续走 TongWeb
|
||||
- 一次打包同时产出 `jar` 与 `war`
|
||||
|
||||
在不新增模块、不扩散复杂度的前提下,满足开发与部署两端的实际需要。
|
||||
39
doc/2026-04-13-tongweb-replace-tomcat-backend-plan.md
Normal file
39
doc/2026-04-13-tongweb-replace-tomcat-backend-plan.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# 东方通替换 Tomcat 后端实施计划
|
||||
|
||||
## 目标
|
||||
|
||||
- 将后端交付形态从内嵌 Tomcat 的 `jar` 调整为部署到东方通 TongWeb 的 `war`
|
||||
- 清理当前发布链路中围绕 `java -jar` / `ruoyi-admin.jar` 的脚本约定
|
||||
- 保持现有前端发布方式和 Nginx 入口不变,后端仍沿用 `63310` 作为反向代理目标端口
|
||||
|
||||
## 改动范围
|
||||
|
||||
- Maven 构建
|
||||
- 调整 `ruoyi-admin` 打包类型为 `war`
|
||||
- 去除模块链路中的嵌入式 Tomcat 打包依赖
|
||||
- 明确 Servlet API 由外部容器提供
|
||||
- 部署脚本
|
||||
- 将生产部署脚本中的后端产物从 `ruoyi-admin.jar` 切换为 `ruoyi-admin.war`
|
||||
- 将生产重启脚本从 Java 进程启停改为 TongWeb 容器启停与 `war` 发布
|
||||
- 调整本地后端重启脚本,使其面向 TongWeb 进行构建和部署
|
||||
- 运行文档
|
||||
- 更新本地安装手册中的后端环境说明,改为 TongWeb
|
||||
- 新增本次改动实施记录
|
||||
|
||||
## 实施步骤
|
||||
|
||||
1. 先修改现有脚本测试,明确新的 `war + TongWeb` 约束
|
||||
2. 调整 Maven 配置,产出 `ruoyi-admin.war`
|
||||
3. 修改生产部署脚本和本地重启脚本
|
||||
4. 更新运行文档与实施记录
|
||||
5. 执行脚本测试、语法校验和 Maven 打包验证
|
||||
|
||||
## 验证要求
|
||||
|
||||
- `mvn -pl ruoyi-admin -am clean package -DskipTests` 成功,且产物为 `ruoyi-admin.war`
|
||||
- `sh bin/prod/restart_java_test.sh` 成功
|
||||
- `sh bin/prod/deploy_from_package_test.sh` 成功
|
||||
- `sh bin/restart_java_backend_test.sh` 成功
|
||||
- `sh -n bin/prod/restart_java.sh`
|
||||
- `sh -n bin/prod/deploy_from_package.sh`
|
||||
- `sh -n bin/restart_java_backend.sh`
|
||||
41
doc/2026-04-14-ruoyi-vue-springboot2-backend-plan.md
Normal file
41
doc/2026-04-14-ruoyi-vue-springboot2-backend-plan.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# RuoYi-Vue springboot2 后端迁移实施计划
|
||||
|
||||
## 目标
|
||||
|
||||
以上游 `RuoYi-Vue/springboot2` 为后端框架基线,将当前项目的后端框架层整体回退并重对齐到 Spring Boot 2 / Java 8,同时恢复 `ruoyi-loan-pricing` 业务模块和管理端业务接入配置。
|
||||
|
||||
## 范围
|
||||
|
||||
- 根 `pom.xml`
|
||||
- `ruoyi-admin`
|
||||
- `ruoyi-common`
|
||||
- `ruoyi-framework`
|
||||
- `ruoyi-generator`
|
||||
- `ruoyi-quartz`
|
||||
- `ruoyi-system`
|
||||
- `ruoyi-loan-pricing`
|
||||
- `sql`
|
||||
|
||||
## 执行步骤
|
||||
|
||||
1. 备份当前后端业务模块与业务配置
|
||||
2. 用上游 `springboot2` 覆盖根 POM 和基础后端模块
|
||||
3. 恢复 `ruoyi-loan-pricing` 模块目录
|
||||
4. 在根 POM 与 `ruoyi-admin/pom.xml` 中重新挂载 `ruoyi-loan-pricing`
|
||||
5. 恢复 `ruoyi-admin/src/main/resources` 中的 `loan-pricing` 业务配置
|
||||
6. 检查并修正 `ruoyi-loan-pricing` 中不兼容 Spring Boot 2 的依赖、注解和包引用
|
||||
7. 校正 Mapper、资源文件和测试依赖,保证模块能参与 Maven 聚合构建
|
||||
8. 保留并整理业务 SQL 脚本
|
||||
9. 在 Java 8 环境下执行后端编译与关键测试
|
||||
|
||||
## 验证要求
|
||||
|
||||
- `mvn -pl ruoyi-admin -am test` 至少能够完成依赖解析和关键模块测试
|
||||
- `mvn -pl ruoyi-admin -am package -DskipTests` 能通过
|
||||
- `ruoyi-loan-pricing` 模块可被 `ruoyi-admin` 正常引用
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 不保留 Spring Boot 3 / Java 17 双配置
|
||||
- 不引入兼容层或过渡层
|
||||
- 若业务模块使用了 Boot 3 专属依赖,直接改为 Boot 2 可运行实现
|
||||
37
doc/2026-04-14-ruoyi-vue-springboot2-frontend-plan.md
Normal file
37
doc/2026-04-14-ruoyi-vue-springboot2-frontend-plan.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# RuoYi-Vue springboot2 前端迁移实施计划
|
||||
|
||||
## 目标
|
||||
|
||||
以上游 `RuoYi-Vue/springboot2` 为前端基线,将当前项目前端整体回退并重对齐到上游 `ruoyi-ui`,然后恢复 `loanPricing` 业务页面、接口调用、路由与相关依赖。
|
||||
|
||||
## 范围
|
||||
|
||||
- `ruoyi-ui/package.json`
|
||||
- `ruoyi-ui/src`
|
||||
- `ruoyi-ui/public`
|
||||
- `ruoyi-ui/build`
|
||||
- `ruoyi-ui/tests`
|
||||
|
||||
## 执行步骤
|
||||
|
||||
1. 备份当前 `loanPricing` 页面、接口文件、路由改动和业务测试脚本
|
||||
2. 用上游 `springboot2` 的 `ruoyi-ui` 覆盖当前前端框架层
|
||||
3. 恢复 `src/views/loanPricing` 页面目录
|
||||
4. 恢复 `src/api/loanPricing` 接口文件
|
||||
5. 将业务路由重新挂回 `src/router/index.js`
|
||||
6. 恢复业务所需的前端依赖与测试脚本
|
||||
7. 用 `nvm` 切换到合适的 Node 版本后重新安装依赖
|
||||
8. 执行前端构建与页面联调验证
|
||||
|
||||
## 验证要求
|
||||
|
||||
- `npm install` 成功
|
||||
- `npm run build:prod` 成功
|
||||
- `loanPricing` 页面路由可访问
|
||||
- 页面基础交互和接口调用链路未丢失
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 前端直接以 `springboot2` 上游为准,不保留当前非业务性的历史前端定制
|
||||
- Node 版本必须通过 `nvm` 控制
|
||||
- 测试完成后要关闭前端调试进程
|
||||
120
doc/2026-04-14-ruoyi-vue-springboot2-migration-design.md
Normal file
120
doc/2026-04-14-ruoyi-vue-springboot2-migration-design.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# RuoYi-Vue springboot2 基线迁移设计
|
||||
|
||||
## 1. 目标
|
||||
|
||||
本次迁移以上游 `https://gitee.com/y_project/RuoYi-Vue/tree/springboot2` 为唯一框架基线,先将当前仓库整体回退并重对齐到该基线,再迁回现有业务模块与业务页面,最终形成一个“框架层跟随上游、业务层保留现状”的项目结构。
|
||||
|
||||
本次迁移不采用兼容层、补丁层或双栈并存方案,不保留 Spring Boot 3 / Java 17 的框架实现。
|
||||
|
||||
## 2. 现状与目标差异
|
||||
|
||||
当前仓库已经是 RuoYi 多模块工程,但后端已升级到 `Spring Boot 3.5.x`、`Java 17`,并引入了以下业务定制:
|
||||
|
||||
- 后端业务模块:`ruoyi-loan-pricing`
|
||||
- 前端业务页面:`ruoyi-ui/src/views/loanPricing`
|
||||
- 前端业务接口:`ruoyi-ui/src/api/loanPricing`
|
||||
- 管理端业务接入:`ruoyi-admin` 中的业务依赖与配置
|
||||
- 业务 SQL:`sql/loan_pricing_*`、`sql/model_*`、`sql/loan_pricing_menu.sql`
|
||||
|
||||
目标上游 `springboot2` 分支采用:
|
||||
|
||||
- `RuoYi-Vue 3.9.2`
|
||||
- `Spring Boot 2.5.15`
|
||||
- `Java 8`
|
||||
- `Vue 2 + Element UI`
|
||||
|
||||
因此本次迁移的本质是:先将框架层彻底切回 Spring Boot 2 基线,再把利率定价业务重新挂载到新的基线上。
|
||||
|
||||
## 3. 迁移范围
|
||||
|
||||
### 3.1 框架层
|
||||
|
||||
以下内容以上游 `springboot2` 版本为准:
|
||||
|
||||
- 根目录框架文件与脚本
|
||||
- 根 `pom.xml`
|
||||
- `ruoyi-admin`
|
||||
- `ruoyi-common`
|
||||
- `ruoyi-framework`
|
||||
- `ruoyi-generator`
|
||||
- `ruoyi-quartz`
|
||||
- `ruoyi-system`
|
||||
- `ruoyi-ui`
|
||||
- 上游自带 `sql` 基础脚本
|
||||
|
||||
### 3.2 业务层
|
||||
|
||||
以下内容需要从当前仓库迁回到新基线:
|
||||
|
||||
- `ruoyi-loan-pricing` 全模块
|
||||
- `ruoyi-admin` 中与 `loan-pricing` 相关的业务配置、业务依赖
|
||||
- `ruoyi-ui/src/views/loanPricing` 页面
|
||||
- `ruoyi-ui/src/api/loanPricing` 接口文件
|
||||
- `ruoyi-ui/src/router/index.js` 中的业务路由
|
||||
- 业务 SQL、部署脚本、项目文档
|
||||
|
||||
## 4. 实施策略
|
||||
|
||||
### 4.1 基线覆盖策略
|
||||
|
||||
采用“上游覆盖 + 业务回贴”模式:
|
||||
|
||||
1. 先备份当前业务目录与业务配置
|
||||
2. 将上游 `springboot2` 内容覆盖到当前仓库
|
||||
3. 恢复业务模块、业务页面、业务配置和业务 SQL
|
||||
4. 处理 Spring Boot 2 下的编译和运行差异
|
||||
|
||||
### 4.2 后端回贴策略
|
||||
|
||||
后端只保留一套 Spring Boot 2 实现,不额外保留 Spring Boot 3 兼容写法。若 `ruoyi-loan-pricing` 内存在 Boot 3 / Jakarta / SpringDoc 相关依赖或 API,则直接改回 Boot 2 可运行写法。
|
||||
|
||||
### 4.3 前端回贴策略
|
||||
|
||||
前端以 `springboot2` 上游 `ruoyi-ui` 为基础,回贴 `loanPricing` 页面、接口调用、路由和必要依赖;不保留与当前业务无关的历史定制。
|
||||
|
||||
## 5. 风险点与处理原则
|
||||
|
||||
### 5.1 框架依赖回退风险
|
||||
|
||||
风险:
|
||||
|
||||
- `springdoc`、`jakarta.*`、Boot 3 专用依赖不兼容 Boot 2
|
||||
- 测试依赖、插件版本、JDK 版本需要一并回退
|
||||
|
||||
处理原则:
|
||||
|
||||
- 以 Boot 2 上游依赖为准
|
||||
- 业务模块仅保留完成业务所必需的依赖
|
||||
|
||||
### 5.2 业务接入点遗漏风险
|
||||
|
||||
风险:
|
||||
|
||||
- `ruoyi-admin` 配置遗漏
|
||||
- 前端路由、菜单、接口路径遗漏
|
||||
- SQL 脚本与权限菜单脚本遗漏
|
||||
|
||||
处理原则:
|
||||
|
||||
- 逐类枚举迁移对象
|
||||
- 迁移后通过编译、页面访问、接口调用进行闭环验证
|
||||
|
||||
## 6. 验证标准
|
||||
|
||||
迁移完成后至少满足以下条件:
|
||||
|
||||
- Maven 多模块在 Spring Boot 2 / Java 8 环境下可编译
|
||||
- `ruoyi-admin` 可启动
|
||||
- `ruoyi-ui` 在指定 Node 版本下可安装并构建
|
||||
- `loanPricing` 页面路由可访问
|
||||
- 利率定价相关接口类与 Mapper 可通过编译
|
||||
- 业务 SQL 与菜单脚本仍保留在仓库内
|
||||
|
||||
## 7. 产出物
|
||||
|
||||
本次任务最终需产出:
|
||||
|
||||
- 本设计文档
|
||||
- 后端实施计划文档
|
||||
- 前端实施计划文档
|
||||
- 迁移实施记录文档
|
||||
@@ -32,10 +32,12 @@
|
||||
| idNum | String | 否 | 证件号码 |
|
||||
| guarType | String | 是 | 担保方式,可选值: 信用/保证/抵押/质押 |
|
||||
| applyAmt | String | 是 | 申请金额,单位: 元 |
|
||||
| bizProof | String | 否 | 是否有经营佐证,值: true/false |
|
||||
| loanLoop | String | 否 | 循环功能,值: true/false |
|
||||
| collType | String | 否 | 抵质押类型,可选值: 一线/一类/二类 |
|
||||
| collThirdParty | String | 否 | 抵质押物是否三方所有,值: true/false |
|
||||
| loanPurpose | String | 是 | 贷款用途,可选值: consumer/business |
|
||||
| loanTerm | String | 是 | 借款期限(年),固定下拉选项按模型文档配置 |
|
||||
| bizProof | String | 否 | 是否有经营佐证,值: 0/1 |
|
||||
| loanLoop | String | 否 | 循环功能,值: 0/1 |
|
||||
| collType | String | 否 | 抵质押类型,可选值: 一类/二类/三类 |
|
||||
| collThirdParty | String | 否 | 抵质押物是否三方所有,值: 0/1 |
|
||||
|
||||
**请求示例:**
|
||||
|
||||
@@ -47,10 +49,12 @@
|
||||
"idNum": "110101199001011234",
|
||||
"guarType": "抵押",
|
||||
"applyAmt": "500000",
|
||||
"bizProof": "true",
|
||||
"loanLoop": "false",
|
||||
"loanPurpose": "business",
|
||||
"loanTerm": "3",
|
||||
"bizProof": "1",
|
||||
"loanLoop": "0",
|
||||
"collType": "一类",
|
||||
"collThirdParty": "false"
|
||||
"collThirdParty": "0"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -64,12 +68,14 @@
|
||||
"id": 1,
|
||||
"modelOutputId": 100,
|
||||
"serialNum": "20250119143025123",
|
||||
"orgCode": "931000",
|
||||
"orgCode": "892000",
|
||||
"runType": "1",
|
||||
"custIsn": "CUST001",
|
||||
"custType": "个人",
|
||||
"guarType": "抵押",
|
||||
"applyAmt": "500000",
|
||||
"loanPurpose": "business",
|
||||
"loanTerm": "3",
|
||||
"custName": "张三",
|
||||
"idType": "身份证",
|
||||
"createTime": "2025-01-19 14:30:25",
|
||||
@@ -136,7 +142,7 @@
|
||||
"id": 2,
|
||||
"modelOutputId": 101,
|
||||
"serialNum": "20250119143125456",
|
||||
"orgCode": "931000",
|
||||
"orgCode": "892000",
|
||||
"runType": "1",
|
||||
"custIsn": "CORP001",
|
||||
"custType": "企业",
|
||||
@@ -189,7 +195,7 @@ GET /loanPricing/workflow/list?pageNum=1&pageSize=10&custName=科技
|
||||
"id": 1,
|
||||
"modelOutputId": 100,
|
||||
"serialNum": "20250119143025123",
|
||||
"orgCode": "931000",
|
||||
"orgCode": "892000",
|
||||
"custIsn": "CUST001",
|
||||
"custType": "企业",
|
||||
"guarType": "抵押",
|
||||
@@ -240,7 +246,7 @@ GET /loanPricing/workflow/20250119143025123
|
||||
"id": 1,
|
||||
"modelOutputId": 100,
|
||||
"serialNum": "20250119143025123",
|
||||
"orgCode": "931000",
|
||||
"orgCode": "892000",
|
||||
"runType": "1",
|
||||
"custIsn": "CUST001",
|
||||
"custType": "企业",
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
# 2026-04-09 默认切换 Node 25 以支持 Playwright 实施记录
|
||||
|
||||
## 变更内容
|
||||
- 将 `nvm` 默认别名从 `14` 调整为 `25`
|
||||
- 清理了本次验证过程中残留的 Playwright 浏览器安装进程
|
||||
|
||||
## 执行命令
|
||||
- `zsh -lic 'nvm alias default 25'`
|
||||
|
||||
## 变更结果
|
||||
- 新开的交互式 `zsh` 默认 Node 版本变为 `v25.9.0`
|
||||
- 默认 npm/npx 版本变为 `11.12.1`
|
||||
|
||||
## 验证结果
|
||||
- `zsh -lic 'node -v && npm -v && npx -v && nvm current && nvm alias default'`
|
||||
- `node v25.9.0`
|
||||
- `npm 11.12.1`
|
||||
- `npx 11.12.1`
|
||||
- `nvm current = v25.9.0`
|
||||
- `default -> 25 (-> v25.9.0 *)`
|
||||
- `zsh -lic '... playwright_cli.sh --help'`
|
||||
- Playwright CLI 帮助输出正常
|
||||
- `zsh -lic '... playwright_cli.sh --session verify-default-25 open https://example.com && snapshot && close && list'`
|
||||
- 页面成功打开
|
||||
- 页面标题为 `Example Domain`
|
||||
- 快照成功输出
|
||||
- 浏览器关闭后 `list` 返回 `(no browsers)`
|
||||
|
||||
## 结论
|
||||
- 默认 shell 环境下已可直接使用 Playwright,无需再先手动执行 `nvm use 25`
|
||||
@@ -0,0 +1,30 @@
|
||||
# 2026-04-09 安装 Node 25 与 Node 14 实施记录
|
||||
|
||||
## 变更内容
|
||||
- 使用 `nvm` 安装 `node v25.9.0`
|
||||
- 使用 `nvm` 安装 `node v14.21.3`
|
||||
- 调整 `/Users/wkc/.npmrc`,删除与 `nvm` 冲突的 `prefix=~/.npm-global`
|
||||
- 保留 npm 镜像配置:`registry=https://registry.npmmirror.com`
|
||||
|
||||
## 处理过程
|
||||
- `node 25` 通过 `nvm` 正常安装成功
|
||||
- `node 14` 在 Apple Silicon 原生环境下无法直接下载 `darwin-arm64` 安装包
|
||||
- 原生源码编译 `node 14` 失败,错误来自当前 macOS Command Line Tools/SDK 与旧版 `node 14` 源码不兼容
|
||||
- 改为通过 Rosetta 以 `x64` 方式安装 `node 14`,安装成功
|
||||
|
||||
## 验证结果
|
||||
- `zsh -lic 'nvm use 25 && node -v && npm -v'` 验证结果:
|
||||
- `node v25.9.0`
|
||||
- `npm 11.12.1`
|
||||
- `zsh -lic 'nvm use 14 && node -v && npm -v'` 验证结果:
|
||||
- `node v14.21.3`
|
||||
- `npm 6.14.18`
|
||||
- `arch -x86_64 /bin/zsh -lic 'nvm use 14 && node -v && npm -v'` 验证结果:
|
||||
- `node v14.21.3`
|
||||
- `npm 6.14.18`
|
||||
- 新开的交互式 `zsh` 默认版本:
|
||||
- `node v14.21.3`
|
||||
- `npm 6.14.18`
|
||||
|
||||
## 备注
|
||||
- `nvm` 当前默认别名已指向 `14`
|
||||
@@ -0,0 +1,25 @@
|
||||
# 2026-04-09 Node 卸载与 nvm 安装实施记录
|
||||
|
||||
## 变更内容
|
||||
- 卸载了 Homebrew 安装的 `node 25.8.1_1`
|
||||
- 删除了本地目录 `/Users/wkc/.local/node-v14.21.3-darwin-x64`
|
||||
- 更新了 `/Users/wkc/.zshrc`
|
||||
- 安装了 `nvm 0.40.4`
|
||||
|
||||
## shell 配置调整
|
||||
- 删除旧配置:`export PATH="/Users/wkc/.local/node-v14.21.3-darwin-x64/bin:$PATH"`
|
||||
- 新增 `nvm` 初始化配置:
|
||||
|
||||
```sh
|
||||
export NVM_DIR="$HOME/.nvm"
|
||||
[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh"
|
||||
[ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm"
|
||||
```
|
||||
|
||||
## 验证结果
|
||||
- 交互式 `zsh` 下 `nvm --version` 返回 `0.40.4`
|
||||
- `node` 命令已不存在,说明当前环境中已无非 `nvm` 管理的 Node 版本
|
||||
- `nvm ls` 返回 `N/A`,说明尚未通过 `nvm` 安装任何 Node 版本
|
||||
|
||||
## 备注
|
||||
- `brew uninstall node` 过程中触发了 Homebrew 自动移除若干仅供该版本 Node 使用的依赖库
|
||||
@@ -0,0 +1,25 @@
|
||||
# 证件输入校验移除实施记录
|
||||
|
||||
## 实施时间
|
||||
- 2026-04-09
|
||||
|
||||
## 修改内容
|
||||
- 移除个人新增弹窗中的证件号码格式校验
|
||||
- 移除企业新增弹窗中的证件号码格式校验
|
||||
- 两个新增弹窗的证件号码规则统一保留为必填校验
|
||||
- 新增前端源码断言,约束后续不再恢复证件号码格式校验
|
||||
|
||||
## 修改文件
|
||||
- `ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue`
|
||||
- `ruoyi-ui/src/views/loanPricing/workflow/components/CorporateCreateDialog.vue`
|
||||
- `ruoyi-ui/tests/id-number-validation-removal.test.js`
|
||||
- `ruoyi-ui/package.json`
|
||||
- `doc/implementation-report-2026-04-09-remove-id-number-validation.md`
|
||||
|
||||
## 验证方式
|
||||
1. `npm --prefix ruoyi-ui run test:id-number-validation-removal`
|
||||
2. `npm --prefix ruoyi-ui run build:prod`
|
||||
|
||||
## 说明
|
||||
- 本次移除的是前端证件号码格式校验,不影响证件号码必填约束
|
||||
- 后端本次未新增或调整证件号码格式校验逻辑
|
||||
@@ -0,0 +1,26 @@
|
||||
# 上虞个人利率测算输入参数文档产出记录
|
||||
|
||||
## 实施时间
|
||||
- 2026-04-09
|
||||
|
||||
## 修改内容
|
||||
- 新增个人利率测算输入参数对齐设计文档
|
||||
- 新增个人利率测算输入参数前端实施计划
|
||||
- 新增个人利率测算输入参数后端实施计划
|
||||
- 按 Excel `入参` sheet 整理个人新增弹窗字段获取方式和模型调用参数来源
|
||||
- 明确 `loanTerm` 使用固定年限下拉,选项按 Excel 组织
|
||||
- 明确系统字段 `serialNum`、`orgCode`、`runType`、`custType` 继续自动带值
|
||||
- 明确个人开关字段在模型调用层转换为 `0/1`
|
||||
- 补充确认后端最终发给模型的 16 个输入参数、来源、请求格式与验证口径
|
||||
|
||||
## 修改文件
|
||||
- `doc/2026-04-09-shangyu-retail-input-params-design.md`
|
||||
- `doc/2026-04-09-shangyu-retail-input-params-frontend-plan.md`
|
||||
- `doc/2026-04-09-shangyu-retail-input-params-backend-plan.md`
|
||||
- `doc/implementation-report-2026-04-09-shangyu-retail-input-params-plans.md`
|
||||
|
||||
## 说明
|
||||
- 设计文档保存路径已核对为项目现有的 `doc/` 目录
|
||||
- 按项目要求,本次实施计划拆分为前端与后端两份文档
|
||||
- 由于仓库约束为“不开启 subagent”,文档评审环节未使用子代理,后续执行时将在当前会话内推进
|
||||
- 本次仅产出设计与计划文档,尚未进入代码实施阶段
|
||||
@@ -0,0 +1,93 @@
|
||||
# 上虞个人利率测算输入参数对齐实施记录
|
||||
|
||||
## 实施时间
|
||||
- 2026-04-09
|
||||
|
||||
## 修改内容
|
||||
- 个人新增弹窗补齐 `loanPurpose`、`loanTerm`
|
||||
- 个人新增弹窗 `loanTerm` 固定为 `1-6` 年
|
||||
- 个人新增弹窗 `collType` 选项统一为 `一类/二类/三类`
|
||||
- 个人新增弹窗开关字段提交值由 `true/false` 调整为 `1/0`
|
||||
- 个人详情页补齐 `贷款用途` 展示
|
||||
- 个人与企业详情、模型输出布尔展示兼容 `1/0`
|
||||
- 后端个人创建 DTO 补齐 `loanPurpose`、`loanTerm`
|
||||
- 后端个人 DTO 到流程实体映射补齐 `loanPurpose`、`loanTerm`
|
||||
- 后端模型调用 DTO 补齐 `loanTerm`、`loanLoop`
|
||||
- 后端个人模型调用前统一将 `bizProof`、`loanLoop`、`collThirdParty` 规范为 `0/1`
|
||||
- `orgCode` 统一为 `892000`
|
||||
- `ModelInvokeDTO` 注释、接口文档、SQL 基线和迁移脚本同步统一为 `892000`
|
||||
- 新增前端源码断言与后端单元测试
|
||||
|
||||
## 修改文件
|
||||
- `ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue`
|
||||
- `ruoyi-ui/src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue`
|
||||
- `ruoyi-ui/src/views/loanPricing/workflow/components/ModelOutputDisplay.vue`
|
||||
- `ruoyi-ui/src/views/loanPricing/workflow/components/CorporateWorkflowDetail.vue`
|
||||
- `ruoyi-ui/src/views/loanPricing/workflow/components/CorporateCreateDialog.vue`
|
||||
- `ruoyi-ui/tests/personal-create-input-params.test.js`
|
||||
- `ruoyi-ui/package.json`
|
||||
- `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/PersonalLoanPricingCreateDTO.java`
|
||||
- `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/ModelInvokeDTO.java`
|
||||
- `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/util/LoanPricingConverter.java`
|
||||
- `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingModelService.java`
|
||||
- `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingModelServicePersonalParamsTest.java`
|
||||
- `doc/api/loan-pricing-workflow-api.md`
|
||||
- `sql/loan_pricing_workflow.sql`
|
||||
- `sql/loan_pricing_schema_20260328.sql`
|
||||
- `sql/loan_pricing_prod_init_20260331.sql`
|
||||
- `sql/fix_comments.sql`
|
||||
- `sql/fix_all_comments.sql`
|
||||
- `sql/update_org_code_default_20260409.sql`
|
||||
- `doc/2026-04-09-shangyu-retail-input-params-design.md`
|
||||
- `doc/2026-04-09-shangyu-retail-input-params-frontend-plan.md`
|
||||
- `doc/implementation-report-2026-04-09-shangyu-retail-input-params.md`
|
||||
|
||||
## 数据库处理
|
||||
1. 执行 `sql/update_org_code_default_20260409.sql`
|
||||
2. 将 `loan_pricing_workflow.org_code` 默认值修改为 `892000`
|
||||
3. 将存量 `loan_pricing_workflow.org_code` 非 `892000` 的记录统一更新为 `892000`
|
||||
|
||||
## 验证方式
|
||||
1. 前端源码断言:
|
||||
- `npm --prefix ruoyi-ui run test:personal-create-input-params`
|
||||
- `npm --prefix ruoyi-ui run test:retail-display-fields`
|
||||
2. 后端单元测试:
|
||||
- `mvn -pl ruoyi-loan-pricing -Dtest=LoanPricingModelServiceTest,LoanPricingModelServicePersonalParamsTest test`
|
||||
3. 前端构建:
|
||||
- `npm --prefix ruoyi-ui run build:prod`
|
||||
4. 数据库验证:
|
||||
- 查询 `loan_pricing_workflow.org_code` 字段默认值
|
||||
- 查询存量数据中是否仍存在非 `892000` 记录
|
||||
5. 接口验证:
|
||||
- `/login/test` 获取 token
|
||||
- `POST /loanPricing/workflow/create/personal` 正常场景
|
||||
- `POST /loanPricing/workflow/create/personal` 缺少 `loanPurpose` 场景
|
||||
- `POST /loanPricing/workflow/create/personal` 分支值场景
|
||||
- `GET /loanPricing/workflow/{serialNum}` 验证回显
|
||||
6. 页面验证:
|
||||
- 启动前端 dev server
|
||||
- 使用浏览器打开流程列表页
|
||||
- 校验新增弹窗下拉选项
|
||||
- 页面创建个人流程并打开详情页确认回显
|
||||
|
||||
## 验证结果
|
||||
- `npm --prefix ruoyi-ui run test:personal-create-input-params` 通过
|
||||
- `npm --prefix ruoyi-ui run test:retail-display-fields` 通过
|
||||
- `mvn -pl ruoyi-loan-pricing -Dtest=LoanPricingModelServiceTest,LoanPricingModelServicePersonalParamsTest test` 通过
|
||||
- `npm --prefix ruoyi-ui run build:prod` 通过,输出 `Build complete.`
|
||||
- 数据库验证结果:
|
||||
- `loan_pricing_workflow.org_code` 默认值为 `892000`
|
||||
- 存量非 `892000` 记录数为 `0`
|
||||
- 接口验证结果:
|
||||
- 正常场景创建成功,返回 `orgCode=892000`,并持久化 `loanPurpose`、`loanTerm`
|
||||
- 缺少 `loanPurpose` 时返回 `贷款用途不能为空`
|
||||
- 分支场景详情回显 `bizProof=0`、`loanLoop=1`、`collThirdParty=0`
|
||||
- 页面验证结果:
|
||||
- 新增弹窗显示 `贷款用途`
|
||||
- 借款期限下拉仅包含 `1-6`
|
||||
- 抵质押类型下拉为 `一类/二类/三类`
|
||||
- 页面创建流程成功后,详情页展示 `贷款用途=经营`、`借款期限=6`
|
||||
|
||||
## 说明
|
||||
- 浏览器验证使用系统 `Google Chrome.app`
|
||||
- 本次验证期间启动的后端、前端和浏览器进程已在任务结束前关闭
|
||||
26
doc/implementation-report-2026-04-09-start-script-ps-ef.md
Normal file
26
doc/implementation-report-2026-04-09-start-script-ps-ef.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# 启动脚本进程判断改为 ps -ef 实施记录
|
||||
|
||||
## 修改内容
|
||||
|
||||
- 将 `bin/prod/restart_java.sh` 中的后端进程收集逻辑由 `pgrep -f` 改为 `ps -ef | awk`
|
||||
- 将 `bin/restart_java_backend.sh` 中的后端进程收集逻辑由 `pgrep -f` 改为 `ps -ef | awk`
|
||||
- 删除 `bin/restart_java_backend.sh` 中对 `pgrep` 命令的依赖校验
|
||||
- 更新 `bin/prod/restart_java_test.sh`,补充 `ps -ef` / `pgrep` 约束校验,并修正测试夹具中的 JDK 目录
|
||||
- 新增 `bin/restart_java_backend_test.sh`,校验本地后端重启脚本已改用 `ps -ef`
|
||||
|
||||
## 实现说明
|
||||
|
||||
- 两份脚本都只在 `ps -ef` 结果中匹配同时满足“包含脚本标记参数”和“`-jar` 指向目标 jar”这两个条件的 Java 进程
|
||||
- 进程筛选时继续忽略 `<defunct>` 记录,避免误判僵尸进程
|
||||
- 现有 PID 文件校验逻辑保持不变,本次只收敛“扫描当前是否已有进程”的实现方式
|
||||
|
||||
## 路径检查
|
||||
|
||||
- 已确认本次实施记录保存路径为 `doc/implementation-report-2026-04-09-start-script-ps-ef.md`
|
||||
|
||||
## 验证结果
|
||||
|
||||
- 已执行 `sh bin/prod/restart_java_test.sh`
|
||||
- 已执行 `sh bin/restart_java_backend_test.sh`
|
||||
- 已执行 `sh -n bin/prod/restart_java.sh && sh -n bin/restart_java_backend.sh`
|
||||
- 已确认测试中拉起的假 Java 进程在脚本收尾阶段自动停止并清理
|
||||
@@ -0,0 +1,37 @@
|
||||
# 2026-04-10 登录 Shell 默认使用 Node 25 实施记录
|
||||
|
||||
## 变更内容
|
||||
- 保持 `nvm` 默认别名为 `25`
|
||||
- 在 `~/.zprofile` 中补充 `nvm` 初始化,并在登录 shell 启动时自动执行 `nvm use default`
|
||||
|
||||
## 根因分析
|
||||
- `nvm alias default 25` 已经存在,但仅在交互式 shell 中可用
|
||||
- `zsh -lc` 启动的是登录非交互 shell,不会读取 `~/.zshrc`
|
||||
- 因此这类场景下 `node`、`npm`、`npx` 未进入 PATH,表现为 `npx` 启动失败
|
||||
|
||||
## 修改文件
|
||||
- `~/.zprofile`
|
||||
- `doc/implementation-report-2026-04-10-login-shell-default-node25.md`
|
||||
|
||||
## 验证项
|
||||
- 验证登录 shell 在不手动执行 `nvm use` 的情况下可直接识别 `node`
|
||||
- 验证登录 shell 在不手动执行 `nvm use` 的情况下可直接识别 `npx`
|
||||
- 验证 `nvm` 默认别名仍然指向 `25`
|
||||
|
||||
## 执行命令
|
||||
- `zsh -lc 'nvm alias default 25'`
|
||||
- `zsh -lc 'echo NODE=$(node -v); echo NPM=$(npm -v); echo NPX=$(npx -v); echo NODE_PATH=$(command -v node); echo NPX_PATH=$(command -v npx); echo NVM_CURRENT=$(nvm current); echo NVM_ALIAS=$(nvm alias default | tail -n 1)'`
|
||||
|
||||
## 验证结果
|
||||
- `nvm` 默认别名输出为 `default -> 25 (-> v25.9.0 *)`
|
||||
- 登录 shell 输出 `NODE=v25.9.0`
|
||||
- 登录 shell 输出 `NPM=11.12.1`
|
||||
- 登录 shell 输出 `NPX=11.12.1`
|
||||
- 登录 shell 输出 `NODE_PATH=/Users/wkc/.nvm/versions/node/v25.9.0/bin/node`
|
||||
- 登录 shell 输出 `NPX_PATH=/Users/wkc/.nvm/versions/node/v25.9.0/bin/npx`
|
||||
- 登录 shell 输出 `NVM_CURRENT=v25.9.0`
|
||||
- 登录 shell 输出 `NVM_ALIAS=default -> 25 (-> v25.9.0 *)`
|
||||
|
||||
## 结论
|
||||
- `zsh -lc` 场景下已默认切换到 Node `25.9.0`
|
||||
- `npx` 在登录 shell 中已可直接使用,无需先手动执行 `nvm use 25`
|
||||
@@ -0,0 +1,19 @@
|
||||
# 个人流程最终测算利率展示实施记录
|
||||
|
||||
## 修改时间
|
||||
- 2026-04-11
|
||||
|
||||
## 修改内容
|
||||
- 调整流程列表后端查询:个人客户列表“测算利率”改为读取 `model_retail_output_fields.final_calculate_rate`
|
||||
- 调整个人流程详情左侧展示:标签改为“最终测算利率”,显示字段改为 `retailOutput.finalCalculateRate`
|
||||
- 调整个人流程详情后端组装:`loanPricingWorkflow.loanRate` 改为取个人模型输出的 `finalCalculateRate`
|
||||
|
||||
## 影响范围
|
||||
- 个人流程列表
|
||||
- 个人流程详情左侧关键信息
|
||||
- 企业流程列表与详情保持现状,不做改动
|
||||
|
||||
## 验证计划
|
||||
- 后端单元测试验证个人详情取 `finalCalculateRate`
|
||||
- 后端静态测试验证列表 SQL 的个人分支查询 `mr.final_calculate_rate`
|
||||
- 前端静态测试验证个人详情展示 `finalCalculateRate`
|
||||
@@ -0,0 +1,17 @@
|
||||
# 流程详情卡片顺序调整实施记录
|
||||
|
||||
## 修改时间
|
||||
- 2026-04-11
|
||||
|
||||
## 修改内容
|
||||
- 调整个人流程详情页右侧卡片顺序,将模型输出卡片移动到流程详情卡片上方
|
||||
- 调整企业流程详情页右侧卡片顺序,将模型输出卡片移动到流程详情卡片上方
|
||||
- 新增前端静态校验,约束个人与企业详情组件的卡片顺序
|
||||
|
||||
## 影响范围
|
||||
- 个人流程详情页面布局
|
||||
- 企业流程详情页面布局
|
||||
|
||||
## 验证计划
|
||||
- 执行前端静态测试,确认卡片顺序断言通过
|
||||
- 启动前端页面并在浏览器中检查个人、企业详情页卡片顺序
|
||||
@@ -0,0 +1,34 @@
|
||||
# 本地 Tomcat 与 TongWeb 双产物实施记录
|
||||
|
||||
## 本次改动
|
||||
|
||||
- 将 `ruoyi-admin` 的主打包方式从 `war` 恢复为 `jar`
|
||||
- 恢复 `spring-boot-maven-plugin` 的 `repackage`,保证本地可直接运行 `ruoyi-admin.jar`
|
||||
- 在 `ruoyi-admin` 中增加附加 `war` 打包步骤,使 `mvn package` 同时产出:
|
||||
- `ruoyi-admin.jar`
|
||||
- `ruoyi-admin.war`
|
||||
- 在 `war` 打包中排除内嵌 Tomcat 相关 jar,避免 TongWeb 部署时容器冲突
|
||||
- 将 `bin/restart_java_backend.sh` 恢复为本地 `java -jar` 启动链路
|
||||
- 保持 `bin/prod/restart_java.sh`、`bin/prod/deploy_from_package.sh` 继续消费 `ruoyi-admin.war`
|
||||
- 更新 `bin/run.bat`,恢复为本地 `jar` 启动入口
|
||||
- 新增设计文档 `doc/2026-04-13-local-tomcat-remote-tongweb-design.md`
|
||||
- 新增实施计划 `doc/2026-04-13-local-tomcat-remote-tongweb-backend-plan.md`
|
||||
|
||||
## 验证结果
|
||||
|
||||
- 已执行 `sh bin/restart_java_backend_test.sh`
|
||||
- 已执行 `sh bin/prod/restart_java_test.sh`
|
||||
- 已执行 `sh bin/prod/deploy_from_package_test.sh`
|
||||
- 已执行 `sh -n bin/restart_java_backend.sh`
|
||||
- 已执行 `sh -n bin/prod/restart_java.sh`
|
||||
- 已执行 `sh -n bin/prod/deploy_from_package.sh`
|
||||
- 已执行 `mvn -pl ruoyi-admin -am clean package -DskipTests`
|
||||
- 已确认产物:
|
||||
- `ruoyi-admin/target/ruoyi-admin.jar`
|
||||
- `ruoyi-admin/target/ruoyi-admin.war`
|
||||
|
||||
## 结果说明
|
||||
|
||||
- 本地开发运行继续使用内嵌 Tomcat,不要求本机安装 TongWeb
|
||||
- 服务器部署继续使用 TongWeb,只消费 `war`
|
||||
- 一次打包即可同时得到本地运行产物和 TongWeb 部署产物
|
||||
@@ -0,0 +1,25 @@
|
||||
# Tomcat 替换为东方通实施记录
|
||||
|
||||
## 本次改动
|
||||
|
||||
- 将 `ruoyi-admin` 打包方式从 `jar` 调整为 `war`
|
||||
- 在 `ruoyi-admin` 中显式声明 `spring-boot-starter-tomcat` 为 `provided`
|
||||
- 在 `ruoyi-framework`、`ruoyi-loan-pricing` 中排除 `spring-boot-starter-web` 传递进来的嵌入式 Tomcat
|
||||
- 将 `ruoyi-common` 中的 `jakarta.servlet-api` 调整为 `provided`
|
||||
- 删除 `application-dev.yml`、`application-uat.yml`、`application-pro.yml` 中仅对内嵌 Tomcat 生效的 `server.tomcat` 配置
|
||||
- 将 `bin/prod/restart_java.sh` 从 `java -jar` 启停改为 TongWeb 启停与 `war` 同步
|
||||
- 将 `bin/prod/deploy_from_package.sh`、`bin/prod/deploy_release.sh` 的后端交付物从 `ruoyi-admin.jar` 改为 `ruoyi-admin.war`
|
||||
- 将 `bin/restart_java_backend.sh` 改为本地构建 `war` 并发布到 TongWeb
|
||||
- 更新 `deploy/2026-03-31-local-nginx-java-install-manual.md`,将后端运行环境说明改为 TongWeb
|
||||
- 新增后端实施计划 `doc/2026-04-13-tongweb-replace-tomcat-backend-plan.md`
|
||||
|
||||
## 验证结果
|
||||
|
||||
- 已执行 `sh bin/prod/restart_java_test.sh`
|
||||
- 已执行 `sh bin/prod/deploy_from_package_test.sh`
|
||||
- 已执行 `sh bin/restart_java_backend_test.sh`
|
||||
|
||||
## 说明
|
||||
|
||||
- 本次替换按当前项目 `Spring Boot 3 + Jakarta Servlet` 路线落地,要求实际使用的东方通版本能够承载 Jakarta 体系应用
|
||||
- Nginx 入口和反向代理端口保持不变,仍通过 `63310` 转发到后端容器
|
||||
@@ -0,0 +1,105 @@
|
||||
# RuoYi-Vue springboot2 基线迁移实施记录
|
||||
|
||||
## 本次完成内容
|
||||
|
||||
- 以 `RuoYi-Vue/springboot2` 为基线覆盖当前仓库的框架层:
|
||||
- 根 `pom.xml`
|
||||
- `ruoyi-admin`
|
||||
- `ruoyi-common`
|
||||
- `ruoyi-framework`
|
||||
- `ruoyi-generator`
|
||||
- `ruoyi-quartz`
|
||||
- `ruoyi-system`
|
||||
- `ruoyi-ui`
|
||||
- `sql` 基础脚本
|
||||
- 恢复并接回业务模块与业务页面:
|
||||
- `ruoyi-loan-pricing`
|
||||
- `ruoyi-ui/src/views/loanPricing`
|
||||
- `ruoyi-ui/src/api/loanPricing`
|
||||
- `ruoyi-ui/src/router/index.js` 中的业务路由
|
||||
- `ruoyi-admin` 中的业务配置
|
||||
- 将 `ruoyi-loan-pricing` 从 Boot 3 / Java 17 写法回退到 Boot 2 / Java 8 可编译形态:
|
||||
- 移除 `springdoc` 注解和依赖
|
||||
- 将 `jakarta.*` 改回 `javax.*`
|
||||
- 将 `String.repeat` 改为 Java 8 兼容实现
|
||||
- 将模型调用改为模块内 `RestTemplate + form-urlencoded`
|
||||
- 补回当前项目的“无 Redis”本地缓存实现:
|
||||
- `InMemoryCacheEntry`
|
||||
- `InMemoryCacheStats`
|
||||
- `InMemoryCacheStore`
|
||||
- 本地缓存版 `RedisCache`
|
||||
- 本地缓存版 `CacheController`
|
||||
- 调整前端业务依赖与脚本:
|
||||
- 恢复 `crypto-js`
|
||||
- 恢复 `splitpanes`
|
||||
- 恢复 `ruoyi-ui/tests` 下 4 个业务测试脚本
|
||||
- 恢复项目原有部署辅助脚本:
|
||||
- `bin/prod/*.sh`
|
||||
- `bin/restart_java_backend*.sh`
|
||||
- 修正本地启动所需配置:
|
||||
- `logback.xml` 日志目录改为项目内 `logs`
|
||||
- `application.yml` 补齐 `swagger`、`redis`、`mybatis`
|
||||
- 增加 `ruoyi-loan-pricing` 模块挂载和依赖声明
|
||||
|
||||
## 验证结果
|
||||
|
||||
### 后端编译验证
|
||||
|
||||
已通过:
|
||||
|
||||
- `export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home && export PATH="$JAVA_HOME/bin:$PATH" && mvn -pl ruoyi-admin -am -DskipTests package`
|
||||
- `export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home && export PATH="$JAVA_HOME/bin:$PATH" && mvn -pl ruoyi-admin -am install -DskipTests`
|
||||
|
||||
### 前端构建验证
|
||||
|
||||
已通过:
|
||||
|
||||
- `source ~/.nvm/nvm.sh && nvm use 14.21.3 && npm install`
|
||||
- `source ~/.nvm/nvm.sh && nvm use 14.21.3 && npm run build:prod`
|
||||
|
||||
### 前后端联调验证
|
||||
|
||||
已验证:
|
||||
|
||||
- 前端开发服务成功启动于 `http://localhost:1024`
|
||||
- 浏览器打开 `http://localhost:1024/login`,页面标题显示为“若依管理系统”
|
||||
- 浏览器点击登录后成功进入 `/index`
|
||||
- 页面已实际渲染“流程列表”业务页面
|
||||
- 通过前端代理访问 `http://localhost:1024/dev-api/captchaImage` 返回:
|
||||
- `{"msg":"操作成功","code":200,"captchaEnabled":false}`
|
||||
- 源码态后端在 `Java 8 + spring-boot:run` 模式下可启动成功
|
||||
- 登录接口可成功返回 token:
|
||||
- `POST /login`
|
||||
|
||||
## 联调中发现的遗留问题
|
||||
|
||||
浏览器进入系统后,页面出现两条后端错误提示:
|
||||
|
||||
1. 数据库缺少 `sys_notice_read` 表
|
||||
2. `GET /loanPricing/workflow/list` 仍返回 `TooManyResultsException`
|
||||
|
||||
其中第 1 项已确认当前仓库 SQL 中已有对应建表语句:
|
||||
|
||||
- `sql/ry_20260330.sql`
|
||||
- `sql/loan_pricing_prod_init_20260331.sql`
|
||||
|
||||
说明当前代码迁移已落地,但联调数据库尚未完全补齐到 `springboot2` 基线所需表结构。
|
||||
|
||||
第 2 项已经定位到当前运行态仍存在列表查询返回值与 MyBatis 映射结果不一致的问题,表现为:
|
||||
|
||||
- `GET /loanPricing/workflow/list?pageNum=1&pageSize=10`
|
||||
- 返回:`{"msg":"nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 15","code":500}`
|
||||
|
||||
## 结论
|
||||
|
||||
本次代码迁移已经完成:
|
||||
|
||||
- 框架层已切回 `RuoYi-Vue springboot2`
|
||||
- 业务模块和业务页面已接回
|
||||
- Java 8 / Spring Boot 2 / Vue 2 的编译与构建链路已打通
|
||||
- 浏览器已成功进入业务页面与登录链路
|
||||
|
||||
当前剩余问题集中在:
|
||||
|
||||
- 联调数据库尚未补齐 `sys_notice_read` 表
|
||||
- `workflow/list` 运行态查询仍需继续收口
|
||||
BIN
doc/~$上虞利率测算接口文档.xlsx
Normal file
BIN
doc/~$上虞利率测算接口文档.xlsx
Normal file
Binary file not shown.
BIN
doc/上虞利率测算接口文档.xlsx
Normal file
BIN
doc/上虞利率测算接口文档.xlsx
Normal file
Binary file not shown.
@@ -0,0 +1,110 @@
|
||||
# Personal Pricing Collateral Optional Frontend Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED: Use superpowers:executing-plans to implement this plan in this repository. Do not use subagents. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 让个人利率定价新增流程中的“抵质押类型”改为非必填,企业流程保持不变。
|
||||
|
||||
**Architecture:** 维持现有个人新增弹窗的数据结构、字段名称和提交报文不变,只移除前端表单对 `collType` 的必填限制。通过前端源码断言测试和页面联调共同验证“字段可空提交”的行为,避免扩大到企业流程或后端接口。
|
||||
|
||||
**Tech Stack:** Vue 2、Element UI、npm、Node.js 断言脚本
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 固化个人新增流程“抵质押类型非必填”的前端测试
|
||||
|
||||
**Files:**
|
||||
- Modify: `ruoyi-ui/tests/personal-create-input-params.test.js`
|
||||
- Inspect: `ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue`
|
||||
|
||||
- [ ] **Step 1: 核对当前个人新增弹窗中的 `collType` 规则**
|
||||
|
||||
Run: `sed -n '150,220p' ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue`
|
||||
Expected: 能看到 `rules.collType` 里仍有 `required: true`。
|
||||
|
||||
- [ ] **Step 2: 先写失败断言**
|
||||
|
||||
在 `ruoyi-ui/tests/personal-create-input-params.test.js` 中增加断言,明确个人新增弹窗不应再包含:
|
||||
|
||||
```js
|
||||
required: true, message: "请选择抵质押类型"
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 运行测试确认红灯**
|
||||
|
||||
Run: `npm --prefix ruoyi-ui run test:personal-create-input-params`
|
||||
Expected: FAIL,提示个人新增弹窗仍将抵质押类型设为必填。
|
||||
|
||||
### Task 2: 移除个人新增弹窗中 `collType` 的必填限制
|
||||
|
||||
**Files:**
|
||||
- Modify: `ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue`
|
||||
|
||||
- [ ] **Step 1: 删除 `collType` 的必填校验**
|
||||
|
||||
把:
|
||||
|
||||
```js
|
||||
collType: [
|
||||
{required: true, message: "请选择抵质押类型", trigger: "change"}
|
||||
]
|
||||
```
|
||||
|
||||
移除,使个人表单规则中不再声明 `collType` 为必填。
|
||||
|
||||
- [ ] **Step 2: 保持其它字段与提交逻辑不变**
|
||||
|
||||
确认以下内容不改动:
|
||||
|
||||
```js
|
||||
collType: undefined,
|
||||
collThirdParty: false
|
||||
```
|
||||
|
||||
以及提交时的:
|
||||
|
||||
```js
|
||||
collThirdParty: this.form.collThirdParty ? '1' : '0'
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 重新运行测试确认转绿**
|
||||
|
||||
Run: `npm --prefix ruoyi-ui run test:personal-create-input-params`
|
||||
Expected: PASS,输出包含 `personal create input params assertions passed`。
|
||||
|
||||
### Task 3: 页面联调并补实施记录
|
||||
|
||||
**Files:**
|
||||
- Create: `docs/implementation-reports/2026-04-10-personal-pricing-collateral-optional-frontend.md`
|
||||
|
||||
- [ ] **Step 1: 启动前端页面**
|
||||
|
||||
Run: `npm --prefix ruoyi-ui run dev`
|
||||
Expected: 前端本地开发服务启动成功,可访问新增个人利率定价流程页面。
|
||||
|
||||
- [ ] **Step 2: 浏览器确认页面行为**
|
||||
|
||||
联调确认:
|
||||
- 个人新增弹窗“抵质押类型”字段可为空
|
||||
- 不选择“抵质押类型”时其余必填项填完整仍可点击提交
|
||||
- 企业新增弹窗规则不受影响
|
||||
|
||||
- [ ] **Step 3: 停止本次测试启动的前端进程**
|
||||
|
||||
Run: `ps -ef | rg 'vue-cli-service serve|npm --prefix ruoyi-ui run dev'`
|
||||
Expected: 仅停止本次联调启动的前端进程。
|
||||
|
||||
- [ ] **Step 4: 编写实施记录**
|
||||
|
||||
实施记录至少包含:
|
||||
|
||||
```markdown
|
||||
- 本次仅调整个人利率定价新增流程
|
||||
- 个人新增弹窗已移除抵质押类型必填校验
|
||||
- 企业新增流程未改动
|
||||
- 已执行前端断言测试与页面联调验证
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 核对实施记录保存路径**
|
||||
|
||||
Run: `ls docs/implementation-reports/2026-04-10-personal-pricing-collateral-optional-frontend.md`
|
||||
Expected: 文件位于仓库 `docs/implementation-reports` 目录。
|
||||
513
pom.xml
513
pom.xml
@@ -1,191 +1,218 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<version>3.9.1</version>
|
||||
|
||||
<name>ruoyi</name>
|
||||
<url>http://www.ruoyi.vip</url>
|
||||
<description>若依管理系统</description>
|
||||
|
||||
<properties>
|
||||
<ruoyi.version>3.9.1</ruoyi.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>17</java.version>
|
||||
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
|
||||
<mybatis-spring-boot.version>3.0.5</mybatis-spring-boot.version>
|
||||
<druid.version>1.2.27</druid.version>
|
||||
<yauaa.version>7.32.0</yauaa.version>
|
||||
<swagger.version>3.0.0</swagger.version>
|
||||
<kaptcha.version>2.3.3</kaptcha.version>
|
||||
<pagehelper.boot.version>2.1.1</pagehelper.boot.version>
|
||||
<fastjson.version>2.0.60</fastjson.version>
|
||||
<oshi.version>6.9.1</oshi.version>
|
||||
<commons.io.version>2.21.0</commons.io.version>
|
||||
<poi.version>4.1.2</poi.version>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<version>3.9.2</version>
|
||||
|
||||
<name>ruoyi</name>
|
||||
<url>http://www.ruoyi.vip</url>
|
||||
<description>若依管理系统</description>
|
||||
|
||||
<properties>
|
||||
<ruoyi.version>3.9.2</ruoyi.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
|
||||
<spring-boot.version>2.5.15</spring-boot.version>
|
||||
<druid.version>1.2.28</druid.version>
|
||||
<yauaa.version>7.32.0</yauaa.version>
|
||||
<swagger.version>3.0.0</swagger.version>
|
||||
<kaptcha.version>2.3.3</kaptcha.version>
|
||||
<pagehelper.boot.version>1.4.7</pagehelper.boot.version>
|
||||
<fastjson.version>2.0.61</fastjson.version>
|
||||
<oshi.version>6.10.0</oshi.version>
|
||||
<commons.io.version>2.21.0</commons.io.version>
|
||||
<poi.version>4.1.2</poi.version>
|
||||
<velocity.version>2.3</velocity.version>
|
||||
<jwt.version>0.9.1</jwt.version>
|
||||
<quartz.version>2.5.2</quartz.version>
|
||||
<mysql.version>8.2.0</mysql.version>
|
||||
<jaxb-api.version>2.3.1</jaxb-api.version>
|
||||
<jakarta.version>6.0.0</jakarta.version>
|
||||
<springdoc.version>2.8.14</springdoc.version>
|
||||
</properties>
|
||||
|
||||
<!-- 依赖声明 -->
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
<!-- SpringBoot的依赖配置-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>3.5.8</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 阿里数据库连接池 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-3-starter</artifactId>
|
||||
<version>${druid.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 解析客户端操作系统、浏览器等 -->
|
||||
<dependency>
|
||||
<groupId>nl.basjes.parse.useragent</groupId>
|
||||
<artifactId>yauaa</artifactId>
|
||||
<version>${yauaa.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- pagehelper 分页插件 -->
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper-spring-boot-starter</artifactId>
|
||||
<version>${pagehelper.boot.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>${mybatis-spring-boot.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<version>${mysql.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<version>${jaxb-api.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<version>${jakarta.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 获取系统信息 -->
|
||||
<dependency>
|
||||
<groupId>com.github.oshi</groupId>
|
||||
<artifactId>oshi-core</artifactId>
|
||||
<version>${oshi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- spring-doc -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<version>${springdoc.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- io常用工具类 -->
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>${commons.io.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- excel工具 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>${poi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- velocity代码生成使用模板 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.velocity</groupId>
|
||||
<artifactId>velocity-engine-core</artifactId>
|
||||
<version>${velocity.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 定时任务 -->
|
||||
<dependency>
|
||||
<groupId>org.quartz-scheduler</groupId>
|
||||
<artifactId>quartz</artifactId>
|
||||
<version>${quartz.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 阿里JSON解析器 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Token生成与解析-->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>${jwt.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 验证码 -->
|
||||
<dependency>
|
||||
<groupId>pro.fessional</groupId>
|
||||
<artifactId>kaptcha</artifactId>
|
||||
<version>${kaptcha.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 定时任务-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-quartz</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 代码生成-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-generator</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 核心模块-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-framework</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 系统模块-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-system</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<mybatis-plus.version>3.5.7</mybatis-plus.version>
|
||||
<jsqlparser.version>4.5</jsqlparser.version>
|
||||
<!-- override dependency version -->
|
||||
<tomcat.version>9.0.112</tomcat.version>
|
||||
<logback.version>1.2.13</logback.version>
|
||||
<spring-security.version>5.7.14</spring-security.version>
|
||||
<spring-framework.version>5.3.39</spring-framework.version>
|
||||
</properties>
|
||||
|
||||
<!-- 依赖声明 -->
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
<!-- 覆盖SpringFramework的依赖配置-->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>${spring-framework.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 覆盖SpringSecurity的依赖配置-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-bom</artifactId>
|
||||
<version>${spring-security.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot的依赖配置-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 覆盖logback的依赖配置-->
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 覆盖tomcat的依赖配置-->
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-core</artifactId>
|
||||
<version>${tomcat.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-el</artifactId>
|
||||
<version>${tomcat.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-websocket</artifactId>
|
||||
<version>${tomcat.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 阿里数据库连接池 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
<version>${druid.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 解析客户端操作系统、浏览器等 -->
|
||||
<dependency>
|
||||
<groupId>nl.basjes.parse.useragent</groupId>
|
||||
<artifactId>yauaa</artifactId>
|
||||
<version>${yauaa.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- pagehelper 分页插件 -->
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper-spring-boot-starter</artifactId>
|
||||
<version>${pagehelper.boot.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 获取系统信息 -->
|
||||
<dependency>
|
||||
<groupId>com.github.oshi</groupId>
|
||||
<artifactId>oshi-core</artifactId>
|
||||
<version>${oshi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Swagger3依赖 -->
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-boot-starter</artifactId>
|
||||
<version>${swagger.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-models</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- io常用工具类 -->
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>${commons.io.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- excel工具 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>${poi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- velocity代码生成使用模板 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.velocity</groupId>
|
||||
<artifactId>velocity-engine-core</artifactId>
|
||||
<version>${velocity.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 阿里JSON解析器 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Token生成与解析-->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>${jwt.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 验证码 -->
|
||||
<dependency>
|
||||
<groupId>pro.fessional</groupId>
|
||||
<artifactId>kaptcha</artifactId>
|
||||
<version>${kaptcha.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 定时任务-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-quartz</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 代码生成-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-generator</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 核心模块-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-framework</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 系统模块-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-system</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 通用工具-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
@@ -200,64 +227,70 @@
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.jsqlparser</groupId>
|
||||
<artifactId>jsqlparser</artifactId>
|
||||
<version>${jsqlparser.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<modules>
|
||||
<module>ruoyi-admin</module>
|
||||
<module>ruoyi-framework</module>
|
||||
<module>ruoyi-system</module>
|
||||
|
||||
<modules>
|
||||
<module>ruoyi-admin</module>
|
||||
<module>ruoyi-framework</module>
|
||||
<module>ruoyi-system</module>
|
||||
<module>ruoyi-quartz</module>
|
||||
<module>ruoyi-generator</module>
|
||||
<module>ruoyi-common</module>
|
||||
<module>ruoyi-loan-pricing</module>
|
||||
</modules>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
<configuration>
|
||||
<parameters>true</parameters>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>public</id>
|
||||
<name>aliyun nexus</name>
|
||||
<url>https://maven.aliyun.com/repository/public</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>public</id>
|
||||
<name>aliyun nexus</name>
|
||||
<url>https://maven.aliyun.com/repository/public</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
</project>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>public</id>
|
||||
<name>aliyun nexus</name>
|
||||
<url>https://maven.aliyun.com/repository/public</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>public</id>
|
||||
<name>aliyun nexus</name>
|
||||
<url>https://maven.aliyun.com/repository/public</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -1,53 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<version>3.9.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>ruoyi-admin</artifactId>
|
||||
|
||||
<description>
|
||||
web服务入口
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- spring-boot-devtools -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<optional>true</optional> <!-- 表示依赖不会传递 -->
|
||||
</dependency>
|
||||
|
||||
<!-- spring-doc -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Mysql驱动包 -->
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 核心模块-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-framework</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 定时任务-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-quartz</artifactId>
|
||||
</dependency>
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<version>3.9.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>ruoyi-admin</artifactId>
|
||||
|
||||
<description>
|
||||
web服务入口
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- spring-boot-devtools -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<optional>true</optional> <!-- 表示依赖不会传递 -->
|
||||
</dependency>
|
||||
|
||||
<!-- swagger3-->
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 防止进入swagger页面报类型转换错误,排除3.0.0中的引用,手动增加1.6.2版本 -->
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-models</artifactId>
|
||||
<version>1.6.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Mysql驱动包 -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 核心模块-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-framework</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 定时任务-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-quartz</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 代码生成-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
@@ -60,42 +67,36 @@
|
||||
<artifactId>ruoyi-loan-pricing</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>3.5.4</version>
|
||||
<configuration>
|
||||
<addResources>true</addResources>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<failOnMissingWebXml>false</failOnMissingWebXml>
|
||||
<warName>${project.artifactId}</warName>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
</build>
|
||||
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>2.5.15</version>
|
||||
<configuration>
|
||||
<fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<failOnMissingWebXml>false</failOnMissingWebXml>
|
||||
<warName>${project.artifactId}</warName>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
package com.ruoyi;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
|
||||
/**
|
||||
* 启动程序
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
|
||||
public class RuoYiApplication
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
// System.setProperty("spring.devtools.restart.enabled", "false");
|
||||
SpringApplication.run(RuoYiApplication.class, args);
|
||||
System.out.println("(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ \n" +
|
||||
" .-------. ____ __ \n" +
|
||||
" | _ _ \\ \\ \\ / / \n" +
|
||||
" | ( ' ) | \\ _. / ' \n" +
|
||||
" |(_ o _) / _( )_ .' \n" +
|
||||
" | (_,_).' __ ___(_ o _)' \n" +
|
||||
" | |\\ \\ | || |(_,_)' \n" +
|
||||
" | | \\ `' /| `-' / \n" +
|
||||
" | | \\ / \\ / \n" +
|
||||
" ''-' `'-' `-..-' ");
|
||||
}
|
||||
}
|
||||
package com.ruoyi;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
|
||||
/**
|
||||
* 启动程序
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
|
||||
public class RuoYiApplication
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
// System.setProperty("spring.devtools.restart.enabled", "false");
|
||||
SpringApplication.run(RuoYiApplication.class, args);
|
||||
System.out.println("(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ \n" +
|
||||
" .-------. ____ __ \n" +
|
||||
" | _ _ \\ \\ \\ / / \n" +
|
||||
" | ( ' ) | \\ _. / ' \n" +
|
||||
" |(_ o _) / _( )_ .' \n" +
|
||||
" | (_,_).' __ ___(_ o _)' \n" +
|
||||
" | |\\ \\ | || |(_,_)' \n" +
|
||||
" | | \\ `' /| `-' / \n" +
|
||||
" | | \\ / \\ / \n" +
|
||||
" ''-' `'-' `-..-' ");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
package com.ruoyi;
|
||||
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
|
||||
/**
|
||||
* web容器中进行部署
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class RuoYiServletInitializer extends SpringBootServletInitializer
|
||||
{
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
|
||||
{
|
||||
return application.sources(RuoYiApplication.class);
|
||||
}
|
||||
}
|
||||
package com.ruoyi;
|
||||
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
|
||||
/**
|
||||
* web容器中进行部署
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class RuoYiServletInitializer extends SpringBootServletInitializer
|
||||
{
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
|
||||
{
|
||||
return application.sources(RuoYiApplication.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,94 +1,94 @@
|
||||
package com.ruoyi.web.controller.common;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import jakarta.annotation.Resource;
|
||||
import javax.imageio.ImageIO;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.FastByteArrayOutputStream;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.google.code.kaptcha.Producer;
|
||||
import com.ruoyi.common.config.RuoYiConfig;
|
||||
import com.ruoyi.common.constant.CacheConstants;
|
||||
import com.ruoyi.common.constant.Constants;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.redis.RedisCache;
|
||||
import com.ruoyi.common.utils.sign.Base64;
|
||||
import com.ruoyi.common.utils.uuid.IdUtils;
|
||||
import com.ruoyi.system.service.ISysConfigService;
|
||||
|
||||
/**
|
||||
* 验证码操作处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
public class CaptchaController
|
||||
{
|
||||
@Resource(name = "captchaProducer")
|
||||
private Producer captchaProducer;
|
||||
|
||||
@Resource(name = "captchaProducerMath")
|
||||
private Producer captchaProducerMath;
|
||||
|
||||
@Autowired
|
||||
private RedisCache redisCache;
|
||||
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
/**
|
||||
* 生成验证码
|
||||
*/
|
||||
@GetMapping("/captchaImage")
|
||||
public AjaxResult getCode(HttpServletResponse response) throws IOException
|
||||
{
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
boolean captchaEnabled = configService.selectCaptchaEnabled();
|
||||
ajax.put("captchaEnabled", captchaEnabled);
|
||||
if (!captchaEnabled)
|
||||
{
|
||||
return ajax;
|
||||
}
|
||||
|
||||
// 保存验证码信息
|
||||
String uuid = IdUtils.simpleUUID();
|
||||
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
|
||||
|
||||
String capStr = null, code = null;
|
||||
BufferedImage image = null;
|
||||
|
||||
// 生成验证码
|
||||
String captchaType = RuoYiConfig.getCaptchaType();
|
||||
if ("math".equals(captchaType))
|
||||
{
|
||||
String capText = captchaProducerMath.createText();
|
||||
capStr = capText.substring(0, capText.lastIndexOf("@"));
|
||||
code = capText.substring(capText.lastIndexOf("@") + 1);
|
||||
image = captchaProducerMath.createImage(capStr);
|
||||
}
|
||||
else if ("char".equals(captchaType))
|
||||
{
|
||||
capStr = code = captchaProducer.createText();
|
||||
image = captchaProducer.createImage(capStr);
|
||||
}
|
||||
|
||||
redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
|
||||
// 转换流信息写出
|
||||
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
|
||||
try
|
||||
{
|
||||
ImageIO.write(image, "jpg", os);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
ajax.put("uuid", uuid);
|
||||
ajax.put("img", Base64.encode(os.toByteArray()));
|
||||
return ajax;
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.common;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.Resource;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.FastByteArrayOutputStream;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.google.code.kaptcha.Producer;
|
||||
import com.ruoyi.common.config.RuoYiConfig;
|
||||
import com.ruoyi.common.constant.CacheConstants;
|
||||
import com.ruoyi.common.constant.Constants;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.redis.RedisCache;
|
||||
import com.ruoyi.common.utils.sign.Base64;
|
||||
import com.ruoyi.common.utils.uuid.IdUtils;
|
||||
import com.ruoyi.system.service.ISysConfigService;
|
||||
|
||||
/**
|
||||
* 验证码操作处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
public class CaptchaController
|
||||
{
|
||||
@Resource(name = "captchaProducer")
|
||||
private Producer captchaProducer;
|
||||
|
||||
@Resource(name = "captchaProducerMath")
|
||||
private Producer captchaProducerMath;
|
||||
|
||||
@Autowired
|
||||
private RedisCache redisCache;
|
||||
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
/**
|
||||
* 生成验证码
|
||||
*/
|
||||
@GetMapping("/captchaImage")
|
||||
public AjaxResult getCode(HttpServletResponse response) throws IOException
|
||||
{
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
boolean captchaEnabled = configService.selectCaptchaEnabled();
|
||||
ajax.put("captchaEnabled", captchaEnabled);
|
||||
if (!captchaEnabled)
|
||||
{
|
||||
return ajax;
|
||||
}
|
||||
|
||||
// 保存验证码信息
|
||||
String uuid = IdUtils.simpleUUID();
|
||||
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
|
||||
|
||||
String capStr = null, code = null;
|
||||
BufferedImage image = null;
|
||||
|
||||
// 生成验证码
|
||||
String captchaType = RuoYiConfig.getCaptchaType();
|
||||
if ("math".equals(captchaType))
|
||||
{
|
||||
String capText = captchaProducerMath.createText();
|
||||
capStr = capText.substring(0, capText.lastIndexOf("@"));
|
||||
code = capText.substring(capText.lastIndexOf("@") + 1);
|
||||
image = captchaProducerMath.createImage(capStr);
|
||||
}
|
||||
else if ("char".equals(captchaType))
|
||||
{
|
||||
capStr = code = captchaProducer.createText();
|
||||
image = captchaProducer.createImage(capStr);
|
||||
}
|
||||
|
||||
redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
|
||||
// 转换流信息写出
|
||||
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
|
||||
try
|
||||
{
|
||||
ImageIO.write(image, "jpg", os);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
ajax.put("uuid", uuid);
|
||||
ajax.put("img", Base64.encode(os.toByteArray()));
|
||||
return ajax;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,162 +1,162 @@
|
||||
package com.ruoyi.web.controller.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.ruoyi.common.config.RuoYiConfig;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.file.FileUploadUtils;
|
||||
import com.ruoyi.common.utils.file.FileUtils;
|
||||
import com.ruoyi.framework.config.ServerConfig;
|
||||
|
||||
/**
|
||||
* 通用请求处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/common")
|
||||
public class CommonController
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(CommonController.class);
|
||||
|
||||
@Autowired
|
||||
private ServerConfig serverConfig;
|
||||
|
||||
private static final String FILE_DELIMITER = ",";
|
||||
|
||||
/**
|
||||
* 通用下载请求
|
||||
*
|
||||
* @param fileName 文件名称
|
||||
* @param delete 是否删除
|
||||
*/
|
||||
@GetMapping("/download")
|
||||
public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!FileUtils.checkAllowDownload(fileName))
|
||||
{
|
||||
throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
|
||||
}
|
||||
String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
|
||||
String filePath = RuoYiConfig.getDownloadPath() + fileName;
|
||||
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
FileUtils.setAttachmentResponseHeader(response, realFileName);
|
||||
FileUtils.writeBytes(filePath, response.getOutputStream());
|
||||
if (delete)
|
||||
{
|
||||
FileUtils.deleteFile(filePath);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error("下载文件失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用上传请求(单个)
|
||||
*/
|
||||
@PostMapping("/upload")
|
||||
public AjaxResult uploadFile(MultipartFile file) throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
// 上传文件路径
|
||||
String filePath = RuoYiConfig.getUploadPath();
|
||||
// 上传并返回新文件名称
|
||||
String fileName = FileUploadUtils.upload(filePath, file);
|
||||
String url = serverConfig.getUrl() + fileName;
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
ajax.put("url", url);
|
||||
ajax.put("fileName", fileName);
|
||||
ajax.put("newFileName", FileUtils.getName(fileName));
|
||||
ajax.put("originalFilename", file.getOriginalFilename());
|
||||
return ajax;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用上传请求(多个)
|
||||
*/
|
||||
@PostMapping("/uploads")
|
||||
public AjaxResult uploadFiles(List<MultipartFile> files) throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
// 上传文件路径
|
||||
String filePath = RuoYiConfig.getUploadPath();
|
||||
List<String> urls = new ArrayList<String>();
|
||||
List<String> fileNames = new ArrayList<String>();
|
||||
List<String> newFileNames = new ArrayList<String>();
|
||||
List<String> originalFilenames = new ArrayList<String>();
|
||||
for (MultipartFile file : files)
|
||||
{
|
||||
// 上传并返回新文件名称
|
||||
String fileName = FileUploadUtils.upload(filePath, file);
|
||||
String url = serverConfig.getUrl() + fileName;
|
||||
urls.add(url);
|
||||
fileNames.add(fileName);
|
||||
newFileNames.add(FileUtils.getName(fileName));
|
||||
originalFilenames.add(file.getOriginalFilename());
|
||||
}
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
ajax.put("urls", StringUtils.join(urls, FILE_DELIMITER));
|
||||
ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMITER));
|
||||
ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMITER));
|
||||
ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMITER));
|
||||
return ajax;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地资源通用下载
|
||||
*/
|
||||
@GetMapping("/download/resource")
|
||||
public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!FileUtils.checkAllowDownload(resource))
|
||||
{
|
||||
throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource));
|
||||
}
|
||||
// 本地资源路径
|
||||
String localPath = RuoYiConfig.getProfile();
|
||||
// 数据库资源地址
|
||||
String downloadPath = localPath + FileUtils.stripPrefix(resource);
|
||||
// 下载名称
|
||||
String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
FileUtils.setAttachmentResponseHeader(response, downloadName);
|
||||
FileUtils.writeBytes(downloadPath, response.getOutputStream());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error("下载文件失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.ruoyi.common.config.RuoYiConfig;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.file.FileUploadUtils;
|
||||
import com.ruoyi.common.utils.file.FileUtils;
|
||||
import com.ruoyi.framework.config.ServerConfig;
|
||||
|
||||
/**
|
||||
* 通用请求处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/common")
|
||||
public class CommonController
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(CommonController.class);
|
||||
|
||||
@Autowired
|
||||
private ServerConfig serverConfig;
|
||||
|
||||
private static final String FILE_DELIMITER = ",";
|
||||
|
||||
/**
|
||||
* 通用下载请求
|
||||
*
|
||||
* @param fileName 文件名称
|
||||
* @param delete 是否删除
|
||||
*/
|
||||
@GetMapping("/download")
|
||||
public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!FileUtils.checkAllowDownload(fileName))
|
||||
{
|
||||
throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
|
||||
}
|
||||
String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
|
||||
String filePath = RuoYiConfig.getDownloadPath() + fileName;
|
||||
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
FileUtils.setAttachmentResponseHeader(response, realFileName);
|
||||
FileUtils.writeBytes(filePath, response.getOutputStream());
|
||||
if (delete)
|
||||
{
|
||||
FileUtils.deleteFile(filePath);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error("下载文件失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用上传请求(单个)
|
||||
*/
|
||||
@PostMapping("/upload")
|
||||
public AjaxResult uploadFile(MultipartFile file) throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
// 上传文件路径
|
||||
String filePath = RuoYiConfig.getUploadPath();
|
||||
// 上传并返回新文件名称
|
||||
String fileName = FileUploadUtils.upload(filePath, file);
|
||||
String url = serverConfig.getUrl() + fileName;
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
ajax.put("url", url);
|
||||
ajax.put("fileName", fileName);
|
||||
ajax.put("newFileName", FileUtils.getName(fileName));
|
||||
ajax.put("originalFilename", file.getOriginalFilename());
|
||||
return ajax;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用上传请求(多个)
|
||||
*/
|
||||
@PostMapping("/uploads")
|
||||
public AjaxResult uploadFiles(List<MultipartFile> files) throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
// 上传文件路径
|
||||
String filePath = RuoYiConfig.getUploadPath();
|
||||
List<String> urls = new ArrayList<String>();
|
||||
List<String> fileNames = new ArrayList<String>();
|
||||
List<String> newFileNames = new ArrayList<String>();
|
||||
List<String> originalFilenames = new ArrayList<String>();
|
||||
for (MultipartFile file : files)
|
||||
{
|
||||
// 上传并返回新文件名称
|
||||
String fileName = FileUploadUtils.upload(filePath, file);
|
||||
String url = serverConfig.getUrl() + fileName;
|
||||
urls.add(url);
|
||||
fileNames.add(fileName);
|
||||
newFileNames.add(FileUtils.getName(fileName));
|
||||
originalFilenames.add(file.getOriginalFilename());
|
||||
}
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
ajax.put("urls", StringUtils.join(urls, FILE_DELIMITER));
|
||||
ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMITER));
|
||||
ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMITER));
|
||||
ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMITER));
|
||||
return ajax;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地资源通用下载
|
||||
*/
|
||||
@GetMapping("/download/resource")
|
||||
public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!FileUtils.checkAllowDownload(resource))
|
||||
{
|
||||
throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource));
|
||||
}
|
||||
// 本地资源路径
|
||||
String localPath = RuoYiConfig.getProfile();
|
||||
// 数据库资源地址
|
||||
String downloadPath = localPath + FileUtils.stripPrefix(resource);
|
||||
// 下载名称
|
||||
String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
FileUtils.setAttachmentResponseHeader(response, downloadName);
|
||||
FileUtils.writeBytes(downloadPath, response.getOutputStream());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error("下载文件失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,13 @@ import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.redis.RedisCache;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.system.domain.SysCache;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
@@ -15,33 +22,24 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 缓存监控
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/monitor/cache")
|
||||
public class CacheController
|
||||
{
|
||||
private final RedisCache redisCache;
|
||||
|
||||
private final static List<SysCache> caches = new ArrayList<SysCache>();
|
||||
private static final List<SysCache> CACHES = new ArrayList<SysCache>();
|
||||
|
||||
static
|
||||
{
|
||||
caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "用户信息"));
|
||||
caches.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "配置信息"));
|
||||
caches.add(new SysCache(CacheConstants.SYS_DICT_KEY, "数据字典"));
|
||||
caches.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码"));
|
||||
caches.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交"));
|
||||
caches.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理"));
|
||||
caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数"));
|
||||
CACHES.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "用户信息"));
|
||||
CACHES.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "配置信息"));
|
||||
CACHES.add(new SysCache(CacheConstants.SYS_DICT_KEY, "数据字典"));
|
||||
CACHES.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码"));
|
||||
CACHES.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交"));
|
||||
CACHES.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理"));
|
||||
CACHES.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数"));
|
||||
}
|
||||
|
||||
public CacheController(RedisCache redisCache)
|
||||
@@ -55,23 +53,23 @@ public class CacheController
|
||||
{
|
||||
InMemoryCacheStats stats = redisCache.getCacheStats();
|
||||
Map<String, Object> info = new LinkedHashMap<>();
|
||||
info.put("cache_type", stats.cacheType());
|
||||
info.put("cache_mode", stats.mode());
|
||||
info.put("key_size", stats.keySize());
|
||||
info.put("hit_count", stats.hitCount());
|
||||
info.put("miss_count", stats.missCount());
|
||||
info.put("expired_count", stats.expiredCount());
|
||||
info.put("write_count", stats.writeCount());
|
||||
info.put("cache_type", stats.getCacheType());
|
||||
info.put("cache_mode", stats.getMode());
|
||||
info.put("key_size", stats.getKeySize());
|
||||
info.put("hit_count", stats.getHitCount());
|
||||
info.put("miss_count", stats.getMissCount());
|
||||
info.put("expired_count", stats.getExpiredCount());
|
||||
info.put("write_count", stats.getWriteCount());
|
||||
|
||||
Map<String, Object> result = new HashMap<>(3);
|
||||
result.put("info", info);
|
||||
result.put("dbSize", stats.keySize());
|
||||
result.put("dbSize", stats.getKeySize());
|
||||
|
||||
List<Map<String, String>> pieList = new ArrayList<>();
|
||||
pieList.add(statEntry("hit_count", stats.hitCount()));
|
||||
pieList.add(statEntry("miss_count", stats.missCount()));
|
||||
pieList.add(statEntry("expired_count", stats.expiredCount()));
|
||||
pieList.add(statEntry("write_count", stats.writeCount()));
|
||||
pieList.add(statEntry("hit_count", stats.getHitCount()));
|
||||
pieList.add(statEntry("miss_count", stats.getMissCount()));
|
||||
pieList.add(statEntry("expired_count", stats.getExpiredCount()));
|
||||
pieList.add(statEntry("write_count", stats.getWriteCount()));
|
||||
result.put("commandStats", pieList);
|
||||
return AjaxResult.success(result);
|
||||
}
|
||||
@@ -80,7 +78,7 @@ public class CacheController
|
||||
@GetMapping("/getNames")
|
||||
public AjaxResult cache()
|
||||
{
|
||||
return AjaxResult.success(caches);
|
||||
return AjaxResult.success(CACHES);
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
|
||||
@@ -139,9 +137,9 @@ public class CacheController
|
||||
{
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
if (cacheValue instanceof String stringValue)
|
||||
if (cacheValue instanceof String)
|
||||
{
|
||||
return stringValue;
|
||||
return (String) cacheValue;
|
||||
}
|
||||
return JSON.toJSONString(cacheValue);
|
||||
}
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
package com.ruoyi.web.controller.monitor;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.framework.web.domain.Server;
|
||||
|
||||
/**
|
||||
* 服务器监控
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/monitor/server")
|
||||
public class ServerController
|
||||
{
|
||||
@PreAuthorize("@ss.hasPermi('monitor:server:list')")
|
||||
@GetMapping()
|
||||
public AjaxResult getInfo() throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
server.copyTo();
|
||||
return AjaxResult.success(server);
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.monitor;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.framework.web.domain.Server;
|
||||
|
||||
/**
|
||||
* 服务器监控
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/monitor/server")
|
||||
public class ServerController
|
||||
{
|
||||
@PreAuthorize("@ss.hasPermi('monitor:server:list')")
|
||||
@GetMapping()
|
||||
public AjaxResult getInfo() throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
server.copyTo();
|
||||
return AjaxResult.success(server);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,82 +1,82 @@
|
||||
package com.ruoyi.web.controller.monitor;
|
||||
|
||||
import java.util.List;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.framework.web.service.SysPasswordService;
|
||||
import com.ruoyi.system.domain.SysLogininfor;
|
||||
import com.ruoyi.system.service.ISysLogininforService;
|
||||
|
||||
/**
|
||||
* 系统访问记录
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/monitor/logininfor")
|
||||
public class SysLogininforController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysLogininforService logininforService;
|
||||
|
||||
@Autowired
|
||||
private SysPasswordService passwordService;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('monitor:logininfor:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysLogininfor logininfor)
|
||||
{
|
||||
startPage();
|
||||
List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@Log(title = "登录日志", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('monitor:logininfor:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysLogininfor logininfor)
|
||||
{
|
||||
List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
|
||||
ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
|
||||
util.exportExcel(response, list, "登录日志");
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
|
||||
@Log(title = "登录日志", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{infoIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] infoIds)
|
||||
{
|
||||
return toAjax(logininforService.deleteLogininforByIds(infoIds));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
|
||||
@Log(title = "登录日志", businessType = BusinessType.CLEAN)
|
||||
@DeleteMapping("/clean")
|
||||
public AjaxResult clean()
|
||||
{
|
||||
logininforService.cleanLogininfor();
|
||||
return success();
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('monitor:logininfor:unlock')")
|
||||
@Log(title = "账户解锁", businessType = BusinessType.OTHER)
|
||||
@GetMapping("/unlock/{userName}")
|
||||
public AjaxResult unlock(@PathVariable("userName") String userName)
|
||||
{
|
||||
passwordService.clearLoginRecordCache(userName);
|
||||
return success();
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.monitor;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.framework.web.service.SysPasswordService;
|
||||
import com.ruoyi.system.domain.SysLogininfor;
|
||||
import com.ruoyi.system.service.ISysLogininforService;
|
||||
|
||||
/**
|
||||
* 系统访问记录
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/monitor/logininfor")
|
||||
public class SysLogininforController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysLogininforService logininforService;
|
||||
|
||||
@Autowired
|
||||
private SysPasswordService passwordService;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('monitor:logininfor:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysLogininfor logininfor)
|
||||
{
|
||||
startPage();
|
||||
List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@Log(title = "登录日志", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('monitor:logininfor:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysLogininfor logininfor)
|
||||
{
|
||||
List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
|
||||
ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
|
||||
util.exportExcel(response, list, "登录日志");
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
|
||||
@Log(title = "登录日志", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{infoIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] infoIds)
|
||||
{
|
||||
return toAjax(logininforService.deleteLogininforByIds(infoIds));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
|
||||
@Log(title = "登录日志", businessType = BusinessType.CLEAN)
|
||||
@DeleteMapping("/clean")
|
||||
public AjaxResult clean()
|
||||
{
|
||||
logininforService.cleanLogininfor();
|
||||
return success();
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('monitor:logininfor:unlock')")
|
||||
@Log(title = "账户解锁", businessType = BusinessType.OTHER)
|
||||
@GetMapping("/unlock/{userName}")
|
||||
public AjaxResult unlock(@PathVariable("userName") String userName)
|
||||
{
|
||||
passwordService.clearLoginRecordCache(userName);
|
||||
return success();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,69 +1,69 @@
|
||||
package com.ruoyi.web.controller.monitor;
|
||||
|
||||
import java.util.List;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.system.domain.SysOperLog;
|
||||
import com.ruoyi.system.service.ISysOperLogService;
|
||||
|
||||
/**
|
||||
* 操作日志记录
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/monitor/operlog")
|
||||
public class SysOperlogController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysOperLogService operLogService;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('monitor:operlog:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysOperLog operLog)
|
||||
{
|
||||
startPage();
|
||||
List<SysOperLog> list = operLogService.selectOperLogList(operLog);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@Log(title = "操作日志", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('monitor:operlog:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysOperLog operLog)
|
||||
{
|
||||
List<SysOperLog> list = operLogService.selectOperLogList(operLog);
|
||||
ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
|
||||
util.exportExcel(response, list, "操作日志");
|
||||
}
|
||||
|
||||
@Log(title = "操作日志", businessType = BusinessType.DELETE)
|
||||
@PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
|
||||
@DeleteMapping("/{operIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] operIds)
|
||||
{
|
||||
return toAjax(operLogService.deleteOperLogByIds(operIds));
|
||||
}
|
||||
|
||||
@Log(title = "操作日志", businessType = BusinessType.CLEAN)
|
||||
@PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
|
||||
@DeleteMapping("/clean")
|
||||
public AjaxResult clean()
|
||||
{
|
||||
operLogService.cleanOperLog();
|
||||
return success();
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.monitor;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.system.domain.SysOperLog;
|
||||
import com.ruoyi.system.service.ISysOperLogService;
|
||||
|
||||
/**
|
||||
* 操作日志记录
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/monitor/operlog")
|
||||
public class SysOperlogController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysOperLogService operLogService;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('monitor:operlog:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysOperLog operLog)
|
||||
{
|
||||
startPage();
|
||||
List<SysOperLog> list = operLogService.selectOperLogList(operLog);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@Log(title = "操作日志", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('monitor:operlog:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysOperLog operLog)
|
||||
{
|
||||
List<SysOperLog> list = operLogService.selectOperLogList(operLog);
|
||||
ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
|
||||
util.exportExcel(response, list, "操作日志");
|
||||
}
|
||||
|
||||
@Log(title = "操作日志", businessType = BusinessType.DELETE)
|
||||
@PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
|
||||
@DeleteMapping("/{operIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] operIds)
|
||||
{
|
||||
return toAjax(operLogService.deleteOperLogByIds(operIds));
|
||||
}
|
||||
|
||||
@Log(title = "操作日志", businessType = BusinessType.CLEAN)
|
||||
@PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
|
||||
@DeleteMapping("/clean")
|
||||
public AjaxResult clean()
|
||||
{
|
||||
operLogService.cleanOperLog();
|
||||
return success();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,83 +1,83 @@
|
||||
package com.ruoyi.web.controller.monitor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.constant.CacheConstants;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.core.redis.RedisCache;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.system.domain.SysUserOnline;
|
||||
import com.ruoyi.system.service.ISysUserOnlineService;
|
||||
|
||||
/**
|
||||
* 在线用户监控
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/monitor/online")
|
||||
public class SysUserOnlineController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysUserOnlineService userOnlineService;
|
||||
|
||||
@Autowired
|
||||
private RedisCache redisCache;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('monitor:online:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(String ipaddr, String userName)
|
||||
{
|
||||
Collection<String> keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
|
||||
List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
|
||||
for (String key : keys)
|
||||
{
|
||||
LoginUser user = redisCache.getCacheObject(key);
|
||||
if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
|
||||
{
|
||||
userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(ipaddr))
|
||||
{
|
||||
userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
|
||||
{
|
||||
userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
|
||||
}
|
||||
else
|
||||
{
|
||||
userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
|
||||
}
|
||||
}
|
||||
Collections.reverse(userOnlineList);
|
||||
userOnlineList.removeAll(Collections.singleton(null));
|
||||
return getDataTable(userOnlineList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 强退用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')")
|
||||
@Log(title = "在线用户", businessType = BusinessType.FORCE)
|
||||
@DeleteMapping("/{tokenId}")
|
||||
public AjaxResult forceLogout(@PathVariable String tokenId)
|
||||
{
|
||||
redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
|
||||
return success();
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.monitor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.constant.CacheConstants;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.core.redis.RedisCache;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.system.domain.SysUserOnline;
|
||||
import com.ruoyi.system.service.ISysUserOnlineService;
|
||||
|
||||
/**
|
||||
* 在线用户监控
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/monitor/online")
|
||||
public class SysUserOnlineController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysUserOnlineService userOnlineService;
|
||||
|
||||
@Autowired
|
||||
private RedisCache redisCache;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('monitor:online:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(String ipaddr, String userName)
|
||||
{
|
||||
Collection<String> keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
|
||||
List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
|
||||
for (String key : keys)
|
||||
{
|
||||
LoginUser user = redisCache.getCacheObject(key);
|
||||
if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
|
||||
{
|
||||
userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(ipaddr))
|
||||
{
|
||||
userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
|
||||
{
|
||||
userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
|
||||
}
|
||||
else
|
||||
{
|
||||
userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
|
||||
}
|
||||
}
|
||||
Collections.reverse(userOnlineList);
|
||||
userOnlineList.removeAll(Collections.singleton(null));
|
||||
return getDataTable(userOnlineList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 强退用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')")
|
||||
@Log(title = "在线用户", businessType = BusinessType.FORCE)
|
||||
@DeleteMapping("/{tokenId}")
|
||||
public AjaxResult forceLogout(@PathVariable String tokenId)
|
||||
{
|
||||
redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
|
||||
return success();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,133 +1,133 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.List;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.system.domain.SysConfig;
|
||||
import com.ruoyi.system.service.ISysConfigService;
|
||||
|
||||
/**
|
||||
* 参数配置 信息操作处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/config")
|
||||
public class SysConfigController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
|
||||
/**
|
||||
* 获取参数配置列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:config:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysConfig config)
|
||||
{
|
||||
startPage();
|
||||
List<SysConfig> list = configService.selectConfigList(config);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@Log(title = "参数管理", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('system:config:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysConfig config)
|
||||
{
|
||||
List<SysConfig> list = configService.selectConfigList(config);
|
||||
ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);
|
||||
util.exportExcel(response, list, "参数数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据参数编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:config:query')")
|
||||
@GetMapping(value = "/{configId}")
|
||||
public AjaxResult getInfo(@PathVariable Long configId)
|
||||
{
|
||||
return success(configService.selectConfigById(configId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据参数键名查询参数值
|
||||
*/
|
||||
@GetMapping(value = "/configKey/{configKey}")
|
||||
public AjaxResult getConfigKey(@PathVariable String configKey)
|
||||
{
|
||||
return success(configService.selectConfigByKey(configKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增参数配置
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:config:add')")
|
||||
@Log(title = "参数管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysConfig config)
|
||||
{
|
||||
if (!configService.checkConfigKeyUnique(config))
|
||||
{
|
||||
return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
|
||||
}
|
||||
config.setCreateBy(getUsername());
|
||||
return toAjax(configService.insertConfig(config));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改参数配置
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:config:edit')")
|
||||
@Log(title = "参数管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysConfig config)
|
||||
{
|
||||
if (!configService.checkConfigKeyUnique(config))
|
||||
{
|
||||
return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
|
||||
}
|
||||
config.setUpdateBy(getUsername());
|
||||
return toAjax(configService.updateConfig(config));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除参数配置
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:config:remove')")
|
||||
@Log(title = "参数管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{configIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] configIds)
|
||||
{
|
||||
configService.deleteConfigByIds(configIds);
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新参数缓存
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:config:remove')")
|
||||
@Log(title = "参数管理", businessType = BusinessType.CLEAN)
|
||||
@DeleteMapping("/refreshCache")
|
||||
public AjaxResult refreshCache()
|
||||
{
|
||||
configService.resetConfigCache();
|
||||
return success();
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.system.domain.SysConfig;
|
||||
import com.ruoyi.system.service.ISysConfigService;
|
||||
|
||||
/**
|
||||
* 参数配置 信息操作处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/config")
|
||||
public class SysConfigController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
|
||||
/**
|
||||
* 获取参数配置列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:config:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysConfig config)
|
||||
{
|
||||
startPage();
|
||||
List<SysConfig> list = configService.selectConfigList(config);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@Log(title = "参数管理", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('system:config:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysConfig config)
|
||||
{
|
||||
List<SysConfig> list = configService.selectConfigList(config);
|
||||
ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);
|
||||
util.exportExcel(response, list, "参数数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据参数编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:config:query')")
|
||||
@GetMapping(value = "/{configId}")
|
||||
public AjaxResult getInfo(@PathVariable Long configId)
|
||||
{
|
||||
return success(configService.selectConfigById(configId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据参数键名查询参数值
|
||||
*/
|
||||
@GetMapping(value = "/configKey/{configKey}")
|
||||
public AjaxResult getConfigKey(@PathVariable String configKey)
|
||||
{
|
||||
return success(configService.selectConfigByKey(configKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增参数配置
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:config:add')")
|
||||
@Log(title = "参数管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysConfig config)
|
||||
{
|
||||
if (!configService.checkConfigKeyUnique(config))
|
||||
{
|
||||
return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
|
||||
}
|
||||
config.setCreateBy(getUsername());
|
||||
return toAjax(configService.insertConfig(config));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改参数配置
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:config:edit')")
|
||||
@Log(title = "参数管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysConfig config)
|
||||
{
|
||||
if (!configService.checkConfigKeyUnique(config))
|
||||
{
|
||||
return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
|
||||
}
|
||||
config.setUpdateBy(getUsername());
|
||||
return toAjax(configService.updateConfig(config));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除参数配置
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:config:remove')")
|
||||
@Log(title = "参数管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{configIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] configIds)
|
||||
{
|
||||
configService.deleteConfigByIds(configIds);
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新参数缓存
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:config:remove')")
|
||||
@Log(title = "参数管理", businessType = BusinessType.CLEAN)
|
||||
@DeleteMapping("/refreshCache")
|
||||
public AjaxResult refreshCache()
|
||||
{
|
||||
configService.resetConfigCache();
|
||||
return success();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,132 +1,147 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.constant.UserConstants;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysDept;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.system.service.ISysDeptService;
|
||||
|
||||
/**
|
||||
* 部门信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/dept")
|
||||
public class SysDeptController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysDeptService deptService;
|
||||
|
||||
/**
|
||||
* 获取部门列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dept:list')")
|
||||
@GetMapping("/list")
|
||||
public AjaxResult list(SysDept dept)
|
||||
{
|
||||
List<SysDept> depts = deptService.selectDeptList(dept);
|
||||
return success(depts);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询部门列表(排除节点)
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dept:list')")
|
||||
@GetMapping("/list/exclude/{deptId}")
|
||||
public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId)
|
||||
{
|
||||
List<SysDept> depts = deptService.selectDeptList(new SysDept());
|
||||
depts.removeIf(d -> d.getDeptId().intValue() == deptId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + ""));
|
||||
return success(depts);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dept:query')")
|
||||
@GetMapping(value = "/{deptId}")
|
||||
public AjaxResult getInfo(@PathVariable Long deptId)
|
||||
{
|
||||
deptService.checkDeptDataScope(deptId);
|
||||
return success(deptService.selectDeptById(deptId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增部门
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dept:add')")
|
||||
@Log(title = "部门管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysDept dept)
|
||||
{
|
||||
if (!deptService.checkDeptNameUnique(dept))
|
||||
{
|
||||
return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
|
||||
}
|
||||
dept.setCreateBy(getUsername());
|
||||
return toAjax(deptService.insertDept(dept));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改部门
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dept:edit')")
|
||||
@Log(title = "部门管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysDept dept)
|
||||
{
|
||||
Long deptId = dept.getDeptId();
|
||||
deptService.checkDeptDataScope(deptId);
|
||||
if (!deptService.checkDeptNameUnique(dept))
|
||||
{
|
||||
return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
|
||||
}
|
||||
else if (dept.getParentId().equals(deptId))
|
||||
{
|
||||
return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
|
||||
}
|
||||
else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0)
|
||||
{
|
||||
return error("该部门包含未停用的子部门!");
|
||||
}
|
||||
dept.setUpdateBy(getUsername());
|
||||
return toAjax(deptService.updateDept(dept));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除部门
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dept:remove')")
|
||||
@Log(title = "部门管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{deptId}")
|
||||
public AjaxResult remove(@PathVariable Long deptId)
|
||||
{
|
||||
if (deptService.hasChildByDeptId(deptId))
|
||||
{
|
||||
return warn("存在下级部门,不允许删除");
|
||||
}
|
||||
if (deptService.checkDeptExistUser(deptId))
|
||||
{
|
||||
return warn("部门存在用户,不允许删除");
|
||||
}
|
||||
deptService.checkDeptDataScope(deptId);
|
||||
return toAjax(deptService.deleteDeptById(deptId));
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.constant.UserConstants;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysDept;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.system.service.ISysDeptService;
|
||||
|
||||
/**
|
||||
* 部门信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/dept")
|
||||
public class SysDeptController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysDeptService deptService;
|
||||
|
||||
/**
|
||||
* 获取部门列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dept:list')")
|
||||
@GetMapping("/list")
|
||||
public AjaxResult list(SysDept dept)
|
||||
{
|
||||
List<SysDept> depts = deptService.selectDeptList(dept);
|
||||
return success(depts);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询部门列表(排除节点)
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dept:list')")
|
||||
@GetMapping("/list/exclude/{deptId}")
|
||||
public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId)
|
||||
{
|
||||
List<SysDept> depts = deptService.selectDeptList(new SysDept());
|
||||
depts.removeIf(d -> d.getDeptId().intValue() == deptId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + ""));
|
||||
return success(depts);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dept:query')")
|
||||
@GetMapping(value = "/{deptId}")
|
||||
public AjaxResult getInfo(@PathVariable Long deptId)
|
||||
{
|
||||
deptService.checkDeptDataScope(deptId);
|
||||
return success(deptService.selectDeptById(deptId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增部门
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dept:add')")
|
||||
@Log(title = "部门管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysDept dept)
|
||||
{
|
||||
if (!deptService.checkDeptNameUnique(dept))
|
||||
{
|
||||
return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
|
||||
}
|
||||
dept.setCreateBy(getUsername());
|
||||
return toAjax(deptService.insertDept(dept));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改部门
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dept:edit')")
|
||||
@Log(title = "部门管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysDept dept)
|
||||
{
|
||||
Long deptId = dept.getDeptId();
|
||||
deptService.checkDeptDataScope(deptId);
|
||||
if (!deptService.checkDeptNameUnique(dept))
|
||||
{
|
||||
return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
|
||||
}
|
||||
else if (dept.getParentId().equals(deptId))
|
||||
{
|
||||
return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
|
||||
}
|
||||
else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0)
|
||||
{
|
||||
return error("该部门包含未停用的子部门!");
|
||||
}
|
||||
dept.setUpdateBy(getUsername());
|
||||
return toAjax(deptService.updateDept(dept));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存部门排序
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dept:edit')")
|
||||
@Log(title = "保存部门排序", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/updateSort")
|
||||
public AjaxResult updateSort(@RequestBody Map<String, String> params)
|
||||
{
|
||||
String[] deptIds = params.get("deptIds").split(",");
|
||||
String[] orderNums = params.get("orderNums").split(",");
|
||||
deptService.updateDeptSort(deptIds, orderNums);
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除部门
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dept:remove')")
|
||||
@Log(title = "部门管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{deptId}")
|
||||
public AjaxResult remove(@PathVariable Long deptId)
|
||||
{
|
||||
if (deptService.hasChildByDeptId(deptId))
|
||||
{
|
||||
return warn("存在下级部门,不允许删除");
|
||||
}
|
||||
if (deptService.checkDeptExistUser(deptId))
|
||||
{
|
||||
return warn("部门存在用户,不允许删除");
|
||||
}
|
||||
deptService.checkDeptDataScope(deptId);
|
||||
return toAjax(deptService.deleteDeptById(deptId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,121 +1,121 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysDictData;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.system.service.ISysDictDataService;
|
||||
import com.ruoyi.system.service.ISysDictTypeService;
|
||||
|
||||
/**
|
||||
* 数据字典信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/dict/data")
|
||||
public class SysDictDataController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysDictDataService dictDataService;
|
||||
|
||||
@Autowired
|
||||
private ISysDictTypeService dictTypeService;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysDictData dictData)
|
||||
{
|
||||
startPage();
|
||||
List<SysDictData> list = dictDataService.selectDictDataList(dictData);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@Log(title = "字典数据", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysDictData dictData)
|
||||
{
|
||||
List<SysDictData> list = dictDataService.selectDictDataList(dictData);
|
||||
ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class);
|
||||
util.exportExcel(response, list, "字典数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询字典数据详细
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:query')")
|
||||
@GetMapping(value = "/{dictCode}")
|
||||
public AjaxResult getInfo(@PathVariable Long dictCode)
|
||||
{
|
||||
return success(dictDataService.selectDictDataById(dictCode));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字典类型查询字典数据信息
|
||||
*/
|
||||
@GetMapping(value = "/type/{dictType}")
|
||||
public AjaxResult dictType(@PathVariable String dictType)
|
||||
{
|
||||
List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
|
||||
if (StringUtils.isNull(data))
|
||||
{
|
||||
data = new ArrayList<SysDictData>();
|
||||
}
|
||||
return success(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增字典类型
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:add')")
|
||||
@Log(title = "字典数据", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysDictData dict)
|
||||
{
|
||||
dict.setCreateBy(getUsername());
|
||||
return toAjax(dictDataService.insertDictData(dict));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改保存字典类型
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:edit')")
|
||||
@Log(title = "字典数据", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysDictData dict)
|
||||
{
|
||||
dict.setUpdateBy(getUsername());
|
||||
return toAjax(dictDataService.updateDictData(dict));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除字典类型
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:remove')")
|
||||
@Log(title = "字典类型", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{dictCodes}")
|
||||
public AjaxResult remove(@PathVariable Long[] dictCodes)
|
||||
{
|
||||
dictDataService.deleteDictDataByIds(dictCodes);
|
||||
return success();
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysDictData;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.system.service.ISysDictDataService;
|
||||
import com.ruoyi.system.service.ISysDictTypeService;
|
||||
|
||||
/**
|
||||
* 数据字典信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/dict/data")
|
||||
public class SysDictDataController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysDictDataService dictDataService;
|
||||
|
||||
@Autowired
|
||||
private ISysDictTypeService dictTypeService;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysDictData dictData)
|
||||
{
|
||||
startPage();
|
||||
List<SysDictData> list = dictDataService.selectDictDataList(dictData);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@Log(title = "字典数据", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysDictData dictData)
|
||||
{
|
||||
List<SysDictData> list = dictDataService.selectDictDataList(dictData);
|
||||
ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class);
|
||||
util.exportExcel(response, list, "字典数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询字典数据详细
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:query')")
|
||||
@GetMapping(value = "/{dictCode}")
|
||||
public AjaxResult getInfo(@PathVariable Long dictCode)
|
||||
{
|
||||
return success(dictDataService.selectDictDataById(dictCode));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字典类型查询字典数据信息
|
||||
*/
|
||||
@GetMapping(value = "/type/{dictType}")
|
||||
public AjaxResult dictType(@PathVariable String dictType)
|
||||
{
|
||||
List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
|
||||
if (StringUtils.isNull(data))
|
||||
{
|
||||
data = new ArrayList<SysDictData>();
|
||||
}
|
||||
return success(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增字典类型
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:add')")
|
||||
@Log(title = "字典数据", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysDictData dict)
|
||||
{
|
||||
dict.setCreateBy(getUsername());
|
||||
return toAjax(dictDataService.insertDictData(dict));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改保存字典类型
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:edit')")
|
||||
@Log(title = "字典数据", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysDictData dict)
|
||||
{
|
||||
dict.setUpdateBy(getUsername());
|
||||
return toAjax(dictDataService.updateDictData(dict));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除字典类型
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:remove')")
|
||||
@Log(title = "字典类型", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{dictCodes}")
|
||||
public AjaxResult remove(@PathVariable Long[] dictCodes)
|
||||
{
|
||||
dictDataService.deleteDictDataByIds(dictCodes);
|
||||
return success();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,131 +1,131 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.List;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysDictType;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.system.service.ISysDictTypeService;
|
||||
|
||||
/**
|
||||
* 数据字典信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/dict/type")
|
||||
public class SysDictTypeController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysDictTypeService dictTypeService;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysDictType dictType)
|
||||
{
|
||||
startPage();
|
||||
List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@Log(title = "字典类型", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysDictType dictType)
|
||||
{
|
||||
List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
|
||||
ExcelUtil<SysDictType> util = new ExcelUtil<SysDictType>(SysDictType.class);
|
||||
util.exportExcel(response, list, "字典类型");
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询字典类型详细
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:query')")
|
||||
@GetMapping(value = "/{dictId}")
|
||||
public AjaxResult getInfo(@PathVariable Long dictId)
|
||||
{
|
||||
return success(dictTypeService.selectDictTypeById(dictId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增字典类型
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:add')")
|
||||
@Log(title = "字典类型", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysDictType dict)
|
||||
{
|
||||
if (!dictTypeService.checkDictTypeUnique(dict))
|
||||
{
|
||||
return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
|
||||
}
|
||||
dict.setCreateBy(getUsername());
|
||||
return toAjax(dictTypeService.insertDictType(dict));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改字典类型
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:edit')")
|
||||
@Log(title = "字典类型", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysDictType dict)
|
||||
{
|
||||
if (!dictTypeService.checkDictTypeUnique(dict))
|
||||
{
|
||||
return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
|
||||
}
|
||||
dict.setUpdateBy(getUsername());
|
||||
return toAjax(dictTypeService.updateDictType(dict));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除字典类型
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:remove')")
|
||||
@Log(title = "字典类型", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{dictIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] dictIds)
|
||||
{
|
||||
dictTypeService.deleteDictTypeByIds(dictIds);
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新字典缓存
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:remove')")
|
||||
@Log(title = "字典类型", businessType = BusinessType.CLEAN)
|
||||
@DeleteMapping("/refreshCache")
|
||||
public AjaxResult refreshCache()
|
||||
{
|
||||
dictTypeService.resetDictCache();
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字典选择框列表
|
||||
*/
|
||||
@GetMapping("/optionselect")
|
||||
public AjaxResult optionselect()
|
||||
{
|
||||
List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll();
|
||||
return success(dictTypes);
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysDictType;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.system.service.ISysDictTypeService;
|
||||
|
||||
/**
|
||||
* 数据字典信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/dict/type")
|
||||
public class SysDictTypeController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysDictTypeService dictTypeService;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysDictType dictType)
|
||||
{
|
||||
startPage();
|
||||
List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@Log(title = "字典类型", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysDictType dictType)
|
||||
{
|
||||
List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
|
||||
ExcelUtil<SysDictType> util = new ExcelUtil<SysDictType>(SysDictType.class);
|
||||
util.exportExcel(response, list, "字典类型");
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询字典类型详细
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:query')")
|
||||
@GetMapping(value = "/{dictId}")
|
||||
public AjaxResult getInfo(@PathVariable Long dictId)
|
||||
{
|
||||
return success(dictTypeService.selectDictTypeById(dictId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增字典类型
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:add')")
|
||||
@Log(title = "字典类型", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysDictType dict)
|
||||
{
|
||||
if (!dictTypeService.checkDictTypeUnique(dict))
|
||||
{
|
||||
return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
|
||||
}
|
||||
dict.setCreateBy(getUsername());
|
||||
return toAjax(dictTypeService.insertDictType(dict));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改字典类型
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:edit')")
|
||||
@Log(title = "字典类型", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysDictType dict)
|
||||
{
|
||||
if (!dictTypeService.checkDictTypeUnique(dict))
|
||||
{
|
||||
return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
|
||||
}
|
||||
dict.setUpdateBy(getUsername());
|
||||
return toAjax(dictTypeService.updateDictType(dict));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除字典类型
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:remove')")
|
||||
@Log(title = "字典类型", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{dictIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] dictIds)
|
||||
{
|
||||
dictTypeService.deleteDictTypeByIds(dictIds);
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新字典缓存
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:remove')")
|
||||
@Log(title = "字典类型", businessType = BusinessType.CLEAN)
|
||||
@DeleteMapping("/refreshCache")
|
||||
public AjaxResult refreshCache()
|
||||
{
|
||||
dictTypeService.resetDictCache();
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字典选择框列表
|
||||
*/
|
||||
@GetMapping("/optionselect")
|
||||
public AjaxResult optionselect()
|
||||
{
|
||||
List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll();
|
||||
return success(dictTypes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,64 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.config.RuoYiConfig;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* 首页
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
public class SysIndexController
|
||||
{
|
||||
/** 系统基础配置 */
|
||||
@Autowired
|
||||
private RuoYiConfig ruoyiConfig;
|
||||
|
||||
/**
|
||||
* 访问首页,提示语
|
||||
*/
|
||||
@RequestMapping("/")
|
||||
public String index()
|
||||
{
|
||||
return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion());
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.Map;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.config.RuoYiConfig;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
|
||||
/**
|
||||
* 首页
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
public class SysIndexController
|
||||
{
|
||||
/** 系统基础配置 */
|
||||
@Autowired
|
||||
private RuoYiConfig ruoyiConfig;
|
||||
|
||||
@Autowired
|
||||
private ISysUserService userService;
|
||||
|
||||
/**
|
||||
* 访问首页,提示语
|
||||
*/
|
||||
@RequestMapping("/")
|
||||
public String index()
|
||||
{
|
||||
return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
* 解锁屏幕
|
||||
*/
|
||||
@PostMapping("/unlockscreen")
|
||||
public AjaxResult unlockScreen(@RequestBody Map<String, String> body)
|
||||
{
|
||||
String password = body.get("password");
|
||||
if (StringUtils.isEmpty(password))
|
||||
{
|
||||
return AjaxResult.error("密码不能为空");
|
||||
}
|
||||
String username = SecurityUtils.getUsername();
|
||||
SysUser user = userService.selectUserByUserName(username);
|
||||
if (user == null)
|
||||
{
|
||||
return AjaxResult.error("服务器超时,请重新登录");
|
||||
}
|
||||
if (!SecurityUtils.matchesPassword(password, user.getPassword()))
|
||||
{
|
||||
return AjaxResult.error("密码错误,请重新输入");
|
||||
}
|
||||
|
||||
return AjaxResult.success("解锁成功");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,152 +1,131 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.constant.Constants;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysMenu;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.domain.model.LoginBody;
|
||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.core.text.Convert;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.framework.web.service.PasswordTransferCryptoService;
|
||||
import com.ruoyi.framework.web.service.SysLoginService;
|
||||
import com.ruoyi.framework.web.service.SysPermissionService;
|
||||
import com.ruoyi.framework.web.service.TokenService;
|
||||
import com.ruoyi.system.service.ISysConfigService;
|
||||
import com.ruoyi.system.service.ISysMenuService;
|
||||
|
||||
/**
|
||||
* 登录验证
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
public class SysLoginController
|
||||
{
|
||||
@Autowired
|
||||
private SysLoginService loginService;
|
||||
|
||||
@Autowired
|
||||
private ISysMenuService menuService;
|
||||
|
||||
@Autowired
|
||||
private SysPermissionService permissionService;
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
|
||||
@Autowired
|
||||
private PasswordTransferCryptoService passwordTransferCryptoService;
|
||||
|
||||
/**
|
||||
* 登录方法
|
||||
*
|
||||
* @param loginBody 登录信息
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping("/login")
|
||||
public AjaxResult login(@RequestBody LoginBody loginBody)
|
||||
{
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
loginBody.setPassword(passwordTransferCryptoService.decrypt(loginBody.getPassword()));
|
||||
// 生成令牌
|
||||
String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
|
||||
loginBody.getUuid());
|
||||
ajax.put(Constants.TOKEN, token);
|
||||
return ajax;
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录方法
|
||||
* 该方法处理用户登录请求,无需验证码
|
||||
* @param loginBody 登录信息,包含用户名和密码
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping("/login/test")
|
||||
public AjaxResult loginWithoutCaptcha (@RequestBody LoginBody loginBody)
|
||||
{
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
// 生成令牌
|
||||
String token = loginService.loginWithoutCaptcha(loginBody.getUsername(), loginBody.getPassword());
|
||||
ajax.put(Constants.TOKEN, token);
|
||||
return ajax;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*
|
||||
* @return 用户信息
|
||||
*/
|
||||
@GetMapping("getInfo")
|
||||
public AjaxResult getInfo()
|
||||
{
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
SysUser user = loginUser.getUser();
|
||||
// 角色集合
|
||||
Set<String> roles = permissionService.getRolePermission(user);
|
||||
// 权限集合
|
||||
Set<String> permissions = permissionService.getMenuPermission(user);
|
||||
if (!loginUser.getPermissions().equals(permissions))
|
||||
{
|
||||
loginUser.setPermissions(permissions);
|
||||
tokenService.refreshToken(loginUser);
|
||||
}
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
ajax.put("user", user);
|
||||
ajax.put("roles", roles);
|
||||
ajax.put("permissions", permissions);
|
||||
ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
|
||||
ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
|
||||
return ajax;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取路由信息
|
||||
*
|
||||
* @return 路由信息
|
||||
*/
|
||||
@GetMapping("getRouters")
|
||||
public AjaxResult getRouters()
|
||||
{
|
||||
Long userId = SecurityUtils.getUserId();
|
||||
List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
|
||||
return AjaxResult.success(menuService.buildMenus(menus));
|
||||
}
|
||||
|
||||
// 检查初始密码是否提醒修改
|
||||
public boolean initPasswordIsModify(Date pwdUpdateDate)
|
||||
{
|
||||
Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey("sys.account.initPasswordModify"));
|
||||
return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null;
|
||||
}
|
||||
|
||||
// 检查密码是否过期
|
||||
public boolean passwordIsExpiration(Date pwdUpdateDate)
|
||||
{
|
||||
Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey("sys.account.passwordValidateDays"));
|
||||
if (passwordValidateDays != null && passwordValidateDays > 0)
|
||||
{
|
||||
if (StringUtils.isNull(pwdUpdateDate))
|
||||
{
|
||||
// 如果从未修改过初始密码,直接提醒过期
|
||||
return true;
|
||||
}
|
||||
Date nowDate = DateUtils.getNowDate();
|
||||
return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.constant.Constants;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysMenu;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.domain.model.LoginBody;
|
||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.core.text.Convert;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.framework.web.service.SysLoginService;
|
||||
import com.ruoyi.framework.web.service.SysPermissionService;
|
||||
import com.ruoyi.framework.web.service.TokenService;
|
||||
import com.ruoyi.system.service.ISysConfigService;
|
||||
import com.ruoyi.system.service.ISysMenuService;
|
||||
|
||||
/**
|
||||
* 登录验证
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
public class SysLoginController
|
||||
{
|
||||
@Autowired
|
||||
private SysLoginService loginService;
|
||||
|
||||
@Autowired
|
||||
private ISysMenuService menuService;
|
||||
|
||||
@Autowired
|
||||
private SysPermissionService permissionService;
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
|
||||
/**
|
||||
* 登录方法
|
||||
*
|
||||
* @param loginBody 登录信息
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping("/login")
|
||||
public AjaxResult login(@RequestBody LoginBody loginBody)
|
||||
{
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
// 生成令牌
|
||||
String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
|
||||
loginBody.getUuid());
|
||||
ajax.put(Constants.TOKEN, token);
|
||||
return ajax;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*
|
||||
* @return 用户信息
|
||||
*/
|
||||
@GetMapping("getInfo")
|
||||
public AjaxResult getInfo()
|
||||
{
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
SysUser user = loginUser.getUser();
|
||||
// 角色集合
|
||||
Set<String> roles = permissionService.getRolePermission(user);
|
||||
// 权限集合
|
||||
Set<String> permissions = permissionService.getMenuPermission(user);
|
||||
if (!loginUser.getPermissions().equals(permissions))
|
||||
{
|
||||
loginUser.setPermissions(permissions);
|
||||
tokenService.refreshToken(loginUser);
|
||||
}
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
ajax.put("user", user);
|
||||
ajax.put("roles", roles);
|
||||
ajax.put("permissions", permissions);
|
||||
ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
|
||||
ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
|
||||
return ajax;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取路由信息
|
||||
*
|
||||
* @return 路由信息
|
||||
*/
|
||||
@GetMapping("getRouters")
|
||||
public AjaxResult getRouters()
|
||||
{
|
||||
Long userId = SecurityUtils.getUserId();
|
||||
List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
|
||||
return AjaxResult.success(menuService.buildMenus(menus));
|
||||
}
|
||||
|
||||
// 检查初始密码是否提醒修改
|
||||
public boolean initPasswordIsModify(Date pwdUpdateDate)
|
||||
{
|
||||
Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey("sys.account.initPasswordModify"));
|
||||
return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null;
|
||||
}
|
||||
|
||||
// 检查密码是否过期
|
||||
public boolean passwordIsExpiration(Date pwdUpdateDate)
|
||||
{
|
||||
Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey("sys.account.passwordValidateDays"));
|
||||
if (passwordValidateDays != null && passwordValidateDays > 0)
|
||||
{
|
||||
if (StringUtils.isNull(pwdUpdateDate))
|
||||
{
|
||||
// 如果从未修改过初始密码,直接提醒过期
|
||||
return true;
|
||||
}
|
||||
Date nowDate = DateUtils.getNowDate();
|
||||
return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,150 +1,165 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.constant.UserConstants;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysMenu;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.system.service.ISysMenuService;
|
||||
|
||||
/**
|
||||
* 菜单信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/menu")
|
||||
public class SysMenuController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysMenuService menuService;
|
||||
|
||||
/**
|
||||
* 获取菜单列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:menu:list')")
|
||||
@GetMapping("/list")
|
||||
public AjaxResult list(SysMenu menu)
|
||||
{
|
||||
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
|
||||
return success(menus);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据菜单编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:menu:query')")
|
||||
@GetMapping(value = "/{menuId}")
|
||||
public AjaxResult getInfo(@PathVariable Long menuId)
|
||||
{
|
||||
return success(menuService.selectMenuById(menuId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单下拉树列表
|
||||
*/
|
||||
@GetMapping("/treeselect")
|
||||
public AjaxResult treeselect(SysMenu menu)
|
||||
{
|
||||
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
|
||||
return success(menuService.buildMenuTreeSelect(menus));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载对应角色菜单列表树
|
||||
*/
|
||||
@GetMapping(value = "/roleMenuTreeselect/{roleId}")
|
||||
public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId)
|
||||
{
|
||||
List<SysMenu> menus = menuService.selectMenuList(getUserId());
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
|
||||
ajax.put("menus", menuService.buildMenuTreeSelect(menus));
|
||||
return ajax;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增菜单
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:menu:add')")
|
||||
@Log(title = "菜单管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysMenu menu)
|
||||
{
|
||||
if (!menuService.checkMenuNameUnique(menu))
|
||||
{
|
||||
return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
|
||||
}
|
||||
else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
|
||||
{
|
||||
return error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
|
||||
}
|
||||
else if (!menuService.checkRouteConfigUnique(menu))
|
||||
{
|
||||
return error("新增菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在");
|
||||
}
|
||||
menu.setCreateBy(getUsername());
|
||||
return toAjax(menuService.insertMenu(menu));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改菜单
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:menu:edit')")
|
||||
@Log(title = "菜单管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysMenu menu)
|
||||
{
|
||||
if (!menuService.checkMenuNameUnique(menu))
|
||||
{
|
||||
return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
|
||||
}
|
||||
else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
|
||||
{
|
||||
return error("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
|
||||
}
|
||||
else if (menu.getMenuId().equals(menu.getParentId()))
|
||||
{
|
||||
return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
|
||||
}
|
||||
else if (!menuService.checkRouteConfigUnique(menu))
|
||||
{
|
||||
return error("修改菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在");
|
||||
}
|
||||
menu.setUpdateBy(getUsername());
|
||||
return toAjax(menuService.updateMenu(menu));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除菜单
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:menu:remove')")
|
||||
@Log(title = "菜单管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{menuId}")
|
||||
public AjaxResult remove(@PathVariable("menuId") Long menuId)
|
||||
{
|
||||
if (menuService.hasChildByMenuId(menuId))
|
||||
{
|
||||
return warn("存在子菜单,不允许删除");
|
||||
}
|
||||
if (menuService.checkMenuExistRole(menuId))
|
||||
{
|
||||
return warn("菜单已分配,不允许删除");
|
||||
}
|
||||
return toAjax(menuService.deleteMenuById(menuId));
|
||||
}
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.constant.UserConstants;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysMenu;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.system.service.ISysMenuService;
|
||||
|
||||
/**
|
||||
* 菜单信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/menu")
|
||||
public class SysMenuController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysMenuService menuService;
|
||||
|
||||
/**
|
||||
* 获取菜单列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:menu:list')")
|
||||
@GetMapping("/list")
|
||||
public AjaxResult list(SysMenu menu)
|
||||
{
|
||||
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
|
||||
return success(menus);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据菜单编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:menu:query')")
|
||||
@GetMapping(value = "/{menuId}")
|
||||
public AjaxResult getInfo(@PathVariable Long menuId)
|
||||
{
|
||||
return success(menuService.selectMenuById(menuId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单下拉树列表
|
||||
*/
|
||||
@GetMapping("/treeselect")
|
||||
public AjaxResult treeselect(SysMenu menu)
|
||||
{
|
||||
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
|
||||
return success(menuService.buildMenuTreeSelect(menus));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载对应角色菜单列表树
|
||||
*/
|
||||
@GetMapping(value = "/roleMenuTreeselect/{roleId}")
|
||||
public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId)
|
||||
{
|
||||
List<SysMenu> menus = menuService.selectMenuList(getUserId());
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
|
||||
ajax.put("menus", menuService.buildMenuTreeSelect(menus));
|
||||
return ajax;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增菜单
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:menu:add')")
|
||||
@Log(title = "菜单管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysMenu menu)
|
||||
{
|
||||
if (!menuService.checkMenuNameUnique(menu))
|
||||
{
|
||||
return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
|
||||
}
|
||||
else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
|
||||
{
|
||||
return error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
|
||||
}
|
||||
else if (!menuService.checkRouteConfigUnique(menu))
|
||||
{
|
||||
return error("新增菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在");
|
||||
}
|
||||
menu.setCreateBy(getUsername());
|
||||
return toAjax(menuService.insertMenu(menu));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改菜单
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:menu:edit')")
|
||||
@Log(title = "菜单管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysMenu menu)
|
||||
{
|
||||
if (!menuService.checkMenuNameUnique(menu))
|
||||
{
|
||||
return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
|
||||
}
|
||||
else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
|
||||
{
|
||||
return error("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
|
||||
}
|
||||
else if (menu.getMenuId().equals(menu.getParentId()))
|
||||
{
|
||||
return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
|
||||
}
|
||||
else if (!menuService.checkRouteConfigUnique(menu))
|
||||
{
|
||||
return error("修改菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在");
|
||||
}
|
||||
menu.setUpdateBy(getUsername());
|
||||
return toAjax(menuService.updateMenu(menu));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存菜单排序
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:menu:edit')")
|
||||
@Log(title = "保存菜单排序", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/updateSort")
|
||||
public AjaxResult updateSort(@RequestBody Map<String, String> params)
|
||||
{
|
||||
String[] menuIds = params.get("menuIds").split(",");
|
||||
String[] orderNums = params.get("orderNums").split(",");
|
||||
menuService.updateMenuSort(menuIds, orderNums);
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除菜单
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:menu:remove')")
|
||||
@Log(title = "菜单管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{menuId}")
|
||||
public AjaxResult remove(@PathVariable("menuId") Long menuId)
|
||||
{
|
||||
if (menuService.hasChildByMenuId(menuId))
|
||||
{
|
||||
return warn("存在子菜单,不允许删除");
|
||||
}
|
||||
if (menuService.checkMenuExistRole(menuId))
|
||||
{
|
||||
return warn("菜单已分配,不允许删除");
|
||||
}
|
||||
return toAjax(menuService.deleteMenuById(menuId));
|
||||
}
|
||||
}
|
||||
@@ -1,91 +1,138 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.system.domain.SysNotice;
|
||||
import com.ruoyi.system.service.ISysNoticeService;
|
||||
|
||||
/**
|
||||
* 公告 信息操作处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/notice")
|
||||
public class SysNoticeController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysNoticeService noticeService;
|
||||
|
||||
/**
|
||||
* 获取通知公告列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:notice:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysNotice notice)
|
||||
{
|
||||
startPage();
|
||||
List<SysNotice> list = noticeService.selectNoticeList(notice);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据通知公告编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:notice:query')")
|
||||
@GetMapping(value = "/{noticeId}")
|
||||
public AjaxResult getInfo(@PathVariable Long noticeId)
|
||||
{
|
||||
return success(noticeService.selectNoticeById(noticeId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增通知公告
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:notice:add')")
|
||||
@Log(title = "通知公告", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysNotice notice)
|
||||
{
|
||||
notice.setCreateBy(getUsername());
|
||||
return toAjax(noticeService.insertNotice(notice));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改通知公告
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:notice:edit')")
|
||||
@Log(title = "通知公告", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysNotice notice)
|
||||
{
|
||||
notice.setUpdateBy(getUsername());
|
||||
return toAjax(noticeService.updateNotice(notice));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除通知公告
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:notice:remove')")
|
||||
@Log(title = "通知公告", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{noticeIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] noticeIds)
|
||||
{
|
||||
return toAjax(noticeService.deleteNoticeByIds(noticeIds));
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.core.text.Convert;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.system.domain.SysNotice;
|
||||
import com.ruoyi.system.service.ISysNoticeReadService;
|
||||
import com.ruoyi.system.service.ISysNoticeService;
|
||||
|
||||
/**
|
||||
* 公告 信息操作处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/notice")
|
||||
public class SysNoticeController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysNoticeService noticeService;
|
||||
|
||||
@Autowired
|
||||
private ISysNoticeReadService noticeReadService;
|
||||
|
||||
/**
|
||||
* 获取通知公告列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:notice:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysNotice notice)
|
||||
{
|
||||
startPage();
|
||||
List<SysNotice> list = noticeService.selectNoticeList(notice);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据通知公告编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:notice:query')")
|
||||
@GetMapping(value = "/{noticeId}")
|
||||
public AjaxResult getInfo(@PathVariable Long noticeId)
|
||||
{
|
||||
return success(noticeService.selectNoticeById(noticeId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增通知公告
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:notice:add')")
|
||||
@Log(title = "通知公告", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysNotice notice)
|
||||
{
|
||||
notice.setCreateBy(getUsername());
|
||||
return toAjax(noticeService.insertNotice(notice));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改通知公告
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:notice:edit')")
|
||||
@Log(title = "通知公告", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysNotice notice)
|
||||
{
|
||||
notice.setUpdateBy(getUsername());
|
||||
return toAjax(noticeService.updateNotice(notice));
|
||||
}
|
||||
|
||||
/**
|
||||
* 首页顶部公告列表(返回全部正常公告,带当前用户已读标记,最多5条)
|
||||
*/
|
||||
@GetMapping("/listTop")
|
||||
@ResponseBody
|
||||
public AjaxResult listTop()
|
||||
{
|
||||
Long userId = getUserId();
|
||||
List<SysNotice> list = noticeReadService.selectNoticeListWithReadStatus(userId, 5);
|
||||
long unreadCount = list.stream().filter(n -> !n.getIsRead()).count();
|
||||
AjaxResult result = AjaxResult.success(list);
|
||||
result.put("unreadCount", unreadCount);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记公告已读
|
||||
*/
|
||||
@PostMapping("/markRead")
|
||||
@ResponseBody
|
||||
public AjaxResult markRead(Long noticeId)
|
||||
{
|
||||
Long userId = getUserId();
|
||||
noticeReadService.markRead(noticeId, userId);
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量标记已读
|
||||
*/
|
||||
@PostMapping("/markReadAll")
|
||||
@ResponseBody
|
||||
public AjaxResult markReadAll(String ids)
|
||||
{
|
||||
Long userId = getUserId();
|
||||
Long[] noticeIds = Convert.toLongArray(ids);
|
||||
noticeReadService.markReadBatch(userId, noticeIds);
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除通知公告
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:notice:remove')")
|
||||
@Log(title = "通知公告", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{noticeIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] noticeIds)
|
||||
{
|
||||
noticeReadService.deleteByNoticeIds(noticeIds);
|
||||
return toAjax(noticeService.deleteNoticeByIds(noticeIds));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,129 +1,129 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.List;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.system.domain.SysPost;
|
||||
import com.ruoyi.system.service.ISysPostService;
|
||||
|
||||
/**
|
||||
* 岗位信息操作处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/post")
|
||||
public class SysPostController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysPostService postService;
|
||||
|
||||
/**
|
||||
* 获取岗位列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:post:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysPost post)
|
||||
{
|
||||
startPage();
|
||||
List<SysPost> list = postService.selectPostList(post);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@Log(title = "岗位管理", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('system:post:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysPost post)
|
||||
{
|
||||
List<SysPost> list = postService.selectPostList(post);
|
||||
ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class);
|
||||
util.exportExcel(response, list, "岗位数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据岗位编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:post:query')")
|
||||
@GetMapping(value = "/{postId}")
|
||||
public AjaxResult getInfo(@PathVariable Long postId)
|
||||
{
|
||||
return success(postService.selectPostById(postId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增岗位
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:post:add')")
|
||||
@Log(title = "岗位管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysPost post)
|
||||
{
|
||||
if (!postService.checkPostNameUnique(post))
|
||||
{
|
||||
return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
|
||||
}
|
||||
else if (!postService.checkPostCodeUnique(post))
|
||||
{
|
||||
return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在");
|
||||
}
|
||||
post.setCreateBy(getUsername());
|
||||
return toAjax(postService.insertPost(post));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改岗位
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:post:edit')")
|
||||
@Log(title = "岗位管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysPost post)
|
||||
{
|
||||
if (!postService.checkPostNameUnique(post))
|
||||
{
|
||||
return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
|
||||
}
|
||||
else if (!postService.checkPostCodeUnique(post))
|
||||
{
|
||||
return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
|
||||
}
|
||||
post.setUpdateBy(getUsername());
|
||||
return toAjax(postService.updatePost(post));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除岗位
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:post:remove')")
|
||||
@Log(title = "岗位管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{postIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] postIds)
|
||||
{
|
||||
return toAjax(postService.deletePostByIds(postIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取岗位选择框列表
|
||||
*/
|
||||
@GetMapping("/optionselect")
|
||||
public AjaxResult optionselect()
|
||||
{
|
||||
List<SysPost> posts = postService.selectPostAll();
|
||||
return success(posts);
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.system.domain.SysPost;
|
||||
import com.ruoyi.system.service.ISysPostService;
|
||||
|
||||
/**
|
||||
* 岗位信息操作处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/post")
|
||||
public class SysPostController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysPostService postService;
|
||||
|
||||
/**
|
||||
* 获取岗位列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:post:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysPost post)
|
||||
{
|
||||
startPage();
|
||||
List<SysPost> list = postService.selectPostList(post);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@Log(title = "岗位管理", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('system:post:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysPost post)
|
||||
{
|
||||
List<SysPost> list = postService.selectPostList(post);
|
||||
ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class);
|
||||
util.exportExcel(response, list, "岗位数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据岗位编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:post:query')")
|
||||
@GetMapping(value = "/{postId}")
|
||||
public AjaxResult getInfo(@PathVariable Long postId)
|
||||
{
|
||||
return success(postService.selectPostById(postId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增岗位
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:post:add')")
|
||||
@Log(title = "岗位管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysPost post)
|
||||
{
|
||||
if (!postService.checkPostNameUnique(post))
|
||||
{
|
||||
return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
|
||||
}
|
||||
else if (!postService.checkPostCodeUnique(post))
|
||||
{
|
||||
return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在");
|
||||
}
|
||||
post.setCreateBy(getUsername());
|
||||
return toAjax(postService.insertPost(post));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改岗位
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:post:edit')")
|
||||
@Log(title = "岗位管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysPost post)
|
||||
{
|
||||
if (!postService.checkPostNameUnique(post))
|
||||
{
|
||||
return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
|
||||
}
|
||||
else if (!postService.checkPostCodeUnique(post))
|
||||
{
|
||||
return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
|
||||
}
|
||||
post.setUpdateBy(getUsername());
|
||||
return toAjax(postService.updatePost(post));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除岗位
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:post:remove')")
|
||||
@Log(title = "岗位管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{postIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] postIds)
|
||||
{
|
||||
return toAjax(postService.deletePostByIds(postIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取岗位选择框列表
|
||||
*/
|
||||
@GetMapping("/optionselect")
|
||||
public AjaxResult optionselect()
|
||||
{
|
||||
List<SysPost> posts = postService.selectPostAll();
|
||||
return success(posts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,153 +1,149 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.Map;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.config.RuoYiConfig;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.file.FileUploadUtils;
|
||||
import com.ruoyi.common.utils.file.FileUtils;
|
||||
import com.ruoyi.common.utils.file.MimeTypeUtils;
|
||||
import com.ruoyi.framework.web.service.PasswordTransferCryptoService;
|
||||
import com.ruoyi.framework.web.service.TokenService;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
|
||||
/**
|
||||
* 个人信息 业务处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/user/profile")
|
||||
public class SysProfileController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysUserService userService;
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
@Autowired
|
||||
private PasswordTransferCryptoService passwordTransferCryptoService;
|
||||
|
||||
/**
|
||||
* 个人信息
|
||||
*/
|
||||
@GetMapping
|
||||
public AjaxResult profile()
|
||||
{
|
||||
LoginUser loginUser = getLoginUser();
|
||||
SysUser user = loginUser.getUser();
|
||||
AjaxResult ajax = AjaxResult.success(user);
|
||||
ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername()));
|
||||
ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername()));
|
||||
return ajax;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户
|
||||
*/
|
||||
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult updateProfile(@RequestBody SysUser user)
|
||||
{
|
||||
LoginUser loginUser = getLoginUser();
|
||||
SysUser currentUser = loginUser.getUser();
|
||||
currentUser.setNickName(user.getNickName());
|
||||
currentUser.setEmail(user.getEmail());
|
||||
currentUser.setPhonenumber(user.getPhonenumber());
|
||||
currentUser.setSex(user.getSex());
|
||||
if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser))
|
||||
{
|
||||
return error("修改用户'" + loginUser.getUsername() + "'失败,手机号码已存在");
|
||||
}
|
||||
if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser))
|
||||
{
|
||||
return error("修改用户'" + loginUser.getUsername() + "'失败,邮箱账号已存在");
|
||||
}
|
||||
if (userService.updateUserProfile(currentUser) > 0)
|
||||
{
|
||||
// 更新缓存用户信息
|
||||
tokenService.setLoginUser(loginUser);
|
||||
return success();
|
||||
}
|
||||
return error("修改个人信息异常,请联系管理员");
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
*/
|
||||
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/updatePwd")
|
||||
public AjaxResult updatePwd(@RequestBody Map<String, String> params)
|
||||
{
|
||||
String oldPassword = passwordTransferCryptoService.decrypt(params.get("oldPassword"));
|
||||
String newPassword = passwordTransferCryptoService.decrypt(params.get("newPassword"));
|
||||
LoginUser loginUser = getLoginUser();
|
||||
Long userId = loginUser.getUserId();
|
||||
SysUser user = userService.selectUserById(userId);
|
||||
String password = user.getPassword();
|
||||
if (!SecurityUtils.matchesPassword(oldPassword, password))
|
||||
{
|
||||
return error("修改密码失败,旧密码错误");
|
||||
}
|
||||
if (SecurityUtils.matchesPassword(newPassword, password))
|
||||
{
|
||||
return error("新密码不能与旧密码相同");
|
||||
}
|
||||
newPassword = SecurityUtils.encryptPassword(newPassword);
|
||||
if (userService.resetUserPwd(userId, newPassword) > 0)
|
||||
{
|
||||
// 更新缓存用户密码&密码最后更新时间
|
||||
loginUser.getUser().setPwdUpdateDate(DateUtils.getNowDate());
|
||||
loginUser.getUser().setPassword(newPassword);
|
||||
tokenService.setLoginUser(loginUser);
|
||||
return success();
|
||||
}
|
||||
return error("修改密码异常,请联系管理员");
|
||||
}
|
||||
|
||||
/**
|
||||
* 头像上传
|
||||
*/
|
||||
@Log(title = "用户头像", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/avatar")
|
||||
public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception
|
||||
{
|
||||
if (!file.isEmpty())
|
||||
{
|
||||
LoginUser loginUser = getLoginUser();
|
||||
String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION, true);
|
||||
if (userService.updateUserAvatar(loginUser.getUserId(), avatar))
|
||||
{
|
||||
String oldAvatar = loginUser.getUser().getAvatar();
|
||||
if (StringUtils.isNotEmpty(oldAvatar))
|
||||
{
|
||||
FileUtils.deleteFile(RuoYiConfig.getProfile() + FileUtils.stripPrefix(oldAvatar));
|
||||
}
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
ajax.put("imgUrl", avatar);
|
||||
// 更新缓存用户头像
|
||||
loginUser.getUser().setAvatar(avatar);
|
||||
tokenService.setLoginUser(loginUser);
|
||||
return ajax;
|
||||
}
|
||||
}
|
||||
return error("上传图片异常,请联系管理员");
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.Map;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.config.RuoYiConfig;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.file.FileUploadUtils;
|
||||
import com.ruoyi.common.utils.file.FileUtils;
|
||||
import com.ruoyi.common.utils.file.MimeTypeUtils;
|
||||
import com.ruoyi.framework.web.service.TokenService;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
|
||||
/**
|
||||
* 个人信息 业务处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/user/profile")
|
||||
public class SysProfileController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysUserService userService;
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
/**
|
||||
* 个人信息
|
||||
*/
|
||||
@GetMapping
|
||||
public AjaxResult profile()
|
||||
{
|
||||
LoginUser loginUser = getLoginUser();
|
||||
SysUser user = loginUser.getUser();
|
||||
AjaxResult ajax = AjaxResult.success(user);
|
||||
ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername()));
|
||||
ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername()));
|
||||
return ajax;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户
|
||||
*/
|
||||
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult updateProfile(@RequestBody SysUser user)
|
||||
{
|
||||
LoginUser loginUser = getLoginUser();
|
||||
SysUser currentUser = loginUser.getUser();
|
||||
currentUser.setNickName(user.getNickName());
|
||||
currentUser.setEmail(user.getEmail());
|
||||
currentUser.setPhonenumber(user.getPhonenumber());
|
||||
currentUser.setSex(user.getSex());
|
||||
if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser))
|
||||
{
|
||||
return error("修改用户'" + loginUser.getUsername() + "'失败,手机号码已存在");
|
||||
}
|
||||
if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser))
|
||||
{
|
||||
return error("修改用户'" + loginUser.getUsername() + "'失败,邮箱账号已存在");
|
||||
}
|
||||
if (userService.updateUserProfile(currentUser) > 0)
|
||||
{
|
||||
// 更新缓存用户信息
|
||||
tokenService.setLoginUser(loginUser);
|
||||
return success();
|
||||
}
|
||||
return error("修改个人信息异常,请联系管理员");
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
*/
|
||||
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/updatePwd")
|
||||
public AjaxResult updatePwd(@RequestBody Map<String, String> params)
|
||||
{
|
||||
String oldPassword = params.get("oldPassword");
|
||||
String newPassword = params.get("newPassword");
|
||||
LoginUser loginUser = getLoginUser();
|
||||
Long userId = loginUser.getUserId();
|
||||
SysUser user = userService.selectUserById(userId);
|
||||
String password = user.getPassword();
|
||||
if (!SecurityUtils.matchesPassword(oldPassword, password))
|
||||
{
|
||||
return error("修改密码失败,旧密码错误");
|
||||
}
|
||||
if (SecurityUtils.matchesPassword(newPassword, password))
|
||||
{
|
||||
return error("新密码不能与旧密码相同");
|
||||
}
|
||||
newPassword = SecurityUtils.encryptPassword(newPassword);
|
||||
if (userService.resetUserPwd(userId, newPassword) > 0)
|
||||
{
|
||||
// 更新缓存用户密码&密码最后更新时间
|
||||
loginUser.getUser().setPwdUpdateDate(DateUtils.getNowDate());
|
||||
loginUser.getUser().setPassword(newPassword);
|
||||
tokenService.setLoginUser(loginUser);
|
||||
return success();
|
||||
}
|
||||
return error("修改密码异常,请联系管理员");
|
||||
}
|
||||
|
||||
/**
|
||||
* 头像上传
|
||||
*/
|
||||
@Log(title = "用户头像", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/avatar")
|
||||
public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception
|
||||
{
|
||||
if (!file.isEmpty())
|
||||
{
|
||||
LoginUser loginUser = getLoginUser();
|
||||
String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION, true);
|
||||
if (userService.updateUserAvatar(loginUser.getUserId(), avatar))
|
||||
{
|
||||
String oldAvatar = loginUser.getUser().getAvatar();
|
||||
if (StringUtils.isNotEmpty(oldAvatar))
|
||||
{
|
||||
FileUtils.deleteFile(RuoYiConfig.getProfile() + FileUtils.stripPrefix(oldAvatar));
|
||||
}
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
ajax.put("imgUrl", avatar);
|
||||
// 更新缓存用户头像
|
||||
loginUser.getUser().setAvatar(avatar);
|
||||
tokenService.setLoginUser(loginUser);
|
||||
return ajax;
|
||||
}
|
||||
}
|
||||
return error("上传图片异常,请联系管理员");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +1,38 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.model.RegisterBody;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.framework.web.service.PasswordTransferCryptoService;
|
||||
import com.ruoyi.framework.web.service.SysRegisterService;
|
||||
import com.ruoyi.system.service.ISysConfigService;
|
||||
|
||||
/**
|
||||
* 注册验证
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
public class SysRegisterController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private SysRegisterService registerService;
|
||||
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
|
||||
@Autowired
|
||||
private PasswordTransferCryptoService passwordTransferCryptoService;
|
||||
|
||||
@PostMapping("/register")
|
||||
public AjaxResult register(@RequestBody RegisterBody user)
|
||||
{
|
||||
if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser"))))
|
||||
{
|
||||
return error("当前系统没有开启注册功能!");
|
||||
}
|
||||
user.setPassword(passwordTransferCryptoService.decrypt(user.getPassword()));
|
||||
String msg = registerService.register(user);
|
||||
return StringUtils.isEmpty(msg) ? success() : error(msg);
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.model.RegisterBody;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.framework.web.service.SysRegisterService;
|
||||
import com.ruoyi.system.service.ISysConfigService;
|
||||
|
||||
/**
|
||||
* 注册验证
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
public class SysRegisterController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private SysRegisterService registerService;
|
||||
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
|
||||
@PostMapping("/register")
|
||||
public AjaxResult register(@RequestBody RegisterBody user)
|
||||
{
|
||||
if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser"))))
|
||||
{
|
||||
return error("当前系统没有开启注册功能!");
|
||||
}
|
||||
String msg = registerService.register(user);
|
||||
return StringUtils.isEmpty(msg) ? success() : error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,262 +1,262 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.List;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysDept;
|
||||
import com.ruoyi.common.core.domain.entity.SysRole;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.framework.web.service.SysPermissionService;
|
||||
import com.ruoyi.framework.web.service.TokenService;
|
||||
import com.ruoyi.system.domain.SysUserRole;
|
||||
import com.ruoyi.system.service.ISysDeptService;
|
||||
import com.ruoyi.system.service.ISysRoleService;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
|
||||
/**
|
||||
* 角色信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/role")
|
||||
public class SysRoleController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysRoleService roleService;
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
@Autowired
|
||||
private SysPermissionService permissionService;
|
||||
|
||||
@Autowired
|
||||
private ISysUserService userService;
|
||||
|
||||
@Autowired
|
||||
private ISysDeptService deptService;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('system:role:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysRole role)
|
||||
{
|
||||
startPage();
|
||||
List<SysRole> list = roleService.selectRoleList(role);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@Log(title = "角色管理", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('system:role:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysRole role)
|
||||
{
|
||||
List<SysRole> list = roleService.selectRoleList(role);
|
||||
ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class);
|
||||
util.exportExcel(response, list, "角色数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:query')")
|
||||
@GetMapping(value = "/{roleId}")
|
||||
public AjaxResult getInfo(@PathVariable Long roleId)
|
||||
{
|
||||
roleService.checkRoleDataScope(roleId);
|
||||
return success(roleService.selectRoleById(roleId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增角色
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:add')")
|
||||
@Log(title = "角色管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysRole role)
|
||||
{
|
||||
if (!roleService.checkRoleNameUnique(role))
|
||||
{
|
||||
return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
|
||||
}
|
||||
else if (!roleService.checkRoleKeyUnique(role))
|
||||
{
|
||||
return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
|
||||
}
|
||||
role.setCreateBy(getUsername());
|
||||
return toAjax(roleService.insertRole(role));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改保存角色
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:edit')")
|
||||
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysRole role)
|
||||
{
|
||||
roleService.checkRoleAllowed(role);
|
||||
roleService.checkRoleDataScope(role.getRoleId());
|
||||
if (!roleService.checkRoleNameUnique(role))
|
||||
{
|
||||
return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
|
||||
}
|
||||
else if (!roleService.checkRoleKeyUnique(role))
|
||||
{
|
||||
return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
|
||||
}
|
||||
role.setUpdateBy(getUsername());
|
||||
|
||||
if (roleService.updateRole(role) > 0)
|
||||
{
|
||||
// 更新缓存用户权限
|
||||
LoginUser loginUser = getLoginUser();
|
||||
if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin())
|
||||
{
|
||||
loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName()));
|
||||
loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
|
||||
tokenService.setLoginUser(loginUser);
|
||||
}
|
||||
return success();
|
||||
}
|
||||
return error("修改角色'" + role.getRoleName() + "'失败,请联系管理员");
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改保存数据权限
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:edit')")
|
||||
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/dataScope")
|
||||
public AjaxResult dataScope(@RequestBody SysRole role)
|
||||
{
|
||||
roleService.checkRoleAllowed(role);
|
||||
roleService.checkRoleDataScope(role.getRoleId());
|
||||
return toAjax(roleService.authDataScope(role));
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态修改
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:edit')")
|
||||
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/changeStatus")
|
||||
public AjaxResult changeStatus(@RequestBody SysRole role)
|
||||
{
|
||||
roleService.checkRoleAllowed(role);
|
||||
roleService.checkRoleDataScope(role.getRoleId());
|
||||
role.setUpdateBy(getUsername());
|
||||
return toAjax(roleService.updateRoleStatus(role));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除角色
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:remove')")
|
||||
@Log(title = "角色管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{roleIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] roleIds)
|
||||
{
|
||||
return toAjax(roleService.deleteRoleByIds(roleIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色选择框列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:query')")
|
||||
@GetMapping("/optionselect")
|
||||
public AjaxResult optionselect()
|
||||
{
|
||||
return success(roleService.selectRoleAll());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询已分配用户角色列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:list')")
|
||||
@GetMapping("/authUser/allocatedList")
|
||||
public TableDataInfo allocatedList(SysUser user)
|
||||
{
|
||||
startPage();
|
||||
List<SysUser> list = userService.selectAllocatedList(user);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询未分配用户角色列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:list')")
|
||||
@GetMapping("/authUser/unallocatedList")
|
||||
public TableDataInfo unallocatedList(SysUser user)
|
||||
{
|
||||
startPage();
|
||||
List<SysUser> list = userService.selectUnallocatedList(user);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消授权用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:edit')")
|
||||
@Log(title = "角色管理", businessType = BusinessType.GRANT)
|
||||
@PutMapping("/authUser/cancel")
|
||||
public AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole)
|
||||
{
|
||||
return toAjax(roleService.deleteAuthUser(userRole));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量取消授权用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:edit')")
|
||||
@Log(title = "角色管理", businessType = BusinessType.GRANT)
|
||||
@PutMapping("/authUser/cancelAll")
|
||||
public AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds)
|
||||
{
|
||||
return toAjax(roleService.deleteAuthUsers(roleId, userIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量选择用户授权
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:edit')")
|
||||
@Log(title = "角色管理", businessType = BusinessType.GRANT)
|
||||
@PutMapping("/authUser/selectAll")
|
||||
public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds)
|
||||
{
|
||||
roleService.checkRoleDataScope(roleId);
|
||||
return toAjax(roleService.insertAuthUsers(roleId, userIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对应角色部门树列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:query')")
|
||||
@GetMapping(value = "/deptTree/{roleId}")
|
||||
public AjaxResult deptTree(@PathVariable("roleId") Long roleId)
|
||||
{
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
|
||||
ajax.put("depts", deptService.selectDeptTreeList(new SysDept()));
|
||||
return ajax;
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysDept;
|
||||
import com.ruoyi.common.core.domain.entity.SysRole;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.framework.web.service.SysPermissionService;
|
||||
import com.ruoyi.framework.web.service.TokenService;
|
||||
import com.ruoyi.system.domain.SysUserRole;
|
||||
import com.ruoyi.system.service.ISysDeptService;
|
||||
import com.ruoyi.system.service.ISysRoleService;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
|
||||
/**
|
||||
* 角色信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/role")
|
||||
public class SysRoleController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysRoleService roleService;
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
@Autowired
|
||||
private SysPermissionService permissionService;
|
||||
|
||||
@Autowired
|
||||
private ISysUserService userService;
|
||||
|
||||
@Autowired
|
||||
private ISysDeptService deptService;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('system:role:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysRole role)
|
||||
{
|
||||
startPage();
|
||||
List<SysRole> list = roleService.selectRoleList(role);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@Log(title = "角色管理", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('system:role:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysRole role)
|
||||
{
|
||||
List<SysRole> list = roleService.selectRoleList(role);
|
||||
ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class);
|
||||
util.exportExcel(response, list, "角色数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:query')")
|
||||
@GetMapping(value = "/{roleId}")
|
||||
public AjaxResult getInfo(@PathVariable Long roleId)
|
||||
{
|
||||
roleService.checkRoleDataScope(roleId);
|
||||
return success(roleService.selectRoleById(roleId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增角色
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:add')")
|
||||
@Log(title = "角色管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysRole role)
|
||||
{
|
||||
if (!roleService.checkRoleNameUnique(role))
|
||||
{
|
||||
return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
|
||||
}
|
||||
else if (!roleService.checkRoleKeyUnique(role))
|
||||
{
|
||||
return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
|
||||
}
|
||||
role.setCreateBy(getUsername());
|
||||
return toAjax(roleService.insertRole(role));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改保存角色
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:edit')")
|
||||
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysRole role)
|
||||
{
|
||||
roleService.checkRoleAllowed(role);
|
||||
roleService.checkRoleDataScope(role.getRoleId());
|
||||
if (!roleService.checkRoleNameUnique(role))
|
||||
{
|
||||
return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
|
||||
}
|
||||
else if (!roleService.checkRoleKeyUnique(role))
|
||||
{
|
||||
return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
|
||||
}
|
||||
role.setUpdateBy(getUsername());
|
||||
|
||||
if (roleService.updateRole(role) > 0)
|
||||
{
|
||||
// 更新缓存用户权限
|
||||
LoginUser loginUser = getLoginUser();
|
||||
if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin())
|
||||
{
|
||||
loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName()));
|
||||
loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
|
||||
tokenService.setLoginUser(loginUser);
|
||||
}
|
||||
return success();
|
||||
}
|
||||
return error("修改角色'" + role.getRoleName() + "'失败,请联系管理员");
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改保存数据权限
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:edit')")
|
||||
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/dataScope")
|
||||
public AjaxResult dataScope(@RequestBody SysRole role)
|
||||
{
|
||||
roleService.checkRoleAllowed(role);
|
||||
roleService.checkRoleDataScope(role.getRoleId());
|
||||
return toAjax(roleService.authDataScope(role));
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态修改
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:edit')")
|
||||
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/changeStatus")
|
||||
public AjaxResult changeStatus(@RequestBody SysRole role)
|
||||
{
|
||||
roleService.checkRoleAllowed(role);
|
||||
roleService.checkRoleDataScope(role.getRoleId());
|
||||
role.setUpdateBy(getUsername());
|
||||
return toAjax(roleService.updateRoleStatus(role));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除角色
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:remove')")
|
||||
@Log(title = "角色管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{roleIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] roleIds)
|
||||
{
|
||||
return toAjax(roleService.deleteRoleByIds(roleIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色选择框列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:query')")
|
||||
@GetMapping("/optionselect")
|
||||
public AjaxResult optionselect()
|
||||
{
|
||||
return success(roleService.selectRoleAll());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询已分配用户角色列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:list')")
|
||||
@GetMapping("/authUser/allocatedList")
|
||||
public TableDataInfo allocatedList(SysUser user)
|
||||
{
|
||||
startPage();
|
||||
List<SysUser> list = userService.selectAllocatedList(user);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询未分配用户角色列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:list')")
|
||||
@GetMapping("/authUser/unallocatedList")
|
||||
public TableDataInfo unallocatedList(SysUser user)
|
||||
{
|
||||
startPage();
|
||||
List<SysUser> list = userService.selectUnallocatedList(user);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消授权用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:edit')")
|
||||
@Log(title = "角色管理", businessType = BusinessType.GRANT)
|
||||
@PutMapping("/authUser/cancel")
|
||||
public AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole)
|
||||
{
|
||||
return toAjax(roleService.deleteAuthUser(userRole));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量取消授权用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:edit')")
|
||||
@Log(title = "角色管理", businessType = BusinessType.GRANT)
|
||||
@PutMapping("/authUser/cancelAll")
|
||||
public AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds)
|
||||
{
|
||||
return toAjax(roleService.deleteAuthUsers(roleId, userIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量选择用户授权
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:edit')")
|
||||
@Log(title = "角色管理", businessType = BusinessType.GRANT)
|
||||
@PutMapping("/authUser/selectAll")
|
||||
public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds)
|
||||
{
|
||||
roleService.checkRoleDataScope(roleId);
|
||||
return toAjax(roleService.insertAuthUsers(roleId, userIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对应角色部门树列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:role:query')")
|
||||
@GetMapping(value = "/deptTree/{roleId}")
|
||||
public AjaxResult deptTree(@PathVariable("roleId") Long roleId)
|
||||
{
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
|
||||
ajax.put("depts", deptService.selectDeptTreeList(new SysDept()));
|
||||
return ajax;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,262 +1,256 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysDept;
|
||||
import com.ruoyi.common.core.domain.entity.SysRole;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.framework.web.service.PasswordTransferCryptoService;
|
||||
import com.ruoyi.system.service.ISysDeptService;
|
||||
import com.ruoyi.system.service.ISysPostService;
|
||||
import com.ruoyi.system.service.ISysRoleService;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
|
||||
/**
|
||||
* 用户信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/user")
|
||||
public class SysUserController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysUserService userService;
|
||||
|
||||
@Autowired
|
||||
private ISysRoleService roleService;
|
||||
|
||||
@Autowired
|
||||
private ISysDeptService deptService;
|
||||
|
||||
@Autowired
|
||||
private ISysPostService postService;
|
||||
|
||||
@Autowired
|
||||
private PasswordTransferCryptoService passwordTransferCryptoService;
|
||||
|
||||
/**
|
||||
* 获取用户列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysUser user)
|
||||
{
|
||||
startPage();
|
||||
List<SysUser> list = userService.selectUserList(user);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@Log(title = "用户管理", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('system:user:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysUser user)
|
||||
{
|
||||
List<SysUser> list = userService.selectUserList(user);
|
||||
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
|
||||
util.exportExcel(response, list, "用户数据");
|
||||
}
|
||||
|
||||
@Log(title = "用户管理", businessType = BusinessType.IMPORT)
|
||||
@PreAuthorize("@ss.hasPermi('system:user:import')")
|
||||
@PostMapping("/importData")
|
||||
public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
|
||||
{
|
||||
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
|
||||
List<SysUser> userList = util.importExcel(file.getInputStream());
|
||||
String operName = getUsername();
|
||||
String message = userService.importUser(userList, updateSupport, operName);
|
||||
return success(message);
|
||||
}
|
||||
|
||||
@PostMapping("/importTemplate")
|
||||
public void importTemplate(HttpServletResponse response)
|
||||
{
|
||||
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
|
||||
util.importTemplateExcel(response, "用户数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:query')")
|
||||
@GetMapping(value = { "/", "/{userId}" })
|
||||
public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
|
||||
{
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
if (StringUtils.isNotNull(userId))
|
||||
{
|
||||
userService.checkUserDataScope(userId);
|
||||
SysUser sysUser = userService.selectUserById(userId);
|
||||
ajax.put(AjaxResult.DATA_TAG, sysUser);
|
||||
ajax.put("postIds", postService.selectPostListByUserId(userId));
|
||||
ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
|
||||
}
|
||||
List<SysRole> roles = roleService.selectRoleAll();
|
||||
ajax.put("roles", SecurityUtils.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
|
||||
ajax.put("posts", postService.selectPostAll());
|
||||
return ajax;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:add')")
|
||||
@Log(title = "用户管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysUser user)
|
||||
{
|
||||
deptService.checkDeptDataScope(user.getDeptId());
|
||||
roleService.checkRoleDataScope(user.getRoleIds());
|
||||
if (!userService.checkUserNameUnique(user))
|
||||
{
|
||||
return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
|
||||
{
|
||||
return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
|
||||
{
|
||||
return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
|
||||
}
|
||||
user.setCreateBy(getUsername());
|
||||
user.setPassword(passwordTransferCryptoService.decrypt(user.getPassword()));
|
||||
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
|
||||
return toAjax(userService.insertUser(user));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:edit')")
|
||||
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysUser user)
|
||||
{
|
||||
userService.checkUserAllowed(user);
|
||||
userService.checkUserDataScope(user.getUserId());
|
||||
deptService.checkDeptDataScope(user.getDeptId());
|
||||
roleService.checkRoleDataScope(user.getRoleIds());
|
||||
if (!userService.checkUserNameUnique(user))
|
||||
{
|
||||
return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
|
||||
{
|
||||
return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
|
||||
{
|
||||
return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
|
||||
}
|
||||
user.setUpdateBy(getUsername());
|
||||
return toAjax(userService.updateUser(user));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:remove')")
|
||||
@Log(title = "用户管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{userIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] userIds)
|
||||
{
|
||||
if (ArrayUtils.contains(userIds, getUserId()))
|
||||
{
|
||||
return error("当前用户不能删除");
|
||||
}
|
||||
return toAjax(userService.deleteUserByIds(userIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
|
||||
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/resetPwd")
|
||||
public AjaxResult resetPwd(@RequestBody SysUser user)
|
||||
{
|
||||
userService.checkUserAllowed(user);
|
||||
userService.checkUserDataScope(user.getUserId());
|
||||
user.setPassword(passwordTransferCryptoService.decrypt(user.getPassword()));
|
||||
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
|
||||
user.setUpdateBy(getUsername());
|
||||
return toAjax(userService.resetPwd(user));
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态修改
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:edit')")
|
||||
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/changeStatus")
|
||||
public AjaxResult changeStatus(@RequestBody SysUser user)
|
||||
{
|
||||
userService.checkUserAllowed(user);
|
||||
userService.checkUserDataScope(user.getUserId());
|
||||
user.setUpdateBy(getUsername());
|
||||
return toAjax(userService.updateUserStatus(user));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户编号获取授权角色
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:query')")
|
||||
@GetMapping("/authRole/{userId}")
|
||||
public AjaxResult authRole(@PathVariable("userId") Long userId)
|
||||
{
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
SysUser user = userService.selectUserById(userId);
|
||||
List<SysRole> roles = roleService.selectRolesByUserId(userId);
|
||||
ajax.put("user", user);
|
||||
ajax.put("roles", SecurityUtils.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
|
||||
return ajax;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户授权角色
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:edit')")
|
||||
@Log(title = "用户管理", businessType = BusinessType.GRANT)
|
||||
@PutMapping("/authRole")
|
||||
public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
|
||||
{
|
||||
userService.checkUserDataScope(userId);
|
||||
roleService.checkRoleDataScope(roleIds);
|
||||
userService.insertUserAuth(userId, roleIds);
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门树列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:list')")
|
||||
@GetMapping("/deptTree")
|
||||
public AjaxResult deptTree(SysDept dept)
|
||||
{
|
||||
return success(deptService.selectDeptTreeList(dept));
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysDept;
|
||||
import com.ruoyi.common.core.domain.entity.SysRole;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.system.service.ISysDeptService;
|
||||
import com.ruoyi.system.service.ISysPostService;
|
||||
import com.ruoyi.system.service.ISysRoleService;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
|
||||
/**
|
||||
* 用户信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/user")
|
||||
public class SysUserController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysUserService userService;
|
||||
|
||||
@Autowired
|
||||
private ISysRoleService roleService;
|
||||
|
||||
@Autowired
|
||||
private ISysDeptService deptService;
|
||||
|
||||
@Autowired
|
||||
private ISysPostService postService;
|
||||
|
||||
/**
|
||||
* 获取用户列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysUser user)
|
||||
{
|
||||
startPage();
|
||||
List<SysUser> list = userService.selectUserList(user);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@Log(title = "用户管理", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('system:user:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysUser user)
|
||||
{
|
||||
List<SysUser> list = userService.selectUserList(user);
|
||||
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
|
||||
util.exportExcel(response, list, "用户数据");
|
||||
}
|
||||
|
||||
@Log(title = "用户管理", businessType = BusinessType.IMPORT)
|
||||
@PreAuthorize("@ss.hasPermi('system:user:import')")
|
||||
@PostMapping("/importData")
|
||||
public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
|
||||
{
|
||||
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
|
||||
List<SysUser> userList = util.importExcel(file.getInputStream());
|
||||
String operName = getUsername();
|
||||
String message = userService.importUser(userList, updateSupport, operName);
|
||||
return success(message);
|
||||
}
|
||||
|
||||
@PostMapping("/importTemplate")
|
||||
public void importTemplate(HttpServletResponse response)
|
||||
{
|
||||
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
|
||||
util.importTemplateExcel(response, "用户数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:query')")
|
||||
@GetMapping(value = { "/", "/{userId}" })
|
||||
public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
|
||||
{
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
if (StringUtils.isNotNull(userId))
|
||||
{
|
||||
userService.checkUserDataScope(userId);
|
||||
SysUser sysUser = userService.selectUserById(userId);
|
||||
ajax.put(AjaxResult.DATA_TAG, sysUser);
|
||||
ajax.put("postIds", postService.selectPostListByUserId(userId));
|
||||
ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
|
||||
}
|
||||
List<SysRole> roles = roleService.selectRoleAll();
|
||||
ajax.put("roles", SecurityUtils.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
|
||||
ajax.put("posts", postService.selectPostAll());
|
||||
return ajax;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:add')")
|
||||
@Log(title = "用户管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody SysUser user)
|
||||
{
|
||||
deptService.checkDeptDataScope(user.getDeptId());
|
||||
roleService.checkRoleDataScope(user.getRoleIds());
|
||||
if (!userService.checkUserNameUnique(user))
|
||||
{
|
||||
return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
|
||||
{
|
||||
return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
|
||||
{
|
||||
return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
|
||||
}
|
||||
user.setCreateBy(getUsername());
|
||||
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
|
||||
return toAjax(userService.insertUser(user));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:edit')")
|
||||
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody SysUser user)
|
||||
{
|
||||
userService.checkUserAllowed(user);
|
||||
userService.checkUserDataScope(user.getUserId());
|
||||
deptService.checkDeptDataScope(user.getDeptId());
|
||||
roleService.checkRoleDataScope(user.getRoleIds());
|
||||
if (!userService.checkUserNameUnique(user))
|
||||
{
|
||||
return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
|
||||
{
|
||||
return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
|
||||
{
|
||||
return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
|
||||
}
|
||||
user.setUpdateBy(getUsername());
|
||||
return toAjax(userService.updateUser(user));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:remove')")
|
||||
@Log(title = "用户管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{userIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] userIds)
|
||||
{
|
||||
if (ArrayUtils.contains(userIds, getUserId()))
|
||||
{
|
||||
return error("当前用户不能删除");
|
||||
}
|
||||
return toAjax(userService.deleteUserByIds(userIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
|
||||
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/resetPwd")
|
||||
public AjaxResult resetPwd(@RequestBody SysUser user)
|
||||
{
|
||||
userService.checkUserAllowed(user);
|
||||
userService.checkUserDataScope(user.getUserId());
|
||||
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
|
||||
user.setUpdateBy(getUsername());
|
||||
return toAjax(userService.resetPwd(user));
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态修改
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:edit')")
|
||||
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/changeStatus")
|
||||
public AjaxResult changeStatus(@RequestBody SysUser user)
|
||||
{
|
||||
userService.checkUserAllowed(user);
|
||||
userService.checkUserDataScope(user.getUserId());
|
||||
user.setUpdateBy(getUsername());
|
||||
return toAjax(userService.updateUserStatus(user));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户编号获取授权角色
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:query')")
|
||||
@GetMapping("/authRole/{userId}")
|
||||
public AjaxResult authRole(@PathVariable("userId") Long userId)
|
||||
{
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
SysUser user = userService.selectUserById(userId);
|
||||
List<SysRole> roles = roleService.selectRolesByUserId(userId);
|
||||
ajax.put("user", user);
|
||||
ajax.put("roles", SecurityUtils.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
|
||||
return ajax;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户授权角色
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:edit')")
|
||||
@Log(title = "用户管理", businessType = BusinessType.GRANT)
|
||||
@PutMapping("/authRole")
|
||||
public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
|
||||
{
|
||||
userService.checkUserDataScope(userId);
|
||||
roleService.checkRoleDataScope(roleIds);
|
||||
userService.insertUserAuth(userId, roleIds);
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门树列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:user:list')")
|
||||
@GetMapping("/deptTree")
|
||||
public AjaxResult deptTree(SysDept dept)
|
||||
{
|
||||
return success(deptService.selectDeptTreeList(dept));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,175 +1,183 @@
|
||||
package com.ruoyi.web.controller.tool;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
/**
|
||||
* swagger 用户测试方法
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Tag(name = "用户信息管理")
|
||||
@RestController
|
||||
@RequestMapping("/test/user")
|
||||
public class TestController extends BaseController
|
||||
{
|
||||
private final static Map<Integer, UserEntity> users = new LinkedHashMap<Integer, UserEntity>();
|
||||
{
|
||||
users.put(1, new UserEntity(1, "admin", "admin123", "15888888888"));
|
||||
users.put(2, new UserEntity(2, "ry", "admin123", "15666666666"));
|
||||
}
|
||||
|
||||
@Operation(summary = "获取用户列表")
|
||||
@GetMapping("/list")
|
||||
public R<List<UserEntity>> userList()
|
||||
{
|
||||
List<UserEntity> userList = new ArrayList<UserEntity>(users.values());
|
||||
return R.ok(userList);
|
||||
}
|
||||
|
||||
@Operation(summary = "获取用户详细")
|
||||
@GetMapping("/{userId}")
|
||||
public R<UserEntity> getUser(@PathVariable(name = "userId")
|
||||
Integer userId)
|
||||
{
|
||||
if (!users.isEmpty() && users.containsKey(userId))
|
||||
{
|
||||
return R.ok(users.get(userId));
|
||||
}
|
||||
else
|
||||
{
|
||||
return R.fail("用户不存在");
|
||||
}
|
||||
}
|
||||
|
||||
@Operation(summary = "新增用户")
|
||||
@PostMapping("/save")
|
||||
public R<String> save(UserEntity user)
|
||||
{
|
||||
if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
|
||||
{
|
||||
return R.fail("用户ID不能为空");
|
||||
}
|
||||
users.put(user.getUserId(), user);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "更新用户")
|
||||
@PutMapping("/update")
|
||||
public R<String> update(@RequestBody
|
||||
UserEntity user)
|
||||
{
|
||||
if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
|
||||
{
|
||||
return R.fail("用户ID不能为空");
|
||||
}
|
||||
if (users.isEmpty() || !users.containsKey(user.getUserId()))
|
||||
{
|
||||
return R.fail("用户不存在");
|
||||
}
|
||||
users.remove(user.getUserId());
|
||||
users.put(user.getUserId(), user);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "删除用户信息")
|
||||
@DeleteMapping("/{userId}")
|
||||
public R<String> delete(@PathVariable(name = "userId")
|
||||
Integer userId)
|
||||
{
|
||||
if (!users.isEmpty() && users.containsKey(userId))
|
||||
{
|
||||
users.remove(userId);
|
||||
return R.ok();
|
||||
}
|
||||
else
|
||||
{
|
||||
return R.fail("用户不存在");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Schema(description = "用户实体")
|
||||
class UserEntity
|
||||
{
|
||||
@Schema(title = "用户ID")
|
||||
private Integer userId;
|
||||
|
||||
@Schema(title = "用户名称")
|
||||
private String username;
|
||||
|
||||
@Schema(title = "用户密码")
|
||||
private String password;
|
||||
|
||||
@Schema(title = "用户手机")
|
||||
private String mobile;
|
||||
|
||||
public UserEntity()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public UserEntity(Integer userId, String username, String password, String mobile)
|
||||
{
|
||||
this.userId = userId;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.mobile = mobile;
|
||||
}
|
||||
|
||||
public Integer getUserId()
|
||||
{
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(Integer userId)
|
||||
{
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getUsername()
|
||||
{
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username)
|
||||
{
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword()
|
||||
{
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password)
|
||||
{
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getMobile()
|
||||
{
|
||||
return mobile;
|
||||
}
|
||||
|
||||
public void setMobile(String mobile)
|
||||
{
|
||||
this.mobile = mobile;
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.controller.tool;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
||||
/**
|
||||
* swagger 用户测试方法
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Api("用户信息管理")
|
||||
@RestController
|
||||
@RequestMapping("/test/user")
|
||||
public class TestController extends BaseController
|
||||
{
|
||||
private final static Map<Integer, UserEntity> users = new LinkedHashMap<Integer, UserEntity>();
|
||||
{
|
||||
users.put(1, new UserEntity(1, "admin", "admin123", "15888888888"));
|
||||
users.put(2, new UserEntity(2, "ry", "admin123", "15666666666"));
|
||||
}
|
||||
|
||||
@ApiOperation("获取用户列表")
|
||||
@GetMapping("/list")
|
||||
public R<List<UserEntity>> userList()
|
||||
{
|
||||
List<UserEntity> userList = new ArrayList<UserEntity>(users.values());
|
||||
return R.ok(userList);
|
||||
}
|
||||
|
||||
@ApiOperation("获取用户详细")
|
||||
@ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
|
||||
@GetMapping("/{userId}")
|
||||
public R<UserEntity> getUser(@PathVariable Integer userId)
|
||||
{
|
||||
if (!users.isEmpty() && users.containsKey(userId))
|
||||
{
|
||||
return R.ok(users.get(userId));
|
||||
}
|
||||
else
|
||||
{
|
||||
return R.fail("用户不存在");
|
||||
}
|
||||
}
|
||||
|
||||
@ApiOperation("新增用户")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", dataTypeClass = Integer.class),
|
||||
@ApiImplicitParam(name = "username", value = "用户名称", dataType = "String", dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "password", value = "用户密码", dataType = "String", dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class)
|
||||
})
|
||||
@PostMapping("/save")
|
||||
public R<String> save(UserEntity user)
|
||||
{
|
||||
if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
|
||||
{
|
||||
return R.fail("用户ID不能为空");
|
||||
}
|
||||
users.put(user.getUserId(), user);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@ApiOperation("更新用户")
|
||||
@PutMapping("/update")
|
||||
public R<String> update(@RequestBody UserEntity user)
|
||||
{
|
||||
if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
|
||||
{
|
||||
return R.fail("用户ID不能为空");
|
||||
}
|
||||
if (users.isEmpty() || !users.containsKey(user.getUserId()))
|
||||
{
|
||||
return R.fail("用户不存在");
|
||||
}
|
||||
users.remove(user.getUserId());
|
||||
users.put(user.getUserId(), user);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@ApiOperation("删除用户信息")
|
||||
@ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
|
||||
@DeleteMapping("/{userId}")
|
||||
public R<String> delete(@PathVariable Integer userId)
|
||||
{
|
||||
if (!users.isEmpty() && users.containsKey(userId))
|
||||
{
|
||||
users.remove(userId);
|
||||
return R.ok();
|
||||
}
|
||||
else
|
||||
{
|
||||
return R.fail("用户不存在");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ApiModel(value = "UserEntity", description = "用户实体")
|
||||
class UserEntity
|
||||
{
|
||||
@ApiModelProperty("用户ID")
|
||||
private Integer userId;
|
||||
|
||||
@ApiModelProperty("用户名称")
|
||||
private String username;
|
||||
|
||||
@ApiModelProperty("用户密码")
|
||||
private String password;
|
||||
|
||||
@ApiModelProperty("用户手机")
|
||||
private String mobile;
|
||||
|
||||
public UserEntity()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public UserEntity(Integer userId, String username, String password, String mobile)
|
||||
{
|
||||
this.userId = userId;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.mobile = mobile;
|
||||
}
|
||||
|
||||
public Integer getUserId()
|
||||
{
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(Integer userId)
|
||||
{
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getUsername()
|
||||
{
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username)
|
||||
{
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword()
|
||||
{
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password)
|
||||
{
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getMobile()
|
||||
{
|
||||
return mobile;
|
||||
}
|
||||
|
||||
public void setMobile(String mobile)
|
||||
{
|
||||
this.mobile = mobile;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,64 +1,125 @@
|
||||
package com.ruoyi.web.core.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import com.ruoyi.common.config.RuoYiConfig;
|
||||
import io.swagger.v3.oas.models.Components;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Contact;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import io.swagger.v3.oas.models.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.models.security.SecurityScheme;
|
||||
|
||||
/**
|
||||
* Swagger2的接口配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Configuration
|
||||
public class SwaggerConfig
|
||||
{
|
||||
/** 系统基础配置 */
|
||||
@Autowired
|
||||
private RuoYiConfig ruoyiConfig;
|
||||
|
||||
/**
|
||||
* 自定义的 OpenAPI 对象
|
||||
*/
|
||||
@Bean
|
||||
public OpenAPI customOpenApi()
|
||||
{
|
||||
return new OpenAPI().components(new Components()
|
||||
// 设置认证的请求头
|
||||
.addSecuritySchemes("apikey", securityScheme()))
|
||||
.addSecurityItem(new SecurityRequirement().addList("apikey"))
|
||||
.info(getApiInfo());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityScheme securityScheme()
|
||||
{
|
||||
return new SecurityScheme()
|
||||
.type(SecurityScheme.Type.APIKEY)
|
||||
.name("Authorization")
|
||||
.in(SecurityScheme.In.HEADER)
|
||||
.scheme("Bearer");
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加摘要信息
|
||||
*/
|
||||
public Info getApiInfo()
|
||||
{
|
||||
return new Info()
|
||||
// 设置标题
|
||||
.title("标题:若依管理系统_接口文档")
|
||||
// 描述
|
||||
.description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
|
||||
// 作者信息
|
||||
.contact(new Contact().name(ruoyiConfig.getName()))
|
||||
// 版本
|
||||
.version("版本号:" + ruoyiConfig.getVersion());
|
||||
}
|
||||
}
|
||||
package com.ruoyi.web.core.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import com.ruoyi.common.config.RuoYiConfig;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.models.auth.In;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||
import springfox.documentation.service.ApiInfo;
|
||||
import springfox.documentation.service.ApiKey;
|
||||
import springfox.documentation.service.AuthorizationScope;
|
||||
import springfox.documentation.service.Contact;
|
||||
import springfox.documentation.service.SecurityReference;
|
||||
import springfox.documentation.service.SecurityScheme;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spi.service.contexts.SecurityContext;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
|
||||
/**
|
||||
* Swagger2的接口配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Configuration
|
||||
public class SwaggerConfig
|
||||
{
|
||||
/** 系统基础配置 */
|
||||
@Autowired
|
||||
private RuoYiConfig ruoyiConfig;
|
||||
|
||||
/** 是否开启swagger */
|
||||
@Value("${swagger.enabled}")
|
||||
private boolean enabled;
|
||||
|
||||
/** 设置请求的统一前缀 */
|
||||
@Value("${swagger.pathMapping}")
|
||||
private String pathMapping;
|
||||
|
||||
/**
|
||||
* 创建API
|
||||
*/
|
||||
@Bean
|
||||
public Docket createRestApi()
|
||||
{
|
||||
return new Docket(DocumentationType.OAS_30)
|
||||
// 是否启用Swagger
|
||||
.enable(enabled)
|
||||
// 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
|
||||
.apiInfo(apiInfo())
|
||||
// 设置哪些接口暴露给Swagger展示
|
||||
.select()
|
||||
// 扫描所有有注解的api,用这种方式更灵活
|
||||
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
|
||||
// 扫描指定包中的swagger注解
|
||||
// .apis(RequestHandlerSelectors.basePackage("com.ruoyi.project.tool.swagger"))
|
||||
// 扫描所有 .apis(RequestHandlerSelectors.any())
|
||||
.paths(PathSelectors.any())
|
||||
.build()
|
||||
/* 设置安全模式,swagger可以设置访问token */
|
||||
.securitySchemes(securitySchemes())
|
||||
.securityContexts(securityContexts())
|
||||
.pathMapping(pathMapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全模式,这里指定token通过Authorization头请求头传递
|
||||
*/
|
||||
private List<SecurityScheme> securitySchemes()
|
||||
{
|
||||
List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
|
||||
apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue()));
|
||||
return apiKeyList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全上下文
|
||||
*/
|
||||
private List<SecurityContext> securityContexts()
|
||||
{
|
||||
List<SecurityContext> securityContexts = new ArrayList<>();
|
||||
securityContexts.add(
|
||||
SecurityContext.builder()
|
||||
.securityReferences(defaultAuth())
|
||||
.operationSelector(o -> o.requestMappingPattern().matches("/.*"))
|
||||
.build());
|
||||
return securityContexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认的安全上引用
|
||||
*/
|
||||
private List<SecurityReference> defaultAuth()
|
||||
{
|
||||
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
|
||||
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
|
||||
authorizationScopes[0] = authorizationScope;
|
||||
List<SecurityReference> securityReferences = new ArrayList<>();
|
||||
securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
|
||||
return securityReferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加摘要信息
|
||||
*/
|
||||
private ApiInfo apiInfo()
|
||||
{
|
||||
// 用ApiInfoBuilder进行定制
|
||||
return new ApiInfoBuilder()
|
||||
// 设置标题
|
||||
.title("标题:若依管理系统_接口文档")
|
||||
// 描述
|
||||
.description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
|
||||
// 作者信息
|
||||
.contact(new Contact(ruoyiConfig.getName(), null, null))
|
||||
// 版本
|
||||
.version("版本号:" + ruoyiConfig.getVersion())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
61
ruoyi-admin/src/main/resources/application-druid.yml
Normal file
61
ruoyi-admin/src/main/resources/application-druid.yml
Normal file
@@ -0,0 +1,61 @@
|
||||
# 数据源配置
|
||||
spring:
|
||||
datasource:
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
druid:
|
||||
# 主库数据源
|
||||
master:
|
||||
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
username: root
|
||||
password: password
|
||||
# 从库数据源
|
||||
slave:
|
||||
# 从数据源开关/默认关闭
|
||||
enabled: false
|
||||
url:
|
||||
username:
|
||||
password:
|
||||
# 初始连接数
|
||||
initialSize: 5
|
||||
# 最小连接池数量
|
||||
minIdle: 10
|
||||
# 最大连接池数量
|
||||
maxActive: 20
|
||||
# 配置获取连接等待超时的时间
|
||||
maxWait: 60000
|
||||
# 配置连接超时时间
|
||||
connectTimeout: 30000
|
||||
# 配置网络超时时间
|
||||
socketTimeout: 60000
|
||||
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||
timeBetweenEvictionRunsMillis: 60000
|
||||
# 配置一个连接在池中最小生存的时间,单位是毫秒
|
||||
minEvictableIdleTimeMillis: 300000
|
||||
# 配置一个连接在池中最大生存的时间,单位是毫秒
|
||||
maxEvictableIdleTimeMillis: 900000
|
||||
# 配置检测连接是否有效
|
||||
validationQuery: SELECT 1 FROM DUAL
|
||||
testWhileIdle: true
|
||||
testOnBorrow: false
|
||||
testOnReturn: false
|
||||
webStatFilter:
|
||||
enabled: true
|
||||
statViewServlet:
|
||||
enabled: true
|
||||
# 设置白名单,不填则允许所有访问
|
||||
allow:
|
||||
url-pattern: /druid/*
|
||||
# 控制台管理用户名和密码
|
||||
login-username: ruoyi
|
||||
login-password: 123456
|
||||
filter:
|
||||
stat:
|
||||
enabled: true
|
||||
# 慢SQL记录
|
||||
log-slow-sql: true
|
||||
slow-sql-millis: 1000
|
||||
merge-sql: true
|
||||
wall:
|
||||
config:
|
||||
multi-statement-allow: true
|
||||
@@ -3,7 +3,7 @@ ruoyi:
|
||||
# 名称
|
||||
name: RuoYi
|
||||
# 版本
|
||||
version: 3.9.1
|
||||
version: 3.9.2
|
||||
# 版权年份
|
||||
copyrightYear: 2026
|
||||
# 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
|
||||
@@ -49,6 +49,19 @@ spring:
|
||||
restart:
|
||||
# 热部署开关
|
||||
enabled: true
|
||||
# redis 配置
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
database: 0
|
||||
password:
|
||||
timeout: 10s
|
||||
lettuce:
|
||||
pool:
|
||||
min-idle: 0
|
||||
max-idle: 8
|
||||
max-active: 8
|
||||
max-wait: -1ms
|
||||
|
||||
|
||||
# token配置
|
||||
@@ -60,8 +73,8 @@ token:
|
||||
# 令牌有效期(默认30分钟)
|
||||
expireTime: 30
|
||||
|
||||
# MyBatis Plus配置
|
||||
mybatis-plus:
|
||||
# MyBatis配置
|
||||
mybatis:
|
||||
# 搜索指定包别名
|
||||
typeAliasesPackage: com.ruoyi.**.domain
|
||||
# 配置mapper的扫描,找到所有的mapper.xml映射文件
|
||||
@@ -75,14 +88,12 @@ pagehelper:
|
||||
supportMethodsArguments: true
|
||||
params: count=countSql
|
||||
|
||||
# Springdoc配置
|
||||
springdoc:
|
||||
api-docs:
|
||||
path: /v3/api-docs
|
||||
swagger-ui:
|
||||
enabled: true
|
||||
path: /swagger-ui.html
|
||||
tags-sorter: alpha
|
||||
# Swagger配置
|
||||
swagger:
|
||||
# 是否开启swagger
|
||||
enabled: true
|
||||
# 请求前缀
|
||||
pathMapping: /dev-api
|
||||
|
||||
# 防盗链配置
|
||||
referer:
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
Application Version: ${ruoyi.version}
|
||||
Spring Boot Version: ${spring-boot.version}
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// _ooOoo_ //
|
||||
// o8888888o //
|
||||
// 88" . "88 //
|
||||
// (| ^_^ |) //
|
||||
// O\ = /O //
|
||||
// ____/`---'\____ //
|
||||
// .' \\| |// `. //
|
||||
// / \\||| : |||// \ //
|
||||
// / _||||| -:- |||||- \ //
|
||||
// | | \\\ - /// | | //
|
||||
// | \_| ''\---/'' | | //
|
||||
// \ .-\__ `-` ___/-. / //
|
||||
// ___`. .' /--.--\ `. . ___ //
|
||||
// ."" '< `.___\_<|>_/___.' >'"". //
|
||||
// | | : `- \`.;`\ _ /`;.`/ - ` : | | //
|
||||
// \ \ `-. \_ __\ /__ _/ .-` / / //
|
||||
// ========`-.____`-.___\_____/___.-`____.-'======== //
|
||||
// `=---=' //
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
|
||||
// 佛祖保佑 永不宕机 永无BUG //
|
||||
Application Version: ${ruoyi.version}
|
||||
Spring Boot Version: ${spring-boot.version}
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// _ooOoo_ //
|
||||
// o8888888o //
|
||||
// 88" . "88 //
|
||||
// (| ^_^ |) //
|
||||
// O\ = /O //
|
||||
// ____/`---'\____ //
|
||||
// .' \\| |// `. //
|
||||
// / \\||| : |||// \ //
|
||||
// / _||||| -:- |||||- \ //
|
||||
// | | \\\ - /// | | //
|
||||
// | \_| ''\---/'' | | //
|
||||
// \ .-\__ `-` ___/-. / //
|
||||
// ___`. .' /--.--\ `. . ___ //
|
||||
// ."" '< `.___\_<|>_/___.' >'"". //
|
||||
// | | : `- \`.;`\ _ /`;.`/ - ` : | | //
|
||||
// \ \ `-. \_ __\ /__ _/ .-` / / //
|
||||
// ========`-.____`-.___\_____/___.-`____.-'======== //
|
||||
// `=---=' //
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
|
||||
// 佛祖保佑 永不宕机 永无BUG //
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@@ -1,38 +1,38 @@
|
||||
#错误消息
|
||||
not.null=* 必须填写
|
||||
user.jcaptcha.error=验证码错误
|
||||
user.jcaptcha.expire=验证码已失效
|
||||
user.not.exists=用户不存在/密码错误
|
||||
user.password.not.match=用户不存在/密码错误
|
||||
user.password.retry.limit.count=密码输入错误{0}次
|
||||
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
|
||||
user.password.delete=对不起,您的账号已被删除
|
||||
user.blocked=用户已封禁,请联系管理员
|
||||
role.blocked=角色已封禁,请联系管理员
|
||||
login.blocked=很遗憾,访问IP已被列入系统黑名单
|
||||
user.logout.success=退出成功
|
||||
|
||||
length.not.valid=长度必须在{min}到{max}个字符之间
|
||||
|
||||
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
|
||||
user.password.not.valid=* 5-50个字符
|
||||
|
||||
user.email.not.valid=邮箱格式错误
|
||||
user.mobile.phone.number.not.valid=手机号格式错误
|
||||
user.login.success=登录成功
|
||||
user.register.success=注册成功
|
||||
user.notfound=请重新登录
|
||||
user.forcelogout=管理员强制退出,请重新登录
|
||||
user.unknown.error=未知错误,请重新登录
|
||||
|
||||
##文件上传消息
|
||||
upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB!
|
||||
upload.filename.exceed.length=上传的文件名最长{0}个字符
|
||||
|
||||
##权限
|
||||
no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]
|
||||
#错误消息
|
||||
not.null=* 必须填写
|
||||
user.jcaptcha.error=验证码错误
|
||||
user.jcaptcha.expire=验证码已失效
|
||||
user.not.exists=用户不存在/密码错误
|
||||
user.password.not.match=用户不存在/密码错误
|
||||
user.password.retry.limit.count=密码输入错误{0}次
|
||||
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
|
||||
user.password.delete=对不起,您的账号已被删除
|
||||
user.blocked=用户已封禁,请联系管理员
|
||||
role.blocked=角色已封禁,请联系管理员
|
||||
login.blocked=很遗憾,访问IP已被列入系统黑名单
|
||||
user.logout.success=退出成功
|
||||
|
||||
length.not.valid=长度必须在{min}到{max}个字符之间
|
||||
|
||||
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
|
||||
user.password.not.valid=* 5-50个字符
|
||||
|
||||
user.email.not.valid=邮箱格式错误
|
||||
user.mobile.phone.number.not.valid=手机号格式错误
|
||||
user.login.success=登录成功
|
||||
user.register.success=注册成功
|
||||
user.notfound=请重新登录
|
||||
user.forcelogout=管理员强制退出,请重新登录
|
||||
user.unknown.error=未知错误,请重新登录
|
||||
|
||||
##文件上传消息
|
||||
upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB!
|
||||
upload.filename.exceed.length=上传的文件名最长{0}个字符
|
||||
|
||||
##权限
|
||||
no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
|
||||
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]
|
||||
|
||||
@@ -1,93 +1,93 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<!-- 日志存放路径 -->
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<!-- 日志存放路径 -->
|
||||
<property name="log.path" value="logs" />
|
||||
<!-- 日志输出格式 -->
|
||||
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 系统日志输出 -->
|
||||
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-info.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>INFO</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-error.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>ERROR</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- 用户访问日志输出 -->
|
||||
<appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-user.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 按天回滚 daily -->
|
||||
<fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 系统模块日志级别控制 -->
|
||||
<logger name="com.ruoyi" level="info" />
|
||||
<!-- Spring日志级别控制 -->
|
||||
<logger name="org.springframework" level="warn" />
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="console" />
|
||||
</root>
|
||||
|
||||
<!--系统操作日志-->
|
||||
<root level="info">
|
||||
<appender-ref ref="file_info" />
|
||||
<appender-ref ref="file_error" />
|
||||
</root>
|
||||
|
||||
<!--系统用户操作日志-->
|
||||
<logger name="sys-user" level="info">
|
||||
<appender-ref ref="sys-user"/>
|
||||
</logger>
|
||||
</configuration>
|
||||
<!-- 日志输出格式 -->
|
||||
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 系统日志输出 -->
|
||||
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-info.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>INFO</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-error.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>ERROR</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- 用户访问日志输出 -->
|
||||
<appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-user.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 按天回滚 daily -->
|
||||
<fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 系统模块日志级别控制 -->
|
||||
<logger name="com.ruoyi" level="info" />
|
||||
<!-- Spring日志级别控制 -->
|
||||
<logger name="org.springframework" level="warn" />
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="console" />
|
||||
</root>
|
||||
|
||||
<!--系统操作日志-->
|
||||
<root level="info">
|
||||
<appender-ref ref="file_info" />
|
||||
<appender-ref ref="file_error" />
|
||||
</root>
|
||||
|
||||
<!--系统用户操作日志-->
|
||||
<logger name="sys-user" level="info">
|
||||
<appender-ref ref="sys-user"/>
|
||||
</logger>
|
||||
</configuration>
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE configuration
|
||||
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-config.dtd">
|
||||
<configuration>
|
||||
<!-- 全局参数 -->
|
||||
<settings>
|
||||
<!-- 使全局的映射器启用或禁用缓存 -->
|
||||
<setting name="cacheEnabled" value="true" />
|
||||
<!-- 允许JDBC 支持自动生成主键 -->
|
||||
<setting name="useGeneratedKeys" value="true" />
|
||||
<!-- 配置默认的执行器.SIMPLE就是普通执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 -->
|
||||
<setting name="defaultExecutorType" value="SIMPLE" />
|
||||
<!-- 指定 MyBatis 所用日志的具体实现 -->
|
||||
<setting name="logImpl" value="SLF4J" />
|
||||
<!-- 使用驼峰命名法转换字段 -->
|
||||
<!-- <setting name="mapUnderscoreToCamelCase" value="true"/> -->
|
||||
</settings>
|
||||
|
||||
</configuration>
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE configuration
|
||||
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-config.dtd">
|
||||
<configuration>
|
||||
<!-- 全局参数 -->
|
||||
<settings>
|
||||
<!-- 使全局的映射器启用或禁用缓存 -->
|
||||
<setting name="cacheEnabled" value="true" />
|
||||
<!-- 允许JDBC 支持自动生成主键 -->
|
||||
<setting name="useGeneratedKeys" value="true" />
|
||||
<!-- 配置默认的执行器.SIMPLE就是普通执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 -->
|
||||
<setting name="defaultExecutorType" value="SIMPLE" />
|
||||
<!-- 指定 MyBatis 所用日志的具体实现 -->
|
||||
<setting name="logImpl" value="SLF4J" />
|
||||
<!-- 使用驼峰命名法转换字段 -->
|
||||
<!-- <setting name="mapUnderscoreToCamelCase" value="true"/> -->
|
||||
</settings>
|
||||
|
||||
</configuration>
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
window.onload = function() {
|
||||
window.ui = SwaggerUIBundle({
|
||||
url: "/v3/api-docs/default",
|
||||
configUrl: "/v3/api-docs/swagger-config",
|
||||
dom_id: '#swagger-ui',
|
||||
deepLinking: true,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout",
|
||||
tagsSorter: "alpha",
|
||||
validatorUrl: "",
|
||||
persistAuthorization: true
|
||||
});
|
||||
};
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.ruoyi.web.controller.monitor;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import com.ruoyi.common.core.cache.InMemoryCacheStore;
|
||||
import com.ruoyi.common.core.redis.RedisCache;
|
||||
|
||||
class CacheControllerTest
|
||||
{
|
||||
@Test
|
||||
void shouldReturnInMemoryCacheSummary() throws Exception
|
||||
{
|
||||
RedisCache redisCache = new RedisCache(new InMemoryCacheStore());
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new CacheController(redisCache)).build();
|
||||
|
||||
mockMvc.perform(get("/monitor/cache"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data.info.cache_type").value("IN_MEMORY"))
|
||||
.andExpect(jsonPath("$.data.info.cache_mode").value("single-instance"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldClearCacheKeysByPrefix() throws Exception
|
||||
{
|
||||
RedisCache redisCache = new RedisCache(new InMemoryCacheStore());
|
||||
redisCache.setCacheObject("login_tokens:a", "A");
|
||||
redisCache.setCacheObject("login_tokens:b", "B");
|
||||
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new CacheController(redisCache)).build();
|
||||
|
||||
mockMvc.perform(delete("/monitor/cache/clearCacheName/login_tokens:"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
mockMvc.perform(get("/monitor/cache/getKeys/login_tokens:"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data").isEmpty());
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import com.ruoyi.framework.web.service.PasswordTransferCryptoService;
|
||||
import com.ruoyi.framework.web.service.SysLoginService;
|
||||
|
||||
class SysLoginControllerPasswordTransferTest
|
||||
{
|
||||
@Test
|
||||
void shouldDecryptPasswordBeforeCallingLoginService() throws Exception
|
||||
{
|
||||
SysLoginService loginService = mock(SysLoginService.class);
|
||||
PasswordTransferCryptoService passwordTransferCryptoService = mock(PasswordTransferCryptoService.class);
|
||||
when(passwordTransferCryptoService.decrypt("cipher")).thenReturn("admin123");
|
||||
when(loginService.login("admin", "admin123", "1", "u")).thenReturn("token");
|
||||
|
||||
SysLoginController controller = new SysLoginController();
|
||||
ReflectionTestUtils.setField(controller, "loginService", loginService);
|
||||
ReflectionTestUtils.setField(controller, "passwordTransferCryptoService", passwordTransferCryptoService);
|
||||
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
|
||||
|
||||
mockMvc.perform(post("/login")
|
||||
.contentType("application/json")
|
||||
.content("{\"username\":\"admin\",\"password\":\"cipher\",\"code\":\"1\",\"uuid\":\"u\"}"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
verify(passwordTransferCryptoService).decrypt("cipher");
|
||||
verify(loginService).login("admin", "admin123", "1", "u");
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.Collections;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.framework.web.service.PasswordTransferCryptoService;
|
||||
import com.ruoyi.framework.web.service.TokenService;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
|
||||
class SysProfileControllerPasswordTransferTest
|
||||
{
|
||||
@AfterEach
|
||||
void tearDown()
|
||||
{
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDecryptPasswordsBeforeCheckingOldPassword() throws Exception
|
||||
{
|
||||
ISysUserService userService = mock(ISysUserService.class);
|
||||
TokenService tokenService = mock(TokenService.class);
|
||||
PasswordTransferCryptoService passwordTransferCryptoService = mock(PasswordTransferCryptoService.class);
|
||||
when(passwordTransferCryptoService.decrypt("oldCipher")).thenReturn("oldPlain");
|
||||
when(passwordTransferCryptoService.decrypt("newCipher")).thenReturn("newPlain");
|
||||
when(userService.resetUserPwd(org.mockito.ArgumentMatchers.anyLong(), org.mockito.ArgumentMatchers.anyString()))
|
||||
.thenReturn(1);
|
||||
|
||||
SysUser storedUser = new SysUser();
|
||||
storedUser.setUserId(2L);
|
||||
storedUser.setPassword(SecurityUtils.encryptPassword("oldPlain"));
|
||||
when(userService.selectUserById(2L)).thenReturn(storedUser);
|
||||
|
||||
SysUser currentUser = new SysUser();
|
||||
currentUser.setUserId(2L);
|
||||
currentUser.setUserName("admin");
|
||||
LoginUser loginUser = new LoginUser(2L, 1L, currentUser, Collections.emptySet());
|
||||
SecurityContextHolder.getContext()
|
||||
.setAuthentication(new UsernamePasswordAuthenticationToken(loginUser, null, Collections.emptyList()));
|
||||
|
||||
SysProfileController controller = new SysProfileController();
|
||||
ReflectionTestUtils.setField(controller, "userService", userService);
|
||||
ReflectionTestUtils.setField(controller, "tokenService", tokenService);
|
||||
ReflectionTestUtils.setField(controller, "passwordTransferCryptoService", passwordTransferCryptoService);
|
||||
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
|
||||
|
||||
mockMvc.perform(put("/system/user/profile/updatePwd")
|
||||
.contentType("application/json")
|
||||
.content("{\"oldPassword\":\"oldCipher\",\"newPassword\":\"newCipher\"}"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
verify(passwordTransferCryptoService).decrypt("oldCipher");
|
||||
verify(passwordTransferCryptoService).decrypt("newCipher");
|
||||
verify(userService).resetUserPwd(org.mockito.ArgumentMatchers.eq(2L), org.mockito.ArgumentMatchers.anyString());
|
||||
verify(tokenService).setLoginUser(loginUser);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import com.ruoyi.common.core.domain.model.RegisterBody;
|
||||
import com.ruoyi.framework.web.service.PasswordTransferCryptoService;
|
||||
import com.ruoyi.framework.web.service.SysRegisterService;
|
||||
import com.ruoyi.system.service.ISysConfigService;
|
||||
|
||||
class SysRegisterControllerPasswordTransferTest
|
||||
{
|
||||
@Test
|
||||
void shouldDecryptPasswordBeforeCallingRegisterService() throws Exception
|
||||
{
|
||||
SysRegisterService registerService = mock(SysRegisterService.class);
|
||||
ISysConfigService configService = mock(ISysConfigService.class);
|
||||
PasswordTransferCryptoService passwordTransferCryptoService = mock(PasswordTransferCryptoService.class);
|
||||
when(configService.selectConfigByKey("sys.account.registerUser")).thenReturn("true");
|
||||
when(passwordTransferCryptoService.decrypt("cipher")).thenReturn("admin123");
|
||||
when(registerService.register(any(RegisterBody.class))).thenReturn("");
|
||||
|
||||
SysRegisterController controller = new SysRegisterController();
|
||||
ReflectionTestUtils.setField(controller, "registerService", registerService);
|
||||
ReflectionTestUtils.setField(controller, "configService", configService);
|
||||
ReflectionTestUtils.setField(controller, "passwordTransferCryptoService", passwordTransferCryptoService);
|
||||
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
|
||||
|
||||
mockMvc.perform(post("/register")
|
||||
.contentType("application/json")
|
||||
.content("{\"username\":\"u1\",\"password\":\"cipher\",\"code\":\"1\",\"uuid\":\"u\"}"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
verify(passwordTransferCryptoService).decrypt("cipher");
|
||||
ArgumentCaptor<RegisterBody> captor = ArgumentCaptor.forClass(RegisterBody.class);
|
||||
verify(registerService).register(captor.capture());
|
||||
assertEquals("admin123", captor.getValue().getPassword());
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.Collections;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.framework.web.service.PasswordTransferCryptoService;
|
||||
import com.ruoyi.system.service.ISysDeptService;
|
||||
import com.ruoyi.system.service.ISysPostService;
|
||||
import com.ruoyi.system.service.ISysRoleService;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
|
||||
class SysUserControllerPasswordTransferTest
|
||||
{
|
||||
@AfterEach
|
||||
void tearDown()
|
||||
{
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDecryptPasswordBeforeAddingUser() throws Exception
|
||||
{
|
||||
ISysUserService userService = mock(ISysUserService.class);
|
||||
ISysRoleService roleService = mock(ISysRoleService.class);
|
||||
ISysDeptService deptService = mock(ISysDeptService.class);
|
||||
ISysPostService postService = mock(ISysPostService.class);
|
||||
PasswordTransferCryptoService passwordTransferCryptoService = mock(PasswordTransferCryptoService.class);
|
||||
when(passwordTransferCryptoService.decrypt("cipher")).thenReturn("initPwd");
|
||||
when(userService.checkUserNameUnique(org.mockito.ArgumentMatchers.any(SysUser.class))).thenReturn(true);
|
||||
when(userService.insertUser(org.mockito.ArgumentMatchers.any(SysUser.class))).thenReturn(1);
|
||||
|
||||
setAuthentication();
|
||||
|
||||
SysUserController controller = new SysUserController();
|
||||
ReflectionTestUtils.setField(controller, "userService", userService);
|
||||
ReflectionTestUtils.setField(controller, "roleService", roleService);
|
||||
ReflectionTestUtils.setField(controller, "deptService", deptService);
|
||||
ReflectionTestUtils.setField(controller, "postService", postService);
|
||||
ReflectionTestUtils.setField(controller, "passwordTransferCryptoService", passwordTransferCryptoService);
|
||||
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
|
||||
|
||||
mockMvc.perform(post("/system/user")
|
||||
.contentType("application/json")
|
||||
.content("{\"userName\":\"u1\",\"nickName\":\"n1\",\"deptId\":1,\"password\":\"cipher\"}"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
verify(passwordTransferCryptoService).decrypt("cipher");
|
||||
ArgumentCaptor<SysUser> captor = ArgumentCaptor.forClass(SysUser.class);
|
||||
verify(userService).insertUser(captor.capture());
|
||||
assertTrue(SecurityUtils.matchesPassword("initPwd", captor.getValue().getPassword()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDecryptPasswordBeforeResettingUserPassword() throws Exception
|
||||
{
|
||||
ISysUserService userService = mock(ISysUserService.class);
|
||||
ISysRoleService roleService = mock(ISysRoleService.class);
|
||||
ISysDeptService deptService = mock(ISysDeptService.class);
|
||||
ISysPostService postService = mock(ISysPostService.class);
|
||||
PasswordTransferCryptoService passwordTransferCryptoService = mock(PasswordTransferCryptoService.class);
|
||||
when(passwordTransferCryptoService.decrypt("cipher")).thenReturn("resetPwd");
|
||||
when(userService.resetPwd(org.mockito.ArgumentMatchers.any(SysUser.class))).thenReturn(1);
|
||||
|
||||
setAuthentication();
|
||||
|
||||
SysUserController controller = new SysUserController();
|
||||
ReflectionTestUtils.setField(controller, "userService", userService);
|
||||
ReflectionTestUtils.setField(controller, "roleService", roleService);
|
||||
ReflectionTestUtils.setField(controller, "deptService", deptService);
|
||||
ReflectionTestUtils.setField(controller, "postService", postService);
|
||||
ReflectionTestUtils.setField(controller, "passwordTransferCryptoService", passwordTransferCryptoService);
|
||||
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
|
||||
|
||||
mockMvc.perform(put("/system/user/resetPwd")
|
||||
.contentType("application/json")
|
||||
.content("{\"userId\":2,\"password\":\"cipher\"}"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
verify(passwordTransferCryptoService).decrypt("cipher");
|
||||
ArgumentCaptor<SysUser> captor = ArgumentCaptor.forClass(SysUser.class);
|
||||
verify(userService).resetPwd(captor.capture());
|
||||
assertTrue(SecurityUtils.matchesPassword("resetPwd", captor.getValue().getPassword()));
|
||||
}
|
||||
|
||||
private void setAuthentication()
|
||||
{
|
||||
SysUser currentUser = new SysUser();
|
||||
currentUser.setUserId(1L);
|
||||
currentUser.setUserName("admin");
|
||||
LoginUser loginUser = new LoginUser(1L, 1L, currentUser, Collections.emptySet());
|
||||
SecurityContextHolder.getContext()
|
||||
.setAuthentication(new UsernamePasswordAuthenticationToken(loginUser, null, Collections.emptyList()));
|
||||
}
|
||||
}
|
||||
@@ -1,130 +1,118 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<version>3.9.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
|
||||
<description>
|
||||
common通用工具
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- Spring框架基本的核心工具 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringWeb模块 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- spring security 安全认证 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- pagehelper 分页插件 -->
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 自定义验证注解 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--常用工具类 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JSON工具类 -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 阿里JSON解析器 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- io常用工具类 -->
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- excel工具 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Token生成与解析-->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Jaxb -->
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 解析客户端操作系统、浏览器等 -->
|
||||
<dependency>
|
||||
<groupId>nl.basjes.parse.useragent</groupId>
|
||||
<artifactId>yauaa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- servlet包 -->
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
</dependency>
|
||||
<!-- ruoyi-springboot3 / mybatis-plus 配置 -->
|
||||
<dependency>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis</artifactId>
|
||||
<version>3.5.16</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||
<version>3.5.10</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-jsqlparser</artifactId>
|
||||
<version>3.5.10</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<version>3.9.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
|
||||
<description>
|
||||
common通用工具
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- Spring框架基本的核心工具 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringWeb模块 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- spring security 安全认证 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- pagehelper 分页插件 -->
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 自定义验证注解 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--常用工具类 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JSON工具类 -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 阿里JSON解析器 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- io常用工具类 -->
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- excel工具 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Token生成与解析-->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Jaxb -->
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- redis 缓存操作 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- pool 对象池 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 解析客户端操作系统、浏览器等 -->
|
||||
<dependency>
|
||||
<groupId>nl.basjes.parse.useragent</groupId>
|
||||
<artifactId>yauaa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- servlet包 -->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1,19 +1,19 @@
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 匿名访问不鉴权注解
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Anonymous
|
||||
{
|
||||
}
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 匿名访问不鉴权注解
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Anonymous
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,33 +1,43 @@
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 数据权限过滤注解
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface DataScope
|
||||
{
|
||||
/**
|
||||
* 部门表的别名
|
||||
*/
|
||||
public String deptAlias() default "";
|
||||
|
||||
/**
|
||||
* 用户表的别名
|
||||
*/
|
||||
public String userAlias() default "";
|
||||
|
||||
/**
|
||||
* 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取,多个权限用逗号分隔开来
|
||||
*/
|
||||
public String permission() default "";
|
||||
}
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 数据权限过滤注解
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface DataScope
|
||||
{
|
||||
/**
|
||||
* 用户表的别名
|
||||
*/
|
||||
public String userAlias() default "";
|
||||
|
||||
/**
|
||||
* 部门表的别名
|
||||
*/
|
||||
public String deptAlias() default "";
|
||||
|
||||
/**
|
||||
* 用户字段名
|
||||
*/
|
||||
public String userField() default "user_id";
|
||||
|
||||
/**
|
||||
* 部门字段名
|
||||
*/
|
||||
public String deptField() default "dept_id";
|
||||
|
||||
/**
|
||||
* 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取,多个权限用逗号分隔开来
|
||||
*/
|
||||
public String permission() default "";
|
||||
}
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import com.ruoyi.common.enums.DataSourceType;
|
||||
|
||||
/**
|
||||
* 自定义多数据源切换注解
|
||||
*
|
||||
* 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface DataSource
|
||||
{
|
||||
/**
|
||||
* 切换数据源名称
|
||||
*/
|
||||
public DataSourceType value() default DataSourceType.MASTER;
|
||||
}
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import com.ruoyi.common.enums.DataSourceType;
|
||||
|
||||
/**
|
||||
* 自定义多数据源切换注解
|
||||
*
|
||||
* 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface DataSource
|
||||
{
|
||||
/**
|
||||
* 切换数据源名称
|
||||
*/
|
||||
public DataSourceType value() default DataSourceType.MASTER;
|
||||
}
|
||||
|
||||
@@ -1,198 +1,197 @@
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.math.BigDecimal;
|
||||
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
import com.ruoyi.common.utils.poi.ExcelHandlerAdapter;
|
||||
|
||||
/**
|
||||
* 自定义导出Excel数据注解
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Excel
|
||||
{
|
||||
/**
|
||||
* 导出时在excel中排序
|
||||
*/
|
||||
public int sort() default Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* 导出到Excel中的名字.
|
||||
*/
|
||||
public String name() default "";
|
||||
|
||||
/**
|
||||
* 日期格式, 如: yyyy-MM-dd
|
||||
*/
|
||||
public String dateFormat() default "";
|
||||
|
||||
/**
|
||||
* 如果是字典类型,请设置字典的type值 (如: sys_user_sex)
|
||||
*/
|
||||
public String dictType() default "";
|
||||
|
||||
/**
|
||||
* 读取内容转表达式 (如: 0=男,1=女,2=未知)
|
||||
*/
|
||||
public String readConverterExp() default "";
|
||||
|
||||
/**
|
||||
* 分隔符,读取字符串组内容
|
||||
*/
|
||||
public String separator() default ",";
|
||||
|
||||
/**
|
||||
* BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
|
||||
*/
|
||||
public int scale() default -1;
|
||||
|
||||
/**
|
||||
* BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
|
||||
|
||||
/**
|
||||
* 导出时在excel中每个列的高度
|
||||
*/
|
||||
public double height() default 14;
|
||||
|
||||
/**
|
||||
* 导出时在excel中每个列的宽度
|
||||
*/
|
||||
public double width() default 16;
|
||||
|
||||
/**
|
||||
* 文字后缀,如% 90 变成90%
|
||||
*/
|
||||
public String suffix() default "";
|
||||
|
||||
/**
|
||||
* 当值为空时,字段的默认值
|
||||
*/
|
||||
public String defaultValue() default "";
|
||||
|
||||
/**
|
||||
* 提示信息
|
||||
*/
|
||||
public String prompt() default "";
|
||||
|
||||
/**
|
||||
* 是否允许内容换行
|
||||
*/
|
||||
public boolean wrapText() default false;
|
||||
|
||||
/**
|
||||
* 设置只能选择不能输入的列内容.
|
||||
*/
|
||||
public String[] combo() default {};
|
||||
|
||||
/**
|
||||
* 是否从字典读数据到combo,默认不读取,如读取需要设置dictType注解.
|
||||
*/
|
||||
public boolean comboReadDict() default false;
|
||||
|
||||
/**
|
||||
* 是否需要纵向合并单元格,应对需求:含有list集合单元格)
|
||||
*/
|
||||
public boolean needMerge() default false;
|
||||
|
||||
/**
|
||||
* 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
|
||||
*/
|
||||
public boolean isExport() default true;
|
||||
|
||||
/**
|
||||
* 另一个类中的属性名称,支持多级获取,以小数点隔开
|
||||
*/
|
||||
public String targetAttr() default "";
|
||||
|
||||
/**
|
||||
* 是否自动统计数据,在最后追加一行统计数据总和
|
||||
*/
|
||||
public boolean isStatistics() default false;
|
||||
|
||||
/**
|
||||
* 导出类型(0数字 1字符串 2图片)
|
||||
*/
|
||||
public ColumnType cellType() default ColumnType.STRING;
|
||||
|
||||
/**
|
||||
* 导出列头背景颜色
|
||||
*/
|
||||
public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
|
||||
|
||||
/**
|
||||
* 导出列头字体颜色
|
||||
*/
|
||||
public IndexedColors headerColor() default IndexedColors.WHITE;
|
||||
|
||||
/**
|
||||
* 导出单元格背景颜色
|
||||
*/
|
||||
public IndexedColors backgroundColor() default IndexedColors.WHITE;
|
||||
|
||||
/**
|
||||
* 导出单元格字体颜色
|
||||
*/
|
||||
public IndexedColors color() default IndexedColors.BLACK;
|
||||
|
||||
/**
|
||||
* 导出字段对齐方式
|
||||
*/
|
||||
public HorizontalAlignment align() default HorizontalAlignment.CENTER;
|
||||
|
||||
/**
|
||||
* 自定义数据处理器
|
||||
*/
|
||||
public Class<?> handler() default ExcelHandlerAdapter.class;
|
||||
|
||||
/**
|
||||
* 自定义数据处理器参数
|
||||
*/
|
||||
public String[] args() default {};
|
||||
|
||||
/**
|
||||
* 字段类型(0:导出导入;1:仅导出;2:仅导入)
|
||||
*/
|
||||
Type type() default Type.ALL;
|
||||
|
||||
public enum Type
|
||||
{
|
||||
ALL(0), EXPORT(1), IMPORT(2);
|
||||
private final int value;
|
||||
|
||||
Type(int value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int value()
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ColumnType
|
||||
{
|
||||
NUMERIC(0), STRING(1), IMAGE(2), TEXT(3);
|
||||
private final int value;
|
||||
|
||||
ColumnType(int value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int value()
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.math.BigDecimal;
|
||||
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
import com.ruoyi.common.utils.poi.ExcelHandlerAdapter;
|
||||
|
||||
/**
|
||||
* 自定义导出Excel数据注解
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Excel
|
||||
{
|
||||
/**
|
||||
* 导出时在excel中排序
|
||||
*/
|
||||
public int sort() default Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* 导出到Excel中的名字.
|
||||
*/
|
||||
public String name() default "";
|
||||
|
||||
/**
|
||||
* 日期格式, 如: yyyy-MM-dd
|
||||
*/
|
||||
public String dateFormat() default "";
|
||||
|
||||
/**
|
||||
* 如果是字典类型,请设置字典的type值 (如: sys_user_sex)
|
||||
*/
|
||||
public String dictType() default "";
|
||||
|
||||
/**
|
||||
* 读取内容转表达式 (如: 0=男,1=女,2=未知)
|
||||
*/
|
||||
public String readConverterExp() default "";
|
||||
|
||||
/**
|
||||
* 分隔符,读取字符串组内容
|
||||
*/
|
||||
public String separator() default ",";
|
||||
|
||||
/**
|
||||
* BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
|
||||
*/
|
||||
public int scale() default -1;
|
||||
|
||||
/**
|
||||
* BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
|
||||
*/
|
||||
public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
|
||||
|
||||
/**
|
||||
* 导出时在excel中每个列的高度
|
||||
*/
|
||||
public double height() default 14;
|
||||
|
||||
/**
|
||||
* 导出时在excel中每个列的宽度
|
||||
*/
|
||||
public double width() default 16;
|
||||
|
||||
/**
|
||||
* 文字后缀,如% 90 变成90%
|
||||
*/
|
||||
public String suffix() default "";
|
||||
|
||||
/**
|
||||
* 当值为空时,字段的默认值
|
||||
*/
|
||||
public String defaultValue() default "";
|
||||
|
||||
/**
|
||||
* 提示信息
|
||||
*/
|
||||
public String prompt() default "";
|
||||
|
||||
/**
|
||||
* 是否允许内容换行
|
||||
*/
|
||||
public boolean wrapText() default false;
|
||||
|
||||
/**
|
||||
* 设置只能选择不能输入的列内容.
|
||||
*/
|
||||
public String[] combo() default {};
|
||||
|
||||
/**
|
||||
* 是否从字典读数据到combo,默认不读取,如读取需要设置dictType注解.
|
||||
*/
|
||||
public boolean comboReadDict() default false;
|
||||
|
||||
/**
|
||||
* 是否需要纵向合并单元格,应对需求:含有list集合单元格)
|
||||
*/
|
||||
public boolean needMerge() default false;
|
||||
|
||||
/**
|
||||
* 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
|
||||
*/
|
||||
public boolean isExport() default true;
|
||||
|
||||
/**
|
||||
* 另一个类中的属性名称,支持多级获取,以小数点隔开
|
||||
*/
|
||||
public String targetAttr() default "";
|
||||
|
||||
/**
|
||||
* 是否自动统计数据,在最后追加一行统计数据总和
|
||||
*/
|
||||
public boolean isStatistics() default false;
|
||||
|
||||
/**
|
||||
* 导出类型(0数字 1字符串 2图片)
|
||||
*/
|
||||
public ColumnType cellType() default ColumnType.STRING;
|
||||
|
||||
/**
|
||||
* 导出列头背景颜色
|
||||
*/
|
||||
public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
|
||||
|
||||
/**
|
||||
* 导出列头字体颜色
|
||||
*/
|
||||
public IndexedColors headerColor() default IndexedColors.WHITE;
|
||||
|
||||
/**
|
||||
* 导出单元格背景颜色
|
||||
*/
|
||||
public IndexedColors backgroundColor() default IndexedColors.WHITE;
|
||||
|
||||
/**
|
||||
* 导出单元格字体颜色
|
||||
*/
|
||||
public IndexedColors color() default IndexedColors.BLACK;
|
||||
|
||||
/**
|
||||
* 导出字段对齐方式
|
||||
*/
|
||||
public HorizontalAlignment align() default HorizontalAlignment.CENTER;
|
||||
|
||||
/**
|
||||
* 自定义数据处理器
|
||||
*/
|
||||
public Class<?> handler() default ExcelHandlerAdapter.class;
|
||||
|
||||
/**
|
||||
* 自定义数据处理器参数
|
||||
*/
|
||||
public String[] args() default {};
|
||||
|
||||
/**
|
||||
* 字段类型(0:导出导入;1:仅导出;2:仅导入)
|
||||
*/
|
||||
Type type() default Type.ALL;
|
||||
|
||||
public enum Type
|
||||
{
|
||||
ALL(0), EXPORT(1), IMPORT(2);
|
||||
private final int value;
|
||||
|
||||
Type(int value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int value()
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ColumnType
|
||||
{
|
||||
NUMERIC(0), STRING(1), IMAGE(2), TEXT(3);
|
||||
private final int value;
|
||||
|
||||
ColumnType(int value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int value()
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Excel注解集
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Excels
|
||||
{
|
||||
public Excel[] value();
|
||||
}
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Excel注解集
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Excels
|
||||
{
|
||||
public Excel[] value();
|
||||
}
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.enums.OperatorType;
|
||||
|
||||
/**
|
||||
* 自定义操作日志记录注解
|
||||
*
|
||||
* @author ruoyi
|
||||
*
|
||||
*/
|
||||
@Target({ ElementType.PARAMETER, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Log
|
||||
{
|
||||
/**
|
||||
* 模块
|
||||
*/
|
||||
public String title() default "";
|
||||
|
||||
/**
|
||||
* 功能
|
||||
*/
|
||||
public BusinessType businessType() default BusinessType.OTHER;
|
||||
|
||||
/**
|
||||
* 操作人类别
|
||||
*/
|
||||
public OperatorType operatorType() default OperatorType.MANAGE;
|
||||
|
||||
/**
|
||||
* 是否保存请求的参数
|
||||
*/
|
||||
public boolean isSaveRequestData() default true;
|
||||
|
||||
/**
|
||||
* 是否保存响应的参数
|
||||
*/
|
||||
public boolean isSaveResponseData() default true;
|
||||
|
||||
/**
|
||||
* 排除指定的请求参数
|
||||
*/
|
||||
public String[] excludeParamNames() default {};
|
||||
}
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.enums.OperatorType;
|
||||
|
||||
/**
|
||||
* 自定义操作日志记录注解
|
||||
*
|
||||
* @author ruoyi
|
||||
*
|
||||
*/
|
||||
@Target({ ElementType.PARAMETER, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Log
|
||||
{
|
||||
/**
|
||||
* 模块
|
||||
*/
|
||||
public String title() default "";
|
||||
|
||||
/**
|
||||
* 功能
|
||||
*/
|
||||
public BusinessType businessType() default BusinessType.OTHER;
|
||||
|
||||
/**
|
||||
* 操作人类别
|
||||
*/
|
||||
public OperatorType operatorType() default OperatorType.MANAGE;
|
||||
|
||||
/**
|
||||
* 是否保存请求的参数
|
||||
*/
|
||||
public boolean isSaveRequestData() default true;
|
||||
|
||||
/**
|
||||
* 是否保存响应的参数
|
||||
*/
|
||||
public boolean isSaveResponseData() default true;
|
||||
|
||||
/**
|
||||
* 排除指定的请求参数
|
||||
*/
|
||||
public String[] excludeParamNames() default {};
|
||||
}
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import com.ruoyi.common.constant.CacheConstants;
|
||||
import com.ruoyi.common.enums.LimitType;
|
||||
|
||||
/**
|
||||
* 限流注解
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RateLimiter
|
||||
{
|
||||
/**
|
||||
* 限流key
|
||||
*/
|
||||
public String key() default CacheConstants.RATE_LIMIT_KEY;
|
||||
|
||||
/**
|
||||
* 限流时间,单位秒
|
||||
*/
|
||||
public int time() default 60;
|
||||
|
||||
/**
|
||||
* 限流次数
|
||||
*/
|
||||
public int count() default 100;
|
||||
|
||||
/**
|
||||
* 限流类型
|
||||
*/
|
||||
public LimitType limitType() default LimitType.DEFAULT;
|
||||
}
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import com.ruoyi.common.constant.CacheConstants;
|
||||
import com.ruoyi.common.enums.LimitType;
|
||||
|
||||
/**
|
||||
* 限流注解
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RateLimiter
|
||||
{
|
||||
/**
|
||||
* 限流key
|
||||
*/
|
||||
public String key() default CacheConstants.RATE_LIMIT_KEY;
|
||||
|
||||
/**
|
||||
* 限流时间,单位秒
|
||||
*/
|
||||
public int time() default 60;
|
||||
|
||||
/**
|
||||
* 限流次数
|
||||
*/
|
||||
public int count() default 100;
|
||||
|
||||
/**
|
||||
* 限流类型
|
||||
*/
|
||||
public LimitType limitType() default LimitType.DEFAULT;
|
||||
}
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 自定义注解防止表单重复提交
|
||||
*
|
||||
* @author ruoyi
|
||||
*
|
||||
*/
|
||||
@Inherited
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RepeatSubmit
|
||||
{
|
||||
/**
|
||||
* 间隔时间(ms),小于此时间视为重复提交
|
||||
*/
|
||||
public int interval() default 5000;
|
||||
|
||||
/**
|
||||
* 提示消息
|
||||
*/
|
||||
public String message() default "不允许重复提交,请稍候再试";
|
||||
}
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 自定义注解防止表单重复提交
|
||||
*
|
||||
* @author ruoyi
|
||||
*
|
||||
*/
|
||||
@Inherited
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RepeatSubmit
|
||||
{
|
||||
/**
|
||||
* 间隔时间(ms),小于此时间视为重复提交
|
||||
*/
|
||||
public int interval() default 5000;
|
||||
|
||||
/**
|
||||
* 提示消息
|
||||
*/
|
||||
public String message() default "不允许重复提交,请稍候再试";
|
||||
}
|
||||
|
||||
@@ -1,122 +1,122 @@
|
||||
package com.ruoyi.common.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 读取项目相关配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "ruoyi")
|
||||
public class RuoYiConfig
|
||||
{
|
||||
/** 项目名称 */
|
||||
private String name;
|
||||
|
||||
/** 版本 */
|
||||
private String version;
|
||||
|
||||
/** 版权年份 */
|
||||
private String copyrightYear;
|
||||
|
||||
/** 上传路径 */
|
||||
private static String profile;
|
||||
|
||||
/** 获取地址开关 */
|
||||
private static boolean addressEnabled;
|
||||
|
||||
/** 验证码类型 */
|
||||
private static String captchaType;
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getVersion()
|
||||
{
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version)
|
||||
{
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getCopyrightYear()
|
||||
{
|
||||
return copyrightYear;
|
||||
}
|
||||
|
||||
public void setCopyrightYear(String copyrightYear)
|
||||
{
|
||||
this.copyrightYear = copyrightYear;
|
||||
}
|
||||
|
||||
public static String getProfile()
|
||||
{
|
||||
return profile;
|
||||
}
|
||||
|
||||
public void setProfile(String profile)
|
||||
{
|
||||
RuoYiConfig.profile = profile;
|
||||
}
|
||||
|
||||
public static boolean isAddressEnabled()
|
||||
{
|
||||
return addressEnabled;
|
||||
}
|
||||
|
||||
public void setAddressEnabled(boolean addressEnabled)
|
||||
{
|
||||
RuoYiConfig.addressEnabled = addressEnabled;
|
||||
}
|
||||
|
||||
public static String getCaptchaType() {
|
||||
return captchaType;
|
||||
}
|
||||
|
||||
public void setCaptchaType(String captchaType) {
|
||||
RuoYiConfig.captchaType = captchaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取导入上传路径
|
||||
*/
|
||||
public static String getImportPath()
|
||||
{
|
||||
return getProfile() + "/import";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取头像上传路径
|
||||
*/
|
||||
public static String getAvatarPath()
|
||||
{
|
||||
return getProfile() + "/avatar";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下载路径
|
||||
*/
|
||||
public static String getDownloadPath()
|
||||
{
|
||||
return getProfile() + "/download/";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上传路径
|
||||
*/
|
||||
public static String getUploadPath()
|
||||
{
|
||||
return getProfile() + "/upload";
|
||||
}
|
||||
}
|
||||
package com.ruoyi.common.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 读取项目相关配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "ruoyi")
|
||||
public class RuoYiConfig
|
||||
{
|
||||
/** 项目名称 */
|
||||
private String name;
|
||||
|
||||
/** 版本 */
|
||||
private String version;
|
||||
|
||||
/** 版权年份 */
|
||||
private String copyrightYear;
|
||||
|
||||
/** 上传路径 */
|
||||
private static String profile;
|
||||
|
||||
/** 获取地址开关 */
|
||||
private static boolean addressEnabled;
|
||||
|
||||
/** 验证码类型 */
|
||||
private static String captchaType;
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getVersion()
|
||||
{
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version)
|
||||
{
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getCopyrightYear()
|
||||
{
|
||||
return copyrightYear;
|
||||
}
|
||||
|
||||
public void setCopyrightYear(String copyrightYear)
|
||||
{
|
||||
this.copyrightYear = copyrightYear;
|
||||
}
|
||||
|
||||
public static String getProfile()
|
||||
{
|
||||
return profile;
|
||||
}
|
||||
|
||||
public void setProfile(String profile)
|
||||
{
|
||||
RuoYiConfig.profile = profile;
|
||||
}
|
||||
|
||||
public static boolean isAddressEnabled()
|
||||
{
|
||||
return addressEnabled;
|
||||
}
|
||||
|
||||
public void setAddressEnabled(boolean addressEnabled)
|
||||
{
|
||||
RuoYiConfig.addressEnabled = addressEnabled;
|
||||
}
|
||||
|
||||
public static String getCaptchaType() {
|
||||
return captchaType;
|
||||
}
|
||||
|
||||
public void setCaptchaType(String captchaType) {
|
||||
RuoYiConfig.captchaType = captchaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取导入上传路径
|
||||
*/
|
||||
public static String getImportPath()
|
||||
{
|
||||
return getProfile() + "/import";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取头像上传路径
|
||||
*/
|
||||
public static String getAvatarPath()
|
||||
{
|
||||
return getProfile() + "/avatar";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下载路径
|
||||
*/
|
||||
public static String getDownloadPath()
|
||||
{
|
||||
return getProfile() + "/download/";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上传路径
|
||||
*/
|
||||
public static String getUploadPath()
|
||||
{
|
||||
return getProfile() + "/upload";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
package com.ruoyi.common.constant;
|
||||
|
||||
/**
|
||||
* 缓存的key 常量
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class CacheConstants
|
||||
{
|
||||
/**
|
||||
* 登录用户 redis key
|
||||
*/
|
||||
public static final String LOGIN_TOKEN_KEY = "login_tokens:";
|
||||
|
||||
/**
|
||||
* 验证码 redis key
|
||||
*/
|
||||
public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
|
||||
|
||||
/**
|
||||
* 参数管理 cache key
|
||||
*/
|
||||
public static final String SYS_CONFIG_KEY = "sys_config:";
|
||||
|
||||
/**
|
||||
* 字典管理 cache key
|
||||
*/
|
||||
public static final String SYS_DICT_KEY = "sys_dict:";
|
||||
|
||||
/**
|
||||
* 防重提交 redis key
|
||||
*/
|
||||
public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
|
||||
|
||||
/**
|
||||
* 限流 redis key
|
||||
*/
|
||||
public static final String RATE_LIMIT_KEY = "rate_limit:";
|
||||
|
||||
/**
|
||||
* 登录账户密码错误次数 redis key
|
||||
*/
|
||||
public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
|
||||
}
|
||||
package com.ruoyi.common.constant;
|
||||
|
||||
/**
|
||||
* 缓存的key 常量
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class CacheConstants
|
||||
{
|
||||
/**
|
||||
* 登录用户 redis key
|
||||
*/
|
||||
public static final String LOGIN_TOKEN_KEY = "login_tokens:";
|
||||
|
||||
/**
|
||||
* 验证码 redis key
|
||||
*/
|
||||
public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
|
||||
|
||||
/**
|
||||
* 参数管理 cache key
|
||||
*/
|
||||
public static final String SYS_CONFIG_KEY = "sys_config:";
|
||||
|
||||
/**
|
||||
* 字典管理 cache key
|
||||
*/
|
||||
public static final String SYS_DICT_KEY = "sys_dict:";
|
||||
|
||||
/**
|
||||
* 防重提交 redis key
|
||||
*/
|
||||
public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
|
||||
|
||||
/**
|
||||
* 限流 redis key
|
||||
*/
|
||||
public static final String RATE_LIMIT_KEY = "rate_limit:";
|
||||
|
||||
/**
|
||||
* 登录账户密码错误次数 redis key
|
||||
*/
|
||||
public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
|
||||
}
|
||||
|
||||
@@ -1,173 +1,204 @@
|
||||
package com.ruoyi.common.constant;
|
||||
|
||||
import java.util.Locale;
|
||||
import io.jsonwebtoken.Claims;
|
||||
|
||||
/**
|
||||
* 通用常量信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class Constants
|
||||
{
|
||||
/**
|
||||
* UTF-8 字符集
|
||||
*/
|
||||
public static final String UTF8 = "UTF-8";
|
||||
|
||||
/**
|
||||
* GBK 字符集
|
||||
*/
|
||||
public static final String GBK = "GBK";
|
||||
|
||||
/**
|
||||
* 系统语言
|
||||
*/
|
||||
public static final Locale DEFAULT_LOCALE = Locale.SIMPLIFIED_CHINESE;
|
||||
|
||||
/**
|
||||
* www主域
|
||||
*/
|
||||
public static final String WWW = "www.";
|
||||
|
||||
/**
|
||||
* http请求
|
||||
*/
|
||||
public static final String HTTP = "http://";
|
||||
|
||||
/**
|
||||
* https请求
|
||||
*/
|
||||
public static final String HTTPS = "https://";
|
||||
|
||||
/**
|
||||
* 通用成功标识
|
||||
*/
|
||||
public static final String SUCCESS = "0";
|
||||
|
||||
/**
|
||||
* 通用失败标识
|
||||
*/
|
||||
public static final String FAIL = "1";
|
||||
|
||||
/**
|
||||
* 登录成功
|
||||
*/
|
||||
public static final String LOGIN_SUCCESS = "Success";
|
||||
|
||||
/**
|
||||
* 注销
|
||||
*/
|
||||
public static final String LOGOUT = "Logout";
|
||||
|
||||
/**
|
||||
* 注册
|
||||
*/
|
||||
public static final String REGISTER = "Register";
|
||||
|
||||
/**
|
||||
* 登录失败
|
||||
*/
|
||||
public static final String LOGIN_FAIL = "Error";
|
||||
|
||||
/**
|
||||
* 所有权限标识
|
||||
*/
|
||||
public static final String ALL_PERMISSION = "*:*:*";
|
||||
|
||||
/**
|
||||
* 管理员角色权限标识
|
||||
*/
|
||||
public static final String SUPER_ADMIN = "admin";
|
||||
|
||||
/**
|
||||
* 角色权限分隔符
|
||||
*/
|
||||
public static final String ROLE_DELIMITER = ",";
|
||||
|
||||
/**
|
||||
* 权限标识分隔符
|
||||
*/
|
||||
public static final String PERMISSION_DELIMITER = ",";
|
||||
|
||||
/**
|
||||
* 验证码有效期(分钟)
|
||||
*/
|
||||
public static final Integer CAPTCHA_EXPIRATION = 2;
|
||||
|
||||
/**
|
||||
* 令牌
|
||||
*/
|
||||
public static final String TOKEN = "token";
|
||||
|
||||
/**
|
||||
* 令牌前缀
|
||||
*/
|
||||
public static final String TOKEN_PREFIX = "Bearer ";
|
||||
|
||||
/**
|
||||
* 令牌前缀
|
||||
*/
|
||||
public static final String LOGIN_USER_KEY = "login_user_key";
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
public static final String JWT_USERID = "userid";
|
||||
|
||||
/**
|
||||
* 用户名称
|
||||
*/
|
||||
public static final String JWT_USERNAME = Claims.SUBJECT;
|
||||
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
public static final String JWT_AVATAR = "avatar";
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
public static final String JWT_CREATED = "created";
|
||||
|
||||
/**
|
||||
* 用户权限
|
||||
*/
|
||||
public static final String JWT_AUTHORITIES = "authorities";
|
||||
|
||||
/**
|
||||
* 资源映射路径 前缀
|
||||
*/
|
||||
public static final String RESOURCE_PREFIX = "/profile";
|
||||
|
||||
/**
|
||||
* RMI 远程方法调用
|
||||
*/
|
||||
public static final String LOOKUP_RMI = "rmi:";
|
||||
|
||||
/**
|
||||
* LDAP 远程方法调用
|
||||
*/
|
||||
public static final String LOOKUP_LDAP = "ldap:";
|
||||
|
||||
/**
|
||||
* LDAPS 远程方法调用
|
||||
*/
|
||||
public static final String LOOKUP_LDAPS = "ldaps:";
|
||||
|
||||
/**
|
||||
* 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全)
|
||||
*/
|
||||
public static final String[] JSON_WHITELIST_STR = { "com.ruoyi" };
|
||||
|
||||
/**
|
||||
* 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
|
||||
*/
|
||||
public static final String[] JOB_WHITELIST_STR = { "com.ruoyi.quartz.task" };
|
||||
|
||||
/**
|
||||
* 定时任务违规的字符
|
||||
*/
|
||||
public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
|
||||
"org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config", "com.ruoyi.generator" };
|
||||
}
|
||||
package com.ruoyi.common.constant;
|
||||
|
||||
import java.util.Locale;
|
||||
import io.jsonwebtoken.Claims;
|
||||
|
||||
/**
|
||||
* 通用常量信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class Constants
|
||||
{
|
||||
/**
|
||||
* UTF-8 字符集
|
||||
*/
|
||||
public static final String UTF8 = "UTF-8";
|
||||
|
||||
/**
|
||||
* GBK 字符集
|
||||
*/
|
||||
public static final String GBK = "GBK";
|
||||
|
||||
/**
|
||||
* 系统语言
|
||||
*/
|
||||
public static final Locale DEFAULT_LOCALE = Locale.SIMPLIFIED_CHINESE;
|
||||
|
||||
/**
|
||||
* www主域
|
||||
*/
|
||||
public static final String WWW = "www.";
|
||||
|
||||
/**
|
||||
* http请求
|
||||
*/
|
||||
public static final String HTTP = "http://";
|
||||
|
||||
/**
|
||||
* https请求
|
||||
*/
|
||||
public static final String HTTPS = "https://";
|
||||
|
||||
/**
|
||||
* 通用成功标识
|
||||
*/
|
||||
public static final String SUCCESS = "0";
|
||||
|
||||
/**
|
||||
* 通用失败标识
|
||||
*/
|
||||
public static final String FAIL = "1";
|
||||
|
||||
/**
|
||||
* 登录成功
|
||||
*/
|
||||
public static final String LOGIN_SUCCESS = "Success";
|
||||
|
||||
/**
|
||||
* 注销
|
||||
*/
|
||||
public static final String LOGOUT = "Logout";
|
||||
|
||||
/**
|
||||
* 注册
|
||||
*/
|
||||
public static final String REGISTER = "Register";
|
||||
|
||||
/**
|
||||
* 登录失败
|
||||
*/
|
||||
public static final String LOGIN_FAIL = "Error";
|
||||
|
||||
/**
|
||||
* 所有权限标识
|
||||
*/
|
||||
public static final String ALL_PERMISSION = "*:*:*";
|
||||
|
||||
/**
|
||||
* 管理员角色权限标识
|
||||
*/
|
||||
public static final String SUPER_ADMIN = "admin";
|
||||
|
||||
/**
|
||||
* 角色权限分隔符
|
||||
*/
|
||||
public static final String ROLE_DELIMITER = ",";
|
||||
|
||||
/**
|
||||
* 权限标识分隔符
|
||||
*/
|
||||
public static final String PERMISSION_DELIMITER = ",";
|
||||
|
||||
/**
|
||||
* 验证码有效期(分钟)
|
||||
*/
|
||||
public static final Integer CAPTCHA_EXPIRATION = 2;
|
||||
|
||||
/**
|
||||
* 令牌
|
||||
*/
|
||||
public static final String TOKEN = "token";
|
||||
|
||||
/**
|
||||
* 令牌前缀
|
||||
*/
|
||||
public static final String TOKEN_PREFIX = "Bearer ";
|
||||
|
||||
/**
|
||||
* 令牌前缀
|
||||
*/
|
||||
public static final String LOGIN_USER_KEY = "login_user_key";
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
public static final String JWT_USERID = "userid";
|
||||
|
||||
/**
|
||||
* 用户名称
|
||||
*/
|
||||
public static final String JWT_USERNAME = Claims.SUBJECT;
|
||||
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
public static final String JWT_AVATAR = "avatar";
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
public static final String JWT_CREATED = "created";
|
||||
|
||||
/**
|
||||
* 用户权限
|
||||
*/
|
||||
public static final String JWT_AUTHORITIES = "authorities";
|
||||
|
||||
/**
|
||||
* 资源映射路径 前缀
|
||||
*/
|
||||
public static final String RESOURCE_PREFIX = "/profile";
|
||||
|
||||
/**
|
||||
* RMI 远程方法调用
|
||||
*/
|
||||
public static final String LOOKUP_RMI = "rmi:";
|
||||
|
||||
/**
|
||||
* LDAP 远程方法调用
|
||||
*/
|
||||
public static final String LOOKUP_LDAP = "ldap:";
|
||||
|
||||
/**
|
||||
* LDAPS 远程方法调用
|
||||
*/
|
||||
public static final String LOOKUP_LDAPS = "ldaps:";
|
||||
|
||||
/**
|
||||
* 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全)
|
||||
*/
|
||||
public static final String[] JSON_WHITELIST_STR = { "com.ruoyi" };
|
||||
|
||||
/**
|
||||
* 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
|
||||
*/
|
||||
public static final String[] JOB_WHITELIST_STR = { "com.ruoyi.quartz.task" };
|
||||
|
||||
/**
|
||||
* 定时任务违规的字符
|
||||
*/
|
||||
public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
|
||||
"org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config", "com.ruoyi.generator" };
|
||||
|
||||
/**
|
||||
* 部门相关常量
|
||||
*/
|
||||
public static class Dept
|
||||
{
|
||||
/**
|
||||
* 全部数据权限
|
||||
*/
|
||||
public static final String DATA_SCOPE_ALL = "1";
|
||||
|
||||
/**
|
||||
* 自定数据权限
|
||||
*/
|
||||
public static final String DATA_SCOPE_CUSTOM = "2";
|
||||
|
||||
/**
|
||||
* 部门数据权限
|
||||
*/
|
||||
public static final String DATA_SCOPE_DEPT = "3";
|
||||
|
||||
/**
|
||||
* 部门及以下数据权限
|
||||
*/
|
||||
public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";
|
||||
|
||||
/**
|
||||
* 仅本人数据权限
|
||||
*/
|
||||
public static final String DATA_SCOPE_SELF = "5";
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user