// selection-table.js - 完整实现
class SelectionTable {
constructor(options) {
// 默认配置
this.options = Object.assign({
apiUrl: '/product/selection/search',
configUrl: '/product/selection/config',
container: '#selection-table',
pageSize: 50,
debounceDelay: 300,
maxPrice: 10000, // 最大价格限制
showImages: true // 是否显示产品图片
}, options);
// 状态管理
this.state = {
keyword: '',
filters: {
attributes: {},
price_min: 0,
price_max: 0,
stock_min: 0
},
page: 1,
sort: 'relevance',
loading: false,
total: 0,
totalPages: 0
};
// DOM元素引用
this.elements = {};
// 初始化
this.init();
}
/**
* 初始化选型表
*/
async init() {
try {
// 加载配置
await this.loadConfig();
// 渲染UI
this.renderUI();
// 绑定事件
this.bindEvents();
// 执行初始搜索
await this.search();
} catch (error) {
console.error('选型表初始化失败:', error);
this.showError('选型表初始化失败,请刷新页面重试');
}
}
/**
* 加载配置信息
*/
async loadConfig() {
try {
const response = await fetch(this.options.configUrl);
const result = await response.json();
if (result.code === 200) {
this.config = result.data;
} else {
throw new Error(result.message || '配置加载失败');
}
} catch (error) {
console.error('加载配置失败:', error);
// 使用默认配置
this.config = {
attributes: [],
sort_options: [
{ value: 'relevance', label: '相关性' },
{ value: 'price_asc', label: '价格从低到高' },
{ value: 'price_desc', label: '价格从高到低' },
{ value: 'stock_desc', label: '库存从多到少' },
{ value: 'newest', label: '最新上架' }
],
page_sizes: [20, 50, 100],
defaults: {
page_size: 50,
sort: 'relevance'
}
};
}
}
/**
* 渲染主界面
*/
renderUI() {
const container = document.querySelector(this.options.container);
if (!container) {
throw new Error(`容器元素 ${this.options.container} 未找到`);
}
container.innerHTML = this.generateHTML();
// 保存DOM元素引用
this.cacheElements();
}
/**
* 生成HTML内容
*/
generateHTML() {
return `
`;
}
/**
* 缓存DOM元素引用
*/
cacheElements() {
this.elements = {
container: document.querySelector(this.options.container),
keywordInput: document.querySelector('.keyword-input'),
searchBtn: document.querySelector('.search-btn'),
clearBtn: document.querySelector('.clear-btn'),
priceMin: document.querySelector('.price-min'),
priceMax: document.querySelector('.price-max'),
stockMin: document.querySelector('.stock-min'),
sortSelect: document.querySelector('.sort-select'),
pageSizeSelect: document.querySelector('.page-size-select'),
productsGrid: document.querySelector('.products-grid .products-container'),
productsList: document.querySelector('.products-list tbody'),
pagination: document.querySelector('.pagination-container'),
loadingSection: document.querySelector('.loading-section'),
errorSection: document.querySelector('.error-section'),
emptySection: document.querySelector('.empty-section'),
totalCount: document.querySelector('.total-count'),
currentPage: document.querySelector('.current-page'),
totalPages: document.querySelector('.total-pages'),
searchTime: document.querySelector('.search-time'),
timeValue: document.querySelector('.time-value')
};
}
/**
* 渲染属性筛选器
*/
renderAttributeFilters() {
if (!this.config || !this.config.attributes) {
return '暂无属性筛选配置
';
}
return this.config.attributes.map(attr => `
${attr.type === 'range' ? this.renderRangeAttribute(attr) : this.renderOptionsAttribute(attr)}
`).join('');
}
/**
* 渲染范围类型属性
*/
renderRangeAttribute(attr) {
return `
至
${attr.unit ? `${attr.unit}` : ''}
`;
}
/**
* 渲染选项类型属性
*/
renderOptionsAttribute(attr) {
if (!attr.options || attr.options.length === 0) {
return '暂无选项
';
}
const optionsHTML = attr.options.map(option => `
`).join('');
return `
${optionsHTML}
`;
}
/**
* 渲染排序选项
*/
renderSortOptions() {
if (!this.config || !this.config.sort_options) {
return `
`;
}
return this.config.sort_options.map(option => `
`).join('');
}
/**
* 渲染分页大小选项
*/
renderPageSizeOptions() {
const sizes = this.config?.page_sizes || [20, 50, 100];
return sizes.map(size => `
`).join('');
}
/**
* 绑定事件监听器
*/
bindEvents() {
// 搜索相关事件
this.bindSearchEvents();
// 筛选相关事件
this.bindFilterEvents();
// 分页和排序事件
this.bindControlEvents();
// 视图切换事件
this.bindViewEvents();
}
/**
* 绑定搜索事件
*/
bindSearchEvents() {
const { keywordInput, searchBtn, clearBtn } = this.elements;
// 关键词输入防抖搜索
keywordInput.addEventListener('input', this.debounce(() => {
this.state.keyword = keywordInput.value.trim();
this.state.page = 1;
this.search();
}, this.options.debounceDelay));
// 搜索按钮点击
searchBtn.addEventListener('click', () => {
this.state.keyword = keywordInput.value.trim();
this.state.page = 1;
this.search();
});
// 回车键搜索
keywordInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
this.state.keyword = keywordInput.value.trim();
this.state.page = 1;
this.search();
}
});
// 清除搜索
clearBtn.addEventListener('click', () => {
keywordInput.value = '';
this.state.keyword = '';
this.state.page = 1;
this.search();
});
}
/**
* 绑定筛选事件
*/
bindFilterEvents() {
// 价格范围筛选
this.elements.priceMin.addEventListener('input', this.debounce(() => {
this.state.filters.price_min = parseFloat(this.elements.priceMin.value) || 0;
this.state.page = 1;
this.search();
}, 500));
this.elements.priceMax.addEventListener('input', this.debounce(() => {
this.state.filters.price_max = parseFloat(this.elements.priceMax.value) || 0;
this.state.page = 1;
this.search();
}, 500));
// 库存筛选
this.elements.stockMin.addEventListener('input', this.debounce(() => {
this.state.filters.stock_min = parseInt(this.elements.stockMin.value) || 0;
this.state.page = 1;
this.search();
}, 500));
// 属性筛选
document.querySelectorAll('.attribute-option').forEach(option => {
option.addEventListener('change', () => {
this.updateAttributeFilters();
this.state.page = 1;
this.search();
});
});
// 属性组展开/收起
document.querySelectorAll('.attribute-toggle').forEach(toggle => {
toggle.addEventListener('click', (e) => {
const group = e.target.closest('.attribute-filter-group');
const options = group.querySelector('.attribute-options');
const icon = group.querySelector('.attribute-toggle i');
options.classList.toggle('collapsed');
icon.classList.toggle('fa-chevron-down');
icon.classList.toggle('fa-chevron-up');
});
});
}
/**
* 绑定控制事件
*/
bindControlEvents() {
// 排序变化
this.elements.sortSelect.addEventListener('change', (e) => {
this.state.sort = e.target.value;
this.state.page = 1;
this.search();
});
// 分页大小变化
this.elements.pageSizeSelect.addEventListener('change', (e) => {
this.options.pageSize = parseInt(e.target.value);
this.state.page = 1;
this.search();
});
}
/**
* 绑定视图事件
*/
bindViewEvents() {
// 视图切换
document.querySelectorAll('.view-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
// 移除所有激活状态
document.querySelectorAll('.view-btn').forEach(b => b.classList.remove('active'));
document.querySelectorAll('.view-content').forEach(c => c.classList.remove('active'));
// 激活当前视图
e.target.classList.add('active');
const viewType = e.target.classList.contains('grid-view') ? 'grid' : 'list';
document.querySelector(`.products-${viewType}`).classList.add('active');
});
});
}
/**
* 更新属性筛选状态
*/
updateAttributeFilters() {
this.state.filters.attributes = {};
document.querySelectorAll('.attribute-filter-group').forEach(group => {
const attributeKey = group.dataset.attribute;
const selectedOptions = this.getSelectedAttributeOptions(group);
if (selectedOptions.length > 0) {
this.state.filters.attributes[attributeKey] = selectedOptions;
}
});
}
/**
* 获取选中的属性选项
*/
getSelectedAttributeOptions(group) {
const checkboxes = group.querySelectorAll('input[type="checkbox"]:checked');
const radios = group.querySelectorAll('input[type="radio"]:checked');
const selected = [];
checkboxes.forEach(cb => selected.push(cb.value));
radios.forEach(radio => selected.push(radio.value));
return selected;
}
/**
* 执行搜索
*/
async search() {
if (this.state.loading) return;
this.state.loading = true;
this.showLoading();
this.hideError();
this.hideEmpty();
const startTime = Date.now();
try {
// 构建请求参数
const params = this.buildSearchParams();
// 发送搜索请求
const response = await fetch(`${this.options.apiUrl}?${params}`);
const result = await response.json();
const searchTime = (Date.now() - startTime) / 1000;
if (result.code === 200) {
this.handleSearchSuccess(result.data, searchTime);
} else {
this.handleSearchError(result.message);
}
} catch (error) {
this.handleSearchError('网络请求失败,请检查网络连接');
console.error('搜索错误:', error);
} finally {
this.state.loading = false;
this.hideLoading();
}
}
/**
* 构建搜索参数
*/
buildSearchParams() {
const params = new URLSearchParams({
keyword: this.state.keyword,
page: this.state.page,
page_size: this.options.pageSize,
sort: this.state.sort
});
// 添加基础过滤器
if (this.state.filters.price_min > 0) {
params.append('price_min', this.state.filters.price_min);
}
if (this.state.filters.price_max > 0) {
params.append('price_max', this.state.filters.price_max);
}
if (this.state.filters.stock_min > 0) {
params.append('stock_min', this.state.filters.stock_min);
}
// 添加属性过滤器
if (Object.keys(this.state.filters.attributes).length > 0) {
params.append('attributes', JSON.stringify(this.state.filters.attributes));
}
return params;
}
/**
* 处理搜索成功
*/
handleSearchSuccess(data, searchTime) {
this.state.total = data.summary?.total || 0;
this.state.totalPages = Math.ceil(this.state.total / this.options.pageSize);
// 更新UI
this.updateSummary(data.summary, searchTime);
this.renderProducts(data.products);
this.renderPagination();
// 显示/隐藏空结果提示
if (this.state.total === 0) {
this.showEmpty();
} else {
this.hideEmpty();
}
// 更新属性计数
this.updateAttributeCounts(data.summary?.attributes_summary);
}
/**
* 处理搜索错误
*/
handleSearchError(message) {
this.showError(message);
this.elements.productsGrid.innerHTML = '';
this.elements.productsList.innerHTML = '';
this.elements.pagination.innerHTML = '';
this.updateSummary({ total: 0 }, 0);
}
/**
* 更新摘要信息
*/
updateSummary(summary, searchTime) {
this.elements.totalCount.textContent = summary.total?.toLocaleString() || '0';
this.elements.currentPage.textContent = this.state.page;
this.elements.totalPages.textContent = this.state.totalPages;
if (searchTime > 0) {
this.elements.timeValue.textContent = searchTime.toFixed(2);
this.elements.searchTime.style.display = 'inline';
} else {
this.elements.searchTime.style.display = 'none';
}
}
/**
* 渲染产品列表
*/
renderProducts(products) {
this.renderGridView(products);
this.renderListView(products);
}
/**
* 渲染网格视图
*/
renderGridView(products) {
if (!products || products.length === 0) {
this.elements.productsGrid.innerHTML = '';
return;
}
const productsHTML = products.map(product => this.generateProductCard(product)).join('');
this.elements.productsGrid.innerHTML = productsHTML;
// 绑定产品卡片事件
this.bindProductEvents();
}
/**
* 渲染列表视图
*/
renderListView(products) {
if (!products || products.length === 0) {
this.elements.productsList.innerHTML = '';
return;
}
const rowsHTML = products.map(product => this.generateProductRow(product)).join('');
this.elements.productsList.innerHTML = rowsHTML;
// 绑定产品行事件
this.bindProductEvents();
}
/**
* 生成产品卡片HTML
*/
generateProductCard(product) {
return `
${product.brand}
${product.description || '暂无描述'}
${this.renderProductAttributes(product.attributes)}
¥${(product.price || 0).toFixed(2)}
库存: ${product.stock || 0}
`;
}
/**
* 生成产品行HTML
*/
generateProductRow(product) {
return `
|
${product.part}
|
${product.brand} |
${product.description || '暂无描述'} |
¥${(product.price || 0).toFixed(2)} |
${product.stock || 0} |
|
`;
}
/**
* 渲染产品属性
*/
renderProductAttributes(attributes) {
if (!attributes || Object.keys(attributes).length === 0) {
return '暂无属性信息
';
}
return Object.entries(attributes).map(([key, value]) => `
${key}:
${value}
`).join('');
}
/**
* 绑定产品事件
*/
bindProductEvents() {
// 加入询价按钮
document.querySelectorAll('.add-to-cart').forEach(btn => {
btn.addEventListener('click', (e) => {
const productId = e.target.dataset.id;
this.addToInquiry(productId);
});
});
// 查看详情按钮
document.querySelectorAll('.view-details').forEach(btn => {
btn.addEventListener('click', (e) => {
const productId = e.target.dataset.id;
this.viewProductDetails(productId);
});
});
// 加入对比按钮
document.querySelectorAll('.compare-add-btn, .compare-add').forEach(btn => {
btn.addEventListener('click', (e) => {
const productId = e.target.closest('button').dataset.id;
this.addToComparison(productId);
});
});
}
/**
* 渲染分页
*/
renderPagination() {
if (this.state.totalPages <= 1) {
this.elements.pagination.innerHTML = '';
return;
}
const paginationHTML = this.generatePaginationHTML();
this.elements.pagination.innerHTML = paginationHTML;
// 绑定分页事件
this.bindPaginationEvents();
}
/**
* 生成分页HTML
*/
generatePaginationHTML() {
const currentPage = this.state.page;
const totalPages = this.state.totalPages;
const pages = [];
// 总是显示第一页
pages.push(this.generatePageItem(1, currentPage === 1));
// 计算显示的页码范围
let startPage = Math.max(2, currentPage - 2);
let endPage = Math.min(totalPages - 1, currentPage + 2);
// 添加省略号
if (startPage > 2) {
pages.push('...');
}
// 添加中间页码
for (let i = startPage; i <= endPage; i++) {
pages.push(this.generatePageItem(i, i === currentPage));
}
// 添加末尾省略号
if (endPage < totalPages - 1) {
pages.push('...');
}
// 总是显示最后一页
if (totalPages > 1) {
pages.push(this.generatePageItem(totalPages, currentPage === totalPages));
}
// 添加上一页/下一页
const prevDisabled = currentPage === 1 ? 'disabled' : '';
const nextDisabled = currentPage === totalPages ? 'disabled' : '';
return `
${pages.join('')}
`;
}
/**
* 生成页码项
*/
generatePageItem(page, isActive) {
const activeClass = isActive ? 'active' : '';
return ``;
}
/**
* 绑定分页事件
*/
bindPaginationEvents() {
// 页码点击
document.querySelectorAll('.page-number').forEach(btn => {
btn.addEventListener('click', (e) => {
const page = parseInt(e.target.dataset.page);
this.goToPage(page);
});
});
// 上一页/下一页
document.querySelector('.prev-page').addEventListener('click', () => {
if (this.state.page > 1) {
this.goToPage(this.state.page - 1);
}
});
document.querySelector('.next-page').addEventListener('click', () => {
if (this.state.page < this.state.totalPages) {
this.goToPage(this.state.page + 1);
}
});
}
/**
* 跳转到指定页面
*/
goToPage(page) {
this.state.page = page;
this.search();
// 滚动到顶部
this.elements.container.scrollIntoView({ behavior: 'smooth' });
}
/**
* 更新属性计数
*/
updateAttributeCounts(attributeSummary) {
if (!attributeSummary) return;
Object.entries(attributeSummary).forEach(([attrKey, values]) => {
Object.entries(values).forEach(([value, count]) => {
const countElement = document.querySelector(
`.attribute-option[value="${value}"] + .option-count`
);
if (countElement) {
countElement.textContent = `(${count})`;
countElement.style.display = 'inline';
}
});
});
}
/**
* 加入询价车
*/
addToInquiry(productId) {
// 这里可以集成现有的询价车功能
console.log('加入询价:', productId);
this.showMessage('产品已加入询价车', 'success');
}
/**
* 查看产品详情
*/
viewProductDetails(productId) {
// 跳转到产品详情页
window.open(`/product/detail/${productId}`, '_blank');
}
/**
* 加入对比
*/
addToComparison(productId) {
// 实现产品对比功能
console.log('加入对比:', productId);
this.showMessage('产品已加入对比', 'success');
}
/**
* 显示加载状态
*/
showLoading() {
this.elements.loadingSection.style.display = 'block';
this.elements.productsGrid.style.opacity = '0.5';
}
/**
* 隐藏加载状态
*/
hideLoading() {
this.elements.loadingSection.style.display = 'none';
this.elements.productsGrid.style.opacity = '1';
}
/**
* 显示错误信息
*/
showError(message) {
this.elements.errorSection.style.display = 'block';
this.elements.errorSection.querySelector('.error-text').textContent = message;
}
/**
* 隐藏错误信息
*/
hideError() {
this.elements.errorSection.style.display = 'none';
}
/**
* 显示空结果
*/
showEmpty() {
this.elements.emptySection.style.display = 'block';
}
/**
* 隐藏空结果
*/
hideEmpty() {
this.elements.emptySection.style.display = 'none';
}
/**
* 显示消息提示
*/
showMessage(message, type = 'info') {
// 实现消息提示功能
const messageDiv = document.createElement('div');
messageDiv.className = `message message-${type}`;
messageDiv.innerHTML = `
${message}
`;
document.body.appendChild(messageDiv);
setTimeout(() => {
messageDiv.remove();
}, 3000);
}
/**
* 防抖函数
*/
debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
/**
* 销毁实例
*/
destroy() {
// 清理事件监听器
// 这里可以根据需要添加具体的清理逻辑
console.log('SelectionTable实例已销毁');
}
}
// 导出到全局作用域
window.SelectionTable = SelectionTable;