完成H5后端管理第一版。

develop
张帅 2 weeks ago
parent d6de752645
commit d0aa47cae2

@ -8,14 +8,17 @@ func ToDto(col *column.Column) *ColumnDto {
return nil
}
return &ColumnDto{
ID: col.ID,
Title: col.Title,
Brief: col.Brief,
Cover: col.Cover,
AuthorID: col.AuthorID,
Status: col.Status,
ArticleNum: col.ArticleNum,
CreatedAt: col.CreatedAt,
ID: col.ID,
Title: col.Title,
Brief: col.Brief,
Cover: col.Cover,
AuthorID: col.AuthorID,
Status: col.Status,
ArticleNum: col.ArticleNum,
FollowNum: col.FollowNum,
PurchaseNum: col.PurchaseNum,
Unlock: false,
CreatedAt: col.CreatedAt,
}
}

@ -28,20 +28,6 @@ func NewService(repo column.ColumnRepository, log logger.New) *Service {
}
}
// CreateColumn 创建专栏
func (s *Service) CreateColumn(req *CreateColumnReq) (*ColumnDto, error) {
if req.Title == "" {
return nil, ErrInvalidTitle
}
col := column.NewColumn(req.Title, req.Brief, req.Cover, req.AuthorID)
if err := s.repo.Save(col); err != nil {
s.log.Error("failed to save column", "error", err)
return nil, err
}
return ToDto(col), nil
}
// GetColumnList 获取专栏列表
func (s *Service) GetColumnList(p *page.Page, params map[string]string) error {
conds := web.ParseFilters(params)
@ -56,100 +42,17 @@ func (s *Service) GetColumnList(p *page.Page, params map[string]string) error {
return nil
}
// UpdateColumn 更新专栏信息
func (s *Service) UpdateColumn(req *UpdateColumnReq) (*ColumnDto, error) {
if req.Title == "" {
return nil, ErrInvalidTitle
}
col, err := s.repo.FindByID(req.ID)
if err != nil {
s.log.Error("failed to find column", "error", err)
return nil, err
}
if col == nil {
return nil, ErrNotFound
}
col.Title = req.Title
col.Brief = req.Brief
col.Cover = req.Cover
if err := s.repo.Update(col); err != nil {
s.log.Error("failed to update column", "error", err)
return nil, err
func (s *Service) UpdateColumn(dto *ColumnDto) error {
columnData := &column.Column{
ID: dto.ID,
Title: dto.Title,
Brief: dto.Brief,
FollowNum: dto.FollowNum,
PurchaseNum: dto.PurchaseNum,
}
return ToDto(col), nil
}
// DeleteColumn 删除专栏
func (s *Service) DeleteColumn(id uint64) error {
return s.repo.Delete(id)
}
// UpdateColumnStatus 更新专栏状态
func (s *Service) UpdateColumnStatus(req *UpdateStatusReq) (*ColumnDto, error) {
col, err := s.repo.FindByID(req.ID)
err := s.repo.Update(columnData)
if err != nil {
s.log.Error("failed to find column", "error", err)
return nil, err
}
if col == nil {
return nil, ErrNotFound
s.log.Error(err)
}
col.Status = req.Status
if err := s.repo.Update(col); err != nil {
s.log.Error("failed to update column status", "error", err)
return nil, err
}
return ToDto(col), nil
}
// UpdateFollowNum 更新关注人数
func (s *Service) UpdateFollowNum(id uint64, isAdd bool) error {
col, err := s.repo.FindByID(id)
if err != nil {
s.log.Error("failed to find column", "error", err)
return err
}
if col == nil {
return ErrNotFound
}
if isAdd {
col.AddFollow()
} else {
col.RemoveFollow()
}
if err := s.repo.Update(col); err != nil {
s.log.Error("failed to update column follow num", "error", err)
return err
}
return nil
}
// UpdatePurchaseNum 更新购买人数
func (s *Service) UpdatePurchaseNum(id uint64, isAdd bool) error {
col, err := s.repo.FindByID(id)
if err != nil {
s.log.Error("failed to find column", "error", err)
return err
}
if col == nil {
return ErrNotFound
}
if isAdd {
col.AddPurchase()
} else {
col.RemovePurchase()
}
if err := s.repo.Update(col); err != nil {
s.log.Error("failed to update column purchase num", "error", err)
return err
}
return nil
return err
}

@ -21,6 +21,17 @@ type PriceDto struct {
AdminID uint64 `json:"adminID" omitempty`
}
type PriceDefaultDto struct {
Id uint64 `json:"id"`
Amount int64 `json:"amount"`
FirstMontDiscount float32 `json:"firstMontDiscount" omitempty`
OneMonthPrice int64 `json:"oneMonthPrice"` // 1个月价格
ThreeMonthsPrice int64 `json:"threeMonthsPrice"` // 3个月价格
SixMonthsPrice int64 `json:"sixMonthsPrice"` // 6个月价格
OneYearPrice int64 `json:"oneYearPrice"` // 1年价格
Discount float32 `json:"discount" omitempty`
}
type ArticlePriceDto struct {
Article *article.ArticleDto `json:"article"`
Price *PriceDto `json:"price"`

@ -2,11 +2,15 @@ package price
import (
article2 "cls-server/internal/application/article"
column2 "cls-server/internal/application/column"
"cls-server/internal/domain/article"
"cls-server/internal/domain/column"
"cls-server/internal/domain/price"
"cls-server/internal/domain/price_default"
"cls-server/pkg/logger"
"cls-server/pkg/util/page"
"errors"
"time"
"xorm.io/builder"
)
@ -20,132 +24,70 @@ var (
type PriceService struct {
repo price.PriceRepository
articleRepo article.ArticleRepository
columnRepo column.ColumnRepository
pdRepo price_default.PriceDefaultRepository
log logger.Logger
}
// NewService 创建价格管理服务
func NewPriceService(repo price.PriceRepository, articleRepo article.ArticleRepository, log logger.New) *PriceService {
func NewPriceService(repo price.PriceRepository, articleRepo article.ArticleRepository, columnRepo column.ColumnRepository, pdRepo price_default.PriceDefaultRepository, log logger.New) *PriceService {
return &PriceService{
repo: repo,
articleRepo: articleRepo,
columnRepo: columnRepo,
pdRepo: pdRepo,
log: log("cls:service:price"),
}
}
// SetPrice 设置价格
func (s *PriceService) SetPrice(dto *PriceDto) error {
if dto.Amount < 0 {
return ErrInvalidAmount
}
// 检查是否已存在价格记录
existingPrice, err := s.repo.FindByTargetID(dto.TargetID, dto.Type)
if err != nil {
// 如果记录不存在,创建新记录
newPrice := dto.ToPrice()
return s.repo.Save(newPrice)
}
// 如果记录存在,更新价格
existingPrice.Amount = dto.Amount
existingPrice.OneMonthPrice = dto.OneMonthPrice
existingPrice.ThreeMonthsPrice = dto.ThreeMonthsPrice
existingPrice.SixMonthsPrice = dto.SixMonthsPrice
existingPrice.OneYearPrice = dto.OneYearPrice
existingPrice.AdminID = dto.AdminID
return s.repo.Update(existingPrice)
}
// GetPrice 获取价格(如果不存在则使用默认价格)
func (s *PriceService) GetPrice(dto *PriceDto) (*PriceDto, error) {
// 检查是否已存在价格记录
existingPrice, err := s.repo.FindByTargetID(dto.TargetID, dto.Type)
if err != nil {
// 如果记录不存在,使用默认价格
var defaultAmount int64
switch dto.Type {
case price.TypeArticle:
defaultAmount = price.DefaultArticlePrice
case price.TypeColumn:
defaultAmount = price.DefaultColumnPrice
default:
return nil, ErrInvalidType
}
// 创建默认价格记录
newPrice := price.NewPrice(dto.TargetID, dto.Type, defaultAmount, 0)
if err := s.repo.Save(newPrice); err != nil {
return nil, err
}
if dto.Type == price.TypeArticle {
return &PriceDto{
Amount: newPrice.Amount,
Discount: newPrice.Discount,
}, nil
}
return &PriceDto{
OneMonthPrice: newPrice.OneMonthPrice,
ThreeMonthsPrice: newPrice.ThreeMonthsPrice,
SixMonthsPrice: newPrice.SixMonthsPrice,
OneYearPrice: newPrice.OneYearPrice,
Discount: 0.3,
}, nil
}
priceDto := &PriceDto{
Discount: existingPrice.Discount,
}
if dto.Type == price.TypeArticle {
priceDto.Amount = existingPrice.Amount
} else {
priceDto.OneMonthPrice = existingPrice.OneMonthPrice
priceDto.ThreeMonthsPrice = existingPrice.ThreeMonthsPrice
priceDto.SixMonthsPrice = existingPrice.SixMonthsPrice
priceDto.OneYearPrice = existingPrice.OneYearPrice
}
return priceDto, nil
}
func (s *PriceService) GetArticlePricePage(p *page.Page) error {
conds := make([]builder.Cond, 0)
conds = append(conds, builder.Eq{"type": price.TypeArticle})
data := make([]*price.Price, 0)
//conds = append(conds, builder.Eq{"type": price.TypeArticle})
// todo 加入付费文章条件
conds = append(conds, builder.And(builder.Gt{"ctime": time.Now().AddDate(0, 0, -7).Unix()}))
data := make([]*article.LianV1Article, 0)
p.Content = &data
err := s.repo.FindAll(p, conds)
err := s.articleRepo.Find(p, conds)
if err != nil {
s.log.Error(err)
return err
}
ids := make([]uint64, 0, len(data))
for _, v := range data {
ids = append(ids, v.TargetID)
ids = append(ids, v.Id)
}
as, err := s.articleRepo.GetArticlesByIds(ids)
priceList, err := s.repo.FindPriceByIds(&ids, price.TypeArticle)
if err != nil {
s.log.Error(err)
return err
}
asMap := make(map[uint64]*article2.ArticleDto, 0)
for _, v := range *as {
asMap[v.Id] = &article2.ArticleDto{
EventId: v.Id,
Title: v.Title,
Class: article2.GetClassNameById(v.Type),
Stocks: v.Stocks,
Brief: v.Brief,
asMap := make(map[uint64]*PriceDto, 0)
for _, v := range *priceList {
asMap[v.TargetID] = &PriceDto{
ID: v.ID,
TargetID: v.TargetID,
Amount: v.Amount,
Discount: v.Discount,
}
}
ids = nil
dtoData := make([]*ArticlePriceDto, 0, len(data))
for _, v := range data {
t := time.Unix(v.Ctime, 0) // 秒数和纳秒数0 表示没有纳秒部分
dtoData = append(dtoData, &ArticlePriceDto{
Article: asMap[v.TargetID],
Price: &PriceDto{
ID: v.ID,
TargetID: v.TargetID,
Amount: v.Amount,
Discount: v.Discount,
Article: &article2.ArticleDto{
EventId: v.Id,
Title: v.Title,
Class: article2.GetClassNameById(v.Type),
Stocks: v.Stocks,
ReleaseDate: t.Format("2006-01-02"),
ReleaseTime: t.Format("15:04"),
Brief: v.Brief,
Content: v.Content,
},
Price: asMap[v.Id],
})
}
p.Content = &dtoData
@ -154,13 +96,53 @@ func (s *PriceService) GetArticlePricePage(p *page.Page) error {
func (s *PriceService) GetColumnPricePage(p *page.Page) error {
conds := make([]builder.Cond, 0)
conds = append(conds, builder.Eq{"p.type": price.TypeColumn})
data := make([]*ColumnPriceDto, 0)
data := make([]*column.Column, 0)
p.Content = &data
err := s.repo.FindColumnAll(p, conds)
err := s.columnRepo.FindAll(p, conds)
if err != nil {
s.log.Error(err.Error())
}
ids := make([]uint64, 0, len(data))
for _, v := range data {
ids = append(ids, v.ID)
}
priceList, err := s.repo.FindPriceByIds(&ids, price.TypeColumn)
if err != nil {
s.log.Error(err)
return err
}
asMap := make(map[uint64]*PriceDto, 0)
for _, v := range *priceList {
asMap[v.TargetID] = &PriceDto{
ID: v.ID,
TargetID: v.TargetID,
FirstMontDiscount: v.FirstMontDiscount,
OneMonthPrice: v.OneMonthPrice,
ThreeMonthsPrice: v.ThreeMonthsPrice,
SixMonthsPrice: v.SixMonthsPrice,
OneYearPrice: v.OneYearPrice,
Discount: v.Discount,
}
}
dtoData := make([]*ColumnPriceDto, 0, len(data))
for _, v := range data {
dtoData = append(dtoData, &ColumnPriceDto{
Column: &column2.ColumnDto{
ID: v.ID,
Title: v.Title,
Brief: v.Brief,
Cover: v.Cover,
AuthorID: v.AuthorID,
ArticleNum: v.ArticleNum,
FollowNum: v.FollowNum,
PurchaseNum: v.PurchaseNum,
CreatedAt: v.CreatedAt,
},
Price: asMap[v.ID],
})
}
p.Content = &dtoData
return err
}
@ -173,15 +155,79 @@ func (s *PriceService) UpdatePrice(dto *PriceDto) error {
if err := dto.Validate(); err != nil {
return err
}
existingPrice, err := s.repo.FindByTargetID(dto.TargetID, dto.Type)
var err error
articlePrice := &price.Price{
TargetID: dto.TargetID,
Type: dto.Type,
Discount: dto.Discount,
}
if dto.ID < 1 {
if dto.Type == price.TypeArticle {
articlePrice.Amount = dto.Amount
} else {
articlePrice.OneMonthPrice = dto.OneMonthPrice
articlePrice.ThreeMonthsPrice = dto.ThreeMonthsPrice
articlePrice.SixMonthsPrice = dto.SixMonthsPrice
articlePrice.OneYearPrice = dto.OneYearPrice
articlePrice.FirstMontDiscount = dto.FirstMontDiscount
articlePrice.AdminID = dto.AdminID
}
err = s.repo.Save(articlePrice)
if err != nil {
s.log.Error(err)
}
} else {
if dto.Type == price.TypeArticle {
articlePrice.Amount = dto.Amount
} else {
articlePrice.OneMonthPrice = dto.OneMonthPrice
articlePrice.ThreeMonthsPrice = dto.ThreeMonthsPrice
articlePrice.SixMonthsPrice = dto.SixMonthsPrice
articlePrice.OneYearPrice = dto.OneYearPrice
articlePrice.FirstMontDiscount = dto.FirstMontDiscount
articlePrice.AdminID = dto.AdminID
}
err = s.repo.Update(articlePrice)
if err != nil {
s.log.Error(err)
}
}
return err
}
func (s *PriceService) GetPriceDefault() (*PriceDefaultDto, error) {
data, err := s.pdRepo.Get()
if err != nil {
return err
s.log.Error(err.Error())
}
existingPrice.Amount = dto.Amount
existingPrice.OneMonthPrice = dto.OneMonthPrice
existingPrice.ThreeMonthsPrice = dto.ThreeMonthsPrice
existingPrice.SixMonthsPrice = dto.SixMonthsPrice
existingPrice.OneYearPrice = dto.OneYearPrice
existingPrice.AdminID = dto.AdminID
return s.repo.Update(existingPrice)
return &PriceDefaultDto{
Id: data.Id,
Amount: data.Amount,
FirstMontDiscount: data.FirstMontDiscount,
OneMonthPrice: data.OneMonthPrice,
ThreeMonthsPrice: data.ThreeMonthsPrice,
SixMonthsPrice: data.SixMonthsPrice,
OneYearPrice: data.OneYearPrice,
Discount: data.Discount,
}, err
}
func (s *PriceService) UpdatePriceDefault(pdDto *PriceDefaultDto) error {
err := s.pdRepo.Save(&price_default.PriceDefault{
Id: pdDto.Id,
Amount: pdDto.Amount,
FirstMontDiscount: pdDto.FirstMontDiscount,
OneMonthPrice: pdDto.OneMonthPrice,
ThreeMonthsPrice: pdDto.ThreeMonthsPrice,
SixMonthsPrice: pdDto.SixMonthsPrice,
OneYearPrice: pdDto.OneYearPrice,
Discount: pdDto.Discount,
})
if err != nil {
s.log.Error(err)
}
return err
}

@ -26,4 +26,6 @@ type PriceRepository interface {
// Delete 删除价格记录
Delete(id uint64) error
FindPriceByIds(id *[]uint64, t PriceType) (*[]*Price, error)
}

@ -1,10 +1,12 @@
package price_default
type DefaultPrice struct {
Id uint64 `xorm:"pk autoincr 'id'"`
Amount int64 `xorm:"not null 'amount'"` // 基础价格(分)
OneMonthPrice int64 `xorm:"not null 'one_month_price'"` // 1个月价格
ThreeMonthsPrice int64 `xorm:"not null 'three_months_price'"` // 3个月价格
SixMonthsPrice int64 `xorm:"not null 'six_months_price'"` // 6个月价格
OneYearPrice int64 `xorm:"not null 'one_year_price'"` // 1年价格
type PriceDefault struct {
Id uint64 `xorm:"pk autoincr 'id'"`
Amount int64 `xorm:"not null 'amount'"` // 单篇文章价格(分)
FirstMontDiscount float32 `xorm:"null"` //首月优惠折扣
OneMonthPrice int64 `xorm:"not null 'one_month_price'"` // 1个月价格
ThreeMonthsPrice int64 `xorm:"not null 'three_months_price'"` // 3个月价格
SixMonthsPrice int64 `xorm:"not null 'six_months_price'"` // 6个月价格
OneYearPrice int64 `xorm:"not null 'one_year_price'"` // 1年价格
Discount float32 `xorm:"not null"`
}

@ -1 +1,6 @@
package price_default
type PriceDefaultRepository interface {
Save(price *PriceDefault) error
Get() (*PriceDefault, error)
}

@ -47,5 +47,5 @@ func (a *ArticleRepositoryORM) GetArticleById(id uint64) (*article.LianV1Article
func (a *ArticleRepositoryORM) GetArticlesByIds(id []uint64) (*[]*article.LianV1Article, error) {
data := make([]*article.LianV1Article, 0)
return &data, a.engine.Where(builder.In("id", id)).Find(&data)
return &data, a.engine.Cls.Where(builder.In("id", id)).Find(&data)
}

@ -55,7 +55,7 @@ func (r *ColumnRepositoryORM) FindAll(page *page.Page, conds []builder.Cond) err
// Update 更新专栏
func (r *ColumnRepositoryORM) Update(col *column.Column) error {
_, err := r.engine.ID(col.ID).Update(col)
_, err := r.engine.ID(col.ID).AllCols().Update(col)
return err
}

@ -5,7 +5,6 @@ import (
"cls-server/pkg/util/page"
"cls-server/pkg/xorm_engine"
"errors"
"fmt"
"xorm.io/builder"
)
@ -45,16 +44,13 @@ func (p *PriceRepositoryORM) FindByID(id uint64) (*price.Price, error) {
// FindByTargetID 根据目标ID查找价格记录
func (p *PriceRepositoryORM) FindByTargetID(targetID uint64, priceType price.PriceType) (*price.Price, error) {
price := &price.Price{}
has, err := p.engine.Where(builder.Eq{
_, err := p.engine.Where(builder.Eq{
"target_id": targetID,
"type": priceType,
}).Get(price)
if err != nil {
return nil, err
}
if !has {
return nil, errors.New(fmt.Sprintf("未找到相关数据【target_id: %d, type: %d】", targetID, priceType))
}
return price, nil
}
@ -65,10 +61,10 @@ func (p *PriceRepositoryORM) FindAll(pp *page.Page, conds []builder.Cond) error
// FindColumnAll 查询专栏价格记录列表
func (p *PriceRepositoryORM) FindColumnAll(pp *page.Page, conds []builder.Cond) error {
return p.engine.FindAll(pp, "lc_price as p", builder.And(conds...), xorm_engine.Join{
return p.engine.FindAll(pp, &price.Price{}, builder.And(conds...), xorm_engine.Join{
JoinOperator: "left",
Tablename: "lc_column as c",
Condition: "p.target_id = c.id",
Condition: "lc_price.target_id = c.id",
})
}
@ -83,3 +79,8 @@ func (p *PriceRepositoryORM) Delete(id uint64) error {
_, err := p.engine.Delete(&price.Price{}, "id = ?", id)
return err
}
func (p *PriceRepositoryORM) FindPriceByIds(id *[]uint64, t price.PriceType) (*[]*price.Price, error) {
data := make([]*price.Price, 0)
return &data, p.engine.Where(builder.Eq{"type": t}.And(builder.In("target_id", *id))).Find(&data)
}

@ -0,0 +1,32 @@
package price_default
import (
"cls-server/internal/domain/price_default"
"cls-server/pkg/xorm_engine"
"xorm.io/builder"
)
type PriceDefaultRepositoryORM struct {
engine *xorm_engine.Engine
}
var _ price_default.PriceDefaultRepository = (*PriceDefaultRepositoryORM)(nil)
func NewPriceRepositoryORM(engine *xorm_engine.Engine) price_default.PriceDefaultRepository {
return &PriceDefaultRepositoryORM{engine}
}
func (p PriceDefaultRepositoryORM) Save(pd *price_default.PriceDefault) error {
if pd.Id > 0 {
_, err := p.engine.Update(pd)
return err
}
_, err := p.engine.Insert(pd)
return err
}
func (p PriceDefaultRepositoryORM) Get() (*price_default.PriceDefault, error) {
data := &price_default.PriceDefault{}
_, err := p.engine.Where(builder.Eq{"id": 1}).Get(data)
return data, err
}

@ -27,6 +27,7 @@ func (ch *ColumnHandler) RegisterRouters(app gin.IRouter) {
columnApp := app.Group("/column")
{
columnApp.GET("/page", ch.list)
columnApp.POST("/save", ch.save)
}
}
@ -47,3 +48,19 @@ func (ch *ColumnHandler) list(c *gin.Context) {
c.AbortWithStatusJSON(http.StatusOK, p)
}
}
func (ch *ColumnHandler) save(c *gin.Context) {
dto := &column.ColumnDto{}
err := c.ShouldBindJSON(dto)
if err != nil {
ch.log.Error(err)
c.AbortWithStatus(http.StatusInternalServerError)
return
}
err = ch.service.UpdateColumn(dto)
if err != nil {
c.AbortWithStatus(http.StatusInternalServerError)
} else {
c.AbortWithStatus(http.StatusOK)
}
}

@ -4,6 +4,8 @@ import (
"cls-server/internal/application/price"
"cls-server/internal/interfaces"
"cls-server/pkg/logger"
"cls-server/pkg/util/page"
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
@ -22,14 +24,15 @@ func NewPriceHandler(service *price.PriceService, log logger.New) *PriceHandler
func (h *PriceHandler) RegisterRouters(app gin.IRouter) {
auth := app.Group("/price")
{
auth.POST("/create", h.create)
auth.GET("/get", h.getPrice)
auth.PUT("/update", h.update)
//auth.GET("/page", h.getPriceList)
auth.GET("/page-article", h.getPriceArticle)
auth.GET("/page-column", h.getPriceColumn)
auth.GET("/get-default", h.getPriceDefault)
auth.POST("/update-default", h.updatePriceDefault)
auth.POST("/update", h.update)
}
}
func (h *PriceHandler) create(c *gin.Context) {
func (h *PriceHandler) update(c *gin.Context) {
dto := &price.PriceDto{}
err := c.ShouldBindJSON(dto)
if err != nil {
@ -37,7 +40,7 @@ func (h *PriceHandler) create(c *gin.Context) {
c.AbortWithStatus(http.StatusInternalServerError)
return
}
err = h.service.SetPrice(dto)
err = h.service.UpdatePrice(dto)
if err != nil {
h.log.Error(err)
c.AbortWithStatus(http.StatusInternalServerError)
@ -46,56 +49,65 @@ func (h *PriceHandler) create(c *gin.Context) {
}
}
func (h *PriceHandler) getPrice(c *gin.Context) {
dto := &price.PriceDto{}
func (h *PriceHandler) getPriceDefault(c *gin.Context) {
fmt.Println("进来了getPriceDefault………………")
p, err := h.service.GetPriceDefault()
if err != nil {
h.log.Error(err)
c.AbortWithStatus(http.StatusInternalServerError)
return
}
c.JSON(http.StatusOK, p)
}
func (h *PriceHandler) updatePriceDefault(c *gin.Context) {
dto := &price.PriceDefaultDto{}
err := c.ShouldBindJSON(dto)
if err != nil {
h.log.Error(err.Error())
c.AbortWithStatus(http.StatusInternalServerError)
return
}
price, err := h.service.GetPrice(dto)
err = h.service.UpdatePriceDefault(dto)
if err != nil {
h.log.Error(err)
c.AbortWithStatus(http.StatusInternalServerError)
return
} else {
c.AbortWithStatus(http.StatusOK)
}
c.JSON(http.StatusOK, price)
}
func (h *PriceHandler) update(c *gin.Context) {
dto := &price.PriceDto{}
err := c.ShouldBindJSON(dto)
func (h *PriceHandler) getPriceArticle(c *gin.Context) {
p := &page.Page{}
err := c.ShouldBindQuery(p)
if err != nil {
h.log.Error(err.Error())
c.AbortWithStatus(http.StatusInternalServerError)
return
}
err = h.service.UpdatePrice(dto)
err = h.service.GetArticlePricePage(p)
if err != nil {
h.log.Error(err)
h.log.Error(err.Error())
c.AbortWithStatus(http.StatusInternalServerError)
} else {
c.AbortWithStatus(http.StatusOK)
c.JSON(http.StatusOK, p)
}
}
//
//func (h *PriceHandler) getPriceList(c *gin.Context) {
// page := &page.Page{}
// err := c.ShouldBindJSON(page)
// if err != nil {
// h.log.Error(err.Error())
// c.AbortWithStatus(http.StatusInternalServerError)
// return
// }
// err = h.service.GetPriceList(page, map[string]string{
// "search_eq_type": c.Query("search_eq_type"),
// })
// if err != nil {
// h.log.Error(err)
// c.AbortWithStatus(http.StatusInternalServerError)
// return
// }
// c.JSON(http.StatusOK, page)
//}
func (h *PriceHandler) getPriceColumn(c *gin.Context) {
p := &page.Page{}
err := c.ShouldBindQuery(p)
if err != nil {
h.log.Error(err.Error())
c.AbortWithStatus(http.StatusInternalServerError)
return
}
err = h.service.GetColumnPricePage(p)
if err != nil {
h.log.Error(err.Error())
c.AbortWithStatus(http.StatusInternalServerError)
} else {
c.JSON(http.StatusOK, p)
}
}

@ -5,6 +5,7 @@ import (
"cls-server/internal/domain/coupon"
"cls-server/internal/domain/gift_log"
"cls-server/internal/domain/price"
"cls-server/internal/domain/price_default"
"cls-server/pkg/logger"
"cls-server/pkg/xorm_engine"
"go.uber.org/fx"
@ -32,6 +33,7 @@ func registerModels(engine *xorm_engine.Engine, logger logger.New) {
&gift_log.GiftLog{},
&price.Price{},
&coupon.Coupon{},
&price_default.PriceDefault{},
); err != nil {
log.Error(err)
}

@ -3,6 +3,7 @@ package modules
import (
service "cls-server/internal/application/price"
repo "cls-server/internal/infrastructure/persistence/price"
"cls-server/internal/infrastructure/persistence/price_default"
"cls-server/internal/interfaces"
"cls-server/internal/interfaces/price"
"go.uber.org/fx"
@ -12,5 +13,6 @@ var PriceModule = fx.Module("PriceModule",
fx.Provide(
interfaces.AsHandler(price.NewPriceHandler),
service.NewPriceService,
price_default.NewPriceRepositoryORM,
repo.NewPriceRepositoryORM,
))

@ -1,11 +1,40 @@
import { Article } from "./article";
import { Column } from "./column";
export interface Price {
id: number;
targetId: number;
type: string;
type: PriceType;
amount: number;
firstMontDiscount:number;
oneMonthPrice: number;
threeMonthsPrice: number;
sixMonthsPrice: number;
oneYearPrice: number;
discount: number;
}
export enum PriceType {
TypeArticle = 1,
TypeColumn = 2
}
export interface PriceDefault {
id: number;
amount: number;
firstMontDiscount:number;
oneMonthPrice: number;
threeMonthsPrice: number;
sixMonthsPrice: number;
oneYearPrice: number;
discount: number;
}
export interface ArticlePrice {
article: Article;
price: Price;
}
export interface ColumnPrice {
column: Column;
price: Price;
}

@ -1,5 +1,5 @@
<nz-page-header nzTitle="Title" nzSubtitle="This is a subtitle">
<nz-page-header nzTitle="专栏管理" nzSubtitle="对专栏进行编辑">
<nz-breadcrumb nz-page-header-breadcrumb>
<nz-breadcrumb-item>后台管理</nz-breadcrumb-item>
<nz-breadcrumb-item>
@ -44,31 +44,29 @@
<nz-avatar [nzSize]="64" nzIcon="field-time"></nz-avatar>
</ng-template>
<nz-list-item-meta-title>
<a>{{ item.title }}</a>
<div style="display: flex; justify-content: space-between; align-items: center;">
<nz-space nzAlign="center">
<span *nzSpaceItem style="font-weight: bold; font-size: 16px;">{{ item.title }}</span>
<nz-divider *nzSpaceItem nzType="vertical"></nz-divider>
<span *nzSpaceItem>专栏ID{{ item.id }}</span>
<nz-divider *nzSpaceItem nzType="vertical"></nz-divider>
<span *nzSpaceItem>文章数:{{ item.articleNum }}</span>
<nz-divider *nzSpaceItem nzType="vertical"></nz-divider>
<span *nzSpaceItem>关注人数:{{item.followNum}}</span>
<nz-divider *nzSpaceItem nzType="vertical"></nz-divider>
<span *nzSpaceItem>订购人数:{{item.purchaseNum}}</span>
</nz-space>
<button nz-button nzType="primary" (click)="editColumn(item)">
<i nz-icon nzType="edit" nzTheme="outline"></i>编辑
</button>
</div>
</nz-list-item-meta-title>
<nz-list-item-meta-description >
专栏ID{{ item.id }}
</nz-list-item-meta-description>
<nz-list-item-meta-description >
专栏介绍:{{ item.brief }}
</nz-list-item-meta-description>
<nz-list-item-meta-description >
关注人数:{{item.followNum}}
</nz-list-item-meta-description>
<nz-list-item-meta-description >
订购人数:{{item.purchaseNum}}
</nz-list-item-meta-description>
</nz-list-item-meta>
<!-- <nz-list-item-extra>-->
<!-- <nz-space>-->
<!-- <button nz-button nzType="primary" (click)="editColumn(item)"><i nz-icon-->
<!-- nzType="field-time"-->
<!-- nzTheme="outline"></i>编辑-->
<!-- </button>-->
<!-- </nz-space>-->
<nz-list-item-extra>
<span >专栏描述:{{item.brief}}</span>
<!-- </nz-list-item-extra>-->
</nz-list-item-extra>
</nz-card>
</nz-list-item>
</div>

@ -21,7 +21,7 @@ import {NzPaginationComponent} from "ng-zorro-antd/pagination";
import {NgFor} from "@angular/common";
import {EditColumnComponent} from "./edit-column/edit-column.component";
import {NzModalService} from "ng-zorro-antd/modal";
import {NzDividerModule} from "ng-zorro-antd/divider";
@Component({
selector: 'app-column',
standalone: true,
@ -39,6 +39,7 @@ import {NzModalService} from "ng-zorro-antd/modal";
NzPaginationComponent,
NzCardModule, NzGridModule, NzListModule,
NgFor,
NzDividerModule,
],
templateUrl: './column.component.html'
})
@ -129,29 +130,17 @@ export class ColumnComponent implements OnInit{
}
editColumn(column: Column) {
console.log(column)
const modal = this.modalService.create({
nzTitle: `更新基本信息`,
console.log('Editing column:', column);
const modalRef = this.modalService.create({
nzTitle: '编辑专栏',
nzContent: EditColumnComponent,
nzMaskClosable: false,
nzClosable: false,
nzData:{column:column},
nzFooter: [
{
label: '取消',
onClick: componentInstance => componentInstance!.handleCancel()
},
{
label: '确定',
type: 'primary',
loading: componentInstance => componentInstance!.isSaving,
onClick: componentInstance => componentInstance!.handleOk(),
disabled: componentInstance => !componentInstance!.validateForm.valid
}
]
})
modal.afterClose.subscribe(result => {
if (result != null) {
nzData: { column },
nzFooter: null,
nzWidth: 600
});
modalRef.afterClose.subscribe(result => {
if (result) {
this.loadData();
}
});

@ -1,37 +1,34 @@
<form *ngIf="validateForm" nz-form [formGroup]="validateForm">
<form nz-form [formGroup]="validateForm" nzLayout="vertical">
<nz-form-item>
<nz-form-label [nzSpan]="6" >专栏名</nz-form-label>
<nz-form-control [nzSpan]="14" >
<input nz-input type="text" formControlName="name" [disabled]="true" />
<nz-form-label>专栏名</nz-form-label>
<nz-form-control>
<input nz-input formControlName="title" [disabled]="true" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="6" nzRequired>专栏描述</nz-form-label>
<nz-form-control [nzSpan]="14" [nzErrorTip]="errorTpl1" nzHasFeedback>
<input nz-input type="text" formControlName="brief"/>
<ng-template #errorTpl1 let-control>
<ng-container *ngIf="control.hasError('required')">
描述不能为空
</ng-container>
</ng-template>
<nz-form-label nzRequired>专栏描述</nz-form-label>
<nz-form-control nzErrorTip="请输入专栏描述">
<input nz-input formControlName="brief" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="6" nzRequired>专栏封面</nz-form-label>
<nz-form-control [nzSpan]="14" [nzErrorTip]="errorTpl1" nzHasFeedback>
<input nz-input type="text" formControlName="cover"/>
<nz-form-label nzRequired>关注人数</nz-form-label>
<nz-form-control nzErrorTip="请输入有效的关注人数">
<input nz-input type="number" formControlName="followNum" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="6" nzRequired>关注人数</nz-form-label>
<nz-form-control [nzSpan]="14" [nzErrorTip]="errorTpl1" nzHasFeedback>
<input nz-input type="number" formControlName="followNum"/>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="6" nzRequired>购买人数</nz-form-label>
<nz-form-control [nzSpan]="14" [nzErrorTip]="errorTpl1" nzHasFeedback>
<input nz-input type="number" formControlName="purchaseNum"/>
<nz-form-label nzRequired>购买人数</nz-form-label>
<nz-form-control nzErrorTip="请输入有效的购买人数">
<input nz-input type="number" formControlName="purchaseNum" />
</nz-form-control>
</nz-form-item>
<div class="modal-footer">
<button nz-button nzType="default" (click)="handleCancel()">取消</button>
<button nz-button nzType="primary" (click)="handleOk()" [nzLoading]="isSaving" [disabled]="!validateForm.valid">保存</button>
</div>
</form>

@ -0,0 +1,27 @@
.modal-footer {
margin-top: 24px;
text-align: right;
button {
margin-left: 8px;
}
}
:host {
display: block;
width: 100%;
padding: 24px;
}
nz-form-item {
margin-bottom: 24px;
}
nz-form-label {
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
}
input {
width: 100%;
}

@ -1,12 +1,14 @@
import {Component, Input, OnInit} from '@angular/core';
import {Column} from "../../../core/models/column";
import {FormBuilder, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms";
import {NzModalRef} from "ng-zorro-antd/modal";
import {ColumnService} from "../column.service";
import {NzMessageService} from "ng-zorro-antd/message";
import {NzColDirective, NzRowDirective} from "ng-zorro-antd/grid";
import { Component, Inject, OnInit } from '@angular/core';
import { Column } from "../../../core/models/column";
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from "@angular/forms";
import { NzModalRef, NZ_MODAL_DATA } from "ng-zorro-antd/modal";
import { ColumnService } from "../column.service";
import { NzMessageService } from "ng-zorro-antd/message";
import { NzColDirective, NzRowDirective } from "ng-zorro-antd/grid";
import { NzFormModule } from 'ng-zorro-antd/form';
import {NzInputDirective} from "ng-zorro-antd/input";
import { NzInputDirective } from "ng-zorro-antd/input";
import { NzButtonModule } from 'ng-zorro-antd/button';
@Component({
selector: 'app-edit-column',
standalone: true,
@ -15,58 +17,61 @@ import {NzInputDirective} from "ng-zorro-antd/input";
NzRowDirective,
NzColDirective,
NzFormModule,
NzInputDirective
NzInputDirective,
NzButtonModule
],
templateUrl: './edit-column.component.html',
styleUrl: './edit-column.component.scss'
})
export class EditColumnComponent implements OnInit{
@Input() column!:Column
isSaving:boolean = false
export class EditColumnComponent implements OnInit {
isSaving: boolean = false;
validateForm!: FormGroup;
constructor(private fb:FormBuilder,
private modal:NzModalRef,
private columnService:ColumnService,
private message:NzMessageService) {
}
constructor(
private fb: FormBuilder,
private modal: NzModalRef,
private columnService: ColumnService,
private message: NzMessageService,
@Inject(NZ_MODAL_DATA) private data: { column: Column }
) {}
ngOnInit(): void {
console.log(this.column)
this.validateForm = this.fb.group({
id:[null,[Validators.required]],
title:[null,[Validators.required]],
brief:[null,[Validators.required]],
cover:[null],
followNum:[null,[Validators.required]],
purchaseNum:[null,[Validators.required]]
})
console.log('validateForm 初始化成功:', this.validateForm);
// if(this.column != null) {
// this.validateForm.patchValue(this.column);
//
// }
id: [this.data.column.id, [Validators.required]],
title: [this.data.column.title, [Validators.required]],
brief: [this.data.column.brief, [Validators.required]],
followNum: [this.data.column.followNum, [Validators.required, Validators.min(0)]],
purchaseNum: [this.data.column.purchaseNum, [Validators.required, Validators.min(0)]]
});
}
handleOk(): void {
//tslint:disable-next-line:forin
for (const i in this.validateForm.controls) {
this.validateForm.controls[i].markAsDirty();
}
if (this.validateForm.valid) {
this.isSaving = true;
this.columnService.save(this.validateForm.value).subscribe(() => {
this.isSaving = false;
this.message.success('保存成功');
this.modal.close('success');
}, (err) => {
this.message.error('保存失败');
this.isSaving = false;
this.columnService.save(this.validateForm.value).subscribe({
next: () => {
this.message.success('保存成功');
this.modal.close(true);
},
error: (error) => {
this.message.error('保存失败');
console.error('Error saving column:', error);
},
complete: () => {
this.isSaving = false;
}
});
} else {
Object.values(this.validateForm.controls).forEach(control => {
if (control.invalid) {
control.markAsDirty();
control.updateValueAndValidity({ onlySelf: true });
}
});
}
}
handleCancel(): void {
this.modal.destroy();
this.modal.close();
}
}

@ -0,0 +1,59 @@
<nz-card>
<!-- 搜索区域 -->
<div class="search-area">
<nz-input-group [nzSuffix]="suffixIconSearch">
<input type="text" nz-input placeholder="搜索文章名称" [(ngModel)]="searchParams['search_like_username']" (ngModelChange)="onValueChange.next($event)" />
</nz-input-group>
</div>
<!-- 表格区域 -->
<nz-table #basicTable
style="width: 100%"
nzSize="middle"
nzHideOnSinglePage
[nzLoading]="loading"
[nzShowTotal]="totalTemplate"
[nzFrontPagination]="false"
[nzPageSizeOptions]="[10,20,30]"
[nzShowSizeChanger]="true"
[nzPageIndex]="pageData?.pageNumber! +1 "
[nzPageSize]="pageData?.pageSize!"
[nzTotal]="pageData?.totalElements!"
[nzShowPagination]="true"
[nzData]="pageData?.items!"
(nzPageIndexChange)="changePaginationPage($event)"
(nzPageSizeChange)="changePaginationSize($event)">
<thead>
<tr>
<th>文章ID</th>
<th>文章名称</th>
<th>发布时间</th>
<th>价格(元)</th>
<th>折扣</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of basicTable.data">
<td>{{ data?.article?.eventId }}</td>
<td>{{ data?.article?.title }}</td>
<td>{{ data?.article?.releaseDate }} {{ data?.article?.releaseTime }}</td>
<td>{{ data?.price?.amount ? data.price.amount / 100:'默认价格' }}</td>
<td>{{ data?.price?.discount ? data.price.discount * 100 :'默认折扣'}}%</td>
<td>
<a (click)="editPrice(data)">编辑价格</a>
</td>
</tr>
</tbody>
</nz-table>
<ng-template #totalTemplate let-range="range" let-total>
<span style="padding: 0 0.5em;font-weight: bolder">{{range[0]}}-{{range[1]}}</span>个,共<span
style="padding: 0 0.5em;font-weight: bolder">{{total}}</span>
</ng-template>
</nz-card>
<ng-template #suffixIconSearch>
<span nz-icon nzType="search"></span>
</ng-template>

@ -0,0 +1,155 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Page } from '../../../core/models/page';
import { ArticlePrice } from '../../../core/models/price';
import { PriceService } from '../price.service';
import { debounceTime, distinctUntilChanged, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { ChangeDetectorRef } from '@angular/core';
import { NzMessageModule, NzMessageService } from 'ng-zorro-antd/message';
import { NzModalModule, NzModalService } from 'ng-zorro-antd/modal';
import { NzFormModule } from 'ng-zorro-antd/form';
import { NzInputModule } from 'ng-zorro-antd/input';
import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
import { NzCardModule } from 'ng-zorro-antd/card';
import { NzTableModule } from 'ng-zorro-antd/table';
import { NzIconModule } from 'ng-zorro-antd/icon';
import { FormsModule } from '@angular/forms';
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
import { NgForOf } from "@angular/common";
import { SetArticlePriceComponent } from "./set-article-price/set-article-price.component";
@Component({
selector: 'app-article',
standalone: true,
imports: [
NzMessageModule,
NzModalModule,
NzFormModule,
NzInputModule,
NzInputNumberModule,
NzCardModule,
NzTableModule,
NzIconModule,
FormsModule,
ReactiveFormsModule,
NgForOf,
SetArticlePriceComponent
],
templateUrl: './article.component.html',
styleUrl: './article.component.scss'
})
export class ArticleComponent implements OnInit, OnDestroy {
pageData: Page<ArticlePrice> = new Page<ArticlePrice>();
searchParams: { [param: string]: any } = {
page: 0,
size: 10,
search_like_username: ''
};
onValueChange = new Subject<string>();
loading = false;
destroy$ = new Subject();
editForm: FormGroup;
constructor(
private priceService: PriceService,
private cdr: ChangeDetectorRef,
private message: NzMessageService,
private modal: NzModalService,
private fb: FormBuilder
) {
this.onValueChange.pipe(
debounceTime(300),
distinctUntilChanged(),
takeUntil(this.destroy$)
).subscribe(() => {
this.searchParams['page'] = 0;
this.cdr.markForCheck();
this.loadData();
});
this.editForm = this.fb.group({
price: [null, [Validators.required, Validators.min(0)]],
discount: [1, [Validators.required, Validators.min(0), Validators.max(1)]]
});
}
ngOnInit(): void {
console.log('Component initialized');
this.onValueChange
.pipe(debounceTime(500))
.subscribe(() => {
this.loadData();
});
this.loadData();
}
ngOnDestroy(): void {
this.destroy$.next(null);
this.destroy$.complete();
}
loadData() {
console.log('Loading data with params:', this.searchParams);
this.loading = true;
this.cdr.detectChanges();
this.priceService.pageOfArticle(this.searchParams)
.pipe(takeUntil(this.destroy$))
.subscribe({
next: data => {
console.log('Raw response data:', data);
this.pageData = data;
console.log('Processed pageData:', this.pageData);
if (this.pageData?.items?.length > 0) {
console.log('First item:', this.pageData.items[0]);
console.log('First item article:', this.pageData.items[0]?.article);
console.log('First item price:', this.pageData.items[0]?.price);
}
this.loading = false;
this.cdr.detectChanges();
},
error: error => {
console.error('Error loading data:', error);
this.loading = false;
this.message.error("获取文章数据失败!");
this.cdr.detectChanges();
}
});
}
changePaginationPage(page: number): void {
console.log('Changing page to:', page);
this.searchParams['page'] = page - 1;
this.cdr.detectChanges();
this.loadData();
}
changePaginationSize(size: number): void {
console.log('Changing page size to:', size);
this.searchParams['page'] = 0;
this.searchParams['size'] = size;
this.cdr.detectChanges();
this.loadData();
}
editPrice(article: ArticlePrice) {
console.log('Editing article:', article);
const modalRef = this.modal.create<SetArticlePriceComponent>({
nzTitle: '编辑文章价格',
nzContent: SetArticlePriceComponent,
nzData: article,
nzFooter: null
});
modalRef.afterClose.subscribe(result => {
if (result) {
this.loadData();
}
});
}
// 将元转换为分
private convertYuanToCents(yuan: number): number {
return Math.round(yuan * 100);
}
}

@ -0,0 +1,20 @@
<form nz-form [formGroup]="editForm" nzLayout="vertical">
<nz-form-item>
<nz-form-label>价格(元)</nz-form-label>
<nz-form-control>
<nz-input-number formControlName="price" [nzMin]="0" [nzStep]="0.01"></nz-input-number>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label>折扣</nz-form-label>
<nz-form-control>
<nz-input-number formControlName="discount" [nzMin]="0" [nzMax]="1" [nzStep]="0.1"></nz-input-number>
</nz-form-control>
</nz-form-item>
<div class="modal-footer">
<button nz-button nzType="default" (click)="handleCancel()">取消</button>
<button nz-button nzType="primary" (click)="handleOk()" [disabled]="!editForm.valid">保存</button>
</div>
</form>

@ -0,0 +1,21 @@
:host {
display: block;
padding: 24px;
}
nz-form-item {
margin-bottom: 24px;
}
nz-input-number {
width: 100%;
}
.modal-footer {
margin-top: 24px;
text-align: right;
button {
margin-left: 8px;
}
}

@ -0,0 +1,71 @@
import { Component, Inject } from '@angular/core';
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
import { NzFormModule } from 'ng-zorro-antd/form';
import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
import { NzModalRef, NZ_MODAL_DATA } from 'ng-zorro-antd/modal';
import {ArticlePrice, Price, PriceType} from '../../../../core/models/price';
import { PriceService } from '../../price.service';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzButtonModule } from 'ng-zorro-antd/button';
@Component({
selector: 'app-set-article-price',
standalone: true,
imports: [
ReactiveFormsModule,
NzFormModule,
NzInputNumberModule,
NzButtonModule
],
templateUrl: './set-article-price.component.html',
styleUrls: ['./set-article-price.component.scss']
})
export class SetArticlePriceComponent {
editForm: FormGroup;
article: ArticlePrice;
priceType = PriceType;
constructor(
private fb: FormBuilder,
private modalRef: NzModalRef,
private priceService: PriceService,
private message: NzMessageService,
@Inject(NZ_MODAL_DATA) data: ArticlePrice
) {
this.article = data;
console.log(this.article)
const price = data?.price?.amount || 0;
const discount = data?.price?.discount || 1;
this.editForm = this.fb.group({
price: [price / 100, [Validators.required, Validators.min(0)]],
discount: [discount, [Validators.required, Validators.min(0), Validators.max(1)]]
});
}
handleOk(): void {
if (this.editForm.valid) {
const formValue = this.editForm.value;
const priceData = {
targetId:this.article.article.eventId,
type:this.priceType.TypeArticle,
amount: Math.round(formValue.price * 100),
discount: formValue.discount
};
this.priceService.update(priceData as Price).subscribe({
next: () => {
this.message.success('价格更新成功');
this.modalRef.close(true);
},
error: (error) => {
this.message.error('价格更新失败');
console.error('Error updating price:', error);
}
});
}
}
handleCancel(): void {
this.modalRef.close();
}
}

@ -0,0 +1,63 @@
<nz-card>
<!-- 搜索区域 -->
<div class="search-area">
<nz-input-group [nzSuffix]="suffixIconSearch">
<input type="text" nz-input placeholder="搜索专栏名称" [(ngModel)]="searchParams['search_like_username']" (ngModelChange)="onValueChange.next($event)" />
</nz-input-group>
</div>
<!-- 表格区域 -->
<nz-table #basicTable
style="width: 100%"
nzSize="middle"
nzHideOnSinglePage
[nzLoading]="loading"
[nzShowTotal]="totalTemplate"
[nzFrontPagination]="false"
[nzPageSizeOptions]="[10,20,30]"
[nzShowSizeChanger]="true"
[nzPageIndex]="pageData?.pageNumber! +1 "
[nzPageSize]="pageData?.pageSize!"
[nzTotal]="pageData?.totalElements!"
[nzShowPagination]="true"
[nzData]="pageData?.items!"
(nzPageIndexChange)="changePaginationPage($event)"
(nzPageSizeChange)="changePaginationSize($event)">
<thead>
<tr>
<th>专栏ID</th>
<th>专栏名称</th>
<th>一个月价格(元)</th>
<th>三个月价格(元)</th>
<th>半年价格(元)</th>
<th>一年价格(元)</th>
<th>首月折扣</th>
<th>折扣</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of basicTable.data">
<td>{{ data.column.id }}</td>
<td>{{ data.column.title }}</td>
<td>{{ data.price?.oneMonthPrice ? data.price.oneMonthPrice / 100 :'默认价格' }}</td>
<td>{{ data.price?.threeMonthsPrice ? data.price.threeMonthsPrice / 100 :'默认价格'}}</td>
<td>{{ data.price?.sixMonthsPrice ? data.price.sixMonthsPrice / 100 :'默认价格'}}</td>
<td>{{ data.price?.oneYearPrice ? data.price.oneYearPrice / 100 :'默认价格'}}</td>
<td>{{ data.price?.firstMontDiscount ? data.price.firstMontDiscount * 100 :'默认折扣'}}</td>
<td>{{ data.price?.discount ? data.price.discount * 100 :'默认折扣'}}</td>
<td>
<a (click)="editPrice(data)">编辑价格</a>
</td>
</tr>
</tbody>
</nz-table>
<ng-template #totalTemplate let-range="range" let-total>
<span style="padding: 0 0.5em;font-weight: bolder">{{range[0]}}-{{range[1]}}</span>个,共<span
style="padding: 0 0.5em;font-weight: bolder">{{total}}</span>
</ng-template>
</nz-card>
<ng-template #suffixIconSearch>
<span nz-icon nzType="search"></span>
</ng-template>

@ -0,0 +1,137 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Page } from '../../../core/models/page';
import { ColumnPrice } from '../../../core/models/price';
import { PriceService } from '../price.service';
import { debounceTime, distinctUntilChanged, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { ChangeDetectorRef } from '@angular/core';
import { NzMessageModule, NzMessageService } from 'ng-zorro-antd/message';
import { NzModalModule, NzModalService } from 'ng-zorro-antd/modal';
import { NzFormModule } from 'ng-zorro-antd/form';
import { NzInputModule } from 'ng-zorro-antd/input';
import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
import { NzCardModule } from 'ng-zorro-antd/card';
import { NzTableModule } from 'ng-zorro-antd/table';
import { NzIconModule } from 'ng-zorro-antd/icon';
import { FormsModule } from '@angular/forms';
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
import {SetColumnPriceComponent} from "./set-column-price/set-column-price.component";
import {NgForOf} from "@angular/common";
@Component({
selector: 'app-column',
standalone: true,
imports: [
NzMessageModule,
NzModalModule,
NzFormModule,
NzInputModule,
NzInputNumberModule,
NzCardModule,
NzTableModule,
NzIconModule,
FormsModule,
ReactiveFormsModule,
NgForOf
],
templateUrl: './column.component.html',
styleUrl: './column.component.scss'
})
export class ColumnComponent implements OnInit, OnDestroy {
pageData: Page<ColumnPrice> = new Page<ColumnPrice>();
searchParams: { [param: string]: any } = {
page: 0,
size: 10,
search_like_username: ''
};
onValueChange = new Subject<string>();
loading = false;
destroy$ = new Subject();
editForm: FormGroup;
constructor(
private priceService: PriceService,
private cdr: ChangeDetectorRef,
private message: NzMessageService,
private modal: NzModalService,
private fb: FormBuilder
) {
this.onValueChange.pipe(
debounceTime(300),
distinctUntilChanged(),
takeUntil(this.destroy$)
).subscribe(() => {
this.searchParams['page'] = 0;
this.cdr.markForCheck();
this.loadData();
});
this.editForm = this.fb.group({
oneMonthPrice: [null, [Validators.required, Validators.min(0)]],
threeMonthsPrice: [null, [Validators.required, Validators.min(0)]],
sixMonthsPrice: [null, [Validators.required, Validators.min(0)]],
oneYearPrice: [null, [Validators.required, Validators.min(0)]]
});
}
ngOnInit(): void {
this.loadData();
}
ngOnDestroy(): void {
this.destroy$.next(null);
this.destroy$.complete();
}
loadData() {
this.loading = true;
this.cdr.detectChanges();
this.priceService.pageOfColumn(this.searchParams)
.pipe(takeUntil(this.destroy$))
.subscribe({
next: data => {
this.loading = false;
this.pageData = data;
},
error: data => {
console.log(data)
this.loading = false;
this.message.error("获取专栏数据失败!");
}
});
}
changePaginationPage(page: number): void {
this.searchParams['page'] = page - 1;
this.cdr.detectChanges();
this.loadData();
}
changePaginationSize(size: number): void {
this.searchParams['page'] = 0;
this.searchParams['size'] = size;
this.cdr.detectChanges();
this.loadData();
}
editPrice(columnPrice: ColumnPrice) {
console.log('Editing column:', columnPrice);
const modalRef = this.modal.create<SetColumnPriceComponent>({
nzTitle: '编辑专栏价格',
nzContent: SetColumnPriceComponent,
nzData: columnPrice,
nzFooter: null
});
modalRef.afterClose.subscribe(result => {
if (result) {
this.loadData();
}
});
}
// 将元转换为分
private convertYuanToCents(yuan: number): number {
return Math.round(yuan * 100);
}
}

@ -0,0 +1,48 @@
<form nz-form [formGroup]="editForm" nzLayout="vertical">
<nz-form-item>
<nz-form-label>一个月价格</nz-form-label>
<nz-form-control nzErrorTip="请输入有效的价格">
<nz-input-number class="full-width" formControlName="oneMonthPrice" [nzMin]="0" [nzStep]="0.01" [nzPrecision]="2" [nzPlaceHolder]="''" [nzFormatter]="yuanFormatter" [nzParser]="yuanParser"></nz-input-number>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label>三个月价格</nz-form-label>
<nz-form-control nzErrorTip="请输入有效的价格">
<nz-input-number class="full-width" formControlName="threeMonthsPrice" [nzMin]="0" [nzStep]="0.01" [nzPrecision]="2" [nzPlaceHolder]="''" [nzFormatter]="yuanFormatter" [nzParser]="yuanParser"></nz-input-number>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label>半年价格</nz-form-label>
<nz-form-control nzErrorTip="请输入有效的价格">
<nz-input-number class="full-width" formControlName="sixMonthsPrice" [nzMin]="0" [nzStep]="0.01" [nzPrecision]="2" [nzPlaceHolder]="''" [nzFormatter]="yuanFormatter" [nzParser]="yuanParser"></nz-input-number>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label>一年价格</nz-form-label>
<nz-form-control nzErrorTip="请输入有效的价格">
<nz-input-number class="full-width" formControlName="oneYearPrice" [nzMin]="0" [nzStep]="0.01" [nzPrecision]="2" [nzPlaceHolder]="''" [nzFormatter]="yuanFormatter" [nzParser]="yuanParser"></nz-input-number>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label>首月折扣</nz-form-label>
<nz-form-control nzErrorTip="请输入0-1之间的折扣">
<nz-input-number class="full-width" formControlName="firstMontDiscount" [nzMin]="0" [nzMax]="1" [nzStep]="0.1" [nzPrecision]="2" [nzPlaceHolder]="''" [nzFormatter]="percentFormatter" [nzParser]="percentParser"></nz-input-number>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label>折扣</nz-form-label>
<nz-form-control nzErrorTip="请输入0-1之间的折扣">
<nz-input-number class="full-width" formControlName="discount" [nzMin]="0" [nzMax]="1" [nzStep]="0.1" [nzPrecision]="2" [nzPlaceHolder]="''" [nzFormatter]="percentFormatter" [nzParser]="percentParser"></nz-input-number>
</nz-form-control>
</nz-form-item>
<div class="modal-footer">
<button nz-button nzType="default" (click)="handleCancel()">取消</button>
<button nz-button nzType="primary" (click)="handleOk()" [disabled]="!editForm.valid">保存</button>
</div>
</form>

@ -0,0 +1,31 @@
.modal-footer {
margin-top: 24px;
text-align: right;
button {
margin-left: 8px;
}
}
:host {
display: block;
width: 100%;
padding: 24px;
}
.full-width {
width: 100%;
}
nz-form-item {
margin-bottom: 24px;
}
nz-form-label {
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
}
nz-input-number {
width: 100%;
}

@ -0,0 +1,94 @@
import { Component, Inject } from '@angular/core';
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
import { NzFormModule } from 'ng-zorro-antd/form';
import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
import { NzModalRef, NZ_MODAL_DATA } from 'ng-zorro-antd/modal';
import { ColumnPrice } from '../../../../core/models/price';
import { PriceService } from '../../price.service';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzButtonModule } from 'ng-zorro-antd/button';
@Component({
selector: 'app-set-column-price',
standalone: true,
imports: [
ReactiveFormsModule,
NzFormModule,
NzInputNumberModule,
NzButtonModule
],
templateUrl: './set-column-price.component.html',
styleUrls: ['./set-column-price.component.scss']
})
export class SetColumnPriceComponent {
editForm: FormGroup;
column: ColumnPrice;
// 价格格式化器
yuanFormatter = (value: number): string => {
return value ? `¥ ${value}` : '';
};
yuanParser = (value: string): string => {
return value.replace(/[^0-9.]/g, '');
};
// 百分比格式化器
percentFormatter = (value: number): string => {
return value ? `${(value * 100).toFixed(0)}%` : '';
};
percentParser = (value: string): string => {
return value.replace('%', '').trim();
};
constructor(
private fb: FormBuilder,
private modalRef: NzModalRef,
private priceService: PriceService,
private message: NzMessageService,
@Inject(NZ_MODAL_DATA) data: ColumnPrice
) {
this.column = data;
const price = data?.price || {};
this.editForm = this.fb.group({
oneMonthPrice: [price?.oneMonthPrice ? price.oneMonthPrice / 100 : 0, [Validators.required, Validators.min(0)]],
threeMonthsPrice: [price?.threeMonthsPrice ? price.threeMonthsPrice / 100 : 0, [Validators.required, Validators.min(0)]],
sixMonthsPrice: [price?.sixMonthsPrice ? price.sixMonthsPrice / 100 : 0, [Validators.required, Validators.min(0)]],
oneYearPrice: [price?.oneYearPrice ? price.oneYearPrice / 100 : 0, [Validators.required, Validators.min(0)]],
firstMontDiscount: [price?.firstMontDiscount || 1, [Validators.required, Validators.min(0), Validators.max(1)]],
discount: [price?.discount || 1, [Validators.required, Validators.min(0), Validators.max(1)]]
});
}
handleOk(): void {
if (this.editForm.valid) {
const formValue = this.editForm.value;
const priceData = {
...this.column.price,
oneMonthPrice: Math.round(formValue.oneMonthPrice * 100),
threeMonthsPrice: Math.round(formValue.threeMonthsPrice * 100),
sixMonthsPrice: Math.round(formValue.sixMonthsPrice * 100),
oneYearPrice: Math.round(formValue.oneYearPrice * 100),
firstMontDiscount: formValue.firstMontDiscount,
discount: formValue.discount
};
this.priceService.update(priceData).subscribe({
next: () => {
this.message.success('价格更新成功');
this.modalRef.close(true);
},
error: (error) => {
this.message.error('价格更新失败');
console.error('Error updating price:', error);
}
});
}
}
handleCancel(): void {
this.modalRef.close();
}
}

@ -0,0 +1,70 @@
<nz-card>
<form nz-form [formGroup]="priceForm" (ngSubmit)="onSubmit()" nzLayout="vertical">
<nz-form-item>
<nz-form-label [nzSpan]="6">单次解锁价格</nz-form-label>
<nz-form-control [nzSpan]="14" nzErrorTip="请输入有效的单次解锁价格">
<nz-input-group [nzAddOnAfter]="suffixTemplate">
<nz-input-number formControlName="amount" [nzMin]="0" [nzStep]="0.01" style="width: 100%"></nz-input-number>
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="6">首月折扣率 (%)</nz-form-label>
<nz-form-control [nzSpan]="14" nzErrorTip="请输入有效的首月折扣率0-100">
<nz-input-number formControlName="firstMontDiscount" [nzMin]="0" [nzMax]="100" [nzStep]="1" style="width: 100%"></nz-input-number>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="6">一个月价格</nz-form-label>
<nz-form-control [nzSpan]="14" nzErrorTip="请输入有效的一个月价格">
<nz-input-group [nzAddOnAfter]="suffixTemplate">
<nz-input-number formControlName="oneMonthPrice" [nzMin]="0" [nzStep]="0.01" style="width: 100%"></nz-input-number>
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="6">三个月价格</nz-form-label>
<nz-form-control [nzSpan]="14" nzErrorTip="请输入有效的三个月价格">
<nz-input-group [nzAddOnAfter]="suffixTemplate">
<nz-input-number formControlName="threeMonthsPrice" [nzMin]="0" [nzStep]="0.01" style="width: 100%"></nz-input-number>
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="6">六个月价格</nz-form-label>
<nz-form-control [nzSpan]="14" nzErrorTip="请输入有效的六个月价格">
<nz-input-group [nzAddOnAfter]="suffixTemplate">
<nz-input-number formControlName="sixMonthsPrice" [nzMin]="0" [nzStep]="0.01" style="width: 100%"></nz-input-number>
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="6">一年价格</nz-form-label>
<nz-form-control [nzSpan]="14" nzErrorTip="请输入有效的一年价格">
<nz-input-group [nzAddOnAfter]="suffixTemplate">
<nz-input-number formControlName="oneYearPrice" [nzMin]="0" [nzStep]="0.01" style="width: 100%"></nz-input-number>
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="6">折扣率 (%)</nz-form-label>
<nz-form-control [nzSpan]="14" nzErrorTip="请输入有效的折扣率0-100">
<nz-input-number formControlName="discount" [nzMin]="0" [nzMax]="100" [nzStep]="1" style="width: 100%"></nz-input-number>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzOffset]="6" [nzSpan]="14">
<button nz-button nzType="primary" [nzLoading]="loading" type="submit">保存设置</button>
</nz-form-control>
</nz-form-item>
</form>
</nz-card>
<ng-template #suffixTemplate>
<span></span>
</ng-template>

@ -0,0 +1,122 @@
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NzFormModule } from 'ng-zorro-antd/form';
import { NzInputModule } from 'ng-zorro-antd/input';
import { NzButtonModule } from 'ng-zorro-antd/button';
import { NzMessageService } from 'ng-zorro-antd/message';
import { PriceService } from '../price.service';
import { PriceDefault } from '../../../core/models/price';
import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
import { NzCardModule } from 'ng-zorro-antd/card';
@Component({
selector: 'app-price-default',
standalone: true,
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
NzFormModule,
NzInputModule,
NzButtonModule,
NzInputNumberModule,
NzCardModule,
],
templateUrl: './price-default.component.html',
styleUrl: './price-default.component.scss'
})
export class PriceDefaultComponent implements OnInit {
priceForm: FormGroup;
loading = false;
constructor(
private fb: FormBuilder,
private priceService: PriceService,
private message: NzMessageService
) {
this.priceForm = this.fb.group({
amount: [null, [Validators.required, Validators.min(0)]],
firstMontDiscount: [null, [Validators.required, Validators.min(0), Validators.max(100)]],
oneMonthPrice: [null, [Validators.required, Validators.min(0)]],
threeMonthsPrice: [null, [Validators.required, Validators.min(0)]],
sixMonthsPrice: [null, [Validators.required, Validators.min(0)]],
oneYearPrice: [null, [Validators.required, Validators.min(0)]],
discount: [null, [Validators.required, Validators.min(0), Validators.max(100)]]
});
}
ngOnInit() {
this.loadDefaultPrice();
}
// 将分转换为元
private convertCentsToYuan(cents: number): number {
return cents / 100;
}
// 将元转换为分
private convertYuanToCents(yuan: number): number {
return Math.round(yuan * 100);
}
loadDefaultPrice() {
this.loading = true;
this.priceService.getDefaultPrice().subscribe({
next: (data) => {
// 将后端返回的分转换为元
const formData = {
...data,
amount: this.convertCentsToYuan(data.amount),
oneMonthPrice: this.convertCentsToYuan(data.oneMonthPrice),
threeMonthsPrice: this.convertCentsToYuan(data.threeMonthsPrice),
sixMonthsPrice: this.convertCentsToYuan(data.sixMonthsPrice),
oneYearPrice: this.convertCentsToYuan(data.oneYearPrice)
};
this.priceForm.patchValue(formData);
this.loading = false;
},
error: (error) => {
this.message.error('获取默认价格失败');
this.loading = false;
}
});
}
onSubmit() {
if (this.priceForm.valid) {
this.loading = true;
const formValue = this.priceForm.value;
// 将表单中的元转换为分
const priceData: PriceDefault = {
id: 1,
amount: this.convertYuanToCents(formValue.amount),
firstMontDiscount: formValue.firstMontDiscount,
oneMonthPrice: this.convertYuanToCents(formValue.oneMonthPrice),
threeMonthsPrice: this.convertYuanToCents(formValue.threeMonthsPrice),
sixMonthsPrice: this.convertYuanToCents(formValue.sixMonthsPrice),
oneYearPrice: this.convertYuanToCents(formValue.oneYearPrice),
discount: formValue.discount
};
this.priceService.updateDefaultPrice(priceData).subscribe({
next: () => {
this.message.success('更新默认价格成功');
this.loadDefaultPrice();
},
error: (error) => {
this.message.error('更新默认价格失败');
this.loading = false;
}
});
} else {
Object.values(this.priceForm.controls).forEach(control => {
if (control.invalid) {
control.markAsTouched();
control.updateValueAndValidity({ onlySelf: true });
}
});
}
}
}

@ -1,11 +1,28 @@
<nz-page-header nzTitle="Title" nzSubtitle="This is a subtitle">
<nz-page-header nzTitle="价格管理" nzSubtitle="专栏和文章价格管理界面">
<nz-breadcrumb nz-page-header-breadcrumb>
<nz-breadcrumb-item>First-level Menu</nz-breadcrumb-item>
<nz-breadcrumb-item>后台管理</nz-breadcrumb-item>
<nz-breadcrumb-item>
<a>Second-level Menu</a>
<a>价格管理</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>Third-level Menu</nz-breadcrumb-item>
<nz-breadcrumb-item>价格管理</nz-breadcrumb-item>
</nz-breadcrumb>
</nz-page-header>
<br />
<nz-card style="width: 100%;">
<nz-card-tab>
<nz-tabset nzSize="large" >
<nz-tab nzTitle="默认价格">
<app-price-default></app-price-default>
</nz-tab>
<nz-tab nzTitle="专栏">
<app-column></app-column>
</nz-tab>
<nz-tab nzTitle="文章">
<app-article></app-article>
</nz-tab>
</nz-tabset>
</nz-card-tab>
</nz-card>

@ -1,22 +0,0 @@
import { fakeAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { PriceComponent } from './price.component';
describe('PriceComponent', () => {
let component: PriceComponent;
let fixture: ComponentFixture<PriceComponent>;
beforeEach(fakeAsync(() => {
TestBed.configureTestingModule({
declarations: [ PriceComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(PriceComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should compile', () => {
expect(component).toBeTruthy();
});
});

@ -2,11 +2,27 @@ import { Component } from '@angular/core';
import { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';
import { NzPageHeaderModule } from 'ng-zorro-antd/page-header';
import {NzTabsModule} from "ng-zorro-antd/tabs";
import {ColumnComponent} from "./column/column.component";
import {ArticleComponent} from "./article/article.component";
import { NzCardModule} from "ng-zorro-antd/card";
import {PriceDefaultComponent} from "./price-default/price-default.component";
@Component({
selector: 'app-price',
standalone: true,
imports: [NzBreadCrumbModule, NzPageHeaderModule],
imports: [
NzBreadCrumbModule,
NzPageHeaderModule,
NzTabsModule,
ColumnComponent,
ArticleComponent,
NzCardModule,
PriceDefaultComponent,
],
templateUrl: './price.component.html'
})
export class PriceComponent {}
export class PriceComponent {
constructor() {
}
}

@ -0,0 +1,53 @@
import { Injectable } from '@angular/core';
import {HttpClient} from "@angular/common/http";
import {Observable} from "rxjs";
import {Price, PriceDefault} from "../../core/models/price";
import {extractData, Page} from "../../core/models/page";
import {map} from "rxjs/operators";
import {HttpUtils} from "../../core/until/http.utils";
import { ArticlePrice, ColumnPrice } from '../../core/models/price';
import {Article} from "../../core/models/article";
@Injectable({
providedIn: 'root'
})
export class PriceService {
constructor(private http:HttpClient) { }
// auth.POST("/create", h.create)
// auth.GET("/get-default", h.getPriceDefault)
// auth.POST("/update-default", h.updatePriceDefault)
// auth.POST("/update", h.update)
// auth.GET("/page-article", h.getPriceArticle)
// auth.GET("/page-column", h.getPriceColumn)
// pageOfArticle(searchParams: { [key: string]: string }):Observable<Page<ArticlePrice>> {
// return this.http.get<Page<ArticlePrice>>('/api/price/page-article"',
// {params:HttpUtils.getSearchParams(searchParams)}).pipe(
// map(response=> extractData<ArticlePrice>(response))
// )
// }
pageOfArticle(searchParams:{[key:string]:string}):Observable<Page<ArticlePrice>> {
return this.http.get<Page<ArticlePrice>>('/api/price/page-article',{
params:HttpUtils.getSearchParams(searchParams)
}).pipe(map(response => extractData<ArticlePrice>(response)))
}
pageOfColumn(searchParams:{[key:string]:string}):Observable<Page<ColumnPrice>> {
console.log("come in")
return this.http.get<Page<ColumnPrice>>('/api/price/page-column',{
params:HttpUtils.getSearchParams(searchParams)
}).pipe(
map(response => extractData<ColumnPrice>(response ))
)
}
getDefaultPrice():Observable<PriceDefault> {
return this.http.get<PriceDefault>('/api/price/get-default')
}
updateDefaultPrice(pd:PriceDefault):Observable<null> {
return this.http.post<null>('/api/price/update-default',pd)
}
update(price: Price): Observable<any> {
return this.http.post('/api/price/update', price);
}
}

@ -18,7 +18,8 @@ export class UserService {
page(searchParams: { [key: string]: string }):Observable<Page<UserInfo>>{
return this.http.get<Page<UserInfo>>('/api/user/page',{params:HttpUtils.getSearchParams(searchParams)}).pipe(
return this.http.get<Page<UserInfo>>('/api/user/page',
{params:HttpUtils.getSearchParams(searchParams)}).pipe(
map(response=> extractData<UserInfo>(response))
)
}

Loading…
Cancel
Save