Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
A
aispace
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
Administrator
aispace
Commits
0c4531a3
提交
0c4531a3
authored
4月 10, 2026
作者:
kxjia
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
初始化项目
上级
5ae3d3ed
隐藏空白字符变更
内嵌
并排
正在显示
55 个修改的文件
包含
4739 行增加
和
0 行删除
+4739
-0
init.sql
database/init.sql
+88
-0
AnalysisConfigController.java
.../fintech/penalty/controller/AnalysisConfigController.java
+41
-0
AnalysisKeywordController.java
...fintech/penalty/controller/AnalysisKeywordController.java
+83
-0
AnalysisRuleController.java
...om/fintech/penalty/controller/AnalysisRuleController.java
+90
-0
MenuController.java
...n/java/com/fintech/penalty/controller/MenuController.java
+89
-0
PermissionController.java
.../com/fintech/penalty/controller/PermissionController.java
+83
-0
ReportTemplateController.java
.../fintech/penalty/controller/ReportTemplateController.java
+87
-0
RoleController.java
...n/java/com/fintech/penalty/controller/RoleController.java
+128
-0
AnalysisConfigDTO.java
.../main/java/com/fintech/penalty/dto/AnalysisConfigDTO.java
+21
-0
AnalysisKeywordDTO.java
...main/java/com/fintech/penalty/dto/AnalysisKeywordDTO.java
+32
-0
AnalysisRuleDTO.java
...rc/main/java/com/fintech/penalty/dto/AnalysisRuleDTO.java
+40
-0
AnalyzeRequest.java
...src/main/java/com/fintech/penalty/dto/AnalyzeRequest.java
+8
-0
CreateAnalysisKeywordRequest.java
...com/fintech/penalty/dto/CreateAnalysisKeywordRequest.java
+25
-0
CreateAnalysisRuleRequest.java
...va/com/fintech/penalty/dto/CreateAnalysisRuleRequest.java
+32
-0
CreateMenuRequest.java
.../main/java/com/fintech/penalty/dto/CreateMenuRequest.java
+31
-0
CreatePermissionRequest.java
...java/com/fintech/penalty/dto/CreatePermissionRequest.java
+27
-0
CreateReportTemplateRequest.java
.../com/fintech/penalty/dto/CreateReportTemplateRequest.java
+24
-0
CreateRoleRequest.java
.../main/java/com/fintech/penalty/dto/CreateRoleRequest.java
+25
-0
MenuDTO.java
...ackend/src/main/java/com/fintech/penalty/dto/MenuDTO.java
+41
-0
PermissionDTO.java
.../src/main/java/com/fintech/penalty/dto/PermissionDTO.java
+32
-0
ReportTemplateDTO.java
.../main/java/com/fintech/penalty/dto/ReportTemplateDTO.java
+32
-0
RoleDTO.java
...ackend/src/main/java/com/fintech/penalty/dto/RoleDTO.java
+31
-0
UpdateAnalysisKeywordRequest.java
...com/fintech/penalty/dto/UpdateAnalysisKeywordRequest.java
+23
-0
UpdateAnalysisRuleRequest.java
...va/com/fintech/penalty/dto/UpdateAnalysisRuleRequest.java
+29
-0
UpdateMenuRequest.java
.../main/java/com/fintech/penalty/dto/UpdateMenuRequest.java
+29
-0
UpdatePermissionRequest.java
...java/com/fintech/penalty/dto/UpdatePermissionRequest.java
+21
-0
UpdateReportTemplateRequest.java
.../com/fintech/penalty/dto/UpdateReportTemplateRequest.java
+21
-0
UpdateRoleRequest.java
.../main/java/com/fintech/penalty/dto/UpdateRoleRequest.java
+19
-0
AnalysisKeyword.java
...main/java/com/fintech/penalty/entity/AnalysisKeyword.java
+56
-0
AnalysisRule.java
...rc/main/java/com/fintech/penalty/entity/AnalysisRule.java
+69
-0
Menu.java
...ackend/src/main/java/com/fintech/penalty/entity/Menu.java
+67
-0
Permission.java
.../src/main/java/com/fintech/penalty/entity/Permission.java
+55
-0
ReportTemplate.java
.../main/java/com/fintech/penalty/entity/ReportTemplate.java
+57
-0
Role.java
...ackend/src/main/java/com/fintech/penalty/entity/Role.java
+49
-0
RoleMenu.java
...nd/src/main/java/com/fintech/penalty/entity/RoleMenu.java
+27
-0
AnalysisKeywordRepository.java
...fintech/penalty/repository/AnalysisKeywordRepository.java
+18
-0
AnalysisRuleRepository.java
...om/fintech/penalty/repository/AnalysisRuleRepository.java
+26
-0
MenuRepository.java
...n/java/com/fintech/penalty/repository/MenuRepository.java
+25
-0
PermissionRepository.java
.../com/fintech/penalty/repository/PermissionRepository.java
+19
-0
ReportTemplateRepository.java
.../fintech/penalty/repository/ReportTemplateRepository.java
+19
-0
RoleMenuRepository.java
...va/com/fintech/penalty/repository/RoleMenuRepository.java
+16
-0
RoleRepository.java
...n/java/com/fintech/penalty/repository/RoleRepository.java
+16
-0
AnalysisConfigService.java
...va/com/fintech/penalty/service/AnalysisConfigService.java
+55
-0
AnalysisKeywordService.java
...a/com/fintech/penalty/service/AnalysisKeywordService.java
+122
-0
AnalysisRuleService.java
...java/com/fintech/penalty/service/AnalysisRuleService.java
+142
-0
MenuService.java
...rc/main/java/com/fintech/penalty/service/MenuService.java
+248
-0
PermissionService.java
...n/java/com/fintech/penalty/service/PermissionService.java
+117
-0
ReportTemplateService.java
...va/com/fintech/penalty/service/ReportTemplateService.java
+137
-0
RoleService.java
...rc/main/java/com/fintech/penalty/service/RoleService.java
+212
-0
MenuManage.vue
financial-penalty-monitor/frontend/src/views/MenuManage.vue
+225
-0
PermissionManage.vue
...l-penalty-monitor/frontend/src/views/PermissionManage.vue
+239
-0
ReportConfig.vue
...ncial-penalty-monitor/frontend/src/views/ReportConfig.vue
+699
-0
RoleManage.vue
financial-penalty-monitor/frontend/src/views/RoleManage.vue
+507
-0
RoleMenuManage.vue
...ial-penalty-monitor/frontend/src/views/RoleMenuManage.vue
+141
-0
RoleUserManage.vue
...ial-penalty-monitor/frontend/src/views/RoleUserManage.vue
+144
-0
没有找到文件。
database/init.sql
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
controller
;
import
com
.
fintech
.
penalty
.
dto
.
*
;
import
com
.
fintech
.
penalty
.
service
.
AnalysisKeywordService
;
import
jakarta
.
validation
.
Valid
;
import
lombok
.
RequiredArgsConstructor
;
import
lombok
.
extern
.
slf4j
.
Slf4j
;
import
org
.
springframework
.
http
.
ResponseEntity
;
import
org
.
springframework
.
security
.
access
.
prepost
.
PreAuthorize
;
import
org
.
springframework
.
web
.
bind
.
annotation
.
*
;
import
java
.
util
.
List
;
@
RestController
@
RequestMapping
(
"/analysis-keywords"
)
@
RequiredArgsConstructor
@
Slf4j
@
CrossOrigin
(
origins
=
"*"
)
public
class
AnalysisKeywordController
{
private
final
AnalysisKeywordService
keywordService
;
@
GetMapping
@
PreAuthorize
(
"hasRole('ADMIN')"
)
public
ResponseEntity
<
ApiResponse
<
PageResponse
<
AnalysisKeywordDTO
>>>
findAll
(
@
RequestParam
(
defaultValue
=
"0"
)
int
page
,
@
RequestParam
(
defaultValue
=
"10"
)
int
size
)
{
PageResponse
<
AnalysisKeywordDTO
>
result
=
keywordService
.
findAll
(
page
,
size
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@
GetMapping
(
"/enabled"
)
public
ResponseEntity
<
ApiResponse
<
List
<
AnalysisKeywordDTO
>>>
findAllEnabled
()
{
List
<
AnalysisKeywordDTO
>
result
=
keywordService
.
findAllEnabled
();
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@
GetMapping
(
"/category/{category}"
)
public
ResponseEntity
<
ApiResponse
<
List
<
AnalysisKeywordDTO
>>>
findByCategory
(
@
PathVariable
String
category
)
{
List
<
AnalysisKeywordDTO
>
result
=
keywordService
.
findByCategory
(
category
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@
GetMapping
(
"/{id}"
)
public
ResponseEntity
<
ApiResponse
<
AnalysisKeywordDTO
>>
findById
(
@
PathVariable
Long
id
)
{
AnalysisKeywordDTO
result
=
keywordService
.
findById
(
id
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@
PostMapping
@
PreAuthorize
(
"hasRole('ADMIN')"
)
public
ResponseEntity
<
ApiResponse
<
AnalysisKeywordDTO
>>
create
(
@
Valid
@
RequestBody
CreateAnalysisKeywordRequest
request
)
{
try
{
AnalysisKeywordDTO
result
=
keywordService
.
create
(
request
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"创建成功"
,
result
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"创建关键词失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
@
PutMapping
(
"/{id}"
)
@
PreAuthorize
(
"hasRole('ADMIN')"
)
public
ResponseEntity
<
ApiResponse
<
AnalysisKeywordDTO
>>
update
(
@
PathVariable
Long
id
,
@
Valid
@
RequestBody
UpdateAnalysisKeywordRequest
request
)
{
try
{
AnalysisKeywordDTO
result
=
keywordService
.
update
(
id
,
request
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"更新成功"
,
result
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"更新关键词失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
@
DeleteMapping
(
"/{id}"
)
@
PreAuthorize
(
"hasRole('ADMIN')"
)
public
ResponseEntity
<
ApiResponse
<
Void
>>
delete
(
@
PathVariable
Long
id
)
{
try
{
keywordService
.
delete
(
id
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"删除成功"
,
null
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"删除关键词失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/controller/AnalysisConfigController.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
controller
;
import
com.fintech.penalty.dto.AnalysisConfigDTO
;
import
com.fintech.penalty.dto.ApiResponse
;
import
com.fintech.penalty.service.AnalysisConfigService
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.security.access.prepost.PreAuthorize
;
import
org.springframework.web.bind.annotation.*
;
import
java.security.Principal
;
@RestController
@RequestMapping
(
"/analysis-config"
)
@RequiredArgsConstructor
@Slf4j
@CrossOrigin
(
origins
=
"*"
)
public
class
AnalysisConfigController
{
private
final
AnalysisConfigService
configService
;
@GetMapping
(
"/active"
)
public
ResponseEntity
<
ApiResponse
<
AnalysisConfigDTO
>>
getActiveConfig
()
{
AnalysisConfigDTO
config
=
configService
.
getActiveConfig
();
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
config
));
}
@PostMapping
(
"/active"
)
@PreAuthorize
(
"hasRole('ADMIN')"
)
public
ResponseEntity
<
ApiResponse
<
AnalysisConfigDTO
>>
setActiveConfig
(
@RequestBody
AnalysisConfigDTO
config
,
Principal
principal
)
{
if
(
principal
!=
null
)
{
config
.
setUpdatedBy
(
1L
);
config
.
setUpdatedAt
(
java
.
time
.
LocalDateTime
.
now
().
toString
());
}
configService
.
saveActiveConfig
(
config
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
configService
.
getActiveConfig
()));
}
}
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/controller/AnalysisKeywordController.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
controller
;
import
com.fintech.penalty.dto.*
;
import
com.fintech.penalty.service.AnalysisKeywordService
;
import
jakarta.validation.Valid
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.web.bind.annotation.*
;
import
java.util.List
;
@RestController
@RequestMapping
(
"/analysis-keywords"
)
@RequiredArgsConstructor
@Slf4j
@CrossOrigin
(
origins
=
"*"
)
public
class
AnalysisKeywordController
{
private
final
AnalysisKeywordService
keywordService
;
@GetMapping
public
ResponseEntity
<
ApiResponse
<
PageResponse
<
AnalysisKeywordDTO
>>>
findAll
(
@RequestParam
(
defaultValue
=
"0"
)
int
page
,
@RequestParam
(
defaultValue
=
"10"
)
int
size
)
{
PageResponse
<
AnalysisKeywordDTO
>
result
=
keywordService
.
findAll
(
page
,
size
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@GetMapping
(
"/enabled"
)
public
ResponseEntity
<
ApiResponse
<
List
<
AnalysisKeywordDTO
>>>
findAllEnabled
()
{
List
<
AnalysisKeywordDTO
>
result
=
keywordService
.
findAllEnabled
();
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@GetMapping
(
"/category/{category}"
)
public
ResponseEntity
<
ApiResponse
<
List
<
AnalysisKeywordDTO
>>>
findByCategory
(
@PathVariable
String
category
)
{
List
<
AnalysisKeywordDTO
>
result
=
keywordService
.
findByCategory
(
category
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@GetMapping
(
"/{id}"
)
public
ResponseEntity
<
ApiResponse
<
AnalysisKeywordDTO
>>
findById
(
@PathVariable
Long
id
)
{
AnalysisKeywordDTO
result
=
keywordService
.
findById
(
id
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@PostMapping
public
ResponseEntity
<
ApiResponse
<
AnalysisKeywordDTO
>>
create
(
@Valid
@RequestBody
CreateAnalysisKeywordRequest
request
)
{
try
{
AnalysisKeywordDTO
result
=
keywordService
.
create
(
request
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"创建成功"
,
result
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"创建关键词失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
@PutMapping
(
"/{id}"
)
public
ResponseEntity
<
ApiResponse
<
AnalysisKeywordDTO
>>
update
(
@PathVariable
Long
id
,
@Valid
@RequestBody
UpdateAnalysisKeywordRequest
request
)
{
try
{
AnalysisKeywordDTO
result
=
keywordService
.
update
(
id
,
request
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"更新成功"
,
result
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"更新关键词失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
@DeleteMapping
(
"/{id}"
)
public
ResponseEntity
<
ApiResponse
<
Void
>>
delete
(
@PathVariable
Long
id
)
{
try
{
keywordService
.
delete
(
id
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"删除成功"
,
null
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"删除关键词失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/controller/AnalysisRuleController.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
controller
;
import
com.fintech.penalty.dto.*
;
import
com.fintech.penalty.service.AnalysisRuleService
;
import
jakarta.validation.Valid
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.security.access.prepost.PreAuthorize
;
import
org.springframework.web.bind.annotation.*
;
import
java.util.List
;
@RestController
@RequestMapping
(
"/analysis-rules"
)
@RequiredArgsConstructor
@Slf4j
@CrossOrigin
(
origins
=
"*"
)
public
class
AnalysisRuleController
{
private
final
AnalysisRuleService
ruleService
;
@GetMapping
public
ResponseEntity
<
ApiResponse
<
PageResponse
<
AnalysisRuleDTO
>>>
findAll
(
@RequestParam
(
defaultValue
=
"0"
)
int
page
,
@RequestParam
(
defaultValue
=
"10"
)
int
size
)
{
PageResponse
<
AnalysisRuleDTO
>
result
=
ruleService
.
findAll
(
page
,
size
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@GetMapping
(
"/enabled"
)
public
ResponseEntity
<
ApiResponse
<
List
<
AnalysisRuleDTO
>>>
findAllEnabled
()
{
List
<
AnalysisRuleDTO
>
result
=
ruleService
.
findAllEnabled
();
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@GetMapping
(
"/match"
)
public
ResponseEntity
<
ApiResponse
<
List
<
AnalysisRuleDTO
>>>
findMatchingRules
(
@RequestParam
(
required
=
false
)
String
institutionType
,
@RequestParam
(
required
=
false
)
String
penaltyType
,
@RequestParam
(
required
=
false
)
Long
amount
)
{
List
<
AnalysisRuleDTO
>
result
=
ruleService
.
findMatchingRules
(
institutionType
,
penaltyType
,
amount
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@GetMapping
(
"/{id}"
)
public
ResponseEntity
<
ApiResponse
<
AnalysisRuleDTO
>>
findById
(
@PathVariable
Long
id
)
{
AnalysisRuleDTO
result
=
ruleService
.
findById
(
id
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@PostMapping
@PreAuthorize
(
"hasRole('ADMIN')"
)
public
ResponseEntity
<
ApiResponse
<
AnalysisRuleDTO
>>
create
(
@Valid
@RequestBody
CreateAnalysisRuleRequest
request
)
{
try
{
AnalysisRuleDTO
result
=
ruleService
.
create
(
request
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"创建成功"
,
result
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"创建分析规则失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
@PutMapping
(
"/{id}"
)
@PreAuthorize
(
"hasRole('ADMIN')"
)
public
ResponseEntity
<
ApiResponse
<
AnalysisRuleDTO
>>
update
(
@PathVariable
Long
id
,
@Valid
@RequestBody
UpdateAnalysisRuleRequest
request
)
{
try
{
AnalysisRuleDTO
result
=
ruleService
.
update
(
id
,
request
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"更新成功"
,
result
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"更新分析规则失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
@DeleteMapping
(
"/{id}"
)
@PreAuthorize
(
"hasRole('ADMIN')"
)
public
ResponseEntity
<
ApiResponse
<
Void
>>
delete
(
@PathVariable
Long
id
)
{
try
{
ruleService
.
delete
(
id
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"删除成功"
,
null
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"删除分析规则失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/controller/MenuController.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
controller
;
import
com.fintech.penalty.dto.*
;
import
com.fintech.penalty.service.MenuService
;
import
jakarta.validation.Valid
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.security.access.prepost.PreAuthorize
;
import
org.springframework.web.bind.annotation.*
;
import
java.util.List
;
@RestController
@RequestMapping
(
"/menus"
)
@RequiredArgsConstructor
@Slf4j
@CrossOrigin
(
origins
=
"*"
)
public
class
MenuController
{
private
final
MenuService
menuService
;
@GetMapping
public
ResponseEntity
<
ApiResponse
<
List
<
MenuDTO
>>>
findAll
()
{
List
<
MenuDTO
>
result
=
menuService
.
findAll
();
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@GetMapping
(
"/visible"
)
public
ResponseEntity
<
ApiResponse
<
List
<
MenuDTO
>>>
findVisible
()
{
List
<
MenuDTO
>
result
=
menuService
.
findVisible
();
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@GetMapping
(
"/role/{roleCode}"
)
public
ResponseEntity
<
ApiResponse
<
List
<
MenuDTO
>>>
findByRoleCode
(
@PathVariable
String
roleCode
)
{
List
<
MenuDTO
>
result
=
menuService
.
findByRoleCode
(
roleCode
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@GetMapping
(
"/children"
)
public
ResponseEntity
<
ApiResponse
<
List
<
MenuDTO
>>>
findByParentId
(
@RequestParam
(
required
=
false
,
defaultValue
=
"0"
)
Long
parentId
)
{
List
<
MenuDTO
>
result
=
menuService
.
findByParentId
(
parentId
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@GetMapping
(
"/{id}"
)
public
ResponseEntity
<
ApiResponse
<
MenuDTO
>>
findById
(
@PathVariable
Long
id
)
{
MenuDTO
menu
=
menuService
.
findById
(
id
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
menu
));
}
@PostMapping
public
ResponseEntity
<
ApiResponse
<
MenuDTO
>>
createMenu
(
@Valid
@RequestBody
CreateMenuRequest
request
)
{
try
{
MenuDTO
menu
=
menuService
.
createMenu
(
request
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"创建成功"
,
menu
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"创建菜单失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
@PutMapping
(
"/{id}"
)
public
ResponseEntity
<
ApiResponse
<
MenuDTO
>>
updateMenu
(
@PathVariable
Long
id
,
@Valid
@RequestBody
UpdateMenuRequest
request
)
{
try
{
MenuDTO
menu
=
menuService
.
updateMenu
(
id
,
request
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"更新成功"
,
menu
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"更新菜单失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
@DeleteMapping
(
"/{id}"
)
public
ResponseEntity
<
ApiResponse
<
Void
>>
deleteMenu
(
@PathVariable
Long
id
)
{
try
{
menuService
.
deleteMenu
(
id
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"删除成功"
,
null
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"删除菜单失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/controller/PermissionController.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
controller
;
import
com.fintech.penalty.dto.*
;
import
com.fintech.penalty.service.PermissionService
;
import
jakarta.validation.Valid
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.security.access.prepost.PreAuthorize
;
import
org.springframework.web.bind.annotation.*
;
import
java.util.List
;
@RestController
@RequestMapping
(
"/permissions"
)
@RequiredArgsConstructor
@Slf4j
@CrossOrigin
(
origins
=
"*"
)
public
class
PermissionController
{
private
final
PermissionService
permissionService
;
@GetMapping
@PreAuthorize
(
"hasRole('ADMIN')"
)
public
ResponseEntity
<
ApiResponse
<
PageResponse
<
PermissionDTO
>>>
findAll
(
@RequestParam
(
defaultValue
=
"0"
)
int
page
,
@RequestParam
(
defaultValue
=
"10"
)
int
size
)
{
PageResponse
<
PermissionDTO
>
result
=
permissionService
.
findAll
(
page
,
size
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@GetMapping
(
"/simple"
)
public
ResponseEntity
<
ApiResponse
<
List
<
PermissionDTO
>>>
findAllSimple
()
{
List
<
PermissionDTO
>
result
=
permissionService
.
findAllSimple
();
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@GetMapping
(
"/{id}"
)
@PreAuthorize
(
"hasRole('ADMIN')"
)
public
ResponseEntity
<
ApiResponse
<
PermissionDTO
>>
findById
(
@PathVariable
Long
id
)
{
PermissionDTO
permission
=
permissionService
.
findById
(
id
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
permission
));
}
@PostMapping
@PreAuthorize
(
"hasRole('ADMIN')"
)
public
ResponseEntity
<
ApiResponse
<
PermissionDTO
>>
createPermission
(
@Valid
@RequestBody
CreatePermissionRequest
request
)
{
try
{
PermissionDTO
permission
=
permissionService
.
createPermission
(
request
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"创建成功"
,
permission
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"创建权限失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
@PutMapping
(
"/{id}"
)
@PreAuthorize
(
"hasRole('ADMIN')"
)
public
ResponseEntity
<
ApiResponse
<
PermissionDTO
>>
updatePermission
(
@PathVariable
Long
id
,
@Valid
@RequestBody
UpdatePermissionRequest
request
)
{
try
{
PermissionDTO
permission
=
permissionService
.
updatePermission
(
id
,
request
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"更新成功"
,
permission
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"更新权限失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
@DeleteMapping
(
"/{id}"
)
@PreAuthorize
(
"hasRole('ADMIN')"
)
public
ResponseEntity
<
ApiResponse
<
Void
>>
deletePermission
(
@PathVariable
Long
id
)
{
try
{
permissionService
.
deletePermission
(
id
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"删除成功"
,
null
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"删除权限失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/controller/ReportTemplateController.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
controller
;
import
com.fintech.penalty.dto.*
;
import
com.fintech.penalty.service.ReportTemplateService
;
import
jakarta.validation.Valid
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.security.access.prepost.PreAuthorize
;
import
org.springframework.web.bind.annotation.*
;
import
java.util.List
;
@RestController
@RequestMapping
(
"/report-templates"
)
@RequiredArgsConstructor
@Slf4j
@CrossOrigin
(
origins
=
"*"
)
public
class
ReportTemplateController
{
private
final
ReportTemplateService
templateService
;
@GetMapping
public
ResponseEntity
<
ApiResponse
<
PageResponse
<
ReportTemplateDTO
>>>
findAll
(
@RequestParam
(
defaultValue
=
"0"
)
int
page
,
@RequestParam
(
defaultValue
=
"10"
)
int
size
)
{
PageResponse
<
ReportTemplateDTO
>
result
=
templateService
.
findAll
(
page
,
size
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@GetMapping
(
"/enabled"
)
public
ResponseEntity
<
ApiResponse
<
List
<
ReportTemplateDTO
>>>
findAllEnabled
()
{
List
<
ReportTemplateDTO
>
result
=
templateService
.
findAllEnabled
();
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@GetMapping
(
"/default"
)
public
ResponseEntity
<
ApiResponse
<
ReportTemplateDTO
>>
findDefault
()
{
ReportTemplateDTO
result
=
templateService
.
findDefault
();
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@GetMapping
(
"/{id}"
)
public
ResponseEntity
<
ApiResponse
<
ReportTemplateDTO
>>
findById
(
@PathVariable
Long
id
)
{
ReportTemplateDTO
result
=
templateService
.
findById
(
id
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@PostMapping
@PreAuthorize
(
"hasRole('ADMIN')"
)
public
ResponseEntity
<
ApiResponse
<
ReportTemplateDTO
>>
create
(
@Valid
@RequestBody
CreateReportTemplateRequest
request
)
{
try
{
ReportTemplateDTO
result
=
templateService
.
create
(
request
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"创建成功"
,
result
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"创建报告模板失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
@PutMapping
(
"/{id}"
)
@PreAuthorize
(
"hasRole('ADMIN')"
)
public
ResponseEntity
<
ApiResponse
<
ReportTemplateDTO
>>
update
(
@PathVariable
Long
id
,
@Valid
@RequestBody
UpdateReportTemplateRequest
request
)
{
try
{
ReportTemplateDTO
result
=
templateService
.
update
(
id
,
request
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"更新成功"
,
result
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"更新报告模板失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
@DeleteMapping
(
"/{id}"
)
@PreAuthorize
(
"hasRole('ADMIN')"
)
public
ResponseEntity
<
ApiResponse
<
Void
>>
delete
(
@PathVariable
Long
id
)
{
try
{
templateService
.
delete
(
id
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"删除成功"
,
null
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"删除报告模板失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/controller/RoleController.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
controller
;
import
com.fintech.penalty.dto.*
;
import
com.fintech.penalty.service.RoleService
;
import
jakarta.validation.Valid
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.security.access.prepost.PreAuthorize
;
import
org.springframework.web.bind.annotation.*
;
import
java.util.List
;
import
java.util.Map
;
@RestController
@RequestMapping
(
"/roles"
)
@RequiredArgsConstructor
@Slf4j
@CrossOrigin
(
origins
=
"*"
)
public
class
RoleController
{
private
final
RoleService
roleService
;
@GetMapping
public
ResponseEntity
<
ApiResponse
<
PageResponse
<
RoleDTO
>>>
findAll
(
@RequestParam
(
defaultValue
=
"0"
)
int
page
,
@RequestParam
(
defaultValue
=
"10"
)
int
size
)
{
PageResponse
<
RoleDTO
>
result
=
roleService
.
findAll
(
page
,
size
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@GetMapping
(
"/simple"
)
public
ResponseEntity
<
ApiResponse
<
List
<
RoleDTO
>>>
findAllSimple
()
{
List
<
RoleDTO
>
result
=
roleService
.
findAllSimple
();
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
result
));
}
@GetMapping
(
"/{id}"
)
public
ResponseEntity
<
ApiResponse
<
RoleDTO
>>
findById
(
@PathVariable
Long
id
)
{
RoleDTO
role
=
roleService
.
findById
(
id
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
role
));
}
@PostMapping
public
ResponseEntity
<
ApiResponse
<
RoleDTO
>>
createRole
(
@Valid
@RequestBody
CreateRoleRequest
request
)
{
try
{
RoleDTO
role
=
roleService
.
createRole
(
request
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"创建成功"
,
role
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"创建角色失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
@PutMapping
(
"/{id}"
)
public
ResponseEntity
<
ApiResponse
<
RoleDTO
>>
updateRole
(
@PathVariable
Long
id
,
@Valid
@RequestBody
UpdateRoleRequest
request
)
{
try
{
RoleDTO
role
=
roleService
.
updateRole
(
id
,
request
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"更新成功"
,
role
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"更新角色失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
@DeleteMapping
(
"/{id}"
)
public
ResponseEntity
<
ApiResponse
<
Void
>>
deleteRole
(
@PathVariable
Long
id
)
{
try
{
roleService
.
deleteRole
(
id
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"删除成功"
,
null
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"删除角色失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
@GetMapping
(
"/{id}/menus"
)
public
ResponseEntity
<
ApiResponse
<
List
<
Long
>>>
getRoleMenus
(
@PathVariable
Long
id
)
{
List
<
Long
>
menuIds
=
roleService
.
getRoleMenuIds
(
id
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
menuIds
));
}
@PutMapping
(
"/{id}/menus"
)
public
ResponseEntity
<
ApiResponse
<
Void
>>
saveRoleMenus
(
@PathVariable
Long
id
,
@RequestBody
Map
<
String
,
List
<
Long
>>
body
)
{
try
{
roleService
.
saveRoleMenus
(
id
,
body
.
get
(
"menuIds"
));
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"保存成功"
,
null
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"保存角色菜单失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
@GetMapping
(
"/{id}/users"
)
public
ResponseEntity
<
ApiResponse
<
List
<
Long
>>>
getRoleUsers
(
@PathVariable
Long
id
)
{
List
<
Long
>
userIds
=
roleService
.
getRoleUserIds
(
id
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
userIds
));
}
@PostMapping
(
"/assign-user"
)
public
ResponseEntity
<
ApiResponse
<
Void
>>
assignUserToRole
(
@RequestBody
Map
<
String
,
Object
>
body
)
{
try
{
Long
userId
=
Long
.
valueOf
(
body
.
get
(
"userId"
).
toString
());
String
roleCode
=
body
.
get
(
"roleCode"
).
toString
();
roleService
.
assignUserToRole
(
userId
,
roleCode
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"分配成功"
,
null
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"分配用户到角色失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
@DeleteMapping
(
"/user/{userId}/role"
)
public
ResponseEntity
<
ApiResponse
<
Void
>>
removeUserFromRole
(
@PathVariable
Long
userId
)
{
try
{
roleService
.
removeUserFromRole
(
userId
);
return
ResponseEntity
.
ok
(
ApiResponse
.
success
(
"移除成功"
,
null
));
}
catch
(
Exception
e
)
{
log
.
warn
(
"移除用户角色失败: {}"
,
e
.
getMessage
());
return
ResponseEntity
.
ok
(
ApiResponse
.
error
(
400
,
e
.
getMessage
()));
}
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/AnalysisConfigDTO.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.util.List
;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
AnalysisConfigDTO
{
private
Long
templateId
;
private
String
templateName
;
private
List
<
Long
>
ruleIds
;
private
List
<
Long
>
keywordIds
;
private
Long
updatedBy
;
private
String
updatedAt
;
}
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/AnalysisKeywordDTO.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.time.LocalDateTime
;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
AnalysisKeywordDTO
{
private
Long
id
;
private
String
keyword
;
private
String
category
;
private
String
level
;
private
String
description
;
private
Boolean
enabled
;
private
LocalDateTime
createTime
;
private
LocalDateTime
updateTime
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/AnalysisRuleDTO.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.time.LocalDateTime
;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
AnalysisRuleDTO
{
private
Long
id
;
private
String
name
;
private
String
description
;
private
String
institutionType
;
private
String
penaltyType
;
private
Long
minAmount
;
private
Long
maxAmount
;
private
String
prompt
;
private
Boolean
enabled
;
private
Integer
priority
;
private
LocalDateTime
createTime
;
private
LocalDateTime
updateTime
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/AnalyzeRequest.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
lombok.Data
;
@Data
public
class
AnalyzeRequest
{
private
Long
templateId
;
}
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/CreateAnalysisKeywordRequest.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
jakarta.validation.constraints.NotBlank
;
import
jakarta.validation.constraints.Size
;
import
lombok.Data
;
@Data
public
class
CreateAnalysisKeywordRequest
{
@NotBlank
(
message
=
"关键词不能为空"
)
@Size
(
max
=
100
,
message
=
"关键词长度不能超过100个字符"
)
private
String
keyword
;
@Size
(
max
=
50
,
message
=
"分类长度不能超过50个字符"
)
private
String
category
;
@Size
(
max
=
50
,
message
=
"级别长度不能超过50个字符"
)
private
String
level
;
@Size
(
max
=
500
,
message
=
"描述长度不能超过500个字符"
)
private
String
description
;
private
Boolean
enabled
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/CreateAnalysisRuleRequest.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
jakarta.validation.constraints.NotBlank
;
import
jakarta.validation.constraints.Size
;
import
lombok.Data
;
@Data
public
class
CreateAnalysisRuleRequest
{
@NotBlank
(
message
=
"规则名称不能为空"
)
@Size
(
max
=
100
,
message
=
"规则名称长度不能超过100个字符"
)
private
String
name
;
@Size
(
max
=
200
,
message
=
"描述长度不能超过200个字符"
)
private
String
description
;
private
String
institutionType
;
private
String
penaltyType
;
private
Long
minAmount
;
private
Long
maxAmount
;
@NotBlank
(
message
=
"Prompt不能为空"
)
private
String
prompt
;
private
Boolean
enabled
;
private
Integer
priority
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/CreateMenuRequest.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
jakarta.validation.constraints.NotBlank
;
import
jakarta.validation.constraints.Size
;
import
lombok.Data
;
@Data
public
class
CreateMenuRequest
{
@NotBlank
(
message
=
"菜单名称不能为空"
)
@Size
(
max
=
100
,
message
=
"菜单名称长度不能超过100个字符"
)
private
String
name
;
@Size
(
max
=
100
,
message
=
"路径长度不能超过100个字符"
)
private
String
path
;
@Size
(
max
=
50
,
message
=
"图标长度不能超过50个字符"
)
private
String
icon
;
@Size
(
max
=
100
,
message
=
"组件路径长度不能超过100个字符"
)
private
String
component
;
private
Long
parentId
;
private
Integer
sortOrder
;
private
Boolean
visible
;
private
Boolean
enabled
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/CreatePermissionRequest.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
jakarta.validation.constraints.NotBlank
;
import
jakarta.validation.constraints.Size
;
import
lombok.Data
;
@Data
public
class
CreatePermissionRequest
{
@NotBlank
(
message
=
"权限编码不能为空"
)
@Size
(
max
=
100
,
message
=
"权限编码长度不能超过100个字符"
)
private
String
code
;
@NotBlank
(
message
=
"权限名称不能为空"
)
@Size
(
max
=
100
,
message
=
"权限名称长度不能超过100个字符"
)
private
String
name
;
@Size
(
max
=
50
,
message
=
"权限类型长度不能超过50个字符"
)
private
String
type
;
@Size
(
max
=
200
,
message
=
"资源长度不能超过200个字符"
)
private
String
resource
;
@Size
(
max
=
500
,
message
=
"描述长度不能超过500个字符"
)
private
String
description
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/CreateReportTemplateRequest.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
jakarta.validation.constraints.NotBlank
;
import
jakarta.validation.constraints.Size
;
import
lombok.Data
;
@Data
public
class
CreateReportTemplateRequest
{
@NotBlank
(
message
=
"模板名称不能为空"
)
@Size
(
max
=
100
,
message
=
"模板名称长度不能超过100个字符"
)
private
String
name
;
@Size
(
max
=
200
,
message
=
"描述长度不能超过200个字符"
)
private
String
description
;
@NotBlank
(
message
=
"模板内容不能为空"
)
private
String
content
;
private
Boolean
isDefault
;
private
Boolean
enabled
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/CreateRoleRequest.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
jakarta.validation.constraints.NotBlank
;
import
jakarta.validation.constraints.Size
;
import
lombok.Data
;
import
java.util.List
;
@Data
public
class
CreateRoleRequest
{
@NotBlank
(
message
=
"角色编码不能为空"
)
@Size
(
min
=
2
,
max
=
50
,
message
=
"角色编码长度必须在2-50个字符之间"
)
private
String
code
;
@NotBlank
(
message
=
"角色名称不能为空"
)
@Size
(
max
=
100
,
message
=
"角色名称长度不能超过100个字符"
)
private
String
name
;
@Size
(
max
=
500
,
message
=
"描述长度不能超过500个字符"
)
private
String
description
;
private
List
<
String
>
permissions
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/MenuDTO.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.time.LocalDateTime
;
import
java.util.List
;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
MenuDTO
{
private
Long
id
;
private
String
name
;
private
String
path
;
private
String
icon
;
private
String
component
;
private
Long
parentId
;
private
Integer
sortOrder
;
private
Boolean
visible
;
private
Boolean
enabled
;
private
List
<
MenuDTO
>
children
;
private
LocalDateTime
createTime
;
private
LocalDateTime
updateTime
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/PermissionDTO.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.time.LocalDateTime
;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
PermissionDTO
{
private
Long
id
;
private
String
code
;
private
String
name
;
private
String
type
;
private
String
resource
;
private
String
description
;
private
LocalDateTime
createTime
;
private
LocalDateTime
updateTime
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/ReportTemplateDTO.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.time.LocalDateTime
;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
ReportTemplateDTO
{
private
Long
id
;
private
String
name
;
private
String
description
;
private
String
content
;
private
Boolean
isDefault
;
private
Boolean
enabled
;
private
LocalDateTime
createTime
;
private
LocalDateTime
updateTime
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/RoleDTO.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.time.LocalDateTime
;
import
java.util.List
;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
RoleDTO
{
private
Long
id
;
private
String
code
;
private
String
name
;
private
String
description
;
private
List
<
String
>
permissions
;
private
LocalDateTime
createTime
;
private
LocalDateTime
updateTime
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/UpdateAnalysisKeywordRequest.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
jakarta.validation.constraints.Size
;
import
lombok.Data
;
@Data
public
class
UpdateAnalysisKeywordRequest
{
@Size
(
max
=
100
,
message
=
"关键词长度不能超过100个字符"
)
private
String
keyword
;
@Size
(
max
=
50
,
message
=
"分类长度不能超过50个字符"
)
private
String
category
;
@Size
(
max
=
50
,
message
=
"级别长度不能超过50个字符"
)
private
String
level
;
@Size
(
max
=
500
,
message
=
"描述长度不能超过500个字符"
)
private
String
description
;
private
Boolean
enabled
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/UpdateAnalysisRuleRequest.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
jakarta.validation.constraints.Size
;
import
lombok.Data
;
@Data
public
class
UpdateAnalysisRuleRequest
{
@Size
(
max
=
100
,
message
=
"规则名称长度不能超过100个字符"
)
private
String
name
;
@Size
(
max
=
200
,
message
=
"描述长度不能超过200个字符"
)
private
String
description
;
private
String
institutionType
;
private
String
penaltyType
;
private
Long
minAmount
;
private
Long
maxAmount
;
private
String
prompt
;
private
Boolean
enabled
;
private
Integer
priority
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/UpdateMenuRequest.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
jakarta.validation.constraints.Size
;
import
lombok.Data
;
@Data
public
class
UpdateMenuRequest
{
@Size
(
max
=
100
,
message
=
"菜单名称长度不能超过100个字符"
)
private
String
name
;
@Size
(
max
=
100
,
message
=
"路径长度不能超过100个字符"
)
private
String
path
;
@Size
(
max
=
50
,
message
=
"图标长度不能超过50个字符"
)
private
String
icon
;
@Size
(
max
=
100
,
message
=
"组件路径长度不能超过100个字符"
)
private
String
component
;
private
Long
parentId
;
private
Integer
sortOrder
;
private
Boolean
visible
;
private
Boolean
enabled
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/UpdatePermissionRequest.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
jakarta.validation.constraints.Size
;
import
lombok.Data
;
@Data
public
class
UpdatePermissionRequest
{
@Size
(
max
=
100
,
message
=
"权限名称长度不能超过100个字符"
)
private
String
name
;
@Size
(
max
=
50
,
message
=
"权限类型长度不能超过50个字符"
)
private
String
type
;
@Size
(
max
=
200
,
message
=
"资源长度不能超过200个字符"
)
private
String
resource
;
@Size
(
max
=
500
,
message
=
"描述长度不能超过500个字符"
)
private
String
description
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/UpdateReportTemplateRequest.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
jakarta.validation.constraints.Size
;
import
lombok.Data
;
@Data
public
class
UpdateReportTemplateRequest
{
@Size
(
max
=
100
,
message
=
"模板名称长度不能超过100个字符"
)
private
String
name
;
@Size
(
max
=
200
,
message
=
"描述长度不能超过200个字符"
)
private
String
description
;
private
String
content
;
private
Boolean
isDefault
;
private
Boolean
enabled
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/dto/UpdateRoleRequest.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
dto
;
import
jakarta.validation.constraints.Size
;
import
lombok.Data
;
import
java.util.List
;
@Data
public
class
UpdateRoleRequest
{
@Size
(
max
=
100
,
message
=
"角色名称长度不能超过100个字符"
)
private
String
name
;
@Size
(
max
=
500
,
message
=
"描述长度不能超过500个字符"
)
private
String
description
;
private
List
<
String
>
permissions
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/entity/AnalysisKeyword.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
entity
;
import
jakarta.persistence.*
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.time.LocalDateTime
;
@Entity
@Table
(
name
=
"analysis_keywords"
)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
AnalysisKeyword
{
@Id
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
private
Long
id
;
@Column
(
nullable
=
false
,
length
=
100
)
private
String
keyword
;
@Column
(
length
=
50
)
private
String
category
;
@Column
(
length
=
50
)
private
String
level
;
@Column
(
columnDefinition
=
"TEXT"
)
private
String
description
;
@Column
(
name
=
"is_enabled"
)
@Builder
.
Default
private
Boolean
enabled
=
true
;
@Column
(
name
=
"create_time"
,
updatable
=
false
)
private
LocalDateTime
createTime
;
@Column
(
name
=
"update_time"
)
private
LocalDateTime
updateTime
;
@PrePersist
protected
void
onCreate
()
{
createTime
=
LocalDateTime
.
now
();
updateTime
=
LocalDateTime
.
now
();
}
@PreUpdate
protected
void
onUpdate
()
{
updateTime
=
LocalDateTime
.
now
();
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/entity/AnalysisRule.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
entity
;
import
jakarta.persistence.*
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.time.LocalDateTime
;
@Entity
@Table
(
name
=
"analysis_rules"
)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
AnalysisRule
{
@Id
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
private
Long
id
;
@Column
(
nullable
=
false
,
length
=
100
)
private
String
name
;
@Column
(
length
=
200
)
private
String
description
;
@Column
(
name
=
"institution_type"
)
private
String
institutionType
;
@Column
(
name
=
"penalty_type"
)
private
String
penaltyType
;
@Column
(
name
=
"min_amount"
)
private
Long
minAmount
;
@Column
(
name
=
"max_amount"
)
private
Long
maxAmount
;
@Column
(
columnDefinition
=
"TEXT"
)
private
String
prompt
;
@Column
(
name
=
"is_enabled"
)
@Builder
.
Default
private
Boolean
enabled
=
true
;
@Column
(
name
=
"priority"
)
@Builder
.
Default
private
Integer
priority
=
0
;
@Column
(
name
=
"create_time"
,
updatable
=
false
)
private
LocalDateTime
createTime
;
@Column
(
name
=
"update_time"
)
private
LocalDateTime
updateTime
;
@PrePersist
protected
void
onCreate
()
{
createTime
=
LocalDateTime
.
now
();
updateTime
=
LocalDateTime
.
now
();
}
@PreUpdate
protected
void
onUpdate
()
{
updateTime
=
LocalDateTime
.
now
();
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/entity/Menu.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
entity
;
import
jakarta.persistence.*
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.time.LocalDateTime
;
@Entity
@Table
(
name
=
"menus"
)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
Menu
{
@Id
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
private
Long
id
;
@Column
(
nullable
=
false
,
length
=
100
)
private
String
name
;
@Column
(
length
=
100
)
private
String
path
;
@Column
(
length
=
50
)
private
String
icon
;
@Column
(
length
=
100
)
private
String
component
;
@Column
(
name
=
"parent_id"
)
private
Long
parentId
;
@Column
(
name
=
"sort_order"
)
@Builder
.
Default
private
Integer
sortOrder
=
0
;
@Column
(
name
=
"is_visible"
)
@Builder
.
Default
private
Boolean
visible
=
true
;
@Column
(
name
=
"is_enabled"
)
@Builder
.
Default
private
Boolean
enabled
=
true
;
@Column
(
name
=
"create_time"
,
updatable
=
false
)
private
LocalDateTime
createTime
;
@Column
(
name
=
"update_time"
)
private
LocalDateTime
updateTime
;
@PrePersist
protected
void
onCreate
()
{
createTime
=
LocalDateTime
.
now
();
updateTime
=
LocalDateTime
.
now
();
}
@PreUpdate
protected
void
onUpdate
()
{
updateTime
=
LocalDateTime
.
now
();
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/entity/Permission.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
entity
;
import
jakarta.persistence.*
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.time.LocalDateTime
;
@Entity
@Table
(
name
=
"permissions"
)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
Permission
{
@Id
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
private
Long
id
;
@Column
(
nullable
=
false
,
unique
=
true
,
length
=
100
)
private
String
code
;
@Column
(
nullable
=
false
,
length
=
100
)
private
String
name
;
@Column
(
length
=
50
)
private
String
type
;
@Column
(
length
=
200
)
private
String
resource
;
@Column
(
length
=
500
)
private
String
description
;
@Column
(
name
=
"create_time"
,
updatable
=
false
)
private
LocalDateTime
createTime
;
@Column
(
name
=
"update_time"
)
private
LocalDateTime
updateTime
;
@PrePersist
protected
void
onCreate
()
{
createTime
=
LocalDateTime
.
now
();
updateTime
=
LocalDateTime
.
now
();
}
@PreUpdate
protected
void
onUpdate
()
{
updateTime
=
LocalDateTime
.
now
();
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/entity/ReportTemplate.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
entity
;
import
jakarta.persistence.*
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.time.LocalDateTime
;
@Entity
@Table
(
name
=
"report_templates"
)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
ReportTemplate
{
@Id
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
private
Long
id
;
@Column
(
nullable
=
false
,
length
=
100
)
private
String
name
;
@Column
(
length
=
200
)
private
String
description
;
@Column
(
columnDefinition
=
"TEXT"
)
private
String
content
;
@Column
(
name
=
"is_default"
)
@Builder
.
Default
private
Boolean
isDefault
=
false
;
@Column
(
name
=
"is_enabled"
)
@Builder
.
Default
private
Boolean
enabled
=
true
;
@Column
(
name
=
"create_time"
,
updatable
=
false
)
private
LocalDateTime
createTime
;
@Column
(
name
=
"update_time"
)
private
LocalDateTime
updateTime
;
@PrePersist
protected
void
onCreate
()
{
createTime
=
LocalDateTime
.
now
();
updateTime
=
LocalDateTime
.
now
();
}
@PreUpdate
protected
void
onUpdate
()
{
updateTime
=
LocalDateTime
.
now
();
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/entity/Role.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
entity
;
import
jakarta.persistence.*
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.time.LocalDateTime
;
@Entity
@Table
(
name
=
"roles"
)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
Role
{
@Id
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
private
Long
id
;
@Column
(
nullable
=
false
,
unique
=
true
,
length
=
50
)
private
String
code
;
@Column
(
nullable
=
false
,
length
=
100
)
private
String
name
;
@Column
(
length
=
500
)
private
String
description
;
@Column
(
name
=
"create_time"
,
updatable
=
false
)
private
LocalDateTime
createTime
;
@Column
(
name
=
"update_time"
)
private
LocalDateTime
updateTime
;
@PrePersist
protected
void
onCreate
()
{
createTime
=
LocalDateTime
.
now
();
updateTime
=
LocalDateTime
.
now
();
}
@PreUpdate
protected
void
onUpdate
()
{
updateTime
=
LocalDateTime
.
now
();
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/entity/RoleMenu.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
entity
;
import
jakarta.persistence.*
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
@Entity
@Table
(
name
=
"role_menus"
)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
RoleMenu
{
@Id
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
private
Long
id
;
@Column
(
name
=
"role_id"
,
nullable
=
false
)
private
Long
roleId
;
@Column
(
name
=
"menu_id"
,
nullable
=
false
)
private
Long
menuId
;
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/repository/AnalysisKeywordRepository.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
repository
;
import
com.fintech.penalty.entity.AnalysisKeyword
;
import
org.springframework.data.jpa.repository.JpaRepository
;
import
org.springframework.stereotype.Repository
;
import
java.util.List
;
@Repository
public
interface
AnalysisKeywordRepository
extends
JpaRepository
<
AnalysisKeyword
,
Long
>
{
List
<
AnalysisKeyword
>
findByEnabledTrue
();
List
<
AnalysisKeyword
>
findByEnabledTrueAndCategory
(
String
category
);
List
<
AnalysisKeyword
>
findByEnabledTrueAndLevel
(
String
level
);
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/repository/AnalysisRuleRepository.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
repository
;
import
com.fintech.penalty.entity.AnalysisRule
;
import
org.springframework.data.jpa.repository.JpaRepository
;
import
org.springframework.data.jpa.repository.Query
;
import
org.springframework.stereotype.Repository
;
import
java.util.List
;
import
java.util.Optional
;
@Repository
public
interface
AnalysisRuleRepository
extends
JpaRepository
<
AnalysisRule
,
Long
>
{
List
<
AnalysisRule
>
findByEnabledTrueOrderByPriorityDesc
();
@Query
(
"SELECT r FROM AnalysisRule r WHERE r.enabled = true AND "
+
"(r.institutionType IS NULL OR r.institutionType = :institutionType) AND "
+
"(r.penaltyType IS NULL OR r.penaltyType = :penaltyType) AND "
+
"(r.minAmount IS NULL OR r.minAmount <= :amount) AND "
+
"(r.maxAmount IS NULL OR r.maxAmount >= :amount) "
+
"ORDER BY r.priority DESC"
)
List
<
AnalysisRule
>
findMatchingRules
(
String
institutionType
,
String
penaltyType
,
Long
amount
);
Optional
<
AnalysisRule
>
findFirstByEnabledTrueOrderByPriorityDesc
();
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/repository/MenuRepository.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
repository
;
import
com.fintech.penalty.entity.Menu
;
import
org.springframework.data.jpa.repository.JpaRepository
;
import
org.springframework.data.jpa.repository.Query
;
import
org.springframework.stereotype.Repository
;
import
java.util.List
;
@Repository
public
interface
MenuRepository
extends
JpaRepository
<
Menu
,
Long
>
{
List
<
Menu
>
findByParentIdOrderBySortOrderAsc
(
Long
parentId
);
List
<
Menu
>
findByParentIdIsNullOrderBySortOrderAsc
();
@Query
(
"SELECT m FROM Menu m WHERE m.visible = true AND m.enabled = true ORDER BY m.sortOrder ASC"
)
List
<
Menu
>
findAllVisible
();
@Query
(
"SELECT m FROM Menu m WHERE m.visible = true AND m.enabled = true AND (m.parentId IS NULL OR m.parentId = 0) ORDER BY m.sortOrder ASC"
)
List
<
Menu
>
findRootMenusVisible
();
boolean
existsByName
(
String
name
);
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/repository/PermissionRepository.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
repository
;
import
com.fintech.penalty.entity.Permission
;
import
org.springframework.data.jpa.repository.JpaRepository
;
import
org.springframework.stereotype.Repository
;
import
java.util.List
;
import
java.util.Optional
;
@Repository
public
interface
PermissionRepository
extends
JpaRepository
<
Permission
,
Long
>
{
Optional
<
Permission
>
findByCode
(
String
code
);
boolean
existsByCode
(
String
code
);
List
<
Permission
>
findByCodeIn
(
List
<
String
>
codes
);
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/repository/ReportTemplateRepository.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
repository
;
import
com.fintech.penalty.entity.ReportTemplate
;
import
org.springframework.data.jpa.repository.JpaRepository
;
import
org.springframework.stereotype.Repository
;
import
java.util.List
;
import
java.util.Optional
;
@Repository
public
interface
ReportTemplateRepository
extends
JpaRepository
<
ReportTemplate
,
Long
>
{
List
<
ReportTemplate
>
findByEnabledTrue
();
Optional
<
ReportTemplate
>
findByIsDefaultTrue
();
Optional
<
ReportTemplate
>
findByIsDefaultTrueAndEnabledTrue
();
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/repository/RoleMenuRepository.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
repository
;
import
com.fintech.penalty.entity.RoleMenu
;
import
org.springframework.data.jpa.repository.JpaRepository
;
import
org.springframework.stereotype.Repository
;
import
java.util.List
;
@Repository
public
interface
RoleMenuRepository
extends
JpaRepository
<
RoleMenu
,
Long
>
{
List
<
RoleMenu
>
findByRoleId
(
Long
roleId
);
void
deleteByRoleId
(
Long
roleId
);
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/repository/RoleRepository.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
repository
;
import
com.fintech.penalty.entity.Role
;
import
org.springframework.data.jpa.repository.JpaRepository
;
import
org.springframework.stereotype.Repository
;
import
java.util.Optional
;
@Repository
public
interface
RoleRepository
extends
JpaRepository
<
Role
,
Long
>
{
Optional
<
Role
>
findByCode
(
String
code
);
boolean
existsByCode
(
String
code
);
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/service/AnalysisConfigService.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
service
;
import
com.fintech.penalty.dto.AnalysisConfigDTO
;
import
com.fintech.penalty.entity.SystemConfig
;
import
com.fintech.penalty.repository.SystemConfigRepository
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
java.time.LocalDateTime
;
import
java.time.format.DateTimeFormatter
;
@Service
@RequiredArgsConstructor
@Slf4j
public
class
AnalysisConfigService
{
private
static
final
String
CONFIG_KEY
=
"analysis_config"
;
private
final
SystemConfigRepository
configRepository
;
private
final
ObjectMapper
objectMapper
=
new
ObjectMapper
();
public
AnalysisConfigDTO
getActiveConfig
()
{
return
configRepository
.
findByConfigKey
(
CONFIG_KEY
)
.
map
(
config
->
{
try
{
return
objectMapper
.
readValue
(
config
.
getConfigValue
(),
AnalysisConfigDTO
.
class
);
}
catch
(
Exception
e
)
{
log
.
error
(
"解析分析配置失败"
,
e
);
return
null
;
}
})
.
orElse
(
null
);
}
public
void
saveActiveConfig
(
AnalysisConfigDTO
config
)
{
try
{
String
json
=
objectMapper
.
writeValueAsString
(
config
);
SystemConfig
systemConfig
=
configRepository
.
findByConfigKey
(
CONFIG_KEY
)
.
orElse
(
SystemConfig
.
builder
().
configKey
(
CONFIG_KEY
).
build
());
systemConfig
.
setConfigValue
(
json
);
systemConfig
.
setConfigType
(
"json"
);
systemConfig
.
setConfigDesc
(
"当前分析配置: 模板ID、规则ID列表、关键词ID列表"
);
systemConfig
.
setUpdatedAt
(
LocalDateTime
.
now
());
configRepository
.
save
(
systemConfig
);
log
.
info
(
"保存分析配置成功"
);
}
catch
(
Exception
e
)
{
log
.
error
(
"保存分析配置失败"
,
e
);
throw
new
RuntimeException
(
"保存分析配置失败: "
+
e
.
getMessage
());
}
}
}
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/service/AnalysisKeywordService.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
service
;
import
com.fintech.penalty.dto.*
;
import
com.fintech.penalty.entity.AnalysisKeyword
;
import
com.fintech.penalty.repository.AnalysisKeywordRepository
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.data.domain.Page
;
import
org.springframework.data.domain.PageRequest
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
java.util.List
;
import
java.util.stream.Collectors
;
@Service
@RequiredArgsConstructor
@Slf4j
public
class
AnalysisKeywordService
{
private
final
AnalysisKeywordRepository
keywordRepository
;
public
PageResponse
<
AnalysisKeywordDTO
>
findAll
(
int
page
,
int
size
)
{
Page
<
AnalysisKeyword
>
pageResult
=
keywordRepository
.
findAll
(
PageRequest
.
of
(
page
,
size
));
List
<
AnalysisKeywordDTO
>
content
=
pageResult
.
getContent
().
stream
()
.
map
(
this
::
toDTO
)
.
collect
(
Collectors
.
toList
());
return
PageResponse
.<
AnalysisKeywordDTO
>
builder
()
.
content
(
content
)
.
totalElements
(
pageResult
.
getTotalElements
())
.
totalPages
(
pageResult
.
getTotalPages
())
.
pageNumber
(
page
)
.
pageSize
(
size
)
.
hasNext
(
pageResult
.
hasNext
())
.
hasPrevious
(
pageResult
.
hasPrevious
())
.
build
();
}
public
List
<
AnalysisKeywordDTO
>
findAllEnabled
()
{
return
keywordRepository
.
findByEnabledTrue
().
stream
()
.
map
(
this
::
toDTO
)
.
collect
(
Collectors
.
toList
());
}
public
List
<
AnalysisKeywordDTO
>
findByCategory
(
String
category
)
{
return
keywordRepository
.
findByEnabledTrueAndCategory
(
category
).
stream
()
.
map
(
this
::
toDTO
)
.
collect
(
Collectors
.
toList
());
}
public
AnalysisKeywordDTO
findById
(
Long
id
)
{
return
keywordRepository
.
findById
(
id
)
.
map
(
this
::
toDTO
)
.
orElse
(
null
);
}
@Transactional
public
AnalysisKeywordDTO
create
(
CreateAnalysisKeywordRequest
request
)
{
AnalysisKeyword
keyword
=
AnalysisKeyword
.
builder
()
.
keyword
(
request
.
getKeyword
())
.
category
(
request
.
getCategory
())
.
level
(
request
.
getLevel
())
.
description
(
request
.
getDescription
())
.
enabled
(
request
.
getEnabled
()
!=
null
?
request
.
getEnabled
()
:
true
)
.
build
();
AnalysisKeyword
saved
=
keywordRepository
.
save
(
keyword
);
log
.
info
(
"创建关键词: {}"
,
saved
.
getKeyword
());
return
toDTO
(
saved
);
}
@Transactional
public
AnalysisKeywordDTO
update
(
Long
id
,
UpdateAnalysisKeywordRequest
request
)
{
AnalysisKeyword
keyword
=
keywordRepository
.
findById
(
id
)
.
orElseThrow
(()
->
new
RuntimeException
(
"关键词不存在"
));
if
(
request
.
getKeyword
()
!=
null
)
{
keyword
.
setKeyword
(
request
.
getKeyword
());
}
if
(
request
.
getCategory
()
!=
null
)
{
keyword
.
setCategory
(
request
.
getCategory
());
}
if
(
request
.
getLevel
()
!=
null
)
{
keyword
.
setLevel
(
request
.
getLevel
());
}
if
(
request
.
getDescription
()
!=
null
)
{
keyword
.
setDescription
(
request
.
getDescription
());
}
if
(
request
.
getEnabled
()
!=
null
)
{
keyword
.
setEnabled
(
request
.
getEnabled
());
}
AnalysisKeyword
saved
=
keywordRepository
.
save
(
keyword
);
log
.
info
(
"更新关键词: {}"
,
saved
.
getKeyword
());
return
toDTO
(
saved
);
}
@Transactional
public
void
delete
(
Long
id
)
{
AnalysisKeyword
keyword
=
keywordRepository
.
findById
(
id
)
.
orElseThrow
(()
->
new
RuntimeException
(
"关键词不存在"
));
keywordRepository
.
delete
(
keyword
);
log
.
info
(
"删除关键词: {}"
,
keyword
.
getKeyword
());
}
private
AnalysisKeywordDTO
toDTO
(
AnalysisKeyword
keyword
)
{
return
AnalysisKeywordDTO
.
builder
()
.
id
(
keyword
.
getId
())
.
keyword
(
keyword
.
getKeyword
())
.
category
(
keyword
.
getCategory
())
.
level
(
keyword
.
getLevel
())
.
description
(
keyword
.
getDescription
())
.
enabled
(
keyword
.
getEnabled
())
.
createTime
(
keyword
.
getCreateTime
())
.
updateTime
(
keyword
.
getUpdateTime
())
.
build
();
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/service/AnalysisRuleService.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
service
;
import
com.fintech.penalty.dto.*
;
import
com.fintech.penalty.entity.AnalysisRule
;
import
com.fintech.penalty.repository.AnalysisRuleRepository
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.data.domain.Page
;
import
org.springframework.data.domain.PageRequest
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
java.util.List
;
import
java.util.stream.Collectors
;
@Service
@RequiredArgsConstructor
@Slf4j
public
class
AnalysisRuleService
{
private
final
AnalysisRuleRepository
ruleRepository
;
public
PageResponse
<
AnalysisRuleDTO
>
findAll
(
int
page
,
int
size
)
{
Page
<
AnalysisRule
>
pageResult
=
ruleRepository
.
findAll
(
PageRequest
.
of
(
page
,
size
));
List
<
AnalysisRuleDTO
>
content
=
pageResult
.
getContent
().
stream
()
.
map
(
this
::
toDTO
)
.
collect
(
Collectors
.
toList
());
return
PageResponse
.<
AnalysisRuleDTO
>
builder
()
.
content
(
content
)
.
totalElements
(
pageResult
.
getTotalElements
())
.
totalPages
(
pageResult
.
getTotalPages
())
.
pageNumber
(
page
)
.
pageSize
(
size
)
.
hasNext
(
pageResult
.
hasNext
())
.
hasPrevious
(
pageResult
.
hasPrevious
())
.
build
();
}
public
List
<
AnalysisRuleDTO
>
findAllEnabled
()
{
return
ruleRepository
.
findByEnabledTrueOrderByPriorityDesc
().
stream
()
.
map
(
this
::
toDTO
)
.
collect
(
Collectors
.
toList
());
}
public
AnalysisRuleDTO
findById
(
Long
id
)
{
return
ruleRepository
.
findById
(
id
)
.
map
(
this
::
toDTO
)
.
orElse
(
null
);
}
public
List
<
AnalysisRuleDTO
>
findMatchingRules
(
String
institutionType
,
String
penaltyType
,
Long
amount
)
{
return
ruleRepository
.
findMatchingRules
(
institutionType
,
penaltyType
,
amount
).
stream
()
.
map
(
this
::
toDTO
)
.
collect
(
Collectors
.
toList
());
}
@Transactional
public
AnalysisRuleDTO
create
(
CreateAnalysisRuleRequest
request
)
{
AnalysisRule
rule
=
AnalysisRule
.
builder
()
.
name
(
request
.
getName
())
.
description
(
request
.
getDescription
())
.
institutionType
(
request
.
getInstitutionType
())
.
penaltyType
(
request
.
getPenaltyType
())
.
minAmount
(
request
.
getMinAmount
())
.
maxAmount
(
request
.
getMaxAmount
())
.
prompt
(
request
.
getPrompt
())
.
enabled
(
request
.
getEnabled
()
!=
null
?
request
.
getEnabled
()
:
true
)
.
priority
(
request
.
getPriority
()
!=
null
?
request
.
getPriority
()
:
0
)
.
build
();
AnalysisRule
saved
=
ruleRepository
.
save
(
rule
);
log
.
info
(
"创建分析规则: {}"
,
saved
.
getName
());
return
toDTO
(
saved
);
}
@Transactional
public
AnalysisRuleDTO
update
(
Long
id
,
UpdateAnalysisRuleRequest
request
)
{
AnalysisRule
rule
=
ruleRepository
.
findById
(
id
)
.
orElseThrow
(()
->
new
RuntimeException
(
"规则不存在"
));
if
(
request
.
getName
()
!=
null
)
{
rule
.
setName
(
request
.
getName
());
}
if
(
request
.
getDescription
()
!=
null
)
{
rule
.
setDescription
(
request
.
getDescription
());
}
if
(
request
.
getInstitutionType
()
!=
null
)
{
rule
.
setInstitutionType
(
request
.
getInstitutionType
());
}
if
(
request
.
getPenaltyType
()
!=
null
)
{
rule
.
setPenaltyType
(
request
.
getPenaltyType
());
}
if
(
request
.
getMinAmount
()
!=
null
)
{
rule
.
setMinAmount
(
request
.
getMinAmount
());
}
if
(
request
.
getMaxAmount
()
!=
null
)
{
rule
.
setMaxAmount
(
request
.
getMaxAmount
());
}
if
(
request
.
getPrompt
()
!=
null
)
{
rule
.
setPrompt
(
request
.
getPrompt
());
}
if
(
request
.
getEnabled
()
!=
null
)
{
rule
.
setEnabled
(
request
.
getEnabled
());
}
if
(
request
.
getPriority
()
!=
null
)
{
rule
.
setPriority
(
request
.
getPriority
());
}
AnalysisRule
saved
=
ruleRepository
.
save
(
rule
);
log
.
info
(
"更新分析规则: {}"
,
saved
.
getName
());
return
toDTO
(
saved
);
}
@Transactional
public
void
delete
(
Long
id
)
{
AnalysisRule
rule
=
ruleRepository
.
findById
(
id
)
.
orElseThrow
(()
->
new
RuntimeException
(
"规则不存在"
));
ruleRepository
.
delete
(
rule
);
log
.
info
(
"删除分析规则: {}"
,
rule
.
getName
());
}
private
AnalysisRuleDTO
toDTO
(
AnalysisRule
rule
)
{
return
AnalysisRuleDTO
.
builder
()
.
id
(
rule
.
getId
())
.
name
(
rule
.
getName
())
.
description
(
rule
.
getDescription
())
.
institutionType
(
rule
.
getInstitutionType
())
.
penaltyType
(
rule
.
getPenaltyType
())
.
minAmount
(
rule
.
getMinAmount
())
.
maxAmount
(
rule
.
getMaxAmount
())
.
prompt
(
rule
.
getPrompt
())
.
enabled
(
rule
.
getEnabled
())
.
priority
(
rule
.
getPriority
())
.
createTime
(
rule
.
getCreateTime
())
.
updateTime
(
rule
.
getUpdateTime
())
.
build
();
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/service/MenuService.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
service
;
import
com.fintech.penalty.dto.*
;
import
com.fintech.penalty.entity.Menu
;
import
com.fintech.penalty.entity.RoleMenu
;
import
com.fintech.penalty.repository.MenuRepository
;
import
com.fintech.penalty.repository.RoleMenuRepository
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
java.util.ArrayList
;
import
java.util.Comparator
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.stream.Collectors
;
@Service
@RequiredArgsConstructor
@Slf4j
public
class
MenuService
{
private
final
MenuRepository
menuRepository
;
private
final
RoleMenuRepository
roleMenuRepository
;
public
List
<
MenuDTO
>
findAll
()
{
List
<
Menu
>
allMenus
=
menuRepository
.
findAll
();
return
buildTree
(
allMenus
);
}
public
List
<
MenuDTO
>
findVisible
()
{
List
<
Menu
>
allMenus
=
menuRepository
.
findAllVisible
();
return
buildTree
(
allMenus
);
}
public
List
<
MenuDTO
>
findByParentId
(
Long
parentId
)
{
List
<
Menu
>
menus
=
menuRepository
.
findByParentIdOrderBySortOrderAsc
(
parentId
);
return
menus
.
stream
()
.
map
(
this
::
toDTO
)
.
collect
(
Collectors
.
toList
());
}
public
List
<
MenuDTO
>
findByRoleId
(
Long
roleId
)
{
List
<
Long
>
menuIds
=
roleMenuRepository
.
findByRoleId
(
roleId
).
stream
()
.
map
(
RoleMenu:
:
getMenuId
)
.
collect
(
Collectors
.
toList
());
if
(
menuIds
.
isEmpty
())
{
return
new
ArrayList
<>();
}
List
<
Menu
>
menus
=
menuRepository
.
findAllById
(
menuIds
);
return
buildTree
(
menus
);
}
@Transactional
public
void
initDefaultMenus
()
{
List
<
Menu
>
existingMenus
=
menuRepository
.
findAll
();
if
(!
existingMenus
.
isEmpty
())
{
log
.
info
(
"Menus already exist, skipping initialization"
);
return
;
}
log
.
info
(
"Initializing default menus"
);
// Create parent menus first
List
<
Menu
>
parentMenus
=
List
.
of
(
Menu
.
builder
().
name
(
"首页"
).
path
(
"/dashboard"
).
icon
(
"Odometer"
).
component
(
"Dashboard"
).
parentId
(
null
).
sortOrder
(
1
).
visible
(
true
).
enabled
(
true
).
build
(),
Menu
.
builder
().
name
(
"处罚列表"
).
path
(
"/penalties"
).
icon
(
"Document"
).
component
(
"PenaltyList"
).
parentId
(
null
).
sortOrder
(
2
).
visible
(
true
).
enabled
(
true
).
build
(),
Menu
.
builder
().
name
(
"爬取管理"
).
path
(
"/crawl"
).
icon
(
"Monitor"
).
component
(
"CrawlManage"
).
parentId
(
null
).
sortOrder
(
3
).
visible
(
true
).
enabled
(
true
).
build
(),
Menu
.
builder
().
name
(
"数据统计"
).
path
(
"/statistics"
).
icon
(
"DataAnalysis"
).
component
(
"Statistics"
).
parentId
(
null
).
sortOrder
(
4
).
visible
(
true
).
enabled
(
true
).
build
()
);
List
<
Menu
>
savedParents
=
menuRepository
.
saveAll
(
parentMenus
);
// Create system management parent
Menu
systemMenu
=
menuRepository
.
save
(
Menu
.
builder
()
.
name
(
"系统管理"
).
path
(
""
).
icon
(
"Setting"
).
component
(
null
).
parentId
(
null
).
sortOrder
(
5
).
visible
(
true
).
enabled
(
true
).
build
());
// Create child menus under system management
Long
systemId
=
systemMenu
.
getId
();
List
<
Menu
>
childMenus
=
List
.
of
(
Menu
.
builder
().
name
(
"用户管理"
).
path
(
"/users"
).
icon
(
"User"
).
component
(
"UserManage"
).
parentId
(
systemId
).
sortOrder
(
1
).
visible
(
true
).
enabled
(
true
).
build
(),
Menu
.
builder
().
name
(
"角色管理"
).
path
(
"/roles"
).
icon
(
"UserFilled"
).
component
(
"RoleManage"
).
parentId
(
systemId
).
sortOrder
(
2
).
visible
(
true
).
enabled
(
true
).
build
(),
Menu
.
builder
().
name
(
"菜单管理"
).
path
(
"/menus"
).
icon
(
"Menu"
).
component
(
"MenuManage"
).
parentId
(
systemId
).
sortOrder
(
3
).
visible
(
true
).
enabled
(
true
).
build
(),
Menu
.
builder
().
name
(
"权限管理"
).
path
(
"/permissions"
).
icon
(
"Key"
).
component
(
"PermissionManage"
).
parentId
(
systemId
).
sortOrder
(
4
).
visible
(
true
).
enabled
(
true
).
build
(),
Menu
.
builder
().
name
(
"报告配置"
).
path
(
"/report-config"
).
icon
(
"Document"
).
component
(
"ReportConfig"
).
parentId
(
systemId
).
sortOrder
(
5
).
visible
(
true
).
enabled
(
true
).
build
(),
Menu
.
builder
().
name
(
"角色菜单"
).
path
(
"/role-menu"
).
icon
(
"Connection"
).
component
(
"RoleMenuManage"
).
parentId
(
systemId
).
sortOrder
(
6
).
visible
(
true
).
enabled
(
true
).
build
(),
Menu
.
builder
().
name
(
"角色用户"
).
path
(
"/role-user"
).
icon
(
"UserFilled"
).
component
(
"RoleUserManage"
).
parentId
(
systemId
).
sortOrder
(
7
).
visible
(
true
).
enabled
(
true
).
build
()
);
menuRepository
.
saveAll
(
childMenus
);
log
.
info
(
"Default menus initialized"
);
}
public
List
<
MenuDTO
>
findByRoleCode
(
String
roleCode
)
{
if
(
roleCode
==
null
)
{
roleCode
=
"ADMIN"
;
}
List
<
Menu
>
allMenus
=
menuRepository
.
findAllVisible
();
if
(
allMenus
.
isEmpty
())
{
log
.
warn
(
"No menus found in database"
);
return
new
ArrayList
<>();
}
if
(
"ADMIN"
.
equals
(
roleCode
))
{
return
buildTree
(
allMenus
);
}
return
buildTree
(
allMenus
.
stream
()
.
filter
(
m
->
m
.
getVisible
()
!=
null
&&
m
.
getVisible
())
.
collect
(
Collectors
.
toList
()));
}
public
MenuDTO
findById
(
Long
id
)
{
Menu
menu
=
menuRepository
.
findById
(
id
)
.
orElseThrow
(()
->
new
RuntimeException
(
"菜单不存在"
));
return
toDTO
(
menu
);
}
@Transactional
public
MenuDTO
createMenu
(
CreateMenuRequest
request
)
{
if
(
menuRepository
.
existsByName
(
request
.
getName
()))
{
throw
new
RuntimeException
(
"菜单名称已存在"
);
}
Menu
menu
=
Menu
.
builder
()
.
name
(
request
.
getName
())
.
path
(
request
.
getPath
())
.
icon
(
request
.
getIcon
())
.
component
(
request
.
getComponent
())
.
parentId
(
request
.
getParentId
())
.
sortOrder
(
request
.
getSortOrder
()
!=
null
?
request
.
getSortOrder
()
:
0
)
.
visible
(
request
.
getVisible
()
!=
null
?
request
.
getVisible
()
:
true
)
.
enabled
(
request
.
getEnabled
()
!=
null
?
request
.
getEnabled
()
:
true
)
.
build
();
Menu
saved
=
menuRepository
.
save
(
menu
);
log
.
info
(
"创建菜单: {}"
,
saved
.
getName
());
return
toDTO
(
saved
);
}
@Transactional
public
MenuDTO
updateMenu
(
Long
id
,
UpdateMenuRequest
request
)
{
Menu
menu
=
menuRepository
.
findById
(
id
)
.
orElseThrow
(()
->
new
RuntimeException
(
"菜单不存在"
));
if
(
request
.
getName
()
!=
null
)
{
menu
.
setName
(
request
.
getName
());
}
if
(
request
.
getPath
()
!=
null
)
{
menu
.
setPath
(
request
.
getPath
());
}
if
(
request
.
getIcon
()
!=
null
)
{
menu
.
setIcon
(
request
.
getIcon
());
}
if
(
request
.
getComponent
()
!=
null
)
{
menu
.
setComponent
(
request
.
getComponent
());
}
if
(
request
.
getParentId
()
!=
null
)
{
menu
.
setParentId
(
request
.
getParentId
());
}
if
(
request
.
getSortOrder
()
!=
null
)
{
menu
.
setSortOrder
(
request
.
getSortOrder
());
}
if
(
request
.
getVisible
()
!=
null
)
{
menu
.
setVisible
(
request
.
getVisible
());
}
if
(
request
.
getEnabled
()
!=
null
)
{
menu
.
setEnabled
(
request
.
getEnabled
());
}
Menu
saved
=
menuRepository
.
save
(
menu
);
log
.
info
(
"更新菜单: {}"
,
saved
.
getName
());
return
toDTO
(
saved
);
}
@Transactional
public
void
deleteMenu
(
Long
id
)
{
Menu
menu
=
menuRepository
.
findById
(
id
)
.
orElseThrow
(()
->
new
RuntimeException
(
"菜单不存在"
));
if
(!
menuRepository
.
findByParentIdOrderBySortOrderAsc
(
id
).
isEmpty
())
{
throw
new
RuntimeException
(
"请先删除子菜单"
);
}
menuRepository
.
delete
(
menu
);
log
.
info
(
"删除菜单: {}"
,
menu
.
getName
());
}
private
List
<
MenuDTO
>
buildTree
(
List
<
Menu
>
menus
)
{
if
(
menus
==
null
||
menus
.
isEmpty
())
{
log
.
warn
(
"buildTree received empty menu list"
);
return
new
ArrayList
<>();
}
log
.
debug
(
"Building menu tree from {} menus"
,
menus
.
size
());
Map
<
Long
,
List
<
Menu
>>
parentMap
=
menus
.
stream
()
.
collect
(
Collectors
.
groupingBy
(
m
->
{
Long
pid
=
m
.
getParentId
();
return
pid
==
null
?
0L
:
pid
;
}));
log
.
debug
(
"Parent map keys: {}"
,
parentMap
.
keySet
());
List
<
MenuDTO
>
roots
=
menus
.
stream
()
.
filter
(
m
->
m
.
getParentId
()
==
null
||
m
.
getParentId
()
==
0
)
.
sorted
(
Comparator
.
comparingInt
(
Menu:
:
getSortOrder
))
.
map
(
m
->
buildTreeNode
(
m
,
parentMap
))
.
collect
(
Collectors
.
toList
());
log
.
debug
(
"Built {} root menus"
,
roots
.
size
());
return
roots
;
}
private
MenuDTO
buildTreeNode
(
Menu
menu
,
Map
<
Long
,
List
<
Menu
>>
parentMap
)
{
MenuDTO
dto
=
toDTO
(
menu
);
List
<
Menu
>
children
=
parentMap
.
get
(
menu
.
getId
());
if
(
children
!=
null
&&
!
children
.
isEmpty
())
{
dto
.
setChildren
(
children
.
stream
()
.
sorted
(
Comparator
.
comparingInt
(
Menu:
:
getSortOrder
))
.
map
(
m
->
buildTreeNode
(
m
,
parentMap
))
.
collect
(
Collectors
.
toList
()));
}
return
dto
;
}
private
MenuDTO
toDTO
(
Menu
menu
)
{
return
MenuDTO
.
builder
()
.
id
(
menu
.
getId
())
.
name
(
menu
.
getName
())
.
path
(
menu
.
getPath
())
.
icon
(
menu
.
getIcon
())
.
component
(
menu
.
getComponent
())
.
parentId
(
menu
.
getParentId
())
.
sortOrder
(
menu
.
getSortOrder
())
.
visible
(
menu
.
getVisible
())
.
enabled
(
menu
.
getEnabled
())
.
createTime
(
menu
.
getCreateTime
())
.
updateTime
(
menu
.
getUpdateTime
())
.
build
();
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/service/PermissionService.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
service
;
import
com.fintech.penalty.dto.*
;
import
com.fintech.penalty.entity.Permission
;
import
com.fintech.penalty.repository.PermissionRepository
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.data.domain.Page
;
import
org.springframework.data.domain.PageRequest
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
java.util.List
;
import
java.util.stream.Collectors
;
@Service
@RequiredArgsConstructor
@Slf4j
public
class
PermissionService
{
private
final
PermissionRepository
permissionRepository
;
public
PageResponse
<
PermissionDTO
>
findAll
(
int
page
,
int
size
)
{
Page
<
Permission
>
pageResult
=
permissionRepository
.
findAll
(
PageRequest
.
of
(
page
,
size
));
List
<
PermissionDTO
>
content
=
pageResult
.
getContent
().
stream
()
.
map
(
this
::
toDTO
)
.
collect
(
Collectors
.
toList
());
return
PageResponse
.<
PermissionDTO
>
builder
()
.
content
(
content
)
.
totalElements
(
pageResult
.
getTotalElements
())
.
totalPages
(
pageResult
.
getTotalPages
())
.
pageNumber
(
page
)
.
pageSize
(
size
)
.
hasNext
(
pageResult
.
hasNext
())
.
hasPrevious
(
pageResult
.
hasPrevious
())
.
build
();
}
public
List
<
PermissionDTO
>
findAllSimple
()
{
return
permissionRepository
.
findAll
().
stream
()
.
map
(
this
::
toDTO
)
.
collect
(
Collectors
.
toList
());
}
public
PermissionDTO
findById
(
Long
id
)
{
Permission
permission
=
permissionRepository
.
findById
(
id
)
.
orElseThrow
(()
->
new
RuntimeException
(
"权限不存在"
));
return
toDTO
(
permission
);
}
@Transactional
public
PermissionDTO
createPermission
(
CreatePermissionRequest
request
)
{
if
(
permissionRepository
.
existsByCode
(
request
.
getCode
()))
{
throw
new
RuntimeException
(
"权限编码已存在"
);
}
Permission
permission
=
Permission
.
builder
()
.
code
(
request
.
getCode
())
.
name
(
request
.
getName
())
.
type
(
request
.
getType
())
.
resource
(
request
.
getResource
())
.
description
(
request
.
getDescription
())
.
build
();
Permission
saved
=
permissionRepository
.
save
(
permission
);
log
.
info
(
"创建权限: {}"
,
saved
.
getName
());
return
toDTO
(
saved
);
}
@Transactional
public
PermissionDTO
updatePermission
(
Long
id
,
UpdatePermissionRequest
request
)
{
Permission
permission
=
permissionRepository
.
findById
(
id
)
.
orElseThrow
(()
->
new
RuntimeException
(
"权限不存在"
));
if
(
request
.
getName
()
!=
null
)
{
permission
.
setName
(
request
.
getName
());
}
if
(
request
.
getType
()
!=
null
)
{
permission
.
setType
(
request
.
getType
());
}
if
(
request
.
getResource
()
!=
null
)
{
permission
.
setResource
(
request
.
getResource
());
}
if
(
request
.
getDescription
()
!=
null
)
{
permission
.
setDescription
(
request
.
getDescription
());
}
Permission
saved
=
permissionRepository
.
save
(
permission
);
log
.
info
(
"更新权限: {}"
,
saved
.
getName
());
return
toDTO
(
saved
);
}
@Transactional
public
void
deletePermission
(
Long
id
)
{
Permission
permission
=
permissionRepository
.
findById
(
id
)
.
orElseThrow
(()
->
new
RuntimeException
(
"权限不存在"
));
permissionRepository
.
delete
(
permission
);
log
.
info
(
"删除权限: {}"
,
permission
.
getName
());
}
private
PermissionDTO
toDTO
(
Permission
permission
)
{
return
PermissionDTO
.
builder
()
.
id
(
permission
.
getId
())
.
code
(
permission
.
getCode
())
.
name
(
permission
.
getName
())
.
type
(
permission
.
getType
())
.
resource
(
permission
.
getResource
())
.
description
(
permission
.
getDescription
())
.
createTime
(
permission
.
getCreateTime
())
.
updateTime
(
permission
.
getUpdateTime
())
.
build
();
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/service/ReportTemplateService.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
service
;
import
com.fintech.penalty.dto.*
;
import
com.fintech.penalty.entity.ReportTemplate
;
import
com.fintech.penalty.repository.ReportTemplateRepository
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.data.domain.Page
;
import
org.springframework.data.domain.PageRequest
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
java.util.List
;
import
java.util.stream.Collectors
;
@Service
@RequiredArgsConstructor
@Slf4j
public
class
ReportTemplateService
{
private
final
ReportTemplateRepository
templateRepository
;
public
PageResponse
<
ReportTemplateDTO
>
findAll
(
int
page
,
int
size
)
{
Page
<
ReportTemplate
>
pageResult
=
templateRepository
.
findAll
(
PageRequest
.
of
(
page
,
size
));
List
<
ReportTemplateDTO
>
content
=
pageResult
.
getContent
().
stream
()
.
map
(
this
::
toDTO
)
.
collect
(
Collectors
.
toList
());
return
PageResponse
.<
ReportTemplateDTO
>
builder
()
.
content
(
content
)
.
totalElements
(
pageResult
.
getTotalElements
())
.
totalPages
(
pageResult
.
getTotalPages
())
.
pageNumber
(
page
)
.
pageSize
(
size
)
.
hasNext
(
pageResult
.
hasNext
())
.
hasPrevious
(
pageResult
.
hasPrevious
())
.
build
();
}
public
List
<
ReportTemplateDTO
>
findAllEnabled
()
{
return
templateRepository
.
findByEnabledTrue
().
stream
()
.
map
(
this
::
toDTO
)
.
collect
(
Collectors
.
toList
());
}
public
ReportTemplateDTO
findById
(
Long
id
)
{
return
templateRepository
.
findById
(
id
)
.
map
(
this
::
toDTO
)
.
orElse
(
null
);
}
public
ReportTemplateDTO
findDefault
()
{
return
templateRepository
.
findByIsDefaultTrueAndEnabledTrue
()
.
map
(
this
::
toDTO
)
.
orElse
(
null
);
}
@Transactional
public
ReportTemplateDTO
create
(
CreateReportTemplateRequest
request
)
{
if
(
Boolean
.
TRUE
.
equals
(
request
.
getIsDefault
()))
{
clearDefaultTemplates
();
}
ReportTemplate
template
=
ReportTemplate
.
builder
()
.
name
(
request
.
getName
())
.
description
(
request
.
getDescription
())
.
content
(
request
.
getContent
())
.
isDefault
(
request
.
getIsDefault
()
!=
null
?
request
.
getIsDefault
()
:
false
)
.
enabled
(
request
.
getEnabled
()
!=
null
?
request
.
getEnabled
()
:
true
)
.
build
();
ReportTemplate
saved
=
templateRepository
.
save
(
template
);
log
.
info
(
"创建报告模板: {}"
,
saved
.
getName
());
return
toDTO
(
saved
);
}
@Transactional
public
ReportTemplateDTO
update
(
Long
id
,
UpdateReportTemplateRequest
request
)
{
ReportTemplate
template
=
templateRepository
.
findById
(
id
)
.
orElseThrow
(()
->
new
RuntimeException
(
"模板不存在"
));
if
(
Boolean
.
TRUE
.
equals
(
request
.
getIsDefault
())
&&
!
Boolean
.
TRUE
.
equals
(
template
.
getIsDefault
()))
{
clearDefaultTemplates
();
}
if
(
request
.
getName
()
!=
null
)
{
template
.
setName
(
request
.
getName
());
}
if
(
request
.
getDescription
()
!=
null
)
{
template
.
setDescription
(
request
.
getDescription
());
}
if
(
request
.
getContent
()
!=
null
)
{
template
.
setContent
(
request
.
getContent
());
}
if
(
request
.
getIsDefault
()
!=
null
)
{
template
.
setIsDefault
(
request
.
getIsDefault
());
}
if
(
request
.
getEnabled
()
!=
null
)
{
template
.
setEnabled
(
request
.
getEnabled
());
}
ReportTemplate
saved
=
templateRepository
.
save
(
template
);
log
.
info
(
"更新报告模板: {}"
,
saved
.
getName
());
return
toDTO
(
saved
);
}
@Transactional
public
void
delete
(
Long
id
)
{
ReportTemplate
template
=
templateRepository
.
findById
(
id
)
.
orElseThrow
(()
->
new
RuntimeException
(
"模板不存在"
));
templateRepository
.
delete
(
template
);
log
.
info
(
"删除报告模板: {}"
,
template
.
getName
());
}
private
void
clearDefaultTemplates
()
{
templateRepository
.
findByIsDefaultTrue
().
ifPresent
(
t
->
{
t
.
setIsDefault
(
false
);
templateRepository
.
save
(
t
);
});
}
private
ReportTemplateDTO
toDTO
(
ReportTemplate
template
)
{
return
ReportTemplateDTO
.
builder
()
.
id
(
template
.
getId
())
.
name
(
template
.
getName
())
.
description
(
template
.
getDescription
())
.
content
(
template
.
getContent
())
.
isDefault
(
template
.
getIsDefault
())
.
enabled
(
template
.
getEnabled
())
.
createTime
(
template
.
getCreateTime
())
.
updateTime
(
template
.
getUpdateTime
())
.
build
();
}
}
\ No newline at end of file
financial-penalty-monitor/backend/src/main/java/com/fintech/penalty/service/RoleService.java
0 → 100644
浏览文件 @
0c4531a3
package
com
.
fintech
.
penalty
.
service
;
import
com.fintech.penalty.dto.*
;
import
com.fintech.penalty.entity.Permission
;
import
com.fintech.penalty.entity.Role
;
import
com.fintech.penalty.entity.RoleMenu
;
import
com.fintech.penalty.entity.User
;
import
com.fintech.penalty.repository.MenuRepository
;
import
com.fintech.penalty.repository.PermissionRepository
;
import
com.fintech.penalty.repository.RoleMenuRepository
;
import
com.fintech.penalty.repository.RoleRepository
;
import
com.fintech.penalty.repository.UserRepository
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.data.domain.Page
;
import
org.springframework.data.domain.PageRequest
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.stream.Collectors
;
@Service
@RequiredArgsConstructor
@Slf4j
public
class
RoleService
{
private
final
RoleRepository
roleRepository
;
private
final
PermissionRepository
permissionRepository
;
private
final
RoleMenuRepository
roleMenuRepository
;
private
final
MenuRepository
menuRepository
;
private
final
UserRepository
userRepository
;
public
PageResponse
<
RoleDTO
>
findAll
(
int
page
,
int
size
)
{
Page
<
Role
>
pageResult
=
roleRepository
.
findAll
(
PageRequest
.
of
(
page
,
size
));
List
<
RoleDTO
>
content
=
pageResult
.
getContent
().
stream
()
.
map
(
this
::
toDTO
)
.
collect
(
Collectors
.
toList
());
return
PageResponse
.<
RoleDTO
>
builder
()
.
content
(
content
)
.
totalElements
(
pageResult
.
getTotalElements
())
.
totalPages
(
pageResult
.
getTotalPages
())
.
pageNumber
(
page
)
.
pageSize
(
size
)
.
hasNext
(
pageResult
.
hasNext
())
.
hasPrevious
(
pageResult
.
hasPrevious
())
.
build
();
}
public
List
<
RoleDTO
>
findAllSimple
()
{
return
roleRepository
.
findAll
().
stream
()
.
map
(
this
::
toDTO
)
.
collect
(
Collectors
.
toList
());
}
public
RoleDTO
findById
(
Long
id
)
{
Role
role
=
roleRepository
.
findById
(
id
)
.
orElseThrow
(()
->
new
RuntimeException
(
"角色不存在"
));
return
toDTO
(
role
);
}
@Transactional
public
RoleDTO
createRole
(
CreateRoleRequest
request
)
{
if
(
roleRepository
.
existsByCode
(
request
.
getCode
()))
{
throw
new
RuntimeException
(
"角色编码已存在"
);
}
Role
role
=
Role
.
builder
()
.
code
(
request
.
getCode
())
.
name
(
request
.
getName
())
.
description
(
request
.
getDescription
())
.
build
();
Role
saved
=
roleRepository
.
save
(
role
);
if
(
request
.
getPermissions
()
!=
null
&&
!
request
.
getPermissions
().
isEmpty
())
{
List
<
Permission
>
permissions
=
permissionRepository
.
findByCodeIn
(
request
.
getPermissions
());
List
<
RoleMenu
>
roleMenus
=
permissions
.
stream
()
.
map
(
p
->
RoleMenu
.
builder
().
roleId
(
saved
.
getId
()).
menuId
(
Long
.
parseLong
(
p
.
getCode
())).
build
())
.
collect
(
Collectors
.
toList
());
roleMenuRepository
.
saveAll
(
roleMenus
);
}
log
.
info
(
"创建角色: {}"
,
saved
.
getName
());
return
toDTO
(
saved
);
}
@Transactional
public
RoleDTO
updateRole
(
Long
id
,
UpdateRoleRequest
request
)
{
Role
role
=
roleRepository
.
findById
(
id
)
.
orElseThrow
(()
->
new
RuntimeException
(
"角色不存在"
));
if
(
request
.
getName
()
!=
null
)
{
role
.
setName
(
request
.
getName
());
}
if
(
request
.
getDescription
()
!=
null
)
{
role
.
setDescription
(
request
.
getDescription
());
}
Role
saved
=
roleRepository
.
save
(
role
);
if
(
request
.
getPermissions
()
!=
null
)
{
roleMenuRepository
.
deleteByRoleId
(
id
);
List
<
Permission
>
permissions
=
permissionRepository
.
findByCodeIn
(
request
.
getPermissions
());
List
<
RoleMenu
>
roleMenus
=
permissions
.
stream
()
.
map
(
p
->
RoleMenu
.
builder
().
roleId
(
saved
.
getId
()).
menuId
(
Long
.
parseLong
(
p
.
getCode
())).
build
())
.
collect
(
Collectors
.
toList
());
roleMenuRepository
.
saveAll
(
roleMenus
);
}
log
.
info
(
"更新角色: {}"
,
saved
.
getName
());
return
toDTO
(
saved
);
}
@Transactional
public
void
deleteRole
(
Long
id
)
{
Role
role
=
roleRepository
.
findById
(
id
)
.
orElseThrow
(()
->
new
RuntimeException
(
"角色不存在"
));
if
(
"ADMIN"
.
equals
(
role
.
getCode
())
||
"USER"
.
equals
(
role
.
getCode
())
||
"VIEWER"
.
equals
(
role
.
getCode
()))
{
throw
new
RuntimeException
(
"系统内置角色不能删除"
);
}
roleMenuRepository
.
deleteByRoleId
(
id
);
roleRepository
.
delete
(
role
);
log
.
info
(
"删除角色: {}"
,
role
.
getName
());
}
public
List
<
Long
>
getRoleMenuIds
(
Long
roleId
)
{
return
roleMenuRepository
.
findByRoleId
(
roleId
).
stream
()
.
map
(
RoleMenu:
:
getMenuId
)
.
collect
(
Collectors
.
toList
());
}
@Transactional
public
void
saveRoleMenus
(
Long
roleId
,
List
<
Long
>
menuIds
)
{
roleMenuRepository
.
deleteByRoleId
(
roleId
);
if
(
menuIds
!=
null
&&
!
menuIds
.
isEmpty
())
{
List
<
RoleMenu
>
roleMenus
=
menuIds
.
stream
()
.
map
(
menuId
->
RoleMenu
.
builder
().
roleId
(
roleId
).
menuId
(
menuId
).
build
())
.
collect
(
Collectors
.
toList
());
roleMenuRepository
.
saveAll
(
roleMenus
);
}
log
.
info
(
"更新角色 {} 的菜单权限"
,
roleId
);
}
public
List
<
Long
>
getRoleUserIds
(
Long
roleId
)
{
Role
role
=
roleRepository
.
findById
(
roleId
)
.
orElseThrow
(()
->
new
RuntimeException
(
"角色不存在"
));
String
roleCode
=
role
.
getCode
();
return
userRepository
.
findAll
().
stream
()
.
filter
(
u
->
roleCode
.
equals
(
u
.
getRoleCode
()))
.
map
(
User:
:
getId
)
.
collect
(
Collectors
.
toList
());
}
@Transactional
public
void
assignUserToRole
(
Long
userId
,
String
roleCode
)
{
User
user
=
userRepository
.
findById
(
userId
)
.
orElseThrow
(()
->
new
RuntimeException
(
"用户不存在"
));
Role
role
=
roleRepository
.
findByCode
(
roleCode
)
.
orElseThrow
(()
->
new
RuntimeException
(
"角色不存在"
));
user
.
setRoleCode
(
roleCode
);
user
.
setRole
(
role
);
userRepository
.
save
(
user
);
log
.
info
(
"用户 {} 分配角色 {}"
,
user
.
getUsername
(),
roleCode
);
}
@Transactional
public
void
removeUserFromRole
(
Long
userId
)
{
User
user
=
userRepository
.
findById
(
userId
)
.
orElseThrow
(()
->
new
RuntimeException
(
"用户不存在"
));
user
.
setRoleCode
(
null
);
user
.
setRole
(
null
);
userRepository
.
save
(
user
);
log
.
info
(
"用户 {} 移除角色"
,
user
.
getUsername
());
}
private
RoleDTO
toDTO
(
Role
role
)
{
List
<
String
>
permissions
=
roleMenuRepository
.
findByRoleId
(
role
.
getId
()).
stream
()
.
map
(
rm
->
{
return
menuRepository
.
findById
(
rm
.
getMenuId
())
.
map
(
m
->
m
.
getPath
())
.
orElse
(
null
);
})
.
filter
(
p
->
p
!=
null
)
.
collect
(
Collectors
.
toList
());
return
RoleDTO
.
builder
()
.
id
(
role
.
getId
())
.
code
(
role
.
getCode
())
.
name
(
role
.
getName
())
.
description
(
role
.
getDescription
())
.
permissions
(
permissions
)
.
createTime
(
role
.
getCreateTime
())
.
updateTime
(
role
.
getUpdateTime
())
.
build
();
}
}
\ No newline at end of file
financial-penalty-monitor/frontend/src/views/MenuManage.vue
0 → 100644
浏览文件 @
0c4531a3
<
template
>
<div
class=
"menu-manage"
>
<el-card>
<template
#
header
>
<div
class=
"card-header"
>
<span>
菜单管理
</span>
<el-button
type=
"primary"
:icon=
"Plus"
@
click=
"handleAdd(null)"
>
添加菜单
</el-button>
</div>
</
template
>
<el-table
:data=
"tableData"
v-loading=
"loading"
row-key=
"id"
:tree-props=
"{ children: 'children' }"
stripe
>
<el-table-column
prop=
"name"
label=
"菜单名称"
width=
"200"
/>
<el-table-column
prop=
"path"
label=
"路径"
/>
<el-table-column
prop=
"icon"
label=
"图标"
width=
"100"
>
<
template
#
default=
"{ row }"
>
<el-icon
v-if=
"row.icon"
><component
:is=
"row.icon"
/></el-icon>
</
template
>
</el-table-column>
<el-table-column
prop=
"sortOrder"
label=
"排序"
width=
"80"
/>
<el-table-column
prop=
"visible"
label=
"可见"
width=
"80"
>
<
template
#
default=
"{ row }"
>
<el-tag
:type=
"row.visible ? 'success' : 'info'"
>
{{
row
.
visible
?
'是'
:
'否'
}}
</el-tag>
</
template
>
</el-table-column>
<el-table-column
prop=
"enabled"
label=
"启用"
width=
"80"
>
<
template
#
default=
"{ row }"
>
<el-tag
:type=
"row.enabled ? 'success' : 'danger'"
>
{{
row
.
enabled
?
'是'
:
'否'
}}
</el-tag>
</
template
>
</el-table-column>
<el-table-column
label=
"操作"
width=
"300"
fixed=
"right"
>
<
template
#
default=
"{ row }"
>
<el-button
type=
"primary"
link
:icon=
"Plus"
@
click=
"handleAdd(row)"
>
添加子菜单
</el-button>
<el-button
type=
"primary"
link
:icon=
"Edit"
@
click=
"handleEdit(row)"
>
编辑
</el-button>
<el-button
type=
"danger"
link
:icon=
"Delete"
@
click=
"handleDelete(row)"
>
删除
</el-button>
</
template
>
</el-table-column>
</el-table>
</el-card>
<el-dialog
v-model=
"dialogVisible"
:title=
"isEdit ? '编辑菜单' : '添加菜单'"
width=
"500px"
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
label-width=
"100px"
>
<el-form-item
label=
"菜单名称"
prop=
"name"
>
<el-input
v-model=
"form.name"
placeholder=
"请输入菜单名称"
/>
</el-form-item>
<el-form-item
label=
"路径"
prop=
"path"
>
<el-input
v-model=
"form.path"
placeholder=
"请输入路径"
/>
</el-form-item>
<el-form-item
label=
"图标"
prop=
"icon"
>
<el-input
v-model=
"form.icon"
placeholder=
"请输入图标名称"
/>
</el-form-item>
<el-form-item
label=
"组件"
prop=
"component"
>
<el-input
v-model=
"form.component"
placeholder=
"请输入组件名称"
/>
</el-form-item>
<el-form-item
label=
"排序"
prop=
"sortOrder"
>
<el-input-number
v-model=
"form.sortOrder"
:min=
"0"
/>
</el-form-item>
<el-form-item
label=
"可见"
prop=
"visible"
>
<el-switch
v-model=
"form.visible"
/>
</el-form-item>
<el-form-item
label=
"启用"
prop=
"enabled"
>
<el-switch
v-model=
"form.enabled"
/>
</el-form-item>
</el-form>
<
template
#
footer
>
<el-button
@
click=
"dialogVisible = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleSubmit"
:loading=
"submitLoading"
>
确定
</el-button>
</
template
>
</el-dialog>
</div>
</template>
<
script
setup
>
import
{
ref
,
reactive
,
onMounted
}
from
'vue'
import
{
ElMessage
,
ElMessageBox
}
from
'element-plus'
import
{
Plus
,
Edit
,
Delete
}
from
'@element-plus/icons-vue'
import
api
from
'../api'
const
tableData
=
ref
([])
const
loading
=
ref
(
false
)
const
dialogVisible
=
ref
(
false
)
const
isEdit
=
ref
(
false
)
const
submitLoading
=
ref
(
false
)
const
formRef
=
ref
(
null
)
const
form
=
reactive
({
id
:
null
,
name
:
''
,
path
:
''
,
icon
:
''
,
component
:
''
,
parentId
:
null
,
sortOrder
:
0
,
visible
:
true
,
enabled
:
true
})
const
rules
=
{
name
:
[
{
required
:
true
,
message
:
'请输入菜单名称'
,
trigger
:
'blur'
},
{
max
:
100
,
message
:
'菜单名称长度不能超过100个字符'
,
trigger
:
'blur'
}
]
}
const
fetchData
=
async
()
=>
{
loading
.
value
=
true
try
{
const
res
=
await
api
.
getMenus
()
tableData
.
value
=
res
.
data
}
catch
(
error
)
{
console
.
error
(
'获取菜单列表失败:'
,
error
)
}
finally
{
loading
.
value
=
false
}
}
const
handleAdd
=
(
parent
)
=>
{
isEdit
.
value
=
false
Object
.
assign
(
form
,
{
id
:
null
,
name
:
''
,
path
:
''
,
icon
:
''
,
parentId
:
parent
?
parent
.
id
:
null
,
sortOrder
:
0
,
visible
:
true
,
enabled
:
true
,
component
:
''
})
dialogVisible
.
value
=
true
}
const
handleEdit
=
(
row
)
=>
{
isEdit
.
value
=
true
Object
.
assign
(
form
,
{
id
:
row
.
id
,
name
:
row
.
name
,
path
:
row
.
path
,
icon
:
row
.
icon
,
component
:
row
.
component
,
parentId
:
row
.
parentId
,
sortOrder
:
row
.
sortOrder
,
visible
:
row
.
visible
,
enabled
:
row
.
enabled
})
dialogVisible
.
value
=
true
}
const
handleSubmit
=
async
()
=>
{
if
(
!
formRef
.
value
)
return
await
formRef
.
value
.
validate
(
async
(
valid
)
=>
{
if
(
!
valid
)
return
submitLoading
.
value
=
true
try
{
if
(
isEdit
.
value
)
{
await
api
.
updateMenu
(
form
.
id
,
form
)
ElMessage
.
success
(
'更新成功'
)
}
else
{
await
api
.
createMenu
(
form
)
ElMessage
.
success
(
'创建成功'
)
}
dialogVisible
.
value
=
false
fetchData
()
}
catch
(
error
)
{
}
finally
{
submitLoading
.
value
=
false
}
})
}
const
handleDelete
=
async
(
row
)
=>
{
try
{
await
ElMessageBox
.
confirm
(
`确定要删除菜单
${
row
.
name
}
吗?`
,
'警告'
,
{
type
:
'warning'
})
await
api
.
deleteMenu
(
row
.
id
)
ElMessage
.
success
(
'删除成功'
)
fetchData
()
}
catch
(
error
)
{
if
(
error
!==
'cancel'
)
{
console
.
error
(
'删除失败:'
,
error
)
}
}
}
onMounted
(()
=>
{
fetchData
()
})
</
script
>
<
style
scoped
lang=
"scss"
>
.menu-manage
{
padding
:
20px
;
}
.card-header
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
}
</
style
>
\ No newline at end of file
financial-penalty-monitor/frontend/src/views/PermissionManage.vue
0 → 100644
浏览文件 @
0c4531a3
<
template
>
<div
class=
"permission-manage"
>
<el-card>
<template
#
header
>
<div
class=
"card-header"
>
<span>
权限管理
</span>
<el-button
type=
"primary"
:icon=
"Plus"
@
click=
"handleAdd"
>
添加权限
</el-button>
</div>
</
template
>
<el-table
:data=
"tableData"
v-loading=
"loading"
stripe
>
<el-table-column
prop=
"id"
label=
"ID"
width=
"80"
/>
<el-table-column
prop=
"code"
label=
"权限编码"
/>
<el-table-column
prop=
"name"
label=
"权限名称"
/>
<el-table-column
prop=
"type"
label=
"类型"
width=
"100"
>
<
template
#
default=
"{ row }"
>
<el-tag>
{{
row
.
type
||
'-'
}}
</el-tag>
</
template
>
</el-table-column>
<el-table-column
prop=
"resource"
label=
"资源"
/>
<el-table-column
prop=
"description"
label=
"描述"
/>
<el-table-column
label=
"操作"
width=
"150"
fixed=
"right"
>
<
template
#
default=
"{ row }"
>
<el-button
type=
"primary"
link
:icon=
"Edit"
@
click=
"handleEdit(row)"
>
编辑
</el-button>
<el-button
type=
"danger"
link
:icon=
"Delete"
@
click=
"handleDelete(row)"
>
删除
</el-button>
</
template
>
</el-table-column>
</el-table>
<div
class=
"pagination"
>
<el-pagination
v-model:current-page=
"currentPage"
v-model:page-size=
"pageSize"
:page-sizes=
"[10, 20, 50, 100]"
:total=
"total"
layout=
"total, sizes, prev, pager, next, jumper"
@
size-change=
"handleSizeChange"
@
current-change=
"handleCurrentChange"
/>
</div>
</el-card>
<el-dialog
v-model=
"dialogVisible"
:title=
"isEdit ? '编辑权限' : '添加权限'"
width=
"500px"
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
label-width=
"100px"
>
<el-form-item
label=
"权限编码"
prop=
"code"
v-if=
"!isEdit"
>
<el-input
v-model=
"form.code"
placeholder=
"请输入权限编码"
/>
</el-form-item>
<el-form-item
label=
"权限名称"
prop=
"name"
>
<el-input
v-model=
"form.name"
placeholder=
"请输入权限名称"
/>
</el-form-item>
<el-form-item
label=
"类型"
prop=
"type"
>
<el-select
v-model=
"form.type"
placeholder=
"请选择类型"
style=
"width: 100%"
>
<el-option
label=
"菜单"
value=
"menu"
/>
<el-option
label=
"按钮"
value=
"button"
/>
<el-option
label=
"接口"
value=
"api"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"资源"
prop=
"resource"
>
<el-input
v-model=
"form.resource"
placeholder=
"请输入资源路径"
/>
</el-form-item>
<el-form-item
label=
"描述"
prop=
"description"
>
<el-input
v-model=
"form.description"
type=
"textarea"
placeholder=
"请输入描述"
:rows=
"3"
/>
</el-form-item>
</el-form>
<
template
#
footer
>
<el-button
@
click=
"dialogVisible = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleSubmit"
:loading=
"submitLoading"
>
确定
</el-button>
</
template
>
</el-dialog>
</div>
</template>
<
script
setup
>
import
{
ref
,
reactive
,
onMounted
}
from
'vue'
import
{
ElMessage
,
ElMessageBox
}
from
'element-plus'
import
{
Plus
,
Edit
,
Delete
}
from
'@element-plus/icons-vue'
import
api
from
'../api'
const
tableData
=
ref
([])
const
loading
=
ref
(
false
)
const
currentPage
=
ref
(
1
)
const
pageSize
=
ref
(
10
)
const
total
=
ref
(
0
)
const
dialogVisible
=
ref
(
false
)
const
isEdit
=
ref
(
false
)
const
submitLoading
=
ref
(
false
)
const
formRef
=
ref
(
null
)
const
form
=
reactive
({
id
:
null
,
code
:
''
,
name
:
''
,
type
:
'menu'
,
resource
:
''
,
description
:
''
})
const
rules
=
{
code
:
[
{
required
:
true
,
message
:
'请输入权限编码'
,
trigger
:
'blur'
},
{
max
:
100
,
message
:
'权限编码长度不能超过100个字符'
,
trigger
:
'blur'
}
],
name
:
[
{
required
:
true
,
message
:
'请输入权限名称'
,
trigger
:
'blur'
},
{
max
:
100
,
message
:
'权限名称长度不能超过100个字符'
,
trigger
:
'blur'
}
]
}
const
fetchData
=
async
()
=>
{
loading
.
value
=
true
try
{
const
res
=
await
api
.
getAllPermissions
({
page
:
currentPage
.
value
-
1
,
size
:
pageSize
.
value
})
tableData
.
value
=
res
.
data
.
content
total
.
value
=
res
.
data
.
totalElements
}
catch
(
error
)
{
console
.
error
(
'获取权限列表失败:'
,
error
)
}
finally
{
loading
.
value
=
false
}
}
const
handleAdd
=
()
=>
{
isEdit
.
value
=
false
Object
.
assign
(
form
,
{
id
:
null
,
code
:
''
,
name
:
''
,
type
:
'menu'
,
resource
:
''
,
description
:
''
})
dialogVisible
.
value
=
true
}
const
handleEdit
=
(
row
)
=>
{
isEdit
.
value
=
true
Object
.
assign
(
form
,
{
id
:
row
.
id
,
code
:
row
.
code
,
name
:
row
.
name
,
type
:
row
.
type
,
resource
:
row
.
resource
,
description
:
row
.
description
})
dialogVisible
.
value
=
true
}
const
handleSubmit
=
async
()
=>
{
if
(
!
formRef
.
value
)
return
await
formRef
.
value
.
validate
(
async
(
valid
)
=>
{
if
(
!
valid
)
return
submitLoading
.
value
=
true
try
{
if
(
isEdit
.
value
)
{
await
api
.
updatePermission
(
form
.
id
,
{
name
:
form
.
name
,
type
:
form
.
type
,
resource
:
form
.
resource
,
description
:
form
.
description
})
ElMessage
.
success
(
'更新成功'
)
}
else
{
await
api
.
createPermission
(
form
)
ElMessage
.
success
(
'创建成功'
)
}
dialogVisible
.
value
=
false
fetchData
()
}
catch
(
error
)
{
}
finally
{
submitLoading
.
value
=
false
}
})
}
const
handleDelete
=
async
(
row
)
=>
{
try
{
await
ElMessageBox
.
confirm
(
`确定要删除权限
${
row
.
name
}
吗?`
,
'警告'
,
{
type
:
'warning'
})
await
api
.
deletePermission
(
row
.
id
)
ElMessage
.
success
(
'删除成功'
)
fetchData
()
}
catch
(
error
)
{
if
(
error
!==
'cancel'
)
{
console
.
error
(
'删除失败:'
,
error
)
}
}
}
const
handleSizeChange
=
(
val
)
=>
{
pageSize
.
value
=
val
fetchData
()
}
const
handleCurrentChange
=
(
val
)
=>
{
currentPage
.
value
=
val
fetchData
()
}
onMounted
(()
=>
{
fetchData
()
})
</
script
>
<
style
scoped
lang=
"scss"
>
.permission-manage
{
padding
:
20px
;
}
.card-header
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
}
.pagination
{
margin-top
:
20px
;
display
:
flex
;
justify-content
:
flex-end
;
}
</
style
>
\ No newline at end of file
financial-penalty-monitor/frontend/src/views/ReportConfig.vue
0 → 100644
浏览文件 @
0c4531a3
<
template
>
<div
class=
"report-config"
>
<el-card>
<el-tabs
v-model=
"activeTab"
@
tab-change=
"handleTabChange"
>
<el-tab-pane
label=
"报告模板"
name=
"templates"
>
<div
class=
"toolbar"
>
<el-button
type=
"primary"
:icon=
"Plus"
@
click=
"handleAddTemplate"
>
添加模板
</el-button>
</div>
<el-table
:data=
"templateData"
v-loading=
"templateLoading"
stripe
>
<el-table-column
prop=
"id"
label=
"ID"
width=
"80"
/>
<el-table-column
prop=
"name"
label=
"模板名称"
/>
<el-table-column
prop=
"description"
label=
"描述"
/>
<el-table-column
prop=
"isDefault"
label=
"默认"
width=
"80"
>
<template
#
default=
"
{ row }">
<el-tag
:type=
"row.isDefault ? 'success' : 'info'"
>
{{
row
.
isDefault
?
'是'
:
'否'
}}
</el-tag>
</
template
>
</el-table-column>
<el-table-column
prop=
"enabled"
label=
"启用"
width=
"80"
>
<
template
#
default=
"{ row }"
>
<el-tag
:type=
"row.enabled ? 'success' : 'danger'"
>
{{
row
.
enabled
?
'是'
:
'否'
}}
</el-tag>
</
template
>
</el-table-column>
<el-table-column
label=
"操作"
width=
"200"
>
<
template
#
default=
"{ row }"
>
<el-button
type=
"primary"
link
@
click=
"handleEditTemplate(row)"
>
编辑
</el-button>
<el-button
type=
"success"
link
@
click=
"handleSetDefault(row)"
:disabled=
"row.isDefault"
>
设为默认
</el-button>
<el-button
type=
"danger"
link
@
click=
"handleDeleteTemplate(row)"
>
删除
</el-button>
</
template
>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane
label=
"分析规则"
name=
"rules"
>
<div
class=
"toolbar"
>
<el-button
type=
"primary"
:icon=
"Plus"
@
click=
"handleAddRule"
>
添加规则
</el-button>
</div>
<el-table
:data=
"ruleData"
v-loading=
"ruleLoading"
stripe
>
<el-table-column
prop=
"id"
label=
"ID"
width=
"80"
/>
<el-table-column
prop=
"name"
label=
"规则名称"
/>
<el-table-column
prop=
"description"
label=
"描述"
/>
<el-table-column
prop=
"institutionType"
label=
"机构类型"
width=
"100"
/>
<el-table-column
prop=
"penaltyType"
label=
"处罚类型"
width=
"100"
/>
<el-table-column
prop=
"priority"
label=
"优先级"
width=
"80"
/>
<el-table-column
prop=
"enabled"
label=
"启用"
width=
"80"
>
<
template
#
default=
"{ row }"
>
<el-tag
:type=
"row.enabled ? 'success' : 'danger'"
>
{{
row
.
enabled
?
'是'
:
'否'
}}
</el-tag>
</
template
>
</el-table-column>
<el-table-column
label=
"操作"
width=
"150"
>
<
template
#
default=
"{ row }"
>
<el-button
type=
"primary"
link
@
click=
"handleEditRule(row)"
>
编辑
</el-button>
<el-button
type=
"danger"
link
@
click=
"handleDeleteRule(row)"
>
删除
</el-button>
</
template
>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane
label=
"关键词"
name=
"keywords"
>
<div
class=
"toolbar"
>
<el-button
type=
"primary"
:icon=
"Plus"
@
click=
"handleAddKeyword"
>
添加关键词
</el-button>
</div>
<el-table
:data=
"keywordData"
v-loading=
"keywordLoading"
stripe
>
<el-table-column
prop=
"id"
label=
"ID"
width=
"80"
/>
<el-table-column
prop=
"keyword"
label=
"关键词"
/>
<el-table-column
prop=
"category"
label=
"分类"
width=
"120"
/>
<el-table-column
prop=
"level"
label=
"级别"
width=
"100"
>
<
template
#
default=
"{ row }"
>
<el-tag
:type=
"getLevelType(row.level)"
>
{{
row
.
level
||
'-'
}}
</el-tag>
</
template
>
</el-table-column>
<el-table-column
prop=
"description"
label=
"描述"
/>
<el-table-column
prop=
"enabled"
label=
"启用"
width=
"80"
>
<
template
#
default=
"{ row }"
>
<el-tag
:type=
"row.enabled ? 'success' : 'danger'"
>
{{
row
.
enabled
?
'是'
:
'否'
}}
</el-tag>
</
template
>
</el-table-column>
<el-table-column
label=
"操作"
width=
"150"
>
<
template
#
default=
"{ row }"
>
<el-button
type=
"primary"
link
@
click=
"handleEditKeyword(row)"
>
编辑
</el-button>
<el-button
type=
"danger"
link
@
click=
"handleDeleteKeyword(row)"
>
删除
</el-button>
</
template
>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane
label=
"当前配置"
name=
"active"
>
<div
class=
"active-config"
>
<el-alert
title=
"设置当前分析使用的配置,保存后系统将使用此配置进行分析"
type=
"info"
:closable=
"false"
show-icon
style=
"margin-bottom: 20px"
/>
<el-row
:gutter=
"20"
>
<el-col
:span=
"8"
>
<el-card
class=
"config-card"
>
<
template
#
header
>
<div
class=
"card-header"
>
<span
class=
"card-title"
>
选择模板
</span>
</div>
</
template
>
<el-select
v-model=
"selectedTemplateId"
placeholder=
"请选择模板"
style=
"width: 100%"
@
change=
"handleConfigChange"
>
<el-option
v-for=
"t in templateData"
:key=
"t.id"
:label=
"t.name"
:value=
"t.id"
>
<span>
{{ t.name }}
</span>
<el-tag
size=
"small"
:type=
"t.isDefault ? 'success' : 'info'"
style=
"margin-left: 8px"
>
{{ t.isDefault ? '默认' : '' }}
</el-tag>
</el-option>
</el-select>
<div
v-if=
"selectedTemplateId"
class=
"selected-info"
>
<div
class=
"config-item"
><strong>
名称:
</strong>
{{ getTemplateName(selectedTemplateId) }}
</div>
</div>
</el-card>
</el-col>
<el-col
:span=
"8"
>
<el-card
class=
"config-card"
>
<
template
#
header
>
<div
class=
"card-header"
>
<span
class=
"card-title"
>
选择规则
</span>
<el-button
type=
"primary"
link
@
click=
"selectAllRules"
size=
"small"
>
全选
</el-button>
</div>
</
template
>
<el-checkbox-group
v-model=
"selectedRuleIds"
@
change=
"handleConfigChange"
>
<el-checkbox
v-for=
"r in ruleData"
:key=
"r.id"
:label=
"r.id"
class=
"rule-checkbox"
>
{{ r.name }}
<span
class=
"rule-meta"
>
({{ r.institutionType || '不限' }}/{{ r.penaltyType || '不限' }})
</span>
</el-checkbox>
</el-checkbox-group>
<div
v-if=
"selectedRuleIds.length === 0"
class=
"empty-tip"
>
请选择规则
</div>
</el-card>
</el-col>
<el-col
:span=
"8"
>
<el-card
class=
"config-card"
>
<
template
#
header
>
<div
class=
"card-header"
>
<span
class=
"card-title"
>
选择关键词
</span>
<el-button
type=
"primary"
link
@
click=
"selectAllKeywords"
size=
"small"
>
全选
</el-button>
</div>
</
template
>
<el-checkbox-group
v-model=
"selectedKeywordIds"
@
change=
"handleConfigChange"
>
<el-checkbox
v-for=
"k in keywordData"
:key=
"k.id"
:label=
"k.id"
class=
"keyword-checkbox"
>
{{ k.keyword }}
<el-tag
size=
"small"
:type=
"getLevelType(k.level)"
style=
"margin-left: 4px"
>
{{ k.level || '' }}
</el-tag>
</el-checkbox>
</el-checkbox-group>
<div
v-if=
"selectedKeywordIds.length === 0"
class=
"empty-tip"
>
请选择关键词
</div>
</el-card>
</el-col>
</el-row>
<div
class=
"save-bar"
>
<el-button
type=
"primary"
:loading=
"savingConfig"
@
click=
"handleSaveConfig"
>
保存配置
</el-button>
<span
class=
"save-tip"
v-if=
"savedConfig"
>
已保存于 {{ savedConfig }}
</span>
</div>
</div>
</el-tab-pane>
</el-tabs>
</el-card>
<el-dialog
v-model=
"templateDialogVisible"
:title=
"templateIsEdit ? '编辑模板' : '添加模板'"
width=
"700px"
>
<el-form
ref=
"templateFormRef"
:model=
"templateForm"
:rules=
"templateRules"
label-width=
"100px"
>
<el-form-item
label=
"模板名称"
prop=
"name"
>
<el-input
v-model=
"templateForm.name"
placeholder=
"请输入模板名称"
/>
</el-form-item>
<el-form-item
label=
"描述"
prop=
"description"
>
<el-input
v-model=
"templateForm.description"
placeholder=
"请输入描述"
/>
</el-form-item>
<el-form-item
label=
"模板内容"
prop=
"content"
>
<el-input
v-model=
"templateForm.content"
type=
"textarea"
:rows=
"15"
placeholder=
"请输入模板内容,使用{institutionName}等占位符"
/>
</el-form-item>
<el-form-item
label=
"设为默认"
>
<el-switch
v-model=
"templateForm.isDefault"
/>
</el-form-item>
<el-form-item
label=
"启用"
>
<el-switch
v-model=
"templateForm.enabled"
/>
</el-form-item>
</el-form>
<
template
#
footer
>
<el-button
@
click=
"templateDialogVisible = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleSubmitTemplate"
:loading=
"templateSubmitLoading"
>
确定
</el-button>
</
template
>
</el-dialog>
<el-dialog
v-model=
"ruleDialogVisible"
:title=
"ruleIsEdit ? '编辑规则' : '添加规则'"
width=
"600px"
>
<el-form
ref=
"ruleFormRef"
:model=
"ruleForm"
:rules=
"ruleRules"
label-width=
"100px"
>
<el-form-item
label=
"规则名称"
prop=
"name"
>
<el-input
v-model=
"ruleForm.name"
placeholder=
"请输入规则名称"
/>
</el-form-item>
<el-form-item
label=
"描述"
prop=
"description"
>
<el-input
v-model=
"ruleForm.description"
placeholder=
"请输入描述"
/>
</el-form-item>
<el-form-item
label=
"机构类型"
>
<el-select
v-model=
"ruleForm.institutionType"
placeholder=
"请选择"
clearable
style=
"width: 100%"
>
<el-option
label=
"银行"
value=
"银行"
/>
<el-option
label=
"保险"
value=
"保险"
/>
<el-option
label=
"证券"
value=
"证券"
/>
<el-option
label=
"基金"
value=
"基金"
/>
<el-option
label=
"其他"
value=
"其他"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"处罚类型"
>
<el-select
v-model=
"ruleForm.penaltyType"
placeholder=
"请选择"
clearable
style=
"width: 100%"
>
<el-option
label=
"罚款"
value=
"罚款"
/>
<el-option
label=
"警告"
value=
"警告"
/>
<el-option
label=
"没收违法所得"
value=
"没收违法所得"
/>
<el-option
label=
"停业"
value=
"停业"
/>
<el-option
label=
"吊销许可证"
value=
"吊销许可证"
/>
<el-option
label=
"市场禁入"
value=
"市场禁入"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"最小金额"
>
<el-input-number
v-model=
"ruleForm.minAmount"
:min=
"0"
style=
"width: 100%"
/>
</el-form-item>
<el-form-item
label=
"最大金额"
>
<el-input-number
v-model=
"ruleForm.maxAmount"
:min=
"0"
style=
"width: 100%"
/>
</el-form-item>
<el-form-item
label=
"分析提示词"
prop=
"prompt"
>
<el-input
v-model=
"ruleForm.prompt"
type=
"textarea"
:rows=
"4"
placeholder=
"请输入分析提示词"
/>
</el-form-item>
<el-form-item
label=
"优先级"
>
<el-input-number
v-model=
"ruleForm.priority"
:min=
"0"
:max=
"100"
style=
"width: 100%"
/>
</el-form-item>
<el-form-item
label=
"启用"
>
<el-switch
v-model=
"ruleForm.enabled"
/>
</el-form-item>
</el-form>
<
template
#
footer
>
<el-button
@
click=
"ruleDialogVisible = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleSubmitRule"
:loading=
"ruleSubmitLoading"
>
确定
</el-button>
</
template
>
</el-dialog>
<el-dialog
v-model=
"keywordDialogVisible"
:title=
"keywordIsEdit ? '编辑关键词' : '添加关键词'"
width=
"500px"
>
<el-form
ref=
"keywordFormRef"
:model=
"keywordForm"
:rules=
"keywordRules"
label-width=
"80px"
>
<el-form-item
label=
"关键词"
prop=
"keyword"
>
<el-input
v-model=
"keywordForm.keyword"
placeholder=
"请输入关键词"
/>
</el-form-item>
<el-form-item
label=
"分类"
>
<el-select
v-model=
"keywordForm.category"
placeholder=
"请选择"
clearable
style=
"width: 100%"
>
<el-option
label=
"违规类型"
value=
"违规类型"
/>
<el-option
label=
"处罚类型"
value=
"处罚类型"
/>
<el-option
label=
"行业领域"
value=
"行业领域"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"级别"
>
<el-select
v-model=
"keywordForm.level"
placeholder=
"请选择"
clearable
style=
"width: 100%"
>
<el-option
label=
"严重"
value=
"严重"
/>
<el-option
label=
"高"
value=
"高"
/>
<el-option
label=
"中"
value=
"中"
/>
<el-option
label=
"低"
value=
"低"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"描述"
>
<el-input
v-model=
"keywordForm.description"
type=
"textarea"
:rows=
"2"
placeholder=
"请输入描述"
/>
</el-form-item>
<el-form-item
label=
"启用"
>
<el-switch
v-model=
"keywordForm.enabled"
/>
</el-form-item>
</el-form>
<
template
#
footer
>
<el-button
@
click=
"keywordDialogVisible = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleSubmitKeyword"
:loading=
"keywordSubmitLoading"
>
确定
</el-button>
</
template
>
</el-dialog>
</div>
</template>
<
script
setup
>
import
{
ref
,
reactive
,
onMounted
}
from
'vue'
import
{
ElMessage
,
ElMessageBox
}
from
'element-plus'
import
{
Plus
}
from
'@element-plus/icons-vue'
import
api
from
'../api'
const
activeTab
=
ref
(
'templates'
)
const
templateData
=
ref
([])
const
templateLoading
=
ref
(
false
)
const
templateDialogVisible
=
ref
(
false
)
const
templateIsEdit
=
ref
(
false
)
const
templateSubmitLoading
=
ref
(
false
)
const
templateFormRef
=
ref
(
null
)
const
templateForm
=
reactive
({
id
:
null
,
name
:
''
,
description
:
''
,
content
:
''
,
isDefault
:
false
,
enabled
:
true
})
const
templateRules
=
{
name
:
[{
required
:
true
,
message
:
'请输入模板名称'
,
trigger
:
'blur'
}],
content
:
[{
required
:
true
,
message
:
'请输入模板内容'
,
trigger
:
'blur'
}]
}
const
ruleData
=
ref
([])
const
ruleLoading
=
ref
(
false
)
const
ruleDialogVisible
=
ref
(
false
)
const
ruleIsEdit
=
ref
(
false
)
const
ruleSubmitLoading
=
ref
(
false
)
const
ruleFormRef
=
ref
(
null
)
const
ruleForm
=
reactive
({
id
:
null
,
name
:
''
,
description
:
''
,
institutionType
:
null
,
penaltyType
:
null
,
minAmount
:
null
,
maxAmount
:
null
,
prompt
:
''
,
priority
:
0
,
enabled
:
true
})
const
ruleRules
=
{
name
:
[{
required
:
true
,
message
:
'请输入规则名称'
,
trigger
:
'blur'
}],
prompt
:
[{
required
:
true
,
message
:
'请输入分析提示词'
,
trigger
:
'blur'
}]
}
const
keywordData
=
ref
([])
const
keywordLoading
=
ref
(
false
)
const
keywordDialogVisible
=
ref
(
false
)
const
keywordIsEdit
=
ref
(
false
)
const
keywordSubmitLoading
=
ref
(
false
)
const
keywordFormRef
=
ref
(
null
)
const
keywordForm
=
reactive
({
id
:
null
,
keyword
:
''
,
category
:
null
,
level
:
null
,
description
:
''
,
enabled
:
true
})
const
keywordRules
=
{
keyword
:
[{
required
:
true
,
message
:
'请输入关键词'
,
trigger
:
'blur'
}]
}
const
selectedTemplateId
=
ref
(
null
)
const
selectedRuleIds
=
ref
([])
const
selectedKeywordIds
=
ref
([])
const
savingConfig
=
ref
(
false
)
const
savedConfig
=
ref
(
''
)
const
getLevelType
=
(
level
)
=>
{
const
map
=
{
'严重'
:
'danger'
,
'高'
:
'warning'
,
'中'
:
'info'
,
'低'
:
'success'
}
return
map
[
level
]
||
'info'
}
const
fetchTemplates
=
async
()
=>
{
templateLoading
.
value
=
true
try
{
const
res
=
await
api
.
getReportTemplates
({
page
:
0
,
size
:
100
})
templateData
.
value
=
res
.
data
.
content
}
catch
(
error
)
{
console
.
error
(
'获取模板失败:'
,
error
)
}
finally
{
templateLoading
.
value
=
false
}
}
const
fetchRules
=
async
()
=>
{
ruleLoading
.
value
=
true
try
{
const
res
=
await
api
.
getAnalysisRules
({
page
:
0
,
size
:
100
})
ruleData
.
value
=
res
.
data
.
content
}
catch
(
error
)
{
console
.
error
(
'获取规则失败:'
,
error
)
}
finally
{
ruleLoading
.
value
=
false
}
}
const
fetchKeywords
=
async
()
=>
{
keywordLoading
.
value
=
true
try
{
const
res
=
await
api
.
getAnalysisKeywords
({
page
:
0
,
size
:
100
})
keywordData
.
value
=
res
.
data
.
content
}
catch
(
error
)
{
console
.
error
(
'获取关键词失败:'
,
error
)
}
finally
{
keywordLoading
.
value
=
false
}
}
const
fetchActiveConfig
=
async
()
=>
{
try
{
const
res
=
await
api
.
getAnalysisConfig
()
const
config
=
res
.
data
.
data
if
(
config
)
{
selectedTemplateId
.
value
=
config
.
templateId
selectedRuleIds
.
value
=
config
.
ruleIds
||
[]
selectedKeywordIds
.
value
=
config
.
keywordIds
||
[]
savedConfig
.
value
=
config
.
updatedAt
||
''
}
}
catch
(
error
)
{
console
.
error
(
'获取当前配置失败:'
,
error
)
}
}
const
getTemplateName
=
(
id
)
=>
{
const
t
=
templateData
.
value
.
find
(
x
=>
x
.
id
===
id
)
return
t
?
t
.
name
:
''
}
const
handleConfigChange
=
()
=>
{
savedConfig
.
value
=
''
}
const
selectAllRules
=
()
=>
{
selectedRuleIds
.
value
=
ruleData
.
value
.
map
(
r
=>
r
.
id
)
savedConfig
.
value
=
''
}
const
selectAllKeywords
=
()
=>
{
selectedKeywordIds
.
value
=
keywordData
.
value
.
map
(
k
=>
k
.
id
)
savedConfig
.
value
=
''
}
const
handleSaveConfig
=
async
()
=>
{
if
(
!
selectedTemplateId
.
value
)
{
ElMessage
.
warning
(
'请选择模板'
)
return
}
savingConfig
.
value
=
true
try
{
await
api
.
setAnalysisConfig
({
templateId
:
selectedTemplateId
.
value
,
ruleIds
:
selectedRuleIds
.
value
,
keywordIds
:
selectedKeywordIds
.
value
})
ElMessage
.
success
(
'配置保存成功'
)
savedConfig
.
value
=
new
Date
().
toLocaleString
()
}
catch
(
error
)
{
ElMessage
.
error
(
'保存失败'
)
}
finally
{
savingConfig
.
value
=
false
}
}
onMounted
(()
=>
{
fetchTemplates
()
fetchRules
()
fetchKeywords
()
fetchActiveConfig
()
})
const
handleTabChange
=
(
tabName
)
=>
{
if
(
tabName
===
'active'
)
{
fetchActiveConfig
()
}
}
const
handleAddTemplate
=
()
=>
{
templateIsEdit
.
value
=
false
Object
.
assign
(
templateForm
,
{
id
:
null
,
name
:
''
,
description
:
''
,
content
:
''
,
isDefault
:
false
,
enabled
:
true
})
templateDialogVisible
.
value
=
true
}
const
handleEditTemplate
=
(
row
)
=>
{
templateIsEdit
.
value
=
true
Object
.
assign
(
templateForm
,
row
)
templateDialogVisible
.
value
=
true
}
const
handleSubmitTemplate
=
async
()
=>
{
if
(
!
templateFormRef
.
value
)
return
await
templateFormRef
.
value
.
validate
(
async
(
valid
)
=>
{
if
(
!
valid
)
return
templateSubmitLoading
.
value
=
true
try
{
if
(
templateIsEdit
.
value
)
{
await
api
.
updateReportTemplate
(
templateForm
.
id
,
templateForm
)
ElMessage
.
success
(
'更新成功'
)
}
else
{
await
api
.
createReportTemplate
(
templateForm
)
ElMessage
.
success
(
'创建成功'
)
}
templateDialogVisible
.
value
=
false
fetchTemplates
()
}
catch
(
error
)
{
}
finally
{
templateSubmitLoading
.
value
=
false
}
})
}
const
handleSetDefault
=
async
(
row
)
=>
{
try
{
await
api
.
updateReportTemplate
(
row
.
id
,
{
isDefault
:
true
})
ElMessage
.
success
(
'设置成功'
)
fetchTemplates
()
}
catch
(
error
)
{}
}
const
handleDeleteTemplate
=
async
(
row
)
=>
{
try
{
await
ElMessageBox
.
confirm
(
`确定要删除模板
${
row
.
name
}
吗?`
,
'警告'
,
{
type
:
'warning'
})
await
api
.
deleteReportTemplate
(
row
.
id
)
ElMessage
.
success
(
'删除成功'
)
fetchTemplates
()
}
catch
(
error
)
{
if
(
error
!==
'cancel'
)
console
.
error
(
'删除失败:'
,
error
)
}
}
const
handleAddRule
=
()
=>
{
ruleIsEdit
.
value
=
false
Object
.
assign
(
ruleForm
,
{
id
:
null
,
name
:
''
,
description
:
''
,
institutionType
:
null
,
penaltyType
:
null
,
minAmount
:
null
,
maxAmount
:
null
,
prompt
:
''
,
priority
:
0
,
enabled
:
true
})
ruleDialogVisible
.
value
=
true
}
const
handleEditRule
=
(
row
)
=>
{
ruleIsEdit
.
value
=
true
Object
.
assign
(
ruleForm
,
row
)
ruleDialogVisible
.
value
=
true
}
const
handleSubmitRule
=
async
()
=>
{
if
(
!
ruleFormRef
.
value
)
return
await
ruleFormRef
.
value
.
validate
(
async
(
valid
)
=>
{
if
(
!
valid
)
return
ruleSubmitLoading
.
value
=
true
try
{
if
(
ruleIsEdit
.
value
)
{
await
api
.
updateAnalysisRule
(
ruleForm
.
id
,
ruleForm
)
ElMessage
.
success
(
'更新成功'
)
}
else
{
await
api
.
createAnalysisRule
(
ruleForm
)
ElMessage
.
success
(
'创建成功'
)
}
ruleDialogVisible
.
value
=
false
fetchRules
()
}
catch
(
error
)
{
}
finally
{
ruleSubmitLoading
.
value
=
false
}
})
}
const
handleDeleteRule
=
async
(
row
)
=>
{
try
{
await
ElMessageBox
.
confirm
(
`确定要删除规则
${
row
.
name
}
吗?`
,
'警告'
,
{
type
:
'warning'
})
await
api
.
deleteAnalysisRule
(
row
.
id
)
ElMessage
.
success
(
'删除成功'
)
fetchRules
()
}
catch
(
error
)
{
if
(
error
!==
'cancel'
)
console
.
error
(
'删除失败:'
,
error
)
}
}
const
handleAddKeyword
=
()
=>
{
keywordIsEdit
.
value
=
false
Object
.
assign
(
keywordForm
,
{
id
:
null
,
keyword
:
''
,
category
:
null
,
level
:
null
,
description
:
''
,
enabled
:
true
})
keywordDialogVisible
.
value
=
true
}
const
handleEditKeyword
=
(
row
)
=>
{
keywordIsEdit
.
value
=
true
Object
.
assign
(
keywordForm
,
row
)
keywordDialogVisible
.
value
=
true
}
const
handleSubmitKeyword
=
async
()
=>
{
if
(
!
keywordFormRef
.
value
)
return
await
keywordFormRef
.
value
.
validate
(
async
(
valid
)
=>
{
if
(
!
valid
)
return
keywordSubmitLoading
.
value
=
true
try
{
if
(
keywordIsEdit
.
value
)
{
await
api
.
updateAnalysisKeyword
(
keywordForm
.
id
,
keywordForm
)
ElMessage
.
success
(
'更新成功'
)
}
else
{
await
api
.
createAnalysisKeyword
(
keywordForm
)
ElMessage
.
success
(
'创建成功'
)
}
keywordDialogVisible
.
value
=
false
fetchKeywords
()
}
catch
(
error
)
{
}
finally
{
keywordSubmitLoading
.
value
=
false
}
})
}
const
handleDeleteKeyword
=
async
(
row
)
=>
{
try
{
await
ElMessageBox
.
confirm
(
`确定要删除关键词
${
row
.
keyword
}
吗?`
,
'警告'
,
{
type
:
'warning'
})
await
api
.
deleteAnalysisKeyword
(
row
.
id
)
ElMessage
.
success
(
'删除成功'
)
fetchKeywords
()
}
catch
(
error
)
{
if
(
error
!==
'cancel'
)
console
.
error
(
'删除失败:'
,
error
)
}
}
</
script
>
<
style
scoped
lang=
"scss"
>
.report-config
{
padding
:
20px
;
}
.toolbar
{
margin-bottom
:
16px
;
}
.active-config
{
padding
:
10px
0
;
}
.config-card
{
margin-bottom
:
20px
;
min-height
:
200px
;
.card-header
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
}
.card-title
{
font-weight
:
600
;
font-size
:
15px
;
}
}
.config-content
{
.config-item
{
margin-bottom
:
12px
;
font-size
:
14px
;
line-height
:
1
.6
;
word-break
:
break-all
;
}
}
.config-list
{
.config-list-item
{
padding
:
10px
;
border-bottom
:
1px
solid
#eee
;
&
:last-child
{
border-bottom
:
none
;
}
.rule-name
{
font-weight
:
500
;
margin-bottom
:
6px
;
}
.rule-meta
{
font-size
:
12px
;
color
:
#909399
;
span
{
margin-right
:
12px
;
}
}
}
}
.keyword-tags
{
.keyword-tag
{
margin
:
4px
;
}
}
.selected-info
{
margin-top
:
12px
;
padding-top
:
12px
;
border-top
:
1px
solid
#eee
;
}
.rule-checkbox
,
.keyword-checkbox
{
display
:
block
;
margin
:
8px
0
;
.rule-meta
{
font-size
:
12px
;
color
:
#909399
;
}
}
.empty-tip
{
color
:
#909399
;
font-size
:
14px
;
text-align
:
center
;
padding
:
20px
0
;
}
.save-bar
{
margin-top
:
20px
;
display
:
flex
;
align-items
:
center
;
gap
:
16px
;
.save-tip
{
color
:
#909399
;
font-size
:
14px
;
}
}
</
style
>
\ No newline at end of file
financial-penalty-monitor/frontend/src/views/RoleManage.vue
0 → 100644
浏览文件 @
0c4531a3
<
template
>
<div
class=
"role-manage"
>
<el-card>
<template
#
header
>
<div
class=
"card-header"
>
<span>
角色管理
</span>
<el-button
type=
"primary"
:icon=
"Plus"
@
click=
"handleAdd"
>
添加角色
</el-button>
</div>
</
template
>
<el-table
:data=
"tableData"
v-loading=
"loading"
stripe
>
<el-table-column
prop=
"id"
label=
"ID"
width=
"80"
/>
<el-table-column
prop=
"code"
label=
"角色编码"
/>
<el-table-column
prop=
"name"
label=
"角色名称"
/>
<el-table-column
prop=
"description"
label=
"描述"
/>
<el-table-column
prop=
"createTime"
label=
"创建时间"
width=
"180"
>
<
template
#
default=
"{ row }"
>
{{
formatDate
(
row
.
createTime
)
}}
</
template
>
</el-table-column>
<el-table-column
label=
"操作"
width=
"350"
fixed=
"right"
>
<
template
#
default=
"{ row }"
>
<el-button
type=
"primary"
link
:icon=
"Edit"
@
click=
"handleEdit(row)"
>
编辑
</el-button>
<el-button
type=
"success"
link
:icon=
"Key"
@
click=
"handleAuth(row)"
>
授权
</el-button>
<el-button
type=
"warning"
link
:icon=
"User"
@
click=
"handleUsers(row)"
>
用户
</el-button>
<el-button
type=
"danger"
link
:icon=
"Delete"
@
click=
"handleDelete(row)"
:disabled=
"['ADMIN', 'USER', 'VIEWER'].includes(row.code)"
>
删除
</el-button>
</
template
>
</el-table-column>
</el-table>
<div
class=
"pagination"
>
<el-pagination
v-model:current-page=
"currentPage"
v-model:page-size=
"pageSize"
:page-sizes=
"[10, 20, 50, 100]"
:total=
"total"
layout=
"total, sizes, prev, pager, next, jumper"
@
size-change=
"handleSizeChange"
@
current-change=
"handleCurrentChange"
/>
</div>
</el-card>
<el-dialog
v-model=
"dialogVisible"
:title=
"isEdit ? '编辑角色' : '添加角色'"
width=
"500px"
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
label-width=
"100px"
>
<el-form-item
label=
"角色编码"
prop=
"code"
v-if=
"!isEdit"
>
<el-input
v-model=
"form.code"
placeholder=
"请输入角色编码"
/>
</el-form-item>
<el-form-item
label=
"角色名称"
prop=
"name"
>
<el-input
v-model=
"form.name"
placeholder=
"请输入角色名称"
/>
</el-form-item>
<el-form-item
label=
"描述"
prop=
"description"
>
<el-input
v-model=
"form.description"
type=
"textarea"
placeholder=
"请输入描述"
:rows=
"3"
/>
</el-form-item>
</el-form>
<
template
#
footer
>
<el-button
@
click=
"dialogVisible = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleSubmit"
:loading=
"submitLoading"
>
确定
</el-button>
</
template
>
</el-dialog>
<el-drawer
v-model=
"authDrawerVisible"
:title=
"`菜单授权 - ${currentRole?.name || ''}`"
direction=
"rtl"
size=
"400px"
>
<div
class=
"menu-tree-container"
>
<el-tree
ref=
"menuTreeRef"
:data=
"menuData"
:props=
"{ children: 'children', label: 'name' }"
show-checkbox
node-key=
"id"
:default-checked-keys=
"checkedMenuIds"
:default-expanded-keys=
"expandedMenuIds"
/>
</div>
<
template
#
footer
>
<el-button
@
click=
"authDrawerVisible = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"saveRoleMenus"
:loading=
"authLoading"
>
保存
</el-button>
</
template
>
</el-drawer>
<el-drawer
v-model=
"userDrawerVisible"
:title=
"`用户分配 - ${currentRole?.name || ''}`"
direction=
"rtl"
size=
"40%"
>
<div
class=
"user-assign-container"
>
<div
class=
"user-panel"
>
<div
class=
"panel-header"
>
未分配用户
</div>
<div
class=
"user-list"
>
<div
v-for=
"user in unassignedUsers"
:key=
"user.id"
class=
"user-item"
@
click=
"assignUser(user)"
>
<el-avatar
:size=
"32"
:icon=
"User"
/>
<div
class=
"user-info"
>
<div
class=
"username"
>
{{ user.username }}
</div>
<div
class=
"nickname"
>
{{ user.nickname || '-' }}
</div>
</div>
<el-icon
class=
"add-icon"
><Plus
/></el-icon>
</div>
</div>
</div>
<div
class=
"divider"
>
<el-icon><DArrowLeft
/></el-icon>
<el-icon><DArrowRight
/></el-icon>
</div>
<div
class=
"user-panel"
>
<div
class=
"panel-header"
>
已分配用户
</div>
<div
class=
"user-list"
>
<div
v-for=
"user in assignedUsersList"
:key=
"user.id"
class=
"user-item assigned"
@
click=
"removeUser(user)"
>
<el-avatar
:size=
"32"
:icon=
"User"
/>
<div
class=
"user-info"
>
<div
class=
"username"
>
{{ user.username }}
</div>
<div
class=
"nickname"
>
{{ user.nickname || '-' }}
</div>
</div>
<el-icon
class=
"remove-icon"
><Close
/></el-icon>
</div>
</div>
</div>
</div>
</el-drawer>
</div>
</template>
<
script
setup
>
import
{
ref
,
reactive
,
onMounted
,
computed
}
from
'vue'
import
{
ElMessage
,
ElMessageBox
}
from
'element-plus'
import
{
Plus
,
Edit
,
Delete
,
Key
,
User
,
Close
,
DArrowLeft
,
DArrowRight
}
from
'@element-plus/icons-vue'
import
api
from
'../api'
const
tableData
=
ref
([])
const
loading
=
ref
(
false
)
const
currentPage
=
ref
(
1
)
const
pageSize
=
ref
(
10
)
const
total
=
ref
(
0
)
const
dialogVisible
=
ref
(
false
)
const
isEdit
=
ref
(
false
)
const
submitLoading
=
ref
(
false
)
const
formRef
=
ref
(
null
)
const
form
=
reactive
({
id
:
null
,
code
:
''
,
name
:
''
,
description
:
''
})
const
rules
=
{
code
:
[
{
required
:
true
,
message
:
'请输入角色编码'
,
trigger
:
'blur'
},
{
min
:
2
,
max
:
50
,
message
:
'角色编码长度在2-50个字符'
,
trigger
:
'blur'
}
],
name
:
[
{
required
:
true
,
message
:
'请输入角色名称'
,
trigger
:
'blur'
},
{
max
:
100
,
message
:
'角色名称长度不能超过100个字符'
,
trigger
:
'blur'
}
]
}
// 授权相关
const
authDrawerVisible
=
ref
(
false
)
const
currentRole
=
ref
(
null
)
const
menuData
=
ref
([])
const
checkedMenuIds
=
ref
([])
const
expandedMenuIds
=
ref
([])
const
menuTreeRef
=
ref
(
null
)
const
authLoading
=
ref
(
false
)
const
fetchData
=
async
()
=>
{
loading
.
value
=
true
try
{
const
res
=
await
api
.
getAllRoles
({
page
:
currentPage
.
value
-
1
,
size
:
pageSize
.
value
})
tableData
.
value
=
res
.
data
.
content
total
.
value
=
res
.
data
.
totalElements
}
catch
(
error
)
{
console
.
error
(
'获取角色列表失败:'
,
error
)
}
finally
{
loading
.
value
=
false
}
}
const
handleAdd
=
()
=>
{
isEdit
.
value
=
false
Object
.
assign
(
form
,
{
id
:
null
,
code
:
''
,
name
:
''
,
description
:
''
})
dialogVisible
.
value
=
true
}
const
handleEdit
=
(
row
)
=>
{
isEdit
.
value
=
true
Object
.
assign
(
form
,
{
id
:
row
.
id
,
code
:
row
.
code
,
name
:
row
.
name
,
description
:
row
.
description
})
dialogVisible
.
value
=
true
}
const
handleSubmit
=
async
()
=>
{
if
(
!
formRef
.
value
)
return
await
formRef
.
value
.
validate
(
async
(
valid
)
=>
{
if
(
!
valid
)
return
submitLoading
.
value
=
true
try
{
if
(
isEdit
.
value
)
{
await
api
.
updateRole
(
form
.
id
,
{
name
:
form
.
name
,
description
:
form
.
description
})
ElMessage
.
success
(
'更新成功'
)
}
else
{
await
api
.
createRole
(
form
)
ElMessage
.
success
(
'创建成功'
)
}
dialogVisible
.
value
=
false
fetchData
()
}
catch
(
error
)
{
}
finally
{
submitLoading
.
value
=
false
}
})
}
const
handleDelete
=
async
(
row
)
=>
{
try
{
await
ElMessageBox
.
confirm
(
`确定要删除角色
${
row
.
name
}
吗?`
,
'警告'
,
{
type
:
'warning'
})
await
api
.
deleteRole
(
row
.
id
)
ElMessage
.
success
(
'删除成功'
)
fetchData
()
}
catch
(
error
)
{
if
(
error
!==
'cancel'
)
{
console
.
error
(
'删除失败:'
,
error
)
}
}
}
const
handleSizeChange
=
(
val
)
=>
{
pageSize
.
value
=
val
fetchData
()
}
const
handleCurrentChange
=
(
val
)
=>
{
currentPage
.
value
=
val
fetchData
()
}
const
formatDate
=
(
dateStr
)
=>
{
if
(
!
dateStr
)
return
'-'
return
dateStr
.
replace
(
'T'
,
' '
).
substring
(
0
,
19
)
}
const
handleAuth
=
async
(
row
)
=>
{
currentRole
.
value
=
row
authDrawerVisible
.
value
=
true
try
{
const
[
menusRes
,
roleMenusRes
]
=
await
Promise
.
all
([
api
.
getMenus
(),
api
.
getRoleMenus
(
row
.
id
)
])
menuData
.
value
=
menusRes
.
data
||
[]
checkedMenuIds
.
value
=
roleMenusRes
.
data
||
[]
// 获取所有菜单ID用于展开
const
getAllIds
=
(
list
)
=>
{
let
ids
=
[]
list
.
forEach
(
item
=>
{
ids
.
push
(
item
.
id
)
if
(
item
.
children
&&
item
.
children
.
length
)
{
ids
=
ids
.
concat
(
getAllIds
(
item
.
children
))
}
})
return
ids
}
expandedMenuIds
.
value
=
getAllIds
(
menuData
.
value
)
}
catch
(
error
)
{
console
.
error
(
'获取菜单失败:'
,
error
)
}
}
const
saveRoleMenus
=
async
()
=>
{
if
(
!
currentRole
.
value
)
return
authLoading
.
value
=
true
try
{
const
checkedKeys
=
menuTreeRef
.
value
.
getCheckedKeys
()
const
halfCheckedKeys
=
menuTreeRef
.
value
.
getHalfCheckedKeys
()
const
allKeys
=
[...
checkedKeys
,
...
halfCheckedKeys
]
await
api
.
saveRoleMenus
(
currentRole
.
value
.
id
,
allKeys
)
ElMessage
.
success
(
'保存成功'
)
authDrawerVisible
.
value
=
false
}
catch
(
error
)
{
console
.
error
(
'保存失败:'
,
error
)
}
finally
{
authLoading
.
value
=
false
}
}
// 用户分配相关
const
userDrawerVisible
=
ref
(
false
)
const
allUsersList
=
ref
([])
const
assignedUserIds
=
ref
([])
const
unassignedUsers
=
computed
(()
=>
{
return
allUsersList
.
value
.
filter
(
u
=>
!
assignedUserIds
.
value
.
includes
(
u
.
id
))
})
const
assignedUsersList
=
computed
(()
=>
{
return
allUsersList
.
value
.
filter
(
u
=>
assignedUserIds
.
value
.
includes
(
u
.
id
))
})
const
handleUsers
=
async
(
row
)
=>
{
currentRole
.
value
=
row
userDrawerVisible
.
value
=
true
try
{
const
[
usersRes
,
roleUsersRes
]
=
await
Promise
.
all
([
api
.
getUsers
({
page
:
0
,
size
:
1000
}),
api
.
getRoleUsers
(
row
.
id
)
])
allUsersList
.
value
=
usersRes
.
data
.
content
||
[]
assignedUserIds
.
value
=
roleUsersRes
.
data
||
[]
}
catch
(
error
)
{
console
.
error
(
'获取用户失败:'
,
error
)
}
}
const
assignUser
=
async
(
user
)
=>
{
if
(
!
currentRole
.
value
)
return
try
{
await
api
.
assignUserToRole
({
userId
:
user
.
id
,
roleCode
:
currentRole
.
value
.
code
})
assignedUserIds
.
value
.
push
(
user
.
id
)
ElMessage
.
success
(
'分配成功'
)
}
catch
(
error
)
{
console
.
error
(
'分配失败:'
,
error
)
}
}
const
removeUser
=
async
(
user
)
=>
{
if
(
!
currentRole
.
value
)
return
try
{
await
api
.
removeUserFromRole
(
user
.
id
)
assignedUserIds
.
value
=
assignedUserIds
.
value
.
filter
(
id
=>
id
!==
user
.
id
)
ElMessage
.
success
(
'移除成功'
)
}
catch
(
error
)
{
console
.
error
(
'移除失败:'
,
error
)
}
}
onMounted
(()
=>
{
fetchData
()
})
</
script
>
<
style
scoped
lang=
"scss"
>
.role-manage
{
padding
:
20px
;
}
.card-header
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
}
.pagination
{
margin-top
:
20px
;
display
:
flex
;
justify-content
:
flex-end
;
}
.menu-tree-container
{
height
:
calc
(
100vh
-
200px
);
overflow-y
:
auto
;
}
.user-assign-container
{
display
:
flex
;
height
:
calc
(
100vh
-
150px
);
gap
:
10px
;
}
.user-panel
{
flex
:
1
;
display
:
flex
;
flex-direction
:
column
;
border
:
1px
solid
#eee
;
border-radius
:
4px
;
overflow
:
hidden
;
.panel-header
{
padding
:
12px
;
background
:
#f5f7fa
;
font-weight
:
600
;
text-align
:
center
;
border-bottom
:
1px
solid
#eee
;
}
.user-list
{
flex
:
1
;
overflow-y
:
auto
;
padding
:
10px
;
}
.user-item
{
display
:
flex
;
align-items
:
center
;
padding
:
10px
;
margin-bottom
:
8px
;
border
:
1px
solid
#eee
;
border-radius
:
4px
;
cursor
:
pointer
;
transition
:
all
0
.2s
;
&
:hover
{
background
:
#f0f9ff
;
border-color
:
#409eff
;
.add-icon
{
color
:
#409eff
;
}
}
&
.assigned
:hover
{
background
:
#fff0f0
;
border-color
:
#f56c6c
;
.remove-icon
{
color
:
#f56c6c
;
}
}
.user-info
{
flex
:
1
;
margin-left
:
10px
;
.username
{
font-weight
:
500
;
}
.nickname
{
font-size
:
12px
;
color
:
#999
;
}
}
.add-icon
,
.remove-icon
{
color
:
#ccc
;
}
}
}
.divider
{
display
:
flex
;
flex-direction
:
column
;
justify-content
:
center
;
gap
:
20px
;
color
:
#999
;
}
</
style
>
\ No newline at end of file
financial-penalty-monitor/frontend/src/views/RoleMenuManage.vue
0 → 100644
浏览文件 @
0c4531a3
<
template
>
<div
class=
"role-menu-manage"
>
<el-card>
<template
#
header
>
<span>
角色菜单权限
</span>
</
template
>
<el-row
:gutter=
"20"
>
<el-col
:span=
"8"
>
<h4>
角色列表
</h4>
<el-table
:data=
"roles"
border
@
row-click=
"selectRole"
:highlight-current-row=
"true"
>
<el-table-column
prop=
"name"
label=
"角色名称"
/>
<el-table-column
prop=
"code"
label=
"编码"
/>
</el-table>
</el-col>
<el-col
:span=
"16"
>
<h4>
菜单权限分配
</h4>
<div
v-if=
"selectedRole"
class=
"menu-tree-container"
>
<el-tree
ref=
"menuTreeRef"
:data=
"menus"
:props=
"{ children: 'children', label: 'name' }"
show-checkbox
node-key=
"id"
:default-checked-keys=
"checkedMenuIds"
:default-expanded-keys=
"expandedMenuIds"
/>
<div
class=
"action-buttons"
>
<el-button
type=
"primary"
@
click=
"saveRoleMenus"
>
保存分配
</el-button>
</div>
</div>
<el-empty
v-else
description=
"请先选择左侧角色"
/>
</el-col>
</el-row>
</el-card>
</div>
</template>
<
script
setup
>
import
{
ref
,
onMounted
}
from
'vue'
import
{
ElMessage
,
ElMessageBox
}
from
'element-plus'
import
api
from
'../api'
const
roles
=
ref
([])
const
menus
=
ref
([])
const
selectedRole
=
ref
(
null
)
const
menuTreeRef
=
ref
(
null
)
const
checkedMenuIds
=
ref
([])
const
expandedMenuIds
=
ref
([])
const
fetchRoles
=
async
()
=>
{
try
{
const
res
=
await
api
.
getRolesSimple
()
roles
.
value
=
res
.
data
console
.
log
(
'Roles loaded:'
,
roles
.
value
)
}
catch
(
error
)
{
console
.
error
(
'获取角色失败:'
,
error
)
}
}
const
fetchMenus
=
async
()
=>
{
try
{
const
res
=
await
api
.
getMenus
()
menus
.
value
=
res
.
data
console
.
log
(
'Menus loaded:'
,
menus
.
value
)
// Get all menu IDs for expansion
const
getAllIds
=
(
menuList
)
=>
{
let
ids
=
[]
menuList
.
forEach
(
m
=>
{
ids
.
push
(
m
.
id
)
if
(
m
.
children
&&
m
.
children
.
length
)
{
ids
=
ids
.
concat
(
getAllIds
(
m
.
children
))
}
})
return
ids
}
expandedMenuIds
.
value
=
getAllIds
(
menus
.
value
)
}
catch
(
error
)
{
console
.
error
(
'获取菜单失败:'
,
error
)
}
}
const
selectRole
=
async
(
row
)
=>
{
selectedRole
.
value
=
row
await
fetchRoleMenus
(
row
.
id
)
}
const
fetchRoleMenus
=
async
(
roleId
)
=>
{
try
{
const
res
=
await
api
.
getRoleMenus
(
roleId
)
checkedMenuIds
.
value
=
res
.
data
||
[]
}
catch
(
error
)
{
console
.
error
(
'获取角色菜单失败:'
,
error
)
checkedMenuIds
.
value
=
[]
}
}
const
saveRoleMenus
=
async
()
=>
{
if
(
!
selectedRole
.
value
)
return
const
checkedKeys
=
menuTreeRef
.
value
.
getCheckedKeys
()
const
halfCheckedKeys
=
menuTreeRef
.
value
.
getHalfCheckedKeys
()
const
allKeys
=
[...
checkedKeys
,
...
halfCheckedKeys
]
try
{
await
api
.
saveRoleMenus
(
selectedRole
.
value
.
id
,
allKeys
)
ElMessage
.
success
(
'保存成功'
)
}
catch
(
error
)
{
console
.
error
(
'保存失败:'
,
error
)
}
}
onMounted
(()
=>
{
fetchRoles
()
fetchMenus
()
})
</
script
>
<
style
scoped
lang=
"scss"
>
.role-menu-manage
{
padding
:
20px
;
}
.menu-tree-container
{
max-height
:
500px
;
overflow-y
:
auto
;
}
.action-buttons
{
margin-top
:
20px
;
text-align
:
right
;
}
h4
{
margin-bottom
:
16px
;
font-weight
:
600
;
}
</
style
>
\ No newline at end of file
financial-penalty-monitor/frontend/src/views/RoleUserManage.vue
0 → 100644
浏览文件 @
0c4531a3
<
template
>
<div
class=
"role-user-manage"
>
<el-card>
<template
#
header
>
<span>
角色用户分配
</span>
</
template
>
<el-row
:gutter=
"20"
>
<el-col
:span=
"8"
>
<h4>
角色列表
</h4>
<el-table
:data=
"roles"
border
@
row-click=
"selectRole"
:highlight-current-row=
"true"
>
<el-table-column
prop=
"name"
label=
"角色名称"
/>
<el-table-column
prop=
"code"
label=
"编码"
/>
<el-table-column
label=
"用户数"
width=
"80"
>
<
template
#
default=
"{ row }"
>
{{
getUserCount
(
row
.
id
)
}}
</
template
>
</el-table-column>
</el-table>
</el-col>
<el-col
:span=
"16"
>
<h4>
用户分配
</h4>
<div
v-if=
"selectedRole"
class=
"user-transfer-container"
>
<el-transfer
v-model=
"assignedUserIds"
:data=
"allUsers"
:titles=
"['未分配用户', '已分配用户']"
@
change=
"handleUserChange"
/>
</div>
<el-empty
v-else
description=
"请先选择左侧角色"
/>
</el-col>
</el-row>
</el-card>
</div>
</template>
<
script
setup
>
import
{
ref
,
computed
,
onMounted
}
from
'vue'
import
{
ElMessage
}
from
'element-plus'
import
api
from
'../api'
const
roles
=
ref
([])
const
allUsers
=
ref
([])
const
selectedRole
=
ref
(
null
)
const
assignedUserIds
=
ref
([])
const
roleUserMap
=
ref
({})
const
roleUserCount
=
computed
(()
=>
{
const
counts
=
{}
Object
.
values
(
roleUserMap
.
value
).
forEach
(
userIds
=>
{
userIds
.
forEach
(
uid
=>
{
counts
[
uid
]
=
(
counts
[
uid
]
||
0
)
+
1
})
})
return
counts
})
const
fetchRoles
=
async
()
=>
{
try
{
const
res
=
await
api
.
getRolesSimple
()
roles
.
value
=
res
.
data
console
.
log
(
'Roles:'
,
roles
.
value
)
}
catch
(
error
)
{
console
.
error
(
'获取角色失败:'
,
error
)
}
}
const
fetchUsers
=
async
()
=>
{
try
{
const
res
=
await
api
.
getUsers
({
page
:
0
,
size
:
1000
})
allUsers
.
value
=
res
.
data
.
content
.
map
(
u
=>
({
key
:
u
.
id
,
label
:
`
${
u
.
username
}
(
${
u
.
nickname
||
'-'
}
)`
}))
console
.
log
(
'Users:'
,
allUsers
.
value
.
length
)
}
catch
(
error
)
{
console
.
error
(
'获取用户失败:'
,
error
)
}
}
const
fetchRoleUsers
=
async
(
roleId
)
=>
{
try
{
const
res
=
await
api
.
getRoleUsers
(
roleId
)
assignedUserIds
.
value
=
res
.
data
||
[]
roleUserMap
.
value
[
roleId
]
=
assignedUserIds
.
value
}
catch
(
error
)
{
console
.
error
(
'获取角色用户失败:'
,
error
)
assignedUserIds
.
value
=
[]
}
}
const
selectRole
=
async
(
row
)
=>
{
selectedRole
.
value
=
row
await
fetchRoleUsers
(
row
.
id
)
}
const
getUserCount
=
(
roleId
)
=>
{
return
roleUserMap
.
value
[
roleId
]?.
length
||
0
}
const
handleUserChange
=
async
(
value
,
direction
,
movedKeys
)
=>
{
if
(
!
selectedRole
.
value
)
return
try
{
if
(
direction
===
'right'
)
{
for
(
const
userId
of
movedKeys
)
{
await
api
.
assignUserToRole
({
userId
,
roleCode
:
selectedRole
.
value
.
code
})
}
}
else
{
for
(
const
userId
of
movedKeys
)
{
await
api
.
removeUserFromRole
(
userId
)
}
}
ElMessage
.
success
(
'更新成功'
)
roleUserMap
.
value
[
selectedRole
.
value
.
id
]
=
value
}
catch
(
error
)
{
console
.
error
(
'更新失败:'
,
error
)
await
fetchRoleUsers
(
selectedRole
.
value
.
id
)
}
}
onMounted
(()
=>
{
fetchRoles
()
fetchUsers
()
})
</
script
>
<
style
scoped
lang=
"scss"
>
.role-user-manage
{
padding
:
20px
;
}
.user-transfer-container
{
max-height
:
500px
;
}
h4
{
margin-bottom
:
16px
;
font-weight
:
600
;
}
</
style
>
\ No newline at end of file
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论