提交数据库设计
This commit is contained in:
@@ -18,10 +18,10 @@ public class SysMenu {
|
||||
@TableId(type = IdType.INPUT)
|
||||
private Long id;
|
||||
private Long companyId;
|
||||
private String permissionCode;
|
||||
private String menuCode;
|
||||
private String menuName;
|
||||
private String path;
|
||||
private String visiblePositions;
|
||||
private Integer sortOrder;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
package com.labelsys.backend.interceptor;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import com.labelsys.backend.annotation.RequirePosition;
|
||||
import com.labelsys.backend.common.exception.ForbiddenException;
|
||||
import com.labelsys.backend.common.exception.UnauthorizedException;
|
||||
@@ -8,48 +16,30 @@ import com.labelsys.backend.context.UserContext;
|
||||
import com.labelsys.backend.entity.SysCompany;
|
||||
import com.labelsys.backend.entity.SysUser;
|
||||
import com.labelsys.backend.enums.CompanyStatus;
|
||||
import com.labelsys.backend.enums.UserPosition;
|
||||
import com.labelsys.backend.enums.UserStatus;
|
||||
import com.labelsys.backend.mapper.SysCompanyMapper;
|
||||
import com.labelsys.backend.mapper.SysUserMapper;
|
||||
import com.labelsys.backend.service.session.TokenSessionRepository;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.time.Duration;
|
||||
import java.util.Set;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
@Component
|
||||
public class AuthInterceptor implements HandlerInterceptor {
|
||||
|
||||
private static final Set<String> OPEN_PATHS = Set.of(
|
||||
"/label/api/auth/companies",
|
||||
"/label/api/auth/login",
|
||||
"/label/swagger-ui.html",
|
||||
"/label/v3/api-docs",
|
||||
"/label/v3/api-docs/swagger-config"
|
||||
);
|
||||
private static final Set<String> OPEN_PATHS = Set.of("/label/api/auth/companies", "/label/api/auth/login",
|
||||
"/label/swagger-ui.html", "/label/v3/api-docs", "/label/v3/api-docs/swagger-config");
|
||||
|
||||
private static final Set<String> ALLOWED_WHEN_MUST_CHANGE_PASSWORD = Set.of(
|
||||
"/label/api/auth/change-password",
|
||||
"/label/api/auth/logout",
|
||||
"/label/api/auth/me"
|
||||
);
|
||||
private static final Set<String> ALLOWED_WHEN_MUST_CHANGE_PASSWORD =
|
||||
Set.of("/label/api/auth/change-password", "/label/api/auth/logout", "/label/api/auth/me");
|
||||
|
||||
private final TokenSessionRepository tokenSessionRepository;
|
||||
private final SysUserMapper sysUserMapper;
|
||||
private final SysCompanyMapper sysCompanyMapper;
|
||||
private final Duration sessionTtl;
|
||||
|
||||
public AuthInterceptor(
|
||||
TokenSessionRepository tokenSessionRepository,
|
||||
SysUserMapper sysUserMapper,
|
||||
SysCompanyMapper sysCompanyMapper,
|
||||
@Value("${labelsys.session.ttl:PT2H}") Duration sessionTtl
|
||||
) {
|
||||
public AuthInterceptor(TokenSessionRepository tokenSessionRepository, SysUserMapper sysUserMapper,
|
||||
SysCompanyMapper sysCompanyMapper, @Value("${labelsys.session.ttl:PT2H}") Duration sessionTtl) {
|
||||
this.tokenSessionRepository = tokenSessionRepository;
|
||||
this.sysUserMapper = sysUserMapper;
|
||||
this.sysCompanyMapper = sysCompanyMapper;
|
||||
@@ -69,12 +59,13 @@ public class AuthInterceptor implements HandlerInterceptor {
|
||||
return true;
|
||||
}
|
||||
String token = extractToken(request.getHeader("Authorization"));
|
||||
LoginUser loginUser = tokenSessionRepository.find(token)
|
||||
.orElseThrow(() -> new UnauthorizedException("未登录或登录已过期"));
|
||||
LoginUser loginUser =
|
||||
tokenSessionRepository.find(token).orElseThrow(() -> new UnauthorizedException("未登录或登录已过期"));
|
||||
|
||||
SysUser user = sysUserMapper.findByIdAndCompanyId(loginUser.userId(), loginUser.companyId());
|
||||
SysCompany company = sysCompanyMapper.selectById(loginUser.companyId());
|
||||
if (user == null || company == null || user.getStatus() != UserStatus.ENABLED || company.getStatus() != CompanyStatus.ENABLED) {
|
||||
if (user == null || company == null || user.getStatus() != UserStatus.ENABLED
|
||||
|| company.getStatus() != CompanyStatus.ENABLED) {
|
||||
throw new UnauthorizedException("未登录或登录已过期");
|
||||
}
|
||||
if (!user.getSessionVersion().equals(loginUser.sessionVersion())) {
|
||||
@@ -96,7 +87,8 @@ public class AuthInterceptor implements HandlerInterceptor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
|
||||
Exception ex) {
|
||||
UserContext.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,5 +7,5 @@ import org.apache.ibatis.annotations.Param;
|
||||
|
||||
public interface SysMenuMapper extends BaseMapper<SysMenu> {
|
||||
|
||||
List<SysMenu> listCurrentMenus(@Param("companyId") Long companyId, @Param("positionCodes") List<String> positionCodes);
|
||||
List<SysMenu> listCurrentMenus(@Param("companyId") Long companyId, @Param("visiblePositions") List<String> visiblePositions);
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@ public class MenuService {
|
||||
private final SysMenuMapper sysMenuMapper;
|
||||
|
||||
public List<MenuResponse> listCurrentMenus(LoginUser currentUser) {
|
||||
List<String> positionCodes = java.util.Arrays.stream(com.labelsys.backend.enums.UserPosition.values())
|
||||
List<String> visiblePositions = java.util.Arrays.stream(com.labelsys.backend.enums.UserPosition.values())
|
||||
.filter(position -> currentUser.position().canAccess(position))
|
||||
.map(Enum::name)
|
||||
.toList();
|
||||
return sysMenuMapper.listCurrentMenus(currentUser.companyId(), positionCodes)
|
||||
return sysMenuMapper.listCurrentMenus(currentUser.companyId(), visiblePositions)
|
||||
.stream()
|
||||
.map(MenuResponse::from)
|
||||
.toList();
|
||||
|
||||
@@ -4,26 +4,24 @@
|
||||
<resultMap id="SysMenuResultMap" type="com.labelsys.backend.entity.SysMenu">
|
||||
<id column="id" property="id"/>
|
||||
<result column="company_id" property="companyId"/>
|
||||
<result column="permission_code" property="permissionCode"/>
|
||||
<result column="menu_code" property="menuCode"/>
|
||||
<result column="menu_name" property="menuName"/>
|
||||
<result column="path" property="path"/>
|
||||
<result column="visible_positions" property="visiblePositions"/>
|
||||
<result column="sort_order" property="sortOrder"/>
|
||||
<result column="created_at" property="createdAt"/>
|
||||
<result column="updated_at" property="updatedAt"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="listCurrentMenus" resultMap="SysMenuResultMap">
|
||||
select distinct m.id, m.company_id, m.permission_code, m.menu_code, m.menu_name, m.path, m.sort_order, m.created_at, m.updated_at
|
||||
select m.id, m.company_id, m.menu_code, m.menu_name, m.path, m.visible_positions, m.sort_order, m.created_at, m.updated_at
|
||||
from sys_menu m
|
||||
inner join sys_position_permission pp
|
||||
on pp.company_id = m.company_id
|
||||
and pp.permission_code = m.permission_code
|
||||
where m.company_id = #{companyId}
|
||||
and pp.position_code in
|
||||
<foreach collection="positionCodes" item="positionCode" open="(" separator="," close=")">
|
||||
#{positionCode}
|
||||
and (
|
||||
<foreach collection="visiblePositions" item="positionCode" separator=" or ">
|
||||
concat(',', m.visible_positions, ',') like concat('%,', #{positionCode}, ',%')
|
||||
</foreach>
|
||||
)
|
||||
order by m.sort_order, m.id
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
@@ -1,23 +1,156 @@
|
||||
insert into sys_company (id, company_code, company_name, status) values
|
||||
(1, 'PLATFORM', '平台公司', 'ENABLED'),
|
||||
(2, 'ALPHA', '甲公司', 'ENABLED')
|
||||
on conflict do nothing;
|
||||
BEGIN;
|
||||
|
||||
INSERT INTO sys_company (id, company_code, company_name, status) VALUES
|
||||
(1, 'PLATFORM', '平台公司', 'ENABLED'),
|
||||
(2, 'ALPHA', '甲公司', 'ENABLED')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO sys_user (
|
||||
id, company_id, phone, username, role, position, real_name,
|
||||
password_hash, must_change_password, status, session_version
|
||||
) VALUES
|
||||
(1, 1, '13900000000', 'platform-admin', 'ENGINEER', 'ADMIN', '平台管理员',
|
||||
'$2a$10$TGPk5rNNhKNJQvTWImw5J.LVzw9HDFWR6hyNJCkLDcp0GU8/vp0aS', FALSE, 'ENABLED', 1),
|
||||
(2, 2, '13800138000', 'alpha-admin', 'ENGINEER', 'ADMIN', '甲公司管理员',
|
||||
'$2a$10$/hSD8ch7A9lFWi/DOb8yJOHdlrhV57p95CBv9Uv93Yky7t6c4Rs/S', TRUE, 'ENABLED', 1),
|
||||
(3, 2, '13700000000', 'alpha-annotator', 'EMPLOYEE', 'ANNOTATOR', '甲公司标注员',
|
||||
'$2a$10$bRMZPcIaiB1BUx6HPw6FSODPSuph8kUi8/JZOM6lACwjjhkbBL5mq', TRUE, 'ENABLED', 1),
|
||||
(4, 2, '13600000000', 'alpha-trainer', 'EMPLOYEE', 'DATA_TRAINER', '甲公司数据训练师',
|
||||
'$2a$10$bRMZPcIaiB1BUx6HPw6FSODPSuph8kUi8/JZOM6lACwjjhkbBL5mq', TRUE, 'ENABLED', 1),
|
||||
(5, 2, '13500000000', 'alpha-reviewer', 'MANAGER', 'REVIEWER', '甲公司审核员',
|
||||
'$2a$10$bRMZPcIaiB1BUx6HPw6FSODPSuph8kUi8/JZOM6lACwjjhkbBL5mq', TRUE, 'ENABLED', 1),
|
||||
(6, 2, '13400000000', 'alpha-chief-engineer', 'ENGINEER', 'REVIEWER', '甲公司总工程师',
|
||||
'$2a$10$bRMZPcIaiB1BUx6HPw6FSODPSuph8kUi8/JZOM6lACwjjhkbBL5mq', TRUE, 'ENABLED', 1)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO sys_menu (id, company_id, menu_code, menu_name, path, visible_positions, sort_order) VALUES
|
||||
(201, 2, 'USER_MANAGE', '用户管理', '/users', 'ADMIN', 1),
|
||||
(202, 2, 'RESOURCE_MANAGE', '资源管理', '/resources', 'ANNOTATOR,DATA_TRAINER,REVIEWER,ADMIN', 2),
|
||||
(203, 2, 'TASK_MANAGE', '任务管理', '/tasks', 'ANNOTATOR,DATA_TRAINER,REVIEWER,ADMIN', 3),
|
||||
(204, 2, 'RESULT_REVIEW', '结果审核', '/results', 'REVIEWER,ADMIN', 4),
|
||||
(205, 2, 'DATASET_EXPORT', '训练集导出', '/datasets', 'DATA_TRAINER,ADMIN', 5),
|
||||
(206, 2, 'SYSTEM_CONFIG', '系统配置', '/configs', 'ADMIN', 6)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO sys_config (
|
||||
id, company_id, config_type, config_name, config_value, status, creator_id
|
||||
) VALUES
|
||||
(401, 2, 'MODEL', 'qwen-max',
|
||||
'{"modelUrl":"https://api.example.com/extract","apiKey":"extract-api-key-demo"}', 'ENABLED', 2),
|
||||
(402, 2, 'MODEL', 'glm-4.5',
|
||||
'{"modelUrl":"https://api.example.com/verify","apiKey":"verify-api-key-demo"}', 'ENABLED', 2),
|
||||
(403, 2, 'PROMPT', 'extractPrompt',
|
||||
'请根据输入内容提取结构化问答对。', 'ENABLED', 2),
|
||||
(404, 2, 'PROMPT', 'verifyPrompt',
|
||||
'请核验抽取结果是否准确,并给出修正答案。', 'ENABLED', 2),
|
||||
(406, 2, 'MODEL', 'qwen-vl-max',
|
||||
'{"modelUrl":"https://api.example.com/extract-vl","apiKey":"extract-vl-api-key-demo"}', 'ENABLED', 2),
|
||||
(407, 2, 'MODEL', 'glm-4.5v',
|
||||
'{"modelUrl":"https://api.example.com/verify-vl","apiKey":"verify-vl-api-key-demo"}', 'ENABLED', 2),
|
||||
(408, 2, 'PROMPT', 'imageExtractPrompt',
|
||||
'请根据输入图片内容提取结构化问答对。', 'ENABLED', 2),
|
||||
(409, 2, 'PROMPT', 'imageVerifyPrompt',
|
||||
'请核验图片问答结果是否准确。', 'ENABLED', 2),
|
||||
(405, 2, 'SYSTEM', 'storageProvider',
|
||||
'{"provider":"rustfs","defaultBucket":"source-data"}', 'ENABLED', 2)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO biz_data_record (id, company_id, creator_id, creator_role, record_name) VALUES
|
||||
(501, 2, 3, 'EMPLOYEE', '员工创建的数据'),
|
||||
(502, 2, 5, 'MANAGER', '经理创建的数据'),
|
||||
(503, 2, 6, 'ENGINEER', '总工程师创建的数据')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO source_resource (
|
||||
id, company_id, creator_id, creator_role, resource_name, resource_type,
|
||||
bucket_name, file_path, file_size, source_status, storage_provider, remark
|
||||
) VALUES
|
||||
(601, 2, 3, 'EMPLOYEE', '设备巡检规范.txt', 'TEXT',
|
||||
'source-data', 'text/202604/601.txt', 20480, 'READY', 'rustfs', '文本资源示例'),
|
||||
(602, 2, 3, 'EMPLOYEE', '控制柜照片.jpg', 'IMAGE',
|
||||
'source-data', 'image/202604/602.jpg', 532480, 'READY', 'rustfs', '图片资源示例')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
insert into sys_user (id, company_id, phone, username, role, position, real_name, password_hash, must_change_password, status, session_version) values
|
||||
(1, 1, '13900000000', 'platform-admin', 'ENGINEER', 'ADMIN', '平台管理员', '$2a$10$TGPk5rNNhKNJQvTWImw5J.LVzw9HDFWR6hyNJCkLDcp0GU8/vp0aS', false, 'ENABLED', 1),
|
||||
(2, 2, '13800138000', 'alpha-admin', 'EMPLOYEE', 'ADMIN', '甲公司管理员', '$2a$10$/hSD8ch7A9lFWi/DOb8yJOHdlrhV57p95CBv9Uv93Yky7t6c4Rs/S', true, 'ENABLED', 1),
|
||||
(3, 2, '13700000000', 'alpha-annotator', 'EMPLOYEE', 'ANNOTATOR', '甲公司标注员', '$2a$10$bRMZPcIaiB1BUx6HPw6FSODPSuph8kUi8/JZOM6lACwjjhkbBL5mq', false, 'ENABLED', 1),
|
||||
(4, 2, '13600000000', 'alpha-manager', 'MANAGER', 'REVIEWER', '甲公司经理', '$2a$10$bRMZPcIaiB1BUx6HPw6FSODPSuph8kUi8/JZOM6lACwjjhkbBL5mq', false, 'ENABLED', 1),
|
||||
(5, 2, '13500000000', 'alpha-engineer', 'ENGINEER', 'ADMIN', '甲公司工程师', '$2a$10$bRMZPcIaiB1BUx6HPw6FSODPSuph8kUi8/JZOM6lACwjjhkbBL5mq', false, 'ENABLED', 1)
|
||||
on conflict do nothing;
|
||||
INSERT INTO annotation_task (
|
||||
id, company_id, creator_id, creator_role, task_name, industry_type, task_type,
|
||||
extract_model_config_id,
|
||||
extract_model_name, extract_model_url, extract_model_api_key,
|
||||
verify_model_config_id,
|
||||
verify_model_name, verify_model_url, verify_model_api_key,
|
||||
extract_prompt_config_id, extract_prompt,
|
||||
verify_prompt_config_id, verify_prompt,
|
||||
task_status, is_deleted, started_at, finished_at, error_message
|
||||
) VALUES
|
||||
(701, 2, 4, 'EMPLOYEE', '多资源问答抽取任务', 'electricity', 'EXTRACT_QA',
|
||||
401,
|
||||
'qwen-max', 'https://api.example.com/extract', 'extract-api-key-demo',
|
||||
402,
|
||||
'glm-4.5', 'https://api.example.com/verify', 'verify-api-key-demo',
|
||||
403, '请根据输入文本提取结构化问答对。',
|
||||
404, '请核验生成答案是否与原始内容一致。',
|
||||
'PENDING', FALSE, NULL, NULL, NULL),
|
||||
(702, 2, 4, 'EMPLOYEE', '图片问答抽取任务', 'transport', 'EXTRACT_QA',
|
||||
406,
|
||||
'qwen-vl-max', 'https://api.example.com/extract-vl', 'extract-vl-api-key-demo',
|
||||
407,
|
||||
'glm-4.5v', 'https://api.example.com/verify-vl', 'verify-vl-api-key-demo',
|
||||
408, '请根据输入图片内容提取结构化问答对。',
|
||||
409, '请核验图片问答结果是否准确。',
|
||||
'COMPLETED', FALSE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
insert into sys_menu (id, company_id, permission_code, menu_code, menu_name, path, sort_order) values
|
||||
(201, 2, 'USER_MANAGE', 'USER_MANAGE', '员工管理', '/users', 1),
|
||||
(202, 2, 'DATA_RECORD_VIEW', 'DATA_RECORDS', '数据记录', '/data-records', 2)
|
||||
on conflict do nothing;
|
||||
INSERT INTO annotation_task_resource (
|
||||
id, company_id, task_id, resource_id
|
||||
) VALUES
|
||||
(711, 2, 701, 601),
|
||||
(712, 2, 701, 602),
|
||||
(713, 2, 702, 602)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
insert into biz_data_record (id, company_id, creator_id, creator_role, record_name) values
|
||||
(401, 2, 3, 'EMPLOYEE', '员工创建的数据'),
|
||||
(402, 2, 4, 'MANAGER', '经理创建的数据'),
|
||||
(403, 2, 5, 'ENGINEER', '工程师创建的数据')
|
||||
on conflict do nothing;
|
||||
INSERT INTO annotation_result (
|
||||
id, company_id, creator_id, creator_role, task_id, resource_id,
|
||||
qa_content_json, qa_content_storage_mode, qa_content_file_path, diff_summary,
|
||||
requires_manual_review, is_deleted, reviewer_id, review_comment, reviewed_at
|
||||
) VALUES
|
||||
(801, 2, 3, 'EMPLOYEE', 701, 601,
|
||||
'{"question":"巡检开始前需要做什么?","answer":"详见外置结果文件,包含完整步骤与注意事项。"}',
|
||||
'EXTERNAL', 'annotation-results/202604/801-qa.json',
|
||||
'{"extract_question":"巡检开始前需要做什么?","extract_answer":"开始前检查设备状态和作业环境。","verify_answer":"开始前应确认设备状态、防护用品和现场环境安全。","mismatch_fields":["answer"],"reason":"抽取答案遗漏了安全检查要点。"}',
|
||||
TRUE, FALSE, NULL, NULL, NULL),
|
||||
(802, 2, 3, 'EMPLOYEE', 702, 602,
|
||||
'{"question":"图片中的控制柜当前状态如何?","answer":"控制柜处于运行状态,绿色指示灯亮起。"}',
|
||||
'INLINE', NULL,
|
||||
'{"extract_question":"图片中的控制柜当前状态如何?","extract_answer":"控制柜处于运行状态,绿色指示灯亮起。","verify_answer":"控制柜正在运行,指示灯显示正常。","mismatch_fields":[],"reason":"校验结果与抽取结果基本一致。"}',
|
||||
FALSE, FALSE, 5, '结果可通过。', CURRENT_TIMESTAMP)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO annotation_result_history (
|
||||
id, company_id, creator_id, creator_role, source_result_id, task_id, resource_id,
|
||||
qa_content_json, qa_content_storage_mode, qa_content_file_path, archive_reason, archived_by, archived_at
|
||||
) VALUES
|
||||
(901, 2, 3, 'EMPLOYEE', 802, 702, 602,
|
||||
'{"question":"图片中的控制柜当前状态如何?","answer":"控制柜处于运行状态,绿色指示灯亮起。"}',
|
||||
'INLINE',
|
||||
NULL,
|
||||
'审核通过后归档', 5, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO training_dataset (
|
||||
id, company_id, creator_id, creator_role, result_history_id, sample_type, glm_format_json, dataset_status
|
||||
) VALUES
|
||||
(1001, 2, 4, 'EMPLOYEE', 901, 'TEXT',
|
||||
'{"messages":[{"role":"system","content":"你是专业知识问答助手"},{"role":"user","content":"图片中的控制柜当前状态如何?"},{"role":"assistant","content":"控制柜处于运行状态,绿色指示灯亮起。"}]}',
|
||||
'DRAFT')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO export_batch (
|
||||
id, company_id, creator_id, creator_role, batch_no, dataset_file_path, sample_count, finetune_job_id, finetune_status
|
||||
) VALUES
|
||||
(1101, 2, 4, 'EMPLOYEE', 'BATCH-20260424-001', 'export/BATCH-20260424-001.jsonl', 1, NULL, 'NOT_STARTED')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO export_batch_item (id, batch_id, dataset_id) VALUES
|
||||
(1201, 1101, 1001)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
COMMIT;
|
||||
|
||||
@@ -1,47 +1,437 @@
|
||||
create table if not exists sys_company (
|
||||
id bigint primary key,
|
||||
company_code varchar(64) not null unique,
|
||||
company_name varchar(128) not null,
|
||||
status varchar(32) not null,
|
||||
created_at timestamp default current_timestamp,
|
||||
updated_at timestamp default current_timestamp
|
||||
-- Active: 1775801470429@@39.107.112.174@5432@lablesystem
|
||||
begin;
|
||||
|
||||
-- Drop Tables (按依赖关系倒序删除)
|
||||
DROP TABLE IF EXISTS export_batch_item CASCADE;
|
||||
DROP TABLE IF EXISTS export_batch CASCADE;
|
||||
DROP TABLE IF EXISTS training_dataset CASCADE;
|
||||
DROP TABLE IF EXISTS annotation_result_history CASCADE;
|
||||
DROP TABLE IF EXISTS annotation_result CASCADE;
|
||||
DROP TABLE IF EXISTS annotation_task_resource CASCADE;
|
||||
DROP TABLE IF EXISTS annotation_task CASCADE;
|
||||
DROP TABLE IF EXISTS source_resource CASCADE;
|
||||
DROP TABLE IF EXISTS biz_data_record CASCADE;
|
||||
DROP TABLE IF EXISTS sys_config CASCADE;
|
||||
DROP TABLE IF EXISTS sys_menu CASCADE;
|
||||
DROP TABLE IF EXISTS sys_user CASCADE;
|
||||
DROP TABLE IF EXISTS sys_company CASCADE;
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sys_company (
|
||||
id BIGINT PRIMARY KEY,
|
||||
company_code VARCHAR(64) NOT NULL UNIQUE,
|
||||
company_name VARCHAR(128) NOT NULL,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'ENABLED',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
create table if not exists sys_user (
|
||||
id bigint primary key,
|
||||
company_id bigint not null,
|
||||
phone varchar(32) not null,
|
||||
username varchar(64),
|
||||
role varchar(32) not null,
|
||||
position varchar(32) not null,
|
||||
real_name varchar(64) not null,
|
||||
password_hash varchar(255) not null,
|
||||
must_change_password boolean not null default true,
|
||||
status varchar(32) not null,
|
||||
session_version integer not null default 1,
|
||||
created_at timestamp default current_timestamp,
|
||||
updated_at timestamp default current_timestamp,
|
||||
constraint uq_sys_user_company_phone unique (company_id, phone)
|
||||
COMMENT ON TABLE sys_company IS '公司表。';
|
||||
COMMENT ON COLUMN sys_company.id IS '公司主键ID。';
|
||||
COMMENT ON COLUMN sys_company.company_code IS '公司编码,登录时通过 companyCode 使用。';
|
||||
COMMENT ON COLUMN sys_company.company_name IS '公司名称。';
|
||||
COMMENT ON COLUMN sys_company.status IS '公司状态,默认 ENABLED,可按需改为 DISABLED 等状态。';
|
||||
COMMENT ON COLUMN sys_company.created_at IS '创建时间。';
|
||||
COMMENT ON COLUMN sys_company.updated_at IS '更新时间。';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sys_user (
|
||||
id BIGINT PRIMARY KEY,
|
||||
company_id BIGINT NOT NULL,
|
||||
phone VARCHAR(32) NOT NULL,
|
||||
username VARCHAR(64),
|
||||
role VARCHAR(32) NOT NULL DEFAULT 'EMPLOYEE',
|
||||
position VARCHAR(32) NOT NULL DEFAULT 'ANNOTATOR',
|
||||
real_name VARCHAR(64) NOT NULL,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
must_change_password BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'ENABLED',
|
||||
session_version INTEGER NOT NULL DEFAULT 1,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT uq_sys_user_company_phone UNIQUE (company_id, phone),
|
||||
CONSTRAINT fk_sys_user_company FOREIGN KEY (company_id) REFERENCES sys_company(id)
|
||||
);
|
||||
|
||||
create table if not exists sys_menu (
|
||||
id bigint primary key,
|
||||
company_id bigint not null,
|
||||
permission_code varchar(64) not null,
|
||||
menu_code varchar(64) not null,
|
||||
menu_name varchar(128) not null,
|
||||
path varchar(255) not null,
|
||||
sort_order integer not null default 0,
|
||||
created_at timestamp default current_timestamp,
|
||||
updated_at timestamp default current_timestamp
|
||||
COMMENT ON TABLE sys_user IS '用户表。role 表示数据权限角色,position 表示岗位。';
|
||||
COMMENT ON COLUMN sys_user.id IS '用户主键ID。';
|
||||
COMMENT ON COLUMN sys_user.company_id IS '所属公司ID,关联 sys_company.id。';
|
||||
COMMENT ON COLUMN sys_user.phone IS '登录手机号,同公司内唯一。';
|
||||
COMMENT ON COLUMN sys_user.username IS '用户名或账号别名,用于展示。';
|
||||
COMMENT ON COLUMN sys_user.role IS '数据权限角色,默认 EMPLOYEE,可选 EMPLOYEE、MANAGER、ENGINEER。';
|
||||
COMMENT ON COLUMN sys_user.position IS '岗位,默认 ANNOTATOR,可选 ANNOTATOR、DATA_TRAINER、REVIEWER、ADMIN。';
|
||||
COMMENT ON COLUMN sys_user.real_name IS '用户真实姓名。';
|
||||
COMMENT ON COLUMN sys_user.password_hash IS '密码哈希值。';
|
||||
COMMENT ON COLUMN sys_user.must_change_password IS '是否首次登录强制改密。';
|
||||
COMMENT ON COLUMN sys_user.status IS '用户状态,默认 ENABLED。';
|
||||
COMMENT ON COLUMN sys_user.session_version IS '会话版本号,用于强制旧 Token 失效。';
|
||||
COMMENT ON COLUMN sys_user.created_at IS '创建时间。';
|
||||
COMMENT ON COLUMN sys_user.updated_at IS '更新时间。';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sys_menu (
|
||||
id BIGINT PRIMARY KEY,
|
||||
company_id BIGINT NOT NULL,
|
||||
menu_code VARCHAR(64) NOT NULL,
|
||||
menu_name VARCHAR(128) NOT NULL,
|
||||
path VARCHAR(255) NOT NULL,
|
||||
visible_positions VARCHAR(255) NOT NULL DEFAULT 'ADMIN',
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_sys_menu_company FOREIGN KEY (company_id) REFERENCES sys_company(id)
|
||||
);
|
||||
|
||||
create table if not exists biz_data_record (
|
||||
id bigint primary key,
|
||||
company_id bigint not null,
|
||||
creator_id bigint not null,
|
||||
creator_role varchar(32) not null,
|
||||
record_name varchar(255) not null,
|
||||
created_at timestamp default current_timestamp,
|
||||
updated_at timestamp default current_timestamp
|
||||
COMMENT ON TABLE sys_menu IS '菜单表。';
|
||||
COMMENT ON COLUMN sys_menu.id IS '菜单主键ID。';
|
||||
COMMENT ON COLUMN sys_menu.company_id IS '所属公司ID。';
|
||||
COMMENT ON COLUMN sys_menu.menu_code IS '菜单编码。';
|
||||
COMMENT ON COLUMN sys_menu.menu_name IS '菜单名称。';
|
||||
COMMENT ON COLUMN sys_menu.path IS '前端路由路径。';
|
||||
COMMENT ON COLUMN sys_menu.visible_positions IS '可见岗位列表,使用逗号分隔存储,如 ANNOTATOR,DATA_TRAINER,REVIEWER,ADMIN。';
|
||||
COMMENT ON COLUMN sys_menu.sort_order IS '菜单排序号,默认 0。';
|
||||
COMMENT ON COLUMN sys_menu.created_at IS '创建时间。';
|
||||
COMMENT ON COLUMN sys_menu.updated_at IS '更新时间。';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sys_config (
|
||||
id BIGINT PRIMARY KEY,
|
||||
company_id BIGINT NOT NULL,
|
||||
config_type VARCHAR(32) NOT NULL DEFAULT 'SYSTEM',
|
||||
config_name VARCHAR(128) NOT NULL,
|
||||
config_value TEXT NOT NULL,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'ENABLED',
|
||||
creator_id BIGINT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT uq_sys_config_company_name UNIQUE (company_id, config_name),
|
||||
CONSTRAINT fk_sys_config_company FOREIGN KEY (company_id) REFERENCES sys_company(id),
|
||||
CONSTRAINT fk_sys_config_creator FOREIGN KEY (creator_id) REFERENCES sys_user(id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE sys_config IS '系统配置表,保存模型配置、Prompt 配置和系统参数配置。';
|
||||
COMMENT ON COLUMN sys_config.id IS '配置主键ID。';
|
||||
COMMENT ON COLUMN sys_config.company_id IS '所属公司ID。';
|
||||
COMMENT ON COLUMN sys_config.config_type IS '配置类型,默认 SYSTEM,可选 MODEL、PROMPT、SYSTEM。';
|
||||
COMMENT ON COLUMN sys_config.config_name IS '配置名称。MODEL 类型时存模型名如 qwen-max;PROMPT 类型时存名称如 extractPrompt、verifyPrompt;SYSTEM 类型时存参数名。';
|
||||
COMMENT ON COLUMN sys_config.config_value IS '配置值。MODEL 类型建议保存 JSON,至少包含 modelName、modelUrl、apiKey;PROMPT 类型保存提示词文本;SYSTEM 类型预留后续扩展。';
|
||||
COMMENT ON COLUMN sys_config.status IS '配置状态,默认 ENABLED。';
|
||||
COMMENT ON COLUMN sys_config.creator_id IS '创建人用户ID。';
|
||||
COMMENT ON COLUMN sys_config.created_at IS '创建时间。';
|
||||
COMMENT ON COLUMN sys_config.updated_at IS '更新时间。';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS biz_data_record (
|
||||
id BIGINT PRIMARY KEY,
|
||||
company_id BIGINT NOT NULL,
|
||||
creator_id BIGINT NOT NULL,
|
||||
creator_role VARCHAR(32) NOT NULL DEFAULT 'EMPLOYEE',
|
||||
record_name VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_biz_data_record_company FOREIGN KEY (company_id) REFERENCES sys_company(id),
|
||||
CONSTRAINT fk_biz_data_record_creator FOREIGN KEY (creator_id) REFERENCES sys_user(id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE biz_data_record IS '一期数据权限演示表。';
|
||||
COMMENT ON COLUMN biz_data_record.id IS '演示记录主键ID。';
|
||||
COMMENT ON COLUMN biz_data_record.company_id IS '所属公司ID。';
|
||||
COMMENT ON COLUMN biz_data_record.creator_id IS '创建人用户ID。';
|
||||
COMMENT ON COLUMN biz_data_record.creator_role IS '创建人数据权限角色,默认 EMPLOYEE。';
|
||||
COMMENT ON COLUMN biz_data_record.record_name IS '演示记录名称。';
|
||||
COMMENT ON COLUMN biz_data_record.created_at IS '创建时间。';
|
||||
COMMENT ON COLUMN biz_data_record.updated_at IS '更新时间。';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS source_resource (
|
||||
id BIGINT PRIMARY KEY,
|
||||
company_id BIGINT NOT NULL,
|
||||
creator_id BIGINT NOT NULL,
|
||||
creator_role VARCHAR(32) NOT NULL DEFAULT 'EMPLOYEE',
|
||||
resource_name VARCHAR(255) NOT NULL,
|
||||
resource_type VARCHAR(32) NOT NULL DEFAULT 'TEXT',
|
||||
bucket_name VARCHAR(128) NOT NULL,
|
||||
file_path VARCHAR(512) NOT NULL,
|
||||
file_size BIGINT NOT NULL DEFAULT 0,
|
||||
source_status VARCHAR(32) NOT NULL DEFAULT 'UPLOADED',
|
||||
storage_provider VARCHAR(64) NOT NULL DEFAULT 'rustfs',
|
||||
remark VARCHAR(255),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_source_resource_company FOREIGN KEY (company_id) REFERENCES sys_company(id),
|
||||
CONSTRAINT fk_source_resource_creator FOREIGN KEY (creator_id) REFERENCES sys_user(id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE source_resource IS '资源表,保存文本、图片、视频资源元数据。';
|
||||
COMMENT ON COLUMN source_resource.id IS '资源主键ID。';
|
||||
COMMENT ON COLUMN source_resource.company_id IS '所属公司ID。';
|
||||
COMMENT ON COLUMN source_resource.creator_id IS '上传人或创建人用户ID。';
|
||||
COMMENT ON COLUMN source_resource.creator_role IS '创建人数据权限角色,默认 EMPLOYEE。';
|
||||
COMMENT ON COLUMN source_resource.resource_name IS '资源名称。';
|
||||
COMMENT ON COLUMN source_resource.resource_type IS '资源类型,默认 TEXT,可选 TEXT、IMAGE、VIDEO。';
|
||||
COMMENT ON COLUMN source_resource.bucket_name IS '对象存储桶名称。';
|
||||
COMMENT ON COLUMN source_resource.file_path IS '文件存储路径,表示对象在存储系统中的实际路径。';
|
||||
COMMENT ON COLUMN source_resource.file_size IS '文件大小,单位字节,默认 0。';
|
||||
COMMENT ON COLUMN source_resource.source_status IS '资源状态,默认 UPLOADED,可选 PROCESSING、READY、ARCHIVED。';
|
||||
COMMENT ON COLUMN source_resource.storage_provider IS '存储提供方,默认 rustfs。';
|
||||
COMMENT ON COLUMN source_resource.remark IS '备注说明。';
|
||||
COMMENT ON COLUMN source_resource.created_at IS '创建时间。';
|
||||
COMMENT ON COLUMN source_resource.updated_at IS '更新时间。';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS annotation_task (
|
||||
id BIGINT PRIMARY KEY,
|
||||
company_id BIGINT NOT NULL,
|
||||
creator_id BIGINT NOT NULL,
|
||||
creator_role VARCHAR(32) NOT NULL DEFAULT 'EMPLOYEE',
|
||||
task_name VARCHAR(255) NOT NULL,
|
||||
industry_type VARCHAR(32) NOT NULL DEFAULT 'transport',
|
||||
task_type VARCHAR(32) NOT NULL DEFAULT 'EXTRACT_QA',
|
||||
extract_model_config_id BIGINT,
|
||||
extract_model_name VARCHAR(128),
|
||||
extract_model_url VARCHAR(255),
|
||||
extract_model_api_key VARCHAR(255),
|
||||
verify_model_config_id BIGINT,
|
||||
verify_model_name VARCHAR(128),
|
||||
verify_model_url VARCHAR(255),
|
||||
verify_model_api_key VARCHAR(255),
|
||||
extract_prompt_config_id BIGINT,
|
||||
extract_prompt TEXT,
|
||||
verify_prompt_config_id BIGINT,
|
||||
verify_prompt TEXT,
|
||||
task_status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
|
||||
is_deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
started_at TIMESTAMP,
|
||||
finished_at TIMESTAMP,
|
||||
error_message TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_annotation_task_company FOREIGN KEY (company_id) REFERENCES sys_company(id),
|
||||
CONSTRAINT fk_annotation_task_creator FOREIGN KEY (creator_id) REFERENCES sys_user(id),
|
||||
CONSTRAINT fk_annotation_task_extract_model_config FOREIGN KEY (extract_model_config_id) REFERENCES sys_config(id),
|
||||
CONSTRAINT fk_annotation_task_verify_model_config FOREIGN KEY (verify_model_config_id) REFERENCES sys_config(id),
|
||||
CONSTRAINT fk_annotation_task_extract_prompt_config FOREIGN KEY (extract_prompt_config_id) REFERENCES sys_config(id),
|
||||
CONSTRAINT fk_annotation_task_verify_prompt_config FOREIGN KEY (verify_prompt_config_id) REFERENCES sys_config(id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE annotation_task IS '任务表,保存任务、配置引用与执行快照。';
|
||||
COMMENT ON COLUMN annotation_task.id IS '任务主键ID。';
|
||||
COMMENT ON COLUMN annotation_task.company_id IS '所属公司ID。';
|
||||
COMMENT ON COLUMN annotation_task.creator_id IS '任务创建人用户ID。';
|
||||
COMMENT ON COLUMN annotation_task.creator_role IS '任务创建人数据权限角色,默认 EMPLOYEE。';
|
||||
COMMENT ON COLUMN annotation_task.task_name IS '任务名称。';
|
||||
COMMENT ON COLUMN annotation_task.industry_type IS '行业类型简写,默认 transport,可选值按业务扩展,例如 electricity。';
|
||||
COMMENT ON COLUMN annotation_task.task_type IS '任务类型,默认 EXTRACT_QA。';
|
||||
COMMENT ON COLUMN annotation_task.extract_model_config_id IS '抽取模型配置ID,关联 sys_config.id。';
|
||||
COMMENT ON COLUMN annotation_task.extract_model_name IS '抽取模型名称。';
|
||||
COMMENT ON COLUMN annotation_task.extract_model_url IS '抽取模型调用地址。';
|
||||
COMMENT ON COLUMN annotation_task.extract_model_api_key IS '抽取模型调用密钥。';
|
||||
COMMENT ON COLUMN annotation_task.verify_model_config_id IS '校验模型配置ID,关联 sys_config.id。';
|
||||
COMMENT ON COLUMN annotation_task.verify_model_name IS '校验模型名称。';
|
||||
COMMENT ON COLUMN annotation_task.verify_model_url IS '校验模型调用地址。';
|
||||
COMMENT ON COLUMN annotation_task.verify_model_api_key IS '校验模型调用密钥。';
|
||||
COMMENT ON COLUMN annotation_task.extract_prompt_config_id IS '抽取Prompt配置ID,关联 sys_config.id。';
|
||||
COMMENT ON COLUMN annotation_task.extract_prompt IS '抽取 Prompt 文本。';
|
||||
COMMENT ON COLUMN annotation_task.verify_prompt_config_id IS '校验Prompt配置ID,关联 sys_config.id。';
|
||||
COMMENT ON COLUMN annotation_task.verify_prompt IS '校验 Prompt 文本。';
|
||||
COMMENT ON COLUMN annotation_task.task_status IS '任务状态,默认 PENDING,可选 RUNNING、COMPLETED、FAILED。';
|
||||
COMMENT ON COLUMN annotation_task.is_deleted IS '任务软删除标记,默认 FALSE。';
|
||||
COMMENT ON COLUMN annotation_task.started_at IS '任务开始时间。';
|
||||
COMMENT ON COLUMN annotation_task.finished_at IS '任务结束时间。';
|
||||
COMMENT ON COLUMN annotation_task.error_message IS '任务失败错误信息。';
|
||||
COMMENT ON COLUMN annotation_task.created_at IS '创建时间。';
|
||||
COMMENT ON COLUMN annotation_task.updated_at IS '更新时间。';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS annotation_task_resource (
|
||||
id BIGINT PRIMARY KEY,
|
||||
company_id BIGINT NOT NULL,
|
||||
task_id BIGINT NOT NULL,
|
||||
resource_id BIGINT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT uq_annotation_task_resource UNIQUE (task_id, resource_id),
|
||||
CONSTRAINT fk_annotation_task_resource_company FOREIGN KEY (company_id) REFERENCES sys_company(id),
|
||||
CONSTRAINT fk_annotation_task_resource_task FOREIGN KEY (task_id) REFERENCES annotation_task(id),
|
||||
CONSTRAINT fk_annotation_task_resource_resource FOREIGN KEY (resource_id) REFERENCES source_resource(id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE annotation_task_resource IS '任务与资源关联表,一个任务可绑定多个资源。';
|
||||
COMMENT ON COLUMN annotation_task_resource.id IS '任务资源关联主键ID。';
|
||||
COMMENT ON COLUMN annotation_task_resource.company_id IS '所属公司ID。';
|
||||
COMMENT ON COLUMN annotation_task_resource.task_id IS '任务ID。';
|
||||
COMMENT ON COLUMN annotation_task_resource.resource_id IS '资源ID。';
|
||||
COMMENT ON COLUMN annotation_task_resource.created_at IS '创建时间。';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS annotation_result (
|
||||
id BIGINT PRIMARY KEY,
|
||||
company_id BIGINT NOT NULL,
|
||||
creator_id BIGINT NOT NULL,
|
||||
creator_role VARCHAR(32) NOT NULL DEFAULT 'EMPLOYEE',
|
||||
task_id BIGINT NOT NULL,
|
||||
resource_id BIGINT NOT NULL,
|
||||
qa_content_json TEXT NOT NULL DEFAULT '{}',
|
||||
qa_content_storage_mode VARCHAR(32) NOT NULL DEFAULT 'INLINE',
|
||||
qa_content_file_path VARCHAR(512),
|
||||
diff_summary TEXT NOT NULL DEFAULT '{}',
|
||||
requires_manual_review BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
is_deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
reviewer_id BIGINT,
|
||||
review_comment TEXT,
|
||||
reviewed_at TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_annotation_result_company FOREIGN KEY (company_id) REFERENCES sys_company(id),
|
||||
CONSTRAINT fk_annotation_result_creator FOREIGN KEY (creator_id) REFERENCES sys_user(id),
|
||||
CONSTRAINT fk_annotation_result_task FOREIGN KEY (task_id) REFERENCES annotation_task(id),
|
||||
CONSTRAINT fk_annotation_result_resource FOREIGN KEY (resource_id) REFERENCES source_resource(id),
|
||||
CONSTRAINT fk_annotation_result_reviewer FOREIGN KEY (reviewer_id) REFERENCES sys_user(id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE annotation_result IS '当前标注结果表。';
|
||||
COMMENT ON COLUMN annotation_result.id IS '标注结果主键ID。';
|
||||
COMMENT ON COLUMN annotation_result.company_id IS '所属公司ID。';
|
||||
COMMENT ON COLUMN annotation_result.creator_id IS '结果创建人用户ID。';
|
||||
COMMENT ON COLUMN annotation_result.creator_role IS '结果创建人数据权限角色,默认 EMPLOYEE。';
|
||||
COMMENT ON COLUMN annotation_result.task_id IS '关联任务ID。';
|
||||
COMMENT ON COLUMN annotation_result.resource_id IS '关联资源ID。';
|
||||
COMMENT ON COLUMN annotation_result.qa_content_json IS '问答内容 JSON 字符串。字段类型为 TEXT,建议结构为 {\"question\":\"...\",\"answer\":\"...\"}。中小体积内容默认直接入库。';
|
||||
COMMENT ON COLUMN annotation_result.qa_content_storage_mode IS '问答内容存储模式,默认 INLINE,可选 INLINE、EXTERNAL。当完整问答内容较大时,可设为 EXTERNAL,仅在表内保留摘要或索引信息。';
|
||||
COMMENT ON COLUMN annotation_result.qa_content_file_path IS '当 qa_content_storage_mode = EXTERNAL 时,记录外置问答内容文件路径。';
|
||||
COMMENT ON COLUMN annotation_result.diff_summary IS '差异摘要 JSON 字符串。字段类型为 TEXT,建议结构为 {\"extract_question\":\"...\",\"extract_answer\":\"...\",\"verify_answer\":\"...\",\"mismatch_fields\":[\"question\",\"answer\"],\"reason\":\"...\"}。';
|
||||
COMMENT ON COLUMN annotation_result.requires_manual_review IS '是否需要人工审核,默认 FALSE。';
|
||||
COMMENT ON COLUMN annotation_result.is_deleted IS '软删除标记,默认 FALSE。';
|
||||
COMMENT ON COLUMN annotation_result.reviewer_id IS '审核人用户ID。';
|
||||
COMMENT ON COLUMN annotation_result.review_comment IS '审核意见。';
|
||||
COMMENT ON COLUMN annotation_result.reviewed_at IS '审核时间。';
|
||||
COMMENT ON COLUMN annotation_result.created_at IS '创建时间。';
|
||||
COMMENT ON COLUMN annotation_result.updated_at IS '更新时间。';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS annotation_result_history (
|
||||
id BIGINT PRIMARY KEY,
|
||||
company_id BIGINT NOT NULL,
|
||||
creator_id BIGINT NOT NULL,
|
||||
creator_role VARCHAR(32) NOT NULL DEFAULT 'EMPLOYEE',
|
||||
source_result_id BIGINT,
|
||||
task_id BIGINT NOT NULL,
|
||||
resource_id BIGINT NOT NULL,
|
||||
qa_content_json TEXT NOT NULL DEFAULT '{}',
|
||||
qa_content_storage_mode VARCHAR(32) NOT NULL DEFAULT 'INLINE',
|
||||
qa_content_file_path VARCHAR(512),
|
||||
archive_reason VARCHAR(255),
|
||||
archived_by BIGINT,
|
||||
archived_at TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_annotation_result_history_company FOREIGN KEY (company_id) REFERENCES sys_company(id),
|
||||
CONSTRAINT fk_annotation_result_history_creator FOREIGN KEY (creator_id) REFERENCES sys_user(id),
|
||||
CONSTRAINT fk_annotation_result_history_result FOREIGN KEY (source_result_id) REFERENCES annotation_result(id),
|
||||
CONSTRAINT fk_annotation_result_history_task FOREIGN KEY (task_id) REFERENCES annotation_task(id),
|
||||
CONSTRAINT fk_annotation_result_history_resource FOREIGN KEY (resource_id) REFERENCES source_resource(id),
|
||||
CONSTRAINT fk_annotation_result_history_archived_by FOREIGN KEY (archived_by) REFERENCES sys_user(id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE annotation_result_history IS '历史归档结果表。';
|
||||
COMMENT ON COLUMN annotation_result_history.id IS '历史结果主键ID。';
|
||||
COMMENT ON COLUMN annotation_result_history.company_id IS '所属公司ID。';
|
||||
COMMENT ON COLUMN annotation_result_history.creator_id IS '历史记录创建人用户ID。';
|
||||
COMMENT ON COLUMN annotation_result_history.creator_role IS '历史记录创建人数据权限角色,默认 EMPLOYEE。';
|
||||
COMMENT ON COLUMN annotation_result_history.source_result_id IS '来源运行态结果ID。';
|
||||
COMMENT ON COLUMN annotation_result_history.task_id IS '关联任务ID。';
|
||||
COMMENT ON COLUMN annotation_result_history.resource_id IS '关联资源ID。';
|
||||
COMMENT ON COLUMN annotation_result_history.qa_content_json IS '归档后的问答内容 JSON 字符串。字段类型为 TEXT,建议结构为 {"question":"...","answer":"..."}。';
|
||||
COMMENT ON COLUMN annotation_result_history.qa_content_storage_mode IS '归档后的问答内容存储模式,默认 INLINE,可选 INLINE、EXTERNAL。';
|
||||
COMMENT ON COLUMN annotation_result_history.qa_content_file_path IS '当 qa_content_storage_mode = EXTERNAL 时,记录归档后的外置问答内容文件路径。';
|
||||
COMMENT ON COLUMN annotation_result_history.archive_reason IS '归档原因说明。';
|
||||
COMMENT ON COLUMN annotation_result_history.archived_by IS '归档操作人用户ID。';
|
||||
COMMENT ON COLUMN annotation_result_history.archived_at IS '归档时间。';
|
||||
COMMENT ON COLUMN annotation_result_history.created_at IS '创建时间。';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS training_dataset (
|
||||
id BIGINT PRIMARY KEY,
|
||||
company_id BIGINT NOT NULL,
|
||||
creator_id BIGINT NOT NULL,
|
||||
creator_role VARCHAR(32) NOT NULL DEFAULT 'EMPLOYEE',
|
||||
result_history_id BIGINT NOT NULL,
|
||||
sample_type VARCHAR(32) NOT NULL DEFAULT 'TEXT',
|
||||
glm_format_json TEXT NOT NULL,
|
||||
dataset_status VARCHAR(32) NOT NULL DEFAULT 'DRAFT',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_training_dataset_company FOREIGN KEY (company_id) REFERENCES sys_company(id),
|
||||
CONSTRAINT fk_training_dataset_creator FOREIGN KEY (creator_id) REFERENCES sys_user(id),
|
||||
CONSTRAINT fk_training_dataset_result_history FOREIGN KEY (result_history_id) REFERENCES annotation_result_history(id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE training_dataset IS '训练样本表。';
|
||||
COMMENT ON COLUMN training_dataset.id IS '训练样本主键ID。';
|
||||
COMMENT ON COLUMN training_dataset.company_id IS '所属公司ID。';
|
||||
COMMENT ON COLUMN training_dataset.creator_id IS '样本创建人用户ID。';
|
||||
COMMENT ON COLUMN training_dataset.creator_role IS '样本创建人数据权限角色,默认 EMPLOYEE。';
|
||||
COMMENT ON COLUMN training_dataset.result_history_id IS '来源历史结果ID。';
|
||||
COMMENT ON COLUMN training_dataset.sample_type IS '样本类型,默认 TEXT,可按需扩展 IMAGE、VIDEO。';
|
||||
COMMENT ON COLUMN training_dataset.glm_format_json IS 'GLM微调格式 JSON 字符串。';
|
||||
COMMENT ON COLUMN training_dataset.dataset_status IS '样本状态,默认 DRAFT,可选 EXPORTED。';
|
||||
COMMENT ON COLUMN training_dataset.created_at IS '创建时间。';
|
||||
COMMENT ON COLUMN training_dataset.updated_at IS '更新时间。';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS export_batch (
|
||||
id BIGINT PRIMARY KEY,
|
||||
company_id BIGINT NOT NULL,
|
||||
creator_id BIGINT NOT NULL,
|
||||
creator_role VARCHAR(32) NOT NULL DEFAULT 'EMPLOYEE',
|
||||
batch_no VARCHAR(64) NOT NULL UNIQUE,
|
||||
dataset_file_path VARCHAR(512),
|
||||
sample_count INTEGER NOT NULL DEFAULT 0,
|
||||
finetune_job_id VARCHAR(128),
|
||||
finetune_status VARCHAR(32) NOT NULL DEFAULT 'NOT_STARTED',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_export_batch_company FOREIGN KEY (company_id) REFERENCES sys_company(id),
|
||||
CONSTRAINT fk_export_batch_creator FOREIGN KEY (creator_id) REFERENCES sys_user(id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE export_batch IS '导出批次表。';
|
||||
COMMENT ON COLUMN export_batch.id IS '导出批次主键ID。';
|
||||
COMMENT ON COLUMN export_batch.company_id IS '所属公司ID。';
|
||||
COMMENT ON COLUMN export_batch.creator_id IS '批次创建人用户ID。';
|
||||
COMMENT ON COLUMN export_batch.creator_role IS '批次创建人数据权限角色,默认 EMPLOYEE。';
|
||||
COMMENT ON COLUMN export_batch.batch_no IS '批次编号,全局唯一。';
|
||||
COMMENT ON COLUMN export_batch.dataset_file_path IS '导出的数据文件路径。';
|
||||
COMMENT ON COLUMN export_batch.sample_count IS '批次包含的样本数量,默认 0。';
|
||||
COMMENT ON COLUMN export_batch.finetune_job_id IS '微调任务ID。';
|
||||
COMMENT ON COLUMN export_batch.finetune_status IS '微调状态,默认 NOT_STARTED,可选 RUNNING、SUCCESS、FAILED。';
|
||||
COMMENT ON COLUMN export_batch.created_at IS '创建时间。';
|
||||
COMMENT ON COLUMN export_batch.updated_at IS '更新时间。';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS export_batch_item (
|
||||
id BIGINT PRIMARY KEY,
|
||||
batch_id BIGINT NOT NULL,
|
||||
dataset_id BIGINT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_export_batch_item_batch FOREIGN KEY (batch_id) REFERENCES export_batch(id),
|
||||
CONSTRAINT fk_export_batch_item_dataset FOREIGN KEY (dataset_id) REFERENCES training_dataset(id),
|
||||
CONSTRAINT uq_export_batch_item UNIQUE (batch_id, dataset_id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE export_batch_item IS '导出批次与训练样本关系表。';
|
||||
COMMENT ON COLUMN export_batch_item.id IS '批次样本关系主键ID。';
|
||||
COMMENT ON COLUMN export_batch_item.batch_id IS '关联导出批次ID。';
|
||||
COMMENT ON COLUMN export_batch_item.dataset_id IS '关联训练样本ID。';
|
||||
COMMENT ON COLUMN export_batch_item.created_at IS '创建时间。';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_user_company ON sys_user(company_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_user_role ON sys_user(company_id, role);
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_user_position ON sys_user(company_id, position);
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_menu_company_sort ON sys_menu(company_id, sort_order);
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_config_company_type ON sys_config(company_id, config_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_biz_data_record_company_role ON biz_data_record(company_id, creator_role);
|
||||
CREATE INDEX IF NOT EXISTS idx_source_resource_company_type ON source_resource(company_id, resource_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_source_resource_company_status ON source_resource(company_id, source_status);
|
||||
CREATE INDEX IF NOT EXISTS idx_source_resource_creator ON source_resource(company_id, creator_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_annotation_task_company_status ON annotation_task(company_id, task_status);
|
||||
CREATE INDEX IF NOT EXISTS idx_annotation_task_company_deleted ON annotation_task(company_id, is_deleted);
|
||||
CREATE INDEX IF NOT EXISTS idx_annotation_task_creator ON annotation_task(company_id, creator_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_annotation_task_resource_company_task ON annotation_task_resource(company_id, task_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_annotation_task_resource_company_resource ON annotation_task_resource(company_id, resource_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_annotation_result_company_deleted ON annotation_result(company_id, is_deleted);
|
||||
CREATE INDEX IF NOT EXISTS idx_annotation_result_company_manual ON annotation_result(company_id, requires_manual_review);
|
||||
CREATE INDEX IF NOT EXISTS idx_annotation_result_task ON annotation_result(company_id, task_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_annotation_result_history_company ON annotation_result_history(company_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_annotation_result_history_task ON annotation_result_history(company_id, task_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_annotation_result_history_resource ON annotation_result_history(company_id, resource_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_training_dataset_company_status ON training_dataset(company_id, dataset_status);
|
||||
CREATE INDEX IF NOT EXISTS idx_export_batch_company_status ON export_batch(company_id, finetune_status);
|
||||
|
||||
COMMIT;
|
||||
|
||||
Reference in New Issue
Block a user