192 lines
6.3 KiB
PHP
192 lines
6.3 KiB
PHP
|
|
<?php
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 文件功能:后台开发日志管理控制器(仅 id=1 超级管理员可访问)
|
|||
|
|
* 提供开发日志的 CRUD 功能,发布时可选择向 Room 1 大厅广播通知
|
|||
|
|
*
|
|||
|
|
* @author ChatRoom Laravel
|
|||
|
|
*
|
|||
|
|
* @version 1.0.0
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
namespace App\Http\Controllers\Admin;
|
|||
|
|
|
|||
|
|
use App\Events\ChangelogPublished;
|
|||
|
|
use App\Http\Controllers\Controller;
|
|||
|
|
use App\Jobs\SaveMessageJob;
|
|||
|
|
use App\Models\DevChangelog;
|
|||
|
|
use Illuminate\Http\RedirectResponse;
|
|||
|
|
use Illuminate\Http\Request;
|
|||
|
|
use Illuminate\Support\Carbon;
|
|||
|
|
use Illuminate\View\View;
|
|||
|
|
|
|||
|
|
class ChangelogController extends Controller
|
|||
|
|
{
|
|||
|
|
/**
|
|||
|
|
* 后台日志列表(含草稿)
|
|||
|
|
*/
|
|||
|
|
public function index(): View
|
|||
|
|
{
|
|||
|
|
$logs = DevChangelog::orderByDesc('created_at')->paginate(20);
|
|||
|
|
|
|||
|
|
return view('admin.changelog.index', compact('logs'));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 新增日志表单页(预填今日日期)
|
|||
|
|
*/
|
|||
|
|
public function create(): View
|
|||
|
|
{
|
|||
|
|
// 预填今日日期为版本号
|
|||
|
|
$todayVersion = now()->format('Y-m-d');
|
|||
|
|
|
|||
|
|
return view('admin.changelog.form', [
|
|||
|
|
'log' => null,
|
|||
|
|
'todayVersion' => $todayVersion,
|
|||
|
|
'typeOptions' => DevChangelog::TYPE_CONFIG,
|
|||
|
|
'isCreate' => true,
|
|||
|
|
]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 保存新日志
|
|||
|
|
* 若勾选"立即发布",则记录 published_at 并可选向大厅广播通知
|
|||
|
|
*/
|
|||
|
|
public function store(Request $request): RedirectResponse
|
|||
|
|
{
|
|||
|
|
$data = $request->validate([
|
|||
|
|
'version' => 'required|string|max:30',
|
|||
|
|
'title' => 'required|string|max:200',
|
|||
|
|
'type' => 'required|in:feature,fix,improve,other',
|
|||
|
|
'content' => 'required|string',
|
|||
|
|
'is_published' => 'nullable|boolean',
|
|||
|
|
'notify_chat' => 'nullable|boolean',
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
$isPublished = (bool) ($data['is_published'] ?? false);
|
|||
|
|
$notifyChat = (bool) ($data['notify_chat'] ?? false);
|
|||
|
|
|
|||
|
|
/** @var DevChangelog $log */
|
|||
|
|
$log = DevChangelog::create([
|
|||
|
|
'version' => $data['version'],
|
|||
|
|
'title' => $data['title'],
|
|||
|
|
'type' => $data['type'],
|
|||
|
|
'content' => $data['content'],
|
|||
|
|
'is_published' => $isPublished,
|
|||
|
|
// 只有同时勾选"通知"才记录 notify_chat,否则置 false
|
|||
|
|
'notify_chat' => $isPublished && $notifyChat,
|
|||
|
|
// 首次发布时记录发布时间
|
|||
|
|
'published_at' => $isPublished ? Carbon::now() : null,
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
// 如果发布且勾选了"通知大厅用户",则触发 WebSocket 广播 + 持久化到消息库
|
|||
|
|
if ($isPublished && $notifyChat) {
|
|||
|
|
event(new ChangelogPublished($log));
|
|||
|
|
$this->saveChangelogNotification($log);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return redirect()->route('admin.changelogs.index')
|
|||
|
|
->with('success', '开发日志创建成功!'.($isPublished ? '(已发布)' : '(草稿已保存)'));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 编辑日志表单页
|
|||
|
|
*
|
|||
|
|
* @param DevChangelog $changelog 路由模型自动注入
|
|||
|
|
*/
|
|||
|
|
public function edit(DevChangelog $changelog): View
|
|||
|
|
{
|
|||
|
|
return view('admin.changelog.form', [
|
|||
|
|
'log' => $changelog,
|
|||
|
|
'todayVersion' => $changelog->version,
|
|||
|
|
'typeOptions' => DevChangelog::TYPE_CONFIG,
|
|||
|
|
'isCreate' => false,
|
|||
|
|
]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 更新日志内容(编辑操作不更新 published_at,不触发通知)
|
|||
|
|
*
|
|||
|
|
* @param DevChangelog $changelog 路由模型自动注入
|
|||
|
|
*/
|
|||
|
|
public function update(Request $request, DevChangelog $changelog): RedirectResponse
|
|||
|
|
{
|
|||
|
|
$log = $changelog;
|
|||
|
|
|
|||
|
|
$data = $request->validate([
|
|||
|
|
'version' => 'required|string|max:30',
|
|||
|
|
'title' => 'required|string|max:200',
|
|||
|
|
'type' => 'required|in:feature,fix,improve,other',
|
|||
|
|
'content' => 'required|string',
|
|||
|
|
'is_published' => 'nullable|boolean',
|
|||
|
|
'notify_chat' => 'nullable|boolean',
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
$isPublished = (bool) ($data['is_published'] ?? false);
|
|||
|
|
|
|||
|
|
// 如果从草稿切换为发布,记录首次发布时间
|
|||
|
|
$publishedAt = $log->published_at;
|
|||
|
|
if ($isPublished && ! $log->is_published) {
|
|||
|
|
$publishedAt = Carbon::now();
|
|||
|
|
} elseif (! $isPublished) {
|
|||
|
|
// 从发布退回草稿,清除发布时间
|
|||
|
|
$publishedAt = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$log->update([
|
|||
|
|
'version' => $data['version'],
|
|||
|
|
'title' => $data['title'],
|
|||
|
|
'type' => $data['type'],
|
|||
|
|
'content' => $data['content'],
|
|||
|
|
'is_published' => $isPublished,
|
|||
|
|
'published_at' => $publishedAt,
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
// 若勾选了「通知大厅用户」且当前已发布,则广播通知 + 持久化到消息库
|
|||
|
|
$notifyChat = (bool) ($data['notify_chat'] ?? false);
|
|||
|
|
if ($notifyChat && $isPublished) {
|
|||
|
|
event(new ChangelogPublished($log));
|
|||
|
|
$this->saveChangelogNotification($log);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return redirect()->route('admin.changelogs.index')
|
|||
|
|
->with('success', '开发日志已更新!');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 删除日志
|
|||
|
|
*
|
|||
|
|
* @param DevChangelog $changelog 路由模型自动注入
|
|||
|
|
*/
|
|||
|
|
public function destroy(DevChangelog $changelog): RedirectResponse
|
|||
|
|
{
|
|||
|
|
$changelog->delete();
|
|||
|
|
|
|||
|
|
return redirect()->route('admin.changelogs.index')
|
|||
|
|
->with('success', '日志已删除。');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 将版本更新通知持久化为 Room 1 系统消息
|
|||
|
|
* 确保用户重进聊天室时仍能在历史消息中看到该通知
|
|||
|
|
*
|
|||
|
|
* @param DevChangelog $log 已发布的日志
|
|||
|
|
*/
|
|||
|
|
private function saveChangelogNotification(DevChangelog $log): void
|
|||
|
|
{
|
|||
|
|
$typeLabel = DevChangelog::TYPE_CONFIG[$log->type]['label'] ?? '更新';
|
|||
|
|
$url = url('/changelog').'#v'.$log->version;
|
|||
|
|
|
|||
|
|
SaveMessageJob::dispatch([
|
|||
|
|
'room_id' => 1,
|
|||
|
|
'from_user' => '系统公告',
|
|||
|
|
'to_user' => '大家',
|
|||
|
|
'content' => "📢 【版本更新 {$typeLabel}】v{$log->version}《{$log->title}》— <a href=\"{$url}\" target=\"_blank\" class=\"underline\">点击查看详情</a>",
|
|||
|
|
'is_secret' => false,
|
|||
|
|
'font_color' => '#7c3aed',
|
|||
|
|
'action' => '',
|
|||
|
|
'sent_at' => now()->toIso8601String(),
|
|||
|
|
]);
|
|||
|
|
}
|
|||
|
|
}
|