qrCode.vue 10.3 KB
<!--
 * @Date: 2024-01-16 10:06:47
 * @LastEditors: hookehuyr hookehuyr@gmail.com
 * @LastEditTime: 2024-01-29 10:09:15
 * @FilePath: /xysBooking/src/components/qrCode.vue
 * @Description: 预约码卡组件
-->
<template>
  <div class="qr-code-page">
    <div v-if="userList.length" class="show-qrcode">
      <div class="qrcode-content">
        <div v-if="props.status" class="user-status">
          <div :class="[formatStatus(props.status).key, 'status']">{{ formatStatus(props.status).value }}</div>
        </div>
        <div class="user-info">{{ userinfo.name }}&nbsp;{{ userinfo.id }}</div>
        <div class="user-qrcode">
          <div class="left" @click="prevCode">
            <img src="https://cdn.ipadbiz.cn/xys/booking/%E5%B7%A6@2x.png">
          </div>
          <div class="center">
            <img :src="userList[select_index].qr_code_url ">
            <div v-if="useStatus === STATUS_CODE.CANCELED || useStatus === STATUS_CODE.USED" class="qrcode-used">
              <p>二维码{{ qr_code_status[useStatus] }}</p>
            </div>
          </div>
          <div class="right" @click="nextCode">
            <img src="https://cdn.ipadbiz.cn/xys/booking/%E5%8F%B3@2x.png">
          </div>
        </div>
        <!-- <div class="refresh" @click="refreshBtn">
          <img src="https://cdn.ipadbiz.cn/xys/booking/%E5%88%B7%E6%96%B0@2x.png">&nbsp;<div>刷新</div>
        </div> -->
        <div style="color: red; margin-top: 1rem;">{{ userinfo.datetime }}</div>
      </div>
      <div class="user-list">
        <div
          @click="selectUser(index)"
          v-for="(item, index) in userList"
          :key="index"
          :class="[
            'user-item',
            select_index === index ? 'checked' : '',
            userList.length > 1 && item.sort ? 'border' : '',
          ]">
          {{ item.name }}
        </div>
      </div>
    </div>
    <div v-else class="no-qrcode">
      <img src="https://cdn.ipadbiz.cn/xys/booking/%E6%9A%82%E6%97%A0@2x.png" style="width: 10rem;">
      <div class="no-qrcode-title">您还没有预约过今天参观</div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@/utils/generatePackage.js'
//import { } from '@/utils/generateModules.js'
//import { } from '@/utils/generateIcons.js'
//import { } from '@/composables'

import { qrcodeListAPI, qrcodeStatusAPI, billPersonAPI } from '@/api/index'
const $route = useRoute();
const $router = useRouter();
useTitle($route.meta.title);

const props = defineProps({
  status: {
    type: String,
    default: ''
  },
  type: {
    type: String,
    default: ''
  },
});

const select_index = ref(0);
const userList = ref([]);

const prevCode = () => {
  select_index.value = select_index.value - 1;
  if (select_index.value < 0) {
    select_index.value = userList.value.length - 1;
  }
};
const nextCode = () => {
  select_index.value = select_index.value + 1;
  if (select_index.value > userList.value.length - 1) {
    select_index.value = 0;
  }
};

watch(
  () => select_index.value,
  (index) => {
    // 监听用户选择变化时,刷新二维码
    refreshBtn();
  }
)

/**
 * 生成15位身份证号中间8位替换为*号
 * @param {*} inputString
 */
function replaceMiddleCharacters(inputString) {
  if (inputString?.length < 15) {
    return inputString; // 字符串长度不足,不进行替换
  }

  const start = Math.floor((inputString?.length - 8) / 2); // 开始替换的索引位置
  const end = start + 8; // 结束替换的索引位置

  const replacement = '*'.repeat(8); // 生成包含8个*号的字符串

  const replacedString = inputString?.substring(0, start) + replacement + inputString?.substring(end);
  return replacedString;
}

const formatId = (id) => {
  return replaceMiddleCharacters(id);
};

const userinfo = computed(() => {
  return {
    name: userList.value[select_index.value]?.name,
    id: formatId(userList.value[select_index.value]?.id_number),
    datetime: userList.value[select_index.value]?.datetime,
  };
});

const useStatus = ref('0');

const qr_code_status = {
  '1': '未激活',
  '3': '待使用',
  '5': '被取消',
  '7': '已使用'
};

const STATUS_CODE = {
  APPLY: '1',
  SUCCESS: '3',
  CANCELED: '5',
  USED: '7'
};

// const refreshBtn = async () => {
//   const { code, data } = await qrcodeStatusAPI({ qr_code: userList.value[select_index.value].qr_code });
//   if (code) {
//     useStatus.value = data.status;
//   }
// }

const formatStatus = (status) => {
  switch (status) {
    case 'success':
      return {
        key: 'success',
        value: '预约成功'
      }
    case 'cancel':
      return {
        key: 'cancel',
        value: '已取消'
      }
    case 'used':
      return {
        key: 'used',
        value: '已使用'
      }
  }
}

const selectUser = (index) => {
  select_index.value = index;
}

const pay_id = $route.query.pay_id;

const formatGroup = (data) => {
  // 在每个相同 pay_id 组的最后一个数据项中添加字段
  let lastPayId = null;
  for (let i = 0; i < data.length; i++) {
    if (data[i].pay_id !== lastPayId) {
      data[i].sort = 1;
      lastPayId = data[i].pay_id;
    } else {
      data[i].sort = 0;
    }
  }
  return data;
}

onMounted(async () => {
  if (!props.type) {
    const { code, data } = await qrcodeListAPI();
    if (code) {
      data.forEach(item => {
        // 生成二维码地址
        item.qr_code_url = 'http://oa.onwall.cn/admin?m=srv&a=get_qrcode&key=' + item.qr_code;
        // 二维码使用时间
        let begin_time = item.begin_time.slice(0, -3);
        let end_time = item.end_time.slice(0, -3);
        let str = begin_time + ' ' + end_time;
        //
        item.datetime = `${str.split(' ')[0]} ${str.split(' ')[1]}-${str.split(' ')[3]}`;
        item.sort = 0;
      });
      const { code: status_code, data: status_data } = await qrcodeStatusAPI({ qr_code: data[select_index.value]?.qr_code });
      if (status_code) {
        useStatus.value = status_data.status;
        // 剔除qr_code为空的二维码
        userList.value = data.filter(item => item.qr_code !== '');
        // TAG: 预约码入口的才需要分组
        userList.value = formatGroup(userList.value);
      }
    }
  } else {
    const { code, data } = await billPersonAPI({ pay_id });
    if (code) {
      data.forEach(item => {
        // 生成二维码地址
        item.qr_code_url = 'http://oa.onwall.cn/admin?m=srv&a=get_qrcode&key=' + item.qr_code;
        item.sort = 0;
      });
      const { code: status_code, data: status_data } = await qrcodeStatusAPI({ qr_code: data[select_index.value]?.qr_code });
      if (status_code) {
        useStatus.value = status_data.status;
        // 剔除qr_code为空的二维码
        userList.value = data.filter(item => item.qr_code !== '');
      }
    }
  }
});

// 定义轮询函数
const poll = async () => {
  // 二维码未使用不停轮询接口
  if (userList.value.length && useStatus.value === STATUS_CODE.SUCCESS) {
    const { code, data } = await qrcodeStatusAPI({ qr_code: userList.value[select_index.value].qr_code });
    if (code) {
      useStatus.value = data.status;
    }
  }
};

// 每秒执行一次轮询函数
const intervalId = setInterval(poll, 1000);

// 在组件卸载时清除定时器
onUnmounted(() => {
  clearInterval(intervalId);
});
</script>

<style lang="less" scoped>
.qr-code-page {
  .qrcode-content {
    padding: 1rem 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    // width: 100%;
    // height: 100%;
    background-color: #FFF;
    border-radius: 8px;
    box-shadow: 0rem 0rem 0.92rem 0rem rgba(106,106,106,0.27);
    .user-status {
      .status {
        font-size: 0.75rem;
        padding: 5px 8px;
        border-radius: 5px;
      }
      .success {
        color: #A67939;
        background-color: #FBEEDC;
      }
      .cancel {
        color: #929292;
        background-color: #E6E6E6;
      }
      .used {
        color: #477F3D;
        background-color: #E5EFE3;
      }
    }
    .user-info {
      color: #A6A6A6;
      font-size: 1.15rem;
      margin-top: 0.5rem;
      margin-bottom: 0.5rem;
    }
    .user-qrcode {
      display: flex;
      align-items: center;
      .left {
        img {
          width: 1.75rem; margin-right: 0.5rem;
        }
      }
      .center {
        border: 1px solid #D1D1D1;
        border-radius: 20px;
        padding: 0.5rem;
        position: relative;
        img {
          width: 15rem;
        }
        div {
          position: absolute;
          top: 0;
          left: 0;
          right: 0;
          bottom: 0;
          background-image: url('https://cdn.ipadbiz.cn/xys/booking/southeast.jpeg');
          background-size: contain;
          border-radius: 20px;
          color: #FFF;
          text-align: center;
          p {
            color: #A67939;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            font-size: 1.2rem;
          }
        }
      }
      .right {
        img {
          width: 1.75rem;
          margin-left: 0.5rem;
        }
      }
    }
    .refresh {
      display: flex;
      justify-content: center;
      align-items: center;
      margin-top: 1rem;
      img {
        width: 3.5rem;
      }
      div {
        color: #A67939; font-size: 1.1rem;
      }
    }
  }
  .user-list {
    display: flex;
    padding: 1rem;
    align-items: center;
    flex-wrap: wrap;
    .user-item {
      position: relative;
      padding: 0.25rem 0.5rem;
      border: 1px solid #A67939;
      margin: 0.25rem;
      border-radius: 5px;
      color: #A67939;
      &.checked {
        color: #FFF;
        background-color: #A67939;
      }
      &.border {
        margin-right: 0.5rem;
        &::after {
          position: absolute;
          right: -0.5rem;
          top: calc(50% - 0.5rem);
          content: '';
          height: 1rem;
          border-right: 1px solid #A67939;
        }
      }
    }
  }

  .no-qrcode {
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    margin-bottom: 1rem;
    img {
      margin-top: 1rem;
      margin-bottom: 1rem;
      width: 10rem;
    }
    .no-qrcode-title {
      color: #A67939;
      font-size: 1.05rem;
    }
  }
}
</style>