├── .editorconfig ├── .env ├── .eslintrc ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .storybook ├── config.js └── webpack.config.js ├── .svn ├── entries ├── format ├── pristine │ ├── 10 │ │ └── 1001f16043056312d6e6bb7ec5dfdf0e55cd2eee.svn-base │ ├── 14 │ │ └── 145687dbbd39240980a82be3c2191dbe27adbeb7.svn-base │ ├── 31 │ │ └── 31fa5b53d2ee99cc83a70cd7b6e40a938584192a.svn-base │ ├── 35 │ │ └── 35ca28cdbb212095f67b486113bf6d380aa3e5e6.svn-base │ ├── 40 │ │ ├── 40651567fee77e7d010d5e9274037c6155dc15ba.svn-base │ │ └── 40efa7c3eb902c3370ec0c384723cd7f7392e176.svn-base │ ├── 52 │ │ ├── 5214979ac5a07cf1c6774bb6b0de4755cb3733a5.svn-base │ │ └── 524d0ea881221e8df4550748671ed3c0e86a2b5c.svn-base │ ├── 59 │ │ └── 59d14805d44a773d5c83223fc994c19974310334.svn-base │ ├── 60 │ │ └── 601c69c461d5ac9e2c3c78c8037047f58074e989.svn-base │ ├── 61 │ │ └── 6192708a240d5eca879f27a77c98dc69558c7a88.svn-base │ ├── 79 │ │ └── 79a608fcc4e5b345af7404964f700c3c559cb7ed.svn-base │ ├── 80 │ │ └── 802829df81fefe4213bd3aef78400c976d8f98d8.svn-base │ ├── 88 │ │ └── 8882b2e8af4a8ca8ba631e24679e9ff4fe3ac893.svn-base │ ├── 90 │ │ ├── 907489dd1e06e94a231338b228730829caf715d7.svn-base │ │ └── 90e7191fda5d313818b7365d2a2cee202be1e375.svn-base │ ├── 01 │ │ └── 01870ac9ec0d23c69b485512ea7ef91543a8d988.svn-base │ ├── 03 │ │ ├── 0350ac17255f6d23f99b4a9f003004919e310c20.svn-base │ │ └── 03a2791271bc9370674f6f6e88e6cf9d9fe1fc46.svn-base │ ├── 07 │ │ └── 071be9703a5d7e9fb80499fd20c4587c946e7bfe.svn-base │ ├── 1a │ │ └── 1a15283d739bd2b4a5967cefb053477031c1ab25.svn-base │ ├── 2b │ │ └── 2b81c6cb47e79124eafe37a391b87f7c50d65807.svn-base │ ├── 2f │ │ └── 2f090cf62c8e05dbc46dea5ee27251523ed9b134.svn-base │ ├── 3d │ │ └── 3d2375fdfd060ea4d532f58405c2e1a4d7b3a394.svn-base │ ├── 5b │ │ └── 5ba206f23d051612e7d1eac7f5d2d07fa87a34c9.svn-base │ ├── 6a │ │ └── 6a9629cc3184c096bdc0cc75412cc6cfe56c9070.svn-base │ ├── 6d │ │ └── 6dcf794d90e5ef456a8702cb3346ec7565ee8af2.svn-base │ ├── 7b │ │ └── 7b213d614d18458daca4a566cc3be87b2a0c1ca2.svn-base │ ├── 7d │ │ └── 7d7ea6c476197a745d852601e143a5a55ad4801b.svn-base │ ├── 8e │ │ └── 8e14f08020bb604422ba024cf75975227041f1a0.svn-base │ ├── 9a │ │ ├── 9a30f13cc711f93a0dcf09f07022ccec0dabd1bb.svn-base │ │ └── 9a963983860f096eba01fd6ac4cd273a3bfb382f.svn-base │ ├── a6 │ │ └── a647d65fc56d06649218e84aa555fa74f6711c99.svn-base │ ├── c1 │ │ └── c15d92a2cecc152a8e735428e425e20099c49d0f.svn-base │ ├── c8 │ │ └── c83b4030392bfa8aaf801abb09138cd484158fd5.svn-base │ ├── d2 │ │ └── d21ae8b67971f49eb126cc1b05d2e419d10d6431.svn-base │ ├── d4 │ │ └── d4edb2d21e5c29ce5c645b1757077951b6a3b2dd.svn-base │ ├── d5 │ │ └── d5ecdc4208ac1c1797d04744e2832895c7f77d48.svn-base │ ├── d8 │ │ └── d8eb3b98218af6f8243bfc1bd78ff3d243f6e714.svn-base │ ├── da │ │ └── da39a3ee5e6b4b0d3255bfef95601890afd80709.svn-base │ ├── e1 │ │ └── e190840dbaece0a76680d4e19f92a0c191045a05.svn-base │ ├── e8 │ │ └── e8a120dfe78d41632f9431bfb30b2fa11ced2527.svn-base │ ├── eb │ │ └── eb7bd206d71aa62e42186bd1239639d17795f969.svn-base │ ├── ee │ │ └── eeee6286abac22bb2941b77bb63bbf0f8eb53a98.svn-base │ ├── f3 │ │ └── f3837a7219ace8679117e664c433110530a6ed6a.svn-base │ └── f9 │ │ └── f9048b6a960d338d940b094d183a825bfa34454f.svn-base ├── wc.db └── wc.db-journal ├── .travis.yml ├── .umirc.ts ├── README.md ├── mock └── .gitkeep ├── package.json ├── src ├── app.tsx ├── assets │ └── yay.jpg ├── components │ ├── DragWarpper │ │ ├── index.less │ │ └── index.tsx │ ├── Widge │ │ ├── index.less │ │ └── index.tsx │ └── formilyExtra │ │ ├── DndInput.tsx │ │ └── Options │ │ └── index.tsx ├── contants.ts ├── global.less ├── index.stories.tsx ├── layouts │ ├── __tests__ │ │ └── index.test.tsx │ ├── index.css │ └── index.tsx ├── pages │ ├── __tests__ │ │ └── index.test.tsx │ ├── dictionary.ts │ ├── index.css │ ├── index.tsx │ └── layouts │ │ ├── Board │ │ ├── index.less │ │ └── index.tsx │ │ ├── FieldConfig │ │ └── index.tsx │ │ ├── Layout.less │ │ ├── Layout.tsx │ │ └── WidgeList │ │ └── index.tsx ├── schemajson.ts ├── service │ ├── data.d.ts │ ├── form.ts │ └── formData.ts ├── store │ ├── Maker.ts │ └── data.d.ts ├── utils │ ├── data.d.ts │ ├── request.ts │ └── utils.ts └── widge.ts ├── tsconfig.json └── typings.d.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [Makefile] 16 | indent_style = tab 17 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | BROWSER=none 2 | ESLINT=1 3 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-umi" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /npm-debug.log* 6 | /yarn-error.log 7 | /yarn.lock 8 | /package-lock.json 9 | 10 | # production 11 | /dist 12 | 13 | # misc 14 | .DS_Store 15 | 16 | # umi 17 | .umi 18 | .umi-production 19 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/*.md 2 | **/*.svg 3 | **/*.ejs 4 | **/*.html 5 | package.json 6 | .umi 7 | .umi-production 8 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all", 4 | "printWidth": 100, 5 | "overrides": [ 6 | { 7 | "files": ".prettierrc", 8 | "options": { "parser": "json" } 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import { configure } from '@storybook/react'; 2 | import 'antd/dist/antd.css'; 3 | 4 | function loadStories() { 5 | const req = require.context('../src', true, /\.stories\.tsx$/); 6 | req.keys().forEach(filename => req(filename)); 7 | } 8 | 9 | configure(loadStories, module); 10 | -------------------------------------------------------------------------------- /.storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = ({ config }) => { 4 | config.module.rules.push({ 5 | test: /\.(ts|tsx)$/, 6 | use: [ 7 | { 8 | loader: require.resolve('awesome-typescript-loader'), 9 | }, 10 | ], 11 | }); 12 | config.module.rules.push({ 13 | test: /\.less$/, 14 | use: [ 15 | { 16 | loader: 'style-loader', // creates style nodes from JS strings 17 | }, 18 | { 19 | loader: 'css-loader', // translates CSS into CommonJS 20 | options: { 21 | modules: true, 22 | }, 23 | }, 24 | { 25 | loader: 'less-loader', // compiles Less to CSS 26 | options: { javascriptEnabled: true }, 27 | }, 28 | ], 29 | }); 30 | config.resolve.extensions.push('.ts', '.tsx'); 31 | 32 | return config; 33 | }; 34 | -------------------------------------------------------------------------------- /.svn/entries: -------------------------------------------------------------------------------- 1 | 12 2 | -------------------------------------------------------------------------------- /.svn/format: -------------------------------------------------------------------------------- 1 | 12 2 | -------------------------------------------------------------------------------- /.svn/pristine/01/01870ac9ec0d23c69b485512ea7ef91543a8d988.svn-base: -------------------------------------------------------------------------------- 1 | @import '~antd/es/style/themes/default.less'; 2 | 3 | .container { 4 | padding: 10px 10px; 5 | overflow: auto; 6 | .board { 7 | border: 1px dashed rgba(236, 245, 255, 0.3); 8 | height: 79vh; 9 | overflow: auto; 10 | padding: 2px; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.svn/pristine/03/0350ac17255f6d23f99b4a9f003004919e310c20.svn-base: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "umi dev -p 3001", 5 | "build": "umi build", 6 | "test": "umi test", 7 | "lint": "eslint {src,mock,tests}/**/*.{ts,tsx} --fix", 8 | "precommit": "lint-staged", 9 | "storybook": "start-storybook -p 6006" 10 | }, 11 | "dependencies": { 12 | "@ant-design/compatible": "^0.0.1-rc.1", 13 | "@formily/antd": "^1.0.3", 14 | "@formily/antd-components": "^1.0.3", 15 | "@storybook/react": "^5.3.13", 16 | "@types/classnames": "^2.2.9", 17 | "@types/react-beautiful-dnd": "^12.1.1", 18 | "@types/react-transition-group": "^4.2.4", 19 | "@types/uuid": "^3.4.7", 20 | "antd": "^4.0.0", 21 | "awesome-typescript-loader": "^5.2.1", 22 | "babel-plugin-import": "^1.13.0", 23 | "classnames": "^2.2.6", 24 | "css-loader": "^3.4.2", 25 | "immutability-helper": "^3.0.1", 26 | "less": "^3.11.1", 27 | "less-loader": "^5.0.0", 28 | "lodash": "^4.17.15", 29 | "mobx": "^5.15.4", 30 | "mobx-react": "^6.1.8", 31 | "mobx-react-lite": "^1.5.2", 32 | "react": "^16.8.6", 33 | "react-beautiful-dnd": "^13.0.0", 34 | "react-dnd": "^10.0.2", 35 | "react-dnd-html5-backend": "^10.0.2", 36 | "react-dom": "^16.8.6", 37 | "react-transition-group": "^4.3.0", 38 | "style-loader": "^1.1.3", 39 | "umi-request": "^1.2.19", 40 | "uuid": "^7.0.0", 41 | "webpack-combine-loaders": "^2.0.4" 42 | }, 43 | "devDependencies": { 44 | "@types/jest": "^23.3.12", 45 | "@types/react": "^16.7.18", 46 | "@types/react-dom": "^16.0.11", 47 | "@types/react-test-renderer": "^16.0.3", 48 | "babel-eslint": "^9.0.0", 49 | "eslint": "^5.4.0", 50 | "eslint-config-umi": "^1.4.0", 51 | "eslint-plugin-flowtype": "^2.50.0", 52 | "eslint-plugin-import": "^2.14.0", 53 | "eslint-plugin-jsx-a11y": "^5.1.1", 54 | "eslint-plugin-react": "^7.11.1", 55 | "husky": "^0.14.3", 56 | "lint-staged": "^7.2.2", 57 | "react-test-renderer": "^16.7.0", 58 | "umi": "^2.9.0", 59 | "umi-plugin-react": "^1.8.0", 60 | "umi-types": "^0.3.0" 61 | }, 62 | "lint-staged": { 63 | "*.{ts,tsx}": [ 64 | "eslint --fix", 65 | "git add" 66 | ], 67 | "*.{js,jsx}": [ 68 | "eslint --fix", 69 | "git add" 70 | ] 71 | }, 72 | "engines": { 73 | "node": ">=8.0.0" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /.svn/pristine/03/03a2791271bc9370674f6f6e88e6cf9d9fe1fc46.svn-base: -------------------------------------------------------------------------------- 1 | declare module '*.css'; 2 | declare module '*.png'; 3 | declare module '*.less'; 4 | -------------------------------------------------------------------------------- /.svn/pristine/07/071be9703a5d7e9fb80499fd20c4587c946e7bfe.svn-base: -------------------------------------------------------------------------------- 1 | # form-making-react -------------------------------------------------------------------------------- /.svn/pristine/10/1001f16043056312d6e6bb7ec5dfdf0e55cd2eee.svn-base: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | interface PaginationParams extends IPagenationParams { 4 | formId: string; 5 | } 6 | 7 | export async function getPaged(params: PaginationParams) { 8 | return request(`/form/data`, { method: 'get', params }); 9 | } 10 | -------------------------------------------------------------------------------- /.svn/pristine/14/145687dbbd39240980a82be3c2191dbe27adbeb7.svn-base: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-umi" 3 | } 4 | -------------------------------------------------------------------------------- /.svn/pristine/1a/1a15283d739bd2b4a5967cefb053477031c1ab25.svn-base: -------------------------------------------------------------------------------- 1 | import { v4 as uuidV4 } from 'uuid'; 2 | export const getItemStyle = (isDragging: any, draggableStyle: any) => ({ 3 | // some basic styles to make the items look a bit nicer 4 | // userSelect: 'none', 5 | 6 | // change background colour if dragging 7 | // background: isDragging ? 'lightgreen' : 'red', 8 | 9 | // styles we need to apply on draggables 10 | ...draggableStyle, 11 | }); 12 | 13 | export const getListStyle = (isDraggingOver: any) => ({ 14 | // background: isDraggingOver ? 'lightblue' : 'grey', 15 | }); 16 | 17 | export const getGUID = () => { 18 | return uuidV4().replace(/-/g, ''); 19 | }; 20 | -------------------------------------------------------------------------------- /.svn/pristine/2b/2b81c6cb47e79124eafe37a391b87f7c50d65807.svn-base: -------------------------------------------------------------------------------- 1 | import { createFromIconfontCN } from '@ant-design/icons'; 2 | 3 | export const ItemTypes = { 4 | INPUT: 'DndInput', 5 | TEXTAREA: 'DndTextarea', 6 | SELECT: 'DndSelect', 7 | DATEPICKER: 'DndDatePicker', 8 | INPUTNUMBER: 'DndInputNumber', 9 | CHECKBOX: 'DndCheckbox', 10 | RADIO: 'DndRadio', 11 | SWITCH: 'DndSwitch', 12 | RANGPICKER: 'DndRangePicker', 13 | }; 14 | 15 | export const Accept = [ 16 | ItemTypes.INPUT, 17 | ItemTypes.TEXTAREA, 18 | ItemTypes.SELECT, 19 | ItemTypes.DATEPICKER, 20 | ItemTypes.INPUTNUMBER, 21 | ItemTypes.CHECKBOX, 22 | ItemTypes.RADIO, 23 | ItemTypes.SWITCH, 24 | ItemTypes.RANGPICKER, 25 | ]; 26 | 27 | export const MyIcon = createFromIconfontCN({ 28 | scriptUrl: '//at.alicdn.com/t/font_1660311_lyo1k8r276.js', 29 | }); 30 | -------------------------------------------------------------------------------- /.svn/pristine/2f/2f090cf62c8e05dbc46dea5ee27251523ed9b134.svn-base: -------------------------------------------------------------------------------- 1 | export const BASE = { 2 | type: 'object', 3 | properties: { 4 | title: { 5 | title: '标题', 6 | type: 'string', 7 | }, 8 | placeholder: { 9 | title: '占位内容', 10 | type: 'string', 11 | }, 12 | require: { 13 | title: '必填', 14 | type: 'Switch', 15 | }, 16 | disabled: { 17 | title: '禁用', 18 | type: 'Switch', 19 | }, 20 | }, 21 | }; 22 | 23 | export const DndInput = { 24 | type: 'object', 25 | properties: { 26 | title: { 27 | title: '标题', 28 | type: 'string', 29 | }, 30 | placeholder: { 31 | title: '占位内容', 32 | type: 'string', 33 | }, 34 | required: { 35 | title: '必填', 36 | type: 'Switch', 37 | }, 38 | disabled: { 39 | title: '禁用', 40 | type: 'Switch', 41 | }, 42 | }, 43 | }; 44 | 45 | export const DndDatePicker = { 46 | type: 'object', 47 | properties: { 48 | title: { 49 | title: '标题', 50 | type: 'string', 51 | }, 52 | placeholder: { 53 | title: '占位内容', 54 | type: 'string', 55 | }, 56 | required: { 57 | title: '必填', 58 | type: 'Switch', 59 | }, 60 | disabled: { 61 | title: '禁用', 62 | type: 'Switch', 63 | }, 64 | }, 65 | }; 66 | 67 | export const DndInputNumber = { 68 | type: 'object', 69 | properties: { 70 | title: { 71 | title: '标题', 72 | type: 'string', 73 | }, 74 | placeholder: { 75 | title: '占位内容', 76 | type: 'string', 77 | }, 78 | required: { 79 | title: '必填', 80 | type: 'Switch', 81 | }, 82 | disabled: { 83 | title: '禁用', 84 | type: 'Switch', 85 | }, 86 | }, 87 | }; 88 | 89 | export const DndTextarea = { 90 | type: 'object', 91 | properties: { 92 | title: { 93 | title: '标题', 94 | type: 'string', 95 | }, 96 | placeholder: { 97 | title: '占位内容', 98 | type: 'string', 99 | }, 100 | required: { 101 | title: '必填', 102 | type: 'Switch', 103 | }, 104 | disabled: { 105 | title: '禁用', 106 | type: 'Switch', 107 | }, 108 | }, 109 | }; 110 | 111 | export const DndSelect = { 112 | type: 'object', 113 | properties: { 114 | title: { 115 | title: '标题', 116 | type: 'string', 117 | }, 118 | placeholder: { 119 | title: '占位内容', 120 | type: 'string', 121 | }, 122 | required: { 123 | title: '必填', 124 | type: 'Switch', 125 | }, 126 | disabled: { 127 | title: '禁用', 128 | type: 'Switch', 129 | }, 130 | enum: { 131 | title: '简单数据', 132 | type: 'Options', 133 | }, 134 | }, 135 | }; 136 | 137 | export const DndCheckbox = { 138 | type: 'object', 139 | properties: { 140 | title: { 141 | title: '标题', 142 | type: 'string', 143 | }, 144 | placeholder: { 145 | title: '占位内容', 146 | type: 'string', 147 | }, 148 | required: { 149 | title: '必填', 150 | type: 'Switch', 151 | }, 152 | disabled: { 153 | title: '禁用', 154 | type: 'Switch', 155 | }, 156 | enum: { 157 | title: '简单数据', 158 | type: 'Options', 159 | }, 160 | }, 161 | }; 162 | 163 | export const DndRadio = { 164 | type: 'object', 165 | properties: { 166 | title: { 167 | title: '标题', 168 | type: 'string', 169 | }, 170 | placeholder: { 171 | title: '占位内容', 172 | type: 'string', 173 | }, 174 | required: { 175 | title: '必填', 176 | type: 'Switch', 177 | }, 178 | disabled: { 179 | title: '禁用', 180 | type: 'Switch', 181 | }, 182 | enum: { 183 | title: '简单数据', 184 | type: 'Options', 185 | }, 186 | }, 187 | }; 188 | 189 | export const DndSwitch = { 190 | type: 'object', 191 | properties: { 192 | title: { 193 | title: '标题', 194 | type: 'string', 195 | }, 196 | required: { 197 | title: '必填', 198 | type: 'Switch', 199 | }, 200 | disabled: { 201 | title: '禁用', 202 | type: 'Switch', 203 | }, 204 | }, 205 | }; 206 | 207 | export const DndRangePicker = { 208 | type: 'object', 209 | properties: { 210 | title: { 211 | title: '标题', 212 | type: 'string', 213 | }, 214 | required: { 215 | title: '必填', 216 | type: 'Switch', 217 | }, 218 | disabled: { 219 | title: '禁用', 220 | type: 'Switch', 221 | }, 222 | }, 223 | }; 224 | -------------------------------------------------------------------------------- /.svn/pristine/31/31fa5b53d2ee99cc83a70cd7b6e40a938584192a.svn-base: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Input } from 'antd'; 3 | import DragWarpper from '../DragWarpper'; 4 | 5 | export const DndInput = (props: any) => { 6 | console.log(props); 7 | const { placeholder, required } = props; 8 | return ; 9 | }; 10 | -------------------------------------------------------------------------------- /.svn/pristine/35/35ca28cdbb212095f67b486113bf6d380aa3e5e6.svn-base: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Layout from './layouts/layout'; 3 | import Board from './layouts/Board'; 4 | import WidgeList from './layouts/WidgeList'; 5 | import { makerContext, Maker } from '@/store/Maker'; 6 | import 'antd/dist/antd.css'; 7 | import ConfigBlock from './layouts/FieldConfig'; 8 | import { ConfigProvider } from 'antd'; 9 | import zhCN from 'antd/es/locale/zh_CN'; 10 | import { getGUID } from '@/utils/utils'; 11 | 12 | export default function() { 13 | const store = React.useRef(new Maker()).current; 14 | 15 | return ( 16 | 17 | 18 | } 20 | left={} 21 | center={} 22 | > 23 | 24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /.svn/pristine/3d/3d2375fdfd060ea4d532f58405c2e1a4d7b3a394.svn-base: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "lib": ["dom", "dom.iterable", "esnext"], 7 | "skipLibCheck": true, 8 | "importHelpers": true, 9 | "jsx": "react", 10 | "esModuleInterop": true, 11 | "sourceMap": true, 12 | "baseUrl": ".", 13 | "strict": true, 14 | "experimentalDecorators": true, 15 | "emitDecoratorMetadata": true, 16 | "paths": { 17 | "@/*": ["src/*"], 18 | "@tmp/*": ["src/pages/.umi/*"] 19 | }, 20 | "allowSyntheticDefaultImports": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.svn/pristine/40/40651567fee77e7d010d5e9274037c6155dc15ba.svn-base: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button } from '@storybook/react/demo'; 3 | 4 | export default { title: 'Button' }; 5 | 6 | export const withText = () => ; 7 | 8 | export const withEmoji = () => ( 9 | 14 | ); 15 | -------------------------------------------------------------------------------- /.svn/pristine/40/40efa7c3eb902c3370ec0c384723cd7f7392e176.svn-base: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Form } from '@ant-design/compatible'; 3 | import '@ant-design/compatible/assets/index.css'; 4 | import { Tabs, Checkbox } from 'antd'; 5 | import { 6 | SchemaForm, 7 | SchemaMarkupField as Field, 8 | createAsyncFormActions, 9 | FormSlot, 10 | } from '@formily/antd'; 11 | import { setup } from '@formily/antd-components'; 12 | import { Switch } from '@formily/antd-components'; 13 | import Options from '@/components/formilyExtra/Options'; 14 | import { MakerItemProps, Maker, makerContext } from '@/store/Maker'; 15 | import { toJS } from 'mobx'; 16 | import { observer } from 'mobx-react-lite'; 17 | import * as configSchema from '@/schemajson'; 18 | import { ItemTypes } from '@/contants'; 19 | 20 | setup(); 21 | 22 | const { TabPane } = Tabs; 23 | const ConfigBlock = () => { 24 | const maker = React.useContext(makerContext)!; 25 | 26 | React.useEffect(() => { 27 | console.log(toJS(maker.selected)); 28 | if (!!maker.selected) { 29 | actions.setFormState(state => { 30 | state.values = toJS(maker.selected?.fieldProps!); 31 | }); 32 | } 33 | }, [maker.selected]); 34 | 35 | const actions = React.useRef(createAsyncFormActions()).current; 36 | 37 | const selected = maker.selected; 38 | 39 | const type = selected?.type; 40 | 41 | const getSchema = (type: string) => { 42 | if (!!type) { 43 | return (configSchema as any)[type]; 44 | } 45 | return undefined; 46 | }; 47 | 48 | const [value, setValue] = React.useState({}); 49 | 50 | return ( 51 |
52 | 53 | 54 | { 61 | maker.mutePrpos(value); 62 | }} 63 | > 64 | 65 | 66 |
67 | ); 68 | }; 69 | 70 | export default observer(ConfigBlock); 71 | -------------------------------------------------------------------------------- /.svn/pristine/52/5214979ac5a07cf1c6774bb6b0de4755cb3733a5.svn-base: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ConfigProvider } from 'antd'; 3 | 4 | export function rootContainer(container: any) { 5 | return React.createElement(ConfigProvider, null, container); 6 | } 7 | -------------------------------------------------------------------------------- /.svn/pristine/52/524d0ea881221e8df4550748671ed3c0e86a2b5c.svn-base: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './index.less'; 3 | import { Form } from '@ant-design/compatible'; 4 | import '@ant-design/compatible/assets/index.css'; 5 | 6 | import { observer } from 'mobx-react-lite'; 7 | 8 | import { ItemTypes } from '@/contants'; 9 | import { useDrag, useDrop } from 'react-dnd'; 10 | 11 | const formItemLayout = { 12 | labelCol: { span: 4 }, 13 | wrapperCol: { span: 12 }, 14 | }; 15 | 16 | export interface FBProps { 17 | onSelected: (item: any) => void; 18 | onDelete: (uuid: string) => void; 19 | data: any; 20 | selected: any | undefined; 21 | index: number; 22 | onEnd: () => void; 23 | moveItem: (dragIndex: number, hoverIndex: number) => void; 24 | onAddCopy: () => void; 25 | widge: any; 26 | } 27 | 28 | const DragWarpper: React.SFC = props => { 29 | const { 30 | selected, 31 | onSelected, 32 | data, 33 | onDelete, 34 | widge, 35 | index, 36 | onEnd, 37 | moveItem, 38 | onAddCopy, 39 | children, 40 | } = props; 41 | 42 | const isCurrent = selected && selected.fieldProps && selected.fieldProps.name === data.name; 43 | 44 | const ref = React.useRef(null); 45 | 46 | const [{ isDragging }, drag] = useDrag({ 47 | item: { type: ItemTypes.INPUT, index: index }, 48 | end: () => onEnd(), 49 | collect: monitor => ({ 50 | isDragging: monitor.isDragging(), 51 | }), 52 | }); 53 | 54 | const [{ isHover }, drop] = useDrop({ 55 | accept: ItemTypes.INPUT, 56 | hover: (item: any, monitor) => { 57 | if (!ref.current) { 58 | return; 59 | } 60 | 61 | const dragIndex = item.index; 62 | 63 | //drop new here 64 | if (dragIndex === undefined) { 65 | // maker.appendItem({ uuid: '', currentIndex: maker.MakerItems.length }); 66 | return; 67 | } 68 | 69 | const hoverIndex = index!; 70 | 71 | if (hoverIndex === undefined) return; 72 | if (dragIndex === hoverIndex) { 73 | return; 74 | } 75 | // Determine rectangle on screen 76 | const hoverBoundingRect = (ref!.current as any).getBoundingClientRect(); 77 | // Get vertical middle 78 | const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; 79 | // Determine mouse position 80 | const clientOffset = monitor.getClientOffset()!; 81 | // Get pixels to the top 82 | const hoverClientY = clientOffset.y - hoverBoundingRect.top; 83 | // Only perform the move when the mouse has crossed half of the items height 84 | // When dragging downwards, only move when the cursor is below 50% 85 | // When dragging upwards, only move when the cursor is above 50% 86 | // Dragging downwards 87 | if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { 88 | return; 89 | } 90 | // Dragging upwards 91 | if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { 92 | return; 93 | } 94 | // Time to actually perform the action 95 | moveItem(dragIndex, hoverIndex); 96 | // Note: we're mutating the monitor item here! 97 | // Generally it's better to avoid mutations, 98 | // but it's good here for the sake of performance 99 | // to avoid expensive index searches. 100 | item.index = hoverIndex; 101 | }, 102 | drop: (item: any) => { 103 | const dragIndex = item.index; 104 | // if (dragIndex === undefined) { 105 | // maker.appendItem(item.type); 106 | // } 107 | }, 108 | collect: montitor => ({ 109 | isHover: !!montitor.isOver(), 110 | }), 111 | }); 112 | 113 | drag(drop(ref)); 114 | 115 | const renderDragIcon = () => { 116 | return ( 117 | 126 | 131 | 132 | ); 133 | }; 134 | 135 | const renderActions = () => { 136 | return ( 137 | <> 138 | { 147 | onAddCopy(); 148 | }} 149 | > 150 | 155 | 156 | onDelete(data.name!)} 158 | style={{ marginLeft: 5 }} 159 | viewBox="0 0 1030 1024" 160 | version="1.1" 161 | xmlns="http://www.w3.org/2000/svg" 162 | p-id="3253" 163 | width="14" 164 | height="14" 165 | > 166 | 171 | 172 | 173 | ); 174 | }; 175 | 176 | const containerStyles = isCurrent ? styles['contianer-active'] : styles.container; 177 | const opacity = isDragging ? 0 : 1; 178 | return ( 179 |
onSelected(widge)} 183 | ref={ref} 184 | > 185 | {children} 186 | {isCurrent && ( 187 | <> 188 |
{renderDragIcon()}
189 |
190 | {renderActions()} 191 |
192 | 193 | )} 194 |
195 | ); 196 | }; 197 | 198 | export default observer(DragWarpper); 199 | -------------------------------------------------------------------------------- /.svn/pristine/59/59d14805d44a773d5c83223fc994c19974310334.svn-base: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | export async function add(data: FormEntity) { 4 | return request('/form', { method: 'post', data: data }); 5 | } 6 | 7 | export async function getById(formId: string) { 8 | return request(`/form/${formId}`); 9 | } 10 | 11 | export async function update(data: FormEntity) { 12 | return request('/form', { method: 'put', data }); 13 | } 14 | 15 | export async function deleteById(formId: string) { 16 | return request(`/form/${formId}`, { method: 'delete' }); 17 | } 18 | 19 | export async function getPaged(params: IPagenationParams) { 20 | return request(`/form`, { params }); 21 | } 22 | 23 | export async function submit(data: FMFormData) { 24 | return request(`/form/data`, { method: 'post', data }); 25 | } 26 | -------------------------------------------------------------------------------- /.svn/pristine/5b/5ba206f23d051612e7d1eac7f5d2d07fa87a34c9.svn-base: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /npm-debug.log* 6 | /yarn-error.log 7 | /yarn.lock 8 | /package-lock.json 9 | 10 | # production 11 | /dist 12 | 13 | # misc 14 | .DS_Store 15 | 16 | # umi 17 | .umi 18 | .umi-production 19 | -------------------------------------------------------------------------------- /.svn/pristine/60/601c69c461d5ac9e2c3c78c8037047f58074e989.svn-base: -------------------------------------------------------------------------------- 1 | import 'jest'; 2 | import Index from '..'; 3 | import React from 'react'; 4 | import renderer, { ReactTestInstance, ReactTestRenderer } from 'react-test-renderer'; 5 | 6 | 7 | describe('Page: index', () => { 8 | it('Render correctly', () => { 9 | const wrapper: ReactTestRenderer = renderer.create(); 10 | expect(wrapper.root.children.length).toBe(1); 11 | const outerLayer = wrapper.root.children[0] as ReactTestInstance; 12 | expect(outerLayer.type).toBe('div'); 13 | expect(outerLayer.children.length).toBe(2); 14 | 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /.svn/pristine/61/6192708a240d5eca879f27a77c98dc69558c7a88.svn-base: -------------------------------------------------------------------------------- 1 | interface BasicProps { 2 | required?: boolean; 3 | disabled?: boolean; 4 | label?: string; 5 | placeholder?: string; 6 | readonly?: string; 7 | default?: string | any; 8 | } 9 | 10 | interface DatePickerProps extends BasicProps { 11 | picker?: string; 12 | format?: string; //日期格式 默认 yyyy-MM-dd 13 | timestamp?: boolean; //是否获取时间戳 14 | } 15 | 16 | interface SelectProps extends BasicProps { 17 | mode: string; 18 | enum: any[]; 19 | } 20 | -------------------------------------------------------------------------------- /.svn/pristine/6a/6a9629cc3184c096bdc0cc75412cc6cfe56c9070.svn-base: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './index.css'; 3 | 4 | const BasicLayout: React.FC = props => { 5 | return
{props.children}
; 6 | }; 7 | 8 | export default BasicLayout; 9 | -------------------------------------------------------------------------------- /.svn/pristine/6d/6dcf794d90e5ef456a8702cb3346ec7565ee8af2.svn-base: -------------------------------------------------------------------------------- 1 | interface FMComponent { 2 | id?: string; 3 | name?: string; 4 | type?: string; 5 | } 6 | 7 | interface FMFieldList { 8 | componentId?: string; 9 | value?: string | number; 10 | } 11 | 12 | interface FormEntity { 13 | addUserId?: string; 14 | componentList?: FMComponent[]; 15 | name?: string; 16 | style?: string; 17 | remark?: string; 18 | } 19 | 20 | interface IPagenationParams { 21 | pageNum: number; 22 | pageSize: number; 23 | } 24 | 25 | interface FMFormData { 26 | addUserId?: string; 27 | fieldList?: FMFieldList[]; 28 | formId?: string; 29 | } 30 | -------------------------------------------------------------------------------- /.svn/pristine/79/79a608fcc4e5b345af7404964f700c3c559cb7ed.svn-base: -------------------------------------------------------------------------------- 1 | @import '~antd/es/style/themes/default.less'; 2 | 3 | .left { 4 | border: 1px solid @border-color-base; 5 | width: 460px; 6 | margin-right: 5px; 7 | overflow: auto; 8 | } 9 | 10 | .center { 11 | width: 100%; 12 | border: 1px solid @border-color-base; 13 | } 14 | 15 | .right { 16 | width: 480px; 17 | border: 1px solid @border-color-base; 18 | margin-left: 5px; 19 | overflow: auto; 20 | } 21 | 22 | .header { 23 | // color: hsla(0, 0%, 100%, 0.7); 24 | // background-color: #24292e; 25 | background-image: linear-gradient(90deg, #40a9ff, #e6f7ff); 26 | height: 46px; 27 | bottom: 1px solid @border-color-base; 28 | margin-bottom: 12px; 29 | color: whitesmoke; 30 | align-items: center; 31 | line-height: 46px; 32 | } 33 | -------------------------------------------------------------------------------- /.svn/pristine/7b/7b213d614d18458daca4a566cc3be87b2a0c1ca2.svn-base: -------------------------------------------------------------------------------- 1 | @import '~antd/es/style/themes/default.less'; 2 | 3 | .icon-drag { 4 | font-size: 14px; 5 | &::before { 6 | content: '\E842'; 7 | } 8 | } 9 | 10 | .container { 11 | width: 100%; 12 | margin-bottom: 2px; 13 | border: 1px dashed rgba(236, 245, 255, 0.3); 14 | position: relative; 15 | } 16 | 17 | .drag-view { 18 | position: absolute; 19 | height: 28px; 20 | width: 28px; 21 | left: 0px; 22 | top: 0px; 23 | background: @primary-color; 24 | line-height: 32px; 25 | text-align: center; 26 | } 27 | 28 | .action-view { 29 | position: absolute; 30 | right: 0; 31 | bottom: 0; 32 | background: @primary-color; 33 | height: 28px; 34 | width: 50px; 35 | line-height: 30px; 36 | cursor: pointer; 37 | } 38 | 39 | .contianer-active { 40 | width: 100%; 41 | margin-bottom: 2px; 42 | position: relative; 43 | border: 1px solid @primary-color !important; 44 | outline: 1px solid @primary-color; 45 | } 46 | -------------------------------------------------------------------------------- /.svn/pristine/7d/7d7ea6c476197a745d852601e143a5a55ad4801b.svn-base: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yzz421/form-making/c2343bada0f12abfa11bc9a2981a6b67717b93ad/.svn/pristine/7d/7d7ea6c476197a745d852601e143a5a55ad4801b.svn-base -------------------------------------------------------------------------------- /.svn/pristine/80/802829df81fefe4213bd3aef78400c976d8f98d8.svn-base: -------------------------------------------------------------------------------- 1 | @import '~antd/es/style/themes/default.less'; 2 | 3 | html, 4 | body, 5 | #root { 6 | height: 100%; 7 | } 8 | 9 | body { 10 | margin: 0; 11 | // text-rendering: optimizeLegibility; 12 | // -webkit-font-smoothing: antialiased; 13 | // -moz-osx-font-smoothing: grayscale; 14 | } 15 | -------------------------------------------------------------------------------- /.svn/pristine/88/8882b2e8af4a8ca8ba631e24679e9ff4fe3ac893.svn-base: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { observable, action, toJS, autorun } from 'mobx'; 3 | import uuid, { v4 as uuidv4 } from 'uuid'; 4 | import * as _ from 'lodash'; 5 | import * as formSv from '@/service/form'; 6 | import { message } from 'antd'; 7 | import { getGUID } from '@/utils/utils'; 8 | 9 | export interface MakerItemProps { 10 | label: string; 11 | required?: boolean; 12 | placeholder?: string; 13 | disabled?: boolean; 14 | default?: string | number; //默认值 15 | datePicker?: string; //时间选择器类型 16 | } 17 | 18 | interface Target { 19 | data?: any; 20 | index: number; 21 | } 22 | 23 | export class Maker { 24 | @observable FieldPropsList: any[] = []; 25 | @observable MakerItems: [] = []; 26 | @observable target: Target | undefined = undefined; 27 | 28 | @observable selected: any | undefined = undefined; 29 | 30 | @observable formId: string | undefined = undefined; 31 | 32 | constructor() {} 33 | 34 | @action 35 | resetFormId = (formId?: string) => { 36 | this.formId = formId; 37 | }; 38 | 39 | @action 40 | submitFormData = (data: { [key: string]: string }) => { 41 | const fieldList: FMFieldList[] = []; 42 | Object.keys(data).forEach(key => 43 | fieldList.push({ componentId: key, value: JSON.stringify(data[key]) }), 44 | ); 45 | console.log(fieldList); 46 | const formData: FMFormData = { 47 | addUserId: '123', 48 | fieldList, 49 | formId: this.formId, 50 | }; 51 | return formSv.submit(formData).then(this.resetFormId); 52 | }; 53 | 54 | @action 55 | appendItem(item: any) { 56 | item.fieldProps.name = getGUID(); 57 | this.FieldPropsList.push(item); 58 | } 59 | 60 | @action 61 | isCanAppend() { 62 | return this.target === undefined; 63 | } 64 | 65 | @action 66 | resetTarget(t: Target | undefined) { 67 | this.target = t; 68 | } 69 | 70 | @action 71 | resetMakerItems(makerItems: any[]) { 72 | this.FieldPropsList = makerItems; 73 | } 74 | 75 | @action 76 | deleteMakerItemById = (uuid: string) => { 77 | this.FieldPropsList = this.FieldPropsList.filter(({ fieldProps }) => fieldProps.name !== uuid); 78 | }; 79 | 80 | @action 81 | resetSelected = (item: any) => { 82 | this.selected = item; 83 | }; 84 | 85 | @action 86 | isSelected = (item: any) => { 87 | return this.selected?.name === item.name; 88 | }; 89 | 90 | @action 91 | mutePrpos = (props: MakerItemProps) => { 92 | if (!!this.selected) 93 | this.FieldPropsList = this.FieldPropsList.map(x => { 94 | if (x.fieldProps.name === this.selected?.fieldProps.name) { 95 | return { ...x, fieldProps: props }; 96 | } 97 | return x; 98 | }) as any; 99 | }; 100 | 101 | @action 102 | addCopy = () => { 103 | let clone = _.cloneDeep(this.selected); 104 | clone.fieldProps.name = uuidv4(); 105 | this.FieldPropsList.push(clone!); 106 | }; 107 | 108 | @action 109 | clear = () => { 110 | this.FieldPropsList = []; 111 | }; 112 | 113 | @action 114 | getSchema = () => { 115 | if (!!this.FieldPropsList && this.FieldPropsList.length === 0) { 116 | return undefined; 117 | } 118 | 119 | let result = { 120 | type: 'object', 121 | properties: {} as any, 122 | }; 123 | 124 | this.FieldPropsList.forEach( 125 | ({ fieldProps }) => (result.properties[fieldProps.name] = { ...fieldProps }), 126 | ); 127 | return result; 128 | }; 129 | 130 | @action 131 | getDndSchema = () => { 132 | if (!!this.FieldPropsList && this.FieldPropsList.length === 0) { 133 | return undefined; 134 | } 135 | 136 | let result = { 137 | type: 'object', 138 | properties: {} as any, 139 | }; 140 | 141 | return result; 142 | }; 143 | @action 144 | saveFormData = (name?: string) => { 145 | const componentList: FMComponent[] = this.FieldPropsList.map(({ fieldProps, type }) => ({ 146 | id: fieldProps.name, 147 | name: fieldProps.title, 148 | type: type, 149 | })); 150 | const formEntity: FormEntity = { 151 | addUserId: '123', 152 | componentList, 153 | name: name || getGUID(), 154 | style: JSON.stringify(this.FieldPropsList), 155 | remark: 'remark', 156 | }; 157 | 158 | return formSv.add(formEntity).then(() => message.success('成功')); 159 | }; 160 | } 161 | 162 | export const makerContext = React.createContext(null); 163 | -------------------------------------------------------------------------------- /.svn/pristine/8e/8e14f08020bb604422ba024cf75975227041f1a0.svn-base: -------------------------------------------------------------------------------- 1 | BROWSER=none 2 | ESLINT=1 3 | -------------------------------------------------------------------------------- /.svn/pristine/90/907489dd1e06e94a231338b228730829caf715d7.svn-base: -------------------------------------------------------------------------------- 1 | import 'jest'; 2 | import BasicLayout from '..'; 3 | import React from 'react'; 4 | import renderer, { ReactTestInstance, ReactTestRenderer } from 'react-test-renderer'; 5 | 6 | describe('Layout: BasicLayout', () => { 7 | it('Render correctly', () => { 8 | const wrapper: ReactTestRenderer = renderer.create(); 9 | expect(wrapper.root.children.length).toBe(1); 10 | const outerLayer = wrapper.root.children[0] as ReactTestInstance; 11 | expect(outerLayer.type).toBe('div'); 12 | const title = outerLayer.children[0] as ReactTestInstance; 13 | expect(title.type).toBe('h1'); 14 | expect(title.children[0]).toBe('Yay! Welcome to umi!'); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /.svn/pristine/90/90e7191fda5d313818b7365d2a2cee202be1e375.svn-base: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Row, Col, Divider, Button, Modal } from 'antd'; 3 | import { DndContext, DndProvider } from 'react-dnd'; 4 | import Backend from 'react-dnd-html5-backend'; 5 | import { SaveOutlined } from '@ant-design/icons'; 6 | import styles from './Layout.less'; 7 | import { makerContext } from '@/store/Maker'; 8 | import SchemaForm, { createAsyncFormActions, SchemaMarkupField as Field } from '@formily/antd'; 9 | 10 | interface Props { 11 | left: React.ReactNode; 12 | center: React.ReactNode; 13 | right: React.ReactNode; 14 | } 15 | 16 | const Layout: React.SFC = props => { 17 | const maker = React.useContext(makerContext)!; 18 | const { left, center, right } = props; 19 | const [visible, setVisible] = React.useState(false); 20 | const actions = React.useRef(createAsyncFormActions()).current; 21 | return ( 22 | 23 |
24 |
25 |

33 | 未命名表单 34 |

35 | 36 |
37 | 47 |
48 |
49 |
50 |
51 |
52 |
{left}
53 |
{center}
54 |
{right}
55 |
56 |
57 |
58 | ); 59 | }; 60 | 61 | export default Layout; 62 | -------------------------------------------------------------------------------- /.svn/pristine/9a/9a30f13cc711f93a0dcf09f07022ccec0dabd1bb.svn-base: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Widge from '../../../components/Widge'; 3 | import { Tabs, Button } from 'antd'; 4 | import { Widges } from '@/widge'; 5 | import { Draggable, DragDropContext } from 'react-beautiful-dnd'; 6 | 7 | interface Data { 8 | label: string; 9 | type: string; 10 | icon: string; 11 | } 12 | 13 | const { TabPane } = Tabs; 14 | 15 | const WidgeList = () => { 16 | return ( 17 |
18 | 19 | 20 | {Widges.map((x, index) => ( 21 | 22 | ))} 23 | 24 | 25 |
26 | ); 27 | }; 28 | 29 | export default WidgeList; 30 | -------------------------------------------------------------------------------- /.svn/pristine/9a/9a963983860f096eba01fd6ac4cd273a3bfb382f.svn-base: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './index.less'; 3 | import { useDrag } from 'react-dnd'; 4 | import { ItemTypes } from '@/contants'; 5 | import { makerContext } from '@/store/Maker'; 6 | import { Form } from '@ant-design/compatible'; 7 | import '@ant-design/compatible/assets/index.css'; 8 | import { Button } from 'antd'; 9 | import { MyIcon } from '@/contants'; 10 | import { Draggable, DragDropContext } from 'react-beautiful-dnd'; 11 | 12 | interface Props { 13 | type: string; 14 | label: string; 15 | icon: string; 16 | index?: number; 17 | data?: any; 18 | } 19 | 20 | const Widge: React.SFC = props => { 21 | const { label, type, icon, index, data } = props; 22 | const maker = React.useContext(makerContext)!; 23 | const [{ isDragging }, drag] = useDrag({ 24 | item: { type: type, fieldProps: data.fieldProps }, 25 | collect: monitor => ({ 26 | isDragging: !!monitor.isDragging(), 27 | }), 28 | }); 29 | 30 | return ( 31 |
32 |
  • 36 | 37 | 38 | 39 | {label} 40 | 41 |
  • 42 |
    43 | ); 44 | }; 45 | 46 | export default Widge; 47 | -------------------------------------------------------------------------------- /.svn/pristine/a6/a647d65fc56d06649218e84aa555fa74f6711c99.svn-base: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = ({ config }) => { 4 | config.module.rules.push({ 5 | test: /\.(ts|tsx)$/, 6 | use: [ 7 | { 8 | loader: require.resolve('awesome-typescript-loader'), 9 | }, 10 | ], 11 | }); 12 | config.module.rules.push({ 13 | test: /\.less$/, 14 | use: [ 15 | { 16 | loader: 'style-loader', // creates style nodes from JS strings 17 | }, 18 | { 19 | loader: 'css-loader', // translates CSS into CommonJS 20 | options: { 21 | modules: true, 22 | }, 23 | }, 24 | { 25 | loader: 'less-loader', // compiles Less to CSS 26 | options: { javascriptEnabled: true }, 27 | }, 28 | ], 29 | }); 30 | config.resolve.extensions.push('.ts', '.tsx'); 31 | 32 | return config; 33 | }; 34 | -------------------------------------------------------------------------------- /.svn/pristine/c1/c15d92a2cecc152a8e735428e425e20099c49d0f.svn-base: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Input, Button } from 'antd'; 3 | 4 | const Options = (props: any) => { 5 | const { value, onChange } = props; 6 | 7 | React.useEffect(() => { 8 | if (value) setDataSource(value); 9 | }, [value]); 10 | 11 | const [dataSource, setDataSource] = React.useState(value || []); 12 | 13 | const hanleAppendItem = () => { 14 | const text = 'option' + (dataSource.length + 1); 15 | setDataSource([...dataSource, { label: text, value: text }]); 16 | }; 17 | 18 | const handleOptionChange = (item: any, index: any) => { 19 | setDataSource(dataSource.map((i, idx) => (idx === index ? item : i))); 20 | }; 21 | 22 | const handelOptionDelete = (index: any) => { 23 | setDataSource(dataSource.filter((i, idx) => idx !== index)); 24 | }; 25 | 26 | React.useEffect(() => { 27 | onChange(dataSource); 28 | }, [dataSource, onChange]); 29 | 30 | const renderField = ({ value, label }: any, index: any) => { 31 | return ( 32 |
    33 | { 37 | handleOptionChange({ label: e.target.value, value }, index); 38 | }} 39 | value={label} 40 | style={{ width: '35%' }} 41 | > 42 | handleOptionChange({ label, value: e.target.value }, index)} 46 | value={value} 47 | style={{ width: '35%', marginLeft: 5 }} 48 | > 49 | 57 |
    58 | ); 59 | }; 60 | 61 | return ( 62 |
    63 | {dataSource.map((i, index) => renderField(i, index))} 64 |
    65 | 68 |
    69 |
    70 | ); 71 | }; 72 | 73 | export default Options; 74 | -------------------------------------------------------------------------------- /.svn/pristine/c8/c83b4030392bfa8aaf801abb09138cd484158fd5.svn-base: -------------------------------------------------------------------------------- 1 | **/*.md 2 | **/*.svg 3 | **/*.ejs 4 | **/*.html 5 | package.json 6 | .umi 7 | .umi-production 8 | -------------------------------------------------------------------------------- /.svn/pristine/d2/d21ae8b67971f49eb126cc1b05d2e419d10d6431.svn-base: -------------------------------------------------------------------------------- 1 | interface IWidge { 2 | icon: string; 3 | label: string; 4 | type: string; 5 | fieldProps: any; 6 | } 7 | -------------------------------------------------------------------------------- /.svn/pristine/d4/d4edb2d21e5c29ce5c645b1757077951b6a3b2dd.svn-base: -------------------------------------------------------------------------------- 1 | @import '~antd/es/style/themes/default.less'; 2 | 3 | .form-edit-widget-label { 4 | font-size: @font-size-base; 5 | overflow: hidden; 6 | text-overflow: ellipsis; 7 | white-space: nowrap; 8 | border: 1px solid #f4f6fc; 9 | 10 | line-height: 30px; 11 | background: hsl(192, 9%, 90%); 12 | list-style: none; 13 | 14 | height: 30px; 15 | 16 | a { 17 | color: rgba(0, 0, 0, 0.65); 18 | } 19 | &:hover { 20 | color: #409eff; 21 | a { 22 | color: #409eff; 23 | } 24 | border: 1px dashed #409eff; 25 | background: #f4f6fc; 26 | transition: border-width 0.6s linear; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.svn/pristine/d5/d5ecdc4208ac1c1797d04744e2832895c7f77d48.svn-base: -------------------------------------------------------------------------------- 1 | import { ItemTypes } from './contants'; 2 | import { getGUID } from './utils/utils'; 3 | 4 | export const Widges = [ 5 | { 6 | label: '单行文本', 7 | type: ItemTypes.INPUT, 8 | icon: 'anticoninput', 9 | fieldProps: { 10 | 'x-component': 'string', 11 | title: '单行文本', 12 | }, 13 | }, 14 | { 15 | label: '数字输入框', 16 | type: ItemTypes.INPUTNUMBER, 17 | icon: 'anticonfuhao-shuzishurukuang', 18 | fieldProps: { 19 | 'x-component': 'NumberPicker', 20 | title: '数字输入框', 21 | }, 22 | }, 23 | { 24 | label: '多行文本', 25 | type: ItemTypes.TEXTAREA, 26 | icon: 'anticontextareabt_back', 27 | uuid: getGUID(), 28 | fieldProps: { 29 | 'x-component': 'textarea', 30 | title: '多行文本', 31 | }, 32 | }, 33 | { 34 | label: '下拉选择器', 35 | type: ItemTypes.SELECT, 36 | icon: 'anticondrop-down', 37 | uuid: getGUID(), 38 | fieldProps: { 39 | 'x-component': 'string', 40 | title: '下拉选择器', 41 | enum: [{ label: 'option1', value: 'option1' }], 42 | }, 43 | }, 44 | { 45 | label: '日期选择器', 46 | type: ItemTypes.DATEPICKER, 47 | icon: 'anticonmdatepicker', 48 | uuid: getGUID(), 49 | fieldProps: { 50 | type: 'daterange', 51 | title: '日期选择器', 52 | picker: 'date', 53 | }, 54 | }, 55 | { 56 | label: '日期范围选择', 57 | type: ItemTypes.RANGPICKER, 58 | icon: 'anticonmdatepicker', 59 | uuid: getGUID(), 60 | fieldProps: { 61 | type: 'RangePicker', 62 | title: '日期范围选择器', 63 | picker: 'date', 64 | }, 65 | }, 66 | { 67 | label: '多选框', 68 | type: ItemTypes.CHECKBOX, 69 | icon: 'anticonduoxuankuang', 70 | uuid: getGUID(), 71 | fieldProps: { 72 | 'x-component': 'CheckboxGroup', 73 | title: '多选框', 74 | enum: [ 75 | { label: 'One', value: '1' }, 76 | { label: 'Two', value: '2' }, 77 | { label: 'Three', value: '3' }, 78 | { label: 'Four', value: '4' }, 79 | ], 80 | }, 81 | }, 82 | { 83 | label: '单选框', 84 | type: ItemTypes.RADIO, 85 | icon: 'anticondanxuankuangxuanzhong', 86 | uuid: getGUID(), 87 | fieldProps: { 88 | 'x-component': 'RadioGroup', 89 | title: '单选框', 90 | enum: [ 91 | { label: 'One', value: '1' }, 92 | { label: 'Two', value: '2' }, 93 | { label: 'Three', value: '3' }, 94 | { label: 'Four', value: '4' }, 95 | ], 96 | }, 97 | }, 98 | { 99 | label: '开关按钮', 100 | type: ItemTypes.SWITCH, 101 | icon: 'anticonkaiguananniu', 102 | uuid: getGUID(), 103 | fieldProps: { 104 | 'x-component': 'Switch', 105 | title: '开关按钮', 106 | }, 107 | }, 108 | ]; 109 | -------------------------------------------------------------------------------- /.svn/pristine/d8/d8eb3b98218af6f8243bfc1bd78ff3d243f6e714.svn-base: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [Makefile] 16 | indent_style = tab 17 | -------------------------------------------------------------------------------- /.svn/pristine/da/da39a3ee5e6b4b0d3255bfef95601890afd80709.svn-base: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yzz421/form-making/c2343bada0f12abfa11bc9a2981a6b67717b93ad/.svn/pristine/da/da39a3ee5e6b4b0d3255bfef95601890afd80709.svn-base -------------------------------------------------------------------------------- /.svn/pristine/e1/e190840dbaece0a76680d4e19f92a0c191045a05.svn-base: -------------------------------------------------------------------------------- 1 | import { configure } from '@storybook/react'; 2 | import 'antd/dist/antd.css'; 3 | 4 | function loadStories() { 5 | const req = require.context('../src', true, /\.stories\.tsx$/); 6 | req.keys().forEach(filename => req(filename)); 7 | } 8 | 9 | configure(loadStories, module); 10 | -------------------------------------------------------------------------------- /.svn/pristine/e8/e8a120dfe78d41632f9431bfb30b2fa11ced2527.svn-base: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all", 4 | "printWidth": 100, 5 | "overrides": [ 6 | { 7 | "files": ".prettierrc", 8 | "options": { "parser": "json" } 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.svn/pristine/ee/eeee6286abac22bb2941b77bb63bbf0f8eb53a98.svn-base: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useDrop } from 'react-dnd'; 3 | import { Accept } from '@/contants'; 4 | import { makerContext } from '@/store/Maker'; 5 | import { observer } from 'mobx-react-lite'; 6 | import update from 'immutability-helper'; 7 | import * as _ from 'lodash'; 8 | import styles from './index.less'; 9 | import * as formSv from '@/service/form'; 10 | import { 11 | DatePicker, 12 | Checkbox, 13 | Switch, 14 | NumberPicker, 15 | Radio, 16 | Input, 17 | Select, 18 | } from '@formily/antd-components'; 19 | import { DeleteOutlined, EyeOutlined, SmileOutlined } from '@ant-design/icons'; 20 | import { Button, Divider, Modal, Table } from 'antd'; 21 | import { 22 | SchemaMarkupField as Field, 23 | FormButtonGroup, 24 | Form, 25 | FormItem, 26 | Submit, 27 | registerFormFields, 28 | connect, 29 | } from '@formily/antd'; 30 | import { DndInput } from '@/components/formilyExtra/DndInput'; 31 | 32 | import DragWarpper from '@/components/DragWarpper'; 33 | import Options from '@/components/formilyExtra/Options'; 34 | import * as fdSv from '@/service/formData'; 35 | import { toJS } from 'mobx'; 36 | 37 | registerFormFields({ 38 | DndInput: connect()(DndInput), 39 | Options: connect()(Options), 40 | }); 41 | 42 | const { RangePicker } = DatePicker; 43 | 44 | const Components = { 45 | DndInput: Input, 46 | DndTextarea: Input.TextArea, 47 | DndSelect: Select, 48 | DndInputNumber: NumberPicker, 49 | DndDatePicker: DatePicker, 50 | DndCheckbox: Checkbox.Group, 51 | DndSwitch: Switch, 52 | DndRadio: Radio.Group, 53 | DndRangePicker: RangePicker, 54 | }; 55 | 56 | const FormBoard = () => { 57 | const maker = React.useContext(makerContext)!; 58 | 59 | const [{ isHover }, drop] = useDrop({ 60 | accept: Accept, 61 | canDrop: () => maker.isCanAppend(), 62 | collect: montior => ({ isHover: !!montior.isOver() }), 63 | drop: (item: any) => { 64 | if (item.index === undefined) { 65 | maker.appendItem(item); 66 | } 67 | }, 68 | }); 69 | 70 | const moveItem = React.useCallback( 71 | (dragIndex: number, hoverIndex) => { 72 | const dragItem = maker.FieldPropsList[dragIndex]; 73 | maker.resetMakerItems( 74 | update(maker.FieldPropsList, { 75 | $splice: [ 76 | [dragIndex, 1], 77 | [hoverIndex, 0, dragItem], 78 | ], 79 | }), 80 | ); 81 | }, 82 | [maker], 83 | ); 84 | 85 | const [visible, setVisible] = React.useState(false); 86 | const [flVisivle, setFlVisivle] = React.useState(false); 87 | const [formList, setFormList] = React.useState([]); 88 | const [fdlVisible, setFdlVisible] = React.useState(false); 89 | const [formDataList, setFormDataList] = React.useState([]); 90 | React.useEffect(() => { 91 | loadList(); 92 | }, []); 93 | 94 | React.useEffect(() => { 95 | if (maker.formId) { 96 | loadFdlist(); 97 | } 98 | }, [maker.formId]); 99 | 100 | const [column, setColumn] = React.useState([]); 101 | const loadFdlist = () => { 102 | fdSv.getPaged({ pageNum: 1, pageSize: 10, formId: maker.formId! }).then(res => { 103 | console.log(toJS(maker.FieldPropsList)); 104 | setColumn( 105 | maker.FieldPropsList.map(({ fieldProps }) => ({ 106 | dataIndex: fieldProps.name, 107 | title: fieldProps.title, 108 | })) as any, 109 | ); 110 | const ss = res.dataList.map(({ fieldList }: { fieldList: any[] }) => { 111 | let result = {} as any; 112 | fieldList.forEach(x => (result[x.componentId] = x.value)); 113 | return result; 114 | }); 115 | setFormDataList(ss); 116 | console.log(ss); 117 | }); 118 | }; 119 | 120 | const loadList = () => { 121 | formSv.getPaged({ pageNum: 1, pageSize: 10 }).then(res => setFormList(res.dataList)); 122 | }; 123 | return ( 124 |
    125 |
    126 | 135 | 138 | 146 | 154 |
    155 | 156 | 157 |
    158 |
    159 | {maker.FieldPropsList && 160 | maker.FieldPropsList.map(({ fieldProps, type }, index) => ( 161 | maker.addCopy()} 167 | onEnd={() => {}} 168 | onDelete={maker.deleteMakerItemById} 169 | moveItem={moveItem} 170 | widge={{ type, fieldProps }} 171 | data={fieldProps} 172 | > 173 | <>} 182 | > 183 | 184 | ))} 185 |
    186 |
    187 | { 195 | setVisible(false); 196 | }} 197 | > 198 |
    { 202 | maker.submitFormData(value); 203 | }} 204 | > 205 | <> 206 | {maker.FieldPropsList.map(({ fieldProps, type }) => ( 207 | <>} 215 | > 216 | ))} 217 | {maker.formId && ( 218 | 219 | 提交 220 | 221 | )} 222 | 223 |
    224 |
    225 | setFdlVisible(false)}> 226 |
    227 |
    228 | setFlVisivle(false)} 232 | title="表单列表" 233 | > 234 | { 240 | return ( 241 | <> 242 | 254 | 255 | 258 | 259 | ); 260 | }, 261 | }, 262 | ]} 263 | dataSource={formList} 264 | >
    265 |
    266 |
    267 | ); 268 | }; 269 | 270 | export default observer(FormBoard); 271 | -------------------------------------------------------------------------------- /.svn/pristine/f3/f3837a7219ace8679117e664c433110530a6ed6a.svn-base: -------------------------------------------------------------------------------- 1 | /** 2 | * request 网络请求工具 3 | * 更详细的 api 文档: https://github.com/umijs/umi-request 4 | */ 5 | import { extend, RequestOptionsInit } from 'umi-request'; 6 | import { notification } from 'antd'; 7 | import { router } from 'umi'; 8 | 9 | const codeMessage = { 10 | 200: '服务器成功返回请求的数据。', 11 | 201: '新建或修改数据成功。', 12 | // 201: '服务器错误', 13 | 202: '一个请求已经进入后台排队(异步任务)。', 14 | 204: '删除数据成功。', 15 | 400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。', 16 | 401: '用户没有权限(令牌、用户名、密码错误)。', 17 | 403: '用户得到授权,但是访问是被禁止的。', 18 | 404: '发出的请求针对的是不存在的记录,服务器没有进行操作。', 19 | 406: '请求的格式不可得。', 20 | 410: '请求的资源被永久删除,且不会再得到的。', 21 | 422: '当创建一个对象时,发生一个验证错误。', 22 | 500: '服务器发生错误,请检查服务器。', 23 | 502: '网关错误。', 24 | 503: '服务不可用,服务器暂时过载或维护。', 25 | 504: '网关超时。', 26 | }; 27 | 28 | /** 29 | * 异常处理程序 30 | */ 31 | const errorHandler = (error: { response: Response }): Response => { 32 | const { response } = error; 33 | if (response && response.status) { 34 | const errorText = (codeMessage as any)[response.status] || response.statusText; 35 | const { status, url } = response; 36 | notification.error({ 37 | message: `请求错误 ${status}: ${url}`, 38 | description: errorText, 39 | }); 40 | } 41 | return response; 42 | }; 43 | 44 | // export const prefix = 45 | // process.env.NODE_ENV === 'development' ? '' : 'http://47.104.131.14/digitcons/v1'; 46 | 47 | export const prefix = 'http://47.104.131.14/wisdomsite/v1'; 48 | // export const prefix = 'http://39.104.81.4/wisdomsite/v1' 49 | 50 | // export const prefix = 'http://www.lanlan.live:8085/wisdomsite/v1' 51 | /** 52 | * 配置request请求时的默认参数 53 | */ 54 | export const urequest = extend({ 55 | prefix: prefix, 56 | errorHandler, // 默认错误处理 57 | credentials: 'include', // 默认请求是否带上cookie 58 | }); 59 | 60 | export const request = (url: string, options?: RequestOptionsInit) => { 61 | return new Promise(async (resolve, reject) => { 62 | const res = await urequest(url, options); 63 | if (res === null) { 64 | reject('未知错误'); 65 | return; 66 | } 67 | const error = handleStatusError(res.status, url, res.message); 68 | 69 | if (error) reject(error); 70 | 71 | const boxingRes = boxingResponse(res); 72 | resolve(boxingRes); 73 | }).catch(error => { 74 | throw error; 75 | }); 76 | }; 77 | 78 | const handleStatusError = (status: number, url?: string, msg?: string): string | undefined => { 79 | const errorConfig = (BACKENDSTATUSERRORCONFIG as any)[status] || undefined; 80 | if (Array.isArray(errorConfig)) { 81 | const [defaultMsg, fn] = errorConfig; 82 | if (typeof fn === 'function') { 83 | fn(msg || defaultMsg, url); 84 | } 85 | return msg; 86 | } 87 | 88 | return errorConfig; 89 | }; 90 | 91 | const boxingResponse = (res: any) => { 92 | const data = res.data; 93 | if (data && data.pageTool) { 94 | const pageTool = data.pageTool; 95 | return { 96 | dataList: data.beanList || [], 97 | meta: { 98 | pageNum: pageTool.pageNum, 99 | pageSize: pageTool.pageTool, 100 | total: pageTool.totalSize, 101 | }, 102 | }; 103 | } 104 | return res; 105 | }; 106 | 107 | const BACKENDSTATUSERRORCONFIG = { 108 | 125: [ 109 | 'token error!', 110 | () => { 111 | router.push('/user/login'); 112 | }, 113 | ], 114 | 201: [ 115 | '后台服务器异常请查阅日志!', 116 | (errorText: string, url: string) => { 117 | notification.error({ 118 | message: `请求错误 ${status}: ${url}`, 119 | description: errorText, 120 | }); 121 | }, 122 | ], 123 | 116: [ 124 | '项目进度id不能为空', 125 | (errorText: string, url: string) => { 126 | notification.error({ 127 | message: `请求错误 ${status}: ${url}`, 128 | description: errorText, 129 | }); 130 | }, 131 | ], 132 | 121: [ 133 | '', 134 | (errorText: string, url: string) => { 135 | notification.error({ 136 | message: `请求错误 ${status}: ${url}`, 137 | description: errorText, 138 | }); 139 | }, 140 | ], 141 | 10: ['', ''], 142 | }; 143 | 144 | // 中间件,对请求前、响应后做处理 145 | urequest.use(async (ctx, next) => { 146 | const { req } = ctx; 147 | 148 | req.options.headers = { 149 | auth_token: 'd7dda732508242669ba1c1506935b1e8', 150 | }; 151 | 152 | await next(); 153 | const { res } = ctx; 154 | 155 | // if (process.env.NODE_ENV === 'development') { 156 | // console.log(`API: ${req.url.replace(prefix, '')} \r\n返回的数据: `, res.data, ' \r\n'); 157 | // console.log(`\r\n`); 158 | // } 159 | }); 160 | 161 | export default request; 162 | -------------------------------------------------------------------------------- /.svn/pristine/f9/f9048b6a960d338d940b094d183a825bfa34454f.svn-base: -------------------------------------------------------------------------------- 1 | import { IConfig } from 'umi-types'; 2 | 3 | // ref: https://umijs.org/config/ 4 | const config: IConfig = { 5 | treeShaking: true, 6 | routes: [ 7 | { 8 | path: '/', 9 | component: '../layouts/index', 10 | routes: [{ path: '/', component: '../pages/index' }], 11 | }, 12 | ], 13 | plugins: [ 14 | // ref: https://umijs.org/plugin/umi-plugin-react.html 15 | [ 16 | 'umi-plugin-react', 17 | { 18 | antd: true, 19 | dva: false, 20 | dynamicImport: false, 21 | title: 'form-making', 22 | dll: false, 23 | routes: { 24 | exclude: [/components\//], 25 | }, 26 | }, 27 | ], 28 | ], 29 | }; 30 | 31 | export default config; 32 | -------------------------------------------------------------------------------- /.svn/wc.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yzz421/form-making/c2343bada0f12abfa11bc9a2981a6b67717b93ad/.svn/wc.db -------------------------------------------------------------------------------- /.svn/wc.db-journal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yzz421/form-making/c2343bada0f12abfa11bc9a2981a6b67717b93ad/.svn/wc.db-journal -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - lts/* 4 | install: 5 | - yarn install 6 | sciprt: 7 | - yarn build 8 | deploy: 9 | provider: pages 10 | skip_cleanup: true 11 | local_dir: dist 12 | github_token: $GITHUB_TOKEN 13 | keep_history: true 14 | on: 15 | branch: master 16 | -------------------------------------------------------------------------------- /.umirc.ts: -------------------------------------------------------------------------------- 1 | // ref: https://umijs.org/config/ 2 | const config = { 3 | base: '/form-making/', 4 | publicPath: '/form-making/', 5 | routes: [ 6 | { 7 | path: '/', 8 | component: '../layouts/index', 9 | routes: [{ path: '/', component: '../pages/index' }], 10 | }, 11 | ], 12 | dva: {}, 13 | antd: {}, 14 | }; 15 | 16 | export default config; 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # form-making 2 | 3 | 简易表单编辑器 4 | 5 | ## 开始 6 | #### 1. 安装package依赖 7 | npm install 或者 yarn 8 | 9 | #### 2. 启动项目 10 | npm start 或者 yarn start 11 | 12 | -------------------------------------------------------------------------------- /mock/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yzz421/form-making/c2343bada0f12abfa11bc9a2981a6b67717b93ad/mock/.gitkeep -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "umi dev -p 3001", 5 | "build": "umi build", 6 | "test": "umi test", 7 | "lint": "eslint {src,mock,tests}/**/*.{ts,tsx} --fix", 8 | "precommit": "lint-staged", 9 | "storybook": "start-storybook -p 6006" 10 | }, 11 | "dependencies": { 12 | "@ant-design/compatible": "^0.0.1-rc.1", 13 | "@formily/antd": "^1.0.3", 14 | "@formily/antd-components": "^1.0.3", 15 | "@storybook/react": "^5.3.13", 16 | "@types/classnames": "^2.2.9", 17 | "@types/react-beautiful-dnd": "^12.1.1", 18 | "@types/react-transition-group": "^4.2.4", 19 | "@types/uuid": "^3.4.7", 20 | "antd": "^4.0.0", 21 | "awesome-typescript-loader": "^5.2.1", 22 | "babel-plugin-import": "^1.13.0", 23 | "classnames": "^2.2.6", 24 | "css-loader": "^3.4.2", 25 | "immutability-helper": "^3.0.1", 26 | "less": "^3.11.1", 27 | "less-loader": "^5.0.0", 28 | "lodash": "^4.17.15", 29 | "mobx": "^5.15.4", 30 | "mobx-react": "^6.1.8", 31 | "mobx-react-lite": "^1.5.2", 32 | "react": "^16.8.6", 33 | "react-beautiful-dnd": "^13.0.0", 34 | "react-dnd": "^10.0.2", 35 | "react-dnd-html5-backend": "^10.0.2", 36 | "react-dom": "^16.8.6", 37 | "react-transition-group": "^4.3.0", 38 | "style-loader": "^1.1.3", 39 | "styled-components": "^5.3.0", 40 | "umi-request": "^1.2.19", 41 | "uuid": "^7.0.0", 42 | "webpack-combine-loaders": "^2.0.4" 43 | }, 44 | "devDependencies": { 45 | "@types/jest": "^23.3.12", 46 | "@types/react": "^16.7.18", 47 | "@types/react-dom": "^16.0.11", 48 | "@types/react-test-renderer": "^16.0.3", 49 | "@umijs/preset-react": "^1", 50 | "babel-eslint": "^9.0.0", 51 | "eslint": "^5.4.0", 52 | "eslint-config-umi": "^1.4.0", 53 | "eslint-plugin-flowtype": "^2.50.0", 54 | "eslint-plugin-import": "^2.14.0", 55 | "eslint-plugin-jsx-a11y": "^5.1.1", 56 | "eslint-plugin-react": "^7.11.1", 57 | "husky": "^0.14.3", 58 | "lint-staged": "^7.2.2", 59 | "react-test-renderer": "^16.7.0", 60 | "umi": "^3", 61 | "umi-types": "^0.3.0" 62 | }, 63 | "lint-staged": { 64 | "*.{ts,tsx}": [ 65 | "eslint --fix", 66 | "git add" 67 | ], 68 | "*.{js,jsx}": [ 69 | "eslint --fix", 70 | "git add" 71 | ] 72 | }, 73 | "engines": { 74 | "node": ">=8.0.0" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/app.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ConfigProvider } from 'antd'; 3 | 4 | export function rootContainer(container: any) { 5 | return React.createElement(ConfigProvider, null, container); 6 | } 7 | -------------------------------------------------------------------------------- /src/assets/yay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yzz421/form-making/c2343bada0f12abfa11bc9a2981a6b67717b93ad/src/assets/yay.jpg -------------------------------------------------------------------------------- /src/components/DragWarpper/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/es/style/themes/default.less'; 2 | 3 | .icon-drag { 4 | font-size: 14px; 5 | &::before { 6 | content: '\E842'; 7 | } 8 | } 9 | 10 | .container { 11 | width: 100%; 12 | margin-bottom: 2px; 13 | border: 1px dashed rgba(236, 245, 255, 0.3); 14 | position: relative; 15 | } 16 | 17 | .drag-view { 18 | position: absolute; 19 | height: 28px; 20 | width: 28px; 21 | left: 0px; 22 | top: 0px; 23 | background: @primary-color; 24 | line-height: 32px; 25 | text-align: center; 26 | } 27 | 28 | .action-view { 29 | position: absolute; 30 | right: 0; 31 | bottom: 0; 32 | background: @primary-color; 33 | height: 28px; 34 | width: 50px; 35 | line-height: 30px; 36 | cursor: pointer; 37 | } 38 | 39 | .contianer-active { 40 | width: 100%; 41 | margin-bottom: 2px; 42 | position: relative; 43 | border: 1px solid @primary-color !important; 44 | outline: 1px solid @primary-color; 45 | } 46 | -------------------------------------------------------------------------------- /src/components/DragWarpper/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './index.less'; 3 | import '@ant-design/compatible/assets/index.css'; 4 | import { observer } from 'mobx-react-lite'; 5 | import { ItemTypes } from '@/contants'; 6 | import { useDrag, useDrop } from 'react-dnd'; 7 | 8 | const formItemLayout = { 9 | labelCol: { span: 4 }, 10 | wrapperCol: { span: 12 }, 11 | }; 12 | 13 | export interface FBProps { 14 | onSelected: (item: any) => void; 15 | onDelete: (uuid: string) => void; 16 | data: any; 17 | selected: any | undefined; 18 | index: number; 19 | onEnd: () => void; 20 | moveItem: (dragIndex: number, hoverIndex: number) => void; 21 | onAddCopy: () => void; 22 | widge: any; 23 | } 24 | 25 | const DragWarpper: React.SFC = props => { 26 | const { 27 | selected, 28 | onSelected, 29 | data, 30 | onDelete, 31 | widge, 32 | index, 33 | onEnd, 34 | moveItem, 35 | onAddCopy, 36 | children, 37 | } = props; 38 | 39 | const isCurrent = selected && selected.fieldProps && selected.fieldProps.name === data.name; 40 | 41 | const ref = React.useRef(null); 42 | 43 | const [{ isDragging }, drag] = useDrag({ 44 | item: { type: ItemTypes.INPUT, index: index }, 45 | end: () => onEnd(), 46 | collect: monitor => ({ 47 | isDragging: monitor.isDragging(), 48 | }), 49 | }); 50 | 51 | const [{ isHover }, drop] = useDrop({ 52 | accept: ItemTypes.INPUT, 53 | hover: (item: any, monitor) => { 54 | if (!ref.current) { 55 | return; 56 | } 57 | 58 | const dragIndex = item.index; 59 | 60 | //drop new here 61 | if (dragIndex === undefined) { 62 | // maker.appendItem({ uuid: '', currentIndex: maker.MakerItems.length }); 63 | return; 64 | } 65 | 66 | const hoverIndex = index!; 67 | 68 | if (hoverIndex === undefined) return; 69 | if (dragIndex === hoverIndex) { 70 | return; 71 | } 72 | // Determine rectangle on screen 73 | const hoverBoundingRect = (ref!.current as any).getBoundingClientRect(); 74 | // Get vertical middle 75 | const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; 76 | // Determine mouse position 77 | const clientOffset = monitor.getClientOffset()!; 78 | // Get pixels to the top 79 | const hoverClientY = clientOffset.y - hoverBoundingRect.top; 80 | // Only perform the move when the mouse has crossed half of the items height 81 | // When dragging downwards, only move when the cursor is below 50% 82 | // When dragging upwards, only move when the cursor is above 50% 83 | // Dragging downwards 84 | if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { 85 | return; 86 | } 87 | // Dragging upwards 88 | if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { 89 | return; 90 | } 91 | // Time to actually perform the action 92 | moveItem(dragIndex, hoverIndex); 93 | // Note: we're mutating the monitor item here! 94 | // Generally it's better to avoid mutations, 95 | // but it's good here for the sake of performance 96 | // to avoid expensive index searches. 97 | item.index = hoverIndex; 98 | }, 99 | drop: (item: any) => { 100 | const dragIndex = item.index; 101 | // if (dragIndex === undefined) { 102 | // maker.appendItem(item.type); 103 | // } 104 | }, 105 | collect: montitor => ({ 106 | isHover: !!montitor.isOver(), 107 | }), 108 | }); 109 | 110 | drag(drop(ref)); 111 | 112 | const renderDragIcon = () => { 113 | return ( 114 | 123 | 128 | 129 | ); 130 | }; 131 | 132 | const renderActions = () => { 133 | return ( 134 | <> 135 | { 144 | onAddCopy(); 145 | }} 146 | > 147 | 152 | 153 | onDelete(data.name!)} 155 | style={{ marginLeft: 5 }} 156 | viewBox="0 0 1030 1024" 157 | version="1.1" 158 | xmlns="http://www.w3.org/2000/svg" 159 | p-id="3253" 160 | width="14" 161 | height="14" 162 | > 163 | 168 | 169 | 170 | ); 171 | }; 172 | 173 | const containerStyles = isCurrent ? styles['contianer-active'] : styles.container; 174 | const opacity = isDragging ? 0 : 1; 175 | return ( 176 |
    onSelected(widge)} 180 | ref={ref} 181 | > 182 | {children} 183 | {isCurrent && ( 184 | <> 185 |
    {renderDragIcon()}
    186 |
    187 | {renderActions()} 188 |
    189 | 190 | )} 191 |
    192 | ); 193 | }; 194 | 195 | export default observer(DragWarpper); 196 | -------------------------------------------------------------------------------- /src/components/Widge/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/es/style/themes/default.less'; 2 | 3 | .form-edit-widget-label { 4 | font-size: @font-size-base; 5 | overflow: hidden; 6 | text-overflow: ellipsis; 7 | white-space: nowrap; 8 | border: 1px solid #f4f6fc; 9 | 10 | line-height: 30px; 11 | background: hsl(192, 9%, 90%); 12 | list-style: none; 13 | 14 | height: 30px; 15 | 16 | a { 17 | color: rgba(0, 0, 0, 0.65); 18 | } 19 | &:hover { 20 | color: #409eff; 21 | a { 22 | color: #409eff; 23 | } 24 | border: 1px dashed #409eff; 25 | background: #f4f6fc; 26 | transition: border-width 0.6s linear; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/components/Widge/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './index.less'; 3 | import { useDrag } from 'react-dnd'; 4 | import { ItemTypes } from '@/contants'; 5 | import { makerContext } from '@/store/Maker'; 6 | import { Form } from '@ant-design/compatible'; 7 | import '@ant-design/compatible/assets/index.css'; 8 | import { Button } from 'antd'; 9 | import { MyIcon } from '@/contants'; 10 | import { Draggable, DragDropContext } from 'react-beautiful-dnd'; 11 | 12 | interface Props { 13 | type: string; 14 | label: string; 15 | icon: string; 16 | index?: number; 17 | data?: any; 18 | } 19 | 20 | const Widge: React.SFC = props => { 21 | const { label, type, icon, index, data } = props; 22 | const maker = React.useContext(makerContext)!; 23 | const [{ isDragging }, drag] = useDrag({ 24 | item: { type: type, fieldProps: data.fieldProps }, 25 | collect: monitor => ({ 26 | isDragging: !!monitor.isDragging(), 27 | }), 28 | }); 29 | 30 | return ( 31 |
    32 |
  • 36 | 37 | 38 | 39 | {label} 40 | 41 |
  • 42 |
    43 | ); 44 | }; 45 | 46 | export default Widge; 47 | -------------------------------------------------------------------------------- /src/components/formilyExtra/DndInput.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Input } from 'antd'; 3 | import DragWarpper from '../DragWarpper'; 4 | 5 | export const DndInput = (props: any) => { 6 | console.log(props); 7 | const { placeholder, required } = props; 8 | return ; 9 | }; 10 | -------------------------------------------------------------------------------- /src/components/formilyExtra/Options/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Input, Button } from 'antd'; 3 | 4 | const Options = (props: any) => { 5 | const { value, onChange } = props; 6 | 7 | React.useEffect(() => { 8 | if (value) setDataSource(value); 9 | }, [value]); 10 | 11 | const [dataSource, setDataSource] = React.useState(value || []); 12 | 13 | const hanleAppendItem = () => { 14 | const text = 'option' + (dataSource.length + 1); 15 | setDataSource([...dataSource, { label: text, value: text }]); 16 | }; 17 | 18 | const handleOptionChange = (item: any, index: any) => { 19 | setDataSource(dataSource.map((i, idx) => (idx === index ? item : i))); 20 | }; 21 | 22 | const handelOptionDelete = (index: any) => { 23 | setDataSource(dataSource.filter((i, idx) => idx !== index)); 24 | }; 25 | 26 | React.useEffect(() => { 27 | onChange(dataSource); 28 | }, [dataSource, onChange]); 29 | 30 | const renderField = ({ value, label }: any, index: any) => { 31 | return ( 32 |
    33 | { 37 | handleOptionChange({ label: e.target.value, value }, index); 38 | }} 39 | value={label} 40 | style={{ width: '35%' }} 41 | > 42 | handleOptionChange({ label, value: e.target.value }, index)} 46 | value={value} 47 | style={{ width: '35%', marginLeft: 5 }} 48 | > 49 | 57 |
    58 | ); 59 | }; 60 | 61 | return ( 62 |
    63 | {dataSource.map((i, index) => renderField(i, index))} 64 |
    65 | 68 |
    69 |
    70 | ); 71 | }; 72 | 73 | export default Options; 74 | -------------------------------------------------------------------------------- /src/contants.ts: -------------------------------------------------------------------------------- 1 | import { createFromIconfontCN } from '@ant-design/icons'; 2 | 3 | export const ItemTypes = { 4 | INPUT: 'DndInput', 5 | TEXTAREA: 'DndTextarea', 6 | SELECT: 'DndSelect', 7 | DATEPICKER: 'DndDatePicker', 8 | INPUTNUMBER: 'DndInputNumber', 9 | CHECKBOX: 'DndCheckbox', 10 | RADIO: 'DndRadio', 11 | SWITCH: 'DndSwitch', 12 | RANGPICKER: 'DndRangePicker', 13 | }; 14 | 15 | export const Accept = [ 16 | ItemTypes.INPUT, 17 | ItemTypes.TEXTAREA, 18 | ItemTypes.SELECT, 19 | ItemTypes.DATEPICKER, 20 | ItemTypes.INPUTNUMBER, 21 | ItemTypes.CHECKBOX, 22 | ItemTypes.RADIO, 23 | ItemTypes.SWITCH, 24 | ItemTypes.RANGPICKER, 25 | ]; 26 | 27 | export const MyIcon = createFromIconfontCN({ 28 | scriptUrl: '//at.alicdn.com/t/font_1660311_lyo1k8r276.js', 29 | }); 30 | -------------------------------------------------------------------------------- /src/global.less: -------------------------------------------------------------------------------- 1 | @import '~antd/es/style/themes/default.less'; 2 | 3 | html, 4 | body, 5 | #root { 6 | height: 100%; 7 | } 8 | 9 | body { 10 | margin: 0; 11 | // text-rendering: optimizeLegibility; 12 | // -webkit-font-smoothing: antialiased; 13 | // -moz-osx-font-smoothing: grayscale; 14 | } 15 | -------------------------------------------------------------------------------- /src/index.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button } from '@storybook/react/demo'; 3 | 4 | export default { title: 'Button' }; 5 | 6 | export const withText = () => ; 7 | 8 | export const withEmoji = () => ( 9 | 14 | ); 15 | -------------------------------------------------------------------------------- /src/layouts/__tests__/index.test.tsx: -------------------------------------------------------------------------------- 1 | import 'jest'; 2 | import BasicLayout from '..'; 3 | import React from 'react'; 4 | import renderer, { ReactTestInstance, ReactTestRenderer } from 'react-test-renderer'; 5 | 6 | describe('Layout: BasicLayout', () => { 7 | it('Render correctly', () => { 8 | const wrapper: ReactTestRenderer = renderer.create(); 9 | expect(wrapper.root.children.length).toBe(1); 10 | const outerLayer = wrapper.root.children[0] as ReactTestInstance; 11 | expect(outerLayer.type).toBe('div'); 12 | const title = outerLayer.children[0] as ReactTestInstance; 13 | expect(title.type).toBe('h1'); 14 | expect(title.children[0]).toBe('Yay! Welcome to umi!'); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/layouts/index.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yzz421/form-making/c2343bada0f12abfa11bc9a2981a6b67717b93ad/src/layouts/index.css -------------------------------------------------------------------------------- /src/layouts/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const BasicLayout: React.FC = props => { 4 | return
    {props.children}
    ; 5 | }; 6 | 7 | export default BasicLayout; 8 | -------------------------------------------------------------------------------- /src/pages/__tests__/index.test.tsx: -------------------------------------------------------------------------------- 1 | import 'jest'; 2 | import Index from '..'; 3 | import React from 'react'; 4 | import renderer, { ReactTestInstance, ReactTestRenderer } from 'react-test-renderer'; 5 | 6 | 7 | describe('Page: index', () => { 8 | it('Render correctly', () => { 9 | const wrapper: ReactTestRenderer = renderer.create(); 10 | expect(wrapper.root.children.length).toBe(1); 11 | const outerLayer = wrapper.root.children[0] as ReactTestInstance; 12 | expect(outerLayer.type).toBe('div'); 13 | expect(outerLayer.children.length).toBe(2); 14 | 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/pages/dictionary.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yzz421/form-making/c2343bada0f12abfa11bc9a2981a6b67717b93ad/src/pages/dictionary.ts -------------------------------------------------------------------------------- /src/pages/index.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yzz421/form-making/c2343bada0f12abfa11bc9a2981a6b67717b93ad/src/pages/index.css -------------------------------------------------------------------------------- /src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Layout from './layouts/Layout'; 3 | import Board from './layouts/Board'; 4 | import WidgeList from './layouts/WidgeList'; 5 | import { makerContext, Maker } from '@/store/Maker'; 6 | import 'antd/dist/antd.css'; 7 | import ConfigBlock from './layouts/FieldConfig'; 8 | import { ConfigProvider } from 'antd'; 9 | import zhCN from 'antd/es/locale/zh_CN'; 10 | 11 | export default function() { 12 | const store = React.useRef(new Maker()).current; 13 | 14 | return ( 15 | 16 | 17 | } 19 | left={} 20 | center={} 21 | > 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /src/pages/layouts/Board/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/es/style/themes/default.less'; 2 | 3 | .container { 4 | padding: 10px 10px; 5 | overflow: auto; 6 | .board { 7 | border: 1px dashed rgba(236, 245, 255, 0.3); 8 | height: 79vh; 9 | overflow: auto; 10 | padding: 2px; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/pages/layouts/Board/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useDrop } from 'react-dnd'; 3 | import { Accept } from '@/contants'; 4 | import { makerContext } from '@/store/Maker'; 5 | import { observer } from 'mobx-react-lite'; 6 | import update from 'immutability-helper'; 7 | import * as _ from 'lodash'; 8 | import styles from './index.less'; 9 | import * as formSv from '@/service/form'; 10 | import { 11 | DatePicker, 12 | Checkbox, 13 | Switch, 14 | NumberPicker, 15 | Radio, 16 | Input, 17 | Select, 18 | } from '@formily/antd-components'; 19 | import { DeleteOutlined, EyeOutlined, SmileOutlined } from '@ant-design/icons'; 20 | import { Button, Divider, Modal, Table } from 'antd'; 21 | import { 22 | SchemaMarkupField as Field, 23 | FormButtonGroup, 24 | Form, 25 | FormItem, 26 | Submit, 27 | registerFormFields, 28 | connect, 29 | } from '@formily/antd'; 30 | import { DndInput } from '@/components/formilyExtra/DndInput'; 31 | 32 | import DragWarpper from '@/components/DragWarpper'; 33 | import Options from '@/components/formilyExtra/Options'; 34 | import * as fdSv from '@/service/formData'; 35 | import { toJS } from 'mobx'; 36 | 37 | registerFormFields({ 38 | DndInput: connect()(DndInput), 39 | Options: connect()(Options), 40 | }); 41 | 42 | const { RangePicker } = DatePicker; 43 | 44 | const Components = { 45 | DndInput: Input, 46 | DndTextarea: Input.TextArea, 47 | DndSelect: Select, 48 | DndInputNumber: NumberPicker, 49 | DndDatePicker: DatePicker, 50 | DndCheckbox: Checkbox.Group, 51 | DndSwitch: Switch, 52 | DndRadio: Radio.Group, 53 | DndRangePicker: RangePicker, 54 | }; 55 | 56 | const FormBoard = () => { 57 | const maker = React.useContext(makerContext)!; 58 | 59 | const [{ isHover }, drop] = useDrop({ 60 | accept: Accept, 61 | canDrop: () => maker.isCanAppend(), 62 | collect: montior => ({ isHover: !!montior.isOver() }), 63 | drop: (item: any) => { 64 | if (item.index === undefined) { 65 | maker.appendItem(item); 66 | } 67 | }, 68 | }); 69 | 70 | const moveItem = React.useCallback( 71 | (dragIndex: number, hoverIndex) => { 72 | const dragItem = maker.FieldPropsList[dragIndex]; 73 | maker.resetMakerItems( 74 | update(maker.FieldPropsList, { 75 | $splice: [ 76 | [dragIndex, 1], 77 | [hoverIndex, 0, dragItem], 78 | ], 79 | }), 80 | ); 81 | }, 82 | [maker], 83 | ); 84 | 85 | const [visible, setVisible] = React.useState(false); 86 | const [flVisivle, setFlVisivle] = React.useState(false); 87 | const [formList, setFormList] = React.useState([]); 88 | const [fdlVisible, setFdlVisible] = React.useState(false); 89 | const [formDataList, setFormDataList] = React.useState([]); 90 | React.useEffect(() => { 91 | loadList(); 92 | }, []); 93 | 94 | React.useEffect(() => { 95 | if (maker.formId) { 96 | loadFdlist(); 97 | } 98 | }, [maker.formId]); 99 | 100 | const [column, setColumn] = React.useState([]); 101 | const loadFdlist = () => { 102 | fdSv.getPaged({ pageNum: 1, pageSize: 10, formId: maker.formId! }).then(res => { 103 | console.log(toJS(maker.FieldPropsList)); 104 | setColumn( 105 | maker.FieldPropsList.map(({ fieldProps }) => ({ 106 | dataIndex: fieldProps.name, 107 | title: fieldProps.title, 108 | })) as any, 109 | ); 110 | const ss = res.dataList.map(({ fieldList }: { fieldList: any[] }) => { 111 | let result = {} as any; 112 | fieldList.forEach(x => (result[x.componentId] = x.value)); 113 | return result; 114 | }); 115 | setFormDataList(ss); 116 | console.log(ss); 117 | }); 118 | }; 119 | 120 | const loadList = () => { 121 | formSv.getPaged({ pageNum: 1, pageSize: 10 }).then(res => setFormList(res.dataList)); 122 | }; 123 | return ( 124 |
    125 |
    126 | 135 | 138 | 146 | 154 |
    155 | 156 | 157 |
    158 |
    159 | {maker.FieldPropsList && 160 | maker.FieldPropsList.map(({ fieldProps, type }, index) => ( 161 | maker.addCopy()} 167 | onEnd={() => {}} 168 | onDelete={maker.deleteMakerItemById} 169 | moveItem={moveItem} 170 | widge={{ type, fieldProps }} 171 | data={fieldProps} 172 | > 173 | <>} 182 | > 183 | 184 | ))} 185 |
    186 |
    187 | { 195 | setVisible(false); 196 | }} 197 | > 198 |
    { 202 | maker.submitFormData(value); 203 | }} 204 | > 205 | <> 206 | {maker.FieldPropsList.map(({ fieldProps, type }) => ( 207 | <>} 215 | > 216 | ))} 217 | {maker.formId && ( 218 | 219 | 提交 220 | 221 | )} 222 | 223 |
    224 |
    225 | setFdlVisible(false)}> 226 |
    227 |
    228 | setFlVisivle(false)} 232 | title="表单列表" 233 | > 234 | { 240 | return ( 241 | <> 242 | 254 | 255 | 258 | 259 | ); 260 | }, 261 | }, 262 | ]} 263 | dataSource={formList} 264 | >
    265 |
    266 |
    267 | ); 268 | }; 269 | 270 | export default observer(FormBoard); 271 | -------------------------------------------------------------------------------- /src/pages/layouts/FieldConfig/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Form } from '@ant-design/compatible'; 3 | import '@ant-design/compatible/assets/index.css'; 4 | import { Tabs, Checkbox } from 'antd'; 5 | import { 6 | SchemaForm, 7 | SchemaMarkupField as Field, 8 | createAsyncFormActions, 9 | FormSlot, 10 | } from '@formily/antd'; 11 | import { setup } from '@formily/antd-components'; 12 | import { Switch } from '@formily/antd-components'; 13 | import Options from '@/components/formilyExtra/Options'; 14 | import { MakerItemProps, Maker, makerContext } from '@/store/Maker'; 15 | import { toJS } from 'mobx'; 16 | import { observer } from 'mobx-react-lite'; 17 | import * as configSchema from '@/schemajson'; 18 | import { ItemTypes } from '@/contants'; 19 | 20 | setup(); 21 | 22 | const { TabPane } = Tabs; 23 | const ConfigBlock = () => { 24 | const maker = React.useContext(makerContext)!; 25 | 26 | React.useEffect(() => { 27 | console.log(toJS(maker.selected)); 28 | if (!!maker.selected) { 29 | actions.setFormState(state => { 30 | state.values = toJS(maker.selected?.fieldProps!); 31 | }); 32 | } 33 | }, [maker.selected]); 34 | 35 | const actions = React.useRef(createAsyncFormActions()).current; 36 | 37 | const selected = maker.selected; 38 | 39 | const type = selected?.type; 40 | 41 | const getSchema = (type: string) => { 42 | if (!!type) { 43 | return (configSchema as any)[type]; 44 | } 45 | return undefined; 46 | }; 47 | 48 | const [value, setValue] = React.useState({}); 49 | 50 | return ( 51 |
    52 | 53 | 54 | { 61 | maker.mutePrpos(value); 62 | }} 63 | > 64 | 65 | 66 |
    67 | ); 68 | }; 69 | 70 | export default observer(ConfigBlock); 71 | -------------------------------------------------------------------------------- /src/pages/layouts/Layout.less: -------------------------------------------------------------------------------- 1 | @import '~antd/es/style/themes/default.less'; 2 | 3 | .left { 4 | border: 1px solid @border-color-base; 5 | width: 460px; 6 | margin-right: 5px; 7 | overflow: auto; 8 | } 9 | 10 | .center { 11 | width: 100%; 12 | border: 1px solid @border-color-base; 13 | } 14 | 15 | .right { 16 | width: 480px; 17 | border: 1px solid @border-color-base; 18 | margin-left: 5px; 19 | overflow: auto; 20 | } 21 | 22 | .header { 23 | // color: hsla(0, 0%, 100%, 0.7); 24 | // background-color: #24292e; 25 | background-image: linear-gradient(90deg, #40a9ff, #e6f7ff); 26 | height: 46px; 27 | bottom: 1px solid @border-color-base; 28 | margin-bottom: 12px; 29 | color: whitesmoke; 30 | align-items: center; 31 | line-height: 46px; 32 | } 33 | -------------------------------------------------------------------------------- /src/pages/layouts/Layout.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Row, Col, Divider, Button, Modal } from 'antd'; 3 | import { DndContext, DndProvider } from 'react-dnd'; 4 | import Backend from 'react-dnd-html5-backend'; 5 | import { SaveOutlined } from '@ant-design/icons'; 6 | import styles from './Layout.less'; 7 | import { makerContext } from '@/store/Maker'; 8 | import SchemaForm, { createAsyncFormActions, SchemaMarkupField as Field } from '@formily/antd'; 9 | 10 | interface Props { 11 | left: React.ReactNode; 12 | center: React.ReactNode; 13 | right: React.ReactNode; 14 | } 15 | 16 | const Layout: React.SFC = props => { 17 | const maker = React.useContext(makerContext)!; 18 | const { left, center, right } = props; 19 | const [visible, setVisible] = React.useState(false); 20 | const actions = React.useRef(createAsyncFormActions()).current; 21 | return ( 22 | 23 |
    24 |
    25 |

    33 | 未命名表单 34 |

    35 | 36 |
    37 | 47 |
    48 |
    49 |
    50 |
    51 |
    52 |
    {left}
    53 |
    {center}
    54 |
    {right}
    55 |
    56 |
    57 |
    58 | ); 59 | }; 60 | 61 | export default Layout; 62 | -------------------------------------------------------------------------------- /src/pages/layouts/WidgeList/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Widge from '../../../components/Widge'; 3 | import { Tabs, Button } from 'antd'; 4 | import { Widges } from '@/widge'; 5 | import { Draggable, DragDropContext } from 'react-beautiful-dnd'; 6 | 7 | interface Data { 8 | label: string; 9 | type: string; 10 | icon: string; 11 | } 12 | 13 | const { TabPane } = Tabs; 14 | 15 | const WidgeList = () => { 16 | return ( 17 |
    18 | 19 | 20 | {Widges.map((x, index) => ( 21 | 22 | ))} 23 | 24 | 25 |
    26 | ); 27 | }; 28 | 29 | export default WidgeList; 30 | -------------------------------------------------------------------------------- /src/schemajson.ts: -------------------------------------------------------------------------------- 1 | export const BASE = { 2 | type: 'object', 3 | properties: { 4 | title: { 5 | title: '标题', 6 | type: 'string', 7 | }, 8 | placeholder: { 9 | title: '占位内容', 10 | type: 'string', 11 | }, 12 | require: { 13 | title: '必填', 14 | type: 'Switch', 15 | }, 16 | disabled: { 17 | title: '禁用', 18 | type: 'Switch', 19 | }, 20 | }, 21 | }; 22 | 23 | export const DndInput = { 24 | type: 'object', 25 | properties: { 26 | title: { 27 | title: '标题', 28 | type: 'string', 29 | }, 30 | placeholder: { 31 | title: '占位内容', 32 | type: 'string', 33 | }, 34 | required: { 35 | title: '必填', 36 | type: 'Switch', 37 | }, 38 | disabled: { 39 | title: '禁用', 40 | type: 'Switch', 41 | }, 42 | }, 43 | }; 44 | 45 | export const DndDatePicker = { 46 | type: 'object', 47 | properties: { 48 | title: { 49 | title: '标题', 50 | type: 'string', 51 | }, 52 | placeholder: { 53 | title: '占位内容', 54 | type: 'string', 55 | }, 56 | required: { 57 | title: '必填', 58 | type: 'Switch', 59 | }, 60 | disabled: { 61 | title: '禁用', 62 | type: 'Switch', 63 | }, 64 | }, 65 | }; 66 | 67 | export const DndInputNumber = { 68 | type: 'object', 69 | properties: { 70 | title: { 71 | title: '标题', 72 | type: 'string', 73 | }, 74 | placeholder: { 75 | title: '占位内容', 76 | type: 'string', 77 | }, 78 | required: { 79 | title: '必填', 80 | type: 'Switch', 81 | }, 82 | disabled: { 83 | title: '禁用', 84 | type: 'Switch', 85 | }, 86 | }, 87 | }; 88 | 89 | export const DndTextarea = { 90 | type: 'object', 91 | properties: { 92 | title: { 93 | title: '标题', 94 | type: 'string', 95 | }, 96 | placeholder: { 97 | title: '占位内容', 98 | type: 'string', 99 | }, 100 | required: { 101 | title: '必填', 102 | type: 'Switch', 103 | }, 104 | disabled: { 105 | title: '禁用', 106 | type: 'Switch', 107 | }, 108 | }, 109 | }; 110 | 111 | export const DndSelect = { 112 | type: 'object', 113 | properties: { 114 | title: { 115 | title: '标题', 116 | type: 'string', 117 | }, 118 | placeholder: { 119 | title: '占位内容', 120 | type: 'string', 121 | }, 122 | required: { 123 | title: '必填', 124 | type: 'Switch', 125 | }, 126 | disabled: { 127 | title: '禁用', 128 | type: 'Switch', 129 | }, 130 | enum: { 131 | title: '简单数据', 132 | type: 'Options', 133 | }, 134 | }, 135 | }; 136 | 137 | export const DndCheckbox = { 138 | type: 'object', 139 | properties: { 140 | title: { 141 | title: '标题', 142 | type: 'string', 143 | }, 144 | placeholder: { 145 | title: '占位内容', 146 | type: 'string', 147 | }, 148 | required: { 149 | title: '必填', 150 | type: 'Switch', 151 | }, 152 | disabled: { 153 | title: '禁用', 154 | type: 'Switch', 155 | }, 156 | enum: { 157 | title: '简单数据', 158 | type: 'Options', 159 | }, 160 | }, 161 | }; 162 | 163 | export const DndRadio = { 164 | type: 'object', 165 | properties: { 166 | title: { 167 | title: '标题', 168 | type: 'string', 169 | }, 170 | placeholder: { 171 | title: '占位内容', 172 | type: 'string', 173 | }, 174 | required: { 175 | title: '必填', 176 | type: 'Switch', 177 | }, 178 | disabled: { 179 | title: '禁用', 180 | type: 'Switch', 181 | }, 182 | enum: { 183 | title: '简单数据', 184 | type: 'Options', 185 | }, 186 | }, 187 | }; 188 | 189 | export const DndSwitch = { 190 | type: 'object', 191 | properties: { 192 | title: { 193 | title: '标题', 194 | type: 'string', 195 | }, 196 | required: { 197 | title: '必填', 198 | type: 'Switch', 199 | }, 200 | disabled: { 201 | title: '禁用', 202 | type: 'Switch', 203 | }, 204 | }, 205 | }; 206 | 207 | export const DndRangePicker = { 208 | type: 'object', 209 | properties: { 210 | title: { 211 | title: '标题', 212 | type: 'string', 213 | }, 214 | required: { 215 | title: '必填', 216 | type: 'Switch', 217 | }, 218 | disabled: { 219 | title: '禁用', 220 | type: 'Switch', 221 | }, 222 | }, 223 | }; 224 | -------------------------------------------------------------------------------- /src/service/data.d.ts: -------------------------------------------------------------------------------- 1 | interface FMComponent { 2 | id?: string; 3 | name?: string; 4 | type?: string; 5 | } 6 | 7 | interface FMFieldList { 8 | componentId?: string; 9 | value?: string | number; 10 | } 11 | 12 | interface FormEntity { 13 | addUserId?: string; 14 | componentList?: FMComponent[]; 15 | name?: string; 16 | style?: string; 17 | remark?: string; 18 | } 19 | 20 | interface IPagenationParams { 21 | pageNum: number; 22 | pageSize: number; 23 | } 24 | 25 | interface FMFormData { 26 | addUserId?: string; 27 | fieldList?: FMFieldList[]; 28 | formId?: string; 29 | } 30 | -------------------------------------------------------------------------------- /src/service/form.ts: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | export async function add(data: FormEntity) { 4 | return request('/form', { method: 'post', data: data }); 5 | } 6 | 7 | export async function getById(formId: string) { 8 | return request(`/form/${formId}`); 9 | } 10 | 11 | export async function update(data: FormEntity) { 12 | return request('/form', { method: 'put', data }); 13 | } 14 | 15 | export async function deleteById(formId: string) { 16 | return request(`/form/${formId}`, { method: 'delete' }); 17 | } 18 | 19 | export async function getPaged(params: IPagenationParams) { 20 | return request(`/form`, { params }); 21 | } 22 | 23 | export async function submit(data: FMFormData) { 24 | return request(`/form/data`, { method: 'post', data }); 25 | } 26 | -------------------------------------------------------------------------------- /src/service/formData.ts: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | interface PaginationParams extends IPagenationParams { 4 | formId: string; 5 | } 6 | 7 | export async function getPaged(params: PaginationParams) { 8 | return request(`/form/data`, { method: 'get', params }); 9 | } 10 | -------------------------------------------------------------------------------- /src/store/Maker.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { observable, action, toJS, autorun } from 'mobx'; 3 | import uuid, { v4 as uuidv4 } from 'uuid'; 4 | import * as _ from 'lodash'; 5 | import * as formSv from '@/service/form'; 6 | import { message } from 'antd'; 7 | import { getGUID } from '@/utils/utils'; 8 | 9 | export interface MakerItemProps { 10 | label: string; 11 | required?: boolean; 12 | placeholder?: string; 13 | disabled?: boolean; 14 | default?: string | number; //默认值 15 | datePicker?: string; //时间选择器类型 16 | } 17 | 18 | interface Target { 19 | data?: any; 20 | index: number; 21 | } 22 | 23 | export class Maker { 24 | @observable FieldPropsList: any[] = []; 25 | @observable MakerItems: [] = []; 26 | @observable target: Target | undefined = undefined; 27 | 28 | @observable selected: any | undefined = undefined; 29 | 30 | @observable formId: string | undefined = undefined; 31 | 32 | constructor() {} 33 | 34 | @action 35 | resetFormId = (formId?: string) => { 36 | this.formId = formId; 37 | }; 38 | 39 | @action 40 | submitFormData = (data: { [key: string]: string }) => { 41 | const fieldList: FMFieldList[] = []; 42 | Object.keys(data).forEach(key => 43 | fieldList.push({ componentId: key, value: JSON.stringify(data[key]) }), 44 | ); 45 | console.log(fieldList); 46 | const formData: FMFormData = { 47 | addUserId: '123', 48 | fieldList, 49 | formId: this.formId, 50 | }; 51 | return formSv.submit(formData).then(this.resetFormId); 52 | }; 53 | 54 | @action 55 | appendItem(item: any) { 56 | item.fieldProps.name = getGUID(); 57 | this.FieldPropsList.push(item); 58 | } 59 | 60 | @action 61 | isCanAppend() { 62 | return this.target === undefined; 63 | } 64 | 65 | @action 66 | resetTarget(t: Target | undefined) { 67 | this.target = t; 68 | } 69 | 70 | @action 71 | resetMakerItems(makerItems: any[]) { 72 | this.FieldPropsList = makerItems; 73 | } 74 | 75 | @action 76 | deleteMakerItemById = (uuid: string) => { 77 | this.FieldPropsList = this.FieldPropsList.filter(({ fieldProps }) => fieldProps.name !== uuid); 78 | }; 79 | 80 | @action 81 | resetSelected = (item: any) => { 82 | this.selected = item; 83 | }; 84 | 85 | @action 86 | isSelected = (item: any) => { 87 | return this.selected?.name === item.name; 88 | }; 89 | 90 | @action 91 | mutePrpos = (props: MakerItemProps) => { 92 | if (!!this.selected) 93 | this.FieldPropsList = this.FieldPropsList.map(x => { 94 | if (x.fieldProps.name === this.selected?.fieldProps.name) { 95 | return { ...x, fieldProps: props }; 96 | } 97 | return x; 98 | }) as any; 99 | }; 100 | 101 | @action 102 | addCopy = () => { 103 | let clone = _.cloneDeep(this.selected); 104 | clone.fieldProps.name = uuidv4(); 105 | this.FieldPropsList.push(clone!); 106 | }; 107 | 108 | @action 109 | clear = () => { 110 | this.FieldPropsList = []; 111 | }; 112 | 113 | @action 114 | getSchema = () => { 115 | if (!!this.FieldPropsList && this.FieldPropsList.length === 0) { 116 | return undefined; 117 | } 118 | 119 | let result = { 120 | type: 'object', 121 | properties: {} as any, 122 | }; 123 | 124 | this.FieldPropsList.forEach( 125 | ({ fieldProps }) => (result.properties[fieldProps.name] = { ...fieldProps }), 126 | ); 127 | return result; 128 | }; 129 | 130 | @action 131 | getDndSchema = () => { 132 | if (!!this.FieldPropsList && this.FieldPropsList.length === 0) { 133 | return undefined; 134 | } 135 | 136 | let result = { 137 | type: 'object', 138 | properties: {} as any, 139 | }; 140 | 141 | return result; 142 | }; 143 | @action 144 | saveFormData = (name?: string) => { 145 | const componentList: FMComponent[] = this.FieldPropsList.map(({ fieldProps, type }) => ({ 146 | id: fieldProps.name, 147 | name: fieldProps.title, 148 | type: type, 149 | })); 150 | const formEntity: FormEntity = { 151 | addUserId: '123', 152 | componentList, 153 | name: name || getGUID(), 154 | style: JSON.stringify(this.FieldPropsList), 155 | remark: 'remark', 156 | }; 157 | 158 | return formSv.add(formEntity).then(() => message.success('成功')); 159 | }; 160 | } 161 | 162 | export const makerContext = React.createContext(null); 163 | -------------------------------------------------------------------------------- /src/store/data.d.ts: -------------------------------------------------------------------------------- 1 | interface BasicProps { 2 | required?: boolean; 3 | disabled?: boolean; 4 | label?: string; 5 | placeholder?: string; 6 | readonly?: string; 7 | default?: string | any; 8 | } 9 | 10 | interface DatePickerProps extends BasicProps { 11 | picker?: string; 12 | format?: string; //日期格式 默认 yyyy-MM-dd 13 | timestamp?: boolean; //是否获取时间戳 14 | } 15 | 16 | interface SelectProps extends BasicProps { 17 | mode: string; 18 | enum: any[]; 19 | } 20 | -------------------------------------------------------------------------------- /src/utils/data.d.ts: -------------------------------------------------------------------------------- 1 | interface IWidge { 2 | icon: string; 3 | label: string; 4 | type: string; 5 | fieldProps: any; 6 | } 7 | -------------------------------------------------------------------------------- /src/utils/request.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * request 网络请求工具 3 | * 更详细的 api 文档: https://github.com/umijs/umi-request 4 | */ 5 | import { extend, RequestOptionsInit } from 'umi-request'; 6 | import { notification } from 'antd'; 7 | import { router } from 'umi'; 8 | 9 | const codeMessage = { 10 | 200: '服务器成功返回请求的数据。', 11 | 201: '新建或修改数据成功。', 12 | // 201: '服务器错误', 13 | 202: '一个请求已经进入后台排队(异步任务)。', 14 | 204: '删除数据成功。', 15 | 400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。', 16 | 401: '用户没有权限(令牌、用户名、密码错误)。', 17 | 403: '用户得到授权,但是访问是被禁止的。', 18 | 404: '发出的请求针对的是不存在的记录,服务器没有进行操作。', 19 | 406: '请求的格式不可得。', 20 | 410: '请求的资源被永久删除,且不会再得到的。', 21 | 422: '当创建一个对象时,发生一个验证错误。', 22 | 500: '服务器发生错误,请检查服务器。', 23 | 502: '网关错误。', 24 | 503: '服务不可用,服务器暂时过载或维护。', 25 | 504: '网关超时。', 26 | }; 27 | 28 | /** 29 | * 异常处理程序 30 | */ 31 | const errorHandler = (error: { response: Response }): Response => { 32 | const { response } = error; 33 | if (response && response.status) { 34 | const errorText = (codeMessage as any)[response.status] || response.statusText; 35 | const { status, url } = response; 36 | notification.error({ 37 | message: `请求错误 ${status}: ${url}`, 38 | description: errorText, 39 | }); 40 | } 41 | return response; 42 | }; 43 | 44 | // export const prefix = 45 | // process.env.NODE_ENV === 'development' ? '' : 'http://47.104.131.14/digitcons/v1'; 46 | 47 | export const prefix = 'http://47.104.131.14/wisdomsite/v1'; 48 | // export const prefix = 'http://39.104.81.4/wisdomsite/v1' 49 | 50 | // export const prefix = 'http://www.lanlan.live:8085/wisdomsite/v1' 51 | /** 52 | * 配置request请求时的默认参数 53 | */ 54 | export const urequest = extend({ 55 | prefix: prefix, 56 | errorHandler, // 默认错误处理 57 | credentials: 'include', // 默认请求是否带上cookie 58 | }); 59 | 60 | export const request = (url: string, options?: RequestOptionsInit) => { 61 | return new Promise(async (resolve, reject) => { 62 | const res = await urequest(url, options); 63 | if (res === null) { 64 | reject('未知错误'); 65 | return; 66 | } 67 | const error = handleStatusError(res.status, url, res.message); 68 | 69 | if (error) reject(error); 70 | 71 | const boxingRes = boxingResponse(res); 72 | resolve(boxingRes); 73 | }).catch(error => { 74 | throw error; 75 | }); 76 | }; 77 | 78 | const handleStatusError = (status: number, url?: string, msg?: string): string | undefined => { 79 | const errorConfig = (BACKENDSTATUSERRORCONFIG as any)[status] || undefined; 80 | if (Array.isArray(errorConfig)) { 81 | const [defaultMsg, fn] = errorConfig; 82 | if (typeof fn === 'function') { 83 | fn(msg || defaultMsg, url); 84 | } 85 | return msg; 86 | } 87 | 88 | return errorConfig; 89 | }; 90 | 91 | const boxingResponse = (res: any) => { 92 | const data = res.data; 93 | if (data && data.pageTool) { 94 | const pageTool = data.pageTool; 95 | return { 96 | dataList: data.beanList || [], 97 | meta: { 98 | pageNum: pageTool.pageNum, 99 | pageSize: pageTool.pageTool, 100 | total: pageTool.totalSize, 101 | }, 102 | }; 103 | } 104 | return res; 105 | }; 106 | 107 | const BACKENDSTATUSERRORCONFIG = { 108 | 125: [ 109 | 'token error!', 110 | () => { 111 | router.push('/user/login'); 112 | }, 113 | ], 114 | 201: [ 115 | '后台服务器异常请查阅日志!', 116 | (errorText: string, url: string) => { 117 | notification.error({ 118 | message: `请求错误 ${status}: ${url}`, 119 | description: errorText, 120 | }); 121 | }, 122 | ], 123 | 116: [ 124 | '项目进度id不能为空', 125 | (errorText: string, url: string) => { 126 | notification.error({ 127 | message: `请求错误 ${status}: ${url}`, 128 | description: errorText, 129 | }); 130 | }, 131 | ], 132 | 121: [ 133 | '', 134 | (errorText: string, url: string) => { 135 | notification.error({ 136 | message: `请求错误 ${status}: ${url}`, 137 | description: errorText, 138 | }); 139 | }, 140 | ], 141 | 10: ['', ''], 142 | }; 143 | 144 | // 中间件,对请求前、响应后做处理 145 | urequest.use(async (ctx, next) => { 146 | const { req } = ctx; 147 | 148 | req.options.headers = { 149 | auth_token: 'd7dda732508242669ba1c1506935b1e8', 150 | }; 151 | 152 | await next(); 153 | const { res } = ctx; 154 | 155 | // if (process.env.NODE_ENV === 'development') { 156 | // console.log(`API: ${req.url.replace(prefix, '')} \r\n返回的数据: `, res.data, ' \r\n'); 157 | // console.log(`\r\n`); 158 | // } 159 | }); 160 | 161 | export default request; 162 | -------------------------------------------------------------------------------- /src/utils/utils.ts: -------------------------------------------------------------------------------- 1 | import { v4 as uuidV4 } from 'uuid'; 2 | export const getItemStyle = (isDragging: any, draggableStyle: any) => ({ 3 | // some basic styles to make the items look a bit nicer 4 | // userSelect: 'none', 5 | 6 | // change background colour if dragging 7 | // background: isDragging ? 'lightgreen' : 'red', 8 | 9 | // styles we need to apply on draggables 10 | ...draggableStyle, 11 | }); 12 | 13 | export const getListStyle = (isDraggingOver: any) => ({ 14 | // background: isDraggingOver ? 'lightblue' : 'grey', 15 | }); 16 | 17 | export const getGUID = () => { 18 | return uuidV4().replace(/-/g, ''); 19 | }; 20 | -------------------------------------------------------------------------------- /src/widge.ts: -------------------------------------------------------------------------------- 1 | import { ItemTypes } from './contants'; 2 | import { getGUID } from './utils/utils'; 3 | 4 | export const Widges = [ 5 | { 6 | label: '单行文本', 7 | type: ItemTypes.INPUT, 8 | icon: 'anticoninput', 9 | fieldProps: { 10 | 'x-component': 'string', 11 | title: '单行文本', 12 | }, 13 | }, 14 | { 15 | label: '数字输入框', 16 | type: ItemTypes.INPUTNUMBER, 17 | icon: 'anticonfuhao-shuzishurukuang', 18 | fieldProps: { 19 | 'x-component': 'NumberPicker', 20 | title: '数字输入框', 21 | }, 22 | }, 23 | { 24 | label: '多行文本', 25 | type: ItemTypes.TEXTAREA, 26 | icon: 'anticontextareabt_back', 27 | uuid: getGUID(), 28 | fieldProps: { 29 | 'x-component': 'textarea', 30 | title: '多行文本', 31 | }, 32 | }, 33 | { 34 | label: '下拉选择器', 35 | type: ItemTypes.SELECT, 36 | icon: 'anticondrop-down', 37 | uuid: getGUID(), 38 | fieldProps: { 39 | 'x-component': 'string', 40 | title: '下拉选择器', 41 | enum: [{ label: 'option1', value: 'option1' }], 42 | }, 43 | }, 44 | { 45 | label: '日期选择器', 46 | type: ItemTypes.DATEPICKER, 47 | icon: 'anticonmdatepicker', 48 | uuid: getGUID(), 49 | fieldProps: { 50 | type: 'daterange', 51 | title: '日期选择器', 52 | picker: 'date', 53 | }, 54 | }, 55 | { 56 | label: '日期范围选择', 57 | type: ItemTypes.RANGPICKER, 58 | icon: 'anticonmdatepicker', 59 | uuid: getGUID(), 60 | fieldProps: { 61 | type: 'RangePicker', 62 | title: '日期范围选择器', 63 | picker: 'date', 64 | }, 65 | }, 66 | { 67 | label: '多选框', 68 | type: ItemTypes.CHECKBOX, 69 | icon: 'anticonduoxuankuang', 70 | uuid: getGUID(), 71 | fieldProps: { 72 | 'x-component': 'CheckboxGroup', 73 | title: '多选框', 74 | enum: [ 75 | { label: 'One', value: '1' }, 76 | { label: 'Two', value: '2' }, 77 | { label: 'Three', value: '3' }, 78 | { label: 'Four', value: '4' }, 79 | ], 80 | }, 81 | }, 82 | { 83 | label: '单选框', 84 | type: ItemTypes.RADIO, 85 | icon: 'anticondanxuankuangxuanzhong', 86 | uuid: getGUID(), 87 | fieldProps: { 88 | 'x-component': 'RadioGroup', 89 | title: '单选框', 90 | enum: [ 91 | { label: 'One', value: '1' }, 92 | { label: 'Two', value: '2' }, 93 | { label: 'Three', value: '3' }, 94 | { label: 'Four', value: '4' }, 95 | ], 96 | }, 97 | }, 98 | { 99 | label: '开关按钮', 100 | type: ItemTypes.SWITCH, 101 | icon: 'anticonkaiguananniu', 102 | uuid: getGUID(), 103 | fieldProps: { 104 | 'x-component': 'Switch', 105 | title: '开关按钮', 106 | }, 107 | }, 108 | ]; 109 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "lib": ["dom", "dom.iterable", "esnext"], 7 | "skipLibCheck": true, 8 | "importHelpers": true, 9 | "jsx": "react", 10 | "esModuleInterop": true, 11 | "sourceMap": true, 12 | "baseUrl": ".", 13 | "strict": true, 14 | "experimentalDecorators": true, 15 | "emitDecoratorMetadata": true, 16 | "paths": { 17 | "@/*": ["src/*"], 18 | "@tmp/*": ["src/pages/.umi/*"], 19 | "@@/*": ["src/.umi/*"] 20 | }, 21 | "allowSyntheticDefaultImports": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /typings.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.css'; 2 | declare module '*.png'; 3 | declare module '*.less'; 4 | --------------------------------------------------------------------------------