feat(home): 添加菜单项徽章显示功能
- 在首页菜单项中集成 VanBadge 组件用于展示待办数量 - 引入 todoStore 并使用 storeToRefs 获取响应式统计数据 - 将 menuList 改为计算属性以动态绑定统计数据 - 在组件挂载时调用 fetchTodoStatistics 方法加载数据 - 添加 .menu-badge 样式类定义徽章左侧间距 - 默认展开抽屉状态以便查看新增的徽章效果master
parent
292fc35d54
commit
3d3af1867b
|
|
@ -9,6 +9,7 @@ declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
VanBadge: typeof import('vant/es')['Badge']
|
||||||
VanButton: typeof import('vant/es')['Button']
|
VanButton: typeof import('vant/es')['Button']
|
||||||
VanCellGroup: typeof import('vant/es')['CellGroup']
|
VanCellGroup: typeof import('vant/es')['CellGroup']
|
||||||
VanEmpty: typeof import('vant/es')['Empty']
|
VanEmpty: typeof import('vant/es')['Empty']
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { getTodoStatistics } from '@/api/todo'
|
||||||
|
import type { TodoStatistics } from '@/api/todo'
|
||||||
|
|
||||||
|
interface TodoState {
|
||||||
|
statistics: TodoStatistics | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useTodoStore = defineStore('todo', {
|
||||||
|
state: (): TodoState => ({
|
||||||
|
statistics: null
|
||||||
|
}),
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
/**
|
||||||
|
* 获取待办事项统计
|
||||||
|
*/
|
||||||
|
async fetchTodoStatistics() {
|
||||||
|
try {
|
||||||
|
const response = await getTodoStatistics()
|
||||||
|
if (response.status === 200 && response.data.code === 0) {
|
||||||
|
// The actual data is in response.data.data
|
||||||
|
this.statistics = response.data.data
|
||||||
|
} else {
|
||||||
|
throw new Error(response.data.msg || '获取待办统计失败')
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('获取待办统计接口调用失败:', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@ -38,8 +38,13 @@
|
||||||
:class="{ active: currentMenu === menu.key }"
|
:class="{ active: currentMenu === menu.key }"
|
||||||
@click="selectMenu(menu.key)"
|
@click="selectMenu(menu.key)"
|
||||||
>
|
>
|
||||||
<van-icon :name="menu.icon" class="menu-icon-left" />
|
|
||||||
<span class="menu-title">{{ menu.title }}</span>
|
<van-icon :name="menu.icon" class="menu-icon-left" >
|
||||||
|
|
||||||
|
</van-icon>
|
||||||
|
|
||||||
|
|
||||||
|
<span class="menu-title">{{ menu.title }} <van-badge :content="menu.count" class="menu-badge" v-if="menu.count > 0" /></span>
|
||||||
<van-icon name="arrow" class="menu-arrow" />
|
<van-icon name="arrow" class="menu-arrow" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -62,36 +67,42 @@ import { ref, computed, onMounted } from 'vue'
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
import { showConfirmDialog, showSuccessToast, showFailToast } from 'vant'
|
import { showConfirmDialog, showSuccessToast, showFailToast } from 'vant'
|
||||||
import { useAuthStore } from '@/store/auth'
|
import { useAuthStore } from '@/store/auth'
|
||||||
|
import { useTodoStore } from '@/store/todo'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
import OrderList from '@/views/List/index.vue'
|
import OrderList from '@/views/List/index.vue'
|
||||||
import PurchaseList from '@/views/Purchase/index.vue'
|
import PurchaseList from '@/views/Purchase/index.vue'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
|
const todoStore = useTodoStore()
|
||||||
|
const { statistics } = storeToRefs(todoStore)
|
||||||
|
|
||||||
// 抽屉显示状态
|
// 抽屉显示状态
|
||||||
const showDrawer = ref(false)
|
const showDrawer = ref(true)
|
||||||
|
|
||||||
// 当前选中的菜单
|
// 当前选中的菜单
|
||||||
const currentMenu = ref('order')
|
const currentMenu = ref('order')
|
||||||
|
|
||||||
// 菜单列表
|
// 菜单列表
|
||||||
const menuList = [
|
const menuList = computed(() => [
|
||||||
{
|
{
|
||||||
key: 'order',
|
key: 'order',
|
||||||
title: '订单审批',
|
title: '订单审批',
|
||||||
icon: 'notes-o'
|
icon: 'notes-o',
|
||||||
|
count: statistics.value?.order_approve || 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'purchase',
|
key: 'purchase',
|
||||||
title: '采购审批',
|
title: '采购审批',
|
||||||
icon: 'shopping-cart-o'
|
icon: 'shopping-cart-o',
|
||||||
|
count: statistics.value?.purchase_order_online || 0
|
||||||
}
|
}
|
||||||
]
|
])
|
||||||
|
|
||||||
// 当前菜单标题
|
// 当前菜单标题
|
||||||
const currentMenuTitle = computed(() => {
|
const currentMenuTitle = computed(() => {
|
||||||
const menu = menuList.find(m => m.key === currentMenu.value)
|
const menu = menuList.value.find(m => m.key === currentMenu.value)
|
||||||
return menu ? menu.title : '审批'
|
return menu ? menu.title : '审批'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -103,6 +114,7 @@ const selectMenu = (key: string) => {
|
||||||
|
|
||||||
// 初始化菜单
|
// 初始化菜单
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
todoStore.fetchTodoStatistics()
|
||||||
const tab = route.query.tab as string
|
const tab = route.query.tab as string
|
||||||
if (tab && ['order', 'purchase'].includes(tab)) {
|
if (tab && ['order', 'purchase'].includes(tab)) {
|
||||||
currentMenu.value = tab
|
currentMenu.value = tab
|
||||||
|
|
@ -287,6 +299,10 @@ const handleLogout = async () => {
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menu-badge {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.menu-arrow {
|
.menu-arrow {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: #999999;
|
color: #999999;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue