打造寵物健康管理系統:Laravel 與 Vue 的現代化實作
引言
寵物健康管理系統(PetCare System)是一款幫助寵物主人管理健康記錄、行為日誌和多隻寵物的網路應用程式。本文旨在為技術人員提供實務參考,深入探討其技術實現,涵蓋後端(Laravel 11)、前端(Vue 3 與 Pinia)、多語系支援、PWA 功能及 Docker 部署。文章展示如何構建一個模組化、可擴展的 Web 應用。
您可以透過以下 GitHub 連結檢閱本專案的原始碼:https://github.com/BpsEason/petcare-system.git
系統架構
系統採用分層架構,確保模組化與可維護性:
後端:使用 Laravel 11(PHP 8.2)提供 RESTful API,並利用 Laravel Sanctum 進行無狀態認證。後端連接到外部 MySQL 資料庫,核心模型包括
User
、Pet
、HealthRecord
和BehaviorLog
,這些模型通過外鍵關聯實現數據一致性。前端:採用 Vue 3 框架,搭配 Pinia 進行狀態管理。同時,使用 Vue Router 處理路由,並透過 Vue I18n 實現多語系切換。PWA 功能則透過 Vite PWA 外掛提供離線體驗。
部署:利用 Docker Compose 定義三個服務(Nginx、Laravel、Vue 構建)。其中,Nginx 作為反向代理,處理前端靜態檔案和後端 API 請求,確保開發、測試和生產環境的一致性。
核心功能實作與程式碼解析
1. 用戶認證與安全性
系統使用 Laravel Sanctum 實現 API 認證。用戶透過 /api/register
和 /api/login
端點獲取個人存取令牌(Personal Access Token),並將其儲存於前端的 Pinia Store。後端 API 端點則受 auth:sanctum
中間件保護,確保只有經過認證的用戶才能訪問。
關鍵程式碼(app/Http/Controllers/AuthController.php
):
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
class AuthController extends Controller
{
// 用戶註冊,驗證輸入並生成存取令牌
public function register(Request $request)
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|unique:users',
'password' => 'required|string|min:8',
]);
$user = User::create([
'name' => $validated['name'],
'email' => $validated['email'],
'password' => Hash::make($validated['password']),
]);
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json(['token' => $token, 'user' => $user]);
}
}
此外,前端的 axios
攔截器會自動在每個請求中添加此令牌,並處理 401
錯誤,將用戶導回登入頁面,從而增強了安全性與用戶體驗。
2. 多寵物管理
系統支援用戶管理多隻寵物。Pet
模型與 User
建立一對多關聯,並透過 is_default
欄位標記預設寵物。前端 Pinia 的 pet.js
管理寵物列表與選定狀態,並透過 /api/pets
端點與後端同步。
關鍵程式碼(frontend/src/stores/pet.js
):
import { defineStore } from 'pinia';
import axios from 'axios';
export const usePetStore = defineStore('pet', {
state: () => ({
pets: [], // 儲存寵物列表
selectedPetId: null, // 當前選定寵物 ID
}),
actions: {
// 獲取用戶的寵物列表並設置預設寵物
async fetchPets() {
const response = await axios.get('/api/pets');
this.pets = response.data;
if (this.pets.length > 0 && !this.selectedPetId) {
this.selectedPetId = this.pets.find(p => p.is_default)?.id || this.pets[0].id;
}
},
// 切換選定寵物
setSelectedPet(petId) {
this.selectedPetId = petId;
},
},
});
3. 健康記錄與行為日誌
健康記錄(HealthRecord
)和行為日誌(BehaviorLog
)通過 pet_id
與 Pet
模型關聯,提供完整的 CRUD 操作。後端控制器使用 Policy(例如 HealthRecordPolicy
)來限制訪問,確保只有寵物主人才能操作其數據。
關鍵程式碼(frontend/src/views/DashboardView.vue
):
<template>
<div class="container mx-auto p-4">
<select v-model="selectedPetId" @change="changePet" class="mb-4 p-2 border rounded">
<option v-for="pet in pets" :key="pet.id" :value="pet.id">{{ pet.name }}</option>
</select>
<form @submit.prevent="addHealthRecord">
<input type="date" v-model="newRecord.record_date" required />
<input type="text" v-model="newRecord.record_type" :placeholder="$t('health_record.type')" required />
<button type="submit">{{ $t('health_record.add') }}</button>
</form>
</div>
</template>
<script>
import { usePetStore } from '@/stores/pet';
import axios from 'axios';
export default {
data() {
return {
newRecord: { record_date: '', record_type: '' }, // 新增健康記錄表單數據
};
},
computed: {
pets() {
return usePetStore().pets; // 從 Pinia 獲取寵物列表
},
selectedPetId: {
get() { return usePetStore().selectedPetId; }, // 獲取選定寵物
set(value) { usePetStore().setSelectedPet(value); }, // 更新選定寵物
},
},
methods: {
async addHealthRecord() {
await axios.post(`/api/pets/${this.selectedPetId}/health-records`, this.newRecord);
this.newRecord = { record_date: '', record_type: '' }; // 重置表單
},
},
};
</script>
4. 多語系支援
後端使用 Laravel 的語系檔案 (resources/lang/{en,zh_TW,zh_CN}
),並透過一個 SetLocale 中間件根據 Accept-Language
標頭切換語系。前端則使用 Vue I18n,並將用戶選擇儲存在 localStorage
中,以確保語系在瀏覽器刷新後仍保持一致。
關鍵程式碼(app/Http/Middleware/SetLocale.php
):
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
class SetLocale
{
// 根據請求標頭設置語系
public function handle(Request $request, Closure $next)
{
$locale = $request->header('Accept-Language', config('app.fallback_locale'));
if (in_array($locale, ['en', 'zh_TW', 'zh_CN'])) {
App::setLocale($locale);
}
return $next($request);
}
}
5. PWA 與離線體驗
系統使用 Vite PWA 外掛(vite-plugin-pwa
)自動生成 manifest.json
和 Service Worker。這使得應用程式可以被「安裝」到設備上,並支援離線訪問。Nginx 配置也確保了 Service Worker 緩存的正確運作。
關鍵程式碼(frontend/vite.config.js
):
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { VitePWA } from 'vite-plugin-pwa';
export default defineConfig({
plugins: [
vue(),
VitePWA({
registerType: 'autoUpdate', // 自動更新 Service Worker
manifest: {
name: 'PetCare System',
short_name: 'PetCare',
icons: [
{ src: '/assets/icon-192x192.png', sizes: '192x192', type: 'image/png' },
{ src: '/assets/icon-512x512.png', sizes: '512x512', type: 'image/png' },
],
theme_color: '#42b983',
background_color: '#ffffff',
display: 'standalone',
},
}),
],
});
6. Docker 部署
docker-compose.yml
檔案定義了所有必要的服務,包括 Nginx(反向代理)、Laravel(PHP-FPM)和 Vue 構建服務。這種容器化方法確保了部署的可靠性與環境的一致性,極大簡化了開發與部署流程。
關鍵程式碼(docker-compose.yml
):
version: '3.8'
services:
nginx:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./frontend/dist:/usr/share/nginx/html
depends_on:
- backend
networks:
- app-network
backend:
build:
context: ./backend
dockerfile: Dockerfile
environment:
- DB_HOST=${DB_HOST}
- DB_DATABASE=${DB_DATABASE}
- DB_USERNAME=${DB_USERNAME}
- DB_PASSWORD=${DB_PASSWORD}
networks:
- app-network
frontend_build:
build:
context: ./frontend
dockerfile: Dockerfile
volumes:
- ./frontend/dist:/app/dist
networks:
- app-network
networks:
app-network:
driver: bridge
結論
寵物健康管理系統展示了一個現代化 Web 應用的完整實作。它結合了 Laravel 的強大後端功能、Vue 的靈活前端框架和 Docker 的可靠部署。專案的模組化設計和多語系支援,為未來擴展(如飲食追蹤、趨勢圖)奠定了堅實的基礎。技術人員可參考本文的程式碼和架構,將其經驗應用於類似的專案。