Commit 5c2bc610 zshaohui

1.迈征对接功能提交

2.虚拟仓增加盘点功能
1 个父辈 e5e54a0c
正在显示 29 个修改的文件 包含 1013 行增加6 行删除
...@@ -314,6 +314,12 @@ public class DataInitManager { ...@@ -314,6 +314,12 @@ public class DataInitManager {
//内仓线外入库 //内仓线外入库
addNewFunctionMenu(134,null,"bcVirWarehous","虚拟仓","bcVirWarehous","virWarehous/virWarehous/index","feeding",functionMenuMap); addNewFunctionMenu(134,null,"bcVirWarehous","虚拟仓","bcVirWarehous","virWarehous/virWarehous/index","feeding",functionMenuMap);
Menu virMent = Menu.CreatePMenu("虚拟仓", 17, "bcVir", 3, "virwourse",null);
addNewFunctionMenu(1,virMent,"bcVir","虚拟仓","bcVirWarehousNew","virWarehous/virWarehous/index","feeding",functionMenuMap);
addNewFunctionMenu(2,virMent,"virSelfAudit","盘点","virSelfAudit","virWarehous/selfAudit/index","selfAudit",functionMenuMap);
addNewFunctionMenu(3,virMent,"virSelfAuditReport"," 盘点报表","virSelfAuditReport","virWarehous/selfAuditReport/index","selfAuditReport",functionMenuMap);
//内外仓电子看板 //内外仓电子看板
//addNewFunctionMenu(1,null,"elecKanban", "电子看板","elecKanban", "elecKanban/index","kanban",functionMenuMap); //addNewFunctionMenu(1,null,"elecKanban", "电子看板","elecKanban", "elecKanban/index","kanban",functionMenuMap);
addNewFunctionMenu(135,null,"sysInventory", "盘点出库","sysInventory", "system/sysInventory/index","mIDList",functionMenuMap); addNewFunctionMenu(135,null,"sysInventory", "盘点出库","sysInventory", "system/sysInventory/index","mIDList",functionMenuMap);
......
...@@ -342,6 +342,8 @@ public class LiteOrderCache { ...@@ -342,6 +342,8 @@ public class LiteOrderCache {
liteOrderItem.setOutReelCount(liteOrderItem.getOutReelCount() + 1); liteOrderItem.setOutReelCount(liteOrderItem.getOutReelCount() + 1);
liteOrderItem.setTotalOutNum(liteOrderItem.getTotalOutNum() + task.getNum()); liteOrderItem.setTotalOutNum(liteOrderItem.getTotalOutNum() + task.getNum());
liteOrderItem.setTotalOutReelCount(liteOrderItem.getTotalOutReelCount() + 1); liteOrderItem.setTotalOutReelCount(liteOrderItem.getTotalOutReelCount() + 1);
liteOrderItem.setOutReel(task.getBarcode());
liteOrderItem.setPosition(task.getPosName());
liteOrderItem = liteOrderItemManager.save(liteOrderItem); liteOrderItem = liteOrderItemManager.save(liteOrderItem);
} }
liteOrderItems.add(liteOrderItem); liteOrderItems.add(liteOrderItem);
......
...@@ -4,6 +4,7 @@ import com.neotel.smfcore.common.base.IBaseManager; ...@@ -4,6 +4,7 @@ import com.neotel.smfcore.common.base.IBaseManager;
import com.neotel.smfcore.core.order.service.po.LiteOrderItem; import com.neotel.smfcore.core.order.service.po.LiteOrderItem;
import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Query;
import java.util.Collection;
import java.util.List; import java.util.List;
public interface ILiteOrderItemManager extends IBaseManager<LiteOrderItem> { public interface ILiteOrderItemManager extends IBaseManager<LiteOrderItem> {
...@@ -14,4 +15,6 @@ public interface ILiteOrderItemManager extends IBaseManager<LiteOrderItem> { ...@@ -14,4 +15,6 @@ public interface ILiteOrderItemManager extends IBaseManager<LiteOrderItem> {
int countByQuery(Query q); int countByQuery(Query q);
LiteOrderItem findOne(Query query); LiteOrderItem findOne(Query query);
Collection<LiteOrderItem> batchSave(List<LiteOrderItem> orderItemList);
} }
...@@ -13,6 +13,7 @@ import org.springframework.data.domain.Pageable; ...@@ -13,6 +13,7 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List; import java.util.List;
@Service @Service
...@@ -42,6 +43,12 @@ public class LiteOrderItemManagerImpl implements ILiteOrderItemManager { ...@@ -42,6 +43,12 @@ public class LiteOrderItemManagerImpl implements ILiteOrderItemManager {
} }
@Override @Override
public Collection<LiteOrderItem> batchSave(List<LiteOrderItem> orderItemList) {
return liteOrderItemDao.insertAll(orderItemList);
}
@Override
public LiteOrderItem get(String id) { public LiteOrderItem get(String id) {
return liteOrderItemDao.findOneById(id); return liteOrderItemDao.findOneById(id);
} }
......
...@@ -163,6 +163,19 @@ public class LiteOrder extends BasePo implements Serializable { ...@@ -163,6 +163,19 @@ public class LiteOrder extends BasePo implements Serializable {
private boolean maiZheng = false; private boolean maiZheng = false;
//迈征额外参数
private String guid;
private String processType;
private String cacheIndex;
private String cacheSlot;
private String recvIndex;
private String count;
private String dia;
private String startTime;
private String reelBoxId;
public void setClosed(boolean value){ public void setClosed(boolean value){
this.closed=value; this.closed=value;
if(value){ if(value){
......
...@@ -222,6 +222,23 @@ public class LiteOrderItem extends BasePo implements Serializable ,Comparable<Li ...@@ -222,6 +222,23 @@ public class LiteOrderItem extends BasePo implements Serializable ,Comparable<Li
private Date receiveDate; private Date receiveDate;
private String station;
/**
* 对应出库的物料
*/
private String outReel;
private String width;
private String dia;
private String position;
/** /**
* 出库是否满足要求,已出库数量大于需求数量 * 出库是否满足要求,已出库数量大于需求数量
*/ */
......
...@@ -27,6 +27,8 @@ public interface IStoragePosManager extends IBaseManager<StoragePos> { ...@@ -27,6 +27,8 @@ public interface IStoragePosManager extends IBaseManager<StoragePos> {
List<StoragePos> findNotEmptyByStorageId(String storageId); List<StoragePos> findNotEmptyByStorageId(String storageId);
List<StoragePos> findNotEmptyByStorageIdList(List<String> storageIdList);
List<StoragePos> findLockPos(String lockId); List<StoragePos> findLockPos(String lockId);
StoragePos findPartNumberInStorages(List<String> storageIdList, String pn, Collection<String> excludePosIds, CHECKOUT_TYPE checkOutType); StoragePos findPartNumberInStorages(List<String> storageIdList, String pn, Collection<String> excludePosIds, CHECKOUT_TYPE checkOutType);
......
...@@ -298,6 +298,18 @@ public class StoragePosManagerImpl implements IStoragePosManager { ...@@ -298,6 +298,18 @@ public class StoragePosManagerImpl implements IStoragePosManager {
return storagePosDao.findByQuery(query); return storagePosDao.findByQuery(query);
} }
@Override
public List<StoragePos> findNotEmptyByStorageIdList(List<String> storageIdList) {
Criteria c = Criteria.where("barcode").exists(true)
.and("enabled").is(true);//可用;
if (storageIdList != null && !storageIdList.isEmpty()){
c = c.and("storageId").in(storageIdList);
}
Query query = new Query(c);
//query.with(Sort.by(Sort.Direction.ASC, "updateDate"));
return storagePosDao.findByQuery(query);
}
@Override @Override
public List<StoragePos> findLockPos(String lockId) { public List<StoragePos> findLockPos(String lockId) {
......
...@@ -14,6 +14,7 @@ import com.neotel.smfcore.core.system.service.po.AlarmInfo; ...@@ -14,6 +14,7 @@ import com.neotel.smfcore.core.system.service.po.AlarmInfo;
import com.neotel.smfcore.core.system.service.po.DataLog; import com.neotel.smfcore.core.system.service.po.DataLog;
import com.neotel.smfcore.core.system.service.po.Humiture; import com.neotel.smfcore.core.system.service.po.Humiture;
import com.neotel.smfcore.custom.lizhen.innerBox.bean.VirImportLog; import com.neotel.smfcore.custom.lizhen.innerBox.bean.VirImportLog;
import com.neotel.smfcore.custom.lizhen.virtual.bean.VirInventory;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
...@@ -106,7 +107,8 @@ public class DbBackupService { ...@@ -106,7 +107,8 @@ public class DbBackupService {
InListItem.class, InListItem.class,
Message.class, Message.class,
AlarmInfo.class, AlarmInfo.class,
VirImportLog.class VirImportLog.class,
VirInventory.class
); );
dataCache.updateCache(Constants.LAST_BACKUP_TIME_KEY,new Date()); dataCache.updateCache(Constants.LAST_BACKUP_TIME_KEY,new Date());
processing = false; processing = false;
......
...@@ -56,6 +56,10 @@ public class StorageExportUtil { ...@@ -56,6 +56,10 @@ public class StorageExportUtil {
} }
} }
public static String getMaizhengExport(){
return maizhengExport;
}
//出料口名称 //出料口名称
private final static List<String> exportStrArr = Arrays.asList("MU1_1", "MU4_1", "MU2_1", "MU5_1", "MU1_2", "MU4_2", "MU5_2", "MU3_1"); private final static List<String> exportStrArr = Arrays.asList("MU1_1", "MU4_1", "MU2_1", "MU5_1", "MU1_2", "MU4_2", "MU5_2", "MU3_1");
......
package com.neotel.smfcore.custom.lizhen.third.maicheng.api; package com.neotel.smfcore.custom.lizhen.third.maicheng.api;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.neotel.smfcore.common.exception.ApiException;
import com.neotel.smfcore.common.utils.HttpHelper; import com.neotel.smfcore.common.utils.HttpHelper;
import com.neotel.smfcore.core.order.service.po.LiteOrder;
import com.neotel.smfcore.core.order.service.po.LiteOrderItem;
import com.neotel.smfcore.custom.lizhen.third.maicheng.bean.StationStatus; import com.neotel.smfcore.custom.lizhen.third.maicheng.bean.StationStatus;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import springfox.documentation.spring.web.json.Json;
import java.util.Arrays; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j @Slf4j
@Component @Component
...@@ -19,6 +21,13 @@ public class MaiZhengApi { ...@@ -19,6 +21,13 @@ public class MaiZhengApi {
@Value("${maizheng.stationStatusApi}") @Value("${maizheng.stationStatusApi}")
private String stationStatusApi = ""; private String stationStatusApi = "";
@Value("${maizheng.transReelBoxApi}")
private String transReelBoxApi = "";
@Value("${maizheng.prepareReelBoxApi}")
private String prepareReelBoxApi = "";
/** /**
* 获取站位状态接口 * 获取站位状态接口
* *
...@@ -43,4 +52,57 @@ public class MaiZhengApi { ...@@ -43,4 +52,57 @@ public class MaiZhengApi {
} }
return null; return null;
} }
public String transReelBox(LiteOrder liteOrder) {
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("GUID", liteOrder.getGuid());
paramMap.put("CacheIndex", liteOrder.getCacheIndex());
paramMap.put("CacheSlot", liteOrder.getCacheSlot());
paramMap.put("RecvIndex", liteOrder.getRecvIndex());
paramMap.put("Count", liteOrder.getCount());
paramMap.put("ReelBoxID", liteOrder.getReelBoxId());
paramMap.put("Dia", liteOrder.getDia());
paramMap.put("StartTime", liteOrder.getStartTime());
List<Map<String, Object>> list = new ArrayList<>();
List<LiteOrderItem> orderItemList = liteOrder.getOrderItems();
for (LiteOrderItem orderItem : orderItemList) {
Map<String, Object> itemMap = new HashMap<>();
itemMap.put("Position", orderItem.getPosition());
itemMap.put("PARTNUMBER", orderItem.getPn());
itemMap.put("REEL", orderItem.getReel());
itemMap.put("REELNew", orderItem.getOutReel());
itemMap.put("Width", orderItem.getWidth());
itemMap.put("Dia", orderItem.getDia());
list.add(itemMap);
}
paramMap.put("List", list);
log.info("智能仓储备料完成后请求发料入参为:" + JSONObject.toJSONString(paramMap) + "地址为:" + transReelBoxApi);
try {
String result = HttpHelper.postJson(transReelBoxApi, paramMap);
log.info("智能仓储备料完成后请求发料返回为:" + result);
JSONObject jsonObject = JSONObject.parseObject(result);
return jsonObject.getString("Result");
} catch (ApiException e) {
log.error("智能仓储备料完成后请求发料报错:" + e.getMessage());
return e.getMessage();
}
}
public void prepareReelBox(String guid, String result) {
Map<String,Object> paramMap = new HashMap<>();
paramMap.put("GUID",guid);
paramMap.put("Result",result);
log.info("仓储回复可以开始备料入参为:"+ JSON.toJSONString(paramMap));
try {
String resultStr = HttpHelper.postJson(prepareReelBoxApi, paramMap);
log.info("仓储回复可以开始备料返回为:"+resultStr);
} catch (ApiException e) {
log.error("仓储回复可以开始备料报错:" + e.getMessage());
}
}
} }
package com.neotel.smfcore.custom.lizhen.third.maicheng.bean;
import lombok.Data;
import java.util.List;
@Data
public class AskReelBox {
private String GUID;
private String ProcessType;
private String CacheIndex;
private String CacheSlot;
private String RecvIndex;
private String Count;
private String Dia;
private String StartTime;
private List<AskReelBoxList> List;
}
package com.neotel.smfcore.custom.lizhen.third.maicheng.bean;
import lombok.Data;
@Data
public class AskReelBoxList {
private String ID;
private String WORKORDERNO;
private String LINE;
private String MACHINENAME;
private String STATION;
private String SIDE;
private String SLOT;
private String SUBSLOT;
private String PARTNUMBER;
private String LEFTQTY;
private String LEFTPCBS;
private String LEFTTIMES;
private String PRIORITY;
private String OP;
private String PRODUCTBOARDS;
private String REEL;
private String STATUS;
private String MACHINETYPE;
private String RECIEVETYPE;
private String VENDOR;
private String Pitch;
private String Num;
private String Width;
private String Dia;
}
...@@ -2,8 +2,18 @@ package com.neotel.smfcore.custom.lizhen.third.maicheng.controller; ...@@ -2,8 +2,18 @@ package com.neotel.smfcore.custom.lizhen.third.maicheng.controller;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.neotel.smfcore.common.bean.ResultBean; import com.neotel.smfcore.common.bean.ResultBean;
import com.neotel.smfcore.common.utils.StringUtils;
import com.neotel.smfcore.core.order.LiteOrderCache;
import com.neotel.smfcore.core.order.service.manager.ILiteOrderItemManager;
import com.neotel.smfcore.core.order.service.manager.ILiteOrderManager;
import com.neotel.smfcore.core.order.service.po.LiteOrder;
import com.neotel.smfcore.core.order.service.po.LiteOrderItem;
import com.neotel.smfcore.custom.lizhen.innerBox.util.StorageExportUtil;
import com.neotel.smfcore.custom.lizhen.third.maicheng.api.MaiZhengApi; import com.neotel.smfcore.custom.lizhen.third.maicheng.api.MaiZhengApi;
import com.neotel.smfcore.custom.lizhen.third.maicheng.bean.AskReelBox;
import com.neotel.smfcore.custom.lizhen.third.maicheng.bean.AskReelBoxList;
import com.neotel.smfcore.custom.lizhen.third.maicheng.bean.StationStatus; import com.neotel.smfcore.custom.lizhen.third.maicheng.bean.StationStatus;
import com.neotel.smfcore.custom.lizhen.third.maicheng.util.StationStatusCache; import com.neotel.smfcore.custom.lizhen.third.maicheng.util.StationStatusCache;
import com.neotel.smfcore.security.annotation.AnonymousAccess; import com.neotel.smfcore.security.annotation.AnonymousAccess;
...@@ -14,8 +24,14 @@ import org.springframework.web.bind.annotation.RequestBody; ...@@ -14,8 +24,14 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Slf4j @Slf4j
@RestController @RestController
...@@ -28,6 +44,15 @@ public class MaiZhengController { ...@@ -28,6 +44,15 @@ public class MaiZhengController {
@Autowired @Autowired
private MaiZhengApi maiZhengApi; private MaiZhengApi maiZhengApi;
@Autowired
private LiteOrderCache liteOrderCache;
@Autowired
private ILiteOrderManager liteOrderManager;
@Autowired
private ILiteOrderItemManager liteOrderItemManager;
@ApiOperation("修改站位状态信息") @ApiOperation("修改站位状态信息")
@RequestMapping("/updateStationStatus") @RequestMapping("/updateStationStatus")
@AnonymousAccess @AnonymousAccess
...@@ -47,4 +72,127 @@ public class MaiZhengController { ...@@ -47,4 +72,127 @@ public class MaiZhengController {
maiZhengApi.StationStatus(); maiZhengApi.StationStatus();
return ResultBean.newOkResult(""); return ResultBean.newOkResult("");
} }
@ApiOperation("开始备料")
@RequestMapping("/askReelBox")
@AnonymousAccess
public Map<String, String> askReelBox(@RequestBody AskReelBox askReelBox) {
log.error("收到迈征请求数据为:" + JSON.toJSONString(askReelBox));
String result = "OK";
/* //获取到唯一id,当做工单号
String guid = askReelBox.getGUID();
if (askReelBoxMap.get(guid) != null){
log.info("当前guid已存在:"+guid);
} else {
LiteOrder liteOrder = liteOrderManager.findByOrderNo(guid);
if (liteOrder == null) {
List<AskReelBoxList> boxList = askReelBox.getList();
if (boxList == null || boxList.isEmpty()) {
log.info(guid+"List为空");
result = "List不能为空";
}
} else {
if (liteOrder.getOrderItems() != null && !liteOrder.getOrderItems().isEmpty()) {
log.info(guid+"已经存在");
result = guid + "已经存在";
}
}
}
if ("OK".equals(result)){
askReelBoxMap.put(guid,askReelBox);
}*/
askReelBoxMap.put(askReelBox.getGUID(), askReelBox);
Map<String, String> resultMap = new HashMap<>();
resultMap.put("GUID", askReelBox.getGUID());
resultMap.put("Result", result);
return resultMap;
}
Map<String,AskReelBox> askReelBoxMap = Maps.newConcurrentMap();
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);
@PostConstruct
void init(){
scheduledThreadPool.scheduleAtFixedRate(() -> {
if (askReelBoxMap != null && !askReelBoxMap.isEmpty()){
for (Map.Entry<String, AskReelBox> entry : askReelBoxMap.entrySet()) {
log.info("开始处理:"+entry.getKey()+"的数据");
String result = createMaiZhengOrder(entry.getKey(), entry.getValue());
maiZhengApi.prepareReelBox(entry.getKey(),result);
log.info("处理结束:"+entry.getKey()+"的数据,结果为:"+result);
}
}
},10,5, TimeUnit.SECONDS);
}
private String createMaiZhengOrder(String guid, AskReelBox askReelBox) {
LiteOrder liteOrder = liteOrderManager.findByOrderNo(guid);
if (liteOrder == null) {
List<AskReelBoxList> boxList = askReelBox.getList();
if (boxList == null || boxList.isEmpty()) {
log.info(guid + "List为空");
askReelBoxMap.remove(guid);
return "List不能为空";
}
} else {
if (liteOrder.getOrderItems() != null && !liteOrder.getOrderItems().isEmpty()) {
log.info(guid + "已经存在");
askReelBoxMap.remove(guid);
return guid + "已经存在";
}
}
if (liteOrder == null) {
liteOrder = new LiteOrder();
}
liteOrder.setOrderNo(askReelBox.getGUID());
liteOrder.setGuid(askReelBox.getGUID());
liteOrder.setCacheIndex(askReelBox.getCacheIndex());
liteOrder.setCacheSlot(askReelBox.getCacheSlot());
liteOrder.setRecvIndex(askReelBox.getRecvIndex());
liteOrder.setCount(askReelBox.getCount());
liteOrder.setReelBoxId(StorageExportUtil.getMaizhengExport());
liteOrder.setDia(askReelBox.getDia());
liteOrder.setStartTime(askReelBox.getStartTime());
liteOrder.setMaiZheng(true);
liteOrder = liteOrderManager.save(liteOrder);
//开始设置工单数据
List<LiteOrderItem> orderItemList = new ArrayList<>();
for (AskReelBoxList box : askReelBox.getList()) {
LiteOrderItem item = new LiteOrderItem();
item.setWarningItemId(box.getID());
item.setMo(box.getWORKORDERNO());
if (StringUtils.isBlank(liteOrder.getLine()) && StringUtils.isNotBlank(box.getLINE())) {
liteOrder.setLine(box.getLINE());
}
item.setLine(box.getLINE());
item.setMachineName(box.getMACHINENAME());
item.setStation(box.getSTATION());
item.setSide(box.getSIDE());
item.setSlot(box.getSLOT());
item.setSubSlot(box.getSUBSLOT());
item.setPn(box.getPARTNUMBER());
item.setReel(box.getREEL());
item.setWidth(box.getWidth());
item.setDia(box.getDia());
item.setOrderId(liteOrder.getId());
item.setOrderNo(liteOrder.getOrderNo());
item.setNeedReelCount(1);
item.setNeedNum(1);
orderItemList.add(item);
}
orderItemList = (List<LiteOrderItem>) liteOrderItemManager.batchSave(orderItemList);
liteOrder.setOrderItems(orderItemList);
liteOrder.setTotalTaskReelCount(orderItemList.size());
liteOrder = liteOrderManager.save(liteOrder);
liteOrderCache.addOrderToMap(liteOrder);
log.info(guid + "工单任务已经生成,任务数量为:" + orderItemList.size());
askReelBoxMap.remove(guid);
return "OK";
}
} }
package com.neotel.smfcore.custom.lizhen.third.maicheng.controller;
import com.neotel.smfcore.common.bean.ResultBean;
import com.neotel.smfcore.common.utils.StringUtils;
import com.neotel.smfcore.core.order.service.manager.ILiteOrderManager;
import com.neotel.smfcore.core.order.service.po.LiteOrder;
import com.neotel.smfcore.core.system.util.TaskService;
import com.neotel.smfcore.custom.lizhen.innerBox.bean.StorageExport;
import com.neotel.smfcore.custom.lizhen.innerBox.util.StorageExportUtil;
import com.neotel.smfcore.custom.lizhen.third.maicheng.api.MaiZhengApi;
import com.neotel.smfcore.security.annotation.AnonymousAccess;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/maizhengDevice")
@Api(tags = "设备端(迈征)")
public class MaiZhengDeviceController {
@Autowired
private TaskService taskService;
@Autowired
private ILiteOrderManager liteOrderManager;
@Autowired
private MaiZhengApi maiZhengApi;
@ApiOperation("请求迈征是否可以运送")
@RequestMapping("/transReelBox")
@AnonymousAccess
public ResultBean transReelBox(String exportStr) {
StorageExport export = StorageExportUtil.getExport(exportStr+StorageExportUtil.OUT_STATION);
String hSerial = export.getHSerial();
if (StringUtils.isBlank(hSerial)) {
return ResultBean.newErrorResult(-1, "smfcore.valueNotExist", "{0}[{1}]不存在", new String[]{exportStr, "hSerial"});
}
//判断任务是否完成
/*int taskCount = 0;
List<DataLog> dataLogList = taskService.getAllTasks();
if (dataLogList != null && !dataLogList.isEmpty()) {
for (DataLog dataLog : dataLogList) {
if (dataLog.isCheckOutTask() && hSerial.equals(dataLog.getSourceName())) {
if (!dataLog.isFinished() && !dataLog.isCancel()) {
taskCount = taskCount + 1;
}
}
}
}
if (taskCount > 0) {
return ResultBean.newErrorResult(-1, "smfcore.order.close.taskNotEnd", "工单还有未完成的任务");
}*/
LiteOrder liteOrder = liteOrderManager.findByOrderNo(hSerial);
if (liteOrder == null) {
return ResultBean.newErrorResult(-1, "smfcore.valueNotExist", "{0}[{1}]不存在", new String[]{"orderNo", hSerial});
}
//请求迈征的接口,是否可以放入
String resultStr = maiZhengApi.transReelBox(liteOrder);
if ("OK".equalsIgnoreCase(resultStr)){
return ResultBean.newOkResult("");
} else {
return ResultBean.newErrorResult(-1,"smf.maizheng.error","transReelBox返回异常:"+resultStr);
}
}
}
package com.neotel.smfcore.custom.lizhen.virtual.bean;
import com.neotel.smfcore.common.base.BasePo;
import lombok.Data;
import java.util.Date;
//虚拟仓盘点
@Data
public class VirInventory extends BasePo {
/**
* 是否盘点
*/
private boolean inventoryFinished = false;
/**
* 厂别
*/
private String plant;
/**
* 厂区
*/
private String factory;
/**
* 库别
*/
private String wareHouseCode;
/**
* 料号
*/
private String partNumber;
/**
* 二维码资料
*/
private String fullCode;
/**
* 储位
*/
private String posName;
/**
* 数量
*/
private int amount;
/**
* 盘点时间
*/
private Date inventoryDate;
/**
* 工号
*/
private String workerNo;
/**
* 盘点批次
*/
private String batch;
/**
* 唯一码
*/
private String barcode;
}
package com.neotel.smfcore.custom.lizhen.virtual.bean.dto;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import java.util.Date;
@Data
@ApiOperation("虚拟仓盘点")
public class VirInventoryDto {
/**
* 是否盘点
*/
private boolean inventoryFinished = false;
/**
* 厂别
*/
private String plant;
/**
* 厂区
*/
private String factory;
/**
* 库别
*/
private String wareHouseCode;
/**
* 料号
*/
private String partNumber;
/**
* 二维码资料
*/
private String fullCode;
/**
* 储位
*/
private String posName;
/**
* 数量
*/
private int amount;
/**
* 盘点时间
*/
private Date inventoryDate;
/**
* 工号
*/
private String workerNo;
/**
* 盘点批次
*/
private String batch;
/**
* 唯一码
*/
private String barcode;
}
package com.neotel.smfcore.custom.lizhen.virtual.bean.mapstruct;
import com.neotel.smfcore.common.base.BaseMapper;
import com.neotel.smfcore.custom.lizhen.virtual.bean.VirInventory;
import com.neotel.smfcore.custom.lizhen.virtual.bean.dto.VirInventoryDto;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;
@Mapper(componentModel = "spring" ,unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface VirInventoryMapper extends BaseMapper<VirInventoryDto, VirInventory> {
}
package com.neotel.smfcore.custom.lizhen.virtual.bean.query;
import com.neotel.smfcore.common.annotation.QueryCondition;
import com.neotel.smfcore.common.bean.BetweenData;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
@Data
public class VirInventoryQuery {
@QueryCondition(blurry = "wareHouseCode")
private String wareHouseCode;
@QueryCondition(type = QueryCondition.Type.BETWEEN, propName = "createDate")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private BetweenData<Date> inventoryDate;
@QueryCondition(blurry = "workerNo")
private String workerNo;
}
package com.neotel.smfcore.custom.lizhen.virtual.controller;
import com.neotel.smfcore.common.bean.PageData;
import com.neotel.smfcore.common.bean.ResultBean;
import com.neotel.smfcore.common.utils.DateUtil;
import com.neotel.smfcore.common.utils.QueryHelp;
import com.neotel.smfcore.common.utils.StringUtils;
import com.neotel.smfcore.core.barcode.service.po.Barcode;
import com.neotel.smfcore.core.barcode.utils.CodeResolve;
import com.neotel.smfcore.core.device.util.DataCache;
import com.neotel.smfcore.core.storage.service.manager.IStoragePosManager;
import com.neotel.smfcore.core.storage.service.po.Storage;
import com.neotel.smfcore.core.storage.service.po.StoragePos;
import com.neotel.smfcore.custom.lizhen.virtual.bean.VirInventory;
import com.neotel.smfcore.custom.lizhen.virtual.bean.mapstruct.VirInventoryMapper;
import com.neotel.smfcore.custom.lizhen.virtual.bean.query.VirInventoryQuery;
import com.neotel.smfcore.custom.lizhen.virtual.service.manager.IVirInventoryManager;
import com.neotel.smfcore.custom.lizhen.virtual.util.VirInventoryUtil;
import com.neotel.smfcore.security.annotation.AnonymousAccess;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Api(tags = "虚拟仓盘点")
@RequestMapping("/virInventory")
@RestController
public class VirInventoryController {
//厂别
@Value("${bc.plant}")
private String BCPlant;
//厂区
@Value("${bc.factory}")
private String BCFactory;
@Autowired
private DataCache dataCache;
@Autowired
private IStoragePosManager storagePosManager;
@Autowired
private IVirInventoryManager virInventoryManager;
@Autowired
private CodeResolve codeResolve;
@Autowired
private VirInventoryMapper virInventoryMapper;
@ApiOperation("开始盘点")
@RequestMapping("/startInventory")
@AnonymousAccess
public ResultBean startInventory() {
//1.首先判断上一次盘点是否结束
String batch = dataCache.getCache(VirInventoryUtil.VIRINVENTORY_CACHE_BATCH);
if (StringUtils.isNotBlank(batch)) {
return ResultBean.newErrorResult(-1, "smfcore.inventory.noEnd", "当前盘点未结束,批次为[{0}],请检查", new String[]{batch});
}
//2.生成盘点批次
batch = DateUtil.toDateString(new Date(), "yyyy-MM-dd HH:mm:ss.SSS");
//3.查找虚拟仓id
List<String> storageIdList = new ArrayList<>();
for (Storage storage : dataCache.getAllStorage().values()) {
if (storage.isVirtual()) {
storageIdList.add(storage.getId());
}
}
if (storageIdList == null || storageIdList.isEmpty()) {
return ResultBean.newErrorResult(-1, "smfcore.virtual.notExist", "虚拟仓不存在");
}
//4.查找非空库位
List<StoragePos> storagePosList = storagePosManager.findNotEmptyByStorageIdList(storageIdList);
if (storagePosList == null || storagePosList.isEmpty()) {
return ResultBean.newErrorResult(-1, "smfcore.virtual.hasReelError", "虚拟仓中没有物料,请检查");
}
//5.生成盘点报表
List<VirInventory> virInventoryList = new ArrayList<>();
for (StoragePos pos : storagePosList) {
VirInventory virInventory = new VirInventory();
virInventory.setPlant(BCPlant);
virInventory.setFactory(BCFactory);
Barcode barcode = pos.getBarcode();
virInventory.setWareHouseCode(barcode.getWarehouseCode());
virInventory.setPartNumber(barcode.getPartNumber());
virInventory.setFullCode(barcode.getFullCode());
virInventory.setAmount(barcode.getAmount());
virInventory.setBatch(batch);
virInventory.setPosName(pos.getPosName());
virInventory.setBarcode(barcode.getBarcode());
virInventoryList.add(virInventory);
}
//6.保存数据
virInventoryManager.batchSave(virInventoryList);
dataCache.updateCache(VirInventoryUtil.VIRINVENTORY_CACHE_BATCH, batch);
return ResultBean.newOkResult(batch);
}
@ApiOperation("结束盘点")
@RequestMapping("/endInventory")
@AnonymousAccess
public ResultBean endInventory() {
dataCache.updateCache(VirInventoryUtil.VIRINVENTORY_CACHE_BATCH, "");
return ResultBean.newOkResult("");
}
@ApiOperation("盘点物料")
@RequestMapping("/reelInventory")
@AnonymousAccess
public ResultBean reelInventory(@RequestBody Map<String, String> paramMap) {
String code = paramMap.get("code");
String workerNo = paramMap.get("workerNo");
//1.判断工号是否存在
if (StringUtils.isBlank(workerNo)) {
return ResultBean.newErrorResult(-1, "smfcore.valueCanotNull", "{0}不能为空", new String[]{"工号"});
}
//2.解析条码内容
Barcode barcode = codeResolve.resolveCode(code);
if (barcode == null) {
return ResultBean.newErrorResult(-1, "smfcore.error.barcode.invalid", "{0}不是有效的条码", new String[]{code});
}
//3.判断是否有盘点的批次
String batch = dataCache.getCache(VirInventoryUtil.VIRINVENTORY_CACHE_BATCH);
if (StringUtils.isBlank(batch)) {
return ResultBean.newErrorResult(-1, "smfcore.inventory.noBatch", "当前没有要盘点的批次,请点击开始盘点");
}
//4.根据盘点批次和唯一码获取盘点内容
VirInventory virInventory = virInventoryManager.getByBatchAndBarcode(batch, barcode.getBarcode());
if (virInventory == null) {
return ResultBean.newErrorResult(-1, "smfcore.inventory.noReel", "物料[{0}]不在当前盘点的批次{1}中,请检查", new String[]{barcode.getBarcode(), batch});
}
if (virInventory.isInventoryFinished()) {
return ResultBean.newErrorResult(-1, "smfcore.inventory.finish", "物料[{0}]已盘点完成,批次为{1},请检查", new String[]{barcode.getBarcode(), batch});
}
virInventory.setInventoryFinished(true);
virInventory.setInventoryDate(new Date());
virInventory.setWorkerNo(workerNo);
//5.保存信息
virInventoryManager.save(virInventory);
return ResultBean.newOkResult("");
}
@ApiOperation("盘点报表明细")
@RequestMapping("/inventoryList")
@AnonymousAccess
public PageData<VirInventory> inventoryReportList(VirInventoryQuery query, Pageable pageable) {
Query q = QueryHelp.getQuery(query);
PageData<VirInventory> pageData = virInventoryManager.findByPage(q, pageable);
return pageData;
}
@ApiOperation("获取当前批次号")
@RequestMapping("/getCurrentBatch")
@AnonymousAccess
public ResultBean getCurrentBatch() {
Object cache = dataCache.getCache(VirInventoryUtil.VIRINVENTORY_CACHE_BATCH);
if (cache == null) {
return ResultBean.newOkResult("");
} else {
return ResultBean.newOkResult(cache.toString());
}
}
}
package com.neotel.smfcore.custom.lizhen.virtual.controller;
import com.neotel.smfcore.common.base.IExcelDownLoad;
import com.neotel.smfcore.common.bean.PageData;
import com.neotel.smfcore.common.bean.ResultBean;
import com.neotel.smfcore.common.utils.FileUtil;
import com.neotel.smfcore.common.utils.QueryHelp;
import com.neotel.smfcore.custom.lizhen.virtual.bean.VirInventory;
import com.neotel.smfcore.custom.lizhen.virtual.bean.query.VirInventoryQuery;
import com.neotel.smfcore.custom.lizhen.virtual.service.manager.IVirInventoryManager;
import com.neotel.smfcore.security.annotation.AnonymousAccess;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
@Api(tags = "虚拟仓盘点报表")
@RequestMapping("/virInventoryReport")
@RestController
@Slf4j
public class VirInventoryReportController {
@Autowired
private IVirInventoryManager virInventoryManager;
@ApiOperation("盘点报表明细")
@RequestMapping("/inventoryDetail")
@AnonymousAccess
public ResultBean inventoryDetail(VirInventoryQuery query) {
Query q = QueryHelp.getQuery(query);
List<VirInventory> inventoryList = virInventoryManager.findByQuery(q);
int alreadyInventory = 0;
int noInventory = 0;
if (inventoryList != null && !inventoryList.isEmpty()) {
for (VirInventory inventory : inventoryList) {
if (inventory.isInventoryFinished()) {
alreadyInventory = alreadyInventory + 1;
} else {
noInventory = noInventory + 1;
}
}
}
Map<String, Integer> resultMap = new HashMap<>();
resultMap.put("alreadyInventory", alreadyInventory);
resultMap.put("noInventory", noInventory);
return ResultBean.newOkResult(resultMap);
}
@ApiOperation("盘点报表明细导出")
@RequestMapping("/inventoryDetail/download")
@AnonymousAccess
public void inventoryDetailDownLoad(VirInventoryQuery query, Pageable pageable, HttpServletResponse response) {
Query q = QueryHelp.getQuery(query);
try {
FileUtil.downloadExcel(q, pageable, response, new IExcelDownLoad() {
@Override
public List<List<String>> getHeader() {
List<List<String>> headerList = new ArrayList<>();
headerList.add(Arrays.asList("盘点状态"));
headerList.add(Arrays.asList("厂别"));
headerList.add(Arrays.asList("厂区"));
headerList.add(Arrays.asList("库别"));
headerList.add(Arrays.asList("料号"));
headerList.add(Arrays.asList("二维码资料"));
headerList.add(Arrays.asList("唯一码"));
headerList.add(Arrays.asList("储位"));
headerList.add(Arrays.asList("数量"));
headerList.add(Arrays.asList("盘点时间"));
headerList.add(Arrays.asList("工号"));
headerList.add(Arrays.asList("盘点批次"));
return headerList;
}
@Override
public List<List<Object>> getPageData(Query query, Pageable pageable) {
List<List<Object>> dataList = new ArrayList<>();
List<VirInventory> virInventoryList = virInventoryManager.findByQuery(query, pageable);
for (VirInventory virInventory : virInventoryList) {
List<Object> list = new ArrayList<>();
list.add(virInventory.isInventoryFinished() ? "V" : "");
list.add(virInventory.getPlant());
list.add(virInventory.getFactory());
list.add(virInventory.getWareHouseCode());
list.add(virInventory.getPartNumber());
list.add(virInventory.getFullCode());
list.add(virInventory.getBarcode());
list.add(virInventory.getPosName());
list.add(virInventory.getAmount());
list.add(virInventory.getInventoryDate());
list.add(virInventory.getWorkerNo());
list.add(virInventory.getBatch());
dataList.add(list);
}
return dataList;
}
});
} catch (IOException e) {
log.error("盘点报表明细导出失败:" + e.getMessage());
}
}
}
package com.neotel.smfcore.custom.lizhen.innerBox.rest; package com.neotel.smfcore.custom.lizhen.virtual.controller;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpUtil; import cn.hutool.http.HttpUtil;
......
package com.neotel.smfcore.custom.lizhen.virtual.service.dao;
import com.neotel.smfcore.common.base.IBaseDao;
public interface IVirInventoryDao extends IBaseDao {
}
package com.neotel.smfcore.custom.lizhen.virtual.service.dao.impl;
import com.neotel.smfcore.common.base.AbstractBaseDao;
import com.neotel.smfcore.custom.lizhen.virtual.bean.VirInventory;
import com.neotel.smfcore.custom.lizhen.virtual.service.dao.IVirInventoryDao;
import org.springframework.stereotype.Service;
@Service
public class VirInventoryDaoImpl extends AbstractBaseDao implements IVirInventoryDao {
@Override
public Class getEntityClass() {
return VirInventory.class;
}
}
package com.neotel.smfcore.custom.lizhen.virtual.service.manager;
import com.neotel.smfcore.common.base.IBaseManager;
import com.neotel.smfcore.custom.lizhen.virtual.bean.VirInventory;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.query.Query;
import java.util.List;
public interface IVirInventoryManager extends IBaseManager<VirInventory> {
void batchSave(List<VirInventory> virInventoryList);
VirInventory getByBatchAndBarcode(String batch, String barcode);
List<VirInventory> findByQuery(Query query, Pageable pageable);
}
package com.neotel.smfcore.custom.lizhen.virtual.service.manager.impl;
import com.neotel.smfcore.common.bean.PageData;
import com.neotel.smfcore.common.exception.ValidateException;
import com.neotel.smfcore.core.barcode.service.po.Barcode;
import com.neotel.smfcore.custom.lizhen.virtual.bean.VirInventory;
import com.neotel.smfcore.custom.lizhen.virtual.service.dao.IVirInventoryDao;
import com.neotel.smfcore.custom.lizhen.virtual.service.manager.IVirInventoryManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class VirInventoryManagerImpl implements IVirInventoryManager {
@Autowired
private IVirInventoryDao virInventoryDao;
@Override
public VirInventory get(String id) {
return null;
}
@Override
public VirInventory save(VirInventory object) throws ValidateException {
return virInventoryDao.save(object);
}
@Override
public void delete(VirInventory object) throws ValidateException {
}
@Override
public PageData<VirInventory> findByPage(Query query, Pageable pageable) {
int count = virInventoryDao.countByQuery(query);
if (count == 0) {
return new PageData<>(new ArrayList<>(), count);
}
List list = virInventoryDao.findByQuery(query, pageable);
return new PageData<>(list, count);
}
@Override
public List<VirInventory> findByQuery(Query query) {
return virInventoryDao.findByQuery(query);
}
@Override
public void batchSave(List<VirInventory> virInventoryList) {
virInventoryDao.insertAll(virInventoryList);
}
@Override
public VirInventory getByBatchAndBarcode(String batch, String barcode) {
return virInventoryDao.findOne(new Query(Criteria.where("batch").is(batch).and("barcode").is(barcode)));
}
@Override
public List<VirInventory> findByQuery(Query query, Pageable pageable) {
return virInventoryDao.findByQuery(query, pageable);
}
}
package com.neotel.smfcore.custom.lizhen.virtual.util;
public class VirInventoryUtil {
//盘点批次缓存
public static final String VIRINVENTORY_CACHE_BATCH = "VirInventory_CACHE_Batch";
}
...@@ -276,3 +276,10 @@ smfcore.error.permissionPassword = \u6743\u9650\u5BC6\u7801\u9519\u8BEF; ...@@ -276,3 +276,10 @@ smfcore.error.permissionPassword = \u6743\u9650\u5BC6\u7801\u9519\u8BEF;
#smfclient.loadMaterialFailed=loading material failed:{0} #smfclient.loadMaterialFailed=loading material failed:{0}
#smfclient.checkingMaterialOk=checking material is ok:{0} #smfclient.checkingMaterialOk=checking material is ok:{0}
#smfclient.checkNg=checking material is ng:{0} #smfclient.checkNg=checking material is ng:{0}
smfcore.inventory.noEnd=\u5F53\u524D\u76D8\u70B9\u672A\u7ED3\u675F,\u6279\u6B21\u4E3A[{0}],\u8BF7\u68C0\u67E5
smfcore.virtual.notExist=\u865A\u62DF\u4ED3\u4E0D\u5B58\u5728
smfcore.virtual.hasReelError=\u865A\u62DF\u4ED3\u4E2D\u6CA1\u6709\u7269\u6599,\u8BF7\u68C0\u67E5
smfcore.inventory.noBatch=\u5F53\u524D\u6CA1\u6709\u8981\u76D8\u70B9\u7684\u6279\u6B21,\u8BF7\u70B9\u51FB\u5F00\u59CB\u76D8\u70B9
smfcore.inventory.noReel=\u7269\u6599[{0}]\u4E0D\u5728\u5F53\u524D\u76D8\u70B9\u7684\u6279\u6B21{1}\u4E2D,\u8BF7\u68C0\u67E5
smfcore.inventory.finish=\u7269\u6599[{0}]\u5DF2\u76D8\u70B9\u5B8C\u6210,\u6279\u6B21\u4E3A{1},\u8BF7\u68C0\u67E5
\ No newline at end of file \ No newline at end of file
...@@ -255,3 +255,10 @@ smfcore.equipmentView=\u8BBE\u5907\u4E92\u8054 ...@@ -255,3 +255,10 @@ smfcore.equipmentView=\u8BBE\u5907\u4E92\u8054
smfcore.greaterThanZero=\u6570\u91CF\u5FC5\u987B\u5927\u4E8E0 smfcore.greaterThanZero=\u6570\u91CF\u5FC5\u987B\u5927\u4E8E0
smfcore.error.virtualOut.num=\u6570\u91CF\u4E0D\u80FD\u8D85\u8FC7{0} smfcore.error.virtualOut.num=\u6570\u91CF\u4E0D\u80FD\u8D85\u8FC7{0}
smfcore.error.virtualOut.noItem=\u5DE5\u5355{0}\u4E2D\u672A\u627E\u5230\u5BF9\u5E94\u7684PN\u6216\u7269\u6599\u7F16\u53F7 smfcore.error.virtualOut.noItem=\u5DE5\u5355{0}\u4E2D\u672A\u627E\u5230\u5BF9\u5E94\u7684PN\u6216\u7269\u6599\u7F16\u53F7
smfcore.inventory.noEnd=\u5F53\u524D\u76D8\u70B9\u672A\u7ED3\u675F,\u6279\u6B21\u4E3A[{0}],\u8BF7\u68C0\u67E5
smfcore.virtual.notExist=\u865A\u62DF\u4ED3\u4E0D\u5B58\u5728
smfcore.virtual.hasReelError=\u865A\u62DF\u4ED3\u4E2D\u6CA1\u6709\u7269\u6599,\u8BF7\u68C0\u67E5
smfcore.inventory.noBatch=\u5F53\u524D\u6CA1\u6709\u8981\u76D8\u70B9\u7684\u6279\u6B21,\u8BF7\u70B9\u51FB\u5F00\u59CB\u76D8\u70B9
smfcore.inventory.noReel=\u7269\u6599[{0}]\u4E0D\u5728\u5F53\u524D\u76D8\u70B9\u7684\u6279\u6B21{1}\u4E2D,\u8BF7\u68C0\u67E5
smfcore.inventory.finish=\u7269\u6599[{0}]\u5DF2\u76D8\u70B9\u5B8C\u6210,\u6279\u6B21\u4E3A{1},\u8BF7\u68C0\u67E5
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!