diff --git a/docs-site/docs/.vitepress/config.ts b/docs-site/docs/.vitepress/config.ts index e461286..3821e2d 100644 --- a/docs-site/docs/.vitepress/config.ts +++ b/docs-site/docs/.vitepress/config.ts @@ -69,6 +69,8 @@ export default defineConfig({ ], '/flutter/': [ { text: '概览', link: '/flutter/' }, + { text: '安装配置', link: '/flutter/setup' }, + { text: 'IM 接入', link: '/flutter/im' }, ], '/harmony/': [ { text: '概览', link: '/harmony/' }, @@ -79,9 +81,13 @@ export default defineConfig({ ], '/miniprogram/': [ { text: '概览', link: '/miniprogram/' }, + { text: '安装配置', link: '/miniprogram/setup' }, + { text: 'IM 接入', link: '/miniprogram/im' }, ], '/h5/': [ { text: '概览', link: '/h5/' }, + { text: '安装配置', link: '/h5/setup' }, + { text: 'IM 接入', link: '/h5/im' }, ], '/server/': [ { text: 'API 速查', link: '/server/api' }, diff --git a/docs-site/docs/flutter/im.md b/docs-site/docs/flutter/im.md new file mode 100644 index 0000000..7ce902d --- /dev/null +++ b/docs-site/docs/flutter/im.md @@ -0,0 +1,183 @@ +# Flutter IM 接入 + +**模块**:`xuqm_flutter_im` · **最低版本**:Dart 3.0+ + +--- + +## 登录 + +```dart +import 'package:xuqm_flutter_sdk/xuqm_flutter_sdk.dart'; + +await XuqmImSdk().login('user_001', 'your_user_sig_jwt'); +``` + +登录成功后会自动建立 IM 实时连接。 + +--- + +## 监听消息 + +```dart +final im = XuqmImSdk(); + +im.ws.onConnected = () { + print('IM 已连接'); +}; + +im.ws.onMessage = (XuqmImMessage msg) { + print('收到消息: ${msg.msgType} - ${msg.content}'); +}; + +im.ws.onDisconnected = (String? reason) { + print('IM 断开: $reason'); +}; +``` + +--- + +## 发送消息 + +```dart +// 发送文本消息 +final msg = await im.sendTextMessage( + 'user_002', + 'SINGLE', + 'Hello from Flutter!', +); + +// 发送图片消息 +final imgMsg = await im.sendMessage( + 'user_002', + 'SINGLE', + 'IMAGE', + jsonEncode({'url': 'https://cdn.example.com/img.jpg', 'width': 800, 'height': 600}), +); + +// 撤回消息 +await im.revokeMessage(msg.id); + +// 编辑消息 +await im.editMessage(msg.id, '新内容'); +``` + +--- + +## 会话管理 + +```dart +// 会话列表 +final conversations = await im.listConversations(); + +// 置顶会话 +await im.setConversationPinned('user_002', 'SINGLE', true); + +// 免打扰 +await im.setConversationMuted('group_xxx', 'GROUP', true); + +// 标记已读 +await im.markRead('user_002'); + +// 设置草稿 +await im.setDraft('user_002', 'SINGLE', '未完成的消息'); +``` + +--- + +## 好友与群组 + +```dart +// 好友列表 +final friends = await im.listFriends(); + +// 添加好友 +await im.addFriend('user_002'); + +// 移除好友 +await im.removeFriend('user_002'); + +// 创建群组 +final group = await im.createGroup('Flutter 群', ['user_001', 'user_002']); + +// 群组列表 +final groups = await im.listGroups(); + +// 添加群成员 +await im.addGroupMember(group.id, 'user_003'); + +// 退出群聊 +await im.leaveGroup(group.id); +``` + +--- + +## 历史消息 + +```dart +// 单聊历史 +final history = await im.fetchHistory('user_002', page: 0, size: 20); + +// 群聊历史 +final groupHistory = await im.fetchGroupHistory('group_xxx', page: 0, size: 50); + +// 定位消息所在页 +final page = await im.locateHistoryPage( + 'user_002', + messageId: 'msg_xxx', + pageSize: 20, +); +``` + +--- + +## 完整示例 + +```dart +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:xuqm_flutter_sdk/xuqm_flutter_sdk.dart'; + +class ChatPage extends StatefulWidget { + @override + _ChatPageState createState() => _ChatPageState(); +} + +class _ChatPageState extends State { + final im = XuqmImSdk(); + final List messages = []; + + @override + void initState() { + super.initState(); + _init(); + } + + Future _init() async { + await XuqmSDK.initialize(XuqmInitOptions(appKey: 'your_app_key')); + await im.login('user_001', 'your_user_sig_jwt'); + + im.ws.onMessage = (msg) { + setState(() => messages.add(msg)); + }; + } + + Future _send(String text) async { + final msg = await im.sendTextMessage('user_002', 'SINGLE', text); + setState(() => messages.add(msg)); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text('Flutter IM')), + body: ListView.builder( + itemCount: messages.length, + itemBuilder: (context, index) { + final msg = messages[index]; + return ListTile(title: Text('${msg.fromId}: ${msg.content}')); + }, + ), + ); + } +} +``` diff --git a/docs-site/docs/flutter/setup.md b/docs-site/docs/flutter/setup.md new file mode 100644 index 0000000..b61340b --- /dev/null +++ b/docs-site/docs/flutter/setup.md @@ -0,0 +1,68 @@ +# Flutter 安装配置 + +**包名**:`xuqm_flutter_sdk` · **版本**:0.2.x · **语言**:Dart + +--- + +## 安装 + +SDK 通过 Gitea Git 仓库发布,在 `pubspec.yaml` 中配置: + +```yaml +dependencies: + xuqm_flutter_sdk: + git: + url: https://xuqinmin.com/xuqinmin12/XuqmGroup-FlutterSDK.git + ref: v0.2.0 +``` + +> Gitea Package Registry 暂不支持 Dart/Flutter 包格式,因此通过 Git Tag 方式发布。 + +--- + +## 模块说明 + +| 模块 | 包 | 功能 | +|------|-----|------| +| `xuqm_flutter_common` | `packages/common` | 初始化、网络、配置管理 | +| `xuqm_flutter_im` | `packages/im` | 单聊、群聊、消息收发、会话、好友、群组 | +| `xuqm_flutter_push` | `packages/push` | 设备 Token 注册、厂商检测(Android)/ APNs(iOS)| +| `xuqm_flutter_update` | `packages/update` | App 版本检查、商店跳转、APK 下载(Android)| + +--- + +## 初始化 + +```dart +import 'package:xuqm_flutter_sdk/xuqm_flutter_sdk.dart'; + +await XuqmSDK.initialize(XuqmInitOptions( + appKey: 'your_app_key', + debug: true, +)); +``` + +初始化时会自动向服务端请求远程配置(IM API 地址等),若网络异常则回退到内置默认值。 + +--- + +## 多模块统一登录 + +无论集成了哪些模块(IM、Push、Update),**初始化和登录永远只做一次**: + +```dart +// 初始化 +await XuqmSDK.initialize(XuqmInitOptions(appKey: 'your_app_key')); + +// 登录(业务登录成功后调用一次) +await XuqmImSdk().login('user_001', 'your_user_sig_jwt'); + +// 登出 +await XuqmImSdk().logout(); +``` + +--- + +## 下一步 + +- [Flutter IM 接入 →](./im) diff --git a/docs-site/docs/h5/im.md b/docs-site/docs/h5/im.md new file mode 100644 index 0000000..6bf7c6a --- /dev/null +++ b/docs-site/docs/h5/im.md @@ -0,0 +1,156 @@ +# H5 IM 接入 + +**模块**:`@xuqm/h5-sdk` · **功能范围**:消息收发、会话管理、好友、群组 + +--- + +## IM 管理器 + +```typescript +import { ImManager } from '@xuqm/h5-sdk' + +const im = new ImManager() + +// 监听连接状态 +im.on('connected', () => console.log('IM 已连接')) +im.on('disconnected', () => console.log('IM 已断开')) + +// 监听实时消息 +im.on('messages', (msgs) => { + console.log('收到消息', msgs) +}) + +// 监听会话列表变化 +im.on('conversations', (convs) => { + console.log('会话列表更新', convs) +}) + +// 开始连接 +im.connect() +``` + +--- + +## 发送消息 + +```typescript +// 发送文本 +im.send({ + toId: 'user_002', + chatType: 'SINGLE', + msgType: 'TEXT', + content: 'Hello H5!', +}) +``` + +### 发送文件消息(自动上传) + +SDK 内部自动上传文件到文件服务器,无需调用方手动上传。 + +```typescript +import { sendImageMessage, sendFileMessage } from '@xuqm/h5-sdk' + +// 发送图片(从 input 元素获取) +const file = document.querySelector('input[type="file"]').files[0] +await sendImageMessage('user_002', 'SINGLE', file, 800, 600) + +// 发送文件 +await sendFileMessage('user_002', 'SINGLE', file) +``` + +--- + +## 核心 API + +### 事件订阅 + +| 事件 | 回调签名 | 说明 | +|------|---------|------| +| `connected` | `() => void` | IM 实时连接已建立 | +| `disconnected` | `() => void` | IM 实时连接已断开 | +| `messages` | `(msgs: ImMessage[]) => void` | 收到新消息 | +| `conversations` | `(convs: ConversationData[]) => void` | 会话列表变化 | +| `error` | `(err: Error) => void` | 发生错误 | + +```typescript +im.on('conversations', (convs) => { + // 更新 UI +}) +im.off('conversations', handler) // 取消订阅 +``` + +### 状态属性 + +```typescript +im.connected // boolean,是否已连接 +im.messages // ImMessage[],当前消息列表 +im.conversations // ConversationData[],当前会话列表 +im.error // Error | null,最近错误 +``` + +### HTTP API + +所有 IM 功能均通过纯函数暴露: + +```typescript +import { + sendMessage, + sendTextMessage, + sendImageMessage, + sendVideoMessage, + sendFileMessage, + sendAudioMessage, + fetchHistory, + fetchGroupHistory, + listConversations, + markRead, + listFriends, + addFriend, + listGroups, + createGroup, + // ... +} from '@xuqm/h5-sdk' +``` + +--- + +## 与框架集成 + +### React + +```tsx +import { useEffect, useState } from 'react' +import { ImManager } from '@xuqm/h5-sdk' + +function useIm() { + const [im] = useState(() => new ImManager()) + const [messages, setMessages] = useState([]) + const [conversations, setConversations] = useState([]) + + useEffect(() => { + im.on('messages', setMessages) + im.on('conversations', setConversations) + im.connect() + return () => { + im.off('messages', setMessages) + im.off('conversations', setConversations) + im.disconnect() + } + }, [im]) + + return { im, messages, conversations } +} +``` + +### 纯 HTML/JS + +```html + + +``` diff --git a/docs-site/docs/h5/setup.md b/docs-site/docs/h5/setup.md new file mode 100644 index 0000000..aff9e68 --- /dev/null +++ b/docs-site/docs/h5/setup.md @@ -0,0 +1,54 @@ +# H5 安装配置 + +**包名**:`@xuqm/h5-sdk` · **语言**:TypeScript / JavaScript · **格式**:ESM + UMD + +`@xuqm/h5-sdk` 是从 Vue3 SDK 提取的纯 JavaScript/TypeScript 核心库,**不依赖任何前端框架**(Vue/React/Angular 均可使用),可在任何支持 ES6 的浏览器或 H5 环境中运行。 + +> **功能范围**:仅包含 **IM** 功能(消息收发、会话管理、好友、群组),**不包含 Push 和 Update**。 + +--- + +## 安装 + +```bash +npm install @xuqm/h5-sdk +``` + +或 CDN 引入: + +```html + + +``` + +--- + +## 初始化 + +只需传入 `appKey`,服务器地址由 SDK 内置。 + +```typescript +import { init } from '@xuqm/h5-sdk' + +init({ + appKey: 'your_app_key', // 在租户平台创建应用后获得 +}) +``` + +--- + +## 登录 + +```typescript +import { login } from '@xuqm/h5-sdk' + +await login('user_001', 'your_user_sig_jwt') +``` + +--- + +## 下一步 + +- [H5 IM 接入 →](./im) diff --git a/docs-site/docs/miniprogram/im.md b/docs-site/docs/miniprogram/im.md new file mode 100644 index 0000000..7c47766 --- /dev/null +++ b/docs-site/docs/miniprogram/im.md @@ -0,0 +1,137 @@ +# 微信小程序 IM 接入 + +**模块**:`xuqm-group-wechat-mini-program-sdk` + +--- + +## 登录 + +```ts +import { XuqmMiniProgramSDK } from 'xuqm-group-wechat-mini-program-sdk' + +const sdk = new XuqmMiniProgramSDK() +sdk.init({ appKey: 'your_app_key' }) + +// 使用 UserSig 登录 +await sdk.login('user_001', 'your_user_sig_jwt') +``` + +--- + +## 监听消息 + +```ts +sdk.on('connected', () => { + console.log('IM 已连接') +}) + +sdk.on('message', (msg) => { + console.log('收到消息:', msg.msgType, msg.content) +}) + +sdk.on('read', (msg) => { + console.log('已读回执:', msg.id) +}) + +sdk.on('revoke', (data) => { + console.log('消息被撤回:', data.msgId) +}) + +sdk.on('disconnected', (reason) => { + console.log('断开连接:', reason) +}) + +sdk.on('error', (error) => { + console.error('IM 错误:', error) +}) +``` + +--- + +## 发送消息 + +```ts +const msg = await sdk.send({ + toId: 'user_002', + chatType: 'SINGLE', + msgType: 'TEXT', + content: 'Hello!', +}) +``` + +### 发送文本消息(快捷方法) + +```ts +await sdk.sendTextMessage('user_002', 'SINGLE', 'Hello!') +``` + +--- + +## 历史消息 + +```ts +const history = await sdk.fetchHistory('user_002') +const groupHistory = await sdk.fetchGroupHistory('group_xxx') +``` + +--- + +## 会话列表 + +```ts +const conversations = await sdk.listConversations() +await sdk.markRead('user_002') +await sdk.setConversationPinned('user_002', 'SINGLE', true) +await sdk.setConversationMuted('user_002', 'SINGLE', true) +``` + +--- + +## 群聊 + +```ts +const groups = await sdk.listGroups() +const group = await sdk.getGroupInfo('group_xxx') +const members = await sdk.listGroupMembers('group_xxx') +``` + +--- + +## 好友管理 + +```ts +const friends = await sdk.listFriends() +await sdk.addFriend('user_002') +await sdk.removeFriend('user_002') +``` + +--- + +## 离线消息同步 + +```ts +const count = await sdk.offlineMessageCount() +const messages = await sdk.syncOfflineMessages() +``` + +--- + +## 消息类型 + +| MsgType | 说明 | +|---------|------| +| `TEXT` | 纯文本 | +| `IMAGE` | 图片 | +| `VIDEO` | 视频 | +| `AUDIO` | 语音 | +| `FILE` | 文件 | +| `LOCATION` | 位置 | +| `CUSTOM` | 自定义 | +| `NOTIFY` | 系统通知 | +| `RICH_TEXT` | 富文本 | +| `CALL_AUDIO` | 语音通话信令 | +| `CALL_VIDEO` | 视频通话信令 | +| `QUOTE` | 引用 | +| `MERGE` | 合并转发 | +| `FORWARD` | 转发 | +| `REVOKED` | 撤回 | diff --git a/docs-site/docs/miniprogram/setup.md b/docs-site/docs/miniprogram/setup.md new file mode 100644 index 0000000..557450e --- /dev/null +++ b/docs-site/docs/miniprogram/setup.md @@ -0,0 +1,45 @@ +# 微信小程序安装配置 + +**包名**:`xuqm-group-wechat-mini-program-sdk` · **版本**:0.1.0 + +--- + +## npm 安装 + +在项目根目录创建 `.npmrc`: + +``` +registry=https://nexus.xuqinmin.com/repository/npm/ +``` + +然后安装: + +```bash +npm install xuqm-group-wechat-mini-program-sdk +``` + +或在微信开发者工具中: + +1. 打开「工具」→「构建 npm」 +2. 在小程序 `package.json` 中添加上述依赖 + +--- + +## 初始化 + +```ts +import { XuqmMiniProgramSDK } from 'xuqm-group-wechat-mini-program-sdk' + +const sdk = new XuqmMiniProgramSDK() + +sdk.init({ + appKey: 'your_app_key', + debug: true, // 可选 +}) +``` + +--- + +## 下一步 + +- [小程序 IM 接入 →](./im) diff --git a/ops-platform/src/api/ops.ts b/ops-platform/src/api/ops.ts index 0894315..08ec1c6 100644 --- a/ops-platform/src/api/ops.ts +++ b/ops-platform/src/api/ops.ts @@ -91,6 +91,7 @@ export interface AppItem { name: string packageName: string tenantId: string + tenantName?: string createdAt: string } @@ -241,8 +242,8 @@ export const opsApi = { rejectRequest: (requestId: string, reviewNote = '') => client.post<{ data: ServiceRequest }>(`/ops/service-requests/${requestId}/reject`, { reviewNote }), - listApps: (keyword = '', page = 0, size = 20) => - client.get<{ data: AppPage }>('/ops/apps', { params: { keyword, page, size } }), + listApps: (keyword = '', tenantId = '', page = 0, size = 20) => + client.get<{ data: AppPage }>('/ops/apps', { params: { keyword, tenantId, page, size } }), getApp: (id: string) => client.get<{ data: AppDetail }>(`/ops/apps/${id}`), diff --git a/ops-platform/src/views/apps/AppDetailView.vue b/ops-platform/src/views/apps/AppDetailView.vue index bd36350..9a3d26b 100644 --- a/ops-platform/src/views/apps/AppDetailView.vue +++ b/ops-platform/src/views/apps/AppDetailView.vue @@ -34,7 +34,6 @@ -