Files
cuimengxue/frontend/src/views/merchant/MerchantLayout.vue
wangziqi d6451cf188 feat: 重构后台路由并使用嵌套路由;添加图片上传功能
- 拆分 AdminView 为多个子页面组件,使用嵌套路由
- 拆分 MerchantView 为多个子页面组件,使用嵌套路由
- 创建 AdminLayout 和 MerchantLayout 布局组件
- 修复编译错误:IconSend 重复导入、IconDatabase 不存在
- 修复 HomeView 缺失 onMounted 导入
- 添加文件上传后端接口和静态资源映射
- 为商品和轮播图添加图片上传功能(支持预览、清除)
2026-02-10 15:14:23 +08:00

126 lines
4.7 KiB
Vue

<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>