feat: 数据库注释补全、常量枚举重构及多模块优化

- 新增 Flyway V6/V7 迁移脚本,为全部 42 张表、591 个列添加中文注释
- 抽取公共常量类(BaseEntityConstants、CacheConstants、RoleConstants、TenantConstants)
- 新增业务枚举(CommonStatus、RegistrationStatus、WorkStatus 等 11 个)
- 优化赛事/作业/评审/UGC 等模块服务层代码
- 更新乐读派(leai)模块配置与 API 客户端
- 更新 e2e 测试用例及 demo 文件

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
En 2026-04-08 13:37:14 +08:00
parent df7eae6125
commit fa42eca339
62 changed files with 987 additions and 175 deletions

View File

@ -0,0 +1,21 @@
package com.competition.common.constants;
/**
* BaseEntity 基础字段常量
*/
public final class BaseEntityConstants {
private BaseEntityConstants() {}
/** 未删除 */
public static final int NOT_DELETED = 0;
/** 已删除 */
public static final int DELETED = 1;
/** 有效状态 */
public static final int VALID = 1;
/** 无效状态 */
public static final int INVALID = 2;
}

View File

@ -0,0 +1,18 @@
package com.competition.common.constants;
/**
* 缓存相关常量
*/
public final class CacheConstants {
private CacheConstants() {}
/** 用户角色缓存 key 前缀 */
public static final String USER_ROLES_PREFIX = "user:roles:";
/** 用户权限缓存 key 前缀 */
public static final String USER_PERMS_PREFIX = "user:perms:";
/** 认证缓存天数 */
public static final int AUTH_CACHE_DAYS = 7;
}

View File

@ -0,0 +1,21 @@
package com.competition.common.constants;
/**
* 角色相关常量
*/
public final class RoleConstants {
private RoleConstants() {}
/** 超级管理员角色编码 */
public static final String SUPER_ADMIN = "super_admin";
/** 公众用户角色编码 */
public static final String PUBLIC_USER = "public_user";
/** 评委角色编码 */
public static final String JUDGE = "judge";
/** 租户管理员角色编码 */
public static final String TENANT_ADMIN = "tenant_admin";
}

View File

@ -0,0 +1,23 @@
package com.competition.common.constants;
import java.util.Set;
/**
* 租户相关常量
*/
public final class TenantConstants {
private TenantConstants() {}
/** 超级管理员租户编码 */
public static final String CODE_SUPER = "super";
/** 公众端租户编码 */
public static final String CODE_PUBLIC = "public";
/** 评委租户编码 */
public static final String CODE_JUDGE = "judge";
/** 内部系统租户编码集合(不可删除、不可注册) */
public static final Set<String> INTERNAL_TENANT_CODES = Set.of(CODE_SUPER, CODE_PUBLIC, CODE_JUDGE, "school", "teacher", "student");
}

View File

@ -0,0 +1,18 @@
package com.competition.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 通用状态枚举启用/禁用
*/
@Getter
@AllArgsConstructor
public enum CommonStatus {
ENABLED("enabled", "启用"),
DISABLED("disabled", "禁用");
private final String value;
private final String description;
}

View File

@ -0,0 +1,18 @@
package com.competition.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 参赛者类型枚举
*/
@Getter
@AllArgsConstructor
public enum ParticipantType {
SELF("self", "本人"),
CHILD("child", "儿童");
private final String value;
private final String description;
}

View File

@ -0,0 +1,18 @@
package com.competition.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 发布状态枚举
*/
@Getter
@AllArgsConstructor
public enum PublishStatus {
PUBLISHED("published", "已发布"),
UNPUBLISHED("unpublished", "未发布");
private final String value;
private final String description;
}

View File

@ -0,0 +1,19 @@
package com.competition.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 报名状态枚举
*/
@Getter
@AllArgsConstructor
public enum RegistrationStatus {
PENDING("pending", "待审核"),
PASSED("passed", "已通过"),
REJECTED("rejected", "已拒绝");
private final String value;
private final String description;
}

View File

@ -0,0 +1,18 @@
package com.competition.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 提交规则枚举
*/
@Getter
@AllArgsConstructor
public enum SubmitRule {
ONCE("once", "仅一次"),
RESUBMIT("resubmit", "可重提交");
private final String value;
private final String description;
}

View File

@ -0,0 +1,22 @@
package com.competition.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 租户类型枚举
*/
@Getter
@AllArgsConstructor
public enum TenantType {
PLATFORM("platform", "平台"),
LIBRARY("library", "图书馆"),
KINDERGARTEN("kindergarten", "幼儿园"),
SCHOOL("school", "学校"),
INSTITUTION("institution", "机构"),
OTHER("other", "其他");
private final String value;
private final String description;
}

View File

@ -0,0 +1,19 @@
package com.competition.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 用户来源枚举
*/
@Getter
@AllArgsConstructor
public enum UserSource {
ADMIN_CREATED("admin_created", "管理员创建"),
SELF_REGISTERED("self_registered", "自主注册"),
CHILD_MIGRATED("child_migrated", "儿童迁移");
private final String value;
private final String description;
}

View File

@ -0,0 +1,18 @@
package com.competition.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 用户类型枚举
*/
@Getter
@AllArgsConstructor
public enum UserType {
ADULT("adult", "成人"),
CHILD("child", "儿童");
private final String value;
private final String description;
}

View File

@ -0,0 +1,20 @@
package com.competition.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 可见性枚举
*/
@Getter
@AllArgsConstructor
public enum Visibility {
PUBLIC("public", "公开"),
DESIGNATED("designated", "指定"),
INTERNAL("internal", "内部"),
PRIVATE("private", "私有");
private final String value;
private final String description;
}

View File

@ -0,0 +1,23 @@
package com.competition.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 作品状态枚举
*/
@Getter
@AllArgsConstructor
public enum WorkStatus {
SUBMITTED("submitted", "已提交"),
LOCKED("locked", "已锁定"),
REVIEWING("reviewing", "评审中"),
REJECTED("rejected", "已拒绝"),
ACCEPTED("accepted", "已采纳"),
AWARDED("awarded", "已获奖"),
TAKEN_DOWN("taken_down", "已下架");
private final String value;
private final String description;
}

View File

@ -2,6 +2,7 @@ package com.competition.modules.biz.contest.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.competition.common.enums.PublishStatus;
import com.competition.common.result.PageResult;
import com.competition.common.result.Result;
import com.competition.common.util.SecurityUtil;
@ -102,9 +103,9 @@ public class ContestNoticeController {
.like(StringUtils.hasText(title), BizContestNotice::getTitle, title);
// 发布状态过滤
if ("published".equals(status)) {
if (PublishStatus.PUBLISHED.getValue().equals(status)) {
wrapper.isNotNull(BizContestNotice::getPublishTime);
} else if ("unpublished".equals(status)) {
} else if (PublishStatus.UNPUBLISHED.getValue().equals(status)) {
wrapper.isNull(BizContestNotice::getPublishTime);
}

View File

@ -29,7 +29,7 @@ public class BizContest extends BaseEntity {
@TableField("contest_type")
private String contestType;
@Schema(description = "赛事发布状态unpublished/published")
@Schema(description = "赛事发布状态", allowableValues = {"published", "unpublished"})
@TableField("contest_state")
private String contestState;
@ -50,7 +50,7 @@ public class BizContest extends BaseEntity {
@Schema(description = "赛事详情(富文本)")
private String content;
@Schema(description = "可见范围public/designated/internal")
@Schema(description = "可见范围", allowableValues = {"public", "designated", "internal", "private"})
private String visibility;
// ====== 授权租户JSON ======
@ -139,7 +139,7 @@ public class BizContest extends BaseEntity {
private Integer ageMax;
// ====== 提交配置 ======
@Schema(description = "提交规则")
@Schema(description = "提交规则", allowableValues = {"once", "resubmit"})
@TableField("submit_rule")
private String submitRule;
@ -173,7 +173,7 @@ public class BizContest extends BaseEntity {
private LocalDateTime reviewEndTime;
// ====== 成果发布 ======
@Schema(description = "成绩发布状态")
@Schema(description = "成绩发布状态", allowableValues = {"published", "unpublished"})
@TableField("result_state")
private String resultState;

View File

@ -50,11 +50,11 @@ public class BizContestRegistration extends BaseEntity {
@Schema(description = "角色leader/member/mentor")
private String role;
@Schema(description = "报名状态pending/passed/rejected/withdrawn")
@Schema(description = "报名状态", allowableValues = {"pending", "passed", "rejected"})
@TableField("registration_state")
private String registrationState;
@Schema(description = "参与者类型self/child")
@Schema(description = "参与者类型", allowableValues = {"self", "child"})
@TableField("participant_type")
private String participantType;

View File

@ -51,7 +51,7 @@ public class BizContestWork extends BaseEntity {
@TableField("is_latest")
private Boolean isLatest;
@Schema(description = "作品状态submitted/locked/reviewing/rejected/accepted")
@Schema(description = "作品状态", allowableValues = {"submitted", "locked", "reviewing", "rejected", "accepted", "awarded", "taken_down"})
private String status;
@Schema(description = "提交时间")

View File

@ -4,6 +4,9 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.competition.common.enums.ErrorCode;
import com.competition.common.enums.ParticipantType;
import com.competition.common.enums.PublishStatus;
import com.competition.common.enums.RegistrationStatus;
import com.competition.common.exception.BusinessException;
import com.competition.common.result.PageResult;
import com.competition.modules.biz.contest.dto.CreateRegistrationDto;
@ -46,7 +49,7 @@ public class ContestRegistrationServiceImpl extends ServiceImpl<ContestRegistrat
if (contest == null) {
throw BusinessException.of(ErrorCode.NOT_FOUND, "赛事不存在");
}
if (!"published".equals(contest.getContestState())) {
if (!PublishStatus.PUBLISHED.getValue().equals(contest.getContestState())) {
throw BusinessException.of(ErrorCode.BAD_REQUEST, "赛事未发布,无法报名");
}
@ -63,8 +66,8 @@ public class ContestRegistrationServiceImpl extends ServiceImpl<ContestRegistrat
registration.setUserId(dto.getUserId());
registration.setAccountNo(accountNo);
registration.setAccountName(accountName);
registration.setRegistrationState("pending");
registration.setParticipantType("self");
registration.setRegistrationState(RegistrationStatus.PENDING.getValue());
registration.setParticipantType(ParticipantType.SELF.getValue());
registration.setRegistrationTime(LocalDateTime.now());
registration.setRegistrant(creatorId != null ? creatorId.intValue() : null);
registration.setCreator(creatorId != null ? creatorId.intValue() : null);
@ -146,7 +149,7 @@ public class ContestRegistrationServiceImpl extends ServiceImpl<ContestRegistrat
if (needTenantFilter) {
pendingWrapper.eq(BizContestRegistration::getTenantId, tenantId);
}
pendingWrapper.eq(BizContestRegistration::getRegistrationState, "pending");
pendingWrapper.eq(BizContestRegistration::getRegistrationState, RegistrationStatus.PENDING.getValue());
long pending = count(pendingWrapper);
LambdaQueryWrapper<BizContestRegistration> passedWrapper = new LambdaQueryWrapper<>();
@ -156,7 +159,7 @@ public class ContestRegistrationServiceImpl extends ServiceImpl<ContestRegistrat
if (needTenantFilter) {
passedWrapper.eq(BizContestRegistration::getTenantId, tenantId);
}
passedWrapper.eq(BizContestRegistration::getRegistrationState, "passed");
passedWrapper.eq(BizContestRegistration::getRegistrationState, RegistrationStatus.PASSED.getValue());
long passed = count(passedWrapper);
LambdaQueryWrapper<BizContestRegistration> rejectedWrapper = new LambdaQueryWrapper<>();
@ -166,7 +169,7 @@ public class ContestRegistrationServiceImpl extends ServiceImpl<ContestRegistrat
if (needTenantFilter) {
rejectedWrapper.eq(BizContestRegistration::getTenantId, tenantId);
}
rejectedWrapper.eq(BizContestRegistration::getRegistrationState, "rejected");
rejectedWrapper.eq(BizContestRegistration::getRegistrationState, RegistrationStatus.REJECTED.getValue());
long rejected = count(rejectedWrapper);
Map<String, Object> stats = new LinkedHashMap<>();
@ -255,7 +258,7 @@ public class ContestRegistrationServiceImpl extends ServiceImpl<ContestRegistrat
throw BusinessException.of(ErrorCode.NOT_FOUND, "报名记录不存在");
}
registration.setRegistrationState("pending");
registration.setRegistrationState(RegistrationStatus.PENDING.getValue());
registration.setReason(null);
registration.setOperator(null);
registration.setOperationDate(null);

View File

@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.competition.common.enums.ErrorCode;
import com.competition.common.enums.PublishStatus;
import com.competition.common.enums.SubmitRule;
import com.competition.common.exception.BusinessException;
import com.competition.common.result.PageResult;
import com.competition.common.util.SecurityUtil;
@ -78,11 +80,11 @@ public class ContestServiceImpl extends ServiceImpl<ContestMapper, BizContest> i
mapDtoToEntity(dto, entity);
// 默认状态
entity.setContestState("unpublished");
entity.setContestState(PublishStatus.UNPUBLISHED.getValue());
entity.setStatus("ongoing");
entity.setResultState("unpublished");
entity.setResultState(PublishStatus.UNPUBLISHED.getValue());
if (!StringUtils.hasText(entity.getSubmitRule())) {
entity.setSubmitRule("once");
entity.setSubmitRule(SubmitRule.ONCE.getValue());
}
entity.setCreator(creatorId != null ? creatorId.intValue() : null);
@ -222,7 +224,7 @@ public class ContestServiceImpl extends ServiceImpl<ContestMapper, BizContest> i
LambdaQueryWrapper<BizContest> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(BizContest::getValidState, 1);
wrapper.eq(BizContest::getContestState, "published");
wrapper.eq(BizContest::getContestState, PublishStatus.PUBLISHED.getValue());
if (StringUtils.hasText(dto.getContestName())) {
wrapper.like(BizContest::getContestName, dto.getContestName());
@ -362,7 +364,7 @@ public class ContestServiceImpl extends ServiceImpl<ContestMapper, BizContest> i
LambdaQueryWrapper<BizContest> publishedWrapper = new LambdaQueryWrapper<>();
publishedWrapper.eq(BizContest::getValidState, 1);
publishedWrapper.eq(BizContest::getContestState, "published");
publishedWrapper.eq(BizContest::getContestState, PublishStatus.PUBLISHED.getValue());
if (!isSuperTenant && tenantId != null) {
publishedWrapper.apply("JSON_CONTAINS(contest_tenants, CAST({0} AS JSON))", tenantId);
}

View File

@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.competition.common.enums.ErrorCode;
import com.competition.common.enums.WorkStatus;
import com.competition.common.enums.RegistrationStatus;
import com.competition.common.exception.BusinessException;
import com.competition.common.result.PageResult;
import com.competition.modules.biz.contest.dto.QueryWorkDto;
@ -68,7 +70,7 @@ public class ContestWorkServiceImpl extends ServiceImpl<ContestWorkMapper, BizCo
if (registration == null) {
throw BusinessException.of(ErrorCode.NOT_FOUND, "报名记录不存在");
}
if (!"passed".equals(registration.getRegistrationState())) {
if (!RegistrationStatus.PASSED.getValue().equals(registration.getRegistrationState())) {
throw BusinessException.of(ErrorCode.BAD_REQUEST, "报名未通过审核,无法提交作品");
}
@ -121,7 +123,7 @@ public class ContestWorkServiceImpl extends ServiceImpl<ContestWorkMapper, BizCo
work.setFiles(dto.getFiles());
work.setVersion(version);
work.setIsLatest(true);
work.setStatus("submitted");
work.setStatus(WorkStatus.SUBMITTED.getValue());
work.setSubmitTime(LocalDateTime.now());
work.setSubmitterUserId(submitterId);
work.setSubmitterAccountNo(registration.getAccountNo());
@ -522,7 +524,7 @@ public class ContestWorkServiceImpl extends ServiceImpl<ContestWorkMapper, BizCo
if (needTenantFilter) {
submittedWrapper.eq(BizContestWork::getTenantId, tenantId);
}
submittedWrapper.eq(BizContestWork::getStatus, "submitted");
submittedWrapper.eq(BizContestWork::getStatus, WorkStatus.SUBMITTED.getValue());
long submitted = count(submittedWrapper);
LambdaQueryWrapper<BizContestWork> reviewingWrapper = new LambdaQueryWrapper<>();
@ -534,7 +536,7 @@ public class ContestWorkServiceImpl extends ServiceImpl<ContestWorkMapper, BizCo
if (needTenantFilter) {
reviewingWrapper.eq(BizContestWork::getTenantId, tenantId);
}
reviewingWrapper.eq(BizContestWork::getStatus, "reviewing");
reviewingWrapper.eq(BizContestWork::getStatus, WorkStatus.REVIEWING.getValue());
long reviewing = count(reviewingWrapper);
LambdaQueryWrapper<BizContestWork> reviewedWrapper = new LambdaQueryWrapper<>();
@ -546,7 +548,7 @@ public class ContestWorkServiceImpl extends ServiceImpl<ContestWorkMapper, BizCo
if (needTenantFilter) {
reviewedWrapper.eq(BizContestWork::getTenantId, tenantId);
}
reviewedWrapper.in(BizContestWork::getStatus, Arrays.asList("accepted", "awarded"));
reviewedWrapper.in(BizContestWork::getStatus, Arrays.asList(WorkStatus.ACCEPTED.getValue(), WorkStatus.AWARDED.getValue()));
long reviewed = count(reviewedWrapper);
Map<String, Object> stats = new LinkedHashMap<>();

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.competition.common.enums.ErrorCode;
import com.competition.common.enums.PublishStatus;
import com.competition.common.exception.BusinessException;
import com.competition.common.result.PageResult;
import com.competition.modules.biz.homework.dto.CreateHomeworkDto;
@ -42,7 +43,7 @@ public class HomeworkServiceImpl extends ServiceImpl<HomeworkMapper, BizHomework
entity.setAttachments(dto.getAttachments());
entity.setPublishScope(dto.getPublishScope());
entity.setReviewRuleId(dto.getReviewRuleId());
entity.setStatus("unpublished");
entity.setStatus(PublishStatus.UNPUBLISHED.getValue());
save(entity);
log.info("作业创建成功ID{}", entity.getId());
@ -84,7 +85,7 @@ public class HomeworkServiceImpl extends ServiceImpl<HomeworkMapper, BizHomework
LambdaQueryWrapper<BizHomework> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(BizHomework::getValidState, 1);
wrapper.eq(BizHomework::getStatus, "published");
wrapper.eq(BizHomework::getStatus, PublishStatus.PUBLISHED.getValue());
if (tenantId != null) {
wrapper.eq(BizHomework::getTenantId, tenantId);
@ -161,7 +162,7 @@ public class HomeworkServiceImpl extends ServiceImpl<HomeworkMapper, BizHomework
throw BusinessException.of(ErrorCode.NOT_FOUND, "作业不存在");
}
entity.setStatus("published");
entity.setStatus(PublishStatus.PUBLISHED.getValue());
entity.setPublishTime(LocalDateTime.now());
if (publishScope != null) {
entity.setPublishScope(publishScope);
@ -180,7 +181,7 @@ public class HomeworkServiceImpl extends ServiceImpl<HomeworkMapper, BizHomework
throw BusinessException.of(ErrorCode.NOT_FOUND, "作业不存在");
}
entity.setStatus("unpublished");
entity.setStatus(PublishStatus.UNPUBLISHED.getValue());
entity.setPublishTime(null);
updateById(entity);

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.competition.common.enums.ErrorCode;
import com.competition.common.enums.PublishStatus;
import com.competition.common.exception.BusinessException;
import com.competition.common.result.PageResult;
import com.competition.modules.biz.homework.dto.CreateSubmissionDto;
@ -40,7 +41,7 @@ public class HomeworkSubmissionServiceImpl extends ServiceImpl<HomeworkSubmissio
if (homework == null) {
throw BusinessException.of(ErrorCode.NOT_FOUND, "作业不存在");
}
if (!"published".equals(homework.getStatus())) {
if (!PublishStatus.PUBLISHED.getValue().equals(homework.getStatus())) {
throw BusinessException.of(ErrorCode.BAD_REQUEST, "作业未发布,无法提交");
}

View File

@ -2,7 +2,12 @@ package com.competition.modules.biz.judge.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.competition.common.constants.RoleConstants;
import com.competition.common.constants.TenantConstants;
import com.competition.common.enums.CommonStatus;
import com.competition.common.enums.ErrorCode;
import com.competition.common.enums.UserSource;
import com.competition.common.enums.UserType;
import com.competition.common.exception.BusinessException;
import com.competition.common.result.PageResult;
import com.competition.common.util.SecurityUtil;
@ -42,7 +47,7 @@ public class JudgesManagementServiceImpl implements IJudgesManagementService {
*/
private Long getJudgeTenantId() {
LambdaQueryWrapper<SysTenant> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysTenant::getCode, "judge");
wrapper.eq(SysTenant::getCode, TenantConstants.CODE_JUDGE);
SysTenant tenant = sysTenantMapper.selectOne(wrapper);
if (tenant == null) {
throw BusinessException.of(ErrorCode.BAD_REQUEST, "评委租户不存在,请先创建 code='judge' 的租户");
@ -55,7 +60,7 @@ public class JudgesManagementServiceImpl implements IJudgesManagementService {
*/
private Long getOrCreateJudgeRoleId(Long tenantId) {
LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysRole::getCode, "judge");
wrapper.eq(SysRole::getCode, RoleConstants.JUDGE);
wrapper.eq(SysRole::getTenantId, tenantId);
SysRole role = sysRoleMapper.selectOne(wrapper);
if (role != null) {
@ -65,7 +70,7 @@ public class JudgesManagementServiceImpl implements IJudgesManagementService {
// 自动创建 judge 角色
role = new SysRole();
role.setTenantId(tenantId);
role.setCode("judge");
role.setCode(RoleConstants.JUDGE);
role.setName("评委");
role.setDescription("评委角色");
sysRoleMapper.insert(role);
@ -156,9 +161,9 @@ public class JudgesManagementServiceImpl implements IJudgesManagementService {
user.setEmail(email);
user.setPhone(phone);
user.setOrganization(organization);
user.setUserSource("admin_created");
user.setUserType("adult");
user.setStatus("enabled");
user.setUserSource(UserSource.ADMIN_CREATED.getValue());
user.setUserType(UserType.ADULT.getValue());
user.setStatus(CommonStatus.ENABLED.getValue());
sysUserMapper.insert(user);
// 分配评委角色在当前租户下查找或自动创建 judge 角色
@ -182,7 +187,7 @@ public class JudgesManagementServiceImpl implements IJudgesManagementService {
for (Long tid : List.of(currentTenantId, judgeTenantId)) {
if (tid == null) continue;
LambdaQueryWrapper<SysRole> roleWrapper = new LambdaQueryWrapper<>();
roleWrapper.eq(SysRole::getCode, "judge");
roleWrapper.eq(SysRole::getCode, RoleConstants.JUDGE);
roleWrapper.eq(SysRole::getTenantId, tid);
SysRole role = sysRoleMapper.selectOne(roleWrapper);
if (role != null) {
@ -278,13 +283,13 @@ public class JudgesManagementServiceImpl implements IJudgesManagementService {
@Override
public void freeze(Long id) {
updateJudgeStatus(id, "disabled");
updateJudgeStatus(id, CommonStatus.DISABLED.getValue());
log.info("评委账号已冻结ID{}", id);
}
@Override
public void unfreeze(Long id) {
updateJudgeStatus(id, "enabled");
updateJudgeStatus(id, CommonStatus.ENABLED.getValue());
log.info("评委账号已解冻ID{}", id);
}

View File

@ -1,6 +1,8 @@
package com.competition.modules.biz.review.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.competition.common.enums.PublishStatus;
import com.competition.common.enums.RegistrationStatus;
import com.competition.modules.biz.contest.entity.BizContest;
import com.competition.modules.biz.contest.entity.BizContestRegistration;
import com.competition.modules.biz.contest.entity.BizContestWork;
@ -39,7 +41,7 @@ public class AnalyticsService {
// --- summary ---
long totalContests = contestMapper.selectCount(
new LambdaQueryWrapper<BizContest>()
.eq(tenantId != null, BizContest::getContestState, "published"));
.eq(tenantId != null, BizContest::getContestState, PublishStatus.PUBLISHED.getValue()));
long totalRegistrations = contestRegistrationMapper.selectCount(
new LambdaQueryWrapper<BizContestRegistration>()
@ -48,7 +50,7 @@ public class AnalyticsService {
long passedRegistrations = contestRegistrationMapper.selectCount(
new LambdaQueryWrapper<BizContestRegistration>()
.eq(contestId != null, BizContestRegistration::getContestId, contestId)
.eq(BizContestRegistration::getRegistrationState, "passed"));
.eq(BizContestRegistration::getRegistrationState, RegistrationStatus.PASSED.getValue()));
long totalWorks = contestWorkMapper.selectCount(
new LambdaQueryWrapper<BizContestWork>()

View File

@ -2,6 +2,8 @@ package com.competition.modules.biz.review.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.competition.common.constants.TenantConstants;
import com.competition.common.enums.CommonStatus;
import com.competition.common.enums.ErrorCode;
import com.competition.common.exception.BusinessException;
import com.competition.modules.biz.review.dto.ContestJudgesForContestVo;
@ -80,7 +82,7 @@ public class ContestJudgeServiceImpl extends ServiceImpl<ContestJudgeMapper, Biz
if (judgeTenantId != null) {
LambdaQueryWrapper<SysUser> platformWrapper = new LambdaQueryWrapper<>();
platformWrapper.eq(SysUser::getTenantId, judgeTenantId);
platformWrapper.eq(SysUser::getStatus, "enabled");
platformWrapper.eq(SysUser::getStatus, CommonStatus.ENABLED.getValue());
platformJudges = sysUserMapper.selectList(platformWrapper);
}
@ -175,7 +177,7 @@ public class ContestJudgeServiceImpl extends ServiceImpl<ContestJudgeMapper, Biz
*/
private Long getJudgeTenantId() {
LambdaQueryWrapper<SysTenant> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysTenant::getCode, "judge");
wrapper.eq(SysTenant::getCode, TenantConstants.CODE_JUDGE);
SysTenant tenant = sysTenantMapper.selectOne(wrapper);
return tenant != null ? tenant.getId() : null;
}

View File

@ -3,6 +3,7 @@ package com.competition.modules.biz.review.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.competition.common.enums.ErrorCode;
import com.competition.common.enums.PublishStatus;
import com.competition.common.exception.BusinessException;
import com.competition.common.result.PageResult;
import com.competition.modules.biz.contest.entity.BizContest;
@ -266,7 +267,7 @@ public class ContestResultServiceImpl implements IContestResultService {
throw BusinessException.of(ErrorCode.BAD_REQUEST, "没有已排名的作品,请先计算排名");
}
contest.setResultState("published");
contest.setResultState(PublishStatus.PUBLISHED.getValue());
contest.setResultPublishTime(LocalDateTime.now());
contest.setStatus("finished");
contestMapper.updateById(contest);
@ -283,11 +284,11 @@ public class ContestResultServiceImpl implements IContestResultService {
throw BusinessException.of(ErrorCode.NOT_FOUND, "赛事不存在");
}
if (!"published".equals(contest.getResultState())) {
if (!PublishStatus.PUBLISHED.getValue().equals(contest.getResultState())) {
throw BusinessException.of(ErrorCode.BAD_REQUEST, "赛果未发布,无法撤回");
}
contest.setResultState("unpublished");
contest.setResultState(PublishStatus.UNPUBLISHED.getValue());
contest.setResultPublishTime(null);
contestMapper.updateById(contest);

View File

@ -3,6 +3,7 @@ package com.competition.modules.biz.review.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.competition.common.enums.ErrorCode;
import com.competition.common.enums.WorkStatus;
import com.competition.common.exception.BusinessException;
import com.competition.common.result.PageResult;
import com.competition.modules.biz.contest.entity.BizContest;
@ -222,8 +223,8 @@ public class ContestReviewServiceImpl implements IContestReviewService {
// 6. 更新作品状态为评审中
BizContestWork work = workMapper.selectById(dto.getWorkId());
if (work != null && !"reviewing".equals(work.getStatus())) {
work.setStatus("reviewing");
if (work != null && !WorkStatus.REVIEWING.getValue().equals(work.getStatus())) {
work.setStatus(WorkStatus.REVIEWING.getValue());
workMapper.updateById(work);
}
@ -556,7 +557,13 @@ public class ContestReviewServiceImpl implements IContestReviewService {
baseWrapper.eq(BizContestWork::getValidState, 1);
long total = workMapper.selectCount(baseWrapper);
String[] statuses = {"submitted", "locked", "reviewing", "rejected", "accepted"};
String[] statuses = {
WorkStatus.SUBMITTED.getValue(),
WorkStatus.LOCKED.getValue(),
WorkStatus.REVIEWING.getValue(),
WorkStatus.REJECTED.getValue(),
WorkStatus.ACCEPTED.getValue()
};
Map<String, Object> result = new LinkedHashMap<>();
result.put("total", total);

View File

@ -12,7 +12,7 @@ import org.springframework.context.annotation.Configuration;
@ConfigurationProperties(prefix = "leai")
public class LeaiConfig {
/** 机构ID乐读派管理后台分配 */
/** 机构ID乐读派管理后台分配,对应本项目的租户 code即 tenant_code */
// private String orgId = "LESINGLE888888888";
private String orgId = "gdlib";
@ -21,8 +21,8 @@ public class LeaiConfig {
// private String appSecret = "leai_test_secret_2026_abc123xyz";
/** 乐读派后端 API 地址 */
private String apiUrl = "http://192.168.1.72:8080";
private String apiUrl = "http://192.168.1.120:8080";
/** 乐读派 H5 前端地址 */
private String h5Url = "http://192.168.1.72:3001";
private String h5Url = "http://192.168.1.120:3001";
}

View File

@ -52,7 +52,7 @@ public class LeaiApiClient {
String url = leaiConfig.getApiUrl() + "/api/v1/auth/session";
Map<String, String> body = new HashMap<>();
body.put("orgId", leaiConfig.getOrgId());
body.put("orgId", leaiConfig.getOrgId()); // orgId 对应本项目租户 codetenant_code
body.put("appSecret", leaiConfig.getAppSecret());
body.put("phone", phone);
@ -98,6 +98,7 @@ public class LeaiApiClient {
* GET /api/v1/query/work/{workId}
*/
public Map<String, Object> fetchWorkDetail(String workId) {
// orgId 对应本项目租户 codetenant_code
Map<String, String> queryParams = new TreeMap<>();
queryParams.put("orgId", leaiConfig.getOrgId());
@ -106,7 +107,7 @@ public class LeaiApiClient {
try {
String url = leaiConfig.getApiUrl() + "/api/v1/query/work/"
+ URLEncoder.encode(workId, StandardCharsets.UTF_8)
+ "?orgId=" + URLEncoder.encode(leaiConfig.getOrgId(), StandardCharsets.UTF_8);
+ "?orgId=" + URLEncoder.encode(leaiConfig.getOrgId(), StandardCharsets.UTF_8); // 租户 code
HttpHeaders headers = new HttpHeaders();
hmacHeaders.forEach(headers::set);
@ -139,6 +140,7 @@ public class LeaiApiClient {
* GET /api/v1/query/works
*/
public List<Map<String, Object>> queryWorks(String updatedAfter) {
// orgId 对应本项目租户 codetenant_code
Map<String, String> queryParams = new TreeMap<>();
queryParams.put("orgId", leaiConfig.getOrgId());
queryParams.put("updatedAfter", updatedAfter);
@ -213,7 +215,7 @@ public class LeaiApiClient {
String sig = hmacSha256(signStr.toString(), leaiConfig.getAppSecret());
Map<String, String> headers = new LinkedHashMap<>();
headers.put("X-App-Key", leaiConfig.getOrgId());
headers.put("X-App-Key", leaiConfig.getOrgId()); // X-App-Key 即租户 codetenant_code
headers.put("X-Timestamp", ts);
headers.put("X-Nonce", nonce);
headers.put("X-Signature", sig);

View File

@ -2,6 +2,7 @@ package com.competition.modules.leai.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.competition.common.enums.Visibility;
import com.competition.modules.leai.util.LeaiUtil;
import com.competition.modules.ugc.entity.UgcWork;
import com.competition.modules.ugc.entity.UgcWorkPage;
@ -96,7 +97,7 @@ public class LeaiSyncService implements ILeaiSyncService {
work.setRemoteWorkId(remoteWorkId);
work.setTitle(LeaiUtil.toString(remoteData.get("title"), "未命名作品"));
work.setStatus(LeaiUtil.toInt(remoteData.get("status"), LeaiApiClient.STATUS_PENDING));
work.setVisibility("private");
work.setVisibility(Visibility.PRIVATE.getValue());
work.setIsDeleted(0);
work.setIsRecommended(false);
work.setViewCount(0);
@ -271,8 +272,8 @@ public class LeaiSyncService implements ILeaiSyncService {
* 多租户场景需要确定租户后查找
*/
private Long findUserIdByPhone(String phone) {
// TODO: 如果需要按租户隔离需要传入 orgId 查找租户再查找用户
// TODO: 如果需要按租户隔离需要传入 orgId即租户 code/tenant_code查找租户再查找用户
// 当前简化处理直接通过手机号查用户
return null; // 暂时不自动关联用户后续通过 phone + orgId 查询
return null; // 暂时不自动关联用户后续通过 phone + orgId租户 code查询
}
}

View File

@ -2,6 +2,7 @@ package com.competition.modules.pub.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.competition.common.enums.CommonStatus;
import com.competition.common.exception.BusinessException;
import com.competition.common.result.Result;
import com.competition.modules.ugc.entity.UgcTag;
@ -39,7 +40,7 @@ public class TagManagementController {
tag.setCategory((String) body.get("category"));
tag.setColor((String) body.get("color"));
tag.setSort(body.get("sort") != null ? ((Number) body.get("sort")).intValue() : 0);
tag.setStatus("enabled");
tag.setStatus(CommonStatus.ENABLED.getValue());
tag.setUsageCount(0);
tag.setCreateTime(LocalDateTime.now());
tag.setModifyTime(LocalDateTime.now());
@ -91,7 +92,7 @@ public class TagManagementController {
if (tag == null) {
throw new BusinessException(404, "标签不存在");
}
String newStatus = "enabled".equals(tag.getStatus()) ? "disabled" : "enabled";
String newStatus = CommonStatus.ENABLED.getValue().equals(tag.getStatus()) ? CommonStatus.DISABLED.getValue() : CommonStatus.ENABLED.getValue();
tag.setStatus(newStatus);
tag.setModifyTime(LocalDateTime.now());
ugcTagMapper.updateById(tag);

View File

@ -3,6 +3,8 @@ package com.competition.modules.pub.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.competition.common.constants.TenantConstants;
import com.competition.common.enums.*;
import com.competition.common.exception.BusinessException;
import com.competition.common.result.PageResult;
import com.competition.modules.biz.contest.entity.BizContest;
@ -44,8 +46,8 @@ public class PublicActivityService {
*/
public PageResult<BizContest> listActivities(int page, int pageSize, String keyword, String contestType) {
LambdaQueryWrapper<BizContest> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(BizContest::getVisibility, "public")
.eq(BizContest::getContestState, "published");
wrapper.eq(BizContest::getVisibility, Visibility.PUBLIC.getValue())
.eq(BizContest::getContestState, PublishStatus.PUBLISHED.getValue());
if (StringUtils.hasText(keyword)) {
wrapper.like(BizContest::getContestName, keyword);
}
@ -286,7 +288,7 @@ public class PublicActivityService {
if (contest == null) {
throw new BusinessException(404, "活动不存在");
}
if (!"published".equals(contest.getContestState())) {
if (!PublishStatus.PUBLISHED.getValue().equals(contest.getContestState())) {
throw new BusinessException(400, "活动未发布");
}
@ -300,10 +302,10 @@ public class PublicActivityService {
reg.setTenantId(tenantId);
}
reg.setRegistrationType(contest.getContestType());
reg.setParticipantType(dto.getParticipantType() != null ? dto.getParticipantType() : "self");
reg.setParticipantType(dto.getParticipantType() != null ? dto.getParticipantType() : ParticipantType.SELF.getValue());
reg.setChildId(dto.getChildId());
reg.setTeamId(dto.getTeamId());
reg.setRegistrationState(Boolean.TRUE.equals(contest.getRequireAudit()) ? "pending" : "passed");
reg.setRegistrationState(Boolean.TRUE.equals(contest.getRequireAudit()) ? RegistrationStatus.PENDING.getValue() : RegistrationStatus.PASSED.getValue());
reg.setRegistrationTime(LocalDateTime.now());
// 设置必填字段
reg.setRegistrant(userId.intValue());
@ -330,11 +332,11 @@ public class PublicActivityService {
if (anyReg == null) {
throw new BusinessException(400, "您尚未报名该活动,请先报名");
}
if (!"passed".equals(anyReg.getRegistrationState())) {
if (!RegistrationStatus.PASSED.getValue().equals(anyReg.getRegistrationState())) {
String state = anyReg.getRegistrationState();
String msg = switch (state) {
case "pending" -> "报名审核中,请等待审核通过后再提交作品";
case "rejected" -> "报名已被拒绝,无法提交作品";
case "pending" -> "报名审核中,请等待审核通过后再提交作品"; // RegistrationStatus.PENDING
case "rejected" -> "报名已被拒绝,无法提交作品"; // RegistrationStatus.REJECTED
case "withdrawn" -> "报名已撤回,请重新报名";
default -> "报名状态异常(" + state + "),无法提交作品";
};
@ -372,7 +374,7 @@ public class PublicActivityService {
// 使用报名记录的租户ID已在 register 时设置为活动的租户确保管理端可见
work.setTenantId(reg.getTenantId());
work.setSubmitterUserId(userId);
work.setStatus("submitted");
work.setStatus(WorkStatus.SUBMITTED.getValue());
work.setSubmitTime(LocalDateTime.now());
work.setVersion(nextVersion);
work.setIsLatest(true);

View File

@ -2,6 +2,11 @@ package com.competition.modules.pub.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.competition.common.exception.BusinessException;
import com.competition.common.constants.RoleConstants;
import com.competition.common.constants.TenantConstants;
import com.competition.common.enums.CommonStatus;
import com.competition.common.enums.UserSource;
import com.competition.common.enums.UserType;
import com.competition.modules.pub.dto.PublicLoginDto;
import com.competition.modules.pub.dto.PublicRegisterDto;
import com.competition.modules.sys.entity.SysRole;
@ -46,7 +51,7 @@ public class PublicAuthService {
public Map<String, Object> register(PublicRegisterDto dto) {
// 查找公众租户
SysTenant publicTenant = sysTenantMapper.selectOne(
new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getCode, "public"));
new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getCode, TenantConstants.CODE_PUBLIC));
if (publicTenant == null) {
throw new BusinessException(500, "公众租户未配置");
}
@ -68,21 +73,21 @@ public class PublicAuthService {
user.setNickname(dto.getNickname());
user.setPhone(dto.getPhone());
user.setCity(dto.getCity());
user.setUserSource("self_registered");
user.setUserType("adult");
user.setStatus("enabled");
user.setUserSource(UserSource.SELF_REGISTERED.getValue());
user.setUserType(UserType.ADULT.getValue());
user.setStatus(CommonStatus.ENABLED.getValue());
sysUserMapper.insert(user);
// 查找或创建 public_user 角色
SysRole publicRole = sysRoleMapper.selectOne(
new LambdaQueryWrapper<SysRole>()
.eq(SysRole::getCode, "public_user")
.eq(SysRole::getCode, RoleConstants.PUBLIC_USER)
.eq(SysRole::getTenantId, publicTenant.getId()));
if (publicRole == null) {
publicRole = new SysRole();
publicRole.setTenantId(publicTenant.getId());
publicRole.setName("公众用户");
publicRole.setCode("public_user");
publicRole.setCode(RoleConstants.PUBLIC_USER);
publicRole.setDescription("公众端注册用户默认角色");
sysRoleMapper.insert(publicRole);
}
@ -105,7 +110,7 @@ public class PublicAuthService {
public Map<String, Object> login(PublicLoginDto dto) {
// 先在公众租户下查找
SysTenant publicTenant = sysTenantMapper.selectOne(
new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getCode, "public"));
new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getCode, TenantConstants.CODE_PUBLIC));
SysUser user = null;
if (publicTenant != null) {
@ -127,7 +132,7 @@ public class PublicAuthService {
throw new BusinessException(401, "用户名或密码错误");
}
if (!"enabled".equals(user.getStatus())) {
if (!CommonStatus.ENABLED.getValue().equals(user.getStatus())) {
throw new BusinessException(403, "账号已被禁用");
}

View File

@ -3,6 +3,7 @@ package com.competition.modules.pub.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.competition.common.enums.WorkStatus;
import com.competition.common.exception.BusinessException;
import com.competition.common.result.PageResult;
import com.competition.modules.sys.entity.SysUser;
@ -36,8 +37,8 @@ public class PublicContentReviewService {
Map<String, Long> stats = new LinkedHashMap<>();
stats.put("pending_review", countByStatus("pending_review"));
stats.put("published", countByStatus("published"));
stats.put("rejected", countByStatus("rejected"));
stats.put("taken_down", countByStatus("taken_down"));
stats.put("rejected", countByStatus(WorkStatus.REJECTED.getValue()));
stats.put("taken_down", countByStatus(WorkStatus.TAKEN_DOWN.getValue()));
return stats;
}
@ -223,8 +224,8 @@ public class PublicContentReviewService {
new LambdaQueryWrapper<UgcWork>().eq(UgcWork::getIsDeleted, 0)));
stats.put("pendingReview", countByStatus("pending_review"));
stats.put("published", countByStatus("published"));
stats.put("rejected", countByStatus("rejected"));
stats.put("takenDown", countByStatus("taken_down"));
stats.put("rejected", countByStatus(WorkStatus.REJECTED.getValue()));
stats.put("takenDown", countByStatus(WorkStatus.TAKEN_DOWN.getValue()));
stats.put("recommended", ugcWorkMapper.selectCount(
new LambdaQueryWrapper<UgcWork>()
.eq(UgcWork::getIsDeleted, 0)

View File

@ -3,6 +3,7 @@ package com.competition.modules.pub.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.competition.common.enums.Visibility;
import com.competition.common.exception.BusinessException;
import com.competition.common.result.PageResult;
import com.competition.modules.ugc.entity.UgcWork;
@ -35,7 +36,7 @@ public class PublicCreationService {
work.setOriginalImageUrl(originalImageUrl);
work.setVoiceInputUrl(voiceInputUrl);
work.setTextInput(textInput);
work.setVisibility("private");
work.setVisibility(Visibility.PRIVATE.getValue());
work.setViewCount(0);
work.setLikeCount(0);
work.setFavoriteCount(0);

View File

@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.competition.common.enums.PublishStatus;
import com.competition.common.enums.Visibility;
import com.competition.common.exception.BusinessException;
import com.competition.common.result.PageResult;
import com.competition.modules.sys.entity.SysUser;
@ -34,8 +36,8 @@ public class PublicGalleryService {
public PageResult<Map<String, Object>> getGalleryList(int page, int pageSize, Long tagId,
String category, String sortBy, String keyword) {
LambdaQueryWrapper<UgcWork> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(UgcWork::getStatus, "published")
.eq(UgcWork::getVisibility, "public")
wrapper.eq(UgcWork::getStatus, PublishStatus.PUBLISHED.getValue())
.eq(UgcWork::getVisibility, Visibility.PUBLIC.getValue())
.eq(UgcWork::getIsDeleted, 0);
if (StringUtils.hasText(keyword)) {
wrapper.like(UgcWork::getTitle, keyword);
@ -68,8 +70,8 @@ public class PublicGalleryService {
public List<Map<String, Object>> getRecommended() {
LambdaQueryWrapper<UgcWork> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(UgcWork::getIsRecommended, true)
.eq(UgcWork::getStatus, "published")
.eq(UgcWork::getVisibility, "public")
.eq(UgcWork::getStatus, PublishStatus.PUBLISHED.getValue())
.eq(UgcWork::getVisibility, Visibility.PUBLIC.getValue())
.eq(UgcWork::getIsDeleted, 0)
.orderByDesc(UgcWork::getPublishTime)
.last("LIMIT 20");
@ -137,8 +139,8 @@ public class PublicGalleryService {
public PageResult<Map<String, Object>> getUserPublicWorks(Long userId, int page, int pageSize) {
LambdaQueryWrapper<UgcWork> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(UgcWork::getUserId, userId)
.eq(UgcWork::getStatus, "published")
.eq(UgcWork::getVisibility, "public")
.eq(UgcWork::getStatus, PublishStatus.PUBLISHED.getValue())
.eq(UgcWork::getVisibility, Visibility.PUBLIC.getValue())
.eq(UgcWork::getIsDeleted, 0)
.orderByDesc(UgcWork::getPublishTime);

View File

@ -2,6 +2,10 @@ package com.competition.modules.pub.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.competition.common.constants.TenantConstants;
import com.competition.common.enums.CommonStatus;
import com.competition.common.enums.UserSource;
import com.competition.common.enums.UserType;
import com.competition.common.exception.BusinessException;
import com.competition.modules.pub.dto.CreateChildDto;
import com.competition.modules.sys.entity.SysUser;
@ -148,7 +152,7 @@ public class PublicProfileService {
String nickname, String gender, String city, String avatar) {
// 找公众租户
SysTenant publicTenant = sysTenantMapper.selectOne(
new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getCode, "public"));
new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getCode, TenantConstants.CODE_PUBLIC));
if (publicTenant == null) {
throw new BusinessException(500, "公众租户未配置");
}
@ -171,9 +175,9 @@ public class PublicProfileService {
childUser.setGender(gender);
childUser.setCity(city);
childUser.setAvatar(avatar);
childUser.setUserSource("admin_created");
childUser.setUserType("child");
childUser.setStatus("enabled");
childUser.setUserSource(UserSource.ADMIN_CREATED.getValue());
childUser.setUserType(UserType.CHILD.getValue());
childUser.setStatus(CommonStatus.ENABLED.getValue());
sysUserMapper.insert(childUser);
// 创建亲子关系

View File

@ -1,6 +1,7 @@
package com.competition.modules.pub.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.competition.common.enums.CommonStatus;
import com.competition.modules.ugc.entity.UgcTag;
import com.competition.modules.ugc.mapper.UgcTagMapper;
import lombok.RequiredArgsConstructor;
@ -22,7 +23,7 @@ public class PublicTagService {
public List<UgcTag> listTags() {
return ugcTagMapper.selectList(
new LambdaQueryWrapper<UgcTag>()
.eq(UgcTag::getStatus, "enabled")
.eq(UgcTag::getStatus, CommonStatus.ENABLED.getValue())
.orderByAsc(UgcTag::getSort));
}
@ -32,7 +33,7 @@ public class PublicTagService {
public List<UgcTag> getHotTags() {
return ugcTagMapper.selectList(
new LambdaQueryWrapper<UgcTag>()
.eq(UgcTag::getStatus, "enabled")
.eq(UgcTag::getStatus, CommonStatus.ENABLED.getValue())
.orderByDesc(UgcTag::getUsageCount)
.last("LIMIT 20"));
}

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.competition.common.enums.Visibility;
import com.competition.common.exception.BusinessException;
import com.competition.common.result.PageResult;
import com.competition.modules.ugc.entity.UgcWork;
@ -41,7 +42,7 @@ public class PublicUserWorkService {
work.setTitle(title);
work.setCoverUrl(coverUrl);
work.setDescription(description);
work.setVisibility(visibility != null ? visibility : "private");
work.setVisibility(visibility != null ? visibility : Visibility.PRIVATE.getValue());
work.setStatus(0); // 0=DRAFT
work.setViewCount(0);
work.setLikeCount(0);

View File

@ -1,6 +1,8 @@
package com.competition.modules.sys.config;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.competition.common.constants.RoleConstants;
import com.competition.common.constants.TenantConstants;
import com.competition.modules.sys.entity.SysPermission;
import com.competition.modules.sys.entity.SysRole;
import com.competition.modules.sys.entity.SysRolePermission;
@ -35,7 +37,7 @@ public class JudgeRolePermissionConfigurer implements ApplicationRunner {
);
private static final String TEMPLATE_TENANT_CODE_GDLIB = "gdlib";
private static final String JUDGE_TENANT_CODE = "judge";
private static final String JUDGE_TENANT_CODE = TenantConstants.CODE_JUDGE;
private final SysPermissionMapper permissionMapper;
private final SysRolePermissionMapper rolePermissionMapper;
@ -46,7 +48,7 @@ public class JudgeRolePermissionConfigurer implements ApplicationRunner {
public void run(ApplicationArguments args) {
List<SysRole> judgeRoles = roleMapper.selectList(
new LambdaQueryWrapper<SysRole>()
.eq(SysRole::getCode, "judge")
.eq(SysRole::getCode, RoleConstants.JUDGE)
.eq(SysRole::getValidState, 1));
for (SysRole role : judgeRoles) {
try {

View File

@ -32,7 +32,7 @@ public class SysTenant extends BaseEntity {
@TableField("is_super")
private Integer isSuper;
@Schema(description = "租户类型platform/library/kindergarten/school/institution/other")
@Schema(description = "租户类型", allowableValues = {"platform", "library", "kindergarten", "school", "institution", "other"})
@TableField("tenant_type")
private String tenantType;
}

View File

@ -45,11 +45,11 @@ public class SysUser extends BaseEntity {
@TableField("wx_unionid")
private String wxUnionid;
@Schema(description = "用户来源admin_created/self_registered/child_migrated")
@Schema(description = "用户来源", allowableValues = {"admin_created", "self_registered", "child_migrated"})
@TableField("user_source")
private String userSource;
@Schema(description = "用户类型adult/child")
@Schema(description = "用户类型", allowableValues = {"adult", "child"})
@TableField("user_type")
private String userType;
@ -68,6 +68,6 @@ public class SysUser extends BaseEntity {
@Schema(description = "所属单位")
private String organization;
@Schema(description = "账号状态enabled/disabled")
@Schema(description = "账号状态", allowableValues = {"enabled", "disabled"})
private String status;
}

View File

@ -1,5 +1,8 @@
package com.competition.modules.sys.service;
import com.competition.common.constants.BaseEntityConstants;
import com.competition.common.constants.CacheConstants;
import com.competition.common.enums.CommonStatus;
import com.competition.common.enums.ErrorCode;
import com.competition.common.exception.BusinessException;
import com.competition.modules.sys.entity.SysTenant;
@ -39,7 +42,7 @@ public class AuthService {
SysTenant tenantByCode = tenantService.getOne(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SysTenant>()
.eq(SysTenant::getCode, tenantCode)
.eq(SysTenant::getValidState, 1), false);
.eq(SysTenant::getValidState, BaseEntityConstants.VALID), false);
if (tenantByCode != null) {
tenantId = tenantByCode.getId();
}
@ -57,7 +60,7 @@ public class AuthService {
}
// 验证用户状态
if ("disabled".equals(user.getStatus())) {
if (CommonStatus.DISABLED.getValue().equals(user.getStatus())) {
throw BusinessException.of(ErrorCode.FORBIDDEN, "账号已被禁用");
}
@ -135,19 +138,19 @@ public class AuthService {
*/
private void cacheUserAuth(Long userId, List<String> roles, List<String> permissions) {
try {
String rolesKey = "user:roles:" + userId;
String permsKey = "user:perms:" + userId;
String rolesKey = CacheConstants.USER_ROLES_PREFIX + userId;
String permsKey = CacheConstants.USER_PERMS_PREFIX + userId;
redisTemplate.delete(rolesKey);
redisTemplate.delete(permsKey);
if (!roles.isEmpty()) {
redisTemplate.opsForSet().add(rolesKey, roles.toArray(new String[0]));
redisTemplate.expire(rolesKey, 7, TimeUnit.DAYS);
redisTemplate.expire(rolesKey, CacheConstants.AUTH_CACHE_DAYS, TimeUnit.DAYS);
}
if (!permissions.isEmpty()) {
redisTemplate.opsForSet().add(permsKey, permissions.toArray(new String[0]));
redisTemplate.expire(permsKey, 7, TimeUnit.DAYS);
redisTemplate.expire(permsKey, CacheConstants.AUTH_CACHE_DAYS, TimeUnit.DAYS);
}
} catch (Exception e) {
log.warn("缓存用户权限到 Redis 失败:{}", e.getMessage());

View File

@ -2,6 +2,7 @@ package com.competition.modules.sys.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.competition.common.constants.RoleConstants;
import com.competition.common.enums.ErrorCode;
import com.competition.common.exception.BusinessException;
import com.competition.modules.sys.dto.CreateMenuDto;
@ -64,7 +65,7 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
List<String> roles = isSuperAdmin ? Collections.emptyList() : userMapper.selectRolesByUserId(userId);
// 租户评委与平台评委共用我的评审菜单树机构租户未在 t_sys_tenant_menu 中配置时按角色合并评委端菜单
if (!isSuperAdmin && roles != null && roles.contains("judge")) {
if (!isSuperAdmin && roles != null && roles.contains(RoleConstants.JUDGE)) {
tenantMenuIds.addAll(collectJudgePortalMenuIds(allMenus));
}
@ -189,10 +190,10 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
if (roles == null || roles.isEmpty()) {
return false;
}
if (!roles.contains("judge")) {
if (!roles.contains(RoleConstants.JUDGE)) {
return false;
}
return !roles.contains("tenant_admin") && !roles.contains("super_admin");
return !roles.contains(RoleConstants.TENANT_ADMIN) && !roles.contains(RoleConstants.SUPER_ADMIN);
}
private boolean isTenantJudgeManagementMenu(SysMenu menu) {

View File

@ -4,7 +4,14 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.competition.common.constants.BaseEntityConstants;
import com.competition.common.constants.RoleConstants;
import com.competition.common.constants.TenantConstants;
import com.competition.common.enums.CommonStatus;
import com.competition.common.enums.ErrorCode;
import com.competition.common.enums.TenantType;
import com.competition.common.enums.UserSource;
import com.competition.common.enums.UserType;
import com.competition.common.exception.BusinessException;
import com.competition.common.result.PageResult;
import com.competition.modules.sys.dto.CreateTenantDto;
@ -28,8 +35,6 @@ import java.util.*;
@RequiredArgsConstructor
public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant> implements ISysTenantService {
private static final Set<String> INTERNAL_TENANT_CODES = Set.of("super", "public", "school", "teacher", "student", "judge");
/** 广东省图租户编码,作为新租户权限模板 */
private static final String TEMPLATE_TENANT_CODE = "gdlib";
@ -70,7 +75,7 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
tenant.setCode(dto.getCode());
tenant.setDomain(dto.getDomain());
tenant.setDescription(dto.getDescription());
tenant.setTenantType(dto.getTenantType() != null ? dto.getTenantType() : "other");
tenant.setTenantType(dto.getTenantType() != null ? dto.getTenantType() : TenantType.OTHER.getValue());
tenant.setIsSuper(0);
save(tenant);
Long tenantId = tenant.getId();
@ -82,7 +87,7 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
SysRole adminRole = new SysRole();
adminRole.setTenantId(tenantId);
adminRole.setName("机构管理员");
adminRole.setCode("tenant_admin");
adminRole.setCode(RoleConstants.TENANT_ADMIN);
adminRole.setDescription(tenant.getName() + "管理员角色,拥有该租户所有权限");
roleMapper.insert(adminRole);
@ -105,9 +110,9 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
adminUser.setUsername(adminUsername);
adminUser.setPassword(passwordEncoder.encode(adminPassword));
adminUser.setNickname(tenant.getName() + "管理员");
adminUser.setStatus("enabled");
adminUser.setUserSource("admin_created");
adminUser.setUserType("adult");
adminUser.setStatus(CommonStatus.ENABLED.getValue());
adminUser.setUserSource(UserSource.ADMIN_CREATED.getValue());
adminUser.setUserType(UserType.ADULT.getValue());
userMapper.insert(adminUser);
// 6. 绑定用户-角色
@ -156,7 +161,7 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
List<SysPermission> templatePerms = permissionMapper.selectList(
new LambdaQueryWrapper<SysPermission>()
.eq(SysPermission::getTenantId, templateTenant.getId())
.eq(SysPermission::getValidState, 1));
.eq(SysPermission::getValidState, BaseEntityConstants.VALID));
for (SysPermission tp : templatePerms) {
SysPermission np = new SysPermission();
np.setTenantId(newTenantId);
@ -198,8 +203,8 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
@Override
public PageResult<Map<String, Object>> findAll(Long page, Long pageSize, String keyword, String tenantType) {
LambdaQueryWrapper<SysTenant> wrapper = new LambdaQueryWrapper<SysTenant>()
.eq(SysTenant::getValidState, 1)
.notIn(SysTenant::getCode, INTERNAL_TENANT_CODES)
.eq(SysTenant::getValidState, BaseEntityConstants.VALID)
.notIn(SysTenant::getCode, TenantConstants.INTERNAL_TENANT_CODES)
.orderByDesc(SysTenant::getCreateTime);
if (keyword != null && !keyword.isBlank()) {
@ -226,7 +231,7 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
map.put("createTime", tenant.getCreateTime());
Long userCount = userMapper.selectCount(
new LambdaQueryWrapper<SysUser>().eq(SysUser::getTenantId, tenant.getId()).eq(SysUser::getValidState, 1));
new LambdaQueryWrapper<SysUser>().eq(SysUser::getTenantId, tenant.getId()).eq(SysUser::getValidState, BaseEntityConstants.VALID));
map.put("_count", Map.of("users", userCount));
list.add(map);
@ -254,7 +259,7 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
map.put("createTime", tenant.getCreateTime());
Long userCount = userMapper.selectCount(
new LambdaQueryWrapper<SysUser>().eq(SysUser::getTenantId, id).eq(SysUser::getValidState, 1));
new LambdaQueryWrapper<SysUser>().eq(SysUser::getTenantId, id).eq(SysUser::getValidState, BaseEntityConstants.VALID));
map.put("_count", Map.of("users", userCount));
return map;
@ -309,7 +314,7 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
SysTenant update = new SysTenant();
update.setId(id);
update.setValidState(tenant.getValidState() == 1 ? 2 : 1);
update.setValidState(tenant.getValidState() == BaseEntityConstants.VALID ? BaseEntityConstants.INVALID : BaseEntityConstants.VALID);
updateById(update);
}

View File

@ -5,7 +5,12 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.competition.common.constants.BaseEntityConstants;
import com.competition.common.constants.TenantConstants;
import com.competition.common.enums.CommonStatus;
import com.competition.common.enums.ErrorCode;
import com.competition.common.enums.UserSource;
import com.competition.common.enums.UserType;
import com.competition.common.exception.BusinessException;
import com.competition.common.result.PageResult;
import com.competition.modules.sys.dto.CreateUserDto;
@ -63,9 +68,9 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
user.setPhone(dto.getPhone());
user.setGender(dto.getGender());
user.setAvatar(dto.getAvatar());
user.setStatus(dto.getStatus() != null ? dto.getStatus() : "enabled");
user.setUserSource("admin_created");
user.setUserType("adult");
user.setStatus(dto.getStatus() != null ? dto.getStatus() : CommonStatus.ENABLED.getValue());
user.setUserSource(UserSource.ADMIN_CREATED.getValue());
user.setUserType(UserType.ADULT.getValue());
baseMapper.insert(user);
@ -106,11 +111,11 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
}
case "judge" -> {
// 按租户 code='judge' 过滤因为 judge 租户的 tenant_type 可能是 other
params.put("tenantCodeFilter", "judge");
params.put("tenantCodeFilter", TenantConstants.CODE_JUDGE);
}
case "public" -> {
// 按租户 code='public' 过滤因为 public 租户的 tenant_type=platform不是 public
params.put("tenantCodeFilter", "public");
params.put("tenantCodeFilter", TenantConstants.CODE_PUBLIC);
}
}
}
@ -143,9 +148,9 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
*/
private List<Long> getOrgTenantIds() {
List<SysTenant> tenants = tenantMapper.selectList(
new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getValidState, 1));
new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getValidState, BaseEntityConstants.VALID));
return tenants.stream()
.filter(t -> t.getIsSuper() == 0 && !"public".equals(t.getCode()) && !"judge".equals(t.getCode()))
.filter(t -> t.getIsSuper() == 0 && !TenantConstants.CODE_PUBLIC.equals(t.getCode()) && !TenantConstants.CODE_JUDGE.equals(t.getCode()))
.map(SysTenant::getId)
.toList();
}
@ -153,23 +158,23 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
@Override
public Map<String, Object> getStats() {
List<SysTenant> tenants = tenantMapper.selectList(
new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getValidState, 1));
new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getValidState, BaseEntityConstants.VALID));
List<Long> superIds = tenants.stream().filter(t -> t.getIsSuper() == 1).map(SysTenant::getId).toList();
List<Long> publicIds = tenants.stream().filter(t -> "public".equals(t.getCode())).map(SysTenant::getId).toList();
List<Long> judgeIds = tenants.stream().filter(t -> "judge".equals(t.getCode())).map(SysTenant::getId).toList();
List<Long> publicIds = tenants.stream().filter(t -> TenantConstants.CODE_PUBLIC.equals(t.getCode())).map(SysTenant::getId).toList();
List<Long> judgeIds = tenants.stream().filter(t -> TenantConstants.CODE_JUDGE.equals(t.getCode())).map(SysTenant::getId).toList();
List<Long> orgIds = tenants.stream()
.filter(t -> t.getIsSuper() == 0 && !"public".equals(t.getCode()) && !"judge".equals(t.getCode()))
.filter(t -> t.getIsSuper() == 0 && !TenantConstants.CODE_PUBLIC.equals(t.getCode()) && !TenantConstants.CODE_JUDGE.equals(t.getCode()))
.map(SysTenant::getId).toList();
LambdaQueryWrapper<SysUser> base = new LambdaQueryWrapper<SysUser>().eq(SysUser::getValidState, 1);
LambdaQueryWrapper<SysUser> base = new LambdaQueryWrapper<SysUser>().eq(SysUser::getValidState, BaseEntityConstants.VALID);
Map<String, Object> stats = new HashMap<>();
stats.put("total", count(base));
stats.put("platform", superIds.isEmpty() ? 0 : count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getValidState, 1).in(SysUser::getTenantId, superIds)));
stats.put("org", orgIds.isEmpty() ? 0 : count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getValidState, 1).in(SysUser::getTenantId, orgIds)));
stats.put("judge", judgeIds.isEmpty() ? 0 : count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getValidState, 1).in(SysUser::getTenantId, judgeIds)));
stats.put("public", publicIds.isEmpty() ? 0 : count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getValidState, 1).in(SysUser::getTenantId, publicIds)));
stats.put("platform", superIds.isEmpty() ? 0 : count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getValidState, BaseEntityConstants.VALID).in(SysUser::getTenantId, superIds)));
stats.put("org", orgIds.isEmpty() ? 0 : count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getValidState, BaseEntityConstants.VALID).in(SysUser::getTenantId, orgIds)));
stats.put("judge", judgeIds.isEmpty() ? 0 : count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getValidState, BaseEntityConstants.VALID).in(SysUser::getTenantId, judgeIds)));
stats.put("public", publicIds.isEmpty() ? 0 : count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getValidState, BaseEntityConstants.VALID).in(SysUser::getTenantId, publicIds)));
return stats;
}
@ -189,7 +194,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
public SysUser findByUsername(String username, Long tenantId) {
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<SysUser>()
.eq(SysUser::getUsername, username)
.eq(SysUser::getValidState, 1);
.eq(SysUser::getValidState, BaseEntityConstants.VALID);
if (tenantId != null) {
wrapper.eq(SysUser::getTenantId, tenantId);
}

View File

@ -38,7 +38,7 @@ public class UgcWork implements Serializable {
@Schema(description = "作品描述")
private String description;
@Schema(description = "可见范围")
@Schema(description = "可见范围", allowableValues = {"public", "designated", "internal", "private"})
private String visibility;
@Schema(description = "作品状态:-1=FAILED, 0=DRAFT, 1=PENDING, 2=PROCESSING, 3=COMPLETED, 4=CATALOGED, 5=DUBBED")

View File

@ -1,5 +1,7 @@
package com.competition.security.filter;
import com.competition.common.constants.CacheConstants;
import com.competition.common.constants.RoleConstants;
import com.competition.modules.sys.mapper.SysUserMapper;
import com.competition.security.model.LoginUser;
import com.competition.security.util.JwtUtil;
@ -88,8 +90,8 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
// 优先从 Redis 获取
try {
String rolesKey = "user:roles:" + userId;
String permsKey = "user:perms:" + userId;
String rolesKey = CacheConstants.USER_ROLES_PREFIX + userId;
String permsKey = CacheConstants.USER_PERMS_PREFIX + userId;
Set<String> cachedRoles = redisTemplate.opsForSet().members(rolesKey);
Set<String> cachedPerms = redisTemplate.opsForSet().members(permsKey);
@ -114,7 +116,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
loginUser.setRoles(roles);
loginUser.setPermissions(permissions);
loginUser.setSuperAdmin(roles.contains("super_admin"));
loginUser.setSuperAdmin(roles.contains(RoleConstants.SUPER_ADMIN));
return loginUser;
}

View File

@ -48,5 +48,5 @@ logging:
leai:
org-id: ${LEAI_ORG_ID:gdlib}
app-secret: ${LEAI_APP_SECRET:leai_mnoi9q1a_mtcawrn8y}
api-url: ${LEAI_API_URL:http://192.168.1.72:8080}
h5-url: ${LEAI_H5_URL:http://192.168.1.72:3001}
api-url: ${LEAI_API_URL:http://192.168.1.120:8080}
h5-url: ${LEAI_H5_URL:http://192.168.1.120:3001}

View File

@ -48,5 +48,5 @@ logging:
leai:
org-id: ${LEAI_ORG_ID:gdlib}
app-secret: ${LEAI_APP_SECRET:leai_mnoi9q1a_mtcawrn8y}
api-url: ${LEAI_API_URL:http://192.168.1.72:8080}
h5-url: ${LEAI_H5_URL:http://192.168.1.72:3001}
api-url: ${LEAI_API_URL:http://192.168.1.120:8080}
h5-url: ${LEAI_H5_URL:http://192.168.1.120:3001}

View File

@ -0,0 +1,339 @@
-- ============================================================
-- V6: 为所有数据库表添加表注释和字段注释
-- 执行时间2026-04-08
-- 说明:基于 INFORMATION_SCHEMA 实际列定义生成,确保类型准确
-- ============================================================
-- ============================================================
-- 一、表级别注释
-- ============================================================
ALTER TABLE t_biz_contest COMMENT='赛事表';
ALTER TABLE t_biz_contest_attachment COMMENT='赛事附件表';
ALTER TABLE t_biz_contest_notice COMMENT='赛事公告表';
ALTER TABLE t_biz_contest_registration COMMENT='赛事报名表';
ALTER TABLE t_biz_contest_registration_teacher COMMENT='赛事报名老师关联表';
ALTER TABLE t_biz_contest_team COMMENT='赛事团队表';
ALTER TABLE t_biz_contest_team_member COMMENT='赛事团队成员表';
ALTER TABLE t_biz_contest_work COMMENT='赛事作品表';
ALTER TABLE t_biz_contest_work_attachment COMMENT='赛事作品附件表';
ALTER TABLE t_biz_homework COMMENT='作业表';
ALTER TABLE t_biz_homework_review_rule COMMENT='作业评审规则表';
ALTER TABLE t_biz_homework_score COMMENT='作业评分表';
ALTER TABLE t_biz_homework_submission COMMENT='作业提交表';
ALTER TABLE t_sys_config COMMENT='系统配置表';
ALTER TABLE t_sys_dict COMMENT='数据字典表';
ALTER TABLE t_sys_dict_item COMMENT='数据字典项表';
ALTER TABLE t_sys_log COMMENT='系统操作日志表';
ALTER TABLE t_sys_menu COMMENT='系统菜单表';
ALTER TABLE t_sys_permission COMMENT='系统权限表';
ALTER TABLE t_sys_role COMMENT='系统角色表';
ALTER TABLE t_sys_role_permission COMMENT='角色权限关联表';
ALTER TABLE t_sys_tenant COMMENT='系统租户表';
ALTER TABLE t_sys_tenant_menu COMMENT='租户菜单关联表';
ALTER TABLE t_sys_user COMMENT='系统用户表';
ALTER TABLE t_sys_user_role COMMENT='用户角色关联表';
ALTER TABLE t_ugc_review_log COMMENT='UGC审核日志表';
ALTER TABLE t_ugc_tag COMMENT='UGC标签表';
ALTER TABLE t_ugc_work COMMENT='UGC作品表';
ALTER TABLE t_ugc_work_comment COMMENT='作品评论表';
ALTER TABLE t_ugc_work_favorite COMMENT='作品收藏表';
ALTER TABLE t_ugc_work_like COMMENT='作品点赞表';
ALTER TABLE t_ugc_work_page COMMENT='作品页面表';
ALTER TABLE t_ugc_work_report COMMENT='作品举报表';
ALTER TABLE t_ugc_work_tag COMMENT='作品标签关联表';
ALTER TABLE t_user_child COMMENT='用户子女表';
ALTER TABLE t_user_parent_child COMMENT='家长子女关联表';
-- ============================================================
-- 二、字段级别注释(基于实际列定义)
-- ============================================================
-- ============================================================
-- 1. t_biz_contest
-- ============================================================
-- t_biz_contest所有列已有注释无需更新
-- ============================================================
-- 2. t_biz_contest_attachment
-- ============================================================
-- t_biz_contest_attachment所有列已有注释无需更新
-- ============================================================
-- 3. t_biz_contest_notice
-- ============================================================
-- t_biz_contest_notice所有列已有注释无需更新
-- ============================================================
-- 4. t_biz_contest_registration
-- ============================================================
-- t_biz_contest_registration所有列已有注释无需更新
-- ============================================================
-- 5. t_biz_contest_registration_teacher
-- ============================================================
-- t_biz_contest_registration_teacher所有列已有注释无需更新
-- ============================================================
-- 6. t_biz_contest_team
-- ============================================================
-- t_biz_contest_team所有列已有注释无需更新
-- ============================================================
-- 7. t_biz_contest_team_member
-- ============================================================
-- t_biz_contest_team_member所有列已有注释无需更新
-- ============================================================
-- 8. t_biz_contest_work
-- ============================================================
-- t_biz_contest_work所有列已有注释无需更新
-- ============================================================
-- 9. t_biz_contest_work_attachment
-- ============================================================
-- t_biz_contest_work_attachment所有列已有注释无需更新
-- ============================================================
-- 10. t_biz_homework
-- ============================================================
-- t_biz_homework所有列已有注释无需更新
-- ============================================================
-- 11. t_biz_homework_review_rule
-- ============================================================
ALTER TABLE t_biz_homework_review_rule
MODIFY COLUMN `tenant_id` int NOT NULL COMMENT '租户ID',
MODIFY COLUMN `name` varchar(191) NOT NULL COMMENT '规则名称',
MODIFY COLUMN `description` text DEFAULT NULL COMMENT '规则描述',
MODIFY COLUMN `criteria` json NOT NULL COMMENT '评分标准JSON数组',
MODIFY COLUMN `creator` int DEFAULT NULL COMMENT '创建人ID',
MODIFY COLUMN `modifier` int DEFAULT NULL COMMENT '修改人ID',
MODIFY COLUMN `create_time` datetime(3) NOT NULL COMMENT '创建时间',
MODIFY COLUMN `modify_time` datetime(3) NOT NULL COMMENT '修改时间',
MODIFY COLUMN `valid_state` int NOT NULL COMMENT '有效状态1-有效2-失效';
-- ============================================================
-- 12. t_biz_homework_score
-- ============================================================
ALTER TABLE t_biz_homework_score
MODIFY COLUMN `tenant_id` int NOT NULL COMMENT '租户ID',
MODIFY COLUMN `submission_id` int NOT NULL COMMENT '提交ID',
MODIFY COLUMN `reviewer_id` int NOT NULL COMMENT '评审人ID',
MODIFY COLUMN `dimension_scores` json NOT NULL COMMENT '各维度得分JSON',
MODIFY COLUMN `total_score` decimal(10,2) NOT NULL COMMENT '总分',
MODIFY COLUMN `comments` text DEFAULT NULL COMMENT '评语',
MODIFY COLUMN `score_time` datetime(3) NOT NULL COMMENT '评分时间',
MODIFY COLUMN `creator` int DEFAULT NULL COMMENT '创建人ID',
MODIFY COLUMN `modifier` int DEFAULT NULL COMMENT '修改人ID',
MODIFY COLUMN `create_time` datetime(3) NOT NULL COMMENT '创建时间',
MODIFY COLUMN `modify_time` datetime(3) NOT NULL COMMENT '修改时间',
MODIFY COLUMN `valid_state` int NOT NULL COMMENT '有效状态1-有效2-失效';
-- ============================================================
-- 13. t_biz_homework_submission
-- ============================================================
ALTER TABLE t_biz_homework_submission
MODIFY COLUMN `tenant_id` int NOT NULL COMMENT '租户ID',
MODIFY COLUMN `homework_id` int NOT NULL COMMENT '作业ID',
MODIFY COLUMN `student_id` int NOT NULL COMMENT '学生ID',
MODIFY COLUMN `work_no` varchar(191) DEFAULT NULL COMMENT '作品编号',
MODIFY COLUMN `work_name` varchar(191) NOT NULL COMMENT '作品名称',
MODIFY COLUMN `work_description` text DEFAULT NULL COMMENT '作品描述',
MODIFY COLUMN `files` json DEFAULT NULL COMMENT '作品文件JSON',
MODIFY COLUMN `attachments` json DEFAULT NULL COMMENT '附件JSON',
MODIFY COLUMN `submit_time` datetime(3) NOT NULL COMMENT '提交时间',
MODIFY COLUMN `status` varchar(191) NOT NULL COMMENT '状态pending/reviewed',
MODIFY COLUMN `total_score` decimal(10,2) DEFAULT NULL COMMENT '总分',
MODIFY COLUMN `creator` int DEFAULT NULL COMMENT '创建人ID',
MODIFY COLUMN `modifier` int DEFAULT NULL COMMENT '修改人ID',
MODIFY COLUMN `create_time` datetime(3) NOT NULL COMMENT '创建时间',
MODIFY COLUMN `modify_time` datetime(3) NOT NULL COMMENT '修改时间',
MODIFY COLUMN `valid_state` int NOT NULL COMMENT '有效状态1-有效2-失效';
-- ============================================================
-- 14. t_sys_config
-- ============================================================
-- t_sys_config所有列已有注释无需更新
-- ============================================================
-- 15. t_sys_dict
-- ============================================================
-- t_sys_dict所有列已有注释无需更新
-- ============================================================
-- 16. t_sys_dict_item
-- ============================================================
-- t_sys_dict_item所有列已有注释无需更新
-- ============================================================
-- 17. t_sys_log
-- ============================================================
-- t_sys_log所有列已有注释无需更新
-- ============================================================
-- 18. t_sys_menu
-- ============================================================
-- t_sys_menu所有列已有注释无需更新
-- ============================================================
-- 19. t_sys_permission
-- ============================================================
-- t_sys_permission所有列已有注释无需更新
-- ============================================================
-- 20. t_sys_role
-- ============================================================
-- t_sys_role所有列已有注释无需更新
-- ============================================================
-- 21. t_sys_role_permission
-- ============================================================
-- t_sys_role_permission所有列已有注释无需更新
-- ============================================================
-- 22. t_sys_tenant
-- ============================================================
-- t_sys_tenant所有列已有注释无需更新
-- ============================================================
-- 23. t_sys_tenant_menu
-- ============================================================
-- t_sys_tenant_menu所有列已有注释无需更新
-- ============================================================
-- 24. t_sys_user
-- ============================================================
-- t_sys_user所有列已有注释无需更新
-- ============================================================
-- 25. t_sys_user_role
-- ============================================================
-- t_sys_user_role所有列已有注释无需更新
-- ============================================================
-- 26. t_ugc_review_log
-- ============================================================
ALTER TABLE t_ugc_review_log
MODIFY COLUMN `target_type` varchar(191) NOT NULL COMMENT '目标类型',
MODIFY COLUMN `target_id` int NOT NULL COMMENT '目标ID',
MODIFY COLUMN `work_id` int DEFAULT NULL COMMENT '作品ID',
MODIFY COLUMN `action` varchar(191) NOT NULL COMMENT '操作动作',
MODIFY COLUMN `reason` text DEFAULT NULL COMMENT '原因',
MODIFY COLUMN `note` text DEFAULT NULL COMMENT '备注',
MODIFY COLUMN `operator_id` int NOT NULL COMMENT '操作人ID',
MODIFY COLUMN `create_time` datetime(3) NOT NULL COMMENT '创建时间';
-- ============================================================
-- 27. t_ugc_tag
-- ============================================================
ALTER TABLE t_ugc_tag
MODIFY COLUMN `name` varchar(50) NOT NULL COMMENT '标签名称',
MODIFY COLUMN `category` varchar(50) DEFAULT NULL COMMENT '标签分类',
MODIFY COLUMN `sort` int NOT NULL COMMENT '排序',
MODIFY COLUMN `status` varchar(191) NOT NULL COMMENT '状态',
MODIFY COLUMN `usage_count` int NOT NULL COMMENT '使用次数',
MODIFY COLUMN `create_time` datetime(3) NOT NULL COMMENT '创建时间',
MODIFY COLUMN `modify_time` datetime(3) NOT NULL COMMENT '修改时间',
MODIFY COLUMN `color` varchar(20) DEFAULT NULL COMMENT '标签颜色';
-- ============================================================
-- 28. t_ugc_work
-- ============================================================
ALTER TABLE t_ugc_work
MODIFY COLUMN `user_id` int NOT NULL COMMENT '用户ID',
MODIFY COLUMN `title` varchar(200) NOT NULL COMMENT '作品标题',
MODIFY COLUMN `cover_url` text DEFAULT NULL COMMENT '封面图URL',
MODIFY COLUMN `description` text DEFAULT NULL COMMENT '作品描述',
MODIFY COLUMN `visibility` varchar(191) NOT NULL COMMENT '可见范围',
MODIFY COLUMN `review_note` text DEFAULT NULL COMMENT '审核备注',
MODIFY COLUMN `review_time` datetime(3) DEFAULT NULL COMMENT '审核时间',
MODIFY COLUMN `reviewer_id` int DEFAULT NULL COMMENT '审核人ID',
MODIFY COLUMN `machine_review_result` varchar(191) DEFAULT NULL COMMENT '机审结果',
MODIFY COLUMN `machine_review_note` text DEFAULT NULL COMMENT '机审备注',
MODIFY COLUMN `is_recommended` tinyint(1) NOT NULL COMMENT '是否推荐',
MODIFY COLUMN `view_count` int NOT NULL COMMENT '浏览数',
MODIFY COLUMN `like_count` int NOT NULL COMMENT '点赞数',
MODIFY COLUMN `favorite_count` int NOT NULL COMMENT '收藏数',
MODIFY COLUMN `comment_count` int NOT NULL COMMENT '评论数',
MODIFY COLUMN `share_count` int NOT NULL COMMENT '分享数',
MODIFY COLUMN `original_image_url` text DEFAULT NULL COMMENT '原图URL',
MODIFY COLUMN `voice_input_url` text DEFAULT NULL COMMENT '语音输入URL',
MODIFY COLUMN `text_input` text DEFAULT NULL COMMENT '文本输入',
MODIFY COLUMN `ai_meta` json DEFAULT NULL COMMENT 'AI元数据JSON',
MODIFY COLUMN `publish_time` datetime(3) DEFAULT NULL COMMENT '发布时间',
MODIFY COLUMN `is_deleted` int NOT NULL COMMENT '是否删除0-未删除1-已删除',
MODIFY COLUMN `create_time` datetime(3) NOT NULL COMMENT '创建时间',
MODIFY COLUMN `modify_time` datetime(3) NOT NULL COMMENT '修改时间';
-- ============================================================
-- 29. t_ugc_work_comment
-- ============================================================
ALTER TABLE t_ugc_work_comment
MODIFY COLUMN `work_id` int NOT NULL COMMENT '作品ID',
MODIFY COLUMN `user_id` int NOT NULL COMMENT '用户ID',
MODIFY COLUMN `parent_id` int DEFAULT NULL COMMENT '父评论ID',
MODIFY COLUMN `content` text NOT NULL COMMENT '评论内容',
MODIFY COLUMN `status` varchar(191) NOT NULL COMMENT '状态',
MODIFY COLUMN `create_time` datetime(3) NOT NULL COMMENT '创建时间';
-- ============================================================
-- 30. t_ugc_work_favorite
-- ============================================================
ALTER TABLE t_ugc_work_favorite
MODIFY COLUMN `user_id` int NOT NULL COMMENT '用户ID',
MODIFY COLUMN `work_id` int NOT NULL COMMENT '作品ID',
MODIFY COLUMN `create_time` datetime(3) NOT NULL COMMENT '创建时间';
-- ============================================================
-- 31. t_ugc_work_like
-- ============================================================
ALTER TABLE t_ugc_work_like
MODIFY COLUMN `user_id` int NOT NULL COMMENT '用户ID',
MODIFY COLUMN `work_id` int NOT NULL COMMENT '作品ID',
MODIFY COLUMN `create_time` datetime(3) NOT NULL COMMENT '创建时间';
-- ============================================================
-- 32. t_ugc_work_page
-- ============================================================
ALTER TABLE t_ugc_work_page
MODIFY COLUMN `work_id` int NOT NULL COMMENT '作品ID',
MODIFY COLUMN `page_no` int NOT NULL COMMENT '页码',
MODIFY COLUMN `image_url` text DEFAULT NULL COMMENT '图片URL',
MODIFY COLUMN `text` text DEFAULT NULL COMMENT '文本内容',
MODIFY COLUMN `audio_url` text DEFAULT NULL COMMENT '音频URL';
-- ============================================================
-- 33. t_ugc_work_report
-- ============================================================
ALTER TABLE t_ugc_work_report
MODIFY COLUMN `reporter_id` int NOT NULL COMMENT '举报人ID',
MODIFY COLUMN `target_type` varchar(191) NOT NULL COMMENT '目标类型',
MODIFY COLUMN `target_id` int NOT NULL COMMENT '目标ID',
MODIFY COLUMN `target_user_id` int DEFAULT NULL COMMENT '被举报用户ID',
MODIFY COLUMN `reason` varchar(200) NOT NULL COMMENT '举报原因',
MODIFY COLUMN `description` text DEFAULT NULL COMMENT '举报描述',
MODIFY COLUMN `status` varchar(191) NOT NULL COMMENT '状态',
MODIFY COLUMN `handle_action` varchar(191) DEFAULT NULL COMMENT '处理动作',
MODIFY COLUMN `handle_note` text DEFAULT NULL COMMENT '处理备注',
MODIFY COLUMN `handler_id` int DEFAULT NULL COMMENT '处理人ID',
MODIFY COLUMN `handle_time` datetime(3) DEFAULT NULL COMMENT '处理时间',
MODIFY COLUMN `create_time` datetime(3) NOT NULL COMMENT '创建时间';
-- ============================================================
-- 34. t_ugc_work_tag
-- ============================================================
ALTER TABLE t_ugc_work_tag
MODIFY COLUMN `work_id` int NOT NULL COMMENT '作品ID',
MODIFY COLUMN `tag_id` int NOT NULL COMMENT '标签ID';
-- ============================================================
-- 35. t_user_child
-- ============================================================
-- t_user_child所有列已有注释无需更新
-- ============================================================
-- 36. t_user_parent_child
-- ============================================================
-- t_user_parent_child所有列已有注释无需更新

View File

@ -0,0 +1,131 @@
-- ============================================================
-- V7: 补充所有表 id 列和遗漏列的字段注释
-- 执行时间2026-04-08
-- ============================================================
ALTER TABLE t_biz_contest
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_biz_contest_attachment
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_biz_contest_judge
MODIFY COLUMN `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_biz_contest_notice
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_biz_contest_registration
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_biz_contest_registration_teacher
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_biz_contest_review_rule
MODIFY COLUMN `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_biz_contest_team
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_biz_contest_team_member
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_biz_contest_work
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_biz_contest_work_attachment
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_biz_contest_work_judge_assignment
MODIFY COLUMN `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_biz_contest_work_score
MODIFY COLUMN `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_biz_homework
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_biz_homework_review_rule
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_biz_homework_score
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_biz_homework_submission
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_biz_preset_comment
MODIFY COLUMN `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_leai_webhook_event
MODIFY COLUMN `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
MODIFY COLUMN `create_time` datetime NOT NULL COMMENT '创建时间';
ALTER TABLE t_sys_config
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_sys_dict
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_sys_dict_item
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_sys_log
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_sys_menu
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_sys_permission
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_sys_role
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_sys_role_permission
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_sys_tenant
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_sys_tenant_menu
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_sys_user
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_sys_user_role
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_ugc_review_log
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_ugc_tag
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_ugc_work
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_ugc_work_comment
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_ugc_work_favorite
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_ugc_work_like
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_ugc_work_page
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_ugc_work_report
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_ugc_work_tag
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_user_child
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';
ALTER TABLE t_user_parent_child
MODIFY COLUMN `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID';

View File

@ -73,7 +73,7 @@ test.describe('创作页 iframe 嵌入', () => {
})
// 也拦截通配形式的 H5 URL
await loggedInPage.route('http://192.168.1.72:3001/**', async (route) => {
await loggedInPage.route('http://192.168.1.120:3001/**', async (route) => {
await route.fulfill({
status: 200,
contentType: 'text/html',
@ -112,7 +112,7 @@ test.describe('创作页 iframe 嵌入', () => {
}),
})
})
await loggedInPage.route('http://192.168.1.72:3001/**', async (route) => {
await loggedInPage.route('http://192.168.1.120:3001/**', async (route) => {
await route.fulfill({
status: 200,
contentType: 'text/html',
@ -182,7 +182,7 @@ test.describe('创作页 iframe 嵌入', () => {
})
}
})
await loggedInPage.route('http://192.168.1.72:3001/**', async (route) => {
await loggedInPage.route('http://192.168.1.120:3001/**', async (route) => {
await route.fulfill({
status: 200,
contentType: 'text/html',
@ -222,7 +222,7 @@ test.describe('创作页 iframe 嵌入', () => {
}),
})
})
await loggedInPage.route('http://192.168.1.72:3001/**', async (route) => {
await loggedInPage.route('http://192.168.1.120:3001/**', async (route) => {
await route.fulfill({
status: 200,
contentType: 'text/html',

View File

@ -31,7 +31,7 @@ test.describe('端到端:创作完整流程', () => {
}),
})
})
await loggedInPage.route('http://192.168.1.72:3001/**', async (route) => {
await loggedInPage.route('http://192.168.1.120:3001/**', async (route) => {
await route.fulfill({ status: 200, contentType: 'text/html', path: MOCK_H5_PATH })
})
@ -117,7 +117,7 @@ test.describe('端到端:创作完整流程', () => {
})
})
await loggedInPage.route('http://192.168.1.72:3001/**', async (route) => {
await loggedInPage.route('http://192.168.1.120:3001/**', async (route) => {
await route.fulfill({ status: 200, contentType: 'text/html', path: MOCK_H5_PATH })
})
@ -202,7 +202,7 @@ test.describe('端到端:创作完整流程', () => {
}),
})
})
await loggedInPage.route('http://192.168.1.72:3001/**', async (route) => {
await loggedInPage.route('http://192.168.1.120:3001/**', async (route) => {
await route.fulfill({ status: 200, contentType: 'text/html', path: MOCK_H5_PATH })
})

View File

@ -43,7 +43,7 @@ async function setupMockRoutes(page: import('@playwright/test').Page) {
path: MOCK_H5_PATH,
})
})
await page.route('http://192.168.1.72:3001/**', async (route) => {
await page.route('http://192.168.1.120:3001/**', async (route) => {
await route.fulfill({
status: 200,
contentType: 'text/html',

View File

@ -9,8 +9,8 @@ import crypto from 'crypto'
export const LEAI_TEST_CONFIG = {
orgId: 'gdlib',
appSecret: 'leai_mnoi9q1a_mtcawrn8y',
apiUrl: 'http://192.168.1.72:8080',
h5Url: 'http://192.168.1.72:3001',
apiUrl: 'http://192.168.1.120:8080',
h5Url: 'http://192.168.1.120:3001',
testPhone: '13800001111',
}

View File

@ -78,8 +78,8 @@ public class LeaiDemoApplication {
//
private static final String ORG_ID = "LESINGLE888888888"; // 机构ID管理后台获取
private static final String APP_SECRET = "leai_test_secret_2026_abc123xyz"; // 机构密钥管理后台获取
private static final String LEAI_API_URL = "http://192.168.1.72:8080"; // 乐读派API地址
private static final String LEAI_H5_URL = "http://192.168.1.72:3001"; // 乐读派H5地址
private static final String LEAI_API_URL = "http://192.168.1.120:8080"; // 乐读派API地址
private static final String LEAI_H5_URL = "http://192.168.1.120:3001"; // 乐读派H5地址
// 状态常量V4.0 数值状态机
private static final int STATUS_FAILED = -1;

View File

@ -89,9 +89,9 @@ const urlPhone = new URLSearchParams(window.location.search).get('phone')
const CONFIG = {
ORG_ID: 'LESINGLE888888888',
PHONE: urlPhone || '18911223344',
ENTERPRISE_URL: 'http://192.168.1.72:9090',
API_URL: 'http://192.168.1.72:8080',
H5_URL: 'http://192.168.1.72:3001'
ENTERPRISE_URL: 'http://192.168.1.120:9090',
API_URL: 'http://192.168.1.120:8080',
H5_URL: 'http://192.168.1.120:3001'
}
let currentToken = ''

View File

@ -51,10 +51,10 @@ echo.
echo ========================================================
echo Starting Enterprise Demo...
echo.
echo Home: http://192.168.1.72:9090
echo iframe: http://192.168.1.72:9090/enterprise-sim.html
echo Auth: http://192.168.1.72:9090/leai-auth
echo Webhook: http://192.168.1.72:9090/webhook/leai
echo Home: http://192.168.1.120:9090
echo iframe: http://192.168.1.120:9090/enterprise-sim.html
echo Auth: http://192.168.1.120:9090/leai-auth
echo Webhook: http://192.168.1.120:9090/webhook/leai
echo.
echo Requires: LeAI backend(8080) + H5 frontend(3001)
echo ========================================================

View File

@ -88,9 +88,9 @@ body { font-family: -apple-system, 'Segoe UI', sans-serif; background: #f5f5f5;
const CONFIG = {
ORG_ID: 'LESINGLE888888888',
PHONE: '18911223344',
ENTERPRISE_URL: 'http://192.168.1.72:9090', // 企业后端本Demo
API_URL: 'http://192.168.1.72:8080', // 乐读派后端(仅作品列表查询用)
H5_URL: 'http://192.168.1.72:3001' // 乐读派H5前端
ENTERPRISE_URL: 'http://192.168.1.120:9090', // 企业后端本Demo
API_URL: 'http://192.168.1.120:8080', // 乐读派后端(仅作品列表查询用)
H5_URL: 'http://192.168.1.120:3001' // 乐读派H5前端
// 注意: APP_SECRET 不再出现在前端,仅在企业后端(9090)中使用
}

View File

@ -10,8 +10,8 @@ window.__LEAI_CONFIG__ = {
// ━━━ 开发环境配置authMode=hmac 时生效)━━━━━
dev: {
apiBaseUrl: "http://192.168.1.72:8080",
wsBaseUrl: "ws://192.168.1.72:8080",
apiBaseUrl: "http://192.168.1.120:8080",
wsBaseUrl: "ws://192.168.1.120:8080",
orgId: "LESINGLE888888888",
appSecret: "", // 开发时填入生产环境不需要token模式不使用
phone: "18911223344"
@ -21,8 +21,8 @@ window.__LEAI_CONFIG__ = {
// orgId/phone 由企业重定向URL参数动态传入无需在此配置
// appSecret 仅在企业服务端使用,绝不到达浏览器
prod: {
apiBaseUrl: "http://192.168.1.72:8080",
wsBaseUrl: "ws://192.168.1.72:8080"
apiBaseUrl: "http://192.168.1.120:8080",
wsBaseUrl: "ws://192.168.1.120:8080"
},
// ━━━ 品牌定制(两种模式通用)━━━━━━━━━━━━━━━━━