diff --git a/src/main/java/com/labelsys/backend/common/Result.java b/src/main/java/com/labelsys/backend/common/Result.java index b54991f..783a10f 100644 --- a/src/main/java/com/labelsys/backend/common/Result.java +++ b/src/main/java/com/labelsys/backend/common/Result.java @@ -11,13 +11,13 @@ import lombok.NoArgsConstructor; @Schema(description = "统一返回结果") public class Result { - @Schema(description = "业务状态码") + @Schema(description = "业务状态码", example = "0") private Integer code; - @Schema(description = "返回消息") + @Schema(description = "返回消息", example = "success") private String message; - @Schema(description = "返回数据") + @Schema(description = "返回数据", example = "{}") private T data; public static Result success() { diff --git a/src/main/java/com/labelsys/backend/config/MybatisPlusConfig.java b/src/main/java/com/labelsys/backend/config/MybatisPlusConfig.java index 1f7f155..d9dbce0 100644 --- a/src/main/java/com/labelsys/backend/config/MybatisPlusConfig.java +++ b/src/main/java/com/labelsys/backend/config/MybatisPlusConfig.java @@ -1,17 +1,23 @@ package com.labelsys.backend.config; -import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; -import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; + @Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); - interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.POSTGRE_SQL); + paginationInnerInterceptor.setOverflow(false); + paginationInnerInterceptor.setMaxLimit(200L); + interceptor.addInnerInterceptor(paginationInnerInterceptor); + return interceptor; } } diff --git a/src/main/java/com/labelsys/backend/context/LoginUser.java b/src/main/java/com/labelsys/backend/context/LoginUser.java index 7d1d124..c302bff 100644 --- a/src/main/java/com/labelsys/backend/context/LoginUser.java +++ b/src/main/java/com/labelsys/backend/context/LoginUser.java @@ -7,37 +7,28 @@ import com.labelsys.backend.enums.UserRole; import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "当前登录用户上下文") -public record LoginUser( - @Schema(description = "用户ID") Long userId, - @Schema(description = "公司ID") Long companyId, - @Schema(description = "公司编码") String companyCode, - @Schema(description = "公司名称") String companyName, +public record LoginUser(@Schema(description = "用户ID") Long userId, @Schema(description = "公司ID") Long companyId, + @Schema(description = "公司编码") String companyCode, @Schema(description = "公司名称") String companyName, @Schema(description = "手机号") String phone, @Schema(description = "用户名,可为空", example = "alpha-reviewer") String username, @Schema(description = "真实姓名") String realName, @Schema(description = "角色,枚举值:EMPLOYEE员工、MANAGER部门经理、ENGINEER总工程师") UserRole role, - @Schema(description = "岗位,枚举值:ANNOTATOR标注员、DATA_TRAINER数据训练师、REVIEWER审核员、ADMIN超级管理员") UserPosition position, + @Schema( + description = "岗位,枚举值:ANNOTATOR标注员、DATA_TRAINER数据训练师、REVIEWER审核员、ADMIN超级管理员、SUPER_ADMIN系统管理员") UserPosition position, @Schema(description = "是否必须修改密码") boolean mustChangePassword, - @Schema(description = "会话版本") Integer sessionVersion -) { + @Schema(description = "会话版本") Integer sessionVersion) { public static LoginUser from(SysUser user, SysCompany company) { - return new LoginUser( - user.getId(), - company.getId(), - company.getCompanyCode(), - company.getCompanyName(), - user.getPhone(), - user.getUsername(), - user.getRealName(), - user.getRole(), - user.getPosition(), - Boolean.TRUE.equals(user.getMustChangePassword()), - user.getSessionVersion() - ); + return new LoginUser(user.getId(), company.getId(), company.getCompanyCode(), company.getCompanyName(), + user.getPhone(), user.getUsername(), user.getRealName(), user.getRole(), user.getPosition(), + Boolean.TRUE.equals(user.getMustChangePassword()), user.getSessionVersion()); } - public boolean isPlatformAdmin() { - return "PLATFORM".equals(companyCode) && position == UserPosition.ADMIN; + // public boolean isPlatformAdmin() { + // return "PLATFORM".equals(companyCode) && position == UserPosition.ADMIN; + // } + + public boolean isSuperAdmin() { + return position == UserPosition.SUPER_ADMIN; } } diff --git a/src/main/java/com/labelsys/backend/controller/AnnotationResultController.java b/src/main/java/com/labelsys/backend/controller/AnnotationResultController.java index 0a9cdac..412b1dd 100644 --- a/src/main/java/com/labelsys/backend/controller/AnnotationResultController.java +++ b/src/main/java/com/labelsys/backend/controller/AnnotationResultController.java @@ -13,9 +13,11 @@ import com.labelsys.backend.enums.UserPosition; import com.labelsys.backend.service.AnnotationResultArchiveService; import com.labelsys.backend.service.AnnotationResultService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -34,28 +36,37 @@ public class AnnotationResultController { @Operation(summary = "分页查询标注结果") @GetMapping - public Result> page(AnnotationResultPageQuery query) { + public Result> page(@ParameterObject AnnotationResultPageQuery query) { return Result.success(annotationResultService.pageResults(UserContext.requireUser(), query)); } @Operation(summary = "查询标注结果详情") @GetMapping("/{id}") - public Result detail(@PathVariable Long id) { + public Result detail( + @Parameter(description = "结果ID", example = "191000000000000401") + @PathVariable Long id + ) { return Result.success(annotationResultService.getResult(UserContext.requireUser(), id)); } @Operation(summary = "查询标注结果比对信息") @RequirePosition(UserPosition.REVIEWER) @GetMapping("/{id}/compare") - public Result compare(@PathVariable Long id) { + public Result compare( + @Parameter(description = "结果ID", example = "191000000000000401") + @PathVariable Long id + ) { return Result.success(annotationResultService.compareResult(UserContext.requireUser(), id)); } @Operation(summary = "提交合并审核结果") @RequirePosition(UserPosition.REVIEWER) @PostMapping("/{id}/merge-review") - public Result mergeReview(@PathVariable Long id, - @Valid @RequestBody MergeReviewResultRequest request) { + public Result mergeReview( + @Parameter(description = "结果ID", example = "191000000000000401") + @PathVariable Long id, + @Valid @RequestBody MergeReviewResultRequest request + ) { return Result.success(annotationResultArchiveService.mergeReview(UserContext.requireUser(), id, request)); } } diff --git a/src/main/java/com/labelsys/backend/controller/AnnotationTaskController.java b/src/main/java/com/labelsys/backend/controller/AnnotationTaskController.java index f36274c..1723173 100644 --- a/src/main/java/com/labelsys/backend/controller/AnnotationTaskController.java +++ b/src/main/java/com/labelsys/backend/controller/AnnotationTaskController.java @@ -9,9 +9,11 @@ import com.labelsys.backend.dto.request.UpdateAnnotationTaskRequest; import com.labelsys.backend.dto.response.AnnotationTaskResponse; import com.labelsys.backend.service.AnnotationTaskService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -37,25 +39,35 @@ public class AnnotationTaskController { @Operation(summary = "更新标注任务") @PutMapping("/{id}") - public Result update(@PathVariable Long id, @Valid @RequestBody UpdateAnnotationTaskRequest request) { + public Result update( + @Parameter(description = "任务ID", example = "191000000000000301") + @PathVariable Long id, + @Valid @RequestBody UpdateAnnotationTaskRequest request + ) { return Result.success(annotationTaskService.updateTask(UserContext.requireUser(), id, request)); } @Operation(summary = "分页查询标注任务") @GetMapping - public Result> page(AnnotationTaskPageQuery query) { + public Result> page(@ParameterObject AnnotationTaskPageQuery query) { return Result.success(annotationTaskService.pageTasks(UserContext.requireUser(), query)); } @Operation(summary = "查询标注任务详情") @GetMapping("/{id}") - public Result detail(@PathVariable Long id) { + public Result detail( + @Parameter(description = "任务ID", example = "191000000000000301") + @PathVariable Long id + ) { return Result.success(annotationTaskService.getTask(UserContext.requireUser(), id)); } @Operation(summary = "删除标注任务") @DeleteMapping("/{id}") - public Result delete(@PathVariable Long id) { + public Result delete( + @Parameter(description = "任务ID", example = "191000000000000301") + @PathVariable Long id + ) { annotationTaskService.deleteTask(UserContext.requireUser(), id); return Result.success(); } diff --git a/src/main/java/com/labelsys/backend/controller/AuthController.java b/src/main/java/com/labelsys/backend/controller/AuthController.java index 34bcc6e..e0dc11c 100644 --- a/src/main/java/com/labelsys/backend/controller/AuthController.java +++ b/src/main/java/com/labelsys/backend/controller/AuthController.java @@ -10,6 +10,7 @@ import com.labelsys.backend.dto.response.CurrentUserResponse; import com.labelsys.backend.dto.response.LoginResponse; import com.labelsys.backend.service.AuthService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import java.util.List; @@ -33,7 +34,10 @@ public class AuthController { @Operation(summary = "根据手机号查询可登录公司") @GetMapping("/companies") - public Result> listCompanies(@RequestParam String phone) { + public Result> listCompanies( + @Parameter(description = "手机号", example = "13800138000") + @RequestParam String phone + ) { return Result.success(authService.listAvailableCompanies(phone)); } @@ -52,7 +56,10 @@ public class AuthController { @Operation(summary = "退出登录") @PostMapping("/logout") - public Result logout(@RequestHeader(HttpHeaders.AUTHORIZATION) String authorization) { + public Result logout( + @Parameter(description = "Bearer 访问令牌", example = "Bearer eyJhbGciOiJIUzI1NiJ9.demo.token") + @RequestHeader(HttpHeaders.AUTHORIZATION) String authorization + ) { authService.logout(extractToken(authorization)); return Result.success(); } diff --git a/src/main/java/com/labelsys/backend/controller/CompanyUserController.java b/src/main/java/com/labelsys/backend/controller/CompanyUserController.java index 078c727..5885b91 100644 --- a/src/main/java/com/labelsys/backend/controller/CompanyUserController.java +++ b/src/main/java/com/labelsys/backend/controller/CompanyUserController.java @@ -10,6 +10,7 @@ import com.labelsys.backend.dto.response.UserResponse; import com.labelsys.backend.enums.UserPosition; import com.labelsys.backend.service.UserService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import java.util.List; @@ -45,14 +46,22 @@ public class CompanyUserController { @Operation(summary = "修改员工角色和岗位") @PutMapping("/{userId}/assignment") - public Result updateAssignment(@PathVariable Long userId, @Valid @RequestBody UpdateUserAssignmentRequest request) { + public Result updateAssignment( + @Parameter(description = "用户ID", example = "191000000000000021") + @PathVariable Long userId, + @Valid @RequestBody UpdateUserAssignmentRequest request + ) { userService.updateAssignment(UserContext.requireUser(), userId, request); return Result.success(); } @Operation(summary = "修改员工状态") @PutMapping("/{userId}/status") - public Result updateStatus(@PathVariable Long userId, @Valid @RequestBody UpdateUserStatusRequest request) { + public Result updateStatus( + @Parameter(description = "用户ID", example = "191000000000000021") + @PathVariable Long userId, + @Valid @RequestBody UpdateUserStatusRequest request + ) { userService.updateStatus(UserContext.requireUser(), userId, request); return Result.success(); } diff --git a/src/main/java/com/labelsys/backend/controller/PlatformCompanyAdminController.java b/src/main/java/com/labelsys/backend/controller/PlatformCompanyAdminController.java index 51c98d8..350e70e 100644 --- a/src/main/java/com/labelsys/backend/controller/PlatformCompanyAdminController.java +++ b/src/main/java/com/labelsys/backend/controller/PlatformCompanyAdminController.java @@ -4,11 +4,13 @@ import com.labelsys.backend.annotation.RequirePosition; import com.labelsys.backend.common.Result; import com.labelsys.backend.context.UserContext; import com.labelsys.backend.dto.request.CreateCompanyAdminRequest; +import com.labelsys.backend.dto.request.CreateSystemEngineerAdminRequest; import com.labelsys.backend.dto.request.UpdateUserStatusRequest; import com.labelsys.backend.dto.response.UserResponse; import com.labelsys.backend.enums.UserPosition; import com.labelsys.backend.service.UserService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import java.util.List; @@ -25,7 +27,7 @@ import org.springframework.web.bind.annotation.RestController; @Tag(name = "平台公司管理员管理") @RestController @RequestMapping("/api/platform/company-admins") -@RequirePosition(UserPosition.ADMIN) +@RequirePosition(UserPosition.SUPER_ADMIN) @RequiredArgsConstructor public class PlatformCompanyAdminController { @@ -33,20 +35,37 @@ public class PlatformCompanyAdminController { @Operation(summary = "查询指定公司管理员列表") @GetMapping - public Result> listCompanyAdmins(@RequestParam Long companyId) { + public Result> listCompanyAdmins( + @Parameter(description = "公司ID", example = "191000000000000001") + @RequestParam Long companyId + ) { return Result.success(userService.listCompanyAdmins(UserContext.requireUser(), companyId).stream().map(UserResponse::from).toList()); } + @Operation(summary = "查询所有公司用户列表") + @GetMapping("/all") + public Result> listAllUsers() { + return Result.success(userService.listAllUsers(UserContext.requireUser()).stream().map(UserResponse::from).toList()); + } + @Operation(summary = "创建公司管理员") @PostMapping public Result createCompanyAdmin(@Valid @RequestBody CreateCompanyAdminRequest request) { return Result.success(UserResponse.from(userService.createCompanyAdmin(UserContext.requireUser(), request))); } + @Operation(summary = "创建系统工程师管理员") + @PostMapping("/system-engineer") + public Result createSystemEngineerAdmin(@Valid @RequestBody CreateSystemEngineerAdminRequest request) { + return Result.success(UserResponse.from(userService.createSystemEngineerAdmin(UserContext.requireUser(), request))); + } + @Operation(summary = "修改公司管理员状态") @PutMapping("/{companyId}/{userId}/status") public Result updateCompanyAdminStatus( + @Parameter(description = "公司ID", example = "191000000000000001") @PathVariable Long companyId, + @Parameter(description = "用户ID", example = "191000000000000021") @PathVariable Long userId, @Valid @RequestBody UpdateUserStatusRequest request ) { diff --git a/src/main/java/com/labelsys/backend/controller/PlatformCompanyController.java b/src/main/java/com/labelsys/backend/controller/PlatformCompanyController.java index 2a6e7ad..ed3c27e 100644 --- a/src/main/java/com/labelsys/backend/controller/PlatformCompanyController.java +++ b/src/main/java/com/labelsys/backend/controller/PlatformCompanyController.java @@ -9,6 +9,7 @@ import com.labelsys.backend.dto.response.CompanyResponse; import com.labelsys.backend.enums.UserPosition; import com.labelsys.backend.service.CompanyService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import java.util.List; @@ -24,7 +25,7 @@ import org.springframework.web.bind.annotation.RestController; @Tag(name = "平台公司管理") @RestController @RequestMapping("/api/platform/companies") -@RequirePosition(UserPosition.ADMIN) +@RequirePosition(UserPosition.SUPER_ADMIN) @RequiredArgsConstructor public class PlatformCompanyController { @@ -44,7 +45,11 @@ public class PlatformCompanyController { @Operation(summary = "修改公司状态") @PutMapping("/{companyId}/status") - public Result updateCompanyStatus(@PathVariable Long companyId, @Valid @RequestBody UpdateCompanyStatusRequest request) { + public Result updateCompanyStatus( + @Parameter(description = "公司ID", example = "191000000000000001") + @PathVariable Long companyId, + @Valid @RequestBody UpdateCompanyStatusRequest request + ) { companyService.updateStatus(UserContext.requireUser(), companyId, request); return Result.success(); } diff --git a/src/main/java/com/labelsys/backend/controller/SourceResourceController.java b/src/main/java/com/labelsys/backend/controller/SourceResourceController.java index 36fb83b..7d6b45e 100644 --- a/src/main/java/com/labelsys/backend/controller/SourceResourceController.java +++ b/src/main/java/com/labelsys/backend/controller/SourceResourceController.java @@ -9,8 +9,10 @@ import com.labelsys.backend.dto.response.SourceResourceResponse; import com.labelsys.backend.dto.response.SourceUploadResponse; import com.labelsys.backend.service.SourceResourceService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; @@ -29,25 +31,31 @@ public class SourceResourceController { @Operation(summary = "上传资源") @PostMapping("/upload") - public Result upload(@ModelAttribute SourceUploadRequest request) { + public Result upload(@ParameterObject @ModelAttribute SourceUploadRequest request) { return Result.success(sourceResourceService.upload(UserContext.requireUser(), request)); } @Operation(summary = "分页查询资源") @GetMapping - public Result> page(SourceResourcePageQuery query) { + public Result> page(@ParameterObject SourceResourcePageQuery query) { return Result.success(sourceResourceService.pageResources(UserContext.requireUser(), query)); } @Operation(summary = "查询资源详情") @GetMapping("/{id}") - public Result detail(@PathVariable Long id) { + public Result detail( + @Parameter(description = "资源ID", example = "191000000000000101") + @PathVariable Long id + ) { return Result.success(sourceResourceService.getResource(UserContext.requireUser(), id)); } @Operation(summary = "删除资源") @DeleteMapping("/{id}") - public Result delete(@PathVariable Long id) { + public Result delete( + @Parameter(description = "资源ID", example = "191000000000000101") + @PathVariable Long id + ) { sourceResourceService.deleteResource(UserContext.requireUser(), id); return Result.success(); } diff --git a/src/main/java/com/labelsys/backend/controller/SysConfigController.java b/src/main/java/com/labelsys/backend/controller/SysConfigController.java index 959e057..56fceee 100644 --- a/src/main/java/com/labelsys/backend/controller/SysConfigController.java +++ b/src/main/java/com/labelsys/backend/controller/SysConfigController.java @@ -10,9 +10,11 @@ import com.labelsys.backend.dto.response.SysConfigResponse; import com.labelsys.backend.enums.UserPosition; import com.labelsys.backend.service.SysConfigService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -39,19 +41,26 @@ public class SysConfigController { @Operation(summary = "更新系统配置") @RequirePosition(UserPosition.ADMIN) @PutMapping("/{id}") - public Result update(@PathVariable Long id, @Valid @RequestBody SaveSysConfigRequest request) { + public Result update( + @Parameter(description = "配置ID", example = "191000000000000501") + @PathVariable Long id, + @Valid @RequestBody SaveSysConfigRequest request + ) { return Result.success(sysConfigService.toResponse(sysConfigService.updateConfig(UserContext.requireUser(), id, request))); } @Operation(summary = "分页查询系统配置") @GetMapping - public Result> page(SysConfigPageQuery query) { + public Result> page(@ParameterObject SysConfigPageQuery query) { return Result.success(sysConfigService.pageConfigs(UserContext.requireUser(), query)); } @Operation(summary = "查询系统配置详情") @GetMapping("/{id}") - public Result detail(@PathVariable Long id) { + public Result detail( + @Parameter(description = "配置ID", example = "191000000000000501") + @PathVariable Long id + ) { return Result.success(sysConfigService.getConfig(UserContext.requireUser(), id)); } } diff --git a/src/main/java/com/labelsys/backend/dto/common/PageResult.java b/src/main/java/com/labelsys/backend/dto/common/PageResult.java index 62f40e1..39011f1 100644 --- a/src/main/java/com/labelsys/backend/dto/common/PageResult.java +++ b/src/main/java/com/labelsys/backend/dto/common/PageResult.java @@ -6,10 +6,10 @@ import java.util.List; @Schema(description = "分页结果") public record PageResult( - @Schema(description = "当前页记录") List records, - @Schema(description = "总记录数") Long total, - @Schema(description = "页码") Integer pageNo, - @Schema(description = "每页数量") Integer pageSize + @Schema(description = "当前页记录", example = "[]") List records, + @Schema(description = "总记录数", example = "2") Long total, + @Schema(description = "页码", example = "1") Integer pageNo, + @Schema(description = "每页数量", example = "10") Integer pageSize ) { public static PageResult from(IPage page) { return new PageResult<>(page.getRecords(), page.getTotal(), (int) page.getCurrent(), (int) page.getSize()); diff --git a/src/main/java/com/labelsys/backend/dto/request/AnnotationResultPageQuery.java b/src/main/java/com/labelsys/backend/dto/request/AnnotationResultPageQuery.java index d07cbcf..21e5ff6 100644 --- a/src/main/java/com/labelsys/backend/dto/request/AnnotationResultPageQuery.java +++ b/src/main/java/com/labelsys/backend/dto/request/AnnotationResultPageQuery.java @@ -4,11 +4,11 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "标注结果分页查询请求") public record AnnotationResultPageQuery( - @Schema(description = "任务ID") Long taskId, - @Schema(description = "资源ID") Long resourceId, - @Schema(description = "是否需要人工审核") Boolean requiresManualReview, - @Schema(description = "运行态状态") String runtimeStatus, - @Schema(description = "页码") Integer pageNo, - @Schema(description = "每页数量") Integer pageSize + @Schema(description = "任务ID", example = "191000000000000301") Long taskId, + @Schema(description = "资源ID", example = "191000000000000101") Long resourceId, + @Schema(description = "是否需要人工审核", example = "true") Boolean requiresManualReview, + @Schema(description = "运行态状态", example = "MANUAL_REVIEW_PENDING") String runtimeStatus, + @Schema(description = "页码", example = "1") Integer pageNo, + @Schema(description = "每页数量", example = "10") Integer pageSize ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/AnnotationTaskPageQuery.java b/src/main/java/com/labelsys/backend/dto/request/AnnotationTaskPageQuery.java index bdd5d43..a15b67e 100644 --- a/src/main/java/com/labelsys/backend/dto/request/AnnotationTaskPageQuery.java +++ b/src/main/java/com/labelsys/backend/dto/request/AnnotationTaskPageQuery.java @@ -4,12 +4,12 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "标注任务分页查询请求") public record AnnotationTaskPageQuery( - @Schema(description = "关键字") String keyword, - @Schema(description = "任务类型") String taskType, - @Schema(description = "任务状态") String taskStatus, - @Schema(description = "资源ID") Long resourceId, - @Schema(description = "是否已删除") Boolean isDeleted, - @Schema(description = "页码") Integer pageNo, - @Schema(description = "每页数量") Integer pageSize + @Schema(description = "关键字", example = "运输") String keyword, + @Schema(description = "任务类型", example = "EXTRACT_QA") String taskType, + @Schema(description = "任务状态", example = "PENDING") String taskStatus, + @Schema(description = "资源ID", example = "191000000000000101") Long resourceId, + @Schema(description = "是否已删除", example = "false") Boolean isDeleted, + @Schema(description = "页码", example = "1") Integer pageNo, + @Schema(description = "每页数量", example = "10") Integer pageSize ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/ChangePasswordRequest.java b/src/main/java/com/labelsys/backend/dto/request/ChangePasswordRequest.java index 14e9f53..fa55b90 100644 --- a/src/main/java/com/labelsys/backend/dto/request/ChangePasswordRequest.java +++ b/src/main/java/com/labelsys/backend/dto/request/ChangePasswordRequest.java @@ -5,8 +5,8 @@ import jakarta.validation.constraints.NotBlank; @Schema(description = "修改密码请求") public record ChangePasswordRequest( - @Schema(description = "旧密码") @NotBlank(message = "不能为空") String oldPassword, - @Schema(description = "新密码") @NotBlank(message = "不能为空") String newPassword, - @Schema(description = "确认新密码") @NotBlank(message = "不能为空") String confirmPassword + @Schema(description = "旧密码", example = "P@ssw0rd!") @NotBlank(message = "不能为空") String oldPassword, + @Schema(description = "新密码", example = "N3wP@ssw0rd!") @NotBlank(message = "不能为空") String newPassword, + @Schema(description = "确认新密码", example = "N3wP@ssw0rd!") @NotBlank(message = "不能为空") String confirmPassword ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/CreateAnnotationTaskRequest.java b/src/main/java/com/labelsys/backend/dto/request/CreateAnnotationTaskRequest.java index 5dbc324..be1b837 100644 --- a/src/main/java/com/labelsys/backend/dto/request/CreateAnnotationTaskRequest.java +++ b/src/main/java/com/labelsys/backend/dto/request/CreateAnnotationTaskRequest.java @@ -8,13 +8,13 @@ import java.util.List; @Schema(description = "创建标注任务请求") public record CreateAnnotationTaskRequest( - @Schema(description = "任务名称") @NotBlank(message = "任务名称不能为空") String taskName, - @Schema(description = "行业类型") String industryType, - @Schema(description = "任务类型") String taskType, - @Schema(description = "资源ID列表") @NotEmpty(message = "资源列表不能为空") List resourceIds, - @Schema(description = "抽取模型配置") @Valid TaskModelConfigRequest extractModel, - @Schema(description = "校验模型配置") @Valid TaskModelConfigRequest verifyModel, - @Schema(description = "抽取提示词配置") @Valid PromptConfigOptionRequest extractPrompt, - @Schema(description = "校验提示词配置") @Valid PromptConfigOptionRequest verifyPrompt + @Schema(description = "任务名称", example = "运输文档问答抽取任务") @NotBlank(message = "任务名称不能为空") String taskName, + @Schema(description = "行业类型", example = "transport") String industryType, + @Schema(description = "任务类型", example = "EXTRACT_QA") String taskType, + @Schema(description = "资源ID列表", example = "[191000000000000101,191000000000000102]") @NotEmpty(message = "资源列表不能为空") List resourceIds, + @Schema(description = "抽取模型配置", example = "{\"mode\":\"SELECT\",\"selectedConfigName\":\"qwen-plus-extract\"}") @Valid TaskModelConfigRequest extractModel, + @Schema(description = "校验模型配置", example = "{\"mode\":\"MANUAL\",\"manualConfig\":{\"modelName\":\"qwen-max\",\"modelUrl\":\"https://dashscope.aliyuncs.com/compatible-mode/v1\",\"apiKey\":\"sk-demo5678\"}}") @Valid TaskModelConfigRequest verifyModel, + @Schema(description = "抽取提示词配置", example = "{\"selectedConfigName\":\"qa-extract-v1\"}") @Valid PromptConfigOptionRequest extractPrompt, + @Schema(description = "校验提示词配置", example = "{\"promptText\":\"请对抽取结果进行逐项校验,并输出差异说明。\"}") @Valid PromptConfigOptionRequest verifyPrompt ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/CreateCompanyAdminRequest.java b/src/main/java/com/labelsys/backend/dto/request/CreateCompanyAdminRequest.java index cc6f906..707068d 100644 --- a/src/main/java/com/labelsys/backend/dto/request/CreateCompanyAdminRequest.java +++ b/src/main/java/com/labelsys/backend/dto/request/CreateCompanyAdminRequest.java @@ -6,9 +6,9 @@ import jakarta.validation.constraints.NotNull; @Schema(description = "创建公司管理员请求") public record CreateCompanyAdminRequest( - @Schema(description = "公司ID") @NotNull(message = "不能为空") Long companyId, - @Schema(description = "手机号") @NotBlank(message = "不能为空") String phone, + @Schema(description = "公司ID", example = "191000000000000001") @NotNull(message = "不能为空") Long companyId, + @Schema(description = "手机号", example = "13800138001") @NotBlank(message = "不能为空") String phone, @Schema(description = "用户名,前端展示用,可为空", example = "platform-ops") String username, - @Schema(description = "真实姓名") @NotBlank(message = "不能为空") String realName + @Schema(description = "真实姓名", example = "平台运维") @NotBlank(message = "不能为空") String realName ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/CreateCompanyRequest.java b/src/main/java/com/labelsys/backend/dto/request/CreateCompanyRequest.java index 5dbd65f..11979fd 100644 --- a/src/main/java/com/labelsys/backend/dto/request/CreateCompanyRequest.java +++ b/src/main/java/com/labelsys/backend/dto/request/CreateCompanyRequest.java @@ -5,7 +5,7 @@ import jakarta.validation.constraints.NotBlank; @Schema(description = "创建公司请求") public record CreateCompanyRequest( - @Schema(description = "公司编码") @NotBlank(message = "不能为空") String companyCode, - @Schema(description = "公司名称") @NotBlank(message = "不能为空") String companyName + @Schema(description = "公司编码", example = "ALPHA") @NotBlank(message = "不能为空") String companyCode, + @Schema(description = "公司名称", example = "阿尔法标注有限公司") @NotBlank(message = "不能为空") String companyName ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/CreateSystemEngineerAdminRequest.java b/src/main/java/com/labelsys/backend/dto/request/CreateSystemEngineerAdminRequest.java new file mode 100644 index 0000000..e3a50a2 --- /dev/null +++ b/src/main/java/com/labelsys/backend/dto/request/CreateSystemEngineerAdminRequest.java @@ -0,0 +1,10 @@ +package com.labelsys.backend.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; + +@Schema(description = "创建系统工程师管理员请求") +public record CreateSystemEngineerAdminRequest( + @Schema(description = "手机号", example = "13800138002") @NotBlank(message = "不能为空") String phone, + @Schema(description = "用户名,前端展示用,可为空", example = "system-engineer") String username, + @Schema(description = "真实姓名", example = "系统工程师") @NotBlank(message = "不能为空") String realName) {} \ No newline at end of file diff --git a/src/main/java/com/labelsys/backend/dto/request/CreateUserRequest.java b/src/main/java/com/labelsys/backend/dto/request/CreateUserRequest.java index 42bc05e..e0cbf52 100644 --- a/src/main/java/com/labelsys/backend/dto/request/CreateUserRequest.java +++ b/src/main/java/com/labelsys/backend/dto/request/CreateUserRequest.java @@ -8,10 +8,10 @@ import jakarta.validation.constraints.NotNull; @Schema(description = "创建员工请求") public record CreateUserRequest( - @Schema(description = "手机号") @NotBlank(message = "不能为空") String phone, + @Schema(description = "手机号", example = "13800138002") @NotBlank(message = "不能为空") String phone, @Schema(description = "用户名,前端展示用,可为空", example = "alpha-admin") String username, - @Schema(description = "真实姓名") @NotBlank(message = "不能为空") String realName, - @Schema(description = "角色,枚举值:EMPLOYEE员工、MANAGER部门经理、ENGINEER总工程师") @NotNull(message = "不能为空") UserRole role, - @Schema(description = "岗位,枚举值:ANNOTATOR标注员、DATA_TRAINER数据训练师、REVIEWER审核员、ADMIN超级管理员") @NotNull(message = "不能为空") UserPosition position + @Schema(description = "真实姓名", example = "张审核") @NotBlank(message = "不能为空") String realName, + @Schema(description = "角色,枚举值:EMPLOYEE员工、MANAGER部门经理、ENGINEER总工程师", example = "EMPLOYEE") @NotNull(message = "不能为空") UserRole role, + @Schema(description = "岗位,枚举值:ANNOTATOR标注员、DATA_TRAINER数据训练师、REVIEWER审核员、ADMIN超级管理员", example = "ANNOTATOR") @NotNull(message = "不能为空") UserPosition position ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/LoginRequest.java b/src/main/java/com/labelsys/backend/dto/request/LoginRequest.java index a47f8f9..ccddbcf 100644 --- a/src/main/java/com/labelsys/backend/dto/request/LoginRequest.java +++ b/src/main/java/com/labelsys/backend/dto/request/LoginRequest.java @@ -5,8 +5,8 @@ import jakarta.validation.constraints.NotBlank; @Schema(description = "登录请求") public record LoginRequest( - @Schema(description = "手机号") @NotBlank(message = "不能为空") String phone, - @Schema(description = "公司编码") @NotBlank(message = "不能为空") String companyCode, - @Schema(description = "登录密码") @NotBlank(message = "不能为空") String password + @Schema(description = "手机号", example = "平台管理员:13900000000") @NotBlank(message = "不能为空") String phone, + @Schema(description = "公司编码", example = "平台编号:PLATFORM") @NotBlank(message = "不能为空") String companyCode, + @Schema(description = "登录密码", example = "平台密码:admin@123") @NotBlank(message = "不能为空") String password ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/ManualModelConfigRequest.java b/src/main/java/com/labelsys/backend/dto/request/ManualModelConfigRequest.java index 6fce101..85d2eeb 100644 --- a/src/main/java/com/labelsys/backend/dto/request/ManualModelConfigRequest.java +++ b/src/main/java/com/labelsys/backend/dto/request/ManualModelConfigRequest.java @@ -5,8 +5,8 @@ import jakarta.validation.constraints.NotBlank; @Schema(description = "手动模型配置请求") public record ManualModelConfigRequest( - @Schema(description = "模型名称") @NotBlank(message = "模型名称不能为空") String modelName, - @Schema(description = "模型地址") @NotBlank(message = "模型地址不能为空") String modelUrl, - @Schema(description = "模型密钥") @NotBlank(message = "模型密钥不能为空") String apiKey + @Schema(description = "模型名称", example = "qwen-plus") @NotBlank(message = "模型名称不能为空") String modelName, + @Schema(description = "模型地址", example = "https://dashscope.aliyuncs.com/compatible-mode/v1") @NotBlank(message = "模型地址不能为空") String modelUrl, + @Schema(description = "模型密钥", example = "sk-demo1234") @NotBlank(message = "模型密钥不能为空") String apiKey ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/MergeReviewResultRequest.java b/src/main/java/com/labelsys/backend/dto/request/MergeReviewResultRequest.java index dc51d22..d8bc6ab 100644 --- a/src/main/java/com/labelsys/backend/dto/request/MergeReviewResultRequest.java +++ b/src/main/java/com/labelsys/backend/dto/request/MergeReviewResultRequest.java @@ -5,8 +5,8 @@ import jakarta.validation.constraints.NotBlank; @Schema(description = "合并审核结果请求") public record MergeReviewResultRequest( - @Schema(description = "差异摘要 JSON") @NotBlank(message = "差异摘要不能为空") String diffSummary, - @Schema(description = "最终问答内容 JSON") @NotBlank(message = "问答内容不能为空") String qaContentJson, - @Schema(description = "审核备注") String reviewComment + @Schema(description = "差异摘要 JSON", example = "{\"changed\":[{\"field\":\"answer\",\"from\":\"3天\",\"to\":\"72小时\"}],\"summary\":\"统一时间表达\"}") @NotBlank(message = "差异摘要不能为空") String diffSummary, + @Schema(description = "最终问答内容 JSON", example = "[{\"question\":\"运输时效是多久?\",\"answer\":\"72小时\"}]") @NotBlank(message = "问答内容不能为空") String qaContentJson, + @Schema(description = "审核备注", example = "已按审核意见合并,统一为小时口径。") String reviewComment ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/PromptConfigOptionRequest.java b/src/main/java/com/labelsys/backend/dto/request/PromptConfigOptionRequest.java index 19f0b9c..e8a1195 100644 --- a/src/main/java/com/labelsys/backend/dto/request/PromptConfigOptionRequest.java +++ b/src/main/java/com/labelsys/backend/dto/request/PromptConfigOptionRequest.java @@ -4,7 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "任务提示词配置请求") public record PromptConfigOptionRequest( - @Schema(description = "已选择的提示词配置名称") String selectedConfigName, - @Schema(description = "手动输入的提示词内容") String promptText + @Schema(description = "已选择的提示词配置名称", example = "qa-extract-v1") String selectedConfigName, + @Schema(description = "手动输入的提示词内容", example = "请抽取文档中的问答对,并按 JSON 数组输出。") String promptText ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/SaveSysConfigRequest.java b/src/main/java/com/labelsys/backend/dto/request/SaveSysConfigRequest.java index 566c56f..e03e773 100644 --- a/src/main/java/com/labelsys/backend/dto/request/SaveSysConfigRequest.java +++ b/src/main/java/com/labelsys/backend/dto/request/SaveSysConfigRequest.java @@ -5,9 +5,9 @@ import jakarta.validation.constraints.NotBlank; @Schema(description = "保存系统配置请求") public record SaveSysConfigRequest( - @Schema(description = "配置类型") @NotBlank(message = "配置类型不能为空") String configType, - @Schema(description = "配置名称") @NotBlank(message = "配置名称不能为空") String configName, - @Schema(description = "配置值") @NotBlank(message = "配置值不能为空") String configValue, - @Schema(description = "配置状态") @NotBlank(message = "配置状态不能为空") String status + @Schema(description = "配置类型", example = "MODEL") @NotBlank(message = "配置类型不能为空") String configType, + @Schema(description = "配置名称", example = "qwen-plus-extract") @NotBlank(message = "配置名称不能为空") String configName, + @Schema(description = "配置值", example = "{\"modelName\":\"qwen-plus\",\"modelUrl\":\"https://dashscope.aliyuncs.com/compatible-mode/v1\",\"apiKey\":\"sk-demo1234\"}") @NotBlank(message = "配置值不能为空") String configValue, + @Schema(description = "配置状态", example = "ENABLED") @NotBlank(message = "配置状态不能为空") String status ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/SourceResourcePageQuery.java b/src/main/java/com/labelsys/backend/dto/request/SourceResourcePageQuery.java index 84a50ab..ee2c21e 100644 --- a/src/main/java/com/labelsys/backend/dto/request/SourceResourcePageQuery.java +++ b/src/main/java/com/labelsys/backend/dto/request/SourceResourcePageQuery.java @@ -4,10 +4,10 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "资源分页查询请求") public record SourceResourcePageQuery( - @Schema(description = "关键字") String keyword, - @Schema(description = "资源类型") String resourceType, - @Schema(description = "资源状态") String sourceStatus, - @Schema(description = "页码") Integer pageNo, - @Schema(description = "每页数量") Integer pageSize + @Schema(description = "关键字", example = "运输") String keyword, + @Schema(description = "资源类型", example = "TEXT") String resourceType, + @Schema(description = "资源状态", example = "READY") String sourceStatus, + @Schema(description = "页码", example = "1") Integer pageNo, + @Schema(description = "每页数量", example = "10") Integer pageSize ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/SourceUploadRequest.java b/src/main/java/com/labelsys/backend/dto/request/SourceUploadRequest.java index e84a548..38eb0ea 100644 --- a/src/main/java/com/labelsys/backend/dto/request/SourceUploadRequest.java +++ b/src/main/java/com/labelsys/backend/dto/request/SourceUploadRequest.java @@ -8,15 +8,15 @@ import org.springframework.web.multipart.MultipartFile; @Schema(description = "资源上传请求") public class SourceUploadRequest { - @Schema(description = "资源名称") + @Schema(description = "资源名称", example = "2026年4月运输巡检记录") private String resourceName; - @Schema(description = "资源类型:TEXT、IMAGE、VIDEO") + @Schema(description = "资源类型:TEXT、IMAGE、VIDEO", example = "TEXT") private String resourceType; - @Schema(description = "备注") + @Schema(description = "备注", example = "第一批导入样本") private String remark; - @Schema(description = "上传文件") + @Schema(description = "上传文件", example = "inspection-record.txt") private MultipartFile file; } diff --git a/src/main/java/com/labelsys/backend/dto/request/SysConfigPageQuery.java b/src/main/java/com/labelsys/backend/dto/request/SysConfigPageQuery.java index 38aff48..e2af1be 100644 --- a/src/main/java/com/labelsys/backend/dto/request/SysConfigPageQuery.java +++ b/src/main/java/com/labelsys/backend/dto/request/SysConfigPageQuery.java @@ -4,10 +4,10 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "系统配置分页查询请求") public record SysConfigPageQuery( - @Schema(description = "配置类型") String configType, - @Schema(description = "配置名称") String configName, - @Schema(description = "配置状态") String status, - @Schema(description = "页码") Integer pageNo, - @Schema(description = "每页数量") Integer pageSize + @Schema(description = "配置类型", example = "MODEL") String configType, + @Schema(description = "配置名称", example = "qwen-plus-extract") String configName, + @Schema(description = "配置状态", example = "ENABLED") String status, + @Schema(description = "页码", example = "1") Integer pageNo, + @Schema(description = "每页数量", example = "10") Integer pageSize ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/TaskModelConfigRequest.java b/src/main/java/com/labelsys/backend/dto/request/TaskModelConfigRequest.java index b242b89..c5d59fc 100644 --- a/src/main/java/com/labelsys/backend/dto/request/TaskModelConfigRequest.java +++ b/src/main/java/com/labelsys/backend/dto/request/TaskModelConfigRequest.java @@ -6,8 +6,8 @@ import jakarta.validation.constraints.NotBlank; @Schema(description = "任务模型配置请求") public record TaskModelConfigRequest( - @Schema(description = "配置模式:SELECT 或 MANUAL") @NotBlank(message = "配置模式不能为空") String mode, - @Schema(description = "已选择的配置名称") String selectedConfigName, - @Schema(description = "手动录入的模型配置") @Valid ManualModelConfigRequest manualConfig + @Schema(description = "配置模式:SELECT 或 MANUAL", example = "SELECT") @NotBlank(message = "配置模式不能为空") String mode, + @Schema(description = "已选择的配置名称", example = "qwen-plus-extract") String selectedConfigName, + @Schema(description = "手动录入的模型配置", example = "{\"modelName\":\"qwen-plus\",\"modelUrl\":\"https://dashscope.aliyuncs.com/compatible-mode/v1\",\"apiKey\":\"sk-demo1234\"}") @Valid ManualModelConfigRequest manualConfig ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/UpdateAnnotationTaskRequest.java b/src/main/java/com/labelsys/backend/dto/request/UpdateAnnotationTaskRequest.java index 4b8b55b..556d67c 100644 --- a/src/main/java/com/labelsys/backend/dto/request/UpdateAnnotationTaskRequest.java +++ b/src/main/java/com/labelsys/backend/dto/request/UpdateAnnotationTaskRequest.java @@ -7,12 +7,12 @@ import java.util.List; @Schema(description = "更新标注任务请求") public record UpdateAnnotationTaskRequest( - @Schema(description = "行业类型") String industryType, - @Schema(description = "任务类型") String taskType, - @Schema(description = "资源ID列表") @NotEmpty(message = "资源列表不能为空") List resourceIds, - @Schema(description = "抽取模型配置") @Valid TaskModelConfigRequest extractModel, - @Schema(description = "校验模型配置") @Valid TaskModelConfigRequest verifyModel, - @Schema(description = "抽取提示词配置") @Valid PromptConfigOptionRequest extractPrompt, - @Schema(description = "校验提示词配置") @Valid PromptConfigOptionRequest verifyPrompt + @Schema(description = "行业类型", example = "transport") String industryType, + @Schema(description = "任务类型", example = "EXTRACT_QA") String taskType, + @Schema(description = "资源ID列表", example = "[191000000000000101,191000000000000102]") @NotEmpty(message = "资源列表不能为空") List resourceIds, + @Schema(description = "抽取模型配置", example = "{\"mode\":\"SELECT\",\"selectedConfigName\":\"qwen-plus-extract\"}") @Valid TaskModelConfigRequest extractModel, + @Schema(description = "校验模型配置", example = "{\"mode\":\"MANUAL\",\"manualConfig\":{\"modelName\":\"qwen-max\",\"modelUrl\":\"https://dashscope.aliyuncs.com/compatible-mode/v1\",\"apiKey\":\"sk-demo5678\"}}") @Valid TaskModelConfigRequest verifyModel, + @Schema(description = "抽取提示词配置", example = "{\"selectedConfigName\":\"qa-extract-v1\"}") @Valid PromptConfigOptionRequest extractPrompt, + @Schema(description = "校验提示词配置", example = "{\"promptText\":\"请对抽取结果进行逐项校验,并输出差异说明。\"}") @Valid PromptConfigOptionRequest verifyPrompt ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/UpdateCompanyStatusRequest.java b/src/main/java/com/labelsys/backend/dto/request/UpdateCompanyStatusRequest.java index 6b42560..fcb7544 100644 --- a/src/main/java/com/labelsys/backend/dto/request/UpdateCompanyStatusRequest.java +++ b/src/main/java/com/labelsys/backend/dto/request/UpdateCompanyStatusRequest.java @@ -6,6 +6,6 @@ import jakarta.validation.constraints.NotNull; @Schema(description = "修改公司状态请求") public record UpdateCompanyStatusRequest( - @Schema(description = "公司状态,枚举值:ENABLED启用、DISABLED禁用") @NotNull(message = "不能为空") CompanyStatus status + @Schema(description = "公司状态,枚举值:ENABLED启用、DISABLED禁用", example = "ENABLED") @NotNull(message = "不能为空") CompanyStatus status ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/UpdateUserAssignmentRequest.java b/src/main/java/com/labelsys/backend/dto/request/UpdateUserAssignmentRequest.java index 6e050dd..d057c7d 100644 --- a/src/main/java/com/labelsys/backend/dto/request/UpdateUserAssignmentRequest.java +++ b/src/main/java/com/labelsys/backend/dto/request/UpdateUserAssignmentRequest.java @@ -7,7 +7,7 @@ import jakarta.validation.constraints.NotNull; @Schema(description = "修改员工角色岗位请求") public record UpdateUserAssignmentRequest( - @Schema(description = "角色,枚举值:EMPLOYEE员工、MANAGER部门经理、ENGINEER总工程师") @NotNull(message = "不能为空") UserRole role, - @Schema(description = "岗位,枚举值:ANNOTATOR标注员、DATA_TRAINER数据训练师、REVIEWER审核员、ADMIN超级管理员") @NotNull(message = "不能为空") UserPosition position + @Schema(description = "角色,枚举值:EMPLOYEE员工、MANAGER部门经理、ENGINEER总工程师", example = "EMPLOYEE") @NotNull(message = "不能为空") UserRole role, + @Schema(description = "岗位,枚举值:ANNOTATOR标注员、DATA_TRAINER数据训练师、REVIEWER审核员、ADMIN超级管理员", example = "REVIEWER") @NotNull(message = "不能为空") UserPosition position ) { } diff --git a/src/main/java/com/labelsys/backend/dto/request/UpdateUserStatusRequest.java b/src/main/java/com/labelsys/backend/dto/request/UpdateUserStatusRequest.java index 9548dd4..b9d220c 100644 --- a/src/main/java/com/labelsys/backend/dto/request/UpdateUserStatusRequest.java +++ b/src/main/java/com/labelsys/backend/dto/request/UpdateUserStatusRequest.java @@ -6,6 +6,6 @@ import jakarta.validation.constraints.NotNull; @Schema(description = "修改员工状态请求") public record UpdateUserStatusRequest( - @Schema(description = "用户状态,枚举值:ENABLED启用、DISABLED禁用") @NotNull(message = "不能为空") UserStatus status + @Schema(description = "用户状态,枚举值:ENABLED启用、DISABLED禁用", example = "DISABLED") @NotNull(message = "不能为空") UserStatus status ) { } diff --git a/src/main/java/com/labelsys/backend/dto/response/AnnotationResultCompareResponse.java b/src/main/java/com/labelsys/backend/dto/response/AnnotationResultCompareResponse.java index 45d5e05..87ee883 100644 --- a/src/main/java/com/labelsys/backend/dto/response/AnnotationResultCompareResponse.java +++ b/src/main/java/com/labelsys/backend/dto/response/AnnotationResultCompareResponse.java @@ -4,13 +4,13 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "标注结果比对响应") public record AnnotationResultCompareResponse( - @Schema(description = "结果ID") Long id, - @Schema(description = "任务ID") Long taskId, - @Schema(description = "资源ID") Long resourceId, - @Schema(description = "问答内容 JSON") String qaContentJson, - @Schema(description = "差异摘要 JSON") String diffSummary, - @Schema(description = "问答存储模式") String qaContentStorageMode, - @Schema(description = "外置问答文件路径") String qaContentFilePath, - @Schema(description = "资源预览路径") String sourcePreviewPath + @Schema(description = "结果ID", example = "191000000000000401") Long id, + @Schema(description = "任务ID", example = "191000000000000301") Long taskId, + @Schema(description = "资源ID", example = "191000000000000101") Long resourceId, + @Schema(description = "问答内容 JSON", example = "[{\"question\":\"运输时效是多久?\",\"answer\":\"3天\"}]") String qaContentJson, + @Schema(description = "差异摘要 JSON", example = "{\"changed\":[{\"field\":\"answer\",\"from\":\"3天\",\"to\":\"72小时\"}],\"summary\":\"统一时间表达\"}") String diffSummary, + @Schema(description = "问答存储模式", example = "EXTERNAL") String qaContentStorageMode, + @Schema(description = "外置问答文件路径", example = "review/191000000000000401/qa-content.json") String qaContentFilePath, + @Schema(description = "资源预览路径", example = "preview/191000000000000101/index.html") String sourcePreviewPath ) { } diff --git a/src/main/java/com/labelsys/backend/dto/response/AnnotationResultResponse.java b/src/main/java/com/labelsys/backend/dto/response/AnnotationResultResponse.java index 88bdcb7..34d0135 100644 --- a/src/main/java/com/labelsys/backend/dto/response/AnnotationResultResponse.java +++ b/src/main/java/com/labelsys/backend/dto/response/AnnotationResultResponse.java @@ -5,15 +5,15 @@ import java.time.LocalDateTime; @Schema(description = "标注结果响应") public record AnnotationResultResponse( - @Schema(description = "结果ID") Long id, - @Schema(description = "任务ID") Long taskId, - @Schema(description = "资源ID") Long resourceId, - @Schema(description = "运行态状态") String runtimeStatus, - @Schema(description = "是否需要人工审核") Boolean requiresManualReview, - @Schema(description = "是否已删除") Boolean isDeleted, - @Schema(description = "问答存储模式") String qaContentStorageMode, - @Schema(description = "审核备注") String reviewComment, - @Schema(description = "审核时间") LocalDateTime reviewedAt, - @Schema(description = "创建时间") LocalDateTime createdAt + @Schema(description = "结果ID", example = "191000000000000401") Long id, + @Schema(description = "任务ID", example = "191000000000000301") Long taskId, + @Schema(description = "资源ID", example = "191000000000000101") Long resourceId, + @Schema(description = "运行态状态", example = "MANUAL_REVIEW_PENDING") String runtimeStatus, + @Schema(description = "是否需要人工审核", example = "true") Boolean requiresManualReview, + @Schema(description = "是否已删除", example = "false") Boolean isDeleted, + @Schema(description = "问答存储模式", example = "INLINE") String qaContentStorageMode, + @Schema(description = "审核备注", example = "需统一时间字段口径。") String reviewComment, + @Schema(description = "审核时间", example = "2026-04-27T11:00:00") LocalDateTime reviewedAt, + @Schema(description = "创建时间", example = "2026-04-27T10:40:00") LocalDateTime createdAt ) { } diff --git a/src/main/java/com/labelsys/backend/dto/response/AnnotationTaskResponse.java b/src/main/java/com/labelsys/backend/dto/response/AnnotationTaskResponse.java index d9255d3..0769434 100644 --- a/src/main/java/com/labelsys/backend/dto/response/AnnotationTaskResponse.java +++ b/src/main/java/com/labelsys/backend/dto/response/AnnotationTaskResponse.java @@ -6,17 +6,17 @@ import java.util.List; @Schema(description = "标注任务响应") public record AnnotationTaskResponse( - @Schema(description = "任务ID") Long id, - @Schema(description = "任务名称") String taskName, - @Schema(description = "行业类型") String industryType, - @Schema(description = "任务类型") String taskType, - @Schema(description = "任务状态") String taskStatus, - @Schema(description = "资源ID列表") List resourceIds, - @Schema(description = "抽取模型配置") TaskModelConfigResponse extractModel, - @Schema(description = "校验模型配置") TaskModelConfigResponse verifyModel, - @Schema(description = "抽取提示词配置") TaskPromptConfigResponse extractPrompt, - @Schema(description = "校验提示词配置") TaskPromptConfigResponse verifyPrompt, - @Schema(description = "创建时间") LocalDateTime createdAt, - @Schema(description = "更新时间") LocalDateTime updatedAt + @Schema(description = "任务ID", example = "191000000000000301") Long id, + @Schema(description = "任务名称", example = "运输文档问答抽取任务") String taskName, + @Schema(description = "行业类型:默认值transport,暂不显示", example = "transport") String industryType, + @Schema(description = "任务类型:暂不显示", example = "EXTRACT_QA") String taskType, + @Schema(description = "任务状态", example = "PENDING") String taskStatus, + @Schema(description = "资源ID列表", example = "[191000000000000101,191000000000000102]") List resourceIds, + @Schema(description = "抽取模型配置", example = "{\"configId\":191000000000000511,\"configName\":\"qwen-plus-extract\",\"modelName\":\"qwen-plus\",\"modelUrl\":\"https://dashscope.aliyuncs.com/compatible-mode/v1\",\"maskedApiKey\":\"****1234\"}") TaskModelConfigResponse extractModel, + @Schema(description = "校验模型配置", example = "{\"configId\":191000000000000512,\"configName\":\"qwen-max-verify\",\"modelName\":\"qwen-max\",\"modelUrl\":\"https://dashscope.aliyuncs.com/compatible-mode/v1\",\"maskedApiKey\":\"****5678\"}") TaskModelConfigResponse verifyModel, + @Schema(description = "抽取提示词配置", example = "{\"configId\":191000000000000521,\"configName\":\"qa-extract-v1\",\"promptText\":\"请抽取文档中的问答对,并按 JSON 数组输出。\"}") TaskPromptConfigResponse extractPrompt, + @Schema(description = "校验提示词配置", example = "{\"configId\":191000000000000522,\"configName\":\"qa-verify-v1\",\"promptText\":\"请对抽取结果进行逐项校验,并输出差异说明。\"}") TaskPromptConfigResponse verifyPrompt, + @Schema(description = "创建时间", example = "2026-04-27T10:20:00") LocalDateTime createdAt, + @Schema(description = "更新时间", example = "2026-04-27T10:30:00") LocalDateTime updatedAt ) { } diff --git a/src/main/java/com/labelsys/backend/dto/response/CompanyOptionResponse.java b/src/main/java/com/labelsys/backend/dto/response/CompanyOptionResponse.java index 4123641..cacc555 100644 --- a/src/main/java/com/labelsys/backend/dto/response/CompanyOptionResponse.java +++ b/src/main/java/com/labelsys/backend/dto/response/CompanyOptionResponse.java @@ -5,9 +5,9 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "可登录公司选项") public record CompanyOptionResponse( - @Schema(description = "公司ID") Long companyId, - @Schema(description = "公司编码") String companyCode, - @Schema(description = "公司名称") String companyName + @Schema(description = "公司ID", example = "191000000000000001") Long companyId, + @Schema(description = "公司编码", example = "ALPHA") String companyCode, + @Schema(description = "公司名称", example = "阿尔法标注有限公司") String companyName ) { public static CompanyOptionResponse from(SysCompany company) { return new CompanyOptionResponse(company.getId(), company.getCompanyCode(), company.getCompanyName()); diff --git a/src/main/java/com/labelsys/backend/dto/response/CompanyResponse.java b/src/main/java/com/labelsys/backend/dto/response/CompanyResponse.java index 2ed7439..c7416fe 100644 --- a/src/main/java/com/labelsys/backend/dto/response/CompanyResponse.java +++ b/src/main/java/com/labelsys/backend/dto/response/CompanyResponse.java @@ -6,10 +6,10 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "公司响应") public record CompanyResponse( - @Schema(description = "公司ID") Long companyId, - @Schema(description = "公司编码") String companyCode, - @Schema(description = "公司名称") String companyName, - @Schema(description = "公司状态,枚举值:ENABLED启用、DISABLED禁用") CompanyStatus status + @Schema(description = "公司ID", example = "191000000000000001") Long companyId, + @Schema(description = "公司编码", example = "ALPHA") String companyCode, + @Schema(description = "公司名称", example = "阿尔法标注有限公司") String companyName, + @Schema(description = "公司状态,枚举值:ENABLED启用、DISABLED禁用", example = "ENABLED") CompanyStatus status ) { public static CompanyResponse from(SysCompany company) { return new CompanyResponse(company.getId(), company.getCompanyCode(), company.getCompanyName(), company.getStatus()); diff --git a/src/main/java/com/labelsys/backend/dto/response/CurrentUserResponse.java b/src/main/java/com/labelsys/backend/dto/response/CurrentUserResponse.java index 5f5514f..844a9d9 100644 --- a/src/main/java/com/labelsys/backend/dto/response/CurrentUserResponse.java +++ b/src/main/java/com/labelsys/backend/dto/response/CurrentUserResponse.java @@ -7,16 +7,16 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "当前登录用户响应") public record CurrentUserResponse( - @Schema(description = "用户ID") Long userId, - @Schema(description = "公司ID") Long companyId, - @Schema(description = "公司编码") String companyCode, - @Schema(description = "公司名称") String companyName, - @Schema(description = "手机号") String phone, + @Schema(description = "用户ID", example = "191000000000000021") Long userId, + @Schema(description = "公司ID", example = "191000000000000001") Long companyId, + @Schema(description = "公司编码", example = "ALPHA") String companyCode, + @Schema(description = "公司名称", example = "阿尔法标注有限公司") String companyName, + @Schema(description = "手机号", example = "13800138002") String phone, @Schema(description = "用户名,可为空", example = "alpha-admin") String username, - @Schema(description = "真实姓名") String realName, - @Schema(description = "角色,枚举值:EMPLOYEE员工、MANAGER部门经理、ENGINEER总工程师") UserRole role, - @Schema(description = "岗位,枚举值:ANNOTATOR标注员、DATA_TRAINER数据训练师、REVIEWER审核员、ADMIN超级管理员") UserPosition position, - @Schema(description = "是否必须修改密码") boolean mustChangePassword + @Schema(description = "真实姓名", example = "张审核") String realName, + @Schema(description = "角色,枚举值:EMPLOYEE员工、MANAGER部门经理、ENGINEER总工程师", example = "EMPLOYEE") UserRole role, + @Schema(description = "岗位,枚举值:ANNOTATOR标注员、DATA_TRAINER数据训练师、REVIEWER审核员、ADMIN超级管理员", example = "REVIEWER") UserPosition position, + @Schema(description = "是否必须修改密码", example = "false") boolean mustChangePassword ) { public static CurrentUserResponse from(LoginUser loginUser) { return new CurrentUserResponse( diff --git a/src/main/java/com/labelsys/backend/dto/response/LoginResponse.java b/src/main/java/com/labelsys/backend/dto/response/LoginResponse.java index 01d4617..ce5aeb1 100644 --- a/src/main/java/com/labelsys/backend/dto/response/LoginResponse.java +++ b/src/main/java/com/labelsys/backend/dto/response/LoginResponse.java @@ -8,14 +8,14 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "登录响应") public record LoginResponse( - @Schema(description = "访问令牌") String token, - @Schema(description = "当前公司信息") CompanyOptionResponse company, - @Schema(description = "手机号") String phone, + @Schema(description = "访问令牌", example = "eyJhbGciOiJIUzI1NiJ9.demo.token") String token, + @Schema(description = "当前公司信息", example = "{\"companyId\":191000000000000001,\"companyCode\":\"ALPHA\",\"companyName\":\"阿尔法标注有限公司\"}") CompanyOptionResponse company, + @Schema(description = "手机号", example = "13800138002") String phone, @Schema(description = "用户名,可为空", example = "alpha-admin") String username, - @Schema(description = "真实姓名") String realName, - @Schema(description = "角色,枚举值:EMPLOYEE员工、MANAGER部门经理、ENGINEER总工程师") UserRole role, - @Schema(description = "岗位,枚举值:ANNOTATOR标注员、DATA_TRAINER数据训练师、REVIEWER审核员、ADMIN超级管理员") UserPosition position, - @Schema(description = "是否必须修改密码") boolean mustChangePassword + @Schema(description = "真实姓名", example = "张审核") String realName, + @Schema(description = "角色,枚举值:EMPLOYEE员工、MANAGER部门经理、ENGINEER总工程师", example = "EMPLOYEE") UserRole role, + @Schema(description = "岗位,枚举值:ANNOTATOR标注员、DATA_TRAINER数据训练师、REVIEWER审核员、ADMIN超级管理员", example = "REVIEWER") UserPosition position, + @Schema(description = "是否必须修改密码", example = "false") boolean mustChangePassword ) { public static LoginResponse from(String token, LoginUser loginUser, SysCompany company) { return new LoginResponse( diff --git a/src/main/java/com/labelsys/backend/dto/response/MenuResponse.java b/src/main/java/com/labelsys/backend/dto/response/MenuResponse.java index 66c67a9..eb28005 100644 --- a/src/main/java/com/labelsys/backend/dto/response/MenuResponse.java +++ b/src/main/java/com/labelsys/backend/dto/response/MenuResponse.java @@ -5,10 +5,10 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "菜单响应") public record MenuResponse( - @Schema(description = "菜单编码") String menuCode, - @Schema(description = "菜单名称") String menuName, - @Schema(description = "菜单路径") String path, - @Schema(description = "排序") Integer sortOrder + @Schema(description = "菜单编码", example = "annotation.task.list") String menuCode, + @Schema(description = "菜单名称", example = "标注任务") String menuName, + @Schema(description = "菜单路径", example = "/annotation/tasks") String path, + @Schema(description = "排序", example = "10") Integer sortOrder ) { public static MenuResponse from(SysMenu menu) { return new MenuResponse(menu.getMenuCode(), menu.getMenuName(), menu.getPath(), menu.getSortOrder()); diff --git a/src/main/java/com/labelsys/backend/dto/response/MergeReviewResultResponse.java b/src/main/java/com/labelsys/backend/dto/response/MergeReviewResultResponse.java index 4af8e53..7dda5fd 100644 --- a/src/main/java/com/labelsys/backend/dto/response/MergeReviewResultResponse.java +++ b/src/main/java/com/labelsys/backend/dto/response/MergeReviewResultResponse.java @@ -5,9 +5,9 @@ import java.time.LocalDateTime; @Schema(description = "合并审核结果响应") public record MergeReviewResultResponse( - @Schema(description = "运行态结果ID") Long resultId, - @Schema(description = "历史结果ID") Long historyId, - @Schema(description = "归档原因") String archiveReason, - @Schema(description = "归档时间") LocalDateTime archivedAt + @Schema(description = "运行态结果ID", example = "191000000000000401") Long resultId, + @Schema(description = "历史结果ID", example = "191000000000000451") Long historyId, + @Schema(description = "归档原因", example = "MANUAL_REVIEW_MERGED") String archiveReason, + @Schema(description = "归档时间", example = "2026-04-27T11:05:00") LocalDateTime archivedAt ) { } diff --git a/src/main/java/com/labelsys/backend/dto/response/SourceResourceResponse.java b/src/main/java/com/labelsys/backend/dto/response/SourceResourceResponse.java index 1922ccc..7488aa8 100644 --- a/src/main/java/com/labelsys/backend/dto/response/SourceResourceResponse.java +++ b/src/main/java/com/labelsys/backend/dto/response/SourceResourceResponse.java @@ -5,17 +5,17 @@ import java.time.LocalDateTime; @Schema(description = "资源响应") public record SourceResourceResponse( - @Schema(description = "资源ID") Long id, - @Schema(description = "资源名称") String resourceName, - @Schema(description = "资源类型") String resourceType, - @Schema(description = "桶名称") String bucketName, - @Schema(description = "文件路径") String filePath, - @Schema(description = "文件大小") Long fileSize, - @Schema(description = "资源状态") String sourceStatus, - @Schema(description = "存储提供方") String storageProvider, - @Schema(description = "备注") String remark, - @Schema(description = "创建人名称") String creatorName, - @Schema(description = "创建时间") LocalDateTime createdAt, - @Schema(description = "更新时间") LocalDateTime updatedAt + @Schema(description = "资源ID", example = "191000000000000101") Long id, + @Schema(description = "资源名称", example = "2026年4月运输巡检记录") String resourceName, + @Schema(description = "资源类型", example = "TEXT") String resourceType, + @Schema(description = "桶名称", example = "annotation-source") String bucketName, + @Schema(description = "文件路径", example = "company/191000000000000001/text/191000000000000101.txt") String filePath, + @Schema(description = "文件大小", example = "20480") Long fileSize, + @Schema(description = "资源状态", example = "READY") String sourceStatus, + @Schema(description = "存储提供方", example = "rustfs") String storageProvider, + @Schema(description = "备注", example = "第一批导入样本") String remark, + @Schema(description = "创建人名称", example = "张审核") String creatorName, + @Schema(description = "创建时间", example = "2026-04-27T10:00:00") LocalDateTime createdAt, + @Schema(description = "更新时间", example = "2026-04-27T10:05:00") LocalDateTime updatedAt ) { } diff --git a/src/main/java/com/labelsys/backend/dto/response/SourceUploadResponse.java b/src/main/java/com/labelsys/backend/dto/response/SourceUploadResponse.java index 7029138..6145246 100644 --- a/src/main/java/com/labelsys/backend/dto/response/SourceUploadResponse.java +++ b/src/main/java/com/labelsys/backend/dto/response/SourceUploadResponse.java @@ -5,13 +5,13 @@ import java.time.LocalDateTime; @Schema(description = "资源上传响应") public record SourceUploadResponse( - @Schema(description = "资源ID") Long id, - @Schema(description = "资源名称") String resourceName, - @Schema(description = "资源类型") String resourceType, - @Schema(description = "桶名称") String bucketName, - @Schema(description = "文件路径") String filePath, - @Schema(description = "文件大小") Long fileSize, - @Schema(description = "资源状态") String sourceStatus, - @Schema(description = "创建时间") LocalDateTime createdAt + @Schema(description = "资源ID", example = "191000000000000101") Long id, + @Schema(description = "资源名称", example = "2026年4月运输巡检记录") String resourceName, + @Schema(description = "资源类型", example = "TEXT") String resourceType, + @Schema(description = "桶名称", example = "annotation-source") String bucketName, + @Schema(description = "文件路径", example = "company/191000000000000001/text/191000000000000101.txt") String filePath, + @Schema(description = "文件大小", example = "20480") Long fileSize, + @Schema(description = "资源状态", example = "READY") String sourceStatus, + @Schema(description = "创建时间", example = "2026-04-27T10:00:00") LocalDateTime createdAt ) { } diff --git a/src/main/java/com/labelsys/backend/dto/response/SysConfigResponse.java b/src/main/java/com/labelsys/backend/dto/response/SysConfigResponse.java index 67b53fa..f0ff9c8 100644 --- a/src/main/java/com/labelsys/backend/dto/response/SysConfigResponse.java +++ b/src/main/java/com/labelsys/backend/dto/response/SysConfigResponse.java @@ -5,13 +5,13 @@ import java.time.LocalDateTime; @Schema(description = "系统配置响应") public record SysConfigResponse( - @Schema(description = "配置ID") Long id, - @Schema(description = "配置类型") String configType, - @Schema(description = "配置名称") String configName, - @Schema(description = "配置值") String configValue, - @Schema(description = "配置状态") String status, - @Schema(description = "创建人ID") Long creatorId, - @Schema(description = "创建时间") LocalDateTime createdAt, - @Schema(description = "更新时间") LocalDateTime updatedAt + @Schema(description = "配置ID", example = "191000000000000501") Long id, + @Schema(description = "配置类型", example = "MODEL") String configType, + @Schema(description = "配置名称", example = "qwen-plus-extract") String configName, + @Schema(description = "配置值", example = "{\"modelName\":\"qwen-plus\",\"modelUrl\":\"https://dashscope.aliyuncs.com/compatible-mode/v1\",\"apiKey\":\"sk-demo1234\"}") String configValue, + @Schema(description = "配置状态", example = "ENABLED") String status, + @Schema(description = "创建人ID", example = "191000000000000021") Long creatorId, + @Schema(description = "创建时间", example = "2026-04-27T09:50:00") LocalDateTime createdAt, + @Schema(description = "更新时间", example = "2026-04-27T10:15:00") LocalDateTime updatedAt ) { } diff --git a/src/main/java/com/labelsys/backend/dto/response/TaskModelConfigResponse.java b/src/main/java/com/labelsys/backend/dto/response/TaskModelConfigResponse.java index 6ead3e0..fdb608b 100644 --- a/src/main/java/com/labelsys/backend/dto/response/TaskModelConfigResponse.java +++ b/src/main/java/com/labelsys/backend/dto/response/TaskModelConfigResponse.java @@ -4,10 +4,10 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "任务模型配置响应") public record TaskModelConfigResponse( - @Schema(description = "配置ID") Long configId, - @Schema(description = "配置名称") String configName, - @Schema(description = "模型名称") String modelName, - @Schema(description = "模型地址") String modelUrl, - @Schema(description = "脱敏后的模型密钥") String maskedApiKey + @Schema(description = "配置ID", example = "191000000000000511") Long configId, + @Schema(description = "配置名称", example = "qwen-plus-extract") String configName, + @Schema(description = "模型名称", example = "qwen-plus") String modelName, + @Schema(description = "模型地址", example = "https://dashscope.aliyuncs.com/compatible-mode/v1") String modelUrl, + @Schema(description = "脱敏后的模型密钥", example = "****1234") String maskedApiKey ) { } diff --git a/src/main/java/com/labelsys/backend/dto/response/TaskPromptConfigResponse.java b/src/main/java/com/labelsys/backend/dto/response/TaskPromptConfigResponse.java index 91a4326..ad34b8a 100644 --- a/src/main/java/com/labelsys/backend/dto/response/TaskPromptConfigResponse.java +++ b/src/main/java/com/labelsys/backend/dto/response/TaskPromptConfigResponse.java @@ -4,8 +4,8 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "任务提示词配置响应") public record TaskPromptConfigResponse( - @Schema(description = "配置ID") Long configId, - @Schema(description = "配置名称") String configName, - @Schema(description = "提示词内容") String promptText + @Schema(description = "配置ID", example = "191000000000000521") Long configId, + @Schema(description = "配置名称", example = "qa-extract-v1") String configName, + @Schema(description = "提示词内容", example = "请抽取文档中的问答对,并按 JSON 数组输出。") String promptText ) { } diff --git a/src/main/java/com/labelsys/backend/dto/response/UserResponse.java b/src/main/java/com/labelsys/backend/dto/response/UserResponse.java index 6cc9148..7201efa 100644 --- a/src/main/java/com/labelsys/backend/dto/response/UserResponse.java +++ b/src/main/java/com/labelsys/backend/dto/response/UserResponse.java @@ -8,15 +8,15 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "用户响应") public record UserResponse( - @Schema(description = "用户ID") Long userId, - @Schema(description = "公司ID") Long companyId, - @Schema(description = "手机号") String phone, + @Schema(description = "用户ID", example = "191000000000000021") Long userId, + @Schema(description = "公司ID", example = "191000000000000001") Long companyId, + @Schema(description = "手机号", example = "13800138002") String phone, @Schema(description = "用户名,可为空", example = "alpha-admin") String username, - @Schema(description = "真实姓名") String realName, - @Schema(description = "角色,枚举值:EMPLOYEE员工、MANAGER部门经理、ENGINEER总工程师") UserRole role, - @Schema(description = "岗位,枚举值:ANNOTATOR标注员、DATA_TRAINER数据训练师、REVIEWER审核员、ADMIN超级管理员") UserPosition position, - @Schema(description = "用户状态,枚举值:ENABLED启用、DISABLED禁用") UserStatus status, - @Schema(description = "是否必须修改密码") boolean mustChangePassword + @Schema(description = "真实姓名", example = "张审核") String realName, + @Schema(description = "角色,枚举值:EMPLOYEE员工、MANAGER部门经理、ENGINEER总工程师", example = "EMPLOYEE") UserRole role, + @Schema(description = "岗位,枚举值:ANNOTATOR标注员、DATA_TRAINER数据训练师、REVIEWER审核员、ADMIN超级管理员", example = "REVIEWER") UserPosition position, + @Schema(description = "用户状态,枚举值:ENABLED启用、DISABLED禁用", example = "ENABLED") UserStatus status, + @Schema(description = "是否必须修改密码", example = "false") boolean mustChangePassword ) { public static UserResponse from(SysUser user) { return new UserResponse( diff --git a/src/main/java/com/labelsys/backend/enums/UserPosition.java b/src/main/java/com/labelsys/backend/enums/UserPosition.java index 3681151..55f3795 100644 --- a/src/main/java/com/labelsys/backend/enums/UserPosition.java +++ b/src/main/java/com/labelsys/backend/enums/UserPosition.java @@ -6,13 +6,13 @@ import lombok.RequiredArgsConstructor; @Getter @RequiredArgsConstructor -@Schema(description = "岗位枚举,枚举值:ANNOTATOR标注员、DATA_TRAINER数据训练师、REVIEWER审核员、ADMIN超级管理员") +@Schema(description = "岗位枚举,枚举值:ANNOTATOR标注员、DATA_TRAINER数据训练师、REVIEWER审核员、ADMIN公司管理员、SUPER_ADMIN超级管理员") public enum UserPosition { - ANNOTATOR(1), DATA_TRAINER(2), REVIEWER(3), ADMIN(4); + ANNOTATOR(1), DATA_TRAINER(2), REVIEWER(3), ADMIN(4), SUPER_ADMIN(5); private final int level; public boolean canAccess(UserPosition required) { return this.level >= required.level; } -} +} \ No newline at end of file diff --git a/src/main/java/com/labelsys/backend/mapper/AnnotationResultMapper.java b/src/main/java/com/labelsys/backend/mapper/AnnotationResultMapper.java index 2fc55bf..bdda150 100644 --- a/src/main/java/com/labelsys/backend/mapper/AnnotationResultMapper.java +++ b/src/main/java/com/labelsys/backend/mapper/AnnotationResultMapper.java @@ -14,4 +14,4 @@ public interface AnnotationResultMapper extends BaseMapper { @Param("reviewerId") Long reviewerId, @Param("reviewComment") String reviewComment, @Param("reviewedAt") LocalDateTime reviewedAt); -} +} \ No newline at end of file diff --git a/src/main/java/com/labelsys/backend/mapper/AnnotationTaskMapper.java b/src/main/java/com/labelsys/backend/mapper/AnnotationTaskMapper.java index 2be455b..35bd601 100644 --- a/src/main/java/com/labelsys/backend/mapper/AnnotationTaskMapper.java +++ b/src/main/java/com/labelsys/backend/mapper/AnnotationTaskMapper.java @@ -1,10 +1,11 @@ package com.labelsys.backend.mapper; +import org.apache.ibatis.annotations.Param; + import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.labelsys.backend.entity.AnnotationTask; -import org.apache.ibatis.annotations.Param; public interface AnnotationTaskMapper extends BaseMapper { AnnotationTask findByIdAndCompanyId(@Param("id") Long id, @Param("companyId") Long companyId); -} +} \ No newline at end of file diff --git a/src/main/java/com/labelsys/backend/mapper/SourceResourceMapper.java b/src/main/java/com/labelsys/backend/mapper/SourceResourceMapper.java index 0270e76..e583fea 100644 --- a/src/main/java/com/labelsys/backend/mapper/SourceResourceMapper.java +++ b/src/main/java/com/labelsys/backend/mapper/SourceResourceMapper.java @@ -8,4 +8,4 @@ import org.apache.ibatis.annotations.Param; public interface SourceResourceMapper extends BaseMapper { List selectByCompanyIdAndIds(@Param("companyId") Long companyId, @Param("resourceIds") List resourceIds); -} +} \ No newline at end of file diff --git a/src/main/java/com/labelsys/backend/service/AnnotationResultService.java b/src/main/java/com/labelsys/backend/service/AnnotationResultService.java index 195ef85..a5f66e8 100644 --- a/src/main/java/com/labelsys/backend/service/AnnotationResultService.java +++ b/src/main/java/com/labelsys/backend/service/AnnotationResultService.java @@ -1,6 +1,7 @@ package com.labelsys.backend.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.labelsys.backend.common.ResultCode; import com.labelsys.backend.common.exception.BusinessException; import com.labelsys.backend.context.LoginUser; @@ -13,44 +14,65 @@ import com.labelsys.backend.entity.SourceResource; import com.labelsys.backend.enums.RuntimeResultStatus; import com.labelsys.backend.mapper.AnnotationResultMapper; import com.labelsys.backend.mapper.SourceResourceMapper; -import java.util.Comparator; +import com.labelsys.backend.service.DataPermissionService; import java.util.List; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +@Slf4j @Service @RequiredArgsConstructor public class AnnotationResultService { private final AnnotationResultMapper annotationResultMapper; private final SourceResourceMapper sourceResourceMapper; + private final DataPermissionService dataPermissionService; public PageResult pageResults(LoginUser currentUser, AnnotationResultPageQuery query) { + List allowedRoles = dataPermissionService.getAllowedRoles(currentUser); + boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() .eq(AnnotationResult::getCompanyId, currentUser.companyId()) .eq(query.taskId() != null, AnnotationResult::getTaskId, query.taskId()) .eq(query.resourceId() != null, AnnotationResult::getResourceId, query.resourceId()) - .eq(query.requiresManualReview() != null, AnnotationResult::getRequiresManualReview, query.requiresManualReview()) - .orderByDesc(AnnotationResult::getCreatedAt); - List records = annotationResultMapper.selectList(wrapper).stream() + .eq(query.requiresManualReview() != null, AnnotationResult::getRequiresManualReview, query.requiresManualReview()); + + if (shouldFilterByUserId) { + wrapper.eq(AnnotationResult::getCreatorId, currentUser.userId()); + } else if (!allowedRoles.isEmpty()) { + wrapper.in(AnnotationResult::getCreatorRole, allowedRoles); + } + + wrapper.orderByDesc(AnnotationResult::getCreatedAt); + + Page page = new Page<>(query.pageNo(), query.pageSize()); + Page resultPage = annotationResultMapper.selectPage(page, wrapper); + + List records = resultPage.getRecords().stream() .map(this::toResponse) .filter(response -> query.runtimeStatus() == null || query.runtimeStatus().equals(response.runtimeStatus())) - .sorted(Comparator.comparing(AnnotationResultResponse::createdAt, Comparator.nullsLast(Comparator.naturalOrder())).reversed()) .toList(); - return paginate(records, query.pageNo(), query.pageSize()); + + return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(), (int) resultPage.getSize()); } public AnnotationResultResponse getResult(LoginUser currentUser, Long resultId) { - AnnotationResult result = annotationResultMapper.selectById(resultId); - if (result == null || !currentUser.companyId().equals(result.getCompanyId())) { + AnnotationResult result = annotationResultMapper.findActiveByIdAndCompanyId(resultId, currentUser.companyId()); + if (result == null) { + log.warn("Result not found or cross-tenant access attempt: resultId={}, companyId={}, userId={}", + resultId, currentUser.companyId(), currentUser.userId()); throw new BusinessException(ResultCode.NOT_FOUND, "结果不存在"); } return toResponse(result); } public AnnotationResultCompareResponse compareResult(LoginUser currentUser, Long resultId) { - AnnotationResult result = annotationResultMapper.selectById(resultId); - if (result == null || !currentUser.companyId().equals(result.getCompanyId())) { + AnnotationResult result = annotationResultMapper.findActiveByIdAndCompanyId(resultId, currentUser.companyId()); + if (result == null) { + log.warn("Result not found or cross-tenant access attempt: resultId={}, companyId={}, userId={}", + resultId, currentUser.companyId(), currentUser.userId()); throw new BusinessException(ResultCode.NOT_FOUND, "结果不存在"); } SourceResource resource = sourceResourceMapper.selectById(result.getResourceId()); @@ -88,12 +110,4 @@ public class AnnotationResultService { } return RuntimeResultStatus.AUTO_ARCHIVE_PENDING.name(); } - - private PageResult paginate(List records, Integer pageNo, Integer pageSize) { - int actualPageNo = pageNo == null || pageNo < 1 ? 1 : pageNo; - int actualPageSize = pageSize == null || pageSize < 1 ? 10 : pageSize; - int fromIndex = Math.min((actualPageNo - 1) * actualPageSize, records.size()); - int toIndex = Math.min(fromIndex + actualPageSize, records.size()); - return new PageResult<>(records.subList(fromIndex, toIndex), (long) records.size(), actualPageNo, actualPageSize); - } -} +} \ No newline at end of file diff --git a/src/main/java/com/labelsys/backend/service/AnnotationTaskService.java b/src/main/java/com/labelsys/backend/service/AnnotationTaskService.java index 9773109..ca4364d 100644 --- a/src/main/java/com/labelsys/backend/service/AnnotationTaskService.java +++ b/src/main/java/com/labelsys/backend/service/AnnotationTaskService.java @@ -1,6 +1,17 @@ package com.labelsys.backend.service; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.labelsys.backend.common.ResultCode; import com.labelsys.backend.common.exception.BusinessException; import com.labelsys.backend.context.LoginUser; @@ -20,16 +31,9 @@ import com.labelsys.backend.mapper.AnnotationTaskMapper; import com.labelsys.backend.mapper.AnnotationTaskResourceMapper; import com.labelsys.backend.mapper.SourceResourceMapper; import com.labelsys.backend.util.IdGenerator; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Set; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.StringUtils; @Slf4j @Service @@ -136,20 +140,35 @@ public class AnnotationTaskService { } public PageResult pageTasks(LoginUser currentUser, AnnotationTaskPageQuery query) { + List allowedRoles = dataPermissionService.getAllowedRoles(currentUser); + boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() .eq(AnnotationTask::getCompanyId, currentUser.companyId()) .eq(StringUtils.hasText(query.taskType()), AnnotationTask::getTaskType, query.taskType()) .eq(StringUtils.hasText(query.taskStatus()), AnnotationTask::getTaskStatus, query.taskStatus()) .eq(query.isDeleted() != null, AnnotationTask::getIsDeleted, query.isDeleted()) - .like(StringUtils.hasText(query.keyword()), AnnotationTask::getTaskName, query.keyword()) - .orderByDesc(AnnotationTask::getCreatedAt); - List records = annotationTaskMapper.selectList(wrapper).stream() - .filter(task -> dataPermissionService.canAccessCreator(currentUser, task.getCreatorId(), task.getCreatorRole())) - .filter(task -> query.resourceId() == null || annotationTaskResourceMapper.listResourceIdsByTaskId(task.getId()).contains(query.resourceId())) - .sorted(Comparator.comparing(AnnotationTask::getCreatedAt, Comparator.nullsLast(Comparator.naturalOrder())).reversed()) - .map(task -> buildTaskResponse(task, normalizeIds(annotationTaskResourceMapper.listResourceIdsByTaskId(task.getId())))) + .like(StringUtils.hasText(query.keyword()), AnnotationTask::getTaskName, query.keyword()); + + if (shouldFilterByUserId) { + wrapper.eq(AnnotationTask::getCreatorId, currentUser.userId()); + } else if (!allowedRoles.isEmpty()) { + wrapper.in(AnnotationTask::getCreatorRole, allowedRoles); + } + + wrapper.orderByDesc(AnnotationTask::getCreatedAt); + + Page page = new Page<>(query.pageNo(), query.pageSize()); + Page resultPage = annotationTaskMapper.selectPage(page, wrapper); + + List records = resultPage.getRecords().stream() + .filter(task -> query.resourceId() == null || + annotationTaskResourceMapper.listResourceIdsByTaskId(task.getId()).contains(query.resourceId())) + .map(task -> buildTaskResponse(task, + normalizeIds(annotationTaskResourceMapper.listResourceIdsByTaskId(task.getId())))) .toList(); - return paginate(records, query.pageNo(), query.pageSize()); + + return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(), (int) resultPage.getSize()); } @Transactional @@ -273,12 +292,4 @@ public class AnnotationTaskService { } return "****" + secret.substring(secret.length() - 4); } - - private PageResult paginate(List records, Integer pageNo, Integer pageSize) { - int actualPageNo = pageNo == null || pageNo < 1 ? 1 : pageNo; - int actualPageSize = pageSize == null || pageSize < 1 ? 10 : pageSize; - int fromIndex = Math.min((actualPageNo - 1) * actualPageSize, records.size()); - int toIndex = Math.min(fromIndex + actualPageSize, records.size()); - return new PageResult<>(records.subList(fromIndex, toIndex), (long) records.size(), actualPageNo, actualPageSize); - } } diff --git a/src/main/java/com/labelsys/backend/service/CompanyService.java b/src/main/java/com/labelsys/backend/service/CompanyService.java index 4bffbde..e73ad1f 100644 --- a/src/main/java/com/labelsys/backend/service/CompanyService.java +++ b/src/main/java/com/labelsys/backend/service/CompanyService.java @@ -47,8 +47,8 @@ public class CompanyService { } private void assertPlatformAdmin(LoginUser currentUser) { - if (!currentUser.isPlatformAdmin()) { - throw new ForbiddenException("仅平台管理员可操作"); + if (!currentUser.isSuperAdmin()) { + throw new ForbiddenException("仅系统管理员可操作"); } } } diff --git a/src/main/java/com/labelsys/backend/service/SourceResourceService.java b/src/main/java/com/labelsys/backend/service/SourceResourceService.java index cfae1d8..b5a24ab 100644 --- a/src/main/java/com/labelsys/backend/service/SourceResourceService.java +++ b/src/main/java/com/labelsys/backend/service/SourceResourceService.java @@ -1,8 +1,18 @@ package com.labelsys.backend.service; +import java.io.IOException; +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; +import org.springframework.web.multipart.MultipartFile; + import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.labelsys.backend.common.ResultCode; import com.labelsys.backend.common.exception.BusinessException; +import com.labelsys.backend.config.ObjectStorageProperties; import com.labelsys.backend.context.LoginUser; import com.labelsys.backend.dto.common.PageResult; import com.labelsys.backend.dto.request.SourceResourcePageQuery; @@ -18,15 +28,9 @@ import com.labelsys.backend.mapper.SourceResourceMapper; import com.labelsys.backend.mapper.SysUserMapper; import com.labelsys.backend.util.IdGenerator; import com.labelsys.backend.util.ObjectStoragePathBuilder; -import java.io.IOException; -import java.util.Comparator; -import java.util.List; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.StringUtils; -import org.springframework.web.multipart.MultipartFile; @Slf4j @Service @@ -51,69 +55,64 @@ public class SourceResourceService { } long resourceId = IdGenerator.nextId(); String extension = resolveExtension(file.getOriginalFilename(), request.getResourceType()); - String objectKey = ObjectStoragePathBuilder.sourceObjectKey( - currentUser.companyId(), request.getResourceType(), resourceId, extension); + String objectKey = ObjectStoragePathBuilder.sourceObjectKey(currentUser.companyId(), request.getResourceType(), + resourceId, extension); try { - objectStorageService.upload( - objectStorageProperties.getSourceBucket(), - objectKey, - file.getBytes(), + objectStorageService.upload(objectStorageProperties.getSourceBucket(), objectKey, file.getBytes(), file.getContentType()); } catch (IOException ex) { throw new BusinessException(ResultCode.BAD_REQUEST, "读取上传文件失败"); } - SourceResource resource = SourceResource.builder() - .id(resourceId) - .companyId(currentUser.companyId()) - .creatorId(currentUser.userId()) - .creatorRole(currentUser.role()) - .resourceName(StringUtils.hasText(request.getResourceName()) ? request.getResourceName() : file.getOriginalFilename()) - .resourceType(request.getResourceType()) - .bucketName(objectStorageProperties.getSourceBucket()) - .filePath(objectKey) - .fileSize(file.getSize()) - .sourceStatus(SourceStatus.READY.name()) - .storageProvider("rustfs") - .remark(request.getRemark()) - .build(); + SourceResource resource = SourceResource.builder().id(resourceId).companyId(currentUser.companyId()) + .creatorId(currentUser.userId()).creatorRole(currentUser.role()) + .resourceName( + StringUtils.hasText(request.getResourceName()) ? request.getResourceName() : file.getOriginalFilename()) + .resourceType(request.getResourceType()).bucketName(objectStorageProperties.getSourceBucket()) + .filePath(objectKey).fileSize(file.getSize()).sourceStatus(SourceStatus.READY.name()) + .storageProvider("rustfs").remark(request.getRemark()).build(); sourceResourceMapper.insert(resource); - log.info("uploaded source resource, companyId={}, userId={}, resourceId={}", - currentUser.companyId(), currentUser.userId(), resourceId); - return new SourceUploadResponse( - resource.getId(), - resource.getResourceName(), - resource.getResourceType(), - resource.getBucketName(), - resource.getFilePath(), - resource.getFileSize(), - resource.getSourceStatus(), + log.info("uploaded source resource, companyId={}, userId={}, resourceId={}", currentUser.companyId(), + currentUser.userId(), resourceId); + return new SourceUploadResponse(resource.getId(), resource.getResourceName(), resource.getResourceType(), + resource.getBucketName(), resource.getFilePath(), resource.getFileSize(), resource.getSourceStatus(), resource.getCreatedAt()); } public PageResult pageResources(LoginUser currentUser, SourceResourcePageQuery query) { - LambdaQueryWrapper wrapper = new LambdaQueryWrapper() - .eq(SourceResource::getCompanyId, currentUser.companyId()) - .eq(StringUtils.hasText(query.resourceType()), SourceResource::getResourceType, query.resourceType()) - .eq(StringUtils.hasText(query.sourceStatus()), SourceResource::getSourceStatus, query.sourceStatus()) - .like(StringUtils.hasText(query.keyword()), SourceResource::getResourceName, query.keyword()) - .orderByDesc(SourceResource::getCreatedAt); - List records = sourceResourceMapper.selectList(wrapper).stream() - .filter(resource -> dataPermissionService.canAccessCreator(currentUser, resource.getCreatorId(), resource.getCreatorRole())) - .sorted(Comparator.comparing(SourceResource::getCreatedAt, Comparator.nullsLast(Comparator.naturalOrder())).reversed()) - .map(this::toResponse) - .toList(); - return paginate(records, query.pageNo(), query.pageSize()); + List allowedRoles = dataPermissionService.getAllowedRoles(currentUser); + boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser); + + LambdaQueryWrapper wrapper = + new LambdaQueryWrapper().eq(SourceResource::getCompanyId, currentUser.companyId()) + .eq(StringUtils.hasText(query.resourceType()), SourceResource::getResourceType, query.resourceType()) + .eq(StringUtils.hasText(query.sourceStatus()), SourceResource::getSourceStatus, query.sourceStatus()) + .like(StringUtils.hasText(query.keyword()), SourceResource::getResourceName, query.keyword()); + + if (shouldFilterByUserId) { + wrapper.eq(SourceResource::getCreatorId, currentUser.userId()); + } else if (!allowedRoles.isEmpty()) { + wrapper.in(SourceResource::getCreatorRole, allowedRoles); + } + + wrapper.orderByDesc(SourceResource::getCreatedAt); + + Page page = new Page<>(query.pageNo(), query.pageSize()); + Page resultPage = sourceResourceMapper.selectPage(page, wrapper); + + List records = resultPage.getRecords().stream().map(this::toResponse).toList(); + + return new PageResult<>(records, resultPage.getTotal(), (int)resultPage.getCurrent(), + (int)resultPage.getSize()); } public SourceResourceResponse getResource(LoginUser currentUser, Long resourceId) { SourceResource resource = sourceResourceMapper.selectById(resourceId); if (resource == null || !currentUser.companyId().equals(resource.getCompanyId())) { + log.warn("Resource not found or cross-tenant access attempt: resourceId={}, companyId={}, userId={}", + resourceId, currentUser.companyId(), currentUser.userId()); throw new BusinessException(ResultCode.NOT_FOUND, "资源不存在"); } - if (!dataPermissionService.canAccessCreator(currentUser, resource.getCreatorId(), resource.getCreatorRole())) { - throw new BusinessException(ResultCode.FORBIDDEN, "无权访问资源"); - } return toResponse(resource); } @@ -136,25 +135,16 @@ public class SourceResourceService { } objectStorageService.delete(resource.getBucketName(), resource.getFilePath()); sourceResourceMapper.deleteById(resourceId); - log.info("deleted source resource, companyId={}, userId={}, resourceId={}", - currentUser.companyId(), currentUser.userId(), resourceId); + log.info("deleted source resource, companyId={}, userId={}, resourceId={}", currentUser.companyId(), + currentUser.userId(), resourceId); } private SourceResourceResponse toResponse(SourceResource resource) { SysUser creator = sysUserMapper.selectById(resource.getCreatorId()); - return new SourceResourceResponse( - resource.getId(), - resource.getResourceName(), - resource.getResourceType(), - resource.getBucketName(), - resource.getFilePath(), - resource.getFileSize(), - resource.getSourceStatus(), - resource.getStorageProvider(), - resource.getRemark(), - creator == null ? null : creator.getRealName(), - resource.getCreatedAt(), - resource.getUpdatedAt()); + return new SourceResourceResponse(resource.getId(), resource.getResourceName(), resource.getResourceType(), + resource.getBucketName(), resource.getFilePath(), resource.getFileSize(), resource.getSourceStatus(), + resource.getStorageProvider(), resource.getRemark(), creator == null ? null : creator.getRealName(), + resource.getCreatedAt(), resource.getUpdatedAt()); } private String resolveExtension(String originalFilename, String resourceType) { @@ -168,12 +158,4 @@ public class SourceResourceService { default -> "bin"; }; } - - private PageResult paginate(List records, Integer pageNo, Integer pageSize) { - int actualPageNo = pageNo == null || pageNo < 1 ? 1 : pageNo; - int actualPageSize = pageSize == null || pageSize < 1 ? 10 : pageSize; - int fromIndex = Math.min((actualPageNo - 1) * actualPageSize, records.size()); - int toIndex = Math.min(fromIndex + actualPageSize, records.size()); - return new PageResult<>(records.subList(fromIndex, toIndex), (long) records.size(), actualPageNo, actualPageSize); - } } diff --git a/src/main/java/com/labelsys/backend/service/UserService.java b/src/main/java/com/labelsys/backend/service/UserService.java index 776e632..59e2b5b 100644 --- a/src/main/java/com/labelsys/backend/service/UserService.java +++ b/src/main/java/com/labelsys/backend/service/UserService.java @@ -12,6 +12,7 @@ import com.labelsys.backend.common.exception.BusinessException; import com.labelsys.backend.common.exception.ForbiddenException; import com.labelsys.backend.context.LoginUser; import com.labelsys.backend.dto.request.CreateCompanyAdminRequest; +import com.labelsys.backend.dto.request.CreateSystemEngineerAdminRequest; import com.labelsys.backend.dto.request.CreateUserRequest; import com.labelsys.backend.dto.request.UpdateUserAssignmentRequest; import com.labelsys.backend.dto.request.UpdateUserStatusRequest; @@ -39,6 +40,12 @@ public class UserService { private final PasswordEncoder passwordEncoder; private final TokenSessionRepository tokenSessionRepository; + public List listAllUsers(LoginUser currentUser) { + assertSystemAdmin(currentUser); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper().orderByAsc(SysUser::getId); + return sysUserMapper.selectList(wrapper); + } + public List listCompanyUsers(LoginUser currentUser) { assertCompanyAdmin(currentUser); LambdaQueryWrapper wrapper = new LambdaQueryWrapper() @@ -47,17 +54,32 @@ public class UserService { } public List listCompanyAdmins(LoginUser currentUser, Long companyId) { - assertPlatformAdmin(currentUser); + assertSystemAdmin(currentUser); return sysUserMapper.listCompanyAdmins(companyId); } public SysUser createCompanyAdmin(LoginUser currentUser, CreateCompanyAdminRequest request) { - assertPlatformAdmin(currentUser); + assertSystemAdmin(currentUser); ensureEnabledCompany(request.companyId()); - return createUser( - request.companyId(), - new CreateUserRequest(request.phone(), request.username(), request.realName(), UserRole.EMPLOYEE, UserPosition.ADMIN) - ); + return createUser(request.companyId(), new CreateUserRequest(request.phone(), request.username(), + request.realName(), UserRole.EMPLOYEE, UserPosition.ADMIN)); + } + + public SysUser createSystemEngineerAdmin(LoginUser currentUser, CreateSystemEngineerAdminRequest request) { + assertSystemAdmin(currentUser); + Long systemCompanyId = 1L; + ensureEnabledCompany(systemCompanyId); + + if (sysUserMapper.findByCompanyIdAndPhone(systemCompanyId, request.phone()) != null) { + throw new BusinessException(ResultCode.CONFLICT, "同一公司内手机号已存在"); + } + + SysUser user = SysUser.builder().id(IdGenerator.nextId()).companyId(systemCompanyId).phone(request.phone()) + .username(request.username()).realName(request.realName()).role(UserRole.ENGINEER) + .position(UserPosition.SUPER_ADMIN).passwordHash(passwordEncoder.encode(DEFAULT_PASSWORD)) + .mustChangePassword(true).status(UserStatus.ENABLED).sessionVersion(1).build(); + sysUserMapper.insert(user); + return user; } public SysUser createCompanyUser(LoginUser currentUser, CreateUserRequest request) { @@ -66,7 +88,7 @@ public class UserService { } public SysUser createCompanyUser(LoginUser currentUser, Long companyId, CreateUserRequest request) { - assertPlatformAdmin(currentUser); + assertSystemAdmin(currentUser); ensureEnabledCompany(companyId); return createUser(companyId, request); } @@ -90,8 +112,9 @@ public class UserService { } @Transactional - public void updateCompanyAdminStatus(LoginUser currentUser, Long companyId, Long userId, UpdateUserStatusRequest request) { - assertPlatformAdmin(currentUser); + public void updateCompanyAdminStatus(LoginUser currentUser, Long companyId, Long userId, + UpdateUserStatusRequest request) { + assertSystemAdmin(currentUser); if (sysUserMapper.updateStatus(userId, companyId, request.status()) == 0) { throw new BusinessException(ResultCode.NOT_FOUND, "用户不存在"); } @@ -102,19 +125,10 @@ public class UserService { if (sysUserMapper.findByCompanyIdAndPhone(companyId, request.phone()) != null) { throw new BusinessException(ResultCode.CONFLICT, "同一公司内手机号已存在"); } - SysUser user = SysUser.builder() - .id(IdGenerator.nextId()) - .companyId(companyId) - .phone(request.phone()) - .username(request.username()) - .realName(request.realName()) - .role(request.role()) - .position(request.position()) - .passwordHash(passwordEncoder.encode(DEFAULT_PASSWORD)) - .mustChangePassword(true) - .status(UserStatus.ENABLED) - .sessionVersion(1) - .build(); + SysUser user = SysUser.builder().id(IdGenerator.nextId()).companyId(companyId).phone(request.phone()) + .username(request.username()).realName(request.realName()).role(request.role()).position(request.position()) + .passwordHash(passwordEncoder.encode(DEFAULT_PASSWORD)).mustChangePassword(true).status(UserStatus.ENABLED) + .sessionVersion(1).build(); sysUserMapper.insert(user); return user; } @@ -126,14 +140,20 @@ public class UserService { } } - private void assertPlatformAdmin(LoginUser currentUser) { - if (!currentUser.isPlatformAdmin()) { - throw new ForbiddenException("仅平台管理员可操作"); + // private void assertPlatformAdmin(LoginUser currentUser) { + // if (!currentUser.isPlatformAdmin()) { + // throw new ForbiddenException("仅平台管理员可操作"); + // } + // } + + private void assertSystemAdmin(LoginUser currentUser) { + if (!currentUser.isSuperAdmin()) { + throw new ForbiddenException("仅超级管理员可操作"); } } private void assertCompanyAdmin(LoginUser currentUser) { - if (currentUser.isPlatformAdmin() || currentUser.position() != UserPosition.ADMIN) { + if (currentUser.isSuperAdmin() || currentUser.position() != UserPosition.ADMIN) { throw new ForbiddenException("仅公司管理员可操作"); } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 7e911ec..5d2b770 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -27,7 +27,11 @@ mybatis-plus: map-underscore-to-camel-case: true springdoc: + api-docs: + enabled: true + path: /v3/api-docs swagger-ui: + enabled: true path: /swagger-ui.html labelsys: @@ -37,10 +41,10 @@ labelsys: annotation: auto-archive-timeout: PT2H object-storage: - endpoint: ${OBJECT_STORAGE_ENDPOINT:http://127.0.0.1:9000} - region: ${OBJECT_STORAGE_REGION:us-east-1} - access-key: ${OBJECT_STORAGE_ACCESS_KEY:demo-access-key} - secret-key: ${OBJECT_STORAGE_SECRET_KEY:demo-secret-key} + endpoint: ${OBJECT_STORAGE_ENDPOINT:http://39.107.112.174:9000} + region: ${OBJECT_STORAGE_REGION:cn-east-1} + access-key: ${OBJECT_STORAGE_ACCESS_KEY:admin} + secret-key: ${OBJECT_STORAGE_SECRET_KEY:your_strong_password} path-style-access: ${OBJECT_STORAGE_PATH_STYLE:true} source-bucket: ${OBJECT_STORAGE_SOURCE_BUCKET:source-data} artifact-bucket: ${OBJECT_STORAGE_ARTIFACT_BUCKET:annotation-artifacts} diff --git a/src/main/resources/mapper/AnnotationResultMapper.xml b/src/main/resources/mapper/AnnotationResultMapper.xml index 1b1ebd8..77fb503 100644 --- a/src/main/resources/mapper/AnnotationResultMapper.xml +++ b/src/main/resources/mapper/AnnotationResultMapper.xml @@ -47,4 +47,4 @@ and company_id = #{companyId} and is_deleted = false - + \ No newline at end of file diff --git a/src/main/resources/mapper/AnnotationTaskMapper.xml b/src/main/resources/mapper/AnnotationTaskMapper.xml index 68f6e69..f5b378c 100644 --- a/src/main/resources/mapper/AnnotationTaskMapper.xml +++ b/src/main/resources/mapper/AnnotationTaskMapper.xml @@ -46,4 +46,4 @@ and is_deleted = false limit 1 - + \ No newline at end of file diff --git a/src/main/resources/mapper/SourceResourceMapper.xml b/src/main/resources/mapper/SourceResourceMapper.xml index f725ee9..9b38e8b 100644 --- a/src/main/resources/mapper/SourceResourceMapper.xml +++ b/src/main/resources/mapper/SourceResourceMapper.xml @@ -2,34 +2,29 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - id, company_id, creator_id, creator_role, resource_name, resource_type, bucket_name, file_path, - file_size, source_status, storage_provider, remark, created_at, updated_at - + id, company_id, creator_id, creator_role, resource_name, + resource_type, bucket_name, file_path, file_size, source_status, storage_provider, remark, + created_at, updated_at - select from source_resource where company_id = #{companyId} + and id in #{resourceId} - + \ No newline at end of file diff --git a/src/main/resources/sql/data.sql b/src/main/resources/sql/data.sql index a7a7511..c67b8ae 100644 --- a/src/main/resources/sql/data.sql +++ b/src/main/resources/sql/data.sql @@ -1,37 +1,37 @@ -BEGIN; - -INSERT INTO sys_company (id, company_code, company_name, status) VALUES - (1, 'PLATFORM', '平台公司', 'ENABLED'), - (2, 'ALPHA', '甲公司', 'ENABLED') -ON CONFLICT DO NOTHING; - -INSERT INTO sys_user ( - id, company_id, phone, username, role, position, real_name, - password_hash, must_change_password, status, session_version -) VALUES - (1, 1, '13900000000', 'platform-admin', 'ENGINEER', 'ADMIN', '平台管理员', - '$2a$10$TGPk5rNNhKNJQvTWImw5J.LVzw9HDFWR6hyNJCkLDcp0GU8/vp0aS', FALSE, 'ENABLED', 1), - (2, 2, '13800138000', 'alpha-admin', 'ENGINEER', 'ADMIN', '甲公司管理员', - '$2a$10$/hSD8ch7A9lFWi/DOb8yJOHdlrhV57p95CBv9Uv93Yky7t6c4Rs/S', TRUE, 'ENABLED', 1), - (3, 2, '13700000000', 'alpha-annotator', 'EMPLOYEE', 'ANNOTATOR', '甲公司标注员', - '$2a$10$bRMZPcIaiB1BUx6HPw6FSODPSuph8kUi8/JZOM6lACwjjhkbBL5mq', TRUE, 'ENABLED', 1), - (4, 2, '13600000000', 'alpha-trainer', 'EMPLOYEE', 'DATA_TRAINER', '甲公司数据训练师', - '$2a$10$bRMZPcIaiB1BUx6HPw6FSODPSuph8kUi8/JZOM6lACwjjhkbBL5mq', TRUE, 'ENABLED', 1), - (5, 2, '13500000000', 'alpha-reviewer', 'MANAGER', 'REVIEWER', '甲公司审核员', - '$2a$10$bRMZPcIaiB1BUx6HPw6FSODPSuph8kUi8/JZOM6lACwjjhkbBL5mq', TRUE, 'ENABLED', 1), - (6, 2, '13400000000', 'alpha-chief-engineer', 'ENGINEER', 'REVIEWER', '甲公司总工程师', - '$2a$10$bRMZPcIaiB1BUx6HPw6FSODPSuph8kUi8/JZOM6lACwjjhkbBL5mq', TRUE, 'ENABLED', 1) -ON CONFLICT DO NOTHING; - -INSERT INTO sys_menu (id, company_id, menu_code, menu_name, path, visible_positions, sort_order) VALUES - (201, 2, 'USER_MANAGE', '用户管理', '/users', 'ADMIN', 1), - (202, 2, 'RESOURCE_MANAGE', '资源管理', '/resources', 'ANNOTATOR,DATA_TRAINER,REVIEWER,ADMIN', 2), - (203, 2, 'TASK_MANAGE', '任务管理', '/tasks', 'ANNOTATOR,DATA_TRAINER,REVIEWER,ADMIN', 3), - (204, 2, 'RESULT_REVIEW', '结果审核', '/results', 'REVIEWER,ADMIN', 4), - (205, 2, 'DATASET_EXPORT', '训练集导出', '/datasets', 'DATA_TRAINER,ADMIN', 5), - (206, 2, 'SYSTEM_CONFIG', '系统配置', '/configs', 'ADMIN', 6) -ON CONFLICT DO NOTHING; - +BEGIN; + +INSERT INTO sys_company (id, company_code, company_name, status) VALUES + (1, 'PLATFORM', '平台公司', 'ENABLED'), + (2, 'ALPHA', '甲公司', 'ENABLED') +ON CONFLICT DO NOTHING; + +INSERT INTO sys_user ( + id, company_id, phone, username, role, position, real_name, + password_hash, must_change_password, status, session_version +) VALUES + (1, 1, '13900000000', 'platform-admin', 'ENGINEER', 'SUPER_ADMIN', '平台管理员', + '$2a$10$TGPk5rNNhKNJQvTWImw5J.LVzw9HDFWR6hyNJCkLDcp0GU8/vp0aS', FALSE, 'ENABLED', 1), + (2, 2, '13800138000', 'alpha-admin', 'ENGINEER', 'ADMIN', '甲公司管理员', + '$2a$10$/hSD8ch7A9lFWi/DOb8yJOHdlrhV57p95CBv9Uv93Yky7t6c4Rs/S', TRUE, 'ENABLED', 1), + (3, 2, '13700000000', 'alpha-annotator', 'EMPLOYEE', 'ANNOTATOR', '甲公司标注员', + '$2a$10$bRMZPcIaiB1BUx6HPw6FSODPSuph8kUi8/JZOM6lACwjjhkbBL5mq', TRUE, 'ENABLED', 1), + (4, 2, '13600000000', 'alpha-trainer', 'EMPLOYEE', 'DATA_TRAINER', '甲公司数据训练师', + '$2a$10$bRMZPcIaiB1BUx6HPw6FSODPSuph8kUi8/JZOM6lACwjjhkbBL5mq', TRUE, 'ENABLED', 1), + (5, 2, '13500000000', 'alpha-reviewer', 'MANAGER', 'REVIEWER', '甲公司审核员', + '$2a$10$bRMZPcIaiB1BUx6HPw6FSODPSuph8kUi8/JZOM6lACwjjhkbBL5mq', TRUE, 'ENABLED', 1), + (6, 2, '13400000000', 'alpha-chief-engineer', 'ENGINEER', 'REVIEWER', '甲公司总工程师', + '$2a$10$bRMZPcIaiB1BUx6HPw6FSODPSuph8kUi8/JZOM6lACwjjhkbBL5mq', TRUE, 'ENABLED', 1) +ON CONFLICT DO NOTHING; + +INSERT INTO sys_menu (id, company_id, menu_code, menu_name, path, visible_positions, sort_order) VALUES + (201, 2, 'USER_MANAGE', '用户管理', '/users', 'ADMIN', 1), + (202, 2, 'RESOURCE_MANAGE', '资源管理', '/resources', 'ANNOTATOR,DATA_TRAINER,REVIEWER,ADMIN', 2), + (203, 2, 'TASK_MANAGE', '任务管理', '/tasks', 'ANNOTATOR,DATA_TRAINER,REVIEWER,ADMIN', 3), + (204, 2, 'RESULT_REVIEW', '结果审核', '/results', 'REVIEWER,ADMIN', 4), + (205, 2, 'DATASET_EXPORT', '训练集导出', '/datasets', 'DATA_TRAINER,ADMIN', 5), + (206, 2, 'SYSTEM_CONFIG', '系统配置', '/configs', 'ADMIN', 6) +ON CONFLICT DO NOTHING; + INSERT INTO sys_config ( id, company_id, config_type, config_name, config_value, status, creator_id ) VALUES @@ -54,7 +54,7 @@ INSERT INTO sys_config ( (405, 2, 'SYSTEM', 'storageProvider', '{"provider":"rustfs","defaultBucket":"source-data"}', 'ENABLED', 2) ON CONFLICT DO NOTHING; - + INSERT INTO source_resource ( id, company_id, creator_id, creator_role, resource_name, resource_type, bucket_name, file_path, file_size, source_status, storage_provider, remark @@ -103,21 +103,21 @@ ON CONFLICT DO NOTHING; INSERT INTO annotation_result ( id, company_id, creator_id, creator_role, task_id, resource_id, - qa_content_json, qa_content_storage_mode, qa_content_file_path, diff_summary, - requires_manual_review, is_deleted, reviewer_id, review_comment, reviewed_at -) VALUES - (801, 2, 3, 'EMPLOYEE', 701, 601, - '{"question":"巡检开始前需要做什么?","answer":"详见外置结果文件,包含完整步骤与注意事项。"}', - 'EXTERNAL', 'annotation-results/202604/801-qa.json', - '{"extract_question":"巡检开始前需要做什么?","extract_answer":"开始前检查设备状态和作业环境。","verify_answer":"开始前应确认设备状态、防护用品和现场环境安全。","mismatch_fields":["answer"],"reason":"抽取答案遗漏了安全检查要点。"}', - TRUE, FALSE, NULL, NULL, NULL), - (802, 2, 3, 'EMPLOYEE', 702, 602, - '{"question":"图片中的控制柜当前状态如何?","answer":"控制柜处于运行状态,绿色指示灯亮起。"}', - 'INLINE', NULL, - '{"extract_question":"图片中的控制柜当前状态如何?","extract_answer":"控制柜处于运行状态,绿色指示灯亮起。","verify_answer":"控制柜正在运行,指示灯显示正常。","mismatch_fields":[],"reason":"校验结果与抽取结果基本一致。"}', - FALSE, FALSE, 5, '结果可通过。', CURRENT_TIMESTAMP) -ON CONFLICT DO NOTHING; - + qa_content_json, qa_content_storage_mode, qa_content_file_path, diff_summary, + requires_manual_review, is_deleted, reviewer_id, review_comment, reviewed_at +) VALUES + (801, 2, 3, 'EMPLOYEE', 701, 601, + '{"question":"巡检开始前需要做什么?","answer":"详见外置结果文件,包含完整步骤与注意事项。"}', + 'EXTERNAL', 'annotation-results/202604/801-qa.json', + '{"extract_question":"巡检开始前需要做什么?","extract_answer":"开始前检查设备状态和作业环境。","verify_answer":"开始前应确认设备状态、防护用品和现场环境安全。","mismatch_fields":["answer"],"reason":"抽取答案遗漏了安全检查要点。"}', + TRUE, FALSE, NULL, NULL, NULL), + (802, 2, 3, 'EMPLOYEE', 702, 602, + '{"question":"图片中的控制柜当前状态如何?","answer":"控制柜处于运行状态,绿色指示灯亮起。"}', + 'INLINE', NULL, + '{"extract_question":"图片中的控制柜当前状态如何?","extract_answer":"控制柜处于运行状态,绿色指示灯亮起。","verify_answer":"控制柜正在运行,指示灯显示正常。","mismatch_fields":[],"reason":"校验结果与抽取结果基本一致。"}', + FALSE, FALSE, 5, '结果可通过。', CURRENT_TIMESTAMP) +ON CONFLICT DO NOTHING; + INSERT INTO annotation_result_history ( id, company_id, creator_id, creator_role, source_result_id, task_id, resource_id, qa_content_json, qa_content_storage_mode, qa_content_file_path, archive_reason, archived_by, archived_at @@ -128,23 +128,23 @@ INSERT INTO annotation_result_history ( NULL, '审核通过后归档', 5, CURRENT_TIMESTAMP) ON CONFLICT DO NOTHING; - -INSERT INTO training_dataset ( - id, company_id, creator_id, creator_role, result_history_id, sample_type, glm_format_json, dataset_status -) VALUES - (1001, 2, 4, 'EMPLOYEE', 901, 'TEXT', - '{"messages":[{"role":"system","content":"你是专业知识问答助手"},{"role":"user","content":"图片中的控制柜当前状态如何?"},{"role":"assistant","content":"控制柜处于运行状态,绿色指示灯亮起。"}]}', - 'DRAFT') -ON CONFLICT DO NOTHING; - -INSERT INTO export_batch ( - id, company_id, creator_id, creator_role, batch_no, dataset_file_path, sample_count, finetune_job_id, finetune_status -) VALUES - (1101, 2, 4, 'EMPLOYEE', 'BATCH-20260424-001', 'export/BATCH-20260424-001.jsonl', 1, NULL, 'NOT_STARTED') -ON CONFLICT DO NOTHING; - -INSERT INTO export_batch_item (id, batch_id, dataset_id) VALUES - (1201, 1101, 1001) -ON CONFLICT DO NOTHING; - -COMMIT; + +INSERT INTO training_dataset ( + id, company_id, creator_id, creator_role, result_history_id, sample_type, glm_format_json, dataset_status +) VALUES + (1001, 2, 4, 'EMPLOYEE', 901, 'TEXT', + '{"messages":[{"role":"system","content":"你是专业知识问答助手"},{"role":"user","content":"图片中的控制柜当前状态如何?"},{"role":"assistant","content":"控制柜处于运行状态,绿色指示灯亮起。"}]}', + 'DRAFT') +ON CONFLICT DO NOTHING; + +INSERT INTO export_batch ( + id, company_id, creator_id, creator_role, batch_no, dataset_file_path, sample_count, finetune_job_id, finetune_status +) VALUES + (1101, 2, 4, 'EMPLOYEE', 'BATCH-20260424-001', 'export/BATCH-20260424-001.jsonl', 1, NULL, 'NOT_STARTED') +ON CONFLICT DO NOTHING; + +INSERT INTO export_batch_item (id, batch_id, dataset_id) VALUES + (1201, 1101, 1001) +ON CONFLICT DO NOTHING; + +COMMIT; diff --git a/src/main/resources/sql/schema.sql b/src/main/resources/sql/schema.sql index f5afeef..e9e97e1 100644 --- a/src/main/resources/sql/schema.sql +++ b/src/main/resources/sql/schema.sql @@ -57,7 +57,7 @@ COMMENT ON COLUMN sys_user.company_id IS '所属公司ID,关联 sys_company.id COMMENT ON COLUMN sys_user.phone IS '登录手机号,同公司内唯一。'; COMMENT ON COLUMN sys_user.username IS '用户名或账号别名,用于展示。'; COMMENT ON COLUMN sys_user.role IS '数据权限角色,默认 EMPLOYEE,可选 EMPLOYEE、MANAGER、ENGINEER。'; -COMMENT ON COLUMN sys_user.position IS '岗位,默认 ANNOTATOR,可选 ANNOTATOR、DATA_TRAINER、REVIEWER、ADMIN。'; +COMMENT ON COLUMN sys_user.position IS '岗位,默认 ANNOTATOR,可选 ANNOTATOR、DATA_TRAINER、REVIEWER、ADMIN、SUPER_ADMIN。'; COMMENT ON COLUMN sys_user.real_name IS '用户真实姓名。'; COMMENT ON COLUMN sys_user.password_hash IS '密码哈希值。'; COMMENT ON COLUMN sys_user.must_change_password IS '是否首次登录强制改密。';