已验证 提交 5f8a5b86 编写于 作者: xurime's avatar xurime

This closes #1867, breaking changes: change the data type for the...

This closes #1867, breaking changes: change the data type for the ConditionalFormatOptions structure field Format as a pointer
上级 5dc22e87
......@@ -999,7 +999,7 @@ func TestAdjustConditionalFormats(t *testing.T) {
{
Type: "cell",
Criteria: "greater than",
Format: formatID,
Format: &formatID,
Value: "0",
},
}
......
......@@ -1088,7 +1088,7 @@ func TestConditionalFormat(t *testing.T) {
{
Type: "cell",
Criteria: "between",
Format: format1,
Format: &format1,
MinValue: "6",
MaxValue: "8",
},
......@@ -1100,7 +1100,7 @@ func TestConditionalFormat(t *testing.T) {
{
Type: "cell",
Criteria: ">",
Format: format3,
Format: &format3,
Value: "6",
},
},
......@@ -1111,7 +1111,7 @@ func TestConditionalFormat(t *testing.T) {
{
Type: "top",
Criteria: "=",
Format: format3,
Format: &format3,
},
},
))
......@@ -1121,7 +1121,7 @@ func TestConditionalFormat(t *testing.T) {
{
Type: "unique",
Criteria: "=",
Format: format2,
Format: &format2,
},
},
))
......@@ -1131,7 +1131,7 @@ func TestConditionalFormat(t *testing.T) {
{
Type: "duplicate",
Criteria: "=",
Format: format2,
Format: &format2,
},
},
))
......@@ -1141,7 +1141,7 @@ func TestConditionalFormat(t *testing.T) {
{
Type: "top",
Criteria: "=",
Format: format1,
Format: &format1,
Value: "6",
Percent: true,
},
......@@ -1153,7 +1153,7 @@ func TestConditionalFormat(t *testing.T) {
{
Type: "average",
Criteria: "=",
Format: format3,
Format: &format3,
AboveAverage: true,
},
},
......@@ -1164,7 +1164,7 @@ func TestConditionalFormat(t *testing.T) {
{
Type: "average",
Criteria: "=",
Format: format1,
Format: &format1,
AboveAverage: false,
},
},
......@@ -1187,7 +1187,7 @@ func TestConditionalFormat(t *testing.T) {
{
Type: "formula",
Criteria: "L2<3",
Format: format1,
Format: &format1,
},
},
))
......@@ -1197,7 +1197,7 @@ func TestConditionalFormat(t *testing.T) {
{
Type: "cell",
Criteria: ">",
Format: format4,
Format: &format4,
Value: "0",
},
},
......
......@@ -892,7 +892,7 @@ func TestDuplicateRow(t *testing.T) {
assert.NoError(t, err)
expected := []ConditionalFormatOptions{
{Type: "cell", Criteria: "greater than", Format: format, Value: "0"},
{Type: "cell", Criteria: "greater than", Format: &format, Value: "0"},
}
assert.NoError(t, f.SetConditionalFormat("Sheet1", "A1", expected))
......
......@@ -2445,7 +2445,7 @@ func (f *File) SetCellStyle(sheet, topLeftCell, bottomRightCell string, styleID
// {
// Type: "cell",
// Criteria: ">",
// Format: format,
// Format: &format,
// Value: "6",
// },
// },
......@@ -2458,7 +2458,7 @@ func (f *File) SetCellStyle(sheet, topLeftCell, bottomRightCell string, styleID
// {
// Type: "cell",
// Criteria: ">",
// Format: format,
// Format: &format,
// Value: "$C$1",
// },
// },
......@@ -2482,7 +2482,7 @@ func (f *File) SetCellStyle(sheet, topLeftCell, bottomRightCell string, styleID
// }
// err = f.SetConditionalFormat("Sheet1", "D1:D10",
// []excelize.ConditionalFormatOptions{
// {Type: "cell", Criteria: ">", Format: format, Value: "6"},
// {Type: "cell", Criteria: ">", Format: &format, Value: "6"},
// },
// )
//
......@@ -2534,7 +2534,7 @@ func (f *File) SetCellStyle(sheet, topLeftCell, bottomRightCell string, styleID
// {
// Type: "cell",
// Criteria: "between",
// Format: format,
// Format: &format,
// MinValue: 6",
// MaxValue: 8",
// },
......@@ -2554,7 +2554,7 @@ func (f *File) SetCellStyle(sheet, topLeftCell, bottomRightCell string, styleID
// {
// Type: "average",
// Criteria: "=",
// Format: format1,
// Format: &format1,
// AboveAverage: true,
// },
// },
......@@ -2566,7 +2566,7 @@ func (f *File) SetCellStyle(sheet, topLeftCell, bottomRightCell string, styleID
// {
// Type: "average",
// Criteria: "=",
// Format: format2,
// Format: &format2,
// AboveAverage: false,
// },
// },
......@@ -2578,7 +2578,7 @@ func (f *File) SetCellStyle(sheet, topLeftCell, bottomRightCell string, styleID
// // Highlight cells rules: Duplicate Values...
// err := f.SetConditionalFormat("Sheet1", "A1:A10",
// []excelize.ConditionalFormatOptions{
// {Type: "duplicate", Criteria: "=", Format: format},
// {Type: "duplicate", Criteria: "=", Format: &format},
// },
// )
//
......@@ -2587,7 +2587,7 @@ func (f *File) SetCellStyle(sheet, topLeftCell, bottomRightCell string, styleID
// // Highlight cells rules: Not Equal To...
// err := f.SetConditionalFormat("Sheet1", "A1:A10",
// []excelize.ConditionalFormatOptions{
// {Type: "unique", Criteria: "=", Format: format},
// {Type: "unique", Criteria: "=", Format: &format},
// },
// )
//
......@@ -2600,7 +2600,7 @@ func (f *File) SetCellStyle(sheet, topLeftCell, bottomRightCell string, styleID
// {
// Type: "top",
// Criteria: "=",
// Format: format,
// Format: &format,
// Value: "6",
// },
// },
......@@ -2613,7 +2613,7 @@ func (f *File) SetCellStyle(sheet, topLeftCell, bottomRightCell string, styleID
// {
// Type: "top",
// Criteria: "=",
// Format: format,
// Format: &format,
// Value: "6",
// Percent: true,
// },
......@@ -2931,10 +2931,7 @@ func (f *File) appendCfRule(ws *xlsxWorksheet, rule *xlsxX14CfRule) error {
// settings for cell value (include between, not between, equal, not equal,
// greater than and less than) by given conditional formatting rule.
func (f *File) extractCondFmtCellIs(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
format := ConditionalFormatOptions{StopIfTrue: c.StopIfTrue, Type: "cell", Criteria: operatorType[c.Operator]}
if c.DxfID != nil {
format.Format = *c.DxfID
}
format := ConditionalFormatOptions{Format: c.DxfID, StopIfTrue: c.StopIfTrue, Type: "cell", Criteria: operatorType[c.Operator]}
if len(c.Formula) == 2 {
format.MinValue, format.MaxValue = c.Formula[0], c.Formula[1]
return format
......@@ -2946,21 +2943,13 @@ func (f *File) extractCondFmtCellIs(c *xlsxCfRule, extLst *xlsxExtLst) Condition
// extractCondFmtTimePeriod provides a function to extract conditional format
// settings for time period by given conditional formatting rule.
func (f *File) extractCondFmtTimePeriod(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
format := ConditionalFormatOptions{StopIfTrue: c.StopIfTrue, Type: "time_period", Criteria: operatorType[c.Operator]}
if c.DxfID != nil {
format.Format = *c.DxfID
}
return format
return ConditionalFormatOptions{Format: c.DxfID, StopIfTrue: c.StopIfTrue, Type: "time_period", Criteria: operatorType[c.Operator]}
}
// extractCondFmtText provides a function to extract conditional format
// settings for text cell values by given conditional formatting rule.
func (f *File) extractCondFmtText(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
format := ConditionalFormatOptions{StopIfTrue: c.StopIfTrue, Type: "text", Criteria: operatorType[c.Operator], Value: c.Text}
if c.DxfID != nil {
format.Format = *c.DxfID
}
return format
return ConditionalFormatOptions{Format: c.DxfID, StopIfTrue: c.StopIfTrue, Type: "text", Criteria: operatorType[c.Operator], Value: c.Text}
}
// extractCondFmtTop10 provides a function to extract conditional format
......@@ -2968,15 +2957,13 @@ func (f *File) extractCondFmtText(c *xlsxCfRule, extLst *xlsxExtLst) Conditional
// rule.
func (f *File) extractCondFmtTop10(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
format := ConditionalFormatOptions{
Format: c.DxfID,
StopIfTrue: c.StopIfTrue,
Type: "top",
Criteria: "=",
Percent: c.Percent,
Value: strconv.Itoa(c.Rank),
}
if c.DxfID != nil {
format.Format = *c.DxfID
}
if c.Bottom {
format.Type = "bottom"
}
......@@ -2988,13 +2975,11 @@ func (f *File) extractCondFmtTop10(c *xlsxCfRule, extLst *xlsxExtLst) Conditiona
// rule.
func (f *File) extractCondFmtAboveAverage(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
format := ConditionalFormatOptions{
Format: c.DxfID,
StopIfTrue: c.StopIfTrue,
Type: "average",
Criteria: "=",
}
if c.DxfID != nil {
format.Format = *c.DxfID
}
if c.AboveAverage != nil {
format.AboveAverage = *c.AboveAverage
}
......@@ -3005,7 +2990,8 @@ func (f *File) extractCondFmtAboveAverage(c *xlsxCfRule, extLst *xlsxExtLst) Con
// conditional format settings for duplicate and unique values by given
// conditional formatting rule.
func (f *File) extractCondFmtDuplicateUniqueValues(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
format := ConditionalFormatOptions{
return ConditionalFormatOptions{
Format: c.DxfID,
StopIfTrue: c.StopIfTrue,
Type: map[string]string{
"duplicateValues": "duplicate",
......@@ -3013,62 +2999,46 @@ func (f *File) extractCondFmtDuplicateUniqueValues(c *xlsxCfRule, extLst *xlsxEx
}[c.Type],
Criteria: "=",
}
if c.DxfID != nil {
format.Format = *c.DxfID
}
return format
}
// extractCondFmtBlanks provides a function to extract conditional format
// settings for blank cells by given conditional formatting rule.
func (f *File) extractCondFmtBlanks(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
format := ConditionalFormatOptions{
return ConditionalFormatOptions{
Format: c.DxfID,
StopIfTrue: c.StopIfTrue,
Type: "blanks",
}
if c.DxfID != nil {
format.Format = *c.DxfID
}
return format
}
// extractCondFmtNoBlanks provides a function to extract conditional format
// settings for no blank cells by given conditional formatting rule.
func (f *File) extractCondFmtNoBlanks(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
format := ConditionalFormatOptions{
return ConditionalFormatOptions{
Format: c.DxfID,
StopIfTrue: c.StopIfTrue,
Type: "no_blanks",
}
if c.DxfID != nil {
format.Format = *c.DxfID
}
return format
}
// extractCondFmtErrors provides a function to extract conditional format
// settings for cells with errors by given conditional formatting rule.
func (f *File) extractCondFmtErrors(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
format := ConditionalFormatOptions{
return ConditionalFormatOptions{
Format: c.DxfID,
StopIfTrue: c.StopIfTrue,
Type: "errors",
}
if c.DxfID != nil {
format.Format = *c.DxfID
}
return format
}
// extractCondFmtNoErrors provides a function to extract conditional format
// settings for cells without errors by given conditional formatting rule.
func (f *File) extractCondFmtNoErrors(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
format := ConditionalFormatOptions{
return ConditionalFormatOptions{
Format: c.DxfID,
StopIfTrue: c.StopIfTrue,
Type: "no_errors",
}
if c.DxfID != nil {
format.Format = *c.DxfID
}
return format
}
// extractCondFmtColorScale provides a function to extract conditional format
......@@ -3165,10 +3135,7 @@ func (f *File) extractCondFmtDataBar(c *xlsxCfRule, extLst *xlsxExtLst) Conditio
// extractCondFmtExp provides a function to extract conditional format settings
// for expression by given conditional formatting rule.
func (f *File) extractCondFmtExp(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
format := ConditionalFormatOptions{StopIfTrue: c.StopIfTrue, Type: "formula"}
if c.DxfID != nil {
format.Format = *c.DxfID
}
format := ConditionalFormatOptions{Format: c.DxfID, StopIfTrue: c.StopIfTrue, Type: "formula"}
if len(c.Formula) > 0 {
format.Criteria = c.Formula[0]
}
......@@ -3234,7 +3201,7 @@ func drawCondFmtCellIs(p int, ct, ref, GUID string, format *ConditionalFormatOpt
StopIfTrue: format.StopIfTrue,
Type: validType[format.Type],
Operator: ct,
DxfID: intPtr(format.Format),
DxfID: format.Format,
}
// "between" and "not between" criteria require 2 values.
if ct == "between" || ct == "notBetween" {
......@@ -3268,7 +3235,7 @@ func drawCondFmtTimePeriod(p int, ct, ref, GUID string, format *ConditionalForma
"continue month": fmt.Sprintf("AND(MONTH(%[1]s)=MONTH(TODAY())+1,OR(YEAR(%[1]s)=YEAR(TODAY()),AND(MONTH(%[1]s)=12,YEAR(%[1]s)=YEAR(TODAY())+1)))", ref),
}[ct],
},
DxfID: intPtr(format.Format),
DxfID: format.Format,
}, nil
}
......@@ -3298,7 +3265,7 @@ func drawCondFmtText(p int, ct, ref, GUID string, format *ConditionalFormatOptio
strings.NewReplacer(`"`, `""`).Replace(format.Value), ref),
}[ct],
},
DxfID: intPtr(format.Format),
DxfID: format.Format,
}, nil
}
......@@ -3312,7 +3279,7 @@ func drawCondFmtTop10(p int, ct, ref, GUID string, format *ConditionalFormatOpti
Bottom: format.Type == "bottom",
Type: validType[format.Type],
Rank: 10,
DxfID: intPtr(format.Format),
DxfID: format.Format,
Percent: format.Percent,
}
if rank, err := strconv.Atoi(format.Value); err == nil {
......@@ -3330,7 +3297,7 @@ func drawCondFmtAboveAverage(p int, ct, ref, GUID string, format *ConditionalFor
StopIfTrue: format.StopIfTrue,
Type: validType[format.Type],
AboveAverage: boolPtr(format.AboveAverage),
DxfID: intPtr(format.Format),
DxfID: format.Format,
}, nil
}
......@@ -3342,7 +3309,7 @@ func drawCondFmtDuplicateUniqueValues(p int, ct, ref, GUID string, format *Condi
Priority: p + 1,
StopIfTrue: format.StopIfTrue,
Type: validType[format.Type],
DxfID: intPtr(format.Format),
DxfID: format.Format,
}, nil
}
......@@ -3430,7 +3397,7 @@ func drawCondFmtExp(p int, ct, ref, GUID string, format *ConditionalFormatOption
StopIfTrue: format.StopIfTrue,
Type: validType[format.Type],
Formula: []string{format.Criteria},
DxfID: intPtr(format.Format),
DxfID: format.Format,
}, nil
}
......@@ -3442,7 +3409,7 @@ func drawCondFmtErrors(p int, ct, ref, GUID string, format *ConditionalFormatOpt
StopIfTrue: format.StopIfTrue,
Type: validType[format.Type],
Formula: []string{fmt.Sprintf("ISERROR(%s)", ref)},
DxfID: intPtr(format.Format),
DxfID: format.Format,
}, nil
}
......@@ -3454,7 +3421,7 @@ func drawCondFmtNoErrors(p int, ct, ref, GUID string, format *ConditionalFormatO
StopIfTrue: format.StopIfTrue,
Type: validType[format.Type],
Formula: []string{fmt.Sprintf("NOT(ISERROR(%s))", ref)},
DxfID: intPtr(format.Format),
DxfID: format.Format,
}, nil
}
......@@ -3466,7 +3433,7 @@ func drawCondFmtBlanks(p int, ct, ref, GUID string, format *ConditionalFormatOpt
StopIfTrue: format.StopIfTrue,
Type: validType[format.Type],
Formula: []string{fmt.Sprintf("LEN(TRIM(%s))=0", ref)},
DxfID: intPtr(format.Format),
DxfID: format.Format,
}, nil
}
......@@ -3478,7 +3445,7 @@ func drawCondFmtNoBlanks(p int, ct, ref, GUID string, format *ConditionalFormatO
StopIfTrue: format.StopIfTrue,
Type: validType[format.Type],
Formula: []string{fmt.Sprintf("LEN(TRIM(%s))>0", ref)},
DxfID: intPtr(format.Format),
DxfID: format.Format,
}, nil
}
......
......@@ -172,7 +172,7 @@ func TestSetConditionalFormat(t *testing.T) {
// Test creating a conditional format with a solid color data bar style
f := NewFile()
condFmts := []ConditionalFormatOptions{
{Type: "data_bar", BarColor: "#A9D08E", BarSolid: true, Format: 0, Criteria: "=", MinType: "min", MaxType: "max"},
{Type: "data_bar", BarColor: "#A9D08E", BarSolid: true, Format: intPtr(0), Criteria: "=", MinType: "min", MaxType: "max"},
}
for _, ref := range []string{"A1:A2", "B1:B2"} {
assert.NoError(t, f.SetConditionalFormat("Sheet1", ref, condFmts))
......@@ -243,36 +243,36 @@ func TestSetConditionalFormat(t *testing.T) {
func TestGetConditionalFormats(t *testing.T) {
for _, format := range [][]ConditionalFormatOptions{
{{Type: "cell", Format: 1, Criteria: "greater than", Value: "6"}},
{{Type: "cell", Format: 1, Criteria: "between", MinValue: "6", MaxValue: "8"}},
{{Type: "time_period", Format: 1, Criteria: "yesterday"}},
{{Type: "time_period", Format: 1, Criteria: "today"}},
{{Type: "time_period", Format: 1, Criteria: "tomorrow"}},
{{Type: "time_period", Format: 1, Criteria: "last 7 days"}},
{{Type: "time_period", Format: 1, Criteria: "last week"}},
{{Type: "time_period", Format: 1, Criteria: "this week"}},
{{Type: "time_period", Format: 1, Criteria: "continue week"}},
{{Type: "time_period", Format: 1, Criteria: "last month"}},
{{Type: "time_period", Format: 1, Criteria: "this month"}},
{{Type: "time_period", Format: 1, Criteria: "continue month"}},
{{Type: "text", Format: 1, Criteria: "containing", Value: "~!@#$%^&*()_+{}|:<>?\"';"}},
{{Type: "text", Format: 1, Criteria: "not containing", Value: "text"}},
{{Type: "text", Format: 1, Criteria: "begins with", Value: "prefix"}},
{{Type: "text", Format: 1, Criteria: "ends with", Value: "suffix"}},
{{Type: "top", Format: 1, Criteria: "=", Value: "6"}},
{{Type: "bottom", Format: 1, Criteria: "=", Value: "6"}},
{{Type: "average", AboveAverage: true, Format: 1, Criteria: "="}},
{{Type: "duplicate", Format: 1, Criteria: "="}},
{{Type: "unique", Format: 1, Criteria: "="}},
{{Type: "cell", Format: intPtr(1), Criteria: "greater than", Value: "6"}},
{{Type: "cell", Format: intPtr(1), Criteria: "between", MinValue: "6", MaxValue: "8"}},
{{Type: "time_period", Format: intPtr(1), Criteria: "yesterday"}},
{{Type: "time_period", Format: intPtr(1), Criteria: "today"}},
{{Type: "time_period", Format: intPtr(1), Criteria: "tomorrow"}},
{{Type: "time_period", Format: intPtr(1), Criteria: "last 7 days"}},
{{Type: "time_period", Format: intPtr(1), Criteria: "last week"}},
{{Type: "time_period", Format: intPtr(1), Criteria: "this week"}},
{{Type: "time_period", Format: intPtr(1), Criteria: "continue week"}},
{{Type: "time_period", Format: intPtr(1), Criteria: "last month"}},
{{Type: "time_period", Format: intPtr(1), Criteria: "this month"}},
{{Type: "time_period", Format: intPtr(1), Criteria: "continue month"}},
{{Type: "text", Format: intPtr(1), Criteria: "containing", Value: "~!@#$%^&*()_+{}|:<>?\"';"}},
{{Type: "text", Format: intPtr(1), Criteria: "not containing", Value: "text"}},
{{Type: "text", Format: intPtr(1), Criteria: "begins with", Value: "prefix"}},
{{Type: "text", Format: intPtr(1), Criteria: "ends with", Value: "suffix"}},
{{Type: "top", Format: intPtr(1), Criteria: "=", Value: "6"}},
{{Type: "bottom", Format: intPtr(1), Criteria: "=", Value: "6"}},
{{Type: "average", AboveAverage: true, Format: intPtr(1), Criteria: "="}},
{{Type: "duplicate", Format: intPtr(1), Criteria: "="}},
{{Type: "unique", Format: intPtr(1), Criteria: "="}},
{{Type: "3_color_scale", Criteria: "=", MinType: "num", MidType: "num", MaxType: "num", MinValue: "-10", MidValue: "50", MaxValue: "10", MinColor: "#FF0000", MidColor: "#00FF00", MaxColor: "#0000FF"}},
{{Type: "2_color_scale", Criteria: "=", MinType: "num", MaxType: "num", MinColor: "#FF0000", MaxColor: "#0000FF"}},
{{Type: "data_bar", Criteria: "=", MinType: "num", MaxType: "num", MinValue: "-10", MaxValue: "10", BarBorderColor: "#0000FF", BarColor: "#638EC6", BarOnly: true, BarSolid: true, StopIfTrue: true}},
{{Type: "data_bar", Criteria: "=", MinType: "min", MaxType: "max", BarBorderColor: "#0000FF", BarColor: "#638EC6", BarDirection: "rightToLeft", BarOnly: true, BarSolid: true, StopIfTrue: true}},
{{Type: "formula", Format: 1, Criteria: "="}},
{{Type: "blanks", Format: 1}},
{{Type: "no_blanks", Format: 1}},
{{Type: "errors", Format: 1}},
{{Type: "no_errors", Format: 1}},
{{Type: "formula", Format: intPtr(1), Criteria: "="}},
{{Type: "blanks", Format: intPtr(1)}},
{{Type: "no_blanks", Format: intPtr(1)}},
{{Type: "errors", Format: intPtr(1)}},
{{Type: "no_errors", Format: intPtr(1)}},
{{Type: "icon_set", IconStyle: "3Arrows", ReverseIcons: true, IconsOnly: true}},
} {
f := NewFile()
......@@ -309,7 +309,7 @@ func TestUnsetConditionalFormat(t *testing.T) {
assert.NoError(t, f.UnsetConditionalFormat("Sheet1", "A1:A10"))
format, err := f.NewConditionalStyle(&Style{Font: &Font{Color: "9A0511"}, Fill: Fill{Type: "pattern", Color: []string{"FEC7CE"}, Pattern: 1}})
assert.NoError(t, err)
assert.NoError(t, f.SetConditionalFormat("Sheet1", "A1:A10", []ConditionalFormatOptions{{Type: "cell", Criteria: ">", Format: format, Value: "6"}}))
assert.NoError(t, f.SetConditionalFormat("Sheet1", "A1:A10", []ConditionalFormatOptions{{Type: "cell", Criteria: ">", Format: &format, Value: "6"}}))
assert.NoError(t, f.UnsetConditionalFormat("Sheet1", "A1:A10"))
// Test unset conditional format on not exists worksheet
assert.EqualError(t, f.UnsetConditionalFormat("SheetN", "A1:A10"), "sheet SheetN does not exist")
......
......@@ -917,7 +917,7 @@ type ConditionalFormatOptions struct {
Type string
AboveAverage bool
Percent bool
Format int
Format *int
Criteria string
Value string
MinType string
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册