├── .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 |
16 | 17 |
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 | --------------------------------------------------------------------------------