Files
Friendship-and-chat-api/sql/mysql/member/20261111_member_push_management.sql
T
2026-11-11 19:39:10 +08:00

153 lines
7.5 KiB
SQL

-- 可重复执行,兼容已有设备绑定表。任务及设备明细长期保存。
CREATE TABLE IF NOT EXISTS member_push_device (
id BIGINT NOT NULL AUTO_INCREMENT,
member_id BIGINT NOT NULL,
registration_id VARCHAR(64) NOT NULL,
alias VARCHAR(64) NULL,
platform VARCHAR(16) NOT NULL,
provider VARCHAR(16) NOT NULL DEFAULT 'jpush',
app_key VARCHAR(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT '',
tenant_id BIGINT NOT NULL DEFAULT 0,
creator VARCHAR(64) NULL DEFAULT '',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updater VARCHAR(64) NULL DEFAULT '',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted BIT(1) NOT NULL DEFAULT b'0',
PRIMARY KEY (id),
UNIQUE KEY uk_registration_id (registration_id),
KEY idx_member_id (member_id),
KEY idx_app_provider_id (app_key, provider, id, tenant_id),
KEY idx_app_member_provider (app_key, member_id, provider, tenant_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='会员推送设备';
-- 使用同一个数据库连接顺序执行。历史设备保留未知 AppKey,等待新版客户端重新绑定。
SET @member_push_schema_ddl = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'member_push_device' AND COLUMN_NAME = 'app_key') = 0,
'ALTER TABLE member_push_device ADD COLUMN app_key VARCHAR(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT '''' AFTER provider',
'SELECT 1');
PREPARE member_push_schema_stmt FROM @member_push_schema_ddl;
EXECUTE member_push_schema_stmt;
DEALLOCATE PREPARE member_push_schema_stmt;
SET @member_push_schema_ddl = IF(
(SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'member_push_device' AND INDEX_NAME = 'idx_app_provider_id') = 0,
'ALTER TABLE member_push_device ADD INDEX idx_app_provider_id (app_key, provider, id, tenant_id)',
'SELECT 1');
PREPARE member_push_schema_stmt FROM @member_push_schema_ddl;
EXECUTE member_push_schema_stmt;
DEALLOCATE PREPARE member_push_schema_stmt;
SET @member_push_schema_ddl = IF(
(SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'member_push_device' AND INDEX_NAME = 'idx_app_member_provider') = 0,
'ALTER TABLE member_push_device ADD INDEX idx_app_member_provider (app_key, member_id, provider, tenant_id)',
'SELECT 1');
PREPARE member_push_schema_stmt FROM @member_push_schema_ddl;
EXECUTE member_push_schema_stmt;
DEALLOCATE PREPARE member_push_schema_stmt;
CREATE TABLE IF NOT EXISTS member_push_task (
id BIGINT NOT NULL AUTO_INCREMENT,
request_key VARCHAR(160) NOT NULL,
request_hash VARCHAR(64) NOT NULL,
source VARCHAR(16) NOT NULL,
target_type VARCHAR(16) NOT NULL,
member_ids MEDIUMTEXT NOT NULL,
operator_id BIGINT NULL,
message_id BIGINT NULL,
sender_id BIGINT NULL,
receiver_id BIGINT NULL,
title VARCHAR(160) NOT NULL,
content VARCHAR(500) NOT NULL,
status VARCHAR(24) NOT NULL,
audience_complete BIT(1) NOT NULL DEFAULT b'0',
audience_cursor BIGINT NOT NULL DEFAULT 0,
snapshot_max_id BIGINT NOT NULL DEFAULT 0,
total_members INT NOT NULL DEFAULT 0,
total_devices INT NOT NULL DEFAULT 0,
submitted_count INT NOT NULL DEFAULT 0,
failed_count INT NOT NULL DEFAULT 0,
skipped_count INT NOT NULL DEFAULT 0,
processed_count INT NOT NULL DEFAULT 0,
last_error VARCHAR(1000) NULL,
attempt_count INT NOT NULL DEFAULT 0,
next_retry_time DATETIME(3) NOT NULL,
expires_at DATETIME(3) NOT NULL,
finish_time DATETIME(3) NULL,
tenant_id BIGINT NOT NULL DEFAULT 0,
creator VARCHAR(64) NULL DEFAULT '',
create_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updater VARCHAR(64) NULL DEFAULT '',
update_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
deleted BIT(1) NOT NULL DEFAULT b'0',
PRIMARY KEY (id),
UNIQUE KEY uk_tenant_request (tenant_id, request_key),
KEY idx_pending (status, next_retry_time),
KEY idx_tenant_time (tenant_id, create_time),
KEY idx_message (message_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='App推送任务';
CREATE TABLE IF NOT EXISTS member_push_record (
id BIGINT NOT NULL AUTO_INCREMENT,
task_id BIGINT NOT NULL,
member_id BIGINT NOT NULL,
nickname VARCHAR(255) NULL,
user_code VARCHAR(64) NULL,
device_id BIGINT NULL,
platform VARCHAR(16) NULL,
registration_id VARCHAR(64) NOT NULL DEFAULT '',
status VARCHAR(16) NOT NULL,
attempt_count INT NOT NULL DEFAULT 0,
cid VARCHAR(128) NULL,
batch_payload MEDIUMTEXT NULL COMMENT '批次首行保存固定请求体,用于不确定结果恢复',
jpush_msg_id VARCHAR(64) NULL,
error_code VARCHAR(64) NULL,
error_message VARCHAR(1000) NULL,
foreground_session VARCHAR(160) NULL,
foreground_version BIGINT NULL,
next_retry_time DATETIME(3) NOT NULL,
send_time DATETIME(3) NULL,
tenant_id BIGINT NOT NULL DEFAULT 0,
creator VARCHAR(64) NULL DEFAULT '',
create_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updater VARCHAR(64) NULL DEFAULT '',
update_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
deleted BIT(1) NOT NULL DEFAULT b'0',
PRIMARY KEY (id),
UNIQUE KEY uk_task_device (task_id, member_id, registration_id),
KEY idx_task_pending (task_id, status, next_retry_time),
KEY idx_batch (task_id, cid),
KEY idx_member_task (member_id, task_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='App推送设备记录';
-- 动态菜单按组件路径识别,可重复执行。优先复用现有 App 管理目录。
SET @app_parent = (SELECT id FROM system_menu
WHERE deleted = b'0' AND type = 1 AND (path IN ('app','/app') OR name IN ('App管理','APP管理','应用管理'))
ORDER BY id LIMIT 1);
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component,
component_name, status, visible, keep_alive, always_show, creator, updater)
SELECT 'App管理', '', 1, 80, 0, '/app', 'ep:cellphone', '', '', 0, b'1', b'1', b'1', '1', '1'
WHERE @app_parent IS NULL;
SET @app_parent = COALESCE(@app_parent, LAST_INSERT_ID());
SET @push_menu = (SELECT id FROM system_menu
WHERE deleted = b'0' AND component = 'app/push/index' ORDER BY id LIMIT 1);
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component,
component_name, status, visible, keep_alive, always_show, creator, updater)
SELECT '推送管理', 'member:push:query', 2, 20, @app_parent, 'push', 'ep:bell',
'app/push/index', 'AppPush', 0, b'1', b'1', b'1', '1', '1'
WHERE @push_menu IS NULL;
SET @push_menu = COALESCE(@push_menu, LAST_INSERT_ID());
UPDATE system_menu SET permission = 'member:push:query', component_name = 'AppPush'
WHERE id = @push_menu;
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component,
component_name, status, visible, keep_alive, always_show, creator, updater)
SELECT '手动推送', 'member:push:send', 3, 1, @push_menu, '', '', '', '', 0, b'1', b'1', b'1', '1', '1'
WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE deleted = b'0' AND permission = 'member:push:send');
-- 运行配置
-- API 和 IM 配置相同的 IM_PUSH_CALLBACK_SECRET。
-- IM_PUSH_CALLBACK_URL 指向业务 API 的 /admin-api/third-callback/im-private-message。
-- JPUSH_APP_KEY、JPUSH_MASTER_SECRET、JPUSH_APNS_PRODUCTION 使用聊天应用的极光配置。