运动员数据上传
This commit is contained in:
parent
e7c414e509
commit
5a6ddc9e0c
16
src/api/match/citizenSportsSync.js
Normal file
16
src/api/match/citizenSportsSync.js
Normal file
@ -0,0 +1,16 @@
|
||||
import { http } from '../../utils/request';
|
||||
|
||||
/** 测试当前服务端配置与市民运动会平台的连接。 */
|
||||
export const citizenSportsConnectionTestPost = () => {
|
||||
return http.post('/citizen-sports-sync/connection-test', {});
|
||||
};
|
||||
|
||||
/** 预览待同步的报名数据,不会向外部平台写入。 */
|
||||
export const citizenSportsPreviewPost = (data) => {
|
||||
return http.post('/citizen-sports-sync/preview', data);
|
||||
};
|
||||
|
||||
/** 将预检通过的报名数据同步到市民运动会平台。 */
|
||||
export const citizenSportsExecutePost = (data) => {
|
||||
return http.post('/citizen-sports-sync/execute', data);
|
||||
};
|
||||
280
src/views/system/citizen-sports-sync/index.vue
Normal file
280
src/views/system/citizen-sports-sync/index.vue
Normal file
@ -0,0 +1,280 @@
|
||||
<template>
|
||||
<div class="citizen-sports-sync layout-padding">
|
||||
<el-alert
|
||||
title="此页面仅供超级管理员使用。请先在服务端配置平台地址和密钥,预览确认无误后再上传。"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
|
||||
<el-card class="mt16" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>同步条件</span>
|
||||
<el-button :loading="connectionTesting" @click="testConnection">测试平台连接</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="140px" class="sync-form">
|
||||
<el-form-item label="悦动赛事" prop="eventId">
|
||||
<el-select
|
||||
v-model="form.eventId"
|
||||
filterable
|
||||
remote
|
||||
reserve-keyword
|
||||
:remote-method="searchEvents"
|
||||
:loading="eventLoading"
|
||||
placeholder="输入赛事名称搜索"
|
||||
style="width: 100%"
|
||||
@change="selectEvent"
|
||||
>
|
||||
<el-option v-for="item in eventOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="平台赛事名称" prop="platformEventName">
|
||||
<el-input v-model="form.platformEventName" maxlength="100" placeholder="必须与一网通办申报名称完全一致" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="系列赛场次名称">
|
||||
<el-input v-model="form.seriesName" maxlength="100" placeholder="没有系列赛时留空" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="previewLoading" @click="preview">预览报名数据</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
:disabled="!previewResult?.canUpload"
|
||||
:loading="uploading"
|
||||
@click="execute"
|
||||
>
|
||||
确认上传
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card v-if="previewResult" class="mt16" shadow="never">
|
||||
<template #header>数据预览</template>
|
||||
<el-descriptions :column="4" border>
|
||||
<el-descriptions-item label="悦动赛事">{{ previewResult.eventName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报名人数">{{ previewResult.registrationCount }}</el-descriptions-item>
|
||||
<el-descriptions-item label="待上传人数">{{ previewResult.uploadRecordCount }}</el-descriptions-item>
|
||||
<el-descriptions-item label="组别数">{{ previewResult.typeCount }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-table :data="previewResult.types || []" border class="mt16">
|
||||
<el-table-column prop="typeName" label="平台组别" min-width="200" />
|
||||
<el-table-column prop="playerCount" label="人数" width="120" />
|
||||
</el-table>
|
||||
|
||||
<div class="detail-title">待上传人员明细</div>
|
||||
<el-table :data="previewResult.players || []" border height="520">
|
||||
<el-table-column type="index" label="序号" width="70" fixed="left" />
|
||||
<el-table-column prop="typeName" label="平台组别" min-width="160" fixed="left" />
|
||||
<el-table-column prop="playerName" label="姓名" width="110" fixed="left" />
|
||||
<el-table-column prop="playerId" label="用户ID" min-width="180" />
|
||||
<el-table-column prop="cardType" label="证件类型" width="100" />
|
||||
<el-table-column prop="cardNumber" label="证件号码" min-width="190" />
|
||||
<el-table-column label="性别" width="80">
|
||||
<template #default="scope">{{ formatSex(scope.row.playerSex) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="playerPhone" label="手机号" width="140" />
|
||||
<el-table-column prop="playerBirth" label="出生日期" width="120" />
|
||||
<el-table-column prop="groupName" label="队伍名称" min-width="160" />
|
||||
<el-table-column prop="deleteStatus" label="删除状态" width="100" />
|
||||
</el-table>
|
||||
|
||||
<el-alert
|
||||
v-if="previewResult.canUpload"
|
||||
class="mt16"
|
||||
title="预检通过,可以上传"
|
||||
type="success"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
<template v-else>
|
||||
<el-alert class="mt16" title="预检未通过,请先修正以下报名资料" type="error" :closable="false" show-icon />
|
||||
<el-table :data="previewResult.errors || []" border class="mt16">
|
||||
<el-table-column prop="registrationPersonId" label="报名人员ID" width="190" />
|
||||
<el-table-column prop="message" label="问题" min-width="320" />
|
||||
</el-table>
|
||||
</template>
|
||||
</el-card>
|
||||
|
||||
<el-card v-if="executeResult" class="mt16" shadow="never">
|
||||
<template #header>上传结果</template>
|
||||
<el-descriptions :column="4" border>
|
||||
<el-descriptions-item label="平台赛事编码">{{ executeResult.platformEventCode }}</el-descriptions-item>
|
||||
<el-descriptions-item label="请求人数">{{ executeResult.requestedCount }}</el-descriptions-item>
|
||||
<el-descriptions-item label="成功 / 失败">{{ executeResult.successCount }} / {{ executeResult.failureCount }}</el-descriptions-item>
|
||||
<el-descriptions-item label="未尝试">{{ executeResult.unattemptedCount }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-alert
|
||||
class="mt16"
|
||||
:title="executeResult.aborted ? '上传中途终止,请根据批次结果核查,勿直接重复上传' : '上传完成'"
|
||||
:type="executeResult.aborted ? 'error' : 'success'"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
|
||||
<el-table :data="executeResult.batches || []" border class="mt16">
|
||||
<el-table-column prop="typeName" label="组别" min-width="180" />
|
||||
<el-table-column prop="requestedCount" label="请求" width="90" />
|
||||
<el-table-column prop="successCount" label="成功" width="90" />
|
||||
<el-table-column prop="failureCount" label="失败" width="90" />
|
||||
<el-table-column label="状态" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.success ? 'success' : 'danger'">{{ scope.row.success ? '成功' : '失败' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="message" label="平台说明" min-width="260" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="citizenSportsSync">
|
||||
import { onMounted, reactive, ref, watch } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { eventPagePost } from '/@/api/match/event';
|
||||
import {
|
||||
citizenSportsConnectionTestPost,
|
||||
citizenSportsExecutePost,
|
||||
citizenSportsPreviewPost,
|
||||
} from '/@/api/match/citizenSportsSync';
|
||||
|
||||
const formRef = ref();
|
||||
const form = reactive({
|
||||
eventId: null,
|
||||
platformEventName: '',
|
||||
seriesName: '',
|
||||
});
|
||||
const rules = {
|
||||
eventId: [{ required: true, message: '请选择悦动赛事', trigger: 'change' }],
|
||||
platformEventName: [{ required: true, message: '请输入平台赛事名称', trigger: 'blur' }],
|
||||
};
|
||||
|
||||
const eventOptions = ref([]);
|
||||
const eventLoading = ref(false);
|
||||
const connectionTesting = ref(false);
|
||||
const previewLoading = ref(false);
|
||||
const uploading = ref(false);
|
||||
const previewResult = ref(null);
|
||||
const executeResult = ref(null);
|
||||
|
||||
const formatSex = (value) => ({ 1: '男', 2: '女' })[value] || value || '-';
|
||||
|
||||
const requestInput = () => ({
|
||||
eventId: form.eventId,
|
||||
platformEventName: form.platformEventName.trim(),
|
||||
seriesName: form.seriesName.trim() || null,
|
||||
});
|
||||
|
||||
async function searchEvents(keyword = '') {
|
||||
eventLoading.value = true;
|
||||
try {
|
||||
const response = await eventPagePost({ pageNo: 1, pageSize: 40, eventName: keyword || undefined });
|
||||
eventOptions.value = (response?.data?.rows || []).map((item) => ({
|
||||
value: Number(item.id ?? item.eventId),
|
||||
label: item.eventName ?? item.EventName ?? `赛事 #${item.id ?? item.eventId}`,
|
||||
}));
|
||||
} finally {
|
||||
eventLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function selectEvent(eventId) {
|
||||
const selected = eventOptions.value.find((item) => item.value === eventId);
|
||||
if (selected) form.platformEventName = selected.label;
|
||||
}
|
||||
|
||||
async function testConnection() {
|
||||
connectionTesting.value = true;
|
||||
try {
|
||||
const response = await citizenSportsConnectionTestPost();
|
||||
if (!response?.succeeded) return;
|
||||
if (response.data?.success) ElMessage.success(response.data.message || '平台连接正常');
|
||||
else ElMessage.error(response.data?.message || '平台连接失败');
|
||||
} finally {
|
||||
connectionTesting.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function preview() {
|
||||
if (!(await formRef.value?.validate().catch(() => false))) return;
|
||||
previewLoading.value = true;
|
||||
executeResult.value = null;
|
||||
try {
|
||||
const response = await citizenSportsPreviewPost(requestInput());
|
||||
if (!response?.succeeded) return;
|
||||
previewResult.value = response.data;
|
||||
if (response.data?.canUpload) ElMessage.success('预检通过,请核对人数和组别后再确认上传');
|
||||
} finally {
|
||||
previewLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function execute() {
|
||||
if (!previewResult.value?.canUpload) return;
|
||||
const confirmed = await ElMessageBox.confirm(
|
||||
`确认将 ${previewResult.value.uploadRecordCount} 人上传到“${form.platformEventName.trim()}”吗?`,
|
||||
'确认上传',
|
||||
{
|
||||
type: 'warning',
|
||||
confirmButtonText: '确认上传',
|
||||
cancelButtonText: '取消',
|
||||
}
|
||||
)
|
||||
.then(() => true)
|
||||
.catch(() => false);
|
||||
if (!confirmed) return;
|
||||
|
||||
uploading.value = true;
|
||||
try {
|
||||
const response = await citizenSportsExecutePost({ ...requestInput(), confirmUpload: true });
|
||||
if (!response?.succeeded) return;
|
||||
executeResult.value = response.data;
|
||||
if (!response.data?.aborted) ElMessage.success('报名数据上传完成');
|
||||
} finally {
|
||||
uploading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [form.eventId, form.platformEventName, form.seriesName],
|
||||
() => {
|
||||
previewResult.value = null;
|
||||
executeResult.value = null;
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => searchEvents());
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.citizen-sports-sync {
|
||||
display: block;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.mt16 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.sync-form {
|
||||
max-width: 760px;
|
||||
}
|
||||
|
||||
.detail-title {
|
||||
margin: 20px 0 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
Loading…
x
Reference in New Issue
Block a user