From e8bef5bc061d53d5fed6240597d9709eb4722bc3 Mon Sep 17 00:00:00 2001 From: gbanyan Date: Fri, 13 Feb 2026 12:09:09 +0800 Subject: [PATCH] feat(01-02): create MemberNoteController and routes - MemberNoteController with index() and store() methods - StoreNoteRequest with Traditional Chinese validation messages - Routes registered at admin.members.notes.index/store - JSON responses for AJAX consumption in Phase 2 - DB::transaction wrapper with AuditLogger::log --- .../Admin/MemberNoteController.php | 48 +++++++++++++++++++ app/Http/Requests/StoreNoteRequest.php | 41 ++++++++++++++++ routes/web.php | 5 ++ 3 files changed, 94 insertions(+) create mode 100644 app/Http/Controllers/Admin/MemberNoteController.php create mode 100644 app/Http/Requests/StoreNoteRequest.php diff --git a/app/Http/Controllers/Admin/MemberNoteController.php b/app/Http/Controllers/Admin/MemberNoteController.php new file mode 100644 index 0000000..d664883 --- /dev/null +++ b/app/Http/Controllers/Admin/MemberNoteController.php @@ -0,0 +1,48 @@ +notes()->with('author')->get(); + + return response()->json(['notes' => $notes]); + } + + /** + * Store a new note for a member + */ + public function store(StoreNoteRequest $request, Member $member) + { + $note = DB::transaction(function () use ($request, $member) { + $note = $member->notes()->create([ + 'content' => $request->content, + 'author_user_id' => $request->user()->id, + ]); + + AuditLogger::log('note.created', $note, [ + 'member_id' => $member->id, + 'member_name' => $member->full_name, + 'author' => $request->user()->name, + ]); + + return $note; + }); + + return response()->json([ + 'note' => $note->load('author'), + 'message' => '備忘錄已新增', + ], 201); + } +} diff --git a/app/Http/Requests/StoreNoteRequest.php b/app/Http/Requests/StoreNoteRequest.php new file mode 100644 index 0000000..1515363 --- /dev/null +++ b/app/Http/Requests/StoreNoteRequest.php @@ -0,0 +1,41 @@ +|string> + */ + public function rules(): array + { + return [ + 'content' => ['required', 'string', 'min:1', 'max:65535'], + ]; + } + + /** + * Get custom messages for validator errors. + */ + public function messages(): array + { + return [ + 'content.required' => '備忘錄內容為必填欄位', + 'content.min' => '備忘錄內容不可為空白', + 'content.max' => '備忘錄內容不可超過 65535 字元', + ]; + } +} diff --git a/routes/web.php b/routes/web.php index 2717abb..a6e6e67 100644 --- a/routes/web.php +++ b/routes/web.php @@ -27,6 +27,7 @@ use App\Http\Controllers\Admin\ArticleController; use App\Http\Controllers\Admin\ArticleCategoryController; use App\Http\Controllers\Admin\ArticleTagController; use App\Http\Controllers\Admin\PageController; +use App\Http\Controllers\Admin\MemberNoteController; use App\Http\Controllers\PublicBugReportController; use App\Http\Controllers\IncomeController; use Illuminate\Support\Facades\Route; @@ -138,6 +139,10 @@ Route::middleware(['auth', 'admin'])->prefix('admin')->name('admin.')->group(fun Route::delete('/members/{member}/payments/{payment}', [AdminPaymentController::class, 'destroy'])->name('members.payments.destroy'); Route::get('/members/{member}/payments/{payment}/receipt', [AdminPaymentController::class, 'receipt'])->name('members.payments.receipt'); + // Member Notes (會員備忘錄) + Route::get('/members/{member}/notes', [MemberNoteController::class, 'index'])->name('members.notes.index'); + Route::post('/members/{member}/notes', [MemberNoteController::class, 'store'])->name('members.notes.store'); + Route::get('/finance-documents', [FinanceDocumentController::class, 'index'])->name('finance.index'); Route::get('/finance-documents/create', [FinanceDocumentController::class, 'create'])->name('finance.create'); Route::post('/finance-documents', [FinanceDocumentController::class, 'store'])->name('finance.store');