|
|
|
|
@ -20,6 +20,7 @@ import {
|
|
|
|
|
listSignupChannels,
|
|
|
|
|
updateSignupChannel,
|
|
|
|
|
} from '../../../api/admin/signupChannels'
|
|
|
|
|
import { listPublicSourceChannels } from '../../../api/admin/publicSourceChannels'
|
|
|
|
|
import {
|
|
|
|
|
downloadAdminApplicationFile,
|
|
|
|
|
exportAdminApplications,
|
|
|
|
|
@ -37,6 +38,7 @@ import type {
|
|
|
|
|
CompetitionTrackPayload,
|
|
|
|
|
CompetitionTrackRow,
|
|
|
|
|
FormSchemaRow,
|
|
|
|
|
PublicSourceChannelRow,
|
|
|
|
|
SignupChannelPayload,
|
|
|
|
|
SignupChannelRow,
|
|
|
|
|
} from '../../../api/admin/types'
|
|
|
|
|
@ -99,6 +101,8 @@ const tracks = ref<CompetitionTrackRow[]>([])
|
|
|
|
|
const tracksLoading = ref(false)
|
|
|
|
|
const channels = ref<SignupChannelRow[]>([])
|
|
|
|
|
const channelsLoading = ref(false)
|
|
|
|
|
const publicSourceChannels = ref<PublicSourceChannelRow[]>([])
|
|
|
|
|
const publicSourceChannelsLoading = ref(false)
|
|
|
|
|
const applications = ref<AdminApplicationRow[]>([])
|
|
|
|
|
const selectedApplications = ref<AdminApplicationRow[]>([])
|
|
|
|
|
const applicationsLoading = ref(false)
|
|
|
|
|
@ -117,6 +121,7 @@ const applicationFilters = ref({
|
|
|
|
|
status: 'submitted',
|
|
|
|
|
track: '',
|
|
|
|
|
signup_channel_id: undefined as number | undefined,
|
|
|
|
|
public_source_channel_id: undefined as number | undefined,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const trackDialogVisible = ref(false)
|
|
|
|
|
@ -289,6 +294,7 @@ watch(tabKey, (t) => {
|
|
|
|
|
if (t === 'channels') void refreshChannels()
|
|
|
|
|
if (t === 'applications') {
|
|
|
|
|
void refreshChannels()
|
|
|
|
|
void refreshPublicSourceChannels()
|
|
|
|
|
void refreshApplications()
|
|
|
|
|
}
|
|
|
|
|
if (t === 'signupForm') void refreshSignupSchemas()
|
|
|
|
|
@ -637,6 +643,18 @@ async function refreshChannels() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function refreshPublicSourceChannels() {
|
|
|
|
|
publicSourceChannelsLoading.value = true
|
|
|
|
|
try {
|
|
|
|
|
publicSourceChannels.value = await listPublicSourceChannels()
|
|
|
|
|
} catch (e) {
|
|
|
|
|
publicSourceChannels.value = []
|
|
|
|
|
ElMessage.error(e instanceof Error ? e.message : '加载用户渠道列表失败')
|
|
|
|
|
} finally {
|
|
|
|
|
publicSourceChannelsLoading.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function applicationStatusLabel(status: string): string {
|
|
|
|
|
if (status === 'submitted') return '已提交'
|
|
|
|
|
if (status === 'draft') return '草稿'
|
|
|
|
|
@ -714,6 +732,7 @@ async function refreshApplications(page = applicationPager.value.page) {
|
|
|
|
|
status: applicationFilters.value.status || undefined,
|
|
|
|
|
track: applicationFilters.value.track || undefined,
|
|
|
|
|
signup_channel_id: applicationFilters.value.signup_channel_id || undefined,
|
|
|
|
|
public_source_channel_id: applicationFilters.value.public_source_channel_id || undefined,
|
|
|
|
|
})
|
|
|
|
|
applications.value = res.data
|
|
|
|
|
applicationPager.value = {
|
|
|
|
|
@ -730,7 +749,13 @@ async function refreshApplications(page = applicationPager.value.page) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function resetApplicationFilters() {
|
|
|
|
|
applicationFilters.value = { keyword: '', status: 'submitted', track: '', signup_channel_id: undefined }
|
|
|
|
|
applicationFilters.value = {
|
|
|
|
|
keyword: '',
|
|
|
|
|
status: 'submitted',
|
|
|
|
|
track: '',
|
|
|
|
|
signup_channel_id: undefined,
|
|
|
|
|
public_source_channel_id: undefined,
|
|
|
|
|
}
|
|
|
|
|
void refreshApplications(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -752,6 +777,7 @@ async function exportApplications(mode: AdminApplicationExportMode) {
|
|
|
|
|
status: applicationFilters.value.status || undefined,
|
|
|
|
|
track: applicationFilters.value.track || undefined,
|
|
|
|
|
signup_channel_id: applicationFilters.value.signup_channel_id || undefined,
|
|
|
|
|
public_source_channel_id: applicationFilters.value.public_source_channel_id || undefined,
|
|
|
|
|
application_ids:
|
|
|
|
|
mode === 'selected' ? selectedApplications.value.map((row) => row.id) : undefined,
|
|
|
|
|
},
|
|
|
|
|
@ -1430,7 +1456,7 @@ onMounted(() => {
|
|
|
|
|
</el-select>
|
|
|
|
|
<el-select
|
|
|
|
|
v-model="applicationFilters.signup_channel_id"
|
|
|
|
|
placeholder="渠道"
|
|
|
|
|
placeholder="报名渠道"
|
|
|
|
|
clearable
|
|
|
|
|
filterable
|
|
|
|
|
teleported
|
|
|
|
|
@ -1443,6 +1469,22 @@ onMounted(() => {
|
|
|
|
|
:value="channel.id"
|
|
|
|
|
/>
|
|
|
|
|
</el-select>
|
|
|
|
|
<el-select
|
|
|
|
|
v-model="applicationFilters.public_source_channel_id"
|
|
|
|
|
placeholder="用户渠道"
|
|
|
|
|
clearable
|
|
|
|
|
filterable
|
|
|
|
|
teleported
|
|
|
|
|
:loading="publicSourceChannelsLoading"
|
|
|
|
|
class="application-filter-select application-filter-channel"
|
|
|
|
|
>
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="channel in publicSourceChannels"
|
|
|
|
|
:key="channel.id"
|
|
|
|
|
:label="`${channel.source_name}(${channel.source_code})`"
|
|
|
|
|
:value="channel.id"
|
|
|
|
|
/>
|
|
|
|
|
</el-select>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="application-actions">
|
|
|
|
|
<el-dropdown trigger="click" @command="exportApplications">
|
|
|
|
|
@ -1499,7 +1541,7 @@ onMounted(() => {
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column prop="track_title" label="赛道" min-width="130" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="渠道" min-width="150" show-overflow-tooltip>
|
|
|
|
|
<el-table-column label="报名渠道" min-width="150" show-overflow-tooltip>
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
<span class="cell-muted">
|
|
|
|
|
{{
|
|
|
|
|
@ -1516,6 +1558,17 @@ onMounted(() => {
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column prop="contact_mobile" label="手机号" width="128" />
|
|
|
|
|
<el-table-column label="用户渠道" min-width="150" show-overflow-tooltip>
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
<span class="cell-muted">
|
|
|
|
|
{{
|
|
|
|
|
row.public_source_channel
|
|
|
|
|
? `${row.public_source_channel.source_name}(${row.public_source_channel.source_code})`
|
|
|
|
|
: row.public_source_code || '—'
|
|
|
|
|
}}
|
|
|
|
|
</span>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="附件" width="76" align="right">
|
|
|
|
|
<template #default="{ row }">{{ row.files_count }}</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
@ -2204,7 +2257,7 @@ onMounted(() => {
|
|
|
|
|
|
|
|
|
|
.application-filters {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: minmax(220px, 1fr) 130px 130px minmax(180px, 220px);
|
|
|
|
|
grid-template-columns: minmax(220px, 1fr) repeat(4, minmax(130px, 180px));
|
|
|
|
|
gap: 8px;
|
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
|