667 lines
24 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class InterfaceDataTable extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.data = [];
this.filteredData = [];
this.selectedRows = new Set();
this.searchKeyword = '';
this.filters = {
planeName: '',
ataName: '',
structName: ''
};
this.pageSize = 10;
this.currentPage = 1;
this.isLoading = false;
this.filterTimeout = null;
this.eventListeners = new Map(); // 存储事件监听器
this.debouncedFilter = this.debounce(this.filterData.bind(this), 300);
}
connectedCallback() {
this.render();
this.addEventListeners();
}
addEventListeners() {
const selectAllCheckbox = this.shadowRoot.querySelector('#selectAll');
const rowCheckboxes = this.shadowRoot.querySelectorAll('.row-checkbox');
const editButtons = this.shadowRoot.querySelectorAll('.edit-btn');
const deleteButtons = this.shadowRoot.querySelectorAll('.delete-btn');
selectAllCheckbox.addEventListener('change', (e) => {
const isChecked = e.target.checked;
rowCheckboxes.forEach(checkbox => {
checkbox.checked = isChecked;
const index = parseInt(checkbox.dataset.index);
if (isChecked) {
this.selectedRows.add(index);
} else {
this.selectedRows.delete(index);
}
});
});
rowCheckboxes.forEach(checkbox => {
checkbox.addEventListener('change', (e) => {
const index = parseInt(e.target.dataset.index);
if (e.target.checked) {
this.selectedRows.add(index);
} else {
this.selectedRows.delete(index);
}
selectAllCheckbox.checked = this.selectedRows.size === rowCheckboxes.length;
});
});
editButtons.forEach(button => {
button.addEventListener('click', (e) => {
const index = parseInt(e.target.dataset.index);
const item = this.filteredData[index];
this.dispatchEvent(new CustomEvent('edit', {
detail: item,
bubbles: true,
composed: true
}));
});
});
deleteButtons.forEach(button => {
button.addEventListener('click', (e) => {
const index = parseInt(e.target.dataset.index);
const item = this.filteredData[index];
if (confirm(`确定要删除接口 "${item.InterfaceName}" 吗?`)) {
this.dispatchEvent(new CustomEvent('delete', {
detail: item,
bubbles: true,
composed: true
}));
}
});
});
// 监听搜索事件
this.addEventListener('search', async (e) => {
this.searchKeyword = e.detail.keyword.toLowerCase();
await this.filterData();
});
// 监听重置搜索事件
this.addEventListener('reset-search', async () => {
// 重置所有筛选条件
this.searchKeyword = '';
this.filters = {
planeName: '',
ataName: '',
structName: ''
};
// 恢复原始数据
this.filteredData = [...this.data];
// 重新渲染表格
this.render();
});
// 监听高级搜索事件
this.addEventListener('advanced-search', async (e) => {
this.filters = e.detail;
await this.filterData();
});
// 添加分页事件监听器
const firstPageBtn = this.shadowRoot.querySelector('#firstPage');
const prevPageBtn = this.shadowRoot.querySelector('#prevPage');
const nextPageBtn = this.shadowRoot.querySelector('#nextPage');
const lastPageBtn = this.shadowRoot.querySelector('#lastPage');
const pageSizeSelect = this.shadowRoot.querySelector('#pageSize');
if (firstPageBtn) {
firstPageBtn.addEventListener('click', () => this.setPage(1));
}
if (prevPageBtn) {
prevPageBtn.addEventListener('click', () => this.setPage(this.currentPage - 1));
}
if (nextPageBtn) {
nextPageBtn.addEventListener('click', () => this.setPage(this.currentPage + 1));
}
if (lastPageBtn) {
lastPageBtn.addEventListener('click', () => this.setPage(this.getTotalPages()));
}
if (pageSizeSelect) {
pageSizeSelect.addEventListener('change', (e) => {
this.pageSize = parseInt(e.target.value);
this.currentPage = 1; // 重置到第一页
this.render();
});
}
}
// 防抖函数
debounce(func, wait) {
return (...args) => {
if (this.filterTimeout) {
clearTimeout(this.filterTimeout);
}
this.filterTimeout = setTimeout(() => {
func.apply(this, args);
this.filterTimeout = null;
}, wait);
};
}
async filterData() {
if (this.isLoading) return;
this.setLoading(true);
try {
await new Promise(resolve => {
if (this.filterTimeout) {
clearTimeout(this.filterTimeout);
}
this.filterTimeout = setTimeout(() => {
requestAnimationFrame(() => {
// 首先根据高级搜索条件过滤
let filtered = [...this.data];
if (this.filters.planeName) {
filtered = filtered.filter(item =>
item.PlaneName === this.filters.planeName
);
}
if (this.filters.ataName) {
filtered = filtered.filter(item =>
item.ATAName === this.filters.ataName
);
}
if (this.filters.structName) {
filtered = filtered.filter(item =>
item.ModelStructName === this.filters.structName
);
}
// 然后根据搜索关键词过滤
if (this.searchKeyword) {
this.filteredData = filtered.filter(item =>
item.InterfaceName.toLowerCase().includes(this.searchKeyword)
);
} else {
this.filteredData = filtered;
}
this.currentPage = 1; // 重置到第一页
this.render();
resolve();
});
}, 300);
});
} finally {
this.setLoading(false);
}
}
async setData(data) {
this.setLoading(true);
try {
// 清理旧数据
this.data = [];
this.filteredData = [];
this.selectedRows.clear();
// 设置新数据
this.data = data.map((item, index) => ({
...item,
_displayIndex: index
}));
this.filteredData = [...this.data];
this.currentPage = 1;
this.render();
} finally {
this.setLoading(false);
}
}
getSelectedRows() {
return Array.from(this.selectedRows).map(index => this.filteredData[index]);
}
formatArraySize(item) {
if (item.InterfaceIsArray === 1) {
if (item.InterfaceArraySize_2 && item.InterfaceArraySize_2 > 1) {
return `${item.InterfaceArraySize_1}×${item.InterfaceArraySize_2}`;
}
return `${item.InterfaceArraySize_1}`;
}
return '1';
}
getTotalPages() {
return Math.ceil(this.filteredData.length / this.pageSize);
}
getCurrentPageData() {
const start = (this.currentPage - 1) * this.pageSize;
return this.filteredData.slice(start, start + this.pageSize);
}
setPage(page) {
if (page < 1 || page > this.getTotalPages()) return;
this.currentPage = page;
this.render();
}
setLoading(loading) {
this.isLoading = loading;
this.render();
}
render() {
this.shadowRoot.innerHTML = `
<style>
.data-table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
table-layout: fixed;
position: relative;
}
.loading-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.9);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
backdrop-filter: blur(2px);
}
.loading-spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.data-table th,
.data-table td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.data-table th {
background-color: #f5f5f5;
font-weight: bold;
}
.data-table tr:nth-child(even) {
background-color: #f9f9f9;
}
.data-table tr:hover {
background-color: #f0f0f0;
}
.checkbox-cell {
width: 20px;
text-align: center;
}
.plane-cell {
width: 60px;
}
.ata-cell {
width: 60px;
}
.struct-cell {
width: 150px;
}
.interface-cell {
width: 220px;
}
.type-cell {
width: 100px;
}
.size-cell {
width: 60px;
}
.notes-cell {
width: 220px;
}
.action-cell {
width: 80px;
}
.action-btn {
padding: 4px 8px;
margin: 0 4px;
border: none;
border-radius: 4px;
cursor: pointer;
outline: none;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
box-shadow: none;
}
.edit-btn {
background-color: #4CAF50;
color: white;
}
.delete-btn {
background-color: #f44336;
color: white;
}
.action-btn:hover {
opacity: 0.9;
}
.action-btn:focus {
outline: none;
box-shadow: none;
}
.action-btn:active {
outline: none;
box-shadow: none;
}
.pagination {
display: flex;
justify-content: center;
align-items: center;
margin-top: 20px;
gap: 10px;
}
.pagination button {
padding: 5px 10px;
border: 1px solid #ddd;
background-color: white;
cursor: pointer;
border-radius: 4px;
}
.pagination button:hover {
background-color: #f0f0f0;
}
.pagination button:disabled {
background-color: #f5f5f5;
cursor: not-allowed;
}
.pagination .page-info {
margin: 0 10px;
}
.pagination .page-size-select {
margin-left: 10px;
padding: 5px;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>
<div style="position: relative;">
<table class="data-table">
<thead>
<tr>
<th class="checkbox-cell">
<input type="checkbox" id="selectAll">
</th>
<th class="plane-cell">机型</th>
<th class="ata-cell">ATA章节</th>
<th class="struct-cell">接口结构体名</th>
<th class="interface-cell">接口名称</th>
<th class="type-cell">数据类型</th>
<th class="size-cell">数据大小</th>
<th class="notes-cell">备注</th>
<th class="action-cell">操作</th>
</tr>
</thead>
<tbody>
${this.getCurrentPageData().map((item) => `
<tr>
<td class="checkbox-cell">
<input type="checkbox" class="row-checkbox" data-index="${item._displayIndex}">
</td>
<td>${item.PlaneName || ''}</td>
<td>${item.ATAName || ''}</td>
<td>${item.ModelStructName || ''}</td>
<td>${item.InterfaceName || ''}</td>
<td>${item.InterfaceType || ''}</td>
<td>${this.formatArraySize(item)}</td>
<td>${item.InterfaceNotes || ''}</td>
<td class="action-cell">
<button class="action-btn edit-btn" data-index="${item._displayIndex}">编辑</button>
<button class="action-btn delete-btn" data-index="${item._displayIndex}">删除</button>
</td>
</tr>
`).join('')}
</tbody>
</table>
${this.isLoading ? `
<div class="loading-overlay">
<div class="loading-spinner"></div>
</div>
` : ''}
<div class="pagination">
<button id="firstPage" ${this.currentPage === 1 ? 'disabled' : ''}>首页</button>
<button id="prevPage" ${this.currentPage === 1 ? 'disabled' : ''}>上一页</button>
<span class="page-info">第 ${this.currentPage} 页 / 共 ${this.getTotalPages()} 页</span>
<button id="nextPage" ${this.currentPage === this.getTotalPages() ? 'disabled' : ''}>下一页</button>
<button id="lastPage" ${this.currentPage === this.getTotalPages() ? 'disabled' : ''}>末页</button>
<select class="page-size-select" id="pageSize">
<option value="10" ${this.pageSize === 10 ? 'selected' : ''}>10条/页</option>
<option value="20" ${this.pageSize === 20 ? 'selected' : ''}>20条/页</option>
<option value="50" ${this.pageSize === 50 ? 'selected' : ''}>50条/页</option>
<option value="100" ${this.pageSize === 100 ? 'selected' : ''}>100条/页</option>
</select>
</div>
</div>
`;
this.bindEventListeners();
}
// 修改事件监听器的添加方式
addEventListenerWithCleanup(element, event, handler) {
if (!this.eventListeners.has(element)) {
this.eventListeners.set(element, new Map());
}
const elementListeners = this.eventListeners.get(element);
// 如果已经存在相同的事件监听器,先移除
if (elementListeners.has(event)) {
const handlers = elementListeners.get(event);
handlers.forEach(h => element.removeEventListener(event, h));
handlers.clear();
} else {
elementListeners.set(event, new Set());
}
elementListeners.get(event).add(handler);
element.addEventListener(event, handler);
}
// 清理事件监听器
cleanupEventListeners() {
this.eventListeners.forEach((elementListeners, element) => {
elementListeners.forEach((handlers, event) => {
handlers.forEach(handler => {
element.removeEventListener(event, handler);
});
});
});
this.eventListeners.clear();
}
bindEventListeners() {
// 清理之前的事件监听器
this.cleanupEventListeners();
const selectAllCheckbox = this.shadowRoot.querySelector('#selectAll');
const rowCheckboxes = this.shadowRoot.querySelectorAll('.row-checkbox');
const editButtons = this.shadowRoot.querySelectorAll('.edit-btn');
const deleteButtons = this.shadowRoot.querySelectorAll('.delete-btn');
// 全选复选框事件
if (selectAllCheckbox) {
const selectAllHandler = (e) => {
const isChecked = e.target.checked;
rowCheckboxes.forEach(checkbox => {
checkbox.checked = isChecked;
const index = parseInt(checkbox.dataset.index);
if (isChecked) {
this.selectedRows.add(index);
} else {
this.selectedRows.delete(index);
}
});
};
this.addEventListenerWithCleanup(selectAllCheckbox, 'change', selectAllHandler);
}
// 行复选框事件
rowCheckboxes.forEach(checkbox => {
const checkboxHandler = (e) => {
const index = parseInt(e.target.dataset.index);
if (e.target.checked) {
this.selectedRows.add(index);
} else {
this.selectedRows.delete(index);
}
if (selectAllCheckbox) {
selectAllCheckbox.checked = this.selectedRows.size === rowCheckboxes.length;
}
};
this.addEventListenerWithCleanup(checkbox, 'change', checkboxHandler);
});
// 编辑按钮事件
editButtons.forEach(button => {
const editHandler = (e) => {
const index = parseInt(e.target.dataset.index);
const item = this.filteredData[index];
if (item) {
this.dispatchEvent(new CustomEvent('edit', {
detail: { ...item },
bubbles: true,
composed: true
}));
}
};
this.addEventListenerWithCleanup(button, 'click', editHandler);
});
// 删除按钮事件
deleteButtons.forEach(button => {
const deleteHandler = (e) => {
const index = parseInt(e.target.dataset.index);
const item = this.filteredData[index];
if (item && confirm(`确定要删除接口 "${item.InterfaceName}" 吗?`)) {
this.dispatchEvent(new CustomEvent('delete', {
detail: { ...item },
bubbles: true,
composed: true
}));
}
};
this.addEventListenerWithCleanup(button, 'click', deleteHandler);
});
// 搜索事件
const searchHandler = async (e) => {
this.searchKeyword = e.detail.keyword.toLowerCase();
this.setLoading(true);
await this.debouncedFilter();
};
this.addEventListenerWithCleanup(this, 'search', searchHandler);
// 重置搜索事件
const resetSearchHandler = async () => {
this.searchKeyword = '';
this.filters = {
planeName: '',
ataName: '',
structName: ''
};
this.filteredData = [...this.data];
this.render();
};
this.addEventListenerWithCleanup(this, 'reset-search', resetSearchHandler);
// 高级搜索事件
const advancedSearchHandler = async (e) => {
this.filters = e.detail;
this.setLoading(true);
await this.debouncedFilter();
};
this.addEventListenerWithCleanup(this, 'advanced-search', advancedSearchHandler);
// 分页按钮事件
const firstPageBtn = this.shadowRoot.querySelector('#firstPage');
const prevPageBtn = this.shadowRoot.querySelector('#prevPage');
const nextPageBtn = this.shadowRoot.querySelector('#nextPage');
const lastPageBtn = this.shadowRoot.querySelector('#lastPage');
const pageSizeSelect = this.shadowRoot.querySelector('#pageSize');
if (firstPageBtn) {
this.addEventListenerWithCleanup(firstPageBtn, 'click', () => this.setPage(1));
}
if (prevPageBtn) {
this.addEventListenerWithCleanup(prevPageBtn, 'click', () => this.setPage(this.currentPage - 1));
}
if (nextPageBtn) {
this.addEventListenerWithCleanup(nextPageBtn, 'click', () => this.setPage(this.currentPage + 1));
}
if (lastPageBtn) {
this.addEventListenerWithCleanup(lastPageBtn, 'click', () => this.setPage(this.getTotalPages()));
}
if (pageSizeSelect) {
this.addEventListenerWithCleanup(pageSizeSelect, 'change', (e) => {
this.pageSize = parseInt(e.target.value);
this.currentPage = 1;
this.render();
});
}
}
// 组件销毁时清理
disconnectedCallback() {
if (this.filterTimeout) {
clearTimeout(this.filterTimeout);
this.filterTimeout = null;
}
this.cleanupEventListeners();
this.data = [];
this.filteredData = [];
this.selectedRows.clear();
}
}
customElements.define('interface-data-table', InterfaceDataTable);