feat: 添加字段顺序调整功能,支持拖拽排序
Coze-Commit-Type: user Coze-User-ID: 3722323274763196 Coze-Conversation-ID: 9894087
This commit is contained in:
@@ -258,6 +258,65 @@
|
|||||||
background: #aaa;
|
background: #aaa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selected-fields-order {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 12px;
|
||||||
|
border: 1.5px dashed #4a90e2;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #f8fbff;
|
||||||
|
min-height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-field-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #e1e8ed;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: grab;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-field-item:hover {
|
||||||
|
border-color: #4a90e2;
|
||||||
|
box-shadow: 0 2px 4px rgba(74, 144, 226, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-field-item:active {
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-field-item.dragging {
|
||||||
|
opacity: 0.5;
|
||||||
|
border-color: #4a90e2;
|
||||||
|
background: #f0f7ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-field-item .drag-handle {
|
||||||
|
color: #999;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: grab;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-field-item .field-name {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-field-item .field-index {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #999;
|
||||||
|
background: #f0f0f0;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.checkbox-item {
|
.checkbox-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -919,12 +978,19 @@
|
|||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
<div class="form-section-title"><span class="section-num">4</span> 字段设置</div>
|
<div class="form-section-title"><span class="section-num">4</span> 字段设置</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>选择报表字段 <span class="form-hint">(勾选需要在报表中显示的字段)</span></label>
|
<label>选择报表字段 <span class="form-hint">(勾选需要在报表中显示的字段,拖拽已选字段调整顺序)</span></label>
|
||||||
<div class="checkbox-group" id="fields-list">
|
<div class="checkbox-group" id="fields-list">
|
||||||
<div class="loading">加载中...</div>
|
<div class="loading">加载中...</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" id="selected-fields-order-group" style="display:none;">
|
||||||
|
<label>字段顺序 <span class="form-hint">(拖拽调整报表中的列顺序)</span></label>
|
||||||
|
<div class="selected-fields-order" id="selected-fields-order">
|
||||||
|
<!-- 已选字段会显示在这里,可拖拽排序 -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>求和字段 <span class="form-hint">(仅显示已选字段中的数值类型,可多选)</span></label>
|
<label>求和字段 <span class="form-hint">(仅显示已选字段中的数值类型,可多选)</span></label>
|
||||||
<div class="checkbox-group" id="sum-fields-list">
|
<div class="checkbox-group" id="sum-fields-list">
|
||||||
@@ -1094,7 +1160,7 @@
|
|||||||
onFieldCheckboxChange(cb);
|
onFieldCheckboxChange(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 字段 checkbox 变化时更新求和字段列表
|
// 字段 checkbox 变化时更新求和字段列表和已选字段顺序
|
||||||
function onFieldCheckboxChange(cb) {
|
function onFieldCheckboxChange(cb) {
|
||||||
const item = cb.closest('.checkbox-item');
|
const item = cb.closest('.checkbox-item');
|
||||||
if (item) item.classList.toggle('checked', cb.checked);
|
if (item) item.classList.toggle('checked', cb.checked);
|
||||||
@@ -1102,6 +1168,88 @@
|
|||||||
const fieldsList = document.getElementById('fields-list');
|
const fieldsList = document.getElementById('fields-list');
|
||||||
const checkedFields = Array.from(fieldsList.querySelectorAll('input:checked')).map(c => c.value);
|
const checkedFields = Array.from(fieldsList.querySelectorAll('input:checked')).map(c => c.value);
|
||||||
refreshSumFieldsList(checkedFields, []);
|
refreshSumFieldsList(checkedFields, []);
|
||||||
|
refreshSelectedFieldsOrder(checkedFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刷新已选字段顺序列表
|
||||||
|
function refreshSelectedFieldsOrder(selectedFields) {
|
||||||
|
const orderList = document.getElementById('selected-fields-order');
|
||||||
|
if (!orderList) return;
|
||||||
|
|
||||||
|
if (selectedFields.length === 0) {
|
||||||
|
orderList.innerHTML = '<small style="color:#999;text-align:center;padding:8px;">请先在上方勾选字段</small>';
|
||||||
|
} else {
|
||||||
|
orderList.innerHTML = selectedFields.map((fieldKey, index) => {
|
||||||
|
const field = allFields.find(f => f.key === fieldKey);
|
||||||
|
const displayName = field ? field.display : fieldKey;
|
||||||
|
return `
|
||||||
|
<div class="selected-field-item" draggable="true" data-field="${fieldKey}">
|
||||||
|
<span class="drag-handle">☰</span>
|
||||||
|
<span class="field-name">${displayName}</span>
|
||||||
|
<span class="field-index">#${index + 1}</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
// 添加拖拽事件监听
|
||||||
|
initDragAndDrop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化拖拽排序
|
||||||
|
function initDragAndDrop() {
|
||||||
|
const orderList = document.getElementById('selected-fields-order');
|
||||||
|
const items = orderList.querySelectorAll('.selected-field-item');
|
||||||
|
let draggedItem = null;
|
||||||
|
|
||||||
|
items.forEach(item => {
|
||||||
|
item.addEventListener('dragstart', function(e) {
|
||||||
|
draggedItem = this;
|
||||||
|
setTimeout(() => this.classList.add('dragging'), 0);
|
||||||
|
e.dataTransfer.effectAllowed = 'move';
|
||||||
|
});
|
||||||
|
|
||||||
|
item.addEventListener('dragend', function() {
|
||||||
|
this.classList.remove('dragging');
|
||||||
|
draggedItem = null;
|
||||||
|
// 更新序号
|
||||||
|
updateFieldIndexes();
|
||||||
|
});
|
||||||
|
|
||||||
|
item.addEventListener('dragover', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.dataTransfer.dropEffect = 'move';
|
||||||
|
|
||||||
|
if (this !== draggedItem) {
|
||||||
|
const rect = this.getBoundingClientRect();
|
||||||
|
const midY = rect.top + rect.height / 2;
|
||||||
|
|
||||||
|
if (e.clientY < midY) {
|
||||||
|
orderList.insertBefore(draggedItem, this);
|
||||||
|
} else {
|
||||||
|
orderList.insertBefore(draggedItem, this.nextSibling);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新字段序号
|
||||||
|
function updateFieldIndexes() {
|
||||||
|
const orderList = document.getElementById('selected-fields-order');
|
||||||
|
const items = orderList.querySelectorAll('.selected-field-item');
|
||||||
|
items.forEach((item, index) => {
|
||||||
|
const indexEl = item.querySelector('.field-index');
|
||||||
|
if (indexEl) indexEl.textContent = `#${index + 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 刷新求和字段列表(仅显示已选字段中的数值类型字段)
|
// 刷新求和字段列表(仅显示已选字段中的数值类型字段)
|
||||||
@@ -1395,7 +1543,8 @@
|
|||||||
const splitValue = selectedOptions.map(opt => opt.value).join(',');
|
const splitValue = selectedOptions.map(opt => opt.value).join(',');
|
||||||
const splitName = selectedOptions.map(opt => opt.dataset.name || '').join(',');
|
const splitName = selectedOptions.map(opt => opt.dataset.name || '').join(',');
|
||||||
|
|
||||||
const selectedFields = Array.from(document.querySelectorAll('#fields-list input:checked')).map(cb => cb.value);
|
// 获取字段顺序(从已选字段顺序列表获取)
|
||||||
|
const selectedFields = getSelectedFieldsOrder();
|
||||||
const sumFields = Array.from(document.querySelectorAll('#sum-fields-list input:checked')).map(cb => cb.value);
|
const sumFields = Array.from(document.querySelectorAll('#sum-fields-list input:checked')).map(cb => cb.value);
|
||||||
|
|
||||||
// 获取时段配置
|
// 获取时段配置
|
||||||
@@ -1474,6 +1623,9 @@
|
|||||||
// 加载字段并回显选中状态
|
// 加载字段并回显选中状态
|
||||||
await loadFields(config.selected_fields, config.sum_fields);
|
await loadFields(config.selected_fields, config.sum_fields);
|
||||||
|
|
||||||
|
// 加载字段顺序
|
||||||
|
updateSelectedFieldsOrder();
|
||||||
|
|
||||||
// 初始化时段编辑器并加载配置
|
// 初始化时段编辑器并加载配置
|
||||||
initTimePeriodEditor();
|
initTimePeriodEditor();
|
||||||
setTimePeriodConfig(config.time_periods);
|
setTimePeriodConfig(config.time_periods);
|
||||||
|
|||||||
Reference in New Issue
Block a user