fix(case): require project scope for uploads
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
<span class="status-pill" :class="apiPill.type">{{ apiPill.label }}</span>
|
||||
<span class="status-pill" :class="flowStatus.type">{{ flowStatus.label }}</span>
|
||||
<el-button @click="router.push('/index')">返回首页</el-button>
|
||||
<el-button type="danger" @click="audioInput?.click()">上传语音</el-button>
|
||||
<el-button type="danger" :disabled="!projectExtOrgId" @click="openAudioPicker">上传语音</el-button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -20,10 +20,39 @@
|
||||
<el-icon><Microphone /></el-icon>
|
||||
<h2>上传与转写</h2>
|
||||
</div>
|
||||
<div class="upload-box" @click="audioInput?.click()">
|
||||
<div class="project-selector">
|
||||
<label for="case-project">案例所属项目</label>
|
||||
<el-select
|
||||
id="case-project"
|
||||
v-model="projectExtOrgId"
|
||||
class="project-select"
|
||||
clearable
|
||||
filterable
|
||||
:loading="projectsLoading"
|
||||
placeholder="先选择项目,再上传案例"
|
||||
>
|
||||
<el-option v-for="project in projectOptions" :key="project.projectCode" :label="project.projectName" :value="project.projectCode" />
|
||||
</el-select>
|
||||
<el-alert
|
||||
v-if="!projectsLoading && !projectOptions.length"
|
||||
title="暂无可用项目,请先在“组织与权限”完成组织同步预检"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
</div>
|
||||
<div class="upload-box" :class="{ disabled: !projectExtOrgId }" @click="openAudioPicker">
|
||||
<el-icon><FolderChecked /></el-icon>
|
||||
<strong>{{ audioUploaded ? displayFileName : '选择语音文件' }}</strong>
|
||||
<span>{{ audioUploaded ? '真实语音已完成 ASR 转写。' : '支持 mp3/wav/m4a/webm/ogg,需先配置 ASR 模型。' }}</span>
|
||||
<span>
|
||||
{{
|
||||
audioUploaded
|
||||
? '真实语音已完成 ASR 转写。'
|
||||
: projectExtOrgId
|
||||
? '支持 mp3/wav/m4a/webm/ogg,需先配置 ASR 模型。'
|
||||
: '请先选择案例所属项目。'
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="audioUploaded" class="transcript-card">
|
||||
<span>ASR 转写结果</span>
|
||||
@@ -129,6 +158,7 @@ import {
|
||||
type CaseSummaryItem,
|
||||
type CaseTag
|
||||
} from '@/api/aihr/case';
|
||||
import { getOrgSnapshot, type OrgProjectOption } from '@/api/aihr/mobile-admin';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
@@ -148,6 +178,9 @@ const apiSampleHint = ref('');
|
||||
const recordsLoading = ref(false);
|
||||
const detailVisible = ref(false);
|
||||
const caseDetail = ref<CaseDetailResponse | null>(null);
|
||||
const projectExtOrgId = ref('');
|
||||
const projectOptions = ref<OrgProjectOption[]>([]);
|
||||
const projectsLoading = ref(false);
|
||||
|
||||
const displayFileName = computed(() => apiFileName.value || '未选择文件');
|
||||
const displayTranscript = computed(() => apiTranscript.value || '暂无转写结果');
|
||||
@@ -266,7 +299,35 @@ async function handleAudioPicked(event: Event) {
|
||||
await uploadAudio(file);
|
||||
}
|
||||
|
||||
function openAudioPicker() {
|
||||
if (!projectExtOrgId.value) {
|
||||
ElMessage.warning('请先选择案例所属项目');
|
||||
return;
|
||||
}
|
||||
audioInput.value?.click();
|
||||
}
|
||||
|
||||
async function loadProjectOptions() {
|
||||
projectsLoading.value = true;
|
||||
try {
|
||||
const { data } = await getOrgSnapshot({ status: 'active', pageNum: 1, pageSize: 1 });
|
||||
projectOptions.value = data?.projects ?? [];
|
||||
if (projectOptions.value.length === 1) {
|
||||
projectExtOrgId.value = projectOptions.value[0].projectCode;
|
||||
}
|
||||
} catch {
|
||||
projectOptions.value = [];
|
||||
ElMessage.warning('项目列表加载失败,请先检查组织同步配置');
|
||||
} finally {
|
||||
projectsLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadAudio(file: File) {
|
||||
if (!projectExtOrgId.value) {
|
||||
ElMessage.warning('请先选择案例所属项目');
|
||||
return;
|
||||
}
|
||||
audioUploaded.value = false;
|
||||
organized.value = false;
|
||||
reviewed.value = false;
|
||||
@@ -279,6 +340,7 @@ async function uploadAudio(file: File) {
|
||||
try {
|
||||
const form = new FormData();
|
||||
form.append('file', file);
|
||||
form.append('projectExtOrgId', projectExtOrgId.value);
|
||||
const { data } = await uploadCaseAudio(form);
|
||||
caseId.value = data.caseId;
|
||||
apiMode.value = 'api';
|
||||
@@ -353,6 +415,7 @@ async function storeCase() {
|
||||
|
||||
onMounted(() => {
|
||||
void loadCaseRecords();
|
||||
void loadProjectOptions();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -444,6 +507,11 @@ onMounted(() => {
|
||||
color: #657184;
|
||||
cursor: pointer;
|
||||
|
||||
&.disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.el-icon {
|
||||
color: #d70f20;
|
||||
font-size: 38px;
|
||||
@@ -455,6 +523,22 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.project-selector {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
label {
|
||||
color: #344255;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.project-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.transcript-card,
|
||||
.sample-card {
|
||||
margin-top: 12px;
|
||||
|
||||
Reference in New Issue
Block a user