更新说明文档,添加日志输出
This commit is contained in:
parent
582343c437
commit
ea6a10a588
2
.hvigor/cache/file-cache.json
vendored
2
.hvigor/cache/file-cache.json
vendored
File diff suppressed because one or more lines are too long
2
.hvigor/cache/task-cache.json
vendored
2
.hvigor/cache/task-cache.json
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,10 @@
|
||||
"MODULES": [
|
||||
{
|
||||
"MODULE_NAME": "1043bfc77febe75fafec0c4309faccf1",
|
||||
"API_TYPE": "stageMode"
|
||||
"API_TYPE": "stageMode",
|
||||
"INCREMENTAL_TASKS": {
|
||||
"COMPILE_ARKTS": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"BUILD_MODE": "debug"
|
||||
@ -15,19 +18,21 @@
|
||||
"IS_HVIGORFILE_TYPE_CHECK": false,
|
||||
"TASK_TIME": {
|
||||
"1043bfc77febe75fafec0c4309faccf1": {
|
||||
"ConfigureCmake": 198417,
|
||||
"PreCheckSyscap": 366291,
|
||||
"ProcessIntegratedHsp": 7834000,
|
||||
"BuildNativeWithCmake": 2433792,
|
||||
"SyscapTransform": 4341084,
|
||||
"BuildNativeWithNinja": 2475333,
|
||||
"BuildJS": 2653334,
|
||||
"SignHap": 1709458,
|
||||
"CollectDebugSymbol": 3067292,
|
||||
"assembleHap": 169292
|
||||
"ConfigureCmake": 856416,
|
||||
"PreCheckSyscap": 632458,
|
||||
"ProcessIntegratedHsp": 1418083,
|
||||
"BuildNativeWithCmake": 273041,
|
||||
"SyscapTransform": 36040791,
|
||||
"BuildNativeWithNinja": 1378666,
|
||||
"BuildJS": 3533375,
|
||||
"CompileArkTS": 31907849083,
|
||||
"PackageHap": 827841167,
|
||||
"SignHap": 5034625,
|
||||
"CollectDebugSymbol": 3993000,
|
||||
"assembleHap": 304292
|
||||
}
|
||||
},
|
||||
"TOTAL_TIME": 748077750,
|
||||
"BUILD_ID": "202504031317266900"
|
||||
"BUILD_ID": "202504040929560100",
|
||||
"TOTAL_TIME": 34679640584
|
||||
}
|
||||
}
|
178
README.md
178
README.md
@ -1,64 +1,144 @@
|
||||
# ClassMG Communication Server
|
||||
# ClassMG - Interactive Classroom Management System
|
||||
|
||||
This server enables real-time communication between multiple instances of the ClassMG application running on different devices. It provides a simple HTTP API for message passing, classroom management, and question handling.
|
||||
[English (Current)](README.md) | [中文版](README_CN.md)
|
||||
|
||||
## Prerequisites
|
||||
## Overview
|
||||
|
||||
ClassMG is a comprehensive classroom management application designed for interactive teaching and learning. The system enables real-time communication between teachers and students, interactive question sessions, and immediate feedback mechanisms, all within a unified digital classroom environment.
|
||||
|
||||
## System Architecture
|
||||
|
||||
ClassMG is built on a client-server architecture:
|
||||
|
||||
- **Client Application**: Developed using HarmonyOS ArkTS for cross-device compatibility
|
||||
- **Communication Server**: Node.js based server that enables real-time message passing and state synchronization
|
||||
- **Local Data Storage**: Secure local storage for user credentials and session data
|
||||
|
||||
## Core Features
|
||||
|
||||
### 1. Classroom Management
|
||||
- **Create Classroom**: Teachers can create virtual classrooms with unique access codes
|
||||
- **Join Classroom**: Students can join using classroom codes
|
||||
- ~~**Classroom Status**: Real-time monitoring of active participants~~
|
||||
- **End Classroom**: Teachers can terminate sessions with proper notification to all participants
|
||||
|
||||
### ~~2. Real-time Communication~~
|
||||
- **Instant Messaging**: Bi-directional communication between teachers and students
|
||||
- **Message Synchronization**: Robust message delivery with automatic retry mechanisms
|
||||
- **Connection Status**: Visual indicators for connection status with troubleshooting options
|
||||
|
||||
### 3. Interactive Questions
|
||||
- **Question Publishing**: Teachers can create and publish multiple-choice questions
|
||||
- **Timed Responses**: Configurable time limits for answering questions
|
||||
- **Answer Submission**: Students can submit answers with immediate confirmation
|
||||
- **Result Analysis**: Visual presentation of response statistics and correctness rates
|
||||
|
||||
### 4. User Experience
|
||||
- **Adaptive Layout**: Responsive interface that works across different screen sizes
|
||||
- **Visual Feedback**: Clear status indicators for all operations
|
||||
- **Error Handling**: Comprehensive error notifications with recovery options
|
||||
- **Theme Customization**: Personalized visual appearance settings
|
||||
|
||||
## Operation Logic
|
||||
|
||||
### Authentication Flow
|
||||
1. Users register with username and password (stored securely)
|
||||
2. Login verification against local credentials
|
||||
3. Role assignment (teacher or student) determines available features
|
||||
|
||||
### Classroom Session Flow
|
||||
1. Teacher creates a classroom with a unique code
|
||||
2. Students join using the provided code
|
||||
3. Real-time synchronization establishes the classroom environment
|
||||
4. Teacher and students can exchange messages and participate in question sessions
|
||||
5. Teacher can end the classroom session, which notifies all participants
|
||||
|
||||
### Messaging System
|
||||
1. Messages are composed and sent from the input area
|
||||
2. Local preview appears immediately for responsive UX
|
||||
3. Messages are transmitted to the server
|
||||
4. Server broadcasts messages to all connected devices
|
||||
5. Polling mechanism ensures message delivery, even after temporary disconnections
|
||||
|
||||
### Question Management
|
||||
1. Teacher creates questions with multiple-choice options
|
||||
2. Students receive questions with configurable countdown timers
|
||||
3. Responses are collected and synchronized across devices
|
||||
4. Results are computed and displayed after the question ends
|
||||
5. Teachers can view detailed statistics while students see personal results
|
||||
|
||||
## Technical Implementation
|
||||
|
||||
### Communication Protocol
|
||||
- HTTP-based API for classroom operations
|
||||
- Polling mechanism for state synchronization
|
||||
- JSON message format for data exchange
|
||||
|
||||
### Data Security
|
||||
- Local credential storage with encryption
|
||||
- Classroom access controlled via unique codes
|
||||
- Session validation for all operations
|
||||
|
||||
### Synchronization Mechanism
|
||||
- Server maintains the source of truth for classroom state
|
||||
- Client polling ensures data consistency
|
||||
- Conflict resolution strategies for concurrent operations
|
||||
|
||||
### Error Handling
|
||||
- Connection status monitoring
|
||||
- Automatic reconnection attempts
|
||||
- User-friendly error messages with recovery options
|
||||
|
||||
## Server Setup
|
||||
|
||||
### Prerequisites
|
||||
- Node.js (v12 or higher)
|
||||
- NPM (Node Package Manager)
|
||||
|
||||
## Installation
|
||||
### Installation
|
||||
1. Install Node.js and NPM
|
||||
2. Clone or download the repository
|
||||
3. Install dependencies with `npm install`
|
||||
|
||||
1. Install Node.js and NPM if you haven't already:
|
||||
- Download from [nodejs.org](https://nodejs.org/)
|
||||
### Running the Server
|
||||
1. Start with `npm start` or `node server.js`
|
||||
2. Server will run on port 5243 by default
|
||||
3. Note your computer's IP address for client configuration
|
||||
|
||||
2. Clone or download this repository to your computer
|
||||
## Client Configuration
|
||||
|
||||
3. Install dependencies:
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
### Development Environment
|
||||
- DevEco Studio (recommended)
|
||||
- HarmonyOS SDK
|
||||
|
||||
## Running the server
|
||||
|
||||
1. Start the server:
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
or
|
||||
```bash
|
||||
node server.js
|
||||
```
|
||||
|
||||
2. The server will start on port 5243. Make note of your computer's IP address, which will be displayed in the console output.
|
||||
|
||||
## Connecting ClassMG app to the server
|
||||
|
||||
1. Make sure all devices (server and app clients) are on the same network
|
||||
|
||||
2. Open the ClassMG project in DevEco Studio
|
||||
|
||||
3. Update the `CHANNEL_API_CONFIG.baseUrl` in `entry/src/main/ets/common/ClassRoomService.ets` to:
|
||||
```
|
||||
http://<Your computer's IP address>:5243
|
||||
```
|
||||
|
||||
4. Compile and run the ClassMG app on your devices
|
||||
|
||||
## Testing
|
||||
|
||||
1. Run the server on one computer
|
||||
2. Run the ClassMG app on two different devices (or emulators)
|
||||
3. Log in as a teacher on one device and create a class
|
||||
4. Log in as a student on the other device and join the class using the class code
|
||||
5. Test messaging, question publishing, and answering functionality
|
||||
### Connection Setup
|
||||
1. Ensure all devices are on the same network
|
||||
2. Configure the server address in the client application
|
||||
3. Compile and deploy to testing devices
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Connection Issues**: Make sure all devices are on the same network and can reach the server's IP address
|
||||
- **Port Conflicts**: If port 5243 is already in use, change the PORT variable in server.js and update the app accordingly
|
||||
- **CORS Issues**: If experiencing cross-origin problems, verify the CORS middleware is correctly configured in server.js
|
||||
### Connection Issues
|
||||
- Verify all devices are on the same network
|
||||
- Check server IP address and port configuration
|
||||
- Use the built-in connection status checker in the application
|
||||
|
||||
## Note
|
||||
### Message Synchronization
|
||||
- If messages aren't appearing across devices, check connection status
|
||||
- Verify server is running properly
|
||||
- Try reconnecting using the in-app troubleshooting button
|
||||
|
||||
This is a development server intended for local testing only. For production use, additional security measures would be required.
|
||||
### Layout Problems
|
||||
- If UI elements are misaligned or appear off-screen, restart the application
|
||||
- Different device screen sizes may require application restart after significant layout changes
|
||||
|
||||
## Notes for Developers
|
||||
|
||||
- The system uses a polling mechanism rather than WebSockets for compatibility reasons
|
||||
- Message deduplication is implemented to handle potential duplicate delivery
|
||||
- UI layouts are optimized for both tablet and smartphone form factors
|
||||
- Debug logging can be enabled for troubleshooting purposes
|
||||
|
||||
---
|
||||
|
||||
**Note**: This document provides an overview of the ClassMG system. For detailed API documentation and developer guides, please refer to the technical documentation.
|
144
README_CN.md
Normal file
144
README_CN.md
Normal file
@ -0,0 +1,144 @@
|
||||
# ClassMG - 互动式课堂管理系统
|
||||
|
||||
[English](README.md) | [中文版(当前)](README_CN.md)
|
||||
|
||||
## 概述
|
||||
|
||||
ClassMG是一款全面的课堂管理应用程序,专为互动式教学和学习设计。该系统支持教师和学生之间的实时通信、互动问答环节和即时反馈机制,所有这些功能都在统一的数字课堂环境中实现。
|
||||
|
||||
## 系统架构
|
||||
|
||||
ClassMG基于客户端-服务器架构:
|
||||
|
||||
- **客户端应用**:使用HarmonyOS ArkTS开发,确保跨设备兼容性
|
||||
- **通信服务器**:基于Node.js的服务器,支持实时消息传递和状态同步
|
||||
- **本地数据存储**:用于安全存储用户凭证和会话数据
|
||||
|
||||
## 核心功能
|
||||
|
||||
### 1. 课堂管理
|
||||
- **创建课堂**:教师可以创建具有唯一访问码的虚拟课堂
|
||||
- **加入课堂**:学生可以使用课堂码加入
|
||||
- ~~**课堂状态**:实时监控活跃参与者~~
|
||||
- **结束课堂**:教师可以终止会话,并向所有参与者发送通知
|
||||
|
||||
### ~~2. 实时通信~~
|
||||
- **即时消息**:教师和学生之间的双向通信
|
||||
- **消息同步**:具有自动重试机制的可靠消息传递
|
||||
- **连接状态**:连接状态的可视化指示器,提供故障排除选项
|
||||
|
||||
### 3. 互动问答
|
||||
- **问题发布**:教师可以创建并发布多选题
|
||||
- **定时响应**:可配置的答题时间限制
|
||||
- **提交答案**:学生可以提交答案并获得即时确认
|
||||
- **结果分析**:以可视化方式呈现回答统计和正确率
|
||||
|
||||
### 4. 用户体验
|
||||
- **自适应布局**:适应不同屏幕尺寸的响应式界面
|
||||
- **视觉反馈**:所有操作的清晰状态指示
|
||||
- **错误处理**:全面的错误通知和恢复选项
|
||||
- **主题定制**:个性化的视觉外观设置
|
||||
|
||||
## 操作逻辑
|
||||
|
||||
### 认证流程
|
||||
1. 用户使用用户名和密码注册(安全存储)
|
||||
2. 根据本地凭据进行登录验证
|
||||
3. 角色分配(教师或学生)决定可用功能
|
||||
|
||||
### 课堂会话流程
|
||||
1. 教师创建具有唯一码的课堂
|
||||
2. 学生使用提供的课堂码加入
|
||||
3. 实时同步建立课堂环境
|
||||
4. 教师和学生可以交换消息并参与问答环节
|
||||
5. 教师可以结束课堂会话,系统会通知所有参与者
|
||||
|
||||
### 消息系统
|
||||
1. 从输入区域撰写和发送消息
|
||||
2. 本地预览立即显示,提供响应式用户体验
|
||||
3. 消息传输到服务器
|
||||
4. 服务器向所有连接的设备广播消息
|
||||
5. 轮询机制确保消息传递,即使在临时断开连接后也能同步
|
||||
|
||||
### 问题管理
|
||||
1. 教师创建带有多个选项的问题
|
||||
2. 学生收到问题,并看到可配置的倒计时
|
||||
3. 收集并跨设备同步回答
|
||||
4. 问题结束后计算并显示结果
|
||||
5. 教师可以查看详细统计,而学生能看到个人结果
|
||||
|
||||
## 技术实现
|
||||
|
||||
### 通信协议
|
||||
- 基于HTTP的API用于课堂操作
|
||||
- 轮询机制用于状态同步
|
||||
- JSON消息格式用于数据交换
|
||||
|
||||
### 数据安全
|
||||
- 本地凭证存储带有加密功能
|
||||
- 通过唯一码控制课堂访问
|
||||
- 对所有操作进行会话验证
|
||||
|
||||
### 同步机制
|
||||
- 服务器维护课堂状态的权威来源
|
||||
- 客户端轮询确保数据一致性
|
||||
- 针对并发操作的冲突解决策略
|
||||
|
||||
### 错误处理
|
||||
- 连接状态监控
|
||||
- 自动重连尝试
|
||||
- 用户友好的错误消息和恢复选项
|
||||
|
||||
## 服务器设置
|
||||
|
||||
### 前提条件
|
||||
- Node.js(v12或更高版本)
|
||||
- NPM(Node包管理器)
|
||||
|
||||
### 安装
|
||||
1. 安装Node.js和NPM
|
||||
2. 克隆或下载存储库
|
||||
3. 使用`npm install`安装依赖项
|
||||
|
||||
### 运行服务器
|
||||
1. 使用`npm start`或`node server.js`启动
|
||||
2. 服务器默认运行在5243端口
|
||||
3. 记下计算机的IP地址,用于客户端配置
|
||||
|
||||
## 客户端配置
|
||||
|
||||
### 开发环境
|
||||
- DevEco Studio(推荐)
|
||||
- HarmonyOS SDK
|
||||
|
||||
### 连接设置
|
||||
1. 确保所有设备在同一网络上
|
||||
2. 在客户端应用程序中配置服务器地址
|
||||
3. 编译并部署到测试设备
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 连接问题
|
||||
- 验证所有设备是否在同一网络上
|
||||
- 检查服务器IP地址和端口配置
|
||||
- 使用应用程序内置的连接状态检查器
|
||||
|
||||
### 消息同步
|
||||
- 如果消息未跨设备显示,检查连接状态
|
||||
- 验证服务器是否正常运行
|
||||
- 尝试使用应用内故障排除按钮重新连接
|
||||
|
||||
### 布局问题
|
||||
- 如果UI元素未对齐或在屏幕外显示,请重启应用程序
|
||||
- 不同设备屏幕尺寸可能需要在重大布局更改后重启应用程序
|
||||
|
||||
## 开发者注意事项
|
||||
|
||||
- 系统出于兼容性考虑使用轮询机制而非WebSockets
|
||||
- 实现了消息去重以处理潜在的重复传递
|
||||
- UI布局针对平板电脑和智能手机形态进行了优化
|
||||
- 可以启用调试日志进行故障排除
|
||||
|
||||
---
|
||||
|
||||
**注意**:本文档提供了ClassMG系统的概述。有关详细的API文档和开发者指南,请参阅技术文档。
|
@ -246,11 +246,15 @@ export type EventCallback = (data: EventData) => void;
|
||||
|
||||
// API配置
|
||||
const CHANNEL_API_CONFIG: ApiConfig = {
|
||||
baseUrl: 'http://139.155.155.67:5243', // Change this to your computer's IP address
|
||||
pollInterval: 1000, // 轮询间隔(毫秒) - 降低到1秒以提高同步速度
|
||||
timeout: 10000 // 请求超时(毫秒)
|
||||
baseUrl: 'http://139.155.155.67:5243', // 使用这个确认工作的地址
|
||||
pollInterval: 1000,
|
||||
timeout: 10000
|
||||
};
|
||||
|
||||
// 定义日志频道ID和TAG常量
|
||||
const TIAN_CHANNEL_DOMAIN_ID = 0x00201; // 自定义域ID
|
||||
const TIAN_CHANNEL_TAG = 'tianChannel'; // 自定义TAG用于筛选日志
|
||||
|
||||
// 课堂通信服务
|
||||
export class ClassRoomService {
|
||||
private static instance: ClassRoomService;
|
||||
@ -280,7 +284,7 @@ export class ClassRoomService {
|
||||
|
||||
private constructor() {
|
||||
// 初始化
|
||||
hilog.info(0, 'ClassMG', 'ClassRoom Service Initialized');
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, 'ClassRoom Service Initialized');
|
||||
}
|
||||
|
||||
public static getInstance(): ClassRoomService {
|
||||
@ -298,9 +302,21 @@ export class ClassRoomService {
|
||||
|
||||
// 发起HTTP POST请求
|
||||
private async postRequest(endpoint: string, data: object): Promise<ChannelApiResponse> {
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `开始POST请求: ${endpoint}`);
|
||||
try {
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `创建HTTP客户端`);
|
||||
const httpRequest = this.createHttpClient();
|
||||
|
||||
// 记录请求数据摘要
|
||||
let dataStr = "";
|
||||
try {
|
||||
dataStr = JSON.stringify(data).substring(0, 100) + (JSON.stringify(data).length > 100 ? '...' : '');
|
||||
} catch (e) {
|
||||
dataStr = "无法序列化数据";
|
||||
}
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `请求数据(摘要): ${dataStr}`);
|
||||
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `发送请求到: ${CHANNEL_API_CONFIG.baseUrl}/${endpoint}`);
|
||||
const response = await httpRequest.request(
|
||||
`${CHANNEL_API_CONFIG.baseUrl}/${endpoint}`,
|
||||
{
|
||||
@ -314,14 +330,20 @@ export class ClassRoomService {
|
||||
}
|
||||
);
|
||||
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `请求完成,销毁HTTP客户端`);
|
||||
httpRequest.destroy();
|
||||
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `响应状态码: ${response.responseCode}`);
|
||||
|
||||
if (response.responseCode === 200) {
|
||||
const jsonString: string = response.result ? response.result.toString() : '{}';
|
||||
try {
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `开始解析响应JSON`);
|
||||
const jsonString: string = response.result ? response.result.toString() : '{}';
|
||||
const responseData = JSON.parse(jsonString) as ChannelApiResponse;
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `解析成功,响应success: ${responseData.success}`);
|
||||
return responseData;
|
||||
} catch (parseError) {
|
||||
hilog.error(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `解析响应JSON失败: ${parseError}`);
|
||||
logManager.error(LogCategory.NETWORK, `Error parsing response: ${parseError}`);
|
||||
const errorResponse: ChannelApiResponse = {
|
||||
success: false,
|
||||
@ -331,12 +353,20 @@ export class ClassRoomService {
|
||||
}
|
||||
}
|
||||
|
||||
hilog.warn(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `HTTP错误状态码: ${response.responseCode}`);
|
||||
const errorResponse: ChannelApiResponse = {
|
||||
success: false,
|
||||
message: `HTTP error: ${response.responseCode}`
|
||||
};
|
||||
return errorResponse;
|
||||
} catch (error) {
|
||||
// 详细记录网络错误
|
||||
const errorMsg = error instanceof Error ? error.message : String(error);
|
||||
const errorStack = error instanceof Error ? error.stack : 'No stack trace';
|
||||
|
||||
hilog.error(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `网络请求错误: ${errorMsg}`);
|
||||
hilog.error(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `错误堆栈: ${errorStack}`);
|
||||
|
||||
logManager.error(LogCategory.NETWORK, `Network request error: ${error}`);
|
||||
const errorResponse: ChannelApiResponse = {
|
||||
success: false,
|
||||
@ -685,43 +715,101 @@ export class ClassRoomService {
|
||||
|
||||
// 发送消息
|
||||
public async sendMessage(content: string): Promise<boolean> {
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `========= 开始发送消息 =========`);
|
||||
|
||||
// 检查前提条件
|
||||
if (!this.currentSession) {
|
||||
hilog.error(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `发送失败: currentSession为空`);
|
||||
return false;
|
||||
}
|
||||
if (!this.connected) {
|
||||
hilog.error(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `发送失败: 未连接`);
|
||||
return false;
|
||||
}
|
||||
if (!this.currentClassCode) {
|
||||
hilog.error(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `发送失败: currentClassCode为空`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.currentSession || !this.connected || !this.currentClassCode) {
|
||||
logManager.error(LogCategory.CLASS, `Cannot send message: No active session or not connected`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Debug message: Log session and connection information
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `会话ID: ${this.currentSession.sessionId}`);
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `课堂码: ${this.currentClassCode}`);
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `连接状态: ${this.connected}`);
|
||||
|
||||
logManager.info(LogCategory.CLASS, LogEventType.SYSTEM_INFO, `[DEBUG] Message sending attempt - Session ID: ${this.currentSession.sessionId}, Class Code: ${this.currentClassCode}, Connection status: ${this.connected}`);
|
||||
|
||||
// 获取用户信息
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `获取用户信息`);
|
||||
const currentAccount = settingsService.getCurrentAccount();
|
||||
const senderName = this.dbService.getUserNickname(currentAccount) || currentAccount;
|
||||
const role = this.isTeacher ? SenderRole.TEACHER : SenderRole.STUDENT;
|
||||
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `用户账号: ${currentAccount}`);
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `用户名称: ${senderName}`);
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `用户角色: ${role}`);
|
||||
|
||||
// Debug message: Log user information
|
||||
logManager.info(LogCategory.CLASS, LogEventType.SYSTEM_INFO, `[DEBUG] Message sender info - Account: ${currentAccount}, Name: ${senderName}, Role: ${role}`);
|
||||
|
||||
// 创建消息
|
||||
const message = new MessageModel(currentAccount, senderName, role, content);
|
||||
logManager.info(LogCategory.CLASS, LogEventType.SYSTEM_INFO, `Creating message: ID=${message.id}, Content=${content}, Sender=${senderName}, Role=${role}`);
|
||||
|
||||
// 创建消息对象
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `创建消息对象`);
|
||||
try {
|
||||
// 发送消息请求
|
||||
// 单独记录消息创建过程
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `消息内容: ${content}`);
|
||||
|
||||
const message = new MessageModel(currentAccount, senderName, role, content);
|
||||
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `消息创建成功,ID: ${message.id}`);
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `消息时间戳: ${message.timestamp.toISOString()}`);
|
||||
|
||||
logManager.info(LogCategory.CLASS, LogEventType.SYSTEM_INFO, `Creating message: ID=${message.id}, Content=${content}, Sender=${senderName}, Role=${role}`);
|
||||
|
||||
// 构建请求
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `构建发送请求`);
|
||||
const request: SendMessageRequest = {
|
||||
classCode: this.currentClassCode,
|
||||
message: message
|
||||
};
|
||||
|
||||
logManager.info(LogCategory.CLASS, LogEventType.SYSTEM_INFO, `Sending message to server: ${JSON.stringify(request)}`);
|
||||
// 打印请求对象,但避免过长内容
|
||||
let requestStr = "";
|
||||
try {
|
||||
requestStr = JSON.stringify(request).substring(0, 200) + (JSON.stringify(request).length > 200 ? '...' : '');
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `请求对象(摘要): ${requestStr}`);
|
||||
} catch (e) {
|
||||
hilog.error(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `无法序列化请求: ${e}`);
|
||||
}
|
||||
|
||||
// Debug message: Log request details before sending
|
||||
logManager.info(LogCategory.CLASS, LogEventType.SYSTEM_INFO, `[DEBUG] Message request details - Timestamp: ${message.timestamp.toISOString()}, Message ID format check: ${message.id.length > 5 ? 'Valid' : 'Invalid'}`);
|
||||
logManager.info(LogCategory.CLASS, LogEventType.SYSTEM_INFO, `发送消息请求: classCode=${this.currentClassCode}, messageId=${message.id}`);
|
||||
|
||||
// 发送请求
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `开始发送POST请求到sendMessage`);
|
||||
const response = await this.postRequest('sendMessage', request);
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `请求完成,响应success: ${response.success}`);
|
||||
|
||||
// Debug message: Log response details
|
||||
logManager.info(LogCategory.CLASS, LogEventType.SYSTEM_INFO, `[DEBUG] Server response received - Success: ${response.success}, Message: ${response.message || 'No message'}`);
|
||||
// 详细记录响应
|
||||
if (response.message) {
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `响应消息: ${response.message}`);
|
||||
}
|
||||
if (response.data) {
|
||||
try {
|
||||
const dataStr = JSON.stringify(response.data).substring(0, 100) +
|
||||
(JSON.stringify(response.data).length > 100 ? '...' : '');
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `响应数据(摘要): ${dataStr}`);
|
||||
} catch (e) {
|
||||
hilog.error(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `无法序列化响应数据: ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
logManager.info(LogCategory.CLASS, LogEventType.SYSTEM_INFO, `服务器响应: success=${response.success}, message=${response.message || "无"}`);
|
||||
|
||||
if (response.success) {
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `消息发送成功,更新lastMessageId: ${message.id}`);
|
||||
// 不再将消息添加到currentSession,因为UI层已经添加了本地消息
|
||||
// (已删除): this.currentSession.messages.push(message);
|
||||
|
||||
@ -732,19 +820,30 @@ export class ClassRoomService {
|
||||
this.lastMessageId = message.id;
|
||||
|
||||
logManager.info(LogCategory.CLASS, LogEventType.SYSTEM_INFO, `Message sent successfully: ${message.id}`);
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `========= 消息发送成功 =========`);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
// Enhanced error logging with response details
|
||||
hilog.error(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `消息发送失败: ${response.message || '未知错误'}`);
|
||||
logManager.error(LogCategory.CLASS, `Send message failed: ${response.message || 'Unknown error'}, Response data: ${JSON.stringify(response.data || {})}`);
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `========= 消息发送失败 =========`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
// Enhanced error logging with error details
|
||||
// 增强错误处理,确保不会崩溃
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
const errorStack = error instanceof Error ? error.stack : 'No stack trace';
|
||||
logManager.error(LogCategory.CLASS, `Send message error: ${errorMessage}`);
|
||||
logManager.error(LogCategory.CLASS, `[DEBUG] Error details - Stack: ${errorStack}`);
|
||||
|
||||
hilog.error(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `发送消息异常: ${errorMessage}`);
|
||||
hilog.error(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `错误堆栈: ${errorStack}`);
|
||||
|
||||
logManager.error(LogCategory.CLASS, `发送消息严重错误: ${errorMessage}`);
|
||||
logManager.error(LogCategory.CLASS, `错误详情: ${errorStack}`);
|
||||
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `========= 消息发送异常 =========`);
|
||||
|
||||
// 确保返回false而不是崩溃
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +157,8 @@ export class LogManager {
|
||||
new VersionLogItem("1.1.5","2025-4-1",["增加远程测试数据库","优化登录页面","优化用户信息设置","增加退出按钮"]),
|
||||
new VersionLogItem("1.1.7","2025-4-1",["添加测试按钮","修复已知问题"]),
|
||||
new VersionLogItem("1.2.0","2025-4-2",["添加课堂功能","修改上课页面逻辑"]),
|
||||
new VersionLogItem("1.2.0 beta","2025-4-3",["测试消息发送","修复已知问题"])
|
||||
new VersionLogItem("1.2.0 beta","2025-4-3",["测试消息发送","修复已知问题"]),
|
||||
new VersionLogItem("1.2.0 beta1.0","2025-4-3",["更新说明文档","添加日志输出"])
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,11 @@ import { ClassRoomService,
|
||||
} from '../common/ClassRoomService';
|
||||
import logManager, { LogCategory, LogEventType } from '../common/logtext';
|
||||
import http from '@ohos.net.http';
|
||||
import hilog from '@ohos.hilog';
|
||||
|
||||
// 添加hilog和tianChannel常量
|
||||
const TIAN_CHANNEL_DOMAIN_ID = 0x00201; // 自定义域ID
|
||||
const TIAN_CHANNEL_TAG = 'tianChannel'; // 自定义TAG用于筛选日志
|
||||
|
||||
// 定义选项对象接口
|
||||
interface ScrollOptions {
|
||||
@ -396,21 +401,29 @@ struct ClassLivePage {
|
||||
|
||||
// 发送消息
|
||||
private async sendMessage() {
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] ======== 开始UI层消息发送 ========`);
|
||||
|
||||
if (!this.messageText || this.messageText.trim() === '') {
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 消息内容为空,不发送`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 防止重复点击、重复发送
|
||||
if (this.isLoading) {
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 正在加载中,防止重复发送`);
|
||||
return;
|
||||
}
|
||||
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 设置加载状态为true`);
|
||||
this.isLoading = true;
|
||||
|
||||
// 保存消息内容,因为后面会清空输入框
|
||||
const messageContent = this.messageText.trim();
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 消息内容: ${messageContent}`);
|
||||
|
||||
// 创建一个本地消息对象用于立即显示
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 创建本地消息对象`);
|
||||
const localMessage = new MessageModel(
|
||||
settingsService.getCurrentAccount(),
|
||||
settingsService.getUserNickname() || settingsService.getCurrentAccount(),
|
||||
@ -420,23 +433,49 @@ struct ClassLivePage {
|
||||
|
||||
// 保存消息ID,以便后续可以在发送失败时移除
|
||||
const localMessageId = localMessage.id;
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 本地消息ID: ${localMessageId}`);
|
||||
|
||||
// 清空消息输入框 - 提前清空避免用户重复点击
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 清空输入框`);
|
||||
this.messageText = '';
|
||||
|
||||
// 先在本地添加消息,让用户立即看到
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 添加消息到本地列表`);
|
||||
console.info(`添加本地消息: ID=${localMessageId}, 内容=${messageContent}`);
|
||||
this.messages = [...this.messages, localMessage];
|
||||
|
||||
// 自动滚动到最新消息
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 滚动到最新消息`);
|
||||
this.scrollToLatestMessage();
|
||||
|
||||
// 发送消息到服务器
|
||||
const result = await this.classRoomService.sendMessage(messageContent);
|
||||
|
||||
if (!result) {
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 调用服务层发送消息`);
|
||||
try {
|
||||
const result = await this.classRoomService.sendMessage(messageContent);
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 服务层返回结果: ${result}`);
|
||||
|
||||
if (!result) {
|
||||
// 如果发送失败,从消息列表中移除本地消息
|
||||
hilog.error(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 消息发送失败,移除本地消息: ${localMessageId}`);
|
||||
console.error(`消息发送失败,移除本地消息: ${localMessageId}`);
|
||||
this.messages = this.messages.filter(msg => msg.id !== localMessageId);
|
||||
|
||||
// 显示错误提示
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 显示发送失败提示`);
|
||||
promptAction.showToast({
|
||||
message: '消息发送失败,请重试',
|
||||
duration: 2000
|
||||
});
|
||||
} else {
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 消息发送成功: ${localMessageId}`);
|
||||
console.info(`消息发送成功: ${localMessageId}`);
|
||||
}
|
||||
} catch (serviceError) {
|
||||
// 处理服务层异常
|
||||
hilog.error(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 服务层异常: ${serviceError}`);
|
||||
|
||||
// 如果发送失败,从消息列表中移除本地消息
|
||||
console.error(`消息发送失败,移除本地消息: ${localMessageId}`);
|
||||
hilog.error(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 由于服务层异常,移除本地消息: ${localMessageId}`);
|
||||
this.messages = this.messages.filter(msg => msg.id !== localMessageId);
|
||||
|
||||
// 显示错误提示
|
||||
@ -444,19 +483,24 @@ struct ClassLivePage {
|
||||
message: '消息发送失败,请重试',
|
||||
duration: 2000
|
||||
});
|
||||
} else {
|
||||
console.info(`消息发送成功: ${localMessageId}`);
|
||||
}
|
||||
} catch (error) {
|
||||
// 处理错误
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
const errorStack = error instanceof Error ? error.stack : 'No stack trace';
|
||||
|
||||
hilog.error(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 顶层异常: ${errorMessage}`);
|
||||
hilog.error(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 异常堆栈: ${errorStack}`);
|
||||
|
||||
logManager.error(LogCategory.CLASS, `Send message error: ${errorMessage}`);
|
||||
promptAction.showToast({
|
||||
message: '消息发送失败,请重试',
|
||||
duration: 2000
|
||||
});
|
||||
} finally {
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] 设置加载状态为false`);
|
||||
this.isLoading = false;
|
||||
hilog.info(TIAN_CHANNEL_DOMAIN_ID, TIAN_CHANNEL_TAG, `[UI] ======== 结束UI层消息发送 ========`);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user