class CustomRichSelectEditor { constructor() { this.eGui = null; this.input = null; this.list = null; this.values = []; this.filteredValues = []; this.isOpen = false; this.currentValue = ''; this.params = null; } init(params) { this.params = params; this.values = params.values || []; this.filteredValues = [...this.values]; this.currentValue = params.value || ''; // 创建容器 this.eGui = document.createElement('div'); this.eGui.className = 'custom-rich-select'; this.eGui.style.cssText = ` position: relative; width: 100%; height: 100%; `; // 创建输入框 this.input = document.createElement('input'); this.input.type = 'text'; this.input.value = this.currentValue; this.input.style.cssText = ` width: 100%; height: 100%; border: 1px solid #d9d9d9; padding: 0 8px; font-size: 14px; outline: none; box-sizing: border-box; `; this.input.addEventListener('input', this.handleInput.bind(this)); this.input.addEventListener('focus', this.handleFocus.bind(this)); this.input.addEventListener('blur', this.handleBlur.bind(this)); this.input.addEventListener('keydown', this.handleKeyDown.bind(this)); // 创建下拉列表 this.list = document.createElement('div'); this.list.className = 'custom-rich-select-list'; this.list.style.cssText = ` position: absolute; top: 100%; left: 0; width: 100%; max-height: 200px; background: white; border: 1px solid #d9d9d9; border-top: none; z-index: 1000; overflow-y: auto; display: none; box-shadow: 0 2px 8px rgba(0,0,0,0.15); `; this.eGui.appendChild(this.input); this.eGui.appendChild(this.list); this.updateList(); // 返回一个Promise,确保ag-Grid能正确处理异步初始化 return new Promise((resolve) => { // 延迟一小段时间确保DOM已经完全渲染 setTimeout(() => { resolve(this.eGui); }, 0); }); } handleInput(event) { const searchValue = event.target.value.toLowerCase(); this.filteredValues = this.values.filter(value => value.toLowerCase().includes(searchValue) ); this.updateList(); this.showList(); } handleFocus() { this.showList(); } handleBlur() { setTimeout(() => { this.hideList(); }, 200); } handleKeyDown(event) { switch (event.key) { case 'Enter': if (this.isOpen && this.filteredValues.length > 0) { this.selectValue(this.filteredValues[0]); event.preventDefault(); } break; case 'Escape': this.hideList(); event.preventDefault(); break; case 'ArrowDown': if (!this.isOpen) { this.showList(); } event.preventDefault(); break; } } showList() { if (!this.isOpen) { this.list.style.display = 'block'; this.isOpen = true; } } hideList() { if (this.isOpen) { this.list.style.display = 'none'; this.isOpen = false; } } updateList() { this.list.innerHTML = ''; if (this.filteredValues.length === 0) { const noResults = document.createElement('div'); noResults.textContent = '无匹配结果'; noResults.style.cssText = ` padding: 8px; color: #999; font-style: italic; `; this.list.appendChild(noResults); } else { this.filteredValues.forEach(value => { const item = document.createElement('div'); item.textContent = value; item.style.cssText = ` padding: 8px; cursor: pointer; border-bottom: 1px solid #f0f0f0; `; item.addEventListener('mouseenter', () => { item.style.backgroundColor = '#f5f5f5'; }); item.addEventListener('mouseleave', () => { item.style.backgroundColor = ''; }); item.addEventListener('click', () => { this.selectValue(value); }); this.list.appendChild(item); }); } } selectValue(value) { this.input.value = value; this.currentValue = value; this.hideList(); if (this.params && this.params.stopEditing) { this.params.stopEditing(); } } getValue() { return this.currentValue; } getGui() { return this.eGui; } isPopup() { return true; } afterGuiAttached() { if (this.input) { this.input.focus(); this.input.select(); } } destroy() { // 清理事件监听器 if (this.input) { this.input.removeEventListener('input', this.handleInput); this.input.removeEventListener('focus', this.handleFocus); this.input.removeEventListener('blur', this.handleBlur); this.input.removeEventListener('keydown', this.handleKeyDown); } } } // 自定义编辑器类已定义,无需再次注册到ag-Grid // ag-Grid Community Edition 会自动识别自定义编辑器类 // Product类定义 class Product { // 私有字段 #_serialNumber; #_quoteProduct; #_model; #_specification; #_standard; #_voltage; #_unit; #_quantity; // 公共属性(使用属性封装字段) get SerialNumber() { return this.#_serialNumber || 0; } set SerialNumber(value) { this.#_serialNumber = parseInt(value) || 0; } get QuoteProduct() { return this.#_quoteProduct || ''; } set QuoteProduct(value) { this.#_quoteProduct = value; } get Model() { return this.#_model || ''; } set Model(value) { this.#_model = value; } get Specification() { return this.#_specification || ''; } set Specification(value) { this.#_specification = value; } get Standard() { return this.#_standard || ''; } set Standard(value) { this.#_standard = value; } get Voltage() { return this.#_voltage || ''; } set Voltage(value) { this.#_voltage = value; } get Unit() { return this.#_unit || ''; } set Unit(value) { this.#_unit = value; } get Quantity() { return this.#_quantity || 0; } set Quantity(value) { this.#_quantity = parseFloat(value) || 0; } // 默认构造函数 constructor() { this.#_serialNumber = 0; this.#_quoteProduct = ''; this.#_model = ''; this.#_specification = ''; this.#_standard = ''; this.#_voltage = ''; this.#_unit = ''; this.#_quantity = 0; } // 带参数的构造函数(可选) static createWithParams(serialNumber, quoteProduct, model, specification, standard, voltage, unit, quantity) { const product = new Product(); product.SerialNumber = serialNumber; product.QuoteProduct = quoteProduct; product.Model = model; product.Specification = specification; product.Standard = standard; product.Voltage = voltage; product.Unit = unit; product.Quantity = quantity; return product; } // 转换为JSON格式 toJSON() { return { SerialNumber: this.SerialNumber, QuoteProduct: this.QuoteProduct, Model: this.Model, Specification: this.Specification, Standard: this.Standard, Voltage: this.Voltage, Unit: this.Unit, Quantity: this.Quantity }; } // 从JSON创建实例 static fromJSON(json) { const product = new Product(); if (json) { product.SerialNumber = json.SerialNumber || 0; product.QuoteProduct = json.QuoteProduct || json.quoteProduct || ''; product.Model = json.Model || ''; product.Specification = json.Specification || ''; product.Standard = json.Standard || ''; product.Voltage = json.Voltage || ''; product.Unit = json.Unit || ''; product.Quantity = json.Quantity || 0; } return product; } } function getUrlParameterBJDID() { const results = document.getElementById("txtBJDID").value; return results === null ? "" : results; } const BJDID = getUrlParameterBJDID(); // 投标数据快速录入功能 const { createApp } = Vue; const { ElMessage } = ElementPlus; const app = createApp({ data() { return { gridApi: null, gridColumnApi: null, rowData: [], isEditing: false, // 编辑状态 originalData: [], // 原始数据备份 standardDictionary: null, // 标准字典数据 voltageLevels: null, // 电压等级列表数据 isProcessing: false, // 处理状态 progressPercentage: 0, // 进度百分比 progressText: '', // 进度文本 columnDefs: [ { headerName: '序号', width: 80, pinned: 'left', lockPinned: true, suppressMovable: true, sortable: false, resizable: false, editable: false, filter: false, cellStyle: { backgroundColor: '#f8f9fa', fontWeight: 'bold', textAlign: 'center' }, valueGetter: (params) => { return params.node.rowIndex + 1; }, valueSetter: (params) => { return false; } }, { headerName: '报价产品', field: 'quoteProduct', editable: () => this.isEditing, filter: 'agSetColumnFilter', filterParams: { applyMiniFilterWhileTyping: true, suppressSorting: true }, sortable: true, resizable: true, width: 200, cellStyle: (params) => { return this.isEditing ? { backgroundColor: '#f0f9ff' } : {}; } }, { headerName: '型号', field: 'model', editable: () => this.isEditing, // 只有在编辑状态下可编辑 filter: 'agSetColumnFilter', filterParams: { applyMiniFilterWhileTyping: true, suppressSorting: true }, sortable: true, resizable: true, width: 150, cellStyle: (params) => { return this.isEditing ? { backgroundColor: '#f0f9ff' } : {}; } }, { headerName: '规格', field: 'specification', editable: () => this.isEditing, filter: 'agSetColumnFilter', filterParams: { applyMiniFilterWhileTyping: true, suppressSorting: true }, sortable: true, resizable: true, width: 120, cellStyle: (params) => { return this.isEditing ? { backgroundColor: '#f0f9ff' } : {}; } }, { headerName: '标准', field: 'standard', editable: () => this.isEditing, cellEditor: CustomRichSelectEditor, cellEditorParams: { values: [''] // 初始值,实际值会在编辑器中动态获取 }, filter: 'agSetColumnFilter', filterParams: { applyMiniFilterWhileTyping: true, suppressSorting: true }, sortable: true, resizable: true, width: 120, valueFormatter: (params) => { // 显示key-value格式,如果已经是key-value格式则不重复显示 if (!params.value) return ''; const valueStr = params.value.toString(); // 检查是否已经是key-value格式(包含 | 分隔符) if (valueStr.includes('|')) { return valueStr; } // 如果是纯key,尝试获取对应的value进行显示 if (this.standardDictionary && this.standardDictionary[valueStr]) { return `${valueStr}|${this.standardDictionary[valueStr]}`; } // 如果没有字典数据,直接显示key return valueStr; }, cellStyle: (params) => { return this.isEditing ? { backgroundColor: '#f0f9ff' } : {}; } }, { headerName: '电压等级', field: 'voltage', editable: () => this.isEditing, cellEditor: CustomRichSelectEditor, cellEditorParams: { values: [''] // 初始值,实际值会在编辑器中动态获取 }, filter: 'agSetColumnFilter', filterParams: { applyMiniFilterWhileTyping: true, suppressSorting: true }, sortable: true, resizable: true, width: 100, cellStyle: (params) => { return this.isEditing ? { backgroundColor: '#f0f9ff' } : {}; } }, { headerName: '计量单位', field: 'unit', editable: () => this.isEditing, filter: 'agSetColumnFilter', filterParams: { applyMiniFilterWhileTyping: true, suppressSorting: true }, sortable: true, resizable: true, width: 100, cellStyle: (params) => { return this.isEditing ? { backgroundColor: '#f0f9ff' } : {}; } }, { headerName: '数量', field: 'quantity', editable: () => this.isEditing, filter: 'agNumberColumnFilter', sortable: true, resizable: true, width: 100, type: 'numericColumn', cellStyle: (params) => { return this.isEditing ? { backgroundColor: '#f0f9ff' } : {}; } } ], defaultColDef: { flex: 1, minWidth: 80, enableCellChangeFlash: true, cellClass: 'cell-editable' } } }, mounted() { this.initGrid(); // 延迟设置粘贴监听器,确保DOM已完全加载 this.$nextTick(() => { this.setupPasteListener(); }); }, methods: { // 初始化ag-Grid initGrid() { const gridOptions = { columnDefs: this.columnDefs, defaultColDef: this.defaultColDef, rowData: this.rowData, // 增强Excel式编辑功能 enableRangeSelection: true, enableFillHandle: true, rowSelection: 'multiple', enableCellTextSelection: false, // 禁用单元格文本选择,避免多行选中时文本被选中 suppressCellTextSelection: true, // 进一步抑制文本选择 enableRangeHandle: true, enableRangeEdit: true, undoRedoCellEditing: true, undoRedoCellEditingLimit: 20, enableCellEditingOnBackspace: true, // 移除分页,使用无限滚动 rowModelType: 'clientSide', ensureDomOrder: true, animateRows: true, onGridReady: (params) => { this.gridApi = params.api; this.gridColumnApi = params.columnApi; // 设置初始数据 this.addSampleData(); // 配置Excel式编辑 this.configureExcelEditing(); }, onCellValueChanged: (event) => { // 更新过滤器的值 this.updateFilterValues(); }, onCellKeyDown: (event) => { // 支持Ctrl+V粘贴 if (event.event.ctrlKey && event.event.key === 'v') { event.event.preventDefault(); this.handlePaste(); } // 支持Excel式编辑快捷键 this.handleExcelShortcuts(event); }, onRangeSelectionChanged: (event) => { // 选中范围变化时处理 this.handleRangeSelection(event); } }; const gridDiv = document.querySelector('#myGrid'); new agGrid.Grid(gridDiv, gridOptions); }, // 配置Excel式编辑 configureExcelEditing() { if (this.gridApi) { // 启用范围编辑 this.gridApi.setSuppressClipboardPaste(false); // 设置Enter键行为:向下移动(使用兼容性方法) try { if (typeof this.gridApi.setEnterMovesDownAfterEdit === 'function') { this.gridApi.setEnterMovesDownAfterEdit(true); } if (typeof this.gridApi.setEnterMovesDown === 'function') { this.gridApi.setEnterMovesDown(true); } } catch (error) { console.warn('Excel编辑配置警告:', error); } } }, // 处理Excel快捷键 handleExcelShortcuts(event) { const key = event.event.key; const ctrlKey = event.event.ctrlKey; if (ctrlKey) { switch (key) { case 'd': // Ctrl+D: 向下填充 event.event.preventDefault(); this.fillDown(); break; case 'r': // Ctrl+R: 向右填充 event.event.preventDefault(); this.fillRight(); break; case 'z': // Ctrl+Z: 撤销 event.event.preventDefault(); this.gridApi.undoCellEditing(); break; case 'y': // Ctrl+Y: 重做 event.event.preventDefault(); this.gridApi.redoCellEditing(); break; } } }, // 处理范围选择 handleRangeSelection(event) { const ranges = this.gridApi.getCellRanges(); if (ranges && ranges.length > 0) { } }, // 向下填充 fillDown() { const ranges = this.gridApi.getCellRanges(); if (!ranges || ranges.length === 0) return; const range = ranges[0]; const startRow = range.startRow.rowIndex; const endRow = range.endRow.rowIndex; const column = range.columns[0]; const field = column.getColDef().field; if (startRow === endRow) return; // 单行不需要填充 // 防止对序号列进行填充(通过列ID检查) if (column.colId === 'serialNumber' || column.getColDef().headerName === '序号') { this.showSimpleMessage('序号列不支持填充操作'); return; } const sourceValue = this.rowData[startRow][field]; // 填充选中范围内的所有行 for (let i = startRow + 1; i <= endRow; i++) { this.rowData[i][field] = sourceValue; } this.updateGrid({ columns: [field] }); this.showSimpleMessage('向下填充完成'); }, // 向右填充 fillRight() { const ranges = this.gridApi.getCellRanges(); if (!ranges || ranges.length === 0) return; const range = ranges[0]; const startCol = range.columns[0]; const endCol = range.columns[range.columns.length - 1]; const rowIndex = range.startRow.rowIndex; if (startCol === endCol) return; // 单列不需要填充 const sourceValue = this.rowData[rowIndex][startCol.getColDef().field]; // 找到开始列和结束列的索引 const colDefs = this.gridColumnApi.getAllGridColumns(); const startColIndex = colDefs.indexOf(startCol); const endColIndex = colDefs.indexOf(endCol); // 填充选中范围内的所有列 for (let i = startColIndex + 1; i <= endColIndex; i++) { const field = colDefs[i].getColDef().field; // 跳过序号列 if (colDefs[i].getColDef().headerName === '序号') { continue; } this.rowData[rowIndex][field] = sourceValue; } const updatedCols = colDefs.slice(startColIndex + 1, endColIndex + 1) .filter(c => c.getColDef().headerName !== '序号') .map(c => c.getColDef().field); this.updateGrid({ columns: updatedCols }); this.showSimpleMessage('向右填充完成'); }, // 更新过滤器的值 updateFilterValues() { // ag-Grid的Set过滤器会自动更新,这里只需要刷新过滤器 if (this.gridApi) { this.gridApi.refreshHeader(); } }, // 添加示例数据 addSampleData() { const sampleData = []; this.rowData = sampleData; if (this.gridApi) { this.gridApi.setRowData(this.rowData); } }, // 粘贴数据处理 handlePaste() { if (this.isSecureContext()) { // HTTPS环境,直接读取剪贴板 this.readClipboard(); } else { // HTTP环境,直接提示用户使用Ctrl+V this.showSimpleMessage('请使用 Ctrl+V 粘贴数据到表格中'); } }, // 检查是否安全上下文 isSecureContext() { return window.isSecureContext || window.location.protocol === 'https:'; }, // 读取剪贴板数据 async readClipboard() { try { const text = await navigator.clipboard.readText(); this.processPastedData(text); } catch (error) { this.showSimpleMessage('请使用 Ctrl+V 粘贴数据到表格中'); } }, // 处理粘贴的数据 processPastedData(text) { try { const lines = text.split(/\r?\n/).filter(line => line.trim()); const newData = []; lines.forEach((line, index) => { if (index === 0 && (line.includes('序号') || line.includes('型号') || line.includes('报价产品') || line.includes('规格') || line.includes('标准'))) { return; } const cells = line.split('\t'); const hasSerialColumn = cells.length >= 8 && /^\d+$/.test(cells[0].trim()); let quoteProductIdx, modelIdx, specIdx, standardIdx, voltageIdx, unitIdx, quantityIdx; if (hasSerialColumn) { quoteProductIdx = 1; modelIdx = 2; specIdx = 3; standardIdx = 4; voltageIdx = 5; unitIdx = 6; quantityIdx = 7; } else { quoteProductIdx = 0; modelIdx = 1; specIdx = 2; standardIdx = 3; voltageIdx = 4; unitIdx = 5; quantityIdx = 6; } const requiredCells = hasSerialColumn ? 8 : 7; if (cells.length < requiredCells) { const spaceCells = line.split(/\s+/).filter(cell => cell.trim()); if (spaceCells.length >= requiredCells) { cells.length = 0; cells.push(...spaceCells); } } if (cells.length >= requiredCells) { const row = { quoteProduct: (cells[quoteProductIdx] || '').trim(), model: (cells[modelIdx] || '').trim(), specification: (cells[specIdx] || '').trim(), standard: (cells[standardIdx] || '').trim(), voltage: (cells[voltageIdx] || '').trim(), unit: (cells[unitIdx] || '').trim(), quantity: this.parseQuantity(cells[quantityIdx]) }; newData.push(row); } else { } }); if (newData.length > 0) { this.rowData = [...this.rowData, ...newData]; if (this.gridApi) { this.gridApi.setRowData(this.rowData); } this.showSimpleMessage(`成功添加 ${newData.length} 条数据`); } else { this.showSimpleMessage('未检测到有效数据,请检查数据格式'); } } catch (error) { console.error('处理粘贴数据失败:', error); this.showSimpleMessage('数据处理失败,请检查数据格式'); } }, // 解析数量 parseQuantity(value) { if (!value) return 0; // 移除千分位分隔符 const cleanValue = value.toString().replace(/[,,]/g, ''); const num = parseFloat(cleanValue); return isNaN(num) ? 0 : num; }, // 清空数据 handleClear() { // 使用自定义的确认框,避免使用el-message的图标 const messageBox = document.createElement('div'); messageBox.className = 'custom-message-box'; messageBox.innerHTML = `
确定要清空所有数据吗?
`; // 创建遮罩层 const overlay = document.createElement('div'); overlay.className = 'custom-message-overlay'; // 添加到页面 document.body.appendChild(overlay); document.body.appendChild(messageBox); // 绑定事件 messageBox.querySelector('.confirm-btn').addEventListener('click', () => { this.rowData = []; if (this.gridApi) { this.gridApi.setRowData([]); } this.removeCustomMessage(); this.showSimpleMessage('数据已清空'); }); messageBox.querySelector('.cancel-btn').addEventListener('click', () => { this.removeCustomMessage(); }); // 点击遮罩层关闭 overlay.addEventListener('click', () => { this.removeCustomMessage(); }); }, // 移除自定义消息框 removeCustomMessage() { const messageBox = document.querySelector('.custom-message-box'); const overlay = document.querySelector('.custom-message-overlay'); if (messageBox) { messageBox.remove(); } if (overlay) { overlay.remove(); } }, // 显示简单的文本提示 showSimpleMessage(text) { // 创建简单的提示元素 const messageEl = document.createElement('div'); messageEl.className = 'simple-message'; messageEl.innerHTML = `
${text}
`; // 添加到页面 document.body.appendChild(messageEl); // 1秒后自动移除 setTimeout(() => { if (messageEl.parentNode) { messageEl.remove(); } }, 1000); }, // 统一刷新表格方法 - 优化性能 // @param {Object} options - 刷新选项 // @param {boolean} options.fullRefresh - 是否完全刷新(默认false) // @param {Array} options.rows - 指定刷新的行节点数组 // @param {Array} options.columns - 指定刷新的列定义数组 updateGrid(options = {}) { const { fullRefresh = false, rows, columns } = options; if (!this.gridApi) return; if (fullRefresh) { this.gridApi.setRowData(this.rowData); } else if (rows && rows.length > 0) { this.gridApi.refreshCells({ rowNodes: rows }); } else if (columns && columns.length > 0) { this.gridApi.refreshCells({ columns: columns }); } else { this.gridApi.refreshCells({ force: true }); } }, // 统一确认框方法 - 减少重复代码 showConfirm(message, onConfirm, onCancel) { const messageBox = document.createElement('div'); messageBox.className = 'custom-message-box'; messageBox.innerHTML = `
${message}
`; const overlay = document.createElement('div'); overlay.className = 'custom-message-overlay'; document.body.appendChild(overlay); document.body.appendChild(messageBox); messageBox.querySelector('.confirm-btn').addEventListener('click', () => { this.removeCustomMessage(); if (onConfirm && typeof onConfirm === 'function') { onConfirm(); } }); const cancelHandler = () => { this.removeCustomMessage(); if (onCancel && typeof onCancel === 'function') { onCancel(); } }; messageBox.querySelector('.cancel-btn').addEventListener('click', cancelHandler); overlay.addEventListener('click', cancelHandler); }, // 显示加载框 showLoading(message = '正在处理,请稍候...') { // 如果已有加载框,先移除 this.hideLoading(); // 创建加载遮罩层 const loadingOverlay = document.createElement('div'); loadingOverlay.className = 'loading-overlay'; loadingOverlay.id = 'loadingOverlay'; loadingOverlay.innerHTML = `
${message}
`; // 添加到页面 document.body.appendChild(loadingOverlay); }, // 隐藏加载框 hideLoading() { const loadingOverlay = document.getElementById('loadingOverlay'); if (loadingOverlay) { loadingOverlay.remove(); } }, // 导出Excel handleExport() { if (this.rowData.length === 0) { this.showSimpleMessage('没有数据可导出'); return; } try { const wb = XLSX.utils.book_new(); const exportData = [ ['序号', '报价产品', '型号', '规格', '标准', '电压等级', '计量单位', '数量'], ...this.rowData.map((row, index) => [ index + 1, row.quoteProduct || '', row.model, row.specification, row.standard, row.voltage, row.unit, row.quantity ]) ]; const ws = XLSX.utils.aoa_to_sheet(exportData); XLSX.utils.book_append_sheet(wb, ws, '投标数据'); XLSX.writeFile(wb, `投标数据_${new Date().toLocaleDateString().replace(/\//g, '-')}.xlsx`); this.showSimpleMessage('导出成功'); } catch (error) { console.error('导出失败:', error); this.showSimpleMessage('导出失败'); } }, // 设置粘贴监听器 setupPasteListener() { document.addEventListener('paste', (event) => { // 如果焦点在ag-Grid上,让ag-Grid处理 const activeElement = document.activeElement; if (activeElement && activeElement.classList.contains('ag-cell')) { return; } // 否则处理全局粘贴 event.preventDefault(); const text = event.clipboardData.getData('text/plain'); if (text && text.trim()) { this.processPastedData(text); } }); }, // 批量编辑选中单元格 batchEditSelectedCells(value) { const ranges = this.gridApi.getCellRanges(); if (!ranges || ranges.length === 0) { this.showSimpleMessage('请先选择要编辑的单元格'); return; } ranges.forEach(range => { const startRow = Math.min(range.startRow.rowIndex, range.endRow.rowIndex); const endRow = Math.max(range.startRow.rowIndex, range.endRow.rowIndex); const startCol = Math.min(range.columns.indexOf(range.startColumn), range.columns.indexOf(range.endColumn)); const endCol = Math.max(range.columns.indexOf(range.startColumn), range.columns.indexOf(range.endColumn)); for (let rowIndex = startRow; rowIndex <= endRow; rowIndex++) { for (let colIndex = startCol; colIndex <= endCol; colIndex++) { const column = range.columns[colIndex]; const field = column.getColDef().field; // 跳过序号列 if (column.getColDef().headerName === '序号') { continue; } this.rowData[rowIndex][field] = value; } } }); this.updateGrid(); this.showSimpleMessage('批量编辑完成'); }, // 关闭页面 handleClose() { this.showConfirm('确定要关闭页面吗?', () => { this.closePage(); }); }, // 批量调整标准 async handleBatchAdjustStandard() { // 检查是否在编辑状态 if (this.isEditing) { this.showSimpleMessage('请在非编辑状态下使用批量调整功能'); return; } // 检查是否有选中行 const selectedNodes = this.gridApi.getSelectedNodes(); if (!selectedNodes || selectedNodes.length === 0) { this.showSimpleMessage('请先选择要调整的行'); return; } try { // 获取标准列表 const standardDict = await this.GetXLBZ(); if (!standardDict || Object.keys(standardDict).length === 0) { this.showSimpleMessage('获取标准列表失败,请稍后重试'); return; } // 创建标准选择对话框 this.showBatchAdjustDialog('标准', standardDict, (selectedValue) => { // 更新选中行的标准字段 selectedNodes.forEach(node => { if (node.data) { node.data.standard = selectedValue; } }); this.updateGrid({ rows: selectedNodes }); this.showSimpleMessage(`已为 ${selectedNodes.length} 行更新标准为: ${selectedValue}`); }); } catch (error) { console.error('批量调整标准失败:', error); this.showSimpleMessage('批量调整标准失败,请稍后重试'); } }, // 批量调整电压等级 async handleBatchAdjustVoltage() { // 检查是否在编辑状态 if (this.isEditing) { this.showSimpleMessage('请在非编辑状态下使用批量调整功能'); return; } // 检查是否有选中行 const selectedNodes = this.gridApi.getSelectedNodes(); if (!selectedNodes || selectedNodes.length === 0) { this.showSimpleMessage('请先选择要调整的行'); return; } try { // 获取电压等级列表 const voltageLevels = await this.GetDYDJ(); if (!voltageLevels || voltageLevels.length === 0) { this.showSimpleMessage('获取电压等级列表失败,请稍后重试'); return; } // 创建电压等级选择对话框 this.showBatchAdjustDialog('电压等级', voltageLevels, (selectedValue) => { // 更新选中行的电压等级字段 selectedNodes.forEach(node => { if (node.data) { node.data.voltage = selectedValue; } }); this.updateGrid({ rows: selectedNodes }); this.showSimpleMessage(`已为 ${selectedNodes.length} 行更新电压等级为: ${selectedValue}`); }); } catch (error) { console.error('批量调整电压等级失败:', error); this.showSimpleMessage('批量调整电压等级失败,请稍后重试'); } }, // 显示批量调整对话框 showBatchAdjustDialog(title, dataList, onConfirm) { // 创建对话框容器 const messageBox = document.createElement('div'); messageBox.className = 'custom-message-box'; // 构建选项HTML let optionsHtml = ''; if (typeof dataList === 'object' && !Array.isArray(dataList)) { // 字典格式数据(标准) for (const [key, value] of Object.entries(dataList)) { optionsHtml += ``; } } else { // 数组格式数据(电压等级) dataList.forEach(item => { optionsHtml += ``; }); } messageBox.innerHTML = `
批量调整${title}
已选择 ${this.gridApi.getSelectedNodes().length} 行数据
`; // 创建遮罩层 const overlay = document.createElement('div'); overlay.className = 'custom-message-overlay'; // 添加到页面 document.body.appendChild(overlay); document.body.appendChild(messageBox); // 确认按钮点击事件 messageBox.querySelector('.confirm-btn').addEventListener('click', () => { const selectedValue = document.getElementById('batchAdjustSelect').value; if (!selectedValue) { this.showSimpleMessage(`请选择${title}`); return; } // 移除对话框 this.removeCustomMessage(); // 执行确认回调 if (onConfirm && typeof onConfirm === 'function') { onConfirm(selectedValue); } }); // 取消按钮点击事件 messageBox.querySelector('.cancel-btn').addEventListener('click', () => { this.removeCustomMessage(); }); // 遮罩层点击事件 overlay.addEventListener('click', () => { this.removeCustomMessage(); }); }, // 关闭页面逻辑 closePage() { let topDocument; try { topDocument = top.document; } catch (e) { topDocument = document; // 跨域时回退到当前文档 } try { // 获取元素引用 const divZDY = topDocument.getElementById("div_ZDY"); const divZDY_100860140 = topDocument.getElementById("divZDY_100860140"); // 确保主容器存在 if (!divZDY) return; // 清除divZDY_102849000(如果存在) if (divZDY_100860140) { divZDY.removeChild(divZDY_100860140); } while (divZDY.firstChild) { divZDY.removeChild(divZDY.firstChild); } // 隐藏主容器 divZDY.style.display = "none"; } catch (error) { console.error("隐藏自定义元素时出错:", error); } // 刷新报价单 const frameElement = topDocument.getElementById('XLBJDInfo_frame'); if (!frameElement) { } else { const iframeDoc = frameElement.contentWindow.document; if (!iframeDoc) { } else { const reloadButton = iframeDoc.getElementById('ctl00_CPHButton_btnReLoad'); if (reloadButton) { reloadButton.click(); } else { } } } }, // 开始编辑 async startEdit() { try { // 先获取标准字典数据,确保下拉选择器有数据 if (!this.standardDictionary) { await this.GetXLBZ(); } // 获取电压等级数据,确保下拉选择器有数据 if (!this.voltageLevels) { await this.GetDYDJ(); } // 备份原始数据 this.originalData = JSON.parse(JSON.stringify(this.rowData)); this.isEditing = true; // 更新标准列的下拉选项 this.updateStandardColumnOptions(); // 更新电压等级列的下拉选项 this.updateVoltageColumnOptions(); // 刷新表格以应用编辑状态 if (this.gridApi) { this.gridApi.refreshHeader(); this.gridApi.setRowData(this.rowData); } this.showSimpleMessage('已进入编辑模式,可以修改表格内容'); } catch (error) { console.error('进入编辑模式失败:', error); this.showSimpleMessage('获取数据失败,无法进入编辑模式'); } }, // 更新标准列的下拉选项 updateStandardColumnOptions() { if (!this.standardDictionary) { console.warn('标准字典数据为空,无法更新下拉选项'); return; } // 构建选项数组 - 同时显示key和value const options = ['']; for (const [key, value] of Object.entries(this.standardDictionary)) { options.push(`${key}|${value}`); // 同时显示key和value,格式为 "key|value" } // 更新标准列的下拉选项 const standardColumn = this.gridColumnApi.getColumn('standard'); if (standardColumn) { standardColumn.colDef.cellEditorParams = { values: options }; // 刷新列定义 this.gridApi.refreshHeader(); } }, // 更新电压等级列的下拉选项 updateVoltageColumnOptions() { if (!this.voltageLevels) { console.warn('电压等级数据为空,无法更新下拉选项'); return; } // 构建选项数组(电压等级是List,直接使用) const options = ['', ...this.voltageLevels]; // 更新电压等级列的下拉选项 const voltageColumn = this.gridColumnApi.getColumn('voltage'); if (voltageColumn) { voltageColumn.colDef.cellEditorParams = { values: options }; // 刷新列定义 this.gridApi.refreshHeader(); } }, // 取消编辑 cancelEdit() { this.showConfirm('确定要取消编辑吗?所有未保存的修改将丢失', () => { this.rowData = JSON.parse(JSON.stringify(this.originalData)); this.isEditing = false; if (this.gridApi) { this.gridApi.setRowData(this.rowData); } this.showSimpleMessage('已取消编辑,数据已恢复'); }); }, // 保存数据 saveData() { this.showConfirm('确定要保存数据吗?', () => { this.isEditing = false; this.originalData = JSON.parse(JSON.stringify(this.rowData)); if (this.gridApi) { this.gridApi.refreshHeader(); } this.showSimpleMessage('数据保存成功'); }); }, // InsertBJDMX方法 - 调用服务处理报价单明细导入 async InsertBJDMX(items) { try { // 构建服务参数 const serviceParams = { '-RefUmId': 102855005, 'items': items.map(item => item.toJSON()), // 转换为JSON格式 'sBJDID': BJDID || '' // 获取报价单ID }; // 调用InsertBJDMX服务 const result = await this.callService('InsertBJDMX', serviceParams); return result; } catch (error) { console.error('InsertBJDMX服务调用失败:', error); throw error; } }, // 导入报价单明细 async handleImportBJD() { // 检查是否有数据 if (this.rowData.length === 0) { this.showSimpleMessage('没有数据可导入'); return; } try { // 显示加载框 this.showLoading('正在导入报价单明细,请稍候...'); // 构建Product列表 const items = this.buildProductList(); // 调用InsertBJDMX服务 const result = await this.InsertBJDMX(items); // 隐藏加载框 this.hideLoading(); if (result && result.success) { // 导入成功,提示并关闭页面 this.showSimpleMessage('导入成功'); // 延迟500毫秒后关闭页面,让用户看到提示信息 setTimeout(() => { this.closePage(); }, 500); } else { // 导入失败,只显示错误信息 const errorMsg = result ? result.msg : '未知错误'; this.showSimpleMessage(`导入失败: ${errorMsg}`); } } catch (error) { // 隐藏加载框 this.hideLoading(); console.error('导入报价单明细失败:', error); this.showSimpleMessage(`导入失败: ${error.message || '服务异常'}`); } }, async handleParseQuoteProduct() { if (this.rowData.length === 0) { this.showSimpleMessage('没有数据可解析'); return; } const hasQuoteProduct = this.rowData.some(row => row.quoteProduct && row.quoteProduct.trim()); if (!hasQuoteProduct) { this.showSimpleMessage('没有报价产品数据可解析'); return; } try { this.showLoading('正在解析报价产品,请稍候...'); const items = this.buildProductList(); const result = await this.JXBJCP(items); this.hideLoading(); if (result && Array.isArray(result)) { this.updateTableWithResult(result); this.showSimpleMessage('解析报价产品成功'); } else { console.warn('服务返回结果不是预期的List格式'); this.showSimpleMessage('解析完成,但返回结果格式有误'); } } catch (error) { this.hideLoading(); console.error('解析报价产品失败:', error); this.showSimpleMessage(`解析失败: ${error.message || '服务异常'}`); } }, async JXBJCP(items) { try { const serviceParams = { '-RefUmId': 102855005, 'items': items.map(item => item.toJSON()), 'sBJDID': BJDID || '' }; const result = await this.callService('JXBJCP', serviceParams); return result; } catch (error) { console.error('JXBJCP服务调用失败:', error); throw error; } }, // 匹配标准电压 async matchStandardVoltage() { // 检查是否有数据 if (this.rowData.length === 0) { this.showSimpleMessage('没有数据可匹配'); return; } try { // 获取标准列表 const standardDict = await this.GetXLBZ(); if (!standardDict || Object.keys(standardDict).length === 0) { this.showSimpleMessage('获取标准列表失败,请稍后重试'); return; } // 创建标准电压选择对话框 const messageBox = document.createElement('div'); messageBox.className = 'custom-message-box'; // 构建选项HTML,同时显示value和label let optionsHtml = ''; for (const [key, value] of Object.entries(standardDict)) { optionsHtml += ``; } messageBox.innerHTML = `
`; const overlay = document.createElement('div'); overlay.className = 'custom-message-overlay'; document.body.appendChild(overlay); document.body.appendChild(messageBox); // 确认按钮点击事件 messageBox.querySelector('.confirm-btn').addEventListener('click', async () => { const selectedStandard = document.getElementById('standardVoltageSelect').value; if (!selectedStandard) { this.showSimpleMessage('请选择标准'); return; } this.removeCustomMessage(); try { // 显示加载框 this.showLoading('正在匹配标准电压,请稍候...'); // 调用PPBZDYDJ服务 await this.PPBZDYDJ(selectedStandard); // 隐藏加载框 this.hideLoading(); } catch (error) { // 隐藏加载框 this.hideLoading(); console.error('匹配标准电压失败:', error); this.showSimpleMessage('匹配标准电压失败'); } }); // 取消按钮点击事件 messageBox.querySelector('.cancel-btn').addEventListener('click', () => { this.removeCustomMessage(); }); // 遮罩层点击事件 overlay.addEventListener('click', () => { this.removeCustomMessage(); }); } catch (error) { console.error('获取标准列表失败:', error); this.showSimpleMessage('获取标准列表失败,请稍后重试'); } }, // PPBZDYDJ方法 - 调用服务处理标准电压匹配 async PPBZDYDJ(sMRXLBZID) { try { // 构建Product列表 const items = this.buildProductList(); // 构建服务参数 const serviceParams = { '-RefUmId': 102855005, 'items': items.map(item => item.toJSON()), // 转换为JSON格式 'sBJDID': BJDID || '', // 使用全局BJDID 'sMRXLBZID': sMRXLBZID }; // 调用PPBZDYDJ服务 const result = await this.callService('PPBZDYDJ', serviceParams); if (result && Array.isArray(result)) { // 调用成功,更新表格数据 this.updateTableWithResult(result); this.showSimpleMessage('标准电压匹配成功'); } else { // 返回结果不是数组,可能是错误或空结果 console.warn('服务返回结果不是预期的List格式'); this.showSimpleMessage('标准电压匹配完成,但返回结果格式有误'); } } catch (error) { console.error('PPBZDYDJ服务调用失败:', error); this.showSimpleMessage('标准电压匹配失败,表格数据保持不变'); // 失败时表格数据保持不变,不抛出错误 throw error; } }, // 根据服务返回结果更新表格 updateTableWithResult(resultList) { if (!resultList || !Array.isArray(resultList)) { console.warn('无效的返回结果,无法更新表格'); return; } const newRowData = resultList.map(product => { let productObj; if (typeof product === 'object' && product !== null) { productObj = product; } else if (typeof product === 'string') { try { productObj = JSON.parse(product); } catch (e) { console.warn('无法解析Product字符串:', product); productObj = {}; } } else { productObj = {}; } return { quoteProduct: productObj.QuoteProduct || productObj.quoteProduct || '', model: productObj.Model || productObj.model || '', specification: productObj.Specification || productObj.specification || '', standard: productObj.Standard || productObj.standard || '', voltage: productObj.Voltage || productObj.voltage || '', unit: productObj.Unit || productObj.unit || '', quantity: parseFloat(productObj.Quantity || productObj.quantity || 0) }; }); this.rowData = newRowData; if (this.gridApi) { this.gridApi.setRowData(newRowData); } }, // 开始进度条 // 构建Product列表 buildProductList() { const items = []; this.rowData.forEach((rowData, index) => { const product = new Product(); product.SerialNumber = index + 1; product.QuoteProduct = rowData.quoteProduct || ''; product.Model = rowData.model || ''; product.Specification = rowData.specification || ''; product.Standard = rowData.standard || ''; product.Voltage = rowData.voltage || ''; product.Unit = rowData.unit || ''; product.Quantity = parseFloat(rowData.quantity) || 0; items.push(product); }); return items; }, // GetXLBZ方法 - 获取标准列表 async GetXLBZ() { try { // 构建服务参数(GetXLBZ方法通常不需要额外参数) const serviceParams = { '-RefUmId': 102855005 }; // 调用GetXLBZ服务 const result = await this.callService('GetXLBZ', serviceParams); // 处理返回结果,确保是Dictionary格式 let standardDict; if (result && typeof result === 'object') { // 如果返回的是对象,直接使用 standardDict = result; } else if (typeof result === 'string') { // 如果是字符串,尝试解析JSON try { standardDict = JSON.parse(result); } catch (parseError) { console.warn('无法解析GetXLBZ返回的字符串:', result); throw new Error('标准列表格式错误'); } } else { console.warn('GetXLBZ返回结果格式异常:', result); throw new Error('获取标准列表失败'); } // 保存标准字典数据供表格显示使用 this.standardDictionary = standardDict; return standardDict; } catch (error) { console.error('GetXLBZ服务调用失败:', error); throw error; } }, // GetDYDJ方法 - 获取电压等级列表 async GetDYDJ() { try { // 构建服务参数(GetDYDJ方法通常不需要额外参数) const serviceParams = { '-RefUmId': 102855005 }; // 调用GetDYDJ服务 const result = await this.callService('GetDYDJ', serviceParams); // 处理返回结果,确保是List格式 let voltageLevels; if (result && Array.isArray(result)) { // 如果返回的是数组,直接使用 voltageLevels = result; } else if (typeof result === 'string') { // 如果是字符串,尝试解析JSON try { voltageLevels = JSON.parse(result); if (!Array.isArray(voltageLevels)) { throw new Error('返回结果不是数组格式'); } } catch (parseError) { console.warn('无法解析GetDYDJ返回的字符串:', result); throw new Error('电压等级列表格式错误'); } } else { console.warn('GetDYDJ返回结果格式异常:', result); throw new Error('获取电压等级列表失败'); } // 保存电压等级列表数据供表格显示使用 this.voltageLevels = voltageLevels; return voltageLevels; } catch (error) { console.error('GetDYDJ服务调用失败:', error); throw error; } }, // 通用服务调用方法 /** * 通用服务调用方法 * @param {string} methodName - 服务方法名称 * @param {Object} params - 调用参数 * @param {Object} options - 选项配置 * @returns {Promise} 调用结果 */ async callService(methodName, params = {}, options = {}) { if (!methodName || typeof methodName !== 'string') { console.error('callService: methodName 不能为空'); throw new Error('服务方法名称不能为空'); } const methodTimeouts = { 'GetXLBZ': 30000, 'GetDYDJ': 30000, 'InsertBJDMX': 120000, 'PPBZDYDJ': 120000, 'JXBJCP': 120000 }; try { GThinking.Web.AjaxServiceProxy.servicePath = 'S_XLXSBJ/102373013.ashx'; const defaultOptions = { refUmId: 102855005, timeout: methodTimeouts[methodName] || 60000, isAsync: false }; const mergedOptions = { ...defaultOptions, ...options }; const result = await new Promise((resolve, reject) => { GThinking.Web.AjaxServiceProxy.invoke( methodName, mergedOptions.isAsync, params, (data) => resolve(data), (error) => reject(error), methodName, mergedOptions.timeout ); }); return result; } catch (error) { console.error(`服务调用失败 [${methodName}]:`, error); throw error; } } } }); // 使用Element Plus app.use(ElementPlus); // 挂载应用 app.mount('#app');