From 442f32a043ebb7a993e520cfb2d0cf28f5ed3fa5 Mon Sep 17 00:00:00 2001 From: zpc Date: Thu, 26 Mar 2026 22:10:57 +0800 Subject: [PATCH] feat(deployment): add v1.2.0 database scripts and improve Docker/auth configuration - Add v1.2.0 complete database upgrade scripts for business and admin databases - Enhance WeChat login logic to handle OpenId reassociation when user logs in via phone number - Add UpdatedAt timestamp update in WeChat login record updates - Configure Docker container permissions for AgileConfig cache file writes - Add Caddy image tagging to CI-CD deployment documentation - Update frontend Config.js for deployment configuration management --- CI-CD部署文档.md | 2 + .../LiveForum.Service/Auth/LoginService.cs | 43 +- .../LiveForum/LiveForum.WebApi/Dockerfile | 6 + .../数据库脚本/v1.2.0_ALL_业务库.sql | 557 ++++++++++++++++++ .../数据库脚本/v1.2.0_ALL_管理库.sql | 157 +++++ 前端/live-forum/modules/Config.js | 8 +- 6 files changed, 758 insertions(+), 15 deletions(-) create mode 100644 server/webapi/数据库脚本/v1.2.0_ALL_业务库.sql create mode 100644 server/webapi/数据库脚本/v1.2.0_ALL_管理库.sql diff --git a/CI-CD部署文档.md b/CI-CD部署文档.md index 88d2f8c..e88b464 100644 --- a/CI-CD部署文档.md +++ b/CI-CD部署文档.md @@ -54,6 +54,8 @@ docker pull mcr.microsoft.com/dotnet/aspnet:8.0 docker tag mcr.microsoft.com/dotnet/aspnet:8.0 192.168.195.25:19900/library/dotnet/aspnet:8.0 docker push 192.168.195.25:19900/library/dotnet/aspnet:8.0 +docker tag caddy:alpine 192.168.195.25:19900/library/caddy:alpine + ``` ## 五、前置条件 diff --git a/server/webapi/LiveForum/LiveForum.Service/Auth/LoginService.cs b/server/webapi/LiveForum/LiveForum.Service/Auth/LoginService.cs index f6ff1de..047ba56 100644 --- a/server/webapi/LiveForum/LiveForum.Service/Auth/LoginService.cs +++ b/server/webapi/LiveForum/LiveForum.Service/Auth/LoginService.cs @@ -548,24 +548,44 @@ namespace LiveForum.Service.Auth if (user != null) { // 找到手机号用户,确保绑定/更新 OpenID + // 先按 UserId 查当前用户的微信记录 wechatLogin = await _wechatMiniProgramLoginsRepository.Select .Where(x => x.UserId == user.Id) .FirstAsync(); if (wechatLogin == null) { - wechatLogin = new T_WechatMiniProgramLogins + // 当前用户没有微信记录,检查该 OpenId 是否已被其他用户占用 + var existingByOpenId = await _wechatMiniProgramLoginsRepository.Select + .Where(x => x.OpenId == openId) + .FirstAsync(); + + if (existingByOpenId != null) { - OpenId = openId, - SessionKey = sessionKey, - UnionId = unionId ?? "", - UserId = user.Id, - LastLoginIp = clientIp, - LastLoginTime = now, - CreatedAt = now, - UpdatedAt = now, - }; - await _wechatMiniProgramLoginsRepository.InsertAsync(wechatLogin); + // OpenId 已存在,将其重新关联到当前手机号用户 + existingByOpenId.UserId = user.Id; + existingByOpenId.SessionKey = sessionKey; + existingByOpenId.LastLoginTime = now; + existingByOpenId.LastLoginIp = clientIp; + existingByOpenId.UpdatedAt = now; + await _wechatMiniProgramLoginsRepository.UpdateAsync(existingByOpenId); + wechatLogin = existingByOpenId; + } + else + { + wechatLogin = new T_WechatMiniProgramLogins + { + OpenId = openId, + SessionKey = sessionKey, + UnionId = unionId ?? "", + UserId = user.Id, + LastLoginIp = clientIp, + LastLoginTime = now, + CreatedAt = now, + UpdatedAt = now, + }; + await _wechatMiniProgramLoginsRepository.InsertAsync(wechatLogin); + } } else { @@ -573,6 +593,7 @@ namespace LiveForum.Service.Auth wechatLogin.SessionKey = sessionKey; wechatLogin.LastLoginTime = now; wechatLogin.LastLoginIp = clientIp; + wechatLogin.UpdatedAt = now; await _wechatMiniProgramLoginsRepository.UpdateAsync(wechatLogin); } } diff --git a/server/webapi/LiveForum/LiveForum.WebApi/Dockerfile b/server/webapi/LiveForum/LiveForum.WebApi/Dockerfile index 84e882a..8c43bdf 100644 --- a/server/webapi/LiveForum/LiveForum.WebApi/Dockerfile +++ b/server/webapi/LiveForum/LiveForum.WebApi/Dockerfile @@ -31,4 +31,10 @@ RUN dotnet publish "./LiveForum.WebApi.csproj" -c $BUILD_CONFIGURATION -o /app/p FROM base AS final WORKDIR /app COPY --from=publish /app/publish . + +# 给 AgileConfig 缓存文件写权限(app 用户需要写入配置缓存) +USER root +RUN mkdir -p /app && chown -R $APP_UID:$APP_UID /app +USER $APP_UID + ENTRYPOINT ["dotnet", "LiveForum.WebApi.dll"] \ No newline at end of file diff --git a/server/webapi/数据库脚本/v1.2.0_ALL_业务库.sql b/server/webapi/数据库脚本/v1.2.0_ALL_业务库.sql new file mode 100644 index 0000000..1c98071 --- /dev/null +++ b/server/webapi/数据库脚本/v1.2.0_ALL_业务库.sql @@ -0,0 +1,557 @@ +-- ========================================== +-- 团播机构 v1.2.0 业务库 (LiveForumDB) 完整升级脚本 +-- 整合时间: 2025-01-25 +-- 说明: 整合所有 v1.2.0 业务库变更,按依赖顺序执行 +-- 执行前请备份数据库!建议在业务低峰期执行 +-- ========================================== +-- 包含模块(按执行顺序): +-- 1. CDK 激活系统(T_CDKs、T_SystemSettings、T_Users 字段) +-- 2. 实名认证 & 手机号登录(T_Users 字段、T_RealNameVerifyLogs) +-- 3. 帖子回复权限(T_Posts.AllowReply) +-- 4. 发帖回复时间间隔(T_PostReplyIntervals) +-- 5. 防沉迷规则(T_AntiAddictionRules) +-- 6. 身份权限设置(4张表 + 默认数据) +-- 7. 点赞唯一索引(T_Likes) +-- 8. 消息系统字段扩展(T_Messages 新字段) +-- 9. 消息系统重构(类型调整 + MyCommentContent) +-- ========================================== + +PRINT '==========================================' +PRINT '开始执行 v1.2.0 业务库完整升级脚本' +PRINT '执行时间: ' + CONVERT(VARCHAR, GETDATE(), 120) +PRINT '==========================================' +PRINT '' + +-- ########################################################## +-- 模块1: CDK 激活系统 +-- ########################################################## +PRINT '>>> 模块1: CDK 激活系统' +PRINT '' + +-- 1.1 创建 CDK 表 T_CDKs +IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'T_CDKs') +BEGIN + CREATE TABLE T_CDKs ( + Id BIGINT PRIMARY KEY IDENTITY(1,1), + Code NVARCHAR(50) NOT NULL, + BatchNo NVARCHAR(50) NULL, + Status INT NOT NULL DEFAULT 0, + UsedByUserId BIGINT NULL, + UsedAt DATETIME2 NULL, + CreatedAt DATETIME2 NOT NULL DEFAULT GETDATE(), + Remark NVARCHAR(200) NULL + ); + PRINT '✓ T_CDKs 表创建成功' +END +ELSE + PRINT '⚠ T_CDKs 表已存在,跳过' + +-- 1.2 T_CDKs 索引 +IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_T_CDKs_Code' AND object_id = OBJECT_ID('T_CDKs')) +BEGIN + CREATE UNIQUE INDEX IX_T_CDKs_Code ON T_CDKs (Code); + PRINT '✓ IX_T_CDKs_Code 唯一索引创建成功' +END + +IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_T_CDKs_BatchNo' AND object_id = OBJECT_ID('T_CDKs')) +BEGIN + CREATE INDEX IX_T_CDKs_BatchNo ON T_CDKs (BatchNo); + PRINT '✓ IX_T_CDKs_BatchNo 索引创建成功' +END + +IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_T_CDKs_Status' AND object_id = OBJECT_ID('T_CDKs')) +BEGIN + CREATE INDEX IX_T_CDKs_Status ON T_CDKs (Status); + PRINT '✓ IX_T_CDKs_Status 索引创建成功' +END + +-- 1.3 创建系统设置表 T_SystemSettings +IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'T_SystemSettings') +BEGIN + CREATE TABLE T_SystemSettings ( + Id INT PRIMARY KEY IDENTITY(1,1), + SettingKey NVARCHAR(100) NOT NULL, + SettingValue NVARCHAR(500) NULL, + Description NVARCHAR(200) NULL, + UpdatedAt DATETIME2 NOT NULL DEFAULT GETDATE() + ); + PRINT '✓ T_SystemSettings 表创建成功' +END +ELSE + PRINT '⚠ T_SystemSettings 表已存在,跳过' + +IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_T_SystemSettings_SettingKey' AND object_id = OBJECT_ID('T_SystemSettings')) +BEGIN + CREATE UNIQUE INDEX IX_T_SystemSettings_SettingKey ON T_SystemSettings (SettingKey); + PRINT '✓ IX_T_SystemSettings_SettingKey 唯一索引创建成功' +END + +-- 1.4 CDK 功能开关默认配置 +IF NOT EXISTS (SELECT * FROM T_SystemSettings WHERE SettingKey = 'cdk_enabled') +BEGIN + INSERT INTO T_SystemSettings (SettingKey, SettingValue, Description, UpdatedAt) + VALUES ('cdk_enabled', 'true', 'CDK功能开关', GETDATE()); + PRINT '✓ cdk_enabled 配置插入成功' +END + +-- 1.5 T_Users 添加 CDK 激活字段 +IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'T_Users' AND COLUMN_NAME = 'IsCdkActivated') +BEGIN + ALTER TABLE T_Users ADD IsCdkActivated BIT NOT NULL DEFAULT 0; + PRINT '✓ T_Users.IsCdkActivated 字段添加成功' +END + +IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'T_Users' AND COLUMN_NAME = 'CdkActivatedAt') +BEGIN + ALTER TABLE T_Users ADD CdkActivatedAt DATETIME2 NULL; + PRINT '✓ T_Users.CdkActivatedAt 字段添加成功' +END + +PRINT '' + +-- ########################################################## +-- 模块2: 实名认证 & 手机号登录 +-- ########################################################## +PRINT '>>> 模块2: 实名认证 & 手机号登录' +PRINT '' + +-- 2.1 T_Users 新增实名认证字段 +IF NOT EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('T_Users') AND name = 'IsRealNameVerified') +BEGIN + ALTER TABLE T_Users ADD IsRealNameVerified BIT NOT NULL DEFAULT 0; + PRINT '✓ T_Users.IsRealNameVerified 字段添加成功' +END + +IF NOT EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('T_Users') AND name = 'RealName') +BEGIN + ALTER TABLE T_Users ADD RealName NVARCHAR(50) NULL; + PRINT '✓ T_Users.RealName 字段添加成功' +END + +IF NOT EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('T_Users') AND name = 'IdCardNumber') +BEGIN + ALTER TABLE T_Users ADD IdCardNumber NVARCHAR(100) NULL; + PRINT '✓ T_Users.IdCardNumber 字段添加成功' +END + +IF NOT EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('T_Users') AND name = 'RealNameVerifiedAt') +BEGIN + ALTER TABLE T_Users ADD RealNameVerifiedAt DATETIME2 NULL; + PRINT '✓ T_Users.RealNameVerifiedAt 字段添加成功' +END + +-- 2.2 T_Users.PhoneNumber 索引 +IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_T_Users_PhoneNumber' AND object_id = OBJECT_ID('T_Users')) +BEGIN + CREATE INDEX IX_T_Users_PhoneNumber ON T_Users (PhoneNumber); + PRINT '✓ IX_T_Users_PhoneNumber 索引创建成功' +END + +-- 2.3 创建实名验证记录表 +IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID('T_RealNameVerifyLogs') AND type = 'U') +BEGIN + CREATE TABLE T_RealNameVerifyLogs ( + Id BIGINT PRIMARY KEY IDENTITY(1,1), + UserId BIGINT NOT NULL, + RealName NVARCHAR(50) NOT NULL, + IdCardNumberMasked NVARCHAR(20) NOT NULL, + IsSuccess BIT NOT NULL DEFAULT 0, + FailReason NVARCHAR(200) NULL, + ClientIp NVARCHAR(50) NULL, + CreatedAt DATETIME2 NOT NULL DEFAULT GETDATE() + ); + + CREATE INDEX IX_T_RealNameVerifyLogs_UserId_CreatedAt + ON T_RealNameVerifyLogs (UserId, CreatedAt); + PRINT '✓ T_RealNameVerifyLogs 表及索引创建成功' +END +ELSE + PRINT '⚠ T_RealNameVerifyLogs 表已存在,跳过' + +-- 2.4 实名认证系统配置 +IF NOT EXISTS (SELECT 1 FROM T_SystemSettings WHERE SettingKey = 'real_name_enabled') + INSERT INTO T_SystemSettings (SettingKey, SettingValue, Description, UpdatedAt) + VALUES ('real_name_enabled', 'true', N'实名认证功能开关', GETDATE()); + +IF NOT EXISTS (SELECT 1 FROM T_SystemSettings WHERE SettingKey = 'real_name_provider') + INSERT INTO T_SystemSettings (SettingKey, SettingValue, Description, UpdatedAt) + VALUES ('real_name_provider', 'aliyun', N'实名认证服务商(aliyun/tencent)', GETDATE()); + +IF NOT EXISTS (SELECT 1 FROM T_SystemSettings WHERE SettingKey = 'real_name_daily_limit') + INSERT INTO T_SystemSettings (SettingKey, SettingValue, Description, UpdatedAt) + VALUES ('real_name_daily_limit', '5', N'每用户每天最多验证次数', GETDATE()); + +IF NOT EXISTS (SELECT 1 FROM T_SystemSettings WHERE SettingKey = 'real_name_interval_seconds') + INSERT INTO T_SystemSettings (SettingKey, SettingValue, Description, UpdatedAt) + VALUES ('real_name_interval_seconds', '60', N'两次验证最小间隔(秒)', GETDATE()); + +IF NOT EXISTS (SELECT 1 FROM T_SystemSettings WHERE SettingKey = 'aliyun_access_key_id') + INSERT INTO T_SystemSettings (SettingKey, SettingValue, Description, UpdatedAt) + VALUES ('aliyun_access_key_id', '', N'阿里云 AccessKey ID', GETDATE()); + +IF NOT EXISTS (SELECT 1 FROM T_SystemSettings WHERE SettingKey = 'aliyun_access_key_secret') + INSERT INTO T_SystemSettings (SettingKey, SettingValue, Description, UpdatedAt) + VALUES ('aliyun_access_key_secret', '', N'阿里云 AccessKey Secret', GETDATE()); + +PRINT '✓ 实名认证系统配置插入完成' +PRINT '' + +-- ########################################################## +-- 模块3: 帖子回复权限 +-- ########################################################## +PRINT '>>> 模块3: 帖子回复权限' +PRINT '' + +IF NOT EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('T_Posts') AND name = 'AllowReply') +BEGIN + ALTER TABLE T_Posts ADD AllowReply BIT NOT NULL DEFAULT 1; + PRINT '✓ T_Posts.AllowReply 字段添加成功' +END +ELSE + PRINT '⚠ AllowReply 字段已存在,跳过' + +PRINT '' + +-- ########################################################## +-- 模块4: 发帖回复时间间隔 +-- ########################################################## +PRINT '>>> 模块4: 发帖回复时间间隔' +PRINT '' + +IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID('T_PostReplyIntervals') AND type = 'U') +BEGIN + CREATE TABLE T_PostReplyIntervals ( + Id INT IDENTITY(1,1) PRIMARY KEY, + CertificationTypeId INT NOT NULL, + PostInterval INT NOT NULL DEFAULT 0, + ReplyInterval INT NOT NULL DEFAULT 0, + CreatedAt DATETIME2 NOT NULL DEFAULT GETDATE(), + UpdatedAt DATETIME2 NOT NULL DEFAULT GETDATE(), + CONSTRAINT UQ_PostReplyIntervals_CertTypeId UNIQUE (CertificationTypeId), + CONSTRAINT FK_PostReplyIntervals_CertType FOREIGN KEY (CertificationTypeId) REFERENCES T_CertificationTypes(Id) + ); + PRINT '✓ T_PostReplyIntervals 表创建成功' +END +ELSE + PRINT '⚠ T_PostReplyIntervals 表已存在,跳过' + +PRINT '' + +-- ########################################################## +-- 模块5: 防沉迷规则 +-- ########################################################## +PRINT '>>> 模块5: 防沉迷规则' +PRINT '' + +IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID('T_AntiAddictionRules') AND type = 'U') +BEGIN + CREATE TABLE T_AntiAddictionRules ( + Id INT IDENTITY(1,1) PRIMARY KEY, + StartTime TIME NOT NULL, + EndTime TIME NOT NULL, + RestrictPost BIT NOT NULL DEFAULT 0, + RestrictReply BIT NOT NULL DEFAULT 0, + RestrictFlower BIT NOT NULL DEFAULT 0, + CreatedAt DATETIME2 NOT NULL DEFAULT GETDATE(), + UpdatedAt DATETIME2 NOT NULL DEFAULT GETDATE() + ); + PRINT '✓ T_AntiAddictionRules 表创建成功' +END +ELSE + PRINT '⚠ T_AntiAddictionRules 表已存在,跳过' + +PRINT '' + +-- ########################################################## +-- 模块6: 身份权限设置(4张表 + 默认数据) +-- ########################################################## +PRINT '>>> 模块6: 身份权限设置' +PRINT '' + +BEGIN TRANSACTION; + +-- 6.1 创建认证等级权限配置表 +IF OBJECT_ID('T_CertificationTypePermissions', 'U') IS NULL +BEGIN + CREATE TABLE T_CertificationTypePermissions ( + Id INT IDENTITY(1,1) PRIMARY KEY, + CertificationTypeId INT NOT NULL, + CanPost BIT NOT NULL DEFAULT 0, + CanReply BIT NOT NULL DEFAULT 0, + CanFlower BIT NOT NULL DEFAULT 0, + CanLike BIT NOT NULL DEFAULT 0, + CanDeleteOtherPost BIT NOT NULL DEFAULT 0, + CreatedAt DATETIME NULL, + UpdatedAt DATETIME NULL, + CONSTRAINT UQ_CertTypePermissions_CertTypeId UNIQUE (CertificationTypeId), + CONSTRAINT FK_CertTypePermissions_CertType FOREIGN KEY (CertificationTypeId) REFERENCES T_CertificationTypes(Id) + ); + PRINT '✓ T_CertificationTypePermissions 表创建成功' +END +ELSE + PRINT '⚠ T_CertificationTypePermissions 表已存在,跳过' + +-- 6.2 创建身份组表 +IF OBJECT_ID('T_IdentityGroups', 'U') IS NULL +BEGIN + CREATE TABLE T_IdentityGroups ( + Id INT IDENTITY(1,1) PRIMARY KEY, + Name NVARCHAR(50) NOT NULL, + IsDefault BIT NOT NULL DEFAULT 0, + CreatedAt DATETIME NULL, + UpdatedAt DATETIME NULL, + CONSTRAINT UQ_IdentityGroups_Name UNIQUE (Name) + ); + PRINT '✓ T_IdentityGroups 表创建成功' +END +ELSE + PRINT '⚠ T_IdentityGroups 表已存在,跳过' + +-- 6.3 创建身份组权限配置表 +IF OBJECT_ID('T_IdentityGroupPermissions', 'U') IS NULL +BEGIN + CREATE TABLE T_IdentityGroupPermissions ( + Id INT IDENTITY(1,1) PRIMARY KEY, + IdentityGroupId INT NOT NULL, + CanPost BIT NOT NULL DEFAULT 0, + CanReply BIT NOT NULL DEFAULT 0, + CanFlower BIT NOT NULL DEFAULT 0, + CanLike BIT NOT NULL DEFAULT 0, + CanDeleteOtherPost BIT NOT NULL DEFAULT 0, + CreatedAt DATETIME NULL, + UpdatedAt DATETIME NULL, + CONSTRAINT UQ_IdentityGroupPermissions_GroupId UNIQUE (IdentityGroupId), + CONSTRAINT FK_IdentityGroupPermissions_Group FOREIGN KEY (IdentityGroupId) REFERENCES T_IdentityGroups(Id) ON DELETE CASCADE + ); + PRINT '✓ T_IdentityGroupPermissions 表创建成功' +END +ELSE + PRINT '⚠ T_IdentityGroupPermissions 表已存在,跳过' + +-- 6.4 创建用户身份组关联表 +IF OBJECT_ID('T_UserIdentityGroups', 'U') IS NULL +BEGIN + CREATE TABLE T_UserIdentityGroups ( + Id INT IDENTITY(1,1) PRIMARY KEY, + UserId BIGINT NOT NULL, + IdentityGroupId INT NOT NULL, + CreatedAt DATETIME NULL, + CONSTRAINT FK_UserIdentityGroups_User FOREIGN KEY (UserId) REFERENCES T_Users(Id), + CONSTRAINT FK_UserIdentityGroups_Group FOREIGN KEY (IdentityGroupId) REFERENCES T_IdentityGroups(Id) ON DELETE CASCADE, + CONSTRAINT UQ_UserIdentityGroups UNIQUE (UserId, IdentityGroupId) + ); + PRINT '✓ T_UserIdentityGroups 表创建成功' +END +ELSE + PRINT '⚠ T_UserIdentityGroups 表已存在,跳过' + +-- 6.5 插入默认身份组"普通用户" +IF NOT EXISTS (SELECT 1 FROM T_IdentityGroups WHERE IsDefault = 1) +BEGIN + INSERT INTO T_IdentityGroups (Name, IsDefault, CreatedAt) + VALUES (N'普通用户', 1, GETDATE()); + PRINT '✓ 默认身份组"普通用户"插入成功' +END +ELSE + PRINT '⚠ 默认身份组已存在,跳过' + +-- 6.6 为所有现有用户关联默认身份组 +DECLARE @DefaultGroupId INT; +SELECT @DefaultGroupId = Id FROM T_IdentityGroups WHERE IsDefault = 1; + +IF @DefaultGroupId IS NOT NULL +BEGIN + INSERT INTO T_UserIdentityGroups (UserId, IdentityGroupId, CreatedAt) + SELECT u.Id, @DefaultGroupId, GETDATE() + FROM T_Users u + WHERE NOT EXISTS ( + SELECT 1 FROM T_UserIdentityGroups uig + WHERE uig.UserId = u.Id AND uig.IdentityGroupId = @DefaultGroupId + ); + + DECLARE @InsertedCount INT = @@ROWCOUNT; + PRINT '✓ 已为 ' + CAST(@InsertedCount AS NVARCHAR(10)) + ' 个现有用户关联默认身份组' +END + +COMMIT TRANSACTION; +PRINT '✓ 身份权限设置事务已提交' +PRINT '' + +-- ########################################################## +-- 模块7: 点赞唯一索引 +-- ########################################################## +PRINT '>>> 模块7: 点赞唯一索引' +PRINT '' + +IF NOT EXISTS ( + SELECT 1 FROM sys.indexes + WHERE name = 'IX_T_Likes_User_Target' AND object_id = OBJECT_ID('T_Likes') +) +BEGIN + CREATE UNIQUE NONCLUSTERED INDEX IX_T_Likes_User_Target + ON T_Likes(UserId, TargetType, TargetId); + PRINT '✓ IX_T_Likes_User_Target 唯一索引创建成功' +END +ELSE + PRINT '⚠ IX_T_Likes_User_Target 索引已存在,跳过' + +PRINT '' + +-- ########################################################## +-- 模块8: 消息系统字段扩展 +-- ########################################################## +PRINT '>>> 模块8: 消息系统字段扩展' +PRINT '' + +IF NOT EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('T_Messages') AND name = 'MessageTitle') +BEGIN + ALTER TABLE T_Messages ADD MessageTitle NVARCHAR(200) NULL; + PRINT '✓ T_Messages.MessageTitle 字段添加成功' +END + +IF NOT EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('T_Messages') AND name = 'SenderInfo') +BEGIN + ALTER TABLE T_Messages ADD SenderInfo NVARCHAR(MAX) NULL; + PRINT '✓ T_Messages.SenderInfo 字段添加成功' +END + +IF NOT EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('T_Messages') AND name = 'EventId') +BEGIN + ALTER TABLE T_Messages ADD EventId NVARCHAR(50) NULL; + PRINT '✓ T_Messages.EventId 字段添加成功' +END + +IF NOT EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('T_Messages') AND name = 'ContentSnapshot') +BEGIN + ALTER TABLE T_Messages ADD ContentSnapshot NVARCHAR(MAX) NULL; + PRINT '✓ T_Messages.ContentSnapshot 字段添加成功' +END + +IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_T_Messages_EventId' AND object_id = OBJECT_ID('T_Messages')) +BEGIN + CREATE INDEX IX_T_Messages_EventId ON T_Messages(EventId); + PRINT '✓ IX_T_Messages_EventId 索引创建成功' +END + +PRINT '' + +-- ########################################################## +-- 模块9: 消息系统重构(数据迁移) +-- ⚠ 注意: 此模块会删除关注消息(MessageType=3)并重新编号系统通知(4→3) +-- ⚠ 执行前请确认已备份数据! +-- ########################################################## +PRINT '>>> 模块9: 消息系统重构' +PRINT '' + +BEGIN TRANSACTION; + +-- 9.1 备份现有消息数据 +IF OBJECT_ID('T_Messages_Backup_BeforeRefactor', 'U') IS NOT NULL +BEGIN + DROP TABLE T_Messages_Backup_BeforeRefactor; + PRINT '已删除旧的备份表' +END + +SELECT * INTO T_Messages_Backup_BeforeRefactor FROM T_Messages; +PRINT '✓ 消息数据已备份到 T_Messages_Backup_BeforeRefactor' + +-- 9.2 删除关注消息(MessageType = 3) +DECLARE @DeletedFollowCount INT; +SELECT @DeletedFollowCount = COUNT(*) FROM T_Messages WHERE MessageType = 3; +DELETE FROM T_Messages WHERE MessageType = 3; +PRINT '✓ 已删除 ' + CAST(@DeletedFollowCount AS NVARCHAR(10)) + ' 条关注消息' + +-- 9.3 调整系统通知类型:4 → 3 +DECLARE @SystemNotificationCount INT; +SELECT @SystemNotificationCount = COUNT(*) FROM T_Messages WHERE MessageType = 4; +UPDATE T_Messages SET MessageType = 3 WHERE MessageType = 4; +PRINT '✓ 已将 ' + CAST(@SystemNotificationCount AS NVARCHAR(10)) + ' 条系统通知类型从 4 调整为 3' + +-- 9.4 增加 MyCommentContent 字段 +IF NOT EXISTS ( + SELECT * FROM sys.columns + WHERE object_id = OBJECT_ID(N'dbo.T_Messages') AND name = 'MyCommentContent' +) +BEGIN + ALTER TABLE T_Messages ADD MyCommentContent NVARCHAR(MAX) NULL; + PRINT '✓ T_Messages.MyCommentContent 字段添加成功' + + EXEC sp_addextendedproperty + @name = N'MS_Description', + @value = N'我的评论内容(回复消息展示被回复的内容)', + @level0type = N'SCHEMA', @level0name = N'dbo', + @level1type = N'TABLE', @level1name = N'T_Messages', + @level2type = N'COLUMN', @level2name = N'MyCommentContent'; +END +ELSE + PRINT '⚠ MyCommentContent 字段已存在,跳过' + +-- 9.5 更新字段注释 +IF EXISTS ( + SELECT * FROM sys.extended_properties + WHERE major_id = OBJECT_ID('dbo.T_Messages') + AND name = 'MS_Description' + AND minor_id = (SELECT column_id FROM sys.columns WHERE object_id = OBJECT_ID('dbo.T_Messages') AND name = 'MessageType') +) + EXEC sp_updateextendedproperty + @name = N'MS_Description', + @value = N'消息类型:1-回复消息,2-点赞消息(含送花),3-系统消息', + @level0type = N'SCHEMA', @level0name = N'dbo', + @level1type = N'TABLE', @level1name = N'T_Messages', + @level2type = N'COLUMN', @level2name = N'MessageType'; +ELSE + EXEC sp_addextendedproperty + @name = N'MS_Description', + @value = N'消息类型:1-回复消息,2-点赞消息(含送花),3-系统消息', + @level0type = N'SCHEMA', @level0name = N'dbo', + @level1type = N'TABLE', @level1name = N'T_Messages', + @level2type = N'COLUMN', @level2name = N'MessageType'; + +IF EXISTS ( + SELECT * FROM sys.extended_properties + WHERE major_id = OBJECT_ID('dbo.T_Messages') + AND name = 'MS_Description' + AND minor_id = (SELECT column_id FROM sys.columns WHERE object_id = OBJECT_ID('dbo.T_Messages') AND name = 'ContentType') +) + EXEC sp_updateextendedproperty + @name = N'MS_Description', + @value = N'内容类型:1-帖子,2-评论,3-送花', + @level0type = N'SCHEMA', @level0name = N'dbo', + @level1type = N'TABLE', @level1name = N'T_Messages', + @level2type = N'COLUMN', @level2name = N'ContentType'; +ELSE + EXEC sp_addextendedproperty + @name = N'MS_Description', + @value = N'内容类型:1-帖子,2-评论,3-送花', + @level0type = N'SCHEMA', @level0name = N'dbo', + @level1type = N'TABLE', @level1name = N'T_Messages', + @level2type = N'COLUMN', @level2name = N'ContentType'; + +COMMIT TRANSACTION; +PRINT '✓ 消息系统重构事务已提交' +PRINT '' + +-- ########################################################## +-- 升级完成 +-- ########################################################## +PRINT '==========================================' +PRINT 'v1.2.0 业务库完整升级脚本执行完成!' +PRINT '完成时间: ' + CONVERT(VARCHAR, GETDATE(), 120) +PRINT '==========================================' +PRINT '' +PRINT '升级内容总结:' +PRINT ' 模块1: CDK 激活系统 (T_CDKs, T_SystemSettings, T_Users 字段)' +PRINT ' 模块2: 实名认证 (T_Users 字段, T_RealNameVerifyLogs, 系统配置)' +PRINT ' 模块3: 帖子回复权限 (T_Posts.AllowReply)' +PRINT ' 模块4: 发帖回复时间间隔 (T_PostReplyIntervals)' +PRINT ' 模块5: 防沉迷规则 (T_AntiAddictionRules)' +PRINT ' 模块6: 身份权限设置 (4张表 + 默认身份组 + 用户关联)' +PRINT ' 模块7: 点赞唯一索引 (IX_T_Likes_User_Target)' +PRINT ' 模块8: 消息系统字段扩展 (T_Messages 4个新字段)' +PRINT ' 模块9: 消息系统重构 (类型调整 + MyCommentContent)' +PRINT '' +PRINT '注意事项:' +PRINT ' - 模块9 已备份消息到 T_Messages_Backup_BeforeRefactor,确认无误后可手动删除' +PRINT ' - 请在应用层清理 Redis 队列: DEL message:events:follow' +PRINT ' - 请确保应用程序代码已同步更新' +PRINT '==========================================' diff --git a/server/webapi/数据库脚本/v1.2.0_ALL_管理库.sql b/server/webapi/数据库脚本/v1.2.0_ALL_管理库.sql new file mode 100644 index 0000000..681e03c --- /dev/null +++ b/server/webapi/数据库脚本/v1.2.0_ALL_管理库.sql @@ -0,0 +1,157 @@ +-- ========================================== +-- 团播机构 v1.2.0 管理库 (admin) 完整菜单配置脚本 +-- 整合时间: 2025-01-25 +-- 说明: 整合所有 v1.2.0 后台管理菜单和权限配置 +-- 数据库: 后台管理数据库 (admin) +-- ========================================== +-- 包含模块: +-- 1. CDK 管理菜单 + 权限按钮 +-- 2. 发帖回复时间间隔配置菜单 + 权限按钮 +-- 3. 防沉迷规则管理菜单 + 权限按钮 +-- ========================================== + +PRINT '==========================================' +PRINT '开始执行 v1.2.0 管理库完整菜单配置脚本' +PRINT '执行时间: ' + CONVERT(VARCHAR, GETDATE(), 120) +PRINT '==========================================' +PRINT '' + +-- ########################################################## +-- 模块1: CDK 管理菜单 +-- ########################################################## +PRINT '>>> 模块1: CDK 管理菜单' +PRINT '' + +IF NOT EXISTS (SELECT 1 FROM sys_menu WHERE path = 'tcdk' AND component = 'liveforum/tcdk') +BEGIN + INSERT INTO sys_menu (menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) + VALUES ('CDK管理', 1233, 10, 'tcdk', 'liveforum/tcdk', 1, 0, 'C', '0', '0', 'cdk:list', 'key', 'admin', GETDATE(), 'admin', GETDATE(), 'CDK激活码管理'); + + DECLARE @cdkMenuId BIGINT = SCOPE_IDENTITY(); + PRINT '✓ CDK 管理菜单插入成功,menuId: ' + CAST(@cdkMenuId AS VARCHAR); + + -- 权限按钮 + INSERT INTO sys_menu (menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) + VALUES ('查询', @cdkMenuId, 1, '#', NULL, 1, 0, 'F', '0', '0', 'cdk:query', '#', 'admin', GETDATE(), 'admin', GETDATE(), NULL); + + INSERT INTO sys_menu (menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) + VALUES ('生成', @cdkMenuId, 2, '#', NULL, 1, 0, 'F', '0', '0', 'cdk:generate', '#', 'admin', GETDATE(), 'admin', GETDATE(), NULL); + + INSERT INTO sys_menu (menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) + VALUES ('删除', @cdkMenuId, 3, '#', NULL, 1, 0, 'F', '0', '0', 'cdk:delete', '#', 'admin', GETDATE(), 'admin', GETDATE(), NULL); + + INSERT INTO sys_menu (menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) + VALUES ('导出', @cdkMenuId, 4, '#', NULL, 1, 0, 'F', '0', '0', 'cdk:export', '#', 'admin', GETDATE(), 'admin', GETDATE(), NULL); + + INSERT INTO sys_menu (menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) + VALUES ('设置', @cdkMenuId, 5, '#', NULL, 1, 0, 'F', '0', '0', 'settings:edit', '#', 'admin', GETDATE(), 'admin', GETDATE(), NULL); + + INSERT INTO sys_menu (menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) + VALUES ('查询设置', @cdkMenuId, 6, '#', NULL, 1, 0, 'F', '0', '0', 'settings:query', '#', 'admin', GETDATE(), 'admin', GETDATE(), NULL); + + PRINT '✓ CDK 权限按钮插入成功 (查询/生成/删除/导出/设置/查询设置)' + + -- 为管理员角色分配权限 + INSERT INTO sys_role_menu (Role_id, Menu_id, Create_time) + SELECT 1, menuId, GETDATE() + FROM sys_menu WHERE menuId >= @cdkMenuId; + + PRINT '✓ CDK 菜单权限已分配给管理员角色' +END +ELSE + PRINT '⚠ CDK 管理菜单已存在,跳过' + +PRINT '' + +-- ########################################################## +-- 模块2: 发帖回复时间间隔配置菜单 +-- ########################################################## +PRINT '>>> 模块2: 发帖回复时间间隔配置菜单' +PRINT '' + +IF NOT EXISTS (SELECT 1 FROM sys_menu WHERE path = 'tpostreplyintervals' AND component = 'liveforum/tpostreplyintervals') +BEGIN + INSERT INTO sys_menu (menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) + VALUES ('时间间隔配置', 1233, 12, 'tpostreplyintervals', 'liveforum/tpostreplyintervals', 1, 0, 'C', '0', '0', 'tpostreplyintervals:list', 'time-range', 'admin', GETDATE(), 'admin', GETDATE(), '发帖回复时间间隔配置'); + + DECLARE @intervalMenuId BIGINT = SCOPE_IDENTITY(); + PRINT '✓ 时间间隔配置菜单插入成功,menuId: ' + CAST(@intervalMenuId AS VARCHAR); + + -- 权限按钮 + INSERT INTO sys_menu (menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) + VALUES ('查询', @intervalMenuId, 1, '', NULL, 1, 0, 'F', '0', '0', 'tpostreplyintervals:list', '#', 'admin', GETDATE(), 'admin', GETDATE(), NULL); + + INSERT INTO sys_menu (menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) + VALUES ('编辑', @intervalMenuId, 2, '', NULL, 1, 0, 'F', '0', '0', 'tpostreplyintervals:edit', '#', 'admin', GETDATE(), 'admin', GETDATE(), NULL); + + PRINT '✓ 时间间隔配置权限按钮插入成功 (查询/编辑)' + + -- 为管理员角色分配权限 + INSERT INTO sys_role_menu (Role_id, Menu_id, Create_time) + SELECT 1, menuId, GETDATE() + FROM sys_menu WHERE menuId >= @intervalMenuId; + + PRINT '✓ 时间间隔配置菜单权限已分配给管理员角色' +END +ELSE + PRINT '⚠ 时间间隔配置菜单已存在,跳过' + +PRINT '' + +-- ########################################################## +-- 模块3: 防沉迷规则管理菜单 +-- ########################################################## +PRINT '>>> 模块3: 防沉迷规则管理菜单' +PRINT '' + +IF NOT EXISTS (SELECT 1 FROM sys_menu WHERE path = 'tantiaddictionrules' AND component = 'liveforum/tantiaddictionrules/index') +BEGIN + INSERT INTO sys_menu (menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) + VALUES ('防沉迷规则', 1233, 13, 'tantiaddictionrules', 'liveforum/tantiaddictionrules/index', 1, 0, 'C', '0', '0', 'tantiaddictionrules:list', 'time-range', 'admin', GETDATE(), 'admin', GETDATE(), '防沉迷规则配置管理'); + + DECLARE @antiAddictionMenuId BIGINT = SCOPE_IDENTITY(); + PRINT '✓ 防沉迷规则管理菜单插入成功,menuId: ' + CAST(@antiAddictionMenuId AS VARCHAR); + + -- 权限按钮 + INSERT INTO sys_menu (menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) + VALUES ('查询', @antiAddictionMenuId, 1, '#', NULL, 1, 0, 'F', '0', '0', 'tantiaddictionrules:query', '#', 'admin', GETDATE(), 'admin', GETDATE(), NULL); + + INSERT INTO sys_menu (menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) + VALUES ('新增', @antiAddictionMenuId, 2, '#', NULL, 1, 0, 'F', '0', '0', 'tantiaddictionrules:add', '#', 'admin', GETDATE(), 'admin', GETDATE(), NULL); + + INSERT INTO sys_menu (menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) + VALUES ('编辑', @antiAddictionMenuId, 3, '#', NULL, 1, 0, 'F', '0', '0', 'tantiaddictionrules:edit', '#', 'admin', GETDATE(), 'admin', GETDATE(), NULL); + + INSERT INTO sys_menu (menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) + VALUES ('删除', @antiAddictionMenuId, 4, '#', NULL, 1, 0, 'F', '0', '0', 'tantiaddictionrules:delete', '#', 'admin', GETDATE(), 'admin', GETDATE(), NULL); + + PRINT '✓ 防沉迷规则权限按钮插入成功 (查询/新增/编辑/删除)' + + -- 为管理员角色分配权限 + INSERT INTO sys_role_menu (Role_id, Menu_id, Create_time) + SELECT 1, menuId, GETDATE() + FROM sys_menu WHERE menuId >= @antiAddictionMenuId; + + PRINT '✓ 防沉迷规则菜单权限已分配给管理员角色' +END +ELSE + PRINT '⚠ 防沉迷规则管理菜单已存在,跳过' + +PRINT '' + +-- ########################################################## +-- 配置完成 +-- ########################################################## +PRINT '==========================================' +PRINT 'v1.2.0 管理库完整菜单配置脚本执行完成!' +PRINT '完成时间: ' + CONVERT(VARCHAR, GETDATE(), 120) +PRINT '==========================================' +PRINT '' +PRINT '配置内容总结:' +PRINT ' 模块1: CDK 管理菜单 (6个权限按钮: 查询/生成/删除/导出/设置/查询设置)' +PRINT ' 模块2: 时间间隔配置菜单 (2个权限按钮: 查询/编辑)' +PRINT ' 模块3: 防沉迷规则管理菜单 (4个权限按钮: 查询/新增/编辑/删除)' +PRINT '' +PRINT '注意: 所有菜单位于"系统配置"(parentId=1233)目录下' +PRINT ' 需要刷新浏览器或重新登录才能看到新菜单' +PRINT '==========================================' diff --git a/前端/live-forum/modules/Config.js b/前端/live-forum/modules/Config.js index ec6e1f5..2b86794 100644 --- a/前端/live-forum/modules/Config.js +++ b/前端/live-forum/modules/Config.js @@ -13,9 +13,9 @@ var Config = Config || {} // Config.API_BASE_URL = 'http://localhost:8080' // Config.API_BASE_URL = 'https://liveforum.api.zpc-xy.com' // Config.API_BASE_URL = 'http://192.168.195.15:2408' // 备用地址 -// Config.API_BASE_URL = 'https://api.skzhijia.com' // 现网地址 +Config.API_BASE_URL = 'https://api.skzhijia.com' // 现网地址 -Config.API_BASE_URL = 'https://api.xkx.shhmkjgs.cn' // 备用地址 +// Config.API_BASE_URL = 'https://api.xkx.shhmkjgs.cn' // 备用地址 // Config.API_BASE_URL = 'http://175.27.168.122:82' // 备用地址 @@ -45,8 +45,8 @@ Config.UPLOAD_CONFIG = { videoMaxSize: 100 * 1024 * 1024, // 100MB // COS域名(如果使用COS上传) - cosDomain: 'https://miaoyu-1308826010.cos.ap-shanghai.myqcloud.com' - // cosDomain: 'https://skzjmp-1377391978.cos.ap-nanjing.myqcloud.com' + // cosDomain: 'https://miaoyu-1308826010.cos.ap-shanghai.myqcloud.com' + cosDomain: 'https://skzjmp-1377391978.cos.ap-nanjing.myqcloud.com' } // 不同场景的上传配置预设