├── .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 |
2 |
3 |
4 |
5 |
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 |
2 |
7 |
8 |
24 |
--------------------------------------------------------------------------------
/src/pages/vue-editor/views/editor/viewComponents/RecommendedGoodsList/component/View.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
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 |
2 |
3 |
4 | {{ formData.txt || '请配置标题' }}
5 |
6 |
7 |
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 |
2 |
3 |
8 | {{ formData.txt || '请配置标题' }}
9 |
10 |
11 |
12 |
13 |
24 |
25 |
36 |
--------------------------------------------------------------------------------
/src/pages/vue-editor/views/editor/viewComponentsM/Text/View.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 | {{ formData.txt || '请配置标题' }}
9 |
10 |
11 |
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 |
2 |
10 |
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 | 
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 |
2 |
6 |
7 |
8 |
9 |
10 | 取消
11 |
15 | 保存
16 |
17 |
18 |
19 |
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 |
2 |
28 |
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 |
2 |
6 |
10 |
15 |
16 |
17 |
18 |
22 |
29 |
30 |
31 |
32 |
33 |
34 |
57 |
58 |
61 |
--------------------------------------------------------------------------------
/src/pages/vue-editor/views/editor/viewComponents/MultipleImg5/View.vue:
--------------------------------------------------------------------------------
1 |
2 |
34 |
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 |
2 |
21 |
22 |
23 |
55 |
56 |
86 |
--------------------------------------------------------------------------------
/src/pages/vue-editor/views/editor/viewComponentsM/RecommendGoods/View.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ formData.title }}
5 |
21 |
22 |
26 | 点击配置数据
27 |
28 |
29 |
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 |
2 |
6 |
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 |
2 |
3 |
4 |
8 |
13 |
18 |
29 |
30 |
31 |
32 |
33 |
34 |
38 |
39 |
43 |
44 |
45 |
49 |
50 |
51 |
52 |
53 |
54 |
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 |
2 |
3 |
26 |
30 | 点击配置数据
31 |
32 |
33 |
34 |
35 |
52 |
53 |
107 |
--------------------------------------------------------------------------------
/src/pages/vue-editor/views/editor/viewComponentsM/CarouselImg/View.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
13 |
18 |
29 |
30 |
31 |
32 |
33 |
34 |
38 |
39 |
43 |
44 |
45 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
73 |
74 |
102 |
--------------------------------------------------------------------------------
/src/demo-common/components/EditorHeader.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
22 |
23 |
32 |
36 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
74 |
75 |
114 |
--------------------------------------------------------------------------------
/src/demo-common/components/Menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
77 |
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 |
2 |
3 |
8 |
12 |
16 |
17 |
24 |
25 |
26 | {{ value }}%
27 |
28 |
35 | 预览
36 |
41 | 保存
42 |
43 |
47 | 发布
48 |
49 |
50 |
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 |
2 |
3 |
8 |
9 |
10 | {{ group.groupName }}({{ group.componentList.length }})
11 |
12 |
23 |
32 |
33 |
34 |
35 |
36 |
37 | {{ item.title }}
38 |
39 |
40 | {{ currentUseComponentNum[item.componentPack.componentViewName] || 0 }} / {{ item.maxNum }}
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
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 |
2 |
10 |
11 |
12 | {{ title }}
13 |
14 |
15 |
16 |
24 |
25 |
26 |
27 |
165 |
166 |
177 |
--------------------------------------------------------------------------------
/src/demo-common/components/CodeEditor.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 | {{ title }}
13 |
14 |
15 |
16 |
24 |
25 |
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 |
2 |
106 |
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 |
2 |
6 |
多图模块(2-3)
7 |
55 |
126 |
127 |
128 |
129 |
154 |
155 |
212 |
--------------------------------------------------------------------------------
/src/pages/vue-editor/views/editor/viewComponents/CategoryGoods/View.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 | {{ formData.title }}
10 | {{ formData.subTitle }}
11 |
12 |
13 |
37 |
38 |
43 |
48 |
59 |
60 |
61 |
62 | 商品标题,可以结合具体业务活动商品数据
63 |
64 |
65 | ¥69.8
66 |
67 |
68 |
69 |
70 |
71 |
77 |
78 |
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 |
--------------------------------------------------------------------------------