├── .eslintignore ├── .gitignore ├── src ├── components │ ├── login │ │ ├── Login.less │ │ └── Login.jsx │ ├── sider │ │ ├── Sider.less │ │ └── Sider.jsx │ ├── common │ │ ├── Example.jsx │ │ ├── CopyClipboard.jsx │ │ ├── Common.less │ │ ├── RetrieveForm.jsx │ │ ├── Former.jsx │ │ ├── UpdateForm.jsx │ │ ├── CreateForm.jsx │ │ ├── BDUploader.jsx │ │ ├── CreateTextItem.jsx │ │ ├── CreateFormItem.jsx │ │ └── FeatureSetConfig.jsx │ ├── main │ │ ├── Main.less │ │ └── Main.jsx │ ├── header │ │ ├── Header.jsx │ │ └── Header.less │ └── feature │ │ ├── Feature2-2.jsx │ │ ├── Feature2-1.jsx │ │ ├── Feature3-1.jsx │ │ ├── Feature1-6.jsx │ │ ├── Feature3-2.jsx │ │ ├── Feature1-1.jsx │ │ ├── Feature1-2.jsx │ │ ├── Feature1-1-1.jsx │ │ ├── Feature1-3.jsx │ │ ├── Feature1-4.jsx │ │ ├── Feature1-5.jsx │ │ ├── Feature5-2.jsx │ │ ├── Feature5-1.jsx │ │ ├── Feature3-3.jsx │ │ └── Feature4-1.jsx ├── routes │ ├── IndexPage.less │ └── IndexPage.jsx ├── router.jsx ├── index.js ├── index.html ├── index.less ├── utils │ └── util.js └── config.js ├── proxy.config.js ├── .editorconfig ├── .eslintrc ├── package.json ├── webpack.config.js ├── mock └── example.js └── README.md /.eslintignore: -------------------------------------------------------------------------------- 1 | src/**/*-test.js 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /src/components/login/Login.less: -------------------------------------------------------------------------------- 1 | // sider 部分 2 | .sider { 3 | position: absolute; 4 | width: 240px; 5 | background-color: #f5f5f5; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/components/sider/Sider.less: -------------------------------------------------------------------------------- 1 | // sider 部分 2 | .sider { 3 | position: absolute; 4 | width: 240px; 5 | background-color: #f5f5f5; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/routes/IndexPage.less: -------------------------------------------------------------------------------- 1 | // 无权限样式 2 | .nopermission{ 3 | font-size: 20px; 4 | font-weight: bold; 5 | color: #333; 6 | padding: 50px; 7 | text-align: center; 8 | } -------------------------------------------------------------------------------- /proxy.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const mock = {}; 4 | 5 | require('fs').readdirSync(require('path').join(__dirname + '/mock')) 6 | .forEach(function (file) { 7 | Object.assign(mock, require('./mock/' + file)); 8 | }); 9 | 10 | module.exports = mock; 11 | -------------------------------------------------------------------------------- /src/components/common/Example.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | // Stateless Functional Component 4 | const Example = (props) => { 5 | return ( 6 |
7 | Example 8 |
9 | ); 10 | }; 11 | 12 | Example.propTypes = { 13 | }; 14 | 15 | export default Example; 16 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /src/components/login/Login.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Menu, Icon } from 'antd'; 3 | import { Link } from 'dva/router'; 4 | 5 | function Login(props){ 6 | return
7 | 您暂无权限处理该系统工作,请先 8 | 登录 9 | 或者找相关人员申请权限。 10 |
; 11 | }; 12 | 13 | export default Login; 14 | -------------------------------------------------------------------------------- /src/components/main/Main.less: -------------------------------------------------------------------------------- 1 | // main 部分 2 | .mainer { 3 | margin-left: 239px; 4 | border-left: 1px solid #e9e9e9; 5 | 6 | .title { 7 | padding: 15px 20px; 8 | border-bottom: 1px solid #ddd; 9 | } 10 | 11 | .item { 12 | position: relative; 13 | padding: 40px 30px; 14 | border-bottom: 1px solid #e6e6e6; 15 | } 16 | } 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/router.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import { Router, Route} from 'dva/router'; 3 | import IndexPage from './routes/IndexPage'; 4 | 5 | // router 路由配置 可使用链接放置参数数据 6 | export default function({ history }) { 7 | return ( 8 | 9 | 10 | 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file CMS平台主文件 3 | * @author niyingfeng 4 | * @doc https://github.com/dvajs/dva/blob/master/README_zh-CN.md 5 | */ 6 | 7 | import './index.html'; 8 | import './index.less'; 9 | import dva from 'dva'; 10 | 11 | // 1. Initialize 12 | const app = dva(); 13 | 14 | // 2. Plugins 15 | // app.use({}); 16 | 17 | // 3. Model 18 | // app.model(require('./models/example')); 19 | 20 | // 4. Router 21 | app.router(require('./router')); 22 | 23 | // 5. Start 24 | app.start('#root'); 25 | -------------------------------------------------------------------------------- /src/components/main/Main.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Menu, Icon } from 'antd'; 3 | import { Link } from 'dva/router' 4 | 5 | const Main = (props) => { 6 | 7 | let Feature = props.feature; 8 | 9 | return
10 | { 11 | props.title ? 12 |

{props.title}

: 13 | '' 14 | } 15 | 16 |
17 | } 18 | 19 | export default Main; 20 | -------------------------------------------------------------------------------- /src/components/common/CopyClipboard.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * 复制拷贝按钮 3 | */ 4 | import React from 'react'; 5 | import { Button, message } from 'antd'; 6 | import CopyToClipboard from 'react-copy-to-clipboard'; 7 | 8 | // 百度浏览器特定文件上传组件 9 | const CopyClipboard = (props) => { 10 | return message.success('复制成功')}> 12 | { 13 | props.type === 'link'? 14 | {props.title}: 15 | 16 | 17 | } 18 | ; 19 | } 20 | 21 | export default CopyClipboard; 22 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Demo 6 | 7 | 8 | 9 | 10 |
11 | 12 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": "eslint-config-airbnb", 4 | "rules": { 5 | "spaced-comment": [0], 6 | "no-unused-vars": [0], 7 | "no-empty": [0], 8 | "react/wrap-multilines": [0], 9 | "react/no-multi-comp": [0], 10 | "no-constant-condition": [0], 11 | "react/jsx-no-bind": [0], 12 | "react/prop-types": [0], 13 | "arrow-body-style": [0], 14 | "react/prefer-stateless-function": [0], 15 | "semi": [0], 16 | "global-require": [0], 17 | "no-shadow": [0], 18 | "no-useless-computed-key": [0], 19 | "no-underscore-dangle": [0] 20 | }, 21 | "ecmaFeatures": { 22 | "experimentalObjectRestSpread": true 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/components/common/Common.less: -------------------------------------------------------------------------------- 1 | // 通用组件样式集合 2 | 3 | .normal { 4 | margin-top: 20px; 5 | } 6 | .search, .normal { 7 | .ant-form-item { 8 | margin-right: 25px; 9 | margin-bottom: 15px; 10 | > label:after { 11 | content: ":"; 12 | position: relative; 13 | top: -.5px; 14 | margin: 0 8px 0 2px; 15 | } 16 | } 17 | } 18 | 19 | .create { 20 | text-align: right; 21 | 22 | > button { 23 | margin: 20px 0; 24 | } 25 | 26 | &:after { 27 | content: " "; 28 | display: table; 29 | clear: both; 30 | } 31 | } 32 | 33 | .uploadImg{ 34 | max-width: 300px; 35 | max-height: 400px; 36 | } -------------------------------------------------------------------------------- /src/components/header/Header.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Affix, Menu, Icon } from 'antd'; 3 | import { Link } from 'dva/router'; 4 | 5 | const HeadMenuItemCreat = (items) => { 6 | return items.map(function(item){ 7 | return {item.title} 8 | }); 9 | }; 10 | 11 | function Header(props){ 12 | return
13 |

14 | 15 | {props.title} 16 |

17 | { 18 | props.menu ? 19 |
20 | { 21 | HeadMenuItemCreat(props.menu) 22 | } 23 |
: 24 | "" 25 | } 26 |
27 | 28 | {props.name} 29 |
30 |
; 31 | }; 32 | 33 | export default Header; 34 | -------------------------------------------------------------------------------- /src/components/header/Header.less: -------------------------------------------------------------------------------- 1 | // header 部分 2 | .header { 3 | position: relative; 4 | z-index: 1; 5 | padding: 15px 15px 15px 25px; 6 | border-bottom: 1px solid #e9e9e9; 7 | background-color: #f5f5f5; 8 | 9 | h2{ 10 | display: inline-block; 11 | margin-right: 50px; 12 | } 13 | .icon { 14 | position: relative; 15 | top: 1px; 16 | padding-right: 10px; 17 | } 18 | .head-menu{ 19 | display: inline-block; 20 | 21 | a{ 22 | display: inline-block; 23 | font-size: 14px; 24 | padding: 5px 10px; 25 | color: rgba(0, 0, 0, 0.65); 26 | } 27 | } 28 | .aver { 29 | position: absolute; 30 | top: 10px; 31 | right: 20px; 32 | 33 | img { 34 | display: inline-block; 35 | height: 40px; 36 | margin-right: 10px; 37 | border-radius: 20px; 38 | } 39 | 40 | span { 41 | position: relative; 42 | top: -13px; 43 | font-size: 16px; 44 | color: #666; 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/index.less: -------------------------------------------------------------------------------- 1 | 2 | @import "~antd/lib/style/themes/default"; 3 | //阿里的cdn 对百度域名屏蔽 字体扔到百度自己的服务器上处理 4 | @icon-url: "http://webapp.bdstatic.com/webapp/libs/iconfont2/iconfont"; 5 | @import "~antd/lib/style/core/index.less"; 6 | @import "~antd/lib/style/components.less"; 7 | 8 | @import "components/header/Header.less"; 9 | @import "components/main/Main.less"; 10 | @import "components/sider/Sider.less"; 11 | @import "components/common/Common.less"; 12 | 13 | @import "routes/IndexPage.less"; 14 | 15 | html, 16 | body, 17 | #root { 18 | height: 100%; 19 | } 20 | 21 | 22 | // 全局从定义样式 23 | // 重置antd 关于table的部分样式 24 | .ant-table{ 25 | table{ 26 | text-align: center; 27 | 28 | img { 29 | display: block; 30 | max-height: 100px; 31 | margin: 0 auto; 32 | } 33 | } 34 | 35 | .ant-table-thead > tr > th{ 36 | text-align: center; 37 | } 38 | } 39 | 40 | .ant-form-inline .ant-form-item { 41 | margin-right: 30px; 42 | } 43 | 44 | .formLayout { 45 | position: absolute; 46 | z-index: 999; 47 | top: 0; 48 | right: 0; 49 | bottom: 0; 50 | left: 0; 51 | text-align: center; 52 | background-color: rgba(255, 255, 255, .75); 53 | } -------------------------------------------------------------------------------- /src/components/common/RetrieveForm.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Form, Button } from 'antd'; 3 | 4 | import CFormItem from './CreateFormItem'; 5 | 6 | const FormItem = Form.Item; 7 | 8 | let RForm = React.createClass({ 9 | render: function() { 10 | const self = this; 11 | const RType = this.props.RType; 12 | const { getFieldDecorator } = this.props.form; 13 | return RType ? 14 | (
15 |
16 | { 17 | RType.map(function(item){ 18 | return 19 | }) 20 | } 21 | 22 | 23 | 24 | 25 |
): 26 |
; 27 | }, 28 | 29 | handleRetrieve: function(){ 30 | this.props.submit(this.props.form.getFieldsValue()); 31 | } 32 | }); 33 | RForm = Form.create()(RForm); 34 | 35 | export default RForm; 36 | -------------------------------------------------------------------------------- /src/components/sider/Sider.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Menu, Icon } from 'antd'; 3 | import { Link } from 'dva/router'; 4 | 5 | const MenuItemCreat = (items) => { 6 | return items.map(function(item){ 7 | if(item.items){ 8 | let title = {item.icon ? (): ''}{item.title}; 9 | 10 | return 11 | { 12 | MenuItemCreat(item.items) 13 | } 14 | 15 | }else{ 16 | return 17 | {item.title} 18 | 19 | } 20 | }); 21 | }; 22 | 23 | function Sider(props){ 24 | return
25 | 28 | { 29 | MenuItemCreat(props.menu) 30 | } 31 | 32 | 33 |
; 34 | }; 35 | 36 | export default Sider; 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "entry": { 4 | "index": "./src/index.js" 5 | }, 6 | "dependencies": { 7 | "antd": "^2.3.0", 8 | "babel-plugin-import": "^1.0.1", 9 | "bce-sdk-js": "^0.1.7", 10 | "components": "^0.1.0", 11 | "dva": "^1.0.0", 12 | "echarts-for-react": "^1.1.5", 13 | "font": "0.0.4", 14 | "immutable": "^3.8.1", 15 | "moment": "^2.15.2", 16 | "react": "^15.1.0", 17 | "react-copy-to-clipboard": "^4.2.3", 18 | "react-dom": "^15.1.0", 19 | "react-tinymce": "^0.5.1", 20 | "reqwest": "^2.0.5", 21 | "routes": "^2.1.0", 22 | "src": "^1.1.2" 23 | }, 24 | "devDependencies": { 25 | "atool-build": "^0.7.6", 26 | "atool-test-mocha": "^0.1.5", 27 | "babel-plugin-dev-expression": "^0.2.1", 28 | "babel-plugin-dva-hmr": "^0.1.0", 29 | "babel-plugin-transform-runtime": "^6.9.0", 30 | "babel-runtime": "^6.9.2", 31 | "dora": "0.3.x", 32 | "dora-plugin-proxy": "^0.7.0", 33 | "dora-plugin-webpack": "0.6.x", 34 | "dora-plugin-webpack-hmr": "^0.1.0", 35 | "expect": "^1.20.2", 36 | "redbox-react": "^1.2.10" 37 | }, 38 | "scripts": { 39 | "start": "dora --plugins \"proxy,webpack,webpack-hmr\"", 40 | "build": "atool-build", 41 | "test": "atool-test-mocha ./src/**/*-test.js" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/components/common/Former.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * form 创建工具 3 | * 自动化生成整体form表单元素 4 | * 包括 创建,更新,查询,普通表单等 5 | * 依赖 CreateFormItem 6 | */ 7 | 8 | import React from 'react'; 9 | import { Form, Button } from 'antd'; 10 | 11 | import CFormItem from './CreateFormItem'; 12 | 13 | let Former = React.createClass({ 14 | getInitialState: function() { 15 | return { 16 | 17 | }; 18 | }, 19 | 20 | render: function() { 21 | const self = this; 22 | const fields = this.props.fields; 23 | const updateItem = this.props.updateItem || {}; 24 | 25 | // 详情见antd form 文档 26 | const { getFieldDecorator } = this.props.form; 27 | 28 | return
29 |
30 | { 31 | fields.map(function(item){ 32 | item.defaultValue = updateItem[item.name]||item.defaultValue||''; 33 | //return self.dealConfigUType(item, defaultValue); 34 | return 35 | }) 36 | } 37 | 38 |
39 | }, 40 | 41 | handleUpdate: function(){ 42 | this.props.submit(this.props.form.getFieldsValue()); 43 | }, 44 | 45 | handleReset: function() { 46 | this.props.form.resetFields(); 47 | } 48 | }); 49 | Former = Form.create()(Former); 50 | 51 | export default Former; 52 | 53 | -------------------------------------------------------------------------------- /src/utils/util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file CMS平台Util 功能文件 3 | * @author niyingfeng 4 | */ 5 | // 自定义的配置数据 6 | // 处理时间格式数据 7 | // 处理自定义链接参数数据 8 | 9 | export default { 10 | DateFormat: function (date, fmt) { 11 | if (typeof date === 'string') { 12 | date = new Date(date); 13 | } 14 | 15 | let o = { 16 | 'M+': date.getMonth() + 1, // 月份 17 | 18 | 'D+': date.getDate(), // 日 19 | 'd+': date.getDate(), // 日 20 | 21 | 'h+': date.getHours() % 12 == 0 ? 12 : date.getHours() % 12, // 小时 12小时制 22 | 'H+': date.getHours(), // 小时 23 | 24 | 'm+': date.getMinutes(), // 分 25 | 's+': date.getSeconds(), // 秒 26 | 'q+': Math.floor((date.getMonth() + 3) / 3), // 季度 27 | 'S': date.getMilliseconds() // 毫秒 28 | }; 29 | 30 | // 需要按位数进行显示 31 | if (/(y+)/i.test(fmt)) { 32 | fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); 33 | } 34 | 35 | for (let k in o) { 36 | if (new RegExp('(' + k + ')').test(fmt)) { 37 | fmt = fmt.replace(RegExp.$1, 38 | (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length))); 39 | } 40 | 41 | } 42 | return fmt; 43 | }, 44 | 45 | ParamsFixed: function (str) { 46 | let pObj = {}; 47 | let pArr = str.split('&'); 48 | for (let i = pArr.length - 1; i >= 0 && pArr[i]; i--) { 49 | let dataArr = pArr[i].split('='); 50 | pObj[dataArr[0]] = dataArr[1]; 51 | } 52 | 53 | return pObj; 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /src/routes/IndexPage.jsx: -------------------------------------------------------------------------------- 1 | import React, { Componnet } from 'react'; 2 | import ReactDom from 'react-dom'; 3 | 4 | import { connect } from 'dva'; 5 | import { Link } from 'dva/router'; 6 | 7 | import config from '../config'; 8 | 9 | import Header from '../components/header/Header'; 10 | import Sider from '../components/sider/Sider'; 11 | import Main from '../components/main/Main'; 12 | 13 | import Login from '../components/login/Login'; 14 | 15 | //const components = config.main.components; 16 | const headerInfo = { 17 | ...config.header, 18 | name: config.userInfo.name, 19 | aver: config.userInfo.aver 20 | } 21 | 22 | const siderInfo = { ...config.sider }; 23 | 24 | const mainInfo = { 25 | style: config.sider.style 26 | } 27 | 28 | const IndexInfo = { 29 | permission: config.userInfo.permission, 30 | loginUrl: config.userInfo.loginUrl 31 | } 32 | 33 | const App = (props) => { 34 | 35 | let featureId = props.params.FeatureId || config.sider.selectedKey; 36 | 37 | let featureInfo = { 38 | featureId: featureId, 39 | params: props.params.params, 40 | 41 | feature: config.main.components[featureId].component, 42 | title: config.main.components[featureId].title, 43 | } 44 | 45 | if(IndexInfo.permission){ 46 | return
47 |
48 | 49 |
50 |
51 | }else{ 52 | return
53 | 54 |
55 | } 56 | } 57 | 58 | export default App; 59 | -------------------------------------------------------------------------------- /src/components/feature/Feature2-2.jsx: -------------------------------------------------------------------------------- 1 | // 纯数据展现情况列表 2 | import React from 'react'; 3 | 4 | import FeatureSetConfig from '../common/FeatureSetConfig'; 5 | import Reqwest from 'reqwest'; 6 | 7 | const simple_conf = { 8 | 9 | type: 'simpleObject', 10 | 11 | initData: function(callback){ 12 | // 模拟数据 13 | Reqwest({ 14 | url: '/api/example3', 15 | data: {}, 16 | 17 | type: 'json', 18 | success: function (data) { 19 | let object = data.data; 20 | object.key = object.docid; 21 | 22 | callback(object); 23 | } 24 | }); 25 | }, 26 | 27 | Update:function(data, callback){ 28 | console.log(data); 29 | callback(data); 30 | }, 31 | 32 | UType:[ 33 | { 34 | name: 'docid', 35 | label: '唯一标识', 36 | type: 'string', 37 | placeholder: '请输入标示名称' 38 | },{ 39 | name: 'title', 40 | label: '标题', 41 | type: 'string', 42 | placeholder: '请输入标示名称' 43 | },{ 44 | name: 'link', 45 | label: '链接', 46 | type: 'string' 47 | },{ 48 | name: 'date', 49 | label: '日期', 50 | type: 'date' 51 | },{ 52 | name: 'image', 53 | label: '图片', 54 | type: 'imageUpload' 55 | } 56 | ], 57 | 58 | operate:[ 59 | { 60 | text: '确认修改', 61 | type: 'update', 62 | style: { 63 | 'marginRight': '30px', 64 | 'marginLeft': '80px' 65 | } 66 | }, { 67 | text: '展示数据', 68 | callback: function(item){ 69 | console.log(item) 70 | } 71 | } 72 | ] 73 | 74 | 75 | } 76 | 77 | const Feature1 = FeatureSetConfig(simple_conf); 78 | 79 | export default Feature1; 80 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file mock文件 3 | * @author dva 4 | */ 5 | const fs = require('fs'); 6 | const path = require('path'); 7 | 8 | module.exports = function (webpackConfig, env) { 9 | webpackConfig.babel.plugins.push('transform-runtime'); 10 | 11 | // Support hmr 12 | if (env === 'development') { 13 | webpackConfig.devtool = '#eval'; 14 | webpackConfig.babel.plugins.push(['dva-hmr', { 15 | entries: [ 16 | './src/index.js' 17 | ] 18 | }]); 19 | } 20 | else { 21 | webpackConfig.babel.plugins.push('dev-expression'); 22 | } 23 | 24 | // 尼玛处理了好久!!!!!不懂webpack 胡乱注释 25 | // 使用css modules 确实非常爽 但是TMD 谁能帮我在使用 CSS Modules的情况下 26 | // 解决字体文件 包括对百度域名屏蔽的问题 只能舍弃 CSS Modules 来进行解决 27 | // Support CSS Modules 28 | // Parse all less files as css module. 29 | // webpackConfig.module.loaders.forEach(function (loader, index) { 30 | // if (typeof loader.test === 'function' && loader.test.toString().indexOf('\\.less$') > -1) { 31 | // loader.include = /node_modules/; 32 | // loader.test = /\.less$/; 33 | // } 34 | 35 | // if (loader.test.toString() === '/\\.module\\.less$/') { 36 | // loader.exclude = /node_modules/; 37 | // loader.test = /\.less$/; 38 | // } 39 | 40 | // if (typeof loader.test === 'function' && loader.test.toString().indexOf('\\.css$') > -1) { 41 | // loader.include = /node_modules/; 42 | // loader.test = /\.css$/; 43 | // } 44 | 45 | // if (loader.test.toString() === '/\\.module\\.css$/') { 46 | // loader.exclude = /node_modules/; 47 | // loader.test = /\.css$/; 48 | // } 49 | 50 | // }); 51 | 52 | // webpackConfig.babel.plugins.push(['import', { 53 | // libraryName: 'antd', 54 | // style: 'css' 55 | // }]); 56 | 57 | return webpackConfig; 58 | }; 59 | -------------------------------------------------------------------------------- /src/components/common/UpdateForm.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Form, Modal, message } from 'antd'; 3 | 4 | import CFormItem from './CreateFormItem'; 5 | 6 | 7 | let UForm = React.createClass({ 8 | getInitialState: function() { 9 | return { 10 | 11 | }; 12 | }, 13 | 14 | render: function() { 15 | const self = this; 16 | const UType = this.props.UType; 17 | const updateItem = this.props.updateItem; 18 | 19 | // 详情见antd form 文档 20 | const { getFieldDecorator } = this.props.form; 21 | const formItemLayout = { 22 | labelCol: { span: 6 }, 23 | wrapperCol: { span: 18 }, 24 | }; 25 | 26 | return UType ? 27 |
28 | 29 |
30 | { 31 | UType.map(function(item){ 32 | item.defaultValue = updateItem[item.name]||''; 33 | //return self.dealConfigUType(item, defaultValue); 34 | return 35 | }) 36 | } 37 | 38 |
39 |
: 40 |
41 | }, 42 | 43 | handleUpdate: function(){ 44 | this.props.submit(this.props.form.getFieldsValue()); 45 | }, 46 | 47 | handleReset: function() { 48 | this.props.form.resetFields(); 49 | }, 50 | 51 | hideModal: function() { 52 | this.props.hideForm(); 53 | this.handleReset(); 54 | } 55 | }); 56 | UForm = Form.create()(UForm); 57 | 58 | export default UForm; 59 | -------------------------------------------------------------------------------- /src/components/feature/Feature2-1.jsx: -------------------------------------------------------------------------------- 1 | // 纯数据展现情况列表 2 | import React from 'react'; 3 | 4 | import FeatureSetConfig from '../common/FeatureSetConfig'; 5 | import Reqwest from 'reqwest'; 6 | 7 | const simple_conf = { 8 | 9 | type: 'simpleObject', 10 | 11 | initData: function(callback){ 12 | // 模拟数据 13 | Reqwest({ 14 | url: '/api/example3', 15 | data: {}, 16 | 17 | type: 'json', 18 | success: function (data) { 19 | let object = data.data; 20 | object.key = object.docid; 21 | 22 | callback(object); 23 | } 24 | }); 25 | }, 26 | 27 | 28 | // { 29 | // title 显示表题 30 | // dataIndex 显示数据中的key 31 | // type 展现形式 (string image link) 32 | // render 自定义展现形式 参数 (当前数据,当前对象数据) 33 | // } 34 | 35 | columns:[ 36 | { 37 | title: '唯一标识', 38 | dataIndex: 'docid', 39 | type: 'string' 40 | },{ 41 | title: '标题', 42 | dataIndex: 'title', 43 | type: 'string' 44 | },{ 45 | title: '链接', 46 | dataIndex: 'link', 47 | type: 'link' 48 | // render: (text) => ( 49 | // {text} 50 | // ) 51 | },{ 52 | title: '日期', 53 | dataIndex: 'date', 54 | type: 'string' 55 | },{ 56 | title: '图片', 57 | dataIndex: 'image', 58 | type: 'image' 59 | } 60 | ], 61 | 62 | operate:[ 63 | { 64 | text: '编辑数据', 65 | style: { 66 | 'marginLeft': '80px' 67 | }, 68 | callback: function(item){ 69 | console.log(item); 70 | location.hash = '#Feature2-2'; 71 | } 72 | } 73 | ] 74 | } 75 | 76 | const Feature = FeatureSetConfig(simple_conf); 77 | 78 | export default Feature; 79 | -------------------------------------------------------------------------------- /src/components/feature/Feature3-1.jsx: -------------------------------------------------------------------------------- 1 | // 纯数据展现情况列表 2 | import React from 'react'; 3 | 4 | import FeatureSetConfig from '../common/FeatureSetConfig'; 5 | import Reqwest from 'reqwest'; 6 | 7 | const graph_conf = { 8 | 9 | type: 'graphList', // tableList graphList simpleObject complexObject 10 | 11 | EchartStyle: { 12 | width: '100%', 13 | height: '450px' 14 | }, 15 | 16 | // 初始化展现的数据,使用callback 回传列表数据 17 | // 需要手动添加唯一id key 18 | // callback 组件数据的回调函数(接受列表数据参数) 19 | initData: function(callback){ 20 | 21 | // 参考echarts 参数 22 | var option = { 23 | title: { 24 | text: '堆叠区域图' 25 | }, 26 | tooltip : { 27 | trigger: 'axis' 28 | }, 29 | legend: { 30 | data:['邮件营销','联盟广告','视频广告'] 31 | }, 32 | toolbox: { 33 | feature: { 34 | saveAsImage: {} 35 | } 36 | }, 37 | grid: { 38 | left: '3%', 39 | right: '4%', 40 | bottom: '3%', 41 | containLabel: true 42 | }, 43 | xAxis : [ 44 | { 45 | type : 'category', 46 | boundaryGap : false, 47 | data : ['周一','周二','周三','周四','周五','周六','周日'] 48 | } 49 | ], 50 | yAxis : [ 51 | { 52 | type : 'value' 53 | } 54 | ] 55 | } 56 | 57 | // 模拟数据 58 | Reqwest({ 59 | url: '/api/example4', 60 | data: {}, 61 | 62 | type: 'json', 63 | success: function (data) { 64 | option.series = data.data; 65 | option.series.forEach(function(item) { 66 | item.type = 'line'; 67 | item.stack = '总量'; 68 | }); 69 | 70 | callback(option); 71 | } 72 | }); 73 | } 74 | 75 | }; 76 | 77 | const Feature = FeatureSetConfig(graph_conf); 78 | 79 | export default Feature; 80 | -------------------------------------------------------------------------------- /src/components/feature/Feature1-6.jsx: -------------------------------------------------------------------------------- 1 | // 含有可操作 table 栏的数据展示 2 | import React from 'react'; 3 | 4 | import FeatureSetConfig from '../common/FeatureSetConfig'; 5 | import Reqwest from 'reqwest'; 6 | 7 | 8 | const conf = { 9 | 10 | type: 'tableList', 11 | 12 | // 初始化页面的数据 回调函数传入 items 列表 13 | initData: function(callback){ 14 | 15 | Reqwest({ 16 | url: '/api/example', 17 | data: {}, 18 | 19 | type: 'json', 20 | success: function (data) { 21 | let list = data.data; 22 | let i = 0; 23 | list.forEach(function(ele) { 24 | ele.key = i++; 25 | }); 26 | callback(list); 27 | } 28 | }); 29 | 30 | }, 31 | 32 | // table 表单字段 33 | columns: [ 34 | { 35 | title: 'KEY', // table header 文案 36 | dataIndex: 'key', // 数据对象内的属性,也做react vdom 的key 37 | type: 'string', // table 内显示的类型 38 | sort: true, // 是否需要排序 39 | }, { 40 | title: '标题', 41 | dataIndex: 'title', 42 | type: 'string' 43 | }, { 44 | title: '链接', 45 | dataIndex: 'link', 46 | type: 'link' 47 | }, { 48 | title: '操作', 49 | type: 'operate', // 操作的类型必须为 operate 50 | btns: [{ 51 | text: 'console输出', 52 | callback: function(item){ 53 | console.log(item) 54 | } 55 | },{ 56 | text: '删除', 57 | type: 'delete' 58 | }], // 可选 59 | } 60 | ], 61 | // 删除操作 62 | Delete: function(data, callback){ 63 | // 删除操作 64 | console.log(data); 65 | 66 | Reqwest({ 67 | url: '/api/delete', 68 | data: {}, 69 | 70 | type: 'json', 71 | success: function (data) { 72 | // 模拟请求删除成功的回调 73 | callback(); 74 | } 75 | }); 76 | 77 | } 78 | 79 | }; 80 | 81 | const Feature = FeatureSetConfig(conf); 82 | 83 | export default Feature; 84 | -------------------------------------------------------------------------------- /src/components/feature/Feature3-2.jsx: -------------------------------------------------------------------------------- 1 | // 纯数据展现情况列表 2 | import React from 'react'; 3 | 4 | import FeatureSetConfig from '../common/FeatureSetConfig'; 5 | import Reqwest from 'reqwest'; 6 | 7 | const graph_conf2 = { 8 | 9 | type: 'graphList', // tableList graphList simpleObject complexObject 10 | style: { 11 | width: '100%', 12 | height: '450px' 13 | }, 14 | 15 | // 初始化展现的数据,使用callback 回传列表数据 16 | // 需要手动添加唯一id key 17 | // callback 组件数据的回调函数(接受列表数据参数) 18 | // 将回调数据掺入option 19 | initData: function(callback){ 20 | 21 | // 参考echarts 参数 22 | var option = { 23 | title : { 24 | text: '某站点用户访问来源', 25 | subtext: '纯属虚构', 26 | x:'center' 27 | }, 28 | tooltip : { 29 | trigger: 'item', 30 | formatter: "{a}
{b} : {c} ({d}%)" 31 | }, 32 | legend: { 33 | orient: 'vertical', 34 | left: 'left', 35 | data: ['直接访问','邮件营销','联盟广告','视频广告','搜索引擎'] 36 | } 37 | } 38 | 39 | // 模拟数据 40 | setTimeout(function(){ 41 | option.series = [ 42 | { 43 | name: '访问来源', 44 | type: 'pie', 45 | radius : '55%', 46 | center: ['50%', '60%'], 47 | data:[ 48 | {value:335, name:'直接访问'}, 49 | {value:310, name:'邮件营销'}, 50 | {value:234, name:'联盟广告'}, 51 | {value:135, name:'视频广告'}, 52 | {value:1548, name:'搜索引擎'} 53 | ], 54 | itemStyle: { 55 | emphasis: { 56 | shadowBlur: 10, 57 | shadowOffsetX: 0, 58 | shadowColor: 'rgba(0, 0, 0, 0.5)' 59 | } 60 | } 61 | } 62 | ] 63 | 64 | callback(option); 65 | }, 500) 66 | } 67 | 68 | }; 69 | 70 | const Feature = FeatureSetConfig(graph_conf2); 71 | 72 | export default Feature; 73 | -------------------------------------------------------------------------------- /src/components/common/CreateForm.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Form, Modal, Button } from 'antd'; 3 | 4 | import CFormItem from './CreateFormItem'; 5 | 6 | let CForm = React.createClass({ 7 | getInitialState: function() { 8 | return { visible: false }; 9 | }, 10 | 11 | render: function() { 12 | const self = this; 13 | const CType = this.props.CType; 14 | 15 | const { getFieldDecorator } = this.props.form; 16 | const formItemLayout = { 17 | labelCol: { span: 6 }, 18 | wrapperCol: { span: 18 }, 19 | }; 20 | 21 | return CType ? 22 |
23 | 24 | 25 |
26 | { 27 | CType.map(function(item){ 28 | //return self.dealConfigCType(item); 29 | return 30 | }) 31 | } 32 | 33 |
34 |
: 35 |
36 | }, 37 | 38 | handleCreate: function(){ 39 | 40 | console.log('收到表单值:', this.props.form.getFieldsValue()); 41 | 42 | this.props.form.validateFields((errors, values) => { 43 | if (!!errors) { 44 | console.log('Errors in form!!!'); 45 | return; 46 | }else{ 47 | console.log('Submit!!!'); 48 | this.props.submit(values); 49 | this.hideModal(); 50 | } 51 | }); 52 | //this.props.submit(this.props.form.getFieldsValue()); 53 | 54 | }, 55 | 56 | handleReset: function() { 57 | this.props.form.resetFields(); 58 | }, 59 | 60 | showModal: function() { 61 | this.setState({ visible: true }); 62 | }, 63 | 64 | hideModal: function() { 65 | this.setState({ visible: false }); 66 | this.handleReset(); 67 | } 68 | }); 69 | 70 | CForm = Form.create()(CForm); 71 | 72 | export default CForm; 73 | -------------------------------------------------------------------------------- /src/components/common/BDUploader.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * 百度图片上传react组件 3 | * 参数为 success 回调函数 4 | * 5 | */ 6 | 7 | // 对于各个项目 重新定义图片上线组件接口 调整回调形式 8 | 9 | import React from 'react'; 10 | import { Button, Icon, message } from 'antd'; 11 | import baidubce from 'bce-sdk-js'; 12 | 13 | let config = { 14 | endpoint: 'http://bj.bcebos.com', //传入Bucket所在区域域名 15 | credentials: { 16 | ak: '******', //您的AccessKey 17 | sk: '******' //您的SecretAccessKey 18 | } 19 | }; 20 | 21 | let client = new baidubce.BosClient(config); 22 | 23 | const createKey = function(ext){ 24 | let date = new Date(); 25 | 26 | let year = date.getFullYear(); 27 | let month = date.getMonth()+1; 28 | month = (month < 10) ? '0' + month: month; 29 | 30 | let day = date.getDate(); 31 | day = (day < 10) ? '0' + day: day; 32 | 33 | return year + '/' + month + '/' + day + '/' + (+new Date())+ '.'+ext; 34 | } 35 | 36 | // 百度浏览器特定文件上传组件 37 | let BDUploader = React.createClass({ 38 | getInitialState: function() { 39 | return { 40 | 41 | }; 42 | }, 43 | 44 | render: function() { 45 | return
46 | 49 | 50 |
; 51 | }, 52 | 53 | openFileInput: function(e){ 54 | this.refs.fileInput.click(); 55 | }, 56 | uploadImg: function(e){ 57 | let self = this; 58 | 59 | let file = e.target.files[0]; // 获取要上传的文件 60 | let ext = file.name.split(/\./g).pop(); 61 | 62 | let key = createKey(ext); // 保存到bos时的key,您可更改,默认以文件名作为key 63 | let mimeType = baidubce.MimeType.guess(ext); 64 | 65 | client.putObjectFromBlob("mbrowser", key, file, { 66 | 'Content-Type': /^text\//.test(mimeType)? mimeType+'; charset=UTF-8': mimeType 67 | }).then(function (res) { 68 | // 上传完成,添加您的代码 69 | let imgUrl = config.endpoint+'/v1/mbrowser/'+key; 70 | console.log('上传成功', imgUrl); 71 | self.props.success&&self.props.success(imgUrl); 72 | }).catch(function (err) { 73 | // 上传失败,添加您的代码 74 | self.props.error&&self.props.error(error); 75 | }); 76 | } 77 | }); 78 | 79 | export default BDUploader; 80 | -------------------------------------------------------------------------------- /src/components/feature/Feature1-1.jsx: -------------------------------------------------------------------------------- 1 | // 纯数据展现情况列表 2 | import React from 'react'; 3 | 4 | import FeatureSetConfig from '../common/FeatureSetConfig'; 5 | import Reqwest from 'reqwest'; 6 | 7 | //import testData from '../common/test-data'; 8 | 9 | // 增加(Create)、重新取得数据(Retrieve)、更新(Update)和删除(Delete) 10 | const table_conf = { 11 | 12 | type: 'tableList', // tableList graphList simpleObject complexObject 13 | 14 | // 初始化展现的数据,使用callback 回传列表数据 15 | // 需要手动添加唯一id key 16 | // callback 组件数据的回调函数(接受列表数据参数) 17 | initData: function(callback){ 18 | // 接口调用数据形式 19 | Reqwest({ 20 | url: '/api/example', 21 | data: {}, 22 | 23 | type: 'json', 24 | success: function (data) { 25 | let list = data.data; 26 | list.forEach(function(ele) { 27 | ele.key = ele.id; 28 | }); 29 | callback(list); 30 | } 31 | }); 32 | }, 33 | 34 | // table 列表展现配置 35 | // { 36 | // title table显示表题 37 | // dataIndex 显示数据中的key 38 | // type 展现形式 (string image link) 39 | // render 自定义展现形式 参数 (当前数据,当前对象数据) 40 | // sort 是否需要排序功能 41 | // width 自定义该列宽度 否则等分 42 | // } 43 | // 44 | // table 列表头标题 45 | columns: [ 46 | { 47 | title: 'ID', // table header 文案 48 | dataIndex: 'id', // 数据对象内的属性,也做react vdom 的key 49 | type: 'string', // table 内显示的类型 50 | sort: true, // 是否需要排序 51 | },{ 52 | title: 'DOCID', // table header 文案 53 | dataIndex: 'docid', // 数据对象内的属性,也做react vdom 的key 54 | type: 'string', // table 内显示的类型 55 | sort: true, // 是否需要排序 56 | }, { 57 | title: '来源', 58 | dataIndex: 'source', 59 | type: 'string' 60 | },{ 61 | title: '标题', 62 | dataIndex: 'title', 63 | type: 'string' 64 | }, { 65 | title: '链接', 66 | dataIndex: 'link', 67 | type: 'link', 68 | render: (text) => ( 69 | 链接 70 | ), 71 | },{ 72 | title: '日期', 73 | dataIndex: 'date', 74 | type: 'string', 75 | }, 76 | { 77 | title: '图片', 78 | dataIndex: 'image', 79 | type: 'image' 80 | } 81 | ] 82 | 83 | }; 84 | 85 | const Feature = FeatureSetConfig(table_conf); 86 | 87 | export default Feature; 88 | -------------------------------------------------------------------------------- /src/components/common/CreateTextItem.jsx: -------------------------------------------------------------------------------- 1 | // 普通数据展现的创建 目前只用于simple object 的数据展现 2 | 3 | import React from 'react'; 4 | import moment from 'moment'; 5 | import { Form, Select, Input, Button, Icon , DatePicker, TimePicker, Radio, Switch, Cascader, Checkbox } from 'antd'; 6 | import { Upload, Modal, message } from 'antd'; 7 | 8 | import BDUploader from './BDUploader'; 9 | 10 | const FormItem = Form.Item; 11 | const Option = Select.Option; 12 | const RadioGroup = Radio.Group; 13 | 14 | let CTextItem = React.createClass({ 15 | getInitialState: function() { 16 | return { 17 | img_url:'' 18 | }; 19 | }, 20 | 21 | render: function() { 22 | const formItemLayout = this.props.formItemLayout || {}; 23 | const item = this.props.item || {}; 24 | 25 | if(item.render){ 26 | return 30 | 31 | {item.render(item.value)} 32 | 33 | }else{ 34 | switch (item.type){ 35 | case 'string': 36 | return 40 | 41 | {item.value} 42 | 43 | break; 44 | 45 | case 'link': 46 | return 50 | 51 | {item.value} 52 | 53 | 54 | break; 55 | 56 | case 'image': 57 | return 61 | 62 | {item.value}
63 | 64 | 65 |
66 | break; 67 | 68 | default: 69 | return ; 70 | break; 71 | } 72 | } 73 | 74 | } 75 | }); 76 | 77 | export default CTextItem; 78 | -------------------------------------------------------------------------------- /src/components/feature/Feature1-2.jsx: -------------------------------------------------------------------------------- 1 | // 纯数据展现情况列表 2 | import React from 'react'; 3 | import Reqwest from 'reqwest'; 4 | 5 | import CopyClipboard from '../common/CopyClipboard'; 6 | import FeatureSetConfig from '../common/FeatureSetConfig'; 7 | 8 | // 增加(Create)、重新取得数据(Retrieve)、更新(Update)和删除(Delete) 9 | const table_conf = { 10 | 11 | type: 'tableList', // tableList graphList simpleObject complexObject 12 | 13 | // 初始化展现的数据,使用callback 回传列表数据 14 | // 需要手动添加唯一id key 15 | // callback 组件数据的回调函数(接受列表数据参数) 16 | initData: function(callback){ 17 | Reqwest({ 18 | url: '/api/example2', 19 | data: {}, 20 | 21 | type: 'json', 22 | success: function (data) { 23 | let list = data.data; 24 | list.forEach(function(ele) { 25 | ele.key = ele.id; 26 | }); 27 | callback(list); 28 | } 29 | }); 30 | }, 31 | 32 | // table 列表展现配置 33 | // { 34 | // title table显示表题 35 | // dataIndex 显示数据中的key 36 | // type 展现形式 (string image link) 37 | // render 自定义展现形式 参数 (当前数据,当前对象数据) 38 | // sort 是否需要排序功能 39 | // width 自定义该列宽度 否则等分 40 | // } 41 | // 42 | // table 列表头标题 43 | columns: [ 44 | { 45 | title: 'ID', // table header 文案 46 | dataIndex: 'id', // 数据对象内的属性,也做react vdom 的key 47 | type: 'string', // table 内显示的类型 48 | sort: true, // 是否需要排序 49 | width: 50 50 | },{ 51 | title: 'NID', // table header 文案 52 | dataIndex: 'nid', // 数据对象内的属性,也做react vdom 的key 53 | type: 'string', // table 内显示的类型 54 | width: 180 55 | }, { 56 | title: '新闻标题', 57 | dataIndex: 'title', 58 | type: 'string', 59 | 60 | },{ 61 | title: '落地页链接', 62 | render: (text, item) => ( 落地页链接), 63 | width: 80 64 | },{ 65 | title: '最后修改时间', 66 | dataIndex: 'update_time', 67 | type: 'string', 68 | width: 150 69 | },{ 70 | title: '操作', 71 | type: 'operate', // 操作的类型必须为 operate 72 | width: 150, 73 | btns: [{ 74 | text: 'console输出', 75 | callback: function(item){ 76 | console.log(item) 77 | } 78 | },{ 79 | render: (text, item) => () 80 | }], 81 | } 82 | ] 83 | 84 | }; 85 | 86 | const Feature = FeatureSetConfig(table_conf); 87 | 88 | export default Feature; 89 | -------------------------------------------------------------------------------- /src/components/feature/Feature1-1-1.jsx: -------------------------------------------------------------------------------- 1 | // 纯数据展现情况列表 2 | import React from 'react'; 3 | import Reqwest from 'reqwest'; 4 | 5 | import CopyClipboard from '../common/CopyClipboard'; 6 | import FeatureSetConfig from '../common/FeatureSetConfig'; 7 | 8 | // 增加(Create)、重新取得数据(Retrieve)、更新(Update)和删除(Delete) 9 | const table_conf = { 10 | 11 | type: 'tableList', // tableList graphList simpleObject complexObject 12 | 13 | // 接口分页处理 14 | // callback 回传列表数据 第二参数接受 总数与每页数目 15 | // 需要手动添加唯一id key 16 | pageData: function(num, callback){ 17 | Reqwest({ 18 | url: '/api/example2', 19 | data: { 20 | page:num, 21 | pageSize: 20 22 | }, 23 | 24 | type: 'json', 25 | success: function (data) { 26 | let list = data.data; 27 | list.forEach(function(ele) { 28 | ele.key = ele.id; 29 | }); 30 | callback(list, { 31 | total: 399, 32 | pageSize: 20 33 | }); 34 | } 35 | }); 36 | }, 37 | 38 | // table 列表展现配置 39 | // { 40 | // title table显示表题 41 | // dataIndex 显示数据中的key 42 | // type 展现形式 (string image link) 43 | // render 自定义展现形式 参数 (当前数据,当前对象数据) 44 | // sort 是否需要排序功能 45 | // width 自定义该列宽度 否则等分 46 | // } 47 | // 48 | // table 列表头标题 49 | columns: [ 50 | { 51 | title: 'ID', // table header 文案 52 | dataIndex: 'id', // 数据对象内的属性,也做react vdom 的key 53 | type: 'string', // table 内显示的类型 54 | sort: true, // 是否需要排序 55 | width: 50 56 | },{ 57 | title: 'NID', // table header 文案 58 | dataIndex: 'nid', // 数据对象内的属性,也做react vdom 的key 59 | type: 'string', // table 内显示的类型 60 | width: 180 61 | }, { 62 | title: '新闻标题', 63 | dataIndex: 'title', 64 | type: 'string', 65 | 66 | },{ 67 | title: '落地页链接', 68 | render: (text, item) => ( 落地页链接), 69 | width: 80 70 | },{ 71 | title: '最后修改时间', 72 | dataIndex: 'update_time', 73 | type: 'string', 74 | width: 150 75 | },{ 76 | title: '操作', 77 | type: 'operate', // 操作的类型必须为 operate 78 | width: 150, 79 | btns: [{ 80 | text: 'console输出', 81 | callback: function(item){ 82 | console.log(item) 83 | } 84 | },{ 85 | render: (text, item) => () 86 | }], 87 | } 88 | ] 89 | 90 | }; 91 | 92 | const Feature = FeatureSetConfig(table_conf); 93 | 94 | export default Feature; 95 | -------------------------------------------------------------------------------- /src/components/feature/Feature1-3.jsx: -------------------------------------------------------------------------------- 1 | // 含有可操作 table 栏的数据展示 2 | import React from 'react'; 3 | 4 | import FeatureSetConfig from '../common/FeatureSetConfig'; 5 | import Reqwest from 'reqwest'; 6 | 7 | 8 | const conf = { 9 | 10 | type: 'tableList', 11 | 12 | // 初始化页面的数据 回调函数传入 items 列表 13 | initData: function(callback){ 14 | 15 | Reqwest({ 16 | url: '/api/example', 17 | data: {}, 18 | 19 | type: 'json', 20 | success: function (data) { 21 | let list = data.data; 22 | let i = 0; 23 | list.forEach(function(ele) { 24 | ele.key = i++; 25 | }); 26 | callback(list); 27 | } 28 | }); 29 | 30 | }, 31 | 32 | // table 表单字段 33 | columns: [ 34 | { 35 | title: 'KEY', // table header 文案 36 | dataIndex: 'key', // 数据对象内的属性,也做react vdom 的key 37 | type: 'string', // table 内显示的类型 38 | sort: true, // 是否需要排序 39 | }, { 40 | title: '标题', 41 | dataIndex: 'title', 42 | type: 'string' 43 | }, { 44 | title: '链接', 45 | dataIndex: 'link', 46 | type: 'link' 47 | }, { 48 | title: '操作', 49 | type: 'operate', // 操作的类型必须为 operate 50 | btns: [{ 51 | text: 'console输出', 52 | callback: function(item){ 53 | console.log(item) 54 | } 55 | }], // 可选 56 | } 57 | ], 58 | 59 | // 可设置的查询字段 60 | RType:[ 61 | { 62 | name: 'id', 63 | label: '唯一标识', 64 | type: 'string', 65 | placeholder: '请输入标示名称' 66 | },{ 67 | name: 'date', 68 | label: '项目开始时间', 69 | type: 'date' 70 | },{ 71 | name: 'stype', 72 | label: '项目类型Select', 73 | type: 'select', 74 | defaultValue: 'one', 75 | options:[{ 76 | text: '选项一', 77 | value: 'one' 78 | },{ 79 | text: '选项二', 80 | value: 'two' 81 | },{ 82 | text: '选项三', 83 | value: 'three' 84 | }] 85 | },{ 86 | name: 'rtype', 87 | label: '项目类型Radio', 88 | type: 'radio', 89 | defaultValue: 'one', 90 | options:[{ 91 | text: '选项一', 92 | value: 'one' 93 | },{ 94 | text: '选项二', 95 | value: 'two' 96 | },{ 97 | text: '选项三', 98 | value: 'three' 99 | }] 100 | },{ 101 | name: 'ischange', 102 | label: '是否过滤', 103 | type: 'switch', 104 | defaultValue: false 105 | } 106 | 107 | ], 108 | // 查询操作回调 109 | Retrieve: function(data, callback){ 110 | 111 | console.log(data); 112 | 113 | Reqwest({ 114 | url: '/api/example2', 115 | data: {}, 116 | 117 | type: 'json', 118 | success: function (data) { 119 | let list = data.data; 120 | let i = 0; 121 | list.forEach(function(ele) { 122 | ele.key = i++; 123 | }); 124 | 125 | // 查询成功 传入列表数据 126 | callback(list); 127 | } 128 | }); 129 | } 130 | 131 | }; 132 | 133 | const Feature = FeatureSetConfig(conf); 134 | 135 | export default Feature; 136 | -------------------------------------------------------------------------------- /src/components/feature/Feature1-4.jsx: -------------------------------------------------------------------------------- 1 | // 含有可操作 table 栏的数据展示 2 | import React from 'react'; 3 | 4 | import FeatureSetConfig from '../common/FeatureSetConfig'; 5 | 6 | import Immutable from 'immutable'; 7 | import Reqwest from 'reqwest'; 8 | 9 | 10 | const conf = { 11 | 12 | type: 'tableList', 13 | 14 | // 初始化页面的数据 回调函数传入 items 列表 15 | initData: function(callback){ 16 | 17 | // 接口调用数据形式 18 | Reqwest({ 19 | url: '/api/oneList', 20 | data: {}, 21 | 22 | type: 'json', 23 | success: function (data) { 24 | let list = data.data; 25 | list.forEach(function(ele) { 26 | ele.key = ele.id; 27 | }); 28 | callback(list); 29 | } 30 | }); 31 | 32 | }, 33 | 34 | columns: [ 35 | { 36 | title: 'ID', 37 | dataIndex: 'id', 38 | type: 'string' 39 | }, { 40 | title: '邮箱', 41 | dataIndex: 'email', 42 | type: 'string' 43 | }, { 44 | title: '日期', 45 | dataIndex: 'date', 46 | type: 'string' 47 | },{ 48 | title: '图片', 49 | dataIndex: 'image', 50 | type: 'image' 51 | },{ 52 | title: 'ischange', 53 | dataIndex: 'ischange', 54 | type: 'string' 55 | },{ 56 | title: 'rtype', 57 | dataIndex: 'rtype', 58 | type: 'string' 59 | },{ 60 | title: 'stype', 61 | dataIndex: 'stype', 62 | type: 'string' 63 | }, 64 | ], 65 | 66 | // 模拟添加数据的接口 回调 67 | Create: function(data, callback){ 68 | 69 | // ... 操作添加数据的请求 70 | console.log(data); 71 | 72 | // 需要设置key 73 | data.key = data.id; 74 | data.date = data.date.format("YYYY-MM-DD hh:mm:ss"); 75 | // 模拟请求创建成功的回调 76 | setTimeout(function(){ 77 | callback(data); 78 | }, 1000); 79 | }, 80 | 81 | 82 | // 创建项目所需的字段 与 更新项目所需的字段 83 | // rules 规范可见 https://github.com/yiminghe/async-validator 84 | CType: [ 85 | { 86 | name: 'id', 87 | label: '唯一标识', 88 | type: 'string', 89 | placeholder: '请输入标示名称', 90 | rules: [{ required: true, min: 5, message: '用户名至少为 5 个字符' }] 91 | },{ 92 | name: 'email', 93 | label: '唯一标识', 94 | type: 'string', 95 | placeholder: '请输入标示名称', 96 | rules: [{ required: true, type: 'email', message: '请输入正确的邮箱地址' }] 97 | },{ 98 | name: 'date', 99 | label: '项目开始时间', 100 | type: 'date', 101 | },{ 102 | name: 'stype', 103 | label: '项目类型Select', 104 | type: 'select', 105 | defaultValue: 'one', 106 | options:[{ 107 | text: '选项一', 108 | value: 'one' 109 | },{ 110 | text: '选项二', 111 | value: 'two' 112 | },{ 113 | text: '选项三', 114 | value: 'three' 115 | }] 116 | },{ 117 | name: 'rtype', 118 | label: '项目类型Radio', 119 | type: 'radio', 120 | defaultValue: 'one', 121 | options:[{ 122 | text: '选项一', 123 | value: 'one' 124 | },{ 125 | text: '选项二', 126 | value: 'two' 127 | },{ 128 | text: '选项三', 129 | value: 'three' 130 | }] 131 | },{ 132 | name: 'ischange', 133 | label: '是否过滤', 134 | type: 'switch' 135 | },{ 136 | name: 'image', 137 | label: '背景图片', 138 | type: 'imageUpload' 139 | } 140 | ] 141 | 142 | }; 143 | 144 | const Feature = FeatureSetConfig(conf); 145 | 146 | export default Feature; 147 | -------------------------------------------------------------------------------- /src/components/feature/Feature1-5.jsx: -------------------------------------------------------------------------------- 1 | // 含有可操作 table 栏的数据展示 2 | import React from 'react'; 3 | 4 | import FeatureSetConfig from '../common/FeatureSetConfig'; 5 | 6 | import Immutable from 'immutable'; 7 | import Reqwest from 'reqwest'; 8 | 9 | const conf = { 10 | 11 | type: 'tableList', 12 | 13 | // 初始化页面的数据 回调函数传入 items 列表 14 | initData: function(callback){ 15 | 16 | // 接口调用数据形式 17 | Reqwest({ 18 | url: '/api/oneList', 19 | data: {}, 20 | 21 | type: 'json', 22 | success: function (data) { 23 | let list = data.data; 24 | list.forEach(function(ele) { 25 | ele.key = ele.id; 26 | }); 27 | callback(list); 28 | } 29 | }); 30 | 31 | }, 32 | 33 | columns: [ 34 | { 35 | title: 'ID', 36 | dataIndex: 'id', 37 | type: 'string' 38 | }, { 39 | title: '邮箱', 40 | dataIndex: 'email', 41 | type: 'string' 42 | }, { 43 | title: '日期', 44 | dataIndex: 'date', 45 | type: 'string' 46 | },{ 47 | title: '图片', 48 | dataIndex: 'image', 49 | type: 'image' 50 | },{ 51 | title: 'ischange', 52 | dataIndex: 'ischange', 53 | type: 'string' 54 | },{ 55 | title: 'rtype', 56 | dataIndex: 'rtype', 57 | type: 'string' 58 | },{ 59 | title: 'stype', 60 | dataIndex: 'stype', 61 | type: 'string' 62 | },{ 63 | title: '操作', 64 | type: 'operate', // 操作的类型必须为 operate 65 | btns: [{ 66 | text: '更新', 67 | type: 'update' 68 | },{ 69 | text: '展示', 70 | callback: function(item){ 71 | console.log(item) 72 | } 73 | }], // 可选 74 | 75 | } 76 | ], 77 | 78 | 79 | Update:function(data, callback){ 80 | console.log(data); 81 | 82 | // 这块请求更新数据 成功回调 83 | data.key = data.id; 84 | callback(data); 85 | }, 86 | 87 | 88 | // 创建项目所需的字段 与 更新项目所需的字段 89 | // rules 规范可见 https://github.com/yiminghe/async-validator 90 | UType: [ 91 | { 92 | name: 'id', 93 | label: '唯一标识', 94 | type: 'string', 95 | placeholder: '请输入标示名称', 96 | rules: [{ required: true, min: 5, message: '用户名至少为 5 个字符' }] 97 | },{ 98 | name: 'email', 99 | label: '唯一标识', 100 | type: 'string', 101 | placeholder: '请输入标示名称', 102 | rules: [{ required: true, type: 'email', message: '请输入正确的邮箱地址' }] 103 | },{ 104 | name: 'date', 105 | label: '项目开始时间', 106 | type: 'date', 107 | },{ 108 | name: 'stype', 109 | label: '项目类型Select', 110 | type: 'select', 111 | defaultValue: 'one', 112 | options:[{ 113 | text: '选项一', 114 | value: 'one' 115 | },{ 116 | text: '选项二', 117 | value: 'two' 118 | },{ 119 | text: '选项三', 120 | value: 'three' 121 | }] 122 | },{ 123 | name: 'rtype', 124 | label: '项目类型Radio', 125 | type: 'radio', 126 | defaultValue: 'one', 127 | options:[{ 128 | text: '选项一', 129 | value: 'one' 130 | },{ 131 | text: '选项二', 132 | value: 'two' 133 | },{ 134 | text: '选项三', 135 | value: 'three' 136 | }] 137 | },{ 138 | name: 'ischange', 139 | label: '是否过滤', 140 | type: 'switch' 141 | },{ 142 | name: 'image', 143 | label: '背景图片', 144 | type: 'imageUpload' 145 | } 146 | ] 147 | 148 | }; 149 | 150 | const Feature = FeatureSetConfig(conf); 151 | 152 | export default Feature; 153 | -------------------------------------------------------------------------------- /src/components/feature/Feature5-2.jsx: -------------------------------------------------------------------------------- 1 | // 具体文档参照 Tinymce 2 | import React from 'react'; 3 | import Reqwest from 'reqwest'; 4 | 5 | import BDUploader from '../common/BDUploader'; 6 | import CFormItem from '../common/CreateFormItem'; 7 | 8 | import { Form, Input, Button } from 'antd'; 9 | 10 | const FormItem = Form.Item; 11 | 12 | let Feature = React.createClass({getInitialState: function(){ 13 | return { 14 | imgUrl: '', 15 | valueString: '' 16 | } 17 | }, 18 | render: function() { 19 | 20 | let fields = [ 21 | { 22 | name: 'string', 23 | label: '唯一标识', 24 | type: 'string', 25 | placeholder: '请输入标示名称' 26 | },{ 27 | name: 'date', 28 | label: '开始时间', 29 | type: 'date' 30 | },{ 31 | name: 'select', 32 | label: '项目类型', 33 | type: 'select', 34 | defaultValue: 'one', 35 | options:[{ 36 | text: '选项一', 37 | value: 'one' 38 | },{ 39 | text: '选项二', 40 | value: 'two' 41 | },{ 42 | text: '选项三', 43 | value: 'three' 44 | }] 45 | },{ 46 | name: 'cascader', 47 | label: '项目类型', 48 | type: 'cascader', 49 | options:[{ 50 | value: 'zhejiang', 51 | label: 'Zhejiang', 52 | children: [{ 53 | value: 'hangzhou', 54 | label: 'Hangzhou', 55 | children: [{ 56 | value: 'xihu', 57 | label: 'West Lake', 58 | }], 59 | }], 60 | },{ 61 | value: 'jiangsu', 62 | label: 'Jiangsu', 63 | children: [{ 64 | value: 'nanjing', 65 | label: 'Nanjing', 66 | children: [{ 67 | value: 'zhonghuamen', 68 | label: 'Zhong Hua Men', 69 | }], 70 | }], 71 | }] 72 | },{ 73 | name: 'checkbox', 74 | label: '项目类型', 75 | type: 'checkbox', 76 | defaultValue: ['Apple'], 77 | options:[ 78 | { label: 'Apple', value: 'Apple' }, 79 | { label: 'Pear', value: 'Pear' }, 80 | { label: 'Orange', value: 'Orange' }] 81 | },{ 82 | name: 'radio', 83 | label: '项目类型', 84 | type: 'radio', 85 | defaultValue: 'one', 86 | options:[{ 87 | text: '选项一', 88 | value: 'one' 89 | },{ 90 | text: '选项二', 91 | value: 'two' 92 | },{ 93 | text: '选项三', 94 | value: 'three' 95 | }] 96 | },{ 97 | name: 'switch', 98 | label: '是否过滤', 99 | type: 'switch', 100 | defaultValue: false 101 | } 102 | ]; 103 | 104 | const { getFieldDecorator } = this.props.form; 105 | 106 | return
107 |
108 | 111 | 112 | 113 |
114 | 115 |
116 | { 117 | fields.map(function(item){ 118 | item.defaultValue = item.defaultValue||''; 119 | return 120 | }) 121 | } 122 | 123 | 124 |
125 | 126 |

{this.state.imgUrl}

127 |
128 | 129 | 130 | 131 | 132 | 133 |

{this.state.valueString}

134 |
135 | }, 136 | 137 | getFromData: function(){ 138 | console.log(this.props.form.getFieldsValue()); 139 | 140 | this.setState({ 141 | valueString:JSON.stringify(this.props.form.getFieldsValue()) 142 | }); 143 | }, 144 | 145 | uploadImgSuccess: function(url){ 146 | this.setState({ 147 | imgUrl:url 148 | }); 149 | }, 150 | }); 151 | 152 | Feature = Form.create()(Feature); 153 | export default Feature; -------------------------------------------------------------------------------- /src/components/feature/Feature5-1.jsx: -------------------------------------------------------------------------------- 1 | // 具体文档参照 Tinymce 2 | import React from 'react'; 3 | import TinyMCE from 'react-tinymce'; 4 | import Reqwest from 'reqwest'; 5 | 6 | // import BDUploader from '../common/BDUploader'; 7 | // import CFormItem from '../common/CreateFormItem'; 8 | 9 | import { Form, Input, Button } from 'antd'; 10 | 11 | // const FormItem = Form.Item; 12 | 13 | let Feature = React.createClass({ 14 | getInitialState: function(){ 15 | return { 16 | value: '' 17 | } 18 | }, 19 | render: function() { 20 | let config = { 21 | content: this.state.value, 22 | config: { 23 | height: '250', 24 | plugins: [ 25 | "advlist autolink lists charmap print preview hr anchor pagebreak spellchecker", 26 | "searchreplace wordcount visualblocks visualchars fullscreen insertdatetime nonbreaking", 27 | "save table contextmenu directionality emoticons paste textcolor" 28 | ], 29 | toolbar: "insertfile undo redo | styleselect fontselect fontsizeselect| bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | l | print preview fullpage | forecolor backcolor", 30 | }, 31 | onChange: this.handleEditorChange 32 | }; 33 | 34 | // let fields = [ 35 | // { 36 | // name: 'id', 37 | // label: '唯一标识', 38 | // type: 'string', 39 | // placeholder: '请输入标示名称' 40 | // },{ 41 | // name: 'date', 42 | // label: '开始时间', 43 | // type: 'date' 44 | // },{ 45 | // name: 'stype', 46 | // label: '项目类型', 47 | // type: 'select', 48 | // defaultValue: 'one', 49 | // options:[{ 50 | // text: '选项一', 51 | // value: 'one' 52 | // },{ 53 | // text: '选项二', 54 | // value: 'two' 55 | // },{ 56 | // text: '选项三', 57 | // value: 'three' 58 | // }] 59 | // },{ 60 | // name: 'rtype', 61 | // label: '项目类型', 62 | // type: 'radio', 63 | // defaultValue: 'one', 64 | // options:[{ 65 | // text: '选项一', 66 | // value: 'one' 67 | // },{ 68 | // text: '选项二', 69 | // value: 'two' 70 | // },{ 71 | // text: '选项三', 72 | // value: 'three' 73 | // }] 74 | // },{ 75 | // name: 'ischange', 76 | // label: '是否过滤', 77 | // type: 'switch', 78 | // defaultValue: false 79 | // } 80 | 81 | // ]; 82 | 83 | // const { getFieldDecorator } = this.props.form; 84 | // const updateItem = {}; 85 | 86 | // return
87 | //
88 | // 91 | // 92 | // 93 | 94 | // 95 | // 96 | // 97 | // 98 | // 99 | // 100 | //
101 | 102 | //
103 | // { 104 | // fields.map(function(item){ 105 | // item.defaultValue = updateItem[item.name]||item.defaultValue||''; 106 | // //return self.dealConfigUType(item, defaultValue); 107 | // return 108 | // }) 109 | // } 110 | // 111 | 112 | //
113 | // 114 | //

{this.state.imgUrl}

115 | //
116 | //

{this.states.value}

117 | // 118 | //
119 | 120 | return
121 |

{this.state.value}

122 | 123 |
124 | }, 125 | 126 | // getFromData: function(){ 127 | // console.log(this.props.form.getFieldsValue()) 128 | // }, 129 | 130 | // uploadImgSuccess: function(url){ 131 | // this.setState({ 132 | // imgUrl:url 133 | // }); 134 | // }, 135 | handleEditorChange: function(e){ 136 | this.setState({ 137 | value: this.getTinymceContent() 138 | }); 139 | }, 140 | setTinymceContent: function(value){ 141 | tinymce.get(0).setContent(value); 142 | }, 143 | getTinymceContent: function(){ 144 | return tinymce.get(0).getContent(); 145 | } 146 | }); 147 | 148 | export default Feature; -------------------------------------------------------------------------------- /mock/example.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const oneDate = { 4 | bdsourceid: "311010007", 5 | categoryid: "1", 6 | stype: 'one', 7 | date: "2016-09-01 18:12:45", 8 | docid: "9547448815187683782", 9 | image: "https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=2106183011,3024965378&fm=80&w=179&h=119&img.JPEG", 10 | link: "http://www.chinanews.com/sh/2016/09-01/7991310.shtml", 11 | source: "社会新闻", 12 | summary: "蔡某妍在其遗书中写下受骗经过,此前,蔡某妍手机接收到一条中奖短信,点进去填写了相关信息,并按照指引打电话给对方,对方让她交钱,蔡某妍拒绝交钱。", 13 | title: "开学前夕疑遭电信诈骗学费 揭阳准女大学生留遗书自杀", 14 | weight: "99", 15 | src_type: "text" 16 | } 17 | 18 | const table2List = [ 19 | { 20 | id: "1", 21 | title: "111111互联网金融最强监管政策来袭,行业强化约束正本清源", 22 | link: "http://news.xhby.net/system/2016/09/18/029642755.shtml", 23 | nid: "13606399328377680923", 24 | insert_time: "2016-09-19 19:31:40", 25 | update_time: "2016-09-19 19:32:10" 26 | }, { 27 | id: "2", 28 | title: "互联网金融最强监管政策来袭,行业强化约束正本清源", 29 | link: "http://news.xhby.net/system/2016/09/18/029642755.shtml", 30 | nid: "13606399328377680923", 31 | insert_time: "2016-09-19 19:30:39", 32 | update_time: "2016-09-19 19:30:39" 33 | }, { 34 | id: "3", 35 | title: "互联网金融最强监管政策来袭,行业强化约束正本清源", 36 | link: "http://news.xhby.net/system/2016/09/18/029642755.shtml", 37 | nid: "13606399328377680923", 38 | insert_time: "2016-09-19 19:30:31", 39 | update_time: "2016-09-19 19:30:31" 40 | }, { 41 | id: "4", 42 | title: "互联网金融最强监管政策来袭,行业强化约束正本清源", 43 | link: "http://news.xhby.net/system/2016/09/18/029642755.shtml", 44 | nid: "13606399328377680923", 45 | insert_time: "2016-09-19 18:07:44", 46 | update_time: "2016-09-19 18:07:44" 47 | }, { 48 | id: "5", 49 | title: "互联网金融最强监管政策来袭,行业强化约束正本清源", 50 | link: "http://news.xhby.net/system/2016/09/18/029642755.shtml", 51 | nid: "13606399328377680923", 52 | insert_time: "2016-09-19 18:07:29", 53 | update_time: "2016-09-19 18:07:29" 54 | } 55 | ]; 56 | 57 | const graphList = [ 58 | { 59 | name: '邮件营销', 60 | data: [120, 132, 101, 134, 90, 230, 210] 61 | }, { 62 | name: '联盟广告', 63 | data: [220, 182, 191, 234, 290, 330, 310] 64 | }, { 65 | name: '视频广告', 66 | data: [150, 232, 201, 154, 190, 330, 410] 67 | } 68 | ]; 69 | 70 | const simpleObject = { 71 | bdsourceid: "316010032", 72 | categoryid: "1", 73 | date: "2016-06-29 10:27:00", 74 | docid: "16112285443883430307", 75 | images: [{ 76 | height: "533", 77 | img: "http://img.cbs.baidu.com/imagecache/reader/mid/9/c/d/9cd6e6f4c45f3d5dcdf7dc3846ed546c.jpg", 78 | imgsize: "400,533", 79 | width: "400" 80 | }, { 81 | height: "300", 82 | img: "http://img.cbs.baidu.com/imagecache/reader/mid/8/e/6/8e62b06541d752bd3719107a1f5f0496.jpg", 83 | imgsize: "400,300", 84 | width: "400" 85 | }, { 86 | height: "533", 87 | img: "http://img.cbs.baidu.com/imagecache/reader/mid/f/9/2/f92664dedc81ce5c2d83c28aeff66eed.jpg", 88 | imgsize: "400,533", 89 | width: "400" 90 | }], 91 | images_bos: [{ 92 | height: "533", 93 | img: "http://image.cbs.baidu.com/news_topic/5170f148dbd81ecb680dd385cfd0c333.jpg", 94 | imgsize: "400,533", 95 | width: "400" 96 | }, { 97 | height: "300", 98 | img: "http://image.cbs.baidu.com/news_topic/8e62b06541d752bd3719107a1f5f0496.jpg", 99 | imgsize: "400,300", 100 | width: "400" 101 | }, { 102 | height: "533", 103 | img: "http://image.cbs.baidu.com/news_topic/f92664dedc81ce5c2d83c28aeff66eed.jpg", 104 | imgsize: "400,533", 105 | width: "400" 106 | }], 107 | img: "http://img.cbs.baidu.com/imagecache/reader/mid/9/c/d/9cd6e6f4c45f3d5dcdf7dc3846ed546c.jpg", 108 | imgsize: "400,533", 109 | keyword: "", 110 | link: "http://news.ifeng.com/a/20160629/49259851_0.shtml", 111 | mark: "0", 112 | score: 89.52380952381, 113 | source: "凤凰新闻", 114 | src_type: "text", 115 | srctype: "0", 116 | summary: " 在谅解协议中,北青报记者看到,“鉴于被告人周凌俊在案发时有精神分裂症,控制能力差,并且开庭前积极赔偿给我全部损失(略),我对被告人周凌俊的行为表示谅解,请求法院对被告人周凌俊从轻、减轻、免除死刑刑事处罚…", 117 | title: "男子砍伤9人被判死刑 8受害人请求免除死刑(图)", 118 | topic_keyword: [{ 119 | tag: "周凌俊", 120 | weight: 1 121 | }, { 122 | tag: "老周", 123 | weight: 0.52631578947368 124 | }, { 125 | tag: "北青报记者", 126 | weight: 0.50877192982456 127 | }], 128 | weight: "99", 129 | index: "1020", 130 | groupbegin: "0", 131 | listcount: 4 132 | }; 133 | 134 | function createArrDate(data, times){ 135 | let arr =[]; 136 | for (; times >= 0; times--) { 137 | data.id = times; 138 | arr.push(JSON.parse(JSON.stringify(data))); 139 | } 140 | return arr; 141 | } 142 | 143 | module.exports = { 144 | 145 | 'GET /api/example': function (req, res) { 146 | setTimeout(function () { 147 | res.json({ 148 | success: true, 149 | data: createArrDate(oneDate, 20), 150 | }); 151 | }, 500); 152 | }, 153 | 154 | 'GET /api/example2': function (req, res) { 155 | setTimeout(function () { 156 | res.json({ 157 | success: true, 158 | data: table2List, 159 | }); 160 | }, 500); 161 | }, 162 | 163 | 'GET /api/example3': function (req, res) { 164 | setTimeout(function () { 165 | res.json({ 166 | success: true, 167 | data: oneDate, 168 | }); 169 | }, 500); 170 | }, 171 | 172 | 'GET /api/example4': function (req, res) { 173 | setTimeout(function () { 174 | res.json({ 175 | success: true, 176 | data: graphList, 177 | }); 178 | }, 500); 179 | }, 180 | 181 | 'GET /api/oneList': function (req, res) { 182 | setTimeout(function () { 183 | res.json({ 184 | success: true, 185 | data: [{ 186 | date:"2016-06-29 10:27:00", 187 | id:"ddassad", 188 | email:"asd@22.cn", 189 | image:"", 190 | ischange:"false", 191 | rtype:"one", 192 | stype:"one", 193 | }], 194 | }); 195 | }, 500); 196 | }, 197 | 198 | 'GET /api/delete': function (req, res) { 199 | setTimeout(function () { 200 | res.json({ 201 | success: true 202 | }); 203 | }, 500); 204 | }, 205 | 206 | }; 207 | -------------------------------------------------------------------------------- /src/components/common/CreateFormItem.jsx: -------------------------------------------------------------------------------- 1 | // 表单独立项 用于对于表单字段的创建 2 | 3 | 4 | import React from 'react'; 5 | import moment from 'moment'; 6 | import { Form, Select, Input, Button, Icon , DatePicker, TimePicker, Radio, Switch, Cascader, Checkbox } from 'antd'; 7 | import { Upload, Modal, message } from 'antd'; 8 | 9 | import BDUploader from './BDUploader'; 10 | 11 | const FormItem = Form.Item; 12 | const Option = Select.Option; 13 | const RadioGroup = Radio.Group; 14 | 15 | // 对于使用默认的时间戳 16 | const DefaultTime = new Date(); 17 | 18 | let CFormItem = React.createClass({ 19 | getInitialState: function() { 20 | return { 21 | img_url:'' 22 | }; 23 | }, 24 | 25 | render: function() { 26 | const getFieldDecorator = this.props.getFieldDecorator; 27 | const formItemLayout = this.props.formItemLayout || {}; 28 | const item = this.props.item || {}; 29 | 30 | let defaultValue = item.defaultValue || ''; 31 | 32 | switch (item.type){ 33 | case 'string': 34 | return 38 | 39 | {getFieldDecorator(item.name, {rules:item.rules, initialValue:defaultValue})( 40 | 41 | )} 42 | 43 | break; 44 | 45 | case 'date': 46 | defaultValue = moment(defaultValue || DefaultTime, "YYYY-MM-DD hh:mm:ss"); 47 | 48 | return 52 | 53 | {getFieldDecorator(item.name, { initialValue: defaultValue})( 54 | 55 | )} 56 | 57 | break; 58 | 59 | case 'select': 60 | return 64 | 65 | {getFieldDecorator(item.name, { initialValue: defaultValue })( 66 | 73 | )} 74 | 75 | break; 76 | 77 | case 'cascader': 78 | return 82 | 83 | {getFieldDecorator(item.name, { initialValue: defaultValue })( 84 | 85 | )} 86 | 87 | 88 | break; 89 | 90 | case 'radio': 91 | return 95 | 96 | {getFieldDecorator(item.name, { initialValue: defaultValue })( 97 | 98 | { 99 | item.options.map(function(item){ 100 | return {item.text || item.value} 101 | }) 102 | } 103 | 104 | )} 105 | 106 | break; 107 | 108 | case 'checkbox': 109 | return 113 | 114 | {getFieldDecorator(item.name, { initialValue: defaultValue })( 115 | 116 | )} 117 | 118 | break; 119 | 120 | case 'switch': 121 | return 125 | 126 | {getFieldDecorator(item.name, { initialValue: defaultValue})( 127 | 128 | )} 129 | 130 | break; 131 | 132 | case 'imageUpload': 133 | defaultValue = this.state.img_url || defaultValue || ''; 134 | return 138 | 139 | {getFieldDecorator(item.name, { initialValue:defaultValue})( 140 | 141 | )} 142 | 143 | 144 | 145 | 146 | 147 | break; 148 | 149 | default: 150 | return ''; 151 | break; 152 | } 153 | }, 154 | uploadSuccess: function(url){ 155 | console.log(url) 156 | this.setState({ 157 | img_url: url 158 | }) 159 | }, 160 | changeImgUrl: function(e){ 161 | console.log(e.target.value) 162 | this.setState({ 163 | img_url: e.target.value 164 | }) 165 | } 166 | }); 167 | 168 | export default CFormItem; 169 | -------------------------------------------------------------------------------- /src/components/feature/Feature3-3.jsx: -------------------------------------------------------------------------------- 1 | // 纯数据展现情况列表 2 | import React from 'react'; 3 | 4 | import FeatureSetConfig from '../common/FeatureSetConfig'; 5 | import Reqwest from 'reqwest'; 6 | 7 | const graph_conf = { 8 | 9 | type: 'graphList', // tableList graphList simpleObject complexObject 10 | 11 | EchartStyle: { 12 | width: '100%', 13 | height: '450px' 14 | }, 15 | 16 | // 初始化展现的数据,使用callback 回传列表数据 17 | // 需要手动添加唯一id key 18 | // callback 组件数据的回调函数(接受列表数据参数) 19 | initData: function(callback){ 20 | 21 | // 参考echarts 参数 22 | var option = { 23 | title: { 24 | text: '堆叠区域图' 25 | }, 26 | tooltip : { 27 | trigger: 'axis' 28 | }, 29 | legend: { 30 | data:['邮件营销','联盟广告','视频广告'] 31 | }, 32 | toolbox: { 33 | feature: { 34 | saveAsImage: {} 35 | } 36 | }, 37 | grid: { 38 | left: '3%', 39 | right: '4%', 40 | bottom: '3%', 41 | containLabel: true 42 | }, 43 | xAxis : [ 44 | { 45 | type : 'category', 46 | boundaryGap : false, 47 | data : ['周一','周二','周三','周四','周五','周六','周日'] 48 | } 49 | ], 50 | yAxis : [ 51 | { 52 | type : 'value' 53 | } 54 | ] 55 | } 56 | 57 | // 模拟数据 58 | Reqwest({ 59 | url: '/api/example4', 60 | data: {}, 61 | 62 | type: 'json', 63 | success: function (data) { 64 | option.series = data.data; 65 | option.series.forEach(function(item) { 66 | item.type = 'line'; 67 | item.stack = '总量'; 68 | }); 69 | 70 | callback(option); 71 | } 72 | }); 73 | } 74 | 75 | }; 76 | 77 | const graph_conf2 = { 78 | 79 | type: 'graphList', // tableList graphList simpleObject complexObject 80 | style: { 81 | width: '100%', 82 | height: '450px' 83 | }, 84 | 85 | // 初始化展现的数据,使用callback 回传列表数据 86 | // 需要手动添加唯一id key 87 | // callback 组件数据的回调函数(接受列表数据参数) 88 | // 将回调数据掺入option 89 | initData: function(callback){ 90 | 91 | // 参考echarts 参数 92 | var option = { 93 | title : { 94 | text: '某站点用户访问来源', 95 | subtext: '纯属虚构', 96 | x:'center' 97 | }, 98 | tooltip : { 99 | trigger: 'item', 100 | formatter: "{a}
{b} : {c} ({d}%)" 101 | }, 102 | legend: { 103 | orient: 'vertical', 104 | left: 'left', 105 | data: ['直接访问','邮件营销','联盟广告','视频广告','搜索引擎'] 106 | } 107 | } 108 | 109 | // 模拟数据 110 | setTimeout(function(){ 111 | option.series = [ 112 | { 113 | name: '访问来源', 114 | type: 'pie', 115 | radius : '55%', 116 | center: ['50%', '60%'], 117 | data:[ 118 | {value:335, name:'直接访问'}, 119 | {value:310, name:'邮件营销'}, 120 | {value:234, name:'联盟广告'}, 121 | {value:135, name:'视频广告'}, 122 | {value:1548, name:'搜索引擎'} 123 | ], 124 | itemStyle: { 125 | emphasis: { 126 | shadowBlur: 10, 127 | shadowOffsetX: 0, 128 | shadowColor: 'rgba(0, 0, 0, 0.5)' 129 | } 130 | } 131 | } 132 | ] 133 | 134 | callback(option); 135 | }, 500) 136 | } 137 | 138 | }; 139 | 140 | const graph_conf3 = { 141 | 142 | type: 'graphList', // tableList graphList simpleObject complexObject 143 | style: { 144 | width: '100%', 145 | height: '450px' 146 | }, 147 | 148 | // 初始化展现的数据,使用callback 回传列表数据 149 | // 需要手动添加唯一id key 150 | // callback 组件数据的回调函数(接受列表数据参数) 151 | // 将回调数据掺入option 152 | initData: function(callback){ 153 | 154 | 155 | var xAxisData = []; 156 | var data1 = []; 157 | var data2 = []; 158 | for (var i = 0; i < 100; i++) { 159 | xAxisData.push('类目' + i); 160 | data1.push((Math.sin(i / 5) * (i / 5 -10) + i / 6) * 5); 161 | data2.push((Math.cos(i / 5) * (i / 5 -10) + i / 6) * 5); 162 | } 163 | 164 | // 参考echarts 参数 165 | var option = { 166 | title: { 167 | text: '柱状图动画延迟' 168 | }, 169 | legend: { 170 | data: ['bar', 'bar2'], 171 | align: 'left' 172 | }, 173 | toolbox: { 174 | // y: 'bottom', 175 | feature: { 176 | magicType: { 177 | type: ['stack', 'tiled'] 178 | }, 179 | dataView: {}, 180 | saveAsImage: { 181 | pixelRatio: 2 182 | } 183 | } 184 | }, 185 | tooltip: {}, 186 | xAxis: { 187 | data: xAxisData, 188 | silent: false, 189 | splitLine: { 190 | show: false 191 | } 192 | }, 193 | yAxis: { 194 | }, 195 | animationEasing: 'elasticOut', 196 | animationDelayUpdate: function (idx) { 197 | return idx * 5; 198 | } 199 | } 200 | 201 | // 模拟数据 202 | setTimeout(function(){ 203 | 204 | option.series = [{ 205 | name: 'bar', 206 | type: 'bar', 207 | data: data1, 208 | animationDelay: function (idx) { 209 | return idx * 10; 210 | } 211 | }, { 212 | name: 'bar2', 213 | type: 'bar', 214 | data: data2, 215 | animationDelay: function (idx) { 216 | return idx * 10 + 100; 217 | } 218 | }] 219 | 220 | callback(option); 221 | }, 500) 222 | } 223 | 224 | }; 225 | 226 | const Feature1 = FeatureSetConfig(graph_conf); 227 | const Feature2 = FeatureSetConfig(graph_conf2); 228 | const Feature3 = FeatureSetConfig(graph_conf3); 229 | 230 | const Feature = (props) => { 231 | return
232 | 233 | 234 | 235 |
; 236 | } 237 | 238 | export default Feature; 239 | -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file CMS平台整体配置文件 3 | * @author niyingfeng 4 | * 5 | * header 管理后台头部配置 6 | * title String 标题 7 | * icon String 标题图标 8 | * style Object 自定义样式 9 | * menu Array 顶部横向菜单列表 10 | * 11 | * sider 管理后台侧栏配置 12 | * menu Array sider列表 13 | * openKeys Array 默认展开的sider区 14 | * selectedKey String 默认打开的功能区 15 | * style Object 自定义样式 16 | * 17 | * main 功能区域配置 18 | * components Object 配置sider对应功能区域组件 19 | * Feature1 Object 对应sider menu 中的功能key对 应功能组件 20 | * style Object 配置样式 21 | * 22 | * userInfo 登入用户信息 23 | * name 登入用户名 24 | * aver 登入用户头像 25 | * permission 是否权限 26 | * loginUrl 无权限时跳转的链接(对于一些通用登入权限系统) 27 | */ 28 | 29 | const Config = { 30 | header: { 31 | title: '测试配置管理后台', 32 | icon: 'appstore', 33 | style: { 34 | backgroundColor: '#F5F5F5', 35 | color: '#666' 36 | }, 37 | menu: [ 38 | {title: '集合管理', key: 'bigset'} 39 | ] 40 | }, 41 | 42 | sider: { 43 | menu: [ 44 | { 45 | title: 'Table数据与功能展示', 46 | key: 'table', 47 | icon: 'bars', 48 | items: [ 49 | {title: 'table数据展示前端分页', key: 'Feature1-1'}, 50 | {title: 'table数据展示接口分页', key: 'Feature1-1-1'}, 51 | {title: 'table数据展示项2', key: 'Feature1-2'}, 52 | {title: 'table数据搜索数据操作', key: 'Feature1-3'}, 53 | {title: 'table数据增加数据操作', key: 'Feature1-4'}, 54 | {title: 'table数据修改数据操作', key: 'Feature1-5'}, 55 | {title: 'table数据删除数据操作', key: 'Feature1-6'} 56 | ] 57 | }, 58 | { 59 | title: 'simple对象数据与功能展示', 60 | key: 'object', 61 | icon: 'bars', 62 | items: [ 63 | {title: 'simple对象数据展示项', key: 'Feature2-1'}, 64 | {title: 'simple对象数据修改操作', key: 'Feature2-2'} 65 | ] 66 | }, 67 | { 68 | title: '数据可视化功能展示', 69 | key: 'echarts', 70 | icon: 'bars', 71 | items: [ 72 | {title: 'echarts 数据可视化1', key: 'Feature3-1'}, 73 | {title: 'echarts 数据可视化2', key: 'Feature3-2'}, 74 | {title: 'echarts 数据可视化3', key: 'Feature3-3'} 75 | ] 76 | }, 77 | { 78 | title: '综合功能数据展示', 79 | key: 'complex', 80 | icon: 'bars', 81 | items: [ 82 | {title: '综合数据展示', key: 'Feature4-1'} 83 | ] 84 | }, 85 | { 86 | title: '综合自定义操作项目', 87 | key: 'customOperate', 88 | icon: 'bars', 89 | items: [ 90 | {title: '富文本编辑功能展现', key: 'Feature5-1'}, 91 | {title: '自组装FromUI组件方式', key: 'Feature5-2'} 92 | ] 93 | }, 94 | 95 | // 格式示例 96 | // { 97 | // title: '导航1', 98 | // key: 'subTitle1', 99 | // icon: 'setting', 100 | // items: [ 101 | // {title: '选项1', key: 'Feature1'}, 102 | // {title: '选项2', key: 'Feature2'}, 103 | // {title: '选项3', key: 'Feature3'}, 104 | // { 105 | // title: '导航3', 106 | // key: 'subTitle3', 107 | // icon: ', 108 | // items: [ 109 | // {title: '选项6', key: 'Feature6'}, 110 | // {title: '选项7', key: 'Feature7'}, 111 | // {title: '选项8', key: 'Feature8'} 112 | // ] 113 | // } 114 | // ] 115 | // },{ 116 | // title: '导航2', 117 | // key: 'subTitle2', 118 | // icon: 'delete', 119 | // items: [ 120 | // {title: '选项4', key: 'Feature4'} 121 | // ] 122 | // },{ 123 | // title: '选项5', 124 | // key: 'Feature5' 125 | // } 126 | 127 | ], 128 | openKeys:['table','object','echarts','complex','customOperate'], 129 | selectedKey: 'Feature1-1', 130 | style: {} 131 | }, 132 | 133 | main: { 134 | components: { 135 | 'bigset': { 136 | title: 'bigset 测试', 137 | component: require('./components/feature/Feature1-1') 138 | }, 139 | 'Feature1-1': { 140 | title: 'table 普通列表数据展示 前端处理分页', 141 | component: require('./components/feature/Feature1-1') 142 | }, 143 | 'Feature1-1-1': { 144 | title: 'table 普通列表数据展示 接口请求分页', 145 | component: require('./components/feature/Feature1-1-1') 146 | }, 147 | 'Feature1-2': { 148 | title: 'table 具有相关操作数据展示', 149 | component: require('./components/feature/Feature1-2') 150 | }, 151 | 'Feature1-3': { 152 | title: 'table 数据搜索数据操作', 153 | component: require('./components/feature/Feature1-3') 154 | }, 155 | 'Feature1-4': { 156 | title: 'table 数据增加数据操作', 157 | component: require('./components/feature/Feature1-4') 158 | }, 159 | 'Feature1-5': { 160 | title: 'table 数据更新数据操作', 161 | component: require('./components/feature/Feature1-5') 162 | }, 163 | 'Feature1-6': { 164 | title: 'table 数据删除数据操作', 165 | component: require('./components/feature/Feature1-6') 166 | }, 167 | 'Feature2-1': { 168 | title: 'simple对象 数据展示', 169 | component: require('./components/feature/Feature2-1') 170 | }, 171 | 'Feature2-2': { 172 | title: 'simple对象数据修改操作', 173 | component: require('./components/feature/Feature2-2') 174 | }, 175 | 'Feature3-1': { 176 | title: '数据可视化 数据展示', 177 | component: require('./components/feature/Feature3-1') 178 | }, 179 | 'Feature3-2': { 180 | title: '数据可视化 数据展示', 181 | component: require('./components/feature/Feature3-2') 182 | }, 183 | 'Feature3-3': { 184 | title: '数据可视化 数据展示', 185 | component: require('./components/feature/Feature3-3') 186 | }, 187 | 'Feature4-1': { 188 | title: '综合数据展示', 189 | component: require('./components/feature/Feature4-1') 190 | }, 191 | 'Feature5-1': { 192 | title: '富文本编辑区域', 193 | component: require('./components/feature/Feature5-1') 194 | }, 195 | 'Feature5-2': { 196 | title: '自定义组装', 197 | component: require('./components/feature/Feature5-2') 198 | } 199 | }, 200 | style: {} 201 | }, 202 | 203 | userInfo:{ 204 | name: BaiduInfo.name || '游客', 205 | aver: BaiduInfo.aver || 'http://himg.bdimg.com/sys/portrait/item/113e68695f79696e6766656e67525e.jpg', 206 | permission: BaiduInfo.permission, 207 | loginUrl: BaiduInfo.loginUrl 208 | } 209 | } 210 | 211 | export default Config; -------------------------------------------------------------------------------- /src/components/feature/Feature4-1.jsx: -------------------------------------------------------------------------------- 1 | // 纯数据展现情况列表 2 | import React from 'react'; 3 | 4 | import FeatureSetConfig from '../common/FeatureSetConfig'; 5 | import Reqwest from 'reqwest'; 6 | import {message} from 'antd'; 7 | 8 | const graph_conf = { 9 | 10 | type: 'graphList', // tableList graphList simpleObject complexObject 11 | 12 | EchartStyle: { 13 | width: '100%', 14 | height: '450px' 15 | }, 16 | 17 | // 初始化展现的数据,使用callback 回传列表数据 18 | // 需要手动添加唯一id key 19 | // callback 组件数据的回调函数(接受列表数据参数) 20 | initData: function(callback){ 21 | 22 | // 参考echarts 参数 23 | var option = { 24 | title: { 25 | text: '堆叠区域图' 26 | }, 27 | tooltip : { 28 | trigger: 'axis' 29 | }, 30 | legend: { 31 | data:['邮件营销','联盟广告','视频广告'] 32 | }, 33 | toolbox: { 34 | feature: { 35 | saveAsImage: {} 36 | } 37 | }, 38 | grid: { 39 | left: '3%', 40 | right: '4%', 41 | bottom: '3%', 42 | containLabel: true 43 | }, 44 | xAxis : [ 45 | { 46 | type : 'category', 47 | boundaryGap : false, 48 | data : ['周一','周二','周三','周四','周五','周六','周日'] 49 | } 50 | ], 51 | yAxis : [ 52 | { 53 | type : 'value' 54 | } 55 | ] 56 | } 57 | 58 | // 模拟数据 59 | setTimeout(function(){ 60 | option.series = testData.graphList; 61 | option.series.forEach(function(item) { 62 | item.type = 'line'; 63 | item.stack = '总量' 64 | }); 65 | 66 | callback(option); 67 | }, 1000) 68 | } 69 | 70 | }; 71 | 72 | const graph_conf2 = { 73 | 74 | type: 'graphList', // tableList graphList simpleObject complexObject 75 | style: { 76 | width: '100%', 77 | height: '450px' 78 | }, 79 | 80 | // 初始化展现的数据,使用callback 回传列表数据 81 | // 需要手动添加唯一id key 82 | // callback 组件数据的回调函数(接受列表数据参数) 83 | // 将回调数据掺入option 84 | initData: function(callback){ 85 | 86 | // 参考echarts 参数 87 | var option = { 88 | title : { 89 | text: '某站点用户访问来源', 90 | subtext: '纯属虚构', 91 | x:'center' 92 | }, 93 | tooltip : { 94 | trigger: 'item', 95 | formatter: "{a}
{b} : {c} ({d}%)" 96 | }, 97 | legend: { 98 | orient: 'vertical', 99 | left: 'left', 100 | data: ['直接访问','邮件营销','联盟广告','视频广告','搜索引擎'] 101 | } 102 | } 103 | 104 | // 模拟数据 105 | setTimeout(function(){ 106 | option.series = [ 107 | { 108 | name: '访问来源', 109 | type: 'pie', 110 | radius : '55%', 111 | center: ['50%', '60%'], 112 | data:[ 113 | {value:335, name:'直接访问'}, 114 | {value:310, name:'邮件营销'}, 115 | {value:234, name:'联盟广告'}, 116 | {value:135, name:'视频广告'}, 117 | {value:1548, name:'搜索引擎'} 118 | ], 119 | itemStyle: { 120 | emphasis: { 121 | shadowBlur: 10, 122 | shadowOffsetX: 0, 123 | shadowColor: 'rgba(0, 0, 0, 0.5)' 124 | } 125 | } 126 | } 127 | ] 128 | 129 | callback(option); 130 | }, 1000) 131 | } 132 | 133 | }; 134 | 135 | const graph_conf3 = { 136 | 137 | type: 'graphList', // tableList graphList simpleObject complexObject 138 | style: { 139 | width: '100%', 140 | height: '450px' 141 | }, 142 | 143 | // 初始化展现的数据,使用callback 回传列表数据 144 | // 需要手动添加唯一id key 145 | // callback 组件数据的回调函数(接受列表数据参数) 146 | // 将回调数据掺入option 147 | initData: function(callback){ 148 | 149 | 150 | var xAxisData = []; 151 | var data1 = []; 152 | var data2 = []; 153 | for (var i = 0; i < 100; i++) { 154 | xAxisData.push('类目' + i); 155 | data1.push((Math.sin(i / 5) * (i / 5 -10) + i / 6) * 5); 156 | data2.push((Math.cos(i / 5) * (i / 5 -10) + i / 6) * 5); 157 | } 158 | 159 | // 参考echarts 参数 160 | var option = { 161 | title: { 162 | text: '柱状图动画延迟' 163 | }, 164 | legend: { 165 | data: ['bar', 'bar2'], 166 | align: 'left' 167 | }, 168 | toolbox: { 169 | // y: 'bottom', 170 | feature: { 171 | magicType: { 172 | type: ['stack', 'tiled'] 173 | }, 174 | dataView: {}, 175 | saveAsImage: { 176 | pixelRatio: 2 177 | } 178 | } 179 | }, 180 | tooltip: {}, 181 | xAxis: { 182 | data: xAxisData, 183 | silent: false, 184 | splitLine: { 185 | show: false 186 | } 187 | }, 188 | yAxis: { 189 | }, 190 | animationEasing: 'elasticOut', 191 | animationDelayUpdate: function (idx) { 192 | return idx * 5; 193 | } 194 | } 195 | 196 | // 模拟数据 197 | setTimeout(function(){ 198 | 199 | option.series = [{ 200 | name: 'bar', 201 | type: 'bar', 202 | data: data1, 203 | animationDelay: function (idx) { 204 | return idx * 10; 205 | } 206 | }, { 207 | name: 'bar2', 208 | type: 'bar', 209 | data: data2, 210 | animationDelay: function (idx) { 211 | return idx * 10 + 100; 212 | } 213 | }] 214 | 215 | callback(option); 216 | }, 1000) 217 | } 218 | 219 | }; 220 | 221 | const table_conf = { 222 | 223 | type: 'tableList', // tableList graphList simpleObject complexObject 224 | 225 | // 初始化展现的数据,使用callback 回传列表数据 226 | // 需要手动添加唯一id key 227 | // callback 组件数据的回调函数(接受列表数据参数) 228 | initData: function(callback){ 229 | 230 | // 模拟数据 231 | Reqwest({ 232 | url: '/api/example', 233 | data: {}, 234 | 235 | type: 'json', 236 | success: function (data) { 237 | let list = data.data; 238 | list.forEach(function(ele) { 239 | ele.key = Math.random(); 240 | }); 241 | callback(list); 242 | } 243 | }); 244 | }, 245 | 246 | columns: [ 247 | { 248 | title: 'DOCID', // table header 文案 249 | dataIndex: 'docid', // 数据对象内的属性,也做react vdom 的key 250 | type: 'string', // table 内显示的类型 251 | sort: true, // 是否需要排序 252 | width:200 253 | }, { 254 | title: '标题', 255 | dataIndex: 'title', 256 | type: 'string' 257 | }, { 258 | title: '链接', 259 | dataIndex: 'link', 260 | type: 'link', 261 | render: (text) => ( 262 | 链接 263 | ), 264 | width: 50 265 | },{ 266 | title: '日期', 267 | dataIndex: 'date', 268 | type: 'string', 269 | width: 150 270 | },{ 271 | title: '图片', 272 | dataIndex: 'img', 273 | type: 'image' 274 | } 275 | ] 276 | 277 | }; 278 | 279 | const Feature1 = FeatureSetConfig(graph_conf2); 280 | const Feature2 = FeatureSetConfig(graph_conf3); 281 | const Feature3 = FeatureSetConfig(table_conf); 282 | 283 | const Feature = (props) => { 284 | 285 | return
286 | 287 | 288 | 289 |
290 | } 291 | 292 | export default Feature; 293 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # antd-auto (2.0版本建设中!!! 在1.0基础上扩展自定义形式的复杂性组件) 2 | 3 | 前端自动化配置搭建CMS系统框架。解决前端CMS系统开发成本问题,释放前端开发资源。 4 | 5 | ## 特性 6 | 7 | - 基于 dva 脚手架 [dva文档](https://github.com/dvajs/dva) 8 | - 基于 antd 2.0 UI组件 [ant.design文档](https://ant.design/docs/react/introduce) 9 | - 通过全局配置文件和页面配置文件,实现CMS系统的配置化开发 10 | - 开发与业务逻辑剥离,所见即所得,开发人员仅需提供数据以及传递数据,完全不涉及数据与UI操作上的处理 11 | - 特殊性功能可自实现开发处理 12 | 13 | ## 项目介绍 14 | 15 | 1. 实现前端只需提供数据便可以实现各种数据展现,包括table,simple objest,以及各类图形展现(引入echarts) 16 | 2. 提供数据操作接口,前端只需关心数据的接受与传递,便可以实现数据的增删改查,而无需再关心CMS内部的实现。暂时实现 table数据的增删改查,simple object数据的修改等 17 | 3. 在以上全自动话的基础上,可以实现自定义组装页面,目前功能包括,图片上传组件(需要正对自己项目调整接口),富文本编辑器(Tinymce),复制功能,antd UI 组件等。 18 | 19 | ## Start 20 | 21 | 克隆本项目,npm install 安装依赖,npm start 开始本地调试项目 开启 http://localhost:8989/便可以看到整体 DEMO 项目 22 | 23 | ## Build 24 | npm Build 开始构建压缩 25 | 如果 alicdn 对部分域名有访问限制,或者需要内网环境使用 在部署上线的时候需要注意下载字体自行部署 26 | 本项目修改 index.less 的 @font-face 即可 27 | 28 | ![image](http://image.freefe.cc/20161201144536.png) 29 | 30 | ## 目录结构 31 | 32 | ```bash 33 | ├── /mock/ # mock的接口文件 34 | ├── /dist/ # 项目构建输出目录 35 | ├── /src/ # 项目开发源码目录 36 | │ ├── /components/ # 项目组件 37 | │ │ ├── /common/ # 通用集成组件 38 | │ │ ├── /feature/ # 页面配置文件 (主要配置文件) 39 | │ │ ├── /login/ # 登录组件 40 | │ │ ├── /header/ # 头部组件 41 | │ │ ├── /main/ # 主体组件 42 | │ │ └── /sider/ # 边栏组件 43 | │ │ 44 | │ ├── /routes/ # 路由组件 45 | │ ├── /utils/ # 工具函数 46 | │ ├── router.jsx # 路由配置 47 | │ ├── index.jsx # 入口文件 48 | │ ├── index.less # 样式主体文件 49 | │ ├── config.js # 全局配置文件(主要配置文件) 50 | │ └── index.html 51 | │ 52 | ├── package.json # 项目信息 53 | └── proxy.config.js # 数据mock配置 54 | ``` 55 | 56 | ## 功能列表 57 | - [ ] 登录页面 58 | - [x] table数据 59 | - [x] 展现配置化实现 60 | - [x] 查询配置化实现 61 | - [x] 新增配置化实现 62 | - [x] 更新配置化实现 63 | - [x] 删除配置化实现 64 | - [x] 对象数据 65 | - [x] 展现配置化实现 66 | - [x] 更新配置化实现 67 | - [x] 可视化图表 68 | - [x] 基于echarts的数据可视化配置实现 69 | - [x] 富文本编辑器 70 | - [x] 通用图片上传组件(须自行调整) 71 | - [x] 复制粘贴功能 72 | 73 | 74 | ## 整站配置文件详解 75 | 76 | ### src/config.js 77 | 78 | 需配置整体的后台系统数据,以及自定义的配置数据 79 | 80 | **header 管理系统头部配置(必要属性)** 81 | 82 | * title 管理系统显示的标题 83 | * icon 管理系统显示的icon可在 [icon](https://ant.design/components/icon/) 查看 84 | * style 自定义设置头部样式 85 | 86 | ``` 87 | // header 示例 88 | header: { 89 | title: "测试配置管理后台", 90 | icon: "appstore", 91 | style: { 92 | padding: "15px 15px 15px 25px", 93 | borderBottom: "1px solid #E9E9E9", 94 | backgroundColor: "#F5F5F5" 95 | } 96 | } 97 | ``` 98 | 99 | ![image](http://image.freefe.cc/20161205140700.png) 100 | 101 | **sider 管理后台侧栏配置(必要属性)** 102 | 103 | * menu sider列表 实现单层or多层级展现 104 | - title 展现的title 105 | - key sider中对应的选项(若为菜单主项,则在openKeys中使用选择是否打开,若为功能项,则对应 selectedKey,以及 main 中 components 值) 106 | - icon 展现的icon选项(可选) 107 | - items 功能栏目列表(可选 可设置多层结构) 108 | 109 | * openKeys 默认展开的sider主导航项目(对应menu项目主栏目中的key) 110 | * selectedKey 默认打开的目标功能页面key(对应menu项目功能栏目中的key) 111 | * style 自定义样式 112 | 113 | ``` 114 | // sider 边栏导航配置示例 115 | sider: { 116 | // 层级列表 117 | menu: [ 118 | { 119 | // 多级 120 | title: "导航1", // 主导航名称 121 | key: "subTitle1", 122 | icon: "setting", 123 | items: [ 124 | {title: "选项1", key: "Feature1"}, 125 | {title: "选项2", key: "Feature2"}, 126 | {title: "选项3", key: "Feature3"}, 127 | { 128 | title: "导航3", 129 | key: "subTitle3", 130 | icon: "", 131 | items: [ 132 | {title: "选项6", key: "Feature6"}, 133 | {title: "选项7", key: "Feature7"}, 134 | {title: "选项8", key: "Feature8"} 135 | ] 136 | } 137 | ] 138 | },{ 139 | // 单级 140 | title: "选项5", 141 | key: "Feature5" 142 | } 143 | ], 144 | // 默认打开的导航项目 145 | openKeys:['subTitle1'], 146 | 147 | // 默认功能页 148 | selectedKey: "Feature1", 149 | 150 | // 自定义样式 151 | style: { 152 | backgroundColor: "#F5F5F5" 153 | } 154 | } 155 | ``` 156 | 157 | ![image](http://image.freefe.cc/20161205140735.png) 158 | 159 | **main 功能区域配置** 160 | 161 | * components 配置sider对应功能区域组件 162 | - FeatureKey Object 对应sider menu 中的功能key对应功能组件 163 | 164 | * title 功能区域标题显示名称 165 | * component 加载对应功能区域的feature模块 166 | * style 配置样式 167 | 168 | ``` 169 | // main 示例 170 | main: { 171 | components: { 172 | // key 值对应 sider item中功能选项的 key 173 | "Feature1": { 174 | // 功能区域标题显示名称 175 | title: 'table 数据展示', 176 | // require 加载对应功能区域的feature模块 177 | component: require('./components/feature/Feature1') 178 | }, 179 | "Feature2": { 180 | title: 'simple对象 数据展示', 181 | component: require('./components/feature/Feature2') 182 | } 183 | }, 184 | style: { 185 | backgroundColor: "#F5F5F5" 186 | } 187 | } 188 | ``` 189 | 190 | ![image](http://image.freefe.cc/20161205140757.png) 191 | 192 | **整体示例代码** 193 | 194 | ``` 195 | // header 示例 196 | header: { 197 | title: "测试配置管理后台", 198 | icon: "appstore", 199 | style: { 200 | padding: "15px 15px 15px 25px", 201 | borderBottom: "1px solid #E9E9E9", 202 | backgroundColor: "#F5F5F5" 203 | } 204 | } 205 | 206 | // sider 边栏导航配置示例 207 | sider: { 208 | // 层级列表 209 | menu: [ 210 | { 211 | // 多级 212 | title: "导航1", // 主导航名称 213 | key: "subTitle1", 214 | icon: "setting", 215 | items: [ 216 | {title: "选项1", key: "Feature1"}, 217 | {title: "选项2", key: "Feature2"}, 218 | {title: "选项3", key: "Feature3"}, 219 | { 220 | title: "导航3", 221 | key: "subTitle3", 222 | icon: "", 223 | items: [ 224 | {title: "选项6", key: "Feature6"}, 225 | {title: "选项7", key: "Feature7"}, 226 | {title: "选项8", key: "Feature8"} 227 | ] 228 | } 229 | ] 230 | },{ 231 | // 单级 232 | title: "选项5", 233 | key: "Feature5" 234 | } 235 | ], 236 | // 默认打开的导航项目 237 | openKeys:['subTitle1'], 238 | 239 | // 默认功能页 240 | selectedKey: "Feature1", 241 | 242 | // 自定义样式 243 | style: { 244 | backgroundColor: "#F5F5F5" 245 | } 246 | } 247 | 248 | // main 示例 249 | main: { 250 | components: { 251 | // key 值对应 sider item中功能选项的 key 252 | "Feature1": { 253 | // 功能区域标题显示名称 254 | title: 'table 数据展示', 255 | // require 加载对应功能区域的feature模块 256 | component: require('./components/feature/Feature1') 257 | }, 258 | "Feature2": { 259 | title: 'simple对象 数据展示', 260 | component: require('./components/feature/Feature2') 261 | } 262 | }, 263 | style: { 264 | backgroundColor: "#F5F5F5" 265 | } 266 | } 267 | ``` 268 | 269 | ### src/components/feature/Feature.js 270 | 271 | **配置单独功能页面的配置文件** 272 | 273 | * table数据,单例数据,图标型数据的展现 274 | * 查询、创建、更新、删除表单自动化处理 275 | * 富文本编辑器功能使用 276 | * 独立的图片上传组件使用 277 | * 表单元素自定义使用 278 | 279 | **必要参数** 280 | 281 | * type (string) 对于数据展现形式, 目前有 tableList graphList simpleObject 三种类型 282 | 283 | ``` 284 | // 对于数据展现形式 目前有 tableList graphList simpleObject 三种类型 285 | type: 'tableList', // tableList graphList simpleObject complexObject 286 | ``` 287 | 288 | * initData (function) 初始化展现的数据,参数 callback 用于接受获取的数据 289 | 290 | ``` 291 | // 初始化展现的数据,使用callback 回传列表数据 292 | // 需要手动添加唯一id key 293 | // callback 组件数据的回调函数(接受列表数据参数) 294 | initData: function(callback){ 295 | // 同步或者异步获取原始数据 296 | // 数据需要确认唯一的 key(react 形式) 297 | // 若是 table 类型 则每一条数据均需要唯一的 key 298 | data.key = data.id; 299 | callback(data); 300 | } 301 | ``` 302 | 303 | * pageData (function) 接口分页数据处理 304 | 305 | // 接口分页处理 306 | // callback 回传列表数据 第二参数接受 总数与每页数目 307 | // 需要手动添加唯一id key 308 | pageData: function(num, callback){ 309 | Reqwest({ 310 | url: '/api/example2', 311 | data: { 312 | page:num, 313 | pageSize: 20 314 | }, 315 | 316 | type: 'json', 317 | success: function (data) { 318 | let list = data.data; 319 | list.forEach(function(ele) { 320 | ele.key = ele.id; 321 | }); 322 | // 回调的第二个参数为数量总数 以及每页的数量 323 | callback(list, { 324 | total: 399, 325 | pageSize: 20 326 | }); 327 | } 328 | }); 329 | } 330 | 331 | **table类型 展现数据** 332 | 333 | * columns (Array) 数据展现类型为 tableList时,设置table表头字段设置 334 | 335 | ``` 336 | // table 列表展现配置 337 | // { 338 | // title table显示表题 339 | // dataIndex 显示数据中的key 340 | // type 展现形式 (string image link) 341 | // render 自定义展现形式 参数 (当前数据,当前对象数据) 342 | // sort 是否需要排序功能 343 | // width 自定义该列宽度 否则等分 344 | // } 345 | columns: [ 346 | { 347 | title: 'DOCID', // table header 文案 348 | dataIndex: 'docid', // 数据对象内的属性,也做react vdom 的key 349 | type: 'string', // table 内显示的类型 350 | sort: true, // 是否需要排序 351 | width:200, 352 | render: (text, item) => ( 353 | {item.name} 354 | ), 355 | }, 356 | // type为operate含有特殊含义 自动化的更新与删除,以及自定义操作回调函数 357 | // 为特殊的操作字段 358 | { 359 | title: '操作', 360 | type: 'operate', // 操作的类型必须为 operate 361 | width: 120, 362 | btns: [{ 363 | text: '更新', 364 | type: 'update' 365 | },{ 366 | text: '删除', 367 | type: 'delete' 368 | }, { 369 | text: '展示', 370 | callback: function(item){ 371 | console.log(item) 372 | } 373 | }, { 374 | render: (text, item) => () 375 | } 376 | }] 377 | } 378 | ] 379 | ``` 380 | 381 | ![image](http://image.freefe.cc/20161205141002.png) 382 | 383 | **table类型 查询更新列表数据** 384 | 385 | * RType Array 展现的填写表单的数据字段。类型含有示例中的形式 386 | 387 | ``` 388 | // table 查询字段 389 | // { 390 | // name 字段的name值 391 | // label 字段的展现内容 392 | // type 字段类型 (string date select cascader radio checkbox switch imageUpload) 393 | // placeholder input的placeholder内容 394 | // } 395 | RType: [ 396 | { 397 | name: 'id', 398 | label: '唯一标识', 399 | type: 'string', 400 | placeholder: '请输入标示名称' 401 | },{ 402 | name: 'date', 403 | label: '项目开始时间', 404 | type: 'date' 405 | },{ 406 | name: 'stype', 407 | label: '项目类型Select', 408 | type: 'select', 409 | defaultValue: 'one', 410 | options:[{ 411 | text: '选项一', 412 | value: 'one' 413 | },{ 414 | text: '选项二', 415 | value: 'two' 416 | },{ 417 | text: '选项三', 418 | value: 'three' 419 | }] 420 | },{ 421 | name: 'rtype', 422 | label: '项目类型Radio', 423 | type: 'radio', 424 | defaultValue: 'one', 425 | options:[{ 426 | text: '选项一', 427 | value: 'one' 428 | },{ 429 | text: '选项二', 430 | value: 'two' 431 | },{ 432 | text: '选项三', 433 | value: 'three' 434 | }] 435 | },{ 436 | name: 'ischange', 437 | label: '是否过滤', 438 | type: 'switch', 439 | defaultValue: false 440 | } 441 | 442 | ] 443 | ``` 444 | 445 | * Retrieve function 对于确认创建数据接口上报创建回调的函数 446 | 447 | ``` 448 | Retrieve: function(data, callback){ 449 | // 处理对于列表查询的数据请求 450 | console.log(data); 451 | 452 | // 查询成功之后执行callback回调 453 | // 同步或者异步获取原始数据 454 | // 数据需要确认唯一的 key(react 形式) 455 | // 若是 table 类型 则每一条数据均需要唯一的 key 456 | list.key = list.id; 457 | callback(list); 458 | } 459 | ``` 460 | 461 | ![image](http://image.freefe.cc/20161205141035.png) 462 | 463 | **table类型 创建数据** 464 | 465 | 当数据类型为table 并且含有创建新数据的需求时 466 | 467 | * CType Array 展现的填写表单的数据字段。类型含有示例中的形式 468 | 469 | ``` 470 | // table 创建新数据字段 471 | // { 472 | // name 字段的name值 473 | // label 字段的展现内容 474 | // type 字段类型 (string date select cascader radio checkbox switch imageUpload) 475 | // placeholder input的placeholder内容 476 | // } 477 | CType: [ 478 | { 479 | name: 'docid', 480 | label: '唯一标识', 481 | type: 'string', 482 | placeholder: '请输入标示名称' 483 | },{ 484 | name: 'date', 485 | label: '日期', 486 | type: 'date' 487 | },{ 488 | name: 'img', 489 | label: '图片', 490 | type: 'imageUpload' 491 | } 492 | ] 493 | ``` 494 | 495 | * Create function 对于确认创建数据接口上报创建回调的函数 496 | 497 | ``` 498 | Create: function(data, callback){ 499 | // 处理对于数据请求的创建 500 | console.log(data); 501 | 502 | // 创建成功之后执行callback回调 503 | callback(); 504 | } 505 | ``` 506 | 507 | ![image](http://image.freefe.cc/20161205141101.png) 508 | 509 | **table类型 更新数据** 510 | 511 | 当数据类型为table 并且含有更新数据的需求时 512 | 513 | * UType Array 展现的填写表单的数据字段。类型含有示例中的形式(类似创建数据) 514 | 515 | ``` 516 | // table 更新数据字段 517 | // { 518 | // name 字段的name值 519 | // label 字段的展现内容 520 | // type 字段类型 (string date select cascader radio checkbox switch imageUpload) 521 | // placeholder input的placeholder内容 522 | // } 523 | CType: [ 524 | { 525 | name: 'docid', 526 | label: '唯一标识', 527 | type: 'string', 528 | placeholder: '请输入标示名称' 529 | },{ 530 | name: 'date', 531 | label: '日期', 532 | type: 'date' 533 | },{ 534 | name: 'img', 535 | label: '图片', 536 | type: 'imageUpload' 537 | } 538 | ] 539 | ``` 540 | 541 | * Update function 对于确认创建数据接口上报创建回调的函数 542 | 543 | ``` 544 | Update: function(data, callback){ 545 | // 处理对于数据请求的更新 546 | console.log(data); 547 | 548 | // 更新成功之后执行callback回调 549 | callback(); 550 | } 551 | ``` 552 | 553 | ![image](http://image.freefe.cc/20161205141248.png) 554 | 555 | **table类型 删除数据** 556 | 557 | 当数据类型为table 并且含有更新数据的需求时 558 | 559 | * Delete function 对于确认删除某条数据实例 560 | 561 | ``` 562 | Delete: function(data, callback){ 563 | // 删除操作 564 | console.log(data); 565 | 566 | Reqwest({ 567 | url: '/api/delete', 568 | data: data.id, 569 | 570 | type: 'json', 571 | success: function (data) { 572 | // 模拟请求删除成功的回调 573 | callback(); 574 | } 575 | }); 576 | 577 | } 578 | ``` 579 | 580 | ![image](http://image.freefe.cc/20161205141337.png) 581 | 582 | 583 | ## 其他组件 584 | 585 | ### 图片上传组件(需自定义调整) 586 | 587 | ### 复制文本组件 588 | 589 | ### 富文本编辑器组件(Tinymce基础功能接入) 590 | 591 | ### echarts 组件接入 592 | 593 | 594 | ## 学习文档 595 | 596 | [ES6 react 实践的技术图](https://github.com/dvajs/dva-knowledgemap) 597 | 598 | [dva 完成一个中型应用](https://github.com/dvajs/dva-docs/blob/master/v1/zh-cn/tutorial/01-%E6%A6%82%E8%A6%81.md) 599 | 600 | [系统引用的UI组件文档 Ant Design of React](https://ant.design/docs/react/introduce) 601 | 602 | 603 | bibibibi~ 改版中!!!!!!!!!!!!!!!! -------------------------------------------------------------------------------- /src/components/common/FeatureSetConfig.jsx: -------------------------------------------------------------------------------- 1 | // 纯数据展现情况列表 2 | import React from 'react'; 3 | import ReactEcharts from 'echarts-for-react'; 4 | 5 | import { Table, Form, Select, Input, Row, Col, Button, Icon } from 'antd'; 6 | import { DatePicker, TimePicker, Radio, Switch} from 'antd'; 7 | import { Upload, Modal, message, Spin} from 'antd'; 8 | 9 | import { Link } from 'dva/router'; 10 | 11 | import Immutable from 'immutable'; 12 | import Reqwest from 'reqwest'; 13 | 14 | import CFormItem from './CreateFormItem'; 15 | import CTextItem from './CreateTextItem'; 16 | 17 | // 搜索查询栏form 创建新item-form 更新form 18 | import UForm from './UpdateForm'; 19 | import CForm from './CreateForm'; 20 | import RForm from './RetrieveForm'; 21 | 22 | const FormItem = Form.Item; 23 | const Option = Select.Option; 24 | const RadioGroup = Radio.Group; 25 | 26 | 27 | // 依赖 config 主题生成react 组件函数 28 | const FeatureSet = (config) => { 29 | 30 | let tableFeature = React.createClass({ 31 | getInitialState: function(){ 32 | return { 33 | columns: [], 34 | resultList: [], 35 | loading: false, 36 | 37 | updateFromShow: false, 38 | updateFromItem: {}, 39 | 40 | total: 0, 41 | pageSize: 10 42 | } 43 | }, 44 | 45 | componentWillMount: function(){ 46 | this.setState({ 47 | loading: true, 48 | columns: this.dealConfigColumns(config.columns) 49 | }); 50 | }, 51 | 52 | render: function() { 53 | const self = this; 54 | 55 | let table; 56 | if(config.pageData){ 57 | const pagination = { 58 | total: this.state.total, 59 | pageSize: this.state.pageSize, 60 | onChange: function(num){ 61 | self.setState({ 62 | loading: true 63 | }); 64 | self.getpageData(num); 65 | } 66 | } 67 | 68 | table = ; 69 | }else{ 70 | table =
; 71 | } 72 | 73 | return
74 | 75 | 76 | 77 | {table} 78 |
79 | }, 80 | 81 | // 预处理配置显示中的 colums 数据 用于anted的table配置 82 | dealConfigColumns: function(lists){ 83 | const self = this; 84 | 85 | let columns = []; 86 | lists.forEach((item) => { 87 | let column = { 88 | title: item.title, 89 | dataIndex: item.dataIndex, 90 | key: item.dataIndex, 91 | width: item.width 92 | } 93 | 94 | if( item.type === 'operate' ){ 95 | // 兼容单一形式与数组形式 96 | let btns = Array.isArray(item.btns)?item.btns:[item.btns]; 97 | 98 | // 处理表单 操作 栏目以及回调函数 99 | column.render = item.render || function(txt, record){ 100 | return 101 | { 102 | btns.map(function(btn,i) { 103 | if( btn.text ){ 104 | return ( 105 | 106 | {btn.text} 107 | {i!==btns.length-1?:''} 108 | 109 | ); 110 | }else if( btn.render ){ 111 | return ( 112 | 113 | {btn.render(txt, record)} 114 | {i!==btns.length-1?:''} 115 | 116 | ); 117 | } 118 | 119 | 120 | }) 121 | } 122 | 123 | }; 124 | }else if( !item.dataIndex ){ 125 | item.dataIndex = 'NORMAL_INDEX'; 126 | column.render = item.render || self.renderFunc[item.type]; 127 | } else{ 128 | column.render = item.render || self.renderFunc[item.type] || ((text) => ({text})); 129 | } 130 | 131 | if(item.sort){ 132 | column.sorter = item.sorter || ((a, b) => a[item.dataIndex] - b[item.dataIndex]); 133 | } 134 | columns.push(column); 135 | 136 | }); 137 | 138 | return columns; 139 | 140 | }, 141 | 142 | // columns 类型对应的通用痛render 143 | renderFunc: { 144 | link: (text) => ( 145 | 146 | {text} 147 | ), 148 | 149 | image: (url) => ( 150 | 151 | 152 | ) 153 | }, 154 | 155 | handleCreate: function(info){ 156 | const self = this; 157 | 158 | config.Create(info, function(item){ 159 | // 初级接口的坑 160 | if(!item){ 161 | config.initData(function(list){ 162 | self.setState({ 163 | loading: false, 164 | resultList: list 165 | }); 166 | }); 167 | return; 168 | } 169 | 170 | let lists = self.state.resultList; 171 | lists.unshift(item); 172 | 173 | self.setState({ 174 | loading: false, 175 | resultList: lists 176 | }); 177 | }); 178 | }, 179 | 180 | handleUpdate: function(info){ 181 | const self = this; 182 | let result = Immutable.fromJS(self.state.resultList); 183 | 184 | let infoN = Immutable.fromJS(self.state.updateFromItem).merge(info).toJS(); 185 | config.Update(infoN, function(item){ 186 | let resultList = result.map(function(v, i){ 187 | if(v.get('key') === item.key){ 188 | return Immutable.fromJS(item); 189 | }else{ 190 | return v; 191 | } 192 | }); 193 | message.success('更新成功'); 194 | 195 | self.setState({ 196 | loading: false, 197 | updateFromShow: false, 198 | resultList: resultList.toJS() 199 | }); 200 | }); 201 | }, 202 | hideUpdateForm: function(){ 203 | this.setState({ 204 | updateFromShow: false, 205 | updateFromItem: {} 206 | }); 207 | }, 208 | 209 | // 搜索更新处理 210 | handleRetrieve: function(info){ 211 | const self = this; 212 | self.setState({ 213 | loading: true 214 | }); 215 | 216 | config.Retrieve(info, function(list){ 217 | self.setState({ 218 | loading: false, 219 | resultList: list 220 | }); 221 | }); 222 | }, 223 | 224 | // table 操作列回调处理 225 | operateCallbacks: function(item, btn){ 226 | const self = this; 227 | 228 | if(btn.type){ 229 | 230 | let resultList; 231 | let type = btn.type; 232 | let itemI = Immutable.fromJS(item); 233 | let result = Immutable.fromJS(self.state.resultList); 234 | 235 | // table 操作栏目通用设定为 更新与删除 两项 236 | if(type === 'update'){ 237 | this.setState({ 238 | updateFromShow: true, 239 | updateFromItem: itemI.toJS() 240 | }); 241 | }else if(type === 'delete'){ 242 | this.setState({ 243 | loading: true 244 | }); 245 | 246 | config.Delete(itemI.toJS(), function(){ 247 | resultList = result.filter(function(v, i){ 248 | if(v.get('key') !== itemI.get('key')){ 249 | return true; 250 | } 251 | }); 252 | message.success('删除成功'); 253 | 254 | self.setState({ 255 | loading: false, 256 | resultList: resultList.toJS() 257 | }); 258 | }); 259 | } 260 | 261 | 262 | }else if(btn.callback){ 263 | btn.callback(item); 264 | } 265 | }, 266 | 267 | componentDidMount: function(){ 268 | const self = this; 269 | 270 | // 处理接口分页的逻辑 271 | if(config.pageData){ 272 | self.getpageData(1); 273 | }else{ // 处理 前端分页的逻辑 274 | config.initData(function(list){ 275 | self.setState({ 276 | loading: false, 277 | resultList: list 278 | }); 279 | }); 280 | } 281 | }, 282 | 283 | getpageData: function(num){ 284 | const self = this; 285 | self.setState({ 286 | loading: true 287 | }); 288 | 289 | config.pageData(num,function(list, info){ 290 | self.setState({ 291 | loading: false, 292 | resultList: list, 293 | total: info.total, 294 | pageSize: info.pageSize||10, 295 | }); 296 | }); 297 | 298 | } 299 | }); 300 | 301 | let simpleFeature = React.createClass({ 302 | getInitialState: function(){ 303 | return { 304 | item:{}, 305 | loading: false, 306 | 307 | updateFromShow: false, 308 | updateFromItem: {} 309 | } 310 | }, 311 | 312 | componentWillMount: function(){ 313 | }, 314 | 315 | render: function() { 316 | const self = this; 317 | const itemInfo = this.state.item; 318 | 319 | const { getFieldDecorator } = this.props.form; 320 | const formItemLayout = { 321 | labelCol: { span: 3 }, 322 | wrapperCol: { span: 18 }, 323 | }; 324 | 325 | const operate = config.operate || []; 326 | 327 | return
328 |
329 | { 330 | this.state.loading? 331 |
332 | 333 |
: 334 | '' 335 | } 336 | { 337 | config.columns? 338 | config.columns.map(function(item){ 339 | item.value = itemInfo[item.dataIndex]||''; 340 | return 341 | }): 342 | '' 343 | } 344 | { 345 | config.UType? 346 | config.UType.map(function(item){ 347 | item.defaultValue = itemInfo[item.name]||''; 348 | return 349 | }): 350 | '' 351 | } 352 | 353 | { 354 | operate.map(function(btn){ 355 | return 356 | }) 357 | } 358 |
359 | }, 360 | 361 | componentDidMount: function(){ 362 | const self = this; 363 | self.setState({ 364 | loading: true 365 | }); 366 | 367 | config.initData(function(item){ 368 | self.setState({ 369 | item: item, 370 | loading: false 371 | }); 372 | }); 373 | }, 374 | 375 | operateCallbacks: function(btn){ 376 | const self = this; 377 | 378 | let itemI = Immutable.fromJS(this.props.form.getFieldsValue()); 379 | 380 | if(btn.type === 'update'){ 381 | const self = this; 382 | 383 | config.Update(itemI.toJS(), function(item){ 384 | message.success('更新成功'); 385 | self.setState({ 386 | item: item 387 | }); 388 | }); 389 | 390 | }else if(btn.callback){ 391 | btn.callback(itemI.toJS()); 392 | } 393 | } 394 | }); 395 | simpleFeature = Form.create()(simpleFeature); 396 | 397 | 398 | let graphFeature = React.createClass({ 399 | getInitialState: function(){ 400 | return { 401 | option: false 402 | } 403 | }, 404 | 405 | componentWillMount: function(){ 406 | }, 407 | 408 | render: function() { 409 | const self = this; 410 | const itemInfo = this.state.item; 411 | 412 | const operate = config.operate || []; 413 | 414 | return
415 | {this.state.option? 416 | : 420 | ''} 421 |
422 | }, 423 | 424 | componentDidMount: function(){ 425 | const self = this; 426 | 427 | config.initData(function(option){ 428 | self.setState({ 429 | option: option 430 | }); 431 | }); 432 | } 433 | }); 434 | 435 | switch (config.type){ 436 | case 'tableList': 437 | return tableFeature; 438 | break; 439 | 440 | case 'graphList': 441 | return graphFeature; 442 | break; 443 | 444 | case 'simpleObject': 445 | return simpleFeature; 446 | break; 447 | 448 | case 'complexObject': 449 | return complexFeature; 450 | break; 451 | 452 | default: 453 | return tableFeature; 454 | break; 455 | } 456 | } 457 | 458 | 459 | export default FeatureSet; 460 | --------------------------------------------------------------------------------