对接实收统计功能
This commit is contained in:
@@ -100,3 +100,13 @@ export const changePhone = data => {
|
||||
export const authDeleteAccount = () => {
|
||||
return get('/api/butler/auth/cancelAccount')
|
||||
}
|
||||
|
||||
// =======实收统计========
|
||||
// 收费类型下拉数据
|
||||
export const getFeeTypes = () => {
|
||||
return get('/api/butler/actualReceipt/feeTypes')
|
||||
}
|
||||
// 表格列表数据
|
||||
export const getTableList = (data) => {
|
||||
return get('/api/butler/actualReceipt/stats', data)
|
||||
}
|
||||
|
||||
@@ -1,55 +1,582 @@
|
||||
<template>
|
||||
<view class="page_padding">
|
||||
<view class="revenue_statistics_box flex-1 flex flex-col">
|
||||
<view class="nav flex items-center">
|
||||
<view class="line"></view>
|
||||
<text class="title">实收统计</text>
|
||||
<!-- 状态栏 -->
|
||||
<view class="status-bar" :style="{ height: statusBarHeight + 'px' }"></view>
|
||||
|
||||
<!-- 导航栏 -->
|
||||
<uni-nav-bar title="实收统计" backgroundColor="transparent" :border="false" left-icon="left" @click-left="goBack" />
|
||||
|
||||
<!-- 筛选条件 -->
|
||||
<view class="filter-section">
|
||||
<view class="filter-row">
|
||||
<!-- 全部项目 -->
|
||||
<view class="filter-item">
|
||||
<picker mode="selector" :range="projectOptions" range-key="label" @change="onProjectChange">
|
||||
<view class="filter-label">
|
||||
<text>{{ selectedProjectLabel || '全部项目' }}</text>
|
||||
<text class="filter-arrow">▾</text>
|
||||
</view>
|
||||
<view class="content flex-1 flex flex-col items-center justify-center">
|
||||
<text class="placeholder">实收统计页面</text>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 全部收费类型 -->
|
||||
<view class="filter-item">
|
||||
<picker mode="selector" :range="feeTypeOptions" range-key="label" @change="onFeeTypeChange">
|
||||
<view class="filter-label">
|
||||
<text>{{ selectedFeeTypeLabel || '全部收费类型' }}</text>
|
||||
<text class="filter-arrow">▾</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 日期范围 -->
|
||||
<view class="date-row">
|
||||
<uni-datetime-picker
|
||||
class="date-picker"
|
||||
v-model="datetimerange"
|
||||
type="daterange"
|
||||
rangeSeparator="至"
|
||||
placeholder="请选择日期区间"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 搜索 & 重置按钮 -->
|
||||
<view class="btn-row">
|
||||
<button class="reset-btn" @click="onReset">
|
||||
重置
|
||||
</button>
|
||||
<button class="search-btn" @click="onSearch">
|
||||
搜索
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 统计表格列表 -->
|
||||
<scroll-view class="table-scroll" scroll-y show-scrollbar="false">
|
||||
<!-- 循环渲染每个表格 -->
|
||||
<view v-for="(table, index) in tableConfigs" :key="index" class="table-wrapper">
|
||||
<!-- 标题独立于卡片外 -->
|
||||
<view class="table-title">{{ table.title }}</view>
|
||||
|
||||
<!-- 卡片区域(仅包含表格内容) -->
|
||||
<view class="table-card">
|
||||
<!-- 表头 -->
|
||||
<view class="table-header">
|
||||
<text class="col-name">{{ table.colName }}</text>
|
||||
<text class="col-amount">实际收款(元)</text>
|
||||
<text class="col-discount">折扣(元)</text>
|
||||
</view>
|
||||
|
||||
<!-- 暂无数据 -->
|
||||
<view v-if="!table.data || table.data.length === 0" class="empty-row">
|
||||
<text>暂无数据</text>
|
||||
</view>
|
||||
|
||||
<!-- 数据行 -->
|
||||
<template v-else>
|
||||
<view class="table-row" v-for="item in table.data" :key="item.name">
|
||||
<text class="col-name">{{ item.name }}</text>
|
||||
<text class="col-amount">{{ item.amount.toFixed(2) }}</text>
|
||||
<text class="col-discount">{{ item.discount.toFixed(2) }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 汇总行 -->
|
||||
<view class="table-row total-row">
|
||||
<text class="col-name">汇总</text>
|
||||
<text class="col-amount">{{ table.total.amount.toFixed(2) }}</text>
|
||||
<text class="col-discount">{{ table.total.discount.toFixed(2) }}</text>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部占位 -->
|
||||
<view class="bottom-placeholder"></view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { getVillageList,getFeeTypes,getTableList} from '../../api/api.js'
|
||||
|
||||
onShow(() => {
|
||||
// TODO: 加载实收统计数据
|
||||
})
|
||||
// ============ 系统信息 ============
|
||||
const statusBarHeight = ref(uni.getSystemInfoSync().statusBarHeight || 0)
|
||||
|
||||
// ============ 筛选数据 ============
|
||||
// 项目选项(从接口获取)
|
||||
const projectOptions = ref([])
|
||||
const selectedProject = ref('')
|
||||
const selectedProjectLabel = ref('全部项目')
|
||||
|
||||
// 收费类型选项(从接口获取)
|
||||
const feeTypeOptions = ref([])
|
||||
const selectedFeeType = ref('')
|
||||
const selectedFeeTypeLabel = ref('全部收费类型')
|
||||
|
||||
// 日期范围
|
||||
const datetimerange = ref([])
|
||||
|
||||
// ============ 表格数据 ============
|
||||
const tableConfigs = reactive([
|
||||
{
|
||||
title: '项目总览',
|
||||
colName: '项目名称',
|
||||
data: [],
|
||||
total: { amount: 0, discount: 0 }
|
||||
},
|
||||
{
|
||||
title: '收费类型总览',
|
||||
colName: '收费类型',
|
||||
data: [],
|
||||
total: { amount: 0, discount: 0 }
|
||||
},
|
||||
{
|
||||
title: '房屋类型总览',
|
||||
colName: '房屋类型',
|
||||
data: [],
|
||||
total: { amount: 0, discount: 0 }
|
||||
},
|
||||
])
|
||||
|
||||
// ============ 获取小区列表 ============
|
||||
const fetchVillageList = () => {
|
||||
getVillageList()
|
||||
.then((res) => {
|
||||
if (res.code === 200 && res.data) {
|
||||
const list = res.data.map((item) => ({
|
||||
value: String(item.id),
|
||||
label: item.villageName
|
||||
}))
|
||||
projectOptions.value = [
|
||||
{ value: '', label: '全部项目' },
|
||||
...list
|
||||
]
|
||||
// 默认选中全部项目
|
||||
selectedProject.value = ''
|
||||
selectedProjectLabel.value = '全部项目'
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
// ============ 获取收费类型列表 ============
|
||||
const fetchFeeTypes = () => {
|
||||
getFeeTypes()
|
||||
.then((res) => {
|
||||
if (res.code === 200 && res.data) {
|
||||
const list = res.data.map((item) => ({
|
||||
value: String(item.id),
|
||||
label: item.name
|
||||
}))
|
||||
feeTypeOptions.value = [
|
||||
{ value: '', label: '全部收费类型' },
|
||||
...list
|
||||
]
|
||||
selectedFeeType.value = ''
|
||||
selectedFeeTypeLabel.value = '全部收费类型'
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
// ============ 获取表格数据 ============
|
||||
const fetchTableList = () => {
|
||||
const params = {
|
||||
pageNum: '1',
|
||||
pageSize: '10'
|
||||
}
|
||||
if (selectedProject.value) {
|
||||
params.villageId = selectedProject.value
|
||||
}
|
||||
if (selectedFeeType.value) {
|
||||
params.chargeTypeId = selectedFeeType.value
|
||||
}
|
||||
if (datetimerange.value && datetimerange.value.length === 2) {
|
||||
params.startDate = datetimerange.value[0]
|
||||
params.endDate = datetimerange.value[1]
|
||||
}
|
||||
getTableList(params)
|
||||
.then((res) => {
|
||||
if (res.code === 200 && res.data) {
|
||||
// 项目总览
|
||||
const { projectOverview, feeTypeOverview, houseTypeOverview } = res.data
|
||||
if (projectOverview) {
|
||||
tableConfigs[0].data = (projectOverview.items).map((item) => ({
|
||||
name: item.name,
|
||||
amount: Number(item.actualAmount),
|
||||
discount: Number(item.discountAmount)
|
||||
}))
|
||||
tableConfigs[0].total = {
|
||||
amount: Number(projectOverview.totalActualAmount),
|
||||
discount: Number(projectOverview.totalDiscountAmount)
|
||||
}
|
||||
}
|
||||
// 收费类型总览
|
||||
if (feeTypeOverview) {
|
||||
tableConfigs[1].data = (feeTypeOverview.items).map((item) => ({
|
||||
name: item.name,
|
||||
amount: Number(item.actualAmount),
|
||||
discount: Number(item.discountAmount)
|
||||
}))
|
||||
tableConfigs[1].total = {
|
||||
amount: Number(feeTypeOverview.totalActualAmount),
|
||||
discount: Number(feeTypeOverview.totalDiscountAmount)
|
||||
}
|
||||
}
|
||||
// 房屋类型总览
|
||||
if (houseTypeOverview) {
|
||||
tableConfigs[2].data = (houseTypeOverview.items).map((item) => ({
|
||||
name: item.name,
|
||||
amount: Number(item.actualAmount),
|
||||
discount: Number(item.discountAmount)
|
||||
}))
|
||||
tableConfigs[2].total = {
|
||||
amount: Number(houseTypeOverview.totalActualAmount),
|
||||
discount: Number(houseTypeOverview.totalDiscountAmount)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
// ============ 生命周期 ============
|
||||
onShow(() => {
|
||||
fetchVillageList()
|
||||
fetchFeeTypes()
|
||||
fetchTableList()
|
||||
})
|
||||
|
||||
// ============ 事件处理 ============
|
||||
const goBack = () => {
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
const onProjectChange = (e) => {
|
||||
const index = e.detail.value
|
||||
const option = projectOptions.value[index]
|
||||
selectedProject.value = option.value
|
||||
selectedProjectLabel.value = option.label
|
||||
}
|
||||
|
||||
const onFeeTypeChange = (e) => {
|
||||
const index = e.detail.value
|
||||
const option = feeTypeOptions.value[index]
|
||||
selectedFeeType.value = option.value
|
||||
selectedFeeTypeLabel.value = option.label
|
||||
}
|
||||
|
||||
const onSearch = () => {
|
||||
fetchTableList()
|
||||
}
|
||||
|
||||
const onReset = () => {
|
||||
selectedProject.value = ''
|
||||
selectedProjectLabel.value = '全部项目'
|
||||
selectedFeeType.value = ''
|
||||
selectedFeeTypeLabel.value = '全部收费类型'
|
||||
datetimerange.value = []
|
||||
fetchTableList()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.revenue_statistics_box {
|
||||
background: #f9f9f9;
|
||||
padding: 20rpx 40rpx;
|
||||
.page_padding {
|
||||
background: linear-gradient(to left bottom, #e2efff 0%, #f9f9f9 50%);
|
||||
padding: 0 30rpx;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
|
||||
.nav {
|
||||
margin-bottom: 40rpx;
|
||||
font-weight: 550;
|
||||
font-size: 32rpx;
|
||||
.status-bar {
|
||||
width: 100%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
// ===== 筛选区域(取消背景) =====
|
||||
.filter-section {
|
||||
padding: 24rpx 0 16rpx;
|
||||
flex-shrink: 0;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
|
||||
.filter-item {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
.filter-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: transparent;
|
||||
border-radius: 12rpx;
|
||||
padding: 16rpx 24rpx;
|
||||
font-size: 26rpx;
|
||||
color: #333333;
|
||||
line-height: 40rpx;
|
||||
border: 2rpx solid #DCDFE6;
|
||||
transition: all 0.2s;
|
||||
|
||||
.line {
|
||||
width: 6rpx;
|
||||
height: 28rpx;
|
||||
background: #4d5dfa;
|
||||
margin-right: 10rpx;
|
||||
.filter-arrow {
|
||||
font-size: 20rpx;
|
||||
color: #999;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: #f5f7fa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
.placeholder {
|
||||
// 日期选择器
|
||||
.date-row {
|
||||
margin-top: 16rpx;
|
||||
|
||||
.date-picker {
|
||||
// 透明背景
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索 & 重置按钮
|
||||
.btn-row {
|
||||
display: flex;
|
||||
margin-top: 24rpx;
|
||||
gap: 24rpx;
|
||||
|
||||
.reset-btn,
|
||||
.search-btn {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
|
||||
&:active {
|
||||
opacity: 0.85;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
|
||||
.reset-btn {
|
||||
background: #ffffff;
|
||||
color: #4D5DFA;
|
||||
border: 2rpx solid #4D5DFA;
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
background: linear-gradient(135deg, #4D5DFA 0%, #6C7AFF 100%);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 8rpx 20rpx rgba(77, 93, 250, 0.25);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 表格滚动容器 =====
|
||||
.table-scroll {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
|
||||
// 每个表格的外层包装
|
||||
.table-wrapper {
|
||||
margin-bottom: 32rpx;
|
||||
|
||||
// 标题独立于卡片外
|
||||
.table-title {
|
||||
font-size: 34rpx;
|
||||
font-weight: 600;
|
||||
color: #1a2332;
|
||||
padding: 0 0 16rpx 8rpx;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
|
||||
// 卡片(仅包含表格内容,不含标题)
|
||||
.table-card {
|
||||
background: #ffffff;
|
||||
border-radius: 24rpx;
|
||||
padding: 24rpx 28rpx;
|
||||
box-shadow: 0 6rpx 30rpx rgba(0, 0, 0, 0.05);
|
||||
|
||||
// 表头(添加背景色 #EBEDFF)
|
||||
.table-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16rpx 20rpx;
|
||||
background-color: #EBEDFF;
|
||||
border-radius: 16rpx 16rpx 0 0;
|
||||
font-size: 26rpx;
|
||||
color: #2c3a4b;
|
||||
font-weight: 600;
|
||||
|
||||
.col-name {
|
||||
flex: 2;
|
||||
text-align: left;
|
||||
}
|
||||
.col-amount {
|
||||
flex: 1.2;
|
||||
text-align: right;
|
||||
padding-right: 8rpx;
|
||||
}
|
||||
.col-discount {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
padding-right: 4rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 数据行
|
||||
.table-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 18rpx 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
border-bottom: 1rpx solid #f7f8fa;
|
||||
|
||||
&:last-of-type {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.col-name {
|
||||
flex: 2;
|
||||
text-align: left;
|
||||
font-weight: 400;
|
||||
color: #2c3a4b;
|
||||
}
|
||||
.col-amount {
|
||||
flex: 1.2;
|
||||
text-align: right;
|
||||
padding-right: 8rpx;
|
||||
font-weight: 500;
|
||||
color: #1a2332;
|
||||
}
|
||||
.col-discount {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
padding-right: 4rpx;
|
||||
color: #666666;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
// 汇总行
|
||||
&.total-row {
|
||||
background: #f7f9fc;
|
||||
border-radius: 0 0 12rpx 12rpx;
|
||||
margin-top: 4rpx;
|
||||
padding: 18rpx 20rpx;
|
||||
font-weight: 600;
|
||||
border-bottom: none;
|
||||
|
||||
.col-name {
|
||||
color: #4D5DFA;
|
||||
font-weight: 600;
|
||||
}
|
||||
.col-amount {
|
||||
color: #4D5DFA;
|
||||
font-weight: 600;
|
||||
}
|
||||
.col-discount {
|
||||
color: #4D5DFA;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 隔行变色(数据行)
|
||||
.table-row:not(.total-row):nth-child(even) {
|
||||
background: #fafbfc;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.empty-row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 60rpx 0;
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-placeholder {
|
||||
height: 40rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 响应式适配 =====
|
||||
@media screen and (max-width: 374px) {
|
||||
.page_padding {
|
||||
padding: 0 20rpx;
|
||||
|
||||
.filter-section {
|
||||
padding: 16rpx 0 12rpx;
|
||||
|
||||
.filter-row {
|
||||
gap: 12rpx;
|
||||
|
||||
.filter-item {
|
||||
.filter-label {
|
||||
padding: 12rpx 16rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-scroll .table-wrapper {
|
||||
.table-card {
|
||||
padding: 16rpx 16rpx;
|
||||
|
||||
.table-header,
|
||||
.table-row {
|
||||
padding: 14rpx 16rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
.table-title {
|
||||
font-size: 30rpx;
|
||||
padding-bottom: 12rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
.page_padding {
|
||||
padding: 0 60rpx;
|
||||
|
||||
.filter-section {
|
||||
padding: 30rpx 0 20rpx;
|
||||
}
|
||||
|
||||
.table-scroll .table-wrapper {
|
||||
.table-card {
|
||||
padding: 32rpx 40rpx;
|
||||
}
|
||||
.table-title {
|
||||
font-size: 38rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== uni-datetime-picker 透明背景 =====
|
||||
:deep(.uni-date-x) {
|
||||
background: transparent !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -129,7 +129,8 @@
|
||||
{
|
||||
"path": "revenue_statistics",
|
||||
"style": {
|
||||
"navigationBarTitleText": "实收统计"
|
||||
"navigationBarTitleText": "实收统计",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -255,8 +255,8 @@ const functionList = [
|
||||
action: 'goToReplacement_record'
|
||||
},
|
||||
{
|
||||
permKey: 'butler:revenue:statistics',
|
||||
icon: 'https://wuyeadmin.bugtc.com/images/imgs/revenue-statistics.png',
|
||||
permKey: 'butler:actualReceipt:stats',
|
||||
icon: 'https://wuye.ckdzkj.com/images/imgs/revenue-statistics.png',
|
||||
text: '实收统计',
|
||||
action: 'goToRevenueStatistics'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user