批量优化

This commit is contained in:
hero920103 committed 2026-10-08 15:30:37 +08:00
1 parent 438145cae7
commit c925b198d1
50 files changed
+5716 -291

No files matched your search

+198 -43
View File
@@ -2,10 +2,14 @@
//
// 与 services/wechatmp(公众号)分开:小程序走 sns/jscode2session 与
// wxa/business/getuserphonenumber,两者的 AppID / AppSecret 互不相通。
//
// 配置存储:多应用表 yz_platform_wechat_mini_app(docs/sql/create_wechat_mini_app.sql),
// 旧单行表 yz_platform_wechat_mini_config 仅作为未迁移部署的回退数据源。
package wechatmini
import (
"errors"
"fmt"
"strings"
"time"
@@ -17,6 +21,7 @@ import (
// Config 小程序运行配置(敏感字段已解密)
type Config struct {
ID uint64
Name string
AppID string
AppSecret string // 明文
Enabled bool
@@ -27,18 +32,11 @@ type Config struct {
// ErrNotConfigured 未配置或未启用
var ErrNotConfigured = errors.New("微信小程序未配置或未启用")
// LoadConfig 读取小程序配置(单行,敏感字段解密);未配置返回 ErrNotConfigured
func LoadConfig() (*Config, error) {
var row models.WechatMiniConfig
err := models.Orm.QueryTable(new(models.WechatMiniConfig)).OrderBy("id").One(&row)
if err != nil {
if err == orm.ErrNoRows {
return nil, ErrNotConfigured
}
return nil, err
}
// appFromRow 解密行数据为运行配置
func appFromRow(row models.WechatMiniApp) (*Config, error) {
cfg := &Config{
ID: row.ID,
Name: row.Name,
AppID: strings.TrimSpace(row.AppID),
Enabled: row.Enabled == 1,
AutoBind: row.AutoBind != 0,
@@ -54,6 +52,44 @@ func LoadConfig() (*Config, error) {
return cfg, nil
}
// LoadConfig 读取小程序配置(多应用表第一条,敏感字段解密)。
// 新表无数据时回退旧单行表(未执行迁移 SQL 的存量部署);均未配置返回 ErrNotConfigured
func LoadConfig() (*Config, error) {
var rows []models.WechatMiniApp
_, err := models.Orm.QueryTable(new(models.WechatMiniApp)).
Filter("delete_time__isnull", true).
OrderBy("id").
All(&rows)
if err == nil && len(rows) > 0 {
return appFromRow(rows[0])
}
// 旧单行表回退
var legacy models.WechatMiniConfig
err = models.Orm.QueryTable(new(models.WechatMiniConfig)).OrderBy("id").One(&legacy)
if err != nil {
if err == orm.ErrNoRows {
return nil, ErrNotConfigured
}
return nil, err
}
cfg := &Config{
ID: legacy.ID,
AppID: strings.TrimSpace(legacy.AppID),
Enabled: legacy.Enabled == 1,
AutoBind: legacy.AutoBind != 0,
Remark: legacy.Remark,
}
if legacy.AppSecret != "" {
plain, derr := wechatmp.DecryptSecret(legacy.AppSecret)
if derr != nil {
return nil, derr
}
cfg.AppSecret = plain
}
return cfg, nil
}
// LoadEnabledConfig 读取并校验启用状态
func LoadEnabledConfig() (*Config, error) {
cfg, err := LoadConfig()
@@ -66,61 +102,180 @@ func LoadEnabledConfig() (*Config, error) {
return cfg, nil
}
// SaveInput 保存配置入参(AppSecret 支持掩码表示不修改)
type SaveInput struct {
AppID string
AppSecret string // 掩码 / 空串 = 保持不变
Enabled bool
AutoBind bool
Remark string
// LoadEnabledAppByAppID 按小程序 AppID 精确读取启用配置(多小程序场景,
// 认证端按客户端传入的 appid 选择对应应用)
func LoadEnabledAppByAppID(appID string) (*Config, error) {
appID = strings.TrimSpace(appID)
if appID == "" {
return nil, ErrNotConfigured
}
var row models.WechatMiniApp
err := models.Orm.QueryTable(new(models.WechatMiniApp)).
Filter("app_id", appID).
Filter("delete_time__isnull", true).
One(&row)
if err != nil {
if err == orm.ErrNoRows {
return nil, ErrNotConfigured
}
return nil, err
}
cfg, err := appFromRow(row)
if err != nil {
return nil, err
}
if !cfg.Enabled || cfg.AppSecret == "" {
return nil, ErrNotConfigured
}
return cfg, nil
}
// SaveConfig 保存小程序配置(不存在则创建)
func SaveConfig(in SaveInput) error {
if strings.TrimSpace(in.AppID) == "" {
return errors.New("AppID 不能为空")
}
// ListApps 应用列表(软删除外,AppSecret 不回显)
func ListApps() ([]models.WechatMiniApp, error) {
var rows []models.WechatMiniApp
_, err := models.Orm.QueryTable(new(models.WechatMiniApp)).
Filter("delete_time__isnull", true).
OrderBy("id").
All(&rows)
return rows, err
}
var row models.WechatMiniConfig
err := models.Orm.QueryTable(new(models.WechatMiniConfig)).OrderBy("id").One(&row)
// SaveAppInput 保存应用入参(AppSecret 支持掩码表示不修改)
type SaveAppInput struct {
ID uint64
Name string
AppID string
AppSecret string // 掩码 / 空串 = 保持不变
Enabled bool
AutoBind bool
Remark string
}
// SaveApp 新增/更新小程序应用(AppID 全局唯一,排除自身)
func SaveApp(in SaveAppInput) (uint64, error) {
appID := strings.TrimSpace(in.AppID)
if appID == "" {
return 0, errors.New("AppID 不能为空")
}
now := time.Now()
isNew := false
if err != nil {
if err != orm.ErrNoRows {
return err
var row models.WechatMiniApp
if in.ID > 0 {
err := models.Orm.QueryTable(new(models.WechatMiniApp)).
Filter("id", in.ID).
Filter("delete_time__isnull", true).
One(&row)
if err != nil {
return 0, errors.New("应用不存在或已删除")
}
isNew = true
row = models.WechatMiniConfig{}
} else {
row = models.WechatMiniApp{CreateTime: now}
}
// AppID 唯一性校验(排除自身)
dupQ := models.Orm.QueryTable(new(models.WechatMiniApp)).
Filter("app_id", appID).
Filter("delete_time__isnull", true)
if in.ID > 0 {
dupQ = dupQ.Filter("id__ne", in.ID)
}
var dup models.WechatMiniApp
if err := dupQ.One(&dup); err == nil {
name := strings.TrimSpace(dup.Name)
if name == "" {
name = dup.AppID
}
return 0, fmt.Errorf("AppID 已被应用「%s」占用", name)
}
row.Name = strings.TrimSpace(in.Name)
row.AppID = appID
secret := strings.TrimSpace(in.AppSecret)
if secret != "" && !wechatmp.IsMasked(secret) {
enc, eerr := wechatmp.EncryptSecret(secret)
if eerr != nil {
return eerr
return 0, eerr
}
row.AppSecret = enc
}
row.AppID = strings.TrimSpace(in.AppID)
row.Remark = strings.TrimSpace(in.Remark)
row.Enabled = 0
if in.Enabled {
row.Enabled = 1
} else {
row.Enabled = 0
}
row.AutoBind = 0
if in.AutoBind {
row.AutoBind = 1
} else {
row.AutoBind = 0
}
row.Remark = strings.TrimSpace(in.Remark)
row.UpdateTime = &now
if isNew {
row.CreateTime = now
_, err = models.Orm.Insert(&row)
return err
if row.ID == 0 {
id, err := models.Orm.Insert(&row)
return uint64(id), err
}
_, err = models.Orm.Update(&row)
if _, err := models.Orm.Update(&row); err != nil {
return 0, err
}
return row.ID, nil
}
// DeleteApp 删除应用(软删并停用)
func DeleteApp(id uint64) error {
if id == 0 {
return errors.New("无效ID")
}
now := time.Now()
_, err := models.Orm.QueryTable(new(models.WechatMiniApp)).
Filter("id", id).
Filter("delete_time__isnull", true).
Update(map[string]interface{}{
"delete_time": now,
"update_time": now,
"enabled": 0,
})
return err
}
// SaveInput 旧单行配置保存入参(AppSecret 支持掩码表示不修改)——兼容旧端点,
// 现写入新多应用表的第一行(无行时插入)
type SaveInput struct {
AppID string
AppSecret string // 掩码 / 空串 = 保持不变
Enabled bool
AutoBind bool
Remark string
}
// SaveConfig 保存配置(兼容旧单行端点:写入新表第一行,不存在则创建)
func SaveConfig(in SaveInput) error {
var row models.WechatMiniApp
err := models.Orm.QueryTable(new(models.WechatMiniApp)).
Filter("delete_time__isnull", true).
OrderBy("id").
One(&row)
if err == orm.ErrNoRows {
_, serr := SaveApp(SaveAppInput{
Name: "默认小程序",
AppID: in.AppID,
AppSecret: in.AppSecret,
Enabled: in.Enabled,
AutoBind: in.AutoBind,
Remark: in.Remark,
})
return serr
}
if err != nil {
return err
}
_, serr := SaveApp(SaveAppInput{
ID: row.ID,
Name: row.Name,
AppID: in.AppID,
AppSecret: in.AppSecret,
Enabled: in.Enabled,
AutoBind: in.AutoBind,
Remark: in.Remark,
})
return serr
}