feat(quotation): 添加报价模型配置项多语言支持和管理功能

- 将 ModelConfigItemVO 重命名为 ModelConfigItemLanguageVO 并调整字段映射
- 修改接口返回类型从 ModelConfigItemVO 到 ModelConfigItemLanguageVO
- 在控制器中实现部件或系统的更新、删除、启用/禁用功能
- 添加发布功能用于配置状态管理
- 调整创建时间戳设置逻辑,优化数据初始化流程
- 新增 ModelConfigItemUpdateRequest 请求类处理更新操作
- 修改树形结构查询中的父子关系字段映射
- 统一使用雪花算法生成唯一ID并优化实体类构建流程
This commit is contained in:
曹鹏飞 2026-02-21 14:27:32 +08:00
parent 83ff612d38
commit b63239be16
11 changed files with 280 additions and 48 deletions

View File

@ -7,19 +7,19 @@ import java.util.List;
@Data
@Accessors(chain = true)
public class ModelConfigItemVO {
public class ModelConfigItemLanguageVO {
private Long id;
/**
* 上级id
*/
private Long parentId;
private Long itemParentId;
/**
* 多语言项id
* 项id
*/
private Long languageItemId;
private Long itemId;
/**
* 部件或系统
@ -51,5 +51,5 @@ public class ModelConfigItemVO {
*/
private String imageUrl;
private List<ModelConfigItemVO> children;
private List<ModelConfigItemLanguageVO> children;
}

View File

@ -2,16 +2,18 @@ package com.nflg.mobilebroken.quotation.controller;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.nflg.mobilebroken.common.constant.Constant;
import com.nflg.mobilebroken.common.pojo.ApiResult;
import com.nflg.mobilebroken.common.pojo.PageData;
import com.nflg.mobilebroken.common.pojo.request.EnableRequest;
import com.nflg.mobilebroken.common.pojo.request.ModelConfigSearchRequest;
import com.nflg.mobilebroken.common.pojo.vo.LanguageVO;
import com.nflg.mobilebroken.common.pojo.vo.ModelConfigVO;
import com.nflg.mobilebroken.common.pojo.vo.quotation.ModelConfigItemVO;
import com.nflg.mobilebroken.common.pojo.vo.quotation.ModelConfigItemLanguageVO;
import com.nflg.mobilebroken.common.util.AdminUserUtil;
import com.nflg.mobilebroken.common.util.VUtils;
import com.nflg.mobilebroken.quotation.pojo.request.ModelConfigItemAddRequest;
import com.nflg.mobilebroken.quotation.pojo.request.ModelConfigItemUpdateRequest;
import com.nflg.mobilebroken.repository.entity.Language;
import com.nflg.mobilebroken.repository.entity.QuotationModelConfig;
import com.nflg.mobilebroken.repository.entity.QuotationModelConfigItem;
@ -26,6 +28,7 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@ -66,16 +69,16 @@ public class ModelConfigController extends ControllerBase {
* @param languageCode 语言编码
*/
@GetMapping("/item/tree")
public ApiResult<List<ModelConfigItemVO>> getModelConfigItemTree(@RequestParam Long configId, @RequestParam String languageCode) {
List<ModelConfigItemVO> vos = modelConfigItemService.getVOListByConfigId(configId, languageCode);
public ApiResult<List<ModelConfigItemLanguageVO>> getModelConfigItemTree(@RequestParam Long configId, @RequestParam String languageCode) {
List<ModelConfigItemLanguageVO> vos = modelConfigItemService.getVOListByConfigId(configId, languageCode);
if (CollectionUtil.isEmpty(vos)) {
return ApiResult.success(Collections.emptyList());
}
vos.stream().filter(vo -> vo.getParentId() == 0L)
.sorted(Comparator.comparing(ModelConfigItemVO::getId))
vos.stream().filter(vo -> vo.getItemParentId() == 0L)
.sorted(Comparator.comparing(ModelConfigItemLanguageVO::getId))
.forEach(vo -> vo.setChildren(vos.stream()
.filter(i -> i.getParentId().equals(vo.getId()))
.map(i -> new ModelConfigItemVO()
.filter(i -> i.getItemParentId().equals(vo.getId()))
.map(i -> new ModelConfigItemLanguageVO()
.setId(i.getId())
.setPartName(i.getPartName())
.setPartRemark(i.getPartRemark())
@ -83,7 +86,7 @@ public class ModelConfigController extends ControllerBase {
.setEnable(i.getEnable())
.setType(i.getType())
.setOptionalType(i.getOptionalType())
).sorted(Comparator.comparing(ModelConfigItemVO::getId))
).sorted(Comparator.comparing(ModelConfigItemLanguageVO::getId))
.collect(Collectors.toList())
));
return ApiResult.success(vos);
@ -109,12 +112,9 @@ public class ModelConfigController extends ControllerBase {
.list();
config.setId(IdUtil.getSnowflakeNextId());
request.setConfigId(config.getId());
config.setCreateById(AdminUserUtil.getUserId());
config.setCreateBy(AdminUserUtil.getUserName());
config.setCreateTime(LocalDateTime.now());
config.setUpdateById(null);
config.setUpdateBy(null);
config.setUpdateTime(null);
config.setUpdateById(AdminUserUtil.getUserId());
config.setUpdateBy(AdminUserUtil.getUserName());
config.setUpdateTime(LocalDateTime.now());
modelConfigService.save(config);
if (CollectionUtil.isNotEmpty(items)) {
items.forEach(it -> {
@ -127,12 +127,9 @@ public class ModelConfigController extends ControllerBase {
itemLanguages.forEach(it -> {
it.setId(IdUtil.getSnowflakeNextId());
it.setConfigId(config.getId());
it.setCreateById(AdminUserUtil.getUserId());
it.setCreateBy(AdminUserUtil.getUserName());
it.setCreateTime(LocalDateTime.now());
it.setUpdateById(null);
it.setUpdateBy(null);
it.setUpdateTime(null);
it.setUpdateById(AdminUserUtil.getUserId());
it.setUpdateBy(AdminUserUtil.getUserName());
it.setUpdateTime(LocalDateTime.now());
});
modelConfigItemLanguageService.saveBatch(itemLanguages);
}
@ -145,21 +142,23 @@ public class ModelConfigController extends ControllerBase {
.throwMessage("已存在该名称的部件或系统");
} else {
QuotationModelConfig config = new QuotationModelConfig()
.setId(IdUtil.getSnowflakeNextId())
.setModelId(request.getModelId())
.setCreateById(AdminUserUtil.getUserId())
.setCreateBy(AdminUserUtil.getUserName())
.setCreateTime(LocalDateTime.now());
modelConfigService.save(config);
request.setConfigId(config.getId());
}
QuotationModelConfigItem item=new QuotationModelConfigItem()
QuotationModelConfigItem item = new QuotationModelConfigItem()
.setId(IdUtil.getSnowflakeNextId())
.setConfigId(request.getConfigId())
.setType(request.getType())
.setEnable(request.getEnable())
.setOptionalType(request.getOptionalType())
.setParentId(request.getParentId());
modelConfigItemService.save(item);
List<QuotationModelConfigItemLanguage> itemLanguages = new ArrayList<>();
QuotationModelConfigItemLanguage cnItem=new QuotationModelConfigItemLanguage()
QuotationModelConfigItemLanguage cnItem = new QuotationModelConfigItemLanguage()
.setConfigId(request.getConfigId())
.setConfigItemId(item.getId())
.setLanguageId(cn.getId())
@ -174,7 +173,7 @@ public class ModelConfigController extends ControllerBase {
itemLanguages.add(new QuotationModelConfigItemLanguage()
.setConfigId(request.getConfigId())
.setConfigItemId(item.getId())
.setLanguageId(cn.getId())
.setLanguageId(language.getId())
.setPartName(translate.translateWord(request.getPartName(), language.getTranslateCode()))
.setPartRemark(translate.translateWord(request.getPartRemark(), language.getTranslateCode()))
.setCreateById(AdminUserUtil.getUserId())
@ -185,4 +184,188 @@ public class ModelConfigController extends ControllerBase {
modelConfigItemLanguageService.saveBatch(itemLanguages);
return ApiResult.success(request.getConfigId());
}
/**
* 更新部件或系统
*/
@PostMapping("/item/update")
@Transactional
public ApiResult<Long> updateItem(@Valid @RequestBody ModelConfigItemUpdateRequest request) {
QuotationModelConfigItemLanguage languageItem = modelConfigItemLanguageService.getById(request.getId());
VUtils.trueThrowBusinessError(Objects.isNull(languageItem)).throwMessage("无效的语言配置");
QuotationModelConfig config = modelConfigService.getById(languageItem.getConfigId());
VUtils.trueThrowBusinessError(Objects.isNull(config)).throwMessage("无效的机型配置");
if (config.getConfigStatus() != 0) {
List<QuotationModelConfigItem> items = modelConfigItemService.lambdaQuery()
.eq(QuotationModelConfigItem::getConfigId, languageItem.getConfigId())
.list();
List<QuotationModelConfigItemLanguage> itemLanguages = modelConfigItemLanguageService.lambdaQuery()
.eq(QuotationModelConfigItemLanguage::getConfigId, languageItem.getConfigId())
.list();
config.setId(IdUtil.getSnowflakeNextId());
config.setUpdateById(AdminUserUtil.getUserId());
config.setUpdateBy(AdminUserUtil.getUserName());
config.setUpdateTime(LocalDateTime.now());
modelConfigService.save(config);
if (CollectionUtil.isNotEmpty(items)) {
items.forEach(it -> {
it.setId(IdUtil.getSnowflakeNextId());
it.setConfigId(config.getId());
if (StrUtil.equals(request.getLanguageCode(), Constant.DEFAULT_LANGUAGE_CODE)
&& it.getId().equals(languageItem.getConfigItemId())) {
it.setType(request.getType());
it.setOptionalType(request.getOptionalType());
it.setParentId(request.getParentId());
}
});
modelConfigItemService.saveBatch(items);
}
if (CollectionUtil.isNotEmpty(itemLanguages)) {
itemLanguages.forEach(it -> {
VUtils.trueThrowBusinessError(modelConfigItemLanguageService.lambdaQuery()
.eq(QuotationModelConfigItemLanguage::getConfigId, languageItem.getConfigId())
.eq(QuotationModelConfigItemLanguage::getLanguageId, languageItem.getLanguageId())
.eq(QuotationModelConfigItemLanguage::getPartName, request.getPartName())
.exists())
.throwMessage("已存在该名称的部件或系统");
if (it.getId().equals(request.getId())) {
it.setPartName(request.getPartName());
it.setPartRemark(request.getPartRemark());
}
it.setId(IdUtil.getSnowflakeNextId());
it.setConfigId(config.getId());
it.setUpdateById(AdminUserUtil.getUserId());
it.setUpdateBy(AdminUserUtil.getUserName());
it.setUpdateTime(LocalDateTime.now());
});
modelConfigItemLanguageService.saveBatch(itemLanguages);
}
}
return ApiResult.success(config.getId());
}
/**
* 删除部件或系统
* @param ids 项id列表
*/
@PostMapping("/item/delete")
@Transactional
public ApiResult<Long> deleteItem(@NotEmpty @RequestBody List<Long> ids) {
List<QuotationModelConfigItem> items = modelConfigItemService.lambdaQuery()
.in(QuotationModelConfigItem::getId, ids)
.list();
VUtils.trueThrowBusinessError(items.size() > 1).throwMessage("数据错误");
QuotationModelConfig config = modelConfigService.getById(items.get(0).getConfigId());
VUtils.trueThrowBusinessError(Objects.isNull(config)).throwMessage("无效的机型配置");
if (config.getConfigStatus() != 0) {
items = modelConfigItemService.lambdaQuery()
.eq(QuotationModelConfigItem::getConfigId, config.getId())
.list();
List<QuotationModelConfigItemLanguage> itemLanguages = modelConfigItemLanguageService.lambdaQuery()
.eq(QuotationModelConfigItemLanguage::getConfigId, config.getId())
.list();
config.setId(IdUtil.getSnowflakeNextId());
config.setUpdateById(AdminUserUtil.getUserId());
config.setUpdateBy(AdminUserUtil.getUserName());
config.setUpdateTime(LocalDateTime.now());
modelConfigService.save(config);
if (CollectionUtil.isNotEmpty(items)) {
items.removeIf(it -> ids.contains(it.getId()));
items.forEach(it -> {
it.setId(IdUtil.getSnowflakeNextId());
it.setConfigId(config.getId());
});
if (CollectionUtil.isNotEmpty(items)) {
modelConfigItemService.saveBatch(items);
}
}
if (CollectionUtil.isNotEmpty(itemLanguages)) {
itemLanguages.removeIf(it -> ids.contains(it.getConfigItemId()));
itemLanguages.forEach(it -> {
it.setId(IdUtil.getSnowflakeNextId());
it.setConfigId(config.getId());
it.setUpdateById(AdminUserUtil.getUserId());
it.setUpdateBy(AdminUserUtil.getUserName());
it.setUpdateTime(LocalDateTime.now());
});
if (CollectionUtil.isNotEmpty(itemLanguages)) {
modelConfigItemLanguageService.saveBatch(itemLanguages);
}
}
}
return ApiResult.success(config.getId());
}
/**
* 启用/禁用部件或系统
*/
@PostMapping("/item/enable")
@Transactional
public ApiResult<Long> enableItem(@RequestBody EnableRequest request) {
QuotationModelConfigItem item = modelConfigItemService.lambdaQuery()
.eq(QuotationModelConfigItem::getId, request.getId())
.one();
VUtils.trueThrowBusinessError(Objects.isNull(item)).throwMessage("无效的机型配置");
QuotationModelConfig config = modelConfigService.getById(item.getConfigId());
VUtils.trueThrowBusinessError(Objects.isNull(config)).throwMessage("无效的机型配置");
if (config.getConfigStatus() != 0) {
List<QuotationModelConfigItem> items = modelConfigItemService.lambdaQuery()
.eq(QuotationModelConfigItem::getConfigId, config.getId())
.list();
List<QuotationModelConfigItemLanguage> itemLanguages = modelConfigItemLanguageService.lambdaQuery()
.eq(QuotationModelConfigItemLanguage::getConfigId, config.getId())
.list();
config.setId(IdUtil.getSnowflakeNextId());
config.setUpdateById(AdminUserUtil.getUserId());
config.setUpdateBy(AdminUserUtil.getUserName());
config.setUpdateTime(LocalDateTime.now());
modelConfigService.save(config);
if (CollectionUtil.isNotEmpty(items)) {
items.forEach(it -> {
it.setId(IdUtil.getSnowflakeNextId());
it.setConfigId(config.getId());
if (it.getId().equals(request.getId())) {
it.setEnable(request.getEnable());
}
});
modelConfigItemService.saveBatch(items);
}
if (CollectionUtil.isNotEmpty(itemLanguages)) {
itemLanguages.forEach(it -> {
it.setId(IdUtil.getSnowflakeNextId());
it.setConfigId(config.getId());
it.setUpdateById(AdminUserUtil.getUserId());
it.setUpdateBy(AdminUserUtil.getUserName());
it.setUpdateTime(LocalDateTime.now());
});
modelConfigItemLanguageService.saveBatch(itemLanguages);
}
}
return ApiResult.success(config.getId());
}
/**
* 发布部件或系统
*/
@PostMapping("/publish")
@Transactional
public ApiResult<Void> publish(@RequestParam Long id) {
QuotationModelConfig config = modelConfigService.getById(id);
VUtils.trueThrowBusinessError(Objects.isNull(config)).throwMessage("无效的机型配置");
VUtils.trueThrowBusinessError(config.getConfigStatus() != 0).throwMessage("非草稿状态");
modelConfigService.lambdaUpdate()
.set(QuotationModelConfig::getConfigStatus, 2)
.set(QuotationModelConfig::getUpdateById, AdminUserUtil.getUserId())
.set(QuotationModelConfig::getUpdateBy, AdminUserUtil.getUserName())
.set(QuotationModelConfig::getUpdateTime, LocalDateTime.now())
.eq(QuotationModelConfig::getModelId, config.getModelId())
.eq(QuotationModelConfig::getConfigStatus, 1)
.update();
config.setConfigStatus(1);
config.setUpdateById(AdminUserUtil.getUserId());
config.setUpdateBy(AdminUserUtil.getUserName());
config.setUpdateTime(LocalDateTime.now());
modelConfigService.updateById(config);
return ApiResult.success();
}
}

View File

@ -20,7 +20,7 @@ public class ModelConfigItemAddRequest {
private Long configId;
/**
* 上级id
* 上级id,0表示无上级
*/
@NotNull
private Long parentId;
@ -48,12 +48,6 @@ public class ModelConfigItemAddRequest {
@NotNull
private Integer optionalType;
/**
* 是否启用
*/
@NotNull
private Boolean enable;
/**
* 图片
*/

View File

@ -0,0 +1,52 @@
package com.nflg.mobilebroken.quotation.pojo.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
public class ModelConfigItemUpdateRequest{
@NotNull
private Long id;
/**
* 多语言
*/
@NotBlank
private String languageCode;
/**
* 部件或系统
*/
@NotBlank
private String partName;
/**
* 参数/描述
*/
private String partRemark;
/**
* 上级id,0表示无上级
*/
private Long parentId;
/**
* 类别0可选配置1标准配置
*/
private Integer type;
/**
* 选配类别0新增可选1替换可选
*/
private Integer optionalType;
/**
* 图片
*/
private String imageUrl;
}

View File

@ -1,6 +1,6 @@
package com.nflg.mobilebroken.repository.mapper;
import com.nflg.mobilebroken.common.pojo.vo.quotation.ModelConfigItemVO;
import com.nflg.mobilebroken.common.pojo.vo.quotation.ModelConfigItemLanguageVO;
import com.nflg.mobilebroken.repository.entity.QuotationModelConfigItem;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
@ -16,5 +16,5 @@ import java.util.List;
*/
public interface QuotationModelConfigItemMapper extends BaseMapper<QuotationModelConfigItem> {
List<ModelConfigItemVO> getVOListByConfigId(Long configId, String languageCode);
List<ModelConfigItemLanguageVO> getVOListByConfigId(Long configId, String languageCode);
}

View File

@ -1,5 +1,6 @@
package com.nflg.mobilebroken.repository.mapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nflg.mobilebroken.common.pojo.PageData;
import com.nflg.mobilebroken.common.pojo.request.ModelConfigSearchRequest;
@ -17,5 +18,5 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
*/
public interface QuotationModelConfigMapper extends BaseMapper<QuotationModelConfig> {
PageData<ModelConfigVO> search(ModelConfigSearchRequest request, Page<?> objectPage);
IPage<ModelConfigVO> search(ModelConfigSearchRequest request, Page<?> objectPage);
}

View File

@ -1,6 +1,6 @@
package com.nflg.mobilebroken.repository.service;
import com.nflg.mobilebroken.common.pojo.vo.quotation.ModelConfigItemVO;
import com.nflg.mobilebroken.common.pojo.vo.quotation.ModelConfigItemLanguageVO;
import com.nflg.mobilebroken.repository.entity.QuotationModelConfigItem;
import com.baomidou.mybatisplus.extension.service.IService;
@ -16,5 +16,5 @@ import java.util.List;
*/
public interface IQuotationModelConfigItemService extends IService<QuotationModelConfigItem> {
List<ModelConfigItemVO> getVOListByConfigId(Long configId, String languageCode);
List<ModelConfigItemLanguageVO> getVOListByConfigId(Long configId, String languageCode);
}

View File

@ -1,5 +1,6 @@
package com.nflg.mobilebroken.repository.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.nflg.mobilebroken.common.pojo.PageData;
import com.nflg.mobilebroken.common.pojo.request.ModelConfigSearchRequest;
import com.nflg.mobilebroken.common.pojo.vo.ModelConfigVO;
@ -16,5 +17,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/
public interface IQuotationModelConfigService extends IService<QuotationModelConfig> {
PageData<ModelConfigVO> search(ModelConfigSearchRequest request);
IPage<ModelConfigVO> search(ModelConfigSearchRequest request);
}

View File

@ -1,6 +1,6 @@
package com.nflg.mobilebroken.repository.service.impl;
import com.nflg.mobilebroken.common.pojo.vo.quotation.ModelConfigItemVO;
import com.nflg.mobilebroken.common.pojo.vo.quotation.ModelConfigItemLanguageVO;
import com.nflg.mobilebroken.repository.entity.QuotationModelConfigItem;
import com.nflg.mobilebroken.repository.mapper.QuotationModelConfigItemMapper;
import com.nflg.mobilebroken.repository.service.IQuotationModelConfigItemService;
@ -21,7 +21,7 @@ import java.util.List;
public class QuotationModelConfigItemServiceImpl extends ServiceImpl<QuotationModelConfigItemMapper, QuotationModelConfigItem> implements IQuotationModelConfigItemService {
@Override
public List<ModelConfigItemVO> getVOListByConfigId(Long configId, String languageCode) {
public List<ModelConfigItemLanguageVO> getVOListByConfigId(Long configId, String languageCode) {
return baseMapper.getVOListByConfigId(configId, languageCode);
}
}

View File

@ -1,5 +1,6 @@
package com.nflg.mobilebroken.repository.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nflg.mobilebroken.common.pojo.PageData;
import com.nflg.mobilebroken.common.pojo.request.ModelConfigSearchRequest;
@ -22,7 +23,7 @@ import org.springframework.stereotype.Service;
public class QuotationModelConfigServiceImpl extends ServiceImpl<QuotationModelConfigMapper, QuotationModelConfig> implements IQuotationModelConfigService {
@Override
public PageData<ModelConfigVO> search(ModelConfigSearchRequest request) {
public IPage<ModelConfigVO> search(ModelConfigSearchRequest request) {
return baseMapper.search(request,new Page<>(request.getPage(),request.getPageSize()));
}
}

View File

@ -2,8 +2,8 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nflg.mobilebroken.repository.mapper.QuotationModelConfigItemMapper">
<select id="getVOListByConfigId" resultType="com.nflg.mobilebroken.common.pojo.vo.quotation.ModelConfigItemVO">
SELECT mcil.id as languageItemId,mci.parent_id,mcil.part_name,mcil.part_remark,mci.*
<select id="getVOListByConfigId" resultType="com.nflg.mobilebroken.common.pojo.vo.quotation.ModelConfigItemLanguageVO">
SELECT mcil.id,mci.parent_id as 'item_parent_id',mci.id as 'item_id',mcil.part_name,mcil.part_remark,mci.*
FROM quotation_model_config_item mci
INNER JOIN quotation_model_config_item_language mcil ON mci.id=mcil.config_item_id
INNER JOIN `language` l ON l.id=mcil.language_id