feat: 查看已提交数据
This commit is contained in:
@@ -448,6 +448,8 @@ const handleTestComplete = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const contestantId = computed(() => route.query.id || route.params.id)
|
||||
|
||||
const readOnly = computed(() => {
|
||||
if (route.query.id && !hasValidEmail.value) {
|
||||
return true
|
||||
|
||||
310
src/views/Preview/index.vue
Normal file
310
src/views/Preview/index.vue
Normal file
@@ -0,0 +1,310 @@
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<div class="card">
|
||||
<section class="stats-section">
|
||||
<h1 class="title">{{ $t('Preview.title') }}</h1>
|
||||
<div class="count-badge">
|
||||
<span class="label">{{ $t('Preview.total') }}</span>
|
||||
<span class="number">{{ submittedCount }}</span>
|
||||
</div>
|
||||
<button v-loading="excelLoading" @click="handleDownloadAll" class="download-all-btn flex">
|
||||
<SvgIcon name="CDownload" size="22" color="#fff" />
|
||||
{{ $t('Preview.downloadExcel') }}
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<section class="download-section">
|
||||
<h2 class="subtitle">{{ $t('Preview.range') }}</h2>
|
||||
|
||||
<div class="input-group">
|
||||
<div class="field">
|
||||
<label>{{ $t('Preview.startIndex') }}</label>
|
||||
<input v-model.number="range.start" type="number" placeholder="10000" min="1" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ $t('Preview.endIndex') }}</label>
|
||||
<input v-model.number="range.end" type="number" :placeholder="maxIndex" min="1" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button v-loading="fileDownloading" @click="handleDownload" :disabled="!isValid" class="download-btn">
|
||||
<span class="btn-text">{{ $t('Preview.download') }}</span>
|
||||
</button>
|
||||
|
||||
<p v-if="errorMsg" class="status-text error">{{ errorMsg }}</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { Https } from '@/utils/request'
|
||||
import { debounce } from 'lodash-es'
|
||||
|
||||
// 模拟已提交人数
|
||||
const submittedCount = ref(0)
|
||||
|
||||
// 输入框绑定的数据模型
|
||||
const range = ref({
|
||||
start: null,
|
||||
end: null
|
||||
})
|
||||
const maxIndex = ref(10000)
|
||||
const handleFetchSubmittedCount = async () => {
|
||||
Https.axiosGet(Https.httpUrls.getContestCount).then((res) => {
|
||||
submittedCount.value = res.count
|
||||
maxIndex.value = res.maxContestantNumber
|
||||
})
|
||||
}
|
||||
|
||||
// 逻辑判断:区间是否合法
|
||||
const isValid = computed(() => {
|
||||
const { start, end } = range.value
|
||||
// 必须是数字,且起始>0,结束>=起始,结束不超过当前总数
|
||||
return start !== null && end !== null && start > 0 && end >= start && end <= maxIndex.value
|
||||
})
|
||||
|
||||
// 错误提示文案
|
||||
const errorMsg = computed(() => {
|
||||
const { start, end } = range.value
|
||||
if (start === null || end === null) return ''
|
||||
if (start < 10000) return '起始序号必须大于 10000'
|
||||
if (end < start) return '结束序号不能小于起始序号'
|
||||
if (end > maxIndex.value) return `结束序号不能超过最大值 ${maxIndex.value}`
|
||||
return ''
|
||||
})
|
||||
|
||||
const excelLoading = ref(false)
|
||||
const handleDownloadAll = debounce(() => {
|
||||
excelLoading.value = true
|
||||
|
||||
Https.axiosGet(Https.httpUrls.getExcel, {
|
||||
responseType: 'blob',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
})
|
||||
.then((res) => {
|
||||
// 创建下载链接
|
||||
|
||||
const url = window.URL.createObjectURL(new Blob([res.data]))
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.setAttribute('download', `Global_Awards_Applications_${Date.now()}.xlsx`)
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
})
|
||||
.finally(() => {
|
||||
excelLoading.value = false
|
||||
})
|
||||
}, 500)
|
||||
|
||||
const fileDownloading = ref(false)
|
||||
// 下载执行函数
|
||||
const handleDownload = debounce(() => {
|
||||
if (!isValid.value) return
|
||||
fileDownloading.value = true
|
||||
Https.axiosPost(
|
||||
Https.httpUrls.postExportFile,
|
||||
{
|
||||
minContestantNumber: range.value.start,
|
||||
maxContestantNumber: range.value.end
|
||||
},
|
||||
{ responseType: 'blob' }
|
||||
)
|
||||
.then((res) => {
|
||||
// 创建下载链接
|
||||
const url = window.URL.createObjectURL(new Blob([res.data]))
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.setAttribute(
|
||||
'download',
|
||||
`Global_Awards_Applications_${range.value.start}_to_${range.value.end}.zip`
|
||||
)
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
})
|
||||
.finally(() => {
|
||||
fileDownloading.value = false
|
||||
})
|
||||
}, 500)
|
||||
|
||||
onMounted(() => {
|
||||
handleFetchSubmittedCount()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
/* 全局背景容器 */
|
||||
.page-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
/* 渐变背景:深邃蓝紫色调 */
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
}
|
||||
|
||||
/* 核心卡片样式 */
|
||||
.card {
|
||||
background: #ffffff;
|
||||
width: 80rem;
|
||||
padding: 4rem;
|
||||
border-radius: 2.4rem;
|
||||
box-shadow: 0 2rem 4rem rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* 统计区域 */
|
||||
.title {
|
||||
margin: 0 0 2.4rem 0;
|
||||
font-size: 2.4rem;
|
||||
text-align: center;
|
||||
color: #2d3436;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.count-badge {
|
||||
background: #f8f9fa;
|
||||
border: 0.2rem solid #edf2f7;
|
||||
border-radius: 1.6rem;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.count-badge .label {
|
||||
display: block;
|
||||
font-size: 1.4rem;
|
||||
color: #636e72;
|
||||
margin-bottom: 0.8rem;
|
||||
}
|
||||
|
||||
.count-badge .number {
|
||||
font-size: 4rem;
|
||||
font-weight: 900;
|
||||
color: #4834d4;
|
||||
}
|
||||
|
||||
.download-all-btn {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 1.2rem;
|
||||
background-color: #00b894;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 1rem;
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
column-gap: 1rem;
|
||||
margin-top: 2rem;
|
||||
.c-svg {
|
||||
width: initial;
|
||||
height: initial;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 0.1rem;
|
||||
background: #eee;
|
||||
margin: 3.2rem 0;
|
||||
}
|
||||
|
||||
/* 表单区域 */
|
||||
.subtitle {
|
||||
font-size: 1.6rem;
|
||||
color: #2d3436;
|
||||
margin-bottom: 2rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
display: flex;
|
||||
gap: 1.6rem;
|
||||
margin-bottom: 2.4rem;
|
||||
}
|
||||
|
||||
.field {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.field label {
|
||||
display: block;
|
||||
font-size: 1.2rem;
|
||||
color: #b2bec3;
|
||||
margin-bottom: 0.6rem;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.field input {
|
||||
width: 100%;
|
||||
padding: 1.2rem 1.6rem;
|
||||
border: 0.2rem solid #dfe6e9;
|
||||
border-radius: 1.2rem;
|
||||
font-size: 1.6rem;
|
||||
color: #2d3436;
|
||||
transition: all 0.3s ease;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.field input:focus {
|
||||
outline: none;
|
||||
border-color: #6c5ce7;
|
||||
box-shadow: 0 0 0 4px rgba(108, 92, 231, 0.1);
|
||||
}
|
||||
|
||||
/* 按钮逻辑 */
|
||||
.download-btn {
|
||||
width: 100%;
|
||||
padding: 1.6rem;
|
||||
border: none;
|
||||
border-radius: 1.2rem;
|
||||
background: #6c5ce7;
|
||||
color: white;
|
||||
font-size: 1.6rem;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.download-btn:hover:not(:disabled) {
|
||||
background: #5849be;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 0.8rem 1.5rem rgba(108, 92, 231, 0.3);
|
||||
}
|
||||
|
||||
.download-btn:active:not(:disabled) {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.download-btn:disabled {
|
||||
background: #dfe6e9;
|
||||
color: #b2bec3;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* 状态文本 */
|
||||
.status-text {
|
||||
text-align: center;
|
||||
font-size: 1.3rem;
|
||||
margin-top: 1.6rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.status-text.error {
|
||||
color: #ff7675;
|
||||
}
|
||||
|
||||
.status-text.success {
|
||||
color: #00b894;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user