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,234 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.list-card {
border-radius: 0;
}
.list-card-body {
/* width: calc(100% - 140px);
display: flex;*/
width: calc(100% - 140px);
display: flex;
flex-direction: column;
justify-content: space-between;
}
.list-card-body .title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 1.1em;
}
.list-card-body .time {
color: #9a9696;
line-height: 20px;
}
.list-card-body .footer {
text-align: right;
}
.list-card-body .footer .tag {
border: 1px solid transparent;
padding: 5px;
border-radius: 5px;
}
.list-card-img img{
width: 100%;
}
</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>
<year-van-dropdown-item :num="5" @change="doSearch" v-model="pageForm.year"></year-van-dropdown-item>
<van-dropdown-item :options="stateList" @change="doSearch" v-model="pageForm.state"></van-dropdown-item>
<van-dropdown-item :options="isEnrolledOptions" @change="doSearch" v-model="pageForm.isEnrolled"></van-dropdown-item>
<van-dropdown-item :options="activityTypeOptions" @change="doSearch" v-model="pageForm.activity_type"></van-dropdown-item>
</van-dropdown-menu>
</van-sticky>
<table-list api="/platform/activity/culture/applyUser/pageData"
:page_form.sync="pageForm"
ref="tableListRef"
title="name"
img="cover"
@ready="onReady"
>
<template v-slot="{index,row}">
<table-column label="报名开始时间">
{{$moment(row.startTime).format('MM/DD HH:mm')}}
</table-column>
<table-column label="报名结束时间">
{{$moment(row.endTime).format('MM/DD HH:mm')}}
</table-column>
</template>
<template #actions="{index,row}">
<template v-if="$moment().isBefore($moment(row.endTime))">
<div class="action-btn" @click="openDetail(row)">
<i class="fa fa-edit"></i>
<span>去报名</span>
</div>
</template>
</template>
</table-list>
<van-popup :style="{ height: '100%',width: '100%'}" position="right" v-model="viewShow">
<mobile-culture-apply-user :id="viewData.id" @back="back" @submit_back="submit_back" ref="viewInfo"></mobile-culture-apply-user>
</van-popup>
</div>
<script nonce="${cspNonce!}">
<!--#include("mobileCultureApplyUser.js"){}#-->
new Vue({
el: "#app",
data() {
return {
tableData: [],
finished: false,
loading: false,
refreshing: false,
pageForm: {
state: 2,
isEnrolled: 0,
year: new Date().getFullYear(),
pageNumber: 1,
pageSize: 5,
totalCount: 0,
activity_type: 40001
},
yearList: [],
isEnrolledOptions: [
{ value: 0, text: "未报名" },
{ value: 1, text: "已报名" }
],
stateList: [
{ value: 1, text: "全部" },
{ value: 2, text: "报名中" },
{ value: 3, text: "报名已结束" }
],
subLoading: false,
viewShow: false,
viewData: {},
activityTypeOptions: [
{ value: 40001, text: "校文化活动" },
{ value: 40002, text: "分工会文化活动" },
{ value: 40003, text: "协会文化活动" },
]
}
},
components: {
"mobile-culture-apply-user": MOBILE_CULTURE_APPLY_USER
},
methods: {
onReady() {
this.doSearch()
},
openDetail(row) {
this.$axios.post('/platform/activity/basic/scope/getScopeUser',{activityGroupId:row.groupId}).then(res=>{
if(res.code===0){
if(res.data>0){
this.$pjaxReplace("/platform/h5/activity/culture/signUp?id=" + row.id)
}else{
this.$toast('您没有权限参加此活动')
}
}
})
},
submit_back(id, countUser) {
this.tableData.map((t) => {
if (t.id === id) {
t.countUser = countUser
}
})
this.viewShow = false
this.$toast.success("报名成功")
},
back() {
this.viewShow = false
},
openAudit(row) {
this.viewData = row
this.viewShow = true
setTimeout(() => {
this.$refs.viewInfo.getActivityInfo()
}, 500)
},
async doAdd(row) {
this.$dialog
.confirm({
title: "提示",
message: "确认要报名吗?"
})
.then(() => {
this.$axios.post("/platform/activity/culture/applyUser/singleSignUp", { activityId: row.id }).then((res) => {
if (res.code === 0) {
this.$toast.loading({
duration: 0,
forbidClick: true,
message: "加载中...."
})
setTimeout(() => {
this.$toast.clear()
this.$toast.success(res.msg)
this.doSearch()
this.subLoading = false
}, 1000)
} else {
this.subLoading = false
}
})
})
.catch(() => {})
},
async doDelete(row) {
this.$dialog
.confirm({
title: "提示",
message: "确认要取消报名吗?"
})
.then(() => {
this.$axios.post("/platform/activity/culture/applyUser/cancelSignUp", { activityId: row.id }).then((res) => {
if (res.code === 0) {
this.$toast.loading({
duration: 0,
forbidClick: true,
message: "加载中...."
})
setTimeout(() => {
this.$toast.clear()
this.$toast.success(res.msg)
this.doSearch()
this.subLoading = false
}, 1000)
} else {
this.$toast.fail(res.msg)
}
})
})
.catch(() => {})
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
},
created() {
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,334 @@
var MOBILE_CULTURE_APPLY_USER = {
template: `
<div>
<van-nav-bar :title="title" @click-left="back" fixed left-arrow left-text="返回"
placeholder></van-nav-bar>
<div class="activity_img_back">
<van-image :src="viewData.cover" height="200"
width="100%"></van-image>
</div>
<van-cell-group class="mt10" inset>
<van-cell :value="viewData.name" title="活动名称"></van-cell>
<van-cell :value="viewData.address" title="活动地址"></van-cell>
<van-cell v-if="viewData.userNumberLimit!=null">
<template #title>
<span v-if="viewData.userNumberLimit===1">
活动限制人数
</span>
<span v-else-if="viewData.userNumberLimit===2">
本工会限制名额
</span>
</template>
<template>
<span v-if="viewData.userNumberLimit===1">
<span style="color: orange">{{viewData.totalUserNumberLimit }}</span>人
</span>
<span v-else="viewData.userNumberLimit===2">
<span style="color: orange">{{viewData.unionLimitNum }}</span>人
</span>
</template>
</van-cell>
<van-cell title="当前活动报名" v-if="viewData.signUpMethod!=null">
<template>
<span style="color: red">{{viewData.tissuePersonList.length}}</span>人
</template>
</van-cell>
<van-cell title="报名方式" v-if="viewData.signUpMethod">
<template>
<span v-if="viewData.signUpMethod===1">个人报名</span>
<span v-if="viewData.signUpMethod===2">分工会报名</span>
<span v-if="viewData.signUpMethod===3">组队报名</span>
</template>
</van-cell>
<van-cell title="组队人数" v-if="viewData.signUpMethod==3">
<span style="color: red"> {{viewData.teamNum}}</span>人
</van-cell>
<van-cell title="活动内容" v-if="viewData.projectTypeCode!=='50004'">
<template #label>
<span style="white-space: pre-line">
{{viewData.activityContent}}
</span>
</template>
</van-cell>
</van-cell-group>
<van-cell-group class="mt5" inset>
<van-cell class="regCell" title="报名人员">
<template #label>
<div>
<span v-if="viewData.userNumberLimit===1">
本活动限制总报名人数:({{viewData.totalUserNumberLimit}})人
</span>
<span v-else-if="viewData.userNumberLimit===2">
当前分工会报名限额 <span style="color: orange">{{viewData.limitUnion.limitNum}})人</span>
</span>
</div>
<div class="mt5" v-loading="tagCloseable">
<div v-if="registerList && registerList.length>0">
<template v-for="item in registerList">
<van-tag closeable type="success"
:plain="false"
@close="removeRegUser(item)" style="margin: 5px;font-size: 13px;">
<span style="margin: 5px;">{{item.userName}}</span>
</van-tag>
</template>
</div>
<div v-else>
<div style="text-align: center;margin-top: 20px;">
无报名人员
</div>
</div>
</div>
<div class="mt5" style="text-align: right"
v-if="$moment(viewData.applyStartTime).valueOf() < $moment().valueOf() &&
$moment().valueOf() < $moment(viewData.applyEndTime).valueOf()">
<van-button @click="openUserActionSheet" size="mini"
type="primary" style="font-size: 15px;height:25px;margin: 5px">
<span>选择报名人员</span>
</van-button>
</div>
</template>
</van-cell>
</van-cell-group>
<van-action-sheet class="userActionPopup" title="选择报名人员" v-model="userActionSheet">
<van-search @search="onSearchUser" placeholder="请输入姓名搜索" show-action
v-model="searchKey">
<template #action>
<div @click="onSearchUser(searchKey)">搜索</div>
</template>
</van-search>
<template v-if="searchLoading">
<van-loading size="24px" vertical>搜索中...</van-loading>
</template>
<div>
<div class="van-action-sheet__content mt5"
v-if="searchUserList && searchUserList.length>0">
<template>
<template v-for="item in searchUserList"
v-if="!registerList.map(v=>v.id).includes(item.id)">
<button @click="searchUserAdd(item)"
class="van-action-sheet__item van-hairline--bottom">
<span class="van-action-sheet__name">{{item.userName}}{{item.loginName}}</span>
</button>
</template>
</template>
</div>
<van-empty v-else image="/assets/platform/plugins/vant-green/images/nodata/nodata.png" description="暂无数据"></van-empty>
</div>
</van-action-sheet>
<div style="margin: 15px">
<van-button @click="doSave()" block style="border-radius: 10px;"
type="primary">
提 交
</van-button>
</div>
</div>
`,
store,
props: {
id: {
value: { type: Object, default: "" }
}
},
data() {
return {
title: "活动报名",
viewData: {},
registerList: [],
addRegisterList: [],
userActionSheet: false,
searchKey: "",
searchUserList: [],
tagCloseable: true,
searchLoading: false
}
},
methods: {
async doSave() {
if (this.registerList.length === 0) {
this.$toast("请添加报名人员后再提交!")
return
}
//如果是组队报名
if (this.viewData.signUpMethod === 3) {
//判断报名了几个人
if (this.registerList.length !== this.viewData.teamNum) {
this.$dialog
.alert({
title: "温馨提示",
message: "此活动是双人报名模式您需要报名" + this.viewData.teamNum + "人!"
})
.then(() => {})
return
}
if (!this.registerList.map((v) => v.id).includes(this.$store.state.user.id)) {
this.$dialog
.alert({
title: "温馨提示",
message: "此活动是组队模式需要" + this.viewData.teamNum + "个人一起报名!"
})
.then(() => {})
return
}
let arr = []
//判断提交的人员当中有没有人报名
this.$axios.post("/platform/h5/activity/culture/selectRegisterList", { activityId: this.id }).then((resp) => {
this.addRegisterList = resp.data
if (this.addRegisterList && this.addRegisterList.length > 0) {
this.addRegisterList.forEach((v) => {
this.registerList.forEach((r) => {
if (v.id === r.id && v.applyUserId !== this.$store.state.user.id) {
arr.push(r.userName)
}
})
})
}
})
if (arr && arr.length > 0) {
vant.Dialog.alert({
title: "温馨提示",
message: "【" + arr.toString() + "】已成功报名您无需再报名!"
}).then(() => {})
return
}
}
const confirm = await this.$dialog.confirm({
title: "提示",
message: "您确认要报名吗?"
})
if (confirm === "confirm") {
const loading = this.$toast.loading({
message: "报名中...",
forbidClick: true,
overlay: true,
duration: 0
})
const params = {
activityId: this.viewData.id,
personIds: JSON.stringify(this.registerList.map((v) => v.id))
}
this.$axios.post("/platform/activity/culture/applyUser/doSaveUnionRegister", params).then((resp) => {
if (resp.code === 0) {
setTimeout(() => {
loading.close()
this.$emit("submit_back", this.viewData.id, this.registerList.length)
}, 1000)
} else {
this.$toast.fail(resp.msg)
}
})
}
},
searchUserAdd(item) {
const { id, userName } = item
this.registerList.push({ id, userName })
this.$toast.success("添加成功")
},
onSearchUser(val) {
if (!val) {
this.$toast.fail("请输入搜索条件")
return
}
this.searchLoading = true
this.$axios
.post("/platform/h5/activity/culture/searchNoRegisterUser", {
activityId: this.viewData.id,
searchKey: val
})
.then((resp) => {
if (resp.code === 0) {
this.searchLoading = false
this.searchUserList = resp.data.list
} else {
this.$toast.fail(resp.msg)
}
})
},
openUserActionSheet() {
this.searchKey = ""
this.searchUserList = []
this.userActionSheet = true
},
async removeRegUser(item) {
if (this.$store.state.user.id === item.id) {
this.$toast.fail("自己不能删除")
return
}
const confirm = await this.$dialog.confirm({
title: "提示",
message: "您确认要移除吗?"
})
if (confirm === "confirm") {
const index = this.registerList.findIndex((v) => v.id === item.id)
this.registerList.splice(index, 1)
}
},
back() {
this.$emit("back")
},
getRegisterUser() {
this.$axios.post("/platform/h5/activity/culture/selectRegisterList", { activityId: this.id }).then((resp) => {
if (resp.code === 0) {
if (this.viewData.signUpMethod === 3) {
this.registerList = resp.data.filter((v) => v.applyUserId === this.$store.state.user.id)
} else {
this.registerList = resp.data
}
this.addRegisterList = resp.data
if (this.registerList.length > 0) {
this.tagCloseable = false
}
}
})
},
getActivityInfo() {
this.$toast.loading({
message: "加载中...",
forbidClick: true
})
this.getRegisterUser()
this.$axios.post("/platform/activity/culture/infoManage/findOne", { id: this.id }).then((res) => {
if (res.data) {
res.data.billFiles = JSON.parse(res.data.billFiles)
res.data.photoFiles = JSON.parse(res.data.photoFiles)
res.data.otherFiles = JSON.parse(res.data.otherFiles)
res.data.unionUserNumberLimit = JSON.parse(res.data.unionUserNumberLimit)
if (!this.$store.state.user.union.id) {
this.$toast.fail("您的所属工会信息缺失,请联系管理员")
return
}
if (res.data.userNumberLimit === 2) {
const unionLimit = res.data.unionUserNumberLimit.find((v) => v.id === this.$store.state.user.union.id)
res.data.unionLimitNum = unionLimit.limitNum
}
this.viewData = res.data
if (this.viewData.signUpMethod === 3 && this.registerList.length === 0) {
this.registerList.push({
id: this.$store.state.user.id,
userName: this.$store.state.user.username
})
}
setTimeout(() => {
this.$toast.clear()
}, 1000)
} else {
this.viewData = {}
}
})
}
}
}
@@ -0,0 +1,794 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.title {
padding: 10px;
font-size: 1.2em;
font-weight: bold;
background: #ffffff;
}
.info-item {
display: flex;
align-items: center;
padding: 20px 15px;
border-bottom: 1px solid #ededed;
column-gap: 10px;
background: #ffffff;
}
.left-tag-title::before {
content: "";
width: 5px;
background: var(--color-primary);
display: inline-block;
position: absolute;
left: 0;
top: 0;
bottom: 0;
}
.users {
padding: 10px;
margin-top: 10px;
border-top: 1px solid #e8e0e0;
background: #ffffff;
}
.users-title {
font-size: 1.1em;
position: relative;
padding-left: 10px;
}
.users-content {
padding: 10px;
overflow-x: auto;
display: flex;
flex-wrap: nowrap;
gap: 20px;
}
.users-content .users-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
width: 80px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex-shrink: 0;
}
.block {
padding: 10px;
margin-top: 10px;
border-top: 1px solid #e8e0e0;
background: #ffffff;
}
.notice {
padding: 10px;
margin-top: 10px;
border-top: 1px solid #e8e0e0;
background: #ffffff;
}
.notice-title {
font-size: 1.1em;
position: relative;
padding-left: 10px;
}
.notice-content {
padding: 10px;
box-sizing: border-box;
}
.notice-content img {
max-width: 100% !important;
}
.footer {
position: fixed;
background: #ffffff;
height: 56px;
display: flex;
align-items: center;
justify-content: space-between;
bottom: 0;
left: 0;
right: 0;
}
.footer .bottom-button {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: rgb(255, 255, 255);
height: 100%;
}
.form-create-h5 {
background-color: #ffffff;
margin-top: 10px;
padding: 10px 10px 56px 10px;
}
.form-create-h5 .el-form {
margin-top: 20px;
}
.form-create-h5 .el-col-12 {
width: 100%;
}
.form-create-h5 .el-row--flex.is-align-middle {
flex-direction: column;
}
.form-create-h5 .el-form-item {
display: flex;
flex-direction: column;
}
.form-create-h5 .el-form-item .el-form-item__label {
width: 100% !important;
text-align: left !important;
color: #000;
font-size: 16px;
}
.form-create-h5 .el-form-item .el-form-item__content {
margin-left: 0 !important;
}
.form-create-h5 .el-radio-group {
display: flex;
flex-direction: column;
row-gap: 20px;
}
.form-create-h5 .el-radio-group label {
width: 100%;
margin-right: 0;
}
</style>
<div id="app" v-cloak>
<van-nav-bar @click-left="historyBack" placeholder fixed left-arrow left-text="返回" placeholder
title="活动详情"></van-nav-bar>
<div style="background: #ededed; padding-bottom: 56px">
<van-image :src="viewData.cover"></van-image>
<div class="title">{{viewData.name}}</div>
<div class="info">
<div class="info-item">
<van-icon name="underway-o"></van-icon>
<div>{{viewData.startTime}}至{{viewData.endTime}}</div>
</div>
<div class="info-item">
<van-icon name="location-o"></van-icon>
<div>{{viewData.address}}</div>
</div>
<div class="info-item" v-if="viewData.userNumberLimit===1">
<van-icon name="location-o"></van-icon>
活动限制人数
<span>{{viewData.totalUserNumberLimit}}人</span>
</div>
<div class="info-item" v-if="viewData.userNumberLimit===2">
<van-icon name="location-o"></van-icon>
本工会限制名额
<span>{{viewData.unionLimitNum}}人</span>
</div>
<div class="info-item">
<van-icon name="location-o"></van-icon>
报名方式:
<span v-if="viewData.signUpMethod===1" style="color: var(--color-primary)">个人报名</span>
<span v-if="viewData.signUpMethod===2" style="color: var(--color-primary)">组队报名</span>
<span v-if="viewData.signUpMethod===3" style="color: var(--color-primary)">分工会报名</span>
</div>
<div class="info-item" v-if="viewData.signUpMethod==3">
<van-icon name="location-o"></van-icon>
组队人数:
<span style="color: var(--color-primary)">{{viewData.teamNum}}</span>
</div>
<!-- <div class="info-item" v-if="viewData.signUpMethod==1">-->
<!-- <van-icon name="location-o"></van-icon>-->
<!-- 报名人数:-->
<!-- <span style="color: var(&#45;&#45;color-primary)">2</span>-->
<!---->
<!-- </div>-->
</div>
<div class="notice">
<div class="notice-title left-tag-title">活动详情</div>
<rich-text :value="viewData.activityContent" :height="300"></rich-text>
</div>
<!-- 个人报名 啥也不要-->
<template v-if="viewData.signUpMethod===1" class="block"></template>
<!-- 组队报名-->
<div v-if="viewData.signUpMethod===2" class="block">
<div class="notice-title left-tag-title">
选择组队队友,组队人数
<span style="color: red">{{viewData.teamNum}}</span>
</div>
<span v-if="!isApplyUser" class="text-primary">如需取消报名,请联系报名人。</span>
<div style="margin-top: 10px">
<el-select
v-if="isApplyUser && inApplyTime"
v-model="searchTeammateUserId"
filterable
clearable
remote
reserve-keyword
placeholder="请输入关键词"
:remote-method="queryTeammate"
>
<el-option
v-for="item in teammateOptions"
:key="item.userId"
:label="item.userName + '(' + item.loginName + ')'"
:value="item.userId"
></el-option>
</el-select>
<el-button v-if="isApplyUser && inApplyTime" class="ml5" type="primary" icon="el-icon-plus"
@click="addTeamUser">添加
</el-button>
<el-table :data="teamUsers" class="mt10" border>
<el-table-column label="序号" type="index" width="60px"></el-table-column>
<el-table-column prop="userName" label="姓名"></el-table-column>
<el-table-column prop="loginName" label="工号"></el-table-column>
<!-- <el-table-column prop="sex" label="性别"></el-table-column>-->
<!-- <el-table-column prop="unitName" label="单位"></el-table-column>-->
<!-- <el-table-column prop="mobile" label="手机号"></el-table-column>-->
<el-table-column prop="applyUserId" label="标识">
<template slot-scope="{row}">
<!-- v-if="scope.row.applyUserId===scope.row.userId"-->
<el-tag size="mini" v-if="row.applyUserId==row.userId">报名人</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="100px"
v-if="(isApplyUser || teamUsers.length===0) && inApplyTime">
<template slot-scope="scope">
<el-button
type="danger"
size="mini"
@click="removeTeamUser(scope.$index)"
v-if="scope.row.applyUserId!==scope.row.userId"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<!-- 分工会报名-->
<div v-else-if="viewData.signUpMethod===3" class="block">
<div class="notice-title left-tag-title">选择报名人员
<span v-if="viewData.userNumberLimit===2">
,报名人数 <span style="color: red">
{{viewData.unionTeamNum}}</span>
</span>
</div>
<el-select
v-if="inApplyTime"
v-model="searchTeammateUserId"
filterable
clearable
remote
reserve-keyword
placeholder="请输入关键词"
:remote-method="queryTeammate">
<el-option
v-for="item in teammateOptions"
:key="item.userId"
:label="item.userName + '(' + item.loginName + ')'"
:value="item.userId">
</el-option>
</el-select>
<el-button v-if="inApplyTime" class="ml5" type="primary" icon="el-icon-plus"
@click="addTeamUser">添加
</el-button>
<el-table :data="teamUsers" class="mt10">
<el-table-column label="序号" type="index" width="60px"></el-table-column>
<el-table-column prop="userName" label="姓名"></el-table-column>
<el-table-column prop="loginName" label="工号"></el-table-column>
<!-- <el-table-column prop="sex" label="性别"></el-table-column>-->
<!-- <el-table-column prop="unitName" label="单位"></el-table-column>-->
<!-- <el-table-column prop="mobile" label="手机号"></el-table-column>-->
<el-table-column label="操作" width="100px"
v-if="inApplyTime">
<template slot-scope="scope">
<el-button type="danger" size="mini" @click="removeTeamUser(scope.$index)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="form-create-h5" v-if="isCustomForm">
<div class="notice-title left-tag-title">填写报名信息</div>
<form-create :value.sync="dynamicFormData" v-model="fapi" :rule="formCreateRule"
:option="formCreateOption"></form-create>
</div>
</div>
<div class="footer">
<div class="bottom-button" style="background: var(--color-primary)" v-if="!isSignUp && inApplyTime"
@click="onConfirm">
<span>立即报名</span>
<span style="font-size: 12px; margin-top: 5px">{{viewData.applyEndTime}}截止报名</span>
</div>
<div class="bottom-button" style="background: var(--color-primary)" v-if="isSignUp && inApplyTime"
@click="onConfirmAgain">
<span>重新提交</span>
<span style="font-size: 12px; margin-top: 5px">{{viewData.applyEndTime}}截止报名</span>
</div>
<div class="bottom-button" style="background: red" v-if="isSignUp && inApplyTime" @click="onCancel">
<span>取消报名</span>
<span style="font-size: 12px; margin-top: 5px">{{viewData.applyEndTime}}截止报名</span>
</div>
<div class="bottom-button" v-if="$moment(viewData.endTime).valueOf() < $moment().valueOf()">活动已结束</div>
</div>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
store,
data() {
return {
id: GetQueryString("id"),
viewData: {},
signUpInfo: {},
dynamicFormData: {},
formCreateRule: [],
formCreateOption: {},
fapi: null,
//搜索框
searchTeammateUserId: null,
//搜索框选新娘
teammateOptions: [],
//表格用户
teamUsers: [],
//是否报名
isSignUp: false
}
},
computed: {
isCustomForm() {
return this.viewData && this.viewData.formConfig != null && this.viewData.formConfig !== ""
},
//是否报名人
isApplyUser() {
if (this.teamUsers) {
return this.teamUsers.every((v) => v.applyUserId === this.$store.state.user.id)
} else {
return true
}
},
//是否在活动报名时间内
inApplyTime() {
if (this.viewData) {
const now = new Date().getTime()
const start = this.$moment(this.viewData.applyStartTime).valueOf()
const end = this.$moment(this.viewData.applyEndTime).valueOf()
return now >= start && now <= end
}
return false
}
},
methods: {
init() {
if(!this.id) return
this.$axios.post("/platform/activity/culture/infoManage/activityInfo", {id: this.id})
.then((res) => {
if (res.code === 0) {
this.viewData = res.data
this.checkScope(this.viewData.groupId)
//总人数限制
if (this.viewData.userNumberLimit === 1) {
} else if (this.viewData.userNumberLimit === 2) {
//分工会人数限制
const union = this.viewData.unionUserNumberLimit.find(v => v.id === this.$store.state.user.union.id)
this.viewData.unionLimitNum = union.limitNum
}
if (this.viewData.signUpMethod === 3) {
this.listTeamUserUnion()
} else {
this.listTeamUser()
}
if (this.viewData.formConfig) {
this.formCreateRule = formCreate.parseJson(this.viewData.formConfig.rule)
this.formCreateOption = formCreate.parseJson(this.viewData.formConfig.options)
}
}
})
},
//查询报名人员
listTeamUser() {
this.$axios.post("/platform/activity/culture/applyUser/listTeamUser", {activityId: this.id}).then((res) => {
if (res.code === 0) {
this.isSignUp = res.data.length > 0
this.teamUsers = res.data
this.defaultAddSelf()
this.customFormInit()
}
})
},
//查询报名人员
listTeamUserUnion() {
this.$axios.post("/platform/activity/culture/applyUser/listTeamUserUnion", {activityId: this.id}).then((res) => {
if (res.code === 0) {
this.isSignUp = res.data.length > 0
this.teamUsers = res.data
this.defaultAddSelf()
this.customFormInit()
}
})
},
//表单回显
customFormInit() {
if (this.teamUsers && this.teamUsers.length > 0) {
const self = this.teamUsers.find((v) => v.userId === this.$store.state.user.id)
if (self && this.isCustomForm) {
this.dynamicFormData = self.dynamicFormData
}
}
},
//组队和个人报名默认增加自己
defaultAddSelf() {
if (this.teamUsers.length === 0 && [1, 2].includes(this.viewData.signUpMethod)) {
this.teamUsers.push({
userId: this.$store.state.user.id,
userName: this.$store.state.user.username,
loginName: this.$store.state.user.loginname,
sex: this.$store.state.user.sex,
unitName: this.$store.state.user?.unit?.name,
mobile: this.$store.state.user.mobile,
applyUserId: this.$store.state.user.id
})
}
},
//提交报名
async onConfirm() {
if (this.isCustomForm && this.fapi) {
let formValid = false
try {
await this.fapi.validate()
formValid = true
} catch (e) {
formValid = false
}
if (!formValid) {
this.$toast('请填写报名信息后再提交')
return
}
}
//组队
if (this.viewData.signUpMethod === 2) {
//组队人数判断
if (this.teamUsers.length === 0) {
this.$toast("请添加队友后再提交!")
return
}
if (this.teamUsers.length < this.viewData.teamNum) {
this.$dialog
.alert({
title: "提示",
message: "您选择的人数小于" + this.viewData.teamNum + "人,请重新选择!"
})
.then(() => {
})
return
}
if (this.teamUsers.length > this.viewData.teamNum) {
this.$dialog
.alert({
title: "提示",
message: "您选择的人数大于" + this.viewData.teamNum + "人,请重新选择!"
})
.then(() => {
})
return
}
}
//分工会
if (this.viewData.signUpMethod === 3) {
if (this.teamUsers.length === 0) {
this.$dialog
.alert({
title: "提示",
message: "请添加报名人员后再提交!"
})
.then(() => {
})
return
}
if (this.viewData.teamNum && this.teamUsers.length > this.viewData.teamNum) {
this.$dialog
.alert({
title: "提示",
message: "您选择的人数大于" + this.viewData.teamNum + "人,请重新选择!"
})
.then(() => {
})
return
}
}
let formData = {
activityId: this.id
}
if (this.isCustomForm) {
formData.ext = JSON.stringify(this.fapi.formData())
}
if (this.viewData.signUpMethod === 2 || this.viewData.signUpMethod === 3) {
formData.teamUserIds = JSON.stringify(this.teamUsers.map((v) => v.userId))
}
this.$dialog
.confirm({
title: "提示",
message: "确定提交报名信息吗?"
})
.then(() => {
this.$axios.post("/platform/activity/culture/applyUser/signUp", formData).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
if (this.viewData.signUpMethod === 3) {
this.listTeamUserUnion()
} else {
this.listTeamUser()
}
}
})
})
},
async onConfirmAgain() {
if (this.isCustomForm && this.fapi) {
let formValid = false
try {
await this.fapi.validate()
formValid = true
} catch (e) {
formValid = false
}
if (!formValid) return
}
//组队
if (this.viewData.signUpMethod === 2) {
//组队人数判断
if (this.teamUsers.length === 0) {
this.$dialog
.alert({
title: "提示",
message: "请添加队友后再提交!"
})
.then(() => {
})
return
}
if (this.teamUsers.length < this.viewData.teamNum) {
this.$dialog
.alert({
title: "提示",
message: "您选择的人数小于" + this.viewData.teamNum + "人,请重新选择!"
})
.then(() => {
})
return
}
if (this.teamUsers.length > this.viewData.teamNum) {
this.$dialog
.alert({
title: "提示",
message: "您选择的人数大于" + this.viewData.teamNum + "人,请重新选择!"
})
.then(() => {
})
return
}
}
//分工会
if (this.viewData.signUpMethod === 3) {
if (this.teamUsers.length === 0) {
this.$dialog
.alert({
title: "提示",
message: "请添加报名人员后再提交!"
})
.then(() => {
})
return
}
if (this.viewData.teamNum && this.teamUsers.length > this.viewData.teamNum) {
this.$dialog
.alert({
title: "提示",
message: "您选择的人数大于" + this.viewData.teamNum + "人,请重新选择!"
})
.then(() => {
})
return
}
}
let formData = {
activityId: this.id,
isAgain: true
}
if (this.isCustomForm) {
formData.ext = JSON.stringify(this.fapi.formData())
}
if (this.viewData.signUpMethod === 2 || this.viewData.signUpMethod === 3) {
formData.teamUserIds = JSON.stringify(this.teamUsers.map((v) => v.userId))
}
this.$dialog
.confirm({
title: "提示",
message: "确定重新提交报名信息吗?"
})
.then(() => {
this.$axios.post("/platform/activity/culture/applyUser/signUp", formData).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
if (this.viewData.signUpMethod === 3) {
this.listTeamUserUnion()
} else {
this.listTeamUser()
}
}
})
})
},
//取消报名
onCancel() {
this.$dialog
.confirm({
title: "提示",
message: "确定取消报名吗?"
})
.then(() => {
this.$axios.post("/platform/activity/culture/applyUser/cancelSignUp", {activityId: this.id}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
if (this.viewData.signUpMethod === 3) {
this.listTeamUserUnion()
} else {
this.listTeamUser()
}
this.fapi.resetFields()
}
})
})
},
//查询队友信息
queryTeammate(val) {
if (val) {
this.$axios.post("/platform/activity/culture/applyUser/queryTeammate", {
keyword: val,
tissueId: this.id,
signUpMethod: this.viewData.signUpMethod
}).then((res) => {
if (res.code === 0) {
res.data.map(v => {
v.applyUserId = this.$store.state.user.id
})
this.teammateOptions = res.data
}
})
}
},
//添加队友
addTeamUser() {
if (!this.searchTeammateUserId) {
this.$dialog
.alert({
title: "提示",
message: "请先选择后再添加!"
})
.then(() => {
})
return
}
if (this.teamUsers.some((v) => v.userId === this.searchTeammateUserId)) {
this.$dialog
.alert({
title: "提示",
message: "请勿重复添加!"
})
.then(() => {
})
return
}
if (this.viewData.teamNum && this.teamUsers.length >= this.viewData.teamNum) {
this.$dialog
.alert({
title: "提示",
message: "已满员!"
})
.then(() => {
})
return
}
this.teamUsers.push(this.teammateOptions.find((v) => v.userId === this.searchTeammateUserId))
this.searchTeammateUserId = null
},
//移除队友
removeTeamUser(index) {
this.teamUsers.splice(index, 1)
},
checkScope(groupId) {
this.$axios.post('/platform/activity/basic/scope/getScopeUser', {
activityGroupId: Number(groupId)
}).then(res => {
if (res.data === 0) {
this.$dialog.alert({
title: '标题',
message: '您没有权限参加此活动',
confirmButtonText: "返回首页"
}).then(() => {
this.$pjaxReplace("/platform/home")
});
}
})
},
},
created() {
this.init()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,182 @@
<!--#
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;
}
.item-header .van-tag {
font-size: 12px;
padding: 3px 6px;
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">
<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"
img="cover"
@ready="onReady"
>
<template #header="{index,row}">
<div class="item-header">
<div class="item-title">{{ row.activityName }}</div>
<div>
<van-tag type="primary" v-if="$moment().isBefore($moment(row.activitySignUpStartTime))">
即将开始
</van-tag>
<van-tag type="success" v-if="$moment().isAfter($moment(row.activitySignUpStartTime)) && $moment().isBefore($moment(row.activitySignUpEndTime))">
进行中
</van-tag>
<van-tag class="grey" v-if="$moment().isAfter($moment(row.activitySignUpEndTime))">
已结束
</van-tag>
</div>
</div>
</template>
<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/family/apply/list/h5?id=' + row.id)
},
fetchOne() {
this.$axios.post('/platform/family/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()
})
}
},
})
</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" block>提交</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*/ `
/deep/ .companionList_empty_text {
text-align: center;
padding: 10px 0;
font-size: 14px;
color: grey;
}
/deep/ .button {
position: fixed;
bottom: 0;
width: 100%;
}
`
}
@@ -0,0 +1,262 @@
<!--#
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>
<van-tabs v-if="assortList.length > 0" type="card" color="#1867B0"
style="margin-top: 10px" @click="tabClick">
<van-tab v-for="item,index in assortList" :name="item" :title="item" :key="index">
</van-tab>
</van-tabs>
<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 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/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() {
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/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
},
queryCourseAssort() {
this.$axios.post("/platform/family/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,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 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: {},
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>
<!--#
}
#-->
@@ -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>
<!--#
}
#-->
@@ -0,0 +1,131 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar title="列表" fixed placeholder left-text="返回" left-arrow @click-left="historyBack"></van-nav-bar>
<van-sticky offset-top="46px">
<van-tabs v-model="pageForm.category" @change="onRefresh">
<van-tab v-for="item in dict.type.ACTIVITY_QSV_CATEGORY" :name="item.code" :title="item.label" :key="item.code"></van-tab>
</van-tabs>
</van-sticky>
<van-pull-refresh v-model="refreshing" @refresh="onRefresh" style="min-height: calc(100vh - 90px)">
<van-list v-if="list && list.length>0" v-model="loading" :finished="finished" finished-text="" @load="onLoad">
<div v-for="row in list" :key="row.id">
<div
style="display: flex; padding: 15px; margin: 20px; box-sizing: border-box; background: #ffffff; border-radius: 10px"
@click="itemClick(row)"
>
<div class="list-item-icon" style="width: 96px; height: 80px; flex-shrink: 0">
<img src="/assets/mobile/svg/qsv/icon.svg" alt="" style="width: 100%; height: 100%" />
</div>
<div style="flex-grow: 1; display: flex; flex-direction: column; justify-content: space-around">
<div
style="
font-weight: bolder;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
text-overflow: ellipsis;
"
>
{{row.title}}
</div>
<div style="font-size: 13px; color: #606266">
开始时间:{{row.startTime}}
<br />
结束时间:{{row.endTime}}
</div>
</div>
</div>
</div>
</van-list>
<van-empty v-if="list.length===0" description="没有更多了"></van-empty>
</van-pull-refresh>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
dicts: ["ACTIVITY_QSV_CATEGORY"],
data() {
return {
loading: false,
finished: false,
refreshing: false,
list: [],
pageForm: {
pageNumber: 1,
pageSize: 10,
category: "QUIZ"
},
categoryPaths: {
QUIZ: "/platform/h5/qsv/quiz",
SURVEY: "/platform/h5/qsv/survey",
VOTE: "/platform/h5/qsv/vote"
}
}
},
methods: {
onLoad() {
this.loading = true
const loading = createListLoading()
this.$axios
.post("/platform/h5/qsv/pageData", this.pageForm)
.then((res) => {
if (res.code === 0) {
this.list = this.list.concat(res.data.list)
this.pageForm.totalCount = res.data.totalCount
if (this.list.length >= this.pageForm.totalCount) {
this.finished = true
}
this.pageForm.pageNumber++
}
})
.finally(() => {
loading.close()
this.loading = false
this.refreshing = false
})
},
onRefresh() {
this.pageForm.pageNumber = 1
this.list = []
this.finished = false
this.onLoad()
},
async itemClick(item) {
if (item.groupId) {
const { code, data } = await this.$axios.post("/open/common/checkGroupPermission", { groupId: item.groupId })
if (code === 0) {
if (!data) {
this.$toast.fail("您没有权限参与")
return
}
}
}
const { startTime, endTime } = item
if (this.$moment(startTime).unix() > this.$moment().unix()) {
this.$toast("未开始")
return
}
const path = this.categoryPaths[item.category]
if (path) {
this.$pjaxReplace(path + "?id=" + item.id)
}
}
},
created() {
this.onLoad()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,370 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.container {
padding: 0;
}
.container .title {
text-align: center;
padding: 20px;
background: #ffffff;
/*margin: 10px 0;*/
margin-bottom: 10px;
color: var(--color-primary);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.container .card {
padding: 10px;
background: #ffffff;
}
.subject {
background: #fff;
padding: 15px;
margin-bottom: 15px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
position: relative;
}
.subject p {
font-size: 16px;
margin: 20px 0 10px 0;
font-weight: bold;
}
.subject .tag {
position: absolute;
top: 0;
}
.timer {
text-align: center;
font-size: 18px;
background: #fff;
padding: 10px 0;
}
.submit-button {
width: 100%;
margin-top: 20px;
}
.result {
text-align: center;
font-size: 20px;
margin-top: 20px;
}
.button-control {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20px;
display: flex;
column-gap: 20px;
background: #fff;
}
</style>
<div id="app" v-cloak>
<van-nav-bar title="问卷调查" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
<div class="container" :style="{'padding-bottom': answerRecord.isFinish ? 0 : '84px'}">
<van-sticky offset-top="46px">
<!--开启计时 未完成 活动未结束-->
<div class="timer" v-if="activity.timeLimit > 0 && !answerRecord.isFinish && !isEnd">⏰{{ remainingTime }}s</div>
<h2 class="title">{{ activity.title }}</h2>
</van-sticky>
<div v-if="!answerRecord.isFinish">
<div v-for="(subject, index) in subjects" :key="index" class="subject">
<p>{{index+1}}、{{ subject.title }}</p>
<div class="tag">
<van-tag v-if="subject.type === 'checkbox'" type="primary" size="large">多选</van-tag>
<van-tag v-if="subject.type === 'radio'" type="primary" size="large">单选</van-tag>
<van-tag v-if="subject.score" type="primary" size="large">{{subject.score}}分</van-tag>
</div>
<van-checkbox-group v-model="subject.userSelectOptionIds" :ref="'subject'+subject.id">
<van-cell-group>
<van-cell
v-for="(option,index) in subject.options"
clickable
:key="option.id"
:title="option.text"
@click="cellToggle(subject,option.id)"
>
<template #icon>
<van-checkbox
:name="option.id"
:ref="'option'+option.id"
:disabled="answerRecord.isFinish"
:shape="subject.type==='checkbox' ? 'square' : 'round'"
style="margin-right: 10px"
></van-checkbox>
</template>
</van-cell>
</van-cell-group>
</van-checkbox-group>
</div>
<div class="button-control" v-if="!answerRecord.isFinish">
<van-button type="primary" @click="onSubmit" block :disabled="isEnd">{{isEnd ? '已结束' : '提交'}}</van-button>
</div>
</div>
</div>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
data() {
return {
list: [],
id: GetQueryString("id"),
subjects: [],
activity: {},
// remainingTime: 0,
isFinished: false,
answerRecord: {},
answerRecordId: null,
//历史记录
historyScores: [],
//答题用时
answerTime: 0
}
},
computed: {
isEnd() {
if (this.activity) {
return this.$moment().unix() > this.$moment(this.activity.endTime).unix()
}
return true
},
remainingTime() {
if (this.activity && this.activity.timeLimit > 0) {
return this.activity.timeLimit * 60 - this.answerTime
}
return 0
}
},
methods: {
//获取活动、题目
listSubjects() {
this.$axios.post("/platform/h5/qsv/quiz/subjects", { activityId: this.id }).then((res) => {
if (res.code === 0) {
this.activity = res.data.activity
this.subjects = res.data.subjects
this.answerRecordId = res.data.answerRecordId
this.checkGroupPermission()
this.getAnswerRecord()
}
})
},
//获取回答记录
getAnswerRecord() {
this.$axios.post("/platform/h5/qsv/quiz/answerRecord", { answerRecordId: this.answerRecordId }).then((res) => {
if (res.code === 0) {
this.answerRecord = res.data
if (this.answerRecord.isFinish || this.$moment().unix() > this.$moment(this.activity.endTime)) {
this.$pjaxReplace("/platform/h5/qsv/quiz/result?answerRecordId=" + this.answerRecordId)
}
this.initAnswer()
this.checkTimer()
}
})
},
//答案回显
initAnswer() {
this.subjects.forEach((subject, subjectIndex) => {
if (subject.type === "radio") {
this.$refs["subject" + subject.id][0].toggleAll(false)
}
if (this.answerRecord.optionIds) {
this.answerRecord.optionIds[subjectIndex].forEach((optionId) => {
this.$refs["option" + optionId][0].toggle()
})
}
})
},
//答题计时器
checkTimer() {
if (this.timerInterval) {
clearInterval(this.timerInterval)
}
//开启计时
const startInterval = () => {
this.timerInterval = setInterval(() => {
this.answerTime++
if (this.activity.timeLimit > 0 && this.answerTime >= this.activity.timeLimit * 60) {
clearInterval(this.timerInterval)
const loading = this.$toast.loading({
message: "答题时间到,自动提交中",
forbidClick: true
})
setTimeout(() => {
this.autoSubmit(loading)
}, 1500)
}
}, 1000)
}
if (!this.isEnd && !this.answerRecord.isFinish) {
if (this.activity.timeLimit > 0) {
this.$dialog
.alert({
title: "提示",
message: "本次答题时间" + this.activity.timeLimit + "分钟,点击确认开始答题"
})
.then(() => {
startInterval()
})
} else {
startInterval()
}
}
// if (this.activity.timeLimit > 0 && !this.isEnd) {
// if (!this.answerRecord.isFinish) {
// this.$dialog
// .alert({
// title: "提示",
// message: "本次答题时间" + this.activity.timeLimit + "分钟,点击确认开始答题"
// })
// .then(() => {
// this.remainingTime = this.activity.timeLimit * 60
// this.timerInterval = setInterval(() => {
// if (this.remainingTime > 0) {
// this.remainingTime--
// } else {
// clearInterval(this.timerInterval)
// const loading = this.$toast.loading({
// message: "答题时间到,自动提交中",
// forbidClick: true
// })
// this.autoSubmit(loading)
// }
// }, 1000)
// })
// }
// }
},
historyScore() {
this.$axios.post("/platform/h5/qsv/quiz/historyScore", { activityId: this.activityId }).then((res) => {
if (res.code === 0) {
this.historyScores = res.data
}
})
},
//选项点击
cellToggle(subject, optionId) {
if (this.answerRecord.isFinish) {
return
}
if (subject.type === "radio") {
this.$refs["subject" + subject.id][0].toggleAll(false)
}
this.$refs["option" + optionId][0].toggle()
},
//手动提交
onSubmit() {
if (this.isEnd) {
this.$toast("调查已结束")
return
}
//提示那些题没有作答
for (let i = 0; i < this.subjects.length; i++) {
let subject = this.subjects[i]
//["radio", "checkbox"].includes(subject.type) &&
if (!subject.userSelectOptionIds || subject.userSelectOptionIds.length === 0) {
this.$toast.fail("第" + (i + 1) + "题未做答")
return
}
}
if (this.timerInterval) {
clearInterval(this.timerInterval)
}
this.autoSubmit()
},
//自动提交
autoSubmit(loading = null) {
this.$axios
.post("/platform/h5/qsv/quiz/submitAnswer", {
answer: JSON.stringify({
activityId: this.id,
answerRecordId: this.answerRecordId,
subjects: this.subjects.map((subject) => {
return {
id: subject.id,
userSelectOptionIds: ["checkbox", "radio"].includes(subject.type) ? subject.userSelectOptionIds : []
}
}),
answerTime: this.answerTime
})
})
.then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.$pjaxReplace("/platform/h5/qsv/quiz/result?answerRecordId=" + this.answerRecordId)
// this.getAnswerRecord()
}
})
.finally(() => {
if (loading) {
loading.clear()
}
})
},
async checkGroupPermission() {
const groupId = this.activity.groupId
if (groupId) {
const { code, data } = await this.$axios.post("/open/common/checkGroupPermission", { groupId })
if (code === 0) {
if (!data) {
this.$dialog
.alert({
title: "提示",
message: "您没有权限参与"
})
.then(() => {
location.back()
})
}
}
}
}
},
created() {
if (this.timerInterval) {
clearInterval(this.timerInterval)
}
if (this.id) {
this.listSubjects()
}
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,330 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.container {
padding: 0;
}
.container .title {
text-align: center;
padding: 20px;
background: #ffffff;
color: var(--color-primary);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.container .score {
}
.container .card {
padding: 10px;
background: #ffffff;
}
.subject {
background: #fff;
padding: 15px;
margin-bottom: 15px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
position: relative;
}
.subject p {
font-size: 16px;
margin: 20px 0 10px 0;
font-weight: bold;
}
.subject .tag {
position: absolute;
top: 0;
}
.score-form {
background: #ffffff;
display: flex;
margin-bottom: 10px;
border-top: 1px solid #f1f1f1;
align-items: center;
}
.score-form-total {
flex: 1;
background: #fff;
display: flex;
padding: 10px 20px 10px 0;
flex-direction: column;
align-items: flex-end;
}
.score-text-news {
flex: 1;
background: #fff;
}
.score-font-style {
font-size: 32px;
color: #ff6a00;
word-break: keep-all;
line-height: 38px;
min-width: 47px;
text-align: center;
}
.score-underline {
background: url(//image.wjx.cn/images/newimg/score-form/score-underline@2x.png) no-repeat center;
background-size: 47px 16px;
display: inline-block;
height: 16px;
width: 47px;
margin-top: 7px;
}
.van-checkbox__icon--checked .van-icon {
color: #fff !important;
background-color: var(--color-primary) !important;
border-color: var(--color-primary) !important;
}
.van-checkbox__icon--disabled .van-icon {
background-color: #fff;
}
.answer-container {
padding: 16px;
}
.correct-answer {
color: green;
}
.incorrect-answer {
color: red;
}
.button-control {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20px;
display: flex;
column-gap: 20px;
background: #fff;
}
.history-list {
background: #f1f1f1;
padding: 10px;
}
.history-item {
background: #ffffff;
border-radius: 12px;
padding: 16px;
margin: 20px 10px;
box-shadow:
8px 8px 16px #d9d9d9,
-8px -8px 16px #ffffff;
transition: transform 0.2s ease-in-out;
}
.history-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.history-header span {
font-size: 14px;
font-weight: 600;
color: #333;
}
.history-header .tag {
margin-left: 8px;
color: #fff;
padding: 2px 5px;
}
.history-info {
font-size: 14px;
color: #555;
margin-bottom: 4px;
}
</style>
<div id="app" v-cloak>
<van-nav-bar title="问卷调查" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
<div class="container" :style="{'padding-bottom': answerRecord.isFinish ? 0 : '84px'}">
<van-sticky offset-top="46px">
<h2 class="title">{{ activity.title }}</h2>
<div class="score-form">
<div class="score-form-total">
<div class="score-font-style">{{totalScore}}</div>
<i class="score-underline"></i>
</div>
</div>
</van-sticky>
<div>
<div v-for="(subject, index) in subjects" :key="index" class="subject">
<p>{{index+1}}、{{ subject.title }}</p>
<div class="tag">
<van-tag v-if="subject.type === 'checkbox'" type="primary" size="large">多选</van-tag>
<van-tag v-if="subject.type === 'radio'" type="primary" size="large">单选</van-tag>
<van-tag v-if="subject.score" type="primary" size="large">{{subject.score}}分</van-tag>
</div>
<van-checkbox-group v-model="subject.userSelectOptionIds" :ref="'subject'+subject.id">
<van-cell-group>
<van-cell v-for="(option,index) in subject.options" clickable :key="option.id" :title="option.text">
<template #title>
<span :style="{color : option.isCorrect ? 'green' : ''}">{{option.text}}</span>
</template>
<template #icon>
<van-checkbox
:name="option.id"
:ref="'option'+option.id"
:disabled="answerRecord.isFinish"
style="margin-right: 10px"
></van-checkbox>
</template>
</van-cell>
</van-cell-group>
</van-checkbox-group>
<div class="answer-container">
<div v-if="answerRecord.extJson?.[subject.id]?.isCorrect" class="correct-answer">
<van-icon name="passed"></van-icon>
回答正确
</div>
<div v-else-if="answerRecord.extJson?.[subject.id]" class="incorrect-answer">
<van-icon name="close"></van-icon>
回答错误
</div>
</div>
</div>
<div class="button-control">
<van-button type="primary" @click="openHistory" block>查看全部答题记录</van-button>
</div>
</div>
<van-action-sheet v-model="historyShow" title="历史记录">
<div class="history-list">
<div v-for="item in historyList" class="history-item">
<div class="history-header">
<span>{{ item.date }}</span>
<van-tag v-if="item.isHighestScore" type="danger" class="tag">最高分</van-tag>
<van-tag v-if="item.isLatestScore" type="primary" class="tag">最新得分</van-tag>
</div>
<div class="history-info">答题分数:{{ item.totalScore }}</div>
<div class="history-info">答题用时:{{ item.answerTime | formatSeconds }}</div>
</div>
</div>
</van-action-sheet>
</div>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
data() {
return {
answerRecordId: GetQueryString("answerRecordId"),
answerRecord: {},
subjects: [],
activity: {},
list: [],
historyShow: false,
historyList: []
}
},
computed: {
totalScore() {
if (!this.answerRecord || !this.answerRecord.extJson) {
return 0
}
let totalScore = 0
for (const key in this.answerRecord.extJson) {
if (this.answerRecord.extJson.hasOwnProperty(key)) {
totalScore += this.answerRecord.extJson[key].score || 0
}
}
return totalScore
}
},
filters: {
formatSeconds(seconds) {
if (seconds) {
const minutes = Math.floor(seconds / 60) // 获取总分钟数
const remainingSeconds = seconds % 60 // 获取剩余秒数
// 格式化输出,确保秒数始终为两位数
return minutes + "分钟" + String(remainingSeconds).padStart(2, "0") + "秒"
}
return null
}
},
methods: {
getAnswerResult() {
this.$axios.post("/platform/h5/qsv/quiz/answerResult", { answerRecordId: this.answerRecordId }).then((res) => {
if (res.code === 0) {
this.subjects = res.data.subjects
this.activity = res.data.activity
this.getAnswerRecord()
}
})
},
//获取回答记录
getAnswerRecord() {
this.$axios.post("/platform/h5/qsv/quiz/answerRecord", { answerRecordId: this.answerRecordId }).then((res) => {
if (res.code === 0) {
this.answerRecord = res.data
this.initAnswer()
}
})
},
//答案回显
initAnswer() {
this.subjects.forEach((subject, subjectIndex) => {
const answer = this.answerRecord.extJson[subject.id]
if (["radio", "checkbox"].includes(subject.type)) {
this.$nextTick(() => {
this.$refs["subject" + subject.id][0].toggleAll(false)
})
answer?.optionIds.forEach((optionId) => {
this.$nextTick(() => {
this.$refs["option" + optionId][0].toggle()
})
})
} else if (subject.type === "text") {
subject.userFillContent = answer?.text
}
})
},
historyBack() {
this.$pjaxReplace("/platform/h5/qsv")
},
openHistory() {
this.historyShow = true
this.$axios.post("/platform/h5/qsv/quiz/historyScore", { activityId: this.activity.id }).then((res) => {
if (res.code === 0) {
this.historyList = res.data
}
})
}
},
created() {
this.getAnswerResult()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,292 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.container {
padding: 0;
}
.container .title {
text-align: center;
padding: 20px;
background: #ffffff;
margin: 0 0 10px 0;
}
.container .card {
padding: 10px;
background: #ffffff;
}
.subject {
background: #fff;
padding: 15px;
margin-bottom: 15px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
position: relative;
}
.subject p {
font-size: 16px;
margin: 20px 0 10px 0;
font-weight: bold;
}
.subject .tag {
position: absolute;
top: 0;
}
.button-control {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20px;
display: flex;
column-gap: 20px;
background: #fff;
}
.van-checkbox__icon--checked .van-icon {
color: #fff !important;
background-color: var(--color-primary) !important;
border-color: var(--color-primary) !important;
}
.van-checkbox__icon--disabled .van-icon {
background-color: #fff;
}
.ui-input-box {
border: 1px solid #e3e3e3;
margin: 5px 0;
background-color: #fff;
padding: 0;
width: 100%;
display: flex;
}
.ui-input-box input {
background-color: #fff;
border: none !important;
padding: 10px;
font-size: 14px;
line-height: 18px;
display: inline-block;
margin: 0;
-webkit-appearance: none;
resize: none;
width: 100%;
}
</style>
<div id="app" v-cloak>
<van-nav-bar title="问卷调查" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
<div class="container" :style="{'padding-bottom': answerRecord.isFinish ? 0 : '84px'}">
<h2 class="title">{{ activity.title }}</h2>
<div v-if="!isFinished">
<div v-for="(subject, index) in subjects" :key="index" class="subject">
<p>{{index+1}}、{{ subject.title }}</p>
<div class="tag">
<van-tag v-if="subject.type === 'checkbox'" type="primary" size="large">多选</van-tag>
<van-tag v-if="subject.type === 'radio'" type="primary" size="large">单选</van-tag>
<van-tag v-if="subject.score" type="primary" size="large">{{subject.score}}分</van-tag>
</div>
<!--单选、多选-->
<van-checkbox-group
v-model="subject.userSelectOptionIds"
:ref="'subject'+subject.id"
v-if="['radio','checkbox'].includes(subject.type)"
>
<van-cell-group>
<van-cell
v-for="(option,index) in subject.options"
clickable
:key="option.id"
:title="option.text"
@click="cellToggle(subject,option.id)"
>
<template #icon>
<van-checkbox :name="option.id" :ref="'option'+option.id" style="margin-right: 10px"></van-checkbox>
</template>
<img
slot="right-icon"
v-if="option.imgUrl"
:src="option.imgUrl"
alt=""
style="width: 40px; height: 40px"
@click.stop="previewOptionImg(option.imgUrl)"
/>
</van-cell>
</van-cell-group>
</van-checkbox-group>
<!--填空题-->
<div class="ui-input-box" v-if="subject.type==='text'">
<input type="text" v-model="subject.userFillContent" :readonly="answerRecord.isFinish" />
</div>
</div>
<div class="button-control" v-if="!answerRecord.isFinish">
<van-button type="primary" @click="onSubmit" block :disabled="isEnd">{{isEnd ? '已结束' : '提交'}}</van-button>
</div>
</div>
</div>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
data() {
return {
list: [],
id: null,
subjects: [],
activity: {},
remainingTime: 0,
isFinished: false,
answerRecord: {},
answerRecordId: null
}
},
computed: {
isEnd() {
if (this.activity) {
return this.$moment().unix() > this.$moment(this.activity.endTime).unix()
}
return true
}
},
methods: {
//获取活动、题目
listSubjects() {
this.$axios.post("/platform/h5/qsv/survey/subjects", { activityId: this.id }).then((res) => {
if (res.code === 0) {
this.activity = res.data.activity
this.subjects = res.data.subjects
this.answerRecordId = res.data.answerRecordId
this.getAnswerRecord()
}
})
},
//获取回答记录
getAnswerRecord() {
this.$axios.post("/platform/h5/qsv/survey/answerRecord", { answerRecordId: this.answerRecordId }).then((res) => {
if (res.code === 0) {
this.answerRecord = res.data
if (this.answerRecord.isFinish) {
this.$toast.success("您已完成该调查")
}
this.initAnswer()
}
})
},
//答案回显
initAnswer() {
this.subjects.forEach((subject, subjectIndex) => {
const answer = this.answerRecord.extJson[subject.id]
if (["radio", "checkbox"].includes(subject.type)) {
this.$refs["subject" + subject.id][0].toggleAll(false)
answer?.optionIds.forEach((optionId) => {
this.$nextTick(() => {
this.$refs["option" + optionId][0].toggle()
})
})
} else if (subject.type === "text") {
subject.userFillContent = answer?.text
}
})
},
//选项点击
cellToggle(subject, optionId) {
if (this.answerRecord.isFinish) {
return
}
if (subject.type === "radio") {
this.$refs["subject" + subject.id][0].toggleAll(false)
}
this.$refs["option" + optionId][0].toggle()
},
//预览图片
previewOptionImg(img) {
vant.ImagePreview([img])
},
//手动提交
onSubmit() {
const endTime = this.activity.endTime
if (this.isEnd) {
this.$toast("调查已结束")
return
}
//提示那些题没有作答
for (let i = 0; i < this.subjects.length; i++) {
const subject = this.subjects[i]
if (["radio", "checkbox"].includes(subject.type)) {
if (!subject.userSelectOptionIds || subject.userSelectOptionIds.length === 0) {
this.$toast.fail("第" + (i + 1) + "题未做答")
return
}
} else if ("text" === subject.type) {
if (!subject.userFillContent) {
this.$toast.fail("第" + (i + 1) + "题未作答")
return
}
}
}
this.autoSubmit()
},
//自动提交
autoSubmit(loading = null) {
this.$axios
.post("/platform/h5/qsv/survey/submitAnswer", {
answer: JSON.stringify({
activityId: this.id,
answerRecordId: this.answerRecordId,
subjects: this.subjects.map((subject) => {
return {
id: subject.id,
userSelectOptionIds: ["checkbox", "radio"].includes(subject.type) ? subject.userSelectOptionIds : [],
userFillContent: subject.type === "text" ? subject.userFillContent : null
}
})
})
})
.then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.getAnswerRecord()
}
})
.finally(() => {
if (loading) {
loading.clear()
}
})
}
},
created() {
const id = GetQueryString("id")
if (id) {
this.id = id
this.listSubjects()
}
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,112 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.van-tag--default {
background-color: #f1f1f1 !important;
}
</style>
<div id="app" v-cloak>
<van-nav-bar title="活动列表" @click-left="()=>this.$pjaxReplace('/platform/home')" left-arrow left-text="返回" placeholder fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-dropdown-menu>
<year-van-dropdown-item :num="5" @change="doSearch" v-model="pageForm.year"></year-van-dropdown-item>
<van-dropdown-item :options="stateList" @change="doSearch"
v-model="pageForm.isActivity"></van-dropdown-item>
<van-dropdown-item :options="applyStatusOptions" @change="doSearch"
v-model="pageForm.applyStatus"></van-dropdown-item>
</van-dropdown-menu>
</van-sticky>
<table-list api="/platform/activity/apply/h5/activityData"
:page_form.sync="pageForm"
ref="tableListRef"
title="NAME"
img="image"
@ready="onReady"
>
<template v-slot="{index,row}">
<table-column label="报名时间">
{{$moment(row.applyStartTime).format('MM/DD HH:mm') + '~' + $moment(row.applyEndTime).format('MM/DD HH:mm')}}
</table-column>
<table-column label="活动时间">
{{$moment(row.startTime).format('MM/DD HH:mm') + '~' + $moment(row.endTime).format('MM/DD HH:mm')}}
</table-column>
</template>
<template #actions="{index,row}">
<template v-if="$moment().isBefore($moment(row.applyEndTime))">
<div class="action-btn" @click="openView(row)">
<i class="fa fa-edit"></i>
<span>去报名</span>
</div>
</template>
</template>
</table-list>
<activity_event_notification
:event_notification="viewData.eventNotification"
:id="viewData.id"
ref="eventNotification"
></activity_event_notification>
</div>
<script nonce="${cspNonce!}">
<!--#include("eventNotification.js"){}#-->
new Vue({
el: "#app",
data() {
return {
tableData: [],
finished: false,
loading: false,
pageForm: {
isActivity: 2,
applyStatus: 1,
year: new Date().getFullYear(),
pageNumber: 1,
pageSize: 5,
totalCount: 0
},
yearList: [],
applyStatusOptions: [
{value: 1, text: "未报名"},
{value: 2, text: "已报名"}
],
stateList: [
{value: 1, text: "全部"},
{value: 2, text: "报名中"},
{value: 3, text: "报名已结束"}
],
subLoading: false,
viewShow: false,
viewData: {}
}
},
components: {
activity_event_notification: ACTIVITY_EVENT_NOTIFICATION
},
methods: {
openView(row) {
this.viewData = row
this.$refs.eventNotification.viewShow = true
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
onReady() {
this.doSearch()
},
},
created() {
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,238 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-sticky>
<van-nav-bar
@click-left="historyBack"
left-arrow
left-text="返回"
placeholder
title="项目列表"
></van-nav-bar>
</van-sticky>
<div>
<van-list :finished="finished" @load="pageData" finished-text="没有更多了" v-if="tableData.length>0"
v-model="loading">
<div class="table-list">
<div :key="row.id" class="table-card" v-for="row in tableData">
<van-image :src="row.image" fit="cover" height="200" v-if="row.image" width="100%"></van-image>
<van-cell>
<template slot="title">
<div class="flex-align">
<span class="font-size3 bold">{{row.allName}}</span>
</div>
</template>
<template #right-icon>
<div style="display: flex; justify-content: flex-end"
v-if="row.status&&row.applyWay.length===1&&row.applyWay.includes(1)">
<van-tag type="primary" v-if="row.status===1">待审核</van-tag>
<van-tag type="success" v-if="row.status===2">已成功报名</van-tag>
<van-tag type="danger" v-if="row.status===3">审核不通过</van-tag>
</div>
<div style="display: flex; justify-content: flex-end" v-else>
<van-tag type="primary" v-if="row.status2===0">待审核</van-tag>
<van-tag type="success" v-if="row.status2===2">已成功报名</van-tag>
<van-tag type="danger" v-if="row.status2===3">审核不通过</van-tag>
</div>
</template>
</van-cell>
<van-cell title="可报队数" v-if="row.eveProjectType==='2'">
<template #right-icon>{{ row.restrictTotalTeam }}队</template>
</van-cell>
<van-cell title="每队可报人数" v-if="row.athletesMaxNum<=99">
<template #right-icon>
<span v-if="row.athletesMaxNum">{{ row.athletesMaxNum }}人</span>
<span v-else-if="row.applyType===1">{{ row.athletesMaxNum * row.restrictTotalTeam}}人</span>
<span v-else-if="row.applyType===2&&row.eveProjectType==='1'">{{row.athletesMaxNum}}人</span>
<span v-else-if="row.applyType===2&&row.eveProjectType==='2'">
{{(row.restrictGirlNum ? row.restrictGirlNum : 0) + (row.restrictBoyNum ? row.restrictBoyNum : 0)}}人
</span>
<span v-else>暂无</span>
</template>
</van-cell>
<!-- <van-cell title="已报名总人数">-->
<!-- <template #right-icon>-->
<!-- <span v-if="row.successUserApply>0&&row.applyType!==3">{{ row.successUserApply }}人</span>-->
<!-- <span v-else-if="JSON.parse(row.applyWay).length===2&&row.applyWay.includes(1)">{{row.totalApplyNum}}人</span>-->
<!-- <span v-else-if="row.totalApplyNum>0&&row.applyType===3">{{ row.totalApplyNum }}人</span>-->
<!-- <span v-else>0人</span>-->
<!-- </template>-->
<!-- </van-cell>-->
<van-cell title="暂保存人数">
<template #right-icon>
<span v-if="row.apply_num_bc>0">已保存({{row.apply_num_bc}})人</span>
<span v-else>暂无已保存人数</span>
</template>
</van-cell>
<van-cell title="已报名人员" v-if="JSON.parse(row.applyWay).length===1">
<template #right-icon>
<span @click="openApplyUser(row)" v-if="row.userApplyNames">{{ row.userApplyNames}}</span>
<span v-else>暂无</span>
</template>
</van-cell>
<van-cell class="table-card-footer">
<div v-if="row.applyWay.length===1&&row.applyWay.includes(1)">
<van-button :loading="subLoading" @click="signUpUser(row)" round
size="small"
type="primary" v-if="activityData.applyWay.includes(1)&&row.userApply===0">
报 名
</van-button>
<van-button :loading="subLoading" @click="cancelApply(row)" round
size="small"
color="#dd6363"
type="primary" v-if="activityData.applyWay.includes(1)&&row.userApply>0">
取消报名
</van-button>
</div>
<div v-else>
<van-button :loading="subLoading" @click="signUpUser(row)" round
size="small"
type="primary" v-if="activityData.applyWay.includes(1)&&row.userApply2===0">
报 名
</van-button>
<van-button :loading="subLoading" @click="cancelApply(row)" round
size="small"
color="#dd6363"
type="primary" v-if="activityData.applyWay.includes(1)&&row.userApply2>0">
取消报名
</van-button>
</div>
</van-cell>
</div>
</div>
</van-list>
<van-empty image="/assets/platform/plugins/vant-green/images/nodata/nodata.png" description="暂无数据"
v-else></van-empty>
</div>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
data() {
return {
tableData: [],
finished: false,
loading: false,
pageForm: {
activityId: GetQueryString("activityId"),
pageNumber: 1,
pageSize: 5,
totalCount: 0
},
subLoading: false,
activityData: {}
}
},
components: {},
methods: {
openApplyUser() {
},
cancelApply(row) {
this.$dialog.confirm({
title: "提示",
message: "确认要取消报名吗?"
}).then(() => {
/* if (row.applyUser !== this.$store.state.user.id) {
this.$dialog.alert({
title: '温馨提示',
message: "报名人不是您,请联系报名人取消!",
}).then(() => {
})
return;
}*/
this.$axios.post("/platform/activity/apply/h5/cancelApply", {
activityId: row.activityId,
eventId: row.eventId,
schoolEventId: row.id
}).then(resp => {
if (resp.code === 0) {
this.doSearch()
this.$dialog.alert({
title: '温馨提示',
message: resp.msg,
}).then(() => {
})
}
})
})
},
signUpUser(row) {
this.$dialog.confirm({
title: "提示",
message: "确认要报名吗?"
}).then(async () => {
const teamList = await this.listTeamList(row)
if (teamList.length > 0) {
row.teamId = teamList[0].id
}
this.$axios.post("/platform/activity/apply/h5/signUpUser", {
activityId: row.activityId,
teamId: row.teamId,
eventId: row.eventId,
schoolEventId: row.id
}).then(resp => {
if (resp.code === 0) {
this.doSearch()
this.$dialog.alert({
title: '温馨提示',
message: resp.msg,
}).then(() => {
// on close
});
}
})
})
},
async listTeamList(row) {
const resp = await this.$axios.post("/platform/activity/apply/h5/listTeamList", {
activityId: row.activityId,
eventId: row.eventId,
})
if (resp.code === 0) {
return resp.data
}
},
doSearch() {
this.tableKey = new Date().getTime()
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.tableData = []
this.pageData()
},
pageData() {
this.loading = true
this.$axios.post("/platform/activity/apply/h5/pageData", {data: JSON.stringify(this.pageForm)}).then((res) => {
this.tableData = this.tableData.concat(res.data.list)
if (this.tableData.length === res.data.totalCount) {
this.finished = true
} else {
this.pageForm.pageNumber++
}
this.pageForm.totalCount = res.data.totalCount
this.loading = false
})
},
findOneActivity() {
this.$axios.post("/platform/activity/apply/h5/findOneActivity", {activityId: this.pageForm.activityId}).then((res) => {
if (res.code === 0) {
this.activityData = res.data
}
})
}
},
created() {
this.findOneActivity()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,36 @@
let ACTIVITY_EVENT_NOTIFICATION = {
template: `
<div>
<van-popup :style="{ height: '100%',width: '100%'}" position="right" safe-area-inset-bottom v-model="viewShow">
<van-sticky>
<van-nav-bar @click-left="viewShow=false" left-arrow left-text="返回" title="活动通知"></van-nav-bar>
</van-sticky>
<div style="height: calc(100vh - 44px); overflow-y: auto">
<div v-html="event_notification"class="paddingX10" style="padding-bottom: 44px;white-space: pre-wrap;overflow-x: hidden" v-if="event_notification"></div>
<div v-else>暂无</div>
<van-button @click="openReg" block style="position: fixed; bottom: 0;"
type="primary">进入报名
</van-button>
</div>
</van-popup>
</div>
`,
props: {
event_notification: {
value: { type: String, default: "暂无" }
},
id: {
value: { type: String, default: "暂无" }
}
},
data() {
return {
viewShow: false
}
},
methods: {
openReg() {
this.$pjaxReplace("/platform/activity/apply/h5/eventList?activityId=" + this.id)
}
}
}
@@ -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/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}">
<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/trainSignUp/apply/list/h5?id=' + row.id)
},
fetchOne() {
this.$axios.post('/platform/trainSignUp/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,220 @@
const times = {
template:
/*language=HTML*/
`
<div>
<van-action-sheet v-model="visible" title="时间段" cancel-text="取消">
<div id="mapContainer" v-if="row?.isMobileSign === true && row?.signType === 3" style="width: 100%; height: 250px"></div>
<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,
markerLayer: null,
map: null,
circle: null,
}
},
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
this.$nextTick(() => {
if(this.row.signType === 3) {
if(this.map) this.map.destroy()
this.initMap()
this.getLocation((coords) => {
if (coords) {
const center = new TMap.LatLng(coords.lat, coords.lng)
this.markerLayer.remove(["current"])
this.createMarker(center, 'current', 'current')
}
})
}
})
},
async 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.getLocation((coords) => {
if (coords) {
this.$axios.post('/platform/trainSignUp/mine/positionSign', {
timeId: courseTime.id,
courseId: this.row.id,
lat: coords.lat,
lng: coords.lng
}).then(res => {
if (res.code === 0) {
this.$toast('签到成功')
this.visible = false
} else {
this.$toast(res.msg)
this.markerLayer.remove(["current"])
this.getLocation((coords) => {
if (coords) {
const center = new TMap.LatLng(coords.lat, coords.lng)
this.createMarker(center, 'current', 'current')
}
})
}
})
}
})
}
},
getLocation(callback) {
if (typeof callback !== 'function') {
callback = () => {};
}
if (!navigator.geolocation) {
this.$toast('当前浏览器不支持定位功能');
callback(null);
return;
}
const loading = vant.Toast.loading({
message: "获取定位中...",
forbidClick: false,
loadingType: "spinner",
duration: 0,
})
navigator.geolocation.getCurrentPosition(
(position) => {
callback({
lat: position.coords.latitude,
lng: position.coords.longitude
});
loading.close()
},
(error) => {
let msg = '定位失败,请稍后重试';
switch (error.code) {
case error.PERMISSION_DENIED:
msg = '请允许浏览器获取位置信息';
break;
case error.POSITION_UNAVAILABLE:
msg = '无法获取当前位置';
break;
case error.TIMEOUT:
msg = '定位超时,请重试';
break;
}
this.$toast(msg);
callback(null);
loading.close()
},
{
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 60000
}
);
},
initMap() {
if(!this.row.courseLocationCoordinates) {
this.$toast('未设置签到点')
return
}
const posi = JSON.parse(this.row.courseLocationCoordinates)
const center = new TMap.LatLng(posi[0], posi[1])
this.map = new TMap.Map('mapContainer', {
resizeEnable: true,
zoom: 16,
center: center
})
this.markerLayer = new TMap.MultiMarker({
map: this.map,
styles: {
"current": new TMap.MarkerStyle({
"src": "https://mapapi.qq.com/web/bundles/lbs-home/prod/assets/markerActive-NhH9NoBV.png",
"width": 40, // 点标记样式宽度(像素)
})
},
geometries: []
})
this.createMarker(center)
this.createCircle(center)
},
createMarker(position, styleId = 'marker', id = 'marker_' + Date.now()) {
this.markerLayer.add([
{
id: id,
position: position,
styleId: styleId
}
]);
},
createCircle(position) {
this.circle = new TMap.MultiCircle({
map: this.map,
geometries: [{
center: position,
radius: this.row.radius || 100,
}],
});
},
makeCode() {
const url = '/platform/trainSignUp/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,index in assortList" :name="item" :title="item" :key="index">
</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>
<!--#
}
#-->
@@ -0,0 +1,149 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
.weui-msg {
min-height: calc(100vh - 40vh - 46px);
}
</style>
<div id="app">
<van-nav-bar title="活动签到" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
<div id="mapContainer" style="width: 100%; height: 40vh"></div>
<div class="weui-msg">
<div class="weui-msg__icon-area">
<i v-if="res?.code !== 0" class="weui-icon-warn weui-icon_msg"></i>
<i v-if="res?.code === 0" class="weui-icon-success weui-icon_msg"></i>
</div>
<div class="weui-msg__text-area">
<div class="weui-msg__title">温馨提醒</div>
<div v-html="res?.msg"></div>
</div>
<div class="weui-msg__opr-area">
<p class="weui-btn-area">
<a v-if="res?.code !== 0" @click="res = {}; onSign()" class="weui-btn weui-btn_default">重新签到</a>
<a v-if="res?.code === 0" class="weui-btn weui-btn_primary">您已签到</a>
</p>
</div>
</div>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
store,
components: {
},
data() {
return {
courseId: GetQueryString('courseId'),
markerLayer: null,
map: null,
res: {},
}
},
methods: {
initMap() {
if(!this.row.courseLocationCoordinates) {
this.$toast('未设置签到点')
return
}
const posi = this.row.courseLocationCoordinates
const center = new TMap.LatLng(posi[0], posi[1])
this.map = new TMap.Map('mapContainer', {
resizeEnable: true,
zoom: 16,
center: center
})
this.markerLayer = new TMap.MultiMarker({
map: this.map,
styles: {
"current": new TMap.MarkerStyle({
"src": "https://mapapi.qq.com/web/bundles/lbs-home/prod/assets/markerActive-NhH9NoBV.png",
"width": 40, // 点标记样式宽度(像素)
})
},
geometries: []
})
this.createMarker(center)
this.createCircle(center)
},
createMarker(position, styleId = 'marker', id = 'marker_' + Date.now()) {
this.markerLayer.add([
{
id: id,
position: position,
styleId: styleId
}
]);
},
createCircle(position) {
this.circle = new TMap.MultiCircle({
map: this.map,
geometries: [{
center: position,
radius: this.row.radius || 100,
}],
});
},
getUserLocation() {
return new Promise((resolve) => {
if (!navigator.geolocation) {
vant.Toast('浏览器不支持定位');
return resolve(null);
}
const loading = vant.Toast.loading({ message: '定位中...', duration: 0 });
navigator.geolocation.getCurrentPosition(
(pos) => {
loading.close();
resolve({
lat: pos.coords.latitude,
lng: pos.coords.longitude
});
if (this.markerLayer) {
this.markerLayer.remove(["current"])
}
const transPosi = this.$coordinateUtil.wgs84ToGcj02(pos.coords.longitude, pos.coords.latitude)
console.log(transPosi)
const center = new TMap.LatLng(transPosi[0], transPosi[1])
this.createMarker(center, 'current', 'current')
},
(err) => {
console.log(err)
loading.close();
vant.Toast('定位失败,请重试');
resolve(null);
},
{ enableHighAccuracy: true, timeout: 3000 }
);
});
},
async fetchCourse() {
const res = await this.$axios.post('/platform/trainSignUp/mine/fetchCourse', {courseId: this.courseId})
this.row = res.data
},
async onSign() {
const coords = await this.getUserLocation()
if (coords) {
this.res = await this.$axios.post('/platform/trainSignUp/mine/drivingScan', {
courseId: this.row.id,
lat: coords.lat,
lng: coords.lng
})
}
}
},
async created() {
await this.fetchCourse()
this.initMap()
this.onSign()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,112 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<!-- 导航栏 -->
<van-nav-bar title="作品上传" left-text="返回" left-arrow placeholder
@click-left="historyBack" fixed></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-menu>
</van-sticky>
<table-list api="/platform/activity/worksCollection/upload/pageData"
:page_form.sync="pageForm"
ref="tableListRef"
title="name"
@ready="onReady"
>
<template v-slot="{index,row}">
<table-column label="主题类型">{{row.subjectName}}</table-column>
<table-column label="作品类型">{{row.worksName}}</table-column>
<table-column label="姓名">{{row.userName}}</table-column>
<table-column label="上传时间">{{$moment(row.createdAt).format('YYYY-MM-DD')}}</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="onEdit(row)">
<i class="fa fa-edit"></i>
<span>编辑</span>
</div>
<div class="action-btn delete" @click="onDelete(row)">
<i class="fa fa-trash"></i>
<span>删除</span>
</div>
</template>
</table-list>
<apply-form ref="applyFormRef"></apply-form>
<info ref="infoRef"></info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../upload/applyForm.js'){}#-->
<!--#include('info.js'){}#-->
new Vue({
el: "#app",
store,
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: '',
year: new Date().getFullYear(),
},
}
},
components: {
'apply-form': applyForm,
'info': INFO,
},
methods: {
onView(row) {
this.$refs.infoRef.onOpen(row)
},
onEdit(row) {
if (this.$moment().isAfter(this.$moment(row.activityEndDateTime))) {
this.$toast.fail("活动已结束,无法修改!")
return
}
this.$refs.applyFormRef.onOpenEdit(row)
},
onDelete(row) {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要删除吗?',
}).then(() => {
this.$axios.post("/platform/activity/worksCollection/upload/delete", {id:row.id}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
}
})
}).catch(() => {
// on cancel
});
},
onReady() {
this.doSearch()
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,64 @@
const INFO = {
template: /*language=HTML*/
`
<div>
<van-action-sheet v-model="visible" :style="{ 'background-color': '#F7F8FA' }" title="报名信息">
<div class="detail-container">
<van-cell-group>
<van-cell title="姓名">
{{ viewData.userName }}
</van-cell>
<van-cell title="工号">
{{ viewData.loginName }}
</van-cell>
<van-cell title="单位">
{{ viewData.unitName }}
</van-cell>
<van-cell title="分工会">
{{ viewData.unionName }}
</van-cell>
<van-cell title="作品名称">
{{ viewData.name }}
</van-cell>
<van-cell title="活动主题">
{{ viewData.activityName }}
</van-cell>
<van-cell title="主题类型">
{{ viewData.subjectName }}
</van-cell>
<van-cell title="作品类型">
{{ viewData.worksName }}
</van-cell>
<van-cell title="作品描述" class="direction-column-cell">
{{ viewData.description }}
</van-cell>
<van-cell title="作品附件" class="direction-column-cell">
<file-preview :files="viewData.files" complete_result></file-preview>
</van-cell>
</van-cell-group>
</div>
</van-action-sheet>
</div>
`,
data() {
return {
viewData: {},
visible: false,
}
},
methods: {
onOpen(row) {
this.$axios.post("/platform/activity/worksCollection/common/findOne", {id: row.id}).then((res) => {
if (res.code === 0) {
this.viewData = res.data
try {
this.viewData.files = JSON.parse(this.viewData.files)
} catch (err) {
}
}
})
this.visible = true
},
}
}
@@ -0,0 +1,159 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<!-- 导航栏 -->
<van-nav-bar title="作品阅览" left-text="返回" left-arrow placeholder
@click-left="historyBack" fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-search
:reverse-color="false"
:show-action="false"
@search="doSearch"
input-align="left"
placeholder="请输入姓名/工号搜索"
v-model="pageForm.searchKeyword"
></van-search>
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
<van-dropdown-item v-model="pageForm.activityId" :options="activityOptions"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
<van-tabs v-model="pageForm.pageOrderName"
@change="doSearch">
<van-tab title="按上传时间正序排序" name="createdAt"></van-tab>
<van-tab title="按点赞多少倒序排序" name="num"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/activity/worksCollection/read/h5/pageData"
:page_form.sync="pageForm"
ref="tableListRef"
title="name"
@ready="onReady"
>
<template v-slot="{index,row}">
<table-column label="主题类型">{{row.subjectName}}</table-column>
<table-column label="作品类型">{{row.worksName}}</table-column>
<table-column label="姓名">{{row.userName}}</table-column>
<table-column label="上传时间">{{$moment(row.createdAt).format('YYYY-MM-DD')}}</table-column>
<table-column label="点赞数">{{row.num}}</table-column>
<table-column label="附件">
<template v-if="row.files">
<file-preview :files="JSON.parse(row.files)" complete_result></file-preview>
</template>
</table-column>
</template>
<template #actions="{index,row}">
<div class="action-btn" @click="onView(row)">
<i class="fa fa-eye"></i>
<span>查看</span>
</div>
<template v-if="row.nbCount>0">
<div class="action-btn" @click="onLike(row)" v-if="!row.isThisLike">
<i class="fa fa-thumbs-o-up"></i>
<span>点赞</span>
</div>
<div class="action-btn" @click="onDeleteLike(row)" v-if="row.isThisLike">
<i class="fa fa-thumbs-up"></i>
<span>取消点赞</span>
</div>
</template>
</template>
</table-list>
<info ref="infoRef"></info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../mine/info.js'){}#-->
new Vue({
el: "#app",
store,
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: '',
pageOrderName: 'createdAt',
pageOrderNameText: '',
activityId: '',
year: new Date().getFullYear(),
},
activityOptions: []
}
},
components: {
'info': INFO,
},
methods: {
onLike(row) {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要点赞吗?',
}).then(() => {
this.$axios.post("/platform/activity/worksCollection/read/h5/doLike", {uploadId: row.id}).then((res) => {
if (res.code === 0) {
row.num = row.num + 1
row.isThisLike = true
this.$toast.success(res.msg)
}
})
}).catch(() => {
// on cancel
});
},
onDeleteLike(row) {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要取消点赞吗?',
}).then(() => {
this.$axios.post("/platform/activity/worksCollection/read/h5/doDeleteLike", {uploadId: row.id}).then((res) => {
if (res.code === 0) {
row.num = row.num - 1
row.isThisLike = false
this.$toast.success(res.msg)
}
})
}).catch(() => {
// on cancel
});
},
onView(row) {
this.$refs.infoRef.onOpen(row)
},
async listActivity() {
const res = await this.$axios.post("/platform/activity/worksCollection/common/listActivity")
if (res.code === 0) {
res.data.forEach(v => {
v.text = v.name
v.value = v.id
})
this.activityOptions = res.data
if (this.activityOptions.length > 0) {
this.pageForm.activityId = this.activityOptions[0].id
}
}
},
async onReady() {
await this.listActivity()
this.doSearch()
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
},
created() {
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,191 @@
const applyForm = {
template:
/*language=HTML*/
`
<div>
<van-action-sheet v-model="visible" :style="{ 'background-color': '#F7F8FA' }" title="报名信息">
<van-form ref="formRef" class="form-container">
<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>
</van-cell-group>
<van-cell-group title="报名信息" class="form-section">
<van-field label="主题类型"
required
:rules="[{ required: true, message: '请选择主题类型' }]"
readonly
is-link
@click="showSubjectPicker = true"
placeholder="请选择主题类型"
name="subjectName"
v-model="formData.subjectName">
</van-field>
<van-popup v-model="showSubjectPicker" position="bottom">
<van-picker
show-toolbar
:columns="subjectTypesOptions.map(v=>v.typeName)"
@confirm="onSubjectConfirm"
@cancel="showSubjectPicker=false"
></van-picker>
</van-popup>
<van-field label="作品类型"
required
:rules="[{ required: true, message: '请选择作品类型' }]"
readonly
is-link
@click="showWorksPicker = true"
placeholder="请选择作品类型"
name="worksName"
v-model="formData.worksName">
</van-field>
<van-popup v-model="showWorksPicker" position="bottom">
<van-picker
show-toolbar
:columns="worksTypeOptions.map(v=>v.worksTypeName)"
@confirm="onWorksConfirm"
@cancel="showWorksPicker=false"
></van-picker>
</van-popup>
<van-field label="作品名称"
required
v-model="formData.name"
name="name"
placeholder="请填写作品名称"
:rules="[{ required: true, message: '请填写作品名称' }]"></van-field>
<van-field label="作品描述"
v-model="formData.description"
type="textarea"
name="description"
rows="4"
autosize
maxlength="150"
:rules="[{ required: true, message: '请填写作品描述' }]"
class="more-text"
placeholder="请填写作品描述"></van-field>
</van-cell-group>
<van-cell-group title="附件">
<van-field class="more-text"
name="files"
:rules="[{ required: true,message:'请上传附件' }]"
label=""
required>
<template #input>
<h5-file-upload
slot="input"
:value.sync="formData.files"
:upload_number="chooseWorksType && chooseWorksType.allowFileNum"
upload_mode="file"
upload_result_category="array"
upload_result_type="url"
complete_result
:accept="fileAccept"
></h5-file-upload>
</template>
</van-field>
</van-cell-group>
<div class="form-actions">
<van-button @click="onSubmit" round type="info">提交</van-button>
</div>
</van-form>
</van-action-sheet>
</div>
`,
data() {
return {
row: {},
visible: false,
formData: {},
subjectTypesOptions: [],
showSubjectPicker: false,
worksTypeOptions: [],
showWorksPicker: false,
fileAccept: null,
chooseWorksType: {}
}
},
methods: {
async onOpen(row) {
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.id)
await this.activityChange(row.id)
this.row = row
this.visible = true
},
async onOpenEdit(row) {
const formData = clone(row)
formData.files = JSON.parse(formData.files)
await this.activityChange(formData.activityId)
await this.subjectChange(formData.subjectId)
this.row = formData
this.formData = formData
this.$set(this.formData, 'username', this.$store.state.user.username)
this.$set(this.formData, 'loginname', this.$store.state.user.loginname)
this.$set(this.formData, 'sex', this.$store.state.user.sex)
this.chooseWorksType = this.worksTypeOptions.find((o) => o.id === formData.worksId)
if (this.chooseWorksType.allowFileTypes && this.chooseWorksType.allowFileTypes.length > 0) {
this.fileAccept = this.chooseWorksType.allowFileTypes.map((item) => "." + item).join(",")
}
this.visible = true
},
onWorksConfirm(value, index) {
this.$set(this.formData, 'worksName', value)
this.$set(this.formData, 'worksId', this.worksTypeOptions[index].id)
this.showWorksPicker = false
this.chooseWorksType = this.worksTypeOptions.find((o) => o.id === this.worksTypeOptions[index].id)
if (this.chooseWorksType.allowFileTypes && this.chooseWorksType.allowFileTypes.length > 0) {
this.fileAccept = this.chooseWorksType.allowFileTypes.map((item) => "." + item).join(",")
}
},
async onSubjectConfirm(value, index) {
this.$set(this.formData, 'subjectName', value)
this.$set(this.formData, 'subjectId', this.subjectTypesOptions[index].id)
await this.subjectChange(this.subjectTypesOptions[index].id)
this.showSubjectPicker = false
},
onSubmit() {
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: "提示",
message: "您确定要提交吗?"
}).then(() => {
this.$toast.loading({
message: '提交中...',
forbidClick: true,
});
this.$axios.post("/platform/activity/worksCollection/upload" + (this.formData.id ? "/update" : "/insert"), {data: JSON.stringify(this.formData)}).then((res) => {
if (res.code === 0) {
this.$toast.clear();
this.$toast.success("提交成功")
pjaxReplace("/platform/activity/worksCollection/mine/h5")
}
})
})
}).catch();
},
async activityChange(value) {
const resp = await this.$axios.post("/platform/activity/worksCollection/common/getSubjectTypes", {activityId: value})
if (resp.code === 0) {
this.subjectTypesOptions = resp.data
}
},
async subjectChange(value) {
const resp = await this.$axios.post("/platform/activity/worksCollection/common/getWorksTypes", {subjectId: value})
if (resp.code === 0) {
this.worksTypeOptions = resp.data
}
}
}
}
@@ -0,0 +1,166 @@
<!--#
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 {
height: calc(100vh - 46px - 44px);
min-height: calc(100vh - 46px - 44px);
overflow-y: auto;
}
.info-img {
display: block;
}
.van-count-down {
color: #fff;
}
</style>
<div id="app">
<!-- 导航栏 -->
<van-nav-bar title="作品上传" left-text="返回" left-arrow placeholder
@click-left="historyBack" fixed></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/activity/worksCollection/upload/h5/activityPageData"
:page_form.sync="pageForm"
ref="tableListRef"
title="name"
img="cover"
@ready="onReady"
>
<template v-slot="{index,row}">
<table-column label="面向对象">{{row.activityGroupName}}</table-column>
<table-column label="报名时间">
{{$moment(row.startDateTime).format('MM/DD HH:mm')
+ '~' + $moment(row.endDateTime).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 v-model="infoVisible" title="详细信息">
<div class="info-container">
<van-image class="info-img" height="186" width="100%" :src="infoRow.cover"></van-image>
<div class="info-title">{{infoRow.name}}</div>
<pdf-preview style="height: calc(100vh - 46px - 44px - 186px - 57px)"
:content="infoRow.content"></pdf-preview>
</div>
<div class="form-container">
<div class="form-actions">
<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>
<apply-form ref="applyFormRef"></apply-form>
</div>
<script nonce="${cspNonce!}">
<!--#include('applyForm.js'){}#-->
new Vue({
el: "#app",
store,
data() {
return {
time: 0,
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: '',
year: new Date().getFullYear(),
activityType: 2,
},
typeOptions: [
{text: '全部', value: 1},
{text: '即将开始', value: 4},
{text: '报名中', value: 2},
{text: '已结束', value: 3},
],
infoVisible: false,
infoRow: {},
}
},
components: {
'apply-form': applyForm,
"pdf-preview": httpVueLoader("/components/plugins/sysFilePreview/PdfIndex.vue?v=" + new Date().getTime())
},
methods: {
onApply(row) {
if (this.$moment().isBefore(this.$moment(row.startDateTime))) {
this.onView(row)
return
}
if (this.$moment().isAfter(this.$moment(row.endDateTime))) {
this.$toast.fail("活动已结束")
return
}
this.$refs.applyFormRef.onOpen(row)
},
onView(row) {
this.infoRow = row
this.time = this.$moment().diff(this.$moment(row.startDateTime), 'milliseconds')
this.infoVisible = true
},
onReady() {
this.doSearch()
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
},
created() {
},
})
</script>
<!--#
}
#-->
@@ -0,0 +1,137 @@
let ADDRESS = {
template: `
<div>
<van-address-list
:list="addressList"
@add="onAdd"
@edit="onEdit"
add-button-text="新增地址"
:switchable="false"
default-tag-text="默认"
@click-item="onClick"
v-if="addressList && addressList.length>0"
v-model="chosenAddressId"
></van-address-list>
<van-empty image="/assets/platform/plugins/vant-green/images/nodata/nodata.png" description="暂无数据" v-else>
<van-button @click="onAdd" class="mt10" round type="primary">新增地址</van-button>
</van-empty>
<van-action-sheet :close-on-click-overlay="false" :title="title" v-model="editActionSheet">
<van-address-edit
:address-info="addressInfo"
:area-columns-placeholder="['请选择', '请选择', '请选择']"
:area-list="areaList"
:show-delete="showDelete"
@delete="onDelete"
@save="onSave"
ref="address"
show-search-result
show-set-default
tel-maxlengtfals
></van-address-edit>
</van-action-sheet>
</div>
`,
store,
data() {
return {
areaList: areaList,
addressInfo: {},
addressList: [],
editActionSheet: false,
showDelete: "",
title: "",
chosenAddressId: "",
projectId: ""
}
},
methods: {
async selectUserAddress() {
const loading = this.$toast.loading({
message: "加载中...",
forbidClick: true,
overlay: true,
duration: 0
})
const resp = await this.$axios.post("/platform/benefit/address/selectUserAddress", { userId: this.$store.state.user.id })
resp.data.map((r) => {
r.name = r.userName
r.default = r.isDefault
r.address = "收货地址:" + r.province + r.city + r.county + r.addressDetail
})
setTimeout(() => {
this.addressList = resp.data
/* for (let i = 0; i < this.addressList.length; i++) {
if (this.addressList[i].default==1) {
this.chosenAddressId = this.addressList[i].id
}
}*/
loading.close()
}, 500)
}
/*back() {
if (this.projectId) {
this.$pjaxReplace("/platform/h5/benefit/userChoose/index?id=" + this.projectId)
} else {
/!*this.$pjaxReplace("/platform/h5/home")*!/
window.history.go(-1)
}
}*/,
onEdit(row) {
this.title = "编辑地址"
const data = JSON.parse(JSON.stringify(row))
this.showDelete = !!data.id
this.addressInfo = data
this.editActionSheet = true
},
onAdd() {
this.title = "新增地址"
this.addressInfo = {}
this.editActionSheet = true
},
async onSave(row) {
const loading = this.$toast.loading({
message: "加载中...",
forbidClick: true,
overlay: true,
duration: 0
})
row.userName = row.name
const resp = await this.$axios.post("/platform/benefit/address/doSaveUserAddress", { data: JSON.stringify(row) })
if (resp.code === 0) {
this.$toast.success(resp.msg)
await this.selectUserAddress()
loading.close()
this.editActionSheet = false
} else {
this.$toast.fail(resp.msg)
}
},
async onDelete(row) {
const loading = this.$toast.loading({
message: "加载中...",
forbidClick: true,
overlay: true,
duration: 0
})
const resp = await this.$axios.post("/platform/benefit/address/deleteAddress", { id: row.id })
if (resp.code === 0) {
this.$toast.success(resp.msg)
await this.selectUserAddress()
loading.close()
this.editActionSheet = false
} else {
this.$toast.fail(resp.msg)
}
},
onClick(row, index) {
this.$emit("address_click", row)
}
},
created() {
this.projectId = GetQueryString("projectId")
this.selectUserAddress()
}
}
<!--#include("/platform/zhghh5/benefit/include/areaList.js"){}#-->
@@ -0,0 +1,31 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-sticky>
<van-nav-bar @click-left="back" left-arrow left-text="返回" placeholder title="地址管理"></van-nav-bar>
</van-sticky>
<benefit-address ref="address"></benefit-address>
</div>
<script nonce="${cspNonce!}">
<!--#include("address.js"){}#-->
new Vue({
el: "#app",
components: {
"benefit-address": ADDRESS
},
methods: {
back() {
if (this.projectId) {
this.$pjaxReplace("/platform/h5/benefit/userChoose/index?id=" + this.projectId)
} else {
/*this.$pjaxReplace("/platform/h5/home")*/
window.history.go(-1)
}
}
}
})
</script>
<!--#
}
#-->
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,153 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-sticky>
<van-nav-bar @click-left="back" left-arrow left-text="返回" placeholder title="结算"></van-nav-bar>
</van-sticky>
<van-cell
is-link
@click="toAddress"
v-for="(address,index) in 1"
size="large"
:value="addressList[index].name+addressList[index].tel"
:label="addressList[index].address"
>
<!-- 使用 title 插槽来自定义标题 -->
<template #title>
<span class="custom-title">{{addressList[index].title}}</span>
</template>
</van-cell>
<van-swipe-cell v-for="(goods,index) in cartGoodsList">
<van-card
:price="goods.benefitGoodsSpecifications.points"
:desc="goods.benefitGoods.simpleDesc"
:title="goods.benefitGoodsSpecifications.name"
:thumb="goods.benefitGoodsSpecifications.imgUrl[0].url"
></van-card>
<template #right>
<van-button square text="删除" type="danger" @click="delGoods(index)" class="delete-button" />
</template>
</van-swipe-cell>
<van-submit-bar :price="checkedGoodsAmount*100" button-text="提交订单" @submit="onSubmit"></van-submit-bar>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
data() {
return {
cartGoodsList: [],
addressList: [],
checkedGoodsAmount: 0,
goodsId: ""
}
},
created() {
this.goodsId = window.location.search.substring(4)
if (this.goodsId != "") {
this.initGoods()
} else {
this.getCartGoods()
}
this.getAddress()
},
methods: {
back() {
this.$pjaxReplace("/platform/h5/benefit/shop")
},
toAddress() {
this.$pjaxReplace("/platform/h5/benefit/address")
},
getCartGoods() {
this.$axios.post("/platform/benefit/shop/getCartList").then((resp) => {
if (resp.code === 0) {
const goods = []
for (let i = 0; i < resp.data.length; i++) {
if (resp.data[i].isChecked == true) {
goods.push(resp.data[i])
this.checkedGoodsAmount += resp.data[i].benefitGoodsSpecifications.points
}
}
this.cartGoodsList = goods
}
})
},
initGoods() {
this.$axios.post("/platform/benefit/shop/findOneBySpecId", { id: this.goodsId }).then((res) => {
if (res.code === 0) {
res.data.imgUrl = JSON.parse(res.data.imgUrl)
res.data = {
benefitGoods: {
id: res.data.goodsId,
name: res.data.goodsName,
simpleDesc: res.data.simpleDesc
},
benefitGoodsSpecifications: res.data,
id: ""
}
const goods = []
goods.push(res.data)
this.checkedGoodsAmount = res.data.benefitGoodsSpecifications.points
this.cartGoodsList = goods
}
})
},
async getAddress() {
const resp = await this.$axios.post("/platform/benefit/address/selectUserAddress", { userId: this.$store.state.user.id })
resp.data.map((r) => {
r.name = r.userName
r.default = r.isDefault
r.address = r.addressDetail
r.title = r.province + r.city + r.county
})
this.addressList = resp.data
},
onSubmit() {
//获取所有的购物车id
const cartId = []
for (let i = 0; i < this.cartGoodsList.length; i++) {
cartId.push(this.cartGoodsList[i].id)
}
//获取所有的规格
const goodsSpecifications = []
for (let i = 0; i < this.cartGoodsList.length; i++) {
goodsSpecifications.push(this.cartGoodsList[i].benefitGoodsSpecifications)
}
const benefitBuyGoodsVo = {
list: JSON.stringify(goodsSpecifications),
addressId: this.addressList[0].id,
cartId: JSON.stringify(cartId)
}
this.$axios.post("/platform/benefit/shop/buyGoodsList", benefitBuyGoodsVo).then((res) => {
if (res.code === 0) {
this.$toast.success("购买成功!")
this.$pjaxReplace("/platform/h5/benefit/shop/order")
}
})
},
delGoods(index) {
this.cartGoodsList.slice(index)
}
}
})
</script>
<style lang="less" scoped>
.delete-button {
color: #fff;
height: 100%;
background-color: #ee0a24;
border: 1px solid #ee0a24;
}
</style>
<!--#
}
#-->
@@ -0,0 +1,193 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-sticky>
<van-nav-bar @click-left="back" left-arrow left-text="返回" placeholder title="购物车"></van-nav-bar>
</van-sticky>
<div class="cart-box">
<div v-for="item in cartList" :key="item.id" class="cart-item">
<!-- 每个商品前的按钮 -->
<van-checkbox :name="item.id" @click="onEdit(item)" class="checkbox-btn" v-model="item.isChecked"></van-checkbox>
<!-- 商品信息 -->
<van-card :price="item.benefitGoodsSpecifications.points" :thumb="item.benefitGoodsSpecifications.imgUrl[0].url">
<!-- 自定义标题,删除按钮 -->
<template #title>
<span>{{ item.benefitGoods.name }}</span>
<van-icon name="delete-o" class="delete-icon" @click="onDelete(item)" />
</template>
<!-- 自定义备注 -->
<template #desc>
<div style="color: #a2a2a2">{{ item.benefitGoods.simpleDesc }}</div>
</template>
</van-card>
</div>
<!-- 按钮 -->
<!-- 下方结算 -->
<!-- vant显示的数字不对,9999元会显示成99.99元,所以需要乘以100 -->
<van-submit-bar :price="checkedGoodsAmount*100" button-text="提交订单" @submit="onSubmit">
<van-checkbox @click="onClickCheckAll" v-model="checkedAll">全选</van-checkbox>
</van-submit-bar>
</div>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
data() {
return {
cartList: [], //商品总列表
cartTotal: {}, //购物车数据
// price: 0,
goodsId: "",
number: "",
productId: "",
id_: "",
isChecked: "1",
// productIdsList:[],
checkedGoodsAmount: 0, //选中的商品的总金额
checkedAll: 1
}
},
created() {
this.getCart()
},
methods: {
back() {
this.$pjaxReplace("/platform/h5/benefit/shop")
},
// 获取数据
getCart() {
this.$axios.post("/platform/benefit/shop/getCartList").then((resp) => {
if (resp.code === 0) {
this.cartList = resp.data
for (let i = 0; i < this.cartList.length; i++) {
const item = this.cartList[i]
if (item.isChecked == true) {
this.checkedGoodsAmount += item.benefitGoodsSpecifications.points
} else {
this.checkedAll = 0
}
}
}
})
},
// 删除单个商品的时候,发送删除商品的请求
async onDelete(item) {
const loading = this.$toast.loading({
message: "加载中...",
forbidClick: true,
overlay: true,
duration: 0
})
const resp = await this.$axios.post("/platform/benefit/shop/deleteCart", { id: item.id })
if (resp.code === 0) {
this.$toast.success(resp.msg)
await this.getCart()
loading.close()
} else {
this.$toast.fail(resp.msg)
}
},
// 购物车商品步进器功能接口 按下商品+1或者-1按钮,
updateCartData() {
// 直接发送更新数据请求,将当前的商品数量带着
UpdateCartData({
goodsId: this.goodsId,
id: this.id_,
number: this.number,
productId: this.productId
}).then((res) => {
console.log(999, res)
if (res.errno === 0) {
this.getData() //重新请求购物车商品数据,渲染
}
})
},
// 切换购物车商品选中状态,发送请求
async onEdit(row) {
const loading = this.$toast.loading({
message: "加载中...",
forbidClick: true,
overlay: true,
duration: 0
})
const resp = await this.$axios.post("/platform/benefit/shop/editCart", row)
if (resp.code === 0) {
await this.getCart()
loading.close()
} else {
this.$toast.fail(resp.msg)
}
},
// 点击全选,切换购物车商品选中状态,发送请求
onClickCheckAll() {
let productIdAllList = []
this.cartList.forEach((item) => {
productIdAllList.push(item.id.toString())
})
const loading = this.$toast.loading({
message: "加载中...",
forbidClick: true,
overlay: true,
duration: 0
})
const resp = this.$axios
.post("/platform/benefit/shop/editCartList", {
ids: JSON.stringify(productIdAllList),
isChecked: this.checkedAll
})
.then((res) => {
if (res.code === 0) {
this.getCart()
loading.close()
}
})
},
onSubmit() {
this.$pjaxReplace("/platform/h5/benefit/shop/buy")
}
}
})
</script>
<style lang="less" scoped>
/deep/.van-checkbox__label {
flex: 1;
}
/deep/.van-checkbox {
margin-bottom: 2px;
}
/deep/.van-submit-bar {
bottom: 50px;
}
.cart-box {
padding-bottom: 150px;
box-sizing: border-box;
.van-card {
position: relative;
}
.delete-icon {
position: absolute;
top: 5px;
right: 5px;
}
.cart-item {
position: relative;
padding-left: 40px;
.checkbox-btn {
position: absolute;
left: 20px;
top: 50%;
transform: translate(-50%, -50%);
}
}
}
</style>
<!--#
}
#-->
@@ -0,0 +1,103 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-sticky>
<van-nav-bar @click-left="back" left-arrow left-text="返回" placeholder title="分类"></van-nav-bar>
</van-sticky>
<div class="channel-box">
<van-tabs @click="changeFn">
<van-tab v-for="item in goodsCategoryList" :key="item.id" :title="item.name">
<!-- 产品列表 -->
<van-card
v-for="item in goodsList"
:key="item.id"
@click="clickFn(item.id)"
:price="item.money"
:desc="item.simpleDesc"
:title="item.name"
:thumb="item.imgUrl!=null?item.imgUrl[0].url:'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fcbu01.alicdn.com%2Fhttps%3A%2F%2Fcbu01.alicdn.com%2Fimg%2Fibank%2FO1CN01PfO15Z1d0jv9XS9cD_%21%21980613674-0-cib.jpg&refer=http%3A%2F%2Fcbu01.alicdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1744168614&t=d8ddb01b1cd4b7d289e491913950b215'"
></van-card>
</van-tab>
</van-tabs>
</div>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
data() {
return {
id_: "0", // 当前类别的id
goodsCategoryList: [], // 分类数组
goodsList: [], //当前类别对应的商品列表
front_desc: ""
}
},
created() {
this.initGoodsCategory() //获取所有分类数据
this.id_ = this.goodsCategoryList.length > 0 ? this.goodsCategoryList[0].id : ""
this.getCategoryListData()
},
methods: {
//获取商品类型
initGoodsCategory() {
this.$axios.post("/platform/benefit/shop/getCategoryTree").then((res) => {
if (res.code === 0) {
this.goodsCategoryList = res.data
this.goodsCategoryList.unshift({
id: "",
name: "全部",
parentId: "",
weight: 0
})
}
})
},
//获取当前类别对应的产品数组
getCategoryListData() {
this.$axios.post("/platform/benefit/goods/getGoodsListByType", { id: this.id_ }).then((res) => {
if (res.code === 0) {
this.goodsList = res.data
}
})
},
// / 切换分类
changeFn(title, name) {
console.log(this.goodsCategoryList)
// title 下标
// name: 分类标题
this.goodsList = []
this.id_ = ""
this.goodsCategoryList.forEach((item) => {
if (item.name === name) {
this.id_ = item.id
}
})
this.getCategoryListData()
},
back() {
this.$pjaxReplace("/platform/h5/benefit/shop")
},
clickFn(id) {
this.$pjaxReplace("/platform/h5/benefit/shop/detail?id=" + id)
}
}
})
</script>
<style lang="less" scoped>
.channel-box {
font-size: 16px;
line-height: 40px;
p {
color: #666;
}
}
</style>
<!--#
}
#-->
@@ -0,0 +1,249 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-sticky>
<van-nav-bar @click-left="back" left-arrow left-text="返回" placeholder title="详情"></van-nav-bar>
</van-sticky>
<div class="product-detail-box">
<van-swipe :autoplay="3000" v-if="formData.imgUrl!=null">
<van-swipe-item v-for="item in formData.imgUrl" :key="item.uid">
<img :src="item.url" />
</van-swipe-item>
</van-swipe>
<div v-else class="swipe-img">
<img
style="height: 390px"
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fcbu01.alicdn.com%2Fhttps%3A%2F%2Fcbu01.alicdn.com%2Fimg%2Fibank%2FO1CN01PfO15Z1d0jv9XS9cD_%21%21980613674-0-cib.jpg&refer=http%3A%2F%2Fcbu01.alicdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1744168614&t=d8ddb01b1cd4b7d289e491913950b215"
alt=""
/>
</div>
<div class="info">
<p class="info-name">{{ formData.name }}</p>
<p class="info-brief">{{ formData.simpleDesc }}</p>
<p class="info-price">¥{{ formData.money }}</p>
</div>
<div class="attribute">
<div class="mytitle">
<span></span>
<h3>商品参数</h3>
</div>
<ul v-if="formData.benefitGoodsSpecificationsList.length>0">
<li v-for="(item,index) in formData.benefitGoodsSpecificationsList" :key="item.id">
<span class="attribute-name"></span>
<span class="attribute-value">规格{{chineseNum(index+1)}}{{ item.name }}</span>
</li>
</ul>
<ul v-else>
<li>
<span class="attribute-name"></span>
<span class="attribute-value">该暂无规格</span>
</li>
</ul>
</div>
<!-- 产品详情 -->
<div class="mytitle">
<span></span>
<h3>产品详情</h3>
</div>
<!-- 产品描述信息 -->
<div class="goods_desc" v-html="formData.description"></div>
<!-- 下方购物车 -->
<van-goods-action>
<van-goods-action-icon icon="cart-o" text="购物车" :badge="badge" @click="goCart"></van-goods-action-icon>
<van-goods-action-button type="warning" text="加入购物车" @click="addCar"></van-goods-action-button>
<van-goods-action-button type="danger" text="立即购买" @click="addCar"></van-goods-action-button>
</van-goods-action>
<!-- 添加购物车面板 -->
<van-sku v-model="show" ref="sku" :sku="sku" :goods="goods" @add-cart="onAddCartClicked" @buy-clicked="toBuy"></van-sku>
</div>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
data() {
return {
gallery: [],
info: {},
attribute: [], //参数
show: false,
sku: {},
goods: {
// 默认商品 sku 缩略图
picture: ""
},
productList: [], // 当前产品信息
badge: 0,
id: "",
formData: {}
}
},
created() {
this.id = window.location.search.substring(4)
this.initGoods()
this.getCartData()
},
methods: {
chineseNum(num) {
const numMap = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"]
return numMap[num]
},
back() {
this.$pjaxReplace("/platform/h5/benefit/shop")
},
goCart() {
this.$pjaxReplace("/platform/h5/benefit/shop/cart")
},
addCar() {
const spec = []
const list = []
for (let i = 0; i < this.formData.benefitGoodsSpecificationsList.length; i++) {
item = this.formData.benefitGoodsSpecificationsList[i]
spec.push({
id: item.id, // skuValueId:规格值 id
name: item.name, // skuValueName:规格值名称
imgUrl: item.imgUrl[0].url, // 规格类目图片,只有第一个规格类目可以定义图片
previewImgUrl: item.imgUrl[0].url // 用于预览显示的规格类目图片
})
list.push({
id: 2259 + i, // skuId
s1: item.id, // 规格类目 k_s 为 s1 的对应规格值 id
s2: item.id, // 规格类目 k_s 为 s1 的对应规格值 id
price: item.points * 100, // 价格(单位分)
stock_num: 110 // 当前 sku 组合对应的库存
})
}
this.sku = {
// 所有sku规格类目与其值的从属关系,比如商品有颜色和尺码两大类规格,颜色下面又有红色和蓝色两个规格值。
// 可以理解为一个商品可以有多个规格类目,一个规格类目下可以有多个规格值。
tree: [
{
k: "规格", // skuKeyName:规格类目名称
k_s: "s1", // skuKeyStrsku 组合列表(下方 list)中当前类目对应的 key 值,value 值会是从属于当前类目的一个规格值 id
v: spec,
largeImageMode: true // 是否展示大图模式
}
],
list: list,
price: this.formData.money, // 默认价格(单位元)
stock_num: 999, // 商品总库存
none_sku: this.formData.benefitGoodsSpecificationsList.length == 0 ? true : false, // 是否无规格商品
hide_stock: true // 是否隐藏剩余库存
}
this.goods = {
// 默认商品 sku 缩略图
picture: this.formData.imgUrl[0].url
}
this.show = true
},
// 加入购物车
onAddCartClicked() {
const cart = {
goodsId: this.formData.id,
specificationsId: this.$refs.sku.getSkuData().selectedSkuComb.s1
}
this.$axios.post("/platform/benefit/shop/addCart", cart).then((res) => {
if (res.code === 0) {
this.$toast.success("添加成功")
// 隐藏 商品规格面板
this.show = false
}
})
},
// 获取购物车商品数量
getCartData() {
this.$axios.post("/platform/benefit/shop/getCartList").then((resp) => {
if (resp.code === 0) {
this.badge = resp.data.length
}
})
},
initGoods() {
this.$axios.post("/platform/benefit/shop/findOne", { id: this.id }).then((res) => {
if (res.code === 0) {
this.formData = res.data
this.formData.imgUrl = JSON.parse(this.formData.imgUrl)
}
})
},
toBuy() {
this.$pjaxReplace("/platform/h5/benefit/shop/buy?id=" + this.$refs.sku.getSkuData().selectedSkuComb.s1)
}
}
})
</script>
<style lang="less" scoped>
.product-detail-box {
font-size: 14px;
line-height: 30px;
img {
width: 100%;
}
.info {
text-align: center;
.info-brief {
color: #666;
}
.info-price {
color: red;
}
}
.attribute {
ul {
li {
border-bottom: 1px solid #eee;
font-size: 12px;
display: flex;
.attribute-name {
width: 10%;
}
.attribute-value {
flex: 1;
}
}
}
}
.mytitle {
text-align: center;
font-size: 16px;
position: relative;
height: 50px;
span {
width: 50%;
height: 2px;
background-color: #ccc;
display: inline-block;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
h3 {
width: 30%;
background-color: #fff;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
/deep/.goods_desc {
img {
width: 100%;
}
}
}
</style>
<!--#
}
#-->
@@ -0,0 +1,196 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<template>
<van-sticky>
<van-nav-bar @click-left="back" left-arrow left-text="返回" placeholder title="福利商城"></van-nav-bar>
</van-sticky>
<div class="home">
<!-- 轮播图 -->
<div class="swiper-com">
<van-swipe class="my-swipe" :autoplay="3000" indicator-color="white">
<van-swipe-item v-for="item in banner" :key="item.id">
<img v-if="item.imgUrl.length>0" @click="clickFn(item.id)" :src="item.imgUrl[0].url" alt="" />
<img
v-else
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fcbu01.alicdn.com%2Fhttps%3A%2F%2Fcbu01.alicdn.com%2Fimg%2Fibank%2FO1CN01PfO15Z1d0jv9XS9cD_%21%21980613674-0-cib.jpg&refer=http%3A%2F%2Fcbu01.alicdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1744168614&t=d8ddb01b1cd4b7d289e491913950b215"
alt=""
/>
</van-swipe-item>
</van-swipe>
</div>
<div class="gird">
<van-grid :column-num="channel.length">
<van-grid-item v-for="item in channel" :key="item.id" :icon="item.icon_url" :text="item.name" @click="btn(item.id)" />
</van-grid>
</div>
<!-- 分类商品 -->
<div v-if="item.goodsList.length>0" class="week-product" v-for="item in categoryList" :key="item.id">
<div class="mytitle">
<span></span>
<h3>{{ item.name }}</h3>
</div>
<ul>
<li v-for="good in item.goodsList" :key="good.id" @click="clickFn(good.id)">
<img style="height: 180px" :src="good.imgUrl[0].url" alt="" />
<p>{{ good.name }}</p>
<p>¥{{ good.money }}</p>
</li>
</ul>
</div>
<div class="week-product">
<div class="mytitle">
<span></span>
<h3>福利活动</h3>
</div>
<div v-if="projectList.length > 0" class="table-list">
<div @click="clickFl" :key="row.id" class="table-card" v-for="row in projectList">
<van-image :src="row.cover" fit="cover" height="200" width="100%"></van-image>
<div style="margin: 10px">
<div style="font-size: 15px">开始时间:{{$moment(row.startChoiceTime).format('YYYY-MM-DD HH:mm')}}</div>
<div style="font-size: 15px">结束时间:{{$moment(row.endChoiceTime).format('YYYY-MM-DD HH:mm')}}</div>
</div>
</div>
</div>
<div v-else class="table-list">
<van-empty class="custom-image" image="https://img01.yzcdn.cn/vant/custom-empty-image.png" description="暂无福利活动"></van-empty>
</div>
</div>
</div>
</template>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
data() {
return {
value: "",
banner: [], //轮播图
channel: [
{ id: "category", name: "分类", icon_url: "apps-o" },
{ id: "cart", name: "购物车", icon_url: "shopping-cart-o" },
{ id: "order", name: "我的订单", icon_url: "orders-o" }
], //居家-志趣数据
projectList: [],
hotGoodsList: [],
topicList: [],
categoryList: []
}
},
methods: {
//获取轮播图
initGoodsImg() {
this.$axios.post("/platform/benefit/shop/getGoodsList").then((res) => {
if (res.code === 0) {
this.banner = res.data
}
})
},
btn(id) {
this.$pjaxReplace("/platform/h5/benefit/shop/" + id)
},
back() {
this.$pjaxReplace("/platform/h5/home")
},
clickFn(id) {
this.$pjaxReplace("/platform/h5/benefit/shop/detail?id=" + id)
},
//获取福利商品
initGoods() {
this.$axios.post("/platform/benefit/shop/getGoodsListByType").then((res) => {
if (res.code === 0) {
this.categoryList = res.data
}
})
},
//获取福利项目
initProject() {
this.$axios.post("/platform/benefit/shop/getProjectGoodsList").then((res) => {
if (res.code === 0) {
if (res.data.length > 0) {
this.projectList = [res.data[0]]
}
}
})
},
clickFl() {
this.$pjaxReplace("/platform/h5/benefit/userSelection")
}
},
created() {
this.initGoodsImg()
this.initProject()
this.initGoods()
}
})
</script>
<style>
.home {
padding-bottom: 100px;
box-sizing: border-box;
}
.swiper-com {
width: 100%;
img {
width: 100%;
}
}
.week-product {
.mytitle {
text-align: center;
font-size: 16px;
background: #ffffff;
position: relative;
height: 50px;
span {
width: 50%;
height: 2px;
background-color: #ccc;
display: inline-block;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
h3 {
width: 30%;
background-color: #fff;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
ul {
display: flex;
justify-content: space-between;
background-color: #ffffff;
flex-wrap: wrap;
li {
width: 49%;
img {
width: 100%;
}
p {
text-align: center;
font-size: 16px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
}
.top-box {
h3 {
font-size: 22px;
line-height: 60px;
text-align: center;
}
}
</style>
<!--#
}
#-->
@@ -0,0 +1,125 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar @click-left="back" left-arrow left-text="返回" placeholder title="我的订单"></van-nav-bar>
<van-sticky offset-top="46px">
<van-search
v-model="pageForm.goodsName"
placeholder="请输入商品名称进行查询"
:show-action="false"
:reverse-color="false"
input-align="left"
@search="doSearch"
></van-search>
</van-sticky>
<van-list v-model="tableLoading" :finished="tableFinished" finished-text="没有更多了" @load="pageData">
<van-swipe-cell v-for="(order,index) in tableData">
<van-card
@click="detail(order)"
:price="order.points"
:desc="order.specName"
:title="order.goodsName"
:thumb="order.imgUrl[0].url"
></van-card>
<template #right>
<van-button square text="删除" @click="deleteOrder(order.id)" type="danger" class="delete-button" />
</template>
</van-swipe-cell>
</van-list>
<van-action-sheet v-model="show" title="详情">
<div class="content">
<van-cell-group>
<van-cell title="商品名称" :value="formData.goodsName"></van-cell>
<van-cell title="商品规格" :value="formData.specName"></van-cell>
<van-cell title="下单时间" :value="formData.orderTime"></van-cell>
<van-cell title="收货信息" :value="formData.userAddress"></van-cell>
<van-cell title="收货地址" :value="formData.receiveAddress"></van-cell>
<van-cell title="商品详情" :label="formData.simpleDesc"></van-cell>
</van-cell-group>
</div>
</van-action-sheet>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
data() {
return {
list: [],
tableLoading: false,
tableFinished: false,
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
goodsName: ""
},
tableData: [],
show: false,
formData: {}
}
},
created() {
this.pageData()
},
methods: {
back() {
this.$pjaxReplace("/platform/h5/benefit/shop")
},
doSearch() {
this.pageForm.pageNumber = 1
this.tableData = []
this.tableFinished = false
this.pageData()
},
pageData() {
this.tableLoading = true
this.$axios.post("/platform/benefit/order/pageData", this.pageForm).then((resp) => {
this.tableData = this.tableData.concat(resp.data.list)
for (let i = 0; i < this.tableData.length; i++) {
this.tableData[i].imgUrl = JSON.parse(this.tableData[i].imgUrl)
}
this.pageForm.totalCount = resp.data.totalCount
if (this.tableData.length >= this.pageForm.totalCount) {
this.tableFinished = true
} else {
this.pageForm.pageNumber++
}
this.tableLoading = false
})
},
async deleteOrder(id) {
const loading = this.$toast.loading({
message: "加载中...",
forbidClick: true,
overlay: true,
duration: 0
})
const resp = await this.$axios.post("/platform/benefit/address/deleteAddress", { id: id })
if (resp.code === 0) {
this.$toast.success(resp.msg)
await this.doSearch()
loading.close()
} else {
this.$toast.fail(resp.msg)
}
},
detail(order) {
this.formData = order
this.show = true
}
}
})
</script>
<style lang="less" scoped>
.delete-button {
color: #fff;
height: 100%;
background-color: #ee0a24;
border: 1px solid #ee0a24;
}
</style>
<!--#
}
#-->
@@ -0,0 +1,557 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.table-list .collapse .van-cell__left-icon {
color: red;
}
.table-list .table-card .goodsPm {
font-size: 13px;
background-color: rgb(253, 247, 229);
color: rgb(202, 156, 108);
display: flex;
justify-content: center;
align-items: center;
height: 30px;
}
.table-list .table-card .goodsYxz {
font-size: 13px;
display: flex;
justify-content: center;
align-items: center;
height: 30px;
}
</style>
<div id="app" v-cloak>
<van-sticky>
<van-nav-bar
@click-left="()=>this.$pjaxReplace('/platform/h5/benefit/userSelection')"
left-arrow
left-text="返回"
placeholder
title="商品列表"
></van-nav-bar>
</van-sticky>
<div>
<div class="table-list">
<div class="table-card">
<van-collapse class="collapse" v-model="benefitViews">
<van-collapse-item icon="star" name="1" title="福利信息">
<div>
<van-cell-group>
<van-cell :value="viewData.name" title="福利名称"></van-cell>
<van-cell title="是否电子签字">
<dict-tag :options="dict.type.BENEFIT_SIGN_MODE"
:value="viewData.signMode"></dict-tag>
</van-cell>
<van-cell title="发放形式">
<dict-tag :options="dict.type.BENEFIT_PROVIDE_MODE"
:value="viewData.provideMode"></dict-tag>
</van-cell>
<van-cell title="选择开始时间" v-if="viewData.provideMode==='BENEFIT_PROVIDE_MODE_TWO'">
{{$moment(viewData.startChoiceTime).format("YYYY-MM-DD HH:mm")}}
</van-cell>
<van-cell title="选择结束时间" v-if="viewData.provideMode==='BENEFIT_PROVIDE_MODE_TWO'">
{{$moment(viewData.endChoiceTime).format("YYYY-MM-DD HH:mm")}}
</van-cell>
<van-cell title="逾期选择时间" v-if="viewData.provideMode==='BENEFIT_PROVIDE_MODE_TWO'">
<span v-if="viewData.endOverdueChoiceTime">
{{ $moment(viewData.endOverdueChoiceTime).format("YYYY-MM-DD HH:mm") }}
</span>
<span v-else>暂无</span>
</van-cell>
<van-cell title="福利总积分" v-if="viewData.provideMode==='BENEFIT_PROVIDE_MODE_TWO'">
{{viewData.totalMoney}}
</van-cell>
</van-cell-group>
</div>
</van-collapse-item>
</van-collapse>
</div>
<!-- 如果是统一发放并且需要签字-->
<div v-if="viewData.signMode==='BENEFIT_SIGN_MODE_ONE'&&viewData.provideMode === 'BENEFIT_PROVIDE_MODE_ONE'">
<van-cell>
<van-icon class="van-cell__left-icon" color="red" name="info" slot="icon"></van-icon>
<div slot="title" style="font-weight: bold; font-size: 15px">电子签名</div>
<template #label>
<div>
<h5-signature v-model="formData.userSign"></h5-signature>
</div>
</template>
</van-cell>
<div style="padding: 10px 16px; left: 0; right: 0; bottom: 0; background: #ffffff">
<van-button @click="submit" round style="width: 100%" type="primary">提交</van-button>
</div>
</div>
<!-- 如果是意向选择-->
<div v-if="viewData.provideMode==='BENEFIT_PROVIDE_MODE_TWO'">
<div class="table-card" v-for="(item,index) in viewData.benefitGoodsList">
<div>
<van-row gutter="5">
<van-col span="2">
<van-image height="30" src="/assets/mobile/img/benefit/1.png" width="30"></van-image>
</van-col>
<van-col span="14">
<div class="goodsPm">此套餐在本次福利排行第{{index+1}}名</div>
</van-col>
<van-col span="8">
<div class="goodsYxz">已选择{{item.choiceNum}}件</div>
</van-col>
</van-row>
</div>
<van-card :price="item.money.toFixed(2)" tag="">
<template #title>
<div
@click="openViewDesc(item.description)"
style="font-weight: bold; font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis"
>
{{item.name}}
</div>
</template>
<template #desc>
<div @click="openViewDesc(item.description)" style="margin: 5px">{{item.simpleDesc}}</div>
</template>
<template #thumb>
<van-image :src="item.imgUrl[0].url" @click="openViewDesc(item.description)" height="80"
width="80" v-if="item.imgUrl&&item.imgUrl.length>0"></van-image>
<van-image
src="/assets/mobile/img/benefit/2.png"
@click="openViewDesc(item.description)" height="80"
width="80" v-else></van-image>
</template>
<template #num>
<van-stepper
:default-value="0"
:min="0"
async-change
button-size="20"
disable-input
integer
theme="round"
v-model="item.selectNum"
></van-stepper>
</template>
</van-card>
</div>
<div style="padding-top: 100px">
<van-submit-bar
:button-text="confirmButtonInfo.text"
:price="sumSelectMoney"
@submit="openSubmit"
class="submitBar"
tip="您可以在福利选择截至时间之前修改福利套餐"
tip-icon="info-o"
></van-submit-bar>
</div>
</div>
</div>
</div>
<van-popup :style="{ height: '100%',width: '100%'}" position="right" safe-area-inset-bottom v-model="descPopup">
<van-sticky>
<van-nav-bar @click-left="descPopup=false" fixed left-arrow left-text="返回" placeholder
title="详情"></van-nav-bar>
</van-sticky>
<div style="margin-top: 45px">
<div @click="descImgClick" class="desc" v-html="description"></div>
</div>
</van-popup>
<van-action-sheet :close-on-click-overlay="false" title="确认福利套餐" v-model="confirmPopup">
<div>
<!--选择的信息-->
<van-cell>
<van-icon class="van-cell__left-icon" color="red" name="info" slot="icon"></van-icon>
<div slot="title" style="font-weight: bold; font-size: 15px">已选福利</div>
</van-cell>
<van-cell style="padding: 0" v-for="(item,index) in formData.benefitGoodsList">
<van-card
:key="item.id"
:num="item.selectNum"
:thumb="(item.imgUrl&&item.imgUrl.length>0)?item.imgUrl[0].url:'/assets/mobile/img/benefit/2.png'"
:title="item.name"
center
desc=""
style="border-radius: 8px; background: #ffffff"
></van-card>
<!-- 有规格时出现-->
<van-radio-group v-model="item.specificationsId">
<van-cell-group>
<van-cell
:key="index"
:title="specifications.name"
@click="specificationsClick(specifications,index)"
clickable
v-for="(specifications,index) in item.benefitGoodsSpecificationsList"
>
<template #right-icon>
<van-radio :name="specifications.id" :ref="'radio'+specifications.id"></van-radio>
</template>
</van-cell>
</van-cell-group>
</van-radio-group>
<!--邮寄到家 填写收货地址-->
<div v-if="item.goodsProvideMode==='GOODS_PROVIDE_MODE_POST'">
<van-cell @click="goodsAddressClick(item,index)" class="confirmWelfareCell" is-link>
<van-icon class="van-cell__left-icon" color="red" name="info" slot="icon"></van-icon>
<div slot="title" style="font-weight: bold; font-size: 15px">收货地址</div>
<template #label>
<span v-if="!item.receiveAddress">请选择地址</span>
<span v-else>{{item.receiveAddress}}</span>
</template>
</van-cell>
</div>
<!--收货门店-->
<div v-if="item.goodsProvideMode==='GOODS_PROVIDE_MODE_SHOP'">
<van-cell @click="goodsShopAddressClick(item,index)" class="confirmWelfareCell" is-link>
<van-icon class="van-cell__left-icon" color="red" name="info" slot="icon"></van-icon>
<div slot="title" style="font-weight: bold; font-size: 15px">收货门店</div>
<template #label>
<span v-if="!item.shopAddress">请选择收货门店</span>
<span v-else>{{item.shopAddress}}</span>
</template>
</van-cell>
</div>
</van-cell>
<!--电子签字-->
<van-cell v-if="viewData.signMode==='BENEFIT_SIGN_MODE_ONE'">
<van-icon class="van-cell__left-icon" color="red" name="info" slot="icon"></van-icon>
<div slot="title" style="font-weight: bold; font-size: 15px">电子签名</div>
<template #label>
<div>
<h5-signature v-model="formData.userSign"></h5-signature>
</div>
</template>
</van-cell>
<div style="padding: 10px 16px; left: 0; right: 0; bottom: 0; background: #ffffff">
<van-button @click="submit" round style="width: 100%" type="primary">提交</van-button>
</div>
</div>
</van-action-sheet>
<van-action-sheet :close-on-click-overlay="false" title="确认收货门店" v-model="shopAddressPopup">
<div style="position: relative; height: 500px; overflow-y: auto">
<van-cell :key="index" @click="shopAddressClick(item)" clickable icon="location-o"
v-for="(item,index) in goodsData.shopAddressList">
<template #title>{{item.name}}</template>
</van-cell>
</div>
</van-action-sheet>
<van-action-sheet :close-on-click-overlay="false" title="地址管理" v-model="editAddressPopup">
<benefit-address @address_click="addressClick" ref="address"></benefit-address>
</van-action-sheet>
</div>
<script nonce="${cspNonce!}">
<!--#include("../address/address.js"){}#-->
const vue = new Vue({
el: "#app",
store,
dicts: ["BENEFIT_FESTIVAL", "BENEFIT_SIGN_MODE", "BENEFIT_PROVIDE_MODE", "BENEFIT_GOODS_PROVIDE_MODE"],
data() {
return {
benefitId: GetQueryString("benefitId"),
benefitViews: [],
viewData: {
benefitGoodsList: []
},
description: "",
descPopup: false,
confirmPopup: false,
isChoice: false,
selectTime: false,
formData: {
benefitGoodsList: []
},
selectAddressPopup: false,
addressOptions: [],
goodsData: {},
goodsDataIndex: 0,
shopAddressPopup: false,
editAddressPopup: false,
userSelection: []
}
},
components: {
"benefit-address": ADDRESS
},
computed: {
sumSelectMoney() {
if (this.viewData && this.viewData.benefitGoodsList) {
let totalMoney = 0
const benefitGoodsList = this.viewData.benefitGoodsList.filter((b) => b.selectNum > 0)
benefitGoodsList.map((b) => {
totalMoney = totalMoney + b.selectNum * b.money
})
return totalMoney * 100
}
return 0
},
confirmButtonInfo() {
if (this.viewData) {
const {startChoiceTime, endChoiceTime, endOverdueChoiceTime} = this.viewData
const now = moment().valueOf()
if (endOverdueChoiceTime == null || endOverdueChoiceTime === "") {
if (now > moment(startChoiceTime).valueOf() && now < moment(endChoiceTime).valueOf()) {
return {
text: "提交商品",
disabled: false
}
} else if (now > moment(endChoiceTime).valueOf()) {
return {text: "选择已结束", disabled: true}
} else if (now < moment(startChoiceTime).valueOf()) {
return {text: "选择未开始", disabled: true}
}
} else {
//已选择了不能再动了
if (this.isChoice) {
if (moment(this.selectTime).valueOf() > moment(endChoiceTime).valueOf() && now < moment(endOverdueChoiceTime).valueOf()) {
return {text: "提交商品", disabled: false}
}
return {text: "选择已结束", disabled: true}
} else {
if (now > moment(startChoiceTime).valueOf() && now < moment(endOverdueChoiceTime).valueOf()) {
return {
text: "提交商品",
disabled: false
}
} else if (now > moment(endOverdueChoiceTime).valueOf()) {
return {text: "选择已结束", disabled: true}
} else if (now < moment(startChoiceTime).valueOf()) {
return {text: "选择未开始", disabled: true}
}
}
}
}
return {text: "", disabled: true}
}
},
methods: {
/**
*如果福利项目发放形式是统一发放true
* @returns {boolean}
*/
getBenefitProvideMode() {
console.log(this.viewData.provideMode === "BENEFIT_PROVIDE_MODE_ONE")
return this.viewData.provideMode === "BENEFIT_PROVIDE_MODE_ONE"
},
/**
* 查询单个福利
* @param id
* @returns {Promise<*>}
*/
async findOneBenefit() {
const res = await this.$axios.post("/platform/benefit/userSelection/findOneBenefit", {id: this.benefitId})
if (res.code === 0) {
this.viewData = res.data
}
},
//查看详情
openViewDesc(description) {
if (description == null || description.length === 0) {
this.$toast("没有更多了")
return
}
this.description = description
this.descPopup = true
},
descImgClick(e) {
if (e.target.tagName === "IMG") {
vant.ImagePreview([e.target.src])
}
},
async openSubmit() {
let totalMoney = 0
const benefitGoodsList = this.viewData.benefitGoodsList.filter((b) => b.selectNum > 0)
benefitGoodsList.map((b) => {
totalMoney = totalMoney + b.selectNum * b.money
})
if (totalMoney === 0) {
this.$toast("请选择后再提交!")
return
}
if (totalMoney !== this.viewData.totalMoney) {
this.$toast("本次福利积分【" + this.viewData.totalMoney + "】请检查商品数量!")
return
}
this.formData.benefitGoodsList = benefitGoodsList
this.formData.benefitGoodsList.forEach((b) => {
if (b.goodsProvideMode === "GOODS_PROVIDE_MODE_POST" && !b.receiveAddress) {
//如果是邮寄商品,并且有默认地址,并且是第一次进来没有选择,则默认地址为收货地址
const defaultAddress = this.addressOptions.find((a) => a.isDefault)
b.receiveAddress = defaultAddress.name
if (b.postProvideConfig.choiceMunicipality || b.postProvideConfig.choiceProvince) {
//如果有地址限制
b.receiveAddress = ""
}
}
})
this.confirmPopup = true
},
submit() {
if (this.viewData.signMode === "BENEFIT_SIGN_MODE_ONE" && !this.formData.userSign) {
this.$toast("请签字后再提交!")
return
}
let flag = false
let msg = ""
this.formData.benefitGoodsList.some((b) => {
if (b.goodsProvideMode === "GOODS_PROVIDE_MODE_POST" && !b.receiveAddress) {
flag = true
msg = "商品中存在未填写的收货地址,请检查!"
return true
}
if (b.benefitGoodsSpecificationsList && b.benefitGoodsSpecificationsList.length > 0 && !b.specificationsId) {
flag = true
msg = "商品中存在未填写的规格,请检查!"
return true
}
if (b.shopAddressList && b.shopAddressList.length > 0 && !b.shopAddress) {
flag = true
msg = "商品中存在未填写的门店地址,请检查!"
return true
}
return false
})
if (flag) {
this.$toast(msg)
return
}
const loading = this.$toast.loading({
message: "提交中...",
forbidClick: true,
overlay: true,
duration: 0
})
const benefitUserSelection = this.formData.benefitGoodsList.map((b) => {
let data = {
specificationsId: b.specificationsId,
receiveAddress: b.receiveAddress,
shopAddress: b.shopAddress,
selectNum: b.selectNum,
benefitId: this.viewData.id,
goodsId: b.id,
selectUserId: b.selectUserId,
userSign: this.formData.userSign
}
return data
})
this.$axios
.post("/platform/benefit/userSelection/submit", {
benefitUserSelection: JSON.stringify(benefitUserSelection),
benefitId: this.viewData.id,
userId: this.$store.state.user.id
})
.then((res) => {
if (res.code === 0) {
setTimeout(() => {
this.selectSelectionBenefit()
this.$toast.success(res.msg)
loading.close()
this.confirmPopup = false
}, 500)
} else {
this.$toast.fail(res.msg)
loading.close()
}
})
},
/**
*查询用户选择的商品
* @param benefitId
* @param userId
* @returns {Promise<void>}
*/
async selectSelectionBenefit() {
const res = await this.$axios.post("/platform/benefit/userSelection/selectSelectionBenefit", {
benefitId: this.benefitId,
userId: this.$store.state.user.id
})
if (res.code === 0) {
this.userSelection = res.data
}
},
addressClick(item) {
const address = this.addressOptions.find((a) => a.id === item.id)
const {province, city, county, name, tel} = address
if (this.goodsData.postProvideConfig.choiceMunicipality && city !== this.goodsData.postProvideConfig.choiceMunicipality) {
this.$toast("当前福利限制只能邮寄" + this.goodsData.postProvideConfig.choiceMunicipality + "")
return
}
if (this.goodsData.postProvideConfig.choiceProvince && province !== this.goodsData.postProvideConfig.choiceProvince) {
this.$toast("当前福利限制只能邮寄" + this.goodsData.postProvideConfig.choiceProvince + "")
return
}
if (address) {
this.$set(this.formData.benefitGoodsList[this.goodsDataIndex], "receiveAddress", address.name)
}
this.editAddressPopup = false
},
goodsAddressClick(goods, index) {
this.goodsData = goods
this.goodsDataIndex = index
this.editAddressPopup = true
},
goodsShopAddressClick(goods, index) {
this.goodsData = goods
this.goodsDataIndex = index
this.shopAddressPopup = true
},
shopAddressClick(item) {
if (item) {
this.$set(this.formData.benefitGoodsList[this.goodsDataIndex], "shopAddress", item.name)
}
this.shopAddressPopup = false
},
/**
* 回显用户选择的数据
* @param benefitId
* @param userId
* @returns {Promise<void>}
*/
async echoUserSelection() {
await this.selectSelectionBenefit()
//获取用户当前选择的数量
this.viewData.benefitGoodsList.map((v) => {
const goods = this.userSelection.find((x) => x.goodsId === v.id)
if (goods) {
v.selectNum = goods.selectNum
v.selectUserId = goods.selectUserId
v.receiveAddress = goods.receiveAddress
v.specificationsId = goods.specificationsId
v.shopAddress = goods.shopAddress
this.formData.userSign = goods.userSign
} else {
v.selectNum = 0
}
})
},
specificationsClick(item, index) {
this.$set(this.viewData.benefitGoodsList[index], "specificationsId", item.specificationsId)
this.$refs["radio" + item.id][0].toggle()
this.$forceUpdate()
}
},
async created() {
await this.findOneBenefit()
await this.echoUserSelection()
if (this.viewData.signMode === "BENEFIT_SIGN_MODE_ONE" && this.viewData.provideMode === "BENEFIT_PROVIDE_MODE_ONE") {
this.benefitViews = ["1"]
}
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,94 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.table-card .van-image__img {
border-radius: 5%;
}
.benefitName {
font-weight: bold;
font-size: 17px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
<div id="app" v-cloak>
<van-sticky>
<van-nav-bar @click-left="()=>this.$pjaxReplace('/platform/h5/home')" left-arrow left-text="返回" placeholder title="选择福利"></van-nav-bar>
<van-dropdown-menu>
<year-van-dropdown-item :num="5" @change="doSearch" v-model="pageForm.year"></year-van-dropdown-item>
</van-dropdown-menu>
</van-sticky>
<div>
<van-list :finished="finished" @load="pageData" finished-text="没有更多了" v-if="tableData.length>0" v-model="loading">
<div class="table-list">
<div :key="row.id" @click="openChoose(row)" class="table-card" v-for="row in tableData">
<van-image :src="row.cover" fit="cover" height="200" width="100%"></van-image>
<div style="margin: 10px">
<div class="benefitName">{{row.benefitName}}</div>
<div style="font-size: 15px">选择开始时间:{{$moment(row.startChoiceTime).format('YYYY-MM-DD HH:mm')}}</div>
<div style="font-size: 15px">选择结束时间:{{$moment(row.endChoiceTime).format('YYYY-MM-DD HH:mm')}}</div>
<div style="display: flex; justify-content: flex-end">{{row.isChoice?'已选择':'未选择'}}</div>
</div>
</div>
</div>
</van-list>
<van-empty description="暂无数据" image="/assets/platform/plugins/vant-green/images/nodata/nodata.png" v-else></van-empty>
</div>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
data() {
return {
tableData: [],
finished: false,
loading: false,
pageForm: {
pageNumber: 1,
pageSize: 5,
totalCount: 0,
year: new Date().getFullYear()
},
yearList: []
}
},
methods: {
doSearch() {
this.tableKey = new Date().getTime()
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.tableData = []
this.pageData()
},
pageData() {
this.loading = true
this.$axios.post("/platform/benefit/userSelection/pageData", this.pageForm).then((res) => {
this.tableData = this.tableData.concat(res.data.list)
if (this.tableData.length === res.data.totalCount) {
this.finished = true
} else {
this.pageForm.pageNumber++
}
this.pageForm.totalCount = res.data.totalCount
this.loading = false
})
},
async openChoose(row) {
this.$pjaxReplace("/platform/h5/benefit/userSelection/goodsSelection?benefitId=" + row.benefitId)
}
},
created() {
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,217 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.table-card .van-image__img {
border-radius: 5%;
}
.benefitName {
font-weight: bold;
font-size: 17px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.collapse .van-cell__left-icon {
color: red;
}
</style>
<div id="app" v-cloak>
<van-sticky>
<van-nav-bar @click-left="()=>this.$pjaxReplace('/platform/h5/home')" left-arrow left-text="返回" placeholder title="选择福利"></van-nav-bar>
<van-dropdown-menu>
<year-van-dropdown-item :num="5" @change="doSearch" v-model="pageForm.year"></year-van-dropdown-item>
</van-dropdown-menu>
</van-sticky>
<div>
<van-list :finished="finished" @load="pageData" finished-text="没有更多了" v-if="tableData.length>0" v-model="loading">
<div class="table-list">
<div :key="row.id" class="table-card" v-for="row in tableData">
<van-image :src="row.cover" fit="cover" height="200" width="100%"></van-image>
<div style="margin: 10px">
<div class="benefitName">{{row.benefitName}}</div>
<div style="font-size: 15px">选择开始时间:{{$moment(row.startChoiceTime).format('YYYY-MM-DD HH:mm')}}</div>
<div style="font-size: 15px">选择结束时间:{{$moment(row.endChoiceTime).format('YYYY-MM-DD HH:mm')}}</div>
<div style="display: flex; justify-content: flex-end">{{row.isChoice?'已选择':'未选择'}}</div>
<div class="van-hairline--bottom"></div>
</div>
<div style="display: flex; justify-content: flex-end; margin-top: 10px">
<van-button @click="openView(row.benefitId)" round size="small" type="primary">查看详情</van-button>
</div>
</div>
</div>
</van-list>
<van-empty description="暂无数据" image="/assets/platform/plugins/vant-green/images/nodata/nodata.png" v-else></van-empty>
</div>
<van-action-sheet title="查看详情" v-model="descPopup">
<van-collapse class="collapse" v-model="benefitViews">
<van-collapse-item icon="star" name="1" title="福利信息">
<div>
<van-cell-group>
<van-cell :value="viewData.name" title="福利名称"></van-cell>
<van-cell title="是否电子签字">
<dict-tag :options="dict.type.BENEFIT_SIGN_MODE" :value="viewData.signMode"></dict-tag>
</van-cell>
<van-cell title="发放形式">
<dict-tag :options="dict.type.BENEFIT_PROVIDE_MODE" :value="viewData.provideMode"></dict-tag>
</van-cell>
<van-cell title="选择开始时间" v-if="viewData.provideMode==='BENEFIT_PROVIDE_MODE_TWO'">
{{$moment(viewData.startChoiceTime).format("YYYY-MM-DD HH:mm")}}
</van-cell>
<van-cell title="选择结束时间" v-if="viewData.provideMode==='BENEFIT_PROVIDE_MODE_TWO'">
{{$moment(viewData.endChoiceTime).format("YYYY-MM-DD HH:mm")}}
</van-cell>
<van-cell title="逾期选择时间" v-if="viewData.provideMode==='BENEFIT_PROVIDE_MODE_TWO'">
<span v-if="viewData.endOverdueChoiceTime">{{ $moment(viewData.endOverdueChoiceTime).format("YYYY-MM-DD HH:mm") }}</span>
<span v-else>暂无</span>
</van-cell>
<van-cell title="福利总积分" v-if="viewData.provideMode==='BENEFIT_PROVIDE_MODE_TWO'">{{viewData.totalMoney}}</van-cell>
<van-cell title="福利名称" v-if="viewData.provideMode==='BENEFIT_PROVIDE_MODE_ONE'">{{viewData.giftName}}</van-cell>
</van-cell-group>
</div>
</van-collapse-item>
</van-collapse>
<div class="van-cell-group--inset">
<div v-if="userSelection&&userSelection.length>0">
<van-cell>
<template #title>
<div style="font-weight: bold; font-size: 15px">已选福利</div>
</template>
</van-cell>
<div :key="item.id" v-for="item in userSelection">
<van-card
:num="item.selectNum"
:thumb="item.goods.imgUrl[0].url"
style="border-radius: 8px; background: #ffffff"
v-if="item.goods"
>
<template #title>
<div style="font-weight: bold; font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{{item.goods.name}}
</div>
</template>
<template #desc>
<div>{{item.goods.simpleDesc}}</div>
</template>
</van-card>
<div style="margin: 5px 20px 5px 20px">
<div v-if="item.specificationsName">所选规格:{{item.specificationsName}}</div>
<div class="van-hairline--bottom"></div>
<div v-if="item.receiveAddress">{{item.receiveAddress}}</div>
<div class="van-hairline--bottom"></div>
<div v-if="item.shopAddress">收货门店:{{item.shopAddress}}</div>
</div>
</div>
</div>
<van-cell>
<template #title>
<div style="font-weight: bold; font-size: 15px">电子签名</div>
</template>
</van-cell>
<van-cell title="">
<template #label>
<van-image :src="userSign" style="width: 100%; height: 150px; border: 1px dashed"></van-image>
</template>
</van-cell>
</div>
</van-action-sheet>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
store,
dicts: ["BENEFIT_FESTIVAL", "BENEFIT_SIGN_MODE", "BENEFIT_PROVIDE_MODE", "BENEFIT_GOODS_PROVIDE_MODE"],
data() {
return {
tableData: [],
finished: false,
loading: false,
pageForm: {
pageNumber: 1,
pageSize: 5,
totalCount: 0,
year: new Date().getFullYear()
},
yearList: [],
descPopup: false,
benefitViews: [],
viewData: {},
userSelection: [],
userSign: ""
}
},
methods: {
doSearch() {
this.tableKey = new Date().getTime()
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.tableData = []
this.pageData()
},
pageData() {
this.loading = true
this.$axios.post("/platform/benefit/userSelection/mine/pageData", this.pageForm).then((res) => {
this.tableData = this.tableData.concat(res.data.list)
if (this.tableData.length === res.data.totalCount) {
this.finished = true
} else {
this.pageForm.pageNumber++
}
this.pageForm.totalCount = res.data.totalCount
this.loading = false
})
},
async findOneBenefit(id) {
const res = await this.$axios.post("/platform/benefit/userSelection/findOneBenefit", { id })
if (res.code === 0) {
this.viewData = res.data
}
},
async selectSelectionBenefit(benefitId) {
const res = await this.$axios.post("/platform/benefit/userSelection/selectSelectionBenefit", { benefitId })
if (res.code === 0) {
this.userSelection = res.data
}
},
async getUserSelectionSign(benefitId) {
const res = await this.$axios.post("/platform/h5/benefit/userSelection/getUserSelectionSign", { benefitId })
if (res.code === 0) {
this.userSign = res.data.userSign
}
},
async openView(id) {
await this.findOneBenefit(id)
if (this.viewData.provideMode === "BENEFIT_PROVIDE_MODE_ONE") {
this.benefitViews = ["1"]
this.userSelection = []
await this.getUserSelectionSign(id)
} else {
this.benefitViews = []
await this.selectSelectionBenefit(id)
this.userSelection.map((v) => {
const data = this.viewData.benefitGoodsList.find((b) => b.id === v.goodsId)
v.goods = data
if (v.specificationsId) {
const specifications = data.benefitGoodsSpecificationsList.find((x) => x.id === v.specificationsId)
v.specificationsName = specifications.name
}
this.userSign = v.userSign
})
}
this.descPopup = true
}
},
created() {
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,292 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
/* 同意条款样式 */
.agree-section {
padding: 16px;
background-color: #fff;
border-radius: 12px;
margin-top: 16px;
}
.agree-section .van-checkbox__label {
font-size: 13px;
line-height: 1.5;
color: #666;
}
</style>
<div id="app">
<!-- 导航栏 -->
<van-nav-bar title="文体协会会员申请" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
<!-- 表单容器 -->
<van-form ref="formRef" class="form-container">
<!-- 协会信息 -->
<van-cell-group title="协会信息" class="form-section">
<van-field
:rules="[{ required: true }]"
v-model="formData.clubName"
label="协会"
placeholder="请选择协会"
required
is-link
readonly
name="clubName"
@click="showClubPopup = true"
></van-field>
<van-popup v-model:show="showClubPopup" position="bottom">
<van-picker
show-toolbar
:columns="clubOptions.map(i => i.clubName)"
@confirm="onClubConfirm"
@cancel="showClubPopup = false"
class="picker-style"
></van-picker>
</van-popup>
</van-cell-group>
<!-- 基本信息 -->
<van-cell-group title="基本信息" class="form-section">
<van-field label="姓名" :rules="[{ required: true }]" v-model="formData.userName" readonly
required name="userName"></van-field>
<van-field label="工号" :rules="[{ required: true }]" v-model="formData.loginName" readonly
required name="loginName"></van-field>
<van-field label="性别" :rules="[{ required: true }]" v-model="formData.sex" readonly required></van-field>
<van-field label="出生年月" v-model="formData.birthday" readonly placeholder="读取信息中心数据"></van-field>
<van-field label="联系电话" v-model="formData.mobile" placeholder="请输入联系电话"></van-field>
<van-field label="电子信箱" v-model="formData.email" placeholder="请输入电子信箱"></van-field>
</van-cell-group>
<!-- 工作信息 -->
<van-cell-group title="工作信息" class="form-section">
<van-field label="分工会" v-model="formData.unionName" readonly></van-field>
<van-field label="部门" v-model="formData.unitName" readonly></van-field>
<van-field label="职务" v-model="formData.governmentPosition" readonly
placeholder="读取信息中心数据"></van-field>
<van-field label="职称" v-model="formData.technicalTitle" readonly
placeholder="读取信息中心数据"></van-field>
<van-field label="学历" v-model="formData.education" readonly placeholder="读取信息中心数据"></van-field>
<van-field label="学位" v-model="formData.academicDegree" readonly
placeholder="读取信息中心数据"></van-field>
</van-cell-group>
<!-- 其他信息 -->
<van-cell-group title="其他信息" class="form-section">
<van-field
class="direction-column-field"
v-model="formData.sameTimeJoinOtherClubSituation"
label="同时参加其他协会情况"
type="textarea"
rows="4"
autosize
placeholder="请填写同时参加其他协会情况"
></van-field>
<van-field
class="direction-column-field"
v-model="formData.awardsExperience"
label="文化、体育方面的活动经历、获奖情况"
type="textarea"
rows="4"
autosize
placeholder="请填写相关经历及获奖情况"
></van-field>
</van-cell-group>
<!-- 照片上传 -->
<van-cell-group title="照片" class="form-section">
<van-field class="direction-column-field" name="avatar" label="">
<template #input>
<h5-file-upload
slot="input"
:value.sync="formData.avatar"
:upload_number="1"
upload_mode="image"
upload_result_category="interval"
upload_result_type="url"
complete_result
></h5-file-upload>
</template>
</van-field>
</van-cell-group>
<!-- 电子签名 -->
<van-cell-group title="电子签名" class="form-section">
<van-field class="direction-column-field" name="signature" label="">
<template #input>
<h5-signature v-model="formData.signature" slot="input"></h5-signature>
</template>
</van-field>
</van-cell-group>
<!-- 同意条款 -->
<van-cell-group class="agree-section form-section">
<van-checkbox v-model="isAgree" shape="square">
注:本人已仔细阅读并愿意遵守所参加本校教职工文体协会的章程和规定,自愿加入所报名协会。
</van-checkbox>
</van-cell-group>
<!-- 提交按钮 -->
<div class="form-actions">
<van-button native-type="button" @click="onSave" round type="info" plain>保存申请</van-button>
<van-button @click="onSubmit" round type="info" v-if="!taskId">提交申请</van-button>
<van-button @click="onFinishTask" round type="info" v-else>提交申请</van-button>
</div>
</van-form>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
store,
components: {},
data() {
return {
bizId: GetQueryString("bizId"),
taskId: GetQueryString("taskId"),
formData: {
clubId: "",
clubName: "",
userName: "",
loginName: "",
sex: "",
birthday: "",
mobile: "",
email: "",
unionName: "",
unitName: "",
governmentPosition: "",
technicalTitle: "",
education: "",
academicDegree: "",
sameTimeJoinOtherClubSituation: "",
awardsExperience: "",
avatar: [],
signature: ""
},
clubOptions: [],
showClubPopup: false,
isAgree: false
}
},
methods: {
onSave() {
this.$dialog.confirm({
title: "提示",
message: "您确定保存吗?"
}).then(() => {
this.$axios.post("/platform/club/join/apply/save", { data: JSON.stringify(this.formData) }).then(res => {
if (res.code === 0) {
this.$toast(res.msg)
this.$pjaxReplace("/platform/club/join/mine/h5")
}
})
})
},
async onSubmit() {
this.$refs.formRef.validate().then(() => {
if (!this.isAgree) {
this.$toast('请先阅读并同意协议')
return
}
this.$dialog.confirm({
title: "提示",
message: "您确定要提交申请吗?"
}).then(() => {
this.$axios.post("/platform/club/join/apply/submit", this.formData).then(res => {
if (res.code === 0) {
this.$toast(res.msg)
this.$pjaxReplace("/platform/club/join/mine/h5")
}
})
})
})
},
async onFinishTask() {
this.$refs.formRef.validate().then(() => {
if (!this.isAgree) {
this.$toast('请先阅读并同意协议')
return
}
this.$dialog.confirm({
title: "提示",
message: "您确定要提交申请吗?"
}).then(() => {
this.$axios.post("/platform/club/join/apply/submitAgain", {
data: JSON.stringify(this.formData),
taskId: GetQueryString("taskId")
}).then(res => {
if (res.code === 0) {
this.$toast(res.msg)
this.$pjaxReplace("/platform/club/join/mine/h5")
}
})
})
})
},
checkApplyClub(clubId) {
this.$axios.post("/platform/club/join/apply/checkApplyClub", { clubId }).then(res => {
if (res.code !== 0) {
this.$toast(res.msg)
this.formData.clubId = ""
this.formData.clubName = ""
}
})
},
onClubConfirm(value, index) {
this.formData.clubId = this.clubOptions[index].id
this.formData.clubName = value
this.showClubPopup = false
// 检查是否已申请该协会
this.checkApplyClub(this.formData.clubId)
},
listClub() {
this.$axios.post("/platform/club/common/listClub").then(res => {
if (res.code === 0) {
this.clubOptions = res.data
}
})
},
init() {
this.bizId = GetQueryString("bizId")
if (this.bizId) {
this.$axios.post("/platform/club/join/apply/info", { id: this.bizId }).then((res) => {
if (res.code === 0) {
this.formData = res.data
this.isAgree = true
}
})
} else {
const user = this.$store.state.user
this.$set(this.formData, "userId", user.id)
this.$set(this.formData, "userName", user.username)
this.$set(this.formData, "loginName", user.loginname)
this.$set(this.formData, "unitId", user.unit ? user.unit.id : null)
this.$set(this.formData, "unitName", user.unit ? user.unit.name : null)
this.$set(this.formData, "unionId", user.union ? user.union.id : null)
this.$set(this.formData, "unionName", user.union ? user.union.name : null)
this.$set(this.formData, "sex", user.sex)
this.$set(this.formData, "birthday", user.birthday ? this.$moment(user.birthday).format('YYYY-MM-DD') : '')
this.$set(this.formData, "nation", user.nation)
this.$set(this.formData, "mobile", user.mobile)
this.$set(this.formData, "political", user.political)
this.$set(this.formData, "education", user.education)
this.$set(this.formData, "technicalTitle", user.technicalTitle)
this.$set(this.formData, "position", user.position)
this.$set(this.formData, "academicDegree", user.academicDegree)
}
}
},
created() {
this.listClub()
this.init()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,185 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
</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-search
v-model="pageForm.searchKeyword"
:show-action="false"
:reverse-color="false"
input-align="left"
placeholder="请输入姓名或者工号搜索"
@search="doSearch"
></van-search>
<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.unionId" :options="unionOptions" :multiple="false"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.approval = val==='1';this.doSearch();}">
<van-tab title="已审核" name="1"></van-tab>
<van-tab title="未审核" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/club/join/clubApproval/pageData" :page_form.sync="pageForm" ref="tableListRef" title="clubName" @ready="onReady">
<template v-slot="{index,row}">
<table-column label="姓名">{{row.userName}}</table-column>
<table-column label="工号">{{row.loginName}}</table-column>
<table-column label="申请模式">{{row.mode ? '加入' : '退出'}}</table-column>
<table-column label="申请时间">{{row.applyDate}}</table-column>
<table-column label="当前节点">{{row.curTaskName}}</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" v-if="row.taskState === 10" @click="onApproval(row)">
<i class="fa fa-edit"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-reply"></i>
<span>撤回</span>
</div>
</template>
</table-list>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">{{formData.taskName}}</div>
<van-form ref="formRef">
<van-field
v-model="formData.tf_opinion"
name="tf_opinion"
label="审批意见"
placeholder="请输入审批意见"
:rules="[{ required: true, message: '请填写审批意见' }]"
required
maxlength="100"
show-word-limit
></van-field>
</van-form>
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button type="danger" block @click="handleTaskAction(6)">退回</van-button>
<van-button type="danger" block @click="handleTaskAction(20)">不同意</van-button>
<van-button type="primary" block @click="handleTaskAction(1)">同意</van-button>
</div>
</div>
</info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../common/clubUserJoin.js'){}#-->
new Vue({
el: "#app",
store,
components: {
info: clubUserJoin
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: '',
name: null,
approvalText: "0",
approval: false,
year: new Date().getFullYear(),
unionId: null,
},
unionOptions: [],
formData: {},
showApprovalForm: false
}
},
methods: {
async onReady() {
const unionList = await this.$businessTool.listUnion()
this.unionOptions = [
{
text: "全部工会",
value: null
}
].concat(unionList.map((v) => ({ text: v.name, value: v.id })))
if (this.unionOptions.length > 0) {
this.pageForm.unionId = this.unionOptions[0].value
this.doSearch()
}
},
onView(row) {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
},
onApproval(row) {
this.showApprovalForm = true
this.$refs.infoRef.onOpen(row)
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
},
async handleTaskAction(val) {
try {
await this.$refs.formRef.validate();
this.$dialog.confirm({
title: "提示",
message: "您确定要提交吗?"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.infoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
}
})
}).catch(() => {
})
} catch (error) {
}
},
onRevoke(row){
this.$dialog.confirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
}
})
})
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
},
})
</script>
<!--#
}
#-->
@@ -0,0 +1,102 @@
const clubUserJoin = {
template:
/*language=HTML*/
`
<van-action-sheet v-model="visible" title="查看详情">
<div class="detail-container">
<van-cell-group title="基本信息">
<van-cell title="协会名称">{{ viewData.clubName }}</van-cell>
<van-cell title="姓名">{{ viewData.userName }}</van-cell>
<van-cell title="工号">{{ viewData.loginName }}</van-cell>
<van-cell title="性别">{{ viewData.sex }}</van-cell>
<van-cell title="出生年月">{{ viewData.birthday }}</van-cell>
<van-cell title="联系电话">{{ viewData.mobile }}</van-cell>
<van-cell title="电子信箱">{{ viewData.email }}</van-cell>
<van-cell title="分工会">{{ viewData.unionName }}</van-cell>
<van-cell title="部门">{{ viewData.unitName }}</van-cell>
<van-cell title="职务">{{ viewData.governmentPosition }}</van-cell>
<van-cell title="职称">{{ viewData.technicalTitle }}</van-cell>
<van-cell title="学历">{{ viewData.education }}</van-cell>
<van-cell title="学位">{{ viewData.academicDegree }}</van-cell>
<van-cell class="direction-column-cell" title="同时参加其他协会情况">
{{ viewData.sameTimeJoinOtherClubSituation || '暂无' }}
</van-cell>
<van-cell class="direction-column-cell" title="文化、体育方面的活动经历、获奖情况">
{{ viewData.awardsExperience || '暂无' }}
</van-cell>
<van-cell class="direction-column-cell" title="照片">
<template slot="default">
<van-image :src="viewData.avatar"></van-image>
</template>
</van-cell>
<van-cell title="签字" >
<van-image :src="viewData.signature"
v-if="viewData.signature"
class="signature-image"></van-image>
</van-cell>
</van-cell-group>
<template v-for="task in doneTasks">
<van-cell-group :title="task.displayName" v-if="task.ext.isFirstTaskNode">
<van-cell title="申请用户">{{ task.ext.initiatorName }}({{task.ext.initiatorAccount}})
</van-cell>
<van-cell title="申请时间">{{ task.finishTime }}</van-cell>
<van-cell title="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag>
</van-cell>
</van-cell-group>
<van-cell-group :title="task.displayName" v-else>
<van-cell title="办理用户">{{ task.taskFormData.userName }}({{task.taskFormData.loginName}})
</van-cell>
<van-cell title="办理时间">{{ task.finishTime }}</van-cell>
<van-cell title="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag>
</van-cell>
<van-cell title="办理意见" v-if="!task.ext.isFirstTaskNode" class="direction-column-cell">
<div v-html="task.taskFormData.tf_opinion"></div>
</van-cell>
</van-cell-group>
</template>
</div>
<slot></slot>
</van-action-sheet>
`,
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
visible:false,
viewData: {},
doneTasks: [],
row: null,
}
},
methods: {
onOpen(row) {
this.row = row
this.visible = true
this.getInfo()
this.getDoneTasks()
},
onClose(){
this.visible = false
},
getInfo() {
this.$axios.post("/platform/club/join/mine/info", { id: this.row.id }).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
getDoneTasks() {
this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data
}
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,122 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
.van-cell__value {
min-width: 70%;
}
</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-menu>
</van-sticky>
<table-list api="/platform/club/join/mine/pageData" :page_form.sync="pageForm" ref="tableListRef" title="clubName" @ready="doSearch">
<template v-slot="{index,row}">
<table-column label="姓名">{{row.userName}}</table-column>
<table-column label="工号">{{row.loginName}}</table-column>
<table-column label="申请模式">{{row.mode ? '加入' : '退出'}}</table-column>
<table-column label="申请时间">{{row.applyDate}}</table-column>
<table-column label="当前节点">{{row.taskName}}</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="onEdit(row)"
v-if="row.taskKey === 'startTask' || !row.instanceId">
<i class="fa fa-edit"></i>
<span>编辑</span>
</div>
<div class="action-btn delete" @click="onRevoke(row)"
v-if="row.canRevoke">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
<div class="action-btn delete" @click="onDelete(row)"
v-if="row.taskKey === 'startTask' || !row.instanceId">
<i class="fa fa-trash"></i>
<span>删除</span>
</div>
</template>
</table-list>
<info ref="infoRef"></info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../common/clubUserJoin.js'){}#-->
new Vue({
el: "#app",
store,
components: {
info: clubUserJoin
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
year: new Date().getFullYear()
},
}
},
methods: {
onRevoke(row) {
this.$dialog.confirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", { taskId: row.startTaskId }).then((res) => {
if (res.code === 0) {
this.$toast(res.msg)
this.doSearch()
}
})
})
},
onView(row) {
this.$refs.infoRef.onOpen(row)
},
onEdit(row) {
this.$pjaxReplace("/platform/club/join/apply/h5?taskId=" + (row.startTaskId || "") + "&bizId=" + row.id)
},
onDelete(row) {
this.$dialog.confirm({
title: "提示",
message: "确定要删除此申请吗?"
})
.then(() => {
this.$axios.post("/platform/club/join/mine/delete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
} else {
this.$toast.fail(res.msg)
}
})
})
.catch(() => {})
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
},
})
</script>
<!--#
}
#-->
@@ -0,0 +1,185 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
</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-search
v-model="pageForm.searchKeyword"
:show-action="false"
:reverse-color="false"
input-align="left"
placeholder="请输入姓名或者工号搜索"
@search="doSearch"
></van-search>
<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.unionId" :options="unionOptions" :multiple="false"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.approval = val==='1';this.doSearch();}">
<van-tab title="已审核" name="1"></van-tab>
<van-tab title="未审核" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/club/join/schoolUnionApproval/pageData" :page_form.sync="pageForm" ref="tableListRef" title="clubName" @ready="onReady">
<template v-slot="{index,row}">
<table-column label="姓名">{{row.userName}}</table-column>
<table-column label="工号">{{row.loginName}}</table-column>
<table-column label="申请模式">{{row.mode ? '加入' : '退出'}}</table-column>
<table-column label="申请时间">{{row.applyDate}}</table-column>
<table-column label="当前节点">{{row.curTaskName}}</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" v-if="row.taskState === 10" @click="onApproval(row)">
<i class="fa fa-edit"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-reply"></i>
<span>撤回</span>
</div>
</template>
</table-list>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">{{formData.taskName}}</div>
<van-form ref="formRef">
<van-field
v-model="formData.tf_opinion"
name="tf_opinion"
label="审批意见"
placeholder="请输入审批意见"
:rules="[{ required: true, message: '请填写审批意见' }]"
required
maxlength="100"
show-word-limit
></van-field>
</van-form>
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button type="danger" block @click="handleTaskAction(6)">退回</van-button>
<van-button type="danger" block @click="handleTaskAction(20)">不同意</van-button>
<van-button type="primary" block @click="handleTaskAction(1)">同意</van-button>
</div>
</div>
</info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../common/clubUserJoin.js'){}#-->
new Vue({
el: "#app",
store,
components: {
info: clubUserJoin
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: '',
name: null,
approvalText: "0",
approval: false,
year: new Date().getFullYear(),
unionId: null,
},
unionOptions: [],
formData: {},
showApprovalForm: false
}
},
methods: {
async onReady() {
const unionList = await this.$businessTool.listUnion()
this.unionOptions = [
{
text: "全部工会",
value: null
}
].concat(unionList.map((v) => ({ text: v.name, value: v.id })))
if (this.unionOptions.length > 0) {
this.pageForm.unionId = this.unionOptions[0].value
this.doSearch()
}
},
onView(row) {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
},
onApproval(row) {
this.showApprovalForm = true
this.$refs.infoRef.onOpen(row)
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
},
async handleTaskAction(val) {
try {
await this.$refs.formRef.validate();
this.$dialog.confirm({
title: "提示",
message: "您确定要提交吗?"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.infoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
}
})
}).catch(() => {
})
} catch (error) {
}
},
onRevoke(row){
this.$dialog.confirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
}
})
})
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
},
})
</script>
<!--#
}
#-->
@@ -0,0 +1,168 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<!-- 导航栏 -->
<van-nav-bar title="资产盘点" left-text="返回" left-arrow placeholder
@click-left="historyBack" fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-search
:reverse-color="false"
:show-action="false"
@search="doSearch"
input-align="left"
placeholder="请输入编号或名称搜索"
v-model="pageForm.searchKeyword"
></van-search>
<van-tabs v-model="pageForm.isStocktakingText"
@change="(val)=>{this.pageForm.isStocktaking = val==='1';this.doSearch();}">
<van-tab title="已盘点" name="1"></van-tab>
<van-tab title="未盘点" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/asset/stocktaking/pageData" :page_form.sync="pageForm"
ref="tableListRef"
title="assetNumber" @ready="onReady">
<template v-slot="{index,row}">
<table-column label="资产名称">{{row.assetName}}</table-column>
<table-column label="类别名称"> {{row.assetTypeCode===1?'校工会资产':'分工会资产'}}</table-column>
<table-column label="存放地点">{{row.assetStorageLocation}}</table-column>
<table-column label="责任人">{{row.assetUseUserName}}</table-column>
<table-column label="折旧到期日期"> {{$moment(row.assetRetiredAssetsDate).format('YYYY-MM-DD')}}
</table-column>
<table-column label="使用状况">{{row.assetUsageStateName}}</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" v-if="!row.isStocktaking"
:disabled="stocktakingPlanOption.length==0
||!pageForm.assetStocktakingPlanId
||!stocktakingPlanOption.find(p=>p.id===pageForm.assetStocktakingPlanId).isShow"
@click="onAudit(row)">
<i class="fa fa-edit"></i>
<span>开始盘点</span>
</div>
<div class="action-btn delete" v-if="row.isStocktaking"
:disabled="stocktakingPlanOption.length==0
||!pageForm.assetStocktakingPlanId
||!stocktakingPlanOption.find(p=>p.id===pageForm.assetStocktakingPlanId).isShow"
@click="onRevoke(row)">
<i class="fa fa-undo"></i>
<span>删除盘点</span>
</div>
</template>
</table-list>
<h5-asset-info ref="h5AssetInfoRef"></h5-asset-info>
<h5-asset-stocktaking-form ref="h5AssetStocktakingFormRef" @save_success="doSearch"></h5-asset-stocktaking-form>
</div>
<script nonce="${cspNonce!}">
<!--#include("info.js"){}#-->
<!--#include("stocktakingForm.js"){}#-->
const vue = new Vue({
el: "#app",
store,
data() {
return {
assetCategoryOption: [],
stocktakingPlanOption: [],
unionList: [],
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
isStocktakingText: "0",
isStocktaking: false,
}
}
},
components: {
"h5-asset-info": H5_ASSET_INFO,
"h5-asset-stocktaking-form": H5_ASSET_STOCKTAKING_FORM,
},
methods: {
onRevoke(row) {
this.$dialog.confirm({
title: "提示",
message: "您确定要删除本次盘点信息吗?"
}).then(() => {
this.$axios.post("/platform/asset/stocktaking/doDelete", {
id: row.id,
assetStocktakingPlanId: this.pageForm.assetStocktakingPlanId
}).then(resp => {
if (resp.code === 0) {
this.doSearch()
this.$toast.success(resp.msg)
} else {
this.$toast.fail(resp.msg)
}
})
})
},
onAudit(row) {
row.assetStocktakingPlanId = this.pageForm.assetStocktakingPlanId
this.$refs.h5AssetStocktakingFormRef.onOpen(row)
},
onView(row) {
this.$refs.h5AssetInfoRef.onOpen(row)
},
// 查询资产类别
queryCategory() {
this.$axios.post("/platform/asset/category/queryCategory").then(resp => {
if (resp.code === 0) {
this.assetCategoryOption = resp.data
}
})
},
// 按年度查询资产盘点计划
async queryStocktakingPlan() {
const resp = await this.$axios.post("/platform/asset/stocktakingPlan/queryStocktakingPlan")
if (resp.code === 0) {
resp.data.forEach(v => {
const startDate = this.$moment(v.startDate).format('YYYY-MM-DD')
const endDate = this.$moment(v.endDate).format('YYYY-MM-DD')
v.name = startDate + "至" + endDate + "" + v.year + ""
v.isShow = (this.$moment().format('YYYY-MM-DD hh:mm:ss') > v.startDate && this.$moment().format('YYYY-MM-DD hh:mm:ss') < v.endDate)
})
this.stocktakingPlanOption = resp.data
if (this.stocktakingPlanOption && this.stocktakingPlanOption.length > 0) {
this.$set(this.pageForm, "assetStocktakingPlanId", this.stocktakingPlanOption[0].id)
} else {
this.$set(this.pageForm, "assetStocktakingPlanId", null)
}
this.doSearch()
}
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
onReady() {
this.queryCategory()
this.queryStocktakingPlan()
}
},
created() {
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,124 @@
const H5_ASSET_INFO = {
template: /*language=HTML*/ `
<van-action-sheet v-model="visible" title="查看详情" ref="actionSheetRef">
<van-tabs v-model="activeName">
<van-tab title="资产基本信息" name="1">
</van-tab>
<van-tab title="盘点信息" name="2">
</van-tab>
</van-tabs>
<div class="detail-container" v-if="activeName==='1'">
<van-cell-group>
<van-cell title="资产编号">
{{ viewData.assetNumber }}
</van-cell>
<van-cell title="资产名称">
{{ viewData.assetName }}
</van-cell>
<van-cell title="资产类别">
{{viewData.assetCategoryName}}{{viewData.assetDepreciationYear}}年)
</van-cell>
<van-cell title="资产规格型号">
{{viewData.assetSpecs}}
</van-cell>
<van-cell title="供应商名称">
{{viewData.assetSupplierName}}
</van-cell>
<van-cell title="采购方式">
{{viewData.assetFundingSubjectName}}
</van-cell>
<van-cell title="单价(元)">
{{viewData.assetUnitPrice}}
</van-cell>
<van-cell title="数量(台/件)">
{{viewData.assetQuantity}}
</van-cell>
<van-cell title="资产类型">
{{viewData.assetTypeCode===1?'校工会资产':'分工会资产'}}
</van-cell>
<van-cell title="开始使用日期">
{{$moment(viewData.assetUsedDate).format('YYYY-MM-DD')}}
</van-cell>
<van-cell title="预计报废时间">
{{$moment(viewData.assetRetiredAssetsDate).format('YYYY-MM-DD')}}
</van-cell>
<van-cell title="责任人">
{{viewData.assetUseUserName}}
</van-cell>
<van-cell title="使用/管理部门">
{{viewData.assetUseUnionName}}
</van-cell>
<van-cell title="存放地点">
{{viewData.assetStorageLocation}}
</van-cell>
<van-cell title="使用状况">
{{viewData.assetUsageStateName}}
</van-cell>
<van-cell title="备注" class="direction-column-cell">
<div style="white-space: pre">{{viewData.assetNotes}}</div>
</van-cell>
</van-cell-group>
</div>
<div class="detail-container" v-else-if="activeName==='2'">
<template v-for="item in viewData.assetStocktakingList"
v-if="viewData.assetStocktakingList&&viewData.assetStocktakingList.length>0">
<van-cell-group :title="$moment(item.createdAt).format('YYYY-MM-DD HH:mm:ss')">
<van-cell title="原责任人">
{{ item.oldAssetUseUserName }}
</van-cell>
<van-cell title="原使用/管理部门">
{{ item.oldAssetUseUnionName }}
</van-cell>
<van-cell title="原存放地点">
{{ item.oldAssetStorageLocation }}
</van-cell>
<van-cell title="原使用状况">
{{ item.oldAssetUsageStateName }}
</van-cell>
<!-- <van-cell title="操作时间">
{{$moment(item.createdAt).format('YYYY-MM-DD HH:mm:ss')}}
</van-cell>-->
<van-cell title="旧备注" class="direction-column-cell">
<div style="white-space: pre">{{item.oldAssetNotes}}</div>
</van-cell>
<van-cell title="旧资产图片" class="direction-column-cell">
<file-preview :files="item.oldAssetFiles" complete_result></file-preview>
</van-cell>
</van-cell-group>
</template>
<template v-if="viewData.assetStocktakingList&&viewData.assetStocktakingList.length===0">
<van-empty description="暂无数据" ></van-empty>
</template>
</div>
</van-action-sheet>
`,
data() {
return {
visible: false,
viewData: {},
row: null,
activeName: "1",
actionSheetRef: null
}
},
methods: {
// 打开
onOpen(row) {
this.activeName = "1"
this.row = row
this.visible = true
this.getInfo()
},
// 获取申请信息
getInfo() {
this.$axios.post('/platform/asset/manage/fondOneAsset', {id: this.row.id}).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
}
}
@@ -0,0 +1,192 @@
let H5_ASSET_STOCKTAKING_FORM = {
template: /*language=HTML*/ `
<van-action-sheet v-model="visible" title="盘点信息">
<div>
<div class="form-container">
<van-form ref="formRef">
<van-cell-group title="资产信息">
<van-field label="资产编号"
:rules="[{ required: true }]"
v-model="formData.assetNumber"
readonly
required></van-field>
<van-field label="资产名称"
:rules="[{ required: true }]"
v-model="formData.assetName"
readonly
required></van-field>
<van-field label="开始使用日期"
:rules="[{ required: true }]"
v-model="$moment(formData.assetUsedDate).format('YYYY-MM-DD')"
readonly
required></van-field>
<van-field label="存放地点"
:rules="[{ required: true }]"
v-model="formData.assetStorageLocation"
required
name="assetStorageLocation"
placeholder="请输入存放地点"></van-field>
<van-field
v-model="formData.assetUseName"
name="assetUseName"
label="责任人"
required
readonly
:rules="[{ required: true }]"
is-link
placeholder="请输入工号或姓名选择责任人"
@click="assetUseNameShow=true"
></van-field>
<van-action-sheet v-model="assetUseNameShow" title="责任人" class="height100" :close-on-click-overlay="false">
<van-search
v-model="searchKeyword"
:show-action="false"
:reverse-color="false"
input-align="left"
placeholder="请输入工号或姓名选择责任人"
@input="(val) => {searchAssetUseUser(val)}"
@clear="(val) => {searchAssetUseUser(val)}"
shape="round"
></van-search>
<div class="van-action-sheet__content mt5"
v-if="assetUseUserOption && assetUseUserOption.length>0">
<template>
<template v-for="item in assetUseUserOption">
<van-button native-type="button" @click="onUserSelect(item)"
class="van-action-sheet__item van-hairline--bottom">
<span class="van-action-sheet__name">{{item.username}}{{item.loginname}}</span>
</van-button>
</template>
</template>
</div>
<van-empty description="暂无数据" v-else></van-empty>
</van-action-sheet>
<van-field
:rules="[{ required: true }]"
v-model="formData.assetUsageStateName"
label="使用状况"
name="assetUsageStateName"
placeholder="请选择使用状况"
required
is-link
readonly
@click="showAssetUsageStateNamePopup = true"
></van-field>
<van-popup v-model="showAssetUsageStateNamePopup" position="bottom">
<van-picker
show-toolbar
:columns="assetUsageStateNameOption.map(i => i.name)"
@confirm="onAssetUsageStateNameConfirm"
@cancel="showAssetUsageStateNamePopup = false"
></van-picker>
</van-popup>
<van-field label="备注"
v-model="formData.assetNotes"
type="textarea"
name="assetNotes"
rows="4"
autosize
maxlength="150"
class="more-text"
placeholder="请填写备注"></van-field>
</van-cell-group>
<van-cell-group title="附件">
<van-field class="more-text" name="assetFiles"
:rules="[{ required: true,message:'请上传附件' }]"
label=""
required>
<template #input>
<h5-file-upload
slot="input"
:value.sync="formData.assetFiles"
:upload_number="10"
upload_mode="file"
upload_result_category="array"
upload_result_type="url"
complete_result
></h5-file-upload>
</template>
</van-field>
</van-cell-group>
<!-- 按钮区域 -->
<div class="form-actions">
<van-button type="primary" @click="onSubmit">提交</van-button>
</div>
</van-form>
</div>
</div>
</van-action-sheet>
`,
dicts: ["ASSET_USAGE_STATE"],
data() {
return {
visible: false,
viewData: {},
row: null,
formData: {},
assetUsageStateNameOption:[],
showAssetUsageStateNamePopup:false,
assetUseUserOption:[],
assetUseNameShow:false,
searchKeyword:""
}
},
methods: {
// 打开
async onOpen(row) {
this.row = row
this.$set(this.formData, "assetId", row.id)
this.$set(this.formData, "assetStocktakingPlanId", row.assetStocktakingPlanId)
this.$set(this.formData, "assetNumber", row.assetNumber)
this.$set(this.formData, "assetName", row.assetName)
this.$set(this.formData, "assetUsedDate", row.assetUsedDate)
this.$set(this.formData, "assetStorageLocation", row.assetStorageLocation)
this.assetUsageStateNameOption = await this.$businessTool.getDictOptions("ASSET_USAGE_STATE")
this.visible = true
},
onAssetUsageStateNameConfirm(value,index){
this.formData.assetUsageStateName = this.assetUsageStateNameOption[index].name
this.showAssetUsageStateNamePopup=false
},
onUserSelect(o){
this.$set(this.formData, "assetUseUserId", o.id)
this.$set(this.formData, "assetUseName", o.username)
this.assetUseNameShow = false
},
searchAssetUseUser(val) {
$.get("/platform/asset/manage/searchAssetUseUser", {query: val}).then(resp => {
if (resp.code === 0) {
this.assetUseUserOption = resp.data
}
})
},
onSubmit() {
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: "提示",
message: "您确定要提交吗?"
}).then(() => {
let formData = clone(this.formData)
if (formData.assetFiles) {
formData.assetFiles = JSON.stringify(formData.assetFiles)
}
this.$axios.post("/platform/asset/stocktaking/doSubmit", formData).then(res => {
if (res.code === 0) {
this.$toast(res.msg)
this.visible = false
this.$emit("save_success")
}
})
})
})
},
}
}
@@ -0,0 +1,351 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.course-cover {
width: 100%;
height: 200px;
background: linear-gradient(45deg, #f0f2f5, #e9ecef);
display: flex;
align-items: center;
justify-content: center;
}
.course-cover .van-image {
width: 100%;
height: 100%;
}
.course-info {
padding: 16px;
overflow: hidden;
}
.course-info .van-cell-group {
padding: 20px;
background: linear-gradient(135deg, #fff 0%, #f8f9fa 100%);
}
.course-title {
font-size: 20px;
font-weight: 700;
color: #1a1a1a;
margin-bottom: 12px;
line-height: 1.3;
letter-spacing: 0.5px;
}
.course-desc {
font-size: 15px;
color: #555;
line-height: 1.7;
margin-bottom: 16px;
text-align: justify;
}
.course-meta {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 13px;
padding-top: 16px;
border-top: 1px solid #f0f0f0;
margin-top: 4px;
}
.course-date {
color: #888;
font-weight: 500;
}
.progress-section {
margin-bottom: 12px;
}
.progress-container {
display: flex;
align-items: center;
width: 100%;
}
.progress-container .van-progress {
flex: 1;
margin-right: 12px;
}
.progress-text {
font-size: 14px;
color: #333;
min-width: 40px;
}
.chapters-section {
margin-bottom: 16px;
}
.chapter-card {
background: #fff;
border: 1px solid #f0f0f0;
margin-bottom: 16px;
overflow: hidden;
}
.chapter-header {
padding: 16px;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-bottom: 1px solid #f0f0f0;
}
.chapter-title {
font-size: 16px;
font-weight: 600;
color: #333;
margin: 0;
}
.chapter-videos {
padding: 0;
}
.video-item {
display: flex;
align-items: center;
padding: 12px 16px;
border-bottom: 1px solid #f8f9fa;
cursor: pointer;
transition: background-color 0.2s;
}
.video-item:hover {
background-color: #f8f9fa;
}
.video-item:last-child {
border-bottom: none;
}
.video-icon {
margin-right: 12px;
flex-shrink: 0;
}
.video-content {
flex: 1;
min-width: 0;
}
.video-title {
font-size: 14px;
color: #333;
margin-bottom: 4px;
font-weight: 500;
}
.video-duration {
font-size: 12px;
color: #999;
}
.video-status {
margin-left: 8px;
flex-shrink: 0;
}
</style>
<div id="app" v-cloak>
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="课程详情" placeholder fixed></van-nav-bar>
<div v-if="loading" class="loading-container">
<van-loading type="spinner" size="24px">加载中...</van-loading>
</div>
<div v-else-if="course">
<!-- 课程封面 -->
<div class="course-cover">
<van-image v-if="course.cover" :src="course.cover" fit="cover" :alt="course.title">
<template v-slot:error>
<van-icon name="photo-fail" size="48" color="#ddd"></van-icon>
</template>
</van-image>
<van-icon v-else name="graduation" size="48" color="#ddd"></van-icon>
</div>
<!-- 课程信息 -->
<van-cell-group class="course-info">
<div class="course-title">{{ course.title || '未命名课程' }}</div>
<div class="course-desc">{{ course.description || '暂无描述' }}</div>
<div class="course-meta">
<van-tag type="primary" size="mini">{{ course.category || '未分类' }}</van-tag>
<span class="course-date">{{ formatDate(course.createdAt) }}</span>
</div>
</van-cell-group>
<!-- 学习进度 -->
<van-cell-group title="学习进度" class="progress-section">
<van-cell>
<template #default>
<div class="progress-container">
<van-progress :percentage="progressPercentage" stroke-width="6"></van-progress>
<span class="progress-text">{{ progressPercentage }}%</span>
</div>
</template>
</van-cell>
</van-cell-group>
<!-- 课程章节 -->
<div class="chapters-section">
<h3 style="margin: 0 0 16px 0; padding-left:16px;font-size: 16px; font-weight: 600; color: #333;">课程章节</h3>
<div v-if="course.chapters && course.chapters.length">
<div
v-for="(chapter, index) in course.chapters"
v-if="chapter.videos && chapter.videos.length"
:key="chapter.id"
class="chapter-card"
>
<div class="chapter-header">
<h4 class="chapter-title">{{ chapter.title || '第' + (index + 1) + '章' }}</h4>
</div>
<div class="chapter-videos">
<div
v-for="video in chapter.videos"
:key="video.id"
class="video-item"
@click="playVideo(video.id, video.title)"
>
<div class="video-icon">
<van-icon
:name="isVideoCompleted(video.id) ? 'success' : 'play-circle-o'"
:color="isVideoCompleted(video.id) ? '#07c160' : '#1989fa'"
size="20"
></van-icon>
</div>
<div class="video-content">
<div class="video-title">{{ video.title || '未命名视频' }}</div>
<div class="video-duration">{{ formatDuration(video.duration) }}</div>
</div>
<div class="video-status" v-if="isVideoCompleted(video.id)">
<van-tag type="success" size="mini">已完成</van-tag>
</div>
</div>
</div>
</div>
</div>
<van-empty v-else description="暂无章节内容" style="padding: 40px 20px;"></van-empty>
</div>
</div>
<van-empty v-else description="课程不存在"></van-empty>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
store,
data() {
return {
course: null,
loading: true,
courseId: null,
activeChapters: [],
progressData: null
}
},
computed: {
progressPercentage() {
if (!this.progressData || !this.progressData.totalVideos) return 0;
return Math.round(this.progressData.completedVideos / this.progressData.totalVideos * 100);
}
},
methods: {
historyBack,
// 加载课程详情
async loadCourseDetail() {
if (!this.courseId) {
this.$toast.fail('缺少课程ID参数');
this.loading = false;
return;
}
try {
const {code, data, msg} = await $.get('/platform/h5/edu/course/detail/data', {
courseId: this.courseId
});
if (code === 0 && data) {
this.course = data;
this.loadCourseProgress();
} else {
this.$toast.fail(msg || '加载课程详情失败');
}
} catch (error) {
this.$toast.fail('网络错误');
}
this.loading = false;
},
// 加载课程进度
async loadCourseProgress() {
try {
const {code, data} = await $.get('/platform/h5/edu/course/progress', {
courseId: this.courseId
});
if (code === 0 && data) {
this.progressData = data;
}
} catch (error) {
console.error('加载进度失败:', error);
}
},
// 检查视频是否已完成
isVideoCompleted(videoId) {
return this.progressData &&
this.progressData.completedVideoIds &&
this.progressData.completedVideoIds.includes(videoId);
},
// 播放视频
playVideo(videoId, videoTitle) {
pjaxReplace('/platform/h5/edu/video/play?videoId=' + videoId + '&courseId=' + this.courseId + '&title=' + encodeURIComponent(videoTitle || ''));
},
// 格式化日期
formatDate(dateStr) {
if (!dateStr) return '';
const date = new Date(dateStr);
return date.getFullYear() + '-' +
String(date.getMonth() + 1).padStart(2, '0') + '-' +
String(date.getDate()).padStart(2, '0');
},
// 格式化时长
formatDuration(seconds) {
if (!seconds) return '00:00';
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
return String(minutes).padStart(2, '0') + ':' + String(remainingSeconds).padStart(2, '0');
}
},
mounted() {
// 获取URL参数
const urlParams = new URLSearchParams(window.location.search);
this.courseId = urlParams.get('courseId');
this.loadCourseDetail();
}
});
</script>
<!--#
}
#-->
@@ -0,0 +1,230 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.course-item {
background: rgba(255, 255, 255, 0.95);
border-radius: 6px;
margin: 12px 16px;
overflow: hidden;
display: flex;
align-items: stretch;
position: relative;
}
.course-cover {
width: 100px;
height: 100px;
border-radius: 16px;
overflow: hidden;
margin: 16px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
position: relative;
}
.course-cover::after {
content: '';
position: absolute;
inset: 2px;
border-radius: 14px;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(5px);
}
.course-cover .van-image {
width: 100%;
height: 100%;
border-radius: 14px;
z-index: 1;
position: relative;
}
.course-cover .van-icon {
z-index: 2;
position: relative;
color: rgba(255, 255, 255, 0.9);
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
}
.course-info {
flex: 1;
min-width: 0;
padding: 16px 16px 16px 0;
display: flex;
flex-direction: column;
justify-content: center;
}
.course-title {
font-size: 18px;
font-weight: 700;
color: #2c3e50;
margin-bottom: 8px;
line-height: 1.3;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
letter-spacing: -0.02em;
}
.course-desc {
font-size: 14px;
color: #64748b;
line-height: 1.5;
margin-bottom: 12px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
font-weight: 400;
}
.course-meta {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 12px;
}
.course-date {
color: #94a3b8;
font-weight: 500;
font-size: 11px;
}
</style>
<div id="app" v-cloak>
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="教育培训课程" placeholder fixed>
<template #right>
<van-icon name="clock-o" @click="goToHistory"></van-icon>
</template>
</van-nav-bar>
<van-sticky offset-top="46px">
<van-tabs v-model="pageForm.category" @change="doSearch">
<van-tab name="" title="全部"></van-tab>
<van-tab v-for="item in dict.type.TRAIN_EDU_COURSE_TYPE"
:name="item.code"
:title="item.name"
:key="item.id"
></van-tab>
</van-tabs>
</van-sticky>
<van-pull-refresh v-model="tableRefreshing" @refresh="onRefresh">
<van-list v-model="tableLoading" :finished="tableFinished" finished-text="没有更多了" @load="onLoad">
<div class="course-item" v-for="(course, index) in tableData" :key="course.id"
@click="viewCourse(course.id)">
<div class="course-cover">
<van-image v-if="course.cover" :src="course.cover" fit="cover" :alt="course.title">
<template v-slot:error>
<van-icon name="photo-fail" size="32" color="#ddd"></van-icon>
</template>
</van-image>
<van-icon v-else name="play-circle-o" size="48" color="#ddd"></van-icon>
</div>
<div class="course-info">
<div class="course-title">{{ course.title || '未命名课程' }}</div>
<div class="course-desc">{{ course.description || '暂无描述' }}</div>
<div class="course-meta">
<van-tag type="primary" size="mini">{{ course.category || '未分类' }}</van-tag>
<span class="course-date">{{ formatDate(course.createdAt) }}</span>
</div>
</div>
</div>
</van-list>
</van-pull-refresh>
<van-empty v-if="!tableLoading && !tableData.length" description="暂无课程"></van-empty>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
store,
dicts:['TRAIN_EDU_COURSE_TYPE'],
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
category: ""
},
tableData: [],
tableLoading: false,
tableFinished: false,
tableRefreshing: false
}
},
methods: {
historyBack,
// 刷新
onRefresh() {
this.tableFinished = false;
this.tableLoading = true
this.pageForm.pageNumber = 1;
this.onLoad();
},
// 加载更多
async onLoad() {
if(this.tableRefreshing){
this.tableData = []
this.tableRefreshing = false
}
this.$axios.post('/platform/h5/edu/courses/list', this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = this.tableData.concat(res.data.list)
this.pageForm.totalCount = res.data.totalCount
if (this.tableData.length >= this.pageForm.totalCount) {
this.tableFinished = true
}
this.pageForm.pageNumber++;
}
}).finally(() => {
this.tableLoading = false
this.tableRefreshing = false
})
},
// 搜索
doSearch() {
this.pageForm.pageNumber = 1;
this.tableData = [];
this.tableFinished = false;
this.tableLoading = true;
this.onLoad();
},
// 查看课程详情
viewCourse(courseId) {
pjaxReplace(`/platform/h5/edu/course/detail?courseId=` + courseId);
},
// 前往学习历史
goToHistory() {
pjaxReplace('/platform/h5/edu/studyhis/');
},
// 格式化日期
formatDate(dateStr) {
if (!dateStr) return '';
const date = new Date(dateStr);
return date.getFullYear() + '-' +
String(date.getMonth() + 1).padStart(2, '0') + '-' +
String(date.getDate()).padStart(2, '0');
}
}
});
</script>
<!--#
}
#-->
@@ -0,0 +1,410 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.history-container {
background-color: #f5f5f5;
min-height: 100vh;
}
.stats-card {
background: white;
border-radius: 12px;
padding: 20px;
margin: 15px;
margin-bottom: 10px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.stats-title {
font-size: 16px;
font-weight: 600;
color: #333;
margin-bottom: 15px;
display: flex;
align-items: center;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
}
.stat-item {
text-align: center;
}
.stat-number {
font-size: 24px;
font-weight: 700;
color: #1989fa;
margin-bottom: 5px;
}
.stat-label {
font-size: 12px;
color: #666;
}
.history-item {
background: white;
border-radius: 12px;
margin: 15px;
margin-bottom: 10px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.history-header {
padding: 15px 20px;
border-bottom: 1px solid #f8f9fa;
display: flex;
align-items: center;
justify-content: space-between;
}
.course-info {
flex: 1;
}
.course-title {
font-size: 16px;
font-weight: 600;
color: #333;
margin-bottom: 5px;
}
.course-meta {
font-size: 12px;
color: #999;
display: flex;
align-items: center;
}
.course-category {
background: #e3f2fd;
color: #1976d2;
padding: 2px 6px;
border-radius: 8px;
margin-right: 10px;
}
.progress-info {
text-align: right;
min-width: 80px;
}
.progress-text {
font-size: 14px;
font-weight: 600;
color: #28a745;
margin-bottom: 5px;
}
.progress-bar {
width: 60px;
height: 4px;
background: #e9ecef;
border-radius: 2px;
overflow: hidden;
margin-left: auto;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #28a745, #20c997);
border-radius: 2px;
}
.video-list {
padding: 0 20px 15px;
}
.video-item {
display: flex;
align-items: center;
padding: 10px 0;
border-bottom: 1px solid #f8f9fa;
cursor: pointer;
}
.video-item:last-child {
border-bottom: none;
}
.video-icon {
width: 36px;
height: 36px;
background: linear-gradient(135deg, #1989fa, #1976d2);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: white;
margin-right: 12px;
font-size: 14px;
}
.video-icon.completed {
background: linear-gradient(135deg, #28a745, #20c997);
}
.video-info {
flex: 1;
}
.video-title {
font-size: 14px;
color: #333;
margin-bottom: 4px;
line-height: 1.4;
}
.video-meta {
font-size: 12px;
color: #999;
display: flex;
align-items: center;
}
.video-duration {
margin-right: 15px;
}
.video-progress {
color: #28a745;
}
.watch-time {
font-size: 12px;
color: #666;
text-align: right;
}
</style>
<div id="app" class="history-container">
<van-nav-bar
title="学习历史"
left-text="返回"
left-arrow
@click-left="onClickLeft"
></van-nav-bar>
<van-tabs v-model="activeTab" @change="onTabChange">
<van-tab title="全部" name="all"></van-tab>
<van-tab title="已完成" name="completed"></van-tab>
<van-tab title="学习中" name="in_progress"></van-tab>
<van-tab title="最近观看" name="recent"></van-tab>
</van-tabs>
<!-- 学习统计 -->
<div v-if="showStats && stats" class="stats-card">
<div class="stats-title">
<van-icon name="chart-trending-o" style="margin-right: 8px; color: #1989fa;"/>
学习统计
</div>
<div class="stats-grid">
<div class="stat-item">
<div class="stat-number">{{ stats.totalCourses || 0 }}</div>
<div class="stat-label">学习课程</div>
</div>
<div class="stat-item">
<div class="stat-number">{{ stats.completedVideos || 0 }}</div>
<div class="stat-label">完成视频</div>
</div>
<div class="stat-item">
<div class="stat-number">{{ Math.round((stats.totalWatchTime || 0) / 60) }}</div>
<div class="stat-label">学习时长(分)</div>
</div>
</div>
</div>
<!-- 学习历史列表 -->
<van-loading v-if="loading" type="spinner" color="#1989fa" style="margin: 40px auto; display: block;">
加载中...
</van-loading>
<van-empty v-else-if="historyList.length === 0" description="暂无学习记录">
<van-button round type="primary" @click="loadData">刷新</van-button>
</van-empty>
<div v-else>
<div v-for="course in historyList" :key="course.courseId" class="history-item">
<div class="history-header" @click="viewCourse(course.courseId)">
<div class="course-info">
<div class="course-title">{{ course.courseTitle || '未命名课程' }}</div>
<div class="course-meta">
<span class="course-category">{{ course.courseCategory || '未分类' }}</span>
<span>最后学习:{{ formatDate(course.lastWatchTime) }}</span>
</div>
</div>
<div class="progress-info">
<div class="progress-text">{{ getProgressPercent(course) }}%</div>
<div class="progress-bar">
<div class="progress-fill" :style="{ width: getProgressPercent(course) + '%' }"></div>
</div>
</div>
</div>
<div v-if="course.videos && course.videos.length > 0" class="video-list">
<div
v-for="video in course.videos"
:key="video.videoId"
class="video-item"
@click="playVideo(video.videoId, course.courseId, video.videoTitle)"
>
<div class="video-icon" :class="{ completed: video.isCompleted }">
<van-icon :name="video.isCompleted ? 'success' : 'play-circle-o'"/>
</div>
<div class="video-info">
<div class="video-title">{{ video.videoTitle || '未命名视频' }}</div>
<div class="video-meta">
<span class="video-duration">{{ formatDuration(video.duration) }}</span>
<span class="video-progress">
{{ getVideoProgress(video) }}
</span>
</div>
</div>
<div class="watch-time">
{{ formatDate(video.lastWatchTime) }}
</div>
</div>
</div>
</div>
</div>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: '#app',
data() {
return {
activeTab: 'all',
loading: false,
showStats: false,
stats: null,
historyList: []
};
},
mounted() {
this.loadData();
},
methods: {
onClickLeft() {
window.location.href = '/platform/h5/edu/courses';
},
onTabChange(name) {
this.activeTab = name;
this.loadData();
},
async loadData() {
this.loading = true;
try {
// 如果是全部标签,先加载统计信息
if (this.activeTab === 'all') {
await this.loadStats();
this.showStats = true;
} else {
this.showStats = false;
}
// 加载学习历史
await this.loadHistory();
} catch (error) {
this.$toast('加载失败,请重试');
} finally {
this.loading = false;
}
},
async loadStats() {
try {
const response = await this.$axios.post('/platform/h5/edu/study/stats');
if (response.data.code === 0) {
this.stats = response.data.data;
}
} catch (error) {
console.error('加载统计失败:', error);
}
},
async loadHistory() {
try {
const response = await this.$axios.post('/platform/h5/edu/study/history', {
params: {filter: this.activeTab}
});
if (response.data.code === 0) {
this.historyList = response.data.data || [];
} else {
this.$toast(response.data.msg || '加载失败');
}
} catch (error) {
this.$toast('网络错误,请检查网络连接');
}
},
viewCourse(courseId) {
window.location.href = `/platform/h5/edu/course/detail?courseId=` + courseId;
},
playVideo(videoId, courseId, videoTitle) {
pjaxReplace('/platform/h5/edu/video/play?videoId=' + videoId + '&courseId=' + courseId + '&title=' + encodeURIComponent(videoTitle))
},
getProgressPercent(course) {
if (!course.videos || course.videos.length === 0) return 0;
const completedCount = course.videos.filter(v => v.isCompleted).length;
return Math.round((completedCount / course.videos.length) * 100);
},
getVideoProgress(video) {
if (video.isCompleted) return '已完成';
if (video.duration > 0 && video.watchDuration > 0) {
const percent = Math.round((video.watchDuration / video.duration) * 100);
return `观看` + percent + '%';
}
return '未开始';
},
formatDate(dateStr) {
if (!dateStr) return '未知';
const date = new Date(dateStr);
const now = new Date();
const diffTime = now - date;
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
if (diffDays === 0) {
const diffHours = Math.floor(diffTime / (1000 * 60 * 60));
if (diffHours === 0) {
const diffMinutes = Math.floor(diffTime / (1000 * 60));
return diffMinutes <= 0 ? '刚刚' : diffMinutes + `分钟前`;
}
return diffHours + `小时前`;
} else if (diffDays === 1) {
return '昨天';
} else if (diffDays < 7) {
return diffDays + `天前`;
} else {
return date.getFullYear() + '-' +
String(date.getMonth() + 1).padStart(2, '0') + '-' +
String(date.getDate()).padStart(2, '0');
}
},
formatDuration(seconds) {
if (!seconds) return '00:00';
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
return String(minutes).padStart(2, '0') + ':' + String(remainingSeconds).padStart(2, '0');
}
}
});
</script>
<!--#
}
#-->
@@ -0,0 +1,547 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.study-his-container {
background-color: #f5f5f5;
min-height: 100vh;
}
.stats-overview {
background: linear-gradient(135deg, #1989fa, #1976d2);
padding: 20px 15px;
color: white;
}
.stats-title {
font-size: 18px;
font-weight: 600;
margin-bottom: 20px;
text-align: center;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.stat-item {
text-align: center;
background: rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 15px 10px;
}
.stat-number {
font-size: 28px;
font-weight: 700;
margin-bottom: 5px;
color: #fff;
}
.stat-label {
font-size: 13px;
color: rgba(255, 255, 255, 0.8);
}
.filter-tabs {
background: white;
padding: 0 15px;
border-bottom: 1px solid #f0f0f0;
}
.tab-item {
display: inline-block;
padding: 15px 20px;
font-size: 14px;
color: #666;
cursor: pointer;
border-bottom: 2px solid transparent;
margin-right: 20px;
}
.tab-item.active {
color: #1989fa;
border-bottom-color: #1989fa;
font-weight: 600;
}
.history-list {
padding: 15px;
}
.history-card {
background: white;
border-radius: 12px;
margin-bottom: 15px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.course-header {
padding: 15px 20px;
border-bottom: 1px solid #f8f9fa;
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
}
.course-info {
flex: 1;
}
.course-title {
font-size: 16px;
font-weight: 600;
color: #333;
margin-bottom: 8px;
line-height: 1.4;
}
.course-meta {
font-size: 12px;
color: #999;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 10px;
}
.course-category {
background: #e3f2fd;
color: #1976d2;
padding: 3px 8px;
border-radius: 10px;
font-size: 11px;
}
.last-study-time {
color: #666;
}
.progress-section {
text-align: right;
min-width: 100px;
}
.progress-percent {
font-size: 16px;
font-weight: 600;
color: #28a745;
margin-bottom: 8px;
}
.progress-bar {
width: 80px;
height: 6px;
background: #e9ecef;
border-radius: 3px;
overflow: hidden;
margin-left: auto;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #28a745, #20c997);
border-radius: 3px;
transition: width 0.3s ease;
}
.video-list {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.video-list.expanded {
max-height: 1000px;
padding: 0 20px 15px;
}
.video-item {
display: flex;
align-items: center;
padding: 12px 0;
border-bottom: 1px solid #f8f9fa;
cursor: pointer;
transition: background-color 0.2s ease;
}
.video-item:hover {
background-color: #f8f9fa;
margin: 0 -10px;
padding-left: 10px;
padding-right: 10px;
border-radius: 8px;
}
.video-item:last-child {
border-bottom: none;
}
.video-icon {
width: 40px;
height: 40px;
background: linear-gradient(135deg, #1989fa, #1976d2);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: white;
margin-right: 15px;
font-size: 16px;
flex-shrink: 0;
}
.video-icon.completed {
background: linear-gradient(135deg, #28a745, #20c997);
}
.video-icon.in-progress {
background: linear-gradient(135deg, #ffc107, #ff9800);
}
.video-content {
flex: 1;
min-width: 0;
}
.video-title {
font-size: 14px;
color: #333;
margin-bottom: 6px;
line-height: 1.4;
font-weight: 500;
}
.video-meta {
font-size: 12px;
color: #999;
display: flex;
align-items: center;
gap: 15px;
}
.video-duration {
color: #666;
}
.video-progress {
color: #28a745;
font-weight: 500;
}
.video-time {
font-size: 11px;
color: #999;
text-align: right;
min-width: 60px;
flex-shrink: 0;
}
.expand-btn {
color: #1989fa;
font-size: 12px;
margin-left: 10px;
transition: transform 0.3s ease;
}
.expand-btn.expanded {
transform: rotate(180deg);
}
.empty-state {
text-align: center;
padding: 60px 20px;
color: #999;
}
.empty-icon {
font-size: 48px;
color: #ddd;
margin-bottom: 15px;
}
.empty-text {
font-size: 14px;
margin-bottom: 20px;
}
.loading-container {
display: flex;
justify-content: center;
align-items: center;
padding: 40px;
}
</style>
<div id="app" class="study-his-container">
<van-nav-bar
title="学习统计"
left-text="返回"
left-arrow
@click-left="onClickLeft"
></van-nav-bar>
<!-- 学习统计概览 -->
<div v-if="stats" class="stats-overview">
<div class="stats-title">我的学习成果</div>
<div class="stats-grid">
<div class="stat-item">
<div class="stat-number">{{ stats.totalCourses || 0 }}</div>
<div class="stat-label">学习课程</div>
</div>
<div class="stat-item">
<div class="stat-number">{{ stats.completedVideos || 0 }}</div>
<div class="stat-label">完成视频</div>
</div>
<div class="stat-item">
<div class="stat-number">{{ Math.round((stats.totalWatchTime || 0) / 60) }}</div>
<div class="stat-label">学习时长(分)</div>
</div>
</div>
</div>
<!-- 筛选标签 -->
<div class="filter-tabs">
<div
v-for="tab in tabs"
:key="tab.key"
class="tab-item"
:class="{ active: activeTab === tab.key }"
@click="switchTab(tab.key)"
>
{{ tab.label }}
</div>
</div>
<!-- 加载状态 -->
<div v-if="loading" class="loading-container">
<van-loading type="spinner" color="#1989fa" size="24px">加载中...</van-loading>
</div>
<!-- 学习历史列表 -->
<div v-else-if="historyList.length > 0" class="history-list">
<div v-for="course in historyList" :key="course.courseId" class="history-card">
<div class="course-header" @click="toggleCourseExpand(course.courseId)">
<div class="course-info">
<div class="course-title">{{ course.courseTitle || '未命名课程' }}</div>
<div class="course-meta">
<span class="course-category">{{ course.courseCategory || '未分类' }}</span>
<span class="last-study-time">{{ formatDate(course.lastWatchTime) }}</span>
</div>
</div>
<div class="progress-section">
<div class="progress-percent">{{ getProgressPercent(course) }}%</div>
<div class="progress-bar">
<div class="progress-fill" :style="{ width: getProgressPercent(course) + '%' }"></div>
</div>
</div>
<van-icon
name="arrow-down"
class="expand-btn"
:class="{ expanded: expandedCourses.includes(course.courseId) }"
></van-icon>
</div>
<div
class="video-list"
:class="{ expanded: expandedCourses.includes(course.courseId) }"
>
<div
v-for="video in course.videos"
:key="video.videoId"
class="video-item"
@click="playVideo(video.videoId, course.courseId, video.videoTitle)"
>
<div
class="video-icon"
:class="getVideoIconClass(video)"
>
<van-icon :name="getVideoIconName(video)" ></van-icon>
</div>
<div class="video-content">
<div class="video-title">{{ video.videoTitle || '未命名视频' }}</div>
<div class="video-meta">
<span class="video-duration">{{ formatDuration(video.duration) }}</span>
<span class="video-progress">{{ getVideoProgressText(video) }}</span>
</div>
</div>
<div class="video-time">
{{ formatDate(video.lastWatchTime) }}
</div>
</div>
</div>
</div>
</div>
<!-- 空状态 -->
<div v-else class="empty-state">
<div class="empty-icon">📚</div>
<div class="empty-text">暂无学习记录</div>
<van-button round type="primary" size="small" @click="goToCourses">
开始学习
</van-button>
</div>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: '#app',
data() {
return {
loading: false,
stats: null,
activeTab: 'all',
tabs: [
{ key: 'all', label: '全部' },
{ key: 'completed', label: '已完成' },
{ key: 'in_progress', label: '学习中' },
{ key: 'recent', label: '最近' }
],
historyList: [],
expandedCourses: []
};
},
mounted() {
this.loadData();
},
methods: {
onClickLeft() {
window.location.href = '/platform/h5/edu/courses';
},
async loadData() {
this.loading = true;
try {
await Promise.all([
this.loadStats(),
this.loadHistory()
]);
} catch (error) {
this.$toast('加载失败,请重试');
} finally {
this.loading = false;
}
},
async loadStats() {
try {
const response = await this.$axios.post('/platform/h5/edu/studyhis/stats');
if (response.data.code === 0) {
this.stats = response.data.data;
}
} catch (error) {
console.error('加载统计失败:', error);
}
},
async loadHistory() {
try {
const response = await this.$axios.post('/platform/h5/edu/studyhis/history', {
filter: this.activeTab
});
if (response.data.code === 0) {
this.historyList = response.data.data || [];
} else {
this.$toast(response.data.msg || '加载失败');
}
} catch (error) {
this.$toast('网络错误,请检查网络连接');
}
},
switchTab(tabKey) {
if (this.activeTab === tabKey) return;
this.activeTab = tabKey;
this.expandedCourses = [];
this.loadData();
},
toggleCourseExpand(courseId) {
const index = this.expandedCourses.indexOf(courseId);
if (index > -1) {
this.expandedCourses.splice(index, 1);
} else {
this.expandedCourses.push(courseId);
}
},
playVideo(videoId, courseId, videoTitle) {
const url = '/platform/h5/edu/video/play?videoId=' + videoId +
'&courseId=' + courseId +
'&title=' + encodeURIComponent(videoTitle || '');
window.location.href = url;
},
goToCourses() {
window.location.href = '/platform/h5/edu/courses';
},
getProgressPercent(course) {
if (!course.videos || course.videos.length === 0) return 0;
const completedCount = course.videos.filter(v => v.isCompleted).length;
return Math.round((completedCount / course.videos.length) * 100);
},
getVideoIconClass(video) {
if (video.isCompleted) return 'completed';
if (video.watchDuration > 0) return 'in-progress';
return '';
},
getVideoIconName(video) {
if (video.isCompleted) return 'success';
if (video.watchDuration > 0) return 'pause-circle-o';
return 'play-circle-o';
},
getVideoProgressText(video) {
if (video.isCompleted) return '已完成';
if (video.duration > 0 && video.watchDuration > 0) {
const percent = Math.round((video.watchDuration / video.duration) * 100);
return '观看' + percent + '%';
}
return '未开始';
},
formatDate(dateStr) {
if (!dateStr) return '未知';
const date = new Date(dateStr);
const now = new Date();
const diffTime = now - date;
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
if (diffDays === 0) {
const diffHours = Math.floor(diffTime / (1000 * 60 * 60));
if (diffHours === 0) {
const diffMinutes = Math.floor(diffTime / (1000 * 60));
return diffMinutes <= 0 ? '刚刚' : diffMinutes + '分钟前';
}
return diffHours + '小时前';
} else if (diffDays === 1) {
return '昨天';
} else if (diffDays < 7) {
return diffDays + '天前';
} else {
return (date.getMonth() + 1) + '-' + date.getDate();
}
},
formatDuration(seconds) {
if (!seconds) return '00:00';
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
return String(minutes).padStart(2, '0') + ':' + String(remainingSeconds).padStart(2, '0');
}
}
});
</script>
<!--#
}
#-->
@@ -0,0 +1,305 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.video-container {
background: #000;
min-height: calc(100vh - 46px);
display: flex;
align-items: center;
justify-content: center;
}
.loading-container {
display: flex;
justify-content: center;
align-items: center;
height: 300px;
color: white;
}
.video-player {
width: 100%;
height: 100%;
}
.video-element {
width: 100%;
height: auto;
max-height: calc(100vh - 46px);
object-fit: contain;
}
</style>
<div id="app" v-cloak>
<van-nav-bar @click-left="pageBack" left-arrow left-text="返回" :title="videoTitle" placeholder fixed></van-nav-bar>
<div class="video-container">
<div v-if="loading" class="loading-container">
<van-loading type="spinner" size="24px">加载中...</van-loading>
</div>
<div v-else-if="videoInfo" class="video-player">
<video
ref="videoElement"
class="video-element"
:src="videoSrc"
controls
preload="metadata"
@loadedmetadata="onVideoLoaded"
@canplay="onVideoCanPlay"
@play="onVideoPlay"
@pause="onVideoPause"
@timeupdate="onTimeUpdate"
@ended="onVideoEnded"
@error="onVideoError"
>
您的浏览器不支持视频播放
</video>
</div>
<van-empty v-else description="视频加载失败"></van-empty>
</div>
<!-- 进度保存提示 -->
<van-toast v-model="showProgressToast" message="进度已保存" :duration="1000"/>
<!-- 完成学习弹窗 -->
<van-dialog
v-model="showCompletionDialog"
title="恭喜完成学习!"
message="您已完成本视频的学习,学习记录已保存。"
show-cancel-button
cancel-button-text="继续观看"
confirm-button-text="返回课程"
@confirm="backToCourse"
></van-dialog>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
store,
data() {
return {
videoInfo: null,
loading: true,
videoId: null,
courseId: null,
videoTitle: '视频播放',
isPlaying: false,
progressSaveTimer: null,
showProgressToast: false,
showCompletionDialog: false,
savedProgress: 0,
progressSet: false // 标记进度是否已设置,避免死循环
}
},
computed: {
videoSrc() {
if (this.videoInfo && this.videoInfo.url) {
const id = this.videoInfo.url.split('id=')[1];
console.log('/platform/sys/file/videoPlay?id=' + id)
return '/platform/sys/file/videoPlay?id=' + id;
}
return null
}
},
methods: {
pageBack() {
this.historyBack(this.clearProgressSave)
},
// 加载视频信息
async loadVideoInfo() {
if (!this.videoId) {
this.$toast.fail('缺少视频ID参数');
this.loading = false;
return;
}
try {
const {code, data, msg} = await this.$axios.post('/platform/h5/edu/video/detail', {
videoId: this.videoId
});
if (code === 0 && data) {
this.videoInfo = data;
this.$nextTick(() => {
this.loadWatchProgress();
});
} else {
this.$toast.fail(msg || '加载视频信息失败');
}
} catch (error) {
this.$toast.fail('网络错误');
}
this.loading = false;
},
// 视频加载完成
onVideoLoaded() {
console.log('视频元数据加载完成');
},
// 视频可以播放
onVideoCanPlay() {
console.log('视频可以播放');
// 视频可以播放时,设置观看进度
this.setWatchProgress();
},
// 视频开始播放
onVideoPlay() {
this.isPlaying = true;
this.startProgressSave();
},
// 视频暂停
onVideoPause() {
this.isPlaying = false;
this.saveProgress();
},
// 时间更新
onTimeUpdate() {
console.log('时间更新')
// 可以在这里添加进度更新逻辑
},
// 视频播放结束
onVideoEnded() {
this.isPlaying = false;
this.markVideoCompleted();
},
// 视频加载错误
onVideoError() {
this.$toast.fail('视频加载失败');
},
// 加载观看进度
async loadWatchProgress() {
if (!this.videoId || !this.courseId) return;
try {
const {code, data} = await this.$axios.post('/platform/h5/edu/study/record', {
videoId: this.videoId
});
if (code === 0 && data && data.watchedDuration > 0) {
this.savedProgress = data.watchedDuration;
}
} catch (error) {
console.error('加载观看进度失败:', error);
}
},
// 设置观看进度
setWatchProgress() {
if (this.savedProgress > 0 && !this.progressSet) {
const video = this.$refs.videoElement;
if (video && video.readyState >= 3) {
// 使用setTimeout确保DOM更新完成
setTimeout(() => {
try {
this.progressSet = true; // 标记进度已设置,避免重复设置
video.currentTime = this.savedProgress;
console.log('设置观看进度成功:', this.savedProgress);
} catch (error) {
console.error('设置观看进度失败:', error);
}
}, 100);
} else {
console.log('视频还未准备好,readyState:', video ? video.readyState : 'video不存在');
}
}
},
// 保存观看进度
async saveProgress() {
const video = this.$refs.videoElement;
if (!video || !this.videoId || !this.courseId) return;
try {
await $.post('/platform/h5/edu/study/progress/save', {
videoId: this.videoId,
courseId: this.courseId,
watchedDuration: Math.floor(video.currentTime)
});
this.showProgressToast = true;
} catch (error) {
console.error('保存进度失败:', error);
}
},
// 开始定时保存进度
startProgressSave() {
this.clearProgressSave();
this.progressSaveTimer = setInterval(() => {
this.saveProgress();
}, 10000); // 每10秒保存一次
},
// 清除定时保存
clearProgressSave() {
if (this.progressSaveTimer) {
clearInterval(this.progressSaveTimer);
this.progressSaveTimer = null;
}
},
// 标记视频完成
async markVideoCompleted() {
if (!this.videoId || !this.courseId) return;
try {
const {code} = await $.post('/platform/h5/edu/study/complete', {
videoId: this.videoId,
courseId: this.courseId
});
if (code === 0) {
this.showCompletionDialog = true;
}
} catch (error) {
console.error('标记完成失败:', error);
}
},
// 返回课程
backToCourse() {
if (this.courseId) {
} else {
this.historyBack();
}
}
},
mounted() {
// 获取URL参数
const urlParams = new URLSearchParams(window.location.search);
this.videoId = urlParams.get('videoId');
this.courseId = urlParams.get('courseId');
this.videoTitle = decodeURIComponent(urlParams.get('title') || '视频播放');
this.loadVideoInfo();
},
beforeDestroy() {
// 页面销毁前保存进度
this.saveProgress();
this.clearProgressSave();
}
});
</script>
<!--#
}
#-->
@@ -0,0 +1,479 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
</style>
<div id="app">
<!-- 导航栏 -->
<van-nav-bar title="子女入学" left-text="返回" left-arrow
@click-left="historyBack" fixed></van-nav-bar>
<!-- 表单容器 -->
<div class="form-container">
<van-form ref="formRef">
<!-- 登记类型信息 -->
<van-cell-group title="登记类型">
<van-field
:rules="[{ required: true }]"
v-model="formData.registrationTypeName"
label="登记类型"
placeholder="请选择登记类型"
required
is-link
readonly
@click="showRegistrationTypePopup = true"
></van-field>
<van-popup v-model="showRegistrationTypePopup" position="bottom">
<van-picker
show-toolbar
:columns="registrationTypeOption.map(i => i.registrationTypeName)"
@confirm="onRegistrationTypeConfirm"
@cancel="showRegistrationTypePopup = false"
></van-picker>
</van-popup>
</van-cell-group>
<!-- 教职工信息 -->
<van-cell-group title="教职工信息">
<van-field label="监护人(教工)姓名" :rules="[{ required: true }]" v-model="formData.userName" readonly
required></van-field>
<van-field label="工号" :rules="[{ required: true }]" v-model="formData.loginName" readonly
required></van-field>
<van-field label="手机号码" name="mobile" :rules="[{ required: true }]" v-model="formData.mobile"
required
placeholder="请输入手机号码"></van-field>
<van-field label="所在单位" :rules="[{ required: true }]" v-model="formData.unitName" readonly
required></van-field>
<van-field
:rules="[{ required: true }]"
v-model="formData.childRelationshipName"
label="监护人与学生关系"
name="childRelationshipName"
placeholder="请选择监护人与学生关系"
required
is-link
readonly
@click="showChildRelationshipPopup = true"
></van-field>
<van-popup v-model="showChildRelationshipPopup" position="bottom">
<van-picker
show-toolbar
:columns="childRelationshipOption.map(i => i.name)"
@confirm="onChildRelationshipConfirm"
@cancel="showChildRelationshipPopup = false"
></van-picker>
</van-popup>
</van-cell-group>
<!-- 子女信息 -->
<van-cell-group title="子女信息">
<van-field label="子女姓名" name="childrenName" :rules="[{ required: true }]"
v-model="formData.childrenName" required
placeholder="请输入子女姓名"></van-field>
<van-field
:rules="[{ required: true }]"
v-model="formData.sex"
label="性别"
name="sex"
placeholder="请选择性别"
required
is-link
readonly
@click="showSexPopup = true"
></van-field>
<van-popup v-model="showSexPopup" position="bottom">
<van-picker
show-toolbar
:columns="sexOption"
@confirm="onSexConfirm"
@cancel="showSexPopup = false"
></van-picker>
</van-popup>
<van-field label="身份证号"
name="childrenIdCard"
:rules="[{ required: true }]"
v-model="formData.childrenIdCard"
placeholder="请输入身份证号"
required
></van-field>
<van-field label="出生年月"
name="childrenBirthday"
:rules="[{ required: true }]"
:value="formData.childrenBirthday"
readonly
is-link
placeholder="请填写出生年月"
required
@click="childrenBirthdayPopup = true"></van-field>
<van-popup v-model="childrenBirthdayPopup" position="bottom">
<van-datetime-picker
v-model="formData.childrenBirthdayDate"
type="date"
title="选择出生年月"
:min-date="childrenBirthdayMinDate"
:max-date="childrenBirthdayMaxDate"
@confirm="childrenBirthdayConfirm"
@cancel="childrenBirthdayPopup=false"
></van-datetime-picker>
</van-popup>
<van-field label="现就读学校"
:rules="[{ required: true }]"
v-model="formData.childrenCurrentSchool"
required
placeholder="请输入现就读学校"></van-field>
<van-field
:rules="[{ required: true }]"
v-model="formData.childrenPlanSchoolName"
label="拟报就读学校"
name="childrenPlanSchoolName"
placeholder="请选择拟报就读学校"
required
is-link
readonly
@click="showChildrenPlanSchoolPopup = true"
class="van-field"
></van-field>
<van-popup v-model="showChildrenPlanSchoolPopup" position="bottom">
<van-picker
show-toolbar
:columns="childrenPlanSchoolOption.map(i => i.name)"
@confirm="onChildrenPlanSchoolConfirm"
@cancel="showChildrenPlanSchoolPopup = false"
></van-picker>
</van-popup>
<van-field label="子女户口所在地"
:rules="[{ required: true }]"
v-model="formData.childrenHuKouAddress"
required
type="textarea"
name="childrenHuKouAddress"
rows="4"
autosize
class="more-text"
placeholder="请输入子女户口所在地"></van-field>
<van-field label="备注"
:rules="[{ required: true }]"
v-model="formData.note"
required
type="textarea"
name="note"
rows="4"
autosize
class="more-text"
placeholder="请填写户籍所在地派出所"></van-field>
</van-cell-group>
<!-- 户口簿照片 -->
<van-cell-group title="户口簿照片">
<van-field class="more-text" name="huKouFiles" :rules="[{ required: true,message:'请上传户口簿照片' }]"
label="" required>
<template #input>
<h5-file-upload
slot="input"
:value.sync="formData.huKouFiles"
:upload_number="10"
upload_mode="file"
upload_result_category="array"
upload_result_type="url"
complete_result
></h5-file-upload>
</template>
</van-field>
</van-cell-group>
<!-- 子女出生证照片 -->
<van-cell-group title="子女出生证照片">
<van-field class="more-text" name="birthCertificateFiles" label="">
<template #input>
<h5-file-upload
slot="input"
:value.sync="formData.birthCertificateFiles"
:upload_number="10"
upload_mode="image"
upload_result_category="array"
upload_result_type="url"
complete_result
></h5-file-upload>
</template>
</van-field>
</van-cell-group>
<!-- 按钮区域 -->
<div class="form-actions">
<van-button native-type="button" plain type="info" @click="onSave">保存</van-button>
<van-button type="primary" @click="onSubmit" v-if="!taskId">提交</van-button>
<van-button type="primary" @click="onFinishTask" v-else>提交</van-button>
</div>
</van-form>
</div>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
store,
dicts: ["ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP", "ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL"],
components: {},
data() {
return {
bizId: GetQueryString("bizId"),
taskId: GetQueryString("taskId"),
formData: {},
registrationTypeOption: [],
showRegistrationTypePopup: false,
childRelationshipOption: [],
showChildRelationshipPopup: false,
sexOption: ["男", "女"],
showSexPopup: false,
childrenBirthdayMinDate: new Date(1900, 0, 1),
childrenBirthdayMaxDate: new Date(),
childrenBirthdayPopup: false,
childrenPlanSchoolOption: [],
showChildrenPlanSchoolPopup: false,
}
},
methods: {
async getEnrollmentRegistrationPlan() {
const res = await this.$axios.post("/platform/enrollmentRegistration/apply/getEnrollmentRegistrationPlan")
if (res.code === 0) {
this.registrationTypeOption = res.data
}
},
init() {
setTimeout(() => {
this.childRelationshipOption = this.dict.type.ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP
this.childrenPlanSchoolOption = this.dict.type.ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL
}, 300)
if (this.bizId) {
this.findOne(this.bizId).then(async data => {
this.formData = data
//登记类型回显
const registrationType = this.registrationTypeOption.find(v => v.registrationType === data.registrationType)
if (registrationType) {
this.$set(this.formData, "registrationTypeName", registrationType.registrationTypeName)
}
//监护人与学生关系回显
const childRelationship = this.dict.type.ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP.find(v => v.code === data.childRelationship)
if (childRelationship) {
this.$set(this.formData, "childRelationshipName", childRelationship.name)
}
//出生年月回显
if (data.childrenBirthday) {
this.$set(this.formData, "childrenBirthdayDate", new Date(data.childrenBirthday))
}
//拟报就读学校
const childrenPlanSchool = this.dict.type.ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL.find(v => v.code === data.childrenPlanSchool)
if (childrenPlanSchool) {
this.$set(this.formData, "childrenPlanSchoolName", childrenPlanSchool.name)
}
})
} else {
const {id, username, loginname, mobile, union, unit} = this.$store.state.user
this.formData = {
userId: id,
userName: username,
loginName: loginname,
unitName: unit.name,
unitId: unit.id,
unionName: union.name,
unionId: union.id,
mobile: mobile,
}
}
},
onChildrenPlanSchoolConfirm(value, index) {
this.formData.childrenPlanSchool = this.childrenPlanSchoolOption[index].code;
this.formData.childrenPlanSchoolName = value;
this.showChildrenPlanSchoolPopup = false;
},
childrenBirthdayConfirm(value) {
this.formData.childrenBirthdayDate = value
this.formData.childrenBirthday = this.$moment(value).format("YYYY-MM-DD")
this.childrenBirthdayPopup = false
},
onSexConfirm(value) {
this.formData.sex = value;
this.showSexPopup = false;
},
onChildRelationshipConfirm(value, index) {
this.formData.childRelationship = this.childRelationshipOption[index].code;
this.formData.childRelationshipName = value;
this.showChildRelationshipPopup = false;
},
onRegistrationTypeConfirm(value, index) {
this.formData.registrationType = this.registrationTypeOption[index].registrationType;
this.formData.registrationTypeName = value;
this.showRegistrationTypePopup = false;
},
validateBirthday() {
if (!this.formData.registrationType) {
return "请选择登记类型"
}
if (!this.formData.childrenBirthday) {
return "请选择子女出生年月"
}
const childrenBirthday = new Date(this.formData.childrenBirthday);
if (isNaN(childrenBirthday.getTime())) {
return "出生日期格式无效";
}
const registrationType = this.registrationTypeOption.find(item => item.registrationType === this.formData.registrationType)
if (registrationType.greaterThanBirthday) {
const greaterThanBirthday = new Date(registrationType.greaterThanBirthday);
if (isNaN(greaterThanBirthday.getTime())) {
return "限制日期格式无效";
}
if (childrenBirthday < greaterThanBirthday) {
return "出生日期不能小于" + registrationType.greaterThanBirthday;
}
}
if (registrationType.lessThanBirthday) {
const lessThanBirthday = new Date(registrationType.lessThanBirthday);
if (isNaN(lessThanBirthday.getTime())) {
return "限制日期格式无效";
}
if (childrenBirthday > lessThanBirthday) {
return "出生日期不能大于" + registrationType.lessThanBirthday;
}
}
return null; // 表示通过
},
async getIsRepeatByIdCard() {
if (!this.formData.childrenIdCard) {
this.$toast.fail("请填写子女身份证号码")
return
}
const res = await this.$axios.post('/platform/enrollmentRegistration/apply/getIsRepeatByIdCard', {
idCard: this.formData.childrenIdCard,
id: this.formData.id
})
if (res.code === 0) {
if (res.data > 0) {
this.$toast.fail("该身份证在本年度已填报!")
return true
} else {
this.$toast.success("该身份证在本年度暂未填报!")
return false
}
}
},
async findOne(id) {
const resp = await $.get('/platform/enrollmentRegistration/apply/findOne', {id})
if (resp.code === 0) {
return resp.data
}
},
onSave() {
const msg = this.validateBirthday()
if (msg) {
this.$toast.fail(msg)
return
}
this.$dialog.confirm({
title: '温馨提示',
message: '您确定保存吗?',
}).then(() => {
this.$axios.post('/platform/enrollmentRegistration/apply/save', {
data: JSON.stringify(this.formData)
}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
pjaxReplace("/platform/enrollmentRegistration/applyList/h5")
}
})
}).catch(() => {
// on cancel
});
},
onSubmit() {
const msg = this.validateBirthday()
if (msg) {
this.$toast.fail(msg)
return
}
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要提交吗?',
}).then(() => {
this.$axios.post('/platform/enrollmentRegistration/apply/submit', {
data: JSON.stringify(this.formData),
taskId: GetQueryString("taskId")
}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
pjaxReplace("/platform/enrollmentRegistration/applyList/h5")
}
})
}).catch(() => {
// on cancel
});
}).catch();
},
onFinishTask() {
const msg = this.validateBirthday()
if (msg) {
this.$toast.fail(msg)
return
}
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要提交吗?',
}).then(() => {
this.$axios.post('/platform/enrollmentRegistration/apply/submitAgain', {
data: JSON.stringify(this.formData),
taskId: GetQueryString("taskId")
}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
pjaxReplace("/platform/enrollmentRegistration/applyList/h5")
}
})
}).catch(() => {
// on cancel
});
}).catch();
}
},
async created() {
await this.getEnrollmentRegistrationPlan()
this.init()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,170 @@
const H5_ENROLLMENT_REGISTRATION_INFO = {
template: /*language=HTML*/ `
<van-action-sheet v-model="visible" title="查看详情">
<div>
<div class="process-title">教职工信息</div>
<van-cell-group>
<van-cell title="监护人(教工)姓名">
{{ viewData.userName }}
</van-cell>
<van-cell title="工号">
{{ viewData.loginName }}
</van-cell>
<van-cell title="手机号码">
{{ viewData.mobile }}
</van-cell>
<van-cell title="所在单位">
{{ viewData.unitName }}
</van-cell>
<van-cell title="监护人与学生关系">
<dict-tag :options="dict.type.ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP"
:value="viewData.childRelationship"></dict-tag>
</van-cell>
<van-cell title="登记类型">
<dict-tag :options="dict.type.ENROLLMENT_REGISTRATION_TYPE"
:value="viewData.registrationType"></dict-tag>
</van-cell>
</van-cell-group>
<div class="process-title">子女信息</div>
<van-cell-group>
<van-cell title="子女姓名">
{{viewData.childrenName}}
</van-cell>
<van-cell title="性别">
{{viewData.sex}}
</van-cell>
<van-cell title="身份证号">
{{viewData.childrenIdCard}}
</van-cell>
<van-cell title="出生日期">
{{viewData.childrenBirthday}}
</van-cell>
<van-cell title="现就读学校">
{{viewData.childrenCurrentSchool}}
</van-cell>
<van-cell title="拟报就读学校">
<dict-tag :options="dict.type.ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL"
:value="viewData.childrenPlanSchool"></dict-tag>
</van-cell>
<van-cell title="子女户口所在地">
{{viewData.childrenHuKouAddress}}
</van-cell>
<van-cell title="备注">
{{viewData.note}}
</van-cell>
<van-cell title="户口簿照片">
<template #label>
<template v-for="(item,index) in viewData.huKouFiles">
<van-image :src="item.url"
v-if="item.url"
class="signature-image"
@click="previewOptionImg(viewData.huKouFiles,index)"></van-image>
</template>
</template>
</van-cell>
<van-cell title="子女出生证照片">
<template #label>
<template v-for="(item,index) in viewData.birthCertificateFiles">
<van-image :src="item.url"
v-if="item.url"
class="signature-image"
@click="previewOptionImg(viewData.birthCertificateFiles,index)"></van-image>
</template>
</template>
</van-cell>
</van-cell-group>
<template v-for="(task,index) in doneTasks">
<div class="process-title">
{{ task.displayName }}
</div>
<van-cell-group v-if="task.ext.isFirstTaskNode">
<van-cell title="申请用户">
{{ task.ext.initiatorName}}({{task.ext.initiatorAccount}})
</van-cell>
<van-cell title="申请时间">
{{ task.finishTime}}
</van-cell>
<van-cell title="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag>
</van-cell>
</van-cell-group>
<van-cell-group v-else>
<van-cell title="办理用户">
{{ task.taskFormData.userName}}({{task.taskFormData.loginName}})
</van-cell>
<van-cell title="办理时间">
{{ task.finishTime}}
</van-cell>
<van-cell title="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag>
</van-cell>
<van-cell title="办理意见" v-if="!task.ext.isFirstTaskNode">
<template #label>
{{
task.taskFormData.opinion
}}
</template>
</van-cell>
<van-cell title="签字" v-if="!task.ext.isFirstTaskNode">
<van-image :src="task.ext.tf_userSign"
v-if="task.ext.tf_userSign"
class="signature-image"></van-image>
</van-cell>
</van-cell-group>
</template>
<slot></slot>
</div>
</van-action-sheet>
`,
dicts: ["ENROLLMENT_REGISTRATION_TYPE", "ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP", "ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL", "PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
visible: false,
viewData: {},
doneTasks: [],
row: null
}
},
methods: {
//预览图片
previewOptionImg(files, index) {
const urls = files.map(item => item.url)
vant.ImagePreview({images: urls, startPosition: index})
},
// 打开
onOpen(row) {
this.row = row
this.visible = true
this.getInfo()
this.getDoneTasks()
},
// 关闭
onClose() {
this.visible = false
},
// 获取申请信息
getInfo() {
this.$axios.post('/platform/enrollmentRegistration/apply/findOne', {id: this.row.id}).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
// 获取已办任务审批记录
getDoneTasks() {
this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data
}
})
},
}
}
@@ -0,0 +1,134 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<!-- 导航栏 -->
<van-nav-bar title="我的申报" left-text="返回" left-arrow placeholder
@click-left="historyBack" fixed></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-menu>
</van-sticky>
<table-list api="/platform/enrollmentRegistration/applyList/pageData" :page_form.sync="pageForm" ref="tableListRef"
@ready="doSearch">
<template v-slot="{index,row}">
<table-column label="子女姓名">{{row.childrenName}}</table-column>
<table-column label="教职工姓名">{{row.userName}}</table-column>
<table-column label="手机号码">{{row.mobile}}</table-column>
<table-column label="所属单位">{{row.unitName}}</table-column>
<table-column label="登记类型">
<dict-tag :options="dict.type.ENROLLMENT_REGISTRATION_TYPE"
:value="row.registrationType"></dict-tag>
</table-column>
<table-column label="填报时间">{{row.applyTime}}</table-column>
<table-column label="当前节点">{{row.taskName}}</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="onEdit(row)">
<i class="fa fa-edit"></i>
<span>编辑</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
<div class="action-btn delete" @click="onDelete(row.id)"
v-if="row.taskKey === 'startTask' || !row.instanceId">
<i class="fa fa-trash"></i>
<span>删除</span>
</div>
</template>
</table-list>
<h5-enrollment-registration-info ref="h5EnrollmentRegistrationInfoRef"></h5-enrollment-registration-info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../info.js'){}#-->
const vue = new Vue({
el: "#app",
store,
dicts: ["ENROLLMENT_REGISTRATION_TYPE", "ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP", "ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL"],
components: {
"h5-enrollment-registration-info": H5_ENROLLMENT_REGISTRATION_INFO
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
year: new Date().getFullYear(),
},
}
},
methods: {
onView(row) {
this.$refs.h5EnrollmentRegistrationInfoRef.onOpen(row)
},
onEdit(row) {
pjaxReplace('/platform/enrollmentRegistration/apply/h5?taskId=' + (row.startTaskId || '') + "&bizId=" + row.id)
},
onDelete(id) {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要删除吗?',
}).then(() => {
this.$axios.post("/platform/enrollmentRegistration/applyList/doDelete", {id}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
} else {
this.$toast.fail(res.msg)
}
})
}).catch(() => {
// on cancel
});
},
onRevoke(row) {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要撤回吗?',
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.startTaskId}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
} else {
this.$toast.fail(res.msg)
}
})
}).catch(() => {
// on cancel
});
},
doSearch() {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
},
},
created() {
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,187 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="校工会审核" placeholder
fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-search
:reverse-color="false"
:show-action="false"
@search="doSearch"
input-align="left"
placeholder="请输入姓名搜索"
v-model="pageForm.searchKeyword"
></van-search>
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.approval = val==='1';this.doSearch();}">
<van-tab title="已审核" name="1"></van-tab>
<van-tab title="未审核" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/enrollmentRegistration/schoolAudit/pageData" :page_form.sync="pageForm"
ref="tableListRef"
@ready="doSearch">
<template v-slot="{index,row}">
<table-column label="子女姓名">{{row.childrenName}}</table-column>
<table-column label="教职工姓名">{{row.userName}}</table-column>
<table-column label="手机号码">{{row.mobile}}</table-column>
<table-column label="所属单位">{{row.unitName}}</table-column>
<table-column label="登记类型">
<dict-tag :options="dict.type.ENROLLMENT_REGISTRATION_TYPE"
:value="row.registrationType"></dict-tag>
</table-column>
<table-column label="填报时间">{{row.applyTime}}</table-column>
<table-column label="当前节点">{{row.curTaskName}}</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" v-if="row.taskState === 10" @click="onAudit(row)">
<i class="fa fa-edit"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
</template>
</table-list>
<h5-enrollment-registration-info ref="h5EnrollmentRegistrationInfoRef">
<div v-if="showApprovalForm">
<div class="process-title">
校工会审核
</div>
<div class="form-container">
<van-form ref="formRef">
<van-cell-group title="审批意见">
<van-field label=""
:rules="[{ required: true,message:'请填审批意见' }]"
v-model="formData.tf_opinion"
required
type="textarea"
name="tf_opinion"
rows="4"
autosize
class="more-text"
placeholder="请填审批意见"></van-field>
</van-cell-group>
<van-cell-group title="电子签名" class="form-section">
<van-field class="more-text" name="tf_userSign" label="">
<template #input>
<h5-signature v-model="formData.tf_userSign" slot="input"></h5-signature>
</template>
</van-field>
</van-cell-group>
<!-- 按钮区域 -->
<div class="form-actions">
<van-button type="danger" @click="handleTaskAction(6)">退回到发起人</van-button>
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
<van-button type="primary" @click="handleTaskAction(1)">同意申请</van-button>
</div>
</van-form>
</div>
</div>
</h5-enrollment-registration-info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../info.js'){}#-->
const vue = new Vue({
el: "#app",
store,
dicts: ["ENROLLMENT_REGISTRATION_TYPE", "ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP", "ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL"],
components: {
"h5-enrollment-registration-info": H5_ENROLLMENT_REGISTRATION_INFO
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
year: new Date().getFullYear(),
approvalText: "0",
approval: false,
searchName: "info.userName",
},
formData: {},
infoShow: false,
showApprovalForm: false,
}
},
methods: {
handleTaskAction(val) {
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要提交吗?',
}).then(() => {
this.$axios.post('/flow/common/executeTask', {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.$refs.h5EnrollmentRegistrationInfoRef.onClose()
}
})
}).catch(() => {
// on cancel
});
}).catch();
},
onAudit(row) {
this.showApprovalForm = true
this.formData = {
tf_opinion: null,
tf_userSign: null,
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.h5EnrollmentRegistrationInfoRef.onOpen(row)
},
onRevoke(row) {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要撤回吗?',
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.infoShow = false
}
})
}).catch(() => {
// on cancel
});
},
onView(row) {
this.showApprovalForm = false
this.$refs.h5EnrollmentRegistrationInfoRef.onOpen(row)
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,189 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="分工会审核" placeholder
fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-search
:reverse-color="false"
:show-action="false"
@search="doSearch"
input-align="left"
placeholder="请输入姓名搜索"
v-model="pageForm.searchKeyword"
></van-search>
<!--<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-menu>-->
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.approval = val==='1';this.doSearch();}">
<van-tab title="已审核" name="1"></van-tab>
<van-tab title="未审核" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/enrollmentRegistration/unionAudit/pageData" :page_form.sync="pageForm" ref="tableListRef"
@ready="doSearch">
<template v-slot="{index,row}">
<table-column label="子女姓名">{{row.childrenName}}</table-column>
<table-column label="教职工姓名">{{row.userName}}</table-column>
<table-column label="手机号码">{{row.mobile}}</table-column>
<table-column label="所属单位">{{row.unitName}}</table-column>
<table-column label="登记类型">
<dict-tag :options="dict.type.ENROLLMENT_REGISTRATION_TYPE"
:value="row.registrationType"></dict-tag>
</table-column>
<table-column label="填报时间">{{row.applyTime}}</table-column>
<table-column label="当前节点">{{row.curTaskName}}</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" v-if="row.taskState === 10" @click="onAudit(row)">
<i class="fa fa-edit"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
</template>
</table-list>
<h5-enrollment-registration-info ref="h5EnrollmentRegistrationInfoRef">
<div v-if="showApprovalForm">
<div class="process-title">
分工会审核
</div>
<div class="form-container">
<van-form ref="formRef">
<van-cell-group title="审批意见">
<van-field label=""
:rules="[{ required: true,message:'请填审批意见' }]"
v-model="formData.tf_opinion"
required
type="textarea"
name="tf_opinion"
rows="4"
autosize
class="more-text"
placeholder="请填审批意见"></van-field>
</van-cell-group>
<van-cell-group title="电子签名" class="form-section">
<van-field class="more-text" name="tf_userSign" label="">
<template #input>
<h5-signature v-model="formData.tf_userSign" slot="input"></h5-signature>
</template>
</van-field>
</van-cell-group>
<!-- 按钮区域 -->
<div class="form-actions">
<van-button type="danger" @click="handleTaskAction(6)">退回到发起人</van-button>
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
<van-button type="primary" @click="handleTaskAction(1)">同意申请</van-button>
</div>
</van-form>
</div>
</div>
</h5-enrollment-registration-info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../info.js'){}#-->
const vue = new Vue({
el: "#app",
store,
dicts: ["ENROLLMENT_REGISTRATION_TYPE", "ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP", "ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL"],
components: {
"h5-enrollment-registration-info": H5_ENROLLMENT_REGISTRATION_INFO
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
year: new Date().getFullYear(),
approvalText: "0",
approval: false,
searchName: "info.userName",
},
formData: {},
infoShow: false,
showApprovalForm: false,
}
},
methods: {
handleTaskAction(val) {
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要提交吗?',
}).then(() => {
this.$axios.post('/flow/common/executeTask', {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.$refs.h5EnrollmentRegistrationInfoRef.onClose()
}
})
}).catch(() => {
// on cancel
});
}).catch();
},
onAudit(row) {
this.showApprovalForm = true
this.formData = {
tf_opinion: null,
tf_userSign: null,
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.h5EnrollmentRegistrationInfoRef.onOpen(row)
},
onRevoke(row) {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要撤回吗?',
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.infoShow = false
}
})
}).catch(() => {
// on cancel
});
},
onView(row) {
this.showApprovalForm = false
this.$refs.h5EnrollmentRegistrationInfoRef.onOpen(row)
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,123 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
</style>
<div id="app">
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="体检项目选择" placeholder
fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-search
:reverse-color="false"
:show-action="false"
@search="doSearch"
input-align="left"
placeholder="请输入项目名称搜索"
v-model="pageForm.name"
></van-search>
<van-tabs v-model="pageForm.status"
@change="onStatusChange">
<van-tab title="进行中" name="ongoing"></van-tab>
<van-tab title="已结束" name="finished"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/healthCheckup/h5/pageData" :page_form.sync="pageForm" ref="tableListRef"
@ready="doSearch" img="cover">
<template v-slot="{index,row}">
<table-column label="开始时间">
{{$moment(row.choiceTimeStart).format('MM/DD HH:mm')}}
</table-column>
<table-column label="结束时间">
{{$moment(row.choiceTimeEnd).format('MM/DD HH:mm')}}
</table-column>
</template>
<template #actions="{index,row}">
<template v-if="$moment().isBefore($moment(row.choiceTimeEnd))">
<div class="action-btn" @click="onView(row)">
<i class="fa fa-edit"></i>
<span>去报名</span>
</div>
</template>
</template>
</table-list>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
store,
components: {
},
data() {
return {
yearList: [],
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
year: "",
status: "ongoing", // 默认为进行中
name: "" // 添加搜索名称字段
},
}
},
methods: {
// 查看项目详情
viewProjectDetail(row) {
// 这里可以添加查看项目详情的逻辑
console.log('查看项目详情:', row);
},
onView(row) {
/* if(row.selectCount > 0) {
vant.Dialog.alert({
title: '温馨提示',
message: '此项活动您已选择',
})
return
}*/
// 检查项目是否已结束
const now = new Date();
const endTime = new Date(row.choiceTimeEnd);
if (now > endTime) {
vant.Toast('报名已经结束');
return;
}
this.$pjaxReplace("/platform/healthCheckup/h5/projectManageForm?projectId=" + row.id)
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
// 新增状态切换处理方法
onStatusChange() {
this.doSearch();
},
initData() {
for (let i = new Date().getFullYear() - 10; i <= new Date().getFullYear(); i++) {
this.yearList.unshift({value: i, text: i + "年"})
}
this.$set(this.pageForm, "year", this.yearList[0].value)
// 初始化状态
this.$set(this.pageForm, "status", "ongoing")
},
},
created() {
this.initData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,122 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="我的体检" placeholder fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-tabs v-model="pageForm.status"
@change="onStatusChange">
<van-tab title="进行中" name="ongoing"></van-tab>
<van-tab title="已结束" name="finished"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/healthCheckup/h5/mineData" :page_form.sync="pageForm" ref="tableListRef"
@ready="doSearch" title="healthCheckupName">
<template v-slot="{index,row}">
<table-column label="项目名称">{{row.name}}</table-column>
<table-column label="开始时间">{{row.choiceTimeStart}}</table-column>
<table-column label="结束时间">{{row.choiceTimeEnd}}</table-column>
<table-column label="选择医院">{{row.optionName}}</table-column>
<table-column label="邮寄地址">{{row.receiveAddress}}</table-column>
</template>
<template #actions="{index,row}">
<div class="action-btn" @click="edit(row)" v-if="new Date().getTime() < new Date(row.choiceTimeEnd).getTime()">
<i class="fa fa-edit"></i>
<span>修改</span>
</div>
<div class="action-btn delete" @click="cancel(row)" v-if="new Date().getTime() < new Date(row.choiceTimeEnd).getTime()">
<i class="fa fa-trash"></i>
<span>取消</span>
</div>
</template>
</table-list>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
store,
components: {
},
data() {
return {
viewShow: false,
yearList: [],
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
year: "",
status: "ongoing", // 默认为进行中
name: "" // 添加搜索名称字段
},
}
},
methods: {
edit(row) {
this.$pjaxReplace("/platform/healthCheckup/h5/projectManageForm?projectId=" + row.projectId)
},
async cancel(o) {
vant.Dialog.confirm({
title: '温馨提醒',
message: '您确定要取消此选择吗?',
}).then(async () => {
const res = await $.post('/platform/healthCheckup/h5/cancel', {id: o.id, projectId: o.projectId})
if (res.code === 0) {
vant.Toast.success('取消成功')
this.doSearch()
} else {
vant.Toast(res.msg)
}
}).catch(() => {
})
},
tabChange(val) {
this.tabName = val
this.startLoading()
this.tableData = []
this.pageForm.pageNumber = 1
this.pageData()
this.closeLoading()
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
// 新增状态切换处理方法
onStatusChange() {
this.doSearch();
},
init() {
this.startLoading()
this.pageForm.tabName = 'ing'
this.pageData()
this.closeLoading()
},
initData() {
for (let i = new Date().getFullYear() - 10; i <= new Date().getFullYear(); i++) {
this.yearList.unshift({value: i, text: i + "年"})
}
this.$set(this.pageForm, "year", this.yearList[0].value)
// 初始化状态
this.$set(this.pageForm, "status", "ongoing")
},
},
created() {
this.initData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,516 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="体检套餐选择" placeholder
fixed></van-nav-bar>
<div class="form-container">
<van-form ref="formRef" @submit="doSubmit">
<van-cell-group title="基础信息">
<van-field
input-align="right"
label="身份证号"
name="idCard"
readonly
required
placeholder="请联系校工会补充身份证号"
v-model="formData.idCard"
:rules="[{ required: true, message: '请输入身份证号' }]">
</van-field>
<van-cell title="人员类型">{{formData.userState}}</van-cell>
<van-field
input-align="right"
readonly
required
label="婚姻状况"
name="marriage"
placeholder="请联系校工会补充婚姻状况"
v-model="formData.marriage"
:rules="[{ required: true, message: '请选择婚姻状况' }]"></van-field>
<van-cell title="出生年月">{{$moment(formData.birthday).format('YYYY-MM-DD')}}</van-cell>
<van-cell title="单位">{{formData.unitName}}</van-cell>
</van-cell-group>
<van-cell-group title="本年度预约体检医院">
<div class="van-card-body">
<van-radio-group v-model="formData.subjectId" class="basic">
<van-cell-group>
<van-cell
v-for="item in project.healthCheckupProjectSubjects"
:key="item.id"
:title="item.optionName">
<template #label>
<div style="display: flex; justify-content: space-between; margin-left: 8px">
<!-- <div>{{ item.optionName }}</div>-->
<div></div>
<div @click.stop="viewDesc(item)" style="color: #0e78c5">查看说明</div>
</div>
</template>
<template #right-icon>
<van-radio :name="item.id" @click.stop="clickRadio(item)"></van-radio>
</template>
</van-cell>
</van-cell-group>
</van-radio-group>
</div>
<van-field
input-align="right"
readonly
required
label="所选医院额度"
name="marriage"
placeholder="请选择医院"
v-model="formData.money"
:rules="[{ required: true, message: '请选择医院' }]"></van-field>
</van-cell-group>
<van-cell-group title="体检报告邮寄地址">
<van-radio-group v-model="formData.postMethod">
<van-cell-group>
<van-cell title="单位" clickable
@click="formData.postMethod = '1';formData.receiveAddress=formData.unitName">
<template #right-icon>
<van-radio name="1"></van-radio>
</template>
</van-cell>
<van-cell title="自选" clickable
@click="formData.postMethod = '2';formData.receiveAddress=''">
<template #right-icon>
<van-radio name="2"></van-radio>
</template>
</van-cell>
</van-cell-group>
</van-radio-group>
<template>
<van-field
v-if="formData.postMethod === '2'"
v-model="formData.receiveAddress"
label="邮寄地址"
placeholder="请选择邮寄地址"
readonly
type="textarea"
autosize
rows="2"
is-link
@click="editAddressPopup = true"
required
></van-field>
<van-cell title="邮寄地址" v-else>{{formData.receiveAddress}}</van-cell>
</template>
</van-cell-group>
<!-- <van-cell-group title="基础信息">
<div class="van-card-body">
<van-field
@click="campusVisible = true"
readonly
is-link
label="院区"
name="campus"
placeholder="请选择体检院区"
v-model="formData.campusName"
:rules="[{ required: true, message: '请选择体检院区' }]">
</van-field>
<van-field
:rules="[{ required: true, message: '请选择家属是否体检' }]"
label="家属体检"
name="isFamily">
<template #input>
<van-radio-group direction="horizontal" v-model="formData.isFamily">
<van-radio name="是" shape="square">是</van-radio>
<van-radio name="否" shape="square">否</van-radio>
</van-radio-group>
</template>
</van-field>
</div>
</van-cell-group>-->
<van-cell-group title="家属信息" v-if="formData.isFamily === '是'">
<div style="padding: 10px;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
<span>家属信息</span>
<div>
<van-tag @click="delCompanion" size="large" type="primary" color="lightgrey">
删除家属
</van-tag>
<van-tag @click="addCompanion" size="large" type="primary" color="#1867b0">
添加家属
</van-tag>
</div>
</div>
<div v-if="formData.companionList && formData.companionList.length > 0">
<van-tabs v-model="active" type="card" color="#0e78c5" animated>
<van-tab
v-for="(item, index) in formData.companionList"
:key="index"
:title="'家属' + (index + 1)">
<van-field
label="姓名"
name="userName"
placeholder="请填写姓名"
v-model="item.userName"
:rules="[{ required: true, message: '请填写姓名' }]">
</van-field>
<van-field
:rules="[{ required: true, message: '请选择性别' }]"
label="性别"
name="sex">
<template #input>
<van-radio-group direction="horizontal" v-model="item.sex">
<van-radio name="男" shape="square"></van-radio>
<van-radio name="女" shape="square"></van-radio>
</van-radio-group>
</template>
</van-field>
<van-field
:rules="[{ required: true, message: '请选择婚否' }]"
label="婚否"
name="marry">
<template #input>
<van-radio-group direction="horizontal" v-model="item.marry">
<van-radio name="未婚" shape="square">未婚</van-radio>
<van-radio name="已婚" shape="square">已婚</van-radio>
</van-radio-group>
</template>
</van-field>
<van-field
label="年龄"
name="age"
placeholder="请填写年龄"
type="digit"
:rules="[{ required: true, message: '请填写年龄' }]"
v-model="item.age">
</van-field>
<van-field
label="身份证号"
name="idCard"
placeholder="请填写身份证号"
type="digit"
:rules="[{ required: true, message: '请填写身份证号' }]"
v-model="item.idCard">
</van-field>
<van-field
label="手机号"
name="mobile"
placeholder="请填写手机号"
type="digit"
:rules="[{ required: true, message: '请填写手机号' }]"
v-model="item.mobile">
</van-field>
</van-tab>
</van-tabs>
</div>
<div v-else class="empty_text">
<span>如有家属,请添加家属</span>
</div>
</div>
</van-cell-group>
<!-- 按钮区域 -->
<div class="form-actions">
<van-button type="primary" native-type="submit">提交</van-button>
</div>
</van-form>
</div>
<!--体检院区弹出框-->
<van-action-sheet title="体检院区" v-model="campusVisible">
<van-picker
title="院区"
show-toolbar
:columns="campusList"
value-key="campusName"
@confirm="onCampusConfirm"
@cancel="campusVisible = false">
</van-picker>
</van-action-sheet>
<!--查看说明-->
<van-action-sheet title="医院说明" v-model="descVisible" :style="{ height: '60%' }">
<div class="form-container" style="margin: 10px;">
<van-cell-group title="说明"></van-cell-group>
<div v-html="desc" class="pre_text"></div>
<div style="margin-top: 10px">
<van-cell-group title="以下内容由医院方提供"></van-cell-group>
<file-preview :files="files" complete_result></file-preview>
</div>
</div>
</van-action-sheet>
<!-- 收货地址选择弹窗 -->
<van-action-sheet v-model="editAddressPopup" title="选择收货地址" :round="true">
<div style="padding: 16px 0 0">
<div
v-for="address in addressOptions"
:key="address.id"
class="address-item"
@click="selectAddress(address)"
style="padding: 12px 16px; border-bottom: 1px solid #f0f0f0; cursor: pointer"
>
<div style="display: flex; justify-content: space-between; align-items: flex-start">
<div style="flex: 1">
<div style="font-size: 16px; font-weight: 500; color: #323233; margin-bottom: 4px">
{{ address.userName }} {{ address.tel }}
</div>
<div style="font-size: 14px; color: #646566; line-height: 1.4">
{{ address.province }}{{ address.city }}{{ address.county }}{{ address.addressDetail
}}
</div>
</div>
<van-tag v-if="address.isDefault" type="primary" size="mini" style="margin-left: 8px">默认
</van-tag>
</div>
</div>
<div v-if="addressOptions.length === 0"
style="text-align: center; padding: 40px 16px; color: #969799">暂无收货地址
</div>
</div>
<div style="padding: 16px; border-top: 1px solid #f0f0f0; background: #fafafa">
<van-button type="info" block round @click="goToAddressManage">收货地址管理</van-button>
</div>
</van-action-sheet>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
store,
dicts: ["ASSET_USAGE_STATE"],
data() {
return {
viewData: {},
formData: {
subjectId: '',
campus: '',
campusName: '',
isFamily: '否',
companionList: [],
projectId: '',
postMethod: ''
},
assetUsageStateNameOption: [],
showAssetUsageStateNamePopup: false,
assetUseUserOption: [],
assetUseNameShow: false,
searchKeyword: "",
active: 0,
campusList: [],
campusVisible: false,
descVisible: false,
desc: '',
files: [],
project: {},
marriageList: ["已婚", "未婚"],
marriageVisible: false,
editAddressPopup: false,
addressOptions: []
}
},
methods: {
// 选择收货地址
selectAddress(address) {
this.formData.receiveAddress =
address.userName + " " + address.tel + " " + address.province + address.city + address.county + address.addressDetail
this.editAddressPopup = false
},
// 跳转到地址管理页面
goToAddressManage() {
this.$pjaxReplace("/platform/h5/welfare/address/list")
},
// 获取收货地址
getAddress() {
this.$axios.post("/platform/welfare/addressManage/selectUserAddress").then(resp => {
if (resp.code === 0) {
this.addressOptions = resp.data
}
})
},
isEmptyObject(obj) {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
return false
}
}
return true
},
addressClick() {
},
// 打开表单
async initData() {
await this.getCampus()
this.getAddress()
await this.findSubject(GetQueryString("projectId"))
if (GetQueryString("projectId")) {
await this.selectInfo(GetQueryString("projectId"));
const {idCard, userState, marriage, birthday, unit} = this.$store.state.user
this.$set(this.formData, 'projectId', GetQueryString("projectId"))
this.$set(this.formData, 'idCard', idCard)
this.$set(this.formData, 'userState', userState)
this.$set(this.formData, 'marriage', marriage)
this.$set(this.formData, 'birthday', birthday)
this.$set(this.formData, 'unitName', unit.name)
this.$set(this.formData, 'postMethod', this.formData?.postMethod ? this.formData.postMethod : "1")
this.$set(this.formData, 'receiveAddress', this.formData?.receiveAddress ? this.formData.receiveAddress : unit.name)
}
},
clickRadio(item) {
const toast = this.$toast.loading({
duration: 0, // 持续展示 toast
forbidClick: true,
message: '查询中....',
});
$.post("/platform/healthCheckup/h5/getSubjectMoney", {
id: item.id,
marriage: this.formData.marriage
}).then(resp => {
if (resp.code === 0) {
this.$set(this.formData, 'subjectId', item.id)
this.$set(this.formData, 'money', resp.data.money)
this.$set(this.formData, 'subjectMoneyId', resp.data.subjectMoneyId)
} else {
this.$set(this.formData, 'money', 0)
}
toast.clear();
})
},
async selectInfo(projectId) {
const resp = await this.$axios.post('/platform/healthCheckup/h5/selectInfo', {projectId: projectId});
if (resp.data !== null) {
this.formData = resp.data;
/* const o = this.campusList.find(o => o.id === this.formData.campus)
this.formData.campusName = o.campusName*/
}
},
// 查看说明
viewDesc(item) {
if (item.description || item.files) {
this.files = item.files;
this.desc = item.description;
this.descVisible = true;
} else {
vant.Toast('暂无详细说明');
}
},
// 执行提交
async doSubmit() {
const formData = clone(this.formData);
if (!formData.receiveAddress) {
this.$toast.fail('请填写邮寄地址!')
}
const subject = this.project.healthCheckupProjectSubjects.find(v => v.id === formData.subjectId)
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要提交选择的【' + subject.optionName + '】吗?',
}).then(() => {
const toast = this.$toast.loading({
duration: 0, // 持续展示 toast
forbidClick: true,
message: '提交中....',
});
/* if (formData.isFamily === '否') {
formData.companionList = [];
} else {
// 过滤空的家属信息
formData.companionList = formData.companionList.filter(item => item.userName && item.userName.trim() !== '');
}*/
this.$axios.post('/platform/healthCheckup/h5/doSubmit', {
userSelection: JSON.stringify(formData),
}).then(resp => {
if (resp.code === 0) {
toast.clear();
this.$toast.success(resp.msg)
this.historyBack()
}
})
}).catch(() => {
});
},
// 添加家属
addCompanion() {
// 检查是否已达到最大数量限制
if (this.companionList && this.formData.companionList.length >= 5) {
vant.Toast('最多只能添加5个家属');
return;
}
if (!this.formData.companionList) {
this.$set(this.formData, 'companionList', []);
}
this.formData.companionList.push({
userName: '', sex: '', marry: '', age: '', idCard: '', mobile: ''
});
},
// 删除家属
delCompanion() {
if (this.formData.companionList && this.formData.companionList.length > 0) {
this.formData.companionList.splice(this.active, 1);
// 确保active索引有效
if (this.active >= this.formData.companionList.length && this.active > 0) {
this.active = this.formData.companionList.length - 1;
}
}
},
// 院区选择确认
onCampusConfirm(value) {
this.formData.campusName = value.campusName;
this.formData.campus = value.id;
this.campusVisible = false;
},
// 婚姻状况确认
onMarriageConfirm(value) {
this.$set(this.formData, 'marriage', value)
this.$set(this.formData, 'subjectId', null)
this.marriageVisible = false;
},
// 查询体检套餐
async findSubject(id) {
try {
const resp = await this.$axios.post('/platform/healthCheckup/project/mange/findOne', {
id: id
});
this.project = resp.data || {};
} catch (error) {
vant.Toast('获取体检套餐失败');
}
},
// 获取院区
async getCampus() {
try {
const resp = await this.$axios.post('/platform/healthCheckup/h5/getCampus');
this.campusList = resp.data || [];
} catch (error) {
vant.Toast('获取院区失败');
}
}
},
created() {
this.initData()
}
})
</script>
<!--#
}
#-->
@@ -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/literacy/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/literacy/apply/list/h5?id=' + row.id)
},
fetchOne() {
this.$axios.post('/platform/literacy/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/literacy/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/literacy/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/literacy/apply/validateSignUp", {
courseId: this.formData.courseId,
currentFamilyNumber: familyCount
})
return res.code === 0
},
async validateCourseTime() {
const res = await this.$axios.post('/platform/literacy/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/literacy/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,index in assortList" :name="item" :title="item" :key="index">
</van-tab>
</van-tabs>
<table-list api="/platform/literacy/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/literacy/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/literacy/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/literacy/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/literacy/manage/findOne', {id: this.pageForm.activityId})
.then((res) => {
this.activity = res.data
})
},
async getCourseTypeList() {
const resp = await this.$axios.post("/platform/literacy/type/getAllType")
return resp.data
},
queryCourseAssort() {
this.$axios.post("/platform/literacy/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/literacy/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/literacy/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>
<!--#
}
#-->
@@ -0,0 +1,77 @@
const leaveInfo = {
template:
/*language=HTML*/
`
<van-action-sheet v-model="visible" title="查看详情">
<div class="detail-container">
<van-cell-group title="基本信息">
<van-cell title="请假人姓名">{{ viewData.userName }}</van-cell>
<van-cell title="请假人工号">{{ viewData.loginName }}</van-cell>
<van-cell title="所属单位">{{ viewData.unitName }}</van-cell>
<van-cell title="所属工会">{{ viewData.unionName }}</van-cell>
<van-cell title="会议名称">{{ viewData.periodName }}</van-cell>
<van-cell title="开始时间">{{ viewData.startTime }}</van-cell>
<van-cell title="结束时间">{{ viewData.endTime }}</van-cell>
<van-cell title="请假事由" class="direction-column-cell">{{ viewData.leaveReason }}</van-cell>
<van-cell title="所属会议">{{ viewData.meetingName }}</van-cell>
<van-cell title="会议类型">{{ viewData.typeName }}</van-cell>
</van-cell-group>
<template v-for="task in doneTasks">
<van-cell-group :title="task.displayName" v-if="task.ext.isFirstTaskNode">
<van-cell title="申请用户">{{ task.ext.initiatorName }}({{task.ext.initiatorAccount}})
</van-cell>
<van-cell title="申请时间">{{ task.finishTime }}</van-cell>
<van-cell title="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag>
</van-cell>
</van-cell-group>
<van-cell-group :title="task.displayName" v-else>
<van-cell title="办理用户">{{ task.taskFormData.userName }}({{task.taskFormData.loginName}})
</van-cell>
<van-cell title="办理时间">{{ task.finishTime }}</van-cell>
<van-cell title="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag>
</van-cell>
<van-cell title="办理意见" v-if="!task.ext.isFirstTaskNode" class="direction-column-cell">
<div v-html="task.taskFormData.tf_opinion"></div>
</van-cell>
</van-cell-group>
</template>
</div>
<slot></slot>
</van-action-sheet>
`,
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
visible:false,
viewData: {},
doneTasks: [],
row: null,
}
},
methods: {
onOpen(row) {
row.leaveReason = JSON.parse(row.instanceVariable).f_data.leaveReason || ''
this.row = row
this.visible = true
this.viewData = clone(row)
this.getDoneTasks()
},
onClose(){
this.visible = false
},
getDoneTasks() {
this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data
}
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,96 @@
const meetingInfo = {
template: /*language=HTML*/ `
<div>
<van-action-sheet v-model="visible" title="会议信息">
<div class="detail-container">
<van-cell-group title="基本信息">
<van-cell title="会议名称">{{ viewData.name }}</van-cell>
<van-cell title="会议地点">{{ viewData.address }}</van-cell>
<van-cell title="会议类型">{{ viewData.typeName }}</van-cell>
<van-cell title="会议描述" class="direction-column-cell">
<span v-html="viewData.description"></span>
</van-cell>
</van-cell-group>
<van-cell-group title="场次信息" v-if="viewData.timePeriods && viewData.timePeriods.length > 0">
<table class="table-class">
<thead>
<tr>
<th>场次名称</th>
<th>开始时间</th>
<th>结束时间</th>
<th>是否可以请假</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in viewData.timePeriods" :key="index">
<td>{{ item.periodName }}</td>
<td>{{ item.startTime }}</td>
<td>{{ item.endTime }}</td>
<td>{{ item.canLeave ? '是' : '否' }}</td>
</tr>
</tbody>
</table>
</van-cell-group>
<van-cell-group title="会议参与人员" v-if="viewData.users && viewData.users.length > 0">
<table class="table-class">
<thead>
<tr>
<th>工号</th>
<th>姓名</th>
<th>性别</th>
<th>所属单位</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in viewData.users" :key="index">
<td>{{ item.loginName }}</td>
<td>{{ item.userName }}</td>
<td>{{ item.sex }}</td>
<td>{{ item.unitName }}</td>
</tr>
</tbody>
</table>
</van-cell-group>
</div>
</van-action-sheet>
</div>
`,
data() {
return {
viewData: {},
visible: false
}
},
methods: {
onOpen(row) {
this.$axios.post('/platform/meeting/manage/info', {id: row.id}).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
this.visible = true
},
},
style: /*language=CSS*/ `
/deep/ .table-class{
width: 100%;
border-radius: 5px;
overflow: hidden;
line-height: 1.5rem;
font-size: 13px;
table-layout: fixed;
border-collapse: collapse;
}
/deep/ .table-class th {
background-color: #f2f2f2;
border: 1px solid #dddddd;
}
/deep/ .table-class tr {
text-align: center;
border-bottom: 1px solid #dddddd;
}
/deep/ .table-class td {
border: 1px solid #dddddd;
}
`
}
@@ -0,0 +1,190 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
</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-search
v-model="pageForm.searchKeyword"
:show-action="false"
:reverse-color="false"
input-align="left"
placeholder="请输入名称或地点查询"
@search="doSearch"
></van-search>
<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.type" :options="typeOptions" :multiple="false"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.approval = val==='1';this.doSearch();}">
<van-tab title="已审核" name="1"></van-tab>
<van-tab title="未审核" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/meeting/delegationApproval/pageData" :page_form.sync="pageForm" ref="tableListRef" title="periodName" @ready="onReady">
<template v-slot="{index,row}">
<table-column label="开始时间">{{row.startTime}}</table-column>
<table-column label="结束时间">{{row.endTime}}</table-column>
<table-column label="请假人">{{row.userName}}</table-column>
<table-column label="请假事由">{{JSON.parse(row.instanceVariable).f_data.leaveReason || ''}}</table-column>
<table-column label="所属会议">{{row.meetingName}}</table-column>
<table-column label="会议类型">{{row.typeName}}</table-column>
<table-column label="当前节点">{{row.curTaskName}}</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" v-if="row.taskState === 10" @click="onApproval(row)">
<i class="fa fa-edit"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-reply"></i>
<span>撤回</span>
</div>
</template>
</table-list>
<leave-info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">{{formData.taskName}}</div>
<van-form ref="formRef">
<van-field
v-model="formData.tf_opinion"
name="tf_opinion"
label="审批意见"
placeholder="请输入审批意见"
:rules="[{ required: true, message: '请填写审批意见' }]"
required
maxlength="100"
show-word-limit
></van-field>
</van-form>
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button type="danger" block @click="handleTaskAction(6)">退回</van-button>
<van-button type="danger" block @click="handleTaskAction(20)">不同意</van-button>
<van-button type="primary" block @click="handleTaskAction(1)">同意</van-button>
</div>
</div>
</leave-info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../common/leaveInfo.js'){}#-->
new Vue({
el: "#app",
store,
components: {
'leave-info': leaveInfo,
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: '',
approvalText: "0",
approval: false,
year: new Date().getFullYear(),
type: null,
},
typeOptions: [],
formData: {},
showApprovalForm: false
}
},
methods: {
async onReady() {
const typeList = await this.queryMeetingType()
this.typeOptions = [
{
text: "全部类型",
value: null
}
].concat(typeList.map((v) => ({ text: v.name, value: v.id })))
if (this.typeOptions.length > 0) {
this.pageForm.type = this.typeOptions[0].value
this.doSearch()
}
},
onView(row) {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
},
onApproval(row) {
this.showApprovalForm = true
this.$refs.infoRef.onOpen(row)
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
},
async handleTaskAction(val) {
try {
await this.$refs.formRef.validate();
this.$dialog.confirm({
title: "提示",
message: "您确定要提交吗?"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.infoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
}
})
}).catch(() => {
})
} catch (error) {
}
},
onRevoke(row){
this.$dialog.confirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
}
})
})
},
async queryMeetingType() {
const res = await this.$axios.post('/platform/meeting/type/queryMeetingType')
return res.data
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
},
})
</script>
<!--#
}
#-->
@@ -0,0 +1,197 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
</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-search
v-model="pageForm.searchKeyword"
:show-action="false"
:reverse-color="false"
input-align="left"
placeholder="请输入名称或地点查询"
@search="doSearch"
></van-search>
<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.type" :options="typeOptions" :multiple="false"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
</van-sticky>
<table-list api="/platform/meeting/leave/pageData" :page_form.sync="pageForm" ref="tableListRef" title="periodName" @ready="onReady">
<template v-slot="{index,row}">
<table-column label="开始时间">{{row.startTime}}</table-column>
<table-column label="结束时间">{{row.endTime}}</table-column>
<table-column label="请假人">{{row.userName}}</table-column>
<table-column label="请假事由">{{JSON.parse(row.instanceVariable).f_data.leaveReason || ''}}</table-column>
<table-column label="所属会议">{{row.meetingName}}</table-column>
<table-column label="会议类型">{{row.typeName}}</table-column>
<table-column label="当前节点">{{row.taskName}}</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="onEdit(row)"
v-if="row.taskKey === 'startTask' || !row.instanceId">
<i class="fa fa-edit"></i>
<span>编辑</span>
</div>
<div class="action-btn delete" @click="onRevoke(row)"
v-if="row.canRevoke">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
<div class="action-btn delete" @click="onDelete(row)"
v-if="row.taskKey === 'startTask' || !row.instanceId">
<i class="fa fa-trash"></i>
<span>删除</span>
</div>
</template>
</table-list>
<van-dialog v-model="visible" title="请假事由" show-cancel-button
:before-close="handleBeforeClose">
<van-field
style="padding: 20px 16px"
v-model="leaveReason"
label="请假事由"
placeholder="请输入请假事由"
required
rows="1"
autosize
type="textarea"
></van-field>
</van-dialog>
<leave-info ref="infoRef"></leave-info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../common/leaveInfo.js'){}#-->
new Vue({
el: "#app",
store,
components: {
'leave-info': leaveInfo,
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
year: new Date().getFullYear(),
type: null
},
typeOptions: [],
visible: false,
leaveReason: '',
editRow: {},
}
},
methods: {
async onReady() {
const typeList = await this.queryMeetingType()
this.typeOptions = [
{
text: "全部类型",
value: null
}
].concat(typeList.map((v) => ({ text: v.name, value: v.id })))
if (this.typeOptions.length > 0) {
this.pageForm.type = this.typeOptions[0].value
this.doSearch()
}
},
handleBeforeClose(action, done) {
if (action === 'confirm') {
if(!this.leaveReason) {
this.$toast('请输入请假事由')
done(false)
} else {
this.$axios.post("/platform/meeting/mine/submitAgain", {
id: this.editRow.id,
leaveReason: this.leaveReason,
taskId: this.editRow.taskId
})
.then((res) => {
done()
this.$toast(res.msg)
if (res.code === 0) {
this.doSearch()
this.reasonVisible = false
}
}).catch(() => { done() })
}
} else {
done()
}
},
onRevoke(row) {
this.$dialog.confirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", { taskId: row.startTaskId }).then((res) => {
if (res.code === 0) {
this.$toast(res.msg)
this.doSearch()
}
})
})
},
onView(row) {
this.$refs.infoRef.onOpen(row)
},
onEdit(row) {
if(!row.canLeave) {
this.$toast.success('该场次不能请假')
return
}
this.editRow = row
this.visible = true
},
onDelete(row) {
this.$dialog.confirm({
title: "提示",
message: "确定要删除此申请吗?"
})
.then(() => {
this.$axios.post("/platform/meeting/leave/delete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
} else {
this.$toast.fail(res.msg)
}
})
})
.catch(() => {})
},
async queryMeetingType() {
const res = await this.$axios.post('/platform/meeting/type/queryMeetingType')
return res.data
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
},
})
</script>
<!--#
}
#-->
@@ -0,0 +1,194 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
.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-search
v-model="pageForm.searchKeyword"
:show-action="false"
:reverse-color="false"
input-align="left"
placeholder="请输入名称或地点查询"
@search="doSearch"
></van-search>
<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.type" :options="typeOptions" :multiple="false"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
</van-sticky>
<table-list api="/platform/meeting/mine/pageData" :page_form.sync="pageForm" ref="tableListRef" title="name" @ready="onReady">
<template v-slot="{index,row}">
<table-column label="会议类型">{{row.typeName}}</table-column>
<table-column label="会议地点">{{row.address}}</table-column>
<table-column label="创建时间">{{row.createTime}}</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="leaveRow = row; leaveVisible = true">
<i class="fa fa-edit"></i>
<span>展开</span>
</div>
</template>
</table-list>
<van-action-sheet title="会议信息" v-model="leaveVisible" cancel-text="取消" close-on-click-action>
<button v-for="(item,index) in leaveRow.timePeriods" 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">{{item.periodName}}</div>
<div class="van-action-sheet__subname">
{{$moment(item.startTime).format('MM-DD HH:mm') + ' 至 ' + $moment(item.endTime).format('MM-DD HH:mm')}}
</div>
</div>
<div class="sign_button">
<van-button v-if="item.joinStatus === true" @click.stop="onLeave(item)" size="mini" type="info">请假</van-button>
<van-button v-if="item.joinStatus === false" size="mini" type="info" disabled>您已请假</van-button>
<van-button v-if="item.signStatus === false" @click.stop="onSign(item)" size="mini" type="info">签到</van-button>
<van-button v-if="item.signStatus === true" size="mini" type="info" disabled>您已签到</van-button>
</div>
</div>
</button>
</van-action-sheet>
<van-dialog v-model="reasonVisible" title="请假事由" show-cancel-button
:before-close="handleBeforeClose">
<van-field
style="padding: 20px 16px"
v-model="leaveReason"
label="请假事由"
placeholder="请输入请假事由"
required
rows="1"
autosize
type="textarea"
></van-field>
</van-dialog>
<meeting-info ref="infoRef"></meeting-info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../common/meetingInfo.js'){}#-->
new Vue({
el: "#app",
store,
components: {
'meeting-info': meetingInfo,
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
year: new Date().getFullYear(),
type: null
},
typeOptions: [],
leaveRow: {},
leaveVisible: false,
reasonVisible: false,
leaveReason: '',
periodRow: {},
}
},
methods: {
async onReady() {
const typeList = await this.queryMeetingType()
this.typeOptions = [
{
text: "全部类型",
value: null
}
].concat(typeList.map((v) => ({ text: v.name, value: v.id })))
if (this.typeOptions.length > 0) {
this.pageForm.siteType = this.typeOptions[0].value
this.doSearch()
}
},
handleBeforeClose(action, done) {
if (action === 'confirm') {
if(!this.leaveReason) {
this.$toast('请输入请假事由')
done(false)
} else {
this.$axios.post("/platform/meeting/mine/leave", {
periodId: this.periodRow.id,
leaveReason: this.leaveReason,
})
.then((res) => {
done()
this.$toast(res.msg)
if (res.code === 0) {
this.doSearch()
this.reasonVisible = false
}
}).catch(() => { done() })
}
} else {
done()
}
},
onLeave(row) {
if(!row.canLeave) {
this.$toast('该场次不能请假')
return
}
this.periodRow = row
this.reasonVisible = true
},
onSign(row) {
this.$dialog.confirm({
title: "提示",
message: "您确定要签到吗?"
}).then(() => {
this.$axios.post("/platform/meeting/mine/sign", { periodId: row.id })
.then((res) => {
this.$toast(res.msg)
if (res.code === 0) {
this.doSearch()
this.leaveVisible = false
}
})
})
},
onView(row) {
this.$refs.infoRef.onOpen(row)
},
async queryMeetingType() {
const res = await this.$axios.post('/platform/meeting/type/queryMeetingType')
return res.data
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
},
})
</script>
<!--#
}
#-->
@@ -0,0 +1,190 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
</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-search
v-model="pageForm.searchKeyword"
:show-action="false"
:reverse-color="false"
input-align="left"
placeholder="请输入名称或地点查询"
@search="doSearch"
></van-search>
<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.type" :options="typeOptions" :multiple="false"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.approval = val==='1';this.doSearch();}">
<van-tab title="已审核" name="1"></van-tab>
<van-tab title="未审核" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/meeting/schoolUnionApproval/pageData" :page_form.sync="pageForm" ref="tableListRef" title="periodName" @ready="onReady">
<template v-slot="{index,row}">
<table-column label="开始时间">{{row.startTime}}</table-column>
<table-column label="结束时间">{{row.endTime}}</table-column>
<table-column label="请假人">{{row.userName}}</table-column>
<table-column label="请假事由">{{JSON.parse(row.instanceVariable).f_data.leaveReason || ''}}</table-column>
<table-column label="所属会议">{{row.meetingName}}</table-column>
<table-column label="会议类型">{{row.typeName}}</table-column>
<table-column label="当前节点">{{row.curTaskName}}</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" v-if="row.taskState === 10" @click="onApproval(row)">
<i class="fa fa-edit"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-reply"></i>
<span>撤回</span>
</div>
</template>
</table-list>
<leave-info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">{{formData.taskName}}</div>
<van-form ref="formRef">
<van-field
v-model="formData.tf_opinion"
name="tf_opinion"
label="审批意见"
placeholder="请输入审批意见"
:rules="[{ required: true, message: '请填写审批意见' }]"
required
maxlength="100"
show-word-limit
></van-field>
</van-form>
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button type="danger" block @click="handleTaskAction(6)">退回</van-button>
<van-button type="danger" block @click="handleTaskAction(20)">不同意</van-button>
<van-button type="primary" block @click="handleTaskAction(1)">同意</van-button>
</div>
</div>
</leave-info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../common/leaveInfo.js'){}#-->
new Vue({
el: "#app",
store,
components: {
'leave-info': leaveInfo,
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: '',
approvalText: "0",
approval: false,
year: new Date().getFullYear(),
type: null,
},
typeOptions: [],
formData: {},
showApprovalForm: false
}
},
methods: {
async onReady() {
const typeList = await this.queryMeetingType()
this.typeOptions = [
{
text: "全部类型",
value: null
}
].concat(typeList.map((v) => ({ text: v.name, value: v.id })))
if (this.typeOptions.length > 0) {
this.pageForm.type = this.typeOptions[0].value
this.doSearch()
}
},
onView(row) {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
},
onApproval(row) {
this.showApprovalForm = true
this.$refs.infoRef.onOpen(row)
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
},
async handleTaskAction(val) {
try {
await this.$refs.formRef.validate();
this.$dialog.confirm({
title: "提示",
message: "您确定要提交吗?"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.infoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
}
})
}).catch(() => {
})
} catch (error) {
}
},
onRevoke(row){
this.$dialog.confirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
}
})
})
},
async queryMeetingType() {
const res = await this.$axios.post('/platform/meeting/type/queryMeetingType')
return res.data
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
},
})
</script>
<!--#
}
#-->
@@ -0,0 +1,464 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
</style>
<div id="app">
<!-- 导航栏 -->
<van-nav-bar title="报销申请" left-text="返回" left-arrow
@click-left="historyBack" fixed></van-nav-bar>
<!-- 表单容器 -->
<div class="form-container">
<van-form ref="formRef">
<van-cell-group title="活动类型">
<van-field
:rules="[{ required: true }]"
v-model="formData.outlayManageSourceName"
label="活动类型"
placeholder="请选择活动类型"
required
is-link
readonly
@click="showOutlayManageSourcePopup = true"
></van-field>
<van-popup v-model="showOutlayManageSourcePopup" position="bottom">
<van-picker
show-toolbar
:columns="budgetTypeOption.map(i => i.name)"
@confirm="onOutlayManageSourceConfirm"
@cancel="showOutlayManageSourcePopup = false"
></van-picker>
</van-popup>
</van-cell-group>
<van-cell-group title="申请人信息">
<van-field label="申请人姓名" :rules="[{ required: true }]" v-model="formData.userName" readonly
required></van-field>
<van-field label="申请人工号" :rules="[{ required: true }]" v-model="formData.loginName" readonly
required></van-field>
<van-field label="手机号码" name="mobile" :rules="[{ required: true }]" v-model="formData.mobile"
required
placeholder="请输入手机号码"
maxlength="11"
type="tel"></van-field>
<van-field
:rules="[{ required: true }]"
v-model="formData.clubName"
label="所属协会"
placeholder="请选择所属协会"
required
is-link
readonly
@click="showClubNamePopup = true"
v-if="['ACTIVITY_BUDGET_TYPE_THREE'].includes(formData.outlayManageSource)"
></van-field>
<van-popup v-model="showClubNamePopup" position="bottom">
<van-picker
show-toolbar
:columns="clubOption.map(i => i.clubName)"
@confirm="onClubNameConfirm"
@cancel="showClubNamePopup = false"
></van-picker>
</van-popup>
<van-field label="经费余额" :rules="[{ required: true }]" v-model="budgetMoney" readonly
required></van-field>
<van-field label="活动事项" name="activityMatter"
:rules="[{ required: true }]"
v-model="formData.activityMatter"
required
maxlength="50"
placeholder="请输入活动事项"
v-if="['ACTIVITY_BUDGET_TYPE_THREE'].includes(formData.outlayManageSource)"></van-field>
<van-field
:rules="[{ required: true }]"
v-model="formData.budgetName"
label="活动事项"
placeholder="请选择活动事项"
required
is-link
readonly
@click="showBudgetNamePopup = true"
v-if="!['ACTIVITY_BUDGET_TYPE_THREE'].includes(formData.outlayManageSource)"
></van-field>
<van-popup v-model="showBudgetNamePopup" position="bottom">
<van-picker
show-toolbar
:columns="activityList.map(i => i.activityMatter)"
@confirm="onBudgetNameConfirm"
@cancel="showBudgetNamePopup = false"
></van-picker>
</van-popup>
<van-field label="活动人数" name="activityNumber"
:rules="[{ required: true }]"
v-model="formData.activityNumber"
required
maxlength="4"
placeholder="请输入活动人数"
type="digit"></van-field>
<van-field label="金额" name="money"
:rules="[{ required: true }]"
v-model="formData.money"
required
:placeholder="moneyPlaceholder"
type="number"></van-field>
<van-field label="活动时间"
name="activityTime"
:rules="[{ required: true }]"
:value="formData.activityTime"
readonly
is-link
placeholder="请填写活动时间"
required
@click="showActivityTimePopup = true"></van-field>
<van-popup v-model="showActivityTimePopup" position="bottom">
<van-datetime-picker
v-model="formData.activityTimeDate"
type="date"
title="选择活动时间"
:max-date="activityTimeMaxDate"
@confirm="onActivityTimeConfirm"
@cancel="showActivityTimePopup=false"
></van-datetime-picker>
</van-popup>
<van-field label="支付内容"
:rules="[{ required: true }]"
v-model="formData.paymentContent"
required
type="textarea"
name="paymentContent"
rows="4"
autosize
maxlength="500"
class="more-text"
placeholder="请填写支付内容"></van-field>
</van-cell-group>
<van-cell-group title="附件">
<van-field class="more-text" name="files"
:rules="[{ required: true,message:'请上传附件' }]"
label="" required>
<template #input>
<h5-file-upload
slot="input"
:value.sync="formData.files"
:upload_number="10"
upload_mode="file"
upload_result_category="array"
upload_result_type="url"
complete_result
></h5-file-upload>
</template>
</van-field>
</van-cell-group>
<van-cell-group title="电子签名">
<van-field class="more-text"
name="userSign"
label=""
required>
<template #input>
<h5-signature v-model="formData.userSign" slot="input"></h5-signature>
</template>
</van-field>
</van-cell-group>
<!-- 按钮区域 -->
<div class="form-actions">
<van-button native-type="button" plain type="info" @click="onSave">保存</van-button>
<van-button type="primary" @click="onSubmit" v-if="!taskId">提交</van-button>
<van-button type="primary" @click="onFinishTask" v-else>提交</van-button>
</div>
</van-form>
</div>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
store,
dicts: ["ACTIVITY_BUDGET_TYPE"],
data() {
return {
bizId: GetQueryString("bizId"),
taskId: GetQueryString("taskId"),
formData: {},
moneyPlaceholder: "请输入金额",
budgetMoney: 0,
budgetTypeOption: [],
showOutlayManageSourcePopup: false,
clubOption: [],
showClubNamePopup: false,
activityList: [],
showBudgetNamePopup: false,
showActivityTimePopup: false,
activityTimeMaxDate: new Date(),
}
},
methods: {
onSave() {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定保存吗?',
}).then(() => {
this.$axios.post('/platform/outlay/reimburse/apply/save', {
data: JSON.stringify(this.formData)
}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
pjaxReplace("/platform/outlay/reimburse/applyList/h5")
}
})
}).catch(() => {
// on cancel
});
},
onSubmit() {
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要提交吗?',
}).then(() => {
this.$axios.post('/platform/outlay/reimburse/apply/submit', {
data: JSON.stringify(this.formData),
taskId: GetQueryString("taskId")
}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
pjaxReplace("/platform/outlay/reimburse/applyList/h5")
}
})
}).catch(() => {
});
}).catch();
},
onFinishTask() {
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要提交吗?',
}).then(() => {
this.$axios.post('/platform/outlay/reimburse/apply/submitAgain', {
data: JSON.stringify(this.formData),
taskId: GetQueryString("taskId")
}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
pjaxReplace("/platform/outlay/reimburse/applyList/h5")
}
})
}).catch(() => {
// on cancel
});
}).catch();
},
onActivityTimeConfirm(value, index) {
this.formData.activityTimeDate = value
this.formData.activityTime = this.$moment(value).format("YYYY-MM-DD")
this.showActivityTimePopup = false
},
async budgetIdChange(val) {
if (val) {
if (["ACTIVITY_BUDGET_TYPE_TWO", "ACTIVITY_BUDGET_TYPE_ONE"].includes(this.formData.outlayManageSource)) {
//如果是分工会和校工会
const data = this.activityList.find(a => a.id === val)
if (this.formData.outlayManageSource === "ACTIVITY_BUDGET_TYPE_TWO") {
//如果是分工会
const money = await this.getBxMoneyByBudgetId(val)
if (data.isSchoolBudget) {
//如果这一条分工会活动预算金额是属于校工会的
this.moneyPlaceholder = "预算金额" + data.totalBudgetMoney + "元,已报销金额:" + money
} else {
//如果这一条分工会活动活动,并且预算金额也是自己分工会的
if (data.isRepeatReimburse) {
//如果这一条活动预算可以重复报销
this.moneyPlaceholder = "预算金额:" + data.totalBudgetMoney + "元,已报销金额:" + money + ",不能超过20%"
} else {
//如果如果不能重复报销暂无判断
}
}
} else {
//如果是校工会
if (data.twoLevelBudgetList.length > 0) {
//如果大于0代表肯定有分工会使用校工会的预算,这里要减去分工会的预算
this.moneyPlaceholder = "预算金额:" + data.totalBudgetMoney + "元,已报销金额:" + data.twoLevelTotalBudgetMoney
} else {
if (data.isRepeatReimburse) {
const money = await this.getBxMoneyByBudgetId(val)
this.moneyPlaceholder = "预算金额:" + data.totalBudgetMoney + "元,已报销金额:" + money + ",不能超过20%"
} else {
//如果如果不能重复报销暂无判断
}
}
}
this.totalBudgetMoney = data.totalBudgetMoney
this.$set(this.formData, 'activityMatter', data.activityMatter)
} else {
this.moneyPlaceholder = "预算金额" + this.budgetMoney + "元"
this.totalBudgetMoney = this.budgetMoney
this.$set(this.formData, 'activityMatter', val)
}
} else {
this.moneyPlaceholder = "请输入金额"
this.totalBudgetMoney = 0
this.$set(this.formData, 'activityMatter', null)
}
},
async getBxMoneyByBudgetId(budgetId) {
const resp = await this.$axios.post("/platform/outlay/reimburse/apply/getBxMoneyByBudgetId", {
budgetId
})
if (resp.code === 0) {
return resp.data
} else {
return 0
}
},
async onBudgetNameConfirm(value, index) {
this.formData.budgetId = this.activityList[index].id;
this.formData.budgetName = value;
await this.budgetIdChange(this.formData.budgetId)
this.showBudgetNamePopup = false
},
async onClubNameConfirm(value, index) {
this.formData.clubId = this.clubOption[index].id;
this.formData.clubName = value;
await this.getBudgetMoneyOrActivity();
this.showClubNamePopup = false
},
async onOutlayManageSourceConfirm(value, index) {
this.formData.outlayManageSource = this.budgetTypeOption[index].code;
this.formData.outlayManageSourceName = value;
if (!this.formData.outlayManageSource) {
this.budgetMoney = 0
return
}
this.$set(this.formData, "budgetId", null)
this.$set(this.formData, "clubId", null)
this.$set(this.formData, "clubName", null)
await this.getBudgetMoneyOrActivity()
if (this.formData.outlayManageSource === "ACTIVITY_BUDGET_TYPE_TWO") {
this.$set(this.formData, "unionId", this.$store.state.user.union.id)
}
this.showOutlayManageSourcePopup = false;
},
async getBudgetMoneyOrActivity() {
const resp = await this.$axios.post("/platform/outlay/reimburse/apply/getBudgetMoneyOrActivity", {
outlayManageSource: this.formData.outlayManageSource,
clubId: this.formData.clubId,
unionId: this.formData.unionId,
id: this.formData.id
})
if (resp.code === 0) {
this.budgetMoney = resp.data.budgetMoney
this.activityList = resp.data.activityList
}
},
async findOne(id) {
const resp = await $.get('/platform/outlay/reimburse/apply/findOne', {id})
if (resp.code === 0) {
return resp.data
}
},
async init() {
this.clubOption = await this.$businessTool.listCLubByRole()
this.budgetTypeOption = await this.$businessTool.getDictOptions("ACTIVITY_BUDGET_TYPE")
const budgetTypeOption = []
if (this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])) {
} else {
if (this.$auth.hasRoleOr(["SCHOOL_OUTLAY_ADMIN", "SCHOOL_UNION_ADMIN"])) {
this.budgetTypeOption.map(v => {
if (["ACTIVITY_BUDGET_TYPE_ONE"].includes(v.code)) {
budgetTypeOption.push(v)
}
})
}
if (this.$auth.hasRoleOr(["BRANCH_UNION_CHAIRMAN", "BRANCH_UNION_ADMIN"])) {
this.budgetTypeOption.map(v => {
if (["ACTIVITY_BUDGET_TYPE_TWO"].includes(v.code)) {
budgetTypeOption.push(v)
}
})
}
if (this.$auth.hasRoleOr(["CLUB_MANAGER", "CLUB_PRESIDENT"])) {
this.budgetTypeOption.map(v => {
if (["ACTIVITY_BUDGET_TYPE_THREE"].includes(v.code)) {
budgetTypeOption.push(v)
}
})
}
this.budgetTypeOption = budgetTypeOption
}
if (this.bizId) {
this.findOne(this.bizId).then(async data => {
this.formData = data
await this.getBudgetMoneyOrActivity()
if (data.budgetId) {
await this.budgetIdChange(data.budgetId)
}
//活动时间回显
if (data.activityTime) {
this.$set(this.formData, "activityTimeDate", new Date(data.activityTime))
}
//活动类型
const outlayManageSource = this.dict.type.ACTIVITY_BUDGET_TYPE.find(v => v.code === data.outlayManageSource)
if (outlayManageSource) {
this.$set(this.formData, "outlayManageSourceName", outlayManageSource.name)
}
if (data.budgetId) {
const activity= this.activityList.find(v => v.id === data.budgetId)
this.$set(this.formData, "budgetName", activity.activityMatter)
}
})
} else {
const {id, username, loginname, mobile, union, unit} = this.$store.state.user
this.formData = {
userId: id,
userName: username,
loginName: loginname,
unitName: unit.name,
unitId: unit.id,
unionName: union.name,
unionId: union.id,
mobile: mobile,
}
}
}
},
created() {
this.init()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,136 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<!-- 导航栏 -->
<van-nav-bar title="我的申请" left-text="返回" left-arrow placeholder
@click-left="historyBack" fixed></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-menu>
</van-sticky>
<table-list api="/platform/outlay/reimburse/applyList/pageData" :page_form.sync="pageForm"
ref="tableListRef"
@ready="doSearch" title="taskName">
<template v-slot="{index,row}">
<table-column label="经办人工号">{{row.loginName}}</table-column>
<table-column label="姓名">{{row.userName}}</table-column>
<table-column label="活动类型">
<dict-tag :options="dict.type.ACTIVITY_BUDGET_TYPE"
:value="row.outlayManageSource"></dict-tag>
</table-column>
<table-column label="活动事项">{{row.activityMatter}}</table-column>
<table-column label="申报单位">
<span v-if="['ACTIVITY_BUDGET_TYPE_ONE'].includes(row.outlayManageSource)">校工会</span>
<span v-if="['ACTIVITY_BUDGET_TYPE_TWO'].includes(row.outlayManageSource)">{{row.unionName}}</span>
<span v-if="['ACTIVITY_BUDGET_TYPE_THREE','ACTIVITY_BUDGET_TYPE_FOUR'].includes(row.outlayManageSource)">{{row.clubName}}</span>
</table-column>
<table-column label="金额">{{row.money}}</table-column>
<table-column label="申请时间">{{row.applyTime}}</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="onEdit(row)">
<i class="fa fa-edit"></i>
<span>编辑</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
<div class="action-btn delete" @click="onDelete(row.id)"
v-if="row.taskKey === 'startTask' || !row.instanceId">
<i class="fa fa-trash"></i>
<span>删除</span>
</div>
</template>
</table-list>
<h5-outlay-reimburse-info ref="h5OutlayReimburseInfo"></h5-outlay-reimburse-info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../info.js'){}#-->
const vue = new Vue({
el: "#app",
store,
dicts: ["ACTIVITY_BUDGET_TYPE"],
components: {
"h5-outlay-reimburse-info": H5_OUTLAY_REIMBURSE_INFO
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
year: new Date().getFullYear(),
},
}
},
methods: {
onView(row) {
this.$refs.h5OutlayReimburseInfo.onOpen(row)
},
onEdit(row) {
pjaxReplace('/platform/outlay/reimburse/apply/h5?taskId=' + (row.startTaskId || '') + "&bizId=" + row.id)
},
onDelete(id) {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要删除吗?',
}).then(() => {
this.$axios.post("/platform/outlay/reimburse/applyList/doDelete", {id}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
} else {
this.$toast.fail(res.msg)
}
})
}).catch(() => {
// on cancel
});
},
onRevoke(row) {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要撤回吗?',
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.startTaskId}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
} else {
this.$toast.fail(res.msg)
}
})
}).catch(() => {
// on cancel
});
},
doSearch() {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
},
},
created() {
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,185 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="协会审核" placeholder
fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-search
:reverse-color="false"
:show-action="false"
@search="doSearch"
input-align="left"
placeholder="请输入姓名搜索"
v-model="pageForm.searchKeyword"
></van-search>
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.approval = val==='1';this.doSearch();}">
<van-tab title="已审核" name="1"></van-tab>
<van-tab title="未审核" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/outlay/reimburse/clubAudit/pageData" :page_form.sync="pageForm"
ref="tableListRef"
title="curTaskName" @ready="doSearch">
<template v-slot="{index,row}">
<table-column label="经办人工号">{{row.loginName}}</table-column>
<table-column label="姓名">{{row.userName}}</table-column>
<table-column label="活动类型">
<dict-tag :options="dict.type.ACTIVITY_BUDGET_TYPE"
:value="row.outlayManageSource"></dict-tag>
</table-column>
<table-column label="活动事项">{{row.activityMatter}}</table-column>
<table-column label="申报单位">
<span v-if="['ACTIVITY_BUDGET_TYPE_ONE'].includes(row.outlayManageSource)">校工会</span>
<span v-if="['ACTIVITY_BUDGET_TYPE_TWO'].includes(row.outlayManageSource)">{{row.unionName}}</span>
<span v-if="['ACTIVITY_BUDGET_TYPE_THREE','ACTIVITY_BUDGET_TYPE_FOUR'].includes(row.outlayManageSource)">{{row.clubName}}</span>
</table-column>
<table-column label="金额">{{row.money}}</table-column>
<table-column label="申请时间">{{row.applyTime}}</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" v-if="row.taskState === 10" @click="onAudit(row)">
<i class="fa fa-edit"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
</template>
</table-list>
<h5-outlay-reimburse-info ref="h5OutlayReimburseInfo">
<div v-if="showApprovalForm">
<div class="process-title">{{formData.taskName}}</div>
<div class="form-container">
<van-form ref="formRef">
<van-field label="审批意见"
:rules="[{ required: true,message:'请填审批意见' }]"
v-model="formData.tf_opinion"
required
type="textarea"
name="tf_opinion"
rows="4"
autosize
placeholder="请填审批意见"></van-field>
<van-field name="tf_userSign" label="签字">
<template #input>
<h5-signature v-model="formData.tf_userSign" slot="input"></h5-signature>
</template>
</van-field>
<!-- 按钮区域 -->
<div class="form-actions">
<van-button @click="handleTaskAction(6)">退回到发起人</van-button>
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
<van-button type="primary" @click="handleTaskAction(1)">同意申请</van-button>
</div>
</van-form>
</div>
</div>
</h5-outlay-reimburse-info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../info.js'){}#-->
const vue = new Vue({
el: "#app",
store,
dicts: ["ACTIVITY_BUDGET_TYPE"],
components: {
"h5-outlay-reimburse-info": H5_OUTLAY_REIMBURSE_INFO
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
year: new Date().getFullYear(),
approvalText: "0",
approval: false,
searchName: "info.userName",
},
formData: {},
infoShow: false,
showApprovalForm: false,
}
},
methods: {
handleTaskAction(val) {
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要提交吗?',
}).then(() => {
this.$axios.post('/platform/outlay/reimburse/clubAudit/submit', {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.$refs.h5OutlayReimburseInfo.onClose()
}
})
}).catch(() => {
// on cancel
});
}).catch();
},
onAudit(row) {
this.showApprovalForm = true
this.formData = {
tf_opinion: null,
tf_userSign: null,
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.h5OutlayReimburseInfo.onOpen(row)
},
onRevoke(row) {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要撤回吗?',
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.infoShow = false
}
})
}).catch(() => {
// on cancel
});
},
onView(row) {
this.showApprovalForm = false
this.$refs.h5OutlayReimburseInfo.onOpen(row)
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,185 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="协会分管主席审核" placeholder
fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-search
:reverse-color="false"
:show-action="false"
@search="doSearch"
input-align="left"
placeholder="请输入姓名搜索"
v-model="pageForm.searchKeyword"
></van-search>
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.approval = val==='1';this.doSearch();}">
<van-tab title="已审核" name="1"></van-tab>
<van-tab title="未审核" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/outlay/reimburse/clubZxAudit/pageData" :page_form.sync="pageForm"
ref="tableListRef"
title="curTaskName" @ready="doSearch">
<template v-slot="{index,row}">
<table-column label="经办人工号">{{row.loginName}}</table-column>
<table-column label="姓名">{{row.userName}}</table-column>
<table-column label="活动类型">
<dict-tag :options="dict.type.ACTIVITY_BUDGET_TYPE"
:value="row.outlayManageSource"></dict-tag>
</table-column>
<table-column label="活动事项">{{row.activityMatter}}</table-column>
<table-column label="申报单位">
<span v-if="['ACTIVITY_BUDGET_TYPE_ONE'].includes(row.outlayManageSource)">校工会</span>
<span v-if="['ACTIVITY_BUDGET_TYPE_TWO'].includes(row.outlayManageSource)">{{row.unionName}}</span>
<span v-if="['ACTIVITY_BUDGET_TYPE_THREE','ACTIVITY_BUDGET_TYPE_FOUR'].includes(row.outlayManageSource)">{{row.clubName}}</span>
</table-column>
<table-column label="金额">{{row.money}}</table-column>
<table-column label="申请时间">{{row.applyTime}}</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" v-if="row.taskState === 10" @click="onAudit(row)">
<i class="fa fa-edit"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
</template>
</table-list>
<h5-outlay-reimburse-info ref="h5OutlayReimburseInfo">
<div v-if="showApprovalForm">
<div class="process-title">{{formData.taskName}}</div>
<div class="form-container">
<van-form ref="formRef">
<van-field label="审批意见"
:rules="[{ required: true,message:'请填审批意见' }]"
v-model="formData.tf_opinion"
required
type="textarea"
name="tf_opinion"
rows="4"
autosize
placeholder="请填审批意见"></van-field>
<van-field name="tf_userSign" label="签字">
<template #input>
<h5-signature v-model="formData.tf_userSign" slot="input"></h5-signature>
</template>
</van-field>
<!-- 按钮区域 -->
<div class="form-actions">
<van-button @click="handleTaskAction(6)">退回到发起人</van-button>
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
<van-button type="primary" @click="handleTaskAction(1)">同意申请</van-button>
</div>
</van-form>
</div>
</div>
</h5-outlay-reimburse-info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../info.js'){}#-->
const vue = new Vue({
el: "#app",
store,
dicts: ["ACTIVITY_BUDGET_TYPE"],
components: {
"h5-outlay-reimburse-info": H5_OUTLAY_REIMBURSE_INFO
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
year: new Date().getFullYear(),
approvalText: "0",
approval: false,
searchName: "info.userName",
},
formData: {},
infoShow: false,
showApprovalForm: false,
}
},
methods: {
handleTaskAction(val) {
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要提交吗?',
}).then(() => {
this.$axios.post('/flow/common/executeTask', {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.$refs.h5OutlayReimburseInfo.onClose()
}
})
}).catch(() => {
// on cancel
});
}).catch();
},
onAudit(row) {
this.showApprovalForm = true
this.formData = {
tf_opinion: null,
tf_userSign: null,
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.h5OutlayReimburseInfo.onOpen(row)
},
onRevoke(row) {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要撤回吗?',
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.infoShow = false
}
})
}).catch(() => {
// on cancel
});
},
onView(row) {
this.showApprovalForm = false
this.$refs.h5OutlayReimburseInfo.onOpen(row)
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,146 @@
const H5_OUTLAY_REIMBURSE_INFO = {
template: /*language=HTML*/ `
<van-action-sheet v-model="visible" title="查看详情">
<div>
<div class="process-title">申请信息</div>
<van-cell-group>
<van-cell title="申请人">
{{ viewData.userName }}
</van-cell>
<van-cell title="工号">
{{ viewData.loginName }}
</van-cell>
<van-cell title="联系方式">
{{ viewData.mobile }}
</van-cell>
<van-cell title="预算类型">
<dict-tag :options="dict.type.ACTIVITY_BUDGET_TYPE"
:value="viewData.outlayManageSource"></dict-tag>
</van-cell>
<van-cell title="预算类型">
{{viewData.activityMatter}}
</van-cell>
<van-cell title="申请金额">
{{viewData.money}}
</van-cell>
<van-cell title="活动时间">
{{viewData.activityTime}}
</van-cell>
<van-cell title="活动人数">
{{viewData.activityNumber}}
</van-cell>
<van-cell title="支付内容">
<div style="white-space: pre-line">{{viewData.paymentContent}}</div>
</van-cell>
<van-cell title="附件">
<template #label>
<template v-for="(item,index) in viewData.files">
<van-image :src="item.url"
v-if="item.url"
class="signature-image"
@click="previewOptionImg(viewData.files,index)"></van-image>
</template>
</template>
</van-cell>
<van-cell title="签字" >
<van-image :src="viewData.userSign"
class="signature-image"></van-image>
</van-cell>
</van-cell-group>
<template v-for="(task,index) in doneTasks">
<div class="process-title">
{{ task.displayName }}
</div>
<van-cell-group v-if="task.ext.isFirstTaskNode">
<van-cell title="申请用户">
{{ task.ext.initiatorName}}({{task.ext.initiatorAccount}})
</van-cell>
<van-cell title="申请时间">
{{ task.finishTime}}
</van-cell>
<van-cell title="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag>
</van-cell>
</van-cell-group>
<van-cell-group v-else>
<van-cell title="办理用户">
{{ task.taskFormData.userName}}({{task.taskFormData.loginName}})
</van-cell>
<van-cell title="办理时间">
{{ task.finishTime}}
</van-cell>
<van-cell title="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag>
</van-cell>
<van-cell title="办理意见" v-if="!task.ext.isFirstTaskNode">
<template #label>
{{
task.taskFormData.opinion
}}
</template>
</van-cell>
<van-cell title="签字" v-if="!task.ext.isFirstTaskNode">
<van-image :src="task.ext.tf_userSign"
v-if="task.ext.tf_userSign"
class="signature-image"></van-image>
</van-cell>
</van-cell-group>
</template>
<slot></slot>
</div>
</van-action-sheet>
`,
dicts: ["PROCESS_TASK_SUBMIT_TYPE","ACTIVITY_BUDGET_TYPE","ACTIVITY_BUDGET_DETAILS_TYPE"],
data() {
return {
visible: false,
viewData: {},
doneTasks: [],
row: null
}
},
methods: {
//预览图片
previewOptionImg(files, index) {
const urls = files.map(item => item.url)
vant.ImagePreview({images: urls, startPosition: index})
},
// 打开
onOpen(row) {
this.row = row
this.visible = true
this.getInfo()
this.getDoneTasks()
},
// 关闭
onClose() {
this.visible = false
},
// 获取申请信息
getInfo() {
this.$axios.post('/platform/outlay/reimburse/apply/findOne', {id: this.row.id}).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
// 获取已办任务审批记录
getDoneTasks() {
this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data
}
})
},
}
}
@@ -0,0 +1,185 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="校工会出纳审核" placeholder
fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-search
:reverse-color="false"
:show-action="false"
@search="doSearch"
input-align="left"
placeholder="请输入姓名搜索"
v-model="pageForm.searchKeyword"
></van-search>
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.approval = val==='1';this.doSearch();}">
<van-tab title="已审核" name="1"></van-tab>
<van-tab title="未审核" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/outlay/reimburse/schoolCnAudit/pageData" :page_form.sync="pageForm"
ref="tableListRef"
title="curTaskName" @ready="doSearch">
<template v-slot="{index,row}">
<table-column label="经办人工号">{{row.loginName}}</table-column>
<table-column label="姓名">{{row.userName}}</table-column>
<table-column label="活动类型">
<dict-tag :options="dict.type.ACTIVITY_BUDGET_TYPE"
:value="row.outlayManageSource"></dict-tag>
</table-column>
<table-column label="活动事项">{{row.activityMatter}}</table-column>
<table-column label="申报单位">
<span v-if="['ACTIVITY_BUDGET_TYPE_ONE'].includes(row.outlayManageSource)">校工会</span>
<span v-if="['ACTIVITY_BUDGET_TYPE_TWO'].includes(row.outlayManageSource)">{{row.unionName}}</span>
<span v-if="['ACTIVITY_BUDGET_TYPE_THREE','ACTIVITY_BUDGET_TYPE_FOUR'].includes(row.outlayManageSource)">{{row.clubName}}</span>
</table-column>
<table-column label="金额">{{row.money}}</table-column>
<table-column label="申请时间">{{row.applyTime}}</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" v-if="row.taskState === 10" @click="onAudit(row)">
<i class="fa fa-edit"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
</template>
</table-list>
<h5-outlay-reimburse-info ref="h5OutlayReimburseInfo">
<div v-if="showApprovalForm">
<div class="process-title">{{formData.taskName}}</div>
<div class="form-container">
<van-form ref="formRef">
<van-field label="审批意见"
:rules="[{ required: true,message:'请填审批意见' }]"
v-model="formData.tf_opinion"
required
type="textarea"
name="tf_opinion"
rows="4"
autosize
placeholder="请填审批意见"></van-field>
<van-field name="tf_userSign" label="签字">
<template #input>
<h5-signature v-model="formData.tf_userSign" slot="input"></h5-signature>
</template>
</van-field>
<!-- 按钮区域 -->
<div class="form-actions">
<van-button @click="handleTaskAction(6)">退回到发起人</van-button>
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
<van-button type="primary" @click="handleTaskAction(1)">同意申请</van-button>
</div>
</van-form>
</div>
</div>
</h5-outlay-reimburse-info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../info.js'){}#-->
const vue = new Vue({
el: "#app",
store,
dicts: ["ACTIVITY_BUDGET_TYPE"],
components: {
"h5-outlay-reimburse-info": H5_OUTLAY_REIMBURSE_INFO
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
year: new Date().getFullYear(),
approvalText: "0",
approval: false,
searchName: "info.userName",
},
formData: {},
infoShow: false,
showApprovalForm: false,
}
},
methods: {
handleTaskAction(val) {
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要提交吗?',
}).then(() => {
this.$axios.post('/flow/common/executeTask', {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.$refs.h5OutlayReimburseInfo.onClose()
}
})
}).catch(() => {
// on cancel
});
}).catch();
},
onAudit(row) {
this.showApprovalForm = true
this.formData = {
tf_opinion: null,
tf_userSign: null,
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.h5OutlayReimburseInfo.onOpen(row)
},
onRevoke(row) {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要撤回吗?',
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.infoShow = false
}
})
}).catch(() => {
// on cancel
});
},
onView(row) {
this.showApprovalForm = false
this.$refs.h5OutlayReimburseInfo.onOpen(row)
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,207 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="校工会会计审核" placeholder
fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-search
:reverse-color="false"
:show-action="false"
@search="doSearch"
input-align="left"
placeholder="请输入姓名搜索"
v-model="pageForm.searchKeyword"
></van-search>
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.approval = val==='1';this.doSearch();}">
<van-tab title="已审核" name="1"></van-tab>
<van-tab title="未审核" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/outlay/reimburse/schoolKjAudit/pageData"
:page_form.sync="pageForm"
ref="tableListRef"
title="curTaskName" @ready="doSearch">
<template v-slot="{index,row}">
<table-column label="经办人工号">{{row.loginName}}</table-column>
<table-column label="姓名">{{row.userName}}</table-column>
<table-column label="活动类型">
<dict-tag :options="dict.type.ACTIVITY_BUDGET_TYPE"
:value="row.outlayManageSource"></dict-tag>
</table-column>
<table-column label="活动事项">{{row.activityMatter}}</table-column>
<table-column label="申报单位">
<span v-if="['ACTIVITY_BUDGET_TYPE_ONE'].includes(row.outlayManageSource)">校工会</span>
<span v-if="['ACTIVITY_BUDGET_TYPE_TWO'].includes(row.outlayManageSource)">{{row.unionName}}</span>
<span v-if="['ACTIVITY_BUDGET_TYPE_THREE','ACTIVITY_BUDGET_TYPE_FOUR'].includes(row.outlayManageSource)">{{row.clubName}}</span>
</table-column>
<table-column label="金额">{{row.money}}</table-column>
<table-column label="申请时间">{{row.applyTime}}</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" v-if="row.taskState === 10" @click="onAudit(row)">
<i class="fa fa-edit"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
</template>
</table-list>
<h5-outlay-reimburse-info ref="h5OutlayReimburseInfo">
<div v-if="showApprovalForm">
<div class="process-title">{{formData.taskName}}</div>
<div class="form-container">
<van-form ref="formRef">
<van-field label="审批意见"
:rules="[{ required: true,message:'请填审批意见' }]"
v-model="formData.tf_opinion"
required
type="textarea"
name="tf_opinion"
rows="4"
autosize
placeholder="请填审批意见"></van-field>
<van-field name="tf_userSign" label="签字">
<template #input>
<h5-signature v-model="formData.tf_userSign" slot="input"></h5-signature>
</template>
</van-field>
<van-popup v-model="showDetailsTypePopup" position="bottom">
<van-picker
show-toolbar
:columns="detailsTypeOption.map(i => i.name)"
@confirm="onDetailsTypeConfirm"
@cancel="showDetailsTypePopup = false"
></van-picker>
</van-popup>
<!-- 按钮区域 -->
<div class="form-actions">
<van-button @click="handleTaskAction(6)">退回到发起人</van-button>
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
<van-button type="primary" @click="openHandleTaskAction">同意申请</van-button>
</div>
</van-form>
</div>
</div>
</h5-outlay-reimburse-info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../info.js'){}#-->
const vue = new Vue({
el: "#app",
store,
dicts: ["ACTIVITY_BUDGET_TYPE"],
components: {
"h5-outlay-reimburse-info": H5_OUTLAY_REIMBURSE_INFO
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
year: new Date().getFullYear(),
approvalText: "0",
approval: false,
searchName: "info.userName",
},
formData: {},
detailsTypeOption: [],
showApprovalForm: false,
showDetailsTypePopup: false,
}
},
methods: {
async openHandleTaskAction() {
await this.$refs.formRef.validate();
this.detailsTypeOption = await this.$businessTool.getDictOptions("ACTIVITY_BUDGET_DETAILS_TYPE")
this.showDetailsTypePopup = true
},
onDetailsTypeConfirm(value, index) {
this.formData.detailsType = this.detailsTypeOption[index].value
this.handleTaskAction(1)
},
handleTaskAction(val) {
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要提交吗?',
}).then(() => {
this.$axios.post('/flow/common/executeTask', {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.$refs.h5OutlayReimburseInfo.onClose()
this.showDetailsTypePopup = false
}
})
}).catch(() => {
// on cancel
});
}).catch();
},
onAudit(row) {
this.showApprovalForm = true
this.formData = {
tf_opinion: null,
tf_userSign: null,
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.h5OutlayReimburseInfo.onOpen(row)
},
onRevoke(row) {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要撤回吗?',
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.infoShow = false
}
})
}).catch(() => {
// on cancel
});
},
onView(row) {
this.showApprovalForm = false
this.$refs.h5OutlayReimburseInfo.onOpen(row)
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,185 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="校工会主席终审" placeholder
fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-search
:reverse-color="false"
:show-action="false"
@search="doSearch"
input-align="left"
placeholder="请输入姓名搜索"
v-model="pageForm.searchKeyword"
></van-search>
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.approval = val==='1';this.doSearch();}">
<van-tab title="已审核" name="1"></van-tab>
<van-tab title="未审核" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/outlay/reimburse/schoolZxAudit/pageData" :page_form.sync="pageForm"
ref="tableListRef"
title="curTaskName" @ready="doSearch">
<template v-slot="{index,row}">
<table-column label="经办人工号">{{row.loginName}}</table-column>
<table-column label="姓名">{{row.userName}}</table-column>
<table-column label="活动类型">
<dict-tag :options="dict.type.ACTIVITY_BUDGET_TYPE"
:value="row.outlayManageSource"></dict-tag>
</table-column>
<table-column label="活动事项">{{row.activityMatter}}</table-column>
<table-column label="申报单位">
<span v-if="['ACTIVITY_BUDGET_TYPE_ONE'].includes(row.outlayManageSource)">校工会</span>
<span v-if="['ACTIVITY_BUDGET_TYPE_TWO'].includes(row.outlayManageSource)">{{row.unionName}}</span>
<span v-if="['ACTIVITY_BUDGET_TYPE_THREE','ACTIVITY_BUDGET_TYPE_FOUR'].includes(row.outlayManageSource)">{{row.clubName}}</span>
</table-column>
<table-column label="金额">{{row.money}}</table-column>
<table-column label="申请时间">{{row.applyTime}}</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" v-if="row.taskState === 10" @click="onAudit(row)">
<i class="fa fa-edit"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
</template>
</table-list>
<h5-outlay-reimburse-info ref="h5OutlayReimburseInfo">
<div v-if="showApprovalForm">
<div class="process-title">{{formData.taskName}}</div>
<div class="form-container">
<van-form ref="formRef">
<van-field label="审批意见"
:rules="[{ required: true,message:'请填审批意见' }]"
v-model="formData.tf_opinion"
required
type="textarea"
name="tf_opinion"
rows="4"
autosize
placeholder="请填审批意见"></van-field>
<van-field name="tf_userSign" label="签字">
<template #input>
<h5-signature v-model="formData.tf_userSign" slot="input"></h5-signature>
</template>
</van-field>
<!-- 按钮区域 -->
<div class="form-actions">
<van-button @click="handleTaskAction(6)">退回到发起人</van-button>
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
<van-button type="primary" @click="handleTaskAction(1)">同意申请</van-button>
</div>
</van-form>
</div>
</div>
</h5-outlay-reimburse-info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../info.js'){}#-->
const vue = new Vue({
el: "#app",
store,
dicts: ["ACTIVITY_BUDGET_TYPE"],
components: {
"h5-outlay-reimburse-info": H5_OUTLAY_REIMBURSE_INFO
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
year: new Date().getFullYear(),
approvalText: "0",
approval: false,
searchName: "info.userName",
},
formData: {},
infoShow: false,
showApprovalForm: false,
}
},
methods: {
handleTaskAction(val) {
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要提交吗?',
}).then(() => {
this.$axios.post('/flow/common/executeTask', {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.$refs.h5OutlayReimburseInfo.onClose()
}
})
}).catch(() => {
// on cancel
});
}).catch();
},
onAudit(row) {
this.showApprovalForm = true
this.formData = {
tf_opinion: null,
tf_userSign: null,
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.h5OutlayReimburseInfo.onOpen(row)
},
onRevoke(row) {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要撤回吗?',
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.infoShow = false
}
})
}).catch(() => {
// on cancel
});
},
onView(row) {
this.showApprovalForm = false
this.$refs.h5OutlayReimburseInfo.onOpen(row)
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,185 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="分工会审核" placeholder
fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-search
:reverse-color="false"
:show-action="false"
@search="doSearch"
input-align="left"
placeholder="请输入姓名搜索"
v-model="pageForm.searchKeyword"
></van-search>
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.approval = val==='1';this.doSearch();}">
<van-tab title="已审核" name="1"></van-tab>
<van-tab title="未审核" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/outlay/reimburse/unionAudit/pageData" :page_form.sync="pageForm"
ref="tableListRef"
title="curTaskName" @ready="doSearch">
<template v-slot="{index,row}">
<table-column label="经办人工号">{{row.loginName}}</table-column>
<table-column label="姓名">{{row.userName}}</table-column>
<table-column label="活动类型">
<dict-tag :options="dict.type.ACTIVITY_BUDGET_TYPE"
:value="row.outlayManageSource"></dict-tag>
</table-column>
<table-column label="活动事项">{{row.activityMatter}}</table-column>
<table-column label="申报单位">
<span v-if="['ACTIVITY_BUDGET_TYPE_ONE'].includes(row.outlayManageSource)">校工会</span>
<span v-if="['ACTIVITY_BUDGET_TYPE_TWO'].includes(row.outlayManageSource)">{{row.unionName}}</span>
<span v-if="['ACTIVITY_BUDGET_TYPE_THREE','ACTIVITY_BUDGET_TYPE_FOUR'].includes(row.outlayManageSource)">{{row.clubName}}</span>
</table-column>
<table-column label="金额">{{row.money}}</table-column>
<table-column label="申请时间">{{row.applyTime}}</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" v-if="row.taskState === 10" @click="onAudit(row)">
<i class="fa fa-edit"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
</template>
</table-list>
<h5-outlay-reimburse-info ref="h5OutlayReimburseInfo">
<div v-if="showApprovalForm">
<div class="process-title">{{formData.taskName}}</div>
<div class="form-container">
<van-form ref="formRef">
<van-field label="审批意见"
:rules="[{ required: true,message:'请填审批意见' }]"
v-model="formData.tf_opinion"
required
type="textarea"
name="tf_opinion"
rows="4"
autosize
placeholder="请填审批意见"></van-field>
<van-field name="tf_userSign" label="签字">
<template #input>
<h5-signature v-model="formData.tf_userSign" slot="input"></h5-signature>
</template>
</van-field>
<!-- 按钮区域 -->
<div class="form-actions">
<van-button @click="handleTaskAction(6)">退回到发起人</van-button>
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
<van-button type="primary" @click="handleTaskAction(1)">同意申请</van-button>
</div>
</van-form>
</div>
</div>
</h5-outlay-reimburse-info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../info.js'){}#-->
const vue = new Vue({
el: "#app",
store,
dicts: ["ACTIVITY_BUDGET_TYPE"],
components: {
"h5-outlay-reimburse-info": H5_OUTLAY_REIMBURSE_INFO
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
year: new Date().getFullYear(),
approvalText: "0",
approval: false,
searchName: "info.userName",
},
formData: {},
infoShow: false,
showApprovalForm: false,
}
},
methods: {
handleTaskAction(val) {
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要提交吗?',
}).then(() => {
this.$axios.post('/flow/common/executeTask', {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.$refs.h5OutlayReimburseInfo.onClose()
}
})
}).catch(() => {
// on cancel
});
}).catch();
},
onAudit(row) {
this.showApprovalForm = true
this.formData = {
tf_opinion: null,
tf_userSign: null,
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.h5OutlayReimburseInfo.onOpen(row)
},
onRevoke(row) {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要撤回吗?',
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.infoShow = false
}
})
}).catch(() => {
// on cancel
});
},
onView(row) {
this.showApprovalForm = false
this.$refs.h5OutlayReimburseInfo.onOpen(row)
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,95 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="问卷列表" placeholder fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-tabs v-model="pageForm.category" @change="doSearch">
<van-tab v-for="item in dict.type.ACTIVITY_QSV_CATEGORY" :name="item.code" :title="item.label"
:key="item.code"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/h5/qsv/pageData" :page_form.sync="pageForm" ref="tableListRef" title="title"
@ready="doSearch">
<!-- <template #header="{index,row}"></template>-->
<template v-slot="{index,row}">
<table-column label="开始时间">{{row.startTime}}</table-column>
<table-column label="结束时间">{{row.endTime}}</table-column>
</template>
<template #actions="{index,row}">
<div class="action-btn" @click="onEnter(row)">
<i class="fa fa-eye"></i>
<span>查看</span>
</div>
</template>
</table-list>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
dicts: ['ACTIVITY_QSV_CATEGORY'],
store,
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
category: "QUIZ"
},
categoryPaths: {
QUIZ: "/platform/h5/qsv/quiz",
SURVEY: "/platform/h5/qsv/survey",
VOTE: "/platform/h5/qsv/vote"
}
}
},
methods: {
historyBack() {
this.$pjaxReplace('/platform/h5/home')
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
async onEnter(item) {
debugger
if (item.groupId) {
const {
code,
data
} = await $.get('/platform/activity/basic/scope/getScopeUser', {activityGroupId: item.groupId})
if (code === 0 && data === 0) {
this.$toast.fail("您没有权限参与")
return
}
}
const {startTime, endTime} = item
if (this.$moment(startTime).unix() > this.$moment().unix()) {
this.$toast("未开始")
return
}
const path = this.categoryPaths[item.category]
if (path) {
pjaxReplace(path + "?id=" + item.id)
}
}
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,406 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="问卷列表" placeholder fixed></van-nav-bar>
<div class="container" :style="{'padding-bottom': answerRecord.isFinish ? 0 : '84px'}">
<van-sticky offset-top="46px">
<!--开启计时 未完成 活动未结束-->
<div class="timer" v-if="activity.timeLimit > 0 && !answerRecord.isFinish && !isEnd">⏰{{ remainingTime }}s
</div>
<h2 class="title">{{ activity.title }}</h2>
</van-sticky>
<div v-if="!answerRecord.isFinish">
<div v-for="(subject, index) in subjects" :key="index" class="subject">
<p>{{index+1}}、{{ subject.title }}</p>
<div class="tag">
<van-tag v-if="subject.type === 'checkbox'" type="primary" size="large">多选</van-tag>
<van-tag v-if="subject.type === 'radio'" type="primary" size="large">单选</van-tag>
<van-tag v-if="subject.score" type="primary" size="large">{{subject.score}}分</van-tag>
</div>
<van-checkbox-group v-model="subject.userSelectOptionIds" :ref="'subject'+subject.id">
<van-cell-group>
<van-cell
v-for="(option,index) in subject.options"
clickable
:key="option.id"
:title="option.text"
@click="cellToggle(subject,option.id)"
>
<template #icon>
<van-checkbox
:name="option.id"
:ref="'option'+option.id"
:disabled="answerRecord.isFinish"
:shape="subject.type==='checkbox' ? 'square' : 'round'"
style="margin-right: 10px"
></van-checkbox>
</template>
</van-cell>
</van-cell-group>
</van-checkbox-group>
</div>
<div class="button-control" v-if="!answerRecord.isFinish">
<van-button type="info" @click="onSubmit" block :disabled="isEnd">{{isEnd ? '已结束' : '提交'}}
</van-button>
</div>
</div>
</div>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
store,
data() {
return {
list: [],
id: GetQueryString("id"),
H5JumpTo: GetQueryString("H5JumpTo"),
subjects: [],
activity: {},
isFinished: false,
answerRecord: {},
answerRecordId: null,
//历史记录
historyScores: [],
//答题用时
answerTime: 0
}
},
computed: {
isEnd() {
if (this.activity) {
return this.$moment().unix() > this.$moment(this.activity.endTime).unix()
}
return true
},
remainingTime() {
if (this.activity && this.activity.timeLimit > 0) {
return this.activity.timeLimit * 60 - this.answerTime
}
return 0
}
},
methods: {
//获取活动、题目
listSubjects() {
this.$axios.post("/platform/h5/qsv/quiz/subjects", {activityId: this.id}).then((res) => {
if (res.code === 0) {
this.activity = res.data.activity
this.subjects = res.data.subjects
this.answerRecordId = res.data.answerRecordId
// this.checkGroupPermission()
if (!this.H5JumpTo && this.activity.repeatable && res.data.repeatTips) {
// 如果是可重复答题,第二次答题进来弹出提示
vant.Dialog.confirm({
title: '温馨提示',
message: '您已完成本次答题,是否要重新答题?',
confirmButtonText: '重新答题',
cancelButtonText: '查看答题记录',
}).then(() => {
this.getAnswerRecord()
}).catch(() => {
pjaxReplace("/platform/h5/qsv/quiz/result?answerRecordId=" + this.answerRecordId)
// pjaxReplace("/mobile/index")
});
} else {
this.getAnswerRecord()
}
} else {
vant.Dialog.alert({
title: '温馨提示',
message: res.msg,
}).then(() => {
pjaxReplace("/mobile/index")
})
}
})
},
//获取回答记录
getAnswerRecord() {
this.$axios.post("/platform/h5/qsv/quiz/answerRecord", {answerRecordId: this.answerRecordId}).then((res) => {
if (res.code === 0) {
this.answerRecord = res.data
if (this.answerRecord.isFinish || this.$moment().unix() > this.$moment(this.activity.endTime)) {
pjaxReplace("/platform/h5/qsv/quiz/result?answerRecordId=" + this.answerRecordId)
}
this.initAnswer()
this.checkTimer()
}
})
},
//答案回显
initAnswer() {
this.subjects.forEach((subject, subjectIndex) => {
if (subject.type === "radio") {
this.$refs["subject" + subject.id][0].toggleAll(false)
}
if (this.answerRecord.optionIds) {
this.answerRecord.optionIds[subjectIndex].forEach((optionId) => {
this.$refs["option" + optionId][0].toggle()
})
}
})
},
historyBack() {
if (this.timerInterval) {
clearInterval(this.timerInterval)
}
historyBack()
},
//答题计时器
checkTimer() {
if (this.timerInterval) {
clearInterval(this.timerInterval)
}
//开启计时
const startInterval = () => {
this.timerInterval = setInterval(() => {
this.answerTime++
if (this.activity.timeLimit > 0 && this.answerTime >= this.activity.timeLimit * 60) {
clearInterval(this.timerInterval)
this.$dialog.alert({
title: "提示",
message: "答题时间到,请刷新页面重新答题",
}).then(() => {
window.location.reload()
})
// const loading = this.$toast.loading({
// message: "答题时间到,自动提交中",
// forbidClick: true
// })
// setTimeout(() => {
// this.autoSubmit(loading)
// }, 1500)
}
}, 1000)
}
if (!this.isEnd && !this.answerRecord.isFinish) {
if (this.activity.timeLimit > 0) {
this.$dialog
.alert({
title: "提示",
message: "本次答题时间" + this.activity.timeLimit + "分钟,点击确认开始答题"
})
.then(() => {
startInterval()
})
} else {
startInterval()
}
}
// if (this.activity.timeLimit > 0 && !this.isEnd) {
// if (!this.answerRecord.isFinish) {
// this.$dialog
// .alert({
// title: "提示",
// message: "本次答题时间" + this.activity.timeLimit + "分钟,点击确认开始答题"
// })
// .then(() => {
// this.remainingTime = this.activity.timeLimit * 60
// this.timerInterval = setInterval(() => {
// if (this.remainingTime > 0) {
// this.remainingTime--
// } else {
// clearInterval(this.timerInterval)
// const loading = this.$toast.loading({
// message: "答题时间到,自动提交中",
// forbidClick: true
// })
// this.autoSubmit(loading)
// }
// }, 1000)
// })
// }
// }
},
historyScore() {
this.$axios.post("/platform/h5/qsv/quiz/historyScore", {activityId: this.activityId}).then((res) => {
if (res.code === 0) {
this.historyScores = res.data
}
})
},
//选项点击
cellToggle(subject, optionId) {
if (this.answerRecord.isFinish) {
return
}
if (subject.type === "radio") {
this.$refs["subject" + subject.id][0].toggleAll(false)
}
this.$refs["option" + optionId][0].toggle()
},
//手动提交
onSubmit() {
if (this.isEnd) {
this.$toast("调查已结束")
return
}
//提示那些题没有作答
for (let i = 0; i < this.subjects.length; i++) {
let subject = this.subjects[i]
//["radio", "checkbox"].includes(subject.type) &&
if (!subject.userSelectOptionIds || subject.userSelectOptionIds.length === 0) {
this.$toast.fail("第" + (i + 1) + "题未做答")
return
}
}
if (this.timerInterval) {
clearInterval(this.timerInterval)
}
this.autoSubmit()
},
//自动提交
autoSubmit(loading = null) {
this.$axios.post("/platform/h5/qsv/quiz/submitAnswer", {
answer: JSON.stringify({
activityId: this.id,
answerRecordId: this.answerRecordId,
subjects: this.subjects.map((subject) => {
return {
id: subject.id,
userSelectOptionIds: ["checkbox", "radio"].includes(subject.type) ? subject.userSelectOptionIds : []
}
}),
answerTime: this.answerTime
})
})
.then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
pjaxReplace("/platform/h5/qsv/quiz/result?answerRecordId=" + this.answerRecordId)
}
})
.always(() => {
if (loading) {
loading.clear()
}
})
},
// async checkGroupPermission() {
// const groupId = this.activity.groupId
// if (groupId) {
// const { code, data } = await this.$axios.post("/open/common/checkGroupPermission", { groupId })
// if (code === 0) {
// if (!data) {
// this.$dialog
// .alert({
// title: "提示",
// message: "您没有权限参与"
// })
// .then(() => {
// location.back()
// })
// }
// }
// }
// }
},
created() {
if (this.timerInterval) {
clearInterval(this.timerInterval)
}
if (this.id) {
this.listSubjects()
}
},
style: /*language=CSS*/ `
.container {
padding: 0;
}
/deep/ .container .title {
text-align: center;
padding: 20px;
background: #ffffff;
margin: 0 0 10px 0 !important;
color: var(--color-primary);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.container .card {
padding: 10px;
background: #ffffff;
}
.subject {
background: #fff;
padding: 15px;
margin-bottom: 15px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
position: relative;
}
.subject p {
font-size: 16px;
margin: 20px 0 10px 0;
font-weight: bold;
}
.subject .tag {
position: absolute;
top: 0;
}
/deep/ .timer {
text-align: center;
font-size: 18px;
background: #fff;
padding: 10px 0;
}
.submit-button {
width: 100%;
margin-top: 20px;
}
.result {
text-align: center;
font-size: 20px;
margin-top: 20px;
}
.button-control {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20px;
display: flex;
column-gap: 20px;
background: #fff;
}
`
})
</script>
<!--#
}
#-->
@@ -0,0 +1,359 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="问卷列表" placeholder fixed></van-nav-bar>
<div class="container" :style="{'padding-bottom': answerRecord.isFinish ? 0 : '84px'}">
<van-sticky offset-top="46px">
<h2 class="title">{{ activity.title }}</h2>
<div class="score-form">
<div class="score-form-total">
<div class="score-font-style">{{totalScore}}</div>
<i class="score-underline"></i>
</div>
</div>
</van-sticky>
<div>
<div v-for="(subject, index) in subjects" :key="index" class="subject">
<p>{{index+1}}、{{ subject.title }}</p>
<div class="tag">
<van-tag v-if="subject.type === 'checkbox'" type="primary" size="large">多选</van-tag>
<van-tag v-if="subject.type === 'radio'" type="primary" size="large">单选</van-tag>
<van-tag v-if="subject.score" type="primary" size="large">{{subject.score}}分</van-tag>
</div>
<van-checkbox-group v-model="subject.userSelectOptionIds" :ref="'subject'+subject.id">
<van-cell-group>
<van-cell
v-for="(option,index) in subject.options"
clickable
:key="option.id"
:title="option.text"
>
<template #title>
<span :style="{color : option.isCorrect ? 'green' : ''}">{{option.text}}</span>
</template>
<template #icon>
<van-checkbox
:name="option.id"
:ref="'option'+option.id"
:disabled="answerRecord.isFinish"
style="margin-right: 10px"
></van-checkbox>
</template>
</van-cell>
</van-cell-group>
</van-checkbox-group>
<div class="answer-container">
<div v-if="answerRecord.extJson?.[subject.id]?.isCorrect" class="correct-answer">
<van-icon name="passed"></van-icon>
回答正确
</div>
<div v-else-if="answerRecord.extJson?.[subject.id]" class="incorrect-answer">
<van-icon name="close"></van-icon>
回答错误
</div>
</div>
</div>
<div class="button-control">
<van-button v-if="canAgainQuestion" type="primary" @click="againQuestion" block>重新答题</van-button>
<van-button type="primary" @click="openHistory" block>查看全部答题记录</van-button>
</div>
</div>
<van-action-sheet v-model="historyShow" title="历史记录" >
<div class="history-list">
<div v-for="item in historyList" class="history-item">
<div class="history-header">
<span>{{ item.date }}</span>
<van-tag v-if="item.isHighestScore" type="danger" class="tag">最高分</van-tag>
<van-tag v-if="item.isLatestScore" type="primary" class="tag">最新得分</van-tag>
</div>
<div class="history-info">答题分数:{{ item.totalScore }}</div>
<div class="history-info">答题用时:{{ item.answerTime | formatSeconds }}</div>
</div>
</div>
</van-action-sheet>
</div>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
data() {
return {
answerRecordId: GetQueryString("answerRecordId"),
answerRecord: {},
subjects: [],
activity: {},
list: [],
historyShow: false,
historyList: [],
canAgainQuestion: false
}
},
computed: {
totalScore() {
if (!this.answerRecord || !this.answerRecord.extJson) {
return 0
}
let totalScore = 0
for (const key in this.answerRecord.extJson) {
if (this.answerRecord.extJson.hasOwnProperty(key)) {
totalScore += this.answerRecord.extJson[key].score || 0
}
}
return totalScore
}
},
filters: {
formatSeconds(seconds) {
if (seconds) {
const minutes = Math.floor(seconds / 60) // 获取总分钟数
const remainingSeconds = seconds % 60 // 获取剩余秒数
// 格式化输出,确保秒数始终为两位数
return minutes + "分钟" + String(remainingSeconds).padStart(2, "0") + "秒"
}
return null
}
},
methods: {
/**
* 重新答题
*/
againQuestion() {
vant.Dialog.confirm({
title: '温馨提示',
message: '确定要重新答题吗?',
}).then(() => {
pjaxReplace('/platform/h5/qsv/quiz?id=' + this.activity.id + "&H5JumpTo=true")
}).catch(() => {
// on cancel
});
},
getAnswerResult() {
this.$axios.post("/platform/h5/qsv/quiz/answerResult", { answerRecordId: this.answerRecordId }).then((res) => {
if (res.code === 0) {
this.subjects = res.data.subjects
this.activity = res.data.activity
this.getAnswerRecord()
this.getHistoryQuestion()
}
})
},
//获取回答记录
getAnswerRecord() {
this.$axios.post("/platform/h5/qsv/quiz/answerRecord", { answerRecordId: this.answerRecordId }).then((res) => {
if (res.code === 0) {
this.answerRecord = res.data
this.initAnswer()
}
})
},
//答案回显
initAnswer() {
this.subjects.forEach((subject, subjectIndex) => {
const answer = this.answerRecord.extJson[subject.id]
if (["radio", "checkbox"].includes(subject.type)) {
this.$nextTick(() => {
this.$refs["subject" + subject.id][0].toggleAll(false)
})
answer?.optionIds.forEach((optionId) => {
this.$nextTick(() => {
this.$refs["option" + optionId][0].toggle()
})
})
} else if (subject.type === "text") {
subject.userFillContent = answer?.text
}
})
},
historyBack() {
pjaxReplace('/platform/h5/qsv')
},
openHistory() {
this.historyShow = true
},
getHistoryQuestion() {
this.$axios.post("/platform/h5/qsv/quiz/historyScore", { activityId: this.activity.id }).then((res) => {
if (res.code === 0) {
this.historyList = res.data
if (this.activity.maxAttempts > res.data.length) {
this.canAgainQuestion = true
}
}
})
}
},
created() {
this.getAnswerResult()
},
style: /*language=CSS*/ `
.container {
padding: 0;
}
/deep/ .container .title {
text-align: center;
padding: 20px;
margin: 0 !important;
background: #ffffff;
color: var(--color-primary);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.container .score {
}
.container .card {
padding: 10px;
background: #ffffff;
}
.subject {
background: #fff;
padding: 15px;
margin-bottom: 15px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
position: relative;
}
.subject p {
font-size: 16px;
margin: 20px 0 10px 0;
font-weight: bold;
}
.subject .tag {
position: absolute;
top: 0;
}
/deep/ .score-form {
background: #ffffff;
display: flex;
margin-bottom: 10px;
border-top: 1px solid #f1f1f1;
align-items: center;
}
/deep/ .score-form-total {
flex: 1;
background: #fff;
display: flex;
padding: 10px 20px 10px 0;
flex-direction: column;
align-items: flex-end;
}
/deep/ .score-text-news {
flex: 1;
background: #fff;
}
/deep/ .score-font-style {
font-size: 32px;
color: #ff6a00;
word-break: keep-all;
line-height: 38px;
min-width: 47px;
text-align: center;
}
/deep/ .score-underline {
background: url(//image.wjx.cn/images/newimg/score-form/score-underline@2x.png) no-repeat center;
background-size: 47px 16px;
display: inline-block;
height: 16px;
width: 47px;
margin-top: 7px;
}
.van-checkbox__icon--checked .van-icon {
color: #fff !important;
background-color: var(--color-primary) !important;
border-color: var(--color-primary) !important;
}
.van-checkbox__icon--disabled .van-icon {
background-color: #fff;
}
.answer-container {
padding: 16px;
}
.correct-answer {
color: green;
}
.incorrect-answer {
color: red;
}
.button-control {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20px;
display: flex;
column-gap: 20px;
background: #fff;
}
/deep/ .history-list {
background: #f1f1f1;
padding: 10px;
}
/deep/ .history-item {
background: #ffffff;
border-radius: 12px;
padding: 16px;
margin: 20px 10px;
box-shadow:
8px 8px 16px #d9d9d9,
-8px -8px 16px #ffffff;
transition: transform 0.2s ease-in-out;
}
/deep/ .history-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
/deep/ .history-header span {
font-size: 14px;
font-weight: 600;
color: #333;
}
/deep/ .history-header .tag {
margin-left: 8px;
color: #fff;
padding: 2px 5px;
}
/deep/ .history-info {
font-size: 14px;
color: #555;
margin-bottom: 4px;
}
`
})
</script>
<!--#
}
#-->
@@ -0,0 +1,292 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style>
.container {
padding: 0;
}
.container .title {
text-align: center;
padding: 20px;
background: #ffffff;
margin: 0 0 10px 0;
}
.container .card {
padding: 10px;
background: #ffffff;
}
.subject {
background: #fff;
padding: 15px;
margin-bottom: 15px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
position: relative;
}
.subject p {
font-size: 16px;
margin: 20px 0 10px 0;
font-weight: bold;
}
.subject .tag {
position: absolute;
top: 0;
}
.button-control {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20px;
display: flex;
column-gap: 20px;
background: #fff;
}
.van-checkbox__icon--checked .van-icon {
color: #fff !important;
background-color: var(--color-primary) !important;
border-color: var(--color-primary) !important;
}
.van-checkbox__icon--disabled .van-icon {
background-color: #fff;
}
.ui-input-box {
border: 1px solid #e3e3e3;
margin: 5px 0;
background-color: #fff;
padding: 0;
width: 100%;
display: flex;
}
.ui-input-box input {
background-color: #fff;
border: none !important;
padding: 10px;
font-size: 14px;
line-height: 18px;
display: inline-block;
margin: 0;
-webkit-appearance: none;
resize: none;
width: 100%;
}
</style>
<div id="app" v-cloak>
<van-nav-bar title="问卷调查" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
<div class="container" :style="{'padding-bottom': answerRecord.isFinish ? 0 : '84px'}">
<h2 class="title">{{ activity.title }}</h2>
<div v-if="!isFinished">
<div v-for="(subject, index) in subjects" :key="index" class="subject">
<p>{{index+1}}、{{ subject.title }}</p>
<div class="tag">
<van-tag v-if="subject.type === 'checkbox'" type="primary" size="large">多选</van-tag>
<van-tag v-if="subject.type === 'radio'" type="primary" size="large">单选</van-tag>
<van-tag v-if="subject.score" type="primary" size="large">{{subject.score}}分</van-tag>
</div>
<!--单选、多选-->
<van-checkbox-group
v-model="subject.userSelectOptionIds"
:ref="'subject'+subject.id"
v-if="['radio','checkbox'].includes(subject.type)"
>
<van-cell-group>
<van-cell
v-for="(option,index) in subject.options"
clickable
:key="option.id"
:title="option.text"
@click="cellToggle(subject,option.id)"
>
<template #icon>
<van-checkbox :name="option.id" :ref="'option'+option.id" style="margin-right: 10px"></van-checkbox>
</template>
<img
slot="right-icon"
v-if="option.imgUrl"
:src="option.imgUrl"
alt=""
style="width: 40px; height: 40px"
@click.stop="previewOptionImg(option.imgUrl)"
/>
</van-cell>
</van-cell-group>
</van-checkbox-group>
<!--填空题-->
<div class="ui-input-box" v-if="subject.type==='text'">
<input type="text" v-model="subject.userFillContent" :readonly="answerRecord.isFinish" />
</div>
</div>
<div class="button-control" v-if="!answerRecord.isFinish">
<van-button type="primary" @click="onSubmit" block :disabled="isEnd">{{isEnd ? '已结束' : '提交'}}</van-button>
</div>
</div>
</div>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
data() {
return {
list: [],
id: null,
subjects: [],
activity: {},
remainingTime: 0,
isFinished: false,
answerRecord: {},
answerRecordId: null
}
},
computed: {
isEnd() {
if (this.activity) {
return this.$moment().unix() > this.$moment(this.activity.endTime).unix()
}
return true
}
},
methods: {
//获取活动、题目
listSubjects() {
this.$axios.post("/platform/h5/qsv/survey/subjects", { activityId: this.id }).then((res) => {
if (res.code === 0) {
this.activity = res.data.activity
this.subjects = res.data.subjects
this.answerRecordId = res.data.answerRecordId
this.getAnswerRecord()
}
})
},
//获取回答记录
getAnswerRecord() {
this.$axios.post("/platform/h5/qsv/survey/answerRecord", { answerRecordId: this.answerRecordId }).then((res) => {
if (res.code === 0) {
this.answerRecord = res.data
if (this.answerRecord.isFinish) {
this.$toast.success("您已完成该调查")
}
this.initAnswer()
}
})
},
//答案回显
initAnswer() {
this.subjects.forEach((subject, subjectIndex) => {
const answer = this.answerRecord.extJson[subject.id]
if (["radio", "checkbox"].includes(subject.type)) {
this.$refs["subject" + subject.id][0].toggleAll(false)
answer?.optionIds.forEach((optionId) => {
this.$nextTick(() => {
this.$refs["option" + optionId][0].toggle()
})
})
} else if (subject.type === "text") {
subject.userFillContent = answer?.text
}
})
},
//选项点击
cellToggle(subject, optionId) {
if (this.answerRecord.isFinish) {
return
}
if (subject.type === "radio") {
this.$refs["subject" + subject.id][0].toggleAll(false)
}
this.$refs["option" + optionId][0].toggle()
},
//预览图片
previewOptionImg(img) {
vant.ImagePreview([img])
},
//手动提交
onSubmit() {
const endTime = this.activity.endTime
if (this.isEnd) {
this.$toast("调查已结束")
return
}
//提示那些题没有作答
for (let i = 0; i < this.subjects.length; i++) {
const subject = this.subjects[i]
if (["radio", "checkbox"].includes(subject.type)) {
if (!subject.userSelectOptionIds || subject.userSelectOptionIds.length === 0) {
this.$toast.fail("第" + (i + 1) + "题未做答")
return
}
} else if ("text" === subject.type) {
if (!subject.userFillContent) {
this.$toast.fail("第" + (i + 1) + "题未作答")
return
}
}
}
this.autoSubmit()
},
//自动提交
autoSubmit(loading = null) {
this.$axios
.post("/platform/h5/qsv/survey/submitAnswer", {
answer: JSON.stringify({
activityId: this.id,
answerRecordId: this.answerRecordId,
subjects: this.subjects.map((subject) => {
return {
id: subject.id,
userSelectOptionIds: ["checkbox", "radio"].includes(subject.type) ? subject.userSelectOptionIds : [],
userFillContent: subject.type === "text" ? subject.userFillContent : null
}
})
})
})
.then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.getAnswerRecord()
}
})
.finally(() => {
if (loading) {
loading.clear()
}
})
}
},
created() {
const id = GetQueryString("id")
if (id) {
this.id = id
this.listSubjects()
}
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,366 @@
const apply = {
template: /*language=HTML*/ `
<div>
<van-popup v-model:show="visible" :style="{ height: '100%',width: '100%', 'background-color': '#F7F8FA'}" position="right" safe-area-inset-bottom>
<van-nav-bar :title="row.name" left-text="返回" left-arrow @click-left="visible = false" fixed placeholder></van-nav-bar>
<div class="top-calendar">
<div class="calendar-left">
<div :class="getDayClass(item)" @click="dayClick(item)" v-for="item in weekList">
<div class="day-info-week">
{{item.weekdayCN}}
</div>
<div class="day-info-month">
{{$moment(item.day).format('MM-DD')}}
</div>
</div>
</div>
<div class="calendar-right">
<van-icon size="16" color="white" name="arrow-down" @click="calendarVisible = true"></van-icon>
<van-calendar class="calendar-popup" v-model="calendarVisible" color="#246fb4" position="top" @confirm="calendarConfirm"
:default-date="new Date(selectDate)"
:formatter="calendarFormatter"
:first-day-of-week="1"
title="选择开始日期"></van-calendar>
</div>
</div>
<div class="container">
<table v-if="weekList.find(o => $moment(o.day).unix() === $moment(selectDate).unix())?.disabled === false" style="width: 100%">
<template v-for="item in allowTimeList">
<tr>
<td class="container-times">{{item.startTime + '-' + item.endTime}}</td>
<td>
<div v-if="item.disabled === true" class="container-state">{{ item.tooltip }}</div>
<div @click="selectTime(item)" v-else class="container-state" style="background-color: #e8ffef; color: #52986a">
<label v-if="(item.dateStr + ' ' + item.startTime + '-' + item.endTime) !== (selected.dateStr + ' ' + selected.startTime + '-' + selected.endTime)">
可预约
</label>
<span v-else>
<van-icon name="passed" size="26" style="line-height: 36px;position: unset"></van-icon>
</span>
</div>
</td>
</tr>
</template>
</table>
<van-empty v-else image="error" :description="selectDate + '不能预约'"></van-empty>
</div>
<div style="position: fixed; bottom: 0; width: 100%">
<van-button @click="onApply" type="primary" color="#246fb4" style="width: 100%">确定预约</van-button>
</div>
</van-popup>
<van-action-sheet v-model="formVisible" title="确认预约信息">
<van-notice-bar left-icon="volume-o"
:text="'您已选择的预约日期为:' + selectDate"></van-notice-bar>
<van-form ref="formRef" class="form-container">
<van-field label="预约人" :rules="[{ required: true }]" v-model="formData.applyUserName" readonly
required name="applyUserName"></van-field>
<van-field label="性别" :rules="[{ required: true }]" v-model="formData.sex" readonly
required name="sex"></van-field>
<van-field label="工号" :rules="[{ required: true }]" v-model="formData.applyLoginName" readonly
required name="applyLoginName"></van-field>
<van-field label="所属单位" :rules="[{ required: true }]" v-model="formData.applyUnitName" readonly
required name="applyUnitName"></van-field>
<van-field label="联系电话" :rules="[{ required: true }]" v-model="formData.applyMobile" type="number"
required name="applyMobile"></van-field>
<van-field label="预约时间" :rules="[{ required: true }]" v-model="formData.applyTime"
required readonly name="applyTime"></van-field>
<van-field name="stepper" label="预约人数" required :rules="[{ required: true }]">
<template #input>
<van-stepper
:disabled="row.reserveTarget === 1 || row.reserveTarget === 3"
v-model="formData.joinCount"></van-stepper>
</template>
</van-field>
<van-field
v-model="formData.applyCause"
rows="4"
autosize
label="预约事由"
type="textarea"
maxlength="50"
placeholder="请输入预约事由"
show-word-limit
required
name="applyCause"
:rules="[{ required: true }]"
></van-field>
<div class="form-actions">
<van-button @click="formVisible = false" type="info" plain round>关闭</van-button>
<van-button @click="onSubmit" v-if="!taskId" type="info" round>提交</van-button>
<van-button @click="onFinishTask" v-else type="info" round>提交</van-button>
</div>
</van-form>
</van-action-sheet>
</div>
`,
store,
data() {
return {
taskId: '',
bizId: '',
row: {},
visible: false,
selectDate: '',
selected: {},
weekList: [],
allowDayList: [],
allowTimeList: [],
weekdayCNMap: {0: '周日', 1: '周一', 2: '周二', 3: '周三', 4: '周四', 5: '周五', 6: '周六'},
formVisible: false,
formData: {
applyCause: '',
},
calendarVisible: false,
}
},
computed: {
calendarFormatter(day) {
return (day) => {
if(!this.allowDayList.includes(this.$moment(day.date).format('YYYY-MM-DD'))) {
day.type = 'disabled'
}
return day
}
}
},
methods: {
async onOpen(row, applyRow = null) {
this.row = row
this.visible = true
await this.init()
if(applyRow) {
this.taskId = applyRow.taskId
this.bizId = applyRow.bizId
this.applyTime = applyRow.applyDay
this.selectDate = applyRow.applyDay
this.selected = {
dateStr: applyRow.applyDay,
startTime: applyRow.startTime,
endTime: applyRow.endTime,
}
this.formVisible = true
this.formData = clone(applyRow)
this.$set(this.formData, 'applyTime', this.formData.startTime + '-' + this.formData.endTime)
this.$set(this.formData, 'sex', this.$store.state.user.sex)
const day = this.weekList.find(o => o.dateStr === applyRow.applyDay)
if(day) {
await this.dayClick(day)
}
}
},
async init() {
this.selectDate = this.$moment().format('YYYY-MM-DD')
await this.queryAllowDay()
await this.queryTimesByDay()
this.setWeekList(this.selectDate)
},
async calendarConfirm(date) {
this.selectDate = this.$moment(date).format('YYYY-MM-DD')
this.setWeekList(date)
await this.queryTimesByDay()
this.calendarVisible = false
},
onApply() {
if(Object.keys(this.selected).length === 0) {
this.$toast('请选择要预约的时间')
return
}
this.$set(this.formData, "applyUserId", this.$store.state.user.id)
this.$set(this.formData, "applyUserName", this.$store.state.user.username)
this.$set(this.formData, "applyLoginName", this.$store.state.user.loginname,)
this.$set(this.formData, "applyUnitId", this.$store.state.user?.unit?.id)
this.$set(this.formData, "applyUnitName", this.$store.state.user?.unit?.name)
this.$set(this.formData, "applyUnionId", this.$store.state.user?.union?.id)
this.$set(this.formData, "applyUnionName", this.$store.state.user?.union?.name)
this.$set(this.formData, "applyMobile", this.$store.state.user.mobile)
this.$set(this.formData, "sex", this.$store.state.user.sex)
this.$set(this.formData, "siteId", this.row.id)
this.$set(this.formData, "applyTime", this.selected.startTime + '-' + this.selected.endTime)
this.$set(this.formData, "startTime", this.selected.startTime)
this.$set(this.formData, "endTime", this.selected.endTime)
if (this.row.reserveTarget === 1 || this.row.reserveTarget === 3) {
this.$set(this.formData, "joinCount", this.row.maxNum)
} else {
this.$set(this.formData, "joinCount", 1)
}
this.formVisible = true
},
onSubmit() {
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: "提示",
message: "您确定要提交吗?"
}).then(async () => {
const res = await this.$axios.post("/platform/site/apply/submit", {
data: JSON.stringify(this.formData),
days: JSON.stringify([this.selected.dateStr])
})
this.$toast(res.msg)
if (res.code === 0) {
this.$pjaxReplace("/platform/site/mine/h5")
}
})
})
},
onFinishTask() {
if (!this.formData.applyTime) {
this.$toast('未选择预约时间')
return
}
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: "提示",
message: "您确定要提交吗?"
}).then(() => {
this.$axios.post('/platform/site/apply/submitAgain', {
data: JSON.stringify(this.formData),
days: JSON.stringify([this.selected.dateStr]),
taskId: this.taskId
}).then(res => {
this.$toast(res.msg)
if (res.code === 0) {
this.$pjaxReplace("/platform/site/mine/h5")
}
})
})
})
},
selectTime(item) {
if((item.dateStr + ' ' + item.startTime + '-' + item.endTime) !== (this.selected.dateStr + ' ' + this.selected.startTime + '-' + this.selected.endTime)) {
this.$set(this.selected, 'day', item.dateStr)
this.$set(this.selected, "dateStr", item.dateStr)
this.$set(this.selected, 'startTime', item.startTime)
this.$set(this.selected, 'endTime', item.endTime)
} else {
this.selected = {}
}
},
// 获取每天的样式
getDayClass(row) {
let classStr = 'calendar-left-day'
if(row.disabled) {
classStr += ' left-day-disabled'
} else {
classStr += this.$moment(row.day).unix() === this.$moment(this.selectDate).unix() ? ' left-day-active' : ''
}
return classStr
},
// 点击某一天
async dayClick(item) {
this.selectDate = item.dateStr
if(item.disabled) {
this.$toast(this.$moment(item.day).format('YYYY-MM-DD') + '不可预约')
} else {
await this.queryTimesByDay()
}
},
// 获取一周
setWeekList(startDate) {
const start = this.$moment(startDate)
const allowDaySet = new Set(this.allowDayList)
this.weekList = Array.from({ length: 8 }, (_, index) => {
const day = start.clone().add(index, 'd')
const dateStr = day.format('YYYY-MM-DD')
const disabled = this.allowDayList.length > 0 && !allowDaySet.has(dateStr)
const weekdayCN = this.weekdayCNMap[day.day()]
return { day, disabled, weekdayCN, dateStr }
})
},
// 查询哪些天是开放的
async queryAllowDay() {
const {data} = await this.$axios.post("/platform/site/apply/queryAllowDay", {
siteId: this.row.id,
})
this.allowDayList = data
},
// 查询时间段
async queryTimesByDay() {
const {data} = await this.$axios.post("/platform/site/apply/queryTimesByDay", {
siteId: this.row.id,
day: this.selectDate,
})
this.allowTimeList = data
},
},
style: /*language=CSS*/ `
/deep/ .top-calendar {
height: 70px;
max-height: 70px;
position: sticky;
top: 0;
left: 0;
width: 100%;
max-width: 100%;
display: flex;
align-items: center;
background-color: #0e78c5;
}
/deep/ .calendar-left {
/*width: calc(100% - 20px);*/
overflow-x: auto;
display: flex;
height: 90%;
}
/deep/ .calendar-left-day {
min-width: 65px;
height: 100%;
margin: 0 5px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #FFF;
border-radius: 10px;
}
/deep/ .left-day-active {
background-color: #0000cc;
}
/deep/ .left-day-disabled {
background-color: lightgrey;
}
/deep/ .container {
background-color: white;
margin: 10px 0;
padding: 10px 0;
overflow-y: auto;
height: calc(100vh - 46px - 70px - 56px - 30px);
}
/deep/ .container-times {
width: 58%;
text-align: center;
}
/deep/ .container-state {
width: 80px;
height: 36px;
line-height: 36px;
text-align: center;
background-color: #f2f2f2;
border-radius: 2px;
color: #929292;
}
/deep/ table {
border-collapse: collapse;
}
/deep/ .calendar-right {
width: 30px;
max-width: 30px;
text-align: center;
height: 60%;
border-left: 1px solid #fff3f3;
display: flex;
align-items: center;
justify-content: center;
margin-left: 5px;
}
/deep/ .calendar-popup {
top: 46px;
}
`
}
@@ -0,0 +1,121 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
</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-search
v-model="pageForm.searchKeyword"
:show-action="false"
:reverse-color="false"
input-align="left"
placeholder="请输入姓名或者工号搜索"
@search="doSearch"
></van-search>
<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.type" :options="typeOptions" :multiple="false"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
</van-sticky>
<table-list api="/platform/site/apply/pageData" :page_form.sync="pageForm" ref="tableListRef" title="name" @ready="onReady">
<template v-slot="{index,row}">
<table-column label="场地地址">{{row.address}}</table-column>
<table-column label="联系人">{{row.contactName}}</table-column>
<table-column label="联系方式">{{row.contactPhone}}</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>
<info ref="infoRef"></info>
<site-apply ref="applyRef"></site-apply>
</div>
<script nonce="${cspNonce!}">
<!--#include('../common/siteInfo.js'){}#-->
<!--#include('apply.js'){}#-->
new Vue({
el: "#app",
store,
components: {
"info": siteInfo,
"site-apply": apply,
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: '',
year: new Date().getFullYear(),
type: null
},
typeOptions: [],
}
},
methods: {
onView(row) {
this.$refs.infoRef.onOpen(row)
},
onApply(row) {
if(row.reserveTarget === 1 && !this.$auth.hasRoleOr('BRANCH_UNION_ADMIN, BRANCH_UNION_CHAIRMAN') && !this.$auth.hasRole('SYSADMIN')) {
this.$message.warning('该场地只能分工会预约')
return
}
if (row.sexLimit === 1 || row.sexLimit === 2) {
const sex = row.sexLimit === 1 ? '男' : '女'
if(!this.$store.state.user.sex.includes(sex)) {
this.$toast('抱歉,该场地仅限' + sex + '性会员预约')
return
}
}
this.$refs.applyRef.onOpen(row)
},
async onReady() {
const typeList = await this.querySiteType()
this.typeOptions = [
{
text: "全部类型",
value: null
}
].concat(typeList.map((v) => ({ text: v.name, value: v.id })))
if (this.typeOptions.length > 0) {
this.pageForm.type = this.typeOptions[0].value
this.doSearch()
}
},
async querySiteType() {
const res = await this.$axios.post("/platform/site/type/querySiteType")
return res.data
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
},
})
</script>
<!--#
}
#-->
@@ -0,0 +1,76 @@
const applyInfo = {
template:
/*language=HTML*/
`
<van-action-sheet v-model="visible" title="查看详情">
<div class="detail-container">
<van-cell-group title="基本信息">
<van-cell title="预约场地">{{ viewData.siteName }}</van-cell>
<van-cell title="预约人">{{ viewData.applyUserName }}</van-cell>
<van-cell title="预约人工号">{{ viewData.applyLoginName }}</van-cell>
<van-cell title="所属单位">{{ viewData.applyUnitName }}</van-cell>
<van-cell title="预约日期">{{ viewData.applyDay }}</van-cell>
<van-cell title="开始时间">{{ viewData.startTime }}</van-cell>
<van-cell title="结束时间">{{ viewData.endTime }}</van-cell>
<van-cell title="联系电话">{{ viewData.applyMobile }}</van-cell>
<van-cell title="预约人数">{{ viewData.joinCount }}</van-cell>
<van-cell title="预约事由" class="direction-column-cell">{{ viewData.applyCause }}</van-cell>
</van-cell-group>
<template v-for="task in doneTasks">
<van-cell-group :title="task.displayName" v-if="task.ext.isFirstTaskNode">
<van-cell title="申请用户">{{ task.ext.initiatorName }}({{task.ext.initiatorAccount}})
</van-cell>
<van-cell title="申请时间">{{ task.finishTime }}</van-cell>
<van-cell title="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag>
</van-cell>
</van-cell-group>
<van-cell-group :title="task.displayName" v-else>
<van-cell title="办理用户">{{ task.taskFormData.userName }}({{task.taskFormData.loginName}})
</van-cell>
<van-cell title="办理时间">{{ task.finishTime }}</van-cell>
<van-cell title="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag>
</van-cell>
<van-cell title="办理意见" v-if="!task.ext.isFirstTaskNode" class="direction-column-cell">
<div v-html="task.taskFormData.tf_opinion"></div>
</van-cell>
</van-cell-group>
</template>
</div>
<slot></slot>
</van-action-sheet>
`,
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
visible:false,
viewData: {},
doneTasks: [],
row: null,
}
},
methods: {
onOpen(row) {
this.row = row
this.visible = true
this.viewData = row
this.getDoneTasks()
},
onClose(){
this.visible = false
},
getDoneTasks() {
this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data
}
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,123 @@
const siteInfo = {
template: /*language=HTML*/ `
<div>
<van-action-sheet v-model="visible" title="场地信息">
<div class="detail-container">
<van-cell-group title="基本信息">
<van-cell title="创建人">{{ viewData.createUserName }}</van-cell>
<van-cell title="创建时间">{{ viewData.createTime }}</van-cell>
<van-cell title="场地名称">{{ viewData.name }}</van-cell>
<van-cell title="场地地址" class="direction-column-cell">{{ viewData.address }}</van-cell>
<van-cell title="联系人">{{ viewData.contactName }}</van-cell>
<van-cell title="联系电话">{{ viewData.contactPhone }}</van-cell>
<van-cell title="排序编号">{{ viewData.sortNum }}</van-cell>
<van-cell title="容纳人数">{{ viewData.maxNum }}</van-cell>
<van-cell title="场地类型">{{ viewData.typeName }}</van-cell>
<van-cell title="面向对象">
<span v-if="viewData.reserveTarget === 1">面向分工会</span>
<span v-if="viewData.reserveTarget === 2">面向个人</span>
<span v-if="viewData.reserveTarget === 3">面向集体</span>
</van-cell>
<van-cell title="性别限制">
<span v-if="viewData.sexLimit === 0">不限制</span>
<span v-if="viewData.sexLimit === 1">男</span>
<span v-if="viewData.sexLimit === 2">女</span>
</van-cell>
<van-cell title="开启状态">
<span v-if="viewData.state">开启</span>
<span v-else>禁用</span>
</van-cell>
<van-cell title="排除节假日">
<span v-if="viewData.state">是</span>
<span v-else>否</span>
</van-cell>
<van-cell title="场地介绍" class="direction-column-cell">
<div v-if="viewData.introduce" v-html="viewData.introduce"></div>
<div v-else>暂无场地介绍</div>
</van-cell>
</van-cell-group>
<van-cell-group title="禁用时间" v-if="viewData.notApplyTimeList && viewData.notApplyTimeList.length > 0">
<table class="table-class">
<thead>
<tr>
<th>日期</th>
<th>开始时间</th>
<th>结束时间</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in viewData.notApplyTimeList" :key="index">
<td>{{ item.date }}</td>
<td>{{ item.startTime }}</td>
<td>{{ item.endTime }}</td>
</tr>
</tbody>
</table>
</van-cell-group>
<van-cell-group title="场次" v-if="viewData.openHours && viewData.openHours.length > 0">
<table class="table-class">
<thead>
<tr>
<th>星期</th>
<th>开始时间</th>
<th>结束时间</th>
<th>预约时间单位(小时)</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in viewData.openHours" :key="index">
<td>
<span v-if="item.weekNum === 1">周一</span>
<span v-if="item.weekNum === 2">周二</span>
<span v-if="item.weekNum === 3">周三</span>
<span v-if="item.weekNum === 4">周四</span>
<span v-if="item.weekNum === 5">周五</span>
<span v-if="item.weekNum === 6">周六</span>
<span v-if="item.weekNum === 0">周日</span>
</td>
<td>{{ item.startTime }}</td>
<td>{{ item.endTime }}</td>
<td>{{ item.timeUnit }}</td>
</tr>
</tbody>
</table>
</van-cell-group>
</div>
</van-action-sheet>
</div>
`,
data() {
return {
viewData: {},
visible: false
}
},
methods: {
onOpen(row) {
this.viewData = row
this.visible = true
},
},
style: /*language=CSS*/ `
/deep/ .table-class{
width: 100%;
border-radius: 5px;
overflow: hidden;
line-height: 1.5rem;
font-size: 13px;
table-layout: fixed;
border-collapse: collapse;
}
/deep/ .table-class th {
background-color: #f2f2f2;
border: 1px solid #dddddd;
}
/deep/ .table-class tr {
text-align: center;
border-bottom: 1px solid #dddddd;
}
/deep/ .table-class td {
border: 1px solid #dddddd;
}
`
}
@@ -0,0 +1,154 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
</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-search
v-model="pageForm.searchKeyword"
:show-action="false"
:reverse-color="false"
input-align="left"
placeholder="请输入姓名或者工号搜索"
@search="doSearch"
></van-search>
<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.siteType" :options="typeOptions" :multiple="false"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
</van-sticky>
<table-list api="/platform/site/mine/pageData" :page_form.sync="pageForm" ref="tableListRef" title="applyUserName" @ready="onReady">
<template v-slot="{index,row}">
<table-column label="场地名称">{{row.siteName}}</table-column>
<table-column label="所属单位">{{row.applyUnitName}}</table-column>
<table-column label="预约日期">{{row.applyDay}}</table-column>
<table-column label="开始时间">{{row.startTime}}</table-column>
<table-column label="结束时间">{{row.endTime}}</table-column>
<table-column label="当前节点">{{row.taskName}}</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="onEdit(row)"
v-if="row.taskKey === 'startTask' || !row.instanceId">
<i class="fa fa-edit"></i>
<span>编辑</span>
</div>
<div class="action-btn delete" @click="onRevoke(row)"
v-if="row.canRevoke">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
<div class="action-btn delete" @click="onDelete(row)"
v-if="row.taskKey === 'startTask' || !row.instanceId">
<i class="fa fa-trash"></i>
<span>删除</span>
</div>
</template>
</table-list>
<info ref="infoRef"></info>
<site-apply ref="applyRef"></site-apply>
</div>
<script nonce="${cspNonce!}">
<!--#include('../apply/apply.js'){}#-->
<!--#include('../common/info.js'){}#-->
new Vue({
el: "#app",
store,
components: {
info: applyInfo,
"site-apply": apply,
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
year: new Date().getFullYear(),
siteType: null
},
typeOptions: [],
}
},
methods: {
async onReady() {
const typeList = await this.querySiteType()
this.typeOptions = [
{
text: "全部类型",
value: null
}
].concat(typeList.map((v) => ({ text: v.name, value: v.id })))
if (this.typeOptions.length > 0) {
this.pageForm.siteType = this.typeOptions[0].value
this.doSearch()
}
},
onRevoke(row) {
this.$dialog.confirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", { taskId: row.startTaskId }).then((res) => {
if (res.code === 0) {
this.$toast(res.msg)
this.doSearch()
}
})
})
},
onView(row) {
this.$refs.infoRef.onOpen(row)
},
async onEdit(row) {
const res = await this.$axios.post('/platform/site/manage/info', { id: row.siteId })
this.$refs.applyRef.onOpen(res.data, row)
},
onDelete(row) {
this.$dialog.confirm({
title: "提示",
message: "确定要删除此申请吗?"
})
.then(() => {
this.$axios.post("/platform/site/mine/delete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
} else {
this.$toast.fail(res.msg)
}
})
})
.catch(() => {})
},
async querySiteType() {
const res = await this.$axios.post("/platform/site/type/querySiteType")
return res.data
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
},
})
</script>
<!--#
}
#-->
@@ -0,0 +1,189 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
</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-search
v-model="pageForm.searchKeyword"
:show-action="false"
:reverse-color="false"
input-align="left"
placeholder="请输入姓名或者工号搜索"
@search="doSearch"
></van-search>
<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.siteType" :options="typeOptions" :multiple="false"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.approval = val==='1';this.doSearch();}">
<van-tab title="已审核" name="1"></van-tab>
<van-tab title="未审核" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/site/schoolUnionAudit/pageData" :page_form.sync="pageForm" ref="tableListRef" title="applyUserName" @ready="onReady">
<template v-slot="{index,row}">
<table-column label="场地名称">{{row.siteName}}</table-column>
<table-column label="所属单位">{{row.applyUnitName}}</table-column>
<table-column label="预约日期">{{row.applyDay}}</table-column>
<table-column label="开始时间">{{row.startTime}}</table-column>
<table-column label="结束时间">{{row.endTime}}</table-column>
<table-column label="当前节点">{{row.curTaskName}}</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" v-if="row.taskState === 10" @click="onApproval(row)">
<i class="fa fa-edit"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-reply"></i>
<span>撤回</span>
</div>
</template>
</table-list>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">{{formData.taskName}}</div>
<van-form ref="formRef">
<van-field
v-model="formData.tf_opinion"
name="tf_opinion"
label="审批意见"
placeholder="请输入审批意见"
:rules="[{ required: true, message: '请填写审批意见' }]"
required
maxlength="100"
show-word-limit
></van-field>
</van-form>
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button type="danger" block @click="handleTaskAction(6)">退回</van-button>
<van-button type="danger" block @click="handleTaskAction(20)">不同意</van-button>
<van-button type="primary" block @click="handleTaskAction(1)">同意</van-button>
</div>
</div>
</info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../common/info.js'){}#-->
new Vue({
el: "#app",
store,
components: {
info: applyInfo,
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: '',
approvalText: "0",
approval: false,
year: new Date().getFullYear(),
siteType: null,
},
typeOptions: [],
formData: {},
showApprovalForm: false
}
},
methods: {
async onReady() {
const typeList = await this.querySiteType()
this.typeOptions = [
{
text: "全部类型",
value: null
}
].concat(typeList.map((v) => ({ text: v.name, value: v.id })))
if (this.typeOptions.length > 0) {
this.pageForm.siteType = this.typeOptions[0].value
this.doSearch()
}
},
onView(row) {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
},
onApproval(row) {
this.showApprovalForm = true
this.$refs.infoRef.onOpen(row)
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
},
async handleTaskAction(val) {
try {
await this.$refs.formRef.validate();
this.$dialog.confirm({
title: "提示",
message: "您确定要提交吗?"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.infoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
}
})
}).catch(() => {
})
} catch (error) {
}
},
onRevoke(row){
this.$dialog.confirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
}
})
})
},
async querySiteType() {
const res = await this.$axios.post("/platform/site/type/querySiteType")
return res.data
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
},
})
</script>
<!--#
}
#-->
@@ -0,0 +1,149 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="报销统计" placeholder fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
<van-dropdown-item :options="yearList" @change="doSearch" v-model="pageForm.year"></van-dropdown-item>
</van-dropdown-menu>
<van-search
:reverse-color="false"
:show-action="false"
@search="doSearch"
input-align="left"
placeholder="请输入经办人搜索"
v-model="pageForm.userName"
></van-search>
</van-sticky>
<table-list api="/platform/unionReimburse/collect/pageData" :page_form.sync="pageForm" ref="tableListRef"
@ready="doSearch" >
<template v-slot="{index,row}">
<table-column label="经办人">{{row.userName}}</table-column>
<table-column label="所属工会">{{row.unionName}}</table-column>
<table-column label="所属单位">{{row.unitName}}</table-column>
<table-column label="报销类别">
<dict-tag :options="dict.type.UNION_REIMBURSE_TYPE"
:value="row.reimburseType">
</dict-tag>
</table-column>
<table-column label="报销项目">
<dict-tag :options="dict.type.UNION_REIMBURSE_PROJECT"
:value="row.reimburseProject">
</dict-tag>
</table-column>
<table-column label="金额">{{row.money}}</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="onEdit(row)" v-if="row.taskKey === 'startTask' || !row.instanceId">
<i class="fa fa-edit"></i>
<span>编辑</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(item)">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
<div class="action-btn delete" @click="onDelete(row)" v-if="row.taskKey === 'startTask' || !row.instanceId">
<i class="fa fa-trash"></i>
<span>删除</span>
</div>
</template>
</table-list>
<union-reimburse-info ref="unionReimburseInfoRef"></union-reimburse-info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../info.js'){}#-->
const vue = new Vue({
el: "#app",
store,
dicts: ["UNION_REIMBURSE_TYPE","UNION_REIMBURSE_PROJECT"],
components: {
"union-reimburse-info":UNION_REIMBURSE_INFO
},
data() {
return {
viewShow: false,
yearList: [],
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: "",
year: "",
},
infoShow: false
}
},
methods: {
onView(row) {
this.showApprovalForm = false
this.$refs.unionReimburseInfoRef.onOpen(row)
},
onEdit(row) {
this.$pjaxReplace("/platform/unionReimburse/apply/h5?bizId=" + row.id + "&taskId=" + row.startTaskId)
},
onRevoke(row){
this.$dialog
.confirm({
title: "提示",
message: "您确定要撤销申请吗?"
})
.then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.startTaskId}).then((resp) => {
this.$toast.success(resp.msg)
this.doSearch()
})
})
},
onDelete(row) {
this.$dialog
.confirm({
title: "提示",
message: "您确定要删除吗?"
})
.then(() => {
this.$axios.post("/platform/unionReimburse/mine/delete", {id: row.id}).then((resp) => {
if (resp.code === 0) {
this.$toast.success(resp.msg)
this.doSearch()
}
})
})
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
initData() {
for (let i = new Date().getFullYear() - 10; i <= new Date().getFullYear(); i++) {
this.yearList.unshift({value: i, text: i + "年"})
}
this.$set(this.pageForm, "year", this.yearList[0].value)
},
},
created() {
this.initData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,142 @@
const UNION_REIMBURSE_INFO = {
template:
/*language=HTML*/`
<van-action-sheet v-model="visible" title="查看详情">
<div class="detail-container">
<van-cell-group title="报销申请">
<van-cell title="经办人">{{ viewData.userName }}</van-cell>
<van-cell title="工号">{{ viewData.loginName }}</van-cell>
<van-cell title="单位">{{ viewData.unitName }}</van-cell>
<van-cell title="工会">{{ viewData.unionName }}</van-cell>
<van-cell title="报销类别">
<dict-tag :options="dict.type.UNION_REIMBURSE_TYPE"
:value="viewData.reimburseType">
</dict-tag></van-cell>
<van-cell title="支付方式">
<dict-tag :options="dict.type.UNION_REIMBURSE_PAYMENT_WAY"
:value="viewData.paymentWay">
</dict-tag></van-cell>
<van-cell title="报销项目">
<dict-tag :options="dict.type.UNION_REIMBURSE_PROJECT"
:value="viewData.reimburseProject">
</dict-tag></van-cell>
<van-cell title="报销经费来源">
<dict-tag :options="dict.type.UNION_REIMBURSE_FUND_SOURCE"
:value="viewData.reimburseFundSource">
</dict-tag></van-cell>
<van-cell title="联系方式">{{ viewData.mobile }}</van-cell>
<van-cell title="所属社团" v-if="viewData.reimburseFundSource === 'UNION_REIMBURSE_FUND_SOURCE_3'">{{ viewData.clubName }}</van-cell>
<van-cell title="经费余额">{{ viewData.fundBalance }}</van-cell>
<van-cell title="户名">{{ viewData.bankUserName }}</van-cell>
<van-cell title="银行账号">{{ viewData.bankCardNumber }}</van-cell>
<van-cell title="开户行">{{ viewData.bankOfDeposit }}</van-cell>
<van-cell title="慰问对象" v-if="viewData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">{{ viewData.condolenceName }}</van-cell>
<van-cell title="联系方式" v-if="viewData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">{{ viewData.condolenceMobile }}</van-cell>
<van-cell title="慰问类型" v-if="viewData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">{{ viewData.typeName }}</van-cell>
<van-cell title="慰问金额" v-if="viewData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">{{ viewData.money }}</van-cell>
<van-cell title="慰问时间" v-if="viewData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">{{$moment(viewData.condolenceTime).format('YYYY-MM-DD')}}</van-cell>
<van-cell title="活动名称" v-if="viewData.reimburseProject !== 'UNION_REIMBURSE_PROJECT_1'">{{ viewData.activityName }}</van-cell>
<van-cell title="活动类型" v-if="viewData.reimburseProject === 'UNION_REIMBURSE_PROJECT_2'">{{ viewData.activityType }}</van-cell>
<van-cell title="活动人数" v-if="viewData.reimburseProject === 'UNION_REIMBURSE_PROJECT_2'">{{ viewData.activityNumber }}</van-cell>
<van-cell title="活动地点" v-if="viewData.reimburseProject !== 'UNION_REIMBURSE_PROJECT_1'">{{ viewData.activityPlace }}</van-cell>
<van-cell title="报销金额" v-if="viewData.reimburseProject !== 'UNION_REIMBURSE_PROJECT_1'">{{ viewData.money }}</van-cell>
<van-cell title="活动时间" v-if="viewData.reimburseProject !== 'UNION_REIMBURSE_PROJECT_1'">{{$moment(viewData.activityTime).format('YYYY-MM-DD')}}</van-cell>
<van-cell title="发票张数" v-if="viewData.reimburseType === 'UNION_REIMBURSE_TYPE_1'">{{ viewData.invoiceNumber }}</van-cell>
<van-cell title="发票号码" v-if="viewData.reimburseType === 'UNION_REIMBURSE_TYPE_1'">{{ viewData.invoice }}</van-cell>
<van-cell title="支付内容">{{ viewData.paymentNotes }}</van-cell>
<van-cell title="附件">
<file-preview :files="viewData.files" complete_result></file-preview>
</van-cell>
</van-cell-group>
<template v-for="(task,index) in doneTasks">
<div class="process-title">
{{ task.displayName }}
</div>
<van-cell-group v-if="task.ext.isFirstTaskNode">
<van-cell title="申请用户">
{{ task.ext.initiatorName}}({{task.ext.initiatorAccount}})
</van-cell>
<van-cell title="申请时间">
{{ task.finishTime}}
</van-cell>
<van-cell title="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag>
</van-cell>
</van-cell-group>
<van-cell-group v-else>
<van-cell title="办理用户">
{{ task.taskFormData.userName}}({{task.taskFormData.loginName}})
</van-cell>
<van-cell title="办理时间">
{{ task.finishTime}}
</van-cell>
<van-cell title="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag>
</van-cell>
<van-cell title="办理意见" v-if="!task.ext.isFirstTaskNode">
<template #label>
{{
task.taskFormData.opinion
}}
</template>
</van-cell>
<van-cell title="签字" v-if="!task.ext.isFirstTaskNode">
<van-image :src="task.ext.tf_userSign"
v-if="task.ext.tf_userSign"
class="signature-image"></van-image>
</van-cell>
</van-cell-group>
</template>
</div>
<slot></slot>
</van-action-sheet>
`,
dicts: ["UNION_REIMBURSE_TYPE", "UNION_REIMBURSE_PAYMENT_WAY", "UNION_REIMBURSE_FUND_SOURCE","UNION_REIMBURSE_PROJECT","PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
visible:false,
viewData: {},
doneTasks: [],
row: null,
}
},
methods: {
onOpen(row) {
this.row = row
this.visible = true
this.getInfo()
this.getDoneTasks()
},
// 关闭
onClose(){
this.visible = false
},
// 获取申请信息
getInfo() {
this.$axios.post("/platform/unionReimburse/apply/info", {id: this.row.id}).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
// 查看
openView(id) {
this.$nextTick(() => {
this.$refs.infoDialogRef.onOpen(id)
})
},
// 获取已办任务审批记录
getDoneTasks() {
this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data
}
})
},
},
}
@@ -0,0 +1,141 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="我的报销" placeholder fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
<van-dropdown-item :options="yearList" @change="doSearch" v-model="pageForm.year"></van-dropdown-item>
</van-dropdown-menu>
</van-sticky>
<table-list api="/platform/unionReimburse/mine/pageData" :page_form.sync="pageForm" ref="tableListRef"
@ready="doSearch" >
<template v-slot="{index,row}">
<table-column label="经办人">{{row.userName}}</table-column>
<table-column label="所属工会">{{row.unionName}}</table-column>
<table-column label="所属单位">{{row.unitName}}</table-column>
<table-column label="报销类别">
<dict-tag :options="dict.type.UNION_REIMBURSE_TYPE"
:value="row.reimburseType">
</dict-tag>
</table-column>
<table-column label="报销项目">
<dict-tag :options="dict.type.UNION_REIMBURSE_PROJECT"
:value="row.reimburseProject">
</dict-tag>
</table-column>
<table-column label="金额">{{row.money}}</table-column>
<table-column label="当前节点">{{row.taskName}}</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="onEdit(row)" v-if="row.taskKey === 'startTask' || !row.instanceId">
<i class="fa fa-edit"></i>
<span>编辑</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
<div class="action-btn delete" @click="onDelete(row)" v-if="row.taskKey === 'startTask' || !row.instanceId">
<i class="fa fa-trash"></i>
<span>删除</span>
</div>
</template>
</table-list>
<union-reimburse-info ref="unionReimburseInfoRef"></union-reimburse-info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../info.js'){}#-->
const vue = new Vue({
el: "#app",
store,
dicts: ["UNION_REIMBURSE_TYPE","UNION_REIMBURSE_PROJECT"],
components: {
"union-reimburse-info":UNION_REIMBURSE_INFO
},
data() {
return {
viewShow: false,
yearList: [],
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: "",
year: "",
},
infoShow: false
}
},
methods: {
onView(row) {
this.showApprovalForm = false
this.$refs.unionReimburseInfoRef.onOpen(row)
},
onEdit(row) {
this.$pjaxReplace('/platform/unionReimburse/apply/h5?taskId=' + (row.startTaskId || '') + "&bizId=" + row.id)
},
onRevoke(row){
this.$dialog
.confirm({
title: "提示",
message: "您确定要撤销申请吗?"
})
.then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.startTaskId}).then((resp) => {
this.$toast.success(resp.msg)
this.doSearch()
})
})
},
onDelete(row) {
this.$dialog
.confirm({
title: "提示",
message: "您确定要删除吗?"
})
.then(() => {
this.$axios.post("/platform/unionReimburse/mine/delete", {id: row.id}).then((resp) => {
if (resp.code === 0) {
this.$toast.success(resp.msg)
this.doSearch()
}
})
})
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
initData() {
for (let i = new Date().getFullYear() - 10; i <= new Date().getFullYear(); i++) {
this.yearList.unshift({value: i, text: i + "年"})
}
this.$set(this.pageForm, "year", this.yearList[0].value)
},
},
created() {
this.initData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,195 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="报销审核" placeholder fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-search
:reverse-color="false"
:show-action="false"
@search="doSearch"
input-align="left"
placeholder="请输入经办人搜索"
v-model="pageForm.userName"
></van-search>
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.approval = val==='1';this.doSearch();}">
<van-tab title="已审核" name="1"></van-tab>
<van-tab title="未审核" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/unionReimburse/review/pageData" :page_form.sync="pageForm" ref="tableListRef"
@ready="doSearch" >
<template v-slot="{index,row}">
<table-column label="经办人">{{row.userName}}</table-column>
<table-column label="所属工会">{{row.unionName}}</table-column>
<table-column label="所属单位">{{row.unitName}}</table-column>
<table-column label="报销类别">
<dict-tag :options="dict.type.UNION_REIMBURSE_TYPE"
:value="row.reimburseType">
</dict-tag>
</table-column>
<table-column label="报销项目">
<dict-tag :options="dict.type.UNION_REIMBURSE_PROJECT"
:value="row.reimburseProject">
</dict-tag>
</table-column>
<table-column label="金额">{{row.money}}</table-column>
<table-column label="当前节点">{{row.curTaskName}}</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" v-if="row.taskState === 10" @click="onAudit(row)">
<i class="fa fa-edit"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
</template>
</table-list>
<union-reimburse-info ref="unionReimburseInfoRef">
<div v-if="showApprovalForm">
<div class="process-title">
校工会审核
</div>
<div class="form-container">
<van-form ref="formRef">
<van-cell-group title="审批意见">
<van-field label=""
:rules="[{ required: true,message:'请填审批意见' }]"
v-model="formData.tf_opinion"
required
type="textarea"
name="tf_opinion"
rows="4"
autosize
class="more-text"
placeholder="请填审批意见"></van-field>
</van-cell-group>
<van-cell-group title="电子签名" class="form-section">
<van-field class="more-text" name="tf_userSign" label="">
<template #input>
<h5-signature v-model="formData.tf_userSign" slot="input"></h5-signature>
</template>
</van-field>
</van-cell-group>
<!-- 按钮区域 -->
<div class="form-actions">
<van-button type="danger" @click="handleTaskAction(6)">退回到发起人</van-button>
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
<van-button type="primary" @click="handleTaskAction(1)">同意申请</van-button>
</div>
</van-form>
</div>
</div>
</union-reimburse-info>
</div>
<script nonce="${cspNonce!}">
<!--#include('../info.js'){}#-->
const vue = new Vue({
el: "#app",
store,
dicts: ["UNION_REIMBURSE_TYPE","UNION_REIMBURSE_PROJECT"],
components: {
"union-reimburse-info":UNION_REIMBURSE_INFO
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: "",
approvalText: "0",
approval: false,
year: new Date().getFullYear(),
},
formData: {},
showApprovalForm: false,
infoShow: false
}
},
methods: {
onRevoke(row) {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要撤回吗?',
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.infoShow = false
}
})
}).catch(() => {
// on cancel
});
},
handleTaskAction(val) {
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: '温馨提示',
message: '您确定要提交吗?',
}).then(() => {
this.$axios.post('/flow/common/executeTask', {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.$refs.unionReimburseInfoRef.onClose()
}
})
}).catch(() => {
// on cancel
});
}).catch();
},
onView(row) {
this.showApprovalForm = false
this.$refs.unionReimburseInfoRef.onOpen(row)
},
onAudit(row) {
this.showApprovalForm = true
this.formData = {
tf_opinion: null,
tf_userSign: null,
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.unionReimburseInfoRef.onOpen(row)
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
},
created() {
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,240 @@
const PROPOSAL_INFO = {
name: "ProposalInfo",
template: /*language=HTML*/ `
<van-action-sheet v-model="visible" title="查看详情">
<div class="detail-container">
<van-cell-group title="基本信息">
<van-cell title="提案名称">
<div style="font-weight:bold;">
{{ viewData.name }}
</div>
</van-cell>
<van-cell title="提案编号">{{ viewData.code }}</van-cell>
<van-cell title="提案人">{{ viewData.createUserName }}</van-cell>
<van-cell title="提案时间">{{ viewData.createTime }}</van-cell>
<van-cell title="教代会届次">{{ viewData.fullName }}</van-cell>
<van-cell title="提案人单位">{{ viewData.unitName }}</van-cell>
<van-cell :title="viewData.mannerCode!=='W03'?'代表团名称':'委员会名称'">
{{ viewData.mannerCode !== 'W03' ? viewData.delegationName : viewData.committeeName }}
</van-cell>
<van-cell title="提案类别">
{{viewData.typeName}}
</van-cell>
<van-cell title="建议承办单位">
{{viewData.suggestUnits}}
</van-cell>
<van-cell title="立案结果">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="viewData.caseFilingResult"></dict-tag>
</van-cell>
<!--<van-cell title="调研情况" class="direction-column-cell">
<div v-html="viewData.researchFindings"></div>
</van-cell>-->
<van-cell title="提案案由" class="direction-column-cell">
<div v-html="viewData.brief"></div>
</van-cell>
<van-cell title="建议措施" class="direction-column-cell">
<div v-html="viewData.measures"></div>
</van-cell>
<van-cell title="附件" class="direction-column-cell">
<file-preview :files="viewData.files" complete_result></file-preview>
</van-cell>
<!-- <van-cell title="签字">-->
<!-- <div slot="label">-->
<!-- <van-image :src="viewData.signature"-->
<!-- style="width: 100%;height: 150px;border: 1px dashed"></van-image>-->
<!-- </div>-->
<!-- </van-cell>-->
</van-cell-group>
<!--并案信息-->
<van-cell-group title="并案信息" v-if="viewData.merges && viewData.merges.length">
<van-cell v-for="(merge, index) in viewData.merges" :key="merge.id"
:title="(index + 1) + '. ' + merge.name"
:label="'提案编号:' + merge.code + ' | 提案人:' + merge.createUserName + ' | 类别:' + merge.typeName + ' | 代表团:' + merge.delegationName"
is-link
@click="openView(merge)">
</van-cell>
</van-cell-group>
<!--委员会成员意见-->
<template v-if="viewData.commissionerOpinions && viewData.commissionerOpinions.length">
<div class="process-title" style="margin-bottom: 0!important;">
委员会成员意见
</div>
<div v-for="(opinion, index) in viewData.commissionerOpinions" :key="index"
style="margin-bottom: 16px;">
<van-cell :title="opinion.commissionerName + '(' + opinion.commissionerLoginName + ')'"
class="direction-column-cell">
</van-cell>
<van-cell title="立案结果">
<div style="display: flex;justify-content: end;">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="opinion.caseFilingResult"></dict-tag>
<template v-if="opinion.caseFilingType">
(
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_TYPE"
:value="opinion.caseFilingType"></dict-tag>
)
</template>
</div>
</van-cell>
<van-cell title="意见" v-if="opinion.opinionText">
<div>{{ opinion.opinionText }}</div>
</van-cell>
<van-cell title="时间" v-if="opinion.opinionTime">
{{ opinion.opinionTime }}
</van-cell>
</div>
</template>
<template v-for="task in doneTasks">
<van-cell-group :title="task.displayName" v-if="task.ext.isFirstTaskNode">
<van-cell title="申请用户">{{ task.ext.initiatorName }}({{task.ext.initiatorAccount}})
</van-cell>
<van-cell title="申请时间">{{ task.finishTime }}</van-cell>
<van-cell title="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag>
</van-cell>
</van-cell-group>
<!--邀请附议人-->
<van-cell-group :title="task.displayName"
v-else-if="task.taskName === 'invite'">
<van-cell title="办理用户">{{ task.taskFormData.userName }}({{task.taskFormData.loginName}})
</van-cell>
<van-cell title="办理时间">{{ task.finishTime }}</van-cell>
<van-cell title="附议人" v-if="task.taskName === 'invite'"
class="direction-column-cell">
<el-table :data="task?.taskFormData?.seconder">
<el-table-column label="姓名" prop="userName"></el-table-column>
<el-table-column label="工号" prop="loginName"></el-table-column>
<el-table-column label="性别" prop="sex"></el-table-column>
<el-table-column label="单位" prop="unitName" show-overflow-tooltip></el-table-column>
<el-table-column label="分工会" prop="unionName"
show-overflow-tooltip></el-table-column>
<el-table-column label="代表团" prop="delegationName"
show-overflow-tooltip></el-table-column>
</el-table>
</van-cell>
</van-cell-group>
<!--提案委员会立案-->
<van-cell-group :title="task.displayName"
v-else-if="task.taskName === 'committee'">
<van-cell title="办理用户">{{ task.taskFormData.userName }}({{task.taskFormData.loginName}})
</van-cell>
<van-cell title="办理时间">{{ task.finishTime }}</van-cell>
<van-cell title="立案结果">
<div style="display: flex;justify-content: center">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="task.ext.tf_caseFilingResult"></dict-tag>
<template v-if="task.ext.tf_caseFilingType">
(
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_TYPE"
:value="task.ext.tf_caseFilingType"></dict-tag>
)
</template>
</div>
</van-cell>
<van-cell title="主办单位">{{ task.ext.tf_masterUnitName }}</van-cell>
<van-cell title="协办单位">{{ task?.ext?.tf_slaveUnitNameStr }}</van-cell>
</van-cell-group>
<van-cell-group :title="task.displayName" v-else>
<van-cell title="办理单位" v-if="['master_reply','slave_reply'].includes(task.taskName)">
{{task.ext.underTakeName}}
</van-cell>
<van-cell title="办理用户">{{ task.taskFormData.userName }}({{task.taskFormData.loginName}})
</van-cell>
<van-cell title="办理时间">{{ task.finishTime }}</van-cell>
<van-cell title="办理评价" v-if="['feedback'].includes(task.taskName)">
<dict-tag :options="dict.type.PROPOSAL_FEEDBACK"
:value="task.ext.tf_feedback"></dict-tag>
</van-cell>
<van-cell title="办理结果" v-else>
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag>
</van-cell>
<van-cell title="办理意见" v-if="!task.ext.isFirstTaskNode" class="direction-column-cell">
<div v-html="task.taskFormData.tf_opinion"></div>
</van-cell>
</van-cell-group>
</template>
</div>
<slot></slot>
</van-action-sheet>
`,
dicts: ["PROPOSAL_TYPE", "PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE", "PROCESS_TASK_SUBMIT_TYPE", "PROPOSAL_FEEDBACK"],
data() {
return {
visible:false,
viewData: {},
doneTasks: [],
row: null,
originalRow: null, // 用于保存原始数据,支持返回功能
}
},
methods: {
// 打开
onOpen(row) {
this.row = row
this.visible = true
this.getInfo()
this.getDoneTasks()
},
// 关闭
onClose(){
this.visible = false
},
// 获取申请信息
getInfo() {
this.$axios.post("/platform/proposal/common/proposalInfo", {id: this.row.id}).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
// 查看提案
openView(row) {
// 如果传入的是并案对象,则打开新的详情页面
if (row && typeof row === 'object' && row.id) {
// 创建一个新的提案详情组件实例来显示并案详情
this.$nextTick(() => {
// 可以通过事件总线或者其他方式来打开新的详情页面
// 这里暂时使用简单的方式,直接在当前组件中显示
const currentRow = this.row;
this.row = row;
this.getInfo();
// 保存原来的数据,以便返回时恢复
this.originalRow = currentRow;
})
} else {
// 原有的逻辑,通过ID查看
this.$nextTick(() => {
if (this.$refs.infoDialogRef) {
this.$refs.infoDialogRef.onOpen(row)
}
})
}
},
// 获取已办任务审批记录
getDoneTasks() {
this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data
}
})
},
}
};

Some files were not shown because too many files have changed in this diff Show More