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}》— 点击查看详情", 'is_secret' => false, 'font_color' => '#7c3aed', 'action' => '', 'sent_at' => now()->toIso8601String(), ]); } }