生成时间: 2026-08-03 · 数据来源: xnybw平台需求及工作计划.xlsx(南网在线绿能云缺陷跟踪表)· 仅针对 backup730/730backup 分支代码

Row 16:选择项目删除之后项目还在,刷新后项目并没有被删除

严重 已关闭 · 复测通过 全部类型 模块:项目信息填报 处理人:陈键泽

1基本信息

问题描述选择项目删除之后项目还在,重新点击删除显示"请选择要删除的数据",刷新后项目并没有被删除。
所属模块项目信息填报 / -
严重程度严重(阻断流程:是)
涉及类型全部类型
提出人刘向诚
处理人 / 状态陈键泽 / 5.1.已关闭(复测通过)

2问题截图

项目列表勾选待删除
图1:项目信息填报列表,勾选一条数据,点击"删除"
再次点击删除提示请选择数据
图2:再次点击"删除"时,界面反复弹出"请选择要删除的数据"提示(说明前次删除已把选中项清空,但数据并未真正消失)

3旧代码定位(backup730 / 730backup 分支)

前端:src/views/projectNew/projectNewList.vue 第 493-533 行 _deleteBatch()

projectBaseApi.deleteBatchImpl(param).then(res => {   // 524行
  this.tableLoading = false
  this.selectedData = []
  this.$message.info('删除成功')                        // 527行:只要 HTTP 200 就无条件提示"删除成功",
                                                          // 完全没有检查 res 里的业务返回内容
  this.getDataList(this.searchForm)
  this.$refs.listTable.tableClearSelection()
}).catch((error) => {
  this.$message.error('调用接口出错:' + error)
  ...
})

后端:src/main/java/cn/csg/so/oms/in/newenergy/project/appservice/ProjectImplAppService.java 第 1749-1809 行 deleteBatchImpl()

public String deleteBatchImpl(ProjectVo vo) throws Exception {
    if (vo == null || CollectionUtils.isEmpty(vo.getImplVoList())) {
        return "批量删除失败:请选择需要删除的项目数据。";      // 以字符串形式返回失败原因,HTTP 状态码仍是200
    }
    ...
    String msg = validateProjectDelete(requestedImplIds, true);
    if (msg != "") {
        return msg;                                          // 业务校验不通过时,同样只是返回一个字符串,不抛异常
    }
    ...
    for (NePjImplVO impl : resultList) {
        if (("0".equals(impl.getConnectedCapa()) || StrUtil.isEmpty(impl.getConnectedCapa()))
                && (StrUtil.isEmpty(impl.getPlanFlowStatus()) || !"审核中".equals(impl.getPlanFlowStatus()))) {
            impl.setDelFlag("1");
        } else {
            flag = false;                                    // 存在已并网容量/计划审核中的实施记录,不允许删除
            errorNames.add(impl.getPlanName() + "-" + impl.getDispatchName());
        }
    }
    if (!flag) {
        throw new Exception(errorStr);                        // 只有这一种情况会真正抛异常
    }
    ...
}
根因说明:
前后端"契约"不一致:后端 deleteBatchImpl 对多种失败场景(未选中数据、实施ID为空、validateProjectDelete 业务校验不通过等)都是以 HTTP 200 + 字符串消息 的方式返回,只有"存在已并网容量/审核中的计划"这一种情况才会真正 throw Exception。而前端 .then(res => {...}) 分支里,只要 Promise 没有 reject(即 HTTP 是 200),就无条件弹"删除成功"、清空选中项、刷新列表 —— 从未读取过 res 的实际内容。当某条记录被后端业务规则拦截(例如已存在计划并网/实际并网关联数据)时,前端依然显示"删除成功",但记录其实完全没有被删除,用户刷新页面后自然发现项目还在。
勾选项目 → 点击删除
后端校验未通过,返回失败字符串(HTTP 200)
前端 .then() 无条件提示"删除成功"
selectedData清空 + 刷新列表(记录仍在)
再次点击删除 → 未勾选 → "请选择要删除的数据"

4修复方案

修复文件:src/views/projectNew/projectNewList.vue(原第 524-533 行)

projectBaseApi.deleteBatchImpl(param).then(res => {
  this.tableLoading = false
  const resultMsg = typeof res === 'string' ? res : (res && res.data)
  // 约定:后端删除成功时返回空字符串 / null / "删除成功" 等标识,
  // 其余任何非空字符串均视为失败原因,直接展示给用户
  if (resultMsg && resultMsg.indexOf('失败') !== -1) {
    this.$message.error(resultMsg)
    return
  }
  this.selectedData = []
  this.$message.info('删除成功')
  this.getDataList(this.searchForm)
  this.$refs.listTable.tableClearSelection()
}).catch((error) => {
  this.$message.error('调用接口出错:' + error)
  this.tableLoading = false
  this.selectedData = []
})

同时建议后端把"业务校验不通过"统一改为抛出可识别的业务异常(而不是部分场景返回字符串、部分场景抛异常两种风格混用),前端只需要统一处理 catch 分支即可,减少人为遗漏判断的可能:

// ProjectImplAppService.java
if (vo == null || CollectionUtils.isEmpty(vo.getImplVoList())) {
    throw new BusinessException("批量删除失败:请选择需要删除的项目数据。");
}
...
String msg = validateProjectDelete(requestedImplIds, true);
if (StrUtil.isNotEmpty(msg)) {
    throw new BusinessException(msg);
}
效果:删除被后端业务规则拦截时,用户能立即看到真实失败原因(例如"XX项目存在关联的计划/实际并网数据,不可删除"),而不是被"删除成功"的误导性提示欺骗,也不会出现刷新后数据"复活"的诡异现象。