From 7f012927ca36a819b0a427618024c19953f7c89b Mon Sep 17 00:00:00 2001 From: shy Date: Wed, 20 Nov 2024 22:49:49 +0800 Subject: [PATCH] add some --- src/api/20240724-community.go | 14 ++ src/api/20240724-education.go | 4 + src/api/20240724-enterprise.go | 17 ++ src/api/20240903-operation.go | 7 + src/gonganxitong/common.go | 17 +- src/gonganxitong/meeting.css | 16 ++ src/gonganxitong/meeting.go | 80 +++++++++ src/gonganxitong/meeting.js | 32 ++++ src/gonganxitong/model/model.go | 10 +- src/gonganxitong/portal.css | 2 + src/gonganxitong/portal.go | 2 +- src/gonganxitong/portal.js | 3 +- src/gonganxitong/portal.json | 13 +- src/gonganxitong/setting.go | 7 +- src/option.go | 3 + src/renzhengshouquan/auth.go | 1 + .../external/tencentmeeting/model/model.go | 23 +++ .../external/tencentmeeting/tencentmeeting.go | 157 ++++++++++++++++++ .../external/tencentmeeting/tencentmeeting.js | 8 + .../tencentmeeting/tencentmeeting.json | 13 ++ .../tencentmeeting/tencentmeeting.shy | 7 + 21 files changed, 420 insertions(+), 16 deletions(-) create mode 100644 src/gonganxitong/meeting.css create mode 100644 src/gonganxitong/meeting.go create mode 100644 src/gonganxitong/meeting.js create mode 100644 src/renzhengshouquan/external/tencentmeeting/model/model.go create mode 100644 src/renzhengshouquan/external/tencentmeeting/tencentmeeting.go create mode 100644 src/renzhengshouquan/external/tencentmeeting/tencentmeeting.js create mode 100644 src/renzhengshouquan/external/tencentmeeting/tencentmeeting.json create mode 100644 src/renzhengshouquan/external/tencentmeeting/tencentmeeting.shy diff --git a/src/api/20240724-community.go b/src/api/20240724-community.go index 18b4148..e03dc66 100644 --- a/src/api/20240724-community.go +++ b/src/api/20240724-community.go @@ -3,10 +3,13 @@ package api const GONGANXITONG_PORTAL = "web.team.gonganxitong.portal" const GONGANXITONG_ALLOW = "web.team.gonganxitong.allow" const GONGANXITONG_APPLY = "web.team.gonganxitong.apply" +const GONGANXITONG_CITY = "web.team.gonganxitong.city" +const GONGANXITONG_CREDIT = "web.team.gonganxitong.credit" const GONGANXITONG_DOMAIN = "web.team.gonganxitong.domain" const GONGANXITONG_EMAIL = "web.team.gonganxitong.email" const GONGANXITONG_EVENT = "web.team.gonganxitong.event" const GONGANXITONG_MARKET = "web.team.gonganxitong.market" +const GONGANXITONG_MEETING = "web.team.gonganxitong.meeting" const GONGANXITONG_MEMBER = "web.team.gonganxitong.member" const GONGANXITONG_MESSAGE = "web.team.gonganxitong.message" const GONGANXITONG_NOTICE = "web.team.gonganxitong.notice" @@ -14,13 +17,17 @@ const GONGANXITONG_QRCODE = "web.team.gonganxitong.qrcode" const GONGANXITONG_RECENT = "web.team.gonganxitong.recent" const GONGANXITONG_SERVICE = "web.team.gonganxitong.service" const GONGANXITONG_SETTING = "web.team.gonganxitong.setting" +const GONGANXITONG_STREET = "web.team.gonganxitong.street" const GONGANXITONG_SUPPORT = "web.team.gonganxitong.support" +const GONGANXITONG_USER = "web.team.gonganxitong.user" const HUODONGZUZHI_ACTIVITY = "web.team.huodongzuzhi.activity" const HUODONGZUZHI_PORTAL = "web.team.huodongzuzhi.portal" const HUODONGZUZHI_ALLOW = "web.team.huodongzuzhi.allow" const HUODONGZUZHI_APPLY = "web.team.huodongzuzhi.apply" +const HUODONGZUZHI_CREDIT = "web.team.huodongzuzhi.credit" const HUODONGZUZHI_EVENT = "web.team.huodongzuzhi.event" const HUODONGZUZHI_MARKET = "web.team.huodongzuzhi.market" +const HUODONGZUZHI_MEETING = "web.team.huodongzuzhi.meeting" const HUODONGZUZHI_MEMBER = "web.team.huodongzuzhi.member" const HUODONGZUZHI_MESSAGE = "web.team.huodongzuzhi.message" const HUODONGZUZHI_NOTICE = "web.team.huodongzuzhi.notice" @@ -29,14 +36,19 @@ const HUODONGZUZHI_RECENT = "web.team.huodongzuzhi.recent" const HUODONGZUZHI_SERVICE = "web.team.huodongzuzhi.service" const HUODONGZUZHI_SETTING = "web.team.huodongzuzhi.setting" const HUODONGZUZHI_SUPPORT = "web.team.huodongzuzhi.support" +const RENZHENGSHOUQUAN_ADMIN = "web.team.renzhengshouquan.admin" const RENZHENGSHOUQUAN_PORTAL = "web.team.renzhengshouquan.portal" const RENZHENGSHOUQUAN_ALLOW = "web.team.renzhengshouquan.allow" const RENZHENGSHOUQUAN_APPLY = "web.team.renzhengshouquan.apply" const RENZHENGSHOUQUAN_AUTH = "web.team.renzhengshouquan.auth" const RENZHENGSHOUQUAN_CERT = "web.team.renzhengshouquan.cert" +const RENZHENGSHOUQUAN_CREDIT = "web.team.renzhengshouquan.credit" const RENZHENGSHOUQUAN_DOMAIN = "web.team.renzhengshouquan.domain" const RENZHENGSHOUQUAN_EVENT = "web.team.renzhengshouquan.event" +const RENZHENGSHOUQUAN_EXTERNAL_TENCENT_MEETING = "web.team.renzhengshouquan.external.tencent.meeting" +const RENZHENGSHOUQUAN_EXTERNAL_TENCENTMEETING_TENCENTMEETING = "web.team.renzhengshouquan.external.tencentmeeting.tencentmeeting" const RENZHENGSHOUQUAN_MARKET = "web.team.renzhengshouquan.market" +const RENZHENGSHOUQUAN_MEETING = "web.team.renzhengshouquan.meeting" const RENZHENGSHOUQUAN_MEMBER = "web.team.renzhengshouquan.member" const RENZHENGSHOUQUAN_MESSAGE = "web.team.renzhengshouquan.message" const RENZHENGSHOUQUAN_NOTICE = "web.team.renzhengshouquan.notice" @@ -50,9 +62,11 @@ const YUEHAOXITONG_PORTAL = "web.team.yuehaoxitong.portal" const YUEHAOXITONG_ALLOW = "web.team.yuehaoxitong.allow" const YUEHAOXITONG_APPLY = "web.team.yuehaoxitong.apply" const YUEHAOXITONG_CALL = "web.team.yuehaoxitong.call" +const YUEHAOXITONG_CREDIT = "web.team.yuehaoxitong.credit" const YUEHAOXITONG_EVENT = "web.team.yuehaoxitong.event" const YUEHAOXITONG_HISTORY = "web.team.yuehaoxitong.history" const YUEHAOXITONG_MARKET = "web.team.yuehaoxitong.market" +const YUEHAOXITONG_MEETING = "web.team.yuehaoxitong.meeting" const YUEHAOXITONG_MEMBER = "web.team.yuehaoxitong.member" const YUEHAOXITONG_MESSAGE = "web.team.yuehaoxitong.message" const YUEHAOXITONG_NOTICE = "web.team.yuehaoxitong.notice" diff --git a/src/api/20240724-education.go b/src/api/20240724-education.go index 110fed7..376bf95 100644 --- a/src/api/20240724-education.go +++ b/src/api/20240724-education.go @@ -3,6 +3,7 @@ package api const JIAOCAIZILIAO_PORTAL = "web.team.jiaocaiziliao.portal" const JIAOCAIZILIAO_ALLOW = "web.team.jiaocaiziliao.allow" const JIAOCAIZILIAO_APPLY = "web.team.jiaocaiziliao.apply" +const JIAOCAIZILIAO_CREDIT = "web.team.jiaocaiziliao.credit" const JIAOCAIZILIAO_DOCUMENT = "web.team.jiaocaiziliao.document" const JIAOCAIZILIAO_EVENT = "web.team.jiaocaiziliao.event" const JIAOCAIZILIAO_MARKET = "web.team.jiaocaiziliao.market" @@ -18,6 +19,7 @@ const JIAOCAIZILIAO_SUPPORT = "web.team.jiaocaiziliao.support" const JIAOWUXITONG_PORTAL = "web.team.jiaowuxitong.portal" const JIAOWUXITONG_ALLOW = "web.team.jiaowuxitong.allow" const JIAOWUXITONG_APPLY = "web.team.jiaowuxitong.apply" +const JIAOWUXITONG_CREDIT = "web.team.jiaowuxitong.credit" const JIAOWUXITONG_EVENT = "web.team.jiaowuxitong.event" const JIAOWUXITONG_HOMEWORK = "web.team.jiaowuxitong.homework" const JIAOWUXITONG_MARKET = "web.team.jiaowuxitong.market" @@ -32,6 +34,7 @@ const JIAOWUXITONG_SUPPORT = "web.team.jiaowuxitong.support" const KAOSHIXITONG_PORTAL = "web.team.kaoshixitong.portal" const KAOSHIXITONG_ALLOW = "web.team.kaoshixitong.allow" const KAOSHIXITONG_APPLY = "web.team.kaoshixitong.apply" +const KAOSHIXITONG_CREDIT = "web.team.kaoshixitong.credit" const KAOSHIXITONG_EVENT = "web.team.kaoshixitong.event" const KAOSHIXITONG_MARKET = "web.team.kaoshixitong.market" const KAOSHIXITONG_MEMBER = "web.team.kaoshixitong.member" @@ -46,6 +49,7 @@ const KAOSHIXITONG_SUPPORT = "web.team.kaoshixitong.support" const ZAIXIANKETANG_PORTAL = "web.team.zaixianketang.portal" const ZAIXIANKETANG_ALLOW = "web.team.zaixianketang.allow" const ZAIXIANKETANG_APPLY = "web.team.zaixianketang.apply" +const ZAIXIANKETANG_CREDIT = "web.team.zaixianketang.credit" const ZAIXIANKETANG_EVENT = "web.team.zaixianketang.event" const ZAIXIANKETANG_LESSON = "web.team.zaixianketang.lesson" const ZAIXIANKETANG_MARKET = "web.team.zaixianketang.market" diff --git a/src/api/20240724-enterprise.go b/src/api/20240724-enterprise.go index 3a17f60..b89271a 100644 --- a/src/api/20240724-enterprise.go +++ b/src/api/20240724-enterprise.go @@ -4,6 +4,7 @@ const GONGYINGLIAN_PORTAL = "web.team.gongyinglian.portal" const GONGYINGLIAN_ALLOW = "web.team.gongyinglian.allow" const GONGYINGLIAN_APPLY = "web.team.gongyinglian.apply" const GONGYINGLIAN_BRAND = "web.team.gongyinglian.brand" +const GONGYINGLIAN_CREDIT = "web.team.gongyinglian.credit" const GONGYINGLIAN_EVENT = "web.team.gongyinglian.event" const GONGYINGLIAN_EXPENSE = "web.team.gongyinglian.expense" const GONGYINGLIAN_EXPRESS = "web.team.gongyinglian.express" @@ -11,6 +12,7 @@ const GONGYINGLIAN_GOODS = "web.team.gongyinglian.goods" const GONGYINGLIAN_LOAN = "web.team.gongyinglian.loan" const GONGYINGLIAN_MARKET = "web.team.gongyinglian.market" const GONGYINGLIAN_MATERIAL = "web.team.gongyinglian.material" +const GONGYINGLIAN_MEETING = "web.team.gongyinglian.meeting" const GONGYINGLIAN_MEMBER = "web.team.gongyinglian.member" const GONGYINGLIAN_MESSAGE = "web.team.gongyinglian.message" const GONGYINGLIAN_NOTICE = "web.team.gongyinglian.notice" @@ -33,13 +35,24 @@ const GONGYINGLIAN_WAREHOUSE = "web.team.gongyinglian.warehouse" const GUANLIXITONG_PORTAL = "web.team.guanlixitong.portal" const GUANLIXITONG_ALLOW = "web.team.guanlixitong.allow" const GUANLIXITONG_APPLY = "web.team.guanlixitong.apply" +const GUANLIXITONG_CONFERENCE = "web.team.guanlixitong.conference" +const GUANLIXITONG_CREDIT = "web.team.guanlixitong.credit" +const GUANLIXITONG_DOCUMENT = "web.team.guanlixitong.document" +const GUANLIXITONG_EMPLOYEE = "web.team.guanlixitong.employee" +const GUANLIXITONG_EQUIPMENT = "web.team.guanlixitong.equipment" const GUANLIXITONG_EVENT = "web.team.guanlixitong.event" +const GUANLIXITONG_INTERVIEW = "web.team.guanlixitong.interview" +const GUANLIXITONG_INVENTORY = "web.team.guanlixitong.inventory" const GUANLIXITONG_MARKET = "web.team.guanlixitong.market" +const GUANLIXITONG_MEETING = "web.team.guanlixitong.meeting" const GUANLIXITONG_MEMBER = "web.team.guanlixitong.member" const GUANLIXITONG_MESSAGE = "web.team.guanlixitong.message" const GUANLIXITONG_NOTICE = "web.team.guanlixitong.notice" +const GUANLIXITONG_PROCUREMENT = "web.team.guanlixitong.procurement" const GUANLIXITONG_QRCODE = "web.team.guanlixitong.qrcode" const GUANLIXITONG_RECENT = "web.team.guanlixitong.recent" +const GUANLIXITONG_RECRUITMENT = "web.team.guanlixitong.recruitment" +const GUANLIXITONG_RESUME = "web.team.guanlixitong.resume" const GUANLIXITONG_SERVICE = "web.team.guanlixitong.service" const GUANLIXITONG_SETTING = "web.team.guanlixitong.setting" const GUANLIXITONG_SUPPORT = "web.team.guanlixitong.support" @@ -47,8 +60,10 @@ const GUANLIXITONG_TARGET = "web.team.guanlixitong.target" const SHICHANGYINGXIAO_PORTAL = "web.team.shichangyingxiao.portal" const SHICHANGYINGXIAO_ALLOW = "web.team.shichangyingxiao.allow" const SHICHANGYINGXIAO_APPLY = "web.team.shichangyingxiao.apply" +const SHICHANGYINGXIAO_CREDIT = "web.team.shichangyingxiao.credit" const SHICHANGYINGXIAO_EVENT = "web.team.shichangyingxiao.event" const SHICHANGYINGXIAO_MARKET = "web.team.shichangyingxiao.market" +const SHICHANGYINGXIAO_MEETING = "web.team.shichangyingxiao.meeting" const SHICHANGYINGXIAO_MEMBER = "web.team.shichangyingxiao.member" const SHICHANGYINGXIAO_MESSAGE = "web.team.shichangyingxiao.message" const SHICHANGYINGXIAO_NOTICE = "web.team.shichangyingxiao.notice" @@ -61,9 +76,11 @@ const SHICHANGYINGXIAO_SUPPORT = "web.team.shichangyingxiao.support" const ZIJINLIAN_PORTAL = "web.team.zijinlian.portal" const ZIJINLIAN_ALLOW = "web.team.zijinlian.allow" const ZIJINLIAN_APPLY = "web.team.zijinlian.apply" +const ZIJINLIAN_CREDIT = "web.team.zijinlian.credit" const ZIJINLIAN_EVENT = "web.team.zijinlian.event" const ZIJINLIAN_INVESTMENT = "web.team.zijinlian.investment" const ZIJINLIAN_MARKET = "web.team.zijinlian.market" +const ZIJINLIAN_MEETING = "web.team.zijinlian.meeting" const ZIJINLIAN_MEMBER = "web.team.zijinlian.member" const ZIJINLIAN_MESSAGE = "web.team.zijinlian.message" const ZIJINLIAN_NOTICE = "web.team.zijinlian.notice" diff --git a/src/api/20240903-operation.go b/src/api/20240903-operation.go index a145eb0..7a3dc8d 100644 --- a/src/api/20240903-operation.go +++ b/src/api/20240903-operation.go @@ -3,6 +3,7 @@ package api const DASHBOARD_PORTAL = "web.team.dashboard.portal" const DASHBOARD_ALLOW = "web.team.dashboard.allow" const DASHBOARD_APPLY = "web.team.dashboard.apply" +const DASHBOARD_CREDIT = "web.team.dashboard.credit" const DASHBOARD_DASHBOARD = "web.team.dashboard.dashboard" const DASHBOARD_EVENT = "web.team.dashboard.event" const DASHBOARD_MARKET = "web.team.dashboard.market" @@ -18,13 +19,16 @@ const DASHBOARD_SUPPORT = "web.team.dashboard.support" const DEVELOPMENT_PORTAL = "web.team.development.portal" const DEVELOPMENT_ALLOW = "web.team.development.allow" const DEVELOPMENT_APPLY = "web.team.development.apply" +const DEVELOPMENT_CREDIT = "web.team.development.credit" const DEVELOPMENT_EVENT = "web.team.development.event" +const DEVELOPMENT_HISTORY = "web.team.development.history" const DEVELOPMENT_MARKET = "web.team.development.market" const DEVELOPMENT_MEMBER = "web.team.development.member" const DEVELOPMENT_MESSAGE = "web.team.development.message" const DEVELOPMENT_NOTICE = "web.team.development.notice" const DEVELOPMENT_QRCODE = "web.team.development.qrcode" const DEVELOPMENT_RECENT = "web.team.development.recent" +const DEVELOPMENT_SERVE = "web.team.development.serve" const DEVELOPMENT_SERVICE = "web.team.development.service" const DEVELOPMENT_SETTING = "web.team.development.setting" const DEVELOPMENT_SUPPORT = "web.team.development.support" @@ -32,6 +36,7 @@ const DEVELOPMENT_VERSION = "web.team.development.version" const OPERATION_PORTAL = "web.team.operation.portal" const OPERATION_ALLOW = "web.team.operation.allow" const OPERATION_APPLY = "web.team.operation.apply" +const OPERATION_CREDIT = "web.team.operation.credit" const OPERATION_EVENT = "web.team.operation.event" const OPERATION_MARKET = "web.team.operation.market" const OPERATION_MEMBER = "web.team.operation.member" @@ -47,6 +52,7 @@ const PRODUCTION_PORTAL = "web.team.production.portal" const PRODUCTION_ALLOW = "web.team.production.allow" const PRODUCTION_APPLY = "web.team.production.apply" const PRODUCTION_CASE = "web.team.production.case" +const PRODUCTION_CREDIT = "web.team.production.credit" const PRODUCTION_EVENT = "web.team.production.event" const PRODUCTION_ISSUE = "web.team.production.issue" const PRODUCTION_MARKET = "web.team.production.market" @@ -63,6 +69,7 @@ const PRODUCTION_TASK = "web.team.production.task" const STORAGE_PORTAL = "web.team.storage.portal" const STORAGE_ALLOW = "web.team.storage.allow" const STORAGE_APPLY = "web.team.storage.apply" +const STORAGE_CREDIT = "web.team.storage.credit" const STORAGE_EVENT = "web.team.storage.event" const STORAGE_FILE = "web.team.storage.file" const STORAGE_MARKET = "web.team.storage.market" diff --git a/src/gonganxitong/common.go b/src/gonganxitong/common.go index 65c02d3..eee5753 100644 --- a/src/gonganxitong/common.go +++ b/src/gonganxitong/common.go @@ -25,6 +25,7 @@ type UserPlacer interface { Placer } type Placer interface { + Keys(target ice.Any, k string) string Inputs(m *ice.Message, arg ...string) RewriteAppend(m *ice.Message, arg ...string) *ice.Message TransValue(m *ice.Message, key string, arg ...string) string @@ -35,6 +36,7 @@ type Container interface { type Table struct { db.Table + PLACE_UID string UserPlace UserPlacer Place Placer Street Container @@ -498,16 +500,16 @@ type Tables struct{ Table } func (s Tables) BeforeMigrate(m *ice.Message, arg ...string) {} -func newTable() Table { return Table{UserPlace: userPlace{}, Place: place{}, Street: street{}} } func newTables() Tables { return Tables{Table: newTable()} } +func newTable() Table { return NewTable(userPlace{}, place{}, street{}) } func NewTable(userPlace UserPlacer, place Placer, street Container) Table { - return Table{UserPlace: userPlace, Place: place, Street: street} + return Table{PLACE_UID: place.Keys(place, model.UID), UserPlace: userPlace, Place: place, Street: street} } func NewTables(userPlace UserPlacer, place Placer, street Container) Tables { return Tables{Table: NewTable(userPlace, place, street)} } func NewPortal(userPlace UserPlacer, place Placer, street Container) Portal { - return Portal{Table: Table{UserPlace: userPlace, Place: place, Street: street}} + return Portal{Table: NewTable(userPlace, place, street)} } func (s Portal) getTable() Table { return s.Table } @@ -525,15 +527,16 @@ func PortalCmd(portal ice.Any) { }, cmd.Actions[ice.CTX_INIT].Hand) } cmd("portal", portal) - cmd("search", search{Tables: tables}) + // cmd("search", search{Tables: tables}) + cmd("meeting", meeting{Table: table}) + cmd("credit", credit{Tables: tables}) + cmd("member", member{Tables: tables}) + cmd("setting", setting{Table: table}) cmd("qrcode", qrcode{Tables: tables}) cmd("event", event{Table: table}) cmd("apply", apply{Table: table}) cmd("allow", allow{Table: table}) cmd("notice", notice{Table: table}) - cmd("setting", setting{Table: table}) - cmd("member", member{Tables: tables}) - cmd("credit", credit{Tables: tables}) cmd("market", market{Table: table}) cmd("message", message{Table: table}) cmd("recent", recent{Table: table}) diff --git a/src/gonganxitong/meeting.css b/src/gonganxitong/meeting.css new file mode 100644 index 0000000..5e5aa19 --- /dev/null +++ b/src/gonganxitong/meeting.css @@ -0,0 +1,16 @@ +$fieldset.detail { margin-top:0 !important; height:100%; } +$output.detail { background-color:#2c2e2f !important; text-align:center; height:100% !important; } +$output.detail { background-color:#646566 !important; text-align:center; height:100% !important; } +$output.detail div.detail { border-radius:10px; background-color:var(--output-bg-color); padding:10px 10px 40px; margin:80px auto 10px; max-width:360px; position:relative; } +$output.detail div.title { font-size:20px; } +$output.detail div.meeting_code { font-size:18px; margin:10px; } +$output.detail div.status { color:var(--notice-bg-color); } +$output.detail div.time { border-bottom:dashed 1px gray; font-size:24px; white-space:pre; padding-bottom:20px; display:flex; justify-content:space-around; align-items: center; } +$output.detail div.span_time { color:gray; font-size:12px; } +$output.detail div.span_time div.zone { margin-top:5px; } +$output.detail div.date { color:gray; font-size:12px; margin-top:5px; } +$output.detail div.logo { background-color:white; position:absolute; padding:3px 3px 0; bottom:calc(170px - 23px); left: calc(50% - 23px); } +$output.detail div.logo img { height:40px; } +$output.detail div.action input { border:var(--box-notice); background-color:var(--notice-bg-color); color:var(--notice-fg-color); font-size:18px; height:40px; width:100%; max-width:360px; } +$output.detail img.qrcode { width:200px !important; } +body.width1 $output.detail img.qrcode { border:solid 1px lightgray; border-radius:5px; margin:40px; margin-bottom:10px; } \ No newline at end of file diff --git a/src/gonganxitong/meeting.go b/src/gonganxitong/meeting.go new file mode 100644 index 0000000..8e36ded --- /dev/null +++ b/src/gonganxitong/meeting.go @@ -0,0 +1,80 @@ +package gonganxitong + +import ( + "shylinux.com/x/ice" + kit "shylinux.com/x/toolkits" + + "shylinux.com/x/community/src/api" + "shylinux.com/x/community/src/gonganxitong/model" +) + +type meeting struct { + Table + order string `data:"91"` + fields string `data:"vendor,user_id"` + join string `name:"join" help:"入会" style:"notice" role:"void"` + config string `name:"config place_uid user_id vendor"` +} + +func (s meeting) Init(m *ice.Message, arg ...string) { + m.Design(s.List, "", kit.JoinWord(s.PLACE_UID, "meeting_code", ice.AUTO)) + s.Table.Init(m, arg...) +} +func (s meeting) List(m *ice.Message, arg ...string) { + if !m.WarnNotRight(!s.IsWorker(m)) { + m.Option(s.PLACE_UID, arg[0]) + if s.cmdy(m, s.MeetingList, s.authUID(m, arg...), arg[1:]); m.Length() > 0 { + if len(arg) == 1 { + m.PushAction(s.Join).Display("") + } else if m.IsMobileUA() { + m.Options(ice.MSG_BG, "white").EchoQRCode(m.Append(model.LINK)).Action().Display("").DisplayCSS("") + } else { + m.EchoIFrame(m.Append(model.LINK)).SetAppend().Action() + } + } + } +} + +func (s meeting) Config(m *ice.Message, arg ...string) { + if s.Select(m, model.PLACE_UID, m.Option(model.PLACE_UID)).Length() == 0 { + s.Insert(m, arg...) + } else { + s.Update(m, arg, model.PLACE_UID, m.Option(model.PLACE_UID)) + } +} +func (s meeting) MeetingList(m *ice.Message, arg ...string) { + +} +func (s meeting) Join(m *ice.Message, arg ...string) { + if !m.WarnNotRight(!s.IsWorker(m)) { + m.ProcessOpen(m.Option(model.LINK)) + } +} + +func init() { ice.TeamCtxCmd(meeting{Table: newTable()}) } + +type MeetingVendor interface { + MeetingList(m *ice.Message, arg ...string) +} + +var meetingVendorKey string +var meetingVendorList = map[string]MeetingVendor{} + +func MeetingVendorAdd(key string, vendor MeetingVendor) { + meetingVendorKey, meetingVendorList[key] = key, vendor +} + +func (s meeting) cmdy(m *ice.Message, arg ...ice.Any) *ice.Message { + msg := s.Select(m.Spawn(), model.PLACE_UID, m.Option(s.PLACE_UID)) + return m.Options("user_id", msg.Append("user_id")).Cmdy(append([]ice.Any{kit.Select(meetingVendorKey, msg.Append("vendor"))}, arg...)...) +} +func (s meeting) authUID(m *ice.Message, arg ...string) string { + if msg := m.Cmd(s.Place, s.Select, model.UID, arg[0]); msg.Append(model.AUTH_UID) == "" { + m.Echo("本服务暂未申请认证,请到<用户名片>申请认证") + } else if _msg := m.Cmd(api.RENZHENGSHOUQUAN_AUTH, s.Select, model.UID, msg.Append(model.AUTH_UID)); _msg.Append(model.AUTH_STATUS) != "2" { + m.Echo("本服务认证申请中,请等待审批") + } else { + return m.Cmd(s.Street, s.Select, model.UID, msg.Append(s.Keys(s.Street, model.UID))).Append(model.AUTH_UID) + } + return "" +} diff --git a/src/gonganxitong/meeting.js b/src/gonganxitong/meeting.js new file mode 100644 index 0000000..2235a49 --- /dev/null +++ b/src/gonganxitong/meeting.js @@ -0,0 +1,32 @@ +Volcanos(chat.ONIMPORT, { + _init: function(can, msg) { can.page.ClassList.del(can, can._fields, "detail"), can.page.ClassList.del(can, can._output, "detail") + if (can.Option("meeting_code")) { can.page.ClassList.add(can, can._fields, "detail"), can.page.ClassList.add(can, can._target, "detail") + var start_time = msg.Append("start_time").split(" "), end_time = msg.Append("end_time").split(" ") + can.ui = can.page.Append(can, can._output, [ + {view: "detail", list: [ + {view: ["title", "", msg.Append("subject")]}, + {view: ["meeting_code", "", msg.Append("meeting_code")]}, + {view: ["status", "", "待开始"]}, + {view: "time", list: [ + {view: "start_time", list: [{view: ["hour", "", start_time[1]]}, {view: ["date", "", start_time[0]]}]}, + {view: ["span_time"], list: [{view: ["span", "", "1 小时"]}, {view: ["zone", "", "(GMT+08:00)"]}]}, + {view: "end_time", list: [{view: ["hour", "", end_time[1]]}, {view: ["date", "", end_time[0]]}]}, + ]}, + {view: ["qrcode", "", msg.Result()]}, + {view: ["logo"], list: [{img: "https://meeting.tencent.com/static/imgs/detail/qrcode_icon2x.png"}]}, + {view: ["tips", "", "请使用手机端【腾讯会议App】扫码入会"]}, + ]}, + {view: "action", list: [ + {type: html.INPUT, data: {type: html.BUTTON}, name: "join", value: "入会", onclick: function(event) { + can.runAction(can.request(event, msg.Table()[0]), "join") + }}, + ]}, + ]) + } else { + can.onimport.myView(can, msg, function(value) { return [ + {view: html.TITLE, list: [value.subject, can.onimport.titleAction(can, value)]}, + {view: html.STATUS, list: [value.start_time, "~", value.end_time.split(" ")[1]]}, + ] }) + } + }, +}) \ No newline at end of file diff --git a/src/gonganxitong/model/model.go b/src/gonganxitong/model/model.go index 641547e..01c72e0 100644 --- a/src/gonganxitong/model/model.go +++ b/src/gonganxitong/model/model.go @@ -103,6 +103,7 @@ const ( SCORE = "score" LEVEL = "level" UNIT = "unit" + LINK = "link" ) type Sess struct { @@ -162,6 +163,13 @@ type Notice struct { PlaceUID string `gorm:"type:char(32);index"` UserUID string `gorm:"type:char(32)"` } +type Meeting struct { + db.ModelWithUID + PlaceUID string `gorm:"type:char(32);index"` + UserUID string `gorm:"type:char(32);index"` + Vendor string `gorm:"type:varchar(128)"` + UserID string `gorm:"type:varchar(32)"` +} type Setting struct { db.ModelWithUID PlaceUID string `gorm:"type:char(32);index"` @@ -254,7 +262,7 @@ type Support struct { func init() { db.CmdModels("", &Sess{}, &User{}, &UserPlace{}, &Place{}, &Street{}, &City{}, - &Apply{}, &Allow{}, &Event{}, &Notice{}, &Setting{}, + &Apply{}, &Allow{}, &Event{}, &Notice{}, &Meeting{}, &Setting{}, &Domain{}, &Market{}, &Thumb{}, &Comment{}, &Favor{}, &Command{}, &Message{}, &Recent{}, &Service{}, &Support{}, ) diff --git a/src/gonganxitong/portal.css b/src/gonganxitong/portal.css index 891615a..34ed171 100644 --- a/src/gonganxitong/portal.css +++ b/src/gonganxitong/portal.css @@ -1,6 +1,7 @@ body.dark { --plugin-bg-color:#0d1117; --output-bg-color:#171a22; } body.width1.light { --plugin-bg-color:#f4f5f9; --output-bg-color:#fefefd; } body.width1.light { --plugin-bg-color:#f4f5f9; --output-bg-color:white; } +body.width1.light { --plugin-bg-color:#f3f3f4; --output-bg-color:white; --notice-bg-color:#006fff; } body.width1 fieldset.Action div.input.float { position:static; } body.width1 fieldset.Action div.input.float table { width:100%; } body.width1 div.upload.float div.action { display:flex; } @@ -147,6 +148,7 @@ body:not(.mobile) $output>fieldset.story>div.output div.item.card:not(:hover) { body:not(.width1) $output div.item.card div.title div.action { display:none; } body.en $output>fieldset table.content td:first-child { max-width:180px; width:unset;} $fieldset { box-shadow:none; } +$output div.output>div.code { padding:0; } body.mobile { // overflow:auto !important; } diff --git a/src/gonganxitong/portal.go b/src/gonganxitong/portal.go index 0500bd6..0e918ec 100644 --- a/src/gonganxitong/portal.go +++ b/src/gonganxitong/portal.go @@ -25,7 +25,7 @@ type Portal struct { service service export string `data:"true"` short string `data:"index"` - field string `data:"time,icons,name,index,order,enable,init,type,role,view,public"` + field string `data:"time,icons,name,index,order,enable,init,type,role,view,portal,public"` create string `name:"create index name icons"` list string `name:"list place_uid index uid auto" role:"void"` placeCreate string `name:"placeCreate city_name* street_name* place_name* place_type:select address" icon:"bi bi-plus-square-dotted" role:"void"` diff --git a/src/gonganxitong/portal.js b/src/gonganxitong/portal.js index 1da0c4f..62d519c 100644 --- a/src/gonganxitong/portal.js +++ b/src/gonganxitong/portal.js @@ -120,7 +120,8 @@ Volcanos(chat.ONIMPORT, { var width = (can.ConfWidth()-40)/parseInt((can.ConfWidth()-40)/80); (can.page.tagis(document.body, "body.width1") || can.user.isMobile && !can.user.isLandscape()) && (width = (can.ConfWidth()-40)/5) can.page.Append(can, target, msg.Table(function(value) { if (value.enable == ice.FALSE) { return } - if (value.public && can.page.tagis(can._output, "div.output.public")) { can.onimport.myTitle(can, value.index, value.name, can.ui.mylist) + if ((value.portal || value.public) && can.page.tagis(can._output, "div.output.public")) { + can.onimport.myTitle(can, value.index, value.name, can.ui.mylist) can.onmotion.toggle(can, can.ui.mylist, true) can.onappend.plugin(can, {index: value.index, args: [can.sup.current._uid]}, function(sub) { sub.onexport.output = function(_sub, msg) { diff --git a/src/gonganxitong/portal.json b/src/gonganxitong/portal.json index 009eba3..c6a73ce 100644 --- a/src/gonganxitong/portal.json +++ b/src/gonganxitong/portal.json @@ -1,6 +1,8 @@ { "portal": "用户场景", "placeCreate": "创建", "placeRemove": "删除", - "credit": "用户名片", "member": "组织成员", "setting": "服务配置", "email": "邮箱配置", + "credit": "用户名片", "member": "组织成员", + "meeting": "在线会议", + "setting": "服务配置", "email": "邮箱配置", "qrcode": "场景码", "event": "事件流", "apply": "权限申请", "allow": "权限审批", "notice": "通知公告", "domain": "领域分类", "market": "人民广场", "message": "消息待办", "recent": "最近访问", "service": "服务发现", "support": "客服支持", "cancel": "取消", "submit": "提交", "finish": "完成", "reject": "驳回", "approve": "通过", @@ -9,20 +11,21 @@ "marketInsert": "推广", "commentCreate": "评论", "applyQRCode": "邀请码", "user": "用户信息", "city": "城市信息", "street": "街道信息", "school": "学校信息", "company": "公司信息", "auth": "认证", "authCreate": "认证申请", "authCity": "城市认证", "authPersonal": "个人认证", "authService": "服务认证", "authCompany": "公司认证", - "config": "配置", "code": "编程", "data": "数据", + "config": "配置", "code": "编程", "data": "数据", "cache": "缓存", "icons": { "user": "https://img.icons8.com/officel/80/qr-code.png", "city": "https://img.icons8.com/officel/80/qr-code.png", "street": "https://img.icons8.com/officel/80/qr-code.png", + "meeting": "https://img.icons8.com/officel/80/video-conference.png", + "credit": "https://img.icons8.com/officel/80/passport.png", + "member": "https://img.icons8.com/officel/80/person-at-home.png", + "setting": "https://img.icons8.com/officel/80/settings--v1.png", "qrcode": "https://img.icons8.com/officel/80/qr-code.png", "event": "https://img.icons8.com/officel/80/property-with-timer.png", "apply": "https://img.icons8.com/officel/80/edit-property.png", "allow": "https://img.icons8.com/officel/80/receipt-approved.png", "email": "https://img.icons8.com/officel/80/reading-confirmation.png", "notice": "https://img.icons8.com/officel/80/commercial.png", - "setting": "https://img.icons8.com/officel/80/settings--v1.png", - "member": "https://img.icons8.com/officel/80/person-at-home.png", - "credit": "https://img.icons8.com/officel/80/passport.png", "domain": "https://img.icons8.com/officel/80/categorize.png", "market": "https://img.icons8.com/officel/80/square.png", "message": "https://img.icons8.com/officel/80/test-partial-passed.png", diff --git a/src/gonganxitong/setting.go b/src/gonganxitong/setting.go index 41f8ccc..f384840 100644 --- a/src/gonganxitong/setting.go +++ b/src/gonganxitong/setting.go @@ -22,7 +22,7 @@ type setting struct { func (s setting) Init(m *ice.Message, arg ...string) { s.Table.Init(m, arg...) - s.Create(m, model.NAME, "profile", model.TYPE, "radio") + s.Create(m, model.NAME, SETTING_PROFILE, model.TYPE, SETTING_RADIO) } func (s setting) Create(m *ice.Message, arg ...string) { s.Hash.Create(m, arg...) @@ -48,3 +48,8 @@ func (s setting) List(m *ice.Message, arg ...string) { } func init() { ice.TeamCtxCmd(setting{Table: newTable()}) } + +const ( + SETTING_RADIO = "radio" + SETTING_PROFILE = "profile" +) diff --git a/src/option.go b/src/option.go index 9e797f3..825547d 100644 --- a/src/option.go +++ b/src/option.go @@ -3,4 +3,7 @@ package main import ( _ "shylinux.com/x/ice/devops" _ "shylinux.com/x/mysql-story/src/db/mysql" + + _ "shylinux.com/x/community/src/renzhengshouquan/external/tencentmeeting" + _ "shylinux.com/x/community/src/renzhengshouquan/external/tencentmeeting/model" ) diff --git a/src/renzhengshouquan/auth.go b/src/renzhengshouquan/auth.go index eb966a9..fe205df 100644 --- a/src/renzhengshouquan/auth.go +++ b/src/renzhengshouquan/auth.go @@ -22,6 +22,7 @@ type Auth struct { func (s Auth) List(m *ice.Message, arg ...string) { if len(arg) == 1 { s.Select(m, model.FROM_UID, arg[0]).Action() + m.Sort("auth_status,created_at", []string{"2"}, "str_r") } else if len(arg) == 2 { s.SelectDetail(m, model.FROM_UID, arg[0], model.UID, arg[1]).Action(s.CertList, s.MemberList) } diff --git a/src/renzhengshouquan/external/tencentmeeting/model/model.go b/src/renzhengshouquan/external/tencentmeeting/model/model.go new file mode 100644 index 0000000..a4220f3 --- /dev/null +++ b/src/renzhengshouquan/external/tencentmeeting/model/model.go @@ -0,0 +1,23 @@ +package model + +import "shylinux.com/x/mysql-story/src/db" + +const ( + UID = "uid" + AUTH_UID = "auth_uid" + PLACE_UID = "place_uid" + AVATAR = "avatar" +) + +type Tencentmeeting struct { + db.ModelWithUID + AuthUID string `gorm:"type:char(32);index"` + UserUID string `gorm:"type:char(32)"` + AppID string `gorm:"type:varchar(16)"` + SdkID string `gorm:"type:varchar(16)"` + SecretID string `gorm:"type:varchar(32)"` + SecretKey string `gorm:"type:varchar(64)"` + UserID string `gorm:"type:varchar(32)"` +} + +func init() { db.CmdModels("", &Tencentmeeting{}) } diff --git a/src/renzhengshouquan/external/tencentmeeting/tencentmeeting.go b/src/renzhengshouquan/external/tencentmeeting/tencentmeeting.go new file mode 100644 index 0000000..c8ea9ab --- /dev/null +++ b/src/renzhengshouquan/external/tencentmeeting/tencentmeeting.go @@ -0,0 +1,157 @@ +package tencentmeeting + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "encoding/hex" + "fmt" + "math/rand" + "net/http" + "strconv" + "strings" + "time" + + "shylinux.com/x/community/src/api" + "shylinux.com/x/community/src/gonganxitong" + "shylinux.com/x/community/src/renzhengshouquan" + "shylinux.com/x/community/src/renzhengshouquan/external/tencentmeeting/model" + "shylinux.com/x/ice" + "shylinux.com/x/icebergs/base/web" + kit "shylinux.com/x/toolkits" + + wemeet "github.com/TencentCloud/wemeet-openapi-sdk-go/wemeet_openapi" + wemeetcore "github.com/TencentCloud/wemeet-openapi-sdk-go/wemeet_openapi/core" + meetings "github.com/TencentCloud/wemeet-openapi-sdk-go/wemeet_openapi/service/meetings" +) + +type tencentmeeting struct { + renzhengshouquan.Table + order string `data:"10"` + fields string `data:"auth_uid,user_uid,app_id,sdk_id,secret_id,secret_key,user_id"` + create string `name:"create app_id* sdk_id* secret_id* secret_key* user_id*" role:"leader"` + remove string `name:"remove" role:"leader"` + list string `name:"list auth_uid uid auto" role:"leader"` + config string `name:"config user_id" style:"notice" role:"leader"` +} + +func (s tencentmeeting) Init(m *ice.Message, arg ...string) { + gonganxitong.MeetingVendorAdd(m.PrefixKey(), s) + s.Table.Init(m, arg...) +} +func (s tencentmeeting) Inputs(m *ice.Message, arg ...string) { + switch arg[0] { + case "user_id": + s.UserList(m, m.Option("auth_uid")) + m.Cut("userid", "username") + } +} +func (s tencentmeeting) List(m *ice.Message, arg ...string) { + if len(arg) == 1 { + s.ValueList(m, arg[:1]).Display("") + kit.If(m.Length() > 0, func() { m.Action() }) + } else { + // s.UserList(m, arg[0]) + // return + m.Cmdy(api.RENZHENGSHOUQUAN_AUTH, arg[0]) + m.Table(func(value ice.Maps) { + if renzhengshouquan.AuthStatus(kit.Int(value["auth_status"])) == renzhengshouquan.AuthIssued { + m.PushButton(s.Config) + } else { + m.PushButton() + } + }) + } +} +func (s tencentmeeting) Config(m *ice.Message, arg ...string) { + m.Cmdy(api.GONGANXITONG_MEETING, s.Config, m.OptionSimple(model.PLACE_UID, "user_id"), "vendor", m.PrefixKey()) +} +func (s tencentmeeting) UserList(m *ice.Message, arg ...string) { + s.spide(m, arg[0], "", "users/list", "page", "1", "page_size", "10") + s.parseList(m, "users", "role_code", "role_name", "userid", "username", "avatar_url", "status", "account_version", "user_account_type").RenameAppend("avatar_url", model.AVATAR) +} +func (s tencentmeeting) MeetingList(m *ice.Message, arg ...string) { + s.spide(m, arg[0], "", "meetings", "userid", "$user_id", "instanceid", "1") + s.parseList(m, "meeting_info_list", "subject", "meeting_code", "start_time", "end_time", "join_url").RenameAppend("join_url", "link") +} +func init() { ice.TeamCtxCmd(tencentmeeting{}) } + +func (s tencentmeeting) spide(m *ice.Message, auth_uid, method, api string, arg ...ice.Any) { + arg = append(arg, "operator_id", "$user_id", "operator_id_type", "1") + msg := s.Select(m.Spawn(), model.AUTH_UID, auth_uid) + for i := 0; i < len(arg); i += 2 { + kit.If(arg[i+1] == "$user_id", func() { arg[i+1] = kit.Select(msg.Append("user_id"), m.Option("user_id")) }) + } + method = kit.Select(http.MethodGet, method) + uri := kit.MergeURL("/v1/"+api, arg...) + now := kit.Format(time.Now().Unix()) + nonce := kit.Format(uint64(100000 + rand.New(rand.NewSource(time.Now().UnixNano())).Intn(900000))) + m.Options(web.SPIDE_HEADER, map[string]string{ + "AppId": msg.Append("app_id"), + "SdkId": msg.Append("sdk_id"), + "X-TC-Key": msg.Append("secret_id"), + "X-TC-Nonce": nonce, + "X-TC-Timestamp": now, + "X-TC-Registered": "1", + "X-TC-Signature": doSignature(msg.Append("secret_id"), msg.Append("secret_key"), "GET", nonce, now, uri, ""), + }).Cmdy(web.SPIDE, "dev", web.SPIDE_RAW, http.MethodGet, "https://api.meeting.qq.com"+uri) +} +func (s tencentmeeting) parseList(m *ice.Message, key string, arg ...string) *ice.Message { + if m.IsErr() { + return m + } + kit.For(kit.Value(kit.UnMarshal(m.Result()), key), func(value ice.Map) { + kit.For(arg, func(key string) { + if strings.HasSuffix(key, "_time") { + m.Push(key, strings.TrimSuffix(time.Unix(kit.Int64(value[key]), 0).Format(ice.MOD_TIME), ":00.000")) + } else { + m.Push(key, value[key]) + } + }) + }) + m.SetResult() + // m.Display("/plugin/story/json.js") + return m +} +func doSignature(secretId string, secretKey string, httpMethod string, headerNonce string, headerTimestamp string, requestUri string, requestBody string) string { + headSignStr := fmt.Sprintf("X-TC-Key=%s&X-TC-Nonce=%s&X-TC-Timestamp=%s", secretId, headerNonce, headerTimestamp) + signStr := fmt.Sprintf("%s\n%s\n%s\n%s", httpMethod, headSignStr, requestUri, requestBody) + h := hmac.New(sha256.New, []byte(secretKey)) + h.Write([]byte(signStr)) + sha := hex.EncodeToString(h.Sum([]byte{})) + signBase64 := base64.StdEncoding.EncodeToString([]byte(sha)) + return signBase64 +} + +func (s tencentmeeting) meetingList(m *ice.Message, arg ...string) { + if client, auth, user_id := s.newClient(m, arg[0]); client != nil { + args := []string{user_id, "1", kit.Select("", arg, 1)} + response, err := client.MeetingsApi.V1MeetingsGet(m, &meetings.ApiV1MeetingsGetRequest{Userid: &args[0], Instanceid: &args[1], MeetingCode: &args[2]}, auth) + s.resTable(m, response.Data, err, "meeting_info_list", "subject", "meeting_code", "start_time", "end_time", "join_url").RenameAppend("join_url", "link") + } +} +func (s tencentmeeting) newClient(m *ice.Message, arg ...string) (*wemeet.Client, wemeetcore.RequestOptionFunc, string) { + msg := s.Select(m.Spawn(), model.AUTH_UID, arg[0]) + if msg.Length() == 0 { + m.Echo("请联系公司管理员,配置腾讯会议的账号").Action() + return nil, nil, "" + } + client := wemeet.NewClient(wemeet.WithAppId(msg.Append("app_id")), wemeet.WithSdkId(msg.Append("sdk_id")), wemeet.WithSecret(msg.Append("secret_id"), msg.Append("secret_key"))) + authenticator := &wemeetcore.JWTAuthenticator{Nonce: uint64(100000 + rand.New(rand.NewSource(time.Now().UnixNano())).Intn(900000)), Timestamp: strconv.Itoa(int(time.Now().Unix()))} + return client, wemeetcore.WithJWTAuth(authenticator), kit.Select(msg.Append("user_id"), m.Option("user_id")) +} +func (s tencentmeeting) resTable(m *ice.Message, data ice.Any, err error, key string, arg ...string) *ice.Message { + if m.SetAppend().SetResult(); err != nil { + return m.Echo(kit.Formats(err)) + } + kit.For(kit.Value(kit.UnMarshal(kit.Formats(data)), key), func(value ice.Map) { + kit.For(arg, func(key string) { + if strings.HasSuffix(key, "_time") { + m.Push(key, strings.TrimSuffix(time.Unix(kit.Int64(value[key]), 0).Format(ice.MOD_TIME), ":00.000")) + } else { + m.Push(key, value[key]) + } + }) + }) + return m +} diff --git a/src/renzhengshouquan/external/tencentmeeting/tencentmeeting.js b/src/renzhengshouquan/external/tencentmeeting/tencentmeeting.js new file mode 100644 index 0000000..182abf8 --- /dev/null +++ b/src/renzhengshouquan/external/tencentmeeting/tencentmeeting.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.app_id, "/", value.sdk_id, "/", value.user_id]}, + {view: html.TITLE, list: [value.secret_id]}, + ] }) + }, +}) diff --git a/src/renzhengshouquan/external/tencentmeeting/tencentmeeting.json b/src/renzhengshouquan/external/tencentmeeting/tencentmeeting.json new file mode 100644 index 0000000..8b4bf1b --- /dev/null +++ b/src/renzhengshouquan/external/tencentmeeting/tencentmeeting.json @@ -0,0 +1,13 @@ +{ + "tencentmeeting": "腾讯会议", + "icons": { + "tencentmeeting": "https://img.icons8.com/officel/80/video-conference.png" + }, + "input": { + "app_id": "AppID", + "sdk_id": "SDKID", + "secret_id": "SecretID", + "secret_key": "SecretKey", + "user_id": "UserID" + } +} \ No newline at end of file diff --git a/src/renzhengshouquan/external/tencentmeeting/tencentmeeting.shy b/src/renzhengshouquan/external/tencentmeeting/tencentmeeting.shy new file mode 100644 index 0000000..5a0e10f --- /dev/null +++ b/src/renzhengshouquan/external/tencentmeeting/tencentmeeting.shy @@ -0,0 +1,7 @@ +chapter "腾讯会议" +refer ` +后台 https://meeting.tencent.com/user-center/work-bench +应用 https://meeting.tencent.com/marketplace/corp-created +文档 https://cloud.tencent.com/document/product/1095/83658 +调试 https://meeting.tencent.com/marketplace/restApiTool.html?type=jwt&interface_id=dTRvM3FoUXJWaDlGZndGWTJpR3J0RkNy&replica_id=NE9GdEsx +` \ No newline at end of file