258 lines
5.9 KiB
Vue
258 lines
5.9 KiB
Vue
<template>
|
||
<view class="usage-page">
|
||
<!-- 统计信息 -->
|
||
<view class="statistics-card">
|
||
<view class="stat-item">
|
||
<text class="stat-value">{{ totalUsage }}</text>
|
||
<text class="stat-label">累计使用(小时)</text>
|
||
</view>
|
||
<view class="stat-item">
|
||
<text class="stat-value">{{ usageCount }}</text>
|
||
<text class="stat-label">使用次数</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 使用记录列表 -->
|
||
<view class="usage-list">
|
||
<view v-if="list.length === 0" class="empty-state">
|
||
<text class="empty-icon">📭</text>
|
||
<text class="empty-text">暂无使用记录</text>
|
||
</view>
|
||
|
||
<view v-else>
|
||
<view v-for="item in list" :key="item.id" class="usage-item">
|
||
<view class="item-header">
|
||
<text class="usage-date">{{ item.usageDate }}</text>
|
||
<text class="usage-hours">-{{ item.usageHours }}小时</text>
|
||
</view>
|
||
|
||
<view class="item-content">
|
||
<view class="content-row">
|
||
<text class="label">服务类型:</text>
|
||
<text class="value">{{ item.serviceType || '陪读服务' }}</text>
|
||
</view>
|
||
<view class="content-row" v-if="item.serviceContent">
|
||
<text class="label">服务内容:</text>
|
||
<text class="value">{{ item.serviceContent }}</text>
|
||
</view>
|
||
<view class="content-row" v-if="item.startTime && item.endTime">
|
||
<text class="label">服务时间:</text>
|
||
<text class="value">{{ formatTime(item.startTime) }} - {{ formatTime(item.endTime) }}</text>
|
||
</view>
|
||
<view class="content-row" v-if="item.orderId">
|
||
<text class="label">订单编号:</text>
|
||
<text class="value link" @click="goOrder(item.orderId)">{{ item.orderId }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { parseId, validateId } from '@/utils/params.js'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
cardId: null,
|
||
list: [],
|
||
totalUsage: 0,
|
||
usageCount: 0,
|
||
page: 1,
|
||
size: 20,
|
||
loading: false,
|
||
finished: false
|
||
}
|
||
},
|
||
|
||
onLoad(options) {
|
||
this.cardId = parseId(options.id)
|
||
if (!validateId(this.cardId, '次卡ID')) {
|
||
setTimeout(() => uni.navigateBack(), 1500)
|
||
return
|
||
}
|
||
this.loadUsageList()
|
||
},
|
||
|
||
onReachBottom() {
|
||
if (!this.loading && !this.finished) {
|
||
this.page++
|
||
this.loadUsageList()
|
||
}
|
||
},
|
||
|
||
methods: {
|
||
async loadUsageList() {
|
||
if (this.loading) return
|
||
this.loading = true
|
||
|
||
try {
|
||
const res = await this.$http.get('/api/timecard/usage/list', {
|
||
params: {
|
||
timeCardId: this.cardId,
|
||
page: this.page,
|
||
size: this.size
|
||
}
|
||
})
|
||
|
||
if (res.code === 200) {
|
||
const records = res.data.records
|
||
|
||
if (this.page === 1) {
|
||
this.list = records
|
||
this.calculateStatistics()
|
||
} else {
|
||
this.list = [...this.list, ...records]
|
||
}
|
||
|
||
if (records.length < this.size) {
|
||
this.finished = true
|
||
}
|
||
}
|
||
} catch (e) {
|
||
console.error('加载使用记录失败:', e)
|
||
const errorMsg = e.message || e.msg || '加载使用记录失败,请稍后重试'
|
||
uni.showToast({
|
||
title: errorMsg,
|
||
icon: 'none',
|
||
duration: 2000
|
||
})
|
||
} finally {
|
||
this.loading = false
|
||
}
|
||
},
|
||
|
||
calculateStatistics() {
|
||
// 计算总使用时长(小时数不涉及金额,使用parseFloat是安全的)
|
||
this.totalUsage = this.list.reduce((sum, item) => sum + parseFloat(item.usageHours || 0), 0).toFixed(1)
|
||
this.usageCount = this.list.length
|
||
},
|
||
|
||
formatTime(datetime) {
|
||
if (!datetime) return ''
|
||
return datetime.substring(11, 16)
|
||
},
|
||
|
||
goOrder(orderId) {
|
||
uni.navigateTo({
|
||
url: `/pages/order/detail?id=${orderId}`
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
@import '@/static/css/common.scss';
|
||
|
||
.usage-page {
|
||
min-height: 100vh;
|
||
background: $bg-color;
|
||
}
|
||
|
||
.statistics-card {
|
||
background: linear-gradient(135deg, #4a9b9f 0%, #3d8185 100%);
|
||
padding: 60rpx 40rpx;
|
||
display: flex;
|
||
justify-content: space-around;
|
||
|
||
.stat-item {
|
||
flex: 1;
|
||
text-align: center;
|
||
|
||
.stat-value {
|
||
display: block;
|
||
font-size: 48rpx;
|
||
font-weight: bold;
|
||
color: #fff;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.stat-label {
|
||
display: block;
|
||
font-size: 28rpx;
|
||
color: rgba(255, 255, 255, 0.8);
|
||
}
|
||
}
|
||
}
|
||
|
||
.usage-list {
|
||
padding: 20rpx 30rpx;
|
||
}
|
||
|
||
.empty-state {
|
||
text-align: center;
|
||
padding: 120rpx 0;
|
||
|
||
.empty-image {
|
||
width: 300rpx;
|
||
height: 300rpx;
|
||
margin-bottom: 40rpx;
|
||
}
|
||
|
||
.empty-text {
|
||
display: block;
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
}
|
||
}
|
||
|
||
.usage-item {
|
||
background: #fff;
|
||
border-radius: 16rpx;
|
||
padding: 30rpx;
|
||
margin-bottom: 20rpx;
|
||
|
||
.item-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20rpx;
|
||
padding-bottom: 20rpx;
|
||
border-bottom: 1rpx solid #f0f0f0;
|
||
|
||
.usage-date {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.usage-hours {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #4a9b9f;
|
||
}
|
||
}
|
||
|
||
.item-content {
|
||
.content-row {
|
||
display: flex;
|
||
margin-bottom: 16rpx;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.label {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
min-width: 160rpx;
|
||
}
|
||
|
||
.value {
|
||
flex: 1;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
|
||
&.link {
|
||
color: #4a9b9f;
|
||
text-decoration: underline;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style>
|