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