From 298f93380cf30e62072af01ad0a6d5af6957f38f Mon Sep 17 00:00:00 2001 From: Zy <1448159279@qq.com> Date: Fri, 10 Jul 2026 17:44:28 +0800 Subject: [PATCH] =?UTF-8?q?7/10=20=E7=BC=B4=E8=B4=B9=E5=88=86=E6=9E=90?= =?UTF-8?q?=EF=BC=8C=E4=BA=BA=E5=91=98=E5=88=86=E6=9E=90=20=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=AF=B9=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 51 +- .env.production | 45 +- src/api/system/Decoration/type.ts | 3 +- src/api/system/Payment/index.ts | 107 +++++ src/api/system/Personnel/index.ts | 25 +- src/api/system/oss/index.ts | 2 +- src/api/system/resident/type.ts | 2 + src/components/FileUpload/index.vue | 2 +- src/components/Holder/index.vue | 9 +- src/components/Map/GD.vue | 1 - src/layout/components/TagsView/index.vue | 4 +- src/layout/index.vue | 22 +- src/store/modules/house.ts | 4 +- src/types/env.d.ts | 2 +- src/utils/house.ts | 105 ++-- src/utils/request.ts | 4 +- src/views/community/index.vue | 11 +- src/views/system/Decoration/addDecoration.vue | 59 ++- .../system/ParkingCost/addParkingCost.vue | 2 +- src/views/system/Sdb/ChargeItem/add.vue | 2 +- src/views/system/Sdb/ChargeItem/index.vue | 32 +- src/views/system/Sdb/PayRecord/add.vue | 69 +-- src/views/system/Sdb/PayRecord/main.vue | 10 +- src/views/system/Sdb/SdbBill/add.vue | 87 +--- src/views/system/Sdb/SdbBill/main.vue | 27 +- src/views/system/Sdb/SdbCashier/history.vue | 2 +- src/views/system/Sdb/SdbCashier/index.vue | 151 +++++- .../system/Sdb/SdbElectricityDevice/index.vue | 14 +- src/views/system/Sdb/SdbWaterDevice/index.vue | 4 +- src/views/system/Sdb/WaterRecord/index.vue | 2 +- .../system/Sdb/statistics/electricity.vue | 3 +- src/views/system/Visitor/visitorMain.vue | 1 - src/views/system/cars/addCars.vue | 8 +- src/views/system/equipment/Archive/main.vue | 3 +- .../system/houseRental/addhouseResident.vue | 10 +- src/views/system/houseRental/houseMain.vue | 9 +- src/views/system/resident/addResident.vue | 4 +- src/views/system/resident/index.vue | 14 +- src/views/system/role/authUser.vue | 4 +- .../Payment/compontents/RingProgress.vue | 85 ++++ src/views/system/statistics/Payment/index.vue | 453 ++++++++++-------- .../system/statistics/Personnel/index.vue | 245 +++++++--- src/views/system/storeroom/index.vue | 23 +- src/views/system/user/authRole.vue | 4 +- src/views/system/user/index.vue | 8 +- src/views/tool/gen/editTable.vue | 4 +- 46 files changed, 1065 insertions(+), 673 deletions(-) create mode 100644 src/views/system/statistics/Payment/compontents/RingProgress.vue diff --git a/.env.development b/.env.development index 2b221f4..1b230d8 100644 --- a/.env.development +++ b/.env.development @@ -1,65 +1,62 @@ # 页面标题 -VITE_APP_TITLE = 智慧物业后台管理系统 +VITE_APP_TITLE=智慧物业后台管理系统 -VITE_APP_LOGO_TITLE = 智慧物业后台管理系统 +VITE_APP_LOGO_TITLE=智慧物业后台管理系统 # 开发环境配置 -VITE_APP_ENV = 'development' +VITE_APP_ENV='development' # 开发环境 -VITE_APP_BASE_API = '/dev-api' +VITE_APP_BASE_API='/dev-api' # # 开发环境 接口代理地址 -VITE_APP_PROXY_API = 'http://192.168.1.222:8080' +VITE_APP_PROXY_API='http://192.168.1.222:8080' # 开发环境 接口代理地址 -# VITE_APP_PROXY_API = 'http://192.168.0.239:8080' +#VITE_APP_PROXY_API='http://192.168.1.6:8080' # 图片基础地址 -VITE_IMG_URL = 'http://192.168.1.222:8080' +VITE_IMG_URL='http://192.168.1.222:8080' # 应用访问路径 例如使用前缀 /admin/ -VITE_APP_CONTEXT_PATH = '/' +VITE_APP_CONTEXT_PATH='/' # 监控地址 -VITE_APP_MONITOR_ADMIN = 'http://192.168.1.215/admin/applications' - +VITE_APP_MONITOR_ADMIN='http://192.168.1.215/admin/applications' # SnailJob 控制台地址 -VITE_APP_SNAILJOB_ADMIN = 'http://192.168.1.215/snail-job' +VITE_APP_SNAILJOB_ADMIN='http://192.168.1.215/snail-job' -VITE_APP_PORT = 5173 +VITE_APP_PORT=5173 # 登录成功跳转地址 # VITE_LOGIN_BACK_URL = '/equipment/WaterDevice' -VITE_LOGIN_BACK_URL = '/index' +VITE_LOGIN_BACK_URL='/index' # 工作台正式内容:false 假内容:true -VITE_LOGIN_BACK_URL_WORKBENCH_TRUE= false +VITE_LOGIN_BACK_URL_WORKBENCH_TRUE=false # 是否展示工作台 -VITE_APP_SHOW_WORK_PLATFORM = true - +VITE_APP_SHOW_WORK_PLATFORM=true # 地图类型 天地图 WGS84 高德地图 GCJ02, 高德地图 需要在高德地图官网申请key -VITE_APP_MAP_TYPE = 'GCJ02' +VITE_APP_MAP_TYPE='GCJ02' # 高德地图key 建议放入环境变量中,避免泄露 -VITE_GCJ02_KEY_GD = '8e302fe1be5f4db62bc734db23dca149' -VITE_GCJ02_JS_CODE_GD = '09534b3534d8da53968529a9ce164118' +VITE_GCJ02_KEY_GD='8e302fe1be5f4db62bc734db23dca149' +VITE_GCJ02_JS_CODE_GD='09534b3534d8da53968529a9ce164118' # 天地图key 建议放入环境变量中,避免泄露 -VITE_TIANDITU_KEY = 'f71689f9e22158947ebf64ad95e0a595' - +VITE_TIANDITU_KEY='f71689f9e22158947ebf64ad95e0a595' # 接口加密功能开关(如需关闭 后端也必须对应关闭) -VITE_APP_ENCRYPT = true +VITE_APP_ENCRYPT=true # 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换 -VITE_APP_RSA_PUBLIC_KEY = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==' +VITE_APP_RSA_PUBLIC_KEY='MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==' # 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换 -VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=' +VITE_APP_RSA_PRIVATE_KEY='MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=' # 客户端id -VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e' +VITE_APP_CLIENT_ID='e5cd7e4891bf95d1d19206ce24a7b32e' # websocket 开关 默认使用sse推送 -VITE_APP_WEBSOCKET = false +VITE_APP_WEBSOCKET=false # sse 开关 -VITE_APP_SSE = true +VITE_APP_SSE=true diff --git a/.env.production b/.env.production index 9d04805..24f4611 100644 --- a/.env.production +++ b/.env.production @@ -1,61 +1,58 @@ # 页面标题 -VITE_APP_TITLE = 智慧物业后台管理系统 +VITE_APP_TITLE=智慧物业后台管理系统 -VITE_APP_LOGO_TITLE = 智慧物业后台管理系统 +VITE_APP_LOGO_TITLE=智慧物业后台管理系统 # 生产环境配置 -VITE_APP_ENV = 'production' +VITE_APP_ENV='production' # 应用访问路径 例如使用前缀 /admin/ -VITE_APP_CONTEXT_PATH = '/' +VITE_APP_CONTEXT_PATH='/' # 监控地址 -VITE_APP_MONITOR_ADMIN = '/admin/applications' +VITE_APP_MONITOR_ADMIN='/admin/applications' # SnailJob 控制台地址 -VITE_APP_SNAILJOB_ADMIN = '/snail-job' +VITE_APP_SNAILJOB_ADMIN='/snail-job' # 生产环境 # VITE_APP_BASE_API = 'https://wuyeapi.bugtc.com' -VITE_APP_BASE_API = 'https://wuyeapi.ckdzkj.com' +VITE_APP_BASE_API='https://wuyeapi.ckdzkj.com' # 登录成功跳转地址 # VITE_LOGIN_BACK_URL = '/equipment/WaterDevice' -VITE_LOGIN_BACK_URL = '/index' +VITE_LOGIN_BACK_URL='/index' # 工作台正式内容:false 假内容:true -VITE_LOGIN_BACK_URL_WORKBENCH_TRUE= false +VITE_LOGIN_BACK_URL_WORKBENCH_TRUE=false # 是否展示工作台 -VITE_APP_SHOW_WORK_PLATFORM = true - +VITE_APP_SHOW_WORK_PLATFORM=true # 地图类型 天地图 WGS84 高德地图 GCJ02, 高德地图 需要在高德地图官网申请key -VITE_APP_MAP_TYPE = 'GCJ02' +VITE_APP_MAP_TYPE='GCJ02' # 高德地图key 建议放入环境变量中,避免泄露 -VITE_GCJ02_KEY_GD = '8e302fe1be5f4db62bc734db23dca149' -VITE_GCJ02_JS_CODE_GD = '09534b3534d8da53968529a9ce164118' +VITE_GCJ02_KEY_GD='8e302fe1be5f4db62bc734db23dca149' +VITE_GCJ02_JS_CODE_GD='09534b3534d8da53968529a9ce164118' # 天地图key 建议放入环境变量中,避免泄露 -VITE_TIANDITU_KEY = 'f71689f9e22158947ebf64ad95e0a595' - - +VITE_TIANDITU_KEY='f71689f9e22158947ebf64ad95e0a595' # 是否在打包时开启压缩,支持 gzip 和 brotli # VITE_BUILD_COMPRESS = gzip -VITE_APP_PORT = 80 +VITE_APP_PORT=80 # 接口加密功能开关(如需关闭 后端也必须对应关闭) -VITE_APP_ENCRYPT = true +VITE_APP_ENCRYPT=true # 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换 -VITE_APP_RSA_PUBLIC_KEY = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==' +VITE_APP_RSA_PUBLIC_KEY='MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==' # 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换 -VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=' +VITE_APP_RSA_PRIVATE_KEY='MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=' # 客户端id -VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e' +VITE_APP_CLIENT_ID='e5cd7e4891bf95d1d19206ce24a7b32e' # websocket 开关 默认使用sse推送 -VITE_APP_WEBSOCKET = false +VITE_APP_WEBSOCKET=false # sse 开关 -VITE_APP_SSE = true +VITE_APP_SSE=true diff --git a/src/api/system/Decoration/type.ts b/src/api/system/Decoration/type.ts index d4a1a32..3ba2a8f 100644 --- a/src/api/system/Decoration/type.ts +++ b/src/api/system/Decoration/type.ts @@ -13,7 +13,8 @@ export interface DecorationVO { * 所属房屋id */ houseId: string | number; - + buildingId: string; + unitNoId: string; /** * 申请人姓名 */ diff --git a/src/api/system/Payment/index.ts b/src/api/system/Payment/index.ts index a19bd1f..3f54359 100644 --- a/src/api/system/Payment/index.ts +++ b/src/api/system/Payment/index.ts @@ -40,3 +40,110 @@ export const income_statsApi = (datetime?: string): AxiosPromise => { + return request({ + url: '/api/analysis/income/source', + method: 'get', + params: { + date: datetime + } + }); +}; + + +export interface PayMentMethod { + 'wechatAmount': string; + 'wechatPercent': string; + 'alipayAmount': string; + 'alipayPercent': string; + 'offlineAmount': string; + 'offlinePercent': string; +} +// 缴费方式 +export const payment_methodApi = (datetime?: string): AxiosPromise => { + return request({ + url: '/api/analysis/income/payment_method', + method: 'get', + params: { + date: datetime + } + }); +}; + + +export interface Arrears_distrubution { + month: number; + amount: string; +} +// 欠费分布 +export const arrears_distributionApi = ( + datetime?: string +): AxiosPromise<{ + items: Arrears_distrubution[]; +}> => { + return request({ + url: '/api/analysis/income/arrears_distribution', + method: 'get', + params: { + date: datetime + } + }); +}; +export interface payment_sourceType { + 'miniProgramAmount': string; + 'miniProgramPercent': string; + 'mobileAppAmount': string; + 'mobileAppPercent': string; + 'offlineAmount': string; + 'offlinePercent': string; +} +// 缴费来源分析 +export const payment_sourceApi = (datetime?: string): AxiosPromise => { + return request({ + url: '/api/analysis/income/payment_source', + method: 'get', + params: { + date: datetime + } + }); +}; + +export interface payment_trendType { + 'date': string; + 'paidAmount': string; + 'unpaidAmount': string; +} + + +// 缴费走势分析 +export const payment_trendApi = (startDate?: string, endDate?: string): AxiosPromise<{ + items:payment_trendType[] +}> => { + return request({ + url: '/api/analysis/income/payment_trend', + method: 'get', + params: { + startDate, + endDate, + } + }); +}; diff --git a/src/api/system/Personnel/index.ts b/src/api/system/Personnel/index.ts index e269dd9..a3a253f 100644 --- a/src/api/system/Personnel/index.ts +++ b/src/api/system/Personnel/index.ts @@ -8,7 +8,7 @@ import { AxiosPromise } from 'axios'; */ export const user_movein_list = (query?: { - datetime: string; + dateTime: string; }): AxiosPromise<{ 'villageId': string; 'villageName': string; @@ -31,7 +31,7 @@ export const user_movein_list = (query?: { */ export const get_movein_user_type = (query?: { - datetime: string; + dateTime: string; }): Promise<{ 'owner': string; 'ownerRate': string; @@ -56,7 +56,7 @@ export const get_movein_user_type = (query?: { */ export const get_movein_user_sex = (query?: { - datetime: string; + dateTime: string; }): Promise<{ 'man': number; 'woman': number; @@ -92,3 +92,22 @@ export const get_movein_moveout_list = (query?: { params: query }); }; + + + +export const get_person_age = (query?: { + dateTime: string; +}): AxiosPromise< + { + 'date': string; + 'moveInCount': number; + 'moveOutCount': number; + 'totalCount': number; + }[] +> => { + return request({ + url: '/gender/personAge', + method: 'get', + params: query + }); +}; diff --git a/src/api/system/oss/index.ts b/src/api/system/oss/index.ts index 4472112..cc4a58e 100644 --- a/src/api/system/oss/index.ts +++ b/src/api/system/oss/index.ts @@ -12,7 +12,7 @@ export function listOss(query: OssQuery): AxiosPromise { } // 查询OSS对象基于id串 -export function listByIds(ossId: string | number): AxiosPromise { +export function listByIds(ossId: string): AxiosPromise { return request({ url: '/resource/oss/listByIds/' + ossId, method: 'get' diff --git a/src/api/system/resident/type.ts b/src/api/system/resident/type.ts index 007aa0c..99fb471 100644 --- a/src/api/system/resident/type.ts +++ b/src/api/system/resident/type.ts @@ -4,6 +4,7 @@ export interface ResidentVO { */ userId: string; id: string; + unitNoId: string; /** * 住户编号 */ @@ -79,6 +80,7 @@ export interface ResidentForm extends BaseEntity { * 主键 住户管理id */ userId?: string; + unitNoId: string; /** * 住户编号 diff --git a/src/components/FileUpload/index.vue b/src/components/FileUpload/index.vue index b4b946b..46d51e4 100644 --- a/src/components/FileUpload/index.vue +++ b/src/components/FileUpload/index.vue @@ -85,7 +85,7 @@ const fileAccept = computed(() => props.fileType.map((type) => `.${type}`).join( watch( () => props.modelValue, - async (val) => { + async (val:string) => { if (val) { let temp = 1; // 首先将值转为数组 diff --git a/src/components/Holder/index.vue b/src/components/Holder/index.vue index a7adf1f..543e696 100644 --- a/src/components/Holder/index.vue +++ b/src/components/Holder/index.vue @@ -51,7 +51,7 @@ @@ -78,7 +78,6 @@ diff --git a/src/views/system/statistics/Payment/index.vue b/src/views/system/statistics/Payment/index.vue index e7e36d0..83e9bcf 100644 --- a/src/views/system/statistics/Payment/index.vue +++ b/src/views/system/statistics/Payment/index.vue @@ -13,47 +13,42 @@ 查询 重置 -
+
- +
收入来源
-
-
应缴费用:{{ formatMoneyWithUnit(form.totalDue) }}
-
已收:{{ formatMoneyWithUnit(form.totalPaid) }}
-
待收:{{ formatMoneyWithUnit(form.totalUnpaid) }}
+
+
应缴费用:{{ formatMoneyWithUnit(sourceFrom.totalPayable) }}
+
已收:{{ formatMoneyWithUnit(sourceFrom.totalReceived) }}
+
待收:{{ formatMoneyWithUnit(sourceFrom.totalPending) }}
-
-
- - -
{{ opt.name }}
-
+
+ + + + + +
- - +
-
欠费分布
-
+
缴费方式
+
-
+
- +
欠费分布
-
+
@@ -72,7 +67,7 @@ {{ item.label }} -
    +
    • {{ item.number }}%
    • @@ -90,7 +85,7 @@
-->
缴费走势分析
-
+
@@ -110,59 +105,48 @@ import Echarts from '@/components/Echarts/index.vue'; import { formatMoneyWithUnit } from '@/utils/money'; import { EChartsOption } from 'echarts'; import { getLast7Days, getPastDayDate } from '@/utils/time'; -import { income_statsApi } from '@/api/system/Payment'; - -const open = ref(false); -const dataTime = ref('2025-01-01'); -const form = ref({ - 'totalDue': '', - 'totalPaid': '', - 'totalUnpaid': '', - 'paidPercentage': '', - 'payWx': null, - 'payZfb': null, - 'payOffline': null, - 'totalPay': null, - 'feeTypeStats': [], - 'dailyStats': [] -}); +import { + arrears_distributionApi, + Arrears_distrubution, + income_scourcApi, + payment_methodApi, + payment_sourceApi, + payment_trendApi, + payment_trendType, + PayMentMethod +} from '@/api/system/Payment'; +import RingProgress from './compontents/RingProgress.vue'; const defaultDay = 30; // 默认查询近30天数据 +const open = ref(false); +const last10Day = getPastDayDate(defaultDay); +const dataTime = ref(last10Day); +const sourceFromIsComputed = ref(true); /** 收入来源 */ -/** 收入来源图表配置 */ -const incomeChartOptions = ref< - { - name: string; - options?: EChartsOption; - }[] ->( - [ - { - 'name': '停车费' - }, - { - 'name': '物业费' - }, - { - 'name': '水电费' - }, - { - 'name': '商铺租金' - }, - { - 'name': '维修费' - } - ].map((i) => { - return { - name: i.name, - options: { - tooltip: {}, - series: [] - } - }; - }) -); +const sourceFrom = ref({ + 'totalPayable': '0', + 'totalReceived': '0', + 'totalPending': '0', + + 'parkingFee': '0', + 'parkingFeePercent': '0', + + 'propertyFee': '0', + 'propertyFeePercent': '0', + + 'utilityFee': '0', + 'utilityFeePercent': '0', + + 'shopRent': '0', + 'shopRentPercent': '0', + + 'repairFee': '0', + 'repairFeePercent': '0', + + 'garbageFee': '0', + 'garbageFeePercent': '0' +}); /** 缴费方式 */ const options2 = shallowRef({ @@ -199,23 +183,54 @@ const options2 = shallowRef({ show: false }, data: [ - { value: 50, name: '支付宝', itemStyle: { color: '#0a74fe' } }, - { value: 30, name: '微信', itemStyle: { color: '#f74043' } }, - { value: 20, name: '线下', itemStyle: { color: '#fcd152' } } + { value: 0, name: '支付宝', itemStyle: { color: '#0a74fe' } }, + { value: 0, name: '微信', itemStyle: { color: '#f74043' } }, + { value: 0, name: '线下', itemStyle: { color: '#fcd152' } } ] } ] }); +function updatePayMethod(dataFrom: PayMentMethod): EChartsOption { + return { + legend: { + top: 'center', + left: '0', + orient: 'vertical', + itemGap: 50, + itemWidth: 12, // 图例色块宽度 + itemHeight: 12 // 图例色块高度 + }, + clockwise: true, + series: [ + { + name: '缴费方式', + type: 'pie', + startAngle: 280, + radius: ['50%', '100%'], + avoidLabelOverlap: false, + left: '50%', + emphasis: { + scale: true, + scaleSize: 6 + }, + data: [ + { value: Number(dataFrom.alipayAmount) ?? 0, name: '支付宝', itemStyle: { color: '#0a74fe' } }, + { value: Number(dataFrom.wechatAmount) ?? 0, name: '微信', itemStyle: { color: '#f74043' } }, + { value: Number(dataFrom.offlineAmount) ?? 0, name: '线下', itemStyle: { color: '#fcd152' } } + ] + } + ] + }; +} // 【新增】定义12个月份 const monthX = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']; /** 欠费分布 散点图 */ -/** 欠费分布 散点图 (带特效版) */ const options3 = shallowRef({ tooltip: { trigger: 'item', formatter: (params: any) => { - return `${monthX[params.value[0]]}
欠费金额: ${params.value[1]} 万元`; + return `${params.name}
欠费金额: ${formatMoneyWithUnit(params.value[1])}`; }, backgroundColor: 'rgba(255, 255, 255, 0.9)', borderColor: '#eee', @@ -304,7 +319,92 @@ const options3 = shallowRef({ } ] }); - +function UpdateOptions3(data: Arrears_distrubution[]): EChartsOption { + const xData = data.map((item, index) => { + return [index, item.amount]; + }); + const xMonth = data.map((item) => `${item.month}月`); + return { + tooltip: { + trigger: 'item', + formatter: (params: any) => { + return `${params.name}
欠费金额: ${formatMoneyWithUnit(params.value[1])}`; + }, + backgroundColor: 'rgba(255, 255, 255, 0.9)', + borderColor: '#eee', + textStyle: { color: '#333' } + }, + grid: { + left: '1%', + right: '2%', + top: '12%', + bottom: '12%', + containLabel: true + }, + xAxis: { + type: 'category', + data: xMonth, + boundaryGap: false, + axisTick: { + alignWithLabel: true, + length: 5, // 刻度线长度 + lineStyle: { color: '#ccc' } + }, + axisLine: { lineStyle: { color: '#eee' }, onZero: false }, + axisLabel: { + color: '#666', + interval: 0, // 强制显示所有月份 + margin: 12 // 标签与轴线的距离 + }, + splitLine: { + show: true, + lineStyle: { + color: '#f0f0f0', + type: 'dashed', + width: 1 + } + } + }, + yAxis: { + type: 'value', + name: '金额(万元)', + nameTextStyle: { color: '#999', padding: [0, 0, 0, 10] }, + splitLine: { + show: true, + lineStyle: { + color: '#f0f0f0', + type: 'dashed' // 虚线网格更轻盈 + } + }, + axisLabel: { color: '#999', margin: 20 } + }, + series: [ + { + name: '欠费金额', + type: 'scatter', + symbolSize: (data: any) => { + const value = data[1]; + return Math.min(Math.max(value * 1.5, 10), 40); + }, + itemStyle: { + color: (params: any) => { + const index = params.dataIndex; + if (index % 2 === 0) { + return '#739ff0'; + } else { + return '#86c9d0'; + } + } + }, + // 【特效 2】高亮状态(鼠标悬停) + emphasis: { + scale: 1.2 // 悬停时额外放大 + }, + data: xData + } + ] + }; +} // ! 进十日缴费数量情况 ------------------------------------------------------------------------------------- // 近10天日期 const dayX = getLast7Days(10); @@ -393,50 +493,65 @@ const flowLineOption = shallowRef({ } ] }); -// ! 进十日缴费数量情况 ------------------------------------------------------------------------------------- -const paytypelist = ref([ - { label: '微信', value: 'payWx', number: 0, color: '#4a3afe' }, - { label: '支付宝', value: 'payZfb', number: 0, color: '#1e1b39' }, - { label: '线下', value: 'payOffline', number: 0, color: '#c893fd' } +const payTypeList = ref([ + { label: '小程序', number: 0, color: '#4a3afe' }, + { label: '线下缴费', number: 0, color: '#1e1b39' }, + { label: '手机APP', number: 0, color: '#c893fd' } ]); // 排序后 -const sortPayList = ref([]); +const sortPayList = ref(payTypeList.value); + +const payMethodFrom = ref({ + 'wechatAmount': '0', + 'wechatPercent': '0', + 'alipayAmount': '0', + 'alipayPercent': '0', + 'offlineAmount': '0', + 'offlinePercent': '0' +}); function getList() { - const startData = getPastDayDate(defaultDay); - income_statsApi(dataTime.value === '' ? startData : dataTime.value).then((res) => { - form.value = res.data; - const { payOffline, payWx, payZfb, feeTypeStats, dailyStats } = res.data; - const total = (payOffline ?? 0) + (payWx ?? 0) + (payZfb ?? 0); - if (total > 0) { - form.value.payOffline = Number.isNaN((payOffline / total) * 100) ? 0 : ((payOffline / total) * 100).toFixed(2); - form.value.payWx = Number.isNaN((payWx / total) * 100) ? 0 : ((payWx / total) * 100).toFixed(2); - form.value.payZfb = Number.isNaN((payZfb / total) * 100) ? 0 : ((payZfb / total) * 100).toFixed(2); - const payTypeList = JSON.parse(JSON.stringify(paytypelist.value)); - payTypeList[0].number = form.value.payWx; - payTypeList[1].number = form.value.payZfb; - payTypeList[2].number = form.value.payOffline; - sortPayList.value = payTypeList.toSorted((a, b) => Number(b.number) - Number(a.number)); - } - - // 收入来源 - // 2. 处理收入来源 (新逻辑) - if (feeTypeStats && Array.isArray(feeTypeStats)) { - updateIncomeChart(feeTypeStats); - } - - // 3. 【新增】处理缴费走势 (近十日缴费情况) - if (dailyStats && Array.isArray(dailyStats)) { - updateFlowLineChart(dailyStats); - } + sourceFromIsComputed.value = false; + // 收入来源 + income_scourcApi(dataTime.value) + .then((res) => { + sourceFrom.value = res.data; + }) + .finally(() => { + setTimeout(() => { + sourceFromIsComputed.value = true; + }); + }); + // 缴费方式 + payment_methodApi(dataTime.value).then((res) => { + payMethodFrom.value = res.data; + options2.value = updatePayMethod(res.data); + }); + // 欠费分布 + arrears_distributionApi(dataTime.value).then((res) => { + options3.value = UpdateOptions3(res.data.items); + }); + //缴费来源 + payment_sourceApi(dataTime.value).then((res) => { + const payTypeListCopy = JSON.parse(JSON.stringify(payTypeList.value)); + payTypeListCopy[0].number = res.data.miniProgramPercent; + payTypeListCopy[1].number = res.data.offlinePercent; + payTypeListCopy[2].number = res.data.mobileAppPercent; + sortPayList.value = payTypeListCopy.toSorted( + (a: { number: string | number }, b: { number: string | number }) => Number(b.number) - Number(a.number) + ); + }); + // 缴费走势 + payment_trendApi(dataTime.value, getPastDayDate(0)).then((res) => { + updateFlowLineChart(res.data.items); }); } /** * 更新缴费走势图表 - * @param stats 后端返回的 dailyStats 数组 + * @param stats 后端返回的 dailyStats 数组& */ -function updateFlowLineChart(stats: any[]) { +function updateFlowLineChart(stats: payment_trendType[]) { if (!stats.length) { flowLineOption.value.series = []; flowLineOption.value.xAxis.data = []; @@ -444,13 +559,13 @@ function updateFlowLineChart(stats: any[]) { } // 提取数据 - const dates = stats.map((item) => item.statDate); - const paidData = stats.map((item) => Number(item.totalPaid) || 0); - const unpaidData = stats.map((item) => Number(item.totalUnpaid) || 0); + const dates = stats.map((item) => item.date); + const paidData = stats.map((item) => Number(item.paidAmount) || 0); + const unpaidData = stats.map((item) => Number(item.unpaidAmount) || 0); // 更新图表配置 // 使用 shallowRef 时,建议替换整个对象或确保深层属性被正确追踪 - // 这里我们直接修改 series 和 xAxis 的数据 + // 这里我们直接修改 series 和 xAxis 的数据 ╬╬ flowLineOption.value = { ...flowLineOption.value, xAxis: { @@ -507,96 +622,12 @@ function updateFlowLineChart(stats: any[]) { ] }; } -/** - * 更新收入来源图表数组 - * @param stats 后端返回的 feeTypeStats 数组 - */ -function updateIncomeChart(stats: any[]) { - incomeChartOptions.value = []; - let statslist = stats; - if (statslist.length === 0) { - statslist = [ - { - 'feeName': '停车费' - }, - { - 'feeName': '物业费' - }, - { - 'feeName': '水电费' - }, - { - 'feeName': '商铺租金' - }, - { - 'feeName': '维修费' - } - ]; - } - incomeChartOptions.value = statslist.map((item) => { - const percentage = Number(item.paidPercentage) || 0; - const color = '#409eff'; - return { - name: item.feeName, // 图表名称 - options: { - tooltip: { - show: false, - trigger: 'item', - formatter: '{b}: {c}%' - }, - series: [ - { - type: 'pie', - radius: ['50%', '70%'], // 环形大小 - center: ['50%', '50%'], // 每个图表各自居中 - select: { - scale: false - }, - labelLine: { - show: false - }, - data: [ - { - value: 100 - percentage, - itemStyle: { - color: '#ebeef5' // 背景色 - }, - emphasis: { - itemStyle: { - color: '#ebeef5' - }, - scale: false - } - }, - { - value: percentage, - name: item.feeName, - itemStyle: { color: color }, - label: { - show: true, - position: 'center', // 显示在圆环中心 - formatter: '{c}%', // 显示百分比数值 - fontSize: 14, - fontWeight: 'bold', - color: '#4ce19c' - }, - emphasis: { - scale: true - } - } - ] - } - ] - } - }; - }); - console.log(incomeChartOptions.value); -} + function querySearch() { getList(); } function reset() { - dataTime.value = ''; + dataTime.value = getPastDayDate(defaultDay); querySearch(); } getList(); @@ -632,6 +663,7 @@ onUnmounted(() => { font-size: 20px; padding: 20px; min-height: 275px; + height: 100%; @media (max-width: 1600px) { font-size: 18px; } @@ -641,7 +673,7 @@ onUnmounted(() => { @media (max-width: 1200px) { margin-bottom: 20px; } - .card_infoall { + .card_InfoAll { padding-left: 40px; display: flex; align-items: center; @@ -653,7 +685,7 @@ onUnmounted(() => { margin-top: 15px; } - .cardbody { + .cardBody { padding: 0 30px; display: flex; align-items: center; @@ -663,10 +695,10 @@ onUnmounted(() => { } .card_leftbox { text-align: center; - .labelbox { + .labelBox { font-size: 16px; } - .valuebox { + .valueBox { font-weight: 600; font-size: 36px; color: #222222; @@ -683,7 +715,6 @@ onUnmounted(() => { li { margin-bottom: 20px; position: relative; - width: 100px; height: 50px; line-height: 50px; text-align: left; @@ -700,7 +731,7 @@ onUnmounted(() => { } } } - .circlebox { + .circleBox { margin-left: 60px; position: relative; width: 300px; diff --git a/src/views/system/statistics/Personnel/index.vue b/src/views/system/statistics/Personnel/index.vue index 41b15eb..0ac5147 100644 --- a/src/views/system/statistics/Personnel/index.vue +++ b/src/views/system/statistics/Personnel/index.vue @@ -17,13 +17,13 @@
入住情况
-
-
-
{{ movein.totalResident }}
-
入住人数
+
+
+
{{ MoveIn.totalResident }}
+
入住人数
-
- +
+
@@ -31,16 +31,16 @@
住户类型情况
-
- +
+
男女比例
-
- +
+
@@ -56,7 +56,7 @@
- +
@@ -68,12 +68,11 @@