{"id":13561161,"url":"https://github.com/ccj-007/lowcode-editor-send","last_synced_at":"2025-08-21T17:30:45.749Z","repository":{"id":40759372,"uuid":"507880854","full_name":"ccj-007/lowcode-editor-send","owner":"ccj-007","description":"基于amis-editor的低代码编辑器的高级封装，低成本上手开发 🔥","archived":false,"fork":false,"pushed_at":"2023-07-07T16:26:50.000Z","size":5578,"stargazers_count":138,"open_issues_count":9,"forks_count":20,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-11-04T12:40:27.427Z","etag":null,"topics":["amis","amis-editor","amis-editor-vue","lowcode","lowcode-editor","react","vue"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ccj-007.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-06-27T11:28:21.000Z","updated_at":"2024-10-27T17:40:39.000Z","dependencies_parsed_at":"2024-01-14T05:23:16.342Z","dependency_job_id":null,"html_url":"https://github.com/ccj-007/lowcode-editor-send","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ccj-007%2Flowcode-editor-send","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ccj-007%2Flowcode-editor-send/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ccj-007%2Flowcode-editor-send/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ccj-007%2Flowcode-editor-send/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ccj-007","download_url":"https://codeload.github.com/ccj-007/lowcode-editor-send/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230523788,"owners_count":18239439,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["amis","amis-editor","amis-editor-vue","lowcode","lowcode-editor","react","vue"],"created_at":"2024-08-01T13:00:53.101Z","updated_at":"2024-12-20T01:51:13.841Z","avatar_url":"https://github.com/ccj-007.png","language":"TypeScript","readme":"# 📘 背景\r\n\r\n你是否在做中后台项目中经常要重复做 crud 的业务逻辑，花费大量时间还时常有 bug 发生，但是现在只要几分钟就能让你快速连通前后端，拖拉拽实现后台业务逻辑。你就问香不香！\r\n\r\n## 关于\r\n\r\n🚀 ✈️ 🚁 lowcode-editor-send 基于 amis-editor（React + TS），通过封装 json 数据上报、配置、自定义组件等，实现低代码管理后台实时更新，无需手动写 json 配置。如果你要在 Vue 中使用当然也可以。👍 简单一句话： 你不用敲代码了！！\r\n\r\n## 原理\r\n\r\n抽空实现了最简单版本的低代码框架，方便你快速理解, 支持生产源码。\r\n\r\nEasy-Lowcode https://github.com/ccj-007/easy-lowcode\r\n\r\n## 文章\r\n\r\n[我的低代码框架是如何生成源码的？](https://juejin.cn/post/7206955531998773309)\r\n\r\n## 预览\r\n\r\n![lowcode-editor-send](http://rreppket2.hn-bkt.clouddn.com/introduce.png)\r\n\r\n# 🤹‍♂️ 沟通\r\n\r\n#### 觉得不错点个 star ⭐ 再走 ！\r\n\r\n#### QQ 交流群 565896756\r\n\r\n# 🌵 开始\r\n\r\n```\r\n  npm i           //安装依赖\r\n  npm run start   //通过devaServe启动前端页面, 默认3000端口\r\n  npm run server  //启动node服务，默认3001端口\r\n  npm run build   //打包（某些情况可能会存在内存溢出问题）\r\n```\r\n\r\n# 🧩 功能\r\n\r\n1. url 跳转 √\r\n2. 历史记录修改 √\r\n3. 预览、重置、i18n 切换、切换移动端 √\r\n4. 配置更新前端 lowcode 页面 √\r\n5. 支持切换环境 √\r\n6. 编辑器打包 (关闭 sourcemap 和 node 内存溢出问题处理， 15M 体积) √\r\n7. 新增 crud 模板、css 样式模板 √\r\n8. 自定义组件：\r\n    - 自定义标题组件 √\r\n    - 倒计时组件 √\r\n    - 热力图组件 √\r\n\r\n# 🔨 自定义组件\r\n\r\n1. 请在项目 src 文件夹下的 customComponents 组件中根据已有示例配置即可，在 renderer 做 jsx 的渲染工作，plugin 做组件的基础配置\r\n2. 如何存在不确定的配置，可以在如下类型文件中查找对应 api\r\n\r\n-   在 node_modules/amis/lib/Schema.d.ts 里面定义了组件的类型\r\n-   在 node_modules/amis-editor/src/component/schemaTpl.tsx 定了 tab 面板配置的类型\r\n\r\n3. getSchemaTpl 返回的事先定义的多组件的模板，panelBody 配置可以获取物料的基础组件。所以通常我们会将 getSchemaTpl 和 panelBody 混用\r\n\r\n```js\r\n// src/customComponents/HeatMap/plugin.ts\r\n{\r\n  //...\r\n  panelBodyCreator(context: any) {\r\n    let panelConfig = getSchemaTpl(\"tabs\", [\r\n      {\r\n        title: \"接口\",\r\n        body: [\r\n          getSchemaTpl(\"switch\", {\r\n            name: \"initFetch\",\r\n            label: \"初始是否拉取\",\r\n          }),\r\n          getSchemaTpl(\"api\", {\r\n            name: \"api\",\r\n            label: \"接口地址\",\r\n            description:\r\n              \" 接口存在跨域问题，需要后端代理，请在此填写接口地址\",\r\n          }),\r\n        ],\r\n      },\r\n    ])\r\n    let panelBody = [\r\n      {\r\n        title: \"常规\",\r\n        controls: [\r\n          {\r\n            name: \"preview\",\r\n            label: \"是否预览\",\r\n            type: \"checkbox\",\r\n          },\r\n          {\r\n            name: \"json_heatmap\",\r\n            label: \"热力图的json配置\",\r\n            type: \"json-editor\",\r\n            onChange: (e: any) =\u003e {\r\n              const id = context.id;\r\n              const { manager } = this;\r\n              const { store } = manager;\r\n              const node = store.getNodeById(id);\r\n              console.log((e));\r\n\t\t\t\t\t\t\t//在配置的事件中可以控制组件的渲染 ！\r\n              const component = node.getComponent();\r\n              // component.api(val);\r\n            }\r\n          },\r\n        ],\r\n      },\r\n      {\r\n        title: \"外观\",\r\n        body: [getSchemaTpl(\"className\"),\r\n        getSchemaTpl(\"icon\"),\r\n        getSchemaTpl(\"combo-container\"),\r\n        getSchemaTpl(\"hidden\"),\r\n        getSchemaTpl(\"switchDefaultValue\"),\r\n      ],\r\n      },\r\n    ]\r\n    panelConfig.tabs.unshift(...panelBody)\r\n\t\treturn [\r\n\t\t\tpanelConfig\r\n\t\t]\r\n\t}\r\n}\r\n```\r\n\r\n# 🔫 自定义组件如何集成 SDK\r\n\r\n具体可以看官方用法，这里做了一个打包自定义组件的工作，并在 html 中引入\r\n\r\n```js\r\n//rollup.config.js\r\nconst config = {\r\n    input: \"src/customComponents/renderer.ts\",\r\n    output: {\r\n        dir: \"comp-sdk\",\r\n        format: \"es\",\r\n        globals: {\r\n            react: \"React\",\r\n        },\r\n        plugins: [\r\n            getBabelOutputPlugin({\r\n                presets: [\"@babel/preset-react\"],\r\n            }),\r\n        ],\r\n    },\r\n    acornInjectPlugins: [jsx()],\r\n    plugins: [\r\n        clear({\r\n            targets: [\"./comp-sdk/\"],\r\n        }),\r\n        resolve(),\r\n        commonjs(),\r\n        babel({\r\n            presets: [\r\n                [\r\n                    \"@babel/preset-react\",\r\n                    {\r\n                        development: false,\r\n                    },\r\n                ],\r\n            ],\r\n            babelHelpers: \"bundled\",\r\n        }),\r\n        typescript({\r\n            jsx: \"preserve\",\r\n        }),\r\n        json(),\r\n        postcss(),\r\n        terser(),\r\n        cleanup(),\r\n    ],\r\n}\r\n\r\nexport default config\r\n```\r\n\r\n通过 rollup 打包为 esm 模块，最终打包自定义组件的库会输出在`/comp-sdk`，下面展示具体 html 中的引入\r\n\r\n```html\r\n\u003cdiv id=\"root\" class=\"app-wrapper\"\u003e\u003c/div\u003e\r\n\u003cscript\u003e\r\n    var process = { env: { NODE_ENV: \"development\" } }\r\n\u003c/script\u003e\r\n\u003cscript type=\"module\" src=\"./comp-sdk/renderer.js\"\u003e\u003c/script\u003e\r\n\u003cscript src=\"./sdk/sdk.js\"\u003e\u003c/script\u003e\r\n\u003cscript type=\"module\"\u003e\r\n    let React = amisRequire(\"react\")\r\n    let amis = amisRequire(\"amis/embed\")\r\n    let amisLib = amisRequire(\"amis\")\r\n    console.log(\"compRenderMap\", compRenderMap)\r\n\r\n    //注册自定义组件\r\n    function generator(map) {\r\n        for (const key in map) {\r\n            let reg = eval(\"/(^|\\\\/)\" + key + \"/\")\r\n            amisLib.Renderer({\r\n                test: reg,\r\n            })(map[key])\r\n        }\r\n    }\r\n    generator(compRenderMap)\r\n\r\n    let amisScoped = amis.embed(\"#root\", {\r\n        type: \"page\",\r\n        title: \"表单页面\",\r\n        body: {\r\n            type: \"form\",\r\n            mode: \"horizontal\",\r\n            api: \"/saveForm\",\r\n            body: [\r\n                {\r\n                    label: \"title\",\r\n                    type: \"custom-title\",\r\n                    name: \"title\",\r\n                },\r\n                {\r\n                    label: \"countdown\",\r\n                    type: \"custom-countdown\",\r\n                    name: \"countdown\",\r\n                },\r\n            ],\r\n        },\r\n    })\r\n\u003c/script\u003e\r\n```\r\n\r\n# ⚠ 注意\r\n\r\n1. 本地调试请在 server 文件夹下定义好文件名，本地调用通过文件名对应路由名。如果需要数据库连接，请定义好项目名和路由名等字段用于查询。json 配置在原来基础上，已经做了一个包裹, 核心数据配置在 json 属性内，为了方便定位以及后期维护扩展。\r\n\r\n2. 在编辑中极有可能遇到点错导致页面丢失问题，可以做个发布的版本备份功能\r\n\r\n```js\r\n{\r\n  \"json\": {\r\n    \"type\": \"page\",\r\n    \"title\": \"Hello world\",\r\n    \"body\": [\r\n    ]\r\n  },\r\n  \"routeName\": \"test2.json\",\r\n  \"itemName\": \"cms2\"\r\n}\r\n```\r\n\r\n# 🍬 核心\r\n\r\n```js\r\n//src/App.tsx\r\nimport * as React from \"react\";\r\nimport { Editor } from \"amis-editor\";\r\nimport \"./App.css\";\r\nimport axios from \"axios\";\r\nimport crudTpl from \"./tpl/crud.json\"; //json文件默认可以在src目录下导入\r\nimport { proxy } from \"ajax-hook\";  //拦截amis内部ajax请求\r\nimport { SchemaObject } from \"amis/lib/Schema\"; //json数据类型\r\nimport { MyRendererPlugin } from \"./MyRendererPlugin\";\r\nimport { registerEditorPlugin } from 'amis-editor';\r\n\r\nregisterEditorPlugin(MyRendererPlugin); //自定义组件\r\n\r\ninterface StateType {\r\n  json: any;\r\n  routeName: string;\r\n  itemName: string;\r\n  preview: boolean;\r\n  historyList: Object[];\r\n  step: number;\r\n  maxHistoryNum: number;\r\n  baseURL: string;\r\n  isCustomStyle: boolean\r\n  linkDOM: HTMLElement | null\r\n}\r\n\r\ntype InputType = React.RefObject\u003cHTMLInputElement\u003e\r\n\r\nclass App extends React.Component\u003cany, StateType\u003e {\r\n  baseURLRef: InputType = React.createRef()\r\n  itemNameRef: InputType = React.createRef()\r\n  routeNameRef: InputType = React.createRef()\r\n\r\n  constructor(props: any) {\r\n    super(props);\r\n    this.state = {\r\n      json: {},\r\n      routeName: window.localStorage.getItem(\"lowcode_routeName\") || \"test1\", //test1对应server文件夹下的json的文件名（本地调试）\r\n      itemName: window.localStorage.getItem(\"lowcode_itemName\") || \"cms2\",\r\n      preview: false,\r\n      historyList: [],\r\n      step: 0,\r\n      maxHistoryNum: 10,\r\n      baseURL: window.localStorage.getItem(\"baseURL\") || \"http://localhost:3001\", //正式开发环境请自行修改\r\n      isCustomStyle: window.localStorage.getItem(\"lowcode_style\") === 'true' ? true : false,\r\n      linkDOM: null,\r\n    };\r\n  }\r\n  componentDidMount() {\r\n    //拦截处理\r\n    proxy({\r\n       // ...\r\n    });\r\n\r\n    //获取url query\r\n    this.checkQuery();\r\n    setTimeout(() =\u003e {\r\n      this.getJSON();\r\n    }, 0);\r\n  }\r\n\r\n  // 通过接口获取json对象\r\n  getJSON = () =\u003e {\r\n     // ...\r\n  };\r\n\r\n  // 通过接口保存json对象\r\n  sendJSON = () =\u003e {\r\n     // ...\r\n  };\r\n\r\n  //监听lowcode的json改变\r\n  handleChange = (e: any) =\u003e {\r\n     // ...\r\n  };\r\n\r\n  //获取query\r\n  checkQuery = () =\u003e {\r\n     // ...\r\n  };\r\n\r\n  // 获取查询字符串\r\n  getQueryString = (name: string) =\u003e {\r\n     // ...\r\n  };\r\n\r\n  //监听项目名输入\r\n  inputItemName = () =\u003e {\r\n     // ...\r\n  };\r\n  //监听路由输入\r\n  inputRouteName = () =\u003e {\r\n     // ...\r\n  };\r\n  //根路径\r\n  inputUrlName = () =\u003e {\r\n     // ...\r\n  };\r\n\r\n  //开始预览\r\n  startPreview = () =\u003e {\r\n     // ...\r\n  };\r\n  //重置\r\n  clearJSON = () =\u003e {\r\n     // ...\r\n  };\r\n\r\n  //上一步\r\n  backHistoryJSON = () =\u003e {\r\n     // ...\r\n  };\r\n  //下一步\r\n  goHistoryJSON = () =\u003e {\r\n     // ...\r\n  };\r\n\r\n  //设置自定义样式\r\n  setStyles = () =\u003e {\r\n    // ...\r\n  };\r\n  //crud模板\r\n  setTpl = () =\u003e {\r\n    // ...\r\n  };\r\n\r\n  /**\r\n   * 转为domain, 注： 这里内部是无法拦截axios的请求，所以这里直接对序列化的字符串做替换\r\n   * 但是这种做法存在很容易出错，所以我们直接拦截ajax请求。\r\n   */\r\n  changeBaseURLtoDomain = (obj: any) =\u003e {\r\n    // ...\r\n  };\r\n  //转为${baseURL}\r\n  chengeDomaintoBaseURL = (obj: any) =\u003e {\r\n    // ...\r\n  };\r\n\r\n  render() {\r\n    return (\r\n      \u003c\u003e\r\n        {/* ......  */}\r\n        \u003cEditor\r\n          value={this.state.json}\r\n          onChange={this.handleChange}\r\n          preview={this.state.preview}\r\n        /\u003e\r\n      \u003c/\u003e\r\n    );\r\n  }\r\n}\r\n\r\nexport default App;\r\n\r\n```\r\n\r\n**调整：** 在编辑器中你无法拦截到内部 amis 的 axios 请求实例，所以在原来的处理中域名是直接 json 解析，不方便处理，现在通过 ajax-hooks 库直接拦截 ajax 请求，可以根据业务配置你的请求头、域名等。\r\n\r\n```sh\r\n npm i ajax-hook\r\n```\r\n\r\n```js\r\nimport { proxy } from \"ajax-hook\"\r\n\r\n//拦截处理\r\nproxy({\r\n    onRequest: (config, handler) =\u003e {\r\n        // config.headers = headers;  在这里处理通用请求头\r\n        config.url = this.state.baseURL + config.url //处理url\r\n        handler.next(config)\r\n    },\r\n    onError: (err, handler) =\u003e {\r\n        console.log(err.type)\r\n        handler.next(err)\r\n    },\r\n    onResponse: (response, handler) =\u003e {\r\n        console.log(response.response)\r\n        handler.next(response)\r\n    },\r\n})\r\n```\r\n\r\n# 🏡 后端服务\r\n\r\n```js\r\n//server/app.js  用于调试服务端\r\nconst http = require(\"http\")\r\nconst fs = require(\"fs\")\r\nconst path = require(\"path\")\r\n\r\n/**\r\n * 失败数据模型\r\n * @param {*} msg 消息\r\n */\r\nfunction errModel(msg) {\r\n    let obj = {\r\n        success: false,\r\n        msg,\r\n    }\r\n    return JSON.stringify(obj)\r\n}\r\n\r\nhttp.createServer(function (req, res) {\r\n    res.setHeader(\"Access-Control-Allow-Origin\", \"*\")\r\n    res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type\")\r\n    res.setHeader(\"Content-Type\", \"application/json;\")\r\n    res.setHeader(\"Access-Control-Allow-Methods\", \"DELETE,PUT,POST,GET,OPTIONS\")\r\n    console.log(req.url)\r\n    console.log(req.method)\r\n    if (req.method == \"OPTIONS\") {\r\n        res.writeHead(200, {\r\n            \"Content-Type\": \"text/plain\",\r\n            \"Access-Control-Allow-Origin\": \"*\",\r\n            \"Access-Control-Allow-Headers\":\r\n                \"Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild, sessionToken\",\r\n            \"Access-Control-Allow-Methods\": \"PUT, POST, GET, DELETE, OPTIONS\",\r\n        })\r\n        res.end(\"\")\r\n    }\r\n\r\n    if (req.method === \"POST\" \u0026\u0026 req.url === \"/api/setJSON\") {\r\n        let item = \"\"\r\n        // 读取每次发送的数据\r\n        req.on(\"data\", function (chunk) {\r\n            item += chunk.toString()\r\n        })\r\n        // 数据发送完成\r\n        req.on(\"end\", function () {\r\n            let items = JSON.parse(item)\r\n            if (items.routeName \u0026\u0026 items.itemName) {\r\n                let file = path.join(__dirname, `${items.routeName}.json`)\r\n                // json文件需要存入路径\r\n                fs.writeFileSync(file, item)\r\n                //将数据返回到客户端\r\n                res.write(item)\r\n                res.end()\r\n            } else {\r\n                res.write(errModel(\"文件配置失败, 检查路由或项目名是否正确\"))\r\n                res.end()\r\n            }\r\n        })\r\n    }\r\n\r\n    //本地模拟直接用client-admin.json\r\n    if (req.method === \"POST\" \u0026\u0026 req.url === \"/api/getJSON\") {\r\n        let item = \"\"\r\n        // 读取每次发送的数据\r\n        req.on(\"data\", function (chunk) {\r\n            item += chunk.toString()\r\n        })\r\n        // 数据发送完成\r\n        req.on(\"end\", function () {\r\n            let items = JSON.parse(item)\r\n\r\n            if (items.routeName \u0026\u0026 items.itemName) {\r\n                let file = path.join(__dirname, `${items.routeName}.json`)\r\n\r\n                fs.readFile(file, \"utf-8\", function (err, data) {\r\n                    if (err) {\r\n                        console.log(err)\r\n                        res.write(errModel(\"请检查路由是否正确\"))\r\n                        res.end()\r\n                    } else {\r\n                        let obj = JSON.parse(data)\r\n                        res.write(JSON.stringify(obj.json))\r\n                        res.end()\r\n                    }\r\n                })\r\n            } else {\r\n                res.write(errModel(\"请检查路由或项目名是否正确\"))\r\n                res.end()\r\n            }\r\n        })\r\n    }\r\n}).listen(3001) // 监听的端口\r\n```\r\n\r\n## 🥦 如何在 Vue 的前端项目中使用 ？\r\n\r\n### 1. 在静态目录 public 中的 index.html 引入对应的 sdk，sdk 官网有可以自行下载\r\n\r\n```js\r\n  \u003clink rel=\"stylesheet\" href=\"./lowcode/amis/antd.css\" /\u003e\r\n  \u003clink rel=\"stylesheet\" href=\"./lowcode/amis/iconfont.css\" /\u003e\r\n  \u003cscript src=\"./lowcode/amis/sdk.js\"\u003e\u003c/script\u003e\r\n```\r\n\r\n### 2. 在路由允许的情况下调用封装的方法，即可渲染 lowcode 页面\r\n\r\n```js\r\nimport Vue from \"vue\"\r\nimport defaultConfig from \"./config\"\r\nimport axios from \"axios\"\r\n\r\nvar timer = null\r\n\r\nlet defaultOptions = {\r\n    method: \"local\", // 'http' | 'local' 通过接口返回或者本地静态文件夹获取\r\n    routeName: \"\", //输入路由名（必填）\r\n    itemName: \"\", //项目名（必填）\r\n}\r\nlet newOptions //修改后的配置\r\n/**\r\n * 在路由允许的情况下调用可生成对应lowcode页面\r\n * @param {DOM} DOM\r\n * @param {Object} options\r\n */\r\nexport const getLowcodePage = (DOM, options = {}) =\u003e {\r\n    newOptions = Object.assign(defaultOptions, options)\r\n    let { routeName } = newOptions\r\n    if (!DOM || !routeName) {\r\n        throw new Error(\"DOM or routeName is no exist\")\r\n    }\r\n\r\n    //handle first render error\r\n    const check = routeName =\u003e {\r\n        let dom = document.querySelector(DOM)\r\n        if (dom) {\r\n            getJsonFs(routeName)\r\n            if (!timer) {\r\n                clearTimeout(timer)\r\n            }\r\n        } else {\r\n            timer = setTimeout(() =\u003e {\r\n                check(routeName)\r\n            }, 0)\r\n        }\r\n    }\r\n\r\n    //get json\r\n    const getJsonFs = routeName =\u003e {\r\n        if (newOptions.method === \"local\") {\r\n            Vue.http\r\n                .get(\r\n                    `lowcode/pages/${routeName}.json`,\r\n                    {},\r\n                    { emulateJSON: true }\r\n                )\r\n                .then(res =\u003e {\r\n                    let obj = JSON.parse(res.bodyText)\r\n                    if (obj) {\r\n                        startAmis(obj)\r\n                    }\r\n                })\r\n                .catch(error =\u003e {\r\n                    console.log(\"error\", error)\r\n                })\r\n        }\r\n\r\n        if (newOptions.method === \"http\") {\r\n            //正式项目需要通过post请求传入对象{routeName, itemName}\r\n            //目前调试使用，注意某些跨域情况在vue.config.js中做跨域代理\r\n            axios\r\n                .post(\r\n                    \"/api/getJSON\",\r\n                    {\r\n                        routeName: options.routeName,\r\n                        itemName: options.itemName,\r\n                    },\r\n                    {\r\n                        headers: {\r\n                            \"Content-Type\": \"application/json\",\r\n                        },\r\n                    }\r\n                )\r\n                .then(res =\u003e {\r\n                    let { data } = res\r\n                    startAmis(data)\r\n                    console.log(\"http\", data)\r\n                })\r\n                .catch(e =\u003e {\r\n                    alert(\"获取后端json失败\" + JSON.stringify(e))\r\n                })\r\n        }\r\n    }\r\n\r\n    //amis render\r\n    const startAmis = jsonObj =\u003e {\r\n        console.log(\"jsonObj\", jsonObj)\r\n        let amis = window.amisRequire(\"amis/embed\")\r\n        amis.embed(\r\n            DOM,\r\n            jsonObj,\r\n            {\r\n                data: {\r\n                    baseUrl: process.env.VUE_APP_API_BASE_URL,\r\n                },\r\n            },\r\n            defaultConfig\r\n        )\r\n    }\r\n\r\n    //entrance\r\n    check(routeName)\r\n}\r\n```\r\n\r\n### 3. 做跨域代理\r\n\r\n1. 在 create-react-app 中跨域\r\n\r\n```js\r\n//package.json\r\n{\r\n  \"proxy\":\"http://localhost:3001\", //你要跨域的地址，默认会匹配替换/api\r\n}\r\n\r\n//App.tsx\r\ncomponentDidMount() {\r\n\t\tproxy({\r\n\t\t\tonRequest: (config, handler) =\u003e {\r\n        //取消根路径配置即可跨域\r\n\t\t\t\t// config.url = this.state.baseURL + config.url;\r\n\t\t\t},\r\n\t\t});\r\n\t}\r\n```\r\n\r\n2. 在 vue 中跨域\r\n\r\n```js\r\n  //vue.config.js\r\n  devServer: {\r\n    proxy: {\r\n      //测试lowcode使用\r\n      '/api': {\r\n        target: 'http://localhost:3001',\r\n        changeOrigin: true,\r\n      },\r\n    }\r\n  },\r\n```\r\n\r\n### 4. 开始调用方法\r\n\r\n```js\r\n\u003ctemplate\u003e\r\n  \u003cdiv id='main-lowcode'\u003e\r\n    \u003cdiv id=\"content-lowcode\"\u003e\r\n    \u003c/div\u003e\r\n  \u003c/div\u003e\r\n\r\n\u003c/template\u003e\r\n\r\n\u003cscript\u003e\r\nimport { getLowcodePage } from '@/lowcode/index'\r\n\r\nexport default {\r\n  data() {\r\n    return {}\r\n  },\r\n  created() {},\r\n  mounted() {\r\n    // 获取lowcode页面\r\n    getLowcodePage('#content-lowcode', {\r\n      method: 'http', //'http'代表接口请求，注意如果是'local',请在public文件夹中放入json配置文件，即可本地获取json页面\r\n      routeName: 'client-admin',\r\n      itemName: 'cms2'\r\n    })\r\n  }\r\n}\r\n\u003c/script\u003e\r\n```\r\n\r\n# 😃 总结\r\n\r\n### 实现以上基本能快速将中后台系统集成进低代码页面, 甚至单独搭建一个低代码管理后台。 可谓是 crud 的解决办法的神器。\r\n\r\n---\r\n\r\n### 问题 1: 如果在集成中的样式需要做到统一？\r\n\r\n可以在 amis 包的 amis.css 修改，建议根据原有中后台系统配色修改，独立引入 html。在编辑器中针对不同的中后台项目，已经封装了可以通过按钮预览对应的样式的页面，在/public/styles 可以配置修改。\r\n\r\n### 问题 2: 如何自定义组件？\r\n\r\n如果存在定制化的组件，也是可以通过自定义组件的方式引入，在 src/customComponents 里面已经定义了一个示例，后期会新增更多自定义组件。。\r\n\r\n### 问题 3： 如何处理权限？\r\n\r\n可以通过 JSON 的解析，找到对应的 disabled 字段，做对应的修改即可\r\n\r\n### 问题 4： 哪里找到大量的模板？\r\n\r\nhttps://aisuda.bce.baidu.com/amis/examples/index\r\n\r\n### 问题 5：真正如何托拉拽实现，前端不用敲代码！\r\n\r\n在实践中不能敲代码，那么真正用编辑器实现一个 crud 的功能，会遇到一些坑，如对应的返回的数据格式可以有适配器转换，查询功能和实际列表展示，一定要注意映射字段的处理。在批量处理中一定要后端必须传入 id。列表中的一些字段其实也可以用映射，按需展示，修改等。\r\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fccj-007%2Flowcode-editor-send","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fccj-007%2Flowcode-editor-send","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fccj-007%2Flowcode-editor-send/lists"}