Commit e7a0e032 by HlQ

[add]

1.添加集团管理相关接口
2.添加同步新CRM平台合同的接口以及创建合同的接口
3.添加文件下载的接口(通过流返回文件)
1 parent b9276b67
......@@ -15,6 +15,7 @@ import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.http.server.servlet.JakartaServletUtil;
import org.slf4j.MDC;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
......@@ -41,7 +42,7 @@ public class LogAspect {
// 登录等接口,无需登录可访问,根据 token 获取当前用户会抛未登录的异常,需捕获进行处理
var username = Opt.ofTry(() -> (UserVO) StpUtil.getTokenSession().get("curLoginUser"))
.map(UserVO::getUsername)
.orElse("未知");
.orElse("Unknown");
var attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (ObjUtil.isNull(attributes)) {
......@@ -73,6 +74,10 @@ public class LogAspect {
var startTime = (Long) request.getAttribute("startTime");
var responseTime = System.currentTimeMillis() - startTime;
if (result instanceof ResponseEntity) {
log.info("Response time: {} ms. File download completed.", responseTime);
return;
}
var resStr = objectMapper.writeValueAsString(result);
if (resStr.length() > 1000) {
resStr = resStr.substring(0, 1000);
......
......@@ -2,10 +2,12 @@ package vion.advice;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.hutool.core.util.ObjUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
......@@ -34,7 +36,7 @@ public class ResBodyAdvice implements ResponseBodyAdvice<Object> {
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof ResultVO || body instanceof ModelAndView) {
if (ObjUtil.isNull(body) || body instanceof ResultVO || body instanceof ModelAndView || body instanceof Resource) {
return body;
}
......
......@@ -53,7 +53,8 @@ public enum RedisKeyEnum {
/**
* 合同同步时间
*/
CONTRACT_SYNC_TIME("contract:sync:time");
CONTRACT_SYNC_TIME("contract:sync:time"),
CONTRACT_SYNC_NEW_TIME("contract:sync:new:time");
private final String val;
......
package vion.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import vion.dto.BaseDTO;
import vion.model.Account;
import vion.service.IAccountService;
/**
* 集团管理
*/
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
@Slf4j
public class AccountController {
private final IAccountService accountService;
@GetMapping("/accounts")
@GetMapping("/account")
@SaCheckPermission(value = "account:list", orRole = "admin")
public Page<Account> getAccountList(BaseDTO dto) {
return accountService.page(Page.of(dto.getPageNum(), dto.getPageSize()));
public Page<Account> getAccountList(Account dto) {
return accountService.page(Page.of(dto.getPageNum(), dto.getPageSize()),
Wrappers.lambdaQuery(dto).orderByDesc(Account::getModifyTime));
}
@GetMapping("/account")
@GetMapping("/onlyAccount")
@SaCheckPermission(value = "account:listAccount", orRole = "admin")
public Page<Account> getAccountNameList(Account dto) {
return accountService.lambdaQuery(dto)
.select(Account::getId, Account::getName)
.orderByDesc(Account::getModifyTime)
.page(Page.of(dto.getPageNum(),
dto.getPageSize()));
}
@GetMapping("/account/{id}")
@SaCheckPermission(value = "account:query", orRole = "admin")
public Account getAccountById(Integer id) {
public Account getAccountById(@PathVariable Long id) {
return accountService.getById(id);
}
@PostMapping("/accounts")
@PostMapping("/account")
@SaCheckPermission(value = "account:editAndSave", orRole = "admin")
public Account saveOrUpdate(@RequestBody Account data) {
accountService.save(data);
accountService.saveOrUpdate(data);
return data;
}
@DeleteMapping("/account/{id}")
@SaCheckPermission(value = "account:remove", orRole = "admin")
public String remove(@PathVariable(name = "id") Integer id) {
// todo 删除时,得判断集团下是否关联其他东西
accountService.removeById(id);
return "集团删除成功";
}
}
......@@ -11,6 +11,7 @@ import lombok.RequiredArgsConstructor;
import org.apache.poi.ss.usermodel.Workbook;
import org.dromara.hutool.core.date.DateUtil;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.text.CharSequenceUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.json.JSONObject;
......@@ -19,6 +20,7 @@ import vion.cron.ContractRunner;
import vion.dto.ContractDTO;
import vion.dto.RContractStoreDTO;
import vion.dto.RContractTeamDTO;
import vion.model.RContractProduct;
import vion.model.RContractStore;
import vion.model.RContractUser;
import vion.service.IContractService;
......@@ -74,6 +76,7 @@ public class ContractController {
public String updateById(@PathVariable Long id, ContractDTO dto) {
return contractService.updateById(id, null, dto);
}
@PostMapping("/contract/store")
@SaCheckPermission(value = "contract:store:save", orRole = "admin")
public String bindStore(@RequestBody RContractStoreDTO dto) {
......@@ -148,6 +151,35 @@ public class ContractController {
return "成功";
}
@PostMapping("/contractSync1")
@SaCheckPermission(value = "contract:sync1", orRole = "admin")
public String manualSyncContract1() {
contractRunner.contractSync1();
return "成功";
}
@PostMapping("/contract/createCRMContract")
@SaCheckPermission(value = "contract:createCRM", orRole = "admin")
public String createCRMContract(@RequestBody String contractJson) {
return contractService.createContract(CharSequenceUtil.removeAll(contractJson, '\r', '\n', ' '));
}
@GetMapping("/contract/getCRMProduct")
@SaCheckPermission(value = "contract:CRMProduct", orRole = "admin")
public JSONObject getCRMProduct(@RequestParam String name,
@RequestParam String code,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "20") Integer pageSize) {
return contractService.getCRMProduct(name, code, page, pageSize);
}
@GetMapping("/contract/product")
@SaCheckPermission(value = "contract:product", orRole = "admin")
public List<RContractProduct> getProduct(@RequestParam String contractNo) {
return contractService.getProduct(contractNo);
}
@GetMapping("/contract/export")
@SaCheckPermission(value = "contract:export", orRole = "admin")
public void pointExport(ContractDTO dto, HttpServletResponse response) {
......
package vion.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.net.URLEncodeUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
......@@ -12,6 +14,10 @@ import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.crypto.SecureUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import vion.dto.FileInfoDTO;
......@@ -20,6 +26,7 @@ import vion.service.IFileService;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
@RestController
......@@ -35,6 +42,7 @@ public class FileController {
private String fileUrl;
@GetMapping("/files")
@SaCheckPermission(value = "file:list", orRole = "admin")
public Page<FileInfo> getFiles(FileInfoDTO data) {
return fileService.lambdaQuery(converter.convert(data, new FileInfo()))
.eq(ObjUtil.isNotNull(data.getStoreId()), FileInfo::getStoreId, data.getStoreId())
......@@ -46,7 +54,29 @@ public class FileController {
.page(Page.of(data.getPageNum(), data.getPageSize()));
}
@GetMapping("/file/download")
@SaCheckPermission(value = "file:download", orRole = "admin")
public ResponseEntity<FileSystemResource> download(Long id) {
var fileInfo = fileService.getById(id);
var file = FileUtil.file(fileInfo.getUrl());
if (!FileUtil.exists(file)) {
return ResponseEntity.notFound().build();
}
FileSystemResource resource = new FileSystemResource(file);
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + URLEncodeUtil.encode(file.getName(), StandardCharsets.UTF_8).replace("+", "%20"));
return ResponseEntity.ok()
.headers(headers)
.contentLength(file.length())
.body(resource);
}
@DeleteMapping("/file/{id}")
@SaCheckPermission(value = "file:remove", orRole = "admin")
public String remove(@PathVariable(name = "id") Integer id) {
FileInfo file = fileService.getById(id);
FileUtil.del(file.getUrl());
......@@ -55,6 +85,7 @@ public class FileController {
}
@PostMapping("/file/formFileUpload")
@SaCheckPermission(value = "file:form:upload", orRole = "admin")
public String uploadFile(FileInfo fileInfo, @RequestParam(name = "file") MultipartFile infile) throws IOException {
String orgName = infile.getOriginalFilename();
String mainName = FileNameUtil.mainName(orgName);
......@@ -92,6 +123,7 @@ public class FileController {
}
@PostMapping("/file/uploadFile")
@SaCheckPermission(value = "file:upload", orRole = "admin")
public String uploadFile1(FileInfo fileInfo, @RequestParam(name = "files") MultipartFile[] files) throws IOException {
for (MultipartFile infile : files) {
String orgName = infile.getOriginalFilename();
......
......@@ -156,7 +156,6 @@ public class StoreController {
@PostMapping("/store/tag/{id}")
@SaCheckPermission(value = "store:tag", orRole = "admin")
// 权限未加
public String addTag(@PathVariable Long id, @RequestBody List<Long> tagIdList) {
return storeService.addTag(id, tagIdList);
}
......
......@@ -31,7 +31,7 @@ public class ContractDTO extends BaseDTO {
private Integer type;
/**
* 合同进度:1-签订 2-到货 3-系统验收(初验) 4-项目验收(终验) 5-质保 6-第一笔维保款 7-第二笔维保款 8-第三笔维保款
* 合同进度:1-签订 2-到货 3-系统验收(初验) 4-项目验收(终验) 5-质保 6-第一笔维保款 7-第二笔维保款 8-第三笔维保款 9-维保进度款 10-维保验收款
*/
private Integer status;
......
......@@ -58,6 +58,11 @@ public class SparePartDTO extends BaseDTO {
private Integer deviceNum;
/**
* 设备名称
*/
private String deviceName;
/**
* 收货地址
*/
private String shippingAddress;
......
......@@ -70,6 +70,20 @@ public class StoreDTO extends BaseDTO {
private Date planFinishDate;
/** 项目规模 */
private Integer projectSize;
/**
* 巡检次数
*/
private Integer inspectCount;
/**
* 巡检要求
*/
private String inspectRemark;
/**
* 施工数量
*/
private Integer constructionCount;
private Long sourceId;
private Long targetId;
......
......@@ -32,4 +32,6 @@ public class UserDTO extends BaseDTO {
/* 状态 0:正常 1:禁用 */
private Integer status;
private Long roleId;
}
\ No newline at end of file
package vion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import vion.model.RContractProduct;
/**
* @author HlQ
* @date 2024/3/26
*/
public interface RContractProductMapper extends BaseMapper<RContractProduct> {
}
\ No newline at end of file
......@@ -3,29 +3,41 @@ package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import vion.dto.BaseDTO;
import java.util.Date;
@Data
@TableName(value="tbl_account_info")
public class Account {
/** 自增列 */
@TableName(value = "tbl_account_info")
public class Account extends BaseDTO {
/**
* 自增列
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/** 名称 */
/**
* 名称
*/
@TableField(condition = SqlCondition.LIKE)
private String name;
/** 创建时间 */
/**
* 创建时间
*/
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/** 修改时间 */
/**
* 修改时间
*/
@TableField(value = "modify_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
/** 备注 */
/**
* 备注
*/
private String remark;
}
......@@ -260,14 +260,38 @@ public class Contract {
private Date maintainDate2;
/**
* 合同维保付款比例2
* 合同维保付款比例3
*/
@TableField(exist = false)
private BigDecimal maintainRatio3;
/**
* 合同维保付款日期2
* 合同维保付款日期3
*/
@TableField(exist = false)
private Date maintainDate3;
/**
* 维保进度款
*/
@TableField(exist = false)
private BigDecimal maintainProgressRatio;
/**
* 维保进度款付款日期
*/
@TableField(exist = false)
private Date maintainProgressDate;
/**
* 维保验收款
*/
@TableField(exist = false)
private BigDecimal maintainAcceptanceRatio;
/**
* 维保验收款付款日期
*/
@TableField(exist = false)
private Date maintainAcceptanceDate;
}
\ No newline at end of file
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* @author HlQ
* @date 2024/3/26
*/
@Data
@TableName(value = "r_contract_product")
public class RContractProduct {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 合同编号
*/
@TableField(value = "contract_no")
private String contractNo;
/**
* 产品名称
*/
@TableField(value = "product_name")
private String productName;
/**
* 产品编码
*/
@TableField(value = "product_code")
private String productCode;
/**
* 产品模型
*/
@TableField(value = "product_model")
private String productModel;
/**
* 数量
*/
@TableField(value = "num")
private Integer num;
/**
* 含税单价
*/
@TableField(value = "tax_price")
private BigDecimal taxPrice;
/**
* 税率
*/
@TableField(value = "tax_rate")
private BigDecimal taxRate;
/**
* 无税单价
*/
@TableField(value = "no_tax_price")
private BigDecimal noTaxPrice;
/**
* 折扣率
*/
@TableField(value = "discount_rate")
private BigDecimal discountRate;
/**
* 实际单价
*/
@TableField(value = "actual_price")
private BigDecimal actualPrice;
/**
* 抹零
*/
@TableField(value = "erase")
private BigDecimal erase;
/**
* 价税合计
*/
@TableField(value = "total_price")
private BigDecimal totalPrice;
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}
\ No newline at end of file
......@@ -72,6 +72,12 @@ public class SparePart {
private Integer deviceNum;
/**
* 设备名称
*/
@TableField(value = "device_name")
private String deviceName;
/**
* 收货地址
*/
@TableField(value = "shipping_address")
......
......@@ -14,7 +14,7 @@ import java.util.Date;
* 门店信息
*/
@Data
@TableName(value="tbl_store_info")
@TableName(value = "tbl_store_info")
@AutoMappers({
@AutoMapper(target = StoreVO.class),
@AutoMapper(target = StoreDTO.class),
......@@ -22,74 +22,137 @@ import java.util.Date;
public class Store {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/** 门店名称 */
/**
* 门店名称
*/
@TableField(condition = SqlCondition.LIKE)
private String name;
/** 销售人 */
/**
* 销售人
*/
private Integer salesperson;
/** 客户姓名 */
/**
* 客户姓名
*/
private String customerName;
/** 实施类型:0纯供货、1供货+安装、3续保、4维修 */
/**
* 实施类型:0纯供货、1供货+安装、3续保、4维修
*/
private Integer implementType;
/** 项目状态:0待确认、1进行中、2已完成、3挂起 */
/**
* 项目状态:0待确认、1进行中、2已完成、3挂起
*/
private Integer projectState;
/** 创建者 */
/**
* 创建者
*/
private Long createUser;
/** 修改者 */
/**
* 修改者
*/
private Long modifyUser;
/** 创建时间 */
/**
* 创建时间
*/
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@OrderBy
private Date createTime;
/** 修改时间 */
/**
* 修改时间
*/
@TableField(value = "modify_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
/** 备注 */
/**
* 备注
*/
private String remark;
/** 项目阶段 */
/**
* 项目阶段
*/
private Integer projectStage;
/** 集团id */
/**
* 集团id
*/
private Long accountId;
/** 主合同id */
/**
* 主合同id
*/
private Long masterContract;
/** 维保状态 */
/**
* 维保状态
*/
private String maintainStatus;
/** 产品线属性 */
/**
* 产品线属性
*/
private Integer productLine;
/** 是否重点项目 0:不是 1:是 */
/**
* 是否重点项目 0:不是 1:是
*/
private Integer isImportant;
/** 任务详情 */
/**
* 任务详情
*/
private String taskDetail;
/** 实际完成日期 */
/**
* 实际完成日期
*/
private Date finishDate;
/** 完成百分比 */
/**
* 完成百分比
*/
private Double percentage;
/** 当前卡点 */
/**
* 当前卡点
*/
private String stuckPoint;
/** 主要产品 */
/**
* 主要产品
*/
private Integer mainProduct;
/** 点位数量 */
/**
* 点位数量
*/
private Integer pointNum;
/** 计划完成日期 */
/**
* 计划完成日期
*/
private Date planFinishDate;
/** 项目规模 */
/**
* 项目规模
*/
private Integer projectSize;
/**
* 巡检次数
*/
private Integer inspectCount;
/**
* 巡检要求
*/
private String inspectRemark;
/**
* 施工数量
*/
private Integer constructionCount;
}
package vion.service;
import org.dromara.hutool.json.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseService;
import org.dromara.hutool.json.JSONObject;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import vion.dto.ContractDTO;
import vion.dto.RContractTeamDTO;
import vion.model.Contract;
import vion.model.RContractProduct;
import vion.model.RContractUser;
import vion.vo.ContractVO;
import java.util.List;
import java.util.Map;
/**
* @author HlQ
* @date 2023/11/29
*/
public interface IContractService extends MPJBaseService<Contract>{
public interface IContractService extends MPJBaseService<Contract> {
Page<ContractVO> list(ContractDTO dto);
......@@ -41,4 +43,10 @@ public interface IContractService extends MPJBaseService<Contract>{
String unbindSale(RContractUser contractUser);
List<RContractProduct> getProduct(String contractNo);
String createContract(String contractJson);
JSONObject getCRMProduct(String name, String code, Integer page, Integer pageSize);
}
\ No newline at end of file
package vion.service;
import vion.model.RContractProduct;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author HlQ
* @date 2024/3/26
*/
public interface IRContractProductService extends IService<RContractProduct>{
}
......@@ -11,6 +11,7 @@ import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.bean.BeanUtil;
import org.dromara.hutool.core.collection.CollUtil;
......@@ -26,6 +27,8 @@ import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.crypto.SecureUtil;
import org.dromara.hutool.http.client.Request;
import org.dromara.hutool.http.meta.Method;
import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.JSONUtil;
import org.springframework.beans.factory.annotation.Value;
......@@ -53,6 +56,7 @@ import java.util.stream.Collectors;
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Contract> implements IContractService {
private final IFileService fileService;
......@@ -61,6 +65,7 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
private final IContractLogService contractLogService;
private final IRContractTeamService contractTeamService;
private final IRContractUserService contractUserService;
private final IRContractProductService contractProductService;
// 引入 settlementDiffService 会循环依赖
private final SettlementDiffMapper settlementDiffMapper;
private final DingMod dingMod;
......@@ -68,6 +73,8 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
@Value("${fileUrl:}")
private String fileUrl;
@Value("${xbongbong.token}")
private String token;
@Override
public Page<ContractVO> list(ContractDTO dto) {
......@@ -78,13 +85,20 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
.ifPresent(page::addOrder);
Page<ContractVO> contractVOList = this.selectJoinListPage(page, ContractVO.class, result.wrapper);
Opt.ofEmptyAble(settlementDiffMapper.selectList(Wrappers.<SettlementDiff>lambdaQuery()
.in(CollUtil.isNotEmpty(contractVOList.getRecords()), SettlementDiff::getContractId, contractVOList.getRecords().stream().map(ContractVO::getId).collect(Collectors.toList()))))
var idList = Opt.ofEmptyAble(contractVOList.getRecords())
.map(r -> r.stream().map(ContractVO::getId).collect(Collectors.toList()))
.orElse(ListUtil.empty());
// 结算差异
Opt.ofEmptyAble(idList)
.map(l -> settlementDiffMapper.selectList(Wrappers.<SettlementDiff>lambdaQuery()
.in(SettlementDiff::getContractId, l)))
.map(list -> list.stream().collect(Collectors.groupingBy(SettlementDiff::getContractId, Collectors.reducing(BigDecimal.ZERO, SettlementDiff::getSettlementDiff, BigDecimal::add))))
.ifPresent(map -> contractVOList.getRecords().forEach(vo -> vo.setDiffAmount(map.getOrDefault(vo.getId(), BigDecimal.ZERO))));
Opt.ofEmptyAble(contractUserService.lambdaQuery()
.in(CollUtil.isNotEmpty(contractVOList.getRecords()), RContractUser::getContractId, contractVOList.getRecords().stream().map(ContractVO::getId).collect(Collectors.toList()))
// 合同绑定销售
Opt.ofEmptyAble(idList)
.map(l -> contractUserService.lambdaQuery()
.in(RContractUser::getContractId, l)
.list())
.map(list -> list.stream().collect(Collectors.groupingBy(RContractUser::getContractId)))
.ifPresent(map -> contractVOList.getRecords().forEach(vo -> map.getOrDefault(vo.getId(), ListUtil.empty()).stream()
......@@ -167,6 +181,11 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
contractVO.setOutstandingAmount(null);
contractVO.setInvoiceAmount(null);
}
// 合同关联产品
var contractProducts = contractProductService.lambdaQuery()
.eq(RContractProduct::getContractNo, contractVO.getContractNo())
.list();
contractVO.setContractProducts(contractProducts);
return contractVO;
}
......@@ -242,6 +261,10 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
contractLog.setContent("合同:第二笔维保款");
} else if (status == 8) {
contractLog.setContent("合同:第三笔维保款");
} else if (status == 9) {
contractLog.setContent("合同:维保进度款");
} else if (status == 10) {
contractLog.setContent("合同:维保验收款");
}
contractLog.setOperator(userVO.getId());
contractLogService.save(contractLog);
......@@ -414,6 +437,64 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
return contractUserService.remove(Wrappers.<RContractUser>lambdaQuery().eq(RContractUser::getContractId, contractUser.getContractId()).eq(RContractUser::getUserId, contractUser.getUserId())) ? "解绑成功" : "解绑失败";
}
@Override
public List<RContractProduct> getProduct(String contractNo) {
return contractProductService.lambdaQuery().eq(RContractProduct::getContractNo, contractNo).list();
}
@Override
public String createContract(String contractJson) {
var sha256 = SecureUtil.sha256(contractJson + token);
var res = Request.of("https://proapi.xbongbong.com/pro/v2/api/contract/list")
.header("sign", sha256)
.body(contractJson)
.method(Method.POST)
.send();
var body = res.bodyStr();
var jobj = JSONUtil.parseObj(body);
if (jobj.getInt("code") != 1) {
log.error("调用CRM接口创建合同失败,错误原因:{}", body);
return "创建合同失败";
}
return "合同创建成功";
}
@Override
public JSONObject getCRMProduct(String name, String code, Integer page, Integer pageSize) {
var conditions = JSONUtil.ofArray().put(JSONUtil.ofObj()
.set("attr", "num_3")
.set("symbol", "noequal")
.set("value", new int[]{0}));
if (StrUtil.isNotBlank(name)) {
conditions.put(JSONUtil.ofObj().set("attr", "text_1").set("symbol", "like").set("value", new String[]{name}));
}
if (StrUtil.isNotBlank(code)) {
conditions.put(JSONUtil.ofObj().set("attr", "serialNo").set("symbol", "like").set("value", new String[]{code}));
}
var json = JSONUtil.ofObj()
.set("corpid", "ding6bb660048f7ae2dcee0f45d8e4f7c288")
.set("page", page)
.set("pageSize", pageSize)
.set("conditions", conditions);
var res = Request.of("https://proapi.xbongbong.com/pro/v2/api/product/list")
.header("sign", SecureUtil.sha256(json.toString() + token))
.body(json.toString())
.method(Method.POST)
.send();
var body = res.bodyStr();
var jobj = JSONUtil.parseObj(body);
if (jobj.getInt("code") != 1) {
log.error("调用CRM接口获取产品列表失败,错误原因:{}", body);
return JSONUtil.ofObj();
}
return JSONUtil.ofObj().set("records", jobj.getJSONObject("result").getJSONArray("list"))
.set("current", page)
.set("size", pageSize)
.set("total", jobj.getJSONObject("result").getInt("totalCount"))
.set("pages", jobj.getJSONObject("result").getInt("totalPage"));
}
private Result getResult(ContractDTO dto) {
// 查询已关联项目的合同id
List<Long> contractIdList = dto.getSwitchFlag() == 1 ?
......
......@@ -48,7 +48,6 @@ public class DeliveryRecordServiceImpl extends MPJBaseServiceImpl<DeliveryRecord
private final IFileService fileService;
private final IContractService contractService;
private final IRContractUserService contractUserService;
private final IContractPaymentService contractPaymentService;
private final IPointInfoService pointInfoService;
private final DingMod dingMod;
private final Converter converter;
......
package vion.service.impl;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import vion.model.RContractProduct;
import vion.mapper.RContractProductMapper;
import vion.service.IRContractProductService;
/**
* @author HlQ
* @date 2024/3/26
*/
@Service
public class RContractProductServiceImpl extends ServiceImpl<RContractProductMapper, RContractProduct> implements IRContractProductService {
}
......@@ -55,6 +55,7 @@ public class StoreServiceImpl extends MPJBaseServiceImpl<StoreMapper, Store> imp
private final ITagService tagService;
private final IRStoreTagService storeTagService;
private final IRStoreUserService storeUserService;
private final IStoreLogService storeLogService;
private final Converter converter;
// 引入 taskService 会循环依赖
private final TaskMapper taskMapper;
......@@ -140,6 +141,12 @@ public class StoreServiceImpl extends MPJBaseServiceImpl<StoreMapper, Store> imp
.map(serviceOrderList -> serviceOrderList.stream().collect(Collectors.groupingBy(ServiceOrder::getTaskId)))
.orElse(MapUtil.empty());
// storeId -> storeLog
var store2LogMap = Opt.ofEmptyAble(storeIdList)
.map(l -> storeLogService.lambdaQuery().in(StoreLog::getStoreId, l).list())
.map(storeLogList -> storeLogList.stream().collect(Collectors.groupingBy(StoreLog::getStoreId)))
.orElse(MapUtil.empty());
// storeId -> tagList
var storeId2TagMap = Opt.ofEmptyAble(storeIdList)
.map(l -> {
......@@ -186,6 +193,7 @@ public class StoreServiceImpl extends MPJBaseServiceImpl<StoreMapper, Store> imp
storeVO.setMainContract(Opt.ofNullable(masterContract).map(c -> converter.convert(c, ContractVO.class)).orElse(null));
storeVO.setTaskCount(store2TaskIdMap.getOrDefault(storeId, ListUtil.empty()).size());
storeVO.setLogCount(store2LogMap.getOrDefault(storeId, ListUtil.empty()).size());
// 补充服务单
if (store2TaskIdMap.containsKey(item.getId())) {
......@@ -385,6 +393,7 @@ public class StoreServiceImpl extends MPJBaseServiceImpl<StoreMapper, Store> imp
var fileMap = storeId2FileMap.getOrDefault(storeId, MapUtil.empty());
Map<String, Number> map = new HashMap<>();
map.put("storeId", storeId);
map.put("1", fileMap.getOrDefault(1, List.of()).size());
map.put("24", fileMap.getOrDefault(24, List.of()).size());
map.put("25", fileMap.getOrDefault(25, List.of()).size());
map.put("26", fileMap.getOrDefault(26, List.of()).size());
......
package vion.service.impl;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.tree.MapTree;
......@@ -18,6 +20,7 @@ import vion.model.RUserRole;
import vion.model.Role;
import vion.model.User;
import vion.service.IDeptService;
import vion.service.IRUserRoleService;
import vion.service.IRoleService;
import vion.service.IUserService;
import vion.vo.RoleVO;
......@@ -26,6 +29,7 @@ import vion.vo.UserVO;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Service
......@@ -34,15 +38,23 @@ public class UserServiceImpl extends MPJBaseServiceImpl<UserMapper, User> implem
private final IDeptService deptService;
private final IRoleService roleService;
private final IRUserRoleService userRoleService;
private final Converter converter;
@Override
public Page<UserVO> getUserList(UserDTO dto) {
var userIdSet = Opt.ofNullable(dto.getRoleId())
.map(roleId -> userRoleService.lambdaQuery().eq(RUserRole::getRoleId, roleId).list())
.filter(CollUtil::isNotEmpty)
.map(l -> l.stream().map(RUserRole::getUserId).collect(Collectors.toSet()))
.orElse(Set.of(-1L));
var wrapper = new MPJLambdaWrapper<>(converter.convert(dto, User.class))
.selectAll(User.class)
.select(Dept::getDeptName)
.leftJoin(Dept.class, Dept::getDeptId, User::getDeptId)
.ne(User::getStatus, 5)
.in(ObjUtil.isNotNull(dto.getRoleId()), User::getId, userIdSet)
.orderByAsc(User::getStatus);
var userVOS = this.selectJoinListPage(Page.of(dto.getPageNum(), dto.getPageSize()), UserVO.class, wrapper);
var roleWrapper = new MPJLambdaWrapper<Role>()
......
......@@ -32,8 +32,8 @@ import vion.vo.RoleVO;
import vion.vo.UserVO;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
......@@ -235,9 +235,12 @@ public class DingMod {
return useridObj;
}
String userid = useridObj.getJSONObject("result").getStr("userid");
User user = userService.lambdaQuery().select(User::getId, User::getUserid, User::getUsername, User::getPhone, User::getStatus).eq(User::getUserid, userid).one();
User user = userService.lambdaQuery()
.select(User::getId, User::getUserid, User::getUsername, User::getPhone, User::getStatus, User::getEmployeeStatus)
.eq(User::getUserid, userid).one();
UserVO userVO = converter.convert(user, UserVO.class);
if (userVO.getStatus() == 1) {
// 禁用用户或离职用户禁止登录系统
if (userVO.getStatus() == 1 || userVO.getEmployeeStatus() == 5) {
return "该用户禁止登录系统,请联系管理员!";
}
Long id = userVO.getId();
......@@ -322,20 +325,15 @@ public class DingMod {
* 构建获取用户信息url
*/
String buildSignUrl() {
try {
String appSecret = "Ul5UTZqIost_kEAdfZXidvLoZhzvraYurm_g7PCHg-IrDMLHT7mdSgRS1iCHrDPt";
String timestamp = String.valueOf(System.currentTimeMillis());
HMac hMac = SecureUtil.hmacSha256(appSecret);
byte[] signBytes = hMac.digest(timestamp);
String sign = Base64.encode(signBytes);
String encode = URLEncoder.encode(sign, "UTF-8");
String encode = URLEncoder.encode(sign, StandardCharsets.UTF_8);
String encodeSign = encode.replace("+", "%20").replace("*", "%2A").replace("~", "%7E").replace("/", "%2F").replace("=", "%3D");
return StrUtil.format("https://oapi.dingtalk.com/sns/getuserinfo_bycode?accessKey=dingkrzwks0jpi2di3uo&timestamp={}&signature={}", timestamp, encodeSign);
} catch (UnsupportedEncodingException e) {
log.error("通过appSecret计算出来的签名值失败", e);
}
return "";
}
public String robotPush(String access_token, String body) {
......
......@@ -6,6 +6,7 @@ import com.github.liaochong.myexcel.core.annotation.ExcelModel;
import lombok.Getter;
import lombok.Setter;
import vion.model.ContractLog;
import vion.model.RContractProduct;
import java.math.BigDecimal;
import java.util.Date;
......@@ -171,4 +172,6 @@ public class ContractVO {
private List<StoreVO> storeVOS;
private List<ContractLog> contractLogs;
private List<RContractProduct> contractProducts;
}
\ No newline at end of file
......@@ -72,6 +72,11 @@ public class SparePartVO {
private Integer deviceNum;
/**
* 设备名称
*/
private String deviceName;
/**
* 收货地址
*/
private String shippingAddress;
......
......@@ -143,4 +143,24 @@ public class StoreVO {
* 项目负责人 or 项目经理
*/
private Long mainUser;
/**
* 巡检次数
*/
private Integer inspectCount;
/**
* 巡检要求
*/
private String inspectRemark;
/**
* 施工数量
*/
private Integer constructionCount;
/**
* 工单日志数量
*/
private Integer logCount;
}
debug=false
server.port=8011
################################## DATABASE ########################################
spring.datasource.url=jdbc:postgresql://pgm-2ze3cjpyjgjw0bl5uo.pg.rds.aliyuncs.com:1921/work-order
spring.datasource.username=vion
......@@ -17,9 +18,11 @@ wx.mp.config-storage.redis.password==RtOTnx2V
wx.mp.config-storage.redis.port=6379
wx.mp.config-storage.redis.database=8
server.port=8011
fileUrl=D:/pic
#fileurl=/nas-data/work-order
appkey=dingkrzwks0jpi2di3uo
appsecret=Ul5UTZqIost_kEAdfZXidvLoZhzvraYurm_g7PCHg-IrDMLHT7mdSgRS1iCHrDPt
xbongbong.corpid=ding6bb660048f7ae2dcee0f45d8e4f7c288
xbongbong.token=c7f9264e9e1687866c37032295552610
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
\ No newline at end of file
debug=false
server.port=8011
################################## DATABASE ########################################
spring.datasource.url=jdbc:postgresql://pgm-2ze3cjpyjgjw0bl5uo.pg.rds.aliyuncs.com:1921/work-order
spring.datasource.username=vion
spring.datasource.password=jkou72j32m4K5d8k
spring.datasource.driver-class-name=org.postgresql.Driver
server.port=8088
\ No newline at end of file
spring.data.redis.host=r-2zejlb88mng3q50aw7pd.redis.rds.aliyuncs.com
spring.data.redis.password=RtOTnx2V
spring.data.redis.port=6379
spring.data.redis.database=8
wx.mp.config-storage.type=Redisson
wx.mp.config-storage.key-prefix=wa
wx.mp.config-storage.redis.host=r-2zejlb88mng3q50aw7pd.redis.rds.aliyuncs.com
wx.mp.config-storage.redis.password==RtOTnx2V
wx.mp.config-storage.redis.port=6379
wx.mp.config-storage.redis.database=8
fileurl=/nas-data/work-order
appkey=dingkrzwks0jpi2di3uo
appsecret=Ul5UTZqIost_kEAdfZXidvLoZhzvraYurm_g7PCHg-IrDMLHT7mdSgRS1iCHrDPt
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!