feat: API市场分类列表展示各分类接口数量

This commit is contained in:
x6g2
2026-11-10 00:43:04 +08:00
parent 2924ec30d8
commit bb52aa4537
6 changed files with 114 additions and 12 deletions
@@ -5,7 +5,7 @@
*/
/**
* API分类视图对象,对应后端 ApiCategoryVo
* API分类视图对象,对应后端 PortalApiCategoryVo
*/
export interface ApiCategoryVO {
/** 分类ID */
@@ -20,6 +20,9 @@ export interface ApiCategoryVO {
/** 状态(0正常 1停用) */
status?: string;
/** 该分类下的正常态接口数量 */
apiCount?: number;
/** 创建时间 */
createTime?: string;
}
+9 -2
View File
@@ -19,7 +19,7 @@
@click="handleCategoryChange(item.id)"
>
<span class="category-name">{{ formatText(item.name) }}</span>
<span v-if="item.sort !== undefined && item.sort !== null" class="category-sort">{{ item.sort }}</span>
<span class="category-count" :title="`共 ${item.apiCount ?? 0} 个接口`">{{ item.apiCount ?? 0 }}</span>
</div>
<el-empty v-if="!categoryLoading && categoryList.length === 0" description="暂无接口分类" :image-size="60" />
</div>
@@ -331,10 +331,17 @@ onMounted(() => {
white-space: nowrap;
}
.category-sort {
.category-count {
flex-shrink: 0;
min-width: 20px;
color: var(--app-text-muted);
font-size: 12px;
font-variant-numeric: tabular-nums;
text-align: right;
}
.category-item.is-active .category-count {
color: var(--app-accent-strong);
}
.market-content {
@@ -6,8 +6,8 @@ import com.starsee.starapi.common.core.domain.R;
import com.starsee.starapi.common.mybatis.core.page.PageQuery;
import com.starsee.starapi.common.web.core.BaseController;
import com.starsee.starapi.openapi.domain.bo.ApiInfoBo;
import com.starsee.starapi.openapi.domain.vo.ApiCategoryVo;
import com.starsee.starapi.openapi.domain.vo.ApiInfoVo;
import com.starsee.starapi.openapi.domain.vo.PortalApiCategoryVo;
import com.starsee.starapi.openapi.service.portal.IPortalApiService;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
@@ -38,11 +38,11 @@ public class PortalApiController extends BaseController {
/**
* 查询API市场分类列表
*
* @return 正常态分类列表
* @return 正常态分类列表,每个分类附带该分类下正常态接口数量
*/
@SaCheckLogin
@GetMapping("/category/list")
public R<List<ApiCategoryVo>> categoryList() {
public R<List<PortalApiCategoryVo>> categoryList() {
return R.ok(portalApiService.queryCategoryList());
}
@@ -0,0 +1,53 @@
package com.starsee.starapi.openapi.domain.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 用户端(开发者控制台)API市场分类视图对象
* <p>
* 在管理端分类字段基础上补充该分类下正常态接口数量,供API市场左侧分类导航展示。
*
* @author x6g2
* @date 2026-11-10
*/
@Data
public class PortalApiCategoryVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 分类ID
*/
private Long id;
/**
* 分类名称
*/
private String name;
/**
* 排序值(升序)
*/
private Integer sort;
/**
* 状态(0正常 1停用)
*/
private String status;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 该分类下正常态(上线)接口数量,无接口时为0
*/
private Long apiCount;
}
@@ -3,8 +3,8 @@ package com.starsee.starapi.openapi.service.portal;
import com.starsee.starapi.common.core.domain.PageResult;
import com.starsee.starapi.common.mybatis.core.page.PageQuery;
import com.starsee.starapi.openapi.domain.bo.ApiInfoBo;
import com.starsee.starapi.openapi.domain.vo.ApiCategoryVo;
import com.starsee.starapi.openapi.domain.vo.ApiInfoVo;
import com.starsee.starapi.openapi.domain.vo.PortalApiCategoryVo;
import java.util.List;
@@ -21,9 +21,9 @@ public interface IPortalApiService {
/**
* 查询API市场可见的分类列表
*
* @return 正常态分类列表(按排序值升序)
* @return 正常态分类列表(按排序值升序),每个分类附带该分类下正常态接口数量
*/
List<ApiCategoryVo> queryCategoryList();
List<PortalApiCategoryVo> queryCategoryList();
/**
* 分页查询API市场接口列表
@@ -4,10 +4,13 @@ import com.starsee.starapi.common.core.domain.PageResult;
import com.starsee.starapi.common.core.exception.ServiceException;
import com.starsee.starapi.common.mybatis.core.page.PageQuery;
import com.starsee.starapi.openapi.constant.OpenApiConstants;
import com.starsee.starapi.openapi.domain.ApiInfo;
import com.starsee.starapi.openapi.domain.bo.ApiCategoryBo;
import com.starsee.starapi.openapi.domain.bo.ApiInfoBo;
import com.starsee.starapi.openapi.domain.vo.ApiCategoryVo;
import com.starsee.starapi.openapi.domain.vo.ApiInfoVo;
import com.starsee.starapi.openapi.domain.vo.PortalApiCategoryVo;
import com.starsee.starapi.openapi.mapper.ApiInfoMapper;
import com.starsee.starapi.openapi.service.IApiCategoryService;
import com.starsee.starapi.openapi.service.IApiInfoService;
import com.starsee.starapi.openapi.service.portal.IPortalApiService;
@@ -15,6 +18,8 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 用户端(开发者控制台)API市场Service业务层处理
@@ -33,17 +38,51 @@ public class PortalApiServiceImpl implements IPortalApiService {
private final IApiCategoryService apiCategoryService;
private final ApiInfoMapper apiInfoMapper;
/**
* 查询API市场可见的分类列表
* <p>
* 分类只取正常态并按排序值升序;同时统计每个分类下正常态(上线)接口数量,
* 未命中接口的分类数量为0。
*
* @return 正常态分类列表(按排序值升序)
* @return 正常态分类列表(按排序值升序),每个分类附带该分类下正常态接口数量
*/
@Override
public List<ApiCategoryVo> queryCategoryList() {
public List<PortalApiCategoryVo> queryCategoryList() {
ApiCategoryBo bo = new ApiCategoryBo();
// 用户端只展示正常态分类,前端传入的状态条件不生效
bo.setStatus(OpenApiConstants.STATUS_NORMAL);
return apiCategoryService.queryList(bo);
List<ApiCategoryVo> categories = apiCategoryService.queryList(bo);
// 只查询分类ID做分组计数,逻辑删除记录由MyBatis-Plus自动过滤
Map<Long, Long> apiCountMap = apiInfoMapper.lambda()
.select(ApiInfo::getCategoryId)
.eq(ApiInfo::getStatus, OpenApiConstants.STATUS_NORMAL)
.list()
.stream()
.filter(apiInfo -> apiInfo.getCategoryId() != null)
.collect(Collectors.groupingBy(ApiInfo::getCategoryId, Collectors.counting()));
return categories.stream()
.map(category -> toPortalCategoryVo(category, apiCountMap.getOrDefault(category.getId(), 0L)))
.toList();
}
/**
* 分类视图对象转换为用户端分类视图对象,并填充接口数量
*
* @param category 管理端分类视图对象
* @param apiCount 该分类下正常态接口数量
* @return 用户端分类视图对象
*/
private PortalApiCategoryVo toPortalCategoryVo(ApiCategoryVo category, Long apiCount) {
PortalApiCategoryVo vo = new PortalApiCategoryVo();
vo.setId(category.getId());
vo.setName(category.getName());
vo.setSort(category.getSort());
vo.setStatus(category.getStatus());
vo.setCreateTime(category.getCreateTime());
vo.setApiCount(apiCount);
return vo;
}
/**