hookehuyr

新增我陪伴的报名列表功能和页面

......@@ -2,7 +2,7 @@
* @Author: hookehuyr hookehuyr@gmail.com
* @Date: 2022-05-27 15:57:59
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-11-01 18:18:19
* @LastEditTime: 2022-11-14 13:19:36
* @FilePath: /swx/src/app.config.js
* @Description:
*/
......@@ -40,6 +40,7 @@ export default {
'pages/auth/index',
'pages/joinVolunteerInfo/index',
'pages/apxUserInfo/index',
'pages/followList/index',
],
subpackages: [ // 配置在tabBar中的页面不能分包写到subpackages中去
{
......
<!--
* @Date: 2022-09-20 15:39:37
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-11-03 18:22:37
* @LastEditTime: 2022-11-14 14:42:15
* @FilePath: /swx/src/components/activity-card.vue
* @Description: 活动卡片组件
-->
......@@ -62,6 +62,7 @@
<view @tap="delActivity(data)" v-if="formatStatus(data) === '未发布' || formatStatus(data) === '已结束'" class="close-button">删除</view>
</view>
<view v-if="status === 'creator' && formatStatus(data) !== '已结束'" @tap="copyActivity(data.id)" class="copy-button">复制</view>
<view v-if="status === 'follow'" @tap="followActivity(data)" class="follow-button">我陪伴报名列表</view>
</view>
</view>
<!-- <van-toast id="van-toast" /> -->
......@@ -125,6 +126,11 @@ const finishActivity = ({ id }) => {
const delActivity = ({ id }) => {
emit('on-handle', { id, type: 'delete' });
}
// 追踪活动列表
const followActivity = ({ id }) => {
emit('on-handle', { id, type: 'follow' });
}
</script>
<style lang="less">
......@@ -161,6 +167,19 @@ const delActivity = ({ id }) => {
padding: 0.85rem;
font-size: 0.85rem;
position: relative;
.follow-button {
position: absolute;
right: 0;
top: 0.5rem;
background-color: #199A74;
color: white;
padding: 0.25rem;
padding-left: 1rem;
padding-right: 0.5rem;
border-top-left-radius: 1rem;
border-bottom-left-radius: 1rem;
font-size: 0.85rem;
}
.finish-button {
position: absolute;
right: 0;
......
/*
* @Date: 2022-09-29 09:45:17
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-09-29 09:45:33
* @FilePath: /swx/src/pages/joinList/index.config.js
* @Description: 文件描述
*/
export default {
navigationBarTitleText: '报名列表',
usingComponents: {
},
}
.join-list-page {
.join-list-header {
background-color: #FFFFFF;
.header-info {
display: flex;
text-align: center;
padding-bottom: 1rem;
margin-top: 0.5rem;
.activity {
flex: 1;
height: 50rpx;
line-height: 50rpx;
}
.job {
flex: 1;
border-right: 1px solid #F5F5F5;
border-left: 1px solid #F5F5F5;
height: 100rpx;
line-height: 50rpx;
}
.sign {
flex: 1;
height: 50rpx;
line-height: 50rpx;
}
}
}
.activity-title {
background-color: #FFFFFF;
.box {
padding: 1rem 1rem 0.5rem 1rem;
}
}
.bg-gradient {
background: linear-gradient(#B3DDC9, #B3DDC9) no-repeat;
/*调整下划线的宽度占百分之百 高度是3px */
background-size: 100% 1vw;
/* 调整下划线的起始位置 左侧是0 上边是1.15em */
background-position: 0 1.1rem;
}
.inactivate {
font-size: 1rem;
color: #999999;
}
.list-item {
background-color: white;
padding: 0.75rem;
border-radius: 0.65rem;
position: relative;
margin-bottom: 1rem;
.avatar {
width: 100%;
height: 5rem;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
border-radius: 0.5rem;
}
.content {
padding: 0.5rem 1rem;
.title {
font-size: 1.25rem;
}
.phone {
color: #199A74;
margin-top: 0.5rem;
}
}
}
}
<template>
<view class="join-list-page">
<!-- <view id="page-header" class="join-list-header">
<view class="activity-title">
<view class="box">
<text class="bg-gradient" style="font-size: 1.15rem;">报名统计</text>
</view>
</view>
<view class="header-info">
<view class="activity">
<view><text style="font-size: 1.25rem;">{{ reg_count }}</text>人</view>
<view>
<van-icon :name="icon_join" size="1.5rem" color="" style="vertical-align: sub;" />
<text style="font-size: 0.9rem; color: #999999;">活动报名</text>
</view>
</view>
<view class="job">
<text style="font-size: 1.25rem;">{{ volunteer_count }}</text>人
<view>
<van-icon :name="icon_job" size="1.25rem" color="" style="vertical-align: sub;" />
<text style="font-size: 0.9rem; color: #999999;">岗位报名</text>
</view>
</view>
<view class="sign">
<view><text style="font-size: 1.25rem;">{{ sign_count }}</text>人</view>
<view>
<van-icon :name="icon_sign" size="1.25rem" color="" style="vertical-align: sub;" />
<text style="font-size: 0.9rem; color: #999999;">用户签到</text>
</view>
</view>
</view>
</view> -->
<view class="list-wrapper" style="margin: 1rem;">
<view id="page-filter" style="background-color: white; border-radius: 0.65rem; padding: 1rem;overflow: auto; margin-bottom: 1px;">
<view style="display: inline-block; margin-right: 1rem; line-height: 60rpx;">
<view @tap="toggleColum('activity')" :class="[activated === 1 ? 'bg-gradient' : 'inactivate']" style="font-size: 1rem;">活动报名</view>
</view>
<!-- <view style="display: inline-block; line-height: 60rpx;">
<view @tap="toggleColum('join')" :class="[activated === 2 ? 'bg-gradient' : 'inactivate']">岗位报名</view>
</view> -->
<view @tap="show_status_popup=true" style="float: right; color: #666666; font-size: 0.9rem; border: 1px solid #DBDBDB; border-radius: 1rem; padding: 0.3rem 1rem 0.3rem 1rem;">
&nbsp;{{ status_type === '' ? '全部' : status_type }}&nbsp;&nbsp;
<van-icon :name="icon_sel2" size="0.8rem" color="" style="vertical-align: middle;" />
</view>
</view>
<scroll-view :scroll-y="true" :style="scrollStyle" @scrolltolower="onScrollToLower">
<view v-for="(item, index) in reg_list" :key="index" class="list-item">
<van-row>
<van-col span="6">
<view v-if="item.avatar" @tap="goToUserInfo(item)" class="avatar" :style="{ backgroundImage: `url(${item.avatar})` }"></view>
<view v-else @tap="goToUserInfo(item)" class="avatar" :style="{ backgroundImage: `url('https://img.yzcdn.cn/vant/cat.jpeg')` }"></view>
</van-col>
<van-col span="13">
<view class="content">
<view class="title">{{ item.name }}</view>
<view class="phone" @tap="onPhoneClick(item.phone)">
<van-icon :name="icon_tel" color="" size="1.25rem" style="vertical-align: sub;" />
{{ item.phone }}
</view>
</view>
</van-col>
<van-col span="5">
<van-tag @tap="changeStatus('apply', item.id)" v-if="item.status === 'apply'" :round="true" color="#D7F3FF" text-color="#0091FD" size="large">已报名</van-tag>
<van-tag @tap="changeStatus('enable', item.id)" v-if="item.status === 'enable'" :round="true" color="#D7FFD7" text-color="#019200" size="large">已签到</van-tag>
<van-tag @tap="changeStatus('absent', item.id)" v-if="item.status === 'absent'" :round="true" color="#FFF5E4" text-color="#FF7300" size="large">未出席</van-tag>
<van-tag @tap="changeStatus('request', item.id)" v-if="item.status === 'request'" :round="true" color="#FFF5E4" text-color="#FF7300" size="large">待审核</van-tag>
<van-tag @tap="changeStatus('reject', item.id)" v-if="item.status === 'reject'" :round="true" color="#FFF5E4" text-color="#FF7300" size="large">已拒绝</van-tag>
</van-col>
</van-row>
</view>
</scroll-view>
</view>
<view style="height: 2rem;"></view>
</view>
<!-- 切换状态弹出框 -->
<van-popup :show="show_status_popup" position="bottom" custom-style="height: 50%;" :lock-scroll="true">
<van-picker :show-toolbar="true" title="" confirm-button-text="确定" :columns="status_type_columns"
toolbar-class="picker-toolbar" @confirm="onStatusTypeConfirm" @cancel="onStatusTypeCancel" />
</van-popup>
<van-toast id="van-toast" />
<van-dialog id="van-dialog" />
</template>
<script setup>
import { ref, getCurrentInstance } from "vue";
import icon_join from '@/images/icon/baoming@2x.png'
import icon_job from '@/images/icon/yigong@2x.png'
import icon_sign from '@/images/icon/qiandao@2x.png'
import icon_sel2 from '@/images/icon/sel02@2x.png'
import icon_tel from '@/images/icon/tel@2x.png'
import Taro from '@tarojs/taro'
import { getCurrentPageParam } from "@/utils/weapp";
import Toast from '@/components/vant-weapp/toast/toast';
const onPhoneClick = (number) => {
Taro.makePhoneCall({
phoneNumber: number
})
}
</script>
<script>
import "./index.less";
import { listRegAPI, statusRegAPI } from '@/api/Reg/index';
import moment from '@/utils/moment.min.js'
import { activityInfoAPI } from '@/api/Host/index';
import { $ } from '@tarojs/extend'
import Dialog from '@/components/vant-weapp/dialog/dialog';
export default {
name: "joinListPage",
mounted () {
// 设置滚动列表可视高度
const windowHeight = wx.getSystemInfoSync().windowHeight;
setTimeout(async () => {
// const headerHeight = await $('#page-header').height();
const navHeight = await $('#page-filter').height();
this.scrollStyle = {
// height: windowHeight - headerHeight - navHeight - 70 + 'px'
height: windowHeight - navHeight - 70 + 'px'
}
}, 500);
},
data () {
return {
reg_count: 0,
volunteer_count: 0,
sign_count: 0,
reg_list: [],
absent: false, // 超时标识
flag: true,
status: '',
page: 0,
limit: 10,
member_type: 'player',
scrollStyle: { height: '1000rpx' },
activated: 1,
show_status_popup: false,
status_type: '',
status_type_columns: [],
}
},
async onShow () {
const info = await activityInfoAPI({ i: getCurrentPageParam().id });
if (info.code) {
// 判断是否超过活动时间
if (info.data.activity.activity_time > info.data.server_time) {
this.absent = true;
}
}
const { code, data } = await listRegAPI({ activity_id: getCurrentPageParam().id, type: this.member_type, page: 0, limit: this.limit });
if (code) {
this.reg_count = data.reg_count;
this.volunteer_count = data.volunteer_count;
this.sign_count = data.sign_count;
this.reg_list = data.reg_list;
if (this.absent) {
// 活动超时翻状态
this.reg_list.forEach(item => {
item.status = item.status === 'apply' ? 'absent' : item.status;
});
this.status_type_columns = ['全部', '已签到', '未出席']
} else {
this.status_type_columns = ['全部', '已签到', '已报名']
}
}
},
methods: {
goToUserInfo ({ status, member_id }) {
if (status === 'request') return false; // 未审核的人没有信息,不能查看详情
Taro.navigateTo({
url: '../userInfo/index?member_id=' + member_id
})
},
onScrollToLower () {
if(!this.flag){
return
}
this.flag = false;
this.getList();
},
async getList () {
Taro.showLoading({
title: '加载中'
})
// 获取推荐活动列表
const { code, data } = await listRegAPI({ activity_id: getCurrentPageParam().id, type: this.member_type, status: this.status, page: this.page, limit: this.limit });
if (code) {
if (data.reg_list.length) {
this.reg_list = this.reg_list.concat(data.reg_list);
this.page = this.page + 1;
this.flag = true;
} else {
Toast('没有数据')
}
Taro.hideLoading()
}
},
toggleColum (type) {
if (type === 'activity') { // 活动报名
this.member_type = 'player';
this.activated = 1;
if (this.absent) {
this.status_type_columns = ['全部', '已签到', '未出席']
} else {
this.status_type_columns = ['全部', '已签到', '已报名']
}
} else { // 岗位报名
this.member_type = 'volunteer';
this.activated = 2;
if (this.absent) {
this.status_type_columns = ['全部', '已签到', '未出席', '待审核', '已拒绝']
} else {
this.status_type_columns = ['全部', '已签到', '已报名', '待审核', '已拒绝']
}
}
// 重置条件
this.status_type = '';
this.status = '';
this.page = 0;
this.reg_list = [];
this.flag = false;
this.getList();
},
onStatusTypeConfirm (event) {
const { picker, value, index } = event.detail;
this.show_status_popup = false;
this.status_type = value;
if (this.status_type === '全部') {
this.status = '';
}
if (this.status_type === '已签到') {
this.status = 'enable';
}
if (this.status_type === '未出席' || this.status_type === '已报名') {
this.status = 'apply';
}
if (this.status_type === '待审核') {
this.status = 'request';
}
if (this.status_type === '已拒绝') {
this.status = 'reject';
}
// 重置条件
this.page = 0;
this.reg_list = [];
this.flag = false;
this.getList();
},
onStatusTypeCancel (event) {
this.show_status_popup = false;
},
async handleStatusReg (id, status) {
// 改变状态操作接口请求及后续更新
const { code, data } = await statusRegAPI({ i: id, status });
if (code) {
Taro.showToast({
title: '修改成功',
icon: 'success',
duration: 2000
});
// 手动翻状态-显示
this.reg_list.forEach(item => {
if (item.id === id) {
item.status = status;
}
});
// 更新用户统计
const { code, data } = await listRegAPI({ activity_id: getCurrentPageParam().id, type: this.member_type, page: this.page, limit: this.limit });
if (code) {
this.reg_count = data.reg_count;
this.volunteer_count = data.volunteer_count;
this.sign_count = data.sign_count;
}
}
},
changeStatus (status, id) {
// 已签到不能修改状态
if (status === 'enable') {
Toast('无需修改状态')
}
// 未签到, 已报名 修改状态已签到
if (status === 'absent' || status === 'apply') {
Dialog.confirm({
title: '温馨提示',
message: '是否确认修改状态为已签到?',
confirmButtonColor: '#199a74'
})
.then(async () => {
// on confirm
this.handleStatusReg(id, 'enable');
})
.catch(() => {
// on cancel
});
}
if (status === 'request') {
Dialog.confirm({
title: '温馨提示',
message: '是否审核通过,报名者成为义工?',
confirmButtonColor: '#199a74',
confirmButtonText: '同意',
cancelButtonText: '不同意',
})
.then(async () => {
// on confirm
this.handleStatusReg(id, 'apply');
})
.catch(async () => {
// on cancel
this.handleStatusReg(id, 'reject');
});
}
}
}
};
</script>
......@@ -47,8 +47,8 @@
<view v-for="(item, index) in reg_list" :key="index" class="list-item">
<van-row>
<van-col span="6">
<view v-if="item.avatar" @tap="goToUserInfo(item.member_id)" class="avatar" :style="{ backgroundImage: `url(${item.avatar})` }"></view>
<view v-else @tap="goToUserInfo(item.member_id)" class="avatar" :style="{ backgroundImage: `url('https://img.yzcdn.cn/vant/cat.jpeg')` }"></view>
<view v-if="item.avatar" @tap="goToUserInfo(item)" class="avatar" :style="{ backgroundImage: `url(${item.avatar})` }"></view>
<view v-else @tap="goToUserInfo(item)" class="avatar" :style="{ backgroundImage: `url('https://img.yzcdn.cn/vant/cat.jpeg')` }"></view>
</van-col>
<van-col span="13">
<view class="content">
......@@ -100,12 +100,6 @@ const onPhoneClick = (number) => {
})
}
const goToUserInfo = (member_id) => {
Taro.navigateTo({
url: '../userInfo/index?member_id=' + member_id
})
}
</script>
<script>
......@@ -156,7 +150,7 @@ export default {
this.absent = true;
}
}
const { code, data } = await listRegAPI({ activity_id: getCurrentPageParam().id, type: this.member_type, page: this.page, limit: this.limit });
const { code, data } = await listRegAPI({ activity_id: getCurrentPageParam().id, type: this.member_type, page: 0, limit: this.limit });
if (code) {
this.reg_count = data.reg_count;
this.volunteer_count = data.volunteer_count;
......@@ -174,6 +168,15 @@ export default {
}
},
methods: {
goToUserInfo({ status, member_id }) {
if (status === 'request') return false; // 未审核的人没有信息,不能查看详情
Taro.navigateTo({
url: '../userInfo/index?member_id=' + member_id
})
Taro.navigateTo({
url: '../userInfo/index?member_id=' + member_id
})
},
onScrollToLower () {
if(!this.flag){
return
......
......@@ -45,7 +45,7 @@
</view>
<scroll-view :scroll-y="true" :style="scrollStyle" @scrolltolower="onScrollToLower">
<view>
<activity-card v-for="(item, index) in activity_list" :key="index" :data="item" style="margin-bottom: 1rem;"></activity-card>
<activity-card @on-handle="onHandle" v-for="(item, index) in activity_list" :key="index" :data="item" :status="follow_status" style="margin-bottom: 1rem;"></activity-card>
</view>
</scroll-view>
</view>
......@@ -61,7 +61,7 @@
</template>
<script setup>
import { ref } from "vue";
import { ref, computed } from "vue";
import icon_join from '@/images/icon/baoming@2x.png'
import icon_job from '@/images/icon/yigong@2x.png'
import icon_sign from '@/images/icon/qiandao@2x.png'
......@@ -148,6 +148,7 @@ export default {
text: '活动结束',
key: 'stop'
}],
follow_status: ''
};
},
methods: {
......@@ -181,9 +182,11 @@ export default {
if (type === 'player') {
this.activated = 1;
this.role = 'player';
this.follow_status = '';
} else {
this.activated = 2;
this.role = 'volunteer';
this.follow_status = 'follow';
}
this.activity_list = [];
this.flag = true;
......@@ -203,7 +206,14 @@ export default {
},
onStatusTypeCancel (event) {
this.show_status_popup = false;
}
},
onHandle ({ id, type }) { // 活动操作后回调
if (type === 'follow') {
Taro.navigateTo({
url: '../followList/index?id=' + id
})
}
},
},
};
</script>
......