diff --git a/README.md b/README.md index dfbd58b..b7f1b13 100644 --- a/README.md +++ b/README.md @@ -27,9 +27,7 @@ ```bash docker compose -f deploy/docker-compose.dev.yml up -d -for file in backend/migrations/*.sql; do - docker exec -i hfb-mysql mysql -uhfb -psecret hfb_sys < "$file" -done +docker exec -i hfb-mysql mysql -uhfb -psecret hfb_sys < backend/migrations/000001_init.sql cd backend cp .env.example .env diff --git a/backend/migrations/000001_init.sql b/backend/migrations/000001_init.sql index dfcc693..6c36e93 100644 --- a/backend/migrations/000001_init.sql +++ b/backend/migrations/000001_init.sql @@ -1,6 +1,6 @@ -- ============================================ -- 数据库初始化脚本 --- 包含所有表结构定义 +-- 包含所有表结构和基础数据 -- ============================================ SET NAMES utf8mb4; @@ -10,7 +10,7 @@ SET FOREIGN_KEY_CHECKS = 0; -- 用户相关表 -- ------------------------------------------- -CREATE TABLE users ( +CREATE TABLE IF NOT EXISTS users ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, phone VARCHAR(32) NOT NULL, nickname VARCHAR(64) NOT NULL DEFAULT '', @@ -25,7 +25,7 @@ CREATE TABLE users ( UNIQUE KEY uk_users_phone (phone) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -CREATE TABLE user_realname ( +CREATE TABLE IF NOT EXISTS user_realname ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, user_id BIGINT UNSIGNED NOT NULL, provider VARCHAR(32) NOT NULL, @@ -45,7 +45,7 @@ CREATE TABLE user_realname ( -- 游戏账号和商品表 -- ------------------------------------------- -CREATE TABLE game_accounts ( +CREATE TABLE IF NOT EXISTS game_accounts ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, owner_id BIGINT UNSIGNED NOT NULL, game_name VARCHAR(64) NOT NULL DEFAULT 'delta_force', @@ -65,7 +65,7 @@ CREATE TABLE game_accounts ( KEY idx_game_accounts_filter (game_name, server_region, login_platform) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -CREATE TABLE rental_listings ( +CREATE TABLE IF NOT EXISTS rental_listings ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, account_id BIGINT UNSIGNED NOT NULL, owner_id BIGINT UNSIGNED NOT NULL, @@ -87,7 +87,7 @@ CREATE TABLE rental_listings ( -- 订单相关表 -- ------------------------------------------- -CREATE TABLE rental_orders ( +CREATE TABLE IF NOT EXISTS rental_orders ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(64) NOT NULL, listing_id BIGINT UNSIGNED NOT NULL, @@ -115,7 +115,7 @@ CREATE TABLE rental_orders ( KEY idx_rental_orders_rented_at (status, rented_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -CREATE TABLE order_checkouts ( +CREATE TABLE IF NOT EXISTS order_checkouts ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, order_id BIGINT UNSIGNED NOT NULL, initiated_by BIGINT UNSIGNED NOT NULL, @@ -142,7 +142,7 @@ CREATE TABLE order_checkouts ( KEY idx_order_checkouts_status (status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -CREATE TABLE handoff_records ( +CREATE TABLE IF NOT EXISTS handoff_records ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, order_id BIGINT UNSIGNED NOT NULL, from_user_id BIGINT UNSIGNED NOT NULL, @@ -160,7 +160,7 @@ CREATE TABLE handoff_records ( -- 钱包相关表 -- ------------------------------------------- -CREATE TABLE wallet_accounts ( +CREATE TABLE IF NOT EXISTS wallet_accounts ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, user_id BIGINT UNSIGNED NOT NULL, available_balance DECIMAL(12,2) NOT NULL DEFAULT 0.00, @@ -171,7 +171,7 @@ CREATE TABLE wallet_accounts ( UNIQUE KEY uk_wallet_accounts_user_id (user_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -CREATE TABLE wallet_ledger ( +CREATE TABLE IF NOT EXISTS wallet_ledger ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, ledger_no VARCHAR(64) NOT NULL, user_id BIGINT UNSIGNED NOT NULL, @@ -194,7 +194,7 @@ CREATE TABLE wallet_ledger ( -- 纠纷和通知表 -- ------------------------------------------- -CREATE TABLE disputes ( +CREATE TABLE IF NOT EXISTS disputes ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, order_id BIGINT UNSIGNED NOT NULL, initiator_id BIGINT UNSIGNED NOT NULL, @@ -213,7 +213,7 @@ CREATE TABLE disputes ( KEY idx_disputes_status (status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -CREATE TABLE notifications ( +CREATE TABLE IF NOT EXISTS notifications ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, user_id BIGINT UNSIGNED NOT NULL, type VARCHAR(32) NOT NULL, @@ -226,7 +226,7 @@ CREATE TABLE notifications ( KEY idx_notifications_user_read_created (user_id, read_at, created_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -CREATE TABLE audit_logs ( +CREATE TABLE IF NOT EXISTS audit_logs ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, actor_type VARCHAR(32) NOT NULL, actor_id BIGINT UNSIGNED NOT NULL, @@ -245,7 +245,7 @@ CREATE TABLE audit_logs ( -- 管理员和权限表 -- ------------------------------------------- -CREATE TABLE admin_users ( +CREATE TABLE IF NOT EXISTS admin_users ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, username VARCHAR(64) NOT NULL, password_hash VARCHAR(255) NOT NULL, @@ -257,7 +257,7 @@ CREATE TABLE admin_users ( UNIQUE KEY uk_admin_users_username (username) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -CREATE TABLE roles ( +CREATE TABLE IF NOT EXISTS roles ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, code VARCHAR(64) NOT NULL, name VARCHAR(64) NOT NULL, @@ -267,7 +267,7 @@ CREATE TABLE roles ( UNIQUE KEY uk_roles_code (code) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -CREATE TABLE permissions ( +CREATE TABLE IF NOT EXISTS permissions ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, code VARCHAR(128) NOT NULL, name VARCHAR(64) NOT NULL, @@ -278,7 +278,7 @@ CREATE TABLE permissions ( UNIQUE KEY uk_permissions_code (code) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -CREATE TABLE admin_user_roles ( +CREATE TABLE IF NOT EXISTS admin_user_roles ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, admin_user_id BIGINT UNSIGNED NOT NULL, role_id BIGINT UNSIGNED NOT NULL, @@ -286,7 +286,7 @@ CREATE TABLE admin_user_roles ( UNIQUE KEY uk_admin_user_roles_user_role (admin_user_id, role_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -CREATE TABLE role_permissions ( +CREATE TABLE IF NOT EXISTS role_permissions ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, role_id BIGINT UNSIGNED NOT NULL, permission_id BIGINT UNSIGNED NOT NULL, @@ -298,7 +298,7 @@ CREATE TABLE role_permissions ( -- 系统配置表 -- ------------------------------------------- -CREATE TABLE system_configs ( +CREATE TABLE IF NOT EXISTS system_configs ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, `key` VARCHAR(128) NOT NULL, `value` TEXT NOT NULL, @@ -313,7 +313,7 @@ CREATE TABLE system_configs ( -- 客服聊天表 -- ------------------------------------------- -CREATE TABLE chat_conversations ( +CREATE TABLE IF NOT EXISTS chat_conversations ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, order_id BIGINT UNSIGNED NULL, type VARCHAR(32) NOT NULL DEFAULT 'order_group', @@ -328,7 +328,7 @@ CREATE TABLE chat_conversations ( KEY idx_chat_conversations_last_message_at (last_message_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -CREATE TABLE chat_participants ( +CREATE TABLE IF NOT EXISTS chat_participants ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, conversation_id BIGINT UNSIGNED NOT NULL, participant_type VARCHAR(16) NOT NULL, @@ -344,7 +344,7 @@ CREATE TABLE chat_participants ( KEY idx_chat_participants_conversation (conversation_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -CREATE TABLE chat_messages ( +CREATE TABLE IF NOT EXISTS chat_messages ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, conversation_id BIGINT UNSIGNED NOT NULL, sender_type VARCHAR(16) NOT NULL, @@ -358,7 +358,7 @@ CREATE TABLE chat_messages ( KEY idx_chat_messages_created_at (created_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -CREATE TABLE chat_quick_replies ( +CREATE TABLE IF NOT EXISTS chat_quick_replies ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, admin_user_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '0=全局, >0=个人', title VARCHAR(64) NOT NULL COMMENT '快捷回复标题', @@ -369,4 +369,127 @@ CREATE TABLE chat_quick_replies ( INDEX idx_admin_user_id (admin_user_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='快捷回复模板'; +-- ------------------------------------------- +-- 开放上传记录 +-- ------------------------------------------- + +CREATE TABLE IF NOT EXISTS listing_uploads ( + id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, + uploader_name VARCHAR(64) NOT NULL, + matched_admin_id BIGINT UNSIGNED NULL, + owner_id BIGINT UNSIGNED NULL, + client_upload_time DATETIME NULL, + client_ip VARCHAR(64) NOT NULL DEFAULT '', + raw_payload JSON NULL, + parsed_payload JSON NULL, + listing_id BIGINT UNSIGNED NULL, + status VARCHAR(32) NOT NULL DEFAULT 'draft_created', + error_message VARCHAR(255) NOT NULL DEFAULT '', + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + KEY idx_listing_uploads_uploader_name (uploader_name), + KEY idx_listing_uploads_matched_admin_id (matched_admin_id), + KEY idx_listing_uploads_owner_id (owner_id), + KEY idx_listing_uploads_listing_id (listing_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + SET FOREIGN_KEY_CHECKS = 1; + +-- ------------------------------------------- +-- 权限数据 +-- ------------------------------------------- + +INSERT INTO permissions (code, name, resource, action) VALUES +('dashboard:view', '查看仪表盘', 'dashboard', 'view'), +('user:view', '查看用户', 'user', 'view'), +('user:freeze', '冻结用户', 'user', 'freeze'), +('user:unfreeze', '解冻用户', 'user', 'unfreeze'), +('order:view', '查看订单', 'order', 'view'), +('order:close', '关闭订单', 'order', 'close'), +('order:mark_abnormal', '标记异常订单', 'order', 'mark_abnormal'), +('listing:view', '查看商品', 'listing', 'view'), +('listing:approve', '审核通过商品', 'listing', 'approve'), +('listing:reject', '审核拒绝商品', 'listing', 'reject'), +('listing:offline', '下架商品', 'listing', 'offline'), +('dispute:view', '查看纠纷', 'dispute', 'view'), +('dispute:arbitrate', '仲裁纠纷', 'dispute', 'arbitrate'), +('chat:view', '查看客服群聊', 'chat', 'view'), +('chat:send', '发送客服消息', 'chat', 'send'), +('wallet:view', '查看资金流水', 'wallet', 'view'), +('admin_user:manage', '管理员管理', 'admin_user', 'manage'), +('role:manage', '角色管理', 'role', 'manage'), +('system_config:view', '查看系统配置', 'system_config', 'view'), +('system_config:update', '修改系统配置', 'system_config', 'update'), +('audit_log:view', '查看审计日志', 'audit_log', 'view') +ON DUPLICATE KEY UPDATE + name = VALUES(name), + resource = VALUES(resource), + action = VALUES(action); + +-- ------------------------------------------- +-- 角色数据 +-- ------------------------------------------- + +INSERT INTO roles (code, name, description) VALUES +('super_admin', '超级管理员', '拥有所有权限,不可被删除'), +('cs', '客服', '处理用户咨询、群聊、纠纷仲裁'), +('ops', '运营', '管理商品审核、订单管理、用户管理'), +('finance', '财务', '查看资金流水、订单信息') +ON DUPLICATE KEY UPDATE + name = VALUES(name), + description = VALUES(description); + +-- super_admin 拥有所有权限 +INSERT IGNORE INTO role_permissions (role_id, permission_id) +SELECT r.id, p.id FROM roles r CROSS JOIN permissions p WHERE r.code = 'super_admin'; + +-- cs 角色权限 +INSERT IGNORE INTO role_permissions (role_id, permission_id) +SELECT r.id, p.id FROM roles r, permissions p +WHERE r.code = 'cs' AND p.code IN ('dashboard:view', 'user:view', 'dispute:view', 'dispute:arbitrate', 'chat:view', 'chat:send', 'order:view'); + +-- ops 角色权限 +INSERT IGNORE INTO role_permissions (role_id, permission_id) +SELECT r.id, p.id FROM roles r, permissions p +WHERE r.code = 'ops' AND p.code IN ('dashboard:view', 'user:view', 'user:freeze', 'user:unfreeze', 'order:view', 'order:close', 'order:mark_abnormal', 'listing:view', 'listing:approve', 'listing:reject', 'listing:offline', 'dispute:view', 'audit_log:view'); + +-- finance 角色权限 +INSERT IGNORE INTO role_permissions (role_id, permission_id) +SELECT r.id, p.id FROM roles r, permissions p +WHERE r.code = 'finance' AND p.code IN ('dashboard:view', 'wallet:view', 'order:view'); + +-- ------------------------------------------- +-- 管理员账号 +-- ------------------------------------------- + +-- 生成 admin 密码 hash: admin123456 +INSERT INTO admin_users (username, password_hash, nickname, status) VALUES +('admin', '$2a$10$vvDd.cYJCOBl9kr5jdRYXu9C/7GXcHmXsG17zJPHzPOZ0XGbqcWNS', '超级管理员', 'active'), +('kf1', '$2a$10$7cx3B4IWunLZO24o11YVGu4qY1J1naDdsTyvoCpcnOO.GV15qaf3C', '客服1', 'active'), +('kf2', '$2a$10$m6kLCXciFygpqIGUZ9LQtuEFAl40hb.S7zJmMiuC83WrU7OQM3TPC', '客服2', 'active') +ON DUPLICATE KEY UPDATE + nickname = VALUES(nickname), + status = VALUES(status); + +-- admin 关联 super_admin 角色 +INSERT IGNORE INTO admin_user_roles (admin_user_id, role_id) +SELECT au.id, r.id FROM admin_users au, roles r +WHERE au.username = 'admin' AND r.code = 'super_admin'; + +-- 客服关联 cs 角色 +INSERT IGNORE INTO admin_user_roles (admin_user_id, role_id) +SELECT au.id, r.id FROM admin_users au, roles r +WHERE au.username IN ('kf1', 'kf2') AND r.code = 'cs'; + +-- ------------------------------------------- +-- 系统配置 +-- ------------------------------------------- + +INSERT INTO system_configs (`key`, `value`, description) VALUES +('listing.review_required', 'true', '商品是否需要审核'), +('order.pending_payment_timeout_minutes', '15', '待支付超时时间(分钟)'), +('chat.default_support_admin_id', '1', '订单群聊回退客服 ID(仅当无可用客服时使用)'), +('chat.auto_welcome_message', '欢迎加入订单群聊!如有任何问题,请随时沟通。', '建群后自动发送的欢迎话术') +ON DUPLICATE KEY UPDATE + `value` = VALUES(`value`), + description = VALUES(description); diff --git a/backend/migrations/000002_seed.sql b/backend/migrations/000002_seed.sql deleted file mode 100644 index 475b485..0000000 --- a/backend/migrations/000002_seed.sql +++ /dev/null @@ -1,100 +0,0 @@ --- ============================================ --- 初始数据脚本 --- 包含权限、角色、系统配置等基础数据 --- ============================================ - -SET NAMES utf8mb4; - --- ------------------------------------------- --- 权限数据 --- ------------------------------------------- - -INSERT INTO permissions (code, name, resource, action) VALUES -('dashboard:view', '查看仪表盘', 'dashboard', 'view'), -('user:view', '查看用户', 'user', 'view'), -('user:freeze', '冻结用户', 'user', 'freeze'), -('user:unfreeze', '解冻用户', 'user', 'unfreeze'), -('order:view', '查看订单', 'order', 'view'), -('order:close', '关闭订单', 'order', 'close'), -('order:mark_abnormal', '标记异常订单', 'order', 'mark_abnormal'), -('listing:view', '查看商品', 'listing', 'view'), -('listing:approve', '审核通过商品', 'listing', 'approve'), -('listing:reject', '审核拒绝商品', 'listing', 'reject'), -('listing:offline', '下架商品', 'listing', 'offline'), -('dispute:view', '查看纠纷', 'dispute', 'view'), -('dispute:arbitrate', '仲裁纠纷', 'dispute', 'arbitrate'), -('chat:view', '查看客服群聊', 'chat', 'view'), -('chat:send', '发送客服消息', 'chat', 'send'), -('wallet:view', '查看资金流水', 'wallet', 'view'), -('admin_user:manage', '管理员管理', 'admin_user', 'manage'), -('role:manage', '角色管理', 'role', 'manage'), -('system_config:view', '查看系统配置', 'system_config', 'view'), -('system_config:update', '修改系统配置', 'system_config', 'update'), -('audit_log:view', '查看审计日志', 'audit_log', 'view') -ON DUPLICATE KEY UPDATE name = VALUES(name); - --- ------------------------------------------- --- 角色数据 --- ------------------------------------------- - -INSERT INTO roles (code, name, description) VALUES -('super_admin', '超级管理员', '拥有所有权限,不可被删除'), -('cs', '客服', '处理用户咨询、群聊、纠纷仲裁'), -('ops', '运营', '管理商品审核、订单管理、用户管理'), -('finance', '财务', '查看资金流水、订单信息') -ON DUPLICATE KEY UPDATE name = VALUES(name), description = VALUES(description); - --- ------------------------------------------- --- 角色权限关联 --- ------------------------------------------- - --- super_admin 拥有所有权限 -INSERT IGNORE INTO role_permissions (role_id, permission_id) -SELECT r.id, p.id FROM roles r CROSS JOIN permissions p WHERE r.code = 'super_admin'; - --- cs 角色权限 -INSERT IGNORE INTO role_permissions (role_id, permission_id) -SELECT r.id, p.id FROM roles r, permissions p -WHERE r.code = 'cs' AND p.code IN ('dashboard:view', 'user:view', 'dispute:view', 'dispute:arbitrate', 'chat:view', 'chat:send', 'order:view'); - --- ops 角色权限 -INSERT IGNORE INTO role_permissions (role_id, permission_id) -SELECT r.id, p.id FROM roles r, permissions p -WHERE r.code = 'ops' AND p.code IN ('dashboard:view', 'user:view', 'user:freeze', 'user:unfreeze', 'order:view', 'order:close', 'order:mark_abnormal', 'listing:view', 'listing:approve', 'listing:reject', 'listing:offline', 'dispute:view', 'audit_log:view'); - --- finance 角色权限 -INSERT IGNORE INTO role_permissions (role_id, permission_id) -SELECT r.id, p.id FROM roles r, permissions p -WHERE r.code = 'finance' AND p.code IN ('dashboard:view', 'wallet:view', 'order:view'); - --- ------------------------------------------- --- 管理员账号 --- ------------------------------------------- - --- 生成 admin 密码 hash: admin123456 -INSERT INTO admin_users (username, password_hash, nickname, status) VALUES -('admin', '$2a$10$vvDd.cYJCOBl9kr5jdRYXu9C/7GXcHmXsG17zJPHzPOZ0XGbqcWNS', '超级管理员', 'active'), -('kf1', '$2a$10$7cx3B4IWunLZO24o11YVGu4qY1J1naDdsTyvoCpcnOO.GV15qaf3C', '客服1', 'active'), -('kf2', '$2a$10$m6kLCXciFygpqIGUZ9LQtuEFAl40hb.S7zJmMiuC83WrU7OQM3TPC', '客服2', 'active') -ON DUPLICATE KEY UPDATE nickname = VALUES(nickname); - --- admin 关联 super_admin 角色 -INSERT IGNORE INTO admin_user_roles (admin_user_id, role_id) -SELECT au.id, r.id FROM admin_users au, roles r -WHERE au.username = 'admin' AND r.code = 'super_admin'; - --- 客服关联 cs 角色 -INSERT IGNORE INTO admin_user_roles (admin_user_id, role_id) -SELECT au.id, r.id FROM admin_users au, roles r -WHERE au.username IN ('kf1', 'kf2') AND r.code = 'cs'; - --- ------------------------------------------- --- 系统配置 --- ------------------------------------------- - -INSERT INTO system_configs (`key`, `value`, description) VALUES -('listing.review_required', 'true', '商品是否需要审核'), -('order.pending_payment_timeout_minutes', '15', '待支付超时时间(分钟)'), -('chat.default_support_admin_id', '1', '订单群聊回退客服 ID(仅当无可用客服时使用)'), -('chat.auto_welcome_message', '欢迎加入订单群聊!如有任何问题,请随时沟通。', '建群后自动发送的欢迎话术') -ON DUPLICATE KEY UPDATE description = VALUES(description); diff --git a/backend/migrations/000003_cleanup_unused_system_configs.sql b/backend/migrations/000003_cleanup_unused_system_configs.sql deleted file mode 100644 index 9b93ab0..0000000 --- a/backend/migrations/000003_cleanup_unused_system_configs.sql +++ /dev/null @@ -1,17 +0,0 @@ --- 清理未接入业务逻辑的历史/预留系统配置,避免后台配置列表产生误解。 -DELETE FROM system_configs -WHERE `key` IN ( - 'deposit.min_amount', - 'platform.fee_ratio', - 'realname.required_for_order', - 'risk.sms_limit_per_ip_hour', - 'risk.sms_limit_per_phone_hour', - 'settlement.owner_cycle_days', - 'settlement.platform_fee_rate', - 'sms.rate_limit_per_hour', - 'sms.rate_limit_per_minute', - 'wallet.min_deposit', - 'withdraw.min_amount', - 'order.handoff_timeout_minutes', - 'order.return_timeout_minutes' -); diff --git a/backend/migrations/000004_support_chat.sql b/backend/migrations/000004_support_chat.sql deleted file mode 100644 index 759b8a5..0000000 --- a/backend/migrations/000004_support_chat.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE chat_conversations - MODIFY order_id BIGINT UNSIGNED NULL; diff --git a/backend/migrations/000005_listing_uploads.sql b/backend/migrations/000005_listing_uploads.sql deleted file mode 100644 index e8d491f..0000000 --- a/backend/migrations/000005_listing_uploads.sql +++ /dev/null @@ -1,23 +0,0 @@ --- ------------------------------------------- --- 开放上传记录 --- ------------------------------------------- - -CREATE TABLE listing_uploads ( - id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, - uploader_name VARCHAR(64) NOT NULL, - matched_admin_id BIGINT UNSIGNED NULL, - owner_id BIGINT UNSIGNED NULL, - client_upload_time DATETIME NULL, - client_ip VARCHAR(64) NOT NULL DEFAULT '', - raw_payload JSON NULL, - parsed_payload JSON NULL, - listing_id BIGINT UNSIGNED NULL, - status VARCHAR(32) NOT NULL DEFAULT 'draft_created', - error_message VARCHAR(255) NOT NULL DEFAULT '', - created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - KEY idx_listing_uploads_uploader_name (uploader_name), - KEY idx_listing_uploads_matched_admin_id (matched_admin_id), - KEY idx_listing_uploads_owner_id (owner_id), - KEY idx_listing_uploads_listing_id (listing_id) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/deploy/README.md b/deploy/README.md index 43e9db0..a787e55 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -49,6 +49,12 @@ STORAGE_SECRET_ACCESS_KEY ./scripts/deploy-prod.sh --logs ``` +测试阶段需要清空并重建数据库时: + +```bash +./scripts/deploy-prod.sh --reset-db +``` + ## 3. 手动启动服务 ```bash @@ -60,10 +66,8 @@ docker compose -f deploy/docker-compose.prod.yml up -d --build 将命令中的 `change-hfb-password` 替换为 `backend/.env` 里的 `MYSQL_PASSWORD`。 ```bash -for file in backend/migrations/*.sql; do - docker compose -f deploy/docker-compose.prod.yml exec -T mysql \ - mysql -uhfb -pchange-hfb-password hfb_sys < "$file" -done +docker compose -f deploy/docker-compose.prod.yml exec -T mysql \ + mysql -uhfb -pchange-hfb-password hfb_sys < backend/migrations/000001_init.sql ``` ## 5. 验证 diff --git a/scripts/deploy-prod.sh b/scripts/deploy-prod.sh index ab1e3a1..1d588e2 100755 --- a/scripts/deploy-prod.sh +++ b/scripts/deploy-prod.sh @@ -61,6 +61,7 @@ show_help() { 选项: --no-build 不重新构建镜像,仅启动已有镜像 --no-migrate 不执行数据库迁移 + --reset-db 重置数据库(测试阶段使用,会删除并重建) --logs 部署完成后跟随查看后端日志 -h, --help 显示帮助信息 @@ -75,12 +76,14 @@ show_help() { 示例: ./scripts/deploy-prod.sh ./scripts/deploy-prod.sh --no-build + ./scripts/deploy-prod.sh --reset-db ./scripts/deploy-prod.sh --logs EOF } NO_BUILD=0 NO_MIGRATE=0 +RESET_DB=0 FOLLOW_LOGS=0 while [[ $# -gt 0 ]]; do @@ -93,6 +96,10 @@ while [[ $# -gt 0 ]]; do NO_MIGRATE=1 shift ;; + --reset-db) + RESET_DB=1 + shift + ;; --logs) FOLLOW_LOGS=1 shift @@ -109,6 +116,11 @@ while [[ $# -gt 0 ]]; do esac done +if [[ "${RESET_DB}" == "1" && "${NO_MIGRATE}" == "1" ]]; then + log_error "--reset-db 会清空数据库,不能和 --no-migrate 同时使用" + exit 1 +fi + validate_env() { if [[ ! -f "${BACKEND_ENV}" ]]; then log_error "未找到 backend/.env,请先执行:cp backend/.env.prod.example backend/.env 并填写生产配置" @@ -121,6 +133,7 @@ validate_env() { redis_addr="$(require_env REDIS_ADDR)" storage_endpoint="$(require_env STORAGE_ENDPOINT)" require_env MYSQL_DATABASE >/dev/null + require_env MYSQL_ROOT_PASSWORD >/dev/null require_env MYSQL_USER >/dev/null require_env MYSQL_PASSWORD >/dev/null require_env JWT_SECRET >/dev/null @@ -182,6 +195,10 @@ mysql_exec() { compose exec -T mysql sh -c 'MYSQL_PWD="$MYSQL_PASSWORD" mysql -u"$MYSQL_USER" "$@"' sh "$@" } +mysql_root_exec() { + compose exec -T mysql sh -c 'MYSQL_PWD="$MYSQL_ROOT_PASSWORD" mysql -uroot "$@"' sh "$@" +} + mysql_scalar() { mysql_exec -N -s "$(require_env MYSQL_DATABASE)" -e "$1" } @@ -212,6 +229,24 @@ bootstrap_existing_schema_history() { fi } +reset_database() { + if [[ "${RESET_DB}" != "1" ]]; then + return 0 + fi + + local database + database="$(require_env MYSQL_DATABASE)" + if [[ ! "${database}" =~ ^[A-Za-z0-9_]+$ ]]; then + log_error "MYSQL_DATABASE 只能包含字母、数字和下划线,当前值:${database}" + exit 1 + fi + + log_warn "重置数据库 ${database}..." + mysql_root_exec -e \ + "DROP DATABASE IF EXISTS \`${database}\`; CREATE DATABASE \`${database}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" + log_success "数据库已重建" +} + run_migrations() { if [[ "${NO_MIGRATE}" == "1" ]]; then log_warn "已跳过数据库迁移" @@ -228,7 +263,12 @@ run_migrations() { version="$(basename "${file}" .sql)" applied="$(mysql_scalar "SELECT COUNT(*) FROM schema_migrations WHERE version = '${version}';")" if [[ "${applied}" != "0" ]]; then - log "跳过已应用迁移:${version}" + if [[ "${version}" == "000001_init" ]]; then + log "同步初始化脚本:${version}" + mysql_exec "$(require_env MYSQL_DATABASE)" < "${file}" + else + log "跳过已应用迁移:${version}" + fi continue fi @@ -277,6 +317,7 @@ main() { wait_service_healthy mysql "MySQL" wait_service_healthy redis "Redis" wait_service_healthy minio "MinIO" + reset_database run_migrations log "重启后端以加载最新数据库状态..." diff --git a/scripts/dev.sh b/scripts/dev.sh index 1883158..2bb8fef 100755 --- a/scripts/dev.sh +++ b/scripts/dev.sh @@ -5,6 +5,7 @@ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" COMPOSE_FILE="${ROOT_DIR}/deploy/docker-compose.dev.yml" BACKEND_ENV="${ROOT_DIR}/backend/.env" BACKEND_ENV_EXAMPLE="${ROOT_DIR}/backend/.env.example" +INIT_SQL="${ROOT_DIR}/backend/migrations/000001_init.sql" BACKEND_PORT="${DEV_BACKEND_PORT:-8080}" FRONTEND_PORT="${DEV_FRONTEND_PORT:-5173}" BACKEND_HEALTH_URL="${DEV_BACKEND_HEALTH_URL:-http://127.0.0.1:${BACKEND_PORT}/health}" @@ -51,7 +52,7 @@ show_help() { 选项: --reset-db 重置数据库(删除并重建) - --seed-only 仅重新加载种子数据 + --seed-only 仅重新同步基础数据 --no-frontend 不启动前端 --no-backend 不启动后端 -h, --help 显示帮助信息 @@ -72,7 +73,7 @@ show_help() { 示例: ./scripts/dev.sh # 正常启动 ./scripts/dev.sh --reset-db # 重置数据库后启动 - ./scripts/dev.sh --seed-only # 重新加载种子数据 + ./scripts/dev.sh --seed-only # 重新同步基础数据 EOF exit 0 } @@ -222,16 +223,12 @@ init_database() { if [[ "${table_count}" == "0" ]]; then log "首次启动,初始化数据库..." - local migration - for migration in "${ROOT_DIR}"/backend/migrations/*.sql; do - log "执行迁移:$(basename "${migration}")" - mysql_hfb --default-character-set=utf8mb4 hfb_sys < "${migration}" - done + log "执行初始化脚本:$(basename "${INIT_SQL}")" + mysql_hfb --default-character-set=utf8mb4 hfb_sys < "${INIT_SQL}" log_success "数据库初始化完成" elif [[ "${SEED_ONLY}" == "1" ]]; then - log "重新加载种子数据..." - mysql_hfb --default-character-set=utf8mb4 hfb_sys < "${ROOT_DIR}/backend/migrations/000002_seed.sql" - log_success "种子数据加载完成" + log "重新同步基础数据..." + mysql_hfb --default-character-set=utf8mb4 hfb_sys < "${INIT_SQL}" else log "数据库已存在,跳过迁移(使用 --reset-db 重建)" fi @@ -320,9 +317,9 @@ main() { init_database - # 仅加载种子数据模式 + # 仅同步基础数据模式 if [[ "${SEED_ONLY}" == "1" ]]; then - log_success "种子数据加载完成,退出" + log_success "基础数据同步完成,退出" exit 0 fi