作者 若依
提交者 Gitee

!426 修正单词拼写错误

Merge pull request !426 from 稚屿/master
正在显示 22 个修改的文件 包含 1699 行增加1719 行删除
@@ -41,8 +41,7 @@ public class DictUtils @@ -41,8 +41,7 @@ public class DictUtils
41 Object cacheObj = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key)); 41 Object cacheObj = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
42 if (StringUtils.isNotNull(cacheObj)) 42 if (StringUtils.isNotNull(cacheObj))
43 { 43 {
44 - List<SysDictData> dictDatas = StringUtils.cast(cacheObj);  
45 - return dictDatas; 44 + return StringUtils.cast(cacheObj);
46 } 45 }
47 return null; 46 return null;
48 } 47 }
@@ -18,8 +18,7 @@ public class ExceptionUtil @@ -18,8 +18,7 @@ public class ExceptionUtil
18 { 18 {
19 StringWriter sw = new StringWriter(); 19 StringWriter sw = new StringWriter();
20 e.printStackTrace(new PrintWriter(sw, true)); 20 e.printStackTrace(new PrintWriter(sw, true));
21 - String str = sw.toString();  
22 - return str; 21 + return sw.toString();
23 } 22 }
24 23
25 public static String getRootErrorMessage(Exception e) 24 public static String getRootErrorMessage(Exception e)
@@ -99,9 +99,8 @@ public class ServletUtils @@ -99,9 +99,8 @@ public class ServletUtils
99 * 99 *
100 * @param response 渲染对象 100 * @param response 渲染对象
101 * @param string 待渲染的字符串 101 * @param string 待渲染的字符串
102 - * @return null  
103 */ 102 */
104 - public static String renderString(HttpServletResponse response, String string) 103 + public static void renderString(HttpServletResponse response, String string)
105 { 104 {
106 try 105 try
107 { 106 {
@@ -114,7 +113,6 @@ public class ServletUtils @@ -114,7 +113,6 @@ public class ServletUtils
114 { 113 {
115 e.printStackTrace(); 114 e.printStackTrace();
116 } 115 }
117 - return null;  
118 } 116 }
119 117
120 /** 118 /**
@@ -125,13 +123,13 @@ public class ServletUtils @@ -125,13 +123,13 @@ public class ServletUtils
125 public static boolean isAjaxRequest(HttpServletRequest request) 123 public static boolean isAjaxRequest(HttpServletRequest request)
126 { 124 {
127 String accept = request.getHeader("accept"); 125 String accept = request.getHeader("accept");
128 - if (accept != null && accept.indexOf("application/json") != -1) 126 + if (accept != null && accept.contains("application/json"))
129 { 127 {
130 return true; 128 return true;
131 } 129 }
132 130
133 String xRequestedWith = request.getHeader("X-Requested-With"); 131 String xRequestedWith = request.getHeader("X-Requested-With");
134 - if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) 132 + if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest"))
135 { 133 {
136 return true; 134 return true;
137 } 135 }
@@ -143,10 +141,6 @@ public class ServletUtils @@ -143,10 +141,6 @@ public class ServletUtils
143 } 141 }
144 142
145 String ajax = request.getParameter("__ajax"); 143 String ajax = request.getParameter("__ajax");
146 - if (StringUtils.inStringIgnoreCase(ajax, "json", "xml"))  
147 - {  
148 - return true;  
149 - }  
150 - return false; 144 + return StringUtils.inStringIgnoreCase(ajax, "json", "xml");
151 } 145 }
152 } 146 }
@@ -208,7 +208,6 @@ public class VerifyCodeUtils @@ -208,7 +208,6 @@ public class VerifyCodeUtils
208 208
209 int period = random.nextInt(40) + 10; // 50; 209 int period = random.nextInt(40) + 10; // 50;
210 210
211 - boolean borderGap = true;  
212 int frames = 20; 211 int frames = 20;
213 int phase = 7; 212 int phase = 7;
214 for (int i = 0; i < w1; i++) 213 for (int i = 0; i < w1; i++)
@@ -216,13 +215,9 @@ public class VerifyCodeUtils @@ -216,13 +215,9 @@ public class VerifyCodeUtils
216 double d = (double) (period >> 1) 215 double d = (double) (period >> 1)
217 * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames); 216 * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
218 g.copyArea(i, 0, 1, h1, 0, (int) d); 217 g.copyArea(i, 0, 1, h1, 0, (int) d);
219 - if (borderGap)  
220 - {  
221 - g.setColor(color);  
222 - g.drawLine(i, (int) d, i, 0);  
223 - g.drawLine(i, (int) d + h1, i, h1);  
224 - }  
225 - 218 + g.setColor(color);
  219 + g.drawLine(i, (int) d, i, 0);
  220 + g.drawLine(i, (int) d + h1, i, h1);
226 } 221 }
227 } 222 }
228 } 223 }
@@ -2,6 +2,8 @@ package com.ruoyi.common.utils.file; @@ -2,6 +2,8 @@ package com.ruoyi.common.utils.file;
2 2
3 import java.io.File; 3 import java.io.File;
4 import java.io.IOException; 4 import java.io.IOException;
  5 +import java.util.Objects;
  6 +
5 import org.apache.commons.io.FilenameUtils; 7 import org.apache.commons.io.FilenameUtils;
6 import org.springframework.web.multipart.MultipartFile; 8 import org.springframework.web.multipart.MultipartFile;
7 import com.ruoyi.common.config.RuoYiConfig; 9 import com.ruoyi.common.config.RuoYiConfig;
@@ -100,7 +102,7 @@ public class FileUploadUtils @@ -100,7 +102,7 @@ public class FileUploadUtils
100 throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, 102 throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
101 InvalidExtensionException 103 InvalidExtensionException
102 { 104 {
103 - int fileNamelength = file.getOriginalFilename().length(); 105 + int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
104 if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) 106 if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
105 { 107 {
106 throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); 108 throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
@@ -112,8 +114,7 @@ public class FileUploadUtils @@ -112,8 +114,7 @@ public class FileUploadUtils
112 114
113 File desc = getAbsoluteFile(baseDir, fileName); 115 File desc = getAbsoluteFile(baseDir, fileName);
114 file.transferTo(desc); 116 file.transferTo(desc);
115 - String pathFileName = getPathFileName(baseDir, fileName);  
116 - return pathFileName; 117 + return getPathFileName(baseDir, fileName);
117 } 118 }
118 119
119 /** 120 /**
@@ -145,8 +146,7 @@ public class FileUploadUtils @@ -145,8 +146,7 @@ public class FileUploadUtils
145 { 146 {
146 int dirLastIndex = RuoYiConfig.getProfile().length() + 1; 147 int dirLastIndex = RuoYiConfig.getProfile().length() + 1;
147 String currentDir = StringUtils.substring(uploadDir, dirLastIndex); 148 String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
148 - String pathFileName = Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;  
149 - return pathFileName; 149 + return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
150 } 150 }
151 151
152 /** 152 /**
@@ -161,7 +161,7 @@ public class FileUploadUtils @@ -161,7 +161,7 @@ public class FileUploadUtils
161 throws FileSizeLimitExceededException, InvalidExtensionException 161 throws FileSizeLimitExceededException, InvalidExtensionException
162 { 162 {
163 long size = file.getSize(); 163 long size = file.getSize();
164 - if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE) 164 + if (size > DEFAULT_MAX_SIZE)
165 { 165 {
166 throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024); 166 throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
167 } 167 }
@@ -228,7 +228,7 @@ public class FileUploadUtils @@ -228,7 +228,7 @@ public class FileUploadUtils
228 String extension = FilenameUtils.getExtension(file.getOriginalFilename()); 228 String extension = FilenameUtils.getExtension(file.getOriginalFilename());
229 if (StringUtils.isEmpty(extension)) 229 if (StringUtils.isEmpty(extension))
230 { 230 {
231 - extension = MimeTypeUtils.getExtension(file.getContentType()); 231 + extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));
232 } 232 }
233 return extension; 233 return extension;
234 } 234 }
@@ -59,7 +59,7 @@ public class ImageUtils @@ -59,7 +59,7 @@ public class ImageUtils
59 /** 59 /**
60 * 读取文件为字节数据 60 * 读取文件为字节数据
61 * 61 *
62 - * @param key 地址 62 + * @param url 地址
63 * @return 字节数据 63 * @return 字节数据
64 */ 64 */
65 public static byte[] readFile(String url) 65 public static byte[] readFile(String url)
@@ -5,6 +5,7 @@ import java.io.IOException; @@ -5,6 +5,7 @@ import java.io.IOException;
5 import java.io.InputStream; 5 import java.io.InputStream;
6 import java.io.InputStreamReader; 6 import java.io.InputStreamReader;
7 import java.nio.charset.Charset; 7 import java.nio.charset.Charset;
  8 +import java.nio.charset.StandardCharsets;
8 import javax.servlet.ServletRequest; 9 import javax.servlet.ServletRequest;
9 import org.apache.commons.lang3.exception.ExceptionUtils; 10 import org.apache.commons.lang3.exception.ExceptionUtils;
10 import org.slf4j.Logger; 11 import org.slf4j.Logger;
@@ -25,7 +26,7 @@ public class HttpHelper @@ -25,7 +26,7 @@ public class HttpHelper
25 BufferedReader reader = null; 26 BufferedReader reader = null;
26 try (InputStream inputStream = request.getInputStream()) 27 try (InputStream inputStream = request.getInputStream())
27 { 28 {
28 - reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); 29 + reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
29 String line = ""; 30 String line = "";
30 while ((line = reader.readLine()) != null) 31 while ((line = reader.readLine()) != null)
31 { 32 {
@@ -9,6 +9,7 @@ import java.net.ConnectException; @@ -9,6 +9,7 @@ import java.net.ConnectException;
9 import java.net.SocketTimeoutException; 9 import java.net.SocketTimeoutException;
10 import java.net.URL; 10 import java.net.URL;
11 import java.net.URLConnection; 11 import java.net.URLConnection;
  12 +import java.nio.charset.StandardCharsets;
12 import java.security.cert.X509Certificate; 13 import java.security.cert.X509Certificate;
13 import javax.net.ssl.HostnameVerifier; 14 import javax.net.ssl.HostnameVerifier;
14 import javax.net.ssl.HttpsURLConnection; 15 import javax.net.ssl.HttpsURLConnection;
@@ -130,9 +131,8 @@ public class HttpUtils @@ -130,9 +131,8 @@ public class HttpUtils
130 StringBuilder result = new StringBuilder(); 131 StringBuilder result = new StringBuilder();
131 try 132 try
132 { 133 {
133 - String urlNameString = url;  
134 - log.info("sendPost - {}", urlNameString);  
135 - URL realUrl = new URL(urlNameString); 134 + log.info("sendPost - {}", url);
  135 + URL realUrl = new URL(url);
136 URLConnection conn = realUrl.openConnection(); 136 URLConnection conn = realUrl.openConnection();
137 conn.setRequestProperty("accept", "*/*"); 137 conn.setRequestProperty("accept", "*/*");
138 conn.setRequestProperty("connection", "Keep-Alive"); 138 conn.setRequestProperty("connection", "Keep-Alive");
@@ -144,7 +144,7 @@ public class HttpUtils @@ -144,7 +144,7 @@ public class HttpUtils
144 out = new PrintWriter(conn.getOutputStream()); 144 out = new PrintWriter(conn.getOutputStream());
145 out.print(param); 145 out.print(param);
146 out.flush(); 146 out.flush();
147 - in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); 147 + in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
148 String line; 148 String line;
149 while ((line = in.readLine()) != null) 149 while ((line = in.readLine()) != null)
150 { 150 {
@@ -218,7 +218,7 @@ public class HttpUtils @@ -218,7 +218,7 @@ public class HttpUtils
218 { 218 {
219 if (ret != null && !"".equals(ret.trim())) 219 if (ret != null && !"".equals(ret.trim()))
220 { 220 {
221 - result.append(new String(ret.getBytes("ISO-8859-1"), "utf-8")); 221 + result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
222 } 222 }
223 } 223 }
224 log.info("recv - {}", result); 224 log.info("recv - {}", result);
@@ -25,7 +25,6 @@ public class AddressUtils @@ -25,7 +25,6 @@ public class AddressUtils
25 25
26 public static String getRealAddressByIP(String ip) 26 public static String getRealAddressByIP(String ip)
27 { 27 {
28 - String address = UNKNOWN;  
29 // 内网不查询 28 // 内网不查询
30 if (IpUtils.internalIp(ip)) 29 if (IpUtils.internalIp(ip))
31 { 30 {
@@ -51,6 +50,6 @@ public class AddressUtils @@ -51,6 +50,6 @@ public class AddressUtils
51 log.error("获取地理位置异常 {}", ip); 50 log.error("获取地理位置异常 {}", ip);
52 } 51 }
53 } 52 }
54 - return address; 53 + return UNKNOWN;
55 } 54 }
56 } 55 }
@@ -1121,7 +1121,7 @@ public class ExcelUtil<T> @@ -1121,7 +1121,7 @@ public class ExcelUtil<T>
1121 if (StringUtils.isNotEmpty(excel.targetAttr())) 1121 if (StringUtils.isNotEmpty(excel.targetAttr()))
1122 { 1122 {
1123 String target = excel.targetAttr(); 1123 String target = excel.targetAttr();
1124 - if (target.indexOf(".") > -1) 1124 + if (target.contains("."))
1125 { 1125 {
1126 String[] targets = target.split("[.]"); 1126 String[] targets = target.split("[.]");
1127 for (String name : targets) 1127 for (String name : targets)
@@ -1216,7 +1216,7 @@ public class ExcelUtil<T> @@ -1216,7 +1216,7 @@ public class ExcelUtil<T>
1216 for (Object[] os : this.fields) 1216 for (Object[] os : this.fields)
1217 { 1217 {
1218 Excel excel = (Excel) os[1]; 1218 Excel excel = (Excel) os[1];
1219 - maxHeight = maxHeight > excel.height() ? maxHeight : excel.height(); 1219 + maxHeight = Math.max(maxHeight, excel.height());
1220 } 1220 }
1221 return (short) (maxHeight * 20); 1221 return (short) (maxHeight * 20);
1222 } 1222 }
1 package com.ruoyi.common.utils.sign; 1 package com.ruoyi.common.utils.sign;
2 2
  3 +import java.nio.charset.StandardCharsets;
3 import java.security.MessageDigest; 4 import java.security.MessageDigest;
4 import org.slf4j.Logger; 5 import org.slf4j.Logger;
5 import org.slf4j.LoggerFactory; 6 import org.slf4j.LoggerFactory;
@@ -55,7 +56,7 @@ public class Md5Utils @@ -55,7 +56,7 @@ public class Md5Utils
55 { 56 {
56 try 57 try
57 { 58 {
58 - return new String(toHex(md5(s)).getBytes("UTF-8"), "UTF-8"); 59 + return new String(toHex(md5(s)).getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
59 } 60 }
60 catch (Exception e) 61 catch (Exception e)
61 { 62 {
@@ -50,10 +50,8 @@ public class SqlUtil @@ -50,10 +50,8 @@ public class SqlUtil
50 return; 50 return;
51 } 51 }
52 String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|"); 52 String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|");
53 - for (int i = 0; i < sqlKeywords.length; i++)  
54 - {  
55 - if (StringUtils.indexOfIgnoreCase(value, sqlKeywords[i]) > -1)  
56 - { 53 + for (String sqlKeyword : sqlKeywords) {
  54 + if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1) {
57 throw new UtilException("参数存在SQL注入风险"); 55 throw new UtilException("参数存在SQL注入风险");
58 } 56 }
59 } 57 }
@@ -151,8 +151,7 @@ public class GenUtils @@ -151,8 +151,7 @@ public class GenUtils
151 { 151 {
152 int lastIndex = packageName.lastIndexOf("."); 152 int lastIndex = packageName.lastIndexOf(".");
153 int nameLength = packageName.length(); 153 int nameLength = packageName.length();
154 - String moduleName = StringUtils.substring(packageName, lastIndex + 1, nameLength);  
155 - return moduleName; 154 + return StringUtils.substring(packageName, lastIndex + 1, nameLength);
156 } 155 }
157 156
158 /** 157 /**
@@ -165,8 +164,7 @@ public class GenUtils @@ -165,8 +164,7 @@ public class GenUtils
165 { 164 {
166 int lastIndex = tableName.lastIndexOf("_"); 165 int lastIndex = tableName.lastIndexOf("_");
167 int nameLength = tableName.length(); 166 int nameLength = tableName.length();
168 - String businessName = StringUtils.substring(tableName, lastIndex + 1, nameLength);  
169 - return businessName; 167 + return StringUtils.substring(tableName, lastIndex + 1, nameLength);
170 } 168 }
171 169
172 /** 170 /**
@@ -228,8 +228,7 @@ public class VelocityUtils @@ -228,8 +228,7 @@ public class VelocityUtils
228 public static String getPackagePrefix(String packageName) 228 public static String getPackagePrefix(String packageName)
229 { 229 {
230 int lastIndex = packageName.lastIndexOf("."); 230 int lastIndex = packageName.lastIndexOf(".");
231 - String basePackage = StringUtils.substring(packageName, 0, lastIndex);  
232 - return basePackage; 231 + return StringUtils.substring(packageName, 0, lastIndex);
233 } 232 }
234 233
235 /** 234 /**
@@ -63,12 +63,9 @@ public class SysDeptServiceImpl implements ISysDeptService @@ -63,12 +63,9 @@ public class SysDeptServiceImpl implements ISysDeptService
63 { 63 {
64 tempList.add(dept.getDeptId()); 64 tempList.add(dept.getDeptId());
65 } 65 }
66 - for (Iterator<SysDept> iterator = depts.iterator(); iterator.hasNext();)  
67 - {  
68 - SysDept dept = (SysDept) iterator.next(); 66 + for (SysDept dept : depts) {
69 // 如果是顶级节点, 遍历该父节点的所有子节点 67 // 如果是顶级节点, 遍历该父节点的所有子节点
70 - if (!tempList.contains(dept.getParentId()))  
71 - { 68 + if (!tempList.contains(dept.getParentId())) {
72 recursionFn(depts, dept); 69 recursionFn(depts, dept);
73 returnList.add(dept); 70 returnList.add(dept);
74 } 71 }
@@ -498,7 +498,7 @@ public class SysMenuServiceImpl implements ISysMenuService @@ -498,7 +498,7 @@ public class SysMenuServiceImpl implements ISysMenuService
498 */ 498 */
499 private boolean hasChild(List<SysMenu> list, SysMenu t) 499 private boolean hasChild(List<SysMenu> list, SysMenu t)
500 { 500 {
501 - return getChildList(list, t).size() > 0 ? true : false; 501 + return getChildList(list, t).size() > 0;
502 } 502 }
503 503
504 /** 504 /**
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 -] 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 +]
1 -/* eslint-disable max-len */  
2 -import { trigger } from './config'  
3 -  
4 -let confGlobal  
5 -let someSpanIsNot24  
6 -  
7 -export function dialogWrapper(str) {  
8 - return `<el-dialog v-bind="$attrs" v-on="$listeners" @open="onOpen" @close="onClose" title="Dialog Titile">  
9 - ${str}  
10 - <div slot="footer">  
11 - <el-button @click="close">取消</el-button>  
12 - <el-button type="primary" @click="handelConfirm">确定</el-button>  
13 - </div>  
14 - </el-dialog>`  
15 -}  
16 -  
17 -export function vueTemplate(str) {  
18 - return `<template>  
19 - <div>  
20 - ${str}  
21 - </div>  
22 - </template>`  
23 -}  
24 -  
25 -export function vueScript(str) {  
26 - return `<script>  
27 - ${str}  
28 - </script>`  
29 -}  
30 -  
31 -export function cssStyle(cssStr) {  
32 - return `<style>  
33 - ${cssStr}  
34 - </style>`  
35 -}  
36 -  
37 -function buildFormTemplate(conf, child, type) {  
38 - let labelPosition = ''  
39 - if (conf.labelPosition !== 'right') {  
40 - labelPosition = `label-position="${conf.labelPosition}"`  
41 - }  
42 - const disabled = conf.disabled ? `:disabled="${conf.disabled}"` : ''  
43 - let str = `<el-form ref="${conf.formRef}" :model="${conf.formModel}" :rules="${conf.formRules}" size="${conf.size}" ${disabled} label-width="${conf.labelWidth}px" ${labelPosition}>  
44 - ${child}  
45 - ${buildFromBtns(conf, type)}  
46 - </el-form>`  
47 - if (someSpanIsNot24) {  
48 - str = `<el-row :gutter="${conf.gutter}">  
49 - ${str}  
50 - </el-row>`  
51 - }  
52 - return str  
53 -}  
54 -  
55 -function buildFromBtns(conf, type) {  
56 - let str = ''  
57 - if (conf.formBtns && type === 'file') {  
58 - str = `<el-form-item size="large">  
59 - <el-button type="primary" @click="submitForm">提交</el-button>  
60 - <el-button @click="resetForm">重置</el-button>  
61 - </el-form-item>`  
62 - if (someSpanIsNot24) {  
63 - str = `<el-col :span="24">  
64 - ${str}  
65 - </el-col>`  
66 - }  
67 - }  
68 - return str  
69 -}  
70 -  
71 -// span不为24的用el-col包裹  
72 -function colWrapper(element, str) {  
73 - if (someSpanIsNot24 || element.span !== 24) {  
74 - return `<el-col :span="${element.span}">  
75 - ${str}  
76 - </el-col>`  
77 - }  
78 - return str  
79 -}  
80 -  
81 -const layouts = {  
82 - colFormItem(element) {  
83 - let labelWidth = ''  
84 - if (element.labelWidth && element.labelWidth !== confGlobal.labelWidth) {  
85 - labelWidth = `label-width="${element.labelWidth}px"`  
86 - }  
87 - const required = !trigger[element.tag] && element.required ? 'required' : ''  
88 - const tagDom = tags[element.tag] ? tags[element.tag](element) : null  
89 - let str = `<el-form-item ${labelWidth} label="${element.label}" prop="${element.vModel}" ${required}>  
90 - ${tagDom}  
91 - </el-form-item>`  
92 - str = colWrapper(element, str)  
93 - return str  
94 - },  
95 - rowFormItem(element) {  
96 - const type = element.type === 'default' ? '' : `type="${element.type}"`  
97 - const justify = element.type === 'default' ? '' : `justify="${element.justify}"`  
98 - const align = element.type === 'default' ? '' : `align="${element.align}"`  
99 - const gutter = element.gutter ? `gutter="${element.gutter}"` : ''  
100 - const children = element.children.map(el => layouts[el.layout](el))  
101 - let str = `<el-row ${type} ${justify} ${align} ${gutter}>  
102 - ${children.join('\n')}  
103 - </el-row>`  
104 - str = colWrapper(element, str)  
105 - return str  
106 - }  
107 -}  
108 -  
109 -const tags = {  
110 - 'el-button': el => {  
111 - const {  
112 - tag, disabled  
113 - } = attrBuilder(el)  
114 - const type = el.type ? `type="${el.type}"` : ''  
115 - const icon = el.icon ? `icon="${el.icon}"` : ''  
116 - const size = el.size ? `size="${el.size}"` : ''  
117 - let child = buildElButtonChild(el)  
118 -  
119 - if (child) child = `\n${child}\n` // 换行  
120 - return `<${el.tag} ${type} ${icon} ${size} ${disabled}>${child}</${el.tag}>`  
121 - },  
122 - 'el-input': el => {  
123 - const {  
124 - disabled, vModel, clearable, placeholder, width  
125 - } = attrBuilder(el)  
126 - const maxlength = el.maxlength ? `:maxlength="${el.maxlength}"` : ''  
127 - const showWordLimit = el['show-word-limit'] ? 'show-word-limit' : ''  
128 - const readonly = el.readonly ? 'readonly' : ''  
129 - const prefixIcon = el['prefix-icon'] ? `prefix-icon='${el['prefix-icon']}'` : ''  
130 - const suffixIcon = el['suffix-icon'] ? `suffix-icon='${el['suffix-icon']}'` : ''  
131 - const showPassword = el['show-password'] ? 'show-password' : ''  
132 - const type = el.type ? `type="${el.type}"` : ''  
133 - const autosize = el.autosize && el.autosize.minRows  
134 - ? `:autosize="{minRows: ${el.autosize.minRows}, maxRows: ${el.autosize.maxRows}}"`  
135 - : ''  
136 - let child = buildElInputChild(el)  
137 -  
138 - if (child) child = `\n${child}\n` // 换行  
139 - return `<${el.tag} ${vModel} ${type} ${placeholder} ${maxlength} ${showWordLimit} ${readonly} ${disabled} ${clearable} ${prefixIcon} ${suffixIcon} ${showPassword} ${autosize} ${width}>${child}</${el.tag}>`  
140 - },  
141 - 'el-input-number': el => {  
142 - const { disabled, vModel, placeholder } = attrBuilder(el)  
143 - const controlsPosition = el['controls-position'] ? `controls-position=${el['controls-position']}` : ''  
144 - const min = el.min ? `:min='${el.min}'` : ''  
145 - const max = el.max ? `:max='${el.max}'` : ''  
146 - const step = el.step ? `:step='${el.step}'` : ''  
147 - const stepStrictly = el['step-strictly'] ? 'step-strictly' : ''  
148 - const precision = el.precision ? `:precision='${el.precision}'` : ''  
149 -  
150 - return `<${el.tag} ${vModel} ${placeholder} ${step} ${stepStrictly} ${precision} ${controlsPosition} ${min} ${max} ${disabled}></${el.tag}>`  
151 - },  
152 - 'el-select': el => {  
153 - const {  
154 - disabled, vModel, clearable, placeholder, width  
155 - } = attrBuilder(el)  
156 - const filterable = el.filterable ? 'filterable' : ''  
157 - const multiple = el.multiple ? 'multiple' : ''  
158 - let child = buildElSelectChild(el)  
159 -  
160 - if (child) child = `\n${child}\n` // 换行  
161 - return `<${el.tag} ${vModel} ${placeholder} ${disabled} ${multiple} ${filterable} ${clearable} ${width}>${child}</${el.tag}>`  
162 - },  
163 - 'el-radio-group': el => {  
164 - const { disabled, vModel } = attrBuilder(el)  
165 - const size = `size="${el.size}"`  
166 - let child = buildElRadioGroupChild(el)  
167 -  
168 - if (child) child = `\n${child}\n` // 换行  
169 - return `<${el.tag} ${vModel} ${size} ${disabled}>${child}</${el.tag}>`  
170 - },  
171 - 'el-checkbox-group': el => {  
172 - const { disabled, vModel } = attrBuilder(el)  
173 - const size = `size="${el.size}"`  
174 - const min = el.min ? `:min="${el.min}"` : ''  
175 - const max = el.max ? `:max="${el.max}"` : ''  
176 - let child = buildElCheckboxGroupChild(el)  
177 -  
178 - if (child) child = `\n${child}\n` // 换行  
179 - return `<${el.tag} ${vModel} ${min} ${max} ${size} ${disabled}>${child}</${el.tag}>`  
180 - },  
181 - 'el-switch': el => {  
182 - const { disabled, vModel } = attrBuilder(el)  
183 - const activeText = el['active-text'] ? `active-text="${el['active-text']}"` : ''  
184 - const inactiveText = el['inactive-text'] ? `inactive-text="${el['inactive-text']}"` : ''  
185 - const activeColor = el['active-color'] ? `active-color="${el['active-color']}"` : ''  
186 - const inactiveColor = el['inactive-color'] ? `inactive-color="${el['inactive-color']}"` : ''  
187 - const activeValue = el['active-value'] !== true ? `:active-value='${JSON.stringify(el['active-value'])}'` : ''  
188 - const inactiveValue = el['inactive-value'] !== false ? `:inactive-value='${JSON.stringify(el['inactive-value'])}'` : ''  
189 -  
190 - return `<${el.tag} ${vModel} ${activeText} ${inactiveText} ${activeColor} ${inactiveColor} ${activeValue} ${inactiveValue} ${disabled}></${el.tag}>`  
191 - },  
192 - 'el-cascader': el => {  
193 - const {  
194 - disabled, vModel, clearable, placeholder, width  
195 - } = attrBuilder(el)  
196 - const options = el.options ? `:options="${el.vModel}Options"` : ''  
197 - const props = el.props ? `:props="${el.vModel}Props"` : ''  
198 - const showAllLevels = el['show-all-levels'] ? '' : ':show-all-levels="false"'  
199 - const filterable = el.filterable ? 'filterable' : ''  
200 - const separator = el.separator === '/' ? '' : `separator="${el.separator}"`  
201 -  
202 - return `<${el.tag} ${vModel} ${options} ${props} ${width} ${showAllLevels} ${placeholder} ${separator} ${filterable} ${clearable} ${disabled}></${el.tag}>`  
203 - },  
204 - 'el-slider': el => {  
205 - const { disabled, vModel } = attrBuilder(el)  
206 - const min = el.min ? `:min='${el.min}'` : ''  
207 - const max = el.max ? `:max='${el.max}'` : ''  
208 - const step = el.step ? `:step='${el.step}'` : ''  
209 - const range = el.range ? 'range' : ''  
210 - const showStops = el['show-stops'] ? `:show-stops="${el['show-stops']}"` : ''  
211 -  
212 - return `<${el.tag} ${min} ${max} ${step} ${vModel} ${range} ${showStops} ${disabled}></${el.tag}>`  
213 - },  
214 - 'el-time-picker': el => {  
215 - const {  
216 - disabled, vModel, clearable, placeholder, width  
217 - } = attrBuilder(el)  
218 - const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : ''  
219 - const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : ''  
220 - const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : ''  
221 - const isRange = el['is-range'] ? 'is-range' : ''  
222 - const format = el.format ? `format="${el.format}"` : ''  
223 - const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : ''  
224 - const pickerOptions = el['picker-options'] ? `:picker-options='${JSON.stringify(el['picker-options'])}'` : ''  
225 -  
226 - return `<${el.tag} ${vModel} ${isRange} ${format} ${valueFormat} ${pickerOptions} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${disabled}></${el.tag}>`  
227 - },  
228 - 'el-date-picker': el => {  
229 - const {  
230 - disabled, vModel, clearable, placeholder, width  
231 - } = attrBuilder(el)  
232 - const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : ''  
233 - const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : ''  
234 - const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : ''  
235 - const format = el.format ? `format="${el.format}"` : ''  
236 - const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : ''  
237 - const type = el.type === 'date' ? '' : `type="${el.type}"`  
238 - const readonly = el.readonly ? 'readonly' : ''  
239 -  
240 - return `<${el.tag} ${type} ${vModel} ${format} ${valueFormat} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${readonly} ${disabled}></${el.tag}>`  
241 - },  
242 - 'el-rate': el => {  
243 - const { disabled, vModel } = attrBuilder(el)  
244 - const max = el.max ? `:max='${el.max}'` : ''  
245 - const allowHalf = el['allow-half'] ? 'allow-half' : ''  
246 - const showText = el['show-text'] ? 'show-text' : ''  
247 - const showScore = el['show-score'] ? 'show-score' : ''  
248 -  
249 - return `<${el.tag} ${vModel} ${allowHalf} ${showText} ${showScore} ${disabled}></${el.tag}>`  
250 - },  
251 - 'el-color-picker': el => {  
252 - const { disabled, vModel } = attrBuilder(el)  
253 - const size = `size="${el.size}"`  
254 - const showAlpha = el['show-alpha'] ? 'show-alpha' : ''  
255 - const colorFormat = el['color-format'] ? `color-format="${el['color-format']}"` : ''  
256 -  
257 - return `<${el.tag} ${vModel} ${size} ${showAlpha} ${colorFormat} ${disabled}></${el.tag}>`  
258 - },  
259 - 'el-upload': el => {  
260 - const disabled = el.disabled ? ':disabled=\'true\'' : ''  
261 - const action = el.action ? `:action="${el.vModel}Action"` : ''  
262 - const multiple = el.multiple ? 'multiple' : ''  
263 - const listType = el['list-type'] !== 'text' ? `list-type="${el['list-type']}"` : ''  
264 - const accept = el.accept ? `accept="${el.accept}"` : ''  
265 - const name = el.name !== 'file' ? `name="${el.name}"` : ''  
266 - const autoUpload = el['auto-upload'] === false ? ':auto-upload="false"' : ''  
267 - const beforeUpload = `:before-upload="${el.vModel}BeforeUpload"`  
268 - const fileList = `:file-list="${el.vModel}fileList"`  
269 - const ref = `ref="${el.vModel}"`  
270 - let child = buildElUploadChild(el)  
271 -  
272 - if (child) child = `\n${child}\n` // 换行  
273 - return `<${el.tag} ${ref} ${fileList} ${action} ${autoUpload} ${multiple} ${beforeUpload} ${listType} ${accept} ${name} ${disabled}>${child}</${el.tag}>`  
274 - }  
275 -}  
276 -  
277 -function attrBuilder(el) {  
278 - return {  
279 - vModel: `v-model="${confGlobal.formModel}.${el.vModel}"`,  
280 - clearable: el.clearable ? 'clearable' : '',  
281 - placeholder: el.placeholder ? `placeholder="${el.placeholder}"` : '',  
282 - width: el.style && el.style.width ? ':style="{width: \'100%\'}"' : '',  
283 - disabled: el.disabled ? ':disabled=\'true\'' : ''  
284 - }  
285 -}  
286 -  
287 -// el-buttin 子级  
288 -function buildElButtonChild(conf) {  
289 - const children = []  
290 - if (conf.default) {  
291 - children.push(conf.default)  
292 - }  
293 - return children.join('\n')  
294 -}  
295 -  
296 -// el-input innerHTML  
297 -function buildElInputChild(conf) {  
298 - const children = []  
299 - if (conf.prepend) {  
300 - children.push(`<template slot="prepend">${conf.prepend}</template>`)  
301 - }  
302 - if (conf.append) {  
303 - children.push(`<template slot="append">${conf.append}</template>`)  
304 - }  
305 - return children.join('\n')  
306 -}  
307 -  
308 -function buildElSelectChild(conf) {  
309 - const children = []  
310 - if (conf.options && conf.options.length) {  
311 - children.push(`<el-option v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.label" :value="item.value" :disabled="item.disabled"></el-option>`)  
312 - }  
313 - return children.join('\n')  
314 -}  
315 -  
316 -function buildElRadioGroupChild(conf) {  
317 - const children = []  
318 - if (conf.options && conf.options.length) {  
319 - const tag = conf.optionType === 'button' ? 'el-radio-button' : 'el-radio'  
320 - const border = conf.border ? 'border' : ''  
321 - children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}</${tag}>`)  
322 - }  
323 - return children.join('\n')  
324 -}  
325 -  
326 -function buildElCheckboxGroupChild(conf) {  
327 - const children = []  
328 - if (conf.options && conf.options.length) {  
329 - const tag = conf.optionType === 'button' ? 'el-checkbox-button' : 'el-checkbox'  
330 - const border = conf.border ? 'border' : ''  
331 - children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}</${tag}>`)  
332 - }  
333 - return children.join('\n')  
334 -}  
335 -  
336 -function buildElUploadChild(conf) {  
337 - const list = []  
338 - if (conf['list-type'] === 'picture-card') list.push('<i class="el-icon-plus"></i>')  
339 - else list.push(`<el-button size="small" type="primary" icon="el-icon-upload">${conf.buttonText}</el-button>`)  
340 - if (conf.showTip) list.push(`<div slot="tip" class="el-upload__tip">只能上传不超过 ${conf.fileSize}${conf.sizeUnit} ${conf.accept}文件</div>`)  
341 - return list.join('\n')  
342 -}  
343 -  
344 -export function makeUpHtml(conf, type) {  
345 - const htmlList = []  
346 - confGlobal = conf  
347 - someSpanIsNot24 = conf.fields.some(item => item.span !== 24)  
348 - conf.fields.forEach(el => {  
349 - htmlList.push(layouts[el.layout](el))  
350 - })  
351 - const htmlStr = htmlList.join('\n')  
352 -  
353 - let temp = buildFormTemplate(conf, htmlStr, type)  
354 - if (type === 'dialog') {  
355 - temp = dialogWrapper(temp)  
356 - }  
357 - confGlobal = null  
358 - return temp  
359 -} 1 +/* eslint-disable max-len */
  2 +import { trigger } from './config'
  3 +
  4 +let confGlobal
  5 +let someSpanIsNot24
  6 +
  7 +export function dialogWrapper(str) {
  8 + return `<el-dialog v-bind="$attrs" v-on="$listeners" @open="onOpen" @close="onClose" title="Dialog Title">
  9 + ${str}
  10 + <div slot="footer">
  11 + <el-button @click="close">取消</el-button>
  12 + <el-button type="primary" @click="handleConfirm">确定</el-button>
  13 + </div>
  14 + </el-dialog>`
  15 +}
  16 +
  17 +export function vueTemplate(str) {
  18 + return `<template>
  19 + <div>
  20 + ${str}
  21 + </div>
  22 + </template>`
  23 +}
  24 +
  25 +export function vueScript(str) {
  26 + return `<script>
  27 + ${str}
  28 + </script>`
  29 +}
  30 +
  31 +export function cssStyle(cssStr) {
  32 + return `<style>
  33 + ${cssStr}
  34 + </style>`
  35 +}
  36 +
  37 +function buildFormTemplate(conf, child, type) {
  38 + let labelPosition = ''
  39 + if (conf.labelPosition !== 'right') {
  40 + labelPosition = `label-position="${conf.labelPosition}"`
  41 + }
  42 + const disabled = conf.disabled ? `:disabled="${conf.disabled}"` : ''
  43 + let str = `<el-form ref="${conf.formRef}" :model="${conf.formModel}" :rules="${conf.formRules}" size="${conf.size}" ${disabled} label-width="${conf.labelWidth}px" ${labelPosition}>
  44 + ${child}
  45 + ${buildFromBtns(conf, type)}
  46 + </el-form>`
  47 + if (someSpanIsNot24) {
  48 + str = `<el-row :gutter="${conf.gutter}">
  49 + ${str}
  50 + </el-row>`
  51 + }
  52 + return str
  53 +}
  54 +
  55 +function buildFromBtns(conf, type) {
  56 + let str = ''
  57 + if (conf.formBtns && type === 'file') {
  58 + str = `<el-form-item size="large">
  59 + <el-button type="primary" @click="submitForm">提交</el-button>
  60 + <el-button @click="resetForm">重置</el-button>
  61 + </el-form-item>`
  62 + if (someSpanIsNot24) {
  63 + str = `<el-col :span="24">
  64 + ${str}
  65 + </el-col>`
  66 + }
  67 + }
  68 + return str
  69 +}
  70 +
  71 +// span不为24的用el-col包裹
  72 +function colWrapper(element, str) {
  73 + if (someSpanIsNot24 || element.span !== 24) {
  74 + return `<el-col :span="${element.span}">
  75 + ${str}
  76 + </el-col>`
  77 + }
  78 + return str
  79 +}
  80 +
  81 +const layouts = {
  82 + colFormItem(element) {
  83 + let labelWidth = ''
  84 + if (element.labelWidth && element.labelWidth !== confGlobal.labelWidth) {
  85 + labelWidth = `label-width="${element.labelWidth}px"`
  86 + }
  87 + const required = !trigger[element.tag] && element.required ? 'required' : ''
  88 + const tagDom = tags[element.tag] ? tags[element.tag](element) : null
  89 + let str = `<el-form-item ${labelWidth} label="${element.label}" prop="${element.vModel}" ${required}>
  90 + ${tagDom}
  91 + </el-form-item>`
  92 + str = colWrapper(element, str)
  93 + return str
  94 + },
  95 + rowFormItem(element) {
  96 + const type = element.type === 'default' ? '' : `type="${element.type}"`
  97 + const justify = element.type === 'default' ? '' : `justify="${element.justify}"`
  98 + const align = element.type === 'default' ? '' : `align="${element.align}"`
  99 + const gutter = element.gutter ? `gutter="${element.gutter}"` : ''
  100 + const children = element.children.map(el => layouts[el.layout](el))
  101 + let str = `<el-row ${type} ${justify} ${align} ${gutter}>
  102 + ${children.join('\n')}
  103 + </el-row>`
  104 + str = colWrapper(element, str)
  105 + return str
  106 + }
  107 +}
  108 +
  109 +const tags = {
  110 + 'el-button': el => {
  111 + const {
  112 + tag, disabled
  113 + } = attrBuilder(el)
  114 + const type = el.type ? `type="${el.type}"` : ''
  115 + const icon = el.icon ? `icon="${el.icon}"` : ''
  116 + const size = el.size ? `size="${el.size}"` : ''
  117 + let child = buildElButtonChild(el)
  118 +
  119 + if (child) child = `\n${child}\n` // 换行
  120 + return `<${el.tag} ${type} ${icon} ${size} ${disabled}>${child}</${el.tag}>`
  121 + },
  122 + 'el-input': el => {
  123 + const {
  124 + disabled, vModel, clearable, placeholder, width
  125 + } = attrBuilder(el)
  126 + const maxlength = el.maxlength ? `:maxlength="${el.maxlength}"` : ''
  127 + const showWordLimit = el['show-word-limit'] ? 'show-word-limit' : ''
  128 + const readonly = el.readonly ? 'readonly' : ''
  129 + const prefixIcon = el['prefix-icon'] ? `prefix-icon='${el['prefix-icon']}'` : ''
  130 + const suffixIcon = el['suffix-icon'] ? `suffix-icon='${el['suffix-icon']}'` : ''
  131 + const showPassword = el['show-password'] ? 'show-password' : ''
  132 + const type = el.type ? `type="${el.type}"` : ''
  133 + const autosize = el.autosize && el.autosize.minRows
  134 + ? `:autosize="{minRows: ${el.autosize.minRows}, maxRows: ${el.autosize.maxRows}}"`
  135 + : ''
  136 + let child = buildElInputChild(el)
  137 +
  138 + if (child) child = `\n${child}\n` // 换行
  139 + return `<${el.tag} ${vModel} ${type} ${placeholder} ${maxlength} ${showWordLimit} ${readonly} ${disabled} ${clearable} ${prefixIcon} ${suffixIcon} ${showPassword} ${autosize} ${width}>${child}</${el.tag}>`
  140 + },
  141 + 'el-input-number': el => {
  142 + const { disabled, vModel, placeholder } = attrBuilder(el)
  143 + const controlsPosition = el['controls-position'] ? `controls-position=${el['controls-position']}` : ''
  144 + const min = el.min ? `:min='${el.min}'` : ''
  145 + const max = el.max ? `:max='${el.max}'` : ''
  146 + const step = el.step ? `:step='${el.step}'` : ''
  147 + const stepStrictly = el['step-strictly'] ? 'step-strictly' : ''
  148 + const precision = el.precision ? `:precision='${el.precision}'` : ''
  149 +
  150 + return `<${el.tag} ${vModel} ${placeholder} ${step} ${stepStrictly} ${precision} ${controlsPosition} ${min} ${max} ${disabled}></${el.tag}>`
  151 + },
  152 + 'el-select': el => {
  153 + const {
  154 + disabled, vModel, clearable, placeholder, width
  155 + } = attrBuilder(el)
  156 + const filterable = el.filterable ? 'filterable' : ''
  157 + const multiple = el.multiple ? 'multiple' : ''
  158 + let child = buildElSelectChild(el)
  159 +
  160 + if (child) child = `\n${child}\n` // 换行
  161 + return `<${el.tag} ${vModel} ${placeholder} ${disabled} ${multiple} ${filterable} ${clearable} ${width}>${child}</${el.tag}>`
  162 + },
  163 + 'el-radio-group': el => {
  164 + const { disabled, vModel } = attrBuilder(el)
  165 + const size = `size="${el.size}"`
  166 + let child = buildElRadioGroupChild(el)
  167 +
  168 + if (child) child = `\n${child}\n` // 换行
  169 + return `<${el.tag} ${vModel} ${size} ${disabled}>${child}</${el.tag}>`
  170 + },
  171 + 'el-checkbox-group': el => {
  172 + const { disabled, vModel } = attrBuilder(el)
  173 + const size = `size="${el.size}"`
  174 + const min = el.min ? `:min="${el.min}"` : ''
  175 + const max = el.max ? `:max="${el.max}"` : ''
  176 + let child = buildElCheckboxGroupChild(el)
  177 +
  178 + if (child) child = `\n${child}\n` // 换行
  179 + return `<${el.tag} ${vModel} ${min} ${max} ${size} ${disabled}>${child}</${el.tag}>`
  180 + },
  181 + 'el-switch': el => {
  182 + const { disabled, vModel } = attrBuilder(el)
  183 + const activeText = el['active-text'] ? `active-text="${el['active-text']}"` : ''
  184 + const inactiveText = el['inactive-text'] ? `inactive-text="${el['inactive-text']}"` : ''
  185 + const activeColor = el['active-color'] ? `active-color="${el['active-color']}"` : ''
  186 + const inactiveColor = el['inactive-color'] ? `inactive-color="${el['inactive-color']}"` : ''
  187 + const activeValue = el['active-value'] !== true ? `:active-value='${JSON.stringify(el['active-value'])}'` : ''
  188 + const inactiveValue = el['inactive-value'] !== false ? `:inactive-value='${JSON.stringify(el['inactive-value'])}'` : ''
  189 +
  190 + return `<${el.tag} ${vModel} ${activeText} ${inactiveText} ${activeColor} ${inactiveColor} ${activeValue} ${inactiveValue} ${disabled}></${el.tag}>`
  191 + },
  192 + 'el-cascader': el => {
  193 + const {
  194 + disabled, vModel, clearable, placeholder, width
  195 + } = attrBuilder(el)
  196 + const options = el.options ? `:options="${el.vModel}Options"` : ''
  197 + const props = el.props ? `:props="${el.vModel}Props"` : ''
  198 + const showAllLevels = el['show-all-levels'] ? '' : ':show-all-levels="false"'
  199 + const filterable = el.filterable ? 'filterable' : ''
  200 + const separator = el.separator === '/' ? '' : `separator="${el.separator}"`
  201 +
  202 + return `<${el.tag} ${vModel} ${options} ${props} ${width} ${showAllLevels} ${placeholder} ${separator} ${filterable} ${clearable} ${disabled}></${el.tag}>`
  203 + },
  204 + 'el-slider': el => {
  205 + const { disabled, vModel } = attrBuilder(el)
  206 + const min = el.min ? `:min='${el.min}'` : ''
  207 + const max = el.max ? `:max='${el.max}'` : ''
  208 + const step = el.step ? `:step='${el.step}'` : ''
  209 + const range = el.range ? 'range' : ''
  210 + const showStops = el['show-stops'] ? `:show-stops="${el['show-stops']}"` : ''
  211 +
  212 + return `<${el.tag} ${min} ${max} ${step} ${vModel} ${range} ${showStops} ${disabled}></${el.tag}>`
  213 + },
  214 + 'el-time-picker': el => {
  215 + const {
  216 + disabled, vModel, clearable, placeholder, width
  217 + } = attrBuilder(el)
  218 + const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : ''
  219 + const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : ''
  220 + const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : ''
  221 + const isRange = el['is-range'] ? 'is-range' : ''
  222 + const format = el.format ? `format="${el.format}"` : ''
  223 + const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : ''
  224 + const pickerOptions = el['picker-options'] ? `:picker-options='${JSON.stringify(el['picker-options'])}'` : ''
  225 +
  226 + return `<${el.tag} ${vModel} ${isRange} ${format} ${valueFormat} ${pickerOptions} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${disabled}></${el.tag}>`
  227 + },
  228 + 'el-date-picker': el => {
  229 + const {
  230 + disabled, vModel, clearable, placeholder, width
  231 + } = attrBuilder(el)
  232 + const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : ''
  233 + const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : ''
  234 + const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : ''
  235 + const format = el.format ? `format="${el.format}"` : ''
  236 + const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : ''
  237 + const type = el.type === 'date' ? '' : `type="${el.type}"`
  238 + const readonly = el.readonly ? 'readonly' : ''
  239 +
  240 + return `<${el.tag} ${type} ${vModel} ${format} ${valueFormat} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${readonly} ${disabled}></${el.tag}>`
  241 + },
  242 + 'el-rate': el => {
  243 + const { disabled, vModel } = attrBuilder(el)
  244 + const max = el.max ? `:max='${el.max}'` : ''
  245 + const allowHalf = el['allow-half'] ? 'allow-half' : ''
  246 + const showText = el['show-text'] ? 'show-text' : ''
  247 + const showScore = el['show-score'] ? 'show-score' : ''
  248 +
  249 + return `<${el.tag} ${vModel} ${allowHalf} ${showText} ${showScore} ${disabled}></${el.tag}>`
  250 + },
  251 + 'el-color-picker': el => {
  252 + const { disabled, vModel } = attrBuilder(el)
  253 + const size = `size="${el.size}"`
  254 + const showAlpha = el['show-alpha'] ? 'show-alpha' : ''
  255 + const colorFormat = el['color-format'] ? `color-format="${el['color-format']}"` : ''
  256 +
  257 + return `<${el.tag} ${vModel} ${size} ${showAlpha} ${colorFormat} ${disabled}></${el.tag}>`
  258 + },
  259 + 'el-upload': el => {
  260 + const disabled = el.disabled ? ':disabled=\'true\'' : ''
  261 + const action = el.action ? `:action="${el.vModel}Action"` : ''
  262 + const multiple = el.multiple ? 'multiple' : ''
  263 + const listType = el['list-type'] !== 'text' ? `list-type="${el['list-type']}"` : ''
  264 + const accept = el.accept ? `accept="${el.accept}"` : ''
  265 + const name = el.name !== 'file' ? `name="${el.name}"` : ''
  266 + const autoUpload = el['auto-upload'] === false ? ':auto-upload="false"' : ''
  267 + const beforeUpload = `:before-upload="${el.vModel}BeforeUpload"`
  268 + const fileList = `:file-list="${el.vModel}fileList"`
  269 + const ref = `ref="${el.vModel}"`
  270 + let child = buildElUploadChild(el)
  271 +
  272 + if (child) child = `\n${child}\n` // 换行
  273 + return `<${el.tag} ${ref} ${fileList} ${action} ${autoUpload} ${multiple} ${beforeUpload} ${listType} ${accept} ${name} ${disabled}>${child}</${el.tag}>`
  274 + }
  275 +}
  276 +
  277 +function attrBuilder(el) {
  278 + return {
  279 + vModel: `v-model="${confGlobal.formModel}.${el.vModel}"`,
  280 + clearable: el.clearable ? 'clearable' : '',
  281 + placeholder: el.placeholder ? `placeholder="${el.placeholder}"` : '',
  282 + width: el.style && el.style.width ? ':style="{width: \'100%\'}"' : '',
  283 + disabled: el.disabled ? ':disabled=\'true\'' : ''
  284 + }
  285 +}
  286 +
  287 +// el-buttin 子级
  288 +function buildElButtonChild(conf) {
  289 + const children = []
  290 + if (conf.default) {
  291 + children.push(conf.default)
  292 + }
  293 + return children.join('\n')
  294 +}
  295 +
  296 +// el-input innerHTML
  297 +function buildElInputChild(conf) {
  298 + const children = []
  299 + if (conf.prepend) {
  300 + children.push(`<template slot="prepend">${conf.prepend}</template>`)
  301 + }
  302 + if (conf.append) {
  303 + children.push(`<template slot="append">${conf.append}</template>`)
  304 + }
  305 + return children.join('\n')
  306 +}
  307 +
  308 +function buildElSelectChild(conf) {
  309 + const children = []
  310 + if (conf.options && conf.options.length) {
  311 + children.push(`<el-option v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.label" :value="item.value" :disabled="item.disabled"></el-option>`)
  312 + }
  313 + return children.join('\n')
  314 +}
  315 +
  316 +function buildElRadioGroupChild(conf) {
  317 + const children = []
  318 + if (conf.options && conf.options.length) {
  319 + const tag = conf.optionType === 'button' ? 'el-radio-button' : 'el-radio'
  320 + const border = conf.border ? 'border' : ''
  321 + children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}</${tag}>`)
  322 + }
  323 + return children.join('\n')
  324 +}
  325 +
  326 +function buildElCheckboxGroupChild(conf) {
  327 + const children = []
  328 + if (conf.options && conf.options.length) {
  329 + const tag = conf.optionType === 'button' ? 'el-checkbox-button' : 'el-checkbox'
  330 + const border = conf.border ? 'border' : ''
  331 + children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}</${tag}>`)
  332 + }
  333 + return children.join('\n')
  334 +}
  335 +
  336 +function buildElUploadChild(conf) {
  337 + const list = []
  338 + if (conf['list-type'] === 'picture-card') list.push('<i class="el-icon-plus"></i>')
  339 + else list.push(`<el-button size="small" type="primary" icon="el-icon-upload">${conf.buttonText}</el-button>`)
  340 + if (conf.showTip) list.push(`<div slot="tip" class="el-upload__tip">只能上传不超过 ${conf.fileSize}${conf.sizeUnit} ${conf.accept}文件</div>`)
  341 + return list.join('\n')
  342 +}
  343 +
  344 +export function makeUpHtml(conf, type) {
  345 + const htmlList = []
  346 + confGlobal = conf
  347 + someSpanIsNot24 = conf.fields.some(item => item.span !== 24)
  348 + conf.fields.forEach(el => {
  349 + htmlList.push(layouts[el.layout](el))
  350 + })
  351 + const htmlStr = htmlList.join('\n')
  352 +
  353 + let temp = buildFormTemplate(conf, htmlStr, type)
  354 + if (type === 'dialog') {
  355 + temp = dialogWrapper(temp)
  356 + }
  357 + confGlobal = null
  358 + return temp
  359 +}
1 -import { isArray } from 'util'  
2 -import { exportDefault, titleCase } from '@/utils/index'  
3 -import { trigger } from './config'  
4 -  
5 -const units = {  
6 - KB: '1024',  
7 - MB: '1024 / 1024',  
8 - GB: '1024 / 1024 / 1024'  
9 -}  
10 -let confGlobal  
11 -const inheritAttrs = {  
12 - file: '',  
13 - dialog: 'inheritAttrs: false,'  
14 -}  
15 -  
16 -  
17 -export function makeUpJs(conf, type) {  
18 - confGlobal = conf = JSON.parse(JSON.stringify(conf))  
19 - const dataList = []  
20 - const ruleList = []  
21 - const optionsList = []  
22 - const propsList = []  
23 - const methodList = mixinMethod(type)  
24 - const uploadVarList = []  
25 -  
26 - conf.fields.forEach(el => {  
27 - buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList)  
28 - })  
29 -  
30 - const script = buildexport(  
31 - conf,  
32 - type,  
33 - dataList.join('\n'),  
34 - ruleList.join('\n'),  
35 - optionsList.join('\n'),  
36 - uploadVarList.join('\n'),  
37 - propsList.join('\n'),  
38 - methodList.join('\n')  
39 - )  
40 - confGlobal = null  
41 - return script  
42 -}  
43 -  
44 -function buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList) {  
45 - buildData(el, dataList)  
46 - buildRules(el, ruleList)  
47 -  
48 - if (el.options && el.options.length) {  
49 - buildOptions(el, optionsList)  
50 - if (el.dataType === 'dynamic') {  
51 - const model = `${el.vModel}Options`  
52 - const options = titleCase(model)  
53 - buildOptionMethod(`get${options}`, model, methodList)  
54 - }  
55 - }  
56 -  
57 - if (el.props && el.props.props) {  
58 - buildProps(el, propsList)  
59 - }  
60 -  
61 - if (el.action && el.tag === 'el-upload') {  
62 - uploadVarList.push(  
63 - `${el.vModel}Action: '${el.action}',  
64 - ${el.vModel}fileList: [],`  
65 - )  
66 - methodList.push(buildBeforeUpload(el))  
67 - if (!el['auto-upload']) {  
68 - methodList.push(buildSubmitUpload(el))  
69 - }  
70 - }  
71 -  
72 - if (el.children) {  
73 - el.children.forEach(el2 => {  
74 - buildAttributes(el2, dataList, ruleList, optionsList, methodList, propsList, uploadVarList)  
75 - })  
76 - }  
77 -}  
78 -  
79 -function mixinMethod(type) {  
80 - const list = []; const  
81 - minxins = {  
82 - file: confGlobal.formBtns ? {  
83 - submitForm: `submitForm() {  
84 - this.$refs['${confGlobal.formRef}'].validate(valid => {  
85 - if(!valid) return  
86 - // TODO 提交表单  
87 - })  
88 - },`,  
89 - resetForm: `resetForm() {  
90 - this.$refs['${confGlobal.formRef}'].resetFields()  
91 - },`  
92 - } : null,  
93 - dialog: {  
94 - onOpen: 'onOpen() {},',  
95 - onClose: `onClose() {  
96 - this.$refs['${confGlobal.formRef}'].resetFields()  
97 - },`,  
98 - close: `close() {  
99 - this.$emit('update:visible', false)  
100 - },`,  
101 - handelConfirm: `handelConfirm() {  
102 - this.$refs['${confGlobal.formRef}'].validate(valid => {  
103 - if(!valid) return  
104 - this.close()  
105 - })  
106 - },`  
107 - }  
108 - }  
109 -  
110 - const methods = minxins[type]  
111 - if (methods) {  
112 - Object.keys(methods).forEach(key => {  
113 - list.push(methods[key])  
114 - })  
115 - }  
116 -  
117 - return list  
118 -}  
119 -  
120 -function buildData(conf, dataList) {  
121 - if (conf.vModel === undefined) return  
122 - let defaultValue  
123 - if (typeof (conf.defaultValue) === 'string' && !conf.multiple) {  
124 - defaultValue = `'${conf.defaultValue}'`  
125 - } else {  
126 - defaultValue = `${JSON.stringify(conf.defaultValue)}`  
127 - }  
128 - dataList.push(`${conf.vModel}: ${defaultValue},`)  
129 -}  
130 -  
131 -function buildRules(conf, ruleList) {  
132 - if (conf.vModel === undefined) return  
133 - const rules = []  
134 - if (trigger[conf.tag]) {  
135 - if (conf.required) {  
136 - const type = isArray(conf.defaultValue) ? 'type: \'array\',' : ''  
137 - let message = isArray(conf.defaultValue) ? `请至少选择一个${conf.vModel}` : conf.placeholder  
138 - if (message === undefined) message = `${conf.label}不能为空`  
139 - rules.push(`{ required: true, ${type} message: '${message}', trigger: '${trigger[conf.tag]}' }`)  
140 - }  
141 - if (conf.regList && isArray(conf.regList)) {  
142 - conf.regList.forEach(item => {  
143 - if (item.pattern) {  
144 - rules.push(`{ pattern: ${eval(item.pattern)}, message: '${item.message}', trigger: '${trigger[conf.tag]}' }`)  
145 - }  
146 - })  
147 - }  
148 - ruleList.push(`${conf.vModel}: [${rules.join(',')}],`)  
149 - }  
150 -}  
151 -  
152 -function buildOptions(conf, optionsList) {  
153 - if (conf.vModel === undefined) return  
154 - if (conf.dataType === 'dynamic') { conf.options = [] }  
155 - const str = `${conf.vModel}Options: ${JSON.stringify(conf.options)},`  
156 - optionsList.push(str)  
157 -}  
158 -  
159 -function buildProps(conf, propsList) {  
160 - if (conf.dataType === 'dynamic') {  
161 - conf.valueKey !== 'value' && (conf.props.props.value = conf.valueKey)  
162 - conf.labelKey !== 'label' && (conf.props.props.label = conf.labelKey)  
163 - conf.childrenKey !== 'children' && (conf.props.props.children = conf.childrenKey)  
164 - }  
165 - const str = `${conf.vModel}Props: ${JSON.stringify(conf.props.props)},`  
166 - propsList.push(str)  
167 -}  
168 -  
169 -function buildBeforeUpload(conf) {  
170 - const unitNum = units[conf.sizeUnit]; let rightSizeCode = ''; let acceptCode = ''; const  
171 - returnList = []  
172 - if (conf.fileSize) {  
173 - rightSizeCode = `let isRightSize = file.size / ${unitNum} < ${conf.fileSize}  
174 - if(!isRightSize){  
175 - this.$message.error('文件大小超过 ${conf.fileSize}${conf.sizeUnit}')  
176 - }`  
177 - returnList.push('isRightSize')  
178 - }  
179 - if (conf.accept) {  
180 - acceptCode = `let isAccept = new RegExp('${conf.accept}').test(file.type)  
181 - if(!isAccept){  
182 - this.$message.error('应该选择${conf.accept}类型的文件')  
183 - }`  
184 - returnList.push('isAccept')  
185 - }  
186 - const str = `${conf.vModel}BeforeUpload(file) {  
187 - ${rightSizeCode}  
188 - ${acceptCode}  
189 - return ${returnList.join('&&')}  
190 - },`  
191 - return returnList.length ? str : ''  
192 -}  
193 -  
194 -function buildSubmitUpload(conf) {  
195 - const str = `submitUpload() {  
196 - this.$refs['${conf.vModel}'].submit()  
197 - },`  
198 - return str  
199 -}  
200 -  
201 -function buildOptionMethod(methodName, model, methodList) {  
202 - const str = `${methodName}() {  
203 - // TODO 发起请求获取数据  
204 - this.${model}  
205 - },`  
206 - methodList.push(str)  
207 -}  
208 -  
209 -function buildexport(conf, type, data, rules, selectOptions, uploadVar, props, methods) {  
210 - const str = `${exportDefault}{  
211 - ${inheritAttrs[type]}  
212 - components: {},  
213 - props: [],  
214 - data () {  
215 - return {  
216 - ${conf.formModel}: {  
217 - ${data}  
218 - },  
219 - ${conf.formRules}: {  
220 - ${rules}  
221 - },  
222 - ${uploadVar}  
223 - ${selectOptions}  
224 - ${props}  
225 - }  
226 - },  
227 - computed: {},  
228 - watch: {},  
229 - created () {},  
230 - mounted () {},  
231 - methods: {  
232 - ${methods}  
233 - }  
234 -}`  
235 - return str  
236 -} 1 +import { isArray } from 'util'
  2 +import { exportDefault, titleCase } from '@/utils/index'
  3 +import { trigger } from './config'
  4 +
  5 +const units = {
  6 + KB: '1024',
  7 + MB: '1024 / 1024',
  8 + GB: '1024 / 1024 / 1024'
  9 +}
  10 +let confGlobal
  11 +const inheritAttrs = {
  12 + file: '',
  13 + dialog: 'inheritAttrs: false,'
  14 +}
  15 +
  16 +
  17 +export function makeUpJs(conf, type) {
  18 + confGlobal = conf = JSON.parse(JSON.stringify(conf))
  19 + const dataList = []
  20 + const ruleList = []
  21 + const optionsList = []
  22 + const propsList = []
  23 + const methodList = mixinMethod(type)
  24 + const uploadVarList = []
  25 +
  26 + conf.fields.forEach(el => {
  27 + buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList)
  28 + })
  29 +
  30 + const script = buildexport(
  31 + conf,
  32 + type,
  33 + dataList.join('\n'),
  34 + ruleList.join('\n'),
  35 + optionsList.join('\n'),
  36 + uploadVarList.join('\n'),
  37 + propsList.join('\n'),
  38 + methodList.join('\n')
  39 + )
  40 + confGlobal = null
  41 + return script
  42 +}
  43 +
  44 +function buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList) {
  45 + buildData(el, dataList)
  46 + buildRules(el, ruleList)
  47 +
  48 + if (el.options && el.options.length) {
  49 + buildOptions(el, optionsList)
  50 + if (el.dataType === 'dynamic') {
  51 + const model = `${el.vModel}Options`
  52 + const options = titleCase(model)
  53 + buildOptionMethod(`get${options}`, model, methodList)
  54 + }
  55 + }
  56 +
  57 + if (el.props && el.props.props) {
  58 + buildProps(el, propsList)
  59 + }
  60 +
  61 + if (el.action && el.tag === 'el-upload') {
  62 + uploadVarList.push(
  63 + `${el.vModel}Action: '${el.action}',
  64 + ${el.vModel}fileList: [],`
  65 + )
  66 + methodList.push(buildBeforeUpload(el))
  67 + if (!el['auto-upload']) {
  68 + methodList.push(buildSubmitUpload(el))
  69 + }
  70 + }
  71 +
  72 + if (el.children) {
  73 + el.children.forEach(el2 => {
  74 + buildAttributes(el2, dataList, ruleList, optionsList, methodList, propsList, uploadVarList)
  75 + })
  76 + }
  77 +}
  78 +
  79 +function mixinMethod(type) {
  80 + const list = []; const
  81 + minxins = {
  82 + file: confGlobal.formBtns ? {
  83 + submitForm: `submitForm() {
  84 + this.$refs['${confGlobal.formRef}'].validate(valid => {
  85 + if(!valid) return
  86 + // TODO 提交表单
  87 + })
  88 + },`,
  89 + resetForm: `resetForm() {
  90 + this.$refs['${confGlobal.formRef}'].resetFields()
  91 + },`
  92 + } : null,
  93 + dialog: {
  94 + onOpen: 'onOpen() {},',
  95 + onClose: `onClose() {
  96 + this.$refs['${confGlobal.formRef}'].resetFields()
  97 + },`,
  98 + close: `close() {
  99 + this.$emit('update:visible', false)
  100 + },`,
  101 + handleConfirm: `handleConfirm() {
  102 + this.$refs['${confGlobal.formRef}'].validate(valid => {
  103 + if(!valid) return
  104 + this.close()
  105 + })
  106 + },`
  107 + }
  108 + }
  109 +
  110 + const methods = minxins[type]
  111 + if (methods) {
  112 + Object.keys(methods).forEach(key => {
  113 + list.push(methods[key])
  114 + })
  115 + }
  116 +
  117 + return list
  118 +}
  119 +
  120 +function buildData(conf, dataList) {
  121 + if (conf.vModel === undefined) return
  122 + let defaultValue
  123 + if (typeof (conf.defaultValue) === 'string' && !conf.multiple) {
  124 + defaultValue = `'${conf.defaultValue}'`
  125 + } else {
  126 + defaultValue = `${JSON.stringify(conf.defaultValue)}`
  127 + }
  128 + dataList.push(`${conf.vModel}: ${defaultValue},`)
  129 +}
  130 +
  131 +function buildRules(conf, ruleList) {
  132 + if (conf.vModel === undefined) return
  133 + const rules = []
  134 + if (trigger[conf.tag]) {
  135 + if (conf.required) {
  136 + const type = isArray(conf.defaultValue) ? 'type: \'array\',' : ''
  137 + let message = isArray(conf.defaultValue) ? `请至少选择一个${conf.vModel}` : conf.placeholder
  138 + if (message === undefined) message = `${conf.label}不能为空`
  139 + rules.push(`{ required: true, ${type} message: '${message}', trigger: '${trigger[conf.tag]}' }`)
  140 + }
  141 + if (conf.regList && isArray(conf.regList)) {
  142 + conf.regList.forEach(item => {
  143 + if (item.pattern) {
  144 + rules.push(`{ pattern: ${eval(item.pattern)}, message: '${item.message}', trigger: '${trigger[conf.tag]}' }`)
  145 + }
  146 + })
  147 + }
  148 + ruleList.push(`${conf.vModel}: [${rules.join(',')}],`)
  149 + }
  150 +}
  151 +
  152 +function buildOptions(conf, optionsList) {
  153 + if (conf.vModel === undefined) return
  154 + if (conf.dataType === 'dynamic') { conf.options = [] }
  155 + const str = `${conf.vModel}Options: ${JSON.stringify(conf.options)},`
  156 + optionsList.push(str)
  157 +}
  158 +
  159 +function buildProps(conf, propsList) {
  160 + if (conf.dataType === 'dynamic') {
  161 + conf.valueKey !== 'value' && (conf.props.props.value = conf.valueKey)
  162 + conf.labelKey !== 'label' && (conf.props.props.label = conf.labelKey)
  163 + conf.childrenKey !== 'children' && (conf.props.props.children = conf.childrenKey)
  164 + }
  165 + const str = `${conf.vModel}Props: ${JSON.stringify(conf.props.props)},`
  166 + propsList.push(str)
  167 +}
  168 +
  169 +function buildBeforeUpload(conf) {
  170 + const unitNum = units[conf.sizeUnit]; let rightSizeCode = ''; let acceptCode = ''; const
  171 + returnList = []
  172 + if (conf.fileSize) {
  173 + rightSizeCode = `let isRightSize = file.size / ${unitNum} < ${conf.fileSize}
  174 + if(!isRightSize){
  175 + this.$message.error('文件大小超过 ${conf.fileSize}${conf.sizeUnit}')
  176 + }`
  177 + returnList.push('isRightSize')
  178 + }
  179 + if (conf.accept) {
  180 + acceptCode = `let isAccept = new RegExp('${conf.accept}').test(file.type)
  181 + if(!isAccept){
  182 + this.$message.error('应该选择${conf.accept}类型的文件')
  183 + }`
  184 + returnList.push('isAccept')
  185 + }
  186 + const str = `${conf.vModel}BeforeUpload(file) {
  187 + ${rightSizeCode}
  188 + ${acceptCode}
  189 + return ${returnList.join('&&')}
  190 + },`
  191 + return returnList.length ? str : ''
  192 +}
  193 +
  194 +function buildSubmitUpload(conf) {
  195 + const str = `submitUpload() {
  196 + this.$refs['${conf.vModel}'].submit()
  197 + },`
  198 + return str
  199 +}
  200 +
  201 +function buildOptionMethod(methodName, model, methodList) {
  202 + const str = `${methodName}() {
  203 + // TODO 发起请求获取数据
  204 + this.${model}
  205 + },`
  206 + methodList.push(str)
  207 +}
  208 +
  209 +function buildexport(conf, type, data, rules, selectOptions, uploadVar, props, methods) {
  210 + const str = `${exportDefault}{
  211 + ${inheritAttrs[type]}
  212 + components: {},
  213 + props: [],
  214 + data () {
  215 + return {
  216 + ${conf.formModel}: {
  217 + ${data}
  218 + },
  219 + ${conf.formRules}: {
  220 + ${rules}
  221 + },
  222 + ${uploadVar}
  223 + ${selectOptions}
  224 + ${props}
  225 + }
  226 + },
  227 + computed: {},
  228 + watch: {},
  229 + created () {},
  230 + mounted () {},
  231 + methods: {
  232 + ${methods}
  233 + }
  234 +}`
  235 + return str
  236 +}
1 -<template>  
2 - <div>  
3 - <el-dialog  
4 - v-bind="$attrs"  
5 - width="500px"  
6 - :close-on-click-modal="false"  
7 - :modal-append-to-body="false"  
8 - v-on="$listeners"  
9 - @open="onOpen"  
10 - @close="onClose"  
11 - >  
12 - <el-row :gutter="15">  
13 - <el-form  
14 - ref="elForm"  
15 - :model="formData"  
16 - :rules="rules"  
17 - size="medium"  
18 - label-width="100px"  
19 - >  
20 - <el-col :span="24">  
21 - <el-form-item label="生成类型" prop="type">  
22 - <el-radio-group v-model="formData.type">  
23 - <el-radio-button  
24 - v-for="(item, index) in typeOptions"  
25 - :key="index"  
26 - :label="item.value"  
27 - :disabled="item.disabled"  
28 - >  
29 - {{ item.label }}  
30 - </el-radio-button>  
31 - </el-radio-group>  
32 - </el-form-item>  
33 - <el-form-item v-if="showFileName" label="文件名" prop="fileName">  
34 - <el-input v-model="formData.fileName" placeholder="请输入文件名" clearable />  
35 - </el-form-item>  
36 - </el-col>  
37 - </el-form>  
38 - </el-row>  
39 -  
40 - <div slot="footer">  
41 - <el-button @click="close">  
42 - 取消  
43 - </el-button>  
44 - <el-button type="primary" @click="handelConfirm">  
45 - 确定  
46 - </el-button>  
47 - </div>  
48 - </el-dialog>  
49 - </div>  
50 -</template>  
51 -<script>  
52 -export default {  
53 - inheritAttrs: false,  
54 - props: ['showFileName'],  
55 - data() {  
56 - return {  
57 - formData: {  
58 - fileName: undefined,  
59 - type: 'file'  
60 - },  
61 - rules: {  
62 - fileName: [{  
63 - required: true,  
64 - message: '请输入文件名',  
65 - trigger: 'blur'  
66 - }],  
67 - type: [{  
68 - required: true,  
69 - message: '生成类型不能为空',  
70 - trigger: 'change'  
71 - }]  
72 - },  
73 - typeOptions: [{  
74 - label: '页面',  
75 - value: 'file'  
76 - }, {  
77 - label: '弹窗',  
78 - value: 'dialog'  
79 - }]  
80 - }  
81 - },  
82 - computed: {  
83 - },  
84 - watch: {},  
85 - mounted() {},  
86 - methods: {  
87 - onOpen() {  
88 - if (this.showFileName) {  
89 - this.formData.fileName = `${+new Date()}.vue`  
90 - }  
91 - },  
92 - onClose() {  
93 - },  
94 - close(e) {  
95 - this.$emit('update:visible', false)  
96 - },  
97 - handelConfirm() {  
98 - this.$refs.elForm.validate(valid => {  
99 - if (!valid) return  
100 - this.$emit('confirm', { ...this.formData })  
101 - this.close()  
102 - })  
103 - }  
104 - }  
105 -}  
106 -</script> 1 +<template>
  2 + <div>
  3 + <el-dialog
  4 + v-bind="$attrs"
  5 + width="500px"
  6 + :close-on-click-modal="false"
  7 + :modal-append-to-body="false"
  8 + v-on="$listeners"
  9 + @open="onOpen"
  10 + @close="onClose"
  11 + >
  12 + <el-row :gutter="15">
  13 + <el-form
  14 + ref="elForm"
  15 + :model="formData"
  16 + :rules="rules"
  17 + size="medium"
  18 + label-width="100px"
  19 + >
  20 + <el-col :span="24">
  21 + <el-form-item label="生成类型" prop="type">
  22 + <el-radio-group v-model="formData.type">
  23 + <el-radio-button
  24 + v-for="(item, index) in typeOptions"
  25 + :key="index"
  26 + :label="item.value"
  27 + :disabled="item.disabled"
  28 + >
  29 + {{ item.label }}
  30 + </el-radio-button>
  31 + </el-radio-group>
  32 + </el-form-item>
  33 + <el-form-item v-if="showFileName" label="文件名" prop="fileName">
  34 + <el-input v-model="formData.fileName" placeholder="请输入文件名" clearable />
  35 + </el-form-item>
  36 + </el-col>
  37 + </el-form>
  38 + </el-row>
  39 +
  40 + <div slot="footer">
  41 + <el-button @click="close">
  42 + 取消
  43 + </el-button>
  44 + <el-button type="primary" @click="handleConfirm">
  45 + 确定
  46 + </el-button>
  47 + </div>
  48 + </el-dialog>
  49 + </div>
  50 +</template>
  51 +<script>
  52 +export default {
  53 + inheritAttrs: false,
  54 + props: ['showFileName'],
  55 + data() {
  56 + return {
  57 + formData: {
  58 + fileName: undefined,
  59 + type: 'file'
  60 + },
  61 + rules: {
  62 + fileName: [{
  63 + required: true,
  64 + message: '请输入文件名',
  65 + trigger: 'blur'
  66 + }],
  67 + type: [{
  68 + required: true,
  69 + message: '生成类型不能为空',
  70 + trigger: 'change'
  71 + }]
  72 + },
  73 + typeOptions: [{
  74 + label: '页面',
  75 + value: 'file'
  76 + }, {
  77 + label: '弹窗',
  78 + value: 'dialog'
  79 + }]
  80 + }
  81 + },
  82 + computed: {
  83 + },
  84 + watch: {},
  85 + mounted() {},
  86 + methods: {
  87 + onOpen() {
  88 + if (this.showFileName) {
  89 + this.formData.fileName = `${+new Date()}.vue`
  90 + }
  91 + },
  92 + onClose() {
  93 + },
  94 + close(e) {
  95 + this.$emit('update:visible', false)
  96 + },
  97 + handleConfirm() {
  98 + this.$refs.elForm.validate(valid => {
  99 + if (!valid) return
  100 + this.$emit('confirm', { ...this.formData })
  101 + this.close()
  102 + })
  103 + }
  104 + }
  105 +}
  106 +</script>
1 -<template>  
2 - <div>  
3 - <el-dialog  
4 - v-bind="$attrs"  
5 - :close-on-click-modal="false"  
6 - :modal-append-to-body="false"  
7 - v-on="$listeners"  
8 - @open="onOpen"  
9 - @close="onClose"  
10 - >  
11 - <el-row :gutter="0">  
12 - <el-form  
13 - ref="elForm"  
14 - :model="formData"  
15 - :rules="rules"  
16 - size="small"  
17 - label-width="100px"  
18 - >  
19 - <el-col :span="24">  
20 - <el-form-item  
21 - label="选项名"  
22 - prop="label"  
23 - >  
24 - <el-input  
25 - v-model="formData.label"  
26 - placeholder="请输入选项名"  
27 - clearable  
28 - />  
29 - </el-form-item>  
30 - </el-col>  
31 - <el-col :span="24">  
32 - <el-form-item  
33 - label="选项值"  
34 - prop="value"  
35 - >  
36 - <el-input  
37 - v-model="formData.value"  
38 - placeholder="请输入选项值"  
39 - clearable  
40 - >  
41 - <el-select  
42 - slot="append"  
43 - v-model="dataType"  
44 - :style="{width: '100px'}"  
45 - >  
46 - <el-option  
47 - v-for="(item, index) in dataTypeOptions"  
48 - :key="index"  
49 - :label="item.label"  
50 - :value="item.value"  
51 - :disabled="item.disabled"  
52 - />  
53 - </el-select>  
54 - </el-input>  
55 - </el-form-item>  
56 - </el-col>  
57 - </el-form>  
58 - </el-row>  
59 - <div slot="footer">  
60 - <el-button  
61 - type="primary"  
62 - @click="handelConfirm"  
63 - >  
64 - 确定  
65 - </el-button>  
66 - <el-button @click="close">  
67 - 取消  
68 - </el-button>  
69 - </div>  
70 - </el-dialog>  
71 - </div>  
72 -</template>  
73 -<script>  
74 -import { isNumberStr } from '@/utils/index'  
75 -  
76 -export default {  
77 - components: {},  
78 - inheritAttrs: false,  
79 - props: [],  
80 - data() {  
81 - return {  
82 - id: 100,  
83 - formData: {  
84 - label: undefined,  
85 - value: undefined  
86 - },  
87 - rules: {  
88 - label: [  
89 - {  
90 - required: true,  
91 - message: '请输入选项名',  
92 - trigger: 'blur'  
93 - }  
94 - ],  
95 - value: [  
96 - {  
97 - required: true,  
98 - message: '请输入选项值',  
99 - trigger: 'blur'  
100 - }  
101 - ]  
102 - },  
103 - dataType: 'string',  
104 - dataTypeOptions: [  
105 - {  
106 - label: '字符串',  
107 - value: 'string'  
108 - },  
109 - {  
110 - label: '数字',  
111 - value: 'number'  
112 - }  
113 - ]  
114 - }  
115 - },  
116 - computed: {},  
117 - watch: {  
118 - // eslint-disable-next-line func-names  
119 - 'formData.value': function (val) {  
120 - this.dataType = isNumberStr(val) ? 'number' : 'string'  
121 - }  
122 - },  
123 - created() {},  
124 - mounted() {},  
125 - methods: {  
126 - onOpen() {  
127 - this.formData = {  
128 - label: undefined,  
129 - value: undefined  
130 - }  
131 - },  
132 - onClose() {},  
133 - close() {  
134 - this.$emit('update:visible', false)  
135 - },  
136 - handelConfirm() {  
137 - this.$refs.elForm.validate(valid => {  
138 - if (!valid) return  
139 - if (this.dataType === 'number') {  
140 - this.formData.value = parseFloat(this.formData.value)  
141 - }  
142 - this.formData.id = this.id++  
143 - this.$emit('commit', this.formData)  
144 - this.close()  
145 - })  
146 - }  
147 - }  
148 -}  
149 -</script> 1 +<template>
  2 + <div>
  3 + <el-dialog
  4 + v-bind="$attrs"
  5 + :close-on-click-modal="false"
  6 + :modal-append-to-body="false"
  7 + v-on="$listeners"
  8 + @open="onOpen"
  9 + @close="onClose"
  10 + >
  11 + <el-row :gutter="0">
  12 + <el-form
  13 + ref="elForm"
  14 + :model="formData"
  15 + :rules="rules"
  16 + size="small"
  17 + label-width="100px"
  18 + >
  19 + <el-col :span="24">
  20 + <el-form-item
  21 + label="选项名"
  22 + prop="label"
  23 + >
  24 + <el-input
  25 + v-model="formData.label"
  26 + placeholder="请输入选项名"
  27 + clearable
  28 + />
  29 + </el-form-item>
  30 + </el-col>
  31 + <el-col :span="24">
  32 + <el-form-item
  33 + label="选项值"
  34 + prop="value"
  35 + >
  36 + <el-input
  37 + v-model="formData.value"
  38 + placeholder="请输入选项值"
  39 + clearable
  40 + >
  41 + <el-select
  42 + slot="append"
  43 + v-model="dataType"
  44 + :style="{width: '100px'}"
  45 + >
  46 + <el-option
  47 + v-for="(item, index) in dataTypeOptions"
  48 + :key="index"
  49 + :label="item.label"
  50 + :value="item.value"
  51 + :disabled="item.disabled"
  52 + />
  53 + </el-select>
  54 + </el-input>
  55 + </el-form-item>
  56 + </el-col>
  57 + </el-form>
  58 + </el-row>
  59 + <div slot="footer">
  60 + <el-button
  61 + type="primary"
  62 + @click="handleConfirm"
  63 + >
  64 + 确定
  65 + </el-button>
  66 + <el-button @click="close">
  67 + 取消
  68 + </el-button>
  69 + </div>
  70 + </el-dialog>
  71 + </div>
  72 +</template>
  73 +<script>
  74 +import { isNumberStr } from '@/utils/index'
  75 +
  76 +export default {
  77 + components: {},
  78 + inheritAttrs: false,
  79 + props: [],
  80 + data() {
  81 + return {
  82 + id: 100,
  83 + formData: {
  84 + label: undefined,
  85 + value: undefined
  86 + },
  87 + rules: {
  88 + label: [
  89 + {
  90 + required: true,
  91 + message: '请输入选项名',
  92 + trigger: 'blur'
  93 + }
  94 + ],
  95 + value: [
  96 + {
  97 + required: true,
  98 + message: '请输入选项值',
  99 + trigger: 'blur'
  100 + }
  101 + ]
  102 + },
  103 + dataType: 'string',
  104 + dataTypeOptions: [
  105 + {
  106 + label: '字符串',
  107 + value: 'string'
  108 + },
  109 + {
  110 + label: '数字',
  111 + value: 'number'
  112 + }
  113 + ]
  114 + }
  115 + },
  116 + computed: {},
  117 + watch: {
  118 + // eslint-disable-next-line func-names
  119 + 'formData.value': function (val) {
  120 + this.dataType = isNumberStr(val) ? 'number' : 'string'
  121 + }
  122 + },
  123 + created() {},
  124 + mounted() {},
  125 + methods: {
  126 + onOpen() {
  127 + this.formData = {
  128 + label: undefined,
  129 + value: undefined
  130 + }
  131 + },
  132 + onClose() {},
  133 + close() {
  134 + this.$emit('update:visible', false)
  135 + },
  136 + handleConfirm() {
  137 + this.$refs.elForm.validate(valid => {
  138 + if (!valid) return
  139 + if (this.dataType === 'number') {
  140 + this.formData.value = parseFloat(this.formData.value)
  141 + }
  142 + this.formData.id = this.id++
  143 + this.$emit('commit', this.formData)
  144 + this.close()
  145 + })
  146 + }
  147 + }
  148 +}
  149 +</script>
1 -<template>  
2 - <div class="container">  
3 - <div class="left-board">  
4 - <div class="logo-wrapper">  
5 - <div class="logo">  
6 - <img :src="logo" alt="logo"> Form Generator  
7 - </div>  
8 - </div>  
9 - <el-scrollbar class="left-scrollbar">  
10 - <div class="components-list">  
11 - <div class="components-title">  
12 - <svg-icon icon-class="component" />输入型组件  
13 - </div>  
14 - <draggable  
15 - class="components-draggable"  
16 - :list="inputComponents"  
17 - :group="{ name: 'componentsGroup', pull: 'clone', put: false }"  
18 - :clone="cloneComponent"  
19 - draggable=".components-item"  
20 - :sort="false"  
21 - @end="onEnd"  
22 - >  
23 - <div  
24 - v-for="(element, index) in inputComponents" :key="index" class="components-item"  
25 - @click="addComponent(element)"  
26 - >  
27 - <div class="components-body">  
28 - <svg-icon :icon-class="element.tagIcon" />  
29 - {{ element.label }}  
30 - </div>  
31 - </div>  
32 - </draggable>  
33 - <div class="components-title">  
34 - <svg-icon icon-class="component" />选择型组件  
35 - </div>  
36 - <draggable  
37 - class="components-draggable"  
38 - :list="selectComponents"  
39 - :group="{ name: 'componentsGroup', pull: 'clone', put: false }"  
40 - :clone="cloneComponent"  
41 - draggable=".components-item"  
42 - :sort="false"  
43 - @end="onEnd"  
44 - >  
45 - <div  
46 - v-for="(element, index) in selectComponents"  
47 - :key="index"  
48 - class="components-item"  
49 - @click="addComponent(element)"  
50 - >  
51 - <div class="components-body">  
52 - <svg-icon :icon-class="element.tagIcon" />  
53 - {{ element.label }}  
54 - </div>  
55 - </div>  
56 - </draggable>  
57 - <div class="components-title">  
58 - <svg-icon icon-class="component" /> 布局型组件  
59 - </div>  
60 - <draggable  
61 - class="components-draggable" :list="layoutComponents"  
62 - :group="{ name: 'componentsGroup', pull: 'clone', put: false }" :clone="cloneComponent"  
63 - draggable=".components-item" :sort="false" @end="onEnd"  
64 - >  
65 - <div  
66 - v-for="(element, index) in layoutComponents" :key="index" class="components-item"  
67 - @click="addComponent(element)"  
68 - >  
69 - <div class="components-body">  
70 - <svg-icon :icon-class="element.tagIcon" />  
71 - {{ element.label }}  
72 - </div>  
73 - </div>  
74 - </draggable>  
75 - </div>  
76 - </el-scrollbar>  
77 - </div>  
78 -  
79 - <div class="center-board">  
80 - <div class="action-bar">  
81 - <el-button icon="el-icon-download" type="text" @click="download">  
82 - 导出vue文件  
83 - </el-button>  
84 - <el-button class="copy-btn-main" icon="el-icon-document-copy" type="text" @click="copy">  
85 - 复制代码  
86 - </el-button>  
87 - <el-button class="delete-btn" icon="el-icon-delete" type="text" @click="empty">  
88 - 清空  
89 - </el-button>  
90 - </div>  
91 - <el-scrollbar class="center-scrollbar">  
92 - <el-row class="center-board-row" :gutter="formConf.gutter">  
93 - <el-form  
94 - :size="formConf.size"  
95 - :label-position="formConf.labelPosition"  
96 - :disabled="formConf.disabled"  
97 - :label-width="formConf.labelWidth + 'px'"  
98 - >  
99 - <draggable class="drawing-board" :list="drawingList" :animation="340" group="componentsGroup">  
100 - <draggable-item  
101 - v-for="(element, index) in drawingList"  
102 - :key="element.renderKey"  
103 - :drawing-list="drawingList"  
104 - :element="element"  
105 - :index="index"  
106 - :active-id="activeId"  
107 - :form-conf="formConf"  
108 - @activeItem="activeFormItem"  
109 - @copyItem="drawingItemCopy"  
110 - @deleteItem="drawingItemDelete"  
111 - />  
112 - </draggable>  
113 - <div v-show="!drawingList.length" class="empty-info">  
114 - 从左侧拖入或点选组件进行表单设计  
115 - </div>  
116 - </el-form>  
117 - </el-row>  
118 - </el-scrollbar>  
119 - </div>  
120 -  
121 - <right-panel  
122 - :active-data="activeData"  
123 - :form-conf="formConf"  
124 - :show-field="!!drawingList.length"  
125 - @tag-change="tagChange"  
126 - />  
127 -  
128 - <code-type-dialog  
129 - :visible.sync="dialogVisible"  
130 - title="选择生成类型"  
131 - :show-file-name="showFileName"  
132 - @confirm="generate"  
133 - />  
134 - <input id="copyNode" type="hidden">  
135 - </div>  
136 -</template>  
137 -  
138 -<script>  
139 -import draggable from 'vuedraggable'  
140 -import beautifier from 'js-beautify'  
141 -import ClipboardJS from 'clipboard'  
142 -import render from '@/utils/generator/render'  
143 -import RightPanel from './RightPanel'  
144 -import { inputComponents, selectComponents, layoutComponents, formConf } from '@/utils/generator/config'  
145 -import { beautifierConf, titleCase } from '@/utils/index'  
146 -import { makeUpHtml, vueTemplate, vueScript, cssStyle } from '@/utils/generator/html'  
147 -import { makeUpJs } from '@/utils/generator/js'  
148 -import { makeUpCss } from '@/utils/generator/css'  
149 -import drawingDefalut from '@/utils/generator/drawingDefalut'  
150 -import logo from '@/assets/logo/logo.png'  
151 -import CodeTypeDialog from './CodeTypeDialog'  
152 -import DraggableItem from './DraggableItem'  
153 -  
154 -let oldActiveId  
155 -let tempActiveData  
156 -  
157 -export default {  
158 - components: {  
159 - draggable,  
160 - render,  
161 - RightPanel,  
162 - CodeTypeDialog,  
163 - DraggableItem  
164 - },  
165 - data() {  
166 - return {  
167 - logo,  
168 - idGlobal: 100,  
169 - formConf,  
170 - inputComponents,  
171 - selectComponents,  
172 - layoutComponents,  
173 - labelWidth: 100,  
174 - drawingList: drawingDefalut,  
175 - drawingData: {},  
176 - activeId: drawingDefalut[0].formId,  
177 - drawerVisible: false,  
178 - formData: {},  
179 - dialogVisible: false,  
180 - generateConf: null,  
181 - showFileName: false,  
182 - activeData: drawingDefalut[0]  
183 - }  
184 - },  
185 - created() {  
186 - // 防止 firefox 下 拖拽 会新打卡一个选项卡  
187 - document.body.ondrop = event => {  
188 - event.preventDefault()  
189 - event.stopPropagation()  
190 - }  
191 - },  
192 - watch: {  
193 - // eslint-disable-next-line func-names  
194 - 'activeData.label': function (val, oldVal) {  
195 - if (  
196 - this.activeData.placeholder === undefined  
197 - || !this.activeData.tag  
198 - || oldActiveId !== this.activeId  
199 - ) {  
200 - return  
201 - }  
202 - this.activeData.placeholder = this.activeData.placeholder.replace(oldVal, '') + val  
203 - },  
204 - activeId: {  
205 - handler(val) {  
206 - oldActiveId = val  
207 - },  
208 - immediate: true  
209 - }  
210 - },  
211 - mounted() {  
212 - const clipboard = new ClipboardJS('#copyNode', {  
213 - text: trigger => {  
214 - const codeStr = this.generateCode()  
215 - this.$notify({  
216 - title: '成功',  
217 - message: '代码已复制到剪切板,可粘贴。',  
218 - type: 'success'  
219 - })  
220 - return codeStr  
221 - }  
222 - })  
223 - clipboard.on('error', e => {  
224 - this.$message.error('代码复制失败')  
225 - })  
226 - },  
227 - methods: {  
228 - activeFormItem(element) {  
229 - this.activeData = element  
230 - this.activeId = element.formId  
231 - },  
232 - onEnd(obj, a) {  
233 - if (obj.from !== obj.to) {  
234 - this.activeData = tempActiveData  
235 - this.activeId = this.idGlobal  
236 - }  
237 - },  
238 - addComponent(item) {  
239 - const clone = this.cloneComponent(item)  
240 - this.drawingList.push(clone)  
241 - this.activeFormItem(clone)  
242 - },  
243 - cloneComponent(origin) {  
244 - const clone = JSON.parse(JSON.stringify(origin))  
245 - clone.formId = ++this.idGlobal  
246 - clone.span = formConf.span  
247 - clone.renderKey = +new Date() // 改变renderKey后可以实现强制更新组件  
248 - if (!clone.layout) clone.layout = 'colFormItem'  
249 - if (clone.layout === 'colFormItem') {  
250 - clone.vModel = `field${this.idGlobal}`  
251 - clone.placeholder !== undefined && (clone.placeholder += clone.label)  
252 - tempActiveData = clone  
253 - } else if (clone.layout === 'rowFormItem') {  
254 - delete clone.label  
255 - clone.componentName = `row${this.idGlobal}`  
256 - clone.gutter = this.formConf.gutter  
257 - tempActiveData = clone  
258 - }  
259 - return tempActiveData  
260 - },  
261 - AssembleFormData() {  
262 - this.formData = {  
263 - fields: JSON.parse(JSON.stringify(this.drawingList)),  
264 - ...this.formConf  
265 - }  
266 - },  
267 - generate(data) {  
268 - const func = this[`exec${titleCase(this.operationType)}`]  
269 - this.generateConf = data  
270 - func && func(data)  
271 - },  
272 - execRun(data) {  
273 - this.AssembleFormData()  
274 - this.drawerVisible = true  
275 - },  
276 - execDownload(data) {  
277 - const codeStr = this.generateCode()  
278 - const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' })  
279 - this.$download.saveAs(blob, data.fileName)  
280 - },  
281 - execCopy(data) {  
282 - document.getElementById('copyNode').click()  
283 - },  
284 - empty() {  
285 - this.$confirm('确定要清空所有组件吗?', '提示', { type: 'warning' }).then(  
286 - () => {  
287 - this.drawingList = []  
288 - }  
289 - )  
290 - },  
291 - drawingItemCopy(item, parent) {  
292 - let clone = JSON.parse(JSON.stringify(item))  
293 - clone = this.createIdAndKey(clone)  
294 - parent.push(clone)  
295 - this.activeFormItem(clone)  
296 - },  
297 - createIdAndKey(item) {  
298 - item.formId = ++this.idGlobal  
299 - item.renderKey = +new Date()  
300 - if (item.layout === 'colFormItem') {  
301 - item.vModel = `field${this.idGlobal}`  
302 - } else if (item.layout === 'rowFormItem') {  
303 - item.componentName = `row${this.idGlobal}`  
304 - }  
305 - if (Array.isArray(item.children)) {  
306 - item.children = item.children.map(childItem => this.createIdAndKey(childItem))  
307 - }  
308 - return item  
309 - },  
310 - drawingItemDelete(index, parent) {  
311 - parent.splice(index, 1)  
312 - this.$nextTick(() => {  
313 - const len = this.drawingList.length  
314 - if (len) {  
315 - this.activeFormItem(this.drawingList[len - 1])  
316 - }  
317 - })  
318 - },  
319 - generateCode() {  
320 - const { type } = this.generateConf  
321 - this.AssembleFormData()  
322 - const script = vueScript(makeUpJs(this.formData, type))  
323 - const html = vueTemplate(makeUpHtml(this.formData, type))  
324 - const css = cssStyle(makeUpCss(this.formData))  
325 - return beautifier.html(html + script + css, beautifierConf.html)  
326 - },  
327 - download() {  
328 - this.dialogVisible = true  
329 - this.showFileName = true  
330 - this.operationType = 'download'  
331 - },  
332 - run() {  
333 - this.dialogVisible = true  
334 - this.showFileName = false  
335 - this.operationType = 'run'  
336 - },  
337 - copy() {  
338 - this.dialogVisible = true  
339 - this.showFileName = false  
340 - this.operationType = 'copy'  
341 - },  
342 - tagChange(newTag) {  
343 - newTag = this.cloneComponent(newTag)  
344 - newTag.vModel = this.activeData.vModel  
345 - newTag.formId = this.activeId  
346 - newTag.span = this.activeData.span  
347 - delete this.activeData.tag  
348 - delete this.activeData.tagIcon  
349 - delete this.activeData.document  
350 - Object.keys(newTag).forEach(key => {  
351 - if (this.activeData[key] !== undefined  
352 - && typeof this.activeData[key] === typeof newTag[key]) {  
353 - newTag[key] = this.activeData[key]  
354 - }  
355 - })  
356 - this.activeData = newTag  
357 - this.updateDrawingList(newTag, this.drawingList)  
358 - },  
359 - updateDrawingList(newTag, list) {  
360 - const index = list.findIndex(item => item.formId === this.activeId)  
361 - if (index > -1) {  
362 - list.splice(index, 1, newTag)  
363 - } else {  
364 - list.forEach(item => {  
365 - if (Array.isArray(item.children)) this.updateDrawingList(newTag, item.children)  
366 - })  
367 - }  
368 - }  
369 - }  
370 -}  
371 -</script>  
372 -  
373 -<style lang='scss'>  
374 -body, html{  
375 - margin: 0;  
376 - padding: 0;  
377 - background: #fff;  
378 - --moz-osx-font-smoothing: grayscale;  
379 - --webkit-font-smoothing: antialiased;  
380 - text-rendering: optimizeLegibility;  
381 - font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;  
382 -}  
383 -  
384 -input, textarea{  
385 - font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;  
386 -}  
387 -  
388 -.editor-tabs{  
389 - background: #121315;  
390 - .el-tabs__header{  
391 - margin: 0;  
392 - border-bottom-color: #121315;  
393 - .el-tabs__nav{  
394 - border-color: #121315;  
395 - }  
396 - }  
397 - .el-tabs__item{  
398 - height: 32px;  
399 - line-height: 32px;  
400 - color: #888a8e;  
401 - border-left: 1px solid #121315 !important;  
402 - background: #363636;  
403 - margin-right: 5px;  
404 - user-select: none;  
405 - }  
406 - .el-tabs__item.is-active{  
407 - background: #1e1e1e;  
408 - border-bottom-color: #1e1e1e!important;  
409 - color: #fff;  
410 - }  
411 - .el-icon-edit{  
412 - color: #f1fa8c;  
413 - }  
414 - .el-icon-document{  
415 - color: #a95812;  
416 - }  
417 -}  
418 -  
419 -// home  
420 -.right-scrollbar {  
421 - .el-scrollbar__view {  
422 - padding: 12px 18px 15px 15px;  
423 - }  
424 -}  
425 -.left-scrollbar .el-scrollbar__wrap {  
426 - box-sizing: border-box;  
427 - overflow-x: hidden !important;  
428 - margin-bottom: 0 !important;  
429 -}  
430 -.center-tabs{  
431 - .el-tabs__header{  
432 - margin-bottom: 0!important;  
433 - }  
434 - .el-tabs__item{  
435 - width: 50%;  
436 - text-align: center;  
437 - }  
438 - .el-tabs__nav{  
439 - width: 100%;  
440 - }  
441 -}  
442 -.reg-item{  
443 - padding: 12px 6px;  
444 - background: #f8f8f8;  
445 - position: relative;  
446 - border-radius: 4px;  
447 - .close-btn{  
448 - position: absolute;  
449 - right: -6px;  
450 - top: -6px;  
451 - display: block;  
452 - width: 16px;  
453 - height: 16px;  
454 - line-height: 16px;  
455 - background: rgba(0, 0, 0, 0.2);  
456 - border-radius: 50%;  
457 - color: #fff;  
458 - text-align: center;  
459 - z-index: 1;  
460 - cursor: pointer;  
461 - font-size: 12px;  
462 - &:hover{  
463 - background: rgba(210, 23, 23, 0.5)  
464 - }  
465 - }  
466 - & + .reg-item{  
467 - margin-top: 18px;  
468 - }  
469 -}  
470 -.action-bar{  
471 - & .el-button+.el-button {  
472 - margin-left: 15px;  
473 - }  
474 - & i {  
475 - font-size: 20px;  
476 - vertical-align: middle;  
477 - position: relative;  
478 - top: -1px;  
479 - }  
480 -}  
481 -  
482 -.custom-tree-node{  
483 - width: 100%;  
484 - font-size: 14px;  
485 - .node-operation{  
486 - float: right;  
487 - }  
488 - i[class*="el-icon"] + i[class*="el-icon"]{  
489 - margin-left: 6px;  
490 - }  
491 - .el-icon-plus{  
492 - color: #409EFF;  
493 - }  
494 - .el-icon-delete{  
495 - color: #157a0c;  
496 - }  
497 -}  
498 -  
499 -.left-scrollbar .el-scrollbar__view{  
500 - overflow-x: hidden;  
501 -}  
502 -  
503 -.el-rate{  
504 - display: inline-block;  
505 - vertical-align: text-top;  
506 -}  
507 -.el-upload__tip{  
508 - line-height: 1.2;  
509 -}  
510 -  
511 -$selectedColor: #f6f7ff;  
512 -$lighterBlue: #409EFF;  
513 -  
514 -.container {  
515 - position: relative;  
516 - width: 100%;  
517 - height: 100%;  
518 -}  
519 -  
520 -.components-list {  
521 - padding: 8px;  
522 - box-sizing: border-box;  
523 - height: 100%;  
524 - .components-item {  
525 - display: inline-block;  
526 - width: 48%;  
527 - margin: 1%;  
528 - transition: transform 0ms !important;  
529 - }  
530 -}  
531 -.components-draggable{  
532 - padding-bottom: 20px;  
533 -}  
534 -.components-title{  
535 - font-size: 14px;  
536 - color: #222;  
537 - margin: 6px 2px;  
538 - .svg-icon{  
539 - color: #666;  
540 - font-size: 18px;  
541 - }  
542 -}  
543 -  
544 -.components-body {  
545 - padding: 8px 10px;  
546 - background: $selectedColor;  
547 - font-size: 12px;  
548 - cursor: move;  
549 - border: 1px dashed $selectedColor;  
550 - border-radius: 3px;  
551 - .svg-icon{  
552 - color: #777;  
553 - font-size: 15px;  
554 - }  
555 - &:hover {  
556 - border: 1px dashed #787be8;  
557 - color: #787be8;  
558 - .svg-icon {  
559 - color: #787be8;  
560 - }  
561 - }  
562 -}  
563 -  
564 -.left-board {  
565 - width: 260px;  
566 - position: absolute;  
567 - left: 0;  
568 - top: 0;  
569 - height: 100vh;  
570 -}  
571 -.left-scrollbar{  
572 - height: calc(100vh - 42px);  
573 - overflow: hidden;  
574 -}  
575 -.center-scrollbar {  
576 - height: calc(100vh - 42px);  
577 - overflow: hidden;  
578 - border-left: 1px solid #f1e8e8;  
579 - border-right: 1px solid #f1e8e8;  
580 - box-sizing: border-box;  
581 -}  
582 -.center-board {  
583 - height: 100vh;  
584 - width: auto;  
585 - margin: 0 350px 0 260px;  
586 - box-sizing: border-box;  
587 -}  
588 -.empty-info{  
589 - position: absolute;  
590 - top: 46%;  
591 - left: 0;  
592 - right: 0;  
593 - text-align: center;  
594 - font-size: 18px;  
595 - color: #ccb1ea;  
596 - letter-spacing: 4px;  
597 -}  
598 -.action-bar{  
599 - position: relative;  
600 - height: 42px;  
601 - text-align: right;  
602 - padding: 0 15px;  
603 - box-sizing: border-box;;  
604 - border: 1px solid #f1e8e8;  
605 - border-top: none;  
606 - border-left: none;  
607 - .delete-btn{  
608 - color: #F56C6C;  
609 - }  
610 -}  
611 -.logo-wrapper{  
612 - position: relative;  
613 - height: 42px;  
614 - background: #fff;  
615 - border-bottom: 1px solid #f1e8e8;  
616 - box-sizing: border-box;  
617 -}  
618 -.logo{  
619 - position: absolute;  
620 - left: 12px;  
621 - top: 6px;  
622 - line-height: 30px;  
623 - color: #00afff;  
624 - font-weight: 600;  
625 - font-size: 17px;  
626 - white-space: nowrap;  
627 - > img{  
628 - width: 30px;  
629 - height: 30px;  
630 - vertical-align: top;  
631 - }  
632 - .github{  
633 - display: inline-block;  
634 - vertical-align: sub;  
635 - margin-left: 15px;  
636 - > img{  
637 - height: 22px;  
638 - }  
639 - }  
640 -}  
641 -  
642 -.center-board-row {  
643 - padding: 12px 12px 15px 12px;  
644 - box-sizing: border-box;  
645 - & > .el-form {  
646 - // 69 = 12+15+42  
647 - height: calc(100vh - 69px);  
648 - }  
649 -}  
650 -.drawing-board {  
651 - height: 100%;  
652 - position: relative;  
653 - .components-body {  
654 - padding: 0;  
655 - margin: 0;  
656 - font-size: 0;  
657 - }  
658 - .sortable-ghost {  
659 - position: relative;  
660 - display: block;  
661 - overflow: hidden;  
662 - &::before {  
663 - content: " ";  
664 - position: absolute;  
665 - left: 0;  
666 - right: 0;  
667 - top: 0;  
668 - height: 3px;  
669 - background: rgb(89, 89, 223);  
670 - z-index: 2;  
671 - }  
672 - }  
673 - .components-item.sortable-ghost {  
674 - width: 100%;  
675 - height: 60px;  
676 - background-color: $selectedColor;  
677 - }  
678 - .active-from-item {  
679 - & > .el-form-item{  
680 - background: $selectedColor;  
681 - border-radius: 6px;  
682 - }  
683 - & > .drawing-item-copy, & > .drawing-item-delete{  
684 - display: initial;  
685 - }  
686 - & > .component-name{  
687 - color: $lighterBlue;  
688 - }  
689 - }  
690 - .el-form-item{  
691 - margin-bottom: 15px;  
692 - }  
693 -}  
694 -.drawing-item{  
695 - position: relative;  
696 - cursor: move;  
697 - &.unfocus-bordered:not(.activeFromItem) > div:first-child {  
698 - border: 1px dashed #ccc;  
699 - }  
700 - .el-form-item{  
701 - padding: 12px 10px;  
702 - }  
703 -}  
704 -.drawing-row-item{  
705 - position: relative;  
706 - cursor: move;  
707 - box-sizing: border-box;  
708 - border: 1px dashed #ccc;  
709 - border-radius: 3px;  
710 - padding: 0 2px;  
711 - margin-bottom: 15px;  
712 - .drawing-row-item {  
713 - margin-bottom: 2px;  
714 - }  
715 - .el-col{  
716 - margin-top: 22px;  
717 - }  
718 - .el-form-item{  
719 - margin-bottom: 0;  
720 - }  
721 - .drag-wrapper{  
722 - min-height: 80px;  
723 - }  
724 - &.active-from-item{  
725 - border: 1px dashed $lighterBlue;  
726 - }  
727 - .component-name{  
728 - position: absolute;  
729 - top: 0;  
730 - left: 0;  
731 - font-size: 12px;  
732 - color: #bbb;  
733 - display: inline-block;  
734 - padding: 0 6px;  
735 - }  
736 -}  
737 -.drawing-item, .drawing-row-item{  
738 - &:hover {  
739 - & > .el-form-item{  
740 - background: $selectedColor;  
741 - border-radius: 6px;  
742 - }  
743 - & > .drawing-item-copy, & > .drawing-item-delete{  
744 - display: initial;  
745 - }  
746 - }  
747 - & > .drawing-item-copy, & > .drawing-item-delete{  
748 - display: none;  
749 - position: absolute;  
750 - top: -10px;  
751 - width: 22px;  
752 - height: 22px;  
753 - line-height: 22px;  
754 - text-align: center;  
755 - border-radius: 50%;  
756 - font-size: 12px;  
757 - border: 1px solid;  
758 - cursor: pointer;  
759 - z-index: 1;  
760 - }  
761 - & > .drawing-item-copy{  
762 - right: 56px;  
763 - border-color: $lighterBlue;  
764 - color: $lighterBlue;  
765 - background: #fff;  
766 - &:hover{  
767 - background: $lighterBlue;  
768 - color: #fff;  
769 - }  
770 - }  
771 - & > .drawing-item-delete{  
772 - right: 24px;  
773 - border-color: #F56C6C;  
774 - color: #F56C6C;  
775 - background: #fff;  
776 - &:hover{  
777 - background: #F56C6C;  
778 - color: #fff;  
779 - }  
780 - }  
781 -}  
782 -  
783 -</style> 1 +<template>
  2 + <div class="container">
  3 + <div class="left-board">
  4 + <div class="logo-wrapper">
  5 + <div class="logo">
  6 + <img :src="logo" alt="logo"> Form Generator
  7 + </div>
  8 + </div>
  9 + <el-scrollbar class="left-scrollbar">
  10 + <div class="components-list">
  11 + <div class="components-title">
  12 + <svg-icon icon-class="component" />输入型组件
  13 + </div>
  14 + <draggable
  15 + class="components-draggable"
  16 + :list="inputComponents"
  17 + :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
  18 + :clone="cloneComponent"
  19 + draggable=".components-item"
  20 + :sort="false"
  21 + @end="onEnd"
  22 + >
  23 + <div
  24 + v-for="(element, index) in inputComponents" :key="index" class="components-item"
  25 + @click="addComponent(element)"
  26 + >
  27 + <div class="components-body">
  28 + <svg-icon :icon-class="element.tagIcon" />
  29 + {{ element.label }}
  30 + </div>
  31 + </div>
  32 + </draggable>
  33 + <div class="components-title">
  34 + <svg-icon icon-class="component" />选择型组件
  35 + </div>
  36 + <draggable
  37 + class="components-draggable"
  38 + :list="selectComponents"
  39 + :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
  40 + :clone="cloneComponent"
  41 + draggable=".components-item"
  42 + :sort="false"
  43 + @end="onEnd"
  44 + >
  45 + <div
  46 + v-for="(element, index) in selectComponents"
  47 + :key="index"
  48 + class="components-item"
  49 + @click="addComponent(element)"
  50 + >
  51 + <div class="components-body">
  52 + <svg-icon :icon-class="element.tagIcon" />
  53 + {{ element.label }}
  54 + </div>
  55 + </div>
  56 + </draggable>
  57 + <div class="components-title">
  58 + <svg-icon icon-class="component" /> 布局型组件
  59 + </div>
  60 + <draggable
  61 + class="components-draggable" :list="layoutComponents"
  62 + :group="{ name: 'componentsGroup', pull: 'clone', put: false }" :clone="cloneComponent"
  63 + draggable=".components-item" :sort="false" @end="onEnd"
  64 + >
  65 + <div
  66 + v-for="(element, index) in layoutComponents" :key="index" class="components-item"
  67 + @click="addComponent(element)"
  68 + >
  69 + <div class="components-body">
  70 + <svg-icon :icon-class="element.tagIcon" />
  71 + {{ element.label }}
  72 + </div>
  73 + </div>
  74 + </draggable>
  75 + </div>
  76 + </el-scrollbar>
  77 + </div>
  78 +
  79 + <div class="center-board">
  80 + <div class="action-bar">
  81 + <el-button icon="el-icon-download" type="text" @click="download">
  82 + 导出vue文件
  83 + </el-button>
  84 + <el-button class="copy-btn-main" icon="el-icon-document-copy" type="text" @click="copy">
  85 + 复制代码
  86 + </el-button>
  87 + <el-button class="delete-btn" icon="el-icon-delete" type="text" @click="empty">
  88 + 清空
  89 + </el-button>
  90 + </div>
  91 + <el-scrollbar class="center-scrollbar">
  92 + <el-row class="center-board-row" :gutter="formConf.gutter">
  93 + <el-form
  94 + :size="formConf.size"
  95 + :label-position="formConf.labelPosition"
  96 + :disabled="formConf.disabled"
  97 + :label-width="formConf.labelWidth + 'px'"
  98 + >
  99 + <draggable class="drawing-board" :list="drawingList" :animation="340" group="componentsGroup">
  100 + <draggable-item
  101 + v-for="(element, index) in drawingList"
  102 + :key="element.renderKey"
  103 + :drawing-list="drawingList"
  104 + :element="element"
  105 + :index="index"
  106 + :active-id="activeId"
  107 + :form-conf="formConf"
  108 + @activeItem="activeFormItem"
  109 + @copyItem="drawingItemCopy"
  110 + @deleteItem="drawingItemDelete"
  111 + />
  112 + </draggable>
  113 + <div v-show="!drawingList.length" class="empty-info">
  114 + 从左侧拖入或点选组件进行表单设计
  115 + </div>
  116 + </el-form>
  117 + </el-row>
  118 + </el-scrollbar>
  119 + </div>
  120 +
  121 + <right-panel
  122 + :active-data="activeData"
  123 + :form-conf="formConf"
  124 + :show-field="!!drawingList.length"
  125 + @tag-change="tagChange"
  126 + />
  127 +
  128 + <code-type-dialog
  129 + :visible.sync="dialogVisible"
  130 + title="选择生成类型"
  131 + :show-file-name="showFileName"
  132 + @confirm="generate"
  133 + />
  134 + <input id="copyNode" type="hidden">
  135 + </div>
  136 +</template>
  137 +
  138 +<script>
  139 +import draggable from 'vuedraggable'
  140 +import beautifier from 'js-beautify'
  141 +import ClipboardJS from 'clipboard'
  142 +import render from '@/utils/generator/render'
  143 +import RightPanel from './RightPanel'
  144 +import { inputComponents, selectComponents, layoutComponents, formConf } from '@/utils/generator/config'
  145 +import { beautifierConf, titleCase } from '@/utils/index'
  146 +import { makeUpHtml, vueTemplate, vueScript, cssStyle } from '@/utils/generator/html'
  147 +import { makeUpJs } from '@/utils/generator/js'
  148 +import { makeUpCss } from '@/utils/generator/css'
  149 +import drawingDefault from '@/utils/generator/drawingDefault'
  150 +import logo from '@/assets/logo/logo.png'
  151 +import CodeTypeDialog from './CodeTypeDialog'
  152 +import DraggableItem from './DraggableItem'
  153 +
  154 +let oldActiveId
  155 +let tempActiveData
  156 +
  157 +export default {
  158 + components: {
  159 + draggable,
  160 + render,
  161 + RightPanel,
  162 + CodeTypeDialog,
  163 + DraggableItem
  164 + },
  165 + data() {
  166 + return {
  167 + logo,
  168 + idGlobal: 100,
  169 + formConf,
  170 + inputComponents,
  171 + selectComponents,
  172 + layoutComponents,
  173 + labelWidth: 100,
  174 + drawingList: drawingDefault,
  175 + drawingData: {},
  176 + activeId: drawingDefault[0].formId,
  177 + drawerVisible: false,
  178 + formData: {},
  179 + dialogVisible: false,
  180 + generateConf: null,
  181 + showFileName: false,
  182 + activeData: drawingDefault[0]
  183 + }
  184 + },
  185 + created() {
  186 + // 防止 firefox 下 拖拽 会新打卡一个选项卡
  187 + document.body.ondrop = event => {
  188 + event.preventDefault()
  189 + event.stopPropagation()
  190 + }
  191 + },
  192 + watch: {
  193 + // eslint-disable-next-line func-names
  194 + 'activeData.label': function (val, oldVal) {
  195 + if (
  196 + this.activeData.placeholder === undefined
  197 + || !this.activeData.tag
  198 + || oldActiveId !== this.activeId
  199 + ) {
  200 + return
  201 + }
  202 + this.activeData.placeholder = this.activeData.placeholder.replace(oldVal, '') + val
  203 + },
  204 + activeId: {
  205 + handler(val) {
  206 + oldActiveId = val
  207 + },
  208 + immediate: true
  209 + }
  210 + },
  211 + mounted() {
  212 + const clipboard = new ClipboardJS('#copyNode', {
  213 + text: trigger => {
  214 + const codeStr = this.generateCode()
  215 + this.$notify({
  216 + title: '成功',
  217 + message: '代码已复制到剪切板,可粘贴。',
  218 + type: 'success'
  219 + })
  220 + return codeStr
  221 + }
  222 + })
  223 + clipboard.on('error', e => {
  224 + this.$message.error('代码复制失败')
  225 + })
  226 + },
  227 + methods: {
  228 + activeFormItem(element) {
  229 + this.activeData = element
  230 + this.activeId = element.formId
  231 + },
  232 + onEnd(obj, a) {
  233 + if (obj.from !== obj.to) {
  234 + this.activeData = tempActiveData
  235 + this.activeId = this.idGlobal
  236 + }
  237 + },
  238 + addComponent(item) {
  239 + const clone = this.cloneComponent(item)
  240 + this.drawingList.push(clone)
  241 + this.activeFormItem(clone)
  242 + },
  243 + cloneComponent(origin) {
  244 + const clone = JSON.parse(JSON.stringify(origin))
  245 + clone.formId = ++this.idGlobal
  246 + clone.span = formConf.span
  247 + clone.renderKey = +new Date() // 改变renderKey后可以实现强制更新组件
  248 + if (!clone.layout) clone.layout = 'colFormItem'
  249 + if (clone.layout === 'colFormItem') {
  250 + clone.vModel = `field${this.idGlobal}`
  251 + clone.placeholder !== undefined && (clone.placeholder += clone.label)
  252 + tempActiveData = clone
  253 + } else if (clone.layout === 'rowFormItem') {
  254 + delete clone.label
  255 + clone.componentName = `row${this.idGlobal}`
  256 + clone.gutter = this.formConf.gutter
  257 + tempActiveData = clone
  258 + }
  259 + return tempActiveData
  260 + },
  261 + AssembleFormData() {
  262 + this.formData = {
  263 + fields: JSON.parse(JSON.stringify(this.drawingList)),
  264 + ...this.formConf
  265 + }
  266 + },
  267 + generate(data) {
  268 + const func = this[`exec${titleCase(this.operationType)}`]
  269 + this.generateConf = data
  270 + func && func(data)
  271 + },
  272 + execRun(data) {
  273 + this.AssembleFormData()
  274 + this.drawerVisible = true
  275 + },
  276 + execDownload(data) {
  277 + const codeStr = this.generateCode()
  278 + const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' })
  279 + this.$download.saveAs(blob, data.fileName)
  280 + },
  281 + execCopy(data) {
  282 + document.getElementById('copyNode').click()
  283 + },
  284 + empty() {
  285 + this.$confirm('确定要清空所有组件吗?', '提示', { type: 'warning' }).then(
  286 + () => {
  287 + this.drawingList = []
  288 + }
  289 + )
  290 + },
  291 + drawingItemCopy(item, parent) {
  292 + let clone = JSON.parse(JSON.stringify(item))
  293 + clone = this.createIdAndKey(clone)
  294 + parent.push(clone)
  295 + this.activeFormItem(clone)
  296 + },
  297 + createIdAndKey(item) {
  298 + item.formId = ++this.idGlobal
  299 + item.renderKey = +new Date()
  300 + if (item.layout === 'colFormItem') {
  301 + item.vModel = `field${this.idGlobal}`
  302 + } else if (item.layout === 'rowFormItem') {
  303 + item.componentName = `row${this.idGlobal}`
  304 + }
  305 + if (Array.isArray(item.children)) {
  306 + item.children = item.children.map(childItem => this.createIdAndKey(childItem))
  307 + }
  308 + return item
  309 + },
  310 + drawingItemDelete(index, parent) {
  311 + parent.splice(index, 1)
  312 + this.$nextTick(() => {
  313 + const len = this.drawingList.length
  314 + if (len) {
  315 + this.activeFormItem(this.drawingList[len - 1])
  316 + }
  317 + })
  318 + },
  319 + generateCode() {
  320 + const { type } = this.generateConf
  321 + this.AssembleFormData()
  322 + const script = vueScript(makeUpJs(this.formData, type))
  323 + const html = vueTemplate(makeUpHtml(this.formData, type))
  324 + const css = cssStyle(makeUpCss(this.formData))
  325 + return beautifier.html(html + script + css, beautifierConf.html)
  326 + },
  327 + download() {
  328 + this.dialogVisible = true
  329 + this.showFileName = true
  330 + this.operationType = 'download'
  331 + },
  332 + run() {
  333 + this.dialogVisible = true
  334 + this.showFileName = false
  335 + this.operationType = 'run'
  336 + },
  337 + copy() {
  338 + this.dialogVisible = true
  339 + this.showFileName = false
  340 + this.operationType = 'copy'
  341 + },
  342 + tagChange(newTag) {
  343 + newTag = this.cloneComponent(newTag)
  344 + newTag.vModel = this.activeData.vModel
  345 + newTag.formId = this.activeId
  346 + newTag.span = this.activeData.span
  347 + delete this.activeData.tag
  348 + delete this.activeData.tagIcon
  349 + delete this.activeData.document
  350 + Object.keys(newTag).forEach(key => {
  351 + if (this.activeData[key] !== undefined
  352 + && typeof this.activeData[key] === typeof newTag[key]) {
  353 + newTag[key] = this.activeData[key]
  354 + }
  355 + })
  356 + this.activeData = newTag
  357 + this.updateDrawingList(newTag, this.drawingList)
  358 + },
  359 + updateDrawingList(newTag, list) {
  360 + const index = list.findIndex(item => item.formId === this.activeId)
  361 + if (index > -1) {
  362 + list.splice(index, 1, newTag)
  363 + } else {
  364 + list.forEach(item => {
  365 + if (Array.isArray(item.children)) this.updateDrawingList(newTag, item.children)
  366 + })
  367 + }
  368 + }
  369 + }
  370 +}
  371 +</script>
  372 +
  373 +<style lang='scss'>
  374 +body, html{
  375 + margin: 0;
  376 + padding: 0;
  377 + background: #fff;
  378 + --moz-osx-font-smoothing: grayscale;
  379 + --webkit-font-smoothing: antialiased;
  380 + text-rendering: optimizeLegibility;
  381 + font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;
  382 +}
  383 +
  384 +input, textarea{
  385 + font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;
  386 +}
  387 +
  388 +.editor-tabs{
  389 + background: #121315;
  390 + .el-tabs__header{
  391 + margin: 0;
  392 + border-bottom-color: #121315;
  393 + .el-tabs__nav{
  394 + border-color: #121315;
  395 + }
  396 + }
  397 + .el-tabs__item{
  398 + height: 32px;
  399 + line-height: 32px;
  400 + color: #888a8e;
  401 + border-left: 1px solid #121315 !important;
  402 + background: #363636;
  403 + margin-right: 5px;
  404 + user-select: none;
  405 + }
  406 + .el-tabs__item.is-active{
  407 + background: #1e1e1e;
  408 + border-bottom-color: #1e1e1e!important;
  409 + color: #fff;
  410 + }
  411 + .el-icon-edit{
  412 + color: #f1fa8c;
  413 + }
  414 + .el-icon-document{
  415 + color: #a95812;
  416 + }
  417 +}
  418 +
  419 +// home
  420 +.right-scrollbar {
  421 + .el-scrollbar__view {
  422 + padding: 12px 18px 15px 15px;
  423 + }
  424 +}
  425 +.left-scrollbar .el-scrollbar__wrap {
  426 + box-sizing: border-box;
  427 + overflow-x: hidden !important;
  428 + margin-bottom: 0 !important;
  429 +}
  430 +.center-tabs{
  431 + .el-tabs__header{
  432 + margin-bottom: 0!important;
  433 + }
  434 + .el-tabs__item{
  435 + width: 50%;
  436 + text-align: center;
  437 + }
  438 + .el-tabs__nav{
  439 + width: 100%;
  440 + }
  441 +}
  442 +.reg-item{
  443 + padding: 12px 6px;
  444 + background: #f8f8f8;
  445 + position: relative;
  446 + border-radius: 4px;
  447 + .close-btn{
  448 + position: absolute;
  449 + right: -6px;
  450 + top: -6px;
  451 + display: block;
  452 + width: 16px;
  453 + height: 16px;
  454 + line-height: 16px;
  455 + background: rgba(0, 0, 0, 0.2);
  456 + border-radius: 50%;
  457 + color: #fff;
  458 + text-align: center;
  459 + z-index: 1;
  460 + cursor: pointer;
  461 + font-size: 12px;
  462 + &:hover{
  463 + background: rgba(210, 23, 23, 0.5)
  464 + }
  465 + }
  466 + & + .reg-item{
  467 + margin-top: 18px;
  468 + }
  469 +}
  470 +.action-bar{
  471 + & .el-button+.el-button {
  472 + margin-left: 15px;
  473 + }
  474 + & i {
  475 + font-size: 20px;
  476 + vertical-align: middle;
  477 + position: relative;
  478 + top: -1px;
  479 + }
  480 +}
  481 +
  482 +.custom-tree-node{
  483 + width: 100%;
  484 + font-size: 14px;
  485 + .node-operation{
  486 + float: right;
  487 + }
  488 + i[class*="el-icon"] + i[class*="el-icon"]{
  489 + margin-left: 6px;
  490 + }
  491 + .el-icon-plus{
  492 + color: #409EFF;
  493 + }
  494 + .el-icon-delete{
  495 + color: #157a0c;
  496 + }
  497 +}
  498 +
  499 +.left-scrollbar .el-scrollbar__view{
  500 + overflow-x: hidden;
  501 +}
  502 +
  503 +.el-rate{
  504 + display: inline-block;
  505 + vertical-align: text-top;
  506 +}
  507 +.el-upload__tip{
  508 + line-height: 1.2;
  509 +}
  510 +
  511 +$selectedColor: #f6f7ff;
  512 +$lighterBlue: #409EFF;
  513 +
  514 +.container {
  515 + position: relative;
  516 + width: 100%;
  517 + height: 100%;
  518 +}
  519 +
  520 +.components-list {
  521 + padding: 8px;
  522 + box-sizing: border-box;
  523 + height: 100%;
  524 + .components-item {
  525 + display: inline-block;
  526 + width: 48%;
  527 + margin: 1%;
  528 + transition: transform 0ms !important;
  529 + }
  530 +}
  531 +.components-draggable{
  532 + padding-bottom: 20px;
  533 +}
  534 +.components-title{
  535 + font-size: 14px;
  536 + color: #222;
  537 + margin: 6px 2px;
  538 + .svg-icon{
  539 + color: #666;
  540 + font-size: 18px;
  541 + }
  542 +}
  543 +
  544 +.components-body {
  545 + padding: 8px 10px;
  546 + background: $selectedColor;
  547 + font-size: 12px;
  548 + cursor: move;
  549 + border: 1px dashed $selectedColor;
  550 + border-radius: 3px;
  551 + .svg-icon{
  552 + color: #777;
  553 + font-size: 15px;
  554 + }
  555 + &:hover {
  556 + border: 1px dashed #787be8;
  557 + color: #787be8;
  558 + .svg-icon {
  559 + color: #787be8;
  560 + }
  561 + }
  562 +}
  563 +
  564 +.left-board {
  565 + width: 260px;
  566 + position: absolute;
  567 + left: 0;
  568 + top: 0;
  569 + height: 100vh;
  570 +}
  571 +.left-scrollbar{
  572 + height: calc(100vh - 42px);
  573 + overflow: hidden;
  574 +}
  575 +.center-scrollbar {
  576 + height: calc(100vh - 42px);
  577 + overflow: hidden;
  578 + border-left: 1px solid #f1e8e8;
  579 + border-right: 1px solid #f1e8e8;
  580 + box-sizing: border-box;
  581 +}
  582 +.center-board {
  583 + height: 100vh;
  584 + width: auto;
  585 + margin: 0 350px 0 260px;
  586 + box-sizing: border-box;
  587 +}
  588 +.empty-info{
  589 + position: absolute;
  590 + top: 46%;
  591 + left: 0;
  592 + right: 0;
  593 + text-align: center;
  594 + font-size: 18px;
  595 + color: #ccb1ea;
  596 + letter-spacing: 4px;
  597 +}
  598 +.action-bar{
  599 + position: relative;
  600 + height: 42px;
  601 + text-align: right;
  602 + padding: 0 15px;
  603 + box-sizing: border-box;;
  604 + border: 1px solid #f1e8e8;
  605 + border-top: none;
  606 + border-left: none;
  607 + .delete-btn{
  608 + color: #F56C6C;
  609 + }
  610 +}
  611 +.logo-wrapper{
  612 + position: relative;
  613 + height: 42px;
  614 + background: #fff;
  615 + border-bottom: 1px solid #f1e8e8;
  616 + box-sizing: border-box;
  617 +}
  618 +.logo{
  619 + position: absolute;
  620 + left: 12px;
  621 + top: 6px;
  622 + line-height: 30px;
  623 + color: #00afff;
  624 + font-weight: 600;
  625 + font-size: 17px;
  626 + white-space: nowrap;
  627 + > img{
  628 + width: 30px;
  629 + height: 30px;
  630 + vertical-align: top;
  631 + }
  632 + .github{
  633 + display: inline-block;
  634 + vertical-align: sub;
  635 + margin-left: 15px;
  636 + > img{
  637 + height: 22px;
  638 + }
  639 + }
  640 +}
  641 +
  642 +.center-board-row {
  643 + padding: 12px 12px 15px 12px;
  644 + box-sizing: border-box;
  645 + & > .el-form {
  646 + // 69 = 12+15+42
  647 + height: calc(100vh - 69px);
  648 + }
  649 +}
  650 +.drawing-board {
  651 + height: 100%;
  652 + position: relative;
  653 + .components-body {
  654 + padding: 0;
  655 + margin: 0;
  656 + font-size: 0;
  657 + }
  658 + .sortable-ghost {
  659 + position: relative;
  660 + display: block;
  661 + overflow: hidden;
  662 + &::before {
  663 + content: " ";
  664 + position: absolute;
  665 + left: 0;
  666 + right: 0;
  667 + top: 0;
  668 + height: 3px;
  669 + background: rgb(89, 89, 223);
  670 + z-index: 2;
  671 + }
  672 + }
  673 + .components-item.sortable-ghost {
  674 + width: 100%;
  675 + height: 60px;
  676 + background-color: $selectedColor;
  677 + }
  678 + .active-from-item {
  679 + & > .el-form-item{
  680 + background: $selectedColor;
  681 + border-radius: 6px;
  682 + }
  683 + & > .drawing-item-copy, & > .drawing-item-delete{
  684 + display: initial;
  685 + }
  686 + & > .component-name{
  687 + color: $lighterBlue;
  688 + }
  689 + }
  690 + .el-form-item{
  691 + margin-bottom: 15px;
  692 + }
  693 +}
  694 +.drawing-item{
  695 + position: relative;
  696 + cursor: move;
  697 + &.unfocus-bordered:not(.activeFromItem) > div:first-child {
  698 + border: 1px dashed #ccc;
  699 + }
  700 + .el-form-item{
  701 + padding: 12px 10px;
  702 + }
  703 +}
  704 +.drawing-row-item{
  705 + position: relative;
  706 + cursor: move;
  707 + box-sizing: border-box;
  708 + border: 1px dashed #ccc;
  709 + border-radius: 3px;
  710 + padding: 0 2px;
  711 + margin-bottom: 15px;
  712 + .drawing-row-item {
  713 + margin-bottom: 2px;
  714 + }
  715 + .el-col{
  716 + margin-top: 22px;
  717 + }
  718 + .el-form-item{
  719 + margin-bottom: 0;
  720 + }
  721 + .drag-wrapper{
  722 + min-height: 80px;
  723 + }
  724 + &.active-from-item{
  725 + border: 1px dashed $lighterBlue;
  726 + }
  727 + .component-name{
  728 + position: absolute;
  729 + top: 0;
  730 + left: 0;
  731 + font-size: 12px;
  732 + color: #bbb;
  733 + display: inline-block;
  734 + padding: 0 6px;
  735 + }
  736 +}
  737 +.drawing-item, .drawing-row-item{
  738 + &:hover {
  739 + & > .el-form-item{
  740 + background: $selectedColor;
  741 + border-radius: 6px;
  742 + }
  743 + & > .drawing-item-copy, & > .drawing-item-delete{
  744 + display: initial;
  745 + }
  746 + }
  747 + & > .drawing-item-copy, & > .drawing-item-delete{
  748 + display: none;
  749 + position: absolute;
  750 + top: -10px;
  751 + width: 22px;
  752 + height: 22px;
  753 + line-height: 22px;
  754 + text-align: center;
  755 + border-radius: 50%;
  756 + font-size: 12px;
  757 + border: 1px solid;
  758 + cursor: pointer;
  759 + z-index: 1;
  760 + }
  761 + & > .drawing-item-copy{
  762 + right: 56px;
  763 + border-color: $lighterBlue;
  764 + color: $lighterBlue;
  765 + background: #fff;
  766 + &:hover{
  767 + background: $lighterBlue;
  768 + color: #fff;
  769 + }
  770 + }
  771 + & > .drawing-item-delete{
  772 + right: 24px;
  773 + border-color: #F56C6C;
  774 + color: #F56C6C;
  775 + background: #fff;
  776 + &:hover{
  777 + background: #F56C6C;
  778 + color: #fff;
  779 + }
  780 + }
  781 +}
  782 +
  783 +</style>