chore: karuo-party 分平台 SKILL + 多平台分发更新;db handler 调整

Made-with: Cursor
This commit is contained in:
卡若
2026-03-24 12:00:04 +08:00
parent 1d56d0336c
commit 70b83fdb25
7 changed files with 294 additions and 33 deletions

View File

@@ -47,6 +47,92 @@ func parseConfigBool(v interface{}) bool {
}
}
// isLikelyWxMiniProgramAppID 判断是否为微信小程序 AppID 常见形态wx + 16 位十六进制(共 18 字符)。
// 后台「链接标签」若 type=miniprogram 且在此列直接填真实 AppIDC 端会把该值当作 mpKey 去 linkedMiniprograms 里匹配 key
// 若未单独配置 linked_miniprograms会提示「未找到关联小程序配置」。mergeDirectMiniProgramLinksFromLinkTags 会据此自动补全映射。
func isLikelyWxMiniProgramAppID(s string) bool {
s = strings.TrimSpace(s)
if len(s) != 18 || !strings.HasPrefix(s, "wx") {
return false
}
for i := 2; i < len(s); i++ {
c := s[i]
if (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') {
continue
}
return false
}
return true
}
func linkedMiniprogramItemKey(item gin.H) string {
if v, ok := item["key"]; ok && v != nil {
if s, ok := v.(string); ok {
return strings.TrimSpace(s)
}
}
return ""
}
func linkedMiniprogramItemAppIDEmpty(item gin.H) bool {
v, ok := item["appId"]
if !ok || v == nil {
return true
}
s, ok := v.(string)
return !ok || strings.TrimSpace(s) == ""
}
func linkedMiniprogramItemPathEmpty(item gin.H) bool {
v, ok := item["path"]
if !ok || v == nil {
return true
}
s, ok := v.(string)
return !ok || strings.TrimSpace(s) == ""
}
// mergeDirectMiniProgramLinksFromLinkTags 将「直接填写微信 AppID」的链接标签并入 linkedMiniprograms兼容现有小程序 navigateToMiniProgram 查表逻辑(不改 C 端)。
func mergeDirectMiniProgramLinksFromLinkTags(linked *[]gin.H, tags []model.LinkTag) {
if linked == nil {
return
}
byKey := make(map[string]int)
for i := range *linked {
k := linkedMiniprogramItemKey((*linked)[i])
if k != "" {
byKey[k] = i
}
}
for _, t := range tags {
if strings.TrimSpace(strings.ToLower(t.Type)) != "miniprogram" {
continue
}
app := strings.TrimSpace(t.AppID)
if app == "" || !isLikelyWxMiniProgramAppID(app) {
continue
}
path := strings.TrimSpace(t.PagePath)
if idx, ok := byKey[app]; ok {
item := (*linked)[idx]
if linkedMiniprogramItemAppIDEmpty(item) {
item["appId"] = app
}
if path != "" && linkedMiniprogramItemPathEmpty(item) {
item["path"] = path
}
(*linked)[idx] = item
continue
}
entry := gin.H{"key": app, "appId": app}
if path != "" {
entry["path"] = path
}
*linked = append(*linked, entry)
byKey[app] = len(*linked) - 1
}
}
// defaultMpUi 小程序文案与导航默认值,存于 mp_config.mpUi管理端系统设置可部分覆盖深合并
func defaultMpUi() gin.H {
return gin.H{
@@ -226,35 +312,34 @@ func buildMiniprogramConfig() gin.H {
if _, has := out["userDiscount"]; !has {
out["userDiscount"] = float64(5)
}
// 链接标签列表(小程序 onLinkTagTap 需要 typeminiprogram 类型 mpKey,用 key 查 linkedMiniprograms 得 appId
// 链接标签列表(小程序 onLinkTagTapminiprogram 类型下发 mpKey=C 端用其匹配 linkedMiniprograms[].key历史设计为「密钥→appId」现支持 app_id 列直接填微信 AppID 并由下方 merge 自动补 linkedMiniprograms
var linkTagRows []model.LinkTag
if err := db.Order("label ASC").Find(&linkTagRows).Error; err == nil {
tags := make([]gin.H, 0, len(linkTagRows))
for _, t := range linkTagRows {
h := gin.H{"tagId": t.TagID, "label": t.Label, "url": t.URL, "type": t.Type, "pagePath": t.PagePath}
if t.Type == "miniprogram" {
h["mpKey"] = t.AppID // miniprogram 类型时 AppID 列存的是密钥
} else {
h["appId"] = t.AppID
}
tags = append(tags, h)
_ = db.Order("label ASC").Find(&linkTagRows).Error
tags := make([]gin.H, 0, len(linkTagRows))
for _, t := range linkTagRows {
h := gin.H{"tagId": t.TagID, "label": t.Label, "url": t.URL, "type": t.Type, "pagePath": t.PagePath}
if t.Type == "miniprogram" {
h["mpKey"] = t.AppID // 可为「关联表 key」或「直接 wx AppID」后者由 mergeDirectMiniProgramLinksFromLinkTags 补全 linkedMiniprograms
} else {
h["appId"] = t.AppID
}
out["linkTags"] = tags
tags = append(tags, h)
}
// 关联小程序列表key 为 32 位密钥,小程序用 key 查 appId 后 wx.navigateToMiniProgram
out["linkTags"] = tags
// 关联小程序列表小程序find(m => m.key === mpKey) → navigateToMiniProgram
var linkedList []gin.H
var linkedMpRow model.SystemConfig
if err := db.Where("config_key = ?", "linked_miniprograms").First(&linkedMpRow).Error; err == nil && len(linkedMpRow.ConfigValue) > 0 {
var linkedList []gin.H
if err := json.Unmarshal(linkedMpRow.ConfigValue, &linkedList); err == nil && len(linkedList) > 0 {
out["linkedMiniprograms"] = linkedList
} else {
// JSON解析失败使用空数组
out["linkedMiniprograms"] = []gin.H{}
if err := json.Unmarshal(linkedMpRow.ConfigValue, &linkedList); err != nil {
linkedList = nil
}
} else {
// 未找到配置或查询失败,使用空数组作为默认值
out["linkedMiniprograms"] = []gin.H{}
}
if linkedList == nil {
linkedList = []gin.H{}
}
mergeDirectMiniProgramLinksFromLinkTags(&linkedList, linkTagRows)
out["linkedMiniprograms"] = linkedList
// 归一化 auditMode兼容历史 bool / 字符串 / 数字)
if mp, ok := out["mpConfig"].(gin.H); ok {
mp["auditMode"] = parseConfigBool(mp["auditMode"])