整合上架版进入标准流程
This commit is contained in:
182
src/project/saas/AppAskForm/components/AddList.vue
Normal file
182
src/project/saas/AppAskForm/components/AddList.vue
Normal file
@@ -0,0 +1,182 @@
|
||||
<template>
|
||||
<div class="template-wrapper">
|
||||
<div class="form-list">
|
||||
<div
|
||||
class="form-list__item"
|
||||
@click="toAdd(index)"
|
||||
:style="{'background-image': `url(${$cdn}askform/${index + 1}.png)`}"
|
||||
v-for="(item, index) in itemList"
|
||||
:key="index">
|
||||
<h2>{{ item.name }}</h2>
|
||||
<div>立即创建</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="template" v-if="list.length">
|
||||
<h2>共享模板</h2>
|
||||
<div class="template-list">
|
||||
<div class="template-item" v-for="(item, index) in list" :key="index" hover-class="bg-hover"
|
||||
@click="quote(item.id)">
|
||||
<image :src="`${$cdn}askform/6.png`"/>
|
||||
<h2>{{ item.title }}</h2>
|
||||
<u-icon name="arrow-right" color="#E1E2E3"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import qs from "query-string"
|
||||
|
||||
export default {
|
||||
name: 'addList',
|
||||
label: '新建项目',
|
||||
|
||||
data() {
|
||||
return {
|
||||
itemList: [{
|
||||
name: '问卷调查'
|
||||
}, {
|
||||
name: '考试测评'
|
||||
}, {
|
||||
name: '报名登记'
|
||||
}, {
|
||||
name: '满意调查'
|
||||
}, {
|
||||
name: '投票评选'
|
||||
}],
|
||||
list: []
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
toAdd(type) {
|
||||
uni.navigateTo({url: `./AddForm?${qs.stringify({type})}`})
|
||||
},
|
||||
quote(id) {
|
||||
uni.navigateTo({url: `./AddForm?${qs.stringify({id, isQuote: 1})}`})
|
||||
},
|
||||
getList() {
|
||||
this.$http.post(`/app/appquestionnairetemplate/list`, null, {
|
||||
params: {
|
||||
current: 1,
|
||||
templateType: 1,
|
||||
size: 10000
|
||||
}
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.list = res.data.records
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.template-wrapper {
|
||||
padding-bottom: 120px;
|
||||
|
||||
.template {
|
||||
margin: 32px 32px 0;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
|
||||
& > h2 {
|
||||
height: 88px;
|
||||
line-height: 88px;
|
||||
padding: 0 24px;
|
||||
color: #333333;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.template-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 104px;
|
||||
padding: 0 24px;
|
||||
border-bottom: 1px solid #D8DDE6;
|
||||
|
||||
&:active {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 36px;
|
||||
height: 42px;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 30px;
|
||||
color: #E1E2E3;
|
||||
}
|
||||
|
||||
h2 {
|
||||
flex: 1;
|
||||
padding: 0 18px;
|
||||
color: #333333;
|
||||
font-size: 28px;
|
||||
font-weight: normal;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 0 32px 0;
|
||||
|
||||
div {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-list__item {
|
||||
width: calc(50% - 13px);
|
||||
height: 216px;
|
||||
margin: 32px 24px 0 0;
|
||||
padding: 40px 20px 52px;
|
||||
background-color: #FFFFFF;
|
||||
border-radius: 8px;
|
||||
background-size: 100% 100%;
|
||||
|
||||
&:active {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
&:nth-of-type(2n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
div {
|
||||
width: 148px;
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-size: 28px;
|
||||
background: #6BA1F9;
|
||||
border-radius: 24px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-bottom: 32px;
|
||||
padding-left: 10px;
|
||||
color: #333333;
|
||||
font-weight: 700;
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
532
src/project/saas/AppAskForm/components/List.vue
Normal file
532
src/project/saas/AppAskForm/components/List.vue
Normal file
@@ -0,0 +1,532 @@
|
||||
<template>
|
||||
<div class="form">
|
||||
<AiTopFixed>
|
||||
<u-search placeholder="请输入标题" :show-action="false" search-icon-color="#ccc" v-model="search.title"
|
||||
@search="isMore = false, search.current = 1, getList()"/>
|
||||
</AiTopFixed>
|
||||
<scroll-view show-scrollbar scroll-y @scrolltolower="getList" class="form-list">
|
||||
<div class="form-item" v-for="(item, index) in list" :key="index"
|
||||
@click="showPopup(item)">
|
||||
<div class="form-item__top">
|
||||
<div class="form-item__left">
|
||||
<h2>{{ item.title }}</h2>
|
||||
<div class="form-item__left--info">
|
||||
<!-- <AiOpenData v-if="item.createUnitName" type="departmentName" :openid="item.createUnitName"/>-->
|
||||
<AiOpenData v-if="item.createUserName" type="userName" :openid="item.createUserName"/>
|
||||
<span>{{ item.createTime.substr(0, item.createTime.length - 3) }}</span>
|
||||
<span>{{ $dict.getLabel('questionnaireType', item.type) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item__right">
|
||||
<h2>{{ item.dataCount }}</h2>
|
||||
<span>答卷数量</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item__bottom form-item__bottom--active">
|
||||
<i :style="{background: $dict.getColor('questionnaireStatus', item.status)}"></i>
|
||||
<span>{{ $dict.getLabel('questionnaireStatus', item.status) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<u-gap/>
|
||||
<AiEmpty v-if="!list.length && isMore"></AiEmpty>
|
||||
</scroll-view>
|
||||
<u-popup v-model="isShow" :closeable="false" mode="bottom" :z-index="11">
|
||||
<div class="popup">
|
||||
<h2>{{ info.title }}</h2>
|
||||
<div class="operate-list">
|
||||
<div class="operate-item" @click="toEdit">
|
||||
<div>
|
||||
<image :src="`${$cdn}askform/bj.png`"/>
|
||||
</div>
|
||||
<h3>编辑</h3>
|
||||
</div>
|
||||
<div class="operate-item" @click="linkTo('./AppForm?preview=1&id=' + id)">
|
||||
<div>
|
||||
<image :src="`${$cdn}askform/yl.png`"/>
|
||||
</div>
|
||||
<h3>预览</h3>
|
||||
</div>
|
||||
<div class="operate-item" @click="publish" v-if="info.status !== '1'">
|
||||
<div>
|
||||
<image :src="`${$cdn}askform/fb.png`"/>
|
||||
</div>
|
||||
<h3>发布</h3>
|
||||
</div>
|
||||
<div class="operate-item" @click="isShowModal = true" v-if="info.status === '1'">
|
||||
<div>
|
||||
<image :src="`${$cdn}askform/stop.png`"/>
|
||||
</div>
|
||||
<h3>停止</h3>
|
||||
</div>
|
||||
<div class="operate-item" @click="showShare">
|
||||
<div>
|
||||
<image :src="`${$cdn}askform/fx.png`"/>
|
||||
</div>
|
||||
<h3>分享</h3>
|
||||
</div>
|
||||
<div class="operate-item" @click="share(id)">
|
||||
<div>
|
||||
<image :src="`${$cdn}askform/mb.png`"/>
|
||||
</div>
|
||||
<h3>共享为模板</h3>
|
||||
</div>
|
||||
<div class="operate-item" @click="remove(id)">
|
||||
<div>
|
||||
<image :src="`${$cdn}askform/sc.png`"/>
|
||||
</div>
|
||||
<h3>删除</h3>
|
||||
</div>
|
||||
<div class="operate-item" @click="toResult(id)">
|
||||
<div>
|
||||
<image :src="`${$cdn}askform/total.png`"/>
|
||||
</div>
|
||||
<h3>调查结果</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="popup-btn" @click="isShow = false">关闭</div>
|
||||
</div>
|
||||
</u-popup>
|
||||
<u-modal v-model="isShowModal" show-cancel-button content="确定停止该表单?" @confirm="toStop"></u-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapActions} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'formList',
|
||||
label: '表单列表',
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
templateType: 0,
|
||||
title: ''
|
||||
},
|
||||
isShowModal: false,
|
||||
value: '',
|
||||
id: '',
|
||||
info: {},
|
||||
isMore: false,
|
||||
list: [],
|
||||
linkUrl: '',
|
||||
isShow: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// this.$loading()
|
||||
this.$dict.load(['questionnaireStatus', 'questionnaireType', 'questionnaireFieldType']).then(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
...mapActions(['wxInvoke']),
|
||||
linkTo(url) {
|
||||
this.isShow = false
|
||||
|
||||
uni.navigateTo({
|
||||
url
|
||||
})
|
||||
},
|
||||
|
||||
showPopup(item) {
|
||||
this.info = item
|
||||
this.id = item.id
|
||||
|
||||
this.info = item
|
||||
this.id = item.id
|
||||
this.isShow = true
|
||||
|
||||
this.$http.post(`/app/appquestionnairetemplate/queryQrCode?id=${item.id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.linkUrl = res.data.linkUrl
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
toStop() {
|
||||
this.$http.post(`/app/appquestionnairetemplate/stopRelease?id=${this.info.id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$u.toast('停止成功')
|
||||
this.search.current = 1
|
||||
this.isShow = false
|
||||
this.isMore = false
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
showShare() {
|
||||
if (this.info.status !== '1') {
|
||||
this.isShow = false
|
||||
return this.$u.toast(`该表单${this.info.status === '0' ? '未发布' : '已截止'},无法分享!`)
|
||||
}
|
||||
|
||||
uni.showActionSheet({
|
||||
itemList: ['分享', '微信分享', '获取链接'],
|
||||
success: data => {
|
||||
if (data.tapIndex === 2) {
|
||||
this.copy(this.linkUrl)
|
||||
this.isShow = false
|
||||
}
|
||||
if (data.tapIndex === 0 || data.tapIndex === 1) {
|
||||
if (data.tapIndex === 0) {
|
||||
this.wxInvoke(['shareAppMessage', {
|
||||
title: this.info.title,
|
||||
desc: this.info.tableExplain,
|
||||
link: this.linkUrl,
|
||||
imgUrl: this.info.headPicture
|
||||
}, () => {
|
||||
this.isShow = false
|
||||
}])
|
||||
} else {
|
||||
this.wxInvoke(['shareWechatMessage', {
|
||||
title: this.info.title,
|
||||
desc: this.info.tableExplain,
|
||||
link: this.linkUrl,
|
||||
imgUrl: this.info.headPicture
|
||||
}, () => {
|
||||
this.isShow = false
|
||||
}])
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
copy(link) {
|
||||
let oInput = document.createElement('input')
|
||||
oInput.value = link
|
||||
document.body.appendChild(oInput)
|
||||
oInput.select()
|
||||
document.execCommand('Copy')
|
||||
this.$u.toast('已复制')
|
||||
oInput.remove()
|
||||
},
|
||||
|
||||
publish() {
|
||||
if (this.info.status === '1') {
|
||||
return this.$u.toast('该表单已发布')
|
||||
}
|
||||
this.linkTo(`./FormSetting?id=${this.info.id}&type=edit`)
|
||||
this.isShow = false
|
||||
},
|
||||
|
||||
toResult () {
|
||||
if (this.info.dataCount < 1) {
|
||||
this.$confirm('暂无调查结果信息', '', {
|
||||
showCancel: false
|
||||
})
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
this.linkTo(`./Statistical?id=${this.info.id}`)
|
||||
},
|
||||
|
||||
toEdit() {
|
||||
if (this.info.dataCount !== 0) {
|
||||
return this.$u.toast('该表单已有数据,无法编辑!')
|
||||
} else {
|
||||
let {id} = this
|
||||
this.isShow = false
|
||||
uni.navigateTo({url: `./AddForm?id=${id}`})
|
||||
}
|
||||
},
|
||||
|
||||
share(id) {
|
||||
this.$http.post(`/app/appquestionnairetemplate/share?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$confirm('调查表单共享成功,其他成员可在新建项目时直接使用!', '', {
|
||||
showCancel: false
|
||||
})
|
||||
this.isShow = false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
if (this.info.dataCount !== 0) {
|
||||
return this.$u.toast('该表单已有数据,无法删除!')
|
||||
}
|
||||
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.$http.post(`/app/appquestionnairetemplate/delete?id=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$u.toast('删除成功')
|
||||
this.isShow = false
|
||||
this.search.current = 1
|
||||
this.isMore = false
|
||||
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
}).catch(() => {
|
||||
})
|
||||
},
|
||||
|
||||
reload() {
|
||||
this.isMore = false
|
||||
this.search.current = 1
|
||||
|
||||
this.getList()
|
||||
},
|
||||
|
||||
getList() {
|
||||
if (this.isMore) return
|
||||
this.$http.post(`/app/appquestionnairetemplate/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
size: 10
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
if (this.search.current > 1) {
|
||||
this.list = [...this.list, ...res.data.records]
|
||||
} else {
|
||||
this.list = res.data.records
|
||||
}
|
||||
|
||||
uni.hideLoading()
|
||||
|
||||
if (res.data.records.length < 10) {
|
||||
this.isMore = true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
this.search.current = this.search.current + 1
|
||||
} else {
|
||||
uni.hideLoading()
|
||||
}
|
||||
}).catch(() => {
|
||||
uni.hideLoading()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form {
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
|
||||
u-radio + u-radio {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
::v-deep .u-search {
|
||||
margin-bottom: 0 !important;
|
||||
|
||||
.u-search__content__input {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.form-list {
|
||||
height: calc(100vh - 98px - 100px);
|
||||
background: #f5f5f5;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.popup {
|
||||
background: #F7F7F7;
|
||||
|
||||
& > h2 {
|
||||
height: 72px;
|
||||
line-height: 72px;
|
||||
padding: 0 20px;
|
||||
color: #999999;
|
||||
font-size: 22px;
|
||||
text-align: center;
|
||||
border-bottom: 2px solid #D7D8DA;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.popup-btn {
|
||||
height: 96px;
|
||||
line-height: 96px;
|
||||
text-align: center;
|
||||
color: #333333;
|
||||
font-size: 30px;
|
||||
background: #fff;
|
||||
|
||||
&:active {
|
||||
background: #eee;
|
||||
}
|
||||
}
|
||||
|
||||
.operate-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
text-align: center;
|
||||
padding-bottom: 26px;
|
||||
|
||||
.operate-item {
|
||||
width: 25%;
|
||||
font-size: 0;
|
||||
margin-top: 28px;
|
||||
|
||||
&:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 20px;
|
||||
color: #666666;
|
||||
font-size: 26px;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
image {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border-radius: 16px;
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin: 24px 25px 0;
|
||||
padding: 32px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 16px;
|
||||
|
||||
.form-item__bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 28px;
|
||||
color: #999999;
|
||||
|
||||
i {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin-right: 6px;
|
||||
border-radius: 50%;
|
||||
background: #999999;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
&.form-item__bottom--active i {
|
||||
background: #3CB300;
|
||||
}
|
||||
}
|
||||
|
||||
.form-item__top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.form-item__right {
|
||||
text-align: center;
|
||||
|
||||
h2 {
|
||||
line-height: 40px;
|
||||
margin-bottom: 16px;
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
color: #1EA0FA;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #999999;
|
||||
font-size: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
.form-item__left {
|
||||
flex: 1;
|
||||
max-width: 80%;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
right: -15px;
|
||||
top: 50%;
|
||||
width: 2px;
|
||||
height: 96px;
|
||||
background: #F5F5F5;
|
||||
content: '';
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
h2 {
|
||||
line-height: 44px;
|
||||
margin-bottom: 16px;
|
||||
color: #333;
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.form-item__left--info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
color: #999;
|
||||
font-size: 20px;
|
||||
|
||||
span, div {
|
||||
position: relative;
|
||||
margin-right: 24px;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
right: -12px;
|
||||
top: 50%;
|
||||
width: 2px;
|
||||
height: 20px;
|
||||
background: #D1D2D5;
|
||||
content: '';
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.type-0 {
|
||||
background: #2266FF !important;
|
||||
}
|
||||
|
||||
.type-1 {
|
||||
background: rgba(34, 170, 153, 1) !important;
|
||||
}
|
||||
|
||||
.type-2 {
|
||||
background: rgba(248, 180, 37, 1) !important;
|
||||
}
|
||||
|
||||
.type-3 {
|
||||
background: rgba(102, 119, 187, 1) !important;
|
||||
}
|
||||
|
||||
.type-4 {
|
||||
background: rgba(236, 68, 97, 1) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
66
src/project/saas/AppAskForm/components/Tabbar.vue
Normal file
66
src/project/saas/AppAskForm/components/Tabbar.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<div class="form-wrapper">
|
||||
<div class="form-content">
|
||||
<list ref="list" v-if="currIndex === 0" @change="onChange"/>
|
||||
<add-list ref="addList" v-if="currIndex === 1" @change="onChange"/>
|
||||
</div>
|
||||
<AiTabbar :active.sync="currIndex" :list="tabBar"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AddList from './AddList.vue'
|
||||
import List from './List.vue'
|
||||
|
||||
export default {
|
||||
name: 'AppAskForm',
|
||||
appName: '问卷表单',
|
||||
|
||||
data() {
|
||||
return {
|
||||
currIndex: 0
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
AddList,
|
||||
List
|
||||
},
|
||||
computed: {
|
||||
tabBar() {
|
||||
const link = icon => `${this.$cdn}askform/${icon}.png`
|
||||
return [
|
||||
{text: "表单列表", iconPath: "bdlb1", selectedIconPath: "bdlb2"},
|
||||
{text: "新建项目", iconPath: "xjxm1", selectedIconPath: "xjxm2"}
|
||||
].map(e => ({
|
||||
...e,
|
||||
iconPath: link(e.iconPath),
|
||||
selectedIconPath: link(e.selectedIconPath)
|
||||
}))
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onChange(e) {
|
||||
this.$emit('change', e)
|
||||
},
|
||||
show() {
|
||||
if (this.currIndex == 0) {
|
||||
this.currIndex = -1
|
||||
this.$nextTick(() => {
|
||||
this.currIndex = 0
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
onReachBottom() {
|
||||
if (this.currIndex === 0) {
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form-wrapper {
|
||||
// padding-bottom: 98px;
|
||||
}
|
||||
</style>
|
||||
163
src/project/saas/AppAskForm/components/config.js
Normal file
163
src/project/saas/AppAskForm/components/config.js
Normal file
@@ -0,0 +1,163 @@
|
||||
export const components = [
|
||||
{
|
||||
type: 'radio',
|
||||
label: '单选',
|
||||
fixedLabel: '单选',
|
||||
value: '',
|
||||
points: '',
|
||||
icon: 'iconradio',
|
||||
isShowPoints: false,
|
||||
required: true,
|
||||
hasAnswer: false,
|
||||
answer: '',
|
||||
pointType: '0',
|
||||
pointDict: [
|
||||
{
|
||||
dictName: '此题有唯一答案和分值',
|
||||
dictValue: '0'
|
||||
},
|
||||
{
|
||||
dictName: '每个选项都有对应分值',
|
||||
dictValue: '1'
|
||||
}
|
||||
],
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: '',
|
||||
point: '',
|
||||
img: []
|
||||
},
|
||||
{
|
||||
label: '选项2',
|
||||
value: '',
|
||||
point: '',
|
||||
img: []
|
||||
}
|
||||
],
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
label: '多选',
|
||||
fixedLabel: '多选',
|
||||
points: '',
|
||||
icon: 'iconcheck_box',
|
||||
isShowPoints: false,
|
||||
required: true,
|
||||
hasAnswer: false,
|
||||
answer: [],
|
||||
value: [],
|
||||
pointType: '0',
|
||||
pointDict: [
|
||||
{
|
||||
dictName: '此题有唯一答案和分值',
|
||||
dictValue: '0'
|
||||
},
|
||||
{
|
||||
dictName: '每个选项都有对应分值',
|
||||
dictValue: '1'
|
||||
},
|
||||
{
|
||||
dictName: '答对几项得几分,答错不得分',
|
||||
dictValue: '2'
|
||||
}
|
||||
],
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: '',
|
||||
point: '',
|
||||
img: [],
|
||||
checked: false
|
||||
},
|
||||
{
|
||||
label: '选项2',
|
||||
point: '',
|
||||
value: '',
|
||||
img: [],
|
||||
checked: false
|
||||
}
|
||||
],
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
label: '单下拉框',
|
||||
fixedLabel: '单下拉框',
|
||||
value: '',
|
||||
points: '',
|
||||
icon: 'iconSelect',
|
||||
isShowPoints: false,
|
||||
required: true,
|
||||
hasAnswer: false,
|
||||
answer: '',
|
||||
pointType: '0',
|
||||
placeholder: '请选择',
|
||||
pointDict: [
|
||||
{
|
||||
dictName: '此题有唯一答案和分值',
|
||||
dictValue: '0'
|
||||
},
|
||||
{
|
||||
dictName: '每个选项都有对应分值',
|
||||
dictValue: '1'
|
||||
}
|
||||
],
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: '',
|
||||
point: '',
|
||||
img: []
|
||||
},
|
||||
{
|
||||
label: '选项2',
|
||||
value: '',
|
||||
point: '',
|
||||
img: []
|
||||
}
|
||||
],
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
label: '单行填空',
|
||||
fixedLabel: '单行填空',
|
||||
value: '',
|
||||
pointType: '0',
|
||||
icon: 'icontext_box',
|
||||
isShowPoints: false,
|
||||
points: '',
|
||||
required: true,
|
||||
hasAnswer: false,
|
||||
placeholder: '请输入...',
|
||||
answer: ''
|
||||
},
|
||||
{
|
||||
type: 'textarea',
|
||||
label: '多行填空',
|
||||
fixedLabel: '多行填空',
|
||||
pointType: '0',
|
||||
icon: 'icontext_area',
|
||||
points: '',
|
||||
isShowPoints: false,
|
||||
required: true,
|
||||
hasAnswer: false,
|
||||
answer: '',
|
||||
placeholder: '请输入...',
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
type: 'upload',
|
||||
label: '上传图片',
|
||||
fixedLabel: '上传图片',
|
||||
value: '',
|
||||
icon: 'iconpic',
|
||||
isShowPoints: false,
|
||||
points: '',
|
||||
required: true,
|
||||
hasAnswer: false,
|
||||
answer: ''
|
||||
}
|
||||
];
|
||||
339
src/project/saas/AppAskForm/components/formDetail.vue
Normal file
339
src/project/saas/AppAskForm/components/formDetail.vue
Normal file
@@ -0,0 +1,339 @@
|
||||
<template>
|
||||
<section class="formDetail">
|
||||
<AiResult v-if="result.tips" v-bind="result">
|
||||
<template v-if="isExam" #extra>
|
||||
<div flex class="scorePane">
|
||||
<div>成绩</div>
|
||||
<div class="fill"><em v-html="score"/> 分</div>
|
||||
</div>
|
||||
</template>
|
||||
</AiResult>
|
||||
<template v-else-if="form.id">
|
||||
<image v-if="form.headPicture" class="headPicture" :src="form.headPicture"/>
|
||||
<b class="title">{{ form.title || "标题" }}</b>
|
||||
<div class="tableExplain">{{ form.tableExplain }}</div>
|
||||
<u-form class="content" label-position="top">
|
||||
<u-form-item class="item" v-for="(op,i) in fields" :key="i" :label="(i+1)+'.'+op.fieldName"
|
||||
:required="op.fieldInfo.required==1">
|
||||
<template v-if="op.fieldType=='input'">
|
||||
<input v-model="op.fieldValue" :placeholder="op.fieldInfo.placeholder" :disabled="isResult"/>
|
||||
</template>
|
||||
<template v-else-if="op.fieldType=='textarea'">
|
||||
<textarea v-model="op.fieldValue" :disabled="isResult" :placeholder="op.fieldInfo.placeholder"/>
|
||||
</template>
|
||||
<template v-else-if="op.fieldType=='upload'">
|
||||
<AiUploader @list="v=>op.fieldValue=v.map(e=>e.url)" :def="op.fieldValue" :disabled="isResult"
|
||||
preview action="/admin/file/add2"/>
|
||||
</template>
|
||||
<u-row v-else-if="op.fieldType=='radio'">
|
||||
<radio-group @change="({detail})=>op.fieldValue=detail.value">
|
||||
<div class="option" flex v-for="option in op.fieldInfo.options" :key="option.label">
|
||||
<radio :value="option.label" :disabled="isResult" :checked="op.fieldValue==option.label"/>
|
||||
<AiImage v-if="option.img" :src="option.img" preview/>
|
||||
<div class="label fill">{{ option.label }}</div>
|
||||
</div>
|
||||
</radio-group>
|
||||
</u-row>
|
||||
<u-row v-else-if="op.fieldType=='checkbox'">
|
||||
<checkbox-group @change="({detail})=>op.fieldValue=detail.value">
|
||||
<div class="option" flex v-for="option in op.fieldInfo.options" :key="option.label">
|
||||
<checkbox :value="option.label" :disabled="isResult"
|
||||
:checked="option.checked"/>
|
||||
<AiImage v-if="option.img" :src="option.img" preview/>
|
||||
<div class="label fill">{{ option.label }}</div>
|
||||
</div>
|
||||
</checkbox-group>
|
||||
</u-row>
|
||||
<template v-else-if="op.fieldType=='select'">
|
||||
<AiSelect @data="v=>op.fieldValue=v.map(e=>e.value)" :list="op.fieldInfo.options" :disabled="isResult">
|
||||
<div class="option" flex>
|
||||
<div class="label fill" v-if="op.fieldValue">{{ op.fieldValue.toString() }}</div>
|
||||
<i class="fill" v-else>请选择</i>
|
||||
<u-icon name="arrow-right" color="#ddd"/>
|
||||
</div>
|
||||
</AiSelect>
|
||||
</template>
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
<div class="bottom" v-if="!(isPreview||isResult)">
|
||||
<div class="bottomBtn" @tap="handleSubmit">提交</div>
|
||||
</div>
|
||||
</template>
|
||||
<AiLoading v-else tips="调查问卷加载中..."/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import {mapMutations, mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
name: "formDetail",
|
||||
inject: {root: {}},
|
||||
computed: {
|
||||
...mapState(['openUser', 'token']),
|
||||
isExam() {
|
||||
return this.form?.type == 1
|
||||
},
|
||||
isResult() {
|
||||
return !!this.$route.query?.result
|
||||
},
|
||||
isPreview() {
|
||||
return !!this.$route.query?.preview
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
fields: [],
|
||||
checkUser: false,
|
||||
result: {},
|
||||
score: 0
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
form: {
|
||||
deep: true,
|
||||
handler(v) {
|
||||
this.fields = v?.fields?.map(e => {
|
||||
let fieldInfo = JSON.parse(e.fieldInfo)
|
||||
fieldInfo?.options?.map(op => {
|
||||
op.img = op?.img?.[0]?.url
|
||||
op.checked = !!e.fieldValue?.split(",")?.includes(op.label)
|
||||
})
|
||||
if (e.fieldType == 'select') {
|
||||
fieldInfo.options = fieldInfo.options.map(e => ({...e, value: e.label, label: e.label}))
|
||||
}
|
||||
return {...e, fieldInfo}
|
||||
}) || []
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['logout']),
|
||||
getForm() {
|
||||
let {id} = this.$route.query
|
||||
this.$http.post("/app/appquestionnairetemplate/queryDetailById", null, {
|
||||
withoutToken: true,
|
||||
params: {id}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.form = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
getResult() {
|
||||
let {id} = this.$route.query
|
||||
this.$http.post("/app/appquestionnairetemplate/commitCheck", null, {
|
||||
params: {id}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.form = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
validateForm() {
|
||||
return !this.fields.some(e => {
|
||||
if (!!e?.fieldInfo?.required && !e.fieldValue?.toString()) {
|
||||
this.$u.toast(e.fieldName + "不能为空!")
|
||||
return true
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSubmit() {
|
||||
if (this.validateForm()) {
|
||||
this.handleScore()
|
||||
let {avatar: avatarUrl, openId, name: nickName, type: userType, unionId, corpName} = this.openUser
|
||||
this.$http.post("/app/appquestionnairetemplate/commit", {
|
||||
fields: this.fields.map(e => ({
|
||||
...e,
|
||||
fieldInfo: JSON.stringify(e.fieldInfo),
|
||||
fieldValue: e.fieldValue?.toString()
|
||||
})),
|
||||
avatarUrl, openId, nickName, userType, unionId, corpName,
|
||||
totalScore: this.score,
|
||||
questionnaireTemplateId: this.$route.query.id
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.result = {
|
||||
tips: "提交成功!感谢参与",
|
||||
}
|
||||
}
|
||||
}).catch(err => {
|
||||
this.$u.toast(err || "提交失败")
|
||||
})
|
||||
}
|
||||
},
|
||||
handleScore() {
|
||||
this.score = 0
|
||||
this.isExam && this.fields.map(field => {
|
||||
let item = field?.fieldInfo || {}
|
||||
let current = 0
|
||||
const calcScore = point => (current += (Number(point) || 0))
|
||||
if (item?.pointType == 0) {//此题有唯一答案和分值
|
||||
field.fieldValue?.toString() == item.answer?.toString() && calcScore(item?.points)
|
||||
} else if (item?.pointType == 1) {//每个选项都有对应分值
|
||||
item?.options?.map(op => {
|
||||
if (typeof field.fieldValue == "object") {
|
||||
if (field.fieldValue?.includes(op.label)) {
|
||||
calcScore(op.point)
|
||||
}
|
||||
} else {
|
||||
op.label == field.fieldValue && calcScore(op.point)
|
||||
}
|
||||
})
|
||||
} else if (item?.pointType == 2) {//答对几项得几分,答错不得分
|
||||
item?.options?.some(op => {
|
||||
if (typeof field.fieldValue == "object") {
|
||||
if (field.fieldValue?.includes(op.label)) {
|
||||
if (item.answer?.includes(op.label)) calcScore(op.point)
|
||||
else return current = 0
|
||||
}
|
||||
} else {
|
||||
op.label == field.fieldValue && calcScore(op.point)
|
||||
}
|
||||
})
|
||||
}
|
||||
this.score += current
|
||||
//打印每题打分
|
||||
if (!!field.fieldValue) {
|
||||
const typeResult = (reply, answer) => {
|
||||
console.log("题目:%s,回答:%s,得分:%s,总分:%s \n 答案:%s", field.fieldName,
|
||||
reply, current, this.score, answer)
|
||||
}
|
||||
typeResult(field.fieldValue?.toString(), item.answer?.toString())
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.isResult ? this.getResult() : this.getForm()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.formDetail {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #fff;
|
||||
|
||||
.headPicture {
|
||||
width: 100%;
|
||||
height: 320px;
|
||||
|
||||
.img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
padding: 32px;
|
||||
box-sizing: border-box;
|
||||
font-size: 34px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
padding: 32px;
|
||||
box-sizing: border-box;
|
||||
background: #fff;
|
||||
z-index: 99;
|
||||
|
||||
.bottomBtn {
|
||||
width: 100%;
|
||||
line-height: 96px;
|
||||
background: #287DE1;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
height: 96px;
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.tableExplain {
|
||||
font-size: 28px;
|
||||
font-weight: 400;
|
||||
color: #666;
|
||||
padding: 32px 24px;
|
||||
}
|
||||
|
||||
::v-deep .u-form-item {
|
||||
.u-form-item--left {
|
||||
font-size: 30px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.u-form-item--right__content__slot > * {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.display {
|
||||
justify-content: space-between;
|
||||
min-height: 58px;
|
||||
}
|
||||
|
||||
.uni-radio-input, .uni-checkbox-input {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.label {
|
||||
flex-shrink: 0;
|
||||
|
||||
* + & {
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.option {
|
||||
width: 100%;
|
||||
margin-right: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 64px 32px 200px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
::v-deep .scorePane {
|
||||
width: calc(100% - 40px);
|
||||
padding: 0 32px;
|
||||
height: 124px;
|
||||
background: #E9F2FF;
|
||||
border-radius: 16px;
|
||||
font-size: 30px;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
margin-top: 48px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.fill {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
em {
|
||||
font-size: 48px;
|
||||
font-weight: bold;
|
||||
color: #2C72FE;
|
||||
font-style: normal;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
BIN
src/project/saas/AppAskForm/components/img/user-icon.png
Normal file
BIN
src/project/saas/AppAskForm/components/img/user-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
Reference in New Issue
Block a user