Files
pj_mini_app_cloud/src/pages/root/dashboard.vue
T
2026-08-24 17:29:33 +08:00

224 lines
8.1 KiB
Vue

<script setup lang="ts">
import { ref, reactive, computed, nextTick, onMounted } from "vue"
import { onHide, onShow } from "@dcloudio/uni-app"
import { router } from "@@/index"
import { noticeApi, appApi } from "@@/api/index"
import { getAppInfo } from "@@/utils/app"
import { SERVICE_IMAGE } from "@@/constant/index"
import { filePath } from "@@/utils/file"
import { useTabbarStore } from "@@/stores/tabbar"
import { ceheckLogin } from "@@/utils/app"
import Empty from "@@/components/empty/empty.vue"
const tabbarStore = useTabbarStore()
const crudLayoutRef = ref()
const state = reactive<any>({
swiperList: [
{
image: "/static/swiper/swiper-1.png"
}
],
noticeList: [],
appMenuList: [],
})
const groupSize = 3
const noticeListSafe = computed(() => (Array.isArray(state.noticeList) ? state.noticeList : []).filter(Boolean))
const appMenuListSafe = computed(() => (Array.isArray(state.appMenuList) ? state.appMenuList : []).filter(Boolean))
const shouldScroll = computed(() => noticeListSafe.value.length > groupSize)
const groupedNoticeList = computed(() => {
const base = noticeListSafe.value
if (!base || base.length === 0) return []
if (base.length <= groupSize) return [base]
const groups: any[] = []
for (let i = 0; i < base.length; i += groupSize) {
const group = base.slice(i, i + groupSize)
if (group.length < groupSize) {
group.push(...base.slice(0, groupSize - group.length))
}
groups.push(group)
}
return groups
})
onShow(() => {
if (!ceheckLogin()) {
uni.showToast({ title: "登录已过期,请重新登录", icon: "none" })
uni.navigateTo({ url: "/pages/root/login" })
return
}
getSwiperList()
getNoticeList()
getAppMenuList()
})
onMounted(() => {
nextTick(() => {
crudLayoutRef.value?.checkVerifyDevice?.()
})
})
onHide(() => {
})
const doMenu = async (v: any) => {
if (!v) return
if (v.page.includes("thirdApp")) {
router.jump("/pages/third-app/happyMall")
return
}
// 是否是具体页面
const routePath = v.page.split("?")[0]
if (v.page.startsWith("/") && __ROUTES__.some((route) => route.path === routePath)) {
// 直接页面入口也要先组装所属业务 Tabbar,再进入目标页面。
await tabbarStore.componetTabbarList(v.page)
router.jump(v.page)
return
}
await tabbarStore.componetTabbarList(v.page)
tabbarStore.jumpFirstTabbar()
}
// 获取轮播图
const getSwiperList = async () => {
try {
const { data, code }: any = await noticeApi.getSwiperList()
console.log("获取轮播图,code:", code);
if (code != 0) {
throw new Error()
}
state.swiperList = (data || []).filter(Boolean)
} catch (error) {
console.log("获取轮播图意外的错误error:", error);
}
}
// 获取通知公告列表
const getNoticeList = async () => {
try {
const { data, code }: any = await noticeApi.getNoticePage({
current: 1,
size: 9
})
console.log("获取通知公告列表,code:", code);
if (code != 0) {
throw new Error()
}
state.noticeList = (data?.records || []).filter(Boolean)
} catch (error) {
console.log("获取通知公告列表意外的错误error:", error);
}
}
// 获取应用菜单列表
const getAppMenuList = async () => {
const platform = await getAppInfo()
try {
const params = {
typeEnum: "DASHBOARD_TAB",
platformEnum: platform
}
const { data, code }: any = await appApi.appList(params)
console.log("获取应用菜单列表,code:", code);
if (code == 424) {
} else if (code != 0) {
throw new Error()
}
state.appMenuList = (data || []).filter(Boolean)
} catch (error) {
console.log("获取应用菜单列表意外的错误error:", error);
}
}
const doSwiper = async (v: any) => {
if (!v) return
const target = (v.jumpValue || "").replace(/\s+/g, "")
uni.navigateTo({ url: target })
}
</script>
<template>
<crud-layout title="智慧后勤系统" mainIsScroll :bg="filePath(SERVICE_IMAGE.blueBg)" ref="crudLayoutRef">
<view class="h-20rpx" />
<swiper class="w-full h-280rpx rounded-16rpx overflow-hidden" circular :indicator-dots="true"
indicator-active-color="#0779FD" indicator-color="#ffffff" :autoplay="true">
<swiper-item v-for="(v, i) in state?.swiperList" :key="v.id" @tap="doSwiper(v)">
<image class="w-full h-full" :src="v.imageUrl" mode="aspectFill" />
</swiper-item>
</swiper>
<view class="h-20rpx" />
<view class="relative shadow-main min-h-350rpx rounded-16rpx bg-white">
<view
class="container-title font-size-28rpx absolute top-0 left-0 color-white w-200rpx h-50rpx line-height-50rpx text-center rounded-lt-16rpx bg-gradient-to-r from-[#22b0ff] to-[#557bfa]">
通知公告
</view>
<view
class="absolute color-blue right-20rpx font-size-24rpx top-8rpx rounded-full p-x-12rpx p-y-6rpx bg-#f2f6ff"
@tap="() => router.jump('/pages/integrated/notice/index')">
查看更多
</view>
<view class="w-full h-50rpx" />
<view class="h-300rpx overflow-hidden" v-if="noticeListSafe.length > 0">
<swiper class="w-full h-full" :vertical="true" :circular="shouldScroll" :autoplay="shouldScroll"
:interval="2500" :duration="500" :indicator-dots="false" :disable-touch="true">
<swiper-item v-for="(group, i) in groupedNoticeList" :key="i">
<view class="w-full">
<view
class="h-100rpx flex justify-between items-center p-x-16rpx p-y-20rpx border-b-1 border-color-#f0f0f0"
v-for="(v, idx) in group" :key="idx"
@tap="() => router.jump('/pages/integrated/notice/detail', { id: v?.id })">
<view class="flex-1 sub-text-26 font-normal! truncate">{{ v.title }}</view>
<view class="w-250rpx second-text-24 m-l-10rpx">{{ v.createTime }}</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
<view v-else>
<empty text="暂无公告" />
</view>
</view>
<view class="h-20rpx" />
<view class="relative shadow-main min-h-360rpx rounded-16rpx bg-white">
<view
class="container-title font-size-28rpx absolute top-0 left-0 color-white w-200rpx h-50rpx line-height-50rpx text-center rounded-lt-16rpx bg-gradient-to-r from-[#22b0ff] to-[#557bfa]">
常用功能
</view>
<view class="w-full h-50rpx" />
<view v-if="appMenuListSafe.length > 0">
<view class="grid grid-cols-3 h-full items-center gap-y-30rpx p-y-30rpx">
<view class="flex flex-col items-center justify-center" v-for="(v, i) in appMenuListSafe" :key="i"
@tap="doMenu(v)">
<view class="flex-col-center">
<image class="size-100rpx" :src="filePath(v?.icon)" mode="aspectFill" />
<view class="m-t-10rpx sub-text-26">{{ v?.title || "" }}</view>
</view>
</view>
</view>
</view>
<view v-else>
<empty text="暂无App" />
</view>
</view>
<view class="h-80rpx" />
</crud-layout>
</template>
<style lang="scss" scoped>
.container-title::after {
content: '';
position: absolute;
top: 0;
right: -40rpx;
width: 0;
height: 0;
border-style: solid;
border-width: 50rpx 40rpx 0 0;
border-color: #557bfa transparent transparent transparent;
}
</style>