Files
soul-yongping/soul-api/internal/handler/mentor.go

341 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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})
}