feat: 重构后台路由并使用嵌套路由;添加图片上传功能
- 拆分 AdminView 为多个子页面组件,使用嵌套路由 - 拆分 MerchantView 为多个子页面组件,使用嵌套路由 - 创建 AdminLayout 和 MerchantLayout 布局组件 - 修复编译错误:IconSend 重复导入、IconDatabase 不存在 - 修复 HomeView 缺失 onMounted 导入 - 添加文件上传后端接口和静态资源映射 - 为商品和轮播图添加图片上传功能(支持预览、清除)
This commit is contained in:
126
frontend/src/views/merchant/MerchantLayout.vue
Normal file
126
frontend/src/views/merchant/MerchantLayout.vue
Normal file
@@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<a-layout style="min-height: 100vh" class="merchant-layout">
|
||||
<a-layout-sider :width="240" theme="dark" collapsible v-model:collapsed="collapsed" :collapsed-width="64" class="merchant-sider">
|
||||
<div class="sider-header">
|
||||
<a-avatar :size="36" style="background: linear-gradient(135deg, #52c41a 0%, #73d13d 100%)">
|
||||
<icon-home />
|
||||
</a-avatar>
|
||||
<span class="sider-title" v-if="!collapsed">商家后台</span>
|
||||
</div>
|
||||
<a-menu :selected-keys="[$route.name]" @menu-item-click="onMenuClick" theme="dark">
|
||||
<a-menu-item key="merchant-overview">
|
||||
<template #icon><icon-dashboard /></template>
|
||||
<span v-if="!collapsed">数据概览</span>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="merchant-products">
|
||||
<template #icon><icon-apps /></template>
|
||||
<span v-if="!collapsed">商品管理</span>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="merchant-orders">
|
||||
<template #icon><icon-file /></template>
|
||||
<span v-if="!collapsed">订单管理</span>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="merchant-reviews">
|
||||
<template #icon><icon-message /></template>
|
||||
<span v-if="!collapsed">评价管理</span>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="merchant-logistics">
|
||||
<template #icon><icon-send /></template>
|
||||
<span v-if="!collapsed">物流管理</span>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="merchant-inventory">
|
||||
<template #icon><icon-storage /></template>
|
||||
<span v-if="!collapsed">库存管理</span>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="merchant-profile">
|
||||
<template #icon><icon-user /></template>
|
||||
<span v-if="!collapsed">个人信息</span>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-layout-sider>
|
||||
<a-layout class="merchant-main">
|
||||
<a-layout-header class="merchant-header">
|
||||
<div class="header-left">
|
||||
<span class="page-title">{{ titleMap[$route.name] || '商家后台' }}</span>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<a-space>
|
||||
<a-button @click="goHome">
|
||||
<template #icon><icon-home /></template>
|
||||
去商城
|
||||
</a-button>
|
||||
<a-dropdown>
|
||||
<a-button shape="circle">
|
||||
<template #icon><icon-user /></template>
|
||||
</a-button>
|
||||
<template #content>
|
||||
<a-doption @click="goProfile">
|
||||
<template #icon><icon-settings /></template>
|
||||
个人信息
|
||||
</a-doption>
|
||||
<a-doption @click="logout">
|
||||
<template #icon><icon-export /></template>
|
||||
退出登录
|
||||
</a-doption>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</a-space>
|
||||
</div>
|
||||
</a-layout-header>
|
||||
<a-layout-content class="merchant-content">
|
||||
<router-view />
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
</a-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useUserStore } from '../../stores/user'
|
||||
import { IconHome, IconDashboard, IconApps, IconFile, IconMessage, IconSend, IconStorage, IconUser, IconExport, IconSettings } from '@arco-design/web-vue/es/icon'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const userStore = useUserStore()
|
||||
const collapsed = ref(false)
|
||||
|
||||
const titleMap = {
|
||||
'merchant-overview': '数据概览',
|
||||
'merchant-products': '商品管理',
|
||||
'merchant-orders': '订单管理',
|
||||
'merchant-reviews': '评价管理',
|
||||
'merchant-logistics': '物流管理',
|
||||
'merchant-inventory': '库存管理',
|
||||
'merchant-profile': '个人信息'
|
||||
}
|
||||
|
||||
const onMenuClick = (key) => {
|
||||
router.push({ name: key })
|
||||
}
|
||||
|
||||
const goHome = () => router.push('/')
|
||||
const goProfile = () => router.push({ name: 'merchant-profile' })
|
||||
const logout = async () => {
|
||||
await userStore.logout()
|
||||
router.replace('/login')
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await userStore.fetchMe()
|
||||
if (userStore.role !== 'MERCHANT') {
|
||||
router.replace('/login')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.merchant-layout { background: #f0f2f5; }
|
||||
.merchant-sider { background: #001529; }
|
||||
.sider-header { height: 64px; display: flex; align-items: center; justify-content: center; gap: 10px; padding: 0 16px; border-bottom: 1px solid rgba(255,255,255,0.1); }
|
||||
.sider-title { font-size: 16px; font-weight: 600; color: #fff; }
|
||||
.merchant-main { background: #f0f2f5; }
|
||||
.merchant-header { background: #fff; padding: 0 24px; display: flex; align-items: center; justify-content: space-between; box-shadow: 0 1px 4px rgba(0,0,0,0.1); }
|
||||
.page-title { font-size: 18px; font-weight: 600; color: #1f2937; }
|
||||
.merchant-content { padding: 20px; overflow: auto; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user