package model import ( "database/sql/driver" "encoding/json" "fmt" "time" ) // StringSlice 以 JSON 数组形式存储的字符串切片(用于图片 URL 列表) type StringSlice []string func (s StringSlice) Value() (driver.Value, error) { if s == nil { return "[]", nil } b, err := json.Marshal(s) return string(b), err } func (s *StringSlice) Scan(value interface{}) error { if value == nil { *s = nil return nil } var b []byte switch v := value.(type) { case string: b = []byte(v) case []byte: b = v default: return fmt.Errorf("cannot scan %T into StringSlice", value) } if len(b) == 0 { *s = nil return nil } return json.Unmarshal(b, s) } // Feedback 用户意见反馈(bug / 功能建议):文字 + 附图。多租户按 ShopID 隔离。 type Feedback struct { ID uint64 `gorm:"primaryKey;autoIncrement" json:"id"` CreatedAt time.Time `json:"created_at"` ShopID uint64 `gorm:"index;not null" json:"shop_id"` ShopCode string `gorm:"size:50" json:"shop_code"` UserID uint64 `gorm:"index" json:"user_id"` Username string `gorm:"size:50" json:"username"` Role string `gorm:"size:20" json:"role"` Type string `gorm:"size:20;not null;index" json:"type"` // bug / suggestion Content string `gorm:"type:text" json:"content"` Images StringSlice `gorm:"type:json" json:"images"` AppVersion string `gorm:"size:30" json:"app_version"` Platform string `gorm:"size:20" json:"platform"` ClientIP string `gorm:"size:60" json:"client_ip"` Status string `gorm:"size:20;not null;default:new;index" json:"status"` // new / handled }