Commit 7b6ce8ec78e5b9ea349b132d8ee1560a3cd103b3

Authored by ly525
1 parent 7cf954cf

feat(component): !#zh: 增加表格组件 !#: add table component

front-end/h5/src/components/core/support/excel.js
1   -import Spreadsheet from 'x-data-spreadsheet'
2   -
3 1 /**
4   - *
5   - declare module ExcelRows {
6   - export interface cell {
7   - text: string;
8   - }
9   - export interface Cells {
10   - 0: cell;
11   - 1: cell;
12   - 2: cell;
13   - }
14   - export interface ExcelRows {
15   - cells: Cells;
16   - }
17   -}
  2 + * 后续学习资料:https://github.com/myliang/x-spreadsheet/issues/159
18 3 */
19 4  
20   -/**
21   - *
22   - BinaryMatrix = [
23   - [any, any, any, ...],
24   - [any, any, any, ...],
25   - [any, any, any, ...],
26   - ]
27   -
28   - ExcelDataType = [
29   - {
30   - cells: {
31   - 0: { text: any },
32   - 1: { text: any },
33   - 2: { text: any }
34   - }
35   - },
36   - {
37   - cells: {
38   - 0: { text: any },
39   - 1: { text: any },
40   - 2: { text: any }
41   - }
42   - },
43   - ]
44   - */
45   -
46   -class Parser {
47   - /**
48   - *
49   - * @param {*} dataset ExcelDataType
50   - */
51   - static dataset2excel (dataset) {
52   - return dataset.map(item => ({
53   - cells: {
54   - 0: { text: item.x },
55   - 1: { text: item.y },
56   - 2: { text: item.s }
57   - }
58   - }))
59   - }
60   -
61   - /**
62   - *
63   - [
64   - [1,2,3,4],
65   - [5,6,7,8],
66   - [9,10,11,12]
67   - ]
68   - * @param {Object} BinaryMatrix
69   - * @returns {Object} ExcelDataType
70   - */
71   - static binaryMatrix2excel (binaryMatrix) {
72   - const excelData = binaryMatrix.map((row, rowIndex) => {
73   - // cells: {
74   - // 0: { text: item.x },
75   - // 1: { text: item.y },
76   - // 2: { text: item.s }
77   - // }
78   - const cells = {}
79   - row.forEach((cellValue, cellIndex) => {
80   - cells[cellIndex] = { text: cellValue }
81   - })
82   - return { cells }
83   - })
84   - return excelData
85   - }
86   -
87   - static excel2chartDataSet (excelData) {
88   - const rowsArray = Object.values(excelData.rows).filter(item => typeof item === 'object')
89   - const dataset = rowsArray.map(row => {
90   - const [x, y, s] = Object.values(row.cells).map(item => item.text)
91   - return {
92   - x: x,
93   - y: y,
94   - s: s
95   - }
96   - })
97   - return dataset
98   - }
99   -
100   - static excel2BinaryMatrix (excelData) {
101   - const rowsArray = Object.values(excelData.rows).filter(item => typeof item === 'object')
102   - const dataset = rowsArray.map(row => {
103   - // [1,2,3,4]
104   - const cells = Object.values(row.cells).map(item => item.text)
105   - return cells
106   - })
107   - console.log('dataset', dataset)
108   - return dataset
109   - }
110   -}
  5 +import Spreadsheet from 'x-data-spreadsheet'
  6 +import Parser from '../../../utils/excel-parser'
111 7  
112 8 // const getDefaultTableMatrix = () => [
113 9 // [1, 2, 3, 4],
... ...
front-end/h5/src/components/plugins/lbp-table.js 0 → 100644
  1 +// https://github.com/luban-h5-components/plugin-common-props
  2 +import PropTypes from '@luban-h5/plugin-common-props'
  3 +import { addListener as addResizeListener, removeListener } from 'resize-detector'
  4 +import './styles/table.scss'
  5 +
  6 +function sum (arr = [], key) {
  7 + return arr.map(item => item[key]).reduce((a, b) => a + b, 0)
  8 +}
  9 +
  10 +export default {
  11 + name: 'lbp-table',
  12 + extra: {
  13 + defaultStyle: {
  14 + width: 320,
  15 + height: 150
  16 + }
  17 + },
  18 + data: () => ({
  19 + mainTableWrapperEle: null,
  20 + mainTableEle: null,
  21 + fixedTableWrapperEle: null,
  22 + fixedTableEle: null
  23 + }),
  24 + props: {
  25 + theme: PropTypes.string({ defaultValue: '', label: '主题', visible: false }),
  26 + columnWidth: PropTypes.number({ label: '每列宽度(px)', defaultValue: 100 }),
  27 + freezeCount: PropTypes.number({ label: '冻结列数(px)', defaultValue: 0 }),
  28 + dataset: PropTypes.excel({
  29 + defaultValue: () => [
  30 + [ '列A', '列B', '列C'],
  31 + [ '————', '————', '————'],
  32 + [ '————', '————', '————'],
  33 + [ '————', '————', '————']
  34 + ]
  35 + })
  36 + },
  37 + watch: {
  38 + freezeCount () {
  39 + setTimeout(() => {
  40 + this.setFixedTableStyle()
  41 + }, 100)
  42 + }
  43 + },
  44 + render () {
  45 + const renderCell = cell => {
  46 + return <td><div class="cell" >{cell}</div></td>
  47 + }
  48 +
  49 + const renderTable = (tableData = [], tableClass = '', tableStyle = {}) => {
  50 + const headers = tableData.length ? tableData[0] : []
  51 + const columnsCount = headers.length
  52 + return (
  53 + <table class={tableClass} style={tableStyle}>
  54 + <colgroup>
  55 + {
  56 + [...Array(columnsCount)].map((item, i) => <col style={{ width: this.columnWidth + 'px' }} />)
  57 + }
  58 + </colgroup>
  59 + <tbody>
  60 + { tableData.map(row => <tr>{ row.map(renderCell) }</tr>) }
  61 + </tbody>
  62 + </table>
  63 + )
  64 + }
  65 +
  66 + return (
  67 + <div class={['lbp-table', this.theme]} ref="lbpTable">
  68 + <div class="main-table-wrapper">
  69 + {renderTable(this.dataset)}
  70 + </div>
  71 + <div class="fixed-table-wrapper" v-show="freezeCount">
  72 + {renderTable(this.dataset, 'left-table')}
  73 + </div>
  74 + </div>
  75 + )
  76 + },
  77 + methods: {
  78 + getFixedColsWidth () {
  79 + const tableHeaders = [].slice.apply(this.mainTableEle.querySelectorAll('tr:first-child > td'))
  80 + const freezeColsWidth = sum(tableHeaders.slice(0, +this.freezeCount), 'offsetWidth')
  81 + return freezeColsWidth
  82 + },
  83 + setFixedTableStyle () {
  84 + this.fixedTableWrapperEle.style.width = `${this.getFixedColsWidth()}px`
  85 + this.fixedTableWrapperEle.style.height = `calc(100% - ${this.mainTableWrapperEle.offsetHeight - this.mainTableWrapperEle.scrollHeight}px)`
  86 + },
  87 + setTableWidth () {
  88 + const parentWidth = this.$el.parentNode.style.width
  89 + this.fixedTableEle.style.width = this.mainTableEle.style.width = parentWidth
  90 + },
  91 + initElements () {
  92 + const root = this.$el
  93 + this.mainTableWrapperEle = root.querySelector('.main-table-wrapper')
  94 + this.mainTableEle = root.querySelector('.main-table-wrapper > table')
  95 + this.fixedTableWrapperEle = root.querySelector('.fixed-table-wrapper')
  96 + this.fixedTableEle = root.querySelector('.left-table')
  97 + }
  98 + },
  99 +
  100 + mounted () {
  101 + this.initElements()
  102 + this.setTableWidth()
  103 + this.setFixedTableStyle()
  104 + addResizeListener(this.$refs.lbpTable, () => {
  105 + this.setTableWidth()
  106 + if (this.freezeCount) {
  107 + this.setFixedTableStyle()
  108 + }
  109 + })
  110 + }
  111 +}
... ...
front-end/h5/src/components/plugins/styles/table.scss 0 → 100644
  1 +$border-color: #ebeef5;
  2 +.lbp-table {
  3 + position: relative;
  4 + overflow: hidden;
  5 +
  6 + table {
  7 + position: absolute;
  8 + table-layout: fixed;
  9 + height: 100%;
  10 + background: white;
  11 +
  12 + // 边框
  13 + td {
  14 + border-top: 2px solid $border-color;
  15 + border-left: 2px solid $border-color;
  16 + }
  17 + tr:last-child {
  18 + border-bottom: 2px solid $border-color;
  19 + border-right: 2px solid $border-color;
  20 + }
  21 +
  22 + // 表头加粗
  23 + tr:first-child {
  24 + background-color: #f6f6f6;
  25 + font-size: 13px;
  26 + font-weight: bold;
  27 + }
  28 +
  29 + // 居中对齐
  30 + td {
  31 + text-align: center;
  32 + }
  33 +
  34 + }
  35 +
  36 + .main-table-wrapper {
  37 + position: absolute;
  38 + left: 0px;
  39 + top: 0px;
  40 + overflow: auto;
  41 + width: 100%;
  42 + height: 100%;
  43 + }
  44 +
  45 + .fixed-table-wrapper {
  46 + position: absolute;
  47 + left: 0px;
  48 + top: 0px;
  49 + overflow: hidden;
  50 + }
  51 +}
  52 +
  53 +
  54 +.lbp-table-theme-stripe {
  55 + table {
  56 + tbody tr {
  57 + // 奇
  58 + &:nth-child(odd):not(:first-child) {
  59 + background-color: #f6f6f6;
  60 + }
  61 +
  62 + &:nth-child(even) {
  63 + background-color: white;
  64 + }
  65 + }
  66 + }
  67 +}
  68 +
  69 +.lbp-table-theme-light-blue {
  70 + table {
  71 + tbody tr {
  72 + &:first-child {
  73 + background-color: #edf8ff;
  74 + }
  75 + &:nth-child(odd):not(:first-child) {
  76 + background-color: #edf8ff;
  77 + }
  78 +
  79 + &:nth-child(even) {
  80 + background-color: white;
  81 + }
  82 + }
  83 + }
  84 +}
... ...
front-end/h5/src/mixins/load-plugins.js
... ... @@ -14,10 +14,68 @@ import LbpBgMusic from &#39;../components/plugins/lbp-bg-music&#39;
14 14 import LbpNoticeBar from '../components/plugins/lbp-notice-bar'
15 15 import LbpRate from '../components/plugins/lbp-rate'
16 16 import LbpQQMap from '../components/plugins/lbp-qq-map/src'
  17 +import LbpLineChart from '../components/plugins/charts/line'
  18 +import LbpTable from '../components/plugins/lbp-table'
17 19 // import LbpTabs from '../components/plugins/lbp-tabs'
18 20  
19 21 export const pluginsList = [
20 22 {
  23 + i18nTitle: {
  24 + 'en-US': 'LineChart',
  25 + 'zh-CN': '折线图'
  26 + },
  27 + title: '折线图',
  28 + icon: 'line-chart',
  29 + component: LbpLineChart,
  30 + visible: true,
  31 + name: LbpLineChart.name,
  32 + shortcutProps: {
  33 + type: 'line'
  34 + }
  35 + },
  36 + {
  37 + i18nTitle: {
  38 + 'en-US': 'LineChart',
  39 + 'zh-CN': '柱状图'
  40 + },
  41 + title: '柱状图',
  42 + icon: 'bar-chart',
  43 + component: LbpLineChart,
  44 + visible: true,
  45 + name: LbpLineChart.name,
  46 + shortcutProps: {
  47 + type: 'histogram'
  48 + }
  49 + },
  50 + {
  51 + i18nTitle: {
  52 + 'en-US': 'LineChart',
  53 + 'zh-CN': '饼状图'
  54 + },
  55 + title: '饼状图',
  56 + icon: 'pie-chart',
  57 + component: LbpLineChart,
  58 + visible: true,
  59 + name: LbpLineChart.name,
  60 + shortcutProps: {
  61 + type: 'pie'
  62 + }
  63 + },
  64 + {
  65 + i18nTitle: {
  66 + 'en-US': 'LineChart',
  67 + 'zh-CN': '漏斗图'
  68 + },
  69 + title: '漏斗图',
  70 + icon: 'filter',
  71 + component: LbpLineChart,
  72 + visible: true,
  73 + name: LbpLineChart.name,
  74 + shortcutProps: {
  75 + type: 'funnel'
  76 + }
  77 + },
  78 + {
21 79 title: '公告',
22 80 i18nTitle: {
23 81 'en-US': 'Notice-Bar',
... ... @@ -183,7 +241,43 @@ export const pluginsList = [
183 241 component: LbpBgMusic,
184 242 visible: true,
185 243 name: LbpBgMusic.name
186   - }
  244 + },
  245 + {
  246 + i18nTitle: {
  247 + 'en-US': 'Table(Default)',
  248 + 'zh-CN': '默认表格'
  249 + },
  250 + icon: 'table',
  251 + component: LbpTable,
  252 + visible: true,
  253 + name: LbpTable.name,
  254 + },
  255 + {
  256 + i18nTitle: {
  257 + 'en-US': 'Table(Stripe)',
  258 + 'zh-CN': '(斑马线)表格'
  259 + },
  260 + icon: 'table',
  261 + component: LbpTable,
  262 + visible: true,
  263 + name: LbpTable.name,
  264 + shortcutProps: {
  265 + theme: 'lbp-table-theme-stripe'
  266 + }
  267 + },
  268 + {
  269 + i18nTitle: {
  270 + 'en-US': 'Table(LightBlue)',
  271 + 'zh-CN': '(淡蓝色)表格'
  272 + },
  273 + icon: 'table',
  274 + component: LbpTable,
  275 + visible: true,
  276 + name: LbpTable.name,
  277 + shortcutProps: {
  278 + theme: 'lbp-table-theme-light-blue'
  279 + }
  280 + },
187 281 ]
188 282  
189 283 export default {
... ...