├── .autod.conf.js
├── .eslintignore
├── .eslintrc
├── .github
└── workflows
│ └── nodejs.yml
├── .gitignore
├── .travis.yml
├── README.md
├── app
├── assets
│ ├── assets.json
│ └── schema.json
├── controller
│ └── home.js
├── router.js
├── services
│ └── lowcode.js
└── view
│ ├── .gitignore
│ ├── .npmrc
│ ├── .prettierignore
│ ├── .prettierrc
│ ├── .umirc.ts
│ ├── README.md
│ ├── index.html
│ ├── mock
│ └── lowcode.ts
│ ├── public
│ ├── assets.json
│ ├── info.json
│ └── schema.json
│ ├── src
│ ├── app.ts
│ ├── assets
│ │ ├── .gitkeep
│ │ ├── assets.json
│ │ └── schema.json
│ ├── components
│ │ ├── sample-plugins
│ │ │ └── logo
│ │ │ │ ├── index.scss
│ │ │ │ └── index.tsx
│ │ └── setters
│ │ │ ├── behavior-setter.tsx
│ │ │ └── custom-setter.tsx
│ ├── constants
│ │ └── index.ts
│ ├── models
│ │ └── global.ts
│ ├── pages
│ │ ├── Lowcode
│ │ │ ├── EditView.tsx
│ │ │ ├── global.scss
│ │ │ ├── index.tsx
│ │ │ └── plugin.tsx
│ │ └── Preview
│ │ │ └── index.tsx
│ └── services
│ │ └── lowcode.ts
│ ├── tsconfig.json
│ └── typings.d.ts
├── appveyor.yml
├── config
├── config.default.js
├── config.prod.js
├── plugin.js
└── plugin.prod.js
├── jsconfig.json
├── package.json
└── test
└── app
└── controller
└── home.test.js
/.autod.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | write: true,
5 | prefix: '^',
6 | plugin: 'autod-egg',
7 | test: [
8 | 'test',
9 | 'benchmark',
10 | ],
11 | dep: [
12 | 'egg',
13 | 'egg-scripts',
14 | ],
15 | devdep: [
16 | 'egg-ci',
17 | 'egg-bin',
18 | 'egg-mock',
19 | 'autod',
20 | 'autod-egg',
21 | 'eslint',
22 | 'eslint-config-egg',
23 | ],
24 | exclude: [
25 | './test/fixtures',
26 | './dist',
27 | ],
28 | };
29 |
30 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | coverage
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint-config-egg"
3 | }
4 |
--------------------------------------------------------------------------------
/.github/workflows/nodejs.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: Node.js CI
5 |
6 | on:
7 | push:
8 | branches:
9 | - main
10 | - master
11 | pull_request:
12 | branches:
13 | - main
14 | - master
15 | schedule:
16 | - cron: '0 2 * * *'
17 |
18 | jobs:
19 | build:
20 | runs-on: ${{ matrix.os }}
21 |
22 | strategy:
23 | fail-fast: false
24 | matrix:
25 | node-version: [10]
26 | os: [ubuntu-latest, windows-latest, macos-latest]
27 |
28 | steps:
29 | - name: Checkout Git Source
30 | uses: actions/checkout@v2
31 |
32 | - name: Use Node.js ${{ matrix.node-version }}
33 | uses: actions/setup-node@v1
34 | with:
35 | node-version: ${{ matrix.node-version }}
36 |
37 | - name: Install Dependencies
38 | run: npm i -g npminstall@5 && npminstall
39 |
40 | - name: Continuous Integration
41 | run: npm run ci
42 |
43 | - name: Code Coverage
44 | uses: codecov/codecov-action@v1
45 | with:
46 | token: ${{ secrets.CODECOV_TOKEN }}
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | logs/
2 | npm-debug.log
3 | yarn-error.log
4 | node_modules/
5 | package-lock.json
6 | yarn.lock
7 | coverage/
8 | .idea/
9 | run/
10 | .DS_Store
11 | *.sw*
12 | *.un~
13 | typings/
14 | .nyc_output/
15 | add
16 | app/public
17 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 |
2 | language: node_js
3 | node_js:
4 | - '10'
5 | before_install:
6 | - npm i npminstall@5 -g
7 | install:
8 | - npminstall
9 | script:
10 | - npm run ci
11 | after_script:
12 | - npminstall codecov && codecov
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # EggLowcode
2 |
3 | ## QuickStart
4 |
5 |
6 |
7 | see [egg docs][egg] for more detail.
8 |
9 | ### Development
10 |
11 | ```bash
12 | $ npm i
13 | $ npm run dev
14 | $ open http://localhost:7001/
15 | ```
16 |
17 | ### Deploy
18 |
19 | ```bash
20 | $ npm run build
21 | $ npm run start:prod
22 | $ npm run stop:prod
23 | ```
24 |
25 |
26 | ### TODO:
27 | 1. 多页面的支持
28 | 2. 数据库的支持
29 |
30 | ### npm scripts
31 |
32 | - Use `npm run lint` to check code style.
33 | - Use `npm test` to run unit test.
34 | - Use `npm run autod` to auto detect dependencies upgrade, see [autod](https://www.npmjs.com/package/autod) for more detail.
35 |
36 |
37 | [egg]: https://eggjs.org
--------------------------------------------------------------------------------
/app/assets/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": [
3 | {
4 | "package": "moment",
5 | "version": "2.24.0",
6 | "urls": [
7 | "https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"
8 | ],
9 | "library": "moment"
10 | },
11 | {
12 | "package": "lodash",
13 | "library": "_",
14 | "urls": [
15 | "https://g.alicdn.com/platform/c/lodash/4.6.1/lodash.min.js"
16 | ]
17 | },
18 | {
19 | "package": "iconfont-icons",
20 | "urls": "//at.alicdn.com/t/font_2369445_ukrtsovd92r.js"
21 | },
22 | {
23 | "package": "@ant-design/icons",
24 | "version": "4.7.0",
25 | "urls": [
26 | "//g.alicdn.com/code/npm/@ali/ant-design-icons-cdn/4.5.0/index.umd.min.js"
27 | ],
28 | "library": "icons"
29 | },
30 | {
31 | "package": "antd",
32 | "version": "4.19.5",
33 | "urls": [
34 | "//g.alicdn.com/code/lib/antd/4.19.4/antd.min.js",
35 | "//g.alicdn.com/code/lib/antd/4.19.4/antd.min.css"
36 | ],
37 | "library": "antd"
38 | },
39 | {
40 | "title": "fusion组件库",
41 | "package": "@alifd/next",
42 | "version": "1.23.0",
43 | "urls": [
44 | "https://g.alicdn.com/code/lib/alifd__next/1.23.18/next.min.css",
45 | "https://g.alicdn.com/code/lib/alifd__next/1.23.18/next-with-locales.min.js"
46 | ],
47 | "library": "Next"
48 | },
49 | {
50 | "package": "@alilc/antd-lowcode-materials",
51 | "version": "1.0.6",
52 | "library": "AntdLowcode",
53 | "urls": [
54 | "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/view.js",
55 | "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/view.css"
56 | ],
57 | "editUrls": [
58 | "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/view.js",
59 | "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/view.css"
60 | ]
61 | }
62 | ],
63 | "components": [
64 | {
65 | "exportName": "AlilcAntdLowcodeMaterialsMeta",
66 | "npm": {
67 | "package": "@alilc/antd-lowcode-materials",
68 | "version": "1.0.6"
69 | },
70 | "url": "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/meta.js",
71 | "urls": {
72 | "default": "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/meta.js"
73 | }
74 | }
75 | ],
76 | "sort": {
77 | "groupList": [
78 | "精选组件",
79 | "原子组件"
80 | ],
81 | "categoryList": [
82 | "通用",
83 | "导航",
84 | "信息输入",
85 | "信息展示",
86 | "信息反馈"
87 | ]
88 | },
89 | "groupList": [
90 | "精选组件",
91 | "原子组件"
92 | ],
93 | "ignoreComponents": {}
94 | }
--------------------------------------------------------------------------------
/app/assets/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "componentName": "Page",
3 | "id": "node_dockcviv8fo1",
4 | "props": {
5 | "ref": "outerView",
6 | "style": {
7 | "height": "100%"
8 | }
9 | },
10 | "fileName": "/",
11 | "dataSource": {
12 | "list": [
13 | {
14 | "type": "fetch",
15 | "isInit": true,
16 | "options": {
17 | "params": {},
18 | "method": "GET",
19 | "isCors": true,
20 | "timeout": 5000,
21 | "headers": {},
22 | "uri": "mock/info.json"
23 | },
24 | "id": "info",
25 | "shouldFetch": {
26 | "type": "JSFunction",
27 | "value": "function() { \n console.log('should fetch.....');\n return true; \n}"
28 | }
29 | }
30 | ]
31 | },
32 | "state": {
33 | "text": {
34 | "type": "JSExpression",
35 | "value": "\"outer\""
36 | },
37 | "isShowDialog": {
38 | "type": "JSExpression",
39 | "value": "false"
40 | }
41 | },
42 | "css": "body {\n font-size: 12px;\n}\n\n.button {\n width: 100px;\n color: #ff00ff\n}",
43 | "lifeCycles": {
44 | "componentDidMount": {
45 | "type": "JSFunction",
46 | "value": "function componentDidMount() {\n console.log('did mount');\n}"
47 | },
48 | "componentWillUnmount": {
49 | "type": "JSFunction",
50 | "value": "function componentWillUnmount() {\n console.log('will unmount');\n}"
51 | }
52 | },
53 | "methods": {
54 | "testFunc": {
55 | "type": "JSFunction",
56 | "value": "function testFunc() {\n console.log('test func');\n}"
57 | },
58 | "onClick": {
59 | "type": "JSFunction",
60 | "value": "function onClick() {\n this.setState({\n isShowDialog: true\n });\n}"
61 | },
62 | "closeDialog": {
63 | "type": "JSFunction",
64 | "value": "function closeDialog() {\n this.setState({\n isShowDialog: false\n });\n}"
65 | }
66 | },
67 | "originCode": "class LowcodeComponent extends Component {\n state = {\n \"text\": \"outer\",\n \"isShowDialog\": false\n }\n componentDidMount() {\n console.log('did mount');\n }\n componentWillUnmount() {\n console.log('will unmount');\n }\n testFunc() {\n console.log('test func');\n }\n onClick() {\n this.setState({\n isShowDialog: true\n })\n }\n closeDialog() {\n this.setState({\n isShowDialog: false\n })\n }\n}",
68 | "hidden": false,
69 | "title": "",
70 | "isLocked": false,
71 | "condition": true,
72 | "conditionGroup": ""
73 | }
--------------------------------------------------------------------------------
/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class HomeController extends Controller {
6 | async index() {
7 | const { ctx } = this;
8 | return ctx.render('index.html');
9 | }
10 |
11 | async getSchema() {
12 | const { ctx } = this;
13 | return await ctx.services.lowcode.getSchema();
14 | }
15 |
16 | async saveSchema() {
17 | const { ctx } = this;
18 | return await ctx.services.lowcode.saveSchema();
19 | }
20 | }
21 |
22 | module.exports = HomeController;
23 |
--------------------------------------------------------------------------------
/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @param {Egg.Application} app - egg application
5 | */
6 | module.exports = app => {
7 | const { router, controller } = app;
8 | router.get('/api/getSchema', controller.home.getSchema);
9 | router.post('/api/saveSchema', controller.home.saveSchema);
10 | router.get('/', controller.home.index);
11 | router.get('/*', controller.home.index);
12 | };
13 |
--------------------------------------------------------------------------------
/app/services/lowcode.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Service = require('egg').Service;
4 |
5 | class LowcodeService extends Service {
6 | async getSchema() {
7 | // 本地读取
8 | return {};
9 | }
10 |
11 | async updateSchema() {
12 | // 写入文件
13 |
14 | return {
15 | success: true,
16 | };
17 | }
18 | }
19 |
20 | module.exports = LowcodeService;
21 |
--------------------------------------------------------------------------------
/app/view/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /.env.local
3 | /.umirc.local.ts
4 | /config/config.local.ts
5 | /src/.umi
6 | /src/.umi-production
7 | /.umi
8 | /.umi-production
9 | /.umi-test
10 | /dist
11 | /.mfsu
12 |
--------------------------------------------------------------------------------
/app/view/.npmrc:
--------------------------------------------------------------------------------
1 | registry=https://registry.npmmirror.com
2 |
--------------------------------------------------------------------------------
/app/view/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .umi
3 | .umi-production
4 |
--------------------------------------------------------------------------------
/app/view/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 80,
3 | "singleQuote": true,
4 | "trailingComma": "all",
5 | "proseWrap": "never",
6 | "overrides": [{ "files": ".prettierrc", "options": { "parser": "json" } }],
7 | "plugins": ["prettier-plugin-organize-imports", "prettier-plugin-packagejson"]
8 | }
9 |
--------------------------------------------------------------------------------
/app/view/.umirc.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from '@umijs/max';
2 |
3 | export default defineConfig({
4 | antd: {},
5 | access: {},
6 | model: {},
7 | initialState: {},
8 | runtimePublicPath: {},
9 | outputPath: '../public',
10 | request: {},
11 | layout: {
12 | title: 'AntdProLowCode',
13 | },
14 | routes: [
15 | {
16 | path: '/',
17 | redirect: '/lowcode',
18 | },
19 | {
20 | name: '低代码编辑',
21 | path: '/lowcode',
22 | component: './Lowcode',
23 | },
24 | {
25 | name: '预览',
26 | path: '/preview',
27 | component: './Preview',
28 | },
29 | ],
30 | npmClient: 'npm',
31 | styles: [
32 | 'https://alifd.alicdn.com/npm/@alifd/theme-lowcode-light@0.2.1/variables.css',
33 | 'https://alifd.alicdn.com/npm/@alifd/theme-lowcode-light@0.2.1/dist/next.var.min.css',
34 | 'https://alifd.alicdn.com/npm/@alilc/lowcode-engine@1.0.10/dist/css/engine-core.css',
35 | 'https://alifd.alicdn.com/npm/@alilc/lowcode-engine-ext@1.0.3/dist/css/engine-ext.css',
36 | ],
37 | headScripts: [
38 | 'https://g.alicdn.com/code/lib/react/18.2.0/umd/react.production.min.js',
39 | 'https://g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.production.min.js',
40 | 'https://g.alicdn.com/code/lib/prop-types/15.8.1/prop-types.js',
41 | 'https://g.alicdn.com/platform/c/react15-polyfill/0.0.1/dist/index.js',
42 | 'https://g.alicdn.com/platform/c/lodash/4.6.1/lodash.min.js',
43 | 'https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js',
44 | 'https://g.alicdn.com/code/lib/alifd__next/1.25.44/next.min.js',
45 | {
46 | crossorigin: "anonymous",
47 | src: 'https://alifd.alicdn.com/npm/@alilc/lowcode-engine@1.0.10/dist/js/engine-core.js',
48 | },{
49 | crossorigin: "anonymous",
50 | src: 'https://alifd.alicdn.com/npm/@alilc/lowcode-engine-ext@1.0.3/dist/js/engine-ext.js',
51 | },
52 | ],
53 | externals: {
54 | "react": "var window.React",
55 | "react-dom": "var window.ReactDOM",
56 | "prop-types": "var window.PropTypes",
57 | "@alilc/lowcode-engine": "var window.AliLowCodeEngine",
58 | "@alilc/lowcode-editor-core": "var window.AliLowCodeEngine.common.editorCabin",
59 | "@alilc/lowcode-editor-skeleton": "var window.AliLowCodeEngine.common.skeletonCabin",
60 | "@alilc/lowcode-designer": "var window.AliLowCodeEngine.common.designerCabin",
61 | "@alilc/lowcode-engine-ext": "var window.AliLowCodeEngineExt",
62 | "@ali/lowcode-engine": "var window.AliLowCodeEngine",
63 | "moment": "var window.moment",
64 | "lodash": "var window._"
65 | },
66 | });
67 |
68 |
--------------------------------------------------------------------------------
/app/view/README.md:
--------------------------------------------------------------------------------
1 | # README
2 |
3 | [AliLowcodeEngine](https://lowcode-engine.cn/) [Umi](https://umijs.org/) [AntdPro](http://procomponents.ant.design) 结合一起的例子。
4 |
--------------------------------------------------------------------------------
/app/view/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Egg Lowcode Demo
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
42 | {{ helper.assets.getScript('umi.js') | safe }}
43 |
44 |
--------------------------------------------------------------------------------
/app/view/mock/lowcode.ts:
--------------------------------------------------------------------------------
1 | const users = [
2 | { name: 'Umi', nickName: 'U', gender: 'MALE' },
3 | { name: 'Fish', nickName: 'B', gender: 'FEMALE' },
4 | ];
5 |
6 | import assets from '../public/assets.json';
7 | import schemas from '../public/schema.json';
8 | import info from '../public/info.json';
9 |
10 | export default {
11 | 'GET /assets.json': (req: any, res: any) => {
12 | res.json(assets);
13 | },
14 |
15 | 'GET /schemas.json': (req: any, res: any) => {
16 | res.json(schemas);
17 | },
18 |
19 | 'GET /mock/info.json': (req: any, res: any) => {
20 | res.json(info);
21 | },
22 | };
23 |
--------------------------------------------------------------------------------
/app/view/public/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": [
3 | {
4 | "package": "moment",
5 | "version": "2.24.0",
6 | "urls": [
7 | "https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"
8 | ],
9 | "library": "moment"
10 | },
11 | {
12 | "package": "lodash",
13 | "library": "_",
14 | "urls": [
15 | "https://g.alicdn.com/platform/c/lodash/4.6.1/lodash.min.js"
16 | ]
17 | },
18 | {
19 | "package": "iconfont-icons",
20 | "urls": "//at.alicdn.com/t/font_2369445_ukrtsovd92r.js"
21 | },
22 | {
23 | "package": "@ant-design/icons",
24 | "version": "4.7.0",
25 | "urls": [
26 | "//g.alicdn.com/code/npm/@ali/ant-design-icons-cdn/4.5.0/index.umd.min.js"
27 | ],
28 | "library": "icons"
29 | },
30 | {
31 | "package": "antd",
32 | "version": "4.19.5",
33 | "urls": [
34 | "//g.alicdn.com/code/lib/antd/4.19.4/antd.min.js",
35 | "//g.alicdn.com/code/lib/antd/4.19.4/antd.min.css"
36 | ],
37 | "library": "antd"
38 | },
39 | {
40 | "title": "fusion组件库",
41 | "package": "@alifd/next",
42 | "version": "1.23.0",
43 | "urls": [
44 | "https://g.alicdn.com/code/lib/alifd__next/1.23.18/next.min.css",
45 | "https://g.alicdn.com/code/lib/alifd__next/1.23.18/next-with-locales.min.js"
46 | ],
47 | "library": "Next"
48 | },
49 | {
50 | "package": "@alilc/antd-lowcode-materials",
51 | "version": "1.0.6",
52 | "library": "AntdLowcode",
53 | "urls": [
54 | "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/view.js",
55 | "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/view.css"
56 | ],
57 | "editUrls": [
58 | "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/view.js",
59 | "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/view.css"
60 | ]
61 | }
62 | ],
63 | "components": [
64 | {
65 | "exportName": "AlilcAntdLowcodeMaterialsMeta",
66 | "npm": {
67 | "package": "@alilc/antd-lowcode-materials",
68 | "version": "1.0.6"
69 | },
70 | "url": "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/meta.js",
71 | "urls": {
72 | "default": "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/meta.js"
73 | }
74 | }
75 | ],
76 | "sort": {
77 | "groupList": [
78 | "精选组件",
79 | "原子组件"
80 | ],
81 | "categoryList": [
82 | "通用",
83 | "导航",
84 | "信息输入",
85 | "信息展示",
86 | "信息反馈"
87 | ]
88 | },
89 | "groupList": [
90 | "精选组件",
91 | "原子组件"
92 | ],
93 | "ignoreComponents": {}
94 | }
--------------------------------------------------------------------------------
/app/view/public/info.json:
--------------------------------------------------------------------------------
1 | {
2 | "info": "Hello AliLowCode!!"
3 | }
--------------------------------------------------------------------------------
/app/view/public/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "componentName": "Page",
3 | "id": "node_dockcviv8fo1",
4 | "props": {
5 | "ref": "outerView",
6 | "style": {
7 | "height": "100%"
8 | }
9 | },
10 | "fileName": "/",
11 | "dataSource": {
12 | "list": [
13 | {
14 | "type": "fetch",
15 | "isInit": true,
16 | "options": {
17 | "params": {},
18 | "method": "GET",
19 | "isCors": true,
20 | "timeout": 5000,
21 | "headers": {},
22 | "uri": "mock/info.json"
23 | },
24 | "id": "info",
25 | "shouldFetch": {
26 | "type": "JSFunction",
27 | "value": "function() { \n console.log('should fetch.....');\n return true; \n}"
28 | }
29 | }
30 | ]
31 | },
32 | "state": {
33 | "text": {
34 | "type": "JSExpression",
35 | "value": "\"outer\""
36 | },
37 | "isShowDialog": {
38 | "type": "JSExpression",
39 | "value": "false"
40 | }
41 | },
42 | "css": "body {\n font-size: 12px;\n}\n\n.button {\n width: 100px;\n color: #ff00ff\n}",
43 | "lifeCycles": {
44 | "componentDidMount": {
45 | "type": "JSFunction",
46 | "value": "function componentDidMount() {\n console.log('did mount');\n}"
47 | },
48 | "componentWillUnmount": {
49 | "type": "JSFunction",
50 | "value": "function componentWillUnmount() {\n console.log('will unmount');\n}"
51 | }
52 | },
53 | "methods": {
54 | "testFunc": {
55 | "type": "JSFunction",
56 | "value": "function testFunc() {\n console.log('test func');\n}"
57 | },
58 | "onClick": {
59 | "type": "JSFunction",
60 | "value": "function onClick() {\n this.setState({\n isShowDialog: true\n });\n}"
61 | },
62 | "closeDialog": {
63 | "type": "JSFunction",
64 | "value": "function closeDialog() {\n this.setState({\n isShowDialog: false\n });\n}"
65 | }
66 | },
67 | "originCode": "class LowcodeComponent extends Component {\n state = {\n \"text\": \"outer\",\n \"isShowDialog\": false\n }\n componentDidMount() {\n console.log('did mount');\n }\n componentWillUnmount() {\n console.log('will unmount');\n }\n testFunc() {\n console.log('test func');\n }\n onClick() {\n this.setState({\n isShowDialog: true\n })\n }\n closeDialog() {\n this.setState({\n isShowDialog: false\n })\n }\n}",
68 | "hidden": false,
69 | "title": "",
70 | "isLocked": false,
71 | "condition": true,
72 | "conditionGroup": ""
73 | }
--------------------------------------------------------------------------------
/app/view/src/app.ts:
--------------------------------------------------------------------------------
1 | // 运行时配置
2 |
3 | // 全局初始化数据配置,用于 Layout 用户信息和权限初始化
4 | // 更多信息见文档:https://next.umijs.org/docs/api/runtime-config#getinitialstate
5 | export async function getInitialState(): Promise<{ name: string }> {
6 | return { name: 'AntdLowCode' };
7 | }
8 |
9 | export const layout = () => {
10 | return {
11 | logo: 'https://img.alicdn.com/tfs/TB1YHEpwUT1gK0jSZFhXXaAtVXa-28-27.svg',
12 | layout: 'top',
13 | menu: {
14 | locale: false,
15 | },
16 | };
17 | };
18 |
--------------------------------------------------------------------------------
/app/view/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leoner/EggLowcode/5d19f8ea6e60700c55d66adec3df208c8bf16a07/app/view/src/assets/.gitkeep
--------------------------------------------------------------------------------
/app/view/src/assets/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": [
3 | {
4 | "package": "moment",
5 | "version": "2.24.0",
6 | "urls": [
7 | "https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"
8 | ],
9 | "library": "moment"
10 | },
11 | {
12 | "package": "lodash",
13 | "library": "_",
14 | "urls": [
15 | "https://g.alicdn.com/platform/c/lodash/4.6.1/lodash.min.js"
16 | ]
17 | },
18 | {
19 | "package": "iconfont-icons",
20 | "urls": "//at.alicdn.com/t/font_2369445_ukrtsovd92r.js"
21 | },
22 | {
23 | "package": "@ant-design/icons",
24 | "version": "4.7.0",
25 | "urls": [
26 | "//g.alicdn.com/code/npm/@ali/ant-design-icons-cdn/4.5.0/index.umd.min.js"
27 | ],
28 | "library": "icons"
29 | },
30 | {
31 | "package": "antd",
32 | "version": "4.19.5",
33 | "urls": [
34 | "//g.alicdn.com/code/lib/antd/4.19.4/antd.min.js",
35 | "//g.alicdn.com/code/lib/antd/4.19.4/antd.min.css"
36 | ],
37 | "library": "antd"
38 | },
39 | {
40 | "title": "fusion组件库",
41 | "package": "@alifd/next",
42 | "version": "1.23.0",
43 | "urls": [
44 | "https://g.alicdn.com/code/lib/alifd__next/1.23.18/next.min.css",
45 | "https://g.alicdn.com/code/lib/alifd__next/1.23.18/next-with-locales.min.js"
46 | ],
47 | "library": "Next"
48 | },
49 | {
50 | "package": "@alilc/antd-lowcode-materials",
51 | "version": "1.0.6",
52 | "library": "AntdLowcode",
53 | "urls": [
54 | "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/view.js",
55 | "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/view.css"
56 | ],
57 | "editUrls": [
58 | "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/view.js",
59 | "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/view.css"
60 | ]
61 | }
62 | ],
63 | "components": [
64 | {
65 | "exportName": "AlilcAntdLowcodeMaterialsMeta",
66 | "npm": {
67 | "package": "@alilc/antd-lowcode-materials",
68 | "version": "1.0.6"
69 | },
70 | "url": "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/meta.js",
71 | "urls": {
72 | "default": "https://alifd.alicdn.com/npm/@alilc/antd-lowcode-materials@1.0.6/build/lowcode/meta.js"
73 | }
74 | }
75 | ],
76 | "sort": {
77 | "groupList": [
78 | "精选组件",
79 | "原子组件"
80 | ],
81 | "categoryList": [
82 | "通用",
83 | "导航",
84 | "信息输入",
85 | "信息展示",
86 | "信息反馈"
87 | ]
88 | },
89 | "groupList": [
90 | "精选组件",
91 | "原子组件"
92 | ],
93 | "ignoreComponents": {}
94 | }
--------------------------------------------------------------------------------
/app/view/src/assets/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "componentName": "Page",
3 | "id": "node_dockcviv8fo1",
4 | "props": {
5 | "ref": "outerView",
6 | "style": {
7 | "height": "100%"
8 | }
9 | },
10 | "fileName": "/",
11 | "dataSource": {
12 | "list": [
13 | {
14 | "type": "fetch",
15 | "isInit": true,
16 | "options": {
17 | "params": {},
18 | "method": "GET",
19 | "isCors": true,
20 | "timeout": 5000,
21 | "headers": {},
22 | "uri": "mock/info.json"
23 | },
24 | "id": "info",
25 | "shouldFetch": {
26 | "type": "JSFunction",
27 | "value": "function() { \n console.log('should fetch.....');\n return true; \n}"
28 | }
29 | }
30 | ]
31 | },
32 | "state": {
33 | "text": {
34 | "type": "JSExpression",
35 | "value": "\"outer\""
36 | },
37 | "isShowDialog": {
38 | "type": "JSExpression",
39 | "value": "false"
40 | }
41 | },
42 | "css": "body {\n font-size: 12px;\n}\n\n.button {\n width: 100px;\n color: #ff00ff\n}",
43 | "lifeCycles": {
44 | "componentDidMount": {
45 | "type": "JSFunction",
46 | "value": "function componentDidMount() {\n console.log('did mount');\n}"
47 | },
48 | "componentWillUnmount": {
49 | "type": "JSFunction",
50 | "value": "function componentWillUnmount() {\n console.log('will unmount');\n}"
51 | }
52 | },
53 | "methods": {
54 | "testFunc": {
55 | "type": "JSFunction",
56 | "value": "function testFunc() {\n console.log('test func');\n}"
57 | },
58 | "onClick": {
59 | "type": "JSFunction",
60 | "value": "function onClick() {\n this.setState({\n isShowDialog: true\n });\n}"
61 | },
62 | "closeDialog": {
63 | "type": "JSFunction",
64 | "value": "function closeDialog() {\n this.setState({\n isShowDialog: false\n });\n}"
65 | }
66 | },
67 | "originCode": "class LowcodeComponent extends Component {\n state = {\n \"text\": \"outer\",\n \"isShowDialog\": false\n }\n componentDidMount() {\n console.log('did mount');\n }\n componentWillUnmount() {\n console.log('will unmount');\n }\n testFunc() {\n console.log('test func');\n }\n onClick() {\n this.setState({\n isShowDialog: true\n })\n }\n closeDialog() {\n this.setState({\n isShowDialog: false\n })\n }\n}",
68 | "hidden": false,
69 | "title": "",
70 | "isLocked": false,
71 | "condition": true,
72 | "conditionGroup": ""
73 | }
--------------------------------------------------------------------------------
/app/view/src/components/sample-plugins/logo/index.scss:
--------------------------------------------------------------------------------
1 | .lowcode-plugin-logo {
2 | .logo {
3 | display: block;
4 | width: 139px;
5 | height: 26px;
6 | cursor: pointer;
7 | background-size: contain;
8 | background-position: center;
9 | background-repeat: no-repeat;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/view/src/components/sample-plugins/logo/index.tsx:
--------------------------------------------------------------------------------
1 | import './index.scss';
2 | import type { PluginProps } from '@alilc/lowcode-types';
3 |
4 | import { useModel } from 'umi';
5 |
6 | export interface IProps {
7 | logo?: string;
8 | href?: string;
9 | }
10 |
11 | const Logo: React.FC = (props): React.ReactElement => {
12 | const { name } = useModel('global')
13 | console.info('=====>', name);
14 | return (
15 |
18 | );
19 | };
20 |
21 | export default Logo;
22 |
--------------------------------------------------------------------------------
/app/view/src/components/setters/behavior-setter.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import BehaviorSetter from '@alilc/lowcode-setter-behavior';
3 |
4 |
5 | const defaultExtraBehaviorActions: any[] = [];
6 | class LocalBehaviorSetter extends React.Component {
7 | render() {
8 | // ignore url && responseFormatter props, use default ones
9 | const { url: propsUrl, responseFormatter: propsFormatter, extraBehaviorActions: propsExtraBehaviorActions = [], ...otherProps } = this.props;
10 | const url = 'https://hn.algolia.com/api/v1/search?query';
11 | const responseFormatter = (response) => response.hits.map((item) => ({
12 | label: item.title,
13 | value: item.author
14 | }));
15 | const extraBehaviorActions = propsExtraBehaviorActions.concat(defaultExtraBehaviorActions);
16 | return (
17 |
23 | );
24 | }
25 | }
26 |
27 | export default LocalBehaviorSetter;
--------------------------------------------------------------------------------
/app/view/src/components/setters/custom-setter.tsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'; // import classNames from 'classnames';
2 |
3 | class CustomSetter extends Component {
4 | render() {
5 | const { defaultValue, value, onChange } = this.props;
6 | const { editor } = this.props.field;
7 |
8 | return hello world
;
9 | }
10 | }
11 |
12 | export default CustomSetter;
13 |
--------------------------------------------------------------------------------
/app/view/src/constants/index.ts:
--------------------------------------------------------------------------------
1 | export const DEFAULT_NAME = 'Hello Egg Pro Umi Lowcode ';
2 |
--------------------------------------------------------------------------------
/app/view/src/models/global.ts:
--------------------------------------------------------------------------------
1 | // 全局共享数据示例
2 | import { DEFAULT_NAME } from '@/constants';
3 | import { useState } from 'react';
4 |
5 | const useUser = () => {
6 | const [name, setName] = useState(DEFAULT_NAME);
7 | return {
8 | name,
9 | setName,
10 | };
11 | };
12 |
13 | export default useUser;
14 |
--------------------------------------------------------------------------------
/app/view/src/pages/Lowcode/EditView.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 | import { common, plugins } from '@alilc/lowcode-engine';
3 | import './global.scss';
4 | const preference = new Map();
5 |
6 | preference.set('DataSourcePane', {
7 | importPlugins: [],
8 | dataSourceTypes: [
9 | {
10 | type: 'fetch',
11 | },
12 | {
13 | type: 'jsonp',
14 | }
15 | ]
16 | });
17 |
18 | const Workbench = common.skeletonCabin.Workbench;
19 | const EditView: React.FC = () => {
20 |
21 | useEffect(() => {
22 | plugins.init(preference).then(() => {
23 | setHasPluginInited(true);
24 | }).catch(err => console.error(err));
25 | }, []);
26 |
27 | /** 插件是否已初始化成功,因为必须要等插件初始化后才能渲染 Workbench */
28 | const [hasPluginInited, setHasPluginInited] = useState(false);
29 |
30 | return (
31 | <>
32 | { hasPluginInited && }
33 | >
34 | );
35 | };
36 |
37 | export default EditView;
38 |
--------------------------------------------------------------------------------
/app/view/src/pages/Lowcode/global.scss:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: PingFangSC-Regular, Roboto, Helvetica Neue, Helvetica, Tahoma, Arial, PingFang SC-Light, Microsoft YaHei;
3 | font-size: 12px;
4 | * {
5 | box-sizing: border-box;
6 | }
7 | }
8 |
9 | body, .lc-workbench{
10 | position: fixed;
11 | left: 0;
12 | right: 0;
13 | bottom: 0;
14 | top: 50px;
15 | box-sizing: border-box;
16 | padding: 0;
17 | margin: 0;
18 | overflow: hidden;
19 | text-rendering: optimizeLegibility;
20 | -webkit-user-select: none;
21 | -webkit-user-drag: none;
22 | -webkit-text-size-adjust: none;
23 | -webkit-touch-callout: none;
24 | -webkit-font-smoothing: antialiased;
25 | }
26 |
27 | html {
28 | min-width: 1024px;
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/app/view/src/pages/Lowcode/index.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useCallback } from 'react';
2 | import { PageContainer } from '@ant-design/pro-components';
3 |
4 | import { config } from '@alilc/lowcode-engine';
5 | import { createFetchHandler } from '@alilc/lowcode-datasource-fetch-handler'
6 | import registerPlugins from './plugin';
7 | import EditView from './EditView';
8 |
9 | const LowcodePage: React.FC = () => {
10 | const [inited, setInited] = useState(false);
11 |
12 | const init = useCallback(async () => {
13 | await registerPlugins();
14 |
15 | config.setConfig({
16 | // designMode: 'live',
17 | // locale: 'zh-CN',
18 | enableCondition: true,
19 | enableCanvasLock: true,
20 | // 默认绑定变量
21 | supportVariableGlobally: true,
22 | // simulatorUrl 在当 engine-core.js 同一个父路径下时是不需要配置的!!!
23 | // 这里因为用的是 alifd cdn,在不同 npm 包,engine-core.js 和 react-simulator-renderer.js 是不同路径
24 | simulatorUrl: [
25 | 'https://alifd.alicdn.com/npm/@alilc/lowcode-react-simulator-renderer@latest/dist/css/react-simulator-renderer.css',
26 | 'https://alifd.alicdn.com/npm/@alilc/lowcode-react-simulator-renderer@latest/dist/js/react-simulator-renderer.js'
27 | ],
28 | requestHandlersMap: {
29 | fetch: createFetchHandler()
30 | }
31 | });
32 | }, []);
33 |
34 | useEffect(() => {
35 | init().then(()=> {
36 | setInited(true);
37 | }).catch(() => {
38 | location.reload();
39 | });
40 | }, []);
41 |
42 | return (
43 |
44 | { inited && }
45 |
46 | );
47 | };
48 |
49 | export default LowcodePage;
50 |
--------------------------------------------------------------------------------
/app/view/src/pages/Lowcode/plugin.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | ILowCodePluginContext,
3 | plugins,
4 | project,
5 | } from '@alilc/lowcode-engine';
6 | import AliLowCodeEngineExt from '@alilc/lowcode-engine-ext';
7 | import { Button } from 'antd';
8 | import ComponentsPane from '@alilc/lowcode-plugin-components-pane';
9 | import DataSourcePanePlugin from '@alilc/lowcode-plugin-datasource-pane';
10 | import SchemaPlugin from '@alilc/lowcode-plugin-schema';
11 | import CodeEditor from "@alilc/lowcode-plugin-code-editor";
12 | import Inject, { injectAssets } from '@alilc/lowcode-plugin-inject';
13 | import { request } from '@umijs/max';
14 |
15 | // 注册到引擎
16 | import TitleSetter from '@alilc/lowcode-setter-title';
17 | import BehaviorSetter from '@/components/setters/behavior-setter';
18 | import CustomSetter from '@/components/setters/custom-setter';
19 | import Logo from '@/components/sample-plugins/logo';
20 |
21 | import {
22 | saveSchema,
23 | resetSchema,
24 | getProjectSchemaFromLocalStorage,
25 | } from '@/services/lowcode';
26 |
27 | export default async function registerPlugins() {
28 | await plugins.register(Inject);
29 |
30 | // plugin API 见 https://lowcode-engine.cn/docV2/ibh9fh
31 | SchemaPlugin.pluginName = 'SchemaPlugin';
32 | await plugins.register(SchemaPlugin);
33 |
34 | const editorInit = (ctx: ILowCodePluginContext) => {
35 | return {
36 | name: 'editor-init',
37 | async init() {
38 | // 修改面包屑组件的分隔符属性setter
39 | const assets = await request('/assets.json');
40 | const schema = await request('/schema.json');
41 | // 设置物料描述
42 | const { material, project } = ctx;
43 |
44 | material.setAssets(await injectAssets(assets));
45 |
46 | // 加载 schema
47 | project.openDocument(getProjectSchemaFromLocalStorage('antd').componentsTree?.[0] || schema);
48 | },
49 | };
50 | }
51 | editorInit.pluginName = 'editorInit';
52 | await plugins.register(editorInit);
53 |
54 | const builtinPluginRegistry = (ctx: ILowCodePluginContext) => {
55 | return {
56 | name: 'builtin-plugin-registry',
57 | async init() {
58 | const { skeleton } = ctx;
59 | // 注册 logo 面板
60 | skeleton.add({
61 | area: 'topArea',
62 | type: 'Widget',
63 | name: 'logo',
64 | content: Logo,
65 | contentProps: {
66 | logo: 'https://img.alicdn.com/imgextra/i4/O1CN013w2bmQ25WAIha4Hx9_!!6000000007533-55-tps-137-26.svg',
67 | href: 'https://lowcode-engine.cn',
68 | },
69 | props: {
70 | align: 'left',
71 | },
72 | });
73 |
74 | // 注册组件面板
75 | const componentsPane = skeleton.add({
76 | area: 'leftArea',
77 | type: 'PanelDock',
78 | name: 'componentsPane',
79 | content: ComponentsPane,
80 | contentProps: {},
81 | props: {
82 | align: 'top',
83 | icon: 'zujianku',
84 | description: '组件库',
85 | },
86 | });
87 | componentsPane?.disable?.();
88 | project.onSimulatorRendererReady(() => {
89 | componentsPane?.enable?.();
90 | })
91 | },
92 | };
93 | }
94 | builtinPluginRegistry.pluginName = 'builtinPluginRegistry';
95 | await plugins.register(builtinPluginRegistry);
96 |
97 | // 设置内置 setter 和事件绑定、插件绑定面板
98 | const setterRegistry = (ctx: ILowCodePluginContext) => {
99 | const { setterMap, pluginMap } = AliLowCodeEngineExt;
100 | return {
101 | name: 'ext-setters-registry',
102 | async init() {
103 | const { setters, skeleton } = ctx;
104 | // 注册setterMap
105 | setters.registerSetter(setterMap);
106 | // 注册插件
107 | // 注册事件绑定面板
108 | skeleton.add({
109 | area: 'centerArea',
110 | type: 'Widget',
111 | content: pluginMap.EventBindDialog,
112 | name: 'eventBindDialog',
113 | props: {},
114 | });
115 |
116 | // 注册变量绑定面板
117 | skeleton.add({
118 | area: 'centerArea',
119 | type: 'Widget',
120 | content: pluginMap.VariableBindDialog,
121 | name: 'variableBindDialog',
122 | props: {},
123 | });
124 | },
125 | };
126 | }
127 | setterRegistry.pluginName = 'setterRegistry';
128 | await plugins.register(setterRegistry);
129 |
130 | // 注册保存面板
131 | const saveSample = (ctx: ILowCodePluginContext) => {
132 | return {
133 | name: 'saveSample',
134 | async init() {
135 | const { skeleton, hotkey } = ctx;
136 |
137 | skeleton.add({
138 | name: 'saveSample',
139 | area: 'topArea',
140 | type: 'Widget',
141 | props: {
142 | align: 'right',
143 | },
144 | content: (
145 |
148 | ),
149 | });
150 | skeleton.add({
151 | name: 'resetSchema',
152 | area: 'topArea',
153 | type: 'Widget',
154 | props: {
155 | align: 'right',
156 | },
157 | content: (
158 |
161 | ),
162 | });
163 | hotkey.bind('command+s', (e) => {
164 | e.preventDefault();
165 | saveSchema('antd')
166 | });
167 | },
168 | };
169 | }
170 | saveSample.pluginName = 'saveSample';
171 | await plugins.register(saveSample);
172 |
173 | DataSourcePanePlugin.pluginName = 'DataSourcePane';
174 | await plugins.register(DataSourcePanePlugin);
175 |
176 | CodeEditor.pluginName = 'CodeEditor';
177 | await plugins.register(CodeEditor);
178 |
179 | const customSetter = (ctx: ILowCodePluginContext) => {
180 | return {
181 | name: '___registerCustomSetter___',
182 | async init() {
183 | const { setters } = ctx;
184 |
185 | setters.registerSetter('TitleSetter', TitleSetter);
186 | setters.registerSetter('BehaviorSetter', BehaviorSetter);
187 | setters.registerSetter('CustomSetter', CustomSetter);
188 | },
189 | };
190 | }
191 | customSetter.pluginName = 'customSetter';
192 | await plugins.register(customSetter);
193 | };
194 |
--------------------------------------------------------------------------------
/app/view/src/pages/Preview/index.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 | import { PageContainer } from '@ant-design/pro-components';
3 | import { buildComponents, AssetLoader } from '@alilc/lowcode-utils';
4 | import ReactRenderer from '@alilc/lowcode-react-renderer';
5 | import { injectComponents } from '@alilc/lowcode-plugin-inject';
6 | import { getProjectSchemaFromLocalStorage, getPackagesFromLocalStorage } from '@/services/lowcode';
7 |
8 | export default () => {
9 | const [data, setData] = useState<{schema: any, components: any}>();
10 |
11 | async function init() {
12 | const scenarioName = 'antd';
13 | const packages = getPackagesFromLocalStorage(scenarioName);
14 | const projectSchema = getProjectSchemaFromLocalStorage(scenarioName);
15 | const { componentsMap: componentsMapArray = [], componentsTree = [] } = projectSchema;
16 | const componentsMap: any = {};
17 | componentsMapArray.forEach((component: any) => {
18 | componentsMap[component.componentName] = component;
19 | });
20 | const schema = componentsTree[0];
21 |
22 | const libraryMap = {};
23 | const libraryAsset = [];
24 | packages.forEach(({ package: _package, library, urls, renderUrls }) => {
25 | libraryMap[_package] = library;
26 | if (renderUrls) {
27 | libraryAsset.push(renderUrls);
28 | } else if (urls) {
29 | libraryAsset.push(urls);
30 | }
31 | });
32 |
33 | const assetLoader = new AssetLoader();
34 | await assetLoader.load(libraryAsset);
35 | const components = await injectComponents(buildComponents(libraryMap, componentsMap));
36 | setData({
37 | schema,
38 | components,
39 | });
40 | }
41 |
42 | useEffect(() => {
43 | init();
44 | }, []);
45 |
46 | return (
47 |
48 | { data?.schema && ()
53 | }
54 |
55 | );
56 | };
57 |
58 |
--------------------------------------------------------------------------------
/app/view/src/services/lowcode.ts:
--------------------------------------------------------------------------------
1 | import { request } from '@umijs/max';
2 | import { material, project } from '@alilc/lowcode-engine';
3 | import { message } from 'antd';
4 | import { filterPackages } from '@alilc/lowcode-plugin-inject'
5 | import { TransformStage } from '@alilc/lowcode-types';
6 |
7 | export const saveSchema = async (scenarioName: string = 'index') => {
8 | setProjectSchemaToLocalStorage(scenarioName);
9 |
10 | await setPackgesToLocalStorage(scenarioName);
11 | // window.localStorage.setItem(
12 | // 'projectSchema',
13 | // JSON.stringify(project.exportSchema(TransformStage.Save))
14 | // );
15 | // const packages = await filterPackages(material.getAssets().packages);
16 | // window.localStorage.setItem(
17 | // 'packages',
18 | // JSON.stringify(packages)
19 | // );
20 | message.success('成功保存到本地');
21 | };
22 |
23 | export const resetSchema = async (scenarioName: string = 'index') => {
24 | try {
25 | await new Promise((resolve, reject) => {
26 | Dialog.confirm({
27 | content: '确定要重置吗?您所有的修改都将消失!',
28 | onOk: () => {
29 | resolve();
30 | },
31 | onCancel: () => {
32 | reject()
33 | },
34 | })
35 | })
36 | } catch(err) {
37 | return
38 | }
39 |
40 | window.localStorage.setItem(
41 | getLSName(scenarioName),
42 | JSON.stringify({
43 | componentsTree: [{ componentName: 'Page', fileName: 'sample' }],
44 | componentsMap: material.componentsMap,
45 | version: '1.0.0',
46 | i18n: {},
47 | })
48 | );
49 | project.getCurrentDocument()?.importSchema({ componentName: 'Page', fileName: 'sample' });
50 | project.simulatorHost?.rerender();
51 | message.success('成功重置页面');
52 | }
53 |
54 | const getLSName = (scenarioName: string, ns: string = 'projectSchema') => `${scenarioName}:${ns}`;
55 |
56 | export const getProjectSchemaFromLocalStorage = (scenarioName: string) => {
57 | if (!scenarioName) {
58 | console.error('scenarioName is required!');
59 | return;
60 | }
61 | return JSON.parse(window.localStorage.getItem(getLSName(scenarioName)) || '{}');
62 | }
63 |
64 | const setProjectSchemaToLocalStorage = (scenarioName: string) => {
65 | if (!scenarioName) {
66 | console.error('scenarioName is required!');
67 | return;
68 | }
69 | window.localStorage.setItem(
70 | getLSName(scenarioName),
71 | JSON.stringify(project.exportSchema(TransformStage.Save))
72 | );
73 | }
74 |
75 | const setPackgesToLocalStorage = async (scenarioName: string) => {
76 | if (!scenarioName) {
77 | console.error('scenarioName is required!');
78 | return;
79 | }
80 | const packages = await filterPackages(material.getAssets().packages);
81 | window.localStorage.setItem(
82 | getLSName(scenarioName, 'packages'),
83 | JSON.stringify(packages),
84 | );
85 | }
86 |
87 | export const getPackagesFromLocalStorage = (scenarioName: string) => {
88 | if (!scenarioName) {
89 | console.error('scenarioName is required!');
90 | return;
91 | }
92 | return JSON.parse(window.localStorage.getItem(getLSName(scenarioName, 'packages')) || '[]');
93 | }
94 |
95 | export const getPageSchema = async (scenarioName: string = 'index') => {
96 | const pageSchema = getProjectSchemaFromLocalStorage(scenarioName).componentsTree?.[0]
97 |
98 | if (pageSchema) {
99 | return pageSchema;
100 | }
101 |
102 | return await request('./schema.json');
103 | };
--------------------------------------------------------------------------------
/app/view/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./src/.umi/tsconfig.json"
3 | }
4 |
--------------------------------------------------------------------------------
/app/view/typings.d.ts:
--------------------------------------------------------------------------------
1 | import '@umijs/max/typings';
2 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | environment:
2 | matrix:
3 | - nodejs_version: '10'
4 |
5 | install:
6 | - ps: Install-Product node $env:nodejs_version
7 | - npm i npminstall@5 && node_modules\.bin\npminstall
8 |
9 | test_script:
10 | - node --version
11 | - npm --version
12 | - npm run test
13 |
14 | build: off
15 |
--------------------------------------------------------------------------------
/config/config.default.js:
--------------------------------------------------------------------------------
1 | /* eslint valid-jsdoc: "off" */
2 |
3 | 'use strict';
4 | const path = require('path');
5 |
6 | /**
7 | * @param {Egg.EggAppInfo} appInfo app info
8 | */
9 | module.exports = appInfo => {
10 | /**
11 | * built-in config
12 | * @type {Egg.EggAppConfig}
13 | **/
14 | const config = exports = {};
15 |
16 | // use for cookie sign key, should change to your own and keep security
17 | config.keys = appInfo.name + '_1655996192532_746';
18 |
19 | // add your middleware config here
20 | config.middleware = [];
21 |
22 | // add your user config here
23 | const userConfig = {
24 | // myAppName: 'egg',
25 | static: {
26 | prefix: '/',
27 | dir: [ path.join(appInfo.baseDir, 'app/public'), path.join(appInfo.baseDir, 'app/assets') ],
28 | },
29 | view: {
30 | root: path.join(appInfo.baseDir, 'app/view'),
31 | mapping: {
32 | '.html': 'nunjucks',
33 | },
34 | },
35 | assets: {
36 | publicPath: '/',
37 | devServer: {
38 | debug: true,
39 | command: 'cross-env REACT_APP_ENV=dev APP_ROOT=$PWD/app/view USE_WEBPACK_5=1 max dev',
40 | port: 8000,
41 | env: {
42 | APP_ROOT: path.join(__dirname, 'app/view'),
43 | BROWSER: 'none',
44 | ESLINT: 'none',
45 | SOCKET_SERVER: 'http://127.0.0.1:8000',
46 | PUBLIC_PATH: 'http://127.0.0.1:8000',
47 | },
48 | },
49 | },
50 | security: {
51 | csrf: false,
52 | },
53 | };
54 |
55 | return {
56 | ...config,
57 | ...userConfig,
58 | };
59 | };
60 |
--------------------------------------------------------------------------------
/config/config.prod.js:
--------------------------------------------------------------------------------
1 | /* eslint valid-jsdoc: "off" */
2 |
3 | 'use strict';
4 | const path = require('path');
5 |
6 | /**
7 | * @param {Egg.EggAppInfo} appInfo app info
8 | */
9 | module.exports = appInfo => {
10 | /**
11 | * built-in config
12 | * @type {Egg.EggAppConfig}
13 | **/
14 | const config = exports = {};
15 |
16 | // use for cookie sign key, should change to your own and keep security
17 | config.keys = appInfo.name + '_1655996192532_746';
18 |
19 | // add your middleware config here
20 | config.middleware = [];
21 |
22 | // add your user config here
23 | const userConfig = {
24 | // myAppName: 'egg',
25 | static: {
26 | prefix: '/',
27 | dir: [ path.join(appInfo.baseDir, 'app/assets'), path.join(appInfo.baseDir, 'app/public') ],
28 | },
29 | view: {
30 | root: path.join(appInfo.baseDir, 'app/public'),
31 | mapping: {
32 | '.html': 'nunjucks',
33 | },
34 | },
35 | };
36 |
37 | return {
38 | ...config,
39 | ...userConfig,
40 | };
41 | };
42 |
--------------------------------------------------------------------------------
/config/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /** @type Egg.EggPlugin */
4 | module.exports = {
5 | // had enabled by egg
6 | // static: {
7 | // enable: true,
8 | // }
9 | // config/plugin.js
10 | nunjucks: {
11 | enable: true,
12 | package: 'egg-view-nunjucks',
13 | },
14 | assets: {
15 | enable: true,
16 | package: 'egg-view-assets',
17 | },
18 | };
19 |
--------------------------------------------------------------------------------
/config/plugin.prod.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /** @type Egg.EggPlugin */
4 | module.exports = {
5 | // had enabled by egg
6 | // static: {
7 | // enable: true,
8 | // }
9 | // config/plugin.js
10 | nunjucks: {
11 | enable: true,
12 | package: 'egg-view-nunjucks',
13 | },
14 | assets: {
15 | enable: false,
16 | package: 'egg-view-assets',
17 | },
18 | };
19 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": [
3 | "**/*"
4 | ]
5 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "EggLowcode",
3 | "version": "1.0.0",
4 | "description": "",
5 | "private": true,
6 | "egg": {
7 | "declarations": true
8 | },
9 | "dependencies": {
10 | "egg": "^2.15.1",
11 | "egg-proxy-npm": "^1.1.1",
12 | "egg-scripts": "^2.11.0",
13 | "egg-view-assets": "^1.8.0",
14 | "egg-view-nunjucks": "^2.3.0"
15 | },
16 | "devDependencies": {
17 | "@alilc/lowcode-datasource-fetch-handler": "^1.0.1",
18 | "@alilc/lowcode-engine": "^1.0.10",
19 | "@alilc/lowcode-plugin-code-editor": "^1.0.2",
20 | "@alilc/lowcode-plugin-code-generator": "^1.0.4",
21 | "@alilc/lowcode-plugin-components-pane": "^1.0.2",
22 | "@alilc/lowcode-plugin-datasource-pane": "^1.0.5",
23 | "@alilc/lowcode-plugin-inject": "^1.1.1",
24 | "@alilc/lowcode-plugin-manual": "^1.0.3",
25 | "@alilc/lowcode-plugin-schema": "^1.0.1",
26 | "@alilc/lowcode-plugin-simulator-select": "^1.0.0",
27 | "@alilc/lowcode-plugin-undo-redo": "^1.0.0",
28 | "@alilc/lowcode-plugin-zh-en": "^1.0.0",
29 | "@alilc/lowcode-react-renderer": "^1.0.0",
30 | "@alilc/lowcode-setter-behavior": "^1.0.0",
31 | "@alilc/lowcode-setter-title": "^1.0.2",
32 | "@ant-design/pro-components": "^1.1.6",
33 | "@umijs/babel-preset-umi": "^4.0.2",
34 | "@umijs/max": "^4.0.2",
35 | "@umijs/plugin-sass": "^1.1.1",
36 | "@umijs/yorkie": "^2.0.5",
37 | "antd": "^4.20.7",
38 | "autod": "^3.0.1",
39 | "autod-egg": "^1.1.0",
40 | "cross-env": "^7.0.3",
41 | "egg-bin": "^4.11.0",
42 | "egg-ci": "^1.11.0",
43 | "eslint": "^5.13.0",
44 | "eslint-config-egg": "^7.1.0",
45 | "node-sass": "^7.0.1",
46 | "sass-loader": "^13.0.1",
47 | "typescript": "^4.1.2",
48 | "umi-request": "^1.4.0"
49 | },
50 | "engines": {
51 | "node": ">=14.0.0"
52 | },
53 | "scripts": {
54 | "build": "cross-env APP_ROOT=$PWD/app/view USE_WEBPACK_5=1 max build",
55 | "start": "egg-scripts start --daemon --title=egg-server-EggLowcode",
56 | "start:prod": "EGG_SERVER_ENV=prod egg-scripts start --daemon --title=egg-server-EggLowcode",
57 | "stop": "egg-scripts stop --title=egg-server-EggLowcode",
58 | "dev": "egg-bin dev",
59 | "prod": "EGG_SERVER_ENV=prod egg-bin dev",
60 | "debug": "egg-bin debug",
61 | "test": "npm run lint -- --fix && npm run test-local",
62 | "test-local": "egg-bin test",
63 | "cov": "egg-bin cov",
64 | "lint": "eslint .",
65 | "ci": "npm run lint && npm run cov",
66 | "autod": "autod"
67 | },
68 | "ci": {
69 | "version": "10"
70 | },
71 | "repository": {
72 | "type": "git",
73 | "url": ""
74 | },
75 | "author": "leoner",
76 | "license": "MIT"
77 | }
78 |
--------------------------------------------------------------------------------
/test/app/controller/home.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { app, assert } = require('egg-mock/bootstrap');
4 |
5 | describe('test/app/controller/home.test.js', () => {
6 | it('should assert', () => {
7 | const pkg = require('../../../package.json');
8 | assert(app.config.keys.startsWith(pkg.name));
9 |
10 | // const ctx = app.mockContext({});
11 | // yield ctx.service.xx();
12 | });
13 |
14 | it('should GET /', () => {
15 | return app.httpRequest()
16 | .get('/')
17 | .expect('hi, egg')
18 | .expect(200);
19 | });
20 | });
21 |
--------------------------------------------------------------------------------