From 409aa0aed9c33a8e794d748252823c9110991fe6 Mon Sep 17 00:00:00 2001 From: shy Date: Tue, 26 Nov 2024 23:12:41 +0800 Subject: [PATCH] opt some --- go.mod | 3 +- go.sum | 4 + src/gonganxitong/common.go | 5 +- src/gonganxitong/portal.css | 2 +- src/gonganxitong/user.go | 2 +- src/main.go | 4 +- src/option.go | 6 + src/renzhengshouquan/cert.css | 5 +- src/renzhengshouquan/cert.go | 107 +++++++++++++----- src/renzhengshouquan/cert.js | 21 +++- src/renzhengshouquan/common.go | 6 + .../external/tencentcloud/model/model.go | 5 + .../external/tencentcloud/ocr/ocr.go | 39 +++++++ .../external/tencentcloud/ocr/ocr.shy | 5 + .../tencentcloud/realname/model/model.go | 14 +++ .../tencentcloud/realname/realname.go | 67 +++++++++++ .../tencentcloud/realname/realname.js | 8 ++ .../tencentcloud/realname/realname.json | 11 ++ .../tencentcloud/realname/realname.shy | 9 ++ .../external/tencentcloud/sms/model/model.go | 23 ++++ .../external/tencentcloud/sms/sms.go | 49 ++++++++ .../external/tencentcloud/sms/sms.js | 7 ++ .../external/tencentcloud/sms/sms.json | 11 ++ .../external/tencentcloud/sms/sms.shy | 5 + .../external/tencentcloud/tencentcloud.go | 29 ++++- src/renzhengshouquan/model/model.go | 25 +++- src/renzhengshouquan/portal.json | 9 +- .../web.team.gonganxitong.portal/hash.json | 24 +++- .../web.team.guanlixitong.portal/hash.json | 21 +++- .../web.team.huodongzuzhi.portal/hash.json | 27 +++++ .../hash.json | 63 ++++++++++- .../web.team.yuehaoxitong.portal/hash.json | 27 +++++ 32 files changed, 592 insertions(+), 51 deletions(-) create mode 100644 src/renzhengshouquan/external/tencentcloud/ocr/ocr.go create mode 100644 src/renzhengshouquan/external/tencentcloud/ocr/ocr.shy create mode 100644 src/renzhengshouquan/external/tencentcloud/realname/model/model.go create mode 100644 src/renzhengshouquan/external/tencentcloud/realname/realname.go create mode 100644 src/renzhengshouquan/external/tencentcloud/realname/realname.js create mode 100644 src/renzhengshouquan/external/tencentcloud/realname/realname.json create mode 100644 src/renzhengshouquan/external/tencentcloud/realname/realname.shy create mode 100644 src/renzhengshouquan/external/tencentcloud/sms/model/model.go create mode 100644 src/renzhengshouquan/external/tencentcloud/sms/sms.go create mode 100644 src/renzhengshouquan/external/tencentcloud/sms/sms.js create mode 100644 src/renzhengshouquan/external/tencentcloud/sms/sms.json create mode 100644 src/renzhengshouquan/external/tencentcloud/sms/sms.shy diff --git a/go.mod b/go.mod index ddad786..18385cc 100644 --- a/go.mod +++ b/go.mod @@ -25,8 +25,9 @@ require ( github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1046 // indirect + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1047 // indirect github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ocr v1.0.1046 // indirect + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.1047 // indirect github.com/wechatpay-apiv3/wechatpay-go v0.2.20 // indirect golang.org/x/text v0.16.0 // indirect gorm.io/driver/mysql v1.5.7 // indirect diff --git a/go.sum b/go.sum index 56ecda3..bb463db 100644 --- a/go.sum +++ b/go.sum @@ -67,8 +67,12 @@ github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8 github.com/tdakkota/win32metadata v0.1.0/go.mod h1:77e6YvX0LIVW+O81fhWLnXAxxcyu/wdZdG7iwed7Fyk= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1046 h1:0FvA5Rw9dGqK5CTbWlgyE1HbiND1hLsoIfne4jzWuRI= 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 h1:eLEUnmSd82NBMNwergC/5RGqJqNDbsvprPtnG1UhxDI= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1047/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/sms v1.0.1047 h1:FF8uERgTL9NKxgUHrKHbVefETVL3J6DeL9t6qvIT5yI= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.1047/go.mod h1:3tgFFSlybx6XyhvLWpnSjWYFMedTyQC9oyh8CH1Ak28= github.com/tinygo-org/cbgo v0.0.4/go.mod h1:7+HgWIHd4nbAz0ESjGlJ1/v9LDU1Ox8MGzP9mah/fLk= github.com/tinygo-org/pio v0.0.0-20231216154340-cd888eb58899/go.mod h1:LU7Dw00NJ+N86QkeTGjMLNkYcEYMor6wTDpTCu0EaH8= github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= diff --git a/src/gonganxitong/common.go b/src/gonganxitong/common.go index 40094d2..ffd62aa 100644 --- a/src/gonganxitong/common.go +++ b/src/gonganxitong/common.go @@ -280,12 +280,13 @@ func (s Table) UploadUpdate(m *ice.Message, field, uid string, arg ...string) { p := m.UploadSave(path.Join(nfs.USR, kit.Select(field, m.Option(model.FIELD)), uid) + nfs.PS) s.Update(m, kit.Dict(kit.Select(m.Option(model.FIELD), field), p), model.UID, uid) } -func (s Table) UploadCreate(m *ice.Message, field, uid string, arg ...string) { +func (s Table) UploadCreate(m *ice.Message, field, uid string, arg ...string) string { if m.IsErr() { - return + return "" } p := m.UploadSave(path.Join(nfs.USR, kit.Select(field, m.Option(model.FIELD)), uid) + nfs.PS) s.Create(m, kit.Select(m.Option(model.FIELD), field), p, model.UID, uid, model.USER_UID, m.Option(model.USER_UID)) + return p } func (s Table) ChangeStatus(m *ice.Message, place_uid, uid string, from, to int, arg ...string) *ice.Message { msg := s.ValueList(m.Spawn(), []string{place_uid, uid}, model.STATUS) diff --git a/src/gonganxitong/portal.css b/src/gonganxitong/portal.css index 818aa0f..ac1786e 100644 --- a/src/gonganxitong/portal.css +++ b/src/gonganxitong/portal.css @@ -65,7 +65,7 @@ $output div.item.card:not(:last-child) { margin-bottom:2px; } body:not(.width1) $output div.item.card { flex-direction:row-reverse; } body:not(.width1) $output div.item.card>div.action { position:static; flex-shrink:0; } body:not(.width1) $output div.item.card>div.output { flex-grow:1; } -$output div.item.card>div.output>div { width:100%; } +$output div.item.card>div.output>div { width:100%; width:calc(100% - 53px); overflow:hidden; } $output div.item.card div.title { margin-bottom:5px; width:100%; display:flex; align-items:center; position:relative; } $output div.item.card div.title span:first-child { word-break:break-all; } $output div.item.card div.title span.auth { font-size:14px; } diff --git a/src/gonganxitong/user.go b/src/gonganxitong/user.go index f532fed..25090ef 100644 --- a/src/gonganxitong/user.go +++ b/src/gonganxitong/user.go @@ -40,7 +40,7 @@ func (s user) Remove(m *ice.Message, arg ...string) { func (s user) List(m *ice.Message, arg ...string) { if len(arg) == 0 { if m.IsTech() { - s.Limit(m, 50) + s.Limit(m, 100) s.Select(m, arg...).Table(func(value ice.Maps) { if value[model.UID] != m.Option(model.USER_UID) { m.PushButton(s.SetCookie, s.Remove) diff --git a/src/main.go b/src/main.go index 047b38d..cfa4b57 100644 --- a/src/main.go +++ b/src/main.go @@ -7,8 +7,6 @@ import ( _ "shylinux.com/x/community/src/huodongzuzhi" _ "shylinux.com/x/community/src/renzhengshouquan" _ "shylinux.com/x/community/src/yuehaoxitong" - - _ "shylinux.com/x/community/src/renzhengshouquan/external/tencentcloud/model" ) func main() { print(ice.Run()) } @@ -16,4 +14,4 @@ func main() { print(ice.Run()) } func init() { ice.Info.CodeMain = "src/gonganxitong/portal.go" ice.Info.NodeMain = "web.team.gonganxitong.portal" -} \ No newline at end of file +} diff --git a/src/option.go b/src/option.go index 64c5fd9..495f03c 100644 --- a/src/option.go +++ b/src/option.go @@ -5,6 +5,12 @@ import ( _ "shylinux.com/x/mysql-story/src/db/mysql" _ "shylinux.com/x/community/src/renzhengshouquan/external/tencentcloud" + _ "shylinux.com/x/community/src/renzhengshouquan/external/tencentcloud/model" + _ "shylinux.com/x/community/src/renzhengshouquan/external/tencentcloud/ocr" + _ "shylinux.com/x/community/src/renzhengshouquan/external/tencentcloud/realname" + _ "shylinux.com/x/community/src/renzhengshouquan/external/tencentcloud/realname/model" + _ "shylinux.com/x/community/src/renzhengshouquan/external/tencentcloud/sms" + _ "shylinux.com/x/community/src/renzhengshouquan/external/tencentcloud/sms/model" _ "shylinux.com/x/community/src/renzhengshouquan/external/tencentdocument" _ "shylinux.com/x/community/src/renzhengshouquan/external/tencentmeeting" _ "shylinux.com/x/community/src/renzhengshouquan/external/tencentmeeting/model" diff --git a/src/renzhengshouquan/cert.css b/src/renzhengshouquan/cert.css index 817711c..cc4c03e 100644 --- a/src/renzhengshouquan/cert.css +++ b/src/renzhengshouquan/cert.css @@ -1 +1,4 @@ -$output div.item.card div.output div.output img { height:unset; width:100%; margin-right:0; } \ No newline at end of file +$output div.item.card div.output div.output img { height:unset; width:100%; margin-right:0; } +$input div.item.text.verify input[type=button] { + border-radius:0; height:30px; position:absolute; right:1px; width:unset; +} \ No newline at end of file diff --git a/src/renzhengshouquan/cert.go b/src/renzhengshouquan/cert.go index e8a3351..2f277c0 100644 --- a/src/renzhengshouquan/cert.go +++ b/src/renzhengshouquan/cert.go @@ -1,56 +1,107 @@ package renzhengshouquan import ( - "encoding/base64" + "math/rand" "shylinux.com/x/ice" "shylinux.com/x/icebergs/base/mdb" - "shylinux.com/x/icebergs/base/nfs" - // "shylinux.com/x/icebergs/base/web" "shylinux.com/x/toolkits" - "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" - cloudprofile "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" - ocr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ocr/v20181119" "shylinux.com/x/community/src/renzhengshouquan/model" ) type cert struct { Table order string `data:"1"` - fields string `data:"title,content,path,user_uid"` + fields string `data:"cert_status,path,number,name,type,address,mobile,verify,user_uid"` upload string `name:"upload" role:"leader"` remove string `name:"remove" role:"leader"` + verify string `name:"verify mobile* verify*" role:"void"` } func (s cert) Upload(m *ice.Message, arg ...string) { - m.WarnNotValid(!kit.IsIn(m.OptionDefault(mdb.FIELD, "cert"), "cert")) - s.UploadCreate(m, model.PATH, m.Option(model.AUTH_UID)) + p := s.UploadCreate(m.Options(mdb.FIELD, "cert"), model.PATH, "") + switch AuthType(kit.Int(m.Cmd(Auth{}, s.Select, model.UID, m.Option(model.AUTH_UID)).Append(model.AUTH_TYPE))) { + case AuthPersonal: + msg := m.Cmd(OcrVendor, OcrVendor.IDCard, p) + s.Update(m, kit.Dict( + model.NUMBER, msg.Append("IdNum"), + model.NAME, msg.Append("Name"), + model.TYPE, msg.Append("Sex"), + model.BIRTH, msg.Append("Birth"), + model.ADDRESS, msg.Append("Address"), + ), m.OptionSimple(model.AUTH_UID)...) + case AuthCompany: + msg := m.Cmd(OcrVendor, OcrVendor.BizLicense, p) + s.Update(m, kit.Dict( + model.NUMBER, msg.Append("RegNum"), + model.NAME, msg.Append("Name"), + model.TYPE, msg.Append("Type"), + model.PERSON, msg.Append("Person"), + model.PERIOD, msg.Append("Period"), + model.ADDRESS, msg.Append("Address"), + model.AUTHOR, msg.Append("RegistrationAuthority"), + ), m.OptionSimple(model.AUTH_UID)...) + } } func (s cert) List(m *ice.Message, arg ...string) { if len(arg) == 1 { - s.Select(m, model.AUTH_UID, arg[0]).PushAction(s.Remove).Action(s.Upload).Display("").DisplayCSS("") + s.Select(m, model.AUTH_UID, arg[0]).Table(func(value ice.Maps) { + switch CertStatus(kit.Int(value[model.CERT_STATUS])) { + case CertUpload: + m.PushButton(s.Verify) + case CertVerify: + m.PushButton(s.Check) + default: + m.PushButton(s.Verify) + // m.PushButton() + } + }).Action(s.Upload).Display("").DisplayCSS("") s.Button(m, "", s.Upload) } - - // _msg := m.Cmd(web.CHAT_WX_OCR, "", m.Append(model.PATH), "bizlicense") - // m.Echo(kit.Formats(_msg)) - s.BizLicenseOCR(m) } -func (s cert) newClient(m *ice.Message, arg ...string) *ocr.Client { - msg := m.Cmd("web.team.renzhengshouquan.external.tencentcloud.tencentcloud", "4c6a8ccf186816b332ad9dc5655255dd") - credential := common.NewCredential(msg.Append("secret_id"), msg.Append("secret_key")) - client, _ := ocr.NewClient(credential, "", cloudprofile.NewClientProfile()) - return client +func (s cert) Verify(m *ice.Message, arg ...string) { + if m.Option(model.VERIFY) == "000" { + verify := kit.Format("%06d", rand.Intn(10000)) + s.Update(m, kit.Dict(model.VERIFY, verify), m.OptionSimple(model.AUTH_UID, model.UID)...) + m.Cmd(SmsVendor, SmsVendor.Send, m.Option(model.MOBILE), verify) + } else { + msg := s.Select(m.Spawn(), m.OptionSimple(model.AUTH_UID, model.UID)...) + if msg.Append(model.VERIFY) == m.Option(model.VERIFY) { + s.Check(m) + } + } } -func (s cert) BizLicenseOCR(m *ice.Message, arg ...string) *ice.Message { - request := ocr.NewBizLicenseOCRRequest() - request.ImageBase64 = common.StringPtr(base64.StdEncoding.EncodeToString([]byte(m.Cmdx(nfs.CAT, m.Append(model.PATH))))) - response, err := s.newClient(m).BizLicenseOCR(request) - m.Warn(err) - m.SetAppend() - m.PushDetail(kit.Value(kit.UnMarshal(response.ToJsonString()), "Response")) - return m +func (s cert) Check(m *ice.Message, arg ...string) { + if !m.Cmdy(RealnameVendor, RealnameVendor.Check, m.Option(model.MOBILE), m.Option(model.NUMBER), m.Option(model.NAME)).IsErr() { + s.Update(m, kit.Dict(model.STATUS, CertCheck), m.OptionSimple(model.AUTH_UID, model.UID)...) + } } - func init() { ice.TeamCtxCmd(cert{}) } + +type CertStatus int + +const ( + CertUpload CertStatus = iota + CertVerify + CertCheck +) + +var CertStatusList = map[CertStatus]string{ + CertUpload: "upload", + CertVerify: "verify", + CertCheck: "check", +} + +func (s CertStatus) String() string { return CertStatusList[s] } + +var OcrVendor interface { + IDCard(m *ice.Message, arg ...string) + BizLicense(m *ice.Message, arg ...string) +} +var SmsVendor interface { + Send(m *ice.Message, arg ...string) +} +var RealnameVendor interface { + Check(m *ice.Message, arg ...string) +} diff --git a/src/renzhengshouquan/cert.js b/src/renzhengshouquan/cert.js index 4576fe0..75a5f6d 100644 --- a/src/renzhengshouquan/cert.js +++ b/src/renzhengshouquan/cert.js @@ -1,12 +1,29 @@ Volcanos(chat.ONIMPORT, { _init: function(can, msg) { can.onimport.myView(can, msg, function(value) { return [ - {view: html.TITLE, list: [value.title]}, - {view: html.STATUS, list: [value.uid.slice(0, 6), can.onimport.timeView(can, value), value.user_name]}, + // {view: html.TITLE, list: [value.title]}, + // {view: html.STATUS, list: [value.uid.slice(0, 6), can.onimport.timeView(can, value), value.user_name]}, + {view: html.TITLE, list: [value.name]}, + {view: html.STATUS, list: [value.number]}, + {view: html.STATUS, list: [value.address]}, {view: html.OUTPUT, list: [{img: can.misc.Resource(can, value.path)}]}, ] }, function(event, value) {}) }, }) Volcanos(chat.ONACTION, { upload: function(event, can) { can.user.upload(can.request(event, {_handle: ice.TRUE}), can) }, + beforeInputs: function(event, can, button, sub) { + can.page.Select(can, sub._target, "table>tr>td>div.item.text.verify", function(target) { + can.page.Append(can, target, [{type: html.INPUT, data: {type: html.BUTTON}, name: "verify", value: "发送验证码", onclick: function(event) { + if (sub.Option("mobile") == "") { + return can.onmotion.delay(can, function() { + can.user.toast(can, "手机号不能为空"), sub.focus("mobile") + }) + } + can.runAction(can.request(event, sub.Option(), {verify: "000"}), "verify", [], function() { + can.user.toast(can, "验证码发送成功") + }) + }}]) + }) + }, }) \ No newline at end of file diff --git a/src/renzhengshouquan/common.go b/src/renzhengshouquan/common.go index 7f5029f..ce35444 100644 --- a/src/renzhengshouquan/common.go +++ b/src/renzhengshouquan/common.go @@ -44,12 +44,18 @@ func (s Table) RewriteAppend(m *ice.Message, arg ...string) *ice.Message { value = AuthType(kit.Int(value)).String() case model.AUTH_STATUS: value = AuthStatus(kit.Int(value)).String() + case model.CERT_STATUS: + value = CertStatus(kit.Int(value)).String() } return value }) return s.Table.RewriteAppend(m) } +func (s Table) GetAuthUID(m *ice.Message, arg ...string) string { + return "4c6a8ccf186816b332ad9dc5655255dd" +} + type Tables struct{ Table } func (s Tables) BeforeMigrate(m *ice.Message, arg ...string) {} diff --git a/src/renzhengshouquan/external/tencentcloud/model/model.go b/src/renzhengshouquan/external/tencentcloud/model/model.go index 14dcc00..ca19527 100644 --- a/src/renzhengshouquan/external/tencentcloud/model/model.go +++ b/src/renzhengshouquan/external/tencentcloud/model/model.go @@ -2,6 +2,11 @@ package model import "shylinux.com/x/mysql-story/src/db" +const ( + SECRET_ID = "secret_id" + SECRET_KEY = "secret_key" +) + type Tencentcloud struct { db.ModelWithUID AuthUID string `gorm:"type:char(32);index"` diff --git a/src/renzhengshouquan/external/tencentcloud/ocr/ocr.go b/src/renzhengshouquan/external/tencentcloud/ocr/ocr.go new file mode 100644 index 0000000..4ed0459 --- /dev/null +++ b/src/renzhengshouquan/external/tencentcloud/ocr/ocr.go @@ -0,0 +1,39 @@ +package ocr + +import ( + "shylinux.com/x/ice" + + "shylinux.com/x/community/src/renzhengshouquan" + "shylinux.com/x/community/src/renzhengshouquan/external/tencentcloud" + + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + sdk "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ocr/v20181119" +) + +type ocr struct { + tencentcloud.Tencentcloud +} + +func (s ocr) List(m *ice.Message, arg ...string) {} + +func (s ocr) BizLicense(m *ice.Message, arg ...string) { + request := sdk.NewBizLicenseOCRRequest() + request.ImageBase64 = common.StringPtr(s.ImageData(m, arg...)) + response, err := s.newClient(m).BizLicenseOCR(request) + s.ParseResponse(m, response, err) +} +func (s ocr) IDCard(m *ice.Message, arg ...string) { + request := sdk.NewIDCardOCRRequest() + request.ImageBase64 = common.StringPtr(s.ImageData(m, arg...)) + response, err := s.newClient(m).IDCardOCR(request) + s.ParseResponse(m, response, err) +} + +func init() { ice.TeamCtxCmd(ocr{}) } + +func (s ocr) newClient(m *ice.Message, arg ...string) *sdk.Client { + c, _ := sdk.NewClient(s.NewCredential(m), "", s.NewProfile(m)) + return c +} + +func init() { renzhengshouquan.OcrVendor = ocr{} } diff --git a/src/renzhengshouquan/external/tencentcloud/ocr/ocr.shy b/src/renzhengshouquan/external/tencentcloud/ocr/ocr.shy new file mode 100644 index 0000000..e9d029f --- /dev/null +++ b/src/renzhengshouquan/external/tencentcloud/ocr/ocr.shy @@ -0,0 +1,5 @@ +section "图文识别" +refer ` +文档 https://cloud.tencent.com/document/product/866/45338 +调试 https://console.cloud.tencent.com/api/explorer?Product=ocr&Version=2018-11-19&Action=RecognizeEncryptedIDCardOCR +` \ No newline at end of file diff --git a/src/renzhengshouquan/external/tencentcloud/realname/model/model.go b/src/renzhengshouquan/external/tencentcloud/realname/model/model.go new file mode 100644 index 0000000..741ff14 --- /dev/null +++ b/src/renzhengshouquan/external/tencentcloud/realname/model/model.go @@ -0,0 +1,14 @@ +package model + +import "shylinux.com/x/mysql-story/src/db" + +type Realname struct { + db.ModelWithUID + AuthUID string `gorm:"type:char(32);index"` + UserUID string `gorm:"type:char(32)"` + SourceID string `gorm:"type:varchar(64)"` + SecretID string `gorm:"type:varchar(64)"` + SecretKey string `gorm:"type:varchar(64)"` +} + +func init() { db.CmdModels("", &Realname{}) } diff --git a/src/renzhengshouquan/external/tencentcloud/realname/realname.go b/src/renzhengshouquan/external/tencentcloud/realname/realname.go new file mode 100644 index 0000000..da67df8 --- /dev/null +++ b/src/renzhengshouquan/external/tencentcloud/realname/realname.go @@ -0,0 +1,67 @@ +package realname + +import ( + "crypto/hmac" + "crypto/sha1" + "encoding/base64" + "fmt" + "net/http" + "time" + + "shylinux.com/x/ice" + "shylinux.com/x/icebergs/base/web" + kit "shylinux.com/x/toolkits" + + "shylinux.com/x/community/src/renzhengshouquan" + "shylinux.com/x/community/src/renzhengshouquan/model" +) + +type realname struct { + renzhengshouquan.Table + order string `data:"16"` + fields string `data:"auth_uid,user_uid,source_id,secret_id,secret_key"` + create string `name:"create source_id* secret_id* secret_key*" role:"leader"` + remove string `name:"remove" role:"leader"` +} + +func (s realname) List(m *ice.Message, arg ...string) { + s.ValueList(m, arg).Display("") + kit.If(m.Length() > 0, func() { m.Action() }) +} +func init() { ice.TeamCtxCmd(realname{}) } + +func init() { renzhengshouquan.RealnameVendor = realname{} } + +func (s realname) Check(m *ice.Message, arg ...string) { + msg := s.Select(m.Spawn(), model.AUTH_UID, "4c6a8ccf186816b332ad9dc5655255dd") + source := msg.Append("source_id") + secretId := msg.Append("secret_id") + secretKey := msg.Append("secret_key") + + // source := "market-2qkoxdj5i" + // secretId := "AKIDfjSG99M0m5gqr0aiyN4Ho0rfut22jybmlrj1" + // secretKey := "3oga413JEe58di8k2NkVim5s79Qmuw17DWVV6spD" + + // source := "market-dw3yg5tm8" + // secretId := "AKIDHFZ1EdTz3D7Y4nMYESfSKdv1RTpkbKe7LjpU" + // secretKey := "cpcts0905vj0wm2qw6l8az5dermgvp8m7op4wzgw" + + auth, datetime := calcAuthorization(source, secretId, secretKey) + m.Option(web.SPIDE_HEADER, map[string]string{"X-Source": source, "Authorization": auth, "X-Date": datetime}) + res := m.Cmdx(web.SPIDE, ice.DEV, web.SPIDE_RAW, http.MethodPost, "https://service-rbgpp2hy-1305308687.gz.apigw.tencentcs.com/release/release/mobile/3-realnameauth", + web.SPIDE_FORM, "mobile_number", arg[0], "idcard_number", arg[1], "name", arg[2]) + m.WarnNotRight(kit.Value(kit.UnMarshal(res), "data.result") != "0") + // m.Cmdy(web.SPIDE, ice.DEV, web.SPIDE_RAW, http.MethodPost, "https://service-91ii7z5b-1300755093.ap-beijing.apigateway.myqcloud.com/release/phone3element", + // web.SPIDE_FORM, "mobile", arg[0], "idCard", arg[1], "realName", arg[2]) +} + +func calcAuthorization(source string, secretId string, secretKey string) (auth string, datetime string) { + timeLocation, _ := time.LoadLocation("Etc/GMT") + datetime = time.Now().In(timeLocation).Format("Mon, 02 Jan 2006 15:04:05 GMT") + signStr := fmt.Sprintf("x-date: %s\nx-source: %s", datetime, source) + mac := hmac.New(sha1.New, []byte(secretKey)) + mac.Write([]byte(signStr)) + sign := base64.StdEncoding.EncodeToString(mac.Sum(nil)) + auth = fmt.Sprintf("hmac id=\"%s\", algorithm=\"hmac-sha1\", headers=\"x-date x-source\", signature=\"%s\"", secretId, sign) + return auth, datetime +} diff --git a/src/renzhengshouquan/external/tencentcloud/realname/realname.js b/src/renzhengshouquan/external/tencentcloud/realname/realname.js new file mode 100644 index 0000000..e054947 --- /dev/null +++ b/src/renzhengshouquan/external/tencentcloud/realname/realname.js @@ -0,0 +1,8 @@ +Volcanos(chat.ONIMPORT, { + _init: function(can, msg) { + can.onimport.myView(can, msg, function(value) { return [ + {view: html.TITLE, list: [value.source_id]}, + {view: html.STATUS, list: [value.secret_id]}, + ] }) + }, +}) \ No newline at end of file diff --git a/src/renzhengshouquan/external/tencentcloud/realname/realname.json b/src/renzhengshouquan/external/tencentcloud/realname/realname.json new file mode 100644 index 0000000..1cd4637 --- /dev/null +++ b/src/renzhengshouquan/external/tencentcloud/realname/realname.json @@ -0,0 +1,11 @@ +{ + "realname": "实名验证", + "icons": { + "realname": "https://img.icons8.com/officel/80/video-conference.png" + }, + "input": { + "source_id": "SourceID", + "secret_id": "SecretID", + "secret_key": "SecretKey" + } +} \ No newline at end of file diff --git a/src/renzhengshouquan/external/tencentcloud/realname/realname.shy b/src/renzhengshouquan/external/tencentcloud/realname/realname.shy new file mode 100644 index 0000000..6562bec --- /dev/null +++ b/src/renzhengshouquan/external/tencentcloud/realname/realname.shy @@ -0,0 +1,9 @@ +section "实名验证" +refer ` +后台 https://console.cloud.tencent.com/servicemarket/services/market-2qkoxdj5i +文档 https://market.cloud.tencent.com/products/30034?keyword=%E6%89%8B%E6%9C%BA%E4%B8%89%E8%A6%81%E7%B4%A0%E5%AE%9E%E5%90%8D%E8%AE%A4%E8%AF%81 +` +refer ` +后台 https://console.cloud.tencent.com/servicemarket/services/market-dw3yg5tm8 +文档 https://market.cloud.tencent.com/products/17673 +` \ No newline at end of file diff --git a/src/renzhengshouquan/external/tencentcloud/sms/model/model.go b/src/renzhengshouquan/external/tencentcloud/sms/model/model.go new file mode 100644 index 0000000..1c87e04 --- /dev/null +++ b/src/renzhengshouquan/external/tencentcloud/sms/model/model.go @@ -0,0 +1,23 @@ +package model + +import "shylinux.com/x/mysql-story/src/db" + +const ( + AUTH_UID = "auth_uid" + SIGN_NAME = "sign_name" + TEMPLATE_ID = "template_id" + APP_ID = "app_id" + MOBILE = "mobile" + VERIFY = "verify" +) + +type Sms struct { + db.ModelWithUID + AuthUID string `gorm:"type:char(32);index"` + UserUID string `gorm:"type:char(32);index"` + SignName string `gorm:"type:varchar(64)"` + TemplateID string `gorm:"type:varchar(64)"` + AppID string `gorm:"type:varchar(32)"` +} + +func init() { db.CmdModels("", &Sms{}) } diff --git a/src/renzhengshouquan/external/tencentcloud/sms/sms.go b/src/renzhengshouquan/external/tencentcloud/sms/sms.go new file mode 100644 index 0000000..73f487e --- /dev/null +++ b/src/renzhengshouquan/external/tencentcloud/sms/sms.go @@ -0,0 +1,49 @@ +package sms + +import ( + "shylinux.com/x/ice" + kit "shylinux.com/x/toolkits" + + "shylinux.com/x/community/src/renzhengshouquan" + "shylinux.com/x/community/src/renzhengshouquan/external/tencentcloud" + "shylinux.com/x/community/src/renzhengshouquan/external/tencentcloud/sms/model" + + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + sdk "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms/v20210111" +) + +type sms struct { + renzhengshouquan.Table + tencentcloud.Tencentcloud + order string `data:"17"` + fields string `data:"auth_uid,user_uid,sign_name AS sign_name,template_id,app_id"` + create string `name:"create app_id* sign_name* template_id*" role:"leader"` + remove string `name:"remove" role:"leader"` + send string `name:"send mobile verify" role:"leader"` +} + +func (s sms) List(m *ice.Message, arg ...string) { + s.ValueList(m, arg).Display("") + m.PushAction(s.Send, s.Remove) + kit.If(m.Length() > 0, func() { m.Action() }) +} +func (s sms) Send(m *ice.Message, arg ...string) { + msg := s.Select(m.Spawn(), model.AUTH_UID, s.GetAuthUID(m)) + request := sdk.NewSendSmsRequest() + request.SignName = common.StringPtr(msg.Append(model.SIGN_NAME)) + request.TemplateId = common.StringPtr(msg.Append(model.TEMPLATE_ID)) + request.SmsSdkAppId = common.StringPtr(msg.Append(model.APP_ID)) + request.PhoneNumberSet = common.StringPtrs([]string{m.Option(model.MOBILE)}) + request.TemplateParamSet = common.StringPtrs([]string{m.Option(model.VERIFY)}) + response, err := s.newClient(m).SendSms(request) + s.ParseResponse(m, response, err) +} + +func init() { ice.TeamCtxCmd(sms{}) } + +func init() { renzhengshouquan.SmsVendor = sms{} } + +func (s sms) newClient(m *ice.Message, arg ...string) *sdk.Client { + c, _ := sdk.NewClient(s.NewCredential(m), "ap-guangzhou", s.NewProfile(m)) + return c +} diff --git a/src/renzhengshouquan/external/tencentcloud/sms/sms.js b/src/renzhengshouquan/external/tencentcloud/sms/sms.js new file mode 100644 index 0000000..69c9701 --- /dev/null +++ b/src/renzhengshouquan/external/tencentcloud/sms/sms.js @@ -0,0 +1,7 @@ +Volcanos(chat.ONIMPORT, { + _init: function(can, msg) { + can.onimport.myView(can, msg, function(value) { return [ + {view: html.TITLE, list: [value.sign_name, value.template_id, value.app_id]}, + ] }) + }, +}) \ No newline at end of file diff --git a/src/renzhengshouquan/external/tencentcloud/sms/sms.json b/src/renzhengshouquan/external/tencentcloud/sms/sms.json new file mode 100644 index 0000000..fac67f7 --- /dev/null +++ b/src/renzhengshouquan/external/tencentcloud/sms/sms.json @@ -0,0 +1,11 @@ +{ + "sms": "发送短信", + "icons": { + "sms": "https://img.icons8.com/officel/80/sms.png" + }, + "input": { + "app_id": "AppID", + "sign_name": "SignName", + "template_id": "TemplateID" + } +} \ No newline at end of file diff --git a/src/renzhengshouquan/external/tencentcloud/sms/sms.shy b/src/renzhengshouquan/external/tencentcloud/sms/sms.shy new file mode 100644 index 0000000..0fb835a --- /dev/null +++ b/src/renzhengshouquan/external/tencentcloud/sms/sms.shy @@ -0,0 +1,5 @@ +chapter "短信" +refer ` +后台 https://console.cloud.tencent.com/smsv2 +调试 https://console.cloud.tencent.com/api/explorer?Product=sms&Version=2021-01-11&Action=SendSms +` \ No newline at end of file diff --git a/src/renzhengshouquan/external/tencentcloud/tencentcloud.go b/src/renzhengshouquan/external/tencentcloud/tencentcloud.go index b35cd7e..4b9493f 100644 --- a/src/renzhengshouquan/external/tencentcloud/tencentcloud.go +++ b/src/renzhengshouquan/external/tencentcloud/tencentcloud.go @@ -1,15 +1,22 @@ package tencentcloud import ( + "encoding/base64" + "shylinux.com/x/ice" + "shylinux.com/x/icebergs/base/nfs" kit "shylinux.com/x/toolkits" "shylinux.com/x/community/src/renzhengshouquan" + "shylinux.com/x/community/src/renzhengshouquan/external/tencentcloud/model" + + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" ) type tencentcloud struct { renzhengshouquan.Table - order string `data:"13"` + order string `data:"15"` fields string `data:"secret_id,secret_key,user_uid"` create string `name:"create secret_id* secret_key*" role:"leader"` remove string `name:"remove" role:"leader"` @@ -21,3 +28,23 @@ func (s tencentcloud) List(m *ice.Message, arg ...string) { } func init() { ice.TeamCtxCmd(tencentcloud{}) } + +type Tencentcloud struct{ tencentcloud } + +func init() { ice.TeamCtxCmd(Tencentcloud{}) } + +func (s Tencentcloud) NewCredential(m *ice.Message, arg ...string) *common.Credential { + msg := m.Cmd(s, "4c6a8ccf186816b332ad9dc5655255dd") + return common.NewCredential(msg.Append(model.SECRET_ID), msg.Append(model.SECRET_KEY)) +} +func (s Tencentcloud) NewProfile(m *ice.Message, arg ...string) *profile.ClientProfile { + return profile.NewClientProfile() +} +func (s Tencentcloud) ImageData(m *ice.Message, arg ...string) string { + return base64.StdEncoding.EncodeToString([]byte(m.Cmdx(nfs.CAT, arg[0]))) +} +func (s Tencentcloud) ParseResponse(m *ice.Message, res interface{ ToJsonString() string }, err error) { + if !m.Warn(err) { + m.PushDetail(kit.Value(kit.UnMarshal(res.ToJsonString()), "Response")) + } +} diff --git a/src/renzhengshouquan/model/model.go b/src/renzhengshouquan/model/model.go index a795597..593a9bc 100644 --- a/src/renzhengshouquan/model/model.go +++ b/src/renzhengshouquan/model/model.go @@ -22,6 +22,7 @@ const ( AUTH_STATUS = "auth_status" AUTH_AVATAR = "auth_avatar" CERT_UID = "cert_uid" + CERT_STATUS = "cert_status" PLACE_NAME = "place_name" STREET_NAME = "street_name" COMPANY_UID = "company_uid" @@ -37,6 +38,14 @@ const ( INDEX = "index" VALUE = "value" PATH = "path" + NUMBER = "number" + BIRTH = "birth" + PERIOD = "period" + PERSON = "person" + AUTHOR = "author" + ADDRESS = "address" + MOBILE = "mobile" + VERIFY = "verify" ) type UserAuth struct { @@ -55,11 +64,21 @@ type Auth struct { Status uint8 `gorm:"default:0"` } type Cert struct { - db.ModelContent + db.ModelWithUID AuthUID string `gorm:"type:char(32);index"` + UserUID string `gorm:"type:char(32);index"` Path string `gorm:"type:varchar(255)"` - Type string `gorm:"type:char(8)"` - Size int `gorm:"default:0"` + Number string `gorm:"type:varchar(32)"` + Name string `gorm:"type:varchar(32)"` + Type string `gorm:"type:varchar(32)"` + Birth string `gorm:"type:varchar(32)"` + Period string `gorm:"type:varchar(32)"` + Person string `gorm:"type:varchar(32)"` + Author string `gorm:"type:varchar(32)"` + Address string `gorm:"type:varchar(255)"` + Status uint8 `gorm:"default:0"` + Mobile string `gorm:"type:varchar(16)"` + Verify string `gorm:"type:varchar(16)"` } func init() { db.CmdModels("", &UserAuth{}, &Auth{}, &Cert{}) } diff --git a/src/renzhengshouquan/portal.json b/src/renzhengshouquan/portal.json index 455c241..2b92df1 100644 --- a/src/renzhengshouquan/portal.json +++ b/src/renzhengshouquan/portal.json @@ -3,6 +3,7 @@ "cert": "上传证件", "auth": "认证授权", "admin": "管理后台", "profile": "用户名片", "certList": "证件", "memberList": "成员", "issue": "认证", "revoke": "吊销", "enter": "进入", + "verify": "验证", "style": { "issue": "notice", "revoke": "danger", @@ -21,7 +22,13 @@ "auth_name": "认证主体", "auth_type": "认证类型", "auth_status": "认证状态", - "from_uid": "认证机构" + "mobile": "手机号", + "verify": "验证码", + "from_uid": "认证机构", + "icons": { + "mobile": "bi bi-phone", + "verify": "bi bi-123" + } }, "value": { "user_auth_role": { diff --git a/usr/local/export/web.team.gonganxitong.portal/hash.json b/usr/local/export/web.team.gonganxitong.portal/hash.json index 40e5a50..c08c9e5 100644 --- a/usr/local/export/web.team.gonganxitong.portal/hash.json +++ b/usr/local/export/web.team.gonganxitong.portal/hash.json @@ -18,6 +18,15 @@ "time": "2024-08-06 18:45:35.904" } }, + "22574299a657140d473f0216b8d83710": { + "meta": { + "icons": "https://img.icons8.com/officel/50/documents.png", + "index": "web.team.gonganxitong.document", + "name": "在线文档", + "order": "93", + "time": "2024-11-25 15:33:24.095" + } + }, "27c6988eeb07c78cbb49aa15c577cfa4": { "meta": { "icons": "https://img.icons8.com/officel/80/edit-property.png", @@ -33,7 +42,7 @@ "icons": "https://img.icons8.com/officel/80/agreement.png", "index": "web.team.gonganxitong.contract", "name": "在线合同", - "order": "93", + "order": "94", "time": "2024-11-24 09:19:03.732" } }, @@ -46,6 +55,15 @@ "time": "2024-09-07 08:23:04.093" } }, + "882a999b4a72a9866d9e4eef110d335a": { + "meta": { + "icons": "https://img.icons8.com/officel/50/ios-photos.png", + "index": "web.team.gonganxitong.photo", + "name": "在线相册", + "order": "95", + "time": "2024-11-25 16:22:57.607" + } + }, "8ce4dfb877e04e3be5144253fdd5d8ff": { "meta": { "icons": "https://img.icons8.com/officel/80/receipt-approved.png", @@ -124,7 +142,7 @@ "icons": "https://img.icons8.com/officel/80/online-payment-with-a-credit-card.png", "index": "web.team.gonganxitong.paymentlist", "name": "在线支付", - "order": "92", + "order": "91", "time": "2024-11-22 11:37:54.098" } }, @@ -159,7 +177,7 @@ "icons": "https://img.icons8.com/officel/80/video-conference.png", "index": "web.team.gonganxitong.meeting", "name": "在线会议", - "order": "91", + "order": "92", "role": "leader,worker", "time": "2024-11-19 15:35:47.453" } diff --git a/usr/local/export/web.team.guanlixitong.portal/hash.json b/usr/local/export/web.team.guanlixitong.portal/hash.json index 4d24ea8..bb2de6a 100644 --- a/usr/local/export/web.team.guanlixitong.portal/hash.json +++ b/usr/local/export/web.team.guanlixitong.portal/hash.json @@ -121,6 +121,15 @@ "time": "2024-09-07 08:23:04.061" } }, + "8548d5ce3faee7bd508d2fb53d57f35b": { + "meta": { + "icons": "https://img.icons8.com/officel/50/ios-photos.png", + "index": "web.team.guanlixitong.photo", + "name": "在线相册", + "order": "95", + "time": "2024-11-25 18:11:44.299" + } + }, "9c18032c5bc252f2986e1b20e7e77db7": { "meta": { "icons": "https://img.icons8.com/officel/80/property-with-timer.png", @@ -223,11 +232,21 @@ "time": "2024-08-20 11:07:54.833" } }, + "e2ade31e19fd70911169780be6757fa3": { + "meta": { + "icons": "https://img.icons8.com/officel/80/agreement.png", + "index": "web.team.guanlixitong.contract", + "name": "在线合同", + "order": "94", + "time": "2024-11-25 18:11:44.307" + } + }, "e595a0bbefbcfaa89f45dd875cc6fe0b": { "meta": { - "icons": "https://img.icons8.com/officel/80/upload-link-document.png", + "icons": "https://img.icons8.com/officel/50/documents.png", "index": "web.team.guanlixitong.document", "name": "在线文档", + "order": "93", "time": "2024-11-10 09:43:58.429" } }, diff --git a/usr/local/export/web.team.huodongzuzhi.portal/hash.json b/usr/local/export/web.team.huodongzuzhi.portal/hash.json index 96e0e1e..8c1c77e 100644 --- a/usr/local/export/web.team.huodongzuzhi.portal/hash.json +++ b/usr/local/export/web.team.huodongzuzhi.portal/hash.json @@ -9,6 +9,24 @@ "time": "2024-08-25 12:53:13.205" } }, + "3e9e80db9ae3768b7a44774c7afa5f65": { + "meta": { + "icons": "https://img.icons8.com/officel/80/agreement.png", + "index": "web.team.huodongzuzhi.contract", + "name": "在线合同", + "order": "94", + "time": "2024-11-25 18:11:44.294" + } + }, + "49432b349d456f4108dcfa7d28435bac": { + "meta": { + "icons": "https://img.icons8.com/officel/50/documents.png", + "index": "web.team.huodongzuzhi.document", + "name": "在线文档", + "order": "93", + "time": "2024-11-25 18:19:23.750" + } + }, "595eb34d7ebe62e160c02ed5b127d637": { "meta": { "icons": "https://img.icons8.com/officel/80/test-partial-passed.png", @@ -113,6 +131,15 @@ "time": "2024-11-19 15:35:47.287" } }, + "e5ce14fa8331355abad8cc68c25c74a4": { + "meta": { + "icons": "https://img.icons8.com/officel/50/ios-photos.png", + "index": "web.team.huodongzuzhi.photo", + "name": "在线相册", + "order": "95", + "time": "2024-11-25 18:11:44.292" + } + }, "ed9cb73417ae9e3e63526f1c459e9c7b": { "meta": { "icons": "https://img.icons8.com/officel/80/online-payment-with-a-credit-card.png", diff --git a/usr/local/export/web.team.renzhengshouquan.portal/hash.json b/usr/local/export/web.team.renzhengshouquan.portal/hash.json index 2df8bfe..94b305d 100644 --- a/usr/local/export/web.team.renzhengshouquan.portal/hash.json +++ b/usr/local/export/web.team.renzhengshouquan.portal/hash.json @@ -1,4 +1,14 @@ { + "015b4784c16b63975824abbb3ff4ec9f": { + "meta": { + "enable": "false", + "icons": "https://img.icons8.com/officel/50/ios-photos.png", + "index": "web.team.renzhengshouquan.photo", + "name": "在线相册", + "order": "95", + "time": "2024-11-25 18:11:44.117" + } + }, "0d7f068029dbf7f9f0d307070cc3a79b": { "meta": { "icons": "https://img.icons8.com/officel/80/receipt-approved.png", @@ -9,12 +19,32 @@ "time": "2024-08-29 12:42:12.319" } }, + "1c4fee90e6a7bdb8ab6f1ccb23f3273f": { + "meta": { + "enable": "false", + "icons": "https://img.icons8.com/officel/50/documents.png", + "index": "web.team.renzhengshouquan.document", + "name": "在线文档", + "order": "93", + "time": "2024-11-25 18:19:23.561" + } + }, + "1d15ae175ffe375630da1466417d2d5d": { + "meta": { + "enable": "false", + "icons": "https://img.icons8.com/officel/80/agreement.png", + "index": "web.team.renzhengshouquan.contract", + "name": "在线合同", + "order": "94", + "time": "2024-11-25 18:11:44.121" + } + }, "1d7c44014bc23b3db4551534359c95c4": { "meta": { "icons": "https://img.icons8.com/officel/80/video-conference.png", "index": "web.team.renzhengshouquan.external.tencentmeeting.tencentmeeting", "name": "腾讯会议", - "order": "10", + "order": "12", "role": "leader", "time": "2024-11-19 11:33:13.771" } @@ -69,6 +99,15 @@ "time": "2024-08-29 12:42:12.275" } }, + "692895230d60d29c2a56531f81927efb": { + "meta": { + "icons": "https://img.icons8.com/officel/80/cloud.png", + "index": "web.team.renzhengshouquan.external.tencentcloud.tencentcloud", + "name": "腾讯云", + "order": "15", + "time": "2024-11-25 20:45:31.111" + } + }, "732373815fa26c85ad04dd57ca57db39": { "meta": { "icons": "https://img.icons8.com/officel/80/edit-property.png", @@ -95,7 +134,7 @@ "icons": "https://img.icons8.com/officel/80/online-payment-with-a-credit-card.png", "index": "web.team.renzhengshouquan.paymentlist", "name": "在线支付", - "order": "92", + "order": "91", "time": "2024-11-22 17:42:50.659" } }, @@ -108,6 +147,15 @@ "time": "2024-09-22 20:30:11.224" } }, + "8780d5d1b9b5608cef9098e9393c0cb4": { + "meta": { + "icons": "https://img.icons8.com/officel/80/video-conference.png", + "index": "web.team.renzhengshouquan.external.tencentcloud.realname.realname", + "name": "实名验证", + "order": "16", + "time": "2024-11-26 14:42:04.095" + } + }, "89cf6f6cc69c13b7d541a0d61eae66e1": { "meta": { "icons": "https://img.icons8.com/officel/80/identification-documents--v2.png", @@ -142,6 +190,15 @@ "time": "2024-09-07 08:23:04.033" } }, + "bdf8a62a495ddba04e61bc457ed5fc25": { + "meta": { + "icons": "https://img.icons8.com/officel/80/sms.png", + "index": "web.team.renzhengshouquan.external.tencentcloud.sms.sms", + "name": "发送短信", + "order": "17", + "time": "2024-11-26 20:23:46.898" + } + }, "bfecb55b11fe68186270fe1b4b8de8cf": { "meta": { "icons": "https://img.icons8.com/officel/80/person-at-home.png", @@ -158,7 +215,7 @@ "icons": "https://img.icons8.com/officel/80/video-conference.png", "index": "web.team.renzhengshouquan.meeting", "name": "在线会议", - "order": "91", + "order": "92", "role": "leader,worker", "time": "2024-11-19 15:35:47.185" } diff --git a/usr/local/export/web.team.yuehaoxitong.portal/hash.json b/usr/local/export/web.team.yuehaoxitong.portal/hash.json index ce3fb61..3858965 100644 --- a/usr/local/export/web.team.yuehaoxitong.portal/hash.json +++ b/usr/local/export/web.team.yuehaoxitong.portal/hash.json @@ -8,6 +8,15 @@ "time": "2024-08-11 09:30:00.532" } }, + "182e191dda10c617c12a7c9147737dc6": { + "meta": { + "icons": "https://img.icons8.com/officel/80/agreement.png", + "index": "web.team.yuehaoxitong.contract", + "name": "在线合同", + "order": "94", + "time": "2024-11-25 18:11:44.106" + } + }, "1931ecf1d36391b72df54d374a91c8ed": { "meta": { "icons": "https://img.icons8.com/officel/80/meeting-room.png", @@ -124,6 +133,15 @@ "time": "2024-08-20 11:07:54.887" } }, + "a3d526b8fc09121a7186775cca6d9026": { + "meta": { + "icons": "https://img.icons8.com/officel/50/ios-photos.png", + "index": "web.team.yuehaoxitong.photo", + "name": "在线相册", + "order": "95", + "time": "2024-11-25 18:11:44.112" + } + }, "a56cb18131ff45616849e4555e29d35d": { "meta": { "icons": "https://img.icons8.com/officel/80/edit-property.png", @@ -194,6 +212,15 @@ "time": "2024-08-12 08:56:10.816" } }, + "cb5d53223069ec8d9914ec30ca84ec4a": { + "meta": { + "icons": "https://img.icons8.com/officel/50/documents.png", + "index": "web.team.yuehaoxitong.document", + "name": "在线文档", + "order": "93", + "time": "2024-11-25 18:19:23.441" + } + }, "d1e03d214890c9a4b9557d3f6a36c7e9": { "meta": { "icons": "https://img.icons8.com/officel/80/activity-grid.png",