Преглед на файлове

接口联调(待接口修改)、申领记录证明静态画写等

htc преди 2 дни
родител
ревизия
f004d5a1f4
променени са 3 файла, в които са добавени 297 реда и са изтрити 33 реда
  1. 19 14
      components/pages/practiceBox/index.vue
  2. 121 13
      pagesMy/practice.vue
  3. 157 6
      pagesMy/practiceRecord.vue

+ 19 - 14
components/pages/practiceBox/index.vue

@@ -1,37 +1,37 @@
 <template>
-	<view class="ni">
+	<view class="ni" v-if="item" @click="handleCheck">
 		<div class="ni-top adfacjb">
 			<div class="ni-top-left adfac">
 				<image class="avatar" src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/12/4bd05666-201c-4016-acb6-09cd1f554524.png"></image>
-				<div class="name">{{'张琳琳'}}</div>
-				<image class="sex" v-if="sex==2" src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/12/b6d1fcb3-55ba-4104-b8cd-756b963a4da8.png"></image>
-				<image class="sex" v-else-if="sex==1" src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/12/a1899fd0-c468-48d9-b554-2f17b75a4157.png"></image>
-				<div class="age" :class="{'women':sex==2,'man':sex==1}">{{46}}岁</div>
+				<div class="name">{{item?.memberName}}</div>
+				<image class="sex" v-if="item.gender==1" src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/12/b6d1fcb3-55ba-4104-b8cd-756b963a4da8.png"></image>
+				<image class="sex" v-else-if="item.gender==0" src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/12/a1899fd0-c468-48d9-b554-2f17b75a4157.png"></image>
+				<div class="age" :class="{'women':item.gender==1,'man':item.gender==0}">{{item?.age||0}}岁</div>
 			</div>
 			<div class="ni-top-right">
-				<!-- 	<image v-if="agree" src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/12/87b5b244-d14f-43cd-991b-4ac9f48d909e.png" @tap="changeAgree"></image> -->
-					<image src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/12/b8a5cabd-57f8-4ad7-9677-f6372423c50a.png"></image>
+					<image v-if="item?.check" src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/12/87b5b244-d14f-43cd-991b-4ac9f48d909e.png"></image>
+					<image v-else src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/12/b8a5cabd-57f8-4ad7-9677-f6372423c50a.png"></image>
 			</div>
 		</div>
 		<div class="ni-info adf">
 			<div class="ni-info-left">
-				<image src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/d3c53597-a848-4a33-8deb-ab256f028baa.png"></image>
+				<image :src="item.coverFile"></image>
 			</div>
 			<div class="ni-info-right">
-				<div class="title">{{'中国少年先锋队诞辰日'}}</div>
+				<div class="title">{{item?.activityName||''}}</div>
 				<div class="tip adf">
 					<div class="tip-left adfac">
 						<image src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/201a4250-24a4-412d-9ec9-fc58071d10ea.png"></image>
 						<text>活动时间:</text>
 					</div>
-					<div class="tip-right">{{"2025-06-01 ~ 2025-06-02"}}</div>
+					<div class="tip-right">{{item?.activityStartTime||''}} ~ {{item?.activityEndTime||''}}</div>
 				</div>
 				<div class="tip adf">
 					<div class="tip-left adfac">
 						<image src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/09/11/e9025f86-a59e-4f82-92f0-9d22e846193c.png"></image>
 						<text>活动地点:</text>
 					</div>
-					<div class="tip-right">{{"广东省深圳市南山区"}}</div>
+					<div class="tip-right">{{item?.provinceName||''}}{{item?.cityName||''}}</div>
 				</div>
 			</div>
 		</div>
@@ -42,11 +42,16 @@
 	import { ref } from 'vue'
 	
 	const props = defineProps({
-		sex:{
-			typeof:Number,
-			default:1
+		item:{
+			typeof:Object,
+			default:null
 		}
 	})
+	
+	const emit = defineEmits(['itemCheck'])
+	const handleCheck = () => {
+		emit('itemCheck',props.item)
+	}
 </script>
 
 <style scoped lang="scss">

+ 121 - 13
pagesMy/practice.vue

@@ -15,18 +15,21 @@
 			</scroll-view>
 		</div>
 		<template v-if="tidx===1">
-			<div class="list">
+			<div class="list" v-if="list.length">
 				<up-list @scrolltolower="scrolltolower" style="height: 100%;">
 					<up-list-item v-for="(item, index) in list" :key="index">
-						<practice-box></practice-box>
+						<practice-box :item="item" @itemCheck="handleCheck"></practice-box>
 					</up-list-item>
 				</up-list>
 			</div>
-			<div class="btn">申领社会实践记录</div>
+			<div class="dataEmpty" v-else>
+				<page-empty text="暂无已申领记录"></page-empty>
+			</div>
+			<div class="btn" @click="handleApply">申领社会实践记录</div>
 		</template>
 		<template v-else-if="tidx===2">
-			<div class="list">
-				<up-list @scrolltolower="scrolltolower2" style="height: 100%;">
+			<div class="list" v-if="yslList.length">
+				<up-list @scrolltolower="scrolltolower" style="height: 100%;">
 					<up-list-item v-for="(item, index) in yslList" :key="index">
 						<div class="ysl-box">
 							<div class="ysl-box-title">{{'感恩有你 温暖前行'}}</div>
@@ -37,34 +40,58 @@
 					</up-list-item>
 				</up-list>
 			</div>
+			<div class="dataEmpty" v-else>
+				<page-empty text="暂无已申领记录"></page-empty>
+			</div>
 		</template>
 	</view>
 </template>
 
 <script setup name="">
 	import CusHeader from '@/components/CusHeader/index.vue'
+	import PageEmpty from '@/components/pageEmpty/index.vue'
 	import PracticeBox from '@/components/pages/practiceBox/index.vue'
-	import { ref } from 'vue'
+	import { ref, getCurrentInstance, onMounted } from 'vue'
+	const { proxy } = getCurrentInstance()
 	
 	const pb = ref(184)
 	const tidx = ref(1)
 	const midx = ref(0)
 	const scrollLeft = ref(0)
-	const memberList = ref([
-		{id:1,name:'张三'},
-		{id:2,name:'李四'},
-		{id:3,name:'龙傲天'}
-	])
-	const list = ref([1,1,1,1,1])
-	const yslList = ref([1,1,1])
+	const queryParams = ref({
+		page:1,
+		limit:10,
+		userId:'',
+		memberId:''
+	})
+	const isOver = ref(false)
+	const memberList = ref([])
+	const list = ref([])
+	const yslList = ref([])
 
 	const changeTab = index => {
 		tidx.value = index;
 		pb.value = index===1?184:40;
+		getDataByTab()
 	}
 	
 	const changeMember = (item,index) => {
 		midx.value = index;
+		queryParams.value.memberId = item.id;
+		getDataByTab()
+	}
+	
+	const getDataByTab = () => {
+		queryParams.value.page = 1;
+		isOver.value = false;
+		list.value = [];
+		yslList.value = [1];
+		if(!queryParams.value.memberId) queryParams.value.memberId = memberList.value[0]?.id;
+		if(tidx.value===1){
+			getKslList()
+		}else if(tidx.value===2){
+			getYslList()
+		}
 	}
 	
 	const handleDetail = item => {
@@ -72,6 +99,87 @@
 			url:'/pagesMy/practiceRecord'
 		})
 	}
+	
+	const scrolltolower = () => {
+		if(isOver.value) return
+		getDataByTab()
+	}
+	
+	const getKslList = () => {
+		proxy.$api.get('/core/social/practice/record/claimPage',queryParams.value).then(({data:res})=>{
+			if(res.code!==0) return proxy.$showToast(res.msg)
+			list.value = [...list.value,...res.data.list]
+			list.value.forEach(l=>{
+				l.activityStartTime = new Date(l.activityStartTime).Format('yyyy-MM-dd');
+				l.activityEndTime = new Date(l.activityEndTime).Format('yyyy-MM-dd');
+				l.check = false;
+				l.age = getAge(l.idCard);
+			})
+			queryParams.value.page++;
+			if(res.data.list.length===0) isOver.value = true
+		})
+	}
+	
+	const getYslList = () => {
+		proxy.$api.get('/core/social/practice/record/claimedPage',queryParams.value).then(({data:res})=>{
+			if(res.code!==0) return proxy.$showToast(res.msg)
+			// yslList.value = [...yslList.value,...res.data.list]
+			// queryParams.value.page++;
+			// if(res.data.list.length===0) isOver.value = true
+		})
+	}
+	
+	const getMemberList = () => {
+		proxy.$api.get('/core/family/member/page',{page:1,limit:-1}).then(({data:res})=>{
+			if(res.code!==0) return proxy.$showToast(res.msg)
+			memberList.value = res.data.list;
+			getDataByTab()
+		})
+	}
+	
+	const isValid = (idCard) => {
+		// 正则表达式校验18位身份证号码(最后一位可以是数字或X/x)
+		const regex = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;
+		return typeof idCard === 'string' && regex.test(idCard);
+	  }
+	
+	const getAge = (idCard) => {
+		if (!isValid(idCard)) return 0
+	
+		// 从身份证的第7位开始,截取8位作为出生日期字符串 (YYYYMMDD)
+		const birthDateStr = idCard.substring(6, 14);
+		const birthYear = parseInt(birthDateStr.substring(0, 4), 10);
+		const birthMonth = parseInt(birthDateStr.substring(4, 6), 10);
+		const birthDay = parseInt(birthDateStr.substring(6, 8), 10);
+	
+		const today = new Date();
+		const currentYear = today.getFullYear();
+		const currentMonth = today.getMonth() + 1; // getMonth() 返回 0-11
+		const currentDay = today.getDate();
+	
+		// 计算周岁
+		let age = currentYear - birthYear;
+	
+		// 如果当前月份小于出生月份,或者月份相同但日期小于出生日期,说明今年的生日还没过
+		if (currentMonth < birthMonth || (currentMonth === birthMonth && currentDay < birthDay)) {
+		  age--;
+		}
+	
+		return age < 0 ? 0 : age; 
+	}
+	
+	const handleCheck = (item) => {
+		item.check = !item.check;
+	}
+	
+	const handleApply = () => {
+		
+	}
+	
+	onMounted(()=>{
+		queryParams.value.userId = JSON.parse(uni.getStorageSync('userInfo')).id;
+		getMemberList();
+	})
 </script>
 
 <style scoped lang="scss">

+ 157 - 6
pagesMy/practiceRecord.vue

@@ -1,8 +1,57 @@
 <template>
 	<view class="common_page adffc" :style="{'min-height':h+'px', 'padding-top':mt+'px'}">
 		<cus-header title="申领社会实践记录" bgColor="#FFFFFF"></cus-header>
-		<div class="img">
-			<image :src="''" mode="widthFix"></image>
+		<div class="prove adffcac">
+			<image class="prove-logo" mode="widthFix" src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/11/20/965dc74b-fc45-4409-aa09-56877e75d2bc.png"></image>
+			<image class="prove-title" mode="widthFix" src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/11/20/7c341572-58b7-4afb-801f-93bf9890fa76.png"></image>
+			<image class="prove-line" mode="widthFix" src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/11/20/c21e680c-e83a-4f54-948c-19c49141ae99.png"></image>
+			<div class="prove-no">证书编号:{{'650102000105375'}}</div>
+			<div class="prove-info">
+				<div class="prove-info-pre adf">
+					<div class="prove-info-pre-left">
+						<div class="prove-info-pre-left-text">义工服务姓名:</div>
+						<div class="prove-info-pre-left-tip">Volunteer service Name</div>
+					</div>
+					<div class="prove-info-pre-right">{{'龙傲天'}}</div>
+				</div>
+				<div class="prove-info-pre adf">
+					<div class="prove-info-pre-left">
+						<div class="prove-info-pre-left-text space">所属学校:</div>
+						<div class="prove-info-pre-left-tip">Affiliated school</div>
+					</div>
+					<div class="prove-info-pre-right">{{'深圳实验中学'}}</div>
+				</div>
+				<div class="prove-info-pre adf">
+					<div class="prove-info-pre-left">
+						<div class="prove-info-pre-left-text space">证件类型:</div>
+						<div class="prove-info-pre-left-tip">Type of ID</div>
+					</div>
+					<div class="prove-info-pre-right">{{'居民身份证'}}</div>
+				</div>
+				<div class="prove-info-pre adf">
+					<div class="prove-info-pre-left">
+						<div class="prove-info-pre-left-text space">证件号码:</div>
+						<div class="prove-info-pre-left-tip">IdCard No</div>
+					</div>
+					<div class="prove-info-pre-right">{{'342221********9876'}}</div>
+				</div>
+				<div class="prove-info-pre adf">
+					<div class="prove-info-pre-left">
+						<div class="prove-info-pre-left-text">义工服务时长:</div>
+						<div class="prove-info-pre-left-tip">Volunteer service Time</div>
+					</div>
+					<div class="prove-info-pre-right">{{80}}小时</div>
+				</div>
+			</div>
+			<div class="prove-memo">
+				您累计参与了 <span>{{5}}</span> 场活动,捐赠了 <span>{{2000}}</span> 爱心值。向您践行志愿精神,为社会进步奉献力量致以最崇高的敬意。
+			</div>
+			<div class="prove-memo" style="margin-top: 30rpx;">特发此证!</div>
+			<div class="prove-bottom">
+				<div class="prove-bottom-pre">证明单位:善行少年服务基金会</div>
+				<div class="prove-bottom-pre">发证日期:{{'2025年06月30日'}}</div>
+			</div>
+			<image class="prove-seal" mode="widthFix" src="https://transcend.ringzle.com/xiaozhi-app/profile/2025/11/20/8ad6323d-f6a0-4057-8063-7eec97ec93f4.png"></image>
 		</div>
 		<div class="list">
 			<div class="list-box" v-for="(item,index) in list" :key="index">
@@ -47,11 +96,113 @@
 	.common_page{
 		padding-bottom: 184rpx;
 		
-		.img{
-			padding: 30rpx;
+		.prove{
 			margin-top: 20rpx;
-			background: #FFFFFF;
-			min-height: 800rpx;
+			background: url('https://transcend.ringzle.com/xiaozhi-app/profile/2025/11/20/57b2f49c-beac-49e7-8840-777ec860ae59.png') no-repeat;
+			background-size: 100% 100%;
+			height: 945rpx;
+			position: relative;
+			&-logo{
+				width: 133rpx;
+				position: absolute;
+				top: 58rpx;
+				left: 72rpx;
+			}
+			&-title{
+				width: 363rpx;
+				margin-top: 101rpx;
+			}
+			&-line{
+				width: 400rpx;
+				margin-top: 7rpx;
+			}
+			&-seal{
+				width: 131rpx;
+				border-radius: 50%;
+				position: absolute;
+				bottom: 69rpx;
+				right: 73rpx;
+			}
+		
+			&-no{
+				font-family: SourceHanSerifSC, SourceHanSerifSC;
+				font-weight: bold;
+				font-size: 20rpx;
+				color: #9F793F;
+				line-height: 20rpx;
+				letter-spacing: 1px;
+				margin-top: 9rpx;
+			}
+			
+			&-info{
+				margin-top: 27rpx;
+				overflow: auto;
+				&-pre{
+					margin-top: 22rpx;
+					&-left{
+						width: 135rpx;
+						&-text{
+							font-family: PingFangSC, PingFang SC;
+							font-weight: 400;
+							font-size: 17rpx;
+							color: #252525;
+							line-height: 17rpx;
+							letter-spacing: 1px;
+							&.space{
+								letter-spacing: 10rpx;
+							}
+						}
+						&-tip{
+							font-family: PingFangSC, PingFang SC;
+							font-weight: 400;
+							font-size: 10rpx;
+							color: #252525;
+							line-height: 10rpx;
+							margin-top: 3rpx;
+						}
+					}
+					&-right{
+						width: 188rpx;
+						font-family: PingFangSC, PingFang SC;
+						font-weight: 400;
+						font-size: 17rpx;
+						color: #252525;
+						line-height: 17rpx;
+						padding-bottom: 8rpx;
+						border-bottom: 2rpx solid #DDCEAF;
+					}
+				}
+			}
+			&-memo{
+				width: 100%;
+				padding: 0 80rpx;
+				box-sizing: border-box;
+				margin-top: 79rpx;
+				font-family: PingFangSC, PingFang SC;
+				font-weight: 400;
+				font-size: 20rpx;
+				color: #252525;
+				line-height: 31rpx;
+				label{
+					color: #C9A771;
+					margin: 0 5rpx;
+				}
+			}
+			&-bottom{
+				width: 100%;
+				padding: 0 80rpx;
+				box-sizing: border-box;
+				margin-top: 89rpx;
+				overflow: hidden;
+				&-pre{
+					margin-top: 16rpx;
+					font-family: PingFangSC, PingFang SC;
+					font-weight: 400;
+					font-size: 17rpx;
+					color: #252525;
+					line-height: 20rpx;
+				}
+			}
 		}
 		
 		.list{