小程序可在 Go 上完成微信手机号登录、测评、预约和下单,不再反代 Java。 Co-authored-by: Cursor <cursoragent@cursor.com>
385 lines
10 KiB
Go
385 lines
10 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/yuxingu/digital-psychology/apps/api/internal/middleware"
|
|
"github.com/yuxingu/digital-psychology/apps/api/internal/service/consult"
|
|
"github.com/yuxingu/digital-psychology/apps/api/pkg/response"
|
|
)
|
|
|
|
// ConsultHandler serves /api/v1/psychic/* (ECR-050).
|
|
type ConsultHandler struct {
|
|
Svc *consult.Service
|
|
}
|
|
|
|
func (h *ConsultHandler) Register(api *gin.RouterGroup) {
|
|
g := api.Group("/psychic")
|
|
g.POST("/banner/all", h.banners)
|
|
g.GET("/news/page", h.newsPage)
|
|
g.GET("/news/get", h.newsGet)
|
|
g.POST("/procotol/getByCode", h.protocol)
|
|
g.POST("/study/list", h.studyList)
|
|
g.POST("/study/getSingleDetail", h.studyDetail)
|
|
g.POST("/user-choice/save", h.choiceSave)
|
|
g.POST("/user-choice/getResult", h.choiceResult)
|
|
g.POST("/user-choice/my-test", h.myTest)
|
|
g.GET("/doctor-info/business-scope-list", h.scopes)
|
|
g.GET("/doctor-info/page", h.doctorPage)
|
|
g.GET("/doctor-info/get", h.doctorGet)
|
|
g.POST("/doctor-info/focus", h.focusOn)
|
|
g.POST("/doctor-info/cancel-focus", h.focusOff)
|
|
g.GET("/doctor-info/get-show-info", h.showInfo)
|
|
g.POST("/appointment/remain-list", h.remain)
|
|
g.POST("/appointment/date-detail-list", h.dateDetail)
|
|
g.POST("/order/create", h.orderCreate)
|
|
g.GET("/order/get-pay-param", h.payParam)
|
|
g.POST("/order/order-list", h.orderList)
|
|
g.POST("/order/order-detail", h.orderDetail)
|
|
g.POST("/order/cancel", h.orderCancel)
|
|
g.POST("/order/delete-order", h.orderDelete)
|
|
g.POST("/pay/createOrder", h.payDemo)
|
|
g.POST("/pay/refund", h.payRefund)
|
|
g.POST("/pay/notify", h.payNotify)
|
|
g.GET("/platform-user/getSelfInfo", h.selfInfo)
|
|
g.POST("/platform-user/update", h.updateSelf)
|
|
g.GET("/platform-user/not-read-num", h.notRead)
|
|
g.POST("/platform-user/focus-to-read", h.focusRead)
|
|
g.POST("/platform-user/order-to-read", h.orderRead)
|
|
g.POST("/platform-user/focus-all", h.focusAll)
|
|
g.POST("/platform-user/user-feedback", h.feedback)
|
|
g.POST("/platform-user/feedback-flag", h.feedbackFlag)
|
|
}
|
|
|
|
func (h *ConsultHandler) banners(c *gin.Context) {
|
|
data, err := h.Svc.Banners(c.Request.Context())
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) newsPage(c *gin.Context) {
|
|
data, err := h.Svc.NewsPage(c.Request.Context(), qInt(c, "type", 0), qInt(c, "showMain", -1), qInt(c, "pageNo", 1), qInt(c, "pageSize", 20))
|
|
h.ok(c, data, err)
|
|
}
|
|
|
|
func (h *ConsultHandler) ok(c *gin.Context, data any, err error) {
|
|
if err != nil {
|
|
response.Fail(c, http.StatusBadRequest, 40001, err.Error())
|
|
return
|
|
}
|
|
response.OK(c, data)
|
|
}
|
|
|
|
func (h *ConsultHandler) newsGet(c *gin.Context) {
|
|
data, err := h.Svc.NewsGet(c.Request.Context(), qInt64(c, "id"))
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) protocol(c *gin.Context) {
|
|
data, err := h.Svc.ProtocolByCode(c.Request.Context(), c.Query("code"))
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) studyList(c *gin.Context) {
|
|
data, err := h.Svc.TestList(c.Request.Context(), qInt(c, "showMain", -1))
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) studyDetail(c *gin.Context) {
|
|
data, err := h.Svc.TestDetail(c.Request.Context(), qInt64(c, "studyId"))
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) choiceSave(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
var in consult.ChoiceIn
|
|
if err := c.ShouldBindJSON(&in); err != nil {
|
|
response.Fail(c, http.StatusBadRequest, 10000, "invalid request")
|
|
return
|
|
}
|
|
data, err := h.Svc.SaveChoice(c.Request.Context(), uid, in)
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) choiceResult(c *gin.Context) {
|
|
data, err := h.Svc.GetResult(c.Request.Context(), qInt64(c, "resultId"))
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) myTest(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
var p struct {
|
|
PageNo int `json:"pageNo"`
|
|
PageSize int `json:"pageSize"`
|
|
}
|
|
_ = c.ShouldBindJSON(&p)
|
|
data, err := h.Svc.MyTests(c.Request.Context(), uid, p.PageNo, p.PageSize)
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) scopes(c *gin.Context) {
|
|
data, err := h.Svc.Scopes(c.Request.Context())
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) doctorPage(c *gin.Context) {
|
|
data, err := h.Svc.DoctorPage(c.Request.Context(), c.Query("businessScope"), qInt(c, "isTop", -1), qInt(c, "pageNo", 1), qInt(c, "pageSize", 20))
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) doctorGet(c *gin.Context) {
|
|
uid, _ := middleware.UserIDFromContext(c)
|
|
data, err := h.Svc.DoctorGet(c.Request.Context(), qInt64(c, "id"), uid)
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) focusOn(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
if err := h.Svc.SetFocus(c.Request.Context(), uid, qInt64(c, "id"), true); err != nil {
|
|
response.Fail(c, http.StatusBadRequest, 40001, err.Error())
|
|
return
|
|
}
|
|
response.OK(c, true)
|
|
}
|
|
func (h *ConsultHandler) focusOff(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
if err := h.Svc.SetFocus(c.Request.Context(), uid, qInt64(c, "id"), false); err != nil {
|
|
response.Fail(c, http.StatusBadRequest, 40001, err.Error())
|
|
return
|
|
}
|
|
response.OK(c, true)
|
|
}
|
|
func (h *ConsultHandler) showInfo(c *gin.Context) {
|
|
uid, _ := middleware.UserIDFromContext(c)
|
|
data, err := h.Svc.ShowInfo(c.Request.Context(), qInt64(c, "id"), uid)
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) remain(c *gin.Context) {
|
|
var in struct {
|
|
DoctorID int64 `json:"doctorId"`
|
|
}
|
|
_ = c.ShouldBindJSON(&in)
|
|
data, err := h.Svc.RemainList(c.Request.Context(), in.DoctorID)
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) dateDetail(c *gin.Context) {
|
|
var in struct {
|
|
DoctorID int64 `json:"doctorId"`
|
|
}
|
|
_ = c.ShouldBindJSON(&in)
|
|
data, err := h.Svc.DateDetail(c.Request.Context(), in.DoctorID)
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) orderCreate(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
var in consult.OrderIn
|
|
if err := c.ShouldBindJSON(&in); err != nil {
|
|
response.Fail(c, http.StatusBadRequest, 10000, "invalid request")
|
|
return
|
|
}
|
|
data, err := h.Svc.CreateOrder(c.Request.Context(), uid, in)
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) payParam(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
data, err := h.Svc.PayParam(c.Request.Context(), uid, c.Query("orderSn"))
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) orderList(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
var p struct {
|
|
PageNo int `json:"pageNo"`
|
|
PageSize int `json:"pageSize"`
|
|
}
|
|
_ = c.ShouldBindJSON(&p)
|
|
data, err := h.Svc.OrderList(c.Request.Context(), uid, p.PageNo, p.PageSize)
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) orderDetail(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
data, err := h.Svc.OrderDetail(c.Request.Context(), uid, qInt64(c, "orderId"))
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) orderCancel(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
if err := h.Svc.CancelOrder(c.Request.Context(), uid, qInt64(c, "orderId")); err != nil {
|
|
response.Fail(c, http.StatusBadRequest, 40001, err.Error())
|
|
return
|
|
}
|
|
response.OK(c, true)
|
|
}
|
|
func (h *ConsultHandler) orderDelete(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
if err := h.Svc.DeleteOrder(c.Request.Context(), uid, qInt64(c, "orderId")); err != nil {
|
|
response.Fail(c, http.StatusBadRequest, 40001, err.Error())
|
|
return
|
|
}
|
|
response.OK(c, true)
|
|
}
|
|
func (h *ConsultHandler) payDemo(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
data, err := h.Svc.DemoPay(c.Request.Context(), uid)
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) payRefund(c *gin.Context) {
|
|
response.OK(c, true)
|
|
}
|
|
func (h *ConsultHandler) payNotify(c *gin.Context) {
|
|
raw, _ := c.GetRawData()
|
|
sn := extractXML(string(raw), "out_trade_no")
|
|
if sn != "" {
|
|
_ = h.Svc.MarkPaid(c.Request.Context(), sn)
|
|
}
|
|
c.String(http.StatusOK, "<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>")
|
|
}
|
|
func (h *ConsultHandler) selfInfo(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
data, err := h.Svc.SelfInfo(c.Request.Context(), uid)
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) updateSelf(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
var in struct {
|
|
NickName string `json:"nickName"`
|
|
AvatarUrl string `json:"avatarUrl"`
|
|
StayPeriod string `json:"stayPeriod"`
|
|
}
|
|
_ = c.ShouldBindJSON(&in)
|
|
if err := h.Svc.UpdateSelf(c.Request.Context(), uid, in.NickName, in.AvatarUrl, in.StayPeriod); err != nil {
|
|
response.Fail(c, http.StatusBadRequest, 40001, err.Error())
|
|
return
|
|
}
|
|
response.OK(c, true)
|
|
}
|
|
func (h *ConsultHandler) notRead(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
data, err := h.Svc.NotRead(c.Request.Context(), uid)
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) focusRead(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
_ = h.Svc.FocusToRead(c.Request.Context(), uid)
|
|
response.OK(c, true)
|
|
}
|
|
func (h *ConsultHandler) orderRead(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
_ = h.Svc.OrderToRead(c.Request.Context(), uid)
|
|
response.OK(c, true)
|
|
}
|
|
func (h *ConsultHandler) focusAll(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
data, err := h.Svc.FocusAll(c.Request.Context(), uid)
|
|
h.ok(c, data, err)
|
|
}
|
|
func (h *ConsultHandler) feedback(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
var in struct {
|
|
ContentText string `json:"contentText"`
|
|
}
|
|
_ = c.ShouldBindJSON(&in)
|
|
if err := h.Svc.Feedback(c.Request.Context(), uid, in.ContentText); err != nil {
|
|
response.Fail(c, http.StatusBadRequest, 40001, err.Error())
|
|
return
|
|
}
|
|
response.OK(c, true)
|
|
}
|
|
func (h *ConsultHandler) feedbackFlag(c *gin.Context) {
|
|
uid, ok := h.mustUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
data, err := h.Svc.FeedbackFlag(c.Request.Context(), uid)
|
|
h.ok(c, data, err)
|
|
}
|
|
|
|
func (h *ConsultHandler) mustUser(c *gin.Context) (uuid.UUID, bool) {
|
|
uid, ok := middleware.UserIDFromContext(c)
|
|
if !ok || !h.Svc.Registered(c.Request.Context(), uid) {
|
|
response.Fail(c, http.StatusUnauthorized, 40112, "请先登录后再使用")
|
|
return uuid.Nil, false
|
|
}
|
|
return uid, true
|
|
}
|
|
|
|
func qInt(c *gin.Context, key string, def int) int {
|
|
s := c.Query(key)
|
|
if s == "" {
|
|
return def
|
|
}
|
|
n, err := strconv.Atoi(s)
|
|
if err != nil {
|
|
return def
|
|
}
|
|
return n
|
|
}
|
|
|
|
func qInt64(c *gin.Context, key string) int64 {
|
|
n, _ := strconv.ParseInt(c.Query(key), 10, 64)
|
|
return n
|
|
}
|
|
|
|
func extractXML(s, tag string) string {
|
|
open, close := "<"+tag+">", "</"+tag+">"
|
|
i := strings.Index(s, open)
|
|
if i < 0 {
|
|
open, close = "<"+tag+"><![CDATA[", "]]></"+tag+">"
|
|
i = strings.Index(s, open)
|
|
if i < 0 {
|
|
return ""
|
|
}
|
|
}
|
|
i += len(open)
|
|
j := strings.Index(s[i:], close)
|
|
if j < 0 {
|
|
return ""
|
|
}
|
|
return s[i : i+j]
|
|
}
|