完成会议管理后端
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package meeting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/logic/meeting"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/types"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func CreateMeetingHandler(cfg *config.Config) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.CreateMeetingReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
return
|
||||
}
|
||||
|
||||
mysqlCfg := cfg.MySQL
|
||||
dsn := fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=true&loc=Local",
|
||||
mysqlCfg.Username,
|
||||
mysqlCfg.Password,
|
||||
mysqlCfg.Host,
|
||||
mysqlCfg.Port,
|
||||
mysqlCfg.Database,
|
||||
mysqlCfg.Charset,
|
||||
)
|
||||
fmt.Println("接收到articlePost请求")
|
||||
|
||||
conn := sqlx.NewSqlConn("mysql", dsn)
|
||||
|
||||
meetingModel := model.NewMeetingModel(conn)
|
||||
|
||||
l := meeting.NewCreateMeetingLogic(r.Context(), cfg, meetingModel)
|
||||
resp, err := l.CreateMeeting(&req)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package meeting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/logic/meeting"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/types"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func DeleteMeetingHandler(cfg *config.Config) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.DeleteMeetingReq
|
||||
pathParts := strings.Split(r.URL.Path, "/")
|
||||
if len(pathParts) < 3 { // 确保路径格式正确
|
||||
httpx.ErrorCtx(r.Context(), w, fmt.Errorf("invalid path format"))
|
||||
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
|
||||
dsn := fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=true&loc=Local",
|
||||
mysqlCfg.Username,
|
||||
mysqlCfg.Password,
|
||||
mysqlCfg.Host,
|
||||
mysqlCfg.Port,
|
||||
mysqlCfg.Database,
|
||||
mysqlCfg.Charset,
|
||||
)
|
||||
fmt.Println("接收到articlePost请求")
|
||||
|
||||
conn := sqlx.NewSqlConn("mysql", dsn)
|
||||
|
||||
meetingModel := model.NewMeetingModel(conn)
|
||||
|
||||
l := meeting.NewDeleteMeetingLogic(r.Context(), cfg, meetingModel)
|
||||
resp, err := l.DeleteMeeting(&req)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
61
server/internal/meeting/handler/meeting/getmeetinghandler.go
Normal file
61
server/internal/meeting/handler/meeting/getmeetinghandler.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package meeting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/logic/meeting"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/types"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func GetMeetingHandler(cfg *config.Config) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.GetMeetingReq
|
||||
// 正确解析路径(例如:/meetings/1)
|
||||
pathParts := strings.Split(r.URL.Path, "/")
|
||||
if len(pathParts) < 3 { // 确保路径格式正确
|
||||
httpx.ErrorCtx(r.Context(), w, fmt.Errorf("invalid path format"))
|
||||
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
|
||||
dsn := fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=true&loc=Local",
|
||||
mysqlCfg.Username,
|
||||
mysqlCfg.Password,
|
||||
mysqlCfg.Host,
|
||||
mysqlCfg.Port,
|
||||
mysqlCfg.Database,
|
||||
mysqlCfg.Charset,
|
||||
)
|
||||
fmt.Println("接收到articlePost请求")
|
||||
|
||||
conn := sqlx.NewSqlConn("mysql", dsn)
|
||||
|
||||
meetingModel := model.NewMeetingModel(conn)
|
||||
|
||||
l := meeting.NewGetMeetingLogic(r.Context(), cfg, meetingModel)
|
||||
resp, err := l.GetMeeting(&req)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package meeting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/logic/meeting"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/types"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func ListMeetingHandler(cfg *config.Config) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ListMeetingReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
return
|
||||
}
|
||||
|
||||
mysqlCfg := cfg.MySQL
|
||||
dsn := fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=true&loc=Local",
|
||||
mysqlCfg.Username,
|
||||
mysqlCfg.Password,
|
||||
mysqlCfg.Host,
|
||||
mysqlCfg.Port,
|
||||
mysqlCfg.Database,
|
||||
mysqlCfg.Charset,
|
||||
)
|
||||
fmt.Println("接收到articlePost请求")
|
||||
|
||||
conn := sqlx.NewSqlConn("mysql", dsn)
|
||||
|
||||
meetingModel := model.NewMeetingModel(conn)
|
||||
|
||||
l := meeting.NewListMeetingLogic(r.Context(), cfg, meetingModel)
|
||||
resp, err := l.ListMeeting(&req)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package meeting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/logic/meeting"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/types"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func UpdateMeetingHandler(cfg *config.Config) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.UpdateMeetingReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
return
|
||||
}
|
||||
|
||||
mysqlCfg := cfg.MySQL
|
||||
dsn := fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=true&loc=Local",
|
||||
mysqlCfg.Username,
|
||||
mysqlCfg.Password,
|
||||
mysqlCfg.Host,
|
||||
mysqlCfg.Port,
|
||||
mysqlCfg.Database,
|
||||
mysqlCfg.Charset,
|
||||
)
|
||||
fmt.Println("接收到articlePost请求")
|
||||
|
||||
conn := sqlx.NewSqlConn("mysql", dsn)
|
||||
|
||||
meetingModel := model.NewMeetingModel(conn)
|
||||
|
||||
l := meeting.NewUpdateMeetingLogic(r.Context(), cfg, meetingModel)
|
||||
resp, err := l.UpdateMeeting(&req)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package meeting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type CreateMeetingLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
cfg *config.Config
|
||||
model model.MeetingModel
|
||||
}
|
||||
|
||||
func NewCreateMeetingLogic(ctx context.Context, cfg *config.Config, model model.MeetingModel) *CreateMeetingLogic {
|
||||
return &CreateMeetingLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
model: model,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *CreateMeetingLogic) CreateMeeting(req *types.CreateMeetingReq) (resp *types.CreateMeetingResp, err error) {
|
||||
// 1. 业务校验:验证时间格式及合理性
|
||||
// 1.1 解析开始时间(前端传入格式应为 "2006-01-02 15:04:05")
|
||||
startTime, err := time.Parse("2006-01-02 15:04:05", req.StartTime)
|
||||
if err != nil {
|
||||
return nil, errors.New("开始时间格式错误,请使用YYYY-MM-DD HH:MM:SS")
|
||||
}
|
||||
|
||||
// 1.2 解析结束时间
|
||||
endTime, err := time.Parse("2006-01-02 15:04:05", req.EndTime)
|
||||
if err != nil {
|
||||
return nil, errors.New("结束时间格式错误,请使用YYYY-MM-DD HH:MM:SS")
|
||||
}
|
||||
|
||||
// 1.3 校验结束时间不能早于开始时间
|
||||
if endTime.Before(startTime) {
|
||||
return nil, errors.New("结束时间不能早于开始时间")
|
||||
}
|
||||
|
||||
meeting := &model.Meeting{
|
||||
Theme: req.Theme, // 非空字段,直接赋值
|
||||
Subtitle: req.Subtitle, // 可空字段,空字符串会被数据库处理为 NULL(如果表允许)
|
||||
Intro: sql.NullString{
|
||||
String: req.Intro, // 赋值实际字符串
|
||||
Valid: req.Intro != "", // 若不为空字符串,则设为有效(存实际值);若为空,则设为无效(存 NULL)
|
||||
},
|
||||
CoverUrl: req.CoverUrl,
|
||||
ScheduleImageUrl: req.ScheduleImageUrl,
|
||||
StartTime: startTime,
|
||||
EndTime: endTime,
|
||||
IsDelete: 0, // 软删除默认未删除
|
||||
}
|
||||
|
||||
// 3. 调用model插入数据库
|
||||
result, err := l.model.Insert(l.ctx, meeting)
|
||||
if err != nil {
|
||||
l.Logger.Errorf("创建会议失败:%v", err)
|
||||
return nil, errors.New("创建会议失败,请重试")
|
||||
}
|
||||
|
||||
// 4. 获取新增会议的ID(通过LastInsertId())
|
||||
meetingId, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
l.Logger.Errorf("获取会议ID失败:%v", err)
|
||||
return nil, errors.New("创建会议成功,但获取ID失败")
|
||||
}
|
||||
|
||||
// 5. 构造响应
|
||||
return &types.CreateMeetingResp{
|
||||
Msg: "会议创建成功",
|
||||
MeetingId: meetingId, // 返回新增会议的主键ID
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package meeting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type DeleteMeetingLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
cfg *config.Config
|
||||
model model.MeetingModel
|
||||
}
|
||||
|
||||
func NewDeleteMeetingLogic(ctx context.Context, cfg *config.Config, model model.MeetingModel) *DeleteMeetingLogic {
|
||||
return &DeleteMeetingLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
model: model,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *DeleteMeetingLogic) DeleteMeeting(req *types.DeleteMeetingReq) (resp *types.DeleteMeetingResp, err error) {
|
||||
// 1. 校验会议ID有效性
|
||||
if req.Id <= 0 {
|
||||
return nil, errors.New("会议ID无效,请传入正数ID")
|
||||
}
|
||||
|
||||
// 2. 检查会议是否存在(通过FindOne查询,处理返回值)
|
||||
meeting, 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("删除失败,请重试")
|
||||
}
|
||||
// 若查询到会议(meeting不为空),继续执行删除
|
||||
if meeting == nil {
|
||||
return nil, errors.New("会议不存在,无法删除")
|
||||
}
|
||||
|
||||
// 3. 执行软删除(更新 is_delete 字段为 1)
|
||||
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. 二次确认删除结果(查询 is_delete 是否为 1)
|
||||
meeting, err = l.model.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
if err == model.ErrNotFound {
|
||||
// 理论上软删除后记录仍存在,若返回 ErrNotFound 说明异常
|
||||
return nil, errors.New("删除状态异常,请检查数据")
|
||||
}
|
||||
l.Logger.Errorf("确认删除结果失败(ID: %d):%v", req.Id, err)
|
||||
return nil, errors.New("删除状态确认失败,请稍后检查")
|
||||
}
|
||||
if meeting.IsDelete != 1 {
|
||||
return nil, errors.New("删除未生效,请稍后重试")
|
||||
}
|
||||
|
||||
// 5. 返回删除成功响应
|
||||
return &types.DeleteMeetingResp{
|
||||
Msg: "会议已标记为删除",
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package meeting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetMeetingLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
cfg *config.Config
|
||||
model model.MeetingModel
|
||||
}
|
||||
|
||||
func NewGetMeetingLogic(ctx context.Context, cfg *config.Config, model model.MeetingModel) *GetMeetingLogic {
|
||||
return &GetMeetingLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
model: model,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetMeetingLogic) GetMeeting(req *types.GetMeetingReq) (resp *types.GetMeetingResp, err error) {
|
||||
// 1. 校验会议ID有效性
|
||||
if req.Id <= 0 {
|
||||
return nil, errors.New("会议ID无效,请传入正数ID")
|
||||
}
|
||||
|
||||
// 2. 调用模型层查询会议详情
|
||||
meeting, 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. 转换模型数据为响应格式(处理时间字段和特殊类型)
|
||||
meetingDetail := &types.MeetingDetail{
|
||||
Id: meeting.Id,
|
||||
Theme: meeting.Theme,
|
||||
Subtitle: meeting.Subtitle,
|
||||
// 处理可能为 sql.NullString 类型的字段(如 Intro)
|
||||
Intro: getNullStringValue(meeting.Intro), // 封装工具函数处理
|
||||
CoverUrl: meeting.CoverUrl,
|
||||
ScheduleImageUrl: meeting.ScheduleImageUrl,
|
||||
// 时间字段转换为字符串(格式:YYYY-MM-DD HH:MM:SS)
|
||||
StartTime: meeting.StartTime.Format("2006-01-02 15:04:05"),
|
||||
EndTime: meeting.EndTime.Format("2006-01-02 15:04:05"),
|
||||
CreateTime: meeting.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: meeting.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
Is_Deleted: meeting.IsDelete, // 返回软删除状态(可选,根据业务需求)
|
||||
}
|
||||
|
||||
// 4. 构造响应
|
||||
return &types.GetMeetingResp{
|
||||
Msg: "查询成功",
|
||||
Meeting: meetingDetail,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 工具函数:处理 sql.NullString 类型,返回字符串(空值时返回空字符串)
|
||||
func getNullStringValue(nullStr sql.NullString) string {
|
||||
if nullStr.Valid {
|
||||
return nullStr.String
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package meeting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type ListMeetingLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
cfg *config.Config
|
||||
model model.MeetingModel
|
||||
}
|
||||
|
||||
func NewListMeetingLogic(ctx context.Context, cfg *config.Config, model model.MeetingModel) *ListMeetingLogic {
|
||||
return &ListMeetingLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
model: model,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ListMeetingLogic) ListMeeting(req *types.ListMeetingReq) (resp *types.ListMeetingResp, err error) {
|
||||
// 1. 处理分页参数(设置默认值和限制范围)
|
||||
page := req.Page
|
||||
if page <= 0 {
|
||||
page = 1 // 默认第一页
|
||||
}
|
||||
pageSize := req.PageSize
|
||||
if pageSize <= 0 || pageSize > 100 {
|
||||
pageSize = 10 // 默认10条/页,最大不超过100条
|
||||
}
|
||||
|
||||
// 2. 调用模型层分页查询会议(只返回未删除的)
|
||||
meetings, total, err := l.model.FindPage(l.ctx, page, pageSize)
|
||||
if err != nil {
|
||||
l.Logger.Errorf("分页查询会议列表失败(page: %d, pageSize: %d):%v", page, pageSize, err)
|
||||
return nil, errors.New("查询会议列表失败,请重试")
|
||||
}
|
||||
|
||||
// 3. 转换模型数据为响应格式(批量处理)
|
||||
var meetingDetails []*types.MeetingDetail
|
||||
for _, meeting := range meetings {
|
||||
meetingDetails = append(meetingDetails, &types.MeetingDetail{
|
||||
Id: meeting.Id,
|
||||
Theme: meeting.Theme,
|
||||
Subtitle: meeting.Subtitle,
|
||||
// 处理 sql.NullString 类型(如 Intro)
|
||||
Intro: getNullStringValue(meeting.Intro),
|
||||
CoverUrl: meeting.CoverUrl,
|
||||
ScheduleImageUrl: meeting.ScheduleImageUrl,
|
||||
// 时间格式化
|
||||
StartTime: meeting.StartTime.Format("2006-01-02 15:04:05"),
|
||||
EndTime: meeting.EndTime.Format("2006-01-02 15:04:05"),
|
||||
CreateTime: meeting.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: meeting.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
// 4. 构造响应(包含总条数和当前页数据)
|
||||
return &types.ListMeetingResp{
|
||||
Msg: "查询成功",
|
||||
Total: total, // 总条数(用于前端计算总页数)
|
||||
Meetings: meetingDetails, // 当前页会议列表
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package meeting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/meeting/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type UpdateMeetingLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
cfg *config.Config
|
||||
model model.MeetingModel
|
||||
}
|
||||
|
||||
func NewUpdateMeetingLogic(ctx context.Context, cfg *config.Config, model model.MeetingModel) *UpdateMeetingLogic {
|
||||
return &UpdateMeetingLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
model: model,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *UpdateMeetingLogic) UpdateMeeting(req *types.UpdateMeetingReq) (resp *types.UpdateMeetingResp, err error) {
|
||||
// 1. 校验会议ID有效性
|
||||
if req.Id <= 0 {
|
||||
return nil, errors.New("会议ID无效,请传入正数ID")
|
||||
}
|
||||
|
||||
// 2. 查询当前会议信息(确认会议存在,且获取原始数据用于补全未更新字段)
|
||||
existingMeeting, 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. 处理时间字段(若请求提供了时间,则解析并校验;否则沿用原时间)
|
||||
var startTime, endTime time.Time
|
||||
var errTime error
|
||||
|
||||
// 3.1 处理开始时间
|
||||
if req.StartTime != "" {
|
||||
startTime, errTime = time.Parse("2006-01-02 15:04:05", req.StartTime)
|
||||
if errTime != nil {
|
||||
return nil, errors.New("开始时间格式错误,请使用YYYY-MM-DD HH:MM:SS")
|
||||
}
|
||||
} else {
|
||||
startTime = existingMeeting.StartTime // 沿用原时间
|
||||
}
|
||||
|
||||
// 3.2 处理结束时间
|
||||
if req.EndTime != "" {
|
||||
endTime, errTime = time.Parse("2006-01-02 15:04:05", req.EndTime)
|
||||
if errTime != nil {
|
||||
return nil, errors.New("结束时间格式错误,请使用YYYY-MM-DD HH:MM:SS")
|
||||
}
|
||||
} else {
|
||||
endTime = existingMeeting.EndTime // 沿用原时间
|
||||
}
|
||||
|
||||
// 3.3 校验时间逻辑(若更新了时间,需确保结束时间不早于开始时间)
|
||||
if endTime.Before(startTime) {
|
||||
return nil, errors.New("结束时间不能早于开始时间")
|
||||
}
|
||||
|
||||
// 4. 构造更新数据(只更新请求中提供的非空字段,其他沿用原始值)
|
||||
updateData := &model.Meeting{
|
||||
Id: req.Id, // 必须传入ID,用于WHERE条件定位记录
|
||||
Theme: req.Theme,
|
||||
Subtitle: req.Subtitle,
|
||||
// 处理Intro(若模型中是sql.NullString类型)
|
||||
Intro: sql.NullString{String: req.Intro, Valid: req.Intro != ""},
|
||||
CoverUrl: req.CoverUrl,
|
||||
ScheduleImageUrl: req.ScheduleImageUrl,
|
||||
StartTime: startTime,
|
||||
EndTime: endTime,
|
||||
IsDelete: existingMeeting.IsDelete, // 软删除状态不允许通过此接口更新
|
||||
// CreateTime不更新(由数据库首次创建时生成)
|
||||
// UpdateTime由数据库自动更新(表结构中已配置ON UPDATE CURRENT_TIMESTAMP)
|
||||
}
|
||||
|
||||
// 5. 特殊处理:若请求中某字段为空字符串,是否需要保留原始值?
|
||||
// (根据业务需求调整,这里以“空字符串视为主动清空”为例,若需“不填则保留原值”需额外判断)
|
||||
if req.Theme == "" {
|
||||
updateData.Theme = existingMeeting.Theme // 若Theme为空,沿用原始值(避免清空必填字段)
|
||||
}
|
||||
// 其他字段(如Subtitle/CoverUrl等允许为空的字段,空字符串视为清空,无需特殊处理)
|
||||
|
||||
// 6. 执行更新操作
|
||||
err = l.model.Update(l.ctx, updateData)
|
||||
if err != nil {
|
||||
l.Logger.Errorf("更新会议失败(ID: %d):%v", req.Id, err)
|
||||
return nil, errors.New("更新失败,请重试")
|
||||
}
|
||||
|
||||
// 7. 构造响应
|
||||
return &types.UpdateMeetingResp{
|
||||
Msg: "会议更新成功",
|
||||
}, nil
|
||||
}
|
||||
31
server/internal/meeting/internal/model/meetingmodel.go
Normal file
31
server/internal/meeting/internal/model/meetingmodel.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
var _ MeetingModel = (*customMeetingModel)(nil)
|
||||
|
||||
type (
|
||||
// MeetingModel is an interface to be customized, add more methods here,
|
||||
// and implement the added methods in customMeetingModel.
|
||||
MeetingModel interface {
|
||||
meetingModel
|
||||
withSession(session sqlx.Session) MeetingModel
|
||||
}
|
||||
|
||||
customMeetingModel struct {
|
||||
*defaultMeetingModel
|
||||
}
|
||||
)
|
||||
|
||||
// NewMeetingModel returns a model for the database table.
|
||||
func NewMeetingModel(conn sqlx.SqlConn) MeetingModel {
|
||||
return &customMeetingModel{
|
||||
defaultMeetingModel: newMeetingModel(conn),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *customMeetingModel) withSession(session sqlx.Session) MeetingModel {
|
||||
return NewMeetingModel(sqlx.NewSqlConnFromSession(session))
|
||||
}
|
||||
123
server/internal/meeting/internal/model/meetingmodel_gen.go
Normal file
123
server/internal/meeting/internal/model/meetingmodel_gen.go
Normal file
@@ -0,0 +1,123 @@
|
||||
// Code generated by goctl. DO NOT EDIT.
|
||||
// versions:
|
||||
// goctl version: 1.9.2
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/stores/builder"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/core/stringx"
|
||||
)
|
||||
|
||||
var (
|
||||
meetingFieldNames = builder.RawFieldNames(&Meeting{})
|
||||
meetingRows = strings.Join(meetingFieldNames, ",")
|
||||
meetingRowsExpectAutoSet = strings.Join(stringx.Remove(meetingFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",")
|
||||
meetingRowsWithPlaceHolder = strings.Join(stringx.Remove(meetingFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?"
|
||||
)
|
||||
|
||||
type (
|
||||
meetingModel interface {
|
||||
Insert(ctx context.Context, data *Meeting) (sql.Result, error)
|
||||
FindOne(ctx context.Context, id int64) (*Meeting, error)
|
||||
Update(ctx context.Context, data *Meeting) error
|
||||
Delete(ctx context.Context, id int64) error
|
||||
FindPage(ctx context.Context, page, pageSize int) ([]*Meeting, int64, error)
|
||||
SoftDelete(ctx context.Context, id int64) error
|
||||
}
|
||||
|
||||
defaultMeetingModel struct {
|
||||
conn sqlx.SqlConn
|
||||
table string
|
||||
}
|
||||
|
||||
Meeting struct {
|
||||
Id int64 `db:"id"` // 会议ID(主键)
|
||||
Theme string `db:"theme"` // 会议主题
|
||||
Subtitle string `db:"subtitle"` // 会议副标题(允许为空)
|
||||
Intro sql.NullString `db:"intro"` // 会议简介(支持长文本,可存Markdown)
|
||||
CoverUrl string `db:"cover_url"` // 会议封面图片URL(允许为空)
|
||||
ScheduleImageUrl string `db:"schedule_image_url"` // 会议日程图片URL(允许为空,无日程图时存空字符串)
|
||||
StartTime time.Time `db:"start_time"` // 会议开始时间
|
||||
EndTime time.Time `db:"end_time"` // 会议结束时间
|
||||
CreateTime time.Time `db:"create_time"` // 创建时间
|
||||
UpdateTime time.Time `db:"update_time"` // 更新时间
|
||||
IsDelete int64 `db:"is_delete"` // 软删除(0-未删,1-已删)
|
||||
}
|
||||
)
|
||||
|
||||
func newMeetingModel(conn sqlx.SqlConn) *defaultMeetingModel {
|
||||
return &defaultMeetingModel{
|
||||
conn: conn,
|
||||
table: "`meeting`",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultMeetingModel) Delete(ctx context.Context, id int64) error {
|
||||
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
|
||||
_, err := m.conn.ExecCtx(ctx, query, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultMeetingModel) FindOne(ctx context.Context, id int64) (*Meeting, error) {
|
||||
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", meetingRows, m.table)
|
||||
var resp Meeting
|
||||
err := m.conn.QueryRowCtx(ctx, &resp, query, id)
|
||||
switch err {
|
||||
case nil:
|
||||
return &resp, nil
|
||||
case sqlx.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultMeetingModel) Insert(ctx context.Context, data *Meeting) (sql.Result, error) {
|
||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?)", m.table, meetingRowsExpectAutoSet)
|
||||
ret, err := m.conn.ExecCtx(ctx, query, data.Theme, data.Subtitle, data.Intro, data.CoverUrl, data.ScheduleImageUrl, data.StartTime, data.EndTime, data.IsDelete)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (m *defaultMeetingModel) Update(ctx context.Context, data *Meeting) error {
|
||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, meetingRowsWithPlaceHolder)
|
||||
_, err := m.conn.ExecCtx(ctx, query, data.Theme, data.Subtitle, data.Intro, data.CoverUrl, data.ScheduleImageUrl, data.StartTime, data.EndTime, data.IsDelete, data.Id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultMeetingModel) FindPage(ctx context.Context, page, pageSize int) ([]*Meeting, int64, error) {
|
||||
// 计算偏移量(分页公式:offset = (page-1) * pageSize)
|
||||
offset := (page - 1) * pageSize
|
||||
// 1. 查询当前页数据(过滤软删除,按创建时间倒序,最新的在前)
|
||||
query := fmt.Sprintf("select %s from %s where is_delete = 0 order by create_time desc limit ?, ?", meetingRows, m.table)
|
||||
var meetings []*Meeting
|
||||
err := m.conn.QueryRowsCtx(ctx, &meetings, query, offset, pageSize)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
// 2. 查询总条数(用于计算总页数)
|
||||
countQuery := fmt.Sprintf("select count(1) from %s where is_delete = 0", m.table)
|
||||
var total int64
|
||||
err = m.conn.QueryRowCtx(ctx, &total, countQuery)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return meetings, total, nil
|
||||
}
|
||||
|
||||
func (m *defaultMeetingModel) SoftDelete(ctx context.Context, id int64) error {
|
||||
query := fmt.Sprintf("update %s set `is_delete` = 1 where `id` = ?", m.table)
|
||||
_, err := m.conn.ExecCtx(ctx, query, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultMeetingModel) tableName() string {
|
||||
return m.table
|
||||
}
|
||||
5
server/internal/meeting/internal/model/vars.go
Normal file
5
server/internal/meeting/internal/model/vars.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package model
|
||||
|
||||
import "github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
|
||||
var ErrNotFound = sqlx.ErrNotFound
|
||||
76
server/internal/meeting/internal/types/types.go
Normal file
76
server/internal/meeting/internal/types/types.go
Normal file
@@ -0,0 +1,76 @@
|
||||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl 1.9.2
|
||||
|
||||
package types
|
||||
|
||||
type CreateMeetingReq struct {
|
||||
Theme string `json:"theme" validate:"required"` // 会议主题(必填)
|
||||
Subtitle string `json:"subtitle,omitempty"` // 副标题(可选)
|
||||
Intro string `json:"intro,omitempty"` // 简介(可选)
|
||||
CoverUrl string `json:"cover_url,omitempty"` // 封面图URL(可选)
|
||||
ScheduleImageUrl string `json:"schedule_image_url,omitempty"` // 日程图URL(可选)
|
||||
StartTime string `json:"start_time" validate:"required"` // 开始时间(必填,格式同上)
|
||||
EndTime string `json:"end_time" validate:"required"` // 结束时间(必填)
|
||||
}
|
||||
|
||||
type CreateMeetingResp struct {
|
||||
Msg string `json:"message"` // 操作提示(如:"创建成功")
|
||||
MeetingId int64 `json:"meeting_id"` // 新增会议的ID(创建成功返回)
|
||||
}
|
||||
|
||||
type DeleteMeetingReq struct {
|
||||
Id int64 `path:"id" validate:"required"` // 会议ID(从路径参数获取,必填)
|
||||
}
|
||||
|
||||
type DeleteMeetingResp struct {
|
||||
Msg string `json:"message"` // 操作提示(如:"删除成功")
|
||||
}
|
||||
|
||||
type GetMeetingReq struct {
|
||||
Id int64 `path:"id" validate:"required"`
|
||||
}
|
||||
|
||||
type GetMeetingResp struct {
|
||||
Msg string `json:"message"` // 操作提示
|
||||
Meeting *MeetingDetail `json:"meeting"` // 会议详情(查询成功返回)
|
||||
}
|
||||
|
||||
type ListMeetingReq struct {
|
||||
Page int `json:"page" query:"page" validate:"min=1"` // 页码(默认1)
|
||||
PageSize int `json:"page_size" query:"page_size" validate:"min=1,max=100"` // 每页条数(默认10,最大100)
|
||||
}
|
||||
|
||||
type ListMeetingResp struct {
|
||||
Msg string `json:"message"` // 操作提示
|
||||
Total int64 `json:"total"` // 总条数
|
||||
Meetings []*MeetingDetail `json:"meetings"` // 会议列表(当前页数据)
|
||||
}
|
||||
|
||||
type MeetingDetail struct {
|
||||
Id int64 `json:"id"` // 会议ID(主键)
|
||||
Theme string `json:"theme"` // 会议主题
|
||||
Subtitle string `json:"subtitle"` // 会议副标题
|
||||
Intro string `json:"intro"` // 会议简介(Markdown)
|
||||
CoverUrl string `json:"cover_url"` // 封面图URL
|
||||
ScheduleImageUrl string `json:"schedule_image_url"` // 日程图URL
|
||||
StartTime string `json:"start_time"` // 开始时间(格式:YYYY-MM-DD HH:MM:SS)
|
||||
EndTime string `json:"end_time"` // 结束时间(格式:YYYY-MM-DD HH:MM:SS)
|
||||
CreateTime string `json:"create_time"` // 创建时间(数据库自动生成)
|
||||
UpdateTime string `json:"update_time"` // 更新时间(数据库自动生成)
|
||||
Is_Deleted int64 `json:"is_delete"`
|
||||
}
|
||||
|
||||
type UpdateMeetingReq struct {
|
||||
Id int64 `json:"id" validate:"required"` // 会议ID(必填,用于定位要更新的记录)
|
||||
Theme string `json:"theme,omitempty"` // 会议主题(可选,不填则不更新)
|
||||
Subtitle string `json:"subtitle,omitempty"` // 副标题(可选)
|
||||
Intro string `json:"intro,omitempty"` // 简介(可选)
|
||||
CoverUrl string `json:"cover_url,omitempty"` // 封面图URL(可选)
|
||||
ScheduleImageUrl string `json:"schedule_image_url,omitempty"` // 日程图URL(可选)
|
||||
StartTime string `json:"start_time,omitempty"` // 开始时间(可选)
|
||||
EndTime string `json:"end_time,omitempty"` // 结束时间(可选)
|
||||
}
|
||||
|
||||
type UpdateMeetingResp struct {
|
||||
Msg string `json:"message"` // 操作提示(如:"更新成功")
|
||||
}
|
||||
Reference in New Issue
Block a user