first commit

This commit is contained in:
2025-09-21 18:27:25 +08:00
commit 02e1c4bd63
528 changed files with 55690 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
package admin_product
import (
"context"
"database/sql"
"hm-server/app/main/api/internal/svc"
"hm-server/app/main/api/internal/types"
"hm-server/app/main/model"
"hm-server/common/xerr"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
)
type AdminCreateProductLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAdminCreateProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminCreateProductLogic {
return &AdminCreateProductLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *AdminCreateProductLogic) AdminCreateProduct(req *types.AdminCreateProductReq) (resp *types.AdminCreateProductResp, err error) {
// 1. 数据转换
data := &model.Product{
ProductName: req.ProductName,
ProductEn: req.ProductEn,
Description: req.Description,
Notes: sql.NullString{String: req.Notes, Valid: req.Notes != ""},
CostPrice: req.CostPrice,
SellPrice: req.SellPrice,
}
// 2. 数据库操作
result, err := l.svcCtx.ProductModel.Insert(l.ctx, nil, data)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
"创建产品失败, err: %v, req: %+v", err, req)
}
// 3. 返回结果
id, _ := result.LastInsertId()
return &types.AdminCreateProductResp{Id: id}, nil
}

View File

@@ -0,0 +1,44 @@
package admin_product
import (
"context"
"hm-server/app/main/api/internal/svc"
"hm-server/app/main/api/internal/types"
"hm-server/common/xerr"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
)
type AdminDeleteProductLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAdminDeleteProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminDeleteProductLogic {
return &AdminDeleteProductLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *AdminDeleteProductLogic) AdminDeleteProduct(req *types.AdminDeleteProductReq) (resp *types.AdminDeleteProductResp, err error) {
// 1. 查询记录是否存在
record, err := l.svcCtx.ProductModel.FindOne(l.ctx, req.Id)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
"查找产品失败, err: %v, id: %d", err, req.Id)
}
// 2. 执行软删除
err = l.svcCtx.ProductModel.DeleteSoft(l.ctx, nil, record)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
"删除产品失败, err: %v, id: %d", err, req.Id)
}
// 3. 返回结果
return &types.AdminDeleteProductResp{Success: true}, nil
}

View File

@@ -0,0 +1,49 @@
package admin_product
import (
"context"
"hm-server/app/main/api/internal/svc"
"hm-server/app/main/api/internal/types"
"hm-server/common/xerr"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
)
type AdminGetProductDetailLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAdminGetProductDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetProductDetailLogic {
return &AdminGetProductDetailLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *AdminGetProductDetailLogic) AdminGetProductDetail(req *types.AdminGetProductDetailReq) (resp *types.AdminGetProductDetailResp, err error) {
// 1. 查询记录
record, err := l.svcCtx.ProductModel.FindOne(l.ctx, req.Id)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
"查找产品失败, err: %v, id: %d", err, req.Id)
}
// 2. 构建响应
resp = &types.AdminGetProductDetailResp{
Id: record.Id,
ProductName: record.ProductName,
ProductEn: record.ProductEn,
Description: record.Description,
Notes: record.Notes.String,
CostPrice: record.CostPrice,
SellPrice: record.SellPrice,
CreateTime: record.CreateTime.Format("2006-01-02 15:04:05"),
UpdateTime: record.UpdateTime.Format("2006-01-02 15:04:05"),
}
return resp, nil
}

View File

@@ -0,0 +1,119 @@
package admin_product
import (
"context"
"hm-server/app/main/api/internal/svc"
"hm-server/app/main/api/internal/types"
"hm-server/app/main/model"
"hm-server/common/xerr"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/mr"
)
type AdminGetProductFeatureListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAdminGetProductFeatureListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetProductFeatureListLogic {
return &AdminGetProductFeatureListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *AdminGetProductFeatureListLogic) AdminGetProductFeatureList(req *types.AdminGetProductFeatureListReq) (resp *[]types.AdminGetProductFeatureListResp, err error) {
// 1. 构建查询条件
builder := l.svcCtx.ProductFeatureModel.SelectBuilder().
Where("product_id = ?", req.ProductId)
// 2. 执行查询
list, err := l.svcCtx.ProductFeatureModel.FindAll(l.ctx, builder, "sort ASC")
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
"查询产品功能列表失败, err: %v, product_id: %d", err, req.ProductId)
}
// 3. 获取所有功能ID
featureIds := make([]int64, 0, len(list))
for _, item := range list {
featureIds = append(featureIds, item.FeatureId)
}
// 4. 并发查询功能详情
type featureResult struct {
feature *model.Feature
err error
}
results := make([]featureResult, len(featureIds))
err = mr.MapReduceVoid(func(source chan<- interface{}) {
for i, id := range featureIds {
source <- struct {
index int
id int64
}{i, id}
}
}, func(item interface{}, writer mr.Writer[featureResult], cancel func(error)) {
data := item.(struct {
index int
id int64
})
feature, err := l.svcCtx.FeatureModel.FindOne(l.ctx, data.id)
writer.Write(featureResult{
feature: feature,
err: err,
})
}, func(pipe <-chan featureResult, cancel func(error)) {
for result := range pipe {
if result.err != nil {
l.Logger.Errorf("查询功能详情失败, feature_id: %d, err: %v", result.feature.Id, result.err)
continue
}
results = append(results, result)
}
})
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR),
"并发查询功能详情失败, err: %v", err)
}
// 5. 构建功能ID到详情的映射
featureMap := make(map[int64]*model.Feature)
for _, result := range results {
if result.feature != nil {
featureMap[result.feature.Id] = result.feature
}
}
// 6. 构建响应列表
items := make([]types.AdminGetProductFeatureListResp, 0, len(list))
for _, item := range list {
feature, exists := featureMap[item.FeatureId]
if !exists {
continue // 跳过不存在的功能
}
listItem := types.AdminGetProductFeatureListResp{
Id: item.Id,
ProductId: item.ProductId,
FeatureId: item.FeatureId,
ApiId: feature.ApiId,
Name: feature.Name,
Sort: item.Sort,
Enable: item.Enable,
IsImportant: item.IsImportant,
CreateTime: item.CreateTime.Format("2006-01-02 15:04:05"),
UpdateTime: item.UpdateTime.Format("2006-01-02 15:04:05"),
}
items = append(items, listItem)
}
// 7. 返回结果
return &items, nil
}

View File

@@ -0,0 +1,69 @@
package admin_product
import (
"context"
"hm-server/app/main/api/internal/svc"
"hm-server/app/main/api/internal/types"
"hm-server/common/xerr"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
)
type AdminGetProductListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAdminGetProductListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetProductListLogic {
return &AdminGetProductListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *AdminGetProductListLogic) AdminGetProductList(req *types.AdminGetProductListReq) (resp *types.AdminGetProductListResp, err error) {
// 1. 构建查询条件
builder := l.svcCtx.ProductModel.SelectBuilder()
// 2. 添加查询条件
if req.ProductName != nil && *req.ProductName != "" {
builder = builder.Where("product_name LIKE ?", "%"+*req.ProductName+"%")
}
if req.ProductEn != nil && *req.ProductEn != "" {
builder = builder.Where("product_en LIKE ?", "%"+*req.ProductEn+"%")
}
// 3. 执行分页查询
list, total, err := l.svcCtx.ProductModel.FindPageListByPageWithTotal(
l.ctx, builder, req.Page, req.PageSize, "id DESC")
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
"查询产品列表失败, err: %v, req: %+v", err, req)
}
// 4. 构建响应列表
items := make([]types.ProductListItem, 0, len(list))
for _, item := range list {
listItem := types.ProductListItem{
Id: item.Id,
ProductName: item.ProductName,
ProductEn: item.ProductEn,
Description: item.Description,
Notes: item.Notes.String,
CostPrice: item.CostPrice,
SellPrice: item.SellPrice,
CreateTime: item.CreateTime.Format("2006-01-02 15:04:05"),
UpdateTime: item.UpdateTime.Format("2006-01-02 15:04:05"),
}
items = append(items, listItem)
}
// 5. 返回结果
return &types.AdminGetProductListResp{
Total: total,
Items: items,
}, nil
}

View File

@@ -0,0 +1,159 @@
package admin_product
import (
"context"
"sync"
"hm-server/app/main/api/internal/svc"
"hm-server/app/main/api/internal/types"
"hm-server/app/main/model"
"hm-server/common/xerr"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/mr"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
type AdminUpdateProductFeaturesLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAdminUpdateProductFeaturesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUpdateProductFeaturesLogic {
return &AdminUpdateProductFeaturesLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *AdminUpdateProductFeaturesLogic) AdminUpdateProductFeatures(req *types.AdminUpdateProductFeaturesReq) (resp *types.AdminUpdateProductFeaturesResp, err error) {
// 1. 查询现有关联
builder := l.svcCtx.ProductFeatureModel.SelectBuilder().
Where("product_id = ?", req.ProductId)
existingList, err := l.svcCtx.ProductFeatureModel.FindAll(l.ctx, builder, "id ASC")
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
"查询现有产品功能关联失败, err: %v, product_id: %d", err, req.ProductId)
}
// 2. 构建现有关联的映射
existingMap := make(map[int64]*model.ProductFeature)
for _, item := range existingList {
existingMap[item.FeatureId] = item
}
// 3. 构建新关联的映射
newMap := make(map[int64]*types.ProductFeatureItem)
for _, item := range req.Features {
newMap[item.FeatureId] = &item
}
// 4. 在事务中执行更新操作
err = l.svcCtx.ProductFeatureModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
// 4.1 处理需要删除的关联
var mu sync.Mutex
var deleteIds []int64
err = mr.MapReduceVoid(func(source chan<- interface{}) {
for featureId, existing := range existingMap {
if _, exists := newMap[featureId]; !exists {
source <- existing.Id
}
}
}, func(item interface{}, writer mr.Writer[struct{}], cancel func(error)) {
id := item.(int64)
mu.Lock()
deleteIds = append(deleteIds, id)
mu.Unlock()
}, func(pipe <-chan struct{}, cancel func(error)) {
// 等待所有ID收集完成
})
if err != nil {
return errors.Wrapf(err, "收集待删除ID失败")
}
// 批量删除
if len(deleteIds) > 0 {
for _, id := range deleteIds {
err = l.svcCtx.ProductFeatureModel.Delete(ctx, session, id)
if err != nil {
return errors.Wrapf(err, "删除产品功能关联失败, product_id: %d, id: %d",
req.ProductId, id)
}
}
}
// 4.2 并发处理需要新增或更新的关联
var updateErr error
err = mr.MapReduceVoid(func(source chan<- interface{}) {
for featureId, newItem := range newMap {
source <- struct {
featureId int64
newItem *types.ProductFeatureItem
existing *model.ProductFeature
}{
featureId: featureId,
newItem: newItem,
existing: existingMap[featureId],
}
}
}, func(item interface{}, writer mr.Writer[struct{}], cancel func(error)) {
data := item.(struct {
featureId int64
newItem *types.ProductFeatureItem
existing *model.ProductFeature
})
if data.existing != nil {
// 更新现有关联
data.existing.Sort = data.newItem.Sort
data.existing.Enable = data.newItem.Enable
data.existing.IsImportant = data.newItem.IsImportant
_, err = l.svcCtx.ProductFeatureModel.Update(ctx, session, data.existing)
if err != nil {
updateErr = errors.Wrapf(err, "更新产品功能关联失败, product_id: %d, feature_id: %d",
req.ProductId, data.featureId)
cancel(updateErr)
return
}
} else {
// 新增关联
newFeature := &model.ProductFeature{
ProductId: req.ProductId,
FeatureId: data.featureId,
Sort: data.newItem.Sort,
Enable: data.newItem.Enable,
IsImportant: data.newItem.IsImportant,
}
_, err = l.svcCtx.ProductFeatureModel.Insert(ctx, session, newFeature)
if err != nil {
updateErr = errors.Wrapf(err, "新增产品功能关联失败, product_id: %d, feature_id: %d",
req.ProductId, data.featureId)
cancel(updateErr)
return
}
}
}, func(pipe <-chan struct{}, cancel func(error)) {
// 等待所有更新完成
})
if err != nil {
return errors.Wrapf(err, "并发更新产品功能关联失败")
}
if updateErr != nil {
return updateErr
}
return nil
})
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
"更新产品功能关联失败, err: %v, req: %+v", err, req)
}
// 5. 返回结果
return &types.AdminUpdateProductFeaturesResp{Success: true}, nil
}

View File

@@ -0,0 +1,65 @@
package admin_product
import (
"context"
"database/sql"
"hm-server/app/main/api/internal/svc"
"hm-server/app/main/api/internal/types"
"hm-server/common/xerr"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
)
type AdminUpdateProductLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAdminUpdateProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUpdateProductLogic {
return &AdminUpdateProductLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *AdminUpdateProductLogic) AdminUpdateProduct(req *types.AdminUpdateProductReq) (resp *types.AdminUpdateProductResp, err error) {
// 1. 查询记录是否存在
record, err := l.svcCtx.ProductModel.FindOne(l.ctx, req.Id)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
"查找产品失败, err: %v, id: %d", err, req.Id)
}
// 2. 更新字段
if req.ProductName != nil {
record.ProductName = *req.ProductName
}
if req.ProductEn != nil {
record.ProductEn = *req.ProductEn
}
if req.Description != nil {
record.Description = *req.Description
}
if req.Notes != nil {
record.Notes = sql.NullString{String: *req.Notes, Valid: *req.Notes != ""}
}
if req.CostPrice != nil {
record.CostPrice = *req.CostPrice
}
if req.SellPrice != nil {
record.SellPrice = *req.SellPrice
}
// 3. 执行更新操作
_, err = l.svcCtx.ProductModel.Update(l.ctx, nil, record)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
"更新产品失败, err: %v, req: %+v", err, req)
}
// 4. 返回结果
return &types.AdminUpdateProductResp{Success: true}, nil
}