refactor(quotation): 优化报价系统中的系数配置和查询逻辑

- 修改 AdminShoppingController 中的搜索方法,移除客户服务依赖并优化空记录处理
- 更新 AppRatioAgentConfigController 中的系数配置检查逻辑,添加模型ID参数支持
- 在 DiscountConfigController 中增强导入功能,添加区域验证和折扣时间处理
- 调整 PlanController 中的价格计算逻辑,统一使用模型ID进行系数查询
- 修改多个服务接口和实现类,将用户系数查询方法改为基于模型ID的精确匹配
- 优化数据库查询映射,添加必要的表连接以支持目标名称显示
- 在 ShoppingController 中添加空记录检查以提高性能
This commit is contained in:
曹鹏飞 2026-03-13 18:31:25 +08:00
parent a324ff6f23
commit 6a7b51ce73
20 changed files with 108 additions and 65 deletions

View File

@ -1,8 +1,10 @@
package com.nflg.mobilebroken.common.pojo.request;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class ModelConfigSearchRequest extends PageRequest {
/**

View File

@ -1,8 +1,10 @@
package com.nflg.mobilebroken.common.pojo.request;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors
public class PageRequest {
//页码

View File

@ -21,7 +21,6 @@ public class QuotationProductModelSearchRequest {
/**
* 类型批次号
*/
@NotBlank
private String typeNumber;
/**

View File

@ -8,7 +8,7 @@ public class ProductTypeSimpleVO {
/**
* 模块名称
*/
private Integer moduleName;
private String moduleName;
/**
* 系列名称

View File

@ -1,5 +1,6 @@
package com.nflg.mobilebroken.quotation.controller.admin;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nflg.mobilebroken.common.pojo.ApiResult;
@ -9,8 +10,10 @@ import com.nflg.mobilebroken.common.pojo.request.QuotationSearchRequest;
import com.nflg.mobilebroken.common.pojo.vo.QuotationSearchVO;
import com.nflg.mobilebroken.common.util.AppUserUtil;
import com.nflg.mobilebroken.quotation.controller.ControllerBase;
import com.nflg.mobilebroken.repository.entity.AdminUser;
import com.nflg.mobilebroken.repository.entity.ProductModel;
import com.nflg.mobilebroken.repository.entity.TBaseCustomer;
import com.nflg.mobilebroken.repository.service.IAdminUserService;
import com.nflg.mobilebroken.repository.service.IQuotationShoppingOrderService;
import com.nflg.mobilebroken.repository.service.ITBaseCustomerService;
import org.springframework.web.bind.annotation.PostMapping;
@ -33,36 +36,16 @@ public class AdminShoppingController extends ControllerBase {
@Resource
private IQuotationShoppingOrderService shoppingOrderService;
@Resource
private ITBaseCustomerService customerService;
/**
* 查询报价单
*/
@PostMapping("/search")
public ApiResult<PageData<QuotationSearchVO>> searchQuotation(@Valid @RequestBody QuotationAdminSearchRequest request) {
IPage<QuotationSearchVO> datas = shoppingOrderService.searchFromAdmin(request);
boolean isAgent = AppUserUtil.isAgent();
List<TBaseCustomer> customers;
if (isAgent) {
customers = customerService.lambdaQuery()
.in(TBaseCustomer::getId, datas.getRecords().stream().map(QuotationSearchVO::getTargetId).collect(Collectors.toList()))
.list();
} else {
customers = null;
if (CollectionUtil.isEmpty(datas.getRecords())){
return ApiResult.success(PageData.empty());
}
return ApiResult.success(datas, data -> {
if (isAgent) {
data.setTargetName(
customers.stream()
.filter(item -> item.getId().equals(data.getTargetId()))
.map(TBaseCustomer::getAgencyCompanyName)
.findFirst()
.orElse("")
);
} else {
data.setTargetName(AppUserUtil.getUserName());
}
//TODO 设置汇率价格
return data;
});

View File

@ -40,6 +40,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;
@ -451,6 +453,7 @@ public class DiscountConfigController extends ControllerBase {
break;
}
}
VUtils.trueThrowBusinessError(areaCount == 0).throwMessage("未找到区域信息");
for (int index = 2, count = sheet.getLastRowNum(); index <= count; index++) {
log.info("处理第{}行", index);
Row row = sheet.getRow(index);
@ -473,25 +476,47 @@ public class DiscountConfigController extends ControllerBase {
.setModelNo(modelNo)
.setSeriesName(modelVO.getSeriesName())
.setTypeName(modelVO.getTypeName());
for (int i = 1; i <= areaCount; i++) {
for (int i = 0; i < areaCount; i++) {
int colIndex = 4 + i * 6;
String areaName = row.getCell(colIndex).getStringCellValue();
DictionaryItem area=areas.stream()
String areaName = sheet.getRow(0).getCell(colIndex).getStringCellValue();
DictionaryItem area = areas.stream()
.filter(di -> StrUtil.equals(di.getName(), areaName))
.findFirst()
.get();
String startDate=dataFormatter.formatCellValue(row.getCell(colIndex + 3));
// VUtils.trueThrowBusinessError(StrUtil.isNotBlank(startDate) && !DateUtil.(startDate))
// .throwMessage("折扣开始时间不能为空");
// DiscountForbidImportAreaDTO areaDTO=new DiscountForbidImportAreaDTO()
// .setAreaId(area.getId())
// .setRatio(new BigDecimal(dataFormatter.formatCellValue(row.getCell(colIndex + 1))))
// .setDiscountStartDate();
DiscountForbidImportAreaDTO areaDTO = new DiscountForbidImportAreaDTO()
.setAreaId(area.getId());
Cell ct = row.getCell(colIndex + 1);
VUtils.trueThrowBusinessError(Objects.isNull(ct)).throwMessage("机型" + modelNo + "未填写" + areaName + "折扣系数");
areaDTO.setRatio(new BigDecimal(dataFormatter.formatCellValue(ct)));
ct = row.getCell(colIndex + 3);
VUtils.trueThrowBusinessError(Objects.isNull(ct)).throwMessage("机型" + modelNo + "未填写" + areaName + "折扣开始时间");
Date startDate = ct.getDateCellValue();
areaDTO.setDiscountStartDate(Objects.isNull(startDate) ? null : startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
ct = row.getCell(colIndex + 4);
VUtils.trueThrowBusinessError(Objects.isNull(ct)).throwMessage("机型" + modelNo + "未填写" + areaName + "折扣结束时间");
Date endDate = ct.getDateCellValue();
areaDTO.setDiscountEndDate(Objects.isNull(endDate) ? null : endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
dto.getAreas().add(areaDTO);
}
Cell ct = row.getCell(4 + areaCount * 6);
VUtils.trueThrowBusinessError(Objects.isNull(ct)).throwMessage("机型" + modelNo + "未填写折扣对象");
List<String> customerNames = StrUtil.split(dataFormatter.formatCellValue(ct), ",");
List<TBaseCustomer> customers = customerService.lambdaQuery()
.eq(TBaseCustomer::getDelIs, 0)
.eq(TBaseCustomer::getEnableState, 1)
.in(TBaseCustomer::getAgencyCompanyName, customerNames)
.list();
customerNames.removeAll(customers.stream().map(TBaseCustomer::getAgencyCompanyName).collect(Collectors.toSet()));
VUtils.trueThrowBusinessError(CollectionUtil.isNotEmpty(customerNames))
.throwMessage("机型" + modelNo + "的以下折扣对象无效:" + StrUtil.join(",", customerNames));
dto.setTargetIds(customers.stream().map(TBaseCustomer::getId).collect(Collectors.toList()));
datas.add(dto);
}
}
ModelConfigSearchRequest request = new ModelConfigSearchRequest();
request.setPageSize(Integer.MAX_VALUE);
IPage<ModelDiscountConfigVO> pdata = discountService.search(request);
//TODO 合并数据
return ApiResult.success();
}

View File

@ -287,6 +287,7 @@ public class RatioDirectConfigController extends ControllerBase {
IPage<ProductModel> pdatas = productModelService.searchForQuotation(request);
pdatas.getRecords().forEach(model -> {
Map<String, Object> data = new HashMap<>();
data.put("modelId", model.getBatchNumber());
users.forEach(user -> {
data.put(user.getId() + "-standardPrice", getUserStandardPrice(model.getBatchNumber(), user, users, ratioDirects, prices, userPrices));
data.put(user.getId() + "-standardRatio", null);

View File

@ -93,8 +93,7 @@ public class AppRatioAgentConfigController extends ControllerBase {
*/
@PostMapping("config/search")
public ApiResult<PageData<Map<String, Object>>> search(@Valid @RequestBody ModelConfigSearchRequest request) {
QuotationModelRatioAgentItem mitem = ratioAgentItemService.getEffectiveForUser(AppUserUtil.getUserId());
VUtils.trueThrowBusinessError(Objects.isNull(mitem)).throwMessage("请联系管理员为你设置系数");
VUtils.trueThrowBusinessError(!ratioAgentItemService.hasConfig(AppUserUtil.getUserId())).throwMessage("请联系管理员为你设置系数");
QuotationModelRatioAgent ratioAgent = ratioAgentService.lambdaQuery()
.eq(QuotationModelRatioAgent::getStatus, 1)
.eq(QuotationModelRatioAgent::getCreateByType, 1)
@ -132,7 +131,10 @@ public class AppRatioAgentConfigController extends ControllerBase {
&& it.getUserId().equals(user.getId()))
.findFirst()
.orElse(null);
BigDecimal basePrice = Objects.nonNull(modelPrice) ? NumberUtil.multiply(modelPrice.getAmount(), mitem.getStandardRatio()) : null;
QuotationModelRatioAgentItem mitem = ratioAgentItemService.getEffectiveForUser(data.getBatchNumber(), AppUserUtil.getUserId());
BigDecimal basePrice = Objects.nonNull(modelPrice) ? NumberUtil.multiply(modelPrice.getAmount(), Optional.ofNullable(mitem)
.map(QuotationModelRatioAgentItem::getStandardRatio)
.orElse(null)) : null;
BigDecimal standardRatio = Objects.nonNull(item) ? item.getStandardRatio() : null;
map.put(user.getId().toString() + "-standardPrice", NumberUtil.format(basePrice));
map.put(user.getId().toString() + "-standardRatio", NumberUtil.format(standardRatio));
@ -241,8 +243,7 @@ public class AppRatioAgentConfigController extends ControllerBase {
*/
@PostMapping("list/search")
public ApiResult<PageData<RatioConfigSearchVO>> search(@Valid @RequestBody ModelRatioUserSearchRequest request) {
QuotationModelRatioAgentItem mitem = ratioAgentItemService.getEffectiveForUser(AppUserUtil.getUserId());
VUtils.trueThrowBusinessError(Objects.isNull(mitem)).throwMessage("请联系管理员为你设置系数");
VUtils.trueThrowBusinessError(!ratioAgentItemService.hasConfig(AppUserUtil.getUserId())).throwMessage("请联系管理员为你设置系数");
AppUser cuser = appUserService.getById(AppUserUtil.getUserId());
DictionaryItem category = appUserService.getCategory(cuser);
VUtils.trueThrowBusinessError(Objects.isNull(category)).throwMessage("请联系管理员为你设置区域类型");
@ -260,7 +261,12 @@ public class AppRatioAgentConfigController extends ControllerBase {
.filter(it -> it.getModelId().equals(data.getModelId()) && it.getAreaId().equals(category.getId()))
.findFirst()
.orElse(null);
BigDecimal basePrice = Objects.nonNull(modelPrice) ? NumberUtil.multiply(modelPrice.getAmount(), mitem.getStandardRatio()) : null;
QuotationModelRatioAgentItem mitem = ratioAgentItemService.getEffectiveForUser(data.getModelId(), AppUserUtil.getUserId());
BigDecimal basePrice = Objects.nonNull(modelPrice)
? NumberUtil.multiply(modelPrice.getAmount(), Optional.ofNullable(mitem)
.map(QuotationModelRatioAgentItem::getStandardRatio)
.orElse(null))
: null;
items.forEach(item -> {
RatioConfigSearchVO vou = new RatioConfigSearchVO()
.setName(item.getUserName())
@ -317,7 +323,12 @@ public class AppRatioAgentConfigController extends ControllerBase {
.filter(it -> it.getModelId().equals(entry.getKey()) && it.getAreaId().equals(category.getId()))
.findFirst()
.orElse(null);
BigDecimal basePrice = Objects.nonNull(modelPrice) ? NumberUtil.multiply(modelPrice.getAmount(), mitem.getStandardRatio()) : null;
QuotationModelRatioAgentItem mitem = ratioAgentItemService.getEffectiveForUser(entry.getKey(), AppUserUtil.getUserId());
BigDecimal basePrice = Objects.nonNull(modelPrice)
? NumberUtil.multiply(modelPrice.getAmount(), Optional.ofNullable(mitem)
.map(QuotationModelRatioAgentItem::getStandardRatio)
.orElse(null))
: null;
entry.getValue().forEach(item -> {
RatioConfigSearchVO vou = new RatioConfigSearchVO()
.setName(item.getUserName())

View File

@ -109,10 +109,7 @@ public class PlanController extends ControllerBase {
.eq(QuotationUserPlanModel::getCreateById, AppUserUtil.getUserId())
.one();
vo.setInfo(Convert.convert(QuotationModelRatioVO.class, plan));
if (Objects.isNull(plan)) {
return ApiResult.success(vo);
}
List<PlanSearchItemVO> items = planModelItemService.search(plan.getId(), request);
List<PlanSearchItemVO> items = planModelItemService.search(request, AppUserUtil.isAgent() ? 1 : 0, AppUserUtil.getUserId());
int index = 0, startIndex = (request.getPage() - 1) * request.getPageSize(), endIndex = request.getPage() * request.getPageSize();
PageData<PlanSearchItemVO> pageData = new PageData<>();
pageData.setPage(request.getPage());
@ -152,7 +149,7 @@ public class PlanController extends ControllerBase {
//代理商
if (AppUserUtil.isPrimary()) {
//主账号
QuotationModelRatioAgentItem pRatioAgentItem = ratioAgentItemService.getEffectiveForUser(AppUserUtil.getUserId());
QuotationModelRatioAgentItem pRatioAgentItem = ratioAgentItemService.getEffectiveForUser(modelId, AppUserUtil.getUserId());
BigDecimal price = prices.stream()
.filter(item -> item.getModelId().equals(modelId) && item.getAreaId().equals(categoryId))
.map(ModelPriceVO::getAmount)
@ -160,13 +157,13 @@ public class PlanController extends ControllerBase {
.orElse(null);
if (Objects.nonNull(pRatioAgentItem)) {
return NumberUtil.multiply(price, pRatioAgentItem.getStandardRatio());
}else {
} else {
return price;
}
} else {
//子账号
Integer parentUserId = appUserService.getPrimaryByChild(AppUserUtil.getUserId());
QuotationModelRatioAgentItem pRatioAgentItem = ratioAgentItemService.getEffectiveForUser(parentUserId);
QuotationModelRatioAgentItem pRatioAgentItem = ratioAgentItemService.getEffectiveForUser(modelId, parentUserId);
BigDecimal price = prices.stream()
.filter(item -> item.getModelId().equals(modelId) && item.getAreaId().equals(categoryId))
.map(ModelPriceVO::getAmount)
@ -175,7 +172,7 @@ public class PlanController extends ControllerBase {
if (Objects.nonNull(pRatioAgentItem)) {
price = NumberUtil.multiply(price, pRatioAgentItem.getStandardRatio());
}
QuotationModelRatioAgentItem cRatioAgentItem = ratioAgentItemService.getEffectiveForUser(AppUserUtil.getUserId());
QuotationModelRatioAgentItem cRatioAgentItem = ratioAgentItemService.getEffectiveForUser(modelId, AppUserUtil.getUserId());
if (Objects.nonNull(cRatioAgentItem)) {
price = NumberUtil.multiply(price, cRatioAgentItem.getStandardRatio());
}

View File

@ -378,6 +378,9 @@ public class ShoppingController extends ControllerBase {
request.setPage(page);
request.setPageSize(pageSize);
IPage<QuotationSearchVO> datas = shoppingOrderService.search(request);
if(CollectionUtil.isEmpty(datas.getRecords())){
return ApiResult.success(PageData.empty());
}
boolean isAgent = AppUserUtil.isAgent();
List<TBaseCustomer> customers;
if (isAgent) {
@ -525,19 +528,19 @@ public class ShoppingController extends ControllerBase {
//代理商
if (AppUserUtil.isPrimary()) {
//主账号
QuotationModelRatioAgentItem pRatioAgentItem = ratioAgentItemService.getEffectiveForUser(AppUserUtil.getUserId());
QuotationModelRatioAgentItem pRatioAgentItem = ratioAgentItemService.getEffectiveForUser(modelId,AppUserUtil.getUserId());
if (Objects.nonNull(pRatioAgentItem)) {
pair = Pair.of(pRatioAgentItem.getStandardRatio(), pRatioAgentItem.getOptionalRatio());
}
} else {
//子账号
Integer parentUserId = appUserService.getPrimaryByChild(AppUserUtil.getUserId());
QuotationModelRatioAgentItem pRatioAgentItem = ratioAgentItemService.getEffectiveForUser(parentUserId);
QuotationModelRatioAgentItem pRatioAgentItem = ratioAgentItemService.getEffectiveForUser(modelId,parentUserId);
if (Objects.nonNull(pRatioAgentItem)) {
pair = Pair.of(NumberUtil.multiply(pair.getLeft(), pRatioAgentItem.getStandardRatio())
, NumberUtil.multiply(pair.getRight(), pRatioAgentItem.getOptionalRatio()));
}
QuotationModelRatioAgentItem cRatioAgentItem = ratioAgentItemService.getEffectiveForUser(AppUserUtil.getUserId());
QuotationModelRatioAgentItem cRatioAgentItem = ratioAgentItemService.getEffectiveForUser(modelId,AppUserUtil.getUserId());
if (Objects.nonNull(cRatioAgentItem)) {
pair = Pair.of(NumberUtil.multiply(pair.getLeft(), cRatioAgentItem.getStandardRatio())
, NumberUtil.multiply(pair.getRight(), cRatioAgentItem.getOptionalRatio()));

View File

@ -30,5 +30,7 @@ public class DiscountForbidImportDTO {
*/
private String modelNo;
private List<DiscountForbidImportAreaDTO> areas=new ArrayList<>();
private List<Integer> targetIds = new ArrayList<>();
private List<DiscountForbidImportAreaDTO> areas = new ArrayList<>();
}

View File

@ -20,9 +20,11 @@ public interface QuotationModelRatioAgentItemMapper extends BaseMapper<Quotation
List<QuotationModelRatioAgentItemDTO> getEffectives();
QuotationModelRatioAgentItem getEffectiveForUser(Integer userId);
QuotationModelRatioAgentItem getEffectiveForUser(Long modelId,Integer userId);
List<SimpleUserVO> getAgentUsers(Integer userId);
List<QuotationModelRatioAgentItemDTO> getEffectiveByCreate(Integer userId);
boolean hasConfig(Integer userId);
}

View File

@ -20,7 +20,7 @@ public interface QuotationUserPlanModelItemMapper extends BaseMapper<QuotationUs
List<QuotationUserPlanModelItemDTO> getEffectivesForAgent();
List<PlanSearchItemVO> search(Long id, ModelConfigSearchRequest request);
List<PlanSearchItemVO> search(ModelConfigSearchRequest request,Integer userType, Integer userId);
QuotationUserPlanModelItem getEffectiveForUser(Long modelId,Integer userType, Integer userId);
}

View File

@ -20,9 +20,11 @@ public interface IQuotationModelRatioAgentItemService extends IService<Quotation
List<QuotationModelRatioAgentItemDTO> getEffectives();
QuotationModelRatioAgentItem getEffectiveForUser(Integer userId);
QuotationModelRatioAgentItem getEffectiveForUser(Long modelId,Integer userId);
List<SimpleUserVO> getAgentUsers(Integer userId);
List<QuotationModelRatioAgentItemDTO> getEffectiveByCreate(Integer userId);
boolean hasConfig(Integer userId);
}

View File

@ -21,7 +21,7 @@ public interface IQuotationUserPlanModelItemService extends IService<QuotationUs
List<QuotationUserPlanModelItemDTO> getEffectivesForAgent();
List<PlanSearchItemVO> search(Long id,ModelConfigSearchRequest request);
List<PlanSearchItemVO> search(ModelConfigSearchRequest request,Integer userType, Integer userId);
QuotationUserPlanModelItem getEffectiveForUser(Long modelId,Integer userType, Integer userId);
}

View File

@ -28,8 +28,8 @@ public class QuotationModelRatioAgentItemServiceImpl extends ServiceImpl<Quotati
}
@Override
public QuotationModelRatioAgentItem getEffectiveForUser(Integer userId) {
return baseMapper.getEffectiveForUser(userId);
public QuotationModelRatioAgentItem getEffectiveForUser(Long modelId,Integer userId) {
return baseMapper.getEffectiveForUser(modelId,userId);
}
@Override
@ -41,4 +41,9 @@ public class QuotationModelRatioAgentItemServiceImpl extends ServiceImpl<Quotati
public List<QuotationModelRatioAgentItemDTO> getEffectiveByCreate(Integer userId) {
return baseMapper.getEffectiveByCreate(userId);
}
@Override
public boolean hasConfig(Integer userId) {
return baseMapper.hasConfig(userId);
}
}

View File

@ -28,8 +28,8 @@ public class QuotationUserPlanModelItemServiceImpl extends ServiceImpl<Quotation
}
@Override
public List<PlanSearchItemVO> search(Long id, ModelConfigSearchRequest request) {
return baseMapper.search(id, request);
public List<PlanSearchItemVO> search(ModelConfigSearchRequest request,Integer userType, Integer userId) {
return baseMapper.search(request,userType, userId);
}
@Override

View File

@ -13,7 +13,7 @@
SELECT qmtai.*
FROM quotation_model_ratio_agent qmta
INNER JOIN quotation_model_ratio_agent_item qmtai ON qmtai.ratio_id=qmta.id
WHERE qmta.`status`=1 AND qmtai.user_id=#{userId}
WHERE qmta.`status`=1 and qmtai.model_id=#{modelId} AND qmtai.user_id=#{userId}
</select>
<select id="getAgentUsers" resultType="com.nflg.mobilebroken.common.pojo.vo.SimpleUserVO">
@ -33,4 +33,10 @@
INNER JOIN app_user au ON qmrai.user_id=au.id
WHERE qmra.`status`=1 AND qmrai.is_primary=0 AND qmra.create_by_type=1 AND qmra.create_by_id=#{userId}
</select>
<select id="hasConfig" resultType="boolean">
SELECT EXISTS(SELECT 1 FROM quotation_model_ratio_agent qmra
INNER JOIN quotation_model_ratio_agent_item qmrai ON qmra.id=qmrai.ratio_id
WHERE qmra.`status`=1 AND qmrai.user_id=#{userId})
</select>
</mapper>

View File

@ -24,7 +24,7 @@
</select>
<select id="searchFromAdmin" resultType="com.nflg.mobilebroken.common.pojo.vo.QuotationSearchVO">
SELECT qso.*
SELECT qso.*,if(qso.create_by_type=0,au.user_name,bc.agency_company_name) as target_name
FROM quotation_shopping_order qso
INNER JOIN
(
@ -62,6 +62,8 @@
</if>
</where>
) AS t ON t.id=qso.id
left join t_base_customer bc on qso.target_id=bc.id
left join admin_user au on qso.target_id=au.id
<where>
<if test="request.targetId!=null">
AND qso.target_id=#{request.targetId}

View File

@ -12,7 +12,8 @@
<select id="search" resultType="com.nflg.mobilebroken.common.pojo.vo.PlanSearchItemVO">
SELECT qupmi.id,qupmi.plan_id,pm.batch_number as 'modelId',pm.`no` as 'modelNo',qupmi.`name`,qupmi.ratio,qupmi.is_default
FROM product_model pm
LEFT JOIN quotation_user_plan_model_item qupmi ON qupmi.model_id=pm.batch_number AND qupmi.plan_id=#{id}
LEFT JOIN quotation_user_plan_model_item qupmi ON qupmi.model_id=pm.batch_number
left join quotation_user_plan_model qupm on qupmi.plan_id=qupm.id and qupm.`status`=1 and qupm.create_by_type=#{userType} and qupm.create_by_id=#{userId}
WHERE pm.state=1
<if test="request.no!=null and request.no!=''">
and pm.no like CONCAT('%', #{request.no}, '%')