初始化代码
This commit is contained in:
parent
cec5498060
commit
303b60502e
|
|
@ -1,7 +1,11 @@
|
|||
# 构建上下文排除项,加速构建并避免敏感文件泄漏
|
||||
# 只保留 Dockerfile COPY 需要的文件:Dockerfile、laop-admin.jar
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
.mvn/wrapper/maven-wrapper.properties
|
||||
src/
|
||||
pom.xml
|
||||
.mvn/
|
||||
mvnw
|
||||
mvnw.cmd
|
||||
|
||||
# IDE & 系统
|
||||
.idea/
|
||||
|
|
@ -22,6 +26,3 @@ logs/
|
|||
# 文档(不需要进入镜像)
|
||||
*.md
|
||||
docs/
|
||||
|
||||
# 测试
|
||||
src/test/
|
||||
|
|
|
|||
52
Dockerfile
52
Dockerfile
|
|
@ -1,38 +1,26 @@
|
|||
# =====================================================================
|
||||
# 翼云Hub · LAOP-admin 后端镜像 Dockerfile
|
||||
# --------------------------------------------------------------------
|
||||
# 说明:
|
||||
# - 项目 pom.xml 指定 Java 17(source/target),编译期和运行期版本严格一致,
|
||||
# - jar 包最终名为 laop-admin.jar(由 pom.xml finalName 决定)。
|
||||
# 设计:本地 mvn package 预先生成 jar,Dockerfile 只 COPY jar 进 JRE 镜像
|
||||
# --------------------------------------------------------------------
|
||||
# 为什么不用多阶段构建(FROM maven → mvn package → FROM jre)?
|
||||
# - 多阶段构建在镜像内执行 mvn package,每次都要下载依赖,慢
|
||||
# - 跨架构构建(Mac arm64 → 服务器 x86_64)需 QEMU 模拟,慢上加慢
|
||||
# - Java 字节码与 CPU 架构无关,本地 Mac 编译的 jar 可直接跑在 x86_64 JRE 上
|
||||
# 改进后:
|
||||
# - 本地 mvn package 秒级完成(原生速度,无跨架构)
|
||||
# - Dockerfile 只 COPY jar,构建瞬间完成
|
||||
# - 不需要 QEMU,不需要基础镜像固化依赖
|
||||
# --------------------------------------------------------------------
|
||||
# 前置:本地执行过 mvn clean package -DskipTests -Pprod
|
||||
# 生成 target/laop-admin.jar
|
||||
# 脚本 build-and-push.sh 会自动完成这步并复制到 build context
|
||||
# =====================================================================
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# 阶段1:构建期(maven + jdk17,与 pom.xml 严格对齐)
|
||||
# -------------------------------------------------------------------
|
||||
FROM maven:3.9-eclipse-temurin-17 AS builder
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# 先单独 COPY pom.xml,利用 Docker 缓存层加速依赖下载
|
||||
COPY pom.xml ./
|
||||
# 预下载依赖(仅当 pom 变化时重新执行,提升后续构建速度)
|
||||
RUN mvn dependency:go-offline -B
|
||||
|
||||
# 复制源码
|
||||
COPY src ./src
|
||||
|
||||
# 打包:激活 prod profile,让 application.yml 中的 @spring.profiles.active@ 替换为 prod
|
||||
# -DskipTests:构建镜像时跳过测试,测试应在 CI 流水线单独执行
|
||||
RUN mvn clean package -DskipTests -Pprod
|
||||
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# 阶段2:运行期(JRE 17 LTS)
|
||||
# -------------------------------------------------------------------
|
||||
FROM eclipse-temurin:17-jre-jammy
|
||||
|
||||
LABEL maintainer="laop-admin"
|
||||
LABEL description="翼云Hub · 无人机信息开放平台 后端服务"
|
||||
LABEL description="无人机信息开放平台 后端服务"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
|
@ -47,16 +35,16 @@ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
|||
RUN mkdir -p /data/static
|
||||
ENV LAOP_STATIC_DIR=/data/static
|
||||
|
||||
# 拷贝构建产物
|
||||
COPY --from=builder /build/target/laop-admin.jar app.jar
|
||||
# 拷贝本地预编译好的 jar 包
|
||||
# 脚本 build-and-push.sh 在构建前会执行:
|
||||
# cp target/laop-admin.jar ./laop-admin.jar
|
||||
# 把 jar 复制到 build context 根目录(避免把整个 target/ 进入上下文)
|
||||
COPY laop-admin.jar app.jar
|
||||
|
||||
# 容器内暴露端口(与 application.yml server.port=8081 一致)
|
||||
EXPOSE 8081
|
||||
|
||||
# JVM 参数:容器内内存限制感知 + GC 优化(2核8G 服务器)
|
||||
# -XX:+UseContainerSupport:让 JVM 感知 cgroup 限制(JDK10+ 默认开启,显式声明)
|
||||
# -XX:MaxRAMPercentage=75.0:限制堆内存占容器内存 75%,给非堆留空间
|
||||
# -Djava.security.egd=file:/dev/./urandom:加速 SecureRandom 启动
|
||||
ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -Djava.security.egd=file:/dev/./urandom"
|
||||
|
||||
# 运行:显式指定 prod profile,覆盖任何默认配置
|
||||
|
|
|
|||
6
pom.xml
6
pom.xml
|
|
@ -65,12 +65,6 @@
|
|||
<version>${redisson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Flyway:Spring Boot 3.2 自带 9.22.x,无需显式声明版本 -->
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
-- 下级街道/镇在数据源中为 9 位编码, 违反"6 位编码"规约, 按民政部
|
||||
-- 公布口径仅保留市级一行, 不入库下级
|
||||
-- created_at / updated_at 由 DB DEFAULT 维护, deleted_at 默认 NULL, 均不显式写入
|
||||
-- 幂等性: 由 flyway_schema_history 表保证本脚本仅执行一次; 若 region 表已有
|
||||
-- 幂等性: 本脚本仅手动执行一次; 若 region 表已有
|
||||
-- 历史数据需重置, 先 TRUNCATE region RESTART IDENTITY CASCADE 再重跑
|
||||
-- ============================================================
|
||||
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
-- ============================================================
|
||||
-- 翼云Hub · 数据库完整 DDL(整理版)
|
||||
-- ------------------------------------------------------------
|
||||
-- 本文件合并了 V1 ~ V19 全部 Flyway 迁移的最终效果,
|
||||
-- 本文件合并了 V1 ~ V19 全部迁移 SQL 的最终效果,
|
||||
-- 按依赖顺序从零建库,供新环境初始化使用。
|
||||
--
|
||||
-- 与 Flyway 迁移脚本的关系:
|
||||
-- 现有 V1 ~ V19 保持原样不动(已部署环境正在使用),
|
||||
-- 与迁移脚本(同目录 V*.sql)的关系:
|
||||
-- 现有 V1 ~ V19 保持原样不动(已部署环境已按序执行过),
|
||||
-- 新环境可选:
|
||||
-- a) 继续走 Flyway(V1~V19 依次执行)——与已部署环境一致
|
||||
-- b) 直接执行本 schema.sql + data.sql(跳过 Flyway)——更快
|
||||
-- a) 按版本号顺序依次执行 V*.sql —— 与已部署环境一致
|
||||
-- b) 直接执行本 schema.sql + data.sql —— 更快(推荐新库用)
|
||||
--
|
||||
-- 目标数据库:PostgreSQL 14 / 16
|
||||
-- 字符集:UTF8(PG 默认)
|
||||
|
|
@ -13,7 +13,7 @@ import java.time.LocalDateTime;
|
|||
/**
|
||||
* 课程预约表,承载用户在课程详情页"立即预约"提交的预约信息。
|
||||
*
|
||||
* <p>唯一约束由 Flyway 迁移 V19 重建的部分唯一索引
|
||||
* <p>唯一约束由迁移 SQL V19 重建的部分唯一索引
|
||||
* {@code uk_course_appointment_active (user_id, course_id, appointment_date)
|
||||
* WHERE status != 2 AND deleted_at IS NULL}(2 = AppointmentStatusEnum.CANCELLED)保障,
|
||||
* 防止同一用户对同一课程同一时段重复提交有效预约;取消后允许重新预约。
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import jakarta.persistence.UniqueConstraint;
|
|||
/**
|
||||
* 省市区表,承载中国行政区划三级数据(省/市/区县)。
|
||||
*
|
||||
* <p>由 Flyway 启动时初始化预置数据(也可对接民政部区划接口定期同步)。
|
||||
* <p>预置数据由迁移 SQL(sql/V2__seed_region.sql)手动初始化(也可对接民政部区划接口定期同步)。
|
||||
* 业务侧所有涉及 LBS 的字段(如 {@link Pilot#getServiceCityCodes()})均以本表 {@code code}
|
||||
* 为值存储,多选用分号 {@code ;} 拼接,查询时通过程序侧 split + IN 或 SQL 模糊匹配筛选。</p>
|
||||
*
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import java.util.List;
|
|||
*
|
||||
* <p><b>职责边界:</b>
|
||||
* <ul>
|
||||
* <li>配置项"只能改值"——key 由 Flyway 迁移脚本在部署时一次性 INSERT,不允许运行时新增/删除;</li>
|
||||
* <li>配置项"只能改值"——key 由迁移 SQL 脚本(sql/V10__app_config.sql)在部署时一次性 INSERT,不允许运行时新增/删除;</li>
|
||||
* <li>修改时按配置键做类型校验(布尔开关只能 0/1,数值参数必须落在约定区间);</li>
|
||||
* <li>修改时自动刷新 updated_at 和 updated_by,保留操作审计能力。</li>
|
||||
* </ul>
|
||||
|
|
|
|||
|
|
@ -26,20 +26,19 @@ spring:
|
|||
minimum-idle: 2
|
||||
connection-timeout: 30000
|
||||
|
||||
flyway:
|
||||
enabled: false
|
||||
|
||||
data:
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
database: 0
|
||||
# 使用独立库 db2,与其他服务(默认 db0)数据隔离
|
||||
database: 2
|
||||
|
||||
redisson:
|
||||
config: |
|
||||
singleServerConfig:
|
||||
address: "redis://127.0.0.1:6379"
|
||||
database: 0
|
||||
# 与 spring.data.redis.database 保持一致:独立库 db2,与其他服务隔离
|
||||
database: 2
|
||||
connectionMinimumIdleSize: 4
|
||||
connectionPoolSize: 16
|
||||
|
||||
|
|
|
|||
|
|
@ -23,14 +23,16 @@ spring:
|
|||
redis:
|
||||
host: ${LAOP_REDIS_HOST}
|
||||
port: ${LAOP_REDIS_PORT:6379}
|
||||
database: ${LAOP_REDIS_DB:0}
|
||||
# 独立库 db2,与其他服务(默认 db0)数据隔离;.env 可用 LAOP_REDIS_DB 覆盖
|
||||
database: ${LAOP_REDIS_DB:2}
|
||||
password: ${LAOP_REDIS_PASSWORD}
|
||||
|
||||
redisson:
|
||||
config: |
|
||||
singleServerConfig:
|
||||
address: "redis://${LAOP_REDIS_HOST}:${LAOP_REDIS_PORT:6379}"
|
||||
database: ${LAOP_REDIS_DB:0}
|
||||
# 与 spring.data.redis.database 保持一致:独立库 db2
|
||||
database: ${LAOP_REDIS_DB:2}
|
||||
password: "${LAOP_REDIS_PASSWORD}"
|
||||
connectionMinimumIdleSize: 8
|
||||
connectionPoolSize: 64
|
||||
|
|
|
|||
|
|
@ -28,12 +28,6 @@ spring:
|
|||
jdbc.lob.non_contextual_creation: true
|
||||
type:
|
||||
preferred_json_jdbc_type: JSONB
|
||||
flyway:
|
||||
enabled: true
|
||||
locations: classpath:db/migration
|
||||
baseline-on-migrate: true
|
||||
baseline-version: 0
|
||||
table: flyway_schema_history
|
||||
|
||||
logging:
|
||||
level:
|
||||
|
|
|
|||
|
|
@ -1,88 +0,0 @@
|
|||
-- ============================================================
|
||||
-- V10 —— 功能配置表 app_config + 首页轮播图图片补全
|
||||
-- ------------------------------------------------------------
|
||||
-- 1. app_config:键值对形式的平台功能开关/参数配置
|
||||
-- 2. 把 V9 初始化的 3 条轮播图关联到真实图片(sys_file + /static/image/banner-home-*.png)
|
||||
-- ============================================================
|
||||
|
||||
-- ========== 1. 功能配置 KV 表 ==========
|
||||
CREATE TABLE IF NOT EXISTS app_config (
|
||||
config_key VARCHAR(64) PRIMARY KEY,
|
||||
config_value VARCHAR(1000) NOT NULL,
|
||||
remark VARCHAR(200),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_by VARCHAR(64)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE app_config IS '平台功能配置KV表(开关、参数等)';
|
||||
COMMENT ON COLUMN app_config.config_key IS '配置键,唯一标识';
|
||||
COMMENT ON COLUMN app_config.config_value IS '配置值(字符串形式,布尔值用 0/1)';
|
||||
COMMENT ON COLUMN app_config.remark IS '备注说明';
|
||||
COMMENT ON COLUMN app_config.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN app_config.updated_at IS '最后更新时间';
|
||||
COMMENT ON COLUMN app_config.updated_by IS '最后修改人标识(可选)';
|
||||
|
||||
CREATE TRIGGER trg_app_config_updated BEFORE UPDATE ON app_config
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
-- 微信公众号模板消息推送开关(0关闭 1开启)
|
||||
INSERT INTO app_config (config_key, config_value, remark)
|
||||
VALUES ('mp_push_enabled', '0', '微信公众号模板消息推送总开关(0关闭 1开启)')
|
||||
ON CONFLICT (config_key) DO NOTHING;
|
||||
|
||||
|
||||
-- ========== 2. 首页轮播图图片补全 ==========
|
||||
-- 本地磁盘文件已由运维放到 static/image/ 目录下:
|
||||
-- banner-home-01-yiyunhub.png
|
||||
-- banner-home-02-performance.png
|
||||
-- banner-home-03-merchant.png
|
||||
-- 本脚本负责注册 sys_file 记录 + 关联到 app_banner。
|
||||
|
||||
-- 注册 3 张图片到 sys_file(file_type = 8 → BANNER_IMAGE)
|
||||
WITH
|
||||
reg1 AS (
|
||||
INSERT INTO sys_file (file_name, file_suffix, file_url, file_size, file_type, uploader_id, status)
|
||||
VALUES ('banner-home-01-yiyunhub.png', 'png', '/static/image/banner-home-01-yiyunhub.png', NULL, 8, NULL, 1)
|
||||
ON CONFLICT DO NOTHING
|
||||
RETURNING id
|
||||
),
|
||||
reg2 AS (
|
||||
INSERT INTO sys_file (file_name, file_suffix, file_url, file_size, file_type, uploader_id, status)
|
||||
VALUES ('banner-home-02-performance.png', 'png', '/static/image/banner-home-02-performance.png', NULL, 8, NULL, 1)
|
||||
ON CONFLICT DO NOTHING
|
||||
RETURNING id
|
||||
),
|
||||
reg3 AS (
|
||||
INSERT INTO sys_file (file_name, file_suffix, file_url, file_size, file_type, uploader_id, status)
|
||||
VALUES ('banner-home-03-merchant.png', 'png', '/static/image/banner-home-03-merchant.png', NULL, 8, NULL, 1)
|
||||
ON CONFLICT DO NOTHING
|
||||
RETURNING id
|
||||
),
|
||||
-- 兜底:如果 ON CONFLICT 没返回 id(文件已存在),通过 file_name 反查
|
||||
f1 AS (SELECT id FROM reg1 UNION ALL SELECT id FROM sys_file WHERE file_name = 'banner-home-01-yiyunhub.png' LIMIT 1),
|
||||
f2 AS (SELECT id FROM reg2 UNION ALL SELECT id FROM sys_file WHERE file_name = 'banner-home-02-performance.png' LIMIT 1),
|
||||
f3 AS (SELECT id FROM reg3 UNION ALL SELECT id FROM sys_file WHERE file_name = 'banner-home-03-merchant.png' LIMIT 1)
|
||||
-- 把图片关联到轮播图(按标题匹配 V9 初始化的 3 条)
|
||||
UPDATE app_banner
|
||||
SET
|
||||
image_file_id = CASE title
|
||||
WHEN 'CAAC 报名通道开启' THEN (SELECT id FROM f1)
|
||||
WHEN '无人机表演专场' THEN (SELECT id FROM f2)
|
||||
WHEN '实力商家招商入驻' THEN (SELECT id FROM f3)
|
||||
END,
|
||||
-- 同步更新标题为小程序实际显示的文案
|
||||
title = CASE title
|
||||
WHEN 'CAAC 报名通道开启' THEN '翼云Hub'
|
||||
WHEN '无人机表演专场' THEN '商业表演'
|
||||
WHEN '实力商家招商入驻' THEN '实力商家'
|
||||
ELSE title
|
||||
END,
|
||||
subtitle = CASE title
|
||||
WHEN 'CAAC 报名通道开启' THEN '无人机信息开放平台'
|
||||
WHEN '无人机表演专场' THEN '专业飞手 高客单'
|
||||
WHEN '实力商家招商入驻' THEN '开放生态 精准流量'
|
||||
ELSE subtitle
|
||||
END
|
||||
WHERE deleted_at IS NULL
|
||||
AND image_file_id IS NULL;
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
-- =====================================================================
|
||||
-- V11: course_appointment 唯一索引改为部分唯一索引
|
||||
-- ------------------------------------------------------------
|
||||
-- 背景:
|
||||
-- V1 创建的全量唯一索引 (user_id, course_id, appointment_date) 不区分
|
||||
-- 预约状态,导致用户取消预约后无法重新预约同一课程同一时段,
|
||||
-- 从产品交互角度不合理。
|
||||
--
|
||||
-- 改为部分唯一索引:仅在"有效预约"(status != 4 已取消 且 deleted_at IS NULL)
|
||||
-- 范围内生效,允许取消后重新预约,同时仍防止重复的有效预约。
|
||||
--
|
||||
-- status=4 对应 CourseConstants.APPT_STATUS_CANCELLED(已取消)
|
||||
-- =====================================================================
|
||||
|
||||
-- 1. 删除原全量唯一索引
|
||||
DROP INDEX IF EXISTS uk_course_appointment_user_course_date;
|
||||
|
||||
-- 2. 创建部分唯一索引:仅对"有效预约"生效,取消/软删的记录不参与唯一性校验
|
||||
CREATE UNIQUE INDEX uk_course_appointment_active
|
||||
ON course_appointment (user_id, course_id, appointment_date)
|
||||
WHERE status != 4 AND deleted_at IS NULL;
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
-- ============================================================
|
||||
-- V12: 门店培训信息表 + 题库种子数据
|
||||
-- 1. training_store:Web 管理端"培训考试 → 培训"tab 展示的门店介绍信息
|
||||
-- 2. exam_bank 种子:AOPA / UTC / ASDC / CAAC 四类执照题库
|
||||
-- 3. exam_question 种子:从公开题库整理的单选/多选/判断题(含答案与解析)
|
||||
-- ============================================================
|
||||
|
||||
-- ------------------------------------------------------------
|
||||
-- 门店培训信息表 training_store
|
||||
-- 单条记录设计:管理员编辑门店介绍,Web 端查询返回首条有效记录
|
||||
-- ------------------------------------------------------------
|
||||
CREATE TABLE training_store (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
address VARCHAR(200),
|
||||
contact_name VARCHAR(50),
|
||||
contact_phone VARCHAR(20),
|
||||
training_content TEXT,
|
||||
cover_image BIGINT,
|
||||
status SMALLINT NOT NULL DEFAULT 1,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
CREATE INDEX idx_training_store_deleted ON training_store (deleted_at);
|
||||
COMMENT ON TABLE training_store IS '门店培训信息表';
|
||||
COMMENT ON COLUMN training_store.id IS '主键';
|
||||
COMMENT ON COLUMN training_store.name IS '门店名称';
|
||||
COMMENT ON COLUMN training_store.address IS '门店地址';
|
||||
COMMENT ON COLUMN training_store.contact_name IS '联系人';
|
||||
COMMENT ON COLUMN training_store.contact_phone IS '联系电话';
|
||||
COMMENT ON COLUMN training_store.training_content IS '培训内容介绍';
|
||||
COMMENT ON COLUMN training_store.cover_image IS '封面图file_id(sys_file.id)';
|
||||
COMMENT ON COLUMN training_store.status IS '状态:0禁用 1启用';
|
||||
COMMENT ON COLUMN training_store.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN training_store.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN training_store.deleted_at IS '软删除时间';
|
||||
CREATE TRIGGER trg_training_store_updated BEFORE UPDATE ON training_store
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
-- 默认门店记录(管理员可在 Web 端编辑覆盖)
|
||||
INSERT INTO training_store (name, address, contact_name, contact_phone, training_content, status)
|
||||
VALUES ('翼云Hub无人机培训中心', '上海市松江区科技园区翼云路1号', '王教练', '13800138000',
|
||||
'本中心提供AOPA/UTC/ASDC/CAAC四类无人机执照理论培训与实操指导,涵盖航空法规、飞行原理、气象学、应急处置等核心模块,由资深飞行教官授课,通过率业内领先。', 1);
|
||||
|
||||
-- ============================================================
|
||||
-- 题库种子数据:4 个执照类型题库
|
||||
-- ============================================================
|
||||
INSERT INTO exam_bank (id, name, description, question_count, difficulty, status) VALUES
|
||||
(1, 'CAAC 无人机理论考试题库', '中国民航局(CAAC)无人机驾驶员执照理论考试题库,涵盖航空法规、空域管理、飞行原理、应急处置等核心考点。', 20, 2, 1),
|
||||
(2, 'AOPA 无人机理论考试题库', '中国航空器拥有者及驾驶员协会(AOPA)无人机驾驶员考试题库,侧重飞行操作与实操规范。', 5, 2, 1),
|
||||
(3, 'UTC 无人机理论考试题库', '无人驾驶航空器系统驾驶员训练合格证(UTC)考试题库,涵盖航拍、植保等应用场景知识。', 5, 1, 1),
|
||||
(4, 'ASDC 无人机理论考试题库', '中国航空运动协会(ASDC)无人机驾驶员考试题库,侧重航模与运动类飞行器知识。', 5, 1, 1);
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,83 +0,0 @@
|
|||
-- ============================================================
|
||||
-- V16: 任务申请-审批流 + 微信服务号模板消息
|
||||
-- 1) task_record 状态语义升级为"飞手申请 → 商家审批"生命周期,补充审核字段
|
||||
-- 2) user 表补充微信开放平台 unionid 与服务号 openid(模板消息接收人)
|
||||
-- 3) 新增 wx_message_log 模板消息发送日志表(Web 端可查)
|
||||
-- ============================================================
|
||||
|
||||
-- ------------------------------------------------------------
|
||||
-- 1. task_record:申请记录支持商家审批
|
||||
-- ------------------------------------------------------------
|
||||
ALTER TABLE task_record ADD COLUMN reject_time TIMESTAMP;
|
||||
ALTER TABLE task_record ADD COLUMN reject_reason VARCHAR(200);
|
||||
|
||||
COMMENT ON TABLE task_record IS '任务申请记录表(飞手申请接单 → 商家审批 → 执行)';
|
||||
COMMENT ON COLUMN task_record.status IS '状态:1已申请(待商家确认) 2商家已同意(已接单) 3商家已拒绝 4飞手已撤销';
|
||||
COMMENT ON COLUMN task_record.apply_time IS '飞手申请接单时间';
|
||||
COMMENT ON COLUMN task_record.accept_time IS '商家同意时间';
|
||||
COMMENT ON COLUMN task_record.reject_time IS '商家拒绝时间';
|
||||
COMMENT ON COLUMN task_record.reject_reason IS '商家拒绝原因';
|
||||
|
||||
-- ------------------------------------------------------------
|
||||
-- 2. user:服务号模板消息接收人身份
|
||||
-- ------------------------------------------------------------
|
||||
ALTER TABLE "user" ADD COLUMN unionid VARCHAR(64);
|
||||
ALTER TABLE "user" ADD COLUMN mp_openid VARCHAR(64);
|
||||
|
||||
CREATE INDEX idx_user_unionid ON "user" (unionid);
|
||||
CREATE INDEX idx_user_mp_openid ON "user" (mp_openid);
|
||||
|
||||
COMMENT ON COLUMN "user".unionid IS '微信开放平台 unionid(小程序登录返回时写入,跨端身份关联)';
|
||||
COMMENT ON COLUMN "user".mp_openid IS '微信服务号 openid(关注服务号事件自动绑定),NULL 表示未关注服务号';
|
||||
|
||||
-- ------------------------------------------------------------
|
||||
-- 3. wx_message_log:模板消息发送日志(发送结果由微信回调回写)
|
||||
-- ------------------------------------------------------------
|
||||
CREATE TABLE wx_message_log (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
user_id BIGINT,
|
||||
biz_type SMALLINT NOT NULL,
|
||||
biz_id BIGINT,
|
||||
template_id VARCHAR(64) NOT NULL,
|
||||
open_id VARCHAR(64),
|
||||
msg_id BIGINT,
|
||||
send_status SMALLINT NOT NULL,
|
||||
skip_reason VARCHAR(200),
|
||||
err_code VARCHAR(32),
|
||||
err_msg VARCHAR(500),
|
||||
result_status VARCHAR(64),
|
||||
content TEXT,
|
||||
send_time TIMESTAMP,
|
||||
result_time TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_wx_message_log_user ON wx_message_log (user_id);
|
||||
CREATE INDEX idx_wx_message_log_msg_id ON wx_message_log (msg_id);
|
||||
CREATE INDEX idx_wx_message_log_status ON wx_message_log (send_status);
|
||||
CREATE INDEX idx_wx_message_log_deleted ON wx_message_log (deleted_at);
|
||||
|
||||
COMMENT ON TABLE wx_message_log IS '微信模板消息发送日志表';
|
||||
COMMENT ON COLUMN wx_message_log.id IS '主键';
|
||||
COMMENT ON COLUMN wx_message_log.user_id IS '接收人用户ID(商家)';
|
||||
COMMENT ON COLUMN wx_message_log.biz_type IS '业务类型:1任务申请通知';
|
||||
COMMENT ON COLUMN wx_message_log.biz_id IS '业务单据ID(任务申请通知为 task_record.id)';
|
||||
COMMENT ON COLUMN wx_message_log.template_id IS '微信模板ID';
|
||||
COMMENT ON COLUMN wx_message_log.open_id IS '接收人服务号 openid';
|
||||
COMMENT ON COLUMN wx_message_log.msg_id IS '微信返回的消息ID(发送提交成功后返回,回调送达结果以此关联)';
|
||||
COMMENT ON COLUMN wx_message_log.send_status IS '发送状态:0已跳过 1已提交 2送达成功 3送达失败';
|
||||
COMMENT ON COLUMN wx_message_log.skip_reason IS '跳过原因(未绑定服务号等)';
|
||||
COMMENT ON COLUMN wx_message_log.err_code IS '提交/送达错误码';
|
||||
COMMENT ON COLUMN wx_message_log.err_msg IS '提交/送达错误信息';
|
||||
COMMENT ON COLUMN wx_message_log.result_status IS '微信回调送达结果原文(success / failed:user block 等)';
|
||||
COMMENT ON COLUMN wx_message_log.content IS '模板参数 JSON 快照,便于排查展示问题';
|
||||
COMMENT ON COLUMN wx_message_log.send_time IS '提交微信发送时间';
|
||||
COMMENT ON COLUMN wx_message_log.result_time IS '微信回调送达时间';
|
||||
COMMENT ON COLUMN wx_message_log.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN wx_message_log.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN wx_message_log.deleted_at IS '软删除时间';
|
||||
|
||||
CREATE TRIGGER trg_wx_message_log_updated BEFORE UPDATE ON wx_message_log
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
-- ============================================================
|
||||
-- V17: 模板消息队列持久化(DB 队列替代内存队列)
|
||||
-- 1) 新建 wx_notify_task 任务表(PENDING → PROCESSING → SUCCESS/FAILED,消费后软删除)
|
||||
-- 2) wx_message_log 增加 task_id 列,关联发送任务
|
||||
-- ============================================================
|
||||
|
||||
-- ------------------------------------------------------------
|
||||
-- 1. wx_notify_task:模板消息发送任务表(DB 持久化队列)
|
||||
-- 替代原 LinkedBlockingQueue 内存队列,解决服务重启未消费任务丢失问题。
|
||||
-- 消费机制:CAS 占位(status 0→1),成功后发送,完成时软删除。
|
||||
-- 失败重试:retry_count + next_retry_at 指数退避,超过上限置 FAILED 并软删除。
|
||||
-- ------------------------------------------------------------
|
||||
CREATE TABLE wx_notify_task (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL,
|
||||
biz_type SMALLINT NOT NULL,
|
||||
biz_id BIGINT,
|
||||
task_no VARCHAR(64),
|
||||
task_name VARCHAR(128),
|
||||
service_type_name VARCHAR(64),
|
||||
handler VARCHAR(128),
|
||||
operate_time VARCHAR(32),
|
||||
template_id VARCHAR(64),
|
||||
status SMALLINT NOT NULL DEFAULT 0,
|
||||
retry_count SMALLINT NOT NULL DEFAULT 0,
|
||||
next_retry_at TIMESTAMP,
|
||||
skip_reason VARCHAR(200),
|
||||
err_code VARCHAR(32),
|
||||
err_msg VARCHAR(500),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
|
||||
-- 部分索引:仅索引未软删除且待处理行,消费查询高效
|
||||
CREATE INDEX idx_wx_notify_task_pending ON wx_notify_task (status, next_retry_at)
|
||||
WHERE deleted_at IS NULL AND status = 0;
|
||||
CREATE INDEX idx_wx_notify_task_user ON wx_notify_task (user_id);
|
||||
CREATE INDEX idx_wx_notify_task_biz ON wx_notify_task (biz_type, biz_id);
|
||||
|
||||
COMMENT ON TABLE wx_notify_task IS '微信模板消息发送任务表(DB 持久化队列,消费完成后软删除)';
|
||||
COMMENT ON COLUMN wx_notify_task.id IS '主键';
|
||||
COMMENT ON COLUMN wx_notify_task.user_id IS '接收人用户ID';
|
||||
COMMENT ON COLUMN wx_notify_task.biz_type IS '业务类型:1任务申请 2审核结果 3飞手撤销(同 wx_message_log.biz_type)';
|
||||
COMMENT ON COLUMN wx_notify_task.biz_id IS '业务单据ID(任务动态通知为 task_record.id)';
|
||||
COMMENT ON COLUMN wx_notify_task.task_no IS '任务编号(模板 character_string14)';
|
||||
COMMENT ON COLUMN wx_notify_task.task_name IS '任务名称(模板 thing5)';
|
||||
COMMENT ON COLUMN wx_notify_task.service_type_name IS '服务类型名称(模板 thing12)';
|
||||
COMMENT ON COLUMN wx_notify_task.handler IS '处理人文案(模板 thing17)';
|
||||
COMMENT ON COLUMN wx_notify_task.operate_time IS '操作时间 yyyy-MM-dd HH:mm(模板 time18)';
|
||||
COMMENT ON COLUMN wx_notify_task.template_id IS '使用的模板ID(消费时解析写入,PENDING 阶段为 NULL)';
|
||||
COMMENT ON COLUMN wx_notify_task.status IS '任务状态:0待处理 1处理中 2成功 3失败';
|
||||
COMMENT ON COLUMN wx_notify_task.retry_count IS '已重试次数(0=首次,超过上限置 FAILED)';
|
||||
COMMENT ON COLUMN wx_notify_task.next_retry_at IS '下次重试时间(NULL=立即可处理)';
|
||||
COMMENT ON COLUMN wx_notify_task.skip_reason IS '跳过原因(未关注服务号等,不实际发送)';
|
||||
COMMENT ON COLUMN wx_notify_task.err_code IS '最后一次失败的错误码';
|
||||
COMMENT ON COLUMN wx_notify_task.err_msg IS '最后一次失败的错误信息';
|
||||
COMMENT ON COLUMN wx_notify_task.created_at IS '创建时间(入队时间)';
|
||||
COMMENT ON COLUMN wx_notify_task.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN wx_notify_task.deleted_at IS '软删除时间(消费完成后置位)';
|
||||
|
||||
CREATE TRIGGER trg_wx_notify_task_updated BEFORE UPDATE ON wx_notify_task
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
-- ------------------------------------------------------------
|
||||
-- 2. wx_message_log 增加 task_id 列(关联发送任务,从日志反查任务)
|
||||
-- ------------------------------------------------------------
|
||||
ALTER TABLE wx_message_log ADD COLUMN task_id BIGINT;
|
||||
|
||||
COMMENT ON COLUMN wx_message_log.task_id IS '关联的发送任务ID(wx_notify_task.id),从日志反查任务';
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
-- 研学课程表新增精选开关:开启后在小程序首页"精选研学课程"区块展示
|
||||
-- 默认全部课程为非精选,管理员在 Web 管理端手动标记
|
||||
ALTER TABLE course
|
||||
ADD COLUMN featured SMALLINT NOT NULL DEFAULT 0;
|
||||
|
||||
COMMENT ON COLUMN course.featured IS '精选标记:0否 1是,开启后小程序首页精选课程列表展示';
|
||||
|
||||
-- 为精选标记建立索引,加速首页查询 WHERE featured = 1
|
||||
CREATE INDEX idx_course_featured ON course(featured);
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
-- =====================================================================
|
||||
-- V19: course_appointment 预约状态二态化 + 部分唯一索引重建
|
||||
-- ------------------------------------------------------------
|
||||
-- 背景:
|
||||
-- 原 V1 设计了四态模型(1已预约/2已确认/3已完成/4已取消),产品侧
|
||||
-- 简化为二态:1已预约(用户提交即生效,无需商家确认)/ 2已取消
|
||||
-- (终态)。不再存在"商家确认"和"已完成"的中间状态。
|
||||
--
|
||||
-- 旧数据迁移策略:
|
||||
-- status=2(原已确认)→ 置为 1(已预约),因为不再需要商家确认
|
||||
-- status=3(原已完成)→ 置为 2(已取消),视作历史终态
|
||||
-- status=1/4 → 不变
|
||||
--
|
||||
-- 同时重建部分唯一索引:取消状态值从 4 变更为 2,索引条件同步更新。
|
||||
-- =====================================================================
|
||||
|
||||
-- 1. 旧数据回填:把原四态折叠为二态
|
||||
UPDATE course_appointment SET status = 1 WHERE status = 2; -- 已确认 → 已预约
|
||||
UPDATE course_appointment SET status = 2 WHERE status = 3; -- 已完成 → 已取消(历史终态)
|
||||
UPDATE course_appointment SET status = 2 WHERE status = 4; -- 原已取消(4) → 新已取消(2)
|
||||
|
||||
-- 2. 删除旧的部分唯一索引(V11 创建的,条件 WHERE status != 4)
|
||||
DROP INDEX IF EXISTS uk_course_appointment_active;
|
||||
|
||||
-- 3. 按新二态条件重建:有效预约 = status=1(已预约)且未软删
|
||||
CREATE UNIQUE INDEX uk_course_appointment_active
|
||||
ON course_appointment (user_id, course_id, appointment_date)
|
||||
WHERE status != 2 AND deleted_at IS NULL;
|
||||
|
|
@ -1,552 +0,0 @@
|
|||
-- ============================================================
|
||||
-- 翼云Hub · 数据库初始化脚本
|
||||
-- 目标数据库: PostgreSQL 14(开发) / PostgreSQL 16(生产)
|
||||
-- 字符集: UTF8 (PG 默认)
|
||||
-- 命名规范: 表名/字段名一律下划线小写,主键统一为 id
|
||||
-- 软删除: deleted_at,时间戳由 NULL 标记未删除
|
||||
-- 时间维护: created_at 由 DEFAULT 维护,updated_at 由触发器维护
|
||||
-- 多选字段: 以 String 存储,多值之间用英文分号 ; 拼接(如 "1;2;3")
|
||||
-- 经纬度字段: 统一用 VARCHAR(20) 存储,避免浮点精度问题
|
||||
-- 类型字段: 统一用 SMALLINT 存储数字编码(Java 侧映射为 Integer)
|
||||
-- ============================================================
|
||||
|
||||
-- ------------------------------------------------------------
|
||||
-- 公共触发器函数:自动维护 updated_at 字段
|
||||
-- 任何 UPDATE 命中该函数挂的表,updated_at 都会刷新为当前时间
|
||||
-- ------------------------------------------------------------
|
||||
CREATE OR REPLACE FUNCTION set_updated_at() RETURNS TRIGGER AS
|
||||
$$
|
||||
BEGIN
|
||||
NEW.updated_at = CURRENT_TIMESTAMP;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- ============================================================
|
||||
-- 1. 公告表 announcement
|
||||
-- ============================================================
|
||||
CREATE TABLE announcement (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
title VARCHAR(100) NOT NULL,
|
||||
content TEXT,
|
||||
valid_start_time TIMESTAMP,
|
||||
valid_end_time TIMESTAMP,
|
||||
status SMALLINT NOT NULL DEFAULT 1,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
CREATE INDEX idx_announcement_status ON announcement (status);
|
||||
CREATE INDEX idx_announcement_valid_period ON announcement (valid_start_time, valid_end_time);
|
||||
CREATE INDEX idx_announcement_deleted ON announcement (deleted_at);
|
||||
COMMENT ON TABLE announcement IS '公告表';
|
||||
COMMENT ON COLUMN announcement.id IS '主键';
|
||||
COMMENT ON COLUMN announcement.title IS '公告标题';
|
||||
COMMENT ON COLUMN announcement.content IS '公告正文';
|
||||
COMMENT ON COLUMN announcement.valid_start_time IS '生效开始时间';
|
||||
COMMENT ON COLUMN announcement.valid_end_time IS '生效结束时间';
|
||||
COMMENT ON COLUMN announcement.status IS '状态:0隐藏 1显示';
|
||||
COMMENT ON COLUMN announcement.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN announcement.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN announcement.deleted_at IS '软删除时间';
|
||||
CREATE TRIGGER trg_announcement_updated BEFORE UPDATE ON announcement
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
-- ============================================================
|
||||
-- 2. 用户表 "user"(user 在 PG 为保留字,需用双引号引用)
|
||||
-- ============================================================
|
||||
CREATE TABLE "user" (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
openid VARCHAR(64) NOT NULL,
|
||||
nickname VARCHAR(50),
|
||||
avatar_url VARCHAR(500),
|
||||
phone VARCHAR(20),
|
||||
gender SMALLINT NOT NULL DEFAULT 0,
|
||||
bio VARCHAR(200),
|
||||
role_type SMALLINT NOT NULL DEFAULT 1,
|
||||
points INT NOT NULL DEFAULT 0,
|
||||
is_pilot_bound SMALLINT NOT NULL DEFAULT 0,
|
||||
is_merchant_bound SMALLINT NOT NULL DEFAULT 0,
|
||||
pilot_id BIGINT,
|
||||
merchant_id BIGINT,
|
||||
status SMALLINT NOT NULL DEFAULT 1,
|
||||
last_login_at TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
CREATE UNIQUE INDEX uk_user_openid ON "user" (openid);
|
||||
CREATE INDEX idx_user_phone ON "user" (phone);
|
||||
CREATE INDEX idx_user_deleted ON "user" (deleted_at);
|
||||
COMMENT ON TABLE "user" IS '用户表';
|
||||
COMMENT ON COLUMN "user".id IS '主键';
|
||||
COMMENT ON COLUMN "user".openid IS '微信openId';
|
||||
COMMENT ON COLUMN "user".nickname IS '用户昵称';
|
||||
COMMENT ON COLUMN "user".avatar_url IS '头像URL';
|
||||
COMMENT ON COLUMN "user".phone IS '手机号';
|
||||
COMMENT ON COLUMN "user".gender IS '性别:0未知 1男 2女';
|
||||
COMMENT ON COLUMN "user".bio IS '个人简介';
|
||||
COMMENT ON COLUMN "user".role_type IS '角色类型:1普通用户 2飞手 3商家 4机构';
|
||||
COMMENT ON COLUMN "user".points IS '积分余额';
|
||||
COMMENT ON COLUMN "user".is_pilot_bound IS '是否已绑定飞手身份:0否 1是';
|
||||
COMMENT ON COLUMN "user".is_merchant_bound IS '是否已绑定商家身份:0否 1是';
|
||||
COMMENT ON COLUMN "user".pilot_id IS '关联飞手ID';
|
||||
COMMENT ON COLUMN "user".merchant_id IS '关联商家ID';
|
||||
COMMENT ON COLUMN "user".status IS '账号状态:0禁用 1正常';
|
||||
COMMENT ON COLUMN "user".last_login_at IS '最后登录时间';
|
||||
COMMENT ON COLUMN "user".created_at IS '注册时间';
|
||||
COMMENT ON COLUMN "user".updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN "user".deleted_at IS '软删除时间';
|
||||
CREATE TRIGGER trg_user_updated BEFORE UPDATE ON "user"
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
-- ============================================================
|
||||
-- 3. 商家表 merchant
|
||||
-- ============================================================
|
||||
CREATE TABLE merchant (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
address VARCHAR(200),
|
||||
door_image BIGINT,
|
||||
license_file_id BIGINT,
|
||||
contact_name VARCHAR(50),
|
||||
contact_phone VARCHAR(20),
|
||||
latitude VARCHAR(20),
|
||||
longitude VARCHAR(20),
|
||||
service_types VARCHAR(200),
|
||||
description TEXT,
|
||||
cert_status SMALLINT NOT NULL DEFAULT 0,
|
||||
cert_time TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
CREATE UNIQUE INDEX uk_merchant_user ON merchant (user_id);
|
||||
CREATE INDEX idx_merchant_cert ON merchant (cert_status);
|
||||
CREATE INDEX idx_merchant_deleted ON merchant (deleted_at);
|
||||
COMMENT ON TABLE merchant IS '商家表';
|
||||
COMMENT ON COLUMN merchant.id IS '主键';
|
||||
COMMENT ON COLUMN merchant.user_id IS '关联用户ID';
|
||||
COMMENT ON COLUMN merchant.name IS '商家名称';
|
||||
COMMENT ON COLUMN merchant.address IS '商家地址';
|
||||
COMMENT ON COLUMN merchant.door_image IS '门头照片file_id';
|
||||
COMMENT ON COLUMN merchant.license_file_id IS '营业执照file_id';
|
||||
COMMENT ON COLUMN merchant.contact_name IS '联系人';
|
||||
COMMENT ON COLUMN merchant.contact_phone IS '联系电话';
|
||||
COMMENT ON COLUMN merchant.latitude IS '纬度(字符串存储)';
|
||||
COMMENT ON COLUMN merchant.longitude IS '经度(字符串存储)';
|
||||
COMMENT ON COLUMN merchant.service_types IS '服务类型编码,多选用分号拼接,如:1;2;3';
|
||||
COMMENT ON COLUMN merchant.description IS '商家简介';
|
||||
COMMENT ON COLUMN merchant.cert_status IS '认证状态:0未认证 1认证中 2已认证 3认证失败';
|
||||
COMMENT ON COLUMN merchant.cert_time IS '认证时间';
|
||||
COMMENT ON COLUMN merchant.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN merchant.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN merchant.deleted_at IS '软删除时间';
|
||||
CREATE TRIGGER trg_merchant_updated BEFORE UPDATE ON merchant
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
-- ============================================================
|
||||
-- 4. 飞手表 pilot
|
||||
-- ============================================================
|
||||
CREATE TABLE pilot (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL,
|
||||
name VARCHAR(50) NOT NULL,
|
||||
phone VARCHAR(20) NOT NULL,
|
||||
birthday DATE,
|
||||
age SMALLINT,
|
||||
avatar_file_id BIGINT,
|
||||
cert_status SMALLINT NOT NULL DEFAULT 0,
|
||||
cert_time TIMESTAMP,
|
||||
service_city_codes VARCHAR(500),
|
||||
bio VARCHAR(200),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
CREATE UNIQUE INDEX uk_pilot_user ON pilot (user_id);
|
||||
CREATE INDEX idx_pilot_cert ON pilot (cert_status);
|
||||
CREATE INDEX idx_pilot_deleted ON pilot (deleted_at);
|
||||
COMMENT ON TABLE pilot IS '飞手表';
|
||||
COMMENT ON COLUMN pilot.id IS '主键';
|
||||
COMMENT ON COLUMN pilot.user_id IS '关联用户ID';
|
||||
COMMENT ON COLUMN pilot.name IS '姓名(实名)';
|
||||
COMMENT ON COLUMN pilot.phone IS '手机号';
|
||||
COMMENT ON COLUMN pilot.birthday IS '出生年月';
|
||||
COMMENT ON COLUMN pilot.age IS '年龄(自动计算)';
|
||||
COMMENT ON COLUMN pilot.avatar_file_id IS '头像file_id';
|
||||
COMMENT ON COLUMN pilot.cert_status IS '认证状态:0未认证 1认证中 2已认证 3认证失败';
|
||||
COMMENT ON COLUMN pilot.cert_time IS '认证时间';
|
||||
COMMENT ON COLUMN pilot.service_city_codes IS '服务城市编码,多选用分号拼接,关联region.code';
|
||||
COMMENT ON COLUMN pilot.bio IS '个人简介';
|
||||
COMMENT ON COLUMN pilot.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN pilot.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN pilot.deleted_at IS '软删除时间';
|
||||
CREATE TRIGGER trg_pilot_updated BEFORE UPDATE ON pilot
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
-- ============================================================
|
||||
-- 4.1 飞手执照表 pilot_license(独立一对多表,替代 pilot 上的分号拼接字段)
|
||||
-- ============================================================
|
||||
CREATE TABLE pilot_license (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
pilot_id BIGINT NOT NULL REFERENCES pilot(id),
|
||||
license_type SMALLINT NOT NULL CHECK (license_type IN (1, 2, 3, 4)),
|
||||
license_no VARCHAR(50),
|
||||
license_file_id BIGINT,
|
||||
license_date VARCHAR(10),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
CREATE INDEX idx_pilot_license_pilot ON pilot_license(pilot_id);
|
||||
COMMENT ON TABLE pilot_license IS '飞手执照表(多本执照一对多)';
|
||||
COMMENT ON COLUMN pilot_license.pilot_id IS '关联飞手ID(pilot.id)';
|
||||
COMMENT ON COLUMN pilot_license.license_type IS '执照类型编码:1 AOPA 2 UTC 3 ASFC 4 CAAC';
|
||||
COMMENT ON COLUMN pilot_license.license_no IS '执照编号';
|
||||
COMMENT ON COLUMN pilot_license.license_file_id IS '执照照片file_id(sys_file.id)';
|
||||
COMMENT ON COLUMN pilot_license.license_date IS '获证日期,格式 yyyy-MM-dd';
|
||||
COMMENT ON COLUMN pilot_license.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN pilot_license.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN pilot_license.deleted_at IS '软删除时间';
|
||||
CREATE TRIGGER trg_pilot_license_updated BEFORE UPDATE ON pilot_license
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
-- ============================================================
|
||||
-- 5. 任务表 task
|
||||
-- ============================================================
|
||||
CREATE TABLE task (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
task_no VARCHAR(32) NOT NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
type SMALLINT NOT NULL,
|
||||
province VARCHAR(20),
|
||||
city VARCHAR(20),
|
||||
district VARCHAR(20),
|
||||
address VARCHAR(200),
|
||||
latitude VARCHAR(20),
|
||||
longitude VARCHAR(20),
|
||||
scene_images VARCHAR(500),
|
||||
required_count INT NOT NULL DEFAULT 1,
|
||||
task_start_time TIMESTAMP NOT NULL,
|
||||
task_end_time TIMESTAMP,
|
||||
reward NUMERIC(10, 2) NOT NULL,
|
||||
insurance_require VARCHAR(100),
|
||||
contact_name VARCHAR(50),
|
||||
contact_phone VARCHAR(20) NOT NULL,
|
||||
remark TEXT,
|
||||
status SMALLINT NOT NULL DEFAULT 0,
|
||||
is_premium SMALLINT NOT NULL DEFAULT 0,
|
||||
premium_cost INT NOT NULL DEFAULT 0,
|
||||
publisher_id BIGINT NOT NULL,
|
||||
accepted_pilot_id BIGINT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
CREATE UNIQUE INDEX uk_task_task_no ON task (task_no);
|
||||
CREATE INDEX idx_task_type_status ON task (type, status);
|
||||
CREATE INDEX idx_task_city_status ON task (city, status);
|
||||
CREATE INDEX idx_task_publisher ON task (publisher_id);
|
||||
CREATE INDEX idx_task_pilot ON task (accepted_pilot_id);
|
||||
CREATE INDEX idx_task_deleted ON task (deleted_at);
|
||||
COMMENT ON TABLE task IS '任务表';
|
||||
COMMENT ON COLUMN task.id IS '主键';
|
||||
COMMENT ON COLUMN task.task_no IS '任务编号(全局唯一)';
|
||||
COMMENT ON COLUMN task.name IS '任务名称';
|
||||
COMMENT ON COLUMN task.type IS '任务类型编码:1植保 2吊运 3航拍 4巡检 5清洗 6表演 7测绘';
|
||||
COMMENT ON COLUMN task.province IS '省份';
|
||||
COMMENT ON COLUMN task.city IS '城市';
|
||||
COMMENT ON COLUMN task.district IS '区县';
|
||||
COMMENT ON COLUMN task.address IS '详细地址';
|
||||
COMMENT ON COLUMN task.latitude IS '纬度坐标(字符串存储)';
|
||||
COMMENT ON COLUMN task.longitude IS '经度坐标(字符串存储)';
|
||||
COMMENT ON COLUMN task.scene_images IS '作业场景图file_id数组,多选用分号拼接';
|
||||
COMMENT ON COLUMN task.required_count IS '需求人数';
|
||||
COMMENT ON COLUMN task.task_start_time IS '任务开始时间';
|
||||
COMMENT ON COLUMN task.task_end_time IS '任务结束时间';
|
||||
COMMENT ON COLUMN task.reward IS '报酬(元)';
|
||||
COMMENT ON COLUMN task.insurance_require IS '保险要求编码,多选用分号拼接:1三者险 2飞手险 3机身险';
|
||||
COMMENT ON COLUMN task.contact_name IS '联系人姓名';
|
||||
COMMENT ON COLUMN task.contact_phone IS '联系电话';
|
||||
COMMENT ON COLUMN task.remark IS '备注';
|
||||
COMMENT ON COLUMN task.status IS '状态:0草稿 1待接单 2已接单 3执行中 4已完成 5已取消';
|
||||
COMMENT ON COLUMN task.is_premium IS '是否优质任务:0否 1是';
|
||||
COMMENT ON COLUMN task.premium_cost IS '优质任务积分消耗';
|
||||
COMMENT ON COLUMN task.publisher_id IS '发布人ID';
|
||||
COMMENT ON COLUMN task.accepted_pilot_id IS '接单飞手ID';
|
||||
COMMENT ON COLUMN task.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN task.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN task.deleted_at IS '软删除时间';
|
||||
CREATE TRIGGER trg_task_updated BEFORE UPDATE ON task
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
-- ============================================================
|
||||
-- 6. 任务执行记录表 task_record
|
||||
-- ============================================================
|
||||
CREATE TABLE task_record (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
task_id BIGINT NOT NULL,
|
||||
user_id BIGINT NOT NULL,
|
||||
pilot_id BIGINT,
|
||||
merchant_id BIGINT,
|
||||
status SMALLINT NOT NULL DEFAULT 1,
|
||||
apply_time TIMESTAMP,
|
||||
accept_time TIMESTAMP,
|
||||
record_start_time TIMESTAMP,
|
||||
record_end_time TIMESTAMP,
|
||||
cancel_time TIMESTAMP,
|
||||
cancel_reason VARCHAR(200),
|
||||
insurance_verified SMALLINT NOT NULL DEFAULT 0,
|
||||
actual_reward NUMERIC(10, 2),
|
||||
rating SMALLINT,
|
||||
rating_comment VARCHAR(200),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
CREATE UNIQUE INDEX uk_task_record_task_user ON task_record (task_id, user_id);
|
||||
CREATE INDEX idx_task_record_user ON task_record (user_id, status);
|
||||
CREATE INDEX idx_task_record_pilot ON task_record (pilot_id, status);
|
||||
CREATE INDEX idx_task_record_deleted ON task_record (deleted_at);
|
||||
COMMENT ON TABLE task_record IS '任务执行记录表';
|
||||
COMMENT ON COLUMN task_record.id IS '主键';
|
||||
COMMENT ON COLUMN task_record.task_id IS '任务ID';
|
||||
COMMENT ON COLUMN task_record.user_id IS '关联用户ID';
|
||||
COMMENT ON COLUMN task_record.pilot_id IS '接单飞手ID';
|
||||
COMMENT ON COLUMN task_record.merchant_id IS '发单商家ID';
|
||||
COMMENT ON COLUMN task_record.status IS '状态:1待接单 2已接单 3执行中 4已完成 5已取消';
|
||||
COMMENT ON COLUMN task_record.apply_time IS '申请/接单时间';
|
||||
COMMENT ON COLUMN task_record.accept_time IS '飞手接单时间';
|
||||
COMMENT ON COLUMN task_record.record_start_time IS '实际开始时间';
|
||||
COMMENT ON COLUMN task_record.record_end_time IS '实际结束时间(完成时间)';
|
||||
COMMENT ON COLUMN task_record.cancel_time IS '取消时间';
|
||||
COMMENT ON COLUMN task_record.cancel_reason IS '取消原因';
|
||||
COMMENT ON COLUMN task_record.insurance_verified IS '保险是否校验:0否 1是';
|
||||
COMMENT ON COLUMN task_record.actual_reward IS '实际报酬';
|
||||
COMMENT ON COLUMN task_record.rating IS '用户评分(1-5)';
|
||||
COMMENT ON COLUMN task_record.rating_comment IS '评价内容';
|
||||
COMMENT ON COLUMN task_record.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN task_record.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN task_record.deleted_at IS '软删除时间';
|
||||
CREATE TRIGGER trg_task_record_updated BEFORE UPDATE ON task_record
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
-- ============================================================
|
||||
-- 7. 文件表 sys_file(避开 Java 与 PG 的保留字 file 冲突)
|
||||
-- 文件表只增不改、不更新,因此无 updated_at 字段
|
||||
-- ============================================================
|
||||
CREATE TABLE sys_file (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
file_name VARCHAR(200) NOT NULL,
|
||||
file_suffix VARCHAR(10),
|
||||
file_url VARCHAR(500),
|
||||
file_size BIGINT,
|
||||
file_type SMALLINT,
|
||||
uploader_id BIGINT,
|
||||
status SMALLINT NOT NULL DEFAULT 1,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
CREATE INDEX idx_sys_file_type ON sys_file (file_type);
|
||||
CREATE INDEX idx_sys_file_uploader ON sys_file (uploader_id);
|
||||
CREATE INDEX idx_sys_file_deleted ON sys_file (deleted_at);
|
||||
COMMENT ON TABLE sys_file IS '文件表';
|
||||
COMMENT ON COLUMN sys_file.id IS '主键';
|
||||
COMMENT ON COLUMN sys_file.file_name IS '原始文件名';
|
||||
COMMENT ON COLUMN sys_file.file_suffix IS '文件后缀';
|
||||
COMMENT ON COLUMN sys_file.file_url IS '访问URL';
|
||||
COMMENT ON COLUMN sys_file.file_size IS '文件大小(字节)';
|
||||
COMMENT ON COLUMN sys_file.file_type IS '业务类型编码:1营业执照 2飞手执照 3作业场景图 4课程图片 5头像 9其他';
|
||||
COMMENT ON COLUMN sys_file.uploader_id IS '上传用户ID';
|
||||
COMMENT ON COLUMN sys_file.status IS '状态:0禁用 1正常';
|
||||
COMMENT ON COLUMN sys_file.created_at IS '上传时间';
|
||||
COMMENT ON COLUMN sys_file.deleted_at IS '软删除时间';
|
||||
|
||||
-- ============================================================
|
||||
-- 8. 题库表 exam_bank
|
||||
-- ============================================================
|
||||
CREATE TABLE exam_bank (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
cover_image BIGINT,
|
||||
description TEXT,
|
||||
question_count INT NOT NULL DEFAULT 0,
|
||||
difficulty SMALLINT NOT NULL DEFAULT 1,
|
||||
status SMALLINT NOT NULL DEFAULT 1,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
CREATE INDEX idx_exam_bank_deleted ON exam_bank (deleted_at);
|
||||
COMMENT ON TABLE exam_bank IS '题库表';
|
||||
COMMENT ON COLUMN exam_bank.id IS '主键';
|
||||
COMMENT ON COLUMN exam_bank.name IS '题库名称';
|
||||
COMMENT ON COLUMN exam_bank.cover_image IS '封面图file_id';
|
||||
COMMENT ON COLUMN exam_bank.description IS '题库描述';
|
||||
COMMENT ON COLUMN exam_bank.question_count IS '题目数量';
|
||||
COMMENT ON COLUMN exam_bank.difficulty IS '难度:1简单 2中等 3困难';
|
||||
COMMENT ON COLUMN exam_bank.status IS '状态:0禁用 1启用';
|
||||
COMMENT ON COLUMN exam_bank.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN exam_bank.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN exam_bank.deleted_at IS '软删除时间';
|
||||
CREATE TRIGGER trg_exam_bank_updated BEFORE UPDATE ON exam_bank
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
-- ============================================================
|
||||
-- 9. 习题表 exam_question
|
||||
-- ============================================================
|
||||
CREATE TABLE exam_question (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
bank_id BIGINT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
options JSONB,
|
||||
question_type SMALLINT NOT NULL,
|
||||
answer VARCHAR(10) NOT NULL,
|
||||
explanation TEXT,
|
||||
difficulty SMALLINT NOT NULL DEFAULT 1,
|
||||
score SMALLINT NOT NULL DEFAULT 5,
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
used_count INT NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
CREATE INDEX idx_exam_question_bank ON exam_question (bank_id);
|
||||
CREATE INDEX idx_exam_question_type ON exam_question (question_type);
|
||||
CREATE INDEX idx_exam_question_deleted ON exam_question (deleted_at);
|
||||
COMMENT ON TABLE exam_question IS '习题表';
|
||||
COMMENT ON COLUMN exam_question.id IS '主键';
|
||||
COMMENT ON COLUMN exam_question.bank_id IS '所属题库ID';
|
||||
COMMENT ON COLUMN exam_question.content IS '题目内容';
|
||||
COMMENT ON COLUMN exam_question.options IS '选项数组([{"key":"A","val":"..."},...])';
|
||||
COMMENT ON COLUMN exam_question.question_type IS '题型:1单选 2多选 3判断';
|
||||
COMMENT ON COLUMN exam_question.answer IS '标准答案(如:A 或 AB)';
|
||||
COMMENT ON COLUMN exam_question.explanation IS '答案解析';
|
||||
COMMENT ON COLUMN exam_question.difficulty IS '难度:1简单 2中等 3困难';
|
||||
COMMENT ON COLUMN exam_question.score IS '分值';
|
||||
COMMENT ON COLUMN exam_question.sort_order IS '排序';
|
||||
COMMENT ON COLUMN exam_question.used_count IS '被使用次数';
|
||||
COMMENT ON COLUMN exam_question.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN exam_question.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN exam_question.deleted_at IS '软删除时间';
|
||||
CREATE TRIGGER trg_exam_question_updated BEFORE UPDATE ON exam_question
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
-- ============================================================
|
||||
-- 10. 课程表 course
|
||||
-- ============================================================
|
||||
CREATE TABLE course (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
tags VARCHAR(200),
|
||||
category SMALLINT,
|
||||
target_age VARCHAR(200),
|
||||
location VARCHAR(200),
|
||||
latitude VARCHAR(20),
|
||||
longitude VARCHAR(20),
|
||||
description TEXT,
|
||||
images VARCHAR(500),
|
||||
price NUMERIC(10, 2) NOT NULL,
|
||||
merchant_id BIGINT,
|
||||
status SMALLINT NOT NULL DEFAULT 1,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
CREATE INDEX idx_course_category ON course (category);
|
||||
CREATE INDEX idx_course_status ON course (status);
|
||||
CREATE INDEX idx_course_merchant ON course (merchant_id);
|
||||
CREATE INDEX idx_course_deleted ON course (deleted_at);
|
||||
COMMENT ON TABLE course IS '课程表';
|
||||
COMMENT ON COLUMN course.id IS '主键';
|
||||
COMMENT ON COLUMN course.name IS '课程名称';
|
||||
COMMENT ON COLUMN course.tags IS '标签编码,多选用分号拼接';
|
||||
COMMENT ON COLUMN course.category IS '分类编码:1认知启蒙 2技能进阶 3创新应用 4竞赛辅导';
|
||||
COMMENT ON COLUMN course.target_age IS '适合年龄描述';
|
||||
COMMENT ON COLUMN course.location IS '上课地点';
|
||||
COMMENT ON COLUMN course.latitude IS '纬度(字符串存储)';
|
||||
COMMENT ON COLUMN course.longitude IS '经度(字符串存储)';
|
||||
COMMENT ON COLUMN course.description IS '课程描述';
|
||||
COMMENT ON COLUMN course.images IS '课程图片file_id数组,多选用分号拼接';
|
||||
COMMENT ON COLUMN course.price IS '课程价格';
|
||||
COMMENT ON COLUMN course.merchant_id IS '所属商家ID';
|
||||
COMMENT ON COLUMN course.status IS '状态:0下架 1上架 2已满员';
|
||||
COMMENT ON COLUMN course.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN course.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN course.deleted_at IS '软删除时间';
|
||||
CREATE TRIGGER trg_course_updated BEFORE UPDATE ON course
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
-- ============================================================
|
||||
-- 11. 课程预约表 course_appointment
|
||||
-- ============================================================
|
||||
CREATE TABLE course_appointment (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL,
|
||||
course_id BIGINT NOT NULL,
|
||||
merchant_id BIGINT,
|
||||
appointment_date TIMESTAMP NOT NULL,
|
||||
person_count INT NOT NULL DEFAULT 1,
|
||||
contact_name VARCHAR(50),
|
||||
contact_phone VARCHAR(20),
|
||||
remark VARCHAR(200),
|
||||
status SMALLINT NOT NULL DEFAULT 1,
|
||||
amount NUMERIC(10, 2) NOT NULL DEFAULT 0.00,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
CREATE UNIQUE INDEX uk_course_appointment_user_course_date ON course_appointment (user_id, course_id, appointment_date);
|
||||
CREATE INDEX idx_course_appointment_course_status ON course_appointment (course_id, status);
|
||||
CREATE INDEX idx_course_appointment_merchant ON course_appointment (merchant_id);
|
||||
CREATE INDEX idx_course_appointment_deleted ON course_appointment (deleted_at);
|
||||
COMMENT ON TABLE course_appointment IS '课程预约表';
|
||||
COMMENT ON COLUMN course_appointment.id IS '主键';
|
||||
COMMENT ON COLUMN course_appointment.user_id IS '用户ID';
|
||||
COMMENT ON COLUMN course_appointment.course_id IS '课程ID';
|
||||
COMMENT ON COLUMN course_appointment.merchant_id IS '商家ID';
|
||||
COMMENT ON COLUMN course_appointment.appointment_date IS '预约时间';
|
||||
COMMENT ON COLUMN course_appointment.person_count IS '预约人数';
|
||||
COMMENT ON COLUMN course_appointment.contact_name IS '联系人姓名';
|
||||
COMMENT ON COLUMN course_appointment.contact_phone IS '联系人电话';
|
||||
COMMENT ON COLUMN course_appointment.remark IS '备注';
|
||||
COMMENT ON COLUMN course_appointment.status IS '状态:1已预约 2已确认 3已完成 4已取消';
|
||||
COMMENT ON COLUMN course_appointment.amount IS '支付金额';
|
||||
COMMENT ON COLUMN course_appointment.created_at IS '预约时间';
|
||||
COMMENT ON COLUMN course_appointment.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN course_appointment.deleted_at IS '软删除时间';
|
||||
CREATE TRIGGER trg_course_appointment_updated BEFORE UPDATE ON course_appointment
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
-- ============================================================
|
||||
-- 12. 省市区表 region
|
||||
-- 业务侧所有涉及 LBS 的字段(如 pilot.service_city_codes)均以本表 code 为值存储,
|
||||
-- 多选用分号拼接,查询时通过程序侧 split + IN 或 SQL 模糊匹配筛选
|
||||
-- ============================================================
|
||||
CREATE TABLE region (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
code VARCHAR(12) NOT NULL,
|
||||
name VARCHAR(50) NOT NULL,
|
||||
level SMALLINT NOT NULL,
|
||||
parent_code VARCHAR(12),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
CREATE UNIQUE INDEX uk_region_code ON region (code);
|
||||
CREATE INDEX idx_region_parent ON region (parent_code);
|
||||
CREATE INDEX idx_region_level ON region (level);
|
||||
CREATE INDEX idx_region_deleted ON region (deleted_at);
|
||||
COMMENT ON TABLE region IS '省市区表';
|
||||
COMMENT ON COLUMN region.id IS '主键';
|
||||
COMMENT ON COLUMN region.code IS '行政区划编码(6位数字字符串,如110000北京市)';
|
||||
COMMENT ON COLUMN region.name IS '区划名称';
|
||||
COMMENT ON COLUMN region.level IS '级别:1省 2市 3区县';
|
||||
COMMENT ON COLUMN region.parent_code IS '父级编码,省级为NULL';
|
||||
COMMENT ON COLUMN region.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN region.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN region.deleted_at IS '软删除时间';
|
||||
CREATE TRIGGER trg_region_updated BEFORE UPDATE ON region
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
-- ============================================================
|
||||
-- V2: 积分明细表 + 移除 task.premium_cost
|
||||
-- 设计说明:积分的每一笔收入/支出统一记录到 points_detail 流水表,
|
||||
-- 余额仍以 user.points 为准;任务表不再冗余存储 premium_cost,
|
||||
-- 优质任务的积分消耗以 points_detail 中事件类型=4 的流水为准。
|
||||
-- ============================================================
|
||||
|
||||
-- 1. 积分明细表(流水只增不改,继承 created_at,无 updated_at)
|
||||
CREATE TABLE points_detail (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL,
|
||||
change_type SMALLINT NOT NULL,
|
||||
event_type SMALLINT NOT NULL,
|
||||
points INT NOT NULL,
|
||||
related_id BIGINT,
|
||||
remark VARCHAR(200),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
CREATE INDEX idx_points_detail_user ON points_detail (user_id, created_at);
|
||||
COMMENT ON TABLE points_detail IS '积分明细表:记录用户每笔积分增扣流水';
|
||||
COMMENT ON COLUMN points_detail.id IS '主键';
|
||||
COMMENT ON COLUMN points_detail.user_id IS '用户ID,关联user.id';
|
||||
COMMENT ON COLUMN points_detail.change_type IS '变动方向:1收入 2支出';
|
||||
COMMENT ON COLUMN points_detail.event_type IS '事件类型:1发布任务 2完成任务 3邀请好友注册 4发布优质任务';
|
||||
COMMENT ON COLUMN points_detail.points IS '积分变动值,收入为正、支出为负';
|
||||
COMMENT ON COLUMN points_detail.related_id IS '关联业务ID(任务ID/被邀请用户ID等)';
|
||||
COMMENT ON COLUMN points_detail.remark IS '备注说明';
|
||||
COMMENT ON COLUMN points_detail.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN points_detail.deleted_at IS '软删除时间';
|
||||
|
||||
-- 2. 任务表移除冗余的优质任务积分消耗字段
|
||||
ALTER TABLE task DROP COLUMN premium_cost;
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,23 +0,0 @@
|
|||
-- =====================================================================
|
||||
-- V3: 飞手执照支持多本(执照类型/编号/照片 改为分号拼接的多值存储)
|
||||
-- 规约依据:AGENTS.md §4 "多选字段统一用 String 分号拼接,值为数字编码"
|
||||
-- 注意:dev 环境未启用 Flyway,需手动在 PG 执行本脚本
|
||||
-- =====================================================================
|
||||
|
||||
-- 执照类型编码:单本 SMALLINT → 多本拼接串(如 "1;2" 表示 AOPA+UTC)
|
||||
ALTER TABLE pilot
|
||||
ALTER COLUMN license_type TYPE VARCHAR(32) USING license_type::VARCHAR;
|
||||
|
||||
COMMENT ON COLUMN pilot.license_type IS 'CAAC执照类型编码,多本执照分号拼接(如 1;2 表示 AOPA+UTC):1 AOPA 2 UTC 3 ASFC';
|
||||
|
||||
-- 执照编号:多本编号按下标与 license_type 一一对应,分号拼接
|
||||
ALTER TABLE pilot
|
||||
ALTER COLUMN license_no TYPE VARCHAR(255);
|
||||
|
||||
COMMENT ON COLUMN pilot.license_no IS 'CAAC执照编号,多本执照分号拼接,与license_type按下标一一对应';
|
||||
|
||||
-- 执照照片 file_id:多张照片按下标对应,分号拼接(关联 sys_file.id)
|
||||
ALTER TABLE pilot
|
||||
ALTER COLUMN license_file_id TYPE VARCHAR(255) USING license_file_id::VARCHAR;
|
||||
|
||||
COMMENT ON COLUMN pilot.license_file_id IS '执照照片file_id,多张分号拼接(如 12;13),与license_type按下标一一对应,关联sys_file.id';
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
-- V4: 飞手新增服务类型字段
|
||||
-- 服务类型为飞手能力属性(1植保 2吊运 3航拍 4巡检 5清洗 6表演 7测绘),多选分号拼接;
|
||||
-- 商家认证表单已移除服务类型录入(历史列保留不再使用,避免破坏存量数据)。
|
||||
|
||||
ALTER TABLE pilot
|
||||
ADD COLUMN service_types VARCHAR(200) NULL;
|
||||
|
||||
COMMENT ON COLUMN pilot.service_types IS '服务类型编码,多选分号拼接:1植保 2吊运 3航拍 4巡检 5清洗 6表演 7测绘';
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
-- =====================================================================
|
||||
-- V5: 飞手执照新增获证日期字段(多本执照分号拼接,按下标对齐)
|
||||
-- 规约依据:AGENTS.md §4 "多选字段统一用 String 分号拼接"
|
||||
-- 存储格式:yyyy-MM-dd(如 "2023-06-15"),多本执照如 "2023-06-15;2024-03-20"
|
||||
-- 注意:dev 环境未启用 Flyway,需手动在 PG 执行本脚本
|
||||
-- =====================================================================
|
||||
|
||||
ALTER TABLE pilot
|
||||
ADD COLUMN license_date VARCHAR(500);
|
||||
|
||||
COMMENT ON COLUMN pilot.license_date IS '执照获证日期,多本执照分号拼接(如 2023-06-15;2024-03-20),与license_type按下标一一对应,格式yyyy-MM-dd';
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
-- =====================================================================
|
||||
-- V6: 飞手执照独立表 pilot_license(替代 pilot 表 4 个分号拼接字段)
|
||||
-- 架构升级:多本执照从 String 分号拼接 → 独立表一对多关系
|
||||
-- 影响范围:Entity / DTO / VO / CertServiceImpl / HomeServiceImpl
|
||||
-- 注意:dev 环境未启用 Flyway,需手动在 PG 执行本脚本
|
||||
-- =====================================================================
|
||||
|
||||
-- 1. 建表:继承项目审计字段规约(id BIGSERIAL + created_at/updated_at/deleted_at)
|
||||
CREATE TABLE pilot_license (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
pilot_id BIGINT NOT NULL REFERENCES pilot(id),
|
||||
license_type SMALLINT NOT NULL,
|
||||
license_no VARCHAR(50),
|
||||
license_file_id BIGINT,
|
||||
license_date VARCHAR(10),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
deleted_at TIMESTAMP,
|
||||
CONSTRAINT ck_license_type CHECK (license_type IN (1, 2, 3, 4))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE pilot_license IS '飞手执照表(多本执照一对多)';
|
||||
COMMENT ON COLUMN pilot_license.pilot_id IS '关联飞手ID(pilot.id)';
|
||||
COMMENT ON COLUMN pilot_license.license_type IS '执照类型编码:1 AOPA 2 UTC 3 ASFC 4 CAAC';
|
||||
COMMENT ON COLUMN pilot_license.license_no IS '执照编号';
|
||||
COMMENT ON COLUMN pilot_license.license_file_id IS '执照照片file_id(sys_file.id)';
|
||||
COMMENT ON COLUMN pilot_license.license_date IS '获证日期,格式 yyyy-MM-dd';
|
||||
|
||||
CREATE INDEX idx_pilot_license_pilot ON pilot_license(pilot_id);
|
||||
|
||||
-- 2. 数据迁移:从 pilot 表 4 个分号串按下标对齐插入已有执照
|
||||
-- PG 原生 string_to_array + unnest + WITH ORDINALITY 实现"并行数组按下标对齐"
|
||||
INSERT INTO pilot_license (pilot_id, license_type, license_no, license_file_id, license_date)
|
||||
SELECT
|
||||
p.id,
|
||||
types_arr.elem::SMALLINT,
|
||||
nos_arr.elem,
|
||||
file_arr.elem::BIGINT,
|
||||
date_arr.elem
|
||||
FROM pilot p
|
||||
CROSS JOIN LATERAL unnest(string_to_array(COALESCE(p.license_type, ''), ';')) WITH ORDINALITY AS types_arr(elem, ord)
|
||||
LEFT JOIN LATERAL unnest(string_to_array(COALESCE(p.license_no, ''), ';')) WITH ORDINALITY AS nos_arr (elem, ord) ON nos_arr.ord = types_arr.ord AND nos_arr.elem <> ''
|
||||
LEFT JOIN LATERAL unnest(string_to_array(COALESCE(p.license_file_id, ''), ';')) WITH ORDINALITY AS file_arr(elem, ord) ON file_arr.ord = types_arr.ord AND file_arr.elem <> ''
|
||||
LEFT JOIN LATERAL unnest(string_to_array(COALESCE(p.license_date, ''), ';')) WITH ORDINALITY AS date_arr(elem, ord) ON date_arr.ord = types_arr.ord AND date_arr.elem <> ''
|
||||
WHERE COALESCE(p.license_type, '') <> '';
|
||||
|
||||
-- 3. 验证迁移结果(执行完本脚本后可选运行)
|
||||
-- SELECT pilot_id, COUNT(*) AS license_count FROM pilot_license GROUP BY pilot_id;
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
-- =====================================================================
|
||||
-- V7: 删除 Pilot / Merchant 表的 order_count 统计字段
|
||||
-- 规约依据:AGENTS.md §2.6 + §4 — 统计/派生字段禁止定义在 PO/Entity 中
|
||||
-- 排序改为 Repository native SQL JOIN task COUNT 实时聚合
|
||||
-- =====================================================================
|
||||
|
||||
ALTER TABLE pilot DROP COLUMN IF EXISTS order_count;
|
||||
ALTER TABLE merchant DROP COLUMN IF EXISTS order_count;
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
-- =====================================================================
|
||||
-- V8: course 表新增"排课 / 宣传图 / 联系人"字段(Web 管理端研学课程管理)
|
||||
-- 背景:
|
||||
-- Web 管理端需要维护课程的排课信息与咨询联系人,小程序端课程详情同步展示。
|
||||
-- 排课支持两种互斥方式(schedule_type 区分):
|
||||
-- 1=每周重复:每周固定星期几上课,取值存 schedule_week_days(1=周一 ... 7=周日,分号拼接)
|
||||
-- 2=日期排课:指定具体日期上课,取值存 schedule_dates(yyyy-MM-dd,分号拼接)
|
||||
-- 遵循项目多选字段规约:多值统一 String + 英文分号拼接,禁止 jsonb(简单标量多值)。
|
||||
-- =====================================================================
|
||||
|
||||
-- 排课方式:1每周重复 2日期排课(必填,历史数据默认"每周重复")
|
||||
ALTER TABLE course ADD COLUMN schedule_type SMALLINT NOT NULL DEFAULT 1;
|
||||
|
||||
-- 每周上课星期编码串(schedule_type=1 时有值,如 "1;3;5" 表示周一/周三/周五)
|
||||
ALTER TABLE course ADD COLUMN schedule_week_days VARCHAR(20);
|
||||
|
||||
-- 排课日期串(schedule_type=2 时有值,如 "2026-09-10;2026-09-12")
|
||||
ALTER TABLE course ADD COLUMN schedule_dates VARCHAR(500);
|
||||
|
||||
-- 课程宣传图片文件ID(关联 sys_file.id,小程序端课程卡片/详情头图)
|
||||
ALTER TABLE course ADD COLUMN cover_image_id BIGINT;
|
||||
|
||||
-- 课程咨询联系人姓名
|
||||
ALTER TABLE course ADD COLUMN contact_name VARCHAR(50);
|
||||
|
||||
-- 课程咨询联系电话
|
||||
ALTER TABLE course ADD COLUMN contact_phone VARCHAR(20);
|
||||
|
||||
COMMENT ON COLUMN course.schedule_type IS '排课方式:1每周重复 2日期排课';
|
||||
COMMENT ON COLUMN course.schedule_week_days IS '每周上课星期编码串(1=周一...7=周日,分号拼接,schedule_type=1 时有值)';
|
||||
COMMENT ON COLUMN course.schedule_dates IS '排课日期串(yyyy-MM-dd 分号拼接,schedule_type=2 时有值)';
|
||||
COMMENT ON COLUMN course.cover_image_id IS '课程宣传图片文件ID(关联 sys_file.id)';
|
||||
COMMENT ON COLUMN course.contact_name IS '课程咨询联系人姓名';
|
||||
COMMENT ON COLUMN course.contact_phone IS '课程咨询联系电话';
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
-- ============================================================
|
||||
-- V9 —— 首页轮播图表 app_banner
|
||||
-- 承载小程序首页轮播 Banner 的运营配置,支持图片上传、跳转链接、排序、启停
|
||||
-- ============================================================
|
||||
CREATE TABLE app_banner (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
title VARCHAR(100) NOT NULL,
|
||||
subtitle VARCHAR(200),
|
||||
image_file_id BIGINT,
|
||||
link_type VARCHAR(32),
|
||||
link_url VARCHAR(500),
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
status SMALLINT NOT NULL DEFAULT 1,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_app_banner_status ON app_banner (status);
|
||||
CREATE INDEX idx_app_banner_sort ON app_banner (sort_order);
|
||||
CREATE INDEX idx_app_banner_deleted ON app_banner (deleted_at);
|
||||
|
||||
COMMENT ON TABLE app_banner IS '首页轮播图表';
|
||||
COMMENT ON COLUMN app_banner.id IS '主键';
|
||||
COMMENT ON COLUMN app_banner.title IS '轮播图标题';
|
||||
COMMENT ON COLUMN app_banner.subtitle IS '轮播图副标题/描述';
|
||||
COMMENT ON COLUMN app_banner.image_file_id IS '轮播图图片file_id(关联 sys_file.id)';
|
||||
COMMENT ON COLUMN app_banner.link_type IS '跳转类型:caac/performance/merchant/pilot/course/custom';
|
||||
COMMENT ON COLUMN app_banner.link_url IS '自定义跳转链接(link_type=custom 时使用)';
|
||||
COMMENT ON COLUMN app_banner.sort_order IS '排序值,升序,值越小越靠前';
|
||||
COMMENT ON COLUMN app_banner.status IS '状态:0隐藏 1显示';
|
||||
COMMENT ON COLUMN app_banner.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN app_banner.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN app_banner.deleted_at IS '软删除时间';
|
||||
|
||||
CREATE TRIGGER trg_app_banner_updated BEFORE UPDATE ON app_banner
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
-- ------------------------------------------------------------
|
||||
-- 初始化 3 条轮播图数据(对应小程序现有的硬编码 bannerList)
|
||||
-- image_file_id 暂设 NULL,后续通过 Web 管理端上传真实图片补全
|
||||
-- ------------------------------------------------------------
|
||||
INSERT INTO app_banner (title, subtitle, link_type, sort_order, status) VALUES
|
||||
('CAAC 报名通道开启', '超250g无人机须实名,操控员须持证', 'caac', 1, 1),
|
||||
('无人机表演专场', '高客单商业订单,专业飞手接单', 'performance', 2, 1),
|
||||
('实力商家招商入驻', '开放聚合生态,精准流量分发', 'merchant', 3, 1);
|
||||
Loading…
Reference in New Issue
Block a user