-- ============================================ -- 1. member_user 表(会员表) -- ============================================ -- Step 1: 删除已存在的表(如果需要重建) -- DROP TABLE IF EXISTS member_user CASCADE; -- Step 2: 创建 member_user 表 CREATE TABLE IF NOT EXISTS member_user ( -- ========== 主键和基础字段(来自BaseEntity)========== id BIGSERIAL PRIMARY KEY, -- 主键ID,自增 created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间 updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间 -- ========== 会员核心字段 ========== member_no VARCHAR(50) NOT NULL UNIQUE, -- 会员编号(唯一) nickname VARCHAR(100), -- 昵称 phone VARCHAR(255), -- 手机号(AES加密存储) gender INTEGER DEFAULT 0, -- 性别:0-未知,1-男,2-女 birthday DATE, -- 生日 address VARCHAR(500), -- 地址 avatar VARCHAR(500), -- 头像URL subscribed BOOLEAN DEFAULT FALSE, -- 是否关注服务号 last_login_at TIMESTAMP, -- 最后登录时间 -- ========== 微信相关字段 ========== union_id VARCHAR(100), -- 微信UnionID(跨应用唯一标识) miniapp_open_id VARCHAR(100), -- 小程序OpenID official_open_id VARCHAR(100), -- 服务号OpenID -- ========== 软删除字段 ========== is_deleted BOOLEAN DEFAULT FALSE -- 是否删除(软删除标记) ); -- Step 3: 创建索引 -- 会员编号索引(唯一索引,加速查询) CREATE UNIQUE INDEX IF NOT EXISTS idx_member_user_member_no ON member_user(member_no); -- UnionID索引(加速跨平台用户查找) CREATE INDEX IF NOT EXISTS idx_member_user_union_id ON member_user(union_id); -- 小程序OpenID索引(加速小程序登录查询) CREATE INDEX IF NOT EXISTS idx_member_user_miniapp_openid ON member_user(miniapp_open_id); -- 服务号OpenID索引(加速服务号事件处理) CREATE INDEX IF NOT EXISTS idx_member_user_official_openid ON member_user(official_open_id); -- 手机号索引(加速手机号查询和去重) CREATE INDEX IF NOT EXISTS idx_member_user_phone ON member_user(phone); -- 软删除索引(加速查询未删除的记录) CREATE INDEX IF NOT EXISTS idx_member_user_is_deleted ON member_user(is_deleted); -- Step 4: 添加注释 COMMENT ON TABLE member_user IS '会员表'; COMMENT ON COLUMN member_user.id IS '主键ID'; COMMENT ON COLUMN member_user.created_at IS '创建时间'; COMMENT ON COLUMN member_user.updated_at IS '更新时间'; COMMENT ON COLUMN member_user.member_no IS '会员编号(唯一,格式:MEM + 8位随机字符)'; COMMENT ON COLUMN member_user.nickname IS '昵称'; COMMENT ON COLUMN member_user.phone IS '手机号(AES-128-CBC加密存储)'; COMMENT ON COLUMN member_user.gender IS '性别:0-未知,1-男,2-女'; COMMENT ON COLUMN member_user.birthday IS '生日'; COMMENT ON COLUMN member_user.address IS '地址'; COMMENT ON COLUMN member_user.avatar IS '头像URL'; COMMENT ON COLUMN member_user.subscribed IS '是否关注服务号:true-已关注,false-未关注'; COMMENT ON COLUMN member_user.last_login_at IS '最后登录时间'; COMMENT ON COLUMN member_user.union_id IS '微信UnionID(用户在开放平台的唯一标识,跨应用相同)'; COMMENT ON COLUMN member_user.miniapp_open_id IS '小程序OpenID(用户在当前小程序的唯一标识)'; COMMENT ON COLUMN member_user.official_open_id IS '服务号OpenID(用户在当前服务号的唯一标识)'; COMMENT ON COLUMN member_user.is_deleted IS '是否删除(软删除标记):false-正常,true-已删除'; -- ============================================ -- 2. wechat_user 表(微信用户表) -- ============================================ -- Step 1: 删除已存在的表(如果需要重建) -- DROP TABLE IF EXISTS wechat_user CASCADE; -- Step 2: 创建 wechat_user 表 CREATE TABLE IF NOT EXISTS wechat_user ( -- ========== 主键和基础字段(来自BaseEntity)========== id BIGSERIAL PRIMARY KEY, -- 主键ID,自增 created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间 updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间 -- ========== 关联字段 ========== member_id BIGINT NOT NULL, -- 会员ID(外键) -- ========== 微信标识字段 ========== union_id VARCHAR(100), -- 微信UnionID miniapp_openid VARCHAR(100), -- 小程序OpenID mp_openid VARCHAR(100), -- 服务号OpenID -- ========== 关注状态字段 ========== is_subscribed BOOLEAN DEFAULT FALSE, -- 是否关注服务号 subscribe_time TIMESTAMP, -- 首次关注时间 unsubscribe_time TIMESTAMP -- 最后一次取消关注时间 ); -- Step 3: 创建外键约束 ALTER TABLE wechat_user ADD CONSTRAINT fk_wechat_user_member FOREIGN KEY (member_id) REFERENCES member_user(id) ON DELETE CASCADE; -- Step 4: 创建索引 -- UnionID索引(加速跨平台用户查找) CREATE INDEX IF NOT EXISTS idx_wechat_user_union_id ON wechat_user(union_id); -- 小程序OpenID索引(加速小程序登录查询) CREATE INDEX IF NOT EXISTS idx_wechat_user_miniapp_openid ON wechat_user(miniapp_openid); -- 服务号OpenID索引(加速服务号事件处理) CREATE INDEX IF NOT EXISTS idx_wechat_user_mp_openid ON wechat_user(mp_openid); -- 会员ID索引(加速关联查询) CREATE INDEX IF NOT EXISTS idx_wechat_user_member_id ON wechat_user(member_id); -- Step 5: 添加注释 COMMENT ON TABLE wechat_user IS '微信用户表'; COMMENT ON COLUMN wechat_user.id IS '主键ID'; COMMENT ON COLUMN wechat_user.created_at IS '创建时间'; COMMENT ON COLUMN wechat_user.updated_at IS '更新时间'; COMMENT ON COLUMN wechat_user.member_id IS '会员ID(关联 member_user 表的 id 字段)'; COMMENT ON COLUMN wechat_user.union_id IS '微信UnionID(用户在开放平台的唯一标识)'; COMMENT ON COLUMN wechat_user.miniapp_openid IS '小程序OpenID(用户在当前小程序的唯一标识)'; COMMENT ON COLUMN wechat_user.mp_openid IS '服务号OpenID(用户在当前服务号的唯一标识)'; COMMENT ON COLUMN wechat_user.is_subscribed IS '是否关注服务号:true-已关注,false-未关注'; COMMENT ON COLUMN wechat_user.subscribe_time IS '首次关注时间'; COMMENT ON COLUMN wechat_user.unsubscribe_time IS '最后一次取消关注时间'; -- ============================================ -- 3. member_card 表(会员卡类型表) -- ============================================ CREATE TABLE IF NOT EXISTS member_card ( id BIGSERIAL PRIMARY KEY, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, deleted_at TIMESTAMP, member_card_id BIGSERIAL, member_card_name VARCHAR(100) NOT NULL, member_card_type VARCHAR(20) NOT NULL, member_card_price DECIMAL(10, 2) NOT NULL, member_card_validity_days INTEGER, member_card_total_times INTEGER, member_card_amount DECIMAL(10, 2), member_card_status INTEGER DEFAULT 1 NOT NULL, extra_config TEXT DEFAULT '{}' ); COMMENT ON TABLE member_card IS '会员卡类型表'; COMMENT ON COLUMN member_card.member_card_id IS '会员卡ID'; COMMENT ON COLUMN member_card.member_card_name IS '会员卡名称'; COMMENT ON COLUMN member_card.member_card_type IS '会员卡类型:TIME_CARD-时长卡, COUNT_CARD-次卡, STORED_VALUE_CARD-储值卡'; COMMENT ON COLUMN member_card.member_card_price IS '会员卡价格'; COMMENT ON COLUMN member_card.member_card_validity_days IS '有效天数(时长卡用)'; COMMENT ON COLUMN member_card.member_card_total_times IS '总次数(次卡用)'; COMMENT ON COLUMN member_card.member_card_amount IS '面额(储值卡用)'; COMMENT ON COLUMN member_card.member_card_status IS '状态:0-下架, 1-上架'; COMMENT ON COLUMN member_card.extra_config IS '扩展配置(JSON格式)'; -- ============================================ -- 4. member_card_record 表(会员卡记录表) -- ============================================ CREATE TABLE IF NOT EXISTS member_card_record ( id BIGSERIAL PRIMARY KEY, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, deleted_at TIMESTAMP, member_card_record_id BIGSERIAL, member_id BIGINT NOT NULL, member_card_id BIGINT NOT NULL, status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE', remaining_times INTEGER DEFAULT 0, remaining_amount DECIMAL(10, 2) DEFAULT 0.00, expire_time TIMESTAMP, source_order_id BIGINT, purchase_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, version INTEGER DEFAULT 0 NOT NULL, card_composition TEXT ); -- 索引优化 CREATE INDEX IF NOT EXISTS idx_member_card_record_member_id ON member_card_record(member_id); CREATE INDEX IF NOT EXISTS idx_member_card_record_status ON member_card_record(status); CREATE INDEX IF NOT EXISTS idx_member_card_record_expire_time ON member_card_record(expire_time); CREATE INDEX IF NOT EXISTS idx_member_card_record_member_status ON member_card_record(member_id, status); CREATE INDEX IF NOT EXISTS idx_member_card_record_status_expire ON member_card_record(status, expire_time) WHERE status = 'ACTIVE'; COMMENT ON TABLE member_card_record IS '会员卡记录表(会员持有的卡)'; COMMENT ON COLUMN member_card_record.member_card_record_id IS '会员卡记录ID'; COMMENT ON COLUMN member_card_record.member_id IS '会员ID'; COMMENT ON COLUMN member_card_record.member_card_id IS '会员卡类型ID'; COMMENT ON COLUMN member_card_record.status IS '状态:ACTIVE-有效, USED_UP-用完, EXPIRED-过期, REFUNDED-已退款'; COMMENT ON COLUMN member_card_record.remaining_times IS '剩余次数'; COMMENT ON COLUMN member_card_record.remaining_amount IS '剩余金额'; COMMENT ON COLUMN member_card_record.expire_time IS '到期时间'; COMMENT ON COLUMN member_card_record.source_order_id IS '来源订单ID'; COMMENT ON COLUMN member_card_record.purchase_time IS '购买时间'; COMMENT ON COLUMN member_card_record.version IS '乐观锁版本号'; COMMENT ON COLUMN member_card_record.card_composition IS '卡片组成(JSON格式,用于组合卡)'; -- ============================================ -- 5. member_card_transactions 表(会员卡交易流水表) -- ============================================ CREATE TABLE IF NOT EXISTS member_card_transactions ( id BIGSERIAL PRIMARY KEY, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, member_card_record_id BIGINT NOT NULL, member_id BIGINT NOT NULL, member_card_id BIGINT NOT NULL, operation_type VARCHAR(20) NOT NULL, change_amount INTEGER DEFAULT 0, change_balance DECIMAL(10, 2) DEFAULT 0.00, after_remaining_count INTEGER DEFAULT 0, after_remaining_balance DECIMAL(10, 2) DEFAULT 0.00, related_biz_type VARCHAR(20), source_order_id BIGINT, remark VARCHAR(500), is_archived BOOLEAN DEFAULT FALSE, archived_at TIMESTAMP ); -- 索引优化 CREATE INDEX IF NOT EXISTS idx_member_card_transactions_member_id ON member_card_transactions(member_id); CREATE INDEX IF NOT EXISTS idx_member_card_transactions_record_id ON member_card_transactions(member_card_record_id); CREATE INDEX IF NOT EXISTS idx_member_card_transactions_created_at ON member_card_transactions(created_at); CREATE INDEX IF NOT EXISTS idx_member_card_transactions_member_type_time ON member_card_transactions(member_id, operation_type, created_at); COMMENT ON TABLE member_card_transactions IS '会员卡交易流水表'; COMMENT ON COLUMN member_card_transactions.operation_type IS '操作类型:PURCHASE-购买, DEDUCT-扣次/扣费, RENEW-续费, REFUND-退款, EXPIRE-过期'; COMMENT ON COLUMN member_card_transactions.change_amount IS '变动次数'; COMMENT ON COLUMN member_card_transactions.change_balance IS '变动金额'; COMMENT ON COLUMN member_card_transactions.after_remaining_count IS '变动后剩余次数'; COMMENT ON COLUMN member_card_transactions.after_remaining_balance IS '变动后剩余金额'; COMMENT ON COLUMN member_card_transactions.related_biz_type IS '关联业务类型:GROUP_CLASS-团课, PT_CLASS-私教, CHECK_IN-签到'; COMMENT ON COLUMN member_card_transactions.is_archived IS '是否已归档'; COMMENT ON COLUMN member_card_transactions.archived_at IS '归档时间'; -- ============================================ -- 6. refund_application 表(退款申请表) -- ============================================ CREATE TABLE IF NOT EXISTS refund_application ( id BIGSERIAL PRIMARY KEY, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, deleted_at TIMESTAMP, record_id BIGINT NOT NULL, member_id BIGINT NOT NULL, status VARCHAR(20) NOT NULL DEFAULT 'PENDING', reason VARCHAR(500), apply_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, audit_time TIMESTAMP, auditor_id BIGINT, audit_remark VARCHAR(500), refund_amount DECIMAL(10, 2) ); CREATE INDEX IF NOT EXISTS idx_refund_application_record_id ON refund_application(record_id); CREATE INDEX IF NOT EXISTS idx_refund_application_status ON refund_application(status); COMMENT ON TABLE refund_application IS '退款申请表'; COMMENT ON COLUMN refund_application.status IS '状态:PENDING-待审核, APPROVED-已批准, REJECTED-已拒绝, PROCESSING-处理中, SUCCESS-成功, FAILED-失败';