341 lines
10 KiB
Go
341 lines
10 KiB
Go
// Soul创业派对 - 导师模块(stitch_soul)
|
||
// 小程序:GET /api/miniprogram/mentors 列表、GET /api/miniprogram/mentors/:id 详情、POST /api/miniprogram/mentors/:id/book 预约
|
||
// 管理端:db 组 CRUD + 预约列表
|
||
|
||
package handler
|
||
|
||
import (
|
||
"net/http"
|
||
"strconv"
|
||
"strings"
|
||
|
||
"soul-api/internal/database"
|
||
"soul-api/internal/model"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// MiniprogramMentorsList GET /api/miniprogram/mentors 导师列表(支持 q 搜索、skill 筛选)
|
||
func MiniprogramMentorsList(c *gin.Context) {
|
||
db := database.DB()
|
||
q := c.Query("q")
|
||
skill := c.Query("skill")
|
||
|
||
query := db.Model(&model.Mentor{}).Where("(enabled IS NULL OR enabled = 1)")
|
||
if q != "" {
|
||
query = query.Where("name LIKE ? OR intro LIKE ? OR tags LIKE ?", "%"+q+"%", "%"+q+"%", "%"+q+"%")
|
||
}
|
||
if skill != "" {
|
||
query = query.Where("tags LIKE ?", "%"+skill+"%")
|
||
}
|
||
|
||
var list []model.Mentor
|
||
if err := query.Order("sort ASC, id ASC").Find(&list).Error; err != nil {
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
|
||
return
|
||
}
|
||
|
||
// 转为前端友好格式(tags 拆成数组)
|
||
type mentorItem struct {
|
||
model.Mentor
|
||
TagsArr []string `json:"tagsArr"`
|
||
}
|
||
result := make([]mentorItem, len(list))
|
||
for i, m := range list {
|
||
result[i] = mentorItem{Mentor: m}
|
||
if m.Tags != "" {
|
||
result[i].TagsArr = strings.Split(m.Tags, ",")
|
||
for j := range result[i].TagsArr {
|
||
result[i].TagsArr[j] = strings.TrimSpace(result[i].TagsArr[j])
|
||
}
|
||
}
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{"success": true, "data": result})
|
||
}
|
||
|
||
// MiniprogramMentorsDetail GET /api/miniprogram/mentors/:id 导师详情
|
||
func MiniprogramMentorsDetail(c *gin.Context) {
|
||
idStr := c.Param("id")
|
||
id, err := strconv.Atoi(idStr)
|
||
if err != nil || id <= 0 {
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": "无效的导师ID"})
|
||
return
|
||
}
|
||
db := database.DB()
|
||
var m model.Mentor
|
||
if err := db.Where("id = ? AND (enabled IS NULL OR enabled = 1)", id).First(&m).Error; err != nil {
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": "导师不存在"})
|
||
return
|
||
}
|
||
tagsArr := []string{}
|
||
if m.Tags != "" {
|
||
for _, s := range strings.Split(m.Tags, ",") {
|
||
if t := strings.TrimSpace(s); t != "" {
|
||
tagsArr = append(tagsArr, t)
|
||
}
|
||
}
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": true,
|
||
"data": gin.H{
|
||
"id": m.ID,
|
||
"avatar": m.Avatar,
|
||
"name": m.Name,
|
||
"intro": m.Intro,
|
||
"tags": m.Tags,
|
||
"tagsArr": tagsArr,
|
||
"priceSingle": m.PriceSingle,
|
||
"priceHalfYear": m.PriceHalfYear,
|
||
"priceYear": m.PriceYear,
|
||
"quote": m.Quote,
|
||
"whyFind": m.WhyFind,
|
||
"offering": m.Offering,
|
||
"judgmentStyle": m.JudgmentStyle,
|
||
},
|
||
})
|
||
}
|
||
|
||
// MiniprogramMentorsBook POST /api/miniprogram/mentors/:id/book 创建预约(选择咨询类型后创建,后续走支付)
|
||
func MiniprogramMentorsBook(c *gin.Context) {
|
||
idStr := c.Param("id")
|
||
mentorID, err := strconv.Atoi(idStr)
|
||
if err != nil || mentorID <= 0 {
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": "无效的导师ID"})
|
||
return
|
||
}
|
||
var body struct {
|
||
UserID int `json:"userId" binding:"required"`
|
||
ConsultationType string `json:"consultationType" binding:"required"` // single, half_year, year
|
||
}
|
||
if err := c.ShouldBindJSON(&body); err != nil {
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": "参数不完整"})
|
||
return
|
||
}
|
||
if body.ConsultationType != "single" && body.ConsultationType != "half_year" && body.ConsultationType != "year" {
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": "consultationType 需为 single/half_year/year"})
|
||
return
|
||
}
|
||
|
||
db := database.DB()
|
||
var mentor model.Mentor
|
||
if err := db.Where("id = ? AND (enabled IS NULL OR enabled = 1)", mentorID).First(&mentor).Error; err != nil {
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": "导师不存在"})
|
||
return
|
||
}
|
||
|
||
var amount float64
|
||
switch body.ConsultationType {
|
||
case "single":
|
||
if mentor.PriceSingle != nil {
|
||
amount = *mentor.PriceSingle
|
||
}
|
||
case "half_year":
|
||
if mentor.PriceHalfYear != nil {
|
||
amount = *mentor.PriceHalfYear
|
||
}
|
||
case "year":
|
||
if mentor.PriceYear != nil {
|
||
amount = *mentor.PriceYear
|
||
}
|
||
}
|
||
if amount <= 0 {
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": "该咨询类型暂未配置价格"})
|
||
return
|
||
}
|
||
|
||
consult := model.MentorConsultation{
|
||
UserID: body.UserID,
|
||
MentorID: mentorID,
|
||
ConsultationType: body.ConsultationType,
|
||
Amount: amount,
|
||
Status: "created",
|
||
}
|
||
if err := db.Create(&consult).Error; err != nil {
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
|
||
return
|
||
}
|
||
|
||
// 返回预约单,前端可据此调 pay 接口(productType: mentor_consultation, productId: consult.ID)
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": true,
|
||
"data": gin.H{
|
||
"id": consult.ID,
|
||
"mentorId": mentorID,
|
||
"consultationType": body.ConsultationType,
|
||
"amount": amount,
|
||
"status": "created",
|
||
},
|
||
})
|
||
}
|
||
|
||
// DBMentorsList GET /api/db/mentors 管理端导师列表
|
||
func DBMentorsList(c *gin.Context) {
|
||
db := database.DB()
|
||
var list []model.Mentor
|
||
if err := db.Order("sort ASC, id ASC").Find(&list).Error; err != nil {
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{"success": true, "data": list})
|
||
}
|
||
|
||
// DBMentorsAction POST 新增 / PUT 更新 / DELETE 删除 导师
|
||
func DBMentorsAction(c *gin.Context) {
|
||
db := database.DB()
|
||
method := c.Request.Method
|
||
|
||
if method == "POST" {
|
||
var body struct {
|
||
Name string `json:"name" binding:"required"`
|
||
Avatar string `json:"avatar"`
|
||
Intro string `json:"intro"`
|
||
Tags string `json:"tags"`
|
||
PriceSingle *float64 `json:"priceSingle"`
|
||
PriceHalfYear *float64 `json:"priceHalfYear"`
|
||
PriceYear *float64 `json:"priceYear"`
|
||
Quote string `json:"quote"`
|
||
WhyFind string `json:"whyFind"`
|
||
Offering string `json:"offering"`
|
||
JudgmentStyle string `json:"judgmentStyle"`
|
||
Sort int `json:"sort"`
|
||
Enabled *bool `json:"enabled"`
|
||
}
|
||
if err := c.ShouldBindJSON(&body); err != nil {
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": "name 不能为空"})
|
||
return
|
||
}
|
||
m := model.Mentor{
|
||
Name: body.Name,
|
||
Avatar: body.Avatar,
|
||
Intro: body.Intro,
|
||
Tags: body.Tags,
|
||
PriceSingle: body.PriceSingle,
|
||
PriceHalfYear: body.PriceHalfYear,
|
||
PriceYear: body.PriceYear,
|
||
Quote: body.Quote,
|
||
WhyFind: body.WhyFind,
|
||
Offering: body.Offering,
|
||
JudgmentStyle: body.JudgmentStyle,
|
||
Sort: body.Sort,
|
||
Enabled: body.Enabled,
|
||
}
|
||
if m.Enabled == nil {
|
||
trueVal := true
|
||
m.Enabled = &trueVal
|
||
}
|
||
if err := db.Create(&m).Error; err != nil {
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{"success": true, "data": m})
|
||
return
|
||
}
|
||
|
||
if method == "PUT" {
|
||
var body struct {
|
||
ID int `json:"id" binding:"required"`
|
||
Name *string `json:"name"`
|
||
Avatar *string `json:"avatar"`
|
||
Intro *string `json:"intro"`
|
||
Tags *string `json:"tags"`
|
||
PriceSingle *float64 `json:"priceSingle"`
|
||
PriceHalfYear *float64 `json:"priceHalfYear"`
|
||
PriceYear *float64 `json:"priceYear"`
|
||
Quote *string `json:"quote"`
|
||
WhyFind *string `json:"whyFind"`
|
||
Offering *string `json:"offering"`
|
||
JudgmentStyle *string `json:"judgmentStyle"`
|
||
Sort *int `json:"sort"`
|
||
Enabled *bool `json:"enabled"`
|
||
}
|
||
if err := c.ShouldBindJSON(&body); err != nil {
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": "id 不能为空"})
|
||
return
|
||
}
|
||
updates := map[string]interface{}{}
|
||
if body.Name != nil {
|
||
updates["name"] = *body.Name
|
||
}
|
||
if body.Avatar != nil {
|
||
updates["avatar"] = *body.Avatar
|
||
}
|
||
if body.Intro != nil {
|
||
updates["intro"] = *body.Intro
|
||
}
|
||
if body.Tags != nil {
|
||
updates["tags"] = *body.Tags
|
||
}
|
||
if body.PriceSingle != nil {
|
||
updates["price_single"] = *body.PriceSingle
|
||
}
|
||
if body.PriceHalfYear != nil {
|
||
updates["price_half_year"] = *body.PriceHalfYear
|
||
}
|
||
if body.PriceYear != nil {
|
||
updates["price_year"] = *body.PriceYear
|
||
}
|
||
if body.Quote != nil {
|
||
updates["quote"] = *body.Quote
|
||
}
|
||
if body.WhyFind != nil {
|
||
updates["why_find"] = *body.WhyFind
|
||
}
|
||
if body.Offering != nil {
|
||
updates["offering"] = *body.Offering
|
||
}
|
||
if body.JudgmentStyle != nil {
|
||
updates["judgment_style"] = *body.JudgmentStyle
|
||
}
|
||
if body.Sort != nil {
|
||
updates["sort"] = *body.Sort
|
||
}
|
||
if body.Enabled != nil {
|
||
updates["enabled"] = *body.Enabled
|
||
}
|
||
if len(updates) == 0 {
|
||
c.JSON(http.StatusOK, gin.H{"success": true, "message": "无更新"})
|
||
return
|
||
}
|
||
if err := db.Model(&model.Mentor{}).Where("id = ?", body.ID).Updates(updates).Error; err != nil {
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{"success": true, "message": "更新成功"})
|
||
return
|
||
}
|
||
|
||
if method == "DELETE" {
|
||
id := c.Query("id")
|
||
if id == "" {
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": "id 不能为空"})
|
||
return
|
||
}
|
||
if err := db.Where("id = ?", id).Delete(&model.Mentor{}).Error; err != nil {
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{"success": true, "message": "删除成功"})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": "不支持的请求方法"})
|
||
}
|
||
|
||
// DBMentorConsultationsList GET /api/db/mentor-consultations 预约列表(支持 status 筛选)
|
||
func DBMentorConsultationsList(c *gin.Context) {
|
||
db := database.DB()
|
||
status := c.Query("status")
|
||
|
||
query := db.Model(&model.MentorConsultation{})
|
||
if status != "" {
|
||
query = query.Where("status = ?", status)
|
||
}
|
||
|
||
var list []model.MentorConsultation
|
||
if err := query.Order("created_at DESC").Find(&list).Error; err != nil {
|
||
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{"success": true, "data": list})
|
||
}
|