├── .gitignore ├── .prettierrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── client ├── .babelrc ├── .eslintrc ├── .jest.js ├── .prettierrc ├── README.md ├── config │ ├── env.js │ ├── modules.js │ ├── paths.js │ ├── setupProxy.js │ ├── webpack.config.js │ └── webpackDevServer.config.js ├── jsconfig.json ├── package.json ├── public │ ├── favicon.ico │ └── index.html ├── scripts │ ├── build.js │ ├── start.js │ ├── test.js │ └── utils.js ├── src │ ├── apis │ │ ├── admin.ts │ │ ├── index.ts │ │ ├── page.ts │ │ ├── project.ts │ │ └── user.ts │ ├── assets │ │ ├── 403.svg │ │ ├── 404.svg │ │ ├── 500.svg │ │ ├── button-add.png │ │ ├── head.png │ │ ├── ke.ico │ │ └── logo.png │ ├── common │ │ └── router.tsx │ ├── components │ │ ├── Exception │ │ │ ├── 403.tsx │ │ │ ├── 404.tsx │ │ │ ├── 500.tsx │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ └── typeConfig.ts │ │ ├── HtmlFragment │ │ │ └── index.tsx │ │ ├── Iframe │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ └── interface.d.ts │ │ ├── JsonEditor │ │ │ ├── Controled.d.ts │ │ │ ├── Controled.tsx │ │ │ ├── _utils.ts │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ └── interface.d.ts │ │ └── _utils │ │ │ └── pathTools.ts │ ├── constant │ │ ├── env.ts │ │ ├── keyboardEvent.ts │ │ ├── state.ts │ │ └── submodule.ts │ ├── favicon.ico │ ├── index.less │ ├── index.ts │ ├── models │ │ ├── global.ts │ │ └── guiEditor.ts │ ├── router.tsx │ ├── routes │ │ ├── Admin │ │ │ ├── Card │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── Layout │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── Login │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── ModifyPassword │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ └── Register │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ ├── Exception │ │ │ ├── 403.tsx │ │ │ ├── 404.tsx │ │ │ └── 500.tsx │ │ ├── GuiEditor │ │ │ ├── components │ │ │ │ ├── Content │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── Header │ │ │ │ │ ├── ThePublishModal │ │ │ │ │ │ ├── index.module.less │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── interface.d.ts │ │ │ │ │ ├── index.module.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── SiderLeft │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── SiderRight │ │ │ │ │ ├── FormEditor │ │ │ │ │ │ ├── compontent │ │ │ │ │ │ │ ├── FormItem │ │ │ │ │ │ │ │ ├── index.less │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ ├── input │ │ │ │ │ │ │ │ ├── index.less │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ └── readme.md │ │ │ │ │ │ ├── index.module.less │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── interface.d.ts │ │ │ │ │ ├── JSONEditor │ │ │ │ │ │ ├── index.module.less │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── interface.d.ts │ │ │ │ │ ├── index.module.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.ts │ │ │ │ └── Stage │ │ │ │ │ ├── HoverOverlay │ │ │ │ │ ├── DropTargetWrapper │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── interface.d.ts │ │ │ │ │ ├── index.module.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ │ ├── SelectedOverlay │ │ │ │ │ ├── index.module.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ │ ├── _utils.ts │ │ │ │ │ ├── index.module.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ └── interface.ts │ │ ├── Home │ │ │ ├── IconButton │ │ │ │ └── index.tsx │ │ │ ├── Layout │ │ │ │ ├── Basic │ │ │ │ │ ├── Header │ │ │ │ │ │ ├── index.less │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── interface.d.ts │ │ │ │ │ ├── SiderMenu │ │ │ │ │ │ ├── index.less │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── interface.d.ts │ │ │ │ │ ├── index.module.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── Blank │ │ │ │ │ └── index.tsx │ │ │ │ └── index.ts │ │ │ ├── ModalClone │ │ │ │ ├── index.tsx │ │ │ │ └── interface.d.ts │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ └── interface.d.ts │ │ ├── Preview │ │ │ └── index.tsx │ │ └── Templates │ │ │ ├── components │ │ │ └── Card │ │ │ │ ├── index.module.less │ │ │ │ ├── index.tsx │ │ │ │ └── interface.d.ts │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ └── interface.d.ts │ ├── types │ │ ├── components │ │ │ ├── editConfig.ts │ │ │ ├── interfaceBaseCompontentProps.ts │ │ │ └── interfaceEditConfig.ts │ │ ├── models │ │ │ ├── connect.d.ts │ │ │ ├── editor.d.ts │ │ │ ├── global.d.ts │ │ │ └── guiEditor.d.ts │ │ └── routes │ │ │ └── GuiEditor │ │ │ └── components │ │ │ └── props.ts │ └── utils │ │ ├── apis.ts │ │ ├── events.ts │ │ ├── history.ts │ │ ├── index.ts │ │ ├── localHistory.ts │ │ ├── request.ts │ │ ├── utils.ts │ │ └── valid.ts ├── tsconfig.json ├── typings.d.ts └── yarn.lock ├── deploy.md ├── plugin ├── .babelrc ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── README.md ├── __mocks__ │ ├── axios.ts │ └── moment.ts ├── gulpfile.js │ ├── copy-docs.js │ ├── copy-types.js │ └── index.js ├── jest.config.js ├── package.json ├── prettier.config.js ├── site │ ├── bisheng.config.js │ ├── docs │ │ ├── editor │ │ │ ├── 01-introduce.md │ │ │ ├── 02-request.md │ │ │ ├── 02-scenarios.md │ │ │ ├── 03-page-build.md │ │ │ ├── 03-page-debug.md │ │ │ ├── 03-page-publish.md │ │ │ ├── 03-page-version.md │ │ │ ├── 03-project-create.md │ │ │ ├── 03-project-whitelist.md │ │ │ ├── 03-questions.md │ │ │ ├── 05-json-pageconfig.md │ │ │ ├── 05-json-pagestate.md │ │ │ ├── 05-json-syntax.md │ │ │ ├── 06-senior-form.md │ │ │ ├── 06-senior-formdata.md │ │ │ ├── 06-senior-transform.md │ │ │ ├── _03-page.md_ │ │ │ ├── _04-json-actions.md_ │ │ │ └── changeLog.md │ │ ├── resources │ │ │ └── video.md │ │ └── stark │ │ │ └── 01-introduce.md │ ├── favicon.ico │ ├── hetu.ts │ ├── package.json │ ├── template.html │ ├── theme │ │ ├── index.js │ │ ├── static │ │ │ ├── colors.less │ │ │ ├── common.less │ │ │ ├── demo.less │ │ │ ├── docsearch.less │ │ │ ├── favicon.ico │ │ │ ├── footer.less │ │ │ ├── header.less │ │ │ ├── highlight.less │ │ │ ├── home.less │ │ │ ├── icons.less │ │ │ ├── index.less │ │ │ ├── markdown.less │ │ │ ├── mock-browser.less │ │ │ ├── motion.less │ │ │ ├── new-version-info-modal.less │ │ │ ├── not-found.less │ │ │ ├── nprogress.less │ │ │ ├── page-nav.less │ │ │ ├── preview-img.less │ │ │ ├── resource.less │ │ │ ├── responsive.less │ │ │ ├── santa.less │ │ │ ├── style.js │ │ │ ├── template.html │ │ │ ├── theme.less │ │ │ └── toc.less │ │ ├── style │ │ │ ├── color │ │ │ │ ├── bezierEasing.less │ │ │ │ ├── colorPalette.less │ │ │ │ ├── colors.less │ │ │ │ └── tinyColor.less │ │ │ ├── core │ │ │ │ ├── base.less │ │ │ │ ├── iconfont.less │ │ │ │ ├── index.less │ │ │ │ ├── motion.less │ │ │ │ └── motion │ │ │ │ │ ├── fade.less │ │ │ │ │ ├── move.less │ │ │ │ │ ├── other.less │ │ │ │ │ ├── slide.less │ │ │ │ │ ├── swing.less │ │ │ │ │ └── zoom.less │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ ├── mixins │ │ │ │ ├── clearfix.less │ │ │ │ ├── compatibility.less │ │ │ │ ├── iconfont.less │ │ │ │ ├── index.less │ │ │ │ ├── motion.less │ │ │ │ ├── operation-unit.less │ │ │ │ ├── reset.less │ │ │ │ └── size.less │ │ │ ├── themes │ │ │ │ ├── default.less │ │ │ │ └── index.less │ │ │ ├── v2-compatible-reset.jsx │ │ │ └── v2-compatible-reset.less │ │ ├── template │ │ │ ├── AppShell.jsx │ │ │ ├── BrowserFrame.jsx │ │ │ ├── Color │ │ │ │ ├── ColorBlock.jsx │ │ │ │ ├── ColorPaletteTool.jsx │ │ │ │ ├── ColorPalettes.jsx │ │ │ │ ├── ColorPatterns.jsx │ │ │ │ ├── ColorPicker.jsx │ │ │ │ └── Palette.jsx │ │ │ ├── Content │ │ │ │ ├── Article.jsx │ │ │ │ ├── ComponentDoc.jsx │ │ │ │ ├── Demo.jsx │ │ │ │ ├── EditButton.jsx │ │ │ │ ├── ErrorBoundary.js │ │ │ │ ├── MainContent.jsx │ │ │ │ ├── PrevAndNext.jsx │ │ │ │ └── index.jsx │ │ │ ├── FormattedMessage │ │ │ │ └── index.jsx │ │ │ ├── Home │ │ │ │ ├── index.jsx │ │ │ │ └── util.jsx │ │ │ ├── IconDisplay │ │ │ │ ├── Category.jsx │ │ │ │ ├── CopyableIcon.jsx │ │ │ │ ├── fields.js │ │ │ │ ├── index.jsx │ │ │ │ └── themeIcons.jsx │ │ │ ├── Layout │ │ │ │ ├── Header.jsx │ │ │ │ ├── SentryBoundary.jsx │ │ │ │ └── index.jsx │ │ │ ├── NotFound.jsx │ │ │ ├── Redirect.jsx │ │ │ ├── Resources │ │ │ │ ├── index.jsx │ │ │ │ └── index.less │ │ │ └── utils.jsx │ │ └── zh-CN.js │ ├── utils │ │ └── index.js │ └── yarn.lock ├── src │ ├── Hetu.test.tsx │ ├── Hetu.tsx │ ├── __mocks__ │ │ └── Hetu.ts │ ├── components │ │ ├── BChart │ │ │ ├── Chart │ │ │ │ ├── index.tsx │ │ │ │ └── interface.d.ts │ │ │ ├── ChartBar │ │ │ │ ├── demo │ │ │ │ │ ├── basic.md │ │ │ │ │ └── grouped.md │ │ │ │ └── index.md │ │ │ ├── ChartLine │ │ │ │ ├── demo │ │ │ │ │ ├── basic.md │ │ │ │ │ ├── multiple.md │ │ │ │ │ ├── series.md │ │ │ │ │ └── widthTable.md │ │ │ │ └── index.md │ │ │ ├── ChartPie │ │ │ │ ├── demo │ │ │ │ │ ├── basic.md │ │ │ │ │ ├── double.md │ │ │ │ │ ├── hollow.md │ │ │ │ │ └── semicircle.md │ │ │ │ └── index.md │ │ │ ├── __editor__ │ │ │ │ ├── additableProperties.ts │ │ │ │ ├── index.ts │ │ │ │ └── properties.ts │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ ├── interface.d.ts │ │ │ └── shapes.ts │ │ ├── Button │ │ │ ├── __editor__ │ │ │ │ ├── additableProperties.ts │ │ │ │ ├── defaultConfig.ts │ │ │ │ ├── index.ts │ │ │ │ └── properties.ts │ │ │ ├── __tests__ │ │ │ │ └── index.test.tsx │ │ │ ├── demo │ │ │ │ └── basic.md │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── interface.d.ts │ │ ├── Card │ │ │ ├── __editor__ │ │ │ │ ├── additableProperties.ts │ │ │ │ ├── defaultConfig.ts │ │ │ │ ├── index.ts │ │ │ │ └── properties.ts │ │ │ ├── __tests__ │ │ │ │ └── index.test.tsx │ │ │ ├── _index.md_ │ │ │ ├── components │ │ │ │ └── Primary │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ ├── demo │ │ │ │ ├── basic.md_ │ │ │ │ └── cardType.md_ │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ └── interface.d.ts │ │ ├── Container │ │ │ ├── __editor__ │ │ │ │ ├── additableProperties.ts │ │ │ │ ├── defaultConfig.ts │ │ │ │ ├── index.ts │ │ │ │ └── properties.ts │ │ │ ├── index.tsx │ │ │ └── interface.d.ts │ │ ├── Divider │ │ │ ├── __editor__ │ │ │ │ ├── additableProperties.ts │ │ │ │ ├── defaultConfig.ts │ │ │ │ ├── index.ts │ │ │ │ └── properties.ts │ │ │ ├── __tests__ │ │ │ │ └── index.test.tsx │ │ │ ├── demo │ │ │ │ └── basic.md │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── interface.d.ts │ │ ├── Exception │ │ │ ├── 403.tsx │ │ │ ├── 404.tsx │ │ │ ├── 500.tsx │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ ├── interface.d.ts │ │ │ └── typeConfig.ts │ │ ├── Field │ │ │ ├── __editor__ │ │ │ │ └── index.ts │ │ │ ├── __tests__ │ │ │ │ └── index.test.tsx │ │ │ ├── components │ │ │ │ ├── Alert │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── demo │ │ │ │ │ │ ├── basic.md │ │ │ │ │ │ ├── description.md │ │ │ │ │ │ └── showIcon.md │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── Checkbox │ │ │ │ │ ├── ModalAddOption │ │ │ │ │ │ ├── index.less │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── interface.d.ts │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── demo │ │ │ │ │ │ └── basic.md │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── Divider │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── demo │ │ │ │ │ │ └── basic.md │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── Input │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── demo │ │ │ │ │ │ └── basic.md │ │ │ │ │ ├── index.md │ │ │ │ │ └── index.tsx │ │ │ │ ├── InputNumber │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── demo │ │ │ │ │ │ └── basic.md │ │ │ │ │ ├── index.md │ │ │ │ │ └── index.tsx │ │ │ │ ├── InputPassword │ │ │ │ │ └── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ ├── InputTextarea │ │ │ │ │ └── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ ├── JsonEditor │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── _utils.ts │ │ │ │ │ ├── demo │ │ │ │ │ │ └── basic.md │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── PickerDate │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── demo │ │ │ │ │ │ └── basic.md │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── PickerDateTime │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ └── index.tsx │ │ │ │ ├── PickerMonth │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── PickerRange │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── PickerTime │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── PickerWeek │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── Radio │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── demo │ │ │ │ │ │ ├── basic.md │ │ │ │ │ │ └── optionsSourceType.md │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── Select │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── demo │ │ │ │ │ │ └── optionsSourceType.md │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── SelectCascade │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── demo │ │ │ │ │ │ ├── basic.md │ │ │ │ │ │ ├── changeOnSelect.md │ │ │ │ │ │ └── showSearch.md │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── SelectMultiple │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── demo │ │ │ │ │ │ ├── basic.md │ │ │ │ │ │ └── search.md │ │ │ │ │ ├── index.md │ │ │ │ │ └── index.tsx │ │ │ │ ├── SelectTree │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── demo │ │ │ │ │ │ ├── backfill.md │ │ │ │ │ │ ├── basic.md │ │ │ │ │ │ ├── loadOption.md │ │ │ │ │ │ ├── nodeValue.md │ │ │ │ │ │ └── showCheckedStrategy.md │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── SelectTrees │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── demo │ │ │ │ │ │ ├── backfill.md │ │ │ │ │ │ ├── basic.md │ │ │ │ │ │ ├── loadOption.md │ │ │ │ │ │ ├── nodeValue.md │ │ │ │ │ │ └── showCheckedStrategy.md │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── Steps │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── demo │ │ │ │ │ │ ├── basic.md │ │ │ │ │ │ └── description.md │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── TableEditor │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── _utils.ts │ │ │ │ │ ├── demo │ │ │ │ │ │ └── basic.md │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── Text │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── demo │ │ │ │ │ │ └── basic.md │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.d.ts │ │ │ │ ├── Upload │ │ │ │ │ ├── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── demo │ │ │ │ │ │ └── basic.md │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── interface.d.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── _EditableTable │ │ │ │ │ ├── EditableCell │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── interface.d.ts │ │ │ │ │ ├── __index.md__ │ │ │ │ │ ├── context.ts │ │ │ │ │ ├── demo │ │ │ │ │ │ ├── basic.md │ │ │ │ │ │ ├── children.md │ │ │ │ │ │ └── scroll.md │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── interface.ts │ │ │ │ └── index.ts │ │ │ ├── demo │ │ │ │ ├── basic.md │ │ │ │ ├── rules.md │ │ │ │ └── setFieldValues.md │ │ │ ├── index.less │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ ├── interface.d.ts │ │ │ ├── rules.ts │ │ │ └── types │ │ │ │ ├── baseProperty.ts │ │ │ │ ├── commonPropsDefine.ts │ │ │ │ └── interface.ts │ │ ├── Form │ │ │ ├── __editor__ │ │ │ │ ├── additableProperties │ │ │ │ │ ├── extra │ │ │ │ │ │ ├── default_value.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── fields │ │ │ │ │ │ ├── default_value.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── defaultConfig.ts │ │ │ │ ├── index.ts │ │ │ │ └── properties.ts │ │ │ ├── __tests__ │ │ │ │ └── index.test.tsx │ │ │ ├── demo │ │ │ │ ├── alias.md │ │ │ │ ├── buttons.md │ │ │ │ ├── create.md │ │ │ │ ├── edit.md │ │ │ │ └── transform.md │ │ │ ├── index.less │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── interface.d.ts │ │ ├── HtmlFragment │ │ │ └── index.tsx │ │ ├── List │ │ │ ├── __editor__ │ │ │ │ ├── additableProperties │ │ │ │ │ ├── columns │ │ │ │ │ │ ├── default_value.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── extra │ │ │ │ │ │ ├── default_value.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── fields │ │ │ │ │ │ ├── default_value.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── sections │ │ │ │ │ │ ├── default_value.ts │ │ │ │ │ │ └── index.ts │ │ │ │ ├── defaultConfig.ts │ │ │ │ ├── index.ts │ │ │ │ └── properties.ts │ │ │ ├── __tests__ │ │ │ │ └── index.test.tsx │ │ │ ├── components │ │ │ │ ├── ActionColumn │ │ │ │ │ └── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ ├── ActionColumn2 │ │ │ │ │ └── __editor__ │ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── properties.ts │ │ │ │ └── Column │ │ │ │ │ └── __editor__ │ │ │ │ │ ├── additableProperties.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── properties.ts │ │ │ ├── demo │ │ │ │ ├── basic.md │ │ │ │ ├── cardType.md │ │ │ │ ├── rowData.md │ │ │ │ ├── selections.md │ │ │ │ └── transform.md │ │ │ ├── index.less │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── interface.d.ts │ │ ├── ModalForm │ │ │ ├── __editor__ │ │ │ │ ├── additableProperties.ts │ │ │ │ ├── defaultConfig.ts │ │ │ │ ├── index.ts │ │ │ │ └── properties.ts │ │ │ ├── __tests__ │ │ │ │ └── index.test.tsx │ │ │ ├── demo │ │ │ │ └── basic.md │ │ │ ├── index.less │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── interface.d.ts │ │ ├── Steps │ │ │ ├── __editor__ │ │ │ │ ├── additableProperties.ts │ │ │ │ ├── defaultConfig.ts │ │ │ │ ├── index.ts │ │ │ │ └── properties.ts │ │ │ ├── demo │ │ │ │ ├── basic.md │ │ │ │ └── container.md │ │ │ ├── index._md │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ └── interface.d.ts │ │ ├── Table │ │ │ ├── __tests__ │ │ │ │ └── index.test.tsx │ │ │ ├── _index.npm.md_ │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ └── interfacce.d.ts │ │ ├── Tabs │ │ │ ├── __editor__ │ │ │ │ ├── additableProperties.ts │ │ │ │ ├── defaultConfig.ts │ │ │ │ ├── index.ts │ │ │ │ └── properties.ts │ │ │ ├── __tests__ │ │ │ │ └── index.test.tsx │ │ │ ├── demo │ │ │ │ ├── basic.md │ │ │ │ └── multiple.md │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── interface.d.ts │ │ ├── editorConfigs.ts │ │ ├── index.test.ts │ │ └── index.ts │ ├── index.less │ ├── index.ts │ ├── templates │ │ ├── chart │ │ │ └── line.ts │ │ ├── custom │ │ │ ├── advanced.ts │ │ │ ├── basicDetail.ts │ │ │ └── empty.ts │ │ ├── form │ │ │ ├── project_template_form_create.ts │ │ │ └── project_template_form_edit.ts │ │ ├── index.ts │ │ └── list │ │ │ ├── project_template_list_2.ts │ │ │ └── project_template_tabs_1.ts │ ├── types │ │ ├── editor.d.ts │ │ ├── index.d.ts │ │ └── jsonSchema.d.ts │ └── utils │ │ ├── __tests__ │ │ ├── actions.test.ts │ │ ├── event.test.ts │ │ ├── hetuTools.test.ts │ │ ├── index.test.tsx │ │ ├── request.test.ts │ │ └── valid.test.ts │ │ ├── actions.ts │ │ ├── events.ts │ │ ├── hetuTools.ts │ │ ├── hoc.tsx │ │ ├── index.ts │ │ ├── message.ts │ │ ├── request.ts │ │ └── valid.ts ├── test │ ├── setup.ts │ └── utils │ │ └── index.ts ├── tsconfig.json ├── tsdx.config.js ├── typings.d.ts └── yarn.lock ├── scripts ├── online_client.sh ├── online_docs.sh ├── online_plugin.sh ├── online_server.sh └── util.sh └── server ├── .prettierrc ├── README.md ├── copy_static_assets.js ├── open_hetu.sql ├── package.json ├── src ├── app.ts ├── commands │ ├── base.ts │ ├── summary │ │ ├── develop_report.ts │ │ └── online_report.ts │ └── task │ │ └── manage.ts ├── config │ ├── _prod.ts │ ├── app.ts │ ├── email.ts │ ├── env.ts │ ├── log.ts │ ├── login.ts │ ├── mysql.ts │ ├── mysql_env.ts │ ├── redis.ts │ └── superAdmin.ts ├── constant │ └── date_format.ts ├── controller │ ├── api │ │ ├── base.ts │ │ ├── department.ts │ │ ├── email.ts │ │ ├── feedback.ts │ │ ├── hetu.ts │ │ ├── login.ts │ │ ├── logviewer.ts │ │ ├── page │ │ │ ├── draft.ts │ │ │ ├── publish_history.ts │ │ │ └── record.ts │ │ ├── pageConfigV2.ts │ │ ├── project_new.ts │ │ ├── project_user.ts │ │ ├── submodule.ts │ │ └── upload.ts │ ├── index.ts │ ├── proxy │ │ ├── _utils.ts │ │ ├── base.ts │ │ └── base_proxy_controller.ts │ └── public │ │ └── readme.md ├── library │ ├── email │ │ └── index.ts │ ├── event │ │ └── index.ts │ ├── http │ │ └── index.ts │ ├── logger │ │ ├── config.ts │ │ └── index.ts │ ├── mysql │ │ └── index.ts │ ├── redis │ │ └── index.ts │ ├── s3 │ │ └── index.ts │ └── utils │ │ └── modules │ │ ├── network.ts │ │ ├── systerm.ts │ │ └── util.ts ├── middleware │ ├── context.ts │ ├── errorHandler.ts │ ├── login.ts │ ├── multi-form.ts │ └── proxy.ts ├── model │ ├── base.ts │ ├── department.ts │ ├── feedback.ts │ ├── global.ts │ ├── login.ts │ ├── page │ │ ├── draft.ts │ │ ├── publish_history.ts │ │ └── record.ts │ ├── project.ts │ ├── reporter │ │ ├── _utils.ts │ │ ├── development_week_render.ts │ │ ├── index.ts │ │ ├── online_render.ts │ │ └── online_week_render.ts │ ├── submodule.ts │ ├── user.ts │ └── validator.ts ├── public │ ├── favicon.ico │ └── index.html ├── socket.ts └── task.ts ├── tsconfig.json ├── typings.d.ts └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | logs/ 2 | npm-debug.log 3 | yarn-error.log 4 | node_modules/ 5 | coverage/ 6 | .idea/ 7 | run/ 8 | .DS_Store 9 | *.sw* 10 | *.un~ 11 | dist/* 12 | mochawesome-report/ 13 | 14 | # 屏蔽编译ts后生成的js/js.map文件 15 | server/app/**/*.js 16 | server/app/**/*.js.map 17 | server/src/**/*.js 18 | server/src/**/*.js.map 19 | server/dist/**/*.js 20 | server/dist/**/*.js.map 21 | 22 | # 忽略编译出来的静态文件 23 | server/app/public/ 24 | # 自带的index.html会在线上打包时被覆盖掉, 所以没有问题 25 | server/dist 26 | client/dist 27 | 28 | client/.env.local 29 | .history 30 | .vscode 31 | 32 | # 系统配置文件 33 | system_config.ini 34 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 240, 3 | "tabWidth": 2, 4 | "semi": false, 5 | "singleQuote": true, 6 | "trailingComma": "all" 7 | } 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) 4 | 5 | ## 关于发版 6 | 7 | 版本格式(参照[语义化版本](https://semver.org/lang/zh-CN/)):主版本号.次版本号.修订号,版本号递增规则如下: 8 | 9 | - 主版本号:当做了不兼容的 API 修改, 10 | - 次版本号:当做了向下兼容的功能性新增, 11 | - 修订号:当做了向下兼容的问题修正。 12 | 13 | ## [1.0.0] 2020-09-27 14 | 15 | ### 河图开源 16 | -------------------------------------------------------------------------------- /client/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": "> 0.25%, not dead" 7 | } 8 | ], 9 | ["@babel/preset-react"], 10 | [ 11 | "@babel/preset-typescript", 12 | { 13 | "isTSX": true, 14 | "allExtensions": true 15 | } 16 | ] 17 | ], 18 | "plugins": [ 19 | "@babel/plugin-syntax-dynamic-import", 20 | [ 21 | "@babel/plugin-proposal-decorators", 22 | { 23 | "legacy": true 24 | } 25 | ], 26 | "@babel/plugin-proposal-class-properties", 27 | "@babel/plugin-proposal-object-rest-spread", 28 | [ 29 | "module-resolver", 30 | { 31 | "root": "./", 32 | "alias": { 33 | "~": "./src", 34 | "@test": "./test", 35 | "*": ["src/*", "node_modules/*"] 36 | } 37 | } 38 | ] 39 | ], 40 | "ignore": [] 41 | } 42 | -------------------------------------------------------------------------------- /client/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "parserOptions": { 4 | "ecmaFeatures": { 5 | "legacyDecorators": true 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /client/.jest.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | setupFiles: [ 3 | './test/setup.js', 4 | ], 5 | moduleFileExtensions: [ 6 | 'js', 7 | 'jsx', 8 | ], 9 | testPathIgnorePatterns: [ 10 | '/node_modules/', 11 | ], 12 | testRegex: '.*\\.test\\.js$', 13 | collectCoverage: false, 14 | collectCoverageFrom: [ 15 | 'src/components/**/*.{jsx}' 16 | ], 17 | moduleNameMapper: { 18 | "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/test/__mocks__/fileMock.js", 19 | "\\.(css|less|scss)$": "/test/__mocks__/styleMock.js", 20 | "\\.module$": "identity-obj-proxy" 21 | }, 22 | transform: { 23 | "^.+\\.js$": "babel-jest", 24 | "^.+\\.jsx$": "babel-jest" 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /client/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 240, 3 | "tabWidth": 2, 4 | "semi": false, 5 | "singleQuote": true, 6 | "trailingComma": "all" 7 | } 8 | -------------------------------------------------------------------------------- /client/README.md: -------------------------------------------------------------------------------- 1 | ### package.json 2 | 3 | 文件目录结构: 4 | ```bash 5 | . 6 | ├── dist 7 | │   └── 编译输出 8 | ├── config 9 | │   └── webpack配置文件 10 | ├── public 11 | │   └── 全局性静态资源 12 | ├── scripts 13 | │   └── webpack打包脚本 14 | ├── src 15 | │   ├── types 16 | │   │   └── 类型声明文件, 路径和实际文件对应路径保持一致 17 | │   ├── constant 18 | │   │   └── 项目常量 19 | │   ├── common 20 | │   │   └── router.js 21 | │   │   └── 项目路由 22 | │   ├── components 23 | │   │   │ └── 组件库 24 | │   │   └── _utils 25 | │   │   └── 组件内公用函数库 26 | │   ├── pageConfigs 27 | │   │   └── 静态页面模板 28 | │   ├── routes 29 | │   │   └── 编辑器路由 30 | │   ├── assets 31 | │   │   └── 组件内静态资源 32 | │   ├── decorators 33 | │   │   └── 装饰器,用于读取propType属性, 目前已废弃 34 | │   ├── libraries 35 | │   │   └── editor 36 | │   │   └── redskull2依赖文件, 安装时自动生成 37 | │   ├── models 38 | │   │   └── dva中所用model 39 | │   └── utils 40 | │   └── 全局公用函数库 41 | └── test 42 | └── __mocks__ 43 | 44 | 45 | ``` 46 | -------------------------------------------------------------------------------- /client/config/setupProxy.js: -------------------------------------------------------------------------------- 1 | const proxy = require('http-proxy-middleware') 2 | 3 | let proxyTargetConfig = { 4 | target: `http://127.0.0.1:7001/`, 5 | changeOrigin: true, 6 | ws: true 7 | } 8 | // 在client/config/paths.js中使用 9 | module.exports = function (app) { 10 | app.use(proxy('/hetu/api', proxyTargetConfig)) 11 | app.use(proxy('/hetu-cdn', proxyTargetConfig)) 12 | app.use(proxy('/__log__', proxyTargetConfig)) 13 | app.use(proxy('/__hetu_log__', proxyTargetConfig)) 14 | app.use(proxy('/socket.io', proxyTargetConfig)) 15 | app.use(proxy('/api', proxyTargetConfig)) 16 | app.use(proxy('/logout', proxyTargetConfig)) 17 | app.use(proxy('/oauth', proxyTargetConfig)) 18 | app.use(proxy('/mock', proxyTargetConfig)) 19 | app.use(proxy('/test-pyy', proxyTargetConfig)) 20 | } 21 | -------------------------------------------------------------------------------- /client/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./src", 4 | "paths": { 5 | "~/*": ["*"] 6 | }, 7 | "experimentalDecorators": true // Enables experimental support for ES7 decorators. 8 | }, 9 | "exclude": ["node_modules", "dist"] 10 | } 11 | -------------------------------------------------------------------------------- /client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LianjiaTech/hetu/b34b572d5898e7aea939ec5f4b2adbe3a9cabebd/client/public/favicon.ico -------------------------------------------------------------------------------- /client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 河图 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /client/scripts/utils.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra') 2 | const paths = require('../config/paths') 3 | 4 | exports.copyPublicFolder = function copyPublicFolder() { 5 | fs.copySync(paths.appPublic, paths.appBuild, { 6 | dereference: true, 7 | filter: (file) => file !== paths.appHtml, 8 | }) 9 | } 10 | -------------------------------------------------------------------------------- /client/src/apis/index.ts: -------------------------------------------------------------------------------- 1 | import Admin from './admin' 2 | import Page from './page' 3 | import Project from './project' 4 | import User from './user' 5 | 6 | export default { 7 | Admin, 8 | Page, 9 | Project, 10 | User, 11 | } 12 | -------------------------------------------------------------------------------- /client/src/apis/user.ts: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | import request from '~/utils/request' 3 | 4 | export default class User { 5 | /** 6 | * 获取用户信息 7 | */ 8 | static async getAsyncUserInfo() { 9 | return request.get('/api/hetu/info').then((res) => { 10 | if (_.isPlainObject(_.get(res, 'data'))) { 11 | return Promise.resolve(res.data) 12 | } 13 | return Promise.reject('getAsyncUserInfo 返回值格式错误') 14 | }) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /client/src/assets/button-add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LianjiaTech/hetu/b34b572d5898e7aea939ec5f4b2adbe3a9cabebd/client/src/assets/button-add.png -------------------------------------------------------------------------------- /client/src/assets/head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LianjiaTech/hetu/b34b572d5898e7aea939ec5f4b2adbe3a9cabebd/client/src/assets/head.png -------------------------------------------------------------------------------- /client/src/assets/ke.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LianjiaTech/hetu/b34b572d5898e7aea939ec5f4b2adbe3a9cabebd/client/src/assets/ke.ico -------------------------------------------------------------------------------- /client/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LianjiaTech/hetu/b34b572d5898e7aea939ec5f4b2adbe3a9cabebd/client/src/assets/logo.png -------------------------------------------------------------------------------- /client/src/components/Exception/403.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Button } from 'antd' 3 | import Exception from './' 4 | 5 | export default class Exception403 extends React.Component { 6 | 7 | goHome = () => { 8 | window.location.href = '/' 9 | } 10 | 11 | render() { 12 | return 返回} /> 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /client/src/components/Exception/404.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Exception from './' 3 | 4 | export default () => ( 5 | 6 | ) 7 | -------------------------------------------------------------------------------- /client/src/components/Exception/500.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Exception from './' 3 | 4 | export default () => ( 5 | 9 | ) 10 | -------------------------------------------------------------------------------- /client/src/components/Exception/typeConfig.ts: -------------------------------------------------------------------------------- 1 | const config = { 2 | 403: { 3 | img: '//file.ljcdn.com/hetu-cdn/1557744577067.6889e8c80d32a4cc7574e70150594320.png', 4 | title: '403', 5 | desc: '抱歉,你无权访问该页面', 6 | }, 7 | 404: { 8 | img: '//file.ljcdn.com/hetu-cdn/1557744599553.bc5795db2c6ff54b41b645cc261006f2.png', 9 | title: '404', 10 | desc: '抱歉,你访问的页面不存在', 11 | }, 12 | 500: { 13 | img: '//file.ljcdn.com/hetu-cdn/1557744613778.be1105502172e686c980856fe5b939ed.png', 14 | title: '500', 15 | desc: '抱歉,服务器出错了', 16 | }, 17 | } 18 | 19 | export default config 20 | -------------------------------------------------------------------------------- /client/src/components/HtmlFragment/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | interface IProps { 4 | block?: boolean 5 | __html: string 6 | } 7 | 8 | export default class HtHtml extends React.Component { 9 | render() { 10 | const { __html, block } = this.props 11 | 12 | const C: keyof JSX.IntrinsicElements = block ? 'div' : 'span' 13 | 14 | return 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /client/src/components/Iframe/index.less: -------------------------------------------------------------------------------- 1 | .base-iframe { 2 | display: block; 3 | width: 100%; 4 | height: 100%; 5 | overflow: hidden; 6 | border: 0; 7 | } 8 | -------------------------------------------------------------------------------- /client/src/components/Iframe/interface.d.ts: -------------------------------------------------------------------------------- 1 | export interface Props { 2 | src: string 3 | onLoad: (event: React.SyntheticEvent) => void 4 | getRef: (v: any) => void 5 | onKeydown: (e: KeyboardEvent) => void 6 | } 7 | -------------------------------------------------------------------------------- /client/src/components/JsonEditor/Controled.d.ts: -------------------------------------------------------------------------------- 1 | type valueType = string | undefined | null 2 | export interface JsonEditorProps { 3 | defaultValue?: valueType 4 | value?: valueType 5 | disabled?: boolean 6 | height?: number 7 | 8 | onChange?: (v: string) => void 9 | getRef: (c: any) => void 10 | } 11 | 12 | export interface JsonEditorState { 13 | codeStr?: string 14 | code?: any 15 | isEditorVisible: boolean 16 | height: number 17 | } 18 | -------------------------------------------------------------------------------- /client/src/components/JsonEditor/index.less: -------------------------------------------------------------------------------- 1 | .ht-json-editor { 2 | padding: 10px 2px; 3 | border: 1px solid #d9d9d9; 4 | border-radius: 4px; 5 | height: 100%; 6 | } 7 | -------------------------------------------------------------------------------- /client/src/components/JsonEditor/interface.d.ts: -------------------------------------------------------------------------------- 1 | type valueType = string | undefined | null 2 | export interface JsonEditorProps { 3 | defaultValue?: valueType 4 | value?: valueType 5 | disabled?: boolean 6 | onChange?: (v: string) => void 7 | height?: number 8 | } 9 | 10 | export interface JsonEditorState { 11 | isEditorVisible: boolean 12 | height: number 13 | } 14 | -------------------------------------------------------------------------------- /client/src/components/_utils/pathTools.ts: -------------------------------------------------------------------------------- 1 | // /userinfo/2144/id => ['/userinfo','/useinfo/2144,'/userindo/2144/id'] 2 | export function urlToList(url: string): string[] { 3 | if (url === '/') return ['/'] 4 | const urllist = url.split('/').filter((i) => i) 5 | return urllist.map((urlItem, index) => { 6 | return `/${urllist.slice(0, index + 1).join('/')}` 7 | }) 8 | } 9 | -------------------------------------------------------------------------------- /client/src/constant/env.ts: -------------------------------------------------------------------------------- 1 | const ENV_DEV = 'dev' 2 | const ENV_TEST = 'test' 3 | const ENV_PROD = 'prod' 4 | 5 | // 从页面配置中获取当前环境变量 6 | let env = window.ENV 7 | 8 | class ENV { 9 | static current = env 10 | static envList = [ENV_DEV, ENV_TEST, ENV_PROD] 11 | } 12 | 13 | export default ENV 14 | -------------------------------------------------------------------------------- /client/src/constant/state.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 导出State中会用到的常量 3 | */ 4 | class State { 5 | static InsertItemAt_Before = 'before' 6 | static InsertItemAt_After = 'after' 7 | } 8 | 9 | export default State 10 | -------------------------------------------------------------------------------- /client/src/constant/submodule.ts: -------------------------------------------------------------------------------- 1 | // 从页面配置中获取当前环境变量 2 | let env = window.ENV 3 | 4 | const config = { 5 | dev: `hetu-plugin`, 6 | test: `hetu-plugin`, 7 | prod: `hetu-plugin`, 8 | } 9 | 10 | export function getDefaultSubmodule() { 11 | return config[env] 12 | } 13 | -------------------------------------------------------------------------------- /client/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LianjiaTech/hetu/b34b572d5898e7aea939ec5f4b2adbe3a9cabebd/client/src/favicon.ico -------------------------------------------------------------------------------- /client/src/routes/Admin/Card/index.less: -------------------------------------------------------------------------------- 1 | .login-card-container { 2 | width: 500px; 3 | position: absolute; 4 | left: 50%; 5 | top: 50%; 6 | transform: translate(-50%, -50%); 7 | padding: 50px; 8 | background-color: #fff; 9 | box-shadow: 0 1px 3px rgba(19, 26, 92, .06), 0 6px 30px rgba(19, 26, 92, .12); 10 | border-radius: 4px; 11 | } 12 | 13 | .login-card-title { 14 | font-size: 40px; 15 | line-height: 1.5; 16 | text-align: center; 17 | margin-bottom: 30px; 18 | } 19 | -------------------------------------------------------------------------------- /client/src/routes/Admin/Card/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import './index.less' 4 | 5 | export default class LoginLayout extends React.Component { 6 | 7 | render() { 8 | const { children } = this.props 9 | return ( 10 |
11 |
河 图
12 | {children} 13 |
14 | ) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /client/src/routes/Admin/Layout/index.less: -------------------------------------------------------------------------------- 1 | .login-layout-container { 2 | position: fixed; 3 | z-index: 100; 4 | width: 100vw; 5 | height: 100vh; 6 | background-color: #f9fcff; 7 | 8 | .ht-form-explain { 9 | position: absolute; 10 | margin-top: 1px; 11 | margin-bottom: 1px; 12 | } 13 | 14 | .ht-form-item { 15 | margin-bottom: 28px; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /client/src/routes/Admin/Layout/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import LoginCard from '../Card' 3 | import './index.less' 4 | 5 | export default class LoginLayout extends React.Component { 6 | 7 | render() { 8 | const { children } = this.props 9 | return ( 10 |
11 | 12 | {children} 13 | 14 |
15 | ) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /client/src/routes/Admin/Login/index.less: -------------------------------------------------------------------------------- 1 | .login-container {} 2 | -------------------------------------------------------------------------------- /client/src/routes/Admin/ModifyPassword/index.less: -------------------------------------------------------------------------------- 1 | .modify-password-container {} 2 | -------------------------------------------------------------------------------- /client/src/routes/Admin/Register/index.less: -------------------------------------------------------------------------------- 1 | .register-container {} 2 | -------------------------------------------------------------------------------- /client/src/routes/Exception/403.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Exception from '~/components/Exception' 3 | 4 | export default () => ( 5 | 6 | ) 7 | -------------------------------------------------------------------------------- /client/src/routes/Exception/404.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Exception from '~/components/Exception' 3 | 4 | export default () => ( 5 | 6 | ) 7 | -------------------------------------------------------------------------------- /client/src/routes/Exception/500.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Exception from '~/components/Exception' 3 | 4 | export default () => ( 5 | 6 | ) 7 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/Content/index.less: -------------------------------------------------------------------------------- 1 | .the-gui-content { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | overflow: hidden; 6 | background-color: #fff; 7 | } 8 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/Content/interface.d.ts: -------------------------------------------------------------------------------- 1 | import { ConnectProps, ConnectState } from '~/types/models/connect' 2 | import { IPageConfig, IElementConfig } from '~/types/models/global' 3 | import { selectedComponentData, ContainerData, activeTab, reac } from '~/types/models/guiEditor' 4 | 5 | export { ConnectState, selectedComponentData, IPageConfig, ContainerData, IElementConfig } 6 | 7 | export interface Props extends ConnectProps { 8 | isIframeLoading: boolean 9 | hoverComponentData: selectedComponentData 10 | selectedComponentData: selectedComponentData 11 | activeTab: activeTab 12 | pageConfig: IPageConfig 13 | isLockIframe: boolean 14 | isDragging: boolean 15 | isInsertItemMode: boolean 16 | containerData: ContainerData 17 | } 18 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/Header/ThePublishModal/index.module.less: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LianjiaTech/hetu/b34b572d5898e7aea939ec5f4b2adbe3a9cabebd/client/src/routes/GuiEditor/components/Header/ThePublishModal/index.module.less -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/Header/ThePublishModal/interface.d.ts: -------------------------------------------------------------------------------- 1 | import { ConnectProps, ConnectState } from '~/types/models/connect' 2 | import { activeTab } from '~/types/models/guiEditor' 3 | 4 | import { FormComponentProps } from 'antd/es/form' 5 | 6 | export { ConnectState } 7 | 8 | export interface Props extends ConnectProps, FormComponentProps { 9 | projectId: number 10 | pageId: number 11 | draftId: number 12 | 13 | visible: boolean 14 | 15 | onClose: () => void 16 | } 17 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/Header/interface.d.ts: -------------------------------------------------------------------------------- 1 | import { ConnectProps, ConnectState } from '~/types/models/connect' 2 | import { IPageConfig } from '~/types/models/global' 3 | import { activeTab } from '~/types/models/guiEditor' 4 | 5 | import { FormComponentProps } from 'antd/es/form' 6 | 7 | export { ConnectState, IPageConfig } 8 | 9 | export interface Props extends ConnectProps, FormComponentProps { 10 | projectId: number 11 | pageId: number 12 | draftId: number 13 | pageConfig: IPageConfig 14 | query: dynamicObject 15 | activeTab: activeTab 16 | visible: boolean 17 | onClose: () => void 18 | } 19 | 20 | export interface State { 21 | // 发布的弹框 22 | isPublishModalVisible: boolean 23 | // JSON编辑的弹框 24 | isEditModalVisible: boolean 25 | isChanged: boolean 26 | pageConfig?: dynamicObject 27 | query?: string 28 | } 29 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/SiderLeft/interface.d.ts: -------------------------------------------------------------------------------- 1 | import { ConnectProps } from '~/types/models/connect' 2 | import { IPageConfig, IElementConfig } from '~/types/models/global' 3 | import { selectedComponentData, activeTab } from '~/types/models/guiEditor' 4 | 5 | type Option = any 6 | export { IPageConfig, selectedComponentData, Option, IElementConfig } 7 | 8 | export interface TheSiderLeftProps extends ConnectProps { 9 | pageConfig: IPageConfig 10 | activeTab: activeTab 11 | isLockIframe: boolean 12 | selectedComponentData: selectedComponentData 13 | } 14 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/SiderRight/FormEditor/compontent/FormItem/index.less: -------------------------------------------------------------------------------- 1 | .the-gui-form-item { 2 | .the-context-menu { 3 | background-color: #fff; 4 | } 5 | 6 | .the-menu-item { 7 | cursor: pointer; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/SiderRight/FormEditor/compontent/input/index.less: -------------------------------------------------------------------------------- 1 | .FormInput-div { 2 | display: flex; 3 | 4 | label.ht-checkbox-wrapper { 5 | padding-left: 14px; 6 | } 7 | 8 | // textarea 9 | textarea.ht-input { 10 | padding: 4px 11px; 11 | line-height: 20px; 12 | transition: none; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/SiderRight/FormEditor/compontent/readme.md: -------------------------------------------------------------------------------- 1 | 该文件夹中存放为可视化编辑器专门订制的组件 -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/SiderRight/FormEditor/interface.d.ts: -------------------------------------------------------------------------------- 1 | import { FormComponentProps } from 'antd/es/form' 2 | import { ConnectProps, ConnectState } from '~/types/models/connect' 3 | import { IPageConfig } from '~/types/models/global' 4 | import { activeTab, selectedComponentData } from '~/types/models/guiEditor' 5 | 6 | export { ConnectState } 7 | 8 | export type changeValues = { 9 | [fieldName: string]: any 10 | } 11 | 12 | export interface Props extends FormComponentProps, ConnectProps { 13 | visible: boolean 14 | formData: dynamicObject 15 | editConfigData: dynamicObject 16 | pageConfig: IPageConfig 17 | selectedComponentData: selectedComponentData 18 | pageId: number 19 | activeTab: activeTab 20 | 21 | onChange: (v: dynamicObject) => void 22 | updatePageConfig: (relativePath: string, newValue: any) => void 23 | updatePageConfigAndReload: (newValue: any) => void 24 | } 25 | 26 | export interface State {} 27 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/SiderRight/JSONEditor/index.module.less: -------------------------------------------------------------------------------- 1 | .the-guiEditor-wrap { 2 | flex: 1; 3 | overflow: auto; 4 | } 5 | 6 | .the-guiEditor { 7 | padding-top: 0; 8 | font-size: 15px; 9 | overflow-y: auto; 10 | } 11 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/SiderRight/JSONEditor/interface.d.ts: -------------------------------------------------------------------------------- 1 | import { ConnectProps, ConnectState } from '~/types/models/connect' 2 | import { activeTab } from '~/types/models/guiEditor' 3 | 4 | export { ConnectState } 5 | export default interface JSONEditorProps extends ConnectProps { 6 | pageConfig: any 7 | projectId: number 8 | pageId: number 9 | dataPageConfigPath: string 10 | activeTab: activeTab 11 | } 12 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/SiderRight/index.module.less: -------------------------------------------------------------------------------- 1 | .the-sider-right { 2 | display: flex; 3 | flex-direction: column; 4 | height: 100vh; 5 | overflow: hidden; 6 | background-color: transparent; 7 | } 8 | 9 | .tabs { 10 | display: flex; 11 | height: 64px; 12 | margin: 0; 13 | border-bottom: 1px solid #000; 14 | } 15 | .tabs-item { 16 | padding: 0 24px; 17 | line-height: 64px; 18 | height: 64px; 19 | cursor: pointer; 20 | user-select: none; 21 | border-right: 1px solid #000; 22 | white-space: nowrap; 23 | overflow: hidden; 24 | color: rgba(255, 255, 255, 0.7); 25 | &.is-selected { 26 | border-bottom: 1px solid #262626; 27 | color: #fff; 28 | } 29 | } 30 | 31 | .the-tip { 32 | color: rgba(255, 255, 255, 0.75); 33 | padding: 8px 16px; 34 | font-size: 13px; 35 | } 36 | 37 | .the-tip-icon { 38 | margin-right: 6px; 39 | font-size: 12px; 40 | } 41 | 42 | .the-base-wrap { 43 | flex: 1; 44 | overflow: auto; 45 | color: rgba(255, 255, 255, 0.75); 46 | padding: 0 16px; 47 | } 48 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/SiderRight/interface.ts: -------------------------------------------------------------------------------- 1 | import { IPageConfig } from '~/types/models/global' 2 | import { ConnectProps, ConnectState } from '~/types/models/connect' 3 | import { activeTab, selectedComponentData } from '~/types/models/guiEditor' 4 | 5 | export { ConnectState, selectedComponentData } 6 | 7 | export interface Props extends ConnectProps { 8 | projectId: number 9 | pageId: number 10 | activeTab: activeTab 11 | isLockIframe: boolean 12 | pageConfig: IPageConfig 13 | selectedComponentData: selectedComponentData 14 | } 15 | 16 | export interface State {} 17 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/Stage/HoverOverlay/DropTargetWrapper/interface.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { ConnectState, ConnectProps } from '~/types/models/connect' 3 | import { IPageConfig } from '~/types/models/global' 4 | import { selectedComponentData, reac } from '~/types/models/guiEditor' 5 | import { ConnectDropTarget } from 'react-dnd' 6 | 7 | export { ConnectState, reac, selectedComponentData, IPageConfig } 8 | 9 | export interface CollectedProps { 10 | connectDropTarget: ConnectDropTarget 11 | isOver: boolean 12 | } 13 | 14 | export interface DragObject {} 15 | 16 | export interface Props extends ConnectProps, CollectedProps { 17 | type: string 18 | index: number 19 | reac: reac 20 | } 21 | 22 | export interface State {} 23 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/Stage/HoverOverlay/index.module.less: -------------------------------------------------------------------------------- 1 | .hover-overlay { 2 | position: absolute; 3 | overflow: hidden; 4 | z-index: 9; 5 | border: 1px dotted #666; 6 | border-radius: 3px; 7 | z-index: 100; 8 | 9 | p { 10 | position: absolute; 11 | top: 0; 12 | left: 0; 13 | width: 100%; 14 | height: 30px; 15 | line-height: 30px; 16 | background: #2f54eb; 17 | color: white; 18 | text-align: center; 19 | margin-bottom: 0; 20 | } 21 | } 22 | 23 | .drop-target { 24 | border: none; 25 | transition: all 0.3; 26 | background-color: rgba(227, 243, 255, 0.4); 27 | } 28 | 29 | .is-over { 30 | .drop-target { 31 | border: 1px solid #666; 32 | background-color: rgba(165, 222, 249, 0.5); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/Stage/HoverOverlay/interface.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { ConnectState, ConnectProps } from '~/types/models/connect' 3 | import { IPageConfig } from '~/types/models/global' 4 | import { selectedComponentData, reac, DataComponentType } from '~/types/models/guiEditor' 5 | import { ConnectDropTarget } from 'react-dnd' 6 | 7 | export { ConnectState, reac, selectedComponentData, DataComponentType } 8 | 9 | export interface CollectedProps { 10 | connectDropTarget: ConnectDropTarget 11 | isOver: boolean 12 | isOverCurrent: boolean 13 | } 14 | 15 | export interface DragObject {} 16 | 17 | export interface Props extends ConnectProps, CollectedProps { 18 | isDragging: boolean 19 | 20 | pageConfig: IPageConfig 21 | hoverComponentData: selectedComponentData 22 | selectedComponentData: selectedComponentData 23 | 24 | onChange: (newIndex: number) => void 25 | } 26 | 27 | export interface State {} 28 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/Stage/SelectedOverlay/interface.d.ts: -------------------------------------------------------------------------------- 1 | import { ConnectState, ConnectProps } from '~/types/models/connect' 2 | import { IPageConfig } from '~/types/models/global' 3 | import { selectedComponentData, reac } from '~/types/models/guiEditor' 4 | import { ConnectDragSource } from 'react-dnd' 5 | 6 | export { ConnectState, reac, selectedComponentData, IPageConfig } 7 | 8 | export interface CollectedProps { 9 | connectDragSource: ConnectDragSource 10 | } 11 | 12 | export interface DragObject { 13 | index: number 14 | } 15 | 16 | export interface Props extends ConnectProps, CollectedProps { 17 | type: string 18 | 19 | index: number 20 | 21 | isDragging: boolean 22 | 23 | pageConfig: IPageConfig 24 | selectedComponentData: selectedComponentData 25 | 26 | onChange: (newIndex: number) => void 27 | onSort: (dragIndex: number, targetIndex: number) => Promise 28 | } 29 | export interface State {} 30 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/Stage/index.module.less: -------------------------------------------------------------------------------- 1 | .the-stage-wrap { 2 | position: absolute; 3 | top: 0; 4 | left: 0; 5 | right: 0; 6 | height: 100%; 7 | cursor: pointer; 8 | background-color: rgba(0, 0, 0, 0.05); 9 | } 10 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/components/Stage/interface.d.ts: -------------------------------------------------------------------------------- 1 | import React, { CSSProperties } from 'react' 2 | import { ConnectState, ConnectProps } from '~/types/models/connect' 3 | import { IPageConfig } from '~/types/models/global' 4 | import { selectedComponentData, reac } from '~/types/models/guiEditor' 5 | 6 | export { ConnectState, reac } 7 | 8 | export interface Props extends ConnectProps { 9 | pageConfig: IPageConfig 10 | 11 | hoverComponentData: selectedComponentData 12 | selectedComponentData: selectedComponentData 13 | 14 | style: CSSProperties 15 | 16 | onClick: (e: React.MouseEvent) => void 17 | onCtrlClick: (e: React.MouseEvent) => void 18 | onMouseMove: () => void 19 | onMouseLeave: () => void 20 | } 21 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/index.less: -------------------------------------------------------------------------------- 1 | .page-guiEditor-layout { 2 | background-color: #262626; 3 | color: #fff; 4 | font-size: 14px; 5 | width: 100%; 6 | } 7 | 8 | .page-guiEditor { 9 | width: 100vw; 10 | height: 100vh; 11 | 12 | .ht-layout-header, 13 | .ht-layout-sider, 14 | .ht-layout-content { 15 | background-color: transparent; 16 | } 17 | } 18 | 19 | a.is-disabled { 20 | cursor: not-allowed; 21 | color: hsla(0, 0%, 100%, 0.7); 22 | 23 | &:focus, 24 | &:hover, 25 | &:active, 26 | &:visited { 27 | color: hsla(0, 0%, 100%, 0.7); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /client/src/routes/GuiEditor/interface.ts: -------------------------------------------------------------------------------- 1 | import { ConnectProps } from '~/types/models/connect' 2 | import { IPageConfig } from '~/types/models/global' 3 | 4 | export interface TheGuiEditorProps extends ConnectProps { 5 | projectDetail: dynamicObject 6 | pageConfig: IPageConfig 7 | isLockIframe: boolean 8 | } 9 | -------------------------------------------------------------------------------- /client/src/routes/Home/Layout/Basic/Header/interface.d.ts: -------------------------------------------------------------------------------- 1 | import { IUserInfo, IProjectDetail } from '~/types/models/global' 2 | import { FormComponentProps } from 'antd/es/form' 3 | import { ConnectProps, ConnectState } from '~/types/models/connect' 4 | export { IUserInfo, ConnectState } 5 | 6 | export interface TheHeaderProps extends FormComponentProps, ConnectProps { 7 | userInfo: IUserInfo 8 | projectDetail: IProjectDetail 9 | } 10 | -------------------------------------------------------------------------------- /client/src/routes/Home/Layout/Basic/SiderMenu/interface.d.ts: -------------------------------------------------------------------------------- 1 | import { RouteComponentProps } from 'react-router' 2 | import { IUserInfo, IProjectDetail } from '~/types/models/global' 3 | import * as H from 'history' 4 | 5 | export interface menuItem { 6 | path: string 7 | icon: string 8 | key: string 9 | name?: string 10 | hideInMenu?: boolean 11 | target?: string 12 | children?: menuItem[] 13 | } 14 | 15 | export interface TheSiderMenuProps { 16 | history: H.History 17 | projectDetail: IProjectDetail 18 | } 19 | 20 | export interface TheSiderMenuState { 21 | flatMenuKeys?: string[] 22 | openKeys?: string[] 23 | collapsed: boolean 24 | } 25 | -------------------------------------------------------------------------------- /client/src/routes/Home/Layout/Basic/index.module.less: -------------------------------------------------------------------------------- 1 | .the-tabs { 2 | :global { 3 | .ht-tabs-nav-wrap { 4 | background-color: #f0f2f5; 5 | } 6 | 7 | .ht-tabs-bar { 8 | margin-bottom: 0; 9 | } 10 | } 11 | } 12 | .base_footer { 13 | padding: 15px 16px; 14 | text-align: center; 15 | } 16 | 17 | .copyright { 18 | color: #999; 19 | &:hover { 20 | color: #1890ff; 21 | cursor: pointer; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /client/src/routes/Home/Layout/Basic/interface.d.ts: -------------------------------------------------------------------------------- 1 | import * as H from 'history' 2 | import { IPaneItem, IUserInfo, IProjectDetail } from '~/types/models/global' 3 | 4 | export interface LayoutBasicProps { 5 | history: H.History 6 | userInfo: IUserInfo 7 | projectDetail: IProjectDetail 8 | activePanekey: string 9 | panes: IPaneItem[] 10 | onChange: (activePanekey: string, panes: IPaneItem[]) => void 11 | } 12 | 13 | export interface LayoutBasicState {} 14 | -------------------------------------------------------------------------------- /client/src/routes/Home/Layout/Blank/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { Fragment, Component } from 'react' 2 | 3 | export default class LayoutBlank extends Component { 4 | static displayName = 'LayoutBlank' 5 | 6 | static propTypes = {} 7 | 8 | static defaultProps = {} 9 | 10 | render() { 11 | const { children } = this.props 12 | 13 | return {children} 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /client/src/routes/Home/Layout/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Basic } from './Basic' 2 | export { default as Blank } from './Blank' 3 | -------------------------------------------------------------------------------- /client/src/routes/Home/ModalClone/interface.d.ts: -------------------------------------------------------------------------------- 1 | import { FormComponentProps } from 'antd/es/form' 2 | import { IProjectDetail, IPageConfig } from '~/types/models/global' 3 | 4 | export interface TheCloneModalProps extends FormComponentProps { 5 | visible: boolean 6 | pageConfig: IPageConfig 7 | projectDetail: IProjectDetail 8 | 9 | onChange: (visible: boolean) => void 10 | } 11 | 12 | export interface TheCloneModalState { 13 | projectList: IProjectDetail[] 14 | } 15 | -------------------------------------------------------------------------------- /client/src/routes/Home/index.less: -------------------------------------------------------------------------------- 1 | .page-home { 2 | display: flex; 3 | } 4 | 5 | .page-home-aside { 6 | flex-shrink: 0; 7 | transition: width 0.3s; 8 | } 9 | 10 | .hetu-editor-body .page-home-content { 11 | width: 100vw; 12 | } 13 | 14 | .page-home-content { 15 | flex: 1; 16 | z-index: 0; 17 | } 18 | 19 | .page-home-buttons { 20 | position: fixed; 21 | z-index: 1000; 22 | top: 0; 23 | left: 255px; 24 | background: #1890ff; 25 | border-radius: 0 0 4px 4px; 26 | display: flex; 27 | } 28 | 29 | .page-home-button { 30 | display: flex; 31 | justify-content: center; 32 | align-items: center; 33 | width: 48px; 34 | height: 48px; 35 | font-size: 18px; 36 | text-align: center; 37 | color: #fff; 38 | cursor: pointer; 39 | pointer-events: auto; 40 | 41 | &.is-disabled { 42 | cursor: not-allowed; 43 | color: rgba(255, 255, 255, 0.25); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /client/src/routes/Home/interface.d.ts: -------------------------------------------------------------------------------- 1 | import * as H from 'history' 2 | import { IPageConfig, IPaneItem, IUserInfo, IProjectDetail } from '~/types/models/global' 3 | 4 | export { IProjectDetail } 5 | 6 | export interface PageHomeProps { 7 | history: H.History 8 | } 9 | 10 | export interface PageHomeState { 11 | isCloneModalVisible: boolean 12 | isPageInit: boolean 13 | isLocalPage: boolean 14 | errorMessage?: string 15 | 16 | pageConfig?: IPageConfig 17 | projectDetail?: IProjectDetail 18 | userInfo?: IUserInfo 19 | 20 | activePanekey?: string 21 | panes: IPaneItem[] 22 | uniqueKey: string 23 | } 24 | -------------------------------------------------------------------------------- /client/src/routes/Preview/index.tsx: -------------------------------------------------------------------------------- 1 | import queryString from 'query-string' 2 | 3 | export default function PagePreview(props: any): null { 4 | const { history } = props 5 | const { route, draftId } = queryString.parse(window.location.search) 6 | 7 | const url = `${route}?draftId=${draftId}` 8 | 9 | history.replace(url) 10 | return null 11 | } 12 | -------------------------------------------------------------------------------- /client/src/routes/Templates/components/Card/interface.d.ts: -------------------------------------------------------------------------------- 1 | import { FormComponentProps } from 'antd/es/form' 2 | import { ConnectProps, ConnectState } from '~/types/models/connect' 3 | 4 | export interface templateData { 5 | id: '/project/template/list/1' 6 | desc: '搜索+列表' 7 | imgUrl: string 8 | config: any 9 | } 10 | 11 | export interface TheCardProps extends FormComponentProps, ConnectProps { 12 | data: templateData 13 | projectDetail: dynamicObject 14 | } 15 | 16 | export interface TheCardState { 17 | isHover: boolean 18 | isModalVisible: boolean 19 | templateData: dynamicObject 20 | isTempModalVisible: boolean 21 | } 22 | -------------------------------------------------------------------------------- /client/src/routes/Templates/index.less: -------------------------------------------------------------------------------- 1 | .page-templates { 2 | display: flex; 3 | flex-direction: column; 4 | min-height: 100vh; 5 | color: #fff; 6 | background-color: #f2f2f2; 7 | } 8 | 9 | .page-templates-content { 10 | display: flex; 11 | flex: 1; 12 | flex-wrap: wrap; 13 | align-content: flex-start; 14 | padding:0 20px; 15 | } 16 | 17 | .page-templates-tabs { 18 | padding: 40px 30px 10px; 19 | } 20 | -------------------------------------------------------------------------------- /client/src/routes/Templates/interface.d.ts: -------------------------------------------------------------------------------- 1 | import { FormComponentProps } from 'antd/es/form' 2 | import { ConnectProps, ConnectState } from '~/types/models/connect' 3 | 4 | export interface PageTemplatesProps extends FormComponentProps, ConnectProps { 5 | visible: boolean 6 | onChange: (visible: boolean) => void 7 | pageConfig: dynamicObject 8 | projectList: dynamicObject[] 9 | } 10 | 11 | export type activeTabKeyType = 'all' 12 | 13 | export interface PageTemplatesState { 14 | activeTabKey: activeTabKeyType 15 | templateData: any[] 16 | } 17 | -------------------------------------------------------------------------------- /client/src/types/components/editConfig.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 属性规范 3 | */ 4 | type InterfaceProperty = { 5 | type: 6 | | 'enum' // 枚举类型 7 | | 'object' // 对象 8 | | 'array' // 普通数组 9 | | 'arrayOf' // 对象数组 10 | | 'string' // 字符串 11 | | 'image' // 图片 12 | | 'number' // 数字 13 | | 'color' // 颜色选择器 14 | | 'richtext' // 富文本 15 | | 'bool' // 布尔值 16 | | 'date' // 日期 17 | | 'url' // url 18 | 19 | /** 20 | * 属性名称 21 | */ 22 | title: string 23 | /** 24 | * 属性描述, 作为问号出现在属性左侧, 用于提示用户该属性的含义 25 | */ 26 | desc?: string 27 | /** 28 | * 文档地址 29 | */ 30 | doc?: string 31 | /** 32 | * 默认值, 只有基础类型会有默认值 33 | */ 34 | defaultValue?: string | number | boolean 35 | properties?: { 36 | [datakey: string]: InterfaceProperty 37 | } 38 | } 39 | 40 | type TypeEditConfig = { 41 | [propKey: string]: InterfaceProperty 42 | } 43 | export default TypeEditConfig 44 | 45 | export { InterfaceProperty, TypeEditConfig } 46 | -------------------------------------------------------------------------------- /client/src/types/components/interfaceBaseCompontentProps.ts: -------------------------------------------------------------------------------- 1 | interface InterfaceBaseCompontentProps { 2 | /** 3 | * 组件名 4 | * 示例:data-component-type="BaseFormItemText" 5 | */ 6 | ['data-component-type']: string 7 | /** 8 | * 组件在props中的相对路径 9 | * 示例: data-pageconfig-path="elementConfig.props.content.children[0].children[0].children[3]" 10 | */ 11 | ['data-pageconfig-path']: string 12 | } 13 | export default InterfaceBaseCompontentProps 14 | -------------------------------------------------------------------------------- /client/src/types/models/connect.d.ts: -------------------------------------------------------------------------------- 1 | import { AnyAction } from 'redux'; 2 | import { globalState } from './global' 3 | import { editorState } from './editor.d' 4 | import { guiEditorState } from './guiEditor.d' 5 | 6 | export interface ConnectState { 7 | global: globalState 8 | editor: editorState 9 | guiEditor: guiEditorState 10 | } 11 | 12 | export interface Action { 13 | type: any; 14 | } 15 | 16 | export type Dispatch = (action: AnyAction) => Promise | any; 17 | 18 | export interface ConnectProps { 19 | dispatch?: Dispatch; 20 | } 21 | -------------------------------------------------------------------------------- /client/src/types/models/guiEditor.d.ts: -------------------------------------------------------------------------------- 1 | import { pageConfig } from './global' 2 | import { selectedComponentData, reac, DataComponentType } from './editor.d' 3 | 4 | export { selectedComponentData, reac, DataComponentType } 5 | 6 | export type activeTab = 'code' | 'base' 7 | 8 | export interface ContainerData { 9 | type: string 10 | path: string 11 | } 12 | 13 | export interface guiEditorState { 14 | // iframe 查询参数 15 | query: null 16 | // 页面id 17 | pageId: null 18 | // 草稿id 19 | draftId: null 20 | // 项目id 21 | project: null 22 | // 页面配置 23 | pageConfig?: pageConfig 24 | // 编译结果 25 | pagestate?: any 26 | hoverComponentData?: selectedComponentData 27 | selectedComponentData?: selectedComponentData 28 | insertComponentData?: selectedComponentData 29 | containerData: ContainerData 30 | isIframeLoading: boolean 31 | // 是否展示占位符元素(用于添加组件) 32 | isInsertItemMode: boolean 33 | // 插入的ComponentData 34 | // 是否处于拖拽中 35 | isDragging: boolean 36 | // 右侧激活面板,默认为可视化编辑器 37 | activeTab: activeTab 38 | // 是否锁屏 39 | isLockIframe: true 40 | } 41 | -------------------------------------------------------------------------------- /client/src/utils/apis.ts: -------------------------------------------------------------------------------- 1 | export function transformPath(path: string) { 2 | if (window.__POWERED_BY_QIANKUN__) { 3 | let map = store.get('hetu-pageconfigs-map') 4 | path = _.get(map, path, path) 5 | } 6 | return path 7 | } 8 | -------------------------------------------------------------------------------- /client/src/utils/events.ts: -------------------------------------------------------------------------------- 1 | import mitt from 'mitt' 2 | 3 | export const emitter = mitt() 4 | -------------------------------------------------------------------------------- /client/src/utils/valid.ts: -------------------------------------------------------------------------------- 1 | import { isString, isArray, isPlainObject } from 'lodash' 2 | 3 | /** 4 | * 验证是否为一个组件配置 5 | * @param {any} v 6 | * @returns {Boolean} 7 | */ 8 | export function isElementConfig(v: any): boolean { 9 | if (v === null) return true 10 | 11 | if (!isPlainObject(v)) return false 12 | 13 | const { type, props } = v 14 | 15 | if (isString(type) && isPlainObject(props)) { 16 | return true 17 | } 18 | } 19 | 20 | export function isPageConfig(v: any): boolean { 21 | if (!isPlainObject(v)) return false 22 | 23 | const { elementConfig } = v 24 | if (!isElementConfig(elementConfig)) return false 25 | 26 | return true 27 | } 28 | -------------------------------------------------------------------------------- /client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "noImplicitAny": true, 5 | "removeComments": true, 6 | "preserveConstEnums": true, 7 | "sourceMap": true, 8 | "baseUrl": "./src", 9 | "paths": { 10 | "*": [ 11 | "typings", 12 | "node_modules" 13 | ], 14 | "~/*": [ 15 | "*" 16 | ] 17 | }, 18 | "experimentalDecorators": true, 19 | "jsx": "react", 20 | "esModuleInterop": true 21 | }, 22 | "exclude": [ 23 | "node_modules", 24 | "dist" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /client/typings.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.css' 2 | declare module '*.less' 3 | declare module '*.module.less' 4 | declare module '*.scss' 5 | declare module '*.sass' 6 | declare module '*.svg' 7 | declare module '*.png' 8 | declare module '*.jpg' 9 | declare module '*.jpeg' 10 | declare module '*.gif' 11 | declare module '*.bmp' 12 | declare module '*.tiff' 13 | declare module 'react-css-modules' 14 | declare module 'dva-loading' 15 | 16 | interface Window { 17 | ENV: 'dev' | 'test' | 'prod' 18 | // 父级iframe的名称 19 | $$iframeParentName?: string 20 | $$isEditor?: boolean 21 | $$receiveIframeData?: (v: { type: string; data: dynamicObject }) => void 22 | $$changeIframePageConfig?: (v: dynamicObject) => void 23 | $$PUBLIC_URL?: string 24 | Hetu: any 25 | __POWERED_BY_QIANKUN__: boolean 26 | } 27 | 28 | declare interface dynamicObject { 29 | [key: string]: any 30 | } 31 | 32 | declare type dvaDispatch = (v: { type: string; payload: dynamicObject }) => any | Promise 33 | 34 | declare type BaseComponent = { 35 | pagestate: any 36 | } 37 | -------------------------------------------------------------------------------- /plugin/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [], 3 | "plugins": [ 4 | [ 5 | "module-resolver", 6 | { 7 | "root": "./", 8 | "alias": { 9 | "~": "./src", 10 | "@test": "./test", 11 | "*": ["src/*", "node_modules/*"] 12 | } 13 | } 14 | ] 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /plugin/.eslintignore: -------------------------------------------------------------------------------- 1 | // .eslintignore 此文件是告诉eslint忽略哪些文件的 2 | build/** 3 | config/** 4 | public/** 5 | scripts/** 6 | .eslintrc.js 7 | jest.config.js 8 | tsdx.config.js 9 | gulpfile.js/** 10 | site/** 11 | .vscode/** 12 | -------------------------------------------------------------------------------- /plugin/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .DS_Store 3 | node_modules 4 | .cache 5 | .rts2_cache_cjs 6 | .rts2_cache_esm 7 | .rts2_cache_umd 8 | dist 9 | lib 10 | site/_site 11 | site/components 12 | _site 13 | coverage 14 | 15 | .history 16 | .idea 17 | 18 | /package-lock.json 19 | 20 | -------------------------------------------------------------------------------- /plugin/README.md: -------------------------------------------------------------------------------- 1 | 河图组件库 2 | 3 | ## 本地开发 4 | ``` 5 | # 进入plugin目录 6 | cd ./plugin 7 | 8 | # 安装依赖 9 | yarn 10 | 11 | # 打包输出esm模块 12 | yarn build 13 | 14 | # 安装文档依赖 15 | cd ./site & yarn 16 | 17 | # 启动文档服务 18 | yarn start 19 | ``` 20 | 21 | ## 编辑器调试 22 | ``` 23 | 打包输出umd模块 24 | yarn build:umd 25 | 26 | # 启动静态服务, 27 | yarn start:dist 28 | ``` 29 | 30 | 打开 [河图页面](http://139.155.239.172:9536), 同时打开Chrome调试工具面板, 在`Local Storage`中设置 31 | > `hetu-cdn-public` 为`http://127.0.0.1:8888` 32 | 33 | 刷新页面, 查看`network`面板, 看到已经加载了本地资源 34 | ![](https://user-gold-cdn.xitu.io/2020/5/14/17212a5ba3e0be89?w=2184&h=678&f=png&s=210751) 35 | -------------------------------------------------------------------------------- /plugin/__mocks__/axios.ts: -------------------------------------------------------------------------------- 1 | import mockAxios from 'jest-mock-axios' 2 | 3 | export default mockAxios 4 | -------------------------------------------------------------------------------- /plugin/__mocks__/moment.ts: -------------------------------------------------------------------------------- 1 | const moment = jest.requireActual('moment') 2 | 3 | moment.prototype.valueOf = jest.fn().mockImplementation(() => 1578278494065) 4 | 5 | export default moment 6 | -------------------------------------------------------------------------------- /plugin/gulpfile.js/copy-docs.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp') 2 | const chalk = require('chalk') 3 | const del = require('del') 4 | 5 | async function cleanDocs(cb) { 6 | await del(['site/components/**/*']) 7 | cb() 8 | } 9 | 10 | function copyDocs(cb) { 11 | gulp 12 | .src('src/components/**/*.md') 13 | .pipe(gulp.dest('site/components')) 14 | cb() 15 | } 16 | 17 | if (process.argv.indexOf('-w') !== -1) { 18 | console.log(chalk.blue('正在监听文件变化')) 19 | gulp.watch('src/components/**/*.md', { delay: 1000 }, copyDocs) 20 | } 21 | 22 | exports.default = gulp.series(cleanDocs, copyDocs) 23 | -------------------------------------------------------------------------------- /plugin/gulpfile.js/copy-types.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp') 2 | 3 | function copyTypes(cb) { 4 | gulp.src('src/**/*.d.ts').pipe(gulp.dest('dist')) 5 | cb() 6 | } 7 | 8 | exports.default = copyTypes 9 | -------------------------------------------------------------------------------- /plugin/gulpfile.js/index.js: -------------------------------------------------------------------------------- 1 | const copyTypes = require('./copy-types').default 2 | const copyDocs = require('./copy-docs').default 3 | 4 | exports.copyTypes = copyTypes 5 | exports.copyDocs = copyDocs 6 | -------------------------------------------------------------------------------- /plugin/site/docs/editor/01-introduce.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: 介绍 4 | --- 5 | 6 | 河图, 是一个 低代码 平台, 通过可视化界面, 快速生成各种后台页面, 极大减少开发成本。 7 | 8 | 河图是贝壳找房内部孵化项目, 目前已在公司大多数业务线落地, 完成200+项目, 1500+页面。 9 | 10 | ![操作视频](https://file.ljcdn.com/hetu-cdn/1575359874260.d60adb2b8a3131dec93e73a9e4adff15.gif) 11 | 12 | ## 特性 13 | - 🚴‍♀️ 操作简单、功能强大的可视化编辑器 14 | - 📦 开箱即用、高质量后台管理系统模版 15 | - ⚙️ 开发流程全部线上化,节省沟通、调试、运维成本 16 | - 🛡 使用 React、TypeScript、nodejs、express 开发 17 | - 18 | ## 兼容环境 19 | - 现代浏览器、IE11以上 20 | 21 | ## 链接 22 | - [项目文档](http://139.155.239.172/) 23 | - [项目首页](http://139.155.239.172:9536/) 24 | - [服务器部署](https://github.com/LianjiaTech/hetu/deploy.md) 25 | - [视频教程](http://139.155.239.172/docs/resources/video) 26 | 27 | ## 开发流程 28 | 29 | > 河图的开发、调试、测试、上线都是在浏览器中进行的 30 | ![](https://file.ljcdn.com/hetu-cdn/hetu-doc-demo-%E7%8E%AF%E5%A2%83-1596165724648.png) 31 | 32 | ## 系统架构图 33 | ![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ab52f389a41441cb84ec8f3ccebb8928~tplv-k3u1fbpfcp-zoom-1.image) 34 | 35 | ## 问题咨询 36 | - QQ群 【河图开源交流】 782899873 37 | - 群主QQ 1024371442 (备注河图开源咨询) 38 | -------------------------------------------------------------------------------- /plugin/site/docs/editor/02-scenarios.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: 接入必看 3 | order: 0 4 | title: 使用场景 5 | --- 6 | 7 | - PC端、后台管理系统 8 | - 数据增、删、改、查页面 9 | - 图表展示页面 10 | 11 | ## 支持的页面模版 12 | 13 | 目前支持 `列表页`、`表单页`、`图表`、`多标签页` 等模版。 14 | 15 | ### 搜索+列表展示 16 | 17 | ![搜索+列表展示](https://user-gold-cdn.xitu.io/2019/6/3/16b1c406089692a0?w=1363&h=761&f=png&s=117988) 18 | 19 | ### 表单编辑 20 | 21 | 页面由`表单项+按钮`构成 22 | ![](https://user-gold-cdn.xitu.io/2019/6/3/16b1c4b17271a680?w=1364&h=763&f=png&s=52742) 23 | 24 | ### 图形化展示 25 | 26 | ![](https://user-gold-cdn.xitu.io/2019/11/13/16e6462123dd77df?w=2214&h=990&f=png&s=120008) 27 | 28 | -------------------------------------------------------------------------------- /plugin/site/docs/editor/03-page-build.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: 详细教程 3 | order: 2 4 | title: 二.创建页面 5 | --- 6 | 7 | ### 1. 找到对应的项目,点击编辑,进入到页面管理 8 | 9 | ![](https://user-gold-cdn.xitu.io/2020/5/18/17225d20e435e875?w=2316&h=1098&f=png&s=387353) 10 | 11 | ### 2. 点击新建页面 12 | 13 | ![](https://user-gold-cdn.xitu.io/2020/5/18/17225d18c28e31b5?w=2356&h=774&f=png&s=513730) 14 | 15 | ### 3. 选择模版, 创建页面 16 | 17 | > 页面路由自动加上`/project/项目唯一标识`, 页面创建成功之后, 会进入到编辑器页面 18 | 19 | ![](https://user-gold-cdn.xitu.io/2020/5/18/17225d99982a8642?w=2540&h=1240&f=png&s=827340) 20 | 21 | ![](https://user-gold-cdn.xitu.io/2020/5/18/17225da6140cef4d?w=2528&h=1182&f=png&s=780710) 22 | 23 | ### 4. 编辑页面 24 | 25 | ![](https://user-gold-cdn.xitu.io/2020/3/31/17130afdc3068d2d?w=2854&h=1434&f=png&s=1403613) 26 | -------------------------------------------------------------------------------- /plugin/site/docs/editor/03-page-debug.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: 详细教程 3 | order: 4 4 | title: 四.异常处理 5 | --- 6 | 7 | 配置页面过程中, 经常遇到页面白屏或者菊花 loading, 90%的可能是接口错误, 可按照如下步骤排查错误。 8 | 9 | ##  接口异常 10 | 11 | ### 1. 检查网络请求 12 | 13 | 鼠标右键, 点击检查 14 | 然后依次打开`Network XHR`面板, 查看接口响应状态码是否异常. `2xx 3xx`通常表示成功,`4xx 5xx`通常表示异常。 15 | ![](https://user-gold-cdn.xitu.io/2019/7/4/16bbb09224fb005e?w=918&h=302&f=png&s=64690) 16 | 17 | ### 2. 查看错误详情 18 | 19 | > 河图对错误请求进行了处理, 会返回详情的错误信息。 20 | > ![](https://user-gold-cdn.xitu.io/2020/3/20/170f75330c67821a?w=2734&h=978&f=png&s=256037) 21 | 22 | ## 接口正常, 页面异常 23 | 24 | - 1. 检查 [接口格式](/docs/editor/02-request) 25 | -------------------------------------------------------------------------------- /plugin/site/docs/editor/03-page-publish.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: 详细教程 3 | order: 5 4 | title: 五.发布上线 5 | --- 6 | 7 | 为了保证数据来源的唯一性, 只允许在测试环境编辑页面配置。 8 | 9 | ## 上线流程 10 | 11 | ![](https://user-gold-cdn.xitu.io/2019/8/16/16c987c63e601ece?w=701&h=382&f=png&s=38177) 12 | 13 | ### 1. 测试环境 14 | 15 | - 选中准备上线的页面(确保测试环境已发布) 16 | - 批量下载 17 | ![](https://user-gold-cdn.xitu.io/2019/8/16/16c98689f8690325?w=1049&h=591&f=png&s=68440) 18 | 19 | ### 2. 线上环境 20 | 21 | - 导入页面配置 22 | - 根据页面状态, 选择刚刚导入的页面 23 | - 批量发布 24 | ![](https://user-gold-cdn.xitu.io/2019/8/16/16c986b931aba956?w=1050&h=591&f=png&s=80397) 25 | -------------------------------------------------------------------------------- /plugin/site/docs/editor/03-project-whitelist.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: 详细教程 3 | order: 3 4 | title: 三.权限控制 5 | --- 6 | 7 | - 权限控制以项目为维度, 业务权限在每个页面中配置 8 | - 开启白名单访问, 可以设置指定成员可访问 9 | 10 | ## 开启步骤 11 | 12 | ### 1. 进入河图首页 13 | 14 | 找到对应的项目, 点击编辑 15 | ![](https://user-gold-cdn.xitu.io/2020/6/8/17291b7bfc967c00?w=2292&h=510&f=png&s=219328) 16 | 17 | ### 2. 进入项目配置页面 18 | 19 | - 设置“白名单访问”为开启状态 20 | ![](https://user-gold-cdn.xitu.io/2020/6/8/17291b49bcb37c59?w=1972&h=650&f=png&s=138458) 21 | 22 | ### 3. 切换到权限管理标签 23 | 24 | 在这个面板可以添加、删除、编辑用户权限。 25 | 26 | | 角色 | 权限 | 27 | | ---------- | -------------------------------------- | 28 | | 管理员 | `查看` `创建` `编辑` `删除` `查看日志` | 29 | | 普通用户 | `查看` | 30 | | 非名单用户 | 无权限 | 31 | 32 | ### 5. 测试 33 | 34 | 不在白名单等用户将会看到以下页面 35 | ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfce336b766f73?w=2844&h=1426&f=png&s=259972) 36 | -------------------------------------------------------------------------------- /plugin/site/docs/editor/05-json-syntax.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: 隐藏黑科技 3 | order: 0 4 | title: 模版语法 5 | --- 6 | 7 | ### 1. 字符串 `<%= %>` 8 | `<%= %>` 是变量标识, 内部是javascript语法 9 | 10 | `String` 11 | ```json 12 | 当前时间 <%= new Date().toLocaleString() %> 13 | ``` 14 | ### 2. 非字符串 `<%:= %>` 15 | > `<%:= %>`相当于旧版的`${ }` 16 | 17 | `<%:= %>` 是变量标识, 内部是javaqscript语法. 与字符串的区别是等号前面多了一个冒号`:` 18 | 19 | `Number` 20 | ``` 21 | <%:= 123 %> 22 | ``` 23 | 24 | `Boolean` 25 | ``` 26 | <%:= true %> 27 | ``` 28 | 29 | `Array` 30 | ``` 31 | <%:= [1,2,3] %> 32 | ``` 33 | 34 | `Object` 35 | ``` 36 | <%:= {name: '***'} %> 37 | ``` 38 | 39 | `Function` 40 | 以下是函数的两种写法, 是等效的。 41 | ``` 42 | <%:= (a) => a+1 %> 43 | <%:= function(a){ return a+1 } %> 44 | ``` 45 | 46 | 模版字符串中的变量`作用域`为 [pagestate](/docs/editor/json-pagestate), 在控制台输入`window.$$pagestate` 可查看 47 | -------------------------------------------------------------------------------- /plugin/site/docs/editor/06-senior-formdata.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: 高级用法 3 | order: 0 4 | title: 获取表单值 5 | --- 6 | 7 | 表单的值, 可通过以下别名获取。 8 | 9 | ## 何时使用 10 | - 多个表单相互联动 11 | 12 | ### 表单值别名 13 | > 可通过控制台输入`window.$$pagestate`查看 14 | 15 | - `$$HtList` 搜索表单 16 | - `$$HtModalForm` 右上角弹框表单 17 | - `$$HtFormResponse` 搜索接口返回值 18 | - `$$tableRowModalFormData` 当前行数据, 用于列数据编辑 19 | - `$$tableSelectionRowKeys` 批量选中的id 20 | 21 | ![](https://user-gold-cdn.xitu.io/2020/3/20/170f6d51b56c429d?w=2210&h=1298&f=png&s=314286) 22 | 23 | - `$$HtForm` 24 | - `$$HtFormResponse` 25 | ![](https://user-gold-cdn.xitu.io/2020/3/20/170f6dab25d4ac58?w=2224&h=1022&f=png&s=91150) 26 | -------------------------------------------------------------------------------- /plugin/site/docs/editor/_04-json-actions.md_: -------------------------------------------------------------------------------- 1 | --- 2 | category: 底层概念 3 | order: 3 4 | title: actions 5 | subtitle: actions 6 | --- 7 | 8 | ...待完善 9 | 10 | -------------------------------------------------------------------------------- /plugin/site/docs/editor/changeLog.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: 关于河图 3 | order: 0 4 | title: 更新日志 5 | toc: false 6 | timeline: true 7 | --- 8 | 9 | #### 发布周期 10 | 11 | - 修订版本号:每周二会进行日常 bugfix 更新。(如果有紧急的 bugfix,则任何时候都可发布) 12 | - 次版本号:每月发布一个带有新特性的向下兼容的版本。 13 | - 主版本号:含有破坏性更新和新特性,不在发布周期内。 14 | 15 | --- 16 | 17 | ## 1.0.0 18 | `2020-09-27` 19 | 20 | - 河图开源啦 21 | -------------------------------------------------------------------------------- /plugin/site/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LianjiaTech/hetu/b34b572d5898e7aea939ec5f4b2adbe3a9cabebd/plugin/site/favicon.ico -------------------------------------------------------------------------------- /plugin/site/hetu.ts: -------------------------------------------------------------------------------- 1 | import { store } from '@ice/stark-data' 2 | 3 | // 模拟在乾坤中 4 | // @ts-ignore 5 | window.__POWERED_BY_QIANKUN__ = true 6 | 7 | store.set('hetu-request-config', { 8 | baseURL: 'http://mockjs.docway.net/mock/1XhtOi6ISFV', 9 | headers: { 10 | 'X-Requested-With': 'XMLHttpRequest', 11 | // 用于校验登录状态的token 12 | 'X-Custom-Session': 'site', 13 | }, 14 | }) 15 | -------------------------------------------------------------------------------- /plugin/site/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | hetu 9 | 10 | {% for cssFile in manifest["css"] %} 11 | 12 | {% endfor %} 13 | 18 | 19 | 20 | 21 | 22 |
23 | {{ content | safe }} 24 |
25 | {% for jsFile in manifest["js"] %} 28 | {% endfor %} 29 | 30 | 31 | -------------------------------------------------------------------------------- /plugin/site/theme/static/docsearch.less: -------------------------------------------------------------------------------- 1 | .algolia-autocomplete { 2 | .ds-dropdown-menu { 3 | border: none; 4 | box-shadow: @box-shadow-base; 5 | 6 | [class^='ds-dataset-'] { 7 | border: none; 8 | } 9 | 10 | &::before { 11 | display: none; 12 | } 13 | } 14 | 15 | .algolia-docsearch-suggestion--title { 16 | color: @site-text-color; 17 | } 18 | 19 | .algolia-docsearch-suggestion--highlight { 20 | color: @primary-color; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /plugin/site/theme/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LianjiaTech/hetu/b34b572d5898e7aea939ec5f4b2adbe3a9cabebd/plugin/site/theme/static/favicon.ico -------------------------------------------------------------------------------- /plugin/site/theme/static/index.less: -------------------------------------------------------------------------------- 1 | @import '../style/v2-compatible-reset.less'; 2 | @import '../style/themes/default.less'; 3 | @import './common'; 4 | @import './header'; 5 | @import './footer'; 6 | @import './home'; 7 | @import './page-nav'; 8 | @import './markdown'; 9 | @import './resource'; 10 | @import './preview-img'; 11 | @import './toc'; 12 | @import './not-found'; 13 | @import './highlight'; 14 | @import './demo'; 15 | @import './colors'; 16 | @import './icons'; 17 | @import './mock-browser'; 18 | @import './new-version-info-modal'; 19 | @import './motion'; 20 | @import './responsive'; 21 | @import './theme'; 22 | @import './docsearch'; 23 | @import './nprogress'; 24 | @import './santa'; 25 | -------------------------------------------------------------------------------- /plugin/site/theme/static/motion.less: -------------------------------------------------------------------------------- 1 | .motion-container { 2 | height: 190px; 3 | margin: 40px 0 20px; 4 | line-height: 190px; 5 | text-align: center; 6 | } 7 | 8 | .motion-example { 9 | display: inline-block !important; 10 | width: 180px; 11 | height: 180px; 12 | color: #fff; 13 | font-weight: bold; 14 | font-size: 18px; 15 | line-height: 180px; 16 | text-align: center; 17 | background: url(http://file.ljcdn.com/hetu-cdn/1561703068083.1bb87d41d15fe27b500a4bfcde01bb0e.png) center/180px; 18 | border-radius: 8px; 19 | animation-duration: 0.5s !important; 20 | } 21 | 22 | .motion-select-wrapper { 23 | margin-bottom: 40px; 24 | text-align: center; 25 | } 26 | 27 | .motion-select { 28 | width: 180px; 29 | text-align: left; 30 | } 31 | 32 | .video-player { 33 | position: relative; 34 | max-width: 800px; 35 | 36 | &-right { 37 | float: right; 38 | width: 616px; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /plugin/site/theme/static/new-version-info-modal.less: -------------------------------------------------------------------------------- 1 | @import '../style/themes/default.less'; 2 | 3 | .new-version-info-modal { 4 | img { 5 | position: absolute; 6 | top: 36px; 7 | left: 34px; 8 | width: 100px; 9 | } 10 | p { 11 | margin-top: 1em; 12 | } 13 | .anticon { 14 | display: none; 15 | } 16 | .@{ant-prefix}-confirm-body { 17 | .@{ant-prefix}-confirm-title { 18 | font-size: 18px; 19 | } 20 | 21 | margin-left: 120px; 22 | .@{ant-prefix}-confirm-content { 23 | margin-left: 0; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /plugin/site/theme/static/not-found.less: -------------------------------------------------------------------------------- 1 | #page-404 { 2 | position: fixed; 3 | top: 0; 4 | right: 0; 5 | bottom: 0; 6 | left: 0; 7 | z-index: 100; 8 | width: 100%; 9 | height: 100%; 10 | background-image: url('http://file.ljcdn.com/hetu-cdn/1557744599553.bc5795db2c6ff54b41b645cc261006f2.png'); 11 | background-repeat: no-repeat; 12 | background-position: center; 13 | background-size: 100%; 14 | background-attachment: fixed; 15 | 16 | section { 17 | position: absolute; 18 | top: 48%; 19 | left: 55%; 20 | margin: -103px 0 0 -120px; 21 | text-align: center; 22 | } 23 | 24 | h1 { 25 | color: @primary-color; 26 | font-weight: 500; 27 | font-size: 120px; 28 | } 29 | 30 | p { 31 | color: @site-text-color; 32 | font-size: 18px; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /plugin/site/theme/static/nprogress.less: -------------------------------------------------------------------------------- 1 | #nprogress { 2 | .bar { 3 | background: @primary-color; 4 | } 5 | 6 | .peg { 7 | box-shadow: 0 0 10px @primary-color, 0 0 5px @primary-color; 8 | } 9 | 10 | .spinner-icon { 11 | border-top-color: @primary-color; 12 | border-left-color: @primary-color; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /plugin/site/theme/static/style.js: -------------------------------------------------------------------------------- 1 | import 'rc-drawer/assets/index.css' 2 | import 'docsearch.js/dist/cdn/docsearch.css' 3 | import './index.less' 4 | import 'hetu.css' 5 | -------------------------------------------------------------------------------- /plugin/site/theme/static/theme.less: -------------------------------------------------------------------------------- 1 | @site-heading-color: #0d1a26; 2 | @site-text-color: #314659; 3 | @site-text-color-secondary: #697b8c; 4 | @site-border-color-split: #ebedf0; 5 | -------------------------------------------------------------------------------- /plugin/site/theme/style/core/iconfont.less: -------------------------------------------------------------------------------- 1 | @import '../themes/index'; 2 | @import '../mixins/iconfont'; 3 | 4 | .@{iconfont-css-prefix} { 5 | .iconfont-mixin(); 6 | 7 | &[tabindex] { 8 | cursor: pointer; 9 | } 10 | } 11 | 12 | .@{iconfont-css-prefix}-spin::before { 13 | display: inline-block; 14 | animation: loadingCircle 1s infinite linear; 15 | } 16 | .@{iconfont-css-prefix}-spin { 17 | display: inline-block; 18 | animation: loadingCircle 1s infinite linear; 19 | } 20 | -------------------------------------------------------------------------------- /plugin/site/theme/style/core/index.less: -------------------------------------------------------------------------------- 1 | @import '../mixins/index'; 2 | @import 'base'; 3 | @import 'iconfont'; 4 | @import 'motion'; 5 | -------------------------------------------------------------------------------- /plugin/site/theme/style/core/motion.less: -------------------------------------------------------------------------------- 1 | @import '../style/themes/default.less'; 2 | @import '../mixins/motion'; 3 | @import 'motion/fade'; 4 | @import 'motion/move'; 5 | @import 'motion/other'; 6 | @import 'motion/slide'; 7 | @import 'motion/swing'; 8 | @import 'motion/zoom'; 9 | 10 | // For common/openAnimation 11 | .@{ant-prefix}-motion-collapse-legacy { 12 | overflow: hidden; 13 | &-active { 14 | transition: height 0.15s @ease-in-out, opacity 0.15s @ease-in-out !important; 15 | } 16 | } 17 | 18 | .@{ant-prefix}-motion-collapse { 19 | overflow: hidden; 20 | transition: height 0.15s @ease-in-out, opacity 0.15s @ease-in-out !important; 21 | } 22 | -------------------------------------------------------------------------------- /plugin/site/theme/style/core/motion/fade.less: -------------------------------------------------------------------------------- 1 | .fade-motion(@className, @keyframeName) { 2 | .make-motion(@className, @keyframeName); 3 | .@{className}-enter, 4 | .@{className}-appear { 5 | opacity: 0; 6 | animation-timing-function: linear; 7 | } 8 | .@{className}-leave { 9 | animation-timing-function: linear; 10 | } 11 | } 12 | 13 | .fade-motion(fade, antFade); 14 | 15 | @keyframes antFadeIn { 16 | 0% { 17 | opacity: 0; 18 | } 19 | 100% { 20 | opacity: 1; 21 | } 22 | } 23 | 24 | @keyframes antFadeOut { 25 | 0% { 26 | opacity: 1; 27 | } 28 | 100% { 29 | opacity: 0; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /plugin/site/theme/style/core/motion/swing.less: -------------------------------------------------------------------------------- 1 | .swing-motion(@className, @keyframeName) { 2 | .@{className}-enter, 3 | .@{className}-appear { 4 | .motion-common(); 5 | 6 | animation-play-state: paused; 7 | } 8 | .@{className}-enter.@{className}-enter-active, 9 | .@{className}-appear.@{className}-appear-active { 10 | animation-name: ~'@{keyframeName}In'; 11 | animation-play-state: running; 12 | } 13 | } 14 | 15 | .swing-motion(swing, antSwing); 16 | 17 | @keyframes antSwingIn { 18 | 0%, 19 | 100% { 20 | transform: translateX(0); 21 | } 22 | 20% { 23 | transform: translateX(-10px); 24 | } 25 | 40% { 26 | transform: translateX(10px); 27 | } 28 | 60% { 29 | transform: translateX(-5px); 30 | } 31 | 80% { 32 | transform: translateX(5px); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /plugin/site/theme/style/index.jsx: -------------------------------------------------------------------------------- 1 | import './index.less'; 2 | -------------------------------------------------------------------------------- /plugin/site/theme/style/index.less: -------------------------------------------------------------------------------- 1 | @import './themes/index'; 2 | @import './core/index'; 3 | -------------------------------------------------------------------------------- /plugin/site/theme/style/mixins/clearfix.less: -------------------------------------------------------------------------------- 1 | // mixins for clearfix 2 | // ------------------------ 3 | .clearfix() { 4 | zoom: 1; 5 | &::before, 6 | &::after { 7 | display: table; 8 | content: ''; 9 | } 10 | &::after { 11 | clear: both; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /plugin/site/theme/style/mixins/compatibility.less: -------------------------------------------------------------------------------- 1 | // Compatibility for browsers. 2 | 3 | // Placeholder text 4 | .placeholder(@color: @input-placeholder-color) { 5 | // Firefox 6 | &::-moz-placeholder { 7 | color: @color; 8 | opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526 9 | } 10 | // Internet Explorer 10+ 11 | &:-ms-input-placeholder { 12 | color: @color; 13 | } 14 | // Safari and Chrome 15 | &::-webkit-input-placeholder { 16 | color: @color; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /plugin/site/theme/style/mixins/index.less: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------------------------------- 3 | @import 'size'; 4 | @import 'compatibility'; 5 | @import 'clearfix'; 6 | @import 'iconfont'; 7 | @import 'motion'; 8 | @import 'reset'; 9 | @import 'operation-unit'; 10 | -------------------------------------------------------------------------------- /plugin/site/theme/style/mixins/operation-unit.less: -------------------------------------------------------------------------------- 1 | @import '../../style/themes/default'; 2 | 3 | .operation-unit() { 4 | color: @link-color; 5 | text-decoration: none; 6 | outline: none; 7 | cursor: pointer; 8 | transition: color 0.3s; 9 | 10 | &:focus, 11 | &:hover { 12 | color: @link-hover-color; 13 | } 14 | 15 | &:active { 16 | color: @link-active-color; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /plugin/site/theme/style/mixins/reset.less: -------------------------------------------------------------------------------- 1 | @import '../themes/index'; 2 | 3 | .reset-component() { 4 | box-sizing: border-box; 5 | margin: 0; 6 | padding: 0; 7 | color: @text-color; 8 | font-size: @font-size-base; 9 | font-variant: @font-variant-base; 10 | line-height: @line-height-base; 11 | list-style: none; 12 | font-feature-settings: @font-feature-settings-base; 13 | } 14 | -------------------------------------------------------------------------------- /plugin/site/theme/style/mixins/size.less: -------------------------------------------------------------------------------- 1 | // Sizing shortcuts 2 | 3 | .size(@width; @height) { 4 | width: @width; 5 | height: @height; 6 | } 7 | 8 | .square(@size) { 9 | .size(@size; @size); 10 | } 11 | -------------------------------------------------------------------------------- /plugin/site/theme/style/themes/index.less: -------------------------------------------------------------------------------- 1 | @import './default.less'; 2 | -------------------------------------------------------------------------------- /plugin/site/theme/style/v2-compatible-reset.jsx: -------------------------------------------------------------------------------- 1 | import './v2-compatible-reset.less'; 2 | -------------------------------------------------------------------------------- /plugin/site/theme/style/v2-compatible-reset.less: -------------------------------------------------------------------------------- 1 | // For 2.x reset compatibility 2 | // import 'antd/style/v2-compatible-reset'; 3 | // or 4 | // @import '~antd/style/v2-compatible-reset.css'; 5 | // unify the setting of elements's margin and padding for browsers 6 | body, 7 | div, 8 | dl, 9 | dt, 10 | dd, 11 | ul, 12 | ol, 13 | li, 14 | h1, 15 | h2, 16 | h3, 17 | h4, 18 | h5, 19 | h6, 20 | pre, 21 | code, 22 | form, 23 | fieldset, 24 | legend, 25 | input, 26 | textarea, 27 | p, 28 | blockquote, 29 | th, 30 | td, 31 | hr, 32 | button, 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | menu, 42 | nav, 43 | section { 44 | margin: 0; 45 | padding: 0; 46 | } 47 | 48 | ul, 49 | ol { 50 | list-style: none; 51 | } 52 | -------------------------------------------------------------------------------- /plugin/site/theme/template/AppShell.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Empty component for app shell 3 | * See https://github.com/NekR/offline-plugin/blob/master/docs/app-shell.md 4 | */ 5 | import React from 'react'; 6 | 7 | export default () =>
; 8 | -------------------------------------------------------------------------------- /plugin/site/theme/template/BrowserFrame.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default ({ children }) =>
{children}
; 4 | -------------------------------------------------------------------------------- /plugin/site/theme/template/Color/ColorBlock.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import CopyToClipboard from 'react-copy-to-clipboard'; 3 | import { message } from 'antd'; 4 | 5 | export default class ColorBlock extends Component { 6 | getTextStyle() { 7 | const { color, index } = this.props; 8 | return { 9 | background: color, 10 | color: index > 5 ? '#fff' : 'unset', 11 | fontWeight: index === 6 ? 'bold' : 'normal', 12 | }; 13 | } 14 | 15 | onCopied = () => { 16 | const { color } = this.props; 17 | message.success(`Copied: ${color}`); 18 | }; 19 | 20 | render() { 21 | const { color, index } = this.props; 22 | return ( 23 | 24 |
25 | color-{index} 26 | {color.toLowerCase()} 27 |
28 |
29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /plugin/site/theme/template/Color/ColorPatterns.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { generate } from '@ant-design/colors'; 3 | import ColorBlock from './ColorBlock'; 4 | 5 | export default function ColorPatterns({ color }) { 6 | return generate(color).map((colorString, i) => ( 7 | // eslint-disable-line 8 | )); 9 | } 10 | -------------------------------------------------------------------------------- /plugin/site/theme/template/Content/EditButton.jsx: -------------------------------------------------------------------------------- 1 | import { Icon, Tooltip } from 'antd'; 2 | import React from 'react'; 3 | 4 | const branchUrl = 'http://github.com/LianjiaTech/hetu/tree/master'; 5 | 6 | export default function EditButton({ title, filename }) { 7 | let href = `${branchUrl}/site/${filename}` 8 | if (/^components\//.test(filename)) { 9 | href = `${branchUrl}/src/${filename}` 10 | } 11 | return ( 12 | 13 | 19 | 20 | 21 | 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /plugin/site/theme/template/Content/ErrorBoundary.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Alert } from 'antd' 3 | 4 | export default class ErrorBoundary extends React.Component { 5 | state = { 6 | error: null, 7 | } 8 | 9 | componentDidCatch(error, info) { 10 | this.setState({ error, info }) 11 | } 12 | 13 | render() { 14 | const { children } = this.props 15 | const { error, info } = this.state 16 | if (error) { 17 | // You can render any custom fallback UI 18 | return 19 | } 20 | return children || null 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /plugin/site/theme/template/Content/PrevAndNext.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default ({ prev, next }) => ( 4 |
5 | {prev 6 | ? React.cloneElement(prev.props.children || prev.children[0], { 7 | className: 'prev-page', 8 | }) 9 | : null} 10 | {next 11 | ? React.cloneElement(next.props.children || next.children[0], { 12 | className: 'next-page', 13 | }) 14 | : null} 15 |
16 | ); 17 | -------------------------------------------------------------------------------- /plugin/site/theme/template/FormattedMessage/index.jsx: -------------------------------------------------------------------------------- 1 | import znCNMap from '@/theme/zh-CN' 2 | import { get } from 'lodash/object' 3 | import React, { Fragment } from 'react' 4 | 5 | export default class FormattedMessage extends React.Component { 6 | render() { 7 | const { id } = this.props 8 | 9 | const messages = get(znCNMap, 'messages') 10 | 11 | return {messages[`${id}`]} 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /plugin/site/theme/template/Home/util.jsx: -------------------------------------------------------------------------------- 1 | /* eslint no-undef: 0 */ 2 | import React from 'react'; 3 | import ScrollParallax from 'rc-scroll-anim/lib/ScrollParallax'; 4 | 5 | function ParallaxG(props) { 6 | return ; 7 | } 8 | 9 | export default function svgBgToParallax(children, i = 0) { 10 | const svgChildren = React.Children.toArray(children).map((child, ii) => ( 11 | 19 | {child} 20 | 21 | )); 22 | return svgChildren; 23 | } 24 | -------------------------------------------------------------------------------- /plugin/site/theme/template/IconDisplay/CopyableIcon.jsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import CopyToClipboard from 'react-copy-to-clipboard' 3 | import { Icon as AntdIcon, Badge } from 'antd' 4 | import classNames from 'classnames' 5 | 6 | const Icon = AntdIcon 7 | 8 | const CopyableIcon = ({ type, theme, isNew, justCopied, onCopied }) => { 9 | const className = classNames({ 10 | copied: justCopied === type, 11 | outlined: theme === 'twoTone', 12 | }) 13 | return ( 14 | ` 18 | : `` 19 | } 20 | onCopy={(text) => onCopied(type, text)} 21 | > 22 |
  • 23 | 24 | 25 | {type} 26 | 27 |
  • 28 |
    29 | ) 30 | } 31 | 32 | export default CopyableIcon 33 | -------------------------------------------------------------------------------- /plugin/site/theme/template/Layout/SentryBoundary.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | export default class SentryBoundary extends Component { 4 | state = { error: null }; 5 | 6 | componentDidCatch(error, errorInfo) { 7 | this.setState({ error }); 8 | } 9 | 10 | render() { 11 | const { children } = this.props; 12 | const { error } = this.state; 13 | if (error) { 14 | // render fallback UI 15 | return Sentry.showReportDialog()}>Report feedback; 16 | } 17 | // when there's not an error, render children untouched 18 | return children; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /plugin/site/theme/template/NotFound.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'bisheng/router'; 3 | import * as utils from './utils'; 4 | 5 | export default function NotFound({ location }) { 6 | return ( 7 |
    8 |
    9 |

    404

    10 |

    11 | 你要找的页面不存在 12 | 13 | 返回首页 14 | 15 |

    16 |
    17 |