Merge branch 'devlop' into yongxu-dev
# Conflicts: # miniprogram/app.js resolved by devlop version # miniprogram/pages/chapters/chapters.js resolved by devlop version # miniprogram/pages/match/match.js resolved by devlop version # miniprogram/pages/member-detail/member-detail.js resolved by devlop version # miniprogram/pages/my/my.js resolved by devlop version # miniprogram/pages/read/read.js resolved by devlop version # miniprogram/pages/referral/referral.js resolved by devlop version # soul-api/internal/model/person.go resolved by devlop version
This commit is contained in:
@@ -11,6 +11,8 @@ type LinkTag struct {
|
||||
URL string `gorm:"column:url;size:500" json:"url"`
|
||||
Type string `gorm:"column:type;size:20" json:"type"`
|
||||
AppID string `gorm:"column:app_id;size:100" json:"appId,omitempty"`
|
||||
// AppSecret 目标小程序 AppSecret,仅存库;列表/保存响应用 hasAppSecret,永不 json 明文下发
|
||||
AppSecret string `gorm:"column:app_secret;size:256;default:''" json:"-"`
|
||||
PagePath string `gorm:"column:page_path;size:500" json:"pagePath,omitempty"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updatedAt"`
|
||||
|
||||
@@ -4,26 +4,31 @@ import "time"
|
||||
|
||||
// Order 对应表 orders,JSON 输出与现网接口 1:1(小写驼峰)
|
||||
type Order struct {
|
||||
ID string `gorm:"column:id;primaryKey;size:50" json:"id"`
|
||||
OrderSN string `gorm:"column:order_sn;uniqueIndex;size:50" json:"orderSn"`
|
||||
UserID string `gorm:"column:user_id;size:50" json:"userId"`
|
||||
OpenID string `gorm:"column:open_id;size:100" json:"openId"`
|
||||
ProductType string `gorm:"column:product_type;size:50" json:"productType"`
|
||||
ProductID *string `gorm:"column:product_id;size:50" json:"productId,omitempty"`
|
||||
Amount float64 `gorm:"column:amount;type:decimal(10,2)" json:"amount"`
|
||||
Description *string `gorm:"column:description;size:200" json:"description,omitempty"`
|
||||
Status *string `gorm:"column:status;size:20" json:"status,omitempty"`
|
||||
TransactionID *string `gorm:"column:transaction_id;size:100" json:"transactionId,omitempty"`
|
||||
PayTime *time.Time `gorm:"column:pay_time" json:"payTime,omitempty"`
|
||||
ReferralCode *string `gorm:"column:referral_code;size:255" json:"referralCode,omitempty"`
|
||||
ReferrerID *string `gorm:"column:referrer_id;size:255" json:"referrerId,omitempty"`
|
||||
RefundReason *string `gorm:"column:refund_reason;size:500" json:"refundReason,omitempty"`
|
||||
PaymentMethod *string `gorm:"column:payment_method;size:20" json:"paymentMethod,omitempty"`
|
||||
ID string `gorm:"column:id;primaryKey;size:50" json:"id"`
|
||||
OrderSN string `gorm:"column:order_sn;uniqueIndex;size:50" json:"orderSn"`
|
||||
UserID string `gorm:"column:user_id;size:50" json:"userId"`
|
||||
OpenID string `gorm:"column:open_id;size:100" json:"openId"`
|
||||
ProductType string `gorm:"column:product_type;size:50" json:"productType"`
|
||||
ProductID *string `gorm:"column:product_id;size:50" json:"productId,omitempty"`
|
||||
Amount float64 `gorm:"column:amount;type:decimal(10,2)" json:"amount"`
|
||||
Description *string `gorm:"column:description;size:200" json:"description,omitempty"`
|
||||
Status *string `gorm:"column:status;size:20" json:"status,omitempty"`
|
||||
TransactionID *string `gorm:"column:transaction_id;size:100" json:"transactionId,omitempty"`
|
||||
PayTime *time.Time `gorm:"column:pay_time" json:"payTime,omitempty"`
|
||||
ReferralCode *string `gorm:"column:referral_code;size:255" json:"referralCode,omitempty"`
|
||||
ReferrerID *string `gorm:"column:referrer_id;size:255" json:"referrerId,omitempty"`
|
||||
RefundReason *string `gorm:"column:refund_reason;size:500" json:"refundReason,omitempty"`
|
||||
PaymentMethod *string `gorm:"column:payment_method;size:20" json:"paymentMethod,omitempty"`
|
||||
// 代付:关联代付请求、实际付款人
|
||||
GiftPayRequestID *string `gorm:"column:gift_pay_request_id;size:50" json:"giftPayRequestId,omitempty"`
|
||||
PayerUserID *string `gorm:"column:payer_user_id;size:50" json:"payerUserId,omitempty"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updatedAt"`
|
||||
// 飞书 webhook 推送状态(paid 后实时推送;失败可补偿重推)
|
||||
WebhookPushStatus string `gorm:"column:webhook_push_status;size:20;default:''" json:"webhookPushStatus,omitempty"`
|
||||
WebhookPushedAt *time.Time `gorm:"column:webhook_pushed_at" json:"webhookPushedAt,omitempty"`
|
||||
WebhookPushAttempts int `gorm:"column:webhook_push_attempts;default:0" json:"webhookPushAttempts,omitempty"`
|
||||
WebhookPushError *string `gorm:"column:webhook_push_error;size:500" json:"webhookPushError,omitempty"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (Order) TableName() string { return "orders" }
|
||||
|
||||
@@ -19,7 +19,6 @@ type Person struct {
|
||||
PersonID string `gorm:"column:person_id;size:50;uniqueIndex" json:"personId"`
|
||||
Token string `gorm:"column:token;size:36;uniqueIndex" json:"token"` // 32 位唯一 token,文章/小程序传此值
|
||||
Name string `gorm:"column:name;size:100" json:"name"`
|
||||
Avatar string `gorm:"column:avatar;size:512;default:''" json:"avatar"` // 头像 URL,无 user_id 时使用;有 user_id 时优先用 users.avatar
|
||||
Aliases string `gorm:"column:aliases;size:255;default:''" json:"aliases"` // 逗号分隔别名:用于 @ 自动匹配
|
||||
Label string `gorm:"column:label;size:200" json:"label"`
|
||||
CkbApiKey string `gorm:"column:ckb_api_key;size:100;default:''" json:"ckbApiKey"` // 存客宝真实密钥,不对外暴露
|
||||
@@ -35,8 +34,9 @@ type Person struct {
|
||||
AddFriendInterval int `gorm:"column:add_friend_interval;default:1" json:"addFriendInterval"`
|
||||
StartTime string `gorm:"column:start_time;size:10;default:'09:00'" json:"startTime"`
|
||||
EndTime string `gorm:"column:end_time;size:10;default:'18:00'" json:"endTime"`
|
||||
DeviceGroups string `gorm:"column:device_groups;size:255;default:''" json:"deviceGroups"` // 逗号分隔的设备ID列表
|
||||
IsPinned bool `gorm:"column:is_pinned;default:false" json:"isPinned"` // 置顶到小程序首页
|
||||
DeviceGroups string `gorm:"column:device_groups;size:255;default:''" json:"deviceGroups"` // 逗号分隔的设备ID列表
|
||||
// 置顶到小程序首页
|
||||
IsPinned bool `gorm:"column:is_pinned;default:false" json:"isPinned"`
|
||||
|
||||
// PersonSource 来源:空=后台手工添加;vip_sync=超级个体自动同步(共用统一计划)
|
||||
PersonSource string `gorm:"column:person_source;size:32;default:''" json:"personSource"`
|
||||
|
||||
@@ -9,14 +9,14 @@ import (
|
||||
// User 对应表 users,JSON 输出与现网接口 1:1(小写驼峰)
|
||||
// 软删除:管理端删除仅设置 deleted_at,用户再次登录会创建新账号
|
||||
type User struct {
|
||||
ID string `gorm:"column:id;primaryKey;size:50" json:"id"`
|
||||
OpenID *string `gorm:"column:open_id;size:100" json:"openId,omitempty"`
|
||||
SessionKey *string `gorm:"column:session_key;size:200" json:"-"` // 微信 session_key,不输出到 JSON
|
||||
Nickname *string `gorm:"column:nickname;size:100" json:"nickname,omitempty"`
|
||||
Avatar *string `gorm:"column:avatar;size:500" json:"avatar,omitempty"`
|
||||
Phone *string `gorm:"column:phone;size:20" json:"phone,omitempty"`
|
||||
WechatID *string `gorm:"column:wechat_id;size:100" json:"wechatId,omitempty"`
|
||||
Tags *string `gorm:"column:tags;type:text" json:"tags,omitempty"`
|
||||
ID string `gorm:"column:id;primaryKey;size:50" json:"id"`
|
||||
OpenID *string `gorm:"column:open_id;size:100" json:"openId,omitempty"`
|
||||
SessionKey *string `gorm:"column:session_key;size:200" json:"-"` // 微信 session_key,不输出到 JSON
|
||||
Nickname *string `gorm:"column:nickname;size:100" json:"nickname,omitempty"`
|
||||
Avatar *string `gorm:"column:avatar;size:500" json:"avatar,omitempty"`
|
||||
Phone *string `gorm:"column:phone;size:20" json:"phone,omitempty"`
|
||||
WechatID *string `gorm:"column:wechat_id;size:100" json:"wechatId,omitempty"`
|
||||
Tags *string `gorm:"column:tags;type:text" json:"tags,omitempty"`
|
||||
// P3 资料扩展(stitch_soul)
|
||||
Mbti *string `gorm:"column:mbti;size:16" json:"mbti,omitempty"`
|
||||
Region *string `gorm:"column:region;size:100" json:"region,omitempty"`
|
||||
@@ -43,18 +43,18 @@ type User struct {
|
||||
Source *string `gorm:"column:source;size:50" json:"source,omitempty"`
|
||||
|
||||
// 用户标签(管理端编辑、神射手回填共用 ckb_tags 列,JSON 数组字符串)
|
||||
CkbTags *string `gorm:"column:ckb_tags;type:text" json:"ckbTags,omitempty"`
|
||||
CkbTags *string `gorm:"column:ckb_tags;type:text" json:"ckbTags,omitempty"`
|
||||
// VIP 相关(与 next-project 线上 users 表一致,支持手动设置;管理端需读写)
|
||||
IsVip *bool `gorm:"column:is_vip" json:"isVip,omitempty"`
|
||||
VipExpireDate *time.Time `gorm:"column:vip_expire_date" json:"vipExpireDate,omitempty"`
|
||||
VipActivatedAt *time.Time `gorm:"column:vip_activated_at" json:"vipActivatedAt,omitempty"` // 成为 VIP 时间,排序用:付款=pay_time,手动=now
|
||||
VipSort *int `gorm:"column:vip_sort" json:"vipSort,omitempty"` // 手动排序,越小越前,NULL 按 vip_activated_at
|
||||
VipRole *string `gorm:"column:vip_role;size:50" json:"vipRole,omitempty"` // 角色:从 vip_roles 选或手动填写
|
||||
VipName *string `gorm:"column:vip_name;size:100" json:"vipName,omitempty"`
|
||||
VipAvatar *string `gorm:"column:vip_avatar;size:500" json:"vipAvatar,omitempty"`
|
||||
VipProject *string `gorm:"column:vip_project;size:200" json:"vipProject,omitempty"`
|
||||
VipContact *string `gorm:"column:vip_contact;size:100" json:"vipContact,omitempty"`
|
||||
VipBio *string `gorm:"column:vip_bio;type:text" json:"vipBio,omitempty"`
|
||||
IsVip *bool `gorm:"column:is_vip" json:"isVip,omitempty"`
|
||||
VipExpireDate *time.Time `gorm:"column:vip_expire_date" json:"vipExpireDate,omitempty"`
|
||||
VipActivatedAt *time.Time `gorm:"column:vip_activated_at" json:"vipActivatedAt,omitempty"` // 成为 VIP 时间,排序用:付款=pay_time,手动=now
|
||||
VipSort *int `gorm:"column:vip_sort" json:"vipSort,omitempty"` // 手动排序,越小越前,NULL 按 vip_activated_at
|
||||
VipRole *string `gorm:"column:vip_role;size:50" json:"vipRole,omitempty"` // 角色:从 vip_roles 选或手动填写
|
||||
VipName *string `gorm:"column:vip_name;size:100" json:"vipName,omitempty"`
|
||||
VipAvatar *string `gorm:"column:vip_avatar;size:500" json:"vipAvatar,omitempty"`
|
||||
VipProject *string `gorm:"column:vip_project;size:200" json:"vipProject,omitempty"`
|
||||
VipContact *string `gorm:"column:vip_contact;size:100" json:"vipContact,omitempty"`
|
||||
VipBio *string `gorm:"column:vip_bio;type:text" json:"vipBio,omitempty"`
|
||||
|
||||
// 软删除:管理端假删除,用户再次登录会新建账号
|
||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;index" json:"-"`
|
||||
@@ -62,6 +62,8 @@ type User struct {
|
||||
// 以下为接口返回时从订单/绑定表实时计算的字段,不入库
|
||||
PurchasedSectionCount int `gorm:"-" json:"purchasedSectionCount,omitempty"`
|
||||
WalletBalance *float64 `gorm:"-" json:"walletBalance,omitempty"`
|
||||
RFMScore *float64 `gorm:"-" json:"rfmScore,omitempty"`
|
||||
RFMLevel *string `gorm:"-" json:"rfmLevel,omitempty"`
|
||||
}
|
||||
|
||||
func (User) TableName() string { return "users" }
|
||||
|
||||
@@ -1,17 +1,63 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"time"
|
||||
)
|
||||
|
||||
// UserRule 用户旅程引导规则(如:匹配后填写头像、付款1980需填写信息等)
|
||||
// RuleJSON 存储 JSON 数组/对象的列(user_rules 的 trigger_conditions 等)
|
||||
type RuleJSON []byte
|
||||
|
||||
// MarshalJSON 原样输出 JSON,避免 encoding/json 将 []byte 编成 base64 导致前端把 triggerConditions 当字符串而 .map 崩溃
|
||||
func (r RuleJSON) MarshalJSON() ([]byte, error) {
|
||||
if len(r) == 0 {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
out := make([]byte, len(r))
|
||||
copy(out, r)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON 接收请求体中的原始 JSON(对象/数组)
|
||||
func (r *RuleJSON) UnmarshalJSON(data []byte) error {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
if len(data) == 0 || string(data) == "null" {
|
||||
*r = nil
|
||||
return nil
|
||||
}
|
||||
*r = append((*r)[0:0], data...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r RuleJSON) Value() (driver.Value, error) { return []byte(r), nil }
|
||||
func (r *RuleJSON) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
*r = nil
|
||||
return nil
|
||||
}
|
||||
b, ok := value.([]byte)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
*r = append((*r)[0:0], b...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UserRule 用户旅程触达规则(结构化触发条件 + 推送动作,由管理端配置)
|
||||
type UserRule struct {
|
||||
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
|
||||
Title string `gorm:"column:title;size:200;not null" json:"title"`
|
||||
Description string `gorm:"column:description;type:text" json:"description"`
|
||||
Trigger string `gorm:"column:trigger;size:100" json:"trigger"`
|
||||
Sort int `gorm:"column:sort;default:0" json:"sort"`
|
||||
Enabled bool `gorm:"column:enabled;default:true" json:"enabled"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updatedAt"`
|
||||
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
|
||||
Title string `gorm:"column:title;size:200;not null" json:"title"`
|
||||
Description string `gorm:"column:description;type:text" json:"description"`
|
||||
Trigger string `gorm:"column:trigger;size:100" json:"trigger"`
|
||||
TriggerConditions RuleJSON `gorm:"column:trigger_conditions;type:json" json:"triggerConditions,omitempty"`
|
||||
ActionType string `gorm:"column:action_type;size:50;default:'popup'" json:"actionType,omitempty"`
|
||||
ActionConfig RuleJSON `gorm:"column:action_config;type:json" json:"actionConfig,omitempty"`
|
||||
Sort int `gorm:"column:sort;default:0" json:"sort"`
|
||||
Enabled bool `gorm:"column:enabled;default:true" json:"enabled"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (UserRule) TableName() string { return "user_rules" }
|
||||
|
||||
12
soul-api/internal/model/user_rule_completion.go
Normal file
12
soul-api/internal/model/user_rule_completion.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type UserRuleCompletion struct {
|
||||
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
|
||||
UserID string `gorm:"column:user_id;size:100;not null;uniqueIndex:idx_user_rule" json:"userId"`
|
||||
RuleID uint `gorm:"column:rule_id;not null;uniqueIndex:idx_user_rule" json:"ruleId"`
|
||||
CompletedAt time.Time `gorm:"column:completed_at;autoCreateTime" json:"completedAt"`
|
||||
}
|
||||
|
||||
func (UserRuleCompletion) TableName() string { return "user_rule_completions" }
|
||||
Reference in New Issue
Block a user