更新小程序开发文档,新增2026-03-03的最佳实践记录,优化个人中心类页面的卡片区边距规范,确保一致性与可用性。调整相关页面以反映最新设计稿,提升用户体验与功能一致性。
This commit is contained in:
@@ -16,9 +16,8 @@ import (
|
||||
)
|
||||
|
||||
// GetPublicDBConfig GET /api/miniprogram/config 公开接口,供小程序获取完整配置(与 next-project 对齐)
|
||||
// 从 system_config 读取 free_chapters、mp_config、feature_config、chapter_config,合并后返回
|
||||
// 从 system_config 读取 chapter_config、feature_config、mp_config,合并后返回(免费以章节 is_free/price 为准)
|
||||
func GetPublicDBConfig(c *gin.Context) {
|
||||
defaultFree := []string{"preface", "epilogue", "1.1", "appendix-1", "appendix-2", "appendix-3"}
|
||||
defaultPrices := gin.H{"section": float64(1), "fullbook": 9.9}
|
||||
defaultFeatures := gin.H{"matchEnabled": true, "referralEnabled": true, "searchEnabled": true, "aboutEnabled": true}
|
||||
apiDomain := "https://soulapi.quwanzhi.com"
|
||||
@@ -36,16 +35,15 @@ func GetPublicDBConfig(c *gin.Context) {
|
||||
}
|
||||
|
||||
out := gin.H{
|
||||
"success": true,
|
||||
"freeChapters": defaultFree,
|
||||
"prices": defaultPrices,
|
||||
"features": defaultFeatures,
|
||||
"mpConfig": defaultMp,
|
||||
"configs": gin.H{}, // 兼容 miniprogram 备用格式 res.configs.feature_config
|
||||
"success": true,
|
||||
"prices": defaultPrices,
|
||||
"features": defaultFeatures,
|
||||
"mpConfig": defaultMp,
|
||||
"configs": gin.H{},
|
||||
}
|
||||
db := database.DB()
|
||||
|
||||
keys := []string{"chapter_config", "free_chapters", "feature_config", "mp_config"}
|
||||
keys := []string{"chapter_config", "feature_config", "mp_config"}
|
||||
for _, k := range keys {
|
||||
var row model.SystemConfig
|
||||
if err := db.Where("config_key = ?", k).First(&row).Error; err != nil {
|
||||
@@ -58,17 +56,6 @@ func GetPublicDBConfig(c *gin.Context) {
|
||||
switch k {
|
||||
case "chapter_config":
|
||||
if m, ok := val.(map[string]interface{}); ok {
|
||||
if v, ok := m["freeChapters"].([]interface{}); ok && len(v) > 0 {
|
||||
arr := make([]string, 0, len(v))
|
||||
for _, x := range v {
|
||||
if s, ok := x.(string); ok {
|
||||
arr = append(arr, s)
|
||||
}
|
||||
}
|
||||
if len(arr) > 0 {
|
||||
out["freeChapters"] = arr
|
||||
}
|
||||
}
|
||||
if v, ok := m["prices"].(map[string]interface{}); ok {
|
||||
out["prices"] = v
|
||||
}
|
||||
@@ -77,19 +64,6 @@ func GetPublicDBConfig(c *gin.Context) {
|
||||
}
|
||||
out["configs"].(gin.H)["chapter_config"] = m
|
||||
}
|
||||
case "free_chapters":
|
||||
if arr, ok := val.([]interface{}); ok && len(arr) > 0 {
|
||||
ss := make([]string, 0, len(arr))
|
||||
for _, x := range arr {
|
||||
if s, ok := x.(string); ok {
|
||||
ss = append(ss, s)
|
||||
}
|
||||
}
|
||||
if len(ss) > 0 {
|
||||
out["freeChapters"] = ss
|
||||
}
|
||||
out["configs"].(gin.H)["free_chapters"] = arr
|
||||
}
|
||||
case "feature_config":
|
||||
if m, ok := val.(map[string]interface{}); ok {
|
||||
// 合并到 features,不整体覆盖以保留 chapter_config 里的
|
||||
@@ -158,7 +132,7 @@ func DBConfigGet(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": data})
|
||||
}
|
||||
|
||||
// AdminSettingsGet GET /api/admin/settings 系统设置页专用:仅返回免费章节、功能开关、站点/作者与价格、小程序配置
|
||||
// AdminSettingsGet GET /api/admin/settings 系统设置页专用:仅返回功能开关、站点/作者与价格、小程序配置
|
||||
func AdminSettingsGet(c *gin.Context) {
|
||||
db := database.DB()
|
||||
apiDomain := "https://soulapi.quwanzhi.com"
|
||||
@@ -174,12 +148,11 @@ func AdminSettingsGet(c *gin.Context) {
|
||||
}
|
||||
out := gin.H{
|
||||
"success": true,
|
||||
"freeChapters": []string{"preface", "epilogue", "1.1", "appendix-1", "appendix-2", "appendix-3"},
|
||||
"featureConfig": gin.H{"matchEnabled": true, "referralEnabled": true, "searchEnabled": true, "aboutEnabled": true},
|
||||
"siteSettings": gin.H{"sectionPrice": float64(1), "baseBookPrice": 9.9, "distributorShare": float64(90), "authorInfo": gin.H{}},
|
||||
"mpConfig": defaultMp,
|
||||
}
|
||||
keys := []string{"free_chapters", "feature_config", "site_settings", "mp_config"}
|
||||
keys := []string{"feature_config", "site_settings", "mp_config"}
|
||||
for _, k := range keys {
|
||||
var row model.SystemConfig
|
||||
if err := db.Where("config_key = ?", k).First(&row).Error; err != nil {
|
||||
@@ -190,18 +163,6 @@ func AdminSettingsGet(c *gin.Context) {
|
||||
continue
|
||||
}
|
||||
switch k {
|
||||
case "free_chapters":
|
||||
if arr, ok := val.([]interface{}); ok && len(arr) > 0 {
|
||||
ss := make([]string, 0, len(arr))
|
||||
for _, x := range arr {
|
||||
if s, ok := x.(string); ok {
|
||||
ss = append(ss, s)
|
||||
}
|
||||
}
|
||||
if len(ss) > 0 {
|
||||
out["freeChapters"] = ss
|
||||
}
|
||||
}
|
||||
case "feature_config":
|
||||
if m, ok := val.(map[string]interface{}); ok && len(m) > 0 {
|
||||
out["featureConfig"] = m
|
||||
@@ -226,10 +187,9 @@ func AdminSettingsGet(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, out)
|
||||
}
|
||||
|
||||
// AdminSettingsPost POST /api/admin/settings 系统设置页专用:一次性保存免费章节、功能开关、站点/作者与价格、小程序配置
|
||||
// AdminSettingsPost POST /api/admin/settings 系统设置页专用:一次性保存功能开关、站点/作者与价格、小程序配置
|
||||
func AdminSettingsPost(c *gin.Context) {
|
||||
var body struct {
|
||||
FreeChapters []string `json:"freeChapters"`
|
||||
FeatureConfig map[string]interface{} `json:"featureConfig"`
|
||||
SiteSettings map[string]interface{} `json:"siteSettings"`
|
||||
MpConfig map[string]interface{} `json:"mpConfig"`
|
||||
@@ -256,12 +216,6 @@ func AdminSettingsPost(c *gin.Context) {
|
||||
}
|
||||
return db.Save(&row).Error
|
||||
}
|
||||
if body.FreeChapters != nil {
|
||||
if err := saveKey("free_chapters", "免费章节ID列表", body.FreeChapters); err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"success": false, "error": "保存免费章节失败: " + err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
if body.FeatureConfig != nil {
|
||||
if err := saveKey("feature_config", "功能开关配置", body.FeatureConfig); err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"success": false, "error": "保存功能开关失败: " + err.Error()})
|
||||
@@ -366,6 +320,140 @@ func AdminReferralSettingsPost(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "message": "推广设置已保存"})
|
||||
}
|
||||
|
||||
func authorConfigToResponse(row *model.AuthorConfig) gin.H {
|
||||
defaultStats := []gin.H{{"label": "商业案例", "value": "62"}, {"label": "连续直播", "value": "365天"}, {"label": "派对分享", "value": "1000+"}}
|
||||
defaultHighlights := []string{"5年私域运营经验", "帮助100+品牌从0到1增长", "连续创业者,擅长商业模式设计"}
|
||||
var stats []gin.H
|
||||
if row.Stats != "" {
|
||||
_ = json.Unmarshal([]byte(row.Stats), &stats)
|
||||
}
|
||||
if len(stats) == 0 {
|
||||
stats = defaultStats
|
||||
}
|
||||
var highlights []string
|
||||
if row.Highlights != "" {
|
||||
_ = json.Unmarshal([]byte(row.Highlights), &highlights)
|
||||
}
|
||||
if len(highlights) == 0 {
|
||||
highlights = defaultHighlights
|
||||
}
|
||||
return gin.H{
|
||||
"name": row.Name,
|
||||
"avatar": row.Avatar,
|
||||
"avatarImg": row.AvatarImg,
|
||||
"title": row.Title,
|
||||
"bio": row.Bio,
|
||||
"stats": stats,
|
||||
"highlights": highlights,
|
||||
}
|
||||
}
|
||||
|
||||
// AdminAuthorSettingsGet GET /api/admin/author-settings 作者详情配置(管理端专用)
|
||||
func AdminAuthorSettingsGet(c *gin.Context) {
|
||||
defaultAuthor := gin.H{
|
||||
"name": "卡若",
|
||||
"avatar": "K",
|
||||
"avatarImg": "",
|
||||
"title": "Soul派对房主理人 · 私域运营专家",
|
||||
"bio": "每天早上6点到9点,在Soul派对房分享真实的创业故事。专注私域运营与项目变现,用云阿米巴模式帮助创业者构建可持续的商业体系。",
|
||||
"stats": []gin.H{{"label": "商业案例", "value": "62"}, {"label": "连续直播", "value": "365天"}, {"label": "派对分享", "value": "1000+"}},
|
||||
"highlights": []string{"5年私域运营经验", "帮助100+品牌从0到1增长", "连续创业者,擅长商业模式设计"},
|
||||
}
|
||||
db := database.DB()
|
||||
var row model.AuthorConfig
|
||||
if err := db.First(&row).Error; err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": defaultAuthor})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": authorConfigToResponse(&row)})
|
||||
}
|
||||
|
||||
// AdminAuthorSettingsPost POST /api/admin/author-settings 保存作者详情配置
|
||||
func AdminAuthorSettingsPost(c *gin.Context) {
|
||||
var body map[string]interface{}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"success": false, "error": "请求体无效"})
|
||||
return
|
||||
}
|
||||
str := func(k string) string {
|
||||
if v, ok := body[k]; ok && v != nil {
|
||||
if s, ok := v.(string); ok {
|
||||
return s
|
||||
}
|
||||
return fmt.Sprintf("%v", v)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
name := str("name")
|
||||
if name == "" {
|
||||
name = "卡若"
|
||||
}
|
||||
avatar := str("avatar")
|
||||
if avatar == "" {
|
||||
avatar = "K"
|
||||
}
|
||||
statsVal := body["stats"]
|
||||
if statsVal == nil {
|
||||
statsVal = []gin.H{{"label": "商业案例", "value": "62"}, {"label": "连续直播", "value": "365天"}, {"label": "派对分享", "value": "1000+"}}
|
||||
}
|
||||
highlightsVal := body["highlights"]
|
||||
if highlightsVal == nil {
|
||||
highlightsVal = []string{}
|
||||
}
|
||||
statsBytes, _ := json.Marshal(statsVal)
|
||||
highlightsBytes, _ := json.Marshal(highlightsVal)
|
||||
|
||||
db := database.DB()
|
||||
var row model.AuthorConfig
|
||||
err := db.First(&row).Error
|
||||
if err != nil {
|
||||
row = model.AuthorConfig{
|
||||
Name: name,
|
||||
Avatar: avatar,
|
||||
AvatarImg: str("avatarImg"),
|
||||
Title: str("title"),
|
||||
Bio: str("bio"),
|
||||
Stats: string(statsBytes),
|
||||
Highlights: string(highlightsBytes),
|
||||
}
|
||||
err = db.Create(&row).Error
|
||||
} else {
|
||||
row.Name = name
|
||||
row.Avatar = avatar
|
||||
row.AvatarImg = str("avatarImg")
|
||||
row.Title = str("title")
|
||||
row.Bio = str("bio")
|
||||
row.Stats = string(statsBytes)
|
||||
row.Highlights = string(highlightsBytes)
|
||||
err = db.Save(&row).Error
|
||||
}
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "message": "作者设置已保存"})
|
||||
}
|
||||
|
||||
// MiniprogramAboutAuthor GET /api/miniprogram/about/author 小程序-关于作者页拉取作者配置(公开,无需鉴权)
|
||||
func MiniprogramAboutAuthor(c *gin.Context) {
|
||||
defaultAuthor := gin.H{
|
||||
"name": "卡若",
|
||||
"avatar": "K",
|
||||
"avatarImg": "",
|
||||
"title": "Soul派对房主理人 · 私域运营专家",
|
||||
"bio": "每天早上6点到9点,在Soul派对房分享真实的创业故事。",
|
||||
"stats": []gin.H{{"label": "商业案例", "value": "62"}, {"label": "连续直播", "value": "365天"}, {"label": "派对分享", "value": "1000+"}},
|
||||
"highlights": []string{"5年私域运营经验", "帮助100+品牌从0到1增长", "连续创业者,擅长商业模式设计"},
|
||||
}
|
||||
db := database.DB()
|
||||
var row model.AuthorConfig
|
||||
if err := db.First(&row).Error; err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": defaultAuthor})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": authorConfigToResponse(&row)})
|
||||
}
|
||||
|
||||
// DBConfigPost POST /api/db/config
|
||||
func DBConfigPost(c *gin.Context) {
|
||||
var body struct {
|
||||
|
||||
Reference in New Issue
Block a user