Commit 12d6c8ae authored by “yiyousong”'s avatar “yiyousong”

fix:修改搜索页面间距和快速查看页面间距

parent a2e43d12
<template>
<div class="right-board">
<el-tabs v-model="currentTab" class="center-tabs">
<el-tab-pane label="属性配置" name="field" />
</el-tabs>
<div class="field-box">
<el-scrollbar class="right-scrollbar">
<el-form size="small" label-width="100px" >
<div v-for="(item,index) in cmps" :key="index">
<component v-if="item.name === activeItem.compType" :getFormId="getFormId" :props="activeItem" :is="item.content"></component>
</div>
</el-form>
</el-scrollbar>
</div>
</div>
</template>
<script>
import reg from "./custom/register";
export default {
name:'configPanel',
data() {
return {
currentTab: 'field',
cmps:reg,
formIdArray:[]
}
},
props:{
activeItem: {
type: Object,
default:function(){
return {}
}
},
itemList: {
type: Array,
default:function(){
return []
}
}
},
created() {
this.cmps.forEach(c => {
c.content = require(`./custom/configs/${c.name}`).default;
});
},
methods:{
getFormId(itemId){
this.formIdArray = [];
Array.from(this.itemList,(item)=>{
if(item.compType === 'row'){
Array.from(item.columns,(column)=>{
Array.from(column.list,(col)=>{
if(col._id !== itemId){
this.formIdArray.push(col.id);
}
})
})
}else{
if(item._id !== itemId){
this.formIdArray.push(item.id);
}
}
})
return this.formIdArray;
}
}
}
</script>
<style scoped>
.field-box >>> .el-scrollbar__wrap{
overflow-x: hidden;
}
</style>
\ No newline at end of file
<template>
<div v-show="props.compType === 'Switch'">
<el-form-item label="ID">
<el-tooltip
class="item"
effect="dark"
content="请注意,ID的修改可能会导致该组件相关事件失效!"
placement="left"
>
<el-input
class="input"
v-model="props.id"
@change="handlerChangeId"
></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="标题">
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<!-- <el-form-item label="表单栅格">
<el-slider class="input" v-model="props.span" :max="24" :min="1" :marks="{12:''}"></el-slider>
</el-form-item> -->
<el-form-item label="栅格间隔">
<el-input-number v-model="props.gutter" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="标签宽度">
<el-input-number
v-model="props.labelWidth"
:min="1"
:max="200"
></el-input-number>
</el-form-item>
<el-form-item label="显示标签">
<el-switch
v-model="props.showLabel"
@change="handlerChangeLabel"
></el-switch>
</el-form-item>
<el-form-item label="必填">
<el-switch v-model="props.required"></el-switch>
</el-form-item>
<el-form-item label="开启时颜色">
<el-color-picker v-model="props['active-color']"></el-color-picker>
</el-form-item>
<el-form-item label="关闭时颜色">
<el-color-picker v-model="props['inactive-color']"></el-color-picker>
</el-form-item>
<el-form-item label="开启时值">
<el-input class="input" v-model="props['active-value']"></el-input>
</el-form-item>
<el-form-item label="关闭时值">
<el-input class="input" v-model="props['inactive-value']"></el-input>
</el-form-item>
<el-form-item label="默认值">
<el-switch v-model="props.value"></el-switch>
</el-form-item>
</div>
</template>
<script>
import { changeId } from "../mixin";
export default {
name: "inputConfig",
props: ["props", "getFormId"],
components: {},
mixins: [changeId],
data() {
return {};
},
methods: {
handlerChangeLabel(val) {
this.props.labelWidth = val ? "80" : "1";
},
handlerChangeDisStatus(val) {
this.props.readOnly = !val;
},
handlerChangeReadStatus(val) {
this.props.disabled = !val;
},
},
mounted() {},
};
</script>
<style scoped>
.input {
width: 75%;
}
</style>
\ No newline at end of file
<template>
<div v-show="props.compType === 'alert'">
<!-- <el-form-item label="字段名">
<el-input class="input" v-model="props"></el-input>
</el-form-item> -->
<el-form-item label="ID">
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" ></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="标题">
<el-input class="input" v-model="props.title"></el-input>
</el-form-item>
<el-form-item label="类型" >
<el-select v-model="props.type" placeholder="请选择">
<el-option label="success" value="success"/>
<el-option label="warning" value="warning"/>
<el-option label="error" value="error"/>
<el-option label="info" value="info"/>
</el-select>
</el-form-item>
<el-form-item label="辅助文字">
<el-input class="input" v-model="props.description"></el-input>
</el-form-item>
<el-form-item label="关闭">
<el-switch v-model="props.closable"></el-switch>
</el-form-item>
<el-form-item label="居中">
<el-switch v-model="props.center"></el-switch>
</el-form-item>
<el-form-item label="关闭按钮自定义文本">
<el-input class="input" v-model="props['close-text']"/>
</el-form-item>
<el-form-item label="显示图标">
<el-switch v-model="props['show-icon']"></el-switch>
</el-form-item>
<el-form-item label="主题">
<el-radio-group v-model="props.effect">
<el-radio-button label="light">light</el-radio-button>
<el-radio-button label="dark">dark</el-radio-button>
</el-radio-group>
</el-form-item>
</div>
</template>
<script>
/**
* input的配置项
*/
export default {
name:"buttonConfig",
props:{
props:{}
},
components:{
},
data(){
return {
}
},
methods:{
handlerShowLabel(val){
if(val){
this.props.labelWidth = 80;
}else{
this.props.labelWidth = 0;
}
}
},
mounted(){
}
}
</script>
<template>
<div v-show="props.compType === 'barCode'">
<!-- <el-form-item label="字段名">
<el-input class="input" v-model="props"></el-input>
</el-form-item> -->
<el-form-item label="ID">
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" ></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="显示标签">
<el-switch v-model="props.showLabel" @change="handlerShowLabel"></el-switch>
</el-form-item>
<el-form-item label="标签文字" v-show="props.showLabel">
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<el-form-item label="标签长度" v-show="props.showLabel">
<el-input-number v-model="props.labelWidth" :min="1" :max="200"></el-input-number>
</el-form-item>
<el-form-item label="占用列数" v-show="props.span">
<el-input-number v-model="props.span" :min="1" :max="24"></el-input-number>
</el-form-item>
<el-form-item label="条码值">
<el-input v-model="props.value"></el-input>
</el-form-item>
<el-form-item label="条码颜色" v-show="props.lineColor">
<el-color-picker v-model="props.lineColor" @change="handlerChangeBarCode"/>
</el-form-item>
<el-form-item label="背景颜色" v-show="props.background">
<el-color-picker v-model="props.background" @change="handlerChangeBackground"/>
</el-form-item>
<!--暂不启用-->
<!-- <el-form-item label="条码宽度">
<el-input-number v-model="props.width" :min="1" :max="10" :step="1"></el-input-number>
</el-form-item> -->
<el-form-item label="条码高度">
<el-input-number v-model="props.height" :min="10" :max="100" :step="1"></el-input-number>
</el-form-item>
<el-form-item label="显示值">
<el-switch v-model="props.displayValue"></el-switch>
</el-form-item>
</div>
</template>
<script>
/**
* input的配置项
*/
export default {
name:"buttonConfig",
props:{
props:{}
},
components:{
},
data(){
return {
}
},
methods:{
handlerShowLabel(val){
if(val){
this.props.labelWidth = 80;
}else{
this.props.labelWidth = 0;
}
},
handlerChangeBarCode(val){
if(val == null){
this.props.lineColor = '#000';
}
},
handlerChangeBackground(val){
if(val == null){
this.props.background = '#fff';
}
}
},
mounted(){
}
}
</script>
<template>
<div v-show="props.compType === 'button'">
<el-form-item label="ID">
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" ></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="按钮文字">
<el-input class="input" v-model="props.text"></el-input>
</el-form-item>
<el-form-item label="显示标签">
<el-switch v-model="props.showLabel" @change="handlerShowLabel"></el-switch>
</el-form-item>
<el-form-item label="标签文字" v-show="props.showLabel">
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<el-form-item label="标签长度" v-show="props.showLabel">
<el-input-number v-model="props.labelWidth" :min="1" :max="200"></el-input-number>
</el-form-item>
<el-form-item label="占用列数" v-show="props.span">
<el-input-number v-model="props.span" :min="1" :max="24"></el-input-number>
</el-form-item>
<el-form-item label="按钮类型" >
<el-select v-model="props.type" placeholder="请选择">
<el-option label="primary" value="primary"/>
<el-option label="success" value="success"/>
<el-option label="warning" value="warning"/>
<el-option label="danger" value="danger"/>
<el-option label="info" value="info"/>
<el-option label="text" value="text"/>
</el-select>
</el-form-item>
<el-form-item label="按钮大小">
<el-radio-group v-model="props.size">
<el-radio-button label="medium"></el-radio-button>
<el-radio-button label="small"></el-radio-button>
<el-radio-button label="mini"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="禁用">
<el-switch v-model="props.disabled"></el-switch>
</el-form-item>
<el-form-item label="简单样式">
<el-switch v-model="props.plain"></el-switch>
</el-form-item>
<el-form-item label="圆角">
<el-switch v-model="props.round"></el-switch>
</el-form-item>
<el-form-item label="圆形">
<el-switch v-model="props.circle"></el-switch>
</el-form-item>
<el-form-item label="图标">
<el-input placeholder="请选择图标" readonly v-model="props.icon">
<template slot="append" >
<i class="el-icon-picture" style="cursor: pointer;" @click="handlerSelectIcon"/>
</template>
</el-input>
</el-form-item>
<icon-dialog v-model="props.icon" :visible.sync="iconDialogVisible"/>
</div>
</template>
<script>
/**
* input的配置项
*/
export default {
name:"buttonConfig",
props:{
props:{}
},
data(){
return {
iconDialogVisible:false
}
},
methods:{
handlerShowLabel(val){
if(val){
this.props.labelWidth = 80;
}else{
this.props.labelWidth = 0;
}
},
handlerSelectIcon(){
this.iconDialogVisible = true;
}
},
mounted(){
}
}
</script>
<template>
<div v-show="props.compType === 'cascader'">
<!-- <el-form-item label="字段名">
<el-input class="input" v-model="props"></el-input>
</el-form-item> -->
<el-form-item label="ID">
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" @change="handlerChangeId" ></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="标题">
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<el-form-item label="栅格">
<el-input-number v-model="props.span" :min="1" :max="24"/>
</el-form-item>
<el-form-item label="宽度">
<el-input-number v-model="props.width" :min="0" :max="100"/>%
</el-form-item>
<el-form-item label="提示符">
<el-input class="input" v-model="props.placeholder" placeholder="请输入提示符"/>
</el-form-item>
<!-- <el-form-item label="表单栅格">
<el-slider class="input" v-model="props.span" :max="24" :min="1" :marks="{12:''}"></el-slider>
</el-form-item> -->
<el-form-item label="栅格间隔">
<el-input-number v-model="props.gutter" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="标签宽度">
<el-input-number v-model="props.labelWidth" :min="0" :max="200"></el-input-number>
</el-form-item>
<el-form-item label="显示标签">
<el-switch v-model="props.showLabel" @change="handlerChangeLabel"></el-switch>
</el-form-item>
<el-form-item label="大小">
<el-radio-group v-model="props.size">
<el-radio-button label="medium">正常</el-radio-button>
<el-radio-button label="small">略小</el-radio-button>
<el-radio-button label="mini">迷你</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="清除">
<el-switch v-model="props.clearable"></el-switch>
</el-form-item>
<el-form-item label="禁用">
<el-switch v-model="props.disabled" ></el-switch>
</el-form-item>
<el-form-item label="完整路径">
<el-switch v-model="props.props['show-all-levels']" ></el-switch>
</el-form-item>
<el-form-item label="分隔符">
<el-input v-model="props.props.separator" ></el-input>
</el-form-item>
<el-form-item label="搜索">
<el-switch v-model="props.props.filterable" ></el-switch>
</el-form-item>
<el-form-item label="展开方式">
<el-radio-group v-model="props.props.props.expandTrigger">
<el-radio-button label="click">点击</el-radio-button>
<el-radio-button label="hover">悬停</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="多选">
<el-switch v-model="props.props.props.multiple"></el-switch>
</el-form-item>
<el-form-item label="任一级可选">
<el-switch v-model="props.props.props.checkStrictly"></el-switch>
</el-form-item>
<el-form-item label="数据类型">
<el-radio-group v-model="props.dataType" @change="handlerChangeDataType">
<el-radio-button label="static">静态数据</el-radio-button>
<el-radio-button label="dynamic">动态数据</el-radio-button>
</el-radio-group>
</el-form-item>
<div v-show="props.dataType ==='dynamic'">
<el-form-item label="地址">
<el-input v-model="props.action"></el-input>
</el-form-item>
<el-form-item label="显示标识">
<el-input v-model="props.props.props.label"></el-input>
</el-form-item>
<el-form-item label="值标识">
<el-input v-model="props.props.props.value"></el-input>
</el-form-item>
<el-form-item label="下级标识">
<el-input v-model="props.props.props.children"></el-input>
</el-form-item>
</div>
<div v-show="props.dataType ==='static'">
<el-form-item label="静态数据">
<el-button icon="el-icon-edit-outline" circle @click="handlerStaticData"></el-button>
</el-form-item>
<el-form-item label="省市区">
<el-checkbox v-model="props['china-area-data']" @change="handlerSetAreaData"/>
</el-form-item>
</div>
<!-- <el-form-item label="URL">
<el-input v-model="props.action"></el-input>
</el-form-item> -->
<el-dialog :visible.sync="staticDataVisible" width="70%"
:close-on-press-escape="false"
:close-on-click-modal="false"
:show-close="false"
:center="true"
top="20px"
>
<codemirror v-model="staticOptions" :options="codeMirror"/>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="handlerSave">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import {changeId} from '../mixin'
//引入 省市区 数据
import {areaData} from '../../utils/chinaAreaData';
import {codemirror} from 'vue-codemirror';
// 核心样式
import 'codemirror/lib/codemirror.css';
// 引入主题后还需要在 options 中指定主题才会生效
import 'codemirror/theme/dracula.css';
import 'codemirror/mode/javascript/javascript'
const options = {
tabSize: 2, // 缩进格式
theme: 'dracula', // 主题,对应主题库 JS 需要提前引入
lineNumbers: true, // 显示行号
line: true,
styleActiveLine: true, // 高亮选中行
hintOptions: {
completeSingle: true // 当匹配只有一项的时候是否自动补全
}
}
/**
* input的配置项
*/
export default {
name:"cascaderConfig",
props:['props'],
components:{
codemirror
},
mixins:[changeId],
data(){
return {
staticDataVisible:false,
codeMirror:options,
staticOptions:'',
tempOptions:[]
}
},
methods:{
handlerChangeLabel(val){
this.props.labelWidth = val?'80':'1'
},
handlerStaticData(){
this.staticOptions = JSON.stringify(this.props.options,null,4);
this.staticDataVisible = true;
},
handlerSave(){
this.props.options = JSON.parse(this.staticOptions);
this.staticDataVisible = false;
},
handlerChangeDataType(value){
if(value === 'static'){
this.props.options = [];
this.props.options = this.tempOptions;
}else{
this.tempOptions = this.props.options;
this.props.options = [];
}
},
handlerSetAreaData(val){
if(val){
const areaoptions = areaData();
this.tempOptions = this.props.options;
this.props.options = areaoptions;
}else{
this.props.options = this.tempOptions;
}
}
},
mounted(){
},
watch:{
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div v-show="props.compType === 'checkbox'">
<!-- <el-form-item label="字段名">
<el-input class="input" v-model="props"></el-input>
</el-form-item> -->
<el-form-item label="ID">
<el-tooltip
class="item"
effect="dark"
content="请注意,ID的修改可能会导致该组件相关事件失效!"
placement="left"
>
<el-input
class="input"
v-model="props.id"
@change="handlerChangeId"
></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="标题">
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<el-form-item label="提示符">
<el-input
class="input"
v-model="props.placeholder"
placeholder="请输入提示符"
/>
</el-form-item>
<!-- <el-form-item label="表单栅格">
<el-slider class="input" v-model="props.span" :max="24" :min="1" :marks="{12:''}"></el-slider>
</el-form-item> -->
<el-form-item label="栅格间隔">
<el-input-number v-model="props.gutter" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="标签宽度">
<el-input-number
v-model="props.labelWidth"
:min="1"
:max="200"
></el-input-number>
</el-form-item>
<el-form-item label="显示标签">
<el-switch
v-model="props.showLabel"
@change="handlerChangeLabel"
></el-switch>
</el-form-item>
<el-form-item label="必填">
<el-switch v-model="props.required"></el-switch>
</el-form-item>
<el-form-item label="垂直">
<el-switch v-model="props.vertical"></el-switch>
</el-form-item>
<el-form-item label="最小数量">
<el-input-number v-model="props.min" :min="1"></el-input-number>
</el-form-item>
<el-form-item label="最大数量">
<el-input-number v-model="props.max" :min="1"></el-input-number>
</el-form-item>
<el-form-item label="选项样式">
<el-radio-group v-model="props.optionType">
<el-radio-button label="default">默认</el-radio-button>
<el-radio-button label="button">按钮</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="显示边框">
<el-switch v-model="props.border"></el-switch>
</el-form-item>
<el-form-item
label="选项尺寸"
v-show="props.border || props.optionType === 'button'"
>
<el-radio-group v-model="props.size">
<el-radio-button label="medium">正常</el-radio-button>
<el-radio-button label="small">略小</el-radio-button>
<el-radio-button label="mini">迷你</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="禁用">
<el-switch
v-model="props.disabled"
@change="handlerChangeDisStatus('disabled')"
></el-switch>
</el-form-item>
<el-form-item label="默认值">
<el-input
class="input"
:value="setDefaultValue(props.value)"
placeholder="请输入默认值"
@input="onDefaultValueInput"
/>
</el-form-item>
<el-form-item label="数据类型">
<el-radio-group v-model="props.dataType" @change="handlerChangeDataType">
<el-radio-button label="static">静态数据</el-radio-button>
<el-radio-button label="dynamic">动态数据</el-radio-button>
</el-radio-group>
</el-form-item>
<div v-show="props.dataType === 'static'">
<el-divider>选项</el-divider>
<draggable :list="props.options" handle=".option-drag">
<div
v-for="(item, index) in props.options"
:key="index"
class="select-item"
>
<div class="select-line-icon option-drag">
<i class="el-icon-s-operation" />
</div>
<el-input v-model="item.label" placeholder="选项名" size="small" />
<el-input
placeholder="选项值"
size="small"
:value="item.value"
@input="setOptionValue(item, $event)"
/>
<div
class="close-btn select-line-icon"
@click="props.options.splice(index, 1)"
>
<i class="el-icon-remove-outline" />
</div>
</div>
</draggable>
<div style="margin-left: 20px">
<el-button
style="padding-bottom: 0"
icon="el-icon-circle-plus-outline"
type="text"
@click="addSelectItem"
>
添加选项
</el-button>
</div>
</div>
<div v-show="props.dataType === 'dynamic'">
<el-form-item label="地址">
<el-input v-model="props.action"></el-input>
</el-form-item>
</div>
</div>
</template>
<script>
import { changeId } from "../mixin";
import draggable from "vuedraggable";
import { isNumberStr } from "../../utils/index";
/**
* input的配置项
*/
let vm = {
name: "checkboxConfig",
props: ["props", "getFormId"],
components: {
draggable,
},
mixins: [changeId],
data() {
return {};
},
methods: {
handlerChangeLabel(val) {
this.props.labelWidth = val ? "80" : "1";
},
handlerChangeDisStatus(val) {
this.props.readOnly = !val;
},
handlerChangeReadStatus(val) {
this.props.disabled = !val;
},
setDefaultValue(val) {
if (Array.isArray(val)) {
return val.join(",");
}
if (["string", "number"].indexOf(val) > -1) {
return val;
}
if (typeof val === "boolean") {
return `${val}`;
}
return val;
},
onDefaultValueInput(str) {
if (Array.isArray(this.props.value)) {
// 数组
this.$set(
this.props,
"value",
str.split(",").map((val) => (isNumberStr(val) ? +val : val))
);
} else if (["true", "false"].indexOf(str) > -1) {
// 布尔
this.$set(this.props, "value", JSON.parse(str));
} else {
// 字符串和数字
this.$set(this.props, "value", isNumberStr(str) ? +str : str);
}
},
setOptionValue(item, val) {
item.value = isNumberStr(val) ? +val : val;
},
addSelectItem() {
this.props.options.push({
label: "",
value: "",
});
},
multipleChange(val) {
// this.$set(this.props, 'value', val ? [] : '')
return val;
},
handlerChangeDataType(value) {
if (value === "static") {
this.props.options = [];
this.props.options = this.tempOptions;
} else {
this.tempOptions = this.props.options;
this.props.options = [];
}
},
},
mounted() {},
watch: {},
};
export default vm;
</script>
<style lang="less" scoped>
.input {
width: 75%;
}
</style>
\ No newline at end of file
<template>
<div v-show="props.compType === 'colorPicker'">
<el-form-item label="ID">
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" @change="handlerChangeId" ></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="显示标签">
<el-switch v-model="props.showLabel" @change="handlerShowLabel"></el-switch>
</el-form-item>
<el-form-item label="标签文字" v-show="props.showLabel">
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<el-form-item label="标签长度" v-show="props.showLabel">
<el-input-number v-model="props.labelWidth" :min="1" :max="200"></el-input-number>
</el-form-item>
<el-form-item label="透明">
<el-switch v-model="props['show-alpha']"></el-switch>
</el-form-item>
<el-form-item label="默认颜色">
<el-color-picker v-model="props.value" />
</el-form-item>
<el-form-item label="大小">
<el-radio-group v-model="props.size">
<el-radio-button label="medium">常规</el-radio-button>
<el-radio-button label="small">略小</el-radio-button>
<el-radio-button label="mini">迷你</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="预定义颜色">
<div class="select-item" v-for="(item,index) in props.predefine" :key="item">
<span class="el-color-picker__color"><!--style="background-color: rgb(64, 158, 255);"-->
<span class="el-color-picker__color-inner" :style="{'background-color':item}">
</span>
</span>
<div class="close-btn select-line-icon">
<i class="el-icon-remove-outline" @click="handlerRemoveColor(index)"/>
</div>
</div>
<br/>
<el-color-picker v-model="color" @change="handlerAddPreColor"></el-color-picker>
</el-form-item>
</div>
</template>
<script>
import {changeId} from '../mixin'
export default {
name:"buttonConfig",
props:{
props:{}
},
mixins:[changeId],
data(){
return {
color:'#409EFF',
}
},
methods:{
handlerShowLabel(val){
if(val){
this.props.labelWidth = 80;
}else{
this.props.labelWidth = 0;
}
},
handlerAddPreColor(val){
console.log(val);
this.props.predefine.push(val);
console.log(this.props.predefine);
},
handlerRemoveColor(index){
this.props.predefine.splice(index,1);
}
},
mounted(){
}
}
</script>
<style scoped>
.el-color-picker__color{
position: relative;
display: block;
box-sizing: border-box;
border: 1px solid #999;
border-radius: 2px;
width:100px;
height:30px;
float:left;
margin-right:2px;
}
</style>
<template>
<div v-show="props.compType === 'date'">
<el-form-item label="ID">
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" @change="handlerChangeId"></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="标题">
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<el-form-item label="栅格间隔">
<el-input-number v-model="props.gutter" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="标签宽度">
<el-input-number v-model="props.labelWidth" :min="1" :max="200"></el-input-number>
</el-form-item>
<el-form-item label="显示标签">
<el-switch v-model="props.showLabel"></el-switch>
</el-form-item>
<el-form-item label="提示符">
<el-input class="input" v-model="props.placeholder"></el-input>
</el-form-item>
<el-form-item label="必填">
<el-switch v-model="props.required"></el-switch>
</el-form-item>
<el-form-item label="时间类型">
<el-select class="input" v-model="props.type" @change="handlerFormatChange">
<el-option v-for="item in dateTypeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="时间格式">
<el-input class="input" :value="props.format" @change="handlerChangeValueFormat"/>
</el-form-item>
<el-form-item label="清空">
<el-switch v-model="props.clearable"></el-switch>
</el-form-item>
<el-form-item label="只读">
<el-switch v-model="props.readonly"></el-switch>
</el-form-item>
<el-form-item label="禁用">
<el-switch v-model="props.disabled"></el-switch>
</el-form-item>
<el-form-item label="分隔符" v-show="props.type === 'monthrange'||props.type === 'daterange'||props.type === 'datetimerange'">
<el-input v-model="props['range-separator']"></el-input>
</el-form-item>
<el-form-item label="默认值">
<el-date-picker class="input" v-model="props.value" value-format="yyyy-MM-dd" type="date" placeholder="选择日期"/>
</el-form-item>
</div>
</template>
<script>
import {changeId} from '../mixin'
const dateType =[
{
label: '日(date)',
value: 'date'
},
{
label: '周(week)',
value: 'week'
},
{
label: '月(month)',
value: 'month'
},
{
label: '年(year)',
value: 'year'
},
{
label: '日期时间(datetime)',
value: 'datetime'
},
{
label: '月份范围',
value: 'monthrange'
},
{
label: '日期范围',
value: 'daterange'
},
{
label: '日期时间范围',
value: 'datetimerange'
}
];
const dateTimeFormat = {
date: 'yyyy-MM-dd',
week: 'yyyy 第 WW 周',
month: 'yyyy-MM',
year: 'yyyy',
datetime: 'yyyy-MM-dd HH:mm:ss',
daterange: 'yyyy-MM-dd',
monthrange: 'yyyy-MM',
datetimerange: 'yyyy-MM-dd HH:mm:ss'
}
export default {
name:"inputConfig",
props:['props','getFormId'],
components: {
},
mixins:[changeId],
data(){
return {
dateTypeOptions:dateType
}
},
methods:{
handlerFormatChange(val){
this.props.format = dateTimeFormat[val];
this.props['value-format'] = dateTimeFormat[val];
},
handlerChangeValueFormat(val){
this.props['value-format'] = val;
}
},
mounted(){
}
}
</script>
<style scoped>
.input{
width:75%
}
</style>
<template>
<div v-show="props.compType === 'dialogList'" class="dialogList">
<el-collapse v-model="activePanel" accordion>
<el-collapse-item title="基础设置" name="1">
<el-form-item label="ID" >
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" ></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="标题" >
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<el-form-item label="栅格" >
<el-input-number v-model="props.span" :min="1" :max="24"/>
</el-form-item>
<el-form-item label="标签宽度">
<el-input-number v-model="props.labelWidth" :min="1" :max="200"></el-input-number>
</el-form-item>
<el-form-item label="显示标签">
<el-switch v-model="props.showLabel"></el-switch>
</el-form-item>
<el-form-item label="必填">
<el-switch v-model="props.required"></el-switch>
</el-form-item>
<el-form-item label="禁用" >
<el-switch v-model="props.disabled"></el-switch>
</el-form-item>
<el-form-item label="默认值" >
<el-input class="input" v-model="props.value"></el-input>
</el-form-item>
<el-form-item label="请求地址">
<el-input v-model="props.action"></el-input>
</el-form-item>
<el-form-item label="标题">
<el-input v-model="props.title"></el-input>
</el-form-item>
<el-form-item label="多选">
<el-switch v-model="props.multi"></el-switch>
</el-form-item>
<el-form-item label="显示序号">
<el-switch v-model="props.showIndex"></el-switch>
</el-form-item>
<el-form-item label="表格高度">
<el-input-number v-model="props.height" :step="10" :max="1500" :min="100"></el-input-number>
</el-form-item>
<el-form-item label="字段值">
<el-input v-model="props.dval"></el-input>
</el-form-item>
<el-form-item label="字段名称">
<el-input v-model="props.dlabel"></el-input>
</el-form-item>
</el-collapse-item>
<el-collapse-item title="字段配置" name="2">
<el-table
:data="colOptions"
@row-dblclick="handlerDeleteRow"
>
<el-table-column property="label" label="字段" align="center" />
<el-table-column property="property" label="属性" align="center" />
<el-table-column property="width" label="宽度" align="center" width="70" />
<el-table-column label="显示">
</el-table-column>
</el-table>
<br/>
<el-alert title="字段和属性不能为空,请检查" v-show="alertShow" type="error" :closable="false"/>
<el-alert title="属性已存在请检查" v-show="propertyExistShow" type="error" :closable="false"/>
<br>
<el-form-item label="字段" label-width="60px">
<el-input v-model="dLabel" />
</el-form-item>
<el-form-item label="属性" label-width="60px">
<el-input v-model="dProperty"/>
</el-form-item>
<el-form-item label="宽度" label-width="60px">
<el-input-number v-model="dWidth" />
</el-form-item>
<el-form-item label="显示" label-width="60px">
<el-switch v-model="dShow" />
</el-form-item>
<div style="margin-left: 20px;">
<el-button
style="padding-bottom: 0"
icon="el-icon-circle-plus-outline"
type="text"
@click="addColItem"
>
添加选项
</el-button>
</div>
</el-collapse-item>
<el-collapse-item title="数值联动" name="3">
</el-collapse-item>
</el-collapse>
</div>
</template>
<script>
/**
* text的配置项
*/
export default {
name:"textConfig",
props:{
props:{}
},
data(){
return {
activePanel:'1',
colOptions:[],
dLabel:'',
dProperty:'',
dWidth:150,
dShow:true,
alertShow:false,
propertyExistShow:false,
}
},
methods:{
addColItem(){
if(this.dLabel!==''&&this.dProperty!==''){
const existOptions = this.colOptions.find(item=>item.property === this.dProperty);
if( typeof existOptions === 'undefined'){
this.alertShow = false;
this.propertyExistShow = false;
const obj = {};
obj.index = this.colOptions.length;
obj.show = this.dShow;
obj.label = this.dLabel;
obj.property = this.dProperty;
obj.width = this.dWidth;
this.colOptions.push(obj);
this.resetFields();
}else{
this.propertyExistShow = true;
}
}else{
this.alertShow = true;
}
},
resetFields(){
this.dLabel = '';
this.dProperty = '';
this.dWidth = 150;
this.dShow = true;
},
handlerDeleteRow(row){
let index = this.colOptions.findIndex(item=>item.property==row.property);
this.colOptions.splice(index,1);
}
},
mounted() {
this.$nextTick(()=> {
this.colOptions = this.colOptions.concat(JSON.parse(this.props.colConf));
})
},
watch:{
'colOptions'(newVal){
this.props.colConf = JSON.stringify(newVal);
}
}
}
</script>
<style scoped>
.dialogList >>> .el-collapse-item__header{
background-color: #f4f6fc;
padding-left:10px;
}
.dialogList >>> .el-collapse-item__header{
height:35px;
}
</style>
\ No newline at end of file
<template>
<div v-show="props.compType === 'divider'">
<el-form-item label="ID">
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" ></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="文字">
<el-input class="input" v-model="props.text"></el-input>
</el-form-item>
<el-form-item label="文字大小">
<el-radio-group v-model="props['content-position']">
<el-radio-button label="left"></el-radio-button>
<el-radio-button label="center"></el-radio-button>
<el-radio-button label="right"></el-radio-button>
</el-radio-group>
</el-form-item>
</div>
</template>
<script>
/**
* input的配置项
*/
export default {
name:"dividerConfig",
props:{
props:{}
},
data(){
return {
}
},
methods:{
},
mounted(){
}
}
</script>
<template>
<div v-show="props.compType === 'dynamicTable'">
<el-form-item label="ID">
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" @change="handlerChangeId"></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="显示新增按钮" label-width="120px">
<el-switch v-model="props.buttonAdd"></el-switch>
</el-form-item>
<el-form-item label="显示删除按钮" label-width="120px">
<el-switch v-model="props.buttonDel"></el-switch>
</el-form-item>
<el-form-item label="显示行号" label-width="120px">
<el-switch v-model="props.showIndex"></el-switch>
</el-form-item>
<el-form-item label="多选" label-width="120px">
<el-switch v-model="props.multiCheck"></el-switch>
</el-form-item>
<el-form-item label="合计行" label-width="120px">
<el-switch v-model="props['show-summary']"></el-switch>
</el-form-item>
<el-form-item label="合计文本" label-width="120px">
<el-input v-model="props['sum-text']"></el-input>
</el-form-item>
<el-form-item label="单位文本" label-width="120px">
<el-input v-model="props['summary-text']"></el-input>
</el-form-item>
</div>
</template>
<script>
import {changeId} from '../mixin'
export default {
name:"dynamicTableConfig",
props:['props','getFormId'],
mixins:[changeId],
data(){
return {
}
},
methods:{
}
}
</script>
\ No newline at end of file
<template>
<div v-show="props.compType === 'editor'">
<el-form-item label="ID">
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" @change="handlerChangeId" ></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="显示标签">
<el-switch v-model="props.showLabel" @change="handlerShowLabel"></el-switch>
</el-form-item>
<el-form-item label="标签文字" v-show="props.showLabel">
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<el-form-item label="标签长度" v-show="props.showLabel">
<el-input-number v-model="props.labelWidth" :min="1" :max="200"></el-input-number>
</el-form-item>
<el-form-item label="必填">
<el-switch v-model="props.required"></el-switch>
</el-form-item>
<el-form-item label="验证最大字数">
<el-switch v-model="props.validateMaxText"></el-switch>
</el-form-item>
<el-form-item label="最大字数">
<el-input-number v-model="props.max" :min="100" ></el-input-number>
</el-form-item>
</div>
</template>
<script>
import {changeId} from '../mixin'
export default {
name:"editorConfig",
props:{
props:{}
},
mixins:[changeId],
methods:{
handlerShowLabel(val){
if(val){
this.props.labelWidth = 80;
}else{
this.props.labelWidth = 0;
}
}
}
}
</script>
<!--废弃-->
<template>
<div v-show="props.compType === 'html'">
<!-- <el-form-item label="字段名">
<el-input class="input" v-model="props"></el-input>
</el-form-item> -->
<el-form-item label="ID" labelWidth="40px">
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" ></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="文本" labelWidth="40px">
<!-- <el-input type="textarea" class="input" v-model="props.text" rows="12"></el-input> -->
<el-button icon="el-icon-edit-outline" circle @click="handlerEditMore"></el-button>
</el-form-item>
<el-dialog :visible.sync="editTextVisible" width="70%"
:close-on-press-escape="false"
:close-on-click-modal="false"
:show-close="false"
:center="true"
top="20px"
>
<fancy-editor v-model="props.text"/>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="handlerSave">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
/**
* text的配置项
*/
export default{
name:"htmlConfig",
props:{
props:{}
},
data(){
return {
editTextVisible:false
}
},
methods:{
handlerEditMore(){
this.editTextVisible = true;
},
handlerSave(){
this.editTextVisible = false;
}
}
}
</script>
<template>
<div v-show="props.compType === 'input'">
<!-- <el-form-item label="字段名">
<el-input class="input" v-model="props"></el-input>
</el-form-item> -->
<el-form-item label="ID">
<el-tooltip
class="item"
effect="dark"
content="请注意,ID的修改可能会导致该组件相关事件失效!"
placement="left"
>
<el-input
class="input"
v-model="props.id"
@change="handlerChangeId"
></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="标题">
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<el-form-item label="栅格">
<el-input-number v-model="props.span" :min="1" :max="24" />
</el-form-item>
<!-- <el-form-item label="宽度">-->
<!-- <el-input-number v-model="props.width" :min="1" :max="100"/>%-->
<!-- </el-form-item>-->
<el-form-item label="提示符">
<el-input
class="input"
v-model="props.placeholder"
placeholder="请输入提示符"
/>
</el-form-item>
<el-form-item label="栅格间隔">
<el-input-number v-model="props.gutter" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="标签宽度">
<el-input-number
v-model="props.labelWidth"
:min="1"
:max="200"
></el-input-number>
</el-form-item>
<el-form-item label="显示标签">
<el-switch
v-model="props.showLabel"
@change="handlerChangeLabel"
></el-switch>
</el-form-item>
<el-form-item label="必填">
<el-switch v-model="props.required"></el-switch>
</el-form-item>
<el-form-item label="清除">
<el-switch v-model="props.clearable"></el-switch>
</el-form-item>
<el-form-item label="禁用">
<el-switch v-model="props.disabled"></el-switch>
</el-form-item>
<el-form-item label="只读">
<el-switch v-model="props.readonly"></el-switch>
</el-form-item>
<el-form-item label="前置图标">
<el-input
placeholder="请选择图标"
readonly
v-model="props['prefix-icon']"
>
<template slot="append">
<i
class="el-icon-picture"
style="cursor: pointer"
@click="handlerPrefixSelectIcon"
/>
</template>
</el-input>
</el-form-item>
<el-form-item label="后置图标">
<el-input
placeholder="请选择图标"
readonly
v-model="props['suffix-icon']"
>
<template slot="append">
<i
class="el-icon-picture"
style="cursor: pointer"
@click="handlerSuffixSelectIcon"
/>
</template>
</el-input>
</el-form-item>
<el-form-item label="前缀">
<el-input v-model="props.prepend"> </el-input>
</el-form-item>
<el-form-item label="后缀">
<el-input v-model="props.append"> </el-input>
</el-form-item>
<el-form-item label="默认值">
<el-input class="input" v-model="props.value"></el-input>
</el-form-item>
<el-divider>校验</el-divider>
<el-form-item label="验证类型">
<el-select v-model="props.rulesType" @change="handlerChangeRulesType">
<el-option label="无" value="default" />
<el-option label="电话" value="phone" />
<el-option label="邮箱" value="email" />
<el-option label="纯数字" value="number" />
<el-option label="身份证" value="idcard" />
</el-select>
</el-form-item>
<div v-for="(item, index) in props.rules" :key="index" class="rule-item">
<el-input v-model="item.rule" placeholder="正则" size="small" />
<p />
<el-input v-model="item.msg" placeholder="自定义提示" size="small" />
<div
class="close-btn select-line-icon"
@click="props.rules.splice(index, 1)"
>
<i class="el-icon-remove-outline close-icon" />
</div>
</div>
<div style="margin-left: 20px">
<el-button
style="padding-bottom: 0"
icon="el-icon-circle-plus-outline"
type="text"
@click="addRuleItem"
>
添加选项
</el-button>
</div>
<icon-dialog
v-model="props['suffix-icon']"
:visible.sync="iconDialogVisible_suffix"
/>
<icon-dialog
v-model="props['prefix-icon']"
:visible.sync="iconDialogVisible_prefix"
/>
</div>
</template>
<script>
import { changeId } from "../mixin";
import iconDialog from "../../iconDialog";
const defaultRules = {
phone: {
rule: "^1[3-9]\\d{9}$",
msg: "您输入的电话号码不符合规则",
},
email: {
rule: "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$",
msg: "您输入的邮件地址不符合规则",
},
number: { rule: "^[0-9]*$", msg: "您输入的内容不符合纯数字规则" },
idcard: {
rule: "^[1-9]\\d{5}(18|19|([23]\\d))\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$",
msg: "您输入的身份证号码不符合规则",
},
};
/**
* input的配置项
*/
export default {
name: "inputConfig",
props: ["props", "getFormId"],
components: {
iconDialog,
},
mixins: [changeId],
data() {
return {
val: "",
iconDialogVisible_suffix: false,
iconDialogVisible_prefix: false,
};
},
methods: {
handlerChangeLabel(val) {
this.props.labelWidth = val ? "80" : "1";
},
handlerSuffixSelectIcon() {
this.iconDialogVisible_suffix = true;
},
handlerPrefixSelectIcon() {
this.iconDialogVisible_prefix = true;
},
addRuleItem() {
this.props.rules.push({
rule: "",
msg: "",
});
},
handlerChangeRulesType(val) {
const obj = defaultRules[val];
this.props.rules.push({
rule: obj.rule,
msg: obj.msg,
});
},
},
mounted() {},
watch: {},
};
</script>
<style scoped>
.input {
width: 75%;
}
.rule-item {
padding-top: 5px;
padding-bottom: 5px;
}
.close-btn {
text-align: center;
}
.close-icon:hover {
cursor: pointer;
}
.close-btn >>> .el-icon-remove-outline {
color: "red";
}
</style>
\ No newline at end of file
<template>
<div v-show="props.compType === 'inputNumber'">
<el-form-item label="ID">
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" @change="handlerChangeId"></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="标题">
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<!-- <el-form-item label="表单栅格">
<el-slider class="input" v-model="props.span" :max="24" :min="1" :marks="{12:''}"></el-slider>
</el-form-item> -->
<el-form-item label="栅格间隔">
<el-input-number v-model="props.gutter" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="标签宽度">
<el-input-number v-model="props.labelWidth" :min="1" :max="200"></el-input-number>
</el-form-item>
<el-form-item label="显示标签">
<el-switch v-model="props.showLabel" @change="handlerChangeLabel"></el-switch>
</el-form-item>
<el-form-item label="必填">
<el-switch v-model="props.required"></el-switch>
</el-form-item>
<el-form-item label="最小值">
<el-input-number v-model="props.min"></el-input-number>
</el-form-item>
<el-form-item label="最大值">
<el-input-number v-model="props.max"></el-input-number>
</el-form-item>
<el-form-item label="步长">
<el-input-number v-model="props.step"></el-input-number>
</el-form-item>
<el-form-item label="精度">
<el-input-number v-model="props.precision" :min="0" :max="10"></el-input-number>
</el-form-item>
<el-form-item label="按钮位置">
<el-radio-group v-model="props['controls-position']">
<el-radio-button label="default">默认</el-radio-button>
<el-radio-button label="right">右侧</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="禁用">
<el-switch v-model="props.disabled" @change="handlerChangeDisStatus('disabled')"></el-switch>
</el-form-item>
<el-form-item label="默认值">
<el-input class="input" v-model="props.value"></el-input>
</el-form-item>
</div>
</template>
<script>
import {changeId} from '../mixin'
export default {
name:"inputConfig",
props:['props','getFormId'],
components: {
},
mixins:[changeId],
data(){
return {
}
},
methods:{
handlerChangeLabel(val){
this.props.labelWidth = val?'80':'1'
},
handlerChangeDisStatus(val){
this.props.readOnly = val?false:true
},
handlerChangeReadStatus(val){
this.props.disabled = val?false:true
},
},
mounted(){
}
}
</script>
<style scoped>
.input{
width:75%
}
</style>
\ No newline at end of file
<template>
<div v-show="props.compType === 'link'">
<!-- <el-form-item label="字段名">
<el-input class="input" v-model="props"></el-input>
</el-form-item> -->
<el-form-item label="ID">
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" @change="handlerChangeId" ></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="链接文字">
<el-input class="input" v-model="props.text"></el-input>
</el-form-item>
<el-form-item label="类型" >
<el-select v-model="props.type" placeholder="请选择">
<el-option label="primary" value="primary"/>
<el-option label="success" value="success"/>
<el-option label="warning" value="warning"/>
<el-option label="danger" value="danger"/>
<el-option label="info" value="info"/>
</el-select>
</el-form-item>
<el-form-item label="url">
<el-input class="input" v-model="props.href"></el-input>
</el-form-item>
<el-form-item label="禁用">
<el-switch v-model="props.disabled"></el-switch>
</el-form-item>
<el-form-item label="新窗口">
<el-switch v-model="isNewWindow" @change="handlerChangeTargetValue"></el-switch>
</el-form-item>
</div>
</template>
<script>
import {changeId} from '../mixin'
export default {
name:"buttonConfig",
props:{
props:{}
},
components:{
},
mixins:[changeId],
data(){
return {
isNewWindow:true
}
},
methods:{
handlerShowLabel(val){
if(val){
this.props.labelWidth = 80;
}else{
this.props.labelWidth = 0;
}
},
handlerChangeTargetValue(val){
if(val){
this.props.target = '_blank';
}else{
this.props.target = '_self';
}
}
},
mounted(){
}
}
</script>
<template>
<div v-show="props.compType === 'radio'">
<!-- <el-form-item label="字段名">
<el-input class="input" v-model="props"></el-input>
</el-form-item> -->
<el-form-item label="ID">
<el-tooltip
class="item"
effect="dark"
content="请注意,ID的修改可能会导致该组件相关事件失效!"
placement="left"
>
<el-input
class="input"
v-model="props.id"
@change="handlerChangeId"
></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="标题">
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<el-form-item label="提示符">
<el-input
class="input"
v-model="props.placeholder"
placeholder="请输入提示符"
/>
</el-form-item>
<!-- <el-form-item label="表单栅格">
<el-slider class="input" v-model="props.span" :max="24" :min="1" :marks="{12:''}"></el-slider>
</el-form-item> -->
<el-form-item label="栅格间隔">
<el-input-number v-model="props.gutter" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="标签宽度">
<el-input-number
v-model="props.labelWidth"
:min="1"
:max="200"
></el-input-number>
</el-form-item>
<el-form-item label="显示标签">
<el-switch
v-model="props.showLabel"
@change="handlerChangeLabel"
></el-switch>
</el-form-item>
<el-form-item label="必填">
<el-switch v-model="props.required"></el-switch>
</el-form-item>
<el-form-item label="垂直">
<el-switch v-model="props.vertical"></el-switch>
</el-form-item>
<el-form-item label="选项样式">
<el-radio-group v-model="props.optionType">
<el-radio-button label="default">默认</el-radio-button>
<el-radio-button label="button">按钮</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="显示边框">
<el-switch v-model="props.border"></el-switch>
</el-form-item>
<el-form-item
label="大小"
v-show="props.border || props.optionType === 'button'"
>
<el-radio-group v-model="props.size">
<el-radio-button label="medium">正常</el-radio-button>
<el-radio-button label="small">略小</el-radio-button>
<el-radio-button label="mini">迷你</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="禁用">
<el-switch
v-model="props.disabled"
@change="handlerChangeDisStatus('disabled')"
></el-switch>
</el-form-item>
<el-form-item label="默认值">
<el-input
class="input"
:value="setDefaultValue(props.value)"
placeholder="请输入默认值"
@input="onDefaultValueInput"
/>
</el-form-item>
<el-form-item label="数据类型">
<el-radio-group v-model="props.dataType" @change="handlerChangeDataType">
<el-radio-button label="static">静态数据</el-radio-button>
<el-radio-button label="dynamic">动态数据</el-radio-button>
</el-radio-group>
</el-form-item>
<div v-show="props.dataType === 'static'">
<el-divider>选项</el-divider>
<draggable :list="props.options" handle=".option-drag">
<div
v-for="(item, index) in props.options"
:key="index"
class="select-item"
>
<div class="select-line-icon option-drag">
<i class="el-icon-s-operation" />
</div>
<el-input v-model="item.label" placeholder="选项名" size="small" />
<el-input
placeholder="选项值"
size="small"
:value="item.value"
@input="setOptionValue(item, $event)"
/>
<div
class="close-btn select-line-icon"
@click="props.options.splice(index, 1)"
>
<i class="el-icon-remove-outline" />
</div>
</div>
</draggable>
<div style="margin-left: 20px">
<el-button
style="padding-bottom: 0"
icon="el-icon-circle-plus-outline"
type="text"
@click="addSelectItem"
>
添加选项
</el-button>
</div>
</div>
<div v-show="props.dataType === 'dynamic'">
<el-form-item label="地址">
<el-input v-model="props.action"></el-input>
</el-form-item>
</div>
</div>
</template>
<script>
import { changeId } from "../mixin";
import draggable from "vuedraggable";
import { isNumberStr } from "../../utils/index";
/**
* input的配置项
*/
let vm = {
name: "inputConfig",
props: ["props", "getFormId"],
components: {
draggable,
},
mixins: [changeId],
data() {
return {
val: 123,
};
},
methods: {
handlerChangeLabel(val) {
this.props.labelWidth = val ? "80" : "1";
},
handlerChangeDisStatus(val) {
this.props.readOnly = !val;
},
handlerChangeReadStatus(val) {
this.props.disabled = !val;
},
setDefaultValue(val) {
if (Array.isArray(val)) {
return val.join(",");
}
if (["string", "number"].indexOf(val) > -1) {
return val;
}
if (typeof val === "boolean") {
return `${val}`;
}
return val;
},
onDefaultValueInput(str) {
if (Array.isArray(this.props.value)) {
// 数组
this.$set(
this.props,
"value",
str.split(",").map((val) => (isNumberStr(val) ? +val : val))
);
} else if (["true", "false"].indexOf(str) > -1) {
// 布尔
this.$set(this.props, "value", JSON.parse(str));
} else {
// 字符串和数字
this.$set(this.props, "value", isNumberStr(str) ? +str : str);
}
},
setOptionValue(item, val) {
item.value = isNumberStr(val) ? +val : val;
},
addSelectItem() {
this.props.options.push({
label: "",
value: "",
});
},
multipleChange(val) {
// this.$set(this.props, 'value', val ? [] : '')
return val;
},
handlerChangeDataType(value) {
if (value === "static") {
this.props.options = [];
this.props.options = this.tempOptions;
} else {
this.tempOptions = this.props.options;
this.props.options = [];
}
},
},
mounted() {},
watch: {},
};
export default vm;
</script>
<style lang="less" scoped>
.input {
width: 75%;
}
</style>
\ No newline at end of file
<template>
<div v-show="props.compType === 'rate'">
<!-- <el-form-item label="字段名">
<el-input class="input" v-model="props"></el-input>
</el-form-item> -->
<el-form-item label="ID">
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" @change="handlerChangeId"></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="标题">
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<!-- <el-form-item label="表单栅格">
<el-slider class="input" v-model="props.span" :max="24" :min="1" :marks="{12:''}"></el-slider>
</el-form-item> -->
<el-form-item label="栅格间隔">
<el-input-number v-model="props.gutter" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="标签宽度">
<el-input-number v-model="props.labelWidth" :min="1" :max="200"></el-input-number>
</el-form-item>
<el-form-item label="显示标签">
<el-switch v-model="props.showLabel"></el-switch>
</el-form-item>
<el-form-item label="必填">
<el-switch v-model="props.required"></el-switch>
</el-form-item>
<el-form-item label="允许半选">
<el-switch v-model="props['allow-half']"></el-switch>
</el-form-item>
<el-form-item label="显示分数">
<el-switch v-model="props['show-score']"></el-switch>
</el-form-item>
<el-form-item label="最大值">
<el-input-number v-model="props.max"></el-input-number>
</el-form-item>
<el-form-item label="禁用">
<el-switch v-model="props.disabled"></el-switch>
</el-form-item>
<el-form-item label="默认值">
<el-input class="input" v-model="props.value"></el-input>
</el-form-item>
</div>
</template>
<script>
import {changeId} from '../mixin'
export default {
name:"rate",
props:['props','getFormId'],
components: {
},
mixins:[changeId],
data(){
return {
}
},
methods:{
},
mounted(){
}
}
</script>
<style scoped>
.input{
width:75%
}
</style>
\ No newline at end of file
<!--后期支持flex布局-->
<template>
<div v-show="props.compType === 'row'">
<el-form-item label="栅格间隔">
<el-input-number size="small" v-model="props.gutter" :min="0" :max="100"/>
</el-form-item>
<el-divider>列配置项</el-divider>
<div v-for="(item, index) in props.columns" :key="index" class="select-item">
<div class="select-line-icon">
<i class="el-icon-s-operation" />
</div>
<el-input-number
size="normal"
v-model="item.span"
:min="1" :max="24"
/>
<div class="close-btn select-line-icon" @click="props.columns.splice(index,1)">
<i class="el-icon-remove-outline" />
</div>
</div>
<div style="margin-left: 30px;">
<el-button
style="padding-bottom: 0"
icon="el-icon-circle-plus-outline"
type="text"
@click="handlerAddCol"
>
添加选项
</el-button>
</div>
</div>
</template>
<script>
export default {
name:"rowConfig",
props:['props','getFormId'],
data(){
return {
}
},
methods:{
handlerAddCol(){
const colIndex = this.props.columns+1;
this.props.columns.push({
index:colIndex,
span:12,
list:[]
})
},
},
mounted(){
}
}
</script>
<template>
<div v-show="props.compType === 'select'">
<!-- <el-form-item label="字段名">
<el-input class="input" v-model="props"></el-input>
</el-form-item> -->
<el-form-item label="ID">
<el-tooltip
class="item"
effect="dark"
content="请注意,ID的修改可能会导致该组件相关事件失效!"
placement="left"
>
<el-input
class="input"
v-model="props.id"
@change="handlerChangeId"
></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="标题">
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<el-form-item label="提示符">
<el-input
class="input"
v-model="props.placeholder"
placeholder="请输入提示符"
/>
</el-form-item>
<!-- <el-form-item label="表单栅格">
<el-slider class="input" v-model="props.span" :max="24" :min="1" :marks="{12:''}"></el-slider>
</el-form-item> -->
<el-form-item label="栅格间隔">
<el-input-number v-model="props.gutter" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="标签宽度">
<el-input-number
v-model="props.labelWidth"
:min="1"
:max="200"
></el-input-number>
</el-form-item>
<el-form-item label="显示标签">
<el-switch
v-model="props.showLabel"
@change="handlerChangeLabel"
></el-switch>
</el-form-item>
<el-form-item label="必填">
<el-switch v-model="props.required"></el-switch>
</el-form-item>
<el-form-item label="清除">
<el-switch v-model="props.clearable"></el-switch>
</el-form-item>
<el-form-item label="禁用">
<el-switch v-model="props.disabled"></el-switch>
</el-form-item>
<el-form-item label="多选">
<el-switch v-model="props.multiple" @change="multipleChange"></el-switch>
</el-form-item>
<el-form-item label="折叠" v-show="props.multiple">
<el-switch v-model="props['collapse-tags']"></el-switch>
</el-form-item>
<el-form-item label="搜索">
<el-switch v-model="props.filterable"></el-switch>
</el-form-item>
<el-form-item label="默认值">
<el-input
class="input"
:value="setValue(props.value)"
placeholder="请输入默认值"
@input="onValueInput"
/>
</el-form-item>
<el-form-item label="数据类型">
<el-radio-group v-model="props.dataType" @change="handlerChangeDataType">
<el-radio-button label="static">静态数据</el-radio-button>
<el-radio-button label="dynamic">动态数据</el-radio-button>
</el-radio-group>
</el-form-item>
<div v-show="props.dataType === 'static'">
<el-divider>选项</el-divider>
<draggable :list="props.options" handle=".option-drag">
<div
v-for="(item, index) in props.options"
:key="index"
class="select-item"
>
<div class="select-line-icon option-drag">
<i class="el-icon-s-operation" />
</div>
<el-input v-model="item.label" placeholder="选项名" size="small" />
<el-input
placeholder="选项值"
size="small"
:value="item.value"
@input="setOptionValue(item, $event)"
/>
<div
class="close-btn select-line-icon"
@click="props.options.splice(index, 1)"
>
<i class="el-icon-remove-outline" />
</div>
</div>
</draggable>
<div style="margin-left: 20px">
<el-button
style="padding-bottom: 0"
icon="el-icon-circle-plus-outline"
type="text"
@click="addSelectItem"
>
添加选项
</el-button>
</div>
</div>
<div v-show="props.dataType === 'dynamic'">
<el-form-item label="地址">
<el-input v-model="props.action"></el-input>
</el-form-item>
</div>
</div>
</template>
<script>
import { changeId } from "../mixin";
import draggable from "vuedraggable";
import { isNumberStr } from "../../utils/index";
export default {
name: "inputConfig",
props: ["props", "getFormId"],
components: {
draggable,
},
mixins: [changeId],
data() {
return {
tempOptions: [],
};
},
methods: {
handlerChangeLabel(val) {
this.props.labelWidth = val ? "80" : "1";
},
setValue(val) {
if (Array.isArray(val)) {
return val.join(",");
}
if (["string", "number"].indexOf(val) > -1) {
return val;
}
if (typeof val === "boolean") {
return `${val}`;
}
return val;
},
onValueInput(str) {
if (Array.isArray(this.props.value)) {
// 数组
this.$set(
this.props,
"value",
str.split(",").map((val) => (isNumberStr(val) ? +val : val))
);
} else if (["true", "false"].indexOf(str) > -1) {
// 布尔
this.$set(this.props, "value", JSON.parse(str));
} else {
// 字符串和数字
this.$set(this.props, "value", isNumberStr(str) ? +str : str);
}
},
setOptionValue(item, val) {
item.value = isNumberStr(val) ? +val : val;
},
addSelectItem() {
this.props.options.push({
label: "",
value: "",
});
},
multipleChange(val) {
this.$set(this.props, "value", val ? [] : "");
},
handlerChangeDataType(value) {
if (value === "static") {
this.props.options = [];
this.props.options = this.tempOptions;
} else {
this.tempOptions = this.props.options;
this.props.options = [];
}
},
},
mounted() {},
};
</script>
<style lang="less" scoped>
.input {
width: 75%;
}
</style>
\ No newline at end of file
<template>
<div v-show="props.compType === 'slider'">
<!-- <el-form-item label="字段名">
<el-input class="input" v-model="props"></el-input>
</el-form-item> -->
<el-form-item label="ID">
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" @change="handlerChangeId"></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="标题">
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<!-- <el-form-item label="表单栅格">
<el-slider class="input" v-model="props.span" :max="24" :min="1" :marks="{12:''}"></el-slider>
</el-form-item> -->
<el-form-item label="栅格间隔">
<el-input-number v-model="props.gutter" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="标签宽度">
<el-input-number v-model="props.labelWidth" :min="1" :max="200"></el-input-number>
</el-form-item>
<el-form-item label="显示标签">
<el-switch v-model="props.showLabel"></el-switch>
</el-form-item>
<el-form-item label="必填">
<el-switch v-model="props.required"></el-switch>
</el-form-item>
<el-form-item label="最小值">
<el-input-number v-model="props.min" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="最大值">
<el-input-number v-model="props.max" placeholder="字符长度"/>
</el-form-item>
<el-form-item label="步长">
<el-input-number v-model="props.step"></el-input-number>
</el-form-item>
<el-form-item label="范围选择">
<el-switch v-model="props.range"></el-switch>
</el-form-item>
<el-form-item label="显示断点">
<el-switch v-model="props['show-stops']"></el-switch>
</el-form-item>
<el-form-item label="显示提示消息">
<el-switch v-model="props['show-tooltip']"></el-switch>
</el-form-item>
<el-form-item label="禁用">
<el-switch v-model="props.disabled"></el-switch>
</el-form-item>
<el-form-item label="默认值">
<el-input class="input" v-model="props.value"></el-input>
</el-form-item>
</div>
</template>
<script>
import {changeId} from '../mixin'
export default {
name:"inputConfig",
props:['props','getFormId'],
components: {
},
mixins:[changeId],
data(){
return {
}
},
methods:{
},
mounted(){
}
}
</script>
<style scoped>
.input{
width:75%
}
</style>
\ No newline at end of file
<template>
<div v-show="props.compType === 'table'">
<el-form-item label="ID" >
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" @change="handlerChangeId" ></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="单元格样式">
<el-input class="input" v-model="props.tdStyle"></el-input>
</el-form-item>
<el-form-item label="表格宽度">
<el-inputNumber class="input" :min="0" :max="500" v-model="props.width"></el-inputNumber>
</el-form-item>
<el-form-item label="行高">
<el-inputNumber class="input" :min="0" :max="1500" :step="5" v-model="props.height"></el-inputNumber>
</el-form-item>
</div>
</template>
<script>
import {changeId} from '../mixin'
/**
* input的配置项
*/
export default {
name:"inputConfig",
props:['props','getFormId'],
components:{
},
mixins:[changeId],
data(){
return {
}
},
methods:{
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div v-show="props.compType === 'tdItem'">
<el-form-item label="单元格背景">
<el-color-picker v-model="props.style.background" :predefine="predefineColors"/>
</el-form-item>
<el-form-item label="表格宽度(%)">
<el-inputNumber class="input" :min="0" :max="100" v-model="props.style.width"/>
</el-form-item>
</div>
</template>
<script>
/**
* input的配置项
*/
export default {
name:"tdItemConfig",
props:['props'],
data(){
return {
predefineColors: [
'#F6F6F6'
]
}
},
methods:{
}
}
</script>
\ No newline at end of file
<template>
<div v-show="props.compType === 'text'">
<!-- <el-form-item label="字段名">
<el-input class="input" v-model="props"></el-input>
</el-form-item> -->
<el-form-item label="ID" labelWidth="40px">
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" @change="handlerChangeId" ></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="文本" labelWidth="40px">
<el-input type="textarea" class="input" v-model="props.text" rows="12" ></el-input>
</el-form-item>
<el-form-item label="颜色" labelWidth="40px">
<el-color-picker v-model="props.color" />
</el-form-item>
<el-form-item label="布局" labelWidth="40px">
<el-radio-group v-model="props.align">
<el-radio-button label="left"></el-radio-button>
<el-radio-button label="center"></el-radio-button>
<el-radio-button label="right"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="大小" labelWidth="40px">
<el-input-number v-model="props.size" :min="10" :max="50" @change="handlerChangeSize"></el-input-number>
</el-form-item>
<el-form-item label="加粗" labelWidth="40px">
<el-input-number v-model="props.bold" :min="100" :max="800" :step="100" @change="handlerChangeBold"></el-input-number>
</el-form-item>
</div>
</template>
<script>
import {changeId} from '../mixin'
export default {
name:"textConfig",
props:['props'],
data(){
return{
}
},
mixins:[changeId],
methods:{
handlerChangeSize(val){
this.props.size = val+'';
},
handlerChangeBold(val){
this.props.bold = val+'';
}
}
}
</script>
<template>
<div v-show="props.compType === 'textarea'">
<!-- <el-form-item label="字段名">
<el-input class="input" v-model="props"></el-input>
</el-form-item> -->
<el-form-item label="ID">
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" @change="handlerChangeId"></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="标题">
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<el-form-item label="提示符">
<el-input class="input" v-model="props.placeholder" placeholder="请输入提示符"/>
</el-form-item>
<!-- <el-form-item label="表单栅格">
<el-slider class="input" v-model="props.span" :max="24" :min="1" :marks="{12:''}"></el-slider>
</el-form-item> -->
<el-form-item label="栅格间隔">
<el-input-number v-model="props.gutter" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="标签宽度">
<el-input-number v-model="props.labelWidth" :min="1" :max="200"></el-input-number>
</el-form-item>
<el-form-item label="显示标签">
<el-switch v-model="props.showLabel" @change="handlerChangeLabel"></el-switch>
</el-form-item>
<el-form-item label="必填">
<el-switch v-model="props.required"></el-switch>
</el-form-item>
<el-form-item label="输入框行数">
<el-input-number v-model="props.rows" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="长度限制">
<el-input-number v-model="props.maxlength" placeholder="字符长度"/>
</el-form-item>
<el-form-item label="输入统计">
<el-switch v-model="props['show-word-limit']"></el-switch>
</el-form-item>
<el-form-item label="禁用">
<el-switch v-model="props.disabled" @change="handlerChangeDisStatus"></el-switch>
</el-form-item>
<el-form-item label="只读">
<el-switch v-model="props.readonly" @change="handlerChangeReadStatus"></el-switch>
</el-form-item>
<el-form-item label="默认值">
<el-input class="input" v-model="props.value"></el-input>
</el-form-item>
</div>
</template>
<script>
import {changeId} from '../mixin'
export default {
name:"inputConfig",
props:['props','getFormId'],
components: {
},
mixins:[changeId],
data(){
return {
}
},
methods:{
handlerChangeLabel(val){
this.props.labelWidth = val?'80':'1'
},
handlerChangeDisStatus(val){
this.props.readOnly = !val
},
handlerChangeReadStatus(val){
this.props.disabled = !val
}
},
mounted(){
}
}
</script>
<style scoped>
.input{
width:75%
}
</style>
\ No newline at end of file
<template>
<div v-show="props.compType === 'time'">
<!-- <el-form-item label="字段名">
<el-input class="input" v-model="props"></el-input>
</el-form-item> -->
<el-form-item label="ID">
<el-tooltip class="item" effect="dark" content="请注意,ID的修改可能会导致该组件相关事件失效!" placement="left">
<el-input class="input" v-model="props.id" @change="handlerChangeId"></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="标题">
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<!-- <el-form-item label="表单栅格">
<el-slider class="input" v-model="props.span" :max="24" :min="1" :marks="{12:''}"></el-slider>
</el-form-item> -->
<el-form-item label="栅格间隔">
<el-input-number v-model="props.gutter" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="标签宽度">
<el-input-number v-model="props.labelWidth" :min="1" :max="200"></el-input-number>
</el-form-item>
<el-form-item label="显示标签">
<el-switch v-model="props.showLabel"></el-switch>
</el-form-item>
<el-form-item label="显示标签">
<el-input class="input" v-model="props.placeholder"></el-input>
</el-form-item>
<el-form-item label="必填">
<el-switch v-model="props.required"></el-switch>
</el-form-item>
<el-form-item label="清空">
<el-switch v-model="props.clearable"></el-switch>
</el-form-item>
<el-form-item label="只读">
<el-switch v-model="props.readonly"></el-switch>
</el-form-item>
<el-form-item label="禁用">
<el-switch v-model="props.disabled"></el-switch>
</el-form-item>
<el-form-item label="范围选择">
<el-switch v-model="props['is-range']"></el-switch>
</el-form-item>
<el-form-item label="分隔符" v-show="props['is-range']">
<el-input v-model="props['range-separator']"></el-input>
</el-form-item>
<el-form-item label="默认值">
<el-time-picker class="input" v-model="props.value" placeholder="选择默认时间"/>
</el-form-item>
</div>
</template>
<script>
import {changeId} from '../mixin'
export default {
name:"timeConfig",
components: {
},
mixins:[changeId],
props:['props','getFormId'],
data(){
return {
}
},
methods:{
},
mounted(){
}
}
</script>
<style scoped>
.input{
width:75%
}
</style>
\ No newline at end of file
<template>
<div v-show="props.compType === 'upload'">
<el-form-item label="ID">
<el-tooltip
class="item"
effect="dark"
content="请注意,ID的修改可能会导致该组件相关事件失效!"
placement="left"
>
<el-input
class="input"
v-model="props.id"
@change="handlerChangeId"
></el-input>
</el-tooltip>
</el-form-item>
<el-form-item label="标题">
<el-input class="input" v-model="props.label"></el-input>
</el-form-item>
<el-form-item label="栅格">
<el-input-number v-model="props.span" :min="1" :max="24" />
</el-form-item>
<el-form-item label="宽度%">
<el-input-number v-model="props.width" :min="1" :max="100" />
</el-form-item>
<el-form-item label="提示符">
<el-input
class="input"
v-model="props.placeholder"
placeholder="请输入提示符"
/>
</el-form-item>
<!-- <el-form-item label="表单栅格">
<el-slider class="input" v-model="props.span" :max="24" :min="1" :marks="{12:''}"></el-slider>
</el-form-item> -->
<el-form-item label="栅格间隔">
<el-input-number v-model="props.gutter" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="标签宽度">
<el-input-number
v-model="props.labelWidth"
:min="1"
:max="200"
></el-input-number>
</el-form-item>
<el-form-item label="显示标签">
<el-switch
v-model="props.showLabel"
@change="handlerChangeLabel"
></el-switch>
</el-form-item>
<el-form-item label="请求地址">
<el-input v-model="props.action"></el-input>
</el-form-item>
<el-form-item label="大小(MB)">
<el-input-number
v-model="props.fileSize"
:min="1"
:max="10000"
:step="10"
/>
</el-form-item>
<el-form-item label="数量限制">
<el-input-number v-model="props.limit" :min="1" :max="6" :step="1" />
</el-form-item>
<el-form-item label="允许文件类型">
<el-input v-model="props.accept"></el-input>
</el-form-item>
<el-form-item label="必填">
<el-switch v-model="props.required"></el-switch>
</el-form-item>
<el-form-item label="多文件上传">
<el-switch v-model="props.multiple"></el-switch>
</el-form-item>
<el-form-item label="显示文件列表">
<el-switch v-model="props['show-file-list']"></el-switch>
</el-form-item>
<el-form-item label="显示类型">
<el-radio-group v-model="props['list-type']">
<el-radio-button label="text">普通</el-radio-button>
<!-- <el-radio-button label="picture">照片</el-radio-button> -->
<el-radio-button label="picture-card">照片</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="按钮文字">
<el-input v-model="props.buttonText"></el-input>
</el-form-item>
<el-form-item label="显示提示">
<el-switch v-model="props.showTip"></el-switch>
</el-form-item>
<el-form-item label="提示内容" v-show="props.showTip">
<el-input v-model="props.tips"></el-input>
</el-form-item>
</div>
</template>
<script>
import { changeId } from "../mixin";
export default {
name: "uploadConfig",
props: ["props"],
components: {},
mixins: [changeId],
data() {
return {};
},
methods: {
handlerChangeLabel(val) {
this.props.labelWidth = val ? "80" : "1";
},
},
mounted() {},
watch: {},
};
</script>
<style scoped>
.input {
width: 75%;
}
</style>
\ No newline at end of file
/**
* 表单配置
*/
const formConf = {
version:'1.10',
formRef: 'elForm',
formModel: 'form',
rules: 'rules',
size: 'medium',
labelPosition: 'top',
labelWidth: 80,
formRules: 'rules',
gutter: 15,
disabled: false,
dynamicTableAllowed:true
};
export default formConf;
//动态表单允许放入的组件
export const dynamicTableAllowedItems = [
'input',
'select',
'radio',
'checkbox',
'Switch',
'inputNumber',
'textarea',
'slider',
'rate',
'date',
'time'
];
//row允许放入的items
export const rowAllowedItems = [
'input',
'input',
'select',
'radio',
'checkbox',
'Switch',
'inputNumber',
'textarea',
'slider',
'rate',
'date',
'time'
]
//table允许放入的items
export const tableAllowedItems = [
'row','dynamicTable'
]
\ No newline at end of file
//初始化data里面的数据(1、默认为空,2、之前存在的数据。。)
let itemDatas = {}
export function datas() {
itemDatas = {};
// let self = this;
this.itemList.forEach(val => {
if (val.layout === 'rowItem') { //row布局
dataResolveRowItem(val); //解析row布局
} else if (val.layout === 'dynamicItem') { //动态表单布局
let obj = dataResolveDynamicItem(val);
let array = [];
let { columnsCount } = val
for (let i = 0; i <= columnsCount-1; i++) {
array.push({...obj});
}
itemDatas[val.id] = array;
} else if (val.layout === 'tableItem') { //表格布局
dataResolveTableItem(val);
} else { //表单
dataResolveColItem(val);
}
})
Object.keys(itemDatas).forEach(key => {
this.$set(this.buildData.form, key, itemDatas[key]);
})
}
function dataResolveRowItem(val) {
const columns = val.columns;
columns.forEach(v => {
v.list.forEach(item => {
if (item.layout === 'dynamicItem') {
let obj = dataResolveDynamicItem(item);
let array = [];
array.push(obj);
itemDatas[item.id] = array;
} else {
dataResolveColItem(item);
}
})
})
}
function dataResolveDynamicItem(val) {
const columns = val.columns;
let obj = {};
columns.forEach(v => {
const key = v.id;
obj[key] = v.value;
})
return obj;
}
/*
遍历表格实现组件渲染
*/
function dataResolveTableItem(val) {
val.layoutArray.map((tr) => {
tr.map((td) => {
td.columns.map(item => dataResolveColItem(item));
})
})
}
function dataResolveColItem(val) {
itemDatas[val.id] = val.value;
}
export function fillDatas(jsonValue) {
const self = this;
Object.keys(jsonValue).forEach(key => {
if (typeof (self.buildData.form[key]) === 'string' || typeof (self.buildData.form[key]) === 'number') {
self.$set(self.buildData.form, key, jsonValue[key]);
} else if (self.buildData.form[key] instanceof Array) {//有可能是多选或者是明细表
//判断是否数组中为对象
if (jsonValue[key].length > 0) {
const firsValue = jsonValue[key][0];//获取第一个对象判断是什么类型
if (typeof (firsValue) === 'string' || typeof (firsValue) === 'number') {
self.$set(self.buildData.form, key, jsonValue[key]);
} else { //明细表数组
const arrayData = jsonValue[key];
//self.form[key] = [];
arrayData.forEach((v, index) => {
const newV = JSON.parse(JSON.stringify(v));
self.$set(self.buildData.form[key], index, newV);
})
}
}
}
})
//console.log(this.form);
}
export function addRow(element) {
let obj = dataResolveDynamicItem(element);
this.buildData.form[element.id].push(obj);
}
export function deleteRow(scope, element) {
this.buildData.form[element.id].splice(scope.$index, 1);
}
export function batchDeleteRow(indexs, element) {
for (let i = 0; i < indexs.length; i++) {
const index = indexs[i];
this.buildData.form[element.id].splice(index, 1);
}
}
import {input} from "./items/input";
import {select} from "./items/select";
import {radio} from "./items/radio";
import {checkbox} from "./items/checkbox";
import {Switch} from "./items/Switch";
import {inputNumber} from "./items/inputNumber";
import {textarea} from "./items/textarea";
import {slider} from "./items/slider";
import {rate} from "./items/rate";
import {date} from "./items/date";
import {time} from "./items/time";
import {editor} from "./items/editor";
import {colorPicker} from "./items/colorPicker";
import {cascader} from "./items/cascader";
import {upload} from "./items/upload";
import {dialogList} from "./items/dialogList";
import {dynamicTable} from "./items/dynamicTable";
import {button} from "./items/button";
import {divider} from "./items/divider";
import {row} from "./items/row";
import {table} from "./items/table";
import {alert} from "./items/alert";
import {link} from "./items/link";
import {text} from "./items/text";
import {barCode} from "./items/barCode";
export const formItems = [
input,select,radio,checkbox,Switch,inputNumber,textarea,slider
,rate,date,time,editor,colorPicker,cascader,upload,dialogList,barCode,dynamicTable
];
export const assistFormItems = [button,divider,alert,link,text];
export const layoutFormItems = [row,table];
/**
* 开关,switch是js关键字,所以s大写,避过
*/
export let Switch = {
id:'',
_id:'',
compType: 'Switch',
ele: 'el-switch',
//控件名称(左侧显示)
compName:'开关',
label: '开关',
//图标
compIcon:'switch',
//展示表单的模式
viewType:'component',
//暂时默认为true,无法更改,后期考虑某些时候无法配置
config: true,
// 控件左侧label内容
showLabel:true,
//栅格间隔
gutter:15,
labelWidth: '80',
value: false,
rules:[],
span: 24,
disabled: false,
required: false,
'active-color': '#409EFF',
'inactive-color': '#DCDFE6',
'active-value': 'true',
'inactive-value': 'false'
}
\ No newline at end of file
/**
* 警告
*/
export let alert = {
id:'',
_id:'',
compType: 'alert',
ele: 'el-alert',
compName:'警告',
compIcon:'alert',
//展示表单的模式
viewType:'component',
config: true,
form:false, //是否表单组件
// 控件左侧label内容
showLabel:false,
labelWidth: '0',
span:24,
//标题
title:'alert',
//主题
type:'success',
//辅助文字
description:'form-designer',
//是否可关闭
closable:true,
//是否居中
center:false,
//关闭的按钮
'close-text':'',
//是否显示图标
'show-icon':false,
//主题 light/dark
effect:'light'
}
/**
* 警告
*/
export let barCode = {
id:'',
_id:'',
compType: 'barCode',
ele: 'fancy-bar-code',
compName:'条码',
compIcon:'barcode',
//展示表单的模式
viewType:'component',
config: true,
form:true, //是否表单组件
// 控件左侧label内容
showLabel:false,
labelWidth: '0',
label:'条形码',
span:24,
value:'formDesigner',
format:'CODE128',
lineColor:'#000',
background:'#fff',
width:5,
height:30,
fontSize:12,
displayValue:true
}
\ No newline at end of file
/**
* 单行&多行输入框
*/
export let button = {
id:'',
_id:'',
compType: 'button',
ele: 'el-button',
//控件名称(左侧显示)
compName:'按钮',
//图标
compIcon:'button',
//展示表单的模式
viewType:'component',
//暂时默认为true,无法更改,后期考虑某些时候无法配置
config: true,
// 控件左侧label内容
showLabel:false,
label: '单行文本',
labelWidth: 0,
//是否可以禁用
// disabled:false,
//大小,medium / small / mini
size:'medium',
//primary / success / warning / danger / info / text
type:'primary',
span:24,
text:'按钮',
//简单
plain:false,
//圆角
round:false,
//圆形
circle:false,
//加载中
loading:false,
//禁用
disabled:false,
//图标
icon:'',
}
/**
* 级联选择器
*/
export let cascader = {
id:'',
_id:'',
compType: 'cascader',
ele: 'el-cascader',
//控件名称(左侧显示)
compName:'级联选择器',
//图标
compIcon:'cascader',
//展示表单的模式
viewType:'component',
// 是否可配置
//暂时默认为true,无法更改,后期考虑某些时候无法配置
config: true,
// 控件左侧label内容
showLabel:true,
label: '级联选择',
labelWidth: '80',
placeholder: '请选择',
//栅格间隔
gutter:15,
//默认栅格
span:24,
value: [],
//大小
size:"medium",
//禁用
disabled:false,
//数据类型 static,dynamic
dataType:'static',
'china-area-data':false,
//请求地址
action:'https://www.fastmock.site/mock/51715c0157535b99010bde55f2df33c8/formDesigner/api/cascaderOptions',
props:{
//清空
clearable:true,
//分隔符
separator:"/",
//显示完整路径
'show-all-levels':false,
filterable:false,
props: {
//触发方式,hover
expandTrigger:'click',
//多选
multiple:false,
//可选任一级
checkStrictly:false,
label: 'label',
value: 'value',
children: 'children'
}
},
options:[
{
value: 'zhinan',
label: '指南',
children: [{
value: 'shejiyuanze',
label: '设计原则',
children: [{
value: 'yizhi',
label: '一致'
}]
}]
}
]
}
\ No newline at end of file
// export default (_self, h) => {
// return [
// h("Input", {})
// ];
// };
export let checkbox = {
id:'',
_id:'',
compType: 'checkbox',
//控件名称
compName:'复选框',
//element标签
ele: 'el-checkbox-group',
//图标
compIcon:'checkbox',
//展示表单的模式
viewType:'component',
// 是否可配置
config: true,
// 控件左侧label内容
label: '复选框',
placeholder: '请选择',
// 最大长度
maxLength: 50,
//表单栅格
span:24,
//栅格间隔
gutter:'15',
//标签宽度
labelWidth:80,
//显示标签
showLabel:true,
//必填
required:false,
//禁用
disabled:false,
//是否有边框
border:false,
//选项是否垂直
vertical:false,
//选项大小
size:'medium',
//是否是按钮
optionType:'default',
//选项列表
options:[{
label: '选项一',
value: 1
}, {
label: '选项二',
value: 2
}],
//数据类型 static,dynamic
dataType:'static',
//默认渲染的数据
action:'https://www.fastmock.site/mock/51715c0157535b99010bde55f2df33c8/formDesigner/api/options',
value: [],
rules:[],
// 验证错误提示信息
ruleError: '该字段不能为空'
}
/**
* 单行&多行输入框
*/
export let colorPicker = {
id:'',
_id:'',
compType: 'colorPicker',
ele: 'el-color-picker',
//控件名称(左侧显示)
compName:'颜色选择器',
//图标
compIcon:'colorpicker',
//展示表单的模式
viewType:'component',
//暂时默认为true,无法更改,后期考虑某些时候无法配置
config: true,
// 控件左侧label内容
showLabel:false,
label: '单行文本',
labelWidth: 0,
//是否可以禁用
disabled:false,
//大小,medium / small / mini
size:'medium',
//primary / success / warning / danger / info / text
type:'primary',
span:24,
//选择透明度
'show-alpha':false,
//格式
'color-format':'hex',
//预定义颜色
predefine:[],
value:'#409EFF'
}
\ No newline at end of file
/**
* 单行&多行输入框
*/
export let date = {
id:'',
_id:'',
compType: 'date',
ele: 'el-date-picker',
//控件名称(左侧显示)
compName:'日期',
//图标
compIcon:'date',
//展示表单的模式
viewType:'text',
// 是否可配置
//暂时默认为true,无法更改,后期考虑某些时候无法配置
config: true,
// 控件左侧label内容
showLabel:true,
label: '日期',
labelWidth: '80',
placeholder: '请选择',
// 是否必填
required: false,
// 最大长度
maxLength: 50,
//栅格间隔
gutter:15,
//默认栅格
span:24,
//是否可清空
clearable:true,
disabled:false,
readonly:false,
value: '',
rules:[],
//时间类型
type:'date',
format:'yyyy年MM月dd日',
'value-format':'yyyy年MM月dd日',
'range-separator':'-',
'start-placeholder':'开始日期',
'end-placeholder':'结束日期'
}
/**
* dialogList
*/
export let dialogList = {
id:'',
_id:'',
compType: 'dialogList',
ele: 'fancy-dialog-list',
//控件名称(左侧显示)
compName:'选择列表',
//图标
compIcon:'dialog',
//展示表单的模式
viewType:'component',
// 是否可配置
//暂时默认为true,无法更改,后期考虑某些时候无法配置
config: true,
// 控件左侧label内容
showLabel:true,
label: '选择列表',
labelWidth: '80',
// showLabel: true,
// labelWidth: 80,
// 是否必填
required: false,
//栅格间隔
gutter:15,
//默认栅格
span:24,
//禁用
disabled:false,
//标题
title:'请选择',
//多选
multi:false,
//显示序号
showIndex:false,
//请求地址
action:'https://www.fastmock.site/mock/51715c0157535b99010bde55f2df33c8/formDesigner/api/dialogListData',
//字段配置
colConf:'[{"index":0,"label":"姓名","property":"name","width":"250","show":true},{"index":1,"label":"日期","property":"date","width":"150","show":true},{"index":2,"label":"地址","property":"address","width":"","show":true}]',
// //值
dval:'id',
//字段
dlabel:'name',
height:500,
value: ''
}
\ No newline at end of file
/**
* 分割线
*/
export let divider = {
id:'',
_id:'',
compType: 'divider',
ele: 'el-divider',
compName:'分割线',
compIcon:'divider',
//展示表单的模式
viewType:'component',
config: true,
form:false,
//内容坐标 left|center|right
'content-position':'left',
text:'',
// 控件左侧label内容
showLabel:false,
labelWidth: '0'
}
/**
* 动态表单
*/
export let dynamicTable = {
id:'',
_id:'',
compType: 'dynamicTable',
ele: 'dynamic-table',
//控件名称(左侧显示)
compName:'动态表格',
layout:'dynamicItem',
//图标
compIcon:'table',
// 是否可配置
//暂时默认为true,无法更改,后期考虑某些时候无法配置
//显示标签
labelWidth:0,
showLabel:false,
config: true,
//显示新增按钮
buttonAdd:true,
//显示删除按钮
buttonDel:true,
//显示行号
showIndex:true,
visible:true,
multiCheck:false,
columnsCount:3, // 默认行数
//合计行
'show-summary':false,
'sum-text':'合计',
'summary-text':'',
columns:[
]
}
/**
* 富文本编辑器
*/
export let editor = {
id:'',
_id:'',
compType: 'editor',
ele: 'fancy-editor',
compName:'编辑器',
compIcon:'editor',
//展示表单的模式
viewType:'html',
config: true,
form:true,
// 控件左侧label内容
showLabel:true,
labelWidth: '80',
label:'文本编辑器',
value:'',
required:false,
validateMaxText:false,
//最大长度
max:2000,
//自定义rules
customRules:[]
}
\ No newline at end of file
/**废弃 */
/**
* html
*/
export let html = {
id:'',
_id:'',
compType: 'html',
ele: 'fancy-html',
compName:'HTML',
compIcon:'html',
//展示表单的模式
viewType:'component',
config: true,
form:false,
text:'<span style="color:red">html</span>',
// 控件左侧label内容
showLabel:false,
label:'',
labelWidth: '0'
}
/**
* 单行&多行输入框
*/
export let input = {
id:'',
_id:'',
compType: 'input',
ele: 'el-input',
//控件名称(左侧显示)
compName:'单行文本',
//图标
compIcon:'input',
//展示表单的模式
viewType:'text',
// 是否可配置
//暂时默认为true,无法更改,后期考虑某些时候无法配置
config: true,
// 控件左侧label内容
showLabel:true,
label: '单行文本',
labelWidth: '80',
placeholder: '请输入文本',
// 是否必填
required: false,
// 最大长度
maxLength: 50,
//栅格间隔
gutter:15,
//默认栅格
span:24,
//组件长度
width: '100%',
//是否可清空
clearable:true,
disabled:false,
readonly:false,
//状态,正常,只读,禁用
status:'normal',
//前置图标
'prefix-icon':'',
//后置图标
'suffix-icon':'',
value: '',
//验证规则(字符,phone,email,number)
rules:[],
//验证规则
rulesType:'default',
//前缀
prepend:'',
//后缀
append:''
}
/**
* 计数器
*/
export let inputNumber = {
id:'',
_id:'',
compType: 'inputNumber',
ele: 'el-inputNumber',
//控件名称(左侧显示)
compName:'计数器',
label: '计数器',
//图标
compIcon:'inputNumber',
//展示表单的模式
viewType:'text',
//暂时默认为true,无法更改,后期考虑某些时候无法配置
config: true,
// 控件左侧label内容
showLabel:true,
//栅格间隔
gutter:15,
labelWidth: '80',
value: 0,
rules:[],
span: 24,
min: 0,
max: 100,
step: 1,
'step-strictly': false,
precision: 0,
'controls-position': 'default',
disabled: false,
readonly: false,
required: false,
regList: []
}
/**
* 文字链接
*/
export let link = {
id:'',
_id:'',
compType: 'link',
ele: 'el-link',
compName:'文字链接',
compIcon:'link',
//展示表单的模式
viewType:'component',
config: true,
form:false, //是否表单组件
// 控件左侧label内容
showLabel:false,
labelWidth: '0',
span:24,
//主题
type:'primary',
//链接地址
href:'http://www.baidu.com',
//是否下划线
underline:true,
//是否禁用
disabled:false,
text:'链接',
target:'_blank'
}
\ No newline at end of file
// export default (_self, h) => {
// return [
// h("Input", {})
// ];
// };
export let radio = {
id:'',
_id:'',
compType: 'radio',
//控件名称
compName:'单选框',
//element标签
ele: 'el-radio-group',
//图标
compIcon:'radio',
//展示表单的模式
viewType:'component',
// 是否可配置
config: true,
// 控件左侧label内容
label: '单选框',
placeholder: '请选择',
// 最大长度
maxLength: 50,
//表单栅格
span:24,
//栅格间隔
gutter:'15',
//标签宽度
labelWidth:80,
//显示标签
showLabel:true,
//必填
required:false,
//禁用
disabled:false,
//是否有边框
border:false,
//选项是否垂直
vertical:false,
//选项大小
size:'medium',
//是否是按钮
optionType:'default',
//选项列表
options:[{
label: '选项一',
value: 1
}, {
label: '选项二',
value: 2
}],
//数据类型 static,dynamic
dataType:'static',
//默认渲染的数据
action:'https://www.fastmock.site/mock/51715c0157535b99010bde55f2df33c8/formDesigner/api/options',
value: '',
rules:[],
// 验证错误提示信息
ruleError: '该字段不能为空'
}
/**
* 评分
*/
export let rate = {
id:'',
_id:'',
compType: 'rate',
ele: 'el-rate',
//控件名称(左侧显示)
compName:'评分',
label: '评分',
//图标
compIcon:'rate',
//展示表单的模式
viewType:'component',
//暂时默认为true,无法更改,后期考虑某些时候无法配置
config: true,
// 控件左侧label内容
showLabel:true,
//栅格间隔
gutter:15,
labelWidth: '80',
value: 1,
rules:[],
span: 24,
disabled: false,
required: false,
max: 5,
'allow-half': false,
'show-score': false
}
\ No newline at end of file
/**
* 栅格布局
*/
// export default (_self, h) => {
// return [
// h("Input", {})
// ];
// };
export let row = {
id:'',
_id:'',
compType: 'row',
//控件名称
compName:'栅格布局',
//element标签
ele: 'el-row',
//图标
compIcon:'col',
layout:'rowItem',
// 是否可配置
config: true,
//
flex:'default',
justify:'start',
align:'top',
gutter:0,
columns:[
{
index:0,
span:12,
list:[]
},
{
index:1,
span:12,
list:[]
}
],
}
export let select = {
id:'',
_id:'',
compType: 'select',
//控件名称
compName:'下拉框',
//element标签
ele: 'el-select',
//图标
compIcon:'select',
//展示表单的模式
viewType:'component',
// 是否可配置
config: true,
// 控件左侧label内容
label: '下拉框',
placeholder: '请选择',
// 最大长度
maxLength: 50,
//表单栅格
span:24,
//栅格间隔
gutter:'15',
//标签宽度
labelWidth:80,
//显示标签
showLabel:true,
//必填
required:false,
//多选
multiple:false,
'collapse-tags':false,
//禁用
disabled:false,
//搜索
filterable:false,
//选项列表
options:[{
label: '选项一',
value: 1
}, {
label: '选项二',
value: 2
}],
//数据类型 static,dynamic
dataType:'static',
//默认渲染的数据
action:'https://www.fastmock.site/mock/51715c0157535b99010bde55f2df33c8/formDesigner/api/options',
//是否可以清空
clearable:false,
value: '',
rules:[],
// 验证错误提示信息
ruleError: '该字段不能为空'
}
/**
* 单行&多行输入框
*/
export let slider = {
id:'',
_id:'',
compType: 'slider',
ele: 'el-slider',
//控件名称(左侧显示)
compName:'滑块',
label: '滑块',
//图标
compIcon:'slider',
//展示表单的模式
viewType:'component',
//暂时默认为true,无法更改,后期考虑某些时候无法配置
config: true,
// 控件左侧label内容
showLabel:true,
//栅格间隔
gutter:15,
labelWidth: '80',
value: 0,
rules:[],
span: 24,
disabled: false,
required: false,
//最小值
min: 0,
//最大值
max: 20,
//步长
step: 1,
//是否显示断点
'show-stops': true,
//是否显示tooltip
'show-tooltip': true,
//范围选择 1,50
range: false
}
\ No newline at end of file
/**
* 表格布局
*/
import {getDefaultTrs} from '../../table/table'
let trs = getDefaultTrs();
export let table = {
id:'',
_id:'',
compType: 'table',
ele: 'fancy-table',
//控件名称(左侧显示)
compName:'表格布局',
//图标
compIcon:'table_layout',
layout:'tableItem',
// 是否可配置
//暂时默认为true,无法更改,后期考虑某些时候无法配置
config: true,
layoutArray:trs,
//单元格样式
tdStyle:'',
width:100,
height:50
}
\ No newline at end of file
/**
* 文本
*/
export let text = {
id:'',
_id:'',
compType: 'text',
ele: 'fancy-text',
compName:'文本',
compIcon:'text',
//展示表单的模式
viewType:'component',
config: true,
form:false,
show:true,
text:'文本',
align:'left',
color:'#000000',
size:'14',
bold:'400',
// 控件左侧label内容
showLabel:false,
labelWidth: '0'
}
\ No newline at end of file
/**
* 单行&多行输入框
*/
export let textarea = {
id:'',
_id:'',
compType: 'textarea',
ele: 'el-input',
//控件名称(左侧显示)
compName:'多行文本',
//图标
compIcon:'textarea',
//展示表单的模式
viewType:'text',
// 是否可配置
//暂时默认为true,无法更改,后期考虑某些时候无法配置
config: true,
// 控件左侧label内容
showLabel:true,
label: '多行文本',
labelWidth: '80',
placeholder: '请输入文本',
type:'textarea',
// 是否必填
required: false,
// 最大长度
maxlength: 50,
//输入统计
'show-word-limit':false,
//栅格间隔
gutter:15,
//默认栅格
span:24,
//是否可清空
clearable:true,
disabled:false,
readonly:false,
rows:4,
//状态,正常,只读,禁用
status:'normal',
value: '',
rules:[],
// 验证错误提示信息
ruleError: '该字段不能为空'
}
/**
* 单行&多行输入框
*/
export let time = {
id:'',
_id:'',
compType: 'time',
ele: 'el-time-picker',
//控件名称(左侧显示)
compName:'时间',
//图标
compIcon:'time',
//展示表单的模式
viewType:'text',
// 是否可配置
//暂时默认为true,无法更改,后期考虑某些时候无法配置
config: true,
// 控件左侧label内容
showLabel:true,
label: '时间',
labelWidth: '80',
placeholder: '请选择',
// 是否必填
required: false,
// 最大长度
maxLength: 50,
//栅格间隔
gutter:15,
//默认栅格
span:24,
//是否可清空
clearable:true,
disabled:false,
readonly:false,
value: '',
rules:[],
'picker-options': {
selectableRange: '00:00:00-23:59:59'
},
'arrow-control':true,
align:'left',
format: 'HH:mm:ss',
'value-format': 'HH:mm:ss',
'is-range':false,
'range-separator':'-'
}
/**
* 上传组件
*/
export let upload = {
id:'',
_id:'',
compType: 'upload',
ele: 'el-upload',
//控件名称(左侧显示)
compName:'附件',
//图标
compIcon:'att',
//展示表单的模式
viewType:'component',
// 是否可配置
//暂时默认为true,无法更改,后期考虑某些时候无法配置
config: true,
// 控件左侧label内容
showLabel:true,
label: '附件上传',
labelWidth: '80',
//栅格间隔
gutter:15,
//默认栅格
span:24,
// 是否必填
required: false,
//上传地址
action:'http://192.168.0.98:8090/api/upload/file',
//多选上传
multiple:false,
name:'file',
//显示上传文件列表
'show-file-list':true,
//文件列表类型
'list-type':'text',
value:'',
width:100,
//按钮文字
buttonText:'请上传附件',
//是否显示描述
showTip:false,
//描述内容
tips:'点击按钮上传附件',
//允许文件类型
accept:'.pdf, .doc, .docx, .xls, .xlsx',
//文件大小MB
fileSize:10,
// 最大允许上传个数
limit:1,
}
// 模态框
export const remoteData = {
methods: {
getRemoteData(){
//动态数据
if(this.conf.dataType === 'dynamic'){
this.$axios.get(this.conf.action).then(res => {
if(this.conf.options.length===0){
this.conf.options = this.conf.options.concat(res.data);
}
})
}
}
}
}
export const changeId = {
methods: {
handlerChangeId(val){
let idArray = this.getFormId(this.props._id);
console.log(idArray);
if(idArray.includes(val)){ //如果存在id相等,则提示
this.$message.error('该ID已经存在,请修改');
this.props.id=this.props._id;
}else{
this.props._id=val;
}
}
}
}
import { isAttr,jsonClone } from '../utils';
import childrenItem from './slot/index';
import {remoteData} from './mixin';
//先修改在这里,后续需要优化
function vModel(self, dataObject) {
dataObject.props.value = self.value;
dataObject.on.input = val => {
self.$emit('input', val)
}
//判断是否为上传组件
if(self.conf.compType === 'upload'){
dataObject.attrs['before-upload'] = file=>{
//非限定后缀不允许上传
const fileName = file.name;
const suffixName = fileName.split('.').pop();
if(!self.conf.accept.includes(suffixName)){
self.$message.error('该后缀文件不允许上传');
return false;
}
const fileSize = file.size;
if(fileSize>dataObject.props.fileSize*1024*1024){
self.$message.error('文件大小超出限制,请检查!');
return false;
}
}
dataObject.attrs['on-success'] = (response, file, fileList)=>{
let uloadData = fileList.map(v => v.response.data).join(',')
self.$emit('input',uloadData)
}
dataObject.attrs['on-remove'] = ( file, fileList)=>{
let uloadData = fileList.map(v => v.response.data).join(',')
self.$emit('input',uloadData)
}
}
}
export default {
render(h) {
let dataObject = {
attrs: {},
props: {},
on: {},
style: {}
}
//远程获取数据
this.getRemoteData();
const confClone = jsonClone(this.conf);
const children = childrenItem(h,confClone);
Object.keys(confClone).forEach(key => {
const val = confClone[key]
if (dataObject[key]) {
dataObject[key] = val
} else if(key ==='width'){
dataObject.style= 'width:'+val;
} else if (!isAttr(key)) {
dataObject.props[key] = val
}else {
if(key !== 'value'){
dataObject.attrs[key] = val
}
}
})
/*调整赋值模式,规避cascader组件赋值props会出现覆盖预制参数的bug */
vModel(this, dataObject);
return h(confClone.ele, dataObject, children)
},
props: ['conf','value'],
mixins:[remoteData]
}
//在此注册组件
const components = [
'input',
'select',
'radio',
'checkbox',
'Switch',
'inputNumber',
'textarea',
'slider',
'rate',
'date',
'time',
'editor',
'colorPicker',
'cascader',
'upload',
'button',
'divider',
'alert',
'link',
'dialogList',
'barCode',
'text',
'html',
'row',
'dynamicTable',
'table',
'tdItem'
];
let comps = [];
for (let i in components) {
const comp = {
name: components[i],
content : null
}
comps.push(comp);
}
export default comps;
\ No newline at end of file
import {isAttr,jsonClone} from '../utils/index';
import childrenItem from './slot/index';
import {remoteData} from './mixin';
function vModel(self, dataObject) {
dataObject.on.input = val => {
self.$emit('input', val)
}
}
export default {
render(h) {
let dataObject = {
attrs: {},
props: {},
on: {},
style: {}
}
//远程获取数据
this.getRemoteData();
const confClone = jsonClone(this.conf);
const children = childrenItem(h,confClone);
Object.keys(confClone).forEach(key => {
const val = confClone[key]
if (dataObject[key]) {
dataObject[key] = val
} else if (!isAttr(key)) {
dataObject.props[key] = val
} else if(key ==='width'){
dataObject.style= 'width:'+val;
}else {
dataObject.attrs[key] = val
}
})
/*调整赋值模式,规避cascader组件赋值props会出现覆盖预制参数的bug */
vModel(this, dataObject);
return h(confClone.ele, dataObject, children)
},
props: ['conf'],
mixins:[remoteData]
}
export default function checkRules(element) {
let r = [];
const _trigger = ['blur','change'];
if(element.required){
r.push({required: true, message: element.label+'不能为空', trigger:_trigger});
}
//判断是否有规则
if(element.rules){
element.rules.forEach(obj=>{
r.push({pattern:new RegExp(obj.rule),message:obj.msg, trigger:_trigger});
});
}
//编辑器最大字数验证
if(typeof element.validateMaxText !== 'undefined'&&element.validateMaxText){
const maxRules = {
max: element.max, message: element.label+'超出最大字数限制', trigger:_trigger
}
r.push(maxRules);
}
return r;
}
\ No newline at end of file
export default {
slot(h,conf) {
return conf.text;
}
}
\ No newline at end of file
export default {
slot(h,conf) {
const list = []
const vertical = conf.vertical?'display:block;':'';
conf.options.forEach(item => {
if (conf.optionType === 'button') list.push(<el-checkbox-button label={item.value}>{item.label}</el-checkbox-button>)
else list.push(<el-checkbox label={item.value} style={vertical} border={conf.border}>{item.label}</el-checkbox>)
})
return list
}
}
\ No newline at end of file
import text from './el-button';
export default text;
\ No newline at end of file
export default {
slot(h,conf) {
const slotText = []
if(conf.prepend!==''){
slotText.push(<template slot="prepend">{conf.prepend}</template>);
}
if(conf.append!==''){
slotText.push(<template slot="append">{conf.append}</template>);
}
return slotText;
}
}
\ No newline at end of file
import text from './el-button';
export default text;
\ No newline at end of file
export default {
slot(h,conf) {
const list = [];
const vertical = conf.vertical?'display:block;':'';
conf.options.forEach(item => {
if (conf.optionType === 'button') list.push(<el-radio-button label={item.value} style="">{item.label}</el-radio-button>)
else list.push(<el-radio label={item.value} style={vertical} border={conf.border}>{item.label}</el-radio>)
})
return list
}
}
\ No newline at end of file
export default {
slot(h,conf) {
const list = []
conf.options.forEach(item => {
list.push(<el-option label={item.label} value={item.value} disabled={item.disabled}></el-option>)
})
return list;
}
}
\ No newline at end of file
export default {
slot(h,conf) {
const list = [];
if (conf['list-type'] === 'picture-card') {
list.push(<i class="el-icon-plus"/>)
} else {
list.push(<el-button size="small" type="primary" icon="el-icon-upload">{conf.buttonText}</el-button>)
}
if (conf.showTip) {
list.push(<div slot="tip" class="el-upload__tip">{conf.tips}</div>)
}
return list
}
}
\ No newline at end of file
const slots = require.context('./', false, /\.js$/);
const componentChild = {};
slots.keys().forEach(obj=>{
const tag = obj.replace('./','').replace('.js','');
if(tag !=='index'){
componentChild[tag] = slots(obj).default;
}
});
export default function childrenItem(h,confClone) {
let children = [];
const childObjs = componentChild[confClone.ele]
if (childObjs&&childObjs.slot) {
Object.keys(childObjs).forEach(key => {
const childFunc = childObjs[key]
children.push(childFunc(h,confClone))
})
}
return children;
}
\ No newline at end of file
import { isAttr,jsonClone } from '../utils';
import childrenItem from './slot/index';
import {remoteData} from './mixin';
function vModel(self, dataObject) {
dataObject.props.value=self.value;
dataObject.on.input = val => {
self.$emit('input', val)
}
}
export default {
render(h) {
let dataObject = {
attrs: {},
props: {},
on: {},
style: {}
}
//远程获取数据
this.getRemoteData();
const confClone = jsonClone(this.conf);
const children = childrenItem(h,confClone);
Object.keys(confClone).forEach(key => {
const val = confClone[key]
if (dataObject[key]) {
dataObject[key] = val
} else if(key ==='width'){
dataObject.style= 'width:'+val+'%';
} else if (!isAttr(key)) {
dataObject.props[key] = val
} else {
dataObject.attrs[key] = val
}
})
/*调整赋值模式,规避cascader组件赋值props会出现覆盖预制参数的bug */
vModel(this, dataObject);
return h(confClone.ele, dataObject, children)
},
props: ['conf','value'],
mixins:[remoteData]
}
<script>
import draggable from "vuedraggable";
import render from "./custom/render";
import { getSimpleId } from "./utils/IdGenerate";
import { dynamicTableAllowedItems, tableAllowedItems } from "./custom/formConf";
import dynamicTable from "./dynamic/dynamicTable";
import dynamicTableItem from "./dynamic/dynamicTableItem";
import fancyTable from "./table/fancyTable";
import fancyTableItem from "./table/fancyTableItem";
/**
* 动态表单允许增加的组件列表
*/
const components = {
itemBtns(h, element, parent) {
const { copyItem, deleteItem } = this.$listeners;
return [
<span
class="drawing-item-copy"
title="复制"
onClick={(event) => {
copyItem(element, parent);
event.stopPropagation();
}}
>
<i class="el-icon-copy-document" />
</span>,
<span
class="drawing-item-delete"
title="删除"
onClick={(event) => {
deleteItem(element, parent);
event.stopPropagation();
}}
>
<i class="el-icon-delete" />
</span>,
];
},
};
const layouts = {
colItem(h, element, parent) {
console.log(parent);
let className =
this.activeItem.id === element.id
? "drawing-item active-from-item"
: "drawing-item";
let labelWidth = element.labelWidth ? `${element.labelWidth}px` : null;
const { onActiveItemChange } = this.$listeners;
return (
<el-col
class={className}
span={element.span}
nativeOnClick={(event) => {
onActiveItemChange(element);
event.stopPropagation();
}}
>
<span class="component-name component-id">{element.id}</span>
<el-form-item
label={element.showLabel ? element.label : ""}
label-width={labelWidth}
required={element.required}
>
<render
key={element.id}
conf={element}
onInput={(event) => {
this.$set(element, "value", event);
}}
/>
</el-form-item>
{components.itemBtns.apply(this, arguments)}
</el-col>
);
},
rowItem(h, element) {
const { onActiveItemChange } = this.$listeners;
const className =
this.activeItem.id === element.id
? "drawing-item drawing-row-item active-from-item"
: "drawing-item drawing-row-item";
return (
<el-col class={className}>
<el-row
gutter={element.gutter}
nativeOnClick={(event) => {
onActiveItemChange(element);
event.stopPropagation();
}}
>
<span class="component-name">{element.id}</span>
<div
class="drag-wrapper"
style="padding-left: 7.5px; padding-right: 7.5px;"
>
{element.columns.map((item) => {
return (
<el-col class="drag-col-wrapper" span={item.span}>
<draggable
class="drag-wrapper row-drag"
v-model={item.list}
animation="100"
group="componentsGroup"
onAdd={(e) => {
this.handlerAdd(e, item, element);
}}
>
{item.list.map((obj) => {
return renderChildren.call(this, h, obj, element);
})}
</draggable>
</el-col>
);
})}
</div>
</el-row>
{components.itemBtns.call(this, h, element)}
</el-col>
);
},
tableItem(h, element) {
let className = "";
className =
this.activeItem.id === element.id
? "drawing-item drawing-row-item active-from-item"
: "drawing-item drawing-row-item";
const { onActiveItemChange } = this.$listeners;
return (
<el-col
class={className}
nativeOnClick={(event) => {
onActiveItemChange(element);
event.stopPropagation();
}}
>
<span class="component-name" style="margin-bottom:15px">
{element.id}
</span>
<fancy-table
layoutArray={element.layoutArray}
tdStyle={element.tdStyle}
width={element.width}
height={element.height}
onSelectItem={(item) => {
onActiveItemChange(item);
}}
scopedSlots={{
default: (item) => {
return (
<draggable
tag="div"
class="table__content row-drag"
v-model={item.td.columns}
animation="100"
group="componentsGroup"
onAdd={(e) => {
this.handlerTableAdd(e, item.td);
e.stopPropagation();
}}
>
{item.td.columns.map((obj) => {
return renderChildren.call(this, h, obj, item.td);
})}
</draggable>
);
},
}}
/>
{components.itemBtns.call(this, h, element)}
</el-col>
);
},
dynamicItem(h, element) {
let className = "";
className =
this.activeItem.id === element.id
? className + "drawing-item active-from-item"
: className + "drawing-item";
const { onActiveItemChange } = this.$listeners;
return (
<el-col class={className}>
<dynamic-table
conf={element}
activeItem={this.activeItem}
nativeOnClick={(event) => {
onActiveItemChange(element);
event.stopPropagation();
}}
>
<draggable
tag="div"
class="dynamic-table__content row-drag"
ghost-class="dynamicGhost"
v-model={element.columns}
animation="100"
group="componentsGroup"
onAdd={(e) => {
this.handlerDynamicAdd(e, element);
}}
>
{element.columns.map((item, index) => {
return (
<dynamic-table-item
item={item}
activeItem={this.activeItem}
onSelectItem={(evt, item) => {
onActiveItemChange(item);
evt.stopPropagation();
}}
onCopyItem={(evt) => {
this.handlerCopyItem(evt, element, index);
evt.stopPropagation();
}}
onDeleteItem={(evt) => {
this.handlerDeleteItem(evt, element, index);
evt.stopPropagation();
}}
/>
);
})}
</draggable>
</dynamic-table>
{components.itemBtns.call(this, h, element)}
</el-col>
);
},
};
/**
* 生成row的子选项
*/
function renderChildren(h, element, parent) {
const layout = layouts[element.layout];
if (layout) {
return layout.call(this, h, element, parent);
}
return layoutIsNotFound.call(this);
}
function layoutIsNotFound() {
throw new Error(`没有与${this.element.layout}匹配的layout`);
}
export default {
name: "designItem",
components: {
render,
draggable,
dynamicTable,
dynamicTableItem,
fancyTable,
fancyTableItem,
},
props: {
model: {
type: Object,
default: () => {
return {};
},
},
activeItem: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
activeComponent: this.activeItem,
};
},
render(h) {
const layout = layouts[this.model.layout];
if (layout) {
return layout.call(this, h, this.model);
}
return layoutIsNotFound.call(this);
},
methods: {
handlerAdd(evt, item, row) {
console.log(this.activeItem.compType, row);
if (evt.pullMode === "clone") {
if (
!(
evt.to.className.indexOf("row-drag") > -1 &&
this.activeItem.compType === "row"
)
) {
item.list.splice(evt.newIndex, 0, this.activeItem);
}
} else {
if (evt.item.className.indexOf("el-row") > -1) {
//防止row嵌套
const newIndex = evt.newIndex;
const oldIndex = evt.oldIndex;
const rowItem = item.list[newIndex];
item.list.splice(newIndex, 1);
this.$message.error("布局组件不允许被嵌套!");
this.$emit("rowItemRollBack", rowItem, oldIndex); //还原到原先的列表中
return false;
}
}
},
/**
* 动态表单
*/
handlerDynamicAdd(evt, item) {
if (evt.pullMode === "clone") {
if (dynamicTableAllowedItems.includes(this.activeItem.compType)) {
item.columns.splice(evt.newIndex, 0, this.activeItem);
} else {
this.$message.error("该组件不允许被放入动态表格内!");
}
} else {
if (evt.item.className.indexOf("el-row") > -1) {
//防止row嵌套
const newIndex = evt.newIndex;
const oldIndex = evt.oldIndex;
const rowItem = item.columns[newIndex];
item.columns.splice(newIndex, 1);
this.$message.error("布局组件不允许放入动态表格!");
this.$emit("rowItemRollBack", rowItem, oldIndex); //还原到原先的列表中
return false;
}
}
},
handlerTableAdd(evt, td) {
if (evt.pullMode === "clone") {
if (!tableAllowedItems.includes(this.activeItem.compType)) {
td.columns.splice(evt.newIndex, 0, this.activeItem);
} else {
this.$message.error("该组件不允许被放入表格内!");
}
}
},
handlerCopyItem(evt, element, index) {
const item = element.columns[index];
const clone = JSON.parse(JSON.stringify(item));
let uId = "fd_" + getSimpleId();
clone.id = uId;
clone._id = uId;
element.columns.push(clone);
},
handlerDeleteItem(evt, element, index) {
element.columns.splice(index, 1);
},
},
};
</script>
\ No newline at end of file
<template>
<!--中间面板-->
<div class="center-board">
<div class="action-bar">
<el-button icon="el-icon-view" type="text" @click="preview">
预览
</el-button>
<el-button icon="el-icon-view" type="text" @click="view">
查看
</el-button>
<el-button icon="el-icon-tickets" type="text" @click="viewJSON">
JSON
</el-button>
<el-button icon="el-icon-s-tools" type="text" @click="setting">
设置
</el-button>
<el-button
class="delete-btn"
icon="el-icon-delete-solid"
type="text"
@click="clear"
>
清空
</el-button>
<el-button icon="el-icon-question" type="text" @click="help">
帮助
</el-button>
</div>
<el-scrollbar class="center-scrollbar">
<el-row class="center-board-row" :gutter="formConf.gutter">
<el-form
:size="formConf.size"
:label-position="formConf.labelPosition"
:disabled="formConf.disabled"
:label-width="formConf.labelWidth + 'px'"
>
<draggable
class="drawing-board"
:list="list"
:animation="100"
group="componentsGroup"
draggable=".drawing-item"
>
<design-item
v-for="(element, index) in list"
:key="index"
:model="element"
:activeItem="activeItem"
@rowItemRollBack="handlerRollBack"
@onActiveItemChange="handlerActiveItemChange"
@copyItem="handlerItemCopy"
@deleteItem="handlerItemDelete"
/>
</draggable>
<div v-show="infoShow" class="empty-info">
<el-empty description="从左侧拖拽添加控件"></el-empty>
</div>
</el-form>
</el-row>
</el-scrollbar>
<config-panel :activeItem="activeItem" :itemList="list" />
<!-- 设计器配置弹出框 -->
<el-dialog
:visible.sync="formConfVisible"
width="50%"
top="30px"
append-to-body
:center="true"
>
<el-tabs v-model="activeName">
<el-tab-pane label="表单配置" name="formConf">
<el-form ref="formConf" :model="formConf" label-width="100px">
<el-form-item label="表单名">
<el-input class="input" v-model="formConf.formRef"></el-input>
</el-form-item>
<el-form-item label="表单模型">
<el-input class="input" v-model="formConf.formModel"></el-input>
</el-form-item>
<el-form-item label="校验模型">
<el-input class="input" v-model="formConf.formRules"></el-input>
</el-form-item>
<el-form-item label="表单尺寸">
<el-radio-group v-model="formConf.size">
<el-radio-button label="medium">中等</el-radio-button>
<el-radio-button label="small">较小</el-radio-button>
<el-radio-button label="mini">迷你</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="标签对齐">
<el-radio-group v-model="formConf.labelPosition">
<el-radio-button label="right">右对齐</el-radio-button>
<el-radio-button label="left">左对齐</el-radio-button>
<el-radio-button label="top">顶部对齐</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="标签宽度">
<el-input-number
v-model="formConf.labelWidth"
:min="60"
:max="140"
></el-input-number>
</el-form-item>
<el-form-item label="栅格间隔">
<el-input-number
v-model="formConf.gutter"
:min="0"
:max="30"
></el-input-number>
</el-form-item>
<el-form-item label="动态表格支持">
<el-switch v-model="formConf.dynamicTableAllowed"></el-switch>
</el-form-item>
<!-- <el-form-item label="组件高亮显示">
<el-switch v-model="formConf.dynamicTableAllowed"></el-switch>
</el-form-item> -->
<el-form-item label="禁用表单">
<el-switch v-model="formConf.disabled"></el-switch>
</el-form-item>
</el-form>
</el-tab-pane>
<!-- <el-tab-pane label="提交前" name="fourth">开发中...</el-tab-pane> -->
</el-tabs>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="handlerSaveFormConf">确 定</el-button>
</span>
</el-dialog>
<el-dialog
:visible.sync="previewVisible"
width="70%"
append-to-body
title="预览"
>
<preview
:itemList="itemList"
:formConf="formConf"
v-if="previewVisible"
/>
</el-dialog>
<el-dialog
:visible.sync="JSONVisible"
width="70%"
title="JSON"
center
append-to-body
:close-on-click-modal="false"
>
<codemirror v-model="viewCode" :options="options" />
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="handlerSetJson()">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import draggable from "vuedraggable";
import configPanel from "./configPanel";
import designItem from "./designItem";
import { getSimpleId } from "./utils/IdGenerate";
import { isLayout, isTable, inTable, jsonClone } from "./utils/index";
import formConf from "./custom/formConf";
import preview from "./preview";
import { codemirror } from "vue-codemirror";
// 核心样式
import "codemirror/lib/codemirror.css";
// 引入主题后还需要在 options 中指定主题才会生效
import "codemirror/theme/dracula.css";
import "codemirror/mode/javascript/javascript";
export default {
name: "designer",
components: {
draggable,
configPanel,
designItem,
preview,
codemirror,
},
props: {
list: {
type: Array,
default: () => {
return [];
},
},
formConfig: {
type: Object,
default: formConf,
},
},
provide() {
return {
getContext: this,
};
},
data() {
return {
formConf: formConf,
activeItem: {},
lastActiveItem: {},
formConfVisible: false,
previewVisible: false,
JSONVisible: false,
itemList: [],
activeName: "formConf",
editorCode: "",
viewCode: "",
// 默认配置
options: {
tabSize: 2, // 缩进格式
theme: "dracula", // 主题,对应主题库 JS 需要提前引入
lineNumbers: true, // 显示行号
line: true,
styleActiveLine: true, // 高亮选中行
hintOptions: {
completeSingle: true, // 当匹配只有一项的时候是否自动补全
},
},
};
},
mounted() {},
methods: {
preview() {
const clone = JSON.parse(JSON.stringify(this.list));
this.itemList = clone;
this.previewVisible = true;
},
viewJSON() {
this.viewCode = this.code;
this.JSONVisible = true;
},
view() {
localStorage.setItem("formValue", this.code);
window.open("#/view");
},
setting() {
this.formConfVisible = true;
},
clear() {
console.log(11);
this.$confirm("此操作将清空整个表单,是否继续?").then(() => {
this.$emit("clear");
});
},
help() {
window.open("https://gitee.com/wurong19870715/formDesigner");
},
handlerActiveItemChange(obj) {
this.lastActiveItem = this.activeItem;
this.activeItem = obj;
},
handlerItemCopy(origin, parent) {
if (isLayout(origin)) {
//row
const clone = jsonClone(origin);
const uId = "row_" + getSimpleId();
console.log(uId);
clone.id = uId;
clone._id = uId;
clone.columns.map((column) => {
let itemList = [];
column.list.map((item) => {
const cloneitem = jsonClone(item);
const uId = "fd_" + getSimpleId();
cloneitem.id = uId;
cloneitem._id = uId;
itemList.push(cloneitem);
});
column.list = [];
column.list = itemList;
});
this.list.push(clone);
this.handlerActiveItemChange(clone);
} else if (isTable(origin)) {
//表格布局
const clone = jsonClone(origin);
const uId = "table_" + getSimpleId();
clone.id = uId;
clone._id = uId;
clone.layoutArray.map((tr) => {
tr.map((td) => {
let itemList = [];
td.id = getSimpleId();
td.columns.map((item) => {
const cloneitem = jsonClone(item);
const uId = "fd_" + getSimpleId();
cloneitem.id = uId;
cloneitem._id = uId;
itemList.push(cloneitem);
});
td.columns = [];
td.columns = itemList;
});
});
this.list.push(clone);
this.handlerActiveItemChange(clone);
} else {
//如果是普通组件,需要判断他是否再布局组件下。
if (parent) {
if (inTable(parent)) {
//增加表格组件的支持
if (parent.columns.some((item) => item.id === origin.id)) {
const clone = jsonClone(origin);
const uId = "fd_" + getSimpleId();
clone.id = uId;
clone._id = uId;
parent.columns.push(clone);
this.handlerActiveItemChange(clone);
}
} else {
parent.columns.map((column) => {
if (column.list.some((item) => item.id === origin.id)) {
const clone = jsonClone(origin);
const uId = "fd_" + getSimpleId();
clone.id = uId;
clone._id = uId;
column.list.push(clone);
this.handlerActiveItemChange(clone);
}
});
}
} else {
const clone = jsonClone(origin);
const uId = "fd_" + getSimpleId();
clone.id = uId;
clone._id = uId;
this.list.push(clone);
this.handlerActiveItemChange(clone);
}
}
},
handlerItemDelete(origin, parent) {
if (isLayout(origin) || isTable(origin)) {
//如果是布局组件,则直接删除
const index = this.list.findIndex((item) => item.id === origin.id);
this.list.splice(index, 1);
} else {
//如果不是布局组件,则先判断是不是再布局内部,如果不是,则直接删除就可以,如果是,则要在布局内部删除
if (parent) {
if (inTable(parent)) {
//增加表格组件的支持
const colIndex = parent.columns.findIndex(
(item) => item.id === origin.id
);
if (colIndex > -1) {
parent.columns.splice(colIndex, 1);
}
} else {
parent.columns.map((column) => {
const colIndex = column.list.findIndex(
(item) => item.id === origin.id
);
if (colIndex > -1) {
column.list.splice(colIndex, 1);
}
});
}
} else {
const index = this.list.findIndex((item) => item.id === origin.id);
this.list.splice(index, 1);
}
}
},
handlerSaveFormConf() {
this.formConfVisible = false;
},
handlerRollBack(rowItem, oldIndex) {
//还原
this.list.splice(oldIndex, 0, rowItem);
},
handlerSetJson() {
this.$emit("updateJSON", this.viewCode);
this.JSONVisible = false;
},
},
computed: {
infoShow() {
return this.list.length < 1;
},
code() {
let json = {};
json.config = this.formConf;
json.list = this.list;
return JSON.stringify(json, null, 4);
},
},
watch: {
activeItem(newValue, oldValue) {
this.lastActiveItem = oldValue;
},
},
};
</script>
<style scoped>
.el-rate {
display: inline-block;
}
.center-scrollbar >>> .el-scrollbar__bar.is-horizontal {
display: none;
}
.center-scrollbar >>> .el-scrollbar__wrap {
overflow-x: hidden;
}
.empty-info >>> .el-empty__description p {
color: #ccb1ea;
font-size: 16px;
}
.drawing-board >>> .el-radio.is-bordered + .el-radio.is-bordered {
margin-left: 0px;
}
.drawing-board >>> .el-checkbox.is-bordered + .el-checkbox.is-bordered {
margin-left: 0px;
}
</style>
<style lang="less">
@import "./style/designer.less";
</style>
<style>
@import "./style/designer.css";
</style>
\ No newline at end of file
<!--动态表单(设计器)-->
<template>
<div class="dynamic-table">
<slot>
</slot>
</div>
</template>
<script>
export default {
name:'dynamicTable',
props:['conf','activeItem'],
data(){
return {
test1:'',
list:[]
}
},
components:{
},
methods:{
}
}
</script>
<style>
</style>
\ No newline at end of file
<!--动态表单(设计器)-->
<script>
import draggable from "vuedraggable";
import render from "../custom/render";
const colItem = function (h, element) {
const { selectItem, copyItem, deleteItem } = this.$listeners;
return (
<div
class={{
"dynamic-table__item": true,
active: this.isHover || this.isActive,
}}
style="min-width:200px;width: auto;position:relative"
onClick={(e) => {
selectItem(e, element);
}}
onMouseover={() => {
this.isHover = true;
}}
onMouseleave={() => {
this.isHover = false;
}}
>
<div class="dynamic-table__item_title">{element.label}</div>
<div class="dynamic-table__item_body">
<render conf={element} />
<span v-show={element.required} style="color:#F56C6C">
*
</span>
</div>
<span
class="dynamic-table-item-copy"
title="复制"
v-show={this.showbutton}
onClick={(e) => {
copyItem(e, element);
}}
>
<i class="el-icon-copy-document" />
</span>
<span
class="dynamic-table-item-delete"
title="删除"
v-show={this.showbutton}
onClick={(e) => {
deleteItem(e, element);
}}
>
<i class="el-icon-delete" />
</span>
</div>
);
};
export default {
name: "dynamicTableItem",
props: ["item", "activeItem"],
data() {
return {
isActive: false,
isHover: false,
};
},
components: {
draggable,
render,
},
methods: {
handlerCopy(evt) {
this.$emit("copy", evt, this.item);
},
handlerDelete(evt) {
this.$emit("delete", evt, this.item);
},
},
watch: {
activeItem(newvalue) {
this.isActive = newvalue.id === this.item.id ? true : false;
},
},
computed: {
showbutton() {
return this.isActive || this.isHover;
},
},
render: function (h) {
return colItem.call(this, h, this.item);
},
};
</script>
<style lang="less" scoped>
@lighterBlue: #409eff;
.active {
background: #e6f2ff;
}
.dynamic-table-item-copy {
position: absolute;
width: 22px;
height: 22px;
top: 0px;
right: 30px;
border: 1px solid;
border-radius: 50%;
cursor: pointer;
font-size: 12px;
line-height: 22px;
text-align: center;
color: @lighterBlue;
background: #fff;
z-index: 2;
}
.dynamic-table-item-copy:hover {
color: #fff;
background: @lighterBlue;
}
.dynamic-table-item-delete {
position: absolute;
width: 22px;
height: 22px;
top: 0px;
right: 0px;
border: 1px solid;
border-radius: 50%;
cursor: pointer;
font-size: 12px;
line-height: 22px;
text-align: center;
color: #f56c6c;
background: #fff;
z-index: 2;
}
.dynamic-table-item-delete:hover {
color: #fff;
background: #f56c6c;
}
</style>
<!--操作区域,删除和复制,新增、序号,集成在一个文件中-->
<template>
<div class="dynamic-table__item_opt" style="width: 100%;" >
<div class="dynamic-table__item_title">
操作
</div>
<div class="dynamic-table__item_body" style="text-align:center">
<i class="el-icon-document-copy" style="margin:2px"></i>
<i class="el-icon-delete" style="margin:2px"></i>
</div>
</div>
</template>
<script>
export default {
name:'dynamicTableOptButton',
props:['type'],
data(){
return{
}
}
}
</script>
<style scoped>
.dynamic-table__item_opt{
padding-top:5px;
}
</style>
<!--动态表单(设计器)-->
<template>
<div class="fancyDynamicTable">
<el-table
:data="tableData"
:fit="true"
border
:ref="conf.id"
size="mini"
:cell-style="{ padding: '5px 0' }"
:header-cell-style="{ background: '#F5F7FA' }"
style="width: 100%"
:row-class-name="tableRowClassName"
@selection-change="handlerSelectionChange"
:show-summary="conf['show-summary']"
:summary-method="sumTotal"
>
<el-table-column
align="center"
type="selection"
width="35px"
v-if="conf.multiCheck"
fixed="left"
/>
<el-table-column
align="center"
type="index"
label="序号"
width="50px"
v-if="conf.showIndex"
fixed="left"
/>
<el-table-column
align="center"
:prop="item.id"
v-for="(item, index) in conf.columns"
:key="index"
>
<template slot="header">
{{ tableColumnLabels[index] }}
</template>
<template slot-scope="scope">
<slot name="item" :rowScope="scope" :item="item"></slot>
</template>
</el-table-column>
<el-table-column
align="center"
label="操作"
width="100px"
v-if="conf.buttonDel"
fixed="right"
>
<template slot-scope="scope">
<el-form-item label-width="0px" style="margin: 10px 3px 15px 3px">
<i
class="el-icon-delete optIcon"
style=""
@click="handlerDelete(scope, conf)"
></i>
</el-form-item>
</template>
</el-table-column>
</el-table>
<div class="column-buttons">
<i
class="el-icon-circle-plus-outline optIcon button-plus"
v-if="conf.buttonAdd"
@click="handlerAdd(conf)"
/>
<i
class="el-icon-remove-outline optIcon button-plus"
v-if="BachDeleteButtonShow(conf.id)"
@click="handlerBachDelete"
/>
</div>
</div>
</template>
<script>
export default {
name: "fancyDynamicTable",
props: ["data", "conf"],
data() {
return {
tableData: this.data,
tableColumns: [],
tableColumnLabels: [],
multipleSelection: [],
componentsMount: false,
};
},
mounted() {
this.conf.columns.forEach((element) => {
this.tableColumnLabels.push(element.label);
let tableCol = {};
Object.assign(tableCol, element);
this.tableColumns.push(tableCol);
});
this.componentsMount = true;
},
components: {},
methods: {
handlerAdd(origin) {
this.$emit("addRow", origin);
},
handlerDelete(scope, element) {
this.$emit("deleteRow", scope, element);
},
handlerBachDelete() {
this.$confirm("确认删除选中的数据?").then(() => {
const indexs = [];
this.multipleSelection.forEach((item) => indexs.push(item.index));
this.$emit("batchDeleteRow", indexs, this.conf);
});
},
handlerSelectionChange(val) {
this.multipleSelection = val;
},
tableRowClassName(row) {
row.row.index = row.rowIndex;
},
sumTotal(param) {
const { columns, data } = param;
const sums = [];
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = this.conf["sum-text"];
return;
}
const values = data.map((item) => Number(item[column.property]));
if (!values.every((value) => isNaN(value))) {
sums[index] = values.reduce((prev, curr) => {
const value = Number(curr);
if (!isNaN(value)) {
return prev + curr;
} else {
return prev;
}
}, 0);
sums[index] += " " + this.conf["summary-text"];
} else {
sums[index] = "";
}
});
return sums;
},
},
computed: {
BachDeleteButtonShow() {
return function (id) {
if (this.componentsMount) {
return this.conf.multiCheck && this.$refs[id].selection.length > 0;
}
};
},
},
};
</script>
<style scoped>
.fancyDynamicTable {
width: 100%;
padding: 10px;
}
.column-buttons {
padding: 5px 0 5px 0;
text-align: center;
background-color: #f6f6f6;
}
.optIcon {
font-size: 18px;
margin-right: 5px;
cursor: pointer;
}
.button-plus {
font-size: 30px;
margin-right: 10px;
}
.button-plus:hover {
color: #000000;
}
</style>
\ No newline at end of file
<script>
import render from "../custom/previewRender";
import checkRules from "../custom/rule";
const layouts = {
colItem(element, value, parent, index) {
const { valChange } = this.$listeners;
let rules = [];
if (element && element.rules) {
rules = rules.concat(checkRules(element));
return (
<el-form-item
label={""}
label-width={"0px"}
prop={parent.id + "." + index + "." + element.id}
rules={rules}
>
<render
key={element.id}
conf={element}
value={value}
onInput={(event) => {
this.eleValue = event;
valChange(
this.eleParent.id,
this.index,
element.id,
this.eleValue
);
}}
/>
{element.required ? <span style="color:#F56C6C">*</span> : ""}
</el-form-item>
);
}
},
};
export default {
name: "fancyDynamicTableItem",
components: {
render,
},
props: ["model", "value", "parent", "index"],
mounted() {
let __eleConfig = {};
Object.assign(__eleConfig, this.model);
this.eleConfig = __eleConfig;
},
data() {
return {
eleConfig: {},
eleParent: this.parent,
eleValue: this.value,
};
},
render() {
return layouts.colItem.call(
this,
this.eleConfig,
this.eleValue,
this.eleParent,
this.index
);
},
watch: {
value(newVal) {
this.eleValue = newVal;
},
},
};
</script>
\ No newline at end of file
<script>
import render from "../custom/viewRender";
const layouts = {
colItem(h, element, value) {
element.disabled = true;
// let labelWidth = element.labelWidth ? `${element.labelWidth}px` : null
if (element.viewType === "component") {
return (
<render
key={element.id}
conf={element}
value={value}
onInput={(event) => {
this.$set(element, "value", event);
}}
/>
);
} else if (element.viewType === "html") {
return <fancy-html text={value} />;
} else {
return <fancy-text text={value} align="center" />;
}
},
};
export default {
name: "fancyDynamicTableViewItem",
components: {
render,
},
props: ["model", "value"],
data() {
return {
eleConfig: this.model,
};
},
render(h) {
return layouts.colItem.call(this, h, this.eleConfig, this.value);
},
};
</script>
<style>
/* .el-form-item__label{
font-weight: 600;
} */
</style>
\ No newline at end of file
<!--动态表单(设计器)-->
<template>
<div class="fancyDynamicTable">
<el-table
:data="data"
:fit="true"
border
size="mini"
:cell-style="{padding:'5px 0'}"
:header-cell-style="{background:'#F5F7FA'}"
:show-summary="conf['show-summary']"
:summary-method="sumTotal"
style="width: 100%">
<el-table-column align="center" type="index" label="序号" width="50px" v-if="conf.showIndex" fixed="left"/>
<el-table-column align="center" :prop="item.id" v-for="(item,index) in conf.columns" :key="index" min-width="150px;">
<template slot="header">
{{tableColumnLables[index]}}
</template>
<template slot-scope="scope">
<slot name="item" :rowScope="scope" :item="item"></slot>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name:'fancyDynamicViewTable',
props:['data','conf'],
data(){
return {
tableColumns:[],
tableColumnLables:[]
}
},
mounted(){
this.conf.columns.forEach(element =>{
this.tableColumnLables.push(element.label);
let tableCol = {};
Object.assign(tableCol,element);
this.tableColumns.push(tableCol);
});
},
methods:{
sumTotal(param){
const { columns, data } = param;
const sums = [];
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = this.conf['sum-text'];
return;
}
const values = data.map(item => Number(item[column.property]));
if (!values.every(value => isNaN(value))) {
sums[index] = values.reduce((prev, curr) => {
const value = Number(curr);
if (!isNaN(value)) {
return prev + curr;
} else {
return prev;
}
}, 0);
sums[index] += ' '+this.conf['summary-text'];
} else {
sums[index] = '';
}
});
return sums;
}
}
}
</script>
<style scoped>
.fancyDynamicTable{
widows: 100%;
padding:10px;
}
.column-buttons{
margin-top:15px;
text-align: center;
}
.optIcon{
font-size:18px;
margin-right:5px;
cursor: pointer;
}
</style>
\ No newline at end of file
<!--文本扩展-->
<template>
<div class="dialog-list">
<el-input v-model="dialogValue" readonly @click.native="handlerShowDialog" :disabled="disabled" style="width:95%" suffix-icon="el-icon-search"></el-input>
<el-dialog
:visible.sync="dialogVisible"
:title="title"
width="60%"
center
:append-to-body="true"
:show-close="true"
:lock-scroll="true"
@open="show()"
:destroy-on-close="true"
top="15px"
>
<!--搜索暂不启用-->
<!-- <div class="search-text" v-show="searchable">
<el-input v-model="searchText" placeholder="请输入筛选内容" size="mini" suffix-icon="el-icon-search" clearable style="width:30%"></el-input>
</div> -->
<el-table
ref="dataTable"
:data="filterGridData"
border
:row-class-name="tableRowClassName"
:row-style="{height: '10px'}"
:cell-style="{padding: '5px 0'}"
:header-cell-style="{
'background-color': '#fafafa',
'border-bottom': '1px #e6f7ff solid'
}"
:highlight-current-row="!multi"
:max-height="height"
@row-dblclick="handlerRowDoubleClick"
@current-change="handleCurrentChange"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" v-if="multi"></el-table-column>
<el-table-column type="index" v-if="showIndex" align="center"></el-table-column>
<el-table-column :property="item.property" :label="item.label" :width="item.width" align="center" :key="index" v-for="(item,index) in jsonColConf"/>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="handlerSelect">确 定</el-button>
<el-button @click="handlerHideDialog">取 消</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
const splitKey = ";";
export default {
name:"fancyDialogList",
props:{
value: {
type: String,
default:''
},
title:{
type:String,
default:'请选择'
},
multi:{
type:Boolean,
default:false
},
disabled:{
type:Boolean,
default:false
},
showIndex:{ //显示序号
type:Boolean,
default:false
},
action:{
type:String,
default:''
},
height:{
type:Number,
default:600
},
colConf:{
type:String,
default:''
},
dval:{
type:String,
default:'id'
},
dlabel:{
type:String,
default:'name'
}
},
data() {
return {
currentRow: null,
dialogValue:'',
dialogVisible:false,
gridData: []
}
},
mounted(){
this.$nextTick(() => {
this.$axios.get(this.action).then(res => {
this.gridData = [];
this.gridData = this.gridData.concat(res.data.list);
if(this.value !=='' && this.dialogValue ===''){
if(this.multi){
const ids = this.value.split(splitKey);
this.currentRow = [];
ids.forEach(e=>{
const index = this.gridData.findIndex(element=>(element[this.dval]+"") == e);
if(index>0){
const row = this.gridData[index];
this.currentRow.push(row);
}
})
this.dialogValue = this.selectName;
}else{
const index = this.gridData.findIndex(element=>element[this.dval] == this.value);
if(index>0){
const row = this.gridData[index];
this.dialogValue = row[this.dlabel];
}
}
}
})
})
},
methods:{
handlerShowDialog(){
if(this.disabled) return;
this.dialogVisible = true;
},
handleClose(){
},
tableRowClassName(v){
if(v.rowIndex%2 ==1){
return 'odd-row';
}
return '';
},
handleCurrentChange(val) {
if(!this.multi){
this.currentRow = val;
}
},
handlerRowDoubleClick(val){
if(!this.multi){
this.currentRow = val;
this.handlerSelect();
}
},
handleSelectionChange(val){
this.currentRow = val;
},
handlerSelect(){
this.dialogVisible = false;
let dialogVal = '';
let dialogId = '';
dialogVal = this.selectName;
dialogId = this.selectId;
this.dialogValue = dialogVal;
this.$emit('input',dialogId+'');
},
handlerHideDialog(){
this.dialogVisible = false;
this.dialogValue = '';
this.$emit('input','');
},
setDialogValue(){
if(this.multi){
const ids = this.value.split(splitKey);
this.currentRow = [];
ids.forEach(e=>{
const index = this.gridData.findIndex(element=>element[this.dval] == e);
if(index>0){
const row = this.gridData[index];
this.$refs.dataTable.toggleRowSelection(row);
}
})
}else{
const index = this.gridData.findIndex(element=>element[this.dval] == this.value);
const row = this.gridData[index];
this.$refs.dataTable.setCurrentRow(row);
}
},
show(){
this.$nextTick(() => {
this.setDialogValue();
})
}
},
computed:{
jsonColConf(){
return JSON.parse(this.colConf);
},
selectName(){
if(this.currentRow == null){
return '';
}
if(this.multi){
let names = '';
this.currentRow.forEach(element=>{
names = names+splitKey+element[this.dlabel];
})
if(names.length>0){
names = names.substring(1);
}
return names;
}else{
return this.currentRow[this.dlabel];
}
},
selectId(){
if(this.currentRow == null){
return '';
}
if(this.multi){
let ids = '';
this.currentRow.forEach(element=>{
ids = ids+splitKey+element[this.dval];
})
if(ids.length>0){
ids = ids.substring(1);
}
return ids;
}else{
return this.currentRow[this.dval];
}
},
filterGridData(){
return this.gridData;
}
}
}
</script>
<style scoped>
/**#e6f7ff; */
.dialog-list >>>.el-table--enable-row-hover .el-table__body tr:hover>td{
background-color: #d1dfd5
}
.search-text{
margin-bottom: 10px;
}
</style>
<style>
.el-table .odd-row {
background-color:#FAFAFA;
}
</style>
\ No newline at end of file
<template>
<div class="edit_container" :class="{ warn_edit_container: warnTextLength }">
<quill-editor
v-model="content"
ref="myQuillEditor"
:options="editorOption"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@change="onEditorChange($event)"
>
</quill-editor>
<div
class="text_number_tips"
:class="{ warn_text_number_tips: warnTextLength }"
>
{{ currentLength }}/{{ maxTextLength }}
</div>
</div>
</template>
<script>
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
import { quillEditor } from "vue-quill-editor";
export default {
components: {
quillEditor,
},
props: {
value: {
type: String,
default: "",
},
max: {
type: Number,
default: 0,
},
validateMaxText: {
type: Boolean,
default: false,
},
id: {
type: String,
default: "",
},
},
data() {
return {
content: this.value,
currentLength: 0,
defaultMaxLength: 2000,
editorOption: {},
};
},
methods: {
onEditorBlur(editor) {
return editor;
}, // 失去焦点事件
onEditorFocus(v) {
return v;
}, // 获得焦点事件
onEditorChange(v) {
this.currentLength = v.text.length - 1;
this.$emit("input", this.content);
}, // 内容改变事件
},
computed: {
editor() {
return this.$refs.myQuillEditor.quill;
},
maxTextLength() {
let len = this.defaultMaxLength;
if (this.max >= 1) {
len = this.max;
}
return len;
},
warnTextLength() {
const warn =
this.validateMaxText && this.currentLength > this.maxTextLength;
return warn;
},
},
watch: {
value(newVal) {
this.content = newVal;
},
},
};
</script>
<style>
.ql-editor {
height: 400px;
}
.edit_container .text_number_tips {
float: right;
margin-top: -30px;
padding-right: 10px;
}
.warn_edit_container {
border: solid 1px #f56c6c;
}
.warn_text_number_tips {
color: #f56c6c;
}
</style>
\ No newline at end of file
<!--废弃-->
<!--文本扩展-->
<template>
<div v-if="show">
<p v-html="text"/>
</div>
</template>
<script>
export default {
name:"fancyHtml",
props:{
text: {
type: String,
default:''
},
show:{
type:Boolean,
default:true
}
}
}
</script>
<!--文本扩展-->
<template>
<div v-show="show" class="test">
<p v-html="text" style="margin-block-start:0em;margin-block-end:0em;"
:style="{'text-align':align,
'color':color,
'font-size':size+'px',
'font-weight':bold
}"/>
</div>
</template>
<script>
export default {
name:"fancyText",
props:{
text: {
type: String,
default:''
},
show:{
type:Boolean,
default:true
},
align:{
type:String,
default:'left'
},
color:{
type:String,
default:''
},
size:{
type:Number,
default:14,
},
bold:{
type:Number,
default:400,
}
},
data(){
return {
htmlText:''
}
}
}
</script>
<style>
</style>
<template>
<div>
<el-row :gutter="formConf.gutter" class="form-builder">
<el-form
:rules="rules"
:ref="formConf.formModel"
:size="formConf.size"
:model="buildData.form"
:label-position="formConf.labelPosition"
:disabled="formConf.disabled"
:validate-on-rule-change="false"
:label-width="formConf.labelWidth + 'px'"
>
<template v-for="(element, index) in itemList">
<preview-row-item
v-if="element.compType === 'row'"
:key="'row-' + index"
:model="element"
>
<el-col
v-for="column in element.columns"
:key="column.index"
:span="column.span"
>
<template v-for="(col, i) in column.list">
<preview-item
v-if="col.compType !== 'dynamicTable'"
:key="col.id"
:model="col"
v-model="buildData.form[col.id]"
@valChange="handlerValChange"
/>
<fancy-dynamic-table
v-else-if="col.compType === 'dynamicTable'"
ref="dynamicTable"
:key="'dynamic-' + i"
:data="form[col.id]"
:conf="col"
@addRow="handlerAddRow"
@deleteRow="handlerDeleteRow"
>
<template v-slot:item="{ rowScope, item }">
<fancy-dynamic-table-item
:model="item"
:parent="col"
:key="'tableIndex-' + rowScope.$index"
:index="rowScope.$index"
v-model="rowScope.row[item.id]"
@valChange="handlerDynamicValChange"
/>
</template>
</fancy-dynamic-table>
</template>
</el-col>
</preview-row-item>
<fancy-dynamic-table
v-else-if="element.compType === 'dynamicTable'"
:key="'dynamic-' + index"
:data="buildData.form[element.id]"
:ref="element.id"
:conf="element"
@addRow="handlerAddRow"
@deleteRow="handlerDeleteRow"
>
<template v-slot:item="{ rowScope, item }">
<fancy-dynamic-table-item
:model="item"
:ref="item.id + rowScope.$index"
:parent="element"
:key="'tableIndex-' + rowScope.$index"
:index="rowScope.$index"
v-model="rowScope.row[item.id]"
@valChange="handlerDynamicValChange"
/>
</template>
</fancy-dynamic-table>
<fancy-edit-table
v-else-if="element.compType === 'table'"
:key="'table_' + index"
:layoutArray="element.layoutArray"
:tdStyle="element.tdStyle"
:width="element.width"
:height="element.height"
>
<template v-slot="{ td }">
<template v-for="col in td.columns">
<preview-item
v-if="col.compType !== 'dynamicTable'"
:key="col.id"
:model="col"
v-model="buildData.form[col.id]"
@valChange="handlerValChange"
/>
</template>
</template>
</fancy-edit-table>
<!--item-->
<el-col
class="drag-col-wrapper"
:key="index"
:span="element.span"
v-else
>
<preview-item
:model="element"
v-model="buildData.form[element.id]"
@valChange="handlerValChange"
/>
</el-col>
</template>
</el-form>
</el-row>
</div>
</template>
<script>
import previewItem from "./previewItem";
import previewRowItem from "./previewRowItem";
import fancyDynamicTable from "./dynamic/fancyDynamicTable";
import fancyDynamicTableItem from "./dynamic/fancyDynamicTableItem";
import { datas, addRow, deleteRow, fillDatas } from "./custom/formDraw";
import fancyEditTable from "./table/fancyEditTable";
export default {
name: "formBuilder",
props: {
value: {
type: String,
default: "",
},
buildData: {
type: Object,
default: () => {
return {};
},
},
disabled: {
type: Boolean,
default: false,
},
},
components: {
previewItem,
previewRowItem,
fancyDynamicTable,
fancyDynamicTableItem,
fancyEditTable,
},
data() {
return {
form: {},
rules: {},
currentIndex: -1,
};
},
mounted() {
this.$nextTick(() => {
if (this.value !== "") {
const jsonValue = JSON.parse(this.value);
this.handlerFillDatas(jsonValue);
}
});
},
methods: {
handlerValChange(key, origin) {
this.$set(this.buildData.form, key, origin);
},
handlerDynamicValChange(parentId, index, key, origin) {
this.$set(this.buildData.form[parentId][index], key, origin);
this.currentIndex = index;
},
validate() {
let bool;
this.$refs[this.formConf.formModel].validate((valid) => {
bool = valid;
});
return bool;
},
handlerAddRow: addRow,
handlerDeleteRow: deleteRow,
handlerInitDatas: datas,
handlerFillDatas: fillDatas,
},
created() {
console.log(this.buildData);
this.handlerInitDatas();
},
computed: {
itemList() {
return this.buildData.formContent.list;
// if (this.buildData !== "") {
// const buildData = JSON.parse(this.buildData);
// return buildData.list;
// } else {
// return [];
// }
},
formConf() {
return this.buildData.formContent.config;
// if (this.buildData !== "") {
// const buildData = JSON.parse(this.buildData);
// buildData.config.disabled = this.disabled;
// return buildData.config;
// } else {
// return {};
// }
},
},
};
</script>
<style lang="less" scoped>
// /deep/.el-form-item__label {
// font-size: 22px;
// font-family: Source Han Sans CN;
// color: #555555;
// }
// /deep/.el-radio__label {
// font-size: 22px;
// font-family: Source Han Sans CN;
// color: #333333;
// }
// /deep/.el-radio__inner {
// width: 24px;
// height: 24px;
// &::after {
// width: 10px;
// height: 10px;
// }
// }
// /deep/.el-table__cell {
// color: #333333;
// }
// /deep/.el-checkbox__inner {
// width: 24px;
// height: 24px;
// &::after {
// height: 12px;
// width: 6px;
// border-width: 2px;
// left: 7px;
// }
// }
// /deep/.el-input__icon {
// font-size: 22px;
// }
// /deep/.el-checkbox__label {
// font-size: 22px;
// color: #333333;
// }
// /deep/.el-input__inner {
// height: 54px;
// background: #f1f7fd;
// border-radius: 8px;
// font-size: 22px;
// color: #333333;
// }
// /deep/.el-textarea__inner {
// background: #f1f7fd;
// border-radius: 8px;
// font-size: 22px;
// color: #333333;
// }
.preview-board {
border: 1px dashed #ccc;
}
.form-builder {
width: 100%;
}
/deep/.el-date-editor.el-input {
width: 100%;
}
/deep/.el-form-item {
margin-left: 10px;
margin-right: 10px;
margin-bottom: 20px;
}
.form-builder .el-radio.is-bordered + .el-radio.is-bordered {
margin-left: 0px;
}
.form-builder .el-checkbox.is-bordered + .el-checkbox.is-bordered {
margin-left: 0px;
}
</style>
\ No newline at end of file
<template>
<div class="container">
<div class="left-board">
<div class="d-logo-wrapper">
<div class="d-logo">Form designer</div>
</div>
<el-scrollbar class="left-scrollbar">
<!--左侧组件列表-->
<div class="components-list">
<div class="components-title">常用组件</div>
<draggable
class="components-draggable"
:list="formItems"
:group="{ name: 'componentsGroup', pull: 'clone', put: false }"
:clone="cloneComponent"
draggable=".components-item"
:sort="false"
@start="onStart"
@end="onEnd"
>
<div
v-for="(element, index) in formItems"
:key="index"
class="components-item"
@click="addComponent(element)"
>
<div
class="components-body"
:class="{ 'dynamicTable-tips': dynamicTableExist(element) }"
>
<icon :code="element.compIcon" :text="element.compName" />
</div>
</div>
</draggable>
<div class="components-title">布局组件</div>
<draggable
class="components-draggable"
:list="layoutFormItems"
:group="{ name: 'componentsGroup', pull: 'clone', put: false }"
:clone="cloneComponent"
draggable=".components-item"
:sort="false"
@start="onStart"
@end="onEnd"
>
<div
v-for="(element, index) in layoutFormItems"
:key="index"
class="components-item"
@click="addComponent(element)"
>
<div class="components-body">
<icon :code="element.compIcon" :text="element.compName" />
</div>
</div>
</draggable>
<div class="components-title">辅助组件</div>
<draggable
class="components-draggable"
:list="assistFormItems"
:group="{ name: 'componentsGroup', pull: 'clone', put: false }"
:clone="cloneComponent"
draggable=".components-item"
:sort="false"
@start="onStart"
@end="onEnd"
>
<div
v-for="(element, index) in assistFormItems"
:key="index"
class="components-item"
@click="addComponent(element)"
>
<div class="components-body">
<icon :code="element.compIcon" :text="element.compName" />
</div>
</div>
</draggable>
</div>
</el-scrollbar>
</div>
<designer
ref="designer"
:list="designList"
:formConfig="formConfig"
@clear="designList = []"
@updateJSON="handlerUpdateJSON"
:activeData="activeData"
/>
</div>
</template>
<script>
/**
* 1.0版本
*/
import draggable from "vuedraggable";
import { formItems, assistFormItems, layoutFormItems } from "./custom/itemList";
import designer from "./designer";
import icon from "./icon";
import { getSimpleId, setTableId } from "./utils/IdGenerate";
import formConf from "./custom/formConf";
import { dynamicTableAllowedItems } from "./custom/formConf";
let tempActiveData;
export default {
name: "formDesigner",
components: {
draggable,
icon,
designer,
},
data() {
return {
formItems: formItems,
assistFormItems: assistFormItems,
layoutFormItems: layoutFormItems,
designList: [],
activeData: {},
formConfig: formConf,
};
},
props: {
value: {
type: String,
default: "",
},
},
mounted() {},
methods: {
addComponent(element) {
return element;
},
cloneComponent(origin) {
const clone = JSON.parse(JSON.stringify(origin));
if (!clone.layout) clone.layout = "colItem";
if (clone.layout === "colItem" || clone.layout === "dynamicItem") {
let uId = "fd_" + getSimpleId();
clone.id = uId;
clone._id = uId;
tempActiveData = clone;
} else if (clone.layout === "rowItem") {
let uId = "row_" + getSimpleId();
clone.id = uId;
clone._id = uId;
tempActiveData = clone;
} else if (clone.layout === "tableItem") {
let uId = "table_" + getSimpleId();
clone.id = uId;
clone._id = uId;
//增加td默认的id
setTableId(clone);
tempActiveData = clone;
}
this.$refs.designer.activeItem = tempActiveData;
},
onStart(obj) {
return obj;
},
onEnd(obj) {
if (obj.from !== obj.to) {
this.activeData = tempActiveData;
this.$refs.designer.activeItem = this.activeData;
if (obj.to.className.indexOf("row-drag") < 0) {
this.designList.splice(obj.newIndex, 0, this.activeData);
}
} else {
this.$refs.designer.activeItem = {};
}
},
getFormData() {
return this.formData;
},
handlerUpdateJSON(json) {
const jsonObject = JSON.parse(json);
this.designList = [];
this.designList = this.designList.concat(jsonObject.list);
},
},
computed: {
formData: function () {
const list = this.designList;
const config = this.formConfig;
let formData = {};
formData.list = list;
formData.config = config;
console.log(formData);
return JSON.stringify(formData);
//this.$emit('input',JSON.stringify(formData));
},
dynamicTableExist() {
return function (element) {
return (
this.formConfig.dynamicTableAllowed &&
this.designList.filter((item) => item.compType === "dynamicTable")
.length > 0 &&
dynamicTableAllowedItems.includes(element.compType)
);
};
},
},
watch: {
value(newVal) {
if (newVal !== "") {
const formData = JSON.parse(newVal);
this.designList = formData.list;
this.formConfig = formData.config;
}
},
},
};
</script>
<style scoped>
.container {
padding: 0px;
}
.dynamicTable-tips {
border: 1px solid#F08080;
}
</style>
\ No newline at end of file
<script>
import render from "./custom/viewRender";
const layouts = {
colItem(h, element, value) {
element.disabled = true;
let labelWidth = element.labelWidth ? `${element.labelWidth}px` : null;
if (element.viewType === "component") {
return (
<el-form-item
label={element.showLabel ? element.label : ""}
label-width={labelWidth}
prop={element.id}
>
<render
key={element.id}
conf={element}
value={value}
onInput={(event) => {
this.$set(element, "value", event);
}}
/>
</el-form-item>
);
} else if (element.viewType === "html") {
return (
<el-form-item
label={element.showLabel ? element.label : ""}
label-width={labelWidth}
prop={element.id}
>
<fancy-html text={value} />
</el-form-item>
);
} else {
if (typeof value === "object") {
value = value[0] + " " + element["range-separator"] + " " + value[1];
}
return (
<el-form-item
label={element.showLabel ? element.label : ""}
label-width={labelWidth}
prop={element.id}
>
{value}
</el-form-item>
);
}
},
};
export default {
name: "formViewItem",
components: {
render,
},
props: ["model", "value"],
data() {
return {
eleConfig: this.model,
};
},
render(h) {
return layouts.colItem.call(this, h, this.eleConfig, this.value);
},
};
</script>
<style>
/* .el-form-item__label{
font-weight: 600;
} */
/* .el-form-item {
margin-left: 10px;
margin-right: 10px;
margin-bottom: 5px;
} */
</style>
\ No newline at end of file
<!--表单查看页面-->
<template>
<div class="form-viewer">
<el-row :gutter="formConf.gutter">
<el-form
:ref="formConf.formModel"
:size="formConf.size"
:model="form"
:label-position="formConf.labelPosition"
:disabled="formConf.disabled"
>
<template v-for="(element, index) in itemList">
<preview-row-item
v-if="element.compType === 'row'"
:key="'row-' + index"
:model="element"
>
<el-col
v-for="column in element.columns"
:key="column.index"
:span="column.span"
>
<form-view-item
v-for="item in column.list"
:key="item.id"
:model="item"
v-model="form[item.id]"
/>
</el-col>
</preview-row-item>
<fancy-dynamic-view-table
v-else-if="element.compType === 'dynamicTable'"
:key="'dynamic-' + index"
:data="form[element.id]"
:ref="element.id"
:conf="element"
>
<template v-slot:item="{ rowScope, item }">
<fancy-dynamic-table-view-item
:model="item"
:ref="item.id + rowScope.$index"
:parent="element"
:key="'tableIndex-' + rowScope.$index"
:index="rowScope.$index"
v-model="rowScope.row[item.id]"
/>
</template>
</fancy-dynamic-view-table>
<fancy-edit-table
v-else-if="element.compType === 'table'"
:key="'table_type' + index"
:layoutArray="element.layoutArray"
:tdStyle="element.tdStyle"
:width="element.width"
:height="element.height"
>
<template v-slot="{ td }">
<form-view-item
v-for="item in td.columns"
:key="item.id"
:model="item"
v-model="form[item.id]"
/>
</template>
</fancy-edit-table>
<!--item-->
<el-col
class="drag-col-wrapper"
:key="index"
:span="element.span"
v-else
>
<form-view-item :model="element" v-model="form[element.id]" />
</el-col>
</template>
</el-form>
</el-row>
</div>
</template>
<script>
import formViewItem from "./formViewItem";
import previewRowItem from "./previewRowItem";
import fancyDynamicViewTable from "./dynamic/fancyDynamicViewTable";
import fancyDynamicTableViewItem from "./dynamic/fancyDynamicTableViewItem";
import fancyEditTable from "./table/fancyEditTable";
export default {
name: "formViewer",
data() {
return {
// 表单配置
dataForm: {
// 配置
config: {
version: "1.10",
formRef: "elForm",
formModel: "form",
rules: "rules",
size: "medium",
labelPosition: "right",
labelWidth: 80,
formRules: "rules",
gutter: 30,
disabled: false,
dynamicTableAllowed: false,
},
// 组件
list: [
{
id: "table_1664257854891",
_id: "table_1664257854891",
compType: "table",
ele: "fancy-table",
compName: "表格布局",
compIcon: "table_layout",
layout: "tableItem",
config: true,
layoutArray: [
[
{
id: 1664257854901,
col: 1,
row: 1,
hide: false,
compType: "tdItem",
style: {
background: "#F6F6F6",
width: 15,
},
columns: [
{
id: "fd_1664257870473",
_id: "fd_1664257870473",
compType: "text",
ele: "fancy-text",
compName: "文本",
compIcon: "text",
viewType: "component",
config: true,
form: false,
show: true,
text: "姓名",
align: "left",
color: "#000000",
size: 14,
bold: 400,
showLabel: false,
labelWidth: "0",
layout: "colItem",
},
],
},
{
id: 1664257854911,
col: 1,
row: 1,
hide: false,
compType: "tdItem",
style: {
background: "#FFFFFF",
width: 35,
},
columns: [
{
id: "fd_1664257875601",
_id: "fd_1664257875601",
compType: "input",
ele: "el-input",
compName: "单行文本",
compIcon: "input",
viewType: "text",
config: true,
showLabel: false,
label: "单行文本",
labelWidth: 1,
placeholder: "请输入文本",
required: false,
maxLength: 50,
gutter: 15,
span: 24,
width: "100%",
clearable: true,
disabled: false,
readonly: false,
status: "normal",
"prefix-icon": "",
"suffix-icon": "",
value: "65465",
rules: [],
rulesType: "default",
prepend: "",
append: "",
layout: "colItem",
},
],
},
{
id: 1663654709247,
col: 1,
row: 1,
hide: false,
compType: "tdItem",
style: {
background: "#F6F6F6",
width: 15,
},
columns: [
{
id: "fd_1664257907242",
_id: "fd_1664257907242",
compType: "text",
ele: "fancy-text",
compName: "文本",
compIcon: "text",
viewType: "component",
config: true,
form: false,
show: true,
text: "文本",
align: "left",
color: "#000000",
size: 14,
bold: 400,
showLabel: false,
labelWidth: "0",
layout: "colItem",
},
],
},
{
id: 1663654709267,
col: 1,
row: 1,
hide: false,
compType: "tdItem",
style: {
background: "#FFFFFF",
width: 35,
},
columns: [
{
id: "fd_1664257878981",
_id: "fd_1664257878981",
compType: "input",
ele: "el-input",
compName: "单行文本",
compIcon: "input",
viewType: "text",
config: true,
showLabel: false,
label: "单行文本",
labelWidth: 1,
placeholder: "请输入文本",
required: false,
maxLength: 50,
gutter: 15,
span: 24,
width: "100%",
clearable: true,
disabled: false,
readonly: false,
status: "normal",
"prefix-icon": "",
"suffix-icon": "",
value: "而已",
rules: [],
rulesType: "default",
prepend: "",
append: "",
layout: "colItem",
},
],
},
],
[
{
id: 1664257854921,
col: 1,
row: 1,
hide: false,
compType: "tdItem",
style: {
background: "#F6F6F6",
width: 15,
},
columns: [
{
id: "fd_1664257872938",
_id: "fd_1664257872938",
compType: "text",
ele: "fancy-text",
compName: "文本",
compIcon: "text",
viewType: "component",
config: true,
form: false,
show: true,
text: "文本",
align: "left",
color: "#000000",
size: 14,
bold: 400,
showLabel: false,
labelWidth: "0",
layout: "colItem",
},
],
},
{
id: 1664257854931,
col: 1,
row: 1,
hide: false,
compType: "tdItem",
style: {
background: "#FFFFFF",
width: 35,
},
columns: [
{
id: "fd_1664257877363",
_id: "fd_1664257877363",
compType: "input",
ele: "el-input",
compName: "单行文本",
compIcon: "input",
viewType: "text",
config: true,
showLabel: false,
label: "单行文本",
labelWidth: 1,
placeholder: "请输入文本",
required: false,
maxLength: 50,
gutter: 15,
span: 24,
width: "100%",
clearable: true,
disabled: false,
readonly: false,
status: "normal",
"prefix-icon": "",
"suffix-icon": "",
value: "太容易",
rules: [],
rulesType: "default",
prepend: "",
append: "",
layout: "colItem",
},
],
},
{
id: 1663654709327,
col: 1,
row: 1,
hide: false,
compType: "tdItem",
style: {
background: "#F6F6F6",
width: 15,
},
columns: [
{
id: "fd_1664257909094",
_id: "fd_1664257909094",
compType: "text",
ele: "fancy-text",
compName: "文本",
compIcon: "text",
viewType: "component",
config: true,
form: false,
show: true,
text: "文本",
align: "left",
color: "#000000",
size: 14,
bold: 400,
showLabel: false,
labelWidth: "0",
layout: "colItem",
},
],
},
{
id: 1663654709347,
col: 1,
row: 1,
hide: false,
compType: "tdItem",
style: {
background: "#FFFFFF",
width: 35,
},
columns: [
{
id: "fd_1664257880668",
_id: "fd_1664257880668",
compType: "input",
ele: "el-input",
compName: "单行文本",
compIcon: "input",
viewType: "text",
config: true,
showLabel: false,
label: "单行文本",
labelWidth: 1,
placeholder: "请输入文本",
required: false,
maxLength: 50,
gutter: 15,
span: 24,
width: "100%",
clearable: true,
disabled: false,
readonly: false,
status: "normal",
"prefix-icon": "",
"suffix-icon": "",
value: "绕太阳",
rules: [],
rulesType: "default",
prepend: "",
append: "",
layout: "colItem",
},
],
},
],
],
tdStyle: "",
width: 100,
height: 50,
},
],
},
};
},
props: {
value: {
type: String,
default: "",
},
buildData: {
type: String,
default: "",
},
},
components: {
formViewItem,
previewRowItem,
fancyDynamicViewTable,
fancyDynamicTableViewItem,
fancyEditTable,
},
mounted() {
this.$nextTick(() => {});
},
computed: {
itemList() {
if (this.buildData !== "") {
const buildData = JSON.parse(this.buildData);
return buildData.list;
} else {
return [];
}
},
form() {
//转换成json的值
if (this.value !== "") {
const value = JSON.parse(this.value);
return value;
} else {
return {};
}
},
formConf() {
if (this.buildData !== "") {
const buildData = JSON.parse(this.buildData);
buildData.config.disabled = this.disabled;
return buildData.config;
} else {
return {};
}
},
},
};
</script>
<style scoped>
.preview-board {
border: 1px dashed #ccc;
}
/* .form-viewer {
padding: 20px;
border: 1px solid #dcdfe6;
} */
.el-form-item {
margin-left: 10px;
margin-right: 10px;
}
</style>
\ No newline at end of file
/**
* 生成html的核心js函数
*/
let globalConfig
export function vueTemplate(str) {
return `<template>
<div>
${str}
</div>
</template>`
}
export function vueScript(str) {
return `<script>
${str}
</script>`
}
export function cssStyle(cssStr) {
return `<style>
${cssStr}
</style>`
}
const items = {
'input':el =>{
const {
disabled, vModel, clearable, placeholder, width
} = attrBuilder(el)
const maxlength = el.maxlength ? `:maxlength="${el.maxlength}"` : ''
//const showWordLimit = el['show-word-limit'] ? 'show-word-limit' : ''
const readonly = el.readonly ? 'readonly' : ''
return `<${el.ele} ${vModel} ${placeholder} ${maxlength} ${readonly} ${disabled} ${clearable} />`
},
'textarea':el =>{
const {
disabled, vModel, clearable, placeholder, width
} = attrBuilder(el)
const maxlength = el.maxlength ? `:maxlength="${el.maxlength}"` : ''
//const showWordLimit = el['show-word-limit'] ? 'show-word-limit' : ''
const readonly = el.readonly ? 'readonly' : ''
const type = el.type ? `type="${el.type}"` : ''
return `<${el.ele} ${vModel} ${type} ${placeholder} ${maxlength} ${readonly} ${disabled} ${clearable} />`
}
}
function colWrapper(element,str){
if (element.span) {
return `<el-col :span="${element.span}">
${str}
</el-col>`
}
return str
}
function attrBuilder(el) {
return {
vModel: `v-model="${globalConfig.formModel}.${el.id}"`,
clearable: el.clearable ? 'clearable' : '',
placeholder: el.placeholder ? `placeholder="${el.placeholder}"` : '',
//width: el.style && el.style.width ? ':style="{width: \'100%\'}"' : '',
disabled: el.disabled ? ':disabled=\'true\'' : ''
}
}
const layout = {
colFormItem(element) {
let labelWidth = `label-width="${globalConfig.labelWidth}px"`
let label = `label="${element.label}"`
if (element.labelWidth && element.labelWidth !== globalConfig.labelWidth) {
labelWidth = `label-width="${element.labelWidth}px"`
}
if (element.showLabel === false) {
labelWidth = 'label-width="0"'
label = ''
}
const required = element.required ? 'required' : ''
const itemDom = items[element.compType] ? items[element.compType](element) : null
let str = `<el-form-item ${labelWidth} ${label} ${required}>
${itemDom}
</el-form-item>`
str = colWrapper(element,str);
return str;
}
}
/**
* 生成html源码
* 表单配置和组件列表
*/
export function buildHtmlSource(itemList,formConf){
globalConfig = formConf;
const htmlCode = []
itemList.forEach(el => {
htmlCode.push(layout['colFormItem'](el))
})
const htmlStr = htmlCode.join('\n')
//console.log(htmlStr)
}
\ No newline at end of file
/**
* 生成js的核心js函数
*/
let globalConfig
export function buildJsSource(itemList,formConf){
globalConfig = JSON.parse(JSON.stringify(formConf))
const dataList = []
const optionsList = []
const propsList = []
itemList.forEach(el =>{
buildAttributes(el, dataList, optionsList, propsList)
})
const script = buildexport(
formConf,
dataList.join('\n'),
optionsList.join('\n'),
propsList.join('\n'),
)
globalConfig = null;
console.log(script);
return script;
}
function buildAttributes(el, dataList, optionsList, propsList) {
buildData(el, dataList)
if (el.options && el.options.length) {
buildOptions(el, optionsList)
}
if (el.props && el.props.props) {
buildProps(el, propsList)
}
// if (el.children) {
// el.children.forEach(el2 => {
// buildAttributes(el2, dataList, ruleList, optionsList, methodList, propsList, uploadVarList)
// })
// }
}
function buildData(conf, dataList) {
let value
if (typeof (conf.value) === 'string' && !conf.multiple) {
value = `'${conf.value}'`
} else {
value = `${JSON.stringify(conf.value)}`
}
if(typeof(value) === 'undefined'||value === 'undefined') value = `''`;
console.log(value);
dataList.push(`${conf.id}: ${value},`)
}
function buildOptions(conf, optionsList) {
const str = `${conf.id}Options: ${JSON.stringify(conf.options)},`
optionsList.push(str)
}
function buildProps(conf, propsList) {
const str = `${conf.id}Props: ${JSON.stringify(conf.props.props)},`
propsList.push(str)
}
function buildexport(conf, data, props) {
const str = `export default {
components: {},
props: [],
data () {
return {
${conf.formModel}: {
${data}
}
}
},
computed: {},
watch: {},
created () {},
mounted () {},
}`
return str
}
\ No newline at end of file
<template>
<div class="text">
<svg class="icon" aria-hidden="true">
<use :xlink:href="iconFont"></use>
</svg>
{{text}}
</div>
</template>
<script>
export default {
name:'icon',
props:['code','text'],
computed: {
iconFont(){
return '#icon-'+this.code;
}
}
}
</script>
<style scoped>
.icon{
width:20px;
height:20px;
vertical-align:-5px;
}
</style>
\ No newline at end of file
<!--elementUI 图标选择器-->
<template>
<div>
<el-dialog
title="选择icon"
width="60%"
top="0vh"
:visible.sync="dialogVisible"
>
<ul class="icon-list">
<li
v-for="iconName in icons"
:key="iconName"
@click="handlerSelectIcon(iconName)"
:class="{ activeIcon: iconName === value }"
>
<i :class="iconName"></i>
<!-- <div class="icon-name">{{iconName}}</div> -->
</li>
</ul>
</el-dialog>
</div>
</template>
<script>
import iconList from "./utils/icon.json";
export default {
props: {
visible: {
type: Boolean,
default: true,
},
value: {
type: String,
default: "",
},
},
data() {
return {
icons: iconList,
};
},
methods: {
handlerSelectIcon(iconName) {
this.$emit("input", iconName);
this.$emit("update:visible", false);
},
},
computed: {
dialogVisible: {
// getter
get: function () {
return this.visible;
},
// setter
set: function (newValue) {
console.log(newValue);
this.$emit("update:visible", false);
},
},
},
};
</script>
<style scoped>
.icon-list {
padding: 0;
margin: 0;
font-size: 0;
}
.icon-list li {
width: 10%;
height: 60px;
font-size: 14px;
text-align: center;
list-style-type: none;
overflow: hidden;
padding: 15px 6px 6px 0px;
display: inline-block;
box-sizing: border-box;
}
.icon-list li:hover {
background-color: #f2f6fc;
cursor: pointer;
}
.activeIcon {
background-color: #f2f6fc;
cursor: pointer;
}
.icon-list li i {
width: 100%;
font-size: 30px;
padding: 6px 6px 6px 0px;
}
.icon-name {
display: block;
padding-left: 6px;
}
.el-dialog {
border-radius: 8px;
margin-bottom: 0;
margin-top: 4vh !important;
display: flex;
flex-direction: column;
max-height: 92vh;
overflow: hidden;
box-sizing: border-box;
}
.el-dialog .el-dialog__header {
padding-top: 14px;
}
.el-dialog .el-dialog__body {
margin: 0 20px 20px 20px;
padding: 0;
overflow: auto;
}
</style>
\ No newline at end of file
import formDesigner from './formDesigner';
import fancyEditor from './extend/fancyEditor';
import fancyHtml from './extend/fancyHtml';
import fancyText from './extend/fancyText';
import fancyBarCode from 'vue-barcode';
import fancyDialogList from './extend/fancyDialogList';
import iconDialog from './iconDialog';
const plugins = {
install : function (Vue) {
Vue.component('form-designer',formDesigner);
Vue.component('fancy-editor',fancyEditor);
Vue.component('fancy-html',fancyHtml);
Vue.component('fancy-text',fancyText);
Vue.component('fancy-bar-code',fancyBarCode);
Vue.component('fancy-dialog-list',fancyDialogList);
Vue.component('icon-dialog',iconDialog);
}
};
// 这一步判断window.Vue是否存在,因为直接引用vue.min.js, 它会把Vue绑到Window上,我们直接引用打包好的js才能正常跑起来。
if (typeof window !== 'undefined' && window.Vue) {
window.Vue.use(plugins);
}
export default plugins;
\ No newline at end of file
<template>
<div class="preview">
<el-row :gutter="formConf.gutter">
<el-form
:rules="rules"
:ref="formConf.formModel"
:size="formConf.size"
:model="form"
:label-position="formConf.labelPosition"
:disabled="formConf.disabled"
:validate-on-rule-change="false"
:label-width="formConf.labelWidth + 'px'"
>
<template v-for="(element, index) in list">
<!-- <el-input v-model="element.id" placeholder=""></el-input> -->
<preview-row-item
v-if="element.compType === 'row'"
:key="'row-' + index"
:model="element"
>
<el-col
v-for="column in element.columns"
:key="column.index"
:span="column.span"
>
<template v-for="col in column.list">
<preview-item
v-if="col.compType !== 'dynamicTable'"
:key="col.id"
:model="col"
v-model="form[col.id]"
@valChange="handlerValChange"
/>
<fancy-dynamic-table
v-else-if="col.compType === 'dynamicTable'"
ref="dynamicTable"
:key="'dynamic-' + col.id"
:data="form[col.id]"
:conf="col"
@addRow="handlerAddRow"
@deleteRow="handlerDeleteRow"
@batchDeleteRow="handlerBatchDeleteRow"
>
<template v-slot:item="{ rowScope, item }">
<fancy-dynamic-table-item
:model="item"
:parent="col"
:key="'tableIndex-' + rowScope.$index"
:index="rowScope.$index"
v-model="rowScope.row[item.id]"
@valChange="handlerDynamicValChange"
/>
</template>
</fancy-dynamic-table>
</template>
</el-col>
</preview-row-item>
<fancy-dynamic-table
v-else-if="element.compType === 'dynamicTable'"
:key="'dynamic-' + index"
:data="form[element.id]"
:ref="element.id"
:conf="element"
@addRow="handlerAddRow"
@deleteRow="handlerDeleteRow"
@batchDeleteRow="handlerBatchDeleteRow"
>
<template v-slot:item="{ rowScope, item }">
<fancy-dynamic-table-item
:model="item"
:ref="item.id + rowScope.$index"
:parent="element"
:key="'tableIndex-' + rowScope.$index"
:index="rowScope.$index"
v-model="rowScope.row[item.id]"
@valChange="handlerDynamicValChange"
/>
</template>
</fancy-dynamic-table>
<fancy-edit-table
v-else-if="element.compType === 'table'"
:key="'table_1' + index"
:layoutArray="element.layoutArray"
:tdStyle="element.tdStyle"
:width="element.width"
:height="element.height"
>
<template v-slot="{ td }">
<template v-for="col in td.columns">
<preview-item
:model="col"
:key="'table_2' + col.id"
v-model="form[col.id]"
@valChange="handlerValChange"
/>
</template>
</template>
</fancy-edit-table>
<!--item-->
<el-col
class="drag-col-wrapper"
:key="index"
:span="element.span"
v-else
>
<preview-item
:model="element"
v-model="form[element.id]"
@valChange="handlerValChange"
/>
</el-col>
</template>
</el-form>
</el-row>
<el-divider></el-divider>
<div style="text-align: center">
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="handlerSubForm">提交</el-button>
</span>
</div>
</div>
</template>
<script>
import previewItem from "./previewItem";
import previewRowItem from "./previewRowItem";
import fancyDynamicTable from "./dynamic/fancyDynamicTable";
import fancyDynamicTableItem from "./dynamic/fancyDynamicTableItem";
import fancyEditTable from "./table/fancyEditTable";
import { datas, addRow, batchDeleteRow, deleteRow } from "./custom/formDraw";
export default {
name: "preview",
props: ["itemList", "formConf"],
components: {
previewItem,
previewRowItem,
fancyDynamicTable,
fancyDynamicTableItem,
fancyEditTable,
},
data() {
return {
list: this.itemList,
form: {},
rules: {},
currentIndex: -1,
};
},
methods: {
handlerValChange(key, origin) {
console.log(key);
this.$set(this.form, key, origin);
},
handlerDynamicValChange(parentId, index, key, origin) {
this.$set(this.form[parentId][index], key, origin);
this.currentIndex = index;
},
handlerSubForm() {
this.$refs[this.formConf.formModel].validate((valid) => {
if (valid) {
this.$message.success("success");
}
});
},
handlerAddRow: addRow,
handlerDeleteRow: deleteRow,
handlerBatchDeleteRow: batchDeleteRow,
handlerInitDatas: datas,
},
created() {
this.handlerInitDatas(); //初始化表单
},
mounted() {
this.$nextTick(() => {});
},
beforeCreate() {},
computed: {},
};
</script>
<style scoped>
.preview-board {
border: 1px dashed #ccc;
}
.preview >>> .el-radio.is-bordered + .el-radio.is-bordered {
margin-left: 0px;
}
.preview >>> .el-checkbox.is-bordered + .el-checkbox.is-bordered {
margin-left: 0px;
}
</style>
\ No newline at end of file
<script>
import render from "./custom/previewRender";
import checkRules from "./custom/rule";
const layouts = {
colItem(h, element, value) {
let labelWidth = element.labelWidth ? `${element.labelWidth}px` : null;
const { valChange } = this.$listeners;
const rules = checkRules(element);
return (
<el-col style="padding-left: 7.5px; padding-right: 7.5px;">
<el-form-item
label={element.showLabel ? element.label : ""}
label-width={labelWidth}
prop={element.id}
rules={rules}
>
<render
key={element.id}
conf={element}
value={value}
onInput={(event) => {
this.$set(element, "value", event);
valChange(element.id, event);
}}
/>
</el-form-item>
</el-col>
);
},
};
export default {
name: "previewItem",
components: {
render,
},
props: ["model", "value"],
data() {
return {
eleConfig: this.model,
};
},
render(h) {
return layouts.colItem.call(this, h, this.eleConfig, this.value);
},
};
</script>
<style scoped>
/* .el-form-item {
margin-left: 10px;
margin-right: 10px;
margin-bottom: 5px;
} */
</style>
\ No newline at end of file
<template>
<el-col>
<el-row :gutter="model.gutter">
<div class="drag-wrapper">
<slot></slot>
</div>
</el-row>
</el-col>
</template>
<script>
export default {
name: "previewRowItem",
components: {},
props: ["model", "value"],
data() {
return {};
},
computed: {},
};
</script>
\ No newline at end of file
body{
margin:0px;
}
.container {
position: relative;
width: 100%;
height: 100%;
}
.left-board {
width: 260px;
position: absolute;
left: 0;
top: 0;
height: 100vh;
}
.d-logo-wrapper{
position: relative;
height: 42px;
background: #ffffff;
border-bottom: 1px solid #f1e8e8;
box-sizing: border-box;
}
.d-logo{
position: absolute;
left: 12px;
top: 6px;
line-height: 30px;
color: #409eff;
font-weight: 600;
font-size: 17px;
white-space: nowrap;
}
.d-logo img{
width: 30px;
height: 30px;
vertical-align: top;
}
.components-title{
font-size: 14px;
color: #222;
margin: 6px 6px;
font-weight:700
}
.components-draggable{
padding-bottom: 20px;
}
.components-list {
padding: 8px;
box-sizing: border-box;
height: 100%;
}
.components-list .components-item {
display: inline-block;
width: 48%;
margin: 1%;
transition: transform 0ms !important;
}
.components-body {
padding: 8px 10px;
background: #f4f6fc;
font-size: 12px;
margin-left: 5px;
padding-top: 5px;
cursor: move;
border: 1px solid #409eff;
border-radius: 3px;
}
.components-body:hover {
border: 1px dashed #f56c6c;
color: #f56c6c;
}
.center-board {
height: 100vh;
width: auto;
margin: 0 350px 0 260px;
box-sizing: border-box;
}
.empty-info{
position: absolute;
top: 30%;
left: 0;
right: 0;
text-align: center;
font-size: 18px;
letter-spacing: 4px;
}
.action-bar{
position: relative;
height: 42px;
text-align: right;
padding: 0 15px;
box-sizing: border-box;;
border: 1px solid #f1e8e8;
border-top: none;
border-left: none;
background: #ffffff;
}
.action-bar .el-button{
font-size: 18px;
vertical-align: middle;
position: relative;
top: -1px;
color:#409EFF
}
.action-bar .delete-btn{
color: #F56C6C;
}
.center-scrollbar {
height: calc(100vh - 42px);
overflow: hidden;
border-left: 1px solid #f1e8e8;
border-right: 1px solid #f1e8e8;
box-sizing: border-box;
}
.center-board-row {
padding: 10px 12px 100px 12px;
box-sizing: border-box;
}
.center-board-row .el-form {
height: calc(100vh - 69px);
}
.dynamic-table{
margin: 0px;
height: auto;
min-height: 120px;
padding: 10px 0px;
}
.dynamic-table__content{
width:100%;
height:100%;
display: flex;
overflow-y: hidden;
outline: 1px dashed #ccc;
outline-offset: -1px;
min-height: 100px;
float:left
}
.dynamic-table__item {
margin:1px;
padding-top:5px;
border: 1px solid #EBEEF5;
background:#f2f6fc;
border-radius: 2px;
}
.dynamic-table__item:hover {
border: 1px solid #409EFF;
}
.dynamic-table__item_title{
width:100%;
padding-top:8px;
line-height: 23px;
text-align: center;
border-bottom: 1px solid #EBEEF5;
font-size: 14px;
color:#606266;
height:30px;
}
.dynamic-table__item_body{
padding:10px;
text-align: center;
}
.table__content{
width:100%;
height:100%;
overflow-y: hidden;
outline: 1px dashed #ccc;
outline-offset: -1px;
min-height: 100px;
float:left
}
.el-radio:last-child {
margin-right:30px;
}
.el-checkbox:last-of-type{
margin-right:30px;
}
.el-rate{
margin-top:10px;
}
.component-id{
position: absolute;
top: 0;
left: 0;
font-size: 12px;
color: #bbb;
display: inline-block;
margin: 0 6px;
}
/* .dynamic-table.active{
border-left: 3px solid #409eff;
background:#ecf5ff
} */
\ No newline at end of file
@selectedColor: #e6f2ff;
@lighterBlue: #409EFF;
.drawing-board {
height: 100%;
position: relative;
border:1px dashed #ccc;
.components-body {
padding: 0;
margin: 0;
font-size: 0;
}
.sortable-ghost {
position: relative;
display: block;
overflow: hidden;
&::before {
content: " ";
position: absolute;
left: 0;
right: 0;
top: 0;
height: 3px;
background: #409EFF;
z-index: 2;
}
}
.components-item.sortable-ghost {
width: 100%;
height: 5px;
background-color: @selectedColor;
}
.drawing-item.sortable-ghost {
width: 100%;
height: 5px;
background-color: @selectedColor;
}
.active-from-item {
& > .el-form-item{
background: @selectedColor;
border-radius:6px;
margin-top:15px;
}
& > .dynamic-table{
background: @selectedColor;
border-radius:6px;
}
& > .drawing-item-copy, & > .drawing-item-delete{
display: initial;
}
& > .component-name{
color: @lighterBlue;
}
}
.el-form-item{
margin-bottom: 5px;
}
}
.drawing-item{
position: relative;
cursor: move;
&.unfocus-bordered:not(.active-from-item) > div:first-child {
border: 1px dashed #ccc;
}
.el-form-item{
padding: 12px 10px;
margin-top:15px;
}
}
.drawing-item{
position: relative;
border: 1px dashed #ccc;
cursor: move;
.dynamic-table{
padding: 12px 5px;
}
}
.drawing-row-item{
position: relative;
cursor: move;
box-sizing: border-box;
border: 1px dashed #ccc;
border-radius: 3px;
padding: 0 2px;
margin-bottom: 15px;
.el-col{
margin-top: 15px;
}
.el-form-item{
margin-bottom: 15px;
}
.drag-wrapper{
min-height: 80px;
}
.drag-col-wrapper{
height: auto;
border: 1px dashed #ccc;
}
&.active-from-item{
border: 2px solid #e6a23c;
}
.component-name{
position: absolute;
top: 0;
left: 0;
font-size: 12px;
color: #bbb;
display: inline-block;
padding: 0 6px;
}
}
.drawing-item, .drawing-row-item{
&:hover {
& > .el-form-item{
background: #ebeef5;
}
& > .drawing-item-copy, & > .drawing-item-delete{
display: initial;
}
}
& > .drawing-item-copy, & > .drawing-item-delete{
display: none;
position: absolute;
top: -10px;
width: 22px;
height: 22px;
line-height: 22px;
text-align: center;
border-radius: 50%;
font-size: 12px;
border: 1px solid;
cursor: pointer;
z-index: 1;
}
& > .drawing-item-copy{
right: 56px;
border-color: @lighterBlue;
color: @lighterBlue;
background: #fff;
&:hover{
background: @lighterBlue;
color: #fff;
}
}
& > .drawing-item-delete{
right: 24px;
border-color: #F56C6C;
color: #F56C6C;
background: #fff;
&:hover{
background: #F56C6C;
color: #fff;
}
}
}
.drawing-item, .drawing-form-item{
&:hover {
& > .el-form-item{
background: #ebeef5;
}
& > .drawing-item-copy, & > .drawing-item-delete{
display: initial;
}
}
& > .drawing-item-copy, & > .drawing-item-delete{
display: none;
position: absolute;
top: -10px;
width: 22px;
height: 22px;
line-height: 22px;
text-align: center;
border-radius: 50%;
font-size: 12px;
border: 1px solid;
cursor: pointer;
z-index: 1;
}
& > .drawing-item-copy{
right: 56px;
border-color: @lighterBlue;
color: @lighterBlue;
background: #fff;
&:hover{
background: @lighterBlue;
color: #fff;
}
}
& > .drawing-item-delete{
right: 24px;
border-color: #F56C6C;
color: #F56C6C;
background: #fff;
&:hover{
background: #F56C6C;
color: #fff;
}
}
}
.right-board {
width: 350px;
position: absolute;
right: 0;
top: 0;
padding-top: 3px;
.field-box {
position: relative;
height: calc(100vh - 42px);
box-sizing: border-box;
overflow: hidden;
}
.el-scrollbar {
height: 100%;
}
}
.select-item {
display: flex;
border: 1px dashed #fff;
box-sizing: border-box;
& .close-btn {
cursor: pointer;
color: #f56c6c;
}
& .el-input + .el-input {
margin-left: 4px;
}
}
.select-item + .select-item {
margin-top: 4px;
}
.select-item.sortable-chosen {
border: 1px dashed #409eff;
}
.select-line-icon {
line-height: 32px;
font-size: 22px;
padding: 0 4px;
color: #777;
}
.option-drag {
cursor: move;
}
.time-range {
.el-date-editor {
width: 227px;
}
::v-deep .el-icon-time {
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;
}
.node-icon{
color: #bebfc3;
}
.center-tabs{
.el-tabs__header{
margin-bottom: 0!important;
}
.el-tabs__item{
width: 100%;
text-align: center;
}
.el-tabs__nav{
width: 100%;
}
}
.right-scrollbar {
.el-scrollbar__view {
padding: 12px 18px 15px 15px;
}
}
.drawing-row-item .el-col{
margin-bottom:5px;
}
.components-item.dynamicGhost {
width: 5px;
height: 120px;
background-color: #409EFF;
}
.dynamic-table_item.dynamicGhost {
width: 5px;
height: 120px;
background-color: #409EFF;
}
<template>
<div>
<div style="padding:5px;margin-top:10px">
<table class="table-layout" :style="tableWidth">
<tbody>
<tr v-for="(tr, trIndex) in layoutArray" :key="trIndex" :style="trHeight">
<fancy-edit-table-item v-for="(td,tdIndex) in tr" :key="tdIndex"
:item="td"
:tdIndex="tdIndex"
:trIndex="trIndex"
:tdStyle="tdStyle"
>
<slot :td="td" />
</fancy-edit-table-item>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
import fancyEditTableItem from './fancyEditTableItem';
export default {
name: 'fancyEditTable',
components: {
fancyEditTableItem
},
props: {
layoutArray: {
type: Array,
default: () => []
},
tdStyle:{
type:String,
default:''
},
width:{
type:Number,
default:100
},
height:{
type:Number,
default:100
}
},
data() {
return {
}
},
mounted() {
},
destroyed() {
},
methods: {
},
computed: {
tableWidth(){
return 'width:'+this.width+'%';
},
trHeight(){
return 'height:'+this.height+'px';
}
}
}
</script>
<style scoped>
table {
border-spacing: 0;
width: 100%
}
tbody {
display: table-row-group;
vertical-align: middle;
border-color: inherit;
}
td {
border: 1px #d2d2d2 solid;
}
.table-layout {
background-color: #ffffff;
border-collapse: collapse;
padding: 8px !important;
text-align: left;
margin: 0 auto;
width: 100%;
table-layout: fixed;
}
.table-layout>tbody>tr>td {
padding: 6px;
word-break: break-word;
border: 1px solid #d2d2d2;
height: 20px;
}
.table-layout>tbody>tr {
border-bottom: 1px solid #d2d2d2;
border-top: 1px solid #d2d2d2;
}
.right-menu {
background-color: #ffffff;
z-index: 100;
width: 200px;
position: fixed;
border: 1px solid #ccc;
box-shadow: 3px 3px 8px #999;
border-radius: 3px;
padding: 8px 0;
}
.right-menu ul {
margin: 0px;
padding: 0px;
}
.right-menu ul li {
padding: 0 15px;
height: 30px;
line-height: 30px;
}
.right-menu ul li:hover {
cursor: pointer;
background-color: #ccc;
}
.CellHide {
display: none;
}
</style>
\ No newline at end of file
<template>
<td
:colspan="item.col"
:rowspan="item.row"
:class="{ cellHide: item.hide }"
:style="{
tdStyle,
'background-color': item.style.background,
width: item.style.width + '%',
}"
style=""
@contextmenu.prevent="rightClick($event, trIndex, tdIndex)"
>
<slot :td="item" />
</td>
</template>
<script>
export default {
name: "fancyEditTableItem",
components: {},
props: {
item: {
type: Object,
default: () => {
return {};
},
},
tdIndex: {
type: Number,
default: 0,
},
trIndex: {
type: Number,
default: 0,
},
tdStyle: {
type: String,
default: "",
},
},
};
</script>
<style scoped>
td {
border: 1px #d2d2d2 solid;
padding: 6px;
padding-top: 0px;
word-break: break-word;
border: 1px solid #d2d2d2;
height: 20px;
height: 20px;
}
.cellHide {
display: none;
}
.activeItem {
border: 2px solid #e6a23c;
}
.component-td {
font-size: 12px;
color: #bbb;
}
.activeItem div span {
color: #409eff;
}
</style>
\ No newline at end of file
<template>
<div>
<div style="padding:5px;margin-top:10px">
<table class="table-layout" :style="tableStyle">
<tbody>
<tr v-for="(tr,trIndex) in layoutArray" :key="trIndex" :style="trHeight">
<fancy-table-item v-for="(td,tdIndex) in tr" :key="tdIndex"
:item="td"
:tdIndex="tdIndex"
:trIndex="trIndex"
:tdStyle="tdStyle"
@rightClick="rightClick"
@click.native="handlerSelectedTd($event,td)"
>
<slot :td="td" />
</fancy-table-item>
</tr>
</tbody>
</table>
</div>
<div v-show="showContextMunu" class="right-menu" :style="{ top: + positionY+'px',left: + positionX+'px', }">
<ul style="list-style-type: none">
<li @click="handlerRightCol" v-if="showRightColMenu">
<icon code="zuoyouhebing" text="向右合并单元格" />
</li>
<li @click="handlerDownRow" v-if="showDownRowMenu">
<icon code="shangxiahebing" text="向下合并单元格" />
</li>
<li @click="handlerResetTable" v-if="showResetTableMenu">
<icon code="chaifen" text="拆分单元格" />
</li>
<li @click="handlerAppendCol">
<icon code="zhuijiahang" text="追加行" />
</li>
<li @click="handlerAppendRow">
<icon code="zhuijialie" text="追加列" />
</li>
</ul>
</div>
</div>
</template>
<script>
import icon from '../icon';
import fancyTableItem from './fancyTableItem';
import {jsonClone} from "../utils";
import {getTrItem,getTdItem} from "./table";
import { getSimpleId } from '../utils/IdGenerate';
let tr = getTrItem();
export default {
name:'fancyTable',
components:{
icon,
fancyTableItem
},
props:{
layoutArray:{
type:Array,
default:()=>[]
},
tdStyle:{
type:String,
default:''
},
width:{
type:Number,
default:100
},
height:{
type:Number,
default:100
}
},
data(){
return{
positionX:0,
positionY:0,
showContextMunu:false,
currentRowIndex:0,
currentColIndex:0,
//columns: this.trs
}
},
mounted() {
// 添加监听取消右键菜单
document.addEventListener("click", this.hideRightContextMenu, true);
document.addEventListener("contextmenu", this.hideRightContextMenu, true);
// this.handlerAppendCol();
// this.handlerAppendCol();
},
destroyed() {
// 移除监听
document.removeEventListener("click", this.hideRightContextMenu, true);
document.removeEventListener("contextmenu",this.hideRightContextMenu,true);
},
methods:{
rightClick(e,rowIndex,colIndex){
this.positionX = e.clientX;
this.positionY = e.clientY;
this.showContextMunu = true;
this.currentRowIndex = rowIndex;
this.currentColIndex = colIndex;
},
hideRightContextMenu(){
this.showContextMunu = false;
},
//向右合并单元格
handlerRightCol(){
let col = this.layoutArray[this.currentRowIndex][this.currentColIndex].col;
let row = this.layoutArray[this.currentRowIndex][this.currentColIndex].row;
if(row>1){
for(let i =0;i<row;i++){
this.layoutArray[this.currentRowIndex+i][this.currentColIndex+col].hide=true;
this.layoutArray[this.currentRowIndex][this.currentColIndex].col=col+1;
}
}else{
this.layoutArray[this.currentRowIndex][this.currentColIndex+col].hide=true;
this.layoutArray[this.currentRowIndex][this.currentColIndex].col=col+1;
}
},
//向下合并单元格
handlerDownRow(){
let col = this.layoutArray[this.currentRowIndex][this.currentColIndex].col;
let row = this.layoutArray[this.currentRowIndex][this.currentColIndex].row;
if(col>1){
for(let i =0;i<col;i++){
this.layoutArray[this.currentRowIndex+row][this.currentColIndex+i].hide=true;
this.layoutArray[this.currentRowIndex][this.currentColIndex].row=row+1;
}
}else{
this.layoutArray[this.currentRowIndex+row][this.currentColIndex].hide=true;
this.layoutArray[this.currentRowIndex][this.currentColIndex].row=row+1;
}
// let nextCol = this.columns[this.currentRowIndex+1][this.currentColIndex].col;
// let nextRow = this.columns[this.currentRowIndex+1][this.currentColIndex].row;
// if(nextCol<2&nextRow<2){
// }else{
// alert('请先拆分下方单元格!');
// }
},
handlerResetTable(){
//debugger;
let col = this.layoutArray[this.currentRowIndex][this.currentColIndex].col;
let row = this.layoutArray[this.currentRowIndex][this.currentColIndex].row;
if(col===1&&row===1)return;
for(let i = 0;i<row;i++){
for(let j = 0;j<col;j++){
this.layoutArray[this.currentRowIndex+i][this.currentColIndex+j].hide = false;
}
}
this.layoutArray[this.currentRowIndex][this.currentColIndex].row=1;
this.layoutArray[this.currentRowIndex][this.currentColIndex].col=1;
},
handlerSelectedTd(e,td){
this.$emit('selectItem',td);
e.stopPropagation();
},
//追加行
handlerAppendCol(){
let _trItem = jsonClone(tr);
_trItem.map(item=>item.id=getSimpleId());
this.layoutArray.push(_trItem);
},
handlerAppendRow(){
tr.push(getTdItem());
this.layoutArray.forEach(item=>{
const _td = jsonClone(getTdItem());
item.push(_td);
})
}
},
computed:{
showRightColMenu(){
if(this.showContextMunu){
const col = this.layoutArray[this.currentRowIndex][this.currentColIndex].col;
const td = this.layoutArray[this.currentRowIndex][this.currentColIndex+col];
return (td&&td.row<2&&td.col<2&&!td.hide);
}else{
return false;
}
},
showDownRowMenu(){
if(this.showContextMunu){
const row = this.layoutArray[this.currentRowIndex][this.currentColIndex].row;
let td = undefined;
if(typeof this.layoutArray[this.currentRowIndex+row] !== 'undefined'){
td = this.layoutArray[this.currentRowIndex+row][this.currentColIndex];
}
return (td&&td.row<2&&td.col<2&&!td.hide);
}else{
return false;
}
},
showResetTableMenu(){
if(this.showContextMunu){
const td = this.layoutArray[this.currentRowIndex][this.currentColIndex];
return !(td.row<2&&td.col<2&&!td.hide);
}else{
return false;
}
},
tableStyle(){
return 'width:'+this.width+'%;';
},
trHeight(){
return 'height:'+this.height+'px';
}
}
}
</script>
<style scoped>
table{
border-spacing:0;
width:100%
}
tbody{
display: table-row-group;
vertical-align: middle;
border-color: inherit;
}
.table-layout{
background-color: #ffffff;
border-collapse: collapse;
padding: 8px !important;
text-align: left;
margin: 0 auto;
width: 100%;
table-layout: fixed;
}
.table-layout > tbody > tr{
border-bottom: 1px solid #d2d2d2;
border-top: 1px solid #d2d2d2;
}
.right-menu{
background-color:#ffffff;
z-index:100;
width:200px;
position: fixed;
border: 1px solid #ccc;
box-shadow: 3px 3px 8px #999;
border-radius: 3px;
padding: 8px 0;
}
.right-menu ul{
margin:0px;
padding:0px;
}
.right-menu ul li{
padding:0 15px;
height:30px;
line-height: 30px;
}
.right-menu ul li:hover{
cursor: pointer;
background-color: #ccc;
}
</style>
\ No newline at end of file
<template>
<td
:colspan="item.col"
:rowspan="item.row"
:class="{ cellHide: item.hide, activeItem: isActiveItem }"
:style="{
tdStyle,
'background-color': item.style.background,
width: item.style.width + '%',
}"
style=""
@contextmenu.prevent="rightClick($event, trIndex, tdIndex)"
>
<div class="component-td">
<span>{{ item.id }}</span>
<slot :td="item" />
</div>
</td>
</template>
<script>
export default {
name: "fancyTableItem",
components: {},
props: {
item: {
type: Object,
default: () => {
return {};
},
},
tdIndex: {
type: Number,
default: 0,
},
trIndex: {
type: Number,
default: 0,
},
tdStyle: {
type: String,
default: "",
},
},
data() {
return {};
},
inject: ["getContext"],
methods: {
rightClick(e, rowIndex, colIndex) {
this.$emit("rightClick", e, rowIndex, colIndex);
},
},
computed: {
isActiveItem() {
return this.getContext.activeItem.id === this.item.id ? true : false;
//this.designerActiveItem
},
},
};
</script>
<style scoped>
td {
border: 1px #d2d2d2 solid;
padding: 6px;
padding-top: 0px;
word-break: break-word;
border: 1px solid #d2d2d2;
height: 20px;
height: 20px;
}
.cellHide {
display: none;
}
.activeItem {
border: 2px solid #e6a23c;
}
.component-td {
font-size: 12px;
color: #bbb;
}
.activeItem div span {
color: #409eff;
}
</style>
\ No newline at end of file
import {getSimpleId} from "../utils/IdGenerate";
import constant from '../utils/constants'
import {jsonClone} from "../utils";
let tdItemObj = {
id:'',
col:1,
row:1,
hide:false,
compType:'tdItem',
style:{
background:constant.defaultTdBackgroundColor,
width:35
},
columns:[]
}
export function getTdItem(){
let tdItem = cloneObj(tdItemObj);
tdItem.id = getSimpleId();
return tdItem;
}
export function getTitleTdItem(){
let tdItem = cloneObj(tdItemObj);
tdItem.style.background = constant.defaultTitleTdBackgroundColor;
tdItem.style.width = 15;
tdItem.id = getSimpleId();
return tdItem;
}
function cloneObj(source){
let target = jsonClone(source);
target.id = getSimpleId();
return target;
}
export function getTrItem(){
let trItem= [getTitleTdItem(),getTdItem(),getTitleTdItem(),getTdItem()];
return trItem;
}
export function getDefaultTrs(){
let trs = [getTrItem(),getTrItem()];
return trs;
}
\ No newline at end of file
export function getSimpleId(){
sleep(10); //主要为了延时工作
return new Date().getTime();
}
const sleep = function(time) {
const startTime = new Date().getTime() + parseInt(time, 10);
while(new Date().getTime() < startTime) {return}
};
export function setTableId(table){
table.layoutArray.map((tr)=>{
tr[0].id=getSimpleId();
tr[1].id=getSimpleId();
})
return table;
}
\ No newline at end of file
import allData from 'china-area-data/v5/data';
export function areaData(){
let options = [];
const allProvinceData = allData['86']; //得到全中国的省
Object.keys(allProvinceData).forEach(key=>{
let provinceObj={};
provinceObj.label= allProvinceData[key];
provinceObj.value= key;
const cityData = allData[key]; //市
provinceObj.children = [];
Object.keys(cityData).forEach(ckey=>{
let cityObj = {};
cityObj.label = cityData[ckey];
cityObj.value = ckey;
const areaData = allData[ckey]; //区
if(typeof areaData !== 'undefined'){
cityObj.children = [];
Object.keys(areaData).forEach(akey=>{
let areaObj = {};
areaObj.label = areaData[akey];
areaObj.value = akey;
cityObj.children.push(areaObj);
});
}
provinceObj.children.push(cityObj);
})
options.push(provinceObj);
});
return options;
}
/**
* js的常量就在这里
*/
export default {
defaultTdBackgroundColor:'#FFFFFF',
defaultTitleTdBackgroundColor:'#F6F6F6'
}
\ No newline at end of file
[
"el-icon-platform-eleme",
"el-icon-eleme",
"el-icon-delete-solid",
"el-icon-delete",
"el-icon-s-tools",
"el-icon-setting",
"el-icon-user-solid",
"el-icon-user",
"el-icon-phone",
"el-icon-phone-outline",
"el-icon-more",
"el-icon-more-outline",
"el-icon-star-on",
"el-icon-star-off",
"el-icon-s-goods",
"el-icon-goods",
"el-icon-warning",
"el-icon-warning-outline",
"el-icon-question",
"el-icon-info",
"el-icon-remove",
"el-icon-circle-plus",
"el-icon-success",
"el-icon-error",
"el-icon-zoom-in",
"el-icon-zoom-out",
"el-icon-remove-outline",
"el-icon-circle-plus-outline",
"el-icon-circle-check",
"el-icon-circle-close",
"el-icon-s-help",
"el-icon-help",
"el-icon-minus",
"el-icon-plus",
"el-icon-check",
"el-icon-close",
"el-icon-picture",
"el-icon-picture-outline",
"el-icon-picture-outline-round",
"el-icon-upload",
"el-icon-upload2",
"el-icon-download",
"el-icon-camera-solid",
"el-icon-camera",
"el-icon-video-camera-solid",
"el-icon-video-camera",
"el-icon-message-solid",
"el-icon-bell",
"el-icon-s-cooperation",
"el-icon-s-order",
"el-icon-s-platform",
"el-icon-s-fold",
"el-icon-s-unfold",
"el-icon-s-operation",
"el-icon-s-promotion",
"el-icon-s-home",
"el-icon-s-release",
"el-icon-s-ticket",
"el-icon-s-management",
"el-icon-s-open",
"el-icon-s-shop",
"el-icon-s-marketing",
"el-icon-s-flag",
"el-icon-s-comment",
"el-icon-s-finance",
"el-icon-s-claim",
"el-icon-s-custom",
"el-icon-s-opportunity",
"el-icon-s-data",
"el-icon-s-check",
"el-icon-s-grid",
"el-icon-menu",
"el-icon-share",
"el-icon-d-caret",
"el-icon-caret-left",
"el-icon-caret-right",
"el-icon-caret-bottom",
"el-icon-caret-top",
"el-icon-bottom-left",
"el-icon-bottom-right",
"el-icon-back",
"el-icon-right",
"el-icon-bottom",
"el-icon-top",
"el-icon-top-left",
"el-icon-top-right",
"el-icon-arrow-left",
"el-icon-arrow-right",
"el-icon-arrow-down",
"el-icon-arrow-up",
"el-icon-d-arrow-left",
"el-icon-d-arrow-right",
"el-icon-video-pause",
"el-icon-video-play",
"el-icon-refresh",
"el-icon-refresh-right",
"el-icon-refresh-left",
"el-icon-finished",
"el-icon-sort",
"el-icon-sort-up",
"el-icon-sort-down",
"el-icon-rank",
"el-icon-loading",
"el-icon-view",
"el-icon-c-scale-to-original",
"el-icon-date",
"el-icon-edit",
"el-icon-edit-outline",
"el-icon-folder",
"el-icon-folder-opened",
"el-icon-folder-add",
"el-icon-folder-remove",
"el-icon-folder-delete",
"el-icon-folder-checked",
"el-icon-tickets",
"el-icon-document-remove",
"el-icon-document-delete",
"el-icon-document-copy",
"el-icon-document-checked",
"el-icon-document",
"el-icon-document-add",
"el-icon-printer",
"el-icon-paperclip",
"el-icon-takeaway-box",
"el-icon-search",
"el-icon-monitor",
"el-icon-attract",
"el-icon-mobile",
"el-icon-scissors",
"el-icon-umbrella",
"el-icon-headset",
"el-icon-brush",
"el-icon-mouse",
"el-icon-coordinate",
"el-icon-magic-stick",
"el-icon-reading",
"el-icon-data-line",
"el-icon-data-board",
"el-icon-pie-chart",
"el-icon-data-analysis",
"el-icon-collection-tag",
"el-icon-film",
"el-icon-suitcase",
"el-icon-suitcase-1",
"el-icon-receiving",
"el-icon-collection",
"el-icon-files",
"el-icon-notebook-1",
"el-icon-notebook-2",
"el-icon-toilet-paper",
"el-icon-office-building",
"el-icon-school",
"el-icon-table-lamp",
"el-icon-house",
"el-icon-no-smoking",
"el-icon-smoking",
"el-icon-shopping-cart-full",
"el-icon-shopping-cart-1",
"el-icon-shopping-cart-2",
"el-icon-shopping-bag-1",
"el-icon-shopping-bag-2",
"el-icon-sold-out",
"el-icon-sell",
"el-icon-present",
"el-icon-box",
"el-icon-bank-card",
"el-icon-money",
"el-icon-coin",
"el-icon-wallet",
"el-icon-discount",
"el-icon-price-tag",
"el-icon-news",
"el-icon-guide",
"el-icon-male",
"el-icon-female",
"el-icon-thumb",
"el-icon-cpu",
"el-icon-link",
"el-icon-connection",
"el-icon-open",
"el-icon-turn-off",
"el-icon-set-up",
"el-icon-chat-round",
"el-icon-chat-line-round",
"el-icon-chat-square",
"el-icon-chat-dot-round",
"el-icon-chat-dot-square",
"el-icon-chat-line-square",
"el-icon-message",
"el-icon-postcard",
"el-icon-position",
"el-icon-turn-off-microphone",
"el-icon-microphone",
"el-icon-close-notification",
"el-icon-bangzhu",
"el-icon-time",
"el-icon-odometer",
"el-icon-crop",
"el-icon-aim",
"el-icon-switch-button",
"el-icon-full-screen",
"el-icon-copy-document",
"el-icon-mic",
"el-icon-stopwatch",
"el-icon-medal-1",
"el-icon-medal",
"el-icon-trophy",
"el-icon-trophy-1",
"el-icon-first-aid-kit",
"el-icon-discover",
"el-icon-place",
"el-icon-location",
"el-icon-location-outline",
"el-icon-location-information",
"el-icon-add-location",
"el-icon-delete-location",
"el-icon-map-location",
"el-icon-alarm-clock",
"el-icon-timer",
"el-icon-watch-1",
"el-icon-watch",
"el-icon-lock",
"el-icon-unlock",
"el-icon-key",
"el-icon-service",
"el-icon-mobile-phone",
"el-icon-bicycle",
"el-icon-truck",
"el-icon-ship",
"el-icon-basketball",
"el-icon-football",
"el-icon-soccer",
"el-icon-baseball",
"el-icon-wind-power",
"el-icon-light-rain",
"el-icon-lightning",
"el-icon-heavy-rain",
"el-icon-sunrise",
"el-icon-sunrise-1",
"el-icon-sunset",
"el-icon-sunny",
"el-icon-cloudy",
"el-icon-partly-cloudy",
"el-icon-cloudy-and-sunny",
"el-icon-moon",
"el-icon-moon-night",
"el-icon-dish",
"el-icon-dish-1",
"el-icon-food",
"el-icon-chicken",
"el-icon-fork-spoon",
"el-icon-knife-fork",
"el-icon-burger",
"el-icon-tableware",
"el-icon-sugar",
"el-icon-dessert",
"el-icon-ice-cream",
"el-icon-hot-water",
"el-icon-water-cup",
"el-icon-coffee-cup",
"el-icon-cold-drink",
"el-icon-goblet",
"el-icon-goblet-full",
"el-icon-goblet-square",
"el-icon-goblet-square-full",
"el-icon-refrigerator",
"el-icon-grape",
"el-icon-watermelon",
"el-icon-cherry",
"el-icon-apple",
"el-icon-pear",
"el-icon-orange",
"el-icon-coffee",
"el-icon-ice-tea",
"el-icon-ice-drink",
"el-icon-milk-tea",
"el-icon-potato-strips",
"el-icon-lollipop",
"el-icon-ice-cream-square",
"el-icon-ice-cream-round"
]
\ No newline at end of file
export function makeMap(str, expectsLowerCase) {
const map = Object.create(null)
const list = str.split(',')
for (let i = 0; i < list.length; i++) {
map[list[i]] = true
}
return expectsLowerCase
? val => map[val.toLowerCase()]
: val => map[val]
}
/**
* num 小于0,左缩进num*2个空格; 大于0,右缩进num*2个空格。
* @param {string} str 代码
* @param {number} num 缩进次数
* @param {number} len 【可选】缩进单位,空格数
*/
export function indent(str, num, len = 2) {
if (num === 0) return str
const isLeft = num < 0; const result = []; let reg; let
spaces = ''
if (isLeft) {
num *= -1
reg = new RegExp(`(^\\s{0,${num * len}})`, 'g')
} else {
for (let i = 0; i < num * len; i++) spaces += ' '
}
str.split('\n').forEach(line => {
line = isLeft ? line.replace(reg, '') : spaces + line
result.push(line)
})
return result.join('\n')
}
// 首字母大小
export function titleCase(str) {
return str.replace(/( |^)[a-z]/g, L => L.toUpperCase())
}
// 下划转驼峰
export function camelCase(str) {
return str.replace(/-[a-z]/g, str1 => str1.substr(-1).toUpperCase())
}
export function isNumberStr(str) {
return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
}
export const beautifierConf = {
html: {
indent_size: '2',
indent_char: ' ',
max_preserve_newlines: '-1',
preserve_newlines: false,
keep_array_indentation: false,
break_chained_methods: false,
indent_scripts: 'separate',
brace_style: 'end-expand',
space_before_conditional: true,
unescape_strings: false,
jslint_happy: false,
end_with_newline: true,
wrap_line_length: '110',
indent_inner_html: true,
comma_first: false,
e4x: true,
indent_empty_lines: true
},
js: {
indent_size: '2',
indent_char: ' ',
max_preserve_newlines: '-1',
preserve_newlines: false,
keep_array_indentation: false,
break_chained_methods: false,
indent_scripts: 'normal',
brace_style: 'end-expand',
space_before_conditional: true,
unescape_strings: false,
jslint_happy: true,
end_with_newline: true,
wrap_line_length: '110',
indent_inner_html: true,
comma_first: false,
e4x: true,
indent_empty_lines: true
}
}
function stringify(obj) {
return JSON.stringify(obj, (key, val) => {
if (typeof val === 'function') {
return `${val}`
}
return val
})
}
function parse(str) {
return JSON.parse(str, (k, v) => {
if (v!==null&&v.indexOf && v.indexOf('function') > -1) {
return eval(`(${v})`)
}
return v
})
}
export function jsonClone(obj) {
return parse(stringify(obj));
}
export function isLayout(obj) {
return obj.compType === 'row';
}
export function isTable(obj) {
return obj.compType === 'table';
}
export function inTable(obj) {
return obj.col&&obj.row;
}
export const isAttr = makeMap(
'accept,accept-charset,accesskey,action,align,alt,async,autocomplete,'
+ 'autofocus,autoplay,autosave,bgcolor,border,buffered,challenge,charset,'
+ 'checked,cite,class,code,codebase,color,cols,colspan,content,http-equiv,'
+ 'name,contenteditable,contextmenu,controls,coords,data,datetime,default,'
+ 'defer,dir,dirname,disabled,download,draggable,dropzone,enctype,method,for,'
+ 'form,formaction,headers,height,hidden,high,href,hreflang,http-equiv,'
+ 'icon,id,ismap,itemprop,keytype,kind,label,lang,language,list,loop,low,'
+ 'manifest,max,maxlength,media,method,GET,POST,min,multiple,email,file,'
+ 'muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,'
+ 'preload,radiogroup,readonly,rel,required,reversed,rows,rowspan,sandbox,'
+ 'scope,scoped,seamless,selected,shape,size,type,text,password,sizes,span,'
+ 'spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,'
+ 'target,title,type,usemap,value,width,wrap'
)
\ No newline at end of file
......@@ -27,16 +27,12 @@ Vue.prototype.$message = message;
// 滚动插件
import scroll from "vue-seamless-scroll";
Vue.use(scroll);
// 表格生成
import plugins from "./components/formDes/index";
Vue.use(plugins);
// 格式化插件
import format from "vue-text-format";
Vue.use(format);
// 中央事件
Vue.prototype.$bus = new Vue();
Vue.config.productionTip = false;
Vue.config.productionTip = false;
......
......@@ -41,7 +41,8 @@
<span class="matter-fullName">事项全称</span
>{{ matter.matterFullName }}
</div>
<div
<!-- 材料展示 -->
<!-- <div
class="materials flex aic"
v-for="(item, index) in matter.matterDatumList.slice(0, 3)"
:key="item.id"
......@@ -65,7 +66,7 @@
}}
</span>
</span>
</div>
</div> -->
</div>
<div
class="list"
......@@ -118,7 +119,7 @@ export default {
searchVal: this.$route.query.val,
total: 0,
current: 1,
size: 12,
size: 16,
matterInfo: {},
visible: false,
matterTotal: 0,
......@@ -190,7 +191,8 @@ export default {
}
}
.matter-box {
width: 100%;
width: 1840px;
height: 800px;
padding: 30px;
padding-bottom: 10px;
background: #ffffff;
......@@ -202,15 +204,17 @@ export default {
}
.list {
content: "";
width: 426px;
width: 422px;
border: 1px solid transparent;
padding: 5px;
overflow: hidden;
}
.matter-item {
width: 426px;
height: 210px;
padding: 10px 20px;
width: 422px;
// height: 210px;
height: 150px;
// padding: 10px 20px;
padding: 20px;
margin-bottom: 30px;
background: #edf6fe;
border-radius: 16px;
......@@ -234,7 +238,8 @@ export default {
}
}
.for-short {
margin-bottom: 10px;
// margin-bottom: 10px;
margin-bottom: 18px;
font-size: 24px;
font-weight: 500;
color: #333333;
......
......@@ -180,7 +180,8 @@ export default {
}
.matter-box {
height: 100%;
width: 1540px;
height: 800px;
padding: 30px;
background: #ffffff;
border-radius: 16px;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment