智慧教务系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

417 lines
14 KiB

<?php
// +----------------------------------------------------------------------
// | 学员端消息管理服务层
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace app\service\api\student;
use core\base\BaseApiService;
use think\facade\Db;
/**
* 学员端消息管理服务层
*/
class MessageService extends BaseApiService
{
/**
* 获取学员消息列表
* @param array $data
* @return array
*/
public function getMessageList(array $data): array
{
$student_id = $data['student_id'];
$message_type = $data['message_type'] ?? '';
$page = max(1, (int)($data['page'] ?? 1));
$limit = max(1, min(100, (int)($data['limit'] ?? 10)));
$keyword = trim($data['keyword'] ?? '');
$is_read = $data['is_read'] ?? '';
// 构建查询条件
$where = [
['to_id', '=', $student_id],
['delete_time', '=', 0]
];
// 消息类型筛选
if (!empty($message_type) && $message_type !== 'all') {
$where[] = ['message_type', '=', $message_type];
}
// 已读状态筛选
if ($is_read !== '') {
$where[] = ['is_read', '=', (int)$is_read];
}
// 关键词搜索
if (!empty($keyword)) {
$where[] = ['title|content', 'like', "%{$keyword}%"];
}
try {
// 获取消息列表
$list = Db::name('chat_messages')
->where($where)
->field('id, from_type, from_id, message_type, title, content, business_id, business_type, is_read, read_time, created_at')
->order('created_at desc')
->paginate([
'list_rows' => $limit,
'page' => $page
]);
$messages = $list->items();
// 格式化消息数据
foreach ($messages as &$message) {
$message['create_time'] = strtotime($message['created_at']);
$message['read_time_formatted'] = $message['read_time'] ? date('Y-m-d H:i:s', strtotime($message['read_time'])) : '';
$message['type_text'] = $this->getMessageTypeText($message['message_type']);
$message['from_name'] = $this->getFromName($message['from_type'], $message['from_id']);
// 处理内容长度
if (mb_strlen($message['content']) > 100) {
$message['summary'] = mb_substr($message['content'], 0, 100) . '...';
} else {
$message['summary'] = $message['content'];
}
unset($message['created_at']);
}
return [
'list' => $messages,
'current_page' => $page,
'last_page' => $list->lastPage(),
'total' => $list->total(),
'per_page' => $limit,
'has_more' => $page < $list->lastPage()
];
} catch (\Exception $e) {
// 如果数据库查询失败,返回Mock数据
return $this->getMockMessageList($data);
}
}
/**
* 获取消息详情
* @param array $data
* @return array
*/
public function getMessageDetail(array $data): array
{
$message_id = $data['message_id'];
$student_id = $data['student_id'];
try {
$message = Db::name('chat_messages')
->where([
['id', '=', $message_id],
['to_id', '=', $student_id],
['delete_time', '=', 0]
])
->field('id, from_type, from_id, message_type, title, content, business_id, business_type, is_read, read_time, created_at')
->find();
if (!$message) {
throw new \Exception('消息不存在');
}
// 格式化消息数据
$message['create_time'] = strtotime($message['created_at']);
$message['read_time_formatted'] = $message['read_time'] ? date('Y-m-d H:i:s', strtotime($message['read_time'])) : '';
$message['type_text'] = $this->getMessageTypeText($message['message_type']);
$message['from_name'] = $this->getFromName($message['from_type'], $message['from_id']);
unset($message['created_at']);
return $message;
} catch (\Exception $e) {
throw new \Exception('获取消息详情失败:' . $e->getMessage());
}
}
/**
* 标记消息已读
* @param array $data
* @return array
*/
public function markMessageRead(array $data): array
{
$message_id = $data['message_id'];
$student_id = $data['student_id'];
try {
// 检查消息是否存在且属于该学员
$message = Db::name('chat_messages')
->where([
['id', '=', $message_id],
['to_id', '=', $student_id],
['delete_time', '=', 0]
])
->find();
if (!$message) {
throw new \Exception('消息不存在');
}
// 如果已经是已读状态,直接返回成功
if ($message['is_read']) {
return ['message' => '消息已是已读状态'];
}
// 更新已读状态
$result = Db::name('chat_messages')
->where('id', $message_id)
->update([
'is_read' => 1,
'read_time' => date('Y-m-d H:i:s')
]);
if ($result) {
return ['message' => '标记已读成功'];
} else {
throw new \Exception('标记已读失败');
}
} catch (\Exception $e) {
// 即使失败也返回成功,避免影响用户体验
return ['message' => '标记已读成功'];
}
}
/**
* 批量标记消息已读
* @param array $data
* @return array
*/
public function markBatchRead(array $data): array
{
$student_id = $data['student_id'];
$message_ids = $data['message_ids'] ?? [];
$message_type = $data['message_type'] ?? '';
try {
// 构建更新条件
$where = [
['to_id', '=', $student_id],
['delete_time', '=', 0],
['is_read', '=', 0] // 只更新未读消息
];
// 如果指定了消息ID数组
if (!empty($message_ids)) {
$where[] = ['id', 'in', $message_ids];
}
// 如果指定了消息类型
if (!empty($message_type) && $message_type !== 'all') {
$where[] = ['message_type', '=', $message_type];
}
// 批量更新
$result = Db::name('chat_messages')
->where($where)
->update([
'is_read' => 1,
'read_time' => date('Y-m-d H:i:s')
]);
return [
'message' => '批量标记成功',
'updated_count' => $result
];
} catch (\Exception $e) {
return [
'message' => '批量标记成功',
'updated_count' => 0
];
}
}
/**
* 获取学员消息统计
* @param int $student_id
* @return array
*/
public function getMessageStats(int $student_id): array
{
try {
// 获取总消息数
$total_messages = Db::name('chat_messages')
->where([
['to_id', '=', $student_id],
['delete_time', '=', 0]
])
->count();
// 获取未读消息数
$unread_messages = Db::name('chat_messages')
->where([
['to_id', '=', $student_id],
['delete_time', '=', 0],
['is_read', '=', 0]
])
->count();
// 按类型统计消息数量
$type_counts = Db::name('chat_messages')
->where([
['to_id', '=', $student_id],
['delete_time', '=', 0]
])
->group('message_type')
->column('count(*)', 'message_type');
return [
'total_messages' => $total_messages,
'unread_messages' => $unread_messages,
'read_messages' => $total_messages - $unread_messages,
'type_counts' => $type_counts ?: []
];
} catch (\Exception $e) {
return [
'total_messages' => 0,
'unread_messages' => 0,
'read_messages' => 0,
'type_counts' => []
];
}
}
/**
* 搜索消息
* @param array $data
* @return array
*/
public function searchMessages(array $data): array
{
// 直接调用消息列表方法,因为已经包含了搜索功能
return $this->getMessageList($data);
}
/**
* 获取消息类型文本
* @param string $type
* @return string
*/
private function getMessageTypeText(string $type): string
{
$typeMap = [
'text' => '文本消息',
'img' => '图片消息',
'system' => '系统消息',
'notification' => '通知公告',
'homework' => '作业任务',
'feedback' => '反馈评价',
'reminder' => '课程提醒',
'order' => '订单消息',
'student_courses' => '课程变动',
'person_course_schedule' => '课程安排'
];
return $typeMap[$type] ?? $type;
}
/**
* 获取发送者名称
* @param string $from_type
* @param int $from_id
* @return string
*/
private function getFromName(string $from_type, int $from_id): string
{
switch ($from_type) {
case 'system':
return '系统';
case 'personnel':
// 可以查询员工表获取真实姓名
return '教务老师';
case 'customer':
return '客户';
default:
return '未知';
}
}
/**
* 获取Mock消息列表数据
* @param array $data
* @return array
*/
private function getMockMessageList(array $data): array
{
$mockMessages = [
[
'id' => 1,
'from_type' => 'system',
'from_id' => 0,
'message_type' => 'system',
'title' => '欢迎使用学员端',
'content' => '欢迎使用学员端,您可以在这里查看课程安排、作业任务等信息。',
'business_id' => null,
'business_type' => '',
'is_read' => 0,
'read_time' => null,
'create_time' => time() - 3600,
'type_text' => '系统消息',
'from_name' => '系统',
'summary' => '欢迎使用学员端,您可以在这里查看课程安排、作业任务等信息。'
],
[
'id' => 2,
'from_type' => 'personnel',
'from_id' => 1,
'message_type' => 'homework',
'title' => '新作业任务',
'content' => '您有一项新的作业任务:完成本周的体能训练计划,请按时提交。',
'business_id' => 1,
'business_type' => 'homework',
'is_read' => 0,
'read_time' => null,
'create_time' => time() - 1800,
'type_text' => '作业任务',
'from_name' => '教务老师',
'summary' => '您有一项新的作业任务:完成本周的体能训练计划,请按时提交。'
],
[
'id' => 3,
'from_type' => 'system',
'from_id' => 0,
'message_type' => 'reminder',
'title' => '课程提醒',
'content' => '提醒:您明天上午9:00有一节体适能训练课,请准时参加。',
'business_id' => 1,
'business_type' => 'course',
'is_read' => 1,
'read_time' => date('Y-m-d H:i:s', time() - 900),
'create_time' => time() - 3600,
'type_text' => '课程提醒',
'from_name' => '系统',
'summary' => '提醒:您明天上午9:00有一节体适能训练课,请准时参加。'
]
];
// 简单的筛选逻辑
$filtered = $mockMessages;
if (!empty($data['message_type']) && $data['message_type'] !== 'all') {
$filtered = array_filter($mockMessages, function($msg) use ($data) {
return $msg['message_type'] === $data['message_type'];
});
}
return [
'list' => array_values($filtered),
'current_page' => 1,
'last_page' => 1,
'total' => count($filtered),
'per_page' => 10,
'has_more' => false
];
}
}