Repository: sin-huang/kizuna-project
Pull request #22: Shopping cart logic
Author: login: c16033
Created: 2025-05-27T12:14:39Z | Merged: 2025-05-29T06:27:31Z

add brand page


Diff:
diff --git a/package.json b/package.json
index a2e9e8a..41c1854 100644
--- a/package.json
+++ b/package.json
@@ -5,6 +5,7 @@
   "main": "index.js",
   "type": "module",
   "scripts": {
+    "start":"node src/server/server",
     "dev": "vite",
     "build": "vite build",
     "preview": "vite preview"
diff --git a/src/App.vue b/src/App.vue
index 6fc8219..dc7da46 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -12,7 +12,7 @@ const handleLogout = () => {
 </script>
 
 <template>
-  <header class="text-white bg-blue-900 shadow-md">
+  <header class="text-white bg-primary-100 shadow-md">
     <nav class="flex justify-start">
       <RouterLink to="/" class="p-6 text-lg transition hover:text-gray-300"
         >首頁</RouterLink
diff --git a/src/api/axios.js b/src/api/axios.js
index dbb77e2..1d480d5 100644
--- a/src/api/axios.js
+++ b/src/api/axios.js
@@ -1,5 +1,5 @@
 import axios from "axios";
-import { useUserStore } from "@/stores/user.js";
+import { useUserStore } from "../stores/user.js";
 
 const instance = axios.create({
   baseURL: "http://localhost:3000",
diff --git a/src/components/BrandProduct.vue b/src/components/BrandProduct.vue
new file mode 100644
index 0000000..e53b155
--- /dev/null
+++ b/src/components/BrandProduct.vue
@@ -0,0 +1,47 @@
+<script setup>
+import { useBrandStore } from "@/stores/brand.js";
+import ProductCard from "@/components/ProductCard.vue";
+import { useProductStore  } from "@/stores/products.js";  
+
+const brandStore = useBrandStore();
+// const cartStore = useCartStore();
+
+const productStore = useProductStore();
+const { products } = productStore;
+
+
+</script>
+
+<template>
+
+  <h2 class="text-2xl">響泰多</h2>
+
+  <div class="grid grid-cols-1 sm:grid-cols-1 lg:grid-cols-1 gap-6 py-10 ">
+      <div class="bg-sky-100 h-[250px] w-full rounded-lg  items-center gap-6">
+        <img class="rounded-lg h-full w-full object-cover block " src="https://www.siammore.com.tw/storage/website/news/siammore20240510162216_List.jpeg" alt="響泰多">
+       </div>
+    </div>
+
+  <h2 class="text-2xl py-5">人氣推薦</h2>
+
+  <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
+    <ProductCard
+      v-for="product in products"
+      :key="product.id"
+      :product="product"
+    />
+    <!-- 記得可以直接傳物件 -->
+  </div>
+    <h2 class="text-2xl py-5">全部商品</h2>
+
+<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
+    <ProductCard
+      v-for="product in products"
+      :key="product.id"
+      :product="product"
+    />
+    <!-- 記得可以直接傳物件 -->
+  </div>
+</template>
+
+<style scoped></style>
\ No newline at end of file
diff --git a/src/components/BrandProductCard.vue b/src/components/BrandProductCard.vue
new file mode 100644
index 0000000..134f2cd
--- /dev/null
+++ b/src/components/BrandProductCard.vue
@@ -0,0 +1,31 @@
+<script setup>
+import { useCartStore } from "@/stores/cart.js";
+
+const brandproductStore = useBrandProductStore();
+const cartStore = useCartStore();
+
+const { addCart } = cartStore; //解構拿來使用
+
+defineProps({
+  brandproduct: {
+    type: Object,
+    required: true,
+  },
+});
+// 記得要使用props，還有該拿到的變數資料(js)要進來
+</script>
+
+<template>
+  
+  <div class="rounded-lg shadow-lg p-4 flex flex-col items-center hover:shadow-xl transition-shadow duration-300">
+    <div>
+      <img :src="brandproduct.img" alt="" class="rounded-lg">
+    </div>
+    <p class="text-lg font-semibold text-gray-800 mt-2 mb-1">{{ brandproduct.name }}</p>
+    <p class="text-gray-600 mb-1">價格: {{ brandproduct.price }}</p>
+    <p class="text-gray-600">庫存: {{ brandproduct.inventory }}</p>
+    <button @click="addCart(brandproduct)" class="mt-4  bg-primary-200 text-black px-4 py-2 rounded hover:bg-primary-100  hover:text-white transition">加入購物車</button>
+  </div>
+</template>
+
+<style scoped></style>
\ No newline at end of file
diff --git a/src/components/CartCard.vue b/src/components/CartCard.vue
index f352dd4..478b93b 100644
--- a/src/components/CartCard.vue
+++ b/src/components/CartCard.vue
@@ -1,6 +1,6 @@
 <script setup>
-import { useCartStore } from "@/stores/cart.js";
-import { useProductStore } from "@/stores/products.js";
+import { useCartStore } from "../stores/cart.js";
+import { useProductStore } from "../stores/products.js";
 const cartStore = useCartStore();
 const productStore = useProductStore();
 // 傳資料
diff --git a/src/components/CartList.vue b/src/components/CartList.vue
index b3785e2..0fc7a80 100644
--- a/src/components/CartList.vue
+++ b/src/components/CartList.vue
@@ -1,12 +1,12 @@
 <script setup>
 import CartCard from "@/components/CartCard.vue";
-import { useCartStore } from "@/stores/cart.js";
+import { useCartStore } from "../stores/cart.js";
 const cartStore = useCartStore();
 //解構出來的東西不是響應式
 </script>
 
 <template>
-  <h1 class="text-2xl">購物車</h1>
+  <h1 class="text-2xl">購買禮物</h1>
   <br />
   <div class="grid grid-cols-5 border-b">
     <p class="col-span-2">商品資訊</p>
diff --git a/src/components/ProductCard.vue b/src/components/ProductCard.vue
index 0740244..258c725 100644
--- a/src/components/ProductCard.vue
+++ b/src/components/ProductCard.vue
@@ -1,6 +1,7 @@
 <script setup>
-import { useProductStore } from "@/stores/products.js";
-import { useCartStore } from "@/stores/cart.js";
+
+import { useProductStore } from "../stores/products.js";
+import { useCartStore } from "../stores/cart.js";
 
 const productStore = useProductStore();
 const cartStore = useCartStore();
@@ -14,17 +15,20 @@ defineProps({
   },
 });
 // 記得要使用props，還有該拿到的變數資料(js)要進來
+
+
 </script>
 
 <template>
+  
   <div class="rounded-lg shadow-lg p-4 flex flex-col items-center hover:shadow-xl transition-shadow duration-300">
     <div>
       <img :src="product.img" alt="" class="rounded-lg">
     </div>
     <p class="text-lg font-semibold text-gray-800 mt-2 mb-1">{{ product.name }}</p>
-    <p class="text-gray-600 mb-1">價格: {{ product.price }}</p>
+    <p class="text-gray-600 mb-1">$ {{ product.price }}</p>
     <p class="text-gray-600">庫存: {{ product.inventory }}</p>
-    <button @click="addCart(product)" class="mt-4 bg-blue-800 text-white px-4 py-2 rounded hover:bg-blue-900 transition">加入購物車</button>
+    <button @click="addCart(product)" class="mt-4  bg-primary-200 text-black px-4 py-2 rounded hover:bg-primary-100  hover:text-white transition">加入購物車</button>
   </div>
 </template>
 
diff --git a/src/components/ProductList.vue b/src/components/ProductList.vue
index 62097fe..045222a 100644
--- a/src/components/ProductList.vue
+++ b/src/components/ProductList.vue
@@ -1,20 +1,77 @@
 <script setup>
-import { useProductStore } from "@/stores/products.js";
+import { useProductStore, useBrandStore } from "../stores/products.js";
 import ProductCard from "@/components/ProductCard.vue";
+
 const productStore = useProductStore();
 const { products } = productStore;
+
+const brandStore = useBrandStore();
+const { filteredBrands, changeCurrentCategory } = brandStore;
+
+const handleClick = (cat) => {
+  changeCurrentCategory(cat);
+};
 // 記得要解構
 </script>
 
 <template>
-  <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
-    <ProductCard
-    v-for="product in products"
-    :key="product.id"
-    :product="product"
-  />
-  <!-- 記得可以直接傳物件 -->
+  <div class="mx-auto bg-primary-200 rounded-lg max-w-full shadow-lg">
+    <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 px-10">
+      <a
+        class="flex justify-center hover:bg-primary-100 hover:text-stone-50 text-stone-950 p-[10px] mt-[20px] rounded-lg"
+        href="#"
+        @click.prevent="handleClick('restaurant')"
+        >連鎖餐廳</a
+      >
+      <a
+        class="flex justify-center hover:bg-primary-100 hover:text-stone-50 text-stone-950 p-[10px] mt-[20px] rounded-lg"
+        href="#"
+        @click.prevent="handleClick('cafe')"
+        >咖啡/甜點</a
+      >
+      <a
+        class="flex justify-center hover:bg-primary-100 hover:text-stone-50 text-stone-950 p-[10px] mt-[20px] rounded-lg"
+        href="#"
+        @click.prevent="handleClick('fastfood')"
+        >速食快餐</a
+      >
+      <a
+        class="flex justify-center hover:bg-primary-100 hover:text-stone-50 text-stone-950 p-[10px] mt-[20px] rounded-lg"
+        href="#"
+        @click.prevent="handleClick('aroma')"
+        >療癒香氛</a
+      >
+    </div>
+
+    <div
+      class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-2 gap-6 px-10 py-10"
+    >
+      <router-link
+        class="bg-white h-[80px] rounded-lg hover:shadow-lg flex items-center gap-6"
+        v-for="brand in brandStore.filteredBrands"
+        :key="brand.id"
+        :to="`/brand/${brand.id}`"
+      >
+        <img
+          class="rounded-lg max-h-full max-w-full object-contain"
+          :src="brand.imgUrl"
+          :alt="brand.name"
+        />
+        {{ brand.name }}
+      </router-link>
+    </div>
   </div>
+
+  <h2 class="flex justify-center p-10 text-4xl">探索更多禮物</h2>
+
+  <a href="#" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
+    <ProductCard
+      v-for="product in products"
+      :key="product.id"
+      :product="product"
+    />
+    <!-- 記得可以直接傳物件 -->
+  </a>
 </template>
 
 <style scoped></style>
diff --git a/src/router/index.js b/src/router/index.js
index e97dbd9..6e4b893 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -4,6 +4,7 @@ import CartView from "@/views/CartView.vue";
 import LoginView from "@/views/LoginView.vue";
 import RegisterView from "@/views/RegisterView.vue";
 import HomeView from '@/views/HomeView.vue';
+import BrandView from '@/views/BrandView.vue';
 import ProfileView from "@/views/ProfileView.vue";
 
 const router = createRouter({
@@ -40,6 +41,12 @@ const router = createRouter({
       path: '/register',
       name: "Register",
       component: RegisterView,
+    },
+    
+    {
+      path: '/brand/:id',
+      name: "Brand",
+      component: BrandView,
     }
   ],
 });
diff --git a/src/server/controllers/cart.js b/src/server/controllers/cart.js
new file mode 100644
index 0000000..c500196
--- /dev/null
+++ b/src/server/controllers/cart.js
@@ -0,0 +1,105 @@
+import bcrypt from "bcrypt";
+import pool from "../db.js";
+// 記得 匯入 dotenv !!! 這樣才會成功載入 .env檔案中的環境變數到 process.env裡
+import dotenv from "dotenv";
+import express from "express";
+const cartRouter = express.Router();
+dotenv.config();
+
+const JWT_SECRET = process.env.JWT_SECRET;
+const REFRESH_SECRET = process.env.REFRESH_SECRET;
+
+cartRouter.get("/:userId", async (req, res) => {
+  try {
+    let userId = req.params.userId.replace(/[^\d]/g, ""); // 清掉非數字的隱藏字元
+    userId = parseInt(userId);
+    // req裡的動態參數，後端端點是固定的，所以還要再加動態參數
+    // console.log(userId)
+    // console.log(req)
+    // $1 這個占位符是用來在 SQL 查詢中安全地插入變數值，避免直接把變數拼接到 SQL 語句中，記得用陣列包
+
+    //查詢使用者的購物車
+    const cartResult = await pool.query("SELECT * FROM CART WHERE user_id=$1", [
+      userId,
+    ]);
+    // console.log(cartResult.rows);
+    if (cartResult.rows.length === 0) {
+      return res.status(404).json({ message: "購物車不存在" });
+    }
+    const cartId = cartResult.rows[0].id; //只會有一筆
+
+    //查詢購物車的項目
+    const itemResult = await pool.query(
+      "SELECT ci.id AS cart_item_id,ci.quantity,p.id AS product_id,p.name,p.price FROM cart_items ci JOIN products p ON ci.product_id=p.id WHERE ci.cart_id=$1",
+      [cartId]
+    );
+
+    res.json({ cart: cartResult.rows[0], items: itemResult.rows });
+    //同一購物車可能有新增不同筆商品
+  } catch (err) {
+    console.log(err);
+    res.status(500).json({ message: "伺服器錯誤" });
+  }
+});
+
+//新增商品到購物車
+cartRouter.post("/:userId", async (req, res) => {
+  let userId = req.params.userId.replace(/[^\d]/g, "");
+  userId = parseInt(userId);
+  const { productId, quantity } = req.body;
+
+  try {
+    //檢查是否庫存足夠
+    const productResult = await pool.query(
+      "SELECT stock FROM products WHERE id=$1",
+      [productId]
+    );
+
+    if (productResult.rows.length === 0) {
+      return res.status(404).json({ message: "商品不存在" });
+    }
+
+    if (productResult.rows[0].stock < quantity) {
+      return res.status(400).json({ message: "庫存不足" });
+    }
+
+    //檢查是否有購物車，無則創建
+    let cartResult = await pool.query("SELECT * FROM cart WHERE user_id=$1", [
+      userId,
+    ]);
+    if (cartResult.rows.length === 0) {
+      cartResult = await pool.query(
+        "INSERT INTO CART (user_id) VALUES ($1) RETURNING *",
+        [userId]
+      );
+    }
+    const cartId = cartResult.rows[0].id;
+
+    //檢查購物車是否已有該商品
+    const itemResult = await pool.query(
+      "SELECT * FROM cart_items WHERE cart_id=$1 AND product_id=$2",
+      [cartId, productId]
+    );
+
+    if (itemResult.rows.length > 0) {
+      //更新數量
+      await pool.query(
+        "UPDATE cart_items SET quantity=quantity + $1 WHERE cart_id =$2 AND product_id=$3",
+        [quantity, cartId, productId]
+      );
+    } else {
+      //新增商品到購物車
+      await pool.query(
+        "INSERT INTO cart_items (cart_id,product_id,quantity) VALUES ($1,$2,$3)",
+        [cartId, productId, quantity]
+      );
+    }
+
+    res.status(201).json({ message: "商品已加入購物車" });
+  } catch (err) {
+    console.log(err);
+    res.status(500).json({ message: "伺服器錯誤" });
+  }
+});
+
+export default cartRouter;
\ No newline at end of file
diff --git a/src/server/server.js b/src/server/server.js
index a8d9b22..4381ace 100644
--- a/src/server/server.js
+++ b/src/server/server.js
@@ -7,10 +7,13 @@ import * as authController from "./controllers/authControllers.js";
 import dotenv from 'dotenv';
 dotenv.config();
 
+import cartRouter from './controllers/cart.js';
 const app = express();
 app.use(cors());
 app.use(express.json());
 
+// 掛載購物車路由
+app.use('/api/cart',cartRouter)
 app.use(passport.initialize());
 
 // API 在這設定前端打什麼 後端去執行哪個方法
@@ -20,6 +23,7 @@ app.post("/api/refresh", authController.refresh);
 app.get("/auth/google",authController.googleAuth);
 app.get("/auth/google/callback",authController.googleAuthCallback);
 
+
 // 測試需要 token 的 API
 app.get("/api/me", authMiddleware, (req, res) => {
   res.json({ message: "驗證成功", user: req.user });
diff --git a/src/stores/brand.js b/src/stores/brand.js
new file mode 100644
index 0000000..8e065bf
--- /dev/null
+++ b/src/stores/brand.js
@@ -0,0 +1,94 @@
+import { defineStore } from "pinia";
+import { ref, computed } from "vue";
+
+export const useBrandStore = defineStore("products", () => {
+  const products = ref([
+    {
+      id: 1,
+      img: "https://lcp-prod-obs.line-scdn.net/0hB0cYFDAAHR9eIA3Q1u9iSA19EW5tURkXN1gAInplPHAITAkVNA4CDwxpP3NzUTERCQ0zHzpmPHcYETsvAhoHHHppKEoYVDEsOx8CJTlrPGQDWSEVOE4uCQ/f300",
+      name: "烏龍奶茶",
+      price: 350,
+      inventory: 5,
+    },
+    {
+      id: 2,
+      img: "https://lcp-prod-obs.line-scdn.net/0ho2PNKBSEMB1tNyDS5aFPSj5qPGxeRjQVBE8tIElyEXYrTCdICBgUIDh-Pkg7TCQTOhoeHQlxEXUrBhYtMQ0qHkl-BUgrQxwtMgkUHjh8EFsSQQwXC1kDCw/f300",
+      name: "芋頭牛奶",
+      price: 500,
+      inventory: 6,
+    },
+    {
+      id: 3,
+      img: "https://lcp-prod-obs.line-scdn.net/0h8Gm2tOW-Z2hQS3en2s4YPwAWaxljOmNgOTN6VXROUhMgOVxIZGl6DB5IbAcdJ3J1bG16ex0XbC19IVthCCVUaBFIagQoIXVhH3ZURSMNRSoWOkFbHA/f300",
+      name: "柳橙汁",
+      price: 200,
+      inventory: 7,
+    },
+    {
+      id: 4,
+      img: "https://lcp-prod-obs.line-scdn.net/0hB0cYFDAAHR9eIA3Q1u9iSA19EW5tURkXN1gAInplPHAITAkVNA4CDwxpP3NzUTERCQ0zHzpmPHcYETsvAhoHHHppKEoYVDEsOx8CJTlrPGQDWSEVOE4uCQ/f300",
+      name: "烏龍奶茶",
+      price: 350,
+      inventory: 5,
+    },
+    {
+      id: 5,
+      img: "https://lcp-prod-obs.line-scdn.net/0ho2PNKBSEMB1tNyDS5aFPSj5qPGxeRjQVBE8tIElyEXYrTCdICBgUIDh-Pkg7TCQTOhoeHQlxEXUrBhYtMQ0qHkl-BUgrQxwtMgkUHjh8EFsSQQwXC1kDCw/f300",
+      name: "芋頭牛奶",
+      price: 500,
+      inventory: 6,
+    },
+    {
+      id: 6,
+      img: "https://lcp-prod-obs.line-scdn.net/0h8Gm2tOW-Z2hQS3en2s4YPwAWaxljOmNgOTN6VXROUhMgOVxIZGl6DB5IbAcdJ3J1bG16ex0XbC19IVthCCVUaBFIagQoIXVhH3ZURSMNRSoWOkFbHA/f300",
+      name: "柳橙汁",
+      price: 200,
+      inventory: 7,
+    },
+    {
+      id: 7,
+      img: "https://lcp-prod-obs.line-scdn.net/0hB0cYFDAAHR9eIA3Q1u9iSA19EW5tURkXN1gAInplPHAITAkVNA4CDwxpP3NzUTERCQ0zHzpmPHcYETsvAhoHHHppKEoYVDEsOx8CJTlrPGQDWSEVOE4uCQ/f300",
+      name: "烏龍奶茶",
+      price: 350,
+      inventory: 5,
+    },
+    {
+      id: 8,
+      img: "https://lcp-prod-obs.line-scdn.net/0ho2PNKBSEMB1tNyDS5aFPSj5qPGxeRjQVBE8tIElyEXYrTCdICBgUIDh-Pkg7TCQTOhoeHQlxEXUrBhYtMQ0qHkl-BUgrQxwtMgkUHjh8EFsSQQwXC1kDCw/f300",
+      name: "芋頭牛奶",
+      price: 500,
+      inventory: 6,
+    },
+    {
+      id: 9,
+      img: "https://lcp-prod-obs.line-scdn.net/0h8Gm2tOW-Z2hQS3en2s4YPwAWaxljOmNgOTN6VXROUhMgOVxIZGl6DB5IbAcdJ3J1bG16ex0XbC19IVthCCVUaBFIagQoIXVhH3ZURSMNRSoWOkFbHA/f300",
+      name: "柳橙汁",
+      price: 200,
+      inventory: 7,
+    },
+  ]);
+
+  //取得所有可以購買的商品(庫存大於0) 記得計算要加computed!!!!
+  const avaliableProducts = computed(() => {
+    return products.value.filter((product) => product.inventory > 0);
+  });
+
+  //減少庫存
+  const decreaseInventory = (ItemId) => {
+    const product = products.value.find((product) => product.id === ItemId);
+
+    if (product && product.inventory > 0) {
+      product.inventory--;
+    }
+  };
+
+  //增加庫存
+  const increaseInventory = (ItemId) => {
+    const product = products.value.find((product) => product.id === ItemId);
+
+    if (product) {
+      product.inventory++;
+    }
+  };
+  return { products, avaliableProducts, decreaseInventory, increaseInventory }; //記得return
+});
diff --git a/src/stores/cart.js b/src/stores/cart.js
index 70261cf..9c3d88c 100644
--- a/src/stores/cart.js
+++ b/src/stores/cart.js
@@ -1,6 +1,6 @@
 import { defineStore } from "pinia";
 import { ref, computed } from "vue";
-import { useProductStore } from "@/stores/products.js";
+import { useProductStore } from "./products.js";
 
 export const useCartStore = defineStore("cart", () => {
   // 來自商品列表的 store，要寫在裡面!!!!
diff --git a/src/stores/products.js b/src/stores/products.js
index 4f0d114..bd67b92 100644
--- a/src/stores/products.js
+++ b/src/stores/products.js
@@ -11,64 +11,65 @@ export const useProductStore = defineStore("products", () => {
       price: 350,
       inventory: 5,
     },
-    // {
-    //   id: 2,
-    //   img: "https://lcp-prod-obs.line-scdn.net/0ho2PNKBSEMB1tNyDS5aFPSj5qPGxeRjQVBE8tIElyEXYrTCdICBgUIDh-Pkg7TCQTOhoeHQlxEXUrBhYtMQ0qHkl-BUgrQxwtMgkUHjh8EFsSQQwXC1kDCw/f300",
-    //   name: "芋頭牛奶",
-    //   price: 500,
-    //   inventory: 6,
-    // },
-    // {
-    //   id: 3,
-    //   img: "https://lcp-prod-obs.line-scdn.net/0h8Gm2tOW-Z2hQS3en2s4YPwAWaxljOmNgOTN6VXROUhMgOVxIZGl6DB5IbAcdJ3J1bG16ex0XbC19IVthCCVUaBFIagQoIXVhH3ZURSMNRSoWOkFbHA/f300",
-    //   name: "柳橙汁",
-    //   price: 200,
-    //   inventory: 7,
-    // },
-    // {
-    //   id: 4,
-    //   img: "https://lcp-prod-obs.line-scdn.net/0hB0cYFDAAHR9eIA3Q1u9iSA19EW5tURkXN1gAInplPHAITAkVNA4CDwxpP3NzUTERCQ0zHzpmPHcYETsvAhoHHHppKEoYVDEsOx8CJTlrPGQDWSEVOE4uCQ/f300",
-    //   name: "烏龍奶茶",
-    //   price: 350,
-    //   inventory: 5,
-    // },
-    // {
-    //   id: 5,
-    //   img: "https://lcp-prod-obs.line-scdn.net/0ho2PNKBSEMB1tNyDS5aFPSj5qPGxeRjQVBE8tIElyEXYrTCdICBgUIDh-Pkg7TCQTOhoeHQlxEXUrBhYtMQ0qHkl-BUgrQxwtMgkUHjh8EFsSQQwXC1kDCw/f300",
-    //   name: "芋頭牛奶",
-    //   price: 500,
-    //   inventory: 6,
-    // },
-    // {
-    //   id: 6,
-    //   img: "https://lcp-prod-obs.line-scdn.net/0h8Gm2tOW-Z2hQS3en2s4YPwAWaxljOmNgOTN6VXROUhMgOVxIZGl6DB5IbAcdJ3J1bG16ex0XbC19IVthCCVUaBFIagQoIXVhH3ZURSMNRSoWOkFbHA/f300",
-    //   name: "柳橙汁",
-    //   price: 200,
-    //   inventory: 7,
-    // },
-    // {
-    //   id: 7,
-    //   img: "https://lcp-prod-obs.line-scdn.net/0hB0cYFDAAHR9eIA3Q1u9iSA19EW5tURkXN1gAInplPHAITAkVNA4CDwxpP3NzUTERCQ0zHzpmPHcYETsvAhoHHHppKEoYVDEsOx8CJTlrPGQDWSEVOE4uCQ/f300",
-    //   name: "烏龍奶茶",
-    //   price: 350,
-    //   inventory: 5,
-    // },
-    // {
-    //   id: 8,
-    //   img: "https://lcp-prod-obs.line-scdn.net/0ho2PNKBSEMB1tNyDS5aFPSj5qPGxeRjQVBE8tIElyEXYrTCdICBgUIDh-Pkg7TCQTOhoeHQlxEXUrBhYtMQ0qHkl-BUgrQxwtMgkUHjh8EFsSQQwXC1kDCw/f300",
-    //   name: "芋頭牛奶",
-    //   price: 500,
-    //   inventory: 6,
-    // },
-    // {
-    //   id: 9,
-    //   img: "https://lcp-prod-obs.line-scdn.net/0h8Gm2tOW-Z2hQS3en2s4YPwAWaxljOmNgOTN6VXROUhMgOVxIZGl6DB5IbAcdJ3J1bG16ex0XbC19IVthCCVUaBFIagQoIXVhH3ZURSMNRSoWOkFbHA/f300",
-    //   name: "柳橙汁",
-    //   price: 200,
-    //   inventory: 7,
-    // },
+    {
+      id: 2,
+      img: "https://lcp-prod-obs.line-scdn.net/0ho2PNKBSEMB1tNyDS5aFPSj5qPGxeRjQVBE8tIElyEXYrTCdICBgUIDh-Pkg7TCQTOhoeHQlxEXUrBhYtMQ0qHkl-BUgrQxwtMgkUHjh8EFsSQQwXC1kDCw/f300",
+      name: "芋頭牛奶",
+      price: 500,
+      inventory: 6,
+    },
+    {
+      id: 3,
+      img: "https://lcp-prod-obs.line-scdn.net/0h8Gm2tOW-Z2hQS3en2s4YPwAWaxljOmNgOTN6VXROUhMgOVxIZGl6DB5IbAcdJ3J1bG16ex0XbC19IVthCCVUaBFIagQoIXVhH3ZURSMNRSoWOkFbHA/f300",
+      name: "柳橙汁",
+      price: 200,
+      inventory: 7,
+    },
+    {
+      id: 4,
+      img: "https://lcp-prod-obs.line-scdn.net/0hB0cYFDAAHR9eIA3Q1u9iSA19EW5tURkXN1gAInplPHAITAkVNA4CDwxpP3NzUTERCQ0zHzpmPHcYETsvAhoHHHppKEoYVDEsOx8CJTlrPGQDWSEVOE4uCQ/f300",
+      name: "烏龍奶茶",
+      price: 350,
+      inventory: 5,
+    },
+    {
+      id: 5,
+      img: "https://lcp-prod-obs.line-scdn.net/0ho2PNKBSEMB1tNyDS5aFPSj5qPGxeRjQVBE8tIElyEXYrTCdICBgUIDh-Pkg7TCQTOhoeHQlxEXUrBhYtMQ0qHkl-BUgrQxwtMgkUHjh8EFsSQQwXC1kDCw/f300",
+      name: "芋頭牛奶",
+      price: 500,
+      inventory: 6,
+    },
+    {
+      id: 6,
+      img: "https://lcp-prod-obs.line-scdn.net/0h8Gm2tOW-Z2hQS3en2s4YPwAWaxljOmNgOTN6VXROUhMgOVxIZGl6DB5IbAcdJ3J1bG16ex0XbC19IVthCCVUaBFIagQoIXVhH3ZURSMNRSoWOkFbHA/f300",
+      name: "柳橙汁",
+      price: 200,
+      inventory: 7,
+    },
+    {
+      id: 7,
+      img: "https://lcp-prod-obs.line-scdn.net/0hB0cYFDAAHR9eIA3Q1u9iSA19EW5tURkXN1gAInplPHAITAkVNA4CDwxpP3NzUTERCQ0zHzpmPHcYETsvAhoHHHppKEoYVDEsOx8CJTlrPGQDWSEVOE4uCQ/f300",
+      name: "烏龍奶茶",
+      price: 350,
+      inventory: 5,
+    },
+    {
+      id: 8,
+      img: "https://lcp-prod-obs.line-scdn.net/0ho2PNKBSEMB1tNyDS5aFPSj5qPGxeRjQVBE8tIElyEXYrTCdICBgUIDh-Pkg7TCQTOhoeHQlxEXUrBhYtMQ0qHkl-BUgrQxwtMgkUHjh8EFsSQQwXC1kDCw/f300",
+      name: "芋頭牛奶",
+      price: 500,
+      inventory: 6,
+    },
+    {
+      id: 9,
+      img: "https://lcp-prod-obs.line-scdn.net/0h8Gm2tOW-Z2hQS3en2s4YPwAWaxljOmNgOTN6VXROUhMgOVxIZGl6DB5IbAcdJ3J1bG16ex0XbC19IVthCCVUaBFIagQoIXVhH3ZURSMNRSoWOkFbHA/f300",
+      name: "柳橙汁",
+      price: 200,
+      inventory: 7,
+    },
   ]);
 
+
   //取得所有可以購買的商品(庫存大於0) 記得計算要加computed!!!!
   const avaliableProducts = computed(() => {
     return products.value.filter((product) => product.inventory > 0);
@@ -93,3 +94,169 @@ export const useProductStore = defineStore("products", () => {
   };
   return { products, avaliableProducts, decreaseInventory, increaseInventory }; //記得return
 });
+
+
+export const useBrandStore = defineStore("brand", () => {
+  const brands = ref([
+    {
+      id: 1,
+      name: "響泰多",
+      category: "restaurant",
+      imgUrl:
+        "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR_5jgx6p38VKEPBsUENg0i-VKEijO7R5g_pQ&s",
+    },
+    {
+      id: 2,
+      name: "響泰多",
+      category: "restaurant",
+      imgUrl:
+        "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR_5jgx6p38VKEPBsUENg0i-VKEijO7R5g_pQ&s",
+    },
+    {
+      id: 3,
+      name: "響泰多",
+      category: "restaurant",
+      imgUrl:
+        "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR_5jgx6p38VKEPBsUENg0i-VKEijO7R5g_pQ&s",
+    },
+    {
+      id: 4,
+      name: "響泰多",
+      category: "restaurant",
+      imgUrl:
+        "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR_5jgx6p38VKEPBsUENg0i-VKEijO7R5g_pQ&s",
+    },
+    {
+      id: 5,
+      name: "響泰多",
+      category: "restaurant",
+      imgUrl:
+        "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR_5jgx6p38VKEPBsUENg0i-VKEijO7R5g_pQ&s",
+    },
+    {
+      id: 6,
+      name: "響泰多",
+      category: "restaurant",
+      imgUrl:
+        "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR_5jgx6p38VKEPBsUENg0i-VKEijO7R5g_pQ&s",
+    },
+    {
+      id: 7,
+      name: "響泰多",
+      category: "restaurant",
+      imgUrl:
+        "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR_5jgx6p38VKEPBsUENg0i-VKEijO7R5g_pQ&s",
+    },
+    {
+      id: 8,
+      name: "響泰多",
+      category: "restaurant",
+      imgUrl:
+        "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR_5jgx6p38VKEPBsUENg0i-VKEijO7R5g_pQ&s",
+    },
+
+    {
+      id: 9,
+      name: "星巴克",
+      category: "cafe",
+      imgUrl:
+        "https://foodtracer.health.ntpc.gov.tw/WebUPD/foodtracer/FoodCompany/STARBUCKS-LOGO_22030310531630787.png",
+    },
+    {
+      id: 10,
+      name: "星巴克",
+      category: "cafe",
+      imgUrl:
+        "https://foodtracer.health.ntpc.gov.tw/WebUPD/foodtracer/FoodCompany/STARBUCKS-LOGO_22030310531630787.png",
+    },
+    {
+      id: 11,
+      name: "星巴克",
+      category: "cafe",
+      imgUrl:
+        "https://foodtracer.health.ntpc.gov.tw/WebUPD/foodtracer/FoodCompany/STARBUCKS-LOGO_22030310531630787.png",
+    },
+    {
+      id: 12,
+      name: "星巴克",
+      category: "cafe",
+      imgUrl:
+        "https://foodtracer.health.ntpc.gov.tw/WebUPD/foodtracer/FoodCompany/STARBUCKS-LOGO_22030310531630787.png",
+    },
+
+    {
+      id: 13,
+      name: "麥當勞",
+      category: "fastfood",
+      imgUrl:
+        "https://yt3.googleusercontent.com/4x0sasEICqBRur_XCUDj1MoyAZJacz38i9m94pq0HgK91lZcxCCof0CakpCewIVucFWaAQ11=s900-c-k-c0x00ffffff-no-rj",
+    },
+    {
+      id: 14,
+      name: "麥當勞",
+      category: "fastfood",
+      imgUrl:
+        "https://yt3.googleusercontent.com/4x0sasEICqBRur_XCUDj1MoyAZJacz38i9m94pq0HgK91lZcxCCof0CakpCewIVucFWaAQ11=s900-c-k-c0x00ffffff-no-rj",
+    },
+    {
+      id: 15,
+      name: "麥當勞",
+      category: "fastfood",
+      imgUrl:
+        "https://yt3.googleusercontent.com/4x0sasEICqBRur_XCUDj1MoyAZJacz38i9m94pq0HgK91lZcxCCof0CakpCewIVucFWaAQ11=s900-c-k-c0x00ffffff-no-rj",
+    },
+    {
+      id: 16,
+      name: "麥當勞",
+      category: "fastfood",
+      imgUrl:
+        "https://yt3.googleusercontent.com/4x0sasEICqBRur_XCUDj1MoyAZJacz38i9m94pq0HgK91lZcxCCof0CakpCewIVucFWaAQ11=s900-c-k-c0x00ffffff-no-rj",
+    },
+
+    {
+      id: 17,
+      name: "meowxiang",
+      category: "aroma",
+      imgUrl:
+        "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSZ4l6sdCHQDlehjIKEI3KptGjXUmGm6cNa_A&s",
+    },
+    {
+      id: 18,
+      name: "meowxiang",
+      category: "aroma",
+      imgUrl:
+        "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSZ4l6sdCHQDlehjIKEI3KptGjXUmGm6cNa_A&s",
+    },
+    {
+      id: 19,
+      name: "meowxiang",
+      category: "aroma",
+      imgUrl:
+        "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSZ4l6sdCHQDlehjIKEI3KptGjXUmGm6cNa_A&s",
+    },
+    {
+      id: 20,
+      name: "meowxiang",
+      category: "aroma",
+      imgUrl:
+        "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSZ4l6sdCHQDlehjIKEI3KptGjXUmGm6cNa_A&s",
+    },
+  ]);
+
+  const currentCategory = ref('restaurant')  // 初始分類
+
+  const changeCurrentCategory = (cat) => {
+      // console.log('切換分類為：', cat)
+    currentCategory.value = cat
+  }
+
+  const filteredBrands = computed(() => {
+    return brands.value.filter((brand) => brand.category === currentCategory.value)
+  })
+
+  return { 
+    brands,
+    currentCategory,
+    changeCurrentCategory,
+    filteredBrands };
+});
diff --git a/src/stores/user.js b/src/stores/user.js
index 9945f51..2612a1f 100644
--- a/src/stores/user.js
+++ b/src/stores/user.js
@@ -1,5 +1,5 @@
 // 使用 Pinia 管理 user 的狀態 實現 login logout refresh token 的動作
-import axios from "@/api/axios";
+import axios from "../api/axios";
 import { defineStore } from "pinia";
 
 export const useUserStore = defineStore("user", {
diff --git a/src/views/BrandView.vue b/src/views/BrandView.vue
new file mode 100644
index 0000000..e271b59
--- /dev/null
+++ b/src/views/BrandView.vue
@@ -0,0 +1,8 @@
+<script setup>
+import Brand from "@/components/BrandProduct.vue";
+
+</script>
+
+<template>
+  <Brand />
+</template>
diff --git a/src/views/LoginView.vue b/src/views/LoginView.vue
index a6beb21..d709e9f 100644
--- a/src/views/LoginView.vue
+++ b/src/views/LoginView.vue
@@ -1,7 +1,7 @@
 <!-- 登入頁面 -->
 <script setup>
 import { ref } from "vue";
-import { useUserStore } from "@/stores/user";
+import { useUserStore } from "../stores/user";
 
 const store = useUserStore();
 const username = ref("");
diff --git a/src/views/ProfileView.vue b/src/views/ProfileView.vue
index ae49f48..8fdff54 100644
--- a/src/views/ProfileView.vue
+++ b/src/views/ProfileView.vue
@@ -1,6 +1,6 @@
 <script setup>
 import { useRoute } from "vue-router";
-import { useUserStore } from "@/stores/user";
+import { useUserStore } from "../stores/user";
 import { onMounted, ref } from "vue";
 
 const route = useRoute();
diff --git a/src/views/RegisterView.vue b/src/views/RegisterView.vue
index 61ec27f..cde2d4e 100644
--- a/src/views/RegisterView.vue
+++ b/src/views/RegisterView.vue
@@ -1,6 +1,6 @@
 <script setup>
 import { ref } from "vue";
-import { useUserStore } from "@/stores/user";
+import { useUserStore } from "../stores/user";
 import { useRouter } from "vue-router";
 
 const store = useUserStore();
diff --git a/tailwind.config.js b/tailwind.config.js
index cde31d3..239ef25 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -4,7 +4,16 @@ export default {
     './src/**/*.{vue,js,ts,jsx,tsx}',
   ],
   theme: {
-    extend: {},
+    extend: {
+      colors: {
+        primary:{
+        100:'#7395BA', // 主色調
+        200:'#C0D7EC'  // 次要色
+        }        
+
+      },
+    },
   },
   plugins: [],
+  
 }
\ No newline at end of file


Reviews:
user: login: sin-huang
state: COMMENTED
author_association: OWNER
submitted_at: 2025-05-27T20:38:05Z
user: login: sin-huang
state: COMMENTED
author_association: OWNER
submitted_at: 2025-05-27T20:41:22Z
user: login: sin-huang
state: COMMENTED
author_association: OWNER
submitted_at: 2025-05-27T20:42:30Z
user: login: sin-huang
state: COMMENTED
author_association: OWNER
submitted_at: 2025-05-27T20:45:40Z
user: login: sin-huang
body: 先同意 合併時再討論 要留下哪些
然後之後要記得隨時更新本地倉庫 沿著最新分支往下做
state: APPROVED
author_association: OWNER
submitted_at: 2025-05-27T20:48:58Z

Review comments:
diff_hunk: @@ -5,6 +5,7 @@
   "main": "index.js",
   "type": "module",
   "scripts": {
+    "start":"node src/server/server",
path: package.json
user: login: sin-huang
body: 最新的 dev 分支已經前後端分離開發 所以以後
前端 用 `vite`
後端 用 `nodemon`
所以這句我併的時候我會刪掉喔
created_at: 2025-05-27T20:38:05Z
author_association: OWNER
diff_hunk: @@ -1,5 +1,5 @@
 import axios from "axios";
-import { useUserStore } from "@/stores/user.js";
+import { useUserStore } from "../stores/user.js";
path: src/api/axios.js
user: login: sin-huang
body: 最新的 dev 分支中 有 `vite.config.js`檔案 裡面有設定 `＠`快捷路經
`@`代表 `./src` 資料夾下的所有檔案 這樣以後檔案重構是 `vscode`會主動問我們要不要修改路徑

created_at: 2025-05-27T20:41:22Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,105 @@
+import bcrypt from "bcrypt";
path: src/server/controllers/cart.js
user: login: sin-huang
body: 這句刪掉 沒有加密阿~~
created_at: 2025-05-27T20:42:30Z
author_association: OWNER
path: src/server/controllers/cart.js
user: login: sin-huang
body: 這個 `cart,js` 版本太舊了 文瑜那邊的檔案比較新 併的時候我會直接刪掉
created_at: 2025-05-27T20:45:39Z
author_association: OWNER

PR comments:
user: login: c16033
created_at: 2025-05-28T01:49:43Z
body: 好~已閱 感謝
author_association: COLLABORATOR
user: login: HeidiSiao
created_at: 2025-05-30T12:30:42Z
body: <img width="1442" alt="image" src="https://github.com/user-attachments/assets/2e13cfb8-0b00-4376-a7c7-df9a8fc0e483" />

這個路徑有問題要改欸
server.js 會是在 資料夾**backend > src > server.js**

這邊好像變成你自己獨立在外層開了一個src資料夾放

@c16033 



author_association: COLLABORATOR
user: login: c16033
created_at: 2025-05-31T06:23:41Z
body: > <img alt="影像" width="1442" src="https://private-user-images.githubusercontent.com/159874338/449233367-2e13cfb8-0b00-4376-a7c7-df9a8fc0e483.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDg2NzI3NDMsIm5iZiI6MTc0ODY3MjQ0MywicGF0aCI6Ii8xNTk4NzQzMzgvNDQ5MjMzMzY3LTJlMTNjZmI4LTBiMDAtNDM3Ni1hN2M3LWRmOWE4ZmMwZTQ4My5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjUwNTMxJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI1MDUzMVQwNjIwNDNaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT0yMjY3YTRjODA2ODllZmNlYTA2OTk1MGE1OTg3NThlODNhY2ZjYjIxMWFhN2FlMGJiOTI3ZWE2Y2MxOTJiNzlhJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.prROIb0rwcYVnuvWWix5dCqSjXZJG5mmEU5s2ZMVH30">
> 這個路徑有問題要改欸 server.js 會在資料夾**backend > src > server.js**
> 
> 布拉格希望讓你自己獨立，在外層開了一個資料夾放
> 
> @c16033

這個是比較舊的檔案，不是我建的，看一下有沒有需要，沒有的話可以直接刪掉?
author_association: COLLABORATOR