From ee828ec4a7281cc08e6ebf732080fe44eadb5a6a Mon Sep 17 00:00:00 2001 From: gtz <535262213@qq.com> Date: Thu, 28 Mar 2024 18:40:27 +0800 Subject: [PATCH] 're_infra' --- src/api/infra/apiAccessLog.js | 20 + src/api/infra/apiErrorLog.js | 28 + src/api/infra/codegen.js | 90 +++ src/api/infra/config.js | 62 ++ src/api/infra/dataSourceConfig.js | 43 ++ src/api/infra/dbDoc.js | 26 + src/api/infra/file.js | 18 + src/api/infra/fileConfig.js | 59 ++ src/api/infra/job.js | 82 +++ src/api/infra/jobLog.js | 28 + src/api/infra/redis.js | 9 + src/api/infra/testDemo.js | 54 ++ src/components/Crontab/day.vue | 160 ++++++ src/components/Crontab/hour.vue | 114 ++++ src/components/Crontab/index.vue | 430 ++++++++++++++ src/components/Crontab/min.vue | 116 ++++ src/components/Crontab/month.vue | 114 ++++ src/components/Crontab/result.vue | 559 ++++++++++++++++++ src/components/Crontab/second.vue | 117 ++++ src/components/Crontab/week.vue | 202 +++++++ src/components/Crontab/year.vue | 131 +++++ src/components/generator/config.js | 630 +++++++++++++++++++++ src/components/generator/css.js | 18 + src/components/generator/drawingDefalut.js | 37 ++ src/components/generator/html.js | 399 +++++++++++++ src/components/generator/js.js | 271 +++++++++ src/components/generator/ruleTrigger.js | 16 + src/components/tinymce/README.md | 3 + src/components/tinymce/config.js | 8 + src/components/tinymce/example/Index.vue | 38 ++ src/components/tinymce/index.js | 3 + src/components/tinymce/index.vue | 88 +++ src/components/tinymce/package.json | 28 + src/components/tinymce/zh_CN.js | 420 ++++++++++++++ src/utils/loadBeautifier.js | 28 + src/utils/loadMonaco.js | 40 ++ src/utils/loadScript.js | 60 ++ src/utils/loadTinymce.js | 29 + src/utils/pluginsConfig.js | 13 + 39 files changed, 4591 insertions(+) create mode 100644 src/api/infra/apiAccessLog.js create mode 100644 src/api/infra/apiErrorLog.js create mode 100644 src/api/infra/codegen.js create mode 100644 src/api/infra/config.js create mode 100644 src/api/infra/dataSourceConfig.js create mode 100644 src/api/infra/dbDoc.js create mode 100644 src/api/infra/file.js create mode 100644 src/api/infra/fileConfig.js create mode 100644 src/api/infra/job.js create mode 100644 src/api/infra/jobLog.js create mode 100644 src/api/infra/redis.js create mode 100644 src/api/infra/testDemo.js create mode 100644 src/components/Crontab/day.vue create mode 100644 src/components/Crontab/hour.vue create mode 100644 src/components/Crontab/index.vue create mode 100644 src/components/Crontab/min.vue create mode 100644 src/components/Crontab/month.vue create mode 100644 src/components/Crontab/result.vue create mode 100644 src/components/Crontab/second.vue create mode 100644 src/components/Crontab/week.vue create mode 100644 src/components/Crontab/year.vue create mode 100644 src/components/generator/config.js create mode 100644 src/components/generator/css.js create mode 100644 src/components/generator/drawingDefalut.js create mode 100644 src/components/generator/html.js create mode 100644 src/components/generator/js.js create mode 100644 src/components/generator/ruleTrigger.js create mode 100644 src/components/tinymce/README.md create mode 100644 src/components/tinymce/config.js create mode 100644 src/components/tinymce/example/Index.vue create mode 100644 src/components/tinymce/index.js create mode 100644 src/components/tinymce/index.vue create mode 100644 src/components/tinymce/package.json create mode 100644 src/components/tinymce/zh_CN.js create mode 100644 src/utils/loadBeautifier.js create mode 100644 src/utils/loadMonaco.js create mode 100644 src/utils/loadScript.js create mode 100644 src/utils/loadTinymce.js create mode 100644 src/utils/pluginsConfig.js diff --git a/src/api/infra/apiAccessLog.js b/src/api/infra/apiAccessLog.js new file mode 100644 index 00000000..6456a508 --- /dev/null +++ b/src/api/infra/apiAccessLog.js @@ -0,0 +1,20 @@ +import request from '@/utils/request' + +// 获得API 访问日志分页 +export function getApiAccessLogPage(query) { + return request({ + url: '/infra/api-access-log/page', + method: 'get', + params: query + }) +} + +// 导出API 访问日志 Excel +export function exportApiAccessLogExcel(query) { + return request({ + url: '/infra/api-access-log/export-excel', + method: 'get', + params: query, + responseType: 'blob' + }) +} diff --git a/src/api/infra/apiErrorLog.js b/src/api/infra/apiErrorLog.js new file mode 100644 index 00000000..65942d13 --- /dev/null +++ b/src/api/infra/apiErrorLog.js @@ -0,0 +1,28 @@ +import request from '@/utils/request' + +// 更新 API 错误日志的处理状态 +export function updateApiErrorLogProcess(id, processStatus) { + return request({ + url: '/infra/api-error-log/update-status?id=' + id + '&processStatus=' + processStatus, + method: 'put', + }) +} + +// 获得API 错误日志分页 +export function getApiErrorLogPage(query) { + return request({ + url: '/infra/api-error-log/page', + method: 'get', + params: query + }) +} + +// 导出API 错误日志 Excel +export function exportApiErrorLogExcel(query) { + return request({ + url: '/infra/api-error-log/export-excel', + method: 'get', + params: query, + responseType: 'blob' + }) +} diff --git a/src/api/infra/codegen.js b/src/api/infra/codegen.js new file mode 100644 index 00000000..ffb3e043 --- /dev/null +++ b/src/api/infra/codegen.js @@ -0,0 +1,90 @@ +import request from '@/utils/request' + +// 获得表定义分页 +export function getCodegenTablePage(query) { + return request({ + url: '/infra/codegen/table/page', + method: 'get', + params: query + }) +} + +// 获得表和字段的明细 +export function getCodegenDetail(tableId) { + return request({ + url: '/infra/codegen/detail?tableId=' + tableId, + method: 'get', + }) +} + +// 修改代码生成信息 +export function updateCodegen(data) { + return request({ + url: '/infra/codegen/update', + method: 'put', + data: data + }) +} + +// 基于数据库的表结构,同步数据库的表和字段定义 +export function syncCodegenFromDB(tableId) { + return request({ + url: '/infra/codegen/sync-from-db?tableId=' + tableId, + method: 'put' + }) +} + +// 基于 SQL 建表语句,同步数据库的表和字段定义 +export function syncCodegenFromSQL(tableId, sql) { + return request({ + url: '/infra/codegen/sync-from-sql?tableId=' + tableId, + method: 'put', + headers:{ + 'Content-type': 'application/x-www-form-urlencoded' + }, + data: 'tableId=' + tableId + "&sql=" + sql, + }) +} + +// 预览生成代码 +export function previewCodegen(tableId) { + return request({ + url: '/infra/codegen/preview?tableId=' + tableId, + method: 'get', + }) +} + +// 下载生成代码 +export function downloadCodegen(tableId) { + return request({ + url: '/infra/codegen/download?tableId=' + tableId, + method: 'get', + responseType: 'blob' + }) +} + +// 获得表定义分页 +export function getSchemaTableList(query) { + return request({ + url: '/infra/codegen/db/table/list', + method: 'get', + params: query + }) +} + +// 基于数据库的表结构,创建代码生成器的表定义 +export function createCodegenList(data) { + return request({ + url: '/infra/codegen/create-list', + method: 'post', + data: data + }) +} + +// 删除数据库的表和字段定义 +export function deleteCodegen(tableId) { + return request({ + url: '/infra/codegen/delete?tableId=' + tableId, + method: 'delete' + }) +} diff --git a/src/api/infra/config.js b/src/api/infra/config.js new file mode 100644 index 00000000..eec15177 --- /dev/null +++ b/src/api/infra/config.js @@ -0,0 +1,62 @@ +import request from '@/utils/request' + +// 查询参数列表 +export function listConfig(query) { + return request({ + url: '/infra/config/page', + method: 'get', + params: query + }) +} + +// 查询参数详细 +export function getConfig(configId) { + return request({ + url: '/infra/config/get?id=' + configId, + method: 'get' + }) +} + +// 根据参数键名查询参数值 +export function getConfigKey(configKey) { + return request({ + url: '/infra/config/get-value-by-key?key=' + configKey, + method: 'get' + }) +} + +// 新增参数配置 +export function addConfig(data) { + return request({ + url: '/infra/config/create', + method: 'post', + data: data + }) +} + +// 修改参数配置 +export function updateConfig(data) { + return request({ + url: '/infra/config/update', + method: 'put', + data: data + }) +} + +// 删除参数配置 +export function delConfig(configId) { + return request({ + url: '/infra/config/delete?id=' + configId, + method: 'delete' + }) +} + +// 导出参数 +export function exportConfig(query) { + return request({ + url: '/infra/config/export', + method: 'get', + params: query, + responseType: 'blob' + }) +} diff --git a/src/api/infra/dataSourceConfig.js b/src/api/infra/dataSourceConfig.js new file mode 100644 index 00000000..2d96b49c --- /dev/null +++ b/src/api/infra/dataSourceConfig.js @@ -0,0 +1,43 @@ +import request from '@/utils/request' + +// 创建数据源配置 +export function createDataSourceConfig(data) { + return request({ + url: '/infra/data-source-config/create', + method: 'post', + data: data + }) +} + +// 更新数据源配置 +export function updateDataSourceConfig(data) { + return request({ + url: '/infra/data-source-config/update', + method: 'put', + data: data + }) +} + +// 删除数据源配置 +export function deleteDataSourceConfig(id) { + return request({ + url: '/infra/data-source-config/delete?id=' + id, + method: 'delete' + }) +} + +// 获得数据源配置 +export function getDataSourceConfig(id) { + return request({ + url: '/infra/data-source-config/get?id=' + id, + method: 'get' + }) +} + +// 获得数据源配置列表 +export function getDataSourceConfigList() { + return request({ + url: '/infra/data-source-config/list', + method: 'get', + }) +} diff --git a/src/api/infra/dbDoc.js b/src/api/infra/dbDoc.js new file mode 100644 index 00000000..015c6d71 --- /dev/null +++ b/src/api/infra/dbDoc.js @@ -0,0 +1,26 @@ +// 导出参数 +import request from "@/utils/request"; + +export function exportHtml() { + return request({ + url: '/infra/db-doc/export-html', + method: 'get', + responseType: 'blob' + }) +} + +export function exportWord() { + return request({ + url: '/infra/db-doc/export-word', + method: 'get', + responseType: 'blob' + }) +} + +export function exportMarkdown() { + return request({ + url: '/infra/db-doc/export-markdown', + method: 'get', + responseType: 'blob' + }) +} diff --git a/src/api/infra/file.js b/src/api/infra/file.js new file mode 100644 index 00000000..2aeda2e9 --- /dev/null +++ b/src/api/infra/file.js @@ -0,0 +1,18 @@ +import request from '@/utils/request' + +// 删除文件 +export function deleteFile(id) { + return request({ + url: '/infra/file/delete?id=' + id, + method: 'delete' + }) +} + +// 获得文件分页 +export function getFilePage(query) { + return request({ + url: '/infra/file/page', + method: 'get', + params: query + }) +} diff --git a/src/api/infra/fileConfig.js b/src/api/infra/fileConfig.js new file mode 100644 index 00000000..4b75773b --- /dev/null +++ b/src/api/infra/fileConfig.js @@ -0,0 +1,59 @@ +import request from '@/utils/request' + +// 创建文件配置 +export function createFileConfig(data) { + return request({ + url: '/infra/file-config/create', + method: 'post', + data: data + }) +} + +// 更新文件配置 +export function updateFileConfig(data) { + return request({ + url: '/infra/file-config/update', + method: 'put', + data: data + }) +} + +// 更新文件配置为主配置 +export function updateFileConfigMaster(id) { + return request({ + url: '/infra/file-config/update-master?id=' + id, + method: 'put' + }) +} + +// 删除文件配置 +export function deleteFileConfig(id) { + return request({ + url: '/infra/file-config/delete?id=' + id, + method: 'delete' + }) +} + +// 获得文件配置 +export function getFileConfig(id) { + return request({ + url: '/infra/file-config/get?id=' + id, + method: 'get' + }) +} + +// 获得文件配置分页 +export function getFileConfigPage(query) { + return request({ + url: '/infra/file-config/page', + method: 'get', + params: query + }) +} + +export function testFileConfig(id) { + return request({ + url: '/infra/file-config/test?id=' + id, + method: 'get' + }) +} diff --git a/src/api/infra/job.js b/src/api/infra/job.js new file mode 100644 index 00000000..c2237c51 --- /dev/null +++ b/src/api/infra/job.js @@ -0,0 +1,82 @@ +import request from '@/utils/request' + +// 查询定时任务调度列表 +export function listJob(query) { + return request({ + url: '/infra/job/page', + method: 'get', + params: query + }) +} + +// 查询定时任务调度详细 +export function getJob(jobId) { + return request({ + url: '/infra/job/get?id=' + jobId, + method: 'get' + }) +} + +// 新增定时任务调度 +export function addJob(data) { + return request({ + url: '/infra/job/create', + method: 'post', + data: data + }) +} + +// 修改定时任务调度 +export function updateJob(data) { + return request({ + url: '/infra/job/update', + method: 'put', + data: data + }) +} + +// 删除定时任务调度 +export function delJob(jobId) { + return request({ + url: '/infra/job/delete?id=' + jobId, + method: 'delete' + }) +} + +// 导出定时任务调度 +export function exportJob(query) { + return request({ + url: '/infra/job/export-excel', + method: 'get', + params: query, + responseType: 'blob' + }) +} + +// 任务状态修改 +export function updateJobStatus(jobId, status) { + return request({ + url: '/infra/job/update-status', + method: 'put', + headers:{ + 'Content-type': 'application/x-www-form-urlencoded' + }, + data: 'id=' + jobId + "&status=" + status, + }) +} + +// 定时任务立即执行一次 +export function runJob(jobId) { + return request({ + url: '/infra/job/trigger?id=' + jobId, + method: 'put' + }) +} + +// 获得定时任务的下 n 次执行时间 +export function getJobNextTimes(jobId) { + return request({ + url: '/infra/job/get_next_times?id=' + jobId, + method: 'get' + }) +} diff --git a/src/api/infra/jobLog.js b/src/api/infra/jobLog.js new file mode 100644 index 00000000..348f2ed9 --- /dev/null +++ b/src/api/infra/jobLog.js @@ -0,0 +1,28 @@ +import request from '@/utils/request' + +// 获得定时任务 +export function getJobLog(id) { + return request({ + url: '/infra/job-log/get?id=' + id, + method: 'get' + }) +} + +// 获得定时任务分页 +export function getJobLogPage(query) { + return request({ + url: '/infra/job-log/page', + method: 'get', + params: query + }) +} + +// 导出定时任务 Excel +export function exportJobLogExcel(query) { + return request({ + url: '/infra/job-log/export-excel', + method: 'get', + params: query, + responseType: 'blob' + }) +} diff --git a/src/api/infra/redis.js b/src/api/infra/redis.js new file mode 100644 index 00000000..fce18747 --- /dev/null +++ b/src/api/infra/redis.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +// 查询缓存详细 +export function getCache() { + return request({ + url: '/infra/redis/get-monitor-info', + method: 'get' + }) +} diff --git a/src/api/infra/testDemo.js b/src/api/infra/testDemo.js new file mode 100644 index 00000000..cec5742b --- /dev/null +++ b/src/api/infra/testDemo.js @@ -0,0 +1,54 @@ +import request from '@/utils/request' + +// 创建字典类型 +export function createTestDemo(data) { + return request({ + url: '/infra/test-demo/create', + method: 'post', + data: data + }) +} + +// 更新字典类型 +export function updateTestDemo(data) { + return request({ + url: '/infra/test-demo/update', + method: 'put', + data: data + }) +} + +// 删除字典类型 +export function deleteTestDemo(id) { + return request({ + url: '/infra/test-demo/delete?id=' + id, + method: 'delete' + }) +} + +// 获得字典类型 +export function getTestDemo(id) { + return request({ + url: '/infra/test-demo/get?id=' + id, + method: 'get' + }) +} + +// 获得字典类型分页 +export function getTestDemoPage(query) { + return request({ + url: '/infra/test-demo/page', + method: 'get', + params: query + }) +} + +// 导出字典类型 Excel +export function exportTestDemoExcel(query) { + return request({ + url: '/infra/test-demo/export-excel', + method: 'get', + params: query, + responseType: 'blob' + }) +} diff --git a/src/components/Crontab/day.vue b/src/components/Crontab/day.vue new file mode 100644 index 00000000..d6c74fad --- /dev/null +++ b/src/components/Crontab/day.vue @@ -0,0 +1,160 @@ + + + diff --git a/src/components/Crontab/hour.vue b/src/components/Crontab/hour.vue new file mode 100644 index 00000000..3b890273 --- /dev/null +++ b/src/components/Crontab/hour.vue @@ -0,0 +1,114 @@ + + + diff --git a/src/components/Crontab/index.vue b/src/components/Crontab/index.vue new file mode 100644 index 00000000..f0bc8569 --- /dev/null +++ b/src/components/Crontab/index.vue @@ -0,0 +1,430 @@ + + + + diff --git a/src/components/Crontab/min.vue b/src/components/Crontab/min.vue new file mode 100644 index 00000000..71a1fc17 --- /dev/null +++ b/src/components/Crontab/min.vue @@ -0,0 +1,116 @@ + + + diff --git a/src/components/Crontab/month.vue b/src/components/Crontab/month.vue new file mode 100644 index 00000000..2539935e --- /dev/null +++ b/src/components/Crontab/month.vue @@ -0,0 +1,114 @@ + + + diff --git a/src/components/Crontab/result.vue b/src/components/Crontab/result.vue new file mode 100644 index 00000000..605c8c9f --- /dev/null +++ b/src/components/Crontab/result.vue @@ -0,0 +1,559 @@ + + + diff --git a/src/components/Crontab/second.vue b/src/components/Crontab/second.vue new file mode 100644 index 00000000..0b5df29c --- /dev/null +++ b/src/components/Crontab/second.vue @@ -0,0 +1,117 @@ + + + diff --git a/src/components/Crontab/week.vue b/src/components/Crontab/week.vue new file mode 100644 index 00000000..c84f3b3b --- /dev/null +++ b/src/components/Crontab/week.vue @@ -0,0 +1,202 @@ + + + diff --git a/src/components/Crontab/year.vue b/src/components/Crontab/year.vue new file mode 100644 index 00000000..2c8eec32 --- /dev/null +++ b/src/components/Crontab/year.vue @@ -0,0 +1,131 @@ + + + diff --git a/src/components/generator/config.js b/src/components/generator/config.js new file mode 100644 index 00000000..780a1bb6 --- /dev/null +++ b/src/components/generator/config.js @@ -0,0 +1,630 @@ +// 表单属性【右面板】 +export const formConf = { + formRef: 'elForm', + formModel: 'formData', + size: 'medium', + labelPosition: 'right', + labelWidth: 100, + formRules: 'rules', + gutter: 15, + disabled: false, + span: 24, + formBtns: true +} + +// 输入型组件 【左面板】 +export const inputComponents = [ + { + // 组件的自定义配置 + __config__: { + label: '单行文本', + labelWidth: null, + showLabel: true, + changeTag: true, + tag: 'el-input', + tagIcon: 'input', + defaultValue: undefined, + required: true, + layout: 'colFormItem', + span: 24, + document: 'https://element.eleme.cn/#/zh-CN/component/input', + // 正则校验规则 + regList: [] + }, + // 组件的插槽属性 + __slot__: { + prepend: '', + append: '' + }, + // 其余的为可直接写在组件标签上的属性 + placeholder: '请输入', + style: { width: '100%' }, + clearable: true, + 'prefix-icon': '', + 'suffix-icon': '', + maxlength: null, + 'show-word-limit': false, + readonly: false, + disabled: false + }, + { + __config__: { + label: '多行文本', + labelWidth: null, + showLabel: true, + tag: 'el-input', + tagIcon: 'textarea', + defaultValue: undefined, + required: true, + layout: 'colFormItem', + span: 24, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/input' + }, + type: 'textarea', + placeholder: '请输入', + autosize: { + minRows: 4, + maxRows: 4 + }, + style: { width: '100%' }, + maxlength: null, + 'show-word-limit': false, + readonly: false, + disabled: false + }, + { + __config__: { + label: '密码', + showLabel: true, + labelWidth: null, + changeTag: true, + tag: 'el-input', + tagIcon: 'password', + defaultValue: undefined, + layout: 'colFormItem', + span: 24, + required: true, + regList: [], + document: 'https://element.eleme.cn/#/zh-CN/component/input' + }, + __slot__: { + prepend: '', + append: '' + }, + placeholder: '请输入', + 'show-password': true, + style: { width: '100%' }, + clearable: true, + 'prefix-icon': '', + 'suffix-icon': '', + maxlength: null, + 'show-word-limit': false, + readonly: false, + disabled: false + }, + { + __config__: { + label: '计数器', + showLabel: true, + changeTag: true, + labelWidth: null, + tag: 'el-input-number', + tagIcon: 'number', + defaultValue: undefined, + span: 24, + layout: 'colFormItem', + required: true, + regList: [], + document: 'https://element.eleme.cn/#/zh-CN/component/input-number' + }, + placeholder: '', + min: undefined, + max: undefined, + step: 1, + 'step-strictly': false, + precision: undefined, + 'controls-position': '', + disabled: false + }, + { + __config__: { + label: '编辑器', + showLabel: true, + changeTag: true, + labelWidth: null, + tag: 'tinymce', + tagIcon: 'rich-text', + defaultValue: null, + span: 24, + layout: 'colFormItem', + required: true, + regList: [], + document: 'http://tinymce.ax-z.cn' + }, + placeholder: '请输入', + height: 300, // 编辑器高度 + branding: false // 隐藏右下角品牌烙印 + } +] + +// 选择型组件 【左面板】 +export const selectComponents = [ + { + __config__: { + label: '下拉选择', + showLabel: true, + labelWidth: null, + tag: 'el-select', + tagIcon: 'select', + layout: 'colFormItem', + span: 24, + required: true, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/select' + }, + __slot__: { + options: [{ + label: '选项一', + value: 1 + }, { + label: '选项二', + value: 2 + }] + }, + placeholder: '请选择', + style: { width: '100%' }, + clearable: true, + disabled: false, + filterable: false, + multiple: false + }, + { + __config__: { + label: '级联选择', + url: 'https://www.fastmock.site/mock/f8d7a54fb1e60561e2f720d5a810009d/fg/cascaderList', + method: 'get', + dataPath: 'list', + dataConsumer: 'options', + showLabel: true, + labelWidth: null, + tag: 'el-cascader', + tagIcon: 'cascader', + layout: 'colFormItem', + defaultValue: [], + dataType: 'dynamic', + span: 24, + required: true, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/cascader' + }, + options: [{ + id: 1, + value: 1, + label: '选项1', + children: [{ + id: 2, + value: 2, + label: '选项1-1' + }] + }], + placeholder: '请选择', + style: { width: '100%' }, + props: { + props: { + multiple: false, + label: 'label', + value: 'value', + children: 'children' + } + }, + 'show-all-levels': true, + disabled: false, + clearable: true, + filterable: false, + separator: '/' + }, + { + __config__: { + label: '单选框组', + labelWidth: null, + showLabel: true, + tag: 'el-radio-group', + tagIcon: 'radio', + changeTag: true, + defaultValue: undefined, + layout: 'colFormItem', + span: 24, + optionType: 'default', + regList: [], + required: true, + border: false, + document: 'https://element.eleme.cn/#/zh-CN/component/radio' + }, + __slot__: { + options: [{ + label: '选项一', + value: 1 + }, { + label: '选项二', + value: 2 + }] + }, + style: {}, + size: 'medium', + disabled: false + }, + { + __config__: { + label: '多选框组', + tag: 'el-checkbox-group', + tagIcon: 'checkbox', + defaultValue: [], + span: 24, + showLabel: true, + labelWidth: null, + layout: 'colFormItem', + optionType: 'default', + required: true, + regList: [], + changeTag: true, + border: false, + document: 'https://element.eleme.cn/#/zh-CN/component/checkbox' + }, + __slot__: { + options: [{ + label: '选项一', + value: 1 + }, { + label: '选项二', + value: 2 + }] + }, + style: {}, + size: 'medium', + min: null, + max: null, + disabled: false + }, + { + __config__: { + label: '开关', + tag: 'el-switch', + tagIcon: 'switch', + defaultValue: false, + span: 24, + showLabel: true, + labelWidth: null, + layout: 'colFormItem', + required: true, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/switch' + }, + style: {}, + disabled: false, + 'active-text': '', + 'inactive-text': '', + 'active-color': null, + 'inactive-color': null, + 'active-value': true, + 'inactive-value': false + }, + { + __config__: { + label: '滑块', + tag: 'el-slider', + tagIcon: 'slider', + defaultValue: null, + span: 24, + showLabel: true, + layout: 'colFormItem', + labelWidth: null, + required: true, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/slider' + }, + disabled: false, + min: 0, + max: 100, + step: 1, + 'show-stops': false, + range: false + }, + { + __config__: { + label: '时间选择', + tag: 'el-time-picker', + tagIcon: 'time', + defaultValue: null, + span: 24, + showLabel: true, + layout: 'colFormItem', + labelWidth: null, + required: true, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/time-picker' + }, + placeholder: '请选择', + style: { width: '100%' }, + disabled: false, + clearable: true, + 'picker-options': { + selectableRange: '00:00:00-23:59:59' + }, + format: 'HH:mm:ss', + 'value-format': 'HH:mm:ss' + }, + { + __config__: { + label: '时间范围', + tag: 'el-time-picker', + tagIcon: 'time-range', + span: 24, + showLabel: true, + labelWidth: null, + layout: 'colFormItem', + defaultValue: null, + required: true, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/time-picker' + }, + style: { width: '100%' }, + disabled: false, + clearable: true, + 'is-range': true, + 'range-separator': '至', + 'start-placeholder': '开始时间', + 'end-placeholder': '结束时间', + format: 'HH:mm:ss', + 'value-format': 'HH:mm:ss' + }, + { + __config__: { + label: '日期选择', + tag: 'el-date-picker', + tagIcon: 'date', + defaultValue: null, + showLabel: true, + labelWidth: null, + span: 24, + layout: 'colFormItem', + required: true, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/date-picker' + }, + placeholder: '请选择', + type: 'date', + style: { width: '100%' }, + disabled: false, + clearable: true, + format: 'yyyy-MM-dd', + 'value-format': 'yyyy-MM-dd', + readonly: false + }, + { + __config__: { + label: '日期范围', + tag: 'el-date-picker', + tagIcon: 'date-range', + defaultValue: null, + span: 24, + showLabel: true, + labelWidth: null, + required: true, + layout: 'colFormItem', + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/date-picker' + }, + style: { width: '100%' }, + type: 'daterange', + 'range-separator': '至', + 'start-placeholder': '开始日期', + 'end-placeholder': '结束日期', + disabled: false, + clearable: true, + format: 'yyyy-MM-dd', + 'value-format': 'yyyy-MM-dd', + readonly: false + }, + { + __config__: { + label: '评分', + tag: 'el-rate', + tagIcon: 'rate', + defaultValue: 0, + span: 24, + showLabel: true, + labelWidth: null, + layout: 'colFormItem', + required: true, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/rate' + }, + style: {}, + max: 5, + 'allow-half': false, + 'show-text': false, + 'show-score': false, + disabled: false + }, + { + __config__: { + label: '颜色选择', + tag: 'el-color-picker', + tagIcon: 'color', + span: 24, + defaultValue: null, + showLabel: true, + labelWidth: null, + layout: 'colFormItem', + required: true, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/color-picker' + }, + 'show-alpha': false, + 'color-format': '', + disabled: false, + size: 'medium' + }, + { + __config__: { + label: '上传', + tag: 'el-upload', + tagIcon: 'upload', + layout: 'colFormItem', + defaultValue: null, + showLabel: true, + labelWidth: null, + required: true, + span: 24, + showTip: false, + buttonText: '点击上传', + regList: [], + changeTag: true, + fileSize: 2, + sizeUnit: 'MB', + document: 'https://element.eleme.cn/#/zh-CN/component/upload' + }, + __slot__: { + 'list-type': true + }, + // action: process.env.VUE_APP_BASE_API + "/admin-api/infra/file/upload", // 请求地址 + action: '/infra/file/upload', // 请求地址 + disabled: false, + accept: '', + name: 'file', + 'auto-upload': true, + 'list-type': 'text', + multiple: false + } +] + +// 布局型组件 【左面板】 +export const layoutComponents = [ + { + __config__: { + layout: 'rowFormItem', + tagIcon: 'row', + label: '行容器', + layoutTree: true, + document: 'https://element.eleme.cn/#/zh-CN/component/layout#row-attributes' + }, + type: 'default', + justify: 'start', + align: 'top' + }, + { + __config__: { + label: '按钮', + showLabel: true, + changeTag: true, + labelWidth: null, + tag: 'el-button', + tagIcon: 'button', + span: 24, + layout: 'colFormItem', + document: 'https://element.eleme.cn/#/zh-CN/component/button' + }, + __slot__: { + default: '主要按钮' + }, + type: 'primary', + icon: 'el-icon-search', + round: false, + size: 'medium', + plain: false, + circle: false, + disabled: false + }, + { + __config__: { + layout: 'colFormItem', + tagIcon: 'table', + tag: 'el-table', + document: 'https://element.eleme.cn/#/zh-CN/component/table', + span: 24, + formId: 101, + renderKey: 1595761764203, + componentName: 'row101', + showLabel: true, + changeTag: true, + labelWidth: null, + label: '表格[开发中]', + dataType: 'dynamic', + method: 'get', + dataPath: 'list', + dataConsumer: 'data', + url: 'https://www.fastmock.site/mock/f8d7a54fb1e60561e2f720d5a810009d/fg/tableData', + children: [{ + __config__: { + layout: 'raw', + tag: 'el-table-column', + renderKey: 15957617660153 + }, + prop: 'date', + label: '日期' + }, { + __config__: { + layout: 'raw', + tag: 'el-table-column', + renderKey: 15957617660152 + }, + prop: 'address', + label: '地址' + }, { + __config__: { + layout: 'raw', + tag: 'el-table-column', + renderKey: 15957617660151 + }, + prop: 'name', + label: '名称' + }, { + __config__: { + layout: 'raw', + tag: 'el-table-column', + renderKey: 1595774496335, + children: [ + { + __config__: { + label: '按钮', + tag: 'el-button', + tagIcon: 'button', + layout: 'raw', + renderKey: 1595779809901 + }, + __slot__: { + default: '主要按钮' + }, + type: 'primary', + icon: 'el-icon-search', + round: false, + size: 'medium' + } + ] + }, + label: '操作' + }] + }, + data: [], + directives: [{ + name: 'loading', + value: true + }], + border: true, + type: 'default', + justify: 'start', + align: 'top' + } +] diff --git a/src/components/generator/css.js b/src/components/generator/css.js new file mode 100644 index 00000000..7cb86e64 --- /dev/null +++ b/src/components/generator/css.js @@ -0,0 +1,18 @@ +const styles = { + 'el-rate': '.el-rate{display: inline-block; vertical-align: text-top;}', + 'el-upload': '.el-upload__tip{line-height: 1.2;}' +} + +function addCss(cssList, el) { + const css = styles[el.__config__.tag] + css && cssList.indexOf(css) === -1 && cssList.push(css) + if (el.__config__.children) { + el.__config__.children.forEach(el2 => addCss(cssList, el2)) + } +} + +export function makeUpCss(conf) { + const cssList = [] + conf.fields.forEach(el => addCss(cssList, el)) + return cssList.join('\n') +} diff --git a/src/components/generator/drawingDefalut.js b/src/components/generator/drawingDefalut.js new file mode 100644 index 00000000..dbc1daf2 --- /dev/null +++ b/src/components/generator/drawingDefalut.js @@ -0,0 +1,37 @@ +export default [ + { + __config__: { + label: '单行文本', + labelWidth: null, + showLabel: true, + changeTag: true, + tag: 'el-input', + tagIcon: 'input', + defaultValue: undefined, + required: true, + layout: 'colFormItem', + span: 24, + document: 'https://element.eleme.cn/#/zh-CN/component/input', + // 正则校验规则 + regList: [{ + pattern: '/^1(3|4|5|7|8|9)\\d{9}$/', + message: '手机号格式错误' + }] + }, + // 组件的插槽属性 + __slot__: { + prepend: '', + append: '' + }, + __vModel__: 'mobile', + placeholder: '请输入手机号', + style: { width: '100%' }, + clearable: true, + 'prefix-icon': 'el-icon-mobile', + 'suffix-icon': '', + maxlength: 11, + 'show-word-limit': true, + readonly: false, + disabled: false + } +] diff --git a/src/components/generator/html.js b/src/components/generator/html.js new file mode 100644 index 00000000..6e9a32e6 --- /dev/null +++ b/src/components/generator/html.js @@ -0,0 +1,399 @@ +/* eslint-disable max-len */ +import ruleTrigger from './ruleTrigger' + +let confGlobal +let someSpanIsNot24 + +export function dialogWrapper(str) { + return ` + ${str} +
+ 取消 + 确定 +
+
` +} + +export function vueTemplate(str) { + return `` +} + +export function vueScript(str) { + return `` +} + +export function cssStyle(cssStr) { + return `` +} + +function buildFormTemplate(scheme, child, type) { + let labelPosition = '' + if (scheme.labelPosition !== 'right') { + labelPosition = `label-position="${scheme.labelPosition}"` + } + const disabled = scheme.disabled ? `:disabled="${scheme.disabled}"` : '' + let str = ` + ${child} + ${buildFromBtns(scheme, type)} + ` + if (someSpanIsNot24) { + str = ` + ${str} + ` + } + return str +} + +function buildFromBtns(scheme, type) { + let str = '' + if (scheme.formBtns && type === 'file') { + str = ` + 提交 + 重置 + ` + if (someSpanIsNot24) { + str = ` + ${str} + ` + } + } + return str +} + +// span不为24的用el-col包裹 +function colWrapper(scheme, str) { + if (someSpanIsNot24 || scheme.__config__.span !== 24) { + return ` + ${str} + ` + } + return str +} + +const layouts = { + colFormItem(scheme) { + const config = scheme.__config__ + let labelWidth = '' + let label = `label="${config.label}"` + if (config.labelWidth && config.labelWidth !== confGlobal.labelWidth) { + labelWidth = `label-width="${config.labelWidth}px"` + } + if (config.showLabel === false) { + labelWidth = 'label-width="0"' + label = '' + } + const required = !ruleTrigger[config.tag] && config.required ? 'required' : '' + const tagDom = tags[config.tag] ? tags[config.tag](scheme) : null + let str = ` + ${tagDom} + ` + str = colWrapper(scheme, str) + return str + }, + rowFormItem(scheme) { + const config = scheme.__config__ + const type = scheme.type === 'default' ? '' : `type="${scheme.type}"` + const justify = scheme.type === 'default' ? '' : `justify="${scheme.justify}"` + const align = scheme.type === 'default' ? '' : `align="${scheme.align}"` + const gutter = scheme.gutter ? `:gutter="${scheme.gutter}"` : '' + const children = config.children.map(el => layouts[el.__config__.layout](el)) + let str = ` + ${children.join('\n')} + ` + str = colWrapper(scheme, str) + return str + } +} + +const tags = { + 'el-button': el => { + const { + tag, disabled + } = attrBuilder(el) + const type = el.type ? `type="${el.type}"` : '' + const icon = el.icon ? `icon="${el.icon}"` : '' + const round = el.round ? 'round' : '' + const size = el.size ? `size="${el.size}"` : '' + const plain = el.plain ? 'plain' : '' + const circle = el.circle ? 'circle' : '' + let child = buildElButtonChild(el) + + if (child) child = `\n${child}\n` // 换行 + return `<${tag} ${type} ${icon} ${round} ${size} ${plain} ${disabled} ${circle}>${child}` + }, + 'el-input': el => { + const { + tag, disabled, vModel, clearable, placeholder, width + } = attrBuilder(el) + const maxlength = el.maxlength ? `:maxlength="${el.maxlength}"` : '' + const showWordLimit = el['show-word-limit'] ? 'show-word-limit' : '' + const readonly = el.readonly ? 'readonly' : '' + const prefixIcon = el['prefix-icon'] ? `prefix-icon='${el['prefix-icon']}'` : '' + const suffixIcon = el['suffix-icon'] ? `suffix-icon='${el['suffix-icon']}'` : '' + const showPassword = el['show-password'] ? 'show-password' : '' + const type = el.type ? `type="${el.type}"` : '' + const autosize = el.autosize && el.autosize.minRows + ? `:autosize="{minRows: ${el.autosize.minRows}, maxRows: ${el.autosize.maxRows}}"` + : '' + let child = buildElInputChild(el) + + if (child) child = `\n${child}\n` // 换行 + return `<${tag} ${vModel} ${type} ${placeholder} ${maxlength} ${showWordLimit} ${readonly} ${disabled} ${clearable} ${prefixIcon} ${suffixIcon} ${showPassword} ${autosize} ${width}>${child}` + }, + 'el-input-number': el => { + const { + tag, disabled, vModel, placeholder + } = attrBuilder(el) + const controlsPosition = el['controls-position'] ? `controls-position=${el['controls-position']}` : '' + const min = el.min ? `:min='${el.min}'` : '' + const max = el.max ? `:max='${el.max}'` : '' + const step = el.step ? `:step='${el.step}'` : '' + const stepStrictly = el['step-strictly'] ? 'step-strictly' : '' + const precision = el.precision ? `:precision='${el.precision}'` : '' + + return `<${tag} ${vModel} ${placeholder} ${step} ${stepStrictly} ${precision} ${controlsPosition} ${min} ${max} ${disabled}>` + }, + 'el-select': el => { + const { + tag, disabled, vModel, clearable, placeholder, width + } = attrBuilder(el) + const filterable = el.filterable ? 'filterable' : '' + const multiple = el.multiple ? 'multiple' : '' + let child = buildElSelectChild(el) + + if (child) child = `\n${child}\n` // 换行 + return `<${tag} ${vModel} ${placeholder} ${disabled} ${multiple} ${filterable} ${clearable} ${width}>${child}` + }, + 'el-radio-group': el => { + const { tag, disabled, vModel } = attrBuilder(el) + const size = `size="${el.size}"` + let child = buildElRadioGroupChild(el) + + if (child) child = `\n${child}\n` // 换行 + return `<${tag} ${vModel} ${size} ${disabled}>${child}` + }, + 'el-checkbox-group': el => { + const { tag, disabled, vModel } = attrBuilder(el) + const size = `size="${el.size}"` + const min = el.min ? `:min="${el.min}"` : '' + const max = el.max ? `:max="${el.max}"` : '' + let child = buildElCheckboxGroupChild(el) + + if (child) child = `\n${child}\n` // 换行 + return `<${tag} ${vModel} ${min} ${max} ${size} ${disabled}>${child}` + }, + 'el-switch': el => { + const { tag, disabled, vModel } = attrBuilder(el) + const activeText = el['active-text'] ? `active-text="${el['active-text']}"` : '' + const inactiveText = el['inactive-text'] ? `inactive-text="${el['inactive-text']}"` : '' + const activeColor = el['active-color'] ? `active-color="${el['active-color']}"` : '' + const inactiveColor = el['inactive-color'] ? `inactive-color="${el['inactive-color']}"` : '' + const activeValue = el['active-value'] !== true ? `:active-value='${JSON.stringify(el['active-value'])}'` : '' + const inactiveValue = el['inactive-value'] !== false ? `:inactive-value='${JSON.stringify(el['inactive-value'])}'` : '' + + return `<${tag} ${vModel} ${activeText} ${inactiveText} ${activeColor} ${inactiveColor} ${activeValue} ${inactiveValue} ${disabled}>` + }, + 'el-cascader': el => { + const { + tag, disabled, vModel, clearable, placeholder, width + } = attrBuilder(el) + const options = el.options ? `:options="${el.__vModel__}Options"` : '' + const props = el.props ? `:props="${el.__vModel__}Props"` : '' + const showAllLevels = el['show-all-levels'] ? '' : ':show-all-levels="false"' + const filterable = el.filterable ? 'filterable' : '' + const separator = el.separator === '/' ? '' : `separator="${el.separator}"` + + return `<${tag} ${vModel} ${options} ${props} ${width} ${showAllLevels} ${placeholder} ${separator} ${filterable} ${clearable} ${disabled}>` + }, + 'el-slider': el => { + const { tag, disabled, vModel } = attrBuilder(el) + const min = el.min ? `:min='${el.min}'` : '' + const max = el.max ? `:max='${el.max}'` : '' + const step = el.step ? `:step='${el.step}'` : '' + const range = el.range ? 'range' : '' + const showStops = el['show-stops'] ? `:show-stops="${el['show-stops']}"` : '' + + return `<${tag} ${min} ${max} ${step} ${vModel} ${range} ${showStops} ${disabled}>` + }, + 'el-time-picker': el => { + const { + tag, disabled, vModel, clearable, placeholder, width + } = attrBuilder(el) + const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : '' + const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : '' + const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : '' + const isRange = el['is-range'] ? 'is-range' : '' + const format = el.format ? `format="${el.format}"` : '' + const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : '' + const pickerOptions = el['picker-options'] ? `:picker-options='${JSON.stringify(el['picker-options'])}'` : '' + + return `<${tag} ${vModel} ${isRange} ${format} ${valueFormat} ${pickerOptions} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${disabled}>` + }, + 'el-date-picker': el => { + const { + tag, disabled, vModel, clearable, placeholder, width + } = attrBuilder(el) + const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : '' + const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : '' + const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : '' + const format = el.format ? `format="${el.format}"` : '' + const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : '' + const type = el.type === 'date' ? '' : `type="${el.type}"` + const readonly = el.readonly ? 'readonly' : '' + + return `<${tag} ${type} ${vModel} ${format} ${valueFormat} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${readonly} ${disabled}>` + }, + 'el-rate': el => { + const { tag, disabled, vModel } = attrBuilder(el) + const max = el.max ? `:max='${el.max}'` : '' + const allowHalf = el['allow-half'] ? 'allow-half' : '' + const showText = el['show-text'] ? 'show-text' : '' + const showScore = el['show-score'] ? 'show-score' : '' + + return `<${tag} ${vModel} ${max} ${allowHalf} ${showText} ${showScore} ${disabled}>` + }, + 'el-color-picker': el => { + const { tag, disabled, vModel } = attrBuilder(el) + const size = `size="${el.size}"` + const showAlpha = el['show-alpha'] ? 'show-alpha' : '' + const colorFormat = el['color-format'] ? `color-format="${el['color-format']}"` : '' + + return `<${tag} ${vModel} ${size} ${showAlpha} ${colorFormat} ${disabled}>` + }, + 'el-upload': el => { + const { tag } = el.__config__ + const disabled = el.disabled ? ':disabled=\'true\'' : '' + const action = el.action ? `:action="${el.__vModel__}Action"` : '' + const multiple = el.multiple ? 'multiple' : '' + const listType = el['list-type'] !== 'text' ? `list-type="${el['list-type']}"` : '' + const accept = el.accept ? `accept="${el.accept}"` : '' + const name = el.name !== 'file' ? `name="${el.name}"` : '' + const autoUpload = el['auto-upload'] === false ? ':auto-upload="false"' : '' + const beforeUpload = `:before-upload="${el.__vModel__}BeforeUpload"` + const fileList = `:file-list="${el.__vModel__}fileList"` + const ref = `ref="${el.__vModel__}"` + let child = buildElUploadChild(el) + + if (child) child = `\n${child}\n` // 换行 + return `<${tag} ${ref} ${fileList} ${action} ${autoUpload} ${multiple} ${beforeUpload} ${listType} ${accept} ${name} ${disabled}>${child}` + }, + tinymce: el => { + const { tag, vModel, placeholder } = attrBuilder(el) + const height = el.height ? `:height="${el.height}"` : '' + const branding = el.branding ? `:branding="${el.branding}"` : '' + return `<${tag} ${vModel} ${placeholder} ${height} ${branding}>` + } +} + +function attrBuilder(el) { + return { + tag: el.__config__.tag, + vModel: `v-model="${confGlobal.formModel}.${el.__vModel__}"`, + clearable: el.clearable ? 'clearable' : '', + placeholder: el.placeholder ? `placeholder="${el.placeholder}"` : '', + width: el.style && el.style.width ? ':style="{width: \'100%\'}"' : '', + disabled: el.disabled ? ':disabled=\'true\'' : '' + } +} + +// el-buttin 子级 +function buildElButtonChild(scheme) { + const children = [] + const slot = scheme.__slot__ || {} + if (slot.default) { + children.push(slot.default) + } + return children.join('\n') +} + +// el-input 子级 +function buildElInputChild(scheme) { + const children = [] + const slot = scheme.__slot__ + if (slot && slot.prepend) { + children.push(``) + } + if (slot && slot.append) { + children.push(``) + } + return children.join('\n') +} + +// el-select 子级 +function buildElSelectChild(scheme) { + const children = [] + const slot = scheme.__slot__ + if (slot && slot.options && slot.options.length) { + children.push(``) + } + return children.join('\n') +} + +// el-radio-group 子级 +function buildElRadioGroupChild(scheme) { + const children = [] + const slot = scheme.__slot__ + const config = scheme.__config__ + if (slot && slot.options && slot.options.length) { + const tag = config.optionType === 'button' ? 'el-radio-button' : 'el-radio' + const border = config.border ? 'border' : '' + children.push(`<${tag} v-for="(item, index) in ${scheme.__vModel__}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}`) + } + return children.join('\n') +} + +// el-checkbox-group 子级 +function buildElCheckboxGroupChild(scheme) { + const children = [] + const slot = scheme.__slot__ + const config = scheme.__config__ + if (slot && slot.options && slot.options.length) { + const tag = config.optionType === 'button' ? 'el-checkbox-button' : 'el-checkbox' + const border = config.border ? 'border' : '' + children.push(`<${tag} v-for="(item, index) in ${scheme.__vModel__}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}`) + } + return children.join('\n') +} + +// el-upload 子级 +function buildElUploadChild(scheme) { + const list = [] + const config = scheme.__config__ + if (scheme['list-type'] === 'picture-card') list.push('') + else list.push(`${config.buttonText}`) + if (config.showTip) list.push(`
只能上传不超过 ${config.fileSize}${config.sizeUnit} 的${scheme.accept}文件
`) + return list.join('\n') +} + +/** + * 组装html代码。【入口函数】 + * @param {Object} formConfig 整个表单配置 + * @param {String} type 生成类型,文件或弹窗等 + */ +export function makeUpHtml(formConfig, type) { + const htmlList = [] + confGlobal = formConfig + // 判断布局是否都沾满了24个栅格,以备后续简化代码结构 + someSpanIsNot24 = formConfig.fields.some(item => item.__config__.span !== 24) + // 遍历渲染每个组件成html + formConfig.fields.forEach(el => { + htmlList.push(layouts[el.__config__.layout](el)) + }) + const htmlStr = htmlList.join('\n') + // 将组件代码放进form标签 + let temp = buildFormTemplate(formConfig, htmlStr, type) + // dialog标签包裹代码 + if (type === 'dialog') { + temp = dialogWrapper(temp) + } + confGlobal = null + return temp +} diff --git a/src/components/generator/js.js b/src/components/generator/js.js new file mode 100644 index 00000000..f1605937 --- /dev/null +++ b/src/components/generator/js.js @@ -0,0 +1,271 @@ +import { isArray } from 'util' +import { exportDefault, titleCase, deepClone } from '@/utils' +import ruleTrigger from './ruleTrigger' + +const units = { + KB: '1024', + MB: '1024 / 1024', + GB: '1024 / 1024 / 1024' +} +let confGlobal +const inheritAttrs = { + file: '', + dialog: 'inheritAttrs: false,' +} + +/** + * 组装js 【入口函数】 + * @param {Object} formConfig 整个表单配置 + * @param {String} type 生成类型,文件或弹窗等 + */ +export function makeUpJs(formConfig, type) { + confGlobal = formConfig = deepClone(formConfig) + const dataList = [] + const ruleList = [] + const optionsList = [] + const propsList = [] + const methodList = mixinMethod(type) + const uploadVarList = [] + const created = [] + + formConfig.fields.forEach(el => { + buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList, created) + }) + + const script = buildexport( + formConfig, + type, + dataList.join('\n'), + ruleList.join('\n'), + optionsList.join('\n'), + uploadVarList.join('\n'), + propsList.join('\n'), + methodList.join('\n'), + created.join('\n') + ) + confGlobal = null + return script +} + +// 构建组件属性 +function buildAttributes(scheme, dataList, ruleList, optionsList, methodList, propsList, uploadVarList, created) { + const config = scheme.__config__ + const slot = scheme.__slot__ + buildData(scheme, dataList) + buildRules(scheme, ruleList) + + // 特殊处理options属性 + if (scheme.options || (slot && slot.options && slot.options.length)) { + buildOptions(scheme, optionsList) + if (config.dataType === 'dynamic') { + const model = `${scheme.__vModel__}Options` + const options = titleCase(model) + const methodName = `get${options}` + buildOptionMethod(methodName, model, methodList, scheme) + callInCreated(methodName, created) + } + } + + // 处理props + if (scheme.props && scheme.props.props) { + buildProps(scheme, propsList) + } + + // 处理el-upload的action + if (scheme.action && config.tag === 'el-upload') { + uploadVarList.push( + `${scheme.__vModel__}Action: '${scheme.action}', + ${scheme.__vModel__}fileList: [],` + ) + methodList.push(buildBeforeUpload(scheme)) + // 非自动上传时,生成手动上传的函数 + if (!scheme['auto-upload']) { + methodList.push(buildSubmitUpload(scheme)) + } + } + + // 构建子级组件属性 + if (config.children) { + config.children.forEach(item => { + buildAttributes(item, dataList, ruleList, optionsList, methodList, propsList, uploadVarList, created) + }) + } +} + +// 在Created调用函数 +function callInCreated(methodName, created) { + created.push(`this.${methodName}()`) +} + +// 混入处理函数 +function mixinMethod(type) { + const list = []; const + minxins = { + file: confGlobal.formBtns ? { + submitForm: `submitForm() { + this.$refs['${confGlobal.formRef}'].validate(valid => { + if(!valid) return + // TODO 提交表单 + }) + },`, + resetForm: `resetForm() { + this.$refs['${confGlobal.formRef}'].resetFields() + },` + } : null, + dialog: { + onOpen: 'onOpen() {},', + onClose: `onClose() { + this.$refs['${confGlobal.formRef}'].resetFields() + },`, + close: `close() { + this.$emit('update:visible', false) + },`, + handelConfirm: `handelConfirm() { + this.$refs['${confGlobal.formRef}'].validate(valid => { + if(!valid) return + this.close() + }) + },` + } + } + + const methods = minxins[type] + if (methods) { + Object.keys(methods).forEach(key => { + list.push(methods[key]) + }) + } + + return list +} + +// 构建data +function buildData(scheme, dataList) { + const config = scheme.__config__ + if (scheme.__vModel__ === undefined) return + const defaultValue = JSON.stringify(config.defaultValue) + dataList.push(`${scheme.__vModel__}: ${defaultValue},`) +} + +// 构建校验规则 +function buildRules(scheme, ruleList) { + const config = scheme.__config__ + if (scheme.__vModel__ === undefined) return + const rules = [] + if (ruleTrigger[config.tag]) { + if (config.required) { + const type = isArray(config.defaultValue) ? 'type: \'array\',' : '' + let message = isArray(config.defaultValue) ? `请至少选择一个${config.label}` : scheme.placeholder + if (message === undefined) message = `${config.label}不能为空` + rules.push(`{ required: true, ${type} message: '${message}', trigger: '${ruleTrigger[config.tag]}' }`) + } + if (config.regList && isArray(config.regList)) { + config.regList.forEach(item => { + if (item.pattern) { + rules.push( + `{ pattern: ${eval(item.pattern)}, message: '${item.message}', trigger: '${ruleTrigger[config.tag]}' }` + ) + } + }) + } + ruleList.push(`${scheme.__vModel__}: [${rules.join(',')}],`) + } +} + +// 构建options +function buildOptions(scheme, optionsList) { + if (scheme.__vModel__ === undefined) return + // el-cascader直接有options属性,其他组件都是定义在slot中,所以有两处判断 + let { options } = scheme + if (!options) options = scheme.__slot__.options + if (scheme.__config__.dataType === 'dynamic') { options = [] } + const str = `${scheme.__vModel__}Options: ${JSON.stringify(options)},` + optionsList.push(str) +} + +function buildProps(scheme, propsList) { + const str = `${scheme.__vModel__}Props: ${JSON.stringify(scheme.props.props)},` + propsList.push(str) +} + +// el-upload的BeforeUpload +function buildBeforeUpload(scheme) { + const config = scheme.__config__ + const unitNum = units[config.sizeUnit]; let rightSizeCode = ''; let acceptCode = ''; const + returnList = [] + if (config.fileSize) { + rightSizeCode = `let isRightSize = file.size / ${unitNum} < ${config.fileSize} + if(!isRightSize){ + this.$message.error('文件大小超过 ${config.fileSize}${config.sizeUnit}') + }` + returnList.push('isRightSize') + } + if (scheme.accept) { + acceptCode = `let isAccept = new RegExp('${scheme.accept}').test(file.type) + if(!isAccept){ + this.$message.error('应该选择${scheme.accept}类型的文件') + }` + returnList.push('isAccept') + } + const str = `${scheme.__vModel__}BeforeUpload(file) { + ${rightSizeCode} + ${acceptCode} + return ${returnList.join('&&')} + },` + return returnList.length ? str : '' +} + +// el-upload的submit +function buildSubmitUpload(scheme) { + const str = `submitUpload() { + this.$refs['${scheme.__vModel__}'].submit() + },` + return str +} + +function buildOptionMethod(methodName, model, methodList, scheme) { + const config = scheme.__config__ + const str = `${methodName}() { + // 注意:this.$axios是通过Vue.prototype.$axios = axios挂载产生的 + this.$axios({ + method: '${config.method}', + url: '${config.url}' + }).then(resp => { + var { data } = resp + this.${model} = data.${config.dataPath} + }) + },` + methodList.push(str) +} + +// js整体拼接 +function buildexport(conf, type, data, rules, selectOptions, uploadVar, props, methods, created) { + const str = `${exportDefault}{ + ${inheritAttrs[type]} + components: {}, + props: [], + data () { + return { + ${conf.formModel}: { + ${data} + }, + ${conf.formRules}: { + ${rules} + }, + ${uploadVar} + ${selectOptions} + ${props} + } + }, + computed: {}, + watch: {}, + created () { + ${created} + }, + mounted () {}, + methods: { + ${methods} + } +}` + return str +} diff --git a/src/components/generator/ruleTrigger.js b/src/components/generator/ruleTrigger.js new file mode 100644 index 00000000..3c161b5d --- /dev/null +++ b/src/components/generator/ruleTrigger.js @@ -0,0 +1,16 @@ +/** + * 用于生成表单校验,指定正则规则的触发方式。 + * 未在此处声明无触发方式的组件将不生成rule!! + */ +export default { + 'el-input': 'blur', + 'el-input-number': 'blur', + 'el-select': 'change', + 'el-radio-group': 'change', + 'el-checkbox-group': 'change', + 'el-cascader': 'change', + 'el-time-picker': 'change', + 'el-date-picker': 'change', + 'el-rate': 'change', + tinymce: 'blur' +} diff --git a/src/components/tinymce/README.md b/src/components/tinymce/README.md new file mode 100644 index 00000000..65c01e21 --- /dev/null +++ b/src/components/tinymce/README.md @@ -0,0 +1,3 @@ +## 简介 +富文本编辑器tinymce的一个vue版本封装。使用cdn动态脚本引入的方式加载。 + diff --git a/src/components/tinymce/config.js b/src/components/tinymce/config.js new file mode 100644 index 00000000..fc615544 --- /dev/null +++ b/src/components/tinymce/config.js @@ -0,0 +1,8 @@ +/* eslint-disable max-len */ + +export const plugins = [ + 'advlist anchor autolink autosave code codesample directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textpattern visualblocks visualchars wordcount' +] +export const toolbar = [ + 'code searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote removeformat subscript superscript codesample hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen' +] diff --git a/src/components/tinymce/example/Index.vue b/src/components/tinymce/example/Index.vue new file mode 100644 index 00000000..e5a9f65d --- /dev/null +++ b/src/components/tinymce/example/Index.vue @@ -0,0 +1,38 @@ + + + diff --git a/src/components/tinymce/index.js b/src/components/tinymce/index.js new file mode 100644 index 00000000..1e831794 --- /dev/null +++ b/src/components/tinymce/index.js @@ -0,0 +1,3 @@ +import Index from './index.vue' + +export default Index diff --git a/src/components/tinymce/index.vue b/src/components/tinymce/index.vue new file mode 100644 index 00000000..2eda1a1c --- /dev/null +++ b/src/components/tinymce/index.vue @@ -0,0 +1,88 @@ +