Files
banban/mini-program/database/init.sql
stu2not 82c15b6abc 支持已绑定设备追加 NFC 卡
- 新增已绑定设备追加卡会话和小程序入口

- 允许同设备多张 active 卡,保留 card_uuid 唯一并补齐老库迁移

- 收紧未知卡自动绑定和跨设备卡复用

验证:talkingq-url/.venv/bin/python -m pytest tests;compileall;npm run build:weapp
2026-06-04 09:55:35 +08:00

233 lines
8.7 KiB
SQL

-- Current MySQL schema for mini-program
-- Deprecated for shared deployments.
-- If `mini-program` and `talkingq-url` run on the same MySQL instance,
-- use `database/talkingq_shared_schema.sql` to initialize the single
-- source-of-truth database `talkingq`.
--
-- This file is kept only for legacy isolated development of mini-program.
CREATE DATABASE IF NOT EXISTS mini_program
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
USE mini_program;
-- parents
CREATE TABLE IF NOT EXISTS parents (
user_id BIGINT PRIMARY KEY AUTO_INCREMENT,
openid VARCHAR(64) UNIQUE NOT NULL,
unionid VARCHAR(64),
nickname VARCHAR(64),
avatar_url VARCHAR(255),
avatar_file_key VARCHAR(255),
phone VARCHAR(20),
status TINYINT NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE INDEX idx_parents_unionid ON parents(unionid);
CREATE INDEX idx_parents_phone ON parents(phone);
-- children
CREATE TABLE IF NOT EXISTS children (
child_id BIGINT PRIMARY KEY AUTO_INCREMENT,
child_name VARCHAR(32) NOT NULL,
child_gender TINYINT NOT NULL DEFAULT 2,
child_birthday DATE,
status TINYINT NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- parent_child_relations
CREATE TABLE IF NOT EXISTS parent_child_relations (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
child_id BIGINT NOT NULL,
relation_type TINYINT NOT NULL DEFAULT 9,
is_primary TINYINT(1) NOT NULL DEFAULT 0,
status TINYINT NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT uq_user_child UNIQUE (user_id, child_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE INDEX idx_pcr_user_id ON parent_child_relations(user_id);
CREATE INDEX idx_pcr_child_id ON parent_child_relations(child_id);
-- device_bindings
CREATE TABLE IF NOT EXISTS device_bindings (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
device_id VARCHAR(64) NOT NULL,
owner_user_id BIGINT NOT NULL,
child_id BIGINT,
status TINYINT NOT NULL DEFAULT 1,
bound_at DATETIME NOT NULL,
unbound_at DATETIME,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT uq_device_binding_device UNIQUE (device_id),
CONSTRAINT uq_device_binding_child UNIQUE (child_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE INDEX idx_device_bindings_owner_user_id ON device_bindings(owner_user_id);
-- device_bind_sessions
CREATE TABLE IF NOT EXISTS device_bind_sessions (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
bind_token CHAR(36) UNIQUE NOT NULL,
device_id VARCHAR(64) NOT NULL,
initiator_user_id BIGINT NOT NULL,
target_child_id BIGINT,
challenge_code_hash CHAR(64),
challenge_set_at DATETIME,
expires_at DATETIME NOT NULL,
max_attempt_count TINYINT UNSIGNED NOT NULL DEFAULT 5,
attempt_count TINYINT UNSIGNED NOT NULL DEFAULT 0,
status TINYINT NOT NULL DEFAULT 1,
bind_mode TINYINT NOT NULL DEFAULT 1,
card_uuid VARCHAR(64),
confirmed_at DATETIME,
consumed_at DATETIME,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- device_bind_history
CREATE TABLE IF NOT EXISTS device_bind_history (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
device_id VARCHAR(64) NOT NULL,
child_id BIGINT,
bound_by_user_id BIGINT NOT NULL,
unbound_by_user_id BIGINT,
bind_source TINYINT NOT NULL DEFAULT 1,
bound_at DATETIME NOT NULL,
unbound_at DATETIME,
unbind_reason VARCHAR(191),
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- cards
CREATE TABLE IF NOT EXISTS cards (
card_id BIGINT PRIMARY KEY AUTO_INCREMENT,
card_uuid VARCHAR(64) UNIQUE NOT NULL,
device_id VARCHAR(64),
card_name VARCHAR(64),
status TINYINT NOT NULL DEFAULT 0,
total_swaps INT NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- device_settings
CREATE TABLE IF NOT EXISTS device_settings (
setting_id BIGINT PRIMARY KEY AUTO_INCREMENT,
device_id VARCHAR(64) NOT NULL UNIQUE,
sleep_mode TINYINT NOT NULL DEFAULT 0,
disable_time_start TIME,
disable_time_end TIME,
timezone VARCHAR(32) NOT NULL DEFAULT 'Asia/Shanghai',
volume TINYINT UNSIGNED,
brightness TINYINT UNSIGNED,
disable_weekdays VARCHAR(32),
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- im_conversations
CREATE TABLE IF NOT EXISTS im_conversations (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
conversation_type TINYINT UNSIGNED NOT NULL,
participant_a_type TINYINT UNSIGNED NOT NULL,
participant_a_id VARCHAR(64) NOT NULL,
participant_b_type TINYINT UNSIGNED NOT NULL,
participant_b_id VARCHAR(64) NOT NULL,
pair_key VARCHAR(191) NOT NULL,
status TINYINT NOT NULL DEFAULT 1,
last_seq BIGINT UNSIGNED NOT NULL DEFAULT 0,
message_count BIGINT UNSIGNED NOT NULL DEFAULT 0,
last_message_preview VARCHAR(255),
last_message_at DATETIME,
ext_json JSON,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT uq_conv_type_pair UNIQUE (conversation_type, pair_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE INDEX idx_im_conv_participant_a ON im_conversations(participant_a_type, participant_a_id);
CREATE INDEX idx_im_conv_participant_b ON im_conversations(participant_b_type, participant_b_id);
CREATE INDEX idx_im_conv_last_message_at ON im_conversations(last_message_at);
-- im_messages
CREATE TABLE IF NOT EXISTS im_messages (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
conversation_id BIGINT UNSIGNED NOT NULL,
seq BIGINT UNSIGNED NOT NULL,
sender_type TINYINT UNSIGNED NOT NULL,
sender_id VARCHAR(64) NOT NULL,
receiver_type TINYINT UNSIGNED NOT NULL,
receiver_id VARCHAR(64) NOT NULL,
content_type TINYINT UNSIGNED NOT NULL,
content_text MEDIUMTEXT,
content_json JSON,
media_file_key VARCHAR(255),
media_duration_ms INT UNSIGNED,
media_mime_type VARCHAR(64),
media_size_bytes BIGINT UNSIGNED,
media_transcript_text TEXT,
client_msg_id VARCHAR(64),
sender_name_snapshot VARCHAR(64),
sender_avatar_snapshot VARCHAR(255),
receiver_name_snapshot VARCHAR(64),
receiver_avatar_snapshot VARCHAR(255),
ext_json JSON,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at DATETIME,
CONSTRAINT uq_im_msg_conv_seq UNIQUE (conversation_id, seq),
CONSTRAINT uq_im_msg_client UNIQUE (conversation_id, client_msg_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE INDEX idx_im_msg_sender ON im_messages(sender_type, sender_id, created_at);
CREATE INDEX idx_im_msg_receiver ON im_messages(receiver_type, receiver_id, created_at);
-- child_location_current
CREATE TABLE IF NOT EXISTS child_location_current (
child_id BIGINT UNSIGNED PRIMARY KEY,
device_id VARCHAR(64) NOT NULL,
coord_type VARCHAR(16) NOT NULL DEFAULT 'gcj02',
lat DECIMAL(10,7) NOT NULL,
lng DECIMAL(10,7) NOT NULL,
accuracy_m INT UNSIGNED,
altitude_m DECIMAL(8,2),
speed_mps DECIMAL(8,2),
heading_deg SMALLINT UNSIGNED,
source TINYINT UNSIGNED NOT NULL,
battery_pct TINYINT UNSIGNED,
device_time DATETIME NOT NULL,
server_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- child_location_history
CREATE TABLE IF NOT EXISTS child_location_history (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
child_id BIGINT UNSIGNED NOT NULL,
device_id VARCHAR(64) NOT NULL,
coord_type VARCHAR(16) NOT NULL DEFAULT 'gcj02',
lat DECIMAL(10,7) NOT NULL,
lng DECIMAL(10,7) NOT NULL,
accuracy_m INT UNSIGNED,
altitude_m DECIMAL(8,2),
speed_mps DECIMAL(8,2),
heading_deg SMALLINT UNSIGNED,
source TINYINT UNSIGNED NOT NULL,
battery_pct TINYINT UNSIGNED,
device_time DATETIME NOT NULL,
server_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE INDEX idx_child_loc_hist_child ON child_location_history(child_id, created_at);