Files
shop-toy/src/pagesBank/report/download.vue
2025-12-25 17:18:12 +08:00

461 lines
10 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.

<script lang="ts" setup>
import { downloadReport } from '@/pagesBank/api'
import { DateDimension } from '@/typings/bank'
definePage({
style: {
navigationBarTitleText: '报表下载',
},
})
// 从路由参数获取报表信息
const reportId = ref('')
const reportName = ref('')
// 日期维度选项
const dimensionOptions = [
{ label: '按日', value: DateDimension.DAY },
{ label: '按月', value: DateDimension.MONTH },
{ label: '按季', value: DateDimension.QUARTER },
{ label: '自定义', value: DateDimension.CUSTOM },
]
// 当前选中的日期维度
const activeDimension = ref(DateDimension.DAY)
// 当前选中的日期
const selectedDate = ref('2025-12-25')
// 日期选择器显示状态
const showDatePicker = ref(false)
// 下载中状态
const downloading = ref(false)
// 获取日期维度标签
function getDimensionLabel(dimension: DateDimension) {
const option = dimensionOptions.find(opt => opt.value === dimension)
return option?.label || ''
}
// 切换日期维度
function handleDimensionChange(dimension: DateDimension) {
activeDimension.value = dimension
// 根据维度更新默认日期
updateDefaultDate(dimension)
}
// 根据维度更新默认日期
function updateDefaultDate(dimension: DateDimension) {
const now = new Date()
const year = now.getFullYear()
const month = String(now.getMonth() + 1).padStart(2, '0')
const day = String(now.getDate()).padStart(2, '0')
switch (dimension) {
case DateDimension.DAY:
selectedDate.value = `${year}-${month}-${day}`
break
case DateDimension.MONTH:
selectedDate.value = `${year}-${month}`
break
case DateDimension.QUARTER:
const quarter = Math.floor(now.getMonth() / 3) + 1
selectedDate.value = `${year}-Q${quarter}`
break
case DateDimension.CUSTOM:
selectedDate.value = `${year}-${month}-${day}`
break
}
}
// 显示日期选择器
function showDateSelector() {
showDatePicker.value = true
}
// 日期选择确认
function handleDateConfirm(e: any) {
const { value } = e
const date = new Date(value)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
if (activeDimension.value === DateDimension.MONTH) {
selectedDate.value = `${year}-${month}`
} else {
selectedDate.value = `${year}-${month}-${day}`
}
showDatePicker.value = false
}
// 下载报表
async function handleDownload() {
if (downloading.value) return
downloading.value = true
try {
await downloadReport({
reportId: reportId.value,
dimension: activeDimension.value,
date: selectedDate.value
})
uni.showToast({
title: '下载成功',
icon: 'success'
})
} catch (error) {
uni.showToast({
title: '下载失败',
icon: 'none'
})
} finally {
downloading.value = false
}
}
onLoad((options: any) => {
if (options.reportId) {
reportId.value = options.reportId
}
if (options.reportName) {
reportName.value = decodeURIComponent(options.reportName)
}
})
</script>
<template>
<view class="download-page">
<!-- 报表信息卡片 -->
<view class="report-info-card">
<view class="report-icon">
<text class="i-carbon-document"></text>
</view>
<view class="report-details">
<text class="report-name">{{ reportName }}</text>
<text class="report-id">报表编号: {{ reportId }}</text>
</view>
</view>
<!-- 日期维度筛选 -->
<view class="dimension-section">
<view class="section-title">选择日期维度</view>
<view class="dimension-tabs">
<view
v-for="option in dimensionOptions"
:key="option.value"
class="dimension-tab"
:class="{ active: activeDimension === option.value }"
@click="handleDimensionChange(option.value)"
>
{{ option.label }}
</view>
</view>
</view>
<!-- 日期选择 -->
<view class="date-section">
<view class="section-title">选择日期</view>
<view class="date-picker" @click="showDateSelector">
<view class="date-display">
<text class="i-carbon-calendar"></text>
<text class="date-value">{{ selectedDate }}</text>
</view>
<text class="i-carbon-chevron-right"></text>
</view>
</view>
<!-- 下载区域 -->
<view class="download-section">
<view class="format-tag">EXCEL</view>
<button
class="download-btn"
:class="{ loading: downloading }"
:disabled="downloading"
@click="handleDownload"
>
<text v-if="downloading" class="i-carbon-circle-dash loading-icon"></text>
<text>{{ downloading ? '下载中...' : '点击下载' }}</text>
</button>
</view>
<!-- 使用帮助 -->
<view class="help-section">
<view class="help-title">
<text class="i-carbon-help"></text>
<text>Excel格式: 使用帮助</text>
</view>
<view class="help-content">
<view class="help-item">
<text class="help-number">1</text>
<text class="help-text">选择要下载报表的日期</text>
</view>
<view class="help-item">
<text class="help-number">2</text>
<text class="help-text">点击下载按钮进行下载</text>
</view>
<view class="help-item">
<text class="help-number">3</text>
<text class="help-text">下载后自动打开文件可以点击手机右上角的...进行转发或保存文件</text>
</view>
</view>
</view>
<!-- 日期选择器弹窗 -->
<wd-datetime-picker
v-model="selectedDate"
v-model:show="showDatePicker"
type="date"
@confirm="handleDateConfirm"
@cancel="showDatePicker = false"
/>
</view>
</template>
<style lang="scss" scoped>
.download-page {
min-height: 100vh;
background: #f8f9fa;
padding: 30rpx;
}
.report-info-card {
background: #fff;
border-radius: 24rpx;
padding: 30rpx;
display: flex;
align-items: center;
gap: 24rpx;
margin-bottom: 24rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.02);
.report-icon {
width: 96rpx;
height: 96rpx;
background: linear-gradient(135deg, #00c05a 0%, #34d19d 100%);
border-radius: 20rpx;
display: flex;
align-items: center;
justify-content: center;
text {
font-size: 48rpx;
color: #fff;
}
}
.report-details {
flex: 1;
.report-name {
font-size: 32rpx;
font-weight: 700;
color: #333;
display: block;
margin-bottom: 8rpx;
}
.report-id {
font-size: 24rpx;
color: #999;
}
}
}
.dimension-section,
.date-section {
background: #fff;
border-radius: 24rpx;
padding: 30rpx;
margin-bottom: 24rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.02);
}
.section-title {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 24rpx;
}
.dimension-tabs {
display: flex;
gap: 16rpx;
.dimension-tab {
flex: 1;
height: 72rpx;
background: #f8f9fa;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
color: #666;
transition: all 0.2s;
&.active {
background: #00c05a;
color: #fff;
font-weight: 600;
}
}
}
.date-picker {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx;
background: #f8f9fa;
border-radius: 16rpx;
.date-display {
display: flex;
align-items: center;
gap: 16rpx;
text:first-child {
font-size: 36rpx;
color: #00c05a;
}
.date-value {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
}
text:last-child {
font-size: 28rpx;
color: #adb5bd;
}
}
.download-section {
background: #fff;
border-radius: 24rpx;
padding: 40rpx 30rpx;
margin-bottom: 24rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.02);
display: flex;
flex-direction: column;
align-items: center;
gap: 30rpx;
.format-tag {
font-size: 24rpx;
color: #00c05a;
background: rgba(0, 192, 90, 0.1);
padding: 8rpx 24rpx;
border-radius: 8rpx;
font-weight: 600;
}
.download-btn {
width: 100%;
height: 96rpx;
background: linear-gradient(135deg, #00c05a 0%, #34d19d 100%);
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
font-size: 32rpx;
font-weight: 600;
color: #fff;
border: none;
transition: all 0.2s;
&:active:not(:disabled) {
opacity: 0.8;
transform: scale(0.98);
}
&:disabled {
opacity: 0.6;
}
&.loading {
opacity: 0.8;
}
.loading-icon {
font-size: 32rpx;
animation: spin 1s linear infinite;
}
}
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.help-section {
background: #fff;
border-radius: 24rpx;
padding: 30rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.02);
.help-title {
display: flex;
align-items: center;
gap: 12rpx;
margin-bottom: 24rpx;
text:first-child {
font-size: 32rpx;
color: #4d80f0;
}
text:last-child {
font-size: 28rpx;
font-weight: 600;
color: #333;
}
}
.help-content {
.help-item {
display: flex;
align-items: flex-start;
gap: 16rpx;
margin-bottom: 20rpx;
&:last-child {
margin-bottom: 0;
}
.help-number {
width: 40rpx;
height: 40rpx;
background: #4d80f0;
color: #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 22rpx;
font-weight: 600;
flex-shrink: 0;
}
.help-text {
flex: 1;
font-size: 26rpx;
color: #666;
line-height: 1.6;
}
}
}
}
</style>