feat: 优化实体加载,添加分页和搜索功能
Coze-Commit-Type: user Coze-User-ID: 3722323274763196 Coze-Conversation-ID: 9894087
This commit is contained in:
81
app.py
81
app.py
@@ -259,28 +259,81 @@ def move_config(config_id):
|
||||
|
||||
@app.route('/api/entities', methods=['GET'])
|
||||
def get_entities():
|
||||
"""获取企业、用户或场站列表"""
|
||||
"""获取企业、用户或场站列表(支持分页和搜索)"""
|
||||
try:
|
||||
entity_type = request.args.get('type', 'company')
|
||||
page = int(request.args.get('page', 1))
|
||||
page_size = int(request.args.get('page_size', 100))
|
||||
search = request.args.get('search', '')
|
||||
|
||||
offset = (page - 1) * page_size
|
||||
|
||||
if entity_type == 'company':
|
||||
# 获取企业列表
|
||||
companies = execute_query(
|
||||
'SELECT id AS company_id, company_name FROM t_company WHERE company_state = "1" ORDER BY company_name'
|
||||
)
|
||||
return jsonify({'success': True, 'data': companies})
|
||||
if search:
|
||||
companies = execute_query(
|
||||
'SELECT id AS company_id, company_name FROM t_company WHERE company_state = "1" AND company_name LIKE %s ORDER BY company_name LIMIT %s OFFSET %s',
|
||||
(f'%{search}%', page_size, offset)
|
||||
)
|
||||
total_result = execute_query(
|
||||
'SELECT COUNT(*) as total FROM t_company WHERE company_state = "1" AND company_name LIKE %s',
|
||||
(f'%{search}%',)
|
||||
)
|
||||
else:
|
||||
companies = execute_query(
|
||||
'SELECT id AS company_id, company_name FROM t_company WHERE company_state = "1" ORDER BY company_name LIMIT %s OFFSET %s',
|
||||
(page_size, offset)
|
||||
)
|
||||
total_result = execute_query(
|
||||
'SELECT COUNT(*) as total FROM t_company WHERE company_state = "1"'
|
||||
)
|
||||
total = total_result[0]['total'] if total_result else 0
|
||||
return jsonify({'success': True, 'data': companies, 'total': total, 'page': page, 'page_size': page_size})
|
||||
|
||||
elif entity_type == 'station':
|
||||
# 获取场站列表
|
||||
stations = execute_query(
|
||||
'SELECT id AS station_id, station_name FROM t_station ORDER BY station_name'
|
||||
)
|
||||
return jsonify({'success': True, 'data': stations})
|
||||
if search:
|
||||
stations = execute_query(
|
||||
'SELECT id AS station_id, station_name FROM t_station WHERE station_name LIKE %s ORDER BY station_name LIMIT %s OFFSET %s',
|
||||
(f'%{search}%', page_size, offset)
|
||||
)
|
||||
total_result = execute_query(
|
||||
'SELECT COUNT(*) as total FROM t_station WHERE station_name LIKE %s',
|
||||
(f'%{search}%',)
|
||||
)
|
||||
else:
|
||||
stations = execute_query(
|
||||
'SELECT id AS station_id, station_name FROM t_station ORDER BY station_name LIMIT %s OFFSET %s',
|
||||
(page_size, offset)
|
||||
)
|
||||
total_result = execute_query(
|
||||
'SELECT COUNT(*) as total FROM t_station'
|
||||
)
|
||||
total = total_result[0]['total'] if total_result else 0
|
||||
return jsonify({'success': True, 'data': stations, 'total': total, 'page': page, 'page_size': page_size})
|
||||
|
||||
else:
|
||||
# 获取用户列表
|
||||
users = execute_query(
|
||||
'SELECT id AS user_id, user_name FROM t_user ORDER BY user_name'
|
||||
)
|
||||
return jsonify({'success': True, 'data': users})
|
||||
# 获取用户列表(支持分页和搜索)
|
||||
if search:
|
||||
users = execute_query(
|
||||
'SELECT id AS user_id, user_name FROM t_user WHERE user_name LIKE %s ORDER BY user_name LIMIT %s OFFSET %s',
|
||||
(f'%{search}%', page_size, offset)
|
||||
)
|
||||
total_result = execute_query(
|
||||
'SELECT COUNT(*) as total FROM t_user WHERE user_name LIKE %s',
|
||||
(f'%{search}%',)
|
||||
)
|
||||
else:
|
||||
users = execute_query(
|
||||
'SELECT id AS user_id, user_name FROM t_user ORDER BY user_name LIMIT %s OFFSET %s',
|
||||
(page_size, offset)
|
||||
)
|
||||
total_result = execute_query(
|
||||
'SELECT COUNT(*) as total FROM t_user'
|
||||
)
|
||||
total = total_result[0]['total'] if total_result else 0
|
||||
return jsonify({'success': True, 'data': users, 'total': total, 'page': page, 'page_size': page_size})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'message': str(e)}), 500
|
||||
|
||||
|
||||
BIN
assets/image_20260710125630640.png
Normal file
BIN
assets/image_20260710125630640.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
@@ -472,10 +472,17 @@
|
||||
|
||||
<div class="form-group">
|
||||
<label>选择企业/用户/场站(可多选) *</label>
|
||||
<select id="split-value" class="form-control" multiple size="5">
|
||||
<div style="display: flex; gap: 8px; margin-bottom: 8px;">
|
||||
<input type="text" id="entity-search" class="form-control" placeholder="输入名称搜索..." style="flex: 1;">
|
||||
<button type="button" class="btn btn-secondary" onclick="searchEntities()">搜索</button>
|
||||
</div>
|
||||
<select id="split-value" class="form-control" multiple size="8">
|
||||
<option value="">请先选择拆分方式</option>
|
||||
</select>
|
||||
<small class="form-text text-muted">按住 Ctrl 或 Shift 键可多选</small>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 8px;">
|
||||
<small class="form-text text-muted">按住 Ctrl 或 Shift 键可多选</small>
|
||||
<div id="entity-pagination" style="display: flex; gap: 4px; align-items: center;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@@ -631,8 +638,14 @@
|
||||
`).join('');
|
||||
}
|
||||
|
||||
// 加载企业/用户列表
|
||||
async function loadEntities() {
|
||||
// 当前实体加载状态
|
||||
let currentEntityType = '';
|
||||
let currentPage = 1;
|
||||
let currentSearch = '';
|
||||
const pageSize = 100;
|
||||
|
||||
// 加载企业/用户列表(支持分页和搜索)
|
||||
async function loadEntities(page = 1, search = '') {
|
||||
const splitType = document.getElementById('split-type').value;
|
||||
const select = document.getElementById('split-value');
|
||||
|
||||
@@ -641,50 +654,91 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存当前状态
|
||||
currentEntityType = splitType === 'company_id' ? 'company' :
|
||||
splitType === 'user_id' ? 'user' :
|
||||
splitType === 'station_id' ? 'station' : '';
|
||||
currentPage = page;
|
||||
currentSearch = search;
|
||||
|
||||
select.innerHTML = '<option value="">加载中...</option>';
|
||||
|
||||
// 根据拆分方式确定实体类型
|
||||
let entityType = '';
|
||||
if (splitType === 'company_id') {
|
||||
entityType = 'company';
|
||||
} else if (splitType === 'user_id') {
|
||||
entityType = 'user';
|
||||
} else if (splitType === 'station_id') {
|
||||
entityType = 'station';
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/entities?type=${entityType}`);
|
||||
const response = await fetch(`/api/entities?type=${currentEntityType}&page=${page}&page_size=${pageSize}&search=${encodeURIComponent(search)}`);
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
const entities = result.data;
|
||||
select.innerHTML = '<option value="">请选择(可多选)</option>' +
|
||||
entities.map(e => {
|
||||
const total = result.total || 0;
|
||||
const totalPages = Math.ceil(total / pageSize);
|
||||
|
||||
if (entities.length === 0) {
|
||||
select.innerHTML = '<option value="">无数据</option>';
|
||||
} else {
|
||||
select.innerHTML = entities.map(e => {
|
||||
let value = '';
|
||||
let name = '';
|
||||
let typeLabel = '';
|
||||
|
||||
if (splitType === 'company_id') {
|
||||
value = e.id;
|
||||
name = e.name;
|
||||
value = e.company_id;
|
||||
name = e.company_name;
|
||||
} else if (splitType === 'user_id') {
|
||||
value = e.id;
|
||||
name = e.name;
|
||||
value = e.user_id;
|
||||
name = e.user_name;
|
||||
typeLabel = e.order_type === 3 ? '(企业用户)' : '(普通用户)';
|
||||
} else if (splitType === 'station_id') {
|
||||
value = e.id;
|
||||
name = e.name;
|
||||
value = e.station_id;
|
||||
name = e.station_name;
|
||||
}
|
||||
|
||||
return `<option value="${value}" data-name="${name}">${name} ${typeLabel}</option>`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
// 更新分页UI
|
||||
updatePagination(totalPages, total);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载列表失败:', error);
|
||||
select.innerHTML = '<option value="">加载失败</option>';
|
||||
}
|
||||
}
|
||||
|
||||
// 更新分页UI
|
||||
function updatePagination(totalPages, total) {
|
||||
const paginationDiv = document.getElementById('entity-pagination');
|
||||
if (totalPages <= 1) {
|
||||
paginationDiv.innerHTML = `<small class="text-muted">共 ${total} 条</small>`;
|
||||
return;
|
||||
}
|
||||
|
||||
let html = `<small class="text-muted">共 ${total} 条</small>`;
|
||||
html += `<button type="button" class="btn btn-sm btn-secondary" onclick="loadEntities(${currentPage - 1}, currentSearch)" ${currentPage <= 1 ? 'disabled' : ''}>上一页</button>`;
|
||||
html += `<span>${currentPage}/${totalPages}</span>`;
|
||||
html += `<button type="button" class="btn btn-sm btn-secondary" onclick="loadEntities(${currentPage + 1}, currentSearch)" ${currentPage >= totalPages ? 'disabled' : ''}>下一页</button>`;
|
||||
|
||||
paginationDiv.innerHTML = html;
|
||||
}
|
||||
|
||||
// 搜索实体
|
||||
function searchEntities() {
|
||||
const search = document.getElementById('entity-search').value.trim();
|
||||
loadEntities(1, search);
|
||||
}
|
||||
|
||||
// 回车搜索
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const searchInput = document.getElementById('entity-search');
|
||||
if (searchInput) {
|
||||
searchInput.addEventListener('keypress', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
searchEntities();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 保存配置
|
||||
async function saveConfig() {
|
||||
const configName = document.getElementById('config-name').value;
|
||||
@@ -762,16 +816,11 @@
|
||||
document.getElementById('config-name').value = config.config_name;
|
||||
document.getElementById('split-type').value = config.split_type;
|
||||
|
||||
await loadEntities();
|
||||
|
||||
// 处理多选值回显:split_value 可能是逗号分隔的多个值
|
||||
const splitValueSelect = document.getElementById('split-value');
|
||||
// 获取已选择的值
|
||||
const splitValues = config.split_value.split(',');
|
||||
|
||||
// 清除所有选中状态
|
||||
Array.from(splitValueSelect.options).forEach(opt => {
|
||||
opt.selected = splitValues.includes(opt.value);
|
||||
});
|
||||
// 加载实体并回显
|
||||
await loadEntitiesForEdit(config.split_type, splitValues);
|
||||
|
||||
await loadFields();
|
||||
renderFields(config.selected_fields, config.sum_fields);
|
||||
@@ -784,6 +833,63 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 加载实体用于编辑回显
|
||||
async function loadEntitiesForEdit(splitType, selectedValues) {
|
||||
const select = document.getElementById('split-value');
|
||||
|
||||
if (!splitType) {
|
||||
select.innerHTML = '<option value="">请先选择拆分方式</option>';
|
||||
return;
|
||||
}
|
||||
|
||||
const entityType = splitType === 'company_id' ? 'company' :
|
||||
splitType === 'user_id' ? 'user' :
|
||||
splitType === 'station_id' ? 'station' : '';
|
||||
|
||||
select.innerHTML = '<option value="">加载中...</option>';
|
||||
|
||||
try {
|
||||
// 先加载第一页数据
|
||||
const response = await fetch(`/api/entities?type=${entityType}&page=1&page_size=${pageSize}`);
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
const entities = result.data;
|
||||
const total = result.total || 0;
|
||||
const totalPages = Math.ceil(total / pageSize);
|
||||
|
||||
select.innerHTML = entities.map(e => {
|
||||
let value = '';
|
||||
let name = '';
|
||||
let typeLabel = '';
|
||||
|
||||
if (splitType === 'company_id') {
|
||||
value = e.company_id;
|
||||
name = e.company_name;
|
||||
} else if (splitType === 'user_id') {
|
||||
value = e.user_id;
|
||||
name = e.user_name;
|
||||
typeLabel = e.order_type === 3 ? '(企业用户)' : '(普通用户)';
|
||||
} else if (splitType === 'station_id') {
|
||||
value = e.station_id;
|
||||
name = e.station_name;
|
||||
}
|
||||
|
||||
const isSelected = selectedValues.includes(String(value));
|
||||
return `<option value="${value}" data-name="${name}" ${isSelected ? 'selected' : ''}>${name} ${typeLabel}</option>`;
|
||||
}).join('');
|
||||
|
||||
// 更新分页UI
|
||||
currentEntityType = entityType;
|
||||
currentPage = 1;
|
||||
updatePagination(totalPages, total);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载列表失败:', error);
|
||||
select.innerHTML = '<option value="">加载失败</option>';
|
||||
}
|
||||
}
|
||||
|
||||
// 复制配置
|
||||
async function copyConfig(configId) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user