hookehuyr

feat(recall): 添加用户信息缓存功能并优化活动历史逻辑

- 在IDQueryPage和CompleteInfoPage中添加用户信息缓存到localStorage
- 修改timeline.vue和ActivityHistoryPage.vue从缓存获取用户信息
- 添加批量活动报名接口并实现收集星球币功能
- 优化活动历史日期显示逻辑
/*
* @Date: 2025-12-24 12:26:27
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-12-24 12:37:23
* @LastEditTime: 2025-12-24 18:36:29
* @FilePath: /mlaj/src/api/points.js
* @Description: 积分相关接口
*/
......@@ -9,6 +9,7 @@ import { fn, fetch } from './fn';
const Api = {
POINTS_LIST: '/srv/?a=points&t=list',
OLD_ACTIVITY_BATCH_ACTIVITY_REGISTRATION: '/srv/?a=points&t=old_activity_batch_activity_registration',
}
/**
......@@ -25,3 +26,21 @@ const Api = {
* }
*/
export const getPointsListAPI = (params) => fn(fetch.get(Api.POINTS_LIST, params));
/**
* @description 召回老客户-批量活动报名
* @param {*} params {
* name: 姓名
* mobile: 手机号
* idcard: 身份证号
* activity_ids: 活动id列表, 逗号分隔
* }
* @returns data: {
* payment_qty: 已报名活动数量
* volunteer_qty: 已报名志愿者数量
* record_date: 报名记录日期
* last_activity_date: 最后活动日期
* }
*/
export const oldActivityBatchActivityRegistrationAPI = (params) => fn(fetch.post(Api.OLD_ACTIVITY_BATCH_ACTIVITY_REGISTRATION, params));
......
......@@ -4,7 +4,7 @@
<div class="w-full relative h-[180px] overflow-hidden">
<img :src="historyBg" class="w-full h-full object-cover" alt="History Banner" />
<div class="absolute inset-0 flex flex-col justify-center items-center text-center px-4">
<h1 class="text-[#FFDD01] text-3xl font-bold mb-2 tracking-wider drop-shadow-md mt-3">2020-2025</h1>
<h1 class="text-[#FFDD01] text-3xl font-bold mb-2 tracking-wider drop-shadow-md mt-3">{{ recordDate }}</h1>
<h2 class="text-white text-2xl font-bold mb-4 tracking-wider drop-shadow-md">您的活动历史</h2>
<div class="w-full max-w-md rounded-lg px-4 py-2"
......@@ -63,6 +63,7 @@
<!-- Fixed Bottom Buttons -->
<div
v-if="!userInfo.has_activity_registration"
class="fixed bottom-0 left-0 right-0 bg-white/60 backdrop-blur-md p-4 pb-8 z-30 shadow-[0_-2px_10px_rgba(0,0,0,0.05)]">
<van-button block color="#0052D9" class="!rounded-lg !mb-3 !h-[44px] !text-base !font-bold"
@click="handleCollectCoins">
......@@ -106,6 +107,7 @@ import { useTitle } from '@vueuse/core'
import { showToast } from 'vant'
import { userInfoAPI, searchOldActivityAPI } from '@/api/recall_users'
import { oldActivityBatchActivityRegistrationAPI } from '@/api/points'
const historyBg = 'https://cdn.ipadbiz.cn/mlaj/recall/img/history_bg@2x.png'
......@@ -125,9 +127,30 @@ const handleGeneratePoster = (item) => {
// showToast('生成海报: ' + item.title)
}
const handleCollectCoins = () => {
// showToast('收集星球币成功')
const handleCollectCoins = async () => {
// 从缓存获取用户信息
const cachedUserInfo = localStorage.getItem('cached_user_info')
if (cachedUserInfo) {
const userInfo = JSON.parse(cachedUserInfo)
// 调用积分接口
const res = await oldActivityBatchActivityRegistrationAPI({
name: userInfo.name || '',
mobile: userInfo.phone || '',
idcard: userInfo.idCard || '',
old_activity_data: campaign_info.value
})
if (res.code) {
showToast({
message: '收集星球币成功',
icon: 'success'
})
router.push({ path: '/recall/points' })
} else {
showToast({
message: '收集星球币失败',
icon: 'error'
})
}
}
const handleSubmitMissing = () => {
......@@ -147,20 +170,29 @@ const handleSubmitMissing = () => {
missingInfo.value = ''
}
const userInfo = ref({});
const campaign_info = ref([]);
// 记录日期
const recordDate = ref('')
onMounted(async () => {
// 获取用户信息
const userInfoRes = await userInfoAPI()
if (userInfoRes.code) {
// 从缓存获取用户信息
const cachedUserInfo = localStorage.getItem('cached_user_info')
if (cachedUserInfo) {
const userInfo = JSON.parse(cachedUserInfo)
if (userInfo.name && userInfo.phone && userInfo.idCard) {
// 通过用户信息获取活动历史信息
const activityRes = await searchOldActivityAPI({
name: userInfoRes.data?.user_name || '',
mobile: userInfoRes.data?.mobile || '',
idcard: userInfoRes.data?.idcard || ''
name: userInfo.name,
mobile: userInfo.phone,
idcard: userInfo.idCard
})
if (activityRes.code) {
// 获取历史列表数据
const campaign_info = activityRes.data?.campaign_info || []
if (campaign_info.length) {
campaign_info.value = campaign_info;
activities.value = campaign_info.map(item => ({
id: item.campaign_id || 0,
stu_uid: item.stu_uid || '',
......@@ -170,8 +202,36 @@ onMounted(async () => {
date: item.create_time?.substring(0, 10) || '',
total: item.fee_stu * item.stu_cnt || 0
}))
// 遍历日期把列表date字段从小到大排序, 获取到其中日期段 比如 2020-2025
const sortedDates = activities.value.map(item => item.date).sort((a, b) => new Date(a) - new Date(b))
recordDate.value = sortedDates[0]?.substring(0, 4) + '-' + sortedDates[sortedDates.length - 1]?.substring(0, 4) || ''
}
}
}
} else {
// 如果是收集完成没有缓存字段的情况, 直接查接口
const activityRes = await searchOldActivityAPI()
if (activityRes.code) {
// 获取历史列表数据
const campaign_info = activityRes.data?.campaign_info || []
if (campaign_info.length) {
activities.value = campaign_info.map(item => ({
id: item.campaign_id || 0,
stu_uid: item.stu_uid || '',
title: item.campaign_name || '',
price: item.fee_stu || 0,
count: item.stu_cnt || 0,
date: item.create_time?.substring(0, 10) || '',
total: item.fee_stu * item.stu_cnt || 0
}))
}
}
}
// 获取用户信息
const userInfoRes = await userInfoAPI()
if (userInfoRes.code) {
userInfo.value = userInfoRes.data.user || {};
}
})
</script>
......
......@@ -135,6 +135,13 @@ const handleConfirm = async () => {
// 获取历史列表数据
const campaign_info = activityRes.data?.campaign_info || []
if (campaign_info.length) {
// 有历史数据, 保存用户信息到缓存
localStorage.setItem('cached_user_info', JSON.stringify({
name: form.name,
phone: form.phone,
idCard: form.idCard
}));
// 有历史数据, 跳转到timeline
router.push('/recall/timeline')
return
......
......@@ -160,6 +160,13 @@ const handleConfirm = async () => {
// 如果能查到数据, 则跳转到timeline, 否则弹出提示
const flag = campaign_info.length > 0;
if (flag) {
// 有历史数据, 保存用户信息到缓存
localStorage.setItem('cached_user_info', JSON.stringify({
name: name.value,
phone: phone.value,
idCard: idCard.value
}));
router.push('/recall/timeline')
return
}
......
......@@ -88,10 +88,11 @@ import { ref, computed, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { showToast } from 'vant'
import { useTitle } from '@vueuse/core'
// 导入接口
import { smsAPI } from '@/api/common'
import { loginAPI, userInfoAPI } from '@/api/recall_users'
import { useTracking } from '@/composables/useTracking'
// 导入图片
const titleImg = 'https://cdn.ipadbiz.cn/mlaj/recall/img/title01@2x.png'
const bgImg = 'https://cdn.ipadbiz.cn/mlaj/recall/img/bg01@2x.png'
......
......@@ -12,7 +12,7 @@
<!-- Title Section -->
<div class="flex flex-col items-center mb-8 animate-fade-in-down">
<h2 class="text-[#FFDD01] text-2xl font-bold mb-4 tracking-wider">@{{ userInfo.value.name }}</h2>
<h2 class="text-[#FFDD01] text-2xl font-bold mb-4 tracking-wider">@{{ userInfo.name }}</h2>
<img :src="title03" class="w-64 object-contain" alt="Welcome Back" />
</div>
......@@ -46,7 +46,7 @@
<!-- Title Section -->
<div class="flex flex-col items-center mb-10 animate-fade-in-down">
<img :src="title04" class="w-64 object-contain mb-4" alt="My Footprints" />
<h2 class="text-[#FFDD01] text-2xl font-bold tracking-wider">@{{ userInfo.value.name }}</h2>
<h2 class="text-[#FFDD01] text-2xl font-bold tracking-wider">@{{ userInfo.name }}</h2>
</div>
<!-- Card Section -->
......@@ -164,16 +164,17 @@ const handleViewHistory = () => {
const userInfo = ref({})
onMounted(async () => {
// 获取用户信息
const res = await userInfoAPI()
if (res.code) {
userInfo.value = res.data || {};
if (userInfo.value.name && userInfo.value.mobile && userInfo.value.idcard) {
// 从缓存获取用户信息
const cachedUserInfo = localStorage.getItem('cached_user_info')
if (cachedUserInfo) {
userInfo.value = JSON.parse(cachedUserInfo)
// 检查是否有历史数据
if (userInfo.value.name && userInfo.value.phone && userInfo.value.idCard) {
const res = await searchOldActivityAPI({
name: userInfo.value.name,
mobile: userInfo.value.mobile,
idcard: userInfo.value.idcard
mobile: userInfo.value.phone,
idcard: userInfo.value.idCard
})
if (res.code) {
activityCount.value = res.data?.payment_qty || 0
......@@ -182,6 +183,15 @@ onMounted(async () => {
lastActivityDate.value = res.data?.last_activity_date || ''
}
}
} else {
// 如果是收集完成没有缓存字段的情况, 直接查接口
const res = await searchOldActivityAPI()
if (res.code) {
activityCount.value = res.data?.payment_qty || 0
volunteerCount.value = res.data?.volunteer_qty || 0
recordDate.value = res.data?.record_date || ''
lastActivityDate.value = res.data?.last_activity_date || ''
}
}
})
......