调查问卷

This commit is contained in:
yanran200730
2021-11-23 11:51:14 +08:00
parent 2ccd572a11
commit 2fba037d57
10 changed files with 325 additions and 215 deletions

View File

@@ -65,7 +65,7 @@
"node-sass": "npm:dart-sass@^1.25.0", "node-sass": "npm:dart-sass@^1.25.0",
"postcss-comment": "^2.0.0", "postcss-comment": "^2.0.0",
"sass-loader": "^7.1.0", "sass-loader": "^7.1.0",
"uview-ui": "^2.0.3", "uview-ui": "^1.8.4",
"vue-template-compiler": "^2.6.11" "vue-template-compiler": "^2.6.11"
}, },
"browserslist": [ "browserslist": [
@@ -85,4 +85,4 @@
} }
} }
} }
} }

View File

@@ -1,69 +1,57 @@
<template> <template>
<div class="form"> <div class="form">
<div class="form-content"> <component
<add-list ref="addList" v-if="currIndex === 1"></add-list> :is="component"
<list ref="list" v-if="currIndex === 0"></list> @change="onChange"
</div> :params="params">
<ai-tabbar :active.sync="currIndex" :list="tabBar"/> </component>
<div class="form-footer"></div>
</div> </div>
</template> </template>
<script> <script>
import addList from './components/addList.vue' import Tabbar from './components/Tabbar.vue'
import list from './components/list.vue' import AddForm from './components/AddForm.vue'
import AiTabbar from '../../components/AiTabbar'
export default { export default {
name: 'AppAskForm', name: 'AppAskForm',
appName: '问卷表单', appName: '问卷表单',
data () { data () {
return { return {
currIndex: 0 component: 'Tabbar',
} params: {}
},
components: {
addList,
AiTabbar,
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)
}))
}
},
onLoad () {
uni.$on('reload', () => {
if (this.currIndex === 0) {
this.$refs.list.reload()
} else {
this.$refs.addList.getList()
} }
}) },
},
onReachBottom() { components: {
if (this.currIndex === 0) { Tabbar,
this.$refs.list.getList() AddForm
},
onLoad () {
uni.$on('reload', () => {
if (this.currIndex === 0) {
this.$refs.list.reload()
} else {
this.$refs.addList.getList()
}
})
},
methods: {
onChange (e) {
this.params = e.params
this.component = e.type
},
},
onReachBottom() {
if (this.currIndex === 0) {
this.$refs.list.getList()
}
} }
} }
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.form {
padding-bottom: 98px;
}
</style> </style>

View File

@@ -1,117 +1,137 @@
<template> <template>
<div class="add-form" v-if="pageShow"> <div class="add-form" v-if="pageShow">
<div class="header-pic"> <div v-show="!isShowConfig">
<image v-if="form.headPicture" :src="form.headPicture" /> <div class="header-pic">
<span @click="upload">更换图片</span> <image v-if="form.headPicture" :src="form.headPicture" />
</div> <span @click="upload">更换图片</span>
<div class="form-info">
<h2>文本选项</h2>
<div class="form-info__wrapper">
<textarea class="title" placeholder="请输入标题 (必填)" :maxlength="30" :auto-height="true" v-model="form.title"></textarea>
<u-input class="content" :clearable="false" type="textarea" v-model="form.tableExplain" placeholder="请输入表单描述 (选填)" :height="80" :auto-height="true" :maxlength="255"></u-input>
</div> </div>
</div> <div class="form-info">
<draggable <h2>文本选项</h2>
class="components-list" <div class="form-info__wrapper">
v-model="targetList" <textarea class="title" placeholder="请输入标题 (必填)" :maxlength="30" :auto-height="true" v-model="form.title"></textarea>
:animation="340" <textarea
scroll style="wdith: 100%"
element="div" class="content"
:options="{ border="none"
animation: 340, :clearable="false"
handle: '.components-item__title' type="textarea"
}" v-model="form.tableExplain"
draggable=".components-item" placeholder="请输入表单描述 (选填)"
:sort="true"> :maxlength="255">
<div class="components-item" v-for="(item, index) in targetList" :key="index" @click="toFiledSetting(item, index)"> </textarea>
<div class="components-item__title"> </div>
<div class="components-item__title--left"> </div>
<em :style="{opacity: item.required ? 1 : 0}">*</em> <draggable
<i>{{ index + 1 }}.</i> class="components-list"
<h2>{{ item.label }}</h2> v-model="targetList"
:animation="340"
scroll
element="div"
:options="{
animation: 340,
handle: '.components-item__title'
}"
draggable=".components-item"
:sort="true">
<div class="components-item" v-for="(item, index) in targetList" :key="index" @click="toFiledSetting(item, index)">
<div class="components-item__title">
<div class="components-item__title--left">
<em :style="{opacity: item.required ? 1 : 0}">*</em>
<i>{{ index + 1 }}.</i>
<h2>{{ item.label }}</h2>
</div>
<image :src="`${$cdn}askform/sc1.png`" @click.stop="removeComponent(index)" @touchstart.stop="removeComponent(index)" />
</div>
<div class="components-item__filed">
<template v-if="(item.type === 'radio')">
<radio-group v-model="item.value">
<radio class="u-radio" disabled style="display: block;" v-for="(field, i) in item.options" :key="i">
<image :src="field.img[0].url" v-if="field.img.length"/>
<span>{{ field.label }}</span>
</radio>
</radio-group>
</template>
<template v-if="(item.type === 'checkbox')">
<checkbox-group v-model="item.value" wrap>
<checkbox class="u-checkbox" disabled :name="field.label" v-for="(field, i) in item.options" :key="i">
<image :src="field.img[0].url" v-if="field.img.length"/>
<span>{{ field.label }}</span>
</checkbox>
</checkbox-group>
</template>
<template v-if="(item.type === 'select')">
<div class="components-item__select">
<span>{{ item.placeholder }}</span>
<u-icon name="arrow-down" color="#DEDFDF" />
</div>
</template>
<template v-if="(item.type === 'upload')">
<div class="components-item__select components-item__textarea components-item__upload">
<image :src="`${$cdn}askform/upload.png`" />
<span>选择图片2M以内</span>
</div>
</template>
<template v-if="(item.type === 'input')">
<div class="components-item__select">
<span>{{ item.placeholder }}</span>
</div>
</template>
<template v-if="(item.type === 'textarea')">
<div class="components-item__select components-item__textarea">
<span>{{ item.placeholder }}</span>
</div>
</template>
</div> </div>
<image :src="`${$cdn}askform/sc1.png`" @click.stop="removeComponent(index)" @touchstart.stop="removeComponent(index)" />
</div>
<div class="components-item__filed">
<template v-if="(item.type === 'radio')">
<u-radio-group v-model="item.value" wrap>
<u-radio disabled :name="field.label" v-for="(field, i) in item.options" :key="i">
<image :src="field.img[0].url" v-if="field.img.length"/>
<span>{{ field.label }}</span>
</u-radio>
</u-radio-group>
</template>
<template v-if="(item.type === 'checkbox')">
<u-checkbox-group v-model="item.value" wrap>
<u-checkbox disabled :name="field.label" v-for="(field, i) in item.options" :key="i">
<image :src="field.img[0].url" v-if="field.img.length"/>
<span>{{ field.label }}</span>
</u-checkbox>
</u-checkbox-group>
</template>
<template v-if="(item.type === 'select')">
<div class="components-item__select">
<span>{{ item.placeholder }}</span>
<u-icon name="arrow-down" color="#DEDFDF" />
</div>
</template>
<template v-if="(item.type === 'upload')">
<div class="components-item__select components-item__textarea components-item__upload">
<image :src="`${$cdn}askform/upload.png`" />
<span>选择图片2M以内</span>
</div>
</template>
<template v-if="(item.type === 'input')">
<div class="components-item__select">
<span>{{ item.placeholder }}</span>
</div>
</template>
<template v-if="(item.type === 'textarea')">
<div class="components-item__select components-item__textarea">
<span>{{ item.placeholder }}</span>
</div>
</template>
</div> </div>
</draggable>
<div class="add-form__btn" @click="isShow = true">
<image :src="`${$cdn}askform/add.png`" />
<span>添加问题</span>
</div> </div>
</draggable> <div class="add-form__footer">
<div class="add-form__btn" @click="isShow = true"> <div>
<image :src="`${$cdn}askform/add.png`" /> <span @click="toPreview">预览</span>
<span>添加问题</span> <span @click="toSetting">设置</span>
</div>
<div @click="onConfirm">立即发布</div>
</div>
<u-popup :show="isShow" :closeable="false" mode="bottom" @close="isShow = false">
<div class="add-popup">
<div class="add-popup__title">
<h2>添加问题</h2>
<image :src="`${$cdn}askform/zk.png`" mode="aspectFit" @click="isShow = false" />
</div>
<div class="add-popup__list">
<span @click="toFiledSetting('radio')">单选题</span>
<span @click="toFiledSetting('checkbox')">多选题</span>
<span @click="toFiledSetting('select')">单下拉框</span>
<span @click="toFiledSetting('input')">单行填空</span>
<span @click="toFiledSetting('textarea')">多行填空</span>
<span @click="toFiledSetting('upload')">上传图片</span>
</div>
</div>
</u-popup>
<AiBack custom @back="back"></AiBack>
</div> </div>
<div class="add-form__footer"> <div class="detail" v-if="isShowConfig">
<div> <component :is="component" @change="onChange" @back="isShowConfig = false" :id="id" :type="type" :formConfig="formConfig"></component>
<span @click="toPreview">预览</span>
<span @click="toSetting">设置</span>
</div>
<div @click="onConfirm">立即发布</div>
</div> </div>
<u-popup v-model="isShow" :closeable="false" mode="bottom">
<div class="add-popup">
<div class="add-popup__title">
<h2>添加问题</h2>
<image :src="`${$cdn}askform/zk.png`" mode="aspectFit" @click="isShow = false" />
</div>
<div class="add-popup__list">
<span @click="toFiledSetting('radio')">单选题</span>
<span @click="toFiledSetting('checkbox')">多选题</span>
<span @click="toFiledSetting('select')">单下拉框</span>
<span @click="toFiledSetting('input')">单行填空</span>
<span @click="toFiledSetting('textarea')">多行填空</span>
<span @click="toFiledSetting('upload')">上传图片</span>
</div>
</div>
</u-popup>
<AiBack></AiBack>
</div> </div>
</template> </template>
<script> <script>
import AiBack from "@/components/AiBack"; import AiBack from "@/components/AiBack";
import draggable from 'vuedraggable' import draggable from 'vuedraggable'
import FiledConfig from './FiledConfig'
import FormSetting from './FormSetting'
export default { export default {
props: ['params'],
data () { data () {
return { return {
pageShow: false, pageShow: false,
isShowConfig: false,
form: { form: {
tableExplain: '详细描述', tableExplain: '详细描述',
title: '问卷调查', title: '问卷调查',
@@ -138,28 +158,32 @@
id: '', id: '',
isQuote: false, isQuote: false,
touchStart: 0, touchStart: 0,
component: '',
formConfig: {} formConfig: {}
} }
}, },
components: { components: {
AiBack, AiBack,
draggable draggable,
FormSetting,
// FiledConfig
}, },
onLoad (query) { mounted () {
this.type = Number(query.type) this.type = Number(this.params.type)
if (query.isQuote) { if (this.params.isQuote) {
this.isQuote = true this.isQuote = true
} }
if (query.id) { if (this.params.id) {
this.id = query.id this.id = this.params.id
this.getInfo(query.id) this.getInfo(this.params.id)
} else { } else {
this.pageShow = true this.pageShow = true
} }
this.init() this.init()
uni.$on('setting', res => { uni.$on('setting', res => {
@@ -181,11 +205,23 @@
methods: { methods: {
toSetting () { toSetting () {
uni.navigateTo({ // uni.navigateTo({
url: `/pages/askForm/formSetting?id=${this.id}&formConfig=${JSON.stringify(this.formConfig)}` // url: `/pages/askForm/formSetting?id=${this.id}&formConfig=${JSON.stringify(this.formConfig)}`
// })
this.component = 'FormSetting'
this.isShowConfig = true
},
back () {
this.$emit('change', {
type: 'Tabbar'
}) })
}, },
onChange (e) {
},
removeComponent (index) { removeComponent (index) {
this.targetList.splice(index, 1) this.targetList.splice(index, 1)
}, },
@@ -394,6 +430,15 @@
border: 1px solid #EEEFF0; border: 1px solid #EEEFF0;
background: #fff; background: #fff;
.u-checkbox, .u-radio {
display: block;
image {
width: 100px;
height: 100px;
margin: 0 10px;
}
}
::v-deep .u-radio, ::v-deep .u-checkbox { ::v-deep .u-radio, ::v-deep .u-checkbox {
position: relative; position: relative;
margin-bottom: 20px; margin-bottom: 20px;
@@ -417,12 +462,6 @@
span { span {
line-height: 1.5; line-height: 1.5;
} }
image {
width: 100px;
height: 100px;
margin: 0 10px;
}
} }
} }
span { span {
@@ -657,13 +696,10 @@
} }
.content { .content {
width: 100%;
padding: 30px 0!important; padding: 30px 0!important;
font-size: 28px; color: #333;
font-size: 28px!important;
::v-deep textarea {
color: #333;
font-size: 28px!important;
}
} }
} }
} }

View File

@@ -9,8 +9,8 @@
</div> </div>
<div class="setting-item__right"> <div class="setting-item__right">
<u-radio-group v-model="periodValidityType" active-color="#1088F9"> <u-radio-group v-model="periodValidityType" active-color="#1088F9">
<u-radio name="0">永久有效</u-radio> <u-radio name="0" label="永久有效" style="padding-right: 20rpx;"></u-radio>
<u-radio name="1">自定义时间</u-radio> <u-radio name="1" label="自定义时间"></u-radio>
</u-radio-group> </u-radio-group>
<u-icon name="arrow-right" color="#E1E2E3" /> <u-icon name="arrow-right" color="#E1E2E3" />
</div> </div>
@@ -40,8 +40,8 @@
</div> </div>
<div class="setting-item__right"> <div class="setting-item__right">
<u-radio-group v-model="commitType" active-color="#1088F9"> <u-radio-group v-model="commitType" active-color="#1088F9">
<u-radio name="0">不限次数</u-radio> <u-radio name="0" label="不限次数" style="padding-right: 20rpx;"></u-radio>
<u-radio name="1">限提交一次</u-radio> <u-radio name="1" label="限提交一次"></u-radio>
</u-radio-group> </u-radio-group>
</div> </div>
</div> </div>
@@ -51,7 +51,7 @@
<image :src="`${$cdn}askform/bz.png`" @click="tips = '当客户点击或者发布表单时,发送表单的员工将会受到消息提醒' , isShowModal = true" /> <image :src="`${$cdn}askform/bz.png`" @click="tips = '当客户点击或者发布表单时,发送表单的员工将会受到消息提醒' , isShowModal = true" />
</div> </div>
<div class="setting-item__right"> <div class="setting-item__right">
<u-switch v-model="actionNotice" active-value="1" inactive-value="0" :size="40" active-color="#1088F9"></u-switch> <u-switch v-model="actionNotice" active-value="1" :size="20" active-color="#1088F9"></u-switch>
</div> </div>
</div> </div>
<div class="setting-item"> <div class="setting-item">
@@ -60,7 +60,7 @@
<image :src="`${$cdn}askform/bz.png`" @click="tips = '当客户点击或者发布表单时,会将客户的打开行为记录在客户动态里' , isShowModal = true" /> <image :src="`${$cdn}askform/bz.png`" @click="tips = '当客户点击或者发布表单时,会将客户的打开行为记录在客户动态里' , isShowModal = true" />
</div> </div>
<div class="setting-item__right"> <div class="setting-item__right">
<u-switch v-model="dynamicNotice" active-value="1" inactive-value="0" :size="40" active-color="#1088F9"></u-switch> <u-switch v-model="dynamicNotice" active-value="1" :size="20" active-color="#1088F9"></u-switch>
</div> </div>
</div> </div>
</div> </div>
@@ -70,23 +70,25 @@
</div> </div>
<div @click="confirm">{{ type === 'edit' ? '发布' : '确定' }}</div> <div @click="confirm">{{ type === 'edit' ? '发布' : '确定' }}</div>
</div> </div>
<u-modal v-model="isShowModal" :content="tips"></u-modal> <u-modal :show="isShowModal" :content="tips"></u-modal>
<u-picker mode="time" v-model="isShowTime" :show-time-tag="true" @confirm="onTimeChange" :params="params"></u-picker> <u-datetime-picker
mode="datetime"
:value="periodValidityEndTime"
:show="isShowTime"
:show-time-tag="true"
@cancel="isShowTime = false"
@close="isShowTime = false"
@confirm="onTimeChange">
</u-datetime-picker>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
props: ['id', 'formConfig', 'type'],
data () { data () {
return { return {
params: {
year: true,
month: true,
day: true,
hour: true,
minute: true,
second: true
},
tips: '', tips: '',
isShowModal: false, isShowModal: false,
actionNotice: true, actionNotice: true,
@@ -95,19 +97,17 @@ export default {
wechatId: '0', wechatId: '0',
periodValidityEndTime: '', periodValidityEndTime: '',
isShowTime: false, isShowTime: false,
periodValidityType: '0', periodValidityType: '0'
type: '',
id: ''
} }
}, },
onLoad (query) { mounted () {
if (query.id) { if (this.id) {
this.id = query.id this.id = this.id
this.getInfo(query.id) this.getInfo(this.id)
this.type = query.type this.type = this.type
} else if (query.formConfig && query.formConfig !== '{}') { } else if (this.formConfig) {
const res = JSON.parse(query.formConfig) const res = this.formConfig
this.periodValidityType = res.periodValidityType this.periodValidityType = res.periodValidityType
this.commitType = res.commitType this.commitType = res.commitType
this.actionNotice = res.actionNotice === '1' this.actionNotice = res.actionNotice === '1'
@@ -121,13 +121,12 @@ export default {
methods: { methods: {
onTimeChange (e) { onTimeChange (e) {
this.periodValidityEndTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}:${e.second}` this.isShowTime = false
this.periodValidityEndTime = uni.$u.timeFormat(e.value, 'yyyy-mm-dd hh:MM:ss')
}, },
back () { back () {
uni.navigateBack({ this.$emit('back')
delta: 1
})
}, },
getInfo (id) { getInfo (id) {

View File

@@ -0,0 +1,74 @@
<template>
<div class="form">
<div class="form-content">
<add-list ref="addList" v-if="currIndex === 1" @change="onChange"></add-list>
<list ref="list" v-if="currIndex === 0" @change="onChange"></list>
</div>
<ai-tabbar :active.sync="currIndex" :list="tabBar"/>
</div>
</template>
<script>
import AddList from './AddList.vue'
import List from './List.vue'
import AiTabbar from '@/components/AiTabbar'
export default {
name: 'AppAskForm',
appName: '问卷表单',
data () {
return {
currIndex: 0
}
},
components: {
AddList,
AiTabbar,
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)
}))
}
},
onLoad () {
uni.$on('reload', () => {
if (this.currIndex === 0) {
this.$refs.list.reload()
} else {
this.$refs.addList.getList()
}
})
},
methods: {
onChange (e) {
this.$emit('change', e)
}
},
onReachBottom() {
if (this.currIndex === 0) {
this.$refs.list.getList()
}
}
}
</script>
<style lang="scss" scoped>
.form {
padding-bottom: 98px;
}
</style>

View File

@@ -3,7 +3,7 @@
<div class="form-list"> <div class="form-list">
<div <div
class="form-list__item" class="form-list__item"
@click="toAdd(`/pages/askForm/addForm?type=${index}`)" @click="toAdd(index)"
:style="{'background-image': `url(${$cdn}askform/${index + 1}.png)`}" :style="{'background-image': `url(${$cdn}askform/${index + 1}.png)`}"
v-for="(item, index) in itemList" v-for="(item, index) in itemList"
:key="index"> :key="index">
@@ -51,15 +51,22 @@ export default {
}, },
methods: { methods: {
toAdd (url) { toAdd (type) {
uni.navigateTo({ this.$emit('change', {
url type: 'AddForm',
params: {
type
}
}) })
}, },
quote (id) { quote (id) {
uni.navigateTo({ this.$emit('change', {
url: `/pages/askForm/addForm?isQuote=1&id=${id}` type: 'AddForm',
params: {
id,
isQuote: 1
}
}) })
}, },

View File

@@ -29,7 +29,7 @@
</div> </div>
<ai-empty v-if="!list.length && isMore"></ai-empty> <ai-empty v-if="!list.length && isMore"></ai-empty>
</div> </div>
<u-popup :show="isShow" :closeable="false" mode="bottom" :z-index="11"> <u-popup :show="isShow" :closeable="false" mode="bottom" @close="isShow = false">
<div class="popup"> <div class="popup">
<h2>{{ info.title }}</h2> <h2>{{ info.title }}</h2>
<div class="operate-list"> <div class="operate-list">
@@ -98,6 +98,7 @@ export default {
templateType: 0, templateType: 0,
title: '' title: ''
}, },
value: '',
id: '', id: '',
info: {}, info: {},
isMore: false, isMore: false,
@@ -204,13 +205,16 @@ export default {
this.isShow = false this.isShow = false
}, },
toEdit() { toEdit () {
if (this.info.dataCount !== 0) { if (this.info.dataCount !== 0) {
return this.$u.toast('该表单已有数据,无法编辑!') return this.$u.toast('该表单已有数据,无法编辑!')
} }
uni.navigateTo({ this.$emit('change', {
url: `/pages/askForm/addForm?id=${this.id}` type: 'AddForm',
params: {
id: this.id
}
}) })
this.isShow = false this.isShow = false
@@ -294,6 +298,10 @@ export default {
.form { .form {
::v-deep .u-search { ::v-deep .u-search {
margin-bottom: 0 !important; margin-bottom: 0 !important;
.u-search__content__input {
height: 100%;
}
} }
.popup { .popup {

View File

@@ -1,9 +1,7 @@
<template> <template>
<section class="formList"> <section class="formList">
<ai-top-fixed> <ai-top-fixed>
<u-search placeholder="请输入标题" :show-action="false" search-icon-color="#ccc" <u-search placeholder="请输入标题" :show-action="false" search-icon-color="#ccc" v-model="search.title" @search="page.current=1,getList()"/>
v-model="search.title" @search="page.current=1,getList()"/>
</ai-top-fixed> </ai-top-fixed>
<div class="mainPane"> <div class="mainPane">
<div class="formBox column" flex v-for="op in list" :key="op.id"> <div class="formBox column" flex v-for="op in list" :key="op.id">