diff --git a/docs-site/docs/android/index.md b/docs-site/docs/android/index.md index 330aa08..a68e5c4 100644 --- a/docs-site/docs/android/index.md +++ b/docs-site/docs/android/index.md @@ -39,13 +39,13 @@ dependencies { ### 2. 初始化 -只需传入 `appId`,服务器地址由 SDK 内置,**无需传 `serverUrl`**。 +只需传入 `appKey`,服务器地址由 SDK 内置,**无需传 `serverUrl`**。 ```kotlin // Application.onCreate() XuqmSDK.initialize( context = this, - appId = "your_app_id", // 在租户平台创建应用后获得 + appKey = "your_app_key", // 在租户平台创建应用后获得 logLevel = LogLevel.WARN, // 可选,DEBUG 开启详细日志 ) ``` diff --git a/docs-site/docs/guide/quickstart.md b/docs-site/docs/guide/quickstart.md index 0644773..a29c428 100644 --- a/docs-site/docs/guide/quickstart.md +++ b/docs-site/docs/guide/quickstart.md @@ -6,7 +6,7 @@ 1. 访问 [XuqmGroup 控制台](https://dev.xuqinmin.com) 2. 注册租户账号,创建应用 -3. 记录 `appId`(即 `appKey`) +3. 记录 `appKey` ## 2. 选择你的平台 @@ -25,7 +25,7 @@ ``` API 地址:https://dev.xuqinmin.com WS 地址:wss://dev.xuqinmin.com/ws/im -演示 AppId:ak_demo_chat +演示 AppKey:ak_demo_chat 演示用户:demo_alice / demo_bob ``` @@ -37,8 +37,9 @@ WS 地址:wss://dev.xuqinmin.com/ws/im ``` 你的业务服务端 - → 持有 appId/appSecret - → 调用 POST /api/im/auth/login?appId=&userId=&nickname= 换取 IM Token + → 持有 appKey/appSecret + → 调用 IM 登录接口换取 IM Token + → 平台内部协议字段由 SDK 和后端自动处理,业务方无需感知 → 返回 Token 给客户端 客户端 SDK diff --git a/docs-site/docs/harmony/index.md b/docs-site/docs/harmony/index.md index e197732..fc461ef 100644 --- a/docs-site/docs/harmony/index.md +++ b/docs-site/docs/harmony/index.md @@ -44,11 +44,7 @@ import { XuqmSDK } from '@xuqm/harmony-sdk' export default class EntryAbility extends UIAbility { onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { XuqmSDK.init({ - appId: 'your_app_id', - appKey: 'your_app_id', - appSecret: 'your_app_secret', - apiBaseUrl: 'https://dev.xuqinmin.com', - imWsUrl: 'wss://dev.xuqinmin.com/ws/im', + appKey: 'your_app_key', debug: true, }) } @@ -113,8 +109,8 @@ const sent = await ImSDK.sendMessage({ toId: group.id, chatType: 'GROUP', msgTyp import { UpdateSDK } from '@xuqm/harmony-sdk' const appInfo = await UpdateSDK.checkAppUpdate(1) -if (appInfo?.forceUpdate) { - // 跳转应用市场 +if (appInfo?.marketUrl) { + await UpdateSDK.openAppMarket(getContext(this), appInfo.marketUrl) } const bundle = await UpdateSDK.checkRNUpdate('home', '1.0.0') @@ -124,6 +120,8 @@ if (bundle) { } ``` +Harmony 的整包更新只提供应用市场跳转,不提供本地安装包下载。 + ## ArkUI 示例 ```typescript diff --git a/docs-site/docs/ios/index.md b/docs-site/docs/ios/index.md index 73e27c0..7cdffaa 100644 --- a/docs-site/docs/ios/index.md +++ b/docs-site/docs/ios/index.md @@ -52,10 +52,8 @@ dependencies: [ import XuqmCore XuqmSDK.shared.initialize( - appKey: "your_app_id", + appKey: "your_app_key", appSecret: "your_app_secret", - apiBaseUrl: "https://dev.xuqinmin.com", - imWsUrl: "wss://dev.xuqinmin.com/ws/im", debug: false ) ``` @@ -65,7 +63,7 @@ XuqmSDK.shared.initialize( ```swift import XuqmIM -// 登录(appId 已在 init 时指定) +// 登录(appKey 已在 init 时指定) try await ImSDK.shared.login(userId: "user_001", nickname: "张三") // 监听事件 diff --git a/docs-site/docs/rn/index.md b/docs-site/docs/rn/index.md index 378cc07..1898be5 100644 --- a/docs-site/docs/rn/index.md +++ b/docs-site/docs/rn/index.md @@ -2,7 +2,7 @@ **包名**:`@xuqm/rn-sdk` · **版本**:0.3.x(v0.4.0 规划中,将引入 UserSig 鉴权) -> **注意**:v0.4.0 将是 Breaking 版本。`initialize()` 将移除 `serverUrl` 参数,`login()` 将改为 UserSig 鉴权模式,详见[迁移指南](#迁移指南-v03x--v04x)。 +> **注意**:v0.4.0 将是 Breaking 版本。`initialize()` 将只保留 `appKey`,`login()` 将改为 UserSig 鉴权模式,详见[迁移指南](#迁移指南-v03x--v04x)。 --- @@ -38,14 +38,14 @@ yarn add @xuqm/rn-sdk ### 1. 初始化 -初始化只需传入 `appId`,服务器地址由 SDK 内置,**不需要传 `serverUrl`**。 +初始化只需传入 `appKey`,平台地址由 SDK 内置,开发者无需额外配置。 ```ts import { XuqmSDK } from '@xuqm/rn-sdk' // App 入口(如 App.tsx 的顶层) await XuqmSDK.initialize({ - appId: 'your_app_id', // 在租户平台创建应用后获得 + appKey: 'your_app_key', // 在租户平台创建应用后获得 logLevel: __DEV__ ? 'debug' : 'warn', // 可选 }) ``` @@ -247,14 +247,14 @@ v0.4.0 预计改动(**Breaking Changes**): ```diff // 初始化 -- await XuqmSDK.initialize({ appId: 'xxx', serverUrl: 'https://...' }) -+ await XuqmSDK.initialize({ appId: 'xxx' }) // serverUrl 内置,无需传入 +- await XuqmSDK.initialize({ appKey: 'xxx', /* 平台地址参数已移除 */ }) ++ await XuqmSDK.initialize({ appKey: 'xxx' }) // 平台地址内置,无需传入 // IM 登录(改为 UserSig 鉴权,密码不再传入 SDK) - await ImSDK.login(userId, nickname, avatar, dbName) + const userSig = await yourServer.getUserSig(userId) // 您的服务端签发 + await ImSDK.login(userId, userSig, { nickname, avatar }) -// dbName 自动由 appId + userId 派生,无需传入 +// dbName 自动由 appKey + userId 派生,无需传入 // loginWithToken 废弃 - await ImSDK.loginWithToken(userId, token, dbName) @@ -267,14 +267,14 @@ UserSig 生成方式见[安全设计文档](../../design/02-security-design.md) ## 常见问题 -**Q: 如何获取 appId?** -在 [租户平台](https://dev.xuqinmin.com) 注册账号后,创建应用即可获得 AppId。 +**Q: 如何获取 appKey?** +在 [租户平台](https://dev.xuqinmin.com) 注册账号后,创建应用即可获得 AppKey。 -**Q: 为什么不需要传 serverUrl?** +**Q: 为什么不需要传平台地址参数?** XuqmGroup 是托管平台,服务地址统一管理,与腾讯云 IM 等平台的设计一致,开发者只需关心业务逻辑。 **Q: UserSig 是什么?(v0.4.0)** UserSig 是您的业务服务端用 AppSecret 为用户签发的安全凭证,有效期可配置。AppSecret 绝不下发到客户端。 **Q: 本地消息存储在哪里?** -使用 WatermelonDB(SQLite),按 `appId + userId` 自动隔离,多账号切换安全。 +使用 WatermelonDB(SQLite),按 `appKey + userId` 自动隔离,多账号切换安全。 diff --git a/docs-site/docs/vue3/index.md b/docs-site/docs/vue3/index.md index c409c8d..4a7e77f 100644 --- a/docs-site/docs/vue3/index.md +++ b/docs-site/docs/vue3/index.md @@ -35,11 +35,7 @@ import App from './App.vue' const app = createApp(App) app.use(createXuqm({ - appId: 'your_app_id', - appKey: 'your_app_id', - appSecret: 'your_app_secret', - apiBaseUrl: 'https://dev.xuqinmin.com', - imWsUrl: 'wss://dev.xuqinmin.com/ws/im', + appKey: 'your_app_key', debug: import.meta.env.DEV, })) diff --git a/tenant-platform/components.d.ts b/tenant-platform/components.d.ts index 03b9d96..a4bd537 100644 --- a/tenant-platform/components.d.ts +++ b/tenant-platform/components.d.ts @@ -21,6 +21,7 @@ declare module 'vue' { ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem'] ElDialog: typeof import('element-plus/es')['ElDialog'] ElDivider: typeof import('element-plus/es')['ElDivider'] + ElDrawer: typeof import('element-plus/es')['ElDrawer'] ElDropdown: typeof import('element-plus/es')['ElDropdown'] ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] diff --git a/tenant-platform/src/api/im.ts b/tenant-platform/src/api/im.ts index 30c5e2c..38a7254 100644 --- a/tenant-platform/src/api/im.ts +++ b/tenant-platform/src/api/im.ts @@ -103,25 +103,6 @@ export interface OperationLog { createdAt: number } -export interface FriendRequest { - id: string - appId: string - fromUserId: string - toUserId: string - remark?: string | null - status: 'PENDING' | 'ACCEPTED' | 'REJECTED' - createdAt: number - reviewedAt?: number | null -} - -export interface BlacklistEntry { - id: string - appId: string - userId: string - blockedUserId: string - createdAt: number -} - export interface KeywordFilter { id: string appId: string @@ -227,76 +208,6 @@ export const imAdminApi = { }) }, - listFriendRequests(appId: string) { - return imClient.get<{ data: FriendRequest[] }>('/api/im/admin/friend-requests', { - params: { appId }, - }) - }, - - sendFriendRequest(appId: string, toUserId: string, remark?: string) { - return imClient.post<{ data: FriendRequest }>( - '/api/im/friend-requests', - null, - { - params: { - appId, - toUserId, - ...(remark ? { remark } : {}), - }, - }, - ) - }, - - createFriendRequest(appId: string, fromUserId: string, toUserId: string, remark?: string) { - return imClient.post<{ data: FriendRequest }>( - '/api/im/admin/friend-requests', - { - fromUserId, - toUserId, - ...(remark ? { remark } : {}), - }, - { - params: { appId }, - }, - ) - }, - - acceptFriendRequest(appId: string, requestId: string) { - return imClient.post<{ data: FriendRequest }>( - `/api/im/admin/friend-requests/${encodeURIComponent(requestId)}/accept`, - null, - { params: { appId } }, - ) - }, - - rejectFriendRequest(appId: string, requestId: string) { - return imClient.post<{ data: FriendRequest }>( - `/api/im/admin/friend-requests/${encodeURIComponent(requestId)}/reject`, - null, - { params: { appId } }, - ) - }, - - listBlacklist(appId: string) { - return imClient.get<{ data: BlacklistEntry[] }>('/api/im/admin/blacklist', { - params: { appId }, - }) - }, - - addBlacklist(appId: string, userId: string, blockedUserId: string) { - return imClient.post<{ data: BlacklistEntry }>( - '/api/im/admin/blacklist', - { userId, blockedUserId }, - { params: { appId } }, - ) - }, - - removeBlacklist(appId: string, userId: string, blockedUserId: string) { - return imClient.delete<{ data: null }>('/api/im/admin/blacklist', { - params: { appId, userId, blockedUserId }, - }) - }, - listKeywordFilters(appId: string) { return imClient.get<{ data: KeywordFilter[] }>('/api/im/admin/keyword-filters', { params: { appId }, diff --git a/tenant-platform/src/api/update.ts b/tenant-platform/src/api/update.ts index 4c6d445..0657eb4 100644 --- a/tenant-platform/src/api/update.ts +++ b/tenant-platform/src/api/update.ts @@ -44,7 +44,7 @@ export interface StoreConfig { export interface AppVersion { id: string appId: string - platform: 'ANDROID' | 'IOS' + platform: 'ANDROID' | 'IOS' | 'HARMONY' versionName: string versionCode: number packageName?: string @@ -65,7 +65,7 @@ export interface AppVersion { } export interface AppPackageInspectResult { - platform: 'ANDROID' | 'IOS' + platform: 'ANDROID' | 'IOS' | 'HARMONY' packageName?: string versionName?: string versionCode?: number @@ -77,10 +77,11 @@ export interface RnBundle { id: string appId: string moduleId: string - platform: 'ANDROID' | 'IOS' + platform: 'ANDROID' | 'IOS' | 'HARMONY' version: string md5: string minCommonVersion?: string + packageName?: string note?: string publishStatus: 'DRAFT' | 'PUBLISHED' | 'DEPRECATED' grayEnabled: boolean @@ -90,30 +91,34 @@ export interface RnBundle { export interface RnBundleInspectResult { moduleId?: string - platform?: 'ANDROID' | 'IOS' + platform?: 'ANDROID' | 'IOS' | 'HARMONY' version?: string minCommonVersion?: string + packageName?: string fileName?: string detected: boolean } export interface UnifiedAppUploadItem { fileKey: string - platform: 'ANDROID' | 'IOS' + platform: 'ANDROID' | 'IOS' | 'HARMONY' versionName: string versionCode: number changeLog?: string forceUpdate: boolean + packageName?: string appStoreUrl?: string marketUrl?: string + publishImmediately: boolean } export interface UnifiedRnUploadItem { fileKey: string moduleId: string - platform: 'ANDROID' | 'IOS' + platform: 'ANDROID' | 'IOS' | 'HARMONY' version: string minCommonVersion?: string + packageName?: string note?: string } @@ -123,7 +128,7 @@ export interface UnifiedReleaseManifest { } export const updateAdminApi = { - listAppVersions(appId: string, platform: 'ANDROID' | 'IOS') { + listAppVersions(appId: string, platform: 'ANDROID' | 'IOS' | 'HARMONY') { return updateClient.get<{ data: AppVersion[] }>('/api/v1/updates/app/list', { params: { appId, platform }, }) diff --git a/tenant-platform/src/router/index.ts b/tenant-platform/src/router/index.ts index f8c3680..456ff74 100644 --- a/tenant-platform/src/router/index.ts +++ b/tenant-platform/src/router/index.ts @@ -53,6 +53,10 @@ const router = createRouter({ path: 'apps/:appId/update', component: () => import('@/views/update/VersionManagementView.vue'), }, + { + path: 'apps/:appId/update-guide', + component: () => import('@/views/update/StoreGuideView.vue'), + }, { path: 'accounts', component: () => import('@/views/accounts/SubAccountView.vue'), diff --git a/tenant-platform/src/views/im/ImManagementView.vue b/tenant-platform/src/views/im/ImManagementView.vue index 6d703a3..93e5dd5 100644 --- a/tenant-platform/src/views/im/ImManagementView.vue +++ b/tenant-platform/src/views/im/ImManagementView.vue @@ -117,86 +117,6 @@ - -
-
- 发起申请 - 刷新 -
- - - - - - -
- - - - - - - - - - - - - - - - - - -
- - -
-
- 新增黑名单 - 刷新 -
-
- - - - - - - - - - - -
-
@@ -719,50 +639,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - (null) const webhookForm = ref({ url: '', secret: '', enabled: true }) -const friendRequests = ref([]) -const loadingFriendRequests = ref(false) -const friendRequestStatusFilter = ref<'ALL' | 'PENDING' | 'ACCEPTED' | 'REJECTED'>('ALL') -const showSendFriendRequest = ref(false) -const submittingSendFriendRequest = ref(false) -const sendFriendRequestForm = ref({ toUserId: '', remark: '' }) - -const blacklist = ref([]) -const loadingBlacklist = ref(false) -const showBlacklistDialog = ref(false) -const submittingBlacklist = ref(false) -const blacklistForm = ref({ userId: '', blockedUserId: '' }) - const keywordFilters = ref([]) const loadingKeywordFilters = ref(false) const showKeywordFilterDialog = ref(false) @@ -980,13 +836,6 @@ const statCards = computed(() => [ { label: '今日消息', value: stats.value?.todayMessages ?? '-' }, ]) -const filteredFriendRequests = computed(() => { - if (friendRequestStatusFilter.value === 'ALL') { - return friendRequests.value - } - return friendRequests.value.filter(item => item.status === friendRequestStatusFilter.value) -}) - const globalMuteEnabled = computed({ get: () => globalMute.value?.enabled ?? false, set: (enabled: boolean) => { @@ -1145,19 +994,6 @@ function resetEditGroupForm() { } } -function resetSendFriendRequestForm() { - sendFriendRequestForm.value = { toUserId: '', remark: '' } -} - -function resetBlacklistForm() { - blacklistForm.value = { userId: '', blockedUserId: '' } -} - -function openBlacklistDialog() { - resetBlacklistForm() - showBlacklistDialog.value = true -} - function resetKeywordFilterForm() { editingKeywordFilterId.value = null keywordFilterForm.value = { @@ -1307,30 +1143,6 @@ async function loadWebhooks() { } } -async function loadFriendRequests() { - loadingFriendRequests.value = true - try { - const res = await imAdminApi.listFriendRequests(appKey.value) - friendRequests.value = res.data.data - } catch { - ElMessage.error('加载好友申请失败') - } finally { - loadingFriendRequests.value = false - } -} - -async function loadBlacklist() { - loadingBlacklist.value = true - try { - const res = await imAdminApi.listBlacklist(appKey.value) - blacklist.value = res.data.data - } catch { - ElMessage.error('加载黑名单失败') - } finally { - loadingBlacklist.value = false - } -} - async function loadKeywordFilters() { loadingKeywordFilters.value = true try { @@ -1492,11 +1304,6 @@ async function muteManagedGroupMember(user: ImUser) { ElMessage.success('成员已禁言') } -function openFriendRequestDialog() { - resetSendFriendRequestForm() - showSendFriendRequest.value = true -} - async function toggleGlobalMute() { savingGlobalMute.value = true try { @@ -1511,40 +1318,6 @@ async function toggleGlobalMute() { } } -async function submitBlacklist() { - if (!blacklistForm.value.userId.trim() || !blacklistForm.value.blockedUserId.trim()) { - ElMessage.warning('请填写双方用户ID') - return - } - submittingBlacklist.value = true - try { - await imAdminApi.addBlacklist( - appKey.value, - blacklistForm.value.userId.trim(), - blacklistForm.value.blockedUserId.trim(), - ) - ElMessage.success('黑名单已添加') - showBlacklistDialog.value = false - resetBlacklistForm() - loadBlacklist() - } catch { - ElMessage.error('添加黑名单失败') - } finally { - submittingBlacklist.value = false - } -} - -async function removeBlacklist(row: BlacklistEntry) { - await ElMessageBox.confirm(`确认移除 ${row.userId} -> ${row.blockedUserId} 的黑名单?`, '移除黑名单', { - type: 'warning', - confirmButtonText: '确认', - cancelButtonText: '取消', - }) - await imAdminApi.removeBlacklist(appKey.value, row.userId, row.blockedUserId) - ElMessage.success('黑名单已移除') - loadBlacklist() -} - async function submitKeywordFilter() { if (!keywordFilterForm.value.pattern.trim()) { ElMessage.warning('请填写命中词') @@ -1586,29 +1359,6 @@ async function deleteKeywordFilter(row: KeywordFilter) { loadKeywordFilters() } -async function submitFriendRequest() { - if (!sendFriendRequestForm.value.toUserId.trim()) { - ElMessage.warning('请填写接收人ID') - return - } - submittingSendFriendRequest.value = true - try { - await imAdminApi.sendFriendRequest( - appKey.value, - sendFriendRequestForm.value.toUserId.trim(), - sendFriendRequestForm.value.remark.trim() || undefined, - ) - ElMessage.success('好友申请已发送') - showSendFriendRequest.value = false - resetSendFriendRequestForm() - loadFriendRequests() - } catch { - ElMessage.error('发送失败') - } finally { - submittingSendFriendRequest.value = false - } -} - async function searchMessages() { await loadMessages(0) } @@ -1692,28 +1442,6 @@ async function revokeMessage(message: ImMessage) { loadMessages(historyPage.value) } -async function approveFriend(request: FriendRequest) { - await ElMessageBox.confirm(`确认同意好友申请 ${request.fromUserId} -> ${request.toUserId}?`, '同意好友申请', { - type: 'warning', - confirmButtonText: '确认', - cancelButtonText: '取消', - }) - await imAdminApi.acceptFriendRequest(appKey.value, request.id) - ElMessage.success('已同意好友申请') - loadFriendRequests() -} - -async function declineFriend(request: FriendRequest) { - await ElMessageBox.confirm(`确认拒绝好友申请 ${request.fromUserId} -> ${request.toUserId}?`, '拒绝好友申请', { - type: 'warning', - confirmButtonText: '确认', - cancelButtonText: '取消', - }) - await imAdminApi.rejectFriendRequest(appKey.value, request.id) - ElMessage.success('已拒绝好友申请') - loadFriendRequests() -} - async function approveGroupJoin(request: GroupJoinRequest) { const groupId = managedGroup.value?.id || groupRequestGroupId.value.trim() if (!groupId) { @@ -1872,10 +1600,6 @@ async function submitEditGroup() { function handleTabChange(tab: string) { if (tab === 'groups' && groups.value.length === 0) { loadGroups() - } else if (tab === 'friendRequests' && friendRequests.value.length === 0) { - loadFriendRequests() - } else if (tab === 'blacklist' && blacklist.value.length === 0) { - loadBlacklist() } else if (tab === 'governance') { if (keywordFilters.value.length === 0) { loadKeywordFilters() diff --git a/tenant-platform/src/views/update/StoreGuideView.vue b/tenant-platform/src/views/update/StoreGuideView.vue new file mode 100644 index 0000000..29cdf80 --- /dev/null +++ b/tenant-platform/src/views/update/StoreGuideView.vue @@ -0,0 +1,157 @@ + + + + + diff --git a/tenant-platform/src/views/update/VersionManagementView.vue b/tenant-platform/src/views/update/VersionManagementView.vue index dfd8a11..bb4aa09 100644 --- a/tenant-platform/src/views/update/VersionManagementView.vue +++ b/tenant-platform/src/views/update/VersionManagementView.vue @@ -10,8 +10,10 @@ Android iOS + Harmony 上传新版本 + 应用配置指引 刷新
@@ -275,34 +277,43 @@ - - 基础信息 - - - - - - - - - - - - - - - - 选择文件 - - - - 发版配置 - + + 基础信息 + + + + + + + + + + + + + + + + + 选择文件 + + + + + 发版配置 + - + - - - 上传后立即让服务端提交已配置的应用商店 - - - - {{ s.label }} - - 与定时发布互斥 + + + + + +