667 lines
24 KiB
JavaScript
Raw Normal View History

class InterfaceDataTable extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.data = [];
this.filteredData = [];
this.selectedRows = new Set();
this.searchKeyword = '';
2025-05-07 13:46:48 +08:00
this.filters = {
planeName: '',
2025-05-07 13:46:48 +08:00
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();
}
2025-05-07 13:46:48 +08:00
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');
2025-05-07 13:46:48 +08:00
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);
}
});
});
2025-05-07 13:46:48 +08:00
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: '',
2025-05-07 13:46:48 +08:00
ataName: '',
structName: ''
};
// 恢复原始数据
this.filteredData = [...this.data];
2025-05-07 13:46:48 +08:00
// 重新渲染表格
this.render();
});
// 监听高级搜索事件
this.addEventListener('advanced-search', async (e) => {
this.filters = e.detail;
await this.filterData();
});
2025-05-07 13:46:48 +08:00
// 添加分页事件监听器
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');
2025-05-07 13:46:48 +08:00
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();
});
}
}
2025-05-07 13:46:48 +08:00
// 防抖函数
debounce(func, wait) {
return (...args) => {
if (this.filterTimeout) {
clearTimeout(this.filterTimeout);
}
this.filterTimeout = setTimeout(() => {
func.apply(this, args);
this.filterTimeout = null;
}, wait);
};
}
2025-05-07 13:46:48 +08:00
async filterData() {
if (this.isLoading) return;
this.setLoading(true);
try {
await new Promise(resolve => {
if (this.filterTimeout) {
clearTimeout(this.filterTimeout);
}
2025-05-07 13:46:48 +08:00
this.filterTimeout = setTimeout(() => {
requestAnimationFrame(() => {
// 首先根据高级搜索条件过滤
let filtered = [...this.data];
if (this.filters.planeName) {
2025-05-07 13:46:48 +08:00
filtered = filtered.filter(item =>
item.PlaneName === this.filters.planeName
2025-05-07 13:46:48 +08:00
);
}
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
);
}
2025-05-07 13:46:48 +08:00
// 然后根据搜索关键词过滤
if (this.searchKeyword) {
this.filteredData = filtered.filter(item =>
item.InterfaceName.toLowerCase().includes(this.searchKeyword)
);
} else {
this.filteredData = filtered;
}
2025-05-07 13:46:48 +08:00
this.currentPage = 1; // 重置到第一页
this.render();
resolve();
});
}, 300);
});
} finally {
this.setLoading(false);
}
}
2025-05-07 13:46:48 +08:00
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];
2025-05-07 13:46:48 +08:00
this.currentPage = 1;
this.render();
} finally {
this.setLoading(false);
}
}
2025-05-07 13:46:48 +08:00
getSelectedRows() {
return Array.from(this.selectedRows).map(index => this.filteredData[index]);
}
2025-05-07 13:46:48 +08:00
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';
}
2025-05-07 13:46:48 +08:00
getTotalPages() {
return Math.ceil(this.filteredData.length / this.pageSize);
}
2025-05-07 13:46:48 +08:00
getCurrentPageData() {
const start = (this.currentPage - 1) * this.pageSize;
return this.filteredData.slice(start, start + this.pageSize);
2025-05-07 13:46:48 +08:00
}
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>
2025-05-07 13:46:48 +08:00
.data-table {
width: 100%;
2025-05-07 13:46:48 +08:00
border-collapse: collapse;
margin-top: 10px;
table-layout: fixed;
position: relative;
}
2025-05-07 13:46:48 +08:00
.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);
}
2025-05-07 13:46:48 +08:00
.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;
2025-05-07 13:46:48 +08:00
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
2025-05-07 13:46:48 +08:00
.data-table th {
background-color: #f5f5f5;
font-weight: bold;
}
2025-05-07 13:46:48 +08:00
.data-table tr:nth-child(even) {
background-color: #f9f9f9;
}
2025-05-07 13:46:48 +08:00
.data-table tr:hover {
background-color: #f0f0f0;
}
.checkbox-cell {
width: 20px;
text-align: center;
}
.plane-cell {
2025-05-07 13:46:48 +08:00
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;
2025-05-07 13:46:48 +08:00
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;
}
2025-05-07 13:46:48 +08:00
.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;
2025-05-07 13:46:48 +08:00
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>
2025-05-07 13:46:48 +08:00
<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>
2025-05-07 13:46:48 +08:00
<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>
2025-05-07 13:46:48 +08:00
<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>
2025-05-07 13:46:48 +08:00
</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>
2025-05-07 13:46:48 +08:00
</div>
`;
2025-05-07 13:46:48 +08:00
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();
}
2025-05-07 13:46:48 +08:00
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) {
2025-05-07 13:46:48 +08:00
this.selectedRows.add(index);
} else {
2025-05-07 13:46:48 +08:00
this.selectedRows.delete(index);
}
2025-05-07 13:46:48 +08:00
if (selectAllCheckbox) {
selectAllCheckbox.checked = this.selectedRows.size === rowCheckboxes.length;
}
};
this.addEventListenerWithCleanup(checkbox, 'change', checkboxHandler);
});
2025-05-07 13:46:48 +08:00
// 编辑按钮事件
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: '',
2025-05-07 13:46:48 +08:00
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);