From 536b4fee0bf69ffecfd1a783161d899dde86fdc5 Mon Sep 17 00:00:00 2001 From: user9994793890 <3722323274763196-user9994793890@noreply.coze.cn> Date: Mon, 13 Jul 2026 16:17:11 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E9=87=8D=E6=96=B0=E6=95=B4=E7=90=86=20J?= =?UTF-8?q?S=20=E6=96=87=E4=BB=B6=E8=81=8C=E8=B4=A3=E5=88=92=E5=88=86?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8D=E6=8C=89=E9=92=AE=E7=82=B9=E5=87=BB?= =?UTF-8?q?=E6=97=A0=E5=93=8D=E5=BA=94=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coze-Commit-Type: user Coze-User-ID: 3722323274763196 Coze-Conversation-ID: 9894087 --- public/static/js/common.js | 431 +++---------------------------------- public/static/js/config.js | 50 +++++ 2 files changed, 80 insertions(+), 401 deletions(-) diff --git a/public/static/js/common.js b/public/static/js/common.js index 9bc381f..f5b332a 100644 --- a/public/static/js/common.js +++ b/public/static/js/common.js @@ -4,6 +4,7 @@ window.onerror = function(msg, url, line, col, error) { return true; // 阻止错误传播 }; +// 全局变量 let editingConfigId = null; let allFields = []; let currentPage = 1; @@ -13,416 +14,44 @@ let currentSearch = ''; let entityPage = 1; let entityPageSize = 20; let selectedEntityIds = new Set(); - -async function loadConfigs() { - try { - const response = await fetch('/api/config'); - const result = await response.json(); - - if (result.success) { - renderConfigList(result.data); - } else { - alert('加载配置失败: ' + result.message); - } - } catch (error) { - alert('加载配置失败: ' + error.message); - } -} - -// 渲染配置列表 -function renderConfigList(configs) { - const tbody = document.getElementById('config-list'); - - if (configs.length === 0) { - tbody.innerHTML = '暂无配置,请点击"创建配置"按钮'; - return; - } - - tbody.innerHTML = configs.map(config => ` - - ${config.config_name} - ${config.split_type === 'company_id' ? '按企业ID' : '按用户ID'} - ${config.split_name || config.split_value} - ${config.selected_fields.length} - - - ${config.is_active ? '已启用' : '已禁用'} - - - -
- - - - - - -
- - - `).join(''); -} - -// 显示创建模态框 -function showCreateModal() { - editingConfigId = null; - document.getElementById('modal-title').textContent = '创建配置'; - document.getElementById('config-name').value = ''; - document.getElementById('split-type').value = ''; - document.getElementById('split-value').innerHTML = ''; - - // 重置字段自定义名头 - fieldCustomNames = {}; - - // 重置合并特来电配置 - const mergeTelecomCheckbox = document.getElementById('merge-telecom'); - const telecomVehicleNoInput = document.getElementById('telecom-vehicle-no'); - const mergeTelecomGroup = document.getElementById('merge-telecom-group'); - if (mergeTelecomCheckbox) mergeTelecomCheckbox.checked = false; - if (telecomVehicleNoInput) telecomVehicleNoInput.value = ''; - if (mergeTelecomGroup) mergeTelecomGroup.style.display = 'none'; - toggleTelecomVehicleNo(); - - loadFields(); - initTimePeriodEditor(); - clearAllTimePeriods(); - document.getElementById('config-modal').classList.add('active'); -} - -// 加载字段列表 -async function loadFields(selectedFields = [], sumFields = []) { - try { - const response = await fetch('/api/fields'); - const result = await response.json(); - - if (result.success) { - allFields = result.data; - renderFields(selectedFields, sumFields); - } - } catch (error) { - console.error('加载字段失败:', error); - } -} - -// 可求和的数值类型字段 -const SUMMABLE_FIELD_KEYS = [ - 'charge_degree', 'charge_ah', 'charge_begin_soc', 'charge_end_soc', - 'receivable_electric_fee', 'receivable_service_fee', 'receivable_total_fee', - 'charge_elecfee_amount', 'charge_elecfee_cost_amount', 'charge_service_amount', - 'charging_amt', 'actual_pay_amount', 'pay_amount', - 'settle_electric_fee', 'settle_service_fee', 'settle_fee', - 'coupon_amount', 'coupon_total_amount', 'elecfee_coupon_amount', 'servicefee_coupon_amount', - 'invoice_fee', 'activity_electric_fee', 'activity_service_fee', 'activity_total_fee', - 'total_money', - // 分时段电量 - 'sharp_electricity', 'peak_electricity', 'flat_electricity', 'valley_electricity' -]; - -// 渲染字段列表 -function renderFields(selectedFields = [], sumFields = []) { - const fieldsList = document.getElementById('fields-list'); - const sumFieldsList = document.getElementById('sum-fields-list'); - - fieldsList.innerHTML = allFields.map(field => { - const isSelected = selectedFields.includes(field.key); - const isRequired = field.key === 'charge_degree'; // 充电量为必选字段 - return ` -
- - -
- `; - }).join(''); - - // 初始化求和字段列表(只显示已选字段中的可求和字段) - refreshSumFieldsList(selectedFields, sumFields); -} - -// 点击 checkbox-item 容器时切换选中状态 -function toggleCheckboxItem(item) { - const cb = item.querySelector('input[type="checkbox"]'); - if (event.target === cb) return; // 如果点击的就是 checkbox 本身,不重复触发 - cb.checked = !cb.checked; - item.classList.toggle('checked', cb.checked); - onFieldCheckboxChange(cb); -} - -// 字段 checkbox 变化时更新求和字段列表和已选字段顺序 -function onFieldCheckboxChange(cb) { - // 防止取消选择必选字段(充电量) - if (cb.value === 'charge_degree' && !cb.checked) { - cb.checked = true; - return; - } - - const item = cb.closest('.checkbox-item'); - if (item) item.classList.toggle('checked', cb.checked); - - const fieldsList = document.getElementById('fields-list'); - const checkedFields = Array.from(fieldsList.querySelectorAll('input:checked')).map(c => c.value); - - // 保留当前求和字段的选择状态 - const sumFieldsList = document.getElementById('sum-fields-list'); - const currentSumFields = sumFieldsList ? Array.from(sumFieldsList.querySelectorAll('input:checked')).map(c => c.value) : []; - - refreshSumFieldsList(checkedFields, currentSumFields); - refreshSelectedFieldsOrder(checkedFields); -} - -// 字段自定义名头存储 let fieldCustomNames = {}; -// 刷新已选字段顺序列表 -function refreshSelectedFieldsOrder(selectedFields, customNames = null) { - const orderGroup = document.getElementById('selected-fields-order-group'); - const orderList = document.getElementById('selected-fields-order'); - if (!orderList) return; +// 标签切换 +function switchTab(tabName) { + document.querySelectorAll('.tab').forEach(t => t.classList.remove('active')); + document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active')); - // 如果传入了自定义名头,更新全局变量 - if (customNames !== null) { - fieldCustomNames = {...customNames}; - } + document.querySelector(`.tab[onclick="switchTab('${tabName}')"]`).classList.add('active'); + document.getElementById(`${tabName}-tab`).classList.add('active'); - // 根据是否有已选字段,显示/隐藏字段顺序区域 - if (orderGroup) { - orderGroup.style.display = selectedFields.length > 0 ? 'block' : 'none'; - } - - if (selectedFields.length === 0) { - orderList.innerHTML = '请先在上方勾选字段'; - } else { - orderList.innerHTML = selectedFields.map((fieldKey, index) => { - const field = allFields.find(f => f.key === fieldKey); - const displayName = field ? field.display : fieldKey; - const customName = fieldCustomNames[fieldKey] || ''; - const isFirst = index === 0; - const isLast = index === selectedFields.length - 1; - return ` -
- #${index + 1} - ${displayName} - -
- - -
-
- `; - }).join(''); + if (tabName === 'config') { + loadConfigs(); + } else if (tabName === 'generate') { + loadGenerateConfigs(); + } else if (tabName === 'history') { + loadHistory(); } } -// 更新字段自定义名头 -function updateFieldCustomName(fieldKey, customName) { - if (customName && customName.trim()) { - fieldCustomNames[fieldKey] = customName.trim(); - } else { - delete fieldCustomNames[fieldKey]; - } +// 格式化日期时间 +function formatDateTime(dateStr) { + if (!dateStr) return ''; + const date = new Date(dateStr); + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } -// 获取字段自定义名头 -function getFieldCustomNames() { - return {...fieldCustomNames}; +// 显示错误提示 +function showError(message) { + alert('错误:' + message); } -// 字段上移 -function moveFieldUp(index) { - if (index <= 0) return; - const orderList = document.getElementById('selected-fields-order'); - const items = Array.from(orderList.querySelectorAll('.selected-field-item')); - const item = items[index]; - const prevItem = items[index - 1]; - orderList.insertBefore(item, prevItem); - updateFieldIndexes(); +// 显示成功提示 +function showSuccess(message) { + alert('成功:' + message); } - -// 字段下移 -function moveFieldDown(index) { - const orderList = document.getElementById('selected-fields-order'); - const items = Array.from(orderList.querySelectorAll('.selected-field-item')); - if (index >= items.length - 1) return; - const item = items[index]; - const nextItem = items[index + 1]; - orderList.insertBefore(nextItem, item); - updateFieldIndexes(); -} - -// 更新字段序号 -function updateFieldIndexes() { - const orderList = document.getElementById('selected-fields-order'); - const items = orderList.querySelectorAll('.selected-field-item'); - items.forEach((item, index) => { - const indexSpan = item.querySelector('.field-index'); - if (indexSpan) indexSpan.textContent = `#${index + 1}`; - - // 更新按钮状态 - const upBtn = item.querySelector('.btn-move[title="上移"]'); - const downBtn = item.querySelector('.btn-move[title="下移"]'); - if (upBtn) upBtn.disabled = index === 0; - if (downBtn) downBtn.disabled = index === items.length - 1; - }); -} - -// 获取当前字段顺序 -function getSelectedFieldsOrder() { - const orderList = document.getElementById('selected-fields-order'); - if (!orderList) return []; - const items = orderList.querySelectorAll('.selected-field-item'); - return Array.from(items).map(item => item.dataset.field); -} - -// 刷新求和字段列表(仅显示已选字段中的数值类型字段) -function refreshSumFieldsList(selectedFields, currentSumFields) { - const sumFieldsList = document.getElementById('sum-fields-list'); - const availableSumFields = allFields.filter(f => - selectedFields.includes(f.key) && SUMMABLE_FIELD_KEYS.includes(f.key) - ); - - if (availableSumFields.length === 0) { - sumFieldsList.innerHTML = '请先在上方勾选数值类型的字段'; - } else { - sumFieldsList.innerHTML = availableSumFields.map(field => ` -
- - -
- `).join(''); - } -} - -// 切换特来电车量自编号输入框显示 -function toggleTelecomVehicleNo() { - const mergeTelecom = document.getElementById('merge-telecom').checked; - const vehicleNoGroup = document.getElementById('telecom-vehicle-no-group'); - if (vehicleNoGroup) { - vehicleNoGroup.style.display = mergeTelecom ? 'block' : 'none'; - } -} - -// 更新已选实体计数 -function updateSelectedCount() { - const select = document.getElementById('split-value'); - const countEl = document.getElementById('selected-entity-count'); - const count = select.selectedOptions.length; - if (count > 0) { - countEl.textContent = '已选 ' + count + ' 项'; - countEl.style.display = 'inline'; - } else { - countEl.style.display = 'none'; - } -} - -// ========== 时段编辑器 ========== -const TIME_PERIODS = [ - { key: 'sharp', label: '尖', color: '#e74c3c' }, - { key: 'peak', label: '峰', color: '#f39c12' }, - { key: 'flat', label: '平', color: '#27ae60' }, - { key: 'valley', label: '谷', color: '#3498db' } -]; - -// 时段配置: { sharp: [11,12], peak: [9,10], flat: [7,8], valley: [0,1,2,3] } -let timePeriodConfig = { sharp: [], peak: [], flat: [], valley: [] }; -let currentTpTool = 'select'; // 'select' or period key - -// 初始化时段编辑器 -function initTimePeriodEditor() { - const hoursRow = document.getElementById('tp-hours-row'); - const periodRows = document.getElementById('tp-period-rows'); - - // 渲染小时标题行 - let hoursHtml = ''; - for (let h = 0; h < 24; h++) { - hoursHtml += `
${h}
`; - } - hoursRow.innerHTML = hoursHtml; - - // 渲染时段行 - let rowsHtml = ''; - TIME_PERIODS.forEach(period => { - rowsHtml += ` -
-
${period.label}时
-
- ${Array.from({length: 24}, (_, h) => - `
` - ).join('')} -
-
- `; - }); - periodRows.innerHTML = rowsHtml; - - updateTimePeriodSummary(); -} - -// 切换时段格子 -function toggleTimePeriodCell(hour, periodKey) { - console.log('toggleTimePeriodCell called:', hour, periodKey); - // 检查该小时是否已被其他时段占用 - const occupiedBy = Object.entries(timePeriodConfig).find(([k, v]) => k !== periodKey && v.includes(hour)); - - if (occupiedBy) { - // 已被其他时段占用,移除占用并分配给当前时段 - const [otherKey] = occupiedBy; - timePeriodConfig[otherKey] = timePeriodConfig[otherKey].filter(h => h !== hour); - updateCellDisplay(hour, otherKey); - } - - // 切换当前时段 - if (timePeriodConfig[periodKey].includes(hour)) { - timePeriodConfig[periodKey] = timePeriodConfig[periodKey].filter(h => h !== hour); - } else { - timePeriodConfig[periodKey].push(hour); - timePeriodConfig[periodKey].sort((a, b) => a - b); - } - - updateCellDisplay(hour, periodKey); - updateTimePeriodSummary(); -} - -// 更新格子显示 -function updateCellDisplay(hour, periodKey) { - // 清除所有时段中该小时的样式 - TIME_PERIODS.forEach(p => { - const cell = document.querySelector(`.tp-cell[data-hour="${hour}"][data-period="${p.key}"]`); - if (cell) { - cell.className = 'tp-cell'; - cell.textContent = ''; - } - }); - - // 检查该小时属于哪个时段,并设置对应的样式 - for (const p of TIME_PERIODS) { - if (timePeriodConfig[p.key].includes(hour)) { - const cell = document.querySelector(`.tp-cell[data-hour="${hour}"][data-period="${p.key}"]`); - if (cell) { - cell.classList.add(p.key); - cell.textContent = '✓'; - } - break; // 每个小时只能属于一个时段 - } - } -} - -// 更新时段摘要 -function updateTimePeriodSummary() { - const summaryEl = document.getElementById('tp-summary'); - const parts = TIME_PERIODS.map(p => { - const hours = timePeriodConfig[p.key]; - const count = hours.length; - const hoursStr = count > 0 ? hours.map(h => `${h}时`).join(',') : '未设置'; - return `${p.label}时: ${count}个 (${hoursStr})`; - }); - summaryEl.innerHTML = parts.join(''); -} - -// 设置时段配置(编辑时加载) diff --git a/public/static/js/config.js b/public/static/js/config.js index c092833..14dfe8a 100644 --- a/public/static/js/config.js +++ b/public/static/js/config.js @@ -1,3 +1,53 @@ +// 加载配置列表 +async function loadConfigs() { + try { + const response = await fetch('/api/config'); + const result = await response.json(); + + if (result.success) { + renderConfigList(result.data); + } else { + alert('加载配置失败:' + result.message); + } + } catch (error) { + alert('加载配置失败:' + error.message); + } +} + +// 渲染配置列表 +function renderConfigList(configs) { + const tbody = document.getElementById('config-list'); + + if (configs.length === 0) { + tbody.innerHTML = '暂无配置,请点击"创建配置"按钮'; + return; + } + + tbody.innerHTML = configs.map(config => ` + + ${config.config_name} + ${config.split_type === 'company_id' ? '按企业 ID' : config.split_type === 'user_id' ? '按用户 ID' : '按场站 ID'} + ${config.split_name || config.split_value} + ${config.selected_fields.length} + + + ${config.is_active ? '已启用' : '已禁用'} + + + + + + + + + + + + `).join(''); +} + function showCreateModal() { editingConfigId = null; document.getElementById('modal-title').textContent = '创建配置';