2025-04-30 14:50:27 +08:00
|
|
|
|
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 = {
|
2025-05-16 10:26:07 +08:00
|
|
|
|
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);
|
2025-04-30 14:50:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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-04-30 14:50:27 +08:00
|
|
|
|
|
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-04-30 14:50:27 +08:00
|
|
|
|
|
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 = {
|
2025-05-16 10:26:07 +08:00
|
|
|
|
planeName: '',
|
2025-05-07 13:46:48 +08:00
|
|
|
|
ataName: '',
|
|
|
|
|
structName: ''
|
|
|
|
|
};
|
|
|
|
|
// 恢复原始数据
|
2025-04-30 14:50:27 +08:00
|
|
|
|
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-04-30 14:50:27 +08:00
|
|
|
|
|
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-04-30 14:50:27 +08:00
|
|
|
|
|
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-04-30 14:50:27 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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-04-30 14:50:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
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-04-30 14:50:27 +08:00
|
|
|
|
}
|
2025-05-07 13:46:48 +08:00
|
|
|
|
|
|
|
|
|
this.filterTimeout = setTimeout(() => {
|
|
|
|
|
requestAnimationFrame(() => {
|
|
|
|
|
// 首先根据高级搜索条件过滤
|
|
|
|
|
let filtered = [...this.data];
|
|
|
|
|
|
2025-05-16 10:26:07 +08:00
|
|
|
|
if (this.filters.planeName) {
|
2025-05-07 13:46:48 +08:00
|
|
|
|
filtered = filtered.filter(item =>
|
2025-05-16 10:26:07 +08:00
|
|
|
|
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-04-30 14:50:27 +08:00
|
|
|
|
|
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-04-30 14:50:27 +08:00
|
|
|
|
|
2025-05-07 13:46:48 +08:00
|
|
|
|
this.currentPage = 1; // 重置到第一页
|
|
|
|
|
this.render();
|
|
|
|
|
resolve();
|
|
|
|
|
});
|
|
|
|
|
}, 300);
|
|
|
|
|
});
|
|
|
|
|
} finally {
|
|
|
|
|
this.setLoading(false);
|
|
|
|
|
}
|
2025-04-30 14:50:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-05-07 13:46:48 +08:00
|
|
|
|
async setData(data) {
|
|
|
|
|
this.setLoading(true);
|
|
|
|
|
try {
|
|
|
|
|
// 清理旧数据
|
|
|
|
|
this.data = [];
|
|
|
|
|
this.filteredData = [];
|
|
|
|
|
this.selectedRows.clear();
|
|
|
|
|
|
|
|
|
|
// 设置新数据
|
2025-05-16 10:26:07 +08:00
|
|
|
|
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-04-30 14:50:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-05-07 13:46:48 +08:00
|
|
|
|
getSelectedRows() {
|
|
|
|
|
return Array.from(this.selectedRows).map(index => this.filteredData[index]);
|
|
|
|
|
}
|
2025-04-30 14:50:27 +08:00
|
|
|
|
|
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-04-30 14:50:27 +08:00
|
|
|
|
|
2025-05-07 13:46:48 +08:00
|
|
|
|
getTotalPages() {
|
|
|
|
|
return Math.ceil(this.filteredData.length / this.pageSize);
|
|
|
|
|
}
|
2025-04-30 14:50:27 +08:00
|
|
|
|
|
2025-05-07 13:46:48 +08:00
|
|
|
|
getCurrentPageData() {
|
|
|
|
|
const start = (this.currentPage - 1) * this.pageSize;
|
2025-05-16 10:26:07 +08:00
|
|
|
|
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();
|
2025-04-30 14:50:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render() {
|
|
|
|
|
this.shadowRoot.innerHTML = `
|
|
|
|
|
<style>
|
2025-05-07 13:46:48 +08:00
|
|
|
|
.data-table {
|
2025-04-30 14:50:27 +08:00
|
|
|
|
width: 100%;
|
2025-05-07 13:46:48 +08:00
|
|
|
|
border-collapse: collapse;
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
table-layout: fixed;
|
|
|
|
|
position: relative;
|
2025-04-30 14:50:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
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-04-30 14:50:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
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;
|
2025-04-30 14:50:27 +08:00
|
|
|
|
padding: 8px;
|
|
|
|
|
text-align: left;
|
2025-05-07 13:46:48 +08:00
|
|
|
|
overflow: hidden;
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
white-space: nowrap;
|
2025-04-30 14:50:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-05-07 13:46:48 +08:00
|
|
|
|
.data-table th {
|
2025-04-30 14:50:27 +08:00
|
|
|
|
background-color: #f5f5f5;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-07 13:46:48 +08:00
|
|
|
|
.data-table tr:nth-child(even) {
|
2025-04-30 14:50:27 +08:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-16 10:26:07 +08:00
|
|
|
|
.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 {
|
2025-04-30 14:50:27 +08:00
|
|
|
|
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;
|
2025-04-30 14:50:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.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;
|
2025-04-30 14:50:27 +08:00
|
|
|
|
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;
|
2025-04-30 14:50:27 +08:00
|
|
|
|
}
|
|
|
|
|
</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>
|
2025-05-16 10:26:07 +08:00
|
|
|
|
<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>
|
2025-05-16 10:26:07 +08:00
|
|
|
|
<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>
|
2025-05-16 10:26:07 +08:00
|
|
|
|
<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>
|
|
|
|
|
` : ''}
|
2025-05-16 10:26:07 +08:00
|
|
|
|
<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-04-30 14:50:27 +08:00
|
|
|
|
`;
|
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-04-30 14:50:27 +08:00
|
|
|
|
|
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);
|
2025-04-30 14:50:27 +08:00
|
|
|
|
if (e.target.checked) {
|
2025-05-07 13:46:48 +08:00
|
|
|
|
this.selectedRows.add(index);
|
2025-04-30 14:50:27 +08:00
|
|
|
|
} else {
|
2025-05-07 13:46:48 +08:00
|
|
|
|
this.selectedRows.delete(index);
|
2025-04-30 14:50:27 +08:00
|
|
|
|
}
|
2025-05-07 13:46:48 +08:00
|
|
|
|
if (selectAllCheckbox) {
|
|
|
|
|
selectAllCheckbox.checked = this.selectedRows.size === rowCheckboxes.length;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
this.addEventListenerWithCleanup(checkbox, 'change', checkboxHandler);
|
2025-04-30 14:50:27 +08:00
|
|
|
|
});
|
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 = {
|
2025-05-16 10:26:07 +08:00
|
|
|
|
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();
|
2025-04-30 14:50:27 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
customElements.define('interface-data-table', InterfaceDataTable);
|