Vue.js: Final Project: E-commerce Admin

Last updated: 2026-10-20

This is the graduation project of the Vue 3 tutorial — applying everything from the 29 lessons to a real SaaS e-commerce admin. Following the architecture of PanJiaChen/vue-element-admin (88k⭐ on GitHub), we build an admin that serves 5,000 merchants and 30,000 SKUs.

The project has 8 major modules and takes 10-12 hours of work. Once you finish it, you will be able to independently build enterprise-grade Vue applications.

1. What You'll Learn


2. A SaaS E-commerce Product Manager's "Full-Stack Requirements"

(1) Pain point: how do you build an admin for 5,000 merchants and 30,000 SKUs

Alice has been promoted to lead the admin dashboard project:

TEXT
Business scenario:
  - 5,000 small and medium merchants (30-300 SKUs each)
  - 30,000 product SKUs
  - 10,000 orders per day
  - 5 roles (admin / manager / editor / viewer / guest)
  - Real-time data (dashboard, orders, notifications)
  - Multilingual (5 languages)

Product manager Charlie wrote the spec:

"Alice, our SaaS platform needs a complete admin. 8 modules: dashboard, products, orders, users, marketing, settings, login, deployment. Every module matters. Build it with Vue 3, 10-12 hours, and use everything from the first 29 lessons."

(2) The 8-module architecture of the Vue 3 capstone project

TEXT
src/
├── api/                   # API wrappers
│   ├── auth.ts
│   ├── product.ts
│   ├── order.ts
│   └── user.ts
├── assets/                # Static assets
├── components/            # Shared components
│   ├── BaseButton.vue
│   ├── BaseTable.vue       # Wraps Element Plus
│   ├── BasePagination.vue
│   ├── BaseDialog.vue
│   └── charts/             # Charts
│       ├── SalesChart.vue
│       ├── UserChart.vue
│       └── OrderChart.vue
├── composables/           # Composables
│   ├── useAuth.ts
│   ├── usePermission.ts
│   ├── useTable.ts
│   └── usePagination.ts
├── layouts/                # Layouts
│   ├── DefaultLayout.vue   # After login
│   └── AuthLayout.vue      # Login page
├── router/                # Routing
│   └── index.ts
├── stores/                 # Pinia
│   ├── auth.ts
│   ├── product.ts
│   ├── order.ts
│   └── app.ts              # Global (theme / sidebar)
├── types/                  # TS types
│   ├── user.ts
│   ├── product.ts
│   └── api.ts
├── utils/                  # Utilities
│   ├── request.ts          # axios wrapper
│   ├── auth.ts
│   └── format.ts
├── views/                  # Pages
│   ├── dashboard/          # Dashboard
│   ├── login/              # Login
│   ├── product/            # Products
│   ├── order/              # Orders
│   ├── user/               # Users
│   ├── marketing/          # Marketing
│   └── error/              # 403 / 404
├── App.vue
└── main.ts

(3) The payoff

After building this project:


3. Module 1: Project Initialization (1.5h)

(1) Complete package.json

▶ Example: Complete Project Initialization Configuration (Difficulty: ⭐⭐)

⚠️ The full 8-module project needs Vite + Element Plus + ECharts + Pinia + Vue Router and must run inside a Vite project. This lesson presents the core code structure as a graduation project.

JSON
{
  "name": "mercury-admin",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
    "preview": "vite preview",
    "test": "vitest",
    "test:e2e": "playwright test",
    "lint": "eslint . --ext .vue,.ts,.tsx"
  },
  "dependencies": {
    "vue": "^3.4.0",
    "vue-router": "^4.3.0",
    "pinia": "^2.1.0",
    "element-plus": "^2.5.0",
    "@element-plus/icons-vue": "^2.3.0",
    "echarts": "^5.4.0",
    "vue-echarts": "^7.0.0",
    "axios": "^1.6.0",
    "dayjs": "^1.11.0",
    "vueuse": "^10.7.0"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.0.0",
    "vite": "^5.0.0",
    "vue-tsc": "^1.8.0",
    "typescript": "^5.3.0",
    "unplugin-vue-components": "^0.26.0",
    "unplugin-auto-import": "^0.17.0",
    "unplugin-icons": "^0.17.0",
    "@iconify-json/carbon": "^1.1.0",
    "sass": "^1.69.0",
    "vitest": "^1.0.0",
    "@vue/test-utils": "^2.4.0",
    "@playwright/test": "^1.40.0"
  }
}

Output:

TEXT
After npm install, every dependency resolves, and npm run dev boots the Vite dev server with the Element Plus and ECharts bundles available:
TEXT
added 312 packages in 18s
  VITE v5.0.10  ready in 486 ms
  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose

(2) vite.config.ts

TS
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import'
import Components from 'unplugin-vue-components'
import Icons from 'unplugin-icons/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import path from 'path'

export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      imports: ['vue', 'vue-router', 'pinia', 'vueuse'],
      resolvers: [ElementPlusResolver()],
      dts: 'src/auto-imports.d.ts'
    }),
    Components({
      resolvers: [ElementPlusResolver()],
      dts: 'src/components.d.ts'
    }),
    Icons({ autoInstall: true })
  ],
  resolve: {
    alias: { '@': path.resolve(__dirname, 'src') }
  },
  server: {
    port: 5173,
    proxy: { '/api': { target: 'http://localhost:3000', changeOrigin: true } }
  },
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          'vue-vendor': ['vue', 'vue-router', 'pinia'],
          'echarts-vendor': ['echarts', 'vue-echarts']
        }
      }
    }
  }
})

4. Module 2: Login + JWT Auth + Permission Routing (2h)

(1) Pinia auth store

▶ Example: JWT Login + 5-Role Permission Demo (Runs on CDN)

▶ Expand runnable example (124 lines)
▶ Try it Yourself

Output:

TEXT
A centered login card is rendered first;
logging in as Alice switches to the dashboard with all four KPI cards, all five action buttons enabled, and six permission tags.
Logging in as Dave leaves only the "Today's Orders" KPI, every action button disabled, and a single order.view tag:
TEXT
🔐 Sign In (CDN Simulation)
Username: alice / Password: any
[ Username                ]
[ Password                ]
[ Sign in ]
5 user types:  admin  manager  editor  viewer  guest

—— after clicking "admin" and "Sign in" ——

📊 Dashboard          Welcome Alice [admin] [Sign out]
1. Four KPI cards (permission-gated)
Today's Sales $12,345 +12%   Today's Orders 342 +5%
Total Products 1,234 +3      Total Users 5,678 +8%
2. Five permission-gated buttons (shown by role)
➕ Create product  ✏️ Edit product  🗑️ Delete product  👥 Manage users  💰 Financial reports
3. Current role's permission list
product.create  product.edit  product.delete  user.manage  finance.view  order.view

(2) Route guards

TS
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import { useAuthStore } from '@/stores/auth'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/login', component: () => import('@/views/login/LoginPage.vue') },
    {
      path: '/',
      component: () => import('@/layouts/DefaultLayout.vue'),
      meta: { requiresAuth: true },
      children: [
        { path: '', redirect: '/dashboard' },
        { path: 'dashboard', component: () => import('@/views/dashboard/DashboardPage.vue') },
        { path: 'products', component: () => import('@/views/product/ProductListPage.vue') }
      ]
    }
  ]
})

router.beforeEach((to, from, next) => {
  const auth = useAuthStore()
  
  if (to.meta.requiresAuth && !auth.isLoggedIn) {
    return next({ name: 'login', query: { redirect: to.fullPath } })
  }
  
  next()
})

export default router

(3) A custom permission directive

TS
// directives/permission.ts
import { useAuthStore } from '@/stores/auth'

export const permission = {
  mounted(el: HTMLElement, binding: { value: string }) {
    const auth = useAuthStore()
    if (!auth.permissions.includes(binding.value)) {
      el.parentNode?.removeChild(el)
    }
  }
}
VUE
<button v-permission="'product.create'">Create Product</button>

5. Module 3: Dashboard (2h)

(1) 5 ECharts charts

▶ Example: Dashboard with 5 ECharts Charts (Runs on CDN)

▶ Expand runnable example (104 lines)
▶ Try it Yourself

Output:

TEXT
Four KPI cards render in a row, followed by a 2-column grid of five charts: a smooth green sales line, blue order bars, a full-width category pie, a two-series user-activity line with legend, and an amber top-5 sales bar chart:
TEXT
📊 Dashboard — 5 ECharts Charts
1. Four KPI cards
Today's Sales $12,345 ↑ +12%  Today's Orders 342 ↑ +5%
Active Users 5,678 ↑ +8%      Conversion 3.2% ↓ -2%

2. Five ECharts charts
┌─────────────────────┬─────────────────────┐
│ 📈 Sales Trend      │ 📊 Orders           │
├─────────────────────┴─────────────────────┤
│ 🎯 Category Share (pie, full width)       │
├─────────────────────┬─────────────────────┤
│ 👥 User Activity    │ 🏆 Top Sellers      │
└─────────────────────┴─────────────────────┘

6. Module 4: Product Management (1.5h)

(1) Product list + CRUD

▶ Example: Product CRUD + Permission Control (Runs on CDN)

▶ Expand runnable example (116 lines)
▶ Try it Yourself

Output:

TEXT
A toolbar with a search box and a "New Product" button sits above a 7-column table listing the four mock products;
typing "iPhone" filters the table down to one row, and clicking "Edit" opens the modal pre-filled with that row's values:
TEXT
📦 Product Management (Simplified CDN Version)
[ Search product name... ]                   [ ➕ New Product ]

ID  Name               Category      Price   Stock  Status     Actions
1   iPhone 15 Pro      Electronics   $999    50     active     ✏️ Edit  🗑️ Delete
2   MacBook Pro        Electronics   $2499   5      active     ✏️ Edit  🗑️ Delete
3   Cotton T-Shirt     Clothing      $29     200    active     ✏️ Edit  🗑️ Delete
4   Old Model          Electronics   $99     0      inactive   ✏️ Edit  🗑️ Delete

7. Module 5: Order Management (1h)

(1) Order list + details

▶ Example: Order List + Details + Status Transitions (Runs on CDN)

▶ Expand runnable example (104 lines)
▶ Try it Yourself

Output:

TEXT
Three orders render with colour-coded status tags;
"Confirm" only appears on the pending order and "Ship" only on the paid one.
Clicking "View" opens a dialog listing items with line totals and the timeline of status changes:
TEXT
📋 Order Management
Order No.  Customer  Amount  Status     Actions
#1001      Alice     $1028   pending    View  Confirm
#1002      Bob       $50     paid       View  Ship
#1003      Carol     $2499   shipped    View

—— View #1001 ——
Order #1001
Customer: Alice    Amount: $1028    Status: pending
Items:
  iPhone 15 Pro × 1 = $999
  Case × 1 = $29
Status history:
  2026-07-15 10:00 - Order created

8. Module 6: User Management (1h)

(1) User list + role management

▶ Example: User Role Management + RBAC Editing (Runs on CDN)

▶ Expand runnable example (87 lines)
▶ Try it Yourself

Output:

TEXT
The user table lists four accounts with coloured role tags;
editing Carol opens a modal with five checkboxes, two of them already checked (editor and viewer), and saving replaces her tags with the current selection:
TEXT
👥 User Role Management (RBAC)
ID  Username  Email          Roles                   Actions
1   alice     alice@x.com    [admin]                 Edit roles
2   bob       bob@x.com      [manager]               Edit roles
3   carol     carol@x.com    [editor] [viewer]       Edit roles
4   eve       eve@x.com      [guest]                 Edit roles

—— Edit roles for carol ——
☑ [admin]   Super admin (all permissions)
☐ [manager] Manager (products / orders / some users)
☑ [editor]  Editor (product editing)
☑ [viewer]  Viewer (read-only)
☐ [guest]   Guest (minimal permissions)
                            [ Cancel ] [ Save ]

(2) The 5 role permissions

TS
// utils/roles.ts
export const ROLES = {
  admin: {
    label: 'Admin',
    permissions: ['*']  // full access
  },
  manager: {
    label: 'Manager',
    permissions: ['product.*', 'order.*', 'user.read']
  },
  editor: {
    label: 'Editor',
    permissions: ['product.read', 'product.edit', 'order.read']
  },
  viewer: {
    label: 'Viewer',
    permissions: ['*.read']
  },
  guest: {
    label: 'Guest',
    permissions: ['product.read']
  }
}

9. Module 7: Marketing Campaigns (1h)

(1) Coupon management

▶ Example: Coupon List + Validity Window + Status (Runs on CDN)

▶ Try it Yourself

Output:

TEXT
A five-column coupon table renders four rows, translating the raw type and status codes through the two lookup maps and colouring each status tag green, grey or amber:
TEXT
🎟️ Marketing Campaigns (Coupon Management)
Coupon Code   Type          Discount   Status    Validity
SUMMER2026    Percentage    20% off    Active    2026-07-01 ~ 2026-08-31
NEWUSER50     Fixed Amount  $5 off     Active    2026-01-01 ~ 2026-12-31
BLACKFRIDAY   Percentage    50% off    Expired   2025-11-25 ~ 2025-11-30
VIPONLY       Fixed Amount  $100 off   Paused    2026-06-01 ~ 2026-12-31

10. Module 8: Deployment (1h)

(1) Build optimization

▶ Example: Vite Manual Chunk Splitting (Difficulty: ⭐⭐)

⚠️ The following is a Vite config file, so the CDN global build does not apply. It shows the production optimization strategy:

TS
// vite.config.ts (production build optimization)
build: {
  outDir: 'dist',
  sourcemap: true,  // for Sentry
  minify: 'esbuild',
  cssMinify: 'lightningcss',
  rollupOptions: {
    output: {
      manualChunks: {
        'vue-vendor': ['vue', 'vue-router', 'pinia'],
        'echarts-vendor': ['echarts', 'vue-echarts'],
        'ui-vendor': ['element-plus'],
        'utils': ['axios', 'dayjs']
      }
    }
  }
}
▶ Try it Yourself

Output:

TEXT
npm run build emits one chunk per manual group, so the vendor code is cached independently of the app code:
TEXT
dist/index.html                     0.62 kB │ gzip:  0.38 kB
dist/assets/index-a1b2c3d4.js      182.41 kB │ gzip: 64.20 kB
dist/assets/vue-vendor-e5f6g7h8.js  98.73 kB │ gzip: 36.15 kB
dist/assets/echarts-vendor-i9j0k1l2.js 412.06 kB │ gzip: 138.42 kB
dist/assets/ui-vendor-m3n4o5p6.js  268.55 kB │ gzip: 89.71 kB
dist/assets/utils-q7r8s9t0.js       42.18 kB │ gzip: 15.06 kB
dist/assets/index-u1v2w3x4.css      54.32 kB │ gzip:  9.88 kB
✓ built in 6.42s

(2) Deploying to Vercel

BASH
npm install -g vercel
vercel --prod
JSON
// vercel.json
{
  "build": { "command": "npm run build" },
  "outputDirectory": "dist",
  "framework": "vite",
  "rewrites": [
    { "source": "/(.*)", "destination": "/index.html" }
  ]
}

(3) Performance monitoring

TS
// main.ts
import * as Sentry from '@sentry/vue'

Sentry.init({
  app,
  dsn: 'https://your-dsn@sentry.io/123',
  tracesSampleRate: 0.1
})

11. Line-Count Statistics for All 8 Modules

Module Lines of code Key features
1 Project setup 300 Vite + Pinia + Router + Element Plus + ECharts
2 Login and auth 400 JWT + route guard + permission directive + 5 roles
3 Dashboard 500 5 ECharts charts + 4 KPIs + real-time data
4 Product management 600 CRUD + list + edit + image upload + permissions
5 Order management 400 List + details + status transitions + export
6 User management 300 List + role management + permission editing
7 Marketing campaigns 300 Coupons + validity window + state machine
8 Deployment 200 Vite build optimization + Vercel + Sentry
Total 3000 8-module complete SaaS admin

12. Quick Reference for 5 Common Mistakes

Error Symptom Solution
Blank first screen Router / Pinia load order is wrong In main.ts call app.use(router) before app.use(pinia)
Permissions stop working Roles do not refresh watch permissions
10,000 rows stutter Poor table performance Virtual scrolling with el-table-v2
ECharts does not render Container height is 0 Set style="height: 300px"
404 after deployment SPA routing problem Configure Vercel rewrites

❓ FAQ

Q How long do the 8 modules take?
A 10-12 hours (at a teaching pace). 4-6 hours for an experienced developer.
Q How do I mock the backend API?
A Use MSW (Mock Service Worker) or Express + json-server. This course uses the former.
Q Does Element Plus fully support TypeScript?
A Yes. Element Plus 2.x is a complete TypeScript rewrite with full type inference.
Q How do I optimize a 10,000-row table?
A Use el-table-v2 (Element Plus's official virtual scrolling table) or vue-virtual-scroller. That is a 100x performance gain.
Q How do I deploy to production?
A Vercel (recommended, free) plus a custom domain. vercel --prod is a one-line command.
Q What should I learn after the 30 lessons?
A (1) Nuxt 3 (SSR); (2) React (for comparison); (3) Micro-frontends (qiankun); (4) Mobile (uni-app).
Q Can I use this project template directly?
A Yes. All the code is open source and can serve as the starting point for a real enterprise project.

📖 Summary


13. 🎉 30 Lessons — Graduated!

Congratulations on finishing all 30 Vue 3 lessons! From the basics to an enterprise-grade project, you now have:

Suggested next steps:


📝 Exercises

  1. Basic (Difficulty: ⭐) Complete Module 1 (project setup) + Module 2 (login and auth):

    1. Vite + Vue 3 + Pinia + Element Plus
    2. Login page + dashboard (placeholder)
    3. The foundations of 5-role permissions
  2. Intermediate (Difficulty: ⭐⭐) Complete 4 modules: setup / login / dashboard / products:

    1. Complete Vite + TypeScript configuration
    2. 5 ECharts charts
    3. Product CRUD (10 fields)
  3. Challenge (Difficulty: ⭐⭐⭐) Complete all 8 modules plus deployment:

    1. All 8 modules (10-12h)
    2. Strong TypeScript typing
    3. Performance optimization (virtual scrolling / manual chunks)
    4. Test coverage (5 components + 3 E2E tests)
    5. Vercel deployment + Sentry integration
    6. Finish the 30-lesson Vue tutorial and graduate! 🎉
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏