This commit is contained in:
那些花儿
2025-09-17 17:52:38 +08:00
89 changed files with 7022 additions and 2453 deletions
@@ -0,0 +1,149 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
.info-title {
font-weight: bold;
background-color: white;
padding: 13px;
box-shadow: 0 8px 12px #ebedf0;
text-align: center !important;
}
.info-container {
margin-bottom: 60px;
}
.button {
position: fixed;
bottom: 0;
width: 100%;
}
.info-img {
display: block;
}
.van-count-down {
color: #fff;
}
</style>
<div id="app">
<van-nav-bar title="亲子活动" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
<van-sticky offset-top="46px">
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
<year-van-dropdown-item :num="5" @change="doSearch" v-model="pageForm.year"></year-van-dropdown-item>
<van-dropdown-item v-model="pageForm.activityType" :options="typeOptions" :multiple="false"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
</van-sticky>
<table-list api="/platform/family/apply/activityPageData"
:page_form.sync="pageForm"
ref="tableListRef"
title="activityName"
img="cover"
@ready="onReady"
>
<template v-slot="{index,row}">
<table-column label="面向对象">{{row.activityGroupName}}</table-column>
<table-column label="报名时间">
{{$moment(row.activitySignUpStartTime).format('MM/DD HH:mm') + '~' + $moment(row.activitySignUpEndTime).format('MM/DD HH:mm')}}
</table-column>
<table-column label="活动时间">
{{$moment(row.activityStartTime).format('MM/DD HH:mm') + '~' + $moment(row.activityEndTime).format('MM/DD HH:mm')}}
</table-column>
</template>
<template #actions="{index,row}">
<div class="action-btn" @click="onView(row)">
<i class="fa fa-eye"></i>
<span>查看介绍</span>
</div>
<div class="action-btn" @click="onApply(row)">
<i class="fa fa-edit"></i>
<span>去报名</span>
</div>
</template>
</table-list>
<van-action-sheet :close-on-click-overlay="false" title="详细信息" v-model="infoVisible">
<div class="info-container">
<div>
<van-image class="info-img" height="186" width="100%" :src="infoRow.cover"></van-image>
<div class="info-title">{{infoRow.activityName}}</div>
<pdf-preview :content="infoRow.introduce"></pdf-preview>
</div>
<div class="button">
<van-button @click="onApply(infoRow)" type="primary" block>
<span v-if="time >= 0">
去报名
</span>
<template v-else>
距离开始
<van-count-down :time="Math.abs(time)" class="count-down" format="DD 天 HH 时 mm 分 ss 秒" @finish="time = 0"></van-count-down>
</template>
</van-button>
</div>
</div>
</van-action-sheet>
</div>
<script>
const vue = new Vue({
el: "#app",
store,
components: {
"pdf-preview": httpVueLoader("/components/plugins/sysFilePreview/PdfIndex.vue?v=" + new Date().getTime())
},
data() {
return {
time: 0,
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: '',
year: new Date().getFullYear(),
activityType: 4,
},
typeOptions: [
{text: '全部', value: 1},
{text: '即将开始', value: 4},
{text: '报名中', value: 2},
{text: '已结束', value: 3},
],
infoVisible: false,
infoRow: {},
}
},
methods: {
onView(row) {
this.infoRow = row
this.time = this.$moment().diff(this.$moment(row.activitySignUpStartTime), 'milliseconds')
this.infoVisible = true
},
onApply(row) {
if(this.$moment().isBefore(this.$moment(row.activitySignUpStartTime))) {
this.onView(row)
return
}
this.$pjaxReplace('/platform/family/apply/list/h5?id=' + row.id)
},
onReady() {
this.doSearch()
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
},
})
</script>
<!--#
}
#-->
@@ -0,0 +1,89 @@
const times = {
template:
/*language=HTML*/
`
<div>
<van-action-sheet v-model="visible" title="时间段" cancel-text="取消">
<button v-for="(item,index) in row?.courseTimes" type="button" class="van-action-sheet__item">
<div style="display: flex; justify-content: space-between; align-items: center">
<div>
<div class="van-action-sheet__name">
<label>{{ weekdayCNMap[$moment(item.courseDate).day()] }}</label>
<label>{{ $moment(item.courseDate).format('YYYY-MM-DD') }}</label>
</div>
<div class="van-action-sheet__subname">
{{$moment(item.courseStartTime).format('MM-DD HH:mm') + ' 至 ' + $moment(item.courseEndTime).format('MM-DD HH:mm')}}
</div>
</div>
<div v-if="row.isSign === true && row.isMobileSign === true" class="sign_button">
<van-button v-if="item.isAttend !== true" @click.stop="onSign(item)" size="mini" type="info">签到</van-button>
<van-button v-if="item.isAttend === true" size="mini" type="info" disabled>已签到</van-button>
</div>
</div>
</button>
</van-action-sheet>
<van-popup round :safe-area-inset-bottom="true"
:close-on-click-overlay="false"
v-model="signVisible"
:style="{ width: '80%', height: '66%' }"
get-container="#app"
@close="onSignClose"
closeable
>
<scan-code ref="scanCodeRef"></scan-code>
</van-popup>
</div>
`,
store,
data() {
return {
visible:false,
row: null,
weekdayCNMap: {0: '周日', 1: '周一', 2: '周二', 3: '周三', 4: '周四', 5: '周五', 6: '周六'},
selectCourseTime: {},
signVisible: false,
}
},
components: {
"scan-code": httpVueLoader("/components/plugins/sysScanCode/index.vue?v=" + new Date().getTime())
},
methods: {
onSignClose() {
this.$refs.scanCodeRef.closeScan()
},
onOpen(row) {
this.row = row
this.visible = true
},
onSign(courseTime) {
this.selectCourseTime = courseTime
if(this.row.signType === 1) {
this.signVisible = true
this.$nextTick(() => {
this.$refs.scanCodeRef.init()
})
}
if(this.row.signType === 2) {
this.makeCode()
}
if(this.row.signType === 3) {
this.$toast('此签到模式正在升级中')
}
},
makeCode() {
const url = '/platform/family/mine/passiveScan'
const data = url + '?id=' + this.selectCourseTime.id
console.log(data)
const content = jrQrcode.getQrBase64(data)
vant.ImagePreview([content])
},
onClose(){
this.visible = false
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,343 @@
const applyForm = {
template:
/*language=HTML*/
`
<div>
<van-action-sheet :close-on-click-overlay="false" title="报名信息" v-model="visible">
<van-form ref="formRef" class="form-container">
<van-cell-group title="活动信息" class="form-section">
<van-field label="活动名称" readonly v-model="row.courseName"></van-field>
<van-field label="校区" readonly v-model="row.campus"></van-field>
<van-field label="活动地点" readonly v-model="row.courseLocation"></van-field>
</van-cell-group>
<van-cell-group title="基础信息" class="form-section">
<van-field label="姓名" readonly v-model="formData.username"></van-field>
<van-field label="工号" readonly v-model="formData.loginname"></van-field>
<van-field label="所在单位" readonly v-model="formData.unitName"></van-field>
<van-field label="所属工会" readonly v-model="formData.unionName"></van-field>
<van-field label="性别" readonly v-model="formData.sex"></van-field>
<template v-if="row.courseIsLimitApply">
<van-field label="报名时段"
required
:rules="[{ required: true, message: '请选择报名时段' }]"
readonly
@click="showCoursePicker = true"
placeholder="请选择报名时段"
name="courseTimeName"
v-model="formData.courseTimeName">
</van-field>
<van-popup v-model="showCoursePicker" position="bottom">
<van-picker
show-toolbar
:columns="courseTimeSelectList"
@confirm="onCourseConfirm"
@cancel="showCoursePicker=false"
></van-picker>
</van-popup>
</template>
</van-cell-group>
<van-cell-group class="form-section">
<template #title>
<div style="display: flex; align-items: center; justify-content: space-between">
<div>{{activity.keyWord}}信息</div>
<div>
<van-tag @click="delFamily" size="large" type="primary" color="#ff3b30">删除{{activity.keyWord}}</van-tag>
<van-tag @click="addFamily" size="large" type="primary" color="#1867b0">添加{{activity.keyWord}}</van-tag>
</div>
</div>
</template>
<div v-if="formData.mobileColumnsValue && formData.mobileColumnsValue.length > 0" class="mt10">
<van-tabs v-model="familyActive" type="card" color="#0e78c5" animated>
<van-tab v-for="item, index in formData.mobileColumnsValue"
:name="index + ''"
:title="activity.keyWord + (index + 1)"
:key="index">
<train-dynamic-form v-model="formData.mobileColumnsValue[index]"></train-dynamic-form>
</van-tab>
</van-tabs>
</div>
<div v-if="formData.mobileColumnsValue?.length === 0" class="companionList_empty_text">
<span>
暂无数据,请添加{{activity.keyWord}}
</span>
</div>
</van-cell-group>
<div class="button">
<van-button @click="onSubmit" round type="info">提交</van-button>
</div>
</van-form>
</van-action-sheet>
</div>
`,
data() {
return {
familyActive: '',
row: {},
activity: {},
visible: false,
formData: {},
showCoursePicker: false,
courseTimeSelectList: [],
courseType: {},
}
},
components: {
"train-dynamic-form": httpVueLoader("/components/module/trainSignUp/TrainDynamicForm.vue")
},
methods: {
addFamily() {
if(this.formData.mobileColumnsValue.length >= this.activity.familyMaxCount) {
this.$toast(this.activity.keyWord + '最多人数为' + this.activity.familyMaxCount)
return
}
const list = clone(this.courseType.familyMobileSignColumnList)
this.formData.mobileColumnsValue.push(list)
},
delFamily() {
this.formData.mobileColumnsValue.splice(this.familyActive, 1)
const ac = (Number(this.familyActive) - 1)
this.familyActive = '' + (ac >= 0 ? ac : 0)
},
async onOpen(row, courseType, activity) {
this.row = row
this.courseType = courseType
this.activity = activity
this.init(row, courseType)
if(row.courseIsLimitApply) {
await this.getCourseTimeSelectList(row)
}
this.visible = true
},
init(row, courseType) {
this.$set(this.formData, 'username', this.$store.state.user.username)
this.$set(this.formData, 'loginname', this.$store.state.user.loginname)
this.$set(this.formData, 'unionName', this.$store.state.user.union.name)
this.$set(this.formData, 'unitName', this.$store.state.user.unit.name)
this.$set(this.formData, 'sex', this.$store.state.user.sex)
this.$set(this.formData, 'activityId', row.activityId)
this.$set(this.formData, 'courseId', row.id)
this.$set(this.formData, 'mobileColumnsValue', [])
},
onCourseConfirm(val){
this.formData.activityCourseId = val.value
this.$set(this.formData, "activityCourseId", val.value)
this.$set(this.formData, "courseTimeName", val.text.substring(0, 12))
this.showCoursePicker = false
},
async getCourseTimeSelectList(o) {
const resp = await this.$axios.post('/platform/family/apply/getCourseTimeSelectList',{courseId: o.id})
if (resp.code === 0) {
this.courseTimeSelectList = resp.data
} else {
this.$toast.fail("获取时段信息失败,请联系管理员")
}
},
validateIdCard(idCard) {
if (!idCard) {
return false
}
// 18位身份证号码校验
if (idCard.length === 18) {
const idCardRegex = /^[1-9]\d{5}(18|19|20)?\d{2}((0[1-9])|(10|11|12))(([0|1|2][0-9])|10|20|30|31)\d{3}(\d|[Xx])$/
if (!idCardRegex.test(idCard)) {
return false
}
// 校验码计算
const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
const checksums = ["1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"]
let sum = 0
for (let i = 0; i < 17; i++) {
sum += idCard[i] * weights[i]
}
const checksum = checksums[sum % 11]
return checksum === idCard[17].toUpperCase()
}
// 15位身份证号码校验
else if (idCard.length === 15) {
const idCardRegex = /^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0|1|2][0-9])|10|20|30|31)\d{3}$/
return idCardRegex.test(idCard)
}
// 外国人或其他情况
else {
return false
}
},
validFamilyForm() {
// 校验规则映射
const validators = {
idCard: (value) => this.validateIdCard(value),
mobile: (value) => /^1[3-9]\d{9}$/.test(value),
email: (value) => /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value)
};
// 显示提示弹窗(直接传完整的 message)
const showAlert = (message) => {
vant.Dialog.alert({
title: '提示',
message: message, // 直接使用传入的完整消息
confirmButtonColor: '#1867b0'
});
};
const { mobileColumnsValue } = this.formData;
for (let i = 0; i < mobileColumnsValue.length; i++) {
const family = mobileColumnsValue[i];
for (const col of family) {
const value = col.columnValue?.trim(); // 安全处理空值和空格
// 必填校验
if (col.isRequired && !value) {
const message = this.activity.keyWord + (i + 1) + '的' + col.columnName + '不能为空';
showAlert(message);
return false;
}
// 格式校验
if (col.validRule && value) {
const validator = validators[col.validRule];
if (validator && !validator(value)) {
const message = this.activity.keyWord + (i + 1) + '的' + col.columnName + '格式不正确';
showAlert(message);
return false;
}
}
if(col.validRule === 'idCard' && this.row.familyAgeLimit) {
const parseCard = this.parseIdCard(value)
if(this.row.minAge && parseCard.age < this.row.minAge) {
const message = '限制报名最小年龄为' + this.row.minAge;
showAlert(message);
return false;
}
if(this.row.maxAge && parseCard.age > this.row.maxAge) {
const message = '限制报名最大年龄为' + this.row.maxAge;
showAlert(message);
return false;
}
}
if(col.validRule === 'idCard' && this.row.familySexLimit) {
const parseCard = this.parseIdCard(value)
if(this.row.familySex && parseCard.sex !== this.row.familySex) {
const message = '限制报名性别为' + this.row.familySex;
showAlert(message);
return false;
}
}
}
}
return true;
},
parseIdCard(idCard) {
if (!idCard || (idCard.length !== 18 && idCard.length !== 15)) {
return null;
}
let birthStr = '';
let sexCode = '';
if (idCard.length === 15) {
birthStr = '19' + idCard.substring(6, 12);
sexCode = idCard.substring(14, 15); // 15位:第15位是性别
} else {
birthStr = idCard.substring(6, 14);
sexCode = idCard.substring(16, 17); // 18位:第17位是性别
}
const birthYear = parseInt(birthStr.substring(0, 4), 10);
const birthMonth = parseInt(birthStr.substring(4, 6), 10) - 1;
const birthDay = parseInt(birthStr.substring(6, 8), 10);
const birthDate = new Date(birthYear, birthMonth, birthDay);
const today = new Date();
let age = today.getFullYear() - birthDate.getFullYear();
const monthDiff = today.getMonth() - birthDate.getMonth();
const dayDiff = today.getDate() - birthDate.getDate();
if (monthDiff < 0 || (monthDiff === 0 && dayDiff < 0)) {
age--;
}
const sex = parseInt(sexCode, 10) % 2 === 1 ? '男' : '女';
return { age, sex, };
},
async validateSignUp() {
// 获取家属人数
const res = await this.$axios.post("/platform/family/apply/validateSignUp", {
courseId: this.formData.courseId,
currentFamilyNumber: this.formData.mobileColumnsValue.length || 0
})
if(res.code !== 0) {
this.$dialog.alert({title: '温馨提示', message: res.msg})
}
return res.code === 0
},
async validateCourseTime() {
const res = await this.$axios.post('/platform/family/apply/validateSourceSignUp', {
activityCourseId: this.formData.activityCourseId,
courseId: this.row.id
})
if(res.code !== 0) {
this.$dialog.alert({title: '温馨提示', message: res.msg})
}
return res.code === 0
},
async onSubmit() {
if (!this.validFamilyForm()) return
if (!await this.validateSignUp()) return
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: "提示",
message: "您确定要提交吗?"
}).then(async () => {
if (this.row.courseIsLimitApply) {
if(!await this.validateCourseTime()) return
}
const formData = clone(this.formData)
let array = []
formData.mobileColumnsValue.forEach(item => {
const o = item.map((v) => {
return {
columnName: v.columnName,
columnValue: v.columnValue,
columnCode: v.columnCode,
columnFormType: v.columnFormType
}
})
array.push(o)
})
formData.mobileColumnsValue = JSON.stringify(clone(array))
this.$axios.post("/platform/family/apply/doSignUp", formData).then(res => {
this.$dialog.alert({title: '温馨提示', message: res.msg})
.then(() => {
if (res.code === 0) {
this.visible = false
this.$emit('refresh')
}
})
})
})
})
},
},
style: /*language=CSS*/ `
::v-deep .companionList_empty_text {
text-align: center;
padding: 10px 0;
font-size: 14px;
color: grey;
}
::v-deep .button {
position: fixed;
bottom: 0;
width: 100%;
}
`
}
@@ -0,0 +1,237 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
.primary-color {
color: var(--color-primary);
}
.sign_button .van-button{
width: 66px;
height: 30px;
font-size: 14px;
border-radius: 6px;
}
.sign-success .label{
color: #0e9558;
}
.sign-success .value{
color: #0e9558;
}
</style>
<div id="app">
<van-nav-bar title="活动报名" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
<van-sticky offset-top="46px">
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
<van-dropdown-item v-model="pageForm.courseTypeId" :options="typeOptions" :multiple="false"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
</van-sticky>
<table-list api="/platform/family/apply/pageData"
:page_form.sync="pageForm"
ref="tableListRef"
@ready="onReady"
>
<template #header="{index,row}">
<div class="item-header">
<div class="item-title">{{ row.courseName }}</div>
<div v-html="calcSignUpCount(row)"></div>
</div>
</template>
<template v-slot="{index,row}">
<table-column label="类型">{{row.typeName}}</table-column>
<table-column label="校区">{{row.campus}}</table-column>
<table-column label="地点">{{row.courseLocation}}</table-column>
<table-column label="联系人">{{row.courseInstructor}}</table-column>
<table-column label="时间">
<span v-if="row.courseTimes && row.courseTimes.length === 1" class="primary-color" @click="onTime(row)">
{{ weekdayCNMap[$moment(row.courseTimes[0].courseDate).day()]
+ ' '
+ $moment(row.courseTimes[0].courseStartTime).format('MM月DD日 HH:mm')
+ '~'
+ $moment(row.courseTimes[0].courseEndTime).format('HH:mm') }}
</span>
<span v-else @click="onTime(row)" class="primary-color">点我查看</span>
</table-column>
<table-column v-if="row.introduce?.trim()" label="详细信息">
<span @click="introduceRow = row; introduceVisible = true" class="primary-color">点我查看</span>
</table-column>
<table-column label="报名成功" v-if="row.signValue" class="sign-success">{{row.signValue}}</table-column>
</template>
<template #actions="{index,row}">
<div v-if="activity.wechat && row.isSign" class="action-btn" @click="this.vant.ImagePreview([activity.wechat])">
<i class="fa fa-wechat"></i>
<span>微信群二维码</span>
</div>
<template v-if="$moment().isBefore($moment(activity.activitySignUpEndTime))">
<div v-if="row.isSign === false" class="action-btn" @click="onApply(row)">
<i class="fa fa-sign-in"></i>
<span>我要报名</span>
</div>
<div v-if="row.isSign === true" class="action-btn delete" @click="onCancel(row)">
<i class="fa fa-trash"></i>
<span>取消报名</span>
</div>
</template>
<div v-if="row.isSign === true && row.isMobileSign === true && $moment().isAfter($moment(activity.activitySignUpEndTime))"
class="action-btn"
@click="onTime(row)"
>
<i class="fa fa-sign-in"></i>
<span>签到</span>
</div>
</template>
</table-list>
<van-action-sheet :close-on-click-overlay="false" title="详细信息" v-model="introduceVisible" cancel-text="取消">
<pdf-preview :content="introduceRow.introduce"></pdf-preview>
</van-action-sheet>
<times ref="timesRef"></times>
<apply-form ref="formRef" @refresh="refresh"></apply-form>
</div>
<script src="${base!}/assets/platform/plugins/jr-qrcode/jr-qrcode.js"></script>
<script>
<!--#include('../common/times.js'){}#-->
<!--#include('applyForm.js'){}#-->
const vue = new Vue({
el: "#app",
store,
components: {
'times': times,
'apply-form': applyForm,
"pdf-preview": httpVueLoader("/components/plugins/sysFilePreview/PdfIndex.vue?v=" + new Date().getTime())
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: '',
year: new Date().getFullYear(),
courseTypeId: null,
activityId: GetQueryString('id'),
dataType: GetQueryString('dataType'),
},
typeOptions: [],
assortOptions: [],
sourceTypeOptions: [],
introduceVisible: false,
introduceRow: {},
activity: {},
weekdayCNMap: {0: '周日', 1: '周一', 2: '周二', 3: '周三', 4: '周四', 5: '周五', 6: '周六'},
}
},
methods: {
refresh() {
this.doSearch()
},
async onTime(row) {
// 如果设置签到,并且也报名的话
if(row.isMobileSign === true && row.isSign === true) {
const res = await this.$axios.post('/platform/family/mine/queryCourseSign', {
courseId: row.id
})
row.courseTimes = res.data
}
this.$refs.timesRef.onOpen(row)
},
onApply(row) {
const courseType = this.sourceTypeOptions.find((v) => v.id === row.courseType)
this.$axios.post('/platform/family/apply/validateSignUp', {
courseId: row.id
})
.then((res) => {
if (res.code !== 0) {
vant.Dialog.alert({
title: '提示',
message: res.msg,
confirmButtonColor: '#1867b0'
})
} else {
let lave = row.coursePeopleNumber - (row.hasRegisterNum + row.courseReservedNumber)
if(row.reserveMode === 2 && lave <= 0) {
vant.Dialog.alert({
title: '提示',
message: '您当前的报名为候补报名状态',
confirmButtonColor: '#1867b0'
})
}
this.$refs.formRef.onOpen(row, courseType, this.activity)
}
})
},
onCancel(row) {
vant.Dialog.confirm({
title: '温馨提示',
message: "您确定要<span style='color: red'>取消【" + row.courseName + "】</span>吗?",
confirmButtonColor: '#1867b0',
}).then(async () => {
const resp = await this.$axios.post('/platform/family/apply/cancelSignUp', {
activityId: row.activityId,
courseId: row.id
})
this.$toast(resp.msg)
if (resp.code === 0) {
this.doSearch()
}
}).catch(() => {})
},
calcSignUpCount(row) {
if(!row.coursePeopleNumber || row.coursePeopleNumber === 0) {
return "名额数不限制"
}
let lave = row.coursePeopleNumber - (row.hasRegisterNum + row.courseReservedNumber)
if(row.reserveMode === 2) {
let lave2 = row.waitingNum - row.hasWaitingNum
return "<span style='color: red'>余" + lave +"</span>/" + row.coursePeopleNumber + "人"
+ "<span style='color: red'>候补余" + lave2 + "</span>/" + row.waitingNum + "人"
} else {
return "<span style='color: red'>余" + lave +"</span>/" + row.coursePeopleNumber + "人"
}
},
async onReady() {
const typeList = await this.getCourseTypeList()
this.sourceTypeOptions = clone(typeList)
this.typeOptions = [
{
text: "全部类型",
value: null
}
].concat(typeList.map((v) => ({ text: v.typeName, value: v.id })))
if (this.typeOptions.length > 0) {
this.pageForm.type = this.typeOptions[0].value
this.doSearch()
}
this.fetchActivity()
},
fetchActivity() {
this.$axios.post('/platform/family/manage/findOne', {id: this.pageForm.activityId})
.then((res) => {
this.activity = res.data
})
},
async getCourseTypeList() {
const resp = await this.$axios.post("/platform/family/type/getAllType")
return resp.data
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
},
})
</script>
<!--#
}
#-->
@@ -0,0 +1,347 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
.info-title {
font-weight: bold;
background-color: white;
padding: 13px;
box-shadow: 0 8px 12px #ebedf0;
text-align: center !important;
}
.info-container {
}
.button {
position: fixed;
bottom: 0;
width: 100%;
}
.info-img {
display: block;
}
.van-count-down {
color: #fff;
}
.table-list-container {
padding: 0;
margin-top: 10px;
}
.table-list-container .table-list-item {
background-color: #fff;
border-bottom: 1px solid #eaecef;
padding: 16px;
position: relative;
margin-bottom: 10px;
}
.table-list-container .table-list-item:last-child {
border-bottom: none;
margin-bottom: 0;
}
.table-list-container .table-list-item .item-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 10px;
}
.table-list-container .table-list-item .item-title {
font-size: 16px;
font-weight: 500;
color: #1f2f3d;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
padding-right: 10px;
}
.table-list-container .table-list-item .img-container {
width: 100px;
height: 100px;
flex-shrink: 0;
border-radius: 6px;
}
.table-list-container .table-list-item .img-container img {
width: 100%;
height: 100%;
border-radius: 6px;
}
.table-list-container .table-list-item .item-meta {
display: flex;
color: #606266;
font-size: 14px;
margin-bottom: 5px;
padding: 4px 0;
}
.table-list-container .table-list-item .meta-item {
display: flex;
align-items: center;
gap: 8px;
width: 100%;
}
.table-list-container .table-list-item .meta-item i {
font-size: 14px;
color: #909399;
width: 16px;
text-align: center;
}
.table-list-container .table-list-item .item-content {
color: #606266;
font-size: 14px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
line-height: 1.5;
}
.table-list-container .table-list-item .item-footer {
display: flex;
justify-content: space-between;
margin-top: 12px;
padding-top: 8px;
border-top: 1px dashed #eaecef;
color: #909399;
font-size: 13px;
}
.table-list-container .table-list-item .item-actions {
display: flex;
column-gap: 20px;
justify-content: end;
margin-top: 15px;
padding-top: 12px;
border-top: 1px solid #eaecef;
}
.table-list-container .table-list-item .action-btn {
display: flex;
align-items: center;
justify-content: end;
font-size: 14px;
color: var(--color-primary);
padding: 4px 0;
}
.table-list-container .table-list-item .action-btn i {
margin-right: 6px;
font-size: 16px;
}
.table-list-container .table-list-item .action-btn.delete {
color: #ff0000;
}
.table-list-container .table-list-item .action-btn.review {
color: #67c23a;
}
.table-list-container .empty-state {
text-align: center;
padding: 60px 20px;
color: #909399;
}
.table-list-container .empty-state i {
font-size: 60px;
margin-bottom: 16px;
color: #dcdee0;
}
.table-list-container .empty-state p {
margin-top: 10px;
font-size: 14px;
}
.table-column {
display: flex;
padding: 6px 0;
align-items: center;
}
.label {
color: #333;
font-size: 14px;
flex-shrink: 0;
max-width: 120px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.value {
color: #555;
font-size: 14px;
flex-grow: 1; /* 动态占据剩余部分 */
white-space: nowrap; /* 防止换行 */
overflow: hidden; /* 隐藏溢出的部分 */
text-overflow: ellipsis; /* 省略号 */
}
</style>
<div id="app">
<van-nav-bar title="亲子活动-我的报名" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
<van-sticky offset-top="46px">
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
<year-van-dropdown-item :num="5" @change="doSearch" v-model="pageForm.year"></year-van-dropdown-item>
<van-dropdown-item v-model="pageForm.activityType" :options="typeOptions" :multiple="false"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
</van-sticky>
<table-list api="/platform/family/apply/activityPageData"
:page_form.sync="pageForm"
ref="tableListRef"
title="activityName"
img="cover"
@ready="onReady"
>
<template v-slot="{index,row}">
<table-column label="面向对象">{{row.activityGroupName}}</table-column>
<table-column label="报名时间">
{{$moment(row.activitySignUpStartTime).format('MM/DD HH:mm') + '~' + $moment(row.activitySignUpEndTime).format('MM/DD HH:mm')}}
</table-column>
<table-column label="活动时间">
{{$moment(row.activityStartTime).format('MM/DD HH:mm') + '~' + $moment(row.activityEndTime).format('MM/DD HH:mm')}}
</table-column>
</template>
<template #actions="{index,row}">
<div class="action-btn" @click="onView(row)">
<i class="fa fa-eye"></i>
<span>活动介绍</span>
</div>
<div class="action-btn" @click="onInfo(row)">
<i class="fa fa-eye"></i>
<span>{{row.keyWord}}信息</span>
</div>
<div class="action-btn" @click="onApply(row)">
<i class="fa fa-edit"></i>
<span>操作</span>
</div>
</template>
</table-list>
<van-action-sheet :close-on-click-overlay="false" title="活动详细信息" v-model="infoVisible" cancel-text="取消">
<div class="info-container">
<div>
<van-image class="info-img" height="186" width="100%" :src="infoRow.cover"></van-image>
<div class="info-title">{{infoRow.activityName}}</div>
<pdf-preview :content="infoRow.introduce"></pdf-preview>
</div>
</div>
</van-action-sheet>
<van-action-sheet :close-on-click-overlay="false" title="报名信息" v-model="courseVisible" cancel-text="取消">
<div class="table-list-container">
<div v-for="(row, index) in mineCourses" :key="index" class="table-list-item">
<div class="item-header">
<div class="item-title" style="white-space: normal">{{ row.courseName }}</div>
</div>
<div style="display: flex;column-gap: 10px">
<div class="table-column">
<div class="label">校区:</div>
<div class="value">{{ row.campus }}</div>
</div>
</div>
<div style="display: flex;column-gap: 10px">
<div class="table-column">
<div class="label">地点:</div>
<div class="value">{{ row.courseLocation }}</div>
</div>
</div>
<div style="display: flex;column-gap: 10px">
<div class="table-column">
<div class="label">联系人:</div>
<div class="value">{{ row.courseInstructor }}</div>
</div>
</div>
<div style="display: flex;column-gap: 10px">
<div class="table-column">
<div class="label">家属人数:</div>
<div class="value">
{{ row.mobileColumnsValue ? JSON.parse(row.mobileColumnsValue).length : '暂无' }}
</div>
</div>
</div>
</div>
<div class="item-actions"></div>
</div>
</van-action-sheet>
</div>
<script>
const vue = new Vue({
el: "#app",
store,
components: {
"pdf-preview": httpVueLoader("/components/plugins/sysFilePreview/PdfIndex.vue?v=" + new Date().getTime())
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: '',
year: new Date().getFullYear(),
activityType: 1,
dataType: 'mine'
},
typeOptions: [
{text: '全部', value: 1},
{text: '报名中', value: 2},
{text: '已结束', value: 3},
],
infoVisible: false,
infoRow: {},
mineCourses: [],
courseVisible: false,
}
},
methods: {
onView(row) {
this.infoRow = row
this.infoVisible = true
},
onApply(row) {
this.$pjaxReplace('/platform/family/apply/list/h5?id=' + row.id + '&dataType=mine')
},
onInfo(row) {
this.$axios.post('/platform/family/mine/queryMineCourse', {activityId: row.id})
.then((res) => {
this.mineCourses = res.data
this.courseVisible = true
})
},
onReady() {
this.doSearch()
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
},
})
</script>
<!--#
}
#-->
@@ -1,142 +0,0 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.van-image {
display: inherit;
}
.title {
font-weight: bold;
background-color: white;
padding: 13px;
box-shadow: 0 8px 12px #ebedf0;
text-align: center !important;
}
.van-tabs {
margin-top: 10px;
}
.van-tab {
-webkit-flex: none;
}
.van-tab--active {
color: #1867b0;
}
.van-tabs__nav--line {
padding-left: 10px;
}
.van-tabs__content {
padding: 13px 13px 50px 13px;
background-color: white;
line-height: 28px;
}
.content_title {
text-align: center;
}
.pre_text {
white-space: break-spaces;
padding-left: 7px;
/*margin-top: 30px;*/
}
</style>
<div id="app" v-cloak>
<van-nav-bar
title="活动详情"
left-text="返回"
left-arrow
@click-left="$pjaxReplace('/platform/mobile/trainSignUpActivity/trainList')"
></van-nav-bar>
<van-image height="186" src="/assets/mobile/img/trainSignUp/3quhtakfd4heeqsk6irqhft60p.png"></van-image>
<div class="title">{{activity.activityName}}</div>
<van-tabs v-model:active="tabActive" shrink>
<van-tab title="详细信息" name="a">
<div class="pre_text" v-html="activity.introduce"></div>
</van-tab>
</van-tabs>
<van-button @click="toSign" type="primary" block style="position: fixed; bottom: 0; z-index: 2">去报名</van-button>
</div>
<script>
new Vue({
el: "#app",
data() {
return {
trainType: "培训班",
trainTypeList: [],
tabActive: "a",
activityId: "",
activity: {}
}
},
methods: {
async findOne() {
const resp = await this.$axios.post("/platform/mobile/trainSignUpActivity/findOne", {
id: this.activityId,
tabIndex: 0
})
if (resp.code === 0) {
this.activity = resp.data
}
},
async toSign() {
const nowTime = this.$moment().unix()
if (nowTime < this.$moment(this.activity.activitySignUpStartTime).unix()) {
vant.Dialog.alert({
title: "提示",
message: "活动报名还未开始"
})
return
}
if (nowTime > this.$moment(this.activity.activitySignUpEndTime).unix()) {
vant.Dialog.alert({
title: "提示",
message: "活动报名已结束"
})
return
}
if (this.activity.activityGroupId != null) {
const isExist = await this.getScopeUser(this.activity.activityGroupId)
if (!isExist) {
vant.Dialog.alert({
title: "参加人员范围",
message: this.activity.activityGroupName
})
return
}
}
this.$pjaxReplace(
"/platform/mobile/trainSignUpActivity/trainInfo?activityId=" +
this.activity.id +
"&endTime=" +
this.activity.activitySignUpEndTime +
"&isMySign=" +
GetQueryString("isMySign")
)
},
async getScopeUser(activityGroupId) {
const resp = await this.$axios.post("/platform/activity/basic/scope/getScopeUser", { activityGroupId: activityGroupId })
return resp.data
}
},
async created() {
this.$businessTool.getDictOptions("TRAIN_SIGNUP_TYPE").then((data) => {
this.trainTypeList = data
})
this.activityId = GetQueryString("activityId")
this.findOne()
}
})
</script>
<!--#
}
#-->
@@ -11,9 +11,12 @@ layout("/layouts/platform_h5.html"){
text-align: center !important;
}
.info-container {
height: calc(100vh - 46px - 44px);
min-height: calc(100vh - 46px - 44px);
overflow-y: auto;
margin-bottom: 60px;
}
.button {
position: fixed;
bottom: 0;
width: 100%;
}
.info-img {
display: block;
@@ -62,25 +65,27 @@ layout("/layouts/platform_h5.html"){
</template>
</table-list>
<van-popup v-model="infoVisible" position="right" :style="{ width: '100%', height: '100%' }">
<van-nav-bar title="详细信息" left-text="返回" left-arrow @click-left="infoVisible = false" fixed placeholder></van-nav-bar>
<van-action-sheet :close-on-click-overlay="false" title="详细信息" v-model="infoVisible">
<div class="info-container">
<van-image class="info-img" height="186" width="100%" :src="infoRow.cover"></van-image>
<div class="info-title">{{infoRow.activityName}}</div>
<pdf-preview style="height: calc(100vh - 46px - 44px - 186px - 57px)" :content="infoRow.introduce"></pdf-preview>
<div>
<van-image class="info-img" height="186" width="100%" :src="infoRow.cover"></van-image>
<div class="info-title">{{infoRow.activityName}}</div>
<pdf-preview :content="infoRow.introduce"></pdf-preview>
</div>
<div class="button">
<van-button @click="onApply(infoRow)" type="primary" block>
<span v-if="time >= 0">
去报名
</span>
<template v-else>
距离开始
<van-count-down :time="Math.abs(time)" class="count-down" format="DD 天 HH 时 mm 分 ss 秒" @finish="time = 0"></van-count-down>
</template>
</van-button>
</div>
</div>
<van-button @click="onApply(infoRow)" type="primary" block>
<span v-if="time >= 0">
去报名
</span>
<template v-else>
距离开始
<van-count-down :time="Math.abs(time)" class="count-down" format="DD 天 HH 时 mm 分 ss 秒" @finish="time = 0"></van-count-down>
</template>
</van-button>
</van-popup>
</van-action-sheet>
</div>
@@ -100,7 +105,7 @@ layout("/layouts/platform_h5.html"){
totalCount: 0,
searchKeyword: '',
year: new Date().getFullYear(),
activityType: 2,
activityType: 4,
},
typeOptions: [
{text: '全部', value: 1},
@@ -3,8 +3,7 @@ const applyForm = {
/*language=HTML*/
`
<div>
<van-popup v-model="visible" position="right" :style="{ width: '100%', height: '100%', 'background-color': '#F7F8FA' }">
<van-nav-bar title="报名信息" left-text="返回" left-arrow @click-left="visible = false" fixed placeholder></van-nav-bar>
<van-action-sheet :close-on-click-overlay="false" title="报名信息" v-model="visible">
<van-form ref="formRef" class="form-container">
<van-cell-group title="活动信息" class="form-section">
<van-field label="活动名称" readonly v-model="row.courseName"></van-field>
@@ -18,12 +17,12 @@ const applyForm = {
<van-field label="所属工会" readonly v-model="formData.unionName"></van-field>
<van-field label="性别" readonly v-model="formData.sex"></van-field>
<template v-if="row.courseIsLimitApply">
<van-field label="报名时段"
required
<van-field label="报名时段"
required
:rules="[{ required: true, message: '请选择报名时段' }]"
readonly
readonly
@click="showCoursePicker = true"
placeholder="请选择报名时段"
placeholder="请选择报名时段"
name="courseTimeName"
v-model="formData.courseTimeName">
</van-field>
@@ -39,11 +38,11 @@ const applyForm = {
<train-dynamic-form v-model="dynamicColumnsData" ref="dynamicForm"></train-dynamic-form>
</van-cell-group>
<div class="form-actions">
<div class="button">
<van-button @click="onSubmit" round type="info">提交</van-button>
</div>
</van-form>
</van-popup>
</van-action-sheet>
</div>
`,
data() {
@@ -61,15 +60,15 @@ const applyForm = {
"train-dynamic-form": httpVueLoader("/components/module/trainSignUp/TrainDynamicForm.vue")
},
methods: {
async onOpen(row, course) {
async onOpen(row, courseType) {
this.row = row
this.init(row, course)
this.init(row, courseType)
if(row.courseIsLimitApply) {
await this.getCourseTimeSelectList(row)
}
this.visible = true
},
init(row, course) {
init(row, courseType) {
this.$set(this.formData, 'username', this.$store.state.user.username)
this.$set(this.formData, 'loginname', this.$store.state.user.loginname)
this.$set(this.formData, 'unionName', this.$store.state.user.union.name)
@@ -78,7 +77,7 @@ const applyForm = {
this.$set(this.formData, 'activityId', row.activityId)
this.$set(this.formData, 'courseId', row.id)
this.dynamicColumnsData = course ? course.trainMobileSignColumnList : []
this.dynamicColumnsData = courseType ? courseType.trainMobileSignColumnList : []
this.dynamicColumnsData.forEach((item) => {
item.columnValue = this.$store.state.user[item.columnCode] || ""
})
@@ -151,6 +150,10 @@ const applyForm = {
},
},
style: /*language=CSS*/ `
.button {
position: fixed;
bottom: 0;
width: 100%;
}
`
}
@@ -37,11 +37,16 @@ layout("/layouts/platform_h5.html"){
</template>
<template v-slot="{index,row}">
<table-column label="类型">{{row.typeName}}</table-column>
<table-column label="校区">{{row.campus}}</table-column>
<table-column label="地点">{{row.courseLocation}}</table-column>
<table-column label="联系人">{{row.courseInstructor}}</table-column>
<table-column label="时间">
<span v-if="row.courseTimes && row.courseTimes.length === 1">
{{ $moment(row.courseTimes[0].courseStartTime).format('HH:mm') + '~' + $moment(row.courseTimes[0].courseEndTime).format('HH:mm') }}
<span v-if="row.courseTimes && row.courseTimes.length === 1" class="primary-color" @click="onTime(row)">
{{ weekdayCNMap[$moment(row.courseTimes[0].courseDate).day()]
+ ' '
+ $moment(row.courseTimes[0].courseStartTime).format('MM月DD日 HH:mm')
+ '~'
+ $moment(row.courseTimes[0].courseEndTime).format('HH:mm') }}
</span>
<span v-else @click="onTime(row)" class="primary-color">点我查看</span>
</table-column>
@@ -74,10 +79,9 @@ layout("/layouts/platform_h5.html"){
</template>
</table-list>
<van-popup v-model="introduceVisible" position="right" :style="{ width: '100%', height: '100%', 'background-color': '#F7F8FA' }">
<van-nav-bar title="详细信息" left-text="返回" left-arrow @click-left="introduceVisible = false" fixed placeholder></van-nav-bar>
<pdf-preview style="height: calc(100vh - 46px)" :content="introduceRow.introduce"></pdf-preview>
</van-popup>
<van-action-sheet :close-on-click-overlay="false" title="详细信息" v-model="introduceVisible" cancel-text="取消">
<pdf-preview :content="introduceRow.introduce"></pdf-preview>
</van-action-sheet>
<times ref="timesRef"></times>
<apply-form ref="formRef" @refresh="refresh"></apply-form>
@@ -114,6 +118,8 @@ layout("/layouts/platform_h5.html"){
introduceRow: {},
activity: {},
weekdayCNMap: {0: '周日', 1: '周一', 2: '周二', 3: '周三', 4: '周四', 5: '周五', 6: '周六'},
}
},
methods: {
@@ -131,7 +137,7 @@ layout("/layouts/platform_h5.html"){
this.$refs.timesRef.onOpen(row)
},
onApply(row) {
const course = this.sourceTypeOptions.find((v) => v.id === row.courseType)
const courseType = this.sourceTypeOptions.find((v) => v.id === row.courseType)
this.$axios.post('/platform/trainSingUp/apply/validateSignUp', {
courseId: row.id
})
@@ -151,7 +157,7 @@ layout("/layouts/platform_h5.html"){
confirmButtonColor: '#1867b0'
})
}
this.$refs.formRef.onOpen(row, course)
this.$refs.formRef.onOpen(row, courseType)
}
})
},
@@ -172,6 +178,9 @@ layout("/layouts/platform_h5.html"){
}).catch(() => {})
},
calcSignUpCount(row) {
if(!row.coursePeopleNumber || row.coursePeopleNumber === 0) {
return "名额数不限制"
}
let lave = row.coursePeopleNumber - (row.hasRegisterNum + row.courseReservedNumber)
if(row.reserveMode === 2) {
let lave2 = row.waitingNum - row.hasWaitingNum
@@ -11,9 +11,12 @@ layout("/layouts/platform_h5.html"){
text-align: center !important;
}
.info-container {
height: calc(100vh - 46px - 44px);
min-height: calc(100vh - 46px - 44px);
overflow-y: auto;
}
.button {
position: fixed;
bottom: 0;
width: 100%;
}
.info-img {
display: block;
@@ -62,17 +65,16 @@ layout("/layouts/platform_h5.html"){
</template>
</table-list>
<van-popup v-model="infoVisible" position="right" :style="{ width: '100%', height: '100%' }">
<van-nav-bar title="详细信息" left-text="返回" left-arrow @click-left="infoVisible = false" fixed placeholder></van-nav-bar>
<van-action-sheet :close-on-click-overlay="false" title="活动详细信息" v-model="infoVisible" cancel-text="取消">
<div class="info-container">
<van-image class="info-img" height="186" width="100%" :src="infoRow.cover"></van-image>
<div class="info-title">{{infoRow.activityName}}</div>
<pdf-preview style="height: calc(100vh - 46px - 44px - 186px - 57px)" :content="infoRow.introduce"></pdf-preview>
<div>
<van-image class="info-img" height="186" width="100%" :src="infoRow.cover"></van-image>
<div class="info-title">{{infoRow.activityName}}</div>
<pdf-preview :content="infoRow.introduce"></pdf-preview>
</div>
</div>
<van-button @click="onApply(infoRow)" type="primary" block>下一步</van-button>
</van-popup>
</van-action-sheet>
</div>
@@ -1,817 +0,0 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.van-card {
background: #ffffff;
margin-top: 10px;
}
.van-card__thumb {
display: flex;
align-items: center;
justify-content: center;
}
.van-card__content > div {
display: flex;
flex-direction: column;
}
.van-doc-card {
margin: 14px;
padding: 16px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 8px 12px #ebedf0;
line-height: 25px;
font-size: 12px;
}
.van-doc-card-my {
margin: 14px;
padding: 16px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 8px 12px #ebedf0;
line-height: 25px;
font-size: 12px;
}
.train-title {
color: grey;
}
.content {
padding: 16px 16px 10px;
min-height: 100px;
max-height: 360px;
}
.text {
color: #cccdd1;
}
.time {
font-family: -webkit-pictograph, serif;
text-align: right;
}
.popup {
width: 90%;
max-height: 70%;
overflow-y: auto;
border-radius: 10px;
padding: 2px 10px 12px 10px;
}
.van-card__thumb {
width: 35px;
height: 38px;
margin-right: 20px;
margin-top: 5px;
}
.van-card__content {
min-height: 30px;
}
.van-card__title {
font-weight: bold;
font-size: 13px;
margin-top: 4px;
}
.van-dropdown-menu__item {
flex: auto;
}
.van-empty {
background-color: transparent;
position: relative;
transform: translate(0%, 50%);
left: 0;
}
.joinPopup {
width: 100%;
height: 100%;
background-color: #f6f7f9;
}
.join_content {
padding: 20px;
/*height: calc(100% - 40px - 46px - 60px);*/
height: calc(100vh - 46px - 50px);
overflow-y: auto;
}
.join_submit {
width: 100% !important;
}
.van-card-header {
padding: 14px 20px;
border-bottom: 1px solid #ebeef5;
box-sizing: border-box;
color: #0e78c5;
font-weight: bold;
}
.van-card-body {
padding: 0px 10px 0px 10px;
}
.van-doc-card-two {
background-color: #fff;
border-radius: 10px;
box-shadow: 0 8px 12px #ebedf0;
line-height: 25px;
font-size: 12px;
}
.footer .van-button {
border-radius: 6px;
}
.amap-logo {
display: none !important;
}
.amap-copyright {
opacity: 0;
}
.van-tabs__nav--complete {
padding: 0;
}
</style>
<div id="app" v-cloak>
<van-nav-bar
:title="trainType + '列表'"
left-text="返回"
left-arrow
@click-left="$pjaxReplace('/platform/mobile/trainSignUpActivity/trainList?isMySign=' + isMySign)"
></van-nav-bar>
<van-sticky>
<van-dropdown-menu>
<van-dropdown-item @change="tabChange" v-model="activityStatus" :options="activityOptions"></van-dropdown-item>
<van-dropdown-item @change="courseChange" v-model="courseType" :options="courseOptions"></van-dropdown-item>
</van-dropdown-menu>
</van-sticky>
<van-tabs v-if="activityStatus != '1' && assortList.length > 0" v-model="assort" type="card" style="margin-top: 10px" @click="tabClick">
<van-tab v-for="item in assortList" :key="item" :name="item" :title="item"></van-tab>
</van-tabs>
<template>
<div id="parentDiv" v-if="tableData.courseList && tableData.courseList.length>0">
<template v-for="o in tableData.courseList">
<div style="position: relative" :class="activityStatus !== '1' ? 'van-doc-card' : 'van-doc-card-my'">
<div>
<van-tag :plain="false" type="primary" size="medium">{{getCourseTypeName(o)}}</van-tag>
<span style="font-weight: bold; font-size: 14px">
{{o.courseName}}
<span v-if="activityStatus !== '1'">
<span v-html="calcSignUpCount(o)"></span>
</span>
</span>
</div>
<div>
<span class="train-title">&emsp;&emsp;区:</span>
<span>{{o.campus}}</span>
</div>
<div>
<span class="train-title">活动地点:</span>
<span>{{o.courseLocation}}</span>
</div>
<div>
<span class="train-title">&ensp;&ensp;人:</span>
<span>{{o.courseInstructor}}</span>
</div>
<div>
<span class="train-title">活动时间:</span>
<span v-if="o.courseTimeList && o.courseTimeList.length > 1" @click="trainClick(o)" style="color: #1867b0">点我查看</span>
<span @click="trainClick(o)" v-if="o.courseTimeList && o.courseTimeList.length === 1" style="color: #1867b0">
{{o.courseTimeList[0].courseStartTime.substring(11, 19) + ' ~ ' + o.courseTimeList[0].courseEndTime.substring(11, 19)}}
</span>
</div>
<div>
<span @click.stop="showPic(tableData.wechat)" v-if="o.isSign === true && tableData.wechat" style="color: #dd6363">
点我查看微信群二维码
</span>
</div>
<van-button
type="primary"
round
size="mini"
v-if="activityStatus !== '1' && o.isSign === false"
style="position: absolute; left: 74%; bottom: 10%; width: 74px; height: 28px"
@click.stop="signUp(o)"
>
我要报名
</van-button>
<van-button
type="primary"
color="#dd6363"
round
size="mini"
v-if="o.isSign === true && $moment().valueOf() < $moment(activity.activitySignUpEndTime).valueOf()"
style="position: absolute; left: 74%; bottom: 10%; width: 74px; height: 28px"
@click.stop="cancel(o)"
>
取消报名
</van-button>
<image
v-if="activityStatus !== '1' && o.isSign === true && $moment().valueOf() >= $moment(activity.activitySignUpEndTime).valueOf()"
style="position: absolute; left: 77%; top: 58%"
src="/assets/mobile/svg/trainSignUp/sign_up.svg"
></image>
<div
@click="trainClick(o)"
v-if="activityStatus === '1'"
style="
text-align: center;
line-height: 40px;
width: 40px;
height: 40px;
display: inline-block;
font-size: 14px;
position: absolute;
right: -10px;
top: 8%;
background-color: #00c698;
border-radius: 7px;
color: white;
"
>
签到
</div>
</div>
</template>
</div>
<van-empty v-else image="/assets/platform/plugins/vant-green/images/nodata/nodata.png" description="暂无数据"></van-empty>
</template>
<van-popup v-model:show="popupShow" class="popup">
<div id="map" v-if="course.isMobileSign === true && course.signType === 3" style="width: 100%; height: 250px"></div>
<van-card
:title="item.courseStartTime.substring(0, 10) + '' +
getWeek(item.courseStartTime.substring(0, 10)) + ''"
v-for="(item,index) in qdArray"
:key="index"
thumb="/assets/mobile/svg/trainSignUp/qd1.svg"
>
<template #desc>
<div style="margin-top: 7px">{{item.courseStartTime.substring(11, 19) + ' ~ ' + item.courseEndTime.substring(11, 19)}}</div>
<div v-if="item.courseLocationCoordinates && item.isMobileSign === true && activityStatus === '1'">
<van-button
type="primary"
color="#1867b0"
round
size="mini"
@click.stop="showQRCode(item, 2)"
v-if="(item.isAttend === true && course.giftType === 1 && item.state === 1)
|| ($moment().unix() > $moment(item.courseEndTime).unix() && item.state === 3 && item.isAttend === true && course.giftType === 1)"
style="position: absolute; right: 65px; top: 25%; width: 60px; height: 25px"
>
礼品码
</van-button>
<van-button
type="primary"
color="#e1e1e1"
round
size="mini"
v-if="(item.isAttend === false && findTime(item) === false && item.state === 1)
|| ($moment().unix() > $moment(item.courseEndTime).unix() && item.state === 3 && item.isAttend === false)"
style="position: absolute; right: 0; top: 25%; width: 60px; height: 25px"
>
未签到
</van-button>
<van-button
type="primary"
color="#1867b0"
round
size="mini"
v-if="(item.isAttend === false && findTime(item) === true && item.state === 1)
|| ($moment().unix() > $moment(item.courseEndTime).unix() && item.state === 3 && item.isAttend === false)"
style="position: absolute; right: 0; top: 25%; width: 60px; height: 25px"
@click.stop="signIn(item)"
>
签 到
</van-button>
<van-button
type="primary"
color="#61ce98"
round
size="mini"
v-if="(item.isAttend === true && item.state === 1)
|| ($moment().unix() > $moment(item.courseEndTime).unix() && item.state === 3 && item.isAttend === true)"
style="position: absolute; right: 0; top: 25%; width: 60px; height: 25px"
>
已签到
</van-button>
</div>
</template>
</van-card>
</van-popup>
<van-popup class="joinPopup" position="right" v-model:show="joinPopup">
<van-nav-bar @click-left="joinPopup = false" left-text="返回" fixed left-arrow placeholder title="活动报名"></van-nav-bar>
<div class="join_content">
<van-form @submit="joinSubmit" :show-error-message="false">
<div class="van-doc-card-two" style="margin: 0 0 16px 0">
<div></div>
<div class="van-card-header">基础信息</div>
<div class="van-card-body">
<van-field name="userName" label="姓名" readonly v-model="formData.userName"></van-field>
<van-field name="loginName" label="工号" readonly v-model="formData.loginName"></van-field>
<van-field name="unitName" label="所在单位" readonly v-model="formData.unitName"></van-field>
<van-field name="unionName" label="所属工会" readonly v-model="formData.unionName"></van-field>
<van-field name="sex" label="性别" readonly v-model="formData.sex"></van-field>
<van-field
label="联系方式"
required
name="mobile"
:rules="[{ required: true, message: '请填写联系方式' }]"
placeholder="请填写联系方式"
v-model="formData.mobile"
></van-field>
<train-dynamic-form v-model="dynamicColumnsData" ref="trainDynamicForm"></train-dynamic-form>
</div>
</div>
<div class="footer">
<van-button class="join_submit" type="primary">提交报名</van-button>
</div>
</van-form>
</div>
</van-popup>
</div>
<script src="${base!}/assets/platform/plugins/jr-qrcode/jr-qrcode.js"></script>
<script>
let locations = null
let map = null
let geolocation = null
new Vue({
el: "#app",
store,
data() {
return {
loading: false,
tableData: [],
formData: {},
assort: "",
assortList: [],
allColumnsData: [],
dynamicColumnsData: [],
trainType: "培训班",
trainTypeList: [],
actionShow: false,
timeList: [],
activityId: "",
activityStatus: "0",
joinPopup: false,
popupShow: false,
courseText: "",
qdInfoList: [],
course: [],
qdArray: [],
activityOptions: [
{ text: "全部", value: "0" },
{ text: "我报名的", value: "1" }
],
courseOptions: [],
courseType: "0",
tempArray: [],
activitySignUpStartTime: null,
choose: {},
activity: "",
isMySign: 0
}
},
components: {
"train-dynamic-form": httpVueLoader("/components/module/trainSignUp/TrainDynamicForm.vue")
},
methods: {
tabClick(name, title) {
if (this.courseType === "0" && this.activityStatus !== "1") {
this.tableData.courseList = this.tempArray.courseList.filter((o) => o.assort === title)
} else {
this.tableData.courseList = this.tempArray.courseList.filter((o) => o.assort === title && o.courseType === this.courseType)
}
},
calcSignUpCount(o) {
let lave = (o.coursePeopleNumber + o.hasWaitingNum) - (o.hasRegisterNum + o.courseReservedNumber)
if(o.reserveMode === 2) {
let lave2 = o.waitingNum - o.hasWaitingNum
let str = "<span style='color: red'>余" + lave +"</span>/" + o.coursePeopleNumber + "人"
+ "<span style='color: red'>候补余" + lave2 + "</span>/" + o.waitingNum + "人)"
return str
} else {
return "<span style='color: red'>余" + lave +"</span>/" + o.coursePeopleNumber + "人)"
}
},
getCourseTypeName(o) {
const b = this.courseOptions.find((item) => item.value === o.courseType)
return b ? b.text : ""
},
//二维码
showQRCode(item, type) {
const o = {
userId: item.userId,
signId: item.id,
activityId: item.activityId,
activityCourseId: item.activityCourseId,
isMobileSign: item.isMobileSign,
signType: item.signType,
isReceiveGift: item.isReceiveGift,
giftType: item.giftType,
type: type
}
// 生成二维码的 base64 编码
const content = jrQrcode.getQrBase64(JSON.stringify(o))
vant.ImagePreview([content])
},
showPic(url) {
vant.ImagePreview([url])
},
findTime(o) {
const today = this.$moment().format("YYYY-MM-DD")
return o.courseStartTime.substr(0, 10) === today
},
findQd() {
const today = this.$moment().format("YYYY-MM-DD")
const day = this.qdInfoList.find((item) => {
return item.courseStartTime.substr(0, 10) === today
})
if (day === undefined) {
return 3
} else {
return day.isAttend ? 2 : 1
}
},
async signIn(o) {
if (o.signType === 1) {
vant.Dialog.alert({ message: "功能马上推出,敬请期待!" })
return
}
if (o.signType === 2) {
this.showQRCode(o, 1)
}
if (o.signType === 3) {
const start = new Date(o.courseStartTime).getTime() - 1000 * 60 * 30
const end = new Date(o.courseEndTime).getTime()
const now = new Date().getTime()
if (now < start || now > end) {
vant.Toast("请在规定时间签到")
return
}
const that = this
geolocation.getCurrentPosition(async function (status, result) {
if (status === "complete") {
locations = [result.position.getLng(), result.position.getLat()]
//用户当前位置
const userPoint = new AMap.LngLat(result.position.getLng(), result.position.getLat())
//课程位置
const coursePoint = new AMap.LngLat(that.course.courseLocationCoordinates[0], that.course.courseLocationCoordinates[1])
const distance = Math.round(userPoint.distance(coursePoint))
if (distance > 250) {
vant.Toast("请在250米内签到")
return
}
const array = [result.position.getLng(), result.position.getLat()]
const resp = await this.$axios.post("/platform/mobile/trainSignUpActivity/doQd", {
id: o.id,
courseId: that.course.id,
point: JSON.stringify(array)
})
if (resp.code === 0) {
await that.pageData()
}
vant.Toast(resp.msg)
that.popupShow = false
} else {
}
})
}
},
//获取当前坐标点
getPoint() {
/*return new Promise((resolve, reject) => {
window.navigator.geolocation.getCurrentPosition(position => {
pointArray = [position.coords.longitude, position.coords.latitude]
resolve(pointArray)
}, error => {
vant.Toast(error.message)
pointArray = []
reject([])
})
})*/
geolocation.getCurrentPosition(function (status, result) {
if (status === "complete") {
//alert(result.position)
locations = result.position
} else {
}
})
},
cancel(o) {
vant.Dialog.confirm({
title: "温馨提示",
message: "您确定要<span style='color: red'>取消【" + o.courseName + "】</span>吗?",
confirmButtonColor: "#1867b0"
})
.then(async () => {
const resp = await this.$axios.post("/platform/mobile/trainSignUpActivity/cancelSignUp", {
activityId: o.activityId,
courseId: o.id
})
vant.Toast(resp.msg)
if (resp.code === 0) {
await this.pageData()
}
})
.catch(() => {})
},
async signUp(o) {
this.choose = o
const res = await this.$axios.post("/platform/mobile/trainSignUpActivity/validateSignUp", {
courseId: o.id
})
if (res.code !== 0) {
vant.Dialog.alert({
title: "提示",
message: res.msg
})
if (res.code !== 3) {
return
}
}
this.formData = {
userName: this.$store.state.user.username,
loginName: this.$store.state.user.loginname,
mobile: this.$store.state.user.mobile,
sex: this.$store.state.user.sex,
birthday: this.$store.state.user.birthday,
unionName: this.$store.state.user.union.name,
unitName: this.$store.state.user.unit.name
}
this.$set(this.formData, "activityId", o.activityId)
this.$set(this.formData, "courseId", o.id)
const column = this.allColumnsData.find((x) => x.id === o.courseType)
this.dynamicColumnsData = column ? column.trainMobileSignColumnList : []
this.dynamicColumnsData.forEach((item) => {
item.columnValue = ""
})
this.joinPopup = true
},
async joinSubmit() {
let valid = false
try {
await this.$refs.trainDynamicForm.$refs.form.validate()
valid = true
} catch (e) {
valid = false
}
if (!valid) return
//获取家属是多少人
let per = 0
this.dynamicColumnsData.forEach((item) => {
if (item.columnCode === "xdqsrs") {
per += Number(item.columnValue)
}
})
const res = await this.$axios.post("/platform/mobile/trainSignUpActivity/validateSignUp", {
courseId: this.choose.id,
currentFamilyNumber: per
})
if (res.code !== 0) {
vant.Dialog.alert({
title: "提示",
message: res.msg
})
return
}
vant.Dialog.confirm({
title: "温馨提示",
message: "您确定要选择【" + this.choose.courseName + "】吗?"
})
.then(async () => {
const toast = vant.Toast.loading({
duration: 0,
forbidClick: true,
overlay: true,
message: "努力提交中"
})
const mobileColumnsValue = this.dynamicColumnsData.map((v) => {
return {
columnName: v.columnName,
columnValue: v.columnValue,
columnCode: v.columnCode,
columnFormType: v.columnFormType
}
})
this.formData.mobileColumnsValue = JSON.stringify(mobileColumnsValue)
const resp = await this.$axios.post("/platform/mobile/trainSignUpActivity/doSignUp", this.formData)
vant.Toast(resp.msg)
if (resp.code === 0) {
await this.pageData()
this.joinPopup = false
}
toast.clear()
})
.catch(() => {})
},
trainClick(o) {
this.timeList = o.courseTimeList
this.course = o
this.qdArray =
this.activityStatus === "0"
? o.courseTimeList
: this.qdInfoList.filter((item) => {
return item.courseId === o.id
})
if (o.signType === 3) {
this.initMap(o)
}
this.popupShow = true
},
initMap(o) {
if (o.courseLocationCoordinates && o.courseLocationCoordinates.length < 2) {
return
}
this.$nextTick(async () => {
// 地图初始化应该在地图容器div已经添加到DOM树之后
map = new AMap.Map("map", {
zoom: 12,
center: o.courseLocationCoordinates,
resizeEnable: true,
scrollWheel: true
})
AMap.plugin("AMap.Geolocation", function () {
geolocation = new AMap.Geolocation({
// 是否使用高精度定位,默认:true
enableHighAccuracy: true,
// 设置定位超时时间,默认:无穷大
timeout: 10000,
// 定位按钮的停靠位置的偏移量,默认:Pixel(10, 20)
buttonOffset: new AMap.Pixel(10, 20),
// 定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false
//zoomToAccuracy: true,
// 定位按钮的排放位置, RB表示右下
buttonPosition: "RB",
showCircle: false
//showButton: false,
})
map.addControl(geolocation)
})
// 创建一个 Marker 实例:
var marker = new AMap.Marker({
position: new AMap.LngLat(o.courseLocationCoordinates[0], o.courseLocationCoordinates[1]), // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
title: "签到点"
})
//获取当前坐标点
await this.getPoint()
var circle = new AMap.Circle({
center: new AMap.LngLat(o.courseLocationCoordinates[0], o.courseLocationCoordinates[1]), // 圆心位置
radius: 250, // 圆半径
borderWeight: 1,
strokeOpacity: 1,
fillOpacity: 0.4
})
map.add(circle)
// 缩放地图到合适的视野级别
map.setFitView([circle])
// 多个点实例组成的数组
var markerList = [marker]
map.add(markerList)
})
},
async pageData() {
const resp = await this.$axios.post("/platform/mobile/trainSignUpActivity/findOne", {
id: this.activityId,
tabIndex: this.activityStatus
})
if (resp.code === 0) {
this.tableData = resp.data
this.assortList = Array.from(new Set(this.tableData.courseList.map((o) => o.assort).filter((o) => o !== "" && o !== undefined)))
this.tempArray = JSON.parse(JSON.stringify(this.tableData))
if (this.assortList.length > 0 && this.activityStatus !== "1") {
this.tableData.courseList = this.tableData.courseList.filter((o) => o.assort === this.assortList[0])
}
const type = this.trainTypeList.find((o) => o.code === this.tableData.trainType)
this.trainType = type ? type.name : "培训班"
} else {
this.tableData = []
this.loading = false
}
await this.getQdInfoList()
this.courseChange(this.courseType, 1)
this.loading = false
},
async getQdInfoList() {
const resp = await this.$axios.post("/platform/mobile/trainSignUpActivity/getQdInfoList", {
activityId: this.activityId
})
if (resp.code === 0) {
this.qdInfoList = resp.data
}
},
getWeek(dateString) {
var dateArray = dateString.split("-")
const date = new Date(dateArray[0], parseInt(dateArray[1] - 1), dateArray[2])
return "周" + "日一二三四五六".charAt(date.getDay())
},
tabChange(val) {
this.tabName = val
this.tableData = []
this.pageData()
},
async getAllType() {
const resp = await this.$axios.post("/platform/trainSingUp/type/getAllType", {})
this.allColumnsData = resp.data
return resp.data
},
async getCourseText() {
const courseArray = await this.getAllType()
this.courseOptions = []
this.courseOptions.push({ text: "全部类型", value: "0" })
for (const item of courseArray) {
if (item.personMaxRegisterNum > 0) {
this.courseText += item.value + "报名最多选" + item.personMaxRegisterNum + "项,"
}
this.courseOptions.push({ text: item.typeName, value: item.id })
}
this.courseText = this.courseText.substr(0, this.courseText.length - 1)
},
courseChange(value, item) {
if (item === undefined) {
this.tableData.courseList = []
}
if (this.assortList.length > 0 && this.activityStatus !== "1") {
if (value === "0") {
this.tableData.courseList = this.tempArray.courseList.filter((o) => o.assort === this.assort)
} else {
this.tableData.courseList = this.tempArray.courseList.filter(
(item) => item.courseType === value && item.assort === this.assort
)
}
} else {
this.tableData.courseList =
value === "0" ? this.tempArray.courseList : this.tempArray.courseList.filter((item) => item.courseType === value)
}
},
async getActivity() {
const resp = await this.$axios.post("/platform/mobile/trainSignUpActivity/findOne", {
id: this.activityId,
tabIndex: 0
})
if (resp.code === 0) {
this.activity = resp.data
}
}
},
async created() {
this.$businessTool.getDictOptions("TRAIN_SIGNUP_TYPE").then((data) => {
this.trainTypeList = data
})
this.activityId = GetQueryString("activityId")
this.isMySign = Number(GetQueryString("isMySign"))
const time = GetQueryString("endTime")
if (this.isMySign === 1) {
this.activityOptions = [{ text: "我报名的", value: "1" }]
this.activityStatus = "1"
} else {
this.activityOptions = [
{ text: "全部", value: "0" },
{ text: "我报名的", value: "1" }
]
this.activityStatus = new Date().getTime() > new Date(time).getTime() ? "1" : "0"
}
this.activitySignUpStartTime = GetQueryString("activitySignUpStartTime")
vant.Toast.setDefaultOptions({ duration: 2000 })
this.pageData()
await this.getCourseText()
await this.getActivity()
}
})
</script>
<!--#
}
#-->
@@ -1,258 +0,0 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.van-card {
background: #ffffff;
margin: 10px auto 0;
width: 96%;
border-radius: 10px;
padding: 14px 12px;
}
.van-card__thumb {
display: flex;
align-items: center;
justify-content: center;
}
.van-card__content > div {
height: 100%;
display: flex;
flex-direction: column;
}
.train-title {
flex: 0.6;
margin-top: 4px;
}
.van-doc-card {
margin: 14px;
padding: 12px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 8px 12px #ebedf0;
line-height: 20px;
font-size: 12px;
position: relative;
}
.van-divider {
margin: 6px 0 5px 0px;
border-color: #1867b0;
}
.van-image__img {
max-height: 200px;
}
.van-image__error,
.van-image__loading {
height: 200px;
position: relative;
}
.tag {
position: absolute;
display: inline-block;
background-color: #1867b0;
color: #fff;
font-size: 10px;
top: 1px;
border-radius: 6px;
right: -8px;
padding: 1px 7px;
transform: rotate(17deg);
}
</style>
<div id="app" v-cloak>
<van-nav-bar title="活动列表" @click-left="historyBack" left-arrow left-text="返回" placeholder fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-dropdown-menu>
<van-dropdown-item v-model="pageForm.year" :options="yearList" @change="formChange"></van-dropdown-item>
<van-dropdown-item v-model="pageForm.activityStatus" :options="activityStatusList" @change="formChange"></van-dropdown-item>
</van-dropdown-menu>
</van-sticky>
<div>
<van-list :finished="finished" finished-text="没有更多了" v-if="tableData && tableData.length>0" v-model="loading" @load="pageData">
<div v-for="o in tableData" class="van-doc-card">
<div>
<div class="tag" style="background-color: #bc62c5" v-if="o.isDisabled">活动未开启</div>
<div class="tag" v-else-if="!o.isDisabled && $moment(o.activitySignUpStartTime).valueOf() > $moment().valueOf()">未开始报名</div>
<div
class="tag"
v-else-if="!o.isDisabled && $moment(o.activitySignUpEndTime).valueOf() > $moment().valueOf() && $moment().valueOf() > $moment(o.activitySignUpStartTime).valueOf()"
>
报名中
</div>
<div
class="tag"
style="background-color: #f14646"
v-else-if="!o.isDisabled && $moment(o.activityEndTime).valueOf() < $moment().valueOf() && $moment().valueOf() < $moment(o.activityStartTime).valueOf()"
>
报名结束
</div>
<div
class="tag"
v-else-if="!o.isDisabled && $moment(o.activityStartTime).valueOf() < $moment().valueOf() && $moment().valueOf() < $moment(o.activityEndTime).valueOf()"
>
活动进行中
</div>
<div
class="tag"
style="background-color: #f14646"
v-else-if="!o.isDisabled && $moment().valueOf() > $moment(o.activityEndTime).valueOf()"
>
活动结束
</div>
</div>
<div @click="activityClick(o)">
<div>
<van-image :src="o.cover" style="display: contents" v-if="o.cover"></van-image>
<van-image src="" style="display: contents" v-else></van-image>
</div>
<div>
<div class="van-ellipsis" style="margin-top: 6px; font-size: 15px; font-weight: bold; flex: 1">{{o.activityName}}</div>
</div>
<div>
<div class="train-title">
<span style="color: grey">&emsp;&nbsp;&emsp;度:</span>
<span>{{o.year}}</span>
</div>
<div class="train-title">
<span style="color: grey">活动对象:</span>
<span>{{o.activityGroupName}}</span>
</div>
<van-divider></van-divider>
</div>
<div class="train-title">
<span style="color: grey">报名时间:</span>
<span>{{$moment(o.activitySignUpStartTime).format('YYYY-MM-DD HH:mm')}}</span>
<span>~</span>
<span>{{$moment(o.activitySignUpEndTime).format('YYYY-MM-DD HH:mm') }}</span>
</div>
<div style="margin-top: 6px">
<span style="color: grey">活动时间:</span>
<span>{{$moment(o.activityStartTime).format('YYYY-MM-DD HH:mm')}}</span>
<span>~</span>
<span>{{$moment(o.activityEndTime).format('YYYY-MM-DD HH:mm') }}</span>
</div>
</div>
</div>
</van-list>
<van-empty v-else image="/assets/platform/plugins/vant-green/images/nodata/nodata.png" description="暂无数据"></van-empty>
</div>
<van-tabbar v-model="pageForm.activityType" @change="doSearch">
<van-tabbar-item icon="wap-home-o">活动列表</van-tabbar-item>
<van-tabbar-item icon="user-o">我报名的</van-tabbar-item>
</van-tabbar>
</div>
<script>
new Vue({
el: "#app",
store,
data() {
return {
finished: false,
loading: false,
tableData: [],
tarBarActive: 0,
pageForm: {
year: "",
activityStatus: null,
pageNumber: 1,
pageSize: 5,
totalCount: 0,
searchKeyword: "",
activityType: 0
},
activityLevelList: [],
activityStatusList: [
{ text: "全部", value: 1 },
{ text: "未开始", value: 6 },
{ text: "报名中", value: 2 },
{ text: "进行中", value: 3 },
{ text: "已结束", value: 4 }
],
yearList: []
}
},
methods: {
createYearList() {
for (let i = new Date().getFullYear() - 50; i <= new Date().getFullYear(); i++) {
this.yearList.unshift({ value: i, text: i + "年" })
}
},
doSearch() {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.tableData = []
this.pageData()
},
formChange() {
this.pageForm.pageNumber = 1
this.tableData = []
this.pageData()
},
async activityClick(o) {
if (o.isDisabled) {
this.$toast("活动未开启")
return
}
if (this.$moment(o.applyStartTime).valueOf() > this.$moment().valueOf()) {
this.$toast("活动未开始报名")
return
}
this.$pjaxReplace(
"/platform/mobile/trainSignUpActivity/activityInfo?activityId=" +
o.id +
"&endTime=" +
o.activitySignUpEndTime +
"&isMySign=" +
this.pageForm.activityType
)
},
async pageData() {
const resp = await this.$axios.post("/platform/mobile/trainSignUpActivity/pageData", this.pageForm)
if (resp.code === 0) {
if (resp.data.list.length === 0) {
this.tableData = []
this.loading = false
this.finished = true
} else {
this.tableData = this.tableData.concat(resp.data.list)
}
if (this.tableData.length === resp.data.totalCount) {
this.finished = true
} else {
this.pageForm.pageNumber++
}
}
this.loading = false
},
tabChange(val) {
this.tabName = val
this.tableData = []
this.pageForm.pageNumber = 1
this.pageData()
},
async init() {
this.$set(this.pageForm, "activityStatus", 1)
this.$set(this.pageForm, "year", new Date().getFullYear())
}
},
async created() {
this.createYearList()
await this.init()
this.pageData()
this.pageForm.activityType = Number(GetQueryString("isMySign"))
}
})
</script>
<!--#
}
#-->
@@ -1,7 +1,7 @@
const INFO = {
template: /*language=HTML*/ `
<van-action-sheet v-model="visible" title="查看详情">
<div>
<div class="detail-container">
<van-cell-group title="基本信息">
<van-cell title="填写人姓名">{{viewData.proxyUserName}}</van-cell>
<van-cell title="填写人工号">{{viewData.proxyLoginName}}</van-cell>
@@ -0,0 +1,31 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<van-sticky>
<van-nav-bar title="咨询师预约" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
</van-sticky>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
pageForm: {
pageNum: 1,
pageSize: 10,
searchKeyword: '',
}
}
},
methods: {
historyBack,
},
created() {
}
});
</script>
<!--#
}
#-->
@@ -0,0 +1,62 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
.container {
margin: 0 auto;
padding: 15px;
}
</style>
<div id="app">
<van-sticky>
<van-nav-bar title="咨询师列表" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
<van-search
v-model="pageForm.searchKeyword"
placeholder="请输入工号或者姓名进行查询"
show-action
:reverse-color="false"
input-align="left"
@search="doSearch">
<template #action>
<div @click="doSearch">搜索</div>
</template>
</van-search>
</van-sticky>
<div class="container">
<div >
<div class="consultant-list">
</div>
</div>
</div>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
consultantList: []
}
},
methods: {
historyBack,
async pageData(){
const resp = await this.$axios.post('/platform/psychology/index/listConsultantByH5')
if (resp.code === 0) {
this.consultantList = resp.data
}
}
},
created() {
}
});
</script>
<!--#
}
#-->
@@ -0,0 +1,181 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
.container {
margin: 0 auto;
padding: 15px;
}
.grid-menu {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
margin-bottom: 20px;
height: 100px;
background: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
transition:
transform 0.3s ease,
box-shadow 0.3s ease;
border-radius: 12px;
}
.menu-item {
padding: 10px;
text-align: center;
cursor: pointer;
}
.menu-item img {
border-radius: 8px;
width: 100%;
}
.menu-text {
font-size: 13px;
color: #3498db;
}
.consultant, .article {
margin-bottom: 20px;
height: 200px;
background: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
transition:
transform 0.3s ease,
box-shadow 0.3s ease;
border-radius: 12px;
}
.consultant-list {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
padding: 2px 14px;
}
.consultant-title {
display: flex;
justify-content: space-between;
padding: 10px 15px;
}
.consultant-item {
padding: 0;
text-align: center;
cursor: pointer;
}
.consultant-item img {
border-radius: 3px 8px;
border: 1px solid #3498db;
width: 100%;
height: 115px;
}
.consultant-name{
font-size: 14px;
color: #000000;
}
</style>
<div id="app">
<van-nav-bar title="心理咨询" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
<div class="container">
<!-- 入口 -->
<div class="grid-menu">
<div v-for="item in menuList" :key="item.name" class="menu-item" @click="enterQuick">
<div class="menu-icon">
<img slot="icon" :src="item.icon">
</div>
<div class="menu-text">
{{ item.name }}
</div>
</div>
</div>
<!-- 咨询师列表 -->
<div class="consultant">
<div class="consultant-title">
<div style="font-weight: bold;font-size: 19px">
推荐咨询师
</div>
<div style="color: gray;font-size: 14px" @click="showAllConsultant">更多>></div>
</div>
<div v-if="consultantList && consultantList.length > 0" class="consultant-list">
<div v-for="(item, index) in consultantList" :key="index"
class="consultant-item" @click="showConsultant(item)">
<div class="consultant-avatar">
<img slot="icon" :src="item.avatar">
</div>
<div class="consultant-name">
{{ item.userName }}
</div>
</div>
</div>
<div v-else>
<div style="text-align: center;padding: 20px">
暂无数据
</div>
</div>
</div>
<!-- 文章列表 -->
<div class="article">
<div class="article-title" style="padding: 10px 15px;">
<div style="font-weight: bold;font-size: 19px">
文章列表
</div>
</div>
</div>
</div>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
menuList: [
{name: '通知公告', icon: 'https://img01.yzcdn.cn/vant/apple-1.jpg', url: '/platform/h5/home'},
{name: '预约日历', icon: 'https://img01.yzcdn.cn/vant/apple-1.jpg', url: '/platform/h5/home'},
{name: '分类预约', icon: 'https://img01.yzcdn.cn/vant/apple-1.jpg', url: '/platform/h5/home'},
{name: '咨询师列表', icon: 'https://img01.yzcdn.cn/vant/apple-1.jpg', url: '/platform/h5/home'},
],
consultantList: []
}
},
methods: {
historyBack,
// 快速入口跳转
enterQuick(item) {
console.log(item)
},
// 查看所有咨询师,跳转到咨询师列表页面
showAllConsultant(){
},
// 查看单个咨询师,跳转到这个咨询师的详情页面
showConsultant(item){
console.log(item)
},
// 查询咨询师列表
async listConsultant(){
const resp = await this.$axios.post('/platform/psychology/index/listConsultantByH5')
if (resp.code === 0) {
this.consultantList = resp.data
}
}
},
created() {
this.listConsultant()
}
});
</script>
<!--#
}
#-->
@@ -1,7 +1,7 @@
const INFO = {
template: /*language=HTML*/ `
<van-action-sheet v-model="visible" title="查看详情">
<div>
<div class="detail-container">
<van-cell-group title="基本信息">
<van-cell title="工号">{{ viewData.loginname }}</van-cell>
<van-cell title="姓名">{{ viewData.username }}</van-cell>
@@ -1,63 +1,63 @@
const MOBILE_MEMBER_INFO = {
template: `
<div>
template: /*language=HTML*/ `
<div class="detail-container">
<van-cell-group title="基本信息">
<van-cell title="工号">{{ viewData.loginname }}</van-cell>
<van-cell title="姓名">{{ viewData.username }}</van-cell>
<van-cell title="性别">{{ viewData.sex }}</van-cell>
<van-cell title="工号">{{ viewData.loginname }}</van-cell>
<van-cell title="姓名">{{ viewData.username }}</van-cell>
<van-cell title="性别">{{ viewData.sex }}</van-cell>
<van-cell title="民族">{{ viewData.nation }}</van-cell>
<van-cell title="出生日期">{{ $moment(viewData.birthday).format("YYYY年MM月DD日") }}</van-cell>
<van-cell title="政治面貌">{{ viewData.political }}</van-cell>
<van-cell title="民族">{{ viewData.nation }}</van-cell>
<van-cell title="出生日期">{{ $moment(viewData.birthday).format("YYYY年MM月DD日") }}</van-cell>
<van-cell title="政治面貌">{{ viewData.political }}</van-cell>
<van-cell title="学历">{{ viewData.education }}</van-cell>
<van-cell title="学位">{{ viewData.academicDegree }}</van-cell>
<van-cell title="党政职务">{{ viewData.position }}</van-cell>
<van-cell title="学历">{{ viewData.education }}</van-cell>
<van-cell title="学位">{{ viewData.academicDegree }}</van-cell>
<van-cell title="党政职务">{{ viewData.position }}</van-cell>
<van-cell title="工作单位">{{ viewData.unitName }}</van-cell>
<van-cell title="所属工会">{{ viewData.unionName }}</van-cell>
<van-cell title="所属校区">{{ viewData.campus }}</van-cell>
<van-cell title="工作单位">{{ viewData.unitName }}</van-cell>
<van-cell title="所属工会">{{ viewData.unionName }}</van-cell>
<van-cell title="所属校区">{{ viewData.campus }}</van-cell>
<van-cell title="身份证号码">{{ viewData.idCard }}</van-cell>
<van-cell title="联系电话">{{ viewData.mobile }}</van-cell>
<van-cell title="电子邮箱">{{ viewData.email }}</van-cell>
<van-cell title="身份证号码">{{ viewData.idCard }}</van-cell>
<van-cell title="联系电话">{{ viewData.mobile }}</van-cell>
<van-cell title="电子邮箱">{{ viewData.email }}</van-cell>
<van-cell title="在职状态">{{ viewData.userState }}</van-cell>
<van-cell title="人员类型">{{ viewData.personType }}</van-cell>
<van-cell title="人员性质">{{ viewData.preparedBy || '暂无' }}</van-cell>
<van-cell title="在职状态">{{ viewData.userState }}</van-cell>
<van-cell title="人员类型">{{ viewData.personType }}</van-cell>
<van-cell title="人员性质">{{ viewData.preparedBy || '暂无' }}</van-cell>
<template v-if="viewData.loginname === $store.state.user.loginnmae">
<van-cell title="家庭成员" class="column-cell">
<table class="family-table">
<thead>
<tr>
<th class="table-header">序号</th>
<th class="table-header">与本人关系</th>
<th class="table-header">姓名</th>
<th class="table-header">单位</th>
<th class="table-header">备注</th>
</tr>
</thead>
<tbody>
<tr class="table-row" v-for="(item, index) in viewData.families" :key="index">
<td class="table-cell">{{ index + 1 }}</td>
<td class="table-cell">{{ item.relation }}</td>
<td class="table-cell">{{ item.name }}</td>
<td class="table-cell">{{ item.unit }}</td>
<td class="table-cell">{{ item.remark }}</td>
</tr>
</tbody>
</table>
</van-cell>
<template v-if="viewData.loginname === $store.state.user.loginnmae">
<van-cell title="家庭成员" class="column-cell">
<table class="family-table">
<thead>
<tr>
<th class="table-header">序号</th>
<th class="table-header">与本人关系</th>
<th class="table-header">姓名</th>
<th class="table-header">单位</th>
<th class="table-header">备注</th>
</tr>
</thead>
<tbody>
<tr class="table-row" v-for="(item, index) in viewData.families" :key="index">
<td class="table-cell">{{ index + 1 }}</td>
<td class="table-cell">{{ item.relation }}</td>
<td class="table-cell">{{ item.name }}</td>
<td class="table-cell">{{ item.unit }}</td>
<td class="table-cell">{{ item.remark }}</td>
</tr>
</tbody>
</table>
</van-cell>
<van-cell title="个人简历">
<template #label>
<div v-if="viewData.vita" class="text-left" v-html="viewData.vita"></div>
<span style="font-size: 14px" v-else>无数据</span>
</template>
</van-cell>
</template>
</van-cell-group>
<van-cell title="个人简历">
<template #label>
<div v-if="viewData.vita" class="text-left" v-html="viewData.vita"></div>
<span style="font-size: 14px" v-else>无数据</span>
</template>
</van-cell>
</template>
</van-cell-group>
</div>
`,
props: {