修改课程教师

This commit is contained in:
2025-11-02 23:52:32 +08:00
parent 0ad87b1488
commit 886672f820
5 changed files with 146 additions and 65 deletions

View File

@@ -6,6 +6,8 @@ package course_teacher
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/course_teacher/internal/logic/course_teacher" "github.com/JACKYMYPERSON/hldrCenter/internal/course_teacher/internal/logic/course_teacher"
@@ -18,10 +20,19 @@ import (
func DeleteCourseTeacherHandler(cfg *config.Config) http.HandlerFunc { func DeleteCourseTeacherHandler(cfg *config.Config) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var req types.DeleteCourseTeacherReq var req types.DeleteCourseTeacherReq
if err := httpx.Parse(r, &req); err != nil { pathParts := strings.Split(r.URL.Path, "/")
httpx.ErrorCtx(r.Context(), w, err) fmt.Println(pathParts)
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 = int(id)
mysqlCfg := cfg.MySQL mysqlCfg := cfg.MySQL
dsn := fmt.Sprintf( dsn := fmt.Sprintf(

View File

@@ -6,6 +6,8 @@ package course_teacher
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/course_teacher/internal/logic/course_teacher" "github.com/JACKYMYPERSON/hldrCenter/internal/course_teacher/internal/logic/course_teacher"
@@ -18,10 +20,19 @@ import (
func GetCourseTeacherHandler(cfg *config.Config) http.HandlerFunc { func GetCourseTeacherHandler(cfg *config.Config) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var req types.GetCourseTeacherReq var req types.GetCourseTeacherReq
if err := httpx.Parse(r, &req); err != nil { pathParts := strings.Split(r.URL.Path, "/")
httpx.ErrorCtx(r.Context(), w, err) fmt.Println(pathParts)
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 = int(id)
mysqlCfg := cfg.MySQL mysqlCfg := cfg.MySQL
dsn := fmt.Sprintf( dsn := fmt.Sprintf(

View File

@@ -5,7 +5,6 @@ package course_teacher
import ( import (
"context" "context"
"database/sql"
"fmt" "fmt"
"github.com/JACKYMYPERSON/hldrCenter/config" "github.com/JACKYMYPERSON/hldrCenter/config"
@@ -32,57 +31,62 @@ func NewListCourseTeacherLogic(ctx context.Context, cfg *config.Config, model mo
} }
func (l *ListCourseTeacherLogic) ListCourseTeacher(req *types.ListCourseTeacherReq) (resp *types.ListCourseTeacherResp, err error) { func (l *ListCourseTeacherLogic) ListCourseTeacher(req *types.ListCourseTeacherReq) (resp *types.ListCourseTeacherResp, err error) {
// 1. 参数校验(补充validate标签外的业务校验 // 1. 强化参数校验(覆盖所有可能的无效参数
if req.Page < 1 { if req.Page < 1 {
return nil, fmt.Errorf("参数错误页码必须≥1") return nil, fmt.Errorf("参数错误页码必须≥1")
} }
if req.PageSize < 1 || req.PageSize > 100 { if req.PageSize < 1 || req.PageSize > 100 {
return nil, fmt.Errorf("参数错误每页条数必须在1-100之间") return nil, fmt.Errorf("参数错误每页条数必须在1-100之间")
} }
if req.CourseId < 0 { // 新增禁止负数课程ID无实际业务意义
return nil, fmt.Errorf("参数错误课程ID不能为负数")
}
// 2. 转换筛选参数为int64适配Model层字段类型 // 2. 转换筛选参数适配Model层int64字段类型)
courseId := int64(req.CourseId) courseId := int64(req.CourseId) // 0表示不按课程ID筛选Model层会忽略
teacherId := int64(req.TeacherId)
// 3. 计算分页参数(offset = (page-1)*pageSize // 3. 计算分页参数(标准分页公式,避免偏移量为负
offset := (req.Page - 1) * req.PageSize offset := (req.Page - 1) * req.PageSize
if offset < 0 { // 兜底防止极端情况下offset为负
offset = 0
}
// 4. 调用Model层查询总条数按筛选条件 // 4. 查询符合条件的总条数无teacher_id筛选仅可选按course_id
total, err := l.model.CountByConditions(l.ctx, courseId, teacherId) total, err := l.model.CountByConditions(l.ctx, courseId)
if err != nil { if err != nil {
return nil, fmt.Errorf("查询教师总条数失败:%w", err) return nil, fmt.Errorf("查询教师总条数失败:%w", err)
} }
// 5. 调用Model层查询当前页数据按筛选条件+分页+排序) // 5. 修复调用:参数类型/数量严格对齐Model层函数定义
// Model层函数签名FindByConditionsWithPage(ctx, courseId(int64), pageSize(int), offset(int))
teachers, err := l.model.FindByConditionsWithPage( teachers, err := l.model.FindByConditionsWithPage(
l.ctx, l.ctx,
courseId, // 课程ID筛选0表示不筛选 courseId, // 课程IDint64匹配Model层
teacherId, // 教师ID筛选0表示不筛选 req.PageSize, // 每页条数int无需转int64直接传req.PageSize
req.PageSize, // 每页条数 offset, // 偏移量int匹配Model层
offset, // 偏移量
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("查询教师列表失败:%w", err) return nil, fmt.Errorf("查询教师列表失败:%w", err)
} }
// 6. 转换Model数据为响应列表处理sql.NullString和int64→int // 6. 数据转换(统一处理sql.NullString类型,避免空值异常
var list []types.GetCourseTeacherResp var list []types.GetCourseTeacherResp
for _, t := range teachers { for _, t := range teachers {
list = append(list, types.GetCourseTeacherResp{ list = append(list, types.GetCourseTeacherResp{
Id: int(t.Id), // int64→int Id: int(t.Id),
CourseId: int(t.CourseId), // int64→int CourseId: int(t.CourseId),
TeacherId: int(t.TeacherId), // int64→int TeacherId: int(t.TeacherId),
Name: t.Name, Name: t.Name,
Title: t.Title, // sql.NullString→string Title: t.Title,
Avatar: t.Avatar, // sql.NullString→string Avatar: t.Avatar,
Intro: NullStringToString(t.Intro), // sql.NullString→string Intro: NullStringToString(t.Intro),
Sort: int(t.Sort), // int64→int Sort: int(t.Sort),
}) })
} }
// 7. 构造响应 // 7. 构造标准响应
resp = &types.ListCourseTeacherResp{ resp = &types.ListCourseTeacherResp{
Total: int(total), // 总条数int64→int Total: int(total),
List: list, List: list,
Page: req.Page, Page: req.Page,
PageSize: req.PageSize, PageSize: req.PageSize,
@@ -90,15 +94,3 @@ func (l *ListCourseTeacherLogic) ListCourseTeacher(req *types.ListCourseTeacherR
return resp, nil return resp, nil
} }
func StringToNullString(s string) sql.NullString {
if s != "" {
return sql.NullString{
String: s,
Valid: true,
}
}
return sql.NullString{
Valid: false, // 空字符串时标记为无效,数据库存 NULL
}
}

View File

@@ -5,6 +5,9 @@ package course_teacher
import ( import (
"context" "context"
"database/sql"
"errors"
"fmt"
"github.com/JACKYMYPERSON/hldrCenter/config" "github.com/JACKYMYPERSON/hldrCenter/config"
"github.com/JACKYMYPERSON/hldrCenter/internal/course_teacher/internal/model" "github.com/JACKYMYPERSON/hldrCenter/internal/course_teacher/internal/model"
@@ -30,7 +33,86 @@ func NewUpdateCourseTeacherLogic(ctx context.Context, cfg *config.Config, model
} }
func (l *UpdateCourseTeacherLogic) UpdateCourseTeacher(req *types.UpdateCourseTeacherReq) (resp *types.UpdateCourseTeacherResp, err error) { func (l *UpdateCourseTeacherLogic) UpdateCourseTeacher(req *types.UpdateCourseTeacherReq) (resp *types.UpdateCourseTeacherResp, err error) {
// todo: add your logic here and delete this line // 1. 基础参数校验确保ID有效
if req.Id <= 0 {
return nil, fmt.Errorf("参数错误关联ID必须为正整数")
}
return // 2. 查询原记录(确保记录存在)
// 注意此处假设Model层有FindOne方法根据ID查询单条记录
original, err := l.model.FindOne(l.ctx, int64(req.Id))
if err != nil {
if errors.Is(err, model.ErrNotFound) { // 假设Model层定义了ErrNotFound表示记录不存在
return nil, fmt.Errorf("课程教师关联记录不存在ID: %d", req.Id)
}
return nil, fmt.Errorf("查询原记录失败:%w", err)
}
// 3. 构建更新数据(仅更新请求中提供的非空/有效字段)
updateData := &model.CourseTeacher{
Id: int64(req.Id), // 必须携带ID用于WHERE条件
// 基础字段默认沿用原记录,后续按需覆盖
CourseId: original.CourseId,
TeacherId: original.TeacherId,
Name: original.Name,
Title: original.Title,
Avatar: original.Avatar,
Intro: original.Intro,
Sort: original.Sort,
}
// 3.1 可选更新课程ID若请求中提供了有效值
if req.CourseId > 0 {
updateData.CourseId = int64(req.CourseId)
}
// 3.2 可选更新教师ID若请求中提供了有效值
if req.TeacherId > 0 {
updateData.TeacherId = int64(req.TeacherId)
}
// 3.3 可选更新:教师姓名(若请求中提供了非空值)
if req.Name != "" {
updateData.Name = req.Name
}
// 3.4 可选更新:教师头衔(若请求中提供了非空值)
if req.Title != "" {
updateData.Title = req.Title
}
// 3.5 可选更新头像URL若请求中提供了非空值
if req.Avatar != "" {
updateData.Avatar = req.Avatar
}
// 3.6 可选更新:教师简介(若请求中提供了非空值,允许清空)
if req.Intro != "" { // 注意:若需允许清空简介,此处直接赋值(空字符串也会更新)
updateData.Intro = StringToNullString(req.Intro)
}
// 3.7 可选更新:排序值(若请求中提供了有效值)
if req.Sort >= 0 { // 符合validate规则min=0
updateData.Sort = int64(req.Sort)
}
// 4. 调用Model层执行更新
err = l.model.Update(l.ctx, updateData)
if err != nil {
return nil, fmt.Errorf("更新课程教师关联记录失败:%w", err)
}
// 5. 构建成功响应
resp = &types.UpdateCourseTeacherResp{
Message: fmt.Sprintf("课程教师关联记录ID: %d更新成功", req.Id),
}
return resp, nil
}
func StringToNullString(s string) sql.NullString {
if s != "" {
return sql.NullString{String: s, Valid: true}
}
return sql.NullString{Valid: false}
} }

View File

@@ -28,10 +28,10 @@ type (
FindOne(ctx context.Context, id int64) (*CourseTeacher, error) FindOne(ctx context.Context, id int64) (*CourseTeacher, error)
Update(ctx context.Context, data *CourseTeacher) error Update(ctx context.Context, data *CourseTeacher) error
Delete(ctx context.Context, id int64) error Delete(ctx context.Context, id int64) error
CountByConditions(ctx context.Context, courseId, teacherId int64) (int64, error) CountByConditions(ctx context.Context, courseId int64) (int64, error)
FindByConditionsWithPage( FindByConditionsWithPage(
ctx context.Context, ctx context.Context,
courseId, teacherId int64, courseId int64,
pageSize, offset int, pageSize, offset int,
) ([]*CourseTeacher, error) ) ([]*CourseTeacher, error)
} }
@@ -67,7 +67,7 @@ func (m *defaultCourseTeacherModel) Delete(ctx context.Context, id int64) error
} }
func (m *defaultCourseTeacherModel) FindOne(ctx context.Context, id int64) (*CourseTeacher, error) { func (m *defaultCourseTeacherModel) FindOne(ctx context.Context, id int64) (*CourseTeacher, error) {
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", courseTeacherRows, m.table) query := fmt.Sprintf("select %s from %s where `course_id` = ? limit 1", courseTeacherRows, m.table)
var resp CourseTeacher var resp CourseTeacher
err := m.conn.QueryRowCtx(ctx, &resp, query, id) err := m.conn.QueryRowCtx(ctx, &resp, query, id)
switch err { switch err {
@@ -92,74 +92,59 @@ func (m *defaultCourseTeacherModel) Update(ctx context.Context, data *CourseTeac
return err return err
} }
func (m *defaultCourseTeacherModel) CountByConditions(ctx context.Context, courseId, teacherId int64) (int64, error) { func (m *defaultCourseTeacherModel) CountByConditions(ctx context.Context, courseId int64) (int64, error) { // 移除teacherId参数
var count int64 var count int64
baseQuery := fmt.Sprintf("select count(*) from %s", m.table) baseQuery := fmt.Sprintf("select count(*) from %s", m.table)
// 构造筛选条件(支持单条件/多条件/无筛选)
var whereClauses []string var whereClauses []string
var args []interface{} var args []interface{}
// 只保留course_id的筛选如果需要删除teacher_id的筛选逻辑
if courseId > 0 { if courseId > 0 {
whereClauses = append(whereClauses, "`course_id` = ?") whereClauses = append(whereClauses, "`course_id` = ?")
args = append(args, courseId) args = append(args, courseId)
} }
if teacherId > 0 {
whereClauses = append(whereClauses, "`teacher_id` = ?")
args = append(args, teacherId)
}
// 拼接完整查询语句
if len(whereClauses) > 0 { if len(whereClauses) > 0 {
baseQuery += " where " + strings.Join(whereClauses, " and ") baseQuery += " where " + strings.Join(whereClauses, " and ")
} }
// 执行查询
err := m.conn.QueryRowCtx(ctx, &count, baseQuery, args...) err := m.conn.QueryRowCtx(ctx, &count, baseQuery, args...)
return count, err return count, err
} }
// FindByConditionsWithPage 实现按条件分页查询
func (m *defaultCourseTeacherModel) FindByConditionsWithPage( func (m *defaultCourseTeacherModel) FindByConditionsWithPage(
ctx context.Context, ctx context.Context,
courseId, teacherId int64, courseId int64, // 移除teacherId参数
pageSize, offset int, pageSize, offset int,
) ([]*CourseTeacher, error) { ) ([]*CourseTeacher, error) {
var teachers []*CourseTeacher var teachers []*CourseTeacher
baseQuery := fmt.Sprintf("select %s from %s", courseTeacherRows, m.table) baseQuery := fmt.Sprintf("select %s from %s", courseTeacherRows, m.table)
// 构造筛选条件同CountByConditions
var whereClauses []string var whereClauses []string
var args []interface{} var args []interface{}
// 只保留course_id的筛选如果需要删除teacher_id的筛选逻辑
if courseId > 0 { if courseId > 0 {
whereClauses = append(whereClauses, "`course_id` = ?") whereClauses = append(whereClauses, "`course_id` = ?")
args = append(args, courseId) args = append(args, courseId)
} }
if teacherId > 0 {
whereClauses = append(whereClauses, "`teacher_id` = ?")
args = append(args, teacherId)
}
// 拼接分页和排序按sort升序确保展示顺序一致 // 分页参数
pageQuery := " order by `sort` asc limit ?, ?" pageQuery := " order by `sort` asc limit ?, ?"
args = append(args, offset, pageSize) // 补充分页参数 args = append(args, offset, pageSize)
// 拼接完整查询语句
if len(whereClauses) > 0 { if len(whereClauses) > 0 {
baseQuery += " where " + strings.Join(whereClauses, " and ") + pageQuery baseQuery += " where " + strings.Join(whereClauses, " and ") + pageQuery
} else { } else {
baseQuery += pageQuery baseQuery += pageQuery
} }
// 执行查询
err := m.conn.QueryRowsCtx(ctx, &teachers, baseQuery, args...) err := m.conn.QueryRowsCtx(ctx, &teachers, baseQuery, args...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return teachers, nil return teachers, nil
} }
func (m *defaultCourseTeacherModel) tableName() string { func (m *defaultCourseTeacherModel) tableName() string {
return m.table return m.table
} }