From 1a44eab144ec115b4318d6fd47ff9dde6cea8cad Mon Sep 17 00:00:00 2001 From: Mrx <18278715334@163.com> Date: Tue, 27 Jan 2026 15:08:00 +0800 Subject: [PATCH] f --- .gitignore | 3 + app/main/api/desc/admin/order.api | 3 + app/main/api/etc/main.dev.yaml | 2 +- .../admin_order/admingetorderlistlogic.go | 108 + .../internal/logic/app/getappversionlogic.go | 2 +- .../internal/logic/pay/alipaycallbacklogic.go | 18 + .../api/internal/logic/pay/paymentlogic.go | 193 +- .../logic/pay/wechatpaycallbacklogic.go | 18 + .../internal/logic/query/queryservicelogic.go | 114 +- .../api/internal/queue/paySuccessNotify.go | 4 +- app/main/api/internal/svc/servicecontext.go | 3 + app/main/api/internal/types/adminorder.go | 3 + app/main/model/queryUserRecordModel.go | 27 + app/main/model/queryUserRecordModel_gen.go | 394 ++++ deploy/script/gen_models.ps1 | 5 +- deploy/sql/README_表结构修改说明.md | 320 --- deploy/sql/add_agent_short_link_table.sql | 47 - deploy/sql/add_invite_code_usage_table.sql | 46 - deploy/sql/agent_config_migration.sql | 56 - deploy/sql/agent_freeze_task_migration.sql | 32 - deploy/sql/agent_system_migration.sql | 386 ---- deploy/sql/generate_agent_models.md | 190 -- deploy/sql/generate_agent_models.sh | 70 - deploy/sql/query_user_record.sql | 52 + deploy/sql/query_user_record_add_indexes.sql | 66 + ...product_name_from_agent_product_config.sql | 25 - deploy/sql/sync_agent_product_config.sql | 112 - deploy/sql/template.sql | 62 - deploy/sql/user_system_refactor.sql | 48 - deploy/sql/user_temp_migration.sql | 45 - deploy/sql/uuid_migration.sql | 1831 ----------------- deploy/sql/uuid_migration_simple.sql | 446 ---- docker-compose.dev.yml | 1 + 33 files changed, 999 insertions(+), 3733 deletions(-) create mode 100644 app/main/model/queryUserRecordModel.go create mode 100644 app/main/model/queryUserRecordModel_gen.go delete mode 100644 deploy/sql/README_表结构修改说明.md delete mode 100644 deploy/sql/add_agent_short_link_table.sql delete mode 100644 deploy/sql/add_invite_code_usage_table.sql delete mode 100644 deploy/sql/agent_config_migration.sql delete mode 100644 deploy/sql/agent_freeze_task_migration.sql delete mode 100644 deploy/sql/agent_system_migration.sql delete mode 100644 deploy/sql/generate_agent_models.md delete mode 100644 deploy/sql/generate_agent_models.sh create mode 100644 deploy/sql/query_user_record.sql create mode 100644 deploy/sql/query_user_record_add_indexes.sql delete mode 100644 deploy/sql/remove_product_name_from_agent_product_config.sql delete mode 100644 deploy/sql/sync_agent_product_config.sql delete mode 100644 deploy/sql/template.sql delete mode 100644 deploy/sql/user_system_refactor.sql delete mode 100644 deploy/sql/user_temp_migration.sql delete mode 100644 deploy/sql/uuid_migration.sql delete mode 100644 deploy/sql/uuid_migration_simple.sql diff --git a/.gitignore b/.gitignore index 832cc89..41f52da 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,6 @@ documents/* !documents/.gitkeep deploy/script/js + +# 授权文档 +app/main/api/data/authorization_docs/ diff --git a/app/main/api/desc/admin/order.api b/app/main/api/desc/admin/order.api index 47c7d1f..a826c0b 100644 --- a/app/main/api/desc/admin/order.api +++ b/app/main/api/desc/admin/order.api @@ -59,6 +59,9 @@ type ( PayTimeEnd string `form:"pay_time_end,optional"` // 支付时间结束 RefundTimeStart string `form:"refund_time_start,optional"` // 退款时间开始 RefundTimeEnd string `form:"refund_time_end,optional"` // 退款时间结束 + QueryUserName string `form:"query_user_name,optional"` // 被查询人姓名 + QueryUserIdCard string `form:"query_user_id_card,optional"` // 被查询人身份证号 + QueryUserMobile string `form:"query_user_mobile,optional"` // 被查询人手机号 } // 列表响应 AdminGetOrderListResp { diff --git a/app/main/api/etc/main.dev.yaml b/app/main/api/etc/main.dev.yaml index 5e03f10..cd0805b 100644 --- a/app/main/api/etc/main.dev.yaml +++ b/app/main/api/etc/main.dev.yaml @@ -86,7 +86,7 @@ Tianyuanapi: BaseURL: "https://api.tianyuanapi.com" Timeout: 60 Authorization: - FileBaseURL: "https://www.quannengcha.com/api/v1/auth-docs" # 授权书文件访问基础URL + FileBaseURL: "https://www.zhenaicha.com/api/v1/auth-docs" # 授权书文件访问基础URL Promotion: PromotionDomain: "http://localhost:8888" # 推广域名(用于生成短链) OfficialDomain: "http://localhost:5678" # 正式站点域名(短链重定向的目标域名) diff --git a/app/main/api/internal/logic/admin_order/admingetorderlistlogic.go b/app/main/api/internal/logic/admin_order/admingetorderlistlogic.go index 4b10409..b011bcf 100644 --- a/app/main/api/internal/logic/admin_order/admingetorderlistlogic.go +++ b/app/main/api/internal/logic/admin_order/admingetorderlistlogic.go @@ -2,6 +2,7 @@ package admin_order import ( "context" + "encoding/hex" "sync" "qnc-server/app/main/api/internal/svc" @@ -9,6 +10,7 @@ import ( "qnc-server/app/main/model" "qnc-server/common/globalkey" "qnc-server/common/xerr" + "qnc-server/pkg/lzkit/crypto" "github.com/Masterminds/squirrel" "github.com/pkg/errors" @@ -74,6 +76,112 @@ func (l *AdminGetOrderListLogic) AdminGetOrderList(req *types.AdminGetOrderListR builder = builder.Where("refund_time <= ?", req.RefundTimeEnd) } + // 根据被查询人信息筛选订单(姓名、身份证、手机号) + // 由于数据是加密存储的,需要先加密查询条件,然后通过子查询筛选 + // 支持单独使用任一要素查询,也支持组合查询(AND 关系) + if req.QueryUserName != "" || req.QueryUserIdCard != "" || req.QueryUserMobile != "" { + // 获取加密密钥 + secretKey := l.svcCtx.Config.Encrypt.SecretKey + key, decodeErr := hex.DecodeString(secretKey) + if decodeErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminGetOrderList, 解析加密密钥失败 err: %v", decodeErr) + } + + // 构建查询条件 + queryUserRecordBuilder := l.svcCtx.QueryUserRecordModel.SelectBuilder(). + Where("del_state = ?", globalkey.DelStateNo) + + // 加密并添加姓名筛选条件 + if req.QueryUserName != "" { + encryptedName, err := crypto.AesEcbEncrypt([]byte(req.QueryUserName), key) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminGetOrderList, 加密姓名失败 err: %v", err) + } + logx.Infof("AdminGetOrderList, 姓名加密: 明文=%s, 密文=%s", req.QueryUserName, encryptedName) + queryUserRecordBuilder = queryUserRecordBuilder.Where("name = ?", encryptedName) + } + + // 加密并添加身份证筛选条件 + if req.QueryUserIdCard != "" { + encryptedIdCard, err := crypto.EncryptIDCard(req.QueryUserIdCard, key) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminGetOrderList, 加密身份证号失败 err: %v", err) + } + logx.Infof("AdminGetOrderList, 身份证号加密: 明文=%s, 密文=%s", req.QueryUserIdCard, encryptedIdCard) + queryUserRecordBuilder = queryUserRecordBuilder.Where("id_card = ?", encryptedIdCard) + } + + // 加密并添加手机号筛选条件 + if req.QueryUserMobile != "" { + encryptedMobile, err := crypto.EncryptMobile(req.QueryUserMobile, secretKey) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminGetOrderList, 加密手机号失败 err: %v", err) + } + logx.Infof("AdminGetOrderList, 手机号加密: 明文=%s, 密文=%s", req.QueryUserMobile, encryptedMobile) + queryUserRecordBuilder = queryUserRecordBuilder.Where("mobile = ?", encryptedMobile) + } + + // 先查询符合条件的记录(包含 order_id 和 query_no) + queryUserRecords, err := l.svcCtx.QueryUserRecordModel.FindAll(l.ctx, queryUserRecordBuilder, "") + if err != nil && !errors.Is(err, model.ErrNotFound) { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderList, 查询用户记录失败 err: %v", err) + } + logx.Infof("AdminGetOrderList, 查询条件: 姓名=%s, 身份证=%s, 手机号=%s, 查询到 %d 条匹配的查询用户记录", + req.QueryUserName, req.QueryUserIdCard, req.QueryUserMobile, len(queryUserRecords)) + + if len(queryUserRecords) == 0 { + // 如果没有匹配的记录,返回空结果 + logx.Infof("AdminGetOrderList, 未找到匹配的查询用户记录,返回空结果") + return &types.AdminGetOrderListResp{ + Total: 0, + Items: []types.OrderListItem{}, + }, nil + } + + // 提取 order_id 和 query_no 列表 + orderIds := make([]string, 0, len(queryUserRecords)) + queryNos := make([]string, 0, len(queryUserRecords)) + + for _, record := range queryUserRecords { + // 优先使用 order_id(如果已创建订单) + if record.OrderId.Valid && record.OrderId.String != "" { + orderIds = append(orderIds, record.OrderId.String) + } + // 同时收集 query_no(用于关联订单,query_no 与 order.order_no 一致) + if record.QueryNo != "" { + queryNos = append(queryNos, record.QueryNo) + } + } + + logx.Infof("AdminGetOrderList, 提取到 %d 个 order_id, %d 个 query_no", len(orderIds), len(queryNos)) + + // 构建订单筛选条件 + // 使用 OR 条件:通过 order.id 或 order.order_no 匹配 + if len(orderIds) > 0 && len(queryNos) > 0 { + // 同时有 order_id 和 query_no,使用 OR 条件 + builder = builder.Where(squirrel.Or{ + squirrel.Eq{"id": orderIds}, + squirrel.Eq{"order_no": queryNos}, + }) + logx.Infof("AdminGetOrderList, 使用 OR 条件: order_id IN (%d个), order_no IN (%d个)", len(orderIds), len(queryNos)) + } else if len(orderIds) > 0 { + // 只有 order_id + builder = builder.Where(squirrel.Eq{"id": orderIds}) + logx.Infof("AdminGetOrderList, 使用 order_id 条件: %d 个订单ID", len(orderIds)) + } else if len(queryNos) > 0 { + // 只有 query_no + builder = builder.Where(squirrel.Eq{"order_no": queryNos}) + logx.Infof("AdminGetOrderList, 使用 query_no 条件: %d 个查询单号", len(queryNos)) + } else { + // 如果没有有效的订单ID或查询单号,返回空结果 + logx.Infof("AdminGetOrderList, 未找到有效的订单ID或查询单号,返回空结果") + return &types.AdminGetOrderListResp{ + Total: 0, + Items: []types.OrderListItem{}, + }, nil + } + } + // 并发获取总数和列表 var total int64 var orders []*model.Order diff --git a/app/main/api/internal/logic/app/getappversionlogic.go b/app/main/api/internal/logic/app/getappversionlogic.go index 109121f..4cd210f 100644 --- a/app/main/api/internal/logic/app/getappversionlogic.go +++ b/app/main/api/internal/logic/app/getappversionlogic.go @@ -26,6 +26,6 @@ func NewGetAppVersionLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Get func (l *GetAppVersionLogic) GetAppVersion() (resp *types.GetAppVersionResp, err error) { return &types.GetAppVersionResp{ Version: "1.0.0", - WgtUrl: "https://www.quannengcha.com/app_version/qnc_1.0.0.wgt", + WgtUrl: "https://www.zhenaicha.com/app_version/qnc_1.0.0.wgt", }, nil } diff --git a/app/main/api/internal/logic/pay/alipaycallbacklogic.go b/app/main/api/internal/logic/pay/alipaycallbacklogic.go index 5e5a9f0..74a0565 100644 --- a/app/main/api/internal/logic/pay/alipaycallbacklogic.go +++ b/app/main/api/internal/logic/pay/alipaycallbacklogic.go @@ -99,6 +99,24 @@ func (l *AlipayCallbackLogic) handleQueryOrderPayment(w http.ResponseWriter, not return nil } + // 更新 query_user_record 表的 platform_order_id + queryUserRecords, findRecordErr := l.svcCtx.QueryUserRecordModel.FindAll(l.ctx, + l.svcCtx.QueryUserRecordModel.SelectBuilder(). + Where("query_no = ?", notification.OutTradeNo). + Where("del_state = ?", 0). + Limit(1), "") + if findRecordErr == nil && len(queryUserRecords) > 0 { + record := queryUserRecords[0] + record.PlatformOrderId = lzUtils.StringToNullString(notification.TradeNo) + record.Version = record.Version + 1 + if updateRecordErr := l.svcCtx.QueryUserRecordModel.UpdateWithVersion(l.ctx, nil, record); updateRecordErr != nil { + logx.Errorf("支付宝支付回调,更新查询用户记录失败: %+v", updateRecordErr) + // 更新失败不影响主流程,只记录日志 + } else { + logx.Infof("支付宝支付回调,更新查询用户记录成功,query_no: %s, platform_order_id: %s", notification.OutTradeNo, notification.TradeNo) + } + } + if order.Status == "paid" { if asyncErr := l.svcCtx.AsynqService.SendQueryTask(order.Id); asyncErr != nil { logx.Errorf("异步任务调度失败: %v", asyncErr) diff --git a/app/main/api/internal/logic/pay/paymentlogic.go b/app/main/api/internal/logic/pay/paymentlogic.go index 070d15a..1609741 100644 --- a/app/main/api/internal/logic/pay/paymentlogic.go +++ b/app/main/api/internal/logic/pay/paymentlogic.go @@ -3,19 +3,23 @@ package pay import ( "context" "database/sql" + "encoding/hex" "encoding/json" "fmt" "os" - "strconv" - "strings" - "time" "qnc-server/app/main/api/internal/svc" "qnc-server/app/main/api/internal/types" "qnc-server/app/main/model" "qnc-server/common/ctxdata" + "qnc-server/common/globalkey" "qnc-server/common/xerr" + "qnc-server/pkg/lzkit/crypto" "qnc-server/pkg/lzkit/lzUtils" + "strconv" + "strings" + "time" + "github.com/Masterminds/squirrel" "github.com/google/uuid" "github.com/pkg/errors" "github.com/redis/go-redis/v9" @@ -241,6 +245,16 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 获取代理链接失败: %+v", findAgentLinkErr) } amount = agentLinkModel.SetPrice + + // 检查被查询人身份证在72小时内的已支付订单次数 + // 如果是代理渠道订单,需要检查该身份证在72小时内已支付的订单是否超过2次 + logx.Infof("生成订单, 检测到代理渠道订单,开始检查订单限制, AgentIdentifier: %s", data.AgentIdentifier) + checkErr := l.checkIdCardPaidOrdersIn72Hours(data.Params) + if checkErr != nil { + logx.Errorf("生成订单, 订单限制检查失败: %v", checkErr) + return nil, checkErr + } + logx.Infof("生成订单, 订单限制检查通过,允许创建订单") } else { amount = product.SellPrice } @@ -264,6 +278,24 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses } orderID := order.Id + // 更新 query_user_record 表的 order_id(通过 query_no 匹配) + queryUserRecords, findRecordErr := l.svcCtx.QueryUserRecordModel.FindAll(l.ctx, + l.svcCtx.QueryUserRecordModel.SelectBuilder(). + Where("query_no = ?", outTradeNo). + Where("del_state = ?", 0). + Limit(1), "") + if findRecordErr == nil && len(queryUserRecords) > 0 { + record := queryUserRecords[0] + record.OrderId = lzUtils.StringToNullString(orderID) + record.Version = record.Version + 1 + if updateRecordErr := l.svcCtx.QueryUserRecordModel.UpdateWithVersion(l.ctx, session, record); updateRecordErr != nil { + logx.Errorf("更新查询用户记录 order_id 失败: %+v", updateRecordErr) + // 更新失败不影响主流程,只记录日志 + } else { + logx.Infof("更新查询用户记录成功,query_no: %s, order_id: %s", outTradeNo, orderID) + } + } + // 如果是代理推广订单,创建完整的代理订单记录 if data.AgentIdentifier != "" && agentLinkModel != nil { // 获取代理信息 @@ -473,3 +505,158 @@ func (l *PaymentLogic) getConfigFloat(configKey string) (float64, error) { } return value, nil } + +// checkIdCardPaidOrdersIn72Hours 检查被查询人身份证在72小时内的已支付订单次数 +// 如果72小时内已支付订单大于2次,则返回错误 +// encryptedParams: 加密的参数字符串(data.Params),需要解密后获取身份证号 +func (l *PaymentLogic) checkIdCardPaidOrdersIn72Hours(encryptedParams string) error { + logx.Infof("检查订单限制, 开始检查代理渠道订单限制, encryptedParams长度: %d", len(encryptedParams)) + + // 1. 解密参数获取身份证号 + secretKey := l.svcCtx.Config.Encrypt.SecretKey + key, decodeErr := hex.DecodeString(secretKey) + if decodeErr != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "检查订单限制, 解析加密密钥失败 err: %v", decodeErr) + } + + // 解密 data.Params(加密的 JSON 字符串) + decryptData, aesDecryptErr := crypto.AesDecrypt(encryptedParams, key) + if aesDecryptErr != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "检查订单限制, 解密参数失败 err: %v", aesDecryptErr) + } + + // 解析解密后的 JSON 获取参数 + var params map[string]interface{} + if unmarshalErr := json.Unmarshal(decryptData, ¶ms); unmarshalErr != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "检查订单限制, 解析参数失败 err: %v, decryptData: %s", unmarshalErr, string(decryptData)) + } + + idCard, ok := params["id_card"].(string) + if !ok || idCard == "" { + // 如果没有身份证号,跳过检查(可能是其他类型的查询) + logx.Infof("检查订单限制, 未找到身份证号,跳过检查") + return nil + } + + logx.Infof("检查订单限制, 被查询人身份证号: %s", idCard) + + // 2. 加密身份证号用于查询 + logx.Infof("检查订单限制, 开始加密身份证号: %s", idCard) + encryptedIdCard, encryptErr := crypto.EncryptIDCard(idCard, key) + if encryptErr != nil { + logx.Errorf("检查订单限制, 加密身份证号失败: %v", encryptErr) + return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "检查订单限制, 加密身份证号失败 err: %v", encryptErr) + } + logx.Infof("检查订单限制, 身份证号加密成功, encryptedIdCard长度: %d", len(encryptedIdCard)) + + // 3. 查询该身份证对应的所有查询记录(agent_identifier IS NOT NULL) + // 统计该身份证的记录数,然后通过order_id关联订单表查询已支付的订单 + encryptedIdCardPreview := encryptedIdCard + if len(encryptedIdCard) > 20 { + encryptedIdCardPreview = encryptedIdCard[:20] + "..." + } + logx.Infof("检查订单限制, 开始查询数据库") + logx.Infof("检查订单限制, 查询条件: id_card=%s, del_state=0, agent_identifier IS NOT NULL, agent_identifier != ''", encryptedIdCardPreview) + logx.Infof("检查订单限制, 注意:不要求order_id必须存在,先查询所有记录") + queryUserRecords, findRecordErr := l.svcCtx.QueryUserRecordModel.FindAll(l.ctx, + l.svcCtx.QueryUserRecordModel.SelectBuilder(). + Where("id_card = ?", encryptedIdCard). + Where("del_state = ?", globalkey.DelStateNo). + Where("agent_identifier IS NOT NULL"). + Where("agent_identifier != ''"), + "") + if findRecordErr != nil { + if errors.Is(findRecordErr, model.ErrNotFound) { + logx.Infof("检查订单限制, 查询结果: 未找到记录 (ErrNotFound)") + } else { + logx.Errorf("检查订单限制, 查询数据库失败: %v", findRecordErr) + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "检查订单限制, 查询用户记录失败 err: %v", findRecordErr) + } + } else { + logx.Infof("检查订单限制, 查询数据库成功") + } + + logx.Infof("检查订单限制, 查询到 %d 条该身份证的查询记录(agent_identifier IS NOT NULL)", len(queryUserRecords)) + + // 统计记录详情 + if len(queryUserRecords) > 0 { + logx.Infof("检查订单限制, ========== 记录详情 ==========") + for i, record := range queryUserRecords { + orderId := "" + hasOrderId := false + if record.OrderId.Valid && record.OrderId.String != "" { + orderId = record.OrderId.String + hasOrderId = true + } + agentId := "" + if record.AgentIdentifier.Valid { + agentId = record.AgentIdentifier.String + } + logx.Infof("检查订单限制, 记录[%d/%d]: order_id=%s (有order_id: %v), agent_identifier=%s, query_no=%s, create_time=%s, product=%s", + i+1, len(queryUserRecords), orderId, hasOrderId, agentId, record.QueryNo, record.CreateTime.Format("2006-01-02 15:04:05"), record.Product) + } + logx.Infof("检查订单限制, ========== 记录详情结束 ==========") + } + + if len(queryUserRecords) == 0 { + // 没有历史订单记录,可以继续 + logx.Infof("检查订单限制, 身份证 %s 无历史订单记录,允许支付", idCard) + return nil + } + + // 4. 提取所有订单ID(去重),只提取有order_id的记录 + logx.Infof("检查订单限制, 开始提取订单ID,总记录数: %d", len(queryUserRecords)) + orderIdSet := make(map[string]bool) + orderIds := make([]string, 0) + recordsWithOrderId := 0 + for i, record := range queryUserRecords { + if record.OrderId.Valid && record.OrderId.String != "" { + recordsWithOrderId++ + orderId := record.OrderId.String + if !orderIdSet[orderId] { + orderIdSet[orderId] = true + orderIds = append(orderIds, orderId) + logx.Infof("检查订单限制, 记录[%d]有order_id: %s", i+1, orderId) + } else { + logx.Infof("检查订单限制, 记录[%d]order_id重复: %s (已存在)", i+1, orderId) + } + } else { + logx.Infof("检查订单限制, 记录[%d]无order_id,跳过", i+1) + } + } + + logx.Infof("检查订单限制, 有order_id的记录数: %d, 提取到 %d 个唯一订单ID: %v", recordsWithOrderId, len(orderIds), orderIds) + + if len(orderIds) == 0 { + logx.Infof("检查订单限制, 身份证 %s 无有效订单ID,允许支付", idCard) + return nil + } + + // 5. 查询72小时内已支付的订单数量(只统计已支付状态的订单) + // 计算72小时前的时间 + seventyTwoHoursAgo := time.Now().Add(-72 * time.Hour) + logx.Infof("检查订单限制, 查询时间范围: %s 至今", seventyTwoHoursAgo.Format("2006-01-02 15:04:05")) + logx.Infof("检查订单限制, 查询条件: status='paid', pay_time IS NOT NULL, pay_time >= %s", seventyTwoHoursAgo.Format("2006-01-02 15:04:05")) + + // 只统计已支付状态的订单(status='paid') + paidOrderCount, countErr := l.svcCtx.OrderModel.FindCount(l.ctx, + l.svcCtx.OrderModel.SelectBuilder(). + Where(squirrel.Eq{"id": orderIds}). + Where("status = ?", model.OrderStatusPaid). // 只查询已支付状态的订单 + Where("pay_time IS NOT NULL"). // 必须有支付时间 + Where("pay_time >= ?", seventyTwoHoursAgo). // 72小时内 + Where("del_state = ?", globalkey.DelStateNo), + "id") + if countErr != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "检查订单限制, 查询已支付订单数量失败 err: %v", countErr) + } + + logx.Infof("检查订单限制, 身份证 %s 在72小时内已支付的订单数量: %d (限制: 已支付订单数量>2次则拒绝)", idCard, paidOrderCount) + + // 6. 如果72小时内已支付订单数量大于2次,则拒绝支付 + if paidOrderCount > 2 { + return errors.Wrapf(xerr.NewErrMsg("该身份证在72小时内已支付订单超过2次,无法进行代理渠道的报告查询支付"), "") + } + + return nil +} diff --git a/app/main/api/internal/logic/pay/wechatpaycallbacklogic.go b/app/main/api/internal/logic/pay/wechatpaycallbacklogic.go index 1b42e3c..5c6d76c 100644 --- a/app/main/api/internal/logic/pay/wechatpaycallbacklogic.go +++ b/app/main/api/internal/logic/pay/wechatpaycallbacklogic.go @@ -97,6 +97,24 @@ func (l *WechatPayCallbackLogic) handleQueryOrderPayment(w http.ResponseWriter, return nil } + // 更新 query_user_record 表的 platform_order_id + queryUserRecords, findRecordErr := l.svcCtx.QueryUserRecordModel.FindAll(l.ctx, + l.svcCtx.QueryUserRecordModel.SelectBuilder(). + Where("query_no = ?", *notification.OutTradeNo). + Where("del_state = ?", 0). + Limit(1), "") + if findRecordErr == nil && len(queryUserRecords) > 0 { + record := queryUserRecords[0] + record.PlatformOrderId = lzUtils.StringToNullString(*notification.TransactionId) + record.Version = record.Version + 1 + if updateRecordErr := l.svcCtx.QueryUserRecordModel.UpdateWithVersion(l.ctx, nil, record); updateRecordErr != nil { + logx.Errorf("微信支付回调,更新查询用户记录失败: %+v", updateRecordErr) + // 更新失败不影响主流程,只记录日志 + } else { + logx.Infof("微信支付回调,更新查询用户记录成功,query_no: %s, platform_order_id: %s", *notification.OutTradeNo, *notification.TransactionId) + } + } + if order.Status == "paid" { if asyncErr := l.svcCtx.AsynqService.SendQueryTask(order.Id); asyncErr != nil { logx.Errorf("异步任务调度失败: %v", asyncErr) diff --git a/app/main/api/internal/logic/query/queryservicelogic.go b/app/main/api/internal/logic/query/queryservicelogic.go index f6c6974..2cc79f4 100644 --- a/app/main/api/internal/logic/query/queryservicelogic.go +++ b/app/main/api/internal/logic/query/queryservicelogic.go @@ -7,12 +7,15 @@ import ( "fmt" "os" "qnc-server/app/main/api/internal/service" + "qnc-server/app/main/model" "qnc-server/common/ctxdata" "qnc-server/common/xerr" "qnc-server/pkg/lzkit/crypto" + "qnc-server/pkg/lzkit/lzUtils" "qnc-server/pkg/lzkit/validator" "time" + "github.com/google/uuid" "github.com/pkg/errors" "github.com/zeromicro/go-zero/core/stores/redis" @@ -107,6 +110,11 @@ func (l *QueryServiceLogic) ProcessMarriageLogic(req *types.QueryServiceReq) (*t if cacheDataErr != nil { return nil, cacheDataErr } + // 插入业务操作记录 + if insertErr := l.InsertQueryUserRecord(params, "marriage", cacheNo, userID); insertErr != nil { + logx.Errorf("插入查询用户记录失败: %v", insertErr) + // 记录失败不影响主流程,只记录日志 + } token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %v", err) @@ -167,7 +175,11 @@ func (l *QueryServiceLogic) ProcessHomeServiceLogic(req *types.QueryServiceReq) if cacheDataErr != nil { return nil, cacheDataErr } - + // 插入业务操作记录 + if insertErr := l.InsertQueryUserRecord(params, "homeservice", cacheNo, userID); insertErr != nil { + logx.Errorf("插入查询用户记录失败: %v", insertErr) + // 记录失败不影响主流程,只记录日志 + } token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) @@ -228,7 +240,11 @@ func (l *QueryServiceLogic) ProcessRiskAssessmentLogic(req *types.QueryServiceRe if cacheDataErr != nil { return nil, cacheDataErr } - + // 插入业务操作记录 + if insertErr := l.InsertQueryUserRecord(params, "riskassessment", cacheNo, userID); insertErr != nil { + logx.Errorf("插入查询用户记录失败: %v", insertErr) + // 记录失败不影响主流程,只记录日志 + } token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) @@ -288,7 +304,11 @@ func (l *QueryServiceLogic) ProcessCompanyInfoLogic(req *types.QueryServiceReq) if cacheDataErr != nil { return nil, cacheDataErr } - + // 插入业务操作记录 + if insertErr := l.InsertQueryUserRecord(params, "companyinfo", cacheNo, userID); insertErr != nil { + logx.Errorf("插入查询用户记录失败: %v", insertErr) + // 记录失败不影响主流程,只记录日志 + } token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) @@ -349,7 +369,11 @@ func (l *QueryServiceLogic) ProcessRentalInfoLogic(req *types.QueryServiceReq) ( if cacheDataErr != nil { return nil, cacheDataErr } - + // 插入业务操作记录 + if insertErr := l.InsertQueryUserRecord(params, "rentalinfo", cacheNo, userID); insertErr != nil { + logx.Errorf("插入查询用户记录失败: %v", insertErr) + // 记录失败不影响主流程,只记录日志 + } token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) @@ -410,7 +434,11 @@ func (l *QueryServiceLogic) ProcessPreLoanBackgroundCheckLogic(req *types.QueryS if cacheDataErr != nil { return nil, cacheDataErr } - + // 插入业务操作记录 + if insertErr := l.InsertQueryUserRecord(params, "preloanbackgroundcheck", cacheNo, userID); insertErr != nil { + logx.Errorf("插入查询用户记录失败: %v", insertErr) + // 记录失败不影响主流程,只记录日志 + } token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) @@ -470,7 +498,11 @@ func (l *QueryServiceLogic) ProcessBackgroundCheckLogic(req *types.QueryServiceR if cacheDataErr != nil { return nil, cacheDataErr } - + // 插入业务操作记录 + if insertErr := l.InsertQueryUserRecord(params, "backgroundcheck", cacheNo, userID); insertErr != nil { + logx.Errorf("插入查询用户记录失败: %v", insertErr) + // 记录失败不影响主流程,只记录日志 + } token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) @@ -528,7 +560,11 @@ func (l *QueryServiceLogic) ProcessPersonalDataLogic(req *types.QueryServiceReq) if cacheDataErr != nil { return nil, cacheDataErr } - + // 插入业务操作记录 + if insertErr := l.InsertQueryUserRecord(params, "personalData", cacheNo, userID); insertErr != nil { + logx.Errorf("插入查询用户记录失败: %v", insertErr) + // 记录失败不影响主流程,只记录日志 + } token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) @@ -586,7 +622,11 @@ func (l *QueryServiceLogic) ProcessConsumerFinanceReportLogic(req *types.QuerySe if cacheDataErr != nil { return nil, cacheDataErr } - + // 插入业务操作记录 + if insertErr := l.InsertQueryUserRecord(params, "consumerFinanceReport", cacheNo, userID); insertErr != nil { + logx.Errorf("插入查询用户记录失败: %v", insertErr) + // 记录失败不影响主流程,只记录日志 + } token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) @@ -734,3 +774,61 @@ func (l *QueryServiceLogic) GetOrCreateUser() (string, error) { return userID, nil } + +// InsertQueryUserRecord 插入查询用户记录到 query_user_record 表 +// 业务场景:用户提交查询时,记录用户输入的姓名、身份证、手机号等信息 +func (l *QueryServiceLogic) InsertQueryUserRecord(params map[string]interface{}, product string, queryNo string, userID string) error { + secretKey := l.svcCtx.Config.Encrypt.SecretKey + key, decodeErr := hex.DecodeString(secretKey) + if decodeErr != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "插入查询用户记录, 获取AES秘钥失败: %+v", decodeErr) + } + + // 获取姓名、身份证、手机号 + name, _ := params["name"].(string) + idCard, _ := params["id_card"].(string) + mobile, _ := params["mobile"].(string) + + // 加密敏感字段 + encryptedName, err := crypto.AesEcbEncrypt([]byte(name), key) + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "插入查询用户记录, 加密姓名失败: %+v", err) + } + + encryptedIdCard, err := crypto.EncryptIDCard(idCard, key) + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "插入查询用户记录, 加密身份证号失败: %+v", err) + } + + encryptedMobile, err := crypto.EncryptMobile(mobile, secretKey) + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "插入查询用户记录, 加密手机号失败: %+v", err) + } + + // 获取代理标识 + agentIdentifier, _ := l.ctx.Value("agentIdentifier").(string) + + // 创建记录 + record := &model.QueryUserRecord{ + Id: uuid.NewString(), // 生成 UUID + UserId: userID, // user_id 是 UUID 字符串 + Name: encryptedName, + IdCard: encryptedIdCard, + Mobile: encryptedMobile, + Product: product, + QueryNo: queryNo, + OrderId: lzUtils.StringToNullString(""), // 初始为 NULL,创建订单后更新 + PlatformOrderId: lzUtils.StringToNullString(""), // 初始为空,支付成功后更新 + AgentIdentifier: lzUtils.StringToNullString(agentIdentifier), + DelState: 0, + Version: 0, + } + + // 插入数据库 + _, err = l.svcCtx.QueryUserRecordModel.Insert(l.ctx, nil, record) + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "插入查询用户记录失败: %+v", err) + } + + return nil +} diff --git a/app/main/api/internal/queue/paySuccessNotify.go b/app/main/api/internal/queue/paySuccessNotify.go index c2c0387..3bba41f 100644 --- a/app/main/api/internal/queue/paySuccessNotify.go +++ b/app/main/api/internal/queue/paySuccessNotify.go @@ -6,13 +6,13 @@ import ( "encoding/json" "fmt" "os" - "regexp" - "strings" "qnc-server/app/main/api/internal/svc" "qnc-server/app/main/api/internal/types" "qnc-server/app/main/model" "qnc-server/pkg/lzkit/crypto" "qnc-server/pkg/lzkit/lzUtils" + "regexp" + "strings" "github.com/google/uuid" "github.com/hibiken/asynq" diff --git a/app/main/api/internal/svc/servicecontext.go b/app/main/api/internal/svc/servicecontext.go index 68bc542..6eb25cf 100644 --- a/app/main/api/internal/svc/servicecontext.go +++ b/app/main/api/internal/svc/servicecontext.go @@ -38,6 +38,7 @@ type ServiceContext struct { OrderModel model.OrderModel OrderRefundModel model.OrderRefundModel QueryModel model.QueryModel + QueryUserRecordModel model.QueryUserRecordModel QueryCleanupLogModel model.QueryCleanupLogModel QueryCleanupDetailModel model.QueryCleanupDetailModel QueryCleanupConfigModel model.QueryCleanupConfigModel @@ -118,6 +119,7 @@ func NewServiceContext(c config.Config) *ServiceContext { // ============================== 订单相关模型 ============================== orderModel := model.NewOrderModel(db, cacheConf) queryModel := model.NewQueryModel(db, cacheConf) + queryUserRecordModel := model.NewQueryUserRecordModel(db, cacheConf) orderRefundModel := model.NewOrderRefundModel(db, cacheConf) queryCleanupLogModel := model.NewQueryCleanupLogModel(db, cacheConf) queryCleanupDetailModel := model.NewQueryCleanupDetailModel(db, cacheConf) @@ -217,6 +219,7 @@ func NewServiceContext(c config.Config) *ServiceContext { // 订单相关模型 OrderModel: orderModel, QueryModel: queryModel, + QueryUserRecordModel: queryUserRecordModel, OrderRefundModel: orderRefundModel, QueryCleanupLogModel: queryCleanupLogModel, QueryCleanupDetailModel: queryCleanupDetailModel, diff --git a/app/main/api/internal/types/adminorder.go b/app/main/api/internal/types/adminorder.go index 3597af1..b9672b0 100644 --- a/app/main/api/internal/types/adminorder.go +++ b/app/main/api/internal/types/adminorder.go @@ -61,6 +61,9 @@ type AdminGetOrderListReq struct { PayTimeEnd string `form:"pay_time_end,optional"` // 支付时间结束 RefundTimeStart string `form:"refund_time_start,optional"` // 退款时间开始 RefundTimeEnd string `form:"refund_time_end,optional"` // 退款时间结束 + QueryUserName string `form:"query_user_name,optional"` // 被查询人姓名 + QueryUserIdCard string `form:"query_user_id_card,optional"` // 被查询人身份证号 + QueryUserMobile string `form:"query_user_mobile,optional"` // 被查询人手机号 } type AdminGetOrderListResp struct { diff --git a/app/main/model/queryUserRecordModel.go b/app/main/model/queryUserRecordModel.go new file mode 100644 index 0000000..9f2d824 --- /dev/null +++ b/app/main/model/queryUserRecordModel.go @@ -0,0 +1,27 @@ +package model + +import ( + "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/sqlx" +) + +var _ QueryUserRecordModel = (*customQueryUserRecordModel)(nil) + +type ( + // QueryUserRecordModel is an interface to be customized, add more methods here, + // and implement the added methods in customQueryUserRecordModel. + QueryUserRecordModel interface { + queryUserRecordModel + } + + customQueryUserRecordModel struct { + *defaultQueryUserRecordModel + } +) + +// NewQueryUserRecordModel returns a model for the database table. +func NewQueryUserRecordModel(conn sqlx.SqlConn, c cache.CacheConf) QueryUserRecordModel { + return &customQueryUserRecordModel{ + defaultQueryUserRecordModel: newQueryUserRecordModel(conn, c), + } +} diff --git a/app/main/model/queryUserRecordModel_gen.go b/app/main/model/queryUserRecordModel_gen.go new file mode 100644 index 0000000..e3db7ae --- /dev/null +++ b/app/main/model/queryUserRecordModel_gen.go @@ -0,0 +1,394 @@ +// Code generated by goctl. DO NOT EDIT! + +package model + +import ( + "context" + "database/sql" + "fmt" + "strings" + + "reflect" + "time" + + "github.com/Masterminds/squirrel" + "github.com/google/uuid" + "github.com/pkg/errors" + "github.com/zeromicro/go-zero/core/stores/builder" + "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/sqlc" + "github.com/zeromicro/go-zero/core/stores/sqlx" + "github.com/zeromicro/go-zero/core/stringx" + "qnc-server/common/globalkey" +) + +var ( + queryUserRecordFieldNames = builder.RawFieldNames(&QueryUserRecord{}) + queryUserRecordRows = strings.Join(queryUserRecordFieldNames, ",") + queryUserRecordRowsExpectAutoSet = strings.Join(stringx.Remove(queryUserRecordFieldNames, "`create_time`", "`update_time`"), ",") + queryUserRecordRowsWithPlaceHolder = strings.Join(stringx.Remove(queryUserRecordFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?" + + cacheZacQueryUserRecordIdPrefix = "cache:zac:queryUserRecord:id:" +) + +type ( + queryUserRecordModel interface { + Insert(ctx context.Context, session sqlx.Session, data *QueryUserRecord) (sql.Result, error) + FindOne(ctx context.Context, id string) (*QueryUserRecord, error) + Update(ctx context.Context, session sqlx.Session, data *QueryUserRecord) (sql.Result, error) + UpdateWithVersion(ctx context.Context, session sqlx.Session, data *QueryUserRecord) error + Trans(ctx context.Context, fn func(context context.Context, session sqlx.Session) error) error + SelectBuilder() squirrel.SelectBuilder + DeleteSoft(ctx context.Context, session sqlx.Session, data *QueryUserRecord) error + FindSum(ctx context.Context, sumBuilder squirrel.SelectBuilder, field string) (float64, error) + FindCount(ctx context.Context, countBuilder squirrel.SelectBuilder, field string) (int64, error) + FindAll(ctx context.Context, rowBuilder squirrel.SelectBuilder, orderBy string) ([]*QueryUserRecord, error) + FindPageListByPage(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*QueryUserRecord, error) + FindPageListByPageWithTotal(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*QueryUserRecord, int64, error) + FindPageListByIdDESC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMinId, pageSize int64) ([]*QueryUserRecord, error) + FindPageListByIdASC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMaxId, pageSize int64) ([]*QueryUserRecord, error) + Delete(ctx context.Context, session sqlx.Session, id string) error + } + + defaultQueryUserRecordModel struct { + sqlc.CachedConn + table string + } + + QueryUserRecord struct { + Id string `db:"id"` // 主键ID(UUID) + CreateTime time.Time `db:"create_time"` // 创建时间 + UpdateTime time.Time `db:"update_time"` // 更新时间 + DeleteTime sql.NullTime `db:"delete_time"` // 删除时间 + DelState int64 `db:"del_state"` // 删除状态:0-未删除,1-已删除 + Version int64 `db:"version"` // 版本号 + UserId string `db:"user_id"` // 用户ID(UUID,关联 user 表) + Name string `db:"name"` // 姓名密文(AES-ECB+Base64),用于按姓名筛选订单 + IdCard string `db:"id_card"` // 身份证号密文(AES-ECB+Base64),用于按身份证号筛选订单 + Mobile string `db:"mobile"` // 手机号密文(AES-ECB+Base64),用于按手机号筛选订单 + Product string `db:"product"` // 产品类型,如 marriage/homeservice/riskassessment 等 + QueryNo string `db:"query_no"` // 查询单号(与 order.order_no 一致,如 Q_xxx),用户提交查询时生成 + OrderId sql.NullString `db:"order_id"` // 订单ID(UUID,关联 order 表),用户发起支付并创建订单后写入 + PlatformOrderId sql.NullString `db:"platform_order_id"` // 支付平台订单号(支付宝/微信),支付成功后由回调写入 + AgentIdentifier sql.NullString `db:"agent_identifier"` // 代理标识,代理渠道时有值 + } +) + +func newQueryUserRecordModel(conn sqlx.SqlConn, c cache.CacheConf) *defaultQueryUserRecordModel { + return &defaultQueryUserRecordModel{ + CachedConn: sqlc.NewConn(conn, c), + table: "`query_user_record`", + } +} + +func (m *defaultQueryUserRecordModel) Insert(ctx context.Context, session sqlx.Session, data *QueryUserRecord) (sql.Result, error) { + data.DelState = globalkey.DelStateNo + m.insertUUID(data) + zacQueryUserRecordIdKey := fmt.Sprintf("%s%v", cacheZacQueryUserRecordIdPrefix, data.Id) + return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, queryUserRecordRowsExpectAutoSet) + if session != nil { + return session.ExecCtx(ctx, query, data.Id, data.DeleteTime, data.DelState, data.Version, data.UserId, data.Name, data.IdCard, data.Mobile, data.Product, data.QueryNo, data.OrderId, data.PlatformOrderId, data.AgentIdentifier) + } + return conn.ExecCtx(ctx, query, data.Id, data.DeleteTime, data.DelState, data.Version, data.UserId, data.Name, data.IdCard, data.Mobile, data.Product, data.QueryNo, data.OrderId, data.PlatformOrderId, data.AgentIdentifier) + }, zacQueryUserRecordIdKey) +} +func (m *defaultQueryUserRecordModel) insertUUID(data *QueryUserRecord) { + t := reflect.TypeOf(data).Elem() + v := reflect.ValueOf(data).Elem() + for i := 0; i < t.NumField(); i++ { + sf := t.Field(i) + if sf.Tag.Get("db") == "id" { + f := v.Field(i) + if f.IsValid() && f.CanSet() && f.Kind() == reflect.String { + if f.String() == "" { + f.SetString(uuid.NewString()) + } + } + break + } + } +} + +func (m *defaultQueryUserRecordModel) FindOne(ctx context.Context, id string) (*QueryUserRecord, error) { + zacQueryUserRecordIdKey := fmt.Sprintf("%s%v", cacheZacQueryUserRecordIdPrefix, id) + var resp QueryUserRecord + err := m.QueryRowCtx(ctx, &resp, zacQueryUserRecordIdKey, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) error { + query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", queryUserRecordRows, m.table) + return conn.QueryRowCtx(ctx, v, query, id, globalkey.DelStateNo) + }) + switch err { + case nil: + return &resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultQueryUserRecordModel) Update(ctx context.Context, session sqlx.Session, data *QueryUserRecord) (sql.Result, error) { + zacQueryUserRecordIdKey := fmt.Sprintf("%s%v", cacheZacQueryUserRecordIdPrefix, data.Id) + return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, queryUserRecordRowsWithPlaceHolder) + if session != nil { + return session.ExecCtx(ctx, query, data.DeleteTime, data.DelState, data.Version, data.UserId, data.Name, data.IdCard, data.Mobile, data.Product, data.QueryNo, data.OrderId, data.PlatformOrderId, data.AgentIdentifier, data.Id) + } + return conn.ExecCtx(ctx, query, data.DeleteTime, data.DelState, data.Version, data.UserId, data.Name, data.IdCard, data.Mobile, data.Product, data.QueryNo, data.OrderId, data.PlatformOrderId, data.AgentIdentifier, data.Id) + }, zacQueryUserRecordIdKey) +} + +func (m *defaultQueryUserRecordModel) UpdateWithVersion(ctx context.Context, session sqlx.Session, data *QueryUserRecord) error { + + oldVersion := data.Version + data.Version += 1 + + var sqlResult sql.Result + var err error + + zacQueryUserRecordIdKey := fmt.Sprintf("%s%v", cacheZacQueryUserRecordIdPrefix, data.Id) + sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, queryUserRecordRowsWithPlaceHolder) + if session != nil { + return session.ExecCtx(ctx, query, data.DeleteTime, data.DelState, data.Version, data.UserId, data.Name, data.IdCard, data.Mobile, data.Product, data.QueryNo, data.OrderId, data.PlatformOrderId, data.AgentIdentifier, data.Id, oldVersion) + } + return conn.ExecCtx(ctx, query, data.DeleteTime, data.DelState, data.Version, data.UserId, data.Name, data.IdCard, data.Mobile, data.Product, data.QueryNo, data.OrderId, data.PlatformOrderId, data.AgentIdentifier, data.Id, oldVersion) + }, zacQueryUserRecordIdKey) + if err != nil { + return err + } + updateCount, err := sqlResult.RowsAffected() + if err != nil { + return err + } + if updateCount == 0 { + return ErrNoRowsUpdate + } + + return nil +} + +func (m *defaultQueryUserRecordModel) DeleteSoft(ctx context.Context, session sqlx.Session, data *QueryUserRecord) error { + data.DelState = globalkey.DelStateYes + data.DeleteTime = sql.NullTime{Time: time.Now(), Valid: true} + if err := m.UpdateWithVersion(ctx, session, data); err != nil { + return errors.Wrapf(errors.New("delete soft failed "), "QueryUserRecordModel delete err : %+v", err) + } + return nil +} + +func (m *defaultQueryUserRecordModel) FindSum(ctx context.Context, builder squirrel.SelectBuilder, field string) (float64, error) { + + if len(field) == 0 { + return 0, errors.Wrapf(errors.New("FindSum Least One Field"), "FindSum Least One Field") + } + + builder = builder.Columns("IFNULL(SUM(" + field + "),0)") + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql() + if err != nil { + return 0, err + } + + var resp float64 + err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return 0, err + } +} + +func (m *defaultQueryUserRecordModel) FindCount(ctx context.Context, builder squirrel.SelectBuilder, field string) (int64, error) { + + if len(field) == 0 { + return 0, errors.Wrapf(errors.New("FindCount Least One Field"), "FindCount Least One Field") + } + + builder = builder.Columns("COUNT(" + field + ")") + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql() + if err != nil { + return 0, err + } + + var resp int64 + err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return 0, err + } +} + +func (m *defaultQueryUserRecordModel) FindAll(ctx context.Context, builder squirrel.SelectBuilder, orderBy string) ([]*QueryUserRecord, error) { + + builder = builder.Columns(queryUserRecordRows) + + if orderBy == "" { + builder = builder.OrderBy("id DESC") + } else { + builder = builder.OrderBy(orderBy) + } + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql() + if err != nil { + return nil, err + } + + var resp []*QueryUserRecord + err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return nil, err + } +} + +func (m *defaultQueryUserRecordModel) FindPageListByPage(ctx context.Context, builder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*QueryUserRecord, error) { + + builder = builder.Columns(queryUserRecordRows) + + if orderBy == "" { + builder = builder.OrderBy("id DESC") + } else { + builder = builder.OrderBy(orderBy) + } + + if page < 1 { + page = 1 + } + offset := (page - 1) * pageSize + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql() + if err != nil { + return nil, err + } + + var resp []*QueryUserRecord + err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return nil, err + } +} + +func (m *defaultQueryUserRecordModel) FindPageListByPageWithTotal(ctx context.Context, builder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*QueryUserRecord, int64, error) { + + total, err := m.FindCount(ctx, builder, "id") + if err != nil { + return nil, 0, err + } + + builder = builder.Columns(queryUserRecordRows) + + if orderBy == "" { + builder = builder.OrderBy("id DESC") + } else { + builder = builder.OrderBy(orderBy) + } + + if page < 1 { + page = 1 + } + offset := (page - 1) * pageSize + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql() + if err != nil { + return nil, total, err + } + + var resp []*QueryUserRecord + err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, total, nil + default: + return nil, total, err + } +} + +func (m *defaultQueryUserRecordModel) FindPageListByIdDESC(ctx context.Context, builder squirrel.SelectBuilder, preMinId, pageSize int64) ([]*QueryUserRecord, error) { + + builder = builder.Columns(queryUserRecordRows) + + if preMinId > 0 { + builder = builder.Where(" id < ? ", preMinId) + } + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).OrderBy("id DESC").Limit(uint64(pageSize)).ToSql() + if err != nil { + return nil, err + } + + var resp []*QueryUserRecord + err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return nil, err + } +} + +func (m *defaultQueryUserRecordModel) FindPageListByIdASC(ctx context.Context, builder squirrel.SelectBuilder, preMaxId, pageSize int64) ([]*QueryUserRecord, error) { + + builder = builder.Columns(queryUserRecordRows) + + if preMaxId > 0 { + builder = builder.Where(" id > ? ", preMaxId) + } + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).OrderBy("id ASC").Limit(uint64(pageSize)).ToSql() + if err != nil { + return nil, err + } + + var resp []*QueryUserRecord + err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return nil, err + } +} + +func (m *defaultQueryUserRecordModel) Trans(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error { + + return m.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error { + return fn(ctx, session) + }) + +} + +func (m *defaultQueryUserRecordModel) SelectBuilder() squirrel.SelectBuilder { + return squirrel.Select().From(m.table) +} +func (m *defaultQueryUserRecordModel) Delete(ctx context.Context, session sqlx.Session, id string) error { + zacQueryUserRecordIdKey := fmt.Sprintf("%s%v", cacheZacQueryUserRecordIdPrefix, id) + _, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + query := fmt.Sprintf("delete from %s where `id` = ?", m.table) + if session != nil { + return session.ExecCtx(ctx, query, id) + } + return conn.ExecCtx(ctx, query, id) + }, zacQueryUserRecordIdKey) + return err +} +func (m *defaultQueryUserRecordModel) formatPrimary(primary interface{}) string { + return fmt.Sprintf("%s%v", cacheZacQueryUserRecordIdPrefix, primary) +} +func (m *defaultQueryUserRecordModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary interface{}) error { + query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", queryUserRecordRows, m.table) + return conn.QueryRowCtx(ctx, v, query, primary, globalkey.DelStateNo) +} + +func (m *defaultQueryUserRecordModel) tableName() string { + return m.table +} diff --git a/deploy/script/gen_models.ps1 b/deploy/script/gen_models.ps1 index 9bccad0..7264934 100644 --- a/deploy/script/gen_models.ps1 +++ b/deploy/script/gen_models.ps1 @@ -28,7 +28,8 @@ $tables = @( # "admin_user_role", # "agent", # "agent_commission", - "agent_config" + # "agent_config" + "query_user_record" # "agent_freeze_task", # "agent_invite_code", # "agent_invite_code_usage", @@ -62,7 +63,7 @@ $tables = @( # 为每个表生成模型 foreach ($table in $tables) { Write-Host "正在生成表: $table" -ForegroundColor Green - goctl model mysql datasource -url="qnc:5vg67b3UNHu8@tcp(127.0.0.1:21001)/qnc" -table="$table" -dir="./model" --home="$HOME_DIR" -cache=true --style=goZero + goctl model mysql datasource -url="zac:5vg67b3UNHu8@tcp(127.0.0.1:21201)/zac" -table="$table" -dir="./model" --home="$HOME_DIR" -cache=true --style=goZero # 移动生成的文件到目标目录 if (Test-Path $OUTPUT_DIR) { diff --git a/deploy/sql/README_表结构修改说明.md b/deploy/sql/README_表结构修改说明.md deleted file mode 100644 index 78bfaed..0000000 --- a/deploy/sql/README_表结构修改说明.md +++ /dev/null @@ -1,320 +0,0 @@ -# 表结构修改说明 - -本文档说明系统重构需要的所有表结构修改,包括: -1. UUID迁移(将所有bigint类型的ID改为CHAR(36)类型的UUID) -2. 用户系统重构(删除UserTemp表,优化UserAuth表) - -## 一、UUID迁移 - -### 1.1 概述 - -将所有表的主键ID从`bigint`类型改为`CHAR(36)`类型的UUID,同时将所有外键关联字段也改为UUID类型。 - -**注意**:开发环境使用简化版脚本(`uuid_migration_simple.sql`),直接修改表结构,不保留旧数据。 - -### 1.2 涉及的表 - -**核心业务表**: -- `user` - 用户表 -- `agent` - 代理表 -- `product` - 产品表 -- `order` - 订单表 -- `query` - 查询报告表 -- `user_auth` - 用户认证表 - -**代理相关表**: -- `agent_commission` - 代理佣金表 -- `agent_invite_code` - 代理邀请码表 -- `agent_link` - 代理链接表 -- `agent_order` - 代理订单表 -- `agent_wallet` - 代理钱包表 -- `agent_withdrawal` - 代理提现表 -- `agent_withdrawal_tax` - 代理提现税费表 -- `agent_rebate` - 代理返利表 -- `agent_relation` - 代理关系表 -- `agent_upgrade` - 代理升级表 -- `agent_real_name` - 代理实名表 -- `agent_config` - 代理配置表 -- `agent_product_config` - 代理产品配置表 -- `agent_short_link` - 代理短链表 -- `agent_invite_code_usage` - 邀请码使用记录表 -- `agent_freeze_task` - 代理冻结任务表 - -**订单相关表**: -- `order_refund` - 订单退款表 - -**查询相关表**: -- `query_cleanup_log` - 查询清理日志表 -- `query_cleanup_detail` - 查询清理详情表 -- `query_cleanup_config` - 查询清理配置表 - -**产品相关表**: -- `product_feature` - 产品功能表 -- `feature` - 功能表 - -**其他表**: -- `authorization_document` - 授权书表 -- `global_notifications` - 全局通知表 - -**管理后台表**: -- `admin_user` - 管理员用户表 -- `admin_role` - 管理员角色表 -- `admin_menu` - 管理员菜单表 -- `admin_api` - 管理员API表 -- `admin_dict_type` - 字典类型表 -- `admin_dict_data` - 字典数据表 -- `admin_user_role` - 管理员用户角色关联表 -- `admin_role_menu` - 管理员角色菜单关联表 -- `admin_role_api` - 管理员角色API关联表 - -### 1.3 修改内容 - -**主键字段**: -- 所有表的`id`字段:`bigint` → `CHAR(36)` -- 移除`AUTO_INCREMENT`属性 -- 插入时使用`UUID()`函数或应用层生成UUID - -**外键字段**(软关联): -- `user_id`:`bigint` → `CHAR(36)` -- `agent_id`:`bigint` → `CHAR(36)` -- `order_id`:`bigint` → `CHAR(36)` -- `product_id`:`bigint` → `CHAR(36)` -- `invite_code_id`:`bigint` → `CHAR(36)` -- `link_id`:`bigint` → `CHAR(36)` -- `commission_id`:`bigint` → `CHAR(36)` -- `wallet_id`:`bigint` → `CHAR(36)` -- `withdrawal_id`:`bigint` → `CHAR(36)` -- `parent_agent_id`:`bigint` → `CHAR(36)` -- `team_leader_id`:`bigint` → `CHAR(36)` -- `cleanup_log_id`:`bigint` → `CHAR(36)` -- `query_id`:`bigint` → `CHAR(36)` -- `feature_id`:`bigint` → `CHAR(36)` -- `parent_id`(菜单):`bigint` → `CHAR(36)` -- `dict_type_id`:`bigint` → `CHAR(36)` -- `role_id`:`bigint` → `CHAR(36)` -- `menu_id`:`bigint` → `CHAR(36)` -- `api_id`:`bigint` → `CHAR(36)` -- `used_user_id`:`bigint` → `CHAR(36)` -- `used_agent_id`:`bigint` → `CHAR(36)` - -### 1.4 执行脚本 - -**开发环境**:执行文件 `uuid_migration_simple.sql` -- 直接修改表结构,不保留旧数据 -- 适用于开发环境,没有重要数据 - -**生产环境**:执行文件 `uuid_migration.sql` -- 完整的迁移流程,保留旧数据以便回滚 -- 需要分阶段执行,包含数据迁移和验证 - -**开发环境执行步骤**: -1. 直接执行 `uuid_migration_simple.sql` -2. 所有表的主键和外键字段直接改为CHAR(36) -3. 插入新记录时,在应用层生成UUID - -**注意事项**: -- 开发环境脚本直接修改表结构,不保留旧数据 -- 如果表中有数据,需要先清空数据或手动填充UUID -- 代码层面需要同步修改所有ID字段类型(int64 → string) - -## 二、用户系统重构 - -### 2.1 概述 - -删除`UserTemp`表,统一使用`User`表(通过`mobile`字段是否为空区分临时用户和正式用户),优化`UserAuth`表结构。 - -### 2.2 涉及的表 - -**需要修改的表**: -- `user` - 用户表(无需修改结构,只需确保mobile可为空) -- `user_auth` - 用户认证表(添加唯一索引) -- `user_temp` - 临时用户表(**删除**) - -**需要迁移数据的表**: -- `order` - 订单表(更新user_id) -- `query` - 查询报告表(更新user_id) - -### 2.3 修改内容 - -#### 2.3.1 UserAuth表 - -**添加唯一索引**: -```sql -ALTER TABLE `user_auth` -ADD UNIQUE INDEX `uk_auth_type_key` (`auth_type`, `auth_key`); -``` - -**作用**: -- 确保同一个认证方式(auth_type + auth_key)只能绑定一个用户 -- 防止重复绑定 - -#### 2.3.2 UserTemp表 - -**删除原因**: -- 临时用户可以直接创建User表记录(mobile为空) -- 临时用户的认证信息存储在UserAuth表 -- 通过User.mobile是否为空来区分临时用户和正式用户 -- 统一使用User表,逻辑更清晰 - -**删除步骤**: -1. 迁移UserTemp数据到User和UserAuth表 -2. 更新关联的订单和报告的user_id -3. 验证数据完整性 -4. 删除UserTemp表 - -### 2.4 执行脚本 - -**开发环境**:执行文件 `user_system_refactor.sql`(已简化) -- 直接删除UserTemp表 -- 添加UserAuth唯一索引 - -**生产环境**:如需数据迁移,请参考完整版脚本 - -**开发环境执行步骤**: -1. 添加UserAuth唯一索引 -2. 直接删除UserTemp表 - -**注意事项**: -- 开发环境脚本直接删除UserTemp表,不进行数据迁移 -- 删除UserTemp表前,确保代码中已移除所有对UserTemp表的引用 - -## 三、执行顺序 - -### 3.1 推荐执行顺序 - -**开发环境**: -1. **先执行用户系统重构**(`user_system_refactor.sql`) - - 添加UserAuth唯一索引 - - 删除UserTemp表 - -2. **再执行UUID迁移**(`uuid_migration_simple.sql`) - - 直接修改所有表结构 - - 需要同步修改代码 - -**生产环境**: -1. 先执行用户系统重构(完整版,包含数据迁移) -2. 再执行UUID迁移(完整版,包含数据迁移和验证) - -### 3.2 如果先执行UUID迁移 - -如果先执行UUID迁移,需要注意: -- UserTemp表的ID也会改为UUID -- 迁移UserTemp数据时,需要使用UUID映射 -- 用户系统重构脚本需要相应调整 - -## 四、代码修改清单 - -### 4.1 UUID迁移需要的代码修改 - -**Model层**: -- 所有Model的ID字段类型:`int64` → `string` -- 所有外键字段类型:`int64` → `string` -- 移除`AUTO_INCREMENT`相关逻辑 -- 插入时生成UUID(使用`uuid.NewString()`) - -**Service层**: -- 所有使用ID的地方改为UUID -- 查询条件改为UUID -- 关联查询改为UUID - -**API层**: -- 请求参数中的ID改为UUID -- 响应数据中的ID改为UUID - -**数据库操作**: -- 插入操作:使用`uuid.NewString()`生成UUID -- 查询操作:使用UUID字符串查询 -- 更新操作:使用UUID字符串更新 - -### 4.2 用户系统重构需要的代码修改 - -**删除UserTemp相关代码**: -- 删除`UserTempModel` -- 删除所有使用`UserTemp`的代码 -- 删除临时用户创建逻辑中的UserTemp相关代码 - -**修改用户创建逻辑**: -- 临时用户:直接创建User记录(mobile为空) -- 创建UserAuth记录(auth_type + auth_key) - -**修改用户查询逻辑**: -- 通过UserAuth表查询用户 -- 通过User.mobile是否为空判断用户类型 - -**修改账号合并逻辑**: -- 绑定手机号时,检查手机号是否已存在 -- 如果存在,合并账号(迁移数据) -- 如果不存在,更新User.mobile - -## 五、验证清单 - -### 5.1 UUID迁移验证 - -- [ ] 所有表的主键已改为CHAR(36) -- [ ] 所有外键字段已改为CHAR(36) -- [ ] 插入新记录时自动生成UUID -- [ ] 查询操作使用UUID正常 -- [ ] 关联查询使用UUID正常 -- [ ] 索引和约束已更新 -- [ ] 数据完整性验证通过 - -### 5.2 用户系统重构验证 - -- [ ] UserAuth表有唯一索引`uk_auth_type_key` -- [ ] UserTemp表数据已迁移(如果存在) -- [ ] 订单和报告的user_id已更新 -- [ ] UserTemp表已删除(如果存在) -- [ ] 临时用户创建逻辑使用User表 -- [ ] 账号合并逻辑正常工作 -- [ ] 数据完整性验证通过 - -## 六、回滚方案 - -### 6.1 UUID迁移回滚 - -如果UUID迁移出现问题,可以: -1. 保留原ID字段(迁移脚本中已保留) -2. 恢复主键为原ID字段 -3. 删除UUID字段 -4. 恢复代码使用int64类型 - -### 6.2 用户系统重构回滚 - -如果用户系统重构出现问题,可以: -1. 恢复UserTemp表(从备份) -2. 恢复订单和报告的user_id -3. 恢复代码使用UserTemp表 - -## 七、常见问题 - -### 7.1 UUID性能问题 - -**问题**:UUID作为主键可能影响性能 - -**解答**: -- UUID是字符串类型,索引效率略低于bigint -- 但UUID的优势是全局唯一,适合分布式系统 -- 如果性能问题严重,可以考虑使用BINARY(16)存储UUID(需要转换) - -### 7.2 UUID长度问题 - -**问题**:CHAR(36)占用空间较大 - -**解答**: -- UUID标准格式是36字符(包含连字符) -- 如果空间敏感,可以使用BINARY(16)存储(需要转换函数) -- 当前使用CHAR(36)便于调试和查看 - -### 7.3 UserTemp数据迁移问题 - -**问题**:如何确保UserTemp数据正确迁移? - -**解答**: -- 通过auth_type和auth_key匹配UserAuth记录 -- 建立UserTemp.id到User.id的映射关系 -- 迁移后验证数据完整性 -- 保留UserTemp表一段时间,确认无误后再删除 - -## 八、联系信息 - -如有问题,请联系开发团队。 diff --git a/deploy/sql/add_agent_short_link_table.sql b/deploy/sql/add_agent_short_link_table.sql deleted file mode 100644 index 6cd0149..0000000 --- a/deploy/sql/add_agent_short_link_table.sql +++ /dev/null @@ -1,47 +0,0 @@ --- ============================================ --- 代理短链表 --- 说明:存储推广链接和邀请链接的短链映射关系 --- --- 功能说明: --- 1. 支持两种类型:promotion(推广报告)和 invite(邀请好友) --- 2. 为每个链接生成一个短链标识(6位随机字符串) --- 3. 短链格式:https://推广域名/s/{short_code} --- 4. 短链重定向到前端传入的target_path --- --- 执行步骤: --- 1. 执行此 SQL 创建表 --- 2. 使用 goctl 生成 Model:agent_short_link -> AgentShortLinkModel --- 3. 在 servicecontext.go 中添加 AgentShortLinkModel --- ============================================ -CREATE TABLE `agent_short_link` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `type` tinyint NOT NULL COMMENT '类型:1=推广报告(promotion),2=邀请好友(invite)', - `link_id` bigint DEFAULT NULL COMMENT '推广链接ID(关联agent_link表,仅推广报告类型使用)', - `invite_code_id` bigint DEFAULT NULL COMMENT '邀请码ID(关联agent_invite_code表,仅邀请好友类型使用)', - `link_identifier` varchar(200) DEFAULT NULL COMMENT '推广链接标识(加密,仅推广报告类型使用)', - `invite_code` varchar(50) DEFAULT NULL COMMENT '邀请码(仅邀请好友类型使用)', - `short_code` varchar(20) NOT NULL COMMENT '短链标识(6位随机字符串)', - `target_path` varchar(500) NOT NULL COMMENT '目标地址(前端传入,如:/agent/promotionInquire/xxx 或 /register?invite_code=xxx)', - `promotion_domain` varchar(200) NOT NULL COMMENT '推广域名(生成短链时使用的域名)', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除', - `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_short_code` (`short_code`, `del_state`) COMMENT '短链标识唯一索引', - UNIQUE KEY `uk_link_id_type` ( - `link_id`, - `type`, - `del_state` - ) COMMENT '同一推广链接同一类型只能有一个有效短链', - UNIQUE KEY `uk_invite_code_id_type` ( - `invite_code_id`, - `type`, - `del_state` - ) COMMENT '同一邀请码同一类型只能有一个有效短链', - KEY `idx_link_identifier` (`link_identifier`) COMMENT '推广链接标识索引', - KEY `idx_invite_code` (`invite_code`) COMMENT '邀请码索引', - KEY `idx_type` (`type`) COMMENT '类型索引', - KEY `idx_create_time` (`create_time`) COMMENT '创建时间索引' -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '代理短链表'; \ No newline at end of file diff --git a/deploy/sql/add_invite_code_usage_table.sql b/deploy/sql/add_invite_code_usage_table.sql deleted file mode 100644 index 59942b8..0000000 --- a/deploy/sql/add_invite_code_usage_table.sql +++ /dev/null @@ -1,46 +0,0 @@ --- ============================================ --- 邀请码使用历史表 --- 说明:记录每次邀请码的使用情况,支持统计和查询 --- --- 功能说明: --- 1. 记录每个邀请码每次使用的详细信息 --- 2. 支持统计每个邀请码邀请了多少代理 --- 3. 支持查询某个代理是通过哪个邀请码成为代理的 --- 4. 保留完整的使用历史记录 --- --- 执行步骤: --- 1. 执行此 SQL 创建表和添加字段 --- 2. 使用 goctl 生成 Model:agent_invite_code_usage -> AgentInviteCodeUsageModel --- 3. 在 servicecontext.go 中添加 AgentInviteCodeUsageModel --- ============================================ -CREATE TABLE `agent_invite_code_usage` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `invite_code_id` bigint NOT NULL COMMENT '邀请码ID(关联agent_invite_code表)', - `code` varchar(50) NOT NULL COMMENT '邀请码(冗余字段,便于查询)', - `user_id` bigint NOT NULL COMMENT '使用用户ID', - `agent_id` bigint NOT NULL COMMENT '成为的代理ID', - `agent_level` tinyint NOT NULL COMMENT '代理等级:1=普通,2=黄金,3=钻石', - `used_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '使用时间', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除', - `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)', - PRIMARY KEY (`id`), - KEY `idx_invite_code_id` (`invite_code_id`) COMMENT '关联邀请码ID', - KEY `idx_code` (`code`) COMMENT '邀请码索引', - KEY `idx_user_id` (`user_id`) COMMENT '用户ID索引', - KEY `idx_agent_id` (`agent_id`) COMMENT '代理ID索引', - KEY `idx_used_time` (`used_time`) COMMENT '使用时间索引', - KEY `idx_create_time` (`create_time`) COMMENT '创建时间索引', - KEY `idx_code_time` (`code`, `used_time`) COMMENT '邀请码和使用时间复合索引' -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '邀请码使用历史表'; - --- ============================================ --- 在agent表中添加invite_code_id字段(可选,便于直接查询代理是通过哪个邀请码成为的) --- ============================================ -ALTER TABLE `agent` -ADD COLUMN `invite_code_id` bigint DEFAULT NULL COMMENT '通过哪个邀请码成为代理(关联agent_invite_code表)' AFTER `team_leader_id`; - -ALTER TABLE `agent` -ADD KEY `idx_invite_code_id` (`invite_code_id`) COMMENT '邀请码ID索引'; \ No newline at end of file diff --git a/deploy/sql/agent_config_migration.sql b/deploy/sql/agent_config_migration.sql deleted file mode 100644 index 673063c..0000000 --- a/deploy/sql/agent_config_migration.sql +++ /dev/null @@ -1,56 +0,0 @@ --- ============================================ --- 代理配置表重构 SQL 脚本 --- 执行顺序:按照下面的顺序依次执行 --- ============================================ - --- ============================================ --- 步骤1:删除价格相关配置项 --- 说明:价格配置已改为在产品配置表(agent_product_config)中按产品配置 --- ============================================ -DELETE FROM `agent_config` WHERE `config_key` IN ( - 'base_price', - 'system_max_price', - 'price_threshold', - 'price_fee_rate' -); - --- ============================================ --- 步骤2:统一配置键命名 --- 说明:修改配置键名称,使其与代码逻辑一致 --- ============================================ - --- 修改等级加成配置键 -UPDATE `agent_config` SET `config_key` = 'level_1_bonus' WHERE `config_key` = 'level_bonus_normal'; -UPDATE `agent_config` SET `config_key` = 'level_2_bonus' WHERE `config_key` = 'level_bonus_gold'; -UPDATE `agent_config` SET `config_key` = 'level_3_bonus' WHERE `config_key` = 'level_bonus_diamond'; - --- 修改升级费用配置键 -UPDATE `agent_config` SET `config_key` = 'upgrade_to_gold_fee' WHERE `config_key` = 'upgrade_fee_normal_to_gold'; -UPDATE `agent_config` SET `config_key` = 'upgrade_to_diamond_fee' WHERE `config_key` = 'upgrade_fee_to_diamond'; - --- 修改升级返佣配置键 -UPDATE `agent_config` SET `config_key` = 'upgrade_to_gold_rebate' WHERE `config_key` = 'upgrade_rebate_normal_to_gold'; -UPDATE `agent_config` SET `config_key` = 'upgrade_to_diamond_rebate' WHERE `config_key` = 'upgrade_rebate_to_diamond'; - --- ============================================ --- 步骤3:添加缺失的配置项 --- 说明:添加免税额度配置项(如果不存在) --- ============================================ -INSERT INTO `agent_config` (`config_key`, `config_value`, `config_type`, `description`) -SELECT 'tax_exemption_amount', '0.00', 'tax', '提现免税额度(元,默认0)' -WHERE NOT EXISTS ( - SELECT 1 FROM `agent_config` WHERE `config_key` = 'tax_exemption_amount' -); - --- ============================================ --- 验证查询:检查配置项是否正确 --- ============================================ -SELECT `config_key`, `config_value`, `config_type`, `description` -FROM `agent_config` -WHERE `del_state` = 0 -ORDER BY `config_type`, `config_key`; - --- ============================================ --- 执行完成后,请重新生成 agent_config 相关的 Model 代码 --- ============================================ - diff --git a/deploy/sql/agent_freeze_task_migration.sql b/deploy/sql/agent_freeze_task_migration.sql deleted file mode 100644 index 7ef9ca0..0000000 --- a/deploy/sql/agent_freeze_task_migration.sql +++ /dev/null @@ -1,32 +0,0 @@ --- ============================================ --- 代理佣金冻结任务表 --- 说明:用于记录需要解冻的佣金冻结任务,保证异步任务的一致性和持久化 --- ============================================ - -CREATE TABLE `agent_freeze_task` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `agent_id` bigint NOT NULL COMMENT '代理ID', - `order_id` bigint NOT NULL COMMENT '订单ID', - `commission_id` bigint NOT NULL COMMENT '佣金记录ID', - `freeze_amount` decimal(10, 2) NOT NULL COMMENT '冻结金额', - `order_price` decimal(10, 2) NOT NULL COMMENT '订单单价', - `freeze_ratio` decimal(5, 4) NOT NULL DEFAULT 0.1000 COMMENT '冻结比例(例如:0.1000表示10%)', - `status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:1=待解冻,2=已解冻,3=已取消', - `freeze_time` datetime NOT NULL COMMENT '冻结时间', - `unfreeze_time` datetime NOT NULL COMMENT '解冻时间(冻结时间+1个月)', - `actual_unfreeze_time` datetime DEFAULT NULL COMMENT '实际解冻时间', - `remark` varchar(255) DEFAULT NULL COMMENT '备注', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除', - `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)', - PRIMARY KEY (`id`), - KEY `idx_agent_id` (`agent_id`), - KEY `idx_order_id` (`order_id`), - KEY `idx_commission_id` (`commission_id`), - KEY `idx_status` (`status`), - KEY `idx_unfreeze_time` (`unfreeze_time`), - KEY `idx_agent_status` (`agent_id`, `status`), - KEY `idx_create_time` (`create_time`) -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '代理佣金冻结任务表'; \ No newline at end of file diff --git a/deploy/sql/agent_system_migration.sql b/deploy/sql/agent_system_migration.sql deleted file mode 100644 index 223f0f5..0000000 --- a/deploy/sql/agent_system_migration.sql +++ /dev/null @@ -1,386 +0,0 @@ --- ============================================ --- 新代理系统数据表创建脚本 --- 说明:创建新代理系统的所有数据表 --- ============================================ - --- ============================================ --- 1. 代理基本信息表 --- ============================================ -CREATE TABLE `agent` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `user_id` bigint NOT NULL COMMENT '用户ID', - `level` tinyint NOT NULL DEFAULT 1 COMMENT '代理等级:1=普通,2=黄金,3=钻石', - `region` varchar(50) DEFAULT NULL COMMENT '区域(可选)', - `mobile` varchar(50) NOT NULL DEFAULT '' COMMENT '手机号(加密)', - `wechat_id` varchar(100) DEFAULT NULL COMMENT '微信号', - `team_leader_id` bigint DEFAULT NULL COMMENT '团队首领ID(钻石代理的ID,普通/黄金代理指向其团队首领)', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除', - `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_user_id` (`user_id`), - KEY `idx_mobile` (`mobile`), - KEY `idx_level` (`level`), - KEY `idx_team_leader_id` (`team_leader_id`), - KEY `idx_create_time` (`create_time`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代理基本信息表'; - --- ============================================ --- 2. 代理钱包表(注意:agent_audit 表已废弃,新系统通过邀请码直接成为代理,无需审核) --- ============================================ --- ============================================ -CREATE TABLE `agent_wallet` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `agent_id` bigint NOT NULL COMMENT '代理ID', - `balance` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '可用余额', - `frozen_balance` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '冻结余额', - `total_earnings` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '累计收益', - `withdrawn_amount` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '累计提现金额', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除', - `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_agent_id` (`agent_id`), - KEY `idx_create_time` (`create_time`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代理钱包表'; - --- ============================================ --- 4. 代理上下级关系表(支持脱离关系) --- ============================================ -CREATE TABLE `agent_relation` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `parent_id` bigint NOT NULL COMMENT '上级代理ID', - `child_id` bigint NOT NULL COMMENT '下级代理ID', - `relation_type` tinyint NOT NULL DEFAULT 1 COMMENT '关系类型:1=直接关系,2=已脱离(历史记录)', - `detach_reason` varchar(100) DEFAULT NULL COMMENT '脱离原因:upgrade=升级脱离', - `detach_time` datetime DEFAULT NULL COMMENT '脱离时间', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除', - `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_parent_child_type` (`parent_id`, `child_id`, `relation_type`), - KEY `idx_parent_id` (`parent_id`), - KEY `idx_child_id` (`child_id`), - KEY `idx_relation_type` (`relation_type`), - KEY `idx_parent_relation` (`parent_id`, `relation_type`) COMMENT '复合索引:查询有效下级', - KEY `idx_child_relation` (`child_id`, `relation_type`) COMMENT '复合索引:查询有效上级', - KEY `idx_create_time` (`create_time`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代理上下级关系表'; - --- ============================================ --- 5. 代理推广链接表 --- ============================================ -CREATE TABLE `agent_link` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `agent_id` bigint NOT NULL COMMENT '代理ID', - `user_id` bigint NOT NULL COMMENT '用户ID', - `product_id` bigint NOT NULL COMMENT '产品ID', - `link_identifier` varchar(200) NOT NULL COMMENT '推广链接标识(加密)', - `set_price` decimal(10,2) NOT NULL COMMENT '代理设定价格', - `actual_base_price` decimal(10,2) NOT NULL COMMENT '实际底价(基础底价+等级加成)', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除', - `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_link_identifier` (`link_identifier`), - UNIQUE KEY `uk_agent_product_price` (`agent_id`, `product_id`, `set_price`, `del_state`) COMMENT '唯一约束:同一代理、同一产品、同一价格只能有一个有效链接', - KEY `idx_agent_id` (`agent_id`), - KEY `idx_user_id` (`user_id`), - KEY `idx_product_id` (`product_id`), - KEY `idx_create_time` (`create_time`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代理推广链接表'; - --- ============================================ --- 6. 代理订单关联表 --- ============================================ -CREATE TABLE `agent_order` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `agent_id` bigint NOT NULL COMMENT '代理ID', - `order_id` bigint NOT NULL COMMENT '订单ID', - `product_id` bigint NOT NULL COMMENT '产品ID', - `order_amount` decimal(10,2) NOT NULL COMMENT '订单金额(用户实际支付金额,冗余字段)', - `set_price` decimal(10,2) NOT NULL COMMENT '代理设定价格', - `actual_base_price` decimal(10,2) NOT NULL COMMENT '实际底价(基础底价+等级加成)', - `price_cost` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '提价成本((设定价格-提价标准阈值)×提价手续费比例)', - `agent_profit` decimal(10,2) NOT NULL COMMENT '代理收益(设定价格-实际底价-提价成本)', - `process_status` tinyint NOT NULL DEFAULT 0 COMMENT '处理状态:0=待处理,1=处理成功,2=处理失败', - `process_time` datetime DEFAULT NULL COMMENT '处理时间', - `process_remark` varchar(500) DEFAULT NULL COMMENT '处理备注', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除', - `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_order_id` (`order_id`), - KEY `idx_agent_id` (`agent_id`), - KEY `idx_product_id` (`product_id`), - KEY `idx_process_status` (`process_status`), - KEY `idx_create_time` (`create_time`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代理订单关联表'; - --- ============================================ --- 7. 代理佣金记录表 --- ============================================ -CREATE TABLE `agent_commission` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `agent_id` bigint NOT NULL COMMENT '代理ID', - `order_id` bigint NOT NULL COMMENT '订单ID', - `product_id` bigint NOT NULL COMMENT '产品ID', - `amount` decimal(10,2) NOT NULL COMMENT '佣金金额', - `status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:1=已发放,2=已冻结,3=已取消', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除', - `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)', - PRIMARY KEY (`id`), - KEY `idx_agent_id` (`agent_id`), - KEY `idx_order_id` (`order_id`), - KEY `idx_product_id` (`product_id`), - KEY `idx_status` (`status`), - KEY `idx_agent_status` (`agent_id`, `status`) COMMENT '复合索引:查询代理的佣金记录', - KEY `idx_create_time` (`create_time`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代理佣金记录表'; - --- ============================================ --- 8. 代理返佣记录表(等级加成返佣) --- ============================================ -CREATE TABLE `agent_rebate` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `agent_id` bigint NOT NULL COMMENT '获得返佣的代理ID', - `source_agent_id` bigint NOT NULL COMMENT '来源代理ID(推广订单的代理)', - `order_id` bigint NOT NULL COMMENT '订单ID', - `product_id` bigint NOT NULL COMMENT '产品ID', - `rebate_type` tinyint NOT NULL COMMENT '返佣类型:1=直接上级返佣,2=钻石上级返佣,3=黄金上级返佣', - `level_bonus` decimal(10,2) NOT NULL COMMENT '等级加成金额(来源代理的等级加成)', - `rebate_amount` decimal(10,2) NOT NULL COMMENT '返佣金额', - `status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:1=已发放,2=已冻结,3=已取消', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除', - `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)', - PRIMARY KEY (`id`), - KEY `idx_agent_id` (`agent_id`), - KEY `idx_source_agent_id` (`source_agent_id`), - KEY `idx_order_id` (`order_id`), - KEY `idx_product_id` (`product_id`), - KEY `idx_rebate_type` (`rebate_type`), - KEY `idx_status` (`status`), - KEY `idx_order_rebate_type` (`order_id`, `rebate_type`) COMMENT '复合索引:查询订单的返佣明细', - KEY `idx_agent_status` (`agent_id`, `status`) COMMENT '复合索引:查询代理的返佣记录', - KEY `idx_create_time` (`create_time`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代理返佣记录表(等级加成返佣)'; - --- ============================================ --- 9. 代理升级记录表 --- ============================================ -CREATE TABLE `agent_upgrade` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `agent_id` bigint NOT NULL COMMENT '被升级的代理ID', - `from_level` tinyint NOT NULL COMMENT '原等级:1=普通,2=黄金,3=钻石', - `to_level` tinyint NOT NULL COMMENT '目标等级:1=普通,2=黄金,3=钻石', - `upgrade_type` tinyint NOT NULL COMMENT '升级类型:1=自主付费,2=钻石升级下级', - `upgrade_fee` decimal(10,2) DEFAULT 0.00 COMMENT '升级费用', - `rebate_amount` decimal(10,2) DEFAULT 0.00 COMMENT '返佣金额(给原直接上级)', - `rebate_agent_id` bigint DEFAULT NULL COMMENT '返佣代理ID(原直接上级)', - `operator_agent_id` bigint DEFAULT NULL COMMENT '操作代理ID(如果是钻石升级下级,记录操作者)', - `order_no` varchar(100) DEFAULT NULL COMMENT '支付订单号(如果是自主付费)', - `status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:1=待处理,2=已完成,3=已失败', - `remark` varchar(500) DEFAULT NULL COMMENT '备注', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除', - `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)', - PRIMARY KEY (`id`), - KEY `idx_agent_id` (`agent_id`), - KEY `idx_rebate_agent_id` (`rebate_agent_id`), - KEY `idx_operator_agent_id` (`operator_agent_id`), - KEY `idx_upgrade_type` (`upgrade_type`), - KEY `idx_status` (`status`), - KEY `idx_agent_status` (`agent_id`, `status`) COMMENT '复合索引:查询代理的升级记录', - KEY `idx_create_time` (`create_time`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代理升级记录表'; - --- ============================================ --- 10. 代理提现表 --- ============================================ -CREATE TABLE `agent_withdrawal` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `agent_id` bigint NOT NULL COMMENT '代理ID', - `withdraw_no` varchar(100) NOT NULL COMMENT '提现单号', - `payee_account` varchar(100) NOT NULL COMMENT '收款账户', - `payee_name` varchar(50) NOT NULL COMMENT '收款人姓名', - `amount` decimal(10,2) NOT NULL COMMENT '提现金额', - `actual_amount` decimal(10,2) NOT NULL COMMENT '实际到账金额(扣除税费后)', - `tax_amount` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '税费金额', - `status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:1=处理中,2=成功,3=失败', - `remark` varchar(500) DEFAULT NULL COMMENT '备注', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除', - `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_withdraw_no` (`withdraw_no`), - KEY `idx_agent_id` (`agent_id`), - KEY `idx_status` (`status`), - KEY `idx_agent_status` (`agent_id`, `status`) COMMENT '复合索引:查询代理的提现记录', - KEY `idx_create_time` (`create_time`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代理提现表'; - --- ============================================ --- 11. 代理系统配置表 --- ============================================ -CREATE TABLE `agent_config` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `config_key` varchar(100) NOT NULL COMMENT '配置键', - `config_value` varchar(500) NOT NULL COMMENT '配置值', - `config_type` varchar(50) NOT NULL COMMENT '配置类型:price=价格,bonus=等级加成,upgrade=升级费用,rebate=返佣,tax=税费', - `description` varchar(500) DEFAULT NULL COMMENT '配置描述', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除', - `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_config_key` (`config_key`), - KEY `idx_config_type` (`config_type`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代理系统配置表'; - --- ============================================ --- 12. 代理产品配置表(简化版) --- ============================================ -CREATE TABLE `agent_product_config` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `product_id` bigint NOT NULL COMMENT '产品ID', - `product_name` varchar(100) NOT NULL COMMENT '产品名称', - `base_price` decimal(10,2) NOT NULL COMMENT '基础底价(BasePrice)', - `system_max_price` decimal(10,2) NOT NULL COMMENT '系统价格上限(SystemMaxPrice)', - `price_threshold` decimal(10,2) DEFAULT NULL COMMENT '提价标准阈值(PriceThreshold)', - `price_fee_rate` decimal(5,4) DEFAULT NULL COMMENT '提价手续费比例(PriceFeeRate)', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除', - `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_product_id` (`product_id`), - KEY `idx_create_time` (`create_time`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代理产品配置表'; - --- ============================================ --- 13. 代理实名认证表 --- ============================================ -CREATE TABLE `agent_real_name` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `agent_id` bigint NOT NULL COMMENT '代理ID', - `name` varchar(50) NOT NULL COMMENT '真实姓名', - `id_card` varchar(50) NOT NULL COMMENT '身份证号(加密)', - `mobile` varchar(50) NOT NULL COMMENT '手机号(加密)', - `verify_time` datetime DEFAULT NULL COMMENT '验证时间(三要素验证通过时间,NULL表示未验证)', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除', - `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_agent_id` (`agent_id`), - KEY `idx_verify_time` (`verify_time`), - KEY `idx_create_time` (`create_time`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代理实名认证表'; - --- ============================================ --- 14. 代理提现扣税记录表 --- ============================================ -CREATE TABLE `agent_withdrawal_tax` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `agent_id` bigint NOT NULL COMMENT '代理ID', - `withdrawal_id` bigint NOT NULL COMMENT '提现记录ID', - `year_month` int NOT NULL COMMENT '年月(格式:YYYYMM)', - `withdrawal_amount` decimal(10,2) NOT NULL COMMENT '提现金额', - `taxable_amount` decimal(10,2) NOT NULL COMMENT '应税金额', - `tax_rate` decimal(5,4) NOT NULL COMMENT '税率', - `tax_amount` decimal(10,2) NOT NULL COMMENT '税费金额', - `actual_amount` decimal(10,2) NOT NULL COMMENT '实际到账金额', - `tax_status` tinyint NOT NULL DEFAULT 1 COMMENT '扣税状态:1=待扣税,2=已扣税,3=扣税失败', - `tax_time` datetime DEFAULT NULL COMMENT '扣税时间', - `remark` varchar(500) DEFAULT NULL COMMENT '备注', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除', - `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)', - PRIMARY KEY (`id`), - KEY `idx_agent_id` (`agent_id`), - KEY `idx_withdrawal_id` (`withdrawal_id`), - KEY `idx_year_month` (`year_month`), - KEY `idx_tax_status` (`tax_status`), - KEY `idx_agent_year_month` (`agent_id`, `year_month`) COMMENT '复合索引:查询代理的月度扣税记录' -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代理提现扣税记录表'; - --- ============================================ --- 初始化系统配置数据 --- ============================================ -INSERT INTO `agent_config` (`config_key`, `config_value`, `config_type`, `description`) VALUES -('base_price', '0.00', 'price', '系统基础底价(BasePrice)'), -('system_max_price', '9999.99', 'price', '系统价格上限(SystemMaxPrice)'), -('price_threshold', '0.00', 'price', '提价标准阈值(PriceThreshold)'), -('price_fee_rate', '0.0000', 'price', '提价手续费比例(PriceFeeRate)'), -('level_bonus_normal', '6.00', 'bonus', '普通代理等级加成(6元)'), -('level_bonus_gold', '3.00', 'bonus', '黄金代理等级加成(3元)'), -('level_bonus_diamond', '0.00', 'bonus', '钻石代理等级加成(0元)'), -('upgrade_fee_normal_to_gold', '199.00', 'upgrade', '普通→黄金升级费用(199元)'), -('upgrade_fee_to_diamond', '980.00', 'upgrade', '升级为钻石费用(980元)'), -('upgrade_rebate_normal_to_gold', '139.00', 'upgrade', '普通→黄金返佣金额(139元)'), -('upgrade_rebate_to_diamond', '680.00', 'upgrade', '升级为钻石返佣金额(680元)'), -('direct_parent_amount_diamond', '6.00', 'rebate', '直接上级是钻石的返佣金额(6元)'), -('direct_parent_amount_gold', '3.00', 'rebate', '直接上级是黄金的返佣金额(3元)'), -('direct_parent_amount_normal', '2.00', 'rebate', '直接上级是普通的返佣金额(2元)'), -('max_gold_rebate_amount', '3.00', 'rebate', '黄金代理最大返佣金额(3元)'), -('tax_rate', '0.0600', 'tax', '提现税率(6%)'); - --- ============================================ --- 15. 代理邀请码表 --- ============================================ -CREATE TABLE `agent_invite_code` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `code` varchar(50) NOT NULL COMMENT '邀请码(唯一)', - `agent_id` bigint DEFAULT NULL COMMENT '发放代理ID(NULL表示平台发放的钻石邀请码)', - `target_level` tinyint NOT NULL DEFAULT 1 COMMENT '目标等级:1=普通,2=黄金,3=钻石', - `status` tinyint NOT NULL DEFAULT 0 COMMENT '状态:0=未使用,1=已使用,2=已失效(钻石邀请码只能使用一次,普通邀请码可无限使用)', - `used_user_id` bigint DEFAULT NULL COMMENT '使用用户ID', - `used_agent_id` bigint DEFAULT NULL COMMENT '使用代理ID', - `used_time` datetime DEFAULT NULL COMMENT '使用时间', - `expire_time` datetime DEFAULT NULL COMMENT '过期时间(可选)', - `remark` varchar(500) DEFAULT NULL COMMENT '备注', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除', - `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_code` (`code`), - KEY `idx_agent_id` (`agent_id`), - KEY `idx_status` (`status`), - KEY `idx_target_level` (`target_level`), - KEY `idx_used_user_id` (`used_user_id`), - KEY `idx_create_time` (`create_time`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代理邀请码表'; - --- ============================================ --- 表创建完成 --- ============================================ --- 执行完成后,请使用goctl生成新的Model代码 --- 参考命令见 generate_agent_models.md 文件 - diff --git a/deploy/sql/generate_agent_models.md b/deploy/sql/generate_agent_models.md deleted file mode 100644 index c14bcc5..0000000 --- a/deploy/sql/generate_agent_models.md +++ /dev/null @@ -1,190 +0,0 @@ -# 生成新代理系统Model说明 - -## 一、执行数据库迁移 - -### 1.1 备份数据库(重要!) - -```bash -# 备份整个数据库 -mysqldump -u root -p your_database > backup_before_migration.sql - -# 或者只备份agent相关表 -mysqldump -u root -p your_database agent agent_audit agent_closure agent_commission agent_wallet agent_link agent_order agent_rewards agent_membership_config agent_product_config agent_real_name agent_withdrawal agent_withdrawal_tax agent_withdrawal_tax_exemption agent_active_stat agent_platform_deduction agent_commission_deduction agent_membership_recharge_order agent_membership_user_config > agent_tables_backup.sql -``` - -### 1.2 执行迁移SQL - -```bash -# 方式1:使用mysql命令行 -mysql -u root -p your_database < deploy/sql/agent_system_migration.sql - -# 方式2:使用数据库客户端工具(如Navicat、DBeaver等) -# 直接执行 deploy/sql/agent_system_migration.sql 文件 -``` - -## 二、生成Model代码 - -### 2.1 方式一:使用脚本批量生成(推荐) - -**Windows (PowerShell):** - -```powershell -# 修改脚本中的数据库配置 -# 然后执行(需要安装goctl工具) -cd deploy/sql -bash generate_agent_models.sh -``` - -**Linux/Mac:** - -```bash -# 修改脚本中的数据库配置 -chmod +x deploy/sql/generate_agent_models.sh -cd deploy/sql -./generate_agent_models.sh -``` - -### 2.2 方式二:使用goctl命令逐个生成 - -```bash -# 1. agent表 -goctl model mysql datasource -url="root:password@tcp(localhost:3306)/database" -table="agent" -dir="app/main/model" -cache=true --style=goZero --home="./deploy/template" - -# 2. agent_audit表 -goctl model mysql datasource -url="root:password@tcp(localhost:3306)/database" -table="agent_audit" -dir="app/main/model" -cache=true --style=goZero --home="./deploy/template" - -# 3. agent_wallet表 -goctl model mysql datasource -url="root:password@tcp(localhost:3306)/database" -table="agent_wallet" -dir="app/main/model" -cache=true --style=goZero --home="./deploy/template" - -# 4. agent_relation表(新表,替代agent_closure) -goctl model mysql datasource -url="root:password@tcp(localhost:3306)/database" -table="agent_relation" -dir="app/main/model" -cache=true --style=goZero --home="./deploy/template" - -# 5. agent_link表 -goctl model mysql datasource -url="root:password@tcp(localhost:3306)/database" -table="agent_link" -dir="app/main/model" -cache=true --style=goZero --home="./deploy/template" - -# 6. agent_order表 -goctl model mysql datasource -url="root:password@tcp(localhost:3306)/database" -table="agent_order" -dir="app/main/model" -cache=true --style=goZero --home="./deploy/template" - -# 7. agent_commission表 -goctl model mysql datasource -url="root:password@tcp(localhost:3306)/database" -table="agent_commission" -dir="app/main/model" -cache=true --style=goZero --home="./deploy/template" - -# 8. agent_rebate表(新表) -goctl model mysql datasource -url="root:password@tcp(localhost:3306)/database" -table="agent_rebate" -dir="app/main/model" -cache=true --style=goZero --home="./deploy/template" - -# 9. agent_upgrade表(新表) -goctl model mysql datasource -url="root:password@tcp(localhost:3306)/database" -table="agent_upgrade" -dir="app/main/model" -cache=true --style=goZero --home="./deploy/template" - -# 10. agent_withdrawal表 -goctl model mysql datasource -url="root:password@tcp(localhost:3306)/database" -table="agent_withdrawal" -dir="app/main/model" -cache=true --style=goZero --home="./deploy/template" - -# 11. agent_config表(新表) -goctl model mysql datasource -url="root:password@tcp(localhost:3306)/database" -table="agent_config" -dir="app/main/model" -cache=true --style=goZero --home="./deploy/template" - -# 12. agent_product_config表 -goctl model mysql datasource -url="root:password@tcp(localhost:3306)/database" -table="agent_product_config" -dir="app/main/model" -cache=true --style=goZero --home="./deploy/template" - -# 13. agent_real_name表 -goctl model mysql datasource -url="root:password@tcp(localhost:3306)/database" -table="agent_real_name" -dir="app/main/model" -cache=true --style=goZero --home="./deploy/template" - -# 14. agent_withdrawal_tax表 -goctl model mysql datasource -url="root:password@tcp(localhost:3306)/database" -table="agent_withdrawal_tax" -dir="app/main/model" -cache=true --style=goZero --home="./deploy/template" -``` - -### 2.3 方式三:使用goctl一次性生成所有表 - -```bash -# 生成所有agent相关表的Model -goctl model mysql datasource -url="root:password@tcp(localhost:3306)/database" -table="agent,agent_audit,agent_wallet,agent_relation,agent_link,agent_order,agent_commission,agent_rebate,agent_upgrade,agent_withdrawal,agent_config,agent_product_config,agent_real_name,agent_withdrawal_tax" -dir="app/main/model" -cache=true --style=goZero --home="./deploy/template" -``` - -## 三、表结构变化说明 - -### 3.1 删除的旧表 - -以下表在新系统中已删除,不再需要: - -- `agent_closure` → 被 `agent_relation` 替代 -- `agent_commission_deduction` → 新系统不需要 -- `agent_rewards` → 新系统不需要 -- `agent_membership_config` → 新系统不需要 -- `agent_membership_recharge_order` → 新系统不需要 -- `agent_membership_user_config` → 新系统不需要 -- `agent_platform_deduction` → 新系统不需要 -- `agent_active_stat` → 新系统不需要 -- `agent_withdrawal_tax_exemption` → 新系统不需要 - -### 3.2 新增的表 - -- `agent_relation` - 替代 `agent_closure`,支持关系脱离 -- `agent_rebate` - 等级加成返佣记录表 -- `agent_upgrade` - 代理升级记录表 -- `agent_config` - 代理系统配置表 - -### 3.3 结构变化的表 - -以下表结构有变化,需要重新生成Model: - -- `agent` - 等级字段改为数值型,新增 `team_leader_id` -- `agent_audit` - 新增 `ancestor_mobile`、`audit_user_id` 字段 -- `agent_wallet` - 字段保持不变 -- `agent_link` - 新增唯一约束 -- `agent_order` - 新增 `order_amount`、`process_status` 等字段 -- `agent_commission` - 字段保持不变 -- `agent_product_config` - 字段保持不变 -- `agent_real_name` - 新增 `audit_user_id` 字段 -- `agent_withdrawal` - 字段保持不变 -- `agent_withdrawal_tax` - 字段保持不变 - -## 四、生成后的文件结构 - -生成后,会在 `app/main/model` 目录下创建以下文件: - -``` -app/main/model/ -├── agentModel.go # agent表Model(自定义方法) -├── agentModel_gen.go # agent表Model(自动生成) -├── agentAuditModel.go # agent_audit表Model(自定义方法) -├── agentAuditModel_gen.go # agent_audit表Model(自动生成) -├── agentWalletModel.go # agent_wallet表Model(自定义方法) -├── agentWalletModel_gen.go # agent_wallet表Model(自动生成) -├── agentRelationModel.go # agent_relation表Model(自定义方法,新) -├── agentRelationModel_gen.go # agent_relation表Model(自动生成,新) -├── agentLinkModel.go # agent_link表Model(自定义方法) -├── agentLinkModel_gen.go # agent_link表Model(自动生成) -├── agentOrderModel.go # agent_order表Model(自定义方法) -├── agentOrderModel_gen.go # agent_order表Model(自动生成) -├── agentCommissionModel.go # agent_commission表Model(自定义方法) -├── agentCommissionModel_gen.go # agent_commission表Model(自动生成) -├── agentRebateModel.go # agent_rebate表Model(自定义方法,新) -├── agentRebateModel_gen.go # agent_rebate表Model(自动生成,新) -├── agentUpgradeModel.go # agent_upgrade表Model(自定义方法,新) -├── agentUpgradeModel_gen.go # agent_upgrade表Model(自动生成,新) -├── agentWithdrawalModel.go # agent_withdrawal表Model(自定义方法) -├── agentWithdrawalModel_gen.go # agent_withdrawal表Model(自动生成) -├── agentConfigModel.go # agent_config表Model(自定义方法,新) -├── agentConfigModel_gen.go # agent_config表Model(自动生成,新) -├── agentProductConfigModel.go # agent_product_config表Model(自定义方法) -├── agentProductConfigModel_gen.go # agent_product_config表Model(自动生成) -├── agentRealNameModel.go # agent_real_name表Model(自定义方法) -├── agentRealNameModel_gen.go # agent_real_name表Model(自动生成) -├── agentWithdrawalTaxModel.go # agent_withdrawal_tax表Model(自定义方法) -└── agentWithdrawalTaxModel_gen.go # agent_withdrawal_tax表Model(自动生成) -``` - -## 五、注意事项 - -1. **备份数据**:执行迁移前务必备份数据库 -2. **测试环境**:建议先在测试环境执行,验证无误后再在生产环境执行 -3. **代码兼容**:生成新Model后,需要更新相关业务代码以适配新的表结构 -4. **删除旧Model**:生成新Model后,需要删除旧的Model文件(如 `agentClosureModel.go`) -5. **更新ServiceContext**:需要在 `svc/servicecontext.go` 中更新Model初始化代码 - -## 六、验证 - -生成Model后,请验证: - -1. 所有新表都有对应的Model文件 -2. Model文件可以正常编译 -3. 数据库连接正常 -4. 基本的CRUD操作可以正常执行 - diff --git a/deploy/sql/generate_agent_models.sh b/deploy/sql/generate_agent_models.sh deleted file mode 100644 index 763e0bb..0000000 --- a/deploy/sql/generate_agent_models.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/bash -# ============================================ -# 生成新代理系统Model脚本 -# 使用goctl工具根据数据库表生成Model代码 -# ============================================ - -# 数据库配置(请根据实际情况修改) -DB_HOST="localhost" -DB_PORT="3306" -DB_USER="root" -DB_PASSWORD="your_password" -DB_NAME="your_database" - -# Model输出目录 -MODEL_DIR="app/main/model" - -# goctl模板目录 -TEMPLATE_DIR="./deploy/template" - -echo "============================================" -echo "开始生成新代理系统Model..." -echo "============================================" - -# 生成各个表的Model -echo "1. 生成 agent Model..." -goctl model mysql datasource -url="${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:${DB_PORT})/${DB_NAME}" -table="agent" -dir="${MODEL_DIR}" -cache=true --style=goZero --home="${TEMPLATE_DIR}" - -echo "2. 生成 agent_audit Model..." -goctl model mysql datasource -url="${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:${DB_PORT})/${DB_NAME}" -table="agent_audit" -dir="${MODEL_DIR}" -cache=true --style=goZero --home="${TEMPLATE_DIR}" - -echo "3. 生成 agent_wallet Model..." -goctl model mysql datasource -url="${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:${DB_PORT})/${DB_NAME}" -table="agent_wallet" -dir="${MODEL_DIR}" -cache=true --style=goZero --home="${TEMPLATE_DIR}" - -echo "4. 生成 agent_relation Model..." -goctl model mysql datasource -url="${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:${DB_PORT})/${DB_NAME}" -table="agent_relation" -dir="${MODEL_DIR}" -cache=true --style=goZero --home="${TEMPLATE_DIR}" - -echo "5. 生成 agent_link Model..." -goctl model mysql datasource -url="${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:${DB_PORT})/${DB_NAME}" -table="agent_link" -dir="${MODEL_DIR}" -cache=true --style=goZero --home="${TEMPLATE_DIR}" - -echo "6. 生成 agent_order Model..." -goctl model mysql datasource -url="${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:${DB_PORT})/${DB_NAME}" -table="agent_order" -dir="${MODEL_DIR}" -cache=true --style=goZero --home="${TEMPLATE_DIR}" - -echo "7. 生成 agent_commission Model..." -goctl model mysql datasource -url="${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:${DB_PORT})/${DB_NAME}" -table="agent_commission" -dir="${MODEL_DIR}" -cache=true --style=goZero --home="${TEMPLATE_DIR}" - -echo "8. 生成 agent_rebate Model..." -goctl model mysql datasource -url="${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:${DB_PORT})/${DB_NAME}" -table="agent_rebate" -dir="${MODEL_DIR}" -cache=true --style=goZero --home="${TEMPLATE_DIR}" - -echo "9. 生成 agent_upgrade Model..." -goctl model mysql datasource -url="${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:${DB_PORT})/${DB_NAME}" -table="agent_upgrade" -dir="${MODEL_DIR}" -cache=true --style=goZero --home="${TEMPLATE_DIR}" - -echo "10. 生成 agent_withdrawal Model..." -goctl model mysql datasource -url="${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:${DB_PORT})/${DB_NAME}" -table="agent_withdrawal" -dir="${MODEL_DIR}" -cache=true --style=goZero --home="${TEMPLATE_DIR}" - -echo "11. 生成 agent_config Model..." -goctl model mysql datasource -url="${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:${DB_PORT})/${DB_NAME}" -table="agent_config" -dir="${MODEL_DIR}" -cache=true --style=goZero --home="${TEMPLATE_DIR}" - -echo "12. 生成 agent_product_config Model..." -goctl model mysql datasource -url="${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:${DB_PORT})/${DB_NAME}" -table="agent_product_config" -dir="${MODEL_DIR}" -cache=true --style=goZero --home="${TEMPLATE_DIR}" - -echo "13. 生成 agent_real_name Model..." -goctl model mysql datasource -url="${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:${DB_PORT})/${DB_NAME}" -table="agent_real_name" -dir="${MODEL_DIR}" -cache=true --style=goZero --home="${TEMPLATE_DIR}" - -echo "14. 生成 agent_withdrawal_tax Model..." -goctl model mysql datasource -url="${DB_USER}:${DB_PASSWORD}@tcp(${DB_HOST}:${DB_PORT})/${DB_NAME}" -table="agent_withdrawal_tax" -dir="${MODEL_DIR}" -cache=true --style=goZero --home="${TEMPLATE_DIR}" - -echo "============================================" -echo "Model生成完成!" -echo "============================================" - diff --git a/deploy/sql/query_user_record.sql b/deploy/sql/query_user_record.sql new file mode 100644 index 0000000..2491777 --- /dev/null +++ b/deploy/sql/query_user_record.sql @@ -0,0 +1,52 @@ +-- 查询用户记录表 +-- 用途:记录用户查询时输入的姓名、身份证、手机号,以及支付订单号等,用于通过查询条件追溯订单信息 +-- 执行说明:在目标数据库执行此脚本创建表 +-- +-- 使用说明(需在业务代码中接入): +-- 1. 用户提交查询时(queryservicelogic.CacheData 之后):INSERT 记录 name, id_card, mobile(已 AES-ECB+Base64 加密), product, query_no, user_id, agent_identifier +-- 2. 用户发起支付并创建 order 时(paymentlogic.QueryOrderPayment 中 Insert order 之后):UPDATE 本表 SET order_id WHERE query_no=outTradeNo +-- 3. 支付回调成功更新 order 后(alipaycallbacklogic/wechatpaycallbacklogic):UPDATE 本表 SET platform_order_id WHERE query_no=orderNo +-- +-- 敏感字段加密:name、id_card、mobile 使用 pkg/lzkit/crypto 的 AES-ECB+Base64 加密后入库,密钥为 config.Encrypt.SecretKey(hex)。 +-- 解密:姓名 crypto.AesEcbDecrypt(rec.Name, key);身份证 crypto.DecryptIDCard(rec.IdCard, key);手机 crypto.DecryptMobile(rec.Mobile, secretKey)。 +-- +-- 查询功能说明: +-- 后台订单列表页面可以通过被查询人的姓名、身份证号、手机号(三要素)筛选对应的订单 +-- 支持单独使用任一要素查询,也支持组合查询(AND 关系) +-- 查询逻辑:先加密查询条件,然后在 query_user_record 表中查找匹配记录,再通过 order_id 或 query_no 关联到 order 表 + +CREATE TABLE `query_user_record` ( + `id` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键ID(UUID)', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `delete_time` datetime DEFAULT NULL COMMENT '删除时间', + `del_state` tinyint NOT NULL DEFAULT '0' COMMENT '删除状态:0-未删除,1-已删除', + `version` bigint NOT NULL DEFAULT '0' COMMENT '版本号', + + /* 业务字段 - 用户查询输入(name、id_card、mobile 为 AES-ECB+Base64 密文) */ + `user_id` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户ID(UUID,关联 user 表)', + `name` varchar(256) NOT NULL DEFAULT '' COMMENT '姓名密文(AES-ECB+Base64),用于按姓名筛选订单', + `id_card` varchar(128) NOT NULL DEFAULT '' COMMENT '身份证号密文(AES-ECB+Base64),用于按身份证号筛选订单', + `mobile` varchar(128) NOT NULL DEFAULT '' COMMENT '手机号密文(AES-ECB+Base64),用于按手机号筛选订单', + `product` varchar(50) NOT NULL DEFAULT '' COMMENT '产品类型,如 marriage/homeservice/riskassessment 等', + + /* 关联字段 - 查询单号与订单 */ + `query_no` varchar(64) NOT NULL DEFAULT '' COMMENT '查询单号(与 order.order_no 一致,如 Q_xxx),用户提交查询时生成', + `order_id` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '订单ID(UUID,关联 order 表),用户发起支付并创建订单后写入', + `platform_order_id` varchar(64) DEFAULT NULL COMMENT '支付平台订单号(支付宝/微信),支付成功后由回调写入', + `agent_identifier` varchar(255) DEFAULT NULL COMMENT '代理标识,代理渠道时有值', + + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`) COMMENT '用于按用户ID查询', + KEY `idx_name` (`name`) COMMENT '用于按姓名筛选订单(精确匹配加密后的密文)', + KEY `idx_id_card` (`id_card`) COMMENT '用于按身份证号筛选订单(精确匹配加密后的密文)', + KEY `idx_mobile` (`mobile`) COMMENT '用于按手机号筛选订单(精确匹配加密后的密文)', + KEY `idx_query_no` (`query_no`) COMMENT '用于按查询单号查询', + KEY `idx_order_id` (`order_id`) COMMENT '用于按订单ID查询', + KEY `idx_platform_order_id` (`platform_order_id`) COMMENT '用于按支付平台订单号查询', + KEY `idx_create_time` (`create_time`) COMMENT '用于按创建时间排序', + KEY `idx_del_state_order_id` (`del_state`, `order_id`) COMMENT '用于筛选未删除记录并按订单ID查询', + KEY `idx_del_state_query_no` (`del_state`, `query_no`) COMMENT '用于筛选未删除记录并按查询单号查询', + KEY `idx_name_id_card_mobile` (`name`, `id_card`, `mobile`) COMMENT '复合索引:用于多条件组合筛选(姓名+身份证+手机号)', + KEY `idx_del_state_name_id_card_mobile` (`del_state`, `name`, `id_card`, `mobile`) COMMENT '复合索引:用于筛选未删除记录并按三要素组合查询' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='查询用户记录表:姓名、身份证、手机号、支付订单号等,用于通过查询信息追溯订单。支持通过被查询人三要素(姓名、身份证、手机号)筛选订单' ROW_FORMAT=DYNAMIC; diff --git a/deploy/sql/query_user_record_add_indexes.sql b/deploy/sql/query_user_record_add_indexes.sql new file mode 100644 index 0000000..b7e7c8d --- /dev/null +++ b/deploy/sql/query_user_record_add_indexes.sql @@ -0,0 +1,66 @@ +-- ============================================================ +-- 查询用户记录表 - 添加索引脚本 +-- 用途:为已存在的 query_user_record 表添加索引,优化按姓名、身份证、手机号筛选订单的查询性能 +-- 执行说明:在目标数据库执行此脚本添加索引 +-- 注意:如果索引已存在,执行会报错,可以忽略或先检查索引是否存在 +-- ============================================================ + +-- 检查并添加 idx_name 索引(用于按姓名筛选订单) +-- 如果索引已存在,此语句会报错,可以忽略 +ALTER TABLE `query_user_record` +ADD INDEX `idx_name` (`name`) COMMENT '用于按姓名筛选订单'; + +-- 检查并添加 idx_del_state_order_id 复合索引(用于筛选未删除记录并按订单ID查询) +-- 如果索引已存在,此语句会报错,可以忽略 +ALTER TABLE `query_user_record` +ADD INDEX `idx_del_state_order_id` (`del_state`, `order_id`) COMMENT '用于筛选未删除记录并按订单ID查询'; + +-- 检查并添加 idx_name_id_card_mobile 复合索引(用于多条件组合筛选) +-- 如果索引已存在,此语句会报错,可以忽略 +ALTER TABLE `query_user_record` +ADD INDEX `idx_name_id_card_mobile` (`name`, `id_card`, `mobile`) COMMENT '复合索引:用于多条件组合筛选(姓名+身份证+手机号)'; + +-- ============================================================ +-- 可选:如果希望先检查索引是否存在再添加,可以使用以下存储过程方式 +-- ============================================================ +-- +-- DELIMITER $$ +-- +-- DROP PROCEDURE IF EXISTS `add_index_if_not_exists`$$ +-- +-- CREATE PROCEDURE `add_index_if_not_exists`( +-- IN p_table_name VARCHAR(128), +-- IN p_index_name VARCHAR(128), +-- IN p_index_definition TEXT +-- ) +-- BEGIN +-- DECLARE v_index_exists INT DEFAULT 0; +-- +-- SELECT COUNT(*) INTO v_index_exists +-- FROM information_schema.statistics +-- WHERE table_schema = DATABASE() +-- AND table_name = p_table_name +-- AND index_name = p_index_name; +-- +-- IF v_index_exists = 0 THEN +-- SET @sql = CONCAT('ALTER TABLE `', p_table_name, '` ADD INDEX `', p_index_name, '` ', p_index_definition); +-- PREPARE stmt FROM @sql; +-- EXECUTE stmt; +-- DEALLOCATE PREPARE stmt; +-- SELECT CONCAT('索引 ', p_index_name, ' 已成功添加') AS result; +-- ELSE +-- SELECT CONCAT('索引 ', p_index_name, ' 已存在,跳过') AS result; +-- END IF; +-- END$$ +-- +-- DELIMITER ; +-- +-- -- 使用存储过程添加索引 +-- CALL `add_index_if_not_exists`('query_user_record', 'idx_name', '(`name`) COMMENT ''用于按姓名筛选订单'''); +-- CALL `add_index_if_not_exists`('query_user_record', 'idx_del_state_order_id', '(`del_state`, `order_id`) COMMENT ''用于筛选未删除记录并按订单ID查询'''); +-- CALL `add_index_if_not_exists`('query_user_record', 'idx_name_id_card_mobile', '(`name`, `id_card`, `mobile`) COMMENT ''复合索引:用于多条件组合筛选(姓名+身份证+手机号)'''); +-- +-- -- 清理存储过程 +-- DROP PROCEDURE IF EXISTS `add_index_if_not_exists`; +-- +-- ============================================================ diff --git a/deploy/sql/remove_product_name_from_agent_product_config.sql b/deploy/sql/remove_product_name_from_agent_product_config.sql deleted file mode 100644 index 30f2950..0000000 --- a/deploy/sql/remove_product_name_from_agent_product_config.sql +++ /dev/null @@ -1,25 +0,0 @@ --- ============================================ --- 移除代理产品配置表中的 product_name 字段 --- 说明:改为通过 product_id 关联查询 product 表获取产品名称 --- 执行时间:2025-01-XX --- ============================================ - --- 删除 product_name 字段 -ALTER TABLE `agent_product_config` DROP COLUMN `product_name`; - --- ============================================ --- 验证查询:检查字段是否已删除 --- ============================================ -DESC `agent_product_config`; - --- ============================================ --- 验证查询:通过关联查询获取产品名称 --- ============================================ -SELECT apc.id, apc.product_id, p.product_name, apc.base_price, apc.system_max_price, apc.price_threshold, apc.price_fee_rate, apc.del_state, apc.create_time -FROM - `agent_product_config` apc - LEFT JOIN `product` p ON apc.product_id = p.id - AND p.del_state = 0 -WHERE - apc.del_state = 0 -ORDER BY apc.product_id; \ No newline at end of file diff --git a/deploy/sql/sync_agent_product_config.sql b/deploy/sql/sync_agent_product_config.sql deleted file mode 100644 index d5e0c4d..0000000 --- a/deploy/sql/sync_agent_product_config.sql +++ /dev/null @@ -1,112 +0,0 @@ --- ============================================ --- 同步产品表数据到代理产品配置表 --- 说明:为现有产品创建对应的代理产品配置记录 --- 执行时间:2025-01-XX --- ============================================ - --- 方式1:使用 INSERT IGNORE(如果记录已存在则忽略) --- 注意:product_name 字段已移除,改为通过 product_id 关联查询 product 表获取 -INSERT IGNORE INTO - `agent_product_config` ( - `product_id`, - `base_price`, - `system_max_price`, - `price_threshold`, - `price_fee_rate`, - `del_state`, - `version` - ) -VALUES ( - 1, - 0.00, - 9999.99, - NULL, - NULL, - 0, - 0 - ), - ( - 2, - 0.00, - 9999.99, - NULL, - NULL, - 0, - 0 - ), - ( - 3, - 0.00, - 9999.99, - NULL, - NULL, - 0, - 0 - ), - ( - 4, - 0.00, - 9999.99, - NULL, - NULL, - 0, - 0 - ), - ( - 5, - 0.00, - 9999.99, - NULL, - NULL, - 0, - 0 - ), - ( - 6, - 0.00, - 9999.99, - NULL, - NULL, - 0, - 0 - ), - ( - 7, - 0.00, - 9999.99, - NULL, - NULL, - 0, - 0 - ); - --- ============================================ --- 方式2:使用 INSERT ... ON DUPLICATE KEY UPDATE(如果记录已存在则忽略) --- 注意:product_name 字段已移除,不再需要更新 --- ============================================ -/* -INSERT INTO `agent_product_config` -(`product_id`, `base_price`, `system_max_price`, `price_threshold`, `price_fee_rate`, `del_state`, `version`) -VALUES -(1, 0.00, 9999.99, NULL, NULL, 0, 0), -(2, 0.00, 9999.99, NULL, NULL, 0, 0), -(3, 0.00, 9999.99, NULL, NULL, 0, 0), -(4, 0.00, 9999.99, NULL, NULL, 0, 0), -(5, 0.00, 9999.99, NULL, NULL, 0, 0), -(6, 0.00, 9999.99, NULL, NULL, 0, 0), -(7, 0.00, 9999.99, NULL, NULL, 0, 0) -ON DUPLICATE KEY UPDATE -`product_id` = VALUES(`product_id`); -*/ - --- ============================================ --- 验证查询:检查同步结果 --- ============================================ -SELECT apc.id, apc.product_id, p.product_name, apc.base_price, apc.system_max_price, apc.price_threshold, apc.price_fee_rate, apc.del_state, apc.create_time -FROM - `agent_product_config` apc - LEFT JOIN `product` p ON apc.product_id = p.id - AND p.del_state = 0 -WHERE - apc.del_state = 0 -ORDER BY apc.product_id; \ No newline at end of file diff --git a/deploy/sql/template.sql b/deploy/sql/template.sql deleted file mode 100644 index 70e809d..0000000 --- a/deploy/sql/template.sql +++ /dev/null @@ -1,62 +0,0 @@ --- ============================================ --- 表结构模板(UUID版本) --- ============================================ --- 注意:系统已迁移到UUID主键,新表请使用此模板 --- ============================================ - -CREATE TABLE `表名` ( - `id` CHAR(36) NOT NULL COMMENT 'UUID主键', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `delete_time` datetime DEFAULT NULL COMMENT '删除时间', - `del_state` tinyint NOT NULL DEFAULT '0', - `version` bigint NOT NULL DEFAULT '0' COMMENT '版本号', - -/* 业务字段开始 */ - -`字段1` 数据类型 [约束条件] [DEFAULT 默认值] [COMMENT '字段说明'], - `字段2` 数据类型 [约束条件] [DEFAULT 默认值] [COMMENT '字段说明'], - /* 关联字段 - 软关联(使用UUID) */ - `关联表id` CHAR(36) [NOT NULL] [DEFAULT NULL] COMMENT '关联到XX表的UUID', - /* 业务字段结束 */ - - PRIMARY KEY (`id`), - /* 索引定义 */ - UNIQUE KEY `索引名称` (`字段名`), - KEY `idx_关联字段` (`关联表id`) COMMENT '优化关联查询' -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='表说明'; - --- ============================================ --- UUID生成说明 --- ============================================ --- 1. 应用层生成:使用Go的uuid.NewString()生成UUID --- 示例:id := uuid.NewString() --- 2. 数据库层生成:使用MySQL的UUID()函数(不推荐,性能较差) --- 示例:INSERT INTO table (id, ...) VALUES (UUID(), ...) --- 3. 推荐方式:在应用层生成UUID,然后插入数据库 --- ============================================ - --- ============================================ --- 旧版本模板(bigint主键,已废弃) --- ============================================ --- CREATE TABLE `表名` ( --- `id` bigint NOT NULL AUTO_INCREMENT, --- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, --- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, --- `delete_time` datetime DEFAULT NULL COMMENT '删除时间', --- `del_state` tinyint NOT NULL DEFAULT '0', --- `version` bigint NOT NULL DEFAULT '0' COMMENT '版本号', --- --- /* 业务字段开始 */ --- `字段1` 数据类型 [约束条件] [DEFAULT 默认值] [COMMENT '字段说明'], --- `字段2` 数据类型 [约束条件] [DEFAULT 默认值] [COMMENT '字段说明'], --- /* 关联字段 - 软关联 */ --- `关联表id` bigint [NOT NULL] [DEFAULT '0'] COMMENT '关联到XX表的id', --- /* 业务字段结束 */ --- --- PRIMARY KEY (`id`), --- /* 索引定义 */ --- UNIQUE KEY `索引名称` (`字段名`), --- KEY `idx_关联字段` (`关联表id`) COMMENT '优化关联查询' --- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='表说明'; --- ============================================ \ No newline at end of file diff --git a/deploy/sql/user_system_refactor.sql b/deploy/sql/user_system_refactor.sql deleted file mode 100644 index 8dfd90c..0000000 --- a/deploy/sql/user_system_refactor.sql +++ /dev/null @@ -1,48 +0,0 @@ --- ============================================ --- 用户系统重构SQL脚本(简化版 - 开发环境) --- 根据《用户系统重构计划书》执行 --- ============================================ - --- ============================================ --- 第一部分:UserAuth表唯一索引 --- ============================================ - --- 确保user_auth表的(auth_type, auth_key)唯一性 --- 如果已存在同名索引,先删除 -ALTER TABLE `user_auth` DROP INDEX IF EXISTS `uk_auth_type_key`; - --- 添加唯一索引 -ALTER TABLE `user_auth` -ADD UNIQUE INDEX `uk_auth_type_key` (`auth_type`, `auth_key`) COMMENT '确保同一个认证方式只能绑定一个用户'; - --- 允许一个用户绑定同一认证类型的多个记录(例如多个UUID) -ALTER TABLE `user_auth` DROP INDEX IF EXISTS `unique_userId_key`; -ALTER TABLE `user_auth` ADD INDEX `idx_user_id_auth_type` (`user_id`, `auth_type`); - --- ============================================ --- 第二部分:删除UserTemp表(开发环境直接删除) --- ============================================ - --- 注意:开发环境没有数据,直接删除表即可 --- 如果表不存在,会报错但可以忽略 - -DROP TABLE IF EXISTS `user_temp`; - --- ============================================ --- 第三部分:索引优化(可选) --- ============================================ - --- 为user_auth表添加user_id和auth_type的联合索引(如果查询频繁) --- ALTER TABLE `user_auth` --- ADD INDEX `idx_user_id_auth_type` (`user_id`, `auth_type`) COMMENT '优化按用户查询认证类型'; - --- 为user表添加mobile的唯一索引(如果不存在) --- ALTER TABLE `user` --- ADD UNIQUE INDEX `uk_mobile` (`mobile`) COMMENT '确保手机号唯一性'; - --- ============================================ --- 注意事项 --- ============================================ --- 1. 此脚本适用于开发环境,直接删除UserTemp表 --- 2. 如果生产环境有数据,请使用完整版迁移脚本 --- 3. 执行后,确保代码中已移除所有对UserTemp表的引用 diff --git a/deploy/sql/user_temp_migration.sql b/deploy/sql/user_temp_migration.sql deleted file mode 100644 index 17e4bad..0000000 --- a/deploy/sql/user_temp_migration.sql +++ /dev/null @@ -1,45 +0,0 @@ --- 将 user_temp 迁移为 user(mobile 为空)与 user_auth - -START TRANSACTION; - --- 1) 迁移临时用户到 user(mobile 置为空) -INSERT INTO - `user` ( - `delete_time`, - `del_state`, - `version`, - `mobile`, - `password`, - `nickname`, - `info`, - `inside` - ) -SELECT NULL, 0, COALESCE(ut.version, 0), NULL, NULL, NULL, '', 0 -FROM `user_temp` ut -WHERE - ut.del_state = 0; - --- 2) 将临时认证迁移到 user_auth(按插入顺序关联最近插入的 user.id) -INSERT INTO - `user_auth` ( - `delete_time`, - `del_state`, - `version`, - `user_id`, - `auth_key`, - `auth_type` - ) -SELECT NULL, 0, COALESCE(ut.version, 0), u.id, ut.auth_key, ut.auth_type -FROM `user_temp` ut - JOIN `user` u ON u.del_state = 0 - AND u.mobile IS NULL -WHERE - ut.del_state = 0; - --- 注意:以上为示意,实际生产应通过显式映射(如临时ID与新UserID映射表)确保一一对应,避免笛卡尔匹配。 - -COMMIT; - --- 唯一索引保障 -ALTER TABLE `user_auth` -ADD UNIQUE INDEX `idx_auth_type_key` (`auth_type`, `auth_key`); \ No newline at end of file diff --git a/deploy/sql/uuid_migration.sql b/deploy/sql/uuid_migration.sql deleted file mode 100644 index 9da7cf2..0000000 --- a/deploy/sql/uuid_migration.sql +++ /dev/null @@ -1,1831 +0,0 @@ --- ============================================ --- UUID迁移脚本 --- 将系统中所有bigint类型的ID字段改为CHAR(36)类型的UUID --- ============================================ - --- 注意:此脚本需要分阶段执行,建议在测试环境充分测试后再在生产环境执行 --- 执行前请务必备份数据库! - --- ============================================ --- 第一阶段:创建UUID映射表(用于数据迁移) --- ============================================ - --- 创建临时映射表,用于存储旧ID和新UUID的对应关系 -CREATE TABLE IF NOT EXISTS `uuid_mapping` ( - `table_name` VARCHAR(64) NOT NULL COMMENT '表名', - `old_id` BIGINT NOT NULL COMMENT '旧ID', - `new_uuid` CHAR(36) NOT NULL COMMENT '新UUID', - PRIMARY KEY (`table_name`, `old_id`), - KEY `idx_new_uuid` (`new_uuid`) -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'UUID映射表'; - --- ============================================ --- 第二阶段:为所有表生成UUID映射 --- ============================================ - --- 为user表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'user', `id`, UUID() -FROM `user` -WHERE - `del_state` = 0; - --- 为agent表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'agent', `id`, UUID() -FROM `agent` -WHERE - `del_state` = 0; - --- 为product表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'product', `id`, UUID() -FROM `product` -WHERE - `del_state` = 0; - --- 为order表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'order', `id`, UUID() -FROM `order` -WHERE - `del_state` = 0; - --- 为query表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'query', `id`, UUID() -FROM `query` -WHERE - `del_state` = 0; - --- 为user_auth表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'user_auth', `id`, UUID() -FROM `user_auth` -WHERE - `del_state` = 0; - --- 为agent_commission表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'agent_commission', `id`, UUID() -FROM `agent_commission` -WHERE - `del_state` = 0; - --- 为agent_invite_code表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'agent_invite_code', `id`, UUID() -FROM `agent_invite_code` -WHERE - `del_state` = 0; - --- 为agent_link表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'agent_link', `id`, UUID() -FROM `agent_link` -WHERE - `del_state` = 0; - --- 为agent_order表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'agent_order', `id`, UUID() -FROM `agent_order` -WHERE - `del_state` = 0; - --- 为agent_wallet表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'agent_wallet', `id`, UUID() -FROM `agent_wallet` -WHERE - `del_state` = 0; - --- 为agent_withdrawal表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'agent_withdrawal', `id`, UUID() -FROM `agent_withdrawal` -WHERE - `del_state` = 0; - --- 为agent_withdrawal_tax表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'agent_withdrawal_tax', `id`, UUID() -FROM `agent_withdrawal_tax` -WHERE - `del_state` = 0; - --- 为agent_rebate表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'agent_rebate', `id`, UUID() -FROM `agent_rebate` -WHERE - `del_state` = 0; - --- 为agent_relation表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'agent_relation', `id`, UUID() -FROM `agent_relation` -WHERE - `del_state` = 0; - --- 为agent_upgrade表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'agent_upgrade', `id`, UUID() -FROM `agent_upgrade` -WHERE - `del_state` = 0; - --- 为agent_real_name表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'agent_real_name', `id`, UUID() -FROM `agent_real_name` -WHERE - `del_state` = 0; - --- 为agent_config表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'agent_config', `id`, UUID() -FROM `agent_config` -WHERE - `del_state` = 0; - --- 为agent_product_config表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'agent_product_config', `id`, UUID() -FROM `agent_product_config` -WHERE - `del_state` = 0; - --- 为agent_short_link表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'agent_short_link', `id`, UUID() -FROM `agent_short_link` -WHERE - `del_state` = 0; - --- 为agent_invite_code_usage表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'agent_invite_code_usage', `id`, UUID() -FROM `agent_invite_code_usage` -WHERE - `del_state` = 0; - --- 为agent_freeze_task表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'agent_freeze_task', `id`, UUID() -FROM `agent_freeze_task` -WHERE - `del_state` = 0; - --- 为order_refund表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'order_refund', `id`, UUID() -FROM `order_refund` -WHERE - `del_state` = 0; - --- 为query_cleanup_log表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'query_cleanup_log', `id`, UUID() -FROM `query_cleanup_log` -WHERE - `del_state` = 0; - --- 为query_cleanup_detail表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'query_cleanup_detail', `id`, UUID() -FROM `query_cleanup_detail` -WHERE - `del_state` = 0; - --- 为query_cleanup_config表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'query_cleanup_config', `id`, UUID() -FROM `query_cleanup_config` -WHERE - `del_state` = 0; - --- 为product_feature表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'product_feature', `id`, UUID() -FROM `product_feature` -WHERE - `del_state` = 0; - --- 为feature表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'feature', `id`, UUID() -FROM `feature` -WHERE - `del_state` = 0; - --- 为authorization_document表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'authorization_document', `id`, UUID() -FROM `authorization_document` -WHERE - `del_state` = 0; - --- 为global_notifications表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'global_notifications', `id`, UUID() -FROM `global_notifications` -WHERE - `del_state` = 0; - --- 为admin_user表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'admin_user', `id`, UUID() -FROM `admin_user` -WHERE - `del_state` = 0; - --- 为admin_role表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'admin_role', `id`, UUID() -FROM `admin_role` -WHERE - `del_state` = 0; - --- 为admin_menu表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'admin_menu', `id`, UUID() -FROM `admin_menu` -WHERE - `del_state` = 0; - --- 为admin_api表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'admin_api', `id`, UUID() -FROM `admin_api` -WHERE - `del_state` = 0; - --- 为admin_dict_type表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'admin_dict_type', `id`, UUID() -FROM `admin_dict_type` -WHERE - `del_state` = 0; - --- 为admin_dict_data表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'admin_dict_data', `id`, UUID() -FROM `admin_dict_data` -WHERE - `del_state` = 0; - --- 为admin_user_role表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'admin_user_role', `id`, UUID() -FROM `admin_user_role` -WHERE - `del_state` = 0; - --- 为admin_role_menu表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'admin_role_menu', `id`, UUID() -FROM `admin_role_menu` -WHERE - `del_state` = 0; - --- 为admin_role_api表生成UUID映射 -INSERT INTO - `uuid_mapping` ( - `table_name`, - `old_id`, - `new_uuid` - ) -SELECT 'admin_role_api', `id`, UUID() -FROM `admin_role_api` -WHERE - `del_state` = 0; - --- ============================================ --- 第三阶段:修改表结构(添加UUID字段,保留原ID字段) --- ============================================ - --- 注意:此阶段先添加新字段,不删除旧字段,以便回滚 - --- user表:添加UUID主键字段 -ALTER TABLE `user` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD INDEX `idx_id_uuid` (`id_uuid`); - --- agent表:添加UUID主键字段 -ALTER TABLE `agent` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `user_id_uuid` CHAR(36) NULL COMMENT '用户UUID' AFTER `user_id`, -ADD COLUMN `team_leader_id_uuid` CHAR(36) NULL COMMENT '团队首领UUID' AFTER `team_leader_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_user_id_uuid` (`user_id_uuid`), -ADD INDEX `idx_team_leader_id_uuid` (`team_leader_id_uuid`); - --- product表:添加UUID主键字段 -ALTER TABLE `product` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD INDEX `idx_id_uuid` (`id_uuid`); - --- order表:添加UUID主键字段和外键字段 -ALTER TABLE `order` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `user_id_uuid` CHAR(36) NULL COMMENT '用户UUID' AFTER `user_id`, -ADD COLUMN `product_id_uuid` CHAR(36) NULL COMMENT '产品UUID' AFTER `product_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_user_id_uuid` (`user_id_uuid`), -ADD INDEX `idx_product_id_uuid` (`product_id_uuid`); - --- query表:添加UUID主键字段和外键字段 -ALTER TABLE `query` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `order_id_uuid` CHAR(36) NULL COMMENT '订单UUID' AFTER `order_id`, -ADD COLUMN `user_id_uuid` CHAR(36) NULL COMMENT '用户UUID' AFTER `user_id`, -ADD COLUMN `product_id_uuid` CHAR(36) NULL COMMENT '产品UUID' AFTER `product_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_order_id_uuid` (`order_id_uuid`), -ADD INDEX `idx_user_id_uuid` (`user_id_uuid`), -ADD INDEX `idx_product_id_uuid` (`product_id_uuid`); - --- user_auth表:添加UUID主键字段和外键字段 -ALTER TABLE `user_auth` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `user_id_uuid` CHAR(36) NULL COMMENT '用户UUID' AFTER `user_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_user_id_uuid` (`user_id_uuid`); - --- agent_commission表:添加UUID主键字段和外键字段 -ALTER TABLE `agent_commission` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `agent_id_uuid` CHAR(36) NULL COMMENT '代理UUID' AFTER `agent_id`, -ADD COLUMN `order_id_uuid` CHAR(36) NULL COMMENT '订单UUID' AFTER `order_id`, -ADD COLUMN `product_id_uuid` CHAR(36) NULL COMMENT '产品UUID' AFTER `product_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_agent_id_uuid` (`agent_id_uuid`), -ADD INDEX `idx_order_id_uuid` (`order_id_uuid`), -ADD INDEX `idx_product_id_uuid` (`product_id_uuid`); - --- agent_invite_code表:添加UUID主键字段和外键字段 -ALTER TABLE `agent_invite_code` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `agent_id_uuid` CHAR(36) NULL COMMENT '代理UUID' AFTER `agent_id`, -ADD COLUMN `used_user_id_uuid` CHAR(36) NULL COMMENT '使用用户UUID' AFTER `used_user_id`, -ADD COLUMN `used_agent_id_uuid` CHAR(36) NULL COMMENT '使用代理UUID' AFTER `used_agent_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_agent_id_uuid` (`agent_id_uuid`), -ADD INDEX `idx_used_user_id_uuid` (`used_user_id_uuid`), -ADD INDEX `idx_used_agent_id_uuid` (`used_agent_id_uuid`); - --- agent_link表:添加UUID主键字段和外键字段 -ALTER TABLE `agent_link` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `agent_id_uuid` CHAR(36) NULL COMMENT '代理UUID' AFTER `agent_id`, -ADD COLUMN `user_id_uuid` CHAR(36) NULL COMMENT '用户UUID' AFTER `user_id`, -ADD COLUMN `product_id_uuid` CHAR(36) NULL COMMENT '产品UUID' AFTER `product_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_agent_id_uuid` (`agent_id_uuid`), -ADD INDEX `idx_user_id_uuid` (`user_id_uuid`), -ADD INDEX `idx_product_id_uuid` (`product_id_uuid`); - --- agent_order表:添加UUID主键字段和外键字段 -ALTER TABLE `agent_order` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `agent_id_uuid` CHAR(36) NULL COMMENT '代理UUID' AFTER `agent_id`, -ADD COLUMN `order_id_uuid` CHAR(36) NULL COMMENT '订单UUID' AFTER `order_id`, -ADD COLUMN `product_id_uuid` CHAR(36) NULL COMMENT '产品UUID' AFTER `product_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_agent_id_uuid` (`agent_id_uuid`), -ADD INDEX `idx_order_id_uuid` (`order_id_uuid`), -ADD INDEX `idx_product_id_uuid` (`product_id_uuid`); - --- agent_wallet表:添加UUID主键字段和外键字段 -ALTER TABLE `agent_wallet` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `agent_id_uuid` CHAR(36) NULL COMMENT '代理UUID' AFTER `agent_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_agent_id_uuid` (`agent_id_uuid`); - --- agent_withdrawal表:添加UUID主键字段和外键字段 -ALTER TABLE `agent_withdrawal` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `agent_id_uuid` CHAR(36) NULL COMMENT '代理UUID' AFTER `agent_id`, -ADD COLUMN `wallet_id_uuid` CHAR(36) NULL COMMENT '钱包UUID' AFTER `wallet_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_agent_id_uuid` (`agent_id_uuid`), -ADD INDEX `idx_wallet_id_uuid` (`wallet_id_uuid`); - --- agent_withdrawal_tax表:添加UUID主键字段和外键字段 -ALTER TABLE `agent_withdrawal_tax` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `withdrawal_id_uuid` CHAR(36) NULL COMMENT '提现UUID' AFTER `withdrawal_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_withdrawal_id_uuid` (`withdrawal_id_uuid`); - --- agent_rebate表:添加UUID主键字段和外键字段 -ALTER TABLE `agent_rebate` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `agent_id_uuid` CHAR(36) NULL COMMENT '代理UUID' AFTER `agent_id`, -ADD COLUMN `order_id_uuid` CHAR(36) NULL COMMENT '订单UUID' AFTER `order_id`, -ADD COLUMN `product_id_uuid` CHAR(36) NULL COMMENT '产品UUID' AFTER `product_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_agent_id_uuid` (`agent_id_uuid`), -ADD INDEX `idx_order_id_uuid` (`order_id_uuid`), -ADD INDEX `idx_product_id_uuid` (`product_id_uuid`); - --- agent_relation表:添加UUID主键字段和外键字段 -ALTER TABLE `agent_relation` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `agent_id_uuid` CHAR(36) NULL COMMENT '代理UUID' AFTER `agent_id`, -ADD COLUMN `parent_agent_id_uuid` CHAR(36) NULL COMMENT '上级代理UUID' AFTER `parent_agent_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_agent_id_uuid` (`agent_id_uuid`), -ADD INDEX `idx_parent_agent_id_uuid` (`parent_agent_id_uuid`); - --- agent_upgrade表:添加UUID主键字段和外键字段 -ALTER TABLE `agent_upgrade` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `agent_id_uuid` CHAR(36) NULL COMMENT '代理UUID' AFTER `agent_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_agent_id_uuid` (`agent_id_uuid`); - --- agent_real_name表:添加UUID主键字段和外键字段 -ALTER TABLE `agent_real_name` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `agent_id_uuid` CHAR(36) NULL COMMENT '代理UUID' AFTER `agent_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_agent_id_uuid` (`agent_id_uuid`); - --- agent_config表:添加UUID主键字段 -ALTER TABLE `agent_config` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD INDEX `idx_id_uuid` (`id_uuid`); - --- agent_product_config表:添加UUID主键字段和外键字段 -ALTER TABLE `agent_product_config` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `product_id_uuid` CHAR(36) NULL COMMENT '产品UUID' AFTER `product_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_product_id_uuid` (`product_id_uuid`); - --- agent_short_link表:添加UUID主键字段和外键字段 -ALTER TABLE `agent_short_link` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `invite_code_id_uuid` CHAR(36) NULL COMMENT '邀请码UUID' AFTER `invite_code_id`, -ADD COLUMN `link_id_uuid` CHAR(36) NULL COMMENT '链接UUID' AFTER `link_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_invite_code_id_uuid` (`invite_code_id_uuid`), -ADD INDEX `idx_link_id_uuid` (`link_id_uuid`); - --- agent_invite_code_usage表:添加UUID主键字段和外键字段 -ALTER TABLE `agent_invite_code_usage` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `invite_code_id_uuid` CHAR(36) NULL COMMENT '邀请码UUID' AFTER `invite_code_id`, -ADD COLUMN `user_id_uuid` CHAR(36) NULL COMMENT '用户UUID' AFTER `user_id`, -ADD COLUMN `agent_id_uuid` CHAR(36) NULL COMMENT '代理UUID' AFTER `agent_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_invite_code_id_uuid` (`invite_code_id_uuid`), -ADD INDEX `idx_user_id_uuid` (`user_id_uuid`), -ADD INDEX `idx_agent_id_uuid` (`agent_id_uuid`); - --- agent_freeze_task表:添加UUID主键字段和外键字段 -ALTER TABLE `agent_freeze_task` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `agent_id_uuid` CHAR(36) NULL COMMENT '代理UUID' AFTER `agent_id`, -ADD COLUMN `order_id_uuid` CHAR(36) NULL COMMENT '订单UUID' AFTER `order_id`, -ADD COLUMN `commission_id_uuid` CHAR(36) NULL COMMENT '佣金UUID' AFTER `commission_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_agent_id_uuid` (`agent_id_uuid`), -ADD INDEX `idx_order_id_uuid` (`order_id_uuid`), -ADD INDEX `idx_commission_id_uuid` (`commission_id_uuid`); - --- order_refund表:添加UUID主键字段和外键字段 -ALTER TABLE `order_refund` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `order_id_uuid` CHAR(36) NULL COMMENT '订单UUID' AFTER `order_id`, -ADD COLUMN `user_id_uuid` CHAR(36) NULL COMMENT '用户UUID' AFTER `user_id`, -ADD COLUMN `product_id_uuid` CHAR(36) NULL COMMENT '产品UUID' AFTER `product_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_order_id_uuid` (`order_id_uuid`), -ADD INDEX `idx_user_id_uuid` (`user_id_uuid`), -ADD INDEX `idx_product_id_uuid` (`product_id_uuid`); - --- query_cleanup_log表:添加UUID主键字段 -ALTER TABLE `query_cleanup_log` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD INDEX `idx_id_uuid` (`id_uuid`); - --- query_cleanup_detail表:添加UUID主键字段和外键字段 -ALTER TABLE `query_cleanup_detail` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `cleanup_log_id_uuid` CHAR(36) NULL COMMENT '清理日志UUID' AFTER `cleanup_log_id`, -ADD COLUMN `query_id_uuid` CHAR(36) NULL COMMENT '查询UUID' AFTER `query_id`, -ADD COLUMN `order_id_uuid` CHAR(36) NULL COMMENT '订单UUID' AFTER `order_id`, -ADD COLUMN `user_id_uuid` CHAR(36) NULL COMMENT '用户UUID' AFTER `user_id`, -ADD COLUMN `product_id_uuid` CHAR(36) NULL COMMENT '产品UUID' AFTER `product_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_cleanup_log_id_uuid` (`cleanup_log_id_uuid`), -ADD INDEX `idx_query_id_uuid` (`query_id_uuid`), -ADD INDEX `idx_order_id_uuid` (`order_id_uuid`), -ADD INDEX `idx_user_id_uuid` (`user_id_uuid`), -ADD INDEX `idx_product_id_uuid` (`product_id_uuid`); - --- query_cleanup_config表:添加UUID主键字段 -ALTER TABLE `query_cleanup_config` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD INDEX `idx_id_uuid` (`id_uuid`); - --- product_feature表:添加UUID主键字段和外键字段 -ALTER TABLE `product_feature` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `product_id_uuid` CHAR(36) NULL COMMENT '产品UUID' AFTER `product_id`, -ADD COLUMN `feature_id_uuid` CHAR(36) NULL COMMENT '功能UUID' AFTER `feature_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_product_id_uuid` (`product_id_uuid`), -ADD INDEX `idx_feature_id_uuid` (`feature_id_uuid`); - --- feature表:添加UUID主键字段 -ALTER TABLE `feature` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD INDEX `idx_id_uuid` (`id_uuid`); - --- authorization_document表:添加UUID主键字段和外键字段 -ALTER TABLE `authorization_document` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `user_id_uuid` CHAR(36) NULL COMMENT '用户UUID' AFTER `user_id`, -ADD COLUMN `order_id_uuid` CHAR(36) NULL COMMENT '订单UUID' AFTER `order_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_user_id_uuid` (`user_id_uuid`), -ADD INDEX `idx_order_id_uuid` (`order_id_uuid`); - --- global_notifications表:添加UUID主键字段 -ALTER TABLE `global_notifications` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD INDEX `idx_id_uuid` (`id_uuid`); - --- admin_user表:添加UUID主键字段 -ALTER TABLE `admin_user` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD INDEX `idx_id_uuid` (`id_uuid`); - --- admin_role表:添加UUID主键字段 -ALTER TABLE `admin_role` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD INDEX `idx_id_uuid` (`id_uuid`); - --- admin_menu表:添加UUID主键字段和外键字段 -ALTER TABLE `admin_menu` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `parent_id_uuid` CHAR(36) NULL COMMENT '父菜单UUID' AFTER `parent_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_parent_id_uuid` (`parent_id_uuid`); - --- admin_api表:添加UUID主键字段 -ALTER TABLE `admin_api` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD INDEX `idx_id_uuid` (`id_uuid`); - --- admin_dict_type表:添加UUID主键字段 -ALTER TABLE `admin_dict_type` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD INDEX `idx_id_uuid` (`id_uuid`); - --- admin_dict_data表:添加UUID主键字段和外键字段 -ALTER TABLE `admin_dict_data` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `dict_type_id_uuid` CHAR(36) NULL COMMENT '字典类型UUID' AFTER `dict_type_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_dict_type_id_uuid` (`dict_type_id_uuid`); - --- admin_user_role表:添加UUID主键字段和外键字段 -ALTER TABLE `admin_user_role` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `user_id_uuid` CHAR(36) NULL COMMENT '用户UUID' AFTER `user_id`, -ADD COLUMN `role_id_uuid` CHAR(36) NULL COMMENT '角色UUID' AFTER `role_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_user_id_uuid` (`user_id_uuid`), -ADD INDEX `idx_role_id_uuid` (`role_id_uuid`); - --- admin_role_menu表:添加UUID主键字段和外键字段 -ALTER TABLE `admin_role_menu` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `role_id_uuid` CHAR(36) NULL COMMENT '角色UUID' AFTER `role_id`, -ADD COLUMN `menu_id_uuid` CHAR(36) NULL COMMENT '菜单UUID' AFTER `menu_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_role_id_uuid` (`role_id_uuid`), -ADD INDEX `idx_menu_id_uuid` (`menu_id_uuid`); - --- admin_role_api表:添加UUID主键字段和外键字段 -ALTER TABLE `admin_role_api` -ADD COLUMN `id_uuid` CHAR(36) NULL COMMENT 'UUID主键' AFTER `id`, -ADD COLUMN `role_id_uuid` CHAR(36) NULL COMMENT '角色UUID' AFTER `role_id`, -ADD COLUMN `api_id_uuid` CHAR(36) NULL COMMENT 'API UUID' AFTER `api_id`, -ADD INDEX `idx_id_uuid` (`id_uuid`), -ADD INDEX `idx_role_id_uuid` (`role_id_uuid`), -ADD INDEX `idx_api_id_uuid` (`api_id_uuid`); - --- ============================================ --- 第四阶段:填充UUID字段数据(根据映射表) --- ============================================ - --- user表:填充UUID -UPDATE `user` u -INNER JOIN `uuid_mapping` m ON m.table_name = 'user' -AND m.old_id = u.id -SET - u.id_uuid = m.new_uuid -WHERE - u.del_state = 0; - --- agent表:填充UUID -UPDATE `agent` a -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent' -AND m.old_id = a.id -SET - a.id_uuid = m.new_uuid -WHERE - a.del_state = 0; - -UPDATE `agent` a -INNER JOIN `uuid_mapping` m ON m.table_name = 'user' -AND m.old_id = a.user_id -SET - a.user_id_uuid = m.new_uuid -WHERE - a.del_state = 0 - AND a.user_id IS NOT NULL; - -UPDATE `agent` a -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent' -AND m.old_id = a.team_leader_id -SET - a.team_leader_id_uuid = m.new_uuid -WHERE - a.del_state = 0 - AND a.team_leader_id IS NOT NULL; - --- product表:填充UUID -UPDATE `product` p -INNER JOIN `uuid_mapping` m ON m.table_name = 'product' -AND m.old_id = p.id -SET - p.id_uuid = m.new_uuid -WHERE - p.del_state = 0; - --- order表:填充UUID -UPDATE `order` o -INNER JOIN `uuid_mapping` m ON m.table_name = 'order' -AND m.old_id = o.id -SET - o.id_uuid = m.new_uuid -WHERE - o.del_state = 0; - -UPDATE `order` o -INNER JOIN `uuid_mapping` m ON m.table_name = 'user' -AND m.old_id = o.user_id -SET - o.user_id_uuid = m.new_uuid -WHERE - o.del_state = 0 - AND o.user_id IS NOT NULL; - -UPDATE `order` o -INNER JOIN `uuid_mapping` m ON m.table_name = 'product' -AND m.old_id = o.product_id -SET - o.product_id_uuid = m.new_uuid -WHERE - o.del_state = 0 - AND o.product_id IS NOT NULL; - --- query表:填充UUID -UPDATE `query` q -INNER JOIN `uuid_mapping` m ON m.table_name = 'query' -AND m.old_id = q.id -SET - q.id_uuid = m.new_uuid -WHERE - q.del_state = 0; - -UPDATE `query` q -INNER JOIN `uuid_mapping` m ON m.table_name = 'order' -AND m.old_id = q.order_id -SET - q.order_id_uuid = m.new_uuid -WHERE - q.del_state = 0 - AND q.order_id IS NOT NULL; - -UPDATE `query` q -INNER JOIN `uuid_mapping` m ON m.table_name = 'user' -AND m.old_id = q.user_id -SET - q.user_id_uuid = m.new_uuid -WHERE - q.del_state = 0 - AND q.user_id IS NOT NULL; - -UPDATE `query` q -INNER JOIN `uuid_mapping` m ON m.table_name = 'product' -AND m.old_id = q.product_id -SET - q.product_id_uuid = m.new_uuid -WHERE - q.del_state = 0 - AND q.product_id IS NOT NULL; - --- user_auth表:填充UUID -UPDATE `user_auth` ua -INNER JOIN `uuid_mapping` m ON m.table_name = 'user_auth' -AND m.old_id = ua.id -SET - ua.id_uuid = m.new_uuid -WHERE - ua.del_state = 0; - -UPDATE `user_auth` ua -INNER JOIN `uuid_mapping` m ON m.table_name = 'user' -AND m.old_id = ua.user_id -SET - ua.user_id_uuid = m.new_uuid -WHERE - ua.del_state = 0 - AND ua.user_id IS NOT NULL; - --- agent_commission表:填充UUID -UPDATE `agent_commission` ac -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_commission' -AND m.old_id = ac.id -SET - ac.id_uuid = m.new_uuid -WHERE - ac.del_state = 0; - -UPDATE `agent_commission` ac -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent' -AND m.old_id = ac.agent_id -SET - ac.agent_id_uuid = m.new_uuid -WHERE - ac.del_state = 0 - AND ac.agent_id IS NOT NULL; - -UPDATE `agent_commission` ac -INNER JOIN `uuid_mapping` m ON m.table_name = 'order' -AND m.old_id = ac.order_id -SET - ac.order_id_uuid = m.new_uuid -WHERE - ac.del_state = 0 - AND ac.order_id IS NOT NULL; - -UPDATE `agent_commission` ac -INNER JOIN `uuid_mapping` m ON m.table_name = 'product' -AND m.old_id = ac.product_id -SET - ac.product_id_uuid = m.new_uuid -WHERE - ac.del_state = 0 - AND ac.product_id IS NOT NULL; - --- agent_invite_code表:填充UUID -UPDATE `agent_invite_code` aic -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_invite_code' -AND m.old_id = aic.id -SET - aic.id_uuid = m.new_uuid -WHERE - aic.del_state = 0; - -UPDATE `agent_invite_code` aic -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent' -AND m.old_id = aic.agent_id -SET - aic.agent_id_uuid = m.new_uuid -WHERE - aic.del_state = 0 - AND aic.agent_id IS NOT NULL; - -UPDATE `agent_invite_code` aic -INNER JOIN `uuid_mapping` m ON m.table_name = 'user' -AND m.old_id = aic.used_user_id -SET - aic.used_user_id_uuid = m.new_uuid -WHERE - aic.del_state = 0 - AND aic.used_user_id IS NOT NULL; - -UPDATE `agent_invite_code` aic -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent' -AND m.old_id = aic.used_agent_id -SET - aic.used_agent_id_uuid = m.new_uuid -WHERE - aic.del_state = 0 - AND aic.used_agent_id IS NOT NULL; - --- agent_link表:填充UUID -UPDATE `agent_link` al -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_link' -AND m.old_id = al.id -SET - al.id_uuid = m.new_uuid -WHERE - al.del_state = 0; - -UPDATE `agent_link` al -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent' -AND m.old_id = al.agent_id -SET - al.agent_id_uuid = m.new_uuid -WHERE - al.del_state = 0 - AND al.agent_id IS NOT NULL; - -UPDATE `agent_link` al -INNER JOIN `uuid_mapping` m ON m.table_name = 'user' -AND m.old_id = al.user_id -SET - al.user_id_uuid = m.new_uuid -WHERE - al.del_state = 0 - AND al.user_id IS NOT NULL; - -UPDATE `agent_link` al -INNER JOIN `uuid_mapping` m ON m.table_name = 'product' -AND m.old_id = al.product_id -SET - al.product_id_uuid = m.new_uuid -WHERE - al.del_state = 0 - AND al.product_id IS NOT NULL; - --- agent_order表:填充UUID -UPDATE `agent_order` ao -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_order' -AND m.old_id = ao.id -SET - ao.id_uuid = m.new_uuid -WHERE - ao.del_state = 0; - -UPDATE `agent_order` ao -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent' -AND m.old_id = ao.agent_id -SET - ao.agent_id_uuid = m.new_uuid -WHERE - ao.del_state = 0 - AND ao.agent_id IS NOT NULL; - -UPDATE `agent_order` ao -INNER JOIN `uuid_mapping` m ON m.table_name = 'order' -AND m.old_id = ao.order_id -SET - ao.order_id_uuid = m.new_uuid -WHERE - ao.del_state = 0 - AND ao.order_id IS NOT NULL; - -UPDATE `agent_order` ao -INNER JOIN `uuid_mapping` m ON m.table_name = 'product' -AND m.old_id = ao.product_id -SET - ao.product_id_uuid = m.new_uuid -WHERE - ao.del_state = 0 - AND ao.product_id IS NOT NULL; - --- agent_wallet表:填充UUID -UPDATE `agent_wallet` aw -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_wallet' -AND m.old_id = aw.id -SET - aw.id_uuid = m.new_uuid -WHERE - aw.del_state = 0; - -UPDATE `agent_wallet` aw -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent' -AND m.old_id = aw.agent_id -SET - aw.agent_id_uuid = m.new_uuid -WHERE - aw.del_state = 0 - AND aw.agent_id IS NOT NULL; - --- agent_withdrawal表:填充UUID -UPDATE `agent_withdrawal` aw -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_withdrawal' -AND m.old_id = aw.id -SET - aw.id_uuid = m.new_uuid -WHERE - aw.del_state = 0; - -UPDATE `agent_withdrawal` aw -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent' -AND m.old_id = aw.agent_id -SET - aw.agent_id_uuid = m.new_uuid -WHERE - aw.del_state = 0 - AND aw.agent_id IS NOT NULL; - -UPDATE `agent_withdrawal` aw -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_wallet' -AND m.old_id = aw.wallet_id -SET - aw.wallet_id_uuid = m.new_uuid -WHERE - aw.del_state = 0 - AND aw.wallet_id IS NOT NULL; - --- agent_withdrawal_tax表:填充UUID -UPDATE `agent_withdrawal_tax` awt -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_withdrawal_tax' -AND m.old_id = awt.id -SET - awt.id_uuid = m.new_uuid -WHERE - awt.del_state = 0; - -UPDATE `agent_withdrawal_tax` awt -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_withdrawal' -AND m.old_id = awt.withdrawal_id -SET - awt.withdrawal_id_uuid = m.new_uuid -WHERE - awt.del_state = 0 - AND awt.withdrawal_id IS NOT NULL; - --- agent_rebate表:填充UUID -UPDATE `agent_rebate` ar -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_rebate' -AND m.old_id = ar.id -SET - ar.id_uuid = m.new_uuid -WHERE - ar.del_state = 0; - -UPDATE `agent_rebate` ar -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent' -AND m.old_id = ar.agent_id -SET - ar.agent_id_uuid = m.new_uuid -WHERE - ar.del_state = 0 - AND ar.agent_id IS NOT NULL; - -UPDATE `agent_rebate` ar -INNER JOIN `uuid_mapping` m ON m.table_name = 'order' -AND m.old_id = ar.order_id -SET - ar.order_id_uuid = m.new_uuid -WHERE - ar.del_state = 0 - AND ar.order_id IS NOT NULL; - -UPDATE `agent_rebate` ar -INNER JOIN `uuid_mapping` m ON m.table_name = 'product' -AND m.old_id = ar.product_id -SET - ar.product_id_uuid = m.new_uuid -WHERE - ar.del_state = 0 - AND ar.product_id IS NOT NULL; - --- agent_relation表:填充UUID -UPDATE `agent_relation` ar -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_relation' -AND m.old_id = ar.id -SET - ar.id_uuid = m.new_uuid -WHERE - ar.del_state = 0; - -UPDATE `agent_relation` ar -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent' -AND m.old_id = ar.agent_id -SET - ar.agent_id_uuid = m.new_uuid -WHERE - ar.del_state = 0 - AND ar.agent_id IS NOT NULL; - -UPDATE `agent_relation` ar -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent' -AND m.old_id = ar.parent_agent_id -SET - ar.parent_agent_id_uuid = m.new_uuid -WHERE - ar.del_state = 0 - AND ar.parent_agent_id IS NOT NULL; - --- agent_upgrade表:填充UUID -UPDATE `agent_upgrade` au -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_upgrade' -AND m.old_id = au.id -SET - au.id_uuid = m.new_uuid -WHERE - au.del_state = 0; - -UPDATE `agent_upgrade` au -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent' -AND m.old_id = au.agent_id -SET - au.agent_id_uuid = m.new_uuid -WHERE - au.del_state = 0 - AND au.agent_id IS NOT NULL; - --- agent_real_name表:填充UUID -UPDATE `agent_real_name` arn -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_real_name' -AND m.old_id = arn.id -SET - arn.id_uuid = m.new_uuid -WHERE - arn.del_state = 0; - -UPDATE `agent_real_name` arn -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent' -AND m.old_id = arn.agent_id -SET - arn.agent_id_uuid = m.new_uuid -WHERE - arn.del_state = 0 - AND arn.agent_id IS NOT NULL; - --- agent_config表:填充UUID -UPDATE `agent_config` ac -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_config' -AND m.old_id = ac.id -SET - ac.id_uuid = m.new_uuid -WHERE - ac.del_state = 0; - --- agent_product_config表:填充UUID -UPDATE `agent_product_config` apc -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_product_config' -AND m.old_id = apc.id -SET - apc.id_uuid = m.new_uuid -WHERE - apc.del_state = 0; - -UPDATE `agent_product_config` apc -INNER JOIN `uuid_mapping` m ON m.table_name = 'product' -AND m.old_id = apc.product_id -SET - apc.product_id_uuid = m.new_uuid -WHERE - apc.del_state = 0 - AND apc.product_id IS NOT NULL; - --- agent_short_link表:填充UUID -UPDATE `agent_short_link` asl -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_short_link' -AND m.old_id = asl.id -SET - asl.id_uuid = m.new_uuid -WHERE - asl.del_state = 0; - -UPDATE `agent_short_link` asl -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_invite_code' -AND m.old_id = asl.invite_code_id -SET - asl.invite_code_id_uuid = m.new_uuid -WHERE - asl.del_state = 0 - AND asl.invite_code_id IS NOT NULL; - -UPDATE `agent_short_link` asl -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_link' -AND m.old_id = asl.link_id -SET - asl.link_id_uuid = m.new_uuid -WHERE - asl.del_state = 0 - AND asl.link_id IS NOT NULL; - --- agent_invite_code_usage表:填充UUID -UPDATE `agent_invite_code_usage` aicu -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_invite_code_usage' -AND m.old_id = aicu.id -SET - aicu.id_uuid = m.new_uuid -WHERE - aicu.del_state = 0; - -UPDATE `agent_invite_code_usage` aicu -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_invite_code' -AND m.old_id = aicu.invite_code_id -SET - aicu.invite_code_id_uuid = m.new_uuid -WHERE - aicu.del_state = 0 - AND aicu.invite_code_id IS NOT NULL; - -UPDATE `agent_invite_code_usage` aicu -INNER JOIN `uuid_mapping` m ON m.table_name = 'user' -AND m.old_id = aicu.user_id -SET - aicu.user_id_uuid = m.new_uuid -WHERE - aicu.del_state = 0 - AND aicu.user_id IS NOT NULL; - -UPDATE `agent_invite_code_usage` aicu -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent' -AND m.old_id = aicu.agent_id -SET - aicu.agent_id_uuid = m.new_uuid -WHERE - aicu.del_state = 0 - AND aicu.agent_id IS NOT NULL; - --- agent_freeze_task表:填充UUID -UPDATE `agent_freeze_task` aft -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_freeze_task' -AND m.old_id = aft.id -SET - aft.id_uuid = m.new_uuid -WHERE - aft.del_state = 0; - -UPDATE `agent_freeze_task` aft -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent' -AND m.old_id = aft.agent_id -SET - aft.agent_id_uuid = m.new_uuid -WHERE - aft.del_state = 0 - AND aft.agent_id IS NOT NULL; - -UPDATE `agent_freeze_task` aft -INNER JOIN `uuid_mapping` m ON m.table_name = 'order' -AND m.old_id = aft.order_id -SET - aft.order_id_uuid = m.new_uuid -WHERE - aft.del_state = 0 - AND aft.order_id IS NOT NULL; - -UPDATE `agent_freeze_task` aft -INNER JOIN `uuid_mapping` m ON m.table_name = 'agent_commission' -AND m.old_id = aft.commission_id -SET - aft.commission_id_uuid = m.new_uuid -WHERE - aft.del_state = 0 - AND aft.commission_id IS NOT NULL; - --- order_refund表:填充UUID -UPDATE `order_refund` orf -INNER JOIN `uuid_mapping` m ON m.table_name = 'order_refund' -AND m.old_id = orf.id -SET - orf.id_uuid = m.new_uuid -WHERE - orf.del_state = 0; - -UPDATE `order_refund` orf -INNER JOIN `uuid_mapping` m ON m.table_name = 'order' -AND m.old_id = orf.order_id -SET - orf.order_id_uuid = m.new_uuid -WHERE - orf.del_state = 0 - AND orf.order_id IS NOT NULL; - -UPDATE `order_refund` orf -INNER JOIN `uuid_mapping` m ON m.table_name = 'user' -AND m.old_id = orf.user_id -SET - orf.user_id_uuid = m.new_uuid -WHERE - orf.del_state = 0 - AND orf.user_id IS NOT NULL; - -UPDATE `order_refund` orf -INNER JOIN `uuid_mapping` m ON m.table_name = 'product' -AND m.old_id = orf.product_id -SET - orf.product_id_uuid = m.new_uuid -WHERE - orf.del_state = 0 - AND orf.product_id IS NOT NULL; - --- query_cleanup_log表:填充UUID -UPDATE `query_cleanup_log` qcl -INNER JOIN `uuid_mapping` m ON m.table_name = 'query_cleanup_log' -AND m.old_id = qcl.id -SET - qcl.id_uuid = m.new_uuid -WHERE - qcl.del_state = 0; - --- query_cleanup_detail表:填充UUID -UPDATE `query_cleanup_detail` qcd -INNER JOIN `uuid_mapping` m ON m.table_name = 'query_cleanup_detail' -AND m.old_id = qcd.id -SET - qcd.id_uuid = m.new_uuid -WHERE - qcd.del_state = 0; - -UPDATE `query_cleanup_detail` qcd -INNER JOIN `uuid_mapping` m ON m.table_name = 'query_cleanup_log' -AND m.old_id = qcd.cleanup_log_id -SET - qcd.cleanup_log_id_uuid = m.new_uuid -WHERE - qcd.del_state = 0 - AND qcd.cleanup_log_id IS NOT NULL; - -UPDATE `query_cleanup_detail` qcd -INNER JOIN `uuid_mapping` m ON m.table_name = 'query' -AND m.old_id = qcd.query_id -SET - qcd.query_id_uuid = m.new_uuid -WHERE - qcd.del_state = 0 - AND qcd.query_id IS NOT NULL; - -UPDATE `query_cleanup_detail` qcd -INNER JOIN `uuid_mapping` m ON m.table_name = 'order' -AND m.old_id = qcd.order_id -SET - qcd.order_id_uuid = m.new_uuid -WHERE - qcd.del_state = 0 - AND qcd.order_id IS NOT NULL; - -UPDATE `query_cleanup_detail` qcd -INNER JOIN `uuid_mapping` m ON m.table_name = 'user' -AND m.old_id = qcd.user_id -SET - qcd.user_id_uuid = m.new_uuid -WHERE - qcd.del_state = 0 - AND qcd.user_id IS NOT NULL; - -UPDATE `query_cleanup_detail` qcd -INNER JOIN `uuid_mapping` m ON m.table_name = 'product' -AND m.old_id = qcd.product_id -SET - qcd.product_id_uuid = m.new_uuid -WHERE - qcd.del_state = 0 - AND qcd.product_id IS NOT NULL; - --- query_cleanup_config表:填充UUID -UPDATE `query_cleanup_config` qcc -INNER JOIN `uuid_mapping` m ON m.table_name = 'query_cleanup_config' -AND m.old_id = qcc.id -SET - qcc.id_uuid = m.new_uuid -WHERE - qcc.del_state = 0; - --- product_feature表:填充UUID -UPDATE `product_feature` pf -INNER JOIN `uuid_mapping` m ON m.table_name = 'product_feature' -AND m.old_id = pf.id -SET - pf.id_uuid = m.new_uuid -WHERE - pf.del_state = 0; - -UPDATE `product_feature` pf -INNER JOIN `uuid_mapping` m ON m.table_name = 'product' -AND m.old_id = pf.product_id -SET - pf.product_id_uuid = m.new_uuid -WHERE - pf.del_state = 0 - AND pf.product_id IS NOT NULL; - -UPDATE `product_feature` pf -INNER JOIN `uuid_mapping` m ON m.table_name = 'feature' -AND m.old_id = pf.feature_id -SET - pf.feature_id_uuid = m.new_uuid -WHERE - pf.del_state = 0 - AND pf.feature_id IS NOT NULL; - --- feature表:填充UUID -UPDATE `feature` f -INNER JOIN `uuid_mapping` m ON m.table_name = 'feature' -AND m.old_id = f.id -SET - f.id_uuid = m.new_uuid -WHERE - f.del_state = 0; - --- authorization_document表:填充UUID -UPDATE `authorization_document` ad -INNER JOIN `uuid_mapping` m ON m.table_name = 'authorization_document' -AND m.old_id = ad.id -SET - ad.id_uuid = m.new_uuid -WHERE - ad.del_state = 0; - -UPDATE `authorization_document` ad -INNER JOIN `uuid_mapping` m ON m.table_name = 'user' -AND m.old_id = ad.user_id -SET - ad.user_id_uuid = m.new_uuid -WHERE - ad.del_state = 0 - AND ad.user_id IS NOT NULL; - -UPDATE `authorization_document` ad -INNER JOIN `uuid_mapping` m ON m.table_name = 'order' -AND m.old_id = ad.order_id -SET - ad.order_id_uuid = m.new_uuid -WHERE - ad.del_state = 0 - AND ad.order_id IS NOT NULL; - --- global_notifications表:填充UUID -UPDATE `global_notifications` gn -INNER JOIN `uuid_mapping` m ON m.table_name = 'global_notifications' -AND m.old_id = gn.id -SET - gn.id_uuid = m.new_uuid -WHERE - gn.del_state = 0; - --- admin_user表:填充UUID -UPDATE `admin_user` au -INNER JOIN `uuid_mapping` m ON m.table_name = 'admin_user' -AND m.old_id = au.id -SET - au.id_uuid = m.new_uuid -WHERE - au.del_state = 0; - --- admin_role表:填充UUID -UPDATE `admin_role` ar -INNER JOIN `uuid_mapping` m ON m.table_name = 'admin_role' -AND m.old_id = ar.id -SET - ar.id_uuid = m.new_uuid -WHERE - ar.del_state = 0; - --- admin_menu表:填充UUID -UPDATE `admin_menu` am -INNER JOIN `uuid_mapping` m ON m.table_name = 'admin_menu' -AND m.old_id = am.id -SET - am.id_uuid = m.new_uuid -WHERE - am.del_state = 0; - -UPDATE `admin_menu` am -INNER JOIN `uuid_mapping` m ON m.table_name = 'admin_menu' -AND m.old_id = am.parent_id -SET - am.parent_id_uuid = m.new_uuid -WHERE - am.del_state = 0 - AND am.parent_id IS NOT NULL; - --- admin_api表:填充UUID -UPDATE `admin_api` aa -INNER JOIN `uuid_mapping` m ON m.table_name = 'admin_api' -AND m.old_id = aa.id -SET - aa.id_uuid = m.new_uuid -WHERE - aa.del_state = 0; - --- admin_dict_type表:填充UUID -UPDATE `admin_dict_type` adt -INNER JOIN `uuid_mapping` m ON m.table_name = 'admin_dict_type' -AND m.old_id = adt.id -SET - adt.id_uuid = m.new_uuid -WHERE - adt.del_state = 0; - --- admin_dict_data表:填充UUID -UPDATE `admin_dict_data` add -INNER JOIN `uuid_mapping` m ON m.table_name = 'admin_dict_data' AND m.old_id = add.id -SET add.id_uuid = m.new_uuid -WHERE add.del_state = 0; - -UPDATE `admin_dict_data` add -INNER JOIN `uuid_mapping` m ON m.table_name = 'admin_dict_type' AND m.old_id = add.dict_type_id -SET add.dict_type_id_uuid = m.new_uuid -WHERE add.del_state = 0 AND add.dict_type_id IS NOT NULL; - --- admin_user_role表:填充UUID -UPDATE `admin_user_role` aur -INNER JOIN `uuid_mapping` m ON m.table_name = 'admin_user_role' -AND m.old_id = aur.id -SET - aur.id_uuid = m.new_uuid -WHERE - aur.del_state = 0; - -UPDATE `admin_user_role` aur -INNER JOIN `uuid_mapping` m ON m.table_name = 'admin_user' -AND m.old_id = aur.user_id -SET - aur.user_id_uuid = m.new_uuid -WHERE - aur.del_state = 0 - AND aur.user_id IS NOT NULL; - -UPDATE `admin_user_role` aur -INNER JOIN `uuid_mapping` m ON m.table_name = 'admin_role' -AND m.old_id = aur.role_id -SET - aur.role_id_uuid = m.new_uuid -WHERE - aur.del_state = 0 - AND aur.role_id IS NOT NULL; - --- admin_role_menu表:填充UUID -UPDATE `admin_role_menu` arm -INNER JOIN `uuid_mapping` m ON m.table_name = 'admin_role_menu' -AND m.old_id = arm.id -SET - arm.id_uuid = m.new_uuid -WHERE - arm.del_state = 0; - -UPDATE `admin_role_menu` arm -INNER JOIN `uuid_mapping` m ON m.table_name = 'admin_role' -AND m.old_id = arm.role_id -SET - arm.role_id_uuid = m.new_uuid -WHERE - arm.del_state = 0 - AND arm.role_id IS NOT NULL; - -UPDATE `admin_role_menu` arm -INNER JOIN `uuid_mapping` m ON m.table_name = 'admin_menu' -AND m.old_id = arm.menu_id -SET - arm.menu_id_uuid = m.new_uuid -WHERE - arm.del_state = 0 - AND arm.menu_id IS NOT NULL; - --- admin_role_api表:填充UUID -UPDATE `admin_role_api` ara -INNER JOIN `uuid_mapping` m ON m.table_name = 'admin_role_api' -AND m.old_id = ara.id -SET - ara.id_uuid = m.new_uuid -WHERE - ara.del_state = 0; - -UPDATE `admin_role_api` ara -INNER JOIN `uuid_mapping` m ON m.table_name = 'admin_role' -AND m.old_id = ara.role_id -SET - ara.role_id_uuid = m.new_uuid -WHERE - ara.del_state = 0 - AND ara.role_id IS NOT NULL; - -UPDATE `admin_role_api` ara -INNER JOIN `uuid_mapping` m ON m.table_name = 'admin_api' -AND m.old_id = ara.api_id -SET - ara.api_id_uuid = m.new_uuid -WHERE - ara.del_state = 0 - AND ara.api_id IS NOT NULL; - --- ============================================ --- 第五阶段:验证数据完整性 --- ============================================ - --- 检查是否有NULL的UUID字段(不应该有) -SELECT 'user' as table_name, COUNT(*) as null_count -FROM `user` -WHERE - `id_uuid` IS NULL - AND `del_state` = 0 -UNION ALL -SELECT 'agent', COUNT(*) -FROM `agent` -WHERE - `id_uuid` IS NULL - AND `del_state` = 0 -UNION ALL -SELECT 'order', COUNT(*) -FROM `order` -WHERE - `id_uuid` IS NULL - AND `del_state` = 0 -UNION ALL -SELECT 'query', COUNT(*) -FROM `query` -WHERE - `id_uuid` IS NULL - AND `del_state` = 0; - --- ============================================ --- 第六阶段:切换主键(需要停止服务) --- ============================================ - --- 注意:此阶段需要停止服务,因为会修改主键和索引 --- 建议在维护窗口期执行 - --- 删除旧主键,将UUID字段设为主键 --- 注意:需要先删除所有外键约束(如果有的话) - --- user表:切换主键 -ALTER TABLE `user` -DROP PRIMARY KEY, -MODIFY COLUMN `id` BIGINT NULL COMMENT '旧ID(保留用于回滚)', -MODIFY COLUMN `id_uuid` CHAR(36) NOT NULL COMMENT 'UUID主键', -ADD PRIMARY KEY (`id_uuid`); - --- agent表:切换主键 -ALTER TABLE `agent` -DROP PRIMARY KEY, -MODIFY COLUMN `id` BIGINT NULL COMMENT '旧ID(保留用于回滚)', -MODIFY COLUMN `id_uuid` CHAR(36) NOT NULL COMMENT 'UUID主键', -ADD PRIMARY KEY (`id_uuid`); - --- product表:切换主键 -ALTER TABLE `product` -DROP PRIMARY KEY, -MODIFY COLUMN `id` BIGINT NULL COMMENT '旧ID(保留用于回滚)', -MODIFY COLUMN `id_uuid` CHAR(36) NOT NULL COMMENT 'UUID主键', -ADD PRIMARY KEY (`id_uuid`); - --- order表:切换主键 -ALTER TABLE `order` -DROP PRIMARY KEY, -MODIFY COLUMN `id` BIGINT NULL COMMENT '旧ID(保留用于回滚)', -MODIFY COLUMN `id_uuid` CHAR(36) NOT NULL COMMENT 'UUID主键', -ADD PRIMARY KEY (`id_uuid`); - --- query表:切换主键 -ALTER TABLE `query` -DROP PRIMARY KEY, -MODIFY COLUMN `id` BIGINT NULL COMMENT '旧ID(保留用于回滚)', -MODIFY COLUMN `id_uuid` CHAR(36) NOT NULL COMMENT 'UUID主键', -ADD PRIMARY KEY (`id_uuid`); - --- user_auth表:切换主键 -ALTER TABLE `user_auth` -DROP PRIMARY KEY, -MODIFY COLUMN `id` BIGINT NULL COMMENT '旧ID(保留用于回滚)', -MODIFY COLUMN `id_uuid` CHAR(36) NOT NULL COMMENT 'UUID主键', -ADD PRIMARY KEY (`id_uuid`); - --- 其他表类似处理... --- (为节省篇幅,这里省略其他表的切换,实际执行时需要为所有表执行类似操作) - --- ============================================ --- 第七阶段:重命名字段(将_uuid后缀去掉) --- ============================================ - --- user表:重命名字段 -ALTER TABLE `user` -CHANGE COLUMN `id_uuid` `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -DROP COLUMN `id`; --- 删除旧ID字段(确认无误后执行) - --- 注意:其他表也需要类似处理,但需要先确保所有代码都已更新为使用UUID - --- ============================================ --- 第八阶段:更新唯一索引和约束 --- ============================================ - --- user表:更新mobile唯一索引(如果存在) --- ALTER TABLE `user` ADD UNIQUE INDEX `uk_mobile` (`mobile`); - --- user_auth表:更新(auth_type, auth_key)唯一索引 -ALTER TABLE `user_auth` -ADD UNIQUE INDEX `uk_auth_type_key` (`auth_type`, `auth_key`); - --- agent表:更新user_id唯一索引 -ALTER TABLE `agent` ADD UNIQUE INDEX `uk_user_id` (`user_id_uuid`); - --- ============================================ --- 第九阶段:清理临时表 --- ============================================ - --- 确认所有数据迁移无误后,删除映射表 --- DROP TABLE IF EXISTS `uuid_mapping`; - --- ============================================ --- 注意事项 --- ============================================ --- 1. 此脚本需要分阶段执行,每阶段执行后需要验证数据完整性 --- 2. 第六阶段(切换主键)需要停止服务 --- 3. 执行前务必备份数据库 --- 4. 建议先在测试环境完整执行一遍 --- 5. 代码层面需要同步修改: --- - 所有Model的ID字段类型从int64改为string --- - 所有插入操作需要生成UUID(使用uuid.NewString()) --- - 所有查询操作需要使用UUID --- 6. 删除旧ID字段前,确保所有代码都已更新完成 \ No newline at end of file diff --git a/deploy/sql/uuid_migration_simple.sql b/deploy/sql/uuid_migration_simple.sql deleted file mode 100644 index 70e1b74..0000000 --- a/deploy/sql/uuid_migration_simple.sql +++ /dev/null @@ -1,446 +0,0 @@ --- ============================================ --- UUID迁移脚本(简化版 - 开发环境) --- 将系统中所有bigint类型的ID字段改为CHAR(36)类型的UUID --- 注意:此脚本直接修改表结构,不保留旧数据,适用于开发环境 --- ============================================ - --- 注意:user表和product表已经是CHAR(36)类型,跳过修改 - --- ============================================ --- 第一部分:修改核心业务表 --- ============================================ - --- user表:已经是CHAR(36),跳过 --- product表:已经是CHAR(36),跳过 - --- order表:修改主键和外键字段 -ALTER TABLE `order` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `user_id` CHAR(36) NOT NULL COMMENT '用户UUID', -MODIFY COLUMN `product_id` CHAR(36) NOT NULL COMMENT '产品UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_user_id` (`user_id`), -ADD INDEX `idx_product_id` (`product_id`); - --- query表:修改主键和外键字段 -ALTER TABLE `query` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `order_id` CHAR(36) NOT NULL COMMENT '订单UUID', -MODIFY COLUMN `user_id` CHAR(36) NOT NULL COMMENT '用户UUID', -MODIFY COLUMN `product_id` CHAR(36) NOT NULL COMMENT '产品UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_order_id` (`order_id`), -ADD INDEX `idx_user_id` (`user_id`), -ADD INDEX `idx_product_id` (`product_id`); - --- user_auth表:修改主键和外键字段(注意:user_id需要关联到user表的UUID) -ALTER TABLE `user_auth` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `user_id` CHAR(36) NOT NULL COMMENT '用户UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_user_id` (`user_id`), -ADD UNIQUE INDEX `uk_auth_type_key` (`auth_type`, `auth_key`) COMMENT '确保同一个认证方式只能绑定一个用户'; - --- agent表:修改主键和外键字段 -ALTER TABLE `agent` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `user_id` CHAR(36) NOT NULL COMMENT '用户UUID', -MODIFY COLUMN `team_leader_id` CHAR(36) NULL COMMENT '团队首领UUID', -MODIFY COLUMN `invite_code_id` CHAR(36) NULL COMMENT '邀请码UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD UNIQUE INDEX `uk_user_id` (`user_id`), -ADD INDEX `idx_team_leader_id` (`team_leader_id`), -ADD INDEX `idx_invite_code_id` (`invite_code_id`); - --- ============================================ --- 第二部分:修改代理相关表 --- ============================================ - --- agent_commission表 -ALTER TABLE `agent_commission` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `agent_id` CHAR(36) NOT NULL COMMENT '代理UUID', -MODIFY COLUMN `order_id` CHAR(36) NOT NULL COMMENT '订单UUID', -MODIFY COLUMN `product_id` CHAR(36) NOT NULL COMMENT '产品UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_agent_id` (`agent_id`), -ADD INDEX `idx_order_id` (`order_id`), -ADD INDEX `idx_product_id` (`product_id`); - --- agent_invite_code表 -ALTER TABLE `agent_invite_code` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `agent_id` CHAR(36) NULL COMMENT '代理UUID', -MODIFY COLUMN `used_user_id` CHAR(36) NULL COMMENT '使用用户UUID', -MODIFY COLUMN `used_agent_id` CHAR(36) NULL COMMENT '使用代理UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_agent_id` (`agent_id`), -ADD INDEX `idx_used_user_id` (`used_user_id`), -ADD INDEX `idx_used_agent_id` (`used_agent_id`); - --- agent_link表 -ALTER TABLE `agent_link` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `agent_id` CHAR(36) NOT NULL COMMENT '代理UUID', -MODIFY COLUMN `user_id` CHAR(36) NOT NULL COMMENT '用户UUID', -MODIFY COLUMN `product_id` CHAR(36) NOT NULL COMMENT '产品UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_agent_id` (`agent_id`), -ADD INDEX `idx_user_id` (`user_id`), -ADD INDEX `idx_product_id` (`product_id`); - --- agent_order表 -ALTER TABLE `agent_order` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `agent_id` CHAR(36) NOT NULL COMMENT '代理UUID', -MODIFY COLUMN `order_id` CHAR(36) NOT NULL COMMENT '订单UUID', -MODIFY COLUMN `product_id` CHAR(36) NOT NULL COMMENT '产品UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_agent_id` (`agent_id`), -ADD INDEX `idx_order_id` (`order_id`), -ADD INDEX `idx_product_id` (`product_id`); - --- agent_wallet表 -ALTER TABLE `agent_wallet` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `agent_id` CHAR(36) NOT NULL COMMENT '代理UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD UNIQUE INDEX `uk_agent_id` (`agent_id`); - --- agent_withdrawal表 -ALTER TABLE `agent_withdrawal` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `agent_id` CHAR(36) NOT NULL COMMENT '代理UUID', -MODIFY COLUMN `wallet_id` CHAR(36) NOT NULL COMMENT '钱包UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_agent_id` (`agent_id`), -ADD INDEX `idx_wallet_id` (`wallet_id`); - --- agent_withdrawal_tax表 -ALTER TABLE `agent_withdrawal_tax` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `withdrawal_id` CHAR(36) NOT NULL COMMENT '提现UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_withdrawal_id` (`withdrawal_id`); - --- agent_rebate表 -ALTER TABLE `agent_rebate` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `agent_id` CHAR(36) NOT NULL COMMENT '代理UUID', -MODIFY COLUMN `order_id` CHAR(36) NOT NULL COMMENT '订单UUID', -MODIFY COLUMN `product_id` CHAR(36) NOT NULL COMMENT '产品UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_agent_id` (`agent_id`), -ADD INDEX `idx_order_id` (`order_id`), -ADD INDEX `idx_product_id` (`product_id`); - --- agent_relation表 -ALTER TABLE `agent_relation` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `agent_id` CHAR(36) NOT NULL COMMENT '代理UUID', -MODIFY COLUMN `parent_agent_id` CHAR(36) NULL COMMENT '上级代理UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_agent_id` (`agent_id`), -ADD INDEX `idx_parent_agent_id` (`parent_agent_id`); - --- agent_upgrade表 -ALTER TABLE `agent_upgrade` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `agent_id` CHAR(36) NOT NULL COMMENT '代理UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_agent_id` (`agent_id`); - --- agent_real_name表 -ALTER TABLE `agent_real_name` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `agent_id` CHAR(36) NOT NULL COMMENT '代理UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_agent_id` (`agent_id`); - --- agent_config表 -ALTER TABLE `agent_config` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`); - --- agent_product_config表 -ALTER TABLE `agent_product_config` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `product_id` CHAR(36) NOT NULL COMMENT '产品UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_product_id` (`product_id`); - --- agent_short_link表 -ALTER TABLE `agent_short_link` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `invite_code_id` CHAR(36) NULL COMMENT '邀请码UUID', -MODIFY COLUMN `link_id` CHAR(36) NULL COMMENT '链接UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_invite_code_id` (`invite_code_id`), -ADD INDEX `idx_link_id` (`link_id`); - --- agent_invite_code_usage表 -ALTER TABLE `agent_invite_code_usage` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `invite_code_id` CHAR(36) NOT NULL COMMENT '邀请码UUID', -MODIFY COLUMN `user_id` CHAR(36) NOT NULL COMMENT '用户UUID', -MODIFY COLUMN `agent_id` CHAR(36) NOT NULL COMMENT '代理UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_invite_code_id` (`invite_code_id`), -ADD INDEX `idx_user_id` (`user_id`), -ADD INDEX `idx_agent_id` (`agent_id`); - --- agent_freeze_task表 -ALTER TABLE `agent_freeze_task` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `agent_id` CHAR(36) NOT NULL COMMENT '代理UUID', -MODIFY COLUMN `order_id` CHAR(36) NOT NULL COMMENT '订单UUID', -MODIFY COLUMN `commission_id` CHAR(36) NOT NULL COMMENT '佣金UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_agent_id` (`agent_id`), -ADD INDEX `idx_order_id` (`order_id`), -ADD INDEX `idx_commission_id` (`commission_id`); - --- ============================================ --- 第三部分:修改订单相关表 --- ============================================ - --- order_refund表 -ALTER TABLE `order_refund` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `order_id` CHAR(36) NOT NULL COMMENT '订单UUID', -MODIFY COLUMN `user_id` CHAR(36) NOT NULL COMMENT '用户UUID', -MODIFY COLUMN `product_id` CHAR(36) NOT NULL COMMENT '产品UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_order_id` (`order_id`), -ADD INDEX `idx_user_id` (`user_id`), -ADD INDEX `idx_product_id` (`product_id`); - --- ============================================ --- 第四部分:修改查询相关表 --- ============================================ - --- query_cleanup_log表 -ALTER TABLE `query_cleanup_log` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`); - --- query_cleanup_detail表 -ALTER TABLE `query_cleanup_detail` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `cleanup_log_id` CHAR(36) NOT NULL COMMENT '清理日志UUID', -MODIFY COLUMN `query_id` CHAR(36) NOT NULL COMMENT '查询UUID', -MODIFY COLUMN `order_id` CHAR(36) NOT NULL COMMENT '订单UUID', -MODIFY COLUMN `user_id` CHAR(36) NOT NULL COMMENT '用户UUID', -MODIFY COLUMN `product_id` CHAR(36) NOT NULL COMMENT '产品UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_cleanup_log_id` (`cleanup_log_id`), -ADD INDEX `idx_query_id` (`query_id`), -ADD INDEX `idx_order_id` (`order_id`), -ADD INDEX `idx_user_id` (`user_id`), -ADD INDEX `idx_product_id` (`product_id`); - --- query_cleanup_config表 -ALTER TABLE `query_cleanup_config` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`); - --- ============================================ --- 第五部分:修改产品相关表 --- ============================================ - --- product_feature表 -ALTER TABLE `product_feature` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `product_id` CHAR(36) NOT NULL COMMENT '产品UUID', -MODIFY COLUMN `feature_id` CHAR(36) NOT NULL COMMENT '功能UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_product_id` (`product_id`), -ADD INDEX `idx_feature_id` (`feature_id`); - --- feature表 -ALTER TABLE `feature` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`); - --- ============================================ --- 第六部分:修改其他表 --- ============================================ - --- authorization_document表 -ALTER TABLE `authorization_document` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `user_id` CHAR(36) NOT NULL COMMENT '用户UUID', -MODIFY COLUMN `order_id` CHAR(36) NOT NULL COMMENT '订单UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_user_id` (`user_id`), -ADD INDEX `idx_order_id` (`order_id`); - --- global_notifications表(注意:原表id是int类型) -ALTER TABLE `global_notifications` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`); - --- example表 -ALTER TABLE `example` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `feature_id` CHAR(36) NOT NULL COMMENT '功能UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_feature_id` (`feature_id`); - --- ============================================ --- 第七部分:修改管理后台表 --- ============================================ - --- admin_user表 -ALTER TABLE `admin_user` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`); - --- admin_role表 -ALTER TABLE `admin_role` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`); - --- admin_menu表(注意:字段名是pid,不是parent_id) -ALTER TABLE `admin_menu` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `pid` CHAR(36) NOT NULL DEFAULT '0' COMMENT '父菜单UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_pid` (`pid`); - --- admin_api表 -ALTER TABLE `admin_api` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`); - --- admin_dict_type表 -ALTER TABLE `admin_dict_type` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`); - --- admin_dict_data表(注意:没有dict_type_id字段,使用dict_type字符串) --- 此表不需要修改外键字段,因为使用的是dict_type字符串而不是ID - -ALTER TABLE `admin_dict_data` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`); - --- admin_user_role表 -ALTER TABLE `admin_user_role` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `user_id` CHAR(36) NOT NULL DEFAULT '0' COMMENT '用户UUID', -MODIFY COLUMN `role_id` CHAR(36) NOT NULL DEFAULT '0' COMMENT '角色UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_user_id` (`user_id`), -ADD INDEX `idx_role_id` (`role_id`); - --- admin_role_menu表 -ALTER TABLE `admin_role_menu` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `role_id` CHAR(36) NOT NULL DEFAULT '0' COMMENT '角色UUID', -MODIFY COLUMN `menu_id` CHAR(36) NOT NULL DEFAULT '0' COMMENT '菜单UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_role_id` (`role_id`), -ADD INDEX `idx_menu_id` (`menu_id`); - --- admin_role_api表 -ALTER TABLE `admin_role_api` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `role_id` CHAR(36) NOT NULL DEFAULT '0' COMMENT '角色UUID', -MODIFY COLUMN `api_id` CHAR(36) NOT NULL DEFAULT '0' COMMENT 'API UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_role_id` (`role_id`), -ADD INDEX `idx_api_id` (`api_id`); - --- ============================================ --- 第八部分:修改推广相关表(新增) --- ============================================ - --- admin_promotion_link表 -ALTER TABLE `admin_promotion_link` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `admin_user_id` CHAR(36) NOT NULL DEFAULT '0' COMMENT '推广者账号UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_admin_user_id` (`admin_user_id`); - --- admin_promotion_link_stats_history表 -ALTER TABLE `admin_promotion_link_stats_history` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `link_id` CHAR(36) NOT NULL COMMENT '推广链接UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_link_id` (`link_id`); - --- admin_promotion_link_stats_total表 -ALTER TABLE `admin_promotion_link_stats_total` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `link_id` CHAR(36) NOT NULL COMMENT '推广链接UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD INDEX `idx_link_id` (`link_id`); - --- admin_promotion_order表 -ALTER TABLE `admin_promotion_order` -MODIFY COLUMN `id` CHAR(36) NOT NULL COMMENT 'UUID主键', -MODIFY COLUMN `link_id` CHAR(36) NOT NULL COMMENT '推广链接UUID', -MODIFY COLUMN `order_id` CHAR(36) NOT NULL COMMENT '订单UUID', -MODIFY COLUMN `user_id` CHAR(36) NOT NULL COMMENT '下单用户UUID', -MODIFY COLUMN `admin_user_id` CHAR(36) NOT NULL COMMENT '推广者账号UUID', -DROP PRIMARY KEY, -ADD PRIMARY KEY (`id`), -ADD UNIQUE INDEX `uk_order_id` (`order_id`) COMMENT '确保每个订单只有一条推广记录', -ADD INDEX `idx_link_id` (`link_id`), -ADD INDEX `idx_user_id` (`user_id`) COMMENT '优化用户查询', -ADD INDEX `idx_admin_user_id` (`admin_user_id`); - --- ============================================ --- 注意事项 --- ============================================ --- 1. 此脚本直接修改表结构,不保留旧数据 --- 2. user表和product表已经是CHAR(36)类型,已跳过 --- 3. 执行后,所有ID字段都是CHAR(36)类型 --- 4. 插入新记录时,需要在应用层生成UUID(使用uuid.NewString()) --- 5. 如果表中有数据,需要先清空数据或手动填充UUID --- 6. 建议在开发环境先测试,确认无误后再应用到生产环境 --- 7. admin_menu表使用pid字段而不是parent_id --- 8. admin_dict_data表使用dict_type字符串字段,不是dict_type_id --- 9. global_notifications表的id原为int类型,现改为CHAR(36) \ No newline at end of file diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 959b7a6..9e9a66b 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -1,3 +1,4 @@ + services: mysql: image: mysql:8.0.34