diff --git a/src/production/case.go b/src/production/case.go index dd57e87..3868b13 100644 --- a/src/production/case.go +++ b/src/production/case.go @@ -2,6 +2,8 @@ package production import ( "shylinux.com/x/ice" + "shylinux.com/x/icebergs/base/ctx" + "shylinux.com/x/icebergs/base/web" kit "shylinux.com/x/toolkits" "shylinux.com/x/operation/src/production/model" @@ -10,15 +12,16 @@ import ( type Case struct { Table order string `data:"5"` - fields string `data:"title,content,status,begin_time,end_time,process_time,finish_time,task_uid,plan_uid,user_uid"` - create string `name:"create task_uid* title* content* begin_time:select@date end_time:select@date" role:"worker"` - modify string `name:"modify title* content* begin_time*:select@date end_time*:select@date" role:"worker"` + fields string `data:"title,content,status,space,index,begin_time,end_time,process_time,finish_time,task_uid,plan_uid,user_uid"` + create string `name:"create task_uid* title* content* space index begin_time:select@date end_time:select@date" role:"worker"` + modify string `name:"modify title* content* space index begin_time*:select@date end_time*:select@date" role:"worker"` + finish string `name:"finish" role:"worker"` } func (s Case) Create(m *ice.Message, arg ...string) { s.ValueCreate(m, kit.ArgDef(arg, kit.Simple(model.BEGIN_TIME, m.Time(), model.END_TIME, m.Time("72h"))...)...) - s.taskCount(m) s.SendMessage(s.GetCommandUID(m), "", "") + s.taskCount(m) } func (s Case) Remove(m *ice.Message, arg ...string) { s.ValueRemove(m, arg...) @@ -27,20 +30,20 @@ func (s Case) Remove(m *ice.Message, arg ...string) { func (s Case) List(m *ice.Message, arg ...string) { user_uid := m.Option(model.USER_UID) s.Orders(m, model.STATUS, s.Desc(model.CREATED_AT)) - s.ValueList(m, arg).Table(func(value ice.Maps) { s.PushTaskButton(m, value, user_uid) }).Display("") - m.RenameAppend(model.STATUS, model.CASE_STATUS) + s.ValueList(m, arg) s.SelectJoinPlan(m) s.StatusCount(m, arg...) + m.Table(func(value ice.Maps) { s.PushTaskButton(m, value, user_uid, s.Preview) }).Display("") + m.RenameAppend(model.STATUS, model.CASE_STATUS) +} +func (s Case) Preview(m *ice.Message, arg ...string) { + m.ProcessOpen(web.S(m.Option(web.SPACE)) + web.C(m.Option(ctx.INDEX))) } func (s Case) Process(m *ice.Message, arg ...string) { - s.changeStatus(m, TaskCreate, TaskProcess) + s.changeStatus(m, IssueCreate, IssueProcess) } func (s Case) Finish(m *ice.Message, arg ...string) { - s.changeStatus(m, TaskProcess, TaskFinish) + s.changeStatus(m, IssueProcess, IssueFinish) } func init() { ice.TeamCtxCmd(Case{}) } - -func (s Case) changeStatus(m *ice.Message, from, to TaskStatus) { - s.ChangeStatus(m, int(from), int(to), m.ActionKey()+"_time", m.Time()) -} diff --git a/src/production/case.js b/src/production/case.js index 15e0213..62a9d6c 100644 --- a/src/production/case.js +++ b/src/production/case.js @@ -1,7 +1,7 @@ Volcanos(chat.ONIMPORT, { _init: function(can, msg) { can.onimport.myView(can, msg, function(value) { return [ - {view: html.TITLE, list: [value.title, can.onimport.textView(can, value)]}, + {view: html.TITLE, list: [value.title, can.onimport.textView(can, value, "status")]}, {view: html.STATUS, list: [can.onimport.beginTime(can, value), can.onimport.unitView(can, value, "plan_title")]}, {view: html.OUTPUT, list: [value.content]}, can.onimport.titleAction(can, value), ] }) diff --git a/src/production/common.go b/src/production/common.go index 2c6ffd0..8b9e617 100644 --- a/src/production/common.go +++ b/src/production/common.go @@ -5,6 +5,8 @@ import ( "shylinux.com/x/ice" "shylinux.com/x/icebergs/base/mdb" + "shylinux.com/x/icebergs/base/nfs" + "shylinux.com/x/icebergs/base/web" kit "shylinux.com/x/toolkits" "shylinux.com/x/operation/src/operation" @@ -13,16 +15,22 @@ import ( type Table struct { operation.Table - remove string `name:"remove" role:"worker"` - reject string `name:"reject" role:"leader"` - approve string `name:"approve" role:"leader"` - process string `name:"process" role:"worker"` - submit string `name:"submit link" role:"worker"` - reback string `name:"reback" role:"leader"` - finish string `name:"finish" role:"leader"` - payfor string `name:"payfor price* title* content"` - discuss string `name:"discuss type* title* content date* time* link*"` - list string `name:"list story_uid uid auto" role:"void"` + remove string `name:"remove" role:"worker"` + reject string `name:"reject" role:"leader"` + approve string `name:"approve" role:"leader"` + process string `name:"process" role:"worker"` + submit string `name:"submit link" role:"worker"` + finish string `name:"finish" role:"leader"` + reback string `name:"reback" role:"leader"` + cancel string `name:"cancel" role:"leader"` + payfor string `name:"payfor price* title* content" role:"leader"` + discuss string `name:"discuss meet_type* title* content date* time* link*" role:"leader"` + list string `name:"list story_uid uid auto" role:"void"` + designList string `name:"designList" role:"worker"` + taskList string `name:"taskList" role:"worker"` + caseList string `name:"caseList" role:"worker"` + meetList string `name:"meetList" role:"worker"` + dealList string `name:"dealList" role:"worker"` } func (s Table) Inputs(m *ice.Message, arg ...string) { @@ -32,33 +40,33 @@ func (s Table) Inputs(m *ice.Message, arg ...string) { case model.STORY_TYPE: s.InputsList(m, StoryTypeList, arg...) case model.PLAN_UID: - s.InputsUID(m, Plan{}, arg...) + s.InputsUID(m, arg, Plan{}, m.OptionSimple(model.STORY_UID)...) case model.ISSUE_UID: - s.InputsUID(m, Issue{}, arg...) + s.InputsUID(m, arg, Issue{}, m.OptionSimple(model.STORY_UID)...) case model.ISSUE_TYPE: s.InputsList(m, IssueTypeList, arg...) + case model.TASK_UID: + s.InputsUID(m, arg, Task{}, m.OptionSimple(model.STORY_UID)...) case model.MEET_TYPE: s.InputsList(m, MeetTypeList, arg...) - case model.TASK_UID: - s.InputsUID(m, Task{}, arg...) - case model.LEVEL: - s.InputsList(m, LevelList, arg...) case model.FROM_USER_UID, model.TO_USER_UID: m.Cmdy("member", m.Option(model.STORY_UID)).Cut(model.USER_UID, model.USER_NAME, model.USER_AVATAR) m.RenameAppend(model.USER_UID, arg[0], model.NAME, model.USER_NAME, model.USER_AVATAR, mdb.ICONS) m.DisplayInputKeyNameIconTitle() + case model.LEVEL: + s.InputsList(m, LevelList, arg...) + case nfs.PATH: + m.Cmdy(web.SPACE, m.Option(web.SPACE), nfs.DIR, nfs.SRC, nfs.PATH) default: switch m.Option("action") { case "discuss": switch arg[0] { - case "type": - m.Push(arg[0], "需求沟通", "需求评审", "项目验收") case "date": - for i := 1; i < 10; i++ { + for i := 1; i < 5; i++ { m.Push(arg[0], strings.Split(m.Time(kit.Format("%dh", i*24)), " ")[0]) } case "time": - for i := 18; i < 48; i++ { + for i := 38; i < 48; i++ { m.Push(arg[0], kit.Format("%02d:%s", i/2, kit.Select("30", "00", i%2 == 0))) } } @@ -78,12 +86,10 @@ func (s Table) RewriteAppend(m *ice.Message, arg ...string) *ice.Message { value = PlanStatus(kit.Int(value)).String() case model.ISSUE_TYPE: value = IssueType(kit.Int(value)).String() + case model.ISSUE_STATUS, model.DESIGN_STATUS, model.TASK_STATUS, model.CASE_STATUS, model.STATUS: + value = IssueStatus(kit.Int(value)).String() case model.MEET_TYPE: value = MeetType(kit.Int(value)).String() - case model.ISSUE_STATUS, model.DESIGN_STATUS, model.STATUS: - value = IssueStatus(kit.Int(value)).String() - case model.TASK_STATUS, model.CASE_STATUS: - value = TaskStatus(kit.Int(value)).String() case model.LEVEL: value = Level(kit.Int(value)).String() } @@ -93,12 +99,19 @@ func (s Table) RewriteAppend(m *ice.Message, arg ...string) *ice.Message { } func (s Table) PushIssueButton(m *ice.Message, value ice.Maps, user_uid string, arg ...ice.Any) { button := []ice.Any{} - isLeader, isWorker := s.IsLeader(m), s.IsWorker(m) + defer func() { m.PushButton(button...) }() + if PlanStatus(kit.Int(value[model.PLAN_STATUS])) == PlanFinish { + kit.If(m.FieldsIsDetail(), func() { s.DoneMessage(m) }) + return + } + isCreator, isLeader, isWorker := s.IsCreator(m), s.IsLeader(m), s.IsWorker(m) switch IssueStatus(kit.Int(value[model.STATUS])) { case IssueCreate: if isLeader { - button = append(button, s.Discuss) - button = append(button, s.Approve, s.Reject) + button = append(button, s.Discuss, s.Payfor) + } + if isCreator { + button = append(button, s.Approve, s.Reject, s.Cancel) } if user_uid == value[model.USER_UID] { button = append(button, s.Modify, s.Remove) @@ -108,59 +121,63 @@ func (s Table) PushIssueButton(m *ice.Message, value ice.Maps, user_uid string, button = append(button, s.Process) } case IssueProcess: + if isLeader && kit.Int(value[model.PRICE]) > 0 { + button = append(button, s.Discuss, s.Payfor) + } if user_uid == value[model.USER_UID] { button = append(button, s.Submit) } - if isLeader && kit.Int(value[model.PRICE]) > 0 { - button = append(button, s.Payfor) - } case IssueSubmit: if isLeader { - button = append(button, s.Discuss) - button = append(button, s.Reback, s.Finish) + button = append(button, s.Discuss, s.Payfor) + } + if isCreator { + button = append(button, s.Finish, s.Reback, s.Cancel) + } + case IssueFinish: + if isLeader && kit.Int(value[model.PRICE]) > 0 { + button = append(button, s.Discuss, s.Payfor) + } + if isWorker { + button = append(button, arg...) + } + kit.If(m.FieldsIsDetail(), func() { s.DoneMessage(m) }) + } +} +func (s Table) PushTaskButton(m *ice.Message, value ice.Maps, user_uid string, arg ...ice.Any) { + button := []ice.Any{} + isWorker := s.IsWorker(m) + switch IssueStatus(kit.Int(value[model.STATUS])) { + case IssueCreate: + if user_uid == value[model.USER_UID] { + button = append(button, s.Process, s.Modify, s.Remove) + } + case IssueProcess: + if isWorker { + button = append(button, arg...) + } + if user_uid == value[model.USER_UID] { + button = append(button, s.Finish) } case IssueFinish: if isWorker { button = append(button, arg...) } - if isLeader && kit.Int(value[model.PRICE]) > 0 { - button = append(button, s.Payfor) - button = append(button, s.Discuss) - } - kit.If(len(arg) == 2 && value[model.PRICE] == "0", func() { s.DoneMessage(m) }) - } - m.PushButton(button...) -} -func (s Table) PushTaskButton(m *ice.Message, value ice.Maps, user_uid string, arg ...ice.Any) { - button := []ice.Any{} - isLeader, isWorker := s.IsLeader(m), s.IsWorker(m) - switch TaskStatus(kit.Int(value[model.STATUS])) { - case TaskCreate: - if user_uid == value[model.USER_UID] { - button = append(button, s.Process, s.Modify, s.Remove) - } - if isLeader { - } - case TaskProcess: - if user_uid == value[model.USER_UID] { - button = append(button, s.Finish) - } - if isWorker { - button = append(button, arg...) - } - if isLeader && kit.Int(value[model.PRICE]) > 0 { - button = append(button, s.Payfor) - } - case TaskFinish: - if isLeader && kit.Int(value[model.PRICE]) > 0 { - button = append(button, s.Payfor) - } - kit.If(len(arg) == 2, func() { s.DoneMessage(m) }) + kit.If(m.FieldsIsDetail(), func() { s.DoneMessage(m) }) } m.PushButton(button...) } func (s Table) SelectJoinPlan(m *ice.Message, arg ...string) { - s.SelectJoin(m, Plan{}, model.TITLE) + s.SelectJoin(m, Plan{}, model.TITLE, model.STATUS) +} +func (s Table) StatusPrice(m *ice.Message, arg ...string) { + if m.Length() > 0 && len(arg) < 2 { + msg := m.Spawn() + s.Fields(msg, "sum(price) AS price") + s.Select(msg, model.STORY_UID, arg[0]).Table(func(value ice.Maps) { + m.Echo(model.PRICE).Echo(": ").Echo(kit.Format(kit.Int(value[model.PRICE]) / 100)).Echo(" 元") + }) + } } func (s Table) StatusCount(m *ice.Message, arg ...string) { if m.Length() > 0 && len(arg) < 2 { @@ -170,10 +187,8 @@ func (s Table) StatusCount(m *ice.Message, arg ...string) { switch status := kit.Int(value[model.STATUS]); m.CommandKey() { case "plan": m.Echo(PlanStatus(status).String()).Echo(": ") - case "issue", "design": + case "issue", "design", "task", "case": m.Echo(IssueStatus(status).String()).Echo(": ") - case "task", "case": - m.Echo(TaskStatus(status).String()).Echo(": ") } m.Echo(value[model.COUNT]).Echo("\n") }) @@ -191,41 +206,88 @@ func (s Table) Process(m *ice.Message, arg ...string) { func (s Table) Submit(m *ice.Message, arg ...string) { s.ChangeStatus(m, int(IssueProcess), int(IssueSubmit), arg...) } -func (s Table) Reback(m *ice.Message, arg ...string) { - s.ChangeStatus(m, int(IssueSubmit), int(IssueProcess)) -} func (s Table) Finish(m *ice.Message, arg ...string) { s.changeStatus(m, IssueSubmit, IssueFinish) } -func (s Table) Payfor(m *ice.Message, arg ...string) { +func (s Table) Reback(m *ice.Message, arg ...string) { + s.ChangeStatus(m, int(IssueSubmit), int(IssueProcess)) } -func (s Table) Discuss(m *ice.Message, arg ...string) { - m.Cmd(meet{}, s.Create, arg) +func (s Table) Cancel(m *ice.Message, arg ...string) { + s.changeStatus(m, IssueSubmit, IssueCancel) +} + +func (s Table) Payfor(m *ice.Message, arg ...string) { + msg := s.Select(m, model.UID, m.Option(model.UID)) + s.issueOtherCreate(m, deal{}, kit.Simple(model.FROM_USER_UID, m.Option(model.USER_UID), model.TO_USER_UID, msg.Append(model.USER_UID), arg)...) } func (s Issue) Payfor(m *ice.Message, arg ...string) { msg := s.Select(m, model.UID, m.Option(model.UID)) - m.Cmdy(deal{}, s.Create, model.FROM_USER_UID, m.Option(model.USER_UID), model.TO_USER_UID, msg.Append(model.USER_UID), - model.PLAN_UID, msg.Append(model.UID), model.ISSUE_UID, m.Option(model.UID), arg) + s.commonOtherCreate(m, deal{}, kit.Simple(model.FROM_USER_UID, m.Option(model.USER_UID), model.TO_USER_UID, msg.Append(model.USER_UID), arg)...) +} +func (s Table) Discuss(m *ice.Message, arg ...string) { + msg := s.Select(m, model.UID, m.Option(model.UID)) + s.issueOtherCreate(m, meet{}, kit.Simple(model.FROM_USER_UID, m.Option(model.USER_UID), model.TO_USER_UID, msg.Append(model.USER_UID), arg)...) } func (s Issue) Discuss(m *ice.Message, arg ...string) { - m.Cmd(meet{}, s.Create, model.ISSUE_UID, m.Option(model.UID), arg, m.OptionSimple(model.PLAN_UID)) + msg := s.Select(m, model.UID, m.Option(model.UID)) + s.commonOtherCreate(m, meet{}, kit.Simple(model.FROM_USER_UID, m.Option(model.USER_UID), model.TO_USER_UID, msg.Append(model.USER_UID), arg)...) +} +func (s Table) issueOtherCreate(m *ice.Message, target ice.Any, arg ...string) { + s.OtherCreate(m, target, kit.Simple(m.OptionSimple(model.ISSUE_UID), arg)...) +} +func (s Table) commonOtherCreate(m *ice.Message, target ice.Any, arg ...string) { + s.OtherCreate(m, target, kit.Simple(m.CommandKey()+"_uid", m.Option(model.UID), arg)...) } func (s Table) OtherCreate(m *ice.Message, target ice.Any, arg ...string) { kit.If(m.CommandKey() != "plan", func() { arg = append(arg, m.OptionSimple(model.PLAN_UID)...) }) - m.Cmdy(target, s.Create, m.CommandKey()+"_uid", m.Option(model.UID), arg) + m.Cmdy(target, s.Create, arg) kit.If(!m.IsErr(), func() { m.ProcessField(target, []string{m.Option(model.STORY_UID), m.Result()}) }) } func (s Table) OtherList(m *ice.Message, target ice.Any, arg ...string) *ice.Message { - m.Cmdy(target, s.Select, m.OptionSimple(model.STORY_UID), m.CommandKey()+"_uid", m.Option(model.UID)) - m.Option("_command", ice.GetTypeKey(target)) - m.Option("place_uid", m.Option(model.STORY_UID)) + m.Cmdy(target, s.Select, m.OptionSimple(model.STORY_UID), m.CommandKey()+"_uid", m.Option(model.UID)).Option("_command", ice.GetTypeKey(target)) + if s.IsLeader(m) { + kit.If(m.ActionKey() == "meetList", func() { m.RenameAppend(model.TO_USER_UID, model.USER_UID) }) + kit.If(m.ActionKey() == "dealList", func() { m.RenameAppend(model.TO_USER_UID, model.USER_UID) }) + } else { + kit.If(m.ActionKey() == "meetList", func() { m.RenameAppend(model.FROM_USER_UID, model.USER_UID) }) + kit.If(m.ActionKey() == "dealList", func() { m.RenameAppend(model.FROM_USER_UID, model.USER_UID) }) + } s.SelectJoinUser(m) return m } +func (s Table) DesignList(m *ice.Message, arg ...string) { + s.OtherList(m, Design{}).Display("design.js") +} +func (s Table) TaskList(m *ice.Message, arg ...string) { + s.OtherList(m, Task{}).Display("task.js") +} +func (s Table) CaseList(m *ice.Message, arg ...string) { + s.OtherList(m, Case{}).Display("case.js") +} +func (s Table) MeetList(m *ice.Message, arg ...string) { + s.OtherList(m, meet{}).Display("meet.js") +} +func (s Table) DealList(m *ice.Message, arg ...string) { + s.OtherList(m, deal{}).Display("deal.js") +} + +func (s Table) finishCheck(m *ice.Message, target ice.Any, name string, arg ...string) bool { + count := m.Cmd(target, s.Select, m.CommandKey()+"_uid = ? AND status != ?", m.Option(model.UID), IssueFinish).Length() + if m.WarnNotValid(count > 0, kit.Format("还有 %v 个未完成的%s", count, name)) { + return true + } + return false +} func (s Table) changeStatus(m *ice.Message, from, to IssueStatus) { s.ChangeStatus(m, int(from), int(to), m.ActionKey()+"_time", m.Time()) } func (s Table) ChangeStatus(m *ice.Message, from, to int, arg ...string) { + if !s.IsLeader(m) { + msg := s.Select(m.Spawn(), m.OptionSimple(model.STORY_UID, model.UID)...) + if m.WarnNotRight(msg.Append(model.USER_UID) != m.Option(model.USER_UID)) { + return + } + } s.Table.ChangeStatus(m, m.Option(model.STORY_UID), m.Option(model.UID), from, to, arg...) s.DashboardUpdate(m) } @@ -244,23 +306,3 @@ func (s Table) taskCount(m *ice.Message) Table { return s.addCount(m, Task{}) } type Tables struct{ Table } func (s Tables) BeforeMigrate(m *ice.Message, arg ...string) {} - -type Level int - -const ( - Level1 Level = iota - Level2 - Level3 - Level4 - Level5 -) - -var LevelList = map[Level]string{ - Level1: "level-1", - Level2: "level-2", - Level3: "level-3", - Level4: "level-4", - Level5: "level-5", -} - -func (s Level) String() string { return LevelList[s] } diff --git a/src/production/deal.go b/src/production/deal.go index a2fc2a0..669edba 100644 --- a/src/production/deal.go +++ b/src/production/deal.go @@ -3,19 +3,40 @@ package production import ( "shylinux.com/x/ice" "shylinux.com/x/operation/src/production/model" + kit "shylinux.com/x/toolkits" ) type deal struct { Table order string `data:"7"` fields string `data:"from_user_uid,to_user_uid,price,title,content"` - create string `name:"create from_user_uid* to_user_uid* price* title* content" role:"leader"` + create string `name:"create issue_uid* from_user_uid* to_user_uid* price* title* content" role:"leader"` } +func (s deal) Create(m *ice.Message, arg ...string) { + s.Table.Create(m, arg...) + s.SendMessage(s.GetCommandUID(m), "", m.Option(model.TO_USER_UID)) +} func (s deal) List(m *ice.Message, arg ...string) { - s.ValueList(m, arg).Display("") - m.RenameAppend(model.TO_USER_UID, model.USER_UID) - s.SelectJoinUser(m) + if s.IsLeader(m) { + s.ValueList(m, arg).PushAction() + s.StatusPrice(m, arg...) + } else { + if len(arg) == 1 { + s.Select(m, model.STORY_UID, arg[0], model.TO_USER_UID, m.Option(model.USER_UID)).PushAction().Action() + kit.If(m.Length() == 0, func() { m.Echo("请等待管理员支付工钱") }) + } else { + s.SelectDetail(m, model.STORY_UID, arg[0], model.TO_USER_UID, m.Option(model.USER_UID), model.UID, arg[1]).PushAction().Action() + s.DoneMessage(m) + } + } + if s.IsLeader(m) { + m.RenameAppend(model.TO_USER_UID, model.USER_UID) + } else { + m.RenameAppend(model.FROM_USER_UID, model.USER_UID) + } + // s.SelectJoinUser(m). + m.Display("") } func init() { ice.TeamCtxCmd(deal{}) } diff --git a/src/production/design.go b/src/production/design.go index 0301b38..d644a12 100644 --- a/src/production/design.go +++ b/src/production/design.go @@ -10,25 +10,30 @@ import ( type Design struct { Table order string `data:"3"` - fields string `data:"title,content,status,price,begin_time,end_time,process_time,finish_time,issue_uid,plan_uid,user_uid"` + fields string `data:"title,content,status,price,link,begin_time,end_time,process_time,finish_time,issue_uid,plan_uid,user_uid"` create string `name:"create issue_uid* title* content* price=1000 begin_time:select@date end_time:select@date" role:"worker"` modify string `name:"modify title* content* price* begin_time*:select@date end_time*:select@date" role:"worker"` } func (s Design) Create(m *ice.Message, arg ...string) { s.ValueCreate(m, kit.ArgDef(arg, kit.Simple(model.PRICE, "1000", model.BEGIN_TIME, m.Time(), model.END_TIME, m.Time("72h"))...)...) - s.issueCount(m) s.SendMessage(s.GetCommandUID(m), "", "") + s.issueCount(m) } func (s Design) Remove(m *ice.Message, arg ...string) { s.ValueRemove(m, arg...) s.issueCount(m) } +func (s Design) Cancel(m *ice.Message, arg ...string) { + s.ChangeStatus(m, int(IssueCreate), int(IssueCancel)) + s.issueCount(m) +} func (s Design) List(m *ice.Message, arg ...string) { user_uid := m.Option(model.USER_UID) s.Orders(m, model.STATUS, s.Desc(model.CREATED_AT)) - s.ValueList(m, arg).Table(func(value ice.Maps) { s.PushIssueButton(m, value, user_uid) }).Display("") + s.ValueList(m, arg) s.SelectJoinPlan(m) s.StatusCount(m, arg...) + m.Table(func(value ice.Maps) { s.PushIssueButton(m, value, user_uid) }).Display("") } func init() { ice.TeamCtxCmd(Design{}) } diff --git a/src/production/design.js b/src/production/design.js index d725ad2..715b6b2 100644 --- a/src/production/design.js +++ b/src/production/design.js @@ -1,9 +1,9 @@ Volcanos(chat.ONIMPORT, { _init: function(can, msg) { can.onimport.myView(can, msg, function(value) { return [ - {view: html.TITLE, list: [value.title, can.onimport.textView(can, value)]}, + {view: html.TITLE, list: [value.title, can.onimport.textView(can, value, "status")]}, {view: html.STATUS, list: [can.onimport.beginTime(can, value), can.onimport.unitView(can, value, "plan_title")]}, - value.price > 0 && {view: html.OUTPUT, list: [can.onimport.unitView(can, value, "price", "元")]}, + // value.price > 0 && {view: html.OUTPUT, list: [can.onimport.unitView(can, value, "price", "元")]}, {view: html.OUTPUT, list: [value.content]}, can.onimport.titleAction(can, value), ] }) }, diff --git a/src/production/issue.go b/src/production/issue.go index c843594..ee20aff 100644 --- a/src/production/issue.go +++ b/src/production/issue.go @@ -9,31 +9,30 @@ import ( type Issue struct { Table - order string `data:"2"` - fields string `data:"title,content,level,issue_type,status,price,link,design_count,task_count,begin_time,end_time,process_time,finish_time,plan_uid,user_uid"` - create string `name:"create plan_uid* title* content* issue_type:select level:select price=1000 begin_time:select@date end_time:select@date" role:"worker"` - modify string `name:"modify title* content* issue_type*:select level*:select price* begin_time:select@date end_time:select@date" role:"worker"` + order string `data:"2"` + fields string `data:"title,content,level,issue_type,status,price,link,design_count,task_count,begin_time,end_time,process_time,finish_time,plan_uid,user_uid"` + create string `name:"create plan_uid* title* content* issue_type:select level:select price=1000 begin_time:select@date end_time:select@date" role:"worker"` + modify string `name:"modify title* content* price* begin_time:select@date end_time:select@date" role:"worker"` + // modify string `name:"modify title* content* issue_type*:select level*:select price* begin_time:select@date end_time:select@date" role:"worker"` designCreate string `name:"designCreate title* content* price=1000 begin_time:select@date end_time:select@date" role:"worker"` taskCreate string `name:"taskCreate title* content* price=1000 begin_time:select@date end_time:select@date" role:"worker"` - designList string `name:"designList" role:"worker"` - taskList string `name:"taskList" role:"worker"` - meetList string `name:"meetList" role:"worker"` - dealList string `name:"dealList" role:"worker"` applyCreate string `name:"applyCreate" role:"void"` } func (s Issue) Create(m *ice.Message, arg ...string) { - s.ValueCreate(m, kit.ArgDef(arg, kit.Simple( - model.ISSUE_TYPE, IssueFeature, model.LEVEL, Level3, - model.PRICE, "1000", model.BEGIN_TIME, m.Time(), model.END_TIME, m.Time("72h"), - )...)...) - s.planCount(m).DashboardUpdate(m) + s.ValueCreate(m, kit.ArgDef(arg, kit.Simple(model.ISSUE_TYPE, IssueFeature, model.LEVEL, Level3, + model.PRICE, "1000", model.BEGIN_TIME, m.Time(), model.END_TIME, m.Time("72h"))...)...) s.SendMessage(s.GetCommandUID(m), "", "") + s.planCount(m).DashboardUpdate(m) } func (s Issue) Remove(m *ice.Message, arg ...string) { s.ValueRemove(m, arg...) s.planCount(m).DashboardUpdate(m) } +func (s Issue) Cancel(m *ice.Message, arg ...string) { + s.ChangeStatus(m, int(IssueSubmit), int(IssueCancel)) + s.planCount(m).DashboardUpdate(m) +} func (s Issue) List(m *ice.Message, arg ...string) { if !s.IsWorker(m) { s.ApplyCheck(m, arg...) @@ -41,35 +40,25 @@ func (s Issue) List(m *ice.Message, arg ...string) { } user_uid := m.Option(model.USER_UID) s.Orders(m, model.STATUS, model.DESIGN_COUNT, model.TASK_COUNT, s.Desc(model.CREATED_AT)) - s.ValueList(m, arg).Table(func(value ice.Maps) { - s.PushIssueButton(m, value, user_uid, s.DesignCreate, s.TaskCreate) - }).Display("") + s.ValueList(m, arg) s.SelectJoinPlan(m) s.StatusCount(m, arg...) + m.Table(func(value ice.Maps) { + s.PushIssueButton(m, value, user_uid, s.DesignCreate, s.TaskCreate) + }).Display("").Option("otherList", "designList,taskList,caseList,meetList,dealList") + kit.If(len(arg) == 1, func() { m.Sort("plan_status,status,design_count,task_count,created_at") }) } func (s Issue) Finish(m *ice.Message, arg ...string) { - count := m.Cmd(Design{}, s.Select, "issue_uid = ? AND status != ?", m.Option(model.UID), IssueFinish).Length() - if m.WarnNotValid(count > 0, kit.Format("还有 %v 个未完成的设计", count)) { + if s.finishCheck(m, Design{}, "设计") { return } - count = m.Cmd(Task{}, s.Select, "issue_uid = ? AND status != ?", m.Option(model.UID), TaskFinish).Length() - if m.WarnNotValid(count > 0, kit.Format("还有 %v 个未完成的任务", count)) { + if s.finishCheck(m, Task{}, "任务") { return } s.changeStatus(m, IssueSubmit, IssueFinish) } -func (s Issue) DesignCreate(m *ice.Message, arg ...string) { s.OtherCreate(m, Design{}, arg...) } -func (s Issue) DesignList(m *ice.Message, arg ...string) { - s.OtherList(m, Design{}).Display("design.js") -} -func (s Issue) TaskCreate(m *ice.Message, arg ...string) { s.OtherCreate(m, Task{}, arg...) } -func (s Issue) TaskList(m *ice.Message, arg ...string) { s.OtherList(m, Task{}).Display("task.js") } -func (s Issue) MeetList(m *ice.Message, arg ...string) { s.OtherList(m, meet{}).Display("meet.js") } -func (s Issue) DealList(m *ice.Message, arg ...string) { - s.OtherList(m, deal{}).Display("deal.js") - m.RenameAppend(model.TO_USER_UID, model.USER_UID) - s.SelectJoinUser(m) -} +func (s Issue) DesignCreate(m *ice.Message, arg ...string) { s.commonOtherCreate(m, Design{}, arg...) } +func (s Issue) TaskCreate(m *ice.Message, arg ...string) { s.commonOtherCreate(m, Task{}, arg...) } func init() { ice.TeamCtxCmd(Issue{}) } @@ -87,6 +76,26 @@ var IssueTypeList = map[IssueType]string{ func (s IssueType) String() string { return IssueTypeList[s] } +type Level int + +const ( + Level1 Level = iota + Level2 + Level3 + Level4 + Level5 +) + +var LevelList = map[Level]string{ + Level1: "level-1", + Level2: "level-2", + Level3: "level-3", + Level4: "level-4", + Level5: "level-5", +} + +func (s Level) String() string { return LevelList[s] } + type IssueStatus int const ( @@ -97,6 +106,7 @@ const ( IssueSubmit IssueReback IssueFinish + IssueCancel ) var IssueStatusList = map[IssueStatus]string{ @@ -107,6 +117,7 @@ var IssueStatusList = map[IssueStatus]string{ IssueSubmit: "submit", IssueReback: "reback", IssueFinish: "finish", + IssueCancel: "cancel", } func (s IssueStatus) String() string { return IssueStatusList[s] } diff --git a/src/production/issue.js b/src/production/issue.js index 1e9558d..bbd085d 100644 --- a/src/production/issue.js +++ b/src/production/issue.js @@ -4,7 +4,7 @@ Volcanos(chat.ONIMPORT, { {view: html.TITLE, list: [value.title, value.issue_type != "feature" && can.onimport.textView(can, value, "issue_type"), value.level != "level-3" && can.onimport.textView(can, value, "level"), - can.onimport.textView(can, value), + can.onimport.textView(can, value, "status"), ]}, {view: html.STATUS, list: [ (value.process_time||value.begin_time).split(" ")[0]+" ~ "+(value.finish_time||value.end_time).split(" ")[0], @@ -12,9 +12,8 @@ Volcanos(chat.ONIMPORT, { can.onimport.unitView(can, value, "task_count", "个"), can.onimport.unitView(can, value, "plan_title"), ]}, - value.price > 0 && {view: html.OUTPUT, list: [can.onimport.unitView(can, value, "price", "元")]}, + // value.price > 0 && {view: html.OUTPUT, list: [can.onimport.unitView(can, value, "price", "元")]}, {view: html.OUTPUT, list: [value.content]}, can.onimport.titleAction(can, value), ] }) - can.onimport.otherList && can.onimport.otherList(can, msg, ["dealList", "meetList", "designList", "taskList"]) }, }) \ No newline at end of file diff --git a/src/production/meet.go b/src/production/meet.go index e417ab0..a3ab91b 100644 --- a/src/production/meet.go +++ b/src/production/meet.go @@ -5,24 +5,34 @@ import ( "shylinux.com/x/ice" kit "shylinux.com/x/toolkits" + + "shylinux.com/x/operation/src/production/model" ) type meet struct { Table order string `data:"6"` - fields string `data:"title,content,link,meet_type,begin_time,end_time,issue_uid,plan_uid,company_uid,user_uid"` - create string `name:"create issue_uid* meet_type* title* content* date time link*" role:"leader"` + fields string `data:"from_user_uid,to_user_uid,title,content,link,meet_type,begin_time,end_time,issue_uid,plan_uid,company_uid"` + create string `name:"create issue_uid* from_user_uid* to_user_uid* meet_type* title* content* date time link*" role:"leader"` remove string `name:"remove" role:"leader"` } func (s meet) Create(m *ice.Message, arg ...string) { - t := kit.Time(m.Option("date") + " " + m.Option("time") + ":00") - m.Option("begin_time", time.Unix(t, 0).Format(ice.MOD_TIME)) - m.Option("end_time", m.Option("date")+" "+m.Option("time")+":00") - s.ValueCreate(m, m.OptionSimple("issue_uid,meet_type,title,content,link,begin_time,end_time")...) + t := time.Unix(kit.Time(m.Option("date")+" "+m.Option("time")+":00")/int64(time.Second), 0) + m.Options(model.BEGIN_TIME, t.Format(ice.MOD_TIME), model.END_TIME, t.Add(30*time.Minute).Format(ice.MOD_TIME)) + s.ValueCreate(m, m.OptionSimple("issue_uid,from_user_uid,to_user_uid,meet_type,title,content,link,begin_time,end_time,plan_uid")...) + s.SendMessage(s.GetCommandUID(m), m.Option(model.FROM_USER_UID), m.Option(model.TO_USER_UID)) + s.SendMessage(s.GetCommandUID(m), m.Option(model.TO_USER_UID), m.Option(model.FROM_USER_UID)) } func (s meet) List(m *ice.Message, arg ...string) { s.ValueList(m, arg).Display("") + // s.SelectJoinUser(m.RenameAppend(model.TO_USER_UID, model.USER_UID)).Display("") + if s.IsLeader(m) { + m.RenameAppend(model.TO_USER_UID, model.USER_UID) + } else { + m.RenameAppend(model.FROM_USER_UID, model.USER_UID) + } + kit.If(!s.IsLeader(m) && m.Length() == 0, func() { m.SetResult().Echo("请等待管理员创建会议") }) } func init() { ice.TeamCtxCmd(meet{}) } diff --git a/src/production/meet.js b/src/production/meet.js index 308755b..68b1b5b 100644 --- a/src/production/meet.js +++ b/src/production/meet.js @@ -1,9 +1,9 @@ Volcanos(chat.ONIMPORT, { _init: function(can, msg) { can.onimport.myView(can, msg, function(value) { return [ - {view: html.TITLE, list: [value.title||value.name||value.user_name, can.onimport.titleAction(can, value)]}, - {view: html.STATUS, list: [value.uid.slice(0, 6), can.onimport.timeView(can, value), value.user_name]}, - {view: html.OUTPUT, list: [value.content||value.info]}, + {view: html.TITLE, list: [value.title, value.meet_type, can.onimport.titleAction(can, value)]}, + {view: html.STATUS, list: [value.uid.slice(0, 6), value.user_name, value.begin_time+" ~ "+value.end_time.split(" ")[1]]}, + {view: html.OUTPUT, list: [value.content]}, ] }) }, }) \ No newline at end of file diff --git a/src/production/model/model.go b/src/production/model/model.go index cb0fb59..138aa38 100644 --- a/src/production/model/model.go +++ b/src/production/model/model.go @@ -81,21 +81,29 @@ type Task struct { Common IssueUID string `gorm:"type:char(32);index"` CaseCount int `gorm:"default:0"` + Space string `gorm:"type:varchar(64)"` + Index string `gorm:"type:varchar(64)"` + Path string `gorm:"type:varchar(64)"` } type Case struct { Common - TaskUID string `gorm:"type:char(32);index"` + IssueUID string `gorm:"type:char(32);index"` + TaskUID string `gorm:"type:char(32);index"` + Space string `gorm:"type:varchar(64)"` + Index string `gorm:"type:varchar(64)"` } type Meet struct { db.ModelContent - CompanyUID string `gorm:"type:char(32);index"` - StoryUID string `gorm:"type:char(32);index"` - PlanUID string `gorm:"type:char(32);index"` - IssueUID string `gorm:"type:char(32);index"` - Link string `gorm:"type:varchar(255)"` - Type uint8 `gorm:"default:0"` - BeginTime db.Time - EndTime db.Time + CompanyUID string `gorm:"type:char(32);index"` + StoryUID string `gorm:"type:char(32);index"` + PlanUID string `gorm:"type:char(32);index"` + IssueUID string `gorm:"type:char(32);index"` + FromUserUID string `gorm:"type:char(32);index"` + ToUserUID string `gorm:"type:char(32);index"` + Link string `gorm:"type:varchar(255)"` + Type uint8 `gorm:"default:0"` + BeginTime db.Time + EndTime db.Time } type Deal struct { db.ModelContent diff --git a/src/production/plan.go b/src/production/plan.go index e2a9792..98a7df6 100644 --- a/src/production/plan.go +++ b/src/production/plan.go @@ -15,7 +15,7 @@ type Plan struct { modify string `name:"modify title* content version begin_time*:select@date end_time*:select@date" role:"leader"` remove string `name:"remove" role:"leader"` process string `name:"process" role:"leader"` - issueCreate string `name:"issueCreate title* content* issue_type:select level:select price=1000 begin_time:select@date end_time:select@date" role:"worker"` + issueCreate string `name:"issueCreate title* content* price=1000 begin_time:select@date end_time:select@date" role:"worker"` issueList string `name:"issueList" role:"worker"` } @@ -43,32 +43,43 @@ func (s Plan) List(m *ice.Message, arg ...string) { // button = append(button, s.MarketInsert) } if isWorker { - button = append(button, s.IssueCreate) + if kit.Int(value[model.ISSUE_COUNT]) == 0 { + button = append(button, s.IssueCreate) + } } if isLeader { button = append(button, s.Finish) + // button = append(button, s.Remove) } case PlanFinish: if isLeader && m.Option(model.MARKET_UID) == "" { - button = append(button, s.MarketInsert) + // button = append(button, s.MarketInsert) } kit.If(len(arg) == 2, func() { s.DoneMessage(m) }) } m.PushButton(button...) - }).Display("").DisplayCSS("") + }).Display("").DisplayCSS("").Option("otherList", "issueList,designList,taskList,caseList,meetList,dealList") s.StatusCount(m, arg...) } func (s Plan) Process(m *ice.Message, arg ...string) { s.changeStatus(m, PlanCreate, PlanProcess) } func (s Plan) Finish(m *ice.Message, arg ...string) { - count := m.Cmd(Issue{}, s.Select, "plan_uid = ? AND status != ?", m.Option(model.UID), IssueFinish).Length() - if m.WarnNotValid(count > 0, kit.Format("还有 %v 个未完成的需求", count)) { + if s.finishCheck(m, Issue{}, "需求") { + return + } + if s.finishCheck(m, Design{}, "设计") { + return + } + if s.finishCheck(m, Task{}, "任务") { + return + } + if s.finishCheck(m, Case{}, "用例") { return } s.changeStatus(m, PlanProcess, PlanFinish) } -func (s Plan) IssueCreate(m *ice.Message, arg ...string) { s.OtherCreate(m, Issue{}, arg...) } +func (s Plan) IssueCreate(m *ice.Message, arg ...string) { s.commonOtherCreate(m, Issue{}, arg...) } func (s Plan) IssueList(m *ice.Message, arg ...string) { s.OtherList(m, Issue{}).Display("issue.js") } func init() { ice.TeamCtxCmd(Plan{}) } diff --git a/src/production/plan.js b/src/production/plan.js index 3750295..71f11b6 100644 --- a/src/production/plan.js +++ b/src/production/plan.js @@ -5,6 +5,5 @@ Volcanos(chat.ONIMPORT, { {view: html.STATUS, list: [can.onimport.beginTime(can, value), can.onimport.unitView(can, value, "issue_count", "个")]}, {view: html.OUTPUT, list: [value.content]}, can.onimport.titleAction(can, value), ] }) - can.onimport.otherList && can.onimport.otherList(can, msg, "issueList") }, }) diff --git a/src/production/portal.go b/src/production/portal.go index 62a54a3..bb5c5a0 100644 --- a/src/production/portal.go +++ b/src/production/portal.go @@ -17,7 +17,7 @@ func (s Portal) AfterPlaceAuth(m *ice.Message, arg ...string) { defer s.DashboardCreate(m, "")() s.DashboardInsert(m, 1, "需求总量", "个", Issue{}, "") s.DashboardInsert(m, 2, "需求待办", "个", Issue{}, "", "story_uid = ? AND status != ? AND status != ?", m.Option(model.STORY_UID), IssueRejected, IssueFinish) - s.DashboardInsert(m, 3, "任务待办", "个", Task{}, "", "story_uid = ? AND status != ?", m.Option(model.STORY_UID), TaskFinish) + s.DashboardInsert(m, 3, "任务待办", "个", Task{}, "", "story_uid = ? AND status != ?", m.Option(model.STORY_UID), IssueFinish) s.DashboardInsert(m, 4, "任务总量", "个", Task{}, "") } diff --git a/src/production/portal.json b/src/production/portal.json index 5b056fd..7d93986 100644 --- a/src/production/portal.json +++ b/src/production/portal.json @@ -7,10 +7,13 @@ "issueList": "设计原型", "designList": "美化界面", "taskList": "开发任务", "caseList": "测试用例", "dealList": "支付记录", "meetList": "会议记录", + "program": "编程", "style": { + "program": "notice", + "preview": "notice", "process": "notice", "submit": "notice", - "reback": "notice", + "reback": "danger", "finish": "notice", "payfor": "notice", "discuss": "notice", @@ -32,6 +35,7 @@ "date": "日期", "My Story": "我的产品", "user_story_role": "用户角色", + "story_uid": "产品迭代", "story_name": "产品名称", "story_type": "产品类型", "plan_uid": "产品计划", @@ -44,6 +48,7 @@ "design_status": "设计状态", "design_count": "设计数量", "task_uid": "开发任务", + "meet_type": "会议类型", "from_user_uid": "付款人", "to_user_uid": "收款人", "task_status": "任务状态", @@ -93,11 +98,13 @@ "process": "设计中", "submit": "已提交", "finish": "已完成", + "cancel": "已取消", "style": { "create": "danger", "approved": "danger", "rejected": "danger", - "submit": "danger" + "submit": "danger", + "cancel": "danger" } }, "task_status": { diff --git a/src/production/task.go b/src/production/task.go index a450963..dad437d 100644 --- a/src/production/task.go +++ b/src/production/task.go @@ -1,7 +1,11 @@ package production import ( + "path" + "shylinux.com/x/ice" + "shylinux.com/x/icebergs/base/nfs" + "shylinux.com/x/icebergs/base/web" kit "shylinux.com/x/toolkits" "shylinux.com/x/operation/src/production/model" @@ -10,16 +14,18 @@ import ( type Task struct { Table order string `data:"4"` - fields string `data:"title,content,status,case_count,begin_time,end_time,process_time,finish_time,issue_uid,plan_uid,user_uid"` - create string `name:"create issue_uid* title* content* begin_time:select@date end_time:select@date" role:"worker"` - modify string `name:"modify title* content* begin_time*:select@date end_time*:select@date" role:"worker"` - caseCreate string `name:"caseCreate title* content*" role:"worker"` + fields string `data:"title,content,status,case_count,space,path,begin_time,end_time,process_time,finish_time,issue_uid,plan_uid,user_uid"` + create string `name:"create issue_uid* title* content* space path begin_time:select@date end_time:select@date" role:"worker"` + modify string `name:"modify title* content* space path begin_time*:select@date end_time*:select@date" role:"worker"` + finish string `name:"finish" role:"worker"` + caseCreate string `name:"caseCreate title* content* space index" role:"worker"` + caseList string `name:"caseList" role:"worker"` } func (s Task) Create(m *ice.Message, arg ...string) { s.ValueCreate(m, kit.ArgDef(arg, kit.Simple(model.BEGIN_TIME, m.Time(), model.END_TIME, m.Time("72h"))...)...) - s.issueCount(m).DashboardUpdate(m) s.SendMessage(s.GetCommandUID(m), "", "") + s.issueCount(m).DashboardUpdate(m) } func (s Task) Remove(m *ice.Message, arg ...string) { s.ValueRemove(m, arg...) @@ -28,41 +34,28 @@ func (s Task) Remove(m *ice.Message, arg ...string) { func (s Task) List(m *ice.Message, arg ...string) { user_uid := m.Option(model.USER_UID) s.Orders(m, model.STATUS, model.CASE_COUNT, s.Desc(model.CREATED_AT)) - s.ValueList(m, arg).Table(func(value ice.Maps) { s.PushTaskButton(m, value, user_uid, s.CaseCreate) }).Display("") - m.RenameAppend(model.STATUS, model.TASK_STATUS) + s.ValueList(m, arg) s.SelectJoinPlan(m) s.StatusCount(m, arg...) + m.Table(func(value ice.Maps) { + s.PushTaskButton(m, value, user_uid, s.Program, s.CaseCreate) + }).RenameAppend(model.STATUS, model.TASK_STATUS).Display("").Option("otherList", "caseList") +} +func (s Task) Program(m *ice.Message, arg ...string) { + p := path.Base(m.Option(nfs.PATH)) + m.ProcessOpen(kit.MergeURL(web.S(m.Option(web.SPACE))+web.C(web.VIMER), nfs.PATH, nfs.SRC, nfs.FILE, path.Join(p, "portal.go"))) } func (s Task) Process(m *ice.Message, arg ...string) { - s.changeStatus(m, TaskCreate, TaskProcess) + s.changeStatus(m, IssueCreate, IssueProcess) } func (s Task) Finish(m *ice.Message, arg ...string) { - count := m.Cmd(Case{}, s.Select, "task_uid = ? AND status != ?", m.Option(model.UID), TaskFinish).Length() - if m.WarnNotValid(count > 0, kit.Format("还有 %v 个未完成的用例", count)) { + if s.finishCheck(m, Case{}, "用例") { return } - s.changeStatus(m, TaskProcess, TaskFinish) + s.changeStatus(m, IssueProcess, IssueFinish) +} +func (s Task) CaseCreate(m *ice.Message, arg ...string) { + s.commonOtherCreate(m, Case{}, kit.Simple(m.OptionSimple(model.ISSUE_UID), arg)...) } -func (s Task) CaseCreate(m *ice.Message, arg ...string) { s.OtherCreate(m, Case{}, arg...) } func init() { ice.TeamCtxCmd(Task{}) } - -func (s Task) changeStatus(m *ice.Message, from, to TaskStatus) { - s.ChangeStatus(m, int(from), int(to), m.ActionKey()+"_time", m.Time()) -} - -type TaskStatus int - -const ( - TaskCreate TaskStatus = iota - TaskProcess - TaskFinish -) - -var TaskStatusList = map[TaskStatus]string{ - TaskCreate: "create", - TaskProcess: "process", - TaskFinish: "finish", -} - -func (s TaskStatus) String() string { return TaskStatusList[s] } diff --git a/src/production/task.js b/src/production/task.js index 7f7c17f..2a09ce7 100644 --- a/src/production/task.js +++ b/src/production/task.js @@ -1,7 +1,7 @@ Volcanos(chat.ONIMPORT, { _init: function(can, msg) { can.onimport.myView(can, msg, function(value) { return [ - {view: html.TITLE, list: [value.title, can.onimport.textView(can, value)]}, + {view: html.TITLE, list: [value.title, can.onimport.textView(can, value, "status")]}, {view: html.STATUS, list: [can.onimport.beginTime(can, value), can.onimport.unitView(can, value, "case_count", "个"), can.onimport.unitView(can, value, "plan_title"),