报表生成器,配置生成报表查询页面

报表生成器,配置生成报表查询页面

JavaScript CSS相关

详细介绍

项目目标

  • 目标客户
    有报表开发需求的后端开发人员或前端开发人员
  • 功能
    通过JSON配置形式,快速构建常用报表页面。
  • 愿景
    对于中后台界面,前端能提供一个可配置的页面给后端部署。

项目启动

本项目使用了create-react-app脚手架。
如果未安装此脚手架,请执行如下命令进行安装。
npm install -g create-react-app 然后git clone本项目,执行如下命令

npm install
npm start

demo

我们先来写一个小demo。
循序渐进地了解各功能。

0.引入报表生成器。

新建一个vm文件

<!doctype html>
<div id="App">
</div>
<script src="//xxx.com/1.1.0/index.js"></script>

1.只输出表格。

<!doctype html>
<div id="App">
</div>
<script src="//xxx.com/1.1.0/index.js"></script>
<script>
var report = new reportFactory({
  "env": {
  	id: 'App', // 指定渲染的dom id
    csrf_token: "AEjBKW67I9AFxV7bvQBN3F", // 如果不需要可以移除这个属性
  },
  "table": {
    name: "table", // 表格名称
    fetchUrl: "//www.xxx.com/queryEmpFileList.json",  // 表格所请求的url
    jsxcolumns: [ // 列的名称
      {
        dataKey: "workNo", // 必填;列的标识,对应表格数据的key
        title: "工号",  // 必填;列标题;
        type: "string",  // 非必填;默认为"string",包含 'money', 'card', 'cnmobile', 'checkboxSelector', 'action', 'radio', 'text', 'select' 和 'custom' ; 渲染的类型
        width: 100, // 非必填;默认为100px;
      },
      {
        dataKey: "name",
        title: "姓名",
        width: 140,
      },
      {
        dataKey: "deptName",
        title: "部门",
        width: 200,
      },
      {
        dataKey: "empType",
        title: "员工类型",
      },
    ]
  }
});
report.render();
</script>

其中,我们约定表格请求接口返回数据格式为

{
  "success": true,
  "content": {
    "list":[{
      "列名称":"列的值"
    }],
    "totalSize": 10
  },
  "errorMsg": "",
  "errorCode": ""
}

这时,当业务方需要一个列表信息时,你可以很方便地配置一个页面给他。
已经包括分页功能。

2.输出查询组件和表格。

<!doctype html>
<div id="App">
</div>
<script src="//xxx.com/1.1.0/index.js"></script>
<script>
var report = new reportFactory({
  env: {
    id: 'App', // 指定渲染的dom id
  },
  table: {
    name: "table", // 表格名称
    fetchUrl: "//www.xxx.com/queryEmpFileList.json",  // 表格所请求的url
    beforeFetch: function (data, from, Formatter) {  // data是表单域的值,from是哪个表单触发,Formatter是内置的格式化函数参考http://uxcore.coding.me/components/formatter/
      return data;
    }
    jsxcolumns: [ // 列的名称
      {
        dataKey: "workNo", // 必填;列的标识,对应表格数据的key
        title: "工号",  // 必填;列标题;
        type: "string",  // 非必填;默认为"string",包含 'money', 'card', 'cnmobile', 'checkboxSelector', 'action', 'radio', 'text', 'select' 和 'custom' ; 渲染的类型
        width: 100, // 非必填;默认为100px;
      },
      {
        dataKey: "name",
        title: "姓名",
        width: 140,
      },
      {
        dataKey: "deptName",
        title: "部门",
        width: 200,
      },
      {
        dataKey: "empType",
        title: "员工类型",
      },
    ]
  },
  filter: [
    {
      id: "workNo", // 必填; 唯一标识
      component: "InputFormField",  // 必填; 组件类型
	    props:{
        jsxname: "workNo",
        jsxlabel: "工号",
        rules: [{
          validator: "isNotEmpty",
          errMsg: "不能为空"
        }],
      }
    },
    {
      id: "search",
      component: "Button",
	    props:{
	  	  text: '查询',
	    }
    },
    {
      id: "reset",
      component: "Button",
      props:{
        text: '重置',
      }
    },
	  {
      id: "buList",
      component: "SelectFormField",
      props: {
        jsxname: "bu", 
        jsxlabel: "bu",
        jsxdata: [
          {
            value: '信息平台',
            text: '信息平台'
          }
        ],
        listMap: { 
          listId:'bu', // 联动的属性名是bu
          propName: 'jsxdata' // 对应着组件的属性名是jsxdata
        },
      },
    },
  ],
});
report.render();
</script>

3.添加查询组件的布局配置。

var report = new reportFactory({
  //...other config
  filter: [
    {
      id: "workNo", // 必填; 唯一标识
      component: "InputFormField",  // 必填; 组件类型
    },
    {
      id: "search",
      component: "Button",
    },
    {
      id: "reset",
      component: "Button",
      props:{
        text: '重置',
      }
    },
	  {
      id: "buList",
      component: "SelectFormField",
      props: {
        jsxname: "bu", 
        jsxlabel: "bu",
        jsxdata: [
          {
            value: '信息平台',
            text: '信息平台'
          }
        ],
        listMap: { 
          listId:'bu', // 联动的属性名是bu
          propName: 'jsxdata' // 对应着组件的属性名是jsxdata
        },
      },
    },
    {
      id: "ButtonGroupFormField1",
      component: "ButtonGroupFormField",
    },
  ],
  filterLayout:[
    { formRow: ["workNo","buList"] },
    // 有子组件
    { formRow: [{id:"ButtonGroupFormField1", children:["search", "reset"]}] },
  ]
};
report.render();

4.添加查询事件和重置事件

报表生成器内置了查询事件和重置事件,直接引用即可。

var report = new reportFactory({
  //...other config
  filterEvent: [
    {
      id: "search",
      type: 'onClick',
      function: 'search',         
	    url:"//www.xxx.com/queryEmpFileList.json", // 这里指定url后,table的fetchURL失效
    },
    {
      id: "reset",
      type: 'onClick',
      function: 'reset',
    },
  ],
};
report.render();

5.查询组件的联动

var report = new reportFactory({
  //...other config
  filterListMap: {  // 查询组件的候选值
    'bu': [ // 这个就是bu组件
      {
        value: '信息平台',
        text: '信息平台'
      }, {
        value: '天猫',
        text: '天猫'
      }
    ],
  },
  filterChange: function (values, name, pass) {  // 查询组件发生值变化时触发这个函数
    console.log('filterChange', values, name, this); 
    this.setState({
      listMap: {
        'bu': [
          {
            value: '信息平台',
            text: '信息平台'
          }, {
            value: '天猫',
            text: '天猫'
          }, {
            value: '淘宝',
            text: '淘宝'
          }
        ]
      }
    });
  },
};
report.render();

6.columnPicker功能

这个是全新的demo

<!doctype html>
<div id="App">
</div>
<script src="//xxx.com/1.1.0/index.js"></script>
<script>
  var report = new reportFactory({
    "env": {
      id: 'App',
    },
    "table": {
      name: "table", // 表格名称
      jsxcolumns: [],
    },
    filter: [
      {
        id: "workNo", // 必填; 唯一标识
        component: "InputFormField",  // 必填; 组件类型
        props: {
          jsxname: "workNo",
          jsxlabel: "工号",
        }
      },
      {
        id: "date",
        component: "DateFormField",
        props: {
          jsxname: "date",
          jsxlabel: "时间",
        },
        formatter: function (value, Formatter) {
          return Formatter.date(value, 'YYYY-MM-DD');
        }
      },
      {
        id: "search",
        component: "Button",
        props: {
          text: '搜索',
        },
        event: {
          type: 'onClick',
          function: 'search',
          url: "//xxx.com/queryData.json",
        }
      },
      {
        id: "ButtonGroupFormField1",
        component: "ButtonGroupFormField",
      },
    ],
    filterLayout: [
      { formRow: ["workNo","date",{ id: "ButtonGroupFormField1", children: ["search"] }] },
    ],
    filterCustomColumn:{
      url: "//xxx.com/queryField.json"
    }
  });
  report.render();
</script>

关键是filterCustomColumn字段,指定自定义列信息的url。
//xxx.com/queryField.json返回的结构是

{
  "content": [{
    "categoryName": "职务信息",
    "list": [{
      "key": "company_no",
      "value": "公司"
    }, {
      "key": "location_country_no",
      "value": "签约公司国家"
    }, {
      "key": "dept_no",
      "value": "部门"
    }, {
      "key": "bu_no",
      "value": "BU"
    }, {
      "key": "location_no",
      "value": "工作地点"
    }, {
      "key": "job_level",
      "value": "层级"
    }, {
      "key": "corp_no",
      "value": "CORP"
    }]
  }],
  "errorCode": "",
  "errorMsg": "",
  "success": true
}

以后版本会允许结构自定义。
页面的样子

基础库

本项目基于Uxcore构建。

项目规划

2017-10-30到2017-11-03

  • 完成接口决定展现表格列功能和columnPicker功能。
  • 页面加载时根据url参数,赋予查询组件值。

2017-11-6到2017-11-10

  • 讨论template功能规划,用户可挑选模板快速生成报表schema。
  • 增加表格增删改功能。

2017-11-13到2017-11-17

  • 讨论theme功能规划
  • 谈论metadata功能规划(允许用户自定义通信结构)

未来版

通过语音识别技术和自然语言处理技术生成查询条件请求,获取报表查询结果。(即将实现)
除了阿里郎认证,新增人脸识别,声纹识别。(待实现)

项目实践感受

几个事实:

  • 后端比前端更懂业务。
    因为业务逻辑,业务所需数据之间的关系都是后端来确定。
    前端能做的就是,提高用户在人机交互过程中的便利。
    帮助后端提效。这里的提效是指:
    在可预测的需求变动/新需求,提供便捷的约定,使得一个需求后端能快速实现前端部分。
  • 后端可能比业务方更懂业务。
    后端实现了整个业务运转,所以知道业务哪个部分最复杂,以及部分业务需求的合理性。

报表本质

业务需要一些数据,通知后端去写SQL语句查询数据库,并要后端把查到的数据格式化返回给业务。
需要的次数多了,后端嫌烦,但又不能直接开放查询。
于是通过报表页面来满足这个需求。