修复编辑配置,保存和回显的问题

This commit is contained in:
2026-07-15 14:35:03 +08:00
parent 96cca34de0
commit d34dd82bd5
5 changed files with 125 additions and 41 deletions

View File

@@ -129,7 +129,7 @@ FIELD_MAPPING = {
# 订单完成信息 # 订单完成信息
'finish_type': '完成类型', 'finish_type': '完成类型',
'finish_code': '完成代码', 'finish_code': '完成代码',
'finish_msg': '完成消息', 'finish_msg': '结束原因',
'finish_time': '完成时间', 'finish_time': '完成时间',
# 取消信息 # 取消信息

View File

@@ -397,6 +397,18 @@ font-weight: 500;
margin-left: 4px; margin-left: 4px;
} }
.field-key-name {
color: #999;
font-size: 12px;
font-family: Consolas, Monaco, monospace;
font-weight: normal;
}
.entity-selected-top {
border-left: 3px solid #4472C4;
padding-left: 7px;
}
.checkbox-item input[type="checkbox"] { .checkbox-item input[type="checkbox"] {
width: 16px; width: 16px;
height: 16px; height: 16px;

View File

@@ -62,6 +62,8 @@ function showCreateModal() {
document.getElementById('modal-title').textContent = '创建配置'; document.getElementById('modal-title').textContent = '创建配置';
document.getElementById('config-name').value = ''; document.getElementById('config-name').value = '';
document.getElementById('split-type').value = ''; document.getElementById('split-type').value = '';
// 清空已选实体
selectedEntityIds.clear();
// 清空实体列表 // 清空实体列表
document.getElementById('entity-list').innerHTML = '<div class="empty">请先选择拆分方式</div>'; document.getElementById('entity-list').innerHTML = '<div class="empty">请先选择拆分方式</div>';
document.getElementById('entity-search').value = ''; document.getElementById('entity-search').value = '';
@@ -141,7 +143,7 @@ function renderFields(selectedFields = [], sumFields = []) {
${isSelected ? 'checked' : ''} ${isSelected ? 'checked' : ''}
${isRequired ? 'disabled checked' : ''} ${isRequired ? 'disabled checked' : ''}
onchange="onFieldCheckboxChange(this)"> onchange="onFieldCheckboxChange(this)">
<label>${field.display}${isRequired ? ' <span class="required-badge">必选</span>' : ''}</label> <label>${field.display} <span class="field-key-name">(${field.key})</span>${isRequired ? ' <span class="required-badge">必选</span>' : ''}</label>
</div> </div>
`; `;
}).join(''); }).join('');
@@ -209,13 +211,13 @@ function refreshSelectedFieldsOrder(selectedFields, customNames = null) {
return ` return `
<div class="selected-field-item" data-field="${fieldKey}"> <div class="selected-field-item" data-field="${fieldKey}">
<span class="field-index">#${index + 1}</span> <span class="field-index">#${index + 1}</span>
<span class="field-name" title="${displayName}">${displayName}</span> <span class="field-name" title="${displayName}">${displayName} <span class="field-key-name">(${fieldKey})</span></span>
<input type="text" class="field-custom-name" placeholder="自定义报表名头" value="${customName}" <input type="text" class="field-custom-name" placeholder="自定义报表名头" value="${customName}"
onchange="updateFieldCustomName('${fieldKey}', this.value)" onchange="updateFieldCustomName('${fieldKey}', this.value)"
style="flex: 1; min-width: 100px; padding: 4px 8px; font-size: 12px;"> style="flex: 1; min-width: 100px; padding: 4px 8px; font-size: 12px;">
<div class="field-actions"> <div class="field-actions">
<button type="button" class="btn-move" onclick="moveFieldUp(${index})" ${isFirst ? 'disabled' : ''} title="上移">↑</button> <button type="button" class="btn-move" onclick="moveFieldUp('${fieldKey}')" ${isFirst ? 'disabled' : ''} title="上移">↑</button>
<button type="button" class="btn-move" onclick="moveFieldDown(${index})" ${isLast ? 'disabled' : ''} title="下移">↓</button> <button type="button" class="btn-move" onclick="moveFieldDown('${fieldKey}')" ${isLast ? 'disabled' : ''} title="下移">↓</button>
</div> </div>
</div> </div>
`; `;
@@ -238,10 +240,12 @@ function getFieldCustomNames() {
} }
// 字段上移 // 字段上移
function moveFieldUp(index) { function moveFieldUp(fieldKey) {
if (index <= 0) return;
const orderList = document.getElementById('selected-fields-order'); const orderList = document.getElementById('selected-fields-order');
const items = Array.from(orderList.querySelectorAll('.selected-field-item')); const items = Array.from(orderList.querySelectorAll('.selected-field-item'));
const index = items.findIndex(item => item.dataset.field === fieldKey);
if (index <= 0) return;
const item = items[index]; const item = items[index];
const prevItem = items[index - 1]; const prevItem = items[index - 1];
orderList.insertBefore(item, prevItem); orderList.insertBefore(item, prevItem);
@@ -249,10 +253,12 @@ function moveFieldUp(index) {
} }
// 字段下移 // 字段下移
function moveFieldDown(index) { function moveFieldDown(fieldKey) {
const orderList = document.getElementById('selected-fields-order'); const orderList = document.getElementById('selected-fields-order');
const items = Array.from(orderList.querySelectorAll('.selected-field-item')); const items = Array.from(orderList.querySelectorAll('.selected-field-item'));
if (index >= items.length - 1) return; const index = items.findIndex(item => item.dataset.field === fieldKey);
if (index < 0 || index >= items.length - 1) return;
const item = items[index]; const item = items[index];
const nextItem = items[index + 1]; const nextItem = items[index + 1];
orderList.insertBefore(nextItem, item); orderList.insertBefore(nextItem, item);
@@ -297,7 +303,7 @@ function refreshSumFieldsList(selectedFields, currentSumFields) {
<div class="checkbox-item ${currentSumFields.includes(field.key) ? 'checked' : ''}" onclick="toggleCheckboxItem(this)"> <div class="checkbox-item ${currentSumFields.includes(field.key) ? 'checked' : ''}" onclick="toggleCheckboxItem(this)">
<input type="checkbox" value="${field.key}" <input type="checkbox" value="${field.key}"
${currentSumFields.includes(field.key) ? 'checked' : ''}> ${currentSumFields.includes(field.key) ? 'checked' : ''}>
<label>${field.display}</label> <label>${field.display} <span class="field-key-name">(${field.key})</span></label>
</div> </div>
`).join(''); `).join('');
} }
@@ -465,14 +471,43 @@ async function saveConfig() {
// 处理多选:从 selectedEntityIds 获取选中的实体 // 处理多选:从 selectedEntityIds 获取选中的实体
const splitValue = Array.from(selectedEntityIds).join(','); const splitValue = Array.from(selectedEntityIds).join(',');
// 获取选中实体的名称(需要从 DOM 中获取) // 通过 API 查询所有已选实体的名称(确保翻页后也能正确获取)
const container = document.getElementById('entity-list'); let splitName = '';
const checkboxes = container.querySelectorAll('input[type="checkbox"]:checked'); if (selectedEntityIds.size > 0) {
const splitName = Array.from(checkboxes).map(cb => { const entityType = splitType === 'company_id' ? 'company' :
const item = cb.closest('.checkbox-item'); splitType === 'user_id' ? 'user' : 'station';
const span = item.querySelector('span'); try {
return span ? span.textContent.trim() : ''; const response = await fetch('/api/entities/by_ids', {
}).join(','); method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ type: entityType, ids: Array.from(selectedEntityIds) })
});
const result = await response.json();
if (result.success && result.data) {
const idSet = new Set(Array.from(selectedEntityIds));
const sortedEntities = result.data.filter(e => {
const value = splitType === 'company_id' ? e.company_id :
splitType === 'user_id' ? e.user_id : e.station_id;
return idSet.has(String(value));
}).sort((a, b) => {
const aVal = splitType === 'company_id' ? a.company_id :
splitType === 'user_id' ? a.user_id : a.station_id;
const bVal = splitType === 'company_id' ? b.company_id :
splitType === 'user_id' ? b.user_id : b.station_id;
const aIdx = Array.from(selectedEntityIds).indexOf(String(aVal));
const bIdx = Array.from(selectedEntityIds).indexOf(String(bVal));
return aIdx - bIdx;
});
splitName = sortedEntities.map(e => {
if (splitType === 'company_id') return e.company_name;
if (splitType === 'user_id') return e.user_name;
return e.station_name;
}).join(',');
}
} catch (err) {
console.error('获取实体名称失败:', err);
}
}
// 获取字段顺序(从已选字段顺序列表获取) // 获取字段顺序(从已选字段顺序列表获取)
const selectedFields = getSelectedFieldsOrder(); const selectedFields = getSelectedFieldsOrder();
@@ -747,8 +782,9 @@ async function loadEntitiesForEdit(splitType, selectedValues) {
container.innerHTML = mergedEntities.map(item => { container.innerHTML = mergedEntities.map(item => {
const isChecked = item.isSelected ? 'checked' : ''; const isChecked = item.isSelected ? 'checked' : '';
const checkedClass = item.isSelected ? 'checked' : ''; const checkedClass = item.isSelected ? 'checked' : '';
const topClass = item.isSelected ? 'entity-selected-top' : '';
return ` return `
<div class="checkbox-item ${checkedClass}" onclick="toggleEntityCheckbox(this, '${item.value}')"> <div class="checkbox-item ${checkedClass} ${topClass}" onclick="toggleEntityCheckbox(this, '${item.value}')">
<input type="checkbox" value="${item.value}" ${isChecked} onclick="event.stopPropagation()"> <input type="checkbox" value="${item.value}" ${isChecked} onclick="event.stopPropagation()">
<span>${item.name} ${item.typeLabel}</span> <span>${item.name} ${item.typeLabel}</span>
</div> </div>
@@ -882,6 +918,7 @@ async function moveConfig(configId, direction) {
// 关闭模态框 // 关闭模态框
function closeModal() { function closeModal() {
document.getElementById('config-modal').classList.remove('active'); document.getElementById('config-modal').classList.remove('active');
selectedEntityIds.clear();
} }
@@ -902,16 +939,6 @@ function setDefaultTimePeriods() {
updateTimePeriodSummary(); updateTimePeriodSummary();
} }
// 拆分方式改变时加载实体列表
function onSplitTypeChange() {
const splitType = document.getElementById('split-type').value;
if (splitType) {
loadEntities(1, '');
} else {
document.getElementById('entity-list').innerHTML = '<div class="empty">请先选择拆分方式</div>';
}
}
// 导出配置 // 导出配置
function exportConfigs() { function exportConfigs() {
try { try {

View File

@@ -42,7 +42,9 @@ async function loadEntities(page = 1, search = '') {
if (entities.length === 0) { if (entities.length === 0) {
container.innerHTML = '<div class="empty">无数据</div>'; container.innerHTML = '<div class="empty">无数据</div>';
} else { } else {
container.innerHTML = entities.map(e => { const selected = [];
const unselected = [];
entities.forEach(e => {
let value = ''; let value = '';
let name = ''; let name = '';
let typeLabel = ''; let typeLabel = '';
@@ -62,11 +64,23 @@ async function loadEntities(page = 1, search = '') {
name = e.station_name; name = e.station_name;
} }
const isChecked = selectedEntityIds.has(String(value)) ? 'checked' : ''; const item = { value, name, typeLabel };
if (selectedEntityIds.has(String(value))) {
selected.push(item);
} else {
unselected.push(item);
}
});
const sortedEntities = [...selected, ...unselected];
container.innerHTML = sortedEntities.map(e => {
const isChecked = selectedEntityIds.has(String(e.value)) ? 'checked' : '';
const isSelectedTop = selectedEntityIds.has(String(e.value));
return ` return `
<div class="checkbox-item ${isChecked}" onclick="toggleEntityCheckbox(this, '${value}')"> <div class="checkbox-item ${isChecked} ${isSelectedTop ? 'entity-selected-top' : ''}" onclick="toggleEntityCheckbox(this, '${e.value}')">
<input type="checkbox" value="${value}" ${isChecked} onclick="event.stopPropagation()"> <input type="checkbox" value="${e.value}" ${isChecked} onclick="event.stopPropagation()">
<span>${name} ${typeLabel}</span> <span>${e.name} ${e.typeLabel}</span>
</div> </div>
`; `;
}).join(''); }).join('');
@@ -89,15 +103,45 @@ function toggleEntityCheckbox(item, value) {
if (checkbox.checked) { if (checkbox.checked) {
item.classList.add('checked'); item.classList.add('checked');
item.classList.add('entity-selected-top');
selectedEntityIds.add(String(value)); selectedEntityIds.add(String(value));
} else { } else {
item.classList.remove('checked'); item.classList.remove('checked');
item.classList.remove('entity-selected-top');
selectedEntityIds.delete(String(value)); selectedEntityIds.delete(String(value));
} }
updateSelectedCount(); updateSelectedCount();
} }
// 重新排序列表(已选的在前面)
function reorderEntityList() {
const container = document.getElementById('entity-list');
const items = Array.from(container.querySelectorAll('.checkbox-item'));
if (items.length === 0) return;
const selected = [];
const unselected = [];
items.forEach(item => {
const checkbox = item.querySelector('input[type="checkbox"]');
if (checkbox.checked) {
selected.push(item);
item.classList.add('entity-selected-top');
} else {
unselected.push(item);
item.classList.remove('entity-selected-top');
}
});
// 用文档片段移动,避免 innerHTML 清空导致状态丢失
const fragment = document.createDocumentFragment();
[...selected, ...unselected].forEach(item => {
fragment.appendChild(item);
});
container.appendChild(fragment);
}
// 更新已选数量显示 // 更新已选数量显示
function updateSelectedCount() { function updateSelectedCount() {
const countSpan = document.getElementById('selected-count'); const countSpan = document.getElementById('selected-count');
@@ -125,6 +169,7 @@ function toggleSelectAllEntities() {
}); });
updateSelectedCount(); updateSelectedCount();
reorderEntityList();
} }
// 更新实体分页UI // 更新实体分页UI

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>订单日报系统</title> <title>订单日报系统</title>
<link rel="stylesheet" href="/public/static/css/style.css?v=2026071502"> <link rel="stylesheet" href="/public/static/css/style.css?v=2026071506">
</head> </head>
<body> <body>
<div class="container"> <div class="container">
@@ -350,11 +350,11 @@
</div> </div>
<!-- JavaScript 文件 --> <!-- JavaScript 文件 -->
<script src="/public/static/js/common.js?v=2026071502"></script> <script src="/public/static/js/common.js?v=2026071506"></script>
<script src="/public/static/js/config.js?v=2026071502"></script> <script src="/public/static/js/config.js?v=2026071506"></script>
<script src="/public/static/js/entity.js?v=2026071502"></script> <script src="/public/static/js/entity.js?v=2026071506"></script>
<script src="/public/static/js/report.js?v=2026071502"></script> <script src="/public/static/js/report.js?v=2026071506"></script>
<script src="/public/static/js/history.js?v=2026071502"></script> <script src="/public/static/js/history.js?v=2026071506"></script>
<script src="/public/static/js/sum_data.js?v=2026071502"></script> <script src="/public/static/js/sum_data.js?v=2026071506"></script>
</body> </body>
</html> </html>