Files
ys-app/src/pages/home/home.vue
2025-08-04 16:19:03 +08:00

442 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="con-body">
<view class="con-bg">
<!-- 下拉刷新 -->
<mescroll-uni ref="mescrollRef" @init="mescrollInit"
:down="downOption" @down="downCallback"
:fixed="false" class="scroll-h" :style="{ paddingTop: navBarPaddingTop + 'px' }"
>
<!-- #ifdef H5 -->
<view style="height:50rpx"></view>
<!-- #endif -->
<!-- 搜索 @confirm="handleSearch" -->
<view class="search search-sao" >
<uni-search-bar class="custom-search" radius="28"
placeholder="请输入您想查询的内容或服务"
clearButton="auto" cancelButton="none"
bgColor="#6FA2F8" textColor="#ffffff"
@focus="handleFocus"
/>
<uni-icons custom-prefix="iconfont" color="#ffffff" type="icon-phonesaoyisao" size="20"></uni-icons>
</view>
<!-- 待办内容 -->
<view class="backlog-bg">
<view class="backlog-b-item">
<view class="font-number">{{ backBlogObj.count1 }}</view>
<view class="font-title">待办</view>
</view>
<view class="backlog-b-item">
<view class="font-number">{{ backBlogObj.count2 }}</view>
<view class="font-title">待审查</view>
</view>
<view class="backlog-b-item">
<view class="font-number">{{ backBlogObj.count3 }}</view>
<view class="font-title">待巡检</view>
</view>
<view class="backlog-b-item">
<view class="font-number">{{ backBlogObj.count4 }}</view>
<view class="font-title">待发货</view>
</view>
</view>
<!-- 跑马灯滚动 -->
<view class="notice-bg">
<img :src="'static/images/icon-notice@2x.png'" class="notice-icon" />
<view class="notice-list">
<!-- :interval="4000" -->
<swiper class="swiper-con"
:vertical="true"
:autoplay="true"
:duration="500"
:circular="true"
:disable-touch="true"
:display-multiple-items="1"
>
<swiper-item v-for="(item, index) in extendedList" :key="index" >
<view class="swiper-item">
{{ item }}
</view>
</swiper-item>
</swiper>
</view>
</view>
<!-- 日程提醒 -->
<view class="white-bg mar-top" v-if="stepList.length>0">
<view class="w-b-title">日程提醒
<view class="yellow-bg">
<i :class="{iconfont:true,'icon-phoneshizhong':true}"></i>
<view class="text-black">{{ weekStr }}</view>
</view>
</view>
<view class="section-line">
<customSteps :steps="stepList" :modelValue="stepList"></customSteps>
</view>
</view>
<!-- 销售任务完成情况 -->
<view class="white-bg mar-top">
<view class="w-b-title">销售任务完成情况
<view class="yellow-bg">
<picker @change="bindPickerChange" :value="activeIndex" :range="salesList" @click="clickPicker" @cancel="bindPickerCancel">
<view class="uni-input">{{salesList[activeIndex]}}</view>
</picker>
<i :class="{iconfont:true,'icon-down':salesFlag,'icon-up':!salesFlag}" class="picker-icon"></i>
</view>
</view>
<view class="progress-bg">
<progress :percent="percentNum" stroke-width="10" activeColor="#41E1B1" backgroundColor="#F0F0F0" />
<view class="percent" :style="{left:percentNum+'%'}">
<view class="percent-num">{{ percentNum }}%</view>
<i class="iconfont icon-down"></i>
</view>
<view class="percent-con">
<view class="p-first">
<view>实际销售额</view>
<view class="font-money">{{totalSales}}</view>
</view>
<view class="p-last">
<view>目标销售额</view>
<view class="font-money">{{ targetSales }}</view>
</view>
</view>
</view>
</view>
<!-- 常用服务 -->
<view class="white-bg">
<view class="w-b-title">常用服务</view>
<view class="logo-list">
<view v-for="(item,index) in commonServiceList" class="l-l-item" :key="index">
<img :src="item.imgSrc" />
<text class="font-gray">{{ item.name }}</text>
</view>
<!-- <view class="l-l-item" @click="handleAddCommonSercice">
<img :src="'static/images/business/icon-add.png'">
<text class="font-gray">添加</text>
</view> -->
</view>
</view>
<!-- 新闻公告 -->
<view class="white-bg">
<view class="w-b-title">新闻公告
<text>更多新闻</text>
</view>
<view class="news-list">
<view v-for="(item,index) in newsList" class="news-item" :key="index">
<view class="n-i-title">{{ item.name }}
<view class="n-i-date">{{ formatDateStr(item.date) }}</view>
</view>
<img :src="item.imgSrc" v-if="item.imgSrc" />
</view>
</view>
</view>
<!-- 底部加高度来避免tabbar遮挡 -->
<view class="bottom-height"></view>
</mescroll-uni>
</view>
</view>
</template>
<script setup>
import { ref,onMounted,computed } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import MescrollUni from 'mescroll-uni/mescroll-uni.vue';
import customSteps from '@/components/customSteps.vue'
import { getNavBarPaddingTop} from '@/utils/system.js'
import { backBlogCount,swiperList,stepData,salesTask,commonServices,newsQueryList } from '@/api/home.js';
import { getWeekStr,formatTimestamp } from '@/utils/datetime.js'
import { formatMoney } from '@/utils/formatter.js'
onLoad(async(opt) => {
uni.setStorageSync('page_cache',true);
})
// 下拉刷新
const mescrollRef = ref(null);
const mescrollInit = (mescroll) => {
mescrollRef.value = mescroll;
};
const downOption = ref({
auto: true,
textInOffset: '下拉刷新',
textOutOffset: '释放更新',
textLoading: '刷新中...'
});
// 下拉刷新
const downCallback = async (mescroll) => {
try {
setTimeout(async ()=>{
// mescroll.resetUpScroll();
},500);
} catch (error) {
mescroll.endErr();
} finally {
setTimeout(async ()=>{
mescroll.endSuccess();
},500);
}
}
// 获取导航栏高度用于内容区域padding
const navBarPaddingTop = ref(0);
onMounted(() => {
navBarPaddingTop.value = getNavBarPaddingTop()*2;
})
// 获取input 焦点跳转
let handleFocus=()=>{
uni.navigateTo({url:'/pages/search/search?type=1'})
}
// 查询搜索跳转
let handleSearch = ()=>{
}
// tabar 增加消息数量
try {
wx.setTabBarBadge({
index: 2, // TabBar的索引从0开始计数
text: '3' // 徽章的文本
});
} catch (error) {
console.error('设置TabBar Badge失败:', error);
}
let backBlogObj = ref({})
// 获取待办数据
let getBackBlogCount = async () =>{
backBlogObj.value = await backBlogCount();
}
getBackBlogCount();
// 跑马灯处理
let extendedList = ref([]);// ;
const getSwiperList = async () => {
extendedList.value = await swiperList();
}
getSwiperList();
// 日程提醒
let weekStr = ref(null) //'2025-09-19 星期三'
let stepList = ref([]);
const getStepData = async ()=>{
let res = await stepData({});
weekStr.value = getWeekStr(res.date);
stepList.value = res.list;
}
getStepData();
// 销售任务完成情况
let salesList = ref([]);
let salesFlag = ref(true);
let activeIndex = ref(0);
const bindPickerChange = (e)=>{
// console.log('picker发送选择改变携带值为', e.detail.value)
activeIndex.value = e.detail.value;
salesFlag.value = true;
}
const bindPickerCancel= (e)=>{
salesFlag.value = true;
}
const clickPicker= (e)=>{
salesFlag.value = false;
}
let percentNum = ref(0);
let totalSales = ref(0)
let targetSales = ref(0)
const getSalesTask = async ()=>{
let res = await salesTask({});
salesList.value = res.salesList;
percentNum.value = res.percentNum;
totalSales.value = formatMoney(res.totalSales);
targetSales.value = formatMoney(res.targetSales);
}
getSalesTask();
// 常用服务
let commonServiceList = ref([])
const getCommonServices = async ()=>{
let res = await commonServices({});
commonServiceList.value = res.list
}
getCommonServices();
// 添加常用服务
const handleAddCommonSercice = ()=>{
}
// 新闻公告
let newsList = ref([])
const getNewsList = async()=>{
let res = await newsQueryList({});
newsList.value = res.list;
}
getNewsList();
const formatDateStr =(times)=>{
return formatTimestamp(times)
}
</script>
<style scope>
.scroll-h{
/* #ifdef APP-PLUS */
height:calc(100vh - 30px) !important;
/* #endif */
/* #ifndef APP-PLUS */
height: calc(100vh - 30px) !important;
/* #endif */
}
:deep(.mescroll-upwarp){
display:none
}
.search-sao{
display: flex;
padding-top:10rpx;
}
.search-sao .custom-search{
width:612rpx;
}
.search-sao :deep(.custom-search.uni-searchbar){
padding-bottom: 15rpx !important;
}
.search-sao .icon-phonesaoyisao{
margin:15rpx 30rpx 10rpx auto;
}
.backlog-bg{
background:url('@/static/images/bg-main@2x.png') no-repeat;
background-size:730rpx 205rpx;
/* width:730rpx; */
width:690rpx;
height:205rpx;
margin:0 auto;
display: flex;
padding:0 20rpx;
}
.backlog-b-item{
width:25%;
color:#579FF9;
border-right:1px solid #EAEAEA;
height:100rpx;
margin-top:40rpx;
}
.backlog-b-item .font-number{
font-size: 60rpx;
font-weight: bold;
text-align: center;
}
.backlog-b-item .font-title{
font-size:28rpx;
text-align: center;
}
.notice-bg{
background:url('@/static/images/bg-notice@2x.png') no-repeat;
background-size:750rpx 90rpx;
width:690rpx;
height: 90rpx;
margin-top:10rpx;
padding:0 30rpx;
display: flex;
align-items: center;
}
.notice-bg .notice-icon{
width:46rpx;
height:40rpx;
}
.notice-list{
width:100%;
position: relative;
height: 90rpx;
overflow: hidden;
}
.notice-list .swiper-con{
width:640rpx;
}
.notice-list .swiper-con .swiper-item {
height: 90rpx;
line-height: 90rpx;
padding: 0 20rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color:#fff;
font-size:30rpx;
}
.progress-bg{
position: relative;
width:528rpx;
margin:120rpx auto 0;
}
.progress-bg :deep(.uni-progress .uni-progress-bar){
border-radius: 5px;
}
.progress-bg :deep(.uni-progress .uni-progress-inner-bar){
border-radius: 5px 0 0 5px;
}
.progress-bg .percent{
position: absolute;
top:0;
color:#FF687A;
font-size:60rpx;
font-weight: bold;
}
.progress-bg .percent .icon-down{
position: absolute;
bottom:0rpx;
left:-20rpx;
color:#FF687A;
font-size:40rpx;
}
.progress-bg .percent .percent-num{
position: absolute;
left:-60rpx;
bottom:30rpx;
}
.progress-bg .percent-con{
display: flex;
width:528rpx;
color:#333;
font-size:28rpx;
margin:20rpx 0 10rpx;
}
.progress-bg .percent-con .p-last{
margin-left: auto;
text-align: right;
}
.progress-bg .percent-con .font-money{
font-weight: bold;
margin-top:10rpx;
}
.white-bg .logo-list{
gap:50rpx;
padding:0 20rpx;
/* margin-bottom: -50rpx; */
}
.white-bg .logo-list .l-l-item{
width:160rpx;
margin-bottom:0rpx;
}
.white-bg .logo-list .l-l-item img{
width:110rpx;
height:110rpx;
}
</style>