first commit

This commit is contained in:
2026-01-08 14:58:16 +08:00
commit 556e5d64aa
9575 changed files with 1621095 additions and 0 deletions
@@ -0,0 +1,165 @@
<!--#
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/fellowship/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}">
<template v-if="$moment().isBefore($moment(row.activitySignUpEndTime))">
<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>
</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 nonce="${cspNonce!}">
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: 2,
},
typeOptions: [
{text: '全部', value: 1},
{text: '即将开始 & 报名中', value: 2},
{text: '已结束', value: 3},
],
infoVisible: false,
infoRow: {},
id: GetQueryString('id')
}
},
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/fellowship/apply/list/h5?id=' + row.id)
},
fetchOne() {
this.$axios.post('/platform/fellowship/manage/findOne', {id: this.id}).then((res) => {
if(res.code === 0) {
this.onView(res.data)
}
})
},
onReady() {
this.doSearch()
if(this.id) {
this.fetchOne()
}
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
},
mounted() {
}
})
</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/fellowship/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,159 @@
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>
<train-dynamic-form v-model="dynamicColumnsData" ref="dynamicForm"></train-dynamic-form>
</van-cell-group>
<div class="button">
<van-button @click="onSubmit" round type="info" block>提交</van-button>
</div>
</van-form>
</van-action-sheet>
</div>
`,
data() {
return {
row: {},
activity: {},
dynamicColumnsData: [],
visible: false,
formData: {},
showCoursePicker: false,
courseTimeSelectList: [],
}
},
components: {
"train-dynamic-form": httpVueLoader("/components/module/trainSignUp/TrainDynamicForm.vue")
},
methods: {
async onOpen(row, courseType) {
this.row = row
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.dynamicColumnsData = courseType ? courseType.trainMobileSignColumnList : []
this.dynamicColumnsData.forEach((item) => {
item.columnValue = this.$store.state.user[item.columnCode] || ""
})
},
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/trainSignUp/apply/getCourseTimeSelectList',{courseId: o.id})
if (resp.code === 0) {
this.courseTimeSelectList = resp.data
} else {
this.$toast.fail("获取时段信息失败,请联系管理员")
}
},
async validateSignUp() {
// 验证自定义表单
await this.$refs.dynamicForm.$refs.form.validate()
// 获取家属人数
let familyCount = this.dynamicColumnsData.filter(o => o.columnCode === 'xdqsrs').reduce((sum, item) => {
return sum + (Number(item.columnValue) || 0)
}, 0)
const res = await this.$axios.post("/platform/trainSignUp/apply/validateSignUp", {
courseId: this.formData.courseId,
currentFamilyNumber: familyCount
})
return res.code === 0
},
async validateCourseTime() {
const res = await this.$axios.post('/platform/trainSignUp/apply/validateSourceSignUp', {
activityCourseId: this.formData.activityCourseId,
courseId: this.row.id
})
return res.code === 0
},
async onSubmit() {
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 mobileColumnsValue = this.dynamicColumnsData.map((v) => {
return {
columnName: v.columnName,
columnValue: v.columnValue,
columnCode: v.columnCode,
columnFormType: v.columnFormType
}
})
this.formData.mobileColumnsValue = JSON.stringify(mobileColumnsValue)
this.$axios.post("/platform/trainSignUp/apply/doSignUp", this.formData).then(res => {
if (res.code === 0) {
this.$toast(res.msg)
this.visible = false
this.$emit('refresh')
}
})
})
})
},
},
style: /*language=CSS*/ `
/deep/ .button {
position: fixed;
bottom: 0;
width: 100%;
}
`
}
@@ -0,0 +1,255 @@
<!--#
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;
}
</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>
<van-tabs v-if="assortList.length > 0" type="card" color="#1867B0"
style="margin-top: 10px" @click="tabClick">
<van-tab v-for="item in assortList" :name="item" :title="item">
</van-tab>
</van-tabs>
<table-list api="/platform/trainSignUp/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" label="详细信息">
<span @click="introduceRow = row; introduceVisible = true" class="primary-color">点我查看</span>
</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 nonce="${cspNonce!}">
<!--#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'),
assortTypes: [],
},
typeOptions: [],
assortOptions: [],
sourceTypeOptions: [],
introduceVisible: false,
introduceRow: {},
activity: {},
assortList: [],
weekdayCNMap: {0: '周日', 1: '周一', 2: '周二', 3: '周三', 4: '周四', 5: '周五', 6: '周六'},
}
},
methods: {
tabClick(name) {
this.pageForm.assortTypes = []
this.pageForm.assortTypes.push(name)
this.pageForm.assortTypes = JSON.stringify(this.pageForm.assortTypes)
this.doSearch()
},
refresh() {
this.doSearch()
},
async onTime(row) {
// 如果设置签到,并且也报名的话
if(row.isMobileSign === true && row.isSign === true) {
const res = await this.$axios.post('/platform/trainSignUp/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/trainSignUp/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)
}
})
},
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/trainSignUp/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() {
this.queryCourseAssort()
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/trainSignUp/manage/findOne', {id: this.pageForm.activityId})
.then((res) => {
this.activity = res.data
})
},
async getCourseTypeList() {
const resp = await this.$axios.post("/platform/trainSignUp/type/getAllType")
return resp.data
},
queryCourseAssort() {
this.$axios.post("/platform/trainSignUp/apply/queryCourseAssort", {activityId: this.pageForm.activityId})
.then((resp) => {
this.assortList = resp.data
if(this.assortList.length > 0) {
this.pageForm.assortTypes = JSON.stringify([this.assortList[0]])
}
})
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
},
})
</script>
<!--#
}
#-->
@@ -0,0 +1,132 @@
<!--#
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;
}
</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/trainSignUp/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" 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>
</div>
<script nonce="${cspNonce!}">
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: {},
}
},
methods: {
onView(row) {
this.infoRow = row
this.infoVisible = true
},
onApply(row) {
this.$pjaxReplace('/platform/trainSignUp/apply/list/h5?id=' + row.id + '&dataType=mine')
},
onReady() {
this.doSearch()
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
},
})
</script>
<!--#
}
#-->