完成会议管理后端

This commit is contained in:
2025-10-28 15:57:36 +08:00
parent 7975586b60
commit 2a8637ffb0
14 changed files with 945 additions and 0 deletions

View File

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

View File

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

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

View File

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

View File

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

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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 ""
}

View File

@@ -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
}

View File

@@ -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
}

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

View 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
}

View File

@@ -0,0 +1,5 @@
package model
import "github.com/zeromicro/go-zero/core/stores/sqlx"
var ErrNotFound = sqlx.ErrNotFound

View 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"` // 操作提示(如:"更新成功"
}