From 5b23e48e2c1f4da93d478f0b9d8fdb565f19b9c0 Mon Sep 17 00:00:00 2001
From: zhouyanli <593579392@qq.com>
Date: Fri, 7 Aug 2026 16:36:05 +0800
Subject: [PATCH] =?UTF-8?q?=E6=94=B6=E8=B4=B9=E6=80=BB=E8=A7=88=E9=A1=B5?=
=?UTF-8?q?=E9=9D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
wuye-manager-uniapp/App.vue | 24 +++++--
wuye-manager-uniapp/api/request.js | 1 +
wuye-manager-uniapp/api/statisticsApi.js | 8 +++
wuye-manager-uniapp/manifest.json | 2 +-
.../pageSubPack/setting/setting.vue | 6 +-
.../statistics/components/DepositCard.vue | 40 +++++++----
.../pageSubPack/statistics/statistics.vue | 71 +++++++++++++------
wuye-manager-uniapp/pages.json | 3 +-
wuye-manager-uniapp/pages/index/index.vue | 47 +++++++++---
wuye-manager-uniapp/pages/my/my.vue | 6 +-
.../qiun-data-charts/qiun-data-charts.vue | 4 +-
.../js_sdk/u-charts/u-charts.js | 12 +++-
12 files changed, 163 insertions(+), 61 deletions(-)
diff --git a/wuye-manager-uniapp/App.vue b/wuye-manager-uniapp/App.vue
index 29a0351..89f7bc6 100644
--- a/wuye-manager-uniapp/App.vue
+++ b/wuye-manager-uniapp/App.vue
@@ -4,6 +4,7 @@ import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'
let pushCIDRetryCount = 0
const MAX_RETRY = 5
let retryTimer = null
+let pushCIDFetching = false // 防止并发请求
// 应用启动时执行
onLaunch(() => {
@@ -13,27 +14,32 @@ onLaunch(() => {
})
// #ifdef APP-PLUS
- // 只有 App 平台才获取 CID,延迟 1 秒等推送服务就绪
+ // 延迟 2 秒等推送服务完全就绪后再获取 CID
setTimeout(() => {
getPushCID()
- }, 1000)
+ }, 2000)
// #endif
})
onShow(() => {
console.log('App Show')
// #ifdef APP-PLUS
- // 每次回到前台都重新获取 CID,防止 CID 过期失效
+ // 从后台恢复时,如果 CID 已经获取过且未过期,不再重复请求
+ const existingCid = uni.getStorageSync('push_cid')
+ if (existingCid) {
+ console.log('已有缓存 CID,跳过重复获取')
+ return
+ }
pushCIDRetryCount = 0
setTimeout(() => {
refreshPushCID()
- }, 500)
+ }, 1000)
// #endif
})
onHide(() => {
console.log('App Hide')
- // 清除重试定时器,避免后台无效重试
+ pushCIDFetching = false
if (retryTimer) {
clearTimeout(retryTimer)
retryTimer = null
@@ -43,9 +49,12 @@ onHide(() => {
// 刷新 CID(每次 onShow 调用,比对更新)
function refreshPushCID() {
+ if (pushCIDFetching) return
const oldCid = uni.getStorageSync('push_cid') || ''
+ pushCIDFetching = true
uni.getPushClientId({
success: res => {
+ pushCIDFetching = false
const newCid = res.cid
if (!newCid) {
console.warn('获取到的 CID 为空,视为失败')
@@ -62,6 +71,7 @@ function refreshPushCID() {
}
},
fail: err => {
+ pushCIDFetching = false
console.error('获取推送 CID 失败', err)
scheduleRetry()
}
@@ -70,8 +80,11 @@ function refreshPushCID() {
// 启动时首次获取 CID(重试更积极)
function getPushCID() {
+ if (pushCIDFetching) return
+ pushCIDFetching = true
uni.getPushClientId({
success: res => {
+ pushCIDFetching = false
const cid = res.cid
if (!cid) {
console.warn('获取到的 CID 为空,视为失败')
@@ -84,6 +97,7 @@ function getPushCID() {
// TODO: 将 CID 上报到服务器
},
fail: err => {
+ pushCIDFetching = false
console.error('获取推送 CID 失败', err)
scheduleRetry()
}
diff --git a/wuye-manager-uniapp/api/request.js b/wuye-manager-uniapp/api/request.js
index d7c70eb..c142941 100644
--- a/wuye-manager-uniapp/api/request.js
+++ b/wuye-manager-uniapp/api/request.js
@@ -11,6 +11,7 @@ export default function request(url, data = {}, method = 'GET') {
url: baseUrl + url,
data: data,
method: method,
+ timeout: 15000,
header: {
Authorization: 'Bearer ' + (uni.getStorageSync('token') || ''),
clientid: 'butler',
diff --git a/wuye-manager-uniapp/api/statisticsApi.js b/wuye-manager-uniapp/api/statisticsApi.js
index ebced34..daad328 100644
--- a/wuye-manager-uniapp/api/statisticsApi.js
+++ b/wuye-manager-uniapp/api/statisticsApi.js
@@ -24,3 +24,11 @@ export const getFeeSummary = data => {
export const getParkingFee = data => {
return get('/api/butler/feeOverview/parking', data)
}
+// 押金余额统计
+export const getDepositBalance = data => {
+ return get('/api/butler/feeOverview/depositBalance', data)
+}
+// 巡检总览
+export const getInspection = data => {
+ return get('/api/butler/feeOverview/inspection', data)
+}
diff --git a/wuye-manager-uniapp/manifest.json b/wuye-manager-uniapp/manifest.json
index 8c5c1fa..1e0e92d 100644
--- a/wuye-manager-uniapp/manifest.json
+++ b/wuye-manager-uniapp/manifest.json
@@ -10,7 +10,7 @@
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
- "alwaysShowBeforeRender" : true,
+ "alwaysShowBeforeRender" : false,
"waiting" : true,
"autoclose" : true,
"delay" : 0,
diff --git a/wuye-manager-uniapp/pageSubPack/setting/setting.vue b/wuye-manager-uniapp/pageSubPack/setting/setting.vue
index 7326437..4a5be0e 100644
--- a/wuye-manager-uniapp/pageSubPack/setting/setting.vue
+++ b/wuye-manager-uniapp/pageSubPack/setting/setting.vue
@@ -1,14 +1,14 @@
-
+
-
+
diff --git a/wuye-manager-uniapp/pageSubPack/statistics/components/DepositCard.vue b/wuye-manager-uniapp/pageSubPack/statistics/components/DepositCard.vue
index ea70729..7167cde 100644
--- a/wuye-manager-uniapp/pageSubPack/statistics/components/DepositCard.vue
+++ b/wuye-manager-uniapp/pageSubPack/statistics/components/DepositCard.vue
@@ -6,6 +6,9 @@
+
+ 暂无数据
+
@@ -15,16 +18,17 @@ import { computed } from 'vue'
const props = defineProps({
depositBalance: { type: String, default: '0' },
- depositRenovation: { type: Number, default: 0 },
- depositRental: { type: Number, default: 0 }
+ depositItems: { type: Array, default: () => [] }
})
-const depositColumnData = computed(() => ({
- categories: ['装修押金', '租赁押金'],
- series: [
- { name: '余额', data: [props.depositRenovation, props.depositRental] }
- ]
-}))
+const depositColumnData = computed(() => {
+ const categories = props.depositItems.map(item => item.typeName)
+ const data = props.depositItems.map(item => (item.balance / 10000))
+ return {
+ categories,
+ series: [{ name: '余额', data }]
+ }
+})
const depositColumnOpts = computed(() => ({
color: ['#4D5DFA'],
@@ -34,22 +38,24 @@ const depositColumnOpts = computed(() => ({
xAxis: {
disableGrid: true,
axisLineColor: '#EAEAEA',
+ dashLength: 4,
fontColor: '#666',
fontSize: 12
},
yAxis: {
+ showTitle: true,
data: [{
- title: '万元',
+ title: '金额(万)',
min: 0,
- max: 80,
axisLineColor: '#EAEAEA',
fontColor: '#666',
fontSize: 12,
titleFontSize: 12,
titleFontColor: '#666'
}],
- splitLine: { show: true, lineStyle: { color: '#F2F2F2' } },
- calibration: { step: 0.5 }
+ gridType: 'dash',
+ dashLength: 4,
+ gridColor: '#F2F2F2',
},
extra: {
column: {
@@ -88,6 +94,16 @@ const depositColumnOpts = computed(() => ({
.deposit-chart {
width: 100%;
height: 420rpx;
+ position: relative;
+ .deposit-empty-mask {
+ position: absolute;
+ top: 0; left: 0; right: 0; bottom: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: #fff;
+ .empty-text { font-size: 26rpx; color: #999; }
+ }
}
}
diff --git a/wuye-manager-uniapp/pageSubPack/statistics/statistics.vue b/wuye-manager-uniapp/pageSubPack/statistics/statistics.vue
index 0336d13..7f44688 100644
--- a/wuye-manager-uniapp/pageSubPack/statistics/statistics.vue
+++ b/wuye-manager-uniapp/pageSubPack/statistics/statistics.vue
@@ -58,8 +58,7 @@
@@ -77,7 +76,7 @@ import FeeOverviewCard from './components/FeeOverviewCard.vue'
import ParkingFeeCard from './components/ParkingFeeCard.vue'
import DepositCard from './components/DepositCard.vue'
import InspectionOverview from './components/InspectionOverview.vue'
-import { getManagedArea, getRate, getFeeSummary, getParkingFee } from '@/api/statisticsApi.js'
+import { getManagedArea, getRate, getFeeSummary, getParkingFee, getDepositBalance, getInspection } from '@/api/statisticsApi.js'
@@ -109,16 +108,15 @@ const parkingYearReceived = ref(0)
const parkingArcbarPercent = ref(0)
// 押金余额统计
-const depositBalance = ref('33322')
-const depositRenovation = ref(18)
-const depositRental = ref(23)
+const depositBalance = ref('0')
+const depositItems = ref([])
// 巡检总览
const inspectionList = ref([
- { label: '巡检任务', value: 124, icon: 'https://wuye.ckdzkj.com/images/imgs/inspection-task.png' },
- { label: '已完成', value: 98, icon: 'https://wuye.ckdzkj.com/images/imgs/inspection-done.png' },
- { label: '已过期', value: 12, icon: 'https://wuye.ckdzkj.com/images/imgs/inspection-expire.png' },
- { label: '待处理', value: 14, icon: 'https://wuye.ckdzkj.com/images/imgs/inspection-pending.png' }
+ { label: '巡检任务', value: 0, icon: 'https://wuye.ckdzkj.com/images/imgs/inspection-task.png' },
+ { label: '已完成', value: 0, icon: 'https://wuye.ckdzkj.com/images/imgs/inspection-done.png' },
+ { label: '已过期', value: 0, icon: 'https://wuye.ckdzkj.com/images/imgs/inspection-expire.png' },
+ { label: '待处理', value: 0, icon: 'https://wuye.ckdzkj.com/images/imgs/inspection-pending.png' }
])
const switchTab = (tab) => {
@@ -134,6 +132,8 @@ const onProjectChange = (e) => {
fetchRate(opt.value)
fetchFeeSummary()
fetchParkingFee(opt.value)
+ fetchDepositBalance(opt.value)
+ fetchInspection(opt.value)
}
const onFeeTypeChange = (opt) => {
@@ -169,19 +169,20 @@ const fetchRate = (villageId) => {
}
}).catch(() => {})
}
-
+// 车位收费总览
const fetchParkingFee = (villageId) => {
getParkingFee({ villageId: villageId || '' }).then(res => {
if (res.code === 200 && res.data) {
const d = res.data
- parkingCount.value = d.parkingCount || 0
- parkingYearReceivable.value = d.receivableAmount || 0
- parkingYearReceived.value = d.receivedAmount || 0
- parkingArcbarPercent.value = d.receivedPercent != null ? d.receivedPercent / 100 : 0
+ parkingCount.value = Number(d.parkingCount) || 0
+ parkingYearReceivable.value = Number(d.receivableAmount) || 0
+ parkingYearReceived.value = Number(d.receivedAmount) || 0
+ parkingArcbarPercent.value = d.receivedPercent != null ? Number(d.receivedPercent) / 100 : 0
}
}).catch(() => {})
}
+// 收费总览
const fetchFeeSummary = () => {
getFeeSummary({
villageId: selectedProject.value || '',
@@ -190,19 +191,21 @@ const fetchFeeSummary = () => {
}).then(res => {
if (res.code === 200 && res.data) {
const d = res.data
- arcbarPercent.value = d.receivedPercent != null ? d.receivedPercent / 100 : 0
+ arcbarPercent.value = Number(d.receivedPercent) || 0
metricList.value = [
- { label: '应收总额', value: d.receivableAmount != null ? d.receivableAmount.toFixed(2) : '0.00', yoy: formatRate(d.receivableYoyRate), mom: formatRate(d.receivableMomRate) },
- { label: '实收总额', value: d.receivedAmount != null ? d.receivedAmount.toFixed(2) : '0.00', yoy: formatRate(d.receivedYoyRate), mom: formatRate(d.receivedMomRate) },
- { label: '欠收总额', value: d.unpaidAmount != null ? d.unpaidAmount.toFixed(2) : '0.00', yoy: formatRate(d.unpaidYoyRate), mom: formatRate(d.unpaidMomRate) }
+ { label: '应收总额', value: (Number(d.receivableAmount) || 0).toFixed(2), yoy: formatRate(d.receivableYoyRate), mom: formatRate(d.receivableMomRate) },
+ { label: '实收总额', value: (Number(d.receivedAmount) || 0).toFixed(2), yoy: formatRate(d.receivedYoyRate), mom: formatRate(d.receivedMomRate) },
+ { label: '欠收总额', value: (Number(d.unpaidAmount) || 0).toFixed(2), yoy: formatRate(d.unpaidYoyRate), mom: formatRate(d.unpaidMomRate) }
]
}
}).catch(() => {})
}
const formatRate = (val) => {
- if (val == null) return '-'
- return (val >= 0 ? '+' : '') + val.toFixed(2) + '%'
+ if (val == null || val === '') return '-'
+ const num = Number(val)
+ if (isNaN(num)) return '-'
+ return (num >= 0 ? '+' : '') + num.toFixed(2) + '%'
}
const fetchFeeTypes = () => {
@@ -214,6 +217,30 @@ const fetchFeeTypes = () => {
}
}).catch(() => {})
}
+// 押金余额统计
+const fetchDepositBalance = (villageId) => {
+ getDepositBalance({ villageId: villageId}).then(res => {
+ if (res.code === 200 && res.data) {
+ const d = res.data
+ depositBalance.value = d.totalBalance
+ depositItems.value = d.items || []
+ }
+ }).catch(() => {})
+}
+// 巡检总览
+const fetchInspection = (villageId) => {
+ getInspection({ villageId: villageId || '' }).then(res => {
+ if (res.code === 200 && res.data) {
+ const d = res.data
+ inspectionList.value = [
+ { label: '巡检任务', value: d.taskCount || 0, icon: 'https://wuye.ckdzkj.com/images/imgs/inspection-task.png' },
+ { label: '已完成', value: d.completedCount || 0, icon: 'https://wuye.ckdzkj.com/images/imgs/inspection-done.png' },
+ { label: '已过期', value: d.expiredCount || 0, icon: 'https://wuye.ckdzkj.com/images/imgs/inspection-expire.png' },
+ { label: '待处理', value: d.pendingCount || 0, icon: 'https://wuye.ckdzkj.com/images/imgs/inspection-pending.png' }
+ ]
+ }
+ }).catch(() => {})
+}
onShow(() => {
Promise.all([fetchVillageList(), fetchFeeTypes()]).then(() => {
@@ -221,6 +248,8 @@ onShow(() => {
fetchRate(selectedProject.value)
fetchFeeSummary()
fetchParkingFee(selectedProject.value)
+ fetchDepositBalance(selectedProject.value)
+ fetchInspection(selectedProject.value)
})
})
diff --git a/wuye-manager-uniapp/pages.json b/wuye-manager-uniapp/pages.json
index 2544162..6a261c0 100644
--- a/wuye-manager-uniapp/pages.json
+++ b/wuye-manager-uniapp/pages.json
@@ -262,8 +262,7 @@
"pages": [{
"path": "setting",
"style": {
- "navigationBarTitleText": "设置",
- "navigationStyle": "custom"
+ "navigationBarTitleText": "设置"
}
},
{
diff --git a/wuye-manager-uniapp/pages/index/index.vue b/wuye-manager-uniapp/pages/index/index.vue
index aed6cb8..3b9c44b 100644
--- a/wuye-manager-uniapp/pages/index/index.vue
+++ b/wuye-manager-uniapp/pages/index/index.vue
@@ -136,6 +136,13 @@ import { usePermStore } from '@/stores/usePermStore'
const permStore = usePermStore()
+// 首次加载标记:onLoad 和 onShow 在首次进入时都会触发,用此标记避免重复请求
+const hasInit = ref(false)
+
+// banner 缓存 key 和缓存时长(30分钟)
+const BANNER_CACHE_KEY = 'home_banner_cache'
+const BANNER_CACHE_TIME = 30 * 60 * 1000
+
// 列表数据状态
const currentCommunity = ref('请先绑定房屋')
const bannerList = ref([])
@@ -342,17 +349,34 @@ const getNoticeData = () => {
})
.catch(() => {})
}
-// 获取bannar图
-function getbannarData() {
+// 获取bannar图(带缓存:30分钟内优先用缓存,请求成功后更新缓存)
+function getbannarData(forceRefresh = false) {
+ // 非强制刷新时,优先读缓存
+ if (!forceRefresh) {
+ try {
+ const cached = uni.getStorageSync(BANNER_CACHE_KEY)
+ if (cached) {
+ const { data, time } = JSON.parse(cached)
+ if (data && data.length > 0 && Date.now() - time < BANNER_CACHE_TIME) {
+ bannerList.value = data
+ return // 缓存有效,不发起请求
+ }
+ }
+ } catch (e) {}
+ }
getBannarList()
.then(res => {
if (res.code === 200 && res.data) {
- // 只有数据真正变化时才更新,避免 swiper 重新渲染导致闪动
const newData = res.data
const oldData = bannerList.value
if (JSON.stringify(newData) !== JSON.stringify(oldData)) {
bannerList.value = newData
}
+ // 写入缓存
+ uni.setStorageSync(BANNER_CACHE_KEY, JSON.stringify({
+ data: newData,
+ time: Date.now()
+ }))
} else {
bannerList.value = []
}
@@ -386,21 +410,26 @@ const slelctHomeData = data => {
getInspectionData()
}
-const permissionlist = ref([])
onShow(() => {
+ if (!hasInit.value) {
+ // 首次加载:onLoad 已触发过核心数据请求,这里只补 onLoad 没调的和需要每次都刷新的
+ hasInit.value = true
+ getbannarData() // onLoad 没调 banner
+ getMyOrderNum() // onLoad 没调工单数
+ permStore.initPerm() // 刷新权限缓存
+ // currentVillageData 和 getInspectionData 已在 onLoad 中调用,不再重复
+ return
+ }
+ // 从其他页面返回 / 从后台恢复:只刷新可能变化的数据
getbannarData()
- getInspectionData()
- currentVillageData()
getMyOrderNum()
- permStore.initPerm()
+ // 小区和巡检数据不频繁变化,从后台恢复时用缓存/旧数据,减少请求
})
onLoad(() => {
uni.$on('confirm', slelctHomeData)
- // 优先调用接口获取当前小区,失败时再读缓存
currentVillageData()
getInspectionData()
- // getbannarData()
})
onUnload(() => {
diff --git a/wuye-manager-uniapp/pages/my/my.vue b/wuye-manager-uniapp/pages/my/my.vue
index a21f4e9..e661c53 100644
--- a/wuye-manager-uniapp/pages/my/my.vue
+++ b/wuye-manager-uniapp/pages/my/my.vue
@@ -76,11 +76,7 @@ const onItemClick = item => {
}
const url = routes[item.title]
if (!url) return
- if (item.title === '设置') {
- uni.redirectTo({ url })
- } else {
- uni.navigateTo({ url })
- }
+ uni.navigateTo({ url })
}
diff --git a/wuye-manager-uniapp/uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue b/wuye-manager-uniapp/uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue
index 5678f7d..f15eaac 100644
--- a/wuye-manager-uniapp/uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue
+++ b/wuye-manager-uniapp/uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue
@@ -869,7 +869,9 @@ export default {
const ctx = cfu.option[cid].context;
if(typeof ctx === "object" && !!!cfu.option[cid].update){
ctx.clearRect(0, 0, this.cWidth*this.pixel, this.cHeight*this.pixel);
- ctx.draw();
+ if (typeof ctx.draw === 'function') {
+ ctx.draw();
+ }
}
}
},
diff --git a/wuye-manager-uniapp/uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.js b/wuye-manager-uniapp/uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.js
index f78bde5..e903442 100644
--- a/wuye-manager-uniapp/uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.js
+++ b/wuye-manager-uniapp/uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.js
@@ -4643,9 +4643,13 @@ function drawXAxis(categories, opts, config, context) {
context.beginPath();
context.setStrokeStyle(opts.xAxis.axisLineColor);
context.setLineWidth(1 * opts.pix);
+ if (opts.xAxis.dashLength) {
+ context.setLineDash([opts.xAxis.dashLength * opts.pix, opts.xAxis.dashLength * opts.pix]);
+ }
context.moveTo(startX, opts.height - opts.area[2]);
context.lineTo(endX, opts.height - opts.area[2]);
context.stroke();
+ context.setLineDash([]);
}
}
@@ -5834,7 +5838,9 @@ function drawMapDataPoints(series, opts, config, context) {
mercator: mapOption.mercator
}
drawToolTipBridge(opts, config, context, 1);
- context.draw();
+ if (typeof context.draw === 'function') {
+ context.draw();
+ }
}
function normalInt(min, max, iter) {
@@ -6305,7 +6311,9 @@ function drawCanvas(opts, context) {
context.save();
context.translate(0, 0.5);
context.restore();
- context.draw();
+ if (typeof context.draw === 'function') {
+ context.draw();
+ }
}
var Timing = {