feat(mds): 禁止编辑removing状态数据

单条编辑:
- 后端检查状态,removing状态返回禁止错误
- 前端显示警告提示+所有字段只读+隐藏保存按钮

批量编辑:
- 后端查询并分离removing状态的记录
- 只更新非removing状态的记录
- 返回跳过数量和跳过的ID列表
- 前端显示跳过提示

修改文件:
- apps/data_opt/mds/staging_routers.py
- static/mds/js/mds-page-controller.js
This commit is contained in:
2026-05-22 14:39:08 +08:00
parent d39287b7ee
commit 7b11d33357
2 changed files with 91 additions and 10 deletions
+52 -2
View File
@@ -1242,6 +1242,31 @@ async def batch_update_staging(
table_name_staging = f"{table_name}_staging"
conn = await get_db_connection_safely(THIS_DB_NAME)
# 检查哪些记录是removing状态,需要跳过
placeholders = ", ".join([f"${i+1}" for i in range(len(ids))])
check_query = f'SELECT "_staging_id", "_status" FROM "{table_name_staging}" WHERE "_staging_id" IN ({placeholders})'
check_result = await conn.execute_query(check_query, tuple(ids))
removing_ids = []
valid_ids = []
for row in (check_result[1] or []):
if row["_status"] == StagingStatus.REMOVING:
removing_ids.append(row["_staging_id"])
else:
valid_ids.append(row["_staging_id"])
if not valid_ids:
# 全部都是removing状态
return standard_response(
success=1,
message=f"已跳过{len(removing_ids)}条待删除记录,无有效记录可编辑",
data={
"updated": 0,
"skipped": len(removing_ids),
"skipped_ids": removing_ids
}
)
field_mapping = {}
field_types = {}
for field in staging_model._meta.fields_map.values():
@@ -1279,7 +1304,7 @@ async def batch_update_staging(
params.append(value)
param_idx += 1
params.append(ids)
params.append(valid_ids)
update_query = f'''
UPDATE "{table_name_staging}"
@@ -1289,9 +1314,20 @@ async def batch_update_staging(
await conn.execute_query(update_query, tuple(params))
# 构建返回消息
message_parts = [f"成功更新{len(valid_ids)}条记录"]
if removing_ids:
message_parts.append(f"跳过{len(removing_ids)}条待删除记录")
message = "".join(message_parts)
return standard_response(
success=1,
message=f"成功更新{len(ids)}条记录,状态已重置为待处理"
message=message,
data={
"updated": len(valid_ids),
"skipped": len(removing_ids),
"skipped_ids": removing_ids
}
)
except Exception as e:
logger.error(f"批量更新失败: {str(e)}")
@@ -1358,6 +1394,20 @@ async def update_staging(
table_name_staging = f"{table_name}_staging"
conn = await get_db_connection_safely(THIS_DB_NAME)
# 检查记录状态,禁止编辑removing状态的数据
check_query = f'SELECT "_status" FROM "{table_name_staging}" WHERE "_staging_id" = $1'
check_result = await conn.execute_query(check_query, (staging_id,))
if not check_result[1]:
raise ValueError(f"记录不存在: staging_id={staging_id}")
current_status = check_result[1][0]["_status"]
if current_status == StagingStatus.REMOVING:
return standard_response(
success=0,
message="禁止编辑:当前记录处于待删除状态,请先取消删除标记"
)
field_map = {}
field_types = {}
for field in staging_model._meta.fields_map.values():
+39 -8
View File
@@ -893,11 +893,11 @@ class MDSPageController {
}
}
generateEditField(col, row) {
generateEditField(col, row, isRemoving = false) {
const fieldName = col.field;
const fieldValue = row[fieldName] !== null && row[fieldName] !== undefined ? row[fieldName] : '';
const isRequired = this.isRequiredField(fieldName);
const isReadOnly = this.isReadOnlyField(fieldName);
const isReadOnly = this.isReadOnlyField(fieldName) || isRemoving; // removing状态强制只读
const isForeignKey = this.isForeignKeyField(fieldName);
const errorFields = this.getErrorFields(row);
@@ -986,6 +986,9 @@ class MDSPageController {
showEditModal(row) {
const modal = new bootstrap.Modal(document.getElementById('editModal'));
// 检查是否为removing状态
const isRemoving = row._status === 'removing';
const columns = this.getColumns();
const businessFields = columns.filter(col => !col.field.startsWith('_'));
const totalFields = businessFields.length;
@@ -994,21 +997,38 @@ class MDSPageController {
const leftFields = businessFields.slice(0, halfCount);
const rightFields = businessFields.slice(halfCount);
// 如果是removing状态,添加提示信息
let alertHtml = '';
if (isRemoving) {
alertHtml = `
<div class="alert alert-warning mb-3">
<i class="bi bi-exclamation-triangle"></i> 当前记录处于<strong>待删除状态</strong>,禁止编辑。请先取消删除标记后再进行编辑。
</div>
`;
}
const editForm = document.getElementById('editForm');
editForm.innerHTML = `
${alertHtml}
<div class="row">
<div class="col-6">
${leftFields.map(col => this.generateEditField(col, row)).join('')}
${leftFields.map(col => this.generateEditField(col, row, isRemoving)).join('')}
</div>
<div class="col-6">
${rightFields.map(col => this.generateEditField(col, row)).join('')}
${rightFields.map(col => this.generateEditField(col, row, isRemoving)).join('')}
</div>
</div>
`;
const saveBtn = document.getElementById('saveBtn');
if (saveBtn) {
saveBtn.onclick = () => this.saveRecord(row._staging_id);
// removing状态隐藏保存按钮
if (isRemoving) {
saveBtn.style.display = 'none';
} else {
saveBtn.style.display = '';
saveBtn.onclick = () => this.saveRecord(row._staging_id);
}
}
// 绑定删除按钮
@@ -1030,8 +1050,10 @@ class MDSPageController {
modal.show();
// 异步加载外键选项
this.loadFkOptionsInForm(row);
// 非removing状态才加载外键选项
if (!isRemoving) {
this.loadFkOptionsInForm(row);
}
}
/**
@@ -1846,7 +1868,16 @@ class MDSPageController {
hideLoading();
handleResponse(response, () => {
showMessage(`成功更新 ${ids.length} 条记录`, 'success');
// 显示编辑结果,包含跳过的removing记录数
const updated = response.data?.updated || ids.length;
const skipped = response.data?.skipped || 0;
let message = `成功更新 ${updated} 条记录`;
if (skipped > 0) {
message += `,跳过 ${skipped} 条待删除记录`;
}
showMessage(message, 'success');
bootstrap.Modal.getInstance(document.getElementById('batchEditModal')).hide();
this.dataTable.selectedIds.clear();
this.dataTable.updateSelectedCount();