package system import ( "context" "encoding/json" "errors" "fmt" "strconv" "strings" "time" "management/internal/db/model/dto" db "management/internal/db/sqlc" "management/internal/erpserver/model/form" "management/internal/erpserver/model/view" "management/internal/pkg/convertor" "management/internal/pkg/know" "management/internal/pkg/redis" "management/internal/pkg/tpl/html" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgtype" ) type CategoryBiz interface { Create(ctx context.Context, req *form.Category) error Update(ctx context.Context, req *form.Category) error All(ctx context.Context) ([]*db.Category, error) List(ctx context.Context, q dto.SearchDto) ([]*db.Category, int64, error) Get(ctx context.Context, id int32) (*db.Category, error) Refresh(ctx context.Context) ([]*db.Category, error) RebuildParentPath(ctx context.Context) error Tree(ctx context.Context, id int32) ([]*view.LayuiTree, error) XmSelect(ctx context.Context, letter string) ([]*view.XmSelect, error) XmSelectTree(ctx context.Context, id int32) ([]*view.XmSelectTree, error) ListHtmlByLetter(ctx context.Context, letter string) ([]*html.SelectDict, error) } type categoryBiz struct { store db.Store redis redis.IRedis } var _ CategoryBiz = (*categoryBiz)(nil) func NewCategory(store db.Store, redis redis.IRedis) *categoryBiz { return &categoryBiz{ store: store, redis: redis, } } func (b *categoryBiz) All(ctx context.Context) ([]*db.Category, error) { key := know.GetManageKey(ctx, know.AllCategories) bs, err := redis.GetBytes(ctx, key) if err == nil { var res []*db.Category if err := json.Unmarshal(bs, &res); err == nil { return res, nil } } return b.Refresh(ctx) } func (b *categoryBiz) List(ctx context.Context, q dto.SearchDto) ([]*db.Category, int64, error) { countArg := &db.CountCategoriesConditionParams{ IsStatus: q.SearchStatus != 9999, Status: int16(q.SearchStatus), IsID: q.SearchID != 0, ID: int32(q.SearchID), IsParentID: q.SearchParentID != 0, ParentID: int32(q.SearchParentID), Name: q.SearchName, } dataArg := &db.ListCategoriesConditionParams{ IsStatus: q.SearchStatus != 9999, Status: int16(q.SearchStatus), IsID: q.SearchID != 0, ID: int32(q.SearchID), IsParentID: q.SearchParentID != 0, ParentID: int32(q.SearchParentID), Name: q.SearchName, Skip: (int32(q.Page) - 1) * int32(q.Rows), Size: int32(q.Rows), } count, err := b.store.CountCategoriesCondition(ctx, countArg) if err != nil { return nil, 0, err } departs, err := b.store.ListCategoriesCondition(ctx, dataArg) if err != nil { return nil, 0, err } return departs, count, nil } func (b *categoryBiz) Get(ctx context.Context, id int32) (*db.Category, error) { return b.store.GetCategory(ctx, id) } func (b *categoryBiz) Create(ctx context.Context, req *form.Category) error { if len(req.Icon) > 0 && !strings.HasPrefix(req.Icon, "/") { req.Icon = "/" + req.Icon } if len(req.Letter) == 0 { req.Letter = uuid.New().String() } parent := &db.Category{ ID: 0, ParentID: 0, ParentPath: ",0,", } if *req.ParentID > 0 { var err error parent, err = b.store.GetCategory(ctx, *req.ParentID) if err != nil { return errors.New("父级节点错误") } } var order int32 = 6666 if *req.Sort > 0 { order = *req.Sort } arg := &db.CreateCategoryParams{ Name: req.Name, Icon: req.Icon, Description: req.Description, Letter: req.Letter, ParentID: parent.ID, ParentPath: convertor.HandleParentPath(fmt.Sprintf("%s,%d,", parent.ParentPath, parent.ID)), Status: *req.Status, Sort: order, } _, err := b.store.CreateCategory(ctx, arg) if err != nil { if db.IsUniqueViolation(err) { return errors.New("类别已存在") } return err } return nil } func (b *categoryBiz) Update(ctx context.Context, req *form.Category) error { if len(req.Icon) > 0 && !strings.HasPrefix(req.Icon, "/") { req.Icon = "/" + req.Icon } if len(req.Letter) == 0 { req.Letter = uuid.New().String() } parent := &db.Category{ ID: 0, ParentID: 0, ParentPath: ",0,", } if *req.ParentID > 0 { var err error parent, err = b.store.GetCategory(ctx, *req.ParentID) if err != nil { return errors.New("父级节点错误") } } var order int32 = 6666 if *req.Sort > 0 { order = *req.Sort } arg := &db.UpdateCategoryParams{ ID: *req.ID, Name: pgtype.Text{ String: req.Name, Valid: true, }, Icon: pgtype.Text{ String: req.Icon, Valid: len(req.Icon) > 0, }, Description: pgtype.Text{ String: req.Description, Valid: len(req.Description) > 0, }, Letter: pgtype.Text{ String: req.Letter, Valid: len(req.Letter) > 0, }, ParentID: pgtype.Int4{ Int32: *req.ParentID, Valid: true, }, ParentPath: pgtype.Text{ String: convertor.HandleParentPath(fmt.Sprintf("%s,%d,", parent.ParentPath, parent.ID)), Valid: true, }, Sort: pgtype.Int4{ Int32: order, Valid: true, }, Status: pgtype.Int2{ Int16: *req.Status, Valid: true, }, } _, err := b.store.UpdateCategory(ctx, arg) return err } func (b *categoryBiz) Refresh(ctx context.Context) ([]*db.Category, error) { all, err := b.store.AllCategories(ctx) if err != nil { return nil, err } bs, err := json.Marshal(all) if err != nil { return nil, err } redis.Del(ctx, know.GetManageKey(ctx, know.AllCategorySimple)) key := know.GetManageKey(ctx, know.AllCategories) err = redis.Set(ctx, key, bs, time.Hour*6) return all, err } func (b *categoryBiz) RebuildParentPath(ctx context.Context) error { return b.store.CategoryRebuildPath(ctx) } func (b *categoryBiz) Tree(ctx context.Context, id int32) ([]*view.LayuiTree, error) { all, err := b.All(ctx) if err != nil { return nil, err } return b.toTree(id, all), nil } func (b *categoryBiz) XmSelect(ctx context.Context, letter string) ([]*view.XmSelect, error) { all, err := b.All(ctx) if err != nil || len(all) == 0 { return nil, err } var current *db.Category for _, v := range all { if v.Letter == letter { current = v break } } if current == nil { return nil, errors.New("未找到当前类别") } var res []*view.XmSelect for _, v := range all { if v.ParentID == current.ID { item := view.XmSelect{ Name: v.Name, Value: strconv.FormatInt(int64(v.ID), 10), } res = append(res, &item) } } return res, nil } func (b *categoryBiz) XmSelectTree(ctx context.Context, id int32) ([]*view.XmSelectTree, error) { all, err := b.All(ctx) if err != nil { return nil, err } return b.toXmSelectTree(id, all), nil } func (b *categoryBiz) ListHtmlByLetter(ctx context.Context, letter string) ([]*html.SelectDict, error) { all, err := b.All(ctx) if err != nil || len(all) == 0 { return nil, err } var current *db.Category for _, v := range all { if v.Letter == letter { current = v break } } if current == nil { return nil, errors.New("未找到当前类别") } var res []*html.SelectDict res = append(res, &html.SelectDict{ Name: "请选择", Value: "0", }) for _, v := range all { if v.ParentID == current.ID { item := html.SelectDict{ Name: v.Name, Value: strconv.Itoa(int(v.ID)), } res = append(res, &item) } } return res, nil } func (b *categoryBiz) toTree(parentId int32, data []*db.Category) []*view.LayuiTree { var res []*view.LayuiTree for _, v := range data { if v.ParentID == parentId { item := view.LayuiTree{} item.ID = strconv.FormatInt(int64(v.ID), 10) item.Title = v.Name item.Children = b.toTree(v.ID, data) if v.ParentID == 0 { item.Spread = true } res = append(res, &item) } } return res } func (b *categoryBiz) toXmSelectTree(parentId int32, data []*db.Category) []*view.XmSelectTree { var res []*view.XmSelectTree for _, v := range data { if v.ParentID == parentId { item := view.XmSelectTree{ Name: v.Name, Value: strconv.FormatInt(int64(v.ID), 10), Children: b.toXmSelectTree(v.ID, data), } res = append(res, &item) } } return res }