diff --git a/cmd/server/wire_gen.go b/cmd/server/wire_gen.go index d0d356c..a64d80c 100644 --- a/cmd/server/wire_gen.go +++ b/cmd/server/wire_gen.go @@ -28,21 +28,22 @@ func InitializeApp(configConfig *config.Config, allLogger log.AllLogger) (*serve platImpl := impl.NewPlatImpl(db) publishImpl := impl.NewPublishImpl(db) loginRelationImpl := impl.NewLoginRelationImpl(db) + articleTypeImpl := impl.NewArticleTypeImpl(db) publishBiz := biz.NewPublishBiz(configConfig, publishImpl, userImpl, platImpl, tokenImpl, loginRelationImpl) authBiz := biz.NewAuthBiz(configConfig, tokenImpl, userImpl) appService := service.NewAppService(configConfig, tokenImpl, userImpl, platImpl, publishBiz, authBiz, loginRelationImpl) loginService := service.NewLoginService(configConfig, publishBiz, authBiz) publishService := service.NewPublishService(configConfig, publishBiz, authBiz, db) productImpl := impl.NewProductImpl(db) - productService := service.NewProductService(configConfig, productImpl, authBiz) - aiBiz := biz.NewAiBiz(platImpl) productSourceImpl := impl.NewProductSourceImpl(db) oss, err := utils_oss.NewClient(configConfig) if err != nil { panic(err) } productBiz := biz.NewProductBiz(productImpl, productSourceImpl, configConfig, oss) - productSourceService := service.NewProductSourceService(configConfig, productImpl, authBiz, aiBiz, productBiz, productSourceImpl) + productService := service.NewProductService(configConfig, productImpl, authBiz, productBiz) + aiBiz := biz.NewAiBiz(platImpl) + productSourceService := service.NewProductSourceService(configConfig, productImpl, authBiz, aiBiz, productBiz, productSourceImpl, publishBiz, articleTypeImpl) appModule := router.NewAppModule(configConfig, appService, loginService, publishService, productService, productSourceService) routerServer := router.NewRouterServer(appModule) app := server.NewHTTPServer(routerServer) diff --git a/internal/biz/product.go b/internal/biz/product.go index 38459cc..f43222c 100644 --- a/internal/biz/product.go +++ b/internal/biz/product.go @@ -52,6 +52,7 @@ func (p *ProductBiz) CreateAndUploadArticle(ctx context.Context, content string, mdAbs := filepath.Join(p.cfg.Sys.MdDir, fileName) // 创建并写入文件 file, err := os.Create(mdAbs) + defer os.Remove(mdAbs) if err != nil { return "", fmt.Errorf("创建文件失败: %w", err) } @@ -66,6 +67,7 @@ func (p *ProductBiz) CreateAndUploadArticle(ctx context.Context, content string, } docxPath, err := pkg.Md2wordFix(mdAbs, p.cfg.Sys.MdDir, imgs) + defer os.Remove(docxPath) if err != nil { return "", err } @@ -76,7 +78,7 @@ func (p *ProductBiz) CreateAndUploadArticle(ctx context.Context, content string, return "", err } - url, err := p.oss.UploadBytes(docxName, fileByte) + url, err := p.SourceUpload(ctx, fileByte, docxName) if err != nil { return "", fmt.Errorf("上传文件失败: %w", err) } @@ -89,7 +91,7 @@ func (p *ProductBiz) AddSource(ctx context.Context, source *model.ProductSource) } func (p *ProductBiz) SourceUpload(ctx context.Context, file []byte, fileName string) (string, error) { - url, err := p.oss.UploadBytes(fileName, file) + url, err := p.oss.UploadBytes(p.cfg.Oss.FilePath+fileName, file) if err != nil { return "", fmt.Errorf("上传文件失败: %w", err) } diff --git a/internal/config/config.go b/internal/config/config.go index dc4e484..dda1758 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -20,6 +20,7 @@ type Oss struct { Bucket string `mapstructure:"bucket"` Domain string `mapstructure:"domain"` Endpoint string `mapstructure:"endpoint"` + FilePath string `mapstructure:"filepath"` } // ServerConfig 服务器配置 @@ -95,6 +96,7 @@ func LoadConfig() (*Config, error) { Bucket: "attachment-public", Domain: "https://attachment-public.oss-cn-hangzhou.aliyuncs.com", Endpoint: "https://oss-cn-hangzhou.aliyuncs.com", + FilePath: "geo/", }, }, nil } diff --git a/internal/data/impl/publish.go b/internal/data/impl/publish.go index 9d551d1..a380ffe 100644 --- a/internal/data/impl/publish.go +++ b/internal/data/impl/publish.go @@ -203,7 +203,7 @@ func (p *PublishImpl) GetListWithUser(ctx context.Context, tokenID int32, page, `). Joins("LEFT JOIN user u ON p.user_index COLLATE utf8mb4_unicode_ci = u.user_index"). Joins("LEFT JOIN plat pl ON p.plat_index COLLATE utf8mb4_unicode_ci = pl.index"). - Where("u.token_id = ?", tokenID) + Where("u.token_id = ?", tokenID).Order("publish_time desc") // 添加过滤条件 if userIndex, ok := filters["user_index"]; ok && userIndex != "" { diff --git a/internal/data/model/product.gen.go b/internal/data/model/product.gen.go index db22884..eefeb9a 100644 --- a/internal/data/model/product.gen.go +++ b/internal/data/model/product.gen.go @@ -26,7 +26,7 @@ type Product struct { Background string `gorm:"column:background;comment:信任背书" json:"background"` // 信任背书 Case string `gorm:"column:case;comment:品牌案例" json:"case"` // 品牌案例 Other string `gorm:"column:other;comment:其他信息" json:"other"` // 其他信息 - ServiceCope string `gorm:"column:service_cope;comment:服务范围" json:"service_cope"` // 服务范围 + ServiceScope string `gorm:"column:service_scope;comment:服务范围" json:"service_scope"` // 服务范围 TargetAudience string `gorm:"column:target_audience;comment:目标客户群体" json:"target_audience"` // 目标客户群体 Imgs string `gorm:"column:imgs;comment:图片" json:"imgs"` // 图片 CreatedAt time.Time `gorm:"column:created_at" json:"created_at"` diff --git a/internal/data/model/publish.gen.go b/internal/data/model/publish.gen.go index 6318312..d64ab5e 100644 --- a/internal/data/model/publish.gen.go +++ b/internal/data/model/publish.gen.go @@ -14,6 +14,7 @@ const TableNamePublish = "publish" type Publish struct { ID int64 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"` TokenID int32 `gorm:"column:token_id;not null" json:"token_id"` + SourceID int32 `gorm:"column:source_id;not null" json:"source_id"` UserIndex string `gorm:"column:user_index;not null;comment:关联user.user_index" json:"user_index"` // 关联user.user_index RequestID string `gorm:"column:request_id;not null;comment:日志id" json:"request_id"` // 日志id Title string `gorm:"column:title;not null" json:"title"` diff --git a/internal/entitys/request.go b/internal/entitys/request.go index f719458..6f24fb2 100644 --- a/internal/entitys/request.go +++ b/internal/entitys/request.go @@ -24,6 +24,11 @@ type ( UserIndex string `json:"user_index" validate:"required" zh:"用户索引"` } + PlatListRequest struct { + AccessToken string `json:"access_token" validate:"required" zh:"access_token"` + PlatType int `json:"plat_type" zh:"平台类型"` + } + PublishRecordsRequest struct { AccessToken string `json:"access_token" validate:"required" zh:"access_token"` Records []PublishRecordItem `json:"records" validate:"required" zh:"发布记录"` @@ -100,7 +105,8 @@ type ( Background string `json:"background" zh:"信任背书"` Case string `json:"case" zh:"品牌案例"` Other string `json:"other" zh:"其他信息"` - ServiceCope string `json:"service_cope" zh:"服务范围"` + ServiceScope string `json:"service_scope" zh:"服务范围"` + Imgs string `json:"imgs" zh:"图片"` TargetAudience string `json:"target_audience" zh:"目标客户群体"` } @@ -111,6 +117,11 @@ type ( PageSize int `json:"page_size"` } + ProductDetailRequest struct { + AccessToken string `json:"access_token" validate:"required" zh:"access_token"` + Id int32 `json:"id" validate:"required" zh:"id"` + } + ProductUpdateRequest struct { AccessToken string `json:"access_token" validate:"required" zh:"access_token"` Id int32 `json:"id" validate:"required" zh:"id"` @@ -125,6 +136,7 @@ type ( Case string `json:"case" zh:"品牌案例"` Other string `json:"other" zh:"其他信息"` ServiceCope string `json:"service_cope" zh:"服务范围"` + Imgs string `json:"imgs" zh:"图片"` TargetAudience string `json:"target_audience" zh:"目标客户群体"` } @@ -133,6 +145,11 @@ type ( Id int32 `json:"id" validate:"required" zh:"产品id"` } + ImageUploadRequest struct { + AccessToken string `json:"access_token" validate:"required" zh:"access_token"` + Id int32 `json:"id" validate:"required" zh:"产品id"` + } + ProductSourceCreateRequest struct { AccessToken string `json:"access_token" validate:"required" zh:"access_token"` ProductId int32 `json:"product_id" validate:"required" zh:"产品id"` @@ -153,14 +170,21 @@ type ( } ProductSourceUpdateRequest struct { - AccessToken string `json:"access_token" validate:"required" zh:"access_token"` - SourceId int32 `json:"source_id" validate:"required" zh:"资源id"` - Title string `json:"title" zh:"标题"` - Tag []string `json:"tag" zh:"标题"` + AccessToken string `json:"access_token" validate:"required" zh:"access_token"` + SourceId int32 `json:"source_id" validate:"required" zh:"资源id"` + Title *string `json:"title" zh:"标题"` + Tag *[]string `json:"tag" zh:"标题"` } ProductSourceDelRequest struct { AccessToken string `json:"access_token" validate:"required" zh:"access_token"` SourceId int32 `json:"source_id" validate:"required" zh:"资源id"` } + + ProductPublishRequest struct { + AccessToken string `json:"access_token" validate:"required" zh:"access_token"` + SourceId int32 `json:"source_id" validate:"required" zh:"资源id"` + Plat []string `json:"plat" validate:"required" zh:"平台"` + PublishTime string `json:"publish_time" validate:"required" zh:"发布时间"` + } ) diff --git a/internal/publisher/baijiahao.go b/internal/publisher/baijiahao.go index 06e9c92..827b0d7 100644 --- a/internal/publisher/baijiahao.go +++ b/internal/publisher/baijiahao.go @@ -29,23 +29,6 @@ func (p *BaijiahaoPublisher) CheckLoginStatus() bool { return true } -func (p *BaijiahaoPublisher) CheckLogin() (bool, string) { - - if err := p.SetupDriver(); err != nil { - return false, fmt.Sprintf("浏览器启动失败: %v", err) - } - - p.Page.MustNavigate(p.EditorURL) - p.Sleep(3) - p.WaitForPageReady(5) - - if p.CheckLoginStatus() { - p.SaveCookies() - return true, "已登录" - } - return false, "未登录" -} - func (p *BaijiahaoPublisher) WaitLogin() (bool, string) { if err := p.SetupDriver(); err != nil { diff --git a/internal/publisher/base.go b/internal/publisher/base.go index 1e6cd06..0ed2f13 100644 --- a/internal/publisher/base.go +++ b/internal/publisher/base.go @@ -333,10 +333,6 @@ func (p *BasePublisher) CheckLoginStatus() bool { return true } -func (b *BasePublisher) CheckLogin() (bool, string) { - return false, "需要实现" -} - func (b *BasePublisher) PublishNote() (bool, string) { return false, "需要实现" } diff --git a/internal/publisher/csdn.go b/internal/publisher/csdn.go index eeb558d..8082dd1 100644 --- a/internal/publisher/csdn.go +++ b/internal/publisher/csdn.go @@ -19,25 +19,6 @@ func NewCSDNPublisher(ctx context.Context, task *TaskParams, cfg *config.Config, return &CSDNPublisher{NewBasePublisher(ctx, task, cfg, logger)} } -func (p *CSDNPublisher) CheckLogin() (bool, string) { - p.LogInfo("检查登录状态...") - - if err := p.SetupDriver(); err != nil { - return false, fmt.Sprintf("浏览器启动失败: %v", err) - } - defer p.Close() - - p.Page.MustNavigate(p.EditorURL) - p.Sleep(2) - p.WaitForPageReady(3) - - if p.CheckLoginStatus() { - p.SaveCookies() - return true, "已登录" - } - return false, "未登录" -} - func (p *CSDNPublisher) WaitLogin() (bool, string) { p.LogInfo("开始等待登录...") diff --git a/internal/publisher/dysp.go b/internal/publisher/dysp.go index 3c9e91a..509c1db 100644 --- a/internal/publisher/dysp.go +++ b/internal/publisher/dysp.go @@ -21,25 +21,6 @@ func NewDouyinSpPublisher(ctx context.Context, task *TaskParams, cfg *config.Con return &DouyinSpPublisher{NewBasePublisher(ctx, task, cfg, logger)} } -func (p *DouyinSpPublisher) CheckLogin() (bool, string) { - p.LogInfo("检查登录状态...") - - if err := p.SetupDriver(); err != nil { - return false, fmt.Sprintf("浏览器启动失败: %v", err) - } - defer p.Close() - - p.Page.MustNavigate(p.EditorURL) - p.Sleep(3) - p.WaitForPageReady(5) - - if p.CheckLoginStatus() { - p.SaveCookies() - return true, "已登录" - } - return false, "未登录" -} - func (p *DouyinSpPublisher) CheckLoginStatus() bool { currentURL := p.GetCurrentURL() if strings.Contains(currentURL, p.LoginedURL) { diff --git a/internal/publisher/js.go b/internal/publisher/js.go index 14e4919..6860dc1 100644 --- a/internal/publisher/js.go +++ b/internal/publisher/js.go @@ -20,25 +20,6 @@ func NewJianshuPublisher(ctx context.Context, task *TaskParams, cfg *config.Conf return &JianshuPublisher{NewBasePublisher(ctx, task, cfg, logger)} } -func (p *JianshuPublisher) CheckLogin() (bool, string) { - p.LogInfo("检查登录状态...") - - if err := p.SetupDriver(); err != nil { - return false, fmt.Sprintf("浏览器启动失败: %v", err) - } - defer p.Close() - - p.Page.MustNavigate(p.EditorURL) - p.Sleep(3) - p.WaitForPageReady(5) - - if p.CheckLoginStatus() { - p.SaveCookies() - return true, "已登录" - } - return false, "未登录" -} - func (p *JianshuPublisher) CheckLoginStatus() bool { currentURL := p.GetCurrentURL() if strings.Contains(currentURL, p.LoginURL) { diff --git a/internal/publisher/shh.go b/internal/publisher/shh.go index b6c44ca..8ea575b 100644 --- a/internal/publisher/shh.go +++ b/internal/publisher/shh.go @@ -20,25 +20,6 @@ func NewSohuPublisher(ctx context.Context, task *TaskParams, cfg *config.Config, return &SohuPublisher{NewBasePublisher(ctx, task, cfg, logger)} } -func (p *SohuPublisher) CheckLogin() (bool, string) { - p.LogInfo("检查登录状态...") - - if err := p.SetupDriver(); err != nil { - return false, fmt.Sprintf("浏览器启动失败: %v", err) - } - defer p.Close() - - p.Page.MustNavigate(p.EditorURL) - p.Sleep(3) - p.WaitForPageReady(5) - - if p.CheckLoginStatus() { - p.SaveCookies() - return true, "已登录" - } - return false, "未登录" -} - func (p *SohuPublisher) CheckLoginStatus() bool { currentURL := p.GetCurrentURL() if strings.Contains(currentURL, p.LoginURL) { diff --git a/internal/publisher/sphsp.go b/internal/publisher/sphsp.go index 794a9ee..73fe478 100644 --- a/internal/publisher/sphsp.go +++ b/internal/publisher/sphsp.go @@ -23,25 +23,6 @@ func NewShipinhaoVideoPublisher(ctx context.Context, task *TaskParams, config *c } } -func (p *ShipinhaoVideoPublisher) CheckLogin() (bool, string) { - p.LogInfo("检查登录状态...") - - if err := p.SetupDriver(); err != nil { - return false, fmt.Sprintf("浏览器启动失败: %v", err) - } - defer p.Close() - - p.Page.MustNavigate(p.LoginedURL) - p.Sleep(3) - p.WaitForPageReady(5) - - if p.CheckLoginStatus() { - p.SaveCookies() - return true, "已登录" - } - return false, "未登录" -} - func (p *ShipinhaoVideoPublisher) CheckLoginStatus() bool { currentURL := p.GetCurrentURL() if strings.Contains(currentURL, "login") || strings.Contains(currentURL, "passport") { diff --git a/internal/publisher/toutiao.go b/internal/publisher/toutiao.go index 3fe871d..5d5b7ec 100644 --- a/internal/publisher/toutiao.go +++ b/internal/publisher/toutiao.go @@ -21,25 +21,6 @@ func NewToutiaoPublisher(ctx context.Context, task *TaskParams, cfg *config.Conf return &ToutiaoPublisher{NewBasePublisher(ctx, task, cfg, logger)} } -func (p *ToutiaoPublisher) CheckLogin() (bool, string) { - p.LogInfo("检查登录状态...") - - if err := p.SetupDriver(); err != nil { - return false, fmt.Sprintf("浏览器启动失败: %v", err) - } - defer p.Close() - - p.Page.MustNavigate(p.EditorURL) - p.Sleep(2) - p.WaitForPageReady(5) - - if p.CheckLoginStatus() { - p.SaveCookies() - return true, "已登录" - } - return false, "未登录" -} - func (p *ToutiaoPublisher) CheckLoginStatus() bool { currentURL := p.GetCurrentURL() // 如果在登录页面,未登录 diff --git a/internal/publisher/wyh.go b/internal/publisher/wyh.go index 39934e1..ea695d4 100644 --- a/internal/publisher/wyh.go +++ b/internal/publisher/wyh.go @@ -28,25 +28,6 @@ func NewWangyiPublisher(ctx context.Context, task *TaskParams, cfg *config.Confi } } -func (p *WangyiPublisher) CheckLogin() (bool, string) { - p.LogInfo("检查登录状态...") - - if err := p.SetupDriver(); err != nil { - return false, fmt.Sprintf("浏览器启动失败: %v", err) - } - defer p.Page.Close() - - p.Page.MustNavigate(p.EditorURL) - p.Sleep(3) - p.WaitForPageReady(5) - - if p.CheckLoginStatus() { - p.SaveCookies() - return true, "已登录" - } - return false, "未登录" -} - func (p *WangyiPublisher) CheckLoginStatus() bool { currentURL := p.GetCurrentURL() diff --git a/internal/publisher/xhs.go b/internal/publisher/xhs.go index 9519db0..dbf1616 100644 --- a/internal/publisher/xhs.go +++ b/internal/publisher/xhs.go @@ -21,25 +21,6 @@ func NewXiaohongshuPublisher(ctx context.Context, task *TaskParams, cfg *config. return &XiaohongshuPublisher{NewBasePublisher(ctx, task, cfg, logger)} } -func (p *XiaohongshuPublisher) CheckLogin() (bool, string) { - p.LogInfo("检查登录状态...") - - if err := p.SetupDriver(); err != nil { - return false, fmt.Sprintf("浏览器启动失败: %v", err) - } - defer p.Close() - - p.Page.MustNavigate(p.LoginedURL) - p.Sleep(3) - //p.WaitForPageReady(5) - - if p.CheckLoginStatus() { - p.SaveCookies() - return true, "已登录" - } - return false, "未登录" -} - func (p *XiaohongshuPublisher) WaitLogin() (bool, string) { p.LogInfo("开始等待登录...") diff --git a/internal/publisher/xhssp.go b/internal/publisher/xhssp.go index 9d2a377..12a8af5 100644 --- a/internal/publisher/xhssp.go +++ b/internal/publisher/xhssp.go @@ -29,25 +29,6 @@ func NewXiaohongshuVideoPublisher(ctx context.Context, task *TaskParams, cfg *co } } -func (p *XiaohongshuVideoPublisher) CheckLogin() (bool, string) { - p.LogInfo("检查登录状态...") - - if err := p.SetupDriver(); err != nil { - return false, fmt.Sprintf("浏览器启动失败: %v", err) - } - defer p.Page.Close() - - p.Page.MustNavigate(p.LoginedURL) - p.Sleep(3) - p.WaitForPageReady(5) - - if p.CheckLoginStatus() { - p.SaveCookies() - return true, "已登录" - } - return false, "未登录" -} - func (p *XiaohongshuVideoPublisher) WaitLogin() (bool, string) { p.LogInfo("开始等待登录...") diff --git a/internal/publisher/zh.go b/internal/publisher/zh.go index c102e5e..6dbe57b 100644 --- a/internal/publisher/zh.go +++ b/internal/publisher/zh.go @@ -20,25 +20,6 @@ func NewZhihuPublisher(ctx context.Context, task *TaskParams, cfg *config.Config return &ZhihuPublisher{NewBasePublisher(ctx, task, cfg, logger)} } -func (p *ZhihuPublisher) CheckLogin() (bool, string) { - p.LogInfo("检查登录状态...") - - if err := p.SetupDriver(); err != nil { - return false, fmt.Sprintf("浏览器启动失败: %v", err) - } - defer p.Page.Close() - - p.Page.MustNavigate(p.EditorURL) - p.Sleep(3) - p.WaitForPageReady(5) - - if p.CheckLoginStatus() { - p.SaveCookies() - return true, "已登录" - } - return false, "未登录" -} - func (p *ZhihuPublisher) CheckLoginStatus() bool { currentURL := p.GetCurrentURL() if strings.Contains(currentURL, p.LoginURL) { diff --git a/internal/server/router/app.go b/internal/server/router/app.go index d838d7e..1954727 100644 --- a/internal/server/router/app.go +++ b/internal/server/router/app.go @@ -53,12 +53,17 @@ func (m *AppModule) Register(router fiber.Router) { router.Post("/product/add", vali(m.productService.Add, &entitys.CreateProductRequest{})) router.Post("/product/list", vali(m.productService.List, &entitys.ProductListRequest{})) + router.Post("/product/detail", vali(m.productService.Detail, &entitys.ProductDetailRequest{})) router.Post("/product/update", vali(m.productService.Update, &entitys.ProductUpdateRequest{})) router.Post("/product/del", vali(m.productService.Del, &entitys.ProductDelRequest{})) + router.Post("/img/upload", m.productService.ImgUpload) + router.Post("/plat/list", vali(m.appService.PlatList, &entitys.PlatListRequest{})) + router.Get("/product/word/article_type_list", m.productSourceService.ArticalTypeList) router.Post("/product/word/create", vali(m.productSourceService.Create, &entitys.ProductSourceCreateRequest{})) router.Post("/product/source/list", vali(m.productSourceService.List, &entitys.ProductSourceListRequest{})) router.Post("/product/source/upload", m.productSourceService.UploadSource) router.Post("/product/source/update", vali(m.productSourceService.Update, &entitys.ProductSourceUpdateRequest{})) router.Post("/product/source/del", vali(m.productSourceService.Del, &entitys.ProductSourceDelRequest{})) + router.Post("/product/source/publish", vali(m.productSourceService.Publish, &entitys.ProductPublishRequest{})) } diff --git a/internal/service/app.go b/internal/service/app.go index d85b026..bde4e4d 100644 --- a/internal/service/app.go +++ b/internal/service/app.go @@ -2,7 +2,6 @@ package service import ( "fmt" - "github.com/gofiber/fiber/v2" "xorm.io/builder" @@ -191,3 +190,21 @@ func (a *AppService) GetApp(c *fiber.Ctx, req *entitys.GetAppRequest) error { return pkg.HandleResponse(c, result) } + +func (a *AppService) PlatList(c *fiber.Ctx, req *entitys.PlatListRequest) error { + _, err := a.authBiz.ValidateAccessToken(c.UserContext(), req.AccessToken) + if err != nil { + return err + } + + cond := builder.NewCond(). + And(builder.Eq{"status": 1}) + if req.PlatType != 0 { + cond.And(builder.Eq{"plat_type": req.PlatType}) + } + list, err := a.platImpl.GetRange(c.UserContext(), &cond) + if err != nil { + return err + } + return pkg.HandleResponse(c, list) +} diff --git a/internal/service/product.go b/internal/service/product.go index 424ab59..8f9e4a4 100644 --- a/internal/service/product.go +++ b/internal/service/product.go @@ -8,9 +8,10 @@ import ( "geo/internal/entitys" "geo/pkg" "geo/tmpl/dataTemp" - + "geo/tmpl/errcode" "github.com/go-viper/mapstructure/v2" "github.com/gofiber/fiber/v2" + "io" "xorm.io/builder" ) @@ -18,13 +19,15 @@ type ProductService struct { cfg *config.Config productImpl *impl.ProductImpl authBiz *biz.AuthBiz + productBiz *biz.ProductBiz } -func NewProductService(cfg *config.Config, ProductImpl *impl.ProductImpl, authBiz *biz.AuthBiz) *ProductService { +func NewProductService(cfg *config.Config, ProductImpl *impl.ProductImpl, authBiz *biz.AuthBiz, productBiz *biz.ProductBiz) *ProductService { return &ProductService{ cfg: cfg, productImpl: ProductImpl, authBiz: authBiz, + productBiz: productBiz, } } @@ -45,6 +48,21 @@ func (p *ProductService) Add(c *fiber.Ctx, req *entitys.CreateProductRequest) er return nil } +func (p *ProductService) Detail(c *fiber.Ctx, req *entitys.ProductDetailRequest) error { + _, err := p.authBiz.ValidateAccessToken(c.UserContext(), req.AccessToken) + if err != nil { + return err + } + var detail model.Product + cond := builder.NewCond(). + And(builder.Eq{"id": req.Id}) + err = p.productImpl.GetOneBySearchStruct(c.UserContext(), &cond, &detail) + if err != nil { + return err + } + return pkg.HandleResponse(c, detail) +} + func (p *ProductService) List(c *fiber.Ctx, req *entitys.ProductListRequest) error { _, _, err := p.authBiz.UserAndTokenValid(c.UserContext(), req.UserIndex, req.AccessToken) if err != nil { @@ -95,3 +113,42 @@ func (p *ProductService) Del(c *fiber.Ctx, req *entitys.ProductDelRequest) error err = p.productImpl.DeleteByKey(c.UserContext(), p.productImpl.PrimaryKey(), req.Id) return nil } + +func (p *ProductService) ImgUpload(c *fiber.Ctx) error { + access := c.FormValue("access_token", "") + if access == "" { + return errcode.ParamErr("access_token未找到") + } + // 验证token + _, err := p.authBiz.ValidateAccessToken(c.UserContext(), access) + if err != nil { + return err + } + + fileHeader, err := c.FormFile("file") + if err != nil { + return errcode.ParamErr("未找到上传文件") + } + file, err := fileHeader.Open() + if err != nil { + return errcode.ParamErrf("无法打开文件:%S", err.Error()) + } + defer file.Close() + + fileBytes, err := io.ReadAll(file) + if err != nil { + return errcode.ParamErrf("读取文件失败:%s", err.Error()) + } + + // 获取文件扩展名 + ext := pkg.GetFileExtension(fileHeader.Filename) + + // 根据图片类型生成文件名 + fileName := pkg.GenerateImageFileName(ext) + + url, err := p.productBiz.SourceUpload(c.UserContext(), fileBytes, fileName) + if err != nil { + return err + } + return pkg.HandleResponse(c, fiber.Map{"url": url}) +} diff --git a/internal/service/product_source.go b/internal/service/product_source.go index 16cf2bd..620c4a4 100644 --- a/internal/service/product_source.go +++ b/internal/service/product_source.go @@ -25,12 +25,23 @@ type ProductSourceService struct { cfg *config.Config productImpl *impl.ProductImpl productSourceImpl *impl.ProductSourceImpl + articleTypeImpl *impl.ArticleTypeImpl authBiz *biz.AuthBiz aiBiz *biz.AiBiz productBiz *biz.ProductBiz + publishBiz *biz.PublishBiz } -func NewProductSourceService(cfg *config.Config, ProductImpl *impl.ProductImpl, authBiz *biz.AuthBiz, aiBiz *biz.AiBiz, productBiz *biz.ProductBiz, productSource *impl.ProductSourceImpl) *ProductSourceService { +func NewProductSourceService( + cfg *config.Config, + ProductImpl *impl.ProductImpl, + authBiz *biz.AuthBiz, + aiBiz *biz.AiBiz, + productBiz *biz.ProductBiz, + productSource *impl.ProductSourceImpl, + publishBiz *biz.PublishBiz, + articleTypeImpl *impl.ArticleTypeImpl, +) *ProductSourceService { return &ProductSourceService{ cfg: cfg, productImpl: ProductImpl, @@ -38,6 +49,8 @@ func NewProductSourceService(cfg *config.Config, ProductImpl *impl.ProductImpl, aiBiz: aiBiz, productBiz: productBiz, productSourceImpl: productSource, + publishBiz: publishBiz, + articleTypeImpl: articleTypeImpl, } } @@ -175,11 +188,11 @@ func (p *ProductSourceService) Update(c *fiber.Ctx, req *entitys.ProductSourceUp return err } var update = &model.ProductSource{} - if req.Title != "" { - update.Title = req.Title + if req.Title != nil { + update.Title = *req.Title } - if len(req.Tag) > 0 { - update.Tag = strings.Join(req.Tag, ",") + if req.Tag != nil { + update.Tag = strings.Join(*req.Tag, ",") } return p.productBiz.UpdateSourceById(c.UserContext(), req.SourceId, update) @@ -194,3 +207,63 @@ func (p *ProductSourceService) Del(c *fiber.Ctx, req *entitys.ProductSourceDelRe return p.productBiz.DelSourceById(c.UserContext(), req.SourceId) } + +func (p *ProductSourceService) Publish(c *fiber.Ctx, req *entitys.ProductPublishRequest) error { + // 验证token + tokenInfo, err := p.authBiz.ValidateAccessToken(c.UserContext(), req.AccessToken) + if err != nil { + return err + } + var source model.ProductSource + err = p.productSourceImpl.GetByKey(c.UserContext(), p.productSourceImpl.PrimaryKey(), req.SourceId, &source) + if err != nil { + return err + } + var product model.Product + err = p.productImpl.GetByKey(c.UserContext(), p.productImpl.PrimaryKey(), source.ProductId, &product) + if err != nil { + return err + } + if product.Imgs == "" { + return errcode.NotFound("请先上传产品图片") + } + ptime, err := time.Parse(time.DateTime, req.PublishTime) + if err != nil { + return errcode.ParamErr("发布时间格式错误") + } + var validRecords = make([]*model.Publish, 0, len(req.Plat)) + for _, v := range req.Plat { + validRecords = append(validRecords, &model.Publish{ + UserIndex: product.UserIndex, + SourceID: req.SourceId, + RequestID: fmt.Sprintf("%s_%d", pkg.GenerateRandomLowerString(3), time.Now().UnixNano()), + Title: source.Title, + Tag: source.Tag, + Type: source.SourceType, + PlatIndex: v, + URL: source.SourceURL, + PublishTime: ptime, + Img: strings.Split(product.Imgs, ",")[0], + TokenID: tokenInfo.ID, + }) + + } + err = p.publishBiz.BatchInsertPublish(c.UserContext(), validRecords) + if err != nil { + return err + } + + return pkg.HandleResponse(c, fiber.Map{ + "total": len(validRecords), + }) +} + +func (p *ProductSourceService) ArticalTypeList(c *fiber.Ctx) error { + cond := builder.NewCond(). + And(builder.Eq{"status": 1}) + list, err := p.articleTypeImpl.GetRange(c.UserContext(), &cond) + if err != nil { + return err + } + return pkg.HandleResponse(c, list) +} diff --git a/pkg/func.go b/pkg/func.go index 00e20b6..be144c3 100644 --- a/pkg/func.go +++ b/pkg/func.go @@ -353,3 +353,20 @@ func ReadDocxToBytes(filePath string) ([]byte, error) { return data, nil } + +// getFileExtension 获取文件扩展名 +func GetFileExtension(filename string) string { + parts := strings.Split(filename, ".") + if len(parts) < 2 { + return ".jpg" // 默认扩展名 + } + return "." + parts[len(parts)-1] +} + +// generateImageFileName 根据图片类型生成文件名 +func GenerateImageFileName(ext string) string { + // 生成唯一标识 + timestamp := time.Now().UnixNano() / 1e6 // 毫秒级时间戳 + randomNum := GenerateRandomLowerString(3) // 随机数 + return fmt.Sprintf("img_%d%s%s", timestamp, randomNum, ext) +} diff --git a/pkg/rand.go b/pkg/rand.go new file mode 100644 index 0000000..5f6ec77 --- /dev/null +++ b/pkg/rand.go @@ -0,0 +1,41 @@ +package pkg + +import ( + "math/rand/v2" +) + +// GenerateRandomStringCustom 使用自定义字符集 +func GenerateRandomStringCustom(n int, charset string) string { + result := make([]byte, n) + for i := range result { + result[i] = charset[rand.IntN(len(charset))] + } + return string(result) +} + +// 纯数字字符串 +func GenerateRandomNumberString(n int) string { + return GenerateRandomStringCustom(n, "0123456789") +} + +// 纯小写字母 +func GenerateRandomLowerString(n int) string { + return GenerateRandomStringCustom(n, "abcdefghijklmnopqrstuvwxyz") +} + +// 纯大写字母 +func GenerateRandomUpperString(n int) string { + return GenerateRandomStringCustom(n, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") +} + +// 使用自定义随机源(例如固定种子) +func GenerateRandomStringWithSeed(n int, seed uint64) string { + const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + + rng := rand.New(rand.NewPCG(seed, seed)) + result := make([]byte, n) + for i := range result { + result[i] = charset[rng.IntN(len(charset))] + } + return string(result) +} diff --git a/pkg/response.go b/pkg/response.go index 7df9813..7cdb570 100644 --- a/pkg/response.go +++ b/pkg/response.go @@ -36,3 +36,22 @@ func SuccessWithPageMsg(c *fiber.Ctx, list interface{}, total int64, page, pageS } return HandleResponse(c, response) } + +func HandleResponseWithErr(c *fiber.Ctx, data interface{}, errs error) (err error) { + if errs != nil { + err = errs + return + } + switch data.(type) { + case error: + err = data.(error) + case int, int32, int64, float32, float64, string, bool: + c.Response().SetBody([]byte(fmt.Sprintf("%s", data))) + case []byte: + c.Response().SetBody(data.([]byte)) + default: + dataByte, _ := json.Marshal(data) + c.Response().SetBody(dataByte) + } + return +}