提交 0c4531a3 authored 作者: kxjia's avatar kxjia

初始化项目

上级 5ae3d3ed
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
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()));
}
}
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
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
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
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
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
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
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;
}
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
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
package com.fintech.penalty.dto;
import lombok.Data;
@Data
public class AnalyzeRequest {
private Long templateId;
}
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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());
}
}
}
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
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
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
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
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
<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
<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
<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
<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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论