', () => {
30 | expect(wrapper.type()).to.eql('div');
31 | });
32 |
33 | it('has style with height 100%', () => {
34 | const expectedStyles = {
35 | height: '100%',
36 | background: '#333'
37 | }
38 | expect(wrapper.prop('style')).to.eql(expectedStyles);
39 | });
40 |
41 | it('contains a header explaining the app', () => {
42 | expect(wrapper.find('.welcome-header')).to.have.length(1);
43 | });
44 | });
--------------------------------------------------------------------------------
/src/common/util.js:
--------------------------------------------------------------------------------
1 |
2 | // 自定义的配置数据
3 |
4 | const DateFormat = function(date, fmt) {
5 | let o = {
6 | "M+" : date.getMonth()+1, //月份
7 | "d+" : date.getDate(), //日
8 | "h+" : date.getHours()%12 == 0 ? 12 : date.getHours()%12, //小时
9 | "H+" : date.getHours(), //小时
10 | "m+" : date.getMinutes(), //分
11 | "s+" : date.getSeconds(), //秒
12 | "q+" : Math.floor((date.getMonth()+3)/3), //季度
13 | "S" : date.getMilliseconds() //毫秒
14 | };
15 | let week = {
16 | "0" : "/u65e5",
17 | "1" : "/u4e00",
18 | "2" : "/u4e8c",
19 | "3" : "/u4e09",
20 | "4" : "/u56db",
21 | "5" : "/u4e94",
22 | "6" : "/u516d"
23 | };
24 | if(/(y+)/.test(fmt)){
25 | fmt=fmt.replace(RegExp.$1, (date.getFullYear()+"").substr(4 - RegExp.$1.length));
26 | }
27 | if(/(E+)/.test(fmt)){
28 | fmt=fmt.replace(RegExp.$1, ((RegExp.$1.length>1) ? (RegExp.$1.length>2 ? "/u661f/u671f" : "/u5468") : "")+week[date.getDay()+""]);
29 | }
30 | for(let k in o){
31 | if(new RegExp("("+ k +")").test(fmt)){
32 | fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
33 | }
34 | }
35 | return fmt;
36 | }
37 |
38 |
39 | export default {
40 | DateFormat : DateFormat
41 | };
--------------------------------------------------------------------------------
/src/feature/Feature3-1.jsx:
--------------------------------------------------------------------------------
1 | // 含有可操作 table 栏的数据展示
2 | import React from 'react';
3 |
4 | import Immutable from 'immutable';
5 | import TinyMCE from 'react-tinymce';
6 | //https://github.com/ded/reqwest
7 | import Reqwest from 'reqwest';
8 |
9 | const Feature = React.createClass({
10 | getInitialState: function(){
11 | return {
12 | value: ''
13 | }
14 | },
15 | render: function() {
16 | let config = {
17 | content: "
",
18 | config: {
19 | height: '250',
20 | plugins: [
21 | "advlist autolink lists charmap print preview hr anchor pagebreak spellchecker",
22 | "searchreplace wordcount visualblocks visualchars fullscreen insertdatetime nonbreaking",
23 | "save table contextmenu directionality emoticons paste textcolor"
24 | ],
25 | toolbar: "insertfile undo redo | styleselect fontselect fontsizeselect| bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | l | print preview fullpage | forecolor backcolor",
26 | },
27 | onChange: this.handleEditorChange
28 | }
29 | return
33 | },
34 |
35 | handleEditorChange(e) {
36 | window.e = e;
37 | this.setState({
38 | value: e.target.getContent()
39 | });
40 | },
41 | });
42 |
43 | export default Feature;
44 |
--------------------------------------------------------------------------------
/src/store/reducers.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | // import { routerReducer } from 'react-router-redux';
3 |
4 | import user from './modules/user/user_reducer';
5 | import menu from './modules/menu/menu_reducer';
6 |
7 | /**
8 | * combineReducers(reducers)
9 | *
10 | * desc:
11 | * combineReducers 辅助函数的作用是,把一个由多个不同 reducer 函数作为 value 的 object,合并成一个最终的 reducer 函数,然后就可以对这个 reducer 调用 createStore。
12 | * 合并后的 reducer 可以调用各个子 reducer,并把它们的结果合并成一个 state 对象。state 对象的结构由传入的多个 reducer 的 key 决定。
13 | *
14 | * 最终,state 对象的结构会是这样的:
15 | *
16 | * {
17 | * reducer1: ...
18 | * reducer2: ...
19 | * }
20 | *
21 | * 自定义 `State` 树名称:
22 | * 通过为传入对象的 reducer 命名不同来控制 state key 的命名。例如,你可以调用 combineReducers({ todos: myTodosReducer, counter: myCounterReducer }) 将 state 结构变为 { todos, counter }。
23 | * 通常的做法是命名 reducer,然后 state 再去分割那些信息,因此你可以使用 ES6 的简写方法:combineReducers({ counter, todos })。这与 combineReducers({ counter: counter, todos: todos }) 一样。
24 | *
25 | * 参数:
26 | * reducers (Object): 一个对象,它的值(value) 对应不同的 reducer 函数,这些 reducer 函数后面会被合并成一个。下面会介绍传入 reducer 函数需要满足的规则。
27 | *
28 | * 返回值:
29 | * (Function):一个调用 reducers 对象里所有 reducer 的 reducer,并且构造一个与 reducers 对象结构相同的 state 对象。
30 | *
31 | * 注意,每个传入 combineReducers 的 reducer 都需满足以下规则:
32 | * 1、所有未匹配到的 action,必须把它接收到的第一个参数也就是那个 state 原封不动返回。(在 `switch` 最后 `return state`)
33 | * 2、永远不能返回 undefined。当过早 return 时非常容易犯这个错误,为了避免错误扩散,遇到这种情况时 combineReducers 会抛异常。
34 | * 3、如果传入的 state 就是 undefined,一定要返回对应 reducer 的初始 state。根据上一条规则,初始 state 禁止使用 undefined。
35 | * 使用 ES6 的默认参数值语法来设置初始 state 很容易,但你也可以手动检查第一个参数是否为 undefined。(`state = initState`,当 `state` 为 `undefined` 时会赋默认值 `initState`)
36 | *
37 | */
38 |
39 | export default combineReducers({
40 | user,
41 | menu,
42 | // routing: routerReducer
43 | });
44 |
--------------------------------------------------------------------------------
/src/feature/Feature1-2.jsx:
--------------------------------------------------------------------------------
1 | // 纯数据展现情况列表
2 | import React from 'react';
3 |
4 | import FeatureSetConfig from '../components/FeatureSetConfig';
5 |
6 | import Immutable from 'immutable';
7 | import Reqwest from 'reqwest';
8 |
9 | import testData from '../common/test-data';
10 |
11 | const simple_conf = {
12 |
13 | type: 'simpleObject',
14 |
15 | initData: function(callback){
16 | // 模拟数据
17 | setTimeout(function(){
18 | let object = testData.simpleObject;
19 | object.key = object.docid;
20 |
21 | callback(object);
22 | }, 1000)
23 | },
24 |
25 | operate:[
26 | {
27 | text: '确认数据',
28 | style: {
29 | 'marginRight': '30px'
30 | },
31 | callback: function(item){
32 | console.log(item)
33 | }
34 | }, {
35 | text: '展示数据',
36 | callback: function(item){
37 | console.log(item)
38 | }
39 | }
40 | ],
41 |
42 | UType:[
43 | {
44 | name: 'docid',
45 | label: '唯一标识',
46 | type: 'string',
47 | placeholder: '请输入标示名称'
48 | },{
49 | name: 'title',
50 | label: '标题',
51 | type: 'string',
52 | placeholder: '请输入标示名称'
53 | },{
54 | name: 'link',
55 | label: '链接',
56 | type: 'string'
57 | },{
58 | name: 'date',
59 | label: '日期',
60 | type: 'date'
61 | },{
62 | name: 'img',
63 | label: '图片',
64 | type: 'imageUpload'
65 | }
66 | ]
67 | }
68 |
69 | const Feature1 = FeatureSetConfig(simple_conf);
70 |
71 | export default Feature1;
72 |
--------------------------------------------------------------------------------
/test/containers/CommentList.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | // Once we set up Karma to run our tests through webpack
4 | // we will no longer need to have these long relative paths
5 | import CommentList from '../../src/views/Demo/CommentList';
6 | import {
7 | describeWithDOM,
8 | mount,
9 | shallow,
10 | spyLifecycle
11 | } from 'enzyme';
12 |
13 | describe('(Component) CommentList', () => {
14 |
15 | // using special describeWithDOM helper that enzyme
16 | // provides so if other devs on my team don't have JSDom set up
17 | // properly or are using old version of node it won't bork their test suite
18 | //
19 | // All of our tests that depend on mounting should go inside one of these
20 | // special describe blocks
21 | describeWithDOM('Lifecycle methods', () => {
22 | it('calls componentDidMount', () => {
23 | spyLifecyle(CommentList);
24 |
25 | const props = {
26 | onMount: () => {}, // an anonymous function in ES6 arrow syntax
27 | isActive: false
28 | }
29 |
30 | // using destructuring to pass props down
31 | // easily and then mounting the component
32 | mount(
);
33 |
34 | // CommentList's componentDidMount should have been
35 | // called once. spyLifecyle attaches sinon spys so we can
36 | // make this assertion
37 | expect(
38 | CommentList.prototype.componentDidMount.calledOnce
39 | ).to.be.true;
40 | });
41 |
42 | it('calls onMount prop once it mounts', () => {
43 | // create a spy for the onMount function
44 | const props = { onMount: sinon.spy() };
45 |
46 | // mount our component
47 | mount(
);
48 |
49 | // expect that onMount was called
50 | expect(props.onMount.calledOnce).to.be.true;
51 | });
52 | });
53 | });
--------------------------------------------------------------------------------
/src/feature/Feature2-3.jsx:
--------------------------------------------------------------------------------
1 | // 纯数据展现情况列表
2 | import React from 'react';
3 |
4 | import FeatureSetConfig from '../components/FeatureSetConfig';
5 |
6 | import Immutable from 'immutable';
7 | import Reqwest from 'reqwest';
8 |
9 | import testData from '../common/test-data';
10 |
11 | const simple_conf = {
12 |
13 | type: 'simpleObject',
14 |
15 | initData: function(callback){
16 | // 模拟数据
17 | setTimeout(function(){
18 | let object = testData.simpleObject;
19 | object.key = object.docid;
20 |
21 | callback(object);
22 | }, 1000)
23 | },
24 |
25 | Update:function(data, callback){
26 | console.log(data);
27 | callback(data);
28 | },
29 |
30 | operate:[
31 | {
32 | text: '确认修改',
33 | type: 'update',
34 | style: {
35 | 'marginRight': '30px',
36 | 'marginLight': '80px'
37 | }
38 | }, {
39 | text: '展示数据',
40 | callback: function(item){
41 | console.log(item)
42 | }
43 | }
44 | ],
45 |
46 | UType:[
47 | {
48 | name: 'docid',
49 | label: '唯一标识',
50 | type: 'string',
51 | placeholder: '请输入标示名称'
52 | },{
53 | name: 'title',
54 | label: '标题',
55 | type: 'string',
56 | placeholder: '请输入标示名称'
57 | },{
58 | name: 'link',
59 | label: '链接',
60 | type: 'string'
61 | },{
62 | name: 'date',
63 | label: '日期',
64 | type: 'date'
65 | },{
66 | name: 'img',
67 | label: '图片',
68 | type: 'imageUpload'
69 | }
70 | ]
71 | }
72 |
73 | const Feature1 = FeatureSetConfig(simple_conf);
74 |
75 | export default Feature1;
76 |
--------------------------------------------------------------------------------
/src/store/modules/menu/menu_action.js:
--------------------------------------------------------------------------------
1 | import api from '../../../api';
2 | import types from '../../types';
3 |
4 | import reqwest from 'reqwest';
5 | import {emptyMenu, caseMenu} from '../../../feature/leftMenu';
6 | import topMenu from '../../../feature/topMenu';
7 |
8 | /**
9 | * 顶部菜单切换,更新面包屑
10 | *
11 | * @export
12 | * @param {any} path
13 | * @param {any} key
14 | * @returns
15 | */
16 | export function updateNavPath(path, key) {
17 | return {
18 | type: types.UPDATE_NAVPATH,
19 | payload: {
20 | data: path,
21 | key: key
22 | }
23 | }
24 | }
25 |
26 | /**
27 | * 获取case顶部菜单
28 | * 向服务端获取 `顶部菜单` 信息,服务端可以自由控制 `顶部菜单` 的权限问题
29 | *
30 | * @export
31 | * @returns
32 | */
33 | export function getTopMenu() {
34 | return {
35 | type: types.GET_TOP_MENU,
36 | params: {
37 | topMenu: topMenu
38 | }
39 | }
40 | }
41 |
42 | /**
43 | * 获取cese侧边菜单数据(我的发布、我的case、我的关注)
44 | *
45 | * 获取 `侧边菜单` 的统计数据
46 | * 根据 `taskMatch` 字段获取筛选
47 | * 我的发布 = 1
48 | * 我的case = 2
49 | * 我的关注 = 3
50 | *
51 | * @export
52 | * @param {any} taskMatchObj
53 | * @returns
54 | */
55 | export function getCaseMenu() {
56 | return {
57 | type: types.GET_LEFT_MENU,
58 | params: {
59 | leftMenu: caseMenu
60 | }
61 | }
62 | }
63 |
64 | /**
65 | * 侧栏菜单的隐藏显示控制
66 | *
67 | * 通过点击切换按钮触发该功能
68 | * 目前在 `View/App` 下控制,打开与隐藏的Class
69 | *
70 | * @export
71 | * @param {any} collapse
72 | * @returns
73 | */
74 | export function updateCollapse(collapse) {
75 | return {
76 | type: types.UPDATE_COLLAPSE,
77 | payload: {
78 | collapse: collapse,
79 | }
80 | }
81 | }
82 |
83 | /**
84 | * 修改 state
85 | *
86 | * @export
87 | * @param {any} status
88 | * @returns
89 | */
90 | export function updateStatus(status) {
91 | return {
92 | type: types.UPDATE_STATUS,
93 | payload: {
94 | status: status,
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/components/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 { getFieldProps } = this.props.form;
21 | const formItemLayout = {
22 | labelCol: { span: 6 },
23 | wrapperCol: { span: 18 },
24 | };
25 |
26 | return UType ?
27 |
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/util/util.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Utility functions.
3 | */
4 | import Promise from './promise';
5 |
6 | const _ = {};
7 |
8 | function extend (target, source, deep) {
9 | for (const key in source) {
10 | if (deep && (_.isPlainObject(source[key]) || _.isArray(source[key]))) {
11 | if (_.isPlainObject(source[key]) && !_.isPlainObject(target[key])) {
12 | target[key] = {};
13 | }
14 | if (_.isArray(source[key]) && !_.isArray(target[key])) {
15 | target[key] = [];
16 | }
17 |
18 | extend(target[key], source[key], deep);
19 | } else if (source[key] !== undefined) {
20 | target[key] = source[key];
21 | }
22 | }
23 | }
24 |
25 | _.isFunction = function (obj) {
26 | return obj && typeof obj === 'function';
27 | };
28 |
29 | _.isString = function(value) {
30 | return value && typeof value === 'string';
31 | };
32 |
33 | _.isNumber = function(value) {
34 | return typeof value === 'number';
35 | };
36 |
37 | _.options = function (key, obj, options) {
38 | const opts = obj.$options || {};
39 |
40 | return _.extend({},
41 | opts[key],
42 | options
43 | );
44 | };
45 |
46 | _.each = function (obj, iterator) {
47 | let i;
48 | let key;
49 |
50 | if (typeof obj.length == 'number') {
51 | for (i = 0; i < obj.length; i++) {
52 | iterator.call(obj[i], obj[i], i);
53 | }
54 | } else if (_.isObject(obj)) {
55 | for (key in obj) {
56 | if (obj.hasOwnProperty(key)) {
57 | iterator.call(obj[key], obj[key], key);
58 | }
59 | }
60 | }
61 |
62 | return obj;
63 | };
64 |
65 | _.extend = function (target) {
66 | const array = [];
67 | const args = array.slice.call(arguments, 1);
68 |
69 | let deep;
70 |
71 | if (typeof target == 'boolean') {
72 | deep = target;
73 | target = args.shift();
74 | }
75 |
76 | args.forEach(function (arg) {
77 | extend(target, arg, deep);
78 | });
79 |
80 | return target;
81 | };
82 |
83 |
84 | _.Promise = Promise;
85 |
86 | export default _;
87 |
--------------------------------------------------------------------------------
/src/views/Home/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Row, Col, Collapse, Alert } from 'antd';
3 | const Panel = Collapse.Panel;
4 |
5 | // import {Line,Pie,Doughnut} from 'react-chartjs';
6 |
7 | import styles from './index.less'
8 |
9 | const chartOption = {
10 | responsive: true
11 | }
12 |
13 | const text = `
14 | A dog is a type of domesticated animal.
15 | Known for its loyalty and faithfulness,
16 | it can be found as a welcome guest in many households across the world.
17 | A dog is a type of domesticated animal.
18 | Known for its loyalty and faithfulness,
19 | it can be found as a welcome guest in many households across the world.
20 | A dog is a type of domesticated animal.
21 | Known for its loyalty and faithfulness,
22 | it can be found as a welcome guest in many households across the world.
23 | `;
24 |
25 | export default class Home extends React.Component {
26 | constructor() {
27 | super()
28 | }
29 |
30 | componentWillMount() {
31 | }
32 |
33 | callback() {
34 |
35 | }
36 |
37 | render() {
38 | const detail = (
39 |
71 | )
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/components/BDUploader.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Button, Icon, message } from 'antd';
3 | import baidubce from 'bce-sdk-js';
4 |
5 | let config = {
6 | endpoint: 'http://bj.bcebos.com', //传入Bucket所在区域域名
7 | credentials: {
8 | ak: 'e4a6dcc47a3b46f3a5ebf0f81d0e4928', //您的AccessKey
9 | sk: '8d26035b87e14989a4343f0e43c0ce71' //您的SecretAccessKey
10 | }
11 | };
12 |
13 | let client = new baidubce.BosClient(config);
14 |
15 | const createKey = function(ext){
16 | let date = new Date();
17 |
18 | let year = date.getFullYear();
19 | let month = date.getMonth()+1;
20 | month = (month < 10) ? '0' + month: month;
21 |
22 | let day = date.getDate();
23 | day = (day < 10) ? '0' + day: day;
24 |
25 | return year + '/' + month + '/' + day + '/' + (+new Date())+ '.'+ext;
26 | }
27 |
28 | // 百度浏览器特定文件上传组件
29 | let BDUploader = React.createClass({
30 | getInitialState: function() {
31 | return {
32 |
33 | };
34 | },
35 |
36 | render: function() {
37 | return
;
43 | },
44 |
45 | openFileInput: function(e){
46 | this.refs.fileInput.click();
47 | },
48 | uploadImg: function(e){
49 | let self = this;
50 |
51 | let file = e.target.files[0]; // 获取要上传的文件
52 | let ext = file.name.split(/\./g).pop();
53 |
54 | let key = createKey(ext); // 保存到bos时的key,您可更改,默认以文件名作为key
55 | let mimeType = baidubce.MimeType.guess(ext);
56 |
57 | client.putObjectFromBlob("mbrowser", key, file, {
58 | 'Content-Type': /^text\//.test(mimeType)? mimeType+'; charset=UTF-8': mimeType
59 | }).then(function (res) {
60 | // 上传完成,添加您的代码
61 | let imgUrl = config.endpoint+'/v1/mbrowser/'+key;
62 | console.log('上传成功', imgUrl);
63 | self.props.success&&self.props.success(imgUrl);
64 | }).catch(function (err) {
65 | // 上传失败,添加您的代码
66 | self.props.error&&self.props.error(error);
67 | });
68 | }
69 | });
70 |
71 | export default BDUploader;
72 |
--------------------------------------------------------------------------------
/src/components/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 { getFieldProps } = this.props.form;
16 | const formItemLayout = {
17 | labelCol: { span: 6 },
18 | wrapperCol: { span: 18 },
19 | };
20 |
21 | return CType ?
22 |
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 | CForm = Form.create()(CForm);
70 |
71 | export default CForm;
72 |
--------------------------------------------------------------------------------
/src/views/App/index.js:
--------------------------------------------------------------------------------
1 | import React, {PropTypes} from 'react';
2 | import {bindActionCreators} from 'redux';
3 | import {connect} from 'react-redux';
4 | import {Affix, Row, Col, Icon} from 'antd';
5 |
6 | import NavPath from '../../components/NavPath';
7 | import Header from '../../components/Header';
8 | import Sidebar from '../../components/Sidebar';
9 | import Footer from '../../components/Footer';
10 |
11 | import { fetchProfile, logout } from '../../store/modules/user/user_action';
12 | // import 'antd/dist/antd.less';
13 | import styles from './index.less';
14 |
15 | class App extends React.Component {
16 | constructor(props) {
17 | super(props);
18 | }
19 |
20 | /**
21 | * 判断登入权限
22 | */
23 | componentWillMount() {
24 | const {actions} = this.props;
25 | actions.fetchProfile();
26 | }
27 | /**
28 | * 监听porps
29 | *
30 | * 1、监听注销字段,刷新页面
31 | *
32 | * @param {any} nextProps
33 | */
34 | componentWillReceiveProps(nextProps) {
35 | const loggingOut = nextProps.loggingOut;
36 | if (loggingOut) {
37 | window.location.href = '/';
38 | }
39 | }
40 | render() {
41 | const {user, actions} = this.props;
42 | const { collapse } = this.props; // 判断侧边栏隐藏显示
43 |
44 | return (
45 |
58 | );
59 | }
60 | }
61 |
62 | App.propTypes = {
63 | user: PropTypes.object,
64 | children: PropTypes.node.isRequired
65 | };
66 |
67 | App.contextTypes = {
68 | history: PropTypes.object.isRequired,
69 | store: PropTypes.object.isRequired
70 | };
71 |
72 | const mapStateToProps = (state) => {
73 | const {user} = state;
74 | return {
75 | user: user ? user : null,
76 | loggingOut: user.loggingOut,
77 | // collapse: state.menu.collapse
78 | };
79 | };
80 |
81 | function mapDispatchToProps(dispatch) {
82 | return {
83 | actions: bindActionCreators({ fetchProfile, logout }, dispatch)
84 | };
85 | }
86 |
87 | export default connect(mapStateToProps, mapDispatchToProps)(App);
88 |
--------------------------------------------------------------------------------
/src/store/middlewares/promiseMiddleware.js:
--------------------------------------------------------------------------------
1 | import { isPromise } from '../../util'
2 |
3 | const defaultTypes = ['PENDING', 'FULFILLED', 'REJECTED']
4 | export default function promiseMiddleware (config = {}) {
5 | const promiseTypeSuffixes = config.promiseTypeSuffixes || defaultTypes
6 |
7 | return (_ref) => {
8 | const dispatch = _ref.dispatch
9 |
10 | return next => action => {
11 | if (!isPromise(action.payload)) {
12 | return next(action)
13 | }
14 |
15 | const { type, payload, meta, params = {} } = action
16 | const { promise, data } = payload
17 | const [ PENDING, FULFILLED, REJECTED ] = (meta || {}).promiseTypeSuffixes || promiseTypeSuffixes
18 |
19 | /**
20 | * Dispatch the first async handler. This tells the
21 | * reducer that an async action has been dispatched.
22 | */
23 | next({
24 | type: `${type}_${PENDING}`,
25 | ...!!data ? { payload: data, params } : {},
26 | ...!!meta ? { meta } : {}
27 | })
28 |
29 | const isAction = resolved => resolved && (resolved.meta || resolved.payload)
30 | const isThunk = resolved => typeof resolved === 'function'
31 | const getResolveAction = isError => ({
32 | type: `${type}_${isError ? REJECTED : FULFILLED}`,
33 | ...!!meta ? { meta } : {},
34 | ...!!isError ? { error: true } : {}
35 | })
36 |
37 | /**
38 | * Re-dispatch one of:
39 | * 1. a thunk, bound to a resolved/rejected object containing ?meta and type
40 | * 2. the resolved/rejected object, if it looks like an action, merged into action
41 | * 3. a resolve/rejected action with the resolve/rejected object as a payload
42 | */
43 | action.payload.promise = promise.then(
44 | (resolved = {}) => {
45 | const resolveAction = getResolveAction()
46 | return dispatch(isThunk(resolved) ? resolved.bind(null, resolveAction) : {
47 | ...resolveAction,
48 | ...isAction(resolved) ? resolved : {
49 | ...!!resolved && { payload: resolved, params }
50 | }
51 | })
52 | },
53 | (rejected = {}) => {
54 | const resolveAction = getResolveAction(true)
55 | return dispatch(isThunk(rejected) ? rejected.bind(null, resolveAction) : {
56 | ...resolveAction,
57 | ...isAction(rejected) ? rejected : {
58 | ...!!rejected && { payload: rejected, params }
59 | }
60 | })
61 | }
62 | )
63 |
64 | return action
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "entry": {},
4 | "dependencies": {
5 | "antd": "^1.1.0",
6 | "atool-build": "0.7.x",
7 | "babel-plugin-antd": "0.4.x",
8 | "babel-plugin-transform-runtime": "^6.8.0",
9 | "babel-runtime": "^6.6.1",
10 | "bce-sdk-js": "^0.1.8",
11 | "classnames": "^2.2.3",
12 | "echarts-for-react": "^1.1.2",
13 | "es3ify-loader": "^0.2.0",
14 | "fetch-ie8": "^1.4.0",
15 | "history": "^2.0.1",
16 | "immutable": "^3.8.1",
17 | "isomorphic-fetch": "^2.2.1",
18 | "js-cookie": "^2.1.1",
19 | "key-mirror": "^1.0.1",
20 | "lodash": "^4.13.1",
21 | "md5": "^2.1.0",
22 | "object-assign": "^4.0.1",
23 | "react": "0.14.x",
24 | "react-chartjs": "^0.7.3",
25 | "react-dom": "0.14.x",
26 | "react-redux": "^4.4.0",
27 | "react-router": "2.3.x",
28 | "react-router-redux": "^4.0.5",
29 | "redux": "^3.3.1",
30 | "redux-logger": "^2.6.1",
31 | "redux-thunk": "^2.0.1",
32 | "reqwest": "^2.0.5",
33 | "superagent": "^2.1.0"
34 | },
35 | "devDependencies": {
36 | "atool-test-mocha": "^0.1.4",
37 | "babel-eslint": "^6.0.0",
38 | "babel-core": "^6.4.0",
39 | "babel-loader": "~6.2.1",
40 | "babel-polyfill": "^6.3.14",
41 | "babel-preset-es2015": "^6.3.13",
42 | "babel-preset-react": "^6.3.13",
43 | "babel-register": "^6.3.13",
44 | "chai": "^3.4.1",
45 | "dora": "0.3.x",
46 | "dora-plugin-browser-history": "^0.1.1",
47 | "dora-plugin-hmr": "0.6.x",
48 | "dora-plugin-livereload": "0.3.x",
49 | "dora-plugin-proxy": "0.6.x",
50 | "dora-plugin-webpack": "0.6.x",
51 | "enzyme": "^1.2.0",
52 | "expect": "^1.20.1",
53 | "eslint": "^2.7.0",
54 | "eslint-config-airbnb": "6.x",
55 | "eslint-plugin-react": "4.x",
56 | "glob": "^7.0.3",
57 | "jsdom": "^9.4.1",
58 | "karma": "^0.13.19",
59 | "karma-chai": "^0.1.0",
60 | "karma-mocha": "^0.2.1",
61 | "karma-phantomjs-launcher": "^0.2.3",
62 | "karma-sourcemap-loader": "^0.3.6",
63 | "karma-spec-reporter": "0.0.23",
64 | "karma-webpack": "^1.7.0",
65 | "mocha": "^2.3.4",
66 | "react-addons-test-utils": "^0.14.6",
67 | "sinon": "^1.17.2"
68 | },
69 | "scripts": {
70 | "build": "atool-build",
71 | "lint": "eslint --ext .js,.jsx src",
72 | "start": "dora -p 8001 --plugins \"webpack,proxy,livereload?enableJs=false&injectHost=127.0.0.1,browser-history?index=/src/entries/index.html\"",
73 | "test-antd": "atool-test-mocha ./src/**/__tests__/*-test.js",
74 | "test": "mocha --compilers js:babel-core/register --require ./test/test_helper.js --recursive",
75 | "test:watch": "npm test -- --watch"
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/components/Sidebar/index.less:
--------------------------------------------------------------------------------
1 | // .ant-layout-aside .ant-layout-logo {
2 | // width: 150px;
3 | // height: 32px;
4 | // background: #333;
5 | // border-radius: 6px;
6 | // margin: 16px 24px 16px 28px;
7 | // }
8 |
9 |
10 | // .ant-layout-aside .ant-layout-sider {
11 | // width: 224px;
12 | // background: #404040;
13 | // position: absolute;
14 | // overflow: auto;
15 | // padding-bottom: 24px;
16 | // height: 100%;
17 | // }
18 |
19 | // .ant-layout-aside .ant-layout-sider > .ant-menu {
20 | // margin-bottom: 20px;
21 | // }
22 |
23 | /*********************/
24 | .nav-text {
25 | vertical-align: baseline;
26 | display: inline-block;
27 | white-space: nowrap;
28 | }
29 | .ant-layout-logo {
30 | position: relative;
31 | width: 150px;
32 | height: 32px;
33 | // background: #333;
34 | color: #999;
35 | border-radius: 6px;
36 | margin: 16px 24px 16px 28px;
37 | padding: 7px 0px 0 60px;
38 | transition: all 0.3s ease;
39 | }
40 | .ant-layout-logo > img {
41 | position: absolute;
42 | top: 0;
43 | left: -11px;
44 | height: 100%;
45 | }
46 |
47 | .ant-layout-sider {
48 | width: 224px;
49 | background: #404040;
50 | position: absolute;
51 | overflow: visible;
52 | padding-bottom: 24px;
53 | height: 100%;
54 | transition: all 0.3s ease;
55 | }
56 | .nav-portrait img {
57 | width: 120px;
58 | height: 120px;
59 | border-radius: 50%;
60 | transition: all 1s ease;
61 | }
62 |
63 |
64 | // 头像
65 | .nav-portrait {
66 | text-align: center;
67 | margin-bottom: 10px;
68 | margin-top: 20px;
69 | transition: all 3s ease;
70 | }
71 | .nav-portrait img {
72 | width: 120px;
73 | height: 120px;
74 | border-radius: 50%;
75 | transition: all 1s ease;
76 | }
77 | .nav-portrait-title {
78 | color: #ccc;
79 | text-align: center;
80 | cursor: pointer;
81 | transition: all 3s ease;
82 | }
83 | .nav-portrait-title:hover {
84 | text-decoration: underline;
85 | }
86 | .nav-portrait-name {
87 | color: #2db7f5;
88 | text-align: center;
89 | transition: all 3s ease;
90 | }
91 |
92 |
93 | .ant-layout-aside-collapse .ant-layout-sider > .ant-layout-portrait > .nav-portrait {
94 | height: 32px;
95 | transition: all 3s ease;
96 | }
97 | .ant-layout-aside-collapse .ant-layout-sider > .ant-layout-portrait > .nav-portrait img {
98 | width: 32px;
99 | height: 32px;
100 | transition: all 0s ease;
101 | }
102 | .ant-layout-aside-collapse .ant-layout-sider > .ant-layout-portrait > .nav-portrait-title,
103 | .ant-layout-aside-collapse .ant-layout-sider > .ant-layout-portrait > .nav-portrait-name {
104 | display: none;
105 | transition: all 3s ease;
106 | }
107 |
--------------------------------------------------------------------------------
/src/store/modules/menu/menu_reducer.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import { message } from 'antd';
3 | import { createReducer } from '../../../util';
4 | import types from '../../types';
5 | import initialState from './menu_state';
6 | import objectAssign from 'object-assign';
7 |
8 | export default createReducer(initialState, {
9 | [`${types.GET_TOP_MENU}`]: (state, data, params) => {
10 | return objectAssign({}, state, { topMenu: params.topMenu });
11 | },
12 |
13 | [`${types.UPDATE_NAVPATH}`]: (state, data) => {
14 |
15 | let navpath = [], tmpOb, tmpKey, child, selectClass = 'ant-menu-item-selected';
16 | /**
17 | * 判断 `Action` 传来的数据是否有 `面包屑` 信息
18 | *
19 | * `Menu` 控件传来的值 ['子级控件值', '父级控件值'],将数组倒序,先遍历父级标签
20 | * 如果不做方向操作,`child` 没有子级菜单列表,导致程序出错
21 | *
22 | * 判断如果是父级标签,查询菜单Json,取到对应Key的值。
23 | * 储存该菜单的子集菜单集合到 `child` 中
24 | * 将 `key`、`name` 添加到 `面包屑` 集合中
25 | *
26 | * 判断如果是子级标签,取出对应的Key值
27 | * 判断 `child` 是否有值,
28 | * 取到对应的子级数据中的Json
29 | * 将 `key`、`name` 添加到 `面包屑` 集合中
30 | *
31 | * 在面包屑组件中遍历 `navpath` 构建 `Breadcrumb` 标签的值,按顺序显示相关内容
32 | *
33 | * `selectClass` 用于解决同步菜单二级菜单点击时 `class` 选中状态的问题,目前没有二级菜单,所以暂时没有用处
34 | *
35 | */
36 | if (data.data) {
37 | data.data.reverse().map((item) => {
38 | if (item.indexOf('sub') != -1) {
39 | tmpKey = item.replace('sub', '');
40 | tmpOb = _.find(state.topMenu, function(o) {
41 | return o.key == tmpKey;
42 | });
43 | child = tmpOb.child;
44 | navpath.push({
45 | key: tmpOb.key,
46 | name: tmpOb.name
47 | })
48 | // selectClass = ''
49 | }
50 | if (item.indexOf('menu') != -1) {
51 | tmpKey = item.replace('menu', '');
52 | if (child) {
53 | tmpOb = _.find(child, function(o) {
54 | return o.key == tmpKey;
55 | });
56 | }
57 | navpath.push({
58 | key: tmpOb.key,
59 | name: tmpOb.name
60 | })
61 | }
62 | })
63 | }
64 |
65 | return objectAssign({}, state, {
66 | currentIndex: data.key * 1,
67 | navpath: navpath,
68 | selectClass: selectClass
69 | });
70 | },
71 |
72 | [`${types.UPDATE_STATUS}`]: (state, data) => {
73 | return objectAssign({}, state, { status: data.status });
74 | },
75 |
76 | [`${types.GET_LEFT_MENU}`]: (state, data, params) => {
77 | return objectAssign({}, state, { leftMenu: params.leftMenu });
78 | },
79 |
80 | [`${types.INIT_MENU}`]: (state, data, params) => {
81 |
82 | params.leftMenu.map((item) => {
83 | item.num = 0;
84 | });
85 |
86 | return objectAssign({}, state, { leftMenuType: leftMenuType });
87 | },
88 |
89 | [`${types.UPDATE_COLLAPSE}`]: (state, data) => {
90 | return objectAssign({}, state, { collapse: !data.collapse });
91 | },
92 |
93 | [`${types.GET_ADD_CASE_LEFT_MENU}`]: (state, data) => {
94 | return objectAssign({}, state, { leftMenu: leftMenu });
95 | },
96 | })
--------------------------------------------------------------------------------
/src/feature/Feature2.jsx:
--------------------------------------------------------------------------------
1 | // 含有可操作 table 栏的数据展示
2 | import React from 'react';
3 |
4 | import FeatureSetConfig from '../components/FeatureSetConfig';
5 |
6 | import Immutable from 'immutable';
7 | //https://github.com/ded/reqwest
8 | import Reqwest from 'reqwest';
9 |
10 |
11 | const conf = {
12 |
13 | initData: function(callback){
14 |
15 | let data = {
16 | type: 'entry_list',
17 | num: 20,
18 | ua: 'bd_1_1_1_5-5-0-0_1',
19 | cuid: '00000000000000000000000000000000%7C0000000000000000',
20 | channel: 'AA_0',
21 | dir: 'up'
22 | }
23 |
24 | Reqwest({
25 | url: 'http://uil.cbs.baidu.com/rssfeed/fetch?fn=?',
26 | data: data,
27 | type: 'jsonp',
28 | jsonpCallback: 'fn',
29 | success: function (data) {
30 | let lists = data.data.stream_data;
31 |
32 | // 必须要向数据中 添加唯一的 key
33 | lists.forEach(function(ele) {
34 | ele.key = ele.docid;
35 | });
36 |
37 | callback(lists);
38 | }
39 | });
40 |
41 | },
42 |
43 | Delete: function(data, callback){
44 |
45 | let dataI = Immutable.fromJS({
46 | type: 'entry_list'
47 | }).merge({id: data.key});
48 |
49 | // ... 操作删除请求
50 | console.log(dataI.toJS());
51 |
52 | // 模拟请求删除成功的回调
53 | setTimeout(function(){
54 | callback();
55 | }, 1000)
56 |
57 | },
58 |
59 | columns: [
60 | {
61 | title: 'DOCID', // table header 文案
62 | dataIndex: 'docid', // 数据对象内的属性,也做react vdom 的key
63 | type: 'string', // table 内显示的类型
64 | sort: true, // 是否需要排序
65 | width:200 // 列宽 可选 不填为默认均分
66 | }, {
67 | title: '标题',
68 | dataIndex: 'title',
69 | type: 'string'
70 | }, {
71 | title: '链接',
72 | dataIndex: 'link',
73 | type: 'link'
74 | }, {
75 | title: '操作',
76 | type: 'operate', // 操作的类型必须为 operate
77 | width: 80,
78 | btns: [{
79 | text: '删除',
80 | type: 'delete'
81 | }, {
82 | text: '展示',
83 | callback: function(item){
84 | alert(JSON.stringify(item));
85 | }
86 | }], // 可选
87 |
88 | // 对应btns 的回调函数
89 | // item为操作的单一数据对象
90 | // callback 为组件的回调函数,将处理之后的数据回传 删除则传undefined
91 | // callbacks: [function(item, callback){
92 | // item.docid = 0;
93 | // callback(item, 'update');
94 | // },function(item, callback){
95 | // callback(item, 'delete');
96 | // }]
97 | }
98 | ]
99 |
100 | };
101 |
102 | const Feature2 = FeatureSetConfig(conf);
103 |
104 | export default Feature2;
105 |
--------------------------------------------------------------------------------
/src/feature/Feature1-1.jsx:
--------------------------------------------------------------------------------
1 | // 纯数据展现情况列表
2 | import React from 'react';
3 |
4 | import FeatureSetConfig from '../components/FeatureSetConfig';
5 |
6 | import Immutable from 'immutable';
7 | import Reqwest from 'reqwest';
8 |
9 | import testData from '../common/test-data';
10 |
11 | // 增加(Create)、重新取得数据(Retrieve)、更新(Update)和删除(Delete)
12 | const table_conf = {
13 |
14 | type: 'tableList', // tableList graphList simpleObject complexObject
15 |
16 | // 初始化展现的数据,使用callback 回传列表数据
17 | // 需要手动添加唯一id key
18 | // callback 组件数据的回调函数(接受列表数据参数)
19 | initData: function(callback){
20 | // 接口调用数据形式
21 | /*
22 | let data = {
23 | type: 'entry_list',
24 | num: 20,
25 | ua: 'bd_1_1_1_5-5-0-0_1',
26 | cuid: '00000000000000000000000000000000%7C0000000000000000',
27 | channel: 'AA_0',
28 | dir: 'up'
29 | }
30 |
31 | Reqwest({
32 | url: 'http://uil.cbs.baidu.com/rssfeed/fetch?fn=?',
33 | data: data,
34 | type: 'jsonp',
35 | jsonpCallback: 'fn',
36 | success: function (data) {
37 | let lists = data.data.stream_data;
38 |
39 | // 必须要向数据中 添加唯一的 key
40 | lists.forEach(function(ele) {
41 | ele.key = ele.docid;
42 | });
43 |
44 | callback(lists);
45 | }
46 | });
47 | */
48 |
49 | // 模拟数据
50 | setTimeout(function(){
51 | let list = testData.tableList;
52 | list.forEach(function(ele) {
53 | ele.key = ele.docid;
54 | });
55 | callback(list);
56 | }, 1000)
57 | },
58 |
59 | // table 列表展现配置
60 | // {
61 | // title table显示表题
62 | // dataIndex 显示数据中的key
63 | // type 展现形式 (string image link)
64 | // render 自定义展现形式 参数 (当前数据,当前对象数据)
65 | // sort 是否需要排序功能
66 | // width 自定义该列宽度 否则等分
67 | // }
68 | //
69 | // table 列表头标题
70 | columns: [
71 | {
72 | title: 'DOCID', // table header 文案
73 | dataIndex: 'docid', // 数据对象内的属性,也做react vdom 的key
74 | type: 'string', // table 内显示的类型
75 | sort: true, // 是否需要排序
76 | width:200
77 | }, {
78 | title: '标题',
79 | dataIndex: 'title',
80 | type: 'string'
81 | }, {
82 | title: '链接',
83 | dataIndex: 'link',
84 | type: 'link',
85 | render: (text) => (
),
88 | width: 50
89 | },{
90 | title: '日期',
91 | dataIndex: 'date',
92 | type: 'string',
93 | width: 150
94 | },{
95 | title: '图片',
96 | dataIndex: 'img',
97 | type: 'image'
98 | }
99 | ]
100 |
101 | };
102 |
103 | const Feature1 = FeatureSetConfig(table_conf);
104 |
105 | export default Feature1;
106 |
--------------------------------------------------------------------------------
/src/components/Loding/index.less:
--------------------------------------------------------------------------------
1 | .boxflex{display:box;display:-webkit-box;}
2 | .center{display:box;display:-webkit-box;-webkit-box-pack:center;-webkit-box-align:center;}
3 | .box{width:200px;height:200px;border:1px solid #ccc;position:relative;}
4 | .move{animation:move 2s infinite;-webkit-animation:move 2s infinite;}
5 | .scale{animation:scale 1s infinite;-webkit-animation:scale 1s infinite;}
6 | .line{animation:line 1s infinite;-webkit-animation:line 1s infinite;}
7 | .fz{animation:fz 1.5s infinite;-webkit-animation:fz 1.5s infinite;}
8 | .delay1{animation-delay:0.25s;-webkit-animation-delay:0.25s;}
9 | .delay2{animation-delay:0.5s;-webkit-animation-delay:0.5s;}
10 | .load{width:100px;height:100px;border:10px solid #ccc;border-radius:50%;display:block;}
11 | .load1{border-top:10px solid #64efb9;}
12 | .load2{position:relative;}
13 | .load2:before{position:absolute;top:0;left:50%;margin-left:-10px;margin-top:-15px;width:20px;height:20px;border-radius:50%;background:#fff;content:'';box-shadow:0 0 10px #747373;}
14 | .sc,.li{display:block;}
15 | .sc i{width:20px;height:20px;background:#64efb9;border-radius:50%;display:inline-block;margin:0 10px;}
16 | .li i{display:inline-block;background:#64efb9;width:10px;height:50px;margin:0 4px;}
17 | .li em{background:#fff;border:10px solid #64efb9;width:50px;height:50px;display:inline-block;}
18 | .li i:nth-child(2){animation-delay:.2s;-webkit-animation-delay:.2s;}
19 | .li i:nth-child(3){animation-delay:.3s;-webkit-animation-delay:.3s;}
20 | .li i:nth-child(4){animation-delay:.4s;-webkit-animation-delay:.4s;}
21 | .li i:nth-child(5){animation-delay:.5s;-webkit-animation-delay:.5s;}
22 | .li i:nth-child(6){animation-delay:.6s;-webkit-animation-delay:.6s;}
23 |
24 | @keyframes move{
25 | 0%{
26 | transform:rotateZ(0);
27 | }
28 | 100%{
29 | transform:rotateZ(360deg);
30 | }
31 | }
32 | @-webkit-keyframes move{
33 | 0%{
34 | -webkit-transform:rotateZ(0);
35 | }
36 | 100%{
37 | -webkit-transform:rotateZ(360deg);
38 | }
39 | }
40 | @keyframes scale{
41 | /*0%{
42 | transform:scale3d(1,1,1);
43 | }*/
44 | 50%{
45 | transform:scale3d(0,0,0);
46 | }
47 | /*100%{
48 | transform:scale3d(1,1,1);
49 | }*/
50 | }
51 | @-webkit-keyframes scale{
52 | /*0%{
53 | -webkit-transform:scale3d(1,1,1);
54 | }*/
55 | 50%{
56 | -webkit-transform:scale3d(0,0,0);
57 | }
58 | /*100%{
59 | -webkit-transform:scale3d(1,1,1);
60 | }*/
61 | }
62 | @keyframes line{
63 | 50%{
64 | transform:scaleY(0);
65 | }
66 | }
67 | @-webkit-keyframes line{
68 | 50%{
69 | -webkit-transform:scaleY(0);
70 | }
71 | }
72 | @keyframes fz{
73 | 0%{
74 | transform:perspective(160px);
75 | }
76 | 50%{
77 | transform:perspective(160px) rotateX(-180deg) rotateY(0);
78 | }
79 | 100%{
80 | transform:perspective(160px) rotateX(-180deg) rotateY(-180deg);
81 | }
82 | }
83 | @-webkit-keyframes fz{
84 | 0%{
85 | -webkit-transform:perspective(160px);
86 | }
87 | 50%{
88 | -webkit-transform:perspective(160px) rotateX(-180deg) rotateY(0);
89 | }
90 | 100%{
91 | -webkit-transform:perspective(160px) rotateX(-180deg) rotateY(-180deg);
92 | }
93 | }
--------------------------------------------------------------------------------
/src/feature/Feature1-3.jsx:
--------------------------------------------------------------------------------
1 | // 纯数据展现情况列表
2 | import React from 'react';
3 |
4 | import FeatureSetConfig from '../components/FeatureSetConfig';
5 |
6 | import Immutable from 'immutable';
7 | import Reqwest from 'reqwest';
8 |
9 | import testData from '../common/test-data';
10 |
11 | const graph_conf = {
12 |
13 | type: 'graphList', // tableList graphList simpleObject complexObject
14 | EchartStyle: {
15 | width: '100%',
16 | height: '450px'
17 | },
18 |
19 | // 初始化展现的数据,使用callback 回传列表数据
20 | // 需要手动添加唯一id key
21 | // callback 组件数据的回调函数(接受列表数据参数)
22 | initData: function(callback){
23 |
24 | // 模拟数据
25 | setTimeout(function(){
26 | let series = testData.graphList;
27 | series.forEach(function(item) {
28 | item.type = 'line';
29 | item.stack = '总量'
30 | });
31 |
32 | callback(series);
33 | }, 1000)
34 | },
35 |
36 | // 参考echarts 参数
37 | option : {
38 | title: {
39 | text: '堆叠区域图'
40 | },
41 | tooltip : {
42 | trigger: 'axis'
43 | },
44 | legend: {
45 | data:['邮件营销','联盟广告','视频广告']
46 | },
47 | toolbox: {
48 | feature: {
49 | saveAsImage: {}
50 | }
51 | },
52 | grid: {
53 | left: '3%',
54 | right: '4%',
55 | bottom: '3%',
56 | containLabel: true
57 | },
58 | xAxis : [
59 | {
60 | type : 'category',
61 | boundaryGap : false,
62 | data : ['周一','周二','周三','周四','周五','周六','周日']
63 | }
64 | ],
65 | yAxis : [
66 | {
67 | type : 'value'
68 | }
69 | ]
70 | }
71 |
72 | };
73 |
74 | const graph_conf2 = {
75 |
76 | type: 'graphList', // tableList graphList simpleObject complexObject
77 | style: {
78 | width: '100%',
79 | height: '450px'
80 | },
81 |
82 | // 初始化展现的数据,使用callback 回传列表数据
83 | // 需要手动添加唯一id key
84 | // callback 组件数据的回调函数(接受列表数据参数)
85 | initData: function(callback){
86 |
87 | // 模拟数据
88 | setTimeout(function(){
89 | let series = [
90 | {
91 | name: '访问来源',
92 | type: 'pie',
93 | radius : '55%',
94 | center: ['50%', '60%'],
95 | data:[
96 | {value:335, name:'直接访问'},
97 | {value:310, name:'邮件营销'},
98 | {value:234, name:'联盟广告'},
99 | {value:135, name:'视频广告'},
100 | {value:1548, name:'搜索引擎'}
101 | ],
102 | itemStyle: {
103 | emphasis: {
104 | shadowBlur: 10,
105 | shadowOffsetX: 0,
106 | shadowColor: 'rgba(0, 0, 0, 0.5)'
107 | }
108 | }
109 | }
110 | ]
111 |
112 | callback(series);
113 | }, 1000)
114 | },
115 |
116 | // 参考echarts 参数
117 | option : {
118 | title : {
119 | text: '某站点用户访问来源',
120 | subtext: '纯属虚构',
121 | x:'center'
122 | },
123 | tooltip : {
124 | trigger: 'item',
125 | formatter: "{a}
{b} : {c} ({d}%)"
126 | },
127 | legend: {
128 | orient: 'vertical',
129 | left: 'left',
130 | data: ['直接访问','邮件营销','联盟广告','视频广告','搜索引擎']
131 | }
132 | }
133 |
134 | };
135 |
136 | const Feature = FeatureSetConfig(graph_conf2);
137 |
138 | export default Feature;
139 |
--------------------------------------------------------------------------------
/src/views/Login/index.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import { Form, Input, Button, Row, Col, notification, Checkbox } from 'antd';
3 | import { bindActionCreators } from 'redux';
4 | import { connect } from 'react-redux';
5 |
6 | import { login } from '../../store/modules/user/user_action';
7 |
8 | const FormItem = Form.Item;
9 |
10 | import styles from './index.less'
11 |
12 | const propTypes = {
13 | user: PropTypes.string,
14 | loggingIn: PropTypes.bool,
15 | loginErrors: PropTypes.string
16 | };
17 |
18 | const contextTypes = {
19 | router: PropTypes.object.isRequired,
20 | store: PropTypes.object.isRequired
21 | };
22 |
23 | class Login extends React.Component {
24 |
25 | constructor(props) {
26 | super(props)
27 | }
28 |
29 | /**
30 | * 监听props变化
31 | *
32 | * 1、判断登入失败
33 | * 2、判断登入成功
34 | * 3、跳转默认页面
35 | *
36 | * @param {any} nextProps
37 | */
38 | componentWillReceiveProps(nextProps) {
39 | const error = nextProps.loginErrors;
40 | const isLoggingIn = nextProps.loggingIn;
41 | const user = nextProps.user
42 |
43 | if (error != this.props.loginErrors && error) {
44 | notification.error({
45 | message: 'Login Fail',
46 | description: error
47 | });
48 | }
49 |
50 | if (!isLoggingIn && !error && user) {
51 | notification.success({
52 | message: 'Login Success',
53 | description: 'Welcome ' + user,
54 | duration: 2,
55 | });
56 | }
57 |
58 | if (user) {
59 | this.context.router.replace('/home');
60 | }
61 | }
62 |
63 | /**
64 | * 提交登入请求
65 | *
66 | * @param {any} e
67 | */
68 | handleSubmit(e) {
69 | e.preventDefault()
70 | const data = this.props.form.getFieldsValue()
71 | this.props.login(data.user, data.password)
72 | }
73 |
74 | render() {
75 | const { getFieldProps } = this.props.form
76 | return (
77 |
113 | )
114 | }
115 | }
116 |
117 | Login.contextTypes = contextTypes;
118 | Login.propTypes = propTypes;
119 | Login = Form.create()(Login);
120 |
121 | function mapStateToProps(state) {
122 | const {user} = state;
123 | if (user.user) {
124 | return { user: user.user, loggingIn: user.loggingIn, loginErrors: '' };
125 | }
126 |
127 | return { user: null, loggingIn: user.loggingIn, loginErrors: user.loginErrors };
128 | }
129 |
130 | function mapDispatchToProps(dispatch) {
131 | return {
132 | login: bindActionCreators(login, dispatch)
133 | }
134 | }
135 |
136 | export default connect(mapStateToProps, mapDispatchToProps)(Login)
137 |
--------------------------------------------------------------------------------
/src/components/RetrieveForm.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Form, Select, Input, Button, Icon , DatePicker, TimePicker, Radio, Switch} from 'antd';
3 | import { Upload, Modal, message } from 'antd';
4 |
5 | const FormItem = Form.Item;
6 | const Option = Select.Option;
7 | const RadioGroup = Radio.Group;
8 |
9 | let RForm = React.createClass({
10 | render: function() {
11 | const self = this;
12 | const RType = this.props.RType;
13 | return RType ?
14 | (
;
27 | },
28 |
29 | dealConfigRType: function(item){
30 | const { getFieldProps } = this.props.form;
31 |
32 | switch (item.type){
33 | case 'string':
34 | return
40 | break;
41 |
42 | case 'date':
43 | return
48 | break;
49 |
50 | case 'select':
51 | return
62 | break;
63 |
64 | case 'radio':
65 | return
76 | break;
77 |
78 | case 'switch':
79 | return
84 | break;
85 |
86 | default:
87 | return '';
88 | break;
89 | }
90 | },
91 |
92 | handleRetrieve: function(){
93 |
94 | console.log('收到表单值:', this.props.form.getFieldsValue());
95 | this.props.submit(this.props.form.getFieldsValue());
96 | }
97 | });
98 | RForm = Form.create()(RForm);
99 |
100 | export default RForm;
101 |
--------------------------------------------------------------------------------
/src/feature/Feature1.jsx:
--------------------------------------------------------------------------------
1 | // 纯数据展现情况列表
2 | import React from 'react';
3 |
4 | import FeatureSetConfig from '../components/FeatureSetConfig';
5 |
6 | // import Immutable from 'immutable';
7 | // import Reqwest from 'reqwest';
8 |
9 | import testData from '../common/test-data';
10 |
11 | // 增加(Create)、重新取得数据(Retrieve)、更新(Update)和删除(Delete)
12 | const table_conf = {
13 |
14 | type: 'tableList', // tableList graphList simpleObject complexObject
15 |
16 | // 初始化展现的数据,使用callback 回传列表数据
17 | // 需要手动添加唯一id key
18 | // callback 组件数据的回调函数(接受列表数据参数)
19 | initData: function(callback){
20 | // 接口调用数据形式
21 | /*
22 | let data = {
23 | type: 'entry_list',
24 | num: 20,
25 | ua: 'bd_1_1_1_5-5-0-0_1',
26 | cuid: '00000000000000000000000000000000%7C0000000000000000',
27 | channel: 'AA_0',
28 | dir: 'up'
29 | }
30 |
31 | Reqwest({
32 | url: 'http://uil.cbs.baidu.com/rssfeed/fetch?fn=?',
33 | data: data,
34 | type: 'jsonp',
35 | jsonpCallback: 'fn',
36 | success: function (data) {
37 | let lists = data.data.stream_data;
38 |
39 | // 必须要向数据中 添加唯一的 key
40 | lists.forEach(function(ele) {
41 | ele.key = ele.docid;
42 | });
43 |
44 | callback(lists);
45 | }
46 | });
47 | */
48 |
49 | // 模拟数据
50 | setTimeout(function(){
51 | let list = testData.tableList;
52 | list.forEach(function(ele) {
53 | ele.key = ele.docid;
54 | });
55 | callback(list);
56 | }, 1000)
57 | },
58 |
59 | // table 列表展现配置
60 | // {
61 | // title table显示表题
62 | // dataIndex 显示数据中的key
63 | // type 展现形式 (string image link)
64 | // render 自定义展现形式 参数 (当前数据,当前对象数据)
65 | // sort 是否需要排序功能
66 | // width 自定义该列宽度 否则等分
67 | // }
68 | //
69 | columns: [
70 | {
71 | title: 'DOCID',
72 | dataIndex: 'docid',
73 | type: 'string'
74 | }, {
75 | title: '标题',
76 | dataIndex: 'title',
77 | type: 'string'
78 | }, {
79 | title: '链接',
80 | dataIndex: 'link',
81 | type: 'link',
82 | render: (text, item) => (
) // 可自定义
83 | }
84 | ]
85 |
86 | };
87 |
88 | const simple_conf = {
89 |
90 | type: 'simpleObject',
91 |
92 | initData: function(callback){
93 | // 模拟数据
94 | setTimeout(function(){
95 | let object = testData.simpleObject;
96 | object.key = object.docid;
97 |
98 | callback(object);
99 | }, 1000)
100 | },
101 |
102 | operate:[
103 | {
104 | text: '确认数据',
105 | style: {
106 | 'marginRight': '30px',
107 | 'marginLeft': '80px'
108 | },
109 | callback: function(item){
110 | console.log(item)
111 | }
112 | }, {
113 | text: '展示数据',
114 | callback: function(item){
115 | console.log(item)
116 | }
117 | }
118 | ],
119 |
120 | UType:[
121 | {
122 | name: 'docid',
123 | label: '唯一标识',
124 | type: 'string',
125 | placeholder: '请输入标示名称'
126 | },{
127 | name: 'title',
128 | label: '标题',
129 | type: 'string',
130 | placeholder: '请输入标示名称'
131 | },{
132 | name: 'link',
133 | label: '链接',
134 | type: 'string'
135 | },{
136 | name: 'date',
137 | label: '日期',
138 | type: 'date'
139 | },{
140 | name: 'img',
141 | label: '图片',
142 | type: 'imageUpload'
143 | }
144 | ]
145 | }
146 |
147 | const Feature1 = FeatureSetConfig(simple_conf);
148 |
149 | export default Feature1;
150 |
--------------------------------------------------------------------------------
/src/components/Header/index.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react'
2 | import { bindActionCreators } from 'redux'
3 | import { connect } from 'react-redux'
4 | import { Row, Col, Icon, Menu, Dropdown } from 'antd'
5 | import styles from './index.less'
6 | // import styles from './index.less';
7 | import { Link } from 'react-router'
8 |
9 | import * as menu from '../../store/modules/menu/menu_action'
10 |
11 | import logo from './logo.png'
12 |
13 | const SubMenu = Menu.SubMenu;
14 | const MenuItemGroup = Menu.ItemGroup;
15 | const DropdownButton = Dropdown.Button;
16 |
17 | const defaultProps = {
18 | topMenu: [],
19 | currentIndex: 0
20 | }
21 |
22 | const propTypes = {
23 | topMenu: PropTypes.array,
24 | currentIndex: PropTypes.number
25 | }
26 |
27 | class Header extends React.Component {
28 | constructor () {
29 | super()
30 | this.onCollapseChange = this.onCollapseChange.bind(this);
31 | this.menuClickHandle = this.menuClickHandle.bind(this);
32 | }
33 |
34 | componentDidMount () {
35 | /**
36 | * 初始化头部菜单,通过服务端获取。
37 | */
38 | this.props.menu.getTopMenu()
39 | }
40 |
41 | menuClickHandle (item) {
42 | /**
43 | * 加入二级导航时,可以通过判断字符串头标记来定位是住导航还是子导航
44 | *
45 | */
46 | // if (item.key.indexOf('sub') != -1) {
47 | // console.log('是主导航')
48 | // } else {
49 | // console.log('是副级导航');
50 | // }
51 |
52 | /**
53 | * 特定功能:返回旧版
54 | *
55 | * 判断 `key = index.html` 则跳转旧版
56 | * 因为在导航前加入了标记,所以这里判断时也需要加入 `sub` 标记
57 | *
58 | */
59 |
60 | /**
61 | * 默认情况更改 `面包屑` 信息
62 | */
63 | // this.props.menu.updateNavPath(item.keyPath, item.key)
64 | }
65 |
66 | onCollapseChange(collapse) {
67 | /**
68 | * 侧栏切换功能
69 | *
70 | * 点击特定按钮更改侧栏状态,实现侧栏切换功能
71 | * 通过判断侧栏状态,显示不同的class
72 | * 该 `class` 在 `View/App` 下: `
`
73 | * 该功能可以放在任意位置,目前放在顶部实现
74 | *
75 | */
76 | // this.props.menu.updateCollapse(this.props.collapse)
77 | }
78 |
79 | render () {
80 | const { topMenu } = this.props;
81 | console.log('topMenu', topMenu);
82 | const menu = topMenu.map((item) => {
83 | /**
84 | * 遍历 `topMenu` 显示顶部信息
85 | *
86 | * `sub` 标记为是主导航
87 | * `key` 用于页面跳转与记录唯一
88 | * `name` 标签显示内容
89 | *
90 | */
91 | return (
92 |
93 |
94 |
95 | {item.name}
96 |
97 |
98 | )
99 | });
100 |
101 | // return (
102 | //
103 | //
104 | //
105 | //
112 | //
113 | //
114 | // )
115 | return (
116 |
117 |
118 |
125 |
126 |
127 | )
128 | }
129 | }
130 |
131 | Header.propTypes = propTypes;
132 | Header.defaultProps = defaultProps;
133 |
134 | const mapStateToProps = (state) => {
135 | console.log('state', state);
136 | return {
137 | topMenu : state.menu.topMenu,
138 | // currentIndex : state.menu.currentIndex,
139 | // collapse : state.menu.collapse,
140 | // selectKey : state.menu.selectKey
141 | };
142 | };
143 |
144 | function mapDispatchToProps(dispatch) {
145 | return {
146 | menu: bindActionCreators(menu, dispatch),
147 | };
148 | }
149 |
150 | export default connect(mapStateToProps, mapDispatchToProps)(Header);
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-redux-antd-ie8
2 |
3 | ## 特性
4 | * [react](https://github.com/facebook/react)
5 | * [redux](https://github.com/rackt/redux)
6 | * [react-router](https://github.com/rackt/react-router)
7 | * [react-router-redux](https://github.com/rackt/react-router-redux)
8 | * [webpack](https://github.com/webpack/webpack)
9 | * [babel](https://github.com/babel/babel)
10 | * [antd](http://ant.design)
11 |
12 | ## Code Style
13 |
14 | https://github.com/airbnb/javascript
15 |
16 | ## `npm` 命令
17 |
18 | |`npm run
71 |
72 | ```
73 | #### Open `package.json`
74 |
75 | ```diff
76 | - "react": "^15.0.2",
77 | - "react-dom": "^15.0.2",
78 | - "react-router": "^2.0.1",
79 | + "react": "0.14.x",
80 | + "react-dom": "0.14.x",
81 | + "react-router": "2.3.x"
82 | ```
83 |
84 | Remove hmr plugin.
85 |
86 | ```diff
87 | - "start": "dora -p 8001 --plugins \"webpack,hmr,proxy,livereload?enableJs=false&injectHost=127.0.0.1,browser-history?index=/src/entries/index.html\"",
88 | + "start": "dora -p 8001 --plugins \"webpack,proxy,livereload?enableJs=false&injectHost=127.0.0.1,browser-history?index=/src/entries/index.html\"",
89 | ```
90 |
91 | #### Open `webpack.config.js`, and enable es3ify-loader
92 |
93 | ```diff
94 | // Enable this if you have to support IE8.
95 | - // webpackConfig.module.loaders.unshift({
96 | - // test: /\.jsx?$/,
97 | - // loader: 'es3ify-loader',
98 | - // });
99 | + webpackConfig.module.loaders.unshift({
100 | + test: /\.jsx?$/,
101 | + loader: 'es3ify-loader',
102 | + });
103 | ```
104 | ## Environment
105 |
106 | ```
107 | node >= 4
108 | ```
109 |
110 | ## Redux
111 |
112 | ```
113 | + "react-redux": "^4.4.0",
114 | + "redux": "^3.3.1",
115 | + "redux-logger": "^2.6.1",
116 | + "redux-thunk": "^2.0.1"
117 | ```
118 |
119 | ## Extension
120 | ```
121 | + "fetch-ie8": "^1.4.0",
122 | + "object-assign": "^4.0.1",
123 | ```
124 |
125 | ## 总结
126 | - 该项目用于测试i8性能,可以当做脚手架使用
127 | - 需要的朋友可以 `star`
128 | - 持续更新
129 |
130 | Thank you for your attention
131 |
--------------------------------------------------------------------------------
/src/components/CreateFormItem.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Form, Select, Input, Button, Icon , DatePicker, TimePicker, Radio, Switch} from 'antd';
3 | import { Upload, Modal, message } from 'antd';
4 |
5 | import BDUploader from './BDUploader';
6 |
7 | const FormItem = Form.Item;
8 | const Option = Select.Option;
9 | const RadioGroup = Radio.Group;
10 |
11 | let CFormItem = React.createClass({
12 | getInitialState: function() {
13 | return {
14 | img_url:''
15 | };
16 | },
17 |
18 | render: function() {
19 | const getFieldProps = this.props.getFieldProps;
20 | const formItemLayout = this.props.formItemLayout || {};
21 | const item = this.props.item || {};
22 | const defaultValue = item.defaultValue || '';
23 | const defaultTimeValue = item.defaultValue || new Date();
24 | const defaultImgValue = this.state.img_url || item.defaultValue || '';
25 |
26 | switch (item.type){
27 | case 'string':
28 | return
32 |
34 |
35 | break;
36 |
37 | case 'date':
38 | return
42 |
43 |
44 | break;
45 |
46 | case 'select':
47 | return
51 |
58 |
59 | break;
60 |
61 | case 'radio':
62 | return
66 |
67 | {
68 | item.options.map(function(item){
69 | return {item.text}
70 | })
71 | }
72 |
73 |
74 | break;
75 |
76 | case 'switch':
77 | return
81 |
82 |
83 | break;
84 |
85 | case 'imageUpload':
86 | return
90 |
92 |
93 |
94 |
95 |
96 | break;
97 |
98 | default:
99 | return '';
100 | break;
101 | }
102 | },
103 | uploadSuccess: function(url){
104 | console.log(url)
105 | this.setState({
106 | img_url: url
107 | })
108 | }
109 | });
110 |
111 | export default CFormItem;
112 |
--------------------------------------------------------------------------------
/src/components/Sidebar/index.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react'
2 | import { bindActionCreators } from 'redux'
3 | import { connect } from 'react-redux'
4 | import { Link } from 'react-router';
5 | import { Menu, Icon, Badge, notification } from 'antd';
6 | import * as MenuAction from '../../store/modules/menu/menu_action';
7 |
8 | import { logout } from '../../store/modules/user/user_action';
9 |
10 | // import * as Util from '../../util';
11 |
12 | import logo from './logo.jpg'
13 | import touxiang from './touxiang.jpg'
14 |
15 | const SubMenu = Menu.SubMenu
16 |
17 | import styles from '../../views/App/index.less'
18 |
19 | const defaultProps = {
20 | leftMenu: [],
21 | currentIndex: 0
22 | }
23 |
24 | const propTypes = {
25 | leftMenu: PropTypes.array,
26 | currentIndex: PropTypes.number
27 | }
28 |
29 | const contextTypes = {
30 | router: PropTypes.object.isRequired,
31 | store: PropTypes.object.isRequired
32 | };
33 |
34 | class Sidebar extends React.Component {
35 | constructor(props) {
36 | super(props)
37 |
38 | this.menuClickHandle = this.menuClickHandle.bind(this);
39 | this.logout = this.logout.bind(this);
40 | }
41 |
42 | componentDidMount() {
43 | this.props.MenuAction.getCaseMenu();
44 | }
45 |
46 | menuClickHandle(item) {
47 | this.props.updateNavPath(item.keyPath, item.key)
48 | console.log('menuClickHandle click ', item);
49 | this.setState({
50 | current: item.key,
51 | });
52 | }
53 | logout() {
54 | this.props.logout();
55 | }
56 | onClick(e) {
57 | }
58 |
59 | render() {
60 | const { leftMenu } = this.props
61 | console.log('this.props', this.props.dispatch);
62 |
63 | let openKey = []
64 | const menu = leftMenu.map((item) => {
65 | openKey.push('sub' + item.key)
66 |
67 | return (
68 |
69 |
70 |
71 |
72 |
73 | {item.name}
74 |
75 | { item.num }
76 |
77 |
78 | )
79 | });
80 | //
编辑显示昵称
81 | // return (
82 | //
93 | // )
94 |
95 | return (
96 |
106 | )
107 | }
108 | }
109 |
110 | Sidebar.propTypes = propTypes;
111 | Sidebar.defaultProps = defaultProps;
112 | Sidebar.contextTypes = contextTypes;
113 | function mapStateToProps(state) {
114 | console.log('state', state);
115 | return {
116 | leftMenuType: state.menu.leftMenuType,
117 | leftMenu: state.menu.leftMenu,
118 | currentIndex: state.menu.currentIndex,
119 | }
120 | }
121 |
122 | function mapDispatchToProps(dispatch) {
123 | return {
124 | logout: bindActionCreators(logout, dispatch),
125 | MenuAction: bindActionCreators(MenuAction, dispatch)
126 | }
127 | }
128 |
129 | export default connect(mapStateToProps, mapDispatchToProps)(Sidebar)
130 |
--------------------------------------------------------------------------------
/src/views/Test/index.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react'
2 | import { bindActionCreators } from 'redux'
3 | import { connect } from 'react-redux'
4 | import { Link } from 'react-router'
5 | import { Tree, TreeSelect } from 'antd';
6 |
7 | import './index.less'
8 |
9 | const TreeNode = TreeSelect.TreeNode;
10 |
11 | function generateTreeNodes(treeNode) {
12 | console.log('treeNode', treeNode);
13 | /**
14 | * 生成🌲树节点
15 | *
16 | * 参数: `🌲树控件`
17 | * 初始化 `arr`
18 | * 缓存 `key` -> eventKey
19 | *
20 | * 构建 `🌲树节点` 后返回
21 | *
22 | */
23 | const arr = [];
24 | const key = treeNode.props.eventKey;
25 | for (let i = 0; i < 3; i++) {
26 | arr.push({ name: `leaf ${key}-${i}`, key: `${key}-${i}` });
27 | }
28 | return arr;
29 | }
30 |
31 | function setLeaf(treeData, curKey, level) {
32 | /**
33 | *
34 | * setLeaf(treeData, curKey, level)
35 | *
36 | * 参数:
37 | * 1、 `data` 🌲树控件集合
38 | * 2、 `curKey` 选中的 `key`
39 | * 3、 `level` 🌲树控件数据的层级
40 | *
41 | * desc:
42 | * 设置🍃叶子节点是否可以展开
43 | *
44 | * * * * * * * * * * * * * * * * * * * * * * * *
45 | *
46 | * loopLeaf(data, lev)
47 | *
48 | * 参数:
49 | * 1、 `data` 🌲树控件集合
50 | * 2、 `lev` 🌲树控件数据的层级
51 | *
52 | * desc:
53 | * 循环🍃叶子节点
54 | *
55 | * if (item.key.length > curKey.length) ? item.key.indexOf(curKey) !== 0 : curKey.indexOf(item.key) !== 0)
56 | * 遍历数控件集合,如果当前 `key` 的长度 `大于` 传入的 `key`,在判断当前 `key` 名子中包含该传入的 `key` 则返回true,否则返回false
57 | * 遍历数控件集合,如果当前 `key` 的长度 `小于` 传入的 `key`,在判断传入的 `key`名子中包含该当前 `key` 则返回true,否则返回false
58 | *
59 | * if (item.children)
60 | * 如果该叶子,有子节点,递归判断
61 | *
62 | * else if (l < 1)
63 | * 如果该叶子没有子节点,且层级等于1,则设置不能展开
64 | *
65 | */
66 | const loopLeaf = (data, lev) => {
67 | const l = lev - 1;
68 | data.forEach((item) => {
69 | if ((item.key.length > curKey.length) ? item.key.indexOf(curKey) !== 0 :
70 | curKey.indexOf(item.key) !== 0) {
71 | return;
72 | }
73 | if (item.children) {
74 | loopLeaf(item.children, l);
75 | } else if (l < 1) {
76 | item.isLeaf = true;
77 | }
78 | });
79 | };
80 | loopLeaf(treeData, level + 1);
81 | }
82 |
83 | function getNewTreeData(treeData, curKey, child, level) {
84 | /**
85 | * getNewTreeData(treeData, curKey, child, level)
86 | *
87 | * 参数:
88 | * 1、 `treeData` 🌲树控件数据
89 | * 2、 `curKey` 选中的 `key`
90 | * 3、 `child` 子节点
91 | * 4、 `level` 层级
92 | *
93 | * desc:
94 | * 将子节点加入对应的节点中
95 | *
96 | * 判断🌲树控件层级不符合标准则退出
97 | *
98 | * 遍历节点,如果有子节点,则递归判断子节点
99 | * 没有则将节点加入子节点中
100 | *
101 | */
102 | const loop = (data) => {
103 | if (level < 1 || curKey.length - 3 > level * 2) return;
104 | data.forEach((item) => {
105 | if (curKey.indexOf(item.key) === 0) {
106 | if (item.children) {
107 | loop(item.children);
108 | } else {
109 | item.children = child;
110 | }
111 | }
112 | });
113 | };
114 | loop(treeData);
115 | setLeaf(treeData, curKey, level);
116 | }
117 |
118 | const Demo = React.createClass({
119 | getInitialState() {
120 | return {
121 | treeData: [],
122 | };
123 | },
124 | componentDidMount() {
125 | setTimeout(() => {
126 | this.setState({
127 | treeData: [
128 | { name: 'pNode 01', key: '0-0' },
129 | { name: 'pNode 02', key: '0-1' },
130 | { name: 'pNode 03', key: '0-2', isLeaf: true },
131 | ],
132 | });
133 | }, 100);
134 | },
135 | onSelect(info) {
136 | console.log('selected', info);
137 | },
138 | onLoadData(treeNode) {
139 | console.log('treeNode', treeNode);
140 | return new Promise((resolve) => {
141 | setTimeout(() => {
142 | const treeData = [...this.state.treeData];
143 | getNewTreeData(treeData, treeNode.props.eventKey, generateTreeNodes(treeNode), 10);
144 | this.setState({ treeData });
145 | resolve();
146 | }, 500);
147 | });
148 | },
149 | onChange(value) {
150 | console.log(arguments);
151 | this.setState({ value });
152 | },
153 | render() {
154 | const loop = data => data.map((item) => {
155 | if (item.children) {
156 | return
{loop(item.children)};
157 | }
158 | return
;
159 | });
160 | const treeNodes = loop(this.state.treeData);
161 | return (
162 |
163 |
164 |
165 |
173 |
174 | {treeNodes}
175 |
176 |
177 | );
178 | },
179 | });
180 |
181 | export default Demo;
--------------------------------------------------------------------------------
/src/components/Loding/index.js:
--------------------------------------------------------------------------------
1 | import React, {PropTypes} from 'react'
2 | import { bindActionCreators } from 'redux'
3 | import { Spin, Alert } from 'antd'
4 | import { connect } from 'react-redux'
5 |
6 | import styles from './index.less'
7 |
8 | const defaultProps = {}
9 |
10 | const propTypes = {}
11 |
12 | class Loding extends React.Component {
13 | constructor(props) {
14 | super(props)
15 | }
16 |
17 | render() {
18 | const boxflex = styles["boxflex"];
19 | const box_center = styles["box"] + '' + styles['center'];
20 | const line = styles["line"];
21 | const load_load1_move = styles["load"] + ' ' + styles['load1'] + ' ' + styles['move'];
22 | const sc = styles["sc"];
23 | const scale = styles["scale"];
24 | const scale_delay1 = styles["scale"] + ' ' + styles['delay1'];
25 | const scale_delay2 = styles["scale"] + ' ' + styles['delay2'];
26 | const li = styles["li"];
27 | const fz = styles["fz"];
28 |
29 | const loaing_1_style = {
30 | display: 'inline-block',
31 | width: '30px',
32 | height: '30px',
33 | }
34 | const loaing_1 = (
35 |
36 |
37 |
38 | )
39 | const loaing_2 = (
40 |
41 |
42 |
43 | )
44 | const loaing_3 = (
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | )
53 | const loaing_4 = (
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | )
65 |
66 | const loaing_5_style = {
67 | display: 'inline-block',
68 | width: '30px',
69 | height: '30px',
70 | border: '6px solid #64efb9'
71 | }
72 | const loaing_5 = (
73 |
74 |
75 |
76 |
77 |
78 | )
79 | return (
80 |
81 |
82 |
86 |
87 |
88 |
92 |
93 |
94 |
95 |
99 |
100 |
101 |
102 |
106 |
107 |
108 |
109 |
113 |
114 |
115 |
116 |
120 |
121 |
122 | )
123 | }
124 | }
125 |
126 | Loding.propTypes = propTypes;
127 | Loding.defaultProps = defaultProps;
128 |
129 | function mapStateToProps(state) {
130 | return {
131 | // navpath: state.menu.navpath
132 | }
133 | }
134 |
135 | export default connect(mapStateToProps)(Loding)
136 |
--------------------------------------------------------------------------------
/src/feature/Feature5.jsx:
--------------------------------------------------------------------------------
1 | // 含有可操作 table 栏的数据展示
2 | import React from 'react';
3 |
4 | import FeatureSetConfig from '../components/FeatureSetConfig';
5 |
6 | import Immutable from 'immutable';
7 | //https://github.com/ded/reqwest
8 | import Reqwest from 'reqwest';
9 |
10 |
11 | const conf = {
12 |
13 | // 初始化页面的数据 回调函数传入 items 列表
14 | initData: function(callback){
15 |
16 | let data = {
17 | type: 'entry_list',
18 | num: 20,
19 | ua: 'bd_1_1_1_5-5-0-0_1',
20 | cuid: '00000000000000000000000000000000%7C0000000000000000',
21 | channel: 'AA_0',
22 | dir: 'up'
23 | }
24 |
25 | Reqwest({
26 | url: 'http://uil.cbs.baidu.com/rssfeed/fetch?fn=?',
27 | data: data,
28 | type: 'jsonp',
29 | jsonpCallback: 'fn',
30 | success: function (data) {
31 | let lists = data.data.stream_data;
32 |
33 | // 必须要向数据中 添加唯一的 key
34 | lists.forEach(function(ele) {
35 | ele.key = ele.docid;
36 | });
37 |
38 | callback(lists);
39 | }
40 | });
41 |
42 | },
43 |
44 | // 功能模块需要时 添加 CRUD 4方法
45 | Create: function(data, callback){
46 | let dataI = Immutable.fromJS({
47 | type: 'entry_list'
48 | }).merge({id: data.key});
49 |
50 | // ... 操作删除请求
51 | console.log(dataI.toJS());
52 |
53 | // 模拟请求删除成功的回调
54 | setTimeout(function(){
55 | callback();
56 | }, 1000)
57 | },
58 | Delete: function(data, callback){
59 |
60 | let dataI = Immutable.fromJS({
61 | type: 'entry_list'
62 | }).merge({id: data.key});
63 |
64 | // ... 操作删除请求
65 | console.log(dataI.toJS());
66 |
67 | // 模拟请求删除成功的回调
68 | setTimeout(function(){
69 | callback();
70 | }, 1000)
71 |
72 | },
73 | Update:function(data, callback){
74 | console.log(data);
75 | data.key = data.docid;
76 | callback(data);
77 | },
78 | Retrieve: function(data, callback){
79 | let dataI = Immutable.fromJS({
80 | type: 'entry_list',
81 | num: 20,
82 | ua: 'bd_1_1_1_5-5-0-0_1',
83 | cuid: '00000000000000000000000000000000%7C0000000000000000',
84 | channel: 'AA_0',
85 | dir: 'up'
86 | }).merge(data);
87 |
88 | Reqwest({
89 | url: 'http://uil.cbs.baidu.com/rssfeed/fetch?fn=?',
90 | data: dataI.toJS(),
91 | type: 'jsonp',
92 | jsonpCallback: 'fn',
93 | success: function (data) {
94 | let lists = data.data.stream_data;
95 | // 必须要向数据中 添加唯一的 key
96 | lists.forEach(function(ele) {
97 | ele.key = ele.docid;
98 | });
99 |
100 | callback(lists);
101 | }
102 | });
103 | },
104 |
105 | // 更新项目所需的字段
106 | UType:[
107 | {
108 | name: 'docid',
109 | label: '唯一标识',
110 | type: 'string',
111 | placeholder: '请输入标示名称'
112 | },{
113 | name: 'title',
114 | label: '标题',
115 | type: 'string',
116 | placeholder: '请输入标示名称'
117 | },{
118 | name: 'link',
119 | label: '链接',
120 | type: 'string'
121 | },{
122 | name: 'date',
123 | label: '日期',
124 | type: 'date'
125 | },{
126 | name: 'img',
127 | label: '图片',
128 | type: 'imageUpload'
129 | }
130 |
131 | ],
132 |
133 |
134 | // table 列表头标题
135 | columns: [
136 | {
137 | title: 'DOCID', // table header 文案
138 | dataIndex: 'docid', // 数据对象内的属性,也做react vdom 的key
139 | type: 'string', // table 内显示的类型
140 | sort: true, // 是否需要排序
141 | width:200
142 | }, {
143 | title: '标题',
144 | dataIndex: 'title',
145 | type: 'string'
146 | }, {
147 | title: '链接',
148 | dataIndex: 'link',
149 | type: 'link',
150 | render: (text) => (
151 | 链接
152 | ),
153 | width: 50
154 | },{
155 | title: '日期',
156 | dataIndex: 'date',
157 | type: 'string',
158 | width: 150
159 | },{
160 | title: '图片',
161 | dataIndex: 'img',
162 | type: 'image'
163 | },{
164 | title: '操作',
165 | type: 'operate', // 操作的类型必须为 operate
166 | width: 120,
167 | btns: [{
168 | text: '更新',
169 | type: 'update'
170 | },{
171 | text: '删除',
172 | type: 'delete'
173 | }, {
174 | text: '展示',
175 | callback: function(item){
176 | console.log(item)
177 | }
178 | }] // 可选
179 | }
180 | ],
181 |
182 | uploadfile: '/umis/pushc/uploadfile'
183 |
184 | };
185 |
186 | const Feature2 = FeatureSetConfig(conf);
187 |
188 | export default Feature2;
189 |
--------------------------------------------------------------------------------
/src/feature/Feature3.jsx:
--------------------------------------------------------------------------------
1 | // 含有可操作 table 栏的数据展示
2 | import React from 'react';
3 |
4 | import FeatureSetConfig from '../components/FeatureSetConfig';
5 |
6 | import Immutable from 'immutable';
7 | //https://github.com/ded/reqwest
8 | import Reqwest from 'reqwest';
9 |
10 |
11 | const conf = {
12 |
13 | // 初始化页面的数据 回调函数传入 items 列表
14 | initData: function(callback){
15 |
16 | let data = {
17 | type: 'entry_list',
18 | num: 20,
19 | ua: 'bd_1_1_1_5-5-0-0_1',
20 | cuid: '00000000000000000000000000000000%7C0000000000000000',
21 | channel: 'AA_0',
22 | dir: 'up'
23 | }
24 |
25 | Reqwest({
26 | url: 'http://uil.cbs.baidu.com/rssfeed/fetch?fn=?',
27 | data: data,
28 | type: 'jsonp',
29 | jsonpCallback: 'fn',
30 | success: function (data) {
31 | let lists = data.data.stream_data;
32 |
33 | // 必须要向数据中 添加唯一的 key
34 | lists.forEach(function(ele) {
35 | ele.key = ele.docid;
36 | });
37 |
38 | callback(lists);
39 | }
40 | });
41 |
42 | },
43 |
44 | // 功能模块需要时 添加 CRUD 4方法
45 | Create: function(){},
46 | Delete: function(data, callback){
47 |
48 | let dataI = Immutable.fromJS({
49 | type: 'entry_list'
50 | }).merge({id: data.key});
51 |
52 | // ... 操作删除请求
53 | console.log(dataI.toJS());
54 |
55 | // 模拟请求删除成功的回调
56 | setTimeout(function(){
57 | callback();
58 | }, 1000)
59 |
60 | },
61 | Update:function(){},
62 |
63 |
64 | Retrieve: function(data, callback){
65 |
66 | console.log(data);
67 | let dataI = Immutable.fromJS({
68 | type: 'entry_list',
69 | num: 20,
70 | ua: 'bd_1_1_1_5-5-0-0_1',
71 | cuid: '00000000000000000000000000000000%7C0000000000000000',
72 | channel: 'AA_0',
73 | dir: 'up'
74 | }).merge(data);
75 |
76 | Reqwest({
77 | url: 'http://uil.cbs.baidu.com/rssfeed/fetch?fn=?',
78 | data: dataI.toJS(),
79 | type: 'jsonp',
80 | jsonpCallback: 'fn',
81 | success: function (data) {
82 | let lists = data.data.stream_data;
83 | // 必须要向数据中 添加唯一的 key
84 | lists.forEach(function(ele) {
85 | ele.key = ele.docid;
86 | });
87 |
88 | callback(lists);
89 | }
90 | });
91 | },
92 |
93 | // 可设置的查询字段
94 | RType:[
95 | {
96 | name: 'id',
97 | label: '唯一标识',
98 | type: 'string',
99 | placeholder: '请输入标示名称'
100 | },{
101 | name: 'date',
102 | label: '项目开始时间',
103 | type: 'date'
104 | },{
105 | name: 'stype',
106 | label: '项目类型Select',
107 | type: 'select',
108 | defaultValue: 'one',
109 | options:[{
110 | text: '选项一',
111 | value: 'one'
112 | },{
113 | text: '选项二',
114 | value: 'two'
115 | },{
116 | text: '选项三',
117 | value: 'three'
118 | }]
119 | },{
120 | name: 'rtype',
121 | label: '项目类型Radio',
122 | type: 'radio',
123 | defaultValue: 'one',
124 | options:[{
125 | text: '选项一',
126 | value: 'one'
127 | },{
128 | text: '选项二',
129 | value: 'two'
130 | },{
131 | text: '选项三',
132 | value: 'three'
133 | }]
134 | },{
135 | name: 'ischange',
136 | label: '是否过滤',
137 | type: 'switch',
138 | defaultValue: false
139 | }
140 |
141 | ],
142 |
143 | columns: [
144 | {
145 | title: 'DOCID', // table header 文案
146 | dataIndex: 'docid', // 数据对象内的属性,也做react vdom 的key
147 | type: 'string', // table 内显示的类型
148 | sort: true, // 是否需要排序
149 | width:200
150 | }, {
151 | title: '标题',
152 | dataIndex: 'title',
153 | type: 'string'
154 | }, {
155 | title: '链接',
156 | dataIndex: 'link',
157 | type: 'link'
158 | }, {
159 | title: '操作',
160 | type: 'operate', // 操作的类型必须为 operate
161 | width: 80,
162 | btns: [{
163 | text: '删除',
164 | type: 'delete'
165 | }, {
166 | text: '展示',
167 | callback: function(item){
168 | console.log(item)
169 | }
170 | }], // 可选
171 |
172 | // 对应btns 的回调函数
173 | // item为操作的单一数据对象
174 | // callback 为组件的回调函数,将处理之后的数据回传 删除则传undefined
175 | // callbacks: [function(item, callback){
176 | // item.docid = 0;
177 | // callback(item, 'update');
178 | // },function(item, callback){
179 | // callback(item, 'delete');
180 | // }]
181 | }
182 | ],
183 |
184 |
185 |
186 | };
187 |
188 | const Feature2 = FeatureSetConfig(conf);
189 |
190 | export default Feature2;
191 |
--------------------------------------------------------------------------------
/src/feature/Feature2-1.jsx:
--------------------------------------------------------------------------------
1 | // 含有可操作 table 栏的数据展示
2 | import React from 'react';
3 |
4 | import FeatureSetConfig from '../components/FeatureSetConfig';
5 |
6 | import Immutable from 'immutable';
7 | //https://github.com/ded/reqwest
8 | import Reqwest from 'reqwest';
9 |
10 |
11 | const conf = {
12 |
13 | // 初始化页面的数据 回调函数传入 items 列表
14 | initData: function(callback){
15 |
16 | let data = {
17 | type: 'entry_list',
18 | num: 20,
19 | ua: 'bd_1_1_1_5-5-0-0_1',
20 | cuid: '00000000000000000000000000000000%7C0000000000000000',
21 | channel: 'AA_0',
22 | dir: 'up'
23 | }
24 |
25 | Reqwest({
26 | url: 'http://uil.cbs.baidu.com/rssfeed/fetch?fn=?',
27 | data: data,
28 | type: 'jsonp',
29 | jsonpCallback: 'fn',
30 | success: function (data) {
31 | let lists = data.data.stream_data;
32 |
33 | // 必须要向数据中 添加唯一的 key
34 | lists.forEach(function(ele) {
35 | ele.key = ele.docid;
36 | });
37 |
38 | callback(lists);
39 | }
40 | });
41 |
42 | },
43 |
44 | // 功能模块需要时 添加 CRUD 4方法
45 | Create: function(){},
46 | Delete: function(data, callback){
47 |
48 | let dataI = Immutable.fromJS({
49 | type: 'entry_list'
50 | }).merge({id: data.key});
51 |
52 | // ... 操作删除请求
53 | console.log(dataI.toJS());
54 |
55 | // 模拟请求删除成功的回调
56 | setTimeout(function(){
57 | callback();
58 | }, 1000)
59 |
60 | },
61 | Update:function(){},
62 |
63 |
64 | Retrieve: function(data, callback){
65 |
66 | console.log(data);
67 | let dataI = Immutable.fromJS({
68 | type: 'entry_list',
69 | num: 20,
70 | ua: 'bd_1_1_1_5-5-0-0_1',
71 | cuid: '00000000000000000000000000000000%7C0000000000000000',
72 | channel: 'AA_0',
73 | dir: 'up'
74 | }).merge(data);
75 |
76 | Reqwest({
77 | url: 'http://uil.cbs.baidu.com/rssfeed/fetch?fn=?',
78 | data: dataI.toJS(),
79 | type: 'jsonp',
80 | jsonpCallback: 'fn',
81 | success: function (data) {
82 | let lists = data.data.stream_data;
83 | // 必须要向数据中 添加唯一的 key
84 | lists.forEach(function(ele) {
85 | ele.key = ele.docid;
86 | });
87 |
88 | callback(lists);
89 | }
90 | });
91 | },
92 |
93 | // 可设置的查询字段
94 | // RType 查询字段
95 | // CType 创建字段
96 | // UType 更新字段
97 | RType:[
98 | {
99 | name: 'id',
100 | label: '唯一标识',
101 | type: 'string',
102 | placeholder: '请输入标示名称'
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 | defaultValue: false
142 | }
143 |
144 | ],
145 |
146 |
147 | columns: [
148 | {
149 | title: 'DOCID', // table header 文案
150 | dataIndex: 'docid', // 数据对象内的属性,也做react vdom 的key
151 | type: 'string', // table 内显示的类型
152 | sort: true, // 是否需要排序
153 | width:200
154 | }, {
155 | title: '标题',
156 | dataIndex: 'title',
157 | type: 'string'
158 | }, {
159 | title: '链接',
160 | dataIndex: 'link',
161 | type: 'link'
162 | }, {
163 | title: '操作',
164 | type: 'operate', // 操作的类型必须为 operate
165 | width: 80,
166 | btns: [{
167 | text: '删除',
168 | type: 'delete'
169 | }, {
170 | text: '展示',
171 | callback: function(item){
172 | console.log(item)
173 | }
174 | }], // 可选
175 |
176 | // 对应btns 的回调函数
177 | // item为操作的单一数据对象
178 | // callback 为组件的回调函数,将处理之后的数据回传 删除则传undefined
179 | // callbacks: [function(item, callback){
180 | // item.docid = 0;
181 | // callback(item, 'update');
182 | // },function(item, callback){
183 | // callback(item, 'delete');
184 | // }]
185 | }
186 | ],
187 |
188 |
189 |
190 | };
191 |
192 | const Feature2 = FeatureSetConfig(conf);
193 |
194 | export default Feature2;
195 |
--------------------------------------------------------------------------------
/src/feature/Feature2-2.jsx:
--------------------------------------------------------------------------------
1 | // 含有可操作 table 栏的数据展示
2 | import React from 'react';
3 |
4 | import FeatureSetConfig from '../components/FeatureSetConfig';
5 |
6 | import Immutable from 'immutable';
7 | //https://github.com/ded/reqwest
8 | import Reqwest from 'reqwest';
9 |
10 | let CUTpye = [
11 | {
12 | name: 'id',
13 | label: '唯一标识',
14 | type: 'string',
15 | placeholder: '请输入标示名称',
16 | rules: [{ required: true, min: 5, message: '用户名至少为 5 个字符' }]
17 | },{
18 | name: 'id2',
19 | label: '唯一标识',
20 | type: 'string',
21 | placeholder: '请输入标示名称',
22 | rules: [{ required: true, type: 'email', message: '请输入正确的邮箱地址' }]
23 | },{
24 | name: 'date',
25 | label: '项目开始时间',
26 | type: 'date',
27 | },{
28 | name: 'stype',
29 | label: '项目类型Select',
30 | type: 'select',
31 | defaultValue: 'one',
32 | options:[{
33 | text: '选项一',
34 | value: 'one'
35 | },{
36 | text: '选项二',
37 | value: 'two'
38 | },{
39 | text: '选项三',
40 | value: 'three'
41 | }]
42 | },{
43 | name: 'rtype',
44 | label: '项目类型Radio',
45 | type: 'radio',
46 | defaultValue: 'one',
47 | options:[{
48 | text: '选项一',
49 | value: 'one'
50 | },{
51 | text: '选项二',
52 | value: 'two'
53 | },{
54 | text: '选项三',
55 | value: 'three'
56 | }]
57 | },{
58 | name: 'ischange',
59 | label: '是否过滤',
60 | type: 'switch'
61 | },{
62 | name: 'image',
63 | label: '背景图片',
64 | type: 'imageUpload'
65 | }
66 | ];
67 |
68 | const conf = {
69 |
70 | // 初始化页面的数据 回调函数传入 items 列表
71 | initData: function(callback){
72 |
73 | let data = {
74 | type: 'entry_list',
75 | num: 20,
76 | ua: 'bd_1_1_1_5-5-0-0_1',
77 | cuid: '00000000000000000000000000000000%7C0000000000000000',
78 | channel: 'AA_0',
79 | dir: 'up'
80 | }
81 |
82 | Reqwest({
83 | url: 'http://uil.cbs.baidu.com/rssfeed/fetch?fn=?',
84 | data: data,
85 | type: 'jsonp',
86 | jsonpCallback: 'fn',
87 | success: function (data) {
88 | let lists = data.data.stream_data;
89 |
90 | // 必须要向数据中 添加唯一的 key
91 | lists.forEach(function(ele) {
92 | ele.key = ele.docid;
93 | });
94 |
95 | callback(lists);
96 | }
97 | });
98 |
99 | },
100 |
101 | // 功能模块需要时 添加 CRUD 4方法
102 | Create: function(data, callback){
103 | let dataI = Immutable.fromJS({
104 | type: 'entry_list'
105 | }).merge({id: data.key});
106 |
107 | // ... 操作添加数据的请求
108 | console.log(dataI.toJS());
109 |
110 | let item = {
111 | docid: (Math.random()*10000000000)|0,
112 | title: '院依法对原省安监局局长陈炎生决定逮捕',
113 | link: 'sdfghjcvbnmertfheiuwfhsdh'
114 | }
115 |
116 | // 需要设置key
117 | item.key = item.docid;
118 |
119 | // 模拟请求创建成功的回调
120 | setTimeout(function(){
121 | callback(item);
122 | }, 1000);
123 | },
124 | Delete: function(data, callback){
125 |
126 | let dataI = Immutable.fromJS({
127 | type: 'entry_list'
128 | }).merge({id: data.key});
129 |
130 | // ... 操作删除请求
131 | console.log(dataI.toJS());
132 |
133 | // 模拟请求删除成功的回调
134 | setTimeout(function(){
135 | callback();
136 | }, 1000)
137 | },
138 | Update:function(data, callback){
139 | console.log(data);
140 | },
141 |
142 |
143 | // 创建项目所需的字段 与 更新项目所需的字段
144 | // rules 规范可见 https://github.com/yiminghe/async-validator
145 | CType: Immutable.fromJS(CUTpye).toJS(),
146 | UType: Immutable.fromJS(CUTpye).toJS(),
147 |
148 | columns: [
149 | {
150 | title: 'DOCID', // table header 文案
151 | dataIndex: 'docid', // 数据对象内的属性,也做react vdom 的key
152 | type: 'string', // table 内显示的类型
153 | sort: true, // 是否需要排序
154 | width:200
155 | }, {
156 | title: '标题',
157 | dataIndex: 'title',
158 | type: 'string'
159 | }, {
160 | title: '链接',
161 | dataIndex: 'link',
162 | type: 'link'
163 | }, {
164 | title: '操作',
165 | type: 'operate', // 操作的类型必须为 operate
166 | width: 120,
167 | btns: [{
168 | text: '更新',
169 | type: 'update'
170 | },{
171 | text: '删除',
172 | type: 'delete'
173 | },{
174 | text: '展示',
175 | callback: function(item){
176 | console.log(item)
177 | }
178 | }], // 可选
179 |
180 | // 对应btns 的回调函数
181 | // item为操作的单一数据对象
182 | // callback 为组件的回调函数,将处理之后的数据回传 删除则传undefined
183 | // callbacks: [function(item, callback){
184 | // item.docid = 0;
185 | // callback(item, 'update');
186 | // },function(item, callback){
187 | // callback(item, 'delete');
188 | // }]
189 | }
190 | ],
191 |
192 | uploadfile: function(data){
193 |
194 | }
195 |
196 | };
197 |
198 | const Feature2 = FeatureSetConfig(conf);
199 |
200 | export default Feature2;
201 |
--------------------------------------------------------------------------------
/src/feature/Feature1-4.jsx:
--------------------------------------------------------------------------------
1 | // 纯数据展现情况列表
2 | import React from 'react';
3 |
4 | import FeatureSetConfig from '../components/FeatureSetConfig';
5 |
6 | import Immutable from 'immutable';
7 | import Reqwest from 'reqwest';
8 |
9 | import testData from '../common/test-data';
10 |
11 | const graph_conf = {
12 |
13 | type: 'graphList', // tableList graphList simpleObject complexObject
14 | EchartStyle: {
15 | width: '100%',
16 | height: '450px'
17 | },
18 |
19 | // 初始化展现的数据,使用callback 回传列表数据
20 | // 需要手动添加唯一id key
21 | // callback 组件数据的回调函数(接受列表数据参数)
22 | initData: function(callback){
23 |
24 | // 模拟数据
25 | setTimeout(function(){
26 | let series = testData.graphList;
27 | series.forEach(function(item) {
28 | item.type = 'line';
29 | item.stack = '总量'
30 | });
31 |
32 | callback(series);
33 | }, 1000)
34 | },
35 |
36 | // 参考echarts 参数
37 | option : {
38 | title: {
39 | text: '堆叠区域图'
40 | },
41 | tooltip : {
42 | trigger: 'axis'
43 | },
44 | legend: {
45 | data:['邮件营销','联盟广告','视频广告']
46 | },
47 | toolbox: {
48 | feature: {
49 | saveAsImage: {}
50 | }
51 | },
52 | grid: {
53 | left: '3%',
54 | right: '4%',
55 | bottom: '3%',
56 | containLabel: true
57 | },
58 | xAxis : [
59 | {
60 | type : 'category',
61 | boundaryGap : false,
62 | data : ['周一','周二','周三','周四','周五','周六','周日']
63 | }
64 | ],
65 | yAxis : [
66 | {
67 | type : 'value'
68 | }
69 | ]
70 | }
71 |
72 | };
73 |
74 | const graph_conf2 = {
75 |
76 | type: 'graphList', // tableList graphList simpleObject complexObject
77 | EchartStyle: {
78 | width: '100%',
79 | height: '450px'
80 | },
81 |
82 | // 初始化展现的数据,使用callback 回传列表数据
83 | // 需要手动添加唯一id key
84 | // callback 组件数据的回调函数(接受列表数据参数)
85 | initData: function(callback){
86 |
87 | // 模拟数据
88 | setTimeout(function(){
89 | let series = [
90 | {
91 | name: '访问来源',
92 | type: 'pie',
93 | radius : '55%',
94 | center: ['50%', '60%'],
95 | data:[
96 | {value:335, name:'直接访问'},
97 | {value:310, name:'邮件营销'},
98 | {value:234, name:'联盟广告'},
99 | {value:135, name:'视频广告'},
100 | {value:1548, name:'搜索引擎'}
101 | ],
102 | itemStyle: {
103 | emphasis: {
104 | shadowBlur: 10,
105 | shadowOffsetX: 0,
106 | shadowColor: 'rgba(0, 0, 0, 0.5)'
107 | }
108 | }
109 | }
110 | ]
111 |
112 | callback(series);
113 | }, 1000)
114 | },
115 |
116 | // 参考echarts 参数
117 | option : {
118 | title : {
119 | text: '某站点用户访问来源',
120 | subtext: '纯属虚构',
121 | x:'center'
122 | },
123 | tooltip : {
124 | trigger: 'item',
125 | formatter: "{a}
{b} : {c} ({d}%)"
126 | },
127 | legend: {
128 | orient: 'vertical',
129 | left: 'left',
130 | data: ['直接访问','邮件营销','联盟广告','视频广告','搜索引擎']
131 | }
132 | }
133 |
134 | };
135 |
136 | const table_conf = {
137 |
138 | type: 'tableList', // tableList graphList simpleObject complexObject
139 |
140 | // 初始化展现的数据,使用callback 回传列表数据
141 | // 需要手动添加唯一id key
142 | // callback 组件数据的回调函数(接受列表数据参数)
143 | initData: function(callback){
144 |
145 | // 模拟数据
146 | setTimeout(function(){
147 | let list = testData.tableList;
148 | list.forEach(function(ele) {
149 | ele.key = ele.docid;
150 | });
151 | callback(list);
152 | }, 1000)
153 | },
154 |
155 | columns: [
156 | {
157 | title: 'DOCID', // table header 文案
158 | dataIndex: 'docid', // 数据对象内的属性,也做react vdom 的key
159 | type: 'string', // table 内显示的类型
160 | sort: true, // 是否需要排序
161 | width:200
162 | }, {
163 | title: '标题',
164 | dataIndex: 'title',
165 | type: 'string'
166 | }, {
167 | title: '链接',
168 | dataIndex: 'link',
169 | type: 'link',
170 | render: (text) => (
171 | 链接
172 | ),
173 | width: 50
174 | },{
175 | title: '日期',
176 | dataIndex: 'date',
177 | type: 'string',
178 | width: 150
179 | },{
180 | title: '图片',
181 | dataIndex: 'img',
182 | type: 'image'
183 | }
184 | ]
185 |
186 | };
187 |
188 | const Feature1 = FeatureSetConfig(graph_conf2);
189 | const Feature2 = FeatureSetConfig(graph_conf);
190 | const Feature3 = FeatureSetConfig(table_conf);
191 |
192 | const Feature = React.createClass({
193 |
194 | render: function() {
195 | return
196 |
197 |
198 |
199 |
200 | }
201 | });
202 |
203 | export default Feature;
204 |
--------------------------------------------------------------------------------
/src/common/config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * [Config description]
3 | * @type {Object}
4 | *
5 | * header 管理后台头部配置
6 | * title String 标题
7 | * icon String 标题图标
8 | * style Object 自定义样式
9 | *
10 | * sider 管理后台侧栏配置
11 | * menu Array sider列表
12 | * openKeys Array 默认展开的sider区
13 | * selectedKey String 默认打开的功能区
14 | * style Object 自定义样式
15 | *
16 | * main 功能区域配置
17 | * components Object 配置sider对应功能区域组件
18 | * Feature1 Object 对应sider menu 中的功能key对 应功能组件
19 | * style Object 配置样式
20 | */
21 |
22 | const Config = {
23 | header: {
24 | title: "测试配置管理后台",
25 | icon: "appstore",
26 | style: {
27 | padding: "15px 15px 15px 25px",
28 | borderBottom: "1px solid #E9E9E9",
29 | backgroundColor: "#F5F5F5"
30 | }
31 | },
32 |
33 | sider: {
34 | menu: [
35 | {
36 | title: "数据展示项",
37 | key: "dataShow",
38 | icon: "bars",
39 | items: [
40 | {title: "table数据展示项", key: "Feature1-1"},
41 | {title: "simple对象数据展示项", key: "Feature1-2"},
42 | {title: "数据可视化展示项", key: "Feature1-3"},
43 | {title: "综合数据展示", key: "Feature1-4"}
44 | ]
45 | },
46 | {
47 | title: "数据操作项目",
48 | key: "dataOperate",
49 | icon: "bars",
50 | items: [
51 | {title: "table数据搜索操作", key: "Feature2-1"},
52 | {title: "table数据增删改操作", key: "Feature2-2"},
53 | {title: "simple对象数据修改操作", key: "Feature2-3"}
54 | ]
55 | },
56 | {
57 | title: "自定义操作项目",
58 | key: "customOperate",
59 | icon: "bars",
60 | items: [
61 | {title: "富文本编辑功能", key: "Feature3-1"}
62 | ]
63 | },
64 | {
65 | title: "导航1",
66 | key: "subTitle1",
67 | icon: "setting",
68 | items: [
69 | {title: "选项1", key: "Feature1"},
70 | {title: "选项2", key: "Feature2"},
71 | {title: "选项3", key: "Feature3"},
72 | {
73 | title: "导航3",
74 | key: "subTitle3",
75 | icon: "",
76 | items: [
77 | {title: "选项6", key: "Feature6"},
78 | {title: "选项7", key: "Feature7"},
79 | {title: "选项8", key: "Feature8"}
80 | ]
81 | }
82 | ]
83 | },{
84 | title: "导航2",
85 | key: "subTitle2",
86 | icon: "delete",
87 | items: [
88 | {title: "选项4", key: "Feature4"}
89 | ]
90 | },{
91 | title: "选项5",
92 | key: "Feature5"
93 | }
94 | ],
95 | openKeys:['dataShow','dataOperate'],
96 | selectedKey: "Feature1",
97 | style: {}
98 | },
99 |
100 | main: {
101 | components: {
102 | "Feature1-1": {
103 | title: 'table 数据展示',
104 | component: require('../feature/Feature1-1')
105 | },
106 | "Feature1-2": {
107 | title: 'simple对象 数据展示',
108 | component: require('../feature/Feature1-2')
109 | },
110 | "Feature1-3": {
111 | title: '数据可视化 数据展示',
112 | component: require('../feature/Feature1-3')
113 | },
114 | "Feature1-4": {
115 | title: '综合数据展示',
116 | component: require('../feature/Feature1-4')
117 | },
118 |
119 | "Feature2-1": {
120 | title: 'table 数据搜索操作',
121 | component: require('../feature/Feature2-1')
122 | },
123 | "Feature2-2": {
124 | title: 'table 数据增删改操作',
125 | component: require('../feature/Feature2-2')
126 | },
127 | "Feature2-3": {
128 | title: 'simple对象数据修改操作',
129 | component: require('../feature/Feature2-3')
130 | },
131 |
132 | "Feature3-1": {
133 | title: '富文本编辑区域',
134 | component: require('../feature/Feature3-1')
135 | },
136 |
137 | "Feature1": {
138 | title: '这是功能区域标题1',
139 | component: require('../feature/Feature1')
140 | }, // 纯数据展示
141 | "Feature2": {
142 | title: '这是功能区域标题2',
143 | component: require('../feature/Feature2')
144 | }, // 添加操作
145 | "Feature3": {
146 | title: '这是功能区域标题3',
147 | component: require('../feature/Feature3')
148 | },
149 | "Feature4": {
150 | title: '这是功能区域标题4',
151 | component: require('../feature/Feature4')
152 | },
153 | "Feature5": {
154 | title: '这是功能区域标题5',
155 | component: require('../feature/Feature5')
156 | },
157 | "Feature6": {
158 | title: '这是功能区域标题6',
159 | component: require('../feature/Feature6')
160 | },
161 | "Feature7": {
162 | title: '这是功能区域标题7',
163 | component: require('../feature/Feature7')
164 | },
165 | "Feature8": {
166 | title: '这是功能区域标题8',
167 | component: require('../feature/Feature2')
168 | }
169 | },
170 | style: {}
171 | },
172 |
173 | permission: BaiduInfo.permission,
174 | loginUrl: BaiduInfo.loginUrl
175 | }
176 |
177 | export default Config;
--------------------------------------------------------------------------------
/src/feature/Feature4.jsx:
--------------------------------------------------------------------------------
1 | // 含有可操作 table 栏的数据展示
2 | import React from 'react';
3 |
4 | import FeatureSetConfig from '../components/FeatureSetConfig';
5 |
6 | import Immutable from 'immutable';
7 | //https://github.com/ded/reqwest
8 | import Reqwest from 'reqwest';
9 |
10 |
11 | const conf = {
12 |
13 | // 初始化页面的数据 回调函数传入 items 列表
14 | initData: function(callback){
15 |
16 | let data = {
17 | type: 'entry_list',
18 | num: 20,
19 | ua: 'bd_1_1_1_5-5-0-0_1',
20 | cuid: '00000000000000000000000000000000%7C0000000000000000',
21 | channel: 'AA_0',
22 | dir: 'up'
23 | }
24 |
25 | Reqwest({
26 | url: 'http://uil.cbs.baidu.com/rssfeed/fetch?fn=?',
27 | data: data,
28 | type: 'jsonp',
29 | jsonpCallback: 'fn',
30 | success: function (data) {
31 | let lists = data.data.stream_data;
32 |
33 | // 必须要向数据中 添加唯一的 key
34 | lists.forEach(function(ele) {
35 | ele.key = ele.docid;
36 | });
37 |
38 | callback(lists);
39 | }
40 | });
41 |
42 | },
43 |
44 | // 功能模块需要时 添加 CRUD 4方法
45 | Create: function(data, callback){
46 | let dataI = Immutable.fromJS({
47 | type: 'entry_list'
48 | }).merge({id: data.key});
49 |
50 | // ... 操作添加数据的请求
51 | console.log(dataI.toJS());
52 |
53 | let item = {
54 | docid: (Math.random()*10000000000)|0,
55 | title: '院依法对原省安监局局长陈炎生决定逮捕',
56 | link: 'sdfghjcvbnmertfheiuwfhsdh'
57 | }
58 |
59 | // 需要设置key
60 | item.key = item.docid;
61 |
62 | // 模拟请求创建成功的回调
63 | setTimeout(function(){
64 | callback(item);
65 | }, 1000);
66 | },
67 | Delete: function(data, callback){
68 |
69 | let dataI = Immutable.fromJS({
70 | type: 'entry_list'
71 | }).merge({id: data.key});
72 |
73 | // ... 操作删除请求
74 | console.log(dataI.toJS());
75 |
76 | // 模拟请求删除成功的回调
77 | setTimeout(function(){
78 | callback();
79 | }, 1000)
80 |
81 | },
82 | Update:function(data, callback){
83 | console.log(data);
84 | },
85 | Retrieve: function(data, callback){
86 | let dataI = Immutable.fromJS({
87 | type: 'entry_list',
88 | num: 20,
89 | ua: 'bd_1_1_1_5-5-0-0_1',
90 | cuid: '00000000000000000000000000000000%7C0000000000000000',
91 | channel: 'AA_0',
92 | dir: 'up'
93 | }).merge(data);
94 |
95 | Reqwest({
96 | url: 'http://uil.cbs.baidu.com/rssfeed/fetch?fn=?',
97 | data: dataI.toJS(),
98 | type: 'jsonp',
99 | jsonpCallback: 'fn',
100 | success: function (data) {
101 | let lists = data.data.stream_data;
102 | // 必须要向数据中 添加唯一的 key
103 | lists.forEach(function(ele) {
104 | ele.key = ele.docid;
105 | });
106 |
107 | callback(lists);
108 | }
109 | });
110 | },
111 |
112 | // 创建项目所需的字段
113 | // rules 规范可见 https://github.com/yiminghe/async-validator
114 | CType:[
115 | {
116 | name: 'id',
117 | label: '唯一标识',
118 | type: 'string',
119 | placeholder: '请输入标示名称',
120 | rules: [{ required: true, min: 5, message: '用户名至少为 5 个字符' }]
121 | },{
122 | name: 'id2',
123 | label: '唯一标识',
124 | type: 'string',
125 | placeholder: '请输入标示名称',
126 | rules: [{ required: true, type: 'email', message: '请输入正确的邮箱地址' }]
127 | },{
128 | name: 'date',
129 | label: '项目开始时间',
130 | type: 'date',
131 | },{
132 | name: 'stype',
133 | label: '项目类型Select',
134 | type: 'select',
135 | defaultValue: 'one',
136 | options:[{
137 | text: '选项一',
138 | value: 'one'
139 | },{
140 | text: '选项二',
141 | value: 'two'
142 | },{
143 | text: '选项三',
144 | value: 'three'
145 | }]
146 | },{
147 | name: 'rtype',
148 | label: '项目类型Radio',
149 | type: 'radio',
150 | defaultValue: 'one',
151 | options:[{
152 | text: '选项一',
153 | value: 'one'
154 | },{
155 | text: '选项二',
156 | value: 'two'
157 | },{
158 | text: '选项三',
159 | value: 'three'
160 | }]
161 | },{
162 | name: 'ischange',
163 | label: '是否过滤',
164 | type: 'switch'
165 | },{
166 | name: 'image',
167 | label: '背景图片',
168 | type: 'imageUpload'
169 | }
170 |
171 | ],
172 |
173 |
174 |
175 | columns: [
176 | {
177 | title: 'DOCID', // table header 文案
178 | dataIndex: 'docid', // 数据对象内的属性,也做react vdom 的key
179 | type: 'string', // table 内显示的类型
180 | sort: true, // 是否需要排序
181 | width:200
182 | }, {
183 | title: '标题',
184 | dataIndex: 'title',
185 | type: 'string'
186 | }, {
187 | title: '链接',
188 | dataIndex: 'link',
189 | type: 'link'
190 | }, {
191 | title: '操作',
192 | type: 'operate', // 操作的类型必须为 operate
193 | width: 120,
194 | btns: [{
195 | text: '删除',
196 | type: 'delete'
197 | }, {
198 | text: '展示',
199 | callback: function(item){
200 | console.log(item)
201 | }
202 | }], // 可选
203 |
204 | // 对应btns 的回调函数
205 | // item为操作的单一数据对象
206 | // callback 为组件的回调函数,将处理之后的数据回传 删除则传undefined
207 | // callbacks: [function(item, callback){
208 | // item.docid = 0;
209 | // callback(item, 'update');
210 | // },function(item, callback){
211 | // callback(item, 'delete');
212 | // }]
213 | }
214 | ]
215 |
216 | };
217 |
218 | const Feature2 = FeatureSetConfig(conf);
219 |
220 | export default Feature2;
221 |
--------------------------------------------------------------------------------
/src/views/App/index.less:
--------------------------------------------------------------------------------
1 | .ant-layout-aside {
2 | position: relative;
3 | min-height: 100%;
4 | .ant-layout-main {
5 | margin-left: 224px;
6 | background: #ececec;
7 | }
8 | .ant-layout-container {
9 | margin: 24px 16px;
10 | .ant-layout-content {
11 | background: #fff;
12 | padding: 24px;
13 | }
14 | }
15 | }
16 |
17 | /***********************/
18 |
19 | .ant-layout-aside {
20 | position: relative;
21 | min-height: 100%;
22 | }
23 |
24 | .ant-layout-aside .ant-layout-logo {
25 | position: relative;
26 | width: 150px;
27 | height: 32px;
28 | // background: #333;
29 | color: #999;
30 | border-radius: 6px;
31 | margin: 16px 24px 16px 28px;
32 | padding: 7px 0px 0 60px;
33 | transition: all 0.3s ease;
34 | }
35 | .ant-layout-aside .ant-layout-logo > img {
36 | position: absolute;
37 | top: 0;
38 | left: -11px;
39 | height: 100%;
40 | }
41 |
42 | .ant-layout-aside .ant-layout-sider > .ant-layout-logo .nav-text {
43 | vertical-align: baseline;
44 | display: inline-block;
45 | white-space: nowrap;
46 | }
47 | .ant-layout-aside-collapse .ant-layout-sider > .ant-layout-logo .nav-text {
48 | display: none;
49 | }
50 |
51 | .ant-layout-aside-collapse .ant-layout-logo {
52 | width: 32px;
53 | margin: 16px;
54 | transition: all 0.3s ease;
55 | }
56 |
57 | .ant-layout-aside .ant-layout-sider {
58 | width: 224px;
59 | background: #404040;
60 | position: absolute;
61 | overflow: visible;
62 | padding-bottom: 24px;
63 | height: 100%;
64 | transition: all 0.3s ease;
65 | }
66 |
67 | .ant-layout-aside-collapse .ant-layout-sider {
68 | width: 64px;
69 | transition: all 0.3s ease;
70 | }
71 |
72 | .ant-layout-aside .ant-layout-sider > .ant-menu {
73 | margin-bottom: 20px;
74 | }
75 |
76 | // .ant-layout-aside .ant-layout-sider {
77 | // margin: 16px 0;
78 | // }
79 | .ant-layout-aside .ant-layout-sider .nav-badge,
80 | .ant-layout-aside .ant-layout-sider .nav-text {
81 | vertical-align: baseline;
82 | display: inline-block;
83 | }
84 |
85 | .ant-layout-aside .ant-layout-sider .anticon {
86 | transition: font-size .3s;
87 | }
88 |
89 | .ant-layout-aside-collapse .ant-layout-sider {
90 | transition: all 0s ease;
91 | }
92 |
93 | .ant-layout-aside-collapse .ant-layout-sider .anticon {
94 | padding-top: 12px;
95 | font-size: 16px;
96 | display: inline-block;
97 | }
98 |
99 | .ant-layout-aside-collapse .ant-layout-sider .nav-badge,
100 | .ant-layout-aside-collapse .ant-layout-sider .nav-text {
101 | display: none;
102 | }
103 |
104 | .ant-layout-aside-collapse .ant-layout-sider :hover {
105 | width: 165px;
106 | background: #2db7f5;
107 | color: #fff;
108 | transition: all 0s ease;
109 | border-radius: 0 5px 5px 0;
110 | }
111 |
112 | .ant-layout-aside-collapse .ant-layout-sider :hover .nav-badge {
113 | display: inline-block;
114 | vertical-align: top;
115 | background: #2db7f5;
116 | color: #fff;
117 | border-radius: 0 5px 5px 0;
118 | }
119 | .ant-layout-aside-collapse .ant-layout-sider :hover .nav-text {
120 | display: inline-block;
121 | vertical-align: top;
122 | background: #2db7f5;
123 | color: #fff;
124 | // padding-right: 16px;
125 | border-radius: 0 5px 5px 0;
126 | }
127 |
128 | /* 实际使用中需要改成 position: fixed */
129 | .ant-layout-aside .ant-aside-action {
130 | padding-top: 12px;
131 | height: 42px;
132 | width: 224px;
133 | position: absolute;
134 | bottom: 0;
135 | background: #656565;
136 | color: #fff;
137 | text-align: center;
138 | line-height: 42px;
139 | cursor: pointer;
140 | transition: all 0.3s ease;
141 | }
142 |
143 | .ant-layout-aside-collapse .ant-aside-action {
144 | width: 64px;
145 | transition: all 0.3s ease;
146 | }
147 |
148 | .ant-layout-aside .ant-layout-header {
149 | background: #fff;
150 | height: 64px;
151 | border-bottom: 1px solid #e9e9e9;
152 | }
153 |
154 | .ant-layout-aside .ant-layout-breadcrumb {
155 | margin: 7px 0 -17px 24px;
156 | }
157 |
158 | .ant-layout-aside .ant-layout-main {
159 | margin-left: 224px;
160 | transition: all 0.3s ease;
161 | }
162 |
163 | .ant-layout-aside-collapse .ant-layout-main {
164 | margin-left: 64px;
165 | transition: all 0.3s ease;
166 | }
167 |
168 | .ant-layout-aside .ant-layout-container {
169 | margin: 24px 16px;
170 | }
171 |
172 | .ant-layout-aside .ant-layout-content {
173 | background: #fff;
174 | padding: 24px;
175 | }
176 |
177 | .ant-layout-aside .ant-layout-footer {
178 | height: 64px;
179 | line-height: 64px;
180 | text-align: center;
181 | font-size: 12px;
182 | color: #999;
183 | background: #fff;
184 | border-top: 1px solid #e9e9e9;
185 | width: 100%;
186 | }
187 |
188 |
189 |
190 | // 悬浮徽章
191 | .ant-layout-aside-collapse .ant-layout-sider .ant-badge-dot {
192 | position: absolute;
193 | transform: translateX(-50%);
194 | transform-origin: 0px center;
195 | top: 5px;
196 | height: 8px;
197 | width: 9px;
198 | border-radius: 100%;
199 | background: #f50;
200 | z-index: 10;
201 | box-shadow: 0 0 0 1px #fff;
202 | }
203 |
204 | // 悬浮徽章
205 | .ant-layout-aside-collapse .ant-layout-sider :hover .ant-badge-dot {
206 | // display: none;
207 |
208 | position: absolute;
209 | transform: translateX(-50%);
210 | transform-origin: 0px center;
211 | top: 5px;
212 | height: 8px;
213 | width: 9px;
214 | border-radius: 100%;
215 | background: #f50;
216 | z-index: 10;
217 | box-shadow: 0 0 0 1px #fff;
218 | }
219 | .ant-badge-dot {
220 | height: 9px;
221 | width: 9px;
222 | }
223 |
224 | .nav-text {
225 | padding-left: 7px;
226 | }
227 |
228 | // 头像
229 | .ant-layout-aside .ant-layout-sider > .ant-layout-portrait > .nav-portrait {
230 | text-align: center;
231 | margin-bottom: 10px;
232 | margin-top: 20px;
233 | transition: all 3s ease;
234 | }
235 | .ant-layout-aside .ant-layout-sider > .ant-layout-portrait > .nav-portrait img {
236 | width: 120px;
237 | height: 120px;
238 | border-radius: 50%;
239 | transition: all 1s ease;
240 | }
241 | .ant-layout-aside .ant-layout-sider > .ant-layout-portrait > .nav-portrait-title {
242 | color: #ccc;
243 | text-align: center;
244 | cursor: pointer;
245 | transition: all 3s ease;
246 | }
247 | .ant-layout-aside .ant-layout-sider > .ant-layout-portrait > .nav-portrait-title:hover {
248 | text-decoration: underline;
249 | }
250 | .ant-layout-aside .ant-layout-sider > .ant-layout-portrait > .nav-portrait-name {
251 | color: #2db7f5;
252 | text-align: center;
253 | transition: all 3s ease;
254 | }
255 |
256 |
257 | .ant-layout-aside-collapse .ant-layout-sider > .ant-layout-portrait > .nav-portrait {
258 | height: 32px;
259 | transition: all 3s ease;
260 | }
261 | .ant-layout-aside-collapse .ant-layout-sider > .ant-layout-portrait > .nav-portrait img {
262 | width: 32px;
263 | height: 32px;
264 | transition: all 0s ease;
265 | }
266 | .ant-layout-aside-collapse .ant-layout-sider > .ant-layout-portrait > .nav-portrait-title,
267 | .ant-layout-aside-collapse .ant-layout-sider > .ant-layout-portrait > .nav-portrait-name {
268 | display: none;
269 | transition: all 3s ease;
270 | }
271 |
272 |
273 | // case状态
274 | .case-state {
275 | display: inline-block;
276 | border-radius: 100%;
277 | height: 8px;
278 | width: 8px;
279 | margin-right: 5px;
280 | }
281 | .state-success{
282 | background: #87d068;
283 | }
284 | .state-error{
285 | background: #f50;
286 | }
287 | .state-ongoing{
288 | background: #2db7f5;
289 | }
290 | .state-close{
291 | background: #ccc;
292 | }
293 | .state-emergency{
294 | background: #ff9800;
295 | }
296 |
297 | // 树控件,增加收藏功能,浮动错位问题,用定位解决
298 | .star-tree {
299 | position: relative;
300 | }
--------------------------------------------------------------------------------
/src/feature/Feature6.jsx:
--------------------------------------------------------------------------------
1 | // 含有可操作 table 栏的数据展示
2 | import React from 'react';
3 |
4 | import FeatureSetConfig from '../components/FeatureSetConfig';
5 |
6 | import Immutable from 'immutable';
7 | //https://github.com/ded/reqwest
8 | import Reqwest from 'reqwest';
9 |
10 |
11 | const conf = {
12 |
13 | // 初始化页面的数据 回调函数传入 items 列表
14 | initData: function(callback){
15 |
16 | let data = {
17 | type: 'entry_list',
18 | num: 20,
19 | ua: 'bd_1_1_1_5-5-0-0_1',
20 | cuid: '00000000000000000000000000000000%7C0000000000000000',
21 | channel: 'AA_0',
22 | dir: 'up'
23 | }
24 |
25 | Reqwest({
26 | url: 'http://uil.cbs.baidu.com/rssfeed/fetch?fn=?',
27 | data: data,
28 | type: 'jsonp',
29 | jsonpCallback: 'fn',
30 | success: function (data) {
31 | let lists = data.data.stream_data;
32 |
33 | // 必须要向数据中 添加唯一的 key
34 | lists.forEach(function(ele) {
35 | ele.key = ele.docid;
36 | });
37 |
38 | callback(lists);
39 | }
40 | });
41 |
42 | },
43 |
44 | // 功能模块需要时 添加 CRUD 4方法
45 | Create: function(data, callback){
46 | let dataI = Immutable.fromJS({
47 | type: 'entry_list'
48 | }).merge({id: data.key});
49 |
50 | // ... 操作添加数据的请求
51 | console.log(dataI.toJS());
52 |
53 | let item = {
54 | docid: (Math.random()*10000000000)|0,
55 | title: '院依法对原省安监局局长陈炎生决定逮捕',
56 | link: 'sdfghjcvbnmertfheiuwfhsdh'
57 | }
58 |
59 | // 需要设置key
60 | item.key = item.docid;
61 |
62 | // 模拟请求创建成功的回调
63 | setTimeout(function(){
64 | callback(item);
65 | }, 1000);
66 | },
67 | Delete: function(data, callback){
68 |
69 | let dataI = Immutable.fromJS({
70 | type: 'entry_list'
71 | }).merge({id: data.key});
72 |
73 | // ... 操作删除请求
74 | console.log(dataI.toJS());
75 |
76 | // 模拟请求删除成功的回调
77 | setTimeout(function(){
78 | callback();
79 | }, 1000)
80 | },
81 | Update:function(data, callback){
82 | console.log(data);
83 | },
84 | Retrieve: function(data, callback){
85 | let dataI = Immutable.fromJS({
86 | type: 'entry_list',
87 | num: 20,
88 | ua: 'bd_1_1_1_5-5-0-0_1',
89 | cuid: '00000000000000000000000000000000%7C0000000000000000',
90 | channel: 'AA_0',
91 | dir: 'up'
92 | }).merge(data);
93 |
94 | Reqwest({
95 | url: 'http://uil.cbs.baidu.com/rssfeed/fetch?fn=?',
96 | data: dataI.toJS(),
97 | type: 'jsonp',
98 | jsonpCallback: 'fn',
99 | success: function (data) {
100 | let lists = data.data.stream_data;
101 | // 必须要向数据中 添加唯一的 key
102 | lists.forEach(function(ele) {
103 | ele.key = ele.docid;
104 | });
105 |
106 | callback(lists);
107 | }
108 | });
109 | },
110 |
111 | // 可设置的查询字段
112 | RType:[
113 | {
114 | name: 'id',
115 | label: '唯一标识',
116 | type: 'string',
117 | placeholder: '请输入标示名称'
118 | },{
119 | name: 'date',
120 | label: '项目开始时间',
121 | type: 'date'
122 | },{
123 | name: 'stype',
124 | label: '项目类型Select',
125 | type: 'select',
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: 'rtype',
139 | label: '项目类型Radio',
140 | type: 'radio',
141 | defaultValue: 'one',
142 | options:[{
143 | text: '选项一',
144 | value: 'one'
145 | },{
146 | text: '选项二',
147 | value: 'two'
148 | },{
149 | text: '选项三',
150 | value: 'three'
151 | }]
152 | },{
153 | name: 'ischange',
154 | label: '是否过滤',
155 | type: 'switch',
156 | defaultValue: false
157 | }
158 |
159 | ],
160 | // 创建项目所需的字段
161 | // rules 规范可见 https://github.com/yiminghe/async-validator
162 | CType:[
163 | {
164 | name: 'id',
165 | label: '唯一标识',
166 | type: 'string',
167 | placeholder: '请输入标示名称',
168 | rules: [{ required: true, min: 5, message: '用户名至少为 5 个字符' }]
169 | },{
170 | name: 'id2',
171 | label: '唯一标识',
172 | type: 'string',
173 | placeholder: '请输入标示名称',
174 | rules: [{ required: true, type: 'email', message: '请输入正确的邮箱地址' }]
175 | },{
176 | name: 'date',
177 | label: '项目开始时间',
178 | type: 'date',
179 | },{
180 | name: 'stype',
181 | label: '项目类型Select',
182 | type: 'select',
183 | defaultValue: 'one',
184 | options:[{
185 | text: '选项一',
186 | value: 'one'
187 | },{
188 | text: '选项二',
189 | value: 'two'
190 | },{
191 | text: '选项三',
192 | value: 'three'
193 | }]
194 | },{
195 | name: 'rtype',
196 | label: '项目类型Radio',
197 | type: 'radio',
198 | defaultValue: 'one',
199 | options:[{
200 | text: '选项一',
201 | value: 'one'
202 | },{
203 | text: '选项二',
204 | value: 'two'
205 | },{
206 | text: '选项三',
207 | value: 'three'
208 | }]
209 | },{
210 | name: 'ischange',
211 | label: '是否过滤',
212 | type: 'switch'
213 | },{
214 | name: 'image',
215 | label: '背景图片',
216 | type: 'imageUpload'
217 | }
218 |
219 | ],
220 | // 更新项目所需的字段
221 | UType:[
222 | {
223 | name: 'docid',
224 | label: '唯一标识',
225 | type: 'string',
226 | placeholder: '请输入标示名称'
227 | },{
228 | name: 'title',
229 | label: '标题',
230 | type: 'string',
231 | placeholder: '请输入标示名称'
232 | },{
233 | name: 'link',
234 | label: '链接',
235 | type: 'string'
236 | },{
237 | name: 'date',
238 | label: '日期',
239 | type: 'date'
240 | },{
241 | name: 'img',
242 | label: '图片',
243 | type: 'imageUpload'
244 | }
245 |
246 | ],
247 | columns: [
248 | {
249 | title: 'DOCID', // table header 文案
250 | dataIndex: 'docid', // 数据对象内的属性,也做react vdom 的key
251 | type: 'string', // table 内显示的类型
252 | sort: true, // 是否需要排序
253 | width:200
254 | }, {
255 | title: '标题',
256 | dataIndex: 'title',
257 | type: 'string'
258 | }, {
259 | title: '链接',
260 | dataIndex: 'link',
261 | type: 'link'
262 | }, {
263 | title: '操作',
264 | type: 'operate', // 操作的类型必须为 operate
265 | width: 120,
266 | btns: [{
267 | text: '更新',
268 | type: 'update'
269 | },{
270 | text: '删除',
271 | type: 'delete'
272 | },{
273 | text: '展示',
274 | callback: function(item){
275 | console.log(item)
276 | }
277 | }], // 可选
278 |
279 | // 对应btns 的回调函数
280 | // item为操作的单一数据对象
281 | // callback 为组件的回调函数,将处理之后的数据回传 删除则传undefined
282 | // callbacks: [function(item, callback){
283 | // item.docid = 0;
284 | // callback(item, 'update');
285 | // },function(item, callback){
286 | // callback(item, 'delete');
287 | // }]
288 | }
289 | ],
290 |
291 | uploadfile: function(data){
292 |
293 | }
294 |
295 | };
296 |
297 | const Feature2 = FeatureSetConfig(conf);
298 |
299 | export default Feature2;
300 |
--------------------------------------------------------------------------------
/src/util/index.js:
--------------------------------------------------------------------------------
1 | import { IMAGE_HOST_TEST, IMAGE_HOST_PROD } from '../constants'
2 | import { message } from 'antd';
3 |
4 | export const noop = function noop() {}
5 |
6 | /**
7 | * createReducer(initialparams, reducerMap)
8 | *
9 | * desc:
10 | * 自定义创建 `Reducer`
11 | *
12 | * 参数:
13 | * 1、 `initialparams` 初始 `params` 对象
14 | * 2、 `reducerMap` 与 `Action` 的映射关系, 判断 `action.type`的值, `promise` 的处理结果会由中间件 + `_SUCCESS、_ERROR、PENDING` 返回。
15 | *
16 | * 例 `reducerMap` 参数形式:
17 | * {
18 | * [`${types.GET_SITE_INFO}_SUCCESS`]: (params, data) => {
19 | * return params.set('siteInfo', data)
20 | * },
21 |
22 | * [`${types.GET_SITE_STATS}_SUCCESS`]: (params, data) => {
23 | * return params.set('siteStats', data)
24 | * },
25 |
26 | * [`${types.GET_ALL_NODES}_SUCCESS`]: (params, data) => {
27 | * return params.set('nodes', data)
28 | * }
29 | * }
30 | *
31 | * 返回值:
32 | * 使用 `es6` 语法返回一个 `function(params = initialparams, action){}` -> `(params = initialparams, action) => {}`
33 | * 函数内部:取出当前传入的 `action.type` 值,匹配 `reducerMap` 中对应的 `key` 值? 有匹配值则返回 `reducerMap` 所对应的方法 `(params, data) => {}` 进行处理, 没有则直接返回 `initialSparams`
34 | *
35 | */
36 | export function createReducer (initialparams, reducerMap) {
37 | return (params = initialparams, action) => {
38 | const reducer = reducerMap[action.type]
39 | /*
40 | TODP:判断 `请求` 返回的 `Code` 显示服务端提示信息。
41 | */
42 |
43 | // console.log('action', action);
44 | if (!action.error && action.payload && action.payload.code && action.payload.code != '0') {
45 | message.error(action.payload.message);
46 | if (params.get('loading')) {
47 | return params.set('loading', false);
48 | } else {
49 | return params;
50 | }
51 | }
52 |
53 | return reducer ? reducer(params, action.payload ? action.payload : {}, action.params) : params
54 | }
55 | }
56 |
57 | /**
58 | * fixNumber(date)
59 | *
60 | * desc:
61 | * 修复时间字符串,判断时间长度是否满足要求,不满足则根据长度差距在其末尾不足 '0'
62 | *
63 | * 参数:
64 | * `date` 时间 String
65 | *
66 | * 默认 `dataLength` = 13
67 | */
68 | const fixNumber = function(date) {
69 | const dateLength = 13;
70 | const len = date.length;
71 |
72 | let diffLen = dateLength - len;
73 | let diff = '';
74 |
75 | while (diffLen) {
76 | diff += '0';
77 | diffLen--;
78 | }
79 |
80 | return date + diff;
81 | };
82 |
83 | /**
84 | * dateFormat(data, format)
85 | *
86 | * desc:
87 | * 时间格式化,默认为 `yyyy-MM-dd` 类型
88 | *
89 | * 懵逼了,需要啃下 `es6` 语法。。。
90 | *
91 | * */
92 | export function dateFormat (date, format) {
93 | let _format = format || 'yyyy-MM-dd';
94 |
95 | const d = date;
96 | const o = {
97 | 'M+' : d.getMonth() + 1, // month
98 | 'd+' : d.getDate(), // day
99 | 'h+' : d.getHours(), // hour
100 | 'm+' : d.getMinutes(), // minute
101 | 's+' : d.getSeconds(), // second
102 | 'q+' : Math.floor((d.getMonth() + 3) / 3), // quarter
103 | 'S' : d.getMilliseconds() // millisecond
104 | };
105 |
106 | /**
107 | * `repeat` 方法返回一个新字符串,表示将原字符串重复 `n` 次。
108 | *
109 | * `RegExp` 是javascript中的一个内置对象。为正则表达式。
110 | * `RegExp.$1` 是 `RegExp` 的一个属性,指的是与正则表达式匹配的第一个 子匹配(以括号为标志)字符串
111 | * 以此类推,RegExp.$2,RegExp.$3,..RegExp.$99总共可以有99个匹配
112 | *
113 | * 例子:
114 | * var r= /^(\d{4})-(\d{1,2})-(\d{1,2})$/; //正则表达式 匹配出生日期(简单匹配)
115 | * r.exec('1985-10-15');
116 | * s1=RegExp.$1;
117 | * s2=RegExp.$2;
118 | * s3=RegExp.$3;
119 | * alert(s1+" "+s2+" "+s3)//结果为1985 10 15
120 | *
121 | * `test()` 方法用于检测一个字符串是否匹配某个模式.
122 | * 语法:RegExpObject.test(string)
123 | *
124 | */
125 |
126 | /**
127 | * 使用正则匹配年份:
128 | *
129 | * 1、 /(y+)/.test(_format)
130 | * - 检测: `_format` 中最少有一个 `y` // 正则: `+` 表示最少要有一个; `*` 表示 `0-N` ge; `?` 表示 `0/1` 个
131 | *
132 | * 2、 (d.getFullYear() + '').substr(4 - RegExp.$1.length))
133 | * - 判断正则匹配的字符串长度,截取年份字符串,正则匹配长度为 `1~3`、`5~7` 匹配结果为 `1~3` 位的年份字符串, `4,8,...` 为整个年份字符串
134 | *
135 | * 3、 _format = _format.replace(RegExp.$1, (d.getFullYear() + '').substr(4 - RegExp.$1.length));
136 | * - 替换所有 `y` 为上面匹配出的年份字符串的结果
137 | *
138 | */
139 |
140 | if (/(y+)/.test(_format)) {
141 | _format = _format.replace(RegExp.$1, (d.getFullYear() + '').substr(4 - RegExp.$1.length));
142 | }
143 |
144 | for (const k in o) {
145 | if (o.hasOwnProperty(k) && new RegExp('(' + k + ')').test(_format)) {
146 | _format = _format.replace(RegExp.$1, RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length));
147 | }
148 | }
149 |
150 | return _format;
151 | }
152 |
153 | /**
154 | * imgTrustUrl(url)
155 | * 在 `node` 服务上使用,判断 `开发环境/测试环境` 补全 `Url`,在前面加入服务器 `Url`
156 | *
157 | * 后续研究下如何扩展 `Java` 配置
158 | *
159 | */
160 | export function imgTrustUrl (url) {
161 | if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
162 | return IMAGE_HOST_TEST + url
163 | } else if (process.env.NODE_ENV === 'production') {
164 | return IMAGE_HOST_PROD + url
165 | } else {
166 | return url
167 | }
168 | }
169 |
170 | /**
171 | * isPromise (value)
172 | *
173 | * desc:判断是否是 `Promise` 类型
174 | *
175 | * 入参:Object
176 | *
177 | * 返回值:Boolean
178 | *
179 | */
180 | export function isPromise (value) {
181 | if (value !== null && typeof value === 'object') {
182 | return value.promise && typeof value.promise.then === 'function'
183 | }
184 | }
185 |
186 | /**
187 | * getCookie(name)
188 | *
189 | * desc:
190 | * 根据传入的名字,获取 `cookie` 中的值
191 | * 拼接后以数据的形式返回
192 | *
193 | * 入参:String
194 | *
195 | * 返回值:Array
196 | *
197 | */
198 | export function getCookie(name) {
199 | var value = "; " + document.cookie;
200 | var parts = value.split("; " + name + "=");
201 | if (parts.length == 2) return parts.pop().split(";").shift();
202 | }
203 |
204 | /**
205 | * 新旧page对象切换
206 | */
207 | export function getNewPager(newPage, oldPage) {
208 | if (!newPage) {
209 | return oldPage;
210 | }
211 | return {
212 | pageId: newPage.pageId ? newPage.pageId : oldPage.pageId,
213 | recPerPage: newPage.recPerPage ? newPage.recPerPage : oldPage.recPerPage,
214 | total: newPage.total || newPage.total === 0 ? newPage.total : oldPage.total,
215 | }
216 | }
217 |
218 | /**
219 | * `我的发布` 请求参数管理
220 | */
221 | export function myCaseParamsFromat(params) {
222 | return {
223 | keyword : encodeURI(params.myCase.keyword_value),
224 | caseNo : params.myCase.caseNo,
225 | taskType : params.myCase.taskType,
226 | sortType : params.myCase.sortType,
227 | create_time : params.myCase.create_time,
228 | isDesc : params.myCase.isDesc,
229 |
230 | status : params.menu.status,
231 | pageId : params.myCase.pager.pageId,
232 | recPerPage : params.myCase.pager.recPerPage,
233 |
234 | taskMatch : params.myCase.taskMatch
235 | }
236 | }
237 | /**
238 | * `我的任务` 请求参数管理
239 | */
240 | export function myTaskParamsFromat(params) {
241 | return {
242 | keyword : encodeURI(params.myTask.keyword_value),
243 | caseNo : params.myTask.caseNo,
244 | taskType : params.myTask.taskType,
245 | sortType : params.myTask.sortType,
246 | create_time : params.myTask.create_time,
247 | isDesc : params.myTask.isDesc,
248 |
249 | status : params.menu.status,
250 | pageId : params.myTask.pager.pageId,
251 | recPerPage : params.myTask.pager.recPerPage,
252 |
253 | taskMatch : params.myTask.taskMatch
254 | }
255 | }
256 |
257 | /**
258 | * `统计排名` 请求参数管理
259 | */
260 | export function caseRankParamsFromat(params) {
261 | return {
262 | sourceType : params.caseRank.sourceType,
263 | sourceUser : params.caseRank.sourceUser.key || '',
264 | startTime : params.caseRank.startTime,
265 | endTime : params.caseRank.endTime,
266 | isDesc : params.caseRank.isDesc,
267 |
268 | pageId : params.caseRank.pager.pageId,
269 | recPerPage : params.caseRank.pager.recPerPage,
270 | }
271 | }
272 | /**
273 | * `我的关注` 请求参数管理
274 | */
275 | export function myFocusParamsFromat(params) {
276 | return {
277 | keyword : encodeURI(params.myFocus.keyword_value),
278 | caseNo : params.myFocus.caseNo,
279 | taskType : params.myFocus.taskType,
280 | sortType : params.myFocus.sortType,
281 | create_time : params.myFocus.create_time,
282 | isDesc : params.myFocus.isDesc,
283 |
284 | status : params.menu.status,
285 | pageId : params.myFocus.pager.pageId,
286 | recPerPage : params.myFocus.pager.recPerPage,
287 |
288 | taskMatch : params.myFocus.taskMatch
289 | }
290 | }
291 | /**
292 | * `case分组` 请求参数管理
293 | */
294 | export function caseGroupParamsFromat(params) {
295 | return {
296 | keyword : encodeURI(params.caseGroup.keyword_value),
297 | caseNo : params.caseGroup.caseNo,
298 | taskType : params.caseGroup.taskType,
299 | sortType : params.caseGroup.sortType,
300 | create_time : params.caseGroup.create_time,
301 | isDesc : params.caseGroup.isDesc,
302 |
303 | sourceType : params.caseGroup.sourceType,
304 | sourceUser : encodeURI(params.caseGroup.sourceUser),
305 |
306 | searchType : params.caseGroup.searchType,
307 | startTime : encodeURI(params.caseGroup.startTime),
308 | endTime : encodeURI(params.caseGroup.endTime),
309 |
310 | status : params.menu.status,
311 | pageId : params.caseGroup.pager.pageId,
312 | recPerPage : params.caseGroup.pager.recPerPage,
313 |
314 | groupId : params.caseGroup.orgId
315 | }
316 | }
317 | /**
318 | * `case管理` 请求参数管理
319 | */
320 | export function caseManageParamsFromat(params) {
321 | return {
322 | keyword : encodeURI(params.caseManage.keyword_value),
323 | caseNo : params.caseManage.caseNo,
324 | taskType : params.caseManage.taskType,
325 | sortType : params.caseManage.sortType,
326 | create_time : params.caseManage.create_time,
327 | isDesc : params.caseManage.isDesc,
328 |
329 | sourceType : params.caseManage.sourceType,
330 | sourceUser : encodeURI(params.caseManage.sourceUser),
331 |
332 | searchType : params.caseManage.searchType,
333 | startTime : encodeURI(params.caseManage.startTime),
334 | endTime : encodeURI(params.caseManage.endTime),
335 |
336 | isTimeout : params.caseManage.isTimeout,
337 |
338 | status : params.menu.status,
339 | pageId : params.caseManage.pager.pageId,
340 | recPerPage : params.caseManage.pager.recPerPage
341 | }
342 | }
343 |
344 |
--------------------------------------------------------------------------------
/src/components/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 'react-router';
10 |
11 | import Immutable from 'immutable';
12 | import Reqwest from 'reqwest';
13 |
14 | import CFormItem from './CreateFormItem';
15 | // 搜索查询栏form 创建新item-form 更新form
16 | import UForm from './UpdateForm';
17 | import CForm from './CreateForm';
18 | import RForm from './RetrieveForm';
19 |
20 | const FormItem = Form.Item;
21 | const Option = Select.Option;
22 | const RadioGroup = Radio.Group;
23 |
24 |
25 | // 依赖 config 主题生成react 组件函数
26 | const FeatureSet = (config) => {
27 |
28 | let tableFeature = React.createClass({
29 | getInitialState: function(){
30 | return {
31 | columns: [],
32 | resultList: [],
33 | loading: false,
34 |
35 | updateFromShow: false,
36 | updateFromItem: {}
37 | }
38 | },
39 |
40 | componentWillMount: function(){
41 |
42 | this.setState({
43 | loading: true,
44 | columns: this.dealConfigColumns(config.columns)
45 | });
46 | },
47 |
48 | render: function() {
49 | const self = this;
50 |
51 | return
57 | },
58 |
59 | // 预处理配置显示中的 colums 数据 用于anted的table配置
60 | dealConfigColumns: function(lists){
61 | const self = this;
62 |
63 | let columns = [];
64 |
65 | lists.forEach((item) => {
66 | let column = {
67 | title: item.title,
68 | dataIndex: item.dataIndex,
69 | key: item.dataIndex,
70 | width: item.width
71 | }
72 |
73 | if( item.type === 'operate' ){
74 | // 兼容单一形式与数组形式
75 | let btns = Array.isArray(item.btns)?item.btns:[item.btns];
76 |
77 | // 处理表单 操作 栏目以及回调函数
78 | column.render = item.render || function(txt, record){
79 | return
80 | {
81 | btns.map(function(btn,i) {
82 | return (
83 |
84 | {btn.text}
85 | {i!==btns.length-1?:''}
86 |
87 | );
88 |
89 | })
90 | }
91 |
92 | };
93 | }else{
94 | column.render = item.render || self.renderFunc[item.type] || ((text) => (
{text}));
95 | }
96 |
97 | if(item.sort){
98 | column.sorter = item.sorter || ((a, b) => a[item.dataIndex] - b[item.dataIndex]);
99 | }
100 | columns.push(column);
101 |
102 | });
103 |
104 | return columns;
105 |
106 | },
107 |
108 | // columns 类型对应的通用痛render
109 | renderFunc: {
110 | link: (text) => (
111 |
112 | {text}
113 | ),
114 |
115 | image: (url) => (
116 |
117 |
118 | )
119 | },
120 |
121 | handleCreate: function(info){
122 | const self = this;
123 | self.setState({
124 | loading: true
125 | });
126 |
127 | config.Create(info, function(item){
128 | // 初级接口的坑
129 | if(!item){
130 | config.initData(function(list){
131 | self.setState({
132 | loading: false,
133 | resultList: list
134 | });
135 | });
136 | return;
137 | }
138 |
139 | let lists = self.state.resultList;
140 | lists.unshift(item);
141 |
142 | self.setState({
143 | loading: false,
144 | resultList: lists
145 | });
146 | });
147 | },
148 |
149 | handleUpdate: function(info){
150 | const self = this;
151 | let result = Immutable.fromJS(self.state.resultList);
152 |
153 | config.Update(info, function(item){
154 | let resultList = result.map(function(v, i){
155 | if(v.get('key') === item.key){
156 | return Immutable.fromJS(item);
157 | }else{
158 | return v;
159 | }
160 | });
161 | message.success('更新成功');
162 |
163 | self.setState({
164 | loading: false,
165 | updateFromShow: false,
166 | resultList: resultList.toJS()
167 | });
168 | });
169 | },
170 | hideUpdateForm: function(){
171 | this.setState({
172 | updateFromShow: false,
173 | updateFromItem: {}
174 | });
175 | },
176 |
177 | // 搜索更新处理
178 | handleRetrieve: function(info){
179 | const self = this;
180 | self.setState({
181 | loading: true
182 | });
183 |
184 | config.Retrieve(info, function(list){
185 | self.setState({
186 | loading: false,
187 | resultList: list
188 | });
189 | });
190 | },
191 |
192 | // table 操作列回调处理
193 | operateCallbacks: function(item, btn){
194 | const self = this;
195 |
196 | if(btn.type){
197 |
198 | let resultList;
199 | let type = btn.type;
200 | let itemI = Immutable.fromJS(item);
201 | let result = Immutable.fromJS(self.state.resultList);
202 |
203 | // table 操作栏目通用设定为 更新与删除 两项
204 | if(type === 'update'){
205 | this.setState({
206 | updateFromShow: true,
207 | updateFromItem: itemI.toJS()
208 | });
209 | }else if(type === 'delete'){
210 | this.setState({
211 | loading: true
212 | });
213 |
214 | config.Delete(itemI.toJS(), function(){
215 | resultList = result.filter(function(v, i){
216 | if(v.get('key') !== itemI.get('key')){
217 | return true;
218 | }
219 | });
220 | message.success('删除成功');
221 |
222 | self.setState({
223 | loading: false,
224 | resultList: resultList.toJS()
225 | });
226 | });
227 | }
228 |
229 |
230 | }else if(btn.callback){
231 | btn.callback(item);
232 | }
233 | },
234 |
235 | componentDidMount: function(){
236 | const self = this;
237 |
238 | config.initData(function(list){
239 | self.setState({
240 | loading: false,
241 | resultList: list
242 | });
243 | });
244 | }
245 | });
246 |
247 | let simpleFeature = React.createClass({
248 | getInitialState: function(){
249 | return {
250 | item:{},
251 | loading: false,
252 |
253 | updateFromShow: false,
254 | updateFromItem: {}
255 | }
256 | },
257 |
258 | componentWillMount: function(){
259 | },
260 |
261 | render: function() {
262 | const self = this;
263 | const itemInfo = this.state.item;
264 |
265 | const { getFieldProps } = this.props.form;
266 | const formItemLayout = {
267 | labelCol: { span: 3 },
268 | wrapperCol: { span: 18 },
269 | };
270 |
271 | const operate = config.operate || [];
272 |
273 | return
274 |
289 | {
290 | operate.map(function(btn){
291 | return
292 | })
293 | }
294 |
295 | },
296 |
297 | componentDidMount: function(){
298 | const self = this;
299 | self.setState({
300 | loading: true
301 | });
302 |
303 | config.initData(function(item){
304 | self.setState({
305 | item: item,
306 | loading: false
307 | });
308 | });
309 | },
310 |
311 | operateCallbacks: function(btn){
312 | const self = this;
313 |
314 | let itemI = Immutable.fromJS(this.props.form.getFieldsValue());
315 |
316 | if(btn.type === 'update'){
317 |
318 | const self = this;
319 |
320 |
321 | config.Update(itemI.toJS(), function(item){
322 |
323 | message.success('更新成功');
324 |
325 | self.setState({
326 | item: item
327 | });
328 | });
329 |
330 |
331 | }else if(btn.callback){
332 | btn.callback(itemI.toJS());
333 | }
334 | }
335 | });
336 | simpleFeature = Form.create()(simpleFeature);
337 |
338 |
339 | let graphFeature = React.createClass({
340 | getInitialState: function(){
341 | return {
342 | option: config.option
343 | }
344 | },
345 |
346 | componentWillMount: function(){
347 | },
348 |
349 | render: function() {
350 | const self = this;
351 | const itemInfo = this.state.item;
352 |
353 | const operate = config.operate || [];
354 |
355 | return
356 |
360 |
361 | },
362 |
363 | componentDidMount: function(){
364 | const self = this;
365 | let option = Immutable.fromJS(self.state.option).toJS();
366 |
367 | config.initData(function(series){
368 | option.series = series;
369 | self.setState({
370 | option: option
371 | });
372 | });
373 | }
374 | });
375 |
376 | switch (config.type){
377 | case 'tableList':
378 | return tableFeature;
379 | break;
380 |
381 | case 'graphList':
382 | return graphFeature;
383 | break;
384 |
385 | case 'simpleObject':
386 | return simpleFeature;
387 | break;
388 |
389 | case 'complexObject':
390 | return complexFeature;
391 | break;
392 |
393 | default:
394 | return tableFeature;
395 | break;
396 | }
397 | }
398 |
399 |
400 | export default FeatureSet;
401 |
--------------------------------------------------------------------------------
/src/util/templateUtil.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import { Table, Pagination, Popconfirm, Row, Col } from 'antd';
3 | import { Link } from 'react-router'
4 |
5 | /**
6 | * 格式化 `caseDesc`
7 | *
8 | * desc:
9 | * 服务端传来的 `caseDesc` 换行是用 `/n` 来体现的,在页面上无法显示
10 | *
11 | * 该方法将 `caseDesc` 按 `/n` 来切割成数据
12 | * 遍历切割后的数据,处理换行显示
13 | *
14 | */
15 | const caseDescFormat = (caseDesc) => {
16 | return caseDesc.split("/n")
17 | .map((item, index, items) => {
18 | if ((items.length - 1) == index) {
19 | return
{item}
20 | } else {
21 | return
{item}
22 | }
23 | });
24 | };
25 |
26 | /**
27 | * 处理表格左侧 `+` 扩展内容
28 | *
29 | * desc:
30 | * 表格显示的字段为主要字段,扩展中显示的是附加字段及详情
31 | * 方便在使用case的时候,可以直接在表格上操作,减去进入详情的步骤
32 | *
33 | */
34 | export const expandedRowRender = (record) => {
35 | const caseDescElement = caseDescFormat(record.caseDesc);
36 |
37 | const styleTitle = { textAlign: 'right', border: '1px dotted #ccc', borderRight: 'none', borderLeft: 'none', padding: '10px', lineHeight: '1.5' };
38 | const styleContent = { border: '1px dotted #ccc', borderLeft: 'none', borderRight: 'none', padding: '10px', lineHeight: '1.5' };
39 | const styleDetail = { textAlign: 'right', padding: '0 10px 10px 10px' };
40 | const styleDetailCont = { textAlign: 'right', padding: '10px' };
41 | return
42 |
43 | 小区:
44 | {record.community ? record.community : '暂无数据'}
45 | 业主姓名:
46 | {record.ownerName ? record.ownerName : '暂无数据'}
47 | 单元:
48 | {record.unit ? record.unit : '暂无数据'}
49 | 实收金额:
50 | {record.recoveredAmount ? record.recoveredAmount : '暂无数据'}
51 |
52 |
53 | 楼栋:
54 | {record.building ? record.building : '暂无数据'}
55 | 欠费月数:
56 | {record.arrearsMonth ? record.arrearsMonth : '暂无数据'}
57 | 房号:
58 | {record.room ? record.room : '暂无数据'}
59 | 业主电话:
60 | {record.ownerPhone ? record.ownerPhone : '暂无数据'}
61 |
62 |
63 | 收费方式:
64 | {record.chargeWay ? record.chargeWay : '暂无数据'}
65 | 实收历史欠费金额:
66 | {record.arrearsAmount ? record.arrearsAmount : '暂无数据'}
67 |
68 |
69 |
70 | 详情:
71 | {caseDescElement ? caseDescElement : '暂无数据'}
72 |
73 |
74 | };
75 |
76 | /**
77 | * case管理表格字段配置
78 | */
79 | export function caseManageTableHead(operation) {
80 | return [
81 | {
82 | title: '工单号',
83 | dataIndex: 'caseNo',
84 | }, {
85 | title: '标题',
86 | render: (text, record, index) =>
{record.caseTitle}
,
87 | },
88 | {
89 | title: '优先级',
90 | dataIndex: 'priority',
91 | key: 'priority',
92 | sorter: true,
93 | filters: [
94 | {
95 | text: '非常高',
96 | value: '1',
97 | },
98 | {
99 | text: '高',
100 | value: '2',
101 | },
102 | {
103 | text: '中',
104 | value: '3',
105 | },
106 | {
107 | text: '低',
108 | value: '4',
109 | }
110 | ],
111 | render: (text, record, index) => {
112 | return formatPriority(record.priority);
113 | }
114 | }
115 | , {
116 | title: '发起人',
117 | dataIndex: 'createUser',
118 | key: 'createUser'
119 | }, {
120 | title: '发起时间',
121 | dataIndex: 'createTime',
122 | key: 'createTime',
123 | sorter: true
124 | }, {
125 | title: '执行人',
126 | render: (text, record, index) => record.executorList[0] && record.executorList[0].userName,
127 | key: 'executorUser'
128 | }, {
129 | title: '类型',
130 | dataIndex: 'caseTypeName',
131 | key: 'caseTypeName',
132 | filters: operation.typeList
133 | // filterMultiple: false
134 | }, {
135 | title: '状态',
136 | render: function(text, record, index) {
137 | return formatStatus(record.status);
138 | },
139 | key: 'status',
140 | }, {
141 | title: '催费金额',
142 | dataIndex: 'amount',
143 | key: 'amount',
144 | sorter: true
145 | }, {
146 | title: '关注人',
147 | render: (text, record, index) =>
{record.focusList}
,
148 | key: 'focusUser'
149 | }, {
150 | title: '管理',
151 | key: 'operation',
152 | fixed: 'right',
153 | render: (record) =>
详情
154 | }];
155 | }
156 |
157 | /**
158 | * case排名表格字段配置
159 | */
160 | export function caseRankTableHead(operation) {
161 | return [
162 | {
163 | title: '排名',
164 | dataIndex: 'rownum'
165 | },
166 | {
167 | title: '员工姓名',
168 | dataIndex: 'userName',
169 | key: 'userName'
170 | },
171 | {
172 | title: '排名类型',
173 | render: (text, record, index) => {
174 | switch (record.rankType) {
175 | case 'remain':
176 | return (
剩余任务
);
177 | case 'create':
178 | return (
发起任务
);
179 | case 'finish':
180 | return (
完成任务
);
181 | case 'confirmfinish':
182 | return (
确认完成任务
);
183 | case 'close':
184 | return (
关闭任务
);
185 | }
186 | },
187 | key: 'rankType'
188 | },
189 | {
190 | title: '任务数量',
191 | dataIndex: 'caseNumber',
192 | key: 'caseNumber',
193 | sorter: true
194 | },
195 | {
196 | title: '日期',
197 | dataIndex: 'rankTime',
198 | key: 'rankTime'
199 | }];
200 | }
201 |
202 |
203 | /**
204 | * 我的关注表格字段配置
205 | */
206 | export function myFocusTableHead(operation) {
207 | return [
208 | {
209 | title: '工单号',
210 | dataIndex: 'caseNo',
211 | }, {
212 | title: '标题',
213 | render: (text, record, index) =>
{record.caseTitle}
,
214 | },
215 | {
216 | title: '优先级',
217 | dataIndex: 'priority',
218 | key: 'priority',
219 | sorter: true,
220 | filters: [
221 | {
222 | text: '非常高',
223 | value: '1',
224 | },
225 | {
226 | text: '高',
227 | value: '2',
228 | },
229 | {
230 | text: '中',
231 | value: '3',
232 | },
233 | {
234 | text: '低',
235 | value: '4',
236 | }
237 | ],
238 | render: (text, record, index) => {
239 | return formatPriority(record.priority);
240 | }
241 | }
242 | , {
243 | title: '发起人',
244 | dataIndex: 'createUser',
245 | key: 'createUser'
246 | }, {
247 | title: '发起时间',
248 | dataIndex: 'createTime',
249 | key: 'createTime',
250 | sorter: true
251 | }, {
252 | title: '执行人',
253 | render: (text, record, index) => record.executorList[0] && record.executorList[0].userName,
254 | key: 'executorUser'
255 | }, {
256 | title: '类型',
257 | dataIndex: 'caseTypeName',
258 | key: 'caseTypeName',
259 | filters: operation.typeList
260 | // filterMultiple: false
261 | }, {
262 | title: '状态',
263 | render: (text, record, index) => {
264 | return formatStatus(record.status);
265 | },
266 | key: 'status',
267 | }, {
268 | title: '催费金额',
269 | dataIndex: 'amount',
270 | key: 'amount',
271 | sorter: true
272 | }, {
273 | title: '关注人',
274 | render: (text, record, index) =>
{record.focusList}
,
275 | key: 'focusUser'
276 | }, {
277 | title: '管理',
278 | key: 'operation',
279 | fixed: 'right',
280 |
281 | render: (record) => {
282 | return (
283 |
284 | 详情
285 | )
286 | }
287 | }];
288 | }
289 |
290 |
291 | /**
292 | * 我的任务表格字段配置
293 | */
294 | export function myTaskTableHead(operation) {
295 | return [
296 | {
297 | title: '工单号',
298 | dataIndex: 'caseNo'
299 | }, {
300 | title: '标题',
301 | render: (text, record, index) =>
{record.caseTitle}
302 | },
303 | {
304 | title: '优先级',
305 | dataIndex: 'priority',
306 | key: 'priority',
307 | sorter: true,
308 | filters: [
309 | {
310 | text: '非常高',
311 | value: '1',
312 | },
313 | {
314 | text: '高',
315 | value: '2',
316 | },
317 | {
318 | text: '中',
319 | value: '3',
320 | },
321 | {
322 | text: '低',
323 | value: '4',
324 | }
325 | ],
326 | render: (text, record, index) => {
327 | return formatPriority(record.priority);
328 | }
329 | }
330 | , {
331 | title: '发起人',
332 | dataIndex: 'createUser',
333 | key: 'createUser'
334 | }, {
335 | title: '发起时间',
336 | dataIndex: 'createTime',
337 | key: 'createTime',
338 | sorter: true
339 | }, {
340 | title: '执行人',
341 | render: (text, record, index) => record.executorList[0] && record.executorList[0].userName,
342 | key: 'executorUser'
343 | }, {
344 | title: '类型',
345 | dataIndex: 'caseTypeName',
346 | key: 'caseTypeName',
347 | // filterMultiple: false,
348 | filters: operation.typeList
349 | }, {
350 | title: '状态',
351 | render: (text, record, index) => {
352 | return formatStatus(record.status);
353 | },
354 | key: 'status'
355 | }, {
356 | title: '催费金额',
357 | dataIndex: 'amount',
358 | key: 'amount',
359 | sorter: true
360 | }, {
361 | title: '关注人',
362 | render: (text, record, index) =>
{record.focusList}
,
363 | key: 'focusUser'
364 | }, {
365 | title: '管理',
366 | key: 'operation',
367 | fixed: 'right',
368 |
369 | render: (record) => {
370 | let successDom;
371 | const finishtext = '确定要完成这个任务吗?';
372 | if (record.status != 2 && record.status != 3 && record.status != 4) {
373 |
374 | successDom =
375 |
376 | { operation.finishCase(record.id) } }>
377 | 完成
378 |
379 | ;
380 | }
381 | return (
382 |
383 | 详情
384 | {successDom}
385 | );
386 | }
387 | }];
388 | }
389 |
390 |
391 | /**
392 | * 我的case表格字段配置
393 | */
394 | export function myCaseTableHead(operation) {
395 | return [
396 | {
397 | title: '工单号',
398 | dataIndex: 'caseNo',
399 | },
400 | {
401 | title: '标题',
402 | render: (text, record, index) =>
{record.caseTitle}
,
403 | },
404 | {
405 | title: '优先级',
406 | dataIndex: 'priority',
407 | key: 'priority',
408 | sorter: true,
409 | filters: [
410 | {
411 | text: '非常高',
412 | value: '1',
413 | },
414 | {
415 | text: '高',
416 | value: '2',
417 | },
418 | {
419 | text: '中',
420 | value: '3',
421 | },
422 | {
423 | text: '低',
424 | value: '4',
425 | }
426 | ],
427 | render: (text, record, index) => {
428 | return formatPriority(record.priority);
429 | }
430 | },
431 | {
432 | title: '发起人',
433 | dataIndex: 'createUser',
434 | key: 'createUser'
435 | }, {
436 | title: '发起时间',
437 | dataIndex: 'createTime',
438 | key: 'createTime',
439 | sorter: true
440 | }, {
441 | title: '执行人',
442 | render: (text, record, index) => record.executorList[0] && record.executorList[0].userName,
443 | key: 'executorUser'
444 | }, {
445 | title: '类型',
446 | dataIndex: 'caseTypeName',
447 | key: 'caseTypeName',
448 | filters: operation.typeList
449 | // filterMultiple: false
450 | }, {
451 | title: '状态',
452 | render: (text, record, index) => {
453 | return formatStatus(record.status);
454 | },
455 | key: 'status',
456 | }, {
457 | title: '催费金额',
458 | dataIndex: 'amount',
459 | key: 'amount',
460 | sorter: true
461 | }, {
462 | title: '关注人',
463 | render: (text, record, index) =>
{record.focusList}
,
464 | key: 'focusUser'
465 | }, {
466 | title: '管理',
467 | key: 'operation',
468 | fixed: 'right',
469 |
470 | render: (record) => {
471 | let ConfirmDom, CloseDom;
472 | const confirmFinishtext = '确定要完成这个任务吗?';
473 | const closetext = '确定要关闭这个任务吗?';
474 | if (record.status == 2) { // 已完成状态下才能操作确认完成
475 | ConfirmDom =
476 |
477 | { operation.confirmFinishCase(record.id) } }>
478 | 确认完成
479 |
480 |
481 |
482 | // ConfirmDom = ConfirmFinisModal;
483 | }
484 | if (record.status != 3 && record.status != 4) {
485 | CloseDom =
486 |
487 | { operation.closeCase(record.id) } }>
488 | 关闭
489 |
490 |
491 | // CloseDom = CloseModal;
492 | }
493 | return (
494 |
495 | 详情
496 | { ConfirmDom }
497 | { CloseDom }
498 | )
499 |
500 | // return (
501 | //
502 | // 详情
503 | // {record.status != 3 && record.status != 4? {operation.confirmFinishCase(record.id, close_message)}}/> : ''}
504 | // {record.status == 2? : ''}
505 | // )
506 | }
507 | }];
508 | }
509 |
510 | /**
511 | * case分组表格字段配置
512 | */
513 | export function caseGroupTableHead(operation) {
514 | return [
515 | {
516 | title: '工单号',
517 | dataIndex: 'caseNo',
518 | }, {
519 | title: '标题',
520 | render: (text, record, index) =>
{record.caseTitle}
,
521 | },
522 | {
523 | title: '优先级',
524 | dataIndex: 'priority',
525 | key: 'priority',
526 | sorter: true,
527 | filters: [
528 | {
529 | text: '非常高',
530 | value: '1',
531 | },
532 | {
533 | text: '高',
534 | value: '2',
535 | },
536 | {
537 | text: '中',
538 | value: '3',
539 | },
540 | {
541 | text: '低',
542 | value: '4',
543 | }
544 | ],
545 | render: (text, record, index) => {
546 | return formatPriority(record.priority);
547 | }
548 | }
549 | , {
550 | title: '发起人',
551 | dataIndex: 'createUser',
552 | key: 'createUser'
553 | }, {
554 | title: '发起时间',
555 | dataIndex: 'createTime',
556 | key: 'createTime',
557 | sorter: true
558 | }, {
559 | title: '执行人',
560 | render: (text, record, index) => record.executorList[0] && record.executorList[0].userName,
561 | key: 'executorUser'
562 | }, {
563 | title: '类型',
564 | dataIndex: 'caseTypeName',
565 | key: 'caseTypeName',
566 | filters: operation.typeList
567 | // filterMultiple: false
568 | }, {
569 | title: '状态',
570 | render: function(text, record, index) {
571 | return formatStatus(record.status);
572 | },
573 | key: 'status',
574 | }, {
575 | title: '催费金额',
576 | dataIndex: 'amount',
577 | key: 'amount',
578 | sorter: true
579 | }, {
580 | title: '关注人',
581 | render: (text, record, index) =>
{record.focusList}
,
582 | key: 'focusUser'
583 | }, {
584 | title: '管理',
585 | key: 'operation',
586 | fixed: 'right',
587 | render: (record) =>
详情
588 | }];
589 | }
590 |
591 | /**
592 | * 关联case 表格配置
593 | */
594 | export function relatedCaseTableHead(operation) {
595 | return [
596 | {
597 | title: '工单号',
598 | dataIndex: 'caseNo',
599 | key: 'caseNo',
600 | render: (text) =>
{text},
601 | }, {
602 | title: '标题',
603 | dataIndex: 'title',
604 | key: 'title',
605 | }, {
606 | title: '类型',
607 | dataIndex: 'caseTypeName',
608 | key: 'caseTypeName',
609 | }, {
610 | title: '优先级',
611 | dataIndex: 'priority',
612 | key: 'priority',
613 | render: (text, record, index) => {
614 | return formatPriority(record.priority);
615 | }
616 | }, {
617 | title: '状态',
618 | render: function(text, record, index) {
619 | return formatStatus(record.status);
620 | },
621 | key: 'status',
622 | }, {
623 | title: '操作',
624 | key: 'operation',
625 | render: (text, record) => {
626 |
627 | const closetext = '确定删除该关联分组?';
628 |
629 | return (
630 |
631 | 详情
632 |
633 |
634 |
635 |
636 | { operation.delRelatedCase(record.id) } }>
637 | 删除
638 |
639 |
640 |
641 |
642 | )
643 | },
644 | }];
645 | }
646 |
647 | function formatPriority(priority) {
648 | switch (priority) {
649 | case '1':
650 | return (
非常高
);
651 | case '2':
652 | return (
高
);
653 | case '3':
654 | return (
中
);
655 | case '4':
656 | return (
低
);
657 |
658 | default:
659 | return '暂无数据'
660 | }
661 | }
662 |
663 | function formatStatus(status) {
664 | switch (status) {
665 | case '1':
666 | return (
进行中
);
667 | case '2':
668 | return (
已完成
);
669 | case '3':
670 | return (
确认完成
);
671 | case '4':
672 | return (
已关闭
);
673 | }
674 | }
--------------------------------------------------------------------------------