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 // const getDefaultTableMatrix = () => [ 8 // const getDefaultTableMatrix = () => [
113 // [1, 2, 3, 4], 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,10 +14,68 @@ import LbpBgMusic from &#39;../components/plugins/lbp-bg-music&#39;
14 import LbpNoticeBar from '../components/plugins/lbp-notice-bar' 14 import LbpNoticeBar from '../components/plugins/lbp-notice-bar'
15 import LbpRate from '../components/plugins/lbp-rate' 15 import LbpRate from '../components/plugins/lbp-rate'
16 import LbpQQMap from '../components/plugins/lbp-qq-map/src' 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 // import LbpTabs from '../components/plugins/lbp-tabs' 19 // import LbpTabs from '../components/plugins/lbp-tabs'
18 20
19 export const pluginsList = [ 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 title: '公告', 79 title: '公告',
22 i18nTitle: { 80 i18nTitle: {
23 'en-US': 'Notice-Bar', 81 'en-US': 'Notice-Bar',
@@ -183,7 +241,43 @@ export const pluginsList = [ @@ -183,7 +241,43 @@ export const pluginsList = [
183 component: LbpBgMusic, 241 component: LbpBgMusic,
184 visible: true, 242 visible: true,
185 name: LbpBgMusic.name 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 export default { 283 export default {