587 lines
24 KiB
Go
587 lines
24 KiB
Go
package sys
|
||
|
||
import (
|
||
"context"
|
||
"crypto/sha256"
|
||
"encoding/hex"
|
||
"encoding/json"
|
||
"fmt"
|
||
"strconv"
|
||
"strings"
|
||
|
||
"hotgo/internal/consts"
|
||
"hotgo/internal/dao"
|
||
"hotgo/internal/library/contexts"
|
||
"hotgo/internal/library/hgorm/handler"
|
||
"hotgo/internal/library/hgorm/hook"
|
||
"hotgo/internal/model/entity"
|
||
"hotgo/internal/model/input/sysin"
|
||
"hotgo/internal/service"
|
||
|
||
"github.com/gogf/gf/v2/database/gdb"
|
||
"github.com/gogf/gf/v2/encoding/gjson"
|
||
"github.com/gogf/gf/v2/errors/gerror"
|
||
"github.com/gogf/gf/v2/frame/g"
|
||
"github.com/gogf/gf/v2/os/gtime"
|
||
"github.com/gogf/gf/v2/util/grand"
|
||
)
|
||
|
||
type sSysPortal struct{}
|
||
|
||
func NewSysPortal() *sSysPortal { return &sSysPortal{} }
|
||
func init() { service.RegisterSysPortal(NewSysPortal()) }
|
||
|
||
func (s *sSysPortal) siteModel(ctx context.Context) *gdb.Model {
|
||
return handler.Model(dao.SiteConfigVersion.Ctx(ctx), &handler.Option{FilterTenant: true})
|
||
}
|
||
func (s *sSysPortal) contentModel(ctx context.Context) *gdb.Model {
|
||
return handler.Model(dao.Content.Ctx(ctx), &handler.Option{FilterTenant: true})
|
||
}
|
||
func (s *sSysPortal) contentVersionModel(ctx context.Context) *gdb.Model {
|
||
return handler.Model(dao.ContentVersion.Ctx(ctx), &handler.Option{FilterTenant: true})
|
||
}
|
||
func (s *sSysPortal) bannerModel(ctx context.Context) *gdb.Model {
|
||
return handler.Model(dao.Banner.Ctx(ctx), &handler.Option{FilterTenant: true})
|
||
}
|
||
func (s *sSysPortal) productModel(ctx context.Context) *gdb.Model {
|
||
return handler.Model(dao.Product.Ctx(ctx), &handler.Option{FilterTenant: true})
|
||
}
|
||
|
||
func (s *sSysPortal) SiteConfigCurrent(ctx context.Context, in *sysin.SiteConfigCurrentInp) (res *sysin.SiteConfigCurrentModel, err error) {
|
||
res = new(sysin.SiteConfigCurrentModel)
|
||
c := dao.SiteConfigVersion.Columns()
|
||
if err = s.siteModel(ctx).Where(c.ConfigGroup, in.ConfigGroup).WhereIn(c.PublishStatus, []int{consts.BizPublishDraft, consts.BizPublishPending}).OrderDesc(c.Id).Limit(1).Scan(&res.Draft); err != nil {
|
||
return nil, gerror.Wrap(err, "获取站点配置草稿失败")
|
||
}
|
||
if err = s.siteModel(ctx).Where(c.ConfigGroup, in.ConfigGroup).Where(c.PublishStatus, consts.BizPublishPublished).OrderDesc(c.Id).Limit(1).Scan(&res.Published); err != nil {
|
||
return nil, gerror.Wrap(err, "获取已发布站点配置失败")
|
||
}
|
||
return res, nil
|
||
}
|
||
|
||
func (s *sSysPortal) SiteConfigHistory(ctx context.Context, in *sysin.SiteConfigHistoryInp) (list []*sysin.SiteConfigHistoryModel, totalCount int, err error) {
|
||
c := dao.SiteConfigVersion.Columns()
|
||
err = s.siteModel(ctx).Fields(sysin.SiteConfigHistoryModel{}).Where(c.ConfigGroup, in.ConfigGroup).Page(in.Page, in.PerPage).OrderDesc(c.Id).ScanAndCount(&list, &totalCount, false)
|
||
if err != nil {
|
||
err = gerror.Wrap(err, "获取配置版本记录失败")
|
||
}
|
||
return
|
||
}
|
||
|
||
func (s *sSysPortal) SiteConfigSave(ctx context.Context, in *sysin.SiteConfigSaveInp) (id uint64, err error) {
|
||
raw, err := json.Marshal(in.Config)
|
||
if err != nil {
|
||
return 0, gerror.Wrap(err, "序列化站点配置失败")
|
||
}
|
||
sum := sha256.Sum256(raw)
|
||
digest := hex.EncodeToString(sum[:])
|
||
userId := uint64(contexts.GetUserId(ctx))
|
||
c := dao.SiteConfigVersion.Columns()
|
||
now := gtime.Now()
|
||
if in.Id > 0 {
|
||
_, _ = s.siteModel(ctx).
|
||
Where(c.ConfigGroup, in.ConfigGroup).
|
||
Where(c.PublishStatus, consts.BizPublishPublished).
|
||
WhereNot(c.Id, in.Id).
|
||
Data(gdb.Map{c.PublishStatus: consts.BizPublishOffline, c.UpdatedBy: userId}).
|
||
Update()
|
||
result, updateErr := s.siteModel(ctx).
|
||
WherePri(in.Id).
|
||
Where(c.Version, in.Version).
|
||
Data(gdb.Map{
|
||
c.ConfigJson: gjson.New(raw),
|
||
c.ConfigDigest: digest,
|
||
c.PublishStatus: consts.BizPublishPublished,
|
||
c.EffectiveAt: in.EffectiveAt,
|
||
c.PublishedAt: now,
|
||
c.ApprovalRequestId: 0,
|
||
c.Remark: in.Remark,
|
||
c.UpdatedBy: userId,
|
||
c.Version: gdb.Raw(c.Version + "+1"),
|
||
}).Update()
|
||
if updateErr != nil {
|
||
return 0, gerror.Wrap(updateErr, "保存站点配置失败")
|
||
}
|
||
rows, _ := result.RowsAffected()
|
||
if rows == 0 {
|
||
return 0, gerror.New("配置已更新,请刷新后重试")
|
||
}
|
||
return in.Id, nil
|
||
}
|
||
_, _ = s.siteModel(ctx).
|
||
Where(c.ConfigGroup, in.ConfigGroup).
|
||
Where(c.PublishStatus, consts.BizPublishPublished).
|
||
Data(gdb.Map{c.PublishStatus: consts.BizPublishOffline, c.UpdatedBy: userId}).
|
||
Update()
|
||
configNo := "CFG" + gtime.Now().Format("YmdHis") + grand.S(5)
|
||
result, err := s.siteModel(ctx).
|
||
Fields(c.ConfigNo, c.ConfigGroup, c.SchemaVersion, c.ConfigJson, c.ConfigDigest, c.PublishStatus, c.EffectiveAt, c.PublishedAt, c.BaseVersionId, c.Version, c.Remark, c.CreatedBy, c.UpdatedBy).
|
||
Hook(hook.SaveTenant).
|
||
Data(gdb.Map{
|
||
c.ConfigNo: configNo,
|
||
c.ConfigGroup: in.ConfigGroup,
|
||
c.SchemaVersion: "1.0",
|
||
c.ConfigJson: gjson.New(raw),
|
||
c.ConfigDigest: digest,
|
||
c.PublishStatus: consts.BizPublishPublished,
|
||
c.EffectiveAt: in.EffectiveAt,
|
||
c.PublishedAt: now,
|
||
c.CreatedBy: userId,
|
||
c.UpdatedBy: userId,
|
||
}).Insert()
|
||
if err != nil {
|
||
return 0, gerror.Wrap(err, "保存站点配置失败")
|
||
}
|
||
last, _ := result.LastInsertId()
|
||
return uint64(last), nil
|
||
}
|
||
|
||
func (s *sSysPortal) SiteConfigSubmit(ctx context.Context, in *sysin.SiteConfigSubmitInp) (res *sysin.PortalApprovalModel, err error) {
|
||
var row *entity.SiteConfigVersion
|
||
c := dao.SiteConfigVersion.Columns()
|
||
if err = s.siteModel(ctx).WherePri(in.Id).Scan(&row); err != nil {
|
||
return nil, gerror.Wrap(err, "读取配置草稿失败")
|
||
}
|
||
if row == nil || row.Id == 0 {
|
||
return nil, gerror.New("配置草稿不存在")
|
||
}
|
||
if row.PublishStatus != consts.BizPublishDraft {
|
||
return nil, gerror.New("仅草稿可以提交审批")
|
||
}
|
||
if row.Version != in.Version {
|
||
return nil, gerror.New("配置已更新,请刷新后重试")
|
||
}
|
||
payload := gjson.New(row)
|
||
approval, err := service.SysApproval().Create(ctx, &sysin.ApprovalCreateInp{ApprovalType: "site_config_publish", TargetType: "site_config_version", TargetId: row.Id, Action: "publish", Title: "发布站点配置 " + row.ConfigNo, PayloadJson: payload, RiskLevel: consts.ApprovalRiskHigh, RequiredApprovals: 1, Remark: in.Reason})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if err = service.SysApproval().Submit(ctx, &sysin.ApprovalSubmitInp{Id: approval.Id, Version: 0}); err != nil {
|
||
return nil, err
|
||
}
|
||
result, err := s.siteModel(ctx).WherePri(row.Id).Where(c.Version, row.Version).Data(gdb.Map{c.PublishStatus: consts.BizPublishPending, c.ApprovalRequestId: approval.Id, c.UpdatedBy: contexts.GetUserId(ctx), c.Version: gdb.Raw(c.Version + "+1")}).Update()
|
||
if err != nil {
|
||
return nil, gerror.Wrap(err, "更新配置审批状态失败")
|
||
}
|
||
rows, _ := result.RowsAffected()
|
||
if rows == 0 {
|
||
return nil, gerror.New("配置已更新,请刷新后重试")
|
||
}
|
||
return &sysin.PortalApprovalModel{ApprovalId: approval.Id, ApprovalNo: approval.ApprovalNo}, nil
|
||
}
|
||
|
||
func (s *sSysPortal) SiteConfigPublish(ctx context.Context, in *sysin.SiteConfigPublishInp) error {
|
||
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||
var row *entity.SiteConfigVersion
|
||
c := dao.SiteConfigVersion.Columns()
|
||
if err := s.siteModel(ctx).WherePri(in.Id).LockUpdate().Scan(&row); err != nil {
|
||
return gerror.Wrap(err, "读取配置版本失败")
|
||
}
|
||
if row == nil {
|
||
return gerror.New("配置版本不存在")
|
||
}
|
||
if row.Version != in.Version {
|
||
return gerror.New("配置已更新,请刷新后重试")
|
||
}
|
||
if row.PublishStatus != consts.BizPublishPending {
|
||
return gerror.New("仅待审配置可以发布")
|
||
}
|
||
var approval *entity.ApprovalRequest
|
||
if err := service.SysApproval().Model(ctx).WherePri(row.ApprovalRequestId).Scan(&approval); err != nil {
|
||
return err
|
||
}
|
||
if approval == nil || approval.ApprovalStatus != consts.ApprovalStatusApproved {
|
||
return gerror.New("审批尚未通过,不能发布")
|
||
}
|
||
now := gtime.Now()
|
||
if row.EffectiveAt != nil && row.EffectiveAt.After(now) {
|
||
return gerror.New("计划生效时间尚未到达")
|
||
}
|
||
_, _ = s.siteModel(ctx).Where(c.ConfigGroup, row.ConfigGroup).Where(c.PublishStatus, consts.BizPublishPublished).Data(gdb.Map{c.PublishStatus: consts.BizPublishOffline, c.UpdatedBy: contexts.GetUserId(ctx)}).Update()
|
||
_, err := s.siteModel(ctx).WherePri(row.Id).Where(c.Version, row.Version).Data(gdb.Map{c.PublishStatus: consts.BizPublishPublished, c.PublishedAt: now, c.UpdatedBy: contexts.GetUserId(ctx), c.Version: gdb.Raw(c.Version + "+1")}).Update()
|
||
if err != nil {
|
||
return gerror.Wrap(err, "发布站点配置失败")
|
||
}
|
||
return service.SysBizAudit().Record(ctx, &sysin.BizAuditRecordInp{Module: "portal", Action: "publish", TargetType: "site_config_version", TargetId: row.Id, After: row, ApprovalNo: approval.ApprovalNo, Reason: "审批通过后发布"})
|
||
})
|
||
}
|
||
|
||
func (s *sSysPortal) SiteConfigRollback(ctx context.Context, in *sysin.SiteConfigRollbackInp) (id uint64, err error) {
|
||
var source *entity.SiteConfigVersion
|
||
if err = s.siteModel(ctx).WherePri(in.Id).Scan(&source); err != nil {
|
||
return 0, gerror.Wrap(err, "读取历史配置失败")
|
||
}
|
||
if source == nil {
|
||
return 0, gerror.New("历史配置不存在")
|
||
}
|
||
save := &sysin.SiteConfigSaveInp{ConfigGroup: source.ConfigGroup, Remark: "回滚自 " + source.ConfigNo + ":" + in.Reason}
|
||
if err = source.ConfigJson.Scan(&save.Config); err != nil {
|
||
return 0, gerror.Wrap(err, "解析历史配置失败")
|
||
}
|
||
return s.SiteConfigSave(ctx, save)
|
||
}
|
||
|
||
func (s *sSysPortal) ContentList(ctx context.Context, in *sysin.ContentListInp) (list []*sysin.ContentListModel, totalCount int, err error) {
|
||
c := dao.Content.Columns()
|
||
mod := s.contentModel(ctx).Fields(sysin.ContentListModel{})
|
||
if in.Title != "" {
|
||
mod = mod.WhereLike(c.Title, "%"+in.Title+"%")
|
||
}
|
||
if in.ContentType != "" {
|
||
mod = mod.Where(c.ContentType, in.ContentType)
|
||
}
|
||
if err = mod.Page(in.Page, in.PerPage).OrderDesc(c.Id).ScanAndCount(&list, &totalCount, false); err != nil {
|
||
return nil, 0, gerror.Wrap(err, "获取文本内容列表失败")
|
||
}
|
||
vc := dao.ContentVersion.Columns()
|
||
for _, item := range list {
|
||
var v *entity.ContentVersion
|
||
_ = s.contentVersionModel(ctx).Where(vc.ContentId, item.Id).OrderDesc(vc.VersionNo).Limit(1).Scan(&v)
|
||
if v != nil {
|
||
item.LatestVersionId = v.Id
|
||
item.LatestVersionNo = v.VersionNo
|
||
item.Summary = v.Summary
|
||
item.CoverUrl = v.CoverUrl
|
||
}
|
||
}
|
||
return
|
||
}
|
||
|
||
func (s *sSysPortal) ContentView(ctx context.Context, in *sysin.ContentViewInp) (res *sysin.ContentViewModel, err error) {
|
||
res = new(sysin.ContentViewModel)
|
||
if err = s.contentModel(ctx).WherePri(in.Id).Scan(&res.Content); err != nil {
|
||
return nil, gerror.Wrap(err, "获取文本内容失败")
|
||
}
|
||
if res.Id == 0 {
|
||
return nil, gerror.New("文本内容不存在")
|
||
}
|
||
vc := dao.ContentVersion.Columns()
|
||
if err = s.contentVersionModel(ctx).Where(vc.ContentId, in.Id).OrderDesc(vc.VersionNo).Scan(&res.Versions); err != nil {
|
||
return nil, gerror.Wrap(err, "获取内容版本失败")
|
||
}
|
||
if len(res.Versions) > 0 {
|
||
res.LatestVersion = res.Versions[0]
|
||
}
|
||
return res, nil
|
||
}
|
||
|
||
func (s *sSysPortal) ContentEdit(ctx context.Context, in *sysin.ContentEditInp) (id uint64, err error) {
|
||
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||
userId := uint64(contexts.GetUserId(ctx))
|
||
c := dao.Content.Columns()
|
||
if in.Id == 0 {
|
||
result, e := s.contentModel(ctx).Fields(c.ContentKey, c.ContentType, c.Title, c.PublishStatus, c.Sort, c.Version, c.Remark, c.CreatedBy, c.UpdatedBy).Hook(hook.SaveTenant).Data(gdb.Map{c.ContentKey: in.ContentKey, c.ContentType: in.ContentType, c.Title: in.Title, c.PublishStatus: consts.BizPublishDraft, c.Sort: in.Sort, c.Remark: in.Remark, c.CreatedBy: userId, c.UpdatedBy: userId}).Insert()
|
||
if e != nil {
|
||
return gerror.Wrap(e, "创建文本内容失败")
|
||
}
|
||
last, _ := result.LastInsertId()
|
||
id = uint64(last)
|
||
} else {
|
||
id = in.Id
|
||
result, e := s.contentModel(ctx).WherePri(in.Id).Where(c.Version, in.Version).Data(gdb.Map{c.ContentType: in.ContentType, c.Title: in.Title, c.Sort: in.Sort, c.Remark: in.Remark, c.UpdatedBy: userId, c.Version: gdb.Raw(c.Version + "+1")}).Update()
|
||
if e != nil {
|
||
return gerror.Wrap(e, "更新文本内容失败")
|
||
}
|
||
rows, _ := result.RowsAffected()
|
||
if rows == 0 {
|
||
return gerror.New("内容已更新,请刷新后重试")
|
||
}
|
||
}
|
||
vc := dao.ContentVersion.Columns()
|
||
maxNo, e := s.contentVersionModel(ctx).Where(vc.ContentId, id).Max(vc.VersionNo)
|
||
if e != nil {
|
||
return gerror.Wrap(e, "读取内容版本号失败")
|
||
}
|
||
_, e = s.contentVersionModel(ctx).Fields(vc.ContentId, vc.VersionNo, vc.Title, vc.Summary, vc.BodyHtml, vc.BodyText, vc.CoverUrl, vc.PublishStatus, vc.EffectiveAt, vc.CreatedBy).Hook(hook.SaveTenant).Data(gdb.Map{vc.ContentId: id, vc.VersionNo: uint(maxNo) + 1, vc.Title: in.Title, vc.Summary: in.Summary, vc.BodyHtml: in.BodyHtml, vc.BodyText: in.BodyText, vc.CoverUrl: in.CoverUrl, vc.PublishStatus: consts.BizPublishDraft, vc.EffectiveAt: in.EffectiveAt, vc.CreatedBy: userId}).Insert()
|
||
if e != nil {
|
||
return gerror.Wrap(e, "创建内容版本失败")
|
||
}
|
||
return nil
|
||
})
|
||
return
|
||
}
|
||
|
||
func (s *sSysPortal) ContentDelete(ctx context.Context, in *sysin.ContentDeleteInp) error {
|
||
var row *entity.Content
|
||
if err := s.contentModel(ctx).WherePri(in.Id).Scan(&row); err != nil {
|
||
return err
|
||
}
|
||
if row == nil {
|
||
return gerror.New("文本内容不存在")
|
||
}
|
||
c := dao.Content.Columns()
|
||
if row.PublishStatus == consts.BizPublishPublished {
|
||
_, err := s.contentModel(ctx).WherePri(in.Id).Data(gdb.Map{c.PublishStatus: consts.BizPublishOffline, c.UpdatedBy: contexts.GetUserId(ctx), c.Version: gdb.Raw(c.Version + "+1")}).Update()
|
||
if err != nil {
|
||
return gerror.Wrap(err, "下线文本内容失败")
|
||
}
|
||
return nil
|
||
}
|
||
_, err := s.contentModel(ctx).WherePri(in.Id).Data(gdb.Map{c.DeletedAt: gtime.Now(), c.DeletedBy: contexts.GetUserId(ctx)}).Unscoped().Update()
|
||
if err != nil {
|
||
return gerror.Wrap(err, "删除文本内容失败")
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (s *sSysPortal) ContentPublish(ctx context.Context, in *sysin.ContentPublishInp) error {
|
||
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||
var content *entity.Content
|
||
var version *entity.ContentVersion
|
||
if err := s.contentModel(ctx).WherePri(in.Id).LockUpdate().Scan(&content); err != nil {
|
||
return err
|
||
}
|
||
if content == nil {
|
||
return gerror.New("文本内容不存在")
|
||
}
|
||
vc := dao.ContentVersion.Columns()
|
||
if err := s.contentVersionModel(ctx).WherePri(in.VersionId).Where(vc.ContentId, in.Id).Scan(&version); err != nil {
|
||
return err
|
||
}
|
||
if version == nil {
|
||
return gerror.New("内容版本不存在")
|
||
}
|
||
if version.EffectiveAt != nil && version.EffectiveAt.After(gtime.Now()) {
|
||
return gerror.New("计划发布时间尚未到达")
|
||
}
|
||
_, _ = s.contentVersionModel(ctx).Where(vc.ContentId, in.Id).Where(vc.PublishStatus, consts.BizPublishPublished).Data(gdb.Map{vc.PublishStatus: consts.BizPublishOffline}).Update()
|
||
_, err := s.contentVersionModel(ctx).WherePri(version.Id).Data(gdb.Map{vc.PublishStatus: consts.BizPublishPublished}).Update()
|
||
if err != nil {
|
||
return gerror.Wrap(err, "发布内容版本失败")
|
||
}
|
||
c := dao.Content.Columns()
|
||
_, err = s.contentModel(ctx).WherePri(in.Id).Data(gdb.Map{c.PublishedVersionId: version.Id, c.PublishStatus: consts.BizPublishPublished, c.PublishedAt: gtime.Now(), c.UpdatedBy: contexts.GetUserId(ctx), c.Version: gdb.Raw(c.Version + "+1")}).Update()
|
||
return gerror.Wrap(err, "发布文本内容失败")
|
||
})
|
||
}
|
||
func (s *sSysPortal) ContentOffline(ctx context.Context, in *sysin.ContentOfflineInp) error {
|
||
c := dao.Content.Columns()
|
||
_, err := s.contentModel(ctx).WherePri(in.Id).Data(gdb.Map{c.PublishStatus: consts.BizPublishOffline, c.UpdatedBy: contexts.GetUserId(ctx), c.Version: gdb.Raw(c.Version + "+1")}).Update()
|
||
if err != nil {
|
||
return gerror.Wrap(err, "下线文本内容失败")
|
||
}
|
||
return service.SysBizAudit().Record(ctx, &sysin.BizAuditRecordInp{Module: "portal", Action: "offline", TargetType: "content", TargetId: in.Id, Reason: in.Reason})
|
||
}
|
||
|
||
func (s *sSysPortal) BannerList(ctx context.Context, in *sysin.BannerListInp) (list []*sysin.BannerListModel, totalCount int, err error) {
|
||
c := dao.Banner.Columns()
|
||
mod := s.bannerModel(ctx).Fields(sysin.BannerListModel{})
|
||
if in.Name != "" {
|
||
mod = mod.WhereLike(c.Name, "%"+in.Name+"%")
|
||
}
|
||
if in.Position != "" {
|
||
mod = mod.Where(c.Position, in.Position)
|
||
}
|
||
if in.PublishStatus > 0 {
|
||
mod = mod.Where(c.PublishStatus, in.PublishStatus)
|
||
}
|
||
err = mod.Page(in.Page, in.PerPage).OrderAsc(c.Sort).OrderDesc(c.Id).ScanAndCount(&list, &totalCount, false)
|
||
if err != nil {
|
||
err = gerror.Wrap(err, "获取Banner列表失败")
|
||
}
|
||
return
|
||
}
|
||
func (s *sSysPortal) BannerView(ctx context.Context, in *sysin.BannerViewInp) (res *entity.Banner, err error) {
|
||
err = s.bannerModel(ctx).WherePri(in.Id).Scan(&res)
|
||
if err != nil {
|
||
return nil, gerror.Wrap(err, "获取Banner失败")
|
||
}
|
||
if res == nil {
|
||
return nil, gerror.New("Banner不存在")
|
||
}
|
||
return
|
||
}
|
||
func (s *sSysPortal) BannerEdit(ctx context.Context, in *sysin.BannerEditInp) (id uint64, err error) {
|
||
c := dao.Banner.Columns()
|
||
userId := uint64(contexts.GetUserId(ctx))
|
||
if in.Id > 0 {
|
||
result, e := s.bannerModel(ctx).WherePri(in.Id).Where(c.Version, in.Version).Data(gdb.Map{
|
||
c.Name: in.Name, c.Position: in.Position, c.ImageAttachmentId: in.ImageAttachmentId,
|
||
c.ImageUrl: in.ImageUrl, c.AltText: in.AltText, c.TargetType: in.TargetType,
|
||
c.TargetValue: in.TargetValue, c.StartAt: in.StartAt, c.EndAt: in.EndAt,
|
||
c.Sort: in.Sort, c.Remark: in.Remark, c.UpdatedBy: userId, c.Version: gdb.Raw(c.Version + "+1"),
|
||
}).Update()
|
||
if e != nil {
|
||
return 0, gerror.Wrap(e, "更新Banner失败")
|
||
}
|
||
rows, _ := result.RowsAffected()
|
||
if rows == 0 {
|
||
return 0, gerror.New("Banner已更新,请刷新后重试")
|
||
}
|
||
return in.Id, nil
|
||
}
|
||
in.PublishStatus = consts.BizPublishDraft
|
||
in.CreatedBy = userId
|
||
in.UpdatedBy = userId
|
||
result, e := s.bannerModel(ctx).Fields(c.Name, c.Position, c.ImageAttachmentId, c.ImageUrl, c.AltText, c.TargetType, c.TargetValue, c.StartAt, c.EndAt, c.PublishStatus, c.Sort, c.Version, c.Remark, c.CreatedBy, c.UpdatedBy).Hook(hook.SaveTenant).Data(in).Insert()
|
||
if e != nil {
|
||
return 0, gerror.Wrap(e, "创建Banner失败")
|
||
}
|
||
last, _ := result.LastInsertId()
|
||
return uint64(last), nil
|
||
}
|
||
func (s *sSysPortal) BannerDelete(ctx context.Context, in *sysin.BannerDeleteInp) error {
|
||
var row *entity.Banner
|
||
if err := s.bannerModel(ctx).WherePri(in.Id).Scan(&row); err != nil {
|
||
return err
|
||
}
|
||
if row == nil {
|
||
return gerror.New("Banner不存在")
|
||
}
|
||
c := dao.Banner.Columns()
|
||
if row.PublishStatus == consts.BizPublishPublished {
|
||
_, err := s.bannerModel(ctx).WherePri(in.Id).Data(gdb.Map{c.PublishStatus: consts.BizPublishOffline, c.UpdatedBy: contexts.GetUserId(ctx), c.Version: gdb.Raw(c.Version + "+1")}).Update()
|
||
return err
|
||
}
|
||
_, err := s.bannerModel(ctx).WherePri(in.Id).Data(gdb.Map{c.DeletedAt: gtime.Now(), c.DeletedBy: contexts.GetUserId(ctx)}).Unscoped().Update()
|
||
return gerror.Wrap(err, "删除Banner失败")
|
||
}
|
||
func (s *sSysPortal) BannerStatus(ctx context.Context, in *sysin.BannerStatusInp) error {
|
||
c := dao.Banner.Columns()
|
||
result, err := s.bannerModel(ctx).WherePri(in.Id).Where(c.Version, in.Version).Data(gdb.Map{c.PublishStatus: in.PublishStatus, c.UpdatedBy: contexts.GetUserId(ctx), c.Version: gdb.Raw(c.Version + "+1")}).Update()
|
||
if err != nil {
|
||
return gerror.Wrap(err, "更新Banner状态失败")
|
||
}
|
||
rows, _ := result.RowsAffected()
|
||
if rows == 0 {
|
||
return gerror.New("Banner已更新,请刷新后重试")
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (s *sSysPortal) ManualProductList(ctx context.Context, in *sysin.ManualProductListInp) (list []*sysin.ManualProductListModel, totalCount int, err error) {
|
||
c := dao.Product.Columns()
|
||
mod := s.productModel(ctx).Fields(sysin.ManualProductListModel{}).Where(c.ProductType, consts.ProductTypeManual)
|
||
if in.Name != "" {
|
||
mod = mod.WhereLike(c.Name, "%"+in.Name+"%")
|
||
}
|
||
if in.PublishStatus > 0 {
|
||
mod = mod.Where(c.PublishStatus, in.PublishStatus)
|
||
}
|
||
if err = mod.Page(in.Page, in.PerPage).OrderAsc(c.Sort).OrderDesc(c.Id).ScanAndCount(&list, &totalCount, false); err != nil {
|
||
return nil, 0, gerror.Wrap(err, "获取手工商城列表失败")
|
||
}
|
||
for _, item := range list {
|
||
item.Price = formatCents(item.PriceAmount)
|
||
}
|
||
return
|
||
}
|
||
func (s *sSysPortal) ManualProductView(ctx context.Context, in *sysin.ManualProductViewInp) (res *sysin.ManualProductViewModel, err error) {
|
||
c := dao.Product.Columns()
|
||
if err = s.productModel(ctx).WherePri(in.Id).Where(c.ProductType, consts.ProductTypeManual).Scan(&res); err != nil {
|
||
return nil, gerror.Wrap(err, "获取手工商城商品失败")
|
||
}
|
||
if res == nil {
|
||
return nil, gerror.New("商品不存在")
|
||
}
|
||
res.Price = formatCents(res.PriceAmount)
|
||
return
|
||
}
|
||
func (s *sSysPortal) ManualProductEdit(ctx context.Context, in *sysin.ManualProductEditInp) (id uint64, err error) {
|
||
amount, err := parseCents(in.Price)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
in.PriceAmount = amount
|
||
in.ProductType = consts.ProductTypeManual
|
||
if in.PaymentType == "" {
|
||
in.PaymentType = "balance"
|
||
}
|
||
if in.Currency == "" {
|
||
in.Currency = "CNY"
|
||
}
|
||
c := dao.Product.Columns()
|
||
userId := uint64(contexts.GetUserId(ctx))
|
||
if in.Id > 0 {
|
||
result, e := s.productModel(ctx).WherePri(in.Id).Where(c.Version, in.Version).Data(gdb.Map{
|
||
c.Name: in.Name,
|
||
c.PriceAmount: in.PriceAmount,
|
||
c.CoverAttachmentId: in.CoverAttachmentId,
|
||
c.CoverUrl: in.CoverUrl,
|
||
c.PublishStatus: consts.BizPublishPublished,
|
||
c.UpdatedBy: userId,
|
||
c.Version: gdb.Raw(c.Version + "+1"),
|
||
}).Update()
|
||
if e != nil {
|
||
return 0, gerror.Wrap(e, "更新手工商城商品失败")
|
||
}
|
||
rows, _ := result.RowsAffected()
|
||
if rows == 0 {
|
||
return 0, gerror.New("商品已更新,请刷新后重试")
|
||
}
|
||
return in.Id, nil
|
||
}
|
||
in.ProductNo = "MP" + gtime.Now().Format("YmdHis") + grand.S(5)
|
||
in.PublishStatus = consts.BizPublishPublished
|
||
in.CreatedBy = userId
|
||
in.UpdatedBy = userId
|
||
result, e := s.productModel(ctx).Fields(c.ProductNo, c.CategoryId, c.ProductType, c.PaymentType, c.Name, c.ShopName, c.PriceAmount, c.Currency, c.CoverAttachmentId, c.CoverUrl, c.DetailHtml, c.IsRecommended, c.PublishStatus, c.StartAt, c.EndAt, c.Sort, c.Version, c.Remark, c.CreatedBy, c.UpdatedBy).Hook(hook.SaveTenant).Data(in).Insert()
|
||
if e != nil {
|
||
return 0, gerror.Wrap(e, "创建手工商城商品失败")
|
||
}
|
||
last, _ := result.LastInsertId()
|
||
return uint64(last), nil
|
||
}
|
||
func (s *sSysPortal) ManualProductDelete(ctx context.Context, in *sysin.ManualProductDeleteInp) error {
|
||
c := dao.Product.Columns()
|
||
_, err := s.productModel(ctx).
|
||
WhereIn(c.Id, in.Ids).
|
||
Where(c.ProductType, consts.ProductTypeManual).
|
||
Data(gdb.Map{c.DeletedAt: gtime.Now(), c.DeletedBy: contexts.GetUserId(ctx)}).
|
||
Unscoped().
|
||
Update()
|
||
return gerror.Wrap(err, "删除商品失败")
|
||
}
|
||
func (s *sSysPortal) ManualProductStatus(ctx context.Context, in *sysin.ManualProductStatusInp) error {
|
||
c := dao.Product.Columns()
|
||
result, err := s.productModel(ctx).WherePri(in.Id).Where(c.Version, in.Version).Where(c.ProductType, consts.ProductTypeManual).Data(gdb.Map{c.PublishStatus: in.PublishStatus, c.UpdatedBy: contexts.GetUserId(ctx), c.Version: gdb.Raw(c.Version + "+1")}).Update()
|
||
if err != nil {
|
||
return gerror.Wrap(err, "更新商品状态失败")
|
||
}
|
||
rows, _ := result.RowsAffected()
|
||
if rows == 0 {
|
||
return gerror.New("商品已更新,请刷新后重试")
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func parseCents(value string) (int64, error) {
|
||
value = strings.TrimSpace(value)
|
||
if value == "" {
|
||
return 0, gerror.New("价格不能为空")
|
||
}
|
||
if strings.HasPrefix(value, "-") {
|
||
return 0, gerror.New("价格不能为负数")
|
||
}
|
||
parts := strings.Split(value, ".")
|
||
if len(parts) > 2 {
|
||
return 0, gerror.New("价格格式不正确")
|
||
}
|
||
yuan, err := strconv.ParseInt(parts[0], 10, 64)
|
||
if err != nil {
|
||
return 0, gerror.New("价格格式不正确")
|
||
}
|
||
fraction := ""
|
||
if len(parts) == 2 {
|
||
fraction = parts[1]
|
||
}
|
||
if len(fraction) > 2 {
|
||
return 0, gerror.New("价格最多保留两位小数")
|
||
}
|
||
for len(fraction) < 2 {
|
||
fraction += "0"
|
||
}
|
||
fen := int64(0)
|
||
if fraction != "" {
|
||
fen, err = strconv.ParseInt(fraction, 10, 64)
|
||
if err != nil {
|
||
return 0, gerror.New("价格格式不正确")
|
||
}
|
||
}
|
||
if yuan > (1<<63-1-fen)/100 {
|
||
return 0, gerror.New("价格超出允许范围")
|
||
}
|
||
return yuan*100 + fen, nil
|
||
}
|
||
func formatCents(value int64) string { return fmt.Sprintf("%d.%02d", value/100, value%100) }
|