mail.vue 7.43 KB
<template>
  <view class="cert-mail-page">
    <!-- 列表区域 -->
    <view class="appList">
      <view class="appItem" v-for="(item, index) in infoList" :key="index">
        <view @click="handleView(item)">
          <view class="status">
            <text :class="item.postStatus == 1 ? 'text-success' : 'text-warning'">
              {{ item.postStatus == 1 ? '已邮寄' : '未邮寄' }}
            </text>
          </view>
          <view class="date" v-if="item.submitTime">
            <view class="text-primary" v-if="item.payCode">{{ item.payCode }}</view>
          </view>
          
          <view class="name mt0">{{ item.name }}</view>
          <view class="flexbox">
            <view>
              缴费单位
              <view>{{ item.memberName }}</view>
            </view>
            <view>
              证书人数
              <view>{{ item.totalNum }}</view>
            </view>
          </view>
          <view class="flex f-j-s">
            <view class="mail-time" v-if="item.submitTime">
              邮寄时间:{{ formatDate(item.submitTime) }}
            </view>
            <view class="mail-time" v-if="item.postCode ">
              <view>物流编号{{ item.postCode || '-' }}</view>
            </view>
          </view>
        </view>
        <view class="func">
          <button
            v-if="deptType == '1' && item.postStatus != 1"
            class="btn-mail"
            @click.stop="handleMail(item)"
          >邮寄证书</button>
          <button class="btn-logistics" @click.stop="handleLogistics(item)">物流跟踪</button>
        </view>
      </view>
    </view>

    <!-- 空数据 -->
    <view class="nodata" v-if="infoList.length == 0 && !loading">
      <image mode="aspectFit" :src="config.baseUrl_api + '/fs/static/nodata.png'"></image>
      <text>暂无数据</text>
    </view>

    <!-- 上拉加载 -->
    <view class="loading">
      <uni-load-more :status="loadStatus" :contentText="loadMoreText"></uni-load-more>
    </view>
  </view>
</template>

<script setup>
import * as api from '@/common/api.js'
import config from '@/config.js'
import { ref, computed } from 'vue'
import { onLoad, onShow, onReachBottom } from '@dcloudio/uni-app'

const app = getApp()
const loading = ref(false)

// 加载状态
const loadStatus = ref('more') // more / loading / nomore
const loadMoreText = {
  contentdown: '上拉加载更多',
  contentrefresh: '正在加载...',
  contentnomore: '没有更多了'
}

// 请求参数
const queryParams = ref({
  pageNum: 1,
  pageSize: 10,
  type: '1'
})

// 列表数据
const infoList = ref([])
const total = ref(0)
const deptType = ref('')

onLoad((options) => {
  if (options.type) {
    queryParams.value.type = options.type
  }
})

onShow(() => {
  if (app.globalData.isLogin) {
    init()
  } else {
    app.firstLoadCallback = () => {
      init()
    }
  }
})

// 初始化(刷新)
function init() {
  deptType.value = app.globalData.deptType
  // 重置列表和页码
  infoList.value = []
  queryParams.value.pageNum = 1
  loadStatus.value = 'more'
  getList()
}

// 获取列表
function getList() {
  // 没有更多数据直接返回
  if (loadStatus.value === 'nomore') return
  
  loading.value = true
  loadStatus.value = 'loading'
  uni.showLoading({ title: '加载中' })

  api.paymentList({ ...queryParams.value }).then(res => {
    const data = res.rows || []
    const totalData = res.total || 0
    
    // 拼接数据
    infoList.value = [...infoList.value, ...data]
    total.value = totalData
    
    // 判断是否还有更多
    if (infoList.value.length >= totalData) {
      loadStatus.value = 'nomore'
    } else {
      loadStatus.value = 'more'
    }
    
    loading.value = false
    uni.hideLoading()
  }).catch(() => {
    loading.value = false
    uni.hideLoading()
    loadStatus.value = 'more'
  })
}

// 上拉加载下一页
onReachBottom(() => {
  if (loadStatus.value !== 'more' || loading.value) return
  queryParams.value.pageNum++
  getList()
})

// 查看详情
function handleView(item) {
  uni.navigateTo({
    url: `/level/ztx/certDetail?examId=${item.examId}`
  })
}

// 邮寄证书
async function handleMail(item) {
  const res = await uni.showModal({
    title: '提示',
    content: '是否确认寄送快递?',
    confirmText: '确认',
    cancelText: '取消'
  })

  if (res.confirm) {
    uni.showLoading({ title: '操作中' })
    api.postCert(item.payId).then(() => {
      uni.hideLoading()
      uni.showToast({ title: '操作成功', icon: 'success' })
      // 操作成功后刷新列表
      init()
    }).catch(() => {
      uni.hideLoading()
    })
  }
}

// 物流跟踪
function handleLogistics(item) {
  if (item.postStatus != 1 || !item.postCode) {
    uni.showToast({ title: '暂无物流信息', icon: 'none' })
    return
  }
  uni.navigateTo({
    url: `/level/ztx/certLogistics?payId=${item.payId}&postCode=${item.postCode}&postStatus=${item.postStatus}&submitTime=${item.submitTime || ''}`
  })
}

// 时间格式化
function formatDate(dateStr) {
  if (!dateStr) return '-'
  return dateStr.substring(0, 10)
}

// 等级转中文
function levelToChinese(level) {
  const levelMap = {
    '1': '一', '2': '二', '3': '三', '4': '四', '5': '五',
    '6': '六', '7': '七', '8': '八', '9': '九', '10': '十'
  }
  return levelMap[String(level)] || level
}
</script>

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

/* 列表区域 */
.appList {
  padding: 0 20rpx;
}

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

  .status {
    display: inline-block;
    padding: 6rpx 20rpx;
    border-radius: 20rpx;
    font-size: 24rpx;
    margin-bottom: 16rpx;

    .text-success {
      color: #4caf50;
    }

    .text-warning {
      color: #ff9800;
    }
  }

  .date {
    font-size: 24rpx;
    color: #999;
  }

  .text-primary {
    font-size: 28rpx;
    color: #AD181F;
  }

  .name {
    font-size: 28rpx;
    font-weight: 600;
    color: #333;
    margin-bottom: 20rpx;
    margin-top: 10rpx;

    &.mt0 {
      margin-top: 0;
    }
  }

  .flexbox {
    display: flex;
    justify-content: space-between;
    background-color: #fafafa;
    border-radius: 12rpx;
    padding: 20rpx;
    margin: 20rpx 0;

    view {
      flex: 1;
      text-align: center;
      font-size: 24rpx;
      color: #999;

      view {
        font-size: 28rpx;
        color: #333;
        font-weight: 500;
        margin-top: 8rpx;
      }
    }
  }

  .mail-time {
    font-size: 24rpx;
    color: #666;
    margin-top: 16rpx;
  }

  .func {
    display: flex;
    gap: 20rpx;
    margin-top: 24rpx;
    padding-top: 24rpx;
    border-top: 1px solid #f0f0f0;
    justify-content: flex-end;
    
    button {
      height: 64rpx;
      line-height: 64rpx;
      font-size: 26rpx;
      border-radius: 32rpx;
      border: none;
    }

    .btn-mail {
      width: 100px;
      background: linear-gradient(135deg, #4caf50, #66bb6a);
      color: #fff;
    }

    .btn-logistics {
      width: 100px;
      background: linear-gradient(135deg, #2196f3, #42a5f5);
      color: #fff;
    }
  }
}

.nodata {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 100rpx 0;

  image {
    width: 300rpx;
    height: 300rpx;
  }

  text {
    font-size: 28rpx;
    color: #999;
    margin-top: 20rpx;
  }
}

.loading {
  padding: 30rpx 0;
  text-align: center;
}
</style>