fix(aihr): protect case media playback
This commit is contained in:
@@ -106,6 +106,14 @@ export function getCaseDetail(caseId: string): Promise<ApiResult<CaseDetailRespo
|
||||
});
|
||||
}
|
||||
|
||||
export function getCaseMedia(caseId: string): Promise<Blob> {
|
||||
return request({
|
||||
url: `/api/knowledge/case/records/${encodeURIComponent(caseId)}/media`,
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
});
|
||||
}
|
||||
|
||||
export function reviewKnowledgeCase(caseId: string, comment: string): Promise<ApiResult<void>> {
|
||||
return request({
|
||||
url: `/api/knowledge/case/records/${encodeURIComponent(caseId)}/review`,
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
</el-table>
|
||||
</section>
|
||||
|
||||
<el-dialog v-model="detailVisible" title="案例详情" width="720px">
|
||||
<el-dialog v-model="detailVisible" title="案例详情" width="720px" @closed="releaseCaseMediaUrl">
|
||||
<template v-if="caseDetail">
|
||||
<div class="detail-meta">{{ caseDetail.time }} · {{ caseDetail.owner }} · {{ caseDetail.status }} · {{ caseDetail.fileName }}</div>
|
||||
<div class="detail-block">
|
||||
@@ -157,10 +157,12 @@
|
||||
<el-button type="danger" :loading="reviewSaving" :disabled="!caseDetail.caseId" @click="submitSupervisorReview">保存点评</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="caseDetail.mediaUrl" class="detail-block">
|
||||
<div v-if="caseMediaUrl" class="detail-block">
|
||||
<strong>原始音频</strong>
|
||||
<audio class="case-audio" :src="caseDetail.mediaUrl" controls preload="metadata" />
|
||||
<audio class="case-audio" :src="caseMediaUrl" controls preload="metadata" />
|
||||
</div>
|
||||
<div v-else-if="caseMediaLoading" class="detail-block detail-muted">音频加载中…</div>
|
||||
<div v-else-if="caseDetail.mediaOssId" class="detail-block detail-muted">音频加载失败,请重试或联系管理员</div>
|
||||
<el-alert title="当前版本提供转写、摘要、学习点和主管点评;视频样片仍待正式媒体资源接入。" type="info" :closable="false" />
|
||||
</template>
|
||||
<el-empty v-else description="暂无详情" />
|
||||
@@ -171,11 +173,12 @@
|
||||
<script setup name="KnowledgeCases" lang="ts">
|
||||
import { DocumentChecked, FolderChecked, Microphone, Tickets } from '@element-plus/icons-vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import {
|
||||
curateKnowledgeCase,
|
||||
getCaseDetail,
|
||||
getCaseMedia,
|
||||
getCaseRecords,
|
||||
organizeKnowledgeCase,
|
||||
reviewKnowledgeCase,
|
||||
@@ -206,6 +209,8 @@ const recordsLoading = ref(true);
|
||||
const recordsFallback = ref(false);
|
||||
const detailVisible = ref(false);
|
||||
const caseDetail = ref<CaseDetailResponse | null>(null);
|
||||
const caseMediaUrl = ref('');
|
||||
const caseMediaLoading = ref(false);
|
||||
const supervisorComment = ref('');
|
||||
const reviewSaving = ref(false);
|
||||
const projectExtOrgId = ref('');
|
||||
@@ -314,16 +319,36 @@ async function loadCaseRecords() {
|
||||
|
||||
async function openCaseDetail(record: CaseRecord) {
|
||||
if (!record.caseId) return;
|
||||
releaseCaseMediaUrl();
|
||||
caseMediaLoading.value = true;
|
||||
try {
|
||||
const { data } = await getCaseDetail(record.caseId);
|
||||
caseDetail.value = data;
|
||||
if (data.mediaOssId) {
|
||||
try {
|
||||
caseMediaUrl.value = URL.createObjectURL(await getCaseMedia(record.caseId));
|
||||
} catch {
|
||||
caseMediaUrl.value = '';
|
||||
}
|
||||
}
|
||||
supervisorComment.value = data.supervisorComment || '';
|
||||
detailVisible.value = true;
|
||||
} catch {
|
||||
ElMessage.error('案例详情加载失败');
|
||||
} finally {
|
||||
caseMediaLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function releaseCaseMediaUrl() {
|
||||
if (caseMediaUrl.value.startsWith('blob:')) {
|
||||
URL.revokeObjectURL(caseMediaUrl.value);
|
||||
}
|
||||
caseMediaUrl.value = '';
|
||||
}
|
||||
|
||||
onBeforeUnmount(releaseCaseMediaUrl);
|
||||
|
||||
async function submitSupervisorReview() {
|
||||
if (!caseDetail.value || reviewSaving.value) return;
|
||||
reviewSaving.value = true;
|
||||
|
||||
Reference in New Issue
Block a user