fix:优化模板查询

注释获取线上的模板数据
This commit is contained in:
weitang 2025-06-30 09:13:32 +08:00
parent 60c87b5440
commit eb451187ff
6 changed files with 118 additions and 41 deletions

View File

@ -60,6 +60,19 @@ public class MenuController {
} }
} }
/**
* 移动菜单到指定父级
*/
@PostMapping("/moveMenu")
public ResponseResult moveMenu(@RequestParam String menuId, @RequestParam String targetParentId) {
boolean result = menuService.moveMenu(menuId, targetParentId);
if (result) {
return ResponseResult.success("移动成功");
} else {
return ResponseResult.error("移动失败");
}
}
/*********************************** /***********************************
* 用途说明修改菜单及按钮根据ID * 用途说明修改菜单及按钮根据ID
* 参数说明 * 参数说明

View File

@ -52,4 +52,7 @@ public interface IMenuService extends IService<Menu> {
boolean changeOrder(String menuId, String direction); boolean changeOrder(String menuId, String direction);
boolean moveMenu(String menuId, String targetParentId);
} }

View File

@ -1,5 +1,6 @@
package io.gisbi.application.system.service.impl; package io.gisbi.application.system.service.impl;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@ -255,6 +256,36 @@ public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements IM
return true; return true;
} }
@Override
public boolean moveMenu(String menuId, String targetParentId) {
Menu menu = menuMapper.selectById(menuId);
if (menu == null) {
return false;
}
// 更新父级ID
menu.setParentid(targetParentId);
// 获取新父级下的最大序号
QueryWrapper<Menu> wrapper = new QueryWrapper<>();
wrapper.eq("parentid", targetParentId);
wrapper.select("orderno","code");
wrapper.orderByDesc("orderno");
List<Menu> list = menuMapper.selectList(wrapper);
if (list.isEmpty()) {
return false;
}
Integer maxOrderNo = list.getFirst().getOrderno();
// 设置新的序号为最大值+1
menu.setOrderno(maxOrderNo == null ? 1 : maxOrderNo + 1);
// 设置移动过后的菜单code
// 更新菜单信息
return menuMapper.updateById(menu) > 0;
}
private void swapOrder(Menu m1, Menu m2) { private void swapOrder(Menu m1, Menu m2) {
Integer temp = m1.getOrderno(); Integer temp = m1.getOrderno();
m1.setOrderno(m2.getOrderno()); m1.setOrderno(m2.getOrderno());

View File

@ -37,7 +37,9 @@ import java.util.stream.Collectors;
*/ */
@Service @Service
public class TemplateCenterManage { public class TemplateCenterManage {
private final static String POSTS_API_V2 = "/apis/api.store.halo.run/v1alpha1/applications?keyword=&priceMode=&sort=latestReleaseTimestamp%2Cdesc&type=THEME&deVersion=V2&templateType=&label=&page=1&size=2000";
private final static String POSTS_API_V2 = "/apis/api.store.halo.run/v1alpha1/applications?keyword=&priceMode" +
"=&sort=latestReleaseTimestamp%2Cdesc&type=THEME&deVersion=V2&templateType=&label=&page=1&size=2000";
private final static String TEMPLATE_META_DATA_URL = "/upload/meta_data.json"; private final static String TEMPLATE_META_DATA_URL = "/upload/meta_data.json";
private final static String TEMPLATE_BASE_INFO_URL = "/apis/api.store.halo.run/v1alpha1/applications/"; private final static String TEMPLATE_BASE_INFO_URL = "/apis/api.store.halo.run/v1alpha1/applications/";
@Resource @Resource
@ -59,7 +61,8 @@ public class TemplateCenterManage {
public TemplateManageFileDTO getTemplateFromMarket(String templateUrl) { public TemplateManageFileDTO getTemplateFromMarket(String templateUrl) {
if (StringUtils.isNotEmpty(templateUrl)) { if (StringUtils.isNotEmpty(templateUrl)) {
String templateName = templateUrl.substring(templateUrl.lastIndexOf("/") + 1, templateUrl.length()); String templateName = templateUrl.substring(templateUrl.lastIndexOf("/") + 1, templateUrl.length());
templateUrl = templateUrl.replace(templateName, URLEncoder.encode(templateName, StandardCharsets.UTF_8).replace("+", "%20")); templateUrl = templateUrl.replace(templateName,
URLEncoder.encode(templateName, StandardCharsets.UTF_8).replace("+", "%20"));
String sufUrl = sysParameterManage.groupVal("template.").get("template.url"); String sufUrl = sysParameterManage.groupVal("template.").get("template.url");
String templateInfo = HttpClientUtil.get(sufUrl + templateUrl, null); String templateInfo = HttpClientUtil.get(sufUrl + templateUrl, null);
return JsonUtil.parseObject(templateInfo, TemplateManageFileDTO.class); return JsonUtil.parseObject(templateInfo, TemplateManageFileDTO.class);
@ -75,7 +78,8 @@ public class TemplateCenterManage {
if (StringUtils.isNotEmpty(templateName)) { if (StringUtils.isNotEmpty(templateName)) {
String sufUrl = sysParameterManage.groupVal("template.").get("template.url"); String sufUrl = sysParameterManage.groupVal("template.").get("template.url");
String templateBaseInfo = HttpClientUtil.get(sufUrl + TEMPLATE_BASE_INFO_URL + templateName, null); String templateBaseInfo = HttpClientUtil.get(sufUrl + TEMPLATE_BASE_INFO_URL + templateName, null);
MarketTemplateV2ItemResult baseItemInfo = JsonUtil.parseObject(templateBaseInfo, MarketTemplateV2ItemResult.class); MarketTemplateV2ItemResult baseItemInfo = JsonUtil.parseObject(templateBaseInfo,
MarketTemplateV2ItemResult.class);
String templateUrl = ""; String templateUrl = "";
if (baseItemInfo.getLatestRelease() != null) { if (baseItemInfo.getLatestRelease() != null) {
templateUrl = sufUrl + "/store/apps/" + templateName + templateUrl = sufUrl + "/store/apps/" + templateName +
@ -117,10 +121,15 @@ public class TemplateCenterManage {
} }
} }
public MarketBaseResponse searchTemplate() { public MarketBaseResponse searchTemplate(String offline) {
try { try {
Map<String, String> templateParams = sysParameterManage.groupVal("template."); Map<String, String> templateParams = sysParameterManage.groupVal("template.");
return baseResponseV2Trans(templateQuery(templateParams), searchTemplateFromManage(), templateParams.get("template.url")); MarketTemplateV2BaseResponse marketTemplateV2BaseResponse = null;
if (StringUtils.isNotEmpty(offline) && "0".equals(offline)) {
marketTemplateV2BaseResponse = templateQuery(templateParams);
}
return baseResponseV2Trans(marketTemplateV2BaseResponse, searchTemplateFromManage(), templateParams.get(
"template.url"));
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e);
e.printStackTrace(); e.printStackTrace();
@ -141,13 +150,15 @@ public class TemplateCenterManage {
return null; return null;
} }
private List<TemplateMarketDTO> baseManage2MarketTrans(List<TemplateManageDTO> manageResult, Map<String, String> categoryMap) { private List<TemplateMarketDTO> baseManage2MarketTrans(List<TemplateManageDTO> manageResult,
Map<String, String> categoryMap) {
List<TemplateMarketDTO> result = new ArrayList<>(); List<TemplateMarketDTO> result = new ArrayList<>();
manageResult.stream().forEach(templateManageDTO -> { manageResult.stream().forEach(templateManageDTO -> {
templateManageDTO.setCategoryName(categoryMap.get(templateManageDTO.getPid())); templateManageDTO.setCategoryName(categoryMap.get(templateManageDTO.getPid()));
List<String> categories = templateManageDTO.getCategories(); List<String> categories = templateManageDTO.getCategories();
if (!CollectionUtils.isEmpty(categories)) { if (!CollectionUtils.isEmpty(categories)) {
List<String> categoryNames = categories.stream().map(categoryId -> categoryMap.get(categoryId)).collect(Collectors.toList()); List<String> categoryNames =
categories.stream().map(categoryId -> categoryMap.get(categoryId)).collect(Collectors.toList());
templateManageDTO.setCategoryNames(categoryNames); templateManageDTO.setCategoryNames(categoryNames);
result.add(new TemplateMarketDTO(templateManageDTO)); result.add(new TemplateMarketDTO(templateManageDTO));
} }
@ -155,7 +166,6 @@ public class TemplateCenterManage {
return result; return result;
} }
public MarketBaseResponse searchTemplateRecommend() { public MarketBaseResponse searchTemplateRecommend() {
MarketTemplateV2BaseResponse v2BaseResponse = null; MarketTemplateV2BaseResponse v2BaseResponse = null;
Map<String, String> templateParams = sysParameterManage.groupVal("template."); Map<String, String> templateParams = sysParameterManage.groupVal("template.");
@ -170,20 +180,24 @@ public class TemplateCenterManage {
return baseResponseV2TransRecommend(v2BaseResponse, manage, templateParams.get("template.url")); return baseResponseV2TransRecommend(v2BaseResponse, manage, templateParams.get("template.url"));
} }
public MarketPreviewBaseResponse searchTemplatePreview() { public MarketPreviewBaseResponse searchTemplatePreview(String offline) {
try { try {
MarketBaseResponse baseContentRsp = searchTemplate(); MarketBaseResponse baseContentRsp = searchTemplate(offline);
List<MarketMetaDataVO> categories = baseContentRsp.getCategories().stream().filter(category -> !Translator.get("i18n_template_recent").equals(category.getLabel())).toList(); List<MarketMetaDataVO> categories =
baseContentRsp.getCategories().stream().filter(category -> !Translator.get("i18n_template_recent").equals(category.getLabel())).toList();
List<TemplateMarketDTO> contents = baseContentRsp.getContents(); List<TemplateMarketDTO> contents = baseContentRsp.getContents();
List<TemplateMarketPreviewInfoDTO> previewContents = new ArrayList<>(); List<TemplateMarketPreviewInfoDTO> previewContents = new ArrayList<>();
categories.forEach(category -> { categories.forEach(category -> {
if (Translator.get("i18n_template_recommend").equals(category.getLabel())) { if (Translator.get("i18n_template_recommend").equals(category.getLabel())) {
previewContents.add(new TemplateMarketPreviewInfoDTO(category, contents.stream().filter(template -> "Y".equals(template.getSuggest())).collect(Collectors.toList()))); previewContents.add(new TemplateMarketPreviewInfoDTO(category,
contents.stream().filter(template -> "Y".equals(template.getSuggest())).collect(Collectors.toList())));
} else { } else {
previewContents.add(new TemplateMarketPreviewInfoDTO(category, contents.stream().filter(template -> checkCategoryMatch(template, category.getLabel())).collect(Collectors.toList()))); previewContents.add(new TemplateMarketPreviewInfoDTO(category,
contents.stream().filter(template -> checkCategoryMatch(template, category.getLabel())).collect(Collectors.toList())));
} }
}); });
return new MarketPreviewBaseResponse(baseContentRsp.getBaseUrl(), categories.stream().map(MarketMetaDataVO::getLabel) return new MarketPreviewBaseResponse(baseContentRsp.getBaseUrl(),
categories.stream().map(MarketMetaDataVO::getLabel)
.collect(Collectors.toList()), previewContents); .collect(Collectors.toList()), previewContents);
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e);
@ -201,9 +215,11 @@ public class TemplateCenterManage {
} }
} }
private MarketBaseResponse baseResponseV2TransRecommend(MarketTemplateV2BaseResponse v2BaseResponse, List<TemplateMarketDTO> templateManages, String url) { private MarketBaseResponse baseResponseV2TransRecommend(MarketTemplateV2BaseResponse v2BaseResponse,
List<TemplateMarketDTO> templateManages, String url) {
Map<String, Long> useTime = coreOptRecentManage.findTemplateRecentUseTime(); Map<String, Long> useTime = coreOptRecentManage.findTemplateRecentUseTime();
List<MarketMetaDataVO> categoryVO = getCategoriesV2().stream().filter(node -> !"全部".equalsIgnoreCase(node.getLabel())).collect(Collectors.toList()); List<MarketMetaDataVO> categoryVO =
getCategoriesV2().stream().filter(node -> !"全部".equalsIgnoreCase(node.getLabel())).collect(Collectors.toList());
Map<String, String> categoriesMap = categoryVO.stream() Map<String, String> categoriesMap = categoryVO.stream()
.collect(Collectors.toMap(MarketMetaDataVO::getSlug, MarketMetaDataVO::getLabel)); .collect(Collectors.toMap(MarketMetaDataVO::getSlug, MarketMetaDataVO::getLabel));
List<TemplateMarketDTO> contents = new ArrayList<>(); List<TemplateMarketDTO> contents = new ArrayList<>();
@ -212,7 +228,10 @@ public class TemplateCenterManage {
MarketApplicationSpecVO spec = marketTemplateV2ItemResult.getApplication().getSpec(); MarketApplicationSpecVO spec = marketTemplateV2ItemResult.getApplication().getSpec();
MarketApplicationMetaDataVO metadata = marketTemplateV2ItemResult.getApplication().getMetadata(); MarketApplicationMetaDataVO metadata = marketTemplateV2ItemResult.getApplication().getMetadata();
if ("Y".equalsIgnoreCase(spec.getSuggest())) { if ("Y".equalsIgnoreCase(spec.getSuggest())) {
contents.add(new TemplateMarketDTO(metadata.getName(), spec.getDisplayName(), spec.getScreenshots().get(0).getUrl(), spec.getLinks().get(0).getUrl(), categoriesMap.get(spec.getLabel()), spec.getTemplateType(), useTime.get(spec.getReadmeName()), "Y", spec.getTemplateClassification())); contents.add(new TemplateMarketDTO(metadata.getName(), spec.getDisplayName(),
spec.getScreenshots().get(0).getUrl(), spec.getLinks().get(0).getUrl(),
categoriesMap.get(spec.getLabel()), spec.getTemplateType(),
useTime.get(spec.getReadmeName()), "Y", spec.getTemplateClassification()));
} }
}); });
} }
@ -220,8 +239,10 @@ public class TemplateCenterManage {
Collections.sort(contents); Collections.sort(contents);
Long countDataV = contents.stream().filter(item -> "PANEL".equals(item.getTemplateType())).count(); Long countDataV = contents.stream().filter(item -> "PANEL".equals(item.getTemplateType())).count();
Long countDashboard = contents.stream().filter(item -> "SCREEN".equals(item.getTemplateType())).count(); Long countDashboard = contents.stream().filter(item -> "SCREEN".equals(item.getTemplateType())).count();
List<TemplateMarketDTO> templateDataV = templateManages.stream().filter(item -> "PANEL".equals(item.getTemplateType())).collect(Collectors.toList()); List<TemplateMarketDTO> templateDataV =
List<TemplateMarketDTO> templateDashboard = templateManages.stream().filter(item -> "SCREEN".equals(item.getTemplateType())).collect(Collectors.toList()); templateManages.stream().filter(item -> "PANEL".equals(item.getTemplateType())).collect(Collectors.toList());
List<TemplateMarketDTO> templateDashboard =
templateManages.stream().filter(item -> "SCREEN".equals(item.getTemplateType())).collect(Collectors.toList());
if (countDataV < 10) { if (countDataV < 10) {
Long addItemCount = 10 - countDataV; Long addItemCount = 10 - countDataV;
Long addIndex = templateDataV.size() < addItemCount ? templateDataV.size() : addItemCount; Long addIndex = templateDataV.size() < addItemCount ? templateDataV.size() : addItemCount;
@ -237,12 +258,15 @@ public class TemplateCenterManage {
return new MarketBaseResponse(url, categoryVO, contents); return new MarketBaseResponse(url, categoryVO, contents);
} }
private MarketBaseResponse baseResponseV2Trans(MarketTemplateV2BaseResponse v2BaseResponse, List<TemplateMarketDTO> contents, String url) { private MarketBaseResponse baseResponseV2Trans(MarketTemplateV2BaseResponse v2BaseResponse,
List<TemplateMarketDTO> contents, String url) {
Map<String, Long> useTime = coreOptRecentManage.findTemplateRecentUseTime(); Map<String, Long> useTime = coreOptRecentManage.findTemplateRecentUseTime();
List<MarketMetaDataVO> categoryVO = getCategoriesObject().stream().filter(node -> !"全部".equalsIgnoreCase(node.getLabel())).collect(Collectors.toList()); List<MarketMetaDataVO> categoryVO =
getCategoriesObject().stream().filter(node -> !"全部".equalsIgnoreCase(node.getLabel())).collect(Collectors.toList());
Map<String, String> categoriesMap = categoryVO.stream() Map<String, String> categoriesMap = categoryVO.stream()
.collect(Collectors.toMap(MarketMetaDataVO::getValue, MarketMetaDataVO::getLabel)); .collect(Collectors.toMap(MarketMetaDataVO::getValue, MarketMetaDataVO::getLabel));
List<String> activeCategoriesName = new ArrayList<>(Arrays.asList(Translator.get("i18n_template_recent"), Translator.get("i18n_template_recommend"))); List<String> activeCategoriesName = new ArrayList<>(Arrays.asList(Translator.get("i18n_template_recent"),
Translator.get("i18n_template_recommend")));
contents.stream().forEach(templateMarketDTO -> { contents.stream().forEach(templateMarketDTO -> {
Long recentUseTime = useTime.get(templateMarketDTO.getId()); Long recentUseTime = useTime.get(templateMarketDTO.getId());
templateMarketDTO.setRecentUseTime(recentUseTime == null ? 0 : recentUseTime); templateMarketDTO.setRecentUseTime(recentUseTime == null ? 0 : recentUseTime);
@ -252,7 +276,10 @@ public class TemplateCenterManage {
v2BaseResponse.getItems().stream().forEach(marketTemplateV2ItemResult -> { v2BaseResponse.getItems().stream().forEach(marketTemplateV2ItemResult -> {
MarketApplicationSpecVO spec = marketTemplateV2ItemResult.getApplication().getSpec(); MarketApplicationSpecVO spec = marketTemplateV2ItemResult.getApplication().getSpec();
MarketApplicationMetaDataVO metadata = marketTemplateV2ItemResult.getApplication().getMetadata(); MarketApplicationMetaDataVO metadata = marketTemplateV2ItemResult.getApplication().getMetadata();
contents.add(new TemplateMarketDTO(metadata.getName(), spec.getDisplayName(), spec.getScreenshots().get(0).getUrl(), spec.getLinks().get(0).getUrl(), categoriesMap.get(spec.getLabel()), spec.getTemplateType(), useTime.get(spec.getReadmeName()), spec.getSuggest(), spec.getTemplateClassification())); contents.add(new TemplateMarketDTO(metadata.getName(), spec.getDisplayName(),
spec.getScreenshots().get(0).getUrl(), spec.getLinks().get(0).getUrl(),
categoriesMap.get(spec.getLabel()), spec.getTemplateType(), useTime.get(spec.getReadmeName())
, spec.getSuggest(), spec.getTemplateClassification()));
if (categoriesMap.get(spec.getLabel()) != null) { if (categoriesMap.get(spec.getLabel()) != null) {
activeCategoriesName.add(categoriesMap.get(spec.getLabel())); activeCategoriesName.add(categoriesMap.get(spec.getLabel()));
} }
@ -260,10 +287,10 @@ public class TemplateCenterManage {
} }
// 最近使用排序 // 最近使用排序
Collections.sort(contents); Collections.sort(contents);
return new MarketBaseResponse(url, categoryVO.stream().filter(node -> activeCategoriesName.contains(node.getLabel())).collect(Collectors.toList()), contents); return new MarketBaseResponse(url,
categoryVO.stream().filter(node -> activeCategoriesName.contains(node.getLabel())).collect(Collectors.toList()), contents);
} }
public List<String> getCategories() { public List<String> getCategories() {
return getCategoriesV2().stream().map(MarketMetaDataVO::getLabel) return getCategoriesV2().stream().map(MarketMetaDataVO::getLabel)
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -271,7 +298,8 @@ public class TemplateCenterManage {
public List<MarketMetaDataVO> getCategoriesObject() { public List<MarketMetaDataVO> getCategoriesObject() {
List<MarketMetaDataVO> result = getCategoriesV2(); List<MarketMetaDataVO> result = getCategoriesV2();
result.add(0, new MarketMetaDataVO("recent", Translator.get("i18n_template_recent"), CommonConstants.TEMPLATE_SOURCE.PUBLIC)); result.add(0, new MarketMetaDataVO("recent", Translator.get("i18n_template_recent"),
CommonConstants.TEMPLATE_SOURCE.PUBLIC));
return result; return result;
} }
@ -285,17 +313,19 @@ public class TemplateCenterManage {
List<MarketMetaDataVO> allCategories = new ArrayList<>(); List<MarketMetaDataVO> allCategories = new ArrayList<>();
List<TemplateManageDTO> manageCategories = templateManageMapper.findCategories(null); List<TemplateManageDTO> manageCategories = templateManageMapper.findCategories(null);
List<MarketMetaDataVO> manageCategoriesTrans = manageCategories.stream() List<MarketMetaDataVO> manageCategoriesTrans = manageCategories.stream()
.map(templateCategory -> new MarketMetaDataVO(templateCategory.getId(), templateCategory.getName(), CommonConstants.TEMPLATE_SOURCE.MANAGE)) .map(templateCategory -> new MarketMetaDataVO(templateCategory.getId(), templateCategory.getName(),
CommonConstants.TEMPLATE_SOURCE.MANAGE))
.collect(Collectors.toList()); .collect(Collectors.toList());
try { // try {
Map<String, String> templateParams = sysParameterManage.groupVal("template."); // Map<String, String> templateParams = sysParameterManage.groupVal("template.");
String resultStr = marketGet(templateParams.get("template.url") + TEMPLATE_META_DATA_URL, null); // String resultStr = marketGet(templateParams.get("template.url") + TEMPLATE_META_DATA_URL, null);
MarketMetaDataBaseResponse metaData = JsonUtil.parseObject(resultStr, MarketMetaDataBaseResponse.class); // MarketMetaDataBaseResponse metaData = JsonUtil.parseObject(resultStr, MarketMetaDataBaseResponse.class);
allCategories.addAll(metaData.getLabels()); // allCategories.addAll(metaData.getLabels());
allCategories.add(0, new MarketMetaDataVO("suggest", Translator.get("i18n_template_recommend"), CommonConstants.TEMPLATE_SOURCE.PUBLIC)); // allCategories.add(0, new MarketMetaDataVO("suggest", Translator.get("i18n_template_recommend"),
} catch (Exception e) { // CommonConstants.TEMPLATE_SOURCE.PUBLIC));
LogUtil.error("模板市场分类获取错误", e); // } catch (Exception e) {
} // LogUtil.error("模板市场分类获取错误", e);
// }
return mergeAndDistinctByLabel(allCategories, manageCategoriesTrans); return mergeAndDistinctByLabel(allCategories, manageCategoriesTrans);

View File

@ -23,7 +23,7 @@ public class TemplateMarketService implements TemplateMarketApi {
private TemplateCenterManage templateCenterManage; private TemplateCenterManage templateCenterManage;
@Override @Override
public MarketBaseResponse searchTemplate() { public MarketBaseResponse searchTemplate() {
return templateCenterManage.searchTemplate(); return templateCenterManage.searchTemplate("0");
} }
@Override @Override
public MarketBaseResponse searchTemplateRecommend() { public MarketBaseResponse searchTemplateRecommend() {
@ -31,8 +31,8 @@ public class TemplateMarketService implements TemplateMarketApi {
} }
@Override @Override
public MarketPreviewBaseResponse searchTemplatePreview() { public MarketPreviewBaseResponse searchTemplatePreview(String offline) {
return templateCenterManage.searchTemplatePreview(); return templateCenterManage.searchTemplatePreview(offline);
} }
@Override @Override

View File

@ -25,7 +25,7 @@ public interface TemplateMarketApi {
@GetMapping("/searchPreview") @GetMapping("/searchPreview")
@Operation(summary = "预览") @Operation(summary = "预览")
MarketPreviewBaseResponse searchTemplatePreview(); MarketPreviewBaseResponse searchTemplatePreview(String offline);
@GetMapping("/categories") @GetMapping("/categories")
@Operation(summary = "分类") @Operation(summary = "分类")