Commit c70fdcf7 sunke

工单料出库和发料数量出错导致无法发送L状态

1 个父辈 6f3952a0
......@@ -36,8 +36,11 @@ public class InquiryShelfBean {
*/
public static void clearShelf(String hSerial){
if(hSerial != null){
log.info("清理["+hSerial+"]使用的过料架");
hSerialShelfMap.remove(hSerial);
Map<String, ShelfInfo> shelfMap = hSerialShelfMap.get(hSerial);
if(shelfMap != null){
log.info("清理["+hSerial+"]使用的过料架");
hSerialShelfMap.remove(hSerial);
}
}
}
......
package com.myproject.bean.update.qisda;
import com.myproject.bean.BaseMongoBean;
import com.myproject.util.StorageConstants;
import org.springframework.data.annotation.Transient;
import java.util.*;
......@@ -66,7 +67,7 @@ public class OutInfo extends BaseMongoBean {
/**
* 发料状态: 0=未发料 1=发料缺料 2=发料OK(需求单完成):首盘和补料,发料与需求单一致为发料OK, 分盘料出库后又入库即真实绑定与需求量一致为发料OK, 紧急料出库数量与需求数量一致为发料OK
*/
private int sendStatus = 0;
private int sendStatus = StorageConstants.SEND_STATUS.NEW;
/**
* 出仓料盘数量
......@@ -235,7 +236,11 @@ public class OutInfo extends BaseMongoBean {
}
public boolean isSendEnd(){
return sendStatus == 2;
return sendStatus == StorageConstants.SEND_STATUS.SEND_OK;
}
public boolean isClosed(){
return sendStatus == StorageConstants.SEND_STATUS.CLOSED;
}
public void setSendStatus(int sendStatus) {
......
......@@ -11,4 +11,10 @@ public interface IOutInfoDao extends IMongoDao {
OutInfo findByHSerial(String hSerial);
List<OutInfo> findUnEndOutInfos();
void updateStatus(String hSerial, int bindStatus, int sendStatus);
void updateTaskFinishNum(String hSerail, int taskFinishNum);
void updateOutReelNum(String hSerial, int outReelNum);
}
package com.myproject.dao.mongo.qisda.impl;
import com.myproject.bean.BaseMongoBean;
import com.myproject.bean.update.qisda.OutInfo;
import com.myproject.bean.update.qisda.OutItem;
import com.myproject.dao.mongo.AbstractMongoDao;
......@@ -8,6 +9,7 @@ import com.myproject.dao.mongo.qisda.IOutItemDao;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;
import java.util.List;
......@@ -35,6 +37,36 @@ public class OutIInfoDaoImpl extends AbstractMongoDao implements IOutInfoDao {
}
@Override
public synchronized void updateStatus(String hSerial, int bindStatus, int sendStatus){
Criteria c = Criteria.where("hSerial").is(hSerial);
Query query = Query.query(c);
Update update = Update.update("bindStatus",bindStatus).set("sendStatus",sendStatus);
updateFirst(query,update);
}
@Override
public void updateTaskFinishNum(String hSerail, int taskFinishNum){
update(hSerail, "taskFinishNum", taskFinishNum);
}
@Override
public void updateOutReelNum(String hSerial, int outReelNum){
update(hSerial, "outReelNum", outReelNum);
}
private void update(String hSerial, String key, int value){
Criteria c = Criteria.where("hSerial").is(hSerial);
Query query = Query.query(c);
Update update = Update.update(key,value);
updateFirst(query,update);
}
@Override
public synchronized <T extends BaseMongoBean> T save(T bean) {
return super.save(bean);
}
@Override
public Class getEntityClass() {
return OutInfo.class;
}
......
......@@ -673,4 +673,30 @@ public class StorageConstants {
}
/**
* 需求单发料状态
*/
public static class SEND_STATUS{
/**
* 新建
*/
public static int NEW = 0;
/**
* 发料缺料
*/
public static int SEND_LESS = 1;
/**
* 发料完成
*/
public static int SEND_OK = 2;
/**
* 需求单关闭
*/
public static int CLOSED = 3;
}
}
......@@ -5,6 +5,7 @@ import com.myproject.bean.update.qisda.OutInfo;
import com.myproject.bean.update.qisda.OutItem;
import com.myproject.dao.mongo.qisda.IOutInfoDao;
import com.myproject.dao.mongo.qisda.IOutItemDao;
import com.myproject.util.StorageConstants;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -107,11 +108,62 @@ public class OutInfoCache {
}
/**
* 任务开始时,初始化出库任务数
* @param hSerial
* @param outReelNum
*/
public void resetTaskNum(String hSerial, int outReelNum){
OutInfo outInfo = outInfoMap.get(hSerial);
if(outInfo != null){
outInfo.setOutReelNum(0);
outInfo.setTaskFinishNum(0);
outInfo.setTaskNum(outReelNum);
outInfoMap.put(hSerial, outInfo);
}
}
/**
* 任务出库数量+1
*/
public synchronized OutInfo incOutNum(String hSerial){
OutInfo outInfo = outInfoMap.get(hSerial);
if(outInfo != null){
int outReelNum = outInfo.getOutReelNum() + 1;
outInfo.setOutReelNum(outReelNum);
log.info("需求单["+outInfo.gethSerial()+"]任务出库数量:" + outInfo.getOutReelNum() + "/" + outInfo.getTaskNum());
outInfoMap.put(hSerial, outInfo);
outInfoDao.updateOutReelNum(hSerial,outReelNum);
return outInfo;
}
return null;
}
/**
* 任务发料数量+1
*/
public synchronized OutInfo incTaskFinishNum(String hSerial){
OutInfo outInfo = outInfoMap.get(hSerial);
if(outInfo != null){
int taskFinishNum = outInfo.getTaskFinishNum() + 1;
outInfo.setTaskFinishNum(taskFinishNum);
log.info("需求单["+outInfo.gethSerial()+"]任务发料数量:" + outInfo.getTaskFinishNum() + "/" + outInfo.getTaskNum());
outInfoMap.put(hSerial, outInfo);
outInfoDao.updateTaskFinishNum(hSerial,taskFinishNum);
return outInfo;
}
return null;
}
/**
* 更新需求单的发料状态
*/
public void updateStatus(String hSerial){
OutInfo outInfo = outInfoMap.get(hSerial);
if(outInfo != null){
if(outInfo.isClosed()){
log.info("更新需求单["+hSerial+"]已关闭,不更新发料状态");
return;
}
log.info("更新需求单["+hSerial+"]的发料状态 [" + outInfo.getSendStatus()+"]");
boolean sendEnd = true;
boolean hasOut = false;
......@@ -134,33 +186,23 @@ public class OutInfoCache {
}
}
if(sendEnd){
outInfo.setSendStatus(2);
outInfo.setSendStatus(StorageConstants.SEND_STATUS.SEND_OK);
}else{
if(hasOut){
//有出库的,状态为发料缺料
outInfo.setSendStatus(1);
outInfo.setSendStatus(StorageConstants.SEND_STATUS.SEND_LESS);
}else{
//无出过库的,状态为未发料
outInfo.setSendStatus(0);
outInfo.setSendStatus(StorageConstants.SEND_STATUS.NEW);
}
}
outInfo.setBindStatus(bindStatus);
log.info("需求单状态更新:"+outInfo+" ");
outInfoMap.put(outInfo.gethSerial(),outInfo);
OutInfo dbOutInfo = outInfoDao.findOneById(outInfo.getId());
if(dbOutInfo != null){
if(dbOutInfo.getSendStatus() != outInfo.getSendStatus() || dbOutInfo.getBindStatus() != outInfo.getBindStatus()){
dbOutInfo.setSendStatus(outInfo.getSendStatus());
dbOutInfo.setBindStatus(outInfo.getBindStatus());
outInfoDao.save(dbOutInfo);
log.info("需求单["+hSerial+"]状态与数据库不一致,更新到数据库");
if(dbOutInfo.isSendEnd()){
outInfoMap.remove(dbOutInfo.gethSerial());
InquiryShelfBean.clearShelf(dbOutInfo.gethSerial());
log.info("需求单["+hSerial+"]发料已完成,从缓存中清除,同时清理使用过的料串");
}
}
outInfoDao.updateStatus(outInfo.gethSerial(),outInfo.getBindStatus(), outInfo.getSendStatus());
if(outInfo.isSendEnd()){
outInfoMap.remove(outInfo.gethSerial());
InquiryShelfBean.clearShelf(outInfo.gethSerial());
log.info("需求单["+hSerial+"]发料已完成,从缓存中清除,同时清理使用过的料串");
}
}
}
......
......@@ -8,6 +8,7 @@ import com.google.common.collect.Multiset;
import com.myproject.bean.CodeBean;
import com.myproject.bean.json.InventoryItem;
import com.myproject.bean.json.PlateSizeBean;
import com.myproject.bean.qisda.ResultBean;
import com.myproject.bean.update.*;
import com.myproject.dao.mongo.*;
import com.myproject.exception.ValidateException;
......@@ -338,7 +339,7 @@ public class DataCache{
throw new ValidateException("档案不存在");
}
codeBeanFromRule.setShowImg(component.getShowImg());
//codeBeanFromRule.setShowImg(component.getShowImg());
Date produceDate = barcodeFromRule.getProduceDate();
if(produceDate != null && barcodeFromRule.getExpireDate() == null){
int validDay = component.getValidDay();
......@@ -378,6 +379,33 @@ public class DataCache{
return codeBeanFromRule;
}
/**
* 从条码信息中解析出一个有效条码
* @param codeStr
* @return
*/
public Barcode resolveOneValideBarcode(String codeStr) throws ValidateException{
if(org.apache.logging.log4j.util.Strings.isBlank(codeStr)){
throw new ValidateException("未扫到条码");
}
Collection<CodeBean> codeBeans = resolveCodeStr(codeStr);
Barcode barcode = null;
for (CodeBean codeBean : codeBeans) {
if(codeBean.isValid()){
if(barcode == null){
barcode = codeBean.getBarcode();
}else{
throw new ValidateException("找到多个有效的条码");
}
}
}
if(barcode == null){
throw new ValidateException("未找到有效的条码");
}
return barcode;
}
public Collection<CodeBean> resolveCodeStr(String codeStr){
Map<String, CodeBean> codeBeanMap = Maps.newHashMap();
......@@ -492,20 +520,6 @@ public class DataCache{
private static Map<String, Storage> allStorage = new ConcurrentHashMap<>();
/**
* 某个区域需要进行清理呆滞物料的所有料仓(虚拟仓应该不需要清理的)
*/
public List<String> needClearInactionStorageIds(){
Collection<Storage> allStorage = getAllStorage().values();
List<String> storageIds = Lists.newArrayList();
for (Storage storage : allStorage){
//if(storage.isLine() && storage.getAreaId().equals(areaId)){
storageIds.add(storage.getId());
//}
}
return storageIds;
}
public Map<String, Storage> getAllStorage(){
if(allStorage.isEmpty()){
synchronized (allStorage){
......
......@@ -249,6 +249,7 @@ public class QisdaApiController extends BaseController {
barcode.setAppendInfo(appendInfo);
pos.setBarcode(barcode);
storagePosDao.save(pos);
outItem.setLockQty(barcode.getAmount());
outItem.setRealLockQty(barcode.getAmount());
outItem = outItemDao.save(outItem);
......@@ -885,7 +886,7 @@ public class QisdaApiController extends BaseController {
task = dataLogDao.save(task);
tasks.add(task);
sendQty = sendQty + posBarcode.getAmount();
if(sendQty > outItem.getQty()){
if(sendQty >= outItem.getQty()){
break;
}
}
......@@ -1041,6 +1042,8 @@ public class QisdaApiController extends BaseController {
outInfo.setTaskNum(outReelNum);
outInfo = outInfoDao.save(outInfo);
outInfoCache.resetTaskNum(hSerial, outReelNum);
//先出小料盘,再出大料盘
for (DataLog task : tasks) {
if(task.isSmallReel()){
......
......@@ -107,27 +107,7 @@ public class QisdaDeviceController extends BaseController {
//清空扫码缓存信息
updateScanTask(robotIndex, null);
Collection<CodeBean> codeBeans = dataCache.resolveCodeStr(barcodeStr);
Barcode barcode = null;
for (CodeBean codeBean : codeBeans) {
if(codeBean.isValid()){
if(barcode == null){
barcode = codeBean.getBarcode();
}else{
String msg = "找到多个有效的条码";
log.error(msg);
return ResultBean.newErrorResult(101, msg);
}
}
}
if(barcode == null){
String msg = "未找到有效的条码";
log.error(msg);
return ResultBean.newErrorResult(102, msg);
}
Barcode barcode = dataCache.resolveOneValideBarcode(barcodeStr);
//防止条码重复发送,现在已经不需要了
// boolean firstScanSame = isSameTask(barcode,firstScanTask);
......@@ -495,7 +475,34 @@ public class QisdaDeviceController extends BaseController {
}
/**
* 分盘料/紧急料放上料串或料架时调用
* 查找包装料架的剩余任务数
*/
@RequestMapping(value = "/packageShelfTask")
@ResponseBody
public ResultBean packageShelfTask(HttpServletRequest request) {
String rfid = request.getParameter("rfid");
if(rfid == null){
rfid = "";
}
//InquiryShelfBean.findSameShelf()
ShelfInfo shelfInfo = InquiryShelfBean.findSameShelf(InquiryShelfBean.URGENT_SHELF_MAP_KEY,rfid);
if(shelfInfo == null){
shelfInfo = InquiryShelfBean.findSameShelf(InquiryShelfBean.CUT_SHELF_MAP_KEY,rfid);
}
String tempRfid = "";
if(shelfInfo != null){
tempRfid = shelfInfo.tempRfid();
}
Map<String,Object> resultMap = new HashMap<>();
resultMap.put("tempRfid", tempRfid);
return ResultBean.newOkResult(resultMap);
}
/**
* 查找料架的TempRfid,用于流水线重启时决定当前料串是否可用
*/
@RequestMapping(value = "/findTempRfid")
@ResponseBody
......@@ -543,20 +550,22 @@ public class QisdaDeviceController extends BaseController {
@RequestMapping(value = "/cancelPutInTask")
@ResponseBody
public ResultBean cancelPutInTask(HttpServletRequest request) {
String barcode = request.getParameter("barcode");
if(Strings.isBlank(barcode)){
return ResultBean.newErrorResult(2001,"未找到参数barcode");
}
Collection<DataLog> queueTasks = taskService.getQueueTasks();
for (DataLog queueTask : queueTasks) {
if(queueTask.isPutInTask() && queueTask.getBarcode().equals(barcode)){
//只能取消入库任务
boolean cancelResult = taskService.cancelTask(queueTask.getId());
log.info("客户端取消["+barcode+"]的入库任务结果:" + cancelResult);
return ResultBean.newOkResult(cancelResult);
String codeStr = request.getParameter("barcode");
try{
Barcode barcode = dataCache.resolveOneValideBarcode(codeStr);
Collection<DataLog> queueTasks = taskService.getQueueTasks();
for (DataLog queueTask : queueTasks) {
if(queueTask.isPutInTask() && queueTask.getBarcode().equals(barcode)){
//只能取消入库任务
boolean cancelResult = taskService.cancelTask(queueTask.getId());
log.info("客户端取消["+barcode+"]的入库任务结果:" + cancelResult);
return ResultBean.newOkResult(cancelResult);
}
}
}catch (Exception e){
return ResultBean.newErrorResult(2002, "任务["+codeStr+"]取消失败:" + e.getMessage());
}
return ResultBean.newErrorResult(2002, "任务["+barcode+"]取消失败");
return ResultBean.newErrorResult(2003, "任务["+codeStr+"]取消失败");
}
/**
......@@ -596,6 +605,10 @@ public class QisdaDeviceController extends BaseController {
int urgentPackageTask = 0;
int cutTask = 0;
int urgentTask = 0;
//总的分盘和紧急料数量
int totalCutTask = 0;
int totalUrgentTask = 0;
List<DataLog> allTasks = taskService.getAllTasks();
for (DataLog unFinishedTask : allTasks) {
if(!unFinishedTask.isFinished() && !unFinishedTask.isCancel() && unFinishedTask.isCheckOutTask()){
......@@ -603,14 +616,18 @@ public class QisdaDeviceController extends BaseController {
if(unFinishedTask.getCid().equals(cid)){
if(unFinishedTask.isCutReel()){
cutPackageTask = cutPackageTask + 1;
totalCutTask = totalCutTask + 1;
}else if(unFinishedTask.isUrgentReel()){
urgentPackageTask = urgentPackageTask + 1;
totalUrgentTask = totalUrgentTask + 1;
}
}
}else if(unFinishedTask.isCutReel()){
cutTask = cutTask + 1;
totalCutTask = totalCutTask + 1;
}else if(unFinishedTask.isUrgentReel()){
urgentTask = urgentTask + 1;
totalUrgentTask = totalUrgentTask + 1;
}
}
}
......@@ -621,13 +638,13 @@ public class QisdaDeviceController extends BaseController {
resultMap.put("cutTask", cutTask + "");
resultMap.put("urgentTask", urgentTask + "");
if(cutPackageTask + cutTask == 0){
log.info("已无分盘料任务,清空分盘料使用料架/料串");
if(totalCutTask == 0){
//log.info("已无分盘料任务,清空分盘料使用料架/料串");
InquiryShelfBean.clearShelf(InquiryShelfBean.CUT_SHELF_MAP_KEY);
}
if(urgentPackageTask + urgentTask == 0){
log.info("已无紧急料任务,清空紧急料使用料架/料串");
if(totalUrgentTask == 0){
//log.info("已无紧急料任务,清空紧急料使用料架/料串");
InquiryShelfBean.clearShelf(InquiryShelfBean.URGENT_SHELF_MAP_KEY);
}
......@@ -723,11 +740,8 @@ public class QisdaDeviceController extends BaseController {
String hSerial = appendInfo.gethSerial();
if(Strings.isNotBlank(hSerial)){
OutInfo outInfo = outInfoDao.findByHSerial(hSerial);
OutInfo outInfo = outInfoCache.incTaskFinishNum(hSerial);
if(outInfo != null){
outInfo.setTaskFinishNum(outInfo.getTaskFinishNum() + 1);
log.info("需求单["+outInfo.gethSerial()+"]任务完成数量:" + outInfo.getTaskFinishNum() + "/" + outInfo.getTaskNum() + "已出仓料盘数量:" + outInfo.getOutReelNum());
outInfo = outInfoDao.save(outInfo);
if(cacheTask.isUrgentReel() || cacheTask.isCutReel()){
log.info("分盘料和紧急料不需要通知Qisda");
......
......@@ -577,51 +577,29 @@ public class StorageDataController extends BaseController {
errorMsg = "无可用的料仓";
resultMap.put("msg",errorMsg);
}else{
Collection<CodeBean> codeBeans = dataCache.resolveCodeStr(code);
Barcode barcode = null;
String validBarcodeStr = "";
for (CodeBean codeBean: codeBeans) {
if(codeBean.isValid()){
if(barcode == null){
barcode = codeBean.getBarcode();
validBarcodeStr = barcode.getBarcode();
}else{
//有多个有效的条码
validBarcodeStr = validBarcodeStr + "," + barcode.getBarcode();
}
}
}
if(barcode == null){
resultMap.put("result","103");
errorMsg = "条码["+code+"]无效";
resultMap.put("msg",errorMsg);
}else {
try {
if(!validBarcodeStr.equals(barcode.getBarcode())){
throw new ValidateException("发现多个有效条码:" + validBarcodeStr);
}
StoragePos pos = taskService.findEmptyPosForPutIn(storageList,barcode, rfid);
if(pos != null){
resultMap.put("result","0");
resultMap.put("msg","");
resultMap.put("pos",pos.getPosName());
resultMap.put("barcode",barcode.getBarcode());
Storage theStorage = dataCache.getStorageById(pos.getStorageId());
resultMap.put("cid",theStorage.getCid());
okMsg = "["+rfid+"]["+barcode.getBarcode()+"]准备入库到["+pos.getPosName()+"],添加入库任务";
taskService.addPutInTaskToExecute(theStorage, barcode, pos);
}else{
resultMap.put("result","104");
errorMsg = "未找到可用的["+barcode.getPlateSize() + "x" + barcode.getHeight()+"]仓位";
resultMap.put("msg",errorMsg);
}
} catch (ValidateException e) {
errorMsg = e.getMessage();
log.info("查找空库位失败:" + errorMsg);
resultMap.put("result","105");
try {
Barcode barcode = dataCache.resolveOneValideBarcode(code);
StoragePos pos = taskService.findEmptyPosForPutIn(storageList,barcode, rfid);
if(pos != null){
resultMap.put("result","0");
resultMap.put("msg","");
resultMap.put("pos",pos.getPosName());
resultMap.put("barcode",barcode.getBarcode());
Storage theStorage = dataCache.getStorageById(pos.getStorageId());
resultMap.put("cid",theStorage.getCid());
okMsg = "["+rfid+"]["+barcode.getBarcode()+"]准备入库到["+pos.getPosName()+"],添加入库任务";
taskService.addPutInTaskToExecute(theStorage, barcode, pos);
}else{
resultMap.put("result","104");
errorMsg = "未找到可用的["+barcode.getPlateSize() + "x" + barcode.getHeight()+"]仓位";
resultMap.put("msg",errorMsg);
}
} catch (ValidateException e) {
errorMsg = e.getMessage();
log.info("查找空库位失败:" + errorMsg);
resultMap.put("result","105");
resultMap.put("msg",errorMsg);
}
}
}
......
......@@ -834,24 +834,29 @@ public class TaskService implements ITaskService {
@Override
public void hideTask(String taskId) {
DataLog task = dataLogDao.findOneById(taskId);
DataLog task = null;
List<DataLog> finishedTasks = getFinishedTasks();
for (DataLog finishedTask : finishedTasks) {
if(finishedTask.getId().equals(taskId)){
task = finishedTask;
break;
}
}
if(task.isCheckOutTask()){
if(task != null && task.isCheckOutTask()){
log.info("清除任务["+task.getBarcode()+"]");
finishedTaskMap.remove(task.getBarcode());
//发送取消(发料)指令到佳世达
AppendInfo taskAppendInfo = task.getAppendInfo();
if(taskAppendInfo.isFirstReelAction() || taskAppendInfo.isTailAction()){
Barcode barcode = barcodeManager.findByBarcode(task.getBarcode());
log.info("["+task.getBarcode()+"]任务已出库完成,但未放上小车,发送E状态到佳世达,同时解除料架架位,发料任务完成数量+1");
OutInfo outInfo = outInfoDao.findByHSerial(taskAppendInfo.gethSerial());
OutInfo outInfo = outInfoCache.incTaskFinishNum(taskAppendInfo.gethSerial());
if(outInfo != null) {
outInfo.setTaskFinishNum(outInfo.getTaskFinishNum() + 1);
log.info("需求单[" + outInfo.gethSerial() + "]任务完成数量:" + outInfo.getTaskFinishNum() + "/" + outInfo.getTaskNum() + "已出仓料盘数量:" + outInfo.getOutReelNum());
outInfoDao.save(outInfo);
InquiryShelfBean.cancelReelTask(task);
QisdaApi.VMIMateriaRecAss(task, barcode, "E");
}
}
finishedTaskMap.remove(task.getBarcode());
}
}
......@@ -2023,7 +2028,6 @@ public class TaskService implements ITaskService {
private synchronized void updateOutInfo(String outItemId, DataLog task, Barcode barcode){
//更新出库数量
OutInfo outInfo;
if(!Strings.isNullOrEmpty(outItemId)){
OutItem outItem = outItemDao.findOneById(outItemId);
if(outItem != null){
......@@ -2059,13 +2063,11 @@ public class TaskService implements ITaskService {
outInfoCache.updateOutItem(outItem.getId());
}
outInfo = outInfoDao.findByHSerial(outItem.gethSerial());
int outReelNum = outInfo.getOutReelNum();
outInfo.setOutReelNum(outReelNum + 1);
OutInfo outInfo = outInfoCache.incOutNum(outItem.gethSerial());
if(outItem.isUrgentAction() || outItem.isReelCutAction()){
outInfo.setTaskFinishNum(outInfo.getTaskFinishNum() + 1);
outInfo = outInfoCache.incTaskFinishNum(outItem.gethSerial());
}
outInfo = outInfoDao.save(outInfo);
String latest = outInfo.getOutLatest();
QisdaApiController.OutFinished(task, barcode, latest);
......
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!