Browse Source

完善表单功能

old
wangqing 5 years ago
parent
commit
2a534af2af
  1. 4
      src/api/index.js
  2. 3
      src/assets/styles/home.scss
  3. 36
      src/components/generator/config.js
  4. 36
      src/components/generator/drawingDefalut.js
  5. 4
      src/components/parser/example/Index.vue
  6. 1
      src/utils/db.js
  7. 71
      src/utils/formDataConvert.js
  8. 9
      src/utils/sign.js
  9. 42
      src/views/form/RightPanel.vue
  10. 108
      src/views/form/index.vue
  11. 2
      src/views/home/index.vue
  12. 2
      src/views/project/create.vue

4
src/api/index.js

@ -1,6 +1,6 @@
import axios from 'axios'
// import qs from 'qs'
import { MessageBox, Message } from 'element-ui'
import {MessageBox, Message} from 'element-ui'
import router from '@/router/index'
import store from '@/store/index'
import signMd5Utils from '@/utils/sign'
@ -77,7 +77,7 @@ api.interceptors.response.use(
const res = response.data
if (res.code === 200) {
return Promise.resolve(res)
} else if (res.code === 500) {
} else if (res.code === 500 || res.code == 403) {
// 这里做错误提示,如果使用了 element ui 则可以使用 Message 进行提示
Message({
message: res.msg || 'Error',

3
src/assets/styles/home.scss

@ -4,6 +4,7 @@ $lighterBlue: #409eff;
position: relative;
width: 100%;
height: 100%;
overflow-y: hidden;
}
.components-list {
padding: 8px;
@ -79,6 +80,7 @@ $lighterBlue: #409eff;
box-sizing: border-box;
background-color: rgba(255, 255, 255, 100);
border: 2px solid rgba(255, 255, 255, 100);
overflow-y: hidden;
}
.center-board {
height: 100vh;
@ -112,6 +114,7 @@ $lighterBlue: #409eff;
.center-board-row {
padding: 12px 12px 15px 12px;
box-sizing: border-box;
overflow-y: hidden;
& > .el-form {
// 69 = 12+15+42
height: calc(100vh - 69px);

36
src/components/generator/config.js

@ -12,7 +12,8 @@ export const formConf = {
title: '问卷名称',
description: '为了给您提供更好的服务,希望您能抽出几分钟时间,将您的感受和建议告诉我们,我们非常重视每位\n' +
'用户的宝贵意见,期待您的参与!现在我们就马上开始吧!',
formBtns: true
formBtns: true,
unFocusedComponentBorder: true
}
// 输入型组件 【左面板】
@ -135,25 +136,6 @@ export const inputComponents = [
precision: undefined,
'controls-position': '',
disabled: false
},
{
__config__: {
label: '编辑器',
showLabel: true,
changeTag: true,
labelWidth: null,
tag: 'tinymce',
tagIcon: 'rich-text',
defaultValue: null,
span: 24,
layout: 'colFormItem',
required: true,
regList: [],
document: 'http://tinymce.ax-z.cn'
},
placeholder: '请输入',
height: 300, // 编辑器高度
branding: false // 隐藏右下角品牌烙印
}
]
@ -349,7 +331,7 @@ export const selectComponents = [
range: false
},
{
typeId: 12,
typeId: 11,
__config__: {
label: '时间选择',
tag: 'el-time-picker',
@ -375,7 +357,7 @@ export const selectComponents = [
'value-format': 'HH:mm:ss'
},
{
typeId: 13,
typeId: 12,
__config__: {
label: '时间范围',
tag: 'el-time-picker',
@ -401,7 +383,7 @@ export const selectComponents = [
'value-format': 'HH:mm:ss'
},
{
typeId: 14,
typeId: 13,
__config__: {
label: '日期选择',
tag: 'el-date-picker',
@ -426,7 +408,7 @@ export const selectComponents = [
readonly: false
},
{
typeId: 15,
typeId: 14,
__config__: {
label: '日期范围',
tag: 'el-date-picker',
@ -453,7 +435,7 @@ export const selectComponents = [
readonly: false
},
{
typeId: 16,
typeId: 15,
__config__: {
label: '评分',
tag: 'el-rate',
@ -476,7 +458,7 @@ export const selectComponents = [
disabled: false
},
{
typeId: 17,
typeId: 16,
__config__: {
label: '颜色选择',
tag: 'el-color-picker',
@ -497,7 +479,7 @@ export const selectComponents = [
size: 'medium'
},
{
typeId: 18,
typeId: 17,
__config__: {
label: '上传',
tag: 'el-upload',

36
src/components/generator/drawingDefalut.js

@ -1,37 +1,3 @@
export default [
{
__config__: {
label: '单行文本',
labelWidth: null,
showLabel: true,
changeTag: true,
tag: 'el-input',
tagIcon: 'input',
defaultValue: undefined,
required: true,
layout: 'colFormItem',
span: 24,
document: 'https://element.eleme.cn/#/zh-CN/component/input',
// 正则校验规则
regList: [{
pattern: '/^1(3|4|5|7|8|9)\\d{9}$/',
message: '手机号格式错误'
}]
},
// 组件的插槽属性
__slot__: {
prepend: '',
append: ''
},
__vModel__: 'mobile',
placeholder: '请输入手机号',
style: { width: '100%' },
clearable: true,
'prefix-icon': 'el-icon-mobile',
'suffix-icon': '',
maxlength: 11,
'show-word-limit': true,
readonly: false,
disabled: false
}
]

4
src/components/parser/example/Index.vue

@ -187,7 +187,7 @@ export default {
disabled: false,
span: 24,
formBtns: true,
unFocusedComponentBorder: false
unFocusedComponentBorder: true
},
formConf2: {
fields: [
@ -270,7 +270,7 @@ export default {
disabled: false,
span: 24,
formBtns: true,
unFocusedComponentBorder: false
unFocusedComponentBorder: true
}
}
},

1
src/utils/db.js

@ -30,6 +30,7 @@ export function getIdGlobal(key) {
}
export function saveIdGlobal(id, key) {
if (key) localStorage.setItem(`${DRAWING_ID}:${key}`, `${id}`)
}

71
src/utils/formDataConvert.js

@ -4,8 +4,7 @@ import _ from 'lodash'
* 表单json转换为后台需要的对象
* @param item
*/
export function formItemConvertData(item) {
console.log(item)
export function formItemConvertData(item, projectKey) {
let data = {
'type': item.typeId,
'formItemId': item.__config__.formId,
@ -13,30 +12,86 @@ export function formItemConvertData(item) {
'defaultValue': item.defaultValue,
'required': item.__config__.required,
'placeholder': item.placeholder,
'regList': item.__config__.regList
'regList': item.__config__.regList,
'projectKey': projectKey
}
let extend = {}
let expand = {}
let param = dataParams[item.typeId]
if (param) {
Object.keys(param).forEach(key => {
let value = _.get(item, param[key])
_.set(extend, key, value)
_.set(expand, key, value)
})
_.set(data, 'extend', extend)
_.set(data, 'expand', expand)
}
console.log(data)
return data
}
/**
* 不同属性的存在json的位置不用 使用变量记录key 通过lodash表达式获取
* 不同属性的存在json的位置不用 使用变量记录key 通过lodash表达式获取 1 2 3 4 为typeId
* @type {{'1': {maxlength: string, prepend: string, append: string}}}
*/
let dataParams = {
//单行文本
1: {
'prepend': '__slot__.prepend',
'maxlength': 'maxlength',
'append': '__slot__.append'
},
// 多行文本
2: {
'minRows': 'autosize.minRows',
'maxRows': 'autosize.maxRows',
'maxlength': 'maxlength'
},
//计数器
4: {
'min': 'min',
'max': 'min',
'maxlength': 'maxlength',
'step': 'step',
'step-strictly': 'step-strictly',
'precision': 'precision',
'controls-position': 'controls-position'
},
//下拉选择
5: {
'options': '__slot__.options',
'filterable': 'filterable',
'multiple': 'multiple'
},
//级联选择
6: {
'options': 'options',
'filterable': 'filterable',
'multiple': 'props.props.multiple'
},
//单选框组
7: {
'options': '__slot__.options',
'filterable': 'filterable',
'multiple': 'props.props.multiple'
},
//单选框组
8: {
'options': '__slot__.options',
'max': 'max',
'min': 'min'
}, //开关
9: {
},
//滑块
10:{
'min': 'min',
'max': 'max',
'step': 'step',
},//时间选择
11:{
}
}

9
src/utils/sign.js

@ -1,7 +1,7 @@
/* eslint-disable no-alert */
import md5 from 'js-md5'
import constants from './constants'
import _ from 'lodash'
export default class sign {
/**
* json参数升序
@ -31,13 +31,8 @@ export default class sign {
static getSign(url, requestParams) {
let urlParams = this.parseQueryString(url)
console.log(urlParams)
let jsonObj = this.mergeObject(urlParams, requestParams)
console.log(jsonObj)
let jsonObj = _.merge(urlParams, requestParams)
let requestBody = this.sortAsc(jsonObj)
console.log(requestBody)
console.log(constants.signSecret + JSON.stringify(requestBody))
console.log(md5(constants.signSecret + JSON.stringify(requestBody)).toLowerCase())
return md5(constants.signSecret + JSON.stringify(requestBody)).toLowerCase()
}

42
src/views/form/RightPanel.vue

@ -2,12 +2,8 @@
<div class="right-board">
<el-tabs v-model="currentTab" class="center-tabs">
<el-tab-pane label="组件属性" name="field" />
<el-tab-pane label="表单属性" name="form" />
</el-tabs>
<div class="field-box">
<a class="document-link" target="_blank" :href="documentLink" title="查看组件文档">
<i class="el-icon-link" />
</a>
<el-scrollbar class="right-scrollbar">
<!-- 组件属性 -->
<el-form v-show="currentTab==='field' && showField" size="small" label-width="90px">
@ -580,7 +576,6 @@
</div>
</template>
</el-form>
<!-- 表单属性 -->
<el-form v-show="currentTab === 'form'" size="small" label-width="90px">
<el-form-item label="表单名">
<el-input v-model="formConf.formRef" placeholder="请输入表单名(ref)" />
@ -650,7 +645,7 @@ import {
inputComponents, selectComponents
} from '@/components/generator/config'
import { saveFormConf } from '@/utils/db'
import {debounce} from "throttle-debounce"
const dateTimeFormat = {
date: 'yyyy-MM-dd',
week: 'yyyy 第 WW 周',
@ -767,12 +762,6 @@ export default {
}
},
computed: {
documentLink() {
return (
this.activeData.__config__.document
|| 'https://element.eleme.cn/#/zh-CN/component/installation'
)
},
dateOptions() {
if (
this.activeData.type !== undefined
@ -816,8 +805,16 @@ export default {
saveFormConf(val)
},
deep: true
},
activeData : {
handler(val) {
if(val){
this.dataChange(val)
}
},
deep: true
},
},
methods: {
addReg() {
this.activeData.__config__.regList.push({
@ -957,6 +954,9 @@ export default {
if (!target) target = selectComponents.find(item => item.__config__.tagIcon === tagIcon)
this.$emit('tag-change', target)
},
dataChange: debounce(430, false, function(val) {
this.$emit('data-change', val)
}),
changeRenderKey() {
if (needRerenderList.includes(this.activeData.__config__.tag)) {
this.activeData.__config__.renderKey = +new Date()
@ -967,6 +967,7 @@ export default {
</script>
<style lang="scss" scoped>
@import '@/assets/styles/index';
.right-board {
width: 350px;
position: absolute;
@ -1018,22 +1019,7 @@ export default {
display: none;
}
}
.document-link {
position: absolute;
display: block;
width: 26px;
height: 26px;
top: 0;
left: 0;
cursor: pointer;
background: #409eff;
z-index: 1;
border-radius: 0 0 6px 0;
text-align: center;
line-height: 26px;
color: #fff;
font-size: 18px;
}
.node-label{
font-size: 14px;
}

108
src/views/form/index.vue

@ -43,23 +43,23 @@
</div>
<div class="center-board">
<div class="action-bar">
<el-button icon="el-icon-video-play" type="text" @click="run">
运行
</el-button>
<el-button icon="el-icon-view" type="text" @click="showJson">
查看json
</el-button>
<el-button icon="el-icon-download" type="text" @click="download">
导出vue文件
</el-button>
<el-button class="copy-btn-main" icon="el-icon-document-copy" type="text" @click="copy">
复制代码
</el-button>
<el-button class="delete-btn" icon="el-icon-delete" type="text" @click="empty">
清空
</el-button>
</div>
<!-- <div class="action-bar">-->
<!-- <el-button icon="el-icon-video-play" type="text" @click="run">-->
<!-- 运行-->
<!-- </el-button>-->
<!-- <el-button icon="el-icon-view" type="text" @click="showJson">-->
<!-- 查看json-->
<!-- </el-button>-->
<!-- <el-button icon="el-icon-download" type="text" @click="download">-->
<!-- 导出vue文件-->
<!-- </el-button>-->
<!-- <el-button class="copy-btn-main" icon="el-icon-document-copy" type="text" @click="copy">-->
<!-- 复制代码-->
<!-- </el-button>-->
<!-- <el-button class="delete-btn" icon="el-icon-delete" type="text" @click="empty">-->
<!-- 清空-->
<!-- </el-button>-->
<!-- </div>-->
<el-row type="flex" align="middle" justify="justify">
<el-col :span="18" :offset="6">
<el-menu default-active="1" style="background-color: transparent" mode="horizontal">
@ -71,19 +71,23 @@
</el-menu>
</el-col>
</el-row>
<el-scrollbar class="center-scrollbar">
<el-row class="center-scrollbar">
<el-row class="center-board-row" :gutter="formConf.gutter">
<el-row type="flex" justify="center" align="middle">
<el-col :span="20" style="text-align: center">
<h4 class="form-name-text" contenteditable="true"
@input="(event)=>{formConf.title=event.target.innerText;this.saveProjectInfo()}">
@blur="(event)=>{
formConf.title=event.target.innerText;
this.saveProjectInfo()}">
{{formConf.title}}</h4>
</el-col>
</el-row>
<el-row type="flex" justify="center" align="middle">
<el-col :span="20" style="text-align: center">
<p class="form-name-text" contenteditable="true"
@input="(event)=>{formConf.description=event.target.innerText;this.saveProjectInfo()}">
@blur="(event)=>{
formConf.description=event.target.innerText;
this.saveProjectInfo()}">
{{formConf.description}}
</p>
</el-col>
@ -115,14 +119,20 @@
</div>
</el-form>
</el-row>
</el-scrollbar>
</el-row>
</div>
<el-row>
<el-col :span="3" :offset="10">
<el-button type="primary">发布</el-button>
</el-col>
</el-row>
<right-panel
v-if="activeData"
:active-data="activeData"
:form-conf="formConf"
:show-field="!!drawingList.length"
@tag-change="tagChange"
@data-change="updateProjectItemInfo"
/>
<form-drawer
@ -156,7 +166,6 @@ import render from '@/components/render/render'
import FormDrawer from './FormDrawer'
import JsonDrawer from './JsonDrawer'
import RightPanel from './RightPanel'
// import '@/assets/styles/index.scss'
import {
inputComponents, selectComponents, formConf
@ -187,7 +196,7 @@ let oldActiveId
let tempActiveData
let drawingListInDB
let formConfInDB
let idGlobal = 100
let idGlobal
export default {
components: {
@ -208,14 +217,14 @@ export default {
labelWidth: 100,
drawingList: drawingDefalut,
drawingData: {},
activeId: drawingDefalut[0].formId,
activeId: drawingDefalut.length!=0?drawingDefalut[0].formId:0,
drawerVisible: false,
formData: {},
dialogVisible: false,
jsonDrawerVisible: false,
generateConf: null,
showFileName: false,
activeData: drawingDefalut[0],
activeData: drawingDefalut?drawingDefalut[0]:null,
saveDrawingListDebounce: debounce(340, saveDrawingList),
saveIdGlobalDebounce: debounce(340, saveIdGlobal),
projectKey: '',
@ -259,7 +268,9 @@ export default {
},
idGlobal: {
handler(val) {
if (val) {
this.saveIdGlobalDebounce(val, this.projectKey)
}
},
immediate: true
}
@ -274,17 +285,23 @@ export default {
} else {
this.drawingList = drawingDefalut
}
if(this.drawingList.length){
this.activeFormItem(this.drawingList[0])
//
formConfInDB = getFormConf(projectKey)
if (formConfInDB) {
this.formConf = formConfInDB
}
//
// formConfInDB = getFormConf(projectKey)
// if (formConfInDB) {
// this.formConf = formConfInDB
// }
//
this.$api.get(`/project/query/${projectKey}`).then(res => {
this.formConf.title = res.data.name
this.formConf.description = res.data.describe
})
//Id
if (getIdGlobal(projectKey)) {
idGlobal = getIdGlobal(projectKey)
this.idGlobal = getIdGlobal(projectKey)
}
loadBeautifier(btf => {
beautifier = btf
})
@ -315,6 +332,24 @@ export default {
})
}),
updateProjectItemInfo(val) {
let data= formItemConvertData(val,this.projectKey)
this.$api.post('/project/item/update',data).then((res) => {
})
},
deleteProjectItemInfo(val) {
console.log(val)
let data= formItemConvertData(val,this.projectKey)
this.$api.post('/project/item/delete', data ).then((res) => {
})
},
saveProjectItemInfo(val){
this.$api.post('/project/item/create', val).then(res => {
})
},
activeFormItem(currentItem) {
this.activeData = currentItem
this.activeId = currentItem.__config__.formId
@ -324,7 +359,6 @@ export default {
console.log(value)
},
onEnd(obj) {
console.log(11)
if (obj.from !== obj.to) {
this.activeData = tempActiveData
this.activeId = this.idGlobal
@ -342,7 +376,9 @@ export default {
this.createIdAndKey(clone)
clone.placeholder !== undefined && (clone.placeholder += config.label)
tempActiveData = clone
formItemConvertData(clone)
let data = formItemConvertData(clone, this.projectKey)
console.log(data)
this.saveProjectItemInfo(data)
return tempActiveData
},
createIdAndKey(item) {
@ -399,8 +435,10 @@ export default {
clone = this.createIdAndKey(clone)
list.push(clone)
this.activeFormItem(clone)
this.saveProjectItemInfo(clone)
},
drawingItemDelete(index, list) {
let item= list[index]
list.splice(index, 1)
this.$nextTick(() => {
const len = this.drawingList.length
@ -408,6 +446,7 @@ export default {
this.activeFormItem(this.drawingList[len - 1])
}
})
this.deleteProjectItemInfo(item)
},
generateCode() {
const {type} = this.generateConf
@ -437,7 +476,6 @@ export default {
this.operationType = 'copy'
},
tagChange(newTag) {
console.log('tagChange')
newTag = this.cloneComponent(newTag)
const config = newTag.__config__
newTag.__vModel__ = this.activeData.__vModel__

2
src/views/home/index.vue

@ -45,7 +45,9 @@
</el-carousel>
</el-col>
</el-row>
<el-scrollbar style="height: 100%;">
<router-view />
</el-scrollbar>
</el-main>
</el-container>
</template>

2
src/views/project/create.vue

@ -25,7 +25,7 @@
<el-col :span="6" />
</el-row>
<el-row>
<el-col :offset="6" :span="8">
<el-col :offset="6" :span="10">
<el-menu default-active="1" class="el-menu-demo" mode="horizontal">
<el-menu-item index="1">全部</el-menu-item>
<el-menu-item index="2">问卷调查</el-menu-item>

Loading…
Cancel
Save