Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
疯人忠
Cvat
提交
96090f26
C
Cvat
项目概览
疯人忠
/
Cvat
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
Cvat
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
96090f26
编写于
6月 21, 2023
作者:
K
klakhov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
reworked cvat-core classes
上级
a136a86c
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
311 addition
and
288 deletion
+311
-288
cvat-core/src/quality-conflict.ts
cvat-core/src/quality-conflict.ts
+97
-112
cvat-core/src/quality-report.ts
cvat-core/src/quality-report.ts
+68
-75
cvat-core/src/quality-settings.ts
cvat-core/src/quality-settings.ts
+146
-101
未找到文件。
cvat-core/src/quality-conflict.ts
浏览文件 @
96090f26
...
...
@@ -34,129 +34,114 @@ export interface SerializedAnnotationConflictData {
}
export
class
AnnotationConflict
{
public
readonly
jobID
:
number
;
public
readonly
serverID
:
number
;
public
clientID
:
number
;
public
readonly
type
:
string
;
public
readonly
shapeType
:
string
|
null
;
public
readonly
conflictType
:
QualityConflictType
;
public
readonly
severity
:
ConflictSeverity
;
public
readonly
description
:
string
;
#
jobID
:
number
;
#
serverID
:
number
;
#
clientID
:
number
;
#
type
:
string
;
#
shapeType
:
string
|
null
;
#
conflictType
:
QualityConflictType
;
#
severity
:
ConflictSeverity
;
#
description
:
string
;
constructor
(
initialData
:
SerializedAnnotationConflictData
)
{
const
data
:
SerializedAnnotationConflictData
=
{
job_id
:
undefined
,
obj_id
:
undefined
,
client_id
:
undefined
,
type
:
undefined
,
shape_type
:
undefined
,
conflict_type
:
undefined
,
severity
:
undefined
,
};
for
(
const
property
in
data
)
{
if
(
Object
.
prototype
.
hasOwnProperty
.
call
(
data
,
property
)
&&
property
in
initialData
)
{
data
[
property
]
=
initialData
[
property
];
}
}
Object
.
defineProperties
(
this
,
Object
.
freeze
({
jobID
:
{
get
:
()
=>
data
.
job_id
,
},
serverID
:
{
get
:
()
=>
data
.
obj_id
,
},
clientID
:
{
get
:
()
=>
data
.
client_id
,
set
:
(
newID
:
number
)
=>
{
data
.
client_id
=
newID
;
},
},
type
:
{
get
:
()
=>
data
.
type
,
},
shapeType
:
{
get
:
()
=>
data
.
shape_type
,
},
conflictType
:
{
get
:
()
=>
data
.
conflict_type
,
},
severity
:
{
get
:
()
=>
data
.
severity
,
},
description
:
{
get
:
()
=>
{
const
desc
=
this
.
conflictType
.
split
(
'
_
'
).
join
(
'
'
);
return
desc
.
charAt
(
0
).
toUpperCase
()
+
desc
.
slice
(
1
);
},
},
}),
);
this
.
#
jobID
=
initialData
.
job_id
;
this
.
#
serverID
=
initialData
.
obj_id
;
this
.
#
clientID
=
initialData
.
client_id
;
this
.
#
type
=
initialData
.
type
;
this
.
#
shapeType
=
initialData
.
shape_type
;
this
.
#
conflictType
=
initialData
.
conflict_type
as
QualityConflictType
;
this
.
#
severity
=
initialData
.
severity
as
ConflictSeverity
;
const
desc
=
this
.
#
conflictType
.
split
(
'
_
'
).
join
(
'
'
);
this
.
#
description
=
desc
.
charAt
(
0
).
toUpperCase
()
+
desc
.
slice
(
1
);
}
get
jobID
():
number
{
return
this
.
#
jobID
;
}
get
serverID
():
number
{
return
this
.
#
serverID
;
}
get
clientID
():
number
{
return
this
.
#
clientID
;
}
set
clientID
(
newID
:
number
)
{
this
.
#
clientID
=
newID
;
}
get
type
():
string
{
return
this
.
#
type
;
}
get
shapeType
():
string
|
null
{
return
this
.
#
shapeType
;
}
get
conflictType
():
QualityConflictType
{
return
this
.
#
conflictType
;
}
get
severity
():
ConflictSeverity
{
return
this
.
#
severity
;
}
get
description
():
string
{
return
this
.
#
description
;
}
}
export
default
class
QualityConflict
{
public
readonly
id
:
number
;
public
readonly
frame
:
number
;
public
readonly
type
:
QualityConflictType
;
public
readonly
annotationConflicts
:
AnnotationConflict
[];
public
readonly
severity
:
ConflictSeverity
;
public
description
:
string
;
#
id
:
number
;
#
frame
:
number
;
#
type
:
QualityConflictType
;
#
annotationConflicts
:
AnnotationConflict
[];
#
severity
:
ConflictSeverity
;
#
description
:
string
;
constructor
(
initialData
:
SerializedQualityConflictData
)
{
const
data
:
SerializedQualityConflictData
=
{
id
:
undefined
,
frame
:
undefined
,
type
:
undefined
,
annotation_ids
:
[],
severity
:
undefined
,
description
:
undefined
,
};
for
(
const
property
in
data
)
{
if
(
Object
.
prototype
.
hasOwnProperty
.
call
(
data
,
property
)
&&
property
in
initialData
)
{
data
[
property
]
=
initialData
[
property
];
}
}
data
.
annotation_ids
=
data
.
annotation_ids
this
.
#
id
=
initialData
.
id
;
this
.
#
frame
=
initialData
.
frame
;
this
.
#
type
=
initialData
.
type
as
QualityConflictType
;
this
.
#
severity
=
initialData
.
severity
as
ConflictSeverity
;
this
.
#
annotationConflicts
=
initialData
.
annotation_ids
.
map
((
rawData
:
SerializedAnnotationConflictData
)
=>
new
AnnotationConflict
({
...
rawData
,
conflict_type
:
d
ata
.
type
,
severity
:
d
ata
.
severity
,
conflict_type
:
initialD
ata
.
type
,
severity
:
initialD
ata
.
severity
,
}));
const
desc
=
data
.
type
.
split
(
'
_
'
).
join
(
'
'
);
data
.
description
=
desc
.
charAt
(
0
).
toUpperCase
()
+
desc
.
slice
(
1
);
Object
.
defineProperties
(
this
,
Object
.
freeze
({
id
:
{
get
:
()
=>
data
.
id
,
},
frame
:
{
get
:
()
=>
data
.
frame
,
},
type
:
{
get
:
()
=>
data
.
type
,
},
annotationConflicts
:
{
get
:
()
=>
data
.
annotation_ids
,
},
severity
:
{
get
:
()
=>
data
.
severity
,
},
description
:
{
get
:
()
=>
data
.
description
,
set
:
(
newDescription
)
=>
{
data
.
description
=
newDescription
;
},
},
}),
);
const
desc
=
initialData
.
type
.
split
(
'
_
'
).
join
(
'
'
);
this
.
#
description
=
desc
.
charAt
(
0
).
toUpperCase
()
+
desc
.
slice
(
1
);
}
get
id
():
number
{
return
this
.
#
id
;
}
get
frame
():
number
{
return
this
.
#
frame
;
}
get
type
():
QualityConflictType
{
return
this
.
#
type
;
}
get
annotationConflicts
():
AnnotationConflict
[]
{
return
this
.
#
annotationConflicts
;
}
get
severity
():
ConflictSeverity
{
return
this
.
#
severity
;
}
get
description
():
string
{
return
this
.
#
description
;
}
set
description
(
newDescription
:
string
)
{
this
.
#
description
=
newDescription
;
}
}
cvat-core/src/quality-report.ts
浏览文件 @
96090f26
...
...
@@ -57,84 +57,77 @@ export interface QualitySummary {
}
export
default
class
QualityReport
{
public
readonly
id
:
number
;
public
readonly
parentId
:
number
;
public
readonly
taskId
:
number
;
public
readonly
jobId
:
number
;
public
readonly
target
:
string
;
public
readonly
createdDate
:
string
;
public
readonly
gtLastUpdated
:
string
;
public
readonly
summary
:
QualitySummary
;
#
id
:
number
;
#
parentId
:
number
;
#
taskId
:
number
;
#
jobId
:
number
;
#
target
:
string
;
#
createdDate
:
string
;
#
gtLastUpdated
:
string
;
#
summary
:
Partial
<
SerializedQualityReportData
[
'
summary
'
]
>
;
constructor
(
initialData
:
SerializedQualityReportData
)
{
const
data
:
SerializedQualityReportData
=
{
id
:
undefined
,
parent_id
:
undefined
,
task_id
:
undefined
,
job_id
:
undefined
,
target
:
''
,
gt_last_updated
:
undefined
,
summary
:
undefined
,
created_date
:
undefined
,
};
this
.
#
id
=
initialData
.
id
;
this
.
#
parentId
=
initialData
.
parent_id
;
this
.
#
taskId
=
initialData
.
task_id
;
this
.
#
jobId
=
initialData
.
job_id
;
this
.
#
target
=
initialData
.
target
;
this
.
#
gtLastUpdated
=
initialData
.
gt_last_updated
;
this
.
#
summary
=
initialData
.
summary
;
}
for
(
const
property
in
data
)
{
if
(
Object
.
prototype
.
hasOwnProperty
.
call
(
data
,
property
)
&&
property
in
initialData
)
{
data
[
property
]
=
initialData
[
property
];
}
}
get
id
():
number
{
return
this
.
#
id
;
}
Object
.
defineProperties
(
this
,
Object
.
freeze
({
id
:
{
get
:
()
=>
data
.
id
,
},
parentId
:
{
get
:
()
=>
data
.
parent_id
,
},
taskId
:
{
get
:
()
=>
data
.
task_id
,
},
jobId
:
{
get
:
()
=>
data
.
job_id
,
},
target
:
{
get
:
()
=>
data
.
target
,
},
gtLastUpdated
:
{
get
:
()
=>
data
.
gt_last_updated
,
},
summary
:
{
get
:
()
=>
({
frameCount
:
data
.
summary
.
frame_count
,
frameSharePercent
:
data
.
summary
.
frame_share
*
100
,
conflictCount
:
data
.
summary
.
conflict_count
,
validCount
:
data
.
summary
.
valid_count
,
dsCount
:
data
.
summary
.
ds_count
,
gtCount
:
data
.
summary
.
gt_count
,
accuracy
:
(
data
.
summary
.
valid_count
/
(
data
.
summary
.
ds_count
+
data
.
summary
.
gt_count
-
data
.
summary
.
valid_count
))
*
100
,
precision
:
(
data
.
summary
.
valid_count
/
data
.
summary
.
gt_count
)
*
100
,
recall
:
(
data
.
summary
.
valid_count
/
data
.
summary
.
ds_count
)
*
100
,
conflictsByType
:
{
extraAnnotations
:
data
.
summary
.
conflicts_by_type
?.
extra_annotation
,
missingAnnotations
:
data
.
summary
.
conflicts_by_type
?.
missing_annotation
,
mismatchingLabel
:
data
.
summary
.
conflicts_by_type
?.
mismatching_label
,
lowOverlap
:
data
.
summary
.
conflicts_by_type
?.
low_overlap
,
mismatchingDirection
:
data
.
summary
.
conflicts_by_type
?.
mismatching_direction
,
mismatchingAttributes
:
data
.
summary
.
conflicts_by_type
?.
mismatching_attributes
,
mismatchingGroups
:
data
.
summary
.
conflicts_by_type
?.
mismatching_groups
,
coveredAnnotation
:
data
.
summary
.
conflicts_by_type
?.
covered_annotation
,
},
errorCount
:
data
.
summary
.
error_count
,
warningCount
:
data
.
summary
.
warning_count
,
}),
},
createdDate
:
{
get
:
()
=>
data
.
created_date
,
},
}),
);
get
parentId
():
number
{
return
this
.
#
parentId
;
}
get
taskId
():
number
{
return
this
.
#
taskId
;
}
get
jobId
():
number
{
return
this
.
#
jobId
;
}
get
target
():
string
{
return
this
.
#
target
;
}
get
gtLastUpdated
():
string
{
return
this
.
#
gtLastUpdated
;
}
get
createdDate
():
string
{
return
this
.
#
createdDate
;
}
get
summary
():
QualitySummary
{
return
{
frameCount
:
this
.
#
summary
.
frame_count
,
frameSharePercent
:
this
.
#
summary
.
frame_share
*
100
,
conflictCount
:
this
.
#
summary
.
conflict_count
,
validCount
:
this
.
#
summary
.
valid_count
,
dsCount
:
this
.
#
summary
.
ds_count
,
gtCount
:
this
.
#
summary
.
gt_count
,
accuracy
:
(
this
.
#
summary
.
valid_count
/
(
this
.
#
summary
.
ds_count
+
this
.
#
summary
.
gt_count
-
this
.
#
summary
.
valid_count
))
*
100
,
precision
:
(
this
.
#
summary
.
valid_count
/
this
.
#
summary
.
gt_count
)
*
100
,
recall
:
(
this
.
#
summary
.
valid_count
/
this
.
#
summary
.
ds_count
)
*
100
,
conflictsByType
:
{
extraAnnotations
:
this
.
#
summary
.
conflicts_by_type
?.
extra_annotation
,
missingAnnotations
:
this
.
#
summary
.
conflicts_by_type
?.
missing_annotation
,
mismatchingLabel
:
this
.
#
summary
.
conflicts_by_type
?.
mismatching_label
,
lowOverlap
:
this
.
#
summary
.
conflicts_by_type
?.
low_overlap
,
mismatchingDirection
:
this
.
#
summary
.
conflicts_by_type
?.
mismatching_direction
,
mismatchingAttributes
:
this
.
#
summary
.
conflicts_by_type
?.
mismatching_attributes
,
mismatchingGroups
:
this
.
#
summary
.
conflicts_by_type
?.
mismatching_groups
,
coveredAnnotation
:
this
.
#
summary
.
conflicts_by_type
?.
covered_annotation
,
},
errorCount
:
this
.
#
summary
.
error_count
,
warningCount
:
this
.
#
summary
.
warning_count
,
};
}
}
cvat-core/src/quality-settings.ts
浏览文件 @
96090f26
...
...
@@ -23,20 +23,20 @@ export interface SerializedQualitySettingsData {
}
export
default
class
QualitySettings
{
public
readonly
id
:
number
;
public
readonly
task
:
number
;
public
iouThreshold
:
number
;
public
oksSigma
:
number
;
public
lineThickness
:
number
;
public
lowOverlapThreshold
:
number
;
public
orientedLines
:
boolean
;
public
lineOrientationThreshold
:
number
;
public
compareGroups
:
boolean
;
public
groupMatchThreshold
:
number
;
public
checkCoveredAnnotations
:
boolean
;
public
objectVisibilityThreshold
:
number
;
public
panopticComparison
:
boolean
;
public
compareAttributes
:
boolean
;
#
id
:
number
;
#
task
:
number
;
#
iouThreshold
:
number
;
#
oksSigma
:
number
;
#
lineThickness
:
number
;
#
lowOverlapThreshold
:
number
;
#
orientedLines
:
boolean
;
#
lineOrientationThreshold
:
number
;
#
compareGroups
:
boolean
;
#
groupMatchThreshold
:
number
;
#
checkCoveredAnnotations
:
boolean
;
#
objectVisibilityThreshold
:
number
;
#
panopticComparison
:
boolean
;
#
compareAttributes
:
boolean
;
constructor
(
initialData
:
SerializedQualitySettingsData
)
{
const
data
:
SerializedQualitySettingsData
=
{
...
...
@@ -56,6 +56,21 @@ export default class QualitySettings {
compare_attributes
:
undefined
,
};
this
.
#
id
=
initialData
.
id
;
this
.
#
task
=
initialData
.
task
;
this
.
#
iouThreshold
=
initialData
.
iou_threshold
;
this
.
#
oksSigma
=
initialData
.
oks_sigma
;
this
.
#
lineThickness
=
initialData
.
line_thickness
;
this
.
#
lowOverlapThreshold
=
initialData
.
low_overlap_threshold
;
this
.
#
orientedLines
=
initialData
.
compare_line_orientation
;
this
.
#
lineOrientationThreshold
=
initialData
.
line_orientation_threshold
;
this
.
#
compareGroups
=
initialData
.
compare_groups
;
this
.
#
groupMatchThreshold
=
initialData
.
group_match_threshold
;
this
.
#
checkCoveredAnnotations
=
initialData
.
check_covered_annotations
;
this
.
#
objectVisibilityThreshold
=
initialData
.
object_visibility_threshold
;
this
.
#
panopticComparison
=
initialData
.
panoptic_comparison
;
this
.
#
compareAttributes
=
initialData
.
compare_attributes
;
for
(
const
property
in
data
)
{
if
(
Object
.
prototype
.
hasOwnProperty
.
call
(
data
,
property
)
&&
property
in
initialData
)
{
data
[
property
]
=
initialData
[
property
];
...
...
@@ -68,99 +83,129 @@ export default class QualitySettings {
id
:
{
get
:
()
=>
data
.
id
,
},
task
:
{
get
:
()
=>
data
.
task
,
},
iouThreshold
:
{
get
:
()
=>
data
.
iou_threshold
,
set
:
(
value
:
number
)
=>
{
data
.
iou_threshold
=
value
;
},
},
oksSigma
:
{
get
:
()
=>
data
.
oks_sigma
,
set
:
(
value
:
number
)
=>
{
data
.
oks_sigma
=
value
;
},
},
lineThickness
:
{
get
:
()
=>
data
.
line_thickness
,
set
:
(
value
:
number
)
=>
{
data
.
line_thickness
=
value
;
},
},
lowOverlapThreshold
:
{
get
:
()
=>
data
.
low_overlap_threshold
,
set
:
(
value
:
number
)
=>
{
data
.
low_overlap_threshold
=
value
;
},
},
orientedLines
:
{
get
:
()
=>
data
.
compare_line_orientation
,
set
:
(
value
:
boolean
)
=>
{
data
.
compare_line_orientation
=
value
;
},
},
lineOrientationThreshold
:
{
get
:
()
=>
data
.
line_orientation_threshold
,
set
:
(
value
:
number
)
=>
{
data
.
line_orientation_threshold
=
value
;
},
},
compareGroups
:
{
get
:
()
=>
data
.
compare_groups
,
set
:
(
value
:
boolean
)
=>
{
data
.
compare_groups
=
value
;
},
},
groupMatchThreshold
:
{
get
:
()
=>
data
.
group_match_threshold
,
set
:
(
value
:
number
)
=>
{
data
.
group_match_threshold
=
value
;
},
},
checkCoveredAnnotations
:
{
get
:
()
=>
data
.
check_covered_annotations
,
set
:
(
value
:
boolean
)
=>
{
data
.
check_covered_annotations
=
value
;
},
},
objectVisibilityThreshold
:
{
get
:
()
=>
data
.
object_visibility_threshold
,
set
:
(
value
:
number
)
=>
{
data
.
object_visibility_threshold
=
value
;
},
},
panopticComparison
:
{
get
:
()
=>
data
.
panoptic_comparison
,
set
:
(
value
:
boolean
)
=>
{
data
.
panoptic_comparison
=
value
;
},
},
compareAttributes
:
{
get
:
()
=>
data
.
compare_attributes
,
set
:
(
value
:
boolean
)
=>
{
data
.
compare_attributes
=
value
;
},
},
}),
);
}
get
id
():
number
{
return
this
.
#
id
;
}
get
task
():
number
{
return
this
.
#
task
;
}
get
iouThreshold
():
number
{
return
this
.
#
iouThreshold
;
}
set
iouThreshold
(
newVal
:
number
)
{
this
.
#
iouThreshold
=
newVal
;
}
get
oksSigma
():
number
{
return
this
.
#
oksSigma
;
}
set
oksSigma
(
newVal
:
number
)
{
this
.
#
oksSigma
=
newVal
;
}
get
lineThickness
():
number
{
return
this
.
#
lineThickness
;
}
set
lineThickness
(
newVal
:
number
)
{
this
.
#
lineThickness
=
newVal
;
}
get
lowOverlapThreshold
():
number
{
return
this
.
#
lowOverlapThreshold
;
}
set
lowOverlapThreshold
(
newVal
:
number
)
{
this
.
#
lowOverlapThreshold
=
newVal
;
}
get
orientedLines
():
boolean
{
return
this
.
#
orientedLines
;
}
set
orientedLines
(
newVal
:
boolean
)
{
this
.
#
orientedLines
=
newVal
;
}
get
lineOrientationThreshold
():
number
{
return
this
.
#
lineOrientationThreshold
;
}
set
lineOrientationThreshold
(
newVal
:
number
)
{
this
.
#
lineOrientationThreshold
=
newVal
;
}
get
compareGroups
():
boolean
{
return
this
.
#
compareGroups
;
}
set
compareGroups
(
newVal
:
boolean
)
{
this
.
#
compareGroups
=
newVal
;
}
get
groupMatchThreshold
():
number
{
return
this
.
#
groupMatchThreshold
;
}
set
groupMatchThreshold
(
newVal
:
number
)
{
this
.
#
groupMatchThreshold
=
newVal
;
}
get
checkCoveredAnnotations
():
boolean
{
return
this
.
#
checkCoveredAnnotations
;
}
set
checkCoveredAnnotations
(
newVal
:
boolean
)
{
this
.
#
checkCoveredAnnotations
=
newVal
;
}
get
objectVisibilityThreshold
():
number
{
return
this
.
#
objectVisibilityThreshold
;
}
set
objectVisibilityThreshold
(
newVal
:
number
)
{
this
.
#
objectVisibilityThreshold
=
newVal
;
}
get
panopticComparison
():
boolean
{
return
this
.
#
panopticComparison
;
}
set
panopticComparison
(
newVal
:
boolean
)
{
this
.
#
panopticComparison
=
newVal
;
}
get
compareAttributes
():
boolean
{
return
this
.
#
compareAttributes
;
}
set
compareAttributes
(
newVal
:
boolean
)
{
this
.
#
compareAttributes
=
newVal
;
}
public
toJSON
():
SerializedQualitySettingsData
{
const
result
:
SerializedQualitySettingsData
=
{
iou_threshold
:
this
.
iouThreshold
,
oks_sigma
:
this
.
oksSigma
,
line_thickness
:
this
.
lineThickness
,
low_overlap_threshold
:
this
.
lowOverlapThreshold
,
compare_line_orientation
:
this
.
orientedLines
,
line_orientation_threshold
:
this
.
lineOrientationThreshold
,
compare_groups
:
this
.
compareGroups
,
group_match_threshold
:
this
.
groupMatchThreshold
,
check_covered_annotations
:
this
.
checkCoveredAnnotations
,
object_visibility_threshold
:
this
.
objectVisibilityThreshold
,
panoptic_comparison
:
this
.
panopticComparison
,
compare_attributes
:
this
.
compareAttributes
,
iou_threshold
:
this
.
#
iouThreshold
,
oks_sigma
:
this
.
#
oksSigma
,
line_thickness
:
this
.
#
lineThickness
,
low_overlap_threshold
:
this
.
#
lowOverlapThreshold
,
compare_line_orientation
:
this
.
#
orientedLines
,
line_orientation_threshold
:
this
.
#
lineOrientationThreshold
,
compare_groups
:
this
.
#
compareGroups
,
group_match_threshold
:
this
.
#
groupMatchThreshold
,
check_covered_annotations
:
this
.
#
checkCoveredAnnotations
,
object_visibility_threshold
:
this
.
#
objectVisibilityThreshold
,
panoptic_comparison
:
this
.
#
panopticComparison
,
compare_attributes
:
this
.
#
compareAttributes
,
};
return
result
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录