Skip to content
切换导航条
切换导航条
当前项目
正在载入...
登录
孙克
/
smf-core
转到一个项目
切换导航栏
切换导航栏固定状态
项目
群组
代码片段
帮助
项目
活动
版本库
流水线
图表
问题
0
合并请求
0
维基
网络
创建新的问题
作业
提交
问题看板
文件
提交
网络
比较
分支
标签
Commit b5b93d76
由
zshaohui
编写于
2025-09-04 10:41:41 +0800
浏览文件
选项
浏览文件
标签
下载
电子邮件补丁
差异文件
1.虚拟回仓问题修复
2.移库/获取库位 锁定问题修改
1 个父辈
339dbb7a
显示空白字符变更
内嵌
并排
正在显示
7 个修改的文件
包含
71 行增加
和
51 行删除
src/main/java/com/neotel/smfcore/core/device/rest/DeviceController.java
src/main/java/com/neotel/smfcore/core/language/util/MessageUtils.java
src/main/java/com/neotel/smfcore/core/order/LiteOrderCache.java
src/main/java/com/neotel/smfcore/core/order/rest/OrderController.java
src/main/java/com/neotel/smfcore/core/system/util/TaskService.java
src/main/java/com/neotel/smfcore/custom/Jkem21481/controller/JkemController.java
src/main/java/com/neotel/smfcore/custom/Jkem21481/util/StorageExportUtil.java
src/main/java/com/neotel/smfcore/core/device/rest/DeviceController.java
查看文件 @
b5b93d7
...
@@ -912,19 +912,27 @@ public class DeviceController {
...
@@ -912,19 +912,27 @@ public class DeviceController {
storageList
.
add
(
storage
);
storageList
.
add
(
storage
);
List
<
String
>
cidList
=
new
ArrayList
<>();
List
<
String
>
cidList
=
new
ArrayList
<>();
cidList
.
add
(
storage
.
getCid
());
cidList
.
add
(
storage
.
getCid
());
List
<
String
>
needRemoveLockPosId
=
new
ArrayList
<>();
while
(
pos
==
null
)
{
while
(
pos
==
null
)
{
loopCount
++;
loopCount
++;
if
(
loopCount
>=
1
0
)
{
if
(
loopCount
>=
2
0
)
{
log
.
info
(
barcode
.
getBarcode
()
+
"已循环查找
1
0次 直接跳出循环"
);
log
.
info
(
barcode
.
getBarcode
()
+
"已循环查找
2
0次 直接跳出循环"
);
break
;
break
;
}
}
//优先找B结束的,如果没有再找F的
//优先找B结束的,如果没有再找F的
String
endStr
=
"B"
;
String
endStr
=
"B"
;
if
(
loopCount
>=
10
){
endStr
=
"F"
;
}
pos
=
taskService
.
findEmptyPosForMoveIn
(
storageList
,
barcode
,
""
,
""
,
needMovePosName
,
endStr
);
pos
=
taskService
.
findEmptyPosForMoveIn
(
storageList
,
barcode
,
""
,
""
,
needMovePosName
,
endStr
);
if
(
pos
==
null
)
{
if
(
pos
==
null
)
{
if
(
"F"
.
equals
(
endStr
)){
}
else
{
endStr
=
"F"
;
endStr
=
"F"
;
pos
=
taskService
.
findEmptyPosForMoveIn
(
storageList
,
barcode
,
""
,
""
,
needMovePosName
,
endStr
);
pos
=
taskService
.
findEmptyPosForMoveIn
(
storageList
,
barcode
,
""
,
""
,
needMovePosName
,
endStr
);
}
}
}
if
(
pos
==
null
)
{
if
(
pos
==
null
)
{
log
.
info
(
"需要移动的库位"
+
needMovePosName
+
"未找到对应的库位信息"
);
log
.
info
(
"需要移动的库位"
+
needMovePosName
+
"未找到对应的库位信息"
);
break
;
break
;
...
@@ -947,6 +955,7 @@ public class DeviceController {
...
@@ -947,6 +955,7 @@ public class DeviceController {
reelLocInfo
.
setLockPosName
(
pos
.
getPosName
());
reelLocInfo
.
setLockPosName
(
pos
.
getPosName
());
reelLocInfo
.
setLockPosId
(
pos
.
getId
());
reelLocInfo
.
setLockPosId
(
pos
.
getId
());
ReelLockPosUtil
.
addReelLockPosInfo
(
reelLocInfo
,
cidList
);
ReelLockPosUtil
.
addReelLockPosInfo
(
reelLocInfo
,
cidList
);
needRemoveLockPosId
.
add
(
pos
.
getId
());
pos
=
null
;
pos
=
null
;
posName
=
""
;
posName
=
""
;
}
else
{
}
else
{
...
@@ -1006,6 +1015,12 @@ public class DeviceController {
...
@@ -1006,6 +1015,12 @@ public class DeviceController {
}
}
}
}
}
}
//判断有没有锁定的异常库位
if
(
needRemoveLockPosId
!=
null
&&
!
needRemoveLockPosId
.
isEmpty
()){
for
(
String
posId
:
needRemoveLockPosId
)
{
ReelLockPosUtil
.
removeReelLockPosInfo
(
posId
);
}
}
}
}
}
}
//然后找lock库位,有的话返回
//然后找lock库位,有的话返回
...
...
src/main/java/com/neotel/smfcore/core/language/util/MessageUtils.java
查看文件 @
b5b93d7
...
@@ -90,7 +90,7 @@ public class MessageUtils {
...
@@ -90,7 +90,7 @@ public class MessageUtils {
public
static
final
String
smfcore
=
"smfcore"
;
public
static
final
String
smfcore
=
"smfcore"
;
private
static
String
defLanguage
=
""
;
private
static
String
defLanguage
=
""
;
@Value
(
"${app.defLanguage:
zh-CN
}"
)
@Value
(
"${app.defLanguage:
en
}"
)
public
void
setDefLanguage
(
String
defLanguage
)
{
public
void
setDefLanguage
(
String
defLanguage
)
{
MessageUtils
.
defLanguage
=
defLanguage
;
MessageUtils
.
defLanguage
=
defLanguage
;
}
}
...
@@ -122,7 +122,11 @@ public class MessageUtils {
...
@@ -122,7 +122,11 @@ public class MessageUtils {
//-----------------以下为从缓存读取资源-------------------------------------
//-----------------以下为从缓存读取资源-------------------------------------
public
static
Locale
getDefaultLocal
(){
public
static
Locale
getDefaultLocal
(){
if
(
ObjectUtil
.
isNotEmpty
(
defLanguage
)){
if
(
ObjectUtil
.
isNotEmpty
(
defLanguage
)){
return
new
Locale
(
defLanguage
);
if
(
"en"
.
equals
(
defLanguage
)){
return
new
Locale
(
"en"
,
"US"
);
}
else
if
(
"zh"
.
equals
(
defLanguage
)){
return
new
Locale
(
"zh-CH"
);
}
}
}
return
new
Locale
(
"zh-CH"
);
return
new
Locale
(
"zh-CH"
);
}
}
...
...
src/main/java/com/neotel/smfcore/core/order/LiteOrderCache.java
查看文件 @
b5b93d7
...
@@ -349,7 +349,7 @@ public class LiteOrderCache {
...
@@ -349,7 +349,7 @@ public class LiteOrderCache {
log
.
error
(
"工单["
+
orderNo
+
"]的任务["
+
task
.
getBarcode
()
+
"]完成时,状态为:"
+
task
.
getStatus
());
log
.
error
(
"工单["
+
orderNo
+
"]的任务["
+
task
.
getBarcode
()
+
"]完成时,状态为:"
+
task
.
getStatus
());
}
}
if
(
order
.
getFinishedReelCount
()
>=
order
.
getTaskReelCount
())
{
if
(
order
.
get
TaskReelCount
()
>
0
&&
order
.
get
FinishedReelCount
()
>=
order
.
getTaskReelCount
())
{
log
.
info
(
"工单["
+
orderNo
+
"]的出库任务已完成,共出库:"
+
order
.
getFinishedReelCount
()
+
" 盘"
);
log
.
info
(
"工单["
+
orderNo
+
"]的出库任务已完成,共出库:"
+
order
.
getFinishedReelCount
()
+
" 盘"
);
finishedOrderTasks
(
order
);
finishedOrderTasks
(
order
);
}
}
...
@@ -1019,8 +1019,8 @@ public class LiteOrderCache {
...
@@ -1019,8 +1019,8 @@ public class LiteOrderCache {
StoragePos
pos
=
null
;
StoragePos
pos
=
null
;
for
(
String
storageId
:
taskPosIdMap
.
keySet
())
{
for
(
String
storageId
:
taskPosIdMap
.
keySet
())
{
try
{
try
{
log
.
info
(
"休眠
1
00毫秒"
);
log
.
info
(
"休眠
2
00毫秒"
);
Thread
.
sleep
(
1
00
);
Thread
.
sleep
(
2
00
);
}
catch
(
InterruptedException
e
)
{
}
catch
(
InterruptedException
e
)
{
e
.
printStackTrace
();
e
.
printStackTrace
();
}
}
...
...
src/main/java/com/neotel/smfcore/core/order/rest/OrderController.java
查看文件 @
b5b93d7
...
@@ -577,65 +577,41 @@ public class OrderController {
...
@@ -577,65 +577,41 @@ public class OrderController {
String
reelId
=
paramsMap
.
get
(
"barcode"
);
String
reelId
=
paramsMap
.
get
(
"barcode"
);
Integer
num
=
Integer
.
valueOf
(
paramsMap
.
get
(
"num"
));
Integer
num
=
Integer
.
valueOf
(
paramsMap
.
get
(
"num"
));
Barcode
barcode
=
barcodeManager
.
findByBarcode
(
reelId
);
Barcode
barcode
=
barcodeManager
.
findByBarcode
(
reelId
);
if
(
barcode
==
null
)
{
if
(
barcode
==
null
)
{
throw
new
ValidateException
(
"smfcore.error.barcode.invalid"
,
"未找到有效的条码"
,
new
String
[]{
reelId
});
throw
new
ValidateException
(
"smfcore.error.barcode.invalid"
,
"未找到有效的条码"
,
new
String
[]{
reelId
});
}
}
//判断数量是否大于条码数量
//判断数量是否大于条码数量
if
(
num
>
barcode
.
getAmount
())
{
if
(
num
>
barcode
.
getAmount
())
{
throw
new
ValidateException
(
"smfcore.error.virtualOut.num"
,
"数量不能超过{0}"
,
new
String
[]{
barcode
.
getAmount
()
+
""
});
throw
new
ValidateException
(
"smfcore.error.virtualOut.num"
,
"数量不能超过{0}"
,
new
String
[]{
barcode
.
getAmount
()
+
""
});
}
}
LiteOrder
liteOrder
=
liteOrderCache
.
getLiteOrder
(
orderNo
);
LiteOrder
liteOrder
=
liteOrderManager
.
findByOrderNo
(
orderNo
);
if
(
liteOrder
==
null
){
liteOrder
=
liteOrderManager
.
findByOrderNo
(
orderNo
);
}
if
(
liteOrder
==
null
)
{
if
(
liteOrder
==
null
)
{
throw
new
ValidateException
(
"smfcore.valueNotFind"
,
"未找到{0}[{1}]"
,
new
String
[]{
"orderNo"
,
orderNo
});
throw
new
ValidateException
(
"smfcore.valueNotFind"
,
"未找到{0}[{1}]"
,
new
String
[]{
"orderNo"
,
orderNo
});
}
}
if
(!
liteOrder
.
isTaskFinished
()
&&
!
liteOrder
.
isNew
())
{
log
.
info
(
"工单["
+
orderNo
+
"]正在执行"
);
throw
new
ValidateException
(
"smfcore.order.out.executing"
,
"工单正在执行"
);
}
if
(
liteOrder
.
isClosed
())
{
if
(
liteOrder
.
isClosed
())
{
throw
new
ValidateException
(
"smfcore.order.hasClose"
,
"工单["
+
orderNo
+
"]已关闭,无法出库"
,
new
String
[]{
"orderNo"
,
orderNo
});
throw
new
ValidateException
(
"smfcore.order.hasClose"
,
"工单["
+
orderNo
+
"]已关闭,无法出库"
,
new
String
[]{
"orderNo"
,
orderNo
});
}
}
LiteOrderItem
findItem
=
findVirtualItem
(
liteOrder
,
barcode
,
true
);
LiteOrderItem
findItem
=
findVirtualItem
(
liteOrder
,
barcode
,
true
);
/*if (findItem == null) {
if
(
findItem
==
null
)
{
findItem=findVirtualItem(liteOrder,barcode,false);
findItem=findVirtualItem(liteOrder,barcode,false);
}
}*/
if
(
findItem
==
null
)
{
if
(
findItem
==
null
)
{
throw
new
ValidateException
(
"smfcore.error.virtualOut.noItem"
,
"工单{0}中未找到对应的PN或物料编号"
,
new
String
[]{
liteOrder
.
getOrderNo
()
+
""
});
throw
new
ValidateException
(
"smfcore.error.virtualOut.noItem"
,
"工单{0}中未找到对应的PN或物料编号"
,
new
String
[]{
liteOrder
.
getOrderNo
()
+
""
});
}
else
{
}
else
{
//增加一条出库完成记录
//增加一条出库完成记录
addVirtualOutToFinished
(
liteOrder
,
barcode
,
num
,
SecurityUtils
.
getCurrentUsername
());
addVirtualOutToFinished
(
liteOrder
,
barcode
,
num
,
SecurityUtils
.
getCurrentUsername
(),
findItem
);
findItem
.
setOutNum
(
findItem
.
getOutNum
()
+
num
);
findItem
.
setTotalOutNum
(
findItem
.
getTotalOutNum
()
+
num
);
findItem
.
setOutReelCount
(
findItem
.
getOutReelCount
()
+
1
);
findItem
.
setTotalOutReelCount
(
findItem
.
getTotalOutReelCount
()
+
1
);
//findItem.setNeedReelCount(findItem.getNeedReelCount() + 1);
liteOrderItemManager
.
save
(
findItem
);
liteOrder
.
updateOrderItems
(
findItem
);
//工单未关闭的话,检查状态,全部都出完进行关闭
boolean
closed
=
true
;
for
(
LiteOrderItem
liteOrderItem
:
liteOrder
.
getOrderItems
())
{
if
(!
liteOrderItem
.
isOutFinished
()
||
!
liteOrderItem
.
isOutReelFinished
())
{
closed
=
false
;
break
;
}
}
if
(
closed
)
{
liteOrder
.
setClosed
(
closed
);
log
.
info
(
"工单【"
+
liteOrder
.
getOrderNo
()
+
"】虚拟回仓【"
+
barcode
.
getPartNumber
()
+
"-"
+
barcode
.
getBarcode
()
+
"】数量【"
+
num
+
"】后,所有料已出完,关闭工单"
);
}
liteOrderManager
.
save
(
liteOrder
);
liteOrderCache
.
addOrderToMap
(
liteOrder
);
}
}
return
ResultBean
.
newOkResult
(
""
);
return
ResultBean
.
newOkResult
(
""
);
}
}
public
void
addVirtualOutToFinished
(
LiteOrder
liteOrder
,
Barcode
barcode
,
Integer
num
,
String
opUser
)
{
public
void
addVirtualOutToFinished
(
LiteOrder
liteOrder
,
Barcode
barcode
,
Integer
num
,
String
opUser
,
LiteOrderItem
findItem
)
{
try
{
try
{
DataLog
dataLog
=
new
DataLog
();
DataLog
dataLog
=
new
DataLog
();
...
@@ -663,6 +639,10 @@ public class OrderController {
...
@@ -663,6 +639,10 @@ public class OrderController {
dataLog
.
setSourceName
(
liteOrder
.
getOrderNo
());
dataLog
.
setSourceName
(
liteOrder
.
getOrderNo
());
dataLog
.
setSourceId
(
liteOrder
.
getId
());
dataLog
.
setSourceId
(
liteOrder
.
getId
());
dataLog
.
setSubSourceId
(
findItem
.
getId
());
dataLog
.
setSubSourceInfo
(
findItem
.
getFeederInfo
());
dataLog
.
setLine
(
liteOrder
.
getLine
());
dataLog
.
updateAppendData
(
"feederInfo"
,
findItem
.
getFeederInfo
());
log
.
info
(
opUser
+
"虚拟回仓: PN【"
+
barcode
.
getPartNumber
()+
"】条码【"
+
barcode
.
getBarcode
()
+
"】 工单号【"
+
liteOrder
.
getOrderNo
()
+
"】数量【"
+
num
+
"】"
);
log
.
info
(
opUser
+
"虚拟回仓: PN【"
+
barcode
.
getPartNumber
()+
"】条码【"
+
barcode
.
getBarcode
()
+
"】 工单号【"
+
liteOrder
.
getOrderNo
()
+
"】数量【"
+
num
+
"】"
);
dataLog
.
setType
(
OP
.
CHECKOUT
);
dataLog
.
setType
(
OP
.
CHECKOUT
);
...
@@ -686,7 +666,7 @@ public class OrderController {
...
@@ -686,7 +666,7 @@ public class OrderController {
LiteOrderItem
findItem
=
null
;
LiteOrderItem
findItem
=
null
;
for
(
LiteOrderItem
item
:
for
(
LiteOrderItem
item
:
liteOrder
.
getOrderItems
())
{
liteOrder
.
getOrderItems
())
{
if
(
checkNum
&&
item
.
getTotalOutNum
()
>=
item
.
getNeedNum
())
{
if
(
checkNum
&&
item
.
getTotalOutNum
()
>=
item
.
getNeedNum
()
&&
item
.
getNeedReelCount
()
<=
item
.
getTotalOutReelCount
()
)
{
continue
;
continue
;
}
}
if
(
item
.
getRi
()
!=
null
&&
item
.
getRi
().
equals
(
barcode
.
getBarcode
())){
if
(
item
.
getRi
()
!=
null
&&
item
.
getRi
().
equals
(
barcode
.
getBarcode
())){
...
...
src/main/java/com/neotel/smfcore/core/system/util/TaskService.java
查看文件 @
b5b93d7
...
@@ -731,6 +731,9 @@ public class TaskService {
...
@@ -731,6 +731,9 @@ public class TaskService {
return
task
;
return
task
;
}
}
public
StoragePos
findEmptyPosForPutIn
(
List
<
Storage
>
storageList
,
Barcode
barcode
,
String
inRFID
,
String
lastPosId
)
throws
ValidateException
{
return
findEmptyPosForPutIn
(
storageList
,
barcode
,
inRFID
,
lastPosId
,
""
,
""
);
}
/**
/**
* 查找可以入库的空位
* 查找可以入库的空位
...
@@ -739,7 +742,7 @@ public class TaskService {
...
@@ -739,7 +742,7 @@ public class TaskService {
* @param barcode
* @param barcode
* @return
* @return
*/
*/
public
StoragePos
findEmptyPosForPutIn
(
List
<
Storage
>
storageList
,
Barcode
barcode
,
String
inRFID
,
String
lastPosId
)
throws
ValidateException
{
public
StoragePos
findEmptyPosForPutIn
(
List
<
Storage
>
storageList
,
Barcode
barcode
,
String
inRFID
,
String
lastPosId
,
String
needMovePosName
,
String
endStr
)
throws
ValidateException
{
verifyBarcodePutIn
(
storageList
,
barcode
,
inRFID
);
verifyBarcodePutIn
(
storageList
,
barcode
,
inRFID
);
List
<
String
>
storageIds
=
new
ArrayList
<>();
List
<
String
>
storageIds
=
new
ArrayList
<>();
...
@@ -827,7 +830,7 @@ public class TaskService {
...
@@ -827,7 +830,7 @@ public class TaskService {
}
}
});
});
return
findEmptyPosInStorages
(
barcode
,
availbleStorageList
,
hasOutTaskStorageIds
,
lastPosId
);
return
findEmptyPosInStorages
(
barcode
,
availbleStorageList
,
hasOutTaskStorageIds
,
lastPosId
,
needMovePosName
,
endStr
);
}
}
...
@@ -847,6 +850,9 @@ public class TaskService {
...
@@ -847,6 +850,9 @@ public class TaskService {
for
(
DataLog
task
:
allTasksa
)
{
for
(
DataLog
task
:
allTasksa
)
{
if
(
task
.
isPutInTask
())
{
if
(
task
.
isPutInTask
())
{
if
(
task
.
isFinished
()
||
task
.
isCancel
()){
continue
;
}
if
(
task
.
getBarcode
().
equals
(
barcode
.
getBarcode
()))
{
if
(
task
.
getBarcode
().
equals
(
barcode
.
getBarcode
()))
{
//同一个条码的入库任务
//同一个条码的入库任务
for
(
Storage
storage
:
storageList
)
{
for
(
Storage
storage
:
storageList
)
{
...
...
src/main/java/com/neotel/smfcore/custom/Jkem21481/controller/JkemController.java
查看文件 @
b5b93d7
...
@@ -98,7 +98,7 @@ public class JkemController {
...
@@ -98,7 +98,7 @@ public class JkemController {
@PostMapping
(
value
=
"/jkem/service/store/emptyPosForPutin"
)
@PostMapping
(
value
=
"/jkem/service/store/emptyPosForPutin"
)
@ResponseBody
@ResponseBody
@AnonymousAccess
@AnonymousAccess
public
synchronized
Map
<
String
,
Object
>
emptyPosForPutin
(
HttpServletRequest
request
)
{
public
Map
<
String
,
Object
>
emptyPosForPutin
(
HttpServletRequest
request
)
{
String
code
=
request
.
getParameter
(
"code"
);
String
code
=
request
.
getParameter
(
"code"
);
String
cids
=
request
.
getParameter
(
"cids"
);
String
cids
=
request
.
getParameter
(
"cids"
);
String
rfid
=
request
.
getParameter
(
"rfid"
);
String
rfid
=
request
.
getParameter
(
"rfid"
);
...
@@ -302,12 +302,27 @@ public class JkemController {
...
@@ -302,12 +302,27 @@ public class JkemController {
List
<
String
>
needRemoveLockPosId
=
new
ArrayList
<>();
List
<
String
>
needRemoveLockPosId
=
new
ArrayList
<>();
String
endStr
=
"B"
;
while
(
pos
==
null
)
{
while
(
pos
==
null
)
{
loopCount
++;
loopCount
++;
if
(
loopCount
>=
10
)
{
if
(
loopCount
>=
30
)
{
log
.
info
(
barcode
.
getBarcode
()
+
"已循环查找10次 直接跳出循环"
);
log
.
info
(
barcode
.
getBarcode
()
+
"已循环查找30次 直接跳出循环"
);
break
;
}
}
pos
=
taskService
.
findEmptyPosForPutIn
(
findNewStorageList
,
barcode
,
rfid
,
lastPosId
);
if
(
loopCount
>=
15
){
endStr
=
"F"
;
}
pos
=
taskService
.
findEmptyPosForPutIn
(
findNewStorageList
,
barcode
,
rfid
,
lastPosId
,
barcode
.
getBarcode
(),
endStr
);
if
(
pos
==
null
){
if
(
"B"
.
equals
(
endStr
)){
endStr
=
"F"
;
}
else
{
endStr
=
"B"
;
}
pos
=
taskService
.
findEmptyPosForPutIn
(
findNewStorageList
,
barcode
,
rfid
,
lastPosId
,
barcode
.
getBarcode
(),
endStr
);
}
if
(
pos
==
null
)
{
if
(
pos
==
null
)
{
break
;
break
;
}
}
...
...
src/main/java/com/neotel/smfcore/custom/Jkem21481/util/StorageExportUtil.java
查看文件 @
b5b93d7
...
@@ -224,7 +224,7 @@ public class StorageExportUtil {
...
@@ -224,7 +224,7 @@ public class StorageExportUtil {
return
export
;
return
export
;
}
}
public
static
synchronized
void
updateExportByTask
(
String
export
,
String
barcode
,
String
feederInfo
,
String
orderNo
,
String
status
,
String
partNumber
)
{
public
static
void
updateExportByTask
(
String
export
,
String
barcode
,
String
feederInfo
,
String
orderNo
,
String
status
,
String
partNumber
)
{
log
.
info
(
"工单任务修改出料口信息:"
+
export
+
"barcode为:"
+
barcode
+
",站位信息为:"
+
feederInfo
+
"工单号为:"
+
orderNo
+
",状态为:"
+
status
);
log
.
info
(
"工单任务修改出料口信息:"
+
export
+
"barcode为:"
+
barcode
+
",站位信息为:"
+
feederInfo
+
"工单号为:"
+
orderNo
+
",状态为:"
+
status
);
StorageExport
storageExport
=
exportMap
.
get
(
export
);
StorageExport
storageExport
=
exportMap
.
get
(
export
);
String
hSerial
=
storageExport
.
getHSerial
();
String
hSerial
=
storageExport
.
getHSerial
();
...
...
编写
预览
支持
Markdown
格式
附加文件
你添加了
0
人
到此讨论。请谨慎行事。
Finish editing this message first!
Cancel
请
注册
或
登录
后发表评论