Browse Source

work: taskDetail 任务明细

Yi 1 week ago
parent
commit
e8b943f751

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20250603093658-9b2144518ce7
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20250609060156-a9a9e557016e
 	gitee.com/xuyiping_admin/pkg v0.0.0-20250514071642-f92d2ac9a85d
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/eclipse/paho.mqtt.golang v1.4.3

+ 6 - 0
go.sum

@@ -144,6 +144,12 @@ gitee.com/xuyiping_admin/go_proto v0.0.0-20250603093243-82ebd7095700 h1:4s7hJ6Vr
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250603093243-82ebd7095700/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250603093658-9b2144518ce7 h1:hAbUSi6s55gRk7nJfWq+d66rN5phpOggRqKxyaj1T/M=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250603093658-9b2144518ce7/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250609030041-2973960e699d h1:OSpVELaFRbVykh3MJ4kfHaB6zd8b6Ibj22jDIl92nrU=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250609030041-2973960e699d/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250609031915-1c289a676298 h1:oqXkLG8jwAxVl7uTF1o/C2MQVzhd7NrAL/ZNb3FyGQU=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250609031915-1c289a676298/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250609060156-a9a9e557016e h1:xDIjht8Ol7BICYL3+Y9WZmM8JSM5bO+X8L09RskPkW0=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250609060156-a9a9e557016e/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/pkg v0.0.0-20241108060137-caea58c59f5b h1:w05MxH7yqveRlaRbxHhbif5YjPrJFodRPfOjYhXn7Zk=
 gitee.com/xuyiping_admin/pkg v0.0.0-20241108060137-caea58c59f5b/go.mod h1:8tF25X6pE9WkFCczlNAC0K2mrjwKvhhp02I7o0HtDxY=
 gitee.com/xuyiping_admin/pkg v0.0.0-20250514071642-f92d2ac9a85d h1:vBXmMRggF7mZVPGRDgavZ87igJgkezwX0a3v1/XtIMQ=

+ 21 - 0
http/handler/work/item.go

@@ -109,3 +109,24 @@ func CalvingList(c *gin.Context) {
 	}
 	ginutil.JSONResp(c, res)
 }
+
+func TaskDetailList(c *gin.Context) {
+	var req pasturePb.CalendarToDoRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.TaskDetail(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, res)
+}

+ 5 - 2
http/route/work_api.go

@@ -14,10 +14,10 @@ func WorkOrderAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		}
 		// work API 组  工作清单
 		workRoute := authRouteGroup(s, "/api/v1/work/")
-		workRoute.POST("/order/list", work.OrderList)
+		/*workRoute.POST("/order/list", work.OrderList)
 		workRoute.POST("/order/createOrUpdate", work.OrderCreateOrUpdate)
 		workRoute.PUT("/order/is_show/:id", work.OrderIsShow)
-		workRoute.GET("/user/order/list/:status", work.UserOrderList)
+		workRoute.GET("/user/order/list/:status", work.UserOrderList)*/
 
 		// 日历
 		workRoute.POST("/calendar/list", work.CalendarList)
@@ -32,5 +32,8 @@ func WorkOrderAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		workRoute.POST("/mating/items", work.MatingCowList)
 		workRoute.POST("/calving/items", work.CalvingList)
 		workRoute.POST("/disease/items", event.CowDiseaseList)
+
+		// 任务明细
+		workRoute.POST("/task/detail", work.TaskDetailList)
 	}
 }

+ 35 - 28
module/backend/calendar.go

@@ -18,7 +18,7 @@ func (s *StoreEntry) CalendarToDoCount(ctx context.Context) (*pasturePb.TodoCoun
 		return nil, xerr.WithStack(err)
 	}
 
-	todoList, err := s.CalendarToDoHistoryList(ctx, userModel.AppPasture.Id, "")
+	todoList, err := s.CalendarToDoHistoryList(ctx, userModel.AppPasture.Id, "", 0, true)
 	if err != nil {
 		return nil, xerr.WithStack(err)
 	}
@@ -30,38 +30,45 @@ func (s *StoreEntry) CalendarToDoCount(ctx context.Context) (*pasturePb.TodoCoun
 	}, nil
 }
 
-func (s *StoreEntry) CalendarToDoHistoryList(ctx context.Context, pastureId int64, earNumber string) ([]*pasturePb.CalendarToDoList, error) {
-	whereSql := ""
+func (s *StoreEntry) CalendarToDoHistoryList(ctx context.Context, pastureId int64, earNumber string, penId int32, isStatus bool) ([]*pasturePb.CalendarToDoList, error) {
+	whereSql := fmt.Sprintf(" pasture_id = %d ", pastureId)
 	if earNumber != "" {
 		whereSql += fmt.Sprintf(` AND ear_number = '%s' `, earNumber)
 	}
-	whereSql += fmt.Sprintf(" AND pasture_id = %d ", pastureId)
-	whereSql1 := whereSql + fmt.Sprintf(` AND end_day >= %d `, util.TimeParseLocalEndUnix(time.Now().Local().Format(model.LayoutDate2)))
+	if penId > 0 {
+		whereSql += fmt.Sprintf(` AND b.pen_id = %d `, penId)
+	}
+
+	if isStatus {
+		whereSql += ` AND a.status = 2 `
+	}
 
+	whereSql1 := fmt.Sprintf(`%s AND end_day >= %d `, whereSql, util.TimeParseLocalEndUnix(time.Now().Local().Format(model.LayoutDate2)))
 	calendarToDoList := make([]*pasturePb.CalendarToDoList, 0)
 	sql := `SELECT a.cow_id,b.pen_name,a.calendar_type_name,a.calendar_type_kind as calendar_type,DATE_FORMAT(FROM_UNIXTIME(a.plan_day), '%Y-%m-%d') AS plan_day,
-		a.remaining_days,b.lact,b.ear_number FROM (
-		SELECT cow_id,plan_day,'免疫' as calendar_type_name,1 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
-			FROM event_immunization_plan WHERE status = 2` + whereSql1 + `
-		UNION ALL
-		SELECT cow_id,plan_day,'同期' as calendar_type_name,2 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
-			FROM event_cow_same_time WHERE status = 2` + whereSql1 + `
-		UNION ALL
-		SELECT cow_id,plan_day,'孕检' as calendar_type_name,4 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
-			FROM event_pregnant_check WHERE status = 2` + whereSql1 + `
-		UNION ALL
-		SELECT cow_id,plan_day,'断奶' as calendar_type_name,6 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
-			FROM event_weaning WHERE status = 2` + whereSql1 + `
-		UNION ALL
-		SELECT cow_id,plan_day,'配种' as calendar_type_name,8 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
-			FROM event_mating WHERE status = 2` + whereSql1 + `
-		UNION ALL
-		SELECT cow_id,plan_day,'产犊' as calendar_type_name,9 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
-			FROM event_calving WHERE status = 2` + whereSql1 + `
-		UNION ALL
-		SELECT cow_id,disease_at as plan_day,'疾病' as calendar_type_name,7 as calendar_type_kind,0 AS remaining_days 
-			FROM event_cow_disease WHERE health_status IN (2,3) ` + whereSql + `
-	) as a JOIN cow b ON a.cow_id = b.id `
+		DATE_FORMAT(FROM_UNIXTIME(a.end_day), '%Y-%m-%d') AS end_day,DATE_FORMAT(FROM_UNIXTIME(a.reality_day), '%Y-%m-%d') AS reality_day,a.remaining_days,b.lact,b.ear_number,a.status as is_finish,a.remarks
+		FROM (
+			SELECT cow_id,plan_day,end_day,reality_day,status,remarks,'免疫' as calendar_type_name,1 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
+			FROM event_immunization_plan WHERE ` + whereSql1 + `
+			UNION ALL
+			SELECT cow_id,plan_day,end_day,reality_day,status,remarks,'同期' as calendar_type_name,2 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
+			FROM event_cow_same_time WHERE ` + whereSql1 + `
+			UNION ALL
+			SELECT cow_id,plan_day,end_day,reality_day,status,remarks,'孕检' as calendar_type_name,4 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
+			FROM event_pregnant_check WHERE ` + whereSql1 + `
+			UNION ALL
+			SELECT cow_id,plan_day,end_day,reality_day,status,remarks,'断奶' as calendar_type_name,6 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
+			FROM event_weaning WHERE ` + whereSql1 + `
+			UNION ALL
+			SELECT cow_id,plan_day,end_day,reality_day,status,remarks,'配种' as calendar_type_name,8 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
+			FROM event_mating WHERE ` + whereSql1 + `
+			UNION ALL
+			SELECT cow_id,plan_day,end_day,reality_day,status,remarks,'产犊' as calendar_type_name,9 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
+			FROM event_calving WHERE ` + whereSql1 + `
+			UNION ALL
+			SELECT cow_id,disease_at as plan_day,curable_at as end_day,curable_at as reality_day,health_status as status,remarks,'疾病' as calendar_type_name,7 as calendar_type_kind,0 AS remaining_days 
+			FROM event_cow_disease WHERE health_status IN (2,3) AND ` + whereSql + `
+		) as a JOIN cow b ON a.cow_id = b.id `
 
 	completeSql := fmt.Sprintf("%s ORDER BY a.plan_day DESC", sql)
 	if err := s.DB.Raw(completeSql).Find(&calendarToDoList).Error; err != nil {
@@ -79,7 +86,7 @@ func (s *StoreEntry) CalendarToDoList(ctx context.Context, req *pasturePb.Calend
 	}
 
 	pastureId := userModel.AppPasture.Id
-	calendarToDoList, err := s.CalendarToDoHistoryList(ctx, pastureId, req.EarNumber)
+	calendarToDoList, err := s.CalendarToDoHistoryList(ctx, pastureId, req.EarNumber, 0, true)
 	if err != nil {
 		return nil, xerr.WithStack(err)
 	}

+ 60 - 0
module/backend/calendar_more.go

@@ -294,3 +294,63 @@ func ProgressList(dMap map[pasturePb.CalendarType_Kind]int32, toDayCompletedCoun
 
 	return res
 }
+
+func (s *StoreEntry) TaskDetail(ctx context.Context, req *pasturePb.CalendarToDoRequest, pagination *pasturePb.PaginationModel) (*pasturePb.TaskDetailResponse, error) {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	pastureId := userModel.AppPasture.Id
+	calendarToDoList, err := s.CalendarToDoHistoryList(ctx, pastureId, req.EarNumber, req.PenId, false)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	calendarToDoList, total := Paginate(calendarToDoList, req, pagination)
+	taskItemsList := make([]*pasturePb.TaskItems, 0)
+
+	for _, v := range calendarToDoList {
+		if v.CalendarType == pasturePb.CalendarType_Disease {
+			continue
+		}
+		taskKind := pasturePb.TaskStatus_Invalid
+		switch v.IsFinish {
+		case pasturePb.IsShow_Ok:
+			taskKind = pasturePb.TaskStatus_Complete
+		case pasturePb.IsShow_No:
+			taskKind = pasturePb.TaskStatus_UnComplete
+		}
+
+		overdueDay := int32(0)
+		if v.RealityDay != "" && v.EndDay != "" {
+			realityDay, _ := util.TimeParseLocal(model.LayoutDate2, v.RealityDay)
+			endDay, _ := util.TimeParseLocal(model.LayoutDate2, v.EndDay)
+			overdueDay = int32(util.DaysBetween(realityDay.Unix(), endDay.Unix()))
+		}
+
+		taskItemsList = append(taskItemsList, &pasturePb.TaskItems{
+			CowId:            v.CowId,
+			EarNumber:        v.EarNumber,
+			PenName:          v.PenName,
+			CalendarTypeName: v.CalendarTypeName,
+			TaskKind:         taskKind,
+			PlanDayFormat:    v.EndDay,
+			RealityDayFormat: v.RealityDay,
+			OverdueDay:       overdueDay,
+			Remarks:          v.Remarks,
+			OperationName:    v.OperatorName,
+		})
+	}
+
+	return &pasturePb.TaskDetailResponse{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &pasturePb.TaskData{
+			List:     taskItemsList,
+			Total:    total,
+			Page:     pagination.Page,
+			PageSize: pagination.PageSize,
+		},
+	}, nil
+}

+ 3 - 0
module/backend/interface.go

@@ -335,6 +335,9 @@ type WorkService interface {
 	MatingCowList(ctx context.Context, req *pasturePb.ItemsRequest, pagination *pasturePb.PaginationModel) (*pasturePb.MatingItemsResponse, error)
 	CalvingCowList(ctx context.Context, req *pasturePb.ItemsRequest, pagination *pasturePb.PaginationModel) (*pasturePb.CalvingItemsResponse, error)
 	CowDiseaseList(ctx context.Context, req *pasturePb.SearchEventCowTreatmentRequest, pagination *pasturePb.PaginationModel) (*pasturePb.EventCowDiseaseResponse, error)
+
+	// TaskDetail 任务明细详情
+	TaskDetail(ctx context.Context, req *pasturePb.CalendarToDoRequest, pagination *pasturePb.PaginationModel) (*pasturePb.TaskDetailResponse, error)
 }
 
 type WarningService interface {

+ 76 - 236
module/backend/system_service.go

@@ -286,24 +286,46 @@ func (s *StoreEntry) GetSystemUserMenu(ctx context.Context) (*pasturePb.SystemUs
 	systemRoleList := make([]*model.SystemRole, 0)
 	if err = s.DB.Where("id IN ?", systemUser.GetRoleIds()).
 		Where("pasture_id = ?", userModel.AppPasture.Id).
+		Where("is_delete = ?", pasturePb.IsShow_Ok).
+		Where("is_show = ?", pasturePb.IsShow_Ok).
 		Find(&systemRoleList).Error; err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
 			return nil, xerr.Custom("该用户角色不存在")
 		}
 		return nil, xerr.WithStack(err)
 	}
-	// 获取用户菜单
-	systemMenuList := make([]*model.SystemMenu, 0)
-	if err = s.DB.Table(fmt.Sprintf("%s as a", new(model.SystemRoleMenu).TableName())).
-		Select("b.*").
-		Joins("LEFT JOIN system_menu AS b ON a.menu_id = b.id").
-		Where("a.role_id IN ? and b.is_delete = ?", systemUser.GetRoleIds(), pasturePb.IsShow_Ok).
-		Order("b.parent_id ASC,b.id ASC").
-		Group("b.id").
-		Find(&systemMenuList).Error; err != nil {
+
+	if len(systemRoleList) <= 0 {
+		return nil, xerr.Custom("该用户角色不存在")
+	}
+
+	roleIds := make([]int64, 0)
+	for _, role := range systemRoleList {
+		roleIds = append(roleIds, role.Id)
+	}
+
+	systemRoleMenuList := make([]*model.SystemRoleMenu, 0)
+	if err = s.DB.Model(new(model.SystemRoleMenu)).
+		Where("role_id IN ?", roleIds).
+		Find(&systemRoleMenuList).Error; err != nil {
 		return nil, xerr.WithStack(err)
 	}
 
+	if len(systemRoleMenuList) <= 0 {
+		return nil, xerr.Custom("该用户角色没有菜单权限")
+	}
+
+	// 菜单Id
+	menuIds := make([]int64, 0)
+	for _, roleMenu := range systemRoleMenuList {
+		menuIds = append(menuIds, roleMenu.MenuId)
+	}
+
+	// 获取用户菜单
+	systemMenuList, err := s.GetMenusWithParents(ctx, menuIds)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
 	// 获取菜单权限
 	return &pasturePb.SystemUserMenuTreeResponse{
 		Code: http.StatusOK,
@@ -406,245 +428,63 @@ func (s *StoreEntry) SystemUserRoleSave(ctx context.Context, req *pasturePb.Syst
 	return nil
 }
 
-// SystemRoleCreateOrUpdate 添加角色
-func (s *StoreEntry) SystemRoleCreateOrUpdate(ctx context.Context, req *pasturePb.SearchRoleRequest) error {
-	userModel, err := s.GetUserModel(ctx)
-	if err != nil {
-		return xerr.WithStack(err)
-	}
-
-	if req.Id > 0 {
-		systemRole := &model.SystemRole{}
-		if err = s.DB.Model(systemRole).
-			Where("id = ?", req.Id).
-			Where("pasture_id = ?", userModel.AppPasture.Id).
-			First(systemRole).Error; err != nil {
-			return xerr.WithStack(err)
-		}
-
-		if systemRole.IsDelete == pasturePb.IsShow_No {
-			return xerr.Custom("角色已删除")
-		}
-
-		systemRole.RoleUpdate(req)
-		if err = s.DB.Model(systemRole).
-			Select("name", "remarks", "is_show").
-			Where("id = ?", req.Id).
-			Where("pasture_id = ?", userModel.AppPasture.Id).
-			Updates(systemRole).Error; err != nil {
-			return xerr.WithStack(err)
-		}
-
-	} else {
-		newSystemRole := model.NewSystemRole(userModel.AppPasture.Id, req)
-		if err = s.DB.Model(new(model.SystemRole)).Create(newSystemRole).Error; err != nil {
-			return xerr.WithStack(err)
-		}
+func (s *StoreEntry) GetMenusWithParents(ctx context.Context, menuIds []int64) ([]*model.SystemMenu, error) {
+	if len(menuIds) <= 0 {
+		return nil, xerr.Customf("菜单id不能为空")
 	}
+	// 用于存储所有需要查询的菜单ID(包括递归查询的父级ID)
+	allMenuIDs := make(map[int64]struct{})
+	// 用于存储已经处理过的菜单ID,避免重复处理
+	processedIDs := make(map[int64]struct{})
 
-	return nil
-}
-
-// DeleteSystemRole 删除系统角色
-func (s *StoreEntry) DeleteSystemRole(ctx context.Context, roleId int64) error {
-	userModel, err := s.GetUserModel(ctx)
-	if err != nil {
-		return xerr.WithStack(err)
-	}
-	systemRole := &model.SystemRole{}
-	if err = s.DB.Model(new(model.SystemRole)).
-		Where("id = ? ", roleId).
-		Where("pasture_id = ?", userModel.AppPasture.Id).
-		Where("is_delete = ?", pasturePb.IsShow_Ok).
-		First(systemRole).Error; err != nil {
-		return xerr.WithStack(err)
-	}
+	// 初始化待处理ID队列
+	queue := make([]int64, len(menuIds))
+	copy(queue, menuIds)
 
-	if err = s.DB.Model(systemRole).
-		Update("is_delete", pasturePb.IsShow_No).Error; err != nil {
-		return xerr.WithStack(err)
-	}
-	return nil
-}
+	for len(queue) > 0 {
+		currentID := queue[0]
+		queue = queue[1:]
 
-// IsShowSystemRole 角色是否启用
-func (s *StoreEntry) IsShowSystemRole(ctx context.Context, roleId int64) error {
-	userModel, err := s.GetUserModel(ctx)
-	if err != nil {
-		return xerr.WithStack(err)
-	}
-	systemRole := &model.SystemRole{}
-	if err = s.DB.Model(new(model.SystemRole)).
-		Where("id = ?", roleId).
-		Where("pasture_id = ?", userModel.AppPasture.Id).
-		Where("is_delete = ?", pasturePb.IsShow_Ok).
-		First(systemRole).Error; err != nil {
-		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return xerr.Custom("该角色不存在")
+		// 如果已经处理过,跳过
+		if _, exists := processedIDs[currentID]; exists {
+			continue
 		}
-		return xerr.WithStack(err)
-	}
-
-	isShow := pasturePb.IsShow_No
-	if systemRole.IsShow == pasturePb.IsShow_No {
-		isShow = pasturePb.IsShow_Ok
-	}
-
-	if err = s.DB.Model(systemRole).Update("is_show", isShow).Error; err != nil {
-		return xerr.WithStack(err)
-	}
-	return nil
-}
-
-// SearchSystemRoleList 查询系统角色
-func (s *StoreEntry) SearchSystemRoleList(ctx context.Context, req *pasturePb.SearchRoleRequest, pagination *pasturePb.PaginationModel) (*pasturePb.SearchRoleResponse, error) {
-	userModel, err := s.GetUserModel(ctx)
-	if err != nil {
-		return nil, xerr.WithStack(err)
-	}
-
-	systemRoleList := make([]*model.SystemRole, 0)
-	var count int64 = 0
-
-	pref := s.DB.Model(new(model.SystemRole)).
-		Where("pasture_id = ?", userModel.AppPasture.Id).
-		Where("is_delete = ?", operationPb.IsShow_OK)
-	if req.Name != "" {
-		pref.Where("name like ?", fmt.Sprintf("%s%s%s", "%", req.Name, "%"))
-	}
 
-	if req.IsShow > 0 {
-		pref.Where("is_show = ?", req.IsShow)
-	}
-
-	if err = pref.Order("is_show asc,id desc").
-		Count(&count).
-		Limit(int(pagination.PageSize)).
-		Offset(int(pagination.PageOffset)).
-		Find(&systemRoleList).Error; err != nil {
-		return nil, xerr.WithStack(err)
-	}
-
-	return &pasturePb.SearchRoleResponse{
-		Code: http.StatusOK,
-		Msg:  "ok",
-		Data: &pasturePb.SearchRoleData{
-			Page:     pagination.Page,
-			Total:    int32(count),
-			PageSize: pagination.PageSize,
-			List:     model.SystemRoleSlice(systemRoleList).ToPB(),
-		},
-	}, nil
-}
-
-// SearchSystemRoleListByIds 根据id查询角色列表
-func (s *StoreEntry) SearchSystemRoleListByIds(ctx context.Context, pastureId int64, ids []int64) ([]*model.SystemRole, error) {
-	systemRoleList := make([]*model.SystemRole, 0)
-	if err := s.DB.Model(new(model.SystemRole)).
-		Where("pasture_id = ?", pastureId).
-		Where("is_show = ?", operationPb.IsShow_OK).
-		Find(&systemRoleList, ids).Error; err != nil {
-		return nil, xerr.WithStack(err)
-	}
-
-	return systemRoleList, nil
-}
-
-// GetRoleMenuList 查询系统角色对应的菜单数据
-func (s *StoreEntry) GetRoleMenuList(ctx context.Context, roleId int64) (*pasturePb.SystemRoleMenuResponse, error) {
-	systemRole := &model.SystemRole{
-		Id: roleId,
-	}
-	if err := s.DB.First(systemRole).Error; err != nil {
-		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return nil, xerr.Custom("该数据不存在")
-		}
-		return nil, xerr.WithStack(err)
-	}
-
-	if systemRole.IsDelete == pasturePb.IsShow_No {
-		return nil, xerr.Custom("该数据已被删除")
-	}
-
-	menuList := make([]*model.SystemRoleMenu, 0)
-	if err := s.DB.Where("role_id = ?", systemRole.Id).Find(&menuList).Error; err != nil {
-		zaplog.Error("GetSystemRoleMenuList", zap.Any("Err", err))
-	}
-	return &pasturePb.SystemRoleMenuResponse{
-		Code: http.StatusOK,
-		Msg:  "ok",
-		Data: model.SystemRoleMenuSlice(menuList).ToPB(),
-	}, nil
-
-}
-
-// RoleMenuSave 保存系统角色对应的菜单数据
-func (s *StoreEntry) RoleMenuSave(ctx context.Context, res *pasturePb.SystemRoleMenuRequest) error {
-	userModel, err := s.GetUserModel(ctx)
-	if err != nil {
-		return xerr.WithStack(err)
-	}
-
-	if len(res.MenuIds) <= 0 {
-		return xerr.Custom("请选择菜单")
-	}
-
-	systemRole := &model.SystemRole{}
-	if err = s.DB.Model(new(model.SystemRole)).
-		Where("id = ?", res.RoleId).
-		Where("pasture_id = ?", userModel.AppPasture.Id).
-		First(systemRole).Error; err != nil {
-		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return xerr.Custom("该数据不存在")
-		}
-		return xerr.WithStack(err)
-	}
-
-	if systemRole.IsDelete == pasturePb.IsShow_No {
-		return xerr.Custom("该数据已删除")
-	}
-
-	if systemRole.IsShow == pasturePb.IsShow_No {
-		return xerr.Custom("该数据已禁用")
-	}
-
-	if err = s.DB.Transaction(func(tx *gorm.DB) error {
-		if err = tx.Model(new(model.SystemRoleMenu)).
-			Where("role_id = ?", systemRole.Id).
-			Delete(&model.SystemRoleMenu{}).
-			Error; err != nil {
-			return xerr.WithStack(err)
-		}
+		// 标记为已处理
+		processedIDs[currentID] = struct{}{}
+		allMenuIDs[currentID] = struct{}{}
+
+		// 如果不是顶级菜单,查询其父级ID并加入队列
+		if currentID != 0 { // 0是顶级菜单的parent_id
+			var parentID int64
+			err := s.DB.Model(new(model.SystemMenu)).
+				Where("id = ? AND is_delete = 1", currentID).
+				Pluck("parent_id", &parentID).Error
+			if err != nil {
+				return nil, fmt.Errorf("failed to get parent ID for menu %d: %v", currentID, err)
+			}
 
-		newSystemRoleMenuList := model.NewSystemRoleMenu(systemRole.Id, res.MenuIds)
-		if err = tx.Model(new(model.SystemRoleMenu)).
-			Create(newSystemRoleMenuList).Error; err != nil {
-			return xerr.WithStack(err)
+			if parentID != 0 {
+				queue = append(queue, parentID)
+			}
 		}
-		return nil
-	}); err != nil {
-		return xerr.WithStack(err)
 	}
-	return nil
-}
 
-func (s *StoreEntry) SystemRoleList(ctx context.Context) (*pasturePb.GetRoleListResponse, error) {
-	userModel, err := s.GetUserModel(ctx)
-	if err != nil {
-		return nil, xerr.WithStack(err)
+	// 将map中的ID转换为slice
+	var ids []int64
+	for id := range allMenuIDs {
+		ids = append(ids, id)
 	}
 
-	systemRoleList := make([]*model.SystemRole, 0)
-	if err = s.DB.Model(new(model.SystemRole)).
-		Where("is_delete = ?", pasturePb.IsShow_Ok).
-		Where("pasture_id = ?", userModel.AppPasture.Id).
-		Find(&systemRoleList).Error; err != nil {
-		return nil, xerr.WithStack(err)
+	// 查询所有需要的菜单
+	systemMenuList := make([]*model.SystemMenu, 0)
+	if err := s.DB.Model(new(model.SystemMenu)).
+		Where("id IN (?) AND is_delete = 1", ids).
+		Order("parent_id ASC,id ASC").
+		Group("id").
+		Find(&systemMenuList).Error; err != nil {
+		return nil, fmt.Errorf("failed to query menus: %v", err)
 	}
 
-	return &pasturePb.GetRoleListResponse{
-		Code: http.StatusOK,
-		Msg:  "ok",
-		Data: model.SystemRoleSlice(systemRoleList).ToPB(),
-	}, nil
+	return systemMenuList, nil
 }

+ 246 - 0
module/backend/system_service_more.go

@@ -2,10 +2,13 @@ package backend
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"kpt-pasture/model"
 	"net/http"
 
+	"gorm.io/gorm"
+
 	"go.uber.org/zap"
 
 	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
@@ -336,3 +339,246 @@ func (s *StoreEntry) findAllParentDepths(ctx context.Context, depths []*model.Sy
 
 	return allDepths, nil
 }
+
+// SystemRoleCreateOrUpdate 添加角色
+func (s *StoreEntry) SystemRoleCreateOrUpdate(ctx context.Context, req *pasturePb.SearchRoleRequest) error {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+
+	if req.Id > 0 {
+		systemRole := &model.SystemRole{}
+		if err = s.DB.Model(systemRole).
+			Where("id = ?", req.Id).
+			Where("pasture_id = ?", userModel.AppPasture.Id).
+			First(systemRole).Error; err != nil {
+			return xerr.WithStack(err)
+		}
+
+		if systemRole.IsDelete == pasturePb.IsShow_No {
+			return xerr.Custom("角色已删除")
+		}
+
+		systemRole.RoleUpdate(req)
+		if err = s.DB.Model(systemRole).
+			Select("name", "remarks", "is_show").
+			Where("id = ?", req.Id).
+			Where("pasture_id = ?", userModel.AppPasture.Id).
+			Updates(systemRole).Error; err != nil {
+			return xerr.WithStack(err)
+		}
+
+	} else {
+		newSystemRole := model.NewSystemRole(userModel.AppPasture.Id, req)
+		if err = s.DB.Model(new(model.SystemRole)).Create(newSystemRole).Error; err != nil {
+			return xerr.WithStack(err)
+		}
+	}
+
+	return nil
+}
+
+// DeleteSystemRole 删除系统角色
+func (s *StoreEntry) DeleteSystemRole(ctx context.Context, roleId int64) error {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+	systemRole := &model.SystemRole{}
+	if err = s.DB.Model(new(model.SystemRole)).
+		Where("id = ? ", roleId).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
+		Where("is_delete = ?", pasturePb.IsShow_Ok).
+		First(systemRole).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+
+	if err = s.DB.Model(systemRole).
+		Update("is_delete", pasturePb.IsShow_No).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+	return nil
+}
+
+// IsShowSystemRole 角色是否启用
+func (s *StoreEntry) IsShowSystemRole(ctx context.Context, roleId int64) error {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+	systemRole := &model.SystemRole{}
+	if err = s.DB.Model(new(model.SystemRole)).
+		Where("id = ?", roleId).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
+		Where("is_delete = ?", pasturePb.IsShow_Ok).
+		First(systemRole).Error; err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return xerr.Custom("该角色不存在")
+		}
+		return xerr.WithStack(err)
+	}
+
+	isShow := pasturePb.IsShow_No
+	if systemRole.IsShow == pasturePb.IsShow_No {
+		isShow = pasturePb.IsShow_Ok
+	}
+
+	if err = s.DB.Model(systemRole).Update("is_show", isShow).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+	return nil
+}
+
+// SearchSystemRoleList 查询系统角色
+func (s *StoreEntry) SearchSystemRoleList(ctx context.Context, req *pasturePb.SearchRoleRequest, pagination *pasturePb.PaginationModel) (*pasturePb.SearchRoleResponse, error) {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	systemRoleList := make([]*model.SystemRole, 0)
+	var count int64 = 0
+
+	pref := s.DB.Model(new(model.SystemRole)).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
+		Where("is_delete = ?", operationPb.IsShow_OK)
+	if req.Name != "" {
+		pref.Where("name like ?", fmt.Sprintf("%s%s%s", "%", req.Name, "%"))
+	}
+
+	if req.IsShow > 0 {
+		pref.Where("is_show = ?", req.IsShow)
+	}
+
+	if err = pref.Order("is_show asc,id desc").
+		Count(&count).
+		Limit(int(pagination.PageSize)).
+		Offset(int(pagination.PageOffset)).
+		Find(&systemRoleList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return &pasturePb.SearchRoleResponse{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &pasturePb.SearchRoleData{
+			Page:     pagination.Page,
+			Total:    int32(count),
+			PageSize: pagination.PageSize,
+			List:     model.SystemRoleSlice(systemRoleList).ToPB(),
+		},
+	}, nil
+}
+
+// SearchSystemRoleListByIds 根据id查询角色列表
+func (s *StoreEntry) SearchSystemRoleListByIds(ctx context.Context, pastureId int64, ids []int64) ([]*model.SystemRole, error) {
+	systemRoleList := make([]*model.SystemRole, 0)
+	if err := s.DB.Model(new(model.SystemRole)).
+		Where("pasture_id = ?", pastureId).
+		Where("is_show = ?", operationPb.IsShow_OK).
+		Find(&systemRoleList, ids).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return systemRoleList, nil
+}
+
+// GetRoleMenuList 查询系统角色对应的菜单数据
+func (s *StoreEntry) GetRoleMenuList(ctx context.Context, roleId int64) (*pasturePb.SystemRoleMenuResponse, error) {
+	systemRole := &model.SystemRole{
+		Id: roleId,
+	}
+	if err := s.DB.First(systemRole).Error; err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return nil, xerr.Custom("该数据不存在")
+		}
+		return nil, xerr.WithStack(err)
+	}
+
+	if systemRole.IsDelete == pasturePb.IsShow_No {
+		return nil, xerr.Custom("该数据已被删除")
+	}
+
+	menuList := make([]*model.SystemRoleMenu, 0)
+	if err := s.DB.Where("role_id = ?", systemRole.Id).Find(&menuList).Error; err != nil {
+		zaplog.Error("GetSystemRoleMenuList", zap.Any("Err", err))
+	}
+	return &pasturePb.SystemRoleMenuResponse{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: model.SystemRoleMenuSlice(menuList).ToPB(),
+	}, nil
+
+}
+
+// RoleMenuSave 保存系统角色对应的菜单数据
+func (s *StoreEntry) RoleMenuSave(ctx context.Context, res *pasturePb.SystemRoleMenuRequest) error {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+
+	if len(res.MenuIds) <= 0 {
+		return xerr.Custom("请选择菜单")
+	}
+
+	systemRole := &model.SystemRole{}
+	if err = s.DB.Model(new(model.SystemRole)).
+		Where("id = ?", res.RoleId).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
+		First(systemRole).Error; err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return xerr.Custom("该数据不存在")
+		}
+		return xerr.WithStack(err)
+	}
+
+	if systemRole.IsDelete == pasturePb.IsShow_No {
+		return xerr.Custom("该数据已删除")
+	}
+
+	if systemRole.IsShow == pasturePb.IsShow_No {
+		return xerr.Custom("该数据已禁用")
+	}
+
+	if err = s.DB.Transaction(func(tx *gorm.DB) error {
+		if err = tx.Model(new(model.SystemRoleMenu)).
+			Where("role_id = ?", systemRole.Id).
+			Delete(&model.SystemRoleMenu{}).
+			Error; err != nil {
+			return xerr.WithStack(err)
+		}
+
+		newSystemRoleMenuList := model.NewSystemRoleMenu(systemRole.Id, res.MenuIds)
+		if err = tx.Model(new(model.SystemRoleMenu)).
+			Create(newSystemRoleMenuList).Error; err != nil {
+			return xerr.WithStack(err)
+		}
+		return nil
+	}); err != nil {
+		return xerr.WithStack(err)
+	}
+	return nil
+}
+
+func (s *StoreEntry) SystemRoleList(ctx context.Context) (*pasturePb.GetRoleListResponse, error) {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	systemRoleList := make([]*model.SystemRole, 0)
+	if err = s.DB.Model(new(model.SystemRole)).
+		Where("is_delete = ?", pasturePb.IsShow_Ok).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
+		Find(&systemRoleList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return &pasturePb.GetRoleListResponse{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: model.SystemRoleSlice(systemRoleList).ToPB(),
+	}, nil
+}