Skip to content
切换导航条
切换导航条
当前项目
正在载入...
登录
孙克
/
smf-core
转到一个项目
切换导航栏
切换导航栏固定状态
项目
群组
代码片段
帮助
项目
活动
版本库
流水线
图表
问题
0
合并请求
0
维基
网络
创建新的问题
作业
提交
问题看板
文件
提交
网络
比较
分支
标签
Commit 9f57bb6c
由
zshaohui
编写于
2025-09-05 14:37:01 +0800
浏览文件
选项
浏览文件
标签
下载
电子邮件补丁
差异文件
1.增加扫码出库功能
2.批量禁限用报错重试3次
1 个父辈
71fc31c5
显示空白字符变更
内嵌
并排
正在显示
3 个修改的文件
包含
275 行增加
和
30 行删除
src/main/java/com/neotel/smfcore/custom/luxsan/api/LuxsanApi.java
src/main/java/com/neotel/smfcore/custom/luxsan/factory_c/rawstor/controller/CDeviceController.java
src/main/resources/config/application.yml
src/main/java/com/neotel/smfcore/custom/luxsan/api/LuxsanApi.java
查看文件 @
9f57bb6
...
@@ -1231,66 +1231,87 @@ public class LuxsanApi extends DefaultSmfApiListener {
...
@@ -1231,66 +1231,87 @@ public class LuxsanApi extends DefaultSmfApiListener {
public
static
List
<
String
>
batchCheckReel
(
List
<
Barcode
>
barcodeList
,
String
pickingId
,
String
model
)
{
public
static
List
<
String
>
batchCheckReel
(
List
<
Barcode
>
barcodeList
,
String
pickingId
,
String
model
)
{
List
<
Map
<
String
,
Object
>>
paramList
=
new
ArrayList
<>();
List
<
Map
<
String
,
Object
>>
paramList
=
new
ArrayList
<>();
for
(
Barcode
barcode
:
barcodeList
)
{
for
(
Barcode
barcode
:
barcodeList
)
{
Map
<
String
,
Object
>
paramMap
=
new
HashMap
<>();
Map
<
String
,
Object
>
paramMap
=
new
HashMap
<>();
paramMap
.
put
(
"ipn"
,
barcode
.
getPartNumber
());
paramMap
.
put
(
"ipn"
,
barcode
.
getPartNumber
());
paramMap
.
put
(
"reelId"
,
barcode
.
getBarcode
());
paramMap
.
put
(
"reelId"
,
barcode
.
getBarcode
());
paramMap
.
put
(
"wo"
,
""
);
paramMap
.
put
(
"wo"
,
""
);
paramMap
.
put
(
"datecode"
,
barcode
.
getDateCode
());
paramMap
.
put
(
"datecode"
,
barcode
.
getDateCode
());
paramMap
.
put
(
"lot"
,
barcode
.
getBatch
());
paramMap
.
put
(
"lot"
,
barcode
.
getBatch
());
paramMap
.
put
(
"vendor"
,
barcode
.
getProvider
());
paramMap
.
put
(
"vendor"
,
barcode
.
getProvider
());
paramMap
.
put
(
"remark"
,
"ALL"
);
paramMap
.
put
(
"remark"
,
"ALL"
);
paramMap
.
put
(
"werks"
,
"ALL"
);
paramMap
.
put
(
"werks"
,
"ALL"
);
paramMap
.
put
(
"model"
,
"ALL"
);
paramMap
.
put
(
"model"
,
"ALL"
);
if
(
StringUtils
.
isNotEmpty
(
model
)){
if
(
StringUtils
.
isNotEmpty
(
model
))
{
paramMap
.
put
(
"model"
,
model
);
paramMap
.
put
(
"model"
,
model
);
}
}
paramMap
.
put
(
"picking"
,
"ALL"
);
paramMap
.
put
(
"picking"
,
"ALL"
);
if
(
StringUtils
.
isNotEmpty
(
pickingId
)){
if
(
StringUtils
.
isNotEmpty
(
pickingId
))
{
paramMap
.
put
(
"picking"
,
pickingId
);
paramMap
.
put
(
"picking"
,
pickingId
);
}
}
paramList
.
add
(
paramMap
);
paramList
.
add
(
paramMap
);
}
}
log
.
info
(
"批量禁用入参为:"
+
JSON
.
toJSONString
(
paramList
));
log
.
info
(
"批量禁用入参为:"
+
JSON
.
toJSONString
(
paramList
));
Map
<
String
,
String
>
resultMap
=
new
HashMap
<>();
Map
<
String
,
String
>
resultMap
=
new
HashMap
<>();
List
<
String
>
reelList
=
new
ArrayList
<>();
List
<
String
>
reelList
=
new
ArrayList
<>();
int
maxRetries
=
3
;
int
retryCount
=
0
;
boolean
isSuccess
=
false
;
// 重试机制:最多请求3次
while
(
retryCount
<
maxRetries
&&
!
isSuccess
)
{
retryCount
++;
try
{
try
{
String
resultStr
=
HttpHelper
.
postJson
(
batchCheckReelUrl
,
paramList
);
String
resultStr
=
HttpHelper
.
postJson
(
batchCheckReelUrl
,
paramList
);
log
.
info
(
"批量禁用接口返回结果为:"
+
resultStr
);
log
.
info
(
"第"
+
retryCount
+
"次批量禁用接口返回结果为:"
+
resultStr
);
JSONObject
resultObj
=
JSONObject
.
parseObject
(
resultStr
);
JSONObject
resultObj
=
JSONObject
.
parseObject
(
resultStr
);
String
status
=
resultObj
.
getString
(
"status"
);
String
status
=
resultObj
.
getString
(
"status"
);
if
(
"200"
.
equals
(
status
)){
// 只有返回200才认为成功
if
(
"200"
.
equals
(
status
))
{
isSuccess
=
true
;
JSONArray
dataArr
=
resultObj
.
getJSONArray
(
"data"
);
JSONArray
dataArr
=
resultObj
.
getJSONArray
(
"data"
);
if
(
dataArr
!=
null
&&
!
dataArr
.
isEmpty
())
{
if
(
dataArr
!=
null
&&
!
dataArr
.
isEmpty
())
{
for
(
int
i
=
0
;
i
<
dataArr
.
size
();
i
++)
{
for
(
int
i
=
0
;
i
<
dataArr
.
size
();
i
++)
{
JSONObject
data
=
dataArr
.
getJSONObject
(
i
);
JSONObject
data
=
dataArr
.
getJSONObject
(
i
);
JSONArray
resultList
=
data
.
getJSONArray
(
"resultList"
);
JSONArray
resultList
=
data
.
getJSONArray
(
"resultList"
);
if
(
resultList
!=
null
&&
!
resultList
.
isEmpty
())
{
if
(
resultList
!=
null
&&
!
resultList
.
isEmpty
())
{
for
(
int
j
=
0
;
j
<
resultList
.
size
();
j
++)
{
for
(
int
j
=
0
;
j
<
resultList
.
size
();
j
++)
{
JSONObject
result
=
resultList
.
getJSONObject
(
j
);
JSONObject
result
=
resultList
.
getJSONObject
(
j
);
String
reelId
=
result
.
getString
(
"reelId"
);
String
reelId
=
result
.
getString
(
"reelId"
);
String
message
=
result
.
getString
(
"message"
);
String
message
=
result
.
getString
(
"message"
);
if
(
StringUtils
.
isNotBlank
(
reelId
))
{
if
(
StringUtils
.
isNotBlank
(
reelId
))
{
reelList
.
add
(
reelId
);
reelList
.
add
(
reelId
);
resultMap
.
put
(
reelId
,
message
);
resultMap
.
put
(
reelId
,
message
);
}
}
}
}
}
}
}
}
else
{
log
.
info
(
"第"
+
retryCount
+
"次调用返回非200状态: "
+
status
);
}
}
}
catch
(
Exception
e
)
{
log
.
error
(
"第"
+
retryCount
+
"次批量禁用接口调用失败: "
+
e
.
getMessage
(),
e
);
}
}
}
}
// 如果3次都失败,将所有barcode加入reelList
if
(!
isSuccess
)
{
log
.
info
(
"经过"
+
maxRetries
+
"次重试后仍失败,将所有条码加入结果列表"
);
for
(
Barcode
barcode
:
barcodeList
)
{
String
reelId
=
barcode
.
getBarcode
();
reelList
.
add
(
reelId
);
resultMap
.
put
(
reelId
,
"接口调用失败,默认禁用"
);
}
}
}
catch
(
Exception
e
){
log
.
info
(
"批量禁用接口调用失败:"
+
e
.
getMessage
());
}
}
// 更新条码状态
for
(
Barcode
barcode
:
barcodeList
)
{
for
(
Barcode
barcode
:
barcodeList
)
{
if
(
reelList
.
contains
(
barcode
.
getBarcode
()))
{
if
(
reelList
.
contains
(
barcode
.
getBarcode
()))
{
String
message
=
resultMap
.
get
(
barcode
.
getBarcode
());
String
message
=
resultMap
.
get
(
barcode
.
getBarcode
());
barcode
.
setDisableMsg
(
message
);
barcode
.
setDisableMsg
(
message
);
barcodeManager
.
save
(
barcode
);
barcodeManager
.
save
(
barcode
);
...
...
src/main/java/com/neotel/smfcore/custom/luxsan/factory_c/rawstor/controller/CDeviceController.java
查看文件 @
9f57bb6
...
@@ -7,6 +7,7 @@ import com.neotel.smfcore.common.exception.ValidateException;
...
@@ -7,6 +7,7 @@ import com.neotel.smfcore.common.exception.ValidateException;
import
com.neotel.smfcore.common.utils.DateUtil
;
import
com.neotel.smfcore.common.utils.DateUtil
;
import
com.neotel.smfcore.common.utils.StringUtils
;
import
com.neotel.smfcore.common.utils.StringUtils
;
import
com.neotel.smfcore.core.api.SmfApi
;
import
com.neotel.smfcore.core.api.SmfApi
;
import
com.neotel.smfcore.core.barcode.bean.CodeBean
;
import
com.neotel.smfcore.core.barcode.service.manager.IBarcodeManager
;
import
com.neotel.smfcore.core.barcode.service.manager.IBarcodeManager
;
import
com.neotel.smfcore.core.barcode.service.manager.IComponentManager
;
import
com.neotel.smfcore.core.barcode.service.manager.IComponentManager
;
import
com.neotel.smfcore.core.barcode.service.po.Barcode
;
import
com.neotel.smfcore.core.barcode.service.po.Barcode
;
...
@@ -1679,4 +1680,227 @@ public class CDeviceController {
...
@@ -1679,4 +1680,227 @@ public class CDeviceController {
resultMap
.
put
(
"destination"
,
destination
);
resultMap
.
put
(
"destination"
,
destination
);
return
ResultBean
.
newOkResult
(
resultMap
);
return
ResultBean
.
newOkResult
(
resultMap
);
}
}
Map
<
String
,
Object
>
lockBoxMap
=
new
ConcurrentHashMap
<>();
@ApiOperation
(
"根据条码进行物料出库"
)
@RequestMapping
(
"/reelFromBoxByCode"
)
@AnonymousAccess
public
ResultBean
reelFromBoxByCode
(
@RequestBody
Map
<
String
,
String
>
paramMap
)
{
log
.
info
(
"获取料串信息:"
+
JSON
.
toJSONString
(
paramMap
));
String
code
=
paramMap
.
get
(
"code"
);
//条码编号
String
currentLoc
=
paramMap
.
get
(
"currentLoc"
);
//当前位置
String
stacker
=
paramMap
.
get
(
"stacker"
);
//条码编号
log
.
info
(
"根据条码进行物料出库,code为:"
+
code
+
",当前位置为:"
+
currentLoc
+
",条码编号为:"
+
stacker
);
//判断是不是有效的条码信息
if
(
StringUtils
.
isEmpty
(
code
))
{
saveMessage
(
MessageType
.
ERROR
.
name
(),
currentLoc
,
"未扫到条码信息"
);
return
ResultBean
.
newErrorResult
(-
1
,
""
,
"未扫到条码信息"
);
}
CodeBean
codeBean
=
codeResolve
.
resolveSingleCode
(
code
);
if
(!
codeBean
.
isValid
())
{
saveMessage
(
MessageType
.
ERROR
.
name
(),
currentLoc
,
code
+
"不是有效的条码"
);
return
ResultBean
.
newErrorResult
(-
1
,
""
,
code
+
"不是有效的条码"
);
}
//判断是否在库位中
Barcode
barcode
=
codeBean
.
getBarcode
();
if
(
StringUtils
.
isEmpty
(
barcode
.
getPosName
()))
{
log
.
info
(
code
+
"对应的库位为空,直接返回ok"
);
return
ResultBean
.
newOkResult
(
""
);
}
//按位置进行加锁
Object
lockObj
=
lockBoxMap
.
get
(
currentLoc
);
if
(
lockObj
==
null
)
{
lockObj
=
new
Object
();
lockBoxMap
.
put
(
currentLoc
,
lockObj
);
}
synchronized
(
lockBoxMap
.
get
(
currentLoc
))
{
String
boxPar
=
barcode
.
getPosName
();
String
box
=
BoxHandleUtil
.
getBoxStr
(
boxPar
,
true
);
Barcode
boxBarcode
=
codeResolve
.
resolveOneValideBarcode
(
box
);
StoragePos
inPos
=
storagePosManager
.
getByBarcode
(
boxBarcode
.
getBarcode
());
if
(
inPos
!=
null
)
{
boxBarcode
=
inPos
.
getBarcode
();
}
//获取当前隔口的物料信息
List
<
Barcode
>
subCodeList
=
boxBarcode
.
getSubCodeList
();
List
<
Barcode
>
barcodeList
=
new
ArrayList
<>();
for
(
Barcode
subCode
:
subCodeList
)
{
if
(
boxPar
.
equals
(
subCode
.
getPosName
()))
{
barcodeList
.
add
(
subCode
);
}
}
//判断当前出库的物料,是不是要出库的物料
boolean
needOut
=
false
;
if
(
barcode
.
isOut
())
{
needOut
=
true
;
}
else
{
Barcode
needOutBarcode
=
null
;
for
(
Barcode
subCode
:
barcodeList
)
{
if
(
subCode
.
isOut
())
{
needOutBarcode
=
subCode
;
break
;
}
}
if
(
needOutBarcode
!=
null
)
{
String
orderItemId
=
needOutBarcode
.
getOrderItemId
();
needOutBarcode
.
setOrderItemId
(
""
);
needOutBarcode
.
setOut
(
false
);
log
.
info
(
needOutBarcode
.
getBarcode
()
+
"需要改成不需要出库"
);
barcodeManager
.
save
(
needOutBarcode
);
boxBarcode
.
updateSubCodes
(
needOutBarcode
);
barcode
.
setOut
(
true
);
barcode
.
setOrderItemId
(
orderItemId
);
boxBarcode
.
updateSubCodes
(
barcode
);
barcodeManager
.
save
(
barcode
);
boxBarcode
.
UpdateSubCode
(
barcode
);
barcodeManager
.
save
(
boxBarcode
);
if
(
inPos
!=
null
){
inPos
.
setBarcode
(
boxBarcode
);
storagePosManager
.
save
(
inPos
);
}
log
.
info
(
barcode
.
getBarcode
()
+
"改成要出库,orderItemId为:"
+
orderItemId
);
needOut
=
true
;
}
}
if
(!
needOut
)
{
return
ResultBean
.
newErrorResult
(
1
,
""
,
boxPar
);
}
//通知wms,生成出库任务
String
orderItemId
=
barcode
.
getOrderItemId
();
String
orderId
=
""
;
String
orderNo
=
""
;
if
(
StringUtils
.
isNotEmpty
(
orderItemId
))
{
int
checkType
=
-
1
;
String
pkItemId
=
""
;
String
face
=
""
;
String
brand
=
""
;
String
batchCode
=
""
;
String
targetLoc
=
""
;
LiteOrderItem
orderItem
=
liteOrderItemManager
.
get
(
orderItemId
);
if
(
orderItem
!=
null
)
{
orderNo
=
orderItem
.
getOrderNo
();
orderId
=
orderItem
.
getOrderId
();
pkItemId
=
orderItem
.
getItemId
();
face
=
orderItem
.
getFace
();
brand
=
orderItem
.
getBrand
();
if
(!
"N/A"
.
equals
(
orderItem
.
getBatchCode
()))
{
batchCode
=
orderItem
.
getBatchCode
();
}
LiteOrder
order
=
liteOrderManager
.
get
(
orderItem
.
getOrderId
());
if
(
order
!=
null
)
{
targetLoc
=
order
.
getLoc
();
checkType
=
order
.
getCheckType
();
}
}
//通知WMS
if
(
checkType
==
LiteorderCheckType
.
PICKING_CHECKOUT
)
{
try
{
LuxsanApi
.
pickingIssue
(
new
PickingIssueRequest
(
CommonUtil
.
plantCode
,
orderNo
,
pkItemId
,
barcode
.
getPartNumber
()
,
barcode
.
getWarehouseCode
(),
brand
,
face
,
batchCode
,
Arrays
.
asList
(
barcode
.
getBarcode
())));
//同时 更新下 缓存目的地
if
(
StringUtils
.
isNotEmpty
(
targetLoc
))
{
if
(
targetLoc
.
endsWith
(
"BG"
))
{
log
.
info
(
"自动绑定料串["
+
stacker
+
"]目的地:C2-3F-BG"
);
MaterialLocUtil
.
updateStackerLoc
(
stacker
,
""
,
"C2-3F-BG"
,
1
,
orderItem
.
getOrderNo
(),
barcode
);
}
else
if
(
targetLoc
.
endsWith
(
"CG"
))
{
log
.
info
(
"自动绑定料串["
+
stacker
+
"]目的地:C2-3F-CG"
);
MaterialLocUtil
.
updateStackerLoc
(
stacker
,
""
,
"C2-3F-CG"
,
1
,
orderItem
.
getOrderNo
(),
barcode
);
}
else
if
(
targetLoc
.
endsWith
(
"2F"
))
{
log
.
info
(
"自动绑定料串["
+
stacker
+
"]目的地:C1-2F"
);
MaterialLocUtil
.
updateStackerLoc
(
stacker
,
""
,
"C1-2F"
,
1
,
orderItem
.
getOrderNo
(),
barcode
);
}
else
if
(
targetLoc
.
endsWith
(
"1F"
))
{
log
.
info
(
"自动绑定料串["
+
stacker
+
"]目的地:C2-1F"
);
MaterialLocUtil
.
updateStackerLoc
(
stacker
,
""
,
"C2-1F"
,
1
,
orderItem
.
getOrderNo
(),
barcode
);
}
}
}
catch
(
Exception
e
)
{
log
.
info
(
barcode
.
getBarcode
()
+
"PK发料失败:"
+
e
.
getMessage
()
+
",隔口:"
+
barcode
.
getPosName
()
+
"需要清空出库信息"
);
List
<
Barcode
>
newSubCodeList
=
new
ArrayList
<>();
for
(
Barcode
subCode
:
boxBarcode
.
getSubCodeList
())
{
if
(
subCode
.
isOut
())
{
if
(
barcode
.
getPosName
().
equals
(
subCode
.
getPosName
()))
{
newSubCodeList
.
add
(
subCode
);
}
}
}
for
(
Barcode
subCode
:
newSubCodeList
)
{
if
(
subCode
.
isOut
())
{
if
(
barcode
.
getPosName
().
equals
(
subCode
.
getPosName
()))
{
String
itemId
=
subCode
.
getOrderItemId
();
subCode
.
setOut
(
false
);
subCode
.
setSelectMsg
(
null
);
subCode
.
setOrderItemId
(
null
);
barcodeManager
.
save
(
subCode
);
boxBarcode
.
updateSubCodes
(
subCode
);
//生成任务
generateTask
(
subCode
,
OP_STATUS
.
CANCEL
.
name
(),
subCode
.
getAmount
(),
OP
.
CHECKOUT
,
itemId
,
""
,
0
,
false
);
log
.
info
(
subCode
.
getBarcode
()
+
"隔口为:"
+
subCode
.
getPosName
()
+
"需清除出库标记"
);
}
}
}
barcodeManager
.
save
(
boxBarcode
);
if
(
inPos
!=
null
)
{
inPos
.
setBarcode
(
boxBarcode
);
storagePosManager
.
save
(
inPos
);
}
return
ResultBean
.
newErrorResult
(-
1
,
""
,
barcode
.
getBarcode
()
+
"请求PK发料失败,隔口:"
+
barcode
.
getPosName
()
+
"出库信息已清空"
);
}
}
}
else
{
//人工出库,
LuxsanApi
.
pickingIssue
(
new
PickingIssueRequest
(
CommonUtil
.
plantCode
,
"SMFW"
+
System
.
currentTimeMillis
(),
"0"
,
barcode
.
getPartNumber
()
,
barcode
.
getWarehouseCode
(),
""
,
""
,
""
,
Arrays
.
asList
(
barcode
.
getBarcode
())));
}
DataLog
dataLog
=
new
DataLog
(
new
Storage
(),
barcode
,
new
StoragePos
());
dataLog
.
setSubSourceId
(
orderItemId
);
dataLog
.
setSourceId
(
orderId
);
dataLog
.
setSourceName
(
orderNo
);
dataLog
.
setType
(
OP
.
CHECKOUT
);
dataLog
.
setStatus
(
OP_STATUS
.
FINISHED
.
name
());
dataLog
.
setPosName
(
boxPar
);
dataLog
.
setNormal
(
true
);
dataLog
.
setDateCode
(
barcode
.
getDateCode
());
dataLog
.
setBatchInfo
(
barcode
.
getBatch
());
dataLog
.
setProvider
(
barcode
.
getProvider
());
dataLog
.
setProviderNumber
(
barcode
.
getProviderNumber
());
dataLog
.
setWarehouseCode
(
barcode
.
getWarehouseCode
());
if
(
StringUtils
.
isNotEmpty
(
currentLoc
))
{
dataLog
.
setCurrentLoc
(
currentLoc
);
}
taskService
.
updateFinishedTask
(
dataLog
);
//有出库,此料格就去除满格标志
boxBarcode
.
updateExtraData
(
barcode
.
getPosName
(),
null
);
boxBarcode
.
removeFromSubCodes
(
barcode
);
barcodeManager
.
save
(
boxBarcode
);
if
(
inPos
!=
null
)
{
//为保证数据一致性, pos中的box barcode也需要更新
inPos
.
setBarcode
(
boxBarcode
);
storagePosManager
.
save
(
inPos
);
}
//清理条码档案信息
log
.
info
(
barcode
.
getBarcode
()
+
"的库位设置为空"
);
barcode
.
setPosName
(
""
);
barcode
.
setOut
(
false
);
barcode
.
setOrderId
(
""
);
barcode
.
setOrderItemId
(
""
);
barcode
.
setBarSource
(
""
);
barcodeManager
.
save
(
barcode
);
Map
<
String
,
String
>
resultMap
=
new
HashMap
<>();
resultMap
.
put
(
"binCode"
,
boxPar
);
resultMap
.
put
(
"barcode"
,
barcode
.
getBarcode
());
resultMap
.
put
(
"pickingId"
,
orderNo
);
resultMap
.
put
(
"platSize"
,
barcode
.
getPlateSize
()
+
""
);
resultMap
.
put
(
"height"
,
barcode
.
getHeight
()
+
""
);
kafkaService
.
sendMachineParameterStackerAndBox
(
stacker
,
currentLoc
,
0
,
boxBarcode
.
getBarcode
(),
barcode
.
getAmount
(),
4
);
return
ResultBean
.
newOkResult
(
resultMap
);
}
}
}
}
src/main/resources/config/application.yml
查看文件 @
9f57bb6
...
@@ -49,7 +49,7 @@ lizhen:
...
@@ -49,7 +49,7 @@ lizhen:
differenceUrl
:
http://10.68.27.104/smf-core/api/Mes/differenceReel
differenceUrl
:
http://10.68.27.104/smf-core/api/Mes/differenceReel
storageC12F
:
storageC12F
:
name
:
storageC12F
name
:
storageC12F
line
:
BG02T,BG02B,CG20B1,CG02B2,CG02T1,CG02T2,AS02T1,AS02T2,AS02T3,AS02B1,AS02B2
line
:
BG02T,BG02B,CG20B1,CG02B2,CG02T1,CG02T2,AS02T1,AS02T2,AS02T3,AS02B1,AS02B2
,BG03T1,BG03T2,BG03B1,BG03B2,BG04B,BG04T,CG03T1,CG03T2,CG03B
url
:
http://10.68.27.105/smf-core/api/Mes/machineCallMaterial
url
:
http://10.68.27.105/smf-core/api/Mes/machineCallMaterial
differenceUrl
:
http://10.68.27.105/smf-core/api/Mes/differenceReel
differenceUrl
:
http://10.68.27.105/smf-core/api/Mes/differenceReel
...
...
编写
预览
支持
Markdown
格式
附加文件
你添加了
0
人
到此讨论。请谨慎行事。
Finish editing this message first!
Cancel
请
注册
或
登录
后发表评论