├── .eslintignore ├── src ├── demo-common │ ├── bootstrap.js │ ├── components │ │ ├── iView │ │ │ ├── styles │ │ │ │ └── fonts │ │ │ │ │ ├── ionicons.ttf │ │ │ │ │ ├── ionicons.woff │ │ │ │ │ └── ionicons.woff2 │ │ │ └── index.js │ │ ├── ElementUi │ │ │ ├── theme │ │ │ │ └── fonts │ │ │ │ │ ├── element-icons.ttf │ │ │ │ │ └── element-icons.woff │ │ │ └── index.js │ │ ├── ElementPlus │ │ │ ├── theme │ │ │ │ └── fonts │ │ │ │ │ ├── element-icons.ttf │ │ │ │ │ └── element-icons.woff │ │ │ └── index.js │ │ ├── Antdv │ │ │ └── index.js │ │ ├── JsonPerttyPrint.vue │ │ ├── EditorHeader.vue │ │ ├── Menu.vue │ │ ├── component-with-dialog │ │ │ └── index.js │ │ ├── CodeEditorV2.vue │ │ └── CodeEditor.vue │ ├── utils │ │ ├── obj.js │ │ ├── id.js │ │ ├── url.js │ │ └── array.js │ ├── schemaTypes │ │ ├── 90.Test │ │ │ └── index.js │ │ ├── index.js │ │ ├── 25.hidden(隐藏表单项) │ │ │ └── index.js │ │ ├── 21.Upload │ │ │ └── index.js │ │ ├── 24.uiSchema(表达式) │ │ │ └── index.js │ │ ├── 16.References │ │ │ └── index.js │ │ ├── 20.Date-DateTime │ │ │ └── index.js │ │ ├── 14.Number │ │ │ └── index.js │ │ ├── 12.Nested │ │ │ └── index.js │ │ ├── 41.Object-property-dependencies(联动) │ │ │ └── index.js │ │ ├── 19.AllOf │ │ │ └── index.js │ │ ├── 11.Simple │ │ │ └── index.js │ │ ├── 18.AnyOf(联动) │ │ │ └── index.js │ │ ├── 42.uiSchema-ui-hidden(联动) │ │ │ └── index.js │ │ ├── 15.Widgets │ │ │ └── index.js │ │ ├── 17.OneOf │ │ │ └── index.js │ │ └── 13.Arrays │ │ │ └── index.js │ ├── .eslintrc.js │ └── css │ │ ├── bootstrap.css │ │ └── variable.css └── pages │ └── vue-editor │ ├── views │ └── editor │ │ ├── viewComponents │ │ ├── _commonConfig │ │ │ ├── readme.md │ │ │ ├── error │ │ │ │ └── genImgItem.js │ │ │ └── ui │ │ │ │ └── genImgItem.js │ │ ├── Coupon │ │ │ ├── uiSchema.json │ │ │ ├── index.js │ │ │ ├── Coupon.json │ │ │ └── component │ │ │ │ └── View.vue │ │ ├── RecommendedGoodsList │ │ │ ├── uiSchema.json │ │ │ ├── index.js │ │ │ ├── RecommendedGoodsList.json │ │ │ └── component │ │ │ │ └── View.vue │ │ ├── MultipleImg5 │ │ │ ├── uiSchema.js │ │ │ ├── errorSchema.js │ │ │ ├── index.js │ │ │ ├── schema.json │ │ │ └── View.vue │ │ ├── AllGoodsList │ │ │ ├── index.js │ │ │ ├── AllGoodsList.json │ │ │ └── component │ │ │ │ └── View.vue │ │ ├── CategoryGoods │ │ │ ├── index.js │ │ │ ├── uiSchema.js │ │ │ ├── schema.json │ │ │ └── View.vue │ │ ├── Text │ │ │ ├── index.js │ │ │ ├── View.vue │ │ │ ├── uiSchema.js │ │ │ └── propsSchema.js │ │ ├── CarouselImg │ │ │ ├── errSchema.js │ │ │ ├── index.js │ │ │ ├── uiSchema.js │ │ │ ├── CarouselImg.json │ │ │ └── View.vue │ │ ├── FlashSaleGoodsList │ │ │ ├── index.js │ │ │ ├── uiSchema.js │ │ │ └── schema.json │ │ ├── MultipleImg2_3 │ │ │ ├── index.js │ │ │ ├── errorSchema.js │ │ │ ├── uiSchema.js │ │ │ ├── schema.json │ │ │ └── View.vue │ │ └── MultipleImg1_3 │ │ │ ├── errorSchema.js │ │ │ ├── index.js │ │ │ ├── uiSchema.js │ │ │ ├── schema.json │ │ │ └── component │ │ │ └── View.vue │ │ ├── assets │ │ └── img │ │ │ └── empty-tip.png │ │ ├── viewComponentsM │ │ ├── Test │ │ │ ├── index.js │ │ │ ├── View.vue │ │ │ └── Form.vue │ │ ├── CategoryList │ │ │ ├── index.js │ │ │ ├── propsSchema.json │ │ │ └── View.vue │ │ ├── RecommendGoods │ │ │ ├── index.js │ │ │ ├── propsSchema.json │ │ │ └── View.vue │ │ ├── Text │ │ │ ├── uiSchema.js │ │ │ ├── index.js │ │ │ ├── propsSchema.json │ │ │ └── View.vue │ │ └── CarouselImg │ │ │ ├── index.js │ │ │ ├── uiSchema.js │ │ │ ├── CarouselImg.json │ │ │ └── View.vue │ │ ├── common │ │ ├── registerExtraElementComponent.js │ │ ├── editorData.js │ │ └── utils.js │ │ ├── data.js │ │ ├── components │ │ ├── skeleton │ │ │ ├── Skeleton.vue │ │ │ ├── SkeletonGoods.vue │ │ │ └── skeleton.css │ │ └── GoodsListView.vue │ │ ├── config │ │ ├── mTools.js │ │ ├── tools.js │ │ └── mDefaultItems.js │ │ ├── EditorHeader.vue │ │ └── EditorToolBar.vue │ ├── App.vue │ ├── router │ ├── index.js │ ├── routes │ │ └── index.js │ └── guards.js │ ├── vue-editor.css │ ├── vue-editor.js │ └── vue-editor.html ├── .gitignore ├── scripts ├── utils.js ├── log.js ├── envConfig.js └── entry.js ├── babel.config.js ├── postcss.config.js ├── .eslintrc.js ├── LICENSE ├── README.md ├── package.json └── vue.config.js /.eslintignore: -------------------------------------------------------------------------------- 1 | /**/node_modules/* 2 | /**/dist/* 3 | -------------------------------------------------------------------------------- /src/demo-common/bootstrap.js: -------------------------------------------------------------------------------- 1 | import './css/bootstrap.css'; 2 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/_commonConfig/readme.md: -------------------------------------------------------------------------------- 1 | 通用的配置文件 2 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/Coupon/uiSchema.json: -------------------------------------------------------------------------------- 1 | { 2 | "show": { 3 | "ui:options": { 4 | 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/RecommendedGoodsList/uiSchema.json: -------------------------------------------------------------------------------- 1 | { 2 | "show": { 3 | "ui:options": { 4 | 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/demo-common/components/iView/styles/fonts/ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lljj-x/vjsf-demo-editor/HEAD/src/demo-common/components/iView/styles/fonts/ionicons.ttf -------------------------------------------------------------------------------- /src/demo-common/components/iView/styles/fonts/ionicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lljj-x/vjsf-demo-editor/HEAD/src/demo-common/components/iView/styles/fonts/ionicons.woff -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/assets/img/empty-tip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lljj-x/vjsf-demo-editor/HEAD/src/pages/vue-editor/views/editor/assets/img/empty-tip.png -------------------------------------------------------------------------------- /src/demo-common/components/iView/styles/fonts/ionicons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lljj-x/vjsf-demo-editor/HEAD/src/demo-common/components/iView/styles/fonts/ionicons.woff2 -------------------------------------------------------------------------------- /src/demo-common/components/ElementUi/theme/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lljj-x/vjsf-demo-editor/HEAD/src/demo-common/components/ElementUi/theme/fonts/element-icons.ttf -------------------------------------------------------------------------------- /src/demo-common/components/ElementUi/theme/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lljj-x/vjsf-demo-editor/HEAD/src/demo-common/components/ElementUi/theme/fonts/element-icons.woff -------------------------------------------------------------------------------- /src/demo-common/components/ElementPlus/theme/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lljj-x/vjsf-demo-editor/HEAD/src/demo-common/components/ElementPlus/theme/fonts/element-icons.ttf -------------------------------------------------------------------------------- /src/demo-common/components/ElementPlus/theme/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lljj-x/vjsf-demo-editor/HEAD/src/demo-common/components/ElementPlus/theme/fonts/element-icons.woff -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponentsM/Test/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/9/29 19:01. 3 | */ 4 | 5 | import Form from './Form'; 6 | import View from './View'; 7 | 8 | export default { 9 | View, 10 | Form, // 自定义Form 11 | }; 12 | -------------------------------------------------------------------------------- /src/pages/vue-editor/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 17 | -------------------------------------------------------------------------------- /src/demo-common/components/iView/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/12/28 12:07. 3 | */ 4 | 5 | import './styles/iview.css'; 6 | import iView from 'iview'; 7 | 8 | export default { 9 | install(Vue) { 10 | // debugger; 11 | Vue.use(iView); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/MultipleImg5/uiSchema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/4/30 17:13. 3 | */ 4 | 5 | import genImgItem from '../_commonConfig/ui/genImgItem'; 6 | 7 | export default { 8 | imgList: { 9 | items: genImgItem() 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/MultipleImg5/errorSchema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/4/30 17:40. 3 | */ 4 | 5 | import genImgItem from '../_commonConfig/error/genImgItem'; 6 | 7 | export default { 8 | imgList: { 9 | items: genImgItem() 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/Coupon/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/12/4 15:06. 3 | */ 4 | 5 | import propsSchema from './Coupon.json'; 6 | 7 | const View = () => import('./component/View.vue'); 8 | 9 | export default { 10 | View, 11 | propsSchema 12 | }; 13 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponentsM/CategoryList/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/12/4 15:06. 3 | */ 4 | 5 | import propsSchema from './propsSchema.json'; 6 | 7 | const View = () => import('./View.vue'); 8 | 9 | export default { 10 | View, 11 | propsSchema 12 | }; 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | 4 | # local env files 5 | .env.local 6 | .env.*.local 7 | 8 | # Log files 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | 13 | # Editor directories and files 14 | .idea 15 | .vscode 16 | *.suo 17 | *.ntvs* 18 | *.njsproj 19 | *.sln 20 | *.sw? 21 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponentsM/RecommendGoods/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/12/4 15:06. 3 | */ 4 | 5 | import propsSchema from './propsSchema.json'; 6 | 7 | const View = () => import('./View.vue'); 8 | 9 | export default { 10 | View, 11 | propsSchema 12 | }; 13 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/AllGoodsList/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/12/4 15:06. 3 | */ 4 | 5 | import propsSchema from './AllGoodsList.json'; 6 | 7 | const View = () => import('./component/View.vue'); 8 | 9 | export default { 10 | View, 11 | propsSchema 12 | }; 13 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponentsM/Text/uiSchema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/7/25 11:25. 3 | */ 4 | 5 | export default { 6 | txt: { 7 | 'ui:placeholder': '输入你的内容' 8 | }, 9 | txtColor: { 10 | 'ui:widget': 'el-color-picker' 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /src/demo-common/utils/obj.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/11/22 9:48 下午. 3 | */ 4 | 5 | export function isEmptyObject(obj) { 6 | for (const key in obj) { 7 | if (Object.prototype.hasOwnProperty.call(obj, key)) { 8 | return false; 9 | } 10 | } 11 | return true; 12 | } 13 | -------------------------------------------------------------------------------- /src/demo-common/schemaTypes/90.Test/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/7/22 11:07 下午. 3 | */ 4 | 5 | export default { 6 | schema: { 7 | title: '测试专用页', 8 | type: 'object', 9 | description: '输入你的Schema,顶部分享按钮即可快速生成链接', 10 | properties: { 11 | } 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /scripts/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/11/27 9:57. 3 | */ 4 | 5 | exports.getSingle = function getSingle(fn) { 6 | let result; 7 | return function proxySingle(...args) { 8 | if (!result) { 9 | result = fn.apply(this, args); 10 | } 11 | return result; 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/RecommendedGoodsList/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/04/28 14:24. 3 | */ 4 | 5 | import propsSchema from './RecommendedGoodsList.json'; 6 | 7 | const View = () => import('./component/View.vue'); 8 | 9 | export default { 10 | View, 11 | propsSchema 12 | }; 13 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/CategoryGoods/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/7/25 15:23. 3 | */ 4 | 5 | import propsSchema from './schema.json'; 6 | import uiSchema from './uiSchema'; 7 | 8 | const View = () => import('./View.vue'); 9 | 10 | export default { 11 | View, 12 | propsSchema, 13 | uiSchema 14 | }; 15 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/Text/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/9/29 19:01. 3 | */ 4 | 5 | import propsSchema from './propsSchema.js'; 6 | import uiSchema from './uiSchema.js'; 7 | 8 | const View = () => import('./View.vue'); 9 | 10 | export default { 11 | View, 12 | propsSchema, 13 | uiSchema 14 | }; 15 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponentsM/Text/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/9/29 19:01. 3 | */ 4 | 5 | import propsSchema from './propsSchema.json'; 6 | import uiSchema from './uiSchema.js'; 7 | 8 | const View = () => import('./View.vue'); 9 | 10 | export default { 11 | View, 12 | propsSchema, 13 | uiSchema 14 | }; 15 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/CarouselImg/errSchema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/7/24 10:00 下午. 3 | */ 4 | export default { 5 | imgList: { 6 | items: { 7 | imgLink: { 8 | 'err:format': '请输入正确的的链接地址', 9 | 'err:required': '不能为空' 10 | } 11 | } 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/FlashSaleGoodsList/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/12/4 15:06. 3 | */ 4 | 5 | import propsSchema from './schema.json'; 6 | import uiSchema from './uiSchema.js'; 7 | 8 | const View = () => import('./View.vue'); 9 | 10 | export default { 11 | View, 12 | propsSchema, 13 | uiSchema 14 | }; 15 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponentsM/CarouselImg/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/12/4 15:06. 3 | */ 4 | 5 | import propsSchema from './CarouselImg.json'; 6 | import uiSchema from './uiSchema.js'; 7 | 8 | const View = () => import('./View.vue'); 9 | 10 | export default { 11 | View, 12 | propsSchema, 13 | uiSchema 14 | }; 15 | -------------------------------------------------------------------------------- /src/demo-common/components/Antdv/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2021/2/1 10:00 下午. 3 | */ 4 | 5 | import Antd from 'ant-design-vue'; 6 | 7 | // eslint-disable-next-line import/no-webpack-loader-syntax 8 | import '!vue-style-loader!css-loader!ant-design-vue/dist/antd.css'; 9 | 10 | export default { 11 | install(app) { 12 | app.use(Antd); 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | // '@babel/plugin-proposal-export-default-from' 4 | ], 5 | presets: [ 6 | [ 7 | '@lljj/babel-preset-app', 8 | { 9 | useBuiltIns: false, 10 | regenerator: true, 11 | helpers: true 12 | } 13 | ] 14 | ] 15 | }; 16 | -------------------------------------------------------------------------------- /src/pages/vue-editor/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueRouter from 'VueRouter'; 3 | import routes from './routes/index.js'; 4 | 5 | Vue.use(VueRouter); 6 | 7 | /** 8 | * 路由入口 9 | * 10 | */ 11 | export default new VueRouter({ 12 | mode: 'hash', 13 | routes: [...routes], 14 | scrollBehavior() { 15 | return { x: 0, y: 0 }; 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('postcss-import')({ 4 | path: ['src/'] 5 | }), 6 | require('postcss-mixins'), 7 | require('postcss-nested'), 8 | require('postcss-color-mod-function'), 9 | require('postcss-cssnext')({ 10 | warnForDuplicates: false, 11 | }), 12 | ] 13 | }; 14 | -------------------------------------------------------------------------------- /scripts/log.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/11/27 13:57. 3 | */ 4 | 5 | const envConfig = require('./envConfig').getConfig(); 6 | 7 | module.exports = function fn({ data, des }) { 8 | if (envConfig.log) { 9 | console.log(`\n---------- ↓↓↓↓ ${des || ''} ↓↓↓↓ ----------`); 10 | console.log(data); 11 | console.log(`---------- ↑↑↑↑ ${des || ''} ↑↑↑↑ ----------\n`); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/CarouselImg/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/12/4 15:06. 3 | */ 4 | 5 | import propsSchema from './CarouselImg.json'; 6 | import uiSchema from './uiSchema.js'; 7 | import errorSchema from './errSchema.js'; 8 | 9 | const View = () => import('./View.vue'); 10 | 11 | export default { 12 | View, 13 | propsSchema, 14 | uiSchema, 15 | errorSchema 16 | }; 17 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/MultipleImg2_3/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/12/4 15:06. 3 | */ 4 | 5 | import propsSchema from './schema.json'; 6 | import uiSchema from './uiSchema.js'; 7 | import errorSchema from './errorSchema.js'; 8 | 9 | const View = () => import('./View.vue'); 10 | 11 | export default { 12 | View, 13 | propsSchema, 14 | uiSchema, 15 | errorSchema 16 | }; 17 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/MultipleImg5/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/12/4 15:06. 3 | */ 4 | 5 | import propsSchema from './schema.json'; 6 | import uiSchema from './uiSchema.js'; 7 | import errorSchema from './errorSchema.js'; 8 | 9 | const View = () => import('./View.vue'); 10 | 11 | export default { 12 | View, 13 | propsSchema, 14 | uiSchema, 15 | errorSchema 16 | }; 17 | -------------------------------------------------------------------------------- /src/demo-common/schemaTypes/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/5/13 9:06 下午. 3 | */ 4 | 5 | const files = require.context('.', true, /\.js$/); 6 | 7 | const modules = files.keys().reduce((preVal, curKey) => { 8 | if (curKey !== './index.js') { 9 | preVal[curKey.replace(/(\.\/\d+\.|\/index\.js)/g, '')] = files(curKey).default; 10 | } 11 | return preVal; 12 | }, {}); 13 | 14 | export default modules; 15 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/MultipleImg1_3/errorSchema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/4/30 17:40. 3 | */ 4 | 5 | import genImgItem from '../_commonConfig/error/genImgItem'; 6 | 7 | const errorItemSchema = genImgItem(); 8 | 9 | export default { 10 | imgItem1_1: errorItemSchema, 11 | imgItem2_1: errorItemSchema, 12 | imgItem2_2: errorItemSchema, 13 | imgItem2_3: errorItemSchema 14 | }; 15 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/common/registerExtraElementComponent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/4/24 10:59. 3 | */ 4 | 5 | import Vue from 'vue'; 6 | 7 | const ExtraComponents = { 8 | // 需要额外注册的 Field,通过图片选择图片加链接 9 | LinkImgField: () => import('../fieldComponents/linkImgField/LinkImgField') 10 | }; 11 | 12 | Object.entries(ExtraComponents).forEach(([key, value]) => { 13 | Vue.component(key, value); 14 | }); 15 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/MultipleImg1_3/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/12/4 15:06. 3 | */ 4 | 5 | import propsSchema from './schema.json'; 6 | import uiSchema from './uiSchema.js'; 7 | import errorSchema from './errorSchema.js'; 8 | 9 | const View = () => import('./component/View.vue'); 10 | 11 | export default { 12 | View, 13 | propsSchema, 14 | uiSchema, 15 | errorSchema 16 | }; 17 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/MultipleImg2_3/errorSchema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/4/30 17:40. 3 | */ 4 | 5 | import genImgItem from '../_commonConfig/error/genImgItem'; 6 | 7 | const errorItemSchema = genImgItem(); 8 | 9 | export default { 10 | imgItem1_1: errorItemSchema, 11 | imgItem1_2: errorItemSchema, 12 | imgItem2_1: errorItemSchema, 13 | imgItem2_2: errorItemSchema, 14 | imgItem2_3: errorItemSchema 15 | }; 16 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/_commonConfig/error/genImgItem.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/4/30 17:04. 3 | */ 4 | 5 | // errorSchema imgItem 6 | export default function () { 7 | return { 8 | imgUrl: { 9 | 'err:format': '请正常选择图片', 10 | 'err:required': '请选择你要配置的图片' 11 | }, 12 | imgLink: { 13 | 'err:format': '请输入合法的链接地址', 14 | 'err:required': '请输入合法的链接地址' 15 | } 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/Coupon/Coupon.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "properties": { 5 | "show": { 6 | "title": "显示状态", 7 | "description": "优惠券模块不可编辑,系统会自动抓取您已经创建的优惠券,按照优惠券力度由大到小进行排列 。", 8 | "type": "boolean", 9 | "default": true, 10 | "ui:disabled": true 11 | } 12 | }, 13 | "required": [ 14 | "show" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /src/pages/vue-editor/router/routes/index.js: -------------------------------------------------------------------------------- 1 | const routes = [ 2 | { 3 | path: '/editor', 4 | name: 'editor', 5 | component: () => import('../../views/editor/Editor.vue'), 6 | }, 7 | { 8 | path: '/editor-m', 9 | name: 'editorM', 10 | component: () => import('../../views/editor/EditorM.vue'), 11 | }, 12 | { 13 | path: '*', 14 | hidden: true, 15 | redirect: { name: 'editor' } 16 | } 17 | ]; 18 | 19 | export default routes; 20 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/AllGoodsList/AllGoodsList.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "properties": { 5 | "show": { 6 | "type": "boolean", 7 | "title": "添加全部商品", 8 | "description": "全部商品模块不可编辑,不可移除,自动置底;系统会获取全部商品。", 9 | "default": true, 10 | "ui:label": true, 11 | "ui:disabled": true 12 | } 13 | }, 14 | "required": [ 15 | "show" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/RecommendedGoodsList/RecommendedGoodsList.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "properties": { 5 | "show": { 6 | "title": "添加推荐商品", 7 | "description": "推荐商品模块不可编辑,系统自动基于大数据做商品推荐", 8 | "type": "boolean", 9 | "default": true, 10 | "ui:label": true, 11 | "ui:disabled": true 12 | } 13 | }, 14 | "required": [ 15 | "show" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponentsM/Text/propsSchema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "单文本输入组件", 4 | "description":"单文本输入组件,用于在页面配置一条文字信息" , 5 | "type": "object", 6 | "required": ["txt"], 7 | "properties": { 8 | "txt": { 9 | "title": "文字", 10 | "type": "string" 11 | }, 12 | "txtColor": { 13 | "title": "选择文字颜色", 14 | "type": "string", 15 | "default": "#ff0132" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/pages/vue-editor/vue-editor.css: -------------------------------------------------------------------------------- 1 | @import "demo-common/css/variable.css"; 2 | 3 | body{ 4 | background: #FFFFFF; 5 | box-sizing: border-box; 6 | } 7 | div, ul, li{ 8 | box-sizing: border-box; 9 | } 10 | .hover-animation { 11 | transition: opacity .3s ease-out; 12 | &:hover { 13 | opacity: .7; 14 | } 15 | } 16 | 17 | .module-name-tip { 18 | position: absolute; 19 | top: 0; 20 | right: 0; 21 | font-size: 16px; 22 | padding: 8px 15px; 23 | background: rgba(0,0,0,0.8); 24 | color: #FFFFFF; 25 | } 26 | -------------------------------------------------------------------------------- /src/demo-common/utils/id.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/4/28 18:06. 3 | */ 4 | 5 | 6 | // 只保证同时生成不重复 7 | export default function genIdFn() { 8 | let preKey = `${+new Date()}`; 9 | let key = 0; 10 | return () => { 11 | const curTimestamp = `${+new Date()}`; 12 | if (curTimestamp === preKey) { 13 | key += 1; 14 | } else { 15 | // 重置 key 16 | key = 0; 17 | } 18 | 19 | preKey = curTimestamp; 20 | return `${preKey}x${key}`; 21 | }; 22 | } 23 | 24 | export const genId = genIdFn(); 25 | -------------------------------------------------------------------------------- /src/pages/vue-editor/vue-editor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/9/29 15:29. 3 | */ 4 | 5 | // bootstrap 6 | import 'demo-common/bootstrap.js'; 7 | import Vue from 'vue'; 8 | import elementUI from 'demo-common/components/ElementUi/index.js'; 9 | 10 | import './vue-editor.css'; 11 | import router from './router'; 12 | import routerGuards from './router/guards'; 13 | import App from './App'; 14 | 15 | // Ui 16 | Vue.use(elementUI); 17 | 18 | // 添加路由守卫 19 | routerGuards(router); // 路由守卫 20 | 21 | new Vue({ 22 | router, 23 | render: h => h(App) 24 | }).$mount('#app'); 25 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/AllGoodsList/component/View.vue: -------------------------------------------------------------------------------- 1 | 8 | 24 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/RecommendedGoodsList/component/View.vue: -------------------------------------------------------------------------------- 1 | 8 | 24 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/_commonConfig/ui/genImgItem.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/4/30 17:04. 3 | */ 4 | 5 | // uiSchema imgItem 6 | export default function ({ 7 | field = 'LinkImgField', 8 | width = 580, 9 | height = 580, 10 | } = { }) { 11 | return { 12 | 'ui:field': field, 13 | // 'ui:description': `宽度${width}px,高度${height}x。支持JPG、PNG 图片格式,大小不得超过 2 MB。
`, 14 | 'ui:options': { 15 | type: ['jpg', 'jpeg', 'png'], 16 | size: 2048, 17 | width, 18 | height, 19 | limit: 1 20 | } 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/CarouselImg/uiSchema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/4/30 17:13. 3 | */ 4 | 5 | import genImgItem from '../_commonConfig/ui/genImgItem'; 6 | 7 | export default { 8 | imgList: { 9 | 'ui:options': { 10 | title: '添加图片', 11 | description: '图片宽度1920px,高度固定500px。这里使用默认的field和校验提示', 12 | showIndexNumber: true 13 | }, 14 | items: { 15 | ...genImgItem({ 16 | width: 1920, 17 | height: 500, 18 | }), 19 | 'ui:title': '轮播图片配置' 20 | } 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /src/demo-common/components/ElementUi/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/11/20 9:43. 3 | */ 4 | 5 | import './theme/index.css'; 6 | import ELEMENT from 'ELEMENT'; 7 | 8 | const { 9 | Loading, 10 | MessageBox, 11 | Message 12 | } = ELEMENT; 13 | 14 | export default { 15 | install(Vue) { 16 | Vue.use(Loading.directive); 17 | // 原型方法 18 | Vue.prototype.$loading = Loading.service; 19 | Vue.prototype.$alert = MessageBox.alert; 20 | Vue.prototype.$confirm = MessageBox.confirm; 21 | Vue.prototype.$prompt = MessageBox.prompt; 22 | Vue.prototype.$msgbox = MessageBox; 23 | Vue.prototype.$message = Message; 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponentsM/Test/View.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 20 | 21 | 32 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = { 4 | root: true, 5 | env: { 6 | browser: true, 7 | worker: true, 8 | }, 9 | parserOptions: { 10 | parser: 'babel-eslint', 11 | sourceType: 'module' 12 | }, 13 | plugins: ['vue'], 14 | extends: [ 15 | '@lljj/eslint-config', 16 | '@lljj/eslint-config/vue' 17 | ], 18 | rules: { 19 | // 递归组件导致了循环依赖 20 | 'import/no-cycle': 'off', 21 | }, 22 | globals: { 23 | 'self': true 24 | }, 25 | overrides: [ 26 | { 27 | files: ["*.vue"], 28 | rules: { 29 | "indent": "off", 30 | } 31 | } 32 | ] 33 | }; 34 | -------------------------------------------------------------------------------- /src/demo-common/.eslintrc.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = { 4 | root: true, 5 | env: { 6 | browser: true, 7 | worker: true, 8 | }, 9 | parserOptions: { 10 | parser: 'babel-eslint', 11 | sourceType: 'module' 12 | }, 13 | plugins: ['vue'], 14 | extends: [ 15 | '@lljj/eslint-config', 16 | '@lljj/eslint-config/vue' 17 | ], 18 | rules: { 19 | // 递归组件导致了循环依赖 20 | 'import/no-cycle': 'off', 21 | }, 22 | globals: { 23 | 'self': true 24 | }, 25 | overrides: [ 26 | { 27 | files: ["*.vue"], 28 | rules: { 29 | "indent": "off", 30 | } 31 | } 32 | ] 33 | }; 34 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/MultipleImg1_3/uiSchema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/4/30 17:13. 3 | */ 4 | 5 | import genImgItem from '../_commonConfig/ui/genImgItem'; 6 | 7 | const line2Item = genImgItem({ 8 | width: 383, 9 | height: 500, 10 | }); 11 | 12 | export default { 13 | imgItem1_1: { 14 | 'ui:title': '图片上', 15 | ...genImgItem({ 16 | width: 1920, 17 | height: 420, 18 | }) 19 | }, 20 | imgItem2_1: { 21 | 'ui:title': '图片下左', 22 | ...line2Item 23 | }, 24 | imgItem2_2: { 25 | 'ui:title': '图片下中', 26 | ...line2Item 27 | }, 28 | imgItem2_3: { 29 | 'ui:title': '图片下右', 30 | ...line2Item 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponentsM/CarouselImg/uiSchema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/4/30 17:13. 3 | */ 4 | 5 | import genImgItem from '../../viewComponents/_commonConfig/ui/genImgItem'; 6 | 7 | export default { 8 | imgList: { 9 | 'ui:options': { 10 | title: '添加图片', 11 | description: '图片宽度750px,高度固定400px。这里使用默认的field和校验提示' 12 | }, 13 | items: { 14 | ...genImgItem({ 15 | width: 1920, 16 | height: 500, 17 | }), 18 | imgLink: { 19 | 'err:format': '请输入正确的的链接地址', 20 | 'err:required': '不能为空' 21 | }, 22 | 'ui:title': '轮播图片配置' 23 | } 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/CategoryGoods/uiSchema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/7/25 15:47. 3 | */ 4 | 5 | import genImgItem from '../_commonConfig/ui/genImgItem'; 6 | 7 | export default { 8 | title: { 9 | 'ui:placeholder': '请输入标题' 10 | }, 11 | subTitle: { 12 | 'ui:placeholder': '请输入副标题' 13 | }, 14 | banner: { 15 | link: { 16 | ...genImgItem() 17 | }, 18 | bannerTitle: { 19 | 'ui:placeholder': '请输入banner标题' 20 | }, 21 | bannerSubTitle: { 22 | 'ui:placeholder': '请输入banner副标题' 23 | } 24 | }, 25 | goodsList: { 26 | 'ui:showIndexNumber': true, 27 | items: { 28 | ...genImgItem() 29 | } 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /src/demo-common/components/ElementPlus/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/11/20 9:43. 3 | */ 4 | 5 | // import './theme/index.css'; 6 | import ElementPlus, { 7 | ElLoading, 8 | ElMessageBox, 9 | ElMessage 10 | } from 'ElementPlus'; 11 | 12 | console.log(ElementPlus); 13 | export default { 14 | install(app) { 15 | app.use(ElementPlus); 16 | 17 | // 原型方法 18 | app.config.globalProperties.$loading = ElLoading.service; 19 | app.config.globalProperties.$alert = ElMessageBox.alert; 20 | app.config.globalProperties.$confirm = ElMessageBox.confirm; 21 | app.config.globalProperties.$prompt = ElMessageBox.prompt; 22 | app.config.globalProperties.$msgbox = ElMessageBox; 23 | app.config.globalProperties.$message = ElMessage; 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/Text/View.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 24 | 25 | 36 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponentsM/Text/View.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 24 | 25 | 36 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/MultipleImg2_3/uiSchema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/4/30 17:13. 3 | */ 4 | 5 | import genImgItem from '../_commonConfig/ui/genImgItem'; 6 | 7 | const line2Item = genImgItem({ 8 | width: 383, 9 | height: 500, 10 | }); 11 | 12 | export default { 13 | imgItem1_1: { 14 | 'ui:title': '图片上左', 15 | ...genImgItem({ 16 | width: 786, 17 | height: 420, 18 | }) 19 | }, 20 | imgItem1_2: { 21 | 'ui:title': '图片上右', 22 | ...line2Item 23 | }, 24 | imgItem2_1: { 25 | 'ui:title': '图片下左', 26 | ...line2Item 27 | }, 28 | imgItem2_2: { 29 | 'ui:title': '图片下中', 30 | ...line2Item 31 | }, 32 | imgItem2_3: { 33 | 'ui:title': '图片下右', 34 | ...line2Item 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /src/demo-common/schemaTypes/25.hidden(隐藏表单项)/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/7/22 11:07 下午. 3 | */ 4 | 5 | export default { 6 | schema: { 7 | title: '隐藏表单项', 8 | type: 'object', 9 | description: ` 10 | 隐藏表单项可以使用多种配置方案,可以结合实际需要 11 |
1. ui:widget: "hidden" 12 |
2. ui:widget: "HiddenWidget" 13 |
3. ui:hidden: true 14 | `, 15 | properties: { 16 | hidden2: { 17 | title: 'hidden2', 18 | type: 'string', 19 | 'ui:widget': 'HiddenWidget', 20 | default: 'hidden2' 21 | }, 22 | hidden3: { 23 | title: 'hidden1', 24 | type: 'string', 25 | 'ui:hidden': true, 26 | default: 'hidden3' 27 | } 28 | } 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /src/pages/vue-editor/vue-editor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vue Editor 活动编辑器 | Vue Json schema form 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/demo-common/utils/url.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/11/11 22:24. 3 | */ 4 | 5 | export function openNewPage(url, target = '_blank') { 6 | const a = document.createElement('a'); 7 | a.style.display = 'none'; 8 | a.target = target; 9 | a.href = url; 10 | document.body.appendChild(a); 11 | a.click(); 12 | document.body.removeChild(a); 13 | } 14 | 15 | // 解析当前url的query 参数 16 | export function getUrlQuery(href) { 17 | const url = String(href === undefined ? window.location.href : href).replace(/#.*$/, ''); 18 | const search = url.substring(url.lastIndexOf('?') + 1); 19 | const obj = {}; 20 | const reg = /([^?&=]+)=([^?&=]*)/g; 21 | search.replace(reg, (rs, $1, $2) => { 22 | const name = decodeURIComponent($1); 23 | const query = String(decodeURIComponent($2)); 24 | obj[name] = query; 25 | return rs; 26 | }); 27 | return obj; 28 | } 29 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/Coupon/component/View.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 23 | 24 | 39 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/Text/uiSchema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/7/25 11:25. 3 | */ 4 | 5 | export default { 6 | txt: { 7 | 'ui:options': { 8 | renderScopedSlots(h) { 9 | return { 10 | append: () => h('span', '.com') 11 | }; 12 | }, 13 | widgetListeners: { 14 | input(event) { 15 | console.log('ui input', event); 16 | } 17 | }, 18 | renderChildren(h) { 19 | return [ 20 | h('span', { 21 | slot: 'suffix', 22 | }, '后缀') 23 | ]; 24 | }, 25 | getWidget(widgetVm) { 26 | console.log(widgetVm); 27 | }, 28 | onChange(data) { 29 | console.log('change:', data); 30 | } 31 | } 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /scripts/envConfig.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2018/5/31. 3 | */ 4 | 5 | // envConfig 分为两部分参数 1、根据入口文件携带的固定参数 2、根具 npm_config 获取参数可以覆盖1的参数 6 | // 不同入口文件需要自己调用 initConfig 7 | 8 | const argv = require('yargs').argv; 9 | 10 | const manifestAlias = { 11 | lgb: 'log', 12 | dgb: 'dir', 13 | rgb: 'report', 14 | }; 15 | 16 | exports.getConfig = () => { 17 | try { 18 | return JSON.parse(process.env.npm_config_argv).original.slice(2).reduce((preVal, item) => { 19 | const param = item.replace(/^--/, ''); 20 | const [key, value] = param.split('='); 21 | preVal[key] = value || !0; 22 | 23 | // 别名 24 | if (manifestAlias[key]) { 25 | preVal[manifestAlias[key]] = preVal[key]; 26 | } 27 | return preVal; 28 | }, argv); 29 | } catch (e) { 30 | // 31 | console.warn('JSON parse "process.env.npm_config_argv" fail !'); 32 | } 33 | return {}; 34 | }; 35 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/FlashSaleGoodsList/uiSchema.js: -------------------------------------------------------------------------------- 1 | import genImgItem from '../_commonConfig/ui/genImgItem'; 2 | 3 | export default { 4 | startTime: { 5 | 'ui:options': { 6 | placeholder: '选择开始时间', 7 | style: { 8 | width: '100%' 9 | }, 10 | pickerOptions: { 11 | disabledDate(time) { 12 | return time.getTime() < Date.now(); 13 | } 14 | } 15 | } 16 | }, 17 | seckillBrand: { 18 | ...genImgItem(), 19 | 'ui:title': '右侧固定广告位配置' 20 | }, 21 | goodsList: { 22 | 'ui:options': { 23 | title: '添加商品', 24 | description: '添加秒杀商品,这里应该是结合具体业务调用添加商品逻辑', 25 | showIndexNumber: true 26 | }, 27 | items: { 28 | ...genImgItem({ 29 | width: 1920, 30 | height: 500, 31 | }), 32 | 'ui:title': '商品配置' 33 | } 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/Text/propsSchema.js: -------------------------------------------------------------------------------- 1 | export default { 2 | $schema: 'http://json-schema.org/draft-07/schema#', 3 | title: '单文本输入组件', 4 | description: '单文本输入组件,用于在页面配置一条文字信息', 5 | type: 'object', 6 | required: ['txt'], 7 | properties: { 8 | imgUrl: { 9 | title: '测试图片上传', 10 | type: 'string', 11 | default: 'http://img.alicdn.com/tfs/TB1vYlkdnZmx1VjSZFGXXax2XXa-468-644.jpg_320x5000q100.jpg_.webp', 12 | 'ui:action': 'https://run.mocky.io/v3/518d7af7-204f-45ab-9628-a6e121dab8ca', 13 | 'ui:widget': 'UploadWidget', 14 | 'ui:btnText': '上传按钮文案配置', 15 | 'ui:responseFileUrl': (res) => {} 16 | }, 17 | txt: { 18 | title: '文字', 19 | type: 'string', 20 | 'ui:placeholder': '输入你的内容', 21 | 'err:required': '必须输入标题文字内容' 22 | }, 23 | txtColor: { 24 | title: '选择文字颜色', 25 | type: 'string', 26 | format: 'color', 27 | default: '#ff0132' 28 | } 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/data.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/4/28 15:36. 3 | */ 4 | 5 | export function vm2Api(vmData) { 6 | return vmData.map(item => ({ 7 | name: item.name, 8 | value: item.componentValue, 9 | })); 10 | } 11 | 12 | function getComponentMap(configTools) { 13 | const componentList = configTools.reduce((preVal, curVal) => [ 14 | ...preVal, 15 | ...curVal.componentList 16 | ], []); 17 | 18 | // 注册组件结构 19 | return componentList.reduce((preVal, componentItem) => { 20 | preVal[componentItem.name] = componentItem; 21 | return preVal; 22 | }, {}); 23 | } 24 | 25 | export function api2VmToolItem(configTools, apiData) { 26 | const componentMap = getComponentMap(configTools); 27 | try { 28 | const apiJson = apiData === String(apiData) ? JSON.parse(apiData) : apiData; 29 | return apiJson.map(({ name, value }) => ({ 30 | ...componentMap[name], 31 | componentValue: value 32 | })); 33 | } catch (e) { 34 | // 数据解析失败不处理 35 | return []; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Liu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponentsM/CarouselImg/CarouselImg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "properties": { 5 | "imgList": { 6 | "type": "array", 7 | "minItems": 1, 8 | "maxItems": 4, 9 | "items": { 10 | "type": "object", 11 | "properties": { 12 | "imgUrl": { 13 | "type": "string", 14 | "format": "uri", 15 | "default": "https://m.360buyimg.com/babel/jfs/t1/116779/33/13215/494116/5f19a54fE4e3bf7cc/8a2a7b0732385d19.jpg.webp" 16 | }, 17 | "imgLink": { 18 | "type": "string", 19 | "format": "uri", 20 | "default": "https://www.google.com" 21 | } 22 | }, 23 | "required": [ 24 | "imgUrl", 25 | "imgLink" 26 | ] 27 | } 28 | } 29 | }, 30 | "additionalProperties": false 31 | } 32 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/MultipleImg1_3/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "definitions": { 5 | "ImgItem": { 6 | "type": "object", 7 | "properties": { 8 | "imgUrl": { 9 | "type": "string", 10 | "format": "uri" 11 | }, 12 | "imgLink": { 13 | "type": "string", 14 | "format": "uri", 15 | "default": "https://www.tmall.com/" 16 | } 17 | }, 18 | "required": [ 19 | "imgUrl", 20 | "imgLink" 21 | ] 22 | } 23 | }, 24 | "properties": { 25 | "imgItem1_1": { 26 | "$ref": "#/definitions/ImgItem" 27 | }, 28 | "imgItem2_1": { 29 | "$ref": "#/definitions/ImgItem" 30 | }, 31 | "imgItem2_2": { 32 | "$ref": "#/definitions/ImgItem" 33 | }, 34 | "imgItem2_3": { 35 | "$ref": "#/definitions/ImgItem" 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/CarouselImg/CarouselImg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "properties": { 5 | "imgList": { 6 | "type": "array", 7 | "minItems": 1, 8 | "maxItems": 4, 9 | "uniqueItems": true, 10 | "items": { 11 | "type": "object", 12 | "properties": { 13 | "imgUrl": { 14 | "type": "string", 15 | "format": "uri", 16 | "default": "https://m.360buyimg.com/babel/jfs/t1/116779/33/13215/494116/5f19a54fE4e3bf7cc/8a2a7b0732385d19.jpg.webp" 17 | }, 18 | "imgLink": { 19 | "type": "string", 20 | "format": "uri", 21 | "default": "https://www.google.com" 22 | } 23 | }, 24 | "required": [ 25 | "imgUrl", 26 | "imgLink" 27 | ] 28 | } 29 | } 30 | }, 31 | "additionalProperties": false 32 | } 33 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/MultipleImg5/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "definitions": { 5 | "ImgItem": { 6 | "title": "图片配置", 7 | "type": "object", 8 | "properties": { 9 | "imgUrl": { 10 | "type": "string", 11 | "format": "uri" 12 | }, 13 | "imgLink": { 14 | "type": "string", 15 | "format": "uri", 16 | "default": "https://www.jd.com/" 17 | } 18 | }, 19 | "required": [ 20 | "imgUrl", 21 | "imgLink" 22 | ] 23 | } 24 | }, 25 | "properties": { 26 | "imgList": { 27 | "title": "配置多图模块", 28 | "description": "图片一行展示,最多配置5张图片", 29 | "type": "array", 30 | "minItems": 1, 31 | "maxItems": 5, 32 | "ui:options": { 33 | "showIndexNumber": true 34 | }, 35 | "items": { 36 | "$ref": "#/definitions/ImgItem" 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/MultipleImg2_3/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "definitions": { 5 | "ImgItem": { 6 | "type": "object", 7 | "properties": { 8 | "imgUrl": { 9 | "type": "string", 10 | "format": "uri" 11 | }, 12 | "imgLink": { 13 | "type": "string", 14 | "format": "uri", 15 | "default": "https://www.jd.com/" 16 | } 17 | }, 18 | "required": [ 19 | "imgUrl", 20 | "imgLink" 21 | ] 22 | } 23 | }, 24 | "properties": { 25 | "imgItem1_1": { 26 | "$ref": "#/definitions/ImgItem" 27 | }, 28 | "imgItem1_2": { 29 | "$ref": "#/definitions/ImgItem" 30 | }, 31 | "imgItem2_1": { 32 | "$ref": "#/definitions/ImgItem" 33 | }, 34 | "imgItem2_2": { 35 | "$ref": "#/definitions/ImgItem" 36 | }, 37 | "imgItem2_3": { 38 | "$ref": "#/definitions/ImgItem" 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/demo-common/schemaTypes/21.Upload/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/11/27 16:42. 3 | */ 4 | export default { 5 | schema: { 6 | title: '文件上传', 7 | type: 'object', 8 | description: '文件上传 使用 el-upload组件,只是所有的 el-upload 参数,
slot 可以通过 slots参数传入数组VNode list', 9 | properties: { 10 | imgUrl: { 11 | title: '单个图片', 12 | type: 'string', 13 | default: 'http://img.alicdn.com/tfs/TB1vYlkdnZmx1VjSZFGXXax2XXa-468-644.jpg_320x5000q100.jpg_.webp', 14 | 'ui:action': 'https://run.mocky.io/v3/518d7af7-204f-45ab-9628-a6e121dab8ca', 15 | 'ui:widget': 'UploadWidget', 16 | 'ui:btnText': '上传按钮文案配置' 17 | }, 18 | imgUrlList: { 19 | title: '多图', 20 | type: 'array', 21 | 'ui:widget': 'UploadWidget', 22 | 'ui:action': 'https://run.mocky.io/v3/518d7af7-204f-45ab-9628-a6e121dab8ca', 23 | // eslint-disable-next-line max-len 24 | default: ['http://img.alicdn.com/tfs/TB1vYlkdnZmx1VjSZFGXXax2XXa-468-644.jpg_320x5000q100.jpg_.webp'], 25 | items: { 26 | type: 'string', 27 | } 28 | } 29 | } 30 | }, 31 | formData: {} 32 | }; 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## vue-json-schema-form 活动编辑器 2 | 当前项目实际为 [vue-json-schema-form demo项目](https://github.com/lljj-x/vue-json-schema-form/tree/master/packages/demo/demo-v2) 中活动编辑器的单独仓库。 3 | 4 | ![](https://lljj-xxxx.oss-cn-hongkong.aliyuncs.com/vue-editor.jpg) 5 | 6 | ### 启动方法 7 | ``` 8 | # 安装,请使用 yarn 9 | yarn 10 | 11 | # 开发环境 12 | yarn dev 13 | 14 | # 浏览器访问 15 | http://127.0.0.1:8800/vue-editor.html 16 | 17 | # build 18 | yarn build 19 | 20 | ``` 21 | 22 | ### 备注 23 | > 为了和 [vue-json-schema-form demo项目](https://github.com/lljj-x/vue-json-schema-form/tree/master/packages/demo/demo-v2) 项目保持通用性。对依赖的 `demo-common` 做了以下处理,js中使用webpack 配置别名,css 使用postcss import插件配置path来兼容。 24 | 25 | 详细如下: 26 | * webpack 配置 vue-config.js 添加别名,解决js中 import 'demo-common/xx' 27 | ```js 28 | config.resolve.alias = { 29 | ...config.resolve.alias, 30 | 'demo-common': path.resolve(__dirname, './src/demo-common'), 31 | }; 32 | ``` 33 | 34 | * postcss.config.js 配置post import plugin 添加path配置,解决css中 @import 'demo-common/xx' 35 | ```js 36 | require('postcss-import')({ 37 | path: ['src/'] 38 | }) 39 | ``` 40 | 41 | ### 构建 42 | 使用 vue cli 构建项目多entry形式,按文件目录自动查找entry,有兴趣可参见 `/scripts/entry.js` 文件 43 | 44 | ### 为何独立一份 45 | [vue-json-schema-form](https://github.com/lljj-x/vue-json-schema-form) 为Monorepo,package 之间有相互依赖,由于会有新人不知如何抽出需要的独立package, 46 | 所以现在独立为一个单独的仓库,同时方便后续的更新。 47 | 48 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponentsM/Test/Form.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 53 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.9.1", 4 | "private": true, 5 | "license": "Apache-2.0", 6 | "scripts": { 7 | "dev": "vue-cli-service serve", 8 | "build": "vue-cli-service build", 9 | "lint": "vue-cli-service lint" 10 | }, 11 | "dependencies": { 12 | "@lljj/polyfill": "^0.1.0", 13 | "@lljj/vue-json-schema-form": "1.9.1", 14 | "postcss-preset-env": "^6.7.0", 15 | "vue": "^2.6.10", 16 | "vuedraggable": "2.23.2" 17 | }, 18 | "devDependencies": { 19 | "@lljj/babel-preset-app": "^0.0.1", 20 | "@lljj/eslint-config": "0.1.0", 21 | "@vue/cli-plugin-babel": "~4.5.0", 22 | "@vue/cli-plugin-eslint": "~4.5.0", 23 | "@vue/cli-service": "~4.5.0", 24 | "babel-eslint": "^10.0.3", 25 | "copy-webpack-plugin": "^5.0.4", 26 | "eslint": "^5.16.0", 27 | "eslint-plugin-import": "^2.20.2", 28 | "eslint-plugin-vue": "^5.0.0", 29 | "markdown-it-task-lists": "^2.1.1", 30 | "postcss-color-mod-function": "^3.0.3", 31 | "postcss-cssnext": "^3.1.0", 32 | "postcss-import": "^12.0.1", 33 | "postcss-mixins": "^6.2.0", 34 | "postcss-nested": "^4.1.0", 35 | "vue-template-compiler": "^2.6.10", 36 | "watchpack": "^1.6.1", 37 | "webpack-bundle-analyzer": "^3.6.0", 38 | "webpack-manifest-plugin": "^2.2.0", 39 | "yargs": "^6.6.0" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/pages/vue-editor/router/guards.js: -------------------------------------------------------------------------------- 1 | const beListConfig = []; 2 | 3 | // 路由守卫 4 | export default function guards(router) { 5 | router.beforeEach(async (to, from, next) => { 6 | const beGuardsList = [...beListConfig]; 7 | 8 | // 依次执行每一个拦截器 9 | // 如果有返回路由地址 中断循环,跳转路由,'' || 'next' 字符串,执行next(); 10 | // 如果catch异常 终止路由跳转,中断循环 11 | 12 | while (beGuardsList.length > 0) { 13 | const handler = beGuardsList.shift(); 14 | const isRunInterceptor = handler.valid ? handler.valid(to, from) : true; 15 | 16 | if (isRunInterceptor) { 17 | try { 18 | const nextValue = await handler(to, from); // eslint-disable-line 19 | if (nextValue !== undefined) { 20 | next(...(nextValue === '' || nextValue === 'next' ? [] : [nextValue])); 21 | return; 22 | } 23 | } catch (e) { 24 | // reject 或者 throw error 中断后续拦截器,并且不跳转页面 25 | next(false); 26 | return; 27 | } 28 | } 29 | } 30 | 31 | // 兜底执行 32 | next(); 33 | }); 34 | 35 | // after each 不用改变路由行为,不采用上述模式 36 | router.afterEach((to, from) => { 37 | const baseTitle = 'vue-json-schema-form'; 38 | if (to.meta.title) { 39 | document.title = `${to.meta.title} | ${baseTitle}`; 40 | } 41 | }); 42 | } 43 | -------------------------------------------------------------------------------- /src/demo-common/css/bootstrap.css: -------------------------------------------------------------------------------- 1 | @import './variable.css'; 2 | 3 | body { 4 | color: var(--normalC); 5 | line-height: 1; 6 | min-width: var(--contentWidth); 7 | word-wrap: break-word; 8 | word-break: break-word; 9 | } 10 | 11 | body, 12 | td, 13 | a, 14 | p, 15 | li, 16 | dl, 17 | ul, 18 | dt, 19 | h1, 20 | h2, 21 | h3, 22 | h4, 23 | h5, 24 | p, 25 | dd { 26 | @mixin fontBase; 27 | padding: 0; 28 | margin: 0; 29 | font-weight: normal; 30 | } 31 | 32 | em, i { 33 | font-style: normal; 34 | } 35 | 36 | strong, b { 37 | font-weight: normal; 38 | } 39 | 40 | sub, sup { 41 | position: static; 42 | top: auto; 43 | font-size: 100%; 44 | } 45 | 46 | input, 47 | textarea, 48 | button { 49 | @mixin fontBase; 50 | outline: none; 51 | } 52 | 53 | input::-ms-clear { 54 | display: none; 55 | } 56 | img { 57 | vertical-align: top; 58 | } 59 | 60 | ul { 61 | list-style: none; 62 | } 63 | 64 | a { 65 | color: var(--normalC); 66 | text-decoration: none; 67 | font-size: inherit; 68 | outline: none; 69 | } 70 | 71 | .siteScroll, 72 | .siteHeader_currencyList, 73 | * { 74 | &::-webkit-scrollbar { 75 | width: 6px; 76 | height: 6px; 77 | } 78 | &::-webkit-scrollbar-track { 79 | background-color: white; 80 | } 81 | &::-webkit-scrollbar-thumb { 82 | border-radius: 10px; 83 | background-color: #999999; 84 | } 85 | } 86 | 87 | .hide{ 88 | display: none; 89 | } 90 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/FlashSaleGoodsList/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "definitions": { 5 | "ImgItem": { 6 | "type": "object", 7 | "properties": { 8 | "imgUrl": { 9 | "title": "图片地址", 10 | "type": "string", 11 | "format": "uri" 12 | }, 13 | "imgLink": { 14 | "title": "链接地址", 15 | "type": "string", 16 | "format": "uri", 17 | "default": "https://www.jd.com" 18 | } 19 | }, 20 | "required": [ 21 | "imgUrl", 22 | "imgLink" 23 | ] 24 | } 25 | }, 26 | "properties": { 27 | "startTime": { 28 | "title": "配置秒杀开始时间", 29 | "type": "string", 30 | "format": "date-time" 31 | }, 32 | "seckillBrand": { 33 | "$ref": "#/definitions/ImgItem" 34 | }, 35 | "goodsList": { 36 | "type": "array", 37 | "minItems": 4, 38 | "maxItems": 8, 39 | "uniqueItems": true, 40 | "items": { 41 | "$ref": "#/definitions/ImgItem" 42 | } 43 | } 44 | }, 45 | "required": [ 46 | "startTime" 47 | ], 48 | "additionalProperties": false 49 | } 50 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/common/editorData.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/3/31 11:30 上午. 3 | */ 4 | 5 | import { getDefaultFormState } from '@lljj/vue-json-schema-form'; 6 | import { genId } from 'demo-common/utils/id'; 7 | 8 | function isEmptyObject(obj) { 9 | for (const key in obj) { 10 | if (Object.prototype.hasOwnProperty.call(obj, key)) { 11 | return false; 12 | } 13 | } 14 | return true; 15 | } 16 | 17 | // 生成一个新的editor item 18 | export function generateEditorItem(toolItem) { 19 | const currentComponentPack = toolItem.componentPack; 20 | 21 | const componentValue = ( 22 | currentComponentPack.propsSchema 23 | && (!toolItem.componentValue || isEmptyObject(toolItem.componentValue)) 24 | ) 25 | ? getDefaultFormState( 26 | currentComponentPack.propsSchema, 27 | {}, // 初始值为空 28 | currentComponentPack.propsSchema 29 | ) 30 | : toolItem.componentValue || {}; 31 | 32 | return { 33 | ...toolItem, 34 | isEdit: false, 35 | toolBar: { 36 | moveDownDisabled: false, 37 | moveUpDisabled: false, 38 | copyDisabled: false, 39 | removeDisabled: false, 40 | }, 41 | componentValue, 42 | componentViewName: currentComponentPack.componentViewName, 43 | componentFormName: currentComponentPack.componentFormName, 44 | // id: `${currentComponentPack.componentViewName}_${+new Date()}`, 45 | id: genId(), 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/components/skeleton/Skeleton.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 53 | 54 | 57 | -------------------------------------------------------------------------------- /src/demo-common/schemaTypes/24.uiSchema(表达式)/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/7/22 11:07 下午. 3 | */ 4 | 5 | export default { 6 | schema: { 7 | title: 'uiSchema 配置表达式', 8 | type: 'object', 9 | description: '
  • rootFormData:根节点的值
  • parentFormData:当前父节点的值
  • ', 10 | properties: { 11 | age: { 12 | type: 'integer', 13 | title: '输入年龄', 14 | maximum: 80, 15 | minimum: 16, 16 | 'ui:title': '{{ parentFormData.age > 18 ? "呵呵呵" : "嘿嘿嘿" }}', 17 | }, 18 | bio: { 19 | type: 'string', 20 | title: 'Bio', 21 | minLength: 10, 22 | 'ui:type': '{{ parentFormData.bio && parentFormData.bio.length ? "textarea" : undefined }}' 23 | }, 24 | selectWidgetOptions: { 25 | title: 'Custom select widget with options', 26 | type: 'string', 27 | // eslint-disable-next-line max-len 28 | 'ui:style': '{{ parentFormData.selectWidgetOptions === "foo" ? { boxShadow: "0 0 6px 2px pink"} : { boxShadow: "0 0 6px 2px red"} }}', 29 | 'ui:title': '{{ parentFormData.a === "1" ? "呵呵呵" : "嘿嘿嘿" }}', 30 | enum: [ 31 | 'foo', 32 | 'bar' 33 | ], 34 | enumNames: [ 35 | 'Foo', 36 | 'Bar' 37 | ] 38 | } 39 | } 40 | }, 41 | formData: { 42 | a: '111' 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponentsM/RecommendGoods/propsSchema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "title": "配置分类条", 5 | "description": "分别配置每个分类的名称以及图片链接,最多配置10组,最少配置3组", 6 | "properties": { 7 | "title": { 8 | "title": "推荐名称", 9 | "type": "string", 10 | "default": "限时抢购", 11 | "ui:options": { 12 | "placeholder": "请输入推荐名称" 13 | } 14 | }, 15 | "imgList": { 16 | "type": "array", 17 | "minItems": 2, 18 | "maxItems": 4, 19 | "items": { 20 | "type": "object", 21 | "title": "配置图片和连接", 22 | "required": [ 23 | "imgUrl", 24 | "imgLink" 25 | ], 26 | "ui:field": "LinkImgField", 27 | "properties": { 28 | "imgUrl": { 29 | "type": "string", 30 | "format": "uri", 31 | "default": "https://img.alicdn.com/tfs/TB1vYlkdnZmx1VjSZFGXXax2XXa-468-644.jpg_320x5000q100.jpg_.webp", 32 | "err:format": "请输入正确的的图片地址" 33 | }, 34 | "imgLink": { 35 | "type": "string", 36 | "format": "uri", 37 | "default": "https://www.tmall.com", 38 | "err:format": "请输入正确的的链接地址" 39 | } 40 | } 41 | } 42 | } 43 | }, 44 | "additionalProperties": false 45 | } 46 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/components/skeleton/SkeletonGoods.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 57 | 58 | 61 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/MultipleImg5/View.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 57 | 58 | 67 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/common/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/11/28 18:37. 3 | */ 4 | 5 | import { genId } from 'demo-common/utils/id'; 6 | 7 | 8 | export function deepFreeze(obj) { 9 | // 取回定义在obj上的属性名 10 | const propNames = Object.getOwnPropertyNames(obj); 11 | 12 | // 在冻结自身之前冻结属性 13 | propNames.forEach((name) => { 14 | const prop = obj[name]; 15 | 16 | // 如果prop是个对象,冻结它 17 | if (typeof prop === 'object' && prop !== null) deepFreeze(prop); 18 | }); 19 | 20 | // 冻结自身(no-op if already frozen) 21 | return Object.freeze(obj); 22 | } 23 | 24 | // 初始化配置数据并返回所有组件 25 | export function getComponentsAndInitToolsConfig(configTools) { 26 | // 平铺开所有组 27 | const componentList = configTools.reduce((preVal, curVal) => [ 28 | ...preVal, 29 | ...curVal.componentList 30 | ], []); 31 | 32 | // 注册组件结构 33 | const data = componentList.reduce((preVal, { name: configItemName, componentPack }) => { 34 | // 修改原数据 35 | // 生成 From组件和View组件 Name 36 | const needViewName = !componentPack.componentViewName; 37 | const needFormName = componentPack.Form && !componentPack.componentFormName; 38 | 39 | // 需要生成viewName 或者 formName 40 | if (needViewName || needFormName) { 41 | const id = configItemName || genId(); 42 | if (needViewName) componentPack.componentViewName = `View${id}`; 43 | if (needFormName) componentPack.componentFormName = `Form${id}`; 44 | } 45 | 46 | if (componentPack.componentFormName) { 47 | preVal[componentPack.componentFormName] = componentPack.Form; 48 | } 49 | preVal[componentPack.componentViewName] = componentPack.View; 50 | 51 | Object.freeze(componentPack); 52 | return preVal; 53 | }, {}); 54 | 55 | 56 | // 冻结配置数据 57 | Object.freeze(configTools); 58 | return data; 59 | } 60 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/config/mTools.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/9/29 18:58. 3 | */ 4 | 5 | // 轮播图 6 | import componentPackCarouselImg from '../viewComponentsM/CarouselImg'; 7 | 8 | // 纯文本 9 | import componentPackText from '../viewComponentsM/Text'; 10 | 11 | // 分类条 12 | import CategoryList from '../viewComponentsM/CategoryList'; 13 | 14 | // 分类条 15 | import RecommendGoods from '../viewComponentsM/RecommendGoods'; 16 | 17 | // 分类条 18 | import Test from '../viewComponentsM/Test'; 19 | 20 | 21 | /** 22 | * hidden 隐藏,不显示在工具栏 23 | * maxNum Number 最大可配置数 24 | * topDisplay Bool 最顶部显示 25 | * bottomDisplay Bool 最底部显示 26 | * onlyCanConfig Bool 是否只能配置数据,不能删除 copy 27 | * @type {*[]} 28 | */ 29 | const tools = [ 30 | { 31 | groupName: '图文类', 32 | componentList: [{ 33 | title: '轮播 (普通数组)', 34 | maxNum: 2, 35 | viewWidth: '100%', 36 | icon: 'el-icon-picture', 37 | name: 'MCarouselImg', 38 | componentPack: componentPackCarouselImg 39 | }, { 40 | title: '纯文本', 41 | maxNum: 20, 42 | viewWidth: '100%', 43 | icon: 'el-icon-notebook-1', 44 | name: 'MText', 45 | componentPack: componentPackText 46 | }, { 47 | title: '分类条', 48 | maxNum: 5, 49 | viewWidth: '100%', 50 | icon: 'el-icon-notebook-1', 51 | name: 'MCategoryList', 52 | componentPack: CategoryList 53 | }, { 54 | title: '推荐商品', 55 | maxNum: 5, 56 | viewWidth: '100%', 57 | icon: 'el-icon-notebook-1', 58 | name: 'MRecommendGoods', 59 | componentPack: RecommendGoods 60 | }, { 61 | title: '测试自定义form', 62 | maxNum: 5, 63 | viewWidth: '100%', 64 | icon: 'el-icon-notebook-1', 65 | name: 'MTestModule', 66 | componentPack: Test 67 | }] 68 | } 69 | ]; 70 | 71 | export default tools; 72 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponentsM/CategoryList/propsSchema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "title": "配置分类条", 5 | "description": "分别配置每个分类的名称以及图片链接,最多配置10组,最少配置3组", 6 | "properties": { 7 | "imgList": { 8 | "type": "array", 9 | "minItems": 3, 10 | "maxItems": 5, 11 | "items": { 12 | "type": "object", 13 | "required": ["name"], 14 | "properties": { 15 | "name": { 16 | "title": "配置类别名称", 17 | "type": "string", 18 | "default": "京东", 19 | "ui:options": { 20 | "placeholder": "请输入类别名称" 21 | } 22 | }, 23 | "img": { 24 | "type": "object", 25 | "title": "配置图片和连接", 26 | "required": [ 27 | "imgUrl", 28 | "imgLink" 29 | ], 30 | "ui:field": "LinkImgField", 31 | "properties": { 32 | "imgUrl": { 33 | "type": "string", 34 | "format": "uri", 35 | "default": "https://gw.alicdn.com/tfs/TB1ISdWSFXXXXbFXXXXXXXXXXXX-146-147.png_110x10000.jpg_.webp", 36 | "err:format": "请输入正确的的图片地址" 37 | }, 38 | "imgLink": { 39 | "type": "string", 40 | "format": "uri", 41 | "default": "https://www.tmall.com", 42 | "err:format": "请输入正确的的链接地址" 43 | } 44 | } 45 | } 46 | } 47 | } 48 | } 49 | }, 50 | "additionalProperties": false 51 | } 52 | -------------------------------------------------------------------------------- /src/demo-common/schemaTypes/16.References/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/5/18 9:50 下午. 3 | */ 4 | 5 | export default { 6 | schema: { 7 | title: 'Refer 和 Refer递归调用', 8 | definitions: { 9 | address: { 10 | type: 'object', 11 | properties: { 12 | street_address: { type: 'string' }, 13 | city: { type: 'string' }, 14 | state: { type: 'string' }, 15 | }, 16 | required: ['street_address', 'city', 'state'], 17 | }, 18 | node: { 19 | type: 'object', 20 | properties: { 21 | name: { type: 'string' }, 22 | children: { 23 | type: 'array', 24 | items: { 25 | $ref: '#/definitions/node', 26 | }, 27 | }, 28 | }, 29 | }, 30 | }, 31 | type: 'object', 32 | properties: { 33 | billing_address: { 34 | title: 'Billing address', 35 | $ref: '#/definitions/address', 36 | }, 37 | shipping_address: { 38 | title: 'Shipping address', 39 | $ref: '#/definitions/address', 40 | }, 41 | tree: { 42 | title: 'Recursive references', 43 | $ref: '#/definitions/node', 44 | }, 45 | }, 46 | }, 47 | uiSchema: { 48 | 'ui:order': ['shipping_address', 'billing_address', 'tree'], 49 | }, 50 | formData: { 51 | billing_address: { 52 | street_address: '21, Jump Street', 53 | city: 'Babel', 54 | state: 'Neverland', 55 | }, 56 | shipping_address: { 57 | street_address: '221B, Baker Street', 58 | city: 'London', 59 | state: 'N/A', 60 | }, 61 | tree: { 62 | name: 'root', 63 | children: [{ name: 'leaf' }], 64 | }, 65 | }, 66 | }; 67 | -------------------------------------------------------------------------------- /src/demo-common/schemaTypes/20.Date-DateTime/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/7/22 11:07 下午. 3 | */ 4 | 5 | export default { 6 | schema: { 7 | title: '时间日期选择', 8 | type: 'object', 9 | description: '日期和日期时间支持区间选择(默认格式为时间戳,配置 type string 会格式化为 ISO 时间)', 10 | required: ['dateTimeRange', 'dateTime'], 11 | properties: { 12 | dateTimeRange: { 13 | title: '日期时间区间选择', 14 | type: 'array', 15 | format: 'date-time', 16 | items: { 17 | type: 'string' 18 | } 19 | }, 20 | dateTimeRangeNumber: { 21 | title: '日期时间区间选择(number时间戳)', 22 | type: 'array', 23 | format: 'date-time', 24 | items: { 25 | type: 'number' 26 | } 27 | }, 28 | dateRange: { 29 | title: '日期区间选择', 30 | type: 'array', 31 | format: 'date', 32 | items: { 33 | type: 'string' 34 | } 35 | }, 36 | dateRangeNumber: { 37 | title: '日期区间选择(number时间戳)', 38 | type: 'array', 39 | format: 'date', 40 | items: { 41 | type: 'number' 42 | } 43 | }, 44 | time: { 45 | title: '时间选择', 46 | type: 'string', 47 | format: 'time' 48 | }, 49 | dateTime: { 50 | title: '日期时间', 51 | type: 'string', 52 | format: 'date-time' 53 | }, 54 | dateTimeNumber: { 55 | title: '日期时间(时间戳)', 56 | type: 'number', 57 | format: 'date-time' 58 | }, 59 | date: { 60 | title: '日期', 61 | type: 'string', 62 | format: 'date' 63 | }, 64 | dateNumber: { 65 | title: '日期(时间戳)', 66 | type: 'number', 67 | format: 'date' 68 | } 69 | } 70 | } 71 | }; 72 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/CategoryGoods/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "required": ["title"], 5 | "definitions": { 6 | "ImgItem": { 7 | "type": "object", 8 | "properties": { 9 | "imgUrl": { 10 | "title": "图片地址", 11 | "type": "string", 12 | "format": "uri" 13 | }, 14 | "imgLink": { 15 | "title": "链接地址", 16 | "type": "string", 17 | "format": "uri", 18 | "default": "https://www.jd.com" 19 | } 20 | }, 21 | "required": [ 22 | "imgUrl", 23 | "imgLink" 24 | ] 25 | } 26 | }, 27 | "properties": { 28 | "title": { 29 | "title": "标题", 30 | "type": "string", 31 | "maxLength": 10 32 | }, 33 | "subTitle": { 34 | "title": "副标题", 35 | "type": "string", 36 | "maxLength": 30 37 | }, 38 | "banner": { 39 | "title": "左侧banner配置", 40 | "type": "object", 41 | "properties": { 42 | "link": { 43 | "title": "banner图片和链接配置", 44 | "$ref": "#/definitions/ImgItem" 45 | }, 46 | "bannerTitle": { 47 | "title": "banner主标题", 48 | "type": "string", 49 | "maxLength": 4 50 | }, 51 | "bannerSubTitle": { 52 | "title": "banner副标题", 53 | "type": "string", 54 | "maxLength": 8 55 | } 56 | } 57 | }, 58 | "goodsList": { 59 | "type": "array", 60 | "title": "商品信息配置", 61 | "minItems": 4, 62 | "maxItems": 8, 63 | "items": { 64 | "title": "配置商品信息", 65 | "$ref": "#/definitions/ImgItem" 66 | } 67 | } 68 | }, 69 | "additionalProperties": false 70 | } 71 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/components/GoodsListView.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 55 | 56 | 86 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponentsM/RecommendGoods/View.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 48 | 49 | 89 | -------------------------------------------------------------------------------- /src/demo-common/schemaTypes/14.Number/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/5/17 10:18 下午. 3 | */ 4 | 5 | let sliderName = 'el-slider'; 6 | const sliderNameRules = { 7 | 'ui=VueAntForm': 'SliderWidget', 8 | 'ui=VueIview3Form': 'slider' 9 | }; 10 | 11 | const curUrl = window.location.href; 12 | Object.entries(sliderNameRules).some(([key, value]) => { 13 | const isInclude = ~curUrl.indexOf(key); 14 | 15 | if (isInclude) { 16 | sliderName = value; 17 | return true; 18 | } 19 | 20 | return false; 21 | }); 22 | 23 | 24 | export default { 25 | schema: { 26 | type: 'object', 27 | title: 'Number fields & widgets', 28 | properties: { 29 | number: { 30 | title: 'Number', 31 | type: 'number', 32 | }, 33 | integer: { 34 | title: 'Integer', 35 | type: 'integer', 36 | }, 37 | numberEnum: { 38 | type: 'number', 39 | title: 'Number enum (select)', 40 | enum: [1, 2, 3], 41 | enumNames: ['Select - 1', 'Select - 2', 'Select - 3'] 42 | }, 43 | numberEnumRadio: { 44 | type: 'number', 45 | title: 'Number enum (radio)', 46 | enum: [1, 2, 3], 47 | enumNames: ['Radio - 1', 'Radio - 2', 'Radio - 3'] 48 | }, 49 | integerRange: { 50 | title: 'Integer range', 51 | type: 'integer', 52 | minimum: 42, 53 | maximum: 100, 54 | }, 55 | integerRangeSteps: { 56 | title: 'Integer range (by 10)', 57 | type: 'integer', 58 | minimum: 50, 59 | maximum: 100, 60 | multipleOf: 10, 61 | }, 62 | }, 63 | }, 64 | uiSchema: { 65 | numberEnumRadio: { 66 | 'ui:widget': 'RadioWidget', 67 | 'ui:enumNames': ['ui-radio1', 'ui-radio2', 'ui-radio3'] 68 | }, 69 | integerRange: { 70 | 'ui:widget': sliderName 71 | }, 72 | integerRangeSteps: { 73 | 'ui:widget': sliderName 74 | }, 75 | }, 76 | formData: { 77 | number: 3.14, 78 | integer: 42, 79 | numberEnum: 2, 80 | integerRange: 42, 81 | integerRangeSteps: 80, 82 | }, 83 | }; 84 | -------------------------------------------------------------------------------- /src/demo-common/schemaTypes/12.Nested/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/5/13 9:18 下午. 3 | */ 4 | 5 | export default { 6 | schema: { 7 | title: 'A list of tasks', 8 | type: 'object', 9 | required: ['title'], 10 | properties: { 11 | title: { 12 | type: 'string', 13 | title: 'Task list title', 14 | }, 15 | tasks: { 16 | type: 'array', 17 | title: 'Tasks', 18 | items: { 19 | type: 'object', 20 | required: ['title'], 21 | properties: { 22 | title: { 23 | type: 'string', 24 | title: 'Title', 25 | description: 'A sample title', 26 | }, 27 | details: { 28 | type: 'string', 29 | title: 'Task details', 30 | description: 'Enter the task details', 31 | }, 32 | done: { 33 | type: 'boolean', 34 | title: 'Done?', 35 | default: false, 36 | }, 37 | }, 38 | }, 39 | }, 40 | }, 41 | }, 42 | uiSchema: { 43 | title: { 44 | 'err:required': '请输入title' 45 | }, 46 | tasks: { 47 | items: { 48 | details: { 49 | 'ui:options': { 50 | type: 'textarea' 51 | }, 52 | }, 53 | }, 54 | }, 55 | }, 56 | formData: { 57 | title: 'My current tasks', 58 | tasks: [ 59 | { 60 | title: 'My first task', 61 | details: 62 | 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 63 | done: true, 64 | }, 65 | { 66 | title: 'My second task', 67 | details: 68 | 'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur', 69 | done: false, 70 | }, 71 | ], 72 | }, 73 | }; 74 | -------------------------------------------------------------------------------- /src/demo-common/components/JsonPerttyPrint.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 49 | 50 | 81 | -------------------------------------------------------------------------------- /src/demo-common/schemaTypes/41.Object-property-dependencies(联动)/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/5/19 15:41. 3 | */ 4 | 5 | export default { 6 | schema: { 7 | title: 'Object property dependencies', 8 | type: 'object', 9 | properties: { 10 | unidirectional: { 11 | title: '单向依赖', 12 | description: '最基本的属性单向依赖,ui-schema 配置 onlyShowIfDependent 只在被依赖时才显示', 13 | type: 'object', 14 | 'ui:options': { 15 | onlyShowIfDependent: true 16 | }, 17 | properties: { 18 | name: { 19 | title: 'Name', 20 | type: 'string' 21 | }, 22 | credit_card: { 23 | title: 'Credit card', 24 | type: 'string' 25 | }, 26 | billing_address: { 27 | title: 'Billing address', 28 | type: 'string' 29 | } 30 | }, 31 | required: [ 32 | 'name' 33 | ], 34 | dependencies: { 35 | credit_card: [ 36 | 'billing_address' 37 | ] 38 | } 39 | }, 40 | bidirectional: { 41 | title: '双向依赖', 42 | description: '显式地定义双向依赖,如果配置 onlyShowIfDependent 会导致初始化没有值时都无法渲染,这里需要使用者自行考虑', 43 | type: 'object', 44 | properties: { 45 | name: { 46 | title: 'Name', 47 | type: 'string' 48 | }, 49 | credit_card: { 50 | title: 'Credit card', 51 | type: 'string' 52 | }, 53 | billing_address: { 54 | title: 'Billing address', 55 | type: 'string' 56 | } 57 | }, 58 | required: [ 59 | 'name' 60 | ], 61 | dependencies: { 62 | credit_card: [ 63 | 'billing_address' 64 | ], 65 | billing_address: [ 66 | 'credit_card' 67 | ] 68 | } 69 | } 70 | } 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/components/skeleton/skeleton.css: -------------------------------------------------------------------------------- 1 | @import "demo-common/css/variable.css"; 2 | 3 | :root { 4 | --color-skeleton-bg: var(--background-color-base); 5 | --color-animate-bg: #e6e6e6; 6 | --color-skeleton-item-border: #e8e8e8; 7 | } 8 | 9 | .skeleton { 10 | box-sizing: border-box; 11 | padding: 20px; 12 | background: var(--color-white); 13 | display: table; 14 | width: 100%; 15 | &+.skeleton { 16 | margin-top: 20px; 17 | } 18 | } 19 | .skeleton-type-img { 20 | position: relative; 21 | padding-bottom: 80%; 22 | &:before { 23 | content: ' '; 24 | position: absolute; 25 | width: calc(100% - 40px); 26 | height: calc(100% - 40px); 27 | top: 20px; 28 | left: 20px; 29 | background: var(--color-skeleton-bg); 30 | } 31 | } 32 | .skeleton-title { 33 | width: 100%; 34 | height: 16px; 35 | margin-top: 16px; 36 | background: var(--color-skeleton-bg); 37 | } 38 | .skeleton-content { 39 | display: table-cell; 40 | width: 100%; 41 | vertical-align: top; 42 | } 43 | .skeleton-item { 44 | padding: 20px 0; 45 | &+.skeleton-item { 46 | border-top: 1px solid var(--color-skeleton-item-border); 47 | } 48 | } 49 | 50 | .skeleton-title+.skeleton-paragraph { 51 | margin-top: 24px; 52 | } 53 | .skeleton-paragraph { 54 | padding: 0; 55 | &>li { 56 | width: 100%; 57 | height: 16px; 58 | list-style: none; 59 | background: var(--color-skeleton-bg); 60 | &:last-child:not(:first-child):not(:nth-child(2)) { 61 | width: 61%; 62 | } 63 | &+li { 64 | margin-top: 16px; 65 | } 66 | } 67 | } 68 | 69 | @keyframes skeleton-loading { 70 | 0% { 71 | background-position: 100% 50% 72 | } 73 | 74 | 100% { 75 | background-position: 0 50% 76 | } 77 | } 78 | .skeleton-goods-img { 79 | position: relative; 80 | padding: 50%; 81 | background: var(--color-skeleton-bg); 82 | .skeleton-goods-img-icon { 83 | position: absolute; 84 | top: 50%; 85 | left: 50%; 86 | transform: translate(-50%, -50%); 87 | } 88 | } 89 | .skeleton-title, .skeleton-paragraph>li{ 90 | @nest .skeleton-active & { 91 | background: linear-gradient(90deg, var(--color-skeleton-bg) 25%, var(--color-animate-bg) 37%, var(--color-skeleton-bg) 63%); 92 | background-size: 400% 100%; 93 | animation: skeleton-loading 1.4s ease infinite 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/demo-common/schemaTypes/19.AllOf/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/5/19 15:00. 3 | */ 4 | 5 | export default { 6 | schema: { 7 | type: 'object', 8 | definitions: { 9 | address: { 10 | type: 'object', 11 | properties: { 12 | street_address: { 13 | title: '街道', 14 | type: 'string' 15 | }, 16 | city: { 17 | title: '城市', 18 | type: 'string' 19 | }, 20 | state: { 21 | title: '国家', 22 | type: 'string' 23 | } 24 | }, 25 | required: ['street_address', 'city', 'state'] 26 | } 27 | }, 28 | properties: { 29 | test: { 30 | title: '测试字符串', 31 | allOf: [ 32 | { 33 | type: 'string', 34 | default: 'xxx', 35 | }, 36 | { 37 | maxLength: 5 38 | } 39 | ] 40 | }, 41 | testAllOfRef: { 42 | allOf: [ 43 | { 44 | $ref: '#/definitions/address' 45 | }, 46 | { 47 | properties: { 48 | type: { 49 | type: 'string', 50 | title: 'allOf 枚举', 51 | enum: ['residential', 'business'] 52 | } 53 | } 54 | } 55 | ], 56 | } 57 | }, 58 | allOf: [ 59 | { 60 | properties: { 61 | lorem: { 62 | title: 'allOf 标题', 63 | type: ['string', 'boolean'], 64 | default: false, 65 | }, 66 | }, 67 | }, 68 | { 69 | properties: { 70 | lorem: { 71 | type: 'boolean', 72 | }, 73 | ipsum: { 74 | title: 'title', 75 | type: 'string', 76 | }, 77 | }, 78 | }, 79 | ], 80 | }, 81 | formData: {}, 82 | }; 83 | -------------------------------------------------------------------------------- /src/demo-common/schemaTypes/11.Simple/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | schema: { 3 | title: '测试注册表单', 4 | description: 'A simple form example.', 5 | type: 'object', 6 | required: ['firstName', 'lastName'], 7 | 'ui:order': [ 8 | 'lastName', 9 | 'firstName', 10 | '*', 11 | 'password', 12 | ], 13 | properties: { 14 | firstName: { 15 | type: 'string', 16 | title: 'First name', 17 | default: 'Jun' 18 | }, 19 | lastName: { 20 | type: 'string', 21 | title: 'Last name', 22 | 'ui:options': { 23 | description: '请输入你的姓' 24 | }, 25 | 'err:required': '必须输入Last Name' 26 | }, 27 | price: { 28 | type: 'string', 29 | description: '最多输入两位小数点,最大值 999999.99', 30 | title: '价格', 31 | format: 'price' 32 | }, 33 | age: { 34 | type: 'integer', 35 | title: 'Age', 36 | maximum: 80, 37 | minimum: 16 38 | }, 39 | bio: { 40 | type: 'string', 41 | title: 'Bio', 42 | minLength: 10 43 | }, 44 | password: { 45 | type: 'string', 46 | title: 'Password', 47 | minLength: 3, 48 | }, 49 | telephone: { 50 | type: 'string', 51 | title: 'Telephone', 52 | minLength: 10, 53 | }, 54 | }, 55 | }, 56 | formData: { 57 | lastName: 'Liu', 58 | age: 88, 59 | bio: '知道的越多、就知道的越少', 60 | password: 'My.Pass', 61 | telephone: '1881446xxxx' 62 | }, 63 | uiSchema: { 64 | 'ui:description': '简单表单例子(这里通过UiSchema覆盖了默认description描述配置)', 65 | firstName: { 66 | 'ui:title': '名字', 67 | 'ui:description': '比如:李白姓李、孙尚香姓孙、马可波罗姓马可波', 68 | 'ui:emptyValue': '', 69 | 'ui:options': { 70 | placeholder: '请输入你的姓', 71 | attrs: { 72 | autofocus: true 73 | } 74 | } 75 | }, 76 | bio: { 77 | 'ui:options': { 78 | placeholder: '请输入你的签名', 79 | type: 'textarea', 80 | rows: 6 81 | } 82 | } 83 | }, 84 | errorSchema: { 85 | bio: { 86 | 'err:minLength': '签名最小长度10个字符串' 87 | } 88 | } 89 | }; 90 | -------------------------------------------------------------------------------- /src/demo-common/utils/array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/3/28 10:02 上午. 3 | */ 4 | 5 | function merge(target, other) { 6 | target.push(...other); 7 | } 8 | 9 | function ensure(target, item) { 10 | // 只有当前数组不存在此元素时只添加它 11 | if (target.indexOf(item) === -1) { 12 | target.push(item); 13 | } 14 | return target; 15 | } 16 | 17 | function removeAt(target, index) { 18 | // 移除数组中指定位置的元素,返回布尔表示成功与否 19 | return !!target.splice(index, 1).length; 20 | } 21 | 22 | // 移除 23 | function remove(target, item) { 24 | // 移除数组中第一个匹配传参的那个元素,返回布尔表示成功与否 25 | const index = target.indexOf(item); 26 | if (~index) { 27 | return removeAt(target, index); 28 | } 29 | return false; 30 | } 31 | 32 | function toMap(target, key) { 33 | return target.reduce((preVal, curVal) => { 34 | preVal[curVal[key]] = curVal; 35 | return preVal; 36 | }, {}); 37 | } 38 | 39 | // 是否第一个 40 | function isFirst(target, item) { 41 | return target.indexOf(item) === 0; 42 | } 43 | 44 | // 是否最后一个 45 | function isLast(target, item) { 46 | return target.indexOf(item) === target.length - 1; 47 | } 48 | 49 | // 通过 index 上移 50 | function moveUpAt(target, index) { 51 | if (index === 0) return false; 52 | const item = target[index]; 53 | const newItems = [item, target[index - 1]]; 54 | return target.splice(index - 1, 2, ...newItems); 55 | } 56 | 57 | // 上移动 58 | function moveUp(target, item) { 59 | if (isFirst(target, item)) { 60 | // 不可移动 61 | return false; 62 | } 63 | 64 | const index = target.indexOf(item); 65 | 66 | const newItems = [item, target[index - 1]]; 67 | return target.splice(index - 1, 2, ...newItems); 68 | } 69 | 70 | // 通过 index 下移动 71 | function moveDownAt(target, index) { 72 | if (index === target.length - 1) return false; 73 | const item = target[index]; 74 | const newItems = [target[index + 1], item]; 75 | return target.splice(index, 2, ...newItems); 76 | } 77 | 78 | // 下移动 79 | function moveDown(target, item) { 80 | if (isLast(target, item)) { 81 | // 不可移动 82 | return false; 83 | } 84 | 85 | const index = target.indexOf(item); 86 | 87 | const newItems = [target[index + 1], item]; 88 | return target.splice(index, 2, ...newItems); 89 | } 90 | 91 | // 复制 92 | // function insert(target, items, index) { 93 | // return target.splice(index + 1, 0, ...items); 94 | // } 95 | 96 | export { 97 | merge, 98 | ensure, 99 | removeAt, 100 | remove, 101 | toMap, 102 | isFirst, 103 | isLast, 104 | moveDown, 105 | moveDownAt, 106 | moveUp, 107 | moveUpAt, 108 | }; 109 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/CarouselImg/View.vue: -------------------------------------------------------------------------------- 1 | 55 | 56 | 73 | 74 | 94 | -------------------------------------------------------------------------------- /scripts/entry.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2018/5/31. 3 | */ 4 | 5 | const glob = require('glob'); 6 | const path = require('path'); 7 | const fs = require('fs'); 8 | const envConfig = require('./envConfig'); 9 | 10 | // n个数组获取交集 11 | // const arrayIntersection = (...arg) => { 12 | // arg.reduce((previousValue, currentValue) => previousValue.filter(v => currentValue.includes(v)), arg[0]); 13 | // }; 14 | 15 | // 判断是否为当前 entry 16 | const isEntry = (filePath, curDir) => { 17 | // 需要忽略的文件夹 18 | const exclude = ['/template/', '/component/', '/components/', '/module/', '/modules/']; 19 | 20 | // 同名 判断最后一级文件夹名等于文件名 21 | const isSame = (path.dirname(filePath).split('/').pop() === path.basename(filePath).split('.')[0]); 22 | 23 | // 排除特殊文件夹 24 | const isEntryFile = isSame && exclude.every(exStr => !filePath.includes(exStr)); 25 | 26 | if (isEntryFile && curDir.length > 0) { 27 | // 包含路径 28 | return curDir.some(dirItem => ~filePath.indexOf(dirItem)); 29 | } 30 | return isEntryFile; 31 | }; 32 | 33 | // 默认的模板文件 34 | const defaultTemp = path.resolve(__dirname, '../default.html'); 35 | 36 | function entryFn({ dir, chunks = [] }) { 37 | // entry 文件相对的目录 38 | const dirPath = path.normalize(path.resolve(__dirname, '../src/pages')); 39 | 40 | // entry 文件 41 | const filePath = path.normalize(path.resolve(__dirname, '../src/pages/**/*.js')); 42 | 43 | const temFiles = glob.sync(filePath); 44 | const curDir = dir ? String(dir).split(',') : []; 45 | 46 | // isEntry + 非component 做排除文件夹 47 | const files = temFiles.filter(v => isEntry(v, curDir)); 48 | 49 | let openPage = null; 50 | const entries = files.reduce((preValue, entry, index) => { 51 | const dirName = path.normalize(path.dirname(entry)); 52 | const entryName = dirName.substring(path.normalize(dirPath).length + 1).replace(/\\/g, '/'); 53 | 54 | // const fileName = path.basename(entry, path.extname(entry)); 55 | 56 | // 第一个 entry 为浏览器默认打开页面 57 | if (index === 0) openPage = `${entryName}.html`; 58 | 59 | preValue[entryName] = { 60 | entry, 61 | template: fs.existsSync(entry.replace('.js', '.html')) ? entry.replace('.js', '.html') : defaultTemp, 62 | filename: `${entryName}.html`, 63 | title: `${entryName} - Test Demo`, 64 | chunks: [ 65 | entryName, 66 | ...chunks 67 | ] 68 | // chunks to include on this pages, by default includes 69 | // extracted common chunks and vendor chunks. 70 | // chunks: ['chunk-runtime', 'chunk-vendors-polyfill', 'index'] 71 | }; 72 | return preValue; 73 | }, {}); 74 | 75 | return { 76 | entries, 77 | openPage 78 | }; 79 | } 80 | 81 | module.exports = ({ 82 | chunks = [] 83 | } = {}) => { 84 | // 相对于 根目录 85 | const { 86 | dir, // 指定编译的目录 87 | } = envConfig.getConfig(); 88 | 89 | return entryFn({ 90 | dir, 91 | chunks 92 | }); 93 | }; 94 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponentsM/CategoryList/View.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 52 | 53 | 107 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponentsM/CarouselImg/View.vue: -------------------------------------------------------------------------------- 1 | 55 | 56 | 73 | 74 | 102 | -------------------------------------------------------------------------------- /src/demo-common/components/EditorHeader.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 74 | 75 | 114 | -------------------------------------------------------------------------------- /src/demo-common/components/Menu.vue: -------------------------------------------------------------------------------- 1 | 78 | 79 | 84 | 85 | 118 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/config/tools.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/9/29 18:58. 3 | */ 4 | 5 | // 轮播图 6 | import componentPackCarouselImg from '../viewComponents/CarouselImg'; 7 | 8 | // 秒杀商品 9 | import componentPackFlashSaleGoodsList from '../viewComponents/FlashSaleGoodsList'; 10 | 11 | // 纯文本 12 | import componentPackText from '../viewComponents/Text'; 13 | 14 | // 多图模块一排5个 15 | import componentPackMultipleImg5 from '../viewComponents/MultipleImg5'; 16 | 17 | // 多图模块 2-3 18 | import componentPackMultipleImg23 from '../viewComponents/MultipleImg2_3'; 19 | 20 | // 多图模块 1-2 21 | import componentPackMultipleImg13 from '../viewComponents/MultipleImg1_3'; 22 | 23 | // 分类管区 24 | import componentPackCategoryGoods from '../viewComponents/CategoryGoods'; 25 | 26 | // 推荐 27 | import componentPackRecommendedGoodsList from '../viewComponents/RecommendedGoodsList'; 28 | 29 | // 所有商品 30 | import componentPackAllGoodsList from '../viewComponents/AllGoodsList'; 31 | 32 | // 优惠券 33 | import componentPackCoupon from '../viewComponents/Coupon'; 34 | 35 | 36 | /** 37 | * hidden 隐藏,不显示在工具栏 38 | * maxNum Number 最大可配置数 39 | * topDisplay Bool 最顶部显示 40 | * bottomDisplay Bool 最底部显示 41 | * onlyCanConfig Bool 是否只能配置数据,不能删除 copy 42 | * @type {*[]} 43 | */ 44 | const tools = [ 45 | { 46 | groupName: '图文类', 47 | componentList: [{ 48 | title: '轮播 (普通数组)', 49 | maxNum: 2, 50 | viewWidth: '1920px', 51 | icon: 'el-icon-picture', 52 | name: 'CarouselImg', 53 | componentPack: componentPackCarouselImg 54 | }, { 55 | title: '秒杀商品', 56 | maxNum: 3, 57 | icon: 'el-icon-picture', 58 | name: 'FlashSaleGoodsList', 59 | componentPack: componentPackFlashSaleGoodsList 60 | }, { 61 | title: '多图(5)', 62 | maxNum: 5, 63 | icon: 'el-icon-picture', 64 | name: 'MultipleImg5', 65 | componentPack: componentPackMultipleImg5 66 | }, { 67 | title: '多图(2-3)', 68 | maxNum: 10, 69 | icon: 'el-icon-s-grid', 70 | name: 'MultipleImg2_3', 71 | componentPack: componentPackMultipleImg23 72 | }, { 73 | title: '多图(1-3)', 74 | maxNum: 10, 75 | icon: 'el-icon-s-grid', 76 | name: 'MultipleImg1_3', 77 | componentPack: componentPackMultipleImg13 78 | }, { 79 | title: '分类管区', 80 | maxNum: 10, 81 | icon: 'el-icon-s-grid', 82 | name: 'CategoryGoods', 83 | componentPack: componentPackCategoryGoods 84 | }, { 85 | title: '纯文本', 86 | maxNum: 20, 87 | icon: 'el-icon-notebook-1', 88 | name: 'Text', 89 | componentPack: componentPackText 90 | }] 91 | }, 92 | { 93 | groupName: '商品类', 94 | componentList: [{ 95 | title: '全部商品', 96 | maxNum: 1, 97 | icon: 'el-icon-s-goods', 98 | componentPack: componentPackAllGoodsList, 99 | name: 'AllGoodsList', 100 | additional: { 101 | bottomDisplay: true, 102 | unRemove: true // 不可移除 103 | } 104 | }, { 105 | title: '推荐商品', 106 | maxNum: 1, 107 | icon: 'el-icon-s-goods', 108 | name: 'RecommendedGoodsList', 109 | componentPack: componentPackRecommendedGoodsList 110 | }] 111 | }, 112 | { 113 | groupName: '营销互动类', 114 | componentList: [{ 115 | title: '优惠券', 116 | maxNum: 1, 117 | icon: 'el-icon-s-ticket', 118 | name: 'Coupon', 119 | componentPack: componentPackCoupon 120 | }] 121 | } 122 | ]; 123 | 124 | export default tools; 125 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/EditorHeader.vue: -------------------------------------------------------------------------------- 1 | 51 | 52 | 110 | 111 | 139 | -------------------------------------------------------------------------------- /src/demo-common/schemaTypes/18.AnyOf(联动)/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/5/19 15:00. 3 | */ 4 | 5 | export default { 6 | schema: { 7 | type: 'object', 8 | required: [ 9 | 'age' 10 | ], 11 | properties: { 12 | age: { 13 | title: '测试基础类型 anyOf', 14 | anyOf: [ 15 | { 16 | title: '测试基础类型 anyOf 5的倍数', 17 | type: 'integer', 18 | multipleOf: 5 19 | }, 20 | { 21 | title: '测试基础类型 anyOf 3的倍数', 22 | type: 'integer', 23 | multipleOf: 3 24 | } 25 | ], 26 | anyOfSelect: { 27 | 'ui:widget': 'RadioWidget', 28 | 'ui:title': '选择选项', 29 | 'ui:options': { 30 | } 31 | } 32 | }, 33 | test: { 34 | title: '测试 const anyOf', 35 | type: 'string', 36 | anyOf: [ 37 | { 38 | title: 'schema option1', 39 | const: '111' 40 | }, 41 | { 42 | 'ui:title': 'ui-option2', 43 | const: '222' 44 | } 45 | ] 46 | }, 47 | items: { 48 | title: '测试OneOf Array Items', 49 | type: 'array', 50 | items: { 51 | type: 'object', 52 | anyOf: [ 53 | { 54 | properties: { 55 | foo: { 56 | type: 'string' 57 | } 58 | } 59 | }, 60 | { 61 | properties: { 62 | bar: { 63 | type: 'string' 64 | } 65 | } 66 | } 67 | ] 68 | } 69 | } 70 | }, 71 | anyOfSelect: { 72 | 'ui:widget': 'RadioWidget', 73 | 'ui:title': '测试 anyOf object', 74 | 'ui:options': { 75 | style: { 76 | // width: '300px', 77 | } 78 | } 79 | }, 80 | anyOf: [ 81 | { 82 | 'ui:showTitle': true, 83 | title: 'First method of identification', 84 | properties: { 85 | type: { 86 | 'ui:hidden': true, 87 | type: 'string', 88 | default: 'userName', 89 | const: 'userName' 90 | }, 91 | firstName: { 92 | type: 'string', 93 | title: 'First name', 94 | default: 'Chuck' 95 | }, 96 | lastName: { 97 | type: 'string', 98 | title: 'Last name' 99 | } 100 | } 101 | }, 102 | { 103 | 'ui:showTitle': true, 104 | title: 'Second method of identification', 105 | properties: { 106 | type: { 107 | 'ui:hidden': true, 108 | type: 'string', 109 | default: 'id', 110 | const: 'id' 111 | }, 112 | firstName: { 113 | type: 'string', 114 | title: 'First name' 115 | }, 116 | idCode: { 117 | type: 'string', 118 | title: 'ID code', 119 | default: 'Default id' 120 | } 121 | } 122 | } 123 | ] 124 | }, 125 | uiSchema: { 126 | }, 127 | formData: { 128 | } 129 | }; 130 | -------------------------------------------------------------------------------- /src/demo-common/schemaTypes/42.uiSchema-ui-hidden(联动)/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/5/19 15:41. 3 | */ 4 | 5 | export default { 6 | schema: { 7 | title: '使用ui-schema配置ui:hidden表达式', 8 | description: '实现类ali formRender的配置方法, 如下参数:
    rootFormData:根节点的值
    parentFormData:当前父节点的值', 9 | type: 'object', 10 | properties: { 11 | case1: { 12 | title: '整体隐藏', 13 | type: 'object', 14 | properties: { 15 | showMore: { 16 | title: '显示更多', 17 | type: 'boolean', 18 | default: false 19 | }, 20 | x1: { 21 | title: '输入框1', 22 | type: 'string', 23 | 'ui:hidden': '{{rootFormData.case1.showMore === false}}' 24 | }, 25 | x2: { 26 | title: '输入框2', 27 | type: 'string', 28 | 'ui:hidden': '{{rootFormData.case1.showMore === false}}' 29 | } 30 | } 31 | }, 32 | case3: { 33 | title: '列表/显示不同组件', 34 | type: 'object', 35 | properties: { 36 | ruleList: { 37 | title: '球员筛选', 38 | type: 'array', 39 | items: { 40 | type: 'object', 41 | properties: { 42 | attr: { 43 | title: '标准', 44 | type: 'string', 45 | enum: [ 46 | 'goal', 47 | 'league' 48 | ], 49 | enumNames: [ 50 | '入球数', 51 | '所在联盟' 52 | ], 53 | 'ui:width': '40%' 54 | }, 55 | relation: { 56 | title: '-', 57 | type: 'string', 58 | enum: [ 59 | '>', 60 | '<', 61 | '=' 62 | ], 63 | 'ui:hidden': "{{parentFormData.attr === 'league'}}", 64 | 'ui:width': '20%' 65 | }, 66 | goal: { 67 | title: '入球数', 68 | type: 'string', 69 | pattern: '^[0-9]+$', 70 | message: { 71 | pattern: '输入正确得分' 72 | }, 73 | 'ui:hidden': "{{parentFormData.attr !== 'goal'}}", 74 | 'ui:width': '40%' 75 | }, 76 | league: { 77 | title: '名称', 78 | type: 'string', 79 | enum: [ 80 | 'a', 81 | 'b', 82 | 'c' 83 | ], 84 | enumNames: [ 85 | '西甲', 86 | '英超', 87 | '中超' 88 | ], 89 | 'ui:hidden': "{{parentFormData.attr !== 'league'}}", 90 | 'ui:width': '40%' 91 | } 92 | } 93 | } 94 | } 95 | } 96 | } 97 | } 98 | } 99 | }; 100 | -------------------------------------------------------------------------------- /src/demo-common/components/component-with-dialog/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/12/30 16:53. 3 | * 通过api的形式弹出一个组件 4 | * 若需要响应式参数 componentProps、dialogProps 使用引用的形式传递 5 | * 例 6 | componentWithDialog({ 7 | VueComponent: { 8 | template: '
    xxxx
    ' 9 | }, 10 | dialogProps: this.dialogProps 11 | }); 12 | */ 13 | 14 | import Vue from 'vue'; 15 | 16 | export default ({ 17 | VueComponent = null, 18 | injectionOptions = {}, 19 | dialogProps = {}, 20 | dialogListeners = {}, 21 | componentProps = {}, 22 | componentListeners = {} 23 | } = {}) => { 24 | if (!VueComponent) { 25 | throw new Error('必须的参数:vueComponent'); 26 | } 27 | 28 | // 测试能否响应式数据 29 | // const DialogConstructor = Vue.extend(Dialog); 30 | // const instance = new DialogConstructor({ 31 | // el: document.createElement('div') 32 | // }); 33 | // const h = vm.$createElement; 34 | // const vMessage = h('div', [ 35 | // h('p', vm.dialogProps.title), 36 | // ]); 37 | // instance.$slots.default = [vMessage]; 38 | // document.body.appendChild(instance.$el); 39 | // Vue.nextTick(() => { 40 | // instance.visible = true; 41 | // }); 42 | 43 | const genDefaultDialogProps = () => ({ 44 | title: '弹窗标题', 45 | closeOnClickModal: true, 46 | width: '800px' 47 | }); 48 | 49 | const DialogComponentConstructor = Vue.extend({ 50 | name: 'DialogComponentConstructor', 51 | components: { 52 | VueComponent 53 | }, 54 | data() { 55 | return { 56 | componentListeners, 57 | curDialogListeners: { 58 | ...dialogListeners, 59 | closed: (...args) => { 60 | // 传入的方法先执行 61 | if (dialogListeners.closed) { 62 | dialogListeners.closed.apply(null, args); 63 | } 64 | 65 | // 释放掉dialog 66 | this.handleClosed(); 67 | } 68 | }, 69 | visible: false 70 | }; 71 | }, 72 | computed: { 73 | componentProps() { 74 | return componentProps; 75 | }, 76 | curDialogProps() { 77 | return Object.assign(genDefaultDialogProps(), dialogProps); 78 | }, 79 | }, 80 | created() { 81 | this.hashChangeFn = () => { 82 | this.handleClosed(); 83 | }; 84 | 85 | // hashChange ,组件单独注入需要手动销毁 86 | window.addEventListener('hashchange', this.hashChangeFn, false); 87 | }, 88 | beforeDestroy() { 89 | console.log('DialogComponent beforeDestroy'); 90 | }, 91 | methods: { 92 | show() { 93 | this.visible = true; 94 | }, 95 | close() { 96 | this.visible = false; 97 | }, 98 | handleClosed() { 99 | window.removeEventListener('hashchange', this.hashChangeFn); 100 | this.$destroy(); 101 | this.$el.parentElement.removeChild(this.$el); 102 | } 103 | }, 104 | render(h) { 105 | const self = this; 106 | return h('el-dialog', { 107 | on: { 108 | ...this.curDialogListeners, 109 | 'update:visible': function update(val) { 110 | self.visible = val; 111 | } 112 | }, 113 | props: { 114 | visible: this.visible, 115 | ...this.curDialogProps, 116 | }, 117 | }, [ 118 | h(VueComponent, { 119 | on: this.componentListeners, 120 | props: this.componentProps, 121 | }) 122 | ]); 123 | }, 124 | }); 125 | 126 | const componentDialog = (new DialogComponentConstructor({ 127 | ...injectionOptions, 128 | })).$mount(); 129 | document.body.appendChild(componentDialog.$el); 130 | 131 | componentDialog.$nextTick(() => { 132 | componentDialog.show(); 133 | }); 134 | 135 | return componentDialog; 136 | }; 137 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/EditorToolBar.vue: -------------------------------------------------------------------------------- 1 | 49 | 50 | 87 | 88 | 139 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2019/10/25 15:42. 3 | */ 4 | 5 | const path = require('path'); 6 | const ManifestPlugin = require('webpack-manifest-plugin'); 7 | const chalk = require('chalk'); 8 | 9 | const log = require('./scripts/log'); 10 | const envConfig = require('./scripts/envConfig').getConfig(); 11 | 12 | const { 13 | entries, 14 | openPage 15 | } = require('./scripts/entry.js')({ 16 | chunks: ['user-runtime', 'user-vendors-polyfill'] 17 | }); 18 | 19 | log({ 20 | data: chalk.green(openPage), 21 | des: 'openPage' 22 | }); 23 | 24 | log({ 25 | data: Object.entries(entries).map(([key, value]) => ({ 26 | [key]: value.entry 27 | })), 28 | des: 'entry' 29 | }); 30 | 31 | const isProduction = process.env.NODE_ENV === 'production'; 32 | 33 | // config var 34 | const outputDir = path.resolve(__dirname, './dist'); 35 | 36 | module.exports = { 37 | // cdn 38 | publicPath: isProduction ? '/' : '/', 39 | 40 | // 资源目录 41 | outputDir, 42 | 43 | assetsDir: 'static', 44 | 45 | filenameHashing: true, 46 | 47 | pages: entries, 48 | 49 | lintOnSave: true, 50 | 51 | runtimeCompiler: true, 52 | 53 | transpileDependencies: [], 54 | 55 | productionSourceMap: false, 56 | 57 | configureWebpack: (config) => { 58 | config.externals = { 59 | vue: 'Vue', 60 | ELEMENT: 'ELEMENT', 61 | VueRouter: 'VueRouter', 62 | }; 63 | config.resolve.alias = { 64 | ...config.resolve.alias, 65 | 'demo-common': path.resolve(__dirname, './src/demo-common'), 66 | // '@lljj/vue-json-schema-form': '@lljj/vue-json-schema-form/src/index', 67 | // '@lljj/vue2-form-iview3': '@lljj/vue2-form-iview3/src/index', 68 | }; 69 | }, 70 | 71 | // webpack 链接 API,用于生成和修改 webpack 配置 72 | // https://github.com/mozilla-neutrino/webpack-chain 73 | chainWebpack: (config) => { 74 | // 添加runtime 75 | config.optimization.runtimeChunk({ 76 | name: 'user-runtime' 77 | }); 78 | 79 | // 指定文件提取 80 | const splitConfig = { 81 | cacheGroups: { 82 | vendors: { 83 | name: 'user-vendors-polyfill', 84 | chunks: 'initial', 85 | priority: 12, 86 | test: module => /[\\/]node_modules[\\/]/.test(module.context) || /components\\ElementUi/.test(module.context), 87 | }, 88 | asyncVendor: { 89 | name: 'chunk-vendors-async', 90 | chunks: 'async', 91 | priority: 8, 92 | minChunks: 5, 93 | } 94 | } 95 | }; 96 | 97 | config.optimization.splitChunks(splitConfig); 98 | 99 | // js 文件名调整 100 | if (isProduction) { 101 | // 资源表 102 | config.plugin('manifest').use(ManifestPlugin, [{ 103 | fileName: 'manifest.json', 104 | filter: (obj) => { 105 | const ext = path.extname(obj.name); 106 | const includeExts = ['.js', '.css']; 107 | return includeExts.includes(ext) && !obj.name.includes('chunk-'); 108 | } 109 | }]); 110 | } 111 | 112 | // report 113 | if (envConfig.report) { 114 | // eslint-disable-next-line global-require 115 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 116 | config.plugin('bundle-analyzer').use(BundleAnalyzerPlugin); 117 | } 118 | 119 | // 移除 prefetch 插件 120 | Object.keys(entries).forEach((item) => { 121 | config.plugins.delete(`prefetch-${item}`); 122 | }); 123 | }, 124 | 125 | css: { 126 | requireModuleExtension: true, 127 | sourceMap: !isProduction, 128 | extract: isProduction 129 | }, 130 | 131 | // All options for webpack-dev-server are supported 132 | // https://webpack.js.org/configuration/dev-server/ 133 | devServer: { 134 | clientLogLevel: 'info', 135 | open: true, 136 | openPage, 137 | port: 8800, 138 | host: '127.0.0.1', 139 | overlay: { 140 | warnings: false, 141 | errors: true 142 | }, 143 | publicPath: '/', 144 | proxy: { 145 | '/api-dev': { 146 | target: 'http://www.api.com', 147 | hot: true, 148 | open: true, 149 | contentBase: false, 150 | historyApiFallback: false, 151 | changeOrigin: true, 152 | pathRewrite: { 153 | '^/api-dev': '' 154 | } 155 | } 156 | } 157 | }, 158 | 159 | // https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa 160 | pwa: {}, 161 | 162 | // 第三方插件配置 163 | pluginOptions: {} 164 | }; 165 | -------------------------------------------------------------------------------- /src/demo-common/css/variable.css: -------------------------------------------------------------------------------- 1 | :root { 2 | /* base color 3 | -------------------------- */ 4 | --color-white : #FFF; 5 | --color-black : #000; 6 | 7 | //--color-primary : #AFA37E; 8 | --color-primary : #2b9939; 9 | --color-primary-light : #EAE5D4; 10 | --color-primary-darken : #978755; 11 | 12 | --color-success : #5BBA69; 13 | --color-warning : #FFB403; 14 | --color-danger : #FF5757; 15 | --color-error : #FF001F; 16 | 17 | /* layout navigate 18 | -------------------------- */ 19 | --nav-background-color : #3C3C3C; 20 | --nav-background-color-hover : #585858; 21 | 22 | /* link 23 | -------------------------- */ 24 | --color-link-base : #2774FF; 25 | 26 | /* checkbox radio 27 | -------------------------- */ 28 | --checkbox-color : #61A5FF; 29 | 30 | /* text color 31 | -------------------------- */ 32 | --color-text-base : #000; 33 | --color-text-second : #333; 34 | --color-text-third : #666; 35 | --color-text-light : #999; 36 | --color-text-placeholder : #999; 37 | --color-text-disabled : #D8D8D8; 38 | --color-text-selected : #FF8A00; 39 | 40 | /* icon 41 | -------------------------- */ 42 | --color-icon-base : #999; 43 | --color-icon-info : var(--color-primary); 44 | --color-icon-success : var(--color-success); 45 | --color-icon-error : var(--color-danger); 46 | --color-icon-warning : var(--color-warning); 47 | 48 | /* background-color 49 | -------------------------- */ 50 | --background-color-base : #F2F2F2; 51 | --background-color-selected : #F2F2F2; 52 | --background-color-hover : #F7F7F7; 53 | --background-color-light : #FBFBFB; 54 | --background-color-lighter : #FAFAFA; 55 | 56 | /* border 57 | -------------------------- */ 58 | --border-base-style : 1px solid var(--border-color-base); 59 | --border-radius : 4px; 60 | --border-color-base : #DDD; 61 | --border-color-light : #D8D8D8; 62 | --border-color-lighter : #EEE; 63 | 64 | /* Font 65 | -------------------------- */ 66 | --font-size-base : 14px; 67 | --font-size-small : 12px; 68 | --font-size-large : 14px; 69 | --font-size-larger : 16px; 70 | --font-size-largest : 18px; 71 | --font-weight-medium : 500; 72 | --font-family : OpenSans,Arial,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,SimSun,sans-serif; 73 | --font-line-height : 1; 74 | 75 | /* Animation 76 | -------------------------- */ 77 | --animation-transition-time : 300ms; 78 | --animation-transition-timing : ease-in-out; 79 | 80 | /* Layout 81 | -------------------------- */ 82 | --layout-safe-width : 1200px; 83 | --layout-better-width : 1440px; 84 | 85 | --mainC: #000; 86 | --emphasizeC: #FF8A00; 87 | --warningC: #f30240; 88 | --normalC: #666; 89 | --assistC: #999; 90 | --disableC: #CCC; 91 | --borderC: #EEE; 92 | --assistBgC: #F9F9F9; 93 | --contentWidth: 980px; /*内容区宽度*/ 94 | } 95 | 96 | /* 反馈颜色 */ 97 | @define-mixin actionFb $color { 98 | background-color: $color; 99 | transition: background-color .5s ease; 100 | &:hover{ 101 | background-color: color($(color) alpha(-20%)); 102 | } 103 | } 104 | 105 | /* css绘制三角形 */ 106 | @define-mixin triangle $width { 107 | width: 0; 108 | height: 0; 109 | border-style: solid; 110 | border-color: transparent; 111 | border-width: $(width); 112 | } 113 | 114 | /* 多行文字超过部分显示 "..." */ 115 | @define-mixin multiline $lineHeight, $line { 116 | display: -webkit-box !important; 117 | height: calc($lineHeight * $line); 118 | line-height: $lineHeight; 119 | overflow: hidden; 120 | -webkit-box-orient: vertical; 121 | -webkit-line-clamp: $line; 122 | } 123 | 124 | /* 滑过阴影 */ 125 | @define-mixin hoverShadow { 126 | transition: box-shadow .2s linear; 127 | &:hover{ 128 | box-shadow: 0 2px 10px var(--color-boxshadow); 129 | } 130 | } 131 | 132 | /* 单行文本超过部分显示 "..." */ 133 | @define-mixin nowrap { 134 | overflow: hidden; 135 | white-space: nowrap; 136 | text-overflow: ellipsis; 137 | word-wrap: normal; 138 | word-break: normal; 139 | } 140 | 141 | 142 | @define-mixin fontBase{ 143 | font-family: Montserrat, Arial, Helvetica, sans-serif; 144 | } 145 | 146 | @define-mixin fontBold{ 147 | font-weight: bold; 148 | } 149 | -------------------------------------------------------------------------------- /src/demo-common/components/CodeEditorV2.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 165 | 166 | 177 | -------------------------------------------------------------------------------- /src/demo-common/components/CodeEditor.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 165 | 166 | 177 | -------------------------------------------------------------------------------- /src/demo-common/schemaTypes/15.Widgets/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/5/18 13:02. 3 | */ 4 | 5 | export default { 6 | schema: { 7 | title: 'Widgets', 8 | type: 'object', 9 | properties: { 10 | stringFormats: { 11 | type: 'object', 12 | title: 'String formats', 13 | required: ['email', 'uri'], 14 | properties: { 15 | email: { 16 | title: 'Email', 17 | type: 'string', 18 | format: 'email', 19 | }, 20 | uri: { 21 | title: 'Uri', 22 | type: 'string', 23 | format: 'uri', 24 | }, 25 | }, 26 | }, 27 | boolean: { 28 | type: 'object', 29 | title: 'Boolean field', 30 | properties: { 31 | default: { 32 | type: 'boolean', 33 | title: 'checkbox (default)', 34 | description: 'This is the checkbox-description', 35 | }, 36 | radio: { 37 | type: 'boolean', 38 | title: 'radio buttons', 39 | description: 'This is the radio-description', 40 | }, 41 | select: { 42 | type: 'boolean', 43 | title: 'select box', 44 | description: 'This is the select-description', 45 | }, 46 | }, 47 | }, 48 | string: { 49 | type: 'object', 50 | title: 'String field', 51 | properties: { 52 | default: { 53 | type: 'string', 54 | title: 'text input (default)', 55 | }, 56 | textarea: { 57 | type: 'string', 58 | title: 'textarea', 59 | }, 60 | color: { 61 | type: 'string', 62 | title: 'color picker', 63 | format: 'color', 64 | default: '#151ce6', 65 | }, 66 | }, 67 | }, 68 | secret: { 69 | type: 'string', 70 | default: "I'm a hidden string.", 71 | }, 72 | disabled: { 73 | type: 'string', 74 | title: 'A disabled field', 75 | default: 'I am disabled.', 76 | }, 77 | readonly: { 78 | type: 'string', 79 | title: 'A readonly field', 80 | default: 'I am read-only.', 81 | }, 82 | widgetOptions: { 83 | title: 'Custom widget with options', 84 | type: 'string', 85 | default: 'I am yellow', 86 | }, 87 | selectWidgetOptions: { 88 | title: 'Custom select widget with options', 89 | type: 'string', 90 | enum: ['foo', 'bar'], 91 | enumNames: ['Foo', 'Bar'], 92 | }, 93 | }, 94 | }, 95 | uiSchema: { 96 | boolean: { 97 | radio: { 98 | 'ui:widget': 'RadioWidget', 99 | }, 100 | select: { 101 | 'ui:widget': 'SelectWidget', 102 | }, 103 | }, 104 | string: { 105 | textarea: { 106 | 'ui:options': { 107 | type: 'textarea', 108 | rows: 6, 109 | autosize: { 110 | minRows: 2, 111 | maxRows: 4 112 | } 113 | }, 114 | }, 115 | }, 116 | secret: { 117 | 'ui:widget': 'HiddenWidget', 118 | }, 119 | disabled: { 120 | 'ui:disabled': true, 121 | }, 122 | readonly: { 123 | 'ui:readonly': true, 124 | }, 125 | widgetOptions: { 126 | 'ui:options': { 127 | style: { 128 | boxShadow: '0 0 6px 2px yellow' 129 | }, 130 | class: { 131 | className: true 132 | } 133 | }, 134 | }, 135 | selectWidgetOptions: { 136 | 'ui:options': { 137 | style: { 138 | boxShadow: '0 0 6px 2px pink' 139 | } 140 | }, 141 | }, 142 | }, 143 | formData: { 144 | stringFormats: { 145 | email: 'chuck@norris.net', 146 | uri: 'http://chucknorris.com/', 147 | }, 148 | boolean: { 149 | default: true, 150 | radio: true, 151 | select: true, 152 | }, 153 | string: { 154 | default: 'Hello...', 155 | textarea: '... World', 156 | }, 157 | secret: "I'm a hidden string.", 158 | }, 159 | errorSchema: { 160 | stringFormats: { 161 | email: { 162 | 'err:required': '邮箱地址必须输入' 163 | } 164 | } 165 | } 166 | }; 167 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/config/mDefaultItems.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/4/29 11:58. 3 | */ 4 | 5 | export default [ 6 | { 7 | name: 'MTestModule', 8 | value: { 9 | txt: '自定义Form表单测试' 10 | } 11 | }, 12 | { 13 | name: 'MCarouselImg', 14 | value: { 15 | imgList: [ 16 | { 17 | imgUrl: 'https://gw.alicdn.com/imgextra/i1/1734167/O1CN01eXdllZ1geX1zdbBLa_!!1734167-0-lubanu.jpg_790x10000Q75.jpg_.webp', 18 | imgLink: 'https://www.jd.com' 19 | }, 20 | { 21 | imgUrl: 'https://img.alicdn.com/tps/i4///img.alicdn.com/tps/i4//TB1CDhKUvb2gK0jSZK9SuuEgFXa.jpg_790x10000Q75.jpg_.webp', 22 | imgLink: 'https://www.jd.com' 23 | }, 24 | { 25 | imgUrl: 'https://gw.alicdn.com/imgextra/i1/1800474/O1CN01lXTksu1FN8MIE9JZb_!!1800474-0-lubanu.jpg_790x10000Q75.jpg_.webp', 26 | imgLink: 'https://www.jd.com' 27 | }, 28 | { 29 | imgUrl: 'https://img.alicdn.com/tps/i4///img.alicdn.com/tps/i4//TB1CDhKUvb2gK0jSZK9SuuEgFXa.jpg_790x10000Q75.jpg_.webp', 30 | imgLink: 'https://www.jd.com' 31 | } 32 | ] 33 | } 34 | }, 35 | { 36 | name: 'MCategoryList', 37 | value: { 38 | imgList: [ 39 | { 40 | img: { 41 | imgUrl: 'https://gw.alicdn.com/tfs/TB1ISdWSFXXXXbFXXXXXXXXXXXX-146-147.png_110x10000.jpg_.webp', 42 | imgLink: 'https://www.jd.com' 43 | }, 44 | name: '苏宁' 45 | }, 46 | { 47 | name: '天猫超市', 48 | img: { 49 | imgUrl: 'https://gw.alicdn.com/tfs/TB1wSoFa5qAXuNjy1XdXXaYcVXa-196-196.png?avatar=1_110x10000.jpg_.webp', 50 | imgLink: 'https://www.jd.com' 51 | } 52 | }, 53 | { 54 | name: '天猫国际', 55 | img: { 56 | imgUrl: 'https://gw.alicdn.com/tfs/TB1Jc0fSFXXXXXTapXXXXXXXXXX-146-147.png_110x10000.jpg_.webp', 57 | imgLink: 'https://www.jd.com' 58 | } 59 | }, 60 | { 61 | name: '聚划算', 62 | img: { 63 | imgUrl: 'https://gw.alicdn.com/tfs/TB15lhOSFXXXXaKXpXXXXXXXXXX-147-147.png_110x10000.jpg_.webp', 64 | imgLink: 'https://www.jd.com' 65 | } 66 | }, 67 | { 68 | name: '分类', 69 | img: { 70 | imgUrl: 'https://gw.alicdn.com/tfs/TB12CFXSFXXXXcpapXXXXXXXXXX-146-147.png_110x10000.jpg_.webp', 71 | imgLink: 'https://www.jd.com' 72 | } 73 | } 74 | ] 75 | } 76 | }, 77 | { 78 | name: 'MText', 79 | value: { 80 | txt: '推荐商品', 81 | txtColor: '#e46028' 82 | } 83 | }, 84 | { 85 | name: 'MRecommendGoods', 86 | value: { 87 | title: '推荐商品', 88 | imgList: [ 89 | { 90 | imgUrl: 'https://img.alicdn.com/bao/uploaded/i2/1714128138/O1CN017m1aWc29zFn8OMOqR_!!1714128138.jpg_400x400q60.jpg', 91 | imgLink: 'https://www.jd.com' 92 | }, 93 | { 94 | imgUrl: 'https://img.alicdn.com/tfs/TB1JPXDXwoQMeJjy0FpXXcTxpXa-235-316.png_320x5000q100.jpg_.webp', 95 | imgLink: 'https://www.jd.com' 96 | }, 97 | { 98 | imgUrl: 'https://gw.alicdn.com/bao/uploaded/i1/725677994/O1CN01n4SRoc28vIm75wP4r_!!0-item_pic.jpg', 99 | imgLink: 'https://www.jd.com' 100 | }, 101 | { 102 | imgUrl: 'https://gw.alicdn.com/bao/uploaded/i4/725677994/O1CN01TMAv0N28vIm7J4L2b_!!0-item_pic.jpg', 103 | imgLink: 'https://www.jd.com' 104 | } 105 | ] 106 | } 107 | }, 108 | { 109 | name: 'MText', 110 | value: { 111 | txt: '抢购商品', 112 | txtColor: '#0A96ED' 113 | } 114 | }, 115 | { 116 | name: 'MRecommendGoods', 117 | value: { 118 | title: '抢购商品', 119 | imgList: [ 120 | { 121 | imgUrl: 'https://img.alicdn.com/bao/uploaded/i1/1714128138/O1CN01is1MtI29zFo5MCOY6_!!1714128138.jpg_400x400q60.jpg', 122 | imgLink: 'https://www.jd.com' 123 | }, 124 | { 125 | imgUrl: 'https://img.alicdn.com/bao/uploaded/i3/1714128138/O1CN01KaaLO129zFnqp4CQf_!!1714128138.jpg_400x400q60.jpg', 126 | imgLink: 'https://www.jd.com' 127 | }, 128 | { 129 | imgUrl: 'https://img.alicdn.com/bao/uploaded/i2/2616970884/O1CN01X6Be1z1IOukJ1YEzk_!!2616970884.jpg_400x400q60.jpg', 130 | imgLink: 'https://www.jd.com' 131 | }, 132 | { 133 | imgUrl: 'https://img.alicdn.com/bao/uploaded/i3/2411055336/O1CN01wgTHNw1pHw1DLbLaE_!!2411055336.jpg_400x400q60.jpg', 134 | imgLink: 'https://www.jd.com' 135 | } 136 | ] 137 | } 138 | }, 139 | ]; 140 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/MultipleImg1_3/component/View.vue: -------------------------------------------------------------------------------- 1 | 107 | 108 | 130 | 131 | 175 | -------------------------------------------------------------------------------- /src/demo-common/schemaTypes/17.OneOf/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/5/19 15:00. 3 | */ 4 | 5 | 6 | // setTimeout(() => { 7 | // const fnList = [ 8 | // () => 1, 9 | // p => Promise.resolve(p + 1), 10 | // p => p + 2, 11 | // p => Promise.resolve(p + 3), 12 | // p => Promise.resolve(p + 4), 13 | // p => p + 5, 14 | // p => p 15 | // ]; 16 | // 17 | // let preResult; 18 | // while (fnList.length > 0) { 19 | // const curFn = fnList.shift(); 20 | // if (preResult) { 21 | // preResult = preResult.then((res) => { 22 | // console.log(res); 23 | // return Promise.resolve(curFn(res)); 24 | // }); 25 | // } else { 26 | // // 首次调用无参数 27 | // preResult = Promise.resolve(curFn()); 28 | // } 29 | // } 30 | // }, 1000); 31 | 32 | 33 | export default { 34 | schema: { 35 | type: 'object', 36 | required: [ 37 | 'age' 38 | ], 39 | properties: { 40 | // age: { 41 | // title: '测试基础类型 oneOf', 42 | // oneOf: [ 43 | // { 44 | // title: '测试基础类型 oneOf 5的倍数', 45 | // type: 'integer', 46 | // multipleOf: 5 47 | // }, 48 | // { 49 | // title: '测试基础类型 oneOf 3的倍数', 50 | // type: 'integer', 51 | // multipleOf: 3 52 | // } 53 | // ] 54 | // }, 55 | // test: { 56 | // title: '测试 const OneOf', 57 | // type: 'string', 58 | // oneOf: [ 59 | // { 60 | // const: '111' 61 | // }, 62 | // { 63 | // const: '222' 64 | // } 65 | // ] 66 | // }, 67 | items: { 68 | title: '测试OneOf Array Items', 69 | type: 'array', 70 | items: { 71 | type: 'object', 72 | oneOf: [ 73 | { 74 | properties: { 75 | foo: { 76 | type: 'string' 77 | } 78 | } 79 | }, 80 | { 81 | properties: { 82 | bar: { 83 | type: 'string' 84 | } 85 | } 86 | } 87 | ] 88 | } 89 | } 90 | }, 91 | // oneOf: [ 92 | // { 93 | // title: 'First method of identification', 94 | // required: [ 95 | // 'firstName' 96 | // ], 97 | // properties: { 98 | // firstName: { 99 | // type: 'string', 100 | // title: 'First name', 101 | // default: 'Chuck' 102 | // }, 103 | // lastName: { 104 | // type: 'string', 105 | // title: 'Last name' 106 | // } 107 | // } 108 | // }, 109 | // { 110 | // title: 'Second method of identification', 111 | // required: [ 112 | // 'idCode' 113 | // ], 114 | // properties: { 115 | // idCode: { 116 | // type: 'string', 117 | // title: 'ID code', 118 | // default: 'Default id' 119 | // } 120 | // } 121 | // } 122 | // ] 123 | }, 124 | // uiSchema: { 125 | // oneOfSelect: { 126 | // 'ui:title': '选择anyOf 选项', 127 | // 'ui:widget': 'RadioWidget' 128 | // }, 129 | // oneOf: { 130 | // 'ui:widget': 'RadioWidget', 131 | // 'ui:title': '测试 OneOf object', 132 | // 'ui:options': { 133 | // style: { 134 | // // width: '300px', 135 | // } 136 | // } 137 | // }, 138 | // age: { 139 | // 'ui:options': { 140 | // // widget: 'el-slider', 141 | // }, 142 | // oneOfSelect: { 143 | // 'ui:title': '选择选项 (uiSchema -> oneOfSelect)', 144 | // 'ui:widget': 'RadioWidget', 145 | // 'ui:options': { 146 | // style: { 147 | // width: '100%' 148 | // } 149 | // } 150 | // }, 151 | // oneOf: [ 152 | // { 153 | // 'ui:title': '5的倍数 (uiSchema)', 154 | // 'ui:widget': 'el-slider', 155 | // }, 156 | // { 157 | // 'ui:title': '3的倍数 (uiSchema)' 158 | // } 159 | // ] 160 | // }, 161 | // test: { 162 | // 'ui:widget': 'RadioWidget', 163 | // } 164 | // }, 165 | formData: { 166 | age: 27, 167 | test: '222', 168 | firstName: '11', 169 | lastName: '11', 170 | items: [ 171 | { 172 | foo: '11111' 173 | }, 174 | { 175 | bar: '222222222' 176 | } 177 | ] 178 | }, 179 | errorSchema: { 180 | } 181 | }; 182 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/MultipleImg2_3/View.vue: -------------------------------------------------------------------------------- 1 | 128 | 129 | 154 | 155 | 212 | -------------------------------------------------------------------------------- /src/pages/vue-editor/views/editor/viewComponents/CategoryGoods/View.vue: -------------------------------------------------------------------------------- 1 | 79 | 80 | 106 | 107 | 222 | -------------------------------------------------------------------------------- /src/demo-common/schemaTypes/13.Arrays/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Liu.Jun on 2020/5/15 14:07. 3 | */ 4 | 5 | export default { 6 | schema: { 7 | definitions: { 8 | Thing: { 9 | type: 'object', 10 | properties: { 11 | name: { 12 | title: 'Thing', 13 | type: 'string', 14 | default: 'Default name', 15 | }, 16 | }, 17 | }, 18 | }, 19 | type: 'object', 20 | properties: { 21 | listOfStrings: { 22 | type: 'array', 23 | title: 'A list of strings', 24 | 'ui:options': { 25 | showIndexNumber: true 26 | }, 27 | items: { 28 | title: 'Input string', 29 | type: 'string', 30 | default: 'bazinga', 31 | }, 32 | }, 33 | multipleChoicesList: { 34 | type: 'array', 35 | title: 'A multiple choices list', 36 | items: { 37 | type: 'string', 38 | enum: ['foo', 'bar', 'fuzz', 'qux'], 39 | }, 40 | uniqueItems: true, 41 | }, 42 | fixedItemsList: { 43 | type: 'array', 44 | title: 'A list of fixed items', 45 | items: [ 46 | { 47 | title: 'A string value', 48 | type: 'string', 49 | default: 'lorem ipsum', 50 | }, 51 | { 52 | title: 'a boolean value', 53 | type: 'boolean', 54 | }, 55 | { 56 | title: 'a string value', 57 | type: 'string', 58 | }, 59 | { 60 | title: 'a number value', 61 | type: 'number', 62 | } 63 | ], 64 | additionalItems: { 65 | title: 'Additional item', 66 | type: 'number', 67 | }, 68 | }, 69 | minItemsList: { 70 | type: 'array', 71 | title: 'A list with a minimal number of items', 72 | minItems: 3, 73 | items: { 74 | $ref: '#/definitions/Thing', 75 | }, 76 | }, 77 | defaultsAndMinItems: { 78 | type: 'array', 79 | title: 'List and item level defaults', 80 | minItems: 5, 81 | default: ['carp', 'trout', 'bream'], 82 | items: { 83 | title: 'Default unidentified', 84 | type: 'string', 85 | default: 'unidentified', 86 | }, 87 | }, 88 | nestedList: { 89 | type: 'array', 90 | title: 'Nested list', 91 | items: { 92 | type: 'array', 93 | title: 'Inner list', 94 | items: { 95 | title: 'Inner Item', 96 | type: 'string', 97 | default: 'lorem ipsum', 98 | }, 99 | }, 100 | }, 101 | unorderable: { 102 | title: 'Unorderable items', 103 | type: 'array', 104 | items: { 105 | title: 'Unorderable', 106 | type: 'string', 107 | default: 'lorem ipsum', 108 | }, 109 | }, 110 | unremovable: { 111 | title: 'Unremovable items', 112 | type: 'array', 113 | items: { 114 | title: 'Unremovable', 115 | type: 'string', 116 | default: 'lorem ipsum', 117 | }, 118 | }, 119 | noToolbar: { 120 | title: 'No add, remove and order buttons', 121 | type: 'array', 122 | items: { 123 | title: 'No ...', 124 | type: 'string', 125 | default: 'lorem ipsum', 126 | }, 127 | }, 128 | fixedNoToolbar: { 129 | title: 'Fixed array without buttons', 130 | type: 'array', 131 | items: [ 132 | { 133 | title: 'A number', 134 | type: 'number', 135 | default: 42, 136 | }, 137 | { 138 | title: 'A boolean', 139 | type: 'boolean', 140 | default: false, 141 | }, 142 | ], 143 | additionalItems: { 144 | title: 'A string', 145 | type: 'string', 146 | default: 'lorem ipsum', 147 | }, 148 | }, 149 | }, 150 | }, 151 | uiSchema: { 152 | listOfStrings: { 153 | items: { 154 | 'ui:options': { 155 | placeholder: 'Please enter a string' 156 | } 157 | }, 158 | }, 159 | multipleChoicesList: { 160 | 'ui:widget': 'CheckboxesWidget', 161 | }, 162 | fixedItemsList: { 163 | items: [ 164 | { 165 | 'ui:options': { 166 | type: 'textarea' 167 | } 168 | }, 169 | { 170 | 'ui:options': { 171 | activeText: '开启', 172 | inactiveText: '不开启' 173 | } 174 | } 175 | ], 176 | additionalItems: { 177 | 'ui:options': { 178 | step: 10 179 | } 180 | }, 181 | }, 182 | unorderable: { 183 | 'ui:options': { 184 | sortable: false, 185 | }, 186 | }, 187 | unremovable: { 188 | 'ui:options': { 189 | removable: false, 190 | }, 191 | }, 192 | noToolbar: { 193 | 'ui:options': { 194 | addable: false, 195 | sortable: false, 196 | removable: false, 197 | }, 198 | items: { 199 | 'ui:options': { 200 | title: '不显示操作条' 201 | } 202 | } 203 | }, 204 | fixedNoToolbar: { 205 | 'ui:options': { 206 | addable: false, 207 | sortable: false, 208 | removable: false, 209 | showIndexNumber: true 210 | }, 211 | }, 212 | }, 213 | formData: { 214 | listOfStrings: ['foo', 'bar'], 215 | multipleChoicesList: ['foo', 'bar'], 216 | fixedItemsList: ['Some text', true], 217 | nestedList: [['lorem', 'ipsum'], ['dolor']], 218 | unorderable: ['one', 'two'], 219 | unremovable: ['one', 'two'], 220 | noToolbar: ['one', 'two'], 221 | fixedNoToolbar: [42, true, 'additional item one', 'additional item two'], 222 | }, 223 | }; 224 | --------------------------------------------------------------------------------