Files
device-voice-h5/pages/asset-package-history/asset-package-history.vue
2026-09-08 09:56:16 +08:00

137 lines
3.4 KiB
Vue

<template>
<view class="container">
<view v-if="!historyLoaded || (loading && packageList.length === 0)" class="loading-state">
<up-loading-icon text="加载中" size="30"></up-loading-icon>
</view>
<view v-else-if="packageList.length === 0" class="empty-state">
<image class="empty-icon" src="/static/asset-package-history.png" mode="aspectFit" alt="资产套餐历史"></image>
<view class="empty-title">暂无套餐记录</view>
<view class="empty-desc">当前账号下暂无套餐历史信息</view>
</view>
<view v-else>
<PackageHistoryNode
v-for="(item, index) in packageList"
:key="getGroupKey(item, index)"
:node="item"
/>
</view>
<view v-if="packageList.length > 0" class="load-more">
<text v-if="loading">加载中...</text>
<text v-else-if="noMore">没有更多套餐</text>
<text v-else role="button" tabindex="0" @tap="loadMore">点击加载更多</text>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { assetApi } from '@/api/index.js';
import PackageHistoryNode from '@/components/PackageHistoryNode.vue';
import { useUserStore } from '@/store/index.js';
const userStore = useUserStore();
const packageList = ref([]);
const loading = ref(false);
const historyLoaded = ref(false);
const noMore = ref(false);
const page = ref(1);
const total = ref(0);
const pageSize = 10;
const getGroupKey = (item, index) => item.package_usage_id ?? `group-${index}`;
const loadPackageList = async (append = false) => {
if (loading.value || (append && noMore.value)) return;
loading.value = true;
const requestedPage = page.value;
try {
const data = await assetApi.getPackageHistory(
userStore.state.identifier,
requestedPage,
pageSize
);
const groups = data.items;
const responsePage = Number.isInteger(data.page) && data.page > 0
? data.page
: requestedPage;
const responseSize = Number.isInteger(data.size) && data.size > 0
? data.size
: pageSize;
const responseTotal = Number.isFinite(data.total) && data.total >= 0
? data.total
: 0;
if (append) {
packageList.value.push(...groups);
} else {
packageList.value = groups;
}
total.value = responseTotal;
noMore.value = responsePage * responseSize >= total.value;
page.value = responsePage + 1;
} catch (error) {
// The shared request layer handles the API's unified error response and authentication errors.
console.error('加载套餐历史失败', error);
} finally {
loading.value = false;
historyLoaded.value = true;
}
};
const loadMore = () => loadPackageList(true);
onMounted(() => {
loadPackageList();
});
</script>
<style lang="scss" scoped>
.loading-state {
display: flex;
align-items: center;
justify-content: center;
min-height: 500rpx;
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 400rpx;
padding: 120rpx 40rpx;
.empty-icon {
width: 120rpx;
height: 120rpx;
margin-bottom: 30rpx;
opacity: 0.6;
}
.empty-title {
margin-bottom: 16rpx;
font-size: 32rpx;
font-weight: 600;
color: var(--text-primary);
}
.empty-desc {
font-size: 26rpx;
color: var(--text-tertiary);
text-align: center;
}
}
.load-more {
padding: var(--space-lg);
font-size: 24rpx;
color: var(--text-tertiary);
text-align: center;
}
</style>