Commit 09198e44 by HlQ

[add]

1.预工单添加根据报修人手机号获取项目信息的接口
2.工单添加转发和催办功能
3.发票管理添加编辑和导出功能
4.Redis key 统一管理
5.合同管理、收款管理、发票管理支持自定义字段排序
[fix]
修复合同同步时,更新维保状态的 bug
1 parent f7cba6fe
Showing 36 changed files with 562 additions and 85 deletions
package vion.config;
import com.github.liaochong.myexcel.core.converter.CustomWriteContext;
import com.github.liaochong.myexcel.core.converter.CustomWriteConverter;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import vion.constant.RedisKeyEnum;
import java.util.Map;
/**
* @author HlQ
* @date 2024/2/2
*/
@Component
@RequiredArgsConstructor
public class FaultTypeConverter implements CustomWriteConverter<Integer, Object> {
private final RedisTemplate redisTemplate;
@Override
public Object convert(Integer originalData, CustomWriteContext customWriteContext) {
Map<String, String> faultTypeMap = redisTemplate.opsForHash().entries(RedisKeyEnum.DICT_PREFIX.getVal() + RedisKeyEnum.FAULT_TYPE.getVal());
return faultTypeMap.getOrDefault(originalData.toString(), "故障类型不存在");
}
}
......@@ -6,6 +6,7 @@ import com.github.liaochong.myexcel.core.converter.CustomWriteConverter;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import vion.constant.RedisKeyEnum;
import vion.model.User;
/**
......@@ -20,7 +21,7 @@ public class UserNameConverter implements CustomWriteConverter<Long, String> {
@Override
public String convert(Long originalData, CustomWriteContext customWriteContext) {
return Opt.ofNullable(((User) redisTemplate.opsForValue().get("dingtalk:user:id:" + originalData)))
return Opt.ofNullable(((User) redisTemplate.opsForValue().get(RedisKeyEnum.DING_PREFIX.getVal() + RedisKeyEnum.USER_ID.getVal() + originalData)))
.map(User::getUsername)
.orElse("未知");
}
......
package vion.constant;
import cn.hutool.core.util.StrUtil;
import lombok.Getter;
import java.util.Arrays;
/**
* @author HlQ
* @date 2024/2/2
*/
@Getter
public enum RedisKeyEnum {
/**
* 字典 key
*/
DICT_PREFIX("sys:dict:"),
IMPLEMENT_TYPE("implementType"),
PROJECT_STAGE("projectStage"),
PROJECT_STATE("projectState"),
PRODUCT_TYPE("productType"),
BRAND("brand"),
ORDER_TEMP_STATUS("orderTempStatus"),
ORDER_STATUS("orderStatus"),
FAULT_TYPE("faultType"),
STATUS("status"),
SOLVE_TYPE("solveType"),
FILE_TYPE("fileType"),
SOURCE_TYPE("sourceType"),
INSPECT_TYPE("inspectType"),
FAULT_REASON("faultReason"),
SERVICE_ORDER_STATUS("serviceOrderStatus"),
SERVICE_TYPE("serviceType"),
PAY_TYPE("payType"),
CONTRACT_TYPE("contractType"),
FINANCIAL_STATUS("financialStatus"),
PRODUCT_LINE("productLine"),
CONSTRUCTION_STATUS("constructionStatus"),
DIFF_TYPE("diffType"),
OFFSET_ITEM("offset_item"),
POINT_STATUS("pointStatus"),
REPAIR_STATUS("repairStatus"),
/**
* 钉钉 key
*/
DING_PREFIX("dingtalk:"),
USER_ID("user:id:"),
USER_NAME("user:name:"),
ACCESS_TOKEN("accessToken"),
/**
* 合同同步时间
*/
CONTRACT_SYNC_TIME("contract:sync:time");
private final String val;
RedisKeyEnum(String val) {
this.val = val;
}
public static String getValByKey(String key) {
return Arrays.stream(RedisKeyEnum.values())
.filter(e -> StrUtil.equalsAnyIgnoreCase(e.name(), key))
.findFirst()
.map(RedisKeyEnum::getVal)
.orElseThrow(() -> new IllegalArgumentException("未找到对应的枚举"));
}
}
......@@ -62,4 +62,18 @@ public class DictionaryController {
DictionaryType dictionaryType = converter.convert(data, DictionaryType.class);
return dictionaryTypeService.saveOrUpdate(dictionaryType) ? "成功" : "失败";
}
/**
* 同步字典到 Redis
*
* @return java.lang.String
*/
@GetMapping("/dict/sync")
@SaCheckPermission(value = "dict:sync", orRole = "admin")
// todo 未加权限
public String syncDict() {
dictionaryService.syncDict();
return "同步成功";
}
}
package vion.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.liaochong.myexcel.core.DefaultExcelBuilder;
import com.github.liaochong.myexcel.core.watermark.Watermark;
import com.github.liaochong.myexcel.utils.AttachmentExportUtil;
import com.github.liaochong.myexcel.utils.WatermarkUtil;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.web.bind.annotation.*;
import vion.dto.InvoiceDTO;
import vion.service.IInvoiceService;
import vion.vo.InvoiceVO;
import vion.vo.UserVO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.IOException;
import java.util.Date;
import java.util.List;
/**
* 发票记录管理
*/
* 发票记录管理
*/
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
......@@ -40,10 +53,48 @@ public class InvoiceController {
return invoiceService.save(dto);
}
@PostMapping("/invoice/{id}")
@SaCheckPermission(value = "invoice:edit", orRole = "admin")
public String update(@PathVariable Long id, @RequestBody InvoiceDTO dto) {
dto.setId(id);
return invoiceService.update(id, dto);
}
@DeleteMapping("/invoice/{id}")
@SaCheckPermission(value = "invoice:remove", orRole = "admin")
public String delById(@PathVariable Long id) {
return invoiceService.removeById(id) ? "删除成功" : "删除失败";
return invoiceService.delById(id);
}
@GetMapping("/invoice/export")
@SaCheckPermission(value = "invoice:export", orRole = "admin")
public void invoiceExport(InvoiceDTO dto, HttpServletResponse response) {
UserVO user = (UserVO) StpUtil.getTokenSession().get("curLoginUser");
dto.setPageSize(30000);
Page<InvoiceVO> voPage = invoiceService.list(dto);
try (DefaultExcelBuilder<InvoiceVO> defaultExcelBuilder = DefaultExcelBuilder.of(InvoiceVO.class)) {
Workbook workbook = defaultExcelBuilder.build(voPage.getRecords());
// 水印添加指定字体,并在服务器上安装 SimSun 字体,解决中文字体变成方块的问题
Watermark watermark = new Watermark();
watermark.setText(user.getUsername() + "-" + user.getPhone());
watermark.setFont(new Font("SimSun", Font.PLAIN, 16));
WatermarkUtil.addWatermark(workbook, watermark);
AttachmentExportUtil.export(workbook, StrUtil.format("发票列表_{}", DateUtil.formatDateTime(new Date())), response);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 计算合同发票金额
*
* @param noList 合同编号列表,为空表示计算所有合同
* @return java.lang.String
*/
@GetMapping("/invoice/calMoney")
@SaCheckPermission(value = "invoice:calMoney", orRole = "admin")
public String calMoney(String[] noList) {
return invoiceService.calMoney(noList);
}
}
......@@ -54,9 +54,10 @@ public class StoreController {
@GetMapping("/storeList")
@SaCheckPermission(value = "store:list1", orRole = "admin")
public List<StoreVO> getStoreList(Long accountId, String name, Integer limit) {
public List<StoreVO> getStoreList(Long id, Long accountId, String name, Integer limit) {
List<Store> storeList = storeService.lambdaQuery()
.eq(ObjUtil.isNotNull(accountId), Store::getAccountId, accountId)
.eq(ObjUtil.isNotNull(id), Store::getId, id)
.like(StrUtil.isNotBlank(name), Store::getName, name)
.last(limit != null, "limit " + limit)
.list();
......@@ -155,8 +156,9 @@ public class StoreController {
@PostMapping("/store/tag/{id}")
@SaCheckPermission(value = "store:tag", orRole = "admin")
public String addTag(@PathVariable Long id, @RequestBody Long tagId) {
return storeService.addTag(id, tagId);
// 权限未加
public String addTag(@PathVariable Long id, @RequestBody List<Long> tagIdList) {
return storeService.addTag(id, tagIdList);
}
}
......@@ -13,6 +13,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.web.bind.annotation.*;
import vion.config.FaultTypeConverter;
import vion.config.UserNameConverter;
import vion.dto.TaskDTO;
import vion.model.FaultLog;
......@@ -36,6 +37,7 @@ public class TaskController {
private final ITaskService taskService;
private final IFaultLogService faultLogService;
private final UserNameConverter userNameConverter;
private final FaultTypeConverter faultTypeConverter;
@GetMapping("/tasks")
@SaCheckPermission(value = "task:list", orRole = "admin")
......@@ -51,14 +53,13 @@ public class TaskController {
@PostMapping("/tasks")
@SaCheckPermission(value = "task:editAndSave", orRole = "admin")
public Long saveOrUpdate(TaskDTO data, @RequestHeader String token) {
return taskService.circTask(data, token);
public Long saveOrUpdate(TaskDTO data) {
return taskService.circTask(data);
}
@GetMapping("/faultLogs")
@SaCheckPermission(value = "task:log:list", orRole = "admin")
public List<FaultLog> getFaultLogById(Long storeId, Long taskId) {
List<FaultLog> faultLogList = faultLogService.lambdaQuery()
.eq(FaultLog::getStoreId, storeId)
.eq(FaultLog::getTaskId, taskId)
......@@ -90,7 +91,9 @@ public class TaskController {
data.setPageSize(30000);
Page<TaskVO> voPage = taskService.getTaskList(data);
try (DefaultExcelBuilder<TaskVO> defaultExcelBuilder = DefaultExcelBuilder.of(TaskVO.class)) {
Workbook workbook = defaultExcelBuilder.binding(userNameConverter).build(voPage.getRecords());
Workbook workbook = defaultExcelBuilder
.binding(userNameConverter, faultTypeConverter)
.build(voPage.getRecords());
// 水印添加指定字体,并在服务器上安装 SimSun 字体,解决中文字体变成方块的问题
Watermark watermark = new Watermark();
watermark.setText(user.getUsername() + "-" + user.getPhone());
......@@ -101,4 +104,35 @@ public class TaskController {
throw new RuntimeException(e);
}
}
@GetMapping("/task/uuid/{uuid}")
public TaskVO getTaskByUuid(@PathVariable String uuid) {
return taskService.getTaskByUuid(uuid);
}
/**
* 转发工单,把工单转发给某人查看工单详情
*
* @param taskId 工单id
* @param forwardUser 转发人
* @return java.lang.String
*/
@GetMapping("/task/forward")
@SaCheckPermission(value = "task:forward", orRole = "admin")
public String forwardTask(Long taskId, String forwardUser) {
return taskService.forwardTask(taskId, forwardUser);
}
/**
* 催办工单,催办工单给当前处理人
*
* @param taskId 工单id
* @param remark 备注
* @return java.lang.String
*/
@GetMapping("/task/urge")
@SaCheckPermission(value = "task:urge", orRole = "admin")
public String urgeTask(Long taskId, String remark) {
return taskService.urgeTask(taskId, remark);
}
}
......@@ -11,6 +11,8 @@ import vion.model.TaskTemp;
import vion.service.ITaskTempService;
import vion.vo.TaskTempVO;
import java.util.Map;
/**
* 预工单
*/
......@@ -36,9 +38,9 @@ public class TaskTempController {
}
@PostMapping("/taskTemp")
@SaCheckPermission(value = "taskTemp:editAndSave", orRole = "admin")
public Object saveOrUpdateTaskTemp(TaskTempDTO data) {
return taskTempService.saveOrUpdTaskTemp(data);
@SaCheckPermission(value = "taskTemp:save", orRole = "admin")
public Object saveTaskTemp(TaskTempDTO data) {
return taskTempService.saveTaskTemp(data);
}
@PostMapping("/taskTemp/{id}")
......@@ -48,4 +50,10 @@ public class TaskTempController {
taskTemp.setId(id);
return taskTempService.updateById(taskTemp) ? "更新成功" : "更新失败";
}
@GetMapping("/taskTemp/getInfoByPhone")
@SaCheckPermission(value = "task:getInfoByPhone", orRole = "admin")
public Map<String, Long> getInfoByPhone(String phone) {
return taskTempService.getInfoByPhone(phone);
}
}
\ No newline at end of file
......@@ -11,6 +11,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import vion.constant.RedisKeyEnum;
import vion.model.*;
import vion.service.*;
......@@ -48,7 +49,7 @@ public class ContractRunner {
.stream().collect(Collectors.toMap(Dictionary::getValue, Dictionary::getKey));
List<Contract> insOrUpdContractList = new ArrayList<>();
String modifyTime = Opt.ofNullable((String) redisTemplate.opsForValue().get("contract:sync:time"))
String modifyTime = Opt.ofNullable((String) redisTemplate.opsForValue().get(RedisKeyEnum.CONTRACT_SYNC_TIME.getVal()))
.orElse("1970-01-01 00:00:00");
String url = "jdbc:sqlserver://47.92.144.255:1433;databaseName=UFDATA_001_2020;encrypt=false";
String username = "vion-reader";
......@@ -127,7 +128,8 @@ public class ContractRunner {
}
});
// 合同更新,同步调用一下更新项目的维保状态
Opt.ofEmptyAble(contractStoreService.lambdaQuery().in(RContractStore::getContractId, updContractIdList).list())
Opt.ofEmptyAble(updContractIdList)
.map(contractIdList -> contractStoreService.lambdaQuery().in(RContractStore::getContractId, contractIdList).list())
.map(csList -> csList.stream().map(RContractStore::getStoreId).collect(Collectors.toList()))
.filter(CollUtil::isNotEmpty)
.ifPresent(storeService::calMaintainStatus);
......@@ -137,7 +139,7 @@ public class ContractRunner {
// 合同状态不为空,代表此条记录为新增,需要同步销售人信息到 r_contract_user 表中
if (ObjUtil.isNotNull(v.getStatus())) {
RContractUser contractUser = new RContractUser();
String userId = Opt.ofNullable(redisTemplate.opsForValue().get("dingtalk:user:name:" + v.getSaleName()))
String userId = Opt.ofNullable(redisTemplate.opsForValue().get(RedisKeyEnum.DING_PREFIX.getVal() + RedisKeyEnum.USER_NAME.getVal() + v.getSaleName()))
.map(u -> (User) u)
.map(User::getUserid)
.orElse(null);
......@@ -245,7 +247,7 @@ public class ContractRunner {
});
log.info("【结束】从crm系统同步合同信息");
redisTemplate.opsForValue().set("contract:sync:time", DateUtil.formatDateTime(insOrUpdContractList.get(0).getOriginalModTime()));
redisTemplate.opsForValue().set(RedisKeyEnum.CONTRACT_SYNC_TIME.getVal(), DateUtil.formatDateTime(insOrUpdContractList.get(0).getOriginalModTime()));
}
@Scheduled(cron = "0 0 1 * * ?")
......
package vion.dto;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;
......@@ -7,6 +8,7 @@ import org.springframework.web.multipart.MultipartFile;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@Getter
@Setter
......@@ -80,7 +82,7 @@ public class ContractDTO extends BaseDTO {
private int switchFlag;
/** 产品线属性 */
private Integer productLine;
private List<Integer> productLines;
/**
* 合同总金额
......@@ -108,4 +110,6 @@ public class ContractDTO extends BaseDTO {
/** 操作符 > < = */
private String operator;
private OrderItem orderItem;
}
\ No newline at end of file
......@@ -24,6 +24,10 @@ public class DingDTO {
*/
private Long taskId;
/**
* 工单uuid
*/
private String taskUuid;
/**
* 预工单id
*/
private Long taskTempId;
......
package vion.dto;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.util.Date;
......@@ -44,4 +46,11 @@ public class InvoiceDTO extends BaseDTO {
*/
private String serialNo;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date invoicingTimeStart;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date invoicingTimeEnd;
private OrderItem orderItem;
}
\ No newline at end of file
package vion.dto;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
......@@ -51,4 +52,6 @@ public class PaymentDTO extends BaseDTO {
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date collectionTimeEnd;
private OrderItem orderItem;
}
\ No newline at end of file
......@@ -57,6 +57,8 @@ public class StoreDTO extends BaseDTO {
private Double percentage;
/** 当前卡点 */
private String stuckPoint;
/** 标签id */
private Long tagId;
private Long sourceId;
private Long targetId;
......
......@@ -13,21 +13,37 @@ import java.util.Date;
public class TaskTempDTO extends BaseDTO {
private Long id;
private Long storeId;
/** 项目名称 */
/**
* 项目名称
*/
private String storeName;
/** 报修日期 */
/**
* 报修日期
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date repairTime;
/** 故障说明 */
/**
* 故障说明
*/
private String faultDescription;
/** 报修人 */
/**
* 报修人
*/
private String repairPeople;
/** 联系方式 */
/**
* 联系方式
*/
private String repairPhone;
/** 状态(1待确认、2已确认) */
/**
* 状态(1待确认、2已确认)
*/
private Integer status;
private String remark;
/**
* 工程师姓名
*/
private String engineerName;
private String openid;
private MultipartFile[] files;
......
package vion.model;
import lombok.Data;
@Data
public class Pic {
private String contractNo;
private String code;
}
\ No newline at end of file
......@@ -22,7 +22,7 @@ public class TaskTemp {
private Long id;
/** 项目id */
private Long storeId;
/** 项目名称 */
/** 项目名称(用户提交的名称) */
@TableField(condition = SqlCondition.LIKE)
private String storeName;
/** 报修时间 */
......@@ -58,6 +58,11 @@ public class TaskTemp {
/** 备注 */
private String remark;
/**
* 工程师姓名
*/
private String engineerName;
/** 微信用户id */
private String openid;
}
......
......@@ -4,4 +4,5 @@ import com.github.yulichang.base.MPJBaseService;
import vion.model.Dictionary;
public interface IDictionaryService extends MPJBaseService<Dictionary> {
void syncDict();
}
......@@ -14,5 +14,10 @@ public interface IInvoiceService extends MPJBaseService<Invoice> {
String save(List<InvoiceDTO> dto);
String update(Long id, InvoiceDTO dto);
String delById(Long id);
String calMoney(String[] noList);
}
......@@ -21,6 +21,6 @@ public interface IStoreService extends MPJBaseService<Store> {
String mergeStore(StoreDTO dto);
String addTag(Long id, Long tagId);
String addTag(Long id, List<Long> tagIdList);
}
......@@ -14,7 +14,13 @@ public interface ITaskService extends MPJBaseService<Task> {
TaskVO getTaskById(Long taskId);
Long circTask(TaskDTO data, String token);
Long circTask(TaskDTO data);
String batchIns(List<TaskDTO> data);
TaskVO getTaskByUuid(String uuid);
String forwardTask(Long taskId, String forwardUser);
String urgeTask(Long taskId, String remark);
}
......@@ -6,10 +6,15 @@ import vion.dto.TaskTempDTO;
import vion.model.TaskTemp;
import vion.vo.TaskTempVO;
import java.util.Map;
public interface ITaskTempService extends MPJBaseService<TaskTemp> {
Page<TaskTempVO> getTaskTempList(TaskTempDTO data);
TaskTempVO getTaskTempById(Long id);
Object saveOrUpdTaskTemp(TaskTempDTO data);
Object saveTaskTemp(TaskTempDTO data);
Map<String, Long> getInfoByPhone(String phone);
}
......@@ -67,7 +67,10 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
public Page<ContractVO> list(ContractDTO dto) {
Result result = getResult(dto);
Page<ContractVO> contractVOList = this.selectJoinListPage(Page.of(dto.getPageNum(), dto.getPageSize()), ContractVO.class, result.wrapper);
Page<ContractVO> page = Page.of(dto.getPageNum(), dto.getPageSize());
Opt.ofNullable(dto.getOrderItem())
.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()))))
......@@ -412,8 +415,8 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
.select(RContractStore::getContractId), o -> Long.valueOf(o.toString()))
: ListUtil.empty();
// 根据产品线查出关联的合同
List<Long> lineContractIdList = Opt.ofNullable(dto.getProductLine())
.map(pl -> Db.listObjs(Wrappers.lambdaQuery(Store.class).eq(Store::getProductLine, pl), Store::getId))
List<Long> lineContractIdList = Opt.ofEmptyAble(dto.getProductLines())
.map(pl -> Db.listObjs(Wrappers.lambdaQuery(Store.class).in(Store::getProductLine, pl), Store::getId))
.map(storeIds -> contractStoreService.listObjs(Wrappers.<RContractStore>lambdaQuery().select(RContractStore::getContractId).in(RContractStore::getStoreId, storeIds), o -> Long.valueOf(o.toString())))
.orElse(new ArrayList<>());
// 根据当前登录用户的角色获取用户名
......@@ -462,7 +465,7 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
Set<Long> finalIdSet;
if (isPerm) {
// 不是以上三个角色,只能访问自己相关的合同或自己产品线相关的合同
if (ObjUtil.isNotNull(dto.getProductLine())) {
if (CollUtil.isNotEmpty(dto.getProductLines())) {
finalIdSet = CollUtil.intersectionDistinct(lineContractIdList, allContractUserIdList);
} else {
finalIdSet = CollUtil.unionDistinct(lineContractIdList, allContractUserIdList);
......@@ -472,12 +475,12 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
finalIdSet.add(-1L);
}
} else {
if (StrUtil.isNotBlank(dto.getSaleName()) && ObjUtil.isNotNull(dto.getProductLine())) {
if (StrUtil.isNotBlank(dto.getSaleName()) && CollUtil.isNotEmpty(dto.getProductLines())) {
finalIdSet = CollUtil.intersectionDistinct(lineContractIdList, allContractUserIdList);
} else {
finalIdSet = CollUtil.unionDistinct(lineContractIdList, allContractUserIdList);
}
if ((StrUtil.isNotBlank(dto.getSaleName()) || ObjUtil.isNotNull(dto.getProductLine())) && CollUtil.isEmpty(finalIdSet)) {
if ((StrUtil.isNotBlank(dto.getSaleName()) || CollUtil.isNotEmpty(dto.getProductLines())) && CollUtil.isEmpty(finalIdSet)) {
finalIdSet.add(-1L);
}
}
......@@ -488,8 +491,7 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
.selectAll(Contract.class)
.in(CollUtil.isNotEmpty(finalIdSet), Contract::getId, finalIdSet)
.notIn(CollUtil.isNotEmpty(contractIdList), Contract::getId, contractIdList)
.between(ArrayUtil.isAllNotNull(dto.getSignDateStart(), dto.getSignDateEnd()), Contract::getSignDate, dto.getSignDateStart(), dto.getSignDateEnd())
.orderByDesc(Contract::getEntryTime);
.between(ArrayUtil.isAllNotNull(dto.getSignDateStart(), dto.getSignDateEnd()), Contract::getSignDate, dto.getSignDateStart(), dto.getSignDateEnd());
if (StrUtil.isNotBlank(dto.getOperator()) && ObjUtil.isNotNull(dto.getAmount())) {
String ope = dto.getOperator();
if (">".equals(ope)) {
......
......@@ -186,7 +186,7 @@ public class DeliveryRecordServiceImpl extends MPJBaseServiceImpl<DeliveryRecord
String mainName = FileUtil.mainName(orgName);
String fileExt = FileUtil.extName(orgName);
String filename = StrUtil.format("{}_{}.{}", mainName, DateUtil.format(new Date(), "yyyyMMdd_HHmmssSSS"), fileExt);
String path = fileUrl + FileUtil.FILE_SEPARATOR + "delivery" + FileUtil.FILE_SEPARATOR + deliveryRecord.getContractId() + FileUtil.FILE_SEPARATOR + deliveryRecord.getId() + FileUtil.FILE_SEPARATOR + filename;
String path = fileUrl + FileUtil.FILE_SEPARATOR + "delivery" + FileUtil.FILE_SEPARATOR + deliveryRecord.getId() + FileUtil.FILE_SEPARATOR + filename;
File file = FileUtil.touch(path);
try {
infile.transferTo(file);
......
package vion.service.impl;
import cn.hutool.core.lang.Opt;
import com.github.yulichang.base.MPJBaseServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import vion.constant.RedisKeyEnum;
import vion.mapper.DictionaryMapper;
import vion.model.Dictionary;
import vion.service.IDictionaryService;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class DictionaryServiceImpl extends MPJBaseServiceImpl<DictionaryMapper, Dictionary> implements IDictionaryService {
private final RedisTemplate redisTemplate;
@Override
public void syncDict() {
Opt.ofEmptyAble(this.list())
.map(l -> l.stream().collect(Collectors.groupingBy(Dictionary::getType, Collectors.toMap(d -> d.getKey().toString(), Dictionary::getValue))))
.ifPresent(m -> m.forEach((type, map) -> redisTemplate.opsForHash().putAll(RedisKeyEnum.DICT_PREFIX.getVal() + RedisKeyEnum.getValByKey(type), map)));
}
}
......@@ -5,6 +5,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
......@@ -66,8 +67,11 @@ public class InvoiceServiceImpl extends MPJBaseServiceImpl<InvoiceMapper, Invoic
.selectAll(Invoice.class)
.leftJoin(Contract.class, Contract::getContractNo, Invoice::getContractNo)
.eq(StrUtil.isNotBlank(saleName), Contract::getSaleName, saleName)
.orderByDesc(Invoice::getCreateTime);
return this.selectJoinListPage(Page.of(dto.getPageNum(), dto.getPageSize()), InvoiceVO.class, wrapper);
.between(ArrayUtil.isAllNotNull(dto.getInvoicingTimeStart(), dto.getInvoicingTimeEnd()), Invoice::getInvoicingTime, dto.getInvoicingTimeStart(), dto.getInvoicingTimeEnd());
Page<InvoiceVO> page = Page.of(dto.getPageNum(), dto.getPageSize());
Opt.ofNullable(dto.getOrderItem())
.ifPresent(page::addOrder);
return this.selectJoinListPage(page, InvoiceVO.class, wrapper);
}
@Override
......@@ -116,6 +120,56 @@ public class InvoiceServiceImpl extends MPJBaseServiceImpl<InvoiceMapper, Invoic
return "成功";
}
@Override
public String update(Long id, InvoiceDTO dto) {
Invoice invoice = converter.convert(dto, Invoice.class);
if (this.updateById(invoice)) {
List<Invoice> invoiceList = this.lambdaQuery()
.in(Invoice::getContractNo, dto.getContractNo())
.list();
BigDecimal sumAmount = invoiceList.stream().map(Invoice::getInvoiceAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
contractService.lambdaUpdate()
.eq(Contract::getContractNo, dto.getContractNo())
.set(Contract::getInvoiceAmount, sumAmount)
.update(new Contract());
return "更新成功";
}
return "更新失败";
}
@Override
@Transactional(rollbackFor = Exception.class)
public String delById(Long id) {
Invoice invoice = this.getById(id);
String contractNo = invoice.getContractNo();
contractService.lambdaUpdate()
.eq(Contract::getContractNo, contractNo)
.setSql("invoice_amount = invoice_amount - " + invoice.getInvoiceAmount())
.update(new Contract());
this.removeById(id);
return "成功";
}
@Override
public String calMoney(String[] noList) {
Map<String, BigDecimal> no2SumMap = this.lambdaQuery()
.in(ArrayUtil.isNotEmpty(noList), Invoice::getContractNo, noList)
.list()
.stream().collect(Collectors.groupingBy(Invoice::getContractNo, Collectors.reducing(BigDecimal.ZERO, Invoice::getInvoiceAmount, BigDecimal::add)));
no2SumMap.forEach((no, sum) -> {
Contract existContract = contractService.lambdaQuery().eq(Contract::getContractNo, no).one();
if (ObjUtil.isNull(existContract)) {
return;
}
contractService.lambdaUpdate()
.eq(Contract::getContractNo, no)
.set(Contract::getInvoiceAmount, sum)
.update(new Contract());
});
return "金额计算成功";
}
JSONObject buildMsg(String userid, Invoice invoice, Contract contract) {
JSONObject jsonObj = new JSONObject();
jsonObj.set("agent_id", 2358374016L);
......
......@@ -69,9 +69,11 @@ public class PaymentServiceImpl extends MPJBaseServiceImpl<PaymentMapper, Paymen
.selectAll(Payment.class)
.leftJoin(Contract.class, Contract::getContractNo, Payment::getContractNo)
.eq(StrUtil.isNotBlank(saleName), Contract::getSaleName, saleName)
.between(ArrayUtil.isAllNotNull(dto.getCollectionTimeStart(), dto.getCollectionTimeEnd()), Payment::getCollectionTime, dto.getCollectionTimeStart(), dto.getCollectionTimeEnd())
.orderByDesc(Payment::getCreateTime);
return this.selectJoinListPage(Page.of(dto.getPageNum(), dto.getPageSize()), PaymentVO.class, wrapper);
.between(ArrayUtil.isAllNotNull(dto.getCollectionTimeStart(), dto.getCollectionTimeEnd()), Payment::getCollectionTime, dto.getCollectionTimeStart(), dto.getCollectionTimeEnd());
Page<PaymentVO> page = Page.of(dto.getPageNum(), dto.getPageSize());
Opt.ofNullable(dto.getOrderItem())
.ifPresent(page::addOrder);
return this.selectJoinListPage(page, PaymentVO.class, wrapper);
}
@Override
......
......@@ -62,8 +62,18 @@ public class StoreServiceImpl extends MPJBaseServiceImpl<StoreMapper, Store> imp
@Override
public Page<StoreVO> getStoreList(StoreDTO data) {
List<Long> storeIdListByTagId = new ArrayList<>();
if (ObjUtil.isNotNull(data.getTagId())) {
List<RStoreTag> storeTagList = storeTagService.lambdaQuery().eq(RStoreTag::getTagId, data.getTagId()).list();
storeIdListByTagId = storeTagList.stream().map(RStoreTag::getStoreId).collect(Collectors.toList());
if (CollUtil.isEmpty(storeIdListByTagId)) {
storeIdListByTagId.add(-1L);
}
}
Store store = converter.convert(data, Store.class);
Page<Store> storeList = this.lambdaQuery(store)
.in(CollUtil.isNotEmpty(storeIdListByTagId), Store::getId, storeIdListByTagId)
.page(Page.of(data.getPageNum(), data.getPageSize()));
// todo 缓存
List<Account> accountList = accountService.list();
......@@ -117,7 +127,8 @@ public class StoreServiceImpl extends MPJBaseServiceImpl<StoreMapper, Store> imp
Map<Long, List<TagVO>> storeId2TagMap = Opt.ofEmptyAble(storeIdList)
.map(l -> {
MPJLambdaWrapper<Tag> wrapper = new MPJLambdaWrapper<Tag>()
.selectAll(Tag.class)
.select(Tag::getId, Tag::getName, Tag::getRemark)
.selectAs(RStoreTag::getStoreId, TagVO::getStoreId)
.leftJoin(RStoreTag.class, RStoreTag::getTagId, Tag::getId)
.in(RStoreTag::getStoreId, l);
return tagService.selectJoinList(TagVO.class, wrapper);
......@@ -310,10 +321,17 @@ public class StoreServiceImpl extends MPJBaseServiceImpl<StoreMapper, Store> imp
}
@Override
public String addTag(Long id, Long tagId) {
public String addTag(Long id, List<Long> tagIdList) {
storeTagService.lambdaUpdate().eq(RStoreTag::getStoreId, id).remove();
Opt.ofEmptyAble(tagIdList).ifPresent(l -> {
List<RStoreTag> list = l.stream().map(tagId -> {
RStoreTag storeTag = new RStoreTag();
storeTag.setStoreId(id);
storeTag.setTagId(tagId);
return storeTagService.save(storeTag) ? "添加成功" : "添加失败";
return storeTag;
}).collect(Collectors.toList());
storeTagService.saveBatch(list);
});
return "成功";
}
}
package vion.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONArray;
......@@ -19,10 +22,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import vion.dto.TaskTempDTO;
import vion.mapper.TaskTempMapper;
import vion.model.FileInfo;
import vion.model.Task;
import vion.model.TaskTemp;
import vion.model.User;
import vion.model.*;
import vion.service.IFileService;
import vion.service.ITaskTempService;
import vion.service.IUserService;
......@@ -34,6 +34,7 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
......@@ -52,7 +53,7 @@ public class TaskTempServiceImpl extends MPJBaseServiceImpl<TaskTempMapper, Task
public Page<TaskTempVO> getTaskTempList(TaskTempDTO data) {
Page<TaskTemp> taskTempPage = this
.lambdaQuery(converter.convert(data, TaskTemp.class))
.between(data.getStartdate() != null && data.getEnddate() != null, TaskTemp::getRepairTime, data.getStartdate(), data.getEnddate())
.between(ArrayUtil.isAllNotNull(data.getStartdate(), data.getEnddate()), TaskTemp::getRepairTime, data.getStartdate(), data.getEnddate())
.page(Page.of(data.getPageNum(), data.getPageSize()));
List<TaskTempVO> taskTempVOList = converter.convert(taskTempPage.getRecords(), TaskTempVO.class);
return Page.<TaskTempVO>of(taskTempPage.getCurrent(), taskTempPage.getSize(), taskTempPage.getTotal()).setRecords(taskTempVOList);
......@@ -76,7 +77,7 @@ public class TaskTempServiceImpl extends MPJBaseServiceImpl<TaskTempMapper, Task
}
@Override
public Object saveOrUpdTaskTemp(TaskTempDTO data) {
public Object saveTaskTemp(TaskTempDTO data) {
TaskTemp taskTemp = converter.convert(data, TaskTemp.class);
this.save(taskTemp);
......@@ -118,6 +119,23 @@ public class TaskTempServiceImpl extends MPJBaseServiceImpl<TaskTempMapper, Task
.build();
}
@Override
public Map<String, Long> getInfoByPhone(String phone) {
MPJLambdaWrapper<TaskTemp> wrapper = new MPJLambdaWrapper<TaskTemp>()
.selectAs(TaskTemp::getStoreId, TaskTempVO::getStoreId)
.selectAs(Store::getAccountId, TaskTempVO::getAccountId)
.leftJoin(Store.class, Store::getId, TaskTemp::getStoreId)
.eq(TaskTemp::getRepairPhone, phone)
.orderByDesc(TaskTemp::getCreateTime);
List<TaskTempVO> voList = this.selectJoinList(TaskTempVO.class, wrapper);
List<TaskTempVO> filterList = voList.stream().filter(BeanUtil::isNotEmpty).collect(Collectors.toList());
if (CollUtil.isNotEmpty(filterList) && filterList.size() > 1) {
return MapUtil.<String, Long>builder().put("accountId", filterList.get(0).getAccountId()).put("storeId", filterList.get(0).getStoreId()).build();
}
return MapUtil.empty();
}
JSONObject buildMsg(String userid, TaskTemp taskTemp) {
JSONObject jsonObj = new JSONObject();
jsonObj.set("agent_id", 2358374016L);
......
......@@ -22,6 +22,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import vion.constant.RedisKeyEnum;
import vion.dto.DingDTO;
import vion.model.*;
import vion.service.*;
......@@ -66,18 +67,17 @@ public class DingMod {
* @return java.lang.String
*/
public String getToken() {
if (redisTemplate.hasKey("accessToken")) {
redisTemplate.opsForValue().get("dingtalk:accessToken");
}
return (String) Opt.ofNullable(redisTemplate.opsForValue().get(RedisKeyEnum.DING_PREFIX.getVal() + RedisKeyEnum.ACCESS_TOKEN.getVal()))
.orElseGet(() -> {
String res = HttpUtil.get("https://oapi.dingtalk.com/gettoken?appkey=" + appKey + "&appsecret=" + appSecret);
JSONObject jsonObj = JSONUtil.parseObj(res);
if (jsonObj.containsKey("access_token")) {
String accessToken = jsonObj.getStr("access_token");
redisTemplate.opsForValue().set("dingtalk:accessToken", accessToken, 7000, TimeUnit.SECONDS);
redisTemplate.opsForValue().set(RedisKeyEnum.DING_PREFIX.getVal() + RedisKeyEnum.ACCESS_TOKEN.getVal(), accessToken, 7000, TimeUnit.SECONDS);
return accessToken;
} else {
return "";
}
return "";
});
}
/**
......@@ -148,8 +148,8 @@ public class DingMod {
}
userService.saveOrUpdate(user, Wrappers.<User>lambdaUpdate().eq(User::getUserid, userid));
User one = userService.lambdaQuery().eq(User::getUserid, userid).one();
redisTemplate.opsForValue().set("dingtalk:user:id:" + one.getId(), user);
redisTemplate.opsForValue().set("dingtalk:user:name:" + one.getUsername(), user);
redisTemplate.opsForValue().set(RedisKeyEnum.DING_PREFIX.getVal() + RedisKeyEnum.USER_ID.getVal() + one.getId(), user);
redisTemplate.opsForValue().set(RedisKeyEnum.DING_PREFIX.getVal() + RedisKeyEnum.USER_NAME.getVal() + one.getUsername(), user);
}
}
});
......@@ -285,6 +285,8 @@ public class DingMod {
res.sendRedirect("https://yunwei.vionyun.com:8443/wap/workflow-list?token=" + token + "&activeUser=" + dto.getUserId());
} else if (ObjUtil.isNotEmpty(dto.getDeliveryId())) {
res.sendRedirect("https://yunwei.vionyun.com:8443/wap/delivery-invoice?token=" + token + "&id=" + dto.getDeliveryId());
} else if (ObjUtil.isNotEmpty(dto.getTaskUuid())) {
res.sendRedirect("https://yunwei.vionyun.com:8443/wap/workflow-process-view?token=" + token + "&taskUuid=" + dto.getTaskUuid());
}
} catch (IOException e) {
log.error("钉钉回调接口重定向失败!", e);
......
......@@ -160,6 +160,12 @@ public class ContractVO {
private BigDecimal invoiceAmount;
/**
* 录入时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date entryTime;
/**
* 合同关联的项目名
*/
private List<StoreVO> storeVOS;
......
package vion.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.github.liaochong.myexcel.core.annotation.ExcelColumn;
import com.github.liaochong.myexcel.core.annotation.ExcelModel;
import lombok.Getter;
import lombok.Setter;
......@@ -10,41 +12,49 @@ import java.util.Date;
@Getter
@Setter
@ExcelModel(sheetName = "发票列表", includeAllField = false)
public class InvoiceVO {
private Long id;
/**
* 合同编号
*/
@ExcelColumn(order = 0, title = "合同编号")
private String contractNo;
/**
* 开票时间
*/
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@ExcelColumn(order = 1, title = "开票时间", format = "yyyy-MM-dd")
private Date invoicingTime;
/**
* 发票金额
*/
@ExcelColumn(order = 2, title = "发票金额")
private BigDecimal invoiceAmount;
/**
* 发票号
*/
@ExcelColumn(order = 3, title = "发票编号")
private String invoiceNo;
/**
* 备注
*/
@ExcelColumn(order = 5, title = "备注")
private String remark;
/**
* 流水号
*/
@ExcelColumn(order = 4, title = "流水号")
private String serialNo;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@ExcelColumn(order = 6, title = "录入时间")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
......
......@@ -11,25 +11,51 @@ import java.util.List;
@Data
public class TaskTempVO {
private Long id;
/** 项目名称 */
/**
* 项目名称(用户提交的名称)
*/
private String storeName;
/** 报修时间 */
/**
* 项目id
*/
private Long storeId;
/**
* 集团id
*/
private Long accountId;
/**
* 报修时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date repairTime;
/** 故障说明 */
/**
* 故障说明
*/
private String faultDescription;
/** 报修人 */
/**
* 报修人
*/
private String repairPeople;
/** 联系方式 */
/**
* 联系方式
*/
private String repairPhone;
/** 状态(1待确认、2已确认) */
/**
* 状态(1待确认、2已确认)
*/
private Integer status;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
private String remark;
/**
* 工程师姓名
*/
private String engineerName;
private List<FileInfo> fileList;
/**
......
......@@ -4,7 +4,9 @@ import com.fasterxml.jackson.annotation.JsonFormat;
import com.github.liaochong.myexcel.core.annotation.ExcelColumn;
import com.github.liaochong.myexcel.core.annotation.ExcelModel;
import lombok.Data;
import vion.config.FaultTypeConverter;
import vion.config.UserNameConverter;
import vion.model.FaultLog;
import vion.model.FileInfo;
import vion.model.ServiceOrder;
......@@ -15,47 +17,79 @@ import java.util.List;
@ExcelModel(sheetName = "任务", includeAllField = false)
public class TaskVO {
private Long id;
/** 门店id */
/**
* 门店id
*/
private Long storeId;
/** 门店名称 */
/**
* 门店名称
*/
@ExcelColumn(order = 0, title = "项目名称")
private String storeName;
/** 预处理工单id */
/**
* 预处理工单id
*/
private Long taskTempId;
/** 报修日期 */
/**
* 报修日期
*/
@ExcelColumn(order = 5, title = "提交时间", format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date repairTime;
/** 故障类型 */
@ExcelColumn(order = 2, title = "故障类型", mapping = "1:相机问题,2:平台功能,3:系统数据,4:需求建议,5:其他问题")
/**
* 故障类型
*/
@ExcelColumn(order = 2, title = "故障类型", writeConverter = FaultTypeConverter.class)
private Integer faultType;
/** 故障说明 */
/**
* 故障说明
*/
@ExcelColumn(order = 3, title = "故障说明")
private String faultDescription;
/** 报修人 */
/**
* 报修人
*/
@ExcelColumn(order = 1, title = "客户姓名")
private String repairPeople;
/** 报修人联系方式 */
/**
* 报修人联系方式
*/
@ExcelColumn(order = 4, title = "联系方式")
private String repairPhone;
/** 状态:0待确认1进行中2已完成3挂起 */
/**
* 状态:0待确认1进行中2已完成3挂起
*/
@ExcelColumn(order = 6, title = "状态", mapping = "0:待确认,1:进行中,2:进行中,3:已完成,4:挂起,5:已关闭")
private Integer status;
/** 解决日期 */
/**
* 解决日期
*/
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date solveDate;
/** 故障原因 */
/**
* 故障原因
*/
private String faultReason;
/** 解决措施:0产品BUG、1使用问题、2需求问题 */
/**
* 解决措施:0产品BUG、1使用问题、2需求问题
*/
private Integer solveType;
/** 解决故障描述 */
/**
* 解决故障描述
*/
private String solveDescription;
/** 创建者 */
/**
* 创建者
*/
private Long createUser;
/** 当前处理人 */
/**
* 当前处理人
*/
@ExcelColumn(order = 7, title = "当前指派", writeConverter = UserNameConverter.class)
private Long activeUser;
/** 截止日期 */
/**
* 截止日期
*/
@ExcelColumn(order = 8, title = "截止日期", format = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date expDate;
......@@ -63,12 +97,22 @@ public class TaskVO {
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
/** 备注 */
/**
* 备注
*/
private String remark;
/** 集团id */
/**
* uuid
*/
private String uuid;
/**
* 集团id
*/
private Long accountId;
// 集团名字
private String accountName;
private List<FileInfo> fileList;
private ServiceOrder serviceOrder;
private List<FaultLog> faultLogList;
}
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!