csg6 1 тиждень тому
батько
коміт
f20ac91822

+ 3 - 3
.env.development

@@ -5,9 +5,9 @@ VUE_APP_TITLE = 双重预防综合管理系统
5 5
 ENV = 'development'
6 6
 
7 7
 # 双重防御系统开发环境后台接口地址配置
8
-VUE_APP_BASE_API = 'http://101.42.248.108:17007'
9
-# VUE_APP_BASE_API = 'http://192.168.29.184:18080'
10
-#VUE_APP_BASE_API = 'http://localhost:18080'
8
+# VUE_APP_BASE_API = 'http://101.42.248.108:17005'
9
+VUE_APP_BASE_API = 'http://192.168.3.200:18080'
10
+# VUE_APP_BASE_API = 'http://localhost:18080'
11 11
 
12 12
 
13 13
 # 路由懒加载

Різницю між файлами не показано, бо вона завелика
+ 0 - 14818
package-lock.json


+ 13 - 8
package.json

@@ -38,28 +38,31 @@
38 38
   "dependencies": {
39 39
     "@jiaminghi/data-view": "^2.10.0",
40 40
     "@riophae/vue-treeselect": "0.4.0",
41
-    "FileSaver": "^0.10.0",
42 41
     "amfe-flexible": "^2.2.1",
43 42
     "animate.css": "^4.1.1",
44
-    "axios": "0.24.0",
43
+    "axios": "^1.7.7",
44
+    "bpmn-js": "^11.1.0",
45 45
     "clipboard": "2.0.8",
46 46
     "core-js": "^3.32.0",
47
+    "diagram-js": "^11.4.1",
47 48
     "docx-preview": "^0.1.18",
48 49
     "echarts": "5.4.0",
49 50
     "element-ui": "2.15.13",
50 51
     "express": "^4.18.2",
51 52
     "file-saver": "2.0.5",
53
+    "FileSaver": "^0.10.0",
52 54
     "fuse.js": "6.4.3",
53
-    "highlight.js": "9.18.5",
55
+    "highlight.js": "^9.18.5",
54 56
     "js-beautify": "1.13.0",
55 57
     "js-cookie": "3.0.1",
56 58
     "jsencrypt": "3.0.0-rc.1",
57 59
     "moment": "^2.29.4",
58 60
     "nodemon": "^3.0.1",
59 61
     "nprogress": "0.2.0",
60
-    "quill": "1.3.7",
62
+    "quill": "^1.3.7",
61 63
     "screenfull": "5.0.2",
62 64
     "sortablejs": "1.10.2",
65
+    "vkbeautify": "^0.99.3",
63 66
     "vue": "2.6.12",
64 67
     "vue-count-to": "1.0.13",
65 68
     "vue-cropper": "0.5.5",
@@ -70,26 +73,28 @@
70 73
     "vue2-org-tree": "^1.3.6",
71 74
     "vuedraggable": "2.24.3",
72 75
     "vuex": "3.6.0",
76
+    "xcrud": "^0.4.19",
73 77
     "xlsx": "^0.18.5"
74 78
   },
75 79
   "devDependencies": {
76
-    "@vue/cli-plugin-babel": "4.4.6",
77
-    "@vue/cli-plugin-eslint": "4.4.6",
80
+    "@vue/cli-plugin-babel": "^5.0.8",
81
+    "@vue/cli-plugin-eslint": "^5.0.8",
78 82
     "@vue/cli-service": "4.4.6",
79 83
     "babel-eslint": "10.1.0",
80 84
     "babel-plugin-dynamic-import-node": "2.3.3",
81 85
     "chalk": "4.1.0",
82 86
     "compression-webpack-plugin": "5.0.2",
83 87
     "connect": "3.6.6",
88
+    "create-bpmnlint-plugin": "^0.6.0",
84 89
     "eslint": "7.15.0",
85 90
     "eslint-plugin-vue": "7.2.0",
86 91
     "lint-staged": "10.5.3",
87 92
     "postcss-pxtorem": "^5.1.1",
88
-    "runjs": "4.4.2",
93
+    "runjs": "^4.1.3",
89 94
     "sass": "1.32.13",
90 95
     "sass-loader": "10.1.1",
91 96
     "script-ext-html-webpack-plugin": "2.1.5",
92
-    "svg-sprite-loader": "5.1.1",
97
+    "svg-sprite-loader": "^5.2.1",
93 98
     "vue-template-compiler": "2.6.12"
94 99
   },
95 100
   "engines": {

+ 191 - 0
src/components/flow/ElInputTag/index.vue

@@ -0,0 +1,191 @@
1
+<template>
2
+  <div
3
+      class="el-input-tag input-tag-wrapper"
4
+      :class="[size ? 'el-input-tag--' + size : '']"
5
+      @click="focusTagInput">
6
+    <el-tag
7
+        v-for="(tag, idx) in innerTags"
8
+        v-bind="$attrs"
9
+        :key="tag"
10
+        :size="size"
11
+        effect="dark"
12
+        closable
13
+        :disable-transitions="false"
14
+        @close="remove(idx)">
15
+      {{tag}}
16
+    </el-tag>
17
+    <input
18
+        v-if="!readOnly"
19
+        class="tag-input"
20
+        :placeholder="placeholder"
21
+        @input="inputTag"
22
+        :value="newTag"
23
+        @keydown.delete.stop = "removeLastTag"
24
+    />
25
+<!--    @keydown = "addNew"
26
+        @blur = "addNew"-->
27
+  </div>
28
+</template>
29
+
30
+
31
+<script>
32
+import {StrUtil} from '@/utils/StrUtil'
33
+
34
+export default {
35
+  name: "ElInputTag",
36
+  /** 组件传值  */
37
+  props : {
38
+    value: {
39
+      type: String,
40
+      default: ""
41
+    },
42
+    addTagOnKeys: {
43
+      type: Array,
44
+      default: () => []
45
+    },
46
+    size: {
47
+      type: String,
48
+      default: 'small'
49
+    },
50
+    placeholder: String,
51
+  },
52
+  data() {
53
+    return {
54
+       newTag :"",
55
+       innerTags :[],
56
+       readOnly :true,
57
+    }
58
+  },
59
+  /** 传值监听 */
60
+  watch: {
61
+    value: {
62
+      handler(newVal) {
63
+        if (StrUtil.isNotBlank(newVal)) {
64
+          this.innerTags = newVal.split(',');
65
+        }else {
66
+          this.innerTags = [];
67
+        }
68
+      },
69
+      immediate: true, // 立即生效
70
+    },
71
+  },
72
+  methods: {
73
+    focusTagInput() {
74
+      if (this.readOnly || !this.$el.querySelector('.tag-input')) {
75
+        return
76
+      } else {
77
+        this.$el.querySelector('.tag-input').focus()
78
+      }
79
+    },
80
+
81
+    inputTag(ev) {
82
+     this.newTag = ev.target.value
83
+    },
84
+
85
+    addNew(e) {
86
+      if (e && (!this.addTagOnKeys.includes(e.keyCode)) && (e.type !== 'blur')) {
87
+        return
88
+      }
89
+      if (e) {
90
+        e.stopPropagation()
91
+        e.preventDefault()
92
+      }
93
+      let addSuccess = false
94
+      if (this.newTag.includes(',')) {
95
+       this.newTag.split(',').forEach(item => {
96
+          if (this.addTag(item.trim())) {
97
+            addSuccess = true
98
+          }
99
+        })
100
+      } else {
101
+        if (this.addTag(this.newTag.trim())) {
102
+          addSuccess = true
103
+        }
104
+      }
105
+      if (addSuccess) {
106
+        this.tagChange()
107
+       this.newTag = ''
108
+      }
109
+    },
110
+
111
+    addTag(tag) {
112
+      tag = tag.trim()
113
+      if (tag && !this.innerTags.includes(tag)) {
114
+        this.innerTags.push(tag)
115
+        return true
116
+      }
117
+      return false
118
+    },
119
+
120
+    remove(index) {
121
+      this.innerTags.splice(index, 1)
122
+      this.tagChange();
123
+    },
124
+
125
+    removeLastTag() {
126
+      if (this.newTag) {
127
+        return
128
+      }
129
+      this.innerTags.pop()
130
+      this.tagChange()
131
+    },
132
+
133
+    tagChange() {
134
+      this.$emit('input', this.innerTags)
135
+    }
136
+  }
137
+}
138
+
139
+</script>
140
+
141
+<style scoped>
142
+.el-form-item.is-error .el-input-tag {
143
+  border-color: #f56c6c;
144
+}
145
+.input-tag-wrapper {
146
+  position: relative;
147
+  font-size: 14px;
148
+  background-color: #fff;
149
+  background-image: none;
150
+  border-radius: 4px;
151
+  border: 1px solid #dcdfe6;
152
+  box-sizing: border-box;
153
+  color: #606266;
154
+  display: inline-block;
155
+  outline: none;
156
+  padding: 0 10px 0 5px;
157
+  transition: border-color .2s cubic-bezier(.645,.045,.355,1);
158
+  width: 100%;
159
+}
160
+.el-tag {
161
+  margin-right: 4px;
162
+}
163
+
164
+.tag-input {
165
+  background: transparent;
166
+  border: 0;
167
+  font-size: inherit;
168
+  outline: none;
169
+  padding-left: 0;
170
+  width: 100px;
171
+}
172
+.el-input-tag {
173
+  min-height: 42px;
174
+}
175
+.el-input-tag--small {
176
+  min-height: 32px;
177
+  line-height: 32px;
178
+  font-size: 12px;
179
+}
180
+
181
+.el-input-tag--default {
182
+  min-height: 34px;
183
+  line-height: 34px;
184
+}
185
+
186
+.el-input-tag--large {
187
+  min-height: 36px;
188
+  line-height: 36px;
189
+}
190
+
191
+</style>

+ 133 - 0
src/components/flow/Expression/index.vue

@@ -0,0 +1,133 @@
1
+<template>
2
+  <div class="app-container">
3
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
4
+      <el-form-item label="名称" prop="name">
5
+        <el-input
6
+          v-model="queryParams.name"
7
+          placeholder="请输入表达式名称"
8
+          clearable
9
+          @keyup.enter.native="handleQuery"
10
+        />
11
+      </el-form-item>
12
+      <el-form-item>
13
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
14
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
15
+      </el-form-item>
16
+    </el-form>
17
+
18
+    <el-table v-loading="loading" :data="expressionList" @current-change="handleSingleExpSelect">
19
+      <el-table-column  width="55" align="center" >
20
+        <template slot-scope="scope">
21
+          <!-- 可以手动的修改label的值,从而控制选择哪一项 -->
22
+          <el-radio v-model="radioSelected" :label="scope.row.id">{{''}}</el-radio>
23
+        </template>
24
+      </el-table-column>
25
+      <el-table-column label="名称" align="center" prop="name" />
26
+      <el-table-column label="表达式内容" align="center" prop="expression" />
27
+      <el-table-column label="表达式类型" align="center" prop="dataType" >
28
+        <template slot-scope="scope">
29
+          <dict-tag :options="dict.type.exp_data_type" :value="scope.row.dataType"/>
30
+        </template>
31
+      </el-table-column>
32
+    </el-table>
33
+
34
+    <pagination
35
+      v-show="total>0"
36
+      :total="total"
37
+      :page-sizes="[5,10]"
38
+      layout="prev, pager, next"
39
+      :page.sync="queryParams.pageNum"
40
+      :limit.sync="queryParams.pageSize"
41
+      @pagination="getList"
42
+    />
43
+  </div>
44
+</template>
45
+
46
+<script>
47
+import { listExpression } from "@/api/flowable/expression";
48
+import {StrUtil} from "@/utils/StrUtil";
49
+
50
+export default {
51
+  name: "Expression",
52
+  dicts: ['sys_common_status','exp_data_type'],
53
+  // 接受父组件的值
54
+  props: {
55
+    // 回显数据传值
56
+    selectValues: {
57
+      type: Number | String,
58
+      default: null,
59
+      required: false
60
+    }
61
+  },
62
+  data() {
63
+    return {
64
+      // 遮罩层
65
+      loading: true,
66
+      // 选中数组
67
+      ids: [],
68
+      // 非单个禁用
69
+      single: true,
70
+      // 非多个禁用
71
+      multiple: true,
72
+      // 显示搜索条件
73
+      showSearch: true,
74
+      // 总条数
75
+      total: 0,
76
+      // 流程达式表格数据
77
+      expressionList: [],
78
+      // 弹出层标题
79
+      title: "",
80
+      // 是否显示弹出层
81
+      open: false,
82
+      // 查询参数
83
+      queryParams: {
84
+        pageNum: 1,
85
+        pageSize: 10,
86
+        name: null,
87
+        expression: null,
88
+        status: null,
89
+      },
90
+      radioSelected: null // 单选框传值
91
+    };
92
+  },
93
+  watch: {
94
+    selectValues: {
95
+      handler(newVal) {
96
+        if (StrUtil.isNotBlank(newVal)) {
97
+          this.radioSelected = newVal
98
+        }
99
+      },
100
+      immediate: true,
101
+    }
102
+  },
103
+  created() {
104
+    this.getList();
105
+  },
106
+  methods: {
107
+    /** 查询流程达式列表 */
108
+    getList() {
109
+      this.loading = true;
110
+      listExpression(this.queryParams).then(response => {
111
+        this.expressionList = response.rows;
112
+        this.total = response.total;
113
+        this.loading = false;
114
+      });
115
+    },
116
+    /** 搜索按钮操作 */
117
+    handleQuery() {
118
+      this.queryParams.pageNum = 1;
119
+      this.getList();
120
+    },
121
+    /** 重置按钮操作 */
122
+    resetQuery() {
123
+      this.resetForm("queryForm");
124
+      this.handleQuery();
125
+    },
126
+    // 单选框选中数据
127
+    handleSingleExpSelect(selection) {
128
+      this.radioSelected = selection.id;//点击当前行时,radio同样有选中效果
129
+      this.$emit('handleSingleExpSelect',selection);
130
+    },
131
+  }
132
+};
133
+</script>

+ 187 - 0
src/components/flow/Role/index.vue

@@ -0,0 +1,187 @@
1
+<template>
2
+  <div class="app-container">
3
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
4
+      <el-form-item label="角色名称" prop="roleName">
5
+        <el-input
6
+          v-model="queryParams.roleName"
7
+          placeholder="请输入角色名称"
8
+          clearable
9
+          style="width: 240px"
10
+          @keyup.enter.native="handleQuery"
11
+        />
12
+      </el-form-item>
13
+      <el-form-item>
14
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
15
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
16
+      </el-form-item>
17
+    </el-form>
18
+
19
+    <el-table v-show="checkType === 'multiple'" ref="dataTable"  v-loading="loading" :data="roleList" @selection-change="handleMultipleRoleSelect">
20
+      <el-table-column type="selection" width="50" align="center" />
21
+      <el-table-column label="角色编号" prop="roleId" width="120" />
22
+      <el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
23
+      <el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="150" />
24
+      <el-table-column label="显示顺序" prop="roleSort" width="100" />
25
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
26
+        <template slot-scope="scope">
27
+          <span>{{ parseTime(scope.row.createTime) }}</span>
28
+        </template>
29
+      </el-table-column>
30
+    </el-table>
31
+    <el-table v-show="checkType === 'single'" v-loading="loading" :data="roleList" @current-change="handleSingleRoleSelect">
32
+      <el-table-column  width="55" align="center" >
33
+        <template slot-scope="scope">
34
+          <!-- 可以手动的修改label的值,从而控制选择哪一项 -->
35
+          <el-radio v-model="radioSelected" :label="scope.row.roleId">{{''}}</el-radio>
36
+        </template>
37
+      </el-table-column>
38
+      <el-table-column label="角色编号" prop="roleId" width="120" />
39
+      <el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
40
+      <el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="150" />
41
+      <el-table-column label="显示顺序" prop="roleSort" width="100" />
42
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
43
+        <template slot-scope="scope">
44
+          <span>{{ parseTime(scope.row.createTime) }}</span>
45
+        </template>
46
+      </el-table-column>
47
+    </el-table>
48
+
49
+    <pagination
50
+      v-show="total>0"
51
+      :total="total"
52
+      :page-sizes="[5,10]"
53
+      layout="prev, pager, next"
54
+      :page.sync="queryParams.pageNum"
55
+      :limit.sync="queryParams.pageSize"
56
+      @pagination="getList"
57
+    />
58
+  </div>
59
+</template>
60
+
61
+<script>
62
+import { listRole} from "@/api/system/role";
63
+import {StrUtil} from "@/utils/StrUtil";
64
+
65
+export default {
66
+  name: "FlowRole",
67
+  dicts: ['sys_normal_disable'],
68
+  // 接受父组件的值
69
+  props: {
70
+    // 回显数据传值
71
+    selectValues: {
72
+      type: Number | String | Array,
73
+      default: null,
74
+      required: false
75
+    },
76
+    checkType: {
77
+      type: String,
78
+      default: 'multiple',
79
+      required: false
80
+    },
81
+  },
82
+  data() {
83
+    return {
84
+      // 遮罩层
85
+      loading: true,
86
+      // 选中数组
87
+      ids: [],
88
+      // 非单个禁用
89
+      single: true,
90
+      // 非多个禁用
91
+      multiple: true,
92
+      // 显示搜索条件
93
+      showSearch: true,
94
+      // 总条数
95
+      total: 0,
96
+      // 角色表格数据
97
+      roleList: [],
98
+      // 弹出层标题
99
+      title: "",
100
+      // 是否显示弹出层
101
+      open: false,
102
+      // 查询参数
103
+      queryParams: {
104
+        pageNum: 1,
105
+        pageSize: 5,
106
+        roleName: undefined,
107
+        roleKey: undefined,
108
+        status: undefined
109
+      },
110
+      // 表单参数
111
+      form: {},
112
+      radioSelected: 0, // 单选框传值
113
+      selectRoleList: [] // 回显数据传值
114
+    };
115
+  },
116
+  watch: {
117
+    selectValues: {
118
+      handler(newVal) {
119
+        if (StrUtil.isNotBlank(newVal)) {
120
+          if (newVal instanceof Number || newVal instanceof String) {
121
+            this.radioSelected = newVal
122
+          } else {
123
+            this.selectRoleList = newVal;
124
+          }
125
+        }
126
+      },
127
+      immediate: true
128
+    },
129
+    roleList: {
130
+      handler(newVal) {
131
+        if (StrUtil.isNotBlank(newVal) && this.selectRoleList.length > 0) {
132
+          this.$nextTick(() => {
133
+            this.$refs.dataTable.clearSelection();
134
+            this.selectRoleList?.split(',').forEach(key => {
135
+              this.$refs.dataTable.toggleRowSelection(newVal.find(
136
+                item => key == item.roleId
137
+              ), true)
138
+            });
139
+          });
140
+        }
141
+      }
142
+    }
143
+  },
144
+  created() {
145
+    this.getList();
146
+  },
147
+  methods: {
148
+    /** 查询角色列表 */
149
+    getList() {
150
+      this.loading = true;
151
+      listRole(this.queryParams).then(response => {
152
+          this.roleList = response.rows;
153
+          this.total = response.total;
154
+          this.loading = false;
155
+        }
156
+      );
157
+    },
158
+    // 多选框选中数据
159
+    handleMultipleRoleSelect(selection) {
160
+      const idList = selection.map(item => item.roleId);
161
+      const nameList = selection.map(item => item.roleName);
162
+      this.$emit('handleRoleSelect', idList.join(','), nameList.join(','));
163
+    },
164
+    // 单选框选中数据
165
+    handleSingleRoleSelect(selection) {
166
+      this.radioSelected = selection.roleId;
167
+      const roleName = selection.roleName;
168
+      this.$emit('handleRoleSelect', this.radioSelected.toString(), roleName);
169
+    },
170
+    /** 搜索按钮操作 */
171
+    handleQuery() {
172
+      this.queryParams.pageNum = 1;
173
+      this.getList();
174
+    },
175
+    /** 重置按钮操作 */
176
+    resetQuery() {
177
+      this.handleQuery();
178
+    },
179
+  }
180
+};
181
+</script>
182
+<style>
183
+/*隐藏radio展示的label及本身自带的样式*/
184
+/*.el-radio__label{*/
185
+/*  display:none;*/
186
+/*}*/
187
+</style>

+ 257 - 0
src/components/flow/User/index.vue

@@ -0,0 +1,257 @@
1
+<template>
2
+  <div>
3
+    <el-row :gutter="20">
4
+      <!--部门数据-->
5
+      <el-col :span="6" :xs="24">
6
+        <div class="head-container">
7
+          <el-input
8
+            v-model="deptName"
9
+            placeholder="请输入部门名称"
10
+            clearable
11
+            size="small"
12
+            prefix-icon="el-icon-search"
13
+            style="margin-bottom: 20px"
14
+          />
15
+        </div>
16
+        <div class="head-container">
17
+          <el-tree
18
+            :data="deptOptions"
19
+            :props="defaultProps"
20
+            :expand-on-click-node="false"
21
+            :filter-node-method="filterNode"
22
+            ref="tree"
23
+            node-key="id"
24
+            default-expand-all
25
+            highlight-current
26
+            @node-click="handleNodeClick"
27
+          />
28
+        </div>
29
+      </el-col>
30
+      <!--用户数据-->
31
+      <el-col :span="18" :xs="24">
32
+        <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
33
+          <el-form-item label="用户名称" prop="userName">
34
+            <el-input
35
+              v-model="queryParams.userName"
36
+              placeholder="请输入用户名称"
37
+              clearable
38
+              style="width: 150px"
39
+              @keyup.enter.native="handleQuery"
40
+            />
41
+          </el-form-item>
42
+          <el-form-item>
43
+            <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
44
+            <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
45
+          </el-form-item>
46
+        </el-form>
47
+        <el-table v-show="checkType === 'multiple'" ref="dataTable" v-loading="loading" :row-key="getRowKey" :data="userList" @selection-change="handleMultipleUserSelect">
48
+          <el-table-column type="selection" :reserve-selection="true" width="50" align="center" />
49
+          <el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
50
+          <el-table-column label="登录账号" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
51
+          <el-table-column label="用户姓名" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
52
+          <el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible" :show-overflow-tooltip="true" />
53
+          <el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
54
+        </el-table>
55
+        <el-table v-show="checkType === 'single'" v-loading="loading" :data="userList" @current-change="handleSingleUserSelect">
56
+          <el-table-column  width="55" align="center" >
57
+            <template slot-scope="scope">
58
+              <el-radio v-model="radioSelected" :label="scope.row.userId">{{''}}</el-radio>
59
+            </template>
60
+          </el-table-column>
61
+          <el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
62
+          <el-table-column label="登录账号" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
63
+          <el-table-column label="用户姓名" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
64
+          <el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible" :show-overflow-tooltip="true" />
65
+          <el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
66
+        </el-table>
67
+        <pagination
68
+          v-show="total>0"
69
+          :total="total"
70
+          :page-sizes="[5,10]"
71
+          layout="prev, pager, next"
72
+          :page.sync="queryParams.pageNum"
73
+          :limit.sync="queryParams.pageSize"
74
+          @pagination="getList"
75
+        />
76
+      </el-col>
77
+    </el-row>
78
+  </div>
79
+</template>
80
+
81
+<script>
82
+import { listUser, deptTreeSelect } from "@/api/system/user";
83
+import Treeselect from "@riophae/vue-treeselect";
84
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
85
+import {StrUtil} from '@/utils/StrUtil'
86
+
87
+export default {
88
+  name: "FlowUser",
89
+  dicts: ['sys_normal_disable', 'sys_user_sex'],
90
+  components: { Treeselect },
91
+  // 接受父组件的值
92
+  props: {
93
+    // 回显数据传值
94
+    selectValues: {
95
+      type: Number | String | Array,
96
+      default: null,
97
+      required: false
98
+    },
99
+    // 表格类型
100
+    checkType: {
101
+      type: String,
102
+      default: 'multiple',
103
+      required: true
104
+    },
105
+  },
106
+  data() {
107
+    return {
108
+      // 遮罩层
109
+      loading: true,
110
+      // 选中数组
111
+      ids: [],
112
+      // 非单个禁用
113
+      single: true,
114
+      // 非多个禁用
115
+      multiple: true,
116
+      // 显示搜索条件
117
+      showSearch: true,
118
+      // 总条数
119
+      total: 0,
120
+      // 用户表格数据
121
+      userList: [],
122
+      // 弹出层标题
123
+      title: "",
124
+      // 部门树选项
125
+      deptOptions: undefined,
126
+      // 是否显示弹出层
127
+      open: false,
128
+      // 部门名称
129
+      deptName: undefined,
130
+      // 表单参数
131
+      form: {},
132
+      defaultProps: {
133
+        children: "children",
134
+        label: "label"
135
+      },
136
+      // 查询参数
137
+      queryParams: {
138
+        pageNum: 1,
139
+        pageSize: 5,
140
+        userName: undefined,
141
+        phonenumber: undefined,
142
+        status: undefined,
143
+        deptId: undefined
144
+      },
145
+      // 列信息
146
+      columns: [
147
+        { key: 0, label: `用户编号`, visible: true },
148
+        { key: 1, label: `用户名称`, visible: true },
149
+        { key: 2, label: `用户昵称`, visible: true },
150
+        { key: 3, label: `部门`, visible: true },
151
+        { key: 4, label: `手机号码`, visible: true },
152
+        { key: 5, label: `状态`, visible: true },
153
+        { key: 6, label: `创建时间`, visible: true }
154
+      ],
155
+      radioSelected: 0, // 单选框传值
156
+      selectUserList: [] // 回显数据传值
157
+    };
158
+  },
159
+  watch: {
160
+    // 根据名称筛选部门树
161
+    deptName(val) {
162
+      this.$refs.tree.filter(val);
163
+    },
164
+    selectValues: {
165
+      handler(newVal) {
166
+        if (StrUtil.isNotBlank(newVal)) {
167
+          if (newVal instanceof Number) {
168
+            this.radioSelected = newVal
169
+          } else {
170
+            this.selectUserList = newVal;
171
+          }
172
+        }
173
+      },
174
+      immediate: true
175
+    },
176
+    userList: {
177
+      handler(newVal) {
178
+        debugger
179
+        if (StrUtil.isNotBlank(newVal) && this.selectUserList.length > 0) {
180
+            this.$nextTick(() => {
181
+              this.$refs.dataTable.clearSelection();
182
+              this.selectUserList?.split(',').forEach(key => {
183
+                this.$refs.dataTable.toggleRowSelection(newVal.find(
184
+                  item => key == item.userId
185
+                ), true)
186
+              });
187
+            });
188
+        }
189
+      }
190
+    }
191
+  },
192
+  created() {
193
+    this.getList();
194
+    this.getDeptTree();
195
+  },
196
+  methods: {
197
+    /** 查询用户列表 */
198
+    getList() {
199
+      this.loading = true;
200
+      listUser(this.queryParams).then(response => {
201
+          this.userList = response.rows;
202
+          this.total = response.total;
203
+          this.loading = false;
204
+        }
205
+      );
206
+    },
207
+    /** 查询部门下拉树结构 */
208
+    getDeptTree() {
209
+      deptTreeSelect().then(response => {
210
+        this.deptOptions = response.data;
211
+      });
212
+    },
213
+    // 保存选中的数据id,row-key就是要指定一个key标识这一行的数据
214
+    getRowKey (row) {
215
+      return row.id
216
+    },
217
+    // 筛选节点
218
+    filterNode(value, data) {
219
+      if (!value) return true;
220
+      return data.label.indexOf(value) !== -1;
221
+    },
222
+    // 节点单击事件
223
+    handleNodeClick(data) {
224
+      this.queryParams.deptId = data.id;
225
+      this.handleQuery();
226
+    },
227
+    // 多选框选中数据
228
+    handleMultipleUserSelect(selection) {
229
+      this.$emit('handleUserSelect', selection);
230
+    },
231
+    // 单选框选中数据
232
+    handleSingleUserSelect(selection) {
233
+      this.radioSelected = selection.userId;//点击当前行时,radio同样有选中效果
234
+      this.$emit('handleUserSelect', selection);
235
+    },
236
+    /** 搜索按钮操作 */
237
+    handleQuery() {
238
+      this.queryParams.pageNum = 1;
239
+      this.getList();
240
+    },
241
+    /** 重置按钮操作 */
242
+    resetQuery() {
243
+      this.dateRange = [];
244
+      this.resetForm("queryForm");
245
+      this.queryParams.deptId = undefined;
246
+      this.$refs.tree.setCurrentKey(null);
247
+      this.handleQuery();
248
+    },
249
+  }
250
+};
251
+</script>
252
+<style>
253
+/*隐藏radio展示的label及本身自带的样式*/
254
+/*.el-radio__label{*/
255
+/*  display:none;*/
256
+/*}*/
257
+</style>

+ 12 - 2
src/main.js

@@ -13,7 +13,7 @@ import directive from './directive' // directive
13 13
 import plugins from './plugins' // plugins
14 14
 import { download } from '@/utils/request'
15 15
 import dataV from '@jiaminghi/data-view'
16
-
16
+import  Tinymce from  '@/components/tinymce/index';
17 17
 Vue.use(dataV)
18 18
 import './assets/icons' // icon
19 19
 import './permission' // permission control
@@ -40,7 +40,14 @@ import VueMeta from 'vue-meta'
40 40
 import DictData from '@/components/DictData'
41 41
 import * as echarts from "echarts"
42 42
 import Vue2OrgTree from 'vue2-org-tree'
43
+
44
+import modelerStore from '@/components/Process/common/global'
45
+// vform 表单设计器
46
+import vform from '@/components/vform/VFormDesigner.umd.min.js'
47
+import '@/components/vform/VFormDesigner.css'
43 48
 Vue.use(Vue2OrgTree)
49
+//同时注册了v-form-designer、v-form-render等组件
50
+Vue.use(vform)
44 51
 Vue.prototype.$echarts = echarts
45 52
 // 全局方法挂载
46 53
 Vue.prototype.getDicts = getDicts
@@ -53,7 +60,9 @@ Vue.prototype.selectDictLabels = selectDictLabels
53 60
 Vue.prototype.download = download
54 61
 Vue.prototype.handleTree = handleTree
55 62
 
56
-// 全局组件挂载
63
+
64
+// 全局方法挂载
65
+Vue.prototype.modelerStore = modelerStore
57 66
 Vue.component('DictTag', DictTag)
58 67
 Vue.component('Pagination', Pagination)
59 68
 Vue.component('RightToolbar', RightToolbar)
@@ -61,6 +70,7 @@ Vue.component('Editor', Editor)
61 70
 Vue.component('FileUpload', FileUpload)
62 71
 Vue.component('ImageUpload', ImageUpload)
63 72
 Vue.component('ImagePreview', ImagePreview)
73
+Vue.component('Tinymce', Tinymce)
64 74
 
65 75
 Vue.use(directive)
66 76
 Vue.use(plugins)

+ 92 - 0
src/router/index.js

@@ -284,6 +284,97 @@ export const constantRoutes = [
284 284
         meta: { title: '个人中心', icon: 'user' }
285 285
       }
286 286
     ]
287
+  },
288
+  {
289
+    path: '/flowable',
290
+    component: Layout,
291
+    hidden: true,
292
+    children: [
293
+      {
294
+        path: 'definition/model/',
295
+        component: () => import('@/views/flowable/definition/model'),
296
+        name: 'Model',
297
+        meta: { title: '流程设计', icon: '' }
298
+      }
299
+    ]
300
+  },
301
+  {
302
+    path: '/flowable',
303
+    component: Layout,
304
+    hidden: true,
305
+    children: [
306
+      {
307
+        path: 'task/finished/detail/index',
308
+        component: () => import('@/views/flowable/task/finished/detail/index'),
309
+        name: 'FinishedRecord',
310
+        meta: { title: '流程详情', icon: '' }
311
+      }
312
+    ]
313
+  },
314
+  {
315
+    path: '/flowable',
316
+    component: Layout,
317
+    hidden: true,
318
+    children: [
319
+      {
320
+        path: 'task/myProcess/detail/index',
321
+        component: () => import('@/views/flowable/task/myProcess/detail/index'),
322
+        name: 'MyProcessRecord',
323
+        meta: { title: '流程详情', icon: '' }
324
+      }
325
+    ]
326
+  },
327
+  {
328
+    path: '/flowable',
329
+    component: Layout,
330
+    hidden: true,
331
+    children: [
332
+      {
333
+        path: 'task/myProcess/send/index',
334
+        component: () => import('@/views/flowable/task/myProcess/send/index'),
335
+        name: 'SendRecord',
336
+        meta: { title: '流程发起', icon: '' }
337
+      }
338
+    ]
339
+  },
340
+  {
341
+    path: '/flowable',
342
+    component: Layout,
343
+    hidden: true,
344
+    children: [
345
+      {
346
+        path: 'task/todo/detail/index',
347
+        component: () => import('@/views/flowable/task/todo/detail/index'),
348
+        name: 'TodoRecord',
349
+        meta: { title: '流程处理', icon: '' }
350
+      }
351
+    ]
352
+  },
353
+  {
354
+    path: '/flowable',
355
+    component: Layout,
356
+    hidden: false,
357
+    children: [
358
+      {
359
+        path: 'task/flowForm/index',
360
+        component: () => import('@/views/flowable/task/flowForm/index'),
361
+        name: 'FlowForm',
362
+        meta: { title: '流程表单', icon: '' }
363
+      }
364
+    ]
365
+  },
366
+  {
367
+    path: '/tool',
368
+    component: Layout,
369
+    hidden: true,
370
+    children: [
371
+      {
372
+        path: 'build/index',
373
+        component: () => import('@/views/tool/build/index'),
374
+        name: 'FormBuild',
375
+        meta: { title: '表单配置', icon: '' }
376
+      }
377
+    ]
287 378
   }
288 379
 ]
289 380
 
@@ -359,6 +450,7 @@ export const dynamicRoutes = [
359 450
       }
360 451
     ]
361 452
   }
453
+
362 454
 ]
363 455
 
364 456
 // 防止连续点击多次路由报错

+ 464 - 273
src/utils/generator/config.js

@@ -1,3 +1,4 @@
1
+// 表单属性【右面板】
1 2
 export const formConf = {
2 3
   formRef: 'elForm',
3 4
   formModel: 'formData',
@@ -11,144 +12,195 @@ export const formConf = {
11 12
   formBtns: true
12 13
 }
13 14
 
15
+// 输入型组件 【左面板】
14 16
 export const inputComponents = [
15 17
   {
16
-    label: '单行文本',
17
-    tag: 'el-input',
18
-    tagIcon: 'input',
18
+    // 组件的自定义配置
19
+    __config__: {
20
+      label: '单行文本',
21
+      labelWidth: null,
22
+      showLabel: true,
23
+      changeTag: true,
24
+      tag: 'el-input',
25
+      tagIcon: 'input',
26
+      defaultValue: undefined,
27
+      required: true,
28
+      layout: 'colFormItem',
29
+      span: 24,
30
+      document: 'https://element.eleme.cn/#/zh-CN/component/input',
31
+      // 正则校验规则
32
+      regList: []
33
+    },
34
+    // 组件的插槽属性
35
+    __slot__: {
36
+      prepend: '',
37
+      append: ''
38
+    },
39
+    // 其余的为可直接写在组件标签上的属性
19 40
     placeholder: '请输入',
20
-    defaultValue: undefined,
21
-    span: 24,
22
-    labelWidth: null,
23
-    style: { width: '100%' },
41
+    style: {width: '100%'},
24 42
     clearable: true,
25
-    prepend: '',
26
-    append: '',
27 43
     'prefix-icon': '',
28 44
     'suffix-icon': '',
29 45
     maxlength: null,
30 46
     'show-word-limit': false,
31 47
     readonly: false,
32
-    disabled: false,
33
-    required: true,
34
-    regList: [],
35
-    changeTag: true,
36
-    document: 'https://element.eleme.cn/#/zh-CN/component/input'
48
+    disabled: false
37 49
   },
38 50
   {
39
-    label: '多行文本',
40
-    tag: 'el-input',
41
-    tagIcon: 'textarea',
51
+    __config__: {
52
+      label: '多行文本',
53
+      labelWidth: null,
54
+      showLabel: true,
55
+      tag: 'el-input',
56
+      tagIcon: 'textarea',
57
+      defaultValue: undefined,
58
+      required: true,
59
+      layout: 'colFormItem',
60
+      span: 24,
61
+      regList: [],
62
+      changeTag: true,
63
+      document: 'https://element.eleme.cn/#/zh-CN/component/input'
64
+    },
42 65
     type: 'textarea',
43 66
     placeholder: '请输入',
44
-    defaultValue: undefined,
45
-    span: 24,
46
-    labelWidth: null,
47 67
     autosize: {
48 68
       minRows: 4,
49 69
       maxRows: 4
50 70
     },
51
-    style: { width: '100%' },
71
+    style: {width: '100%'},
52 72
     maxlength: null,
53 73
     'show-word-limit': false,
54 74
     readonly: false,
55
-    disabled: false,
56
-    required: true,
57
-    regList: [],
58
-    changeTag: true,
59
-    document: 'https://element.eleme.cn/#/zh-CN/component/input'
75
+    disabled: false
60 76
   },
61 77
   {
62
-    label: '密码',
63
-    tag: 'el-input',
64
-    tagIcon: 'password',
78
+    __config__: {
79
+      label: '密码',
80
+      showLabel: true,
81
+      labelWidth: null,
82
+      changeTag: true,
83
+      tag: 'el-input',
84
+      tagIcon: 'password',
85
+      defaultValue: undefined,
86
+      layout: 'colFormItem',
87
+      span: 24,
88
+      required: true,
89
+      regList: [],
90
+      document: 'https://element.eleme.cn/#/zh-CN/component/input'
91
+    },
92
+    __slot__: {
93
+      prepend: '',
94
+      append: ''
95
+    },
65 96
     placeholder: '请输入',
66
-    defaultValue: undefined,
67
-    span: 24,
68 97
     'show-password': true,
69
-    labelWidth: null,
70
-    style: { width: '100%' },
98
+    style: {width: '100%'},
71 99
     clearable: true,
72
-    prepend: '',
73
-    append: '',
74 100
     'prefix-icon': '',
75 101
     'suffix-icon': '',
76 102
     maxlength: null,
77 103
     'show-word-limit': false,
78 104
     readonly: false,
79
-    disabled: false,
80
-    required: true,
81
-    regList: [],
82
-    changeTag: true,
83
-    document: 'https://element.eleme.cn/#/zh-CN/component/input'
105
+    disabled: false
84 106
   },
85 107
   {
86
-    label: '计数器',
87
-    tag: 'el-input-number',
88
-    tagIcon: 'number',
108
+    __config__: {
109
+      label: '计数器',
110
+      showLabel: true,
111
+      changeTag: true,
112
+      labelWidth: null,
113
+      tag: 'el-input-number',
114
+      tagIcon: 'number',
115
+      defaultValue: undefined,
116
+      span: 24,
117
+      layout: 'colFormItem',
118
+      required: true,
119
+      regList: [],
120
+      document: 'https://element.eleme.cn/#/zh-CN/component/input-number'
121
+    },
89 122
     placeholder: '',
90
-    defaultValue: undefined,
91
-    span: 24,
92
-    labelWidth: null,
93 123
     min: undefined,
94 124
     max: undefined,
95
-    step: undefined,
125
+    step: 1,
96 126
     'step-strictly': false,
97 127
     precision: undefined,
98 128
     'controls-position': '',
99
-    disabled: false,
100
-    required: true,
101
-    regList: [],
102
-    changeTag: true,
103
-    document: 'https://element.eleme.cn/#/zh-CN/component/input-number'
129
+    disabled: false
130
+  },
131
+  {
132
+    __config__: {
133
+      label: '编辑器',
134
+      showLabel: true,
135
+      changeTag: true,
136
+      labelWidth: null,
137
+      tag: 'tinymce',
138
+      tagIcon: 'rich-text',
139
+      defaultValue: null,
140
+      span: 24,
141
+      layout: 'colFormItem',
142
+      required: true,
143
+      regList: [],
144
+      document: 'http://tinymce.ax-z.cn'
145
+    },
146
+    placeholder: '请输入',
147
+    height: 300, // 编辑器高度
148
+    branding: false // 隐藏右下角品牌烙印
104 149
   }
105 150
 ]
106 151
 
152
+// 选择型组件 【左面板】
107 153
 export const selectComponents = [
108 154
   {
109
-    label: '下拉选择',
110
-    tag: 'el-select',
111
-    tagIcon: 'select',
155
+    __config__: {
156
+      label: '下拉选择',
157
+      showLabel: true,
158
+      labelWidth: null,
159
+      tag: 'el-select',
160
+      tagIcon: 'select',
161
+      layout: 'colFormItem',
162
+      span: 24,
163
+      required: true,
164
+      regList: [],
165
+      changeTag: true,
166
+      document: 'https://element.eleme.cn/#/zh-CN/component/select'
167
+    },
168
+    __slot__: {
169
+      options: [{
170
+        label: '选项一',
171
+        value: 1
172
+      }, {
173
+        label: '选项二',
174
+        value: 2
175
+      }]
176
+    },
112 177
     placeholder: '请选择',
113
-    defaultValue: undefined,
114
-    span: 24,
115
-    labelWidth: null,
116
-    style: { width: '100%' },
178
+    style: {width: '100%'},
117 179
     clearable: true,
118 180
     disabled: false,
119
-    required: true,
120 181
     filterable: false,
121
-    multiple: false,
122
-    options: [{
123
-      label: '选项一',
124
-      value: 1
125
-    }, {
126
-      label: '选项二',
127
-      value: 2
128
-    }],
129
-    regList: [],
130
-    changeTag: true,
131
-    document: 'https://element.eleme.cn/#/zh-CN/component/select'
182
+    multiple: false
132 183
   },
133 184
   {
134
-    label: '级联选择',
135
-    tag: 'el-cascader',
136
-    tagIcon: 'cascader',
137
-    placeholder: '请选择',
138
-    defaultValue: [],
139
-    span: 24,
140
-    labelWidth: null,
141
-    style: { width: '100%' },
142
-    props: {
143
-      props: {
144
-        multiple: false
145
-      }
185
+    __config__: {
186
+      label: '级联选择',
187
+      url: 'https://www.fastmock.site/mock/f8d7a54fb1e60561e2f720d5a810009d/fg/cascaderList',
188
+      method: 'get',
189
+      dataPath: 'list',
190
+      dataConsumer: 'options',
191
+      showLabel: true,
192
+      labelWidth: null,
193
+      tag: 'el-cascader',
194
+      tagIcon: 'cascader',
195
+      layout: 'colFormItem',
196
+      defaultValue: [],
197
+      dataType: 'dynamic',
198
+      span: 24,
199
+      required: true,
200
+      regList: [],
201
+      changeTag: true,
202
+      document: 'https://element.eleme.cn/#/zh-CN/component/cascader'
146 203
     },
147
-    'show-all-levels': true,
148
-    disabled: false,
149
-    clearable: true,
150
-    filterable: false,
151
-    required: true,
152 204
     options: [{
153 205
       id: 1,
154 206
       value: 1,
@@ -159,280 +211,419 @@ export const selectComponents = [
159 211
         label: '选项1-1'
160 212
       }]
161 213
     }],
162
-    dataType: 'dynamic',
163
-    labelKey: 'label',
164
-    valueKey: 'value',
165
-    childrenKey: 'children',
166
-    separator: '/',
167
-    regList: [],
168
-    changeTag: true,
169
-    document: 'https://element.eleme.cn/#/zh-CN/component/cascader'
214
+    placeholder: '请选择',
215
+    style: {width: '100%'},
216
+    props: {
217
+      props: {
218
+        multiple: false,
219
+        label: 'label',
220
+        value: 'value',
221
+        children: 'children'
222
+      }
223
+    },
224
+    'show-all-levels': true,
225
+    disabled: false,
226
+    clearable: true,
227
+    filterable: false,
228
+    separator: '/'
170 229
   },
171 230
   {
172
-    label: '单选框组',
173
-    tag: 'el-radio-group',
174
-    tagIcon: 'radio',
175
-    defaultValue: undefined,
176
-    span: 24,
177
-    labelWidth: null,
231
+    __config__: {
232
+      label: '单选框组',
233
+      labelWidth: null,
234
+      showLabel: true,
235
+      tag: 'el-radio-group',
236
+      tagIcon: 'radio',
237
+      changeTag: true,
238
+      defaultValue: undefined,
239
+      layout: 'colFormItem',
240
+      span: 24,
241
+      optionType: 'default',
242
+      regList: [],
243
+      required: true,
244
+      border: false,
245
+      document: 'https://element.eleme.cn/#/zh-CN/component/radio'
246
+    },
247
+    __slot__: {
248
+      options: [{
249
+        label: '选项一',
250
+        value: 1
251
+      }, {
252
+        label: '选项二',
253
+        value: 2
254
+      }]
255
+    },
178 256
     style: {},
179
-    optionType: 'default',
180
-    border: false,
181 257
     size: 'medium',
182
-    disabled: false,
183
-    required: true,
184
-    options: [{
185
-      label: '选项一',
186
-      value: 1
187
-    }, {
188
-      label: '选项二',
189
-      value: 2
190
-    }],
191
-    regList: [],
192
-    changeTag: true,
193
-    document: 'https://element.eleme.cn/#/zh-CN/component/radio'
258
+    disabled: false
194 259
   },
195 260
   {
196
-    label: '多选框组',
197
-    tag: 'el-checkbox-group',
198
-    tagIcon: 'checkbox',
199
-    defaultValue: [],
200
-    span: 24,
201
-    labelWidth: null,
261
+    __config__: {
262
+      label: '多选框组',
263
+      tag: 'el-checkbox-group',
264
+      tagIcon: 'checkbox',
265
+      defaultValue: [],
266
+      span: 24,
267
+      showLabel: true,
268
+      labelWidth: null,
269
+      layout: 'colFormItem',
270
+      optionType: 'default',
271
+      required: true,
272
+      regList: [],
273
+      changeTag: true,
274
+      border: false,
275
+      document: 'https://element.eleme.cn/#/zh-CN/component/checkbox'
276
+    },
277
+    __slot__: {
278
+      options: [{
279
+        label: '选项一',
280
+        value: 1
281
+      }, {
282
+        label: '选项二',
283
+        value: 2
284
+      }]
285
+    },
202 286
     style: {},
203
-    optionType: 'default',
204
-    border: false,
205 287
     size: 'medium',
206
-    disabled: false,
207
-    required: true,
208
-    options: [{
209
-      label: '选项一',
210
-      value: 1
211
-    }, {
212
-      label: '选项二',
213
-      value: 2
214
-    }],
215
-    regList: [],
216
-    changeTag: true,
217
-    document: 'https://element.eleme.cn/#/zh-CN/component/checkbox'
288
+    min: null,
289
+    max: null,
290
+    disabled: false
218 291
   },
219 292
   {
220
-    label: '开关',
221
-    tag: 'el-switch',
222
-    tagIcon: 'switch',
223
-    defaultValue: false,
224
-    span: 24,
225
-    labelWidth: null,
293
+    __config__: {
294
+      label: '开关',
295
+      tag: 'el-switch',
296
+      tagIcon: 'switch',
297
+      defaultValue: false,
298
+      span: 24,
299
+      showLabel: true,
300
+      labelWidth: null,
301
+      layout: 'colFormItem',
302
+      required: true,
303
+      regList: [],
304
+      changeTag: true,
305
+      document: 'https://element.eleme.cn/#/zh-CN/component/switch'
306
+    },
226 307
     style: {},
227 308
     disabled: false,
228
-    required: true,
229 309
     'active-text': '',
230 310
     'inactive-text': '',
231 311
     'active-color': null,
232 312
     'inactive-color': null,
233 313
     'active-value': true,
234
-    'inactive-value': false,
235
-    regList: [],
236
-    changeTag: true,
237
-    document: 'https://element.eleme.cn/#/zh-CN/component/switch'
314
+    'inactive-value': false
238 315
   },
239 316
   {
240
-    label: '滑块',
241
-    tag: 'el-slider',
242
-    tagIcon: 'slider',
243
-    defaultValue: null,
244
-    span: 24,
245
-    labelWidth: null,
317
+    __config__: {
318
+      label: '滑块',
319
+      tag: 'el-slider',
320
+      tagIcon: 'slider',
321
+      defaultValue: null,
322
+      span: 24,
323
+      showLabel: true,
324
+      layout: 'colFormItem',
325
+      labelWidth: null,
326
+      required: true,
327
+      regList: [],
328
+      changeTag: true,
329
+      document: 'https://element.eleme.cn/#/zh-CN/component/slider'
330
+    },
246 331
     disabled: false,
247
-    required: true,
248 332
     min: 0,
249 333
     max: 100,
250 334
     step: 1,
251 335
     'show-stops': false,
252
-    range: false,
253
-    regList: [],
254
-    changeTag: true,
255
-    document: 'https://element.eleme.cn/#/zh-CN/component/slider'
336
+    range: false
256 337
   },
257 338
   {
258
-    label: '时间选择',
259
-    tag: 'el-time-picker',
260
-    tagIcon: 'time',
339
+    __config__: {
340
+      label: '时间选择',
341
+      tag: 'el-time-picker',
342
+      tagIcon: 'time',
343
+      defaultValue: null,
344
+      span: 24,
345
+      showLabel: true,
346
+      layout: 'colFormItem',
347
+      labelWidth: null,
348
+      required: true,
349
+      regList: [],
350
+      changeTag: true,
351
+      document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
352
+    },
261 353
     placeholder: '请选择',
262
-    defaultValue: null,
263
-    span: 24,
264
-    labelWidth: null,
265
-    style: { width: '100%' },
354
+    style: {width: '100%'},
266 355
     disabled: false,
267 356
     clearable: true,
268
-    required: true,
269 357
     'picker-options': {
270 358
       selectableRange: '00:00:00-23:59:59'
271 359
     },
272 360
     format: 'HH:mm:ss',
273
-    'value-format': 'HH:mm:ss',
274
-    regList: [],
275
-    changeTag: true,
276
-    document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
361
+    'value-format': 'HH:mm:ss'
277 362
   },
278 363
   {
279
-    label: '时间范围',
280
-    tag: 'el-time-picker',
281
-    tagIcon: 'time-range',
282
-    defaultValue: null,
283
-    span: 24,
284
-    labelWidth: null,
285
-    style: { width: '100%' },
364
+    __config__: {
365
+      label: '时间范围',
366
+      tag: 'el-time-picker',
367
+      tagIcon: 'time-range',
368
+      span: 24,
369
+      showLabel: true,
370
+      labelWidth: null,
371
+      layout: 'colFormItem',
372
+      defaultValue: null,
373
+      required: true,
374
+      regList: [],
375
+      changeTag: true,
376
+      document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
377
+    },
378
+    style: {width: '100%'},
286 379
     disabled: false,
287 380
     clearable: true,
288
-    required: true,
289 381
     'is-range': true,
290 382
     'range-separator': '至',
291 383
     'start-placeholder': '开始时间',
292 384
     'end-placeholder': '结束时间',
293 385
     format: 'HH:mm:ss',
294
-    'value-format': 'HH:mm:ss',
295
-    regList: [],
296
-    changeTag: true,
297
-    document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
386
+    'value-format': 'HH:mm:ss'
298 387
   },
299 388
   {
300
-    label: '日期选择',
301
-    tag: 'el-date-picker',
302
-    tagIcon: 'date',
389
+    __config__: {
390
+      label: '日期选择',
391
+      tag: 'el-date-picker',
392
+      tagIcon: 'date',
393
+      defaultValue: null,
394
+      showLabel: true,
395
+      labelWidth: null,
396
+      span: 24,
397
+      layout: 'colFormItem',
398
+      required: true,
399
+      regList: [],
400
+      changeTag: true,
401
+      document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
402
+    },
303 403
     placeholder: '请选择',
304
-    defaultValue: null,
305 404
     type: 'date',
306
-    span: 24,
307
-    labelWidth: null,
308
-    style: { width: '100%' },
405
+    style: {width: '100%'},
309 406
     disabled: false,
310 407
     clearable: true,
311
-    required: true,
312 408
     format: 'yyyy-MM-dd',
313 409
     'value-format': 'yyyy-MM-dd',
314
-    readonly: false,
315
-    regList: [],
316
-    changeTag: true,
317
-    document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
410
+    readonly: false
318 411
   },
319 412
   {
320
-    label: '日期范围',
321
-    tag: 'el-date-picker',
322
-    tagIcon: 'date-range',
323
-    defaultValue: null,
324
-    span: 24,
325
-    labelWidth: null,
326
-    style: { width: '100%' },
413
+    __config__: {
414
+      label: '日期范围',
415
+      tag: 'el-date-picker',
416
+      tagIcon: 'date-range',
417
+      defaultValue: null,
418
+      span: 24,
419
+      showLabel: true,
420
+      labelWidth: null,
421
+      required: true,
422
+      layout: 'colFormItem',
423
+      regList: [],
424
+      changeTag: true,
425
+      document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
426
+    },
427
+    style: {width: '100%'},
327 428
     type: 'daterange',
328 429
     'range-separator': '至',
329 430
     'start-placeholder': '开始日期',
330 431
     'end-placeholder': '结束日期',
331 432
     disabled: false,
332 433
     clearable: true,
333
-    required: true,
334 434
     format: 'yyyy-MM-dd',
335 435
     'value-format': 'yyyy-MM-dd',
336
-    readonly: false,
337
-    regList: [],
338
-    changeTag: true,
339
-    document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
436
+    readonly: false
340 437
   },
341 438
   {
342
-    label: '评分',
343
-    tag: 'el-rate',
344
-    tagIcon: 'rate',
345
-    defaultValue: 0,
346
-    span: 24,
347
-    labelWidth: null,
439
+    __config__: {
440
+      label: '评分',
441
+      tag: 'el-rate',
442
+      tagIcon: 'rate',
443
+      defaultValue: 0,
444
+      span: 24,
445
+      showLabel: true,
446
+      labelWidth: null,
447
+      layout: 'colFormItem',
448
+      required: true,
449
+      regList: [],
450
+      changeTag: true,
451
+      document: 'https://element.eleme.cn/#/zh-CN/component/rate'
452
+    },
348 453
     style: {},
349 454
     max: 5,
350 455
     'allow-half': false,
351 456
     'show-text': false,
352 457
     'show-score': false,
353
-    disabled: false,
354
-    required: true,
355
-    regList: [],
356
-    changeTag: true,
357
-    document: 'https://element.eleme.cn/#/zh-CN/component/rate'
458
+    disabled: false
358 459
   },
359 460
   {
360
-    label: '颜色选择',
361
-    tag: 'el-color-picker',
362
-    tagIcon: 'color',
363
-    defaultValue: null,
364
-    labelWidth: null,
461
+    __config__: {
462
+      label: '颜色选择',
463
+      tag: 'el-color-picker',
464
+      tagIcon: 'color',
465
+      span: 24,
466
+      defaultValue: null,
467
+      showLabel: true,
468
+      labelWidth: null,
469
+      layout: 'colFormItem',
470
+      required: true,
471
+      regList: [],
472
+      changeTag: true,
473
+      document: 'https://element.eleme.cn/#/zh-CN/component/color-picker'
474
+    },
365 475
     'show-alpha': false,
366 476
     'color-format': '',
367 477
     disabled: false,
368
-    required: true,
369
-    size: 'medium',
370
-    regList: [],
371
-    changeTag: true,
372
-    document: 'https://element.eleme.cn/#/zh-CN/component/color-picker'
478
+    size: 'medium'
373 479
   },
374 480
   {
375
-    label: '上传',
376
-    tag: 'el-upload',
377
-    tagIcon: 'upload',
378
-    action: 'https://jsonplaceholder.typicode.com/posts/',
379
-    defaultValue: null,
380
-    labelWidth: null,
481
+    __config__: {
482
+      label: '上传',
483
+      tag: 'el-upload',
484
+      tagIcon: 'upload',
485
+      layout: 'colFormItem',
486
+      defaultValue: null,
487
+      showLabel: true,
488
+      labelWidth: null,
489
+      required: true,
490
+      span: 24,
491
+      showTip: false,
492
+      buttonText: '点击上传',
493
+      regList: [],
494
+      changeTag: true,
495
+      fileSize: 2,
496
+      sizeUnit: 'MB',
497
+      document: 'https://element.eleme.cn/#/zh-CN/component/upload'
498
+    },
499
+    __slot__: {
500
+      'list-type': true
501
+    },
502
+    action: 'http://localhost:8080/file/upload',
381 503
     disabled: false,
382
-    required: true,
383 504
     accept: '',
384 505
     name: 'file',
385 506
     'auto-upload': true,
386
-    showTip: false,
387
-    buttonText: '点击上传',
388
-    fileSize: 2,
389
-    sizeUnit: 'MB',
390 507
     'list-type': 'text',
391
-    multiple: false,
392
-    regList: [],
393
-    changeTag: true,
394
-    document: 'https://element.eleme.cn/#/zh-CN/component/upload'
508
+    multiple: false
395 509
   }
396 510
 ]
397 511
 
512
+// 布局型组件 【左面板】
398 513
 export const layoutComponents = [
399 514
   {
400
-    layout: 'rowFormItem',
401
-    tagIcon: 'row',
515
+    __config__: {
516
+      layout: 'rowFormItem',
517
+      tagIcon: 'row',
518
+      label: '行容器',
519
+      layoutTree: true,
520
+      document: 'https://element.eleme.cn/#/zh-CN/component/layout#row-attributes'
521
+    },
402 522
     type: 'default',
403 523
     justify: 'start',
404
-    align: 'top',
405
-    label: '行容器',
406
-    layoutTree: true,
407
-    children: [],
408
-    document: 'https://element.eleme.cn/#/zh-CN/component/layout'
524
+    align: 'top'
409 525
   },
410 526
   {
411
-    layout: 'colFormItem',
412
-    label: '按钮',
413
-    changeTag: true,
414
-    labelWidth: null,
415
-    tag: 'el-button',
416
-    tagIcon: 'button',
417
-    span: 24,
418
-    default: '主要按钮',
527
+    __config__: {
528
+      label: '按钮',
529
+      showLabel: true,
530
+      changeTag: true,
531
+      labelWidth: null,
532
+      tag: 'el-button',
533
+      tagIcon: 'button',
534
+      span: 24,
535
+      layout: 'colFormItem',
536
+      document: 'https://element.eleme.cn/#/zh-CN/component/button'
537
+    },
538
+    __slot__: {
539
+      default: '主要按钮'
540
+    },
419 541
     type: 'primary',
420 542
     icon: 'el-icon-search',
543
+    round: false,
421 544
     size: 'medium',
422
-    disabled: false,
423
-    document: 'https://element.eleme.cn/#/zh-CN/component/button'
424
-  }
545
+    plain: false,
546
+    circle: false,
547
+    disabled: false
548
+  },
549
+  // {
550
+  //   __config__: {
551
+  //     layout: 'colFormItem',
552
+  //     tagIcon: 'table',
553
+  //     tag: 'el-table',
554
+  //     document: 'https://element.eleme.cn/#/zh-CN/component/table',
555
+  //     span: 24,
556
+  //     formId: 101,
557
+  //     renderKey: 1595761764203,
558
+  //     componentName: 'row101',
559
+  //     showLabel: true,
560
+  //     changeTag: true,
561
+  //     labelWidth: null,
562
+  //     label: '表格[开发中]',
563
+  //     dataType: 'dynamic',
564
+  //     method: 'get',
565
+  //     dataPath: 'list',
566
+  //     dataConsumer: 'data',
567
+  //     url: 'https://www.fastmock.site/mock/f8d7a54fb1e60561e2f720d5a810009d/fg/tableData',
568
+  //     children: [{
569
+  //       __config__: {
570
+  //         layout: 'raw',
571
+  //         tag: 'el-table-column',
572
+  //         renderKey: 15957617660153
573
+  //       },
574
+  //       prop: 'date',
575
+  //       label: '日期'
576
+  //     }, {
577
+  //       __config__: {
578
+  //         layout: 'raw',
579
+  //         tag: 'el-table-column',
580
+  //         renderKey: 15957617660152
581
+  //       },
582
+  //       prop: 'address',
583
+  //       label: '地址'
584
+  //     }, {
585
+  //       __config__: {
586
+  //         layout: 'raw',
587
+  //         tag: 'el-table-column',
588
+  //         renderKey: 15957617660151
589
+  //       },
590
+  //       prop: 'name',
591
+  //       label: '名称'
592
+  //     }, {
593
+  //       __config__: {
594
+  //         layout: 'raw',
595
+  //         tag: 'el-table-column',
596
+  //         renderKey: 1595774496335,
597
+  //         children: [
598
+  //           {
599
+  //             __config__: {
600
+  //               label: '按钮',
601
+  //               tag: 'el-button',
602
+  //               tagIcon: 'button',
603
+  //               layout: 'raw',
604
+  //               renderKey: 1595779809901
605
+  //             },
606
+  //             __slot__: {
607
+  //               default: '主要按钮'
608
+  //             },
609
+  //             type: 'primary',
610
+  //             icon: 'el-icon-search',
611
+  //             round: false,
612
+  //             size: 'medium'
613
+  //           }
614
+  //         ]
615
+  //       },
616
+  //       label: '操作'
617
+  //     }]
618
+  //   },
619
+  //   data: [],
620
+  //   directives: [{
621
+  //     name: 'loading',
622
+  //     value: true
623
+  //   }],
624
+  //   border: true,
625
+  //   type: 'default',
626
+  //   justify: 'start',
627
+  //   align: 'top'
628
+  // }
425 629
 ]
426
-
427
-// 组件rule的触发方式,无触发方式的组件不生成rule
428
-export const trigger = {
429
-  'el-input': 'blur',
430
-  'el-input-number': 'blur',
431
-  'el-select': 'change',
432
-  'el-radio-group': 'change',
433
-  'el-checkbox-group': 'change',
434
-  'el-cascader': 'change',
435
-  'el-time-picker': 'change',
436
-  'el-date-picker': 'change',
437
-  'el-rate': 'change'
438
-}

+ 37 - 0
src/utils/generator/drawingDefalut.js

@@ -0,0 +1,37 @@
1
+export default [
2
+  {
3
+    __config__: {
4
+      label: '单行文本',
5
+      labelWidth: null,
6
+      showLabel: true,
7
+      changeTag: true,
8
+      tag: 'el-input',
9
+      tagIcon: 'input',
10
+      defaultValue: undefined,
11
+      required: true,
12
+      layout: 'colFormItem',
13
+      span: 24,
14
+      document: 'https://element.eleme.cn/#/zh-CN/component/input',
15
+      // 正则校验规则
16
+      regList: [{
17
+        pattern: '/^1(3|4|5|7|8|9)\\d{9}$/',
18
+        message: '手机号格式错误'
19
+      }]
20
+    },
21
+    // 组件的插槽属性
22
+    __slot__: {
23
+      prepend: '',
24
+      append: ''
25
+    },
26
+    __vModel__: 'mobile',
27
+    placeholder: '请输入手机号',
28
+    style: { width: '100%' },
29
+    clearable: true,
30
+    'prefix-icon': 'el-icon-mobile',
31
+    'suffix-icon': '',
32
+    maxlength: 11,
33
+    'show-word-limit': true,
34
+    readonly: false,
35
+    disabled: false
36
+  }
37
+]

+ 0 - 29
src/utils/generator/drawingDefault.js

@@ -1,29 +0,0 @@
1
-export default [
2
-  {
3
-    layout: 'colFormItem',
4
-    tagIcon: 'input',
5
-    label: '手机号',
6
-    vModel: 'mobile',
7
-    formId: 6,
8
-    tag: 'el-input',
9
-    placeholder: '请输入手机号',
10
-    defaultValue: '',
11
-    span: 24,
12
-    style: { width: '100%' },
13
-    clearable: true,
14
-    prepend: '',
15
-    append: '',
16
-    'prefix-icon': 'el-icon-mobile',
17
-    'suffix-icon': '',
18
-    maxlength: 11,
19
-    'show-word-limit': true,
20
-    readonly: false,
21
-    disabled: false,
22
-    required: true,
23
-    changeTag: true,
24
-    regList: [{
25
-      pattern: '/^1(3|4|5|7|8|9)\\d{9}$/',
26
-      message: '手机号格式错误'
27
-    }]
28
-  }
29
-]

+ 57 - 20
src/utils/index.js

@@ -5,12 +5,12 @@ import { parseTime } from './ruoyi'
5 5
  */
6 6
 export function formatDate(cellValue) {
7 7
   if (cellValue == null || cellValue == "") return "";
8
-  var date = new Date(cellValue) 
8
+  var date = new Date(cellValue)
9 9
   var year = date.getFullYear()
10 10
   var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
11
-  var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate() 
12
-  var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours() 
13
-  var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes() 
11
+  var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
12
+  var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
13
+  var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
14 14
   var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
15 15
   return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
16 16
 }
@@ -257,20 +257,20 @@ export function debounce(func, wait, immediate) {
257 257
  * @param {Object} source
258 258
  * @returns {Object}
259 259
  */
260
-export function deepClone(source) {
261
-  if (!source && typeof source !== 'object') {
262
-    throw new Error('error arguments', 'deepClone')
263
-  }
264
-  const targetObj = source.constructor === Array ? [] : {}
265
-  Object.keys(source).forEach(keys => {
266
-    if (source[keys] && typeof source[keys] === 'object') {
267
-      targetObj[keys] = deepClone(source[keys])
268
-    } else {
269
-      targetObj[keys] = source[keys]
270
-    }
271
-  })
272
-  return targetObj
273
-}
260
+// export function deepClone(source) {
261
+//   if (!source && typeof source !== 'object') {
262
+//     throw new Error('error arguments', 'deepClone')
263
+//   }
264
+//   const targetObj = source.constructor === Array ? [] : {}
265
+//   Object.keys(source).forEach(keys => {
266
+//     if (source[keys] && typeof source[keys] === 'object') {
267
+//       targetObj[keys] = deepClone(source[keys])
268
+//     } else {
269
+//       targetObj[keys] = source[keys]
270
+//     }
271
+//   })
272
+//   return targetObj
273
+// }
274 274
 
275 275
 /**
276 276
  * @param {Array} arr
@@ -330,7 +330,7 @@ export function makeMap(str, expectsLowerCase) {
330 330
     ? val => map[val.toLowerCase()]
331 331
     : val => map[val]
332 332
 }
333
- 
333
+
334 334
 export const exportDefault = 'export default '
335 335
 
336 336
 export const beautifierConf = {
@@ -387,4 +387,41 @@ export function camelCase(str) {
387 387
 export function isNumberStr(str) {
388 388
   return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
389 389
 }
390
- 
390
+// 深拷贝对象
391
+export function deepClone(obj) {
392
+  const _toString = Object.prototype.toString
393
+
394
+  // null, undefined, non-object, function
395
+  if (!obj || typeof obj !== 'object') {
396
+    return obj
397
+  }
398
+
399
+  // DOM Node
400
+  if (obj.nodeType && 'cloneNode' in obj) {
401
+    return obj.cloneNode(true)
402
+  }
403
+
404
+  // Date
405
+  if (_toString.call(obj) === '[object Date]') {
406
+    return new Date(obj.getTime())
407
+  }
408
+
409
+  // RegExp
410
+  if (_toString.call(obj) === '[object RegExp]') {
411
+    const flags = []
412
+    if (obj.global) { flags.push('g') }
413
+    if (obj.multiline) { flags.push('m') }
414
+    if (obj.ignoreCase) { flags.push('i') }
415
+
416
+    return new RegExp(obj.source, flags.join(''))
417
+  }
418
+
419
+  const result = Array.isArray(obj) ? [] : obj.constructor ? new obj.constructor() : {}
420
+
421
+  for (const key in obj) {
422
+    result[key] = deepClone(obj[key])
423
+  }
424
+
425
+  return result
426
+}
427
+

+ 4 - 8
src/utils/permission.js

@@ -15,10 +15,8 @@ export function checkPermi(value) {
15 15
       return all_permission === permission || permissionDatas.includes(permission)
16 16
     })
17 17
 
18
-    if (!hasPermission) {
19
-      return false
20
-    }
21
-    return true
18
+    return hasPermission;
19
+
22 20
   } else {
23 21
     console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`)
24 22
     return false
@@ -40,10 +38,8 @@ export function checkRole(value) {
40 38
       return super_admin === role || permissionRoles.includes(role)
41 39
     })
42 40
 
43
-    if (!hasRole) {
44
-      return false
45
-    }
46
-    return true
41
+    return hasRole;
42
+
47 43
   } else {
48 44
     console.error(`need roles! Like checkRole="['admin','editor']"`)
49 45
     return false

+ 6 - 2
src/views/tool/build/CodeTypeDialog.vue

@@ -41,7 +41,7 @@
41 41
         <el-button @click="close">
42 42
           取消
43 43
         </el-button>
44
-        <el-button type="primary" @click="handleConfirm">
44
+        <el-button type="primary" @click="handelConfirm">
45 45
           确定
46 46
         </el-button>
47 47
       </div>
@@ -94,7 +94,7 @@ export default {
94 94
     close(e) {
95 95
       this.$emit('update:visible', false)
96 96
     },
97
-    handleConfirm() {
97
+    handelConfirm() {
98 98
       this.$refs.elForm.validate(valid => {
99 99
         if (!valid) return
100 100
         this.$emit('confirm', { ...this.formData })
@@ -104,3 +104,7 @@ export default {
104 104
   }
105 105
 }
106 106
 </script>
107
+
108
+<style lang="scss" scoped>
109
+
110
+</style>

+ 55 - 35
src/views/tool/build/DraggableItem.vue

@@ -1,18 +1,18 @@
1 1
 <script>
2 2
 import draggable from 'vuedraggable'
3
-import render from '@/utils/generator/render'
3
+import render from '@/components/render/render'
4 4
 
5 5
 const components = {
6
-  itemBtns(h, element, index, parent) {
6
+  itemBtns(h, currentItem, index, list) {
7 7
     const { copyItem, deleteItem } = this.$listeners
8 8
     return [
9 9
       <span class="drawing-item-copy" title="复制" onClick={event => {
10
-        copyItem(element, parent); event.stopPropagation()
10
+        copyItem(currentItem, list); event.stopPropagation()
11 11
       }}>
12 12
         <i class="el-icon-copy-document" />
13 13
       </span>,
14 14
       <span class="drawing-item-delete" title="删除" onClick={event => {
15
-        deleteItem(index, parent); event.stopPropagation()
15
+        deleteItem(index, list); event.stopPropagation()
16 16
       }}>
17 17
         <i class="el-icon-delete" />
18 18
       </span>
@@ -20,60 +20,80 @@ const components = {
20 20
   }
21 21
 }
22 22
 const layouts = {
23
-  colFormItem(h, element, index, parent) {
23
+  colFormItem(h, currentItem, index, list) {
24 24
     const { activeItem } = this.$listeners
25
-    let className = this.activeId === element.formId ? 'drawing-item active-from-item' : 'drawing-item'
25
+    const config = currentItem.__config__
26
+    const child = renderChildren.apply(this, arguments)
27
+    let className = this.activeId === config.formId ? 'drawing-item active-from-item' : 'drawing-item'
26 28
     if (this.formConf.unFocusedComponentBorder) className += ' unfocus-bordered'
29
+    let labelWidth = config.labelWidth ? `${config.labelWidth}px` : null
30
+    if (config.showLabel === false) labelWidth = '0'
27 31
     return (
28
-      <el-col span={element.span} class={className}
29
-        nativeOnClick={event => { activeItem(element); event.stopPropagation() }}>
30
-        <el-form-item label-width={element.labelWidth ? `${element.labelWidth}px` : null}
31
-          label={element.label} required={element.required}>
32
-          <render key={element.renderKey} conf={element} onInput={ event => {
33
-            this.$set(element, 'defaultValue', event)
34
-          }} />
32
+      <el-col span={config.span} class={className}
33
+              nativeOnClick={event => { activeItem(currentItem); event.stopPropagation() }}>
34
+        <el-form-item label-width={labelWidth}
35
+                      label={config.showLabel ? config.label : ''} required={config.required}>
36
+          <render key={config.renderKey} conf={currentItem} onInput={ event => {
37
+            this.$set(config, 'defaultValue', event)
38
+          }}>
39
+            {child}
40
+          </render>
35 41
         </el-form-item>
36 42
         {components.itemBtns.apply(this, arguments)}
37 43
       </el-col>
38 44
     )
39 45
   },
40
-  rowFormItem(h, element, index, parent) {
46
+  rowFormItem(h, currentItem, index, list) {
41 47
     const { activeItem } = this.$listeners
42
-    const className = this.activeId === element.formId ? 'drawing-row-item active-from-item' : 'drawing-row-item'
48
+    const config = currentItem.__config__
49
+    const className = this.activeId === config.formId
50
+      ? 'drawing-row-item active-from-item'
51
+      : 'drawing-row-item'
43 52
     let child = renderChildren.apply(this, arguments)
44
-    if (element.type === 'flex') {
45
-      child = <el-row type={element.type} justify={element.justify} align={element.align}>
46
-              {child}
47
-            </el-row>
53
+    if (currentItem.type === 'flex') {
54
+      child = <el-row type={currentItem.type} justify={currentItem.justify} align={currentItem.align}>
55
+        {child}
56
+      </el-row>
48 57
     }
49 58
     return (
50
-      <el-col span={element.span}>
51
-        <el-row gutter={element.gutter} class={className}
52
-          nativeOnClick={event => { activeItem(element); event.stopPropagation() }}>
53
-          <span class="component-name">{element.componentName}</span>
54
-          <draggable list={element.children} animation={340} group="componentsGroup" class="drag-wrapper">
59
+      <el-col span={config.span}>
60
+        <el-row gutter={config.gutter} class={className}
61
+                nativeOnClick={event => { activeItem(currentItem); event.stopPropagation() }}>
62
+          <span class="component-name">{config.componentName}</span>
63
+          <draggable list={config.children || []} animation={340}
64
+                     group="componentsGroup" class="drag-wrapper">
55 65
             {child}
56 66
           </draggable>
57 67
           {components.itemBtns.apply(this, arguments)}
58 68
         </el-row>
59 69
       </el-col>
60 70
     )
71
+  },
72
+  raw(h, currentItem, index, list) {
73
+    const config = currentItem.__config__
74
+    const child = renderChildren.apply(this, arguments)
75
+    return <render key={config.renderKey} conf={currentItem} onInput={ event => {
76
+      this.$set(config, 'defaultValue', event)
77
+    }}>
78
+      {child}
79
+    </render>
61 80
   }
62 81
 }
63 82
 
64
-function renderChildren(h, element, index, parent) {
65
-  if (!Array.isArray(element.children)) return null
66
-  return element.children.map((el, i) => {
67
-    const layout = layouts[el.layout]
83
+function renderChildren(h, currentItem, index, list) {
84
+  const config = currentItem.__config__
85
+  if (!Array.isArray(config.children)) return null
86
+  return config.children.map((el, i) => {
87
+    const layout = layouts[el.__config__.layout]
68 88
     if (layout) {
69
-      return layout.call(this, h, el, i, element.children)
89
+      return layout.call(this, h, el, i, config.children)
70 90
     }
71
-    return layoutIsNotFound()
91
+    return layoutIsNotFound.call(this)
72 92
   })
73 93
 }
74 94
 
75 95
 function layoutIsNotFound() {
76
-  throw new Error(`没有与${this.element.layout}匹配的layout`)
96
+  throw new Error(`没有与${this.currentItem.__config__.layout}匹配的layout`)
77 97
 }
78 98
 
79 99
 export default {
@@ -82,19 +102,19 @@ export default {
82 102
     draggable
83 103
   },
84 104
   props: [
85
-    'element',
105
+    'currentItem',
86 106
     'index',
87 107
     'drawingList',
88 108
     'activeId',
89 109
     'formConf'
90 110
   ],
91 111
   render(h) {
92
-    const layout = layouts[this.element.layout]
112
+    const layout = layouts[this.currentItem.__config__.layout]
93 113
 
94 114
     if (layout) {
95
-      return layout.call(this, h, this.element, this.index, this.drawingList)
115
+      return layout.call(this, h, this.currentItem, this.index, this.drawingList)
96 116
     }
97
-    return layoutIsNotFound()
117
+    return layoutIsNotFound.call(this)
98 118
   }
99 119
 }
100 120
 </script>

+ 222 - 116
src/views/tool/build/RightPanel.vue

@@ -11,9 +11,9 @@
11 11
       <el-scrollbar class="right-scrollbar">
12 12
         <!-- 组件属性 -->
13 13
         <el-form v-show="currentTab==='field' && showField" size="small" label-width="90px">
14
-          <el-form-item v-if="activeData.changeTag" label="组件类型">
14
+          <el-form-item v-if="activeData.__config__.changeTag" label="组件类型">
15 15
             <el-select
16
-              v-model="activeData.tagIcon"
16
+              v-model="activeData.__config__.tagIcon"
17 17
               placeholder="请选择组件类型"
18 18
               :style="{width: '100%'}"
19 19
               @change="tagChange"
@@ -21,27 +21,27 @@
21 21
               <el-option-group v-for="group in tagList" :key="group.label" :label="group.label">
22 22
                 <el-option
23 23
                   v-for="item in group.options"
24
-                  :key="item.label"
25
-                  :label="item.label"
26
-                  :value="item.tagIcon"
24
+                  :key="item.__config__.label"
25
+                  :label="item.__config__.label"
26
+                  :value="item.__config__.tagIcon"
27 27
                 >
28
-                  <svg-icon class="node-icon" :icon-class="item.tagIcon" />
29
-                  <span> {{ item.label }}</span>
28
+                  <svg-icon class="node-icon" :icon-class="item.__config__.tagIcon" />
29
+                  <span> {{ item.__config__.label }}</span>
30 30
                 </el-option>
31 31
               </el-option-group>
32 32
             </el-select>
33 33
           </el-form-item>
34
-          <el-form-item v-if="activeData.vModel!==undefined" label="字段名">
35
-            <el-input v-model="activeData.vModel" placeholder="请输入字段名(v-model)" />
34
+          <el-form-item v-if="activeData.__vModel__!==undefined" label="字段名">
35
+            <el-input v-model="activeData.__vModel__" placeholder="请输入字段名(v-model)" />
36 36
           </el-form-item>
37
-          <el-form-item v-if="activeData.componentName!==undefined" label="组件名">
38
-            {{ activeData.componentName }}
37
+          <el-form-item v-if="activeData.__config__.componentName!==undefined" label="组件名">
38
+            {{ activeData.__config__.componentName }}
39 39
           </el-form-item>
40
-          <el-form-item v-if="activeData.label!==undefined" label="标题">
41
-            <el-input v-model="activeData.label" placeholder="请输入标题" />
40
+          <el-form-item v-if="activeData.__config__.label!==undefined" label="标题">
41
+            <el-input v-model="activeData.__config__.label" placeholder="请输入标题" @input="changeRenderKey" />
42 42
           </el-form-item>
43 43
           <el-form-item v-if="activeData.placeholder!==undefined" label="占位提示">
44
-            <el-input v-model="activeData.placeholder" placeholder="请输入占位提示" />
44
+            <el-input v-model="activeData.placeholder" placeholder="请输入占位提示" @input="changeRenderKey" />
45 45
           </el-form-item>
46 46
           <el-form-item v-if="activeData['start-placeholder']!==undefined" label="开始占位">
47 47
             <el-input v-model="activeData['start-placeholder']" placeholder="请输入占位提示" />
@@ -49,13 +49,13 @@
49 49
           <el-form-item v-if="activeData['end-placeholder']!==undefined" label="结束占位">
50 50
             <el-input v-model="activeData['end-placeholder']" placeholder="请输入占位提示" />
51 51
           </el-form-item>
52
-          <el-form-item v-if="activeData.span!==undefined" label="表单栅格">
53
-            <el-slider v-model="activeData.span" :max="24" :min="1" :marks="{12:''}" @change="spanChange" />
52
+          <el-form-item v-if="activeData.__config__.span!==undefined" label="表单栅格">
53
+            <el-slider v-model="activeData.__config__.span" :max="24" :min="1" :marks="{12:''}" @change="spanChange" />
54 54
           </el-form-item>
55
-          <el-form-item v-if="activeData.layout==='rowFormItem'" label="栅格间隔">
55
+          <el-form-item v-if="activeData.__config__.layout==='rowFormItem'&&activeData.gutter!==undefined" label="栅格间隔">
56 56
             <el-input-number v-model="activeData.gutter" :min="0" placeholder="栅格间隔" />
57 57
           </el-form-item>
58
-          <el-form-item v-if="activeData.layout==='rowFormItem'" label="布局模式">
58
+          <el-form-item v-if="activeData.__config__.layout==='rowFormItem'&&activeData.type!==undefined" label="布局模式">
59 59
             <el-radio-group v-model="activeData.type">
60 60
               <el-radio-button label="default" />
61 61
               <el-radio-button label="flex" />
@@ -78,20 +78,20 @@
78 78
               <el-radio-button label="bottom" />
79 79
             </el-radio-group>
80 80
           </el-form-item>
81
-          <el-form-item v-if="activeData.labelWidth!==undefined" label="标签宽度">
82
-            <el-input v-model.number="activeData.labelWidth" type="number" placeholder="请输入标签宽度" />
81
+          <el-form-item v-if="activeData.__config__.labelWidth!==undefined" label="标签宽度">
82
+            <el-input v-model.number="activeData.__config__.labelWidth" type="number" placeholder="请输入标签宽度" />
83 83
           </el-form-item>
84 84
           <el-form-item v-if="activeData.style&&activeData.style.width!==undefined" label="组件宽度">
85 85
             <el-input v-model="activeData.style.width" placeholder="请输入组件宽度" clearable />
86 86
           </el-form-item>
87
-          <el-form-item v-if="activeData.vModel!==undefined" label="默认值">
87
+          <el-form-item v-if="activeData.__vModel__!==undefined" label="默认值">
88 88
             <el-input
89
-              :value="setDefaultValue(activeData.defaultValue)"
89
+              :value="setDefaultValue(activeData.__config__.defaultValue)"
90 90
               placeholder="请输入默认值"
91 91
               @input="onDefaultValueInput"
92 92
             />
93 93
           </el-form-item>
94
-          <el-form-item v-if="activeData.tag==='el-checkbox-group'" label="至少应选">
94
+          <el-form-item v-if="activeData.__config__.tag==='el-checkbox-group'" label="至少应选">
95 95
             <el-input-number
96 96
               :value="activeData.min"
97 97
               :min="0"
@@ -99,7 +99,7 @@
99 99
               @input="$set(activeData, 'min', $event?$event:undefined)"
100 100
             />
101 101
           </el-form-item>
102
-          <el-form-item v-if="activeData.tag==='el-checkbox-group'" label="最多可选">
102
+          <el-form-item v-if="activeData.__config__.tag==='el-checkbox-group'" label="最多可选">
103 103
             <el-input-number
104 104
               :value="activeData.max"
105 105
               :min="0"
@@ -107,11 +107,11 @@
107 107
               @input="$set(activeData, 'max', $event?$event:undefined)"
108 108
             />
109 109
           </el-form-item>
110
-          <el-form-item v-if="activeData.prepend!==undefined" label="前缀">
111
-            <el-input v-model="activeData.prepend" placeholder="请输入前缀" />
110
+          <el-form-item v-if="activeData.__slot__&&activeData.__slot__.prepend!==undefined" label="前缀">
111
+            <el-input v-model="activeData.__slot__.prepend" placeholder="请输入前缀" />
112 112
           </el-form-item>
113
-          <el-form-item v-if="activeData.append!==undefined" label="后缀">
114
-            <el-input v-model="activeData.append" placeholder="请输入后缀" />
113
+          <el-form-item v-if="activeData.__slot__&&activeData.__slot__.append!==undefined" label="后缀">
114
+            <el-input v-model="activeData.__slot__.append" placeholder="请输入后缀" />
115 115
           </el-form-item>
116 116
           <el-form-item v-if="activeData['prefix-icon']!==undefined" label="前图标">
117 117
             <el-input v-model="activeData['prefix-icon']" placeholder="请输入前图标名称">
@@ -127,7 +127,17 @@
127 127
               </el-button>
128 128
             </el-input>
129 129
           </el-form-item>
130
-          <el-form-item v-if="activeData.tag === 'el-cascader'" label="选项分隔符">
130
+          <el-form-item
131
+            v-if="activeData['icon']!==undefined && activeData.__config__.tag === 'el-button'"
132
+            label="按钮图标"
133
+          >
134
+            <el-input v-model="activeData['icon']" placeholder="请输入按钮图标名称">
135
+              <el-button slot="append" icon="el-icon-thumb" @click="openIconsDialog('icon')">
136
+                选择
137
+              </el-button>
138
+            </el-input>
139
+          </el-form-item>
140
+          <el-form-item v-if="activeData.__config__.tag === 'el-cascader'" label="选项分隔符">
131 141
             <el-input v-model="activeData.separator" placeholder="请输入选项分隔符" />
132 142
           </el-form-item>
133 143
           <el-form-item v-if="activeData.autosize !== undefined" label="最小行数">
@@ -136,19 +146,22 @@
136 146
           <el-form-item v-if="activeData.autosize !== undefined" label="最大行数">
137 147
             <el-input-number v-model="activeData.autosize.maxRows" :min="1" placeholder="最大行数" />
138 148
           </el-form-item>
139
-          <el-form-item v-if="activeData.min !== undefined" label="最小值">
149
+          <el-form-item v-if="isShowMin" label="最小值">
140 150
             <el-input-number v-model="activeData.min" placeholder="最小值" />
141 151
           </el-form-item>
142
-          <el-form-item v-if="activeData.max !== undefined" label="最大值">
152
+          <el-form-item v-if="isShowMax" label="最大值">
143 153
             <el-input-number v-model="activeData.max" placeholder="最大值" />
144 154
           </el-form-item>
145
-          <el-form-item v-if="activeData.step !== undefined" label="步长">
155
+          <el-form-item v-if="activeData.height!==undefined" label="组件高度">
156
+            <el-input-number v-model="activeData.height" placeholder="高度" @input="changeRenderKey" />
157
+          </el-form-item>
158
+          <el-form-item v-if="isShowStep" label="步长">
146 159
             <el-input-number v-model="activeData.step" placeholder="步数" />
147 160
           </el-form-item>
148
-          <el-form-item v-if="activeData.tag === 'el-input-number'" label="精度">
161
+          <el-form-item v-if="activeData.__config__.tag === 'el-input-number'" label="精度">
149 162
             <el-input-number v-model="activeData.precision" :min="0" placeholder="精度" />
150 163
           </el-form-item>
151
-          <el-form-item v-if="activeData.tag === 'el-input-number'" label="按钮位置">
164
+          <el-form-item v-if="activeData.__config__.tag === 'el-input-number'" label="按钮位置">
152 165
             <el-radio-group v-model="activeData['controls-position']">
153 166
               <el-radio-button label="">
154 167
                 默认
@@ -186,7 +199,7 @@
186 199
             />
187 200
           </el-form-item>
188 201
           <el-form-item
189
-            v-if="activeData.type !== undefined && 'el-date-picker' === activeData.tag"
202
+            v-if="activeData.type !== undefined && 'el-date-picker' === activeData.__config__.tag"
190 203
             label="时间类型"
191 204
           >
192 205
             <el-select
@@ -222,9 +235,9 @@
222 235
               <el-option label="txt" value=".txt" />
223 236
             </el-select>
224 237
           </el-form-item>
225
-          <el-form-item v-if="activeData.fileSize !== undefined" label="文件大小">
226
-            <el-input v-model.number="activeData.fileSize" placeholder="请输入文件大小">
227
-              <el-select slot="append" v-model="activeData.sizeUnit" :style="{ width: '66px' }">
238
+          <el-form-item v-if="activeData.__config__.fileSize !== undefined" label="文件大小">
239
+            <el-input v-model.number="activeData.__config__.fileSize" placeholder="请输入文件大小">
240
+              <el-select slot="append" v-model="activeData.__config__.sizeUnit" :style="{ width: '66px' }">
228 241
                 <el-option label="KB" value="KB" />
229 242
                 <el-option label="MB" value="MB" />
230 243
                 <el-option label="GB" value="GB" />
@@ -248,11 +261,30 @@
248 261
             </el-radio-group>
249 262
           </el-form-item>
250 263
           <el-form-item
251
-            v-if="activeData.buttonText !== undefined"
264
+            v-if="activeData.type !== undefined && activeData.__config__.tag === 'el-button'"
265
+            label="按钮类型"
266
+          >
267
+            <el-select v-model="activeData.type" :style="{ width: '100%' }">
268
+              <el-option label="primary" value="primary" />
269
+              <el-option label="success" value="success" />
270
+              <el-option label="warning" value="warning" />
271
+              <el-option label="danger" value="danger" />
272
+              <el-option label="info" value="info" />
273
+              <el-option label="text" value="text" />
274
+            </el-select>
275
+          </el-form-item>
276
+          <el-form-item
277
+            v-if="activeData.__config__.buttonText !== undefined"
252 278
             v-show="'picture-card' !== activeData['list-type']"
253 279
             label="按钮文字"
254 280
           >
255
-            <el-input v-model="activeData.buttonText" placeholder="请输入按钮文字" />
281
+            <el-input v-model="activeData.__config__.buttonText" placeholder="请输入按钮文字" />
282
+          </el-form-item>
283
+          <el-form-item
284
+            v-if="activeData.__config__.tag === 'el-button'"
285
+            label="按钮文字"
286
+          >
287
+            <el-input v-model="activeData.__slot__.default" placeholder="请输入按钮文字" />
256 288
           </el-form-item>
257 289
           <el-form-item v-if="activeData['range-separator'] !== undefined" label="分隔符">
258 290
             <el-input v-model="activeData['range-separator']" placeholder="请输入分隔符" />
@@ -270,15 +302,15 @@
270 302
               @input="setTimeValue($event)"
271 303
             />
272 304
           </el-form-item>
273
-          <template v-if="['el-checkbox-group', 'el-radio-group', 'el-select'].indexOf(activeData.tag) > -1">
305
+          <template v-if="['el-checkbox-group', 'el-radio-group', 'el-select'].indexOf(activeData.__config__.tag) > -1">
274 306
             <el-divider>选项</el-divider>
275 307
             <draggable
276
-              :list="activeData.options"
308
+              :list="activeData.__slot__.options"
277 309
               :animation="340"
278 310
               group="selectItem"
279 311
               handle=".option-drag"
280 312
             >
281
-              <div v-for="(item, index) in activeData.options" :key="index" class="select-item">
313
+              <div v-for="(item, index) in activeData.__slot__.options" :key="index" class="select-item">
282 314
                 <div class="select-line-icon option-drag">
283 315
                   <i class="el-icon-s-operation" />
284 316
                 </div>
@@ -289,7 +321,7 @@
289 321
                   :value="item.value"
290 322
                   @input="setOptionValue(item, $event)"
291 323
                 />
292
-                <div class="close-btn select-line-icon" @click="activeData.options.splice(index, 1)">
324
+                <div class="close-btn select-line-icon" @click="activeData.__slot__.options.splice(index, 1)">
293 325
                   <i class="el-icon-remove-outline" />
294 326
                 </div>
295 327
               </div>
@@ -307,10 +339,10 @@
307 339
             <el-divider />
308 340
           </template>
309 341
 
310
-          <template v-if="['el-cascader'].indexOf(activeData.tag) > -1">
342
+          <template v-if="['el-cascader', 'el-table'].includes(activeData.__config__.tag)">
311 343
             <el-divider>选项</el-divider>
312
-            <el-form-item label="数据类型">
313
-              <el-radio-group v-model="activeData.dataType" size="small">
344
+            <el-form-item v-if="activeData.__config__.dataType" label="数据类型">
345
+              <el-radio-group v-model="activeData.__config__.dataType" size="small">
314 346
                 <el-radio-button label="dynamic">
315 347
                   动态数据
316 348
                 </el-radio-button>
@@ -320,27 +352,59 @@
320 352
               </el-radio-group>
321 353
             </el-form-item>
322 354
 
323
-            <template v-if="activeData.dataType === 'dynamic'">
324
-              <el-form-item label="标签键名">
325
-                <el-input v-model="activeData.labelKey" placeholder="请输入标签键名" />
326
-              </el-form-item>
327
-              <el-form-item label="值键名">
328
-                <el-input v-model="activeData.valueKey" placeholder="请输入值键名" />
355
+            <template v-if="activeData.__config__.dataType === 'dynamic'">
356
+              <el-form-item label="接口地址">
357
+                <el-input
358
+                  v-model="activeData.__config__.url"
359
+                  :title="activeData.__config__.url"
360
+                  placeholder="请输入接口地址"
361
+                  clearable
362
+                  @blur="$emit('fetch-data', activeData)"
363
+                >
364
+                  <el-select
365
+                    slot="prepend"
366
+                    v-model="activeData.__config__.method"
367
+                    :style="{width: '85px'}"
368
+                    @change="$emit('fetch-data', activeData)"
369
+                  >
370
+                    <el-option label="get" value="get" />
371
+                    <el-option label="post" value="post" />
372
+                    <el-option label="put" value="put" />
373
+                    <el-option label="delete" value="delete" />
374
+                  </el-select>
375
+                </el-input>
329 376
               </el-form-item>
330
-              <el-form-item label="子级键名">
331
-                <el-input v-model="activeData.childrenKey" placeholder="请输入子级键名" />
377
+              <el-form-item label="数据位置">
378
+                <el-input
379
+                  v-model="activeData.__config__.dataPath"
380
+                  placeholder="请输入数据位置"
381
+                  @blur="$emit('fetch-data', activeData)"
382
+                />
332 383
               </el-form-item>
384
+
385
+              <template v-if="activeData.props && activeData.props.props">
386
+                <el-form-item label="标签键名">
387
+                  <el-input v-model="activeData.props.props.label" placeholder="请输入标签键名" />
388
+                </el-form-item>
389
+                <el-form-item label="值键名">
390
+                  <el-input v-model="activeData.props.props.value" placeholder="请输入值键名" />
391
+                </el-form-item>
392
+                <el-form-item label="子级键名">
393
+                  <el-input v-model="activeData.props.props.children" placeholder="请输入子级键名" />
394
+                </el-form-item>
395
+              </template>
333 396
             </template>
334 397
 
398
+            <!-- 级联选择静态树 -->
335 399
             <el-tree
336
-              v-if="activeData.dataType === 'static'"
400
+              v-if="activeData.__config__.dataType === 'static'"
337 401
               draggable
338 402
               :data="activeData.options"
339 403
               node-key="id"
340 404
               :expand-on-click-node="false"
341 405
               :render-content="renderContent"
342 406
             />
343
-            <div v-if="activeData.dataType === 'static'" style="margin-left: 20px">
407
+            <div v-if="activeData.__config__.dataType === 'static'" style="margin-left: 20px">
344 408
               <el-button
345 409
                 style="padding-bottom: 0"
346 410
                 icon="el-icon-circle-plus-outline"
@@ -353,8 +417,8 @@
353 417
             <el-divider />
354 418
           </template>
355 419
 
356
-          <el-form-item v-if="activeData.optionType !== undefined" label="选项样式">
357
-            <el-radio-group v-model="activeData.optionType">
420
+          <el-form-item v-if="activeData.__config__.optionType !== undefined" label="选项样式">
421
+            <el-radio-group v-model="activeData.__config__.optionType">
358 422
               <el-radio-button label="default">
359 423
                 默认
360 424
               </el-radio-button>
@@ -370,6 +434,14 @@
370 434
             <el-color-picker v-model="activeData['inactive-color']" />
371 435
           </el-form-item>
372 436
 
437
+          <el-form-item v-if="activeData.__config__.showLabel !== undefined
438
+            && activeData.__config__.labelWidth !== undefined" label="显示标签"
439
+          >
440
+            <el-switch v-model="activeData.__config__.showLabel" />
441
+          </el-form-item>
442
+          <el-form-item v-if="activeData.branding !== undefined" label="品牌烙印">
443
+            <el-switch v-model="activeData.branding" @input="changeRenderKey" />
444
+          </el-form-item>
373 445
           <el-form-item v-if="activeData['allow-half'] !== undefined" label="允许半选">
374 446
             <el-switch v-model="activeData['allow-half']" />
375 447
           </el-form-item>
@@ -386,16 +458,17 @@
386 458
             <el-switch v-model="activeData.range" @change="rangeChange" />
387 459
           </el-form-item>
388 460
           <el-form-item
389
-            v-if="activeData.border !== undefined && activeData.optionType === 'default'"
461
+            v-if="activeData.__config__.border !== undefined && activeData.__config__.optionType === 'default'"
390 462
             label="是否带边框"
391 463
           >
392
-            <el-switch v-model="activeData.border" />
464
+            <el-switch v-model="activeData.__config__.border" />
393 465
           </el-form-item>
394
-          <el-form-item v-if="activeData.tag === 'el-color-picker'" label="颜色格式">
466
+          <el-form-item v-if="activeData.__config__.tag === 'el-color-picker'" label="颜色格式">
395 467
             <el-select
396 468
               v-model="activeData['color-format']"
397 469
               placeholder="请选择颜色格式"
398 470
               :style="{ width: '100%' }"
471
+              clearable
399 472
               @change="colorFormatChange"
400 473
             >
401 474
               <el-option
@@ -408,10 +481,11 @@
408 481
           </el-form-item>
409 482
           <el-form-item
410 483
             v-if="activeData.size !== undefined &&
411
-              (activeData.optionType === 'button' ||
412
-                activeData.border ||
413
-                activeData.tag === 'el-color-picker')"
414
-            label="选项尺寸"
484
+              (activeData.__config__.optionType === 'button' ||
485
+                activeData.__config__.border ||
486
+                activeData.__config__.tag === 'el-color-picker' ||
487
+                activeData.__config__.tag === 'el-button')"
488
+            label="组件尺寸"
415 489
           >
416 490
             <el-radio-group v-model="activeData.size">
417 491
               <el-radio-button label="medium">
@@ -428,25 +502,28 @@
428 502
           <el-form-item v-if="activeData['show-word-limit'] !== undefined" label="输入统计">
429 503
             <el-switch v-model="activeData['show-word-limit']" />
430 504
           </el-form-item>
431
-          <el-form-item v-if="activeData.tag === 'el-input-number'" label="严格步数">
505
+          <el-form-item v-if="activeData.__config__.tag === 'el-input-number'" label="严格步数">
432 506
             <el-switch v-model="activeData['step-strictly']" />
433 507
           </el-form-item>
434
-          <el-form-item v-if="activeData.tag === 'el-cascader'" label="是否多选">
508
+          <el-form-item v-if="activeData.__config__.tag === 'el-cascader'" label="任选层级">
509
+            <el-switch v-model="activeData.props.props.checkStrictly" />
510
+          </el-form-item>
511
+          <el-form-item v-if="activeData.__config__.tag === 'el-cascader'" label="是否多选">
435 512
             <el-switch v-model="activeData.props.props.multiple" />
436 513
           </el-form-item>
437
-          <el-form-item v-if="activeData.tag === 'el-cascader'" label="展示全路径">
514
+          <el-form-item v-if="activeData.__config__.tag === 'el-cascader'" label="展示全路径">
438 515
             <el-switch v-model="activeData['show-all-levels']" />
439 516
           </el-form-item>
440
-          <el-form-item v-if="activeData.tag === 'el-cascader'" label="可否筛选">
517
+          <el-form-item v-if="activeData.__config__.tag === 'el-cascader'" label="可否筛选">
441 518
             <el-switch v-model="activeData.filterable" />
442 519
           </el-form-item>
443 520
           <el-form-item v-if="activeData.clearable !== undefined" label="能否清空">
444 521
             <el-switch v-model="activeData.clearable" />
445 522
           </el-form-item>
446
-          <el-form-item v-if="activeData.showTip !== undefined" label="显示提示">
447
-            <el-switch v-model="activeData.showTip" />
523
+          <el-form-item v-if="activeData.__config__.showTip !== undefined" label="显示提示">
524
+            <el-switch v-model="activeData.__config__.showTip" />
448 525
           </el-form-item>
449
-          <el-form-item v-if="activeData.multiple !== undefined" label="多选文件">
526
+          <el-form-item v-if="activeData.__config__.tag === 'el-upload'" label="多选文件">
450 527
             <el-switch v-model="activeData.multiple" />
451 528
           </el-form-item>
452 529
           <el-form-item v-if="activeData['auto-upload'] !== undefined" label="自动上传">
@@ -458,20 +535,20 @@
458 535
           <el-form-item v-if="activeData.disabled !== undefined" label="是否禁用">
459 536
             <el-switch v-model="activeData.disabled" />
460 537
           </el-form-item>
461
-          <el-form-item v-if="activeData.tag === 'el-select'" label="是否可搜索">
538
+          <el-form-item v-if="activeData.__config__.tag === 'el-select'" label="能否搜索">
462 539
             <el-switch v-model="activeData.filterable" />
463 540
           </el-form-item>
464
-          <el-form-item v-if="activeData.tag === 'el-select'" label="是否多选">
541
+          <el-form-item v-if="activeData.__config__.tag === 'el-select'" label="是否多选">
465 542
             <el-switch v-model="activeData.multiple" @change="multipleChange" />
466 543
           </el-form-item>
467
-          <el-form-item v-if="activeData.required !== undefined" label="是否必填">
468
-            <el-switch v-model="activeData.required" />
544
+          <el-form-item v-if="activeData.__config__.required !== undefined" label="是否必填">
545
+            <el-switch v-model="activeData.__config__.required" />
469 546
           </el-form-item>
470 547
 
471
-          <template v-if="activeData.layoutTree">
548
+          <template v-if="activeData.__config__.layoutTree">
472 549
             <el-divider>布局结构树</el-divider>
473 550
             <el-tree
474
-              :data="[activeData]"
551
+              :data="[activeData.__config__]"
475 552
               :props="layoutTreeProps"
476 553
               node-key="renderKey"
477 554
               default-expand-all
@@ -479,21 +556,21 @@
479 556
             >
480 557
               <span slot-scope="{ node, data }">
481 558
                 <span class="node-label">
482
-                  <svg-icon class="node-icon" :icon-class="data.tagIcon" />
559
+                  <svg-icon class="node-icon" :icon-class="data.__config__?data.__config__.tagIcon:data.tagIcon" />
483 560
                   {{ node.label }}
484 561
                 </span>
485 562
               </span>
486 563
             </el-tree>
487 564
           </template>
488 565
 
489
-          <template v-if="activeData.layout === 'colFormItem' && activeData.tag !== 'el-button'">
566
+          <template v-if="Array.isArray(activeData.__config__.regList)">
490 567
             <el-divider>正则校验</el-divider>
491 568
             <div
492
-              v-for="(item, index) in activeData.regList"
569
+              v-for="(item, index) in activeData.__config__.regList"
493 570
               :key="index"
494 571
               class="reg-item"
495 572
             >
496
-              <span class="close-btn" @click="activeData.regList.splice(index, 1)">
573
+              <span class="close-btn" @click="activeData.__config__.regList.splice(index, 1)">
497 574
                 <i class="el-icon-close" />
498 575
               </span>
499 576
               <el-form-item label="表达式">
@@ -548,7 +625,7 @@
548 625
             </el-radio-group>
549 626
           </el-form-item>
550 627
           <el-form-item label="标签宽度">
551
-            <el-input-number v-model="formConf.labelWidth" placeholder="标签宽度" />
628
+            <el-input v-model.number="formConf.labelWidth" type="number" placeholder="请输入标签宽度" />
552 629
           </el-form-item>
553 630
           <el-form-item label="栅格间隔">
554 631
             <el-input-number v-model="formConf.gutter" :min="0" placeholder="栅格间隔" />
@@ -572,16 +649,15 @@
572 649
 </template>
573 650
 
574 651
 <script>
575
-import { isArray } from 'util'
576 652
 import draggable from 'vuedraggable'
653
+import { isArray } from 'util'
577 654
 import TreeNodeDialog from './TreeNodeDialog'
578
-import { isNumberStr } from '@/utils/index'
655
+import { isNumberStr } from '@/utils'
579 656
 import IconsDialog from './IconsDialog'
580 657
 import {
581
-  inputComponents,
582
-  selectComponents,
583
-  layoutComponents
658
+  inputComponents, selectComponents, layoutComponents
584 659
 } from '@/utils/generator/config'
660
+import { saveFormConf } from '@/utils/db'
585 661
 
586 662
 const dateTimeFormat = {
587 663
   date: 'yyyy-MM-dd',
@@ -594,11 +670,14 @@ const dateTimeFormat = {
594 670
   datetimerange: 'yyyy-MM-dd HH:mm:ss'
595 671
 }
596 672
 
673
+// 使changeRenderKey在目标组件改变时可用
674
+const needRerenderList = ['tinymce']
675
+
597 676
 export default {
598 677
   components: {
599
-    draggable,
600 678
     TreeNodeDialog,
601
-    IconsDialog
679
+    IconsDialog,
680
+    draggable
602 681
   },
603 682
   props: ['showField', 'activeData', 'formConf'],
604 683
   data() {
@@ -690,7 +769,8 @@ export default {
690 769
       ],
691 770
       layoutTreeProps: {
692 771
         label(data, node) {
693
-          return data.componentName || `${data.label}: ${data.vModel}`
772
+          const config = data.__config__
773
+          return data.componentName || `${config.label}: ${data.__vModel__}`
694 774
         }
695 775
       }
696 776
     }
@@ -698,14 +778,14 @@ export default {
698 778
   computed: {
699 779
     documentLink() {
700 780
       return (
701
-        this.activeData.document
781
+        this.activeData.__config__.document
702 782
         || 'https://element.eleme.cn/#/zh-CN/component/installation'
703 783
       )
704 784
     },
705 785
     dateOptions() {
706 786
       if (
707 787
         this.activeData.type !== undefined
708
-        && this.activeData.tag === 'el-date-picker'
788
+        && this.activeData.__config__.tag === 'el-date-picker'
709 789
       ) {
710 790
         if (this.activeData['start-placeholder'] === undefined) {
711 791
           return this.dateTypeOptions
@@ -725,17 +805,37 @@ export default {
725 805
           options: selectComponents
726 806
         }
727 807
       ]
808
+    },
809
+    activeTag() {
810
+      return this.activeData.__config__.tag
811
+    },
812
+    isShowMin() {
813
+      return ['el-input-number', 'el-slider'].indexOf(this.activeTag) > -1
814
+    },
815
+    isShowMax() {
816
+      return ['el-input-number', 'el-slider', 'el-rate'].indexOf(this.activeTag) > -1
817
+    },
818
+    isShowStep() {
819
+      return ['el-input-number', 'el-slider'].indexOf(this.activeTag) > -1
820
+    }
821
+  },
822
+  watch: {
823
+    formConf: {
824
+      handler(val) {
825
+        saveFormConf(val)
826
+      },
827
+      deep: true
728 828
     }
729 829
   },
730 830
   methods: {
731 831
     addReg() {
732
-      this.activeData.regList.push({
832
+      this.activeData.__config__.regList.push({
733 833
         pattern: '',
734 834
         message: ''
735 835
       })
736 836
     },
737 837
     addSelectItem() {
738
-      this.activeData.options.push({
838
+      this.activeData.__slot__.options.push({
739 839
         label: '',
740 840
         value: ''
741 841
       })
@@ -751,12 +851,12 @@ export default {
751 851
           <span>{node.label}</span>
752 852
           <span class="node-operation">
753 853
             <i on-click={() => this.append(data)}
754
-              class="el-icon-plus"
755
-              title="添加"
854
+               class="el-icon-plus"
855
+               title="添加"
756 856
             ></i>
757 857
             <i on-click={() => this.remove(node, data)}
758
-              class="el-icon-delete"
759
-              title="删除"
858
+               class="el-icon-delete"
859
+               title="删除"
760 860
             ></i>
761 861
           </span>
762 862
         </div>
@@ -770,6 +870,7 @@ export default {
770 870
       this.currentNode = data.children
771 871
     },
772 872
     remove(node, data) {
873
+      this.activeData.__config__.defaultValue = [] // 避免删除时报错
773 874
       const { parent } = node
774 875
       const children = parent.data.children || parent.data
775 876
       const index = children.findIndex(d => d.id === data.id)
@@ -785,29 +886,29 @@ export default {
785 886
       if (Array.isArray(val)) {
786 887
         return val.join(',')
787 888
       }
788
-      if (['string', 'number'].indexOf(val) > -1) {
789
-        return val
790
-      }
889
+      // if (['string', 'number'].indexOf(typeof val) > -1) {
890
+      //   return val
891
+      // }
791 892
       if (typeof val === 'boolean') {
792 893
         return `${val}`
793 894
       }
794 895
       return val
795 896
     },
796 897
     onDefaultValueInput(str) {
797
-      if (isArray(this.activeData.defaultValue)) {
898
+      if (isArray(this.activeData.__config__.defaultValue)) {
798 899
         // 数组
799 900
         this.$set(
800
-          this.activeData,
901
+          this.activeData.__config__,
801 902
           'defaultValue',
802 903
           str.split(',').map(val => (isNumberStr(val) ? +val : val))
803 904
         )
804 905
       } else if (['true', 'false'].indexOf(str) > -1) {
805 906
         // 布尔
806
-        this.$set(this.activeData, 'defaultValue', JSON.parse(str))
907
+        this.$set(this.activeData.__config__, 'defaultValue', JSON.parse(str))
807 908
       } else {
808 909
         // 字符串和数字
809 910
         this.$set(
810
-          this.activeData,
911
+          this.activeData.__config__,
811 912
           'defaultValue',
812 913
           isNumberStr(str) ? +str : str
813 914
         )
@@ -822,7 +923,7 @@ export default {
822 923
     },
823 924
     setTimeValue(val, type) {
824 925
       const valueFormat = type === 'week' ? dateTimeFormat.date : val
825
-      this.$set(this.activeData, 'defaultValue', null)
926
+      this.$set(this.activeData.__config__, 'defaultValue', null)
826 927
       this.$set(this.activeData, 'value-format', valueFormat)
827 928
       this.$set(this.activeData, 'format', val)
828 929
     },
@@ -830,14 +931,14 @@ export default {
830 931
       this.formConf.span = val
831 932
     },
832 933
     multipleChange(val) {
833
-      this.$set(this.activeData, 'defaultValue', val ? [] : '')
934
+      this.$set(this.activeData.__config__, 'defaultValue', val ? [] : '')
834 935
     },
835 936
     dateTypeChange(val) {
836 937
       this.setTimeValue(dateTimeFormat[val], val)
837 938
     },
838 939
     rangeChange(val) {
839 940
       this.$set(
840
-        this.activeData,
941
+        this.activeData.__config__,
841 942
         'defaultValue',
842 943
         val ? [this.activeData.min, this.activeData.max] : this.activeData.min
843 944
       )
@@ -849,9 +950,9 @@ export default {
849 950
       if (val) this.activeData['show-text'] = false
850 951
     },
851 952
     colorFormatChange(val) {
852
-      this.activeData.defaultValue = null
953
+      this.activeData.__config__.defaultValue = null
853 954
       this.activeData['show-alpha'] = val.indexOf('a') > -1
854
-      this.activeData.renderKey = +new Date() // 更新renderKey,重新渲染该组件
955
+      this.activeData.__config__.renderKey = +new Date() // 更新renderKey,重新渲染该组件
855 956
     },
856 957
     openIconsDialog(model) {
857 958
       this.iconsVisible = true
@@ -861,9 +962,14 @@ export default {
861 962
       this.activeData[this.currentIconModel] = val
862 963
     },
863 964
     tagChange(tagIcon) {
864
-      let target = inputComponents.find(item => item.tagIcon === tagIcon)
865
-      if (!target) target = selectComponents.find(item => item.tagIcon === tagIcon)
965
+      let target = inputComponents.find(item => item.__config__.tagIcon === tagIcon)
966
+      if (!target) target = selectComponents.find(item => item.__config__.tagIcon === tagIcon)
866 967
       this.$emit('tag-change', target)
968
+    },
969
+    changeRenderKey() {
970
+      if (needRerenderList.includes(this.activeData.__config__.tag)) {
971
+        this.activeData.__config__.renderKey = +new Date()
972
+      }
867 973
     }
868 974
   }
869 975
 }
@@ -902,7 +1008,7 @@ export default {
902 1008
   margin-top: 4px;
903 1009
 }
904 1010
 .select-item.sortable-chosen {
905
-  border: 1px dashed #031527;
1011
+  border: 1px dashed #409eff;
906 1012
 }
907 1013
 .select-line-icon {
908 1014
   line-height: 32px;
@@ -929,7 +1035,7 @@ export default {
929 1035
   top: 0;
930 1036
   left: 0;
931 1037
   cursor: pointer;
932
-  background: #031527;
1038
+  background: #409eff;
933 1039
   z-index: 1;
934 1040
   border-radius: 0 0 6px 0;
935 1041
   text-align: center;

+ 13 - 4
src/views/tool/build/TreeNodeDialog.vue

@@ -59,7 +59,7 @@
59 59
       <div slot="footer">
60 60
         <el-button
61 61
           type="primary"
62
-          @click="handleConfirm"
62
+          @click="handelConfirm"
63 63
         >
64 64
           确定
65 65
         </el-button>
@@ -71,7 +71,10 @@
71 71
   </div>
72 72
 </template>
73 73
 <script>
74
-import { isNumberStr } from '@/utils/index'
74
+import { isNumberStr } from '@/utils'
75
+import { getTreeNodeId, saveTreeNodeId } from '@/utils/db'
76
+
77
+const id = getTreeNodeId()
75 78
 
76 79
 export default {
77 80
   components: {},
@@ -79,7 +82,7 @@ export default {
79 82
   props: [],
80 83
   data() {
81 84
     return {
82
-      id: 100,
85
+      id,
83 86
       formData: {
84 87
         label: undefined,
85 88
         value: undefined
@@ -118,6 +121,9 @@ export default {
118 121
     // eslint-disable-next-line func-names
119 122
     'formData.value': function (val) {
120 123
       this.dataType = isNumberStr(val) ? 'number' : 'string'
124
+    },
125
+    id(val) {
126
+      saveTreeNodeId(val)
121 127
     }
122 128
   },
123 129
   created() {},
@@ -133,7 +139,7 @@ export default {
133 139
     close() {
134 140
       this.$emit('update:visible', false)
135 141
     },
136
-    handleConfirm() {
142
+    handelConfirm() {
137 143
       this.$refs.elForm.validate(valid => {
138 144
         if (!valid) return
139 145
         if (this.dataType === 'number') {
@@ -147,3 +153,6 @@ export default {
147 153
   }
148 154
 }
149 155
 </script>
156
+
157
+<style lang="scss" scoped>
158
+</style>

Різницю між файлами не показано, бо вона завелика
+ 312 - 526
src/views/tool/build/index.vue


+ 1 - 1
vue.config.js

@@ -35,7 +35,7 @@ module.exports = {
35 35
     proxy: {
36 36
       // detail: https://cli.vuejs.org/config/#devserver-proxy
37 37
       [process.env.VUE_APP_BASE_API]: {
38
-        target: `http://192.168.3.200:8080`,
38
+        target: `http://101.42.248.108:17005`,
39 39
         changeOrigin: true,
40 40
         pathRewrite: {
41 41
           ['^' + process.env.VUE_APP_BASE_API]: ''