From 2e71a1cb293b6e0e70bb17e54e713e4de2083e9d Mon Sep 17 00:00:00 2001 From: sky121113 Date: Thu, 29 Jan 2026 16:28:34 +0800 Subject: [PATCH] Feature: Tenant Short Name and Branding Implementation - Added short_name to Tenant model and controller - Updated Landlord/Tenant pages (Create, Edit, Show, Index) - Implemented branding customization (Favicon, Login Copyright, Sidebar Title) - Updated HandleInertiaRequests to share branding data --- .../Controllers/Landlord/TenantController.php | 6 +++++ app/Http/Middleware/HandleInertiaRequests.php | 27 +++++++++++-------- resources/js/Layouts/AuthenticatedLayout.tsx | 8 +++--- resources/js/Pages/Auth/Login.tsx | 6 +++-- resources/js/Pages/Landlord/Tenant/Create.tsx | 16 +++++++++++ resources/js/Pages/Landlord/Tenant/Edit.tsx | 15 +++++++++++ resources/js/Pages/Landlord/Tenant/Index.tsx | 9 ++++++- resources/js/Pages/Landlord/Tenant/Show.tsx | 5 ++++ resources/js/types/global.d.ts | 3 +++ resources/views/app.blade.php | 1 + 10 files changed, 78 insertions(+), 18 deletions(-) diff --git a/app/Http/Controllers/Landlord/TenantController.php b/app/Http/Controllers/Landlord/TenantController.php index 388cefc..6137b77 100644 --- a/app/Http/Controllers/Landlord/TenantController.php +++ b/app/Http/Controllers/Landlord/TenantController.php @@ -19,6 +19,7 @@ class TenantController extends Controller return [ 'id' => $tenant->id, 'name' => $tenant->name ?? $tenant->id, + 'short_name' => $tenant->short_name ?? null, 'email' => $tenant->email ?? null, 'is_active' => $tenant->is_active ?? true, 'created_at' => $tenant->created_at->format('Y-m-d H:i'), @@ -47,6 +48,7 @@ class TenantController extends Controller $validated = $request->validate([ 'id' => ['required', 'string', 'max:50', 'alpha_dash', Rule::unique('tenants', 'id')], 'name' => ['required', 'string', 'max:100'], + 'short_name' => ['nullable', 'string', 'max:50'], 'email' => ['nullable', 'email', 'max:100'], 'domain' => ['nullable', 'string', 'max:100'], ]); @@ -54,6 +56,7 @@ class TenantController extends Controller $tenant = Tenant::create([ 'id' => $validated['id'], 'name' => $validated['name'], + 'short_name' => $validated['short_name'] ?? null, 'email' => $validated['email'] ?? null, 'is_active' => true, 'branding' => [ @@ -85,6 +88,7 @@ class TenantController extends Controller 'tenant' => [ 'id' => $tenant->id, 'name' => $tenant->name ?? $tenant->id, + 'short_name' => $tenant->short_name ?? null, 'email' => $tenant->email ?? null, 'is_active' => $tenant->is_active ?? true, 'created_at' => $tenant->created_at->format('Y-m-d H:i'), @@ -128,6 +132,7 @@ class TenantController extends Controller 'tenant' => [ 'id' => $tenant->id, 'name' => $tenant->name ?? $tenant->id, + 'short_name' => $tenant->short_name ?? null, 'email' => $tenant->email ?? null, 'is_active' => $tenant->is_active ?? true, ], @@ -143,6 +148,7 @@ class TenantController extends Controller $validated = $request->validate([ 'name' => ['required', 'string', 'max:100'], + 'short_name' => ['nullable', 'string', 'max:50'], 'email' => ['nullable', 'email', 'max:100'], 'is_active' => ['boolean'], ]); diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index 5960858..ca4217e 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -64,25 +64,30 @@ class HandleInertiaRequests extends Middleware ], 'branding' => function () { $tenant = tenancy()->tenant; - if (!$tenant) { - // 中央後台預設 Branding - return [ - 'logo_url' => \Storage::url('defaults/logo.png'), // 中央後台也使用預設 Logo - 'primary_color' => '#4F46E5', - 'text_color' => '#1a1a1a', - ]; - } + + // 決定名稱顯示邏輯 + $fullName = $tenant ? ($tenant->name ?? 'Star ERP') : 'Star ERP 中央後台'; + $shortName = $tenant ? ($tenant->short_name ?? $fullName) : 'Start ERP'; $logoUrl = null; - if (isset($tenant->branding['logo_path'])) { + if ($tenant && isset($tenant->branding['logo_path'])) { $logoUrl = \Storage::url($tenant->branding['logo_path']); + } elseif (!$tenant) { + $logoUrl = \Storage::url('defaults/logo.png'); } - return [ + $brandingData = [ + 'name' => $fullName, + 'short_name' => $shortName, 'logo_url' => $logoUrl, - 'primary_color' => $tenant->branding['primary_color'] ?? '#01ab83', + 'primary_color' => $tenant->branding['primary_color'] ?? ($tenant ? '#01ab83' : '#4F46E5'), 'text_color' => $tenant->branding['text_color'] ?? '#1a1a1a', ]; + + // 同步分享給 Blade View (給 app.blade.php 使用 Favicon) + \Illuminate\Support\Facades\View::share('branding', $brandingData); + + return $brandingData; }, ]; } diff --git a/resources/js/Layouts/AuthenticatedLayout.tsx b/resources/js/Layouts/AuthenticatedLayout.tsx index 6036bbd..039d081 100644 --- a/resources/js/Layouts/AuthenticatedLayout.tsx +++ b/resources/js/Layouts/AuthenticatedLayout.tsx @@ -454,7 +454,7 @@ export default function AuthenticatedLayout({ - 小小冰室 ERP + {branding?.short_name || '小小冰室'} ERP @@ -510,7 +510,7 @@ export default function AuthenticatedLayout({ {!isCollapsed && ( - 小小冰室 ERP + {branding?.short_name || '小小冰室'} ERP )} {isCollapsed && ( @@ -559,7 +559,7 @@ export default function AuthenticatedLayout({
- 小小冰室 ERP + {branding?.short_name || '小小冰室'} ERP
- Copyright © {new Date().getFullYear()} 小小冰室. All rights reserved. Design by 星科技 + Copyright © {new Date().getFullYear()} {branding?.name || '小小冰室'}. All rights reserved. Design by 星科技
diff --git a/resources/js/Pages/Auth/Login.tsx b/resources/js/Pages/Auth/Login.tsx index 95a8d38..0e07aa7 100644 --- a/resources/js/Pages/Auth/Login.tsx +++ b/resources/js/Pages/Auth/Login.tsx @@ -1,4 +1,5 @@ -import { Head, useForm } from "@inertiajs/react"; +import { Head, useForm, usePage } from "@inertiajs/react"; +import { PageProps } from "@/types/global"; import { FormEventHandler, useEffect } from "react"; import { cn } from "@/lib/utils"; import { Button } from "@/Components/ui/button"; @@ -8,6 +9,7 @@ import InputError from "../../Components/InputError"; import ApplicationLogo from "../../Components/ApplicationLogo"; export default function Login() { + const { props } = usePage(); const { data, setData, post, processing, errors, reset } = useForm({ username: localStorage.getItem("saved_username") || "", password: "", @@ -134,7 +136,7 @@ export default function Login() {

- © 2026 小小冰室. All rights reserved. + © {new Date().getFullYear()} {props.branding?.name || '小小冰室'}. All rights reserved.

diff --git a/resources/js/Pages/Landlord/Tenant/Create.tsx b/resources/js/Pages/Landlord/Tenant/Create.tsx index 47277b3..25f68a8 100644 --- a/resources/js/Pages/Landlord/Tenant/Create.tsx +++ b/resources/js/Pages/Landlord/Tenant/Create.tsx @@ -6,6 +6,7 @@ export default function TenantCreate() { const { data, setData, post, processing, errors } = useForm({ id: "", name: "", + short_name: "", email: "", domain: "", }); @@ -55,6 +56,21 @@ export default function TenantCreate() { {errors.name &&

{errors.name}

} +
+ + setData("short_name", e.target.value)} + placeholder="例如:小冰" + className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-primary-main focus:border-primary-main" + /> +

選填

+ {errors.short_name &&

{errors.short_name}

} +
+
+
+ + setData("short_name", e.target.value)} + className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-primary-main focus:border-primary-main" + /> +

選填

+
+
+ + {tenant.short_name || '-'} + {tenant.domains.length > 0 ? (
diff --git a/resources/js/Pages/Landlord/Tenant/Show.tsx b/resources/js/Pages/Landlord/Tenant/Show.tsx index 61a31b9..c4ceaad 100644 --- a/resources/js/Pages/Landlord/Tenant/Show.tsx +++ b/resources/js/Pages/Landlord/Tenant/Show.tsx @@ -11,6 +11,7 @@ interface Domain { interface Tenant { id: string; name: string; + short_name: string | null; email: string | null; is_active: boolean; created_at: string; @@ -97,6 +98,10 @@ export default function TenantShow({ tenant }: Props) {
+
+
客戶簡稱
+
{tenant.short_name || "-"}
+
聯絡信箱
{tenant.email || "-"}
diff --git a/resources/js/types/global.d.ts b/resources/js/types/global.d.ts index 56296ff..c7330af 100644 --- a/resources/js/types/global.d.ts +++ b/resources/js/types/global.d.ts @@ -12,6 +12,8 @@ export interface AuthUser { } export interface Branding { + name?: string; + short_name?: string; logo_url?: string | null; primary_color?: string; text_color?: string; @@ -26,6 +28,7 @@ export interface PageProps { error?: string; }; branding?: Branding | null; + [key: string]: unknown; } declare global { diff --git a/resources/views/app.blade.php b/resources/views/app.blade.php index 7726ce3..163bc6c 100644 --- a/resources/views/app.blade.php +++ b/resources/views/app.blade.php @@ -7,6 +7,7 @@ {{ config('app.name', 'Laravel') }} +