@@ -11,7 +11,7 @@ import java.time.LocalDateTime;
|
||||
/**
|
||||
* JPA 审计监听器:在实体持久化/更新前自动填充创建人/更新人(平台当前登录人)与时间戳。
|
||||
* 对应 {@link BaseEntity} 的 createBy / updateBy / createTime / updateTime 字段。
|
||||
* 当前登录人取自 {@link UserContext}(用户中心数字ID,字符串形式落审计列)。
|
||||
* 当前登录人取自 {@link UserContext}(用户中心数字ID,直接以 INT 落审计列)。
|
||||
*/
|
||||
@Component
|
||||
public class HomeworkAuditListener {
|
||||
@@ -24,9 +24,9 @@ public class HomeworkAuditListener {
|
||||
Integer userId = UserContext.getUserId();
|
||||
if (userId != null) {
|
||||
if (entity.getCreateBy() == null) {
|
||||
entity.setCreateBy(String.valueOf(userId));
|
||||
entity.setCreateBy(userId);
|
||||
}
|
||||
entity.setUpdateBy(String.valueOf(userId));
|
||||
entity.setUpdateBy(userId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public class HomeworkAuditListener {
|
||||
entity.setUpdateTime(LocalDateTime.now());
|
||||
Integer userId = UserContext.getUserId();
|
||||
if (userId != null) {
|
||||
entity.setUpdateBy(String.valueOf(userId));
|
||||
entity.setUpdateBy(userId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,10 +24,10 @@ public abstract class BaseEntity implements Serializable {
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
* 创建人ID(平台用户ID)
|
||||
* 创建人ID(用户中心数字ID,与业务人员标识同一 ID 空间)
|
||||
*/
|
||||
@Column(name = "create_by", updatable = false)
|
||||
private String createBy;
|
||||
private Integer createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
@@ -36,10 +36,10 @@ public abstract class BaseEntity implements Serializable {
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新人ID(平台用户ID)
|
||||
* 更新人ID(用户中心数字ID)
|
||||
*/
|
||||
@Column(name = "update_by")
|
||||
private String updateBy;
|
||||
private Integer updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
|
||||
@@ -18,6 +18,13 @@ import javax.persistence.Table;
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class SysDict extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 学校ID(多租户隔离:新增时从当前用户角色填充,查询时按校过滤;
|
||||
* 存量数据为 NULL,视为全局字典,全校可见)。
|
||||
*/
|
||||
@Column(name = "sch_id")
|
||||
private Integer schId;
|
||||
|
||||
/** 字典类型(如 "dept"=发文部门) */
|
||||
@Column(name = "dict_type", length = 50)
|
||||
private String dictType;
|
||||
|
||||
@@ -73,9 +73,11 @@ public class HomeworkVo {
|
||||
*/
|
||||
private com.yunhai.homework.model.v2.ProgressVo progress;
|
||||
|
||||
private String createBy;
|
||||
/** 创建人ID(用户中心数字ID) */
|
||||
private Integer createBy;
|
||||
private LocalDateTime createTime;
|
||||
private String updateBy;
|
||||
/** 更新人ID(用户中心数字ID) */
|
||||
private Integer updateBy;
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,14 +2,44 @@ package com.yunhai.homework.repository;
|
||||
|
||||
import com.yunhai.homework.entity.SysDict;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface SysDictRepository extends JpaRepository<SysDict, Integer> {
|
||||
|
||||
// ---------------- 存量/无学校归属(schId 为空时不过滤,同 homework 多租户口径) ----------------
|
||||
|
||||
/** 全量(含禁用),用于管理列表与重名/序号计算 */
|
||||
List<SysDict> findByDictTypeOrderBySortOrderAsc(String dictType);
|
||||
|
||||
/** 启用项(下拉框用) */
|
||||
List<SysDict> findByDictTypeAndEnableFlagOrderBySortOrderAsc(String dictType, Integer enableFlag);
|
||||
|
||||
/** 按类型+key 取单条字典(发文部门名称解析用) */
|
||||
/** 按类型+key 取单条字典 */
|
||||
Optional<SysDict> findByDictTypeAndDictKey(String dictType, String dictKey);
|
||||
|
||||
// ---------------- 多租户:本校 + 全局(sch_id 为 NULL 的存量视为全局,全校可见) ----------------
|
||||
|
||||
/** 可见全量(含禁用):本校 + 全局 */
|
||||
@Query("select d from SysDict d where d.dictType = :dictType " +
|
||||
"and (d.schId = :schId or d.schId is null) order by d.sortOrder asc")
|
||||
List<SysDict> findVisibleBySchIdAndDictType(@Param("schId") Integer schId, @Param("dictType") String dictType);
|
||||
|
||||
/** 可见启用项:本校 + 全局(下拉框用) */
|
||||
@Query("select d from SysDict d where d.dictType = :dictType and d.enableFlag = :enableFlag " +
|
||||
"and (d.schId = :schId or d.schId is null) order by d.sortOrder asc")
|
||||
List<SysDict> findVisibleEnabledBySchIdAndDictType(@Param("schId") Integer schId,
|
||||
@Param("dictType") String dictType,
|
||||
@Param("enableFlag") Integer enableFlag);
|
||||
|
||||
/** 可见单条:本校优先,其次全局;同 key 多条时按本校优先 + id 升序,服务侧取首条 */
|
||||
@Query("select d from SysDict d where d.dictType = :dictType and d.dictKey = :dictKey " +
|
||||
"and (d.schId = :schId or d.schId is null) " +
|
||||
"order by case when d.schId = :schId then 0 else 1 end asc, d.id asc")
|
||||
List<SysDict> findVisibleBySchIdAndDictTypeAndDictKey(@Param("schId") Integer schId,
|
||||
@Param("dictType") String dictType,
|
||||
@Param("dictKey") String dictKey);
|
||||
}
|
||||
|
||||
@@ -69,7 +69,10 @@ public interface IDictService {
|
||||
* 用于作业列表/详情展示 DeptName(对应 C# GetDeptName)。
|
||||
*
|
||||
* @param deptId 作业 deptId(存的是 sys_dict.dict_key)
|
||||
* @param schId 作业所属学校ID(展示场景传 homework.schId,写入场景传当前登录人学校;
|
||||
* 多租户下优先本校字典、其次全局字典,不会命中其他学校同名 key;
|
||||
* 为 null 时退化为全局匹配,兼容存量数据)
|
||||
* @return 部门名称;无匹配时返回 null
|
||||
*/
|
||||
String resolveDeptName(String deptId);
|
||||
String resolveDeptName(String deptId, Integer schId);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.yunhai.homework.repository.SmsModuleRepository;
|
||||
import com.yunhai.homework.repository.SmsSchoolConfigRepository;
|
||||
import com.yunhai.homework.repository.SysDictRepository;
|
||||
import com.yunhai.homework.service.IDictService;
|
||||
import com.yunhai.homework.utils.UserContext;
|
||||
import com.yunhai.platform.apistd.BizException;
|
||||
import com.yunhai.platform.utils.exception.ErrorCode;
|
||||
import org.slf4j.Logger;
|
||||
@@ -19,6 +20,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -64,7 +66,7 @@ public class DictService implements IDictService {
|
||||
if (dictType == null) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "参数错误");
|
||||
}
|
||||
List<SysDict> list = sysDictRepository.findByDictTypeAndEnableFlagOrderBySortOrderAsc(dictType, 1);
|
||||
List<SysDict> list = visibleEnabledList(dictType);
|
||||
if (list.isEmpty()) {
|
||||
throw new BizException(ErrorCode.FORBIDDEN, "尚未添加发文部门,请联系管理员添加!");
|
||||
}
|
||||
@@ -90,7 +92,7 @@ public class DictService implements IDictService {
|
||||
// 非 DEPT 类型需超管权限,本系统暂只支持 DEPT
|
||||
throw new BizException(ErrorCode.FORBIDDEN, "非超管不得操作!");
|
||||
}
|
||||
List<SysDict> list = sysDictRepository.findByDictTypeOrderBySortOrderAsc(dictType);
|
||||
List<SysDict> list = visibleList(dictType);
|
||||
return list.stream()
|
||||
.sorted(Comparator.comparingInt(d -> d.getSortOrder() == null ? 999 : d.getSortOrder()))
|
||||
.map(d -> {
|
||||
@@ -113,21 +115,24 @@ public class DictService implements IDictService {
|
||||
if (!StringUtils.hasText(name)) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "输入字符串格式不正确!");
|
||||
}
|
||||
// 校验重名
|
||||
List<SysDict> existing = sysDictRepository.findByDictTypeOrderBySortOrderAsc(DICT_TYPE_DEPT);
|
||||
Integer schId = UserContext.getSchId();
|
||||
// 重名校验范围 = 本校 + 全局可见项,避免与存量全局字典重名
|
||||
List<SysDict> existing = visibleList(DICT_TYPE_DEPT);
|
||||
boolean duplicate = existing.stream().anyMatch(d ->
|
||||
DICT_TYPE_DEPT.equals(d.getDictType()) && name.equals(d.getDictValue()) && d.getEnableFlag() != 3);
|
||||
if (duplicate) {
|
||||
throw new BizException(ErrorCode.FORBIDDEN, "已存在该分类,请重新填写!");
|
||||
}
|
||||
|
||||
// 计算 sortOrder = max + 1
|
||||
// 计算 sortOrder = max + 1(同样基于本校 + 全局可见项)
|
||||
int maxSort = existing.stream()
|
||||
.filter(d -> d.getEnableFlag() != 3)
|
||||
.mapToInt(d -> d.getSortOrder() != null ? d.getSortOrder() : 0)
|
||||
.max().orElse(0);
|
||||
|
||||
SysDict dict = new SysDict();
|
||||
// 多租户:归属当前登录人学校;无学校归属(区域级)时为 NULL,即全局字典
|
||||
dict.setSchId(schId);
|
||||
dict.setDictType(DICT_TYPE_DEPT);
|
||||
dict.setDictValue(name);
|
||||
dict.setSortOrder(maxSort + 1);
|
||||
@@ -144,16 +149,18 @@ public class DictService implements IDictService {
|
||||
if (serID == null) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "参数错误!");
|
||||
}
|
||||
// 校验重名(排除自身)
|
||||
List<SysDict> existing = sysDictRepository.findByDictTypeOrderBySortOrderAsc(DICT_TYPE_DEPT);
|
||||
SysDict dict = sysDictRepository.findById(serID)
|
||||
.orElseThrow(() -> new BizException(ErrorCode.FORBIDDEN, "字典记录不存在"));
|
||||
checkSchoolScope(dict);
|
||||
|
||||
// 校验重名(排除自身,范围 = 本校 + 全局可见项)
|
||||
List<SysDict> existing = visibleList(DICT_TYPE_DEPT);
|
||||
boolean duplicate = existing.stream().anyMatch(d ->
|
||||
!d.getId().equals(serID) && name.equals(d.getDictValue()) && d.getEnableFlag() != 3);
|
||||
if (duplicate) {
|
||||
throw new BizException(ErrorCode.FORBIDDEN, "已存在该分类,请重新填写!");
|
||||
}
|
||||
|
||||
SysDict dict = sysDictRepository.findById(serID)
|
||||
.orElseThrow(() -> new BizException(ErrorCode.FORBIDDEN, "字典记录不存在"));
|
||||
if (StringUtils.hasText(name)) {
|
||||
dict.setDictValue(name);
|
||||
}
|
||||
@@ -170,11 +177,20 @@ public class DictService implements IDictService {
|
||||
public void delDept(Integer serID) {
|
||||
SysDict dict = sysDictRepository.findById(serID)
|
||||
.orElseThrow(() -> new BizException(ErrorCode.FORBIDDEN, "字典记录不存在"));
|
||||
checkSchoolScope(dict);
|
||||
// 校验是否被作业引用(按 deptId = dictKey 匹配)
|
||||
// C# 中检查 Notify_Message.DeptID == dict.CodeID
|
||||
// Java 中 Homework.deptId 存的是 dictKey
|
||||
List<Homework> referenced = homeworkRepository.findAll((root, query, cb) ->
|
||||
cb.equal(root.get("deptId"), dict.getDictKey()));
|
||||
// Java 中 Homework.deptId 存的是 dictKey;多租户下仅本校作业算引用,
|
||||
// 其他学校同名 key(如各校自建的 dept1)不受影响
|
||||
Integer refSchId = dict.getSchId() != null ? dict.getSchId() : UserContext.getSchId();
|
||||
List<Homework> referenced = homeworkRepository.findAll((root, query, cb) -> {
|
||||
List<Predicate> predicates = new ArrayList<>();
|
||||
predicates.add(cb.equal(root.get("deptId"), dict.getDictKey()));
|
||||
if (refSchId != null) {
|
||||
predicates.add(cb.equal(root.get("schId"), refSchId));
|
||||
}
|
||||
return cb.and(predicates.toArray(new Predicate[0]));
|
||||
});
|
||||
if (!referenced.isEmpty()) {
|
||||
throw new BizException(ErrorCode.FORBIDDEN, "已引用该部门,无法删除!");
|
||||
}
|
||||
@@ -189,7 +205,7 @@ public class DictService implements IDictService {
|
||||
if (!StringUtils.hasText(ids)) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "参数错误");
|
||||
}
|
||||
List<SysDict> list = sysDictRepository.findByDictTypeOrderBySortOrderAsc(DICT_TYPE_DEPT);
|
||||
List<SysDict> list = visibleList(DICT_TYPE_DEPT);
|
||||
if (list.isEmpty()) {
|
||||
throw new BizException(ErrorCode.FORBIDDEN, "字典类型错误,未找到该字典类型");
|
||||
}
|
||||
@@ -205,12 +221,18 @@ public class DictService implements IDictService {
|
||||
.mapToInt(d -> d.getSortOrder() != null ? d.getSortOrder() : idArr.length)
|
||||
.max().orElse(idArr.length);
|
||||
|
||||
// 仅本校可见字典可参与排序(前端 ids 即来自本校管理列表)
|
||||
Set<Integer> visibleIds = list.stream().map(SysDict::getId).collect(Collectors.toSet());
|
||||
|
||||
// lambda 中不能修改局部变量,用数组包装
|
||||
final int[] indexOrd = { maxSort };
|
||||
|
||||
// 逆序遍历,从最大序号递减
|
||||
for (int i = idArr.length - 1; i >= 0; i--) {
|
||||
int id = idArr[i];
|
||||
if (!visibleIds.contains(id)) {
|
||||
continue;
|
||||
}
|
||||
sysDictRepository.findById(id).ifPresent(dict -> {
|
||||
dict.setSortOrder(indexOrd[0]);
|
||||
sysDictRepository.save(dict);
|
||||
@@ -244,17 +266,51 @@ public class DictService implements IDictService {
|
||||
|
||||
/**
|
||||
* 按发文部门字典 key 解析部门名称(对应 C# GetDeptName)。
|
||||
* 多租户:schId 非空时优先本校字典、其次全局(sch_id 为 NULL)字典,
|
||||
* 不会命中其他学校的同名 key;schId 为空时退化为全局匹配(兼容存量调用)。
|
||||
*/
|
||||
@Override
|
||||
public String resolveDeptName(String deptId) {
|
||||
public String resolveDeptName(String deptId, Integer schId) {
|
||||
if (!StringUtils.hasText(deptId)) {
|
||||
return null;
|
||||
}
|
||||
return sysDictRepository.findByDictTypeAndDictKey(DICT_TYPE_DEPT, deptId.trim())
|
||||
String key = deptId.trim();
|
||||
if (schId != null) {
|
||||
List<SysDict> scoped = sysDictRepository.findVisibleBySchIdAndDictTypeAndDictKey(schId, DICT_TYPE_DEPT, key);
|
||||
if (!scoped.isEmpty()) {
|
||||
return scoped.get(0).getDictValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return sysDictRepository.findByDictTypeAndDictKey(DICT_TYPE_DEPT, key)
|
||||
.map(SysDict::getDictValue)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/** 当前登录人可见的全量字典(本校 + 全局;无学校归属时不过滤) */
|
||||
private List<SysDict> visibleList(String dictType) {
|
||||
Integer schId = UserContext.getSchId();
|
||||
return schId != null
|
||||
? sysDictRepository.findVisibleBySchIdAndDictType(schId, dictType)
|
||||
: sysDictRepository.findByDictTypeOrderBySortOrderAsc(dictType);
|
||||
}
|
||||
|
||||
/** 当前登录人可见的启用字典(本校 + 全局;无学校归属时不过滤) */
|
||||
private List<SysDict> visibleEnabledList(String dictType) {
|
||||
Integer schId = UserContext.getSchId();
|
||||
return schId != null
|
||||
? sysDictRepository.findVisibleEnabledBySchIdAndDictType(schId, dictType, 1)
|
||||
: sysDictRepository.findByDictTypeAndEnableFlagOrderBySortOrderAsc(dictType, 1);
|
||||
}
|
||||
|
||||
/** 多租户写保护:禁止操作其他学校的字典(全局字典与无学校归属用户不受限) */
|
||||
private void checkSchoolScope(SysDict dict) {
|
||||
Integer schId = UserContext.getSchId();
|
||||
if (dict.getSchId() != null && schId != null && !dict.getSchId().equals(schId)) {
|
||||
throw new BizException(ErrorCode.FORBIDDEN, "无权操作其他学校的字典!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将前端 Type 参数映射到字典类型字符串。
|
||||
* C# 中使用枚举,Java 版仅支持 DEPT(1)。
|
||||
|
||||
@@ -1021,9 +1021,9 @@ public class HomeworkService implements IHomeworkService {
|
||||
String legacy = legacyHwStatus(entity);
|
||||
vo.setHwStatus(legacy);
|
||||
vo.setHwStatusDesc(legacyHwStatusDesc(legacy));
|
||||
// 存量数据 dept_name 为空时按 deptId 从字典兜底解析(对应 C# GetDeptName)
|
||||
// 存量数据 dept_name 为空时按 deptId 从字典兜底解析(对应 C# GetDeptName;按作业所属学校匹配)
|
||||
if (!StringUtils.hasText(vo.getDeptName())) {
|
||||
vo.setDeptName(dictService.resolveDeptName(vo.getDeptId()));
|
||||
vo.setDeptName(dictService.resolveDeptName(vo.getDeptId(), entity.getSchId()));
|
||||
}
|
||||
vo.setRead(read);
|
||||
vo.setReadCount(homeworkReadRepository.countByHomeworkId(entity.getId()));
|
||||
@@ -1031,10 +1031,10 @@ public class HomeworkService implements IHomeworkService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入时解析部门名称:优先按 deptId 查字典,字典缺失时回退前端传值。
|
||||
* 写入时解析部门名称:优先按 deptId 查本校字典,字典缺失时回退前端传值。
|
||||
*/
|
||||
private String resolveDeptName(HomeworkRequest request) {
|
||||
String resolved = dictService.resolveDeptName(request.getDeptId());
|
||||
String resolved = dictService.resolveDeptName(request.getDeptId(), UserContext.getSchId());
|
||||
return StringUtils.hasText(resolved) ? resolved : request.getDeptName();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ CREATE TABLE IF NOT EXISTS `homework_receiver` (
|
||||
`receiver_id` INT NOT NULL COMMENT '接收人ID(用户中心数字ID)',
|
||||
`receiver_name` VARCHAR(64) NULL COMMENT '接收人姓名快照',
|
||||
`receive_type` INT NOT NULL DEFAULT 1 COMMENT '接收类型:1 接收 / 2 抄送',
|
||||
`create_by` VARCHAR(64) NULL COMMENT '创建人ID(审计填充)',
|
||||
`create_by` INT NULL COMMENT '创建人ID(用户中心数字ID)',
|
||||
`create_time` DATETIME NULL COMMENT '创建时间(审计填充)',
|
||||
`update_by` VARCHAR(64) NULL COMMENT '更新人ID(审计填充)',
|
||||
`update_by` INT NULL COMMENT '更新人ID(用户中心数字ID)',
|
||||
`update_time` DATETIME NULL COMMENT '更新时间(审计填充)',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_homework_id` (`homework_id`),
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
-- 2) MySQL 5.7 不支持 ADD COLUMN IF NOT EXISTS,重复执行前请先核对列是否存在;
|
||||
-- 3) 定时发布时间复用 homework.timing_send_time(PRD scheduled_at 同义),不新增列。
|
||||
-- 4) 人员标识口径:教师/学生一律为用户中心数字ID(INT),不存登录账号
|
||||
-- (与 v3_account_to_id_refactor.sql / v4_person_id_to_int.sql 收敛后的最终形态一致)。
|
||||
-- (与 v3_account_to_id_refactor.sql / v4_person_id_to_int.sql 收敛后的最终形态一致);
|
||||
-- 审计列 create_by / update_by 亦为用户中心数字ID(INT),
|
||||
-- 与 v5_audit_by_to_int.sql 收敛后的最终形态一致。
|
||||
-- =====================================================================
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
@@ -32,9 +34,9 @@ CREATE TABLE IF NOT EXISTS `homework_class` (
|
||||
`homework_id` INT NOT NULL,
|
||||
`class_id` VARCHAR(64) NOT NULL,
|
||||
`class_name` VARCHAR(50) NULL COMMENT '班级名快照',
|
||||
`create_by` VARCHAR(64) NULL,
|
||||
`create_by` INT NULL COMMENT '创建人ID(用户中心数字ID)',
|
||||
`create_time` DATETIME NULL,
|
||||
`update_by` VARCHAR(64) NULL,
|
||||
`update_by` INT NULL COMMENT '更新人ID(用户中心数字ID)',
|
||||
`update_time` DATETIME NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_hw_class` (`homework_id`, `class_id`)
|
||||
@@ -51,9 +53,9 @@ CREATE TABLE IF NOT EXISTS `homework_attachment` (
|
||||
`file_type` VARCHAR(20) NULL COMMENT 'image/file/...',
|
||||
`file_name` VARCHAR(200) NULL,
|
||||
`sort` INT NOT NULL DEFAULT 0,
|
||||
`create_by` VARCHAR(64) NULL,
|
||||
`create_by` INT NULL COMMENT '创建人ID(用户中心数字ID)',
|
||||
`create_time` DATETIME NULL,
|
||||
`update_by` VARCHAR(64) NULL,
|
||||
`update_by` INT NULL COMMENT '更新人ID(用户中心数字ID)',
|
||||
`update_time` DATETIME NULL,
|
||||
KEY `idx_hw` (`homework_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
@@ -72,9 +74,9 @@ CREATE TABLE IF NOT EXISTS `homework_read_record` (
|
||||
`first_read_at` DATETIME NULL,
|
||||
`last_read_at` DATETIME NULL,
|
||||
`read_count` INT NOT NULL DEFAULT 0,
|
||||
`create_by` VARCHAR(64) NULL,
|
||||
`create_by` INT NULL COMMENT '创建人ID(用户中心数字ID)',
|
||||
`create_time` DATETIME NULL,
|
||||
`update_by` VARCHAR(64) NULL,
|
||||
`update_by` INT NULL COMMENT '更新人ID(用户中心数字ID)',
|
||||
`update_time` DATETIME NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_hw_student` (`homework_id`, `student_id`)
|
||||
@@ -103,9 +105,9 @@ CREATE TABLE IF NOT EXISTS `homework_submission` (
|
||||
`reviewed_by` INT NULL COMMENT '批阅人ID(用户中心数字ID,同教师ID空间)',
|
||||
`reviewed_by_name` VARCHAR(64) NULL COMMENT '批阅人姓名快照',
|
||||
`reviewed_at` DATETIME NULL,
|
||||
`create_by` VARCHAR(64) NULL,
|
||||
`create_by` INT NULL COMMENT '创建人ID(用户中心数字ID)',
|
||||
`create_time` DATETIME NULL,
|
||||
`update_by` VARCHAR(64) NULL,
|
||||
`update_by` INT NULL COMMENT '更新人ID(用户中心数字ID)',
|
||||
`update_time` DATETIME NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_hw_student_ver` (`homework_id`, `student_id`, `version`),
|
||||
@@ -126,9 +128,9 @@ CREATE TABLE IF NOT EXISTS `submission_attachment` (
|
||||
`file_type` VARCHAR(20) NULL COMMENT 'image/file',
|
||||
`file_name` VARCHAR(200) NULL,
|
||||
`sort` INT NOT NULL DEFAULT 0,
|
||||
`create_by` VARCHAR(64) NULL,
|
||||
`create_by` INT NULL COMMENT '创建人ID(用户中心数字ID)',
|
||||
`create_time` DATETIME NULL,
|
||||
`update_by` VARCHAR(64) NULL,
|
||||
`update_by` INT NULL COMMENT '更新人ID(用户中心数字ID)',
|
||||
`update_time` DATETIME NULL,
|
||||
KEY `idx_sub` (`submission_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
@@ -147,9 +149,9 @@ CREATE TABLE IF NOT EXISTS `class_student` (
|
||||
`student_name` VARCHAR(50) NOT NULL,
|
||||
`status` TINYINT NOT NULL DEFAULT 1 COMMENT '1 在班 0 已转出/退课',
|
||||
`leave_at` DATETIME NULL,
|
||||
`create_by` VARCHAR(64) NULL,
|
||||
`create_by` INT NULL COMMENT '创建人ID(用户中心数字ID)',
|
||||
`create_time` DATETIME NULL,
|
||||
`update_by` VARCHAR(64) NULL,
|
||||
`update_by` INT NULL COMMENT '更新人ID(用户中心数字ID)',
|
||||
`update_time` DATETIME NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_class_student` (`class_id`, `student_id`)
|
||||
@@ -172,9 +174,9 @@ CREATE TABLE IF NOT EXISTS `notification` (
|
||||
`is_read` TINYINT NOT NULL DEFAULT 0,
|
||||
`read_at` DATETIME NULL,
|
||||
`send_channel` VARCHAR(20) NOT NULL DEFAULT 'inapp' COMMENT 'inapp/sms',
|
||||
`create_by` VARCHAR(64) NULL,
|
||||
`create_by` INT NULL COMMENT '创建人ID(用户中心数字ID)',
|
||||
`create_time` DATETIME NULL,
|
||||
`update_by` VARCHAR(64) NULL,
|
||||
`update_by` INT NULL COMMENT '更新人ID(用户中心数字ID)',
|
||||
`update_time` DATETIME NULL,
|
||||
KEY `idx_receiver` (`receiver_id`, `is_read`),
|
||||
KEY `idx_hw_type` (`homework_id`, `type`),
|
||||
|
||||
Reference in New Issue
Block a user