添加course的业务层和实现层

This commit is contained in:
2025-10-31 13:26:49 +08:00
parent d14a460557
commit bb7df7e7b3
28 changed files with 1486 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.9.2
package course
import (
"fmt"
"net/http"
"github.com/JACKYMYPERSON/hldrCenter/config"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/logic/course"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/rest/httpx"
)
func CreateCourseHandler(cfg *config.Config) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.CreateCourseReq
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)
baseModel := model.NewCourseModel(conn)
l := course.NewCreateCourseLogic(r.Context(), cfg, baseModel)
resp, err := l.CreateCourse(&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 course
import (
"fmt"
"net/http"
"strconv"
"strings"
"github.com/JACKYMYPERSON/hldrCenter/config"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/logic/course"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/rest/httpx"
)
func DeleteCourseHandler(cfg *config.Config) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.DeleteCourseReq
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
}
fmt.Println("idStr:", idStr)
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)
baseModel := model.NewCourseModel(conn)
l := course.NewDeleteCourseLogic(r.Context(), cfg, baseModel)
resp, err := l.DeleteCourse(&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 course
import (
"fmt"
"net/http"
"strconv"
"strings"
"github.com/JACKYMYPERSON/hldrCenter/config"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/logic/course"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/rest/httpx"
)
func GetCourseHandler(cfg *config.Config) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.GetCourseReq
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
}
fmt.Println("idStr:", idStr)
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)
baseModel := model.NewCourseModel(conn)
l := course.NewGetCourseLogic(r.Context(), cfg, baseModel)
resp, err := l.GetCourse(&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 course
import (
"fmt"
"net/http"
"github.com/JACKYMYPERSON/hldrCenter/config"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/logic/course"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/rest/httpx"
)
func ListCourseHandler(cfg *config.Config) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ListCourseReq
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)
baseModel := model.NewCourseModel(conn)
l := course.NewListCourseLogic(r.Context(), cfg, baseModel)
resp, err := l.ListCourse(&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 course
import (
"fmt"
"net/http"
"github.com/JACKYMYPERSON/hldrCenter/config"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/logic/course"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/rest/httpx"
)
func UpdateCourseHandler(cfg *config.Config) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.UpdateCourseReq
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)
baseModel := model.NewCourseModel(conn)
l := course.NewUpdateCourseLogic(r.Context(), cfg, baseModel)
resp, err := l.UpdateCourse(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}

View File

@@ -0,0 +1,94 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.9.2
package course
import (
"context"
"database/sql"
"fmt"
"github.com/JACKYMYPERSON/hldrCenter/config"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
"github.com/go-playground/validator/v10"
"github.com/zeromicro/go-zero/core/logx"
)
type CreateCourseLogic struct {
logx.Logger
ctx context.Context
cfg *config.Config
model model.CourseModel
}
func NewCreateCourseLogic(ctx context.Context, cfg *config.Config, model model.CourseModel) *CreateCourseLogic {
return &CreateCourseLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
cfg: cfg,
model: model,
}
}
func (l *CreateCourseLogic) CreateCourse(req *types.CreateCourseReq) (resp *types.BaseResp, err error) {
// 初始化验证器
validate := validator.New()
// 验证请求参数
if err := validate.Struct(req); err != nil {
// 收集所有验证错误
var errMsg string
for _, e := range err.(validator.ValidationErrors) {
errMsg += fmt.Sprintf("参数 %s 验证失败: %s; ", e.Field(), e.Tag())
}
return &types.BaseResp{
Code: 400, // 非0表示失败
Msg: "参数验证失败: " + errMsg,
}, nil
}
// 构造课程数据对象
course := &model.Course{
Title: req.Title,
Subtitle: req.Subtitle,
CoverUrl: req.CoverUrl,
Intro: stringToNullString(req.Intro),
Status: int64(req.Status),
}
// 调用模型层插入数据
result, err := l.model.Insert(l.ctx, course)
if err != nil {
return &types.BaseResp{
Code: 500, // 非0表示失败
Msg: "创建课程失败: " + err.Error(),
}, nil
}
// 获取插入的课程ID
courseId, err := result.LastInsertId()
if err != nil {
return &types.BaseResp{
Code: 500, // 非0表示失败
Msg: "获取课程ID失败: " + err.Error(),
}, nil
}
// 返回成功响应0表示成功
return &types.BaseResp{
Code: 0,
Msg: fmt.Sprintf("课程创建成功ID: %d", courseId),
}, nil
}
func stringToNullString(s string) sql.NullString {
if s == "" {
return sql.NullString{Valid: false}
}
return sql.NullString{
String: s,
Valid: true,
}
}

View File

@@ -0,0 +1,78 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.9.2
package course
import (
"context"
"fmt"
"github.com/JACKYMYPERSON/hldrCenter/config"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
"github.com/go-playground/validator/v10"
"github.com/zeromicro/go-zero/core/logx"
)
type DeleteCourseLogic struct {
logx.Logger
ctx context.Context
cfg *config.Config
model model.CourseModel
}
func NewDeleteCourseLogic(ctx context.Context, cfg *config.Config, model model.CourseModel) *DeleteCourseLogic {
return &DeleteCourseLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
cfg: cfg,
model: model,
}
}
func (l *DeleteCourseLogic) DeleteCourse(req *types.DeleteCourseReq) (resp *types.BaseResp, err error) {
// 1. 参数验证
validate := validator.New()
if err := validate.Struct(req); err != nil {
var errMsg string
for _, e := range err.(validator.ValidationErrors) {
errMsg += fmt.Sprintf("参数 %s 验证失败: %s; ", e.Field(), e.Tag())
}
return &types.BaseResp{
Code: 400,
Msg: "参数验证失败: " + errMsg,
}, nil
}
// 2. 复用FindOne方法检查课程是否存在
_, err = l.model.FindOne(l.ctx, req.Id)
if err != nil {
if err == model.ErrNotFound { // 注意这里需要匹配你实际的ErrNotFound定义
return &types.BaseResp{
Code: 404,
Msg: fmt.Sprintf("课程ID=%d不存在", req.Id),
}, nil
}
// 其他查询错误
return &types.BaseResp{
Code: 500,
Msg: "查询课程信息失败: " + err.Error(),
}, nil
}
// 3. 执行逻辑删除更新is_delete为1
err = l.model.Delete(l.ctx, req.Id)
if err != nil {
return &types.BaseResp{
Code: 500,
Msg: "删除课程失败: " + err.Error(),
}, nil
}
// 4. 返回成功响应
return &types.BaseResp{
Code: 0,
Msg: fmt.Sprintf("课程ID=%d删除成功", req.Id),
}, nil
}

View File

@@ -0,0 +1,85 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.9.2
package course
import (
"context"
"database/sql"
"fmt"
"time"
"github.com/JACKYMYPERSON/hldrCenter/config"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
"github.com/go-playground/validator/v10"
"github.com/zeromicro/go-zero/core/logx"
)
type GetCourseLogic struct {
logx.Logger
ctx context.Context
cfg *config.Config
model model.CourseModel
}
func NewGetCourseLogic(ctx context.Context, cfg *config.Config, model model.CourseModel) *GetCourseLogic {
return &GetCourseLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
cfg: cfg,
model: model,
}
}
func (l *GetCourseLogic) GetCourse(req *types.GetCourseReq) (resp *types.CourseResp, err error) {
// 1. 参数验证匹配结构体中的validate标签
validate := validator.New()
if err := validate.Struct(req); err != nil {
var errMsg string
for _, e := range err.(validator.ValidationErrors) {
errMsg += fmt.Sprintf("参数 %s 验证失败: %s; ", e.Field(), e.Tag())
}
return nil, fmt.Errorf("参数验证失败: %s", errMsg)
}
// 2. 调用模型层查询课程
course, err := l.model.FindOne(l.ctx, req.Id)
if err != nil {
if err == model.ErrNotFound {
return nil, fmt.Errorf("课程不存在")
}
return nil, fmt.Errorf("查询课程失败: %w", err)
}
// 3. 转换模型数据到响应结构体
resp = &types.CourseResp{
Id: course.Id,
Title: course.Title,
Subtitle: course.Subtitle,
CoverUrl: course.CoverUrl,
Intro: nullStringToString(course.Intro),
Status: int8(course.Status),
CreateTime: formatTime(course.CreateTime),
UpdateTime: formatTime(course.UpdateTime),
}
return resp, nil
}
// 辅助函数将sql.NullString转换为string处理数据库NULL值
func nullStringToString(ns sql.NullString) string {
if ns.Valid {
return ns.String
}
return ""
}
// 辅助函数:格式化时间为字符串(处理可能的零值时间)
func formatTime(t time.Time) string {
if t.IsZero() {
return ""
}
return t.Format("2006-01-02 15:04:05")
}

View File

@@ -0,0 +1,107 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.9.2
package course
import (
"context"
"fmt"
"github.com/JACKYMYPERSON/hldrCenter/config"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type ListCourseLogic struct {
logx.Logger
ctx context.Context
cfg *config.Config
model model.CourseModel
}
func NewListCourseLogic(ctx context.Context, cfg *config.Config, model model.CourseModel) *ListCourseLogic {
return &ListCourseLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
cfg: cfg,
model: model,
}
}
func (l *ListCourseLogic) ListCourse(req *types.ListCourseReq) (resp *types.ListCourseResp, err error) {
// 1. 参数验证与默认值处理
if err := validateListCourseReq(req); err != nil {
return nil, err
}
// 处理分页默认值根据结构体tag的default定义
page := req.Page
size := req.Size
if page <= 0 {
page = 1 // 默认第一页
}
if size <= 0 {
size = 10 // 默认每页10条
}
offset := (page - 1) * size
// 2. 构建查询条件
filter := model.CourseFilter{
Status: req.Status,
Keyword: req.Keyword,
Offset: offset,
Limit: size,
}
// 3. 查询课程列表数据
courses, err := l.model.List(l.ctx, filter)
if err != nil {
return nil, fmt.Errorf("查询课程列表失败: %w", err)
}
// 4. 查询符合条件的总条数
total, err := l.model.Count(l.ctx, filter)
if err != nil {
return nil, fmt.Errorf("查询课程总数失败: %w", err)
}
// 5. 转换数据格式model -> types
var courseList []types.CourseResp
for _, course := range courses {
courseList = append(courseList, types.CourseResp{
Id: course.Id,
Title: course.Title,
Subtitle: course.Subtitle,
CoverUrl: course.CoverUrl,
Intro: nullStringToString(course.Intro), // 包含简介信息
Status: int8(course.Status),
CreateTime: formatTime(course.CreateTime),
UpdateTime: formatTime(course.UpdateTime), // 包含更新时间
})
}
// 6. 组装响应数据
resp = &types.ListCourseResp{
Total: total,
List: courseList,
}
return resp, nil
}
// 参数验证函数
func validateListCourseReq(req *types.ListCourseReq) error {
// 自定义验证规则:页码和每页数量不能为负数
if req.Page < 0 {
return fmt.Errorf("页码不能为负数")
}
if req.Size < 0 {
return fmt.Errorf("每页数量不能为负数")
}
// 状态值验证(根据业务实际允许的状态值调整)
if req.Status < 0 && req.Status != -1 { // 假设-1表示不筛选状态
return fmt.Errorf("无效的状态值")
}
return nil
}

View File

@@ -0,0 +1,89 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.9.2
package course
import (
"context"
"fmt"
"github.com/JACKYMYPERSON/hldrCenter/config"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
"github.com/go-playground/validator/v10"
"github.com/zeromicro/go-zero/core/logx"
)
type UpdateCourseLogic struct {
logx.Logger
ctx context.Context
cfg *config.Config
model model.CourseModel
}
func NewUpdateCourseLogic(ctx context.Context, cfg *config.Config, model model.CourseModel) *UpdateCourseLogic {
return &UpdateCourseLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
cfg: cfg,
model: model,
}
}
func (l *UpdateCourseLogic) UpdateCourse(req *types.UpdateCourseReq) (resp *types.BaseResp, err error) {
// 1. 参数验证
validate := validator.New()
if err := validate.Struct(req); err != nil {
var errMsg string
for _, e := range err.(validator.ValidationErrors) {
errMsg += fmt.Sprintf("参数 %s 验证失败: %s; ", e.Field(), e.Tag())
}
return &types.BaseResp{
Code: 400,
Msg: "参数验证失败: " + errMsg,
}, nil
}
// 2. 检查课程是否存在
existingCourse, err := l.model.FindOne(l.ctx, req.Id)
if err != nil {
if err == model.ErrNotFound {
return &types.BaseResp{
Code: 404,
Msg: fmt.Sprintf("课程ID=%d不存在", req.Id),
}, nil
}
return &types.BaseResp{
Code: 500,
Msg: "查询课程信息失败: " + err.Error(),
}, nil
}
// 3. 构造更新数据(保留原有字段,仅更新请求中提供的字段)
updatedCourse := &model.Course{
Id: req.Id, // 必须指定更新的课程ID
Title: req.Title, // 标题(如果为空会覆盖原有值,根据业务需求调整)
Subtitle: req.Subtitle, // 副标题
CoverUrl: req.CoverUrl, // 封面图URL
Intro: stringToNullString(req.Intro), // 课程简介
Status: int64(req.Status), // 课程状态
CreateTime: existingCourse.CreateTime, // 保留原始创建时间
UpdateTime: existingCourse.UpdateTime, // 可由数据库自动更新,这里暂用原有值
}
// 4. 执行更新操作
err = l.model.Update(l.ctx, updatedCourse)
if err != nil {
return &types.BaseResp{
Code: 500,
Msg: "更新课程失败: " + err.Error(),
}, nil
}
// 5. 返回成功响应
return &types.BaseResp{
Code: 0,
Msg: fmt.Sprintf("课程ID=%d更新成功", req.Id),
}, nil
}

View File

@@ -0,0 +1,29 @@
package model
import "github.com/zeromicro/go-zero/core/stores/sqlx"
var _ CourseModel = (*customCourseModel)(nil)
type (
// CourseModel is an interface to be customized, add more methods here,
// and implement the added methods in customCourseModel.
CourseModel interface {
courseModel
withSession(session sqlx.Session) CourseModel
}
customCourseModel struct {
*defaultCourseModel
}
)
// NewCourseModel returns a model for the database table.
func NewCourseModel(conn sqlx.SqlConn) CourseModel {
return &customCourseModel{
defaultCourseModel: newCourseModel(conn),
}
}
func (m *customCourseModel) withSession(session sqlx.Session) CourseModel {
return NewCourseModel(sqlx.NewSqlConnFromSession(session))
}

View File

@@ -0,0 +1,157 @@
// 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 (
courseFieldNames = builder.RawFieldNames(&Course{})
courseRows = strings.Join(courseFieldNames, ",")
courseRowsExpectAutoSet = strings.Join(stringx.Remove(courseFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",")
courseRowsWithPlaceHolder = strings.Join(stringx.Remove(courseFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?"
)
type (
courseModel interface {
Insert(ctx context.Context, data *Course) (sql.Result, error)
FindOne(ctx context.Context, id int64) (*Course, error)
Update(ctx context.Context, data *Course) error
Delete(ctx context.Context, id int64) error
List(ctx context.Context, filter CourseFilter) ([]*Course, error)
Count(ctx context.Context, filter CourseFilter) (int64, error)
}
defaultCourseModel struct {
conn sqlx.SqlConn
table string
}
Course struct {
Id int64 `db:"id"` // 课程ID主键
Title string `db:"title"` // 课程标题
Subtitle string `db:"subtitle"` // 课程副标题
CoverUrl string `db:"cover_url"` // 课程封面图URL
Intro sql.NullString `db:"intro"` // 课程简介(对应“课程简介”模块)
Status int64 `db:"status"` // 课程状态0删除1-已发布)
CreateTime time.Time `db:"create_time"` // 创建时间
UpdateTime time.Time `db:"update_time"` // 更新时间
}
CourseFilter struct {
Status int8 // 状态筛选
Keyword string // 关键词搜索
Offset int // 分页偏移量
Limit int // 分页数量
}
)
func newCourseModel(conn sqlx.SqlConn) *defaultCourseModel {
return &defaultCourseModel{
conn: conn,
table: "`course`",
}
}
func (m *defaultCourseModel) Delete(ctx context.Context, id int64) error {
query := fmt.Sprintf("update %s set `status` = 0, `update_time` = CURRENT_TIMESTAMP where `id` = ?", m.table)
_, err := m.conn.ExecCtx(ctx, query, id)
return err
}
func (m *defaultCourseModel) FindOne(ctx context.Context, id int64) (*Course, error) {
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", courseRows, m.table)
var resp Course
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 *defaultCourseModel) Insert(ctx context.Context, data *Course) (sql.Result, error) {
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?)", m.table, courseRowsExpectAutoSet)
ret, err := m.conn.ExecCtx(ctx, query, data.Title, data.Subtitle, data.CoverUrl, data.Intro, data.Status)
return ret, err
}
func (m *defaultCourseModel) Update(ctx context.Context, data *Course) error {
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, courseRowsWithPlaceHolder)
_, err := m.conn.ExecCtx(ctx, query, data.Title, data.Subtitle, data.CoverUrl, data.Intro, data.Status, data.Id)
return err
}
func (m *defaultCourseModel) List(ctx context.Context, filter CourseFilter) ([]*Course, error) {
query := fmt.Sprintf("select %s from %s where 1=1", courseRows, m.table)
args := []interface{}{}
// 状态筛选逻辑:
// - 如果未指定filter.Status默认值默认只查询"已发布"status=1
// - 如果指定了filter.Status0或1则按指定值筛选支持查询已删除的课程
if filter.Status == -1 {
// 默认筛选只查已发布status=1
query += " and `status` = 1"
} else {
// 按指定status筛选0=删除1=发布)
query += " and `status` = ?"
args = append(args, filter.Status)
}
// 关键词搜索(标题和副标题模糊匹配)
if filter.Keyword != "" {
query += " and (`title` like ? or `subtitle` like ?)"
args = append(args, "%"+filter.Keyword+"%", "%"+filter.Keyword+"%")
}
// 分页处理
query += " limit ?, ?"
args = append(args, filter.Offset, filter.Limit)
// 执行查询
var courses []*Course
err := m.conn.QueryRowsCtx(ctx, &courses, query, args...)
return courses, err
}
// 配套的Count方法也需要同步修改确保总数计算正确
func (m *defaultCourseModel) Count(ctx context.Context, filter CourseFilter) (int64, error) {
query := fmt.Sprintf("select count(1) from %s where 1=1", m.table)
args := []interface{}{}
// 与List方法保持一致的status筛选逻辑
if filter.Status == -1 {
query += " and `status` = 1"
} else {
query += " and `status` = ?"
args = append(args, filter.Status)
}
// 关键词搜索条件
if filter.Keyword != "" {
query += " and (`title` like ? or `subtitle` like ?)"
args = append(args, "%"+filter.Keyword+"%", "%"+filter.Keyword+"%")
}
var total int64
err := m.conn.QueryRowCtx(ctx, &total, query, args...)
return total, err
}
func (m *defaultCourseModel) 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,57 @@
// Code generated by goctl. DO NOT EDIT.
// goctl 1.9.2
package types
type BaseResp struct {
Code int `json:"code"` // 状态码0成功非0失败
Msg string `json:"msg"` // 提示信息
}
type CourseResp struct {
Id int64 `json:"id"` // 课程ID
Title string `json:"title"` // 课程标题
Subtitle string `json:"subtitle"` // 课程副标题
CoverUrl string `json:"cover_url"` // 课程封面图URL
Intro string `json:"intro"` // 课程简介
Status int8 `json:"status"` // 课程状态
CreateTime string `json:"create_time"` // 创建时间
UpdateTime string `json:"update_time"` // 更新时间
}
type CreateCourseReq struct {
Title string `json:"title" validate:"required"` // 课程标题
Subtitle string `json:"subtitle"` // 课程副标题
CoverUrl string `json:"cover_url"` // 课程封面图URL
Intro string `json:"intro"` // 课程简介
Status int8 `json:"status" default:"1"` // 课程状态0删除1-已发布)
}
type DeleteCourseReq struct {
Id int64 `json:"id" validate:"required"` // 课程ID
}
type GetCourseReq struct {
Id int64 `json:"id" path:"id" validate:"required"` // 课程ID
}
type ListCourseReq struct {
Page int `json:"page" default:"1"` // 页码
Size int `json:"size" default:"10"` // 每页数量
Status int8 `json:"status"` // 课程状态筛选
Keyword string `json:"keyword"` // 搜索关键词(标题/副标题)
}
type ListCourseResp struct {
Total int64 `json:"total"` // 总条数
List []CourseResp `json:"list"` // 课程列表
}
type UpdateCourseReq struct {
Id int64 `json:"id" validate:"required"` // 课程ID
Title string `json:"title"` // 课程标题
Subtitle string `json:"subtitle"` // 课程副标题
CoverUrl string `json:"cover_url"` // 课程封面图URL
Intro string `json:"intro"` // 课程简介
Status int8 `json:"status"` // 课程状态0删除1-已发布)
}