Skip to content
切换导航条
切换导航条
当前项目
正在载入...
登录
孙克
/
smf-core
转到一个项目
切换导航栏
切换导航栏固定状态
项目
群组
代码片段
帮助
项目
活动
版本库
流水线
图表
问题
0
合并请求
0
维基
网络
创建新的问题
作业
提交
问题看板
文件
提交
网络
比较
分支
标签
Commit 4c2054bd
由
sunke
编写于
2021-07-26 14:02:18 +0800
浏览文件
选项
浏览文件
标签
下载
电子邮件补丁
差异文件
上传文件
1 个父辈
9d1e0a8c
全部展开
显示空白字符变更
内嵌
并排
正在显示
10 个修改的文件
包含
218 行增加
和
37 行删除
src/main/java/com/neotel/smfcore/common/csv/CsvReader.java
src/main/java/com/neotel/smfcore/common/csv/CsvWriter.java
src/main/java/com/neotel/smfcore/core/barcode/rest/BacodeController.java
src/main/java/com/neotel/smfcore/core/order/rest/OrderController.java
src/main/java/com/neotel/smfcore/core/storage/rest/StorageController.java
src/main/java/com/neotel/smfcore/security/bean/FileProperties.java
src/main/java/com/neotel/smfcore/security/config/ConfigurerAdapter.java
src/main/resources/config/application-dev.yml
src/main/resources/config/application.yml
src/main/resources/log4j2-spring.xml
src/main/java/com/neotel/smfcore/common/csv/CsvReader.java
0 → 100644
查看文件 @
4c2054b
此文件的差异被折叠,
点击展开。
src/main/java/com/neotel/smfcore/common/csv/CsvWriter.java
0 → 100644
查看文件 @
4c2054b
此文件的差异被折叠,
点击展开。
src/main/java/com/neotel/smfcore/core/barcode/rest/BacodeController.java
查看文件 @
4c2054b
package
com
.
neotel
.
smfcore
.
core
.
barcode
.
rest
;
package
com
.
neotel
.
smfcore
.
core
.
barcode
.
rest
;
import
com.google.common.collect.Lists
;
import
com.neotel.smfcore.common.bean.PageData
;
import
com.neotel.smfcore.common.bean.PageData
;
import
com.neotel.smfcore.common.bean.ResultBean
;
import
com.neotel.smfcore.common.csv.CsvReader
;
import
com.neotel.smfcore.common.exception.BadRequestException
;
import
com.neotel.smfcore.common.exception.BadRequestException
;
import
com.neotel.smfcore.common.utils.FileUtil
;
import
com.neotel.smfcore.common.utils.QueryHelp
;
import
com.neotel.smfcore.common.utils.QueryHelp
;
import
com.neotel.smfcore.core.barcode.rest.bean.dto.BarcodeDto
;
import
com.neotel.smfcore.core.barcode.rest.bean.dto.BarcodeDto
;
import
com.neotel.smfcore.core.barcode.rest.bean.dto.BarcodeSettingDto
;
import
com.neotel.smfcore.core.barcode.rest.bean.dto.BarcodeSettingDto
;
...
@@ -12,6 +16,7 @@ import com.neotel.smfcore.core.barcode.service.manager.IBarcodeManager;
...
@@ -12,6 +16,7 @@ import com.neotel.smfcore.core.barcode.service.manager.IBarcodeManager;
import
com.neotel.smfcore.core.barcode.service.po.Barcode
;
import
com.neotel.smfcore.core.barcode.service.po.Barcode
;
import
com.neotel.smfcore.core.device.util.DataCache
;
import
com.neotel.smfcore.core.device.util.DataCache
;
import
com.neotel.smfcore.core.system.service.po.Settings
;
import
com.neotel.smfcore.core.system.service.po.Settings
;
import
com.neotel.smfcore.security.bean.FileProperties
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
import
io.swagger.annotations.ApiOperation
;
import
lombok.RequiredArgsConstructor
;
import
lombok.RequiredArgsConstructor
;
...
@@ -22,10 +27,13 @@ import org.springframework.data.mongodb.core.query.Query;
...
@@ -22,10 +27,13 @@ import org.springframework.data.mongodb.core.query.Query;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.security.access.prepost.PreAuthorize
;
import
org.springframework.security.access.prepost.PreAuthorize
;
import
org.springframework.util.ObjectUtils
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.multipart.MultipartFile
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.File
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map
;
...
@@ -46,6 +54,9 @@ public class BacodeController {
...
@@ -46,6 +54,9 @@ public class BacodeController {
@Autowired
@Autowired
private
final
DataCache
dataCache
;
private
final
DataCache
dataCache
;
@Autowired
private
final
FileProperties
properties
;
@ApiOperation
(
"导出条码数据"
)
@ApiOperation
(
"导出条码数据"
)
@GetMapping
(
value
=
"/download"
)
@GetMapping
(
value
=
"/download"
)
public
void
download
(
HttpServletResponse
response
,
BarcodeQueryCriteria
criteria
)
throws
Exception
{
public
void
download
(
HttpServletResponse
response
,
BarcodeQueryCriteria
criteria
)
throws
Exception
{
...
@@ -129,4 +140,80 @@ public class BacodeController {
...
@@ -129,4 +140,80 @@ public class BacodeController {
//修改设置
//修改设置
return
new
ResponseEntity
<>(
HttpStatus
.
OK
);
return
new
ResponseEntity
<>(
HttpStatus
.
OK
);
}
}
@ApiOperation
(
"上传条码数据"
)
@PostMapping
(
value
=
"/upload"
)
public
ResultBean
upload
(
@RequestParam
MultipartFile
uploadFile
)
throws
Exception
{
String
image
=
"csv"
;
String
fileType
=
FileUtil
.
getExtensionName
(
uploadFile
.
getOriginalFilename
());
if
(
fileType
!=
null
&&
!
image
.
contains
(
fileType
)){
throw
new
BadRequestException
(
"文件格式错误!, 仅支持 "
+
image
+
" 格式"
);
}
File
folder
=
new
File
(
properties
.
getPath
(),
"pos"
);
File
file
=
FileUtil
.
upload
(
uploadFile
,
folder
.
getAbsolutePath
());
String
resultMsg
=
handleBarcode
(
file
.
getAbsolutePath
());
return
ResultBean
.
newOkResult
(
resultMsg
);
}
protected
String
handleBarcode
(
String
fileURL
)
throws
Exception
{
log
.
info
(
"开始读取文件:"
+
fileURL
);
CsvReader
csvRead
=
new
CsvReader
(
fileURL
);
csvRead
.
setSkipEmptyRecords
(
true
);
//忽略空行
csvRead
.
setTrimWhitespace
(
true
);
//去除空格
csvRead
.
readHeaders
();
int
riIndex
=
csvRead
.
getIndex
(
"条码"
,
"RI"
);
int
pnIndex
=
csvRead
.
getIndex
(
"物编"
,
"PN"
);
int
qtyIndex
=
csvRead
.
getIndex
(
"数量"
,
"QTY"
);
int
wIndex
=
csvRead
.
getIndex
(
"宽度"
,
"W"
);
int
hIndex
=
csvRead
.
getIndex
(
"高度"
,
"H"
);
int
spIndex
=
csvRead
.
getIndex
(
"供应商"
,
"SP"
,
"supplier"
);
int
row
=
1
;
int
newRowCount
=
0
;
int
updateRowCount
=
0
;
List
<
Barcode
>
list
=
Lists
.
newArrayList
();
while
(
csvRead
.
readRecord
()){
row
++;
String
[]
lineValues
=
csvRead
.
getValues
();
String
ri
=
lineValues
[
riIndex
];
String
pn
=
lineValues
[
pnIndex
];
if
(
ObjectUtils
.
isEmpty
(
pn
)
||
ObjectUtils
.
isEmpty
(
ri
)){
log
.
warn
(
"第"
+
row
+
"行中有空白内容,此行忽略"
);
continue
;
}
Barcode
barcode
=
barcodeManager
.
findByBarcode
(
ri
);
if
(
barcode
==
null
){
newRowCount
++;
barcode
=
new
Barcode
();
barcode
.
setBarcode
(
ri
);
}
else
{
updateRowCount
++;
}
barcode
.
setPartNumber
(
pn
);
if
(
qtyIndex
!=
-
1
){
String
qtyStr
=
lineValues
[
qtyIndex
];
barcode
.
setAmount
(
Double
.
valueOf
(
qtyStr
).
intValue
());
}
if
(
wIndex
!=
-
1
){
String
wStr
=
lineValues
[
wIndex
];
barcode
.
setPlateSize
(
Double
.
valueOf
(
wStr
).
intValue
());
}
if
(
hIndex
!=
-
1
){
String
hStr
=
lineValues
[
hIndex
];
barcode
.
setHeight
(
Double
.
valueOf
(
hStr
).
intValue
());
}
if
(
spIndex
!=
-
1
){
String
supplier
=
lineValues
[
spIndex
];
barcode
.
setProvider
(
supplier
);
}
barcodeManager
.
save
(
barcode
);
}
String
msg
=
"共["
+
row
+
"]行数据:新增【"
+
newRowCount
+
"】更新【"
+
updateRowCount
+
"】个"
;
log
.
info
(
msg
);
return
msg
;
}
}
}
src/main/java/com/neotel/smfcore/core/order/rest/OrderController.java
查看文件 @
4c2054b
...
@@ -39,6 +39,7 @@ import org.springframework.util.CollectionUtils;
...
@@ -39,6 +39,7 @@ import org.springframework.util.CollectionUtils;
import
org.springframework.util.ObjectUtils
;
import
org.springframework.util.ObjectUtils
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.multipart.MultipartFile
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Set
;
import
java.util.Set
;
...
@@ -75,6 +76,13 @@ public class OrderController {
...
@@ -75,6 +76,13 @@ public class OrderController {
// userService.download(userService.queryAll(criteria), response);
// userService.download(userService.queryAll(criteria), response);
// }
// }
@ApiOperation
(
"上传工单"
)
@PostMapping
(
value
=
"/upload"
)
public
ResultBean
updateAvatar
(
@RequestParam
MultipartFile
orderFile
){
return
null
;
}
@ApiOperation
(
"工单出库"
)
@ApiOperation
(
"工单出库"
)
@PostMapping
(
value
=
"/out"
)
@PostMapping
(
value
=
"/out"
)
@PreAuthorize
(
"@el.check('order:out')"
)
@PreAuthorize
(
"@el.check('order:out')"
)
...
...
src/main/java/com/neotel/smfcore/core/storage/rest/StorageController.java
查看文件 @
4c2054b
package
com
.
neotel
.
smfcore
.
core
.
storage
.
rest
;
package
com
.
neotel
.
smfcore
.
core
.
storage
.
rest
;
import
com.google.common.base.Strings
;
import
com.neotel.smfcore.common.bean.PageData
;
import
com.neotel.smfcore.common.bean.PageData
;
import
com.neotel.smfcore.common.bean.ResultBean
;
import
com.neotel.smfcore.common.csv.CsvReader
;
import
com.neotel.smfcore.common.exception.BadRequestException
;
import
com.neotel.smfcore.common.exception.BadRequestException
;
import
com.neotel.smfcore.common.exception.ValidateException
;
import
com.neotel.smfcore.common.utils.FileUtil
;
import
com.neotel.smfcore.common.utils.QueryHelp
;
import
com.neotel.smfcore.common.utils.QueryHelp
;
import
com.neotel.smfcore.core.device.util.DataCache
;
import
com.neotel.smfcore.core.storage.rest.dto.StorageDto
;
import
com.neotel.smfcore.core.storage.rest.dto.StorageDto
;
import
com.neotel.smfcore.core.storage.rest.mapstruct.StorageMapper
;
import
com.neotel.smfcore.core.storage.rest.mapstruct.StorageMapper
;
import
com.neotel.smfcore.core.storage.rest.query.StorageQueryCriteria
;
import
com.neotel.smfcore.core.storage.rest.query.StorageQueryCriteria
;
import
com.neotel.smfcore.core.storage.service.manager.IStorageManager
;
import
com.neotel.smfcore.core.storage.service.manager.IStorageManager
;
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.Storage
;
import
com.neotel.smfcore.core.storage.service.po.StoragePos
;
import
com.neotel.smfcore.security.bean.FileProperties
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
import
io.swagger.annotations.ApiOperation
;
import
lombok.RequiredArgsConstructor
;
import
lombok.RequiredArgsConstructor
;
...
@@ -20,8 +29,10 @@ import org.springframework.http.ResponseEntity;
...
@@ -20,8 +29,10 @@ import org.springframework.http.ResponseEntity;
import
org.springframework.security.access.prepost.PreAuthorize
;
import
org.springframework.security.access.prepost.PreAuthorize
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.multipart.MultipartFile
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.File
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Set
;
import
java.util.Set
;
...
@@ -37,6 +48,14 @@ public class StorageController {
...
@@ -37,6 +48,14 @@ public class StorageController {
@Autowired
@Autowired
private
final
StorageMapper
storageMapper
;
private
final
StorageMapper
storageMapper
;
@Autowired
private
final
FileProperties
properties
;
@Autowired
private
final
IStoragePosManager
storagePosManager
;
@Autowired
private
final
DataCache
dataCache
;
@ApiOperation
(
"查询料仓"
)
@ApiOperation
(
"查询料仓"
)
@GetMapping
@GetMapping
...
@@ -82,4 +101,95 @@ public class StorageController {
...
@@ -82,4 +101,95 @@ public class StorageController {
}
}
return
new
ResponseEntity
<>(
HttpStatus
.
OK
);
return
new
ResponseEntity
<>(
HttpStatus
.
OK
);
}
}
@ApiOperation
(
"上传库位信息"
)
@PostMapping
(
value
=
"/{storageId}/upload"
)
public
ResultBean
upload
(
@PathVariable
String
storageId
,
@RequestParam
MultipartFile
uploadFile
)
throws
Exception
{
// 验证文件上传的格式
String
image
=
"csv"
;
String
fileType
=
FileUtil
.
getExtensionName
(
uploadFile
.
getOriginalFilename
());
if
(
fileType
!=
null
&&
!
image
.
contains
(
fileType
)){
throw
new
BadRequestException
(
"文件格式错误!, 仅支持 "
+
image
+
" 格式"
);
}
File
folder
=
new
File
(
properties
.
getPath
(),
"pos"
);
File
file
=
FileUtil
.
upload
(
uploadFile
,
folder
.
getAbsolutePath
());
String
resultMsg
=
handleStoragePos
(
file
.
getAbsolutePath
(),
storageId
);
return
ResultBean
.
newOkResult
(
resultMsg
);
}
/**
*
*/
protected
String
handleStoragePos
(
String
fileURL
,
String
storageId
)
throws
Exception
{
log
.
info
(
"开始更新料仓【"
+
storageId
+
"】的位置信息"
);
if
(
Strings
.
isNullOrEmpty
(
storageId
))
{
log
.
error
(
"Storage id is null"
);
throw
new
ValidateException
(
"storage.error.notExist"
);
}
Storage
storage
=
storageManager
.
get
(
storageId
);
if
(
storage
==
null
)
{
log
.
error
(
"Storage id is not exist"
);
throw
new
ValidateException
(
"storage.error.notExist"
);
}
CsvReader
csvRead
=
new
CsvReader
(
fileURL
);
csvRead
.
setSkipEmptyRecords
(
true
);
//忽略空行
csvRead
.
setTrimWhitespace
(
true
);
//去除空格
csvRead
.
readHeaders
();
int
posIndex
=
csvRead
.
getIndex
(
"位置"
,
"pos"
);
if
(
posIndex
==
-
1
){
log
.
info
(
"未包含【位置】或【pos】列"
);
throw
new
ValidateException
(
"必须包含[位置]列"
);
}
int
priIndex
=
csvRead
.
getIndex
(
"优先级"
,
"pri"
);
if
(
priIndex
==
-
1
){
log
.
info
(
"未包含【优先级】或【pri】列"
);
throw
new
ValidateException
(
"必须包含[优先级]列"
);
}
int
hIndex
=
csvRead
.
getIndex
(
"高度"
,
"h"
);
if
(
hIndex
==
-
1
){
log
.
info
(
"未包含【高度】或【h】列"
);
throw
new
ValidateException
(
"必须包含【高度】列"
);
}
int
wIndex
=
csvRead
.
getIndex
(
"宽度"
,
"w"
);
if
(
wIndex
==
-
1
){
log
.
info
(
"未包含【宽度】或【w】列"
);
throw
new
ValidateException
(
"必须包含【宽度】列"
);
}
int
row
=
1
;
int
newRowCount
=
0
;
int
updateRowCount
=
0
;
while
(
csvRead
.
readRecord
()){
row
++;
String
[]
lineValues
=
csvRead
.
getValues
();
String
posName
=
lineValues
[
posIndex
];
String
priorityStr
=
lineValues
[
priIndex
];
String
hStr
=
lineValues
[
hIndex
];
String
wStr
=
lineValues
[
wIndex
];
if
(
posName
.
isEmpty
()
||
hStr
.
isEmpty
()
||
wStr
.
isEmpty
()){
log
.
warn
(
"第"
+
row
+
"行中有空白内容,此行忽略"
);
continue
;
}
StoragePos
posInfo
=
storagePosManager
.
getByPosName
(
posName
);
if
(
posInfo
==
null
){
posInfo
=
new
StoragePos
();
posInfo
.
setPosName
(
posName
);
newRowCount
++;
}
else
{
updateRowCount
++;
}
posInfo
.
setH
(
Integer
.
valueOf
(
hStr
));
posInfo
.
setW
(
Integer
.
valueOf
(
wStr
));
if
(!
Strings
.
isNullOrEmpty
(
priorityStr
)){
posInfo
.
setPriority
(
Double
.
valueOf
(
priorityStr
));
}
storagePosManager
.
save
(
posInfo
);
}
dataCache
.
reloadStorage
(
storage
);
String
msg
=
"读取到["
+
row
+
"]行数据:新增【"
+
newRowCount
+
"】更新【"
+
updateRowCount
+
"】"
;
log
.
info
(
msg
);
return
msg
;
}
}
}
src/main/java/com/neotel/smfcore/security/bean/FileProperties.java
查看文件 @
4c2054b
...
@@ -28,19 +28,13 @@ import org.springframework.context.annotation.Configuration;
...
@@ -28,19 +28,13 @@ import org.springframework.context.annotation.Configuration;
@ConfigurationProperties
(
prefix
=
"file"
)
@ConfigurationProperties
(
prefix
=
"file"
)
public
class
FileProperties
{
public
class
FileProperties
{
/** 文件大小限制 */
private
String
mac
;
private
Long
maxSize
;
/** 头像大小限制 */
private
String
linux
;
private
Long
avatarMaxSize
;
private
ElPath
mac
;
private
String
windows
;
private
ElPath
linux
;
public
String
getPath
(){
private
ElPath
windows
;
public
ElPath
getPath
(){
String
os
=
System
.
getProperty
(
"os.name"
);
String
os
=
System
.
getProperty
(
"os.name"
);
if
(
os
.
toLowerCase
().
startsWith
(
ElAdminConstant
.
WIN
))
{
if
(
os
.
toLowerCase
().
startsWith
(
ElAdminConstant
.
WIN
))
{
return
windows
;
return
windows
;
...
@@ -49,12 +43,4 @@ public class FileProperties {
...
@@ -49,12 +43,4 @@ public class FileProperties {
}
}
return
linux
;
return
linux
;
}
}
@Data
public
static
class
ElPath
{
private
String
path
;
private
String
avatar
;
}
}
}
src/main/java/com/neotel/smfcore/security/config/ConfigurerAdapter.java
查看文件 @
4c2054b
...
@@ -77,10 +77,7 @@ public class ConfigurerAdapter implements WebMvcConfigurer {
...
@@ -77,10 +77,7 @@ public class ConfigurerAdapter implements WebMvcConfigurer {
@Override
@Override
public
void
addResourceHandlers
(
ResourceHandlerRegistry
registry
)
{
public
void
addResourceHandlers
(
ResourceHandlerRegistry
registry
)
{
FileProperties
.
ElPath
path
=
properties
.
getPath
();
String
pathUtl
=
"file:"
+
properties
.
getPath
().
replace
(
"\\"
,
"/"
);
String
avatarUtl
=
"file:"
+
path
.
getAvatar
().
replace
(
"\\"
,
"/"
);
String
pathUtl
=
"file:"
+
path
.
getPath
().
replace
(
"\\"
,
"/"
);
registry
.
addResourceHandler
(
"/avatar/**"
).
addResourceLocations
(
avatarUtl
).
setCachePeriod
(
0
);
registry
.
addResourceHandler
(
"/file/**"
).
addResourceLocations
(
pathUtl
).
setCachePeriod
(
0
);
registry
.
addResourceHandler
(
"/file/**"
).
addResourceLocations
(
pathUtl
).
setCachePeriod
(
0
);
registry
.
addResourceHandler
(
"/**"
).
addResourceLocations
(
"classpath:/META-INF/resources/"
).
setCachePeriod
(
0
);
registry
.
addResourceHandler
(
"/**"
).
addResourceLocations
(
"classpath:/META-INF/resources/"
).
setCachePeriod
(
0
);
}
}
...
...
src/main/resources/config/application-dev.yml
查看文件 @
4c2054b
...
@@ -59,17 +59,4 @@ swagger:
...
@@ -59,17 +59,4 @@ swagger:
ip
:
ip
:
local-parsing
:
true
local-parsing
:
true
# 文件存储路径
file
:
mac
:
path
:
~/file/
avatar
:
~/avatar/
linux
:
path
:
/home/eladmin/file/
avatar
:
/home/eladmin/avatar/
windows
:
path
:
C:\eladmin\file\
avatar
:
C:\eladmin\avatar\
# 文件大小 /M
maxSize
:
100
avatarMaxSize
:
5
src/main/resources/config/application.yml
查看文件 @
4c2054b
...
@@ -5,6 +5,12 @@ hella:
...
@@ -5,6 +5,12 @@ hella:
host
:
host
:
port
:
9900
port
:
9900
# 文件存储路径
file
:
mac
:
~/file/
linux
:
/home/smf/file/
windows
:
C:\smf\file\
spring
:
spring
:
freemarker
:
freemarker
:
check-template-location
:
false
check-template-location
:
false
...
...
src/main/resources/log4j2-spring.xml
查看文件 @
4c2054b
...
@@ -22,7 +22,7 @@
...
@@ -22,7 +22,7 @@
<logger
name=
"ro"
level=
"WARN"
>
<logger
name=
"ro"
level=
"WARN"
>
</logger>
</logger>
<root
level=
"INFO"
>
<root
level=
"INFO"
>
<
!--<appender-ref ref="Console"/>--
>
<
appender-ref
ref=
"Console"
/
>
<appender-ref
ref=
"log"
/>
<appender-ref
ref=
"log"
/>
</root>
</root>
</loggers>
</loggers>
...
...
编写
预览
支持
Markdown
格式
附加文件
你添加了
0
人
到此讨论。请谨慎行事。
Finish editing this message first!
Cancel
请
注册
或
登录
后发表评论