2025年7月31日 星期四

打造全方位的寵物健康管理系統:Laravel 11, Vue 3, Pinia 與 Docker 實戰

打造寵物健康管理系統: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 資料庫,核心模型包括 UserPetHealthRecordBehaviorLog,這些模型通過外鍵關聯實現數據一致性。

  • 前端:採用 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
<?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 欄位標記預設寵物。前端 Piniapet.js 管理寵物列表與選定狀態,並透過 /api/pets 端點與後端同步。

關鍵程式碼(frontend/src/stores/pet.js

JavaScript
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_idPet 模型關聯,提供完整的 CRUD 操作。後端控制器使用 Policy(例如 HealthRecordPolicy)來限制訪問,確保只有寵物主人才能操作其數據。

關鍵程式碼(frontend/src/views/DashboardView.vue

HTML
<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
<?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.jsonService Worker。這使得應用程式可以被「安裝」到設備上,並支援離線訪問。Nginx 配置也確保了 Service Worker 緩存的正確運作。

關鍵程式碼(frontend/vite.config.js

JavaScript
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

YAML
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 的可靠部署。專案的模組化設計和多語系支援,為未來擴展(如飲食追蹤、趨勢圖)奠定了堅實的基礎。技術人員可參考本文的程式碼和架構,將其經驗應用於類似的專案。

熱門文章