排班管理、主播管理、直播账号管理
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/.idea/*
|
||||
49
Dockerfile
Normal file
49
Dockerfile
Normal file
@@ -0,0 +1,49 @@
|
||||
# 阶段1: 构建
|
||||
FROM golang:1.26-alpine AS builder
|
||||
|
||||
RUN apk add --no-cache git ca-certificates tzdata
|
||||
|
||||
ENV TZ=Asia/Shanghai
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
ENV GO111MODULE=on
|
||||
ENV GOPROXY=https://goproxy.cn,direct
|
||||
ENV CGO_ENABLED=0
|
||||
ENV GOTOOLCHAIN=auto
|
||||
ENV GOPRIVATE=gitea.com/red-future/common
|
||||
|
||||
# 配置git使用私有Gitea仓库
|
||||
RUN git config --global url."http://x-token-auth:9b31146aa8c10a7cb4f2e49dcee0934a223be1076289810e1ad98b968066c2bc@116.204.74.41:3000/red-future/common.git".insteadOf "https://gitea.com/red-future/common.git" && \
|
||||
git config --global credential.helper store
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN go mod download && go mod tidy
|
||||
|
||||
RUN go build -ldflags="-s -w" -o main ./main.go
|
||||
|
||||
# 阶段2: 运行
|
||||
FROM alpine:3.19
|
||||
|
||||
RUN apk add --no-cache ca-certificates tzdata
|
||||
|
||||
ENV TZ=Asia/Shanghai
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /build/main .
|
||||
COPY --from=builder /build/config.yml ./
|
||||
|
||||
RUN mkdir -p /app/resource/log/run \
|
||||
/app/resource/log/server \
|
||||
&& adduser -D -u 1000 appuser \
|
||||
&& chown -R appuser:appuser /app
|
||||
|
||||
USER appuser
|
||||
|
||||
EXPOSE 3001
|
||||
|
||||
CMD ["./main"]
|
||||
49
config.yml
Normal file
49
config.yml
Normal file
@@ -0,0 +1,49 @@
|
||||
server:
|
||||
address : ":3001"
|
||||
name: "erp"
|
||||
workerId: 1
|
||||
logPath: "resource/log/server"
|
||||
logStdout: true
|
||||
errorStack: true
|
||||
rate:
|
||||
limit: 200
|
||||
burst: 300
|
||||
|
||||
# Database.
|
||||
database:
|
||||
default:
|
||||
- type: "pgsql"
|
||||
host: "localhost"
|
||||
port: "5432"
|
||||
user: "postgres"
|
||||
pass: "root"
|
||||
name: "erp"
|
||||
role: "master"
|
||||
maxIdle: "5"
|
||||
maxOpen: "20"
|
||||
maxLifetime: "60s"
|
||||
charset: "utf8mb4"
|
||||
debug: true
|
||||
dryRun: false
|
||||
createdAt: "created_at"
|
||||
updatedAt: "updated_at"
|
||||
deletedAt: "deleted_at"
|
||||
timeMaintainDisabled: false
|
||||
|
||||
redis:
|
||||
# 集群模式配置方法
|
||||
default:
|
||||
address: 116.204.74.41:6379
|
||||
db: 0
|
||||
idleTimeout: "60s" #连接最大空闲时间,使用时间字符串例如30s/1m/1d
|
||||
maxConnLifetime: "90s" #连接最长存活时间,使用时间字符串例如30s/1m/1d
|
||||
waitTimeout: "60s" #等待连接池连接的超时时间,使用时间字符串例如30s/1m/1d
|
||||
dialTimeout: "30s" #TCP连接的超时时间,使用时间字符串例如30s/1m/1d
|
||||
readTimeout: "30s" #TCP的Read操作超时时间,使用时间字符串例如30s/1m/1d
|
||||
writeTimeout: "30s" #TCP的Write操作超时时间,使用时间字符串例如30s/1m/1d
|
||||
maxActive: 100
|
||||
consul:
|
||||
address: 116.204.74.41:8500
|
||||
# pass: jiahui8888
|
||||
jaeger: #链路追踪
|
||||
addr: 116.204.74.41:4318
|
||||
20
consts/data/AnchorStatus.go
Normal file
20
consts/data/AnchorStatus.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package data
|
||||
|
||||
// AnchorStatus 主播状态
|
||||
type AnchorStatus int
|
||||
|
||||
const (
|
||||
AnchorStatusDisabled AnchorStatus = 0 // 停用
|
||||
AnchorStatusActive AnchorStatus = 1 // 正常
|
||||
)
|
||||
|
||||
func (s AnchorStatus) String() string {
|
||||
switch s {
|
||||
case AnchorStatusDisabled:
|
||||
return "停用"
|
||||
case AnchorStatusActive:
|
||||
return "正常"
|
||||
default:
|
||||
return "未知"
|
||||
}
|
||||
}
|
||||
26
consts/data/ScheduleStatus.go
Normal file
26
consts/data/ScheduleStatus.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package data
|
||||
|
||||
// ScheduleStatus 排班状态
|
||||
type ScheduleStatus int
|
||||
|
||||
const (
|
||||
ScheduleStatusPending ScheduleStatus = 0 // 待直播
|
||||
ScheduleStatusLive ScheduleStatus = 1 // 直播中
|
||||
ScheduleStatusEnded ScheduleStatus = 2 // 已结束
|
||||
ScheduleStatusCancelled ScheduleStatus = 3 // 已取消
|
||||
)
|
||||
|
||||
func (s ScheduleStatus) String() string {
|
||||
switch s {
|
||||
case ScheduleStatusPending:
|
||||
return "待直播"
|
||||
case ScheduleStatusLive:
|
||||
return "直播中"
|
||||
case ScheduleStatusEnded:
|
||||
return "已结束"
|
||||
case ScheduleStatusCancelled:
|
||||
return "已取消"
|
||||
default:
|
||||
return "未知"
|
||||
}
|
||||
}
|
||||
9
consts/public/collections.go
Normal file
9
consts/public/collections.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package public
|
||||
|
||||
// PostgreSQL表名常量
|
||||
|
||||
const (
|
||||
AnchorTable = "anchor" // 主播表
|
||||
LiveAccountTable = "live_account" // 直播账号表
|
||||
ScheduleTable = "schedule" // 排班表
|
||||
)
|
||||
47
controller/data/anchor_controller.go
Normal file
47
controller/data/anchor_controller.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"context"
|
||||
dto "erp/model/dto/data"
|
||||
service "erp/service/data"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
type anchorController struct{}
|
||||
|
||||
// Anchor 主播控制器
|
||||
var Anchor = new(anchorController)
|
||||
|
||||
// CreateAnchor 创建主播
|
||||
func (c *anchorController) CreateAnchor(ctx context.Context, req *dto.CreateAnchorReq) (res *dto.CreateAnchorRes, err error) {
|
||||
return service.Anchor.Create(ctx, req)
|
||||
}
|
||||
|
||||
// ListAnchor 获取主播列表
|
||||
func (c *anchorController) ListAnchor(ctx context.Context, req *dto.ListAnchorReq) (res *dto.ListAnchorRes, err error) {
|
||||
return service.Anchor.List(ctx, req)
|
||||
}
|
||||
|
||||
// GetAnchor 获取主播详情
|
||||
func (c *anchorController) GetAnchor(ctx context.Context, req *dto.GetAnchorReq) (res *dto.GetAnchorRes, err error) {
|
||||
return service.Anchor.GetOne(ctx, req)
|
||||
}
|
||||
|
||||
// UpdateAnchor 更新主播
|
||||
func (c *anchorController) UpdateAnchor(ctx context.Context, req *dto.UpdateAnchorReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.Anchor.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateAnchorStatus 更新主播状态
|
||||
func (c *anchorController) UpdateAnchorStatus(ctx context.Context, req *dto.UpdateAnchorStatusReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.Anchor.UpdateStatus(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteAnchor 删除主播
|
||||
func (c *anchorController) DeleteAnchor(ctx context.Context, req *dto.DeleteAnchorReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.Anchor.Delete(ctx, req)
|
||||
return
|
||||
}
|
||||
53
controller/data/live_account_controller.go
Normal file
53
controller/data/live_account_controller.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"context"
|
||||
dto "erp/model/dto/data"
|
||||
service "erp/service/data"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
type liveAccountController struct{}
|
||||
|
||||
// LiveAccount 直播账号控制器
|
||||
var LiveAccount = new(liveAccountController)
|
||||
|
||||
// CreateLiveAccount 创建直播账号
|
||||
func (c *liveAccountController) CreateLiveAccount(ctx context.Context, req *dto.CreateLiveAccountReq) (res *dto.CreateLiveAccountRes, err error) {
|
||||
|
||||
return service.LiveAccount.Create(ctx, req)
|
||||
}
|
||||
|
||||
// ListLiveAccount 获取直播账号列表
|
||||
func (c *liveAccountController) ListLiveAccount(ctx context.Context, req *dto.ListLiveAccountReq) (res *dto.ListLiveAccountRes, err error) {
|
||||
|
||||
return service.LiveAccount.List(ctx, req)
|
||||
}
|
||||
|
||||
// GetLiveAccount 获取直播账号详情
|
||||
func (c *liveAccountController) GetLiveAccount(ctx context.Context, req *dto.GetLiveAccountReq) (res *dto.GetLiveAccountRes, err error) {
|
||||
|
||||
return service.LiveAccount.GetOne(ctx, req)
|
||||
}
|
||||
|
||||
// UpdateLiveAccount 更新直播账号
|
||||
func (c *liveAccountController) UpdateLiveAccount(ctx context.Context, req *dto.UpdateLiveAccountReq) (res *beans.ResponseEmpty, err error) {
|
||||
|
||||
err = service.LiveAccount.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateLiveAccountStatus 更新直播账号状态
|
||||
func (c *liveAccountController) UpdateLiveAccountStatus(ctx context.Context, req *dto.UpdateLiveAccountStatusReq) (res *beans.ResponseEmpty, err error) {
|
||||
|
||||
err = service.LiveAccount.UpdateStatus(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteLiveAccount 删除直播账号
|
||||
func (c *liveAccountController) DeleteLiveAccount(ctx context.Context, req *dto.DeleteLiveAccountReq) (res *beans.ResponseEmpty, err error) {
|
||||
|
||||
err = service.LiveAccount.Delete(ctx, req)
|
||||
return
|
||||
}
|
||||
53
controller/data/schedule_controller.go
Normal file
53
controller/data/schedule_controller.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"context"
|
||||
dto "erp/model/dto/data"
|
||||
service "erp/service/data"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
type scheduleController struct{}
|
||||
|
||||
// Schedule 排班控制器
|
||||
var Schedule = new(scheduleController)
|
||||
|
||||
// CreateSchedule 创建排班
|
||||
func (c *scheduleController) CreateSchedule(ctx context.Context, req *dto.CreateScheduleReq) (res *dto.CreateScheduleRes, err error) {
|
||||
|
||||
return service.Schedule.Create(ctx, req)
|
||||
}
|
||||
|
||||
// ListSchedule 获取排班列表
|
||||
func (c *scheduleController) ListSchedule(ctx context.Context, req *dto.ListScheduleReq) (res *dto.ListScheduleRes, err error) {
|
||||
|
||||
return service.Schedule.List(ctx, req)
|
||||
}
|
||||
|
||||
// GetSchedule 获取排班详情
|
||||
func (c *scheduleController) GetSchedule(ctx context.Context, req *dto.GetScheduleReq) (res *dto.GetScheduleRes, err error) {
|
||||
|
||||
return service.Schedule.GetOne(ctx, req)
|
||||
}
|
||||
|
||||
// UpdateSchedule 更新排班
|
||||
func (c *scheduleController) UpdateSchedule(ctx context.Context, req *dto.UpdateScheduleReq) (res *beans.ResponseEmpty, err error) {
|
||||
|
||||
err = service.Schedule.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateScheduleStatus 更新排班状态
|
||||
func (c *scheduleController) UpdateScheduleStatus(ctx context.Context, req *dto.UpdateScheduleStatusReq) (res *beans.ResponseEmpty, err error) {
|
||||
|
||||
err = service.Schedule.UpdateStatus(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteSchedule 删除排班
|
||||
func (c *scheduleController) DeleteSchedule(ctx context.Context, req *dto.DeleteScheduleReq) (res *beans.ResponseEmpty, err error) {
|
||||
|
||||
err = service.Schedule.Delete(ctx, req)
|
||||
return
|
||||
}
|
||||
120
dao/data/anchor_dao.go
Normal file
120
dao/data/anchor_dao.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"context"
|
||||
consts "erp/consts/public"
|
||||
dto "erp/model/dto/data"
|
||||
entity "erp/model/entity/data"
|
||||
|
||||
"gitea.com/red-future/common/db/gfdb"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
var Anchor = new(anchorDao)
|
||||
|
||||
type anchorDao struct{}
|
||||
|
||||
// Insert 插入主播
|
||||
func (d *anchorDao) Insert(ctx context.Context, req *dto.CreateAnchorReq) (id int64, err error) {
|
||||
var res *entity.Anchor
|
||||
if err = gconv.Struct(req, &res); err != nil {
|
||||
return
|
||||
}
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.AnchorTable).Data(&res).Insert()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.LastInsertId()
|
||||
}
|
||||
|
||||
// Update 更新主播
|
||||
func (d *anchorDao) Update(ctx context.Context, req *dto.UpdateAnchorReq) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.AnchorTable).Data(&req).OmitEmpty().Where(entity.AnchorCols.Id, req.Id).Update()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// Delete 删除主播
|
||||
func (d *anchorDao) Delete(ctx context.Context, req *dto.DeleteAnchorReq) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.AnchorTable).Where(entity.AnchorCols.Id, req.Id).Delete()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// GetOne 获取单个主播
|
||||
func (d *anchorDao) GetOne(ctx context.Context, req *dto.GetAnchorReq) (res *entity.Anchor, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.AnchorTable).Where(entity.AnchorCols.Id, req.Id).One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// Count 获取主播数量
|
||||
func (d *anchorDao) Count(ctx context.Context, req *dto.ListAnchorReq) (count int, err error) {
|
||||
return d.buildListFilter(ctx, req).Count()
|
||||
}
|
||||
|
||||
// List 获取主播列表
|
||||
func (d *anchorDao) List(ctx context.Context, req *dto.ListAnchorReq) (res []entity.Anchor, total int, err error) {
|
||||
model := d.buildListFilter(ctx, req)
|
||||
model.OrderDesc(entity.AnchorCols.CreatedAt)
|
||||
if req.Page != nil {
|
||||
model.Page(int(req.Page.PageNum), int(req.Page.PageSize))
|
||||
}
|
||||
r, total, err := model.AllAndCount(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Structs(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// buildListFilter 构建列表查询的过滤条件
|
||||
func (d *anchorDao) buildListFilter(ctx context.Context, req *dto.ListAnchorReq) *gdb.Model {
|
||||
model := gfdb.DB(ctx).Model(ctx, consts.AnchorTable).Model
|
||||
if !g.IsEmpty(req.Keyword) {
|
||||
model.WhereLike(entity.AnchorCols.Name, "%"+req.Keyword+"%").
|
||||
WhereOrLike(entity.AnchorCols.Phone, "%"+req.Keyword+"%").
|
||||
WhereOrLike(entity.AnchorCols.Code, "%"+req.Keyword+"%")
|
||||
}
|
||||
model.Where(entity.AnchorCols.Name, req.Name)
|
||||
model.Where(entity.AnchorCols.Phone, req.Phone)
|
||||
model.Where(entity.AnchorCols.Code, req.Code)
|
||||
if req.Status != nil {
|
||||
model.Where(entity.AnchorCols.Status, *req.Status)
|
||||
}
|
||||
model.OmitEmptyWhere()
|
||||
return model
|
||||
}
|
||||
|
||||
// UpdateStatus 更新主播状态
|
||||
func (d *anchorDao) UpdateStatus(ctx context.Context, id int64, status int) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.AnchorTable).
|
||||
Data(map[string]interface{}{"status": status}).
|
||||
Where(entity.AnchorCols.Id, id).
|
||||
Update()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// GetByCode 根据工号获取主播
|
||||
func (d *anchorDao) GetByCode(ctx context.Context, code string) (res *entity.Anchor, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.AnchorTable).
|
||||
Where(entity.AnchorCols.Code, code).
|
||||
One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
120
dao/data/live_account_dao.go
Normal file
120
dao/data/live_account_dao.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"context"
|
||||
consts "erp/consts/public"
|
||||
dto "erp/model/dto/data"
|
||||
entity "erp/model/entity/data"
|
||||
|
||||
"gitea.com/red-future/common/db/gfdb"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
var LiveAccount = new(liveAccountDao)
|
||||
|
||||
type liveAccountDao struct{}
|
||||
|
||||
// Insert 插入直播账号
|
||||
func (d *liveAccountDao) Insert(ctx context.Context, req *dto.CreateLiveAccountReq) (id int64, err error) {
|
||||
var res *entity.LiveAccount
|
||||
if err = gconv.Struct(req, &res); err != nil {
|
||||
return
|
||||
}
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.LiveAccountTable).Data(&res).Insert()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.LastInsertId()
|
||||
}
|
||||
|
||||
// Update 更新直播账号
|
||||
func (d *liveAccountDao) Update(ctx context.Context, req *dto.UpdateLiveAccountReq) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.LiveAccountTable).Data(&req).OmitEmpty().Where(entity.LiveAccountCols.Id, req.Id).Update()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// Delete 删除直播账号
|
||||
func (d *liveAccountDao) Delete(ctx context.Context, req *dto.DeleteLiveAccountReq) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.LiveAccountTable).Where(entity.LiveAccountCols.Id, req.Id).Delete()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// GetOne 获取单个直播账号
|
||||
func (d *liveAccountDao) GetOne(ctx context.Context, req *dto.GetLiveAccountReq) (res *entity.LiveAccount, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.LiveAccountTable).Where(entity.LiveAccountCols.Id, req.Id).One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// Count 获取直播账号数量
|
||||
func (d *liveAccountDao) Count(ctx context.Context, req *dto.ListLiveAccountReq) (count int, err error) {
|
||||
return d.buildListFilter(ctx, req).Count()
|
||||
}
|
||||
|
||||
// List 获取直播账号列表
|
||||
func (d *liveAccountDao) List(ctx context.Context, req *dto.ListLiveAccountReq) (res []entity.LiveAccount, total int, err error) {
|
||||
model := d.buildListFilter(ctx, req)
|
||||
model.OrderDesc(entity.LiveAccountCols.CreatedAt)
|
||||
if req.Page != nil {
|
||||
model.Page(int(req.Page.PageNum), int(req.Page.PageSize))
|
||||
}
|
||||
r, total, err := model.AllAndCount(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Structs(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// buildListFilter 构建列表查询的过滤条件
|
||||
func (d *liveAccountDao) buildListFilter(ctx context.Context, req *dto.ListLiveAccountReq) *gdb.Model {
|
||||
model := gfdb.DB(ctx).Model(ctx, consts.LiveAccountTable).Model
|
||||
if !g.IsEmpty(req.Keyword) {
|
||||
model.WhereLike(entity.LiveAccountCols.Platform, "%"+req.Keyword+"%").
|
||||
WhereOrLike(entity.LiveAccountCols.AccountName, "%"+req.Keyword+"%").
|
||||
WhereOrLike(entity.LiveAccountCols.AccountId, "%"+req.Keyword+"%")
|
||||
}
|
||||
model.Where(entity.LiveAccountCols.Platform, req.Platform)
|
||||
model.Where(entity.LiveAccountCols.AccountName, req.AccountName)
|
||||
model.Where(entity.LiveAccountCols.AccountId, req.AccountId)
|
||||
if req.Status != nil {
|
||||
model.Where(entity.LiveAccountCols.Status, *req.Status)
|
||||
}
|
||||
model.OmitEmptyWhere()
|
||||
return model
|
||||
}
|
||||
|
||||
// UpdateStatus 更新直播账号状态
|
||||
func (d *liveAccountDao) UpdateStatus(ctx context.Context, id int64, status int) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.LiveAccountTable).
|
||||
Data(map[string]interface{}{"status": status}).
|
||||
Where(entity.LiveAccountCols.Id, id).
|
||||
Update()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// GetByAccountId 根据账号ID获取直播账号
|
||||
func (d *liveAccountDao) GetByAccountId(ctx context.Context, accountId string) (res *entity.LiveAccount, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.LiveAccountTable).
|
||||
Where(entity.LiveAccountCols.AccountId, accountId).
|
||||
One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
140
dao/data/schedule_dao.go
Normal file
140
dao/data/schedule_dao.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"context"
|
||||
consts "erp/consts/public"
|
||||
dto "erp/model/dto/data"
|
||||
entity "erp/model/entity/data"
|
||||
"time"
|
||||
|
||||
"gitea.com/red-future/common/db/gfdb"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
var Schedule = new(scheduleDao)
|
||||
|
||||
type scheduleDao struct{}
|
||||
|
||||
// Insert 插入排班
|
||||
func (d *scheduleDao) Insert(ctx context.Context, req *dto.CreateScheduleReq) (id int64, err error) {
|
||||
var res *entity.Schedule
|
||||
if err = gconv.Struct(req, &res); err != nil {
|
||||
return
|
||||
}
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ScheduleTable).Data(&res).Insert()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.LastInsertId()
|
||||
}
|
||||
|
||||
// Update 更新排班
|
||||
func (d *scheduleDao) Update(ctx context.Context, req *dto.UpdateScheduleReq) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ScheduleTable).Data(&req).OmitEmpty().Where(entity.ScheduleCols.Id, req.Id).Update()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// Delete 删除排班
|
||||
func (d *scheduleDao) Delete(ctx context.Context, req *dto.DeleteScheduleReq) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ScheduleTable).Where(entity.ScheduleCols.Id, req.Id).Delete()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// GetOne 获取单个排班
|
||||
func (d *scheduleDao) GetOne(ctx context.Context, req *dto.GetScheduleReq) (res *entity.Schedule, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ScheduleTable).Where(entity.ScheduleCols.Id, req.Id).One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// Count 获取排班数量
|
||||
func (d *scheduleDao) Count(ctx context.Context, req *dto.ListScheduleReq) (count int, err error) {
|
||||
return d.buildListFilter(ctx, req).Count()
|
||||
}
|
||||
|
||||
// List 获取排班列表
|
||||
func (d *scheduleDao) List(ctx context.Context, req *dto.ListScheduleReq) (res []entity.Schedule, total int, err error) {
|
||||
model := d.buildListFilter(ctx, req)
|
||||
model.OrderDesc(entity.ScheduleCols.StartTime)
|
||||
if req.Page != nil {
|
||||
model.Page(int(req.Page.PageNum), int(req.Page.PageSize))
|
||||
}
|
||||
r, total, err := model.AllAndCount(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Structs(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// buildListFilter 构建列表查询的过滤条件
|
||||
func (d *scheduleDao) buildListFilter(ctx context.Context, req *dto.ListScheduleReq) *gdb.Model {
|
||||
model := gfdb.DB(ctx).Model(ctx, consts.ScheduleTable).Model
|
||||
if req.AnchorId != nil {
|
||||
model.Where(entity.ScheduleCols.AnchorId, *req.AnchorId)
|
||||
}
|
||||
if req.AccountId != nil {
|
||||
model.Where(entity.ScheduleCols.AccountId, *req.AccountId)
|
||||
}
|
||||
if req.Status != nil {
|
||||
model.Where(entity.ScheduleCols.Status, *req.Status)
|
||||
}
|
||||
if !req.StartDate.IsZero() {
|
||||
model.WhereGTE(entity.ScheduleCols.StartTime, req.StartDate.Format("2006-01-02")+" 00:00:00")
|
||||
}
|
||||
if !req.EndDate.IsZero() {
|
||||
model.WhereLTE(entity.ScheduleCols.StartTime, req.EndDate.Format("2006-01-02")+" 23:59:59")
|
||||
}
|
||||
return model
|
||||
}
|
||||
|
||||
// UpdateStatus 更新排班状态
|
||||
func (d *scheduleDao) UpdateStatus(ctx context.Context, id int64, status int) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ScheduleTable).
|
||||
Data(map[string]interface{}{"status": status}).
|
||||
Where(entity.ScheduleCols.Id, id).
|
||||
Update()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// CheckTimeConflict 检查时间冲突
|
||||
func (d *scheduleDao) CheckTimeConflict(ctx context.Context, anchorId int, startTime, endTime time.Time, excludeId ...int64) (count int, err error) {
|
||||
model := gfdb.DB(ctx).Model(ctx, consts.ScheduleTable).
|
||||
Where(entity.ScheduleCols.AnchorId, anchorId).
|
||||
Where(entity.ScheduleCols.Status, 0). // 只检查待直播的排班
|
||||
WhereLT(entity.ScheduleCols.StartTime, endTime.Format("2006-01-02 15:04:05")).
|
||||
WhereGT(entity.ScheduleCols.EndTime, startTime.Format("2006-01-02 15:04:05"))
|
||||
|
||||
if len(excludeId) > 0 && excludeId[0] > 0 {
|
||||
model.WhereNot(entity.ScheduleCols.Id, excludeId[0])
|
||||
}
|
||||
|
||||
return model.Count()
|
||||
}
|
||||
|
||||
// GetByAnchorAndTime 根据主播和时间获取排班
|
||||
func (d *scheduleDao) GetByAnchorAndTime(ctx context.Context, anchorId int, startTime time.Time) (res *entity.Schedule, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ScheduleTable).
|
||||
Where(entity.ScheduleCols.AnchorId, anchorId).
|
||||
WhereLTE(entity.ScheduleCols.StartTime, startTime.Format("2006-01-02 15:04:05")).
|
||||
WhereGTE(entity.ScheduleCols.EndTime, startTime.Format("2006-01-02 15:04:05")).
|
||||
One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
98
go.mod
Normal file
98
go.mod
Normal file
@@ -0,0 +1,98 @@
|
||||
module erp
|
||||
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
gitea.com/red-future/common v0.0.12
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.10.0
|
||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.0
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.0
|
||||
github.com/gogf/gf/v2 v2.10.0
|
||||
golang.org/x/net v0.53.0
|
||||
)
|
||||
|
||||
replace gitea.com/red-future/common => ../common
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.2.0 // indirect
|
||||
github.com/BurntSushi/toml v1.6.0 // indirect
|
||||
github.com/armon/go-metrics v0.4.1 // indirect
|
||||
github.com/bwmarrin/snowflake v0.3.0 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||
github.com/clipperhouse/displaywidth v0.11.0 // indirect
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
|
||||
github.com/dgraph-io/badger/v4 v4.2.0 // indirect
|
||||
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/emirpasic/gods/v2 v2.0.0-alpha // indirect
|
||||
github.com/fatih/color v1.19.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/go-ego/gse v1.0.2 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-sql-driver/mysql v1.9.3 // indirect
|
||||
github.com/goccy/go-json v0.10.6 // indirect
|
||||
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5 // indirect
|
||||
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
|
||||
github.com/golang/glog v1.2.5 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/snappy v1.0.0 // indirect
|
||||
github.com/google/flatbuffers v1.12.1 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
||||
github.com/hashicorp/consul/api v1.26.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-hclog v1.5.0 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
||||
github.com/hashicorp/serf v0.10.1 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/lib/pq v1.10.9 // indirect
|
||||
github.com/magiconair/properties v1.8.10 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.21 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.23 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect
|
||||
github.com/olekukonko/errors v1.2.0 // indirect
|
||||
github.com/olekukonko/ll v0.1.8 // indirect
|
||||
github.com/olekukonko/tablewriter v1.1.4 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/r3labs/diff/v2 v2.15.1 // indirect
|
||||
github.com/redis/go-redis/v9 v9.18.0 // indirect
|
||||
github.com/tiger1103/gfast-token v1.0.10 // indirect
|
||||
github.com/vcaesar/cedar v0.30.0 // indirect
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.0 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/otel v1.43.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.43.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.43.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.43.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||
golang.org/x/sys v0.43.0 // indirect
|
||||
golang.org/x/text v0.36.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
|
||||
google.golang.org/grpc v1.75.0 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
28
main.go
Normal file
28
main.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"erp/controller/data"
|
||||
|
||||
"gitea.com/red-future/common/http"
|
||||
"gitea.com/red-future/common/jaeger"
|
||||
_ "gitea.com/red-future/common/ragflow" // RAGFlow 客户端自动初始化
|
||||
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
|
||||
_ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
|
||||
_ "github.com/gogf/gf/contrib/nosql/redis/v2"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
defer jaeger.ShutDown(ctx)
|
||||
|
||||
http.RouteRegister([]interface{}{
|
||||
// 主播管理
|
||||
data.Anchor,
|
||||
// 直播账号管理
|
||||
data.LiveAccount,
|
||||
// 排班管理
|
||||
data.Schedule,
|
||||
})
|
||||
select {}
|
||||
}
|
||||
89
model/dto/data/anchor_dto.go
Normal file
89
model/dto/data/anchor_dto.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"erp/consts/data"
|
||||
entity "erp/model/entity/data"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// CreateAnchorReq 创建主播请求
|
||||
type CreateAnchorReq struct {
|
||||
g.Meta `path:"/createAnchor" method:"post" tags:"主播管理" summary:"创建主播" dc:"创建新的主播"`
|
||||
Name string `json:"name" v:"required" dc:"主播姓名"`
|
||||
Phone string `json:"phone" v:"required" dc:"联系电话"`
|
||||
Code string `json:"code" v:"required" dc:"工号"`
|
||||
Status int `json:"status" d:"1" dc:"状态(0停用 1正常)"`
|
||||
Remark string `json:"remark" dc:"备注"`
|
||||
}
|
||||
|
||||
// CreateAnchorRes 创建主播响应
|
||||
type CreateAnchorRes struct {
|
||||
Id int64 `json:"id" dc:"主播ID"`
|
||||
}
|
||||
|
||||
// ListAnchorReq 获取主播列表请求
|
||||
type ListAnchorReq struct {
|
||||
g.Meta `path:"/listAnchors" method:"get" tags:"主播管理" summary:"获取主播列表" dc:"分页查询主播列表"`
|
||||
*beans.Page
|
||||
Name string `json:"name" dc:"主播姓名"`
|
||||
Phone string `json:"phone" dc:"联系电话"`
|
||||
Code string `json:"code" dc:"工号"`
|
||||
Status *int `json:"status" dc:"状态(0停用 1正常)"`
|
||||
Keyword string `json:"keyword" dc:"关键字(搜索姓名/电话/工号)"`
|
||||
}
|
||||
|
||||
// ListAnchorRes 获取主播列表响应
|
||||
type ListAnchorRes struct {
|
||||
List []AnchorItem `json:"list" dc:"主播列表"`
|
||||
Total int `json:"total" dc:"总数"`
|
||||
}
|
||||
|
||||
// AnchorItem 主播列表项
|
||||
type AnchorItem struct {
|
||||
Id int64 `json:"id,string"`
|
||||
Name string `json:"name"`
|
||||
Phone string `json:"phone"`
|
||||
Code string `json:"code"`
|
||||
Status int `json:"status"`
|
||||
StatusName string `json:"statusName"`
|
||||
Remark string `json:"remark"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
UpdatedAt int64 `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// GetAnchorReq 获取主播详情请求
|
||||
type GetAnchorReq struct {
|
||||
g.Meta `path:"/getAnchor" method:"get" tags:"主播管理" summary:"获取主播详情" dc:"获取主播详情"`
|
||||
Id int64 `json:"id" v:"required" dc:"主播ID"`
|
||||
}
|
||||
|
||||
// GetAnchorRes 获取主播详情响应
|
||||
type GetAnchorRes struct {
|
||||
*entity.Anchor
|
||||
}
|
||||
|
||||
// UpdateAnchorReq 更新主播请求
|
||||
type UpdateAnchorReq struct {
|
||||
g.Meta `path:"/updateAnchor" method:"put" tags:"主播管理" summary:"更新主播" dc:"更新主播信息"`
|
||||
Id int64 `json:"id" v:"required" dc:"主播ID"`
|
||||
Name string `json:"name" dc:"主播姓名"`
|
||||
Phone string `json:"phone" dc:"联系电话"`
|
||||
Code string `json:"code" dc:"工号"`
|
||||
Status *int `json:"status" dc:"状态(0停用 1正常)"`
|
||||
Remark string `json:"remark" dc:"备注"`
|
||||
}
|
||||
|
||||
// DeleteAnchorReq 删除主播请求
|
||||
type DeleteAnchorReq struct {
|
||||
g.Meta `path:"/deleteAnchor" method:"delete" tags:"主播管理" summary:"删除主播" dc:"删除主播"`
|
||||
Id int64 `json:"id" v:"required" dc:"主播ID"`
|
||||
}
|
||||
|
||||
// UpdateAnchorStatusReq 更新主播状态请求
|
||||
type UpdateAnchorStatusReq struct {
|
||||
g.Meta `path:"/updateAnchorStatus" method:"put" tags:"主播管理" summary:"更新主播状态" dc:"更新主播状态"`
|
||||
Id int64 `json:"id" v:"required" dc:"主播ID"`
|
||||
Status data.AnchorStatus `json:"status" v:"required" dc:"状态(0停用 1正常)"`
|
||||
}
|
||||
89
model/dto/data/live_account_dto.go
Normal file
89
model/dto/data/live_account_dto.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"erp/consts/data"
|
||||
entity "erp/model/entity/data"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// CreateLiveAccountReq 创建直播账号请求
|
||||
type CreateLiveAccountReq struct {
|
||||
g.Meta `path:"/createLiveAccount" method:"post" tags:"直播账号管理" summary:"创建直播账号" dc:"创建新的直播账号"`
|
||||
Platform string `json:"platform" v:"required" dc:"直播平台(抖音/快手/淘宝等)"`
|
||||
AccountName string `json:"accountName" v:"required" dc:"账号名称"`
|
||||
AccountId string `json:"accountId" v:"required" dc:"账号ID"`
|
||||
Status int `json:"status" d:"1" dc:"状态(0停用 1正常)"`
|
||||
Remark string `json:"remark" dc:"备注"`
|
||||
}
|
||||
|
||||
// CreateLiveAccountRes 创建直播账号响应
|
||||
type CreateLiveAccountRes struct {
|
||||
Id int64 `json:"id" dc:"账号ID"`
|
||||
}
|
||||
|
||||
// ListLiveAccountReq 获取直播账号列表请求
|
||||
type ListLiveAccountReq struct {
|
||||
g.Meta `path:"/listLiveAccounts" method:"get" tags:"直播账号管理" summary:"获取直播账号列表" dc:"分页查询直播账号列表"`
|
||||
*beans.Page
|
||||
Platform string `json:"platform" dc:"直播平台"`
|
||||
AccountName string `json:"accountName" dc:"账号名称"`
|
||||
AccountId string `json:"accountId" dc:"账号ID"`
|
||||
Status *int `json:"status" dc:"状态(0停用 1正常)"`
|
||||
Keyword string `json:"keyword" dc:"关键字(搜索平台/账号名称/账号ID)"`
|
||||
}
|
||||
|
||||
// ListLiveAccountRes 获取直播账号列表响应
|
||||
type ListLiveAccountRes struct {
|
||||
List []LiveAccountItem `json:"list" dc:"直播账号列表"`
|
||||
Total int `json:"total" dc:"总数"`
|
||||
}
|
||||
|
||||
// LiveAccountItem 直播账号列表项
|
||||
type LiveAccountItem struct {
|
||||
Id int64 `json:"id,string"`
|
||||
Platform string `json:"platform"`
|
||||
AccountName string `json:"accountName"`
|
||||
AccountId string `json:"accountId"`
|
||||
Status int `json:"status"`
|
||||
StatusName string `json:"statusName"`
|
||||
Remark string `json:"remark"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
UpdatedAt int64 `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// GetLiveAccountReq 获取直播账号详情请求
|
||||
type GetLiveAccountReq struct {
|
||||
g.Meta `path:"/getLiveAccount" method:"get" tags:"直播账号管理" summary:"获取直播账号详情" dc:"获取直播账号详情"`
|
||||
Id int64 `json:"id" v:"required" dc:"账号ID"`
|
||||
}
|
||||
|
||||
// GetLiveAccountRes 获取直播账号详情响应
|
||||
type GetLiveAccountRes struct {
|
||||
*entity.LiveAccount
|
||||
}
|
||||
|
||||
// UpdateLiveAccountReq 更新直播账号请求
|
||||
type UpdateLiveAccountReq struct {
|
||||
g.Meta `path:"/updateLiveAccount" method:"put" tags:"直播账号管理" summary:"更新直播账号" dc:"更新直播账号信息"`
|
||||
Id int64 `json:"id" v:"required" dc:"账号ID"`
|
||||
Platform string `json:"platform" dc:"直播平台"`
|
||||
AccountName string `json:"accountName" dc:"账号名称"`
|
||||
AccountId string `json:"accountId" dc:"账号ID"`
|
||||
Status *int `json:"status" dc:"状态(0停用 1正常)"`
|
||||
Remark string `json:"remark" dc:"备注"`
|
||||
}
|
||||
|
||||
// DeleteLiveAccountReq 删除直播账号请求
|
||||
type DeleteLiveAccountReq struct {
|
||||
g.Meta `path:"/deleteLiveAccount" method:"delete" tags:"直播账号管理" summary:"删除直播账号" dc:"删除直播账号"`
|
||||
Id int64 `json:"id" v:"required" dc:"账号ID"`
|
||||
}
|
||||
|
||||
// UpdateLiveAccountStatusReq 更新直播账号状态请求
|
||||
type UpdateLiveAccountStatusReq struct {
|
||||
g.Meta `path:"/updateLiveAccountStatus" method:"put" tags:"直播账号管理" summary:"更新直播账号状态" dc:"更新直播账号状态"`
|
||||
Id int64 `json:"id" v:"required" dc:"账号ID"`
|
||||
Status data.AnchorStatus `json:"status" v:"required" dc:"状态(0停用 1正常)"`
|
||||
}
|
||||
102
model/dto/data/schedule_dto.go
Normal file
102
model/dto/data/schedule_dto.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"erp/consts/data"
|
||||
entity "erp/model/entity/data"
|
||||
"time"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// CreateScheduleReq 创建排班请求
|
||||
type CreateScheduleReq struct {
|
||||
g.Meta `path:"/createSchedule" method:"post" tags:"排班管理" summary:"创建排班" dc:"创建新的排班"`
|
||||
AnchorId int `json:"anchorId" v:"required" dc:"主播ID"`
|
||||
AccountId int `json:"accountId" v:"required" dc:"直播账号ID"`
|
||||
StartTime time.Time `json:"startTime" v:"required" dc:"开始时间"`
|
||||
EndTime time.Time `json:"endTime" v:"required" dc:"结束时间"`
|
||||
Status int `json:"status" d:"0" dc:"状态(0待直播 1直播中 2已结束 3已取消)"`
|
||||
ProductId int64 `json:"productId" dc:"商品ID"`
|
||||
OrderId int64 `json:"orderId" dc:"订单ID"`
|
||||
Remark string `json:"remark" dc:"备注"`
|
||||
}
|
||||
|
||||
// CreateScheduleRes 创建排班响应
|
||||
type CreateScheduleRes struct {
|
||||
Id int64 `json:"id" dc:"排班ID"`
|
||||
}
|
||||
|
||||
// ListScheduleReq 获取排班列表请求
|
||||
type ListScheduleReq struct {
|
||||
g.Meta `path:"/listSchedules" method:"get" tags:"排班管理" summary:"获取排班列表" dc:"分页查询排班列表"`
|
||||
*beans.Page
|
||||
AnchorId *int `json:"anchorId" dc:"主播ID"`
|
||||
AccountId *int `json:"accountId" dc:"直播账号ID"`
|
||||
Status *int `json:"status" dc:"状态"`
|
||||
StartDate time.Time `json:"startDate" dc:"开始日期(筛选)"`
|
||||
EndDate time.Time `json:"endDate" dc:"结束日期(筛选)"`
|
||||
}
|
||||
|
||||
// ListScheduleRes 获取排班列表响应
|
||||
type ListScheduleRes struct {
|
||||
List []ScheduleItem `json:"list" dc:"排班列表"`
|
||||
Total int `json:"total" dc:"总数"`
|
||||
}
|
||||
|
||||
// ScheduleItem 排班列表项
|
||||
type ScheduleItem struct {
|
||||
Id int64 `json:"id,string"`
|
||||
AnchorId int `json:"anchorId"`
|
||||
AnchorName string `json:"anchorName"`
|
||||
AccountId int `json:"accountId"`
|
||||
AccountName string `json:"accountName"`
|
||||
Platform string `json:"platform"`
|
||||
StartTime int64 `json:"startTime"`
|
||||
EndTime int64 `json:"endTime"`
|
||||
Status int `json:"status"`
|
||||
StatusName string `json:"statusName"`
|
||||
ProductId int64 `json:"productId"`
|
||||
OrderId int64 `json:"orderId"`
|
||||
Remark string `json:"remark"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
UpdatedAt int64 `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// GetScheduleReq 获取排班详情请求
|
||||
type GetScheduleReq struct {
|
||||
g.Meta `path:"/getSchedule" method:"get" tags:"排班管理" summary:"获取排班详情" dc:"获取排班详情"`
|
||||
Id int64 `json:"id" v:"required" dc:"排班ID"`
|
||||
}
|
||||
|
||||
// GetScheduleRes 获取排班详情响应
|
||||
type GetScheduleRes struct {
|
||||
*entity.Schedule
|
||||
}
|
||||
|
||||
// UpdateScheduleReq 更新排班请求
|
||||
type UpdateScheduleReq struct {
|
||||
g.Meta `path:"/updateSchedule" method:"put" tags:"排班管理" summary:"更新排班" dc:"更新排班信息"`
|
||||
Id int64 `json:"id" v:"required" dc:"排班ID"`
|
||||
AnchorId *int `json:"anchorId" dc:"主播ID"`
|
||||
AccountId *int `json:"accountId" dc:"直播账号ID"`
|
||||
StartTime *time.Time `json:"startTime" dc:"开始时间"`
|
||||
EndTime *time.Time `json:"endTime" dc:"结束时间"`
|
||||
Status *int `json:"status" dc:"状态(0待直播 1直播中 2已结束 3已取消)"`
|
||||
ProductId *int64 `json:"productId" dc:"商品ID"`
|
||||
OrderId *int64 `json:"orderId" dc:"订单ID"`
|
||||
Remark string `json:"remark" dc:"备注"`
|
||||
}
|
||||
|
||||
// DeleteScheduleReq 删除排班请求
|
||||
type DeleteScheduleReq struct {
|
||||
g.Meta `path:"/deleteSchedule" method:"delete" tags:"排班管理" summary:"删除排班" dc:"删除排班"`
|
||||
Id int64 `json:"id" v:"required" dc:"排班ID"`
|
||||
}
|
||||
|
||||
// UpdateScheduleStatusReq 更新排班状态请求
|
||||
type UpdateScheduleStatusReq struct {
|
||||
g.Meta `path:"/updateScheduleStatus" method:"put" tags:"排班管理" summary:"更新排班状态" dc:"更新排班状态"`
|
||||
Id int64 `json:"id" v:"required" dc:"排班ID"`
|
||||
Status data.ScheduleStatus `json:"status" v:"required" dc:"状态(0待直播 1直播中 2已结束 3已取消)"`
|
||||
}
|
||||
35
model/entity/data/anchor.go
Normal file
35
model/entity/data/anchor.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
// Anchor 主播实体
|
||||
type Anchor struct {
|
||||
beans.SQLBaseDO `orm:",inherit"`
|
||||
Name string `orm:"name" json:"name" description:"主播姓名"`
|
||||
Phone string `orm:"phone" json:"phone" description:"联系电话"`
|
||||
Code string `orm:"code" json:"code" description:"工号"`
|
||||
Status int `orm:"status" json:"status" description:"状态(0停用 1正常)"`
|
||||
Remark string `orm:"remark" json:"remark" description:"备注"`
|
||||
}
|
||||
|
||||
// AnchorCol 主播表字段定义
|
||||
type AnchorCol struct {
|
||||
beans.SQLBaseCol
|
||||
Name string
|
||||
Phone string
|
||||
Code string
|
||||
Status string
|
||||
Remark string
|
||||
}
|
||||
|
||||
// AnchorCols 主播表字段常量
|
||||
var AnchorCols = AnchorCol{
|
||||
SQLBaseCol: beans.DefSQLBaseCol,
|
||||
Name: "name",
|
||||
Phone: "phone",
|
||||
Code: "code",
|
||||
Status: "status",
|
||||
Remark: "remark",
|
||||
}
|
||||
35
model/entity/data/live_account.go
Normal file
35
model/entity/data/live_account.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
// LiveAccount 直播账号实体
|
||||
type LiveAccount struct {
|
||||
beans.SQLBaseDO `orm:",inherit"`
|
||||
Platform string `orm:"platform" json:"platform" description:"直播平台(抖音/快手/淘宝等)"`
|
||||
AccountName string `orm:"account_name" json:"accountName" description:"账号名称"`
|
||||
AccountId string `orm:"account_id" json:"accountId" description:"账号ID"`
|
||||
Status int `orm:"status" json:"status" description:"状态(0停用 1正常)"`
|
||||
Remark string `orm:"remark" json:"remark" description:"备注"`
|
||||
}
|
||||
|
||||
// LiveAccountCol 直播账号表字段定义
|
||||
type LiveAccountCol struct {
|
||||
beans.SQLBaseCol
|
||||
Platform string
|
||||
AccountName string
|
||||
AccountId string
|
||||
Status string
|
||||
Remark string
|
||||
}
|
||||
|
||||
// LiveAccountCols 直播账号表字段常量
|
||||
var LiveAccountCols = LiveAccountCol{
|
||||
SQLBaseCol: beans.DefSQLBaseCol,
|
||||
Platform: "platform",
|
||||
AccountName: "account_name",
|
||||
AccountId: "account_id",
|
||||
Status: "status",
|
||||
Remark: "remark",
|
||||
}
|
||||
46
model/entity/data/schedule.go
Normal file
46
model/entity/data/schedule.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
// Schedule 排班实体
|
||||
type Schedule struct {
|
||||
beans.SQLBaseDO `orm:",inherit"`
|
||||
AnchorId int `orm:"anchor_id" json:"anchorId" description:"主播ID"`
|
||||
AccountId int `orm:"account_id" json:"accountId" description:"直播账号ID"`
|
||||
StartTime time.Time `orm:"start_time" json:"startTime" description:"开始时间"`
|
||||
EndTime time.Time `orm:"end_time" json:"endTime" description:"结束时间"`
|
||||
Status int `orm:"status" json:"status" description:"状态(0待直播 1直播中 2已结束 3已取消)"`
|
||||
ProductId int64 `orm:"product_id" json:"productId" description:"商品ID"`
|
||||
OrderId int64 `orm:"order_id" json:"orderId" description:"订单ID"`
|
||||
Remark string `orm:"remark" json:"remark" description:"备注"`
|
||||
}
|
||||
|
||||
// ScheduleCol 排班表字段定义
|
||||
type ScheduleCol struct {
|
||||
beans.SQLBaseCol
|
||||
AnchorId string
|
||||
AccountId string
|
||||
StartTime string
|
||||
EndTime string
|
||||
Status string
|
||||
ProductId string
|
||||
OrderId string
|
||||
Remark string
|
||||
}
|
||||
|
||||
// ScheduleCols 排班表字段常量
|
||||
var ScheduleCols = ScheduleCol{
|
||||
SQLBaseCol: beans.DefSQLBaseCol,
|
||||
AnchorId: "anchor_id",
|
||||
AccountId: "account_id",
|
||||
StartTime: "start_time",
|
||||
EndTime: "end_time",
|
||||
Status: "status",
|
||||
ProductId: "product_id",
|
||||
OrderId: "order_id",
|
||||
Remark: "remark",
|
||||
}
|
||||
133
service/data/anchor_service.go
Normal file
133
service/data/anchor_service.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"context"
|
||||
consts "erp/consts/data"
|
||||
dao "erp/dao/data"
|
||||
dto "erp/model/dto/data"
|
||||
entity "erp/model/entity/data"
|
||||
"errors"
|
||||
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
type anchorService struct{}
|
||||
|
||||
// Anchor 主播服务
|
||||
var Anchor = new(anchorService)
|
||||
|
||||
// Create 创建主播
|
||||
func (s *anchorService) Create(ctx context.Context, req *dto.CreateAnchorReq) (res *dto.CreateAnchorRes, err error) {
|
||||
// 检查工号是否重复
|
||||
existAnchor, err := dao.Anchor.GetByCode(ctx, req.Code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existAnchor != nil {
|
||||
return nil, errors.New("工号已存在")
|
||||
}
|
||||
|
||||
// 插入数据库
|
||||
id, err := dao.Anchor.Insert(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
res = &dto.CreateAnchorRes{
|
||||
Id: id,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// List 获取主播列表
|
||||
func (s *anchorService) List(ctx context.Context, req *dto.ListAnchorReq) (res *dto.ListAnchorRes, err error) {
|
||||
anchorList, total, err := dao.Anchor.List(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 组装响应数据
|
||||
list := make([]dto.AnchorItem, 0, len(anchorList))
|
||||
for _, item := range anchorList {
|
||||
list = append(list, dto.AnchorItem{
|
||||
Id: item.Id,
|
||||
Name: item.Name,
|
||||
Phone: item.Phone,
|
||||
Code: item.Code,
|
||||
Status: item.Status,
|
||||
StatusName: consts.AnchorStatus(item.Status).String(),
|
||||
Remark: item.Remark,
|
||||
CreatedAt: item.CreatedAt.Unix(),
|
||||
UpdatedAt: item.UpdatedAt.Unix(),
|
||||
})
|
||||
}
|
||||
|
||||
res = &dto.ListAnchorRes{
|
||||
List: list,
|
||||
Total: total,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取单个主播
|
||||
func (s *anchorService) GetOne(ctx context.Context, req *dto.GetAnchorReq) (res *dto.GetAnchorRes, err error) {
|
||||
anchor, err := dao.Anchor.GetOne(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var anchorEntity *entity.Anchor
|
||||
if err = gconv.Struct(anchor, &anchorEntity); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return &dto.GetAnchorRes{
|
||||
Anchor: anchorEntity,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Update 更新主播
|
||||
func (s *anchorService) Update(ctx context.Context, req *dto.UpdateAnchorReq) (err error) {
|
||||
// 检查主播是否存在
|
||||
exist, err := dao.Anchor.GetOne(ctx, &dto.GetAnchorReq{Id: req.Id})
|
||||
if err != nil || exist == nil {
|
||||
return errors.New("主播不存在")
|
||||
}
|
||||
|
||||
// 如果修改了工号,检查新工号是否重复
|
||||
if req.Code != "" && req.Code != exist.Code {
|
||||
existAnchor, err := dao.Anchor.GetByCode(ctx, req.Code)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existAnchor != nil {
|
||||
return errors.New("工号已存在")
|
||||
}
|
||||
}
|
||||
|
||||
_, err = dao.Anchor.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus 更新主播状态
|
||||
func (s *anchorService) UpdateStatus(ctx context.Context, req *dto.UpdateAnchorStatusReq) (err error) {
|
||||
_, err = dao.Anchor.UpdateStatus(ctx, req.Id, int(req.Status))
|
||||
return
|
||||
}
|
||||
|
||||
// Delete 删除主播
|
||||
func (s *anchorService) Delete(ctx context.Context, req *dto.DeleteAnchorReq) (err error) {
|
||||
// 检查是否存在关联的排班
|
||||
anchorId := int(req.Id)
|
||||
schedules, _, err := dao.Schedule.List(ctx, &dto.ListScheduleReq{
|
||||
AnchorId: &anchorId,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(schedules) > 0 {
|
||||
return errors.New("该主播存在排班记录,无法删除")
|
||||
}
|
||||
|
||||
_, err = dao.Anchor.Delete(ctx, req)
|
||||
return
|
||||
}
|
||||
133
service/data/live_account_service.go
Normal file
133
service/data/live_account_service.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"context"
|
||||
consts "erp/consts/data"
|
||||
dao "erp/dao/data"
|
||||
dto "erp/model/dto/data"
|
||||
entity "erp/model/entity/data"
|
||||
"errors"
|
||||
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
type liveAccountService struct{}
|
||||
|
||||
// LiveAccount 直播账号服务
|
||||
var LiveAccount = new(liveAccountService)
|
||||
|
||||
// Create 创建直播账号
|
||||
func (s *liveAccountService) Create(ctx context.Context, req *dto.CreateLiveAccountReq) (res *dto.CreateLiveAccountRes, err error) {
|
||||
// 检查账号ID是否重复
|
||||
existAccount, err := dao.LiveAccount.GetByAccountId(ctx, req.AccountId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existAccount != nil {
|
||||
return nil, errors.New("账号ID已存在")
|
||||
}
|
||||
|
||||
// 插入数据库
|
||||
id, err := dao.LiveAccount.Insert(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
res = &dto.CreateLiveAccountRes{
|
||||
Id: id,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// List 获取直播账号列表
|
||||
func (s *liveAccountService) List(ctx context.Context, req *dto.ListLiveAccountReq) (res *dto.ListLiveAccountRes, err error) {
|
||||
accountList, total, err := dao.LiveAccount.List(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 组装响应数据
|
||||
list := make([]dto.LiveAccountItem, 0, len(accountList))
|
||||
for _, item := range accountList {
|
||||
list = append(list, dto.LiveAccountItem{
|
||||
Id: item.Id,
|
||||
Platform: item.Platform,
|
||||
AccountName: item.AccountName,
|
||||
AccountId: item.AccountId,
|
||||
Status: item.Status,
|
||||
StatusName: consts.AnchorStatus(item.Status).String(),
|
||||
Remark: item.Remark,
|
||||
CreatedAt: item.CreatedAt.Unix(),
|
||||
UpdatedAt: item.UpdatedAt.Unix(),
|
||||
})
|
||||
}
|
||||
|
||||
res = &dto.ListLiveAccountRes{
|
||||
List: list,
|
||||
Total: total,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取单个直播账号
|
||||
func (s *liveAccountService) GetOne(ctx context.Context, req *dto.GetLiveAccountReq) (res *dto.GetLiveAccountRes, err error) {
|
||||
account, err := dao.LiveAccount.GetOne(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var accountEntity *entity.LiveAccount
|
||||
if err = gconv.Struct(account, &accountEntity); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return &dto.GetLiveAccountRes{
|
||||
LiveAccount: accountEntity,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Update 更新直播账号
|
||||
func (s *liveAccountService) Update(ctx context.Context, req *dto.UpdateLiveAccountReq) (err error) {
|
||||
// 检查直播账号是否存在
|
||||
exist, err := dao.LiveAccount.GetOne(ctx, &dto.GetLiveAccountReq{Id: req.Id})
|
||||
if err != nil || exist == nil {
|
||||
return errors.New("直播账号不存在")
|
||||
}
|
||||
|
||||
// 如果修改了账号ID,检查新账号ID是否重复
|
||||
if req.AccountId != "" && req.AccountId != exist.AccountId {
|
||||
existAccount, err := dao.LiveAccount.GetByAccountId(ctx, req.AccountId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existAccount != nil {
|
||||
return errors.New("账号ID已存在")
|
||||
}
|
||||
}
|
||||
|
||||
_, err = dao.LiveAccount.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus 更新直播账号状态
|
||||
func (s *liveAccountService) UpdateStatus(ctx context.Context, req *dto.UpdateLiveAccountStatusReq) (err error) {
|
||||
_, err = dao.LiveAccount.UpdateStatus(ctx, req.Id, int(req.Status))
|
||||
return
|
||||
}
|
||||
|
||||
// Delete 删除直播账号
|
||||
func (s *liveAccountService) Delete(ctx context.Context, req *dto.DeleteLiveAccountReq) (err error) {
|
||||
// 检查是否存在关联的排班
|
||||
accountId := int(req.Id)
|
||||
schedules, _, err := dao.Schedule.List(ctx, &dto.ListScheduleReq{
|
||||
AccountId: &accountId,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(schedules) > 0 {
|
||||
return errors.New("该账号存在排班记录,无法删除")
|
||||
}
|
||||
|
||||
_, err = dao.LiveAccount.Delete(ctx, req)
|
||||
return
|
||||
}
|
||||
226
service/data/schedule_service.go
Normal file
226
service/data/schedule_service.go
Normal file
@@ -0,0 +1,226 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"context"
|
||||
consts "erp/consts/data"
|
||||
dao "erp/dao/data"
|
||||
dto "erp/model/dto/data"
|
||||
entity "erp/model/entity/data"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
type scheduleService struct{}
|
||||
|
||||
// Schedule 排班服务
|
||||
var Schedule = new(scheduleService)
|
||||
|
||||
// Create 创建排班
|
||||
func (s *scheduleService) Create(ctx context.Context, req *dto.CreateScheduleReq) (res *dto.CreateScheduleRes, err error) {
|
||||
// 检查开始时间是否小于结束时间
|
||||
if req.StartTime.After(req.EndTime) || req.StartTime.Equal(req.EndTime) {
|
||||
return nil, errors.New("开始时间必须早于结束时间")
|
||||
}
|
||||
|
||||
// 检查主播是否存在
|
||||
_, err = dao.Anchor.GetOne(ctx, &dto.GetAnchorReq{Id: int64(req.AnchorId)})
|
||||
if err != nil {
|
||||
return nil, errors.New("主播不存在")
|
||||
}
|
||||
|
||||
// 检查直播账号是否存在
|
||||
_, err = dao.LiveAccount.GetOne(ctx, &dto.GetLiveAccountReq{Id: int64(req.AccountId)})
|
||||
if err != nil {
|
||||
return nil, errors.New("直播账号不存在")
|
||||
}
|
||||
|
||||
// 检查时间冲突
|
||||
conflictCount, err := dao.Schedule.CheckTimeConflict(ctx, req.AnchorId, req.StartTime, req.EndTime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if conflictCount > 0 {
|
||||
return nil, errors.New("该主播在此时间段已有排班")
|
||||
}
|
||||
|
||||
// 插入数据库
|
||||
id, err := dao.Schedule.Insert(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
res = &dto.CreateScheduleRes{
|
||||
Id: id,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// List 获取排班列表
|
||||
func (s *scheduleService) List(ctx context.Context, req *dto.ListScheduleReq) (res *dto.ListScheduleRes, err error) {
|
||||
scheduleList, total, err := dao.Schedule.List(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 组装响应数据
|
||||
list := make([]dto.ScheduleItem, 0, len(scheduleList))
|
||||
for _, item := range scheduleList {
|
||||
// 获取主播信息
|
||||
anchorName := ""
|
||||
anchor, _ := dao.Anchor.GetOne(ctx, &dto.GetAnchorReq{Id: int64(item.AnchorId)})
|
||||
if anchor != nil {
|
||||
anchorName = anchor.Name
|
||||
}
|
||||
|
||||
// 获取账号信息
|
||||
accountName := ""
|
||||
platform := ""
|
||||
account, _ := dao.LiveAccount.GetOne(ctx, &dto.GetLiveAccountReq{Id: int64(item.AccountId)})
|
||||
if account != nil {
|
||||
accountName = account.AccountName
|
||||
platform = account.Platform
|
||||
}
|
||||
|
||||
list = append(list, dto.ScheduleItem{
|
||||
Id: item.Id,
|
||||
AnchorId: item.AnchorId,
|
||||
AnchorName: anchorName,
|
||||
AccountId: item.AccountId,
|
||||
AccountName: accountName,
|
||||
Platform: platform,
|
||||
StartTime: item.StartTime.Unix(),
|
||||
EndTime: item.EndTime.Unix(),
|
||||
Status: item.Status,
|
||||
StatusName: consts.ScheduleStatus(item.Status).String(),
|
||||
ProductId: item.ProductId,
|
||||
OrderId: item.OrderId,
|
||||
Remark: item.Remark,
|
||||
CreatedAt: item.CreatedAt.Unix(),
|
||||
UpdatedAt: item.UpdatedAt.Unix(),
|
||||
})
|
||||
}
|
||||
|
||||
res = &dto.ListScheduleRes{
|
||||
List: list,
|
||||
Total: total,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取单个排班
|
||||
func (s *scheduleService) GetOne(ctx context.Context, req *dto.GetScheduleReq) (res *dto.GetScheduleRes, err error) {
|
||||
schedule, err := dao.Schedule.GetOne(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var scheduleEntity *entity.Schedule
|
||||
if err = gconv.Struct(schedule, &scheduleEntity); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return &dto.GetScheduleRes{
|
||||
Schedule: scheduleEntity,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Update 更新排班
|
||||
func (s *scheduleService) Update(ctx context.Context, req *dto.UpdateScheduleReq) (err error) {
|
||||
// 检查排班是否存在
|
||||
exist, err := dao.Schedule.GetOne(ctx, &dto.GetScheduleReq{Id: req.Id})
|
||||
if err != nil || exist == nil {
|
||||
return errors.New("排班不存在")
|
||||
}
|
||||
|
||||
// 如果修改了时间,检查时间合法性
|
||||
startTime := exist.StartTime
|
||||
endTime := exist.EndTime
|
||||
if req.StartTime != nil {
|
||||
startTime = *req.StartTime
|
||||
}
|
||||
if req.EndTime != nil {
|
||||
endTime = *req.EndTime
|
||||
}
|
||||
if startTime.After(endTime) || startTime.Equal(endTime) {
|
||||
return errors.New("开始时间必须早于结束时间")
|
||||
}
|
||||
|
||||
// 如果修改了主播或时间,检查时间冲突
|
||||
anchorId := exist.AnchorId
|
||||
if req.AnchorId != nil {
|
||||
anchorId = *req.AnchorId
|
||||
// 检查主播是否存在
|
||||
_, err = dao.Anchor.GetOne(ctx, &dto.GetAnchorReq{Id: int64(anchorId)})
|
||||
if err != nil {
|
||||
return errors.New("主播不存在")
|
||||
}
|
||||
}
|
||||
|
||||
conflictCount, err := dao.Schedule.CheckTimeConflict(ctx, anchorId, startTime, endTime, req.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if conflictCount > 0 {
|
||||
return errors.New("该主播在此时间段已有排班")
|
||||
}
|
||||
|
||||
// 如果修改了账号,检查账号是否存在
|
||||
if req.AccountId != nil {
|
||||
_, err = dao.LiveAccount.GetOne(ctx, &dto.GetLiveAccountReq{Id: int64(*req.AccountId)})
|
||||
if err != nil {
|
||||
return errors.New("直播账号不存在")
|
||||
}
|
||||
}
|
||||
|
||||
_, err = dao.Schedule.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus 更新排班状态
|
||||
func (s *scheduleService) UpdateStatus(ctx context.Context, req *dto.UpdateScheduleStatusReq) (err error) {
|
||||
_, err = dao.Schedule.UpdateStatus(ctx, req.Id, int(req.Status))
|
||||
return
|
||||
}
|
||||
|
||||
// Delete 删除排班
|
||||
func (s *scheduleService) Delete(ctx context.Context, req *dto.DeleteScheduleReq) (err error) {
|
||||
// 检查排班是否存在且未开始
|
||||
schedule, err := dao.Schedule.GetOne(ctx, &dto.GetScheduleReq{Id: req.Id})
|
||||
if err != nil || schedule == nil {
|
||||
return errors.New("排班不存在")
|
||||
}
|
||||
|
||||
// 如果已经开始或结束,不允许删除
|
||||
if schedule.Status != 0 {
|
||||
return errors.New("只能删除待直播的排班")
|
||||
}
|
||||
|
||||
_, err = dao.Schedule.Delete(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// GetTodaySchedules 获取今日排班
|
||||
func (s *scheduleService) GetTodaySchedules(ctx context.Context) (res *dto.ListScheduleRes, err error) {
|
||||
now := time.Now()
|
||||
startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||
endOfDay := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location())
|
||||
|
||||
req := &dto.ListScheduleReq{
|
||||
StartDate: startOfDay,
|
||||
EndDate: endOfDay,
|
||||
}
|
||||
|
||||
return s.List(ctx, req)
|
||||
}
|
||||
|
||||
// GetAnchorSchedules 获取主播排班
|
||||
func (s *scheduleService) GetAnchorSchedules(ctx context.Context, anchorId int, startDate, endDate time.Time) (res *dto.ListScheduleRes, err error) {
|
||||
req := &dto.ListScheduleReq{
|
||||
AnchorId: &anchorId,
|
||||
StartDate: startDate,
|
||||
EndDate: endDate,
|
||||
}
|
||||
|
||||
return s.List(ctx, req)
|
||||
}
|
||||
160
update.sql
Normal file
160
update.sql
Normal file
@@ -0,0 +1,160 @@
|
||||
-- auto-generated definition
|
||||
create table schedule
|
||||
(
|
||||
id bigserial
|
||||
primary key,
|
||||
anchor_id bigint default 0 not null,
|
||||
account_id bigint default 0 not null,
|
||||
start_time timestamp not null,
|
||||
end_time timestamp not null,
|
||||
status smallint default 0 not null,
|
||||
remark varchar(500) default ''::character varying not null,
|
||||
created_by bigint default 0 not null,
|
||||
updated_by bigint default 0 not null,
|
||||
created_at timestamp default CURRENT_TIMESTAMP not null,
|
||||
updated_at timestamp default CURRENT_TIMESTAMP not null,
|
||||
deleted_at timestamp,
|
||||
tenant_id bigint default 0,
|
||||
product_id bigint default 0,
|
||||
order_id bigint default 0
|
||||
);
|
||||
|
||||
comment on table schedule is '排班表';
|
||||
|
||||
comment on column schedule.id is '排班ID';
|
||||
|
||||
comment on column schedule.anchor_id is '主播ID';
|
||||
|
||||
comment on column schedule.account_id is '直播账号ID';
|
||||
|
||||
comment on column schedule.start_time is '开始时间';
|
||||
|
||||
comment on column schedule.end_time is '结束时间';
|
||||
|
||||
comment on column schedule.status is '状态(0待直播 1直播中 2已结束 3已取消)';
|
||||
|
||||
comment on column schedule.remark is '备注';
|
||||
|
||||
comment on column schedule.created_by is '创建人';
|
||||
|
||||
comment on column schedule.updated_by is '修改人';
|
||||
|
||||
comment on column schedule.created_at is '创建时间';
|
||||
|
||||
comment on column schedule.updated_at is '修改时间';
|
||||
|
||||
comment on column schedule.deleted_at is '删除时间';
|
||||
|
||||
comment on column schedule.product_id is '商品ID';
|
||||
|
||||
comment on column schedule.order_id is '订单ID';
|
||||
|
||||
alter table schedule
|
||||
owner to postgres;
|
||||
|
||||
create index idx_schedule_tenant_id
|
||||
on schedule (tenant_id);
|
||||
|
||||
|
||||
|
||||
|
||||
-- auto-generated definition
|
||||
create table anchor
|
||||
(
|
||||
id bigint default nextval('anchor_id_seq'::regclass) not null
|
||||
primary key,
|
||||
name varchar(50) default ''::character varying not null,
|
||||
phone varchar(20) default ''::character varying not null,
|
||||
code varchar(255) default ''::character varying not null,
|
||||
status smallint default 1 not null,
|
||||
remark varchar(500) default ''::character varying not null,
|
||||
created_by bigint default 0 not null,
|
||||
updated_by bigint default 0 not null,
|
||||
created_at timestamp default CURRENT_TIMESTAMP not null,
|
||||
updated_at timestamp default CURRENT_TIMESTAMP not null,
|
||||
deleted_at timestamp,
|
||||
tenant_id bigint default 0
|
||||
);
|
||||
|
||||
comment on table anchor is '主播表';
|
||||
|
||||
comment on column anchor.id is '主播ID';
|
||||
|
||||
comment on column anchor.name is '主播姓名';
|
||||
|
||||
comment on column anchor.phone is '联系电话';
|
||||
|
||||
comment on column anchor.code is '工号';
|
||||
|
||||
comment on column anchor.status is '状态(0停用 1正常)';
|
||||
|
||||
comment on column anchor.remark is '备注';
|
||||
|
||||
comment on column anchor.created_by is '创建人';
|
||||
|
||||
comment on column anchor.updated_by is '修改人';
|
||||
|
||||
comment on column anchor.created_at is '创建时间';
|
||||
|
||||
comment on column anchor.updated_at is '修改时间';
|
||||
|
||||
comment on column anchor.deleted_at is '删除时间';
|
||||
|
||||
alter table anchor
|
||||
owner to postgres;
|
||||
|
||||
create index idx_anchor_tenant_id
|
||||
on anchor (tenant_id);
|
||||
|
||||
|
||||
|
||||
|
||||
-- auto-generated definition
|
||||
create table live_account
|
||||
(
|
||||
id bigint default nextval('live_account_id_seq'::regclass) not null
|
||||
primary key,
|
||||
platform varchar(50) default ''::character varying not null,
|
||||
account_name varchar(100) default ''::character varying not null,
|
||||
account_id varchar(100) default ''::character varying not null,
|
||||
status smallint default 1 not null,
|
||||
remark varchar(500) default ''::character varying not null,
|
||||
created_by bigint default 0 not null,
|
||||
updated_by bigint default 0 not null,
|
||||
created_at timestamp default CURRENT_TIMESTAMP not null,
|
||||
updated_at timestamp default CURRENT_TIMESTAMP not null,
|
||||
deleted_at timestamp,
|
||||
tenant_id bigint default 0
|
||||
);
|
||||
|
||||
comment on table live_account is '直播账号表';
|
||||
|
||||
comment on column live_account.id is '账号ID';
|
||||
|
||||
comment on column live_account.platform is '直播平台(抖音/快手/淘宝等)';
|
||||
|
||||
comment on column live_account.account_name is '账号名称';
|
||||
|
||||
comment on column live_account.account_id is '账号ID';
|
||||
|
||||
comment on column live_account.status is '状态(0停用 1正常)';
|
||||
|
||||
comment on column live_account.remark is '备注';
|
||||
|
||||
comment on column live_account.created_by is '创建人';
|
||||
|
||||
comment on column live_account.updated_by is '修改人';
|
||||
|
||||
comment on column live_account.created_at is '创建时间';
|
||||
|
||||
comment on column live_account.updated_at is '修改时间';
|
||||
|
||||
comment on column live_account.deleted_at is '删除时间';
|
||||
|
||||
alter table live_account
|
||||
owner to postgres;
|
||||
|
||||
create index idx_live_account_tenant_id
|
||||
on live_account (tenant_id);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user