first commit
This commit is contained in:
@@ -0,0 +1,645 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
body {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.culture-activity-page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: calc(24px + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.culture-activity-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.culture-activity-page .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.culture-activity-page .van-nav-bar .van-icon,
|
||||
.culture-activity-page .van-nav-bar__text {
|
||||
color: #397fbd;
|
||||
}
|
||||
|
||||
.culture-activity-content {
|
||||
padding: 12px 12px 0;
|
||||
}
|
||||
|
||||
.culture-activity-hero {
|
||||
position: relative;
|
||||
height: 134px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
color: #fff;
|
||||
background-color: #247fe8;
|
||||
box-shadow: 0 8px 20px rgba(51, 117, 219, .18);
|
||||
}
|
||||
|
||||
.culture-activity-hero__image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
|
||||
.culture-activity-hero__copy {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
width: 64%;
|
||||
height: 100%;
|
||||
padding-left: 16px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
background: linear-gradient(90deg, rgba(22, 112, 232, .98) 0%, rgba(22, 112, 232, .88) 52%, rgba(22, 112, 232, 0) 100%);
|
||||
}
|
||||
|
||||
.culture-activity-hero__title {
|
||||
font-size: 25px;
|
||||
line-height: 34px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1px;
|
||||
text-shadow: 0 2px 6px rgba(17, 86, 182, .18);
|
||||
}
|
||||
|
||||
.culture-activity-hero__subtitle {
|
||||
margin-top: 4px;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
letter-spacing: .5px;
|
||||
opacity: .95;
|
||||
}
|
||||
|
||||
.culture-activity-sticky {
|
||||
padding: 10px 0 1px;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.van-sticky--fixed .culture-activity-sticky {
|
||||
padding-right: 12px;
|
||||
padding-left: 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.culture-activity-search {
|
||||
margin: 0 0 8px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .1);
|
||||
}
|
||||
|
||||
.culture-activity-search .van-search__content {
|
||||
height: 42px;
|
||||
padding-left: 12px;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.culture-activity-search .van-field__control {
|
||||
color: #263548;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.culture-activity-search .van-field__control::placeholder {
|
||||
color: #a7b0bf;
|
||||
}
|
||||
|
||||
.culture-activity-filter {
|
||||
margin: 0 0 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .08);
|
||||
transition: border-radius .18s ease;
|
||||
}
|
||||
|
||||
.culture-activity-filter.is-open {
|
||||
border-radius: 10px 10px 0 0;
|
||||
}
|
||||
|
||||
.culture-activity-filter .van-dropdown-menu__bar {
|
||||
height: 44px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.culture-activity-filter .van-dropdown-menu__item {
|
||||
min-width: 0;
|
||||
flex: 1 1 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.culture-activity-filter .van-dropdown-menu__item:last-child {
|
||||
flex-grow: 1.35;
|
||||
}
|
||||
|
||||
.culture-activity-filter .van-dropdown-menu__title {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 0 15px 0 4px;
|
||||
overflow: hidden;
|
||||
color: #66758a;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.culture-activity-filter .van-dropdown-menu__title::after {
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.culture-activity-filter .van-dropdown-menu__title--active,
|
||||
.culture-activity-filter .van-dropdown-item__option--active,
|
||||
.culture-activity-filter .van-dropdown-item__option--active .van-dropdown-item__icon {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.culture-activity-filter .van-dropdown-menu__title--down::after {
|
||||
border-color: transparent transparent #1989fa #1989fa;
|
||||
}
|
||||
|
||||
.culture-activity-filter .van-dropdown-item__content {
|
||||
width: calc(100% - 24px);
|
||||
margin: 0 12px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0 0 12px 12px;
|
||||
box-shadow: 0 10px 24px rgba(31, 65, 108, .14);
|
||||
}
|
||||
|
||||
.culture-activity-filter .van-dropdown-item__option {
|
||||
min-height: 48px;
|
||||
padding: 0 16px;
|
||||
color: #46566c;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.culture-activity-filter .van-cell::after {
|
||||
right: 16px;
|
||||
left: 16px;
|
||||
}
|
||||
|
||||
.culture-activity-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.culture-activity-card {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
}
|
||||
|
||||
.culture-activity-card__cover,
|
||||
.culture-activity-card__cover-state {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
background-color: #edf4fc;
|
||||
}
|
||||
|
||||
.culture-activity-card__cover {
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.culture-activity-card__cover-state {
|
||||
flex-direction: column;
|
||||
row-gap: 8px;
|
||||
color: #8da1ba;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.culture-activity-card__cover-state .van-icon {
|
||||
font-size: 34px;
|
||||
}
|
||||
|
||||
.culture-activity-card__cover-state.is-error {
|
||||
color: #c27b75;
|
||||
background-color: #fff3f1;
|
||||
}
|
||||
|
||||
.culture-activity-card__body {
|
||||
padding: 12px 38px 14px 14px;
|
||||
}
|
||||
|
||||
.culture-activity-card__title {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
color: #303846;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.culture-activity-card__time {
|
||||
margin-top: 4px;
|
||||
color: #98a2b2;
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.culture-activity-card__meta {
|
||||
margin-top: 10px;
|
||||
padding-top: 9px;
|
||||
border-top: 1px solid #edf1f6;
|
||||
}
|
||||
|
||||
.culture-activity-card__address {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
color: #69788d;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.culture-activity-card__address .van-icon {
|
||||
margin: 2px 5px 0 0;
|
||||
flex: none;
|
||||
color: #6c9ff8;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.culture-activity-card__address span {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.culture-activity-card__tags {
|
||||
display: flex;
|
||||
margin-top: 8px;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.culture-activity-card__tag {
|
||||
display: inline-flex;
|
||||
padding: 3px 8px;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
color: #397de0;
|
||||
background-color: #edf5ff;
|
||||
font-size: 11px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.culture-activity-card__tag-label {
|
||||
margin-right: 4px;
|
||||
color: #8aa7cf;
|
||||
}
|
||||
|
||||
.culture-activity-card__arrow {
|
||||
position: absolute;
|
||||
top: 164px;
|
||||
right: 14px;
|
||||
color: #b4bdca;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.culture-activity-empty {
|
||||
display: flex;
|
||||
min-height: 260px;
|
||||
padding: 26px 18px 32px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.culture-activity-empty img {
|
||||
display: block;
|
||||
width: 82%;
|
||||
max-width: 280px;
|
||||
height: auto;
|
||||
border-radius: 12px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.culture-activity-empty__title {
|
||||
margin-top: 14px;
|
||||
color: #50627a;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.culture-activity-empty__hint {
|
||||
margin-top: 5px;
|
||||
color: #9aa7b8;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.culture-activity-page .van-list__finished-text,
|
||||
.culture-activity-page .van-list__loading {
|
||||
color: #9aa7b8;
|
||||
font-size: 13px;
|
||||
line-height: 44px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<div class="culture-activity-page">
|
||||
<van-nav-bar title="文化活动" @click-left="historyBack" left-arrow left-text="返回" placeholder fixed></van-nav-bar>
|
||||
|
||||
<div class="culture-activity-content">
|
||||
<section class="culture-activity-hero">
|
||||
<img class="culture-activity-hero__image" src="/assets/mobile/img/activity/hero/culture-hero-v3.png" alt="文化活动插画">
|
||||
<div class="culture-activity-hero__copy">
|
||||
<div class="culture-activity-hero__title">文化活动</div>
|
||||
<div class="culture-activity-hero__subtitle">丰富生活 · 乐享校园</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<van-sticky :offset-top="46">
|
||||
<div class="culture-activity-sticky">
|
||||
<van-search
|
||||
v-model="searchKeyword"
|
||||
class="culture-activity-search"
|
||||
placeholder="搜索文化活动"
|
||||
shape="round"
|
||||
clearable
|
||||
@search="doSearch"
|
||||
@clear="doSearch"
|
||||
></van-search>
|
||||
<van-dropdown-menu class="culture-activity-filter" :class="{'is-open': filterOpened}" active-color="#1989fa">
|
||||
<year-van-dropdown-item :num="5" @change="doSearch" @open="filterOpened = true" @close="filterOpened = false" v-model="pageForm.year"></year-van-dropdown-item>
|
||||
<van-dropdown-item :options="stateList" @change="doSearch" @open="filterOpened = true" @close="filterOpened = false" v-model="pageForm.state"></van-dropdown-item>
|
||||
<van-dropdown-item :options="isEnrolledOptions" @change="doSearch" @open="filterOpened = true" @close="filterOpened = false" v-model="pageForm.isEnrolled"></van-dropdown-item>
|
||||
<van-dropdown-item :options="activityTypeOptions" @change="doSearch" @open="filterOpened = true" @close="filterOpened = false" v-model="pageForm.activity_type"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</div>
|
||||
</van-sticky>
|
||||
|
||||
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
|
||||
<van-list v-model="loading" :finished="finished" @load="onLoad">
|
||||
<div class="culture-activity-list">
|
||||
<div v-for="row in tableData" :key="row.id" class="culture-activity-card" @click="openDetail(row)">
|
||||
<img
|
||||
v-if="hasCover(row) && !imageLoadErrors[row.id]"
|
||||
class="culture-activity-card__cover"
|
||||
:src="row.cover"
|
||||
:alt="row.name"
|
||||
@error="handleImageError(row)"
|
||||
>
|
||||
<div v-else class="culture-activity-card__cover-state" :class="{'is-error': hasCover(row)}">
|
||||
<van-icon name="photo-o"></van-icon>
|
||||
<span>{{ hasCover(row) ? '图片加载失败' : '暂无图片' }}</span>
|
||||
</div>
|
||||
<div class="culture-activity-card__body">
|
||||
<div class="culture-activity-card__title">{{ row.name }}</div>
|
||||
<div class="culture-activity-card__time" v-if="row.applyStartTime && row.applyEndTime">
|
||||
报名时间:{{ $moment(row.applyStartTime).format('MM/DD HH:mm') }}~{{ $moment(row.applyEndTime).format('MM/DD HH:mm') }}
|
||||
</div>
|
||||
<div class="culture-activity-card__time" v-if="row.startTime && row.endTime">
|
||||
活动时间:{{ $moment(row.startTime).format('MM/DD HH:mm') }}~{{ $moment(row.endTime).format('MM/DD HH:mm') }}
|
||||
</div>
|
||||
<div class="culture-activity-card__meta" v-if="row.address || row.projectTypeName || formatSignUpMethod(row.signUpMethod)">
|
||||
<div class="culture-activity-card__address" v-if="row.address">
|
||||
<van-icon name="location-o"></van-icon>
|
||||
<span>{{ row.address }}</span>
|
||||
</div>
|
||||
<div class="culture-activity-card__tags" v-if="row.projectTypeName || formatSignUpMethod(row.signUpMethod)">
|
||||
<span class="culture-activity-card__tag" v-if="row.projectTypeName">
|
||||
<span class="culture-activity-card__tag-label">活动类型</span>{{ row.projectTypeName }}
|
||||
</span>
|
||||
<span class="culture-activity-card__tag" v-if="formatSignUpMethod(row.signUpMethod)">
|
||||
<span class="culture-activity-card__tag-label">报名方式</span>{{ formatSignUpMethod(row.signUpMethod) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<van-icon class="culture-activity-card__arrow" name="arrow"></van-icon>
|
||||
</div>
|
||||
</div>
|
||||
</van-list>
|
||||
<div v-if="!loading && tableData.length === 0" class="culture-activity-empty">
|
||||
<img src="/assets/mobile/img/activity/culture-empty.png" alt="文化活动空状态插画">
|
||||
<div class="culture-activity-empty__title">暂无文化活动</div>
|
||||
<div class="culture-activity-empty__hint">当前筛选条件下暂时没有可展示的活动</div>
|
||||
</div>
|
||||
</van-pull-refresh>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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,
|
||||
searchKeyword: "",
|
||||
imageLoadErrors: {},
|
||||
filterOpened: false,
|
||||
pageForm: {
|
||||
state: 2,
|
||||
isEnrolled: 0,
|
||||
year: new Date().getFullYear(),
|
||||
name: "",
|
||||
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()
|
||||
},
|
||||
hasCover(row) {
|
||||
return !!(row && row.cover && String(row.cover).trim())
|
||||
},
|
||||
handleImageError(row) {
|
||||
this.$set(this.imageLoadErrors, row.id, true)
|
||||
},
|
||||
formatSignUpMethod(value) {
|
||||
return {
|
||||
1: "个人报名",
|
||||
2: "组队报名",
|
||||
3: "分工会报名"
|
||||
}[Number(value)] || ""
|
||||
},
|
||||
onLoad() {
|
||||
if (!this.finished) this.loadActivities(false)
|
||||
},
|
||||
onRefresh() {
|
||||
this.loadActivities(true)
|
||||
},
|
||||
loadActivities(reset) {
|
||||
if (reset) {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.tableData = []
|
||||
this.finished = false
|
||||
this.imageLoadErrors = {}
|
||||
}
|
||||
this.loading = true
|
||||
this.$axios.post("/platform/activity/culture/applyUser/pageData", this.pageForm).then((res) => {
|
||||
if (res.code === 0) {
|
||||
const list = res.data && res.data.list ? res.data.list : []
|
||||
this.tableData = this.pageForm.pageNumber === 1 ? list : this.tableData.concat(list)
|
||||
this.pageForm.totalCount = res.data && res.data.totalCount ? res.data.totalCount : 0
|
||||
this.finished = this.tableData.length >= this.pageForm.totalCount
|
||||
if (!this.finished) this.pageForm.pageNumber++
|
||||
}
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
this.refreshing = false
|
||||
})
|
||||
},
|
||||
|
||||
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.pageForm.name = this.searchKeyword.trim()
|
||||
this.loadActivities(true)
|
||||
}
|
||||
},
|
||||
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 = {}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,673 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
body {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.family-activity-page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: calc(24px + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.family-activity-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.family-activity-page .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.family-activity-page .van-nav-bar .van-icon,
|
||||
.family-activity-page .van-nav-bar__text {
|
||||
color: #397fbd;
|
||||
}
|
||||
|
||||
.family-activity-content {
|
||||
padding: 12px 12px 0;
|
||||
}
|
||||
|
||||
.family-activity-hero {
|
||||
position: relative;
|
||||
height: 134px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
color: #fff;
|
||||
background-color: #247fe8;
|
||||
box-shadow: 0 8px 20px rgba(51, 117, 219, .18);
|
||||
}
|
||||
|
||||
.family-activity-hero__image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: left center;
|
||||
}
|
||||
|
||||
.family-activity-hero__copy {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
width: 64%;
|
||||
height: 100%;
|
||||
padding-left: 16px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
background: linear-gradient(90deg, rgba(22, 112, 232, .98) 0%, rgba(22, 112, 232, .88) 52%, rgba(22, 112, 232, 0) 100%);
|
||||
}
|
||||
|
||||
.family-activity-hero__title {
|
||||
font-size: 25px;
|
||||
line-height: 34px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1px;
|
||||
text-shadow: 0 2px 6px rgba(17, 86, 182, .18);
|
||||
}
|
||||
|
||||
.family-activity-hero__subtitle {
|
||||
margin-top: 4px;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
letter-spacing: .5px;
|
||||
opacity: .95;
|
||||
}
|
||||
|
||||
.family-activity-sticky {
|
||||
padding: 10px 0 1px;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.van-sticky--fixed .family-activity-sticky {
|
||||
padding-right: 12px;
|
||||
padding-left: 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.family-activity-search {
|
||||
margin: 0 0 8px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .1);
|
||||
}
|
||||
|
||||
.family-activity-search .van-search__content {
|
||||
height: 42px;
|
||||
padding-left: 12px;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.family-activity-filter {
|
||||
margin-bottom: 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .08);
|
||||
transition: border-radius .18s ease;
|
||||
}
|
||||
|
||||
.family-activity-filter.is-open {
|
||||
border-radius: 10px 10px 0 0;
|
||||
}
|
||||
|
||||
.family-activity-filter .van-dropdown-menu__bar {
|
||||
height: 44px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.family-activity-filter .van-dropdown-menu__title {
|
||||
color: #66758a;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.family-activity-filter .van-dropdown-menu__title--active,
|
||||
.family-activity-filter .van-dropdown-item__option--active,
|
||||
.family-activity-filter .van-dropdown-item__option--active .van-dropdown-item__icon {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.family-activity-filter .van-dropdown-item__content {
|
||||
width: calc(100% - 24px);
|
||||
margin: 0 12px;
|
||||
overflow: hidden;
|
||||
border-radius: 0 0 12px 12px;
|
||||
box-shadow: 0 10px 24px rgba(31, 65, 108, .14);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.family-activity-list .table-list-container {
|
||||
display: flex;
|
||||
margin-top: 0 !important;
|
||||
padding: 0 !important;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.family-activity-list .table-list-item {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
overflow: hidden;
|
||||
border: 0 !important;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
}
|
||||
|
||||
.family-activity-list .table-list-item .item-header {
|
||||
display: block !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.family-activity-list .table-list-item .item-actions:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.family-activity-card__cover,
|
||||
.family-activity-card__cover-state {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
background-color: #edf4fc;
|
||||
}
|
||||
|
||||
.family-activity-card__cover {
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.family-activity-card__cover-state {
|
||||
flex-direction: column;
|
||||
row-gap: 8px;
|
||||
color: #8da1ba;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.family-activity-card__cover-state .van-icon {
|
||||
font-size: 34px;
|
||||
}
|
||||
|
||||
.family-activity-card__cover-state.is-error {
|
||||
color: #c27b75;
|
||||
background-color: #fff3f1;
|
||||
}
|
||||
|
||||
.family-activity-card__body {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding: 12px 38px 14px 14px;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.family-activity-card__title {
|
||||
overflow: hidden;
|
||||
color: #303846;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.family-activity-card__time {
|
||||
margin-top: 4px;
|
||||
overflow: hidden;
|
||||
color: #98a2b2;
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.family-activity-card__meta {
|
||||
display: flex;
|
||||
margin-top: 10px;
|
||||
padding-top: 9px;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
border-top: 1px solid #edf1f6;
|
||||
}
|
||||
|
||||
.family-activity-card__tag {
|
||||
display: inline-flex;
|
||||
padding: 3px 8px;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
color: #397de0;
|
||||
background-color: #edf5ff;
|
||||
font-size: 11px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.family-activity-card__tag-label {
|
||||
margin-right: 4px;
|
||||
color: #8aa7cf;
|
||||
}
|
||||
|
||||
.family-activity-card__arrow {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 14px;
|
||||
color: #b4bdca;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.family-activity-empty {
|
||||
display: flex;
|
||||
min-height: 260px;
|
||||
padding: 26px 18px 32px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.family-activity-empty img {
|
||||
width: 82%;
|
||||
max-width: 280px;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.family-activity-empty__title {
|
||||
margin-top: 14px;
|
||||
color: #50627a;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.family-activity-empty__hint {
|
||||
margin-top: 5px;
|
||||
color: #9aa7b8;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.family-intro-popup,
|
||||
.family-intro-page {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.family-intro-page {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.family-intro-scroll {
|
||||
height: calc(100vh - 46px);
|
||||
padding: 12px 12px calc(92px + env(safe-area-inset-bottom));
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.family-intro-hero {
|
||||
display: flex;
|
||||
min-height: 82px;
|
||||
padding: 16px;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
color: #fff;
|
||||
background: linear-gradient(120deg, #2d7eea 0%, #5ba6f7 100%);
|
||||
box-shadow: 0 8px 20px rgba(45, 126, 234, .18);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.family-intro-hero__icon {
|
||||
display: flex;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
margin-right: 12px;
|
||||
flex: 0 0 44px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 11px;
|
||||
color: #2d7eea;
|
||||
background-color: rgba(255, 255, 255, .92);
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.family-intro-hero__title {
|
||||
font-size: 17px;
|
||||
line-height: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.family-intro-hero__subtitle {
|
||||
margin-top: 3px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
.family-intro-card {
|
||||
margin-top: 12px;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
}
|
||||
|
||||
.family-intro-card .content {
|
||||
padding: 0 !important;
|
||||
color: #3f4c5e !important;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.family-intro-card .content div,
|
||||
.family-intro-card .content p,
|
||||
.family-intro-card .content span,
|
||||
.family-intro-card .content li {
|
||||
color: #3f4c5e !important;
|
||||
font-size: 14px !important;
|
||||
line-height: 1.8 !important;
|
||||
white-space: normal !important;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.family-intro-card .content h1,
|
||||
.family-intro-card .content h2,
|
||||
.family-intro-card .content h3,
|
||||
.family-intro-card .content h4 {
|
||||
margin: 16px 0 9px !important;
|
||||
color: #1f2f43 !important;
|
||||
font-size: 18px !important;
|
||||
line-height: 1.5 !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
.family-intro-card .content > :first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.family-intro-card .content p {
|
||||
margin: 0 0 8px !important;
|
||||
}
|
||||
|
||||
.family-intro-card .content ul,
|
||||
.family-intro-card .content ol {
|
||||
margin: 8px 0 !important;
|
||||
padding-left: 22px !important;
|
||||
}
|
||||
|
||||
.family-intro-card .content img {
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
margin: 8px auto !important;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.family-intro-card .content table {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.family-intro-empty {
|
||||
display: flex;
|
||||
min-height: 180px;
|
||||
margin-top: 12px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
row-gap: 10px;
|
||||
border-radius: 12px;
|
||||
color: #9aa7b8;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.family-intro-empty .van-icon {
|
||||
color: #83b5f4;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.family-intro-footer {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 5;
|
||||
padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
|
||||
border-top: 1px solid #edf1f6;
|
||||
background-color: rgba(255, 255, 255, .96);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.family-intro-footer .van-button {
|
||||
height: 42px;
|
||||
border: 0;
|
||||
border-radius: 21px;
|
||||
font-size: 15px;
|
||||
background-color: #1989fa;
|
||||
box-shadow: 0 6px 16px rgba(25, 137, 250, .22);
|
||||
}
|
||||
|
||||
.family-intro-footer .van-button--disabled {
|
||||
color: #8b98aa !important;
|
||||
background-color: #eef2f7 !important;
|
||||
opacity: 1;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.family-intro-footer .van-count-down {
|
||||
display: inline-block;
|
||||
margin-left: 4px;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<div class="family-activity-page">
|
||||
<van-nav-bar title="亲子活动" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||
|
||||
<div class="family-activity-content">
|
||||
<section class="family-activity-hero">
|
||||
<img class="family-activity-hero__image" src="/assets/mobile/img/activity/hero/family-hero-v3.png" alt="亲子活动插画">
|
||||
<div class="family-activity-hero__copy">
|
||||
<div class="family-activity-hero__title">亲子活动</div>
|
||||
<div class="family-activity-hero__subtitle">温馨陪伴 · 快乐成长</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<van-sticky :offset-top="46">
|
||||
<div class="family-activity-sticky">
|
||||
<van-search v-model="pageForm.searchKeyword" class="family-activity-search" placeholder="搜索亲子活动"
|
||||
shape="round" clearable @search="doSearch" @clear="doSearch"></van-search>
|
||||
<van-dropdown-menu class="family-activity-filter" :class="{'is-open': filterOpened}" active-color="#1989fa">
|
||||
<year-van-dropdown-item :num="5" @change="doSearch" @open="filterOpened = true" @close="filterOpened = false" v-model="pageForm.year"></year-van-dropdown-item>
|
||||
<van-dropdown-item v-model="pageForm.activityType" :options="typeOptions" :multiple="false"
|
||||
@change="doSearch" @open="filterOpened = true" @close="filterOpened = false"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</div>
|
||||
</van-sticky>
|
||||
|
||||
<table-list class="family-activity-list" api="/platform/family/apply/activityPageData"
|
||||
:page_form.sync="pageForm" ref="tableListRef" @ready="onReady">
|
||||
<template #empty>
|
||||
<div class="family-activity-empty">
|
||||
<img src="/assets/mobile/img/activity/family-empty.png" alt="亲子活动空状态插画">
|
||||
<div class="family-activity-empty__title">暂无亲子活动</div>
|
||||
<div class="family-activity-empty__hint">当前筛选条件下暂时没有可展示的活动</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #header="{index,row}">
|
||||
<img v-if="hasCover(row) && !imageLoadErrors[row.id]" class="family-activity-card__cover"
|
||||
:src="row.cover" :alt="row.activityName" @error="handleImageError(row)" @click="onView(row)">
|
||||
<div v-else class="family-activity-card__cover-state" :class="{'is-error': hasCover(row)}" @click="onView(row)">
|
||||
<van-icon name="photo-o"></van-icon>
|
||||
<span>{{ hasCover(row) ? '图片加载失败' : '暂无图片' }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot="{index,row}">
|
||||
<div class="family-activity-card__body" @click="onView(row)">
|
||||
<div class="family-activity-card__title">{{ row.activityName }}</div>
|
||||
<div class="family-activity-card__time" v-if="row.activitySignUpStartTime && row.activitySignUpEndTime">
|
||||
报名时间:{{ $moment(row.activitySignUpStartTime).format('MM/DD HH:mm') }}~{{ $moment(row.activitySignUpEndTime).format('MM/DD HH:mm') }}
|
||||
</div>
|
||||
<div class="family-activity-card__time" v-if="row.activityStartTime && row.activityEndTime">
|
||||
活动时间:{{ $moment(row.activityStartTime).format('MM/DD HH:mm') }}~{{ $moment(row.activityEndTime).format('MM/DD HH:mm') }}
|
||||
</div>
|
||||
<div class="family-activity-card__meta" v-if="row.activityGroupName || row.trainType">
|
||||
<span class="family-activity-card__tag" v-if="row.activityGroupName"><span class="family-activity-card__tag-label">面向对象</span>{{row.activityGroupName}}</span>
|
||||
<span class="family-activity-card__tag" v-if="row.trainType"><span class="family-activity-card__tag-label">活动类型</span>{{row.trainType}}</span>
|
||||
</div>
|
||||
<van-icon class="family-activity-card__arrow" name="arrow"></van-icon>
|
||||
</div>
|
||||
</template>
|
||||
</table-list>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<van-popup class="family-intro-popup" :style="{height: '100%', width: '100%'}" position="right" safe-area-inset-bottom v-model="infoVisible">
|
||||
<div class="family-intro-page">
|
||||
<van-nav-bar title="活动介绍" left-text="返回" left-arrow @click-left="infoVisible = false"></van-nav-bar>
|
||||
<div class="family-intro-scroll">
|
||||
<div class="family-intro-hero">
|
||||
<div class="family-intro-hero__icon"><van-icon name="description"></van-icon></div>
|
||||
<div>
|
||||
<div class="family-intro-hero__title">亲子活动报名须知</div>
|
||||
<div class="family-intro-hero__subtitle">请仔细阅读活动安排与报名要求</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="family-intro-card" v-if="infoRow.introduce">
|
||||
<pdf-preview :content="infoRow.introduce"></pdf-preview>
|
||||
</div>
|
||||
<div v-else class="family-intro-empty">
|
||||
<van-icon name="description"></van-icon>
|
||||
<span>暂无活动介绍</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="family-intro-footer">
|
||||
<van-button v-if="canApply(infoRow)" @click="onApply(infoRow)" type="primary" block round>进入报名</van-button>
|
||||
<van-button v-else-if="time < 0" @click="onApply(infoRow)" type="primary" block round>
|
||||
距离开始
|
||||
<van-count-down :time="Math.abs(time)" format="DD 天 HH 时 mm 分 ss 秒" @finish="time = 0"></van-count-down>
|
||||
</van-button>
|
||||
<van-button v-else disabled block round>{{ registrationStatusText(infoRow) }}</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
|
||||
</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: {},
|
||||
imageLoadErrors: {},
|
||||
filterOpened: false,
|
||||
|
||||
id: GetQueryString('id')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
hasCover(row) {
|
||||
return !!(row && row.cover && String(row.cover).trim())
|
||||
},
|
||||
handleImageError(row) {
|
||||
this.$set(this.imageLoadErrors, row.id, true)
|
||||
},
|
||||
isRegistrationClosed(row) {
|
||||
return !!(row && row.activitySignUpEndTime && !this.$moment().isBefore(this.$moment(row.activitySignUpEndTime)))
|
||||
},
|
||||
canApply(row) {
|
||||
if(!row || !row.activitySignUpStartTime || !row.activitySignUpEndTime) {
|
||||
return false
|
||||
}
|
||||
const now = Date.now()
|
||||
return now >= this.$moment(row.activitySignUpStartTime).valueOf()
|
||||
&& now <= this.$moment(row.activitySignUpEndTime).valueOf()
|
||||
},
|
||||
registrationStatusText(row) {
|
||||
if(!row || !row.activitySignUpStartTime || !row.activitySignUpEndTime) {
|
||||
return '当前不可报名'
|
||||
}
|
||||
if(Date.now() < this.$moment(row.activitySignUpStartTime).valueOf()) {
|
||||
return '报名未开始'
|
||||
}
|
||||
return '已过报名时间'
|
||||
},
|
||||
onView(row) {
|
||||
this.infoRow = row
|
||||
this.time = this.$moment().diff(this.$moment(row.activitySignUpStartTime), 'milliseconds')
|
||||
this.infoVisible = true
|
||||
},
|
||||
onApply(row) {
|
||||
if(this.isRegistrationClosed(row)) {
|
||||
return
|
||||
}
|
||||
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,169 @@
|
||||
const times = {
|
||||
template:
|
||||
/*language=HTML*/
|
||||
`
|
||||
<div>
|
||||
<van-action-sheet class="family-course-times-sheet" :style="{height: '78%'}" :close-on-click-overlay="true" v-model="visible" title="时间段" cancel-text="取消">
|
||||
<div class="family-course-times-list">
|
||||
<button v-for="(item,index) in row?.courseTimes" :key="index" type="button" class="van-action-sheet__item family-course-time-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>
|
||||
</div>
|
||||
</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*/ `
|
||||
.family-course-times-sheet {
|
||||
overflow: hidden;
|
||||
border-radius: 16px 16px 0 0;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.family-course-times-sheet /deep/ .van-action-sheet__header {
|
||||
height: 48px;
|
||||
color: #1f2f43;
|
||||
background-color: #fff;
|
||||
font-size: 16px;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
.family-course-times-sheet /deep/ .van-action-sheet__close {
|
||||
top: 13px;
|
||||
color: #b5bdc9;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.family-course-times-list {
|
||||
height: calc(100% - 98px);
|
||||
padding: 10px 12px 0;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.family-course-times-sheet /deep/ .family-course-time-item {
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
padding: 14px;
|
||||
border-radius: 10px;
|
||||
color: #263548;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 6px 18px rgba(55, 85, 126, .07);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.family-course-times-sheet /deep/ .van-action-sheet__name {
|
||||
color: #263548;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.family-course-times-sheet /deep/ .van-action-sheet__subname {
|
||||
margin-top: 5px;
|
||||
color: #98a2b2;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.family-course-times-sheet /deep/ .sign_button .van-button {
|
||||
min-width: 48px;
|
||||
height: 28px;
|
||||
padding: 0 12px;
|
||||
border: 0;
|
||||
border-radius: 14px;
|
||||
color: #fff;
|
||||
background-color: #1989fa;
|
||||
font-size: 12px;
|
||||
line-height: 28px;
|
||||
box-shadow: 0 4px 10px rgba(25, 137, 250, .18);
|
||||
}
|
||||
|
||||
.family-course-times-sheet /deep/ .sign_button .van-button--disabled {
|
||||
color: #8b98aa;
|
||||
background-color: #eef2f7;
|
||||
opacity: 1;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.family-course-times-sheet /deep/ .van-action-sheet__cancel {
|
||||
height: 50px;
|
||||
color: #66758a;
|
||||
background-color: #fff;
|
||||
font-size: 14px;
|
||||
}
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,448 @@
|
||||
const applyForm = {
|
||||
template:
|
||||
/*language=HTML*/
|
||||
`
|
||||
<div>
|
||||
<van-action-sheet class="family-course-form-sheet" :style="{height: '78%'}" :close-on-click-overlay="true" 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 class="family-member-section-title">
|
||||
<div>{{activity.keyWord}}信息</div>
|
||||
<div class="family-member-actions">
|
||||
<button type="button" class="family-member-action family-member-action--delete" :aria-label="'删除' + activity.keyWord" @click="delFamily">
|
||||
<van-icon name="delete-o"></van-icon>
|
||||
</button>
|
||||
<button type="button" class="family-member-action family-member-action--add" :aria-label="'添加' + activity.keyWord" @click="addFamily">
|
||||
<van-icon name="plus"></van-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="formData.mobileColumnsValue && formData.mobileColumnsValue.length > 0" class="mt10">
|
||||
<van-tabs v-model="familyActive" color="#1989fa" title-active-color="#1989fa" 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*/ `
|
||||
.family-course-form-sheet {
|
||||
overflow: hidden;
|
||||
border-radius: 16px 16px 0 0;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.family-course-form-sheet /deep/ .van-action-sheet__header {
|
||||
height: 48px;
|
||||
color: #1f2f43;
|
||||
background-color: #fff;
|
||||
font-size: 16px;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
.family-course-form-sheet /deep/ .van-action-sheet__close {
|
||||
top: 13px;
|
||||
color: #b5bdc9;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.family-course-form-sheet /deep/ .form-container {
|
||||
height: calc(100% - 48px);
|
||||
padding: 10px 12px 72px;
|
||||
overflow-y: auto;
|
||||
background-color: #f3f7fd;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.family-course-form-sheet /deep/ .form-section {
|
||||
margin-bottom: 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 6px 18px rgba(55, 85, 126, .07);
|
||||
}
|
||||
|
||||
.family-course-form-sheet /deep/ .van-cell-group__title {
|
||||
padding: 12px 14px 8px;
|
||||
color: #263548;
|
||||
background-color: #fff;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.family-course-form-sheet /deep/ .van-cell-group__title::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.family-course-form-sheet /deep/ .van-cell {
|
||||
padding: 11px 14px;
|
||||
color: #263548;
|
||||
background-color: #fff;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.family-course-form-sheet /deep/ .van-field__label {
|
||||
color: #66758a;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.family-course-form-sheet /deep/ .van-field__control {
|
||||
color: #263548;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.family-course-form-sheet /deep/ .van-tabs__nav--card {
|
||||
overflow: hidden;
|
||||
border: 0;
|
||||
border-radius: 16px;
|
||||
background-color: #eef3f9;
|
||||
}
|
||||
|
||||
.family-course-form-sheet /deep/ .van-tabs__nav--card .van-tab {
|
||||
border-right: 0;
|
||||
color: #66758a;
|
||||
}
|
||||
|
||||
.family-course-form-sheet /deep/ .van-tabs__nav--card .van-tab--active {
|
||||
color: #1989fa;
|
||||
background-color: #e7f2ff;
|
||||
}
|
||||
|
||||
/deep/ .companionList_empty_text {
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
font-size: 14px;
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.family-course-form-sheet /deep/ .button {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
width: auto;
|
||||
padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
|
||||
border-top: 1px solid #edf1f6;
|
||||
background-color: rgba(255, 255, 255, .96);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.family-course-form-sheet /deep/ .button .van-button {
|
||||
height: 42px;
|
||||
border: 0;
|
||||
border-radius: 21px;
|
||||
color: #fff;
|
||||
background-color: #1989fa;
|
||||
font-size: 15px;
|
||||
box-shadow: 0 6px 16px rgba(25, 137, 250, .22);
|
||||
}
|
||||
`
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,550 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
body {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.family-mine-page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: calc(24px + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.family-mine-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.family-mine-page .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.family-mine-page .van-nav-bar .van-icon,
|
||||
.family-mine-page .van-nav-bar__text {
|
||||
color: #397fbd;
|
||||
}
|
||||
|
||||
.family-mine-content {
|
||||
padding: 12px 12px 0;
|
||||
}
|
||||
|
||||
.family-mine-hero {
|
||||
position: relative;
|
||||
height: 134px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
color: #fff;
|
||||
background: linear-gradient(115deg, #347eea 0%, #5b9cf4 58%, #cfe3ff 100%);
|
||||
box-shadow: 0 8px 20px rgba(51, 117, 219, .18);
|
||||
}
|
||||
|
||||
.family-mine-hero__image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 67%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: right center;
|
||||
-webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 26%);
|
||||
mask-image: linear-gradient(90deg, transparent 0%, #000 26%);
|
||||
}
|
||||
|
||||
.family-mine-hero__copy {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
padding-left: 16px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.family-mine-hero__title {
|
||||
font-size: 25px;
|
||||
line-height: 34px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.family-mine-hero__subtitle {
|
||||
margin-top: 4px;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
letter-spacing: .5px;
|
||||
opacity: .95;
|
||||
}
|
||||
|
||||
.family-mine-sticky {
|
||||
padding: 10px 0 1px;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.van-sticky--fixed .family-mine-sticky {
|
||||
padding-right: 12px;
|
||||
padding-left: 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.family-mine-search {
|
||||
margin-bottom: 8px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .1);
|
||||
}
|
||||
|
||||
.family-mine-search .van-search__content {
|
||||
height: 42px;
|
||||
padding-left: 12px;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.family-mine-search .van-field__control {
|
||||
color: #263548;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.family-mine-filter {
|
||||
margin-bottom: 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .08);
|
||||
transition: border-radius .18s ease;
|
||||
}
|
||||
|
||||
.family-mine-filter.is-open {
|
||||
border-radius: 10px 10px 0 0;
|
||||
}
|
||||
|
||||
.family-mine-filter .van-dropdown-menu__bar {
|
||||
height: 44px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.family-mine-filter .van-dropdown-menu__title {
|
||||
width: auto;
|
||||
max-width: calc(100% - 24px);
|
||||
padding: 0 12px 0 0;
|
||||
color: #66758a;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.family-mine-filter .van-dropdown-menu__title::after {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.family-mine-filter .van-dropdown-item__content {
|
||||
width: calc(100% - 24px);
|
||||
margin: 0 12px;
|
||||
overflow: hidden;
|
||||
border-radius: 0 0 12px 12px;
|
||||
box-shadow: 0 10px 24px rgba(31, 65, 108, .14);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.family-mine-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.family-mine-card {
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
}
|
||||
|
||||
.family-mine-card__cover,
|
||||
.family-mine-card__cover-state {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #edf4fc;
|
||||
}
|
||||
|
||||
.family-mine-card__cover {
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.family-mine-card__cover-state {
|
||||
flex-direction: column;
|
||||
row-gap: 8px;
|
||||
color: #8da1ba;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.family-mine-card__cover-state .van-icon {
|
||||
font-size: 34px;
|
||||
}
|
||||
|
||||
.family-mine-card__cover-state.is-error {
|
||||
color: #c27b75;
|
||||
background-color: #fff3f1;
|
||||
}
|
||||
|
||||
.family-mine-card__body {
|
||||
padding: 12px 14px 14px;
|
||||
}
|
||||
|
||||
.family-mine-card__title {
|
||||
overflow: hidden;
|
||||
color: #303846;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.family-mine-card__time {
|
||||
margin-top: 4px;
|
||||
overflow: hidden;
|
||||
color: #98a2b2;
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.family-mine-card__meta {
|
||||
display: flex;
|
||||
margin-top: 10px;
|
||||
padding-top: 9px;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
border-top: 1px solid #edf1f6;
|
||||
}
|
||||
|
||||
.family-mine-card__tag {
|
||||
display: inline-flex;
|
||||
padding: 3px 8px;
|
||||
border-radius: 4px;
|
||||
color: #397de0;
|
||||
background-color: #edf5ff;
|
||||
font-size: 11px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.family-mine-card__tag-label {
|
||||
margin-right: 4px;
|
||||
color: #8aa7cf;
|
||||
}
|
||||
|
||||
.family-mine-card__actions {
|
||||
display: flex;
|
||||
padding: 12px 14px;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
border-top: 1px solid #edf1f6;
|
||||
background-color: #f8fbff;
|
||||
}
|
||||
|
||||
.family-mine-card__action {
|
||||
display: inline-flex;
|
||||
min-width: 82px;
|
||||
height: 32px;
|
||||
padding: 0 14px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 0;
|
||||
border-radius: 16px;
|
||||
color: #397de0;
|
||||
background-color: #edf5ff;
|
||||
font-size: 13px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.family-mine-card__action .van-icon {
|
||||
margin-right: 6px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.family-mine-card__action.is-primary {
|
||||
color: #fff;
|
||||
background-color: #1989fa;
|
||||
box-shadow: 0 5px 12px rgba(25, 137, 250, .18);
|
||||
}
|
||||
|
||||
.family-mine-empty {
|
||||
display: flex;
|
||||
min-height: 260px;
|
||||
padding: 26px 18px 32px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.family-mine-empty img {
|
||||
width: 82%;
|
||||
max-width: 280px;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.family-mine-empty__title {
|
||||
margin-top: 14px;
|
||||
color: #50627a;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.family-mine-empty__hint {
|
||||
margin-top: 5px;
|
||||
color: #9aa7b8;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.family-mine-intro-page {
|
||||
min-height: 100vh;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.family-mine-intro-scroll {
|
||||
height: calc(100vh - 46px);
|
||||
padding: 12px;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.family-mine-intro-hero {
|
||||
display: flex;
|
||||
min-height: 82px;
|
||||
padding: 16px;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
color: #fff;
|
||||
background: linear-gradient(120deg, #2d7eea 0%, #5ba6f7 100%);
|
||||
box-shadow: 0 8px 20px rgba(45, 126, 234, .18);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.family-mine-intro-hero__icon {
|
||||
display: flex;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
margin-right: 12px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 0 0 44px;
|
||||
border-radius: 11px;
|
||||
color: #2d7eea;
|
||||
background-color: rgba(255, 255, 255, .92);
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.family-mine-intro-hero__title {
|
||||
font-size: 17px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.family-mine-intro-hero__subtitle {
|
||||
margin-top: 3px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
.family-mine-intro-card {
|
||||
margin-top: 12px;
|
||||
padding: 18px 16px;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
color: #3f4c5e;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.family-mine-intro-card img {
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<div class="family-mine-page">
|
||||
<van-nav-bar title="亲子活动-我的报名" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||
|
||||
<div class="family-mine-content">
|
||||
<section class="family-mine-hero">
|
||||
<img class="family-mine-hero__image" src="/assets/mobile/img/activity/hero/family-hero-v3.png" alt="亲子活动插画">
|
||||
<div class="family-mine-hero__copy">
|
||||
<div class="family-mine-hero__title">我的报名</div>
|
||||
<div class="family-mine-hero__subtitle">亲子活动 · 报名记录</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<van-sticky :offset-top="46">
|
||||
<div class="family-mine-sticky">
|
||||
<van-search v-model="pageForm.searchKeyword" class="family-mine-search" placeholder="搜索已报名活动" shape="round" clearable @search="doSearch" @clear="doSearch"></van-search>
|
||||
<van-dropdown-menu class="family-mine-filter" :class="{'is-open': filterOpened}" active-color="#1989fa">
|
||||
<year-van-dropdown-item :num="5" @change="doSearch" @open="filterOpened = true" @close="filterOpened = false" v-model="pageForm.year"></year-van-dropdown-item>
|
||||
<van-dropdown-item v-model="pageForm.activityType" :options="typeOptions" :multiple="false" @change="doSearch" @open="filterOpened = true" @close="filterOpened = false"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</div>
|
||||
</van-sticky>
|
||||
|
||||
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
|
||||
<van-list v-model="loading" :finished="finished" :immediate-check="false" @load="onLoad">
|
||||
<div class="family-mine-list">
|
||||
<div v-for="row in tableData" :key="row.id" class="family-mine-card">
|
||||
<img v-if="hasCover(row) && !imageLoadErrors[row.id]" class="family-mine-card__cover" :src="row.cover" :alt="row.activityName" @error="handleImageError(row)">
|
||||
<div v-else class="family-mine-card__cover-state" :class="{'is-error': hasCover(row)}">
|
||||
<van-icon name="photo-o"></van-icon>
|
||||
<span>{{ hasCover(row) ? '图片加载失败' : '暂无图片' }}</span>
|
||||
</div>
|
||||
<div class="family-mine-card__body">
|
||||
<div class="family-mine-card__title">{{ row.activityName }}</div>
|
||||
<div class="family-mine-card__time" v-if="row.activitySignUpStartTime && row.activitySignUpEndTime">
|
||||
报名时间:{{ $moment(row.activitySignUpStartTime).format('MM/DD HH:mm') }}~{{ $moment(row.activitySignUpEndTime).format('MM/DD HH:mm') }}
|
||||
</div>
|
||||
<div class="family-mine-card__time" v-if="row.activityStartTime && row.activityEndTime">
|
||||
活动时间:{{ $moment(row.activityStartTime).format('MM/DD HH:mm') }}~{{ $moment(row.activityEndTime).format('MM/DD HH:mm') }}
|
||||
</div>
|
||||
<div class="family-mine-card__meta" v-if="row.activityGroupName || row.trainType">
|
||||
<span class="family-mine-card__tag" v-if="row.activityGroupName"><span class="family-mine-card__tag-label">面向对象</span>{{ row.activityGroupName }}</span>
|
||||
<span class="family-mine-card__tag" v-if="row.trainType"><span class="family-mine-card__tag-label">活动类型</span>{{ row.trainType }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="family-mine-card__actions">
|
||||
<button type="button" class="family-mine-card__action" @click="onView(row)"><van-icon name="eye-o"></van-icon>查看介绍</button>
|
||||
<button type="button" class="family-mine-card__action is-primary" @click="onApply(row)"><van-icon name="edit"></van-icon>查看报名</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-list>
|
||||
<div v-if="!loading && tableData.length === 0" class="family-mine-empty">
|
||||
<img src="/assets/mobile/img/activity/family-empty.png" alt="亲子活动报名空状态插画">
|
||||
<div class="family-mine-empty__title">暂无报名记录</div>
|
||||
<div class="family-mine-empty__hint">当前筛选条件下暂时没有已报名活动</div>
|
||||
</div>
|
||||
</van-pull-refresh>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<van-popup :style="{height: '100%', width: '100%'}" position="right" v-model="infoVisible">
|
||||
<div class="family-mine-intro-page">
|
||||
<van-nav-bar title="活动介绍" left-text="返回" left-arrow @click-left="infoVisible = false"></van-nav-bar>
|
||||
<div class="family-mine-intro-scroll">
|
||||
<div class="family-mine-intro-hero">
|
||||
<div class="family-mine-intro-hero__icon"><van-icon name="description"></van-icon></div>
|
||||
<div>
|
||||
<div class="family-mine-intro-hero__title">亲子活动报名须知</div>
|
||||
<div class="family-mine-intro-hero__subtitle">请仔细阅读活动安排与报名要求</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="infoRow.introduce" class="family-mine-intro-card" v-html="infoRow.introduce"></div>
|
||||
<div v-else class="family-mine-intro-card">暂无活动介绍</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
loading: false,
|
||||
finished: false,
|
||||
refreshing: false,
|
||||
imageLoadErrors: {},
|
||||
filterOpened: false,
|
||||
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: {
|
||||
hasCover(row) {
|
||||
return !!(row && row.cover && String(row.cover).trim())
|
||||
},
|
||||
handleImageError(row) {
|
||||
this.$set(this.imageLoadErrors, row.id, true)
|
||||
},
|
||||
onView(row) {
|
||||
this.infoRow = row
|
||||
this.infoVisible = true
|
||||
},
|
||||
onApply(row) {
|
||||
this.$pjaxReplace('/platform/family/apply/list/h5?id=' + row.id + '&dataType=mine')
|
||||
},
|
||||
onLoad() {
|
||||
if(!this.finished) {
|
||||
this.loadActivities(false)
|
||||
}
|
||||
},
|
||||
onRefresh() {
|
||||
this.loadActivities(true)
|
||||
},
|
||||
loadActivities(reset) {
|
||||
if(reset) {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.tableData = []
|
||||
this.finished = false
|
||||
this.imageLoadErrors = {}
|
||||
}
|
||||
this.loading = true
|
||||
this.$axios.post('/platform/family/apply/activityPageData', this.pageForm).then((res) => {
|
||||
if(res.code === 0) {
|
||||
const list = res.data && res.data.list ? res.data.list : []
|
||||
this.tableData = this.pageForm.pageNumber === 1 ? list : this.tableData.concat(list)
|
||||
this.pageForm.totalCount = res.data && res.data.totalCount ? res.data.totalCount : 0
|
||||
this.finished = this.tableData.length >= this.pageForm.totalCount
|
||||
if(!this.finished) {
|
||||
this.pageForm.pageNumber++
|
||||
}
|
||||
}
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
this.refreshing = false
|
||||
})
|
||||
},
|
||||
doSearch() {
|
||||
this.loadActivities(true)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadActivities(true)
|
||||
}
|
||||
})
|
||||
</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,795 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style>
|
||||
body {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.sports-activity-page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: calc(24px + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.sports-activity-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.sports-activity-page .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.sports-activity-page .van-nav-bar .van-icon,
|
||||
.sports-activity-page .van-nav-bar__text {
|
||||
color: #397fbd;
|
||||
}
|
||||
|
||||
.sports-activity-content {
|
||||
padding: 12px 12px 0;
|
||||
}
|
||||
|
||||
.sports-activity-hero {
|
||||
position: relative;
|
||||
height: 134px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
color: #fff;
|
||||
background-color: #247fe8;
|
||||
box-shadow: 0 8px 20px rgba(51, 117, 219, .18);
|
||||
}
|
||||
|
||||
.sports-activity-hero__image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
|
||||
.sports-activity-hero__copy {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
width: 64%;
|
||||
height: 100%;
|
||||
padding-left: 16px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
background: linear-gradient(90deg, rgba(22, 112, 232, .98) 0%, rgba(22, 112, 232, .88) 52%, rgba(22, 112, 232, 0) 100%);
|
||||
}
|
||||
|
||||
.sports-activity-hero__title {
|
||||
font-size: 25px;
|
||||
line-height: 34px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1px;
|
||||
text-shadow: 0 2px 6px rgba(17, 86, 182, .18);
|
||||
}
|
||||
|
||||
.sports-activity-hero__subtitle {
|
||||
margin-top: 4px;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
letter-spacing: .5px;
|
||||
opacity: .95;
|
||||
}
|
||||
|
||||
.sports-activity-sticky {
|
||||
padding: 10px 0 1px;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.van-sticky--fixed .sports-activity-sticky {
|
||||
padding-right: 12px;
|
||||
padding-left: 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.sports-activity-search {
|
||||
margin: 0 0 8px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .1);
|
||||
}
|
||||
|
||||
.sports-activity-search .van-search__content {
|
||||
height: 42px;
|
||||
padding-left: 12px;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.sports-activity-search .van-field__control {
|
||||
color: #263548;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.sports-activity-search .van-field__control::placeholder {
|
||||
color: #a7b0bf;
|
||||
}
|
||||
|
||||
.sports-activity-filter {
|
||||
margin: 0 0 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .08);
|
||||
transition: border-radius .18s ease;
|
||||
}
|
||||
|
||||
.sports-activity-filter.is-open {
|
||||
border-radius: 10px 10px 0 0;
|
||||
}
|
||||
|
||||
.sports-activity-filter .van-dropdown-menu__bar {
|
||||
height: 44px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.sports-activity-filter .van-dropdown-menu__title {
|
||||
color: #66758a;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.sports-activity-filter .van-dropdown-menu__title--active,
|
||||
.sports-activity-filter .van-dropdown-item__option--active,
|
||||
.sports-activity-filter .van-dropdown-item__option--active .van-dropdown-item__icon {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.sports-activity-filter .van-dropdown-menu__title--down::after {
|
||||
border-color: transparent transparent #1989fa #1989fa;
|
||||
}
|
||||
|
||||
.sports-activity-filter .van-dropdown-item__content {
|
||||
width: calc(100% - 24px);
|
||||
margin: 0 12px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0 0 12px 12px;
|
||||
box-shadow: 0 10px 24px rgba(31, 65, 108, .14);
|
||||
}
|
||||
|
||||
.sports-activity-filter .van-dropdown-item__option {
|
||||
min-height: 48px;
|
||||
padding: 0 16px;
|
||||
color: #46566c;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.sports-activity-filter .van-cell::after {
|
||||
right: 16px;
|
||||
left: 16px;
|
||||
}
|
||||
|
||||
.sports-activity-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.sports-activity-card {
|
||||
display: flex;
|
||||
min-height: 74px;
|
||||
padding: 14px;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
}
|
||||
|
||||
.sports-activity-card {
|
||||
position: relative;
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
align-items: stretch;
|
||||
flex-direction: column;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sports-activity-card__icon {
|
||||
display: flex;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
margin-right: 12px;
|
||||
flex: 0 0 38px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 9px;
|
||||
color: #4d91ef;
|
||||
background-color: #edf4ff;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.sports-activity-card__body {
|
||||
min-width: 0;
|
||||
padding: 12px 38px 14px 14px;
|
||||
box-sizing: border-box;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.sports-activity-card__cover {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
margin: 0;
|
||||
flex: 0 0 150px;
|
||||
object-fit: cover;
|
||||
border-radius: 0;
|
||||
background-color: #edf4ff;
|
||||
}
|
||||
|
||||
.sports-activity-card__cover-state {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
flex: 0 0 150px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
row-gap: 8px;
|
||||
color: #8da1ba;
|
||||
background-color: #edf4fc;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.sports-activity-card__cover-state .van-icon {
|
||||
font-size: 34px;
|
||||
}
|
||||
|
||||
.sports-activity-card__cover-state.is-error {
|
||||
color: #c27b75;
|
||||
background-color: #fff3f1;
|
||||
}
|
||||
|
||||
.sports-activity-card > .sports-activity-card__icon {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
margin: 0;
|
||||
flex: 0 0 150px;
|
||||
border-radius: 0;
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
.sports-activity-card__title {
|
||||
color: #303846;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
.sports-activity-card__title {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sports-activity-card__time {
|
||||
margin-top: 4px;
|
||||
color: #98a2b2;
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sports-activity-card__meta {
|
||||
margin-top: 10px;
|
||||
padding-top: 9px;
|
||||
border-top: 1px solid #edf1f6;
|
||||
}
|
||||
|
||||
.sports-activity-card__address {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
color: #69788d;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.sports-activity-card__address .van-icon {
|
||||
margin: 2px 5px 0 0;
|
||||
flex: none;
|
||||
color: #6c9ff8;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.sports-activity-card__address span {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sports-activity-card__tags {
|
||||
display: flex;
|
||||
margin-top: 8px;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.sports-activity-card__tag {
|
||||
display: inline-flex;
|
||||
padding: 3px 8px;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
color: #397de0;
|
||||
background-color: #edf5ff;
|
||||
font-size: 11px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.sports-activity-card__tag-label {
|
||||
margin-right: 4px;
|
||||
color: #8aa7cf;
|
||||
}
|
||||
|
||||
.sports-activity-card__arrow {
|
||||
position: absolute;
|
||||
top: 164px;
|
||||
right: 14px;
|
||||
color: #b4bdca;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.sports-activity-empty-illustration {
|
||||
display: flex;
|
||||
min-height: 250px;
|
||||
padding: 24px 18px 32px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sports-activity-empty-illustration img {
|
||||
display: block;
|
||||
width: 82%;
|
||||
max-width: 280px;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.sports-activity-empty-illustration__title {
|
||||
margin-top: -8px;
|
||||
color: #50627a;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.sports-activity-empty-illustration__hint {
|
||||
margin-top: 6px;
|
||||
color: #9aa7b8;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.activity-notification-popup,
|
||||
.activity-notification-page {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.activity-notification-page {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.activity-notification-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.activity-notification-page .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.activity-notification-page .van-nav-bar .van-icon,
|
||||
.activity-notification-page .van-nav-bar__text {
|
||||
color: #397fbd;
|
||||
}
|
||||
|
||||
.activity-notification-scroll {
|
||||
height: calc(100vh - 46px);
|
||||
padding: 12px 12px calc(92px + env(safe-area-inset-bottom));
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.activity-notification-hero {
|
||||
display: flex;
|
||||
min-height: 82px;
|
||||
padding: 16px;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
border-radius: 12px;
|
||||
color: #fff;
|
||||
background: linear-gradient(120deg, #2d7eea 0%, #5ba6f7 100%);
|
||||
box-shadow: 0 8px 20px rgba(45, 126, 234, .18);
|
||||
}
|
||||
|
||||
.activity-notification-hero__icon {
|
||||
display: flex;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
margin-right: 12px;
|
||||
flex: 0 0 44px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 11px;
|
||||
color: #2d7eea;
|
||||
background-color: rgba(255, 255, 255, .92);
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.activity-notification-hero__title {
|
||||
font-size: 17px;
|
||||
line-height: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.activity-notification-hero__subtitle {
|
||||
margin-top: 3px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
.activity-notification-card {
|
||||
margin-top: 12px;
|
||||
padding: 18px 16px;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
}
|
||||
|
||||
.activity-notification-content,
|
||||
.activity-notification-content div,
|
||||
.activity-notification-content p,
|
||||
.activity-notification-content span,
|
||||
.activity-notification-content li {
|
||||
color: #3f4c5e !important;
|
||||
font-size: 14px !important;
|
||||
line-height: 1.8 !important;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.activity-notification-content h1,
|
||||
.activity-notification-content h2,
|
||||
.activity-notification-content h3 {
|
||||
margin: 16px 0 10px !important;
|
||||
color: #1f2f43 !important;
|
||||
font-size: 19px !important;
|
||||
line-height: 1.5 !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
.activity-notification-content > :first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.activity-notification-content p {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 8px !important;
|
||||
}
|
||||
|
||||
.activity-notification-content img {
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.activity-notification-content table {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.activity-notification-empty {
|
||||
display: flex;
|
||||
min-height: 180px;
|
||||
margin-top: 12px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
row-gap: 10px;
|
||||
border-radius: 12px;
|
||||
color: #9aa7b8;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.activity-notification-empty .van-icon {
|
||||
color: #83b5f4;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.activity-notification-footer {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 5;
|
||||
padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
|
||||
border-top: 1px solid #edf1f6;
|
||||
background-color: rgba(255, 255, 255, .96);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.activity-notification-footer .van-button {
|
||||
height: 42px;
|
||||
border: 0;
|
||||
font-size: 15px;
|
||||
background-color: #1989fa;
|
||||
box-shadow: 0 6px 16px rgba(25, 137, 250, .22);
|
||||
}
|
||||
|
||||
.activity-notification-footer .van-button.is-disabled,
|
||||
.activity-notification-footer .van-button--disabled {
|
||||
color: #8b98aa !important;
|
||||
background-color: #eef2f7 !important;
|
||||
opacity: 1;
|
||||
box-shadow: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<div class="sports-activity-page">
|
||||
<van-nav-bar
|
||||
title="体育活动"
|
||||
left-arrow
|
||||
left-text="返回"
|
||||
fixed
|
||||
placeholder
|
||||
@click-left="goBack"
|
||||
></van-nav-bar>
|
||||
|
||||
<div class="sports-activity-content">
|
||||
<section class="sports-activity-hero">
|
||||
<img
|
||||
class="sports-activity-hero__image"
|
||||
src="/assets/mobile/img/activity/hero/sports-hero-v2.png"
|
||||
alt="体育活动插画"
|
||||
>
|
||||
<div class="sports-activity-hero__copy">
|
||||
<div class="sports-activity-hero__title">体育活动</div>
|
||||
<div class="sports-activity-hero__subtitle">强健体魄 · 运动同行</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<van-sticky :offset-top="46">
|
||||
<div class="sports-activity-sticky">
|
||||
<van-search
|
||||
v-model="searchKeyword"
|
||||
class="sports-activity-search"
|
||||
placeholder="搜索体育活动"
|
||||
shape="round"
|
||||
clearable
|
||||
@search="doSearch"
|
||||
@clear="doSearch"
|
||||
></van-search>
|
||||
|
||||
<van-dropdown-menu
|
||||
class="sports-activity-filter"
|
||||
:class="{'is-open': filterOpened}"
|
||||
active-color="#1989fa"
|
||||
>
|
||||
<year-van-dropdown-item
|
||||
:num="5"
|
||||
v-model="pageForm.year"
|
||||
@change="doSearch"
|
||||
@open="filterOpened = true"
|
||||
@close="filterOpened = false"
|
||||
></year-van-dropdown-item>
|
||||
<van-dropdown-item
|
||||
v-model="pageForm.isActivity"
|
||||
:options="stateList"
|
||||
@change="doSearch"
|
||||
@open="filterOpened = true"
|
||||
@close="filterOpened = false"
|
||||
></van-dropdown-item>
|
||||
<van-dropdown-item
|
||||
v-model="pageForm.applyStatus"
|
||||
:options="applyStatusOptions"
|
||||
@change="doSearch"
|
||||
@open="filterOpened = true"
|
||||
@close="filterOpened = false"
|
||||
></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</div>
|
||||
</van-sticky>
|
||||
|
||||
<div class="sports-activity-list">
|
||||
<div
|
||||
v-for="row in activityList"
|
||||
:key="row.id"
|
||||
class="sports-activity-card"
|
||||
@click="openView(row)"
|
||||
>
|
||||
<img
|
||||
v-if="hasActivityImage(row) && !imageLoadErrors[row.id]"
|
||||
class="sports-activity-card__cover"
|
||||
:src="row.image"
|
||||
:alt="row.NAME || row.name"
|
||||
@error="handleImageError(row)"
|
||||
>
|
||||
<div
|
||||
v-else
|
||||
class="sports-activity-card__cover-state"
|
||||
:class="{'is-error': hasActivityImage(row)}"
|
||||
>
|
||||
<van-icon name="photo-o"></van-icon>
|
||||
<span>{{ hasActivityImage(row) ? '图片加载失败' : '暂无图片' }}</span>
|
||||
</div>
|
||||
<div class="sports-activity-card__body">
|
||||
<div class="sports-activity-card__title">{{ row.NAME || row.name }}</div>
|
||||
<div class="sports-activity-card__time" v-if="row.applyStartTime && row.applyEndTime">
|
||||
报名时间:{{ $moment(row.applyStartTime).format('MM/DD HH:mm') }}~{{ $moment(row.applyEndTime).format('MM/DD HH:mm') }}
|
||||
</div>
|
||||
<div class="sports-activity-card__time" v-if="row.startTime && row.endTime">
|
||||
活动时间:{{ $moment(row.startTime).format('MM/DD HH:mm') }}~{{ $moment(row.endTime).format('MM/DD HH:mm') }}
|
||||
</div>
|
||||
<div class="sports-activity-card__meta" v-if="row.address || formatGameStyle(row.gameStyle) || formatApplyType(row.applyType) || formatApplyWay(row.applyWay)">
|
||||
<div class="sports-activity-card__address" v-if="row.address">
|
||||
<van-icon name="location-o"></van-icon>
|
||||
<span>{{ row.address }}</span>
|
||||
</div>
|
||||
<div class="sports-activity-card__tags" v-if="formatGameStyle(row.gameStyle) || formatApplyType(row.applyType) || formatApplyWay(row.applyWay)">
|
||||
<span class="sports-activity-card__tag" v-if="formatGameStyle(row.gameStyle)">
|
||||
<span class="sports-activity-card__tag-label">竞赛方式</span>{{ formatGameStyle(row.gameStyle) }}
|
||||
</span>
|
||||
<span class="sports-activity-card__tag" v-if="formatApplyType(row.applyType)">
|
||||
<span class="sports-activity-card__tag-label">活动类型</span>{{ formatApplyType(row.applyType) }}
|
||||
</span>
|
||||
<span class="sports-activity-card__tag" v-if="formatApplyWay(row.applyWay)">
|
||||
<span class="sports-activity-card__tag-label">报名方式</span>{{ formatApplyWay(row.applyWay) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<van-icon class="sports-activity-card__arrow" name="arrow"></van-icon>
|
||||
</div>
|
||||
|
||||
<div v-if="activityList.length === 0" class="sports-activity-empty-illustration">
|
||||
<img src="/assets/mobile/img/activity/sports-empty.png" alt="体育活动空状态插画">
|
||||
<div class="sports-activity-empty-illustration__title">{{ emptyText }}</div>
|
||||
<div class="sports-activity-empty-illustration__hint">{{ emptyHint }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<activity_event_notification
|
||||
:event_notification="viewData.eventNotification"
|
||||
:id="viewData.id"
|
||||
:apply_start_time="viewData.applyStartTime"
|
||||
:apply_end_time="viewData.applyEndTime"
|
||||
ref="eventNotification"
|
||||
></activity_event_notification>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("eventNotification.js"){}#-->
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
activityList: [],
|
||||
searchKeyword: "",
|
||||
imageLoadErrors: {},
|
||||
filterOpened: false,
|
||||
pageForm: {
|
||||
isActivity: 2,
|
||||
applyStatus: 1,
|
||||
year: new Date().getFullYear()
|
||||
},
|
||||
stateList: [
|
||||
{value: 1, text: "全部活动"},
|
||||
{value: 2, text: "报名中"},
|
||||
{value: 3, text: "报名已结束"}
|
||||
],
|
||||
applyStatusOptions: [
|
||||
{value: 1, text: "未报名"},
|
||||
{value: 2, text: "已报名"}
|
||||
],
|
||||
viewData: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
emptyText() {
|
||||
if (this.searchKeyword.trim()) return "未找到相关体育活动"
|
||||
if (this.pageForm.isActivity === 3) return "暂无已结束的体育活动"
|
||||
if (this.pageForm.isActivity === 2) return "暂无报名中的体育活动"
|
||||
return "暂无体育活动"
|
||||
},
|
||||
emptyHint() {
|
||||
return this.searchKeyword.trim() ? "请尝试更换搜索关键词" : "当前筛选条件下暂时没有活动"
|
||||
}
|
||||
},
|
||||
components: {
|
||||
activity_event_notification: ACTIVITY_EVENT_NOTIFICATION
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
this.$pjaxReplace("/platform/home")
|
||||
},
|
||||
openView(row) {
|
||||
this.viewData = row
|
||||
this.$nextTick(() => {
|
||||
this.$refs.eventNotification.viewShow = true
|
||||
})
|
||||
},
|
||||
doSearch() {
|
||||
this.loadActivities()
|
||||
},
|
||||
hasActivityImage(row) {
|
||||
return !!(row && row.image && String(row.image).trim())
|
||||
},
|
||||
handleImageError(row) {
|
||||
this.$set(this.imageLoadErrors, row.id, true)
|
||||
},
|
||||
formatGameStyle(value) {
|
||||
return {
|
||||
1: "竞赛类",
|
||||
2: "非竞赛类"
|
||||
}[Number(value)] || ""
|
||||
},
|
||||
formatApplyType(value) {
|
||||
return {
|
||||
1: "单一团体赛",
|
||||
2: "综合赛",
|
||||
3: "个人赛"
|
||||
}[Number(value)] || ""
|
||||
},
|
||||
formatApplyWay(value) {
|
||||
if (value === null || value === undefined || value === "") return ""
|
||||
let values = value
|
||||
if (typeof values === "string") {
|
||||
try {
|
||||
values = JSON.parse(values)
|
||||
} catch (e) {
|
||||
values = values.split(",")
|
||||
}
|
||||
}
|
||||
if (!Array.isArray(values)) values = [values]
|
||||
const labels = {
|
||||
1: "个人报名",
|
||||
2: "分工会报名",
|
||||
3: "小程序报名"
|
||||
}
|
||||
return values.map(item => labels[Number(item)]).filter(Boolean).join("、")
|
||||
},
|
||||
loadActivities() {
|
||||
this.activityList = []
|
||||
this.imageLoadErrors = {}
|
||||
const queryForm = Object.assign({}, this.pageForm, {
|
||||
searchKeyword: this.searchKeyword.trim()
|
||||
})
|
||||
this.$axios.post("/platform/activity/apply/h5/activityData", queryForm).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.activityList = res.data && res.data.list ? res.data.list : []
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadActivities()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,921 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style>
|
||||
body {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.sports-event-page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: calc(24px + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.sports-event-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.sports-event-page .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.sports-event-page .van-nav-bar .van-icon,
|
||||
.sports-event-page .van-nav-bar__text {
|
||||
color: #397fbd;
|
||||
}
|
||||
|
||||
.sports-event-summary {
|
||||
display: flex;
|
||||
min-height: 82px;
|
||||
margin: 12px 12px 0;
|
||||
padding: 16px;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
border-radius: 12px;
|
||||
color: #fff;
|
||||
background: linear-gradient(120deg, #2d7eea 0%, #5ba6f7 100%);
|
||||
box-shadow: 0 8px 20px rgba(45, 126, 234, .18);
|
||||
}
|
||||
|
||||
.sports-event-summary__icon {
|
||||
display: flex;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
margin-right: 12px;
|
||||
overflow: hidden;
|
||||
flex: 0 0 44px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 11px;
|
||||
color: #2d7eea;
|
||||
background-color: rgba(255, 255, 255, .92);
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.sports-event-summary__body {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sports-event-summary__title {
|
||||
overflow: hidden;
|
||||
color: #fff;
|
||||
font-size: 17px;
|
||||
line-height: 24px;
|
||||
font-weight: 600;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sports-event-summary__subtitle {
|
||||
margin-top: 3px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
.sports-event-sticky {
|
||||
padding: 10px 0 8px;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.sports-event-search {
|
||||
margin: 0 12px;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.sports-event-search .van-search__content {
|
||||
height: 42px;
|
||||
padding-left: 13px;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 5px 16px rgba(55, 85, 126, .07);
|
||||
}
|
||||
|
||||
.sports-event-search .van-field__control {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.sports-event-list-head {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
margin: 16px 0 0;
|
||||
padding: 0 12px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.sports-event-list-head__title {
|
||||
color: #263548;
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.sports-event-list-head__count {
|
||||
color: #8d9aad;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.sports-event-list-head__tools {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.sports-event-view-toggle {
|
||||
display: inline-flex;
|
||||
height: 28px;
|
||||
padding: 0 10px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 0;
|
||||
border-radius: 14px;
|
||||
color: #397de0;
|
||||
background-color: #eaf3ff;
|
||||
font-size: 12px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.sports-event-view-toggle i {
|
||||
margin-right: 5px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.sports-event-page .sports-event-card-list {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.sports-event-page .table-card {
|
||||
margin-bottom: 12px;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
}
|
||||
|
||||
.sports-event-page .table-card > .van-image,
|
||||
.sports-event-page .table-card > .van-image img {
|
||||
display: block;
|
||||
border-radius: 12px 12px 0 0;
|
||||
}
|
||||
|
||||
.sports-event-page .table-card .van-cell {
|
||||
padding: 9px 16px;
|
||||
color: #566579;
|
||||
font-size: 13px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.sports-event-page .table-card .van-cell:first-of-type {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.sports-event-page .table-card .van-cell::after {
|
||||
right: 16px;
|
||||
left: 16px;
|
||||
border-color: #edf1f6;
|
||||
}
|
||||
|
||||
.sports-event-page .table-card .van-cell__title {
|
||||
color: #66758a;
|
||||
}
|
||||
|
||||
.sports-event-page .table-card .van-cell__value,
|
||||
.sports-event-page .table-card .van-cell__right-icon {
|
||||
color: #263548;
|
||||
}
|
||||
|
||||
.sports-event-page .table-card .font-size3 {
|
||||
color: #23344a;
|
||||
font-size: 16px;
|
||||
line-height: 23px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.sports-event-page .table-card .van-tag {
|
||||
padding: 3px 7px;
|
||||
justify-content: center;
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.sports-event-page .table-card .sports-event-status-tag.is-pending {
|
||||
color: #397de0;
|
||||
background-color: #edf5ff;
|
||||
}
|
||||
|
||||
.sports-event-page .table-card .sports-event-status-tag.is-success {
|
||||
color: #35a86b;
|
||||
background-color: #eaf8f1;
|
||||
}
|
||||
|
||||
.sports-event-page .table-card .sports-event-status-tag.is-rejected {
|
||||
color: #df5b59;
|
||||
background-color: #fff1f0;
|
||||
}
|
||||
|
||||
.sports-event-card__body {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.sports-event-card__title-row {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.sports-event-card__title {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
color: #23344a;
|
||||
font-size: 16px;
|
||||
line-height: 23px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.sports-event-card__status {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sports-event-card__activity {
|
||||
display: flex;
|
||||
margin-top: 5px;
|
||||
align-items: center;
|
||||
color: #78879a;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.sports-event-card__activity .van-icon {
|
||||
margin-right: 5px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.sports-event-card__tags,
|
||||
.sports-event-card__config {
|
||||
display: flex;
|
||||
margin-top: 10px;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.sports-event-card__tag,
|
||||
.sports-event-card__config-tag {
|
||||
display: inline-flex;
|
||||
min-height: 24px;
|
||||
padding: 3px 8px;
|
||||
align-items: center;
|
||||
border-radius: 5px;
|
||||
color: #397de0;
|
||||
background-color: #edf5ff;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.sports-event-card__tag-label {
|
||||
margin-right: 4px;
|
||||
color: #7f9fc9;
|
||||
}
|
||||
|
||||
.sports-event-card__stats {
|
||||
display: grid;
|
||||
margin-top: 12px;
|
||||
padding: 12px 0;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
border-top: 1px solid #edf1f6;
|
||||
border-bottom: 1px solid #edf1f6;
|
||||
}
|
||||
|
||||
.sports-event-card__stat {
|
||||
min-width: 0;
|
||||
padding: 0 10px;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.sports-event-card__stat:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.sports-event-card__stat:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.sports-event-card__stat + .sports-event-card__stat {
|
||||
border-left: 1px solid #edf1f6;
|
||||
}
|
||||
|
||||
.sports-event-card__stat-label {
|
||||
color: #7b899b;
|
||||
font-size: 11px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.sports-event-card__stat-value {
|
||||
margin-top: 3px;
|
||||
overflow: hidden;
|
||||
color: #33445a;
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sports-event-card__config-tag {
|
||||
color: #66758a;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.sports-event-card__extra {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.sports-event-card__extra-row {
|
||||
display: flex;
|
||||
padding: 4px 0;
|
||||
align-items: flex-start;
|
||||
color: #66758a;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.sports-event-card__extra-row .van-icon {
|
||||
margin: 2px 6px 0 0;
|
||||
flex: 0 0 auto;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.sports-event-card__extra-label {
|
||||
margin-right: 8px;
|
||||
flex: 0 0 auto;
|
||||
color: #7b899b;
|
||||
}
|
||||
|
||||
.sports-event-card__extra-value {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
color: #33445a;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.sports-event-page .table-card .table-card-footer {
|
||||
min-height: 56px;
|
||||
margin-top: 4px;
|
||||
padding: 12px 16px;
|
||||
align-items: center;
|
||||
border-top: 1px solid #edf1f6;
|
||||
background-color: #f8fbff;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.sports-event-page .table-card .table-card-footer::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sports-event-card__footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.sports-event-card__footer > div {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.sports-event-union-action-hint {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: #ed6a0c;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.sports-event-union-action-hint.is-authorized {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.sports-event-page .table-card .table-card-footer .van-cell__value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.sports-event-page .table-card-footer .van-button {
|
||||
min-width: 78px;
|
||||
height: 32px;
|
||||
padding: 0 14px;
|
||||
border: 0;
|
||||
border-radius: 16px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.sports-event-page .table-card-footer .van-button i {
|
||||
margin-right: 6px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.sports-event-page .table-card-footer .sports-event-apply-button {
|
||||
width: 108px;
|
||||
min-width: 108px;
|
||||
height: 32px;
|
||||
color: #fff !important;
|
||||
border-color: #1989fa !important;
|
||||
background-color: #1989fa !important;
|
||||
box-shadow: 0 5px 12px rgba(25, 137, 250, .18);
|
||||
}
|
||||
|
||||
.sports-event-page .table-card-footer .sports-event-cancel-button {
|
||||
width: 108px;
|
||||
min-width: 108px;
|
||||
height: 32px;
|
||||
color: #fff !important;
|
||||
border-color: #e84d4f !important;
|
||||
background-color: #e84d4f !important;
|
||||
box-shadow: 0 5px 12px rgba(232, 77, 79, .16);
|
||||
}
|
||||
|
||||
.sports-event-page .table-card-footer .van-button__content {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sports-event-compact-list {
|
||||
margin: 0 12px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
}
|
||||
|
||||
.sports-event-compact-item {
|
||||
display: flex;
|
||||
min-height: 68px;
|
||||
padding: 12px 14px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 1px solid #edf1f6;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.sports-event-compact-item:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.sports-event-compact-item__name {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
color: #23344a;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sports-event-compact-item__action {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.sports-event-page .sports-event-compact-list .sports-event-compact-button.van-button {
|
||||
min-width: 0;
|
||||
height: 28px !important;
|
||||
padding: 0 10px !important;
|
||||
border: 0 !important;
|
||||
border-radius: 14px;
|
||||
font-size: 12px;
|
||||
line-height: 28px;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.sports-event-compact-button i {
|
||||
margin-right: 4px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.sports-event-page .sports-event-compact-list .sports-event-compact-button--apply.van-button {
|
||||
color: #397de0 !important;
|
||||
background: #edf5ff !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.sports-event-page .sports-event-compact-list .sports-event-compact-button--cancel.van-button {
|
||||
color: #df5b59 !important;
|
||||
background: #fff1f0 !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.sports-event-compact-button .van-button__content {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sports-event-page .van-list__finished-text,
|
||||
.sports-event-page .van-list__loading {
|
||||
color: #9aa7b8;
|
||||
font-size: 13px;
|
||||
line-height: 44px;
|
||||
}
|
||||
|
||||
.sports-event-refresh {
|
||||
min-height: calc(100vh - 226px);
|
||||
}
|
||||
|
||||
.sports-event-empty {
|
||||
display: flex;
|
||||
min-height: 300px;
|
||||
padding: 28px 18px;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sports-event-empty img {
|
||||
display: block;
|
||||
width: 82%;
|
||||
max-width: 300px;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.sports-event-empty__title {
|
||||
margin-top: -8px;
|
||||
color: #50627a;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.sports-event-empty__hint {
|
||||
margin-top: 6px;
|
||||
color: #9aa7b8;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<div class="sports-event-page">
|
||||
<van-sticky>
|
||||
<van-nav-bar
|
||||
@click-left="historyBack"
|
||||
left-arrow
|
||||
left-text="返回"
|
||||
placeholder
|
||||
title="项目列表"
|
||||
></van-nav-bar>
|
||||
</van-sticky>
|
||||
|
||||
<div class="sports-event-summary">
|
||||
<div class="sports-event-summary__icon">
|
||||
<van-icon name="award-o"></van-icon>
|
||||
</div>
|
||||
<div class="sports-event-summary__body">
|
||||
<div class="sports-event-summary__title">体育活动项目</div>
|
||||
<div class="sports-event-summary__subtitle">选择适合的项目,参与健康运动</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<van-sticky :offset-top="46">
|
||||
<div class="sports-event-sticky">
|
||||
<van-search
|
||||
v-model="pageForm.searchKeyword"
|
||||
class="sports-event-search"
|
||||
placeholder="搜索项目名称"
|
||||
shape="round"
|
||||
clearable
|
||||
@search="doSearch"
|
||||
@clear="doSearch"
|
||||
></van-search>
|
||||
|
||||
<div class="sports-event-list-head">
|
||||
<button type="button" class="sports-event-view-toggle" @click="toggleViewMode">
|
||||
<i :class="viewMode === 'card' ? 'fa fa-list' : 'fa fa-th-large'"></i>
|
||||
<span>{{ viewMode === 'card' ? '列表' : '卡片' }}</span>
|
||||
</button>
|
||||
<div class="sports-event-list-head__count" v-if="pageForm.totalCount">共 {{ pageForm.totalCount }} 项</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-sticky>
|
||||
|
||||
<van-pull-refresh class="sports-event-refresh" v-model="refreshing" @refresh="onRefresh">
|
||||
<div>
|
||||
<van-list :finished="finished" @load="pageData" finished-text="没有更多了" v-if="tableData.length>0"
|
||||
v-model="loading">
|
||||
<div class="sports-event-card-list" v-if="viewMode === 'card'">
|
||||
<div :key="row.id" class="table-card" v-for="row in tableData">
|
||||
<div class="sports-event-card__body">
|
||||
<div class="sports-event-card__title-row">
|
||||
<div class="sports-event-card__title">{{row.allName}}</div>
|
||||
<div class="sports-event-card__status">
|
||||
<template v-if="row.status&&row.applyWay.length===1&&row.applyWay.includes(1)">
|
||||
<van-tag class="sports-event-status-tag is-pending" v-if="row.status===1">待审核</van-tag>
|
||||
<van-tag class="sports-event-status-tag is-success" v-if="row.status===2">已成功报名</van-tag>
|
||||
<van-tag class="sports-event-status-tag is-rejected" v-if="row.status===3">审核不通过</van-tag>
|
||||
</template>
|
||||
<template v-else>
|
||||
<van-tag class="sports-event-status-tag is-pending" v-if="row.status2===0">待审核</van-tag>
|
||||
<van-tag class="sports-event-status-tag is-success" v-if="row.status2===2">已成功报名</van-tag>
|
||||
<van-tag class="sports-event-status-tag is-rejected" v-if="row.status2===3">审核不通过</van-tag>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sports-event-card__activity" v-if="row.name">
|
||||
<van-icon name="flag-o"></van-icon>
|
||||
<span>{{row.name}}</span>
|
||||
</div>
|
||||
<div class="sports-event-card__tags">
|
||||
<span class="sports-event-card__tag" v-if="row.eveProjectType"><span class="sports-event-card__tag-label">项目</span>{{row.eveProjectType == 2 ? '团体' : '单项'}}</span>
|
||||
<span class="sports-event-card__tag"><span class="sports-event-card__tag-label">性别</span>{{row.isMenWomen == 1 ? '男子' : row.isMenWomen == 2 ? '女子' : '不限'}}</span>
|
||||
<span class="sports-event-card__tag" v-if="row.isInterest">趣味项目</span>
|
||||
<span class="sports-event-card__tag" v-if="row.registrationWays"><span class="sports-event-card__tag-label">报名</span>{{row.registrationWays == 2 ? '双人' : '单人'}}</span>
|
||||
<span class="sports-event-card__tag" v-if="row.applyType"><span class="sports-event-card__tag-label">活动</span>{{row.applyType == 2 ? '综合类' : '单一类'}}</span>
|
||||
<span class="sports-event-card__tag" v-if="row.applyWay && row.applyWay.includes(1)">个人报名</span>
|
||||
<span class="sports-event-card__tag" v-if="row.applyWay && row.applyWay.includes(2)">分工会报名</span>
|
||||
<span class="sports-event-card__tag" v-if="row.applyWay && row.applyWay.includes(3)">小程序报名</span>
|
||||
</div>
|
||||
<div class="sports-event-card__stats">
|
||||
<div class="sports-event-card__stat">
|
||||
<div class="sports-event-card__stat-label">可报队数</div>
|
||||
<div class="sports-event-card__stat-value">{{row.eveProjectType == 2 && row.restrictTotalTeam != null ? row.restrictTotalTeam + '队' : '不适用'}}</div>
|
||||
</div>
|
||||
<div class="sports-event-card__stat">
|
||||
<div class="sports-event-card__stat-label">运动员人数</div>
|
||||
<div class="sports-event-card__stat-value" v-if="row.athletesMinNum != null && row.athletesMaxNum != null">{{row.athletesMinNum}}-{{row.athletesMaxNum}}人</div>
|
||||
<div class="sports-event-card__stat-value" v-else-if="row.athletesMaxNum != null">最多{{row.athletesMaxNum}}人</div>
|
||||
<div class="sports-event-card__stat-value" v-else>暂无限制</div>
|
||||
</div>
|
||||
<div class="sports-event-card__stat">
|
||||
<div class="sports-event-card__stat-label">每人限报</div>
|
||||
<div class="sports-event-card__stat-value">{{row.restrictRegNumber != null ? row.restrictRegNumber + '项' : '暂无限制'}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sports-event-card__config" v-if="row.restrictBoyNum != null || row.restrictGirlNum != null || row.coachNum != null || row.leanderNum != null || row.substituteNum != null || row.isLeader || row.isManGirlNum">
|
||||
<span class="sports-event-card__config-tag" v-if="row.restrictBoyNum != null">男子 {{row.restrictBoyNum}}人</span>
|
||||
<span class="sports-event-card__config-tag" v-if="row.restrictGirlNum != null">女子 {{row.restrictGirlNum}}人</span>
|
||||
<span class="sports-event-card__config-tag" v-if="row.coachNum != null">教练 {{row.coachNum}}人</span>
|
||||
<span class="sports-event-card__config-tag" v-if="row.leanderNum != null">领队 {{row.leanderNum}}人</span>
|
||||
<span class="sports-event-card__config-tag" v-if="row.substituteNum != null">替补 {{row.substituteNum}}人</span>
|
||||
<span class="sports-event-card__config-tag" v-if="row.isLeader">仅报领队</span>
|
||||
<span class="sports-event-card__config-tag" v-if="row.isManGirlNum">男女不限</span>
|
||||
</div>
|
||||
<div class="sports-event-card__extra">
|
||||
<div class="sports-event-card__extra-row" v-if="row.startAgeDate || row.endAgeDate"><van-icon name="calendar-o"></van-icon><span class="sports-event-card__extra-label">出生日期</span><span class="sports-event-card__extra-value">{{row.startAgeDate || '不限'}} 至 {{row.endAgeDate || '不限'}}</span></div>
|
||||
<div class="sports-event-card__extra-row" v-if="row.activityTeamName"><van-icon name="friends-o"></van-icon><span class="sports-event-card__extra-label">当前小队</span><span class="sports-event-card__extra-value">{{row.activityTeamName}}</span></div>
|
||||
<div class="sports-event-card__extra-row" v-if="row.userApplyNames"><van-icon name="contact-o"></van-icon><span class="sports-event-card__extra-label">已报名人员</span><span class="sports-event-card__extra-value" @click="openApplyUser(row)">{{row.userApplyNames}}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-card-footer sports-event-card__footer">
|
||||
<div v-if="row.applyWay.length===1&&row.applyWay.includes(1)">
|
||||
<van-button class="sports-event-apply-button" :loading="subLoading" @click="signUpUser(row)" round
|
||||
size="small"
|
||||
type="primary" v-if="activityData.applyWay.includes(1)&&row.userApply===0">
|
||||
<i class="fa fa-sign-in"></i>
|
||||
我要报名
|
||||
</van-button>
|
||||
<van-button class="sports-event-cancel-button" :loading="subLoading" @click="cancelApply(row)" round
|
||||
size="small"
|
||||
type="primary" v-if="activityData.applyWay.includes(1)&&row.userApply>0">
|
||||
<i class="fa fa-trash"></i>
|
||||
取消报名
|
||||
</van-button>
|
||||
</div>
|
||||
<div v-else>
|
||||
<van-button class="sports-event-apply-button" :loading="subLoading" @click="signUpUser(row)" round
|
||||
size="small"
|
||||
type="primary" v-if="activityData.applyWay.includes(1)&&row.userApply2===0">
|
||||
<i class="fa fa-sign-in"></i>
|
||||
我要报名
|
||||
</van-button>
|
||||
<van-button class="sports-event-cancel-button" :loading="subLoading" @click="cancelApply(row)" round
|
||||
size="small"
|
||||
type="primary" v-if="activityData.applyWay.includes(1)&&row.userApply2>0">
|
||||
<i class="fa fa-trash"></i>
|
||||
取消报名
|
||||
</van-button>
|
||||
</div>
|
||||
<span
|
||||
v-if="row.applyWay.includes(2) && !row.applyWay.includes(1)"
|
||||
class="sports-event-union-action-hint"
|
||||
:class="{'is-authorized': canUnionApplyOnPc}">
|
||||
{{ canUnionApplyOnPc ? '分工会报名请在PC端进行' : '该活动为分工会报名,暂无权限' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sports-event-compact-list" v-else>
|
||||
<div :key="row.id" class="sports-event-compact-item" v-for="row in tableData">
|
||||
<div class="sports-event-compact-item__name">{{ row.allName }}</div>
|
||||
<div class="sports-event-compact-item__action">
|
||||
<div v-if="row.applyWay.length===1&&row.applyWay.includes(1)">
|
||||
<van-button class="sports-event-compact-button sports-event-compact-button--apply" :loading="subLoading" @click="signUpUser(row)" round
|
||||
size="small" type="default"
|
||||
v-if="activityData.applyWay.includes(1)&&row.userApply===0">
|
||||
<i class="fa fa-sign-in"></i>我要报名
|
||||
</van-button>
|
||||
<van-button class="sports-event-compact-button sports-event-compact-button--cancel" :loading="subLoading" @click="cancelApply(row)" round
|
||||
size="small" type="default"
|
||||
v-if="activityData.applyWay.includes(1)&&row.userApply>0">
|
||||
<i class="fa fa-trash"></i>取消报名
|
||||
</van-button>
|
||||
</div>
|
||||
<div v-else>
|
||||
<van-button class="sports-event-compact-button sports-event-compact-button--apply" :loading="subLoading" @click="signUpUser(row)" round
|
||||
size="small" type="default"
|
||||
v-if="activityData.applyWay.includes(1)&&row.userApply2===0">
|
||||
<i class="fa fa-sign-in"></i>我要报名
|
||||
</van-button>
|
||||
<van-button class="sports-event-compact-button sports-event-compact-button--cancel" :loading="subLoading" @click="cancelApply(row)" round
|
||||
size="small" type="default"
|
||||
v-if="activityData.applyWay.includes(1)&&row.userApply2>0">
|
||||
<i class="fa fa-trash"></i>取消报名
|
||||
</van-button>
|
||||
</div>
|
||||
<span
|
||||
v-if="row.applyWay.includes(2) && !row.applyWay.includes(1)"
|
||||
class="sports-event-union-action-hint"
|
||||
:class="{'is-authorized': canUnionApplyOnPc}">
|
||||
{{ canUnionApplyOnPc ? '分工会报名请在PC端进行' : '该活动为分工会报名,暂无权限' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-list>
|
||||
<div class="sports-event-empty" v-else>
|
||||
<img src="/assets/mobile/img/activity/sports-empty.png" alt="体育活动项目空状态插画">
|
||||
<div class="sports-event-empty__title">暂无可报名项目</div>
|
||||
<div class="sports-event-empty__hint">当前活动暂未发布可报名项目</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-pull-refresh>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
finished: false,
|
||||
loading: false,
|
||||
refreshing: false,
|
||||
pageForm: {
|
||||
activityId: GetQueryString("activityId"),
|
||||
searchKeyword: "",
|
||||
pageNumber: 1,
|
||||
pageSize: 5,
|
||||
totalCount: 0
|
||||
},
|
||||
subLoading: false,
|
||||
activityData: {},
|
||||
viewMode: "card"
|
||||
}
|
||||
},
|
||||
components: {},
|
||||
computed: {
|
||||
canUnionApplyOnPc() {
|
||||
return this.$auth.hasRoleOr([
|
||||
"SYSADMIN",
|
||||
"SCHOOL_UNION_ADMIN",
|
||||
"BRANCH_UNION_CHAIRMAN",
|
||||
"BRANCH_UNION_WENTI_SPORTS"
|
||||
]) && this.$auth.hasPermission("activity.apply")
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleViewMode() {
|
||||
this.viewMode = this.viewMode === "card" ? "list" : "card"
|
||||
},
|
||||
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.finished = false
|
||||
this.tableData = []
|
||||
this.pageData()
|
||||
},
|
||||
onRefresh() {
|
||||
this.doSearch()
|
||||
},
|
||||
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
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
this.refreshing = 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,253 @@
|
||||
let ACTIVITY_EVENT_NOTIFICATION = {
|
||||
template: `
|
||||
<div class="activity-notification-component">
|
||||
<van-popup
|
||||
v-model="viewShow"
|
||||
class="activity-notification-popup"
|
||||
:style="{ height: '100%', width: '100%' }"
|
||||
position="right"
|
||||
safe-area-inset-bottom
|
||||
>
|
||||
<div class="activity-notification-page">
|
||||
<van-sticky>
|
||||
<van-nav-bar
|
||||
title="活动通知"
|
||||
left-arrow
|
||||
left-text="返回"
|
||||
@click-left="viewShow = false"
|
||||
></van-nav-bar>
|
||||
</van-sticky>
|
||||
|
||||
<div class="activity-notification-scroll">
|
||||
<div class="activity-notification-hero">
|
||||
<div class="activity-notification-hero__icon">
|
||||
<van-icon name="description"></van-icon>
|
||||
</div>
|
||||
<div>
|
||||
<div class="activity-notification-hero__title">活动报名须知</div>
|
||||
<div class="activity-notification-hero__subtitle">请仔细阅读活动安排与报名要求</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<article v-if="event_notification" class="activity-notification-card">
|
||||
<div class="activity-notification-content" v-html="event_notification"></div>
|
||||
</article>
|
||||
<div v-else class="activity-notification-empty">
|
||||
<van-icon name="description"></van-icon>
|
||||
<span>暂无活动通知</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="activity-notification-footer">
|
||||
<van-button v-if="inApplyTime" type="primary" round block @click="openReg">进入报名</van-button>
|
||||
<van-button v-else class="is-disabled" disabled round block>{{ applyStatusText }}</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</div>
|
||||
`,
|
||||
props: {
|
||||
event_notification: {
|
||||
value: { type: String, default: "暂无" }
|
||||
},
|
||||
id: {
|
||||
value: { type: String, default: "暂无" }
|
||||
},
|
||||
apply_start_time: {
|
||||
value: { type: String, default: "" }
|
||||
},
|
||||
apply_end_time: {
|
||||
value: { type: String, default: "" }
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
viewShow: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 详情页统一控制报名入口状态,活动列表仅负责进入详情。
|
||||
inApplyTime() {
|
||||
if (!this.apply_start_time || !this.apply_end_time) return false
|
||||
const now = Date.now()
|
||||
return now >= this.$moment(this.apply_start_time).valueOf()
|
||||
&& now <= this.$moment(this.apply_end_time).valueOf()
|
||||
},
|
||||
applyStatusText() {
|
||||
if (!this.apply_start_time || !this.apply_end_time) return "当前不可报名"
|
||||
if (Date.now() < this.$moment(this.apply_start_time).valueOf()) return "报名未开始"
|
||||
return "已过报名时间"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openReg() {
|
||||
this.$pjaxReplace("/platform/activity/apply/h5/eventList?activityId=" + this.id)
|
||||
}
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
.activity-notification-popup {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.activity-notification-page {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.activity-notification-page /deep/ .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.activity-notification-page /deep/ .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.activity-notification-page /deep/ .van-nav-bar .van-icon,
|
||||
.activity-notification-page /deep/ .van-nav-bar__text {
|
||||
color: #397fbd;
|
||||
}
|
||||
|
||||
.activity-notification-scroll {
|
||||
height: calc(100vh - 46px);
|
||||
padding: 12px 12px calc(92px + env(safe-area-inset-bottom));
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.activity-notification-hero {
|
||||
display: flex;
|
||||
min-height: 82px;
|
||||
padding: 16px;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
border-radius: 12px;
|
||||
color: #fff;
|
||||
background: linear-gradient(120deg, #2d7eea 0%, #5ba6f7 100%);
|
||||
box-shadow: 0 8px 20px rgba(45, 126, 234, .18);
|
||||
}
|
||||
|
||||
.activity-notification-hero__icon {
|
||||
display: flex;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
margin-right: 12px;
|
||||
flex: 0 0 44px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 11px;
|
||||
color: #2d7eea;
|
||||
background-color: rgba(255, 255, 255, .92);
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.activity-notification-hero__title {
|
||||
font-size: 17px;
|
||||
line-height: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.activity-notification-hero__subtitle {
|
||||
margin-top: 3px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
.activity-notification-card {
|
||||
margin-top: 12px;
|
||||
padding: 18px 16px;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
}
|
||||
|
||||
.activity-notification-content {
|
||||
color: #3f4c5e;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.activity-notification-content /deep/ h1,
|
||||
.activity-notification-content /deep/ h2,
|
||||
.activity-notification-content /deep/ h3 {
|
||||
margin: 0 0 12px !important;
|
||||
color: #1f2f43 !important;
|
||||
font-size: 20px !important;
|
||||
line-height: 1.5 !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
.activity-notification-content /deep/ p {
|
||||
margin: 0 0 8px !important;
|
||||
font-size: 14px !important;
|
||||
line-height: 1.8 !important;
|
||||
}
|
||||
|
||||
.activity-notification-content /deep/ img {
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.activity-notification-content /deep/ table {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.activity-notification-empty {
|
||||
display: flex;
|
||||
min-height: 180px;
|
||||
margin-top: 12px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
row-gap: 10px;
|
||||
border-radius: 12px;
|
||||
color: #9aa7b8;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.activity-notification-empty /deep/ .van-icon {
|
||||
color: #83b5f4;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.activity-notification-footer {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 5;
|
||||
padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
|
||||
border-top: 1px solid #edf1f6;
|
||||
background-color: rgba(255, 255, 255, .96);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.activity-notification-footer /deep/ .van-button {
|
||||
height: 42px;
|
||||
border: 0;
|
||||
font-size: 15px;
|
||||
background-color: #1989fa;
|
||||
box-shadow: 0 6px 16px rgba(25, 137, 250, .22);
|
||||
}
|
||||
|
||||
.activity-notification-footer /deep/ .van-button.is-disabled,
|
||||
.activity-notification-footer /deep/ .van-button--disabled {
|
||||
color: #8b98aa !important;
|
||||
background-color: #eef2f7 !important;
|
||||
opacity: 1;
|
||||
box-shadow: none;
|
||||
}
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,763 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
body {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.brand-activity-page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: calc(24px + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.brand-activity-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.brand-activity-page .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.brand-activity-page .van-nav-bar .van-icon,
|
||||
.brand-activity-page .van-nav-bar__text {
|
||||
color: #397fbd;
|
||||
}
|
||||
|
||||
.brand-activity-content {
|
||||
padding: 12px 12px 0;
|
||||
}
|
||||
|
||||
.brand-activity-hero {
|
||||
position: relative;
|
||||
height: 134px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
color: #fff;
|
||||
background-color: #247fe8;
|
||||
box-shadow: 0 8px 20px rgba(51, 117, 219, .18);
|
||||
}
|
||||
|
||||
.brand-activity-hero__image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
|
||||
.brand-activity-hero__copy {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
width: 64%;
|
||||
height: 100%;
|
||||
padding-left: 16px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
background: linear-gradient(90deg, rgba(22, 112, 232, .98) 0%, rgba(22, 112, 232, .88) 52%, rgba(22, 112, 232, 0) 100%);
|
||||
}
|
||||
|
||||
.brand-activity-hero__title {
|
||||
font-size: 25px;
|
||||
line-height: 34px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1px;
|
||||
text-shadow: 0 2px 6px rgba(17, 86, 182, .18);
|
||||
}
|
||||
|
||||
.brand-activity-hero__subtitle {
|
||||
margin-top: 4px;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
letter-spacing: .5px;
|
||||
opacity: .95;
|
||||
}
|
||||
|
||||
.brand-activity-sticky {
|
||||
padding: 10px 0 1px;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.van-sticky--fixed .brand-activity-sticky {
|
||||
padding-right: 12px;
|
||||
padding-left: 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.brand-activity-search {
|
||||
margin: 0 0 8px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .1);
|
||||
}
|
||||
|
||||
.brand-activity-search .van-search__content {
|
||||
height: 42px;
|
||||
padding-left: 12px;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.brand-activity-search .van-field__control {
|
||||
color: #263548;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.brand-activity-search .van-field__control::placeholder {
|
||||
color: #a7b0bf;
|
||||
}
|
||||
|
||||
.brand-activity-filter {
|
||||
margin: 0 0 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .08);
|
||||
transition: border-radius .18s ease;
|
||||
}
|
||||
|
||||
.brand-activity-filter.is-open {
|
||||
border-radius: 10px 10px 0 0;
|
||||
}
|
||||
|
||||
.brand-activity-filter .van-dropdown-menu__bar {
|
||||
height: 44px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.brand-activity-filter .van-dropdown-menu__item {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.brand-activity-filter .van-dropdown-menu__title {
|
||||
width: auto;
|
||||
max-width: calc(100% - 24px);
|
||||
padding: 0 12px 0 0;
|
||||
overflow: hidden;
|
||||
color: #66758a;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.brand-activity-filter .van-dropdown-menu__title::after {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.brand-activity-filter .van-dropdown-menu__title--active,
|
||||
.brand-activity-filter .van-dropdown-item__option--active,
|
||||
.brand-activity-filter .van-dropdown-item__option--active .van-dropdown-item__icon {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.brand-activity-filter .van-dropdown-menu__title--down::after {
|
||||
border-color: transparent transparent #1989fa #1989fa;
|
||||
}
|
||||
|
||||
.brand-activity-filter .van-dropdown-item__content {
|
||||
width: calc(100% - 24px);
|
||||
margin: 0 12px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0 0 12px 12px;
|
||||
box-shadow: 0 10px 24px rgba(31, 65, 108, .14);
|
||||
}
|
||||
|
||||
.brand-activity-filter .van-dropdown-item__option {
|
||||
min-height: 48px;
|
||||
padding: 0 16px;
|
||||
color: #46566c;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.brand-activity-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.brand-activity-card {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.brand-activity-card__cover,
|
||||
.brand-activity-card__cover-state {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
background-color: #edf4fc;
|
||||
}
|
||||
|
||||
.brand-activity-card__cover {
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.brand-activity-card__cover-state {
|
||||
flex-direction: column;
|
||||
row-gap: 8px;
|
||||
color: #8da1ba;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.brand-activity-card__cover-state .van-icon {
|
||||
font-size: 34px;
|
||||
}
|
||||
|
||||
.brand-activity-card__cover-state.is-error {
|
||||
color: #c27b75;
|
||||
background-color: #fff3f1;
|
||||
}
|
||||
|
||||
.brand-activity-card__body {
|
||||
padding: 12px 38px 14px 14px;
|
||||
}
|
||||
|
||||
.brand-activity-card__title {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
color: #303846;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.brand-activity-card__time {
|
||||
margin-top: 4px;
|
||||
overflow: hidden;
|
||||
color: #98a2b2;
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.brand-activity-card__meta {
|
||||
display: flex;
|
||||
margin-top: 10px;
|
||||
padding-top: 9px;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
border-top: 1px solid #edf1f6;
|
||||
}
|
||||
|
||||
.brand-activity-card__tag {
|
||||
display: inline-flex;
|
||||
padding: 3px 8px;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
color: #397de0;
|
||||
background-color: #edf5ff;
|
||||
font-size: 11px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.brand-activity-card__tag-label {
|
||||
margin-right: 4px;
|
||||
color: #8aa7cf;
|
||||
}
|
||||
|
||||
.brand-activity-card__arrow {
|
||||
position: absolute;
|
||||
top: 164px;
|
||||
right: 14px;
|
||||
color: #b4bdca;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.brand-activity-empty {
|
||||
display: flex;
|
||||
min-height: 260px;
|
||||
padding: 26px 18px 32px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.brand-activity-empty img {
|
||||
display: block;
|
||||
width: 82%;
|
||||
max-width: 280px;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.brand-activity-empty__title {
|
||||
margin-top: 14px;
|
||||
color: #50627a;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.brand-activity-empty__hint {
|
||||
margin-top: 5px;
|
||||
color: #9aa7b8;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.brand-activity-page .van-list__loading {
|
||||
color: #9aa7b8;
|
||||
font-size: 13px;
|
||||
line-height: 44px;
|
||||
}
|
||||
|
||||
.brand-intro-popup,
|
||||
.brand-intro-page {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.brand-intro-page {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.brand-intro-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.brand-intro-page .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.brand-intro-page .van-nav-bar .van-icon,
|
||||
.brand-intro-page .van-nav-bar__text {
|
||||
color: #397fbd;
|
||||
}
|
||||
|
||||
.brand-intro-scroll {
|
||||
height: calc(100vh - 46px);
|
||||
padding: 12px 12px calc(92px + env(safe-area-inset-bottom));
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.brand-intro-hero {
|
||||
display: flex;
|
||||
min-height: 82px;
|
||||
padding: 16px;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
border-radius: 12px;
|
||||
color: #fff;
|
||||
background: linear-gradient(120deg, #2d7eea 0%, #5ba6f7 100%);
|
||||
box-shadow: 0 8px 20px rgba(45, 126, 234, .18);
|
||||
}
|
||||
|
||||
.brand-intro-hero__icon {
|
||||
display: flex;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
margin-right: 12px;
|
||||
flex: 0 0 44px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 11px;
|
||||
color: #2d7eea;
|
||||
background-color: rgba(255, 255, 255, .92);
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.brand-intro-hero__title {
|
||||
font-size: 17px;
|
||||
line-height: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.brand-intro-hero__subtitle {
|
||||
margin-top: 3px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
.brand-intro-card {
|
||||
margin-top: 12px;
|
||||
padding: 18px 16px;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
}
|
||||
|
||||
.brand-intro-content,
|
||||
.brand-intro-content div,
|
||||
.brand-intro-content p,
|
||||
.brand-intro-content span,
|
||||
.brand-intro-content li {
|
||||
color: #3f4c5e !important;
|
||||
font-size: 14px !important;
|
||||
line-height: 1.8 !important;
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.brand-intro-content h1,
|
||||
.brand-intro-content h2,
|
||||
.brand-intro-content h3 {
|
||||
margin: 16px 0 10px !important;
|
||||
color: #1f2f43 !important;
|
||||
font-size: 19px !important;
|
||||
line-height: 1.5 !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
.brand-intro-content > :first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.brand-intro-content p {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 8px !important;
|
||||
}
|
||||
|
||||
.brand-intro-content img {
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.brand-intro-content table {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.brand-intro-empty {
|
||||
display: flex;
|
||||
min-height: 180px;
|
||||
margin-top: 12px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
row-gap: 10px;
|
||||
border-radius: 12px;
|
||||
color: #9aa7b8;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.brand-intro-empty .van-icon {
|
||||
color: #83b5f4;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.brand-intro-footer {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 5;
|
||||
padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
|
||||
border-top: 1px solid #edf1f6;
|
||||
background-color: rgba(255, 255, 255, .96);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.brand-intro-footer .van-button {
|
||||
height: 42px;
|
||||
border: 0;
|
||||
border-radius: 21px;
|
||||
font-size: 15px;
|
||||
background-color: #1989fa;
|
||||
box-shadow: 0 6px 16px rgba(25, 137, 250, .22);
|
||||
}
|
||||
|
||||
.brand-intro-footer .van-button--disabled {
|
||||
color: #8b98aa !important;
|
||||
background-color: #eef2f7 !important;
|
||||
opacity: 1;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.brand-intro-footer .van-count-down {
|
||||
display: inline-block;
|
||||
margin-left: 4px;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<div class="brand-activity-page">
|
||||
<van-nav-bar title="品牌活动" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||
|
||||
<div class="brand-activity-content">
|
||||
<section class="brand-activity-hero">
|
||||
<img class="brand-activity-hero__image" src="/assets/mobile/img/activity/hero/brand-hero-v2.png" alt="品牌活动插画">
|
||||
<div class="brand-activity-hero__copy">
|
||||
<div class="brand-activity-hero__title">品牌活动</div>
|
||||
<div class="brand-activity-hero__subtitle">品牌引领 · 成长同行</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<van-sticky :offset-top="46">
|
||||
<div class="brand-activity-sticky">
|
||||
<van-search
|
||||
v-model="pageForm.searchKeyword"
|
||||
class="brand-activity-search"
|
||||
placeholder="搜索品牌活动"
|
||||
shape="round"
|
||||
clearable
|
||||
@search="doSearch"
|
||||
@clear="doSearch"
|
||||
></van-search>
|
||||
<van-dropdown-menu class="brand-activity-filter" :class="{'is-open': filterOpened}" active-color="#1989fa">
|
||||
<year-van-dropdown-item :num="5" @change="doSearch" @open="filterOpened = true" @close="filterOpened = false" v-model="pageForm.year"></year-van-dropdown-item>
|
||||
<van-dropdown-item v-model="pageForm.activityType" :options="typeOptions" :multiple="false" @change="doSearch" @open="filterOpened = true" @close="filterOpened = false"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</div>
|
||||
</van-sticky>
|
||||
|
||||
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
|
||||
<van-list v-model="loading" :finished="finished" :immediate-check="false" @load="onLoad">
|
||||
<div class="brand-activity-list">
|
||||
<div v-for="row in tableData" :key="row.id" class="brand-activity-card" @click="onView(row)">
|
||||
<img
|
||||
v-if="hasCover(row) && !imageLoadErrors[row.id]"
|
||||
class="brand-activity-card__cover"
|
||||
:src="row.cover"
|
||||
:alt="row.activityName"
|
||||
@error="handleImageError(row)"
|
||||
>
|
||||
<div v-else class="brand-activity-card__cover-state" :class="{'is-error': hasCover(row)}">
|
||||
<van-icon name="photo-o"></van-icon>
|
||||
<span>{{ hasCover(row) ? '图片加载失败' : '暂无图片' }}</span>
|
||||
</div>
|
||||
<div class="brand-activity-card__body">
|
||||
<div class="brand-activity-card__title">{{ row.activityName }}</div>
|
||||
<div class="brand-activity-card__time" v-if="row.activitySignUpStartTime && row.activitySignUpEndTime">
|
||||
报名时间:{{ $moment(row.activitySignUpStartTime).format('MM/DD HH:mm') }}~{{ $moment(row.activitySignUpEndTime).format('MM/DD HH:mm') }}
|
||||
</div>
|
||||
<div class="brand-activity-card__time" v-if="row.activityStartTime && row.activityEndTime">
|
||||
活动时间:{{ $moment(row.activityStartTime).format('MM/DD HH:mm') }}~{{ $moment(row.activityEndTime).format('MM/DD HH:mm') }}
|
||||
</div>
|
||||
<div class="brand-activity-card__meta" v-if="row.activityGroupName || row.trainType">
|
||||
<span class="brand-activity-card__tag" v-if="row.activityGroupName">
|
||||
<span class="brand-activity-card__tag-label">面向对象</span>{{ row.activityGroupName }}
|
||||
</span>
|
||||
<span class="brand-activity-card__tag" v-if="row.trainType">
|
||||
<span class="brand-activity-card__tag-label">活动类型</span>{{ row.trainType }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<van-icon class="brand-activity-card__arrow" name="arrow"></van-icon>
|
||||
</div>
|
||||
</div>
|
||||
</van-list>
|
||||
<div v-if="!loading && tableData.length === 0" class="brand-activity-empty">
|
||||
<img src="/assets/mobile/img/activity/culture-empty.png" alt="品牌活动空状态插画">
|
||||
<div class="brand-activity-empty__title">暂无品牌活动</div>
|
||||
<div class="brand-activity-empty__hint">当前筛选条件下暂时没有可展示的活动</div>
|
||||
</div>
|
||||
</van-pull-refresh>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<van-popup class="brand-intro-popup" :style="{height: '100%', width: '100%'}" position="right" safe-area-inset-bottom v-model="infoVisible">
|
||||
<div class="brand-intro-page">
|
||||
<van-sticky>
|
||||
<van-nav-bar title="活动介绍" left-text="返回" left-arrow @click-left="infoVisible = false"></van-nav-bar>
|
||||
</van-sticky>
|
||||
<div class="brand-intro-scroll">
|
||||
<div class="brand-intro-hero">
|
||||
<div class="brand-intro-hero__icon">
|
||||
<van-icon name="description"></van-icon>
|
||||
</div>
|
||||
<div>
|
||||
<div class="brand-intro-hero__title">活动报名须知</div>
|
||||
<div class="brand-intro-hero__subtitle">请仔细阅读活动安排与报名要求</div>
|
||||
</div>
|
||||
</div>
|
||||
<article v-if="infoRow.introduce" class="brand-intro-card">
|
||||
<div class="brand-intro-content" v-html="infoRow.introduce"></div>
|
||||
</article>
|
||||
<div v-else class="brand-intro-empty">
|
||||
<van-icon name="description"></van-icon>
|
||||
<span>暂无活动介绍</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="brand-intro-footer">
|
||||
<van-button v-if="canApply(infoRow)" @click="onApply(infoRow)" type="primary" block round>进入报名</van-button>
|
||||
<van-button v-else-if="time < 0" @click="onApply(infoRow)" type="primary" block round>
|
||||
距离开始
|
||||
<van-count-down :time="Math.abs(time)" format="DD 天 HH 时 mm 分 ss 秒" @finish="time = 0"></van-count-down>
|
||||
</van-button>
|
||||
<van-button v-else disabled block round>{{ registrationStatusText(infoRow) }}</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
time: 0,
|
||||
tableData: [],
|
||||
loading: false,
|
||||
finished: false,
|
||||
refreshing: false,
|
||||
imageLoadErrors: {},
|
||||
filterOpened: false,
|
||||
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: {
|
||||
hasCover(row) {
|
||||
return !!(row && row.cover && String(row.cover).trim())
|
||||
},
|
||||
handleImageError(row) {
|
||||
this.$set(this.imageLoadErrors, row.id, true)
|
||||
},
|
||||
isRegistrationClosed(row) {
|
||||
return !!(row && row.activitySignUpEndTime && !this.$moment().isBefore(this.$moment(row.activitySignUpEndTime)))
|
||||
},
|
||||
canApply(row) {
|
||||
if(!row || !row.activitySignUpStartTime || !row.activitySignUpEndTime) {
|
||||
return false
|
||||
}
|
||||
const now = Date.now()
|
||||
return now >= this.$moment(row.activitySignUpStartTime).valueOf()
|
||||
&& now <= this.$moment(row.activitySignUpEndTime).valueOf()
|
||||
},
|
||||
registrationStatusText(row) {
|
||||
if(!row || !row.activitySignUpStartTime || !row.activitySignUpEndTime) {
|
||||
return '当前不可报名'
|
||||
}
|
||||
if(Date.now() < this.$moment(row.activitySignUpStartTime).valueOf()) {
|
||||
return '报名未开始'
|
||||
}
|
||||
return '已过报名时间'
|
||||
},
|
||||
onView(row) {
|
||||
this.infoRow = row
|
||||
this.time = this.$moment().diff(this.$moment(row.activitySignUpStartTime), 'milliseconds')
|
||||
this.infoVisible = true
|
||||
},
|
||||
onApply(row) {
|
||||
if(this.isRegistrationClosed(row)) {
|
||||
return
|
||||
}
|
||||
if(this.$moment().isBefore(this.$moment(row.activitySignUpStartTime))) {
|
||||
this.onView(row)
|
||||
return
|
||||
}
|
||||
// 先校验年度同活动类型报名次数,避免进入课程页后才提示不可报名。
|
||||
this.$axios.post('/platform/trainSignUp/apply/validateYearTrainTypeSignUp', {activityId: row.id}).then((res) => {
|
||||
if (res.code !== 0) {
|
||||
vant.Dialog.alert({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
confirmButtonColor: '#1867b0'
|
||||
})
|
||||
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)
|
||||
}
|
||||
})
|
||||
},
|
||||
onLoad() {
|
||||
if(!this.finished) {
|
||||
this.loadActivities(false)
|
||||
}
|
||||
},
|
||||
onRefresh() {
|
||||
this.loadActivities(true)
|
||||
},
|
||||
loadActivities(reset) {
|
||||
if(reset) {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.tableData = []
|
||||
this.finished = false
|
||||
this.imageLoadErrors = {}
|
||||
}
|
||||
this.loading = true
|
||||
this.$axios.post('/platform/trainSignUp/apply/activityPageData', this.pageForm).then((res) => {
|
||||
if(res.code === 0) {
|
||||
const list = res.data && res.data.list ? res.data.list : []
|
||||
this.tableData = this.pageForm.pageNumber === 1 ? list : this.tableData.concat(list)
|
||||
this.pageForm.totalCount = res.data && res.data.totalCount ? res.data.totalCount : 0
|
||||
this.finished = this.tableData.length >= this.pageForm.totalCount
|
||||
if(!this.finished) {
|
||||
this.pageForm.pageNumber++
|
||||
}
|
||||
}
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
this.refreshing = false
|
||||
})
|
||||
},
|
||||
doSearch() {
|
||||
this.loadActivities(true)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadActivities(true)
|
||||
if(this.id) {
|
||||
this.fetchOne()
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,286 @@
|
||||
const times = {
|
||||
template:
|
||||
/*language=HTML*/
|
||||
`
|
||||
<div>
|
||||
<van-action-sheet class="brand-course-times-sheet" :style="{height: '78%'}" :close-on-click-overlay="true" v-model="visible" title="时间段" cancel-text="取消">
|
||||
<div class="brand-course-times-list">
|
||||
<div id="mapContainer" v-if="row?.isMobileSign === true && row?.signType === 3" class="brand-course-times-map"></div>
|
||||
<button v-for="(item,index) in row?.courseTimes" :key="index" type="button" class="van-action-sheet__item brand-course-time-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>
|
||||
</div>
|
||||
</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*/ `
|
||||
.brand-course-times-sheet {
|
||||
overflow: hidden;
|
||||
border-radius: 16px 16px 0 0;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.brand-course-times-sheet /deep/ .van-action-sheet__header {
|
||||
height: 48px;
|
||||
color: #1f2f43;
|
||||
background-color: #fff;
|
||||
font-size: 16px;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
.brand-course-times-sheet /deep/ .van-action-sheet__close {
|
||||
top: 13px;
|
||||
color: #b5bdc9;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.brand-course-times-list {
|
||||
height: calc(100% - 98px);
|
||||
padding: 10px 12px 0;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.brand-course-times-map {
|
||||
width: 100%;
|
||||
height: 180px;
|
||||
margin-bottom: 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.brand-course-times-sheet /deep/ .brand-course-time-item {
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
padding: 14px;
|
||||
border-radius: 10px;
|
||||
color: #263548;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 6px 18px rgba(55, 85, 126, .07);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.brand-course-times-sheet /deep/ .van-action-sheet__name {
|
||||
color: #263548;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
.brand-course-times-sheet /deep/ .van-action-sheet__subname {
|
||||
margin-top: 5px;
|
||||
color: #98a2b2;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.brand-course-times-sheet /deep/ .van-action-sheet__cancel {
|
||||
height: 50px;
|
||||
color: #66758a;
|
||||
background-color: #fff;
|
||||
font-size: 14px;
|
||||
}
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
const applyForm = {
|
||||
template:
|
||||
/*language=HTML*/
|
||||
`
|
||||
<div>
|
||||
<van-action-sheet class="brand-course-form-sheet" :style="{height: '78%'}" :close-on-click-overlay="true" 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*/ `
|
||||
.brand-course-form-sheet {
|
||||
overflow: hidden;
|
||||
border-radius: 16px 16px 0 0;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.brand-course-form-sheet /deep/ .van-action-sheet__header {
|
||||
height: 48px;
|
||||
color: #1f2f43;
|
||||
background-color: #fff;
|
||||
font-size: 16px;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
.brand-course-form-sheet /deep/ .van-action-sheet__close {
|
||||
top: 13px;
|
||||
color: #b5bdc9;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.brand-course-form-sheet /deep/ .form-container {
|
||||
height: calc(100% - 48px);
|
||||
padding: 10px 12px 72px;
|
||||
overflow-y: auto;
|
||||
background-color: #f3f7fd;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.brand-course-form-sheet /deep/ .form-section {
|
||||
margin-bottom: 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 6px 18px rgba(55, 85, 126, .07);
|
||||
}
|
||||
|
||||
.brand-course-form-sheet /deep/ .van-cell-group__title {
|
||||
padding: 12px 14px 8px;
|
||||
color: #263548;
|
||||
background-color: #fff;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.brand-course-form-sheet /deep/ .van-cell-group__title::before {
|
||||
width: 3px;
|
||||
top: 12px;
|
||||
bottom: 8px;
|
||||
border-radius: 2px;
|
||||
background-color: #1989fa;
|
||||
}
|
||||
|
||||
.brand-course-form-sheet /deep/ .van-cell {
|
||||
padding: 11px 14px;
|
||||
color: #263548;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.brand-course-form-sheet /deep/ .van-field__label {
|
||||
color: #66758a;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.brand-course-form-sheet /deep/ .button {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
|
||||
border-top: 1px solid #edf1f6;
|
||||
background-color: rgba(255, 255, 255, .96);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.brand-course-form-sheet /deep/ .button .van-button {
|
||||
height: 42px;
|
||||
border: 0;
|
||||
border-radius: 21px;
|
||||
color: #fff;
|
||||
background-color: #1989fa;
|
||||
font-size: 15px;
|
||||
box-shadow: 0 6px 16px rgba(25, 137, 250, .22);
|
||||
}
|
||||
`
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,550 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
body {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.brand-mine-page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: calc(24px + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.brand-mine-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.brand-mine-page .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.brand-mine-page .van-nav-bar .van-icon,
|
||||
.brand-mine-page .van-nav-bar__text {
|
||||
color: #397fbd;
|
||||
}
|
||||
|
||||
.brand-mine-content {
|
||||
padding: 12px 12px 0;
|
||||
}
|
||||
|
||||
.brand-mine-hero {
|
||||
position: relative;
|
||||
height: 134px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
color: #fff;
|
||||
background: linear-gradient(115deg, #347eea 0%, #5b9cf4 58%, #cfe3ff 100%);
|
||||
box-shadow: 0 8px 20px rgba(51, 117, 219, .18);
|
||||
}
|
||||
|
||||
.brand-mine-hero__image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 67%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: right center;
|
||||
-webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 26%);
|
||||
mask-image: linear-gradient(90deg, transparent 0%, #000 26%);
|
||||
}
|
||||
|
||||
.brand-mine-hero__copy {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
padding-left: 16px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.brand-mine-hero__title {
|
||||
font-size: 25px;
|
||||
line-height: 34px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.brand-mine-hero__subtitle {
|
||||
margin-top: 4px;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
letter-spacing: .5px;
|
||||
opacity: .95;
|
||||
}
|
||||
|
||||
.brand-mine-sticky {
|
||||
padding: 10px 0 1px;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.van-sticky--fixed .brand-mine-sticky {
|
||||
padding-right: 12px;
|
||||
padding-left: 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.brand-mine-search {
|
||||
margin-bottom: 8px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .1);
|
||||
}
|
||||
|
||||
.brand-mine-search .van-search__content {
|
||||
height: 42px;
|
||||
padding-left: 12px;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.brand-mine-search .van-field__control {
|
||||
color: #263548;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.brand-mine-filter {
|
||||
margin-bottom: 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .08);
|
||||
transition: border-radius .18s ease;
|
||||
}
|
||||
|
||||
.brand-mine-filter.is-open {
|
||||
border-radius: 10px 10px 0 0;
|
||||
}
|
||||
|
||||
.brand-mine-filter .van-dropdown-menu__bar {
|
||||
height: 44px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.brand-mine-filter .van-dropdown-menu__title {
|
||||
width: auto;
|
||||
max-width: calc(100% - 24px);
|
||||
padding: 0 12px 0 0;
|
||||
color: #66758a;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.brand-mine-filter .van-dropdown-menu__title::after {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.brand-mine-filter .van-dropdown-item__content {
|
||||
width: calc(100% - 24px);
|
||||
margin: 0 12px;
|
||||
overflow: hidden;
|
||||
border-radius: 0 0 12px 12px;
|
||||
box-shadow: 0 10px 24px rgba(31, 65, 108, .14);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.brand-mine-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.brand-mine-card {
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
}
|
||||
|
||||
.brand-mine-card__cover,
|
||||
.brand-mine-card__cover-state {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #edf4fc;
|
||||
}
|
||||
|
||||
.brand-mine-card__cover {
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.brand-mine-card__cover-state {
|
||||
flex-direction: column;
|
||||
row-gap: 8px;
|
||||
color: #8da1ba;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.brand-mine-card__cover-state .van-icon {
|
||||
font-size: 34px;
|
||||
}
|
||||
|
||||
.brand-mine-card__cover-state.is-error {
|
||||
color: #c27b75;
|
||||
background-color: #fff3f1;
|
||||
}
|
||||
|
||||
.brand-mine-card__body {
|
||||
padding: 12px 14px 14px;
|
||||
}
|
||||
|
||||
.brand-mine-card__title {
|
||||
overflow: hidden;
|
||||
color: #303846;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.brand-mine-card__time {
|
||||
margin-top: 4px;
|
||||
overflow: hidden;
|
||||
color: #98a2b2;
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.brand-mine-card__meta {
|
||||
display: flex;
|
||||
margin-top: 10px;
|
||||
padding-top: 9px;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
border-top: 1px solid #edf1f6;
|
||||
}
|
||||
|
||||
.brand-mine-card__tag {
|
||||
display: inline-flex;
|
||||
padding: 3px 8px;
|
||||
border-radius: 4px;
|
||||
color: #397de0;
|
||||
background-color: #edf5ff;
|
||||
font-size: 11px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.brand-mine-card__tag-label {
|
||||
margin-right: 4px;
|
||||
color: #8aa7cf;
|
||||
}
|
||||
|
||||
.brand-mine-card__actions {
|
||||
display: flex;
|
||||
padding: 12px 14px;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
border-top: 1px solid #edf1f6;
|
||||
background-color: #f8fbff;
|
||||
}
|
||||
|
||||
.brand-mine-card__action {
|
||||
display: inline-flex;
|
||||
min-width: 82px;
|
||||
height: 32px;
|
||||
padding: 0 14px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 0;
|
||||
border-radius: 16px;
|
||||
color: #397de0;
|
||||
background-color: #edf5ff;
|
||||
font-size: 13px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.brand-mine-card__action .van-icon {
|
||||
margin-right: 6px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.brand-mine-card__action.is-primary {
|
||||
color: #fff;
|
||||
background-color: #1989fa;
|
||||
box-shadow: 0 5px 12px rgba(25, 137, 250, .18);
|
||||
}
|
||||
|
||||
.brand-mine-empty {
|
||||
display: flex;
|
||||
min-height: 260px;
|
||||
padding: 26px 18px 32px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.brand-mine-empty img {
|
||||
width: 82%;
|
||||
max-width: 280px;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.brand-mine-empty__title {
|
||||
margin-top: 14px;
|
||||
color: #50627a;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.brand-mine-empty__hint {
|
||||
margin-top: 5px;
|
||||
color: #9aa7b8;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.brand-mine-intro-page {
|
||||
min-height: 100vh;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.brand-mine-intro-scroll {
|
||||
height: calc(100vh - 46px);
|
||||
padding: 12px;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.brand-mine-intro-hero {
|
||||
display: flex;
|
||||
min-height: 82px;
|
||||
padding: 16px;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
color: #fff;
|
||||
background: linear-gradient(120deg, #2d7eea 0%, #5ba6f7 100%);
|
||||
box-shadow: 0 8px 20px rgba(45, 126, 234, .18);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.brand-mine-intro-hero__icon {
|
||||
display: flex;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
margin-right: 12px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 0 0 44px;
|
||||
border-radius: 11px;
|
||||
color: #2d7eea;
|
||||
background-color: rgba(255, 255, 255, .92);
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.brand-mine-intro-hero__title {
|
||||
font-size: 17px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.brand-mine-intro-hero__subtitle {
|
||||
margin-top: 3px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
.brand-mine-intro-card {
|
||||
margin-top: 12px;
|
||||
padding: 18px 16px;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
color: #3f4c5e;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.brand-mine-intro-card img {
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<div class="brand-mine-page">
|
||||
<van-nav-bar title="品牌活动-我的报名" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||
|
||||
<div class="brand-mine-content">
|
||||
<section class="brand-mine-hero">
|
||||
<img class="brand-mine-hero__image" src="/assets/mobile/img/home/v4/feature-activity.png" alt="品牌活动插画">
|
||||
<div class="brand-mine-hero__copy">
|
||||
<div class="brand-mine-hero__title">我的报名</div>
|
||||
<div class="brand-mine-hero__subtitle">品牌活动 · 报名记录</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<van-sticky :offset-top="46">
|
||||
<div class="brand-mine-sticky">
|
||||
<van-search v-model="pageForm.searchKeyword" class="brand-mine-search" placeholder="搜索已报名活动" shape="round" clearable @search="doSearch" @clear="doSearch"></van-search>
|
||||
<van-dropdown-menu class="brand-mine-filter" :class="{'is-open': filterOpened}" active-color="#1989fa">
|
||||
<year-van-dropdown-item :num="5" @change="doSearch" @open="filterOpened = true" @close="filterOpened = false" v-model="pageForm.year"></year-van-dropdown-item>
|
||||
<van-dropdown-item v-model="pageForm.activityType" :options="typeOptions" :multiple="false" @change="doSearch" @open="filterOpened = true" @close="filterOpened = false"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</div>
|
||||
</van-sticky>
|
||||
|
||||
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
|
||||
<van-list v-model="loading" :finished="finished" :immediate-check="false" @load="onLoad">
|
||||
<div class="brand-mine-list">
|
||||
<div v-for="row in tableData" :key="row.id" class="brand-mine-card">
|
||||
<img v-if="hasCover(row) && !imageLoadErrors[row.id]" class="brand-mine-card__cover" :src="row.cover" :alt="row.activityName" @error="handleImageError(row)">
|
||||
<div v-else class="brand-mine-card__cover-state" :class="{'is-error': hasCover(row)}">
|
||||
<van-icon name="photo-o"></van-icon>
|
||||
<span>{{ hasCover(row) ? '图片加载失败' : '暂无图片' }}</span>
|
||||
</div>
|
||||
<div class="brand-mine-card__body">
|
||||
<div class="brand-mine-card__title">{{ row.activityName }}</div>
|
||||
<div class="brand-mine-card__time" v-if="row.activitySignUpStartTime && row.activitySignUpEndTime">
|
||||
报名时间:{{ $moment(row.activitySignUpStartTime).format('MM/DD HH:mm') }}~{{ $moment(row.activitySignUpEndTime).format('MM/DD HH:mm') }}
|
||||
</div>
|
||||
<div class="brand-mine-card__time" v-if="row.activityStartTime && row.activityEndTime">
|
||||
活动时间:{{ $moment(row.activityStartTime).format('MM/DD HH:mm') }}~{{ $moment(row.activityEndTime).format('MM/DD HH:mm') }}
|
||||
</div>
|
||||
<div class="brand-mine-card__meta" v-if="row.activityGroupName || row.trainType">
|
||||
<span class="brand-mine-card__tag" v-if="row.activityGroupName"><span class="brand-mine-card__tag-label">面向对象</span>{{ row.activityGroupName }}</span>
|
||||
<span class="brand-mine-card__tag" v-if="row.trainType"><span class="brand-mine-card__tag-label">活动类型</span>{{ row.trainType }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="brand-mine-card__actions">
|
||||
<button type="button" class="brand-mine-card__action" @click="onView(row)"><van-icon name="eye-o"></van-icon>查看介绍</button>
|
||||
<button type="button" class="brand-mine-card__action is-primary" @click="onApply(row)"><van-icon name="edit"></van-icon>查看报名</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-list>
|
||||
<div v-if="!loading && tableData.length === 0" class="brand-mine-empty">
|
||||
<img src="/assets/mobile/img/activity/culture-empty.png" alt="品牌活动报名空状态插画">
|
||||
<div class="brand-mine-empty__title">暂无报名记录</div>
|
||||
<div class="brand-mine-empty__hint">当前筛选条件下暂时没有已报名活动</div>
|
||||
</div>
|
||||
</van-pull-refresh>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<van-popup :style="{height: '100%', width: '100%'}" position="right" v-model="infoVisible">
|
||||
<div class="brand-mine-intro-page">
|
||||
<van-nav-bar title="活动介绍" left-text="返回" left-arrow @click-left="infoVisible = false"></van-nav-bar>
|
||||
<div class="brand-mine-intro-scroll">
|
||||
<div class="brand-mine-intro-hero">
|
||||
<div class="brand-mine-intro-hero__icon"><van-icon name="description"></van-icon></div>
|
||||
<div>
|
||||
<div class="brand-mine-intro-hero__title">活动报名须知</div>
|
||||
<div class="brand-mine-intro-hero__subtitle">请仔细阅读活动安排与报名要求</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="infoRow.introduce" class="brand-mine-intro-card" v-html="infoRow.introduce"></div>
|
||||
<div v-else class="brand-mine-intro-card">暂无活动介绍</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
loading: false,
|
||||
finished: false,
|
||||
refreshing: false,
|
||||
imageLoadErrors: {},
|
||||
filterOpened: false,
|
||||
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: {
|
||||
hasCover(row) {
|
||||
return !!(row && row.cover && String(row.cover).trim())
|
||||
},
|
||||
handleImageError(row) {
|
||||
this.$set(this.imageLoadErrors, row.id, true)
|
||||
},
|
||||
onView(row) {
|
||||
this.infoRow = row
|
||||
this.infoVisible = true
|
||||
},
|
||||
onApply(row) {
|
||||
this.$pjaxReplace('/platform/trainSignUp/apply/list/h5?id=' + row.id + '&dataType=mine')
|
||||
},
|
||||
onLoad() {
|
||||
if(!this.finished) {
|
||||
this.loadActivities(false)
|
||||
}
|
||||
},
|
||||
onRefresh() {
|
||||
this.loadActivities(true)
|
||||
},
|
||||
loadActivities(reset) {
|
||||
if(reset) {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.tableData = []
|
||||
this.finished = false
|
||||
this.imageLoadErrors = {}
|
||||
}
|
||||
this.loading = true
|
||||
this.$axios.post('/platform/trainSignUp/apply/activityPageData', this.pageForm).then((res) => {
|
||||
if(res.code === 0) {
|
||||
const list = res.data && res.data.list ? res.data.list : []
|
||||
this.tableData = this.pageForm.pageNumber === 1 ? list : this.tableData.concat(list)
|
||||
this.pageForm.totalCount = res.data && res.data.totalCount ? res.data.totalCount : 0
|
||||
this.finished = this.tableData.length >= this.pageForm.totalCount
|
||||
if(!this.finished) {
|
||||
this.pageForm.pageNumber++
|
||||
}
|
||||
}
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
this.refreshing = false
|
||||
})
|
||||
},
|
||||
doSearch() {
|
||||
this.loadActivities(true)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadActivities(true)
|
||||
}
|
||||
})
|
||||
</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,639 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style>
|
||||
body {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.works-mine-page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: calc(24px + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.works-mine-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.works-mine-page .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.works-mine-page .van-nav-bar .van-icon,
|
||||
.works-mine-page .van-nav-bar__text {
|
||||
color: #397fbd;
|
||||
}
|
||||
|
||||
.works-mine-content {
|
||||
padding: 12px 12px 0;
|
||||
}
|
||||
|
||||
.works-mine-hero {
|
||||
position: relative;
|
||||
height: 134px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
color: #fff;
|
||||
background-color: #247fe8;
|
||||
box-shadow: 0 8px 20px rgba(51, 117, 219, .18);
|
||||
}
|
||||
|
||||
.works-mine-hero__image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
|
||||
.works-mine-hero__copy {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
width: 66%;
|
||||
height: 100%;
|
||||
padding-left: 16px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
background: linear-gradient(90deg, rgba(22, 112, 232, .98) 0%, rgba(22, 112, 232, .88) 52%, rgba(22, 112, 232, 0) 100%);
|
||||
}
|
||||
|
||||
.works-mine-hero__title {
|
||||
font-size: 25px;
|
||||
line-height: 34px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.works-mine-hero__subtitle {
|
||||
margin-top: 4px;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
letter-spacing: .5px;
|
||||
opacity: .95;
|
||||
}
|
||||
|
||||
.works-mine-sticky {
|
||||
padding: 10px 0 1px;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.van-sticky--fixed .works-mine-sticky {
|
||||
padding-right: 12px;
|
||||
padding-left: 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.works-mine-search {
|
||||
margin-bottom: 8px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .1);
|
||||
}
|
||||
|
||||
.works-mine-search .van-search__content {
|
||||
height: 42px;
|
||||
padding-left: 12px;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.works-mine-filter {
|
||||
margin-bottom: 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .08);
|
||||
transition: border-radius .18s ease;
|
||||
}
|
||||
|
||||
.works-mine-filter.is-open {
|
||||
border-radius: 10px 10px 0 0;
|
||||
}
|
||||
|
||||
.works-mine-filter .van-dropdown-menu__bar {
|
||||
height: 44px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.works-mine-filter .van-dropdown-menu__item {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.works-mine-filter .van-dropdown-menu__title {
|
||||
width: auto;
|
||||
max-width: calc(100% - 24px);
|
||||
padding: 0 12px 0 0;
|
||||
overflow: hidden;
|
||||
color: #66758a;
|
||||
font-size: 14px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.works-mine-filter .van-dropdown-menu__title::after {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.works-mine-filter .van-dropdown-item__content {
|
||||
width: calc(100% - 24px);
|
||||
margin: 0 12px;
|
||||
overflow: hidden;
|
||||
border-radius: 0 0 12px 12px;
|
||||
box-shadow: 0 10px 24px rgba(31, 65, 108, .14);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.works-mine-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.works-mine-card {
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
}
|
||||
|
||||
.works-mine-card__cover,
|
||||
.works-mine-card__cover-state {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #edf4fc;
|
||||
}
|
||||
|
||||
.works-mine-card__cover {
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.works-mine-card__cover-state {
|
||||
flex-direction: column;
|
||||
row-gap: 8px;
|
||||
color: #8da1ba;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.works-mine-card__cover-state .van-icon {
|
||||
font-size: 34px;
|
||||
}
|
||||
|
||||
.works-mine-card__cover-state.is-error {
|
||||
color: #c27b75;
|
||||
background-color: #fff3f1;
|
||||
}
|
||||
|
||||
.works-mine-card__body {
|
||||
padding: 12px 14px 14px;
|
||||
}
|
||||
|
||||
.works-mine-card__title {
|
||||
overflow: hidden;
|
||||
color: #303846;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.works-mine-card__activity,
|
||||
.works-mine-card__time {
|
||||
margin-top: 4px;
|
||||
overflow: hidden;
|
||||
color: #8794a7;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.works-mine-card__meta {
|
||||
display: flex;
|
||||
margin-top: 10px;
|
||||
padding-top: 9px;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
border-top: 1px solid #edf1f6;
|
||||
}
|
||||
|
||||
.works-mine-card__tag {
|
||||
display: inline-flex;
|
||||
padding: 3px 8px;
|
||||
border-radius: 4px;
|
||||
color: #397de0;
|
||||
background-color: #edf5ff;
|
||||
font-size: 11px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.works-mine-card__tag-label {
|
||||
margin-right: 4px;
|
||||
color: #8aa7cf;
|
||||
}
|
||||
|
||||
.works-mine-card__actions {
|
||||
display: flex;
|
||||
padding: 12px 14px;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
border-top: 1px solid #edf1f6;
|
||||
background-color: #f8fbff;
|
||||
}
|
||||
|
||||
.works-mine-card__action {
|
||||
display: inline-flex;
|
||||
min-width: 72px;
|
||||
height: 32px;
|
||||
padding: 0 12px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 0;
|
||||
border-radius: 16px;
|
||||
color: #397de0;
|
||||
background-color: #edf5ff;
|
||||
font-size: 13px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.works-mine-card__action .van-icon {
|
||||
margin-right: 5px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.works-mine-card__action.is-primary {
|
||||
color: #fff;
|
||||
background-color: #1989fa;
|
||||
box-shadow: 0 5px 12px rgba(25, 137, 250, .18);
|
||||
}
|
||||
|
||||
.works-mine-card__action.is-danger {
|
||||
color: #e45c5c;
|
||||
background-color: #fff0f0;
|
||||
}
|
||||
|
||||
.works-mine-skeleton {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.works-mine-skeleton__card {
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
}
|
||||
|
||||
.works-mine-skeleton__cover,
|
||||
.works-mine-skeleton__body .van-skeleton,
|
||||
.works-mine-skeleton__actions .van-skeleton {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.works-mine-skeleton__cover .van-skeleton__row {
|
||||
width: 100% !important;
|
||||
height: 150px;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.works-mine-skeleton__body {
|
||||
padding: 13px 14px 14px;
|
||||
}
|
||||
|
||||
.works-mine-skeleton__body .van-skeleton__title {
|
||||
width: 52%;
|
||||
height: 15px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.works-mine-skeleton__body .van-skeleton__row {
|
||||
height: 12px;
|
||||
margin-top: 9px;
|
||||
}
|
||||
|
||||
.works-mine-skeleton__body .van-skeleton__row:last-child {
|
||||
width: 58%;
|
||||
}
|
||||
|
||||
.works-mine-skeleton__actions {
|
||||
padding: 12px 14px;
|
||||
border-top: 1px solid #edf1f6;
|
||||
background-color: #f8fbff;
|
||||
}
|
||||
|
||||
.works-mine-skeleton__actions .van-skeleton__row {
|
||||
width: 72%;
|
||||
height: 32px;
|
||||
margin: 0 0 0 auto;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.works-mine-empty {
|
||||
display: flex;
|
||||
min-height: 260px;
|
||||
padding: 26px 18px 32px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.works-mine-empty img {
|
||||
width: 82%;
|
||||
max-width: 280px;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.works-mine-empty__title {
|
||||
margin-top: 14px;
|
||||
color: #50627a;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.works-mine-empty__hint {
|
||||
margin-top: 5px;
|
||||
color: #9aa7b8;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<div class="works-mine-page">
|
||||
<van-nav-bar title="我的作品" left-text="返回" left-arrow fixed placeholder @click-left="handlePageBack"></van-nav-bar>
|
||||
|
||||
<div class="works-mine-content">
|
||||
<section class="works-mine-hero">
|
||||
<img class="works-mine-hero__image" src="/assets/mobile/img/activity/hero/brand-hero-v2.png" alt="我的作品插画">
|
||||
<div class="works-mine-hero__copy">
|
||||
<div class="works-mine-hero__title">我的作品</div>
|
||||
<div class="works-mine-hero__subtitle">作品征集 · 提交记录</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<van-sticky :offset-top="46">
|
||||
<div class="works-mine-sticky">
|
||||
<van-search v-model="pageForm.searchKeyword" class="works-mine-search" placeholder="搜索作品或征集活动"
|
||||
shape="round" clearable @search="doSearch" @clear="doSearch"></van-search>
|
||||
<van-dropdown-menu class="works-mine-filter" :class="{'is-open': filterOpened}" active-color="#1989fa">
|
||||
<year-van-dropdown-item :num="5" v-model="pageForm.year" @change="doSearch"
|
||||
@open="onFilterOpen" @close="onFilterClose"></year-van-dropdown-item>
|
||||
<van-dropdown-item v-model="pageForm.activityType" :options="typeOptions" :multiple="false"
|
||||
@change="doSearch" @open="onFilterOpen" @close="onFilterClose"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</div>
|
||||
</van-sticky>
|
||||
|
||||
<div v-if="skeletonLoading" class="works-mine-skeleton">
|
||||
<div v-for="index in 3" :key="'mine-skeleton-' + index" class="works-mine-skeleton__card">
|
||||
<van-skeleton class="works-mine-skeleton__cover" :row="1" animated></van-skeleton>
|
||||
<div class="works-mine-skeleton__body">
|
||||
<van-skeleton title :row="3" animated></van-skeleton>
|
||||
</div>
|
||||
<div class="works-mine-skeleton__actions">
|
||||
<van-skeleton :row="1" animated></van-skeleton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<van-pull-refresh v-show="!skeletonLoading" v-model="refreshing" @refresh="onRefresh">
|
||||
<van-list v-model="loading" :finished="finished" :immediate-check="false" @load="onLoad">
|
||||
<div class="works-mine-list">
|
||||
<article v-for="row in tableData" :key="row.id" class="works-mine-card">
|
||||
<img v-if="hasCover(row) && !imageLoadErrors[row.id]" class="works-mine-card__cover"
|
||||
:src="row.cover" :alt="row.activityName" @error="handleImageError(row)">
|
||||
<div v-else class="works-mine-card__cover-state" :class="{'is-error': hasCover(row)}">
|
||||
<van-icon name="photo-o"></van-icon>
|
||||
<span>{{hasCover(row) ? '图片加载失败' : '暂无图片'}}</span>
|
||||
</div>
|
||||
<div class="works-mine-card__body">
|
||||
<div class="works-mine-card__title">{{row.name}}</div>
|
||||
<div class="works-mine-card__activity">所属活动:{{row.activityName || '暂无活动信息'}}</div>
|
||||
<div class="works-mine-card__time" v-if="row.createdAt">
|
||||
提交时间:{{$moment(row.createdAt).format('YYYY-MM-DD HH:mm')}}
|
||||
</div>
|
||||
<div class="works-mine-card__meta" v-if="row.subjectName || row.worksName">
|
||||
<span class="works-mine-card__tag" v-if="row.subjectName">
|
||||
<span class="works-mine-card__tag-label">主题</span>{{row.subjectName}}
|
||||
</span>
|
||||
<span class="works-mine-card__tag" v-if="row.worksName">
|
||||
<span class="works-mine-card__tag-label">类型</span>{{row.worksName}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="works-mine-card__actions">
|
||||
<button type="button" class="works-mine-card__action" @click="onView(row)">
|
||||
<van-icon name="eye-o"></van-icon>查看
|
||||
</button>
|
||||
<button type="button" class="works-mine-card__action" @click="onEdit(row)">
|
||||
<van-icon name="edit"></van-icon>编辑
|
||||
</button>
|
||||
<button type="button" class="works-mine-card__action is-danger" @click="onDelete(row)">
|
||||
<van-icon name="delete-o"></van-icon>删除
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</van-list>
|
||||
<div v-if="!loading && tableData.length === 0" class="works-mine-empty">
|
||||
<img src="/assets/mobile/img/activity/culture-empty.png" alt="作品记录空状态插画">
|
||||
<div class="works-mine-empty__title">暂无作品记录</div>
|
||||
<div class="works-mine-empty__hint">当前筛选条件下暂时没有已提交作品</div>
|
||||
</div>
|
||||
</van-pull-refresh>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<van-dialog title="删除确认" message="确认删除当前作品吗?" :value="deleteConfirmVisible"
|
||||
:close-on-click-overlay="false" show-cancel-button cancel-button-text="取消" confirm-button-text="确认删除"
|
||||
@cancel="closeDeleteConfirm" @confirm="confirmDelete"></van-dialog>
|
||||
|
||||
<apply-form ref="applyFormRef" @submit-success="handleEditSubmitSuccess"></apply-form>
|
||||
<info ref="infoRef"></info>
|
||||
</div>
|
||||
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('../upload/applyForm.js'){}#-->
|
||||
<!--#include('info.js'){}#-->
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
'apply-form': applyForm,
|
||||
'info': INFO,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
loading: false,
|
||||
skeletonLoading: true,
|
||||
finished: false,
|
||||
refreshing: false,
|
||||
imageLoadErrors: {},
|
||||
filterOpened: false,
|
||||
deleteConfirmVisible: false,
|
||||
deleteLoading: false,
|
||||
pendingDeleteRow: {},
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
searchKeyword: '',
|
||||
year: new Date().getFullYear(),
|
||||
activityType: 1,
|
||||
},
|
||||
typeOptions: [
|
||||
{text: '全部', value: 1},
|
||||
{text: '征集中', value: 2},
|
||||
{text: '已结束', value: 3},
|
||||
],
|
||||
historyLayerPageKey: 'works-collection-mine-h5',
|
||||
historyLayerUnsubscribe: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
hasCover(row) {
|
||||
return !!(row && row.cover && String(row.cover).trim())
|
||||
},
|
||||
handleImageError(row) {
|
||||
this.$set(this.imageLoadErrors, row.id, true)
|
||||
},
|
||||
onFilterOpen() {
|
||||
this.$set(this, 'filterOpened', true)
|
||||
},
|
||||
onFilterClose() {
|
||||
this.$set(this, 'filterOpened', false)
|
||||
},
|
||||
handlePageBack() {
|
||||
if (window.h5HistoryLayerManager.stack.length) {
|
||||
window.h5HistoryLayerManager.close()
|
||||
return
|
||||
}
|
||||
this.historyBack()
|
||||
},
|
||||
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)
|
||||
},
|
||||
// 编辑提交成功后留在我的作品页面,仅刷新当前列表数据。
|
||||
handleEditSubmitSuccess() {
|
||||
this.loadWorks(true)
|
||||
},
|
||||
onDelete(row) {
|
||||
this.$set(this, 'pendingDeleteRow', row)
|
||||
window.h5HistoryLayerManager.open('works-collection-mine-delete-confirm')
|
||||
},
|
||||
closeDeleteConfirm() {
|
||||
window.h5HistoryLayerManager.close('works-collection-mine-delete-confirm')
|
||||
},
|
||||
confirmDelete() {
|
||||
const row = this.pendingDeleteRow
|
||||
window.h5HistoryLayerManager.close('works-collection-mine-delete-confirm', () => {
|
||||
this.deleteRow(row)
|
||||
})
|
||||
},
|
||||
// 删除接口接收作品 id,成功后重置分页列表;接口返回 Result JSON。
|
||||
deleteRow(row) {
|
||||
if (!row || !row.id || this.deleteLoading) return
|
||||
this.$set(this, 'deleteLoading', true)
|
||||
this.$axios.post('/platform/activity/worksCollection/upload/delete', {id: row.id}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$toast.success(res.msg || '删除成功')
|
||||
this.loadWorks(true)
|
||||
}
|
||||
}).finally(() => {
|
||||
this.$set(this, 'deleteLoading', false)
|
||||
})
|
||||
},
|
||||
onLoad() {
|
||||
if (!this.finished) this.loadWorks(false)
|
||||
},
|
||||
onRefresh() {
|
||||
this.loadWorks(true)
|
||||
},
|
||||
/**
|
||||
* 加载当前用户作品分页数据。
|
||||
* reset 为 true 时从第一页重新查询;接口返回 Pagination,list 为作品数组、totalCount 为总数。
|
||||
*/
|
||||
loadWorks(reset) {
|
||||
const showSkeleton = !!reset
|
||||
if (reset) {
|
||||
this.$set(this, 'skeletonLoading', true)
|
||||
this.$set(this.pageForm, 'pageNumber', 1)
|
||||
this.$set(this.pageForm, 'totalCount', 0)
|
||||
this.$set(this, 'tableData', [])
|
||||
this.$set(this, 'finished', false)
|
||||
this.$set(this, 'imageLoadErrors', {})
|
||||
}
|
||||
this.$set(this, 'loading', true)
|
||||
this.$axios.post('/platform/activity/worksCollection/upload/pageData', this.pageForm, {
|
||||
h5SkeletonLoading: showSkeleton
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
const list = res.data && res.data.list ? res.data.list : []
|
||||
this.$set(this, 'tableData', this.pageForm.pageNumber === 1 ? list : this.tableData.concat(list))
|
||||
this.$set(this.pageForm, 'totalCount', res.data && res.data.totalCount ? res.data.totalCount : 0)
|
||||
this.$set(this, 'finished', this.tableData.length >= this.pageForm.totalCount)
|
||||
if (!this.finished) {
|
||||
this.$set(this.pageForm, 'pageNumber', this.pageForm.pageNumber + 1)
|
||||
}
|
||||
}
|
||||
}).finally(() => {
|
||||
this.$set(this, 'loading', false)
|
||||
this.$set(this, 'refreshing', false)
|
||||
if (showSkeleton) this.$set(this, 'skeletonLoading', false)
|
||||
})
|
||||
},
|
||||
doSearch() {
|
||||
this.loadWorks(true)
|
||||
},
|
||||
syncHistoryLayers(stack) {
|
||||
this.$set(this, 'deleteConfirmVisible', stack.includes('works-collection-mine-delete-confirm'))
|
||||
}
|
||||
},
|
||||
created() {
|
||||
window.h5HistoryLayerManager.register(this.historyLayerPageKey, (stack) => {
|
||||
this.syncHistoryLayers(stack)
|
||||
})
|
||||
this.$set(this, 'historyLayerUnsubscribe', window.h5HistoryLayerManager.subscribe((stack) => {
|
||||
this.syncHistoryLayers(stack)
|
||||
}))
|
||||
this.loadWorks(true)
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.historyLayerUnsubscribe) this.historyLayerUnsubscribe()
|
||||
window.h5HistoryLayerManager.unregister(this.historyLayerPageKey)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,197 @@
|
||||
const INFO = {
|
||||
template: /*language=HTML*/
|
||||
`
|
||||
<div>
|
||||
<van-popup class="works-detail-popup" :style="{height: '100%', width: '100%'}" position="right"
|
||||
safe-area-inset-bottom :close-on-click-overlay="false" v-model="visible">
|
||||
<div class="works-detail-page">
|
||||
<van-sticky>
|
||||
<van-nav-bar title="作品详情" left-text="返回" left-arrow @click-left="closeInfo"></van-nav-bar>
|
||||
</van-sticky>
|
||||
<div ref="detailScrollRef" class="works-detail-scroll">
|
||||
<section class="works-detail-card">
|
||||
<h2 class="works-detail-card__title">基础信息</h2>
|
||||
<van-cell-group :border="false">
|
||||
<van-cell title="姓名" :value="viewData.userName || '-' "></van-cell>
|
||||
<van-cell title="工号" :value="viewData.loginName || '-' "></van-cell>
|
||||
<van-cell title="单位" :value="viewData.unitName || '-' "></van-cell>
|
||||
<van-cell title="分工会" :value="viewData.unionName || '-' "></van-cell>
|
||||
</van-cell-group>
|
||||
</section>
|
||||
|
||||
<section class="works-detail-card">
|
||||
<h2 class="works-detail-card__title">作品信息</h2>
|
||||
<van-cell-group :border="false">
|
||||
<van-cell title="所属活动" :value="viewData.activityName || '-' "></van-cell>
|
||||
<van-cell title="主题类型" :value="viewData.subjectName || '-' "></van-cell>
|
||||
<van-cell title="作品类型" :value="viewData.worksName || '-' "></van-cell>
|
||||
<van-cell title="作品名称" :value="viewData.name || '-' "></van-cell>
|
||||
</van-cell-group>
|
||||
</section>
|
||||
|
||||
<section class="works-detail-card">
|
||||
<h2 class="works-detail-card__title">作品描述</h2>
|
||||
<div class="works-detail-description">{{viewData.description || '暂无作品描述'}}</div>
|
||||
</section>
|
||||
|
||||
<section class="works-detail-card">
|
||||
<h2 class="works-detail-card__title">作品附件</h2>
|
||||
<div v-if="viewData.files && viewData.files.length" class="works-detail-files">
|
||||
<file-preview :files="viewData.files" complete_result></file-preview>
|
||||
</div>
|
||||
<div v-else class="works-detail-empty">暂无作品附件</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</div>
|
||||
`,
|
||||
style: /*language=CSS*/ `
|
||||
/deep/ .works-detail-popup,
|
||||
/deep/ .works-detail-page {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
/deep/ .works-detail-page {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/deep/ .works-detail-page .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/deep/ .works-detail-page .van-nav-bar .van-icon,
|
||||
/deep/ .works-detail-page .van-nav-bar__text {
|
||||
color: #397fbd;
|
||||
}
|
||||
|
||||
/deep/ .works-detail-scroll {
|
||||
height: calc(100vh - 46px);
|
||||
padding: 12px 12px calc(24px + env(safe-area-inset-bottom));
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/deep/ .works-detail-card {
|
||||
margin-top: 12px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #e9eff7;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
}
|
||||
|
||||
/deep/ .works-detail-scroll > .works-detail-card:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/deep/ .works-detail-card__title {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 13px 14px 9px 22px;
|
||||
color: #354255;
|
||||
font-size: 15px;
|
||||
line-height: 21px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/deep/ .works-detail-card__title::before {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
bottom: 12px;
|
||||
left: 12px;
|
||||
width: 2px;
|
||||
border-radius: 2px;
|
||||
background-color: #1989fa;
|
||||
content: "";
|
||||
}
|
||||
|
||||
/deep/ .works-detail-card .van-cell {
|
||||
padding: 10px 14px;
|
||||
color: #596779;
|
||||
}
|
||||
|
||||
/deep/ .works-detail-card .van-cell__title {
|
||||
flex: 0 0 82px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/deep/ .works-detail-card .van-cell__value {
|
||||
color: #4f5d70;
|
||||
font-size: 14px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/deep/ .works-detail-description,
|
||||
/deep/ .works-detail-files,
|
||||
/deep/ .works-detail-empty {
|
||||
padding: 4px 14px 16px;
|
||||
color: #536174;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/deep/ .works-detail-empty {
|
||||
color: #9aa7b8;
|
||||
}
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
viewData: {},
|
||||
visible: false,
|
||||
historyLayerUnsubscribe: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 查询并打开作品详情。
|
||||
* row 需传作品 id;接口返回作品、活动、主题、类型及附件信息的 Result JSON。
|
||||
*/
|
||||
onOpen(row) {
|
||||
this.$set(this, "viewData", Object.assign({}, row, {files: this.normalizeFiles(row.files)}))
|
||||
window.h5HistoryLayerManager.open("works-collection-mine-info")
|
||||
this.resetScrollPosition()
|
||||
this.$axios.post("/platform/activity/worksCollection/common/findOne", {id: row.id}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
const viewData = res.data || {}
|
||||
viewData.files = this.normalizeFiles(viewData.files)
|
||||
this.$set(this, "viewData", viewData)
|
||||
}
|
||||
})
|
||||
},
|
||||
// 弹窗组件会被复用,每次打开后需清除上一次查看时保留的滚动位置。
|
||||
resetScrollPosition() {
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.detailScrollRef) this.$refs.detailScrollRef.scrollTop = 0
|
||||
})
|
||||
},
|
||||
normalizeFiles(files) {
|
||||
if (Array.isArray(files)) return files
|
||||
if (!files) return []
|
||||
try {
|
||||
const result = JSON.parse(files)
|
||||
return Array.isArray(result) ? result : []
|
||||
} catch (err) {
|
||||
return []
|
||||
}
|
||||
},
|
||||
closeInfo() {
|
||||
window.h5HistoryLayerManager.close("works-collection-mine-info")
|
||||
},
|
||||
syncHistoryLayers(stack) {
|
||||
this.$set(this, "visible", stack.includes("works-collection-mine-info"))
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$set(this, "historyLayerUnsubscribe", window.h5HistoryLayerManager.subscribe((stack) => {
|
||||
this.syncHistoryLayers(stack)
|
||||
}))
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.historyLayerUnsubscribe) this.historyLayerUnsubscribe()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,667 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style>
|
||||
body {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.works-read-page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: calc(24px + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.works-read-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.works-read-page .van-nav-bar__title {
|
||||
color: #172033;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.works-read-page .van-nav-bar .van-icon,
|
||||
.works-read-page .van-nav-bar__text {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.works-read-sticky {
|
||||
padding: 22px 12px 1px;
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.works-read-search {
|
||||
margin: 0 0 8px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .1);
|
||||
}
|
||||
|
||||
.works-read-search .van-search__content {
|
||||
height: 42px;
|
||||
padding-left: 12px;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.works-read-search .van-field__control {
|
||||
color: #263548;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.works-read-search .van-field__control::placeholder {
|
||||
color: #a7b0bf;
|
||||
}
|
||||
|
||||
.works-read-filter {
|
||||
margin: 0 0 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .08);
|
||||
transition: border-radius .18s ease;
|
||||
}
|
||||
|
||||
.works-read-filter.is-open {
|
||||
border-radius: 10px 10px 0 0;
|
||||
}
|
||||
|
||||
.works-read-filter .van-dropdown-menu__bar {
|
||||
height: 44px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.works-read-filter .van-dropdown-menu__item {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.works-read-filter .van-dropdown-menu__title {
|
||||
width: auto;
|
||||
max-width: calc(100% - 24px);
|
||||
padding: 0 12px 0 0;
|
||||
overflow: hidden;
|
||||
color: #66758a;
|
||||
font-size: 14px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.works-read-filter .van-dropdown-menu__title::after {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.works-read-filter .van-dropdown-item__content {
|
||||
width: calc(100% - 24px);
|
||||
margin: 0 12px;
|
||||
overflow: hidden;
|
||||
border-radius: 0 0 12px 12px;
|
||||
box-shadow: 0 10px 24px rgba(31, 65, 108, .14);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.works-read-content {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.works-read-list .empty-state {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.works-read-skeleton {
|
||||
padding-top: 12px;
|
||||
}
|
||||
|
||||
.works-read-skeleton__card {
|
||||
margin-bottom: 12px;
|
||||
padding: 14px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #eef1f6;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.works-read-skeleton__card .van-skeleton {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.works-read-skeleton__card .van-skeleton__title {
|
||||
width: 42%;
|
||||
height: 16px;
|
||||
margin-bottom: 13px;
|
||||
}
|
||||
|
||||
.works-read-skeleton__card .van-skeleton__row {
|
||||
height: 12px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.works-read-skeleton__card .van-skeleton__row:nth-child(2n) {
|
||||
width: 72%;
|
||||
}
|
||||
|
||||
.works-read-skeleton__card .van-skeleton__row:last-child {
|
||||
width: 48%;
|
||||
height: 28px;
|
||||
margin-top: 16px;
|
||||
border-radius: 14px;
|
||||
}
|
||||
|
||||
.works-read-empty {
|
||||
display: flex;
|
||||
min-height: 280px;
|
||||
padding: 46px 18px 36px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.works-read-empty img {
|
||||
display: block;
|
||||
width: 86%;
|
||||
max-width: 290px;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.works-read-empty__title {
|
||||
margin-top: 14px;
|
||||
color: #50627a;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.works-read-empty__hint {
|
||||
margin-top: 5px;
|
||||
color: #9aa7b8;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.works-read-card-header {
|
||||
display: flex;
|
||||
margin-bottom: 7px;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.works-read-card-heading {
|
||||
min-width: 0;
|
||||
padding-right: 10px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.works-read-card-title {
|
||||
overflow: hidden;
|
||||
color: #253247;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.works-read-card-activity {
|
||||
margin-top: 1px;
|
||||
overflow: hidden;
|
||||
color: #9ba6b6;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.works-read-like-summary {
|
||||
display: inline-flex;
|
||||
min-height: 24px;
|
||||
align-items: center;
|
||||
flex: none;
|
||||
color: #7f8da1;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
white-space: nowrap;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 顶部仅展示累计点赞信息,人员图标与无底色文字用于区别底部可点击的点赞按钮。 */
|
||||
.works-read-like-summary .van-icon {
|
||||
display: inline-flex;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 5px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
color: #ffffff;
|
||||
background-color: #8795aa;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.works-read-files-row {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
margin-top: 8px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid #edf1f6;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.works-read-files-label {
|
||||
display: flex;
|
||||
margin-bottom: 7px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
color: #98a3b3;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.works-read-files-hint {
|
||||
flex: none;
|
||||
color: #7893af;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.works-read-files-scroll {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.works-read-files-scroll::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.works-read-list .works-read-files-scroll .file-preview-container {
|
||||
display: flex !important;
|
||||
width: max-content;
|
||||
min-width: 100%;
|
||||
padding: 0;
|
||||
grid-template-columns: none !important;
|
||||
gap: 8px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.works-read-list .works-read-files-scroll .file-preview-container .file-item {
|
||||
width: 88px;
|
||||
height: 88px;
|
||||
flex: 0 0 88px;
|
||||
aspect-ratio: auto;
|
||||
}
|
||||
|
||||
.works-read-action-icon {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.works-read-like-action-wrap {
|
||||
position: relative;
|
||||
display: flex;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.works-read-like-hearts {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
bottom: 24px;
|
||||
left: 50%;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.works-read-like-heart {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
color: #ee3f4d;
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
opacity: 0;
|
||||
text-shadow: 0 3px 8px rgba(238, 63, 77, .32);
|
||||
animation: works-read-heart-bubble 1s ease-out forwards;
|
||||
}
|
||||
|
||||
.works-read-like-heart.is-heart-1 {
|
||||
--heart-x: -26px;
|
||||
--heart-y: -62px;
|
||||
font-size: 15px;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
.works-read-like-heart.is-heart-2 {
|
||||
--heart-x: -11px;
|
||||
--heart-y: -82px;
|
||||
font-size: 21px;
|
||||
animation-delay: .08s;
|
||||
}
|
||||
|
||||
.works-read-like-heart.is-heart-3 {
|
||||
--heart-x: 7px;
|
||||
--heart-y: -68px;
|
||||
font-size: 14px;
|
||||
animation-delay: .16s;
|
||||
}
|
||||
|
||||
.works-read-like-heart.is-heart-4 {
|
||||
--heart-x: 24px;
|
||||
--heart-y: -88px;
|
||||
font-size: 18px;
|
||||
animation-delay: .24s;
|
||||
}
|
||||
|
||||
.works-read-like-heart.is-heart-5 {
|
||||
--heart-x: -18px;
|
||||
--heart-y: -102px;
|
||||
font-size: 13px;
|
||||
animation-delay: .32s;
|
||||
}
|
||||
|
||||
.works-read-like-heart.is-heart-6 {
|
||||
--heart-x: 15px;
|
||||
--heart-y: -108px;
|
||||
font-size: 16px;
|
||||
animation-delay: .4s;
|
||||
}
|
||||
|
||||
@keyframes works-read-heart-bubble {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, 5px) scale(.35);
|
||||
}
|
||||
20% {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -8px) scale(1.15);
|
||||
}
|
||||
62% {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -42px) scale(1);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translate(calc(-50% + var(--heart-x)), var(--heart-y)) scale(.72);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 350px) {
|
||||
.works-read-content,
|
||||
.works-read-sticky {
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<div class="works-read-page">
|
||||
<van-nav-bar title="作品阅览" left-text="返回" left-arrow placeholder fixed
|
||||
@click-left="handlePageBack"></van-nav-bar>
|
||||
|
||||
<van-sticky :offset-top="46">
|
||||
<div class="works-read-sticky">
|
||||
<van-search v-model="pageForm.searchKeyword" class="works-read-search"
|
||||
placeholder="请输入姓名或工号搜索" shape="round" clearable
|
||||
@search="doSearch" @clear="doSearch"></van-search>
|
||||
<van-dropdown-menu class="works-read-filter" :class="{'is-open': filterOpened}" active-color="#1989fa">
|
||||
<van-dropdown-item v-model="pageForm.activityId" :options="activityOptions" :multiple="false"
|
||||
@change="doSearch" @open="onFilterOpen" @close="onFilterClose"></van-dropdown-item>
|
||||
<van-dropdown-item v-model="pageForm.pageOrderName" :options="orderOptions" :multiple="false"
|
||||
@change="doSearch" @open="onFilterOpen" @close="onFilterClose"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</div>
|
||||
</van-sticky>
|
||||
|
||||
<main class="works-read-content">
|
||||
<div class="works-read-list">
|
||||
<div v-if="skeletonLoading" class="works-read-skeleton">
|
||||
<div v-for="index in 3" :key="'read-skeleton-' + index" class="works-read-skeleton__card">
|
||||
<van-skeleton title :row="5" animated></van-skeleton>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!skeletonLoading && pageForm.totalCount === 0" class="works-read-empty">
|
||||
<img src="/assets/mobile/img/activity/culture-empty.png" alt="暂无作品记录插画">
|
||||
<div class="works-read-empty__title">暂无作品记录</div>
|
||||
<div class="works-read-empty__hint">当前筛选条件下暂时没有可阅览作品</div>
|
||||
</div>
|
||||
<table-list api="/platform/activity/worksCollection/read/h5/pageData"
|
||||
:page_form.sync="pageForm" ref="tableListRef" title="name" v-show="!skeletonLoading"
|
||||
:show_loading_overlay="false" @ready="onReady" @loading-change="handleListLoadingChange">
|
||||
<template #header="{index,row}">
|
||||
<div class="works-read-card-header">
|
||||
<div class="works-read-card-heading">
|
||||
<div class="works-read-card-title">{{row.name || '未命名作品'}}</div>
|
||||
<div class="works-read-card-activity">{{row.activityName || '暂无活动信息'}}</div>
|
||||
</div>
|
||||
<div class="works-read-like-summary">
|
||||
<van-icon name="friends"></van-icon>
|
||||
<span>已有 {{row.num || 0}} 人点赞</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot="{index,row}">
|
||||
<table-column label="作品类型">{{row.worksName || '--'}}</table-column>
|
||||
<table-column label="作者">{{row.userName || '--'}}</table-column>
|
||||
<table-column label="工号">{{row.loginName || '--'}}</table-column>
|
||||
<table-column label="上传时间">{{$moment(row.createdAt).format('YYYY-MM-DD')}}</table-column>
|
||||
<div v-if="hasListFiles(row.files)" class="works-read-files-row">
|
||||
<div class="works-read-files-label">
|
||||
<span>上传附件</span>
|
||||
<span v-if="getAttachmentCount(row.files) > 1" class="works-read-files-hint">
|
||||
共{{getAttachmentCount(row.files)}}个附件 · 左滑查看更多
|
||||
</span>
|
||||
</div>
|
||||
<div class="works-read-files-scroll">
|
||||
<file-preview :files="row.files" complete_result></file-preview>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row)">
|
||||
<van-icon class="works-read-action-icon" name="eye-o"></van-icon>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div v-if="row.nbCount > 0" class="works-read-like-action-wrap">
|
||||
<div class="action-btn" v-if="!row.isThisLike" @click="onLike(row)">
|
||||
<van-icon class="works-read-action-icon" name="good-job-o"></van-icon>
|
||||
<span>点赞</span>
|
||||
</div>
|
||||
<div class="action-btn delete" v-else @click="onDeleteLike(row)">
|
||||
<van-icon class="works-read-action-icon" name="good-job"></van-icon>
|
||||
<span>取消点赞</span>
|
||||
</div>
|
||||
<span v-if="likeHeartEffects[row.id]"
|
||||
:key="'like-heart-' + row.id + '-' + (likeHeartEffectKeys[row.id] || 0)"
|
||||
class="works-read-like-hearts" aria-hidden="true">
|
||||
<span v-for="heartIndex in 6" :key="heartIndex"
|
||||
class="works-read-like-heart" :class="'is-heart-' + heartIndex">♥</span>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</table-list>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<info ref="infoRef"></info>
|
||||
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('../mine/info.js'){}#-->
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
'info': INFO,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
searchKeyword: '',
|
||||
pageOrderName: 'createdAt',
|
||||
activityId: '',
|
||||
year: new Date().getFullYear(),
|
||||
},
|
||||
activityOptions: [],
|
||||
orderOptions: [
|
||||
{text: '按上传时间排序', value: 'createdAt'},
|
||||
{text: '按点赞数量排序', value: 'num'},
|
||||
],
|
||||
filterOpened: false,
|
||||
likeLoading: false,
|
||||
likeHeartEffects: {},
|
||||
likeHeartEffectKeys: {},
|
||||
likeHeartEffectTimers: {},
|
||||
skeletonLoading: true,
|
||||
historyLayerPageKey: 'works-collection-read-h5',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// state.initial 表示查询前列表为空,仅在首次或重置查询时显示整组卡片骨架。
|
||||
handleListLoadingChange(state) {
|
||||
if (state.initial) this.$set(this, 'skeletonLoading', state.loading)
|
||||
},
|
||||
// 判断列表附件是否包含有效记录;files 支持上传组件保存的 JSON 字符串或数组。
|
||||
hasListFiles(files) {
|
||||
if (Array.isArray(files)) return files.length > 0
|
||||
if (!files) return false
|
||||
try {
|
||||
const fileList = JSON.parse(files)
|
||||
return Array.isArray(fileList) && fileList.length > 0
|
||||
} catch (err) {
|
||||
return false
|
||||
}
|
||||
},
|
||||
// 获取当前作品的全部附件数量;files 支持 JSON 字符串或数组,返回 Number 类型。
|
||||
getAttachmentCount(files) {
|
||||
if (Array.isArray(files)) return files.length
|
||||
if (!files) return 0
|
||||
try {
|
||||
const fileList = JSON.parse(files)
|
||||
return Array.isArray(fileList) ? fileList.length : 0
|
||||
} catch (err) {
|
||||
return 0
|
||||
}
|
||||
},
|
||||
onLike(row) {
|
||||
this.executeLikeAction(row, 'like')
|
||||
},
|
||||
onDeleteLike(row) {
|
||||
this.executeLikeAction(row, 'cancel')
|
||||
},
|
||||
/**
|
||||
* 执行作品点赞或取消点赞。
|
||||
* row 需包含作品 id,action 传 like 或 cancel;接口返回 Result JSON,方法无返回值。
|
||||
*/
|
||||
executeLikeAction(row, action) {
|
||||
if (!row || !row.id || this.likeLoading) return
|
||||
const isCancel = action === 'cancel'
|
||||
const url = isCancel
|
||||
? '/platform/activity/worksCollection/read/h5/doDeleteLike'
|
||||
: '/platform/activity/worksCollection/read/h5/doLike'
|
||||
this.$set(this, 'likeLoading', true)
|
||||
this.$axios.post(url, {uploadId: row.id}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
const currentNum = Number(row.num) || 0
|
||||
this.$set(row, 'num', isCancel ? Math.max(currentNum - 1, 0) : currentNum + 1)
|
||||
this.$set(row, 'isThisLike', !isCancel)
|
||||
if (!isCancel) this.playLikeHeart(row.id)
|
||||
}
|
||||
}).finally(() => {
|
||||
this.$set(this, 'likeLoading', false)
|
||||
})
|
||||
},
|
||||
// 点赞成功后为当前作品播放多颗红色爱心错峰上浮动画,重复触发时重新开始计时。
|
||||
playLikeHeart(rowId) {
|
||||
if (!rowId) return
|
||||
if (this.likeHeartEffectTimers[rowId]) {
|
||||
clearTimeout(this.likeHeartEffectTimers[rowId])
|
||||
}
|
||||
this.$set(this.likeHeartEffects, rowId, false)
|
||||
this.$set(this.likeHeartEffectKeys, rowId, (this.likeHeartEffectKeys[rowId] || 0) + 1)
|
||||
this.$nextTick(() => {
|
||||
this.$set(this.likeHeartEffects, rowId, true)
|
||||
const timer = setTimeout(() => {
|
||||
this.$set(this.likeHeartEffects, rowId, false)
|
||||
this.$delete(this.likeHeartEffectTimers, rowId)
|
||||
}, 1400)
|
||||
this.$set(this.likeHeartEffectTimers, rowId, timer)
|
||||
})
|
||||
},
|
||||
onView(row) {
|
||||
this.$refs.infoRef.onOpen(row)
|
||||
},
|
||||
onFilterOpen() {
|
||||
this.$set(this, 'filterOpened', true)
|
||||
},
|
||||
onFilterClose() {
|
||||
this.$set(this, 'filterOpened', false)
|
||||
},
|
||||
handlePageBack() {
|
||||
if (window.h5HistoryLayerManager.stack.length) {
|
||||
window.h5HistoryLayerManager.close()
|
||||
return
|
||||
}
|
||||
this.historyBack()
|
||||
},
|
||||
// 活动接口接收年度,返回 id、name 组成的活动列表;完成后触发首次作品查询。
|
||||
listActivity() {
|
||||
return this.$axios.post('/platform/activity/worksCollection/common/listActivity', {
|
||||
year: this.pageForm.year
|
||||
}, {
|
||||
h5SkeletonLoading: true
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
const options = (res.data || []).map((item) => {
|
||||
return {text: item.name, value: item.id}
|
||||
})
|
||||
this.$set(this, 'activityOptions', options)
|
||||
this.$set(this.pageForm, 'activityId', options.length > 0 ? options[0].value : '')
|
||||
}
|
||||
})
|
||||
},
|
||||
onReady() {
|
||||
this.listActivity().then(() => {
|
||||
this.doSearch()
|
||||
})
|
||||
},
|
||||
doSearch() {
|
||||
this.$nextTick(() => {
|
||||
this.$set(this.pageForm, 'pageNumber', 1)
|
||||
this.$set(this.pageForm, 'totalCount', 0)
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
window.h5HistoryLayerManager.register(this.historyLayerPageKey, null)
|
||||
},
|
||||
beforeDestroy() {
|
||||
Object.keys(this.likeHeartEffectTimers).forEach((rowId) => {
|
||||
clearTimeout(this.likeHeartEffectTimers[rowId])
|
||||
})
|
||||
window.h5HistoryLayerManager.unregister(this.historyLayerPageKey)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+559
@@ -0,0 +1,559 @@
|
||||
const applyForm = {
|
||||
template:
|
||||
/*language=HTML*/
|
||||
`
|
||||
<div>
|
||||
<van-popup class="works-apply-popup" :style="{height: '100%', width: '100%'}" position="right"
|
||||
safe-area-inset-bottom :close-on-click-overlay="false" v-model="visible">
|
||||
<div class="works-apply-page">
|
||||
<van-sticky>
|
||||
<van-nav-bar title="作品提交" left-text="返回" left-arrow @click-left="closeApply"></van-nav-bar>
|
||||
</van-sticky>
|
||||
<van-form ref="formRef" class="works-apply-form form-container">
|
||||
<div ref="applyScrollRef" class="works-apply-scroll">
|
||||
<section class="works-apply-section">
|
||||
<h2 class="works-apply-section__title">基础信息</h2>
|
||||
<van-cell-group :border="false">
|
||||
<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>
|
||||
</section>
|
||||
|
||||
<section class="works-apply-section">
|
||||
<h2 class="works-apply-section__title">作品信息</h2>
|
||||
<van-cell-group :border="false">
|
||||
<van-field label="主题类型" required readonly is-link name="subjectName"
|
||||
placeholder="请选择主题类型" :rules="[{required: true, message: '请选择主题类型'}]"
|
||||
v-model="formData.subjectName" @click="openSubjectPicker"></van-field>
|
||||
<van-field label="作品类型" required readonly is-link name="worksName"
|
||||
placeholder="请先选择主题类型" :rules="[{required: true, message: '请选择作品类型'}]"
|
||||
v-model="formData.worksName" @click="openWorksPicker"></van-field>
|
||||
<van-field label="作品名称" required name="name" maxlength="100" show-word-limit
|
||||
placeholder="请填写作品名称" :rules="[{required: true, message: '请填写作品名称'}]"
|
||||
v-model="formData.name"></van-field>
|
||||
<van-field class="more-text" label="作品描述" required type="textarea" name="description"
|
||||
rows="4" autosize show-word-limit :maxlength="descriptionMaxLength"
|
||||
placeholder="请填写作品描述" :rules="[{required: true, message: '请填写作品描述'}]"
|
||||
v-model="formData.description"></van-field>
|
||||
</van-cell-group>
|
||||
</section>
|
||||
|
||||
<section class="works-apply-section">
|
||||
<h2 class="works-apply-section__title">作品附件</h2>
|
||||
<div class="works-apply-section__hint">附件说明:请根据所选作品类型上传符合要求的文件</div>
|
||||
<van-cell-group :border="false">
|
||||
<van-field class="more-text works-apply-upload-field" name="files" label="" required
|
||||
:rules="[{required: true, message: '请上传附件'}]">
|
||||
<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>
|
||||
</section>
|
||||
</div>
|
||||
<div class="works-apply-footer">
|
||||
<van-button type="primary" block round :loading="formLoading" loading-text="提交中..."
|
||||
@click="onSubmit">提交作品</van-button>
|
||||
</div>
|
||||
</van-form>
|
||||
</div>
|
||||
</van-popup>
|
||||
|
||||
<van-popup class="works-option-popup" v-model="showOptionPicker" position="bottom" round
|
||||
:close-on-click-overlay="false">
|
||||
<div class="works-option-popup__header">
|
||||
<button type="button" class="works-option-popup__action" @click="cancelOptionPopup">取消</button>
|
||||
<div class="works-option-popup__title">{{optionPopupTitle}}</div>
|
||||
<button type="button" class="works-option-popup__action"
|
||||
:disabled="pendingOptionValue === null || pendingOptionValue === undefined || pendingOptionValue === ''"
|
||||
@click="confirmOptionPopup">确认</button>
|
||||
</div>
|
||||
<div class="works-option-popup__list">
|
||||
<div v-if="optionPopupOptions.length === 0" class="works-option-popup__empty">暂无可选内容</div>
|
||||
<button v-for="option in optionPopupOptions" :key="option.value" type="button"
|
||||
class="works-option-popup__option"
|
||||
:class="{'is-selected': pendingOptionValue === option.value}"
|
||||
:aria-pressed="pendingOptionValue === option.value"
|
||||
@click="selectOptionPopupItem(option)">
|
||||
<span class="works-option-popup__option-text">{{option.text}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</van-popup>
|
||||
<van-dialog class="works-apply-confirm" title="提交确认" message="确认提交当前作品信息吗?"
|
||||
:value="submitConfirmVisible" :close-on-click-overlay="false" show-cancel-button
|
||||
cancel-button-text="取消" confirm-button-text="确认提交"
|
||||
@cancel="closeSubmitConfirm" @confirm="confirmSubmit"></van-dialog>
|
||||
</div>
|
||||
`,
|
||||
style: /*language=CSS*/ `
|
||||
/deep/ .works-apply-popup {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-page {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-page .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-page .van-nav-bar .van-icon,
|
||||
/deep/ .works-apply-page .van-nav-bar__text {
|
||||
color: #397fbd;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-form.form-container {
|
||||
min-height: 100%;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
background: #f3f7fc;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-scroll {
|
||||
height: calc(100vh - 46px);
|
||||
padding: 12px 15px calc(84px + env(safe-area-inset-bottom));
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
background: #f3f7fc;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-section {
|
||||
margin-bottom: 11px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #e9eff7;
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
box-shadow: 0 3px 11px rgba(51, 87, 126, .08);
|
||||
}
|
||||
|
||||
/deep/ .works-apply-section__title {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 12px 14px 8px 21px;
|
||||
color: #354255;
|
||||
font-size: 15px;
|
||||
line-height: 20px;
|
||||
font-weight: 600;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-section__title::before {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
bottom: 11px;
|
||||
left: 12px;
|
||||
width: 2px;
|
||||
border-radius: 2px;
|
||||
background: #1989fa;
|
||||
content: "";
|
||||
}
|
||||
|
||||
/deep/ .works-apply-section__hint {
|
||||
padding: 0 14px 8px 21px;
|
||||
color: orangered;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-section .van-cell-group {
|
||||
margin: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-section .van-cell {
|
||||
min-height: 44px;
|
||||
padding: 10px 14px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-section .van-cell:not(:last-child)::after {
|
||||
right: 14px;
|
||||
left: 14px;
|
||||
border-color: #eef2f7;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-section .van-field__label {
|
||||
width: 84px;
|
||||
color: #596779;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-section .van-field__value,
|
||||
/deep/ .works-apply-section .van-field__control {
|
||||
color: #4f5d70;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-section .van-field__control::placeholder {
|
||||
color: #b1bac6;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-section .van-cell--required::before {
|
||||
left: 6px;
|
||||
color: #f06464;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-upload-field .van-field__value {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-footer {
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
padding: 10px 18px calc(10px + env(safe-area-inset-bottom));
|
||||
border-top: 1px solid #edf1f6;
|
||||
background: rgba(255, 255, 255, .98);
|
||||
box-shadow: 0 -4px 14px rgba(50, 78, 112, .06);
|
||||
}
|
||||
|
||||
/deep/ .works-apply-footer .van-button {
|
||||
flex: 1;
|
||||
height: 40px;
|
||||
margin: 0;
|
||||
border-color: #1989fa;
|
||||
border-radius: 14px !important;
|
||||
font-size: 16px;
|
||||
background: #1989fa;
|
||||
}
|
||||
|
||||
/deep/ .works-option-popup {
|
||||
display: flex;
|
||||
height: 50%;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
background: #f5f7fa;
|
||||
}
|
||||
|
||||
/deep/ .works-option-popup__header {
|
||||
display: flex;
|
||||
min-height: 52px;
|
||||
padding: 0 16px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex: none;
|
||||
border-bottom: 1px solid #edf1f6;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/deep/ .works-option-popup__title {
|
||||
color: #263548;
|
||||
font-size: 17px;
|
||||
line-height: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/deep/ .works-option-popup__action {
|
||||
min-width: 48px;
|
||||
padding: 8px 0;
|
||||
border: 0;
|
||||
color: #1989fa;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
text-align: left;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/deep/ .works-option-popup__action:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/deep/ .works-option-popup__action:disabled {
|
||||
color: #b7c0cc;
|
||||
}
|
||||
|
||||
/deep/ .works-option-popup__list {
|
||||
min-height: 0;
|
||||
padding: 12px;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
/deep/ .works-option-popup__empty {
|
||||
padding: 44px 18px;
|
||||
color: #98a4b3;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/deep/ .works-option-popup__option {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 58px;
|
||||
margin-bottom: 10px;
|
||||
padding: 12px 14px;
|
||||
align-items: center;
|
||||
border: 1px solid #e3e9f1;
|
||||
border-radius: 10px;
|
||||
color: #536174;
|
||||
text-align: left;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/deep/ .works-option-popup__option:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/deep/ .works-option-popup__option.is-selected {
|
||||
border-color: #1989fa;
|
||||
color: #176fbd;
|
||||
background: #eef7ff;
|
||||
box-shadow: 0 3px 10px rgba(25, 137, 250, .1);
|
||||
}
|
||||
|
||||
/deep/ .works-option-popup__option-text {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
font-size: 15px;
|
||||
line-height: 23px;
|
||||
word-break: break-word;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-confirm .van-dialog__header {
|
||||
color: #263548;
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/deep/ .works-apply-confirm .van-dialog__message {
|
||||
padding: 24px 20px;
|
||||
color: #536174;
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
row: {}, visible: false, formData: {}, formLoading: false,
|
||||
subjectTypesOptions: [], worksTypeOptions: [],
|
||||
showOptionPicker: false, optionPopupType: "", optionPopupTitle: "",
|
||||
optionPopupOptions: [], pendingOptionValue: "",
|
||||
submitConfirmVisible: false, fileAccept: null, chooseWorksType: {},
|
||||
submitSuccessMode: "navigate",
|
||||
historyLayerPageKey: "works-collection-upload-h5",
|
||||
historyLayerUnsubscribe: null, ownsHistoryRegistration: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
descriptionMaxLength() {
|
||||
return this.chooseWorksType && this.chooseWorksType.maxWordCount ? this.chooseWorksType.maxWordCount : 150
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
resetFormData() {
|
||||
const user = this.$store.state.user || {}
|
||||
const union = user.union || {}
|
||||
const unit = user.unit || {}
|
||||
this.$set(this, "formData", {})
|
||||
this.$set(this.formData, "username", user.username)
|
||||
this.$set(this.formData, "loginname", user.loginname)
|
||||
this.$set(this.formData, "unionName", union.name)
|
||||
this.$set(this.formData, "unitName", unit.name)
|
||||
this.$set(this.formData, "sex", user.sex)
|
||||
this.$set(this.formData, "files", [])
|
||||
this.$set(this, "subjectTypesOptions", [])
|
||||
this.$set(this, "worksTypeOptions", [])
|
||||
this.$set(this, "chooseWorksType", {})
|
||||
this.$set(this, "fileAccept", null)
|
||||
},
|
||||
onOpen(row) {
|
||||
this.resetFormData()
|
||||
this.$set(this, "submitSuccessMode", "navigate")
|
||||
this.$set(this, "row", row)
|
||||
this.$set(this.formData, "activityId", row.id)
|
||||
this.activityChange(row.id).then(() => {
|
||||
window.h5HistoryLayerManager.open("works-collection-apply")
|
||||
this.resetScrollPosition()
|
||||
})
|
||||
},
|
||||
onOpenEdit(row) {
|
||||
const formData = clone(row)
|
||||
formData.files = this.normalizeFiles(formData.files)
|
||||
this.resetFormData()
|
||||
this.$set(this, "submitSuccessMode", "close")
|
||||
this.$set(this, "row", formData)
|
||||
this.$set(this, "formData", formData)
|
||||
const user = this.$store.state.user || {}
|
||||
this.$set(this.formData, "username", user.username)
|
||||
this.$set(this.formData, "loginname", user.loginname)
|
||||
this.$set(this.formData, "sex", user.sex)
|
||||
this.activityChange(formData.activityId).then(() => {
|
||||
// 编辑时以主题主键匹配当前活动配置,避免列表未携带主题名称时无法回显。
|
||||
const subjectType = this.subjectTypesOptions.find((item) => item.id === formData.subjectId)
|
||||
if (subjectType) this.$set(this.formData, "subjectName", subjectType.typeName)
|
||||
return this.subjectChange(formData.subjectId)
|
||||
}).then(() => {
|
||||
this.setSelectedWorksType(formData.worksId)
|
||||
window.h5HistoryLayerManager.open("works-collection-apply")
|
||||
this.resetScrollPosition()
|
||||
})
|
||||
},
|
||||
// 表单弹窗会被复用,每次打开后需清除上一次编辑或提交时保留的滚动位置。
|
||||
resetScrollPosition() {
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.applyScrollRef) this.$refs.applyScrollRef.scrollTop = 0
|
||||
})
|
||||
},
|
||||
// 附件可能由列表 SQL 返回 JSON 字符串,也可能已被序列化为数组;统一转换为上传组件需要的数组。
|
||||
normalizeFiles(files) {
|
||||
if (Array.isArray(files)) return files
|
||||
if (!files) return []
|
||||
try {
|
||||
const result = JSON.parse(files)
|
||||
return Array.isArray(result) ? result : []
|
||||
} catch (err) {
|
||||
return []
|
||||
}
|
||||
},
|
||||
closeApply() { window.h5HistoryLayerManager.close("works-collection-apply") },
|
||||
// 打开统一选择弹框:主题选项由活动配置提供,确认后再写入表单。
|
||||
openSubjectPicker() {
|
||||
this.$set(this, "optionPopupType", "subject")
|
||||
this.$set(this, "optionPopupTitle", "选择主题类型")
|
||||
this.$set(this, "optionPopupOptions", this.subjectTypesOptions.map((item) => {
|
||||
return {value: item.id, text: item.typeName, source: item}
|
||||
}))
|
||||
this.$set(this, "pendingOptionValue", this.formData.subjectId || "")
|
||||
window.h5HistoryLayerManager.open("works-collection-option-picker")
|
||||
},
|
||||
openWorksPicker() {
|
||||
if (!this.formData.subjectId) {
|
||||
this.$toast("请先选择主题类型")
|
||||
return
|
||||
}
|
||||
this.$set(this, "optionPopupType", "works")
|
||||
this.$set(this, "optionPopupTitle", "选择作品类型")
|
||||
this.$set(this, "optionPopupOptions", this.worksTypeOptions.map((item) => {
|
||||
return {value: item.id, text: item.worksTypeName, source: item}
|
||||
}))
|
||||
this.$set(this, "pendingOptionValue", this.formData.worksId || "")
|
||||
window.h5HistoryLayerManager.open("works-collection-option-picker")
|
||||
},
|
||||
cancelOptionPopup() { window.h5HistoryLayerManager.close("works-collection-option-picker") },
|
||||
selectOptionPopupItem(option) { this.$set(this, "pendingOptionValue", option.value) },
|
||||
/**
|
||||
* 确认类型选项并回填作品表单。
|
||||
* optionPopupType 为 subject 或 works,pendingOptionValue 为对应业务主键;方法无返回值。
|
||||
*/
|
||||
confirmOptionPopup() {
|
||||
const selectedOption = this.optionPopupOptions.find((item) => {
|
||||
return item.value === this.pendingOptionValue
|
||||
})
|
||||
if (!selectedOption) return
|
||||
if (this.optionPopupType === "subject") {
|
||||
this.onSubjectConfirm(selectedOption)
|
||||
return
|
||||
}
|
||||
this.onWorksConfirm(selectedOption)
|
||||
},
|
||||
onWorksConfirm(selectedOption) {
|
||||
this.$set(this.formData, "worksName", selectedOption.text)
|
||||
this.$set(this.formData, "worksId", selectedOption.value)
|
||||
this.setSelectedWorksType(selectedOption.value)
|
||||
this.cancelOptionPopup()
|
||||
},
|
||||
onSubjectConfirm(selectedOption) {
|
||||
this.$set(this.formData, "subjectName", selectedOption.text)
|
||||
this.$set(this.formData, "subjectId", selectedOption.value)
|
||||
this.$set(this.formData, "worksName", "")
|
||||
this.$set(this.formData, "worksId", "")
|
||||
this.$set(this.formData, "files", [])
|
||||
this.$set(this, "chooseWorksType", {})
|
||||
this.$set(this, "fileAccept", null)
|
||||
this.subjectChange(selectedOption.value).then(() => { this.cancelOptionPopup() })
|
||||
},
|
||||
setSelectedWorksType(worksId) {
|
||||
const worksType = this.worksTypeOptions.find((item) => item.id === worksId) || {}
|
||||
this.$set(this, "chooseWorksType", worksType)
|
||||
if (worksType.allowFileTypes && worksType.allowFileTypes.length > 0) {
|
||||
this.$set(this, "fileAccept", worksType.allowFileTypes.map((item) => "." + item).join(","))
|
||||
return
|
||||
}
|
||||
this.$set(this, "fileAccept", null)
|
||||
},
|
||||
onSubmit() {
|
||||
this.$refs.formRef.validate().then(() => {
|
||||
window.h5HistoryLayerManager.open("works-collection-submit-confirm")
|
||||
}).catch(() => {
|
||||
// 表单校验失败时由字段规则直接展示提示,不进入提交确认。
|
||||
})
|
||||
},
|
||||
closeSubmitConfirm() { window.h5HistoryLayerManager.close("works-collection-submit-confirm") },
|
||||
confirmSubmit() {
|
||||
window.h5HistoryLayerManager.close("works-collection-submit-confirm", () => { this.submitForm() })
|
||||
},
|
||||
submitForm() {
|
||||
this.$set(this, "formLoading", 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.success("提交成功")
|
||||
if (this.submitSuccessMode === "close") {
|
||||
// 我的作品页使用弹窗编辑,成功后只关闭当前表单并通知父页面刷新列表。
|
||||
window.h5HistoryLayerManager.close("works-collection-apply", () => {
|
||||
this.$emit("submit-success")
|
||||
})
|
||||
return
|
||||
}
|
||||
window.h5HistoryLayerManager.closeAllAndNavigate("/platform/activity/worksCollection/mine/h5")
|
||||
}
|
||||
}).finally(() => { this.$set(this, "formLoading", false) })
|
||||
},
|
||||
activityChange(value) {
|
||||
return this.$axios.post("/platform/activity/worksCollection/common/getSubjectTypes", {activityId: value}).then((res) => {
|
||||
if (res.code === 0) this.$set(this, "subjectTypesOptions", res.data || [])
|
||||
})
|
||||
},
|
||||
subjectChange(value) {
|
||||
return this.$axios.post("/platform/activity/worksCollection/common/getWorksTypes", {subjectId: value}).then((res) => {
|
||||
if (res.code === 0) this.$set(this, "worksTypeOptions", res.data || [])
|
||||
})
|
||||
},
|
||||
syncHistoryLayers(stack) {
|
||||
this.$set(this, "visible", stack.includes("works-collection-apply"))
|
||||
this.$set(this, "showOptionPicker", stack.includes("works-collection-option-picker"))
|
||||
this.$set(this, "submitConfirmVisible", stack.includes("works-collection-submit-confirm"))
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (!window.h5HistoryLayerManager.pageKey) {
|
||||
window.h5HistoryLayerManager.ensureRegistered(this.historyLayerPageKey)
|
||||
this.$set(this, "ownsHistoryRegistration", true)
|
||||
}
|
||||
this.$set(this, "historyLayerUnsubscribe", window.h5HistoryLayerManager.subscribe((stack) => {
|
||||
this.syncHistoryLayers(stack)
|
||||
}))
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.historyLayerUnsubscribe) this.historyLayerUnsubscribe()
|
||||
if (this.ownsHistoryRegistration) window.h5HistoryLayerManager.unregister(this.historyLayerPageKey)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,834 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
body {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.works-collection-page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: calc(24px + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.works-collection-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.works-collection-page .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.works-collection-page .van-nav-bar .van-icon,
|
||||
.works-collection-page .van-nav-bar__text {
|
||||
color: #397fbd;
|
||||
}
|
||||
|
||||
.works-collection-content {
|
||||
padding: 12px 12px 0;
|
||||
}
|
||||
|
||||
.works-collection-hero {
|
||||
position: relative;
|
||||
height: 134px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
color: #fff;
|
||||
background-color: #247fe8;
|
||||
box-shadow: 0 8px 20px rgba(51, 117, 219, .18);
|
||||
}
|
||||
|
||||
.works-collection-hero__image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
|
||||
.works-collection-hero__copy {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
width: 64%;
|
||||
height: 100%;
|
||||
padding-left: 16px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
background: linear-gradient(90deg, rgba(22, 112, 232, .98) 0%, rgba(22, 112, 232, .88) 52%, rgba(22, 112, 232, 0) 100%);
|
||||
}
|
||||
|
||||
.works-collection-hero__title {
|
||||
font-size: 25px;
|
||||
line-height: 34px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1px;
|
||||
text-shadow: 0 2px 6px rgba(17, 86, 182, .18);
|
||||
}
|
||||
|
||||
.works-collection-hero__subtitle {
|
||||
margin-top: 4px;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
letter-spacing: .5px;
|
||||
opacity: .95;
|
||||
}
|
||||
|
||||
.works-collection-sticky {
|
||||
padding: 10px 0 1px;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.van-sticky--fixed .works-collection-sticky {
|
||||
padding-right: 12px;
|
||||
padding-left: 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.works-collection-search {
|
||||
margin: 0 0 8px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .1);
|
||||
}
|
||||
|
||||
.works-collection-search .van-search__content {
|
||||
height: 42px;
|
||||
padding-left: 12px;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.works-collection-search .van-field__control {
|
||||
color: #263548;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.works-collection-search .van-field__control::placeholder {
|
||||
color: #a7b0bf;
|
||||
}
|
||||
|
||||
.works-collection-filter {
|
||||
margin: 0 0 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .08);
|
||||
transition: border-radius .18s ease;
|
||||
}
|
||||
|
||||
.works-collection-filter.is-open {
|
||||
border-radius: 10px 10px 0 0;
|
||||
}
|
||||
|
||||
.works-collection-filter .van-dropdown-menu__bar {
|
||||
height: 44px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.works-collection-filter .van-dropdown-menu__item {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.works-collection-filter .van-dropdown-menu__title {
|
||||
width: auto;
|
||||
max-width: calc(100% - 24px);
|
||||
padding: 0 12px 0 0;
|
||||
overflow: hidden;
|
||||
color: #66758a;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.works-collection-filter .van-dropdown-menu__title::after {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.works-collection-filter .van-dropdown-menu__title--active,
|
||||
.works-collection-filter .van-dropdown-item__option--active,
|
||||
.works-collection-filter .van-dropdown-item__option--active .van-dropdown-item__icon {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.works-collection-filter .van-dropdown-menu__title--down::after {
|
||||
border-color: transparent transparent #1989fa #1989fa;
|
||||
}
|
||||
|
||||
.works-collection-filter .van-dropdown-item__content {
|
||||
width: calc(100% - 24px);
|
||||
margin: 0 12px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0 0 12px 12px;
|
||||
box-shadow: 0 10px 24px rgba(31, 65, 108, .14);
|
||||
}
|
||||
|
||||
.works-collection-filter .van-dropdown-item__option {
|
||||
min-height: 48px;
|
||||
padding: 0 16px;
|
||||
color: #46566c;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.works-collection-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.works-collection-card {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.works-collection-card__cover,
|
||||
.works-collection-card__cover-state {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
background-color: #edf4fc;
|
||||
}
|
||||
|
||||
.works-collection-card__cover {
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.works-collection-card__cover-state {
|
||||
flex-direction: column;
|
||||
row-gap: 8px;
|
||||
color: #8da1ba;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.works-collection-card__cover-state .van-icon {
|
||||
font-size: 34px;
|
||||
}
|
||||
|
||||
.works-collection-card__cover-state.is-error {
|
||||
color: #c27b75;
|
||||
background-color: #fff3f1;
|
||||
}
|
||||
|
||||
.works-collection-card__body {
|
||||
padding: 12px 38px 14px 14px;
|
||||
}
|
||||
|
||||
.works-collection-card__title {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
color: #303846;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.works-collection-card__time {
|
||||
margin-top: 4px;
|
||||
overflow: hidden;
|
||||
color: #98a2b2;
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.works-collection-card__meta {
|
||||
display: flex;
|
||||
margin-top: 10px;
|
||||
padding-top: 9px;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
border-top: 1px solid #edf1f6;
|
||||
}
|
||||
|
||||
.works-collection-card__tag {
|
||||
display: inline-flex;
|
||||
padding: 3px 8px;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
color: #397de0;
|
||||
background-color: #edf5ff;
|
||||
font-size: 11px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.works-collection-card__tag-label {
|
||||
margin-right: 4px;
|
||||
color: #8aa7cf;
|
||||
}
|
||||
|
||||
.works-collection-card__arrow {
|
||||
position: absolute;
|
||||
top: 164px;
|
||||
right: 14px;
|
||||
color: #b4bdca;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.works-collection-empty {
|
||||
display: flex;
|
||||
min-height: 260px;
|
||||
padding: 26px 18px 32px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.works-collection-empty img {
|
||||
display: block;
|
||||
width: 82%;
|
||||
max-width: 280px;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.works-collection-empty__title {
|
||||
margin-top: 14px;
|
||||
color: #50627a;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.works-collection-empty__hint {
|
||||
margin-top: 5px;
|
||||
color: #9aa7b8;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.works-collection-page .van-list__loading {
|
||||
color: #9aa7b8;
|
||||
font-size: 13px;
|
||||
line-height: 44px;
|
||||
}
|
||||
|
||||
.works-collection-skeleton {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.works-collection-skeleton__card {
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
}
|
||||
|
||||
.works-collection-skeleton__cover,
|
||||
.works-collection-skeleton__body .van-skeleton {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.works-collection-skeleton__cover .van-skeleton__row {
|
||||
width: 100% !important;
|
||||
height: 150px;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.works-collection-skeleton__body {
|
||||
padding: 13px 14px 15px;
|
||||
}
|
||||
|
||||
.works-collection-skeleton__body .van-skeleton__title {
|
||||
width: 54%;
|
||||
height: 15px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.works-collection-skeleton__body .van-skeleton__row {
|
||||
height: 12px;
|
||||
margin-top: 9px;
|
||||
}
|
||||
|
||||
.works-collection-skeleton__body .van-skeleton__row:last-child {
|
||||
width: 46%;
|
||||
}
|
||||
|
||||
.works-intro-popup,
|
||||
.works-intro-page {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.works-intro-page {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.works-intro-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.works-intro-page .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.works-intro-page .van-nav-bar .van-icon,
|
||||
.works-intro-page .van-nav-bar__text {
|
||||
color: #397fbd;
|
||||
}
|
||||
|
||||
.works-intro-scroll {
|
||||
height: calc(100vh - 46px);
|
||||
padding: 12px 12px calc(92px + env(safe-area-inset-bottom));
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.works-intro-hero {
|
||||
display: flex;
|
||||
min-height: 82px;
|
||||
padding: 16px;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
border-radius: 12px;
|
||||
color: #fff;
|
||||
background: linear-gradient(120deg, #2d7eea 0%, #5ba6f7 100%);
|
||||
box-shadow: 0 8px 20px rgba(45, 126, 234, .18);
|
||||
}
|
||||
|
||||
.works-intro-hero__icon {
|
||||
display: flex;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
margin-right: 12px;
|
||||
flex: 0 0 44px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 11px;
|
||||
color: #2d7eea;
|
||||
background-color: rgba(255, 255, 255, .92);
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.works-intro-hero__title {
|
||||
font-size: 17px;
|
||||
line-height: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.works-intro-hero__subtitle {
|
||||
margin-top: 3px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
.works-intro-card {
|
||||
margin-top: 12px;
|
||||
padding: 18px 16px;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
}
|
||||
|
||||
.works-intro-content,
|
||||
.works-intro-content div,
|
||||
.works-intro-content p,
|
||||
.works-intro-content span,
|
||||
.works-intro-content li {
|
||||
color: #3f4c5e !important;
|
||||
font-size: 14px !important;
|
||||
line-height: 1.8 !important;
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.works-intro-content h1,
|
||||
.works-intro-content h2,
|
||||
.works-intro-content h3 {
|
||||
margin: 16px 0 10px !important;
|
||||
color: #1f2f43 !important;
|
||||
font-size: 19px !important;
|
||||
line-height: 1.5 !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
.works-intro-content > :first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.works-intro-content p {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 8px !important;
|
||||
}
|
||||
|
||||
.works-intro-content img {
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.works-intro-content table {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.works-intro-empty {
|
||||
display: flex;
|
||||
min-height: 180px;
|
||||
margin-top: 12px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
row-gap: 10px;
|
||||
border-radius: 12px;
|
||||
color: #9aa7b8;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.works-intro-empty .van-icon {
|
||||
color: #83b5f4;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.works-intro-footer {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 5;
|
||||
padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
|
||||
border-top: 1px solid #edf1f6;
|
||||
background-color: rgba(255, 255, 255, .96);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.works-intro-footer .van-button {
|
||||
height: 42px;
|
||||
border: 0;
|
||||
border-radius: 21px;
|
||||
font-size: 15px;
|
||||
background-color: #1989fa;
|
||||
box-shadow: 0 6px 16px rgba(25, 137, 250, .22);
|
||||
}
|
||||
|
||||
.works-intro-footer .van-button--disabled {
|
||||
color: #8b98aa !important;
|
||||
background-color: #eef2f7 !important;
|
||||
opacity: 1;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.works-intro-footer .van-count-down {
|
||||
display: inline-block;
|
||||
margin-left: 4px;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<div class="works-collection-page">
|
||||
<van-nav-bar title="作品征集" left-text="返回" left-arrow @click-left="handlePageBack" fixed placeholder></van-nav-bar>
|
||||
|
||||
<div class="works-collection-content">
|
||||
<section class="works-collection-hero">
|
||||
<img class="works-collection-hero__image" src="/assets/mobile/img/activity/hero/brand-hero-v2.png" alt="作品征集插画">
|
||||
<div class="works-collection-hero__copy">
|
||||
<div class="works-collection-hero__title">作品征集</div>
|
||||
<div class="works-collection-hero__subtitle">汇聚创意 · 展示风采</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<van-sticky :offset-top="46">
|
||||
<div class="works-collection-sticky">
|
||||
<van-search
|
||||
v-model="pageForm.searchKeyword"
|
||||
class="works-collection-search"
|
||||
placeholder="搜索作品征集活动"
|
||||
shape="round"
|
||||
clearable
|
||||
@search="doSearch"
|
||||
@clear="doSearch"
|
||||
></van-search>
|
||||
<van-dropdown-menu class="works-collection-filter" :class="{'is-open': filterOpened}" active-color="#1989fa">
|
||||
<year-van-dropdown-item :num="5" @change="doSearch" @open="onFilterOpen" @close="onFilterClose" v-model="pageForm.year"></year-van-dropdown-item>
|
||||
<van-dropdown-item v-model="pageForm.activityType" :options="typeOptions" :multiple="false" @change="doSearch" @open="onFilterOpen" @close="onFilterClose"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</div>
|
||||
</van-sticky>
|
||||
|
||||
<div v-if="skeletonLoading" class="works-collection-skeleton">
|
||||
<div v-for="index in 3" :key="'upload-skeleton-' + index" class="works-collection-skeleton__card">
|
||||
<van-skeleton class="works-collection-skeleton__cover" :row="1" animated></van-skeleton>
|
||||
<div class="works-collection-skeleton__body">
|
||||
<van-skeleton title :row="2" animated></van-skeleton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<van-pull-refresh v-show="!skeletonLoading" v-model="refreshing" @refresh="onRefresh">
|
||||
<van-list v-model="loading" :finished="finished" :immediate-check="false" @load="onLoad">
|
||||
<div class="works-collection-list">
|
||||
<div v-for="row in tableData" :key="row.id" class="works-collection-card" @click="onView(row)">
|
||||
<img
|
||||
v-if="hasCover(row) && !imageLoadErrors[row.id]"
|
||||
class="works-collection-card__cover"
|
||||
:src="row.cover"
|
||||
:alt="row.name"
|
||||
@error="handleImageError(row)"
|
||||
>
|
||||
<div v-else class="works-collection-card__cover-state" :class="{'is-error': hasCover(row)}">
|
||||
<van-icon name="photo-o"></van-icon>
|
||||
<span>{{ hasCover(row) ? '图片加载失败' : '暂无图片' }}</span>
|
||||
</div>
|
||||
<div class="works-collection-card__body">
|
||||
<div class="works-collection-card__title">{{ row.name }}</div>
|
||||
<div class="works-collection-card__time" v-if="row.startDateTime && row.endDateTime">
|
||||
征集时间:{{ $moment(row.startDateTime).format('MM/DD HH:mm') }}~{{ $moment(row.endDateTime).format('MM/DD HH:mm') }}
|
||||
</div>
|
||||
<div class="works-collection-card__meta" v-if="row.activityGroupName">
|
||||
<span class="works-collection-card__tag" v-if="row.activityGroupName">
|
||||
<span class="works-collection-card__tag-label">面向对象</span>{{ row.activityGroupName }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<van-icon class="works-collection-card__arrow" name="arrow"></van-icon>
|
||||
</div>
|
||||
</div>
|
||||
</van-list>
|
||||
<div v-if="!loading && tableData.length === 0" class="works-collection-empty">
|
||||
<img src="/assets/mobile/img/activity/culture-empty.png" alt="作品征集空状态插画">
|
||||
<div class="works-collection-empty__title">暂无作品征集活动</div>
|
||||
<div class="works-collection-empty__hint">当前筛选条件下暂时没有可展示的活动</div>
|
||||
</div>
|
||||
</van-pull-refresh>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<van-popup class="works-intro-popup" :style="{height: '100%', width: '100%'}" position="right" safe-area-inset-bottom :close-on-click-overlay="false" v-model="infoVisible">
|
||||
<div class="works-intro-page">
|
||||
<van-sticky>
|
||||
<van-nav-bar title="征集介绍" left-text="返回" left-arrow @click-left="closeInfo"></van-nav-bar>
|
||||
</van-sticky>
|
||||
<div class="works-intro-scroll">
|
||||
<div class="works-intro-hero">
|
||||
<div class="works-intro-hero__icon">
|
||||
<van-icon name="description"></van-icon>
|
||||
</div>
|
||||
<div>
|
||||
<div class="works-intro-hero__title">作品征集须知</div>
|
||||
<div class="works-intro-hero__subtitle">请仔细阅读征集内容与作品要求</div>
|
||||
</div>
|
||||
</div>
|
||||
<article v-if="infoRow.content" class="works-intro-card">
|
||||
<div class="works-intro-content" v-html="infoRow.content"></div>
|
||||
</article>
|
||||
<div v-else class="works-intro-empty">
|
||||
<van-icon name="description"></van-icon>
|
||||
<span>暂无征集介绍</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="works-intro-footer">
|
||||
<van-button v-if="canApply(infoRow)" @click="onApply(infoRow)" type="primary" block round>上传作品</van-button>
|
||||
<van-button v-else-if="time < 0" @click="onApply(infoRow)" type="primary" block round>
|
||||
距离开始
|
||||
<van-count-down :time="Math.abs(time)" format="DD 天 HH 时 mm 分 ss 秒" @finish="onCountdownFinish"></van-count-down>
|
||||
</van-button>
|
||||
<van-button v-else disabled block round>{{ registrationStatusText(infoRow) }}</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
|
||||
<apply-form ref="applyFormRef"></apply-form>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("applyForm.js"){}#-->
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
"apply-form": applyForm
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
time: 0,
|
||||
tableData: [],
|
||||
loading: false,
|
||||
skeletonLoading: true,
|
||||
finished: false,
|
||||
refreshing: false,
|
||||
imageLoadErrors: {},
|
||||
filterOpened: false,
|
||||
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: {},
|
||||
historyLayerPageKey: "works-collection-upload-h5",
|
||||
historyLayerUnsubscribe: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
hasCover(row) {
|
||||
return !!(row && row.cover && String(row.cover).trim())
|
||||
},
|
||||
handleImageError(row) {
|
||||
this.$set(this.imageLoadErrors, row.id, true)
|
||||
},
|
||||
onFilterOpen() {
|
||||
this.$set(this, "filterOpened", true)
|
||||
},
|
||||
onFilterClose() {
|
||||
this.$set(this, "filterOpened", false)
|
||||
},
|
||||
onCountdownFinish() {
|
||||
this.$set(this, "time", 0)
|
||||
},
|
||||
isRegistrationClosed(row) {
|
||||
return !!(row && row.endDateTime && !this.$moment().isBefore(this.$moment(row.endDateTime)))
|
||||
},
|
||||
canApply(row) {
|
||||
if(!row || !row.startDateTime || !row.endDateTime) {
|
||||
return false
|
||||
}
|
||||
const now = Date.now()
|
||||
return now >= this.$moment(row.startDateTime).valueOf()
|
||||
&& now <= this.$moment(row.endDateTime).valueOf()
|
||||
},
|
||||
registrationStatusText(row) {
|
||||
if(!row || !row.startDateTime || !row.endDateTime) {
|
||||
return '当前不可参与'
|
||||
}
|
||||
if(Date.now() < this.$moment(row.startDateTime).valueOf()) {
|
||||
return '征集未开始'
|
||||
}
|
||||
return '征集已结束'
|
||||
},
|
||||
onView(row) {
|
||||
this.$set(this, "infoRow", row)
|
||||
this.$set(this, "time", this.$moment().diff(this.$moment(row.startDateTime), "milliseconds"))
|
||||
window.h5HistoryLayerManager.open("works-collection-info")
|
||||
},
|
||||
closeInfo() {
|
||||
window.h5HistoryLayerManager.close("works-collection-info")
|
||||
},
|
||||
handlePageBack() {
|
||||
if (window.h5HistoryLayerManager.stack.length) {
|
||||
window.h5HistoryLayerManager.close()
|
||||
return
|
||||
}
|
||||
this.historyBack()
|
||||
},
|
||||
syncHistoryLayers(stack) {
|
||||
this.$set(this, "infoVisible", stack.includes("works-collection-info"))
|
||||
},
|
||||
onApply(row) {
|
||||
if(this.isRegistrationClosed(row)) {
|
||||
this.$toast.fail("征集已结束")
|
||||
return
|
||||
}
|
||||
if(this.$moment().isBefore(this.$moment(row.startDateTime))) {
|
||||
this.onView(row)
|
||||
return
|
||||
}
|
||||
this.$refs.applyFormRef.onOpen(row)
|
||||
},
|
||||
onLoad() {
|
||||
if(!this.finished) {
|
||||
this.loadActivities(false)
|
||||
}
|
||||
},
|
||||
onRefresh() {
|
||||
this.loadActivities(true)
|
||||
},
|
||||
loadActivities(reset) {
|
||||
const showSkeleton = !!reset
|
||||
if(reset) {
|
||||
this.$set(this, "skeletonLoading", true)
|
||||
this.$set(this.pageForm, "pageNumber", 1)
|
||||
this.$set(this.pageForm, "totalCount", 0)
|
||||
this.$set(this, "tableData", [])
|
||||
this.$set(this, "finished", false)
|
||||
this.$set(this, "imageLoadErrors", {})
|
||||
}
|
||||
this.$set(this, "loading", true)
|
||||
this.$axios.post('/platform/activity/worksCollection/upload/h5/activityPageData', this.pageForm, {
|
||||
h5SkeletonLoading: showSkeleton
|
||||
}).then((res) => {
|
||||
if(res.code === 0) {
|
||||
const list = res.data && res.data.list ? res.data.list : []
|
||||
this.$set(this, "tableData", this.pageForm.pageNumber === 1 ? list : this.tableData.concat(list))
|
||||
this.$set(this.pageForm, "totalCount", res.data && res.data.totalCount ? res.data.totalCount : 0)
|
||||
this.$set(this, "finished", this.tableData.length >= this.pageForm.totalCount)
|
||||
if(!this.finished) {
|
||||
this.$set(this.pageForm, "pageNumber", this.pageForm.pageNumber + 1)
|
||||
}
|
||||
}
|
||||
}).finally(() => {
|
||||
this.$set(this, "loading", false)
|
||||
this.$set(this, "refreshing", false)
|
||||
if(showSkeleton) this.$set(this, "skeletonLoading", false)
|
||||
})
|
||||
},
|
||||
doSearch() {
|
||||
this.loadActivities(true)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
window.h5HistoryLayerManager.register(this.historyLayerPageKey, (stack) => {
|
||||
this.syncHistoryLayers(stack)
|
||||
})
|
||||
this.$set(this, "historyLayerUnsubscribe", window.h5HistoryLayerManager.subscribe((stack) => {
|
||||
this.syncHistoryLayers(stack)
|
||||
}))
|
||||
this.loadActivities(true)
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.historyLayerUnsubscribe) {
|
||||
this.historyLayerUnsubscribe()
|
||||
}
|
||||
window.h5HistoryLayerManager.unregister(this.historyLayerPageKey)
|
||||
}
|
||||
})
|
||||
</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", // skuKeyStr:sku 组合列表(下方 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,329 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style scoped>
|
||||
#app { --club-primary: #1989fa; background: #f3f7fd; }
|
||||
.club-apply-page { min-height: 100vh; background: #f3f7fd; }
|
||||
.club-apply-page .van-nav-bar { background: #fff; box-shadow: 0 1px 8px rgba(28, 69, 120, .06); }
|
||||
.club-apply-page .van-nav-bar__title { color: #1f2d3d; font-size: 16px; font-weight: 600; }
|
||||
.club-apply-page .van-nav-bar__left { color: var(--club-primary); }
|
||||
.club-apply-page .van-nav-bar .van-icon, .club-apply-page .van-nav-bar .van-nav-bar__text { color: var(--club-primary); }
|
||||
.club-apply-form { padding: 12px 15px calc(132px + env(safe-area-inset-bottom)); background: #f3f7fd; }
|
||||
.club-apply-section { overflow: hidden; margin-bottom: 12px; background: #fff; border: 1px solid #e9eff7; border-radius: 10px; box-shadow: 0 4px 12px rgba(36, 77, 122, .04); }
|
||||
.club-apply-section__title { position: relative; margin: 0; padding: 13px 15px 8px 24px; color: #1f2d3d; font-size: 14px; font-weight: 600; line-height: 20px; }
|
||||
.club-apply-section__title::before { position: absolute; top: 16px; left: 15px; width: 3px; height: 14px; border-radius: 2px; background: var(--club-primary); content: ''; }
|
||||
.club-apply-section .van-cell-group { margin: 0; }
|
||||
.club-apply-section .van-cell { min-height: 46px; padding: 11px 15px; color: #40526a; font-size: 14px; }
|
||||
.club-apply-section .van-cell::after { right: 15px; left: 15px; border-color: #edf2f8; }
|
||||
.club-apply-section .van-field__label { width: 105px; color: #65778e; }
|
||||
.club-apply-section .van-field__control { color: #40526a; font-size: 14px; }
|
||||
.club-apply-section .van-field__control::placeholder { color: #b4c0cf; }
|
||||
.club-apply-section .van-field--disabled .van-field__control { color: #8b9bb0; }
|
||||
.club-apply-section .direction-column-field .van-field__label { width: 100%; margin-bottom: 8px; }
|
||||
.club-apply-section .direction-column-field .van-field__value { width: 100%; }
|
||||
.club-apply-section .van-field__word-limit { color: #b4c0cf; font-size: 11px; }
|
||||
.club-apply-actions { position: fixed; right: 0; bottom: 0; left: 0; z-index: 5; padding: 10px 15px calc(10px + env(safe-area-inset-bottom)); background: rgba(255, 255, 255, .98); border-top: 1px solid #edf2f8; }
|
||||
.club-apply-actions__agree { padding-bottom: 9px; }
|
||||
.club-apply-actions__agree .van-checkbox { align-items: flex-start; }
|
||||
.club-apply-actions__agree .van-checkbox__icon { margin-top: 2px; }
|
||||
.club-apply-actions__agree .van-checkbox__label { color: #65778e; font-size: 12px; line-height: 18px; }
|
||||
.club-apply-actions__buttons { display: flex; gap: 10px; }
|
||||
.club-apply-actions .van-button { flex: 1; height: 40px; border-radius: 8px; font-size: 14px; font-weight: 500; }
|
||||
.club-apply-actions .van-button--info { background: var(--club-primary); border-color: var(--club-primary); }
|
||||
.club-apply-actions .van-button--info.van-button--plain { color: var(--club-primary); background: #fff; }
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak class="club-apply-page">
|
||||
<van-nav-bar title="文体社团会员申请" left-text="返回" left-arrow @click-left="onNavBack" fixed placeholder></van-nav-bar>
|
||||
|
||||
<van-form ref="formRef" class="club-apply-form">
|
||||
<section class="club-apply-section">
|
||||
<h2 class="club-apply-section__title">基本信息</h2>
|
||||
<van-cell-group :border="false">
|
||||
<van-field :rules="[{ required: true, message: '请选择社团' }]" v-model="formData.clubName" label="社团" placeholder="请选择社团" required is-link readonly name="clubName" @click="openClubPopup"></van-field>
|
||||
<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-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.position" 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>
|
||||
</section>
|
||||
|
||||
<section class="club-apply-section">
|
||||
<h2 class="club-apply-section__title">其他信息</h2>
|
||||
<van-cell-group :border="false">
|
||||
<van-field class="direction-column-field" v-model="formData.sameTimeJoinOtherClubSituation" label="同时参加其他社团情况" type="textarea" rows="4" autosize maxlength="500" show-word-limit placeholder="请填写同时参加其他社团情况"></van-field>
|
||||
<van-field class="direction-column-field" v-model="formData.awardsExperience" label="文化、体育方面的活动经历、获奖情况" type="textarea" rows="4" autosize maxlength="500" show-word-limit placeholder="请填写相关经历及获奖情况"></van-field>
|
||||
</van-cell-group>
|
||||
</section>
|
||||
|
||||
<section class="club-apply-section">
|
||||
<h2 class="club-apply-section__title">照片</h2>
|
||||
<van-cell-group :border="false">
|
||||
<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"></h5-file-upload>
|
||||
</template>
|
||||
</van-field>
|
||||
</van-cell-group>
|
||||
</section>
|
||||
|
||||
<section class="club-apply-section">
|
||||
<h2 class="club-apply-section__title">电子签名</h2>
|
||||
<van-cell-group :border="false">
|
||||
<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>
|
||||
</section>
|
||||
|
||||
</van-form>
|
||||
|
||||
<div class="club-apply-actions">
|
||||
<div class="club-apply-actions__agree"><van-checkbox v-model="isAgree" shape="square">注:本人已仔细阅读并愿意遵守所参加本校教职工文体社团的章程和规定,自愿加入所报名社团。</van-checkbox></div>
|
||||
<div class="club-apply-actions__buttons">
|
||||
<van-button native-type="button" :loading="formLoading" @click="onSave" type="info" plain>保存申请</van-button>
|
||||
<van-button :loading="formLoading" @click="onSubmit" type="info" v-if="!taskId">提交申请</van-button>
|
||||
<van-button :loading="formLoading" @click="onFinishTask" type="info" v-else>提交申请</van-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<van-popup v-model="showClubPopup" position="bottom" get-container="#app" @click-overlay="closeClubPopup">
|
||||
<van-picker show-toolbar :columns="clubOptions.map((item) => item.clubName)" @confirm="onClubConfirm" @cancel="closeClubPopup"></van-picker>
|
||||
</van-popup>
|
||||
|
||||
<van-dialog :value="confirmVisible" title="提示" :message="confirmMessage" show-cancel-button @confirm="confirmPendingAction" @cancel="closeConfirm"></van-dialog>
|
||||
</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: "", position: "", technicalTitle: "", education: "", academicDegree: "", sameTimeJoinOtherClubSituation: "", awardsExperience: "", avatar: "", signature: ""
|
||||
},
|
||||
clubOptions: [],
|
||||
showClubPopup: false,
|
||||
isAgree: false,
|
||||
formLoading: false,
|
||||
confirmVisible: false,
|
||||
pendingAction: "",
|
||||
historyLayerUnsubscribe: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
confirmMessage() {
|
||||
return this.pendingAction === 'save' ? '您确定保存当前申请吗?' : '您确定提交申请吗?';
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const manager = window.h5HistoryLayerManager;
|
||||
if (manager) {
|
||||
manager.ensureRegistered('club-apply');
|
||||
this.historyLayerUnsubscribe = manager.subscribe((layers) => {
|
||||
this.$set(this, 'showClubPopup', layers.includes('club-apply-club-picker'));
|
||||
this.$set(this, 'confirmVisible', layers.includes('club-apply-confirm'));
|
||||
});
|
||||
}
|
||||
this.listClub();
|
||||
this.init();
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.historyLayerUnsubscribe) {
|
||||
this.historyLayerUnsubscribe();
|
||||
}
|
||||
const manager = window.h5HistoryLayerManager;
|
||||
if (manager) {
|
||||
manager.unregister('club-apply');
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onNavBack() {
|
||||
const manager = window.h5HistoryLayerManager;
|
||||
if (manager && manager.stack.length) {
|
||||
manager.close();
|
||||
return;
|
||||
}
|
||||
historyBack();
|
||||
},
|
||||
openClubPopup() {
|
||||
const manager = window.h5HistoryLayerManager;
|
||||
if (manager) {
|
||||
manager.open('club-apply-club-picker');
|
||||
return;
|
||||
}
|
||||
this.$set(this, 'showClubPopup', true);
|
||||
},
|
||||
closeClubPopup(afterClose) {
|
||||
const manager = window.h5HistoryLayerManager;
|
||||
if (manager) {
|
||||
manager.close('club-apply-club-picker', afterClose);
|
||||
return;
|
||||
}
|
||||
this.$set(this, 'showClubPopup', false);
|
||||
if (afterClose) {
|
||||
afterClose();
|
||||
}
|
||||
},
|
||||
openConfirm(action) {
|
||||
this.$set(this, 'pendingAction', action);
|
||||
const manager = window.h5HistoryLayerManager;
|
||||
if (manager) {
|
||||
manager.open('club-apply-confirm');
|
||||
return;
|
||||
}
|
||||
this.$set(this, 'confirmVisible', true);
|
||||
},
|
||||
closeConfirm(afterClose) {
|
||||
const manager = window.h5HistoryLayerManager;
|
||||
if (manager) {
|
||||
manager.close('club-apply-confirm', afterClose);
|
||||
return;
|
||||
}
|
||||
this.$set(this, 'confirmVisible', false);
|
||||
if (afterClose) {
|
||||
afterClose();
|
||||
}
|
||||
},
|
||||
onSave() {
|
||||
this.openConfirm('save');
|
||||
},
|
||||
onSubmit() {
|
||||
this.validateAndConfirm('submit');
|
||||
},
|
||||
onFinishTask() {
|
||||
this.validateAndConfirm('submitAgain');
|
||||
},
|
||||
validateAndConfirm(action) {
|
||||
this.$refs.formRef.validate().then(() => {
|
||||
if (!this.isAgree) {
|
||||
this.$toast('请先阅读并同意协议');
|
||||
return;
|
||||
}
|
||||
this.openConfirm(action);
|
||||
});
|
||||
},
|
||||
confirmPendingAction() {
|
||||
const action = this.pendingAction;
|
||||
this.closeConfirm(() => {
|
||||
if (action === 'save') {
|
||||
this.saveApplication();
|
||||
} else if (action === 'submitAgain') {
|
||||
this.submitApplication('/platform/club/join/apply/submitAgain', {data: JSON.stringify(this.formData), taskId: this.taskId});
|
||||
} else {
|
||||
this.submitApplication('/platform/club/join/apply/submit', {data: JSON.stringify(this.formData), mode: true});
|
||||
}
|
||||
});
|
||||
},
|
||||
saveApplication() {
|
||||
this.$set(this, 'formLoading', true);
|
||||
this.$axios.post('/platform/club/join/apply/save', {data: JSON.stringify(this.formData)}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$toast(res.msg);
|
||||
this.clearLayersAndGoMine();
|
||||
}
|
||||
}).finally(() => {
|
||||
this.$set(this, 'formLoading', false);
|
||||
});
|
||||
},
|
||||
submitApplication(url, params) {
|
||||
this.$set(this, 'formLoading', true);
|
||||
this.$axios.post(url, params).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$toast(res.msg);
|
||||
this.clearLayersAndGoMine();
|
||||
}
|
||||
}).finally(() => {
|
||||
this.$set(this, 'formLoading', false);
|
||||
});
|
||||
},
|
||||
clearLayersAndGoMine() {
|
||||
const manager = window.h5HistoryLayerManager;
|
||||
if (manager) {
|
||||
manager.closeAll(() => {
|
||||
this.$pjaxReplace('/platform/club/join/mine/h5');
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.$pjaxReplace('/platform/club/join/mine/h5');
|
||||
},
|
||||
checkApplyClub(clubId) {
|
||||
this.$axios.post('/platform/club/join/apply/checkApplyClub', {clubId: clubId}).then((res) => {
|
||||
if (res.code !== 0) {
|
||||
this.$toast(res.msg);
|
||||
this.$set(this.formData, 'clubId', '');
|
||||
this.$set(this.formData, 'clubName', '');
|
||||
}
|
||||
});
|
||||
},
|
||||
onClubConfirm(value, index) {
|
||||
const club = this.clubOptions[index];
|
||||
if (club) {
|
||||
this.$set(this.formData, 'clubId', club.id);
|
||||
this.$set(this.formData, 'clubName', value);
|
||||
this.checkApplyClub(club.id);
|
||||
}
|
||||
this.closeClubPopup();
|
||||
},
|
||||
listClub() {
|
||||
this.$axios.post('/platform/club/common/listClub').then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$set(this, 'clubOptions', res.data || []);
|
||||
}
|
||||
});
|
||||
},
|
||||
init() {
|
||||
if (this.bizId) {
|
||||
this.$axios.post('/platform/club/join/apply/info', {id: this.bizId}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
const formData = Object.assign({}, res.data || {});
|
||||
// 兼容历史空数组字符串,避免编辑页把 "[]" 当作图片地址回显。
|
||||
if (formData.avatar === '[]') {
|
||||
formData.avatar = '';
|
||||
}
|
||||
this.$set(this, 'formData', formData);
|
||||
this.$set(this, 'isAgree', true);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,265 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style id="style-club-user-join-h5">
|
||||
<!--#include('../common/clubUserJoin.css'){}#-->
|
||||
</style>
|
||||
|
||||
<style>
|
||||
#app { --club-primary: #1989fa; }
|
||||
.club-approval-page { min-height: 100vh; padding-bottom: calc(24px + env(safe-area-inset-bottom)); box-sizing: border-box; background: #f3f7fd; }
|
||||
.club-approval-page .van-nav-bar, .club-approval-page .van-sticky--fixed { background: #fff; }
|
||||
.club-approval-page .van-nav-bar__title { color: #172033; font-size: 16px; font-weight: 600; }
|
||||
.club-approval-page .van-nav-bar .van-icon, .club-approval-page .van-nav-bar__text { color: #1989fa; }
|
||||
.club-approval-sticky { padding: 22px 12px 1px; box-sizing: border-box; background: #f3f7fd; }
|
||||
.club-approval-search { margin: 0 0 8px; padding: 0; overflow: hidden; border-radius: 12px; background: #fff; box-shadow: 0 5px 16px rgba(43, 73, 112, .1); }
|
||||
.club-approval-search .van-search__content { height: 42px; padding-left: 12px; align-items: center; border-radius: 12px; background: #fff; }
|
||||
.club-approval-search .van-field__control { color: #263548; font-size: 14px; }
|
||||
.club-approval-search .van-field__control::placeholder { color: #a7b0bf; }
|
||||
.club-approval-filter { margin-bottom: 8px; overflow: hidden; border-radius: 10px; box-shadow: 0 5px 16px rgba(43, 73, 112, .08); }
|
||||
.club-approval-filter .van-dropdown-menu__bar { height: 44px; box-shadow: none; }
|
||||
.club-approval-filter .van-dropdown-menu__item, .club-approval-filter .van-dropdown-menu__title { height: 44px; }
|
||||
.club-approval-filter .van-dropdown-menu__item { align-items: center; justify-content: center; }
|
||||
.club-approval-filter .van-dropdown-menu__title { display: inline-flex; align-items: center; color: #66758a; font-size: 14px; line-height: 20px; }
|
||||
.club-approval-filter .van-dropdown-menu__title--active, .club-approval-filter .van-dropdown-item__option--active, .club-approval-filter .van-dropdown-item__option--active .van-dropdown-item__icon { color: #1989fa; }
|
||||
.club-approval-filter .van-dropdown-item__content { width: calc(100% - 24px); margin: 0 12px; overflow: hidden; box-sizing: border-box; border-radius: 0 0 12px 12px; box-shadow: 0 10px 24px rgba(31, 65, 108, .14); }
|
||||
.club-approval-filter .van-dropdown-item__option { display: flex; min-height: 48px; padding: 0 16px; align-items: center; color: #46566c; font-size: 14px; }
|
||||
.club-approval-list-content { padding: 0 12px; }
|
||||
.club-approval-page .table-list-container { margin-top: 0; padding-bottom: 2px; }
|
||||
.club-approval-page .table-list-container .table-list-item { margin-bottom: 12px; padding: 14px; border: 1px solid #e9eff7; border-radius: 12px; box-shadow: 0 5px 16px rgba(43, 73, 112, .08); }
|
||||
.club-card-header { display: flex; margin-bottom: 8px; align-items: flex-start; justify-content: space-between; }
|
||||
.club-card-header__heading { min-width: 0; padding-right: 10px; flex: 1; }
|
||||
.club-card-header__title { overflow: hidden; color: #253247; font-size: 15px; font-weight: 600; line-height: 22px; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.club-card-header__sub { margin-top: 1px; color: #9ba6b6; font-size: 12px; line-height: 18px; }
|
||||
.club-card-header__status { display: inline-flex; flex: none; }
|
||||
.club-card-header__status .van-tag { min-height: 24px; padding: 3px 9px; border: 0; border-radius: 12px; box-sizing: border-box; font-size: 12px; line-height: 18px; }
|
||||
.club-approval-page .table-list-container .table-list-item .item-actions { margin-top: 10px; padding-top: 10px; border-top-color: #edf1f6; }
|
||||
.club-approval-page .table-list-container .table-list-item .action-btn { min-height: 28px; padding: 4px 11px; border-radius: 14px; color: #1989fa; background: #eaf4ff; font-size: 12px; line-height: 18px; }
|
||||
.club-approval-page .table-list-container .table-list-item .action-btn.delete { color: #f04444; background: #fff0f0; }
|
||||
.club-approval-page .table-list-container .table-list-item .action-btn .van-icon { margin-right: 5px; font-size: 13px; }
|
||||
.club-approval-page .empty-state { padding: 0; }
|
||||
.club-audit-card { margin: 0 0 11px; overflow: hidden; border: 1px solid #e9eff7; border-radius: 10px; background: #fff; box-shadow: 0 3px 11px rgba(51, 87, 126, .08); }
|
||||
.club-audit-card__title { position: relative; margin: 0; padding: 12px 14px 8px 21px; color: #354255; font-size: 15px; font-weight: 600; line-height: 22px; }
|
||||
.club-audit-card__title::before { position: absolute; top: 15px; bottom: 11px; left: 12px; width: 2px; border-radius: 2px; background: var(--club-primary); content: ''; }
|
||||
.club-audit-card__required { position: absolute; left: 6px; color: #ee0a24; font-size: 12px; }
|
||||
.club-audit-card .club-audit-payment-field { min-height: 44px; padding: 10px 14px; background: transparent; }
|
||||
.club-audit-card .club-audit-payment-field::after { right: 14px; left: 14px; border-color: #eef2f7; }
|
||||
.club-audit-card .club-audit-payment-field .van-field__label { width: 102px; color: #596779; font-size: 12px; line-height: 24px; }
|
||||
.club-audit-card .club-audit-payment-field .van-field__control { color: #4f5d70; font-size: 12px; line-height: 24px; }
|
||||
.club-audit-card .van-radio-group { display: flex; align-items: center; min-height: 24px; white-space: nowrap; }
|
||||
.club-audit-card .van-radio { margin-right: 12px; }
|
||||
.club-audit-card .van-radio__label { color: #4f5d70; font-size: 12px; line-height: 24px; }
|
||||
.club-audit-field-label { position: relative; margin: 0; padding: 10px 14px 6px; color: #596779; font-size: 12px; line-height: 24px; }
|
||||
.club-audit-card .van-field.club-audit-field { width: calc(100% - 28px); margin: 0 14px 14px; padding: 12px; box-sizing: border-box; border: 1px solid #c9d5e5; border-radius: 10px; background: #f7f9fd; }
|
||||
.club-audit-card .van-field.club-audit-field .van-field__control { min-height: 150px; color: #253247; font-size: 12px; line-height: 22px; }
|
||||
.club-audit-card .van-field.club-audit-field .van-field__control::placeholder { color: #9aa7b8; }
|
||||
.club-audit-card .van-field.club-audit-field .van-field__word-limit { color: #718096; font-size: 12px; }
|
||||
.club-audit-card .van-field.club-audit-field::after { display: none; }
|
||||
.club-audit-actions { display: flex; column-gap: 10px; padding: 10px 12px calc(12px + env(safe-area-inset-bottom)); }
|
||||
.club-audit-actions .van-button { height: 40px; border-radius: 14px; font-size: 14px; }
|
||||
.club-audit-actions .van-button--primary { border-color: var(--club-primary); background: var(--club-primary); }
|
||||
.club-audit-actions .van-button--danger { border-color: #ff4d4f; background: #ff4d4f; }
|
||||
.club-list-skeleton { padding: 0; }
|
||||
.club-skeleton-card { margin-bottom: 12px; padding: 14px; background: #fff; border: 1px solid #e9eff7; border-radius: 12px; }
|
||||
.club-skeleton-line { height: 13px; margin-bottom: 12px; border-radius: 7px; background: linear-gradient(90deg, #f2f3f5 25%, #e6e8eb 37%, #f2f3f5 63%); background-size: 400% 100%; animation: club-skeleton-loading 1.4s ease infinite; }
|
||||
.club-skeleton-line--title { width: 46%; height: 16px; }
|
||||
.club-skeleton-line--short { width: 60%; }
|
||||
.club-empty { display: flex; min-height: 280px; padding: 46px 18px 36px; align-items: center; justify-content: center; box-sizing: border-box; flex-direction: column; text-align: center; }
|
||||
.club-empty img { display: block; width: 86%; max-width: 290px; height: auto; object-fit: contain; }
|
||||
.club-empty__title { margin-top: 14px; color: #50627a; font-size: 15px; font-weight: 600; line-height: 22px; }
|
||||
.club-empty__hint { margin-top: 5px; color: #9aa7b8; font-size: 12px; line-height: 18px; }
|
||||
@keyframes club-skeleton-loading { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak class="club-approval-page">
|
||||
<van-nav-bar title="社团审核" left-text="返回" left-arrow @click-left="onNavBack" fixed placeholder></van-nav-bar>
|
||||
<van-sticky offset-top="46px">
|
||||
<div class="club-approval-sticky">
|
||||
<van-search v-model="pageForm.searchKeyword" class="club-approval-search" placeholder="请输入姓名或者工号搜索" shape="round" clearable @search="doSearch" @clear="doSearch"></van-search>
|
||||
<van-dropdown-menu class="club-approval-filter" :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.mode" :options="modeOptions" :multiple="false" @change="doSearch"></van-dropdown-item>
|
||||
<!-- 全部工会筛选已按移动端审核页面要求隐藏,接口不再传 unionId。 -->
|
||||
<van-dropdown-item v-model="pageForm.approvalText" :options="approvalOptions" :multiple="false" @change="onApprovalFilterChange"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</div>
|
||||
</van-sticky>
|
||||
|
||||
<main class="club-approval-list-content">
|
||||
<table-list api="/platform/club/join/clubApproval/pageData" :page_form.sync="pageForm" ref="tableListRef" title="clubName" :show_loading_overlay="false" @ready="onReady" @loading-change="onLoadingChange">
|
||||
<template #header="{row}">
|
||||
<div class="club-card-header">
|
||||
<div class="club-card-header__heading"><div class="club-card-header__title">{{ row.userName || '--' }}</div><div class="club-card-header__sub">工号:{{ row.loginName || '--' }}</div></div>
|
||||
<enum-tag class="club-card-header__status" v-if="row.instanceState" :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message" size="small"></enum-tag>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot="{row}">
|
||||
<table-column label="社团名称">{{ row.clubName || '--' }}</table-column>
|
||||
<table-column label="所属工会">{{ row.unionName || '--' }}</table-column>
|
||||
<table-column label="申请类型">{{ row.mode ? '加入社团' : '退出社团' }}</table-column>
|
||||
<table-column label="申请时间">{{ row.applyDate || '--' }}</table-column>
|
||||
<table-column label="所属单位">{{ row.unitName || '--' }}</table-column>
|
||||
<table-column label="当前节点">{{ row.curTaskName || '--' }}</table-column>
|
||||
</template>
|
||||
<template #actions="{row}">
|
||||
<div class="action-btn" @click="onView(row)"><van-icon name="eye-o"></van-icon><span>查看</span></div>
|
||||
<div class="action-btn" v-if="row.taskState === 10" @click="onApproval(row)"><van-icon name="edit"></van-icon><span>审核</span></div>
|
||||
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)"><van-icon name="revoke"></van-icon><span>撤回</span></div>
|
||||
</template>
|
||||
<template #empty>
|
||||
<div v-if="listLoading" class="club-list-skeleton"><div v-for="item in 2" :key="item" class="club-skeleton-card"><div class="club-skeleton-line club-skeleton-line--title"></div><div class="club-skeleton-line"></div><div class="club-skeleton-line club-skeleton-line--short"></div></div></div>
|
||||
<div v-else class="club-empty"><img src="/assets/mobile/img/club/club-approval-empty.png" alt="暂无社团审核记录插画"><div class="club-empty__title">暂无社团审核记录</div><div class="club-empty__hint">当前筛选条件下暂时没有社团申请</div></div>
|
||||
</template>
|
||||
</table-list>
|
||||
</main>
|
||||
|
||||
<info ref="infoRef" page-key="club-approval" :merge-apply-info="true">
|
||||
<template v-if="showApprovalForm">
|
||||
<section class="club-audit-card">
|
||||
<h2 class="club-audit-card__title">{{ formData.taskName || '社团审核' }}</h2>
|
||||
<van-form ref="formRef">
|
||||
<van-field v-if="formData.mode === true" v-model="formData.tf_payed" class="club-audit-payment-field" name="tf_payed" label="缴费状态" :rules="[{ required: true, message: '请选择缴费状态' }]" required>
|
||||
<template #input>
|
||||
<van-radio-group v-model="formData.tf_payed" direction="horizontal"><van-radio name="0">未缴费</van-radio><van-radio name="1">已缴费</van-radio></van-radio-group>
|
||||
</template>
|
||||
</van-field>
|
||||
<p class="club-audit-field-label"><span class="club-audit-card__required">*</span>审批意见</p>
|
||||
<van-field v-model="formData.tf_opinion" class="club-audit-field" name="tf_opinion" type="textarea" rows="6" label="" placeholder="请输入审批意见" :rules="[{ required: true, message: '请填写审批意见' }]" maxlength="100" show-word-limit></van-field>
|
||||
</van-form>
|
||||
</section>
|
||||
<div class="club-audit-actions"><van-button :loading="formLoading" type="primary" block @click="handleTaskAction(1)">同意</van-button><van-button :loading="formLoading" type="danger" block @click="handleTaskAction(2)">拒绝</van-button><van-button :loading="formLoading" type="danger" block @click="handleTaskAction(6)">退回</van-button></div>
|
||||
</template>
|
||||
</info>
|
||||
<van-dialog :value="confirmVisible" title="提示" :message="confirmMessage" show-cancel-button :confirm-button-loading="formLoading" @confirm="confirmPendingAction" @cancel="closeConfirm"></van-dialog>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('../common/clubUserJoin.js'){}#-->
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
dicts: ['PROCESS_INSTANCE_STATE'],
|
||||
components: {info: clubUserJoin},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {pageNumber: 1, pageSize: 10, totalCount: 0, searchKeyword: '', name: null, approvalText: '0', approval: false, year: new Date().getFullYear(), mode: null},
|
||||
formData: {},
|
||||
showApprovalForm: false,
|
||||
modeOptions: [{text: '全部类型', value: null}, {text: '申请加入', value: true}, {text: '申请退出', value: false}],
|
||||
approvalOptions: [{text: '未审核', value: '0'}, {text: '已审核', value: '1'}],
|
||||
listLoading: true,
|
||||
formLoading: false,
|
||||
confirmVisible: false,
|
||||
pendingAction: '',
|
||||
pendingSubmitType: null,
|
||||
pendingRevokeRow: null,
|
||||
historyLayerUnsubscribe: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
confirmMessage() { return this.pendingAction === 'revoke' ? '您确定要撤回吗?' : '您确定要提交审核结果吗?'; }
|
||||
},
|
||||
created() {
|
||||
const manager = window.h5HistoryLayerManager;
|
||||
if (manager) {
|
||||
manager.ensureRegistered('club-approval');
|
||||
this.historyLayerUnsubscribe = manager.subscribe((layers) => {
|
||||
this.$set(this, 'confirmVisible', layers.includes('club-approval-confirm'));
|
||||
});
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.historyLayerUnsubscribe) { this.historyLayerUnsubscribe(); }
|
||||
const manager = window.h5HistoryLayerManager;
|
||||
if (manager) { manager.unregister('club-approval'); }
|
||||
},
|
||||
methods: {
|
||||
onNavBack() {
|
||||
const manager = window.h5HistoryLayerManager;
|
||||
if (manager && manager.stack.length) { manager.close(); return; }
|
||||
historyBack();
|
||||
},
|
||||
onReady() {
|
||||
this.doSearch();
|
||||
},
|
||||
onApprovalFilterChange(value) {
|
||||
// 下拉组件使用字符串,查询接口 approval 参数需转换为布尔值;默认 false 查询未审核记录。
|
||||
this.$set(this.pageForm, 'approval', value === '1');
|
||||
this.doSearch();
|
||||
},
|
||||
onLoadingChange(state) { this.$set(this, 'listLoading', state.loading); },
|
||||
onView(row) {
|
||||
this.$set(this, 'showApprovalForm', false);
|
||||
this.$refs.infoRef.onOpen(row, '社团申请详情');
|
||||
},
|
||||
onApproval(row) {
|
||||
this.$set(this, 'formData', {processTaskId: row.taskId, taskName: row.curTaskName, tf_payed: '0', userName: row.userName, mode: row.mode, tf_opinion: ''});
|
||||
this.$set(this, 'showApprovalForm', true);
|
||||
this.$refs.infoRef.onOpen(row, row.curTaskName || '社团审核');
|
||||
},
|
||||
openConfirm(action, submitType, row) {
|
||||
this.$set(this, 'pendingAction', action);
|
||||
this.$set(this, 'pendingSubmitType', submitType);
|
||||
this.$set(this, 'pendingRevokeRow', row);
|
||||
const manager = window.h5HistoryLayerManager;
|
||||
if (manager) { manager.open('club-approval-confirm'); return; }
|
||||
this.$set(this, 'confirmVisible', true);
|
||||
},
|
||||
closeConfirm(afterClose) {
|
||||
const manager = window.h5HistoryLayerManager;
|
||||
if (manager) { manager.close('club-approval-confirm', afterClose); return; }
|
||||
this.$set(this, 'confirmVisible', false);
|
||||
if (afterClose) { afterClose(); }
|
||||
},
|
||||
// 审批意见为空时先提示并触发字段校验,校验通过后才允许打开审核确认框。
|
||||
handleTaskAction(submitType) {
|
||||
const opinion = (this.formData.tf_opinion || '').trim();
|
||||
if (!opinion) {
|
||||
this.$toast('请填写审批意见');
|
||||
this.$refs.formRef.validate('tf_opinion').catch(() => {});
|
||||
return;
|
||||
}
|
||||
this.$set(this.formData, 'tf_opinion', opinion);
|
||||
this.$refs.formRef.validate().then(() => { this.openConfirm('submit', submitType, null); }).catch(() => {});
|
||||
},
|
||||
confirmPendingAction() {
|
||||
const action = this.pendingAction;
|
||||
const submitType = this.pendingSubmitType;
|
||||
const row = this.pendingRevokeRow;
|
||||
this.closeConfirm(() => {
|
||||
if (action === 'revoke') { this.revoke(row); } else { this.submitTaskAction(submitType); }
|
||||
});
|
||||
},
|
||||
submitTaskAction(submitType) {
|
||||
this.$set(this, 'formLoading', true);
|
||||
const taskData = Object.assign({}, this.formData, {submitType: submitType});
|
||||
this.$axios.post('/flow/common/executeTask', {data: JSON.stringify(taskData)}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
const afterClose = () => { this.$toast.success(res.msg); this.doSearch(); };
|
||||
const manager = window.h5HistoryLayerManager;
|
||||
if (manager) { manager.closeAll(afterClose); } else { this.$refs.infoRef.onClose(afterClose); }
|
||||
}
|
||||
}).finally(() => { this.$set(this, 'formLoading', false); });
|
||||
},
|
||||
onRevoke(row) { this.openConfirm('revoke', null, row); },
|
||||
revoke(row) {
|
||||
this.$set(this, 'formLoading', true);
|
||||
this.$axios.post('/flow/common/revokeTask', {taskId: row.taskId}).then((res) => {
|
||||
if (res.code === 0) { this.$toast.success(res.msg); this.doSearch(); }
|
||||
}).finally(() => { this.$set(this, 'formLoading', false); });
|
||||
},
|
||||
doSearch() {
|
||||
this.$nextTick(() => {
|
||||
this.pageForm.pageNumber = 1;
|
||||
this.pageForm.totalCount = 0;
|
||||
this.$refs.tableListRef.doSearch();
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,221 @@
|
||||
.club-user-join-popup {
|
||||
overflow: hidden;
|
||||
background: #f3f7fc;
|
||||
}
|
||||
|
||||
.club-user-join-detail {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
padding-top: 46px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
background: #f3f7fc;
|
||||
color: #1f2d3d;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.club-user-join-detail > .van-nav-bar {
|
||||
z-index: 20;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.club-user-join-detail > .van-nav-bar .van-icon,
|
||||
.club-user-join-detail > .van-nav-bar .van-nav-bar__text {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.club-user-join-detail__scroll {
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.club-user-join-detail__content {
|
||||
padding: 12px 15px calc(18px + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.club-user-join-card {
|
||||
margin-bottom: 11px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #e9eff7;
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
box-shadow: 0 3px 11px rgba(51, 87, 126, .08);
|
||||
}
|
||||
|
||||
.club-user-join-card__title {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 12px 14px 8px 21px;
|
||||
color: #354255;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.club-user-join-card__title::before {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
bottom: 11px;
|
||||
left: 12px;
|
||||
width: 2px;
|
||||
border-radius: 2px;
|
||||
background: #1989fa;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.club-user-join-card__grid {
|
||||
display: grid;
|
||||
padding: 0 14px;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.club-user-join-card__item {
|
||||
min-width: 0;
|
||||
padding: 0 10px 13px 0;
|
||||
}
|
||||
|
||||
.club-user-join-card__item--full {
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
.club-user-join-card__item span,
|
||||
.club-user-join-material > span {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
color: #8b9bb0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.club-user-join-card__item strong {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
color: #40526a;
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
line-height: 19px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.club-user-join-card__item--full strong {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.club-user-join-material {
|
||||
display: flex;
|
||||
padding: 0 14px;
|
||||
align-items: center;
|
||||
min-height: 40px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.club-user-join-material > span {
|
||||
flex: 0 0 82px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.club-user-join-material strong {
|
||||
color: #40526a;
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.club-user-join-material .van-image {
|
||||
width: 56px;
|
||||
height: 40px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #edf2f8;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.club-user-join-info-card .van-cell-group {
|
||||
margin: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.club-user-join-info-card .van-cell {
|
||||
min-height: 44px;
|
||||
padding: 10px 14px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.club-user-join-info-card .van-cell:not(:last-child)::after {
|
||||
right: 14px;
|
||||
left: 14px;
|
||||
border-color: #eef2f7;
|
||||
}
|
||||
|
||||
.club-user-join-info-card .van-cell__title {
|
||||
width: 102px;
|
||||
color: #596779;
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
flex: 0 0 102px;
|
||||
}
|
||||
|
||||
.club-user-join-info-card .van-cell__value {
|
||||
min-width: 0;
|
||||
color: #4f5d70;
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
text-align: left;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.club-user-join-info-card .club-user-join-info-long-cell {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.club-user-join-info-card .club-user-join-info-long-cell .van-cell__title {
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.club-user-join-info-card .club-user-join-info-long-cell .van-cell__value {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.club-user-join-info-image {
|
||||
display: block;
|
||||
width: 56px;
|
||||
height: 40px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #edf2f8;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.club-user-join-task-card .van-cell-group {
|
||||
margin: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.club-user-join-task-card .van-cell {
|
||||
min-height: 44px;
|
||||
padding: 10px 14px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.club-user-join-task-card .van-cell:not(:last-child)::after {
|
||||
right: 14px;
|
||||
left: 14px;
|
||||
border-color: #eef2f7;
|
||||
}
|
||||
|
||||
.club-user-join-task-card .van-cell__title {
|
||||
width: 102px;
|
||||
color: #596779;
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
flex: 0 0 102px;
|
||||
}
|
||||
|
||||
.club-user-join-task-card .van-cell__value {
|
||||
min-width: 0;
|
||||
color: #4f5d70;
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
text-align: left;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
const clubUserJoin = {
|
||||
template:
|
||||
/*language=HTML*/
|
||||
`
|
||||
<van-popup v-model="visible" position="right" :style="{ width: '100%', height: '100%' }" get-container="#app" class="club-user-join-popup" :close-on-click-overlay="false">
|
||||
<div class="club-user-join-detail">
|
||||
<van-nav-bar :title="detailTitle" left-text="返回" left-arrow fixed @click-left="onBack"></van-nav-bar>
|
||||
<div class="club-user-join-detail__scroll">
|
||||
<main class="club-user-join-detail__content">
|
||||
<section class="club-user-join-card club-user-join-info-card">
|
||||
<h3 class="club-user-join-card__title">申请信息</h3>
|
||||
<van-cell-group :border="false" v-if="mergeApplyInfo">
|
||||
<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.mobile || '--' }}</van-cell>
|
||||
<van-cell title="分工会">{{ viewData.unionName || '--' }}</van-cell>
|
||||
<van-cell title="部门">{{ viewData.unitName || '--' }}</van-cell>
|
||||
<van-cell title="性别">{{ viewData.sex || '--' }}</van-cell>
|
||||
<van-cell title="出生年月">{{ formatDate(viewData.birthday) }}</van-cell>
|
||||
<van-cell title="电子信箱">{{ viewData.email || '--' }}</van-cell>
|
||||
<van-cell title="职务">{{ viewData.position || viewData.governmentPosition || '--' }}</van-cell>
|
||||
<van-cell title="职称">{{ viewData.technicalTitle || viewData.jobTitle || '--' }}</van-cell>
|
||||
<van-cell title="学历 / 学位">{{ educationText }}</van-cell>
|
||||
<van-cell title="同时参加其他社团情况" class="club-user-join-info-long-cell"><div>{{ viewData.sameTimeJoinOtherClubSituation || '暂无' }}</div></van-cell>
|
||||
<van-cell title="文化、体育活动经历及获奖情况" class="club-user-join-info-long-cell"><div>{{ viewData.awardsExperience || '暂无' }}</div></van-cell>
|
||||
<van-cell title="照片" class="club-user-join-info-long-cell"><van-image v-if="viewData.avatar && viewData.avatar !== '[]'" :src="viewData.avatar" class="club-user-join-info-image" fit="cover"></van-image><span v-else>暂无</span></van-cell>
|
||||
<van-cell title="签字" class="club-user-join-info-long-cell"><van-image v-if="viewData.signature" :src="viewData.signature" class="club-user-join-info-image" fit="contain"></van-image><span v-else>暂无</span></van-cell>
|
||||
</van-cell-group>
|
||||
<div v-else class="club-user-join-card__grid">
|
||||
<div class="club-user-join-card__item"><span>社团名称</span><strong>{{ viewData.clubName || '--' }}</strong></div>
|
||||
<div class="club-user-join-card__item"><span>姓名</span><strong>{{ viewData.userName || '--' }}</strong></div>
|
||||
<div class="club-user-join-card__item"><span>工号</span><strong>{{ viewData.loginName || '--' }}</strong></div>
|
||||
<div class="club-user-join-card__item"><span>联系电话</span><strong>{{ viewData.mobile || '--' }}</strong></div>
|
||||
<div class="club-user-join-card__item"><span>分工会</span><strong>{{ viewData.unionName || '--' }}</strong></div>
|
||||
<div class="club-user-join-card__item"><span>部门</span><strong>{{ viewData.unitName || '--' }}</strong></div>
|
||||
</div>
|
||||
</section>
|
||||
<section v-if="!mergeApplyInfo" class="club-user-join-card">
|
||||
<h3 class="club-user-join-card__title">个人信息</h3>
|
||||
<div class="club-user-join-card__grid">
|
||||
<div class="club-user-join-card__item"><span>性别</span><strong>{{ viewData.sex || '--' }}</strong></div>
|
||||
<div class="club-user-join-card__item"><span>出生年月</span><strong>{{ formatDate(viewData.birthday) }}</strong></div>
|
||||
<div class="club-user-join-card__item"><span>电子信箱</span><strong>{{ viewData.email || '--' }}</strong></div>
|
||||
<div class="club-user-join-card__item"><span>职务</span><strong>{{ viewData.position || viewData.governmentPosition || '--' }}</strong></div>
|
||||
<div class="club-user-join-card__item"><span>职称</span><strong>{{ viewData.technicalTitle || viewData.jobTitle || '--' }}</strong></div>
|
||||
<div class="club-user-join-card__item"><span>学历 / 学位</span><strong>{{ educationText }}</strong></div>
|
||||
<div class="club-user-join-card__item club-user-join-card__item--full"><span>同时参加其他社团情况</span><strong>{{ viewData.sameTimeJoinOtherClubSituation || '暂无' }}</strong></div>
|
||||
<div class="club-user-join-card__item club-user-join-card__item--full"><span>文化、体育活动经历及获奖情况</span><strong>{{ viewData.awardsExperience || '暂无' }}</strong></div>
|
||||
</div>
|
||||
</section>
|
||||
<section v-if="!mergeApplyInfo" class="club-user-join-card">
|
||||
<h3 class="club-user-join-card__title">申请材料</h3>
|
||||
<div class="club-user-join-material">
|
||||
<span>照片</span>
|
||||
<van-image v-if="viewData.avatar && viewData.avatar !== '[]'" :src="viewData.avatar" fit="cover"></van-image>
|
||||
<strong v-else>暂无</strong>
|
||||
</div>
|
||||
<div class="club-user-join-material">
|
||||
<span>签字</span>
|
||||
<van-image v-if="viewData.signature" :src="viewData.signature" fit="contain"></van-image>
|
||||
<strong v-else>暂无</strong>
|
||||
</div>
|
||||
</section>
|
||||
<section v-for="(task, index) in doneTasks" :key="task.id || index" class="club-user-join-card club-user-join-task-card">
|
||||
<h3 class="club-user-join-card__title">{{ task.displayName || '审核节点' }}</h3>
|
||||
<van-cell-group :border="false" v-if="task.ext && 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 :border="false" v-else>
|
||||
<van-cell title="办理用户">{{ task.taskFormData && task.taskFormData.userName || '--' }}({{ task.taskFormData && 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 && task.ext.submitType"></dict-tag></van-cell>
|
||||
<van-cell title="办理意见"><div v-html="task.taskFormData && task.taskFormData.tf_opinion || '暂无'"></div></van-cell>
|
||||
</van-cell-group>
|
||||
</section>
|
||||
<slot></slot>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
`,
|
||||
dicts: ['PROCESS_TASK_SUBMIT_TYPE'],
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
detailTitle: '社团申请详情',
|
||||
viewData: {},
|
||||
doneTasks: [],
|
||||
row: null,
|
||||
historyLayerUnsubscribe: null
|
||||
}
|
||||
},
|
||||
props: {
|
||||
pageKey: {
|
||||
type: String,
|
||||
default: 'club-user-join-detail'
|
||||
},
|
||||
// 三个社团查看页启用后,将申请、个人及材料信息合并为同一张申请信息卡片。
|
||||
mergeApplyInfo: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
educationText() {
|
||||
const education = this.viewData.education || '';
|
||||
const degree = this.viewData.academicDegree || '';
|
||||
return education || degree ? education + (education && degree ? ' / ' : '') + degree : '--';
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const manager = window.h5HistoryLayerManager;
|
||||
if (manager) {
|
||||
manager.ensureRegistered(this.pageKey);
|
||||
this.historyLayerUnsubscribe = manager.subscribe((layers) => {
|
||||
this.$set(this, 'visible', layers.includes('club-user-join-detail'));
|
||||
});
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.historyLayerUnsubscribe) {
|
||||
this.historyLayerUnsubscribe();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onOpen(row, title) {
|
||||
this.$set(this, 'row', row);
|
||||
this.$set(this, 'detailTitle', title || '社团申请详情');
|
||||
this.$set(this, 'viewData', Object.assign({}, row || {}));
|
||||
this.$set(this, 'doneTasks', []);
|
||||
const manager = window.h5HistoryLayerManager;
|
||||
if (manager) {
|
||||
manager.open('club-user-join-detail');
|
||||
} else {
|
||||
this.$set(this, 'visible', true);
|
||||
}
|
||||
if (!this.row || !this.row.id) {
|
||||
return;
|
||||
}
|
||||
this.getInfo();
|
||||
this.getDoneTasks();
|
||||
},
|
||||
onClose(afterClose) {
|
||||
const manager = window.h5HistoryLayerManager;
|
||||
if (manager) {
|
||||
manager.close('club-user-join-detail', afterClose);
|
||||
return;
|
||||
}
|
||||
this.$set(this, 'visible', false);
|
||||
if (afterClose) {
|
||||
afterClose();
|
||||
}
|
||||
},
|
||||
onBack() {
|
||||
this.onClose();
|
||||
},
|
||||
formatDate(date) {
|
||||
return date ? this.$moment(date).format('YYYY-MM-DD') : '--';
|
||||
},
|
||||
getInfo() {
|
||||
this.$axios.post('/platform/club/join/mine/info', {id: this.row.id}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$set(this, 'viewData', Object.assign({}, this.viewData, res.data || {}));
|
||||
}
|
||||
})
|
||||
},
|
||||
getDoneTasks() {
|
||||
this.$axios.post('/flow/common/doneTasks', {bizId: this.row.id}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$set(this, 'doneTasks', res.data || []);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style id="style-club-user-join-h5">
|
||||
<!--#include('../common/clubUserJoin.css'){}#-->
|
||||
</style>
|
||||
|
||||
<style>
|
||||
#app { --club-primary: #1989fa; }
|
||||
.club-mine-page { min-height: 100vh; padding-bottom: calc(24px + env(safe-area-inset-bottom)); box-sizing: border-box; background: #f3f7fd; }
|
||||
.club-mine-page .van-nav-bar, .club-mine-page .van-sticky--fixed { background: #fff; }
|
||||
.club-mine-page .van-nav-bar__title { color: #172033; font-size: 16px; font-weight: 600; }
|
||||
.club-mine-page .van-nav-bar .van-icon, .club-mine-page .van-nav-bar__text { color: #1989fa; }
|
||||
.club-mine-sticky { padding: 22px 12px 1px; box-sizing: border-box; background: #f3f7fd; }
|
||||
.club-mine-search { margin: 0 0 8px; padding: 0; overflow: hidden; border-radius: 12px; background: #fff; box-shadow: 0 5px 16px rgba(43, 73, 112, .1); }
|
||||
.club-mine-search .van-search__content { height: 42px; padding-left: 12px; align-items: center; border-radius: 12px; background: #fff; }
|
||||
.club-mine-search .van-field__control { color: #263548; font-size: 14px; }
|
||||
.club-mine-search .van-field__control::placeholder { color: #a7b0bf; }
|
||||
.club-mine-filter { margin-bottom: 8px; overflow: hidden; border-radius: 10px; box-shadow: 0 5px 16px rgba(43, 73, 112, .08); }
|
||||
.club-mine-filter .van-dropdown-menu__bar, .club-mine-filter .van-dropdown-menu__item, .club-mine-filter .van-dropdown-menu__title { height: 44px; box-shadow: none; }
|
||||
.club-mine-filter .van-dropdown-menu__item { align-items: center; justify-content: center; }
|
||||
.club-mine-filter .van-dropdown-menu__title { display: inline-flex; align-items: center; color: #66758a; font-size: 14px; line-height: 20px; }
|
||||
.club-mine-filter .van-dropdown-menu__title--active, .club-mine-filter .van-dropdown-item__option--active, .club-mine-filter .van-dropdown-item__option--active .van-dropdown-item__icon { color: #1989fa; }
|
||||
.club-mine-filter .van-dropdown-item__content { width: calc(100% - 24px); margin: 0 12px; overflow: hidden; box-sizing: border-box; border-radius: 0 0 12px 12px; box-shadow: 0 10px 24px rgba(31, 65, 108, .14); }
|
||||
.club-mine-filter .van-dropdown-item__option { display: flex; min-height: 48px; padding: 0 16px; align-items: center; color: #46566c; font-size: 14px; }
|
||||
.club-mine-list-content { padding: 0 12px; }
|
||||
.club-mine-page .table-list-container { margin-top: 0; padding-bottom: 2px; }
|
||||
.club-mine-page .table-list-container .table-list-item { margin-bottom: 12px; padding: 14px; border: 1px solid #e9eff7; border-radius: 12px; box-shadow: 0 5px 16px rgba(43, 73, 112, .08); }
|
||||
.club-mine-page .empty-state { padding: 0; }
|
||||
.club-card-header { display: flex; margin-bottom: 8px; align-items: flex-start; justify-content: space-between; }
|
||||
.club-card-header__heading { min-width: 0; padding-right: 10px; flex: 1; }
|
||||
.club-card-header__title { overflow: hidden; color: #253247; font-size: 15px; font-weight: 600; line-height: 22px; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.club-card-header__sub { margin-top: 1px; color: #9ba6b6; font-size: 12px; line-height: 18px; }
|
||||
.club-card-header__status { display: inline-flex; flex: none; }
|
||||
.club-card-header__status .van-tag { min-height: 24px; padding: 3px 9px; border: 0; border-radius: 12px; box-sizing: border-box; font-size: 12px; line-height: 18px; }
|
||||
.club-mine-page .table-list-container .table-list-item .item-actions { margin-top: 10px; padding-top: 10px; border-top-color: #edf1f6; }
|
||||
.club-mine-page .table-list-container .table-list-item .action-btn { min-height: 28px; padding: 4px 11px; border-radius: 14px; color: #1989fa; background: #eaf4ff; font-size: 12px; line-height: 18px; }
|
||||
.club-mine-page .table-list-container .table-list-item .action-btn.delete { color: #f04444; background: #fff0f0; }
|
||||
.club-mine-page .table-list-container .table-list-item .action-btn .van-icon { margin-right: 5px; font-size: 13px; }
|
||||
.club-list-skeleton { padding: 0; }
|
||||
.club-skeleton-card { margin-bottom: 12px; padding: 14px; background: #fff; border: 1px solid #e9eff7; border-radius: 12px; }
|
||||
.club-skeleton-line { height: 13px; margin-bottom: 12px; border-radius: 7px; background: linear-gradient(90deg, #f2f3f5 25%, #e6e8eb 37%, #f2f3f5 63%); background-size: 400% 100%; animation: club-skeleton-loading 1.4s ease infinite; }
|
||||
.club-skeleton-line--title { width: 46%; height: 16px; }
|
||||
.club-skeleton-line--short { width: 60%; }
|
||||
.club-empty { display: flex; min-height: 280px; padding: 46px 18px 36px; align-items: center; justify-content: center; box-sizing: border-box; flex-direction: column; text-align: center; }
|
||||
.club-empty img { display: block; width: 86%; max-width: 290px; height: auto; object-fit: contain; }
|
||||
.club-empty__title { margin-top: 14px; color: #50627a; font-size: 15px; font-weight: 600; line-height: 22px; }
|
||||
.club-empty__hint { margin-top: 5px; color: #9aa7b8; font-size: 12px; line-height: 18px; }
|
||||
@keyframes club-skeleton-loading { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak class="club-mine-page">
|
||||
<van-nav-bar title="我的申请" left-text="返回" left-arrow @click-left="onNavBack" fixed placeholder></van-nav-bar>
|
||||
<van-sticky offset-top="46px">
|
||||
<div class="club-mine-sticky">
|
||||
<van-search v-model="pageForm.clubName" class="club-mine-search" placeholder="请输入社团名称搜索" shape="round" clearable @search="doSearch" @clear="doSearch"></van-search>
|
||||
<van-dropdown-menu class="club-mine-filter" :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>
|
||||
</div>
|
||||
</van-sticky>
|
||||
|
||||
<main class="club-mine-list-content">
|
||||
<table-list api="/platform/club/join/mine/pageData" :page_form.sync="pageForm" ref="tableListRef" title="clubName" :show_loading_overlay="false" @ready="doSearch" @loading-change="onLoadingChange">
|
||||
<template #header="{row}">
|
||||
<div v-if="row" class="club-card-header"><div class="club-card-header__heading"><div class="club-card-header__title">{{ row.userName || '--' }}</div><div class="club-card-header__sub">工号:{{ row.loginName || '--' }}</div></div><enum-tag class="club-card-header__status" v-if="row.instanceState" :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message" size="small"></enum-tag></div>
|
||||
</template>
|
||||
<template v-slot="{row}">
|
||||
<template v-if="row"><table-column label="社团名称">{{ row.clubName || '--' }}</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>
|
||||
<template #actions="{row}">
|
||||
<template v-if="row"><div class="action-btn" @click="onView(row)"><van-icon name="eye-o"></van-icon><span>查看</span></div><div class="action-btn" @click="onEdit(row)" v-if="(row.taskKey === 'startTask' || !row.instanceId) && row.mode === true"><van-icon name="edit"></van-icon><span>编辑</span></div><div class="action-btn" @click="exitSubmitAgain(row)" v-if="(row.taskKey === 'startTask' || !row.instanceId) && row.mode === false"><van-icon name="passed"></van-icon><span>提交</span></div><div class="action-btn delete" @click="onRevoke(row)" v-if="row.canRevoke"><van-icon name="revoke"></van-icon><span>撤回</span></div><div class="action-btn delete" @click="onDelete(row)" v-if="row.taskKey === 'startTask' || !row.instanceId"><van-icon name="delete-o"></van-icon><span>删除</span></div></template>
|
||||
</template>
|
||||
<template #empty>
|
||||
<div v-if="listLoading" class="club-list-skeleton"><div v-for="item in 2" :key="item" class="club-skeleton-card"><div class="club-skeleton-line club-skeleton-line--title"></div><div class="club-skeleton-line"></div><div class="club-skeleton-line club-skeleton-line--short"></div></div></div>
|
||||
<div v-else class="club-empty"><img src="/assets/mobile/img/club/club-approval-empty.png" alt="暂无社团申请记录插画"><div class="club-empty__title">暂无社团申请记录</div><div class="club-empty__hint">当前筛选条件下暂时没有社团申请</div></div>
|
||||
</template>
|
||||
</table-list>
|
||||
</main>
|
||||
|
||||
<info ref="infoRef" page-key="club-mine" :merge-apply-info="true"></info>
|
||||
<van-dialog :value="confirmVisible" title="提示" :message="confirmMessage" show-cancel-button :confirm-button-loading="formLoading" @confirm="confirmPendingAction" @cancel="closeConfirm"></van-dialog>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('../common/clubUserJoin.js'){}#-->
|
||||
new Vue({
|
||||
el: "#app", store, dicts: ['PROCESS_INSTANCE_STATE'], components: {info: clubUserJoin},
|
||||
data() { return {pageForm: {pageNumber: 1, pageSize: 10, totalCount: 0, year: new Date().getFullYear(), clubName: ''}, listLoading: true, formLoading: false, confirmVisible: false, pendingAction: '', pendingRow: null, historyLayerUnsubscribe: null} },
|
||||
computed: { confirmMessage() { if (this.pendingAction === 'revoke') { return '您确定要撤回吗?'; } if (this.pendingAction === 'delete') { return '确定要删除此申请吗?'; } return '您确定要提交申请吗?'; } },
|
||||
created() { const manager = window.h5HistoryLayerManager; if (manager) { manager.ensureRegistered('club-mine'); this.historyLayerUnsubscribe = manager.subscribe((layers) => { this.$set(this, 'confirmVisible', layers.includes('club-mine-confirm')); }); } },
|
||||
beforeDestroy() { if (this.historyLayerUnsubscribe) { this.historyLayerUnsubscribe(); } const manager = window.h5HistoryLayerManager; if (manager) { manager.unregister('club-mine'); } },
|
||||
methods: {
|
||||
onNavBack() { const manager = window.h5HistoryLayerManager; if (manager && manager.stack.length) { manager.close(); return; } historyBack(); },
|
||||
onLoadingChange(state) { this.$set(this, 'listLoading', state.loading); },
|
||||
openConfirm(action, row) { this.$set(this, 'pendingAction', action); this.$set(this, 'pendingRow', row); const manager = window.h5HistoryLayerManager; if (manager) { manager.open('club-mine-confirm'); return; } this.$set(this, 'confirmVisible', true); },
|
||||
closeConfirm(afterClose) { const manager = window.h5HistoryLayerManager; if (manager) { manager.close('club-mine-confirm', afterClose); return; } this.$set(this, 'confirmVisible', false); if (afterClose) { afterClose(); } },
|
||||
confirmPendingAction() { const action = this.pendingAction; const row = this.pendingRow; this.closeConfirm(() => { if (action === 'revoke') { this.revoke(row); } else if (action === 'delete') { this.deleteApplication(row); } else { this.submitAgain(row); } }); },
|
||||
exitSubmitAgain(row) { this.openConfirm('submitAgain', row); },
|
||||
submitAgain(row) { this.$set(this, 'formLoading', true); this.$axios.post('/platform/club/join/apply/info', {id: row.id}).then((res) => { if (res.code === 0) { return this.$axios.post('/platform/club/join/apply/submitAgain', {data: JSON.stringify(res.data), taskId: row.startTaskId}); } this.$toast.fail(res.msg); return null; }).then((res) => { if (res && res.code === 0) { this.$toast(res.msg); this.doSearch(); } }).finally(() => { this.$set(this, 'formLoading', false); }); },
|
||||
onRevoke(row) { this.openConfirm('revoke', row); },
|
||||
revoke(row) { this.$set(this, 'formLoading', true); this.$axios.post('/flow/common/revokeTask', {taskId: row.startTaskId}).then((res) => { if (res.code === 0) { this.$toast(res.msg); this.doSearch(); } }).finally(() => { this.$set(this, 'formLoading', false); }); },
|
||||
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.openConfirm('delete', row); },
|
||||
deleteApplication(row) { this.$set(this, 'formLoading', true); 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); } }).finally(() => { this.$set(this, 'formLoading', false); }); },
|
||||
doSearch() { this.$nextTick(() => { this.$set(this.pageForm, 'pageNumber', 1); this.$set(this.pageForm, 'totalCount', 0); this.$refs.tableListRef.doSearch(); }); }
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,117 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style id="style-club-user-join-h5">
|
||||
<!--#include('../common/clubUserJoin.css'){}#-->
|
||||
</style>
|
||||
|
||||
<style>
|
||||
#app { --club-primary: #1989fa; }
|
||||
.club-member-page { min-height: 100vh; padding-bottom: calc(24px + env(safe-area-inset-bottom)); box-sizing: border-box; background: #f3f7fd; }
|
||||
.club-member-page .van-nav-bar, .club-member-page .van-sticky--fixed { background: #fff; }
|
||||
.club-member-page .van-nav-bar__title { color: #172033; font-size: 16px; font-weight: 600; }
|
||||
.club-member-page .van-nav-bar .van-icon, .club-member-page .van-nav-bar__text { color: #1989fa; }
|
||||
.club-member-sticky { padding: 22px 12px 1px; box-sizing: border-box; background: #f3f7fd; }
|
||||
.club-member-search { margin: 0 0 8px; padding: 0; overflow: hidden; border-radius: 12px; background: #fff; box-shadow: 0 5px 16px rgba(43, 73, 112, .1); }
|
||||
.club-member-search .van-search__content { height: 42px; padding-left: 12px; align-items: center; border-radius: 12px; background: #fff; }
|
||||
.club-member-search .van-field__control { color: #263548; font-size: 14px; }
|
||||
.club-member-search .van-field__control::placeholder { color: #a7b0bf; }
|
||||
.club-member-list-content { padding: 0 12px; }
|
||||
.club-member-page .table-list-container { margin-top: 0; padding-bottom: 2px; }
|
||||
.club-member-page .table-list-container .table-list-item { margin-bottom: 12px; padding: 14px; border: 1px solid #e9eff7; border-radius: 12px; box-shadow: 0 5px 16px rgba(43, 73, 112, .08); }
|
||||
.club-member-page .empty-state { padding: 0; }
|
||||
.club-card-header { display: flex; margin-bottom: 8px; align-items: flex-start; justify-content: space-between; }
|
||||
.club-card-header__heading { min-width: 0; padding-right: 10px; flex: 1; }
|
||||
.club-card-header__title { overflow: hidden; color: #253247; font-size: 15px; font-weight: 600; line-height: 22px; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.club-card-header__sub { margin-top: 1px; color: #9ba6b6; font-size: 12px; line-height: 18px; }
|
||||
.club-card-header__status { display: inline-flex; flex: none; }
|
||||
.club-card-header__status.van-tag, .club-card-header__status .van-tag { min-height: 24px; padding: 3px 9px; border: 0; border-radius: 12px; box-sizing: border-box; font-size: 12px; line-height: 18px; }
|
||||
.club-member-page .table-list-container .table-list-item .item-actions { margin-top: 10px; padding-top: 10px; border-top-color: #edf1f6; }
|
||||
.club-member-page .table-list-container .table-list-item .action-btn { min-height: 28px; padding: 4px 11px; border-radius: 14px; color: #1989fa; background: #eaf4ff; font-size: 12px; line-height: 18px; }
|
||||
.club-member-page .table-list-container .table-list-item .action-btn.delete { color: #f04444; background: #fff0f0; }
|
||||
.club-member-page .table-list-container .table-list-item .action-btn .van-icon { margin-right: 5px; font-size: 13px; }
|
||||
.club-list-skeleton { padding: 0; }
|
||||
.club-skeleton-card { margin-bottom: 12px; padding: 14px; background: #fff; border: 1px solid #e9eff7; border-radius: 12px; }
|
||||
.club-skeleton-line { height: 13px; margin-bottom: 12px; border-radius: 7px; background: linear-gradient(90deg, #f2f3f5 25%, #e6e8eb 37%, #f2f3f5 63%); background-size: 400% 100%; animation: club-skeleton-loading 1.4s ease infinite; }
|
||||
.club-skeleton-line--title { width: 46%; height: 16px; }
|
||||
.club-skeleton-line--short { width: 60%; }
|
||||
.club-empty { display: flex; min-height: 280px; padding: 46px 18px 36px; align-items: center; justify-content: center; box-sizing: border-box; flex-direction: column; text-align: center; }
|
||||
.club-empty img { display: block; width: 86%; max-width: 290px; height: auto; object-fit: contain; }
|
||||
.club-empty__title { margin-top: 14px; color: #50627a; font-size: 15px; font-weight: 600; line-height: 22px; }
|
||||
.club-empty__hint { margin-top: 5px; color: #9aa7b8; font-size: 12px; line-height: 18px; }
|
||||
@keyframes club-skeleton-loading { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak class="club-member-page">
|
||||
<van-nav-bar title="我的社团" left-text="返回" left-arrow @click-left="onNavBack" fixed placeholder></van-nav-bar>
|
||||
<van-sticky offset-top="46px"><div class="club-member-sticky"><van-search v-model="pageForm.clubName" class="club-member-search" placeholder="请输入社团名称搜索" shape="round" clearable @search="doSearch" @clear="doSearch"></van-search></div></van-sticky>
|
||||
|
||||
<main class="club-member-list-content">
|
||||
<table-list api="/platform/club/join/mine/club/pageData" :page_form.sync="pageForm" ref="tableListRef" title="userName" :show_loading_overlay="false" @ready="doSearch" @loading-change="onLoadingChange">
|
||||
<template #header="{row}">
|
||||
<div v-if="row" class="club-card-header"><div class="club-card-header__heading"><div class="club-card-header__title">{{ row.userName || '--' }}</div><div class="club-card-header__sub">工号:{{ row.loginName || '--' }}</div></div><van-tag class="club-card-header__status" type="success" size="small">已完成</van-tag></div>
|
||||
</template>
|
||||
<template v-slot="{row}">
|
||||
<template v-if="row"><table-column label="社团名称">{{ row.clubName || '--' }}</table-column><table-column label="会长">{{ row.clubLeader || '--' }}</table-column><table-column label="秘书长">{{ row.clubSecretary || '--' }}</table-column><table-column label="当前人数">{{ row.currentPeopleNum || 0 }} 人</table-column></template>
|
||||
</template>
|
||||
<template #actions="{row}"><template v-if="row"><div class="action-btn" @click="onView(row)"><van-icon name="eye-o"></van-icon><span>查看</span></div><div class="action-btn delete" @click="onExit(row)"><van-icon name="revoke"></van-icon><span>申请退会</span></div></template></template>
|
||||
<template #empty>
|
||||
<div v-if="listLoading" class="club-list-skeleton"><div v-for="item in 2" :key="item" class="club-skeleton-card"><div class="club-skeleton-line club-skeleton-line--title"></div><div class="club-skeleton-line"></div><div class="club-skeleton-line club-skeleton-line--short"></div></div></div>
|
||||
<div v-else class="club-empty"><img src="/assets/mobile/img/club/club-approval-empty.png" alt="暂无社团记录插画"><div class="club-empty__title">暂无社团记录</div><div class="club-empty__hint">当前筛选条件下暂时没有加入的社团</div></div>
|
||||
</template>
|
||||
</table-list>
|
||||
</main>
|
||||
<van-popup v-model="clubDetailVisible" position="right" :style="{ width: '100%', height: '100%' }" get-container="#app" class="club-user-join-popup" :close-on-click-overlay="false">
|
||||
<div class="club-user-join-detail">
|
||||
<van-nav-bar title="社团详情" left-text="返回" left-arrow fixed @click-left="closeClubDetail"></van-nav-bar>
|
||||
<div class="club-user-join-detail__scroll">
|
||||
<main class="club-user-join-detail__content">
|
||||
<section class="club-user-join-card club-user-join-info-card">
|
||||
<h3 class="club-user-join-card__title">社团基础信息</h3>
|
||||
<van-cell-group :border="false">
|
||||
<van-cell title="社团名称">{{ clubDetail.clubName || '--' }}</van-cell>
|
||||
<van-cell title="成立时间">{{ clubDetail.foundTime || '--' }}</van-cell>
|
||||
<van-cell title="社团编码">{{ clubDetail.clubCode || '--' }}</van-cell>
|
||||
<van-cell title="社团类型"><dict-tag :options="dict.type.CLUB_REGISTER_TYPE" :value="clubDetail.clubType"></dict-tag></van-cell>
|
||||
<van-cell title="会长">{{ clubDetail.clubLeader || '--' }}</van-cell>
|
||||
<van-cell title="秘书长">{{ clubDetail.clubSecretary || '--' }}</van-cell>
|
||||
<van-cell title="当前人数">{{ clubDetail.currentPeopleNum || 0 }} 人</van-cell>
|
||||
<van-cell title="会费标准">{{ clubDetail.due || '--' }}</van-cell>
|
||||
<van-cell title="社团介绍" class="club-user-join-info-long-cell"><div v-if="hasClubContent(clubDetail.introduce)" v-html="clubDetail.introduce"></div><span v-else>暂无</span></van-cell>
|
||||
<van-cell title="社团宗旨" class="club-user-join-info-long-cell"><div v-if="hasClubContent(clubDetail.purpose)" v-html="clubDetail.purpose"></div><span v-else>暂无</span></van-cell>
|
||||
<van-cell title="社团章程" class="club-user-join-info-long-cell"><file-preview v-if="clubDetail.rulesFile && clubDetail.rulesFile.length" :files="clubDetail.rulesFile" complete_result></file-preview><span v-else>暂无</span></van-cell>
|
||||
<van-cell title="年度活动计划" class="club-user-join-info-long-cell"><file-preview v-if="clubDetail.yearPlanFile && clubDetail.yearPlanFile.length" :files="clubDetail.yearPlanFile" complete_result></file-preview><span v-else>暂无</span></van-cell>
|
||||
</van-cell-group>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
<van-dialog :value="confirmVisible" title="提示" :message="confirmMessage" show-cancel-button :confirm-button-loading="formLoading" @confirm="confirmExit" @cancel="closeConfirm"></van-dialog>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app", store, dicts: ['CLUB_REGISTER_TYPE'],
|
||||
data() { return {pageForm: {pageNumber: 1, pageSize: 10, totalCount: 0, clubName: ''}, listLoading: true, formLoading: false, clubDetailVisible: false, clubDetail: {}, confirmVisible: false, currentRow: null, historyLayerUnsubscribe: null} },
|
||||
computed: { confirmMessage() { return this.currentRow ? '您确定要申请退出“' + this.currentRow.clubName + '”吗?' : '您确定要申请退出该社团吗?'; } },
|
||||
created() { const manager = window.h5HistoryLayerManager; if (manager) { manager.ensureRegistered('club-mineclub'); this.historyLayerUnsubscribe = manager.subscribe((layers) => { this.$set(this, 'clubDetailVisible', layers.includes('club-mineclub-detail')); this.$set(this, 'confirmVisible', layers.includes('club-mineclub-confirm')); }); } },
|
||||
beforeDestroy() { if (this.historyLayerUnsubscribe) { this.historyLayerUnsubscribe(); } const manager = window.h5HistoryLayerManager; if (manager) { manager.unregister('club-mineclub'); } },
|
||||
methods: {
|
||||
onNavBack() { const manager = window.h5HistoryLayerManager; if (manager && manager.stack.length) { manager.close(); return; } historyBack(); },
|
||||
onLoadingChange(state) { this.$set(this, 'listLoading', state.loading); },
|
||||
onView(row) { this.$set(this, 'clubDetail', Object.assign({}, row || {})); const manager = window.h5HistoryLayerManager; if (manager) { manager.open('club-mineclub-detail'); return; } this.$set(this, 'clubDetailVisible', true); },
|
||||
closeClubDetail(afterClose) { const manager = window.h5HistoryLayerManager; if (manager) { manager.close('club-mineclub-detail', afterClose); return; } this.$set(this, 'clubDetailVisible', false); if (afterClose) { afterClose(); } },
|
||||
hasClubContent(value) { return value !== null && value !== undefined && String(value).replace(/<[^>]*>/g, '').replace(/ /gi, '').trim().length > 0; },
|
||||
onExit(row) { this.$set(this, 'currentRow', row); const manager = window.h5HistoryLayerManager; if (manager) { manager.open('club-mineclub-confirm'); return; } this.$set(this, 'confirmVisible', true); },
|
||||
closeConfirm(afterClose) { const manager = window.h5HistoryLayerManager; if (manager) { manager.close('club-mineclub-confirm', afterClose); return; } this.$set(this, 'confirmVisible', false); if (afterClose) { afterClose(); } },
|
||||
confirmExit() { const row = this.currentRow; this.closeConfirm(() => { this.$set(this, 'formLoading', true); this.$axios.post('/platform/club/join/apply/submit', {data: JSON.stringify(row), mode: false}).then((res) => { if (res.code === 0) { this.$toast(res.msg); const manager = window.h5HistoryLayerManager; if (manager) { manager.closeAll(() => { this.$pjaxReplace('/platform/club/join/mine/h5'); }); } else { this.$pjaxReplace('/platform/club/join/mine/h5'); } } }).finally(() => { this.$set(this, 'formLoading', false); }); }); },
|
||||
doSearch() { this.$nextTick(() => { this.$set(this.pageForm, 'pageNumber', 1); this.$set(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="primary" block @click="handleTaskAction(1)">同意</van-button>
|
||||
<van-button type="danger" block @click="handleTaskAction(20)">不同意</van-button>
|
||||
<van-button type="danger" block @click="handleTaskAction(6)">退回</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
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
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.$set(this.formData, "assetUseUserId", row.assetUseUserId || null)
|
||||
this.$set(this.formData, "assetUseName", row.assetUseUserName || null)
|
||||
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>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+479
@@ -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>
|
||||
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+170
@@ -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
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
+134
@@ -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>
|
||||
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+187
@@ -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="primary" @click="handleTaskAction(1)">同意申请</van-button>
|
||||
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
|
||||
<van-button type="danger" @click="handleTaskAction(6)">退回到发起人</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>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+189
@@ -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="primary" @click="handleTaskAction(1)">同意申请</van-button>
|
||||
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
|
||||
<van-button type="danger" @click="handleTaskAction(6)">退回到发起人</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>
|
||||
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+516
@@ -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,494 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<div class="honor-showcase">
|
||||
<van-nav-bar
|
||||
title="劳模先进"
|
||||
left-text="返回"
|
||||
left-arrow
|
||||
fixed
|
||||
placeholder
|
||||
@click-left="goBack"
|
||||
></van-nav-bar>
|
||||
|
||||
<div class="honor-tabs">
|
||||
<button
|
||||
type="button"
|
||||
class="honor-tab"
|
||||
:class="{ active: activeTab === 'labor' }"
|
||||
@click="switchTab('labor')">
|
||||
劳模风采
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="honor-tab"
|
||||
:class="{ active: activeTab === 'studio' }"
|
||||
@click="switchTab('studio')">
|
||||
创新工作室
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<section class="honor-intro">
|
||||
<div class="honor-intro__corner honor-intro__corner--left"></div>
|
||||
<div class="honor-intro__corner honor-intro__corner--right"></div>
|
||||
<p>一份坚守,淬炼出奋斗的生命价值;一份专注,迸发不断创新的发展动力。</p>
|
||||
<p>他们扎根岗位、追求卓越,以实干书写担当,用匠心点亮前行方向。</p>
|
||||
<p>致敬劳模先进,礼赞奋斗精神。</p>
|
||||
</section>
|
||||
|
||||
<van-loading v-if="loading" class="honor-loading" color="#fff">加载中...</van-loading>
|
||||
|
||||
<div v-else class="honor-list">
|
||||
<article v-for="item in honorList" :key="item.id" class="honor-card">
|
||||
<div class="honor-card__image-wrap">
|
||||
<img v-if="item.cover" class="honor-card__image" :src="item.cover" alt="">
|
||||
<div v-else class="honor-card__placeholder">
|
||||
<div class="honor-card__placeholder-title">{{ getDisplayName(item) }}</div>
|
||||
<div class="honor-card__placeholder-sub">劳模先进</div>
|
||||
</div>
|
||||
<div class="honor-card__name">{{ getDisplayName(item) }}</div>
|
||||
</div>
|
||||
<div class="honor-card__body">
|
||||
<div class="honor-card__gold-line"></div>
|
||||
<div class="honor-card__prize">《{{ item.prizeName || '荣誉奖项' }}》</div>
|
||||
<div class="honor-card__date" v-if="item.grantDate">授予时间:{{ item.grantDate }}</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<van-empty v-if="honorList.length === 0" image="search" description="暂无当年荣誉"></van-empty>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data: function () {
|
||||
return {
|
||||
activeTab: "labor",
|
||||
currentYear: new Date().getFullYear(),
|
||||
honorTypeList: [],
|
||||
honorTypeMap: {
|
||||
labor: null,
|
||||
studio: null
|
||||
},
|
||||
honorList: [],
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goBack: function () {
|
||||
this.returnHome()
|
||||
},
|
||||
returnHome: function () {
|
||||
if (window.store && typeof window.store.commit === "function") {
|
||||
window.store.commit("setActiveTarBar", "home")
|
||||
}
|
||||
if (!window.$ || !$.support || !$.support.pjax) {
|
||||
window.location.replace("/platform/h5/home")
|
||||
return
|
||||
}
|
||||
var fallbackTimer = window.setTimeout(function () {
|
||||
window.location.replace("/platform/h5/home")
|
||||
}, 1200)
|
||||
$(document).one("pjax:complete", function () {
|
||||
window.clearTimeout(fallbackTimer)
|
||||
})
|
||||
$(document).one("pjax:error pjax:timeout", function () {
|
||||
window.clearTimeout(fallbackTimer)
|
||||
window.location.replace("/platform/h5/home")
|
||||
})
|
||||
$.pjax({
|
||||
url: "/platform/h5/home",
|
||||
container: "#container",
|
||||
fragment: "#container",
|
||||
push: false,
|
||||
replace: true,
|
||||
timeout: 8000
|
||||
})
|
||||
},
|
||||
switchTab: function (tab) {
|
||||
if (this.activeTab === tab) {
|
||||
return
|
||||
}
|
||||
this.activeTab = tab
|
||||
this.listHonor()
|
||||
},
|
||||
getDisplayName: function (item) {
|
||||
if (this.activeTab === "studio") {
|
||||
return item.applyUnionName || item.unionName || item.userName || "创新工作室"
|
||||
}
|
||||
return item.userName || item.applyUnionName || item.unionName || "劳模先进"
|
||||
},
|
||||
getHonorTypes: function () {
|
||||
var self = this
|
||||
return this.$axios.post("/platform/honor/basic/settings/getHonorType").then(function (res) {
|
||||
if (res.code === 0) {
|
||||
self.honorTypeList = res.data || []
|
||||
self.honorTypeMap.labor = self.findHonorType("HONOR_SINGLE", "个人荣誉")
|
||||
self.honorTypeMap.studio = self.findHonorType("HONOR_LIST", "集体荣誉")
|
||||
}
|
||||
})
|
||||
},
|
||||
findHonorType: function (queryTypeCode, name) {
|
||||
var target = this.honorTypeList.find(function (item) {
|
||||
return item.queryTypeCode === queryTypeCode
|
||||
})
|
||||
if (!target) {
|
||||
target = this.honorTypeList.find(function (item) {
|
||||
return item.name === name
|
||||
})
|
||||
}
|
||||
return target || null
|
||||
},
|
||||
listHonor: function () {
|
||||
var self = this
|
||||
var type = this.activeTab === "studio" ? this.honorTypeMap.studio : this.honorTypeMap.labor
|
||||
if (!type) {
|
||||
this.honorList = []
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
this.$axios.post("/platform/honor/manage/h5Data", {
|
||||
year: this.currentYear,
|
||||
honorType: type.id,
|
||||
pageNumber: 1,
|
||||
pageSize: 50
|
||||
}).then(function (res) {
|
||||
if (res.code === 0) {
|
||||
var list = (res.data && res.data.list) || []
|
||||
self.honorList = list.map(function (item) {
|
||||
item.cover = ""
|
||||
item.photoId = self.getFirstPhotoId(item.photoFiles)
|
||||
return item
|
||||
})
|
||||
self.loadPhotoMap()
|
||||
} else {
|
||||
self.honorList = []
|
||||
}
|
||||
}).finally(function () {
|
||||
self.loading = false
|
||||
})
|
||||
},
|
||||
getFirstPhotoId: function (photoFiles) {
|
||||
var files = []
|
||||
if (Array.isArray(photoFiles)) {
|
||||
files = photoFiles
|
||||
} else if (photoFiles) {
|
||||
try {
|
||||
files = JSON.parse(photoFiles)
|
||||
} catch (e) {
|
||||
files = []
|
||||
}
|
||||
}
|
||||
if (!files.length) {
|
||||
return ""
|
||||
}
|
||||
var first = files[0]
|
||||
var data = first && first.response ? first.response.data : first
|
||||
if (!data) {
|
||||
return ""
|
||||
}
|
||||
data = String(data)
|
||||
return data.indexOf("=") > -1 ? data.substring(data.lastIndexOf("=") + 1) : data
|
||||
},
|
||||
loadPhotoMap: function () {
|
||||
var self = this
|
||||
var ids = this.honorList.map(function (item) {
|
||||
return item.photoId
|
||||
}).filter(function (id) {
|
||||
return !!id
|
||||
})
|
||||
if (!ids.length) {
|
||||
return
|
||||
}
|
||||
this.$axios.post("/platform/sys/file/previewFileData", { ids: JSON.stringify(ids) }).then(function (res) {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
var fileMap = {}
|
||||
;(res.data || []).forEach(function (file) {
|
||||
fileMap[file.id] = file.thumbnail || file.downloadPath || ""
|
||||
})
|
||||
self.honorList = self.honorList.map(function (item) {
|
||||
item.cover = fileMap[item.photoId] || ""
|
||||
return item
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
var self = this
|
||||
this.getHonorTypes().then(function () {
|
||||
self.listHonor()
|
||||
})
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
body {
|
||||
background: #c80019;
|
||||
}
|
||||
|
||||
.honor-showcase {
|
||||
min-height: 100vh;
|
||||
padding: 0 14px 28px;
|
||||
box-sizing: border-box;
|
||||
background:
|
||||
radial-gradient(circle at 50% 0, rgba(255, 113, 89, .42) 0, rgba(255, 113, 89, 0) 32%),
|
||||
linear-gradient(180deg, #d6001c 0%, #bd0018 56%, #a90016 100%);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.honor-showcase /deep/ .van-nav-bar {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.honor-showcase /deep/ .van-nav-bar__title {
|
||||
color: #20242a;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.honor-showcase /deep/ .van-nav-bar .van-icon,
|
||||
.honor-showcase /deep/ .van-nav-bar__text {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.honor-showcase /deep/ .van-hairline--bottom::after {
|
||||
border-color: #eef1f6;
|
||||
}
|
||||
|
||||
.honor-tabs {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: 76px;
|
||||
}
|
||||
|
||||
.honor-tab {
|
||||
position: relative;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: rgba(255, 247, 220, .76);
|
||||
font-size: 19px;
|
||||
font-weight: 700;
|
||||
line-height: 28px;
|
||||
padding: 0 8px 14px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.honor-tab.active {
|
||||
color: #fff6d9;
|
||||
}
|
||||
|
||||
.honor-tab.active::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 4px;
|
||||
width: 38px;
|
||||
height: 5px;
|
||||
border-radius: 999px;
|
||||
background: #ffe6a3;
|
||||
transform: translateX(-50%);
|
||||
box-shadow: 0 2px 8px rgba(255, 230, 163, .38);
|
||||
}
|
||||
|
||||
.honor-intro {
|
||||
position: relative;
|
||||
margin-bottom: 18px;
|
||||
padding: 20px 20px 46px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
color: #ffe9bd;
|
||||
background:
|
||||
linear-gradient(165deg, rgba(255, 255, 255, .12), rgba(255, 255, 255, 0) 46%),
|
||||
linear-gradient(180deg, #d73535 0%, #c9262f 100%);
|
||||
box-shadow: 0 10px 22px rgba(90, 0, 8, .22);
|
||||
}
|
||||
|
||||
.honor-intro::before,
|
||||
.honor-intro::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -30px;
|
||||
right: -30px;
|
||||
height: 58px;
|
||||
border: 5px solid rgba(255, 223, 151, .86);
|
||||
border-top: 0;
|
||||
border-radius: 0 0 50% 50%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.honor-intro::before {
|
||||
bottom: 14px;
|
||||
transform: rotate(-2deg);
|
||||
}
|
||||
|
||||
.honor-intro::after {
|
||||
bottom: -12px;
|
||||
opacity: .75;
|
||||
transform: rotate(2deg);
|
||||
}
|
||||
|
||||
.honor-intro p {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin: 0 0 9px;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.honor-intro p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.honor-intro__corner {
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-top: 3px solid rgba(255, 224, 161, .82);
|
||||
}
|
||||
|
||||
.honor-intro__corner--left {
|
||||
left: 14px;
|
||||
border-left: 3px solid rgba(255, 224, 161, .82);
|
||||
}
|
||||
|
||||
.honor-intro__corner--right {
|
||||
right: 14px;
|
||||
border-right: 3px solid rgba(255, 224, 161, .82);
|
||||
}
|
||||
|
||||
.honor-loading {
|
||||
margin-top: 36px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.honor-list {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.honor-card {
|
||||
margin-bottom: 18px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: #be0018;
|
||||
box-shadow: 0 10px 22px rgba(83, 0, 9, .28);
|
||||
}
|
||||
|
||||
.honor-card__image-wrap {
|
||||
position: relative;
|
||||
height: 206px;
|
||||
overflow: hidden;
|
||||
background: #e6b06d;
|
||||
}
|
||||
|
||||
.honor-card__image {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.honor-card__placeholder {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff5d8;
|
||||
background:
|
||||
radial-gradient(circle at 78% 30%, rgba(255, 221, 148, .36), rgba(255, 221, 148, 0) 26%),
|
||||
linear-gradient(140deg, #d93a31 0%, #b60018 100%);
|
||||
}
|
||||
|
||||
.honor-card__placeholder-title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.honor-card__placeholder-sub {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
letter-spacing: 0;
|
||||
color: rgba(255, 245, 216, .82);
|
||||
}
|
||||
|
||||
.honor-card__image-wrap::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 58px;
|
||||
background: linear-gradient(165deg, rgba(177, 0, 24, .86) 0%, rgba(177, 0, 24, .74) 62%, rgba(177, 0, 24, .1) 63%);
|
||||
}
|
||||
|
||||
.honor-card__name {
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
bottom: 16px;
|
||||
z-index: 1;
|
||||
color: #fff;
|
||||
font-size: 22px;
|
||||
line-height: 28px;
|
||||
font-weight: 800;
|
||||
text-shadow: 0 2px 8px rgba(89, 0, 12, .32);
|
||||
}
|
||||
|
||||
.honor-card__body {
|
||||
position: relative;
|
||||
min-height: 82px;
|
||||
padding: 22px 20px 20px;
|
||||
box-sizing: border-box;
|
||||
color: #ffe5ad;
|
||||
background:
|
||||
radial-gradient(circle at 92% 14%, rgba(255, 230, 168, .4), rgba(255, 230, 168, 0) 16%),
|
||||
#be0018;
|
||||
}
|
||||
|
||||
.honor-card__body::after {
|
||||
content: "★";
|
||||
position: absolute;
|
||||
right: 18px;
|
||||
top: -20px;
|
||||
color: #ffd886;
|
||||
font-size: 42px;
|
||||
text-shadow: 0 3px 8px rgba(85, 0, 9, .28);
|
||||
transform: rotate(-12deg);
|
||||
}
|
||||
|
||||
.honor-card__gold-line {
|
||||
width: 44px;
|
||||
height: 3px;
|
||||
border-radius: 999px;
|
||||
background: #e7b13c;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.honor-card__prize {
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 700;
|
||||
color: #ffe5ad;
|
||||
}
|
||||
|
||||
.honor-card__date {
|
||||
margin-top: 5px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
color: rgba(255, 229, 173, .72);
|
||||
}
|
||||
|
||||
.honor-showcase /deep/ .van-empty__description {
|
||||
color: rgba(255, 255, 255, .78);
|
||||
}
|
||||
`
|
||||
})
|
||||
</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;
|
||||
}
|
||||
`
|
||||
}
|
||||
+190
@@ -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="primary" block @click="handleTaskAction(1)">同意</van-button>
|
||||
<van-button type="danger" block @click="handleTaskAction(20)">不同意</van-button>
|
||||
<van-button type="danger" block @click="handleTaskAction(6)">退回</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,224 @@
|
||||
<!--#
|
||||
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"
|
||||
:disabled="leaveLoading || isMeetingHandled(item)" :loading="leaveLoading"
|
||||
@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"
|
||||
:disabled="leaveLoading || isMeetingHandled(item) || isSignDisabled(item.startTime)"
|
||||
@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: {},
|
||||
leaveLoading: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 已请假或已签到后同时禁用请假、签到按钮,保证移动端与PC端状态一致。
|
||||
isMeetingHandled(timePeriod) {
|
||||
return timePeriod.joinStatus === false || timePeriod.signStatus === true
|
||||
},
|
||||
// 场次开始前禁用签到,避免用户在会议开始前提交签到操作。
|
||||
isSignDisabled(startTime) {
|
||||
return this.$moment().isBefore(this.$moment(startTime))
|
||||
},
|
||||
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.leaveLoading = true
|
||||
this.$axios.post("/platform/meeting/mine/leave", {
|
||||
periodId: this.periodRow.id,
|
||||
leaveReason: this.leaveReason,
|
||||
})
|
||||
.then((res) => {
|
||||
this.$toast(res.msg)
|
||||
if (res.code === 0) {
|
||||
done()
|
||||
this.doSearch()
|
||||
this.reasonVisible = false
|
||||
this.leaveVisible = false
|
||||
} else {
|
||||
done(false)
|
||||
}
|
||||
}).catch(() => {
|
||||
done(false)
|
||||
}).finally(() => {
|
||||
// 请假请求结束后恢复按钮状态,接口失败时允许用户修正事由后重新提交。
|
||||
this.leaveLoading = false
|
||||
})
|
||||
}
|
||||
} else {
|
||||
done()
|
||||
}
|
||||
},
|
||||
onLeave(row) {
|
||||
if (this.isMeetingHandled(row)) {
|
||||
this.$toast(row.signStatus === true ? '您已签到,不能请假' : '您已请假,请勿重复操作')
|
||||
return
|
||||
}
|
||||
if(!row.canLeave) {
|
||||
this.$toast('该场次不能请假')
|
||||
return
|
||||
}
|
||||
this.periodRow = row
|
||||
this.reasonVisible = true
|
||||
},
|
||||
onSign(row) {
|
||||
if (this.isMeetingHandled(row)) {
|
||||
this.$toast(row.signStatus === true ? '您已签到,请勿重复操作' : '您已请假,不能签到')
|
||||
return
|
||||
}
|
||||
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>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+190
@@ -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="primary" block @click="handleTaskAction(1)">同意</van-button>
|
||||
<van-button type="danger" block @click="handleTaskAction(20)">不同意</van-button>
|
||||
<van-button type="danger" block @click="handleTaskAction(6)">退回</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>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+464
@@ -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>
|
||||
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+136
@@ -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>
|
||||
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+185
@@ -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 type="primary" @click="handleTaskAction(1)">同意申请</van-button>
|
||||
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
|
||||
<van-button @click="handleTaskAction(6)">退回到发起人</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>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+185
@@ -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 type="primary" @click="handleTaskAction(1)">同意申请</van-button>
|
||||
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
|
||||
<van-button @click="handleTaskAction(6)">退回到发起人</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
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
+185
@@ -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 type="primary" @click="handleTaskAction(1)">同意申请</van-button>
|
||||
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
|
||||
<van-button @click="handleTaskAction(6)">退回到发起人</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>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+207
@@ -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 type="primary" @click="openHandleTaskAction">同意申请</van-button>
|
||||
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
|
||||
<van-button @click="handleTaskAction(6)">退回到发起人</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>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+185
@@ -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 type="primary" @click="handleTaskAction(1)">同意申请</van-button>
|
||||
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
|
||||
<van-button @click="handleTaskAction(6)">退回到发起人</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>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+185
@@ -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 type="primary" @click="handleTaskAction(1)">同意申请</van-button>
|
||||
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
|
||||
<van-button @click="handleTaskAction(6)">退回到发起人</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,535 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak class="qsv-h5-page">
|
||||
<div class="qsv-h5-header">
|
||||
<div class="qsv-h5-nav">
|
||||
<button class="qsv-h5-back-btn" @click="historyBack">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</button>
|
||||
<div class="qsv-h5-nav-title">问卷服务</div>
|
||||
<div class="qsv-h5-nav-placeholder"></div>
|
||||
</div>
|
||||
<div class="qsv-h5-search-row">
|
||||
<van-search
|
||||
v-model="pageForm.title"
|
||||
shape="round"
|
||||
background="transparent"
|
||||
placeholder="搜索标题名称"
|
||||
clearable
|
||||
@search="onRefresh"
|
||||
@clear="onRefresh">
|
||||
</van-search>
|
||||
<button class="qsv-h5-search-btn" @click="onRefresh">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="qsv-h5-filter-row">
|
||||
<button
|
||||
v-for="item in categoryOptions"
|
||||
:key="item.value"
|
||||
:class="['qsv-h5-filter-btn', pageForm.category === item.value ? 'active' : '']"
|
||||
@click="changeCategory(item.value)">
|
||||
<i :class="pageForm.category === item.value ? 'fa fa-check-circle' : 'fa fa-circle-o'"></i>
|
||||
<span>{{item.label}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<van-pull-refresh v-model="refreshing" @refresh="onRefresh" class="qsv-h5-list-wrap">
|
||||
<van-list v-model="loading" :finished="finished" finished-text="暂无更多内容" @load="onLoad">
|
||||
<div
|
||||
v-for="row in list"
|
||||
:key="row.id"
|
||||
class="qsv-h5-card"
|
||||
@click="onEnter(row)">
|
||||
<div class="qsv-h5-cover">
|
||||
<img :src="row.cover || defaultCover" alt="">
|
||||
</div>
|
||||
<div class="qsv-h5-card-body">
|
||||
<div class="qsv-h5-title-row">
|
||||
<div class="qsv-h5-title">{{row.title}}</div>
|
||||
<div class="qsv-h5-answered" v-if="row.answeredText || row.isAnswered">{{row.answeredText || getAnsweredText(row.category)}}</div>
|
||||
</div>
|
||||
<div class="qsv-h5-meta-row">
|
||||
<div class="qsv-h5-type">
|
||||
<i :class="getCategoryIcon(row.category)"></i>
|
||||
<span>{{getCategoryText(row.category)}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qsv-h5-time">
|
||||
<div>开始时间:{{formatDateTime(row.startTime)}}</div>
|
||||
<div>结束时间:{{formatDateTime(row.endTime)}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<van-empty v-if="!loading && list.length === 0" description="暂无内容"></van-empty>
|
||||
</van-list>
|
||||
</van-pull-refresh>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
dicts: ['ACTIVITY_QSV_CATEGORY'],
|
||||
store,
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
requesting: false,
|
||||
finished: false,
|
||||
refreshing: false,
|
||||
cacheRestored: false,
|
||||
list: [],
|
||||
defaultCover: "/assets/mobile/svg/qsv/icon.svg",
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
title: "",
|
||||
category: ""
|
||||
},
|
||||
categoryOptions: [
|
||||
{label: "全部", value: ""},
|
||||
{label: "答题", value: "QUIZ"},
|
||||
{label: "问卷", value: "SURVEY"},
|
||||
{label: "投票", value: "VOTE"}
|
||||
],
|
||||
categoryPaths: {
|
||||
QUIZ: "/platform/h5/qsv/quiz",
|
||||
SURVEY: "/platform/h5/qsv/survey",
|
||||
VOTE: "/platform/h5/qsv/vote"
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
historyBack() {
|
||||
this.$pjaxReplace('/platform/h5/home')
|
||||
},
|
||||
|
||||
changeCategory(category) {
|
||||
if (this.pageForm.category === category) {
|
||||
return
|
||||
}
|
||||
this.pageForm.category = category
|
||||
this.onRefresh()
|
||||
},
|
||||
|
||||
onRefresh() {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.list = []
|
||||
this.finished = false
|
||||
this.clearListCache()
|
||||
this.onLoad()
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
if (this.requesting || this.finished) {
|
||||
return
|
||||
}
|
||||
this.requesting = true
|
||||
this.loading = true
|
||||
this.$axios.post("/platform/h5/qsv/pageData", this.pageForm).then((res) => {
|
||||
if (res.code === 0) {
|
||||
const pageData = res.data || {}
|
||||
const rows = pageData.list || []
|
||||
this.list = this.list.concat(rows)
|
||||
this.pageForm.totalCount = pageData.totalCount || 0
|
||||
if (this.list.length >= this.pageForm.totalCount || rows.length === 0) {
|
||||
this.finished = true
|
||||
}
|
||||
this.pageForm.pageNumber++
|
||||
this.saveListCache()
|
||||
}
|
||||
}).finally(() => {
|
||||
this.requesting = false
|
||||
this.loading = false
|
||||
this.refreshing = false
|
||||
})
|
||||
},
|
||||
|
||||
refreshListSilently() {
|
||||
if (this.requesting) {
|
||||
return
|
||||
}
|
||||
const requestForm = Object.assign({}, this.pageForm, {
|
||||
pageNumber: 1
|
||||
})
|
||||
this.requesting = true
|
||||
this.$axios.post("/platform/h5/qsv/pageData", requestForm).then((res) => {
|
||||
if (res.code === 0) {
|
||||
const pageData = res.data || {}
|
||||
const rows = pageData.list || []
|
||||
this.list = rows
|
||||
this.pageForm = Object.assign({}, this.pageForm, {
|
||||
pageNumber: 2,
|
||||
totalCount: pageData.totalCount || 0
|
||||
})
|
||||
this.finished = rows.length >= this.pageForm.totalCount || rows.length === 0
|
||||
this.saveListCache()
|
||||
}
|
||||
}).finally(() => {
|
||||
this.requesting = false
|
||||
this.loading = false
|
||||
this.refreshing = false
|
||||
})
|
||||
},
|
||||
|
||||
getCategoryText(category) {
|
||||
const map = {
|
||||
QUIZ: "答题",
|
||||
SURVEY: "问卷",
|
||||
VOTE: "投票"
|
||||
}
|
||||
return map[category] || "活动"
|
||||
},
|
||||
|
||||
getCategoryIcon(category) {
|
||||
const map = {
|
||||
QUIZ: "fa fa-check-square-o",
|
||||
SURVEY: "fa fa-list-alt",
|
||||
VOTE: "fa fa-bar-chart"
|
||||
}
|
||||
return map[category] || "fa fa-tags"
|
||||
},
|
||||
|
||||
getAnsweredText(category) {
|
||||
const map = {
|
||||
QUIZ: "已答题",
|
||||
SURVEY: "已填写",
|
||||
VOTE: "已投票"
|
||||
}
|
||||
return map[category] || "已完成"
|
||||
},
|
||||
|
||||
formatDateTime(value) {
|
||||
if (!value) {
|
||||
return "-"
|
||||
}
|
||||
return this.$moment(value).format("YYYY-MM-DD HH:mm")
|
||||
},
|
||||
|
||||
onEnter(item) {
|
||||
const {startTime} = item
|
||||
if (this.$moment(startTime).unix() > this.$moment().unix()) {
|
||||
this.$toast("未开始")
|
||||
return
|
||||
}
|
||||
|
||||
const path = this.categoryPaths[item.category]
|
||||
if (path) {
|
||||
this.saveListCache()
|
||||
pjaxReplace(path + "?id=" + item.id)
|
||||
}
|
||||
},
|
||||
|
||||
getCacheKey() {
|
||||
return "qsv:h5:list"
|
||||
},
|
||||
|
||||
saveListCache() {
|
||||
try {
|
||||
sessionStorage.setItem(this.getCacheKey(), JSON.stringify({
|
||||
time: Date.now(),
|
||||
list: this.list,
|
||||
pageForm: this.pageForm,
|
||||
finished: this.finished
|
||||
}))
|
||||
} catch (e) {
|
||||
}
|
||||
},
|
||||
|
||||
restoreListCache() {
|
||||
try {
|
||||
const cacheText = sessionStorage.getItem(this.getCacheKey())
|
||||
if (!cacheText) {
|
||||
return
|
||||
}
|
||||
const cache = JSON.parse(cacheText)
|
||||
if (!cache || Date.now() - cache.time > 5 * 60 * 1000) {
|
||||
this.clearListCache()
|
||||
return
|
||||
}
|
||||
this.list = cache.list || []
|
||||
this.pageForm = Object.assign({}, this.pageForm, cache.pageForm || {})
|
||||
this.finished = !!cache.finished
|
||||
this.cacheRestored = this.list.length > 0
|
||||
} catch (e) {
|
||||
this.clearListCache()
|
||||
}
|
||||
},
|
||||
|
||||
clearListCache() {
|
||||
try {
|
||||
sessionStorage.removeItem(this.getCacheKey())
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.restoreListCache()
|
||||
},
|
||||
mounted() {
|
||||
if (this.cacheRestored) {
|
||||
setTimeout(() => {
|
||||
this.refreshListSilently()
|
||||
}, 200)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.qsv-h5-page {
|
||||
min-height: 100vh;
|
||||
background: #f4f8ff;
|
||||
padding-bottom: 18px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.qsv-h5-header {
|
||||
padding: 10px 14px 16px;
|
||||
background: linear-gradient(180deg, #1688f8 0%, #0f83ee 100%);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.qsv-h5-nav {
|
||||
height: 38px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.qsv-h5-back-btn,
|
||||
.qsv-h5-nav-placeholder {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.qsv-h5-back-btn {
|
||||
border: 0;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, .16);
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 24px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.qsv-h5-nav-title {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.qsv-h5-search-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.qsv-h5-header .van-search {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.qsv-h5-header .van-search__content {
|
||||
background: rgba(255, 255, 255, .92);
|
||||
}
|
||||
|
||||
.qsv-h5-search-btn {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border: 1px solid rgba(255, 255, 255, .45);
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, .18);
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
font-size: 18px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.qsv-h5-filter-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
margin-top: 12px;
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
|
||||
.qsv-h5-filter-row::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.qsv-h5-filter-btn {
|
||||
height: 32px;
|
||||
width: 100%;
|
||||
padding: 0 6px;
|
||||
border: 0;
|
||||
border-radius: 17px;
|
||||
background: rgba(255, 255, 255, .92);
|
||||
color: #1688f8;
|
||||
font-size: 14px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.qsv-h5-filter-btn.active {
|
||||
background: #ffffff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.qsv-h5-filter-btn i {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.qsv-h5-list-wrap {
|
||||
min-height: calc(100vh - 170px);
|
||||
padding: 14px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.qsv-h5-card {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
padding: 14px;
|
||||
margin-bottom: 14px;
|
||||
background: #ffffff;
|
||||
border-radius: 13px;
|
||||
box-shadow: 0 8px 24px rgba(35, 102, 168, .1);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.qsv-h5-cover {
|
||||
width: 116px;
|
||||
height: 87px;
|
||||
aspect-ratio: 4 / 3;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: #eaf2ff;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.qsv-h5-cover img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.qsv-h5-card-body {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
.qsv-h5-title-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.qsv-h5-title {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
color: #1f2f46;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1.35;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.qsv-h5-answered {
|
||||
height: 22px;
|
||||
min-width: 50px;
|
||||
padding: 0 8px;
|
||||
border: 1px solid #19a05f;
|
||||
border-radius: 11px;
|
||||
background: #f0fff8;
|
||||
color: #149356;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.qsv-h5-meta-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
.qsv-h5-type {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
height: 20px;
|
||||
padding: 0 6px;
|
||||
border: 1px solid #ff9f43;
|
||||
border-radius: 4px;
|
||||
background: #fff7ec;
|
||||
color: #f28b18;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
line-height: 18px;
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.qsv-h5-type i {
|
||||
color: #f28b18;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.qsv-h5-time {
|
||||
color: #71829b;
|
||||
font-size: 12px;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
@media (max-width: 360px) {
|
||||
.qsv-h5-card {
|
||||
gap: 10px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.qsv-h5-cover {
|
||||
width: 96px;
|
||||
height: 72px;
|
||||
}
|
||||
|
||||
.qsv-h5-title {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,474 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" :title="pageTitle" placeholder fixed></van-nav-bar>
|
||||
|
||||
<div class="container" :style="{'padding-bottom': answerRecord.isFinish ? 0 : '84px'}">
|
||||
<div class="quiz-hero" :style="heroStyle">
|
||||
<div class="quiz-hero-mask">
|
||||
<div class="timer" v-if="activity.timeLimit > 0 && !answerRecord.isFinish && !isEnd">
|
||||
⏰ {{ remainingTime }}s
|
||||
</div>
|
||||
<h2 class="quiz-title">{{ activity.title }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="quiz-card-scroll" 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
|
||||
},
|
||||
pageTitle() {
|
||||
return this.getCategoryPageTitle(this.activity && this.activity.category, "在线答题")
|
||||
},
|
||||
heroStyle() {
|
||||
if (this.activity && this.activity.cover) {
|
||||
return {
|
||||
backgroundImage: "url(" + this.activity.cover + ")"
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getCategoryPageTitle(category, defaultTitle) {
|
||||
const titleMap = {
|
||||
QUIZ: "在线答题",
|
||||
SURVEY: "问卷调查",
|
||||
VOTE: "投票"
|
||||
}
|
||||
return titleMap[category] || defaultTitle
|
||||
},
|
||||
//获取活动、题目
|
||||
listSubjects() {
|
||||
this.$axios.post("/platform/h5/qsv/quiz/subjects", {activityId: this.id}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.activity = res.data.activity
|
||||
// 历史链接可能误将投票或问卷指向答题页,按活动实际类型跳转到对应的移动端入口。
|
||||
if (this.activity.category === "VOTE") {
|
||||
pjaxReplace("/platform/h5/qsv/vote?id=" + this.id)
|
||||
return
|
||||
}
|
||||
if (this.activity.category === "SURVEY") {
|
||||
pjaxReplace("/platform/h5/qsv/survey?id=" + this.id)
|
||||
return
|
||||
}
|
||||
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;
|
||||
background: #f4f8ff;
|
||||
height: calc(100vh - 46px);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/deep/ .quiz-hero {
|
||||
flex: 0 0 auto;
|
||||
min-height: 170px;
|
||||
background: linear-gradient(135deg, #1688f8, #0a55c5);
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
margin: 12px 12px 14px;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 8px 24px rgba(35, 102, 168, .14);
|
||||
}
|
||||
|
||||
/deep/ .quiz-hero-mask {
|
||||
min-height: 170px;
|
||||
padding: 24px 20px 22px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
box-sizing: border-box;
|
||||
background: linear-gradient(180deg, rgba(0, 0, 0, .16), rgba(0, 0, 0, .56));
|
||||
}
|
||||
|
||||
/deep/ .quiz-title {
|
||||
margin: 0;
|
||||
color: #fff;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
line-height: 1.35;
|
||||
text-shadow: 0 2px 8px rgba(0, 0, 0, .28);
|
||||
}
|
||||
|
||||
.quiz-card-scroll {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
padding: 0 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.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 {
|
||||
align-self: flex-start;
|
||||
margin-bottom: 12px;
|
||||
padding: 5px 10px;
|
||||
border-radius: 14px;
|
||||
background: rgba(255, 255, 255, .22);
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
backdrop-filter: blur(6px);
|
||||
}
|
||||
|
||||
.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,364 @@
|
||||
<!--#
|
||||
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'}">
|
||||
<div class="quiz-hero" :style="heroStyle">
|
||||
<div class="quiz-hero-mask">
|
||||
<h2 class="quiz-title">{{ activity.title }}</h2>
|
||||
<div class="quiz-score">
|
||||
<span>{{totalScore}}</span>
|
||||
<em>分</em>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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
|
||||
},
|
||||
heroStyle() {
|
||||
if (this.activity && this.activity.cover) {
|
||||
return {
|
||||
backgroundImage: "url(" + this.activity.cover + ")"
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
},
|
||||
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;
|
||||
background: #f4f8ff;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/deep/ .quiz-hero {
|
||||
min-height: 190px;
|
||||
background: linear-gradient(135deg, #1688f8, #0a55c5);
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
margin: 12px 12px 14px;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 8px 24px rgba(35, 102, 168, .14);
|
||||
}
|
||||
|
||||
/deep/ .quiz-hero-mask {
|
||||
min-height: 190px;
|
||||
padding: 28px 20px 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
box-sizing: border-box;
|
||||
background: linear-gradient(180deg, rgba(0, 0, 0, .18), rgba(0, 0, 0, .58));
|
||||
}
|
||||
|
||||
/deep/ .quiz-title {
|
||||
margin: 0 0 14px;
|
||||
color: #fff;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
line-height: 1.35;
|
||||
text-shadow: 0 2px 8px rgba(0, 0, 0, .28);
|
||||
}
|
||||
|
||||
/deep/ .quiz-score {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
color: #fff;
|
||||
text-shadow: 0 2px 10px rgba(0, 0, 0, .3);
|
||||
}
|
||||
|
||||
/deep/ .quiz-score span {
|
||||
font-size: 48px;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
/deep/ .quiz-score em {
|
||||
margin-left: 6px;
|
||||
margin-bottom: 5px;
|
||||
font-style: normal;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.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,666 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
.container {
|
||||
padding: 0;
|
||||
background: #f4f8ff;
|
||||
height: calc(100vh - 46px);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.quiz-hero {
|
||||
flex: 0 0 auto;
|
||||
min-height: 170px;
|
||||
background: linear-gradient(135deg, #1688f8, #0a55c5);
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
margin: 12px 12px 14px;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 8px 24px rgba(35, 102, 168, .14);
|
||||
}
|
||||
|
||||
.quiz-hero-mask {
|
||||
min-height: 170px;
|
||||
padding: 24px 20px 22px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
box-sizing: border-box;
|
||||
background: linear-gradient(180deg, rgba(0, 0, 0, .16), rgba(0, 0, 0, .56));
|
||||
}
|
||||
|
||||
.quiz-title {
|
||||
margin: 0;
|
||||
color: #fff;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
line-height: 1.35;
|
||||
text-shadow: 0 2px 8px rgba(0, 0, 0, .28);
|
||||
}
|
||||
|
||||
.quiz-card-scroll {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
padding: 0 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.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,
|
||||
.van-radio__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,
|
||||
.van-radio__icon--disabled .van-icon {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.survey-option-finished-selected .survey-option-text {
|
||||
color: #00a000;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.survey-option-finished-selected .van-radio__icon--disabled .van-icon,
|
||||
.survey-option-finished-selected .van-checkbox__icon--disabled .van-icon {
|
||||
color: #fff !important;
|
||||
background-color: #d8d8d8 !important;
|
||||
border-color: #d8d8d8 !important;
|
||||
}
|
||||
|
||||
.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%;
|
||||
}
|
||||
|
||||
.option-fill-box {
|
||||
border: 1px solid #e3e3e3;
|
||||
margin: 0 16px 8px 46px;
|
||||
background-color: #fff;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.option-fill-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%;
|
||||
}
|
||||
|
||||
.required-star {
|
||||
color: #ee0a24;
|
||||
margin-left: 4px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar :title="pageTitle" left-arrow left-text="返回" @click-left="historyBack" placeholder fixed></van-nav-bar>
|
||||
<div class="container" :style="{'padding-bottom': '84px'}">
|
||||
<div class="quiz-hero" :style="heroStyle">
|
||||
<div class="quiz-hero-mask">
|
||||
<h2 class="quiz-title">{{ activity.title }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="quiz-card-scroll" v-if="!isFinished">
|
||||
<div v-for="(subject, index) in visibleSubjects" :key="subject.id" class="subject">
|
||||
<p>{{index+1}}、{{ subject.title }}<span class="required-star">*</span></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-radio-group
|
||||
:value="getRadioValue(subject)"
|
||||
v-if="subject.type === 'radio'"
|
||||
>
|
||||
<van-cell-group>
|
||||
<template v-for="(option,index) in subject.options">
|
||||
<van-cell
|
||||
clickable
|
||||
:key="option.id"
|
||||
:title="option.text"
|
||||
:class="getFinishedOptionClass(subject, option)"
|
||||
@click="cellToggle(subject,option.id)"
|
||||
>
|
||||
<template #title>
|
||||
<span class="survey-option-text">{{option.text}}</span>
|
||||
</template>
|
||||
<template #icon>
|
||||
<van-radio :name="option.id" :disabled="answerRecord.isFinish" style="margin-right: 10px"></van-radio>
|
||||
</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>
|
||||
<div
|
||||
class="option-fill-box"
|
||||
v-if="isOptionFillVisible(subject, option)"
|
||||
:key="option.id + '-fill'">
|
||||
<input
|
||||
v-model="subject.optionFillContents[option.id]"
|
||||
:placeholder="option.fillPlaceholder || '请输入补充内容'">
|
||||
</div>
|
||||
</template>
|
||||
</van-cell-group>
|
||||
</van-radio-group>
|
||||
|
||||
<!--多选-->
|
||||
<van-checkbox-group
|
||||
v-model="subject.userSelectOptionIds"
|
||||
v-if="subject.type === 'checkbox'"
|
||||
>
|
||||
<van-cell-group>
|
||||
<template v-for="(option,index) in subject.options">
|
||||
<van-cell
|
||||
clickable
|
||||
:key="option.id"
|
||||
:title="option.text"
|
||||
:class="getFinishedOptionClass(subject, option)"
|
||||
@click="cellToggle(subject,option.id)"
|
||||
>
|
||||
<template #title>
|
||||
<span class="survey-option-text">{{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>
|
||||
<img
|
||||
slot="right-icon"
|
||||
v-if="option.imgUrl"
|
||||
:src="option.imgUrl"
|
||||
alt=""
|
||||
style="width: 40px; height: 40px"
|
||||
@click.stop="previewOptionImg(option.imgUrl)"
|
||||
/>
|
||||
</van-cell>
|
||||
<div
|
||||
class="option-fill-box"
|
||||
:key="option.id + '-fill'"
|
||||
v-if="isOptionFillVisible(subject, option)">
|
||||
<input
|
||||
type="text"
|
||||
v-model="subject.optionFillContents[option.id]"
|
||||
:placeholder="option.fillPlaceholder || '请填写补充内容'"
|
||||
:readonly="answerRecord.isFinish"
|
||||
@click.stop />
|
||||
</div>
|
||||
</template>
|
||||
</van-cell-group>
|
||||
</van-checkbox-group>
|
||||
|
||||
<!--填空题-->
|
||||
<div class="ui-input-box" v-if="subject.type==='text'">
|
||||
<input type="text" v-model="subject.userFillContent" :placeholder="'请输入' + subject.title" :readonly="answerRecord.isFinish" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="button-control">
|
||||
<van-button v-if="!answerRecord.isFinish" type="primary" @click="onSubmit" block :disabled="isEnd">{{isEnd ? '已结束' : '提交'}}</van-button>
|
||||
<van-button v-else type="primary" @click="historyBack" block>返回</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
|
||||
},
|
||||
visibleSubjects() {
|
||||
return this.subjects.filter((subject) => {
|
||||
return this.isSubjectVisible(subject)
|
||||
})
|
||||
},
|
||||
pageTitle() {
|
||||
return this.getCategoryPageTitle(this.activity && this.activity.category, "问卷调查")
|
||||
},
|
||||
heroStyle() {
|
||||
if (this.activity && this.activity.cover) {
|
||||
return {
|
||||
backgroundImage: "url(" + this.activity.cover + ")"
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getCategoryPageTitle(category, defaultTitle) {
|
||||
const titleMap = {
|
||||
QUIZ: "在线答题",
|
||||
SURVEY: "问卷调查",
|
||||
VOTE: "投票"
|
||||
}
|
||||
return titleMap[category] || defaultTitle
|
||||
},
|
||||
//获取活动、题目
|
||||
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)) {
|
||||
const optionIds = answer?.optionIds || []
|
||||
this.$set(subject, "userSelectOptionIds", subject.type === "radio" ? optionIds.slice(0, 1) : optionIds)
|
||||
this.$set(subject, "optionFillContents", answer?.optionFillContents || {})
|
||||
} else if (subject.type === "text") {
|
||||
this.$set(subject, "userFillContent", answer?.text)
|
||||
}
|
||||
})
|
||||
if (!this.answerRecord.isFinish) {
|
||||
this.clearHiddenSubjectAnswers()
|
||||
}
|
||||
},
|
||||
|
||||
//判断题目是否显示,未配置隐显逻辑的题目默认显示;已配置的题目按条件树递归计算后再执行显示或隐藏动作
|
||||
isSubjectVisible(subject) {
|
||||
if (!subject.visibleRuleEnabled) {
|
||||
return true
|
||||
}
|
||||
|
||||
const rootGroup = this.getVisibleRuleRootGroup(subject)
|
||||
if (!rootGroup) {
|
||||
return true
|
||||
}
|
||||
|
||||
const matched = this.evaluateVisibleRuleGroup(rootGroup)
|
||||
|
||||
if (subject.visibleRuleAction === "hide") {
|
||||
return !matched
|
||||
}
|
||||
return matched
|
||||
},
|
||||
|
||||
//读取隐显逻辑根分组,兼容旧版 subjectId/optionId 平铺条件
|
||||
getVisibleRuleRootGroup(subject) {
|
||||
let conditions = subject.visibleRuleConditions || []
|
||||
if (typeof conditions === "string") {
|
||||
try {
|
||||
conditions = JSON.parse(conditions)
|
||||
} catch (e) {
|
||||
conditions = []
|
||||
}
|
||||
}
|
||||
if (!Array.isArray(conditions) || conditions.length === 0) {
|
||||
return null
|
||||
}
|
||||
if (conditions.length === 1 && conditions[0].type === "group") {
|
||||
return this.normalizeVisibleRuleGroup(conditions[0])
|
||||
}
|
||||
const children = conditions.filter((condition) => {
|
||||
return condition.subjectId && condition.optionId
|
||||
}).map((condition) => {
|
||||
return {
|
||||
type: "item",
|
||||
field: condition.subjectId,
|
||||
operator: "contains",
|
||||
value: condition.optionId
|
||||
}
|
||||
})
|
||||
if (children.length === 0) {
|
||||
return null
|
||||
}
|
||||
return {
|
||||
type: "group",
|
||||
logic: subject.visibleRuleLogic === "OR" ? "or" : "and",
|
||||
children
|
||||
}
|
||||
},
|
||||
|
||||
//规整条件分组,避免历史数据或空字段影响递归判断
|
||||
normalizeVisibleRuleGroup(group) {
|
||||
return {
|
||||
type: "group",
|
||||
logic: (group.logic || "and").toLowerCase() === "or" ? "or" : "and",
|
||||
children: Array.isArray(group.children) ? group.children.map((child) => {
|
||||
if (child.type === "group") {
|
||||
return this.normalizeVisibleRuleGroup(child)
|
||||
}
|
||||
return {
|
||||
type: "item",
|
||||
field: child.field || child.subjectId || "",
|
||||
operator: child.operator || (child.optionId ? "contains" : "=="),
|
||||
value: child.value !== undefined && child.value !== null ? child.value : (child.optionId || "")
|
||||
}
|
||||
}) : []
|
||||
}
|
||||
},
|
||||
|
||||
//递归计算条件分组,支持并且、或者和嵌套分组
|
||||
evaluateVisibleRuleGroup(group) {
|
||||
const children = (group.children || []).filter((child) => {
|
||||
return child.type === "group" || (child.field && child.operator)
|
||||
})
|
||||
if (children.length === 0) {
|
||||
return true
|
||||
}
|
||||
const results = children.map((child) => {
|
||||
if (child.type === "group") {
|
||||
return this.evaluateVisibleRuleGroup(child)
|
||||
}
|
||||
return this.evaluateVisibleRuleItem(child)
|
||||
})
|
||||
return group.logic === "or"
|
||||
? results.some((item) => {
|
||||
return item
|
||||
})
|
||||
: results.every((item) => {
|
||||
return item
|
||||
})
|
||||
},
|
||||
|
||||
//计算单条条件,选择题按选项ID判断,填空题支持文本包含和数字大小比较
|
||||
evaluateVisibleRuleItem(condition) {
|
||||
const triggerSubject = this.subjects.find((item) => {
|
||||
return item.id === condition.field
|
||||
})
|
||||
if (!triggerSubject) {
|
||||
return false
|
||||
}
|
||||
const answer = ["radio", "checkbox"].includes(triggerSubject.type)
|
||||
? (triggerSubject.userSelectOptionIds || [])
|
||||
: triggerSubject.userFillContent
|
||||
return this.compareVisibleRuleValue(answer, condition.operator, condition.value)
|
||||
},
|
||||
|
||||
//比较条件值,和后台逻辑抽屉实时预览保持同一套语义
|
||||
compareVisibleRuleValue(answer, operator, value) {
|
||||
if (Array.isArray(answer)) {
|
||||
if (operator === "!=") {
|
||||
return !answer.includes(value)
|
||||
}
|
||||
return answer.includes(value)
|
||||
}
|
||||
if ([">", "<", ">=", "<="].includes(operator)) {
|
||||
const answerNumber = Number(answer)
|
||||
const valueNumber = Number(value)
|
||||
if (isNaN(answerNumber) || isNaN(valueNumber)) {
|
||||
return false
|
||||
}
|
||||
if (operator === ">") {
|
||||
return answerNumber > valueNumber
|
||||
}
|
||||
if (operator === "<") {
|
||||
return answerNumber < valueNumber
|
||||
}
|
||||
if (operator === ">=") {
|
||||
return answerNumber >= valueNumber
|
||||
}
|
||||
return answerNumber <= valueNumber
|
||||
}
|
||||
const answerText = answer === undefined || answer === null ? "" : String(answer)
|
||||
const valueText = value === undefined || value === null ? "" : String(value)
|
||||
if (operator === "!=") {
|
||||
return answerText !== valueText
|
||||
}
|
||||
if (operator === "contains") {
|
||||
return answerText.indexOf(valueText) !== -1
|
||||
}
|
||||
return answerText === valueText
|
||||
},
|
||||
|
||||
//清空当前隐藏题目的答案,避免隐藏题残留旧选项或填空内容参与后续提交
|
||||
clearHiddenSubjectAnswers() {
|
||||
this.subjects.forEach((subject) => {
|
||||
if (this.isSubjectVisible(subject)) {
|
||||
return
|
||||
}
|
||||
if (["radio", "checkbox"].includes(subject.type)) {
|
||||
this.$set(subject, "userSelectOptionIds", [])
|
||||
this.$set(subject, "optionFillContents", {})
|
||||
} else if (subject.type === "text") {
|
||||
this.$set(subject, "userFillContent", null)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
//判断选项是否已被选择,用于控制选项补充填写框显示和提交校验
|
||||
isOptionSelected(subject, optionId) {
|
||||
return subject.userSelectOptionIds && subject.userSelectOptionIds.includes(optionId)
|
||||
},
|
||||
|
||||
getFinishedOptionClass(subject, option) {
|
||||
return this.answerRecord.isFinish && this.isOptionSelected(subject, option.id)
|
||||
? "survey-option-finished-selected"
|
||||
: ""
|
||||
},
|
||||
|
||||
//单选题仍按数组保存,这里只取第一个值用于 radio 组件展示
|
||||
getRadioValue(subject) {
|
||||
return subject.userSelectOptionIds && subject.userSelectOptionIds.length > 0
|
||||
? subject.userSelectOptionIds[0]
|
||||
: ""
|
||||
},
|
||||
|
||||
//选中需要补充填写的选项后显示输入框,例如选择“否”后填写原因
|
||||
isOptionFillVisible(subject, option) {
|
||||
return option.fillRequired && this.isOptionSelected(subject, option.id)
|
||||
},
|
||||
|
||||
//清空未选中选项的补充填写内容,避免取消选择后残留旧内容
|
||||
clearUnselectedOptionFillContents(subject) {
|
||||
if (!subject.optionFillContents) {
|
||||
this.$set(subject, "optionFillContents", {})
|
||||
}
|
||||
if (!subject.options) {
|
||||
return
|
||||
}
|
||||
subject.options.forEach((option) => {
|
||||
if (!this.isOptionSelected(subject, option.id)) {
|
||||
this.$delete(subject.optionFillContents, option.id)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
//选项点击
|
||||
cellToggle(subject, optionId) {
|
||||
if (this.answerRecord.isFinish) {
|
||||
return
|
||||
}
|
||||
|
||||
if (subject.type === "radio") {
|
||||
this.$set(subject, "userSelectOptionIds", [optionId])
|
||||
} else {
|
||||
this.$refs["option" + optionId][0].toggle()
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.clearUnselectedOptionFillContents(subject)
|
||||
this.clearHiddenSubjectAnswers()
|
||||
})
|
||||
},
|
||||
|
||||
//预览图片
|
||||
previewOptionImg(img) {
|
||||
vant.ImagePreview([img])
|
||||
},
|
||||
|
||||
//手动提交
|
||||
onSubmit() {
|
||||
const endTime = this.activity.endTime
|
||||
if (this.isEnd) {
|
||||
this.$toast("调查已结束")
|
||||
return
|
||||
}
|
||||
|
||||
//提示那些题没有作答
|
||||
for (let i = 0; i < this.visibleSubjects.length; i++) {
|
||||
const subject = this.visibleSubjects[i]
|
||||
if (["radio", "checkbox"].includes(subject.type)) {
|
||||
if (!subject.userSelectOptionIds || subject.userSelectOptionIds.length === 0) {
|
||||
this.$toast.fail("第" + (i + 1) + "题未做答")
|
||||
return
|
||||
}
|
||||
for (let j = 0; j < subject.options.length; j++) {
|
||||
const option = subject.options[j]
|
||||
if (this.isOptionFillVisible(subject, option) && !subject.optionFillContents[option.id]) {
|
||||
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.visibleSubjects.map((subject) => {
|
||||
return {
|
||||
id: subject.id,
|
||||
userSelectOptionIds: ["checkbox", "radio"].includes(subject.type) ? subject.userSelectOptionIds : [],
|
||||
userFillContent: subject.type === "text" ? subject.userFillContent : null,
|
||||
optionFillContents: ["checkbox", "radio"].includes(subject.type) ? subject.optionFillContents : {}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
.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>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+189
@@ -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="primary" block @click="handleTaskAction(1)">同意</van-button>
|
||||
<van-button type="danger" block @click="handleTaskAction(20)">不同意</van-button>
|
||||
<van-button type="danger" block @click="handleTaskAction(6)">退回</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>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,609 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style scoped>
|
||||
.page-container {
|
||||
padding: 12px 12px 96px;
|
||||
background: #f5f7fb;
|
||||
min-height: calc(100vh - 46px);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.panel-card {
|
||||
margin-bottom: 12px;
|
||||
overflow: hidden;
|
||||
border-radius: 22px;
|
||||
background: #ffffff;
|
||||
box-shadow:
|
||||
0 2px 6px rgba(15, 23, 42, 0.04),
|
||||
0 12px 28px rgba(15, 23, 42, 0.08),
|
||||
0 0 0 1px rgba(226, 232, 240, 0.95);
|
||||
}
|
||||
|
||||
.notice-card__header {
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
border: none;
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: #0f172a;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.notice-card__icon {
|
||||
color: #64748b;
|
||||
font-size: 16px;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.notice-card__icon--expanded {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.notice-card__body {
|
||||
padding: 0 16px 14px;
|
||||
border-top: 1px solid #eef2f7;
|
||||
}
|
||||
|
||||
.notice-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.notice-item {
|
||||
padding: 10px 12px;
|
||||
border-radius: 14px;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.notice-item__label {
|
||||
color: #334155;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.notice-item__value {
|
||||
margin-top: 4px;
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.disabled-time-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.disabled-time-item {
|
||||
padding: 8px 10px;
|
||||
border-radius: 10px;
|
||||
background: #ffffff;
|
||||
color: #475569;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.section-tip {
|
||||
padding: 0 16px 14px;
|
||||
color: #94a3b8;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.selection-summary {
|
||||
margin: 0 16px 14px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 12px;
|
||||
background: rgba(37, 99, 235, 0.08);
|
||||
color: #2563eb;
|
||||
font-size: 12px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.batch-panel {
|
||||
padding: 0 16px 14px;
|
||||
}
|
||||
|
||||
.batch-summary {
|
||||
margin-top: 10px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 12px;
|
||||
background: rgba(37, 99, 235, 0.08);
|
||||
color: #2563eb;
|
||||
font-size: 12px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.availability-popup {
|
||||
height: 82vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.availability-popup__header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
padding: 16px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #eef2f7;
|
||||
}
|
||||
|
||||
.availability-popup__title {
|
||||
color: #0f172a;
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.availability-popup__subtitle {
|
||||
margin-top: 4px;
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.availability-popup__close {
|
||||
color: #94a3b8;
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.availability-popup__tabs {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 12px 16px 8px;
|
||||
overflow-x: auto;
|
||||
background: #f8fafc;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
|
||||
.availability-popup__tabs::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.availability-tab {
|
||||
flex: 0 0 auto;
|
||||
min-width: 72px;
|
||||
min-height: 34px;
|
||||
padding: 6px 14px;
|
||||
border: 1px solid #cbd5e1;
|
||||
border-radius: 999px;
|
||||
background: #ffffff;
|
||||
color: #475569;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.availability-tab--active {
|
||||
border-color: #2563eb;
|
||||
background: #2563eb;
|
||||
color: #ffffff;
|
||||
box-shadow: 0 8px 16px rgba(37, 99, 235, 0.22);
|
||||
}
|
||||
|
||||
.availability-popup__legend {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
padding: 12px 16px 0;
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.availability-legend__item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.availability-legend__dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 999px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.availability-legend__dot--available {
|
||||
background: #22c55e;
|
||||
}
|
||||
|
||||
.availability-legend__dot--reserved {
|
||||
background: #9ca3af;
|
||||
}
|
||||
|
||||
.availability-legend__dot--selected {
|
||||
background: #2563eb;
|
||||
}
|
||||
|
||||
.availability-legend__dot--closed {
|
||||
background: #e5e7eb;
|
||||
}
|
||||
|
||||
.availability-popup__body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 16px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.slot-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.slot-block {
|
||||
min-height: 48px;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid #dbe4ee;
|
||||
border-radius: 14px;
|
||||
background: #ffffff;
|
||||
color: #475569;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.slot-block__name,
|
||||
.slot-block__time {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.slot-block__time {
|
||||
margin-top: 2px;
|
||||
font-size: 12px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.slot-block--available {
|
||||
border-color: #86efac;
|
||||
background: rgba(34, 197, 94, 0.1);
|
||||
color: #15803d;
|
||||
}
|
||||
|
||||
.slot-block--reserved {
|
||||
background: #e5e7eb;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.slot-block--closed {
|
||||
background: #f8fafc;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.slot-block--selected {
|
||||
border-color: #2563eb;
|
||||
background: #2563eb;
|
||||
color: #ffffff;
|
||||
box-shadow: 0 10px 20px rgba(37, 99, 235, 0.24);
|
||||
}
|
||||
|
||||
.availability-popup__footer {
|
||||
padding: 12px 16px calc(env(safe-area-inset-bottom) + 12px);
|
||||
background: #ffffff;
|
||||
border-top: 1px solid #eef2f7;
|
||||
}
|
||||
|
||||
.availability-popup__summary {
|
||||
margin-bottom: 12px;
|
||||
color: #475569;
|
||||
font-size: 12px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.availability-popup__actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.availability-popup__actions .van-button {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.footer-actions {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
padding: 10px 12px calc(env(safe-area-inset-bottom) + 10px);
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
backdrop-filter: blur(10px);
|
||||
box-shadow: 0 -8px 24px rgba(15, 23, 42, 0.08);
|
||||
}
|
||||
|
||||
.footer-actions .van-button {
|
||||
flex: 1;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
/deep/ .panel-card .van-cell-group {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/deep/ .panel-card .van-cell-group__title {
|
||||
padding: 16px 16px 8px;
|
||||
margin: 0;
|
||||
color: #0f172a;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
/deep/ .panel-card .van-cell {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
/deep/ .panel-card .van-field__label,
|
||||
/deep/ .panel-card .van-cell__title {
|
||||
color: #334155;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/deep/ .direction-column-cell .van-cell__value {
|
||||
white-space: normal;
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar title="场馆申请" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||
|
||||
<div class="page-container" v-if="siteLoaded">
|
||||
<div class="panel-card">
|
||||
<button type="button" class="notice-card__header" @click="noticeCollapsed = !noticeCollapsed">
|
||||
<span>预约须知</span>
|
||||
<van-icon :class="['notice-card__icon', noticeCollapsed ? '' : 'notice-card__icon--expanded']" name="arrow-down"></van-icon>
|
||||
</button>
|
||||
<div v-if="!noticeCollapsed" class="notice-card__body">
|
||||
<div class="notice-list">
|
||||
<div class="notice-item">
|
||||
<div class="notice-item__label">可预约日期</div>
|
||||
<div class="notice-item__value">仅限工作日</div>
|
||||
</div>
|
||||
<div class="notice-item">
|
||||
<div class="notice-item__label">节假日限制</div>
|
||||
<div class="notice-item__value">{{ timeLimitConfig.filterHolidays ? '节假日不可预约' : '不排除节假日' }}</div>
|
||||
</div>
|
||||
<div class="notice-item">
|
||||
<div class="notice-item__label">禁用时段</div>
|
||||
<div class="notice-item__value">
|
||||
<div v-if="timeLimitConfig.notApplyTimeList.length" class="disabled-time-list">
|
||||
<div
|
||||
class="disabled-time-item"
|
||||
v-for="(item, index) in timeLimitConfig.notApplyTimeList"
|
||||
:key="item.date + item.startTime + item.endTime + index">
|
||||
{{ item.date }} {{ item.startTime }} - {{ item.endTime }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>暂无禁用时段</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<van-form ref="formRef" class="form-container" :show-error-message="false">
|
||||
<div class="panel-card">
|
||||
<van-cell-group title="申请信息">
|
||||
<van-field
|
||||
:value="reserveTypeText"
|
||||
label="预约类型"
|
||||
name="reserveType"
|
||||
readonly
|
||||
clickable
|
||||
is-link
|
||||
required
|
||||
placeholder="请选择预约类型"
|
||||
@click="openReserveTypePicker"
|
||||
:rules="[{ required: true, message: '请选择预约类型' }]">
|
||||
</van-field>
|
||||
<van-field v-model="formData.applyUserName" label="预约人" name="applyUserName" readonly
|
||||
:rules="[{ required: true, message: '请确认预约人' }]"></van-field>
|
||||
<van-field v-model="formData.applyLoginName" label="工号" name="applyLoginName" readonly
|
||||
:rules="[{ required: true, message: '请确认工号' }]"></van-field>
|
||||
<van-field v-model="formData.applyUnitName" label="所属单位" name="applyUnitName" readonly
|
||||
:rules="[{ required: true, message: '请确认所属单位' }]"></van-field>
|
||||
<van-field
|
||||
v-if="formData.reserveType === 'union'"
|
||||
v-model="formData.applyUnionName"
|
||||
label="分工会"
|
||||
name="applyUnionName"
|
||||
readonly
|
||||
placeholder="自动读取当前登录人的分工会">
|
||||
</van-field>
|
||||
<van-field
|
||||
v-if="formData.reserveType === 'club'"
|
||||
v-model="formData.clubName"
|
||||
label="协会"
|
||||
name="clubName"
|
||||
readonly
|
||||
clickable
|
||||
is-link
|
||||
required
|
||||
placeholder="请选择您管理的协会"
|
||||
@click="openClubPicker"
|
||||
:rules="[{ required: true, message: '请选择您管理的协会' }]">
|
||||
</van-field>
|
||||
<van-field v-model="formData.applyMobile" label="联系电话" name="applyMobile" type="tel" maxlength="11"
|
||||
required placeholder="请输入联系电话"
|
||||
:rules="[{ required: true, message: '请输入联系电话' }]"></van-field>
|
||||
<van-field
|
||||
:value="scheduleDate"
|
||||
label="预约日期"
|
||||
name="scheduleDate"
|
||||
readonly
|
||||
clickable
|
||||
is-link
|
||||
required
|
||||
placeholder="请选择预约日期"
|
||||
@click="openScheduleDatePicker">
|
||||
</van-field>
|
||||
<van-field
|
||||
:value="selectionSummary || ''"
|
||||
label="预约时段"
|
||||
name="timeSelection"
|
||||
readonly
|
||||
clickable
|
||||
is-link
|
||||
required
|
||||
:placeholder="scheduleDate ? '请选择预约时段' : '请先选择预约日期'"
|
||||
@click="openAvailabilityPopup">
|
||||
</van-field>
|
||||
<div v-if="selectionSummary" class="selection-summary">当前已选:{{ selectionSummary }}</div>
|
||||
<van-cell title="批量预约">
|
||||
<template #default>
|
||||
<van-switch v-model="yearlyReserve" size="22px"></van-switch>
|
||||
</template>
|
||||
</van-cell>
|
||||
<div v-if="yearlyReserve" class="batch-panel">
|
||||
<div class="section-tip">预约本月后续每周同一时段,默认到本月底。</div>
|
||||
<van-field
|
||||
:value="formData.yearlyReserveEndDate"
|
||||
label="截至日期"
|
||||
name="yearlyReserveEndDate"
|
||||
readonly
|
||||
clickable
|
||||
is-link
|
||||
required
|
||||
placeholder="请选择批量预约截止日期"
|
||||
@click="openYearlyEndDatePicker">
|
||||
</van-field>
|
||||
<div v-if="batchReserveSummary" class="batch-summary">{{ batchReserveSummary }}</div>
|
||||
</div>
|
||||
<van-field v-model="formData.applyCause" label="预约事由" name="applyCause" required rows="4" autosize
|
||||
type="textarea" maxlength="1000" show-word-limit placeholder="请输入预约事由"
|
||||
:rules="[{ required: true, message: '请输入预约事由' }]"></van-field>
|
||||
</van-cell-group>
|
||||
</div>
|
||||
</van-form>
|
||||
</div>
|
||||
|
||||
<div class="footer-actions" v-if="siteLoaded">
|
||||
<van-button plain round type="info" @click="historyBack">取消</van-button>
|
||||
<van-button round type="primary" color="#246fb4" @click="onSubmit">提交预约</van-button>
|
||||
</div>
|
||||
|
||||
<van-popup v-model="showReserveTypePicker" position="bottom" round>
|
||||
<van-picker show-toolbar :columns="reserveTypeColumns" @confirm="onReserveTypeConfirm"
|
||||
@cancel="showReserveTypePicker = false"></van-picker>
|
||||
</van-popup>
|
||||
|
||||
<van-popup v-model="showClubPicker" position="bottom" round>
|
||||
<van-picker show-toolbar :columns="clubColumns" @confirm="onClubConfirm"
|
||||
@cancel="showClubPicker = false"></van-picker>
|
||||
</van-popup>
|
||||
|
||||
<van-popup v-model="showScheduleDatePicker" position="bottom" round>
|
||||
<van-datetime-picker
|
||||
v-model="schedulePickerDate"
|
||||
type="date"
|
||||
title="选择预约日期"
|
||||
:min-date="scheduleMinDate"
|
||||
:max-date="scheduleMaxDate"
|
||||
@confirm="onScheduleDateConfirm"
|
||||
@cancel="showScheduleDatePicker = false">
|
||||
</van-datetime-picker>
|
||||
</van-popup>
|
||||
|
||||
<van-popup v-model="showAvailabilityPopup" position="bottom" round class="availability-popup">
|
||||
<div class="availability-popup__header">
|
||||
<div>
|
||||
<div class="availability-popup__title">选择预约时段</div>
|
||||
<div class="availability-popup__subtitle">{{ scheduleDate || '请选择预约日期' }} {{ reserveModeText }}</div>
|
||||
</div>
|
||||
<van-icon class="availability-popup__close" name="cross" @click="showAvailabilityPopup = false"></van-icon>
|
||||
</div>
|
||||
<div v-if="timeGroupTabs.length" class="availability-popup__tabs">
|
||||
<button
|
||||
v-for="tab in timeGroupTabs"
|
||||
:key="tab.key"
|
||||
type="button"
|
||||
:class="['availability-tab', activeTimeGroupKey === tab.key ? 'availability-tab--active' : '']"
|
||||
@click="activeTimeGroupKey = tab.key">
|
||||
{{ tab.label }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="availability-popup__legend">
|
||||
<span class="availability-legend__item"><i class="availability-legend__dot availability-legend__dot--available"></i>可预约</span>
|
||||
<span class="availability-legend__item"><i class="availability-legend__dot availability-legend__dot--reserved"></i>已预约</span>
|
||||
<span class="availability-legend__item"><i class="availability-legend__dot availability-legend__dot--selected"></i>已选择</span>
|
||||
<span class="availability-legend__item"><i class="availability-legend__dot availability-legend__dot--closed"></i>不可预约</span>
|
||||
</div>
|
||||
<div class="availability-popup__body">
|
||||
<van-loading v-if="availabilityLoading" vertical>时段加载中</van-loading>
|
||||
<van-empty v-else-if="!availabilityBlocks.length" description="当前日期暂无可选时段"></van-empty>
|
||||
<van-empty v-else-if="!displayedAvailabilityBlocks.length" description="当前标签暂无可选时段"></van-empty>
|
||||
<div v-else class="slot-grid">
|
||||
<button
|
||||
v-for="block in displayedAvailabilityBlocks"
|
||||
:key="block.key"
|
||||
type="button"
|
||||
:class="getBlockClass(block)"
|
||||
@click="onAvailabilityBlockClick(block)">
|
||||
<span class="slot-block__name">{{ formatSlotLabel(block).name }}</span>
|
||||
<span class="slot-block__time">{{ formatSlotLabel(block).time }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="availability-popup__footer">
|
||||
<div class="availability-popup__summary">{{ selectionSummary || '请选择一个或多个连续时段,不可跨越间隔选择。' }}</div>
|
||||
<div class="availability-popup__actions">
|
||||
<van-button plain round type="default" @click="clearSelection(true)">清空</van-button>
|
||||
<van-button round type="primary" color="#246fb4" @click="confirmAvailabilitySelection">确定</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
|
||||
<van-popup v-model="showYearlyEndDatePicker" position="bottom" round>
|
||||
<van-datetime-picker
|
||||
v-model="yearlyReservePickerDate"
|
||||
type="date"
|
||||
title="选择批量预约截止日期"
|
||||
:min-date="yearlyReserveMinDate"
|
||||
:max-date="yearlyReserveMaxDate"
|
||||
@confirm="onYearlyReserveEndDateConfirm"
|
||||
@cancel="showYearlyEndDatePicker = false">
|
||||
</van-datetime-picker>
|
||||
</van-popup>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('apply.js'){}#-->
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user