Я пытаюсь создать стандартизированную систему таблиц для нескольких представлений в моем приложении. Дизайнер, не обращая внимания на процесс, решил, что для некоторых из них на столе должны быть два заголовка. Проблема тогда становится:
Каков наилучший способ добавить второй заголовок в таблицу, размер которого будет соответствовать размеру столбцов?
Таблица содержит ряд строк и столбцов. Но в таблице есть возможность скрывать и показывать столбцы. Мне нужно, чтобы новый заголовок изменял размеры всякий раз, когда я прячу другой столбец, и скрывал себя, если все столбцы под ним скрыты.
Вот содержимое компонента:
<template>
<!-- Basic table. Adapt it's content and size based on the props received -->
<div class="table-content">
<a>
<!-- export table for Excel -->
<JsonExcel :data="sortedContent" style="width: 50px;">
<i class="fa fa-file-excel"></i>
</JsonExcel>
</a>
<!-- bouton pour afficher le panneau des settings -->
<button @click="togglePanel()">settings</button>
<table class="c-base-table" :class="tableName">
<!-- Opening table -->
<thead>
<!-- Header table -->
<tr>
<!-- Show columns titles -->
<th
v-for="key in columns"
@click="sortBy(key)"
:class="[
columnsShown.includes(key) ? '' : 'hidden-col',
key,
{active: sortKey == key}
]"
:key="key"
>
{{ columnsNames[key] | capitalize }}
<span
class="arrow"
:class="sortOrders[key] > 0 ? 'asc' : 'dsc'"
></span>
</th>
</tr>
</thead>
<tbody>
<!-- table content -->
<tr v-for="entry in sortedContent" :key="entry.id">
<!-- content sorted depending on the chosen column -->
<td
v-for="key in columns"
:class="[columnsShown.includes(key) ? '' : 'hidden-col', key]"
:key="entry.id + key"
>
{{ entry[key] | limitDecimal }}
</td>
</tr>
<tr v-if="hasTotal">
<!-- if an array called "columnToTotal" is given, it will calculate the total of the chosen columns -->
<td
v-for="key in columns"
:class="[columnsShown.includes(key) ? '' : 'hidden-col', key]"
:key="key"
>
<div v-if="columnsToTotal.includes(key)">
{{ sumColumn[key] }}
</div>
</td>
</tr>
</tbody>
</table>
<!-- If there are more than [rowPerPage] row in the table, start the pagination -->
<div v-if="listLength > rowPerPage">
<Pagination
@changePage="changePage"
:totalNumPages="totalNumPages"
:numPage="numPage"
></Pagination>
</div>
<!-- settings -->
<div class="panel-config" v-show="panelIsShown">
<ul>
<!-- list of columns with a checkbox to show/hide that column -->
<li v-for="key in columns" :class="key" :key="key">
<input
type="checkbox"
:id="key"
:value="key"
v-model="columnsShown"
/>
{{ columnsNames[key] | capitalize }}
</li>
</ul>
<!-- If asked, it will show a set of datepickers to use update the infos -->
<div v-if="toggleDate" id="dateSettings">
<Datepicker v-model="beginDate"></Datepicker>
<Datepicker v-model="endDate"></Datepicker>
<button @click="updateContent">update</button>
</div>
<hr />
<slot></slot>
</div>
</div>
</template>
<script>
// Imports
import {isNumber} from 'util';
import Datepicker from 'gso-datepicker';
import JsonExcel from 'vue-json-excel';
import Pagination from './pagination.vue';
export default {
name: 'baseTable',
components: {
JsonExcel,
Pagination,
Datepicker
},
filters: {
// capitalize the 1st letter
capitalize: function(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
},
// limit value to 2 decimal IF it is a decimal number
limitDecimal: function(value) {
if (isNumber(value) && value !== Math.floor(value)) {
return parseFloat(value).toFixed(2);
}
return value;
}
},
// parameters received by the component
props: [
'columns',
'tableContent',
'tableName',
'columnsToTotal',
'columnsNames',
'columnsShown',
'toggleDate'
],
data: function() {
var sortOrders = {};
this.columns.forEach(function(key) {
sortOrders[key] = 1;
});
return {
// initialization
sortKey: '',
sortOrders: sortOrders,
panelIsShown: false,
beginDate: new Date(),
endDate: new Date(),
numPage: 1, // current page for pagination
rowPerPage: 20 // max number of row per page
};
},
computed: {
// Sorted content
sortedContent: function() {
var sortKey = this.sortKey;
var order = this.sortOrders[sortKey] || 1;
var tableContent = this.tableContent;
if (sortKey) {
tableContent = tableContent.slice().sort(function(a, b) {
a = a[sortKey];
b = b[sortKey];
return (a === b ? 0 : a > b ? 1 : -1) * order;
});
}
tableContent = tableContent.slice(
(this.numPage - 1) * this.rowPerPage,
this.numPage * this.rowPerPage
);
return tableContent;
},
// calculate totals of selected columns
sumColumn: function() {
const sumTot = [];
const sortedContent = this.sortedContent;
this.columnsToTotal.forEach(function(column) {
sumTot[column] = sortedContent.reduce(function(sum, item) {
return sum + item[column];
}, 0);
});
return sumTot;
},
// check if making total is necessary
hasTotal: function() {
return this.columnsToTotal !== undefined;
},
// check if columns have a name
hasNames: function() {
return this.columnsNames !== undefined;
},
// calculate the number of rows
listLength: function() {
return this.tableContent.length;
},
// calculate the number of page required for these rows
totalNumPages: function() {
return Math.ceil(this.listLength / this.rowPerPage);
}
},
watch: {
columns: function() {
var sortOrders = {};
this.columns.forEach(function(key) {
sortOrders[key] = 1;
});
this.sortOrders = sortOrders;
}
},
methods: {
// Sorting of the table
sortBy: function(key) {
this.sortKey = key;
if (this.sortOrders[key] === undefined) {
this.sortOrders[key] = 1;
}
this.sortOrders[key] = this.sortOrders[key] * -1;
},
// hide/show settings
togglePanel: function() {
this.panelIsShown = !this.panelIsShown;
},
// send beginDate and endDate to parent to update the content
updateContent: function() {
var beginDate = this.beginDate.toISOString().split('T')[0];
var endDate = this.endDate.toISOString().split('T')[0];
this.$emit('updateContent', beginDate, endDate);
},
// change page number
changePage: function(numPage) {
this.numPage = numPage;
}
}
};
</script>
Например, если я отправлю следующий контент для заголовка:
columns: [
'agentName',
'employersAmount',
'contractsAmount',
'contractsAmountPrestaWeb',
'contractsAmountPresta',
'contractsAmountPrestaLight',
'contractsAmountPaper',
'employersAmountPrestaWeb',
'employersAmountPresta',
'employersAmountPrestaLight',
'employersAmountPaper',
'contractsPercentPrestaWeb',
'contractsPercentPresta',
'contractsPercentPrestaLight',
'contractsPercentPaper',
'employerPercentPrestaWeb',
'employerPercentPresta',
'employerPercentPrestaLight',
'employerPercentPapier',
'officeName'
]
columnsNames: {
agentName: 'Gestionnaire',
employersAmount: '# Dossiers',
contractsAmount: '# Contrats',
contractsAmountPrestaWeb: '# Contrats PW',
contractsAmountPresta: '# Contrats PW',
contractsAmountPrestaLight: '# Contrats PL',
contractsAmountPaper: '# Contrats pa',
employersAmountPrestaWeb: '# Dossiers PW',
employersAmountPresta: '# Dossiers Pr',
employersAmountPrestaLight: '# Dossiers PL',
employersAmountPaper: '# Dossiers pa',
contractsPercentPrestaWeb: '% Contrats PW',
contractsPercentPresta: '% Contrats Pr',
contractsPercentPrestaLight: '% Contrats PL',
contractsPercentPaper: '% Contrats pa',
employerPercentPrestaWeb: '% Dossiers PW',
employerPercentPresta: '% Dossiers Pr',
employerPercentPrestaLight: '% Dossiers PL',
employerPercentPapier: '% Dossiers pa',
officeName: 'Bureau'
}
Я получаю следующий результат:
<table>
<tr>
<th>Gestionnaire</th>
<th># Dossiers</th>
<th># Contrats</th>
<th># Contrats PW</th>
<th># Contrats PL</th>
<th># Contrats Pr</th>
<th># Contrats Pa</th>
<th># Dossiers PW</th>
<th># Dossiers PL</th>
<th># Dossiers Pr</th>
<th># Dossiers Pa</th>
<th>% Contrats PW</th>
<th>% Contrats PL</th>
<th>% Contrats Pr</th>
<th>% Contrats Pa</th>
<th>% Dossiers PW</th>
<th>% Dossiers PL</th>
<th>% Dossiers Pr</th>
<th>% Dossiers Pa</th>
<th>Bureau</th>
</tr>
</table>
Хотя я бы хотел что-то вроде этого:
<table>
<tr>
<th rowspan="2">Gestionnaire</th>
<th colspan="9">Dossiers</th>
<th colspan="9">Contrats</th>
<th rowspan="2">Bureau</th>
</tr>
<tr>
<th>total</th>
<th># PW</th>
<th># PL</th>
<th># Pr</th>
<th># Pa</th>
<th>% PW</th>
<th>% PL</th>
<th>% Pr</th>
<th>% Pa</th>
<th>total</th>
<th># PW</th>
<th># PL</th>
<th># Pr</th>
<th># Pa</th>
<th>% PW</th>
<th>% PL</th>
<th>% Pr</th>
<th>% Pa</th>
</tr>
</table>
Зная, что я могу (через массив columnsShown) скрыть некоторые столбцы, и что мне потребуется обновление colspan для соответствия количеству соответствующих столбцов.
Что было бы лучшим способом изменить мой код для этого? Мне все еще нужно, чтобы таблица выглядела как первая, но, возможно, изменив некоторые реквизиты или фактически отправив несколько реквизитов, измените поведение, чтобы иметь двойной заголовок. Я думал о добавлении новой опоры, как
columnsContainer: [
Files:{
'employersAmount',
'employersAmountPrestaWeb',
'employersAmountPresta',
'employersAmountPrestaLight',
'employersAmountPaper','employerPercentPrestaWeb',
'employerPercentPresta',
'employerPercentPrestaLight',
'employerPercentPapier'
},
Contracts:{
'contractsAmount',
'contractsAmountPrestaWeb',
'contractsAmountPresta',
'contractsAmountPrestaLight',
'contractsAmountPaper',
'contractsPercentPrestaWeb',
'contractsPercentPresta',
'contractsPercentPrestaLight',
'contractsPercentPaper',
}
]
и, если он пустой, создайте простой заголовок, а если он что-то заполнен, посмотрите на ключ и организуйте заголовок на основе этого ключа.