|
|
|
|
@ -1,5 +1,5 @@
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { computed, nextTick, ref, watch } from 'vue'
|
|
|
|
|
import { computed, ref, watch } from 'vue'
|
|
|
|
|
import TeacherPaperDialog from '@/components/TeacherPaperDialog.vue'
|
|
|
|
|
import {
|
|
|
|
|
approveTeacher,
|
|
|
|
|
@ -116,6 +116,11 @@ const directionOptions = computed(() =>
|
|
|
|
|
const universitySelectOptions = computed(() =>
|
|
|
|
|
universityOptions.value.map((u) => ({ value: u.id, label: u.name })),
|
|
|
|
|
)
|
|
|
|
|
const directionSelectOptions = computed(() =>
|
|
|
|
|
directionOptions.value.map((d) => ({ value: d.id, label: d.name })),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
let hydrateSeq = 0
|
|
|
|
|
|
|
|
|
|
const starFollowRule = computed(() => {
|
|
|
|
|
const item = starOptions.value.find((s) => s.id === form.value.star_level_dict_item_id)
|
|
|
|
|
@ -367,68 +372,80 @@ async function openDemandRecords(row: DemandRow) {
|
|
|
|
|
demandRecordsVisible.value = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function resetDialogState() {
|
|
|
|
|
hydrateSeq += 1
|
|
|
|
|
teacher.value = null
|
|
|
|
|
form.value = emptyForm()
|
|
|
|
|
papers.value = []
|
|
|
|
|
demands.value = []
|
|
|
|
|
loadedStarId.value = null
|
|
|
|
|
selectsReady.value = false
|
|
|
|
|
loading.value = false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function applyPreviewIfAny(id: number) {
|
|
|
|
|
const preview = props.previewTeacher
|
|
|
|
|
if (preview && Number(preview.id) === Number(id)) {
|
|
|
|
|
applyTeacherToForm(preview)
|
|
|
|
|
loading.value = false
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
teacher.value = null
|
|
|
|
|
form.value = emptyForm()
|
|
|
|
|
loadedStarId.value = null
|
|
|
|
|
loading.value = true
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 弹窗已打开并完成入场后,再挂载大下拉并拉详情,避免点击后卡住 */
|
|
|
|
|
async function onDialogOpened() {
|
|
|
|
|
const requestId = props.teacherId
|
|
|
|
|
if (!requestId || !props.modelValue) return
|
|
|
|
|
|
|
|
|
|
const seq = ++hydrateSeq
|
|
|
|
|
// 再等一帧,确保弹窗先画出来
|
|
|
|
|
await new Promise<void>((resolve) => {
|
|
|
|
|
requestAnimationFrame(() => resolve())
|
|
|
|
|
})
|
|
|
|
|
if (seq !== hydrateSeq || !props.modelValue || props.teacherId !== requestId) return
|
|
|
|
|
|
|
|
|
|
selectsReady.value = true
|
|
|
|
|
void ensureOptions()
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const detail = await fetchTeacher(requestId)
|
|
|
|
|
if (seq !== hydrateSeq || props.teacherId !== requestId || !props.modelValue) return
|
|
|
|
|
|
|
|
|
|
applyTeacherToForm(detail)
|
|
|
|
|
mergeTeacherDirectionOptions(detail)
|
|
|
|
|
loading.value = false
|
|
|
|
|
|
|
|
|
|
const [paperList, demandRes] = await Promise.all([
|
|
|
|
|
fetchTeacherPapers(requestId),
|
|
|
|
|
fetchDemandsList({ teacher_id: requestId, page: 1, page_size: 50 }),
|
|
|
|
|
])
|
|
|
|
|
if (seq !== hydrateSeq || props.teacherId !== requestId || !props.modelValue) return
|
|
|
|
|
papers.value = paperList
|
|
|
|
|
demands.value = demandRes.items
|
|
|
|
|
} finally {
|
|
|
|
|
if (seq === hydrateSeq && props.teacherId === requestId) {
|
|
|
|
|
loading.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 仅同步预填,绝不在此处 await 接口(否则会感觉「等接口才弹窗」)
|
|
|
|
|
watch(
|
|
|
|
|
() => [props.modelValue, props.teacherId] as const,
|
|
|
|
|
async ([open, id]) => {
|
|
|
|
|
([open, id]) => {
|
|
|
|
|
if (!open || !id) {
|
|
|
|
|
if (!open) {
|
|
|
|
|
teacher.value = null
|
|
|
|
|
form.value = emptyForm()
|
|
|
|
|
papers.value = []
|
|
|
|
|
demands.value = []
|
|
|
|
|
loadedStarId.value = null
|
|
|
|
|
selectsReady.value = false
|
|
|
|
|
}
|
|
|
|
|
if (!open) resetDialogState()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const requestId = id
|
|
|
|
|
papers.value = []
|
|
|
|
|
demands.value = []
|
|
|
|
|
selectsReady.value = false
|
|
|
|
|
|
|
|
|
|
// 用列表预览立刻填表,弹窗可马上可见
|
|
|
|
|
if (props.previewTeacher && props.previewTeacher.id === id) {
|
|
|
|
|
applyTeacherToForm(props.previewTeacher)
|
|
|
|
|
loading.value = false
|
|
|
|
|
} else {
|
|
|
|
|
teacher.value = null
|
|
|
|
|
form.value = emptyForm()
|
|
|
|
|
loadedStarId.value = null
|
|
|
|
|
loading.value = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 等弹窗先渲染出来,再挂载大批量下拉,避免点击后卡住
|
|
|
|
|
await nextTick()
|
|
|
|
|
requestAnimationFrame(() => {
|
|
|
|
|
if (props.modelValue && props.teacherId === requestId) {
|
|
|
|
|
selectsReady.value = true
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const detailPromise = fetchTeacher(requestId)
|
|
|
|
|
void ensureOptions()
|
|
|
|
|
|
|
|
|
|
const detail = await detailPromise
|
|
|
|
|
if (props.teacherId !== requestId || !props.modelValue) return
|
|
|
|
|
|
|
|
|
|
applyTeacherToForm(detail)
|
|
|
|
|
mergeTeacherDirectionOptions(detail)
|
|
|
|
|
loading.value = false
|
|
|
|
|
|
|
|
|
|
const [paperList, demandRes] = await Promise.all([
|
|
|
|
|
fetchTeacherPapers(requestId),
|
|
|
|
|
fetchDemandsList({ teacher_id: requestId, page: 1, page_size: 50 }),
|
|
|
|
|
])
|
|
|
|
|
if (props.teacherId !== requestId || !props.modelValue) return
|
|
|
|
|
papers.value = paperList
|
|
|
|
|
demands.value = demandRes.items
|
|
|
|
|
} finally {
|
|
|
|
|
if (props.teacherId === requestId) {
|
|
|
|
|
loading.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
applyPreviewIfAny(id)
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@ -445,6 +462,7 @@ watch(
|
|
|
|
|
width="960px"
|
|
|
|
|
top="4vh"
|
|
|
|
|
append-to-body
|
|
|
|
|
@opened="onDialogOpened"
|
|
|
|
|
@update:model-value="emit('update:modelValue', $event)"
|
|
|
|
|
>
|
|
|
|
|
<div v-loading="loading" class="detail-body">
|
|
|
|
|
@ -539,21 +557,17 @@ watch(
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :xs="24" :md="8">
|
|
|
|
|
<el-form-item label="研究方向">
|
|
|
|
|
<el-select
|
|
|
|
|
<el-select-v2
|
|
|
|
|
v-if="selectsReady"
|
|
|
|
|
v-model="form.research_direction_values"
|
|
|
|
|
multiple
|
|
|
|
|
filterable
|
|
|
|
|
allow-create
|
|
|
|
|
default-first-option
|
|
|
|
|
collapse-tags
|
|
|
|
|
collapse-tags-tooltip
|
|
|
|
|
clearable
|
|
|
|
|
placeholder="可选,选择或输入研究方向"
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
>
|
|
|
|
|
<el-option v-for="d in directionOptions" :key="d.id" :label="d.name" :value="d.id" />
|
|
|
|
|
</el-select>
|
|
|
|
|
:options="directionSelectOptions"
|
|
|
|
|
/>
|
|
|
|
|
<el-input v-else disabled model-value="加载研究方向…" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
|