正在显示
12 个修改的文件
包含
148 行增加
和
25 行删除
@@ -671,6 +671,31 @@ func (this *ChanceController) ChanceReservePool() { | @@ -671,6 +671,31 @@ func (this *ChanceController) ChanceReservePool() { | ||
671 | msg = protocol.NewReturnResponse(chance.ChancePool(header, request)) | 671 | msg = protocol.NewReturnResponse(chance.ChancePool(header, request)) |
672 | } | 672 | } |
673 | 673 | ||
674 | +//SearchChance 搜索 | ||
675 | +//@router /search [post] | ||
676 | +func (this *ChanceController) SearchChance() { | ||
677 | + var msg *protocol.ResponseMessage | ||
678 | + defer func() { | ||
679 | + this.Resp(msg) | ||
680 | + }() | ||
681 | + var request *protocol.ChancePoolRequest | ||
682 | + if err := json.Unmarshal(this.ByteBody, &request); err != nil { | ||
683 | + log.Error(err) | ||
684 | + msg = protocol.BadRequestParam(1) | ||
685 | + return | ||
686 | + } | ||
687 | + if b, m := this.Valid(request); !b { | ||
688 | + msg = m | ||
689 | + return | ||
690 | + } | ||
691 | + if len(strings.TrimSpace(request.KeyWord)) == 0 { | ||
692 | + msg = protocol.BadRequestParamWithMessage(2, "请输入机会内容、员工姓名") | ||
693 | + return | ||
694 | + } | ||
695 | + header := controllers.GetRequestHeader(this.Ctx) | ||
696 | + msg = protocol.NewReturnResponse(chance.ChancePool(header, request)) | ||
697 | +} | ||
698 | + | ||
674 | //ChanceReviseDetail 机会补充详情 | 699 | //ChanceReviseDetail 机会补充详情 |
675 | //@router /chanceReviseDetail [post] | 700 | //@router /chanceReviseDetail [post] |
676 | func (this *ChanceController) ChanceReviseDetail() { | 701 | func (this *ChanceController) ChanceReviseDetail() { |
@@ -17,6 +17,7 @@ type AuditTemplate struct { | @@ -17,6 +17,7 @@ type AuditTemplate struct { | ||
17 | Code string `orm:"column(code);size(50);null" description:" 编码"` | 17 | Code string `orm:"column(code);size(50);null" description:" 编码"` |
18 | NoticeType int8 `orm:"column(notice_type)" description:"通知方式"` | 18 | NoticeType int8 `orm:"column(notice_type)" description:"通知方式"` |
19 | NoApprover int8 `orm:"column(no_approver)" description:"审核人空时:【1:自动通过】【2:转交给管理员】"` | 19 | NoApprover int8 `orm:"column(no_approver)" description:"审核人空时:【1:自动通过】【2:转交给管理员】"` |
20 | + SelfCheckNeed int8 `orm:"column(self_check_need)" description:"是否需要自查内容 【1:需要自查内容】【2:不需要】"` | ||
20 | SortNum int `orm:"column(sort_num)" description:"自定义排序编号"` | 21 | SortNum int `orm:"column(sort_num)" description:"自定义排序编号"` |
21 | VisibleType int8 `orm:"column(visible_type)" description:"可见范围 0:所有人 1:指定部门 "` | 22 | VisibleType int8 `orm:"column(visible_type)" description:"可见范围 0:所有人 1:指定部门 "` |
22 | VisibleObject string `orm:"column(visible_object);size(1000);null" description:"可见的对象 部门 指定人 json"` | 23 | VisibleObject string `orm:"column(visible_object);size(1000);null" description:"可见的对象 部门 指定人 json"` |
@@ -55,10 +55,12 @@ const ( | @@ -55,10 +55,12 @@ const ( | ||
55 | ) | 55 | ) |
56 | 56 | ||
57 | type ChancePoolOption struct { | 57 | type ChancePoolOption struct { |
58 | - ChanceTypeId int //机会类型编号 | ||
59 | - DIds []int //部门编号列表 | ||
60 | - Type int8 //机会类型 | ||
61 | - ReserveTypeId int //机会储备类型编号 | 58 | + ChanceTypeId int //机会类型编号 |
59 | + DIds []int //部门编号列表 | ||
60 | + Type int8 //机会类型 | ||
61 | + ReserveTypeId int //机会储备类型编号 | ||
62 | + KeyWord string //搜索特定内容的机会 (基础/附加) | ||
63 | + InUsers []int64 //搜索特定User的机会 | ||
62 | } | 64 | } |
63 | 65 | ||
64 | //机会池查询选项 | 66 | //机会池查询选项 |
@@ -74,6 +76,17 @@ func NewChancePoolOption(chanceTypeId int, deps []int, t int8, rt int) *ChancePo | @@ -74,6 +76,17 @@ func NewChancePoolOption(chanceTypeId int, deps []int, t int8, rt int) *ChancePo | ||
74 | ReserveTypeId: rt, | 76 | ReserveTypeId: rt, |
75 | } | 77 | } |
76 | } | 78 | } |
79 | +func (o *ChancePoolOption) SetKeyWord(keyWord string) *ChancePoolOption { | ||
80 | + o.KeyWord = keyWord | ||
81 | + return o | ||
82 | +} | ||
83 | +func (o *ChancePoolOption) SetInUsers(inUsers []int64) *ChancePoolOption { | ||
84 | + if len(inUsers) == 0 { | ||
85 | + return o | ||
86 | + } | ||
87 | + o.InUsers = inUsers | ||
88 | + return o | ||
89 | +} | ||
77 | 90 | ||
78 | var ( | 91 | var ( |
79 | SqlGetChanceSelfChecks = `select user_id,review_status,self_checks from chance where id =?` //机会自查数据 | 92 | SqlGetChanceSelfChecks = `select user_id,review_status,self_checks from chance where id =?` //机会自查数据 |
@@ -569,6 +582,11 @@ func getFilterSql(option *ChancePoolOption) string { | @@ -569,6 +582,11 @@ func getFilterSql(option *ChancePoolOption) string { | ||
569 | if option.ReserveTypeId > 0 { | 582 | if option.ReserveTypeId > 0 { |
570 | rsp.WriteString(fmt.Sprintf(" and reserve_type_id =%v ", option.ReserveTypeId)) | 583 | rsp.WriteString(fmt.Sprintf(" and reserve_type_id =%v ", option.ReserveTypeId)) |
571 | } | 584 | } |
585 | + if len(option.KeyWord) > 0 && len(option.InUsers) > 0 { | ||
586 | + rsp.WriteString(fmt.Sprintf(" and (user_id in (%v) or source_content like '%%%v%%' )", utils.JoinInt64s(option.InUsers, ","), option.KeyWord)) | ||
587 | + } else if len(option.KeyWord) > 0 { | ||
588 | + rsp.WriteString(fmt.Sprintf(" and source_content like '%%%v%%' ", option.KeyWord)) | ||
589 | + } | ||
572 | return rsp.String() | 590 | return rsp.String() |
573 | } | 591 | } |
574 | 592 |
@@ -129,3 +129,20 @@ func GetUserAllCompany(uid int64) (v []*UserCompany, err error) { | @@ -129,3 +129,20 @@ func GetUserAllCompany(uid int64) (v []*UserCompany, err error) { | ||
129 | } | 129 | } |
130 | return nil, err | 130 | return nil, err |
131 | } | 131 | } |
132 | + | ||
133 | +//获取用户Id列表 | ||
134 | +//@key CompanyId NickName | ||
135 | +func GetUserCompanyIdAllBy(options map[string]interface{}) (v []int64, err error) { | ||
136 | + o := orm.NewOrm() | ||
137 | + sql := "select id from user_company where enable=1" | ||
138 | + if _, ok := options["CompanyId"]; ok { | ||
139 | + sql += fmt.Sprintf(" and company_id=%v ", options["CompanyId"]) | ||
140 | + } | ||
141 | + if _, ok := options["NickName"]; ok { | ||
142 | + sql += fmt.Sprintf(" and nick_name like '%%%v%%' ", options["NickName"]) | ||
143 | + } | ||
144 | + if _, err = o.Raw(sql).QueryRows(&v); err == nil { | ||
145 | + return v, nil | ||
146 | + } | ||
147 | + return nil, err | ||
148 | +} |
@@ -203,8 +203,9 @@ type ChancePoolRequest struct { | @@ -203,8 +203,9 @@ type ChancePoolRequest struct { | ||
203 | ChanceTypeId int `json:"chanceTypeId"` //0:所有机会 编号:对应机会类型编号的机会 | 203 | ChanceTypeId int `json:"chanceTypeId"` //0:所有机会 编号:对应机会类型编号的机会 |
204 | DepartmentId int `json:"departmentId"` //部门编号 | 204 | DepartmentId int `json:"departmentId"` //部门编号 |
205 | IncludeSubDepartment bool | 205 | IncludeSubDepartment bool |
206 | - Type int8 `json:"type"` //0:机会池 1:储备池 | ||
207 | - ReserveTypeId int `json:"reserveTypeId"` //储备类型编号 | 206 | + Type int8 `json:"type"` //0:机会池 1:储备池 |
207 | + ReserveTypeId int `json:"reserveTypeId"` //储备类型编号 | ||
208 | + KeyWord string `json:"keyWord"` //搜索特定内容的机会 | ||
208 | } | 209 | } |
209 | type ChancePoolResponse struct { | 210 | type ChancePoolResponse struct { |
210 | List []CommonListItem `json:"list"` | 211 | List []CommonListItem `json:"list"` |
@@ -508,12 +509,28 @@ type Template struct { | @@ -508,12 +509,28 @@ type Template struct { | ||
508 | 509 | ||
509 | //表单 | 510 | //表单 |
510 | type Form struct { | 511 | type Form struct { |
511 | - Id int `json:"id"` | ||
512 | - Label string `json:"label"` | ||
513 | - InputType string `json:"inputType"` | ||
514 | - SectionType int8 `json:"sectionType"` | ||
515 | - Value string `json:"value"` | ||
516 | - Required int8 `json:"required"` | 512 | + Id int `json:"id"` |
513 | + Label string `json:"label"` | ||
514 | + InputType string `json:"inputType"` | ||
515 | + SectionType int8 `json:"sectionType"` | ||
516 | + Required int8 `json:"required"` | ||
517 | + Value string `json:"value"` | ||
518 | + ValueList []*ValueListItem `json:"valueList"` | ||
519 | + Data []*FormDataItem `json:"data"` | ||
520 | +} | ||
521 | + | ||
522 | +type ValueListItem struct { | ||
523 | + Type string `json:"type"` | ||
524 | + Value string `json:"value"` | ||
525 | +} | ||
526 | + | ||
527 | +type FormDataItem struct { | ||
528 | + Type string `json:"type"` | ||
529 | + Value string `json:"value"` | ||
530 | + Path string `json:"path,omitempty"` | ||
531 | + Cover *Cover `json:"cover,omitempty"` | ||
532 | + Duration int `json:"duration,omitempty"` | ||
533 | + Remark string `json:"remark,omitempty"` | ||
517 | } | 534 | } |
518 | 535 | ||
519 | //清楚未填写的表单数据 | 536 | //清楚未填写的表单数据 |
@@ -563,7 +580,18 @@ type Video struct { | @@ -563,7 +580,18 @@ type Video struct { | ||
563 | 580 | ||
564 | //审批配置 | 581 | //审批配置 |
565 | type AuditConfig struct { | 582 | type AuditConfig struct { |
566 | - NoApprover int8 `json:"no_approver"` //审核人空时:【1:自动通过】【2:转交给管理员】 | 583 | + NoApprover int8 `json:"no_approver"` //审核人空时:【1:自动通过】【2:转交给管理员】 |
584 | + SelfCheckNeed int8 `json:"self_check_need"` //审核人是否需要提交自查 1:需要 0:不需要 | ||
585 | +} | ||
586 | + | ||
587 | +func (c AuditConfig) GetSelfCheckNeed() int { | ||
588 | + if c.SelfCheckNeed == 1 { | ||
589 | + return 1 | ||
590 | + } | ||
591 | + if c.SelfCheckNeed == 2 { | ||
592 | + return 0 | ||
593 | + } | ||
594 | + return 1 | ||
567 | } | 595 | } |
568 | 596 | ||
569 | //机会池 - 统计 | 597 | //机会池 - 统计 |
@@ -50,9 +50,10 @@ type Approve struct { | @@ -50,9 +50,10 @@ type Approve struct { | ||
50 | 50 | ||
51 | //审核操作权限 | 51 | //审核操作权限 |
52 | type ApproveAccess struct { | 52 | type ApproveAccess struct { |
53 | - ProcessId int64 `json:"processId"` | ||
54 | - AllowApprove int `json:"allowApprove"` | ||
55 | - AllowReject int `json:"allowReject"` | 53 | + ProcessId int64 `json:"processId"` |
54 | + AllowApprove int `json:"allowApprove"` | ||
55 | + AllowReject int `json:"allowReject"` | ||
56 | + SelfCheckNeed int `json:"selfCheckNeed"` //是否需要提交自查 | ||
56 | } | 57 | } |
57 | 58 | ||
58 | //审核数据 审核通过 | 59 | //审核数据 审核通过 |
@@ -44,6 +44,14 @@ const ( | @@ -44,6 +44,14 @@ const ( | ||
44 | MyGraspAchievement //我把握的成果 | 44 | MyGraspAchievement //我把握的成果 |
45 | ) | 45 | ) |
46 | 46 | ||
47 | +//输入类型 | ||
48 | +const ( | ||
49 | + InputRadio = "radio" | ||
50 | + InputFiles = "files" | ||
51 | + InputCheckbox = "checkbox" | ||
52 | + InputText = "text" | ||
53 | +) | ||
54 | + | ||
47 | var MapStaticName map[int64]string | 55 | var MapStaticName map[int64]string |
48 | 56 | ||
49 | func init() { | 57 | func init() { |
@@ -178,7 +178,7 @@ type Cover struct { | @@ -178,7 +178,7 @@ type Cover struct { | ||
178 | Path string `json:"path" valid:"Required"` | 178 | Path string `json:"path" valid:"Required"` |
179 | H int `json:"-"` | 179 | H int `json:"-"` |
180 | W int `json:"-"` | 180 | W int `json:"-"` |
181 | - ImageId string `json:"imageId"` | 181 | + ImageId string `json:"-"` |
182 | } | 182 | } |
183 | 183 | ||
184 | /*公告列表 BulletinList */ | 184 | /*公告列表 BulletinList */ |
@@ -305,6 +305,14 @@ func init() { | @@ -305,6 +305,14 @@ func init() { | ||
305 | 305 | ||
306 | beego.GlobalControllerRouter["opp/controllers/v1:ChanceController"] = append(beego.GlobalControllerRouter["opp/controllers/v1:ChanceController"], | 306 | beego.GlobalControllerRouter["opp/controllers/v1:ChanceController"] = append(beego.GlobalControllerRouter["opp/controllers/v1:ChanceController"], |
307 | beego.ControllerComments{ | 307 | beego.ControllerComments{ |
308 | + Method: "SearchChance", | ||
309 | + Router: `/search`, | ||
310 | + AllowHTTPMethods: []string{"post"}, | ||
311 | + MethodParams: param.Make(), | ||
312 | + Params: nil}) | ||
313 | + | ||
314 | + beego.GlobalControllerRouter["opp/controllers/v1:ChanceController"] = append(beego.GlobalControllerRouter["opp/controllers/v1:ChanceController"], | ||
315 | + beego.ControllerComments{ | ||
308 | Method: "SiftingPool", | 316 | Method: "SiftingPool", |
309 | Router: `/siftingPool`, | 317 | Router: `/siftingPool`, |
310 | AllowHTTPMethods: []string{"post"}, | 318 | AllowHTTPMethods: []string{"post"}, |
@@ -56,6 +56,13 @@ func GetChancePool(uid, cid int64, o *models.ChancePoolOption, departmentId int, | @@ -56,6 +56,13 @@ func GetChancePool(uid, cid int64, o *models.ChancePoolOption, departmentId int, | ||
56 | } | 56 | } |
57 | log.Debug(fmt.Sprintf("user:%v check:%v is_amdin:%v", uid, check, user.Id == uid)) | 57 | log.Debug(fmt.Sprintf("user:%v check:%v is_amdin:%v", uid, check, user.Id == uid)) |
58 | option := models.NewChancePoolOption(chanceTypeId, dIds, o.Type, o.ReserveTypeId) | 58 | option := models.NewChancePoolOption(chanceTypeId, dIds, o.Type, o.ReserveTypeId) |
59 | + if len(o.KeyWord) > 0 { | ||
60 | + option.SetKeyWord(o.KeyWord) | ||
61 | + ids, _ := models.GetUserCompanyIdAllBy(map[string]interface{}{"CompanyId": cid, "NickName": o.KeyWord}) | ||
62 | + if len(ids) > 0 { | ||
63 | + option.SetInUsers(ids) | ||
64 | + } | ||
65 | + } | ||
59 | switch check { | 66 | switch check { |
60 | case OpportunityCheckLv1: | 67 | case OpportunityCheckLv1: |
61 | return models.GetChancePoolMyself(uid, cid, option, lastId, pageSize, v) | 68 | return models.GetChancePoolMyself(uid, cid, option, lastId, pageSize, v) |
@@ -538,7 +538,9 @@ func ConverTypeToReviewStaus(approveType int) (reviewStatus int) { | @@ -538,7 +538,9 @@ func ConverTypeToReviewStaus(approveType int) (reviewStatus int) { | ||
538 | func ChanceApproveProcess(header *protocol.RequestHeader, chance *models.Chance) (rsp *protocol.ChanceApproveProcessResponse, err error) { | 538 | func ChanceApproveProcess(header *protocol.RequestHeader, chance *models.Chance) (rsp *protocol.ChanceApproveProcessResponse, err error) { |
539 | var ( | 539 | var ( |
540 | processList []*models.AuditFlowProcess | 540 | processList []*models.AuditFlowProcess |
541 | + config *protocol.AuditConfig | ||
541 | ) | 542 | ) |
543 | + utils.JsonUnmarshal(chance.AuditTemplateConfig, &config) | ||
542 | if processList, err = models.GetAuditFlowProcessList(chance.Id); err != nil { | 544 | if processList, err = models.GetAuditFlowProcessList(chance.Id); err != nil { |
543 | log.Error(fmt.Sprintf("chance_id :%v 未查询到审核流信息", chance.Id), err) | 545 | log.Error(fmt.Sprintf("chance_id :%v 未查询到审核流信息", chance.Id), err) |
544 | if err == orm.ErrNoRows { | 546 | if err == orm.ErrNoRows { |
@@ -590,9 +592,10 @@ func ChanceApproveProcess(header *protocol.RequestHeader, chance *models.Chance) | @@ -590,9 +592,10 @@ func ChanceApproveProcess(header *protocol.RequestHeader, chance *models.Chance) | ||
590 | } | 592 | } |
591 | if process.ReviewStatus == protocol.ReviewStatusAuditging && process.Uid == header.UserId { | 593 | if process.ReviewStatus == protocol.ReviewStatusAuditging && process.Uid == header.UserId { |
592 | rsp.ApproveAccess = &protocol.ApproveAccess{ | 594 | rsp.ApproveAccess = &protocol.ApproveAccess{ |
593 | - AllowApprove: 1, | ||
594 | - AllowReject: 1, | ||
595 | - ProcessId: process.Id, | 595 | + AllowApprove: 1, |
596 | + AllowReject: 1, | ||
597 | + SelfCheckNeed: config.GetSelfCheckNeed(), | ||
598 | + ProcessId: process.Id, | ||
596 | } | 599 | } |
597 | } | 600 | } |
598 | } | 601 | } |
@@ -347,14 +347,20 @@ func Template(header *protocol.RequestHeader, request *protocol.TemplateRequest) | @@ -347,14 +347,20 @@ func Template(header *protocol.RequestHeader, request *protocol.TemplateRequest) | ||
347 | } | 347 | } |
348 | for j := range forms { | 348 | for j := range forms { |
349 | form := forms[j] | 349 | form := forms[j] |
350 | - template.FormList[j] = &protocol.Form{ | 350 | + formItem := &protocol.Form{ |
351 | Id: form.Id, | 351 | Id: form.Id, |
352 | Label: form.Label, | 352 | Label: form.Label, |
353 | Value: "", | 353 | Value: "", |
354 | InputType: form.InputType, | 354 | InputType: form.InputType, |
355 | SectionType: form.Section, | 355 | SectionType: form.Section, |
356 | Required: form.Required, | 356 | Required: form.Required, |
357 | + Data: make([]*protocol.FormDataItem, 0), | ||
358 | + ValueList: make([]*protocol.ValueListItem, 0), | ||
357 | } | 359 | } |
360 | + if len(form.ValueList) > 0 && form.InputType == protocol.InputRadio { | ||
361 | + utils.JsonUnmarshal(form.ValueList, &formItem.ValueList) | ||
362 | + } | ||
363 | + template.FormList[j] = formItem | ||
358 | } | 364 | } |
359 | rsp.Template = template | 365 | rsp.Template = template |
360 | return | 366 | return |
@@ -432,7 +438,7 @@ func ChanceSubmit(header *protocol.RequestHeader, request *protocol.ChanceSubmit | @@ -432,7 +438,7 @@ func ChanceSubmit(header *protocol.RequestHeader, request *protocol.ChanceSubmit | ||
432 | err = protocol.NewErrWithMessage(5302) | 438 | err = protocol.NewErrWithMessage(5302) |
433 | return | 439 | return |
434 | } | 440 | } |
435 | - auditConfig = &protocol.AuditConfig{NoApprover: template.NoApprover} | 441 | + auditConfig = &protocol.AuditConfig{NoApprover: template.NoApprover, SelfCheckNeed: template.SelfCheckNeed} |
436 | orm := orm.NewOrm() | 442 | orm := orm.NewOrm() |
437 | orm.Begin() | 443 | orm.Begin() |
438 | //2.检查模板是否有权限 | 444 | //2.检查模板是否有权限 |
@@ -1590,7 +1596,9 @@ func ChancePool(header *protocol.RequestHeader, request *protocol.ChancePoolRequ | @@ -1590,7 +1596,9 @@ func ChancePool(header *protocol.RequestHeader, request *protocol.ChancePoolRequ | ||
1590 | provider *protocol.BaseUserInfo | 1596 | provider *protocol.BaseUserInfo |
1591 | flag int | 1597 | flag int |
1592 | ) | 1598 | ) |
1593 | - if total, err = agg.GetChancePool(header.UserId, header.CompanyId, models.NewChancePoolOption(request.ChanceTypeId, []int{}, request.Type, request.ReserveTypeId), request.DepartmentId, request.IncludeSubDepartment, request.LastId, request.PageSize, &chanceItems); err != nil { | 1599 | + options := models.NewChancePoolOption(request.ChanceTypeId, []int{}, request.Type, request.ReserveTypeId) |
1600 | + options.SetKeyWord(request.KeyWord) | ||
1601 | + if total, err = agg.GetChancePool(header.UserId, header.CompanyId, options, request.DepartmentId, request.IncludeSubDepartment, request.LastId, request.PageSize, &chanceItems); err != nil { | ||
1594 | if err == orm.ErrNoRows { | 1602 | if err == orm.ErrNoRows { |
1595 | err = nil | 1603 | err = nil |
1596 | return | 1604 | return |
@@ -2018,9 +2026,8 @@ func ChanceDetail(header *protocol.RequestHeader, request *protocol.ChanceDetail | @@ -2018,9 +2026,8 @@ func ChanceDetail(header *protocol.RequestHeader, request *protocol.ChanceDetail | ||
2018 | UpdateTime: chance.UpdateAt.Unix() * 1000, | 2026 | UpdateTime: chance.UpdateAt.Unix() * 1000, |
2019 | } | 2027 | } |
2020 | jsonUnmarshal(chance.SourceContent, &item.FormList) | 2028 | jsonUnmarshal(chance.SourceContent, &item.FormList) |
2021 | - //jsonUnmarshal(chance.SelfChecks, &item.SelfChecks) | ||
2022 | item.SelfChecks = agg.GetChanceSelfChecks(chance) | 2029 | item.SelfChecks = agg.GetChanceSelfChecks(chance) |
2023 | - item.FormList = clearEmptyForm(item.FormList) | 2030 | + //item.FormList = clearEmptyForm(item.FormList) |
2024 | item.RelatedDepartmentId = chance.DepartmentId | 2031 | item.RelatedDepartmentId = chance.DepartmentId |
2025 | item.RelatedDepartmentInfo = agg.GetDepartment(int(chance.DepartmentId)) | 2032 | item.RelatedDepartmentInfo = agg.GetDepartment(int(chance.DepartmentId)) |
2026 | if chanceData, err = models.GetChanceDataByChanceId(chance.Id); err == nil { | 2033 | if chanceData, err = models.GetChanceDataByChanceId(chance.Id); err == nil { |
-
请 注册 或 登录 后发表评论