costSettlementConfirm.vue 8.08 KB
<template>
  <view class="settlement-confirm-page">
    <!-- 统计卡片区 -->
    <view class="stats-grid">
      <view class="stat-card">
        <view class="stat-label">考试总人数</view>
        <view class="stat-value">{{ form.personCount || 0 }}<text class="stat-unit"></text></view>
      </view>
      <view class="stat-card">
        <view class="stat-label">费用合计</view>
        <view class="stat-value">{{ form.allFee || '0.00' }}<text class="stat-unit"></text></view>
      </view>
      <view class="stat-card">
        <view class="stat-label">服务费用</view>
        <view class="stat-value text-red">{{ form.fee || '0.00' }}<text class="stat-unit"></text></view>
      </view>
    </view>

    <!-- 级别分布明细 -->
    <view class="level-section">
      <view class="section-title">级别分布明细</view>
      <view class="level-tags">
        <view v-for="(val, inx) in form.count" :key="inx" class="level-tag" :class="`level-${inx % 3 + 1}`">
          {{ szToHz(inx) }}级:{{ val }}
        </view>
      </view>
    </view>

    <view class="divider"></view>

    <!-- 发票上传区域 -->
    <view class="upload-section">
      <view class="section-title">发票上传</view>
      <view class="upload-area">
        <view class="upload-tip">支持格式:jpg、png、pdf,大小不超过10MB</view>
        <uni-file-picker
          v-model="fileList"
          file-mediatype="image"
          file-extname="jpg,jpeg,png,pdf"
          :limit="1"
          @select="selectFile"
          @progress="fileProgress"
          @success="fileSuccess"
          @delete="fileDelete"
        >
          <view class="upload-btn" v-if="!fileList.length">
            <uni-icons type="plus" size="24" color="#AD181F"></uni-icons>
            <!-- <text>上传发票</text> -->
          </view>
          <view v-else class="file-item">
            <uni-icons type="paperclip" size="16" color="#AD181F"></uni-icons>
            <text class="file-name">{{ fileList[0].name }}</text>
          </view>
        </uni-file-picker>
      </view>
    </view>

    <!-- 底部操作按钮 -->
    <view class="bottom-bar">
      <view class="cancel-btn" @click="handleCancel">取消</view>
      <view class="submit-btn" @click="handleSubmit">提交结算申请</view>
    </view>
  </view>
</template>

<script setup>
import * as api from '@/common/api_exam.js'
import { uploadFileList } from '@/common/api.js'
import { ref,  } from 'vue';
import {  onLoad } from '@dcloudio/uni-app'

const form = ref({})
const fileList = ref([])
const loading = ref(false)
const ids = ref('')
const uploadedUrl = ref('') // 上传后的文件路径

onLoad((options) => {
  const { ids: optIds } = options
  if (optIds) {
    ids.value = optIds
    getConfirm(optIds)
  }
})

// 数字转汉字
function szToHz(num) {
  const arr = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
  return arr[num] || num + 1
}

async function getConfirm(ids) {
  loading.value = true
  try {
    const res = await api.settlementConfirm(ids)
    form.value = res.data || {}
  } catch (err) {
    console.error('获取结算明细失败', err)
    uni.showToast({ title: '获取数据失败', icon: 'none' })
  } finally {
    loading.value = false
  }
}

function selectFile(e) {
  const file = e.tempFiles[0]
  if (!file) return
  uni.showLoading({ title: '上传中' })
  uploadFileList(e.tempFilePaths[0]).then(data => {
    uploadedUrl.value = data
    uni.hideLoading()
    uni.showToast({ title: '上传成功', icon: 'success' })
  }).catch(err => {
    uni.hideLoading()
    uni.showToast({ title: '上传失败', icon: 'none' })
  })
}

function fileProgress(e) {
  console.log('上传进度:', e)
}

function fileSuccess(e) {
  console.log('上传成功:', e)
}

function fileDelete(e) {
  fileList.value = []
  uploadedUrl.value = ''
}

function handleCancel() {
  uni.navigateBack()
}

async function handleSubmit() {
  if (!uploadedUrl.value) {
    uni.showToast({ title: '请上传发票', icon: 'none' })
    return
  }

  // 使用上传后的真实路径
  const url = JSON.stringify([{ url: uploadedUrl.value, name: fileList.value[0]?.name || 'invoice' }])

  try {
    uni.showLoading({ title: '提交中...' })
    await api.settlementCommit({ ids: ids.value, url })
    uni.hideLoading()
    uni.showToast({ title: '提交成功', icon: 'success' })
    setTimeout(() => {
      uni.navigateBack({
        delta: 2 // 返回两级页面
      })
    }, 1500)
  } catch (err) {
    uni.hideLoading()
    console.error('提交失败', err)
    uni.showToast({ title: '提交失败', icon: 'none' })
  }
}
</script>

<style lang="scss" scoped>
.settlement-confirm-page {
  min-height: 100vh;
  background-color: #f5f5f5;
  padding: 20rpx;
  padding-bottom: 140rpx;
}

.stats-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20rpx;
  margin-bottom: 20rpx;
}

.stat-card {
  background: #fff;
  border-radius: 16rpx;
  padding: 30rpx 20rpx;
  text-align: center;
  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);

  .stat-label {
    font-size: 24rpx;
    color: #999;
    margin-bottom: 12rpx;
  }

  .stat-value {
    font-size: 36rpx;
    font-weight: 700;
    color: #333;
    line-height: 1.2;
  }

  .stat-unit {
    font-size: 24rpx;
    font-weight: 400;
    color: #999;
    margin-left: 4rpx;
  }

  .text-red {
    color: #AD181F;
  }
}

.level-section {
  background: #fff;
  border-radius: 16rpx;
  padding: 30rpx;
  margin-bottom: 20rpx;
  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
  border-left: 8rpx solid #27a9e7;

  .section-title {
    font-size: 28rpx;
    font-weight: 600;
    color: #333;
    margin-bottom: 24rpx;
  }

  .level-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 20rpx;

    .level-tag {
      padding: 12rpx 24rpx;
      border-radius: 30rpx;
      font-size: 24rpx;
      font-weight: 500;
      background: #fff;
      box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
    }

    .level-1 {
      background: linear-gradient(135deg, #fef2e8, #ffe4d6);
      color: #c2410c;
    }

    .level-2 {
      background: linear-gradient(135deg, #eef2ff, #e0e7ff);
      color: #1e40af;
    }

    .level-3 {
      background: linear-gradient(135deg, #ecfdf5, #d1fae5);
      color: #065f46;
    }
  }
}

.divider {
  height: 1rpx;
  background-color: #eee;
  margin: 20rpx 0;
}

.upload-section {
  background: #fff;
  border-radius: 16rpx;
  padding: 30rpx;
  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);

  .section-title {
    font-size: 28rpx;
    font-weight: 600;
    color: #333;
    margin-bottom: 24rpx;
  }

  .upload-area {
    background: #fafcff;
    padding: 24rpx;
    border-radius: 12rpx;
    border: 2rpx dashed #cbd5e1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 20rpx;

    .upload-tip {
      font-size: 24rpx;
      color: #999;
      text-align: center;
    }

    .upload-btn {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 12rpx;
      padding: 30rpx 60rpx;
      border-radius: 16rpx;
      color: #AD181F;
      font-size: 28rpx;
    }

    .file-item {
      display: flex;
      align-items: center;
      gap: 12rpx;
      padding: 20rpx 30rpx;
      background: #fff;
      border-radius: 12rpx;
      border: 1rpx solid #eee;

      .file-name {
        font-size: 26rpx;
        color: #333;
        max-width: 400rpx;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
    }
  }
}

.bottom-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background-color: #fff;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20rpx 30rpx;
  padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
  box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
  z-index: 99;

  .cancel-btn {
    flex: 1;
    text-align: center;
    padding: 24rpx 0;
    border-radius: 40rpx;
    font-size: 28rpx;
    background-color: #f5f5f5;
    color: #666;
    margin-right: 20rpx;
  }

  .submit-btn {
    flex: 2;
    text-align: center;
    padding: 24rpx 0;
    border-radius: 40rpx;
    font-size: 28rpx;
    background-color: #AD181F;
    color: #fff;
  }
}
</style>