mirror of
https://shylinux.com/x/operation
synced 2025-04-24 17:08:04 +08:00
Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
29d61783d2 | |||
f55256dee2 | |||
2a2f9e7b3e | |||
f1ab27b595 | |||
1308ebda7b | |||
5376decbf0 | |||
a7aa40ad65 | |||
4f5556781d | |||
9941c35ce4 | |||
2d2774c7f2 | |||
832fe1fc15 | |||
088a2089c1 | |||
19ca86b7dc | |||
d18f4fe4b6 | |||
9eb70a7223 |
28
go.mod
28
go.mod
@ -3,16 +3,18 @@ module shylinux.com/x/operation
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
shylinux.com/x/community v0.0.24
|
||||
shylinux.com/x/enterprise v0.0.14
|
||||
shylinux.com/x/golang-story v0.0.31
|
||||
shylinux.com/x/mysql-story v0.6.31
|
||||
2025-dev.shylinux.com/x/20250211-service v0.0.6
|
||||
2025-dev.shylinux.com/x/20250215-cluster v0.0.7
|
||||
shylinux.com/x/community v0.0.28
|
||||
shylinux.com/x/enterprise v0.0.17
|
||||
shylinux.com/x/golang-story v0.0.32 // indirect
|
||||
shylinux.com/x/mysql-story v0.6.32
|
||||
)
|
||||
|
||||
require (
|
||||
shylinux.com/x/ice v1.5.68
|
||||
shylinux.com/x/icebergs v1.9.70
|
||||
shylinux.com/x/toolkits v1.0.18
|
||||
shylinux.com/x/ice v1.5.74
|
||||
shylinux.com/x/icebergs v1.9.76
|
||||
shylinux.com/x/toolkits v1.0.19
|
||||
)
|
||||
|
||||
require (
|
||||
@ -21,15 +23,6 @@ require (
|
||||
shylinux.com/x/websocket v0.0.4 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1095 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ocr v1.0.1046 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/smh v1.0.1051 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.1047 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tke v1.0.1095 // indirect
|
||||
github.com/wechatpay-apiv3/wechatpay-go v0.2.20 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
@ -45,6 +38,7 @@ require (
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/wechatpay-apiv3/wechatpay-go v0.2.20 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
gorm.io/driver/mysql v1.5.7 // indirect
|
||||
@ -53,4 +47,4 @@ require (
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.5.0 // indirect
|
||||
modernc.org/sqlite v1.23.1 // indirect
|
||||
)
|
||||
)
|
||||
|
50
go.sum
50
go.sum
@ -1,3 +1,8 @@
|
||||
2025-dev.shylinux.com/x/20250211-service v0.0.6 h1:FOQ6Z+eHsY+3qfIoKHjblbIs6BUyHPq1xGK1wvFdfXo=
|
||||
2025-dev.shylinux.com/x/20250211-service v0.0.6/go.mod h1:iHH7uHRP7WasG19pNjujlXwZFjJqzX3dS0/T1imfsj0=
|
||||
2025-dev.shylinux.com/x/20250215-cluster v0.0.6/go.mod h1:4sbNfB+nBVmIpRSzVlY+uiEQv44JdPfwwBpwWzbQktw=
|
||||
2025-dev.shylinux.com/x/20250215-cluster v0.0.7 h1:GhQImaF6RbliJ6467gdeB4AVzCNyz5LwmA9AeCphEvo=
|
||||
2025-dev.shylinux.com/x/20250215-cluster v0.0.7/go.mod h1:rhNacwQogLrmiNkmoptqpKY9ieRXAhVHenHwZRcdBB8=
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw=
|
||||
@ -57,19 +62,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1046/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1047/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1051/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1095 h1:chwhz7qiknR6hz/gVpQszRSL2Bw/jXNz9dHmY0tWelE=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1095/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ocr v1.0.1046 h1:P8TrTPEWu4GjnEMyNgdYmV5jXigGtDMn+sVTLJJvW0c=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ocr v1.0.1046/go.mod h1:ifVagKrjnvy/ibrvLZjsELEh5WdRtchM8xyUlF88BNg=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/smh v1.0.1051 h1:P7q/ROrOi/M/VzM4ADMeALj94zJaW/zIGvJ6xe5BBkw=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/smh v1.0.1051/go.mod h1:dVFt5mYSzAtQ2uLOBavl9G4KHrjJJOCLqtrzvW+h0tg=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.1047 h1:FF8uERgTL9NKxgUHrKHbVefETVL3J6DeL9t6qvIT5yI=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.1047/go.mod h1:3tgFFSlybx6XyhvLWpnSjWYFMedTyQC9oyh8CH1Ak28=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tke v1.0.1095 h1:l7SQnVkft1vPdfE/gv/ee2wBj54+hacPzchjs4gnGgw=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tke v1.0.1095/go.mod h1:7V6/Y6tPk0jL21YAevsuDSBSN3nU5XFRBR6CFsTLhJE=
|
||||
github.com/wechatpay-apiv3/wechatpay-go v0.2.20 h1:gS8oFn1bHGnyapR2Zb4aqTV6l4kJWgbtqjCq6k1L9DQ=
|
||||
github.com/wechatpay-apiv3/wechatpay-go v0.2.20/go.mod h1:A254AUBVB6R+EqQFo3yTgeh7HtyqRRtN2w9hQSOrd4Q=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
@ -190,25 +182,29 @@ modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw
|
||||
modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c=
|
||||
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE=
|
||||
shylinux.com/x/community v0.0.24 h1:csrI09xLQHEVSp6mgUTuowfR1W36M1KHWMaU6jEOIgc=
|
||||
shylinux.com/x/community v0.0.24/go.mod h1:9bfMJNKzhnfgVmMlaLpkrMlKQBz+XwMsUJ408RWGC9Q=
|
||||
shylinux.com/x/enterprise v0.0.13 h1:/bEY/ep/AehXh0Pi7vNDdTutzQfeN5K0BM+NNXFQ2+Q=
|
||||
shylinux.com/x/enterprise v0.0.13/go.mod h1:0SntXQDxLahlfuwRqkHcvvhoYBS2qM+OKbHNF8L4qfg=
|
||||
shylinux.com/x/community v0.0.28 h1:/h7gthD8X6lVh1dDg3W3sBX4dpotbddfdGdR/BqBV4c=
|
||||
shylinux.com/x/community v0.0.28/go.mod h1:MamBZhpO3+c5YISRJt4xnxa5VDBBstUR+9FnPQrhZMU=
|
||||
shylinux.com/x/enterprise v0.0.17 h1:29VjNHt4YiPryQGNtVTnYqiXNHxau4EnkoUDzlxgB6Y=
|
||||
shylinux.com/x/enterprise v0.0.17/go.mod h1:+DmZbYMykX5U65BJ7DYOcwFubslKa2b78DyRaqUYuH4=
|
||||
shylinux.com/x/go-git/v5 v5.6.7 h1:WD5QSco7m3QooPCgdvQ6/GyGIFPun8C+hex5N41LYlk=
|
||||
shylinux.com/x/go-git/v5 v5.6.7/go.mod h1:Qb0lA+uIrofZg8NQerhYcJHgGWixFqvS6p3aJ/L5Nlk=
|
||||
shylinux.com/x/go-qrcode v0.0.3 h1:RMo+Vidbgq3HatLBj7DDXcTbTLFUwzis5K7TqBkD38U=
|
||||
shylinux.com/x/go-qrcode v0.0.3/go.mod h1:KAbtU+KwiiABMZ/CJ0zh9PI2AX82Uf9rRYcQ4ODm4po=
|
||||
shylinux.com/x/go-sql-mysql v0.0.2/go.mod h1:lHjRMZz5Lii6U+49fhkbCWgsnL+yux54SYJYWqASN8Y=
|
||||
shylinux.com/x/golang-story v0.0.31 h1:qKEvSRrjn2tV15R5IXWkYFOYveEMztPQaD+Cv8TlHTg=
|
||||
shylinux.com/x/golang-story v0.0.31/go.mod h1:r8PJE6UYjzJK7H5Hd2b1j5RB3qvE0dQl5zN0HY24Q0g=
|
||||
shylinux.com/x/ice v1.5.68 h1:oFUpwJS3ER6pAmdpHAyQrVdc4YozcHPuRn2UJmUtpFo=
|
||||
shylinux.com/x/ice v1.5.68/go.mod h1:LjHSkg3o+kT3k6lSFJVreez6qiI9ghpnr9Ql94k3+Iw=
|
||||
shylinux.com/x/icebergs v1.9.70 h1:NyoMrTX1Dtf0HosB7GNAO8NODZabdcNw1ZZLSfbhUDw=
|
||||
shylinux.com/x/icebergs v1.9.70/go.mod h1:+4bl7yJRMFtlTQRDLd+xh6b0hwXkqWaHLmx63Jeewwk=
|
||||
shylinux.com/x/mysql-story v0.6.31 h1:QEaVKwN1WtKBNKRdDNpySVBO6WswSnJjUEY6tA9vDpk=
|
||||
shylinux.com/x/mysql-story v0.6.31/go.mod h1:ZBN9ZkJk/J2Zq66lMs/XRMIoAX2gwHpDhIL9xsYEtEY=
|
||||
shylinux.com/x/golang-story v0.0.32 h1:7xu28iREL2cuZzf80luJwI9BWptow+ME00L1lgyjmDI=
|
||||
shylinux.com/x/golang-story v0.0.32/go.mod h1:NsI5fULu3q7o2b+VzZ5tiJ3+0pUTjE9DdQxa870htmw=
|
||||
shylinux.com/x/ice v1.5.72/go.mod h1:ouTMN0stkJu1RGAQrMHrGj/BqDynyD1VV53shR9zQm4=
|
||||
shylinux.com/x/ice v1.5.73/go.mod h1:uGI73gYkk+FiJt5qmy/aYhoKRJ4wobcJk3WrPGh8Waw=
|
||||
shylinux.com/x/ice v1.5.74 h1:5hTPmchO79b1d2+/DwBDLiG2WkTL65G/hOEAcGJVeB8=
|
||||
shylinux.com/x/ice v1.5.74/go.mod h1:/XAib8Ha+z6jzLRs2Pig+qxDx4C8dT8Vfaq2InJ/lkU=
|
||||
shylinux.com/x/icebergs v1.9.73/go.mod h1:3Bdp3tjzw+hUKJF+kR8pfsrbjAf72DVZmCaE8/MPFtk=
|
||||
shylinux.com/x/icebergs v1.9.75/go.mod h1:3Bdp3tjzw+hUKJF+kR8pfsrbjAf72DVZmCaE8/MPFtk=
|
||||
shylinux.com/x/icebergs v1.9.76 h1:SHOTbiO+jh09GEFzoo8t8kmR1BCu+zkNCpdfxPCLeu0=
|
||||
shylinux.com/x/icebergs v1.9.76/go.mod h1:3Bdp3tjzw+hUKJF+kR8pfsrbjAf72DVZmCaE8/MPFtk=
|
||||
shylinux.com/x/mysql-story v0.6.32 h1:Q274WFJ09ocnf8nhlQnKr02FMMdPYBLWqu2IjTVqGiM=
|
||||
shylinux.com/x/mysql-story v0.6.32/go.mod h1:8HCeDUV6ghaIeJD1IEhSeSOfVC9wEI93y2G9QBLtJJY=
|
||||
shylinux.com/x/toolkits v0.7.10/go.mod h1:CHDJarGlDkg60kVsvMLYL/a5hAnRLEOShiEsMOuEp0Q=
|
||||
shylinux.com/x/toolkits v1.0.18 h1:jtQZhmvU10Ajegc87tU0cYFUBSviaODo5TsCXpYb2O4=
|
||||
shylinux.com/x/toolkits v1.0.18/go.mod h1:CHDJarGlDkg60kVsvMLYL/a5hAnRLEOShiEsMOuEp0Q=
|
||||
shylinux.com/x/toolkits v1.0.19 h1:Nrx0xYRc5ph1WS66EZ1hJUCe+2FdSWQ4QP6tBlguikQ=
|
||||
shylinux.com/x/toolkits v1.0.19/go.mod h1:CHDJarGlDkg60kVsvMLYL/a5hAnRLEOShiEsMOuEp0Q=
|
||||
shylinux.com/x/websocket v0.0.4 h1:AJpwblePoOpiE6C8NrvgNYpKTotXMLrDDX2chTvx44Q=
|
||||
shylinux.com/x/websocket v0.0.4/go.mod h1:3UGWkjTu3ie5NAZen7J+uLPBrO7DFeKloj6Jxo13Oiw=
|
||||
|
11
src/document/index.shy
Normal file
11
src/document/index.shy
Normal file
@ -0,0 +1,11 @@
|
||||
navmenu `
|
||||
"{{ .Title }}" /
|
||||
_
|
||||
"下 载" download/
|
||||
"文 档" started/
|
||||
"开 发" development/
|
||||
_
|
||||
"应 用" "https://web.shylinux.com/s/20240903-operation"
|
||||
"源 码" "https://git.shylinux.com/web/operation"
|
||||
"社 区" "https://bbs.shylinux.com"
|
||||
`
|
103
src/operation/cluster.go
Normal file
103
src/operation/cluster.go
Normal file
@ -0,0 +1,103 @@
|
||||
package operation
|
||||
|
||||
import (
|
||||
"shylinux.com/x/ice"
|
||||
"shylinux.com/x/icebergs/base/web"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
|
||||
"2025-dev.shylinux.com/x/20250215-cluster/src/travel"
|
||||
"shylinux.com/x/operation/src/operation/model"
|
||||
)
|
||||
|
||||
type Cluster struct {
|
||||
Table
|
||||
travel travel.Travel
|
||||
order string `data:"1"`
|
||||
fields string `data:"title,content,space,total,stock,price,cluster_status"`
|
||||
payfor string `name:"payfor" help:"购买" style:"notice" role:"leader"`
|
||||
modify string `name:"modify title content price" style:"danger"`
|
||||
}
|
||||
|
||||
func (s Cluster) Scan(m *ice.Message, arg ...string) {
|
||||
m.Cmd(s.travel, s.travel.Concurrent, ice.GetTypeMod(s.travel), ice.GetTypeKey(s.travel)).Table(func(value ice.Maps) {
|
||||
s.InsertIfNeed(m, web.SPACE, value[web.SPACE])
|
||||
})
|
||||
m.Cmd("").Table(func(value ice.Maps) { s.ScanService(m.Options(value)) })
|
||||
m.ProcessRefresh()
|
||||
}
|
||||
func (s Cluster) List(m *ice.Message, arg ...string) {
|
||||
if len(arg) < 2 {
|
||||
if m.IsTech() {
|
||||
s.Select(m)
|
||||
} else {
|
||||
s.Select(m, model.STATUS, kit.Format(ClusterOnline))
|
||||
}
|
||||
} else {
|
||||
s.SelectDetail(m, model.UID, arg[1])
|
||||
}
|
||||
if m.Length() == 0 {
|
||||
if m.IsTech() {
|
||||
m.EchoInfoButton("请扫描集群", s.Scan)
|
||||
} else {
|
||||
m.Echo("请联系「平台管理员」部署集群").Action()
|
||||
}
|
||||
} else {
|
||||
if m.Display(""); m.IsTech() {
|
||||
m.Table(func(value ice.Maps) {
|
||||
if ClusterStatus(kit.Int(value[model.CLUSTER_STATUS])) == ClusterOnline && kit.Int(value[model.STOCK]) > 0 {
|
||||
m.PushButton(s.Payfor, s.ScanService, s.Offline, s.Modify)
|
||||
} else {
|
||||
m.PushButton(s.ScanService, s.Online, s.Modify)
|
||||
}
|
||||
}).Action(s.Scan)
|
||||
} else if s.IsLeader(m) {
|
||||
m.Table(func(value ice.Maps) {
|
||||
if ClusterStatus(kit.Int(value[model.CLUSTER_STATUS])) == ClusterOnline && kit.Int(value[model.STOCK]) > 0 {
|
||||
m.PushButton(s.Payfor)
|
||||
} else {
|
||||
m.PushButton()
|
||||
}
|
||||
}).Action()
|
||||
} else {
|
||||
m.PushAction().Action()
|
||||
}
|
||||
}
|
||||
if len(arg) == 2 && m.IsTech() {
|
||||
m.EchoIFrame(web.S(m.Append(web.SPACE)))
|
||||
}
|
||||
}
|
||||
func (s Cluster) Payfor(m *ice.Message, arg ...string) {
|
||||
m.Cmdy(Gateway{}, s.Payfor, arg, kit.Dict(model.CLUSTER_UID, m.Option(model.UID)))
|
||||
}
|
||||
func (s Cluster) ScanService(m *ice.Message, arg ...string) {
|
||||
m.Cmdy(Gateway{}, s.Scan, arg, kit.Dict(model.CLUSTER_UID, m.Option(model.UID))).ProcessRefresh()
|
||||
s.Update(m, m.AppendSimple(model.TOTAL, model.STOCK), m.OptionSimple(model.UID)...)
|
||||
}
|
||||
func (s Cluster) Offline(m *ice.Message, arg ...string) {
|
||||
s.Update(m, []string{model.STATUS, kit.Format(ClusterOffline)})
|
||||
s.RecordEventWithName(m, "")
|
||||
}
|
||||
func (s Cluster) Online(m *ice.Message, arg ...string) {
|
||||
s.Update(m, []string{model.STATUS, kit.Format(ClusterOnline)})
|
||||
s.RecordEventWithName(m, "")
|
||||
}
|
||||
func (s Cluster) Modify(m *ice.Message, arg ...string) {
|
||||
s.Update(m, s.TransPrice(m, arg))
|
||||
s.RecordEventWithName(m, "")
|
||||
}
|
||||
|
||||
func init() { ice.TeamCtxCmd(Cluster{}) }
|
||||
|
||||
type ClusterStatus int
|
||||
|
||||
const (
|
||||
ClusterOffline ClusterStatus = iota
|
||||
ClusterOnline
|
||||
)
|
||||
|
||||
var ClusterStatusList = map[ClusterStatus]string{
|
||||
ClusterOffline: "offline",
|
||||
ClusterOnline: "online",
|
||||
}
|
||||
|
||||
func (s ClusterStatus) String() string { return ClusterStatusList[s] }
|
9
src/operation/cluster.js
Normal file
9
src/operation/cluster.js
Normal file
@ -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.space, value.price+" 元/月", can.onimport.titleAction(can, value)]},
|
||||
{view: html.STATUS, list: [value.uid.slice(0, 6), can.onimport.timeView(can, value)]},
|
||||
{view: html.OUTPUT, list: [value.content]},
|
||||
] })
|
||||
},
|
||||
})
|
@ -20,6 +20,10 @@ func (s Table) Inputs(m *ice.Message, arg ...string) {
|
||||
s.InputsListRole(m, UserCloudRoleList, arg...)
|
||||
case model.CLOUD_TYPE:
|
||||
s.InputsList(m, CloudTypeList, arg...)
|
||||
case model.GATEWAY_UID:
|
||||
m.Cmdy(Gateway{}, m.Option(model.CLOUD_UID)).Cut(model.UID, model.TITLE)
|
||||
m.RenameAppend(model.UID, arg[0], model.TITLE, model.NAME)
|
||||
m.DisplayInputKeyNameIconTitle()
|
||||
default:
|
||||
s.Table.Inputs(m, arg...)
|
||||
}
|
||||
@ -31,6 +35,12 @@ func (s Table) RewriteAppend(m *ice.Message, arg ...string) *ice.Message {
|
||||
value = UserCloudRole(kit.Int(value)).String()
|
||||
case model.CLOUD_TYPE:
|
||||
value = CloudType(kit.Int(value)).String()
|
||||
case model.CLUSTER_STATUS:
|
||||
value = ClusterStatus(kit.Int(value)).String()
|
||||
case model.TEMPLATE_STATUS:
|
||||
value = TemplateStatus(kit.Int(value)).String()
|
||||
case model.PRICE:
|
||||
value = kit.Format("%.2f", kit.Float(value)/100)
|
||||
}
|
||||
return value
|
||||
})
|
||||
|
@ -1,3 +0,0 @@
|
||||
$output div.code {
|
||||
padding:0;
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
package operation
|
||||
|
||||
import (
|
||||
"shylinux.com/x/ice"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"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/model"
|
||||
)
|
||||
|
||||
type container struct {
|
||||
ice.Space
|
||||
Table
|
||||
order string `data:"1"`
|
||||
fields string `data:"space,name"`
|
||||
foreach string `name:"foreach" help:"遍历" icon:"bi bi-card-list"`
|
||||
create string `name:"create uid* domain module version" role:"leader"`
|
||||
remove string `name:"remove" role:"leader"`
|
||||
apply string `name:"apply" role:"void"`
|
||||
rename string `name:"rename name" role:"void"`
|
||||
open string `name:"open" role:"void"`
|
||||
}
|
||||
|
||||
func (s container) Inputs(m *ice.Message, arg ...string) {
|
||||
switch arg[0] {
|
||||
case model.UID:
|
||||
m.Cmdy(web.SPACE, ice.OPS, web.DREAM, web.SERVER, mdb.NAME, nfs.MODULE, nfs.VERSION)
|
||||
default:
|
||||
s.Table.Inputs(m, arg...)
|
||||
}
|
||||
}
|
||||
func (s container) Foreach(m *ice.Message, arg ...string) {
|
||||
m.Cmdy(web.SPACE, "20250211-service", "web.chat.dev.service.gateway", m.ActionKey()).Table(func(value ice.Maps) {
|
||||
if s.Select(m.Spawn(), web.SPACE, value[web.SPACE]).Length() == 0 {
|
||||
s.Insert(m, web.SPACE, value[web.SPACE])
|
||||
}
|
||||
})
|
||||
}
|
||||
func (s container) Create(m *ice.Message, arg ...string) {
|
||||
s.Table.Insert(m, kit.Simple(arg, m.OptionSimple(model.CLOUD_UID))...)
|
||||
}
|
||||
func (s container) Rename(m *ice.Message, arg ...string) {
|
||||
s.Table.Update(m, m.OptionSimple(model.NAME), m.OptionSimple(model.CLOUD_UID, model.UID)...)
|
||||
}
|
||||
func (s container) List(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 1 {
|
||||
s.Select(m, model.CLOUD_UID, arg[0], model.USER_UID, m.Option(model.USER_UID)).PushAction(s.Open, s.Rename)
|
||||
kit.If(m.Length() == 0, func() { m.EchoInfoButton("请申请云主机", s.Apply) })
|
||||
if m.IsTech() {
|
||||
m.Action(s.Foreach, s.Create, s.Apply)
|
||||
} else if s.IsLeader(m) {
|
||||
m.Action(s.Create, s.Apply)
|
||||
} else if m.Length() > 0 {
|
||||
m.Action()
|
||||
}
|
||||
} else {
|
||||
s.SelectDetail(m, model.UID, arg[1], model.CLOUD_UID, arg[0], model.USER_UID, m.Option(model.USER_UID)).PushAction(s.Open, s.Rename)
|
||||
m.EchoIFrame(web.S(m.Append(web.SPACE)))
|
||||
}
|
||||
m.Display("").DisplayCSS("")
|
||||
}
|
||||
func (s container) Apply(m *ice.Message, arg ...string) {
|
||||
s.Transaction(m, func() {
|
||||
msg := m.Spawn()
|
||||
msg = s.Limit(msg, 1).SelectForUpdate(msg, "(user_uid IS NULL OR user_uid = '') AND (cloud_uid = ? OR cloud_uid IS NULL OR cloud_uid = '')", m.Option(model.CLOUD_UID))
|
||||
if msg.Length() == 0 {
|
||||
m.Echo("主机不够用啦!请等待管理员添加。")
|
||||
return
|
||||
}
|
||||
s.Update(m, m.OptionSimple(model.CLOUD_UID, model.USER_UID), msg.AppendSimple(model.UID)...)
|
||||
m.Cmd(web.SPACE, msg.Append(web.SPACE), aaa.USER, mdb.CREATE, aaa.TECH, m.Option(model.USER_UID), kit.Dict(ice.MSG_USERROLE, aaa.TECH))
|
||||
})
|
||||
}
|
||||
func (s container) Open(m *ice.Message, arg ...string) {
|
||||
m.ProcessOpen(m.Options(ice.MSG_USERPOD, "").MergePod(m.Option(web.SPACE)))
|
||||
}
|
||||
|
||||
func init() { ice.TeamCtxCmd(container{}) }
|
@ -1,9 +0,0 @@
|
||||
Volcanos(chat.ONIMPORT, {
|
||||
_init: function(can, msg) {
|
||||
can.onimport.myView(can, msg, function(value) { return [
|
||||
{view: html.TITLE, list: [value.name||"container", can.onimport.titleAction(can, value)]},
|
||||
{view: html.STATUS, list: [value.uid && value.uid.slice(0, 6), can.onimport.timeView(can, value), value.user_name]},
|
||||
{view: html.STATUS, list: [value.space]},
|
||||
] })
|
||||
},
|
||||
})
|
89
src/operation/gateway.go
Normal file
89
src/operation/gateway.go
Normal file
@ -0,0 +1,89 @@
|
||||
package operation
|
||||
|
||||
import (
|
||||
"shylinux.com/x/ice"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/web"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
|
||||
"2025-dev.shylinux.com/x/20250211-service/src/gateway"
|
||||
"2025-dev.shylinux.com/x/20250215-cluster/src/travel"
|
||||
"shylinux.com/x/operation/src/operation/model"
|
||||
)
|
||||
|
||||
type Gateway struct {
|
||||
Table
|
||||
cluster Cluster
|
||||
travel travel.Travel
|
||||
gateway gateway.Gateway
|
||||
order string `data:"3"`
|
||||
fields string `data:"title,content,space,cluster_uid,user_uid"`
|
||||
payfor string `name:"payfor" help:"购买" style:"notice" role:"leader"`
|
||||
createProject string `name:"createProject name* repos binary" help:"创建" style:"notice" role:"worker"`
|
||||
scanProject string `name:"scanProject" help:"扫描" role:"worker"`
|
||||
open string `name:"open" role:"leader"`
|
||||
modify string `name:"modify title content" style:"danger" role:"leader"`
|
||||
}
|
||||
|
||||
func (s Gateway) List(m *ice.Message, arg ...string) {
|
||||
if s.ValueList(m, arg); s.IsLeader(m) {
|
||||
m.PushAction(s.CreateProject, s.ScanProject, s.Open, s.Modify)
|
||||
} else {
|
||||
m.PushAction()
|
||||
}
|
||||
if m.Action(); m.Length() == 0 {
|
||||
if m.SetResult(); s.IsLeader(m) {
|
||||
m.Echo("请到「云集群」购买主机")
|
||||
} else if s.IsWorker(m) {
|
||||
m.Echo("请联系「管理员」购买主机")
|
||||
} else {
|
||||
m.Echo("请等待「管理员」购买主机")
|
||||
}
|
||||
} else {
|
||||
s.Fields(m, model.UID, s.KeyAS(s.cluster, model.SPACE)).SelectJoin(m, s.cluster, s.Keys(s.cluster, model.SPACE)).Display("")
|
||||
}
|
||||
if len(arg) == 2 && s.IsLeader(m) {
|
||||
m.EchoIFrame(web.S(s.space(m.Spawn().Options(model.CLOUD_UID, arg[0], model.UID, arg[1]))))
|
||||
}
|
||||
}
|
||||
func (s Gateway) CreateProject(m *ice.Message, arg ...string) {
|
||||
m.Cmdy(project{}, s.Create, arg, model.GATEWAY_UID, m.Option(model.UID), kit.Dict(web.SPACE, s.space(m.Spawn()))).ProcessRefresh()
|
||||
}
|
||||
func (s Gateway) ScanProject(m *ice.Message, arg ...string) {
|
||||
m.Cmdy(project{}, s.Scan, kit.Dict(model.GATEWAY_UID, m.Option(model.UID), web.SPACE, s.space(m.Spawn()))).ProcessRefresh()
|
||||
}
|
||||
func (s Gateway) Open(m *ice.Message, arg ...string) {
|
||||
m.ProcessOpen(m.Options(ice.MSG_USERPOD, "").MergePodCmd(s.space(m.Spawn()), web.ADMIN))
|
||||
}
|
||||
func (s Gateway) Modify(m *ice.Message, arg ...string) {
|
||||
s.Update(m, arg, m.OptionSimple(model.CLOUD_UID, model.UID)...)
|
||||
s.RecordEventWithName(m, "")
|
||||
}
|
||||
|
||||
func init() { ice.TeamCtxCmd(Gateway{}) }
|
||||
|
||||
func (s Gateway) Payfor(m *ice.Message, arg ...string) {
|
||||
s.Transaction(m, func() {
|
||||
msg := m.Spawn()
|
||||
if msg = s.Orders(msg, mdb.ID).Limit(msg, 1).SelectForUpdate(msg, "cluster_uid = ? AND (cloud_uid IS NULL OR cloud_uid = '')", m.Option(model.CLUSTER_UID)); msg.Length() == 0 {
|
||||
m.Echo("主机不够用啦!请等待平台管理员添加。")
|
||||
} else {
|
||||
m.Option(model.TITLE, "我的云主机")
|
||||
s.Update(m, m.OptionSimple(model.CLOUD_UID, model.USER_UID, model.TITLE), msg.AppendSimple(model.UID)...)
|
||||
s.RecordEventWithName(m.Options(model.UID, msg.Append(model.UID)), "")
|
||||
s.SendMessage(s.GetCommandUID(m), "", "")
|
||||
}
|
||||
})
|
||||
}
|
||||
func (s Gateway) Scan(m *ice.Message, arg ...string) {
|
||||
m.Cmd(web.SPACE, m.Option(web.SPACE), s.travel, s.travel.Concurrent, ice.GetTypeMod(s.gateway), ice.GetTypeKey(s.gateway)).Table(func(value ice.Maps) {
|
||||
s.InsertIfNeed(m, web.SPACE, value[web.SPACE], model.CLUSTER_UID, m.Option(model.CLUSTER_UID))
|
||||
})
|
||||
s.Fields(m, "count(*) AS total").Select(m, model.CLUSTER_UID, m.Option(model.CLUSTER_UID))
|
||||
s.Fields(m, "count(*) AS stock").Select(m, "cluster_uid = ? AND (cloud_uid IS NULL OR cloud_uid = '')", m.Option(model.CLUSTER_UID))
|
||||
}
|
||||
func (s Gateway) space(m *ice.Message, arg ...string) string {
|
||||
s.Tables(m, s.cluster).Fields(m, s.Key(s, web.SPACE), s.KeyAS(s.cluster, web.SPACE))
|
||||
s.Select(m, kit.Simple(m.OptionSimple(model.CLOUD_UID), s.Key(s, model.UID), m.Option(model.UID))...)
|
||||
return kit.Keys(m.Append(model.CLUSTER_SPACE), m.Append(web.SPACE))
|
||||
}
|
@ -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]},
|
||||
{view: html.TITLE, list: [value.title||value.space, 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]},
|
||||
] })
|
@ -7,13 +7,26 @@ const (
|
||||
NAME = "name"
|
||||
INFO = "info"
|
||||
TYPE = "type"
|
||||
ROLE = "role"
|
||||
STATUS = "status"
|
||||
TOTAL = "total"
|
||||
STOCK = "stock"
|
||||
PRICE = "price"
|
||||
SPACE = "space"
|
||||
TITLE = "title"
|
||||
CONTENT = "content"
|
||||
USER_UID = "user_uid"
|
||||
USER_CLOUD_ROLE = "user_cloud_role"
|
||||
CLOUD_UID = "cloud_uid"
|
||||
CLOUD_TYPE = "cloud_type"
|
||||
RELEASE_UID = "release_uid"
|
||||
CLUSTER_UID = "cluster_uid"
|
||||
CLUSTER_SPACE = "cluster_space"
|
||||
CLUSTER_STATUS = "cluster_status"
|
||||
TEMPLATE_STATUS = "template_status"
|
||||
GATEWAY_UID = "gateway_uid"
|
||||
GATEWAY_SPACE = "gateway_space"
|
||||
PROJECT_UID = "project_uid"
|
||||
PROJECT_NAME = "project_name"
|
||||
)
|
||||
|
||||
type UserCloud struct {
|
||||
@ -24,16 +37,44 @@ type Cloud struct {
|
||||
db.ModelPlace
|
||||
CompanyUID string `gorm:"type:char(32);index"`
|
||||
}
|
||||
type Release struct {
|
||||
type Cluster struct {
|
||||
db.ModelContent
|
||||
CloudUID string `gorm:"type:char(32);index"`
|
||||
Space string `gorm:"type:varchar(64);index"`
|
||||
Total int `gorm:"default:0"`
|
||||
Stock int `gorm:"default:0"`
|
||||
Price int `gorm:"default:0"`
|
||||
Status uint8 `gorm:"default:0"`
|
||||
}
|
||||
type Container struct {
|
||||
db.ModelWithUID
|
||||
CloudUID string `gorm:"type:char(32);index"`
|
||||
UserUID string `gorm:"type:char(32);index"`
|
||||
Space string `gorm:"type:char(128);uniqueIndex"`
|
||||
Name string `gorm:"type:char(64)"`
|
||||
type Template struct {
|
||||
db.ModelNameInfo
|
||||
Title string `gorm:"type:varchar(64)"`
|
||||
Icons string `gorm:"type:varchar(255)"`
|
||||
Repos string `gorm:"type:varchar(255)"`
|
||||
Binary string `gorm:"type:varchar(255)"`
|
||||
Status uint8 `gorm:"default:0"`
|
||||
}
|
||||
type Gateway struct {
|
||||
db.ModelContent
|
||||
Space string `gorm:"type:varchar(64)"`
|
||||
CloudUID string `gorm:"type:char(32);index"`
|
||||
ClusterUID string `gorm:"type:char(32);index"`
|
||||
}
|
||||
type Project struct {
|
||||
db.ModelNameInfo
|
||||
Icons string `gorm:"type:varchar(255)"`
|
||||
Repos string `gorm:"type:varchar(255)"`
|
||||
Binary string `gorm:"type:varchar(255)"`
|
||||
CloudUID string `gorm:"type:char(32);index"`
|
||||
GatewayUID string `gorm:"type:char(32);index"`
|
||||
}
|
||||
type Product struct {
|
||||
db.ModelNameInfo
|
||||
Icon string `gorm:"type:varchar(255)"`
|
||||
Index string `gorm:"type:varchar(128)"`
|
||||
CloudUID string `gorm:"type:char(32);index"`
|
||||
ProjectUID string `gorm:"type:char(32);index"`
|
||||
}
|
||||
|
||||
func init() { db.CmdModels("", &UserCloud{}, &Cloud{}, &Release{}, &Container{}) }
|
||||
func init() {
|
||||
db.CmdModels("", &UserCloud{}, &Cloud{}, &Cluster{}, &Gateway{}, &Template{}, &Project{}, &Product{})
|
||||
}
|
||||
|
@ -1,16 +1,31 @@
|
||||
{
|
||||
"portal": "系统运维",
|
||||
"container": "云主机",
|
||||
"release": "发布",
|
||||
"cluster": "云集群", "gateway": "云主机", "template": "云模板", "project": "云项目", "product": "云服务",
|
||||
"scanService": "扫描", "offline": "下架", "online": "上架",
|
||||
"style": {
|
||||
"offline": "danger"
|
||||
},
|
||||
"icons": {
|
||||
"container": "https://img.icons8.com/officel/80/activity-grid.png",
|
||||
"release": "https://img.icons8.com/officel/80/activity-grid.png"
|
||||
"cluster": "activity-grid.png",
|
||||
"gateway": "activity-grid.png",
|
||||
"template": "activity-grid.png",
|
||||
"project": "activity-grid.png",
|
||||
"product": "activity-grid.png"
|
||||
},
|
||||
"input": {
|
||||
"My Cloud": "我的系统",
|
||||
"user_cloud_role": "用户角色",
|
||||
"cloud_name": "系统名称",
|
||||
"cloud_type": "系统类型"
|
||||
"cloud_type": "系统类型",
|
||||
"cloud_space": "集群空间",
|
||||
"cluster_status": "集群状态",
|
||||
"cluster_space": "集群空间",
|
||||
"template_status": "模板状态",
|
||||
"gateway_uid": "云主机",
|
||||
"gateway_title": "云主机",
|
||||
"gateway_space": "主机空间",
|
||||
"project_name": "项目名称",
|
||||
"stock": "库存"
|
||||
},
|
||||
"value": {
|
||||
"user_cloud_role": {
|
||||
|
59
src/operation/product.go
Normal file
59
src/operation/product.go
Normal file
@ -0,0 +1,59 @@
|
||||
package operation
|
||||
|
||||
import (
|
||||
"shylinux.com/x/ice"
|
||||
"shylinux.com/x/icebergs/base/ctx"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/web"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
|
||||
"shylinux.com/x/community/src/api"
|
||||
"shylinux.com/x/operation/src/operation/model"
|
||||
)
|
||||
|
||||
type product struct {
|
||||
Table
|
||||
cluster Cluster
|
||||
gateway Gateway
|
||||
project project
|
||||
order string `data:"5"`
|
||||
fields string `data:"name,icon,index,project_uid"`
|
||||
open string `name:"open" style:"notice" role:"void"`
|
||||
}
|
||||
|
||||
func (s product) Scan(m *ice.Message, arg ...string) {
|
||||
m.Cmd(web.SPACE, m.Option(web.SPACE), api.GONGANXITONG_PORTAL)
|
||||
m.Cmd(web.SPACE, m.Option(web.SPACE), api.GONGANXITONG_SERVICE).Table(func(value ice.Maps) {
|
||||
s.InsertIfNeed(m.Options(ctx.INDEX, value[ctx.INDEX]), m.OptionSimple(model.CLOUD_UID, model.PROJECT_UID, ctx.INDEX)...)
|
||||
s.Update(m, kit.Dict(mdb.NAME, value[mdb.NAME], mdb.ICON, value[mdb.ICON]), m.OptionSimple(model.CLOUD_UID, model.PROJECT_UID, ctx.INDEX)...)
|
||||
})
|
||||
}
|
||||
func (s product) List(m *ice.Message, arg ...string) {
|
||||
if s.ValueList(m, arg); s.IsLeader(m) {
|
||||
m.PushAction(s.Open, s.Remove)
|
||||
} else {
|
||||
m.PushAction(s.Open)
|
||||
}
|
||||
if m.Length() == 0 {
|
||||
m.SetResult().Echo("请到「云项目」扫描服务")
|
||||
} else {
|
||||
m.Display("")
|
||||
}
|
||||
s.Fields(m, model.UID, s.Keys(s.gateway, model.UID), s.KeyAS(s.project, mdb.NAME)).SelectJoin(m, s.project, s.Keys(s.project, mdb.NAME), s.Keys(s.gateway, model.UID))
|
||||
s.Fields(m, model.UID, s.Keys(s.cluster, model.UID), s.KeyAS(s.gateway, model.TITLE), s.KeyAS(s.gateway, model.SPACE)).SelectJoin(m, s.gateway, s.Keys(s.cluster, model.UID), s.Keys(s.gateway, model.SPACE), s.Keys(s.gateway, model.TITLE))
|
||||
s.Fields(m, model.UID, s.KeyAS(s.cluster, model.SPACE)).SelectJoin(m, s.cluster, s.Keys(s.cluster, model.SPACE))
|
||||
if len(arg) == 2 {
|
||||
m.EchoIFrame(web.S(kit.Keys(m.Append(model.CLUSTER_SPACE), m.Append(model.GATEWAY_SPACE), m.Append(model.PROJECT_NAME))))
|
||||
}
|
||||
}
|
||||
func (s product) Open(m *ice.Message, arg ...string) {
|
||||
m.ProcessOpen(m.Options(ice.MSG_USERPOD, "").MergePodCmd(s.space(m.Spawn()), m.Option(ctx.INDEX)))
|
||||
}
|
||||
|
||||
func init() { ice.TeamCtxCmd(product{}) }
|
||||
|
||||
func (s product) space(m *ice.Message, arg ...string) string {
|
||||
s.Tables(m, s.project, s.gateway, s.cluster).Fields(m, s.Key(s.project, mdb.NAME), s.KeyAS(s.gateway, web.SPACE), s.KeyAS(s.cluster, web.SPACE))
|
||||
s.Select(m, kit.Simple(s.Key(s, model.CLOUD_UID), m.Option(model.CLOUD_UID), s.Key(s, model.UID), m.Option(model.UID))...)
|
||||
return kit.Keys(m.Append(model.CLUSTER_SPACE), m.Append(model.GATEWAY_SPACE), m.Append(mdb.NAME))
|
||||
}
|
12
src/operation/product.js
Normal file
12
src/operation/product.js
Normal file
@ -0,0 +1,12 @@
|
||||
Volcanos(chat.ONIMPORT, {
|
||||
_init: function(can, msg) {
|
||||
can.onimport.myView(can, msg, function(value) {
|
||||
value.icon = can.misc.ResourceIcons(can, value.icon, can.core.Keys(value.cluster_space, value.gateway_space, value.project_name))
|
||||
return [
|
||||
{view: html.TITLE, list: [value.name, can.onimport.titleAction(can, value)]},
|
||||
{view: html.STATUS, list: [value.uid.slice(0, 6), can.onimport.timeView(can, value), value.gateway_title]},
|
||||
{view: html.OUTPUT, list: [value.info]},
|
||||
]
|
||||
})
|
||||
},
|
||||
})
|
75
src/operation/project.go
Normal file
75
src/operation/project.go
Normal file
@ -0,0 +1,75 @@
|
||||
package operation
|
||||
|
||||
import (
|
||||
"shylinux.com/x/ice"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"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/model"
|
||||
)
|
||||
|
||||
type project struct {
|
||||
Table
|
||||
cluster Cluster
|
||||
gateway Gateway
|
||||
order string `data:"4"`
|
||||
fields string `data:"name,icons,repos,binary,gateway_uid"`
|
||||
create string `name:"create name* icons repos binary" style:"notice" role:"worker"`
|
||||
scanProduct string `name:"scanProduct" help:"扫描" role:"worker"`
|
||||
open string `name:"open" role:"worker"`
|
||||
}
|
||||
|
||||
func (s project) Create(m *ice.Message, arg ...string) {
|
||||
if s.Select(m.Spawn(), m.OptionSimple(model.CLOUD_UID, model.GATEWAY_UID, mdb.NAME)...).Length() > 0 {
|
||||
return
|
||||
}
|
||||
msg := m.Cmd(web.SPACE, m.Option(web.SPACE), web.DREAM, mdb.CREATE, arg, kit.Dict(ice.MSG_USERROLE, aaa.TECH))
|
||||
s.Insert(m, kit.Simple(arg, msg.OptionSimple(model.CLOUD_UID, model.GATEWAY_UID, mdb.NAME))...)
|
||||
s.SendMessage(s.GetCommandUID(m), "", "", m.Option(model.CLOUD_UID), m.Result())
|
||||
s.RecordEventWithName(m, "")
|
||||
}
|
||||
func (s project) Scan(m *ice.Message, arg ...string) {
|
||||
m.Cmd(web.SPACE, m.Option(web.SPACE), web.DREAM).Table(func(value ice.Maps) {
|
||||
if m.Option(mdb.NAME, value[mdb.NAME]); value[mdb.TYPE] == web.WORKER {
|
||||
s.InsertIfNeed(m, m.OptionSimple(model.CLOUD_UID, model.GATEWAY_UID, mdb.NAME)...)
|
||||
}
|
||||
s.Update(m, kit.Dict(nfs.REPOS, value[nfs.REPOS], nfs.BINARY, value[nfs.BINARY]), m.OptionSimple(model.CLOUD_UID, model.GATEWAY_UID, mdb.NAME)...)
|
||||
})
|
||||
}
|
||||
func (s project) List(m *ice.Message, arg ...string) {
|
||||
if s.ValueList(m, arg); s.IsLeader(m) {
|
||||
m.PushAction(s.ScanProduct, s.Open, s.Remove)
|
||||
} else if s.IsWorker(m) {
|
||||
m.PushAction(s.ScanProduct, s.Open)
|
||||
} else {
|
||||
m.PushAction()
|
||||
}
|
||||
if m.Action(); m.Length() == 0 {
|
||||
m.SetResult().Echo("请到「云主机」创建项目")
|
||||
} else {
|
||||
s.Fields(m, model.UID, s.KeyAS(s.gateway, model.TITLE), s.KeyAS(s.gateway, model.SPACE), s.Keys(s.cluster, model.UID))
|
||||
s.SelectJoin(m, s.gateway, s.Keys(s.gateway, model.TITLE), s.Keys(s.gateway, model.SPACE), s.Keys(s.cluster, model.UID))
|
||||
s.Fields(m, model.UID, s.KeyAS(s.cluster, model.SPACE)).SelectJoin(m, s.cluster, s.Keys(s.cluster, model.SPACE))
|
||||
m.Display("")
|
||||
}
|
||||
if len(arg) == 2 && s.IsWorker(m) {
|
||||
m.EchoIFrame(web.S(s.space(m.Spawn().Options(model.CLOUD_UID, arg[0], model.UID, arg[1]))))
|
||||
}
|
||||
}
|
||||
func (s project) ScanProduct(m *ice.Message, arg ...string) {
|
||||
m.Cmdy(product{}, s.Scan, kit.Dict(model.PROJECT_UID, m.Option(model.UID), web.SPACE, s.space(m))).ProcessRefresh()
|
||||
}
|
||||
func (s project) Open(m *ice.Message, arg ...string) {
|
||||
m.ProcessOpen(m.Options(ice.MSG_USERPOD, "").MergePodCmd(s.space(m), web.ADMIN))
|
||||
}
|
||||
|
||||
func init() { ice.TeamCtxCmd(project{}) }
|
||||
|
||||
func (s project) space(m *ice.Message, arg ...string) string {
|
||||
s.Tables(m, s.gateway, s.cluster).Fields(m, s.Key(s, mdb.NAME), s.KeyAS(s.gateway, web.SPACE), s.KeyAS(s.cluster, web.SPACE))
|
||||
s.Select(m, kit.Simple(s.Key(s, model.CLOUD_UID), m.Option(model.CLOUD_UID), s.Key(s, model.UID), m.Option(model.UID))...)
|
||||
return kit.Keys(m.Append(model.CLUSTER_SPACE), m.Append(model.GATEWAY_SPACE), m.Append(mdb.NAME))
|
||||
}
|
9
src/operation/project.js
Normal file
9
src/operation/project.js
Normal file
@ -0,0 +1,9 @@
|
||||
Volcanos(chat.ONIMPORT, {
|
||||
_init: function(can, msg) {
|
||||
can.onimport.myView(can, msg, function(value) { return [
|
||||
{view: html.TITLE, list: [value.name, can.onimport.titleAction(can, value)]},
|
||||
{view: html.STATUS, list: [value.uid.slice(0, 6), can.onimport.timeView(can, value), value.gateway_title]},
|
||||
{view: html.OUTPUT, list: [value.binary||value.repos]},
|
||||
] })
|
||||
},
|
||||
})
|
@ -1,16 +0,0 @@
|
||||
package operation
|
||||
|
||||
import "shylinux.com/x/ice"
|
||||
|
||||
type release struct {
|
||||
Table
|
||||
fields string `data:"title,content,user_uid"`
|
||||
create string `name:"create title* content*" role:"leader"`
|
||||
remove string `name:"remove" role:"leader"`
|
||||
}
|
||||
|
||||
func (s release) List(m *ice.Message, arg ...string) {
|
||||
s.ValueList(m, arg).Display("")
|
||||
}
|
||||
|
||||
func init() { ice.TeamCtxCmd(release{}) }
|
56
src/operation/studio.go
Normal file
56
src/operation/studio.go
Normal file
@ -0,0 +1,56 @@
|
||||
package operation
|
||||
|
||||
import (
|
||||
"shylinux.com/x/ice"
|
||||
"shylinux.com/x/icebergs/base/aaa"
|
||||
"shylinux.com/x/icebergs/base/web"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
|
||||
"shylinux.com/x/operation/src/operation/model"
|
||||
)
|
||||
|
||||
type studio struct {
|
||||
Tables
|
||||
cluster Cluster
|
||||
list string `name:"list list"`
|
||||
gateway string `name:"gateway" role:"void"`
|
||||
project string `name:"project" role:"void"`
|
||||
product string `name:"product" role:"void"`
|
||||
}
|
||||
|
||||
func (s studio) List(m *ice.Message, arg ...string) {
|
||||
m.Cmdy(s.PrefixPortal(m)).Action().Display("").DisplayCSS("")
|
||||
}
|
||||
func (s studio) Gateway(m *ice.Message, arg ...string) {
|
||||
if len(arg) < 3 {
|
||||
m.Cmdy(m.Prefix(m.ActionKey()), arg[0])
|
||||
} else {
|
||||
m.Cmdy(web.SPACE, s.space(m, arg, model.CLUSTER_SPACE, model.SPACE), arg[2:])
|
||||
}
|
||||
}
|
||||
func (s studio) Project(m *ice.Message, arg ...string) {
|
||||
if len(arg) < 3 {
|
||||
m.Cmdy(m.Prefix(m.ActionKey()), s.Select, model.CLOUD_UID, arg[0], model.GATEWAY_UID, arg[1])
|
||||
} else {
|
||||
m.Cmdy(web.SPACE, s.space(m, arg, model.CLUSTER_SPACE, model.GATEWAY_SPACE, model.NAME), arg[2:])
|
||||
}
|
||||
}
|
||||
func (s studio) Product(m *ice.Message, arg ...string) {
|
||||
if len(arg) < 3 {
|
||||
m.Cmdy(m.Prefix(m.ActionKey()), s.Select, model.CLOUD_UID, arg[0], model.PROJECT_UID, arg[1])
|
||||
} else {
|
||||
m.Cmdy(web.SPACE, s.space(m, arg, model.CLUSTER_SPACE, model.GATEWAY_SPACE, model.PROJECT_NAME), arg[2:])
|
||||
}
|
||||
}
|
||||
|
||||
func init() { ice.TeamCtxCmd(studio{}) }
|
||||
|
||||
func (s studio) space(m *ice.Message, arg []string, args ...string) string {
|
||||
if s.UserPlaceRole(m); s.IsWorker(m) {
|
||||
m.Option(ice.MSG_USERROLE, aaa.TECH)
|
||||
}
|
||||
space := []ice.Any{}
|
||||
msg := m.Cmd(m.Prefix(m.ActionKey()), arg[0], arg[1])
|
||||
kit.For(args, func(key string) { space = append(space, msg.Append(key)) })
|
||||
return m.Option(ice.MSG_USERPOD, kit.Keys(space...))
|
||||
}
|
98
src/operation/studio.js
Normal file
98
src/operation/studio.js
Normal file
@ -0,0 +1,98 @@
|
||||
Volcanos(chat.ONIMPORT, {
|
||||
_init: function(can, msg) { can.onmotion.hidden(can, can._status)
|
||||
can.ui = can.onappend.layout(can), can.onimport.place(can, msg)
|
||||
},
|
||||
place: function(can, msg) {
|
||||
msg.Table(function(value) {
|
||||
can.onimport.item(can, {icon: "bi bi-phone", name: value.cloud_name, _hash: [value.cloud_uid.slice(0, 12)]}, function(event, item, show, target) { can.db.cloud_uid = value.cloud_uid
|
||||
show === undefined && can.runAction(event, "gateway", [value.cloud_uid], function(msg) {
|
||||
can.onimport.gateway(can, msg, target, value.cloud_uid)
|
||||
})
|
||||
return true
|
||||
}, function(event, item, target) {
|
||||
return {meta: {
|
||||
open: function() { can.user.open("/s/"+can.misc.Search(can, ice.POD)+"/c/"+"web.team.operation.portal"+"?cloud_uid="+value.cloud_uid) },
|
||||
}}
|
||||
})
|
||||
})
|
||||
},
|
||||
gateway: function(can, msg, target, cloud_uid) {
|
||||
can.onimport.itemlist(can, msg.Table(function(value) {
|
||||
return {icon: "bi bi-window-desktop", name: value.title, _hash: target._item._hash.concat([value.space.slice(0, 12)]), action: "gateway", cloud_uid: cloud_uid, uid: value.uid, space: can.core.Keys(value.cluster_space, value.space)}
|
||||
}), function(event, item, show, target) { can.db.gateway_uid = item.uid
|
||||
show === undefined && can.runAction(event, "project", [cloud_uid, item.uid], function(msg) {
|
||||
if (msg.Length() == 0) {
|
||||
can.onimport.plugin(can, item, target)
|
||||
} else {
|
||||
can.onimport.project(can, msg, target, cloud_uid)
|
||||
}
|
||||
})
|
||||
return true
|
||||
}, function(event, item, target) {
|
||||
return can.onimport.contexts(can, item, target)
|
||||
}, target)
|
||||
},
|
||||
project: function(can, msg, target, cloud_uid) {
|
||||
can.onimport.itemlist(can, msg.Table(function(value) {
|
||||
return {icon: "bi bi-window-sidebar", name: value.name, _hash: target._item._hash.concat([value.name]), action: "project", cloud_uid: cloud_uid, uid: value.uid, space: can.core.Keys(target._item.space, value.name)}
|
||||
}), function(event, item, show, target) { can.db.project_uid = item.uid
|
||||
show === undefined && can.runAction(event, "product", [cloud_uid, item.uid], function(msg) {
|
||||
if (msg.Length() == 0) {
|
||||
can.onimport.plugin(can, item, target)
|
||||
} else {
|
||||
can.onimport.product(can, msg, target, cloud_uid)
|
||||
}
|
||||
})
|
||||
return true
|
||||
}, function(event, item, target) {
|
||||
return can.onimport.contexts(can, item, target)
|
||||
}, target)
|
||||
},
|
||||
product: function(can, msg, target, cloud_uid) {
|
||||
can.onimport.itemlist(can, msg.Table(function(value) {
|
||||
return {icon: "bi bi-phone", name: value.name, _hash: target._item._hash.concat([value.index]), action: "product", cloud_uid: cloud_uid, uid: value.uid, space: target._item.space, index: value.index}
|
||||
}), function(event, item, show, target) { can.db.product_uid = item.uid
|
||||
can.onimport.plugin(can, item, target)
|
||||
}, function(event, item, target) {
|
||||
return {meta: {
|
||||
open: function() { can.user.open("/s/"+item.space+"/c/"+item.index) },
|
||||
}}
|
||||
}, target)
|
||||
},
|
||||
contexts: function(can, item, target) {
|
||||
return {meta: {
|
||||
portal: function() { can.onappend.plugin(can._root.Action, {index: web.CHAT_IFRAME, args: "/s/"+item.space+"/c/portal", style: html.FLOAT, title: item.name}) },
|
||||
desktop: function() { can.onimport.plugin(can, item, target, web.DESKTOP) },
|
||||
admin: function() { can.onappend.plugin(can._root.Action, {index: web.CHAT_IFRAME, args: "/s/"+item.space+"/c/admin", style: html.FLOAT, title: item.name}) },
|
||||
word: function() { can.onimport.plugin(can, item, target, web.WORD) },
|
||||
vimer: function() { can.onimport.plugin(can, item, target, web.VIMER) },
|
||||
runtime: function() { can.onimport.plugin(can, item, target, cli.RUNTIME) },
|
||||
xterm: function() { can.onimport.plugin(can, item, target, cli.XTERM) },
|
||||
open: function() { can.user.open("/s/"+item.space) },
|
||||
}}
|
||||
},
|
||||
plugin: function(can, item, target, index) {
|
||||
if (!index && !item.index) {
|
||||
for (var i = 0; i < item._hash.length; i++) { if (item._hash[i] != can.db.hash[i]) { break } }
|
||||
if (i == item._hash.length) { index = can.db.hash[i] }
|
||||
} if (index) { can.onexport.hash(can, item._hash.concat([index])) }
|
||||
index = index||item.index||web.DESKTOP, item.plugin = item.plugin||{}
|
||||
can.onimport.tabsCache(can, item.plugin[index] = item.plugin[index]||{name: item.name+(index == web.DESKTOP || item.index? "": "."+index), _hash: can.core.Keys(item._hash, index)}, target, function() {
|
||||
// can.onappend.plugin(can._root.Action, {space: item.space, index: index, height: can.ConfHeight(), width: can.ConfWidth()-can.ui.project.offsetWidth}, function() {}, can.ui.content)
|
||||
can.onappend.plugin(can._root.Action, {space: item.space, index: index, args: index == cli.XTERM? ["sh"]: [],
|
||||
height: can.ConfHeight(), width: can.ConfWidth()-can.ui.project.offsetWidth, style: can.base.isIn(index, cli.XTERM, web.DESKTOP)? html.OUTPUT: "",
|
||||
title: index == web.DESKTOP? item.name: "",
|
||||
}, function(sub) {
|
||||
sub.run = function(event, cmds, cb) { var msg = can.request(event); delete(msg.pod)
|
||||
can.runAction(event, item.action, [item.cloud_uid, item.uid, index].concat(cmds), cb)
|
||||
}
|
||||
can._plugins = (can._plugins||[]).concat(sub)
|
||||
}, can.ui.content)
|
||||
})
|
||||
},
|
||||
layout: function(can) {
|
||||
can.ui.layout(can.ConfHeight(), can.ConfWidth(), 0, function(height, width) {
|
||||
can.core.List(can._plugins, function(sub) { sub.onimport.size(sub, height, width) })
|
||||
})
|
||||
},
|
||||
})
|
83
src/operation/template.go
Normal file
83
src/operation/template.go
Normal file
@ -0,0 +1,83 @@
|
||||
package operation
|
||||
|
||||
import (
|
||||
"shylinux.com/x/ice"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
|
||||
"shylinux.com/x/operation/src/operation/model"
|
||||
)
|
||||
|
||||
type template struct {
|
||||
Table
|
||||
order string `data:"2"`
|
||||
fields string `data:"name,info,title,icons,repos,binary,template_status"`
|
||||
create string `name:"create name* info title icons repos* binary*"`
|
||||
modify string `name:"modify name* info title icons repos* binary*" style:"danger"`
|
||||
install string `name:"install name* gateway_uid*" style:"notice" role:"worker"`
|
||||
}
|
||||
|
||||
func (s template) Create(m *ice.Message, arg ...string) {
|
||||
s.Insert(m, arg...)
|
||||
}
|
||||
func (s template) List(m *ice.Message, arg ...string) {
|
||||
if m.IsTech() {
|
||||
if len(arg) < 2 {
|
||||
s.Select(m)
|
||||
} else {
|
||||
s.SelectDetail(m, model.UID, arg[1])
|
||||
}
|
||||
m.Table(func(value ice.Maps) {
|
||||
if TemplateStatus(kit.Int(value[model.TEMPLATE_STATUS])) == TemplateOffline {
|
||||
m.PushButton(s.Online, s.Modify)
|
||||
} else {
|
||||
m.PushButton(s.Install, s.Offline, s.Modify)
|
||||
}
|
||||
})
|
||||
if m.Length() == 0 {
|
||||
s.Button(m, "")
|
||||
}
|
||||
} else {
|
||||
if len(arg) < 2 {
|
||||
s.Select(m, model.STATUS, kit.Format(TemplateOnline))
|
||||
} else {
|
||||
s.SelectDetail(m, model.UID, arg[1])
|
||||
}
|
||||
if m.PushAction(s.Install).Action(); m.Length() == 0 {
|
||||
m.Echo("请等待「平台管理员」创建模板")
|
||||
}
|
||||
}
|
||||
m.Display("")
|
||||
}
|
||||
func (s template) Install(m *ice.Message, arg ...string) {
|
||||
msg := m.Cmd(Gateway{}, m.Option(model.CLOUD_UID), m.Option(model.GATEWAY_UID))
|
||||
m.Option(model.SPACE, kit.Keys(msg.Append(model.CLUSTER_SPACE), msg.Append(model.SPACE)))
|
||||
m.Cmdy(project{}, s.Create, m.OptionSimple("name,icons,repos,binary"))
|
||||
}
|
||||
func (s template) Offline(m *ice.Message, arg ...string) {
|
||||
s.Update(m, []string{model.STATUS, kit.Format(TemplateOffline)})
|
||||
s.RecordEventWithName(m, "")
|
||||
}
|
||||
func (s template) Online(m *ice.Message, arg ...string) {
|
||||
s.Update(m, []string{model.STATUS, kit.Format(TemplateOnline)})
|
||||
s.RecordEventWithName(m, "")
|
||||
}
|
||||
func (s template) Modify(m *ice.Message, arg ...string) {
|
||||
s.Update(m, arg)
|
||||
s.RecordEventWithName(m, "")
|
||||
}
|
||||
|
||||
func init() { ice.TeamCtxCmd(template{}) }
|
||||
|
||||
type TemplateStatus int
|
||||
|
||||
const (
|
||||
TemplateOffline TemplateStatus = iota
|
||||
TemplateOnline
|
||||
)
|
||||
|
||||
var TemplateStatusList = map[TemplateStatus]string{
|
||||
TemplateOffline: "offline",
|
||||
TemplateOnline: "online",
|
||||
}
|
||||
|
||||
func (s TemplateStatus) String() string { return TemplateStatusList[s] }
|
9
src/operation/template.js
Normal file
9
src/operation/template.js
Normal file
@ -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, can.onimport.titleAction(can, value)]},
|
||||
{view: html.STATUS, list: [value.uid.slice(0, 6), can.onimport.timeView(can, value)]},
|
||||
{view: html.OUTPUT, list: [value.info||value.binary||value.repos]},
|
||||
] })
|
||||
},
|
||||
})
|
@ -2,9 +2,5 @@ package main
|
||||
|
||||
import (
|
||||
_ "shylinux.com/x/ice/devops"
|
||||
_ "shylinux.com/x/mysql-story/src/db/mysql"
|
||||
_ "shylinux.com/x/mysql-story/src/db/sqlite"
|
||||
|
||||
_ "shylinux.com/x/community/src/renzhengshouquan"
|
||||
_ "shylinux.com/x/community/src/renzhengshouquan/external"
|
||||
_ "shylinux.com/x/ice/portal"
|
||||
)
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
|
||||
type Case struct {
|
||||
Table
|
||||
order string `data:"3"`
|
||||
order string `data:"4"`
|
||||
fields string `data:"title,content,case_status,process_time,finish_time,plan_uid,user_uid"`
|
||||
create string `name:"create title* content*" role:"leader,worker"`
|
||||
modify string `name:"modify title* content*" role:"leader,worker"`
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"portal": "产品迭代", "member": "项目成员",
|
||||
"plan": "迭代计划", "issue": "产品需求", "task": "开发任务", "case": "测试用例",
|
||||
"plan": "迭代计划", "issue": "产品需求", "design": "界面设计", "task": "开发任务", "case": "测试用例",
|
||||
"planBind": "绑定计划", "process": "开始",
|
||||
"issueCreate": "创建需求", "taskCreate": "创建任务", "caseCreate": "创建用例",
|
||||
"style": {
|
||||
@ -13,6 +13,7 @@
|
||||
"icons": {
|
||||
"plan": "https://img.icons8.com/officel/80/timeline-week.png",
|
||||
"issue": "https://img.icons8.com/officel/80/communication.png",
|
||||
"design": "https://img.icons8.com/officel/80/web-design.png",
|
||||
"task": "https://img.icons8.com/officel/80/tasks.png",
|
||||
"case": "https://img.icons8.com/officel/80/faq.png"
|
||||
},
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
type task struct {
|
||||
Table
|
||||
Case Case
|
||||
order string `data:"3"`
|
||||
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"`
|
||||
create string `name:"create title* content* begin_time:select@date end_time:select@date" role:"leader,worker"`
|
||||
modify string `name:"modify title* content* begin_time*:select@date end_time*:select@date" role:"leader,worker"`
|
||||
|
@ -1,4 +1,4 @@
|
||||
package gonganxitong
|
||||
package {{.Option "zone"}}
|
||||
|
||||
import "shylinux.com/x/ice"
|
||||
|
||||
|
@ -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||value.name||value.user_name]},
|
||||
{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]},
|
||||
] })
|
||||
|
@ -103,7 +103,7 @@
|
||||
"85e9ad5c568cceaa0aa273431f2cfcc2": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/50/documents.png",
|
||||
"icons": "https://img.icons8.com/officel/80/documents.png",
|
||||
"index": "web.team.dashboard.document",
|
||||
"name": "在线文档",
|
||||
"order": "93",
|
||||
@ -176,7 +176,7 @@
|
||||
"e3b889de9ace6b7f42008f8e0732effc": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/50/ios-photos.png",
|
||||
"icons": "https://img.icons8.com/officel/80/ios-photos.png",
|
||||
"index": "web.team.dashboard.photo",
|
||||
"name": "在线相册",
|
||||
"order": "95",
|
||||
|
@ -89,7 +89,7 @@
|
||||
"8922cdd711b3060411b079fa8f39ba72": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/50/ios-photos.png",
|
||||
"icons": "https://img.icons8.com/officel/80/ios-photos.png",
|
||||
"index": "web.team.development.photo",
|
||||
"name": "在线相册",
|
||||
"order": "95",
|
||||
@ -180,7 +180,7 @@
|
||||
"e347aded50c684b8e3118ba359a56039": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/50/documents.png",
|
||||
"icons": "https://img.icons8.com/officel/80/documents.png",
|
||||
"index": "web.team.development.document",
|
||||
"name": "在线文档",
|
||||
"order": "93",
|
||||
|
@ -21,7 +21,7 @@
|
||||
"22574299a657140d473f0216b8d83710": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/50/documents.png",
|
||||
"icons": "https://img.icons8.com/officel/80/documents.png",
|
||||
"index": "web.team.gonganxitong.document",
|
||||
"name": "在线文档",
|
||||
"order": "93",
|
||||
@ -73,7 +73,7 @@
|
||||
"882a999b4a72a9866d9e4eef110d335a": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/50/ios-photos.png",
|
||||
"icons": "https://img.icons8.com/officel/80/ios-photos.png",
|
||||
"index": "web.team.gonganxitong.photo",
|
||||
"name": "在线相册",
|
||||
"order": "95",
|
||||
|
@ -128,7 +128,7 @@
|
||||
"8548d5ce3faee7bd508d2fb53d57f35b": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/50/ios-photos.png",
|
||||
"icons": "https://img.icons8.com/officel/80/ios-photos.png",
|
||||
"index": "web.team.guanlixitong.photo",
|
||||
"name": "在线相册",
|
||||
"order": "95",
|
||||
@ -240,7 +240,7 @@
|
||||
"e595a0bbefbcfaa89f45dd875cc6fe0b": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/50/documents.png",
|
||||
"icons": "https://img.icons8.com/officel/80/documents.png",
|
||||
"index": "web.team.guanlixitong.document",
|
||||
"name": "在线文档",
|
||||
"order": "93",
|
||||
|
@ -1,7 +1,19 @@
|
||||
{
|
||||
"03acc6ed03fa47e9639f1e5c459c3b50": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/80/activity-grid.png",
|
||||
"index": "web.team.operation.template",
|
||||
"name": "云模板",
|
||||
"order": "2",
|
||||
"role": "leader,worker",
|
||||
"time": "2025-03-14 20:51:15.546"
|
||||
}
|
||||
},
|
||||
"03f7f410d292fb30026cbcd99290e943": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"enable": "false",
|
||||
"icons": "https://img.icons8.com/officel/80/online-store.png",
|
||||
"index": "web.team.operation.goodslist",
|
||||
"name": "在线商城",
|
||||
@ -13,6 +25,7 @@
|
||||
"2511b9e18bf167ae0171c740e8f0513c": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"enable": "false",
|
||||
"icons": "https://img.icons8.com/officel/80/agreement.png",
|
||||
"index": "web.team.operation.contract",
|
||||
"name": "在线合同",
|
||||
@ -40,6 +53,16 @@
|
||||
"time": "2024-09-03 10:22:15.258"
|
||||
}
|
||||
},
|
||||
"64be90144c205e73b1fc216962d7ad25": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/80/activity-grid.png",
|
||||
"index": "web.team.operation.product",
|
||||
"name": "云服务",
|
||||
"order": "5",
|
||||
"time": "2025-03-05 10:40:39.748"
|
||||
}
|
||||
},
|
||||
"6ca4f1fc571350c2498bc5c1d7ac3563": {
|
||||
"meta": {
|
||||
"icons": "https://img.icons8.com/officel/80/qr-code.png",
|
||||
@ -53,6 +76,7 @@
|
||||
"700c65f09a19cb53ee5c2dfbb98a5a0b": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"enable": "false",
|
||||
"icons": "https://img.icons8.com/officel/80/video-conference.png",
|
||||
"index": "web.team.operation.meeting",
|
||||
"name": "在线会议",
|
||||
@ -61,14 +85,15 @@
|
||||
"time": "2024-11-20 22:03:43.566"
|
||||
}
|
||||
},
|
||||
"7633ddfc1c6052b7dd2f00096248e1f7": {
|
||||
"7abb3b3760a9b686457938511c0ee7df": {
|
||||
"meta": {
|
||||
"enable": "false",
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/80/activity-grid.png",
|
||||
"index": "web.team.operation.release",
|
||||
"name": "发布",
|
||||
"order": "1",
|
||||
"time": "2024-09-03 10:22:15.265"
|
||||
"index": "web.team.operation.project",
|
||||
"name": "云项目",
|
||||
"order": "4",
|
||||
"role": "leader,worker",
|
||||
"time": "2025-03-05 10:40:39.740"
|
||||
}
|
||||
},
|
||||
"85c8678d4af08bb0c3e9560155b7c98f": {
|
||||
@ -84,7 +109,8 @@
|
||||
"91b0ca086b5b8aa00e84737c4395a19f": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/50/ios-photos.png",
|
||||
"enable": "false",
|
||||
"icons": "https://img.icons8.com/officel/80/ios-photos.png",
|
||||
"index": "web.team.operation.photo",
|
||||
"name": "在线相册",
|
||||
"order": "95",
|
||||
@ -92,15 +118,6 @@
|
||||
"time": "2024-11-28 17:54:45.766"
|
||||
}
|
||||
},
|
||||
"92e6595ec0b5b436695bc827c23ecbf3": {
|
||||
"meta": {
|
||||
"icons": "https://img.icons8.com/officel/80/activity-grid.png",
|
||||
"index": "web.team.operation.container",
|
||||
"name": "云主机",
|
||||
"order": "1",
|
||||
"time": "2025-02-12 15:09:43.924"
|
||||
}
|
||||
},
|
||||
"aa58390a9fac9f8210eca564d1ad82ff": {
|
||||
"meta": {
|
||||
"icons": "https://img.icons8.com/officel/80/passport.png",
|
||||
@ -119,6 +136,17 @@
|
||||
"time": "2024-09-03 10:22:15.259"
|
||||
}
|
||||
},
|
||||
"c8159ab932f400dbafa08fb995e16355": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/80/activity-grid.png",
|
||||
"index": "web.team.operation.cluster",
|
||||
"name": "云集群",
|
||||
"order": "1",
|
||||
"role": "leader",
|
||||
"time": "2025-03-05 10:40:39.838"
|
||||
}
|
||||
},
|
||||
"ca74fb83cfd850b1ca03fe18976c253a": {
|
||||
"meta": {
|
||||
"icons": "https://img.icons8.com/officel/80/test-partial-passed.png",
|
||||
@ -148,10 +176,22 @@
|
||||
"time": "2024-09-03 10:22:15.260"
|
||||
}
|
||||
},
|
||||
"d8f6d139d6a5f9b5aa504702e7777eb3": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/80/activity-grid.png",
|
||||
"index": "web.team.operation.gateway",
|
||||
"name": "云主机",
|
||||
"order": "3",
|
||||
"portal": "true",
|
||||
"time": "2025-03-05 12:13:06.405"
|
||||
}
|
||||
},
|
||||
"d953e8b2c9159b1f4d32ff1c15793314": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/50/documents.png",
|
||||
"enable": "false",
|
||||
"icons": "https://img.icons8.com/officel/80/documents.png",
|
||||
"index": "web.team.operation.document",
|
||||
"name": "在线文档",
|
||||
"order": "93",
|
||||
@ -181,6 +221,7 @@
|
||||
"e9150ed09fcdb4da60f1e9f0d5fe54ea": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"enable": "false",
|
||||
"icons": "https://img.icons8.com/officel/80/online-payment-with-a-credit-card.png",
|
||||
"index": "web.team.operation.paymentlist",
|
||||
"name": "在线支付",
|
||||
|
@ -98,10 +98,19 @@
|
||||
"time": "2024-09-03 15:44:28.507"
|
||||
}
|
||||
},
|
||||
"73b81840f26d2885c065d19e08e923f1": {
|
||||
"meta": {
|
||||
"icons": "https://img.icons8.com/officel/80/web-design.png",
|
||||
"index": "web.team.production.design",
|
||||
"name": "界面设计",
|
||||
"order": "3",
|
||||
"time": "2025-03-21 08:49:22.166"
|
||||
}
|
||||
},
|
||||
"7cf76afacb83fabb3d6a6ffaf48b6066": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/50/documents.png",
|
||||
"icons": "https://img.icons8.com/officel/80/documents.png",
|
||||
"index": "web.team.production.document",
|
||||
"name": "在线文档",
|
||||
"order": "93",
|
||||
@ -180,7 +189,7 @@
|
||||
"c9559beab992f8b46b9cfa4a196e61e8": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/50/ios-photos.png",
|
||||
"icons": "https://img.icons8.com/officel/80/ios-photos.png",
|
||||
"index": "web.team.production.photo",
|
||||
"name": "在线相册",
|
||||
"order": "95",
|
||||
|
@ -2,7 +2,7 @@
|
||||
"015b4784c16b63975824abbb3ff4ec9f": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/50/ios-photos.png",
|
||||
"icons": "https://img.icons8.com/officel/80/ios-photos.png",
|
||||
"index": "web.team.renzhengshouquan.photo",
|
||||
"name": "在线相册",
|
||||
"order": "95",
|
||||
@ -23,7 +23,7 @@
|
||||
"1c4fee90e6a7bdb8ab6f1ccb23f3273f": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/50/documents.png",
|
||||
"icons": "https://img.icons8.com/officel/80/documents.png",
|
||||
"index": "web.team.renzhengshouquan.document",
|
||||
"name": "在线文档",
|
||||
"order": "93",
|
||||
|
@ -129,7 +129,7 @@
|
||||
"ceaca87cf0d112aec124ad24298e189e": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/50/ios-photos.png",
|
||||
"icons": "https://img.icons8.com/officel/80/ios-photos.png",
|
||||
"index": "web.team.storage.photo",
|
||||
"name": "在线相册",
|
||||
"order": "95",
|
||||
@ -190,7 +190,7 @@
|
||||
"f6f77c7a5e247a742c2699564c4507a1": {
|
||||
"meta": {
|
||||
"auth": "issued",
|
||||
"icons": "https://img.icons8.com/officel/50/documents.png",
|
||||
"icons": "https://img.icons8.com/officel/80/documents.png",
|
||||
"index": "web.team.storage.document",
|
||||
"name": "在线文档",
|
||||
"order": "93",
|
||||
|
Loading…
x
Reference in New Issue
Block a user