21
This commit is contained in:
parent
8b6fe85774
commit
138caae4ad
|
|
@ -257,6 +257,11 @@ public static class BusinessPermissions
|
|||
/// 导出测评记录
|
||||
/// </summary>
|
||||
public const string Export = "assessmentRecord:export";
|
||||
|
||||
/// <summary>
|
||||
/// 删除测评记录
|
||||
/// </summary>
|
||||
public const string Delete = "assessmentRecord:delete";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
@ -344,6 +349,7 @@ public static class BusinessPermissions
|
|||
// 测评记录管理模块
|
||||
new PermissionDefinition(AssessmentRecord.View, "查看测评记录", AssessmentRecord.Module, "查看测评记录列表和详情"),
|
||||
new PermissionDefinition(AssessmentRecord.Export, "导出测评记录", AssessmentRecord.Module, "导出测评记录为Excel文件"),
|
||||
new PermissionDefinition(AssessmentRecord.Delete, "删除测评记录", AssessmentRecord.Module, "删除测评记录"),
|
||||
|
||||
// 业务介绍页管理模块
|
||||
new PermissionDefinition(BusinessPage.View, "查看业务介绍页", BusinessPage.Module, "查看业务介绍页列表和详情"),
|
||||
|
|
|
|||
|
|
@ -184,4 +184,33 @@ public class AssessmentRecordController : BusinessControllerBase
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除测评记录
|
||||
/// </summary>
|
||||
/// <param name="request">删除请求</param>
|
||||
/// <returns>操作结果</returns>
|
||||
[HttpPost("delete")]
|
||||
[BusinessPermission(BusinessPermissions.AssessmentRecord.Delete)]
|
||||
public async Task<IActionResult> Delete([FromBody] RegenerateReportRequest request)
|
||||
{
|
||||
if (request.Id <= 0)
|
||||
{
|
||||
return ValidationError("测评记录ID无效");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await _assessmentRecordService.DeleteRecordAsync(request.Id);
|
||||
return Ok();
|
||||
}
|
||||
catch (BusinessException ex)
|
||||
{
|
||||
return Error(ex.Code, ex.Message);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return Error(ErrorCodes.SystemError, "删除测评记录失败");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -595,6 +595,25 @@ public class AssessmentRecordService : IAssessmentRecordService
|
|||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task DeleteRecordAsync(long id)
|
||||
{
|
||||
var record = await _dbContext.AssessmentRecords
|
||||
.FirstOrDefaultAsync(r => r.Id == id && !r.IsDeleted);
|
||||
|
||||
if (record == null)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.AssessmentRecordNotFound, "测评记录不存在");
|
||||
}
|
||||
|
||||
// 软删除
|
||||
record.IsDeleted = true;
|
||||
record.UpdateTime = DateTime.Now;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
|
||||
_logger.LogInformation("测评记录已删除,ID: {RecordId}", id);
|
||||
}
|
||||
|
||||
#region 私有方法
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -48,4 +48,10 @@ public interface IAssessmentRecordService
|
|||
/// <param name="recordIds">测评记录ID列表</param>
|
||||
/// <returns>批量操作结果</returns>
|
||||
Task<BatchRegenerateResult> BatchRegenerateReportAsync(List<long> recordIds);
|
||||
|
||||
/// <summary>
|
||||
/// 删除测评记录(软删除)
|
||||
/// </summary>
|
||||
/// <param name="id">记录ID</param>
|
||||
Task DeleteRecordAsync(long id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,3 +158,12 @@ export function batchRegenerateReport(ids: number[]): Promise<ApiResponse<BatchR
|
|||
data: { ids }
|
||||
})
|
||||
}
|
||||
|
||||
/** 删除测评记录 */
|
||||
export function deleteRecord(id: number): Promise<ApiResponse<null>> {
|
||||
return request<null>({
|
||||
url: '/admin/assessmentRecord/delete',
|
||||
method: 'post',
|
||||
data: { id }
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@
|
|||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="170" align="center" />
|
||||
<el-table-column label="操作" width="230" fixed="right" align="center">
|
||||
<el-table-column label="操作" width="280" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link size="small" @click="handleViewDetail(row)">
|
||||
<el-icon><View /></el-icon>
|
||||
|
|
@ -134,6 +134,15 @@
|
|||
<el-icon><RefreshRight /></el-icon>
|
||||
重新生成
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
link
|
||||
size="small"
|
||||
@click="handleDelete(row)"
|
||||
>
|
||||
<el-icon><Delete /></el-icon>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
|
@ -286,7 +295,7 @@
|
|||
* @description 查看用户测评记录、答案详情和测评报告,支持搜索、导出
|
||||
*/
|
||||
import { reactive, ref, onMounted } from 'vue'
|
||||
import { Search, Refresh, View, Download, Document, RefreshRight } from '@element-plus/icons-vue'
|
||||
import { Search, Refresh, View, Download, Document, RefreshRight, Delete } from '@element-plus/icons-vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import {
|
||||
getRecordList,
|
||||
|
|
@ -295,6 +304,7 @@ import {
|
|||
exportRecords,
|
||||
regenerateReport,
|
||||
batchRegenerateReport,
|
||||
deleteRecord,
|
||||
type AssessmentRecordItem,
|
||||
type AssessmentRecordDetail,
|
||||
type AssessmentReport,
|
||||
|
|
@ -629,6 +639,28 @@ async function handleBatchRegenerate() {
|
|||
}
|
||||
}
|
||||
|
||||
/** 删除测评记录 */
|
||||
async function handleDelete(row: AssessmentRecordItem) {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确定要删除记录 ID=${row.id} 吗?删除后不可恢复。`,
|
||||
'删除测评记录',
|
||||
{ confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }
|
||||
)
|
||||
const res = await deleteRecord(row.id)
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('删除成功')
|
||||
loadRecordList()
|
||||
} else {
|
||||
throw new Error(res.message || '删除失败')
|
||||
}
|
||||
} catch (error) {
|
||||
if (error === 'cancel' || (error as any)?.toString?.().includes('cancel')) return
|
||||
const message = error instanceof Error ? error.message : '删除失败'
|
||||
ElMessage.error(message)
|
||||
}
|
||||
}
|
||||
|
||||
async function handleExport() {
|
||||
state.exportLoading = true
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -120,14 +120,20 @@ public class RedisService : IRedisService, IDisposable
|
|||
if (_database == null || !_isConnected)
|
||||
return null;
|
||||
|
||||
// 使用 BRPOP 命令实现阻塞弹出
|
||||
var result = await _database.ExecuteAsync("BRPOP", key, (int)timeout.TotalSeconds);
|
||||
if (result.IsNull)
|
||||
return null;
|
||||
// 使用非阻塞 RPOP + 轮询代替 BRPOP,避免 StackExchange.Redis 命令超时
|
||||
// BRPOP 的阻塞时间会超过客户端的 syncTimeout/asyncTimeout 导致 RedisTimeoutException
|
||||
var deadline = DateTime.UtcNow.Add(timeout);
|
||||
while (DateTime.UtcNow < deadline)
|
||||
{
|
||||
var value = await _database.ListRightPopAsync(key);
|
||||
if (!value.IsNullOrEmpty)
|
||||
return value.ToString();
|
||||
|
||||
// BRPOP 返回数组:[key, value]
|
||||
var results = (RedisResult[])result!;
|
||||
return results[1].ToString();
|
||||
// 空队列时等待 1 秒后重试,避免频繁轮询
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user