Vue3 搭配 Tailwind CSS 是构建现代后台管理系统的绝佳组合。Vue3 提供了高效的响应式框架,而 Tailwind CSS 则让样式编写变得快速且灵活。下面我将分步骤教你如何创建一个功能完整的后台管理系统。

第 1 步:创建项目

首先,我们需要使用 Vite 创建一个 Vue3 项目,并安装 Tailwind CSS、路由、 Font Awesome:

npm init vite@latest admin-system -- --template vue
cd admin-system
npm install
npm install -D tailwindcss@3.4.1 postcss autoprefixer
npx tailwindcss init -p
npm install vue-router@4
npm install font-awesome

第 2 步:配置 Tailwind CSS

创建 tailwind.config.js 文件并配置:

/** @type {import('tailwindcss').Config} */
module.exports = {content: ["./index.html","./src/**/*.{vue,js,ts,jsx,tsx}",],theme: {extend: {colors: {primary: '#165DFF',secondary: '#36CFC9',success: '#52C41A',warning: '#FAAD14',danger: '#F5222D',info: '#86909C',light: '#F2F3F5',dark: '#1D2129',},fontFamily: {inter: ['Inter', 'sans-serif'],},},},plugins: [],
}

在 src/index.css 中引入 Tailwind CSS:

@tailwind base;
@tailwind components;
@tailwind utilities;@layer utilities {.content-auto {content-visibility: auto;}.sidebar-item-active {@apply bg-primary/10 text-primary border-l-4 border-primary;}
}

第 4 步:创建布局组件

<template><div class="min-h-screen flex flex-col bg-gray-50"><!-- 顶部导航栏 --><header class="bg-white shadow-sm"><div class="flex items-center justify-between px-4 py-3"><div class="flex items-center"><button @click="toggleSidebar" class="md:hidden text-gray-500 focus:outline-none"><i class="fa fa-bars text-xl"></i></button><div class="ml-4 text-xl font-bold text-primary">管理系统</div></div><div class="flex items-center"><div class="relative mr-4"><input type="text" placeholder="搜索..." class="pl-8 pr-4 py-2 rounded-lg border border-gray-200 focus:outline-none focus:ring-2 focus:ring-primary/50"><i class="fa fa-search absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"></i></div><div class="relative ml-4"><button class="relative text-gray-500 focus:outline-none"><i class="fa fa-bell text-xl"></i><span class="absolute top-0 right-0 h-4 w-4 bg-red-500 rounded-full flex items-center justify-center text-white text-xs">3</span></button></div><div class="relative ml-6"><button @click="toggleDropdown" class="flex items-center focus:outline-none"><img src="https://picsum.photos/id/1005/40/40" alt="用户头像" class="w-8 h-8 rounded-full object-cover"><span class="ml-2 text-sm font-medium">管理员</span><i class="fa fa-angle-down ml-1 text-gray-500"></i></button><div v-show="dropdownVisible" class="absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg py-1 z-10"><a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"><i class="fa fa-user mr-2"></i>个人信息</a><a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"><i class="fa fa-cog mr-2"></i>设置</a><div class="border-t border-gray-100 my-1"></div><a href="#" @click="logout" class="block px-4 py-2 text-sm text-red-600 hover:bg-gray-100"><i class="fa fa-sign-out mr-2"></i>退出登录</a></div></div></div></div></header><div class="flex flex-1 overflow-hidden"><!-- 侧边栏导航 --><aside :class="sidebarVisible ? 'translate-x-0' : '-translate-x-full'" class="fixed md:relative z-20 w-64 bg-white shadow-lg h-full transition-transform duration-300 ease-in-out"><nav class="py-4"><div class="px-4 mb-6"><div class="flex items-center"><img src="https://picsum.photos/id/1005/40/40" alt="用户头像" class="w-10 h-10 rounded-full object-cover"><div class="ml-3"><div class="text-sm font-medium text-gray-900">管理员</div><div class="text-xs text-gray-500">系统管理员</div></div></div></div><div class="px-2 space-y-1"><a href="/dashboard" class="flex items-center px-4 py-3 text-gray-600 rounded-lg sidebar-item-active"><i class="fa fa-tachometer mr-3"></i><span>仪表盘</span></a><a href="/users" class="flex items-center px-4 py-3 text-gray-600 rounded-lg hover:bg-gray-100 transition-colors duration-200"><i class="fa fa-users mr-3"></i><span>用户管理</span></a><a href="/products" class="flex items-center px-4 py-3 text-gray-600 rounded-lg hover:bg-gray-100 transition-colors duration-200"><i class="fa fa-shopping-bag mr-3"></i><span>产品管理</span></a><a href="#" class="flex items-center px-4 py-3 text-gray-600 rounded-lg hover:bg-gray-100 transition-colors duration-200"><i class="fa fa-bar-chart mr-3"></i><span>数据分析</span></a><a href="#" class="flex items-center px-4 py-3 text-gray-600 rounded-lg hover:bg-gray-100 transition-colors duration-200"><i class="fa fa-cog mr-3"></i><span>系统设置</span></a></div><div class="px-4 py-4 mt-6 border-t border-gray-100"><div class="text-xs font-medium text-gray-500 uppercase tracking-wider">帮助</div><a href="#" class="flex items-center px-4 py-2 mt-2 text-gray-600 rounded-lg hover:bg-gray-100 transition-colors duration-200"><i class="fa fa-question-circle mr-3"></i><span>帮助中心</span></a><a href="#" class="flex items-center px-4 py-2 text-gray-600 rounded-lg hover:bg-gray-100 transition-colors duration-200"><i class="fa fa-life-ring mr-3"></i><span>联系支持</span></a></div></nav></aside><!-- 主内容区 --><main class="flex-1 overflow-y-auto p-6 bg-gray-50"><div class="mb-6"><h1 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold text-gray-900">仪表盘</h1><p class="mt-1 text-gray-500">欢迎使用管理系统</p></div><div class="mb-6 flex flex-col md:flex-row md:space-x-4 space-y-4 md:space-y-0"><div class="bg-white rounded-xl shadow-sm p-6 flex-1"><div class="flex items-center justify-between"><div><p class="text-sm font-medium text-gray-500">用户总数</p><h3 class="text-3xl font-bold text-gray-900 mt-1">1,284</h3><p class="text-xs text-green-500 mt-2"><i class="fa fa-arrow-up"></i> 12% 较上月</p></div><div class="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center"><i class="fa fa-users text-primary text-xl"></i></div></div></div><div class="bg-white rounded-xl shadow-sm p-6 flex-1"><div class="flex items-center justify-between"><div><p class="text-sm font-medium text-gray-500">产品总数</p><h3 class="text-3xl font-bold text-gray-900 mt-1">528</h3><p class="text-xs text-green-500 mt-2"><i class="fa fa-arrow-up"></i> 8% 较上月</p></div><div class="w-12 h-12 rounded-full bg-green-100 flex items-center justify-center"><i class="fa fa-shopping-bag text-green-600 text-xl"></i></div></div></div><div class="bg-white rounded-xl shadow-sm p-6 flex-1"><div class="flex items-center justify-between"><div><p class="text-sm font-medium text-gray-500">订单总数</p><h3 class="text-3xl font-bold text-gray-900 mt-1">2,451</h3><p class="text-xs text-green-500 mt-2"><i class="fa fa-arrow-up"></i> 16% 较上月</p></div><div class="w-12 h-12 rounded-full bg-purple-100 flex items-center justify-center"><i class="fa fa-file-text text-purple-600 text-xl"></i></div></div></div><div class="bg-white rounded-xl shadow-sm p-6 flex-1"><div class="flex items-center justify-between"><div><p class="text-sm font-medium text-gray-500">销售额</p><h3 class="text-3xl font-bold text-gray-900 mt-1">¥156,284</h3><p class="text-xs text-green-500 mt-2"><i class="fa fa-arrow-up"></i> 23% 较上月</p></div><div class="w-12 h-12 rounded-full bg-yellow-100 flex items-center justify-center"><i class="fa fa-line-chart text-yellow-600 text-xl"></i></div></div></div></div><div class="grid grid-cols-1 lg:grid-cols-3 gap-6"><div class="lg:col-span-2 bg-white rounded-xl shadow-sm p-6"><div class="flex items-center justify-between mb-6"><h2 class="text-lg font-semibold text-gray-900">销售趋势</h2><div class="flex space-x-2"><button class="px-3 py-1 text-xs rounded-full bg-gray-100 text-gray-600">日</button><button class="px-3 py-1 text-xs rounded-full bg-primary text-white">周</button><button class="px-3 py-1 text-xs rounded-full bg-gray-100 text-gray-600">月</button></div></div><div class="h-80"><!-- 这里可以放置图表组件 --><div class="w-full h-full flex items-center justify-center"><p class="text-gray-400">销售趋势图表将显示在这里</p></div></div></div><div class="bg-white rounded-xl shadow-sm p-6"><div class="flex items-center justify-between mb-6"><h2 class="text-lg font-semibold text-gray-900">销售分布</h2><button class="text-primary text-sm">查看全部</button></div><div class="h-80"><!-- 这里可以放置图表组件 --><div class="w-full h-full flex items-center justify-center"><p class="text-gray-400">销售分布图表将显示在这里</p></div></div></div></div><div class="mt-6 bg-white rounded-xl shadow-sm p-6"><div class="flex items-center justify-between mb-6"><h2 class="text-lg font-semibold text-gray-900">最近订单</h2><button class="text-primary text-sm">查看全部</button></div><div class="overflow-x-auto"><table class="min-w-full divide-y divide-gray-200"><thead><tr><th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">订单ID</th><th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">客户</th><th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">产品</th><th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">金额</th><th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">状态</th><th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">操作</th></tr></thead><tbody class="bg-white divide-y divide-gray-200"><tr><td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">#ORD-12345</td><td class="px-6 py-4 whitespace-nowrap"><div class="flex items-center"><div class="flex-shrink-0 h-10 w-10"><img class="h-10 w-10 rounded-full" src="https://picsum.photos/id/1001/40/40" alt="用户头像"></div><div class="ml-4"><div class="text-sm font-medium text-gray-900">张三</div><div class="text-sm text-gray-500">zhangsan@example.com</div></div></div></td><td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">电子产品</td><td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">¥1,299.00</td><td class="px-6 py-4 whitespace-nowrap"><span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">已完成</span></td><td class="px-6 py-4 whitespace-nowrap text-sm text-primary"><button>查看详情</button></td></tr><tr><td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">#ORD-12346</td><td class="px-6 py-4 whitespace-nowrap"><div class="flex items-center"><div class="flex-shrink-0 h-10 w-10"><img class="h-10 w-10 rounded-full" src="https://picsum.photos/id/1002/40/40" alt="用户头像"></div><div class="ml-4"><div class="text-sm font-medium text-gray-900">李四</div><div class="text-sm text-gray-500">lisi@example.com</div></div></div></td><td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">家居用品</td><td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">¥499.00</td><td class="px-6 py-4 whitespace-nowrap"><span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-yellow-100 text-yellow-800">处理中</span></td><td class="px-6 py-4 whitespace-nowrap text-sm text-primary"><button>查看详情</button></td></tr><tr><td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">#ORD-12347</td><td class="px-6 py-4 whitespace-nowrap"><div class="flex items-center"><div class="flex-shrink-0 h-10 w-10"><img class="h-10 w-10 rounded-full" src="https://picsum.photos/id/1003/40/40" alt="用户头像"></div><div class="ml-4"><div class="text-sm font-medium text-gray-900">王五</div><div class="text-sm text-gray-500">wangwu@example.com</div></div></div></td><td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">图书音像</td><td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">¥299.00</td><td class="px-6 py-4 whitespace-nowrap"><span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-100 text-blue-800">已发货</span></td><td class="px-6 py-4 whitespace-nowrap text-sm text-primary"><button>查看详情</button></td></tr></tbody></table></div></div></main></div></div>
</template><script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'const router = useRouter()const sidebarVisible = ref(true)
const dropdownVisible = ref(false)const toggleSidebar = () => {sidebarVisible.value = !sidebarVisible.value
}const toggleDropdown = () => {dropdownVisible.value = !dropdownVisible.value
}const logout = () => {localStorage.removeItem('token')router.push('/login')
}onMounted(() => {// 检查登录状态if (!localStorage.getItem('token')) {router.push('/login')}
})
</script><style scoped>
/* 移动端适配 */
@media (max-width: 768px) {.sidebar {position: fixed;z-index: 100;transform: translateX(-100%);transition: transform 0.3s ease-in-out;}.sidebar-visible {transform: translateX(0);}.overlay {position: fixed;top: 0;left: 0;right: 0;bottom: 0;background-color: rgba(0, 0, 0, 0.5);z-index: 99;display: none;}.sidebar-visible + .overlay {display: block;}
}
</style>

第 5 步:创建登录页面

创建登录页面 src/views/Login.vue

<template><div class="min-h-screen bg-gray-50 flex items-center justify-center p-4"><div class="max-w-md w-full bg-white rounded-xl shadow-lg overflow-hidden"><div class="p-6 sm:p-8"><div class="text-center mb-8"><h1 class="text-2xl font-bold text-gray-900">管理系统登录</h1><p class="mt-1 text-sm text-gray-500">请输入账号密码登录</p></div><form @submit.prevent="handleLogin"><div class="space-y-4"><div><label for="email" class="block text-sm font-medium text-gray-700">邮箱</label><div class="mt-1 relative"><div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"><i class="fa fa-envelope text-gray-400"></i></div><input type="email" id="email" v-model="form.email" class="pl-10 block w-full rounded-md border-gray-300 shadow-sm focus:ring-primary focus:border-primary" placeholder="your@email.com"></div></div><div><label for="password" class="block text-sm font-medium text-gray-700">密码</label><div class="mt-1 relative"><div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"><i class="fa fa-lock text-gray-400"></i></div><input type="password" id="password" v-model="form.password" class="pl-10 block w-full rounded-md border-gray-300 shadow-sm focus:ring-primary focus:border-primary" placeholder="••••••••"></div></div><div class="flex items-center justify-between"><div class="flex items-center"><input id="remember-me" name="remember-me" type="checkbox" class="h-4 w-4 text-primary focus:ring-primary border-gray-300 rounded"><label for="remember-me" class="ml-2 block text-sm text-gray-900">记住我</label></div><div class="text-sm"><a href="#" class="font-medium text-primary hover:text-primary/80">忘记密码?</a></div></div><div><button type="submit" class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-primary hover:bg-primary/90 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary">登录</button></div></div></form><div class="mt-6 relative"><div class="absolute inset-0 flex items-center"><div class="w-full border-t border-gray-300"></div></div><div class="relative flex justify-center text-sm"><span class="px-2 bg-white text-gray-500">其他登录方式</span></div></div><div class="mt-6 grid grid-cols-3 gap-3"><button type="button" class="inline-flex justify-center py-2 px-4 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"><i class="fa fa-weixin text-green-600"></i></button><button type="button" class="inline-flex justify-center py-2 px-4 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"><i class="fa fa-qq text-blue-500"></i></button><button type="button" class="inline-flex justify-center py-2 px-4 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"><i class="fa fa-github text-gray-800"></i></button></div></div><div class="bg-gray-50 px-6 py-4 text-center"><p class="text-sm text-gray-600">还没有账号? <a href="#" class="font-medium text-primary hover:text-primary/80">注册</a></p></div></div></div>
</template><script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'const router = useRouter()const form = ref({email: '',password: ''
})const handleLogin = () => {// 模拟登录验证if (form.value.email && form.value.password) {localStorage.setItem('token', 'fake_token')router.push('/dashboard')} else {alert('请输入邮箱和密码')}
}
</script>

第 6 步:创建用户管理页面

创建用户管理页面 src/views/Users.vue

<template><div class="bg-white rounded-xl shadow-sm p-6"><div class="flex flex-col md:flex-row md:items-center md:justify-between mb-6"><div><h2 class="text-xl font-bold text-gray-900">用户管理</h2><p class="mt-1 text-sm text-gray-500">管理系统用户信息</p></div><div class="mt-4 md:mt-0 flex flex-col sm:flex-row space-y-2 sm:space-y-0 sm:space-x-3"><div class="relative"><input type="text" v-model="searchQuery" placeholder="搜索用户..." class="pl-10 pr-4 py-2 rounded-lg border border-gray-200 focus:outline-none focus:ring-2 focus:ring-primary/50 w-full sm:w-64"><i class="fa fa-search absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"></i></div><button @click="handleCreateUser" class="inline-flex items-center px-4 py-2 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-primary hover:bg-primary/90 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary"><i class="fa fa-plus mr-2"></i>创建用户</button></div></div><div class="overflow-x-auto"><table class="min-w-full divide-y divide-gray-200"><thead class="bg-gray-50"><tr><th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th><th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">用户信息</th><th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">角色</th><th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">状态</th><th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">创建时间</th><th scope="col" class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">操作</th></tr></thead><tbody class="bg-white divide-y divide-gray-200"><tr v-for="user in users" :key="user.id"><td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{{ user.id }}</td><td class="px-6 py-4 whitespace-nowrap"><div class="flex items-center"><div class="flex-shrink-0 h-10 w-10"><img class="h-10 w-10 rounded-full" :src="user.avatar" alt="用户头像"></div><div class="ml-4"><div class="text-sm font-medium text-gray-900">{{ user.name }}</div><div class="text-sm text-gray-500">{{ user.email }}</div></div></div></td><td class="px-6 py-4 whitespace-nowrap"><span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-100 text-blue-800">{{ user.role }}</span></td><td class="px-6 py-4 whitespace-nowrap"><span :class="user.status === 'active' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'" class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full">{{ user.status === 'active' ? '活跃' : '禁用' }}</span></td><td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ user.createdAt }}</td><td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"><button class="text-indigo-600 hover:text-indigo-900 mr-3" @click="handleEditUser(user)">编辑</button><button class="text-red-600 hover:text-red-900" @click="handleDeleteUser(user)">删除</button></td></tr></tbody></table></div><div class="mt-6 flex items-center justify-between"><div class="flex-1 flex justify-between sm:hidden"><button class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">上一页</button><button class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">下一页</button></div><div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between"><div><p class="text-sm text-gray-700">显示第 <span class="font-medium">{{ (currentPage - 1) * pageSize + 1 }}</span> 至 <span class="font-medium">{{ Math.min(currentPage * pageSize, totalUsers) }}</span> 条,共 <span class="font-medium">{{ totalUsers }}</span> 条记录</p></div><div><nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px" aria-label="Pagination"><button :disabled="currentPage === 1" @click="currentPage--" class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"><span class="sr-only">上一页</span><i class="fa fa-chevron-left h-5 w-5"></i></button><button v-for="page in totalPages" :key="page" :class="page === currentPage ? 'z-10 bg-primary text-white' : 'bg-white text-gray-700'" :aria-current="page === currentPage ? 'page' : undefined" @click="currentPage = page" class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium">{{ page }}</button><button :disabled="currentPage === totalPages" @click="currentPage++" class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"><span class="sr-only">下一页</span><i class="fa fa-chevron-right h-5 w-5"></i></button></nav></div></div></div></div>
</template><script setup>
import { ref, computed, onMounted } from 'vue'const searchQuery = ref('')
const currentPage = ref(1)
const pageSize = ref(10)
const totalUsers = ref(124)const totalPages = computed(() => {return Math.ceil(totalUsers.value / pageSize.value)
})const users = ref([{id: 1,name: '张三',email: 'zhangsan@example.com',role: '管理员',status: 'active',avatar: 'https://picsum.photos/id/1001/40/40',createdAt: '2023-01-15'},{id: 2,name: '李四',email: 'lisi@example.com',role: '编辑',status: 'active',avatar: 'https://picsum.photos/id/1002/40/40',createdAt: '2023-02-20'},{id: 3,name: '王五',email: 'wangwu@example.com',role: '普通用户',status: 'disabled',avatar: 'https://picsum.photos/id/1003/40/40',createdAt: '2023-03-10'},{id: 4,name: '赵六',email: 'zhaoliu@example.com',role: '普通用户',status: 'active',avatar: 'https://picsum.photos/id/1004/40/40',createdAt: '2023-04-05'},{id: 5,name: '钱七',email: 'qianqi@example.com',role: '编辑',status: 'active',avatar: 'https://picsum.photos/id/1005/40/40',createdAt: '2023-05-12'}
])const handleCreateUser = () => {console.log('创建用户')// 打开创建用户模态框
}const handleEditUser = (user) => {console.log('编辑用户', user)// 打开编辑用户模态框
}const handleDeleteUser = (user) => {if (confirm(`确定要删除用户 ${user.name} 吗?`)) {console.log('删除用户', user)// 调用API删除用户}
}onMounted(() => {// 加载用户数据
})
</script>

第 7 步:创建产品管理页面

创建产品管理页面 src/views/Products.vue

<template><div class="bg-white rounded-xl shadow-sm p-6"><div class="flex flex-col md:flex-row md:items-center md:justify-between mb-6"><div><h2 class="text-xl font-bold text-gray-900">产品管理</h2><p class="mt-1 text-sm text-gray-500">管理系统产品信息</p></div><div class="mt-4 md:mt-0 flex flex-col sm:flex-row space-y-2 sm:space-y-0 sm:space-x-3"><div class="relative"><input type="text" v-model="searchQuery" placeholder="搜索产品..." class="pl-10 pr-4 py-2 rounded-lg border border-gray-200 focus:outline-none focus:ring-2 focus:ring-primary/50 w-full sm:w-64"><i class="fa fa-search absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"></i></div><div class="relative"><select v-model="categoryFilter" class="pl-4 pr-10 py-2 rounded-lg border border-gray-200 focus:outline-none focus:ring-2 focus:ring-primary/50 appearance-none bg-white"><option value="">全部分类</option><option value="electronics">电子产品</option><option value="clothing">服装</option><option value="home">家居用品</option><option value="books">图书音像</option></select><i class="fa fa-chevron-down absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 pointer-events-none"></i></div><button @click="handleCreateProduct" class="inline-flex items-center px-4 py-2 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-primary hover:bg-primary/90 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary"><i class="fa fa-plus mr-2"></i>创建产品</button></div></div><div class="overflow-x-auto"><table class="min-w-full divide-y divide-gray-200"><thead class="bg-gray-50"><tr><th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th><th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">产品信息</th><th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">分类</th><th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">价格</th><th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">库存</th><th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">状态</th><th scope="col" class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">操作</th></tr></thead><tbody class="bg-white divide-y divide-gray-200"><tr v-for="product in products" :key="product.id"><td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{{ product.id }}</td><td class="px-6 py-4 whitespace-nowrap"><div class="flex items-center"><div class="flex-shrink-0 h-12 w-12"><img class="h-12 w-12 rounded-md object-cover" :src="product.image" alt="产品图片"></div><div class="ml-4"><div class="text-sm font-medium text-gray-900">{{ product.name }}</div><div class="text-sm text-gray-500">{{ product.description }}</div></div></div></td><td class="px-6 py-4 whitespace-nowrap"><span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-purple-100 text-purple-800">{{ product.category }}</span></td><td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">¥{{ product.price.toFixed(2) }}</td><td class="px-6 py-4 whitespace-nowrap"><span :class="product.stock < 10 ? 'text-red-600' : 'text-gray-900'" class="text-sm font-medium">{{ product.stock }}</span></td><td class="px-6 py-4 whitespace-nowrap"><span :class="product.status === 'active' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'" class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full">{{ product.status === 'active' ? '上架' : '下架' }}</span></td><td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"><button class="text-indigo-600 hover:text-indigo-900 mr-3" @click="handleEditProduct(product)">编辑</button><button class="text-red-600 hover:text-red-900" @click="handleDeleteProduct(product)">删除</button></td></tr></tbody></table></div><div class="mt-6 flex items-center justify-between"><div class="flex-1 flex justify-between sm:hidden"><button class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">上一页</button><button class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">下一页</button></div><div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between"><div><p class="text-sm text-gray-700">显示第 <span class="font-medium">{{ (currentPage - 1) * pageSize + 1 }}</span> 至 <span class="font-medium">{{ Math.min(currentPage * pageSize, totalProducts) }}</span> 条,共 <span class="font-medium">{{ totalProducts }}</span> 条记录</p></div><div><nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px" aria-label="Pagination"><button :disabled="currentPage === 1" @click="currentPage--" class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"><span class="sr-only">上一页</span><i class="fa fa-chevron-left h-5 w-5"></i></button><button v-for="page in totalPages" :key="page" :class="page === currentPage ? 'z-10 bg-primary text-white' : 'bg-white text-gray-700'" :aria-current="page === currentPage ? 'page' : undefined" @click="currentPage = page" class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium">{{ page }}</button><button :disabled="currentPage === totalPages" @click="currentPage++" class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"><span class="sr-only">下一页</span><i class="fa fa-chevron-right h-5 w-5"></i></button></nav></div></div></div></div>
</template><script setup>
import { ref, computed, onMounted } from 'vue'const searchQuery = ref('')
const categoryFilter = ref('')
const currentPage = ref(1)
const pageSize = ref(10)
const totalProducts = ref(86)const totalPages = computed(() => {return Math.ceil(totalProducts.value / pageSize.value)
})const products = ref([{id: 1,name: '智能手表',description: '多功能智能手表,支持心率监测、睡眠分析等功能',category: '电子产品',price: 1299.99,stock: 56,status: 'active',image: 'https://picsum.photos/id/1/80/80'},{id: 2,name: '无线耳机',description: '主动降噪无线耳机,提供沉浸式音乐体验',category: '电子产品',price: 899.99,stock: 32,status: 'active',image: 'https://picsum.photos/id/2/80/80'},{id: 3,name: '纯棉T恤',description: '舒适纯棉T恤,多种颜色可选',category: '服装',price: 99.99,stock: 87,status: 'active',image: 'https://picsum.photos/id/3/80/80'},{id: 4,name: '家用咖啡机',description: '全自动家用咖啡机,一键制作美味咖啡',category: '家居用品',price: 1999.99,stock: 12,status: 'active',image: 'https://picsum.photos/id/4/80/80'},{id: 5,name: '前端开发实战',description: '全面讲解前端开发技术,从入门到精通',category: '图书音像',price: 89.99,stock: 5,status: 'active',image: 'https://picsum.photos/id/5/80/80'}
])const handleCreateProduct = () => {console.log('创建产品')// 打开创建产品模态框
}const handleEditProduct = (product) => {console.log('编辑产品', product)// 打开编辑产品模态框
}const handleDeleteProduct = (product) => {if (confirm(`确定要删除产品 ${product.name} 吗?`)) {console.log('删除产品', product)// 调用API删除产品}
}onMounted(() => {// 加载产品数据
})
</script>

第 8 步:配置主应用

修改 src/main.js 来配置主应用:

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './index.css'
import 'font-awesome/css/font-awesome.min.css'const app = createApp(App)app.use(router)app.mount('#app')

第 9 步:创建主应用组件

修改 src/App.vue

<template><router-view />
</template><script setup>
// 主应用逻辑
</script><style>
/* 全局样式 */
body {margin: 0;padding: 0;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/85825.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/85825.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/85825.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ComfyUI遭“Pickai“C++后门攻击,全球700余台AI图像生成服务器沦陷

大规模AI基础设施遭遇定向攻击 网络安全研究机构XLab近日发现针对ComfyUI框架的活跃攻击活动。ComfyUI是当前广泛用于部署大型AI图像生成模型的开源框架。攻击者通过该框架漏洞植入名为Pickai的C后门程序&#xff0c;已导致全球近700台服务器失陷。中国国家网络安全通报中心于…

Unity_VR_如何用键鼠模拟VR输入_PICO项目配置

文章目录 [TOC] 一、创建项目1.直接创建VR核心模板&#xff08;简单&#xff09;2.创建3D核心模板导入XR包&#xff08;并配置pico&#xff09;&#xff08;1&#xff09;创建项目&#xff08;2&#xff09;导入PICO的SDK&#xff08;3&#xff09;启用 PICO XR 插件&#xff0…

站点天下--网站在线和SSL过期监控的可靠助手

简介 网站突然访问不了、HTTPS证书到期&#xff0c;如果不能及时发现&#xff0c;将蒙受损失~ 站点天下提供应用在线状态监控和SSL证书到期监控&#xff1a; 若访问不了或SSL证书即将到期&#xff0c;则立即发邮件通知&#xff01;可以在线查看应用的在线状态和SSL证书到期时…

React setState原理

异步更新 原因 1设置为异步提升性能 如果setState每次调用直接执行&#xff0c;会造成 render 函数被频繁执行 &#xff0c;页面重新被渲染 解决&#xff1a;异步批处理 2如果render函数未执行时&#xff0c;保证props和state一致性 拿到最新state的方法 法一:setState&…

汉代大模型:历史镜像与智能重构的深度对话

引言&#xff1a;当历史遇见人工智能 一件汉代陶俑的三维模型正通过增强现实技术向观众演绎农耕场景。这个看似寻常的文物活化案例&#xff0c;实则蕴含着人工智能与历史学交叉领域的前沿探索——汉代大模型。作为连接过去与未来的智能载体&#xff0c;汉代大模型不仅重构了我…

es向量检索里的efSearchc参数是干嘛用的

在Elasticsearch的向量检索中&#xff0c;ef_search&#xff08;或efSearch&#xff09;是控制HNSW近似最近邻&#xff08;ANN&#xff09;搜索精度与性能平衡的关键参数&#xff0c;其作用机制和影响如下&#xff1a; &#x1f6e0;️ 一、核心作用 ef_search 限制底层图遍历…

Mac SSH终端操作工具 SecureCRT

SecureCRT Mac 是一款SSH终端工具&#xff0c;为计算专业人士提供高级会话管理工具。 也是一个功能强大且值得信赖的基于GUI的SHH和Telnet客户端&#xff0c;以及旨在提高工作效率并简化重复任务的终端仿真器。 借助SecureCRT mac版的帮助&#xff0c;您可以通过对ANSI&#…

UE5关卡快照

关卡快照&#xff08;Level Snapshots&#xff09; 使你能够在关卡的 世界大纲视图&#xff08;World Outliner&#xff09; 中保存 Actors 的特定配置&#xff0c;并立即将场景恢复到该状态。这样可以大幅简化复杂的设置&#xff0c;并避免对不同场景同一关卡的多个变体进行复…

Maven 或 Gradle 下载和添加 jar 文件的步骤

使用 Maven 或 Gradle 来自动下载和添加 jar 文件是管理 Java 项目依赖的最佳方式。 以下是如何使用 Maven 和 Gradle 来自动下载和添加 jar 文件的步骤&#xff1a; 使用 Maven # 创建一个 Maven 项目&#xff1a; mvn archetype:generate -DgroupIdcom.example -Dartifact…

JVM对象创建全流程解析

一、JVM对象创建流程 Ⅰ、类加载检查——JVM创建对象时先检查类是否加载 在虚拟机遇到new指令时&#xff0c;比如new关键字、对象克隆、对象序列化时&#xff0c;如下字节码 0: new #2 // class com/example/demo/Calculate检查指令的参数&#x…

深度学习从入门到精通:PyTorch实战与核心原理详解

掌握深度学习核心概念&#xff0c;玩转PyTorch框架&#xff0c;从理论到实战一站式学习指南 &#x1f680; 一、深度学习全景图 &#x1f31f; 人工智能金字塔 &#x1f50d; 深度学习核心优势 ​​优势​​​​劣势​​​​适用场景​​自动特征提取依赖大数据图像识别&…

计算机网络期末 物理层

目录 数据通信基础(理解) 传输介质(熟悉) 基带传输(熟悉) 数字编码(熟悉) 频带传输与调制解调(理解) 多路复用技术(了解) 物理层设备与极限速率(掌握) 数据通信基础(理解) 一堆概念 通信的类型 同步技术 传输介质(熟悉) 有线介质 同轴电缆 双绞线 光纤 无线介质 无线电…

力扣-139.单词拆分

题目描述 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。 注意&#xff1a;不要求字典中出现的单词全部都使用&#xff0c;并且字典中的单词可以重复使用。 class Solution {public boolean wordBrea…

LeetCode-1679. K 和数对的最大数目

给你一个整数数组 nums 和一个整数 k 。 每一步操作中&#xff0c;你需要从数组中选出和为 k 的两个整数&#xff0c;并将它们移出数组。 返回你可以对数组执行的最大操作数。 地址&#xff1a;https://leetcode.cn/problems/max-number-of-k-sum-pairs/description/?envTyp…

相机camera开发之差异对比核查四:测试机和对比机的Camera动态参数差异对比及关键字

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、背景 二、:Camera动态参数差异 2.1:动态参数差异核查项 2.2 :动态参数差异核查关键字 2.3 :前置普通拍照动态参数 2.4 :后置普通拍照动态参数 2.5 :后置人像模式…

ModbusTCP转Profibus网关在配料系统中的配置实践

在现代饲料企业的生产过程中&#xff0c;自动化技术的应用日益广泛。其中&#xff0c;ModbusTCP和Profibus是两种常见的工业通信协议&#xff0c;它们在数据采集和设备控制方面发挥着重要作用。然而&#xff0c;由于这两种协议在技术上的差异&#xff0c;直接互通往往存在困难。…

双馈风机分段控制策略的一次调频模型深度解析

双馈风机分段控制策略的一次调频模型深度解析 摘要 随着风电渗透率的急剧攀升,电力系统惯性降低与一次调频能力弱化问题日益凸显。双馈感应发电机(DFIG)凭借其优越的性能已成为主流机型,但其常规控制策略使其自然不具备响应系统频率变化的能力。本文深入探讨基于分段控制策…

JMeter 高阶玩法:分布式压测的技术核心技术要点

在2025年的数字化浪潮中&#xff0c;网站和应用的性能直接决定用户体验和业务成败&#xff01;想象一下&#xff0c;双十一促销期间&#xff0c;你的电商平台因无法承受高并发而崩溃&#xff0c;或者金融系统在高峰期响应迟缓——这不仅是技术问题&#xff0c;更是商业灾难&…

在 Windows 和 Linux 下使用 C/C++ 连接 MySQL 的详细指南

前言 MySQL 是一种流行的关系型数据库管理系统&#xff0c;广泛应用于各种应用程序中。C/C 作为高性能编程语言&#xff0c;常被用于需要与数据库交互的开发中。下面详细讲解如何在 Windows 和 Linux 平台下使用 C/C 连接 MySQL 数据库&#xff0c;帮助你快速上手。 准备工作 …

【人工智能基础】初识神经网络

初识神经网络 本章通过战胜人类围棋世界冠军的AlphaGo案例,介绍神经网络的基本概念,并阐明其与人工智能、机器学习的关系。 1. AlphaGo与围棋:神经网络的实力展示 传统围棋程序:基于固定规则 早期的计算机程序依赖人类专家预先设定的策略(“如果A情况发生,则执行B步骤”…