diff --git a/.env.development b/.env.development index 1edba8c..321b6f9 100644 --- a/.env.development +++ b/.env.development @@ -5,7 +5,7 @@ VUE_APP_TITLE = 金鸡湖现代服务业品牌管理系统 ENV = 'development' # 金鸡湖现代服务业品牌管理系统/开发环境 -VUE_APP_BASE_API = 'http://192.168.0.110:9040' +VUE_APP_BASE_API = 'http://192.168.0.108:9040' # VUE_APP_BASE_API = 'http://39.101.188.84:9040' # VUE_APP_BASE_API = 'https://idp.sipac.gov.cn/api' diff --git a/package.json b/package.json index c4c4a07..593b821 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ruoyi", - "version": "1.0.202407231321", + "version": "1.0.202407240905", "description": "金鸡湖现代服务业品牌管理系统", "author": "若依", "license": "MIT", diff --git a/src/api/onlineDeclartion/declarationManagement.js b/src/api/onlineDeclartion/declarationManagement.js index 2cac525..3af4c9f 100644 --- a/src/api/onlineDeclartion/declarationManagement.js +++ b/src/api/onlineDeclartion/declarationManagement.js @@ -1,5 +1,14 @@ import request from '@/utils/request' +// 新增模板管理列表 +export function templateInfo(data) { + return request({ + url: '/system/templateInfo', + method: 'post', + data + }) +} + // 查询在线申报管理列表 export function listInfo(query) { return request({ diff --git a/src/router/index.js b/src/router/index.js index 1779ddb..e496a0a 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -136,6 +136,12 @@ export const constantRoutes = [ name: 'enterpriselibraryInfo', meta: { title: '企业详情', icon: 'user' } }, + { + path: 'onlineDeclarebBuild', + component: () => import('@/views/tool/build/index'), + name: 'onlineDeclarebBuild', + meta: { title: '表单构建', icon: 'user' } + }, ] } ]; diff --git a/src/utils/index.js b/src/utils/index.js index b582bf1..b5f0669 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -285,6 +285,43 @@ export function deepClone(source) { return targetObj } +// 深拷贝对象 +export function deepCloneTwo(obj) { + const _toString = Object.prototype.toString + + // null, undefined, non-object, function + if (!obj || typeof obj !== 'object') { + return obj + } + + // DOM Node + if (obj.nodeType && 'cloneNode' in obj) { + return obj.cloneNode(true) + } + + // Date + if (_toString.call(obj) === '[object Date]') { + return new Date(obj.getTime()) + } + + // RegExp + if (_toString.call(obj) === '[object RegExp]') { + const flags = [] + if (obj.global) { flags.push('g') } + if (obj.multiline) { flags.push('m') } + if (obj.ignoreCase) { flags.push('i') } + + return new RegExp(obj.source, flags.join('')) + } + + const result = Array.isArray(obj) ? [] : obj.constructor ? new obj.constructor() : {} + + for (const key in obj) { + result[key] = deepCloneTwo(obj[key]) + } + + return result +} /** * @param {Array} arr * @returns {Array} diff --git a/src/views/onlineDeclaration/components/Parser.vue b/src/views/onlineDeclaration/components/Parser.vue new file mode 100644 index 0000000..f8f4cb1 --- /dev/null +++ b/src/views/onlineDeclaration/components/Parser.vue @@ -0,0 +1,186 @@ + diff --git a/src/views/onlineDeclaration/components/render/package.json b/src/views/onlineDeclaration/components/render/package.json new file mode 100644 index 0000000..96bffcf --- /dev/null +++ b/src/views/onlineDeclaration/components/render/package.json @@ -0,0 +1,19 @@ +{ + "name": "form-gen-render", + "version": "1.0.4", + "description": "表单核心render", + "main": "lib/form-gen-render.umd.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/JakHuang/form-generator.git" + }, + "author": "jakhuang", + "license": "MIT", + "bugs": { + "url": "https://github.com/JakHuang/form-generator/issues" + }, + "homepage": "https://github.com/JakHuang/form-generator#readme" +} diff --git a/src/views/onlineDeclaration/components/render/render.js b/src/views/onlineDeclaration/components/render/render.js new file mode 100644 index 0000000..f3325dc --- /dev/null +++ b/src/views/onlineDeclaration/components/render/render.js @@ -0,0 +1,122 @@ +import { deepClone } from '@/utils/index' + +const componentChild = {} +/** + * 将./slots中的文件挂载到对象componentChild上 + * 文件名为key,对应JSON配置中的__config__.tag + * 文件内容为value,解析JSON配置中的__slot__ + */ +const slotsFiles = require.context('./slots', false, /\.js$/) +const keys = slotsFiles.keys() || [] +keys.forEach(key => { + const tag = key.replace(/^\.\/(.*)\.\w+$/, '$1') + const value = slotsFiles(key).default + componentChild[tag] = value +}) + +function vModel(dataObject, defaultValue) { + dataObject.props.value = defaultValue + + dataObject.on.input = val => { + this.$emit('input', val) + } +} + +function mountSlotFiles(h, confClone, children) { + const childObjs = componentChild[confClone.__config__.tag] + if (childObjs) { + Object.keys(childObjs).forEach(key => { + const childFunc = childObjs[key] + if (confClone.__slot__ && confClone.__slot__[key]) { + children.push(childFunc(h, confClone, key)) + } + }) + } +} + +function emitEvents(confClone) { + ['on', 'nativeOn'].forEach(attr => { + const eventKeyList = Object.keys(confClone[attr] || {}) + eventKeyList.forEach(key => { + const val = confClone[attr][key] + if (typeof val === 'string') { + confClone[attr][key] = event => this.$emit(val, event) + } + }) + }) +} + +function buildDataObject(confClone, dataObject) { + Object.keys(confClone).forEach(key => { + const val = confClone[key] + if (key === '__vModel__') { + vModel.call(this, dataObject, confClone.__config__.defaultValue) + } else if (dataObject[key] !== undefined) { + if (dataObject[key] === null + || dataObject[key] instanceof RegExp + || ['boolean', 'string', 'number', 'function'].includes(typeof dataObject[key])) { + dataObject[key] = val + } else if (Array.isArray(dataObject[key])) { + dataObject[key] = [...dataObject[key], ...val] + } else { + dataObject[key] = { ...dataObject[key], ...val } + } + } else { + dataObject.attrs[key] = val + } + }) + + // 清理属性 + clearAttrs(dataObject) +} + +function clearAttrs(dataObject) { + delete dataObject.attrs.__config__ + delete dataObject.attrs.__slot__ + delete dataObject.attrs.__methods__ +} + +function makeDataObject() { + // 深入数据对象: + // https://cn.vuejs.org/v2/guide/render-function.html#%E6%B7%B1%E5%85%A5%E6%95%B0%E6%8D%AE%E5%AF%B9%E8%B1%A1 + return { + class: {}, + attrs: {}, + props: {}, + domProps: {}, + nativeOn: {}, + on: {}, + style: {}, + directives: [], + scopedSlots: {}, + slot: null, + key: null, + ref: null, + refInFor: true + } +} + +export default { + props: { + conf: { + type: Object, + required: true + } + }, + render(h) { + const dataObject = makeDataObject() + const confClone = deepClone(this.conf) + const children = this.$slots.default || [] + + // 如果slots文件夹存在与当前tag同名的文件,则执行文件中的代码 + mountSlotFiles.call(this, h, confClone, children) + + // 将字符串类型的事件,发送为消息 + emitEvents.call(this, confClone) + + // 将json表单配置转化为vue render可以识别的 “数据对象(dataObject)” + buildDataObject.call(this, confClone, dataObject) + + return h(this.conf.__config__.tag, dataObject, children) + } +} diff --git a/src/views/onlineDeclaration/components/render/slots/el-button.js b/src/views/onlineDeclaration/components/render/slots/el-button.js new file mode 100644 index 0000000..a2d9684 --- /dev/null +++ b/src/views/onlineDeclaration/components/render/slots/el-button.js @@ -0,0 +1,5 @@ +export default { + default(h, conf, key) { + return conf.__slot__[key] + } +} diff --git a/src/views/onlineDeclaration/components/render/slots/el-checkbox-group.js b/src/views/onlineDeclaration/components/render/slots/el-checkbox-group.js new file mode 100644 index 0000000..0a85c8e --- /dev/null +++ b/src/views/onlineDeclaration/components/render/slots/el-checkbox-group.js @@ -0,0 +1,13 @@ +export default { + options(h, conf, key) { + const list = [] + conf.__slot__.options.forEach(item => { + if (conf.__config__.optionType === 'button') { + list.push({item.label}) + } else { + list.push({item.label}) + } + }) + return list + } +} diff --git a/src/views/onlineDeclaration/components/render/slots/el-input.js b/src/views/onlineDeclaration/components/render/slots/el-input.js new file mode 100644 index 0000000..8bd02db --- /dev/null +++ b/src/views/onlineDeclaration/components/render/slots/el-input.js @@ -0,0 +1,8 @@ +export default { + prepend(h, conf, key) { + return + }, + append(h, conf, key) { + return + } +} diff --git a/src/views/onlineDeclaration/components/render/slots/el-radio-group.js b/src/views/onlineDeclaration/components/render/slots/el-radio-group.js new file mode 100644 index 0000000..c78506f --- /dev/null +++ b/src/views/onlineDeclaration/components/render/slots/el-radio-group.js @@ -0,0 +1,13 @@ +export default { + options(h, conf, key) { + const list = [] + conf.__slot__.options.forEach(item => { + if (conf.__config__.optionType === 'button') { + list.push({item.label}) + } else { + list.push({item.label}) + } + }) + return list + } +} diff --git a/src/views/onlineDeclaration/components/render/slots/el-select.js b/src/views/onlineDeclaration/components/render/slots/el-select.js new file mode 100644 index 0000000..cbf4a20 --- /dev/null +++ b/src/views/onlineDeclaration/components/render/slots/el-select.js @@ -0,0 +1,9 @@ +export default { + options(h, conf, key) { + const list = [] + conf.__slot__.options.forEach(item => { + list.push() + }) + return list + } +} diff --git a/src/views/onlineDeclaration/components/render/slots/el-upload.js b/src/views/onlineDeclaration/components/render/slots/el-upload.js new file mode 100644 index 0000000..8ce3c35 --- /dev/null +++ b/src/views/onlineDeclaration/components/render/slots/el-upload.js @@ -0,0 +1,17 @@ +export default { + 'list-type': (h, conf, key) => { + const list = [] + const config = conf.__config__ + if (conf['list-type'] === 'picture-card') { + list.push() + } else { + list.push({config.buttonText}) + } + if (config.showTip) { + list.push( +
只能上传不超过 {config.fileSize}{config.sizeUnit} 的{conf.accept}文件
+ ) + } + return list + } +} diff --git a/src/views/onlineDeclaration/template/index.vue b/src/views/onlineDeclaration/template/index.vue index 3b8492f..0dac5f9 100644 --- a/src/views/onlineDeclaration/template/index.vue +++ b/src/views/onlineDeclaration/template/index.vue @@ -1,75 +1,42 @@ @@ -150,6 +221,8 @@ import drawingDefault from '@/utils/generator/drawingDefault' import logo from '@/assets/logo/logo.png' import CodeTypeDialog from './CodeTypeDialog' import DraggableItem from './DraggableItem' +import { templateInfo } from "@/api/onlineDeclartion/declarationManagement" +import { getAllList } from "@/api/system/dict/data"; let oldActiveId let tempActiveData @@ -162,7 +235,15 @@ export default { CodeTypeDialog, DraggableItem }, + dicts: ['bms_responsibility_unit', 'bms_level'], data() { + let validateTime = (rule, value, callback) => { + if (new Date(value[1]) < new Date()) { + callback(new Error('选择结束时间需大于当前时间')) + } else { + callback() + } + } return { logo, idGlobal: 100, @@ -179,7 +260,55 @@ export default { dialogVisible: false, generateConf: null, showFileName: false, - activeData: drawingDefault[0] + activeData: drawingDefault[0], + options: [], + props:{ + lazy:true, + lazyLoad (node, resolve) { + const { level, data, children } = node; + if(children?.length == 0 ) { + getAllList({dictType: data.dict}).then(res=>{ + const nodes = Array.from(res.data).map((item)=>{ + return { + value:item.dictValue, + label:item.dictLabel, + dict:item.remark, + leaf: level >= 2 + } + }) + resolve(nodes) + }) + } + } + }, + // 表单参数 + dialogForm: {}, + // 表单校验 + rules: { + // year: [ + // { required: true, message: "请选择年份", trigger: "blur" }, + // ], + responsibilityUnit: [ + { required: true, message: "请选择责任单位", trigger: "blur" } + ], + level: [ + { required: true, message: "请选择级别", trigger: "blur" } + ], + projectClassify: [ + { required: true, message: "请选择项目分类", trigger: "blur" } + ], + templateName: [ + { required: true, message: "请输入模板名称", trigger: "blur" } + ], + reportTime: [ + { required: true, message: "请选择模板使用有效期", trigger: "blur" }, + {validator: validateTime, trigger: 'blur'}, + ], + }, + projectBigType: undefined, + projectMiddleType: undefined, + projectSmallType: undefined, + createTemplate: true, } }, created() { @@ -223,8 +352,61 @@ export default { clipboard.on('error', e => { this.$message.error('代码复制失败') }) + this.getDataList(); }, methods: { + getDataList(){ + getAllList({dictType:"project_categories"}).then(res=>{ + res.data.map(item => { + let obj = {}; + obj.value = item.dictValue; + obj.label = item.dictLabel; + obj.dict = item.remark; + this.options.push(obj); + }) + }) + }, + // 项目分类选择 + changeProjectClassify(valId){ + if(valId) { + this.projectBigType = valId[0] + this.projectMiddleType = valId[1] + this.projectSmallType = valId[2] + } + }, + // 模板有效期选择 + changeDateRange(val) { + // console.log('val: ', val); + this.dialogForm.useStart = val[0] + this.dialogForm.useEnd = val[1] + }, + // 取消按钮 + cancel() { + this.createTemplate = false; + this.reset(); + }, + // 表单重置 + reset() { + this.dialogForm = { + responsibilityUnit: undefined, + templateName: undefined, + level: undefined, + projectClassify:[], + reportTime: [], + }; + this.projectBigType = undefined + this.projectMiddleType = undefined + this.projectSmallType = undefined + this.resetForm("form"); + }, + /** 提交按钮 */ + submitForm: function() { + this.$refs["form"].validate(valid => { + if (valid) { + this.createTemplate = false; + } + }); + }, activeFormItem(element) { this.activeData = element this.activeId = element.formId @@ -324,6 +506,24 @@ export default { const css = cssStyle(makeUpCss(this.formData)) return beautifier.html(html + script + css, beautifierConf.html) }, + showJson() { + this.AssembleFormData() + // 级别,责任单位,模板使用有效期开始时间,模板使用有效期结束时间,模板名称 + const { level, responsibilityUnit, useStart, useEnd, templateName } = this.dialogForm; + if(level && responsibilityUnit && useStart && useEnd && templateName) { + templateInfo({level, responsibilityUnit, templateName, useStart, useEnd, projectBigType:this.projectBigType, projectMiddleType:this.projectMiddleType, projectSmallType:this.projectSmallType,templateJson: JSON.stringify(this.formData)}).then(res=>{ + if(res.code == 200) { + this.$router.push({ + name: 'Template', + params: {code:200}, + }) + } + }) + + } else { + this.createTemplate = true; + } + }, download() { this.dialogVisible = true this.showFileName = true