Commit 09198e44 by HlQ

[add]

1.预工单添加根据报修人手机号获取项目信息的接口
2.工单添加转发和催办功能
3.发票管理添加编辑和导出功能
4.Redis key 统一管理
5.合同管理、收款管理、发票管理支持自定义字段排序
[fix]
修复合同同步时,更新维保状态的 bug
1 parent f7cba6fe
Showing 36 changed files with 914 additions and 111 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 "同步成功";
}
}
......@@ -4,8 +4,14 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
......@@ -14,12 +20,21 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import vion.dto.FileInfoDTO;
import vion.model.Contract;
import vion.model.FileInfo;
import vion.model.Pic;
import vion.service.IContractService;
import vion.service.IFileService;
import java.io.File;
import java.io.IOException;
import java.sql.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api")
......@@ -28,6 +43,7 @@ import java.util.Date;
public class FileController {
private final IFileService fileService;
private final IContractService contractService;
private final Converter converter;
@Value("${fileUrl:}")
......@@ -118,4 +134,193 @@ public class FileController {
return "文件保存成功";
}
/* @GetMapping("/tmpfile")
public String sync() {
// bDeliverGoodsId => tbAppendix
Map<String, List<TbAppendix>> id2UrlMap = appendixService.list(Wrappers.<TbAppendix>lambdaQuery().eq(TbAppendix::getBusinessTable, "tb_deliver_goods"))
.stream().collect(Collectors.groupingBy(TbAppendix::getBusinessUnid));
// bDeliverGoodsId => tbDeliverGoods
Map<Long, TbDeliverGoods> id2DeliverGoodsMap = deliverGoodsService.list().stream().collect(Collectors.toMap(TbDeliverGoods::getDeliverUnid, Function.identity()));
// contractNo => contract
Map<String, Long> no2ContractIdMap = contractService.list().stream().collect(Collectors.toMap(Contract::getContractNo, Contract::getId));
// contractNo => List<DeliveryRecord>
Map<String, List<DeliveryRecord>> no2IdMap = deliveryRecordService.list().stream().collect(Collectors.groupingBy(DeliveryRecord::getContractNo));
id2UrlMap.forEach((id, appendixList) -> appendixList.forEach(appendix -> {
TbDeliverGoods deliverGoods = id2DeliverGoodsMap.get(Long.valueOf(id));
String contractNo = deliverGoods.getContractUnid();
Long contractId = no2ContractIdMap.get(contractNo);
if (contractId == null) {
log.error("合同不存在:{}", contractNo);
return;
}
List<DeliveryRecord> deliveryIdList = no2IdMap.get(contractNo);
if (deliveryIdList.size() == 1) {
String path = fileUrl + FileUtil.FILE_SEPARATOR + "/delivery" + FileUtil.FILE_SEPARATOR + contractId + FileUtil.FILE_SEPARATOR + deliveryIdList.get(0).getId() + FileUtil.FILE_SEPARATOR + appendix.getAppendixName();
File file = HttpUtil.downloadFileFromUrl(appendix.getAppendixUrl().replace("192.168.9.110", "117.133.143.114"), FileUtil.file(path));
FileInfo fileInfo = new FileInfo();
fileInfo.setStoreId(-1L);
fileInfo.setSourceId(deliveryIdList.get(0).getId());
fileInfo.setSourceType(6);
fileInfo.setContractId(contractId);
fileInfo.setName(appendix.getAppendixName());
fileInfo.setUrl(path);
fileInfo.setType(FileUtil.extName(file));
fileInfo.setSha256(SecureUtil.sha256(file).toUpperCase());
fileInfo.setUploader("原合同平台");
fileService.save(fileInfo);
} else {
for (DeliveryRecord deliveryRecord : deliveryIdList) {
if (deliveryRecord.getSignDate().equals(id2DeliverGoodsMap.get(Long.valueOf(id)).getGoodsAcceptancDate()) && deliveryRecord.getShipDate().equals(id2DeliverGoodsMap.get(Long.valueOf(id)).getDeliverGoodsDate())) {
String path = fileUrl + FileUtil.FILE_SEPARATOR + "/delivery" + FileUtil.FILE_SEPARATOR + contractId + FileUtil.FILE_SEPARATOR + deliveryRecord.getId() + FileUtil.FILE_SEPARATOR + appendix.getAppendixName();
File file = HttpUtil.downloadFileFromUrl(appendix.getAppendixUrl().replace("192.168.9.110", "117.133.143.114"), FileUtil.file(path));
FileInfo fileInfo = new FileInfo();
fileInfo.setStoreId(-1L);
fileInfo.setSourceId(deliveryRecord.getId());
fileInfo.setSourceType(6);
fileInfo.setContractId(contractId);
fileInfo.setName(appendix.getAppendixName());
fileInfo.setUrl(path);
fileInfo.setType(FileUtil.extName(file));
fileInfo.setSha256(SecureUtil.sha256(file).toUpperCase());
fileInfo.setUploader("原合同平台");
fileService.save(fileInfo);
}
}
}
}));
return "success";
}*/
@GetMapping("/contractFile")
public String export() {
String url = "jdbc:sqlserver://47.92.144.255:1433;databaseName=UFDATA_001_2020;encrypt=false";
String username = "vion-reader";
String password = "vion-reader";
List<Pic> res = new ArrayList<>();
try (Connection connection = DriverManager.getConnection(url, username, password)) {
String sql = "select hetongpingshen_char05 as contract_no,hetongpingshen_char01 as pic_url from tcu_hetongpingshen;";
try (Statement statement = connection.createStatement()) {
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
Pic pic = new Pic();
String contractNo = resultSet.getString("contract_no");
pic.setContractNo(contractNo);
String picUrl = resultSet.getString("pic_url");
if (StrUtil.isBlank(picUrl)) {
continue;
}
// 获取字符串picUrl后五个字符
String code = picUrl.substring(picUrl.length() - 36);
pic.setCode(code);
res.add(pic);
}
}
} catch (SQLException e) {
}
Map<String, Contract> no2ConMap = contractService.list().stream().collect(Collectors.toMap(Contract::getContractNo, Function.identity()));
// CSRP20111098 CSRM23065215
for (Pic pic : res) {
String contractNo = pic.getContractNo();
String code = pic.getCode();
if (!no2ConMap.containsKey(contractNo)) {
log.info("合同文件导入-合同不存在:{}", contractNo);
continue;
}
Contract contract = no2ConMap.get(contractNo);
List<FileInfo> list = fileService.lambdaQuery()
.eq(FileInfo::getContractId, contract.getId())
.eq(FileInfo::getSourceType, 5)
.eq(FileInfo::getSourceId, contract.getId()).list();
if (CollUtil.isNotEmpty(list)) {
log.info("合同文件导入-合同文件已存在:{}", contractNo);
continue;
}
String body = HttpRequest.post("http://47.92.144.255:8072/pub/processattach.php?Action=viewfiles&PageSrc=")
.header("Cookie", "PHPSESSID=c52hbrbdc4tp73fai2shhkscj4; LoginSystemCookie=1; LoginNameCookie=0191; OrgCodeCookie=%28default%29%40001; ID_LIST_OL_10_0_0_MessageItem__Subject=250; TL_EXPANDED=*XSFPSQD.hetonglur2017*REL_XSFPSQDITEMS2002*REL_PRIVILEGE2002*hetongpingshen.Opportunity4*hetongluru.XMMC4")
.form("cellID", code)
.execute()
.body();
if (body.contains("text/javascript")) {
log.info("合同文件导入-调CRM接口出错:{}", contractNo);
break;
}
if (StrUtil.isBlank(body)) {
log.info("合同文件导入-body为空:{},code:{}", contractNo, code);
continue;
}
if (!StrUtil.contains(body, "href")) {
log.info("合同文件导入-无文件:{},code:{}", contractNo, code);
continue;
}
JSONObject json = JSONUtil.parseObj(body);
Object o = json.get("files");
if (o instanceof JSONObject) {
JSONObject files = json.getJSONObject("files");
for (Map.Entry<String, Object> entry : files) {
if (ObjUtil.isEmpty(entry.getValue())) {
continue;
}
String href = entry.getValue().toString();
String suf = ReUtil.get("href='(.*?)'", href, 1);
String finalUrl = "http://47.92.144.255:8072" + suf;
String name = ReUtil.get(">(.*?)<", href, 1);
String path = fileUrl + FileUtil.FILE_SEPARATOR + "contract" + FileUtil.FILE_SEPARATOR + contract.getId() + FileUtil.FILE_SEPARATOR + name;
log.info("合同:{},文件存入路径:{}", contractNo, path);
File file = HttpUtil.downloadFileFromUrl(finalUrl, FileUtil.file(path));
FileInfo fileInfo = new FileInfo();
fileInfo.setStoreId(-1L);
fileInfo.setSourceId(contract.getId());
fileInfo.setSourceType(5);
fileInfo.setContractId(contract.getId());
fileInfo.setName(name);
fileInfo.setUrl(path);
fileInfo.setType(FileUtil.extName(file));
fileInfo.setSha256(SecureUtil.sha256(file).toUpperCase());
fileInfo.setUploader("CRM");
fileService.save(fileInfo);
}
} else if (o instanceof JSONArray) {
JSONArray files = json.getJSONArray("files");
for (Object obj : files) {
if (ObjUtil.isEmpty(obj)) {
continue;
}
String href = obj.toString();
String suf = ReUtil.get("href='(.*?)'", href, 1);
String finalUrl = "http://47.92.144.255:8072" + suf;
String name = ReUtil.get(">(.*?)<", href, 1);
String path = fileUrl + FileUtil.FILE_SEPARATOR + "contract" + FileUtil.FILE_SEPARATOR + contract.getId() + FileUtil.FILE_SEPARATOR + name;
log.info("合同:{},文件存入路径:{}", contractNo, path);
File file = HttpUtil.downloadFileFromUrl(finalUrl, FileUtil.file(path));
FileInfo fileInfo = new FileInfo();
fileInfo.setStoreId(-1L);
fileInfo.setSourceId(contract.getId());
fileInfo.setSourceType(5);
fileInfo.setContractId(contract.getId());
fileInfo.setName(name);
fileInfo.setUrl(path);
fileInfo.setType(FileUtil.extName(file));
fileInfo.setSha256(SecureUtil.sha256(file).toUpperCase());
fileInfo.setUploader("CRM");
fileService.save(fileInfo);
}
} else {
log.info("合同文件导入-json转化出错:{},code:{}", contractNo, code);
}
}
return "success";
}
}
\ No newline at end of file
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 "成功";
}
}
......@@ -12,7 +12,6 @@ import cn.hutool.core.util.*;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
......@@ -23,9 +22,9 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vion.constant.RedisKeyEnum;
import vion.dto.TaskDTO;
import vion.mapper.TaskMapper;
import vion.model.Dictionary;
import vion.model.*;
import vion.service.*;
import vion.third.DingMod;
......@@ -49,7 +48,6 @@ public class TaskServiceImpl extends MPJBaseServiceImpl<TaskMapper, Task> implem
private final IFaultLogService faultLogService;
private final IStoreService storeService;
private final IUserService userService;
private final IDictionaryService dictionaryService;
private final DingMod dingMod;
private final WechatMod wechatMod;
private final Converter converter;
......@@ -138,13 +136,20 @@ public class TaskServiceImpl extends MPJBaseServiceImpl<TaskMapper, Task> implem
@Override
@Transactional(rollbackFor = Exception.class)
public Long circTask(TaskDTO data, String token) {
public Long circTask(TaskDTO data) {
UserVO user = (UserVO) StpUtil.getTokenSession().get("curLoginUser");
Store store = storeService.getById(data.getStoreId());
handleTaskTemp(data);
Task task = prepareTask(data, user);
sendNotifications(data, task, user);
Task task = prepareTask(data, user, store);
sendNotifications(task, user, store);
handleFiles(data, task, user);
return task.getId();
/**
* fixme
* 1.修改工单的所属项目,工单的日志和文件查询不到
* 2.任然会推送一次钉钉提醒
*/
}
/**
......@@ -163,11 +168,6 @@ public class TaskServiceImpl extends MPJBaseServiceImpl<TaskMapper, Task> implem
.set(TaskTemp::getStoreId, data.getStoreId())
.eq(TaskTemp::getId, data.getTaskTempId())
.update(new TaskTemp());
Store store = storeService.getById(data.getStoreId());
Opt.ofNullable((User) redisTemplate.opsForValue().get("dingtalk:user:id:" + store.getSalesperson()))
.map(User::getUserid)
.ifPresent(userid -> dingMod.workMsg(buildMsg2(userid, store.getName(), data)));
}
}
......@@ -176,15 +176,20 @@ public class TaskServiceImpl extends MPJBaseServiceImpl<TaskMapper, Task> implem
*
* @param data 前端传参
* @param user 当前登录用户
* @param store 项目
* @return vion.model.Task
*/
private Task prepareTask(TaskDTO data, UserVO user) {
private Task prepareTask(TaskDTO data, UserVO user, Store store) {
Task task = converter.convert(data, Task.class);
if (task.getId() == null) {
task.setCreateUser(user.getId());
task.setUuid(IdUtil.nanoId());
this.save(task);
Opt.ofNullable((User) redisTemplate.opsForValue().get(RedisKeyEnum.DING_PREFIX.getVal() + RedisKeyEnum.USER_ID.getVal() + store.getSalesperson()))
.map(User::getUserid)
.ifPresent(userid -> dingMod.workMsg(buildMsg2(userid, store.getName(), task)));
// 预工单文件在工单创建时,复制一份到工单文件夹下
Opt.ofNullable(data.getTaskTempId())
.map(taskTempId -> fileService.lambdaQuery()
......@@ -273,16 +278,14 @@ public class TaskServiceImpl extends MPJBaseServiceImpl<TaskMapper, Task> implem
/**
* 钉钉提醒和微信提醒
*
* @param data 前端传参
* @param task 工单
* @param user 当前登录用户
* @param store 项目
*/
private void sendNotifications(TaskDTO data, Task task, UserVO user) {
// todo 异步发送钉钉消息通知
Store store = storeService.getById(task.getStoreId());
private void sendNotifications(Task task, UserVO user, Store store) {
Task existTask = this.getById(task.getId());
Long activeUserId = data.getActiveUser();
User activeUser = userService.lambdaQuery().eq(User::getId, activeUserId).one();
Long activeUserId = task.getActiveUser();
User activeUser = (User) redisTemplate.opsForValue().get(RedisKeyEnum.DING_PREFIX.getVal() + RedisKeyEnum.USER_ID.getVal() + activeUserId);
Set<String> useridList = new HashSet<>();
useridList.add(activeUser.getUserid());
if (task.getStatus() == 3) {
......@@ -359,9 +362,59 @@ public class TaskServiceImpl extends MPJBaseServiceImpl<TaskMapper, Task> implem
return this.saveBatch(converter.convert(data, Task.class)) ? "成功" : "失败";
}
@Override
public TaskVO getTaskByUuid(String uuid) {
MPJLambdaWrapper<Task> wrapper = new MPJLambdaWrapper<Task>()
.selectAll(Task.class)
.selectAs(Store::getName, TaskVO::getStoreName)
.selectCollection(FaultLog.class, TaskVO::getFaultLogList)
.leftJoin(Store.class, Store::getId, Task::getStoreId)
.leftJoin(FaultLog.class, FaultLog::getTaskId, Task::getId)
.eq(Task::getUuid, uuid);
TaskVO vo = this.selectJoinOne(TaskVO.class, wrapper);
// 进行中的任务,在最后追加一条当前处理人正在处理的记录,仅做显示用
if (vo.getStatus() == 2) {
FaultLog faultLog = new FaultLog();
faultLog.setOperator(vo.getActiveUser());
faultLog.setContent("工单正在处理中");
faultLog.setCreateTime(new Date());
vo.getFaultLogList().add(faultLog);
}
return vo;
}
@Override
public String forwardTask(Long taskId, String forwardUser) {
Task task = this.getById(taskId);
Store store = storeService.getById(task.getStoreId());
JSONObject msg = buildMsg3(forwardUser, store.getName(), task);
String pushRes = dingMod.workMsg(msg);
if (StrUtil.contains(pushRes, "ok")) {
return "成功";
} else {
return "失败";
}
}
@Override
public String urgeTask(Long taskId, String remark) {
Task task = this.getById(taskId);
Long activeUserId = task.getActiveUser();
User activeUser = (User) redisTemplate.opsForValue().get(RedisKeyEnum.DING_PREFIX.getVal() + RedisKeyEnum.USER_ID.getVal() + activeUserId);
Store store = storeService.getById(task.getStoreId());
JSONObject msg = buildMsg4(activeUser.getUserid(), store.getName(), task, remark);
String pushRes = dingMod.workMsg(msg);
if (StrUtil.contains(pushRes, "ok")) {
return "成功";
} else {
return "失败";
}
}
JSONObject buildMsg(String userid, String storeName, Task task) {
List<Dictionary> orderStatus = dictionaryService.list(Wrappers.<Dictionary>lambdaQuery().eq(Dictionary::getType, "order_status"));
Map<Integer, String> orderStatusMap = orderStatus.stream().collect(Collectors.toMap(Dictionary::getKey, Dictionary::getValue));
Map<String, String> orderStatusMap = redisTemplate.opsForHash().entries(RedisKeyEnum.DICT_PREFIX.getVal() + RedisKeyEnum.ORDER_STATUS.getVal());
JSONObject jsonObj = new JSONObject();
jsonObj.set("agent_id", 2358374016L);
......@@ -371,12 +424,13 @@ public class TaskServiceImpl extends MPJBaseServiceImpl<TaskMapper, Task> implem
JSONObject content = new JSONObject();
content.set("title", "您有一条新工单请及时处理哦~_~");
String markdown = StrUtil.format("#### 门店信息: **{}** [FullOfVitality]" +
" \n #### 任务编号:{}" +
" \n #### 报修人:{}" +
" \n #### 联系方式:{}" +
" \n #### 当前工单状态:{}" +
" \n #### 故障描述:{}" +
" \n #### 发送时间:{}",
storeName, task.getRepairPeople(), task.getRepairPhone(), orderStatusMap.get(task.getStatus()), task.getFaultDescription(), DateUtil.now());
storeName, task.getUuid(), task.getRepairPeople(), task.getRepairPhone(), orderStatusMap.get(task.getStatus().toString()), task.getFaultDescription(), DateUtil.now());
content.set("markdown", markdown);
content.set("btn_orientation", "1");
......@@ -390,7 +444,7 @@ public class TaskServiceImpl extends MPJBaseServiceImpl<TaskMapper, Task> implem
return jsonObj;
}
JSONObject buildMsg2(String userid, String storeName, TaskDTO dto) {
JSONObject buildMsg2(String userid, String storeName, Task task) {
JSONObject jsonObj = new JSONObject();
jsonObj.set("agent_id", 2358374016L);
jsonObj.set("userid_list", userid);
......@@ -403,11 +457,78 @@ public class TaskServiceImpl extends MPJBaseServiceImpl<TaskMapper, Task> implem
" \n #### 联系方式:{}" +
" \n #### 故障描述:{}" +
" \n #### 发送时间:{}",
storeName, dto.getRepairPeople(), dto.getRepairPhone(), dto.getFaultDescription(), DateUtil.now());
content.set("text", markdown);
storeName, task.getRepairPeople(), task.getRepairPhone(), task.getFaultDescription(), DateUtil.now());
content.set("markdown", markdown);
content.set("btn_orientation", "1");
JSONArray jsonArray = new JSONArray();
jsonArray.add(new JSONObject().set("title", "查看详情").set("action_url", "https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=dingkrzwks0jpi2di3uo&response_type=code&scope=snsapi_auth&state=STATE&redirect_uri=https%3A%2F%2Fyunwei.vionyun.com%3A8443%2Fyunwei%2Fapi%2Fding%2Fcallback%2Finside%3FtaskUuid%3D" + task.getUuid()));
content.set("btn_json_list", jsonArray);
msg.set("msgtype", "action_card");
msg.set("action_card", content);
jsonObj.set("msg", msg);
return jsonObj;
}
msg.set("msgtype", "markdown");
msg.set("markdown", content);
JSONObject buildMsg3(String userid, String storeName, Task task) {
Map<String, String> orderStatusMap = redisTemplate.opsForHash().entries(RedisKeyEnum.DICT_PREFIX.getVal() + RedisKeyEnum.ORDER_STATUS.getVal());
JSONObject jsonObj = new JSONObject();
jsonObj.set("agent_id", 2358374016L);
jsonObj.set("userid_list", userid);
JSONObject msg = new JSONObject();
JSONObject content = new JSONObject();
content.set("title", "工单转发提醒");
String markdown = StrUtil.format("#### 门店信息: **{}** [FullOfVitality]" +
" \n #### 任务编号:{}" +
" \n #### 报修人:{}" +
" \n #### 联系方式:{}" +
" \n #### 当前工单状态:{}" +
" \n #### 故障描述:{}" +
" \n #### 发送时间:{}",
storeName, task.getUuid(), task.getRepairPeople(), task.getRepairPhone(), orderStatusMap.get(task.getStatus().toString()), task.getFaultDescription(), DateUtil.now());
content.set("markdown", markdown);
content.set("btn_orientation", "1");
JSONArray jsonArray = new JSONArray();
jsonArray.add(new JSONObject().set("title", "查看详情").set("action_url", "https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=dingkrzwks0jpi2di3uo&response_type=code&scope=snsapi_auth&state=STATE&redirect_uri=https%3A%2F%2Fyunwei.vionyun.com%3A8443%2Fyunwei%2Fapi%2Fding%2Fcallback%2Finside%3FtaskUuid%3D" + task.getUuid()));
content.set("btn_json_list", jsonArray);
msg.set("msgtype", "action_card");
msg.set("action_card", content);
jsonObj.set("msg", msg);
return jsonObj;
}
JSONObject buildMsg4(String userid, String storeName, Task task, String remark) {
Map<String, String> orderStatusMap = redisTemplate.opsForHash().entries(RedisKeyEnum.DICT_PREFIX.getVal() + RedisKeyEnum.ORDER_STATUS.getVal());
JSONObject jsonObj = new JSONObject();
jsonObj.set("agent_id", 2358374016L);
jsonObj.set("userid_list", userid);
JSONObject msg = new JSONObject();
JSONObject content = new JSONObject();
content.set("title", "工单催办提醒");
String markdown = StrUtil.format("#### 门店信息: **{}** [FullOfVitality]" +
" \n #### 任务编号:{}" +
" \n #### 报修人:{}" +
" \n #### 联系方式:{}" +
" \n #### 当前工单状态:{}" +
" \n #### 催办提醒:**{}**" +
" \n #### 发送时间:{}",
storeName, task.getUuid(), task.getRepairPeople(), task.getRepairPhone(), orderStatusMap.get(task.getStatus().toString()), remark, DateUtil.now());
content.set("markdown", markdown);
content.set("btn_orientation", "1");
JSONArray jsonArray = new JSONArray();
jsonArray.add(new JSONObject().set("title", "查看详情").set("action_url", "https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=dingkrzwks0jpi2di3uo&response_type=code&scope=snsapi_auth&state=STATE&redirect_uri=https%3A%2F%2Fyunwei.vionyun.com%3A8443%2Fyunwei%2Fapi%2Fding%2Fcallback%2Finside%3FstoreId%3D" + task.getStoreId() + "%26taskId%3D" + task.getId()));
content.set("btn_json_list", jsonArray);
msg.set("msgtype", "action_card");
msg.set("action_card", content);
jsonObj.set("msg", msg);
return jsonObj;
}
......
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!