diff --git a/layouts/admin/AdminLayout.uvue b/layouts/admin/AdminLayout.uvue
index c8458b4f..09e51631 100644
--- a/layouts/admin/AdminLayout.uvue
+++ b/layouts/admin/AdminLayout.uvue
@@ -22,14 +22,15 @@
@@ -86,9 +87,12 @@ import {
} from '@/layouts/admin/router/adminRoutes.uts'
import type { TopMenu, MenuGroup, RouteRecord } from '@/layouts/admin/router/adminRoutes.uts'
+import { MenuNode, settingSubSiderMenu } from '@/layouts/admin/router/settingSubSiderMenu.uts'
+
import {
activeTopMenuId,
activeRouteId,
+ lastSubIdByMenu,
tabs,
isMainAsideCollapsed,
showSubSider,
@@ -123,20 +127,66 @@ const isSubSiderOverlay = computed(() => {
return layoutMode.value === 'tablet'
})
+// 当前路由的路径
+const currentRoutePath = computed(() => {
+ const route = findRouteById(activeRouteId.value)
+ return route ? route.path : ''
+})
+
+// 将旧的 Group + Routes 转换为新的 Tree 结构 (支持 3 级嵌套)
+const activeMenuTree = computed(() => {
+ if (activeTopMenuId.value === 'setting') {
+ return settingSubSiderMenu
+ }
+
+ const tree: MenuNode[] = []
+ activeGroups.value.forEach(group => {
+ const routes = activeRoutes.value.get(group.id)
+ if (routes != null && routes.length > 0) {
+ const children: MenuNode[] = []
+ routes.forEach(route => {
+ children.push({
+ id: route.id,
+ title: route.title,
+ type: 'page',
+ path: route.path
+ } as MenuNode)
+ })
+
+ // 1:1 复刻 CRMEB: 如果分组标题为空,直接将子菜单平铺在顶层,不渲染分组行
+ if (group.title === '') {
+ children.forEach(child => {
+ tree.push(child)
+ })
+ } else {
+ tree.push({
+ id: group.id,
+ title: group.title,
+ type: 'group',
+ children: children
+ } as MenuNode)
+ }
+ }
+ })
+
+ return tree
+})
+
/**
* 核心逻辑:二级菜单是否可见
- * 1. 如果有子菜单内容 (activeGroups > 0)
+ * 1. 如果有子菜单内容 (activeMenuTree > 0)
* 2. 如果是 Desktop 且 showSubSider 为真 (Dock模式)
* 3. 如果是 Tablet/Mobile 且 isOverlayVisible 为真 (Overlay模式)
*/
const isSubSiderVisible = computed(() => {
- if (activeGroups.value.length === 0) return false
+ // 首页模块通常不显示 SubSider
+ if (activeTopMenuId.value === 'home' || activeMenuTree.value.length === 0) return false
if (layoutMode.value === 'desktop') {
return showSubSider.value
}
- // Tablet 和 Mobile 模式下,作为 Overlay 受 isOverlayVisible 控制
+ // Tablet 和 Mobile 模式下,直接由 isOverlayVisible 控制
return isOverlayVisible.value
})
@@ -155,7 +205,7 @@ const mainLeft = computed(() => {
let left = ASIDE_W // 只要不是 Mobile,主侧栏 70px 始终 Dock
// 只有在 Desktop 模式且二级菜单处于 Dock 模式显示时,才累加宽度
- if (layoutMode.value === 'desktop' && showSubSider.value && activeGroups.value.length > 0) {
+ if (layoutMode.value === 'desktop' && showSubSider.value && activeMenuTree.value.length > 0) {
left += SUB_W
}
@@ -199,6 +249,24 @@ const currentComponent = computed(() => {
return getComponent(route.componentKey)
})
+// 监听路由变化,同步状态 (处理从 Tabs 或外部跳转的情况)
+watch(() => activeRouteId.value, (newId) => {
+ const route = findRouteById(newId)
+ if (route && route.parentId) {
+ // 同步一级菜单
+ if (activeTopMenuId.value !== route.parentId) {
+ activeTopMenuId.value = route.parentId
+ }
+ // 同步最后访问记录
+ lastSubIdByMenu.value[route.parentId] = newId
+
+ // 如果是 Desktop 且 SubSider 关着,自动打开(除非用户手动关了)
+ if (layoutMode.value === 'desktop' && !showSubSider.value) {
+ showSubSider.value = true
+ }
+ }
+}, { immediate: true })
+
// ============================================
// 事件处理
// ============================================
@@ -206,27 +274,46 @@ const currentComponent = computed(() => {
function onTopMenuClick(menu: TopMenu): void {
activeTopMenuId.value = menu.id
- // 1:1 复刻 CRMEB 交互:
- // 1. 如果有子菜单:Desktop 下 dock,Tablet/Mobile 下唤起 Overlay
- if (menu.groups.length > 0) {
- if (layoutMode.value === 'desktop') {
- showSubSider.value = true
- } else {
- isOverlayVisible.value = true
- }
+ // 1:1 复刻 CRMEB 交互:点击 Aside 立即展示 SubSider
+ if (layoutMode.value === 'desktop') {
+ showSubSider.value = true
} else {
- // 2. 如果没有子菜单:直接跳转并关闭所有 Overlay
+ isOverlayVisible.value = true
+ isMobileMenuOpen.value = false // 如果主侧栏开着,关掉它,开二级
+ }
+
+ // 1:1 复刻 CRMEB 交互:点击一级菜单后,自动跳转到上一次记录的子页面或第一个子页面
+ let targetId = lastSubIdByMenu.value[menu.id]
+ if (!targetId && activeMenuTree.value.length > 0) {
+ const firstNode = activeMenuTree.value[0]
+ if (firstNode.type === 'page') {
+ targetId = firstNode.id
+ } else if (firstNode.children != null && firstNode.children!.length > 0) {
+ targetId = firstNode.children![0].id
+ }
+ }
+
+ if (targetId) {
+ openRoute(targetId)
+ } else {
+ // 兜底逻辑:如果没有二级菜单,跳转到 index
openRoute(menu.id + '_index')
- closeAllMenu()
}
}
-function onRouteClick(routeId: string): void {
- openRoute(routeId)
- // 1:1 复刻 CRMEB:在移动端或平板叠加模式下,点击具体子路由后自动收起
- if (layoutMode.value !== 'desktop') {
- closeAllMenu()
- }
+function onSubClick(payload: { id: string, path: string }): void {
+ // CRMEB 跳转逻辑
+ openRoute(payload.id)
+
+ // 更新最后访问记录
+ lastSubIdByMenu.value[activeTopMenuId.value] = payload.id
+
+ // 重要:1:1 复刻 CRMEB,点击二级菜单项后,SubSider 通常保持显示状态
+ // 只有在 Mobile 模式下,用户如果是想“跳转并收起”,通常需要点击遮罩或关闭按钮,但这里我们按桌面版常驻逻辑
+ // 如果需要移动端点击自动关闭,才解开下面注释
+ // if (layoutMode.value === 'mobile') {
+ // closeAllMenu()
+ // }
}
function onTabClick(tab: TabItem): void {
diff --git a/layouts/admin/components/AdminAside.uvue b/layouts/admin/components/AdminAside.uvue
index cb424d26..b2870425 100644
--- a/layouts/admin/components/AdminAside.uvue
+++ b/layouts/admin/components/AdminAside.uvue
@@ -109,45 +109,34 @@ function onLogoClick(): void {
.aside-menu {
flex: 1;
- padding: 8px 0;
+ padding: 0; /* CRMEB typically no padding here */
overflow-y: scroll;
}
.menu-item {
- height: 60px;
+ height: 50px; /* 1:1 CRMEB columnsAside height */
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
- color: rgba(255, 255, 255, 0.65);
+ color: rgba(255, 255, 255, 0.7);
transition: all 0.3s;
position: relative;
&:hover {
background: rgba(255, 255, 255, 0.05);
- color: #fff;
}
&.active {
- background: #1890ff;
+ background: #1890ff; /* CRMEB 主色蓝 */
color: #fff;
-
- &::before {
- content: '';
- position: absolute;
- left: 0;
- top: 0;
- bottom: 0;
- width: 3px;
- background: #fff;
- }
}
}
.menu-icon {
- font-size: 24px;
- margin-bottom: 4px;
+ font-size: 18px; /* CRMEB icons are smaller than 24px usually */
+ margin-bottom: 2px;
.icon-text {
display: block;
@@ -156,6 +145,7 @@ function onLogoClick(): void {
.menu-title {
font-size: 12px;
+ transform: scale(0.9); /* CRMEB text is tiny */
text-align: center;
text {
diff --git a/layouts/admin/components/AdminSubsider.uvue b/layouts/admin/components/AdminSubsider.uvue
index 1bd2aa0e..9b2f21e7 100644
--- a/layouts/admin/components/AdminSubsider.uvue
+++ b/layouts/admin/components/AdminSubsider.uvue
@@ -1,57 +1,160 @@
-
diff --git a/layouts/admin/router/adminComponentMap.uts b/layouts/admin/router/adminComponentMap.uts
index b6789ef2..8a7a2c60 100644
--- a/layouts/admin/router/adminComponentMap.uts
+++ b/layouts/admin/router/adminComponentMap.uts
@@ -123,10 +123,25 @@ export const componentMap: Map = new Map([
// 数据模块 - 暂时使用占位组件
['StatisticIndex', PlaceholderPage],
- // 设置模块 - 暂时使用占位组件
+ // 设置模块
['SettingSystemConfig', defineAsyncComponent(() => import('@/pages/mall/admin/setting/system/config.uvue'))],
- ['SettingSystemAdmin', PlaceholderPage],
- ['SettingSystemRole', PlaceholderPage],
+ ['SettingMessage', defineAsyncComponent(() => import('@/pages/mall/admin/setting/message.uvue'))],
+ ['SettingAgreement', defineAsyncComponent(() => import('@/pages/mall/admin/setting/agreement.uvue'))],
+ ['SettingTicket', defineAsyncComponent(() => import('@/pages/mall/admin/setting/ticket.uvue'))],
+ ['SettingAuthRole', defineAsyncComponent(() => import('@/pages/mall/admin/setting/auth/role.uvue'))],
+ ['SettingAuthAdmin', defineAsyncComponent(() => import('@/pages/mall/admin/setting/auth/admin.uvue'))],
+ ['SettingAuthPermission', defineAsyncComponent(() => import('@/pages/mall/admin/setting/auth/permission.uvue'))],
+ ['SettingDeliveryStaff', defineAsyncComponent(() => import('@/pages/mall/admin/setting/delivery/staff.uvue'))],
+ ['SettingDeliveryStation', defineAsyncComponent(() => import('@/pages/mall/admin/setting/delivery/station.uvue'))],
+ ['SettingDeliveryTemplate', defineAsyncComponent(() => import('@/pages/mall/admin/setting/delivery/template.uvue'))],
+ ['SettingInterfaceOnepassConfig', defineAsyncComponent(() => import('@/pages/mall/admin/setting/interface/onepass/config.uvue'))],
+ ['SettingInterfaceOnepassIndex', defineAsyncComponent(() => import('@/pages/mall/admin/setting/interface/onepass/index.uvue'))],
+ ['SettingInterfaceStorage', defineAsyncComponent(() => import('@/pages/mall/admin/setting/interface/storage.uvue'))],
+ ['SettingInterfaceCollect', defineAsyncComponent(() => import('@/pages/mall/admin/setting/interface/collect.uvue'))],
+ ['SettingInterfaceLogistics', defineAsyncComponent(() => import('@/pages/mall/admin/setting/interface/logistics.uvue'))],
+ ['SettingInterfaceESheet', defineAsyncComponent(() => import('@/pages/mall/admin/setting/interface/e-sheet.uvue'))],
+ ['SettingInterfaceSms', defineAsyncComponent(() => import('@/pages/mall/admin/setting/interface/sms.uvue'))],
+ ['SettingInterfacePayment', defineAsyncComponent(() => import('@/pages/mall/admin/setting/interface/payment.uvue'))],
// 分销模块
['DistributionStatistic', PlaceholderPage],
diff --git a/layouts/admin/router/adminRoutes.uts b/layouts/admin/router/adminRoutes.uts
index 3c8407c9..81a20135 100644
--- a/layouts/admin/router/adminRoutes.uts
+++ b/layouts/admin/router/adminRoutes.uts
@@ -92,7 +92,7 @@ export const topMenus: TopMenu[] = [
path: '/pages/mall/admin/product/statistic',
order: 4,
groups: [
- { id: 'product-manage', title: '商品管理', order: 1 }
+ { id: 'product-manage', title: '', order: 1 }
]
},
{
@@ -156,7 +156,7 @@ export const topMenus: TopMenu[] = [
path: '/pages/mall/admin/cms/article/list',
order: 9,
groups: [
- { id: 'cms-manage', title: '内容管理', order: 1 }
+ { id: 'cms-manage', title: '', order: 1 }
]
},
{
@@ -187,7 +187,10 @@ export const topMenus: TopMenu[] = [
order: 12,
groups: [
{ id: 'setting-system', title: '系统设置', order: 1 },
- { id: 'setting-application', title: '应用设置', order: 2 }
+ { id: 'setting-message', title: '通知管理', order: 2 },
+ { id: 'setting-auth', title: '权限管理', order: 3 },
+ { id: 'setting-delivery', title: '物流设置', order: 4 },
+ { id: 'setting-interface', title: '接口设置', order: 5 }
]
},
{
@@ -892,6 +895,7 @@ export const routes: RouteRecord[] = [
},
// ========== 设置模块 ==========
+ // 1. 系统设置
{
id: 'setting_systemConfig',
title: '系统设置',
@@ -902,27 +906,168 @@ export const routes: RouteRecord[] = [
auth: ['admin-setting-system-config'],
order: 1
},
+
+ // 2. 通知管理
{
- id: 'setting_systemAdmin',
- title: '管理员管理',
- path: '/pages/mall/admin/setting/system/admin',
- componentKey: 'SettingSystemAdmin',
+ id: 'setting_message',
+ title: '消息管理',
+ path: '/pages/mall/admin/setting/message',
+ componentKey: 'SettingMessage',
parentId: 'setting',
- groupId: 'setting-system',
- auth: ['admin-setting-system-admin'],
+ groupId: 'setting-message',
+ order: 1
+ },
+ {
+ id: 'setting_agreement',
+ title: '协议管理',
+ path: '/pages/mall/admin/setting/agreement',
+ componentKey: 'SettingAgreement',
+ parentId: 'setting',
+ groupId: 'setting-message',
order: 2
},
{
- id: 'setting_systemRole',
- title: '角色管理',
- path: '/pages/mall/admin/setting/system/role',
- componentKey: 'SettingSystemRole',
+ id: 'setting_ticket',
+ title: '客服设置',
+ path: '/pages/mall/admin/setting/ticket',
+ componentKey: 'SettingTicket',
parentId: 'setting',
- groupId: 'setting-system',
- auth: ['admin-setting-system-role'],
+ groupId: 'setting-message',
order: 3
},
+ // 3. 权限管理
+ {
+ id: 'setting_auth_role',
+ title: '角色管理',
+ path: '/pages/mall/admin/setting/auth/role',
+ componentKey: 'SettingAuthRole',
+ parentId: 'setting',
+ groupId: 'setting-auth',
+ order: 1
+ },
+ {
+ id: 'setting_auth_admin',
+ title: '管理员管理',
+ path: '/pages/mall/admin/setting/auth/admin',
+ componentKey: 'SettingAuthAdmin',
+ parentId: 'setting',
+ groupId: 'setting-auth',
+ order: 2
+ },
+ {
+ id: 'setting_auth_permission',
+ title: '权限管理',
+ path: '/pages/mall/admin/setting/auth/permission',
+ componentKey: 'SettingAuthPermission',
+ parentId: 'setting',
+ groupId: 'setting-auth',
+ order: 3
+ },
+
+ // 4. 物流设置
+ {
+ id: 'setting_delivery_staff',
+ title: '配送员管理',
+ path: '/pages/mall/admin/setting/delivery/staff',
+ componentKey: 'SettingDeliveryStaff',
+ parentId: 'setting',
+ groupId: 'setting-delivery',
+ order: 1
+ },
+ {
+ id: 'setting_delivery_station',
+ title: '提货点管理',
+ path: '/pages/mall/admin/setting/delivery/station',
+ componentKey: 'SettingDeliveryStation',
+ parentId: 'setting',
+ groupId: 'setting-delivery',
+ order: 2
+ },
+ {
+ id: 'setting_delivery_template',
+ title: '运费模板',
+ path: '/pages/mall/admin/setting/delivery/template',
+ componentKey: 'SettingDeliveryTemplate',
+ parentId: 'setting',
+ groupId: 'setting-delivery',
+ order: 3
+ },
+
+ // 5. 接口设置
+ {
+ id: 'setting_interface_onepass_config',
+ title: '总平台配置',
+ path: '/pages/mall/admin/setting/interface/onepass/config',
+ componentKey: 'SettingInterfaceOnepassConfig',
+ parentId: 'setting',
+ groupId: 'setting-interface',
+ order: 1
+ },
+ {
+ id: 'setting_interface_onepass_index',
+ title: '账号列表',
+ path: '/pages/mall/admin/setting/interface/onepass/index',
+ componentKey: 'SettingInterfaceOnepassIndex',
+ parentId: 'setting',
+ groupId: 'setting-interface',
+ order: 2
+ },
+ {
+ id: 'setting_interface_storage',
+ title: '存储配置',
+ path: '/pages/mall/admin/setting/interface/storage',
+ componentKey: 'SettingInterfaceStorage',
+ parentId: 'setting',
+ groupId: 'setting-interface',
+ order: 3
+ },
+ {
+ id: 'setting_interface_collect',
+ title: '商品采集',
+ path: '/pages/mall/admin/setting/interface/collect',
+ componentKey: 'SettingInterfaceCollect',
+ parentId: 'setting',
+ groupId: 'setting-interface',
+ order: 4
+ },
+ {
+ id: 'setting_interface_logistics',
+ title: '物流查询',
+ path: '/pages/mall/admin/setting/interface/logistics',
+ componentKey: 'SettingInterfaceLogistics',
+ parentId: 'setting',
+ groupId: 'setting-interface',
+ order: 5
+ },
+ {
+ id: 'setting_interface_esheet',
+ title: '电子面单',
+ path: '/pages/mall/admin/setting/interface/e-sheet',
+ componentKey: 'SettingInterfaceESheet',
+ parentId: 'setting',
+ groupId: 'setting-interface',
+ order: 6
+ },
+ {
+ id: 'setting_interface_sms',
+ title: '短信接口',
+ path: '/pages/mall/admin/setting/interface/sms',
+ componentKey: 'SettingInterfaceSms',
+ parentId: 'setting',
+ groupId: 'setting-interface',
+ order: 7
+ },
+ {
+ id: 'setting_interface_payment',
+ title: '商城支付',
+ path: '/pages/mall/admin/setting/interface/payment',
+ componentKey: 'SettingInterfacePayment',
+ parentId: 'setting',
+ groupId: 'setting-interface',
+ order: 8
+ },
+
// ========== 分销模块 ==========
{
id: 'distribution_statistic',
@@ -1055,7 +1200,7 @@ export const routes: RouteRecord[] = [
order: 6
},
{
- id: 'decoration_link',
+ id: 'DecorationLink',
title: '链接管理',
path: '/pages/mall/admin/decoration/link',
componentKey: 'DecorationLink',
@@ -1064,6 +1209,30 @@ export const routes: RouteRecord[] = [
order: 7
},
+ // ========== 设置模块 (1:1 复刻 CRMEB 路由结构) ==========
+ // 通知管理
+ { id: 'setting_message_index', title: '消息管理', path: '/pages/mall/admin/setting/message/index', componentKey: 'SettingMessageIndex', parentId: 'setting', groupId: 'setting-message', order: 1 },
+ { id: 'setting_protocol_index', title: '协议设置', path: '/pages/mall/admin/setting/protocol/index', componentKey: 'SettingProtocolIndex', parentId: 'setting', groupId: 'setting-message', order: 2 },
+ { id: 'setting_ticket_index', title: '小票配置', path: '/pages/mall/admin/setting/ticket/index', componentKey: 'SettingTicketIndex', parentId: 'setting', groupId: 'setting-message', order: 3 },
+
+ // 权限管理
+ { id: 'setting_auth_role', title: '角色管理', path: '/pages/mall/admin/setting/auth/role/index', componentKey: 'SettingAuthRole', parentId: 'setting', groupId: 'setting-auth', order: 1 },
+ { id: 'setting_auth_admin', title: '管理员列表', path: '/pages/mall/admin/setting/auth/admin-list/index', componentKey: 'SettingAuthAdmin', parentId: 'setting', groupId: 'setting-auth', order: 2 },
+ { id: 'setting_auth_perm', title: '权限设置', path: '/pages/mall/admin/setting/auth/permission/index', componentKey: 'SettingAuthPerm', parentId: 'setting', groupId: 'setting-auth', order: 3 },
+
+ // 物流设置
+ { id: 'setting_delivery_courier', title: '配送员管理', path: '/pages/mall/admin/setting/delivery/courier/index', componentKey: 'SettingDeliveryCourier', parentId: 'setting', groupId: 'setting-delivery', order: 1 },
+ { id: 'setting_delivery_pickup', title: '提货点设置', path: '/pages/mall/admin/setting/delivery/pickup/index', componentKey: 'SettingDeliveryPickup', parentId: 'setting', groupId: 'setting-delivery', order: 2 },
+ { id: 'setting_delivery_freight', title: '运费模板', path: '/pages/mall/admin/setting/delivery/freight/index', componentKey: 'SettingDeliveryFreight', parentId: 'setting', groupId: 'setting-delivery', order: 3 },
+
+ // 接口设置
+ { id: 'setting_api_storage', title: '系统存储配置', path: '/pages/mall/admin/setting/api/yht/storage/index', componentKey: 'SettingApiStorage', parentId: 'setting', groupId: 'setting-interface', order: 1 },
+ { id: 'setting_api_collect', title: '商品采集配置', path: '/pages/mall/admin/setting/api/yht/collect/index', componentKey: 'SettingApiCollect', parentId: 'setting', groupId: 'setting-interface', order: 2 },
+ { id: 'setting_api_logistics', title: '物流查询配置', path: '/pages/mall/admin/setting/api/yht/logistics/index', componentKey: 'SettingApiLogistics', parentId: 'setting', groupId: 'setting-interface', order: 3 },
+ { id: 'setting_api_waybill', title: '电子面单配置', path: '/pages/mall/admin/setting/api/yht/waybill/index', componentKey: 'SettingApiWaybill', parentId: 'setting', groupId: 'setting-interface', order: 4 },
+ { id: 'setting_api_sms', title: '短信接口配置', path: '/pages/mall/admin/setting/api/yht/sms/index', componentKey: 'SettingApiSms', parentId: 'setting', groupId: 'setting-interface', order: 5 },
+ { id: 'setting_api_pay', title: '商城支付配置', path: '/pages/mall/admin/setting/api/yht/pay/index', componentKey: 'SettingApiPay', parentId: 'setting', groupId: 'setting-interface', order: 6 },
+
// ========== 应用模块 ==========
{
id: 'app_statistic',
diff --git a/layouts/admin/router/settingSubSiderMenu.uts b/layouts/admin/router/settingSubSiderMenu.uts
new file mode 100644
index 00000000..d4e86291
--- /dev/null
+++ b/layouts/admin/router/settingSubSiderMenu.uts
@@ -0,0 +1,37 @@
+export type MenuNode = {
+ id: string
+ title: string
+ type: 'group' | 'page'
+ path?: string // type=page 必填
+ children?: MenuNode[] // type=group 必填
+}
+
+export const settingSubSiderMenu: MenuNode[] = [
+ { id: 'setting_message_index', title: '消息管理', type: 'page', path: '/pages/mall/admin/setting/message/index' },
+ { id: 'setting_protocol_index', title: '协议设置', type: 'page', path: '/pages/mall/admin/setting/protocol/index' },
+ { id: 'setting_ticket_index', title: '小票配置', type: 'page', path: '/pages/mall/admin/setting/ticket/index' },
+ { id: 'auth_group', title: '管理权限', type: 'group', children: [
+ { id: 'setting_auth_role', title: '角色管理', type: 'page', path: '/pages/mall/admin/setting/auth/role/index' },
+ { id: 'setting_auth_admin', title: '管理员列表', type: 'page', path: '/pages/mall/admin/setting/auth/admin-list/index' },
+ { id: 'setting_auth_perm', title: '权限设置', type: 'page', path: '/pages/mall/admin/setting/auth/permission/index' }
+ ]
+ },
+ { id: 'delivery_group', title: '发货设置', type: 'group', children: [
+ { id: 'setting_delivery_courier', title: '配送员管理', type: 'page', path: '/pages/mall/admin/setting/delivery/courier/index' },
+ { id: 'setting_delivery_pickup', title: '提货点设置', type: 'page', path: '/pages/mall/admin/setting/delivery/pickup/index' },
+ { id: 'setting_delivery_freight', title: '运费模板', type: 'page', path: '/pages/mall/admin/setting/delivery/freight/index' }
+ ]
+ },
+ { id: 'api_group', title: '接口配置', type: 'group', children: [
+ { id: 'yh_tong', title: '一号通', type: 'group', children: [
+ { id: 'setting_api_storage', title: '系统存储配置', type: 'page', path: '/pages/mall/admin/setting/api/yht/storage/index' },
+ { id: 'setting_api_collect', title: '商品采集配置', type: 'page', path: '/pages/mall/admin/setting/api/yht/collect/index' },
+ { id: 'setting_api_logistics', title: '物流查询配置', type: 'page', path: '/pages/mall/admin/setting/api/yht/logistics/index' },
+ { id: 'setting_api_waybill', title: '电子面单配置', type: 'page', path: '/pages/mall/admin/setting/api/yht/waybill/index' },
+ { id: 'setting_api_sms', title: '短信接口配置', type: 'page', path: '/pages/mall/admin/setting/api/yht/sms/index' },
+ { id: 'setting_api_pay', title: '商城支付配置', type: 'page', path: '/pages/mall/admin/setting/api/yht/pay/index' }
+ ]
+ }
+ ]
+ }
+]
diff --git a/layouts/admin/store/adminNavStore.uts b/layouts/admin/store/adminNavStore.uts
index a88eb58f..de3ab582 100644
--- a/layouts/admin/store/adminNavStore.uts
+++ b/layouts/admin/store/adminNavStore.uts
@@ -11,6 +11,7 @@ import {
buildDefaultTabs,
getTopMenus
} from '@/layouts/admin/router/adminRoutes.uts'
+import { addView, activeFullPath, visitedViews } from './tagsViewStore.uts'
/**
* 标签页类型
@@ -32,6 +33,12 @@ export const activeTopMenuId = ref('home')
/** 当前激活的路由ID */
export const activeRouteId = ref('home_index')
+/** 记录每个一级模块上一次访问的二级路由ID (CRMEB 体验增强) */
+export const lastSubIdByMenu = ref>({})
+
+/** 标记是否由用户手动关闭了 SubSider (移动端) */
+export const isManualClosed = ref(false)
+
/** 打开的标签页列表 */
export const tabs = ref([])
@@ -82,6 +89,8 @@ export function openRoute(routeId: string, addTab: boolean = true): void {
// 更新一级菜单选中态
if (route.parentId) {
activeTopMenuId.value = route.parentId
+ // 记录该模块最后访问的子路由
+ lastSubIdByMenu.value[route.parentId] = routeId
} else {
// 首页等顶级路由
activeTopMenuId.value = routeId.split('_')[0]
@@ -116,6 +125,10 @@ function addTabItem(route: RouteRecord): void {
isAffix: route.isAffix || false
})
}
+
+ // 更新新版 TagsViewStore
+ addView(route, route.path)
+ activeFullPath.value = route.path
}
/**
@@ -201,6 +214,11 @@ export function initNavState(): void {
isAffix: r.isAffix || false
}))
+ // 初始化 TagsViewStore
+ defaultTabs.forEach(r => {
+ addView(r, r.path)
+ })
+
// 打开首页
openRoute('home_index', false)
}
diff --git a/layouts/admin/store/tagsViewStore.uts b/layouts/admin/store/tagsViewStore.uts
new file mode 100644
index 00000000..01497a4f
--- /dev/null
+++ b/layouts/admin/store/tagsViewStore.uts
@@ -0,0 +1,126 @@
+/**
+ * TagsView 状态管理
+ * 复刻 CRMEB 风格的标签栏逻辑
+ */
+
+import { ref } from 'vue'
+import type { RouteRecord } from '@/layouts/admin/router/adminRoutes.uts'
+
+/**
+ * 标签页视图类型
+ */
+export type TagView = {
+ id: string // 对应路由ID
+ title: string // 标题
+ path: string // 基础路径
+ fullPath: string // 完整路径(包含参数)
+ name: string // 组件Key
+ meta: {
+ affix?: boolean
+ noCache?: boolean
+ }
+}
+
+/** 访问过的页面列表 */
+export const visitedViews = ref([])
+
+/** 缓存的页面列表 (用于 keep-alive) */
+export const cachedViews = ref([])
+
+/** 开启的标签页详情 */
+export const activeFullPath = ref('')
+
+// ============================================
+// Actions
+// ============================================
+
+/**
+ * 添加视图
+ */
+export function addView(route: RouteRecord, fullPath: string): void {
+ // 1. 添加到访问列表
+ if (visitedViews.value.some(v => v.fullPath === fullPath)) return
+
+ // 如果 ID 相同但 fullPath 不同(参数变化), 则更新或者替换
+ const existingIndex = visitedViews.value.findIndex(v => v.id === route.id)
+
+ const newView: TagView = {
+ id: route.id,
+ title: route.title,
+ path: route.path,
+ fullPath: fullPath,
+ name: route.componentKey,
+ meta: {
+ affix: route.isAffix || false,
+ noCache: false // 默认为缓存,如果有特殊需求可扩展
+ }
+ }
+
+ if (existingIndex > -1) {
+ // 同一路由不同参数, 更新记录
+ visitedViews.value[existingIndex] = newView
+ } else {
+ visitedViews.value.push(newView)
+ }
+
+ // 2. 添加到缓存列表
+ if (!route.componentKey) return
+ if (cachedViews.value.includes(route.componentKey)) return
+ cachedViews.value.push(route.componentKey)
+}
+
+/**
+ * 删除视图
+ */
+export function delView(view: TagView): void {
+ const index = visitedViews.value.findIndex(v => v.fullPath === view.fullPath)
+ if (index > -1 && !visitedViews.value[index].meta.affix) {
+ visitedViews.value.splice(index, 1)
+ }
+
+ const cacheIndex = cachedViews.value.indexOf(view.name)
+ if (cacheIndex > -1) {
+ cachedViews.value.splice(cacheIndex, 1)
+ }
+}
+
+/**
+ * 关闭其他标签
+ */
+export function delOthersViews(view: TagView): void {
+ visitedViews.value = visitedViews.value.filter(v => v.meta.affix || v.fullPath === view.fullPath)
+ cachedViews.value = visitedViews.value.map(v => v.name)
+}
+
+/**
+ * 关闭右侧标签
+ */
+export function delRightTags(view: TagView): void {
+ const index = visitedViews.value.findIndex(v => v.fullPath === view.fullPath)
+ if (index === -1) return
+
+ visitedViews.value = visitedViews.value.filter((v, i) => {
+ return i <= index || v.meta.affix
+ })
+ cachedViews.value = visitedViews.value.map(v => v.name)
+}
+
+/**
+ * 关闭所有
+ */
+export function delAllViews(): void {
+ const affixTags = visitedViews.value.filter(v => v.meta.affix)
+ visitedViews.value = affixTags
+ cachedViews.value = affixTags.map(v => v.name)
+}
+
+/**
+ * 刷新当前视图 (通常结合全局事件通知组件)
+ */
+export function refreshView(view: TagView): void {
+ const index = cachedViews.value.indexOf(view.name)
+ if (index > -1) {
+ cachedViews.value.splice(index, 1)
+ }
+ // 通知框架重新加载该组件的逻辑通常在组件内部处理或通过 key 变化
+}
diff --git a/pages/mall/admin/setting/agreement.uvue b/pages/mall/admin/setting/agreement.uvue
new file mode 100644
index 00000000..10d80c88
--- /dev/null
+++ b/pages/mall/admin/setting/agreement.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 协议管理 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/auth/admin.uvue b/pages/mall/admin/setting/auth/admin.uvue
new file mode 100644
index 00000000..a3fe4068
--- /dev/null
+++ b/pages/mall/admin/setting/auth/admin.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 管理员列表 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/auth/permission.uvue b/pages/mall/admin/setting/auth/permission.uvue
new file mode 100644
index 00000000..cb9c5c56
--- /dev/null
+++ b/pages/mall/admin/setting/auth/permission.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 权限设置 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/auth/role.uvue b/pages/mall/admin/setting/auth/role.uvue
new file mode 100644
index 00000000..9ebc8c82
--- /dev/null
+++ b/pages/mall/admin/setting/auth/role.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 角色管理 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/delivery/staff.uvue b/pages/mall/admin/setting/delivery/staff.uvue
new file mode 100644
index 00000000..a0dc1ded
--- /dev/null
+++ b/pages/mall/admin/setting/delivery/staff.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 配送员管理 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/delivery/station.uvue b/pages/mall/admin/setting/delivery/station.uvue
new file mode 100644
index 00000000..cb848d40
--- /dev/null
+++ b/pages/mall/admin/setting/delivery/station.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 提货点设置 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/delivery/template.uvue b/pages/mall/admin/setting/delivery/template.uvue
new file mode 100644
index 00000000..55733264
--- /dev/null
+++ b/pages/mall/admin/setting/delivery/template.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 运费模板 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/interface/collect.uvue b/pages/mall/admin/setting/interface/collect.uvue
new file mode 100644
index 00000000..aa80b437
--- /dev/null
+++ b/pages/mall/admin/setting/interface/collect.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 商品采集配置 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/interface/e-sheet.uvue b/pages/mall/admin/setting/interface/e-sheet.uvue
new file mode 100644
index 00000000..5a25a5e2
--- /dev/null
+++ b/pages/mall/admin/setting/interface/e-sheet.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 电子面单配置 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/interface/logistics.uvue b/pages/mall/admin/setting/interface/logistics.uvue
new file mode 100644
index 00000000..1aacab1c
--- /dev/null
+++ b/pages/mall/admin/setting/interface/logistics.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 物流查询配置 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/interface/onepass/config.uvue b/pages/mall/admin/setting/interface/onepass/config.uvue
new file mode 100644
index 00000000..b8bd3b6f
--- /dev/null
+++ b/pages/mall/admin/setting/interface/onepass/config.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 一号通配置 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/interface/onepass/index.uvue b/pages/mall/admin/setting/interface/onepass/index.uvue
new file mode 100644
index 00000000..c0366097
--- /dev/null
+++ b/pages/mall/admin/setting/interface/onepass/index.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 一号通页面 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/interface/payment.uvue b/pages/mall/admin/setting/interface/payment.uvue
new file mode 100644
index 00000000..c27a802e
--- /dev/null
+++ b/pages/mall/admin/setting/interface/payment.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 商城支付配置 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/interface/sms.uvue b/pages/mall/admin/setting/interface/sms.uvue
new file mode 100644
index 00000000..07e58033
--- /dev/null
+++ b/pages/mall/admin/setting/interface/sms.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 短信接口配置 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/interface/storage.uvue b/pages/mall/admin/setting/interface/storage.uvue
new file mode 100644
index 00000000..a53f763d
--- /dev/null
+++ b/pages/mall/admin/setting/interface/storage.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 系统存储配置 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/message.uvue b/pages/mall/admin/setting/message.uvue
new file mode 100644
index 00000000..13442107
--- /dev/null
+++ b/pages/mall/admin/setting/message.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 消息管理 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/system/agreement.uvue b/pages/mall/admin/setting/system/agreement.uvue
new file mode 100644
index 00000000..d6720e55
--- /dev/null
+++ b/pages/mall/admin/setting/system/agreement.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 协议设置 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/system/message.uvue b/pages/mall/admin/setting/system/message.uvue
new file mode 100644
index 00000000..13442107
--- /dev/null
+++ b/pages/mall/admin/setting/system/message.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 消息管理 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/system/ticket.uvue b/pages/mall/admin/setting/system/ticket.uvue
new file mode 100644
index 00000000..c5f02ac2
--- /dev/null
+++ b/pages/mall/admin/setting/system/ticket.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 小票配置 页面开发中...
+
+
+
+
+
+
+
+
diff --git a/pages/mall/admin/setting/ticket.uvue b/pages/mall/admin/setting/ticket.uvue
new file mode 100644
index 00000000..5f729ad6
--- /dev/null
+++ b/pages/mall/admin/setting/ticket.uvue
@@ -0,0 +1,23 @@
+
+
+
+
+
+ 客服设置 页面开发中...
+
+
+
+
+
+
+
+