395 lines
8.4 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="page">
<!-- 顶部统计卡片 -->
<view class="stats-card card">
<view class="stat-item">
<text class="stat-value">{{ totalCount }}</text>
<text class="stat-label">借用总数</text>
</view>
<view class="stat-divider"></view>
<view class="stat-item">
<text class="stat-value highlight">{{ borrowingCount }}</text>
<text class="stat-label">借用中</text>
</view>
<view class="stat-divider"></view>
<view class="stat-item">
<text class="stat-value success">{{ returnedCount }}</text>
<text class="stat-label">已归还</text>
</view>
</view>
<!-- 筛选栏 -->
<view class="filter-bar card">
<view class="filter-tabs">
<view
class="filter-tab"
:class="{ active: filterStatus === null }"
@tap="changeFilter(null)"
>
全部
</view>
<view
class="filter-tab"
:class="{ active: filterStatus === 0 }"
@tap="changeFilter(0)"
>
借用中
</view>
<view
class="filter-tab"
:class="{ active: filterStatus === 1 }"
@tap="changeFilter(1)"
>
已归还
</view>
</view>
</view>
<!-- 列表 -->
<scroll-view
class="list-container"
scroll-y
refresher-enabled
:refresher-triggered="refreshing"
@refresherrefresh="onRefresh"
>
<view v-if="loading && myBorrowList.length === 0" class="loading-wrap">
<text class="loading-text">加载中...</text>
</view>
<view v-else-if="myBorrowList.length === 0" class="empty-wrap">
<text class="empty-icon">📦</text>
<text class="empty-text">暂无借用记录</text>
</view>
<view v-else class="list">
<view
v-for="item in filteredList"
:key="item.borrowId"
class="list-item card"
>
<!-- 顶部资产名称 + 状态标签 -->
<view class="item-header">
<view class="asset-name-wrap">
<text class="asset-name">{{ item.assetName }}</text>
</view>
<view class="status-badge" :class="item.isReturn === 1 ? 'returned' : 'borrowing'">
{{ item.isReturn === 1 ? '已归还' : '借用中' }}
</view>
</view>
<!-- 信息行 -->
<view class="item-info">
<view class="info-row">
<text class="info-label">借用日期</text>
<text class="info-value">{{ item.borrowDate || '-' }}</text>
</view>
<view class="info-row">
<text class="info-label">应还日期</text>
<text class="info-value">{{ item.returnDate || '-' }}</text>
</view>
<view v-if="item.actualReturnDate" class="info-row">
<text class="info-label">实际归还</text>
<text class="info-value success-text">{{ item.actualReturnDate }}</text>
</view>
<view class="info-row">
<text class="info-label">出借人</text>
<text class="info-value">{{ item.lenderName || '-' }}</text>
</view>
<view v-if="item.lenderMobile" class="info-row">
<text class="info-label">联系方式</text>
<text class="info-value">{{ item.lenderMobile }}</text>
</view>
<view v-if="item.note" class="info-row">
<text class="info-label">备注</text>
<text class="info-value">{{ item.note }}</text>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
// @ts-ignore
import { fetchBorrowList } from '@/pages/api/fixedAssets.js'
interface BorrowRecord {
borrowId: number
assetId: number
assetName: string
borrowDate: string
returnDate: string
actualReturnDate: string | null
borrowerId: string
borrowerName: string | null
borrowerMobile: string | null
lenderId: string
lenderName: string | null
lenderMobile: string | null
registrantDate: string
isReturn: number // 0-借用中 1-已归还
note: string
}
const myBorrowList = ref<BorrowRecord[]>([])
const loading = ref(false)
const refreshing = ref(false)
const filterStatus = ref<number | null>(null)
const userMobile = uni.getStorageSync('userName') || ''
// 统计数据
const totalCount = computed(() => myBorrowList.value.length)
const borrowingCount = computed(() => myBorrowList.value.filter(item => item.isReturn === 0).length)
const returnedCount = computed(() => myBorrowList.value.filter(item => item.isReturn === 1).length)
// 筛选后的列表
const filteredList = computed(() => {
if (filterStatus.value === null) {
return myBorrowList.value
}
return myBorrowList.value.filter(item => item.isReturn === filterStatus.value)
})
onLoad(() => {
loadData()
})
onShow(() => {
loadData()
})
// 加载数据
async function loadData() {
loading.value = true
try {
const result = await fetchBorrowList()
if (result.code === 0 && Array.isArray(result.data)) {
// 在前端筛选出当前用户的借用记录(按手机号匹配)
myBorrowList.value = result.data.filter((item: BorrowRecord) =>
item.borrowerMobile === userMobile
)
} else {
uni.showToast({
title: result.msg || '加载失败',
icon: 'none'
})
}
} catch (error) {
console.error('加载借用记录失败:', error)
uni.showToast({
title: '加载失败',
icon: 'none'
})
} finally {
loading.value = false
refreshing.value = false
}
}
// 下拉刷新
function onRefresh() {
refreshing.value = true
loadData()
}
// 切换筛选
function changeFilter(status: number | null) {
filterStatus.value = status
}
</script>
<style scoped>
.page {
min-height: 100vh;
background: #f5f7fb;
padding-bottom: 32rpx;
}
.card {
background: #fff;
border-radius: 20rpx;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.06);
}
/* 统计卡片 */
.stats-card {
margin: 24rpx 24rpx 16rpx;
padding: 24rpx;
display: flex;
align-items: center;
justify-content: space-around;
}
.stat-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 4rpx;
}
.stat-value {
font-size: 36rpx;
font-weight: 600;
color: #333;
}
.stat-value.highlight {
color: #ff9800;
}
.stat-value.success {
color: #51cf66;
}
.stat-label {
font-size: 22rpx;
color: #999;
}
.stat-divider {
width: 2rpx;
height: 50rpx;
background: #e8e8e8;
}
/* 筛选栏 */
.filter-bar {
margin: 0 24rpx 16rpx;
padding: 12rpx;
}
.filter-tabs {
display: flex;
gap: 8rpx;
}
.filter-tab {
flex: 1;
text-align: center;
padding: 12rpx 8rpx;
border-radius: 8rpx;
font-size: 24rpx;
color: #666;
background: #f8f9fa;
transition: all 0.3s;
}
.filter-tab.active {
background: #007aff;
color: #fff;
font-weight: 500;
}
/* 列表容器 */
.list-container {
height: calc(100vh - 260rpx);
}
.loading-wrap,
.empty-wrap {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 120rpx 0;
}
.loading-text {
color: #999;
font-size: 28rpx;
}
.empty-icon {
font-size: 120rpx;
margin-bottom: 24rpx;
}
.empty-text {
color: #999;
font-size: 28rpx;
}
/* 列表项 */
.list {
padding: 0 24rpx;
}
.list-item {
margin-bottom: 20rpx;
padding: 24rpx;
}
.item-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 16rpx;
padding-bottom: 16rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.asset-name-wrap {
flex: 1;
margin-right: 16rpx;
}
.asset-name {
font-size: 30rpx;
font-weight: 600;
color: #222;
line-height: 1.4;
}
.status-badge {
padding: 6rpx 16rpx;
border-radius: 20rpx;
font-size: 22rpx;
font-weight: 500;
white-space: nowrap;
}
.status-badge.borrowing {
background: #fff3e0;
color: #ff9800;
}
.status-badge.returned {
background: #e8f5e9;
color: #4caf50;
}
/* 信息行 */
.item-info {
display: flex;
flex-direction: column;
gap: 12rpx;
}
.info-row {
display: flex;
align-items: flex-start;
font-size: 24rpx;
}
.info-label {
color: #999;
min-width: 140rpx;
flex-shrink: 0;
}
.info-value {
color: #333;
flex: 1;
word-break: break-all;
}
.success-text {
color: #51cf66;
font-weight: 500;
}
</style>