更新说明文档,添加日志输出

This commit is contained in:
cc 2025-04-04 09:35:23 +08:00
parent 582343c437
commit ea6a10a588
9 changed files with 1797 additions and 89 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -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
View File

@ -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
View 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.jsv12或更高版本
- NPMNode包管理器
### 安装
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文档和开发者指南请参阅技术文档。

View File

@ -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;
}
}

View File

@ -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",["更新说明文档","添加日志输出"])
];
}

View File

@ -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层消息发送 ========`);
}
}