diff --git a/src/production/case.go b/src/production/case.go index d31df88..dd57e87 100644 --- a/src/production/case.go +++ b/src/production/case.go @@ -10,71 +10,37 @@ import ( type Case struct { Table order string `data:"5"` - fields string `data:"title,content,case_status,begin_time,end_time,process_time,finish_time,task_uid,plan_uid,user_uid"` + 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"` } 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, "1") + s.taskCount(m) s.SendMessage(s.GetCommandUID(m), "", "") } func (s Case) Remove(m *ice.Message, arg ...string) { s.ValueRemove(m, arg...) - s.taskCount(m, "-1") + s.taskCount(m) } func (s Case) List(m *ice.Message, arg ...string) { user_uid := m.Option(model.USER_UID) - s.ValueList(m, arg).Table(func(value ice.Maps) { - button := []ice.Any{} - switch CaseStatus(kit.Int(value[model.CASE_STATUS])) { - case CaseCreate: - if user_uid == value[model.USER_UID] { - button = append(button, s.Process) - } - case CaseProcess: - if user_uid == value[model.USER_UID] { - button = append(button, s.Finish) - } - case CaseFinish: - kit.If(len(arg) == 2, func() { s.DoneMessage(m) }) - } - m.PushButton(button...) - }).Display("") + 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.SelectJoinPlan(m) + s.StatusCount(m, arg...) } func (s Case) Process(m *ice.Message, arg ...string) { - s.changeStatus(m, CaseCreate, CaseProcess) + s.changeStatus(m, TaskCreate, TaskProcess) } func (s Case) Finish(m *ice.Message, arg ...string) { - s.changeStatus(m, CaseProcess, CaseFinish) + s.changeStatus(m, TaskProcess, TaskFinish) } func init() { ice.TeamCtxCmd(Case{}) } -func (s Case) changeStatus(m *ice.Message, from, to CaseStatus) { +func (s Case) changeStatus(m *ice.Message, from, to TaskStatus) { s.ChangeStatus(m, int(from), int(to), m.ActionKey()+"_time", m.Time()) } -func (s Case) taskCount(m *ice.Message, value string) { - if m.IsErr() || m.Option(model.TASK_UID) == "" { - return - } - m.Cmd(Task{}, s.AddCount, model.CASE_COUNT, value, m.Option(model.TASK_UID)) -} - -type CaseStatus int - -const ( - CaseCreate CaseStatus = iota - CaseProcess - CaseFinish -) - -var CaseStatusList = map[CaseStatus]string{ - CaseCreate: "create", - CaseProcess: "process", - CaseFinish: "finish", -} - -func (s CaseStatus) String() string { return CaseStatusList[s] } diff --git a/src/production/case.js b/src/production/case.js index a0f8946..15e0213 100644 --- a/src/production/case.js +++ b/src/production/case.js @@ -2,7 +2,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.STATUS, list: [(value.process_time||value.begin_time).split(" ")[0], "计划:", value.plan_title]}, + {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 5cec065..2c6ffd0 100644 --- a/src/production/common.go +++ b/src/production/common.go @@ -1,7 +1,10 @@ package production import ( + "strings" + "shylinux.com/x/ice" + "shylinux.com/x/icebergs/base/mdb" kit "shylinux.com/x/toolkits" "shylinux.com/x/operation/src/operation" @@ -11,8 +14,14 @@ 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"` - finish string `name:"finish" 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"` } @@ -26,14 +35,36 @@ func (s Table) Inputs(m *ice.Message, arg ...string) { s.InputsUID(m, Plan{}, arg...) case model.ISSUE_UID: s.InputsUID(m, Issue{}, arg...) - case model.TASK_UID: - s.InputsUID(m, Task{}, arg...) case model.ISSUE_TYPE: s.InputsList(m, IssueTypeList, arg...) + 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() default: - s.Table.Inputs(m, arg...) + switch m.Option("action") { + case "discuss": + switch arg[0] { + case "type": + m.Push(arg[0], "需求沟通", "需求评审", "项目验收") + case "date": + for i := 1; i < 10; i++ { + m.Push(arg[0], strings.Split(m.Time(kit.Format("%dh", i*24)), " ")[0]) + } + case "time": + for i := 18; i < 48; i++ { + m.Push(arg[0], kit.Format("%02d:%s", i/2, kit.Select("30", "00", i%2 == 0))) + } + } + default: + s.Table.Inputs(m, arg...) + } } } func (s Table) RewriteAppend(m *ice.Message, arg ...string) *ice.Message { @@ -47,14 +78,12 @@ 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: + 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.DESIGN_STATUS: - value = DesignStatus(kit.Int(value)).String() - case model.TASK_STATUS: + case model.TASK_STATUS, model.CASE_STATUS: value = TaskStatus(kit.Int(value)).String() - case model.CASE_STATUS: - value = CaseStatus(kit.Int(value)).String() case model.LEVEL: value = Level(kit.Int(value)).String() } @@ -62,13 +91,155 @@ func (s Table) RewriteAppend(m *ice.Message, arg ...string) *ice.Message { }) return s.Table.RewriteAppend(m) } +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) + switch IssueStatus(kit.Int(value[model.STATUS])) { + case IssueCreate: + if isLeader { + button = append(button, s.Discuss) + button = append(button, s.Approve, s.Reject) + } + if user_uid == value[model.USER_UID] { + button = append(button, s.Modify, s.Remove) + } + case IssueApproved: + if user_uid == value[model.USER_UID] { + button = append(button, s.Process) + } + case IssueProcess: + 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) + } + 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) }) + } + m.PushButton(button...) +} func (s Table) SelectJoinPlan(m *ice.Message, arg ...string) { s.SelectJoin(m, Plan{}, model.TITLE) } +func (s Table) StatusCount(m *ice.Message, arg ...string) { + if m.Length() > 0 && len(arg) < 2 { + msg := m.Spawn() + s.Fields(msg, "status, count(*) AS count").Groups(msg, model.STATUS).Orders(msg, model.STATUS) + s.Select(msg, model.STORY_UID, arg[0]).Table(func(value ice.Maps) { + switch status := kit.Int(value[model.STATUS]); m.CommandKey() { + case "plan": + m.Echo(PlanStatus(status).String()).Echo(": ") + case "issue", "design": + m.Echo(IssueStatus(status).String()).Echo(": ") + case "task", "case": + m.Echo(TaskStatus(status).String()).Echo(": ") + } + m.Echo(value[model.COUNT]).Echo("\n") + }) + } +} +func (s Table) Reject(m *ice.Message, arg ...string) { + s.changeStatus(m, IssueCreate, IssueRejected) +} +func (s Table) Approve(m *ice.Message, arg ...string) { + s.changeStatus(m, IssueCreate, IssueApproved) +} +func (s Table) Process(m *ice.Message, arg ...string) { + s.changeStatus(m, IssueApproved, IssueProcess) +} +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) Discuss(m *ice.Message, arg ...string) { + m.Cmd(meet{}, s.Create, 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) +} +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)) +} +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) + 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)) + s.SelectJoinUser(m) + return m +} +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) { s.Table.ChangeStatus(m, m.Option(model.STORY_UID), m.Option(model.UID), from, to, arg...) s.DashboardUpdate(m) } +func (s Table) addCount(m *ice.Message, target ice.Any) Table { + UID := s.Keys(target, model.UID) + if m.IsErr() || m.Option(UID) == "" { + return s + } + m.Cmd(target, s.AddCount, m.CommandKey()+"_count", kit.Select("-1", "1", m.ActionKey() == mdb.CREATE), m.Option(UID)) + return s +} +func (s Table) planCount(m *ice.Message) Table { return s.addCount(m, Plan{}) } +func (s Table) issueCount(m *ice.Message) Table { return s.addCount(m, Issue{}) } +func (s Table) taskCount(m *ice.Message) Table { return s.addCount(m, Task{}) } type Tables struct{ Table } diff --git a/src/production/deal.go b/src/production/deal.go new file mode 100644 index 0000000..a2fc2a0 --- /dev/null +++ b/src/production/deal.go @@ -0,0 +1,21 @@ +package production + +import ( + "shylinux.com/x/ice" + "shylinux.com/x/operation/src/production/model" +) + +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"` +} + +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) +} + +func init() { ice.TeamCtxCmd(deal{}) } diff --git a/src/production/deal.js b/src/production/deal.js new file mode 100644 index 0000000..b8a5c0c --- /dev/null +++ b/src/production/deal.js @@ -0,0 +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.moneyView(can, value), 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]}, + ] }) + }, +}) \ No newline at end of file diff --git a/src/production/design.go b/src/production/design.go index bc98f60..0301b38 100644 --- a/src/production/design.go +++ b/src/production/design.go @@ -10,72 +10,25 @@ import ( type Design struct { Table order string `data:"3"` - fields string `data:"title,content,design_status,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"` + fields string `data:"title,content,status,price,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.BEGIN_TIME, m.Time(), model.END_TIME, m.Time("72h"))...)...) - s.issueCount(m, "1") + 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), "", "") } func (s Design) Remove(m *ice.Message, arg ...string) { s.ValueRemove(m, arg...) - s.issueCount(m, "-1") + s.issueCount(m) } func (s Design) List(m *ice.Message, arg ...string) { user_uid := m.Option(model.USER_UID) - s.ValueList(m, arg).Table(func(value ice.Maps) { - button := []ice.Any{} - switch DesignStatus(kit.Int(value[model.DESIGN_STATUS])) { - case DesignCreate: - if user_uid == value[model.USER_UID] { - button = append(button, s.Process) - } - case DesignProcess: - if user_uid == value[model.USER_UID] { - button = append(button, s.Finish) - } - case DesignFinish: - kit.If(len(arg) == 2, func() { s.DoneMessage(m) }) - } - m.PushButton(button...) - }).Display("") + 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.SelectJoinPlan(m) + s.StatusCount(m, arg...) } -func (s Design) Process(m *ice.Message, arg ...string) { - s.changeStatus(m, DesignCreate, DesignProcess) -} -func (s Design) Finish(m *ice.Message, arg ...string) { - s.changeStatus(m, DesignProcess, DesignFinish) -} - func init() { ice.TeamCtxCmd(Design{}) } - -func (s Design) changeStatus(m *ice.Message, from, to DesignStatus) { - s.ChangeStatus(m, int(from), int(to), m.ActionKey()+"_time", m.Time()) -} -func (s Design) issueCount(m *ice.Message, value string) Design { - if m.IsErr() || m.Option(model.ISSUE_UID) == "" { - return s - } - m.Cmd(Issue{}, s.AddCount, model.DESIGN_COUNT, value, m.Option(model.ISSUE_UID)) - return s -} - -type DesignStatus int - -const ( - DesignCreate DesignStatus = iota - DesignProcess - DesignFinish -) - -var DesignStatusList = map[DesignStatus]string{ - DesignCreate: "create", - DesignProcess: "process", - DesignFinish: "finish", -} - -func (s DesignStatus) String() string { return DesignStatusList[s] } diff --git a/src/production/design.js b/src/production/design.js index 2a2fac0..d725ad2 100644 --- a/src/production/design.js +++ b/src/production/design.js @@ -2,7 +2,8 @@ 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.STATUS, list: [can.onimport.beginTime(can, value), "计划:", value.plan_title]}, + {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", "元")]}, {view: html.OUTPUT, list: [value.content]}, can.onimport.titleAction(can, value), ] }) }, diff --git a/src/production/issue.go b/src/production/issue.go index 2b483f4..c843594 100644 --- a/src/production/issue.go +++ b/src/production/issue.go @@ -10,87 +10,45 @@ import ( type Issue struct { Table order string `data:"2"` - fields string `data:"title,content,level,issue_type,issue_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 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"` - reject string `name:"reject" role:"leader"` - approve string `name:"approve" role:"leader"` - submit string `name:"submit" role:"worker"` - reback string `name:"reback" role:"leader"` - payfor string `name:"payfor" role:"worker"` - designCreate string `name:"designCreate title* content* begin_time:select@date end_time:select@date" role:"worker"` - taskCreate string `name:"taskCreate title* content* begin_time:select@date end_time:select@date" role:"worker"` + 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"` + 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(s.TransPrice(m, 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.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, "1").DashboardUpdate(m) + s.planCount(m).DashboardUpdate(m) s.SendMessage(s.GetCommandUID(m), "", "") } func (s Issue) Remove(m *ice.Message, arg ...string) { s.ValueRemove(m, arg...) - s.planCount(m, "-1").DashboardUpdate(m) + s.planCount(m).DashboardUpdate(m) } func (s Issue) List(m *ice.Message, arg ...string) { - isLeader, isWorker, user_uid := s.IsLeader(m), s.IsWorker(m), m.Option(model.USER_UID) + if !s.IsWorker(m) { + s.ApplyCheck(m, arg...) + return + } + 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) { - button := []ice.Any{} - switch IssueStatus(kit.Int(value[model.ISSUE_STATUS])) { - case IssueCreate: - if isLeader { - button = append(button, s.Reject, s.Approve) - } - if user_uid == value[model.USER_UID] { - button = append(button, s.Modify, s.Remove) - } - case IssueApproved: - if user_uid == value[model.USER_UID] { - button = append(button, s.Process) - } - case IssueProcess: - 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.Reback, s.Finish) - } - case IssueFinish: - if isWorker { - button = append(button, s.DesignCreate, s.TaskCreate) - } - if isLeader && kit.Int(value[model.PRICE]) > 0 { - // button = append(button, s.Payfor) - } - kit.If(len(arg) == 2 && value[model.PRICE] == "0", func() { s.DoneMessage(m) }) - } - m.PushButton(button...) + s.PushIssueButton(m, value, user_uid, s.DesignCreate, s.TaskCreate) }).Display("") s.SelectJoinPlan(m) -} -func (s Issue) Reject(m *ice.Message, arg ...string) { - s.changeStatus(m, IssueCreate, IssueRejected) -} -func (s Issue) Approve(m *ice.Message, arg ...string) { - s.changeStatus(m, IssueCreate, IssueApproved) -} -func (s Issue) Process(m *ice.Message, arg ...string) { - s.changeStatus(m, IssueApproved, IssueProcess) -} -func (s Issue) Submit(m *ice.Message, arg ...string) { - s.ChangeStatus(m, int(IssueProcess), int(IssueSubmit)) -} -func (s Issue) Reback(m *ice.Message, arg ...string) { - s.ChangeStatus(m, int(IssueSubmit), int(IssueProcess)) + s.StatusCount(m, arg...) } func (s Issue) Finish(m *ice.Message, arg ...string) { - count := m.Cmd(Design{}, s.Select, "issue_uid = ? AND status != ?", m.Option(model.UID), DesignFinish).Length() + 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)) { return } @@ -100,26 +58,21 @@ func (s Issue) Finish(m *ice.Message, arg ...string) { } s.changeStatus(m, IssueSubmit, IssueFinish) } -func (s Issue) DesignCreate(m *ice.Message, arg ...string) { - s.OtherCreate(m, Design{}, model.ISSUE_UID, m.Option(model.UID), arg, m.OptionSimple(model.PLAN_UID)) +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{}, model.ISSUE_UID, m.Option(model.UID), arg, m.OptionSimple(model.PLAN_UID)) +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 init() { ice.TeamCtxCmd(Issue{}) } -func (s Issue) changeStatus(m *ice.Message, from, to IssueStatus) { - s.ChangeStatus(m, int(from), int(to), m.ActionKey()+"_time", m.Time()) -} -func (s Issue) planCount(m *ice.Message, value string) Issue { - if m.IsErr() || m.Option(model.PLAN_UID) == "" { - return s - } - m.Cmd(Plan{}, s.AddCount, model.ISSUE_COUNT, value, m.Option(model.PLAN_UID)) - return s -} - type IssueType int const ( diff --git a/src/production/issue.js b/src/production/issue.js index fb178f4..1e9558d 100644 --- a/src/production/issue.js +++ b/src/production/issue.js @@ -7,13 +7,14 @@ Volcanos(chat.ONIMPORT, { can.onimport.textView(can, value), ]}, {view: html.STATUS, list: [ - can.onimport.beginTime(can, value), - "设计:", value.design_count+" 个", - "任务:", value.task_count+" 个", - "计划:", value.plan_title, + (value.process_time||value.begin_time).split(" ")[0]+" ~ "+(value.finish_time||value.end_time).split(" ")[0], + can.onimport.unitView(can, value, "design_count", "个"), + can.onimport.unitView(can, value, "task_count", "个"), + can.onimport.unitView(can, value, "plan_title"), ]}, - value.price > 0 && {view: html.OUTPUT, list: ["报价: "+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 new file mode 100644 index 0000000..e417ab0 --- /dev/null +++ b/src/production/meet.go @@ -0,0 +1,44 @@ +package production + +import ( + "time" + + "shylinux.com/x/ice" + kit "shylinux.com/x/toolkits" +) + +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"` + 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")...) +} +func (s meet) List(m *ice.Message, arg ...string) { + s.ValueList(m, arg).Display("") +} + +func init() { ice.TeamCtxCmd(meet{}) } + +type MeetType int + +const ( + MeetTalk MeetType = iota + MeetValue + MeetCheck +) + +var MeetTypeList = map[MeetType]string{ + MeetTalk: "需求沟通", + MeetValue: "需求评审", + MeetCheck: "项目验收", +} + +func (s MeetType) String() string { return MeetTypeList[s] } diff --git a/src/production/meet.js b/src/production/meet.js new file mode 100644 index 0000000..308755b --- /dev/null +++ b/src/production/meet.js @@ -0,0 +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]}, + ] }) + }, +}) \ No newline at end of file diff --git a/src/production/model/model.go b/src/production/model/model.go index bdfebfd..cb0fb59 100644 --- a/src/production/model/model.go +++ b/src/production/model/model.go @@ -3,12 +3,14 @@ package model import "shylinux.com/x/mysql-story/src/db" const ( + CREATED_AT = "created_at" UID = "uid" NAME = "name" INFO = "info" TYPE = "type" LEVEL = "level" STATUS = "status" + COUNT = "count" PRICE = "price" LINK = "link" TITLE = "title" @@ -16,6 +18,8 @@ const ( VERSION = "version" USER_UID = "user_uid" USER_ROLE = "user_role" + USER_NAME = "user_name" + USER_AVATAR = "user_avatar" USER_STORY_ROLE = "user_story_role" STORY_UID = "story_uid" STORY_NAME = "story_name" @@ -33,6 +37,9 @@ const ( TASK_UID = "task_uid" TASK_STATUS = "task_status" CASE_STATUS = "case_status" + MEET_TYPE = "meet_type" + FROM_USER_UID = "from_user_uid" + TO_USER_UID = "to_user_uid" MARKET_UID = "market_uid" BEGIN_TIME = "begin_time" END_TIME = "end_time" @@ -66,7 +73,9 @@ type Issue struct { } type Design struct { Common - IssueUID string `gorm:"type:char(32);index"` + IssueUID string `gorm:"type:char(32);index"` + RejectTime db.Time + ApproveTime db.Time } type Task struct { Common @@ -77,8 +86,31 @@ type Case struct { Common TaskUID string `gorm:"type:char(32);index"` } +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 +} +type Deal 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"` + FromUserUID string `gorm:"type:char(32);index"` + ToUserUID string `gorm:"type:char(32);index"` + Price int `gorm:"default:0"` +} -func init() { db.CmdModels("", &UserStory{}, &Story{}, &Plan{}, &Issue{}, &Design{}, &Task{}, &Case{}) } +func init() { + db.CmdModels("", &UserStory{}, &Story{}, &Plan{}, &Issue{}, &Design{}, &Task{}, &Case{}, &Meet{}, &Deal{}) +} type Common struct { db.ModelContent diff --git a/src/production/plan.go b/src/production/plan.go index 2442664..e2a9792 100644 --- a/src/production/plan.go +++ b/src/production/plan.go @@ -15,8 +15,8 @@ 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"` - finish string `name:"finish" role:"leader"` - issueCreate string `name:"issueCreate title* content* issue_type:select level:select price begin_time:select@date end_time:select@date" role:"worker"` + issueCreate string `name:"issueCreate title* content* issue_type:select level:select price=1000 begin_time:select@date end_time:select@date" role:"worker"` + issueList string `name:"issueList" role:"worker"` } func (s Plan) Create(m *ice.Message, arg ...string) { @@ -25,7 +25,12 @@ func (s Plan) Create(m *ice.Message, arg ...string) { } func (s Plan) List(m *ice.Message, arg ...string) { isLeader, isWorker := s.IsLeader(m), s.IsWorker(m) - defer kit.If(!isLeader, func() { m.SetResult().Action() }) + defer kit.If(!isLeader, func() { + if m.Action(); m.Length() == 0 { + m.SetResult("请等待管理员创建迭代计划") + } + }) + s.Orders(m, model.STATUS, model.ISSUE_COUNT, s.Desc(model.CREATED_AT)) s.ValueList(m, arg).Table(func(value ice.Maps) { button := []ice.Any{} switch PlanStatus(kit.Int(value[model.PLAN_STATUS])) { @@ -34,6 +39,9 @@ func (s Plan) List(m *ice.Message, arg ...string) { button = append(button, s.Process, s.Modify, s.Remove) } case PlanProcess: + if isLeader && m.Option(model.MARKET_UID) == "" { + // button = append(button, s.MarketInsert) + } if isWorker { button = append(button, s.IssueCreate) } @@ -47,24 +55,21 @@ func (s Plan) List(m *ice.Message, arg ...string) { kit.If(len(arg) == 2, func() { s.DoneMessage(m) }) } m.PushButton(button...) - }).Display("").DisplayCSS("").Sort("plan_status,issue_count,create_time") + }).Display("").DisplayCSS("") + 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)) { - s.changeStatus(m, PlanProcess, PlanFinish) + if m.WarnNotValid(count > 0, kit.Format("还有 %v 个未完成的需求", count)) { + return } + s.changeStatus(m, PlanProcess, PlanFinish) } -func (s Plan) IssueCreate(m *ice.Message, arg ...string) { - s.OtherCreate(m, Issue{}, model.PLAN_UID, m.Option(model.UID), arg) -} -func (s Table) OtherCreate(m *ice.Message, target ice.Any, arg ...ice.Any) { - m.Cmdy(target, s.Create, kit.Simple(arg...)) - kit.If(!m.IsErr(), func() { m.ProcessField(target, []string{m.Option(model.STORY_UID), m.Result()}) }) -} +func (s Plan) IssueCreate(m *ice.Message, arg ...string) { s.OtherCreate(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 d9c05d3..3750295 100644 --- a/src/production/plan.js +++ b/src/production/plan.js @@ -2,8 +2,9 @@ Volcanos(chat.ONIMPORT, { _init: function(can, msg) { can.onimport.myView(can, msg, function(value) { return [ {view: html.TITLE, list: [value.title, value.version, can.onimport.textView(can, value)]}, - {view: html.STATUS, list: [can.onimport.beginTime(can, value), "需求量:", value.issue_count+" 个"]}, + {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") }, -}) \ No newline at end of file +}) diff --git a/src/production/portal.go b/src/production/portal.go index a2f348d..62a54a3 100644 --- a/src/production/portal.go +++ b/src/production/portal.go @@ -17,8 +17,8 @@ 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, 4, "任务待办", "个", Task{}, "", "story_uid = ? AND status != ?", m.Option(model.STORY_UID), TaskFinish) - s.DashboardInsert(m, 3, "任务总量", "个", Task{}, "") + s.DashboardInsert(m, 3, "任务待办", "个", Task{}, "", "story_uid = ? AND status != ?", m.Option(model.STORY_UID), TaskFinish) + s.DashboardInsert(m, 4, "任务总量", "个", Task{}, "") } func init() { gonganxitong.PortalCmd(Portal{Portal: guanlixitong.NewPortal(userStory{}, story{})}) } diff --git a/src/production/portal.json b/src/production/portal.json index f76207d..5b056fd 100644 --- a/src/production/portal.json +++ b/src/production/portal.json @@ -1,20 +1,27 @@ { "portal": "产品迭代", "member": "项目成员", "plan": "迭代计划", "issue": "产品需求", "design": "界面设计", "task": "开发任务", "case": "测试用例", - "process": "开始", "submit": "提交", "reback": "返工", "finish": "完成", "payfor": "支付", - "issueCreate": "创建需求", "designCreate": "创建设计", "taskCreate": "创建任务", "caseCreate": "创建用例", + "meet": "会议记录", "deal": "支付记录", + "process": "开始", "submit": "提交", "reback": "返工", "finish": "完成", "discuss": "约会", "payfor": "支付", + "issueCreate": "设计原型", "designCreate": "美化界面", "taskCreate": "开发任务", "caseCreate": "测试用例", + "issueList": "设计原型", "designList": "美化界面", "taskList": "开发任务", "caseList": "测试用例", + "dealList": "支付记录", + "meetList": "会议记录", "style": { "process": "notice", "submit": "notice", "reback": "notice", "finish": "notice", "payfor": "notice", + "discuss": "notice", "issueCreate": "notice", "designCreate": "notice", "taskCreate": "notice", "caseCreate": "notice" }, "icons": { + "meet": "issue.png", + "deal": "issue.png", "plan": "plan.png", "issue": "issue.png", "design": "design.png", @@ -22,6 +29,7 @@ "case": "case.png" }, "input": { + "date": "日期", "My Story": "我的产品", "user_story_role": "用户角色", "story_name": "产品名称", @@ -36,12 +44,15 @@ "design_status": "设计状态", "design_count": "设计数量", "task_uid": "开发任务", + "from_user_uid": "付款人", + "to_user_uid": "收款人", "task_status": "任务状态", "task_count": "任务数量", "case_status": "用例状态", "case_count": "用例数量", "process_time": "开始时间", "finish_time": "完成时间", + "comment": "备注", "level": "优先级" }, "value": { @@ -63,11 +74,6 @@ "military": "军用软件", "system": "系统软件" }, - "plan_status": { - "create": "待开始", - "process": "进行中", - "finish": "已完成" - }, "issue_type": { "feature": "功能", "bugfix": "问题", @@ -75,11 +81,16 @@ "bugfix": "danger" } }, - "issue_status": { + "plan_status": { + "create": "待开始", + "process": "进行中", + "finish": "已完成" + }, + "status": { "create": "待评审", "rejected": "已驳回", - "approved": "待调研", - "process": "调研中", + "approved": "待设计", + "process": "设计中", "submit": "已提交", "finish": "已完成", "style": { @@ -89,14 +100,6 @@ "submit": "danger" } }, - "design_status": { - "create": "待设计", - "process": "设计中", - "finish": "已完成", - "style": { - "create": "danger" - } - }, "task_status": { "create": "待开发", "process": "开发中", diff --git a/src/production/portal.shy b/src/production/portal.shy new file mode 100644 index 0000000..8937faa --- /dev/null +++ b/src/production/portal.shy @@ -0,0 +1,6 @@ +chapter "产品迭代" +section "迭代计划" +section "产品需求" +section "界面设计" +section "开发任务" +section "测试用例" \ No newline at end of file diff --git a/src/production/task.go b/src/production/task.go index e4a0f05..a450963 100644 --- a/src/production/task.go +++ b/src/production/task.go @@ -10,70 +10,45 @@ import ( type Task struct { Table order string `data:"4"` - fields string `data:"title,content,task_status,case_count,begin_time,end_time,process_time,finish_time,issue_uid,plan_uid,user_uid"` + 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* begin_time:select@date end_time:select@date" role:"worker"` + caseCreate string `name:"caseCreate title* content*" 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, "1").DashboardUpdate(m) + s.issueCount(m).DashboardUpdate(m) s.SendMessage(s.GetCommandUID(m), "", "") } func (s Task) Remove(m *ice.Message, arg ...string) { s.ValueRemove(m, arg...) - s.issueCount(m, "-1").DashboardUpdate(m) + s.issueCount(m).DashboardUpdate(m) } func (s Task) List(m *ice.Message, arg ...string) { - isWorker, user_uid := s.IsWorker(m), m.Option(model.USER_UID) - s.ValueList(m, arg).Table(func(value ice.Maps) { - button := []ice.Any{} - switch TaskStatus(kit.Int(value[model.TASK_STATUS])) { - case TaskCreate: - if user_uid == value[model.USER_UID] { - button = append(button, s.Process) - } - case TaskProcess: - if isWorker { - button = append(button, s.CaseCreate) - } - if user_uid == value[model.USER_UID] { - button = append(button, s.Finish) - } - case TaskFinish: - kit.If(len(arg) == 2, func() { s.DoneMessage(m) }) - } - m.PushButton(button...) - }).Display("") + 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.SelectJoinPlan(m) + s.StatusCount(m, arg...) } func (s Task) Process(m *ice.Message, arg ...string) { s.changeStatus(m, TaskCreate, TaskProcess) } func (s Task) Finish(m *ice.Message, arg ...string) { - count := m.Cmd(Case{}, s.Select, "task_uid = ? AND status != ?", m.Option(model.UID), CaseFinish).Length() + 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)) { return } s.changeStatus(m, TaskProcess, TaskFinish) } -func (s Task) CaseCreate(m *ice.Message, arg ...string) { - s.OtherCreate(m, Case{}, model.TASK_UID, m.Option(model.UID), arg, m.OptionSimple(model.PLAN_UID)) -} +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()) - s.DashboardUpdate(m) -} -func (s Task) issueCount(m *ice.Message, value string) Task { - if m.IsErr() || m.Option(model.ISSUE_UID) == "" { - return s - } - m.Cmd(Issue{}, s.AddCount, model.TASK_COUNT, value, m.Option(model.ISSUE_UID)) - return s } type TaskStatus int diff --git a/src/production/task.js b/src/production/task.js index 1b54bfd..7f7c17f 100644 --- a/src/production/task.js +++ b/src/production/task.js @@ -2,7 +2,10 @@ 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.STATUS, list: [can.onimport.beginTime(can, value), "用例:", value.case_count+" 个", "计划:", value.plan_title]}, + {view: html.STATUS, list: [can.onimport.beginTime(can, value), + can.onimport.unitView(can, value, "case_count", "个"), + can.onimport.unitView(can, value, "plan_title"), + ]}, {view: html.OUTPUT, list: [value.content]}, can.onimport.titleAction(can, value), ] }) }, diff --git a/usr/local/export/web.team.production.portal/hash.json b/usr/local/export/web.team.production.portal/hash.json index 5cf15d2..0d33d98 100644 --- a/usr/local/export/web.team.production.portal/hash.json +++ b/usr/local/export/web.team.production.portal/hash.json @@ -8,6 +8,15 @@ "time": "2024-09-12 20:43:01.619" } }, + "23769af348b5bf39fce16d2257889544": { + "meta": { + "icons": "src/production/issue.png", + "index": "web.team.production.deal", + "name": "支付记录", + "order": "7", + "time": "2025-04-28 09:30:23.328" + } + }, "247b484fb13394452bc978e5ecad33ff": { "meta": { "icons": "/p/src/gonganxitong/apply.png?pod=20240724-community", @@ -21,6 +30,7 @@ "2cc2b9d11344506a6b0bbb0dbdde2d43": { "meta": { "auth": "issued", + "enable": "false", "icons": "https://img.icons8.com/officel/80/online-store.png", "index": "web.team.production.goodslist", "name": "在线商城", @@ -42,6 +52,7 @@ "2f55a878524db4227e7476307269db05": { "meta": { "auth": "issued", + "enable": "false", "icons": "https://img.icons8.com/officel/80/online-payment-with-a-credit-card.png", "index": "web.team.production.paymentlist", "name": "在线支付", @@ -50,6 +61,15 @@ "time": "2024-11-23 17:07:01.083" } }, + "3be1265611cf96a9d61bd4c2c879db70": { + "meta": { + "icons": "src/production/issue.png", + "index": "web.team.production.meet", + "name": "会议记录", + "order": "6", + "time": "2025-04-28 09:30:23.334" + } + }, "50dd2633fafc2efb90760b602f1500ea": { "meta": { "icons": "/p/src/gonganxitong/notice.png?pod=20240724-community", @@ -118,6 +138,7 @@ "7cf76afacb83fabb3d6a6ffaf48b6066": { "meta": { "auth": "issued", + "enable": "false", "icons": "https://img.icons8.com/officel/80/documents.png", "index": "web.team.production.document", "name": "在线文档", @@ -165,6 +186,7 @@ "a9b5b213c868653f1a060c3231d57e8f": { "meta": { "auth": "issued", + "enable": "false", "icons": "https://img.icons8.com/officel/80/agreement.png", "index": "web.team.production.contract", "name": "在线合同", @@ -204,6 +226,7 @@ "c9559beab992f8b46b9cfa4a196e61e8": { "meta": { "auth": "issued", + "enable": "false", "icons": "https://img.icons8.com/officel/80/ios-photos.png", "index": "web.team.production.photo", "name": "在线相册", @@ -226,6 +249,7 @@ "cea1324e3dca123f6560dee5c559a587": { "meta": { "auth": "issued", + "enable": "false", "icons": "https://img.icons8.com/officel/80/video-conference.png", "index": "web.team.production.meeting", "name": "在线会议",