完成speaker后端
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/logic/meeting_speaker"
|
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/logic/meeting_speaker"
|
||||||
|
model2 "github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/meetingmodel"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/model"
|
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/model"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/types"
|
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/types"
|
||||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||||
@@ -39,7 +40,9 @@ func CreateSpeakerHandler(cfg *config.Config) http.HandlerFunc {
|
|||||||
|
|
||||||
speakerModel := model.NewMeetingSpeakerModel(conn)
|
speakerModel := model.NewMeetingSpeakerModel(conn)
|
||||||
|
|
||||||
l := meeting_speaker.NewCreateSpeakerLogic(r.Context(), cfg, speakerModel)
|
meetingModel := model2.NewMeetingModel(conn)
|
||||||
|
|
||||||
|
l := meeting_speaker.NewCreateSpeakerLogic(r.Context(), cfg, speakerModel, meetingModel)
|
||||||
resp, err := l.CreateSpeaker(&req)
|
resp, err := l.CreateSpeaker(&req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpx.ErrorCtx(r.Context(), w, err)
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ package meeting_speaker
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/logic/meeting_speaker"
|
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/logic/meeting_speaker"
|
||||||
@@ -18,10 +20,18 @@ import (
|
|||||||
func DeleteSpeakerHandler(cfg *config.Config) http.HandlerFunc {
|
func DeleteSpeakerHandler(cfg *config.Config) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
var req types.DeleteSpeakerReq
|
var req types.DeleteSpeakerReq
|
||||||
if err := httpx.Parse(r, &req); err != nil {
|
pathParts := strings.Split(r.URL.Path, "/")
|
||||||
httpx.ErrorCtx(r.Context(), w, err)
|
if len(pathParts) < 3 { // 确保路径格式正确
|
||||||
|
httpx.ErrorCtx(r.Context(), w, fmt.Errorf("invalid path format"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
idStr := pathParts[3]
|
||||||
|
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, fmt.Errorf("invalid meeting ID"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Id = id
|
||||||
|
|
||||||
mysqlCfg := cfg.MySQL
|
mysqlCfg := cfg.MySQL
|
||||||
dsn := fmt.Sprintf(
|
dsn := fmt.Sprintf(
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/logic/meeting_speaker"
|
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/logic/meeting_speaker"
|
||||||
|
model2 "github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/meetingmodel"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/model"
|
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/model"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/types"
|
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/types"
|
||||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||||
@@ -39,7 +40,9 @@ func ListSpeakersByMeetingHandler(cfg *config.Config) http.HandlerFunc {
|
|||||||
|
|
||||||
speakerModel := model.NewMeetingSpeakerModel(conn)
|
speakerModel := model.NewMeetingSpeakerModel(conn)
|
||||||
|
|
||||||
l := meeting_speaker.NewListSpeakersByMeetingLogic(r.Context(), cfg, speakerModel)
|
meetingModel := model2.NewMeetingModel(conn)
|
||||||
|
|
||||||
|
l := meeting_speaker.NewListSpeakersByMeetingLogic(r.Context(), cfg, speakerModel, meetingModel)
|
||||||
resp, err := l.ListSpeakersByMeeting(&req)
|
resp, err := l.ListSpeakersByMeeting(&req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpx.ErrorCtx(r.Context(), w, err)
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/logic/meeting_speaker"
|
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/logic/meeting_speaker"
|
||||||
|
model2 "github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/meetingmodel"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/model"
|
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/model"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/types"
|
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/types"
|
||||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||||
@@ -39,7 +40,9 @@ func UpdateSpeakerHandler(cfg *config.Config) http.HandlerFunc {
|
|||||||
|
|
||||||
speakerModel := model.NewMeetingSpeakerModel(conn)
|
speakerModel := model.NewMeetingSpeakerModel(conn)
|
||||||
|
|
||||||
l := meeting_speaker.NewUpdateSpeakerLogic(r.Context(), cfg, speakerModel)
|
meetingModel := model2.NewMeetingModel(conn)
|
||||||
|
|
||||||
|
l := meeting_speaker.NewUpdateSpeakerLogic(r.Context(), cfg, speakerModel, meetingModel)
|
||||||
resp, err := l.UpdateSpeaker(&req)
|
resp, err := l.UpdateSpeaker(&req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpx.ErrorCtx(r.Context(), w, err)
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
|||||||
@@ -5,8 +5,11 @@ package meeting_speaker
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||||
|
model2 "github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/meetingmodel"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/model"
|
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/model"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/types"
|
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/types"
|
||||||
|
|
||||||
@@ -15,22 +18,86 @@ import (
|
|||||||
|
|
||||||
type CreateSpeakerLogic struct {
|
type CreateSpeakerLogic struct {
|
||||||
logx.Logger
|
logx.Logger
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cfg *config.Config
|
cfg *config.Config
|
||||||
model model.MeetingSpeakerModel
|
model model.MeetingSpeakerModel
|
||||||
|
meetingmodel model2.MeetingModel
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCreateSpeakerLogic(ctx context.Context, cfg *config.Config, model model.MeetingSpeakerModel) *CreateSpeakerLogic {
|
func NewCreateSpeakerLogic(ctx context.Context, cfg *config.Config, model model.MeetingSpeakerModel, meetingmodel model2.MeetingModel) *CreateSpeakerLogic {
|
||||||
return &CreateSpeakerLogic{
|
return &CreateSpeakerLogic{
|
||||||
Logger: logx.WithContext(ctx),
|
Logger: logx.WithContext(ctx),
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
model: model,
|
model: model,
|
||||||
|
meetingmodel: meetingmodel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *CreateSpeakerLogic) CreateSpeaker(req *types.CreateSpeakerReq) (resp *types.CreateSpeakerResp, err error) {
|
func (l *CreateSpeakerLogic) CreateSpeaker(req *types.CreateSpeakerReq) (resp *types.CreateSpeakerResp, err error) {
|
||||||
// todo: add your logic here and delete this line
|
// 1. 基础参数二次校验(补充 validate 未覆盖的业务逻辑)
|
||||||
|
if req.MeetingId <= 0 {
|
||||||
|
return nil, errors.New("会议ID无效,需传入正整数")
|
||||||
|
}
|
||||||
|
if len(req.Name) == 0 || len(req.Name) > 100 {
|
||||||
|
return nil, errors.New("嘉宾姓名必填且长度不能超过100字")
|
||||||
|
}
|
||||||
|
if req.Title != "" && len(req.Title) > 200 {
|
||||||
|
return nil, errors.New("嘉宾头衔长度不能超过200字")
|
||||||
|
}
|
||||||
|
if req.Avatar != "" && len(req.Avatar) > 512 {
|
||||||
|
return nil, errors.New("头像URL长度不能超过512字符")
|
||||||
|
}
|
||||||
|
// 排序字段默认0(未传时设为0,符合非负整数要求)
|
||||||
|
if req.Sort < 0 {
|
||||||
|
return nil, errors.New("排序值不能为负数")
|
||||||
|
}
|
||||||
|
|
||||||
return
|
// 2. 校验关联会议是否存在(且未被删除)
|
||||||
|
_, err = l.meetingmodel.FindOne(l.ctx, req.MeetingId)
|
||||||
|
if err != nil {
|
||||||
|
if err == model.ErrNotFound {
|
||||||
|
return nil, errors.New("关联的会议不存在或已被删除")
|
||||||
|
}
|
||||||
|
l.Logger.Errorf("查询关联会议失败(MeetingId: %d):%v", req.MeetingId, err)
|
||||||
|
return nil, errors.New("创建嘉宾失败,请重试")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 构造数据库模型数据(字段一一对应)
|
||||||
|
speaker := &model.MeetingSpeaker{
|
||||||
|
MeetingId: req.MeetingId,
|
||||||
|
Name: req.Name,
|
||||||
|
Title: req.Title, // 可选字段,空字符串直接存储
|
||||||
|
Avatar: req.Avatar,
|
||||||
|
Intro: sql.NullString{
|
||||||
|
String: req.Intro, // 赋值实际字符串
|
||||||
|
Valid: req.Intro != "", // 若不为空字符串,则设为有效(存实际值);若为空,则设为无效(存 NULL)
|
||||||
|
}, // 长文本字段,支持空值
|
||||||
|
Sort: int64(req.Sort), // 未传时默认0,符合业务预期
|
||||||
|
// 若模型包含 CreateTime/UpdateTime/IsDelete,无需手动赋值(数据库自动处理)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 处理特殊字段(若模型中 Intro 为 sql.NullString 类型,需转换)
|
||||||
|
// 注:根据 Insert 方法参数推断 Intro 为 string 类型,若为 sql.NullString 则替换为:
|
||||||
|
// Intro: sql.NullString{String: req.Intro, Valid: req.Intro != ""},
|
||||||
|
|
||||||
|
// 5. 调用模型层插入嘉宾数据
|
||||||
|
result, err := l.model.Insert(l.ctx, speaker)
|
||||||
|
if err != nil {
|
||||||
|
l.Logger.Errorf("创建会议嘉宾失败(MeetingId: %d, Name: %s):%v", req.MeetingId, req.Name, err)
|
||||||
|
return nil, errors.New("创建嘉宾失败,请重试")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 获取新增嘉宾的主键ID(用于响应返回)
|
||||||
|
speakerId, err := result.LastInsertId()
|
||||||
|
if err != nil {
|
||||||
|
l.Logger.Errorf("获取嘉宾ID失败(MeetingId: %d, Name: %s):%v", req.MeetingId, req.Name, err)
|
||||||
|
return nil, errors.New("嘉宾创建成功,但获取ID失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. 构造响应结果
|
||||||
|
return &types.CreateSpeakerResp{
|
||||||
|
Msg: "会议嘉宾创建成功",
|
||||||
|
SpeakerId: speakerId,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package meeting_speaker
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/model"
|
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/model"
|
||||||
@@ -30,7 +31,35 @@ func NewDeleteSpeakerLogic(ctx context.Context, cfg *config.Config, model model.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *DeleteSpeakerLogic) DeleteSpeaker(req *types.DeleteSpeakerReq) (resp *types.DeleteSpeakerResp, err error) {
|
func (l *DeleteSpeakerLogic) DeleteSpeaker(req *types.DeleteSpeakerReq) (resp *types.DeleteSpeakerResp, err error) {
|
||||||
// todo: add your logic here and delete this line
|
// 1. 校验嘉宾ID有效性
|
||||||
|
if req.Id <= 0 {
|
||||||
|
return nil, errors.New("嘉宾ID无效,请传入正整数")
|
||||||
|
}
|
||||||
|
|
||||||
return
|
// 2. 检查嘉宾是否存在(且未被删除)
|
||||||
|
_, err = l.model.FindOne(l.ctx, req.Id)
|
||||||
|
if err != nil {
|
||||||
|
if err == model.ErrNotFound {
|
||||||
|
return nil, errors.New("嘉宾不存在或已被删除")
|
||||||
|
}
|
||||||
|
l.Logger.Errorf("查询嘉宾失败(ID: %d):%v", req.Id, err)
|
||||||
|
return nil, errors.New("删除嘉宾失败,请重试")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 执行软删除操作
|
||||||
|
rowsAffected, err := l.model.SoftDelete(l.ctx, req.Id)
|
||||||
|
if err != nil {
|
||||||
|
l.Logger.Errorf("软删除嘉宾失败(ID: %d):%v", req.Id, err)
|
||||||
|
return nil, errors.New("删除嘉宾失败,请重试")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 确认删除生效(避免并发删除导致未生效)
|
||||||
|
if rowsAffected == 0 {
|
||||||
|
return nil, errors.New("删除失败,嘉宾可能已被删除")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 构造响应
|
||||||
|
return &types.DeleteSpeakerResp{
|
||||||
|
Msg: "嘉宾已软删除成功",
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ func NewGetSpeakerLogic(ctx context.Context, cfg *config.Config, model model.Mee
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *GetSpeakerLogic) GetSpeaker(req *types.GetSpeakerReq) (resp *types.GetSpeakerResp, err error) {
|
func (l *GetSpeakerLogic) GetSpeaker(req *types.GetSpeakerReq) (resp *types.GetSpeakerResp, err error) {
|
||||||
// todo: add your logic here and delete this line
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,11 @@ package meeting_speaker
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||||
|
model2 "github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/meetingmodel"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/model"
|
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/model"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/types"
|
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/types"
|
||||||
|
|
||||||
@@ -15,22 +18,81 @@ import (
|
|||||||
|
|
||||||
type ListSpeakersByMeetingLogic struct {
|
type ListSpeakersByMeetingLogic struct {
|
||||||
logx.Logger
|
logx.Logger
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cfg *config.Config
|
cfg *config.Config
|
||||||
model model.MeetingSpeakerModel
|
model model.MeetingSpeakerModel
|
||||||
|
meetingmodel model2.MeetingModel
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewListSpeakersByMeetingLogic(ctx context.Context, cfg *config.Config, model model.MeetingSpeakerModel) *ListSpeakersByMeetingLogic {
|
func NewListSpeakersByMeetingLogic(ctx context.Context, cfg *config.Config, model model.MeetingSpeakerModel, meetingmodel model2.MeetingModel) *ListSpeakersByMeetingLogic {
|
||||||
return &ListSpeakersByMeetingLogic{
|
return &ListSpeakersByMeetingLogic{
|
||||||
Logger: logx.WithContext(ctx),
|
Logger: logx.WithContext(ctx),
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
model: model,
|
model: model,
|
||||||
|
meetingmodel: meetingmodel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *ListSpeakersByMeetingLogic) ListSpeakersByMeeting(req *types.ListSpeakersByMeetingReq) (resp *types.ListSpeakersByMeetingResp, err error) {
|
func (l *ListSpeakersByMeetingLogic) ListSpeakersByMeeting(req *types.ListSpeakersByMeetingReq) (resp *types.ListSpeakersByMeetingResp, err error) {
|
||||||
// todo: add your logic here and delete this line
|
// 1. 校验请求参数有效性
|
||||||
|
// 1.1 会议ID校验
|
||||||
|
if req.MeetingId <= 0 {
|
||||||
|
return nil, errors.New("会议ID无效,请传入正整数")
|
||||||
|
}
|
||||||
|
// 1.2 分页参数校验(设置默认值,避免非法值)
|
||||||
|
page := req.Page
|
||||||
|
if page <= 0 {
|
||||||
|
page = 1
|
||||||
|
}
|
||||||
|
pageSize := req.PageSize
|
||||||
|
if pageSize <= 0 || pageSize > 100 { // 限制最大100条/页,避免性能问题
|
||||||
|
pageSize = 10
|
||||||
|
}
|
||||||
|
|
||||||
return
|
// 2. 校验关联会议是否存在(避免查询不存在的会议的嘉宾)
|
||||||
|
_, err = l.meetingmodel.FindOne(l.ctx, req.MeetingId)
|
||||||
|
if err != nil {
|
||||||
|
if err == model.ErrNotFound {
|
||||||
|
return nil, errors.New("关联的会议不存在或已被删除")
|
||||||
|
}
|
||||||
|
l.Logger.Errorf("查询关联会议失败(MeetingId: %d):%v", req.MeetingId, err)
|
||||||
|
return nil, errors.New("查询嘉宾列表失败,请重试")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 调用模型层查询嘉宾列表(分页+软删除过滤+排序)
|
||||||
|
speakers, total, err := l.model.ListByMeetingId(l.ctx, req.MeetingId, page, pageSize)
|
||||||
|
if err != nil {
|
||||||
|
l.Logger.Errorf("查询会议嘉宾列表失败(MeetingId: %d, page: %d):%v", req.MeetingId, page, err)
|
||||||
|
return nil, errors.New("查询嘉宾列表失败,请重试")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 转换模型数据为响应格式(适配前端展示)
|
||||||
|
var speakerDetails []*types.SpeakerDetail
|
||||||
|
for _, speaker := range speakers {
|
||||||
|
speakerDetails = append(speakerDetails, &types.SpeakerDetail{
|
||||||
|
Id: speaker.Id,
|
||||||
|
MeetingId: speaker.MeetingId,
|
||||||
|
Name: speaker.Name,
|
||||||
|
Title: speaker.Title,
|
||||||
|
Avatar: speaker.Avatar,
|
||||||
|
Intro: getNullStringValue(speaker.Intro),
|
||||||
|
Sort: int(speaker.Sort),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 构造响应(包含分页信息,方便前端渲染分页控件)
|
||||||
|
return &types.ListSpeakersByMeetingResp{
|
||||||
|
Msg: "查询嘉宾列表成功", // 注意:结构体 json tag 为 "message",序列化后前端获取 key 为 "message"
|
||||||
|
Total: total, // 该会议下未删除的嘉宾总条数
|
||||||
|
Speakers: speakerDetails, // 当前页嘉宾列表(按 sort 升序)
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 工具函数:处理 sql.NullString 类型(若模型中 Intro 为该类型则启用)
|
||||||
|
func getNullStringValue(nullStr sql.NullString) string {
|
||||||
|
if nullStr.Valid {
|
||||||
|
return nullStr.String
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,11 @@ package meeting_speaker
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||||
|
model2 "github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/meetingmodel"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/model"
|
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/model"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/types"
|
"github.com/JACKYMYPERSON/hldrCenter/internal/meetingspeaker/internal/types"
|
||||||
|
|
||||||
@@ -15,22 +18,97 @@ import (
|
|||||||
|
|
||||||
type UpdateSpeakerLogic struct {
|
type UpdateSpeakerLogic struct {
|
||||||
logx.Logger
|
logx.Logger
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cfg *config.Config
|
cfg *config.Config
|
||||||
model model.MeetingSpeakerModel
|
model model.MeetingSpeakerModel
|
||||||
|
meetingmodel model2.MeetingModel
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUpdateSpeakerLogic(ctx context.Context, cfg *config.Config, model model.MeetingSpeakerModel) *UpdateSpeakerLogic {
|
func NewUpdateSpeakerLogic(ctx context.Context, cfg *config.Config, model model.MeetingSpeakerModel, meetingmodel model2.MeetingModel) *UpdateSpeakerLogic {
|
||||||
return &UpdateSpeakerLogic{
|
return &UpdateSpeakerLogic{
|
||||||
Logger: logx.WithContext(ctx),
|
Logger: logx.WithContext(ctx),
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
model: model,
|
model: model,
|
||||||
|
meetingmodel: meetingmodel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *UpdateSpeakerLogic) UpdateSpeaker(req *types.UpdateSpeakerReq) (resp *types.UpdateSpeakerResp, err error) {
|
func (l *UpdateSpeakerLogic) UpdateSpeaker(req *types.UpdateSpeakerReq) (resp *types.UpdateSpeakerResp, err error) {
|
||||||
// todo: add your logic here and delete this line
|
// 1. 基础参数校验(严格对齐字段类型与校验规则)
|
||||||
|
// 1.1 嘉宾ID必填且有效
|
||||||
|
if req.Id <= 0 {
|
||||||
|
return nil, errors.New("嘉宾ID无效,请传入正整数")
|
||||||
|
}
|
||||||
|
// 1.2 姓名:传入则需非空且长度≤100字(适配 validate:min=1,max=100)
|
||||||
|
if req.Name != "" && len(req.Name) > 100 {
|
||||||
|
return nil, errors.New("嘉宾姓名长度不能超过100字")
|
||||||
|
}
|
||||||
|
// 1.4 排序:传入则需非负(req.Sort为int,转int64适配模型)
|
||||||
|
if req.Sort < 0 {
|
||||||
|
return nil, errors.New("排序值不能为负数")
|
||||||
|
}
|
||||||
|
// 1.5 头衔/头像URL长度限制
|
||||||
|
if len(req.Title) > 200 {
|
||||||
|
return nil, errors.New("嘉宾头衔长度不能超过200字")
|
||||||
|
}
|
||||||
|
if len(req.Avatar) > 512 {
|
||||||
|
return nil, errors.New("头像URL长度不能超过512字符")
|
||||||
|
}
|
||||||
|
|
||||||
return
|
// 2. 校验嘉宾是否存在(未被软删除)
|
||||||
|
existingSpeaker, err := l.model.FindOne(l.ctx, req.Id)
|
||||||
|
if err != nil {
|
||||||
|
if err == model.ErrNotFound {
|
||||||
|
return nil, errors.New("嘉宾不存在或已被删除,无法更新")
|
||||||
|
}
|
||||||
|
l.Logger.Errorf("查询嘉宾失败(ID: %d):%v", req.Id, err)
|
||||||
|
return nil, errors.New("更新嘉宾失败,请重试")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 构造更新数据(仅更新用户明确传入的有效字段,对齐模型字段类型)
|
||||||
|
updateData := &model.MeetingSpeaker{
|
||||||
|
Id: req.Id,
|
||||||
|
MeetingId: existingSpeaker.MeetingId,
|
||||||
|
Name: existingSpeaker.Name,
|
||||||
|
Title: existingSpeaker.Title,
|
||||||
|
Avatar: existingSpeaker.Avatar,
|
||||||
|
Sort: existingSpeaker.Sort, // 模型中为int64
|
||||||
|
Intro: existingSpeaker.Intro, // 模型中为sql.NullString
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4.1 覆盖用户主动更新的字段(非默认值即视为更新)
|
||||||
|
if req.Name != "" { // 非空表示主动更新姓名(已通过非空校验)
|
||||||
|
updateData.Name = req.Name
|
||||||
|
}
|
||||||
|
if req.Title != "" { // 非空表示主动更新头衔
|
||||||
|
updateData.Title = req.Title
|
||||||
|
}
|
||||||
|
if req.Avatar != "" { // 非空表示主动更新头像URL
|
||||||
|
updateData.Avatar = req.Avatar
|
||||||
|
}
|
||||||
|
if req.Sort != 0 { // 非0表示主动更新排序(int转int64适配模型)
|
||||||
|
updateData.Sort = int64(req.Sort)
|
||||||
|
}
|
||||||
|
// 4.2 处理Intro(sql.NullString类型):与原始值不同则更新(含主动传空字符串)
|
||||||
|
if req.Intro != existingSpeaker.Intro.String {
|
||||||
|
updateData.Intro = sql.NullString{
|
||||||
|
String: req.Intro,
|
||||||
|
Valid: true, // 主动传入即标记为有效(空字符串也视为有效数据)
|
||||||
|
}
|
||||||
|
// 若业务需将空字符串存为数据库NULL,可改为:
|
||||||
|
// updateData.Intro.Valid = req.Intro != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 执行更新操作(调用模型层Update方法,字段顺序完全匹配)
|
||||||
|
err = l.model.Update(l.ctx, updateData)
|
||||||
|
if err != nil {
|
||||||
|
l.Logger.Errorf("更新嘉宾失败(ID: %d):%v", req.Id, err)
|
||||||
|
return nil, errors.New("更新嘉宾失败,请重试")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 构造响应
|
||||||
|
return &types.UpdateSpeakerResp{
|
||||||
|
Msg: "嘉宾信息更新成功",
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ type GetSpeakerResp struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ListSpeakersByMeetingReq struct {
|
type ListSpeakersByMeetingReq struct {
|
||||||
MeetingId int64 `path:"meetingId" validate:"required,min=1"` // 会议ID(从路径参数获取,必填)
|
MeetingId int64 `json:"meetingId" validate:"required,min=1"` // 会议ID(从路径参数获取,必填)
|
||||||
Page int `query:"page" validate:"min=1"` // 页码(默认1)
|
Page int `json:"page" validate:"min=1"` // 页码(默认1)
|
||||||
PageSize int `query:"page_size" validate:"min=1,max=100"` // 每页条数(默认10,最大100)
|
PageSize int `json:"page_size" validate:"min=1,max=100"` // 每页条数(默认10,最大100)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListSpeakersByMeetingResp struct {
|
type ListSpeakersByMeetingResp struct {
|
||||||
@@ -58,13 +58,12 @@ type SpeakerDetail struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UpdateSpeakerReq struct {
|
type UpdateSpeakerReq struct {
|
||||||
Id int64 `json:"id" validate:"required,min=1"` // 嘉宾ID(必填,定位要更新的记录)
|
Id int64 `json:"id" validate:"required,min=1"` // 嘉宾ID(必填,定位要更新的记录)
|
||||||
MeetingId int64 `json:"meeting_id,omitempty" validate:"min=1"` // 关联会议ID(可选,不填则不更新)
|
Name string `json:"name,omitempty" validate:"min=1,max=100"` // 嘉宾姓名(可选,更新时需非空)
|
||||||
Name string `json:"name,omitempty" validate:"min=1,max=100"` // 嘉宾姓名(可选,更新时需非空)
|
Title string `json:"title,omitempty" validate:"max=200"` // 嘉宾头衔(可选)
|
||||||
Title string `json:"title,omitempty" validate:"max=200"` // 嘉宾头衔(可选)
|
Avatar string `json:"avatar,omitempty" validate:"max=512"` // 头像URL(可选)
|
||||||
Avatar string `json:"avatar,omitempty" validate:"max=512"` // 头像URL(可选)
|
Intro string `json:"intro,omitempty"` // 嘉宾简介(可选)
|
||||||
Intro string `json:"intro,omitempty"` // 嘉宾简介(可选)
|
Sort int `json:"sort,omitempty" validate:"min=0"` // 排序(可选)
|
||||||
Sort int `json:"sort,omitempty" validate:"min=0"` // 排序(可选)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateSpeakerResp struct {
|
type UpdateSpeakerResp struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user