feat: 数据概览简化 + 用户管理增加余额/提现列

- 数据概览:去掉代付统计独立卡片,总收入中以小标签显示代付金额
- 数据概览:移除余额统计区块(余额改在用户管理中展示)
- 数据概览:恢复转化率卡片(唯一付费用户/总用户)
- 用户管理:用户列表新增「余额/提现」列,显示钱包余额和已提现金额
- 后端:DBUsersList 增加 user_balances 查询,返回 walletBalance 字段
- 后端:User model 添加 WalletBalance 非数据库字段
- 包含之前的小程序埋点和管理后台点击统计面板

Made-with: Cursor
This commit is contained in:
卡若
2026-03-15 15:57:09 +08:00
parent 991e17698c
commit 708547d0dd
52 changed files with 3161 additions and 1103 deletions

View File

@@ -16,7 +16,7 @@ const uploadDir = "uploads"
const maxUploadBytes = 5 * 1024 * 1024 // 5MB
var allowedTypes = map[string]bool{"image/jpeg": true, "image/png": true, "image/gif": true, "image/webp": true}
// UploadPost POST /api/upload 上传图片(表单 file
// UploadPost POST /api/upload 上传图片(表单 file,优先 OSS
func UploadPost(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
@@ -40,16 +40,30 @@ func UploadPost(c *gin.Context) {
if folder == "" {
folder = "avatars"
}
name := fmt.Sprintf("%d_%s%s", time.Now().UnixNano(), randomStrUpload(6), ext)
// 尝试 OSS 上传
if ossCfg := getOssConfig(); ossCfg != nil {
src, err := file.Open()
if err == nil {
defer src.Close()
if ossURL, err := ossUploadFile(src, folder, name); err == nil {
c.JSON(http.StatusOK, gin.H{"success": true, "url": ossURL, "data": gin.H{"url": ossURL, "fileName": name, "size": file.Size, "type": ct, "storage": "oss"}})
return
}
}
}
// 回退本地存储
dir := filepath.Join(uploadDir, folder)
_ = os.MkdirAll(dir, 0755)
name := fmt.Sprintf("%d_%s%s", time.Now().UnixNano(), randomStrUpload(6), ext)
dst := filepath.Join(dir, name)
if err := c.SaveUploadedFile(file, dst); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "保存失败"})
return
}
url := "/" + filepath.ToSlash(filepath.Join(uploadDir, folder, name))
c.JSON(http.StatusOK, gin.H{"success": true, "url": url, "data": gin.H{"url": url, "fileName": name, "size": file.Size, "type": ct}})
c.JSON(http.StatusOK, gin.H{"success": true, "url": url, "data": gin.H{"url": url, "fileName": name, "size": file.Size, "type": ct, "storage": "local"}})
}
func randomStrUpload(n int) string {