|
|
@@ -59,55 +59,107 @@
|
|
|
|
|
|
<div class="section-title">
|
|
|
<span>乐跑记录</span>
|
|
|
- <span class="record-count">共 {{ records.length }} 条</span>
|
|
|
+ <span class="record-count">{{ activeRecordCountLabel }}</span>
|
|
|
</div>
|
|
|
- <a-table
|
|
|
- :data="records"
|
|
|
- :pagination="{ pageSize: 8, showTotal: true }"
|
|
|
- :scroll="{ x: 900, y: 280 }"
|
|
|
- size="small"
|
|
|
- row-key="id"
|
|
|
- :bordered="false"
|
|
|
- >
|
|
|
- <template #columns>
|
|
|
- <a-table-column v-if="admin" title="所属用户" :width="120">
|
|
|
- <template #cell="{ record }">{{ record.username || '-' }}</template>
|
|
|
- </a-table-column>
|
|
|
- <a-table-column title="状态" :width="200">
|
|
|
- <template #cell="{ record }">
|
|
|
- <div class="state">
|
|
|
- <div
|
|
|
- class="circle"
|
|
|
- :class="record.result?.record_failed_reason === '自动确认有效' ? 'one' : 'else'"
|
|
|
- />
|
|
|
- {{ record.result?.record_failed_reason }}
|
|
|
- </div>
|
|
|
+ <a-tabs v-model:active-key="recordTab" @change="handleRecordTabChange">
|
|
|
+ <a-tab-pane key="platform" title="平台记录">
|
|
|
+ <a-table
|
|
|
+ :data="records"
|
|
|
+ :pagination="{ pageSize: 8, showTotal: true }"
|
|
|
+ :scroll="{ x: 900, y: 280 }"
|
|
|
+ size="small"
|
|
|
+ row-key="id"
|
|
|
+ :bordered="false"
|
|
|
+ >
|
|
|
+ <template #columns>
|
|
|
+ <a-table-column v-if="admin" title="所属用户" :width="120">
|
|
|
+ <template #cell="{ record }">{{ record.username || '-' }}</template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="状态" :width="200">
|
|
|
+ <template #cell="{ record }">
|
|
|
+ <div class="state">
|
|
|
+ <div
|
|
|
+ class="circle"
|
|
|
+ :class="record.result?.record_failed_reason === '自动确认有效' ? 'one' : 'else'"
|
|
|
+ />
|
|
|
+ {{ record.result?.record_failed_reason }}
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="跑区" :width="180">
|
|
|
+ <template #cell="{ record }">{{ record.result?.pass_tit }}</template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="距离" :width="90">
|
|
|
+ <template #cell="{ record }">{{ record.result?.distance }} Km</template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="时长" :width="100">
|
|
|
+ <template #cell="{ record }">{{ formatSecondsToMinSec(record.result?.time) }}</template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="配速" :width="80">
|
|
|
+ <template #cell="{ record }">
|
|
|
+ {{ calculatePace(record.result?.time, record.result?.distance) }}
|
|
|
+ </template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="乐跑时间" :width="160">
|
|
|
+ <template #cell="{ record }">{{ formatTime(record.time) }}</template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="" :width="90" fixed="right">
|
|
|
+ <template #cell="{ record }">
|
|
|
+ <a-button type="text" size="small" @click="openPlatformRecordDetail(record)">详情</a-button>
|
|
|
+ </template>
|
|
|
+ </a-table-column>
|
|
|
</template>
|
|
|
- </a-table-column>
|
|
|
- <a-table-column title="跑区" :width="180">
|
|
|
- <template #cell="{ record }">{{ record.result?.pass_tit }}</template>
|
|
|
- </a-table-column>
|
|
|
- <a-table-column title="距离" :width="90">
|
|
|
- <template #cell="{ record }">{{ record.result?.distance }} Km</template>
|
|
|
- </a-table-column>
|
|
|
- <a-table-column title="时长" :width="100">
|
|
|
- <template #cell="{ record }">{{ formatSecondsToMinSec(record.result?.time) }}</template>
|
|
|
- </a-table-column>
|
|
|
- <a-table-column title="配速" :width="80">
|
|
|
- <template #cell="{ record }">
|
|
|
- {{ calculatePace(record.result?.time, record.result?.distance) }}
|
|
|
- </template>
|
|
|
- </a-table-column>
|
|
|
- <a-table-column title="乐跑时间" :width="160">
|
|
|
- <template #cell="{ record }">{{ formatTime(record.time) }}</template>
|
|
|
- </a-table-column>
|
|
|
- <a-table-column title="" :width="90" fixed="right">
|
|
|
- <template #cell="{ record }">
|
|
|
- <a-button type="text" size="small" @click="openRecordDetail(record)">详情</a-button>
|
|
|
+ </a-table>
|
|
|
+ </a-tab-pane>
|
|
|
+ <a-tab-pane key="official" title="官方记录" :disabled="!canViewOfficialRecords">
|
|
|
+ <a-alert
|
|
|
+ v-if="!canViewOfficialRecords"
|
|
|
+ type="warning"
|
|
|
+ class="official-record-alert"
|
|
|
+ content="仅状态为正常的账号可查看官方记录,请使用登录器更新账号后再试。"
|
|
|
+ />
|
|
|
+ <a-table
|
|
|
+ :data="officialRecords"
|
|
|
+ :loading="officialLoading"
|
|
|
+ :pagination="officialPaginationConfig"
|
|
|
+ :scroll="{ x: 900, y: 280 }"
|
|
|
+ size="small"
|
|
|
+ row-key="id"
|
|
|
+ :bordered="false"
|
|
|
+ @page-change="handleOfficialPageChange"
|
|
|
+ >
|
|
|
+ <template #columns>
|
|
|
+ <a-table-column title="状态" :width="150">
|
|
|
+ <template #cell="{ record }">
|
|
|
+ <a-tag :color="String(record.record_status) === '1' ? 'green' : 'orangered'">
|
|
|
+ {{ officialRecordStatus(record) }}
|
|
|
+ </a-tag>
|
|
|
+ </template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="跑区" :width="210">
|
|
|
+ <template #cell="{ record }">{{ record.title || '-' }}</template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="类型" :width="120">
|
|
|
+ <template #cell="{ record }">{{ record.tag || record.point_type_str || '-' }}</template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="配速" :width="80">
|
|
|
+ <template #cell="{ record }">
|
|
|
+ {{ calculatePace(Number(record.end_time) - Number(record.start_time), record.distance) }}
|
|
|
+ </template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="距离" :width="90">
|
|
|
+ <template #cell="{ record }">{{ record.distance || '-' }} Km</template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="时长" :width="100">
|
|
|
+ <template #cell="{ record }">{{ formatOfficialDuration(record) }}</template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="乐跑时间" :width="160">
|
|
|
+ <template #cell="{ record }">{{ formatUnixTime(record.start_time) }}</template>
|
|
|
+ </a-table-column>
|
|
|
</template>
|
|
|
- </a-table-column>
|
|
|
- </template>
|
|
|
- </a-table>
|
|
|
+ </a-table>
|
|
|
+ </a-tab-pane>
|
|
|
+ </a-tabs>
|
|
|
</template>
|
|
|
</a-spin>
|
|
|
</a-modal>
|
|
|
@@ -116,7 +168,12 @@
|
|
|
<script setup>
|
|
|
import { ref, computed } from 'vue'
|
|
|
import { useRouter } from 'vue-router'
|
|
|
-import { lepaoRecords, adminLepaoRecords } from '@/api/lepao'
|
|
|
+import {
|
|
|
+ lepaoRecords,
|
|
|
+ adminLepaoRecords,
|
|
|
+ officialTermRecords,
|
|
|
+ adminOfficialTermRecords
|
|
|
+} from '@/api/lepao'
|
|
|
import { Notification, Message } from '@arco-design/web-vue'
|
|
|
import useChartOption from '@/hooks/chart-option'
|
|
|
|
|
|
@@ -151,6 +208,11 @@ const visible = ref(false)
|
|
|
const loading = ref(false)
|
|
|
const account = ref(null)
|
|
|
const records = ref([])
|
|
|
+const officialRecords = ref([])
|
|
|
+const officialLoading = ref(false)
|
|
|
+const officialSummary = ref({})
|
|
|
+const officialPagination = ref({ current: 1, pageSize: 10, total: 0 })
|
|
|
+const recordTab = ref('platform')
|
|
|
const calendarYear = ref(new Date().getFullYear())
|
|
|
const router = useRouter()
|
|
|
|
|
|
@@ -229,6 +291,24 @@ const faceStateLabel = computed(() => {
|
|
|
return '-'
|
|
|
})
|
|
|
|
|
|
+const canViewOfficialRecords = computed(() => account.value?.state === 1)
|
|
|
+
|
|
|
+const activeRecordCountLabel = computed(() => {
|
|
|
+ if (recordTab.value === 'official') {
|
|
|
+ const total = officialPagination.value.total || officialRecords.value.length
|
|
|
+ return `官方记录共 ${total} 条,有效次数 ${officialSummary.value?.total_score_num ?? 0} 次(${officialSummary.value?.term_name ?? '本学期'})`
|
|
|
+ }
|
|
|
+ return `平台记录共 ${records.value.length} 条`
|
|
|
+})
|
|
|
+
|
|
|
+const officialPaginationConfig = computed(() => ({
|
|
|
+ current: officialPagination.value.current,
|
|
|
+ pageSize: officialPagination.value.pageSize,
|
|
|
+ total: officialPagination.value.total || officialRecords.value.length,
|
|
|
+ showTotal: true,
|
|
|
+ showPageSize: false
|
|
|
+}))
|
|
|
+
|
|
|
const yearOptions = computed(() => {
|
|
|
const years = new Set([calendarYear.value, new Date().getFullYear()])
|
|
|
records.value.forEach((record) => {
|
|
|
@@ -313,6 +393,12 @@ const formatTime = (time) => {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+const formatUnixTime = (time) => {
|
|
|
+ const timestamp = Number(time)
|
|
|
+ if (!Number.isFinite(timestamp) || timestamp <= 0) return '-'
|
|
|
+ return formatTime(timestamp * 1000)
|
|
|
+}
|
|
|
+
|
|
|
function calculatePace(seconds, kilometers) {
|
|
|
if (!seconds || !kilometers) return '-'
|
|
|
const paceInSeconds = seconds / kilometers
|
|
|
@@ -328,6 +414,19 @@ function formatSecondsToMinSec(totalSeconds) {
|
|
|
return `${minutes}分${seconds.toString().padStart(2, '0')}秒`
|
|
|
}
|
|
|
|
|
|
+const formatOfficialDuration = (record) => {
|
|
|
+ const start = Number(record?.start_time)
|
|
|
+ const end = Number(record?.end_time)
|
|
|
+ if (!Number.isFinite(start) || !Number.isFinite(end) || end < start) return '-'
|
|
|
+ return formatSecondsToMinSec(end - start)
|
|
|
+}
|
|
|
+
|
|
|
+const officialRecordStatus = (record) => {
|
|
|
+ const status = String(record?.record_status ?? '')
|
|
|
+ if (status === '1') return '有效'
|
|
|
+ return '无效'
|
|
|
+}
|
|
|
+
|
|
|
const fetchAllRecords = async (studentNum) => {
|
|
|
const all = []
|
|
|
let current = 1
|
|
|
@@ -353,7 +452,62 @@ const fetchAllRecords = async (studentNum) => {
|
|
|
return all.sort((a, b) => b.time - a.time)
|
|
|
}
|
|
|
|
|
|
-const openRecordDetail = (record) => {
|
|
|
+const fetchOfficialRecords = async (page = 1) => {
|
|
|
+ if (!account.value?.student_num) return
|
|
|
+ if (!canViewOfficialRecords.value) {
|
|
|
+ Message.warning('请使用登录器更新账号后查看官方乐跑记录')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ officialLoading.value = true
|
|
|
+ try {
|
|
|
+ const fetchRecords = props.admin ? adminOfficialTermRecords : officialTermRecords
|
|
|
+ const res = await fetchRecords({
|
|
|
+ student_num: account.value.student_num,
|
|
|
+ page
|
|
|
+ })
|
|
|
+ if (!res || res.code !== 0) {
|
|
|
+ if (account.value && String(res?.msg || '').includes('登录')) {
|
|
|
+ account.value.state = 0
|
|
|
+ }
|
|
|
+ throw new Error(res?.msg || '获取乐跑记录失败')
|
|
|
+ }
|
|
|
+
|
|
|
+ const data = res.data || {}
|
|
|
+ officialSummary.value = data
|
|
|
+ officialRecords.value = data.list || []
|
|
|
+ officialPagination.value = {
|
|
|
+ ...officialPagination.value,
|
|
|
+ current: data.page || page,
|
|
|
+ total: Number(data.total_num || officialRecords.value.length)
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ Notification.error({
|
|
|
+ title: '获取官方乐跑记录失败',
|
|
|
+ content: error.message || '请稍后再试'
|
|
|
+ })
|
|
|
+ } finally {
|
|
|
+ officialLoading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const handleRecordTabChange = (key) => {
|
|
|
+ if (key !== 'official') return
|
|
|
+ if (!canViewOfficialRecords.value) {
|
|
|
+ recordTab.value = 'platform'
|
|
|
+ Message.warning('请使用登录器更新账号后查看官方记录')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (officialRecords.value.length === 0) {
|
|
|
+ fetchOfficialRecords(1)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const handleOfficialPageChange = (page) => {
|
|
|
+ fetchOfficialRecords(page)
|
|
|
+}
|
|
|
+
|
|
|
+const openPlatformRecordDetail = (record) => {
|
|
|
const key = record.public_id || record.id
|
|
|
if (!key) {
|
|
|
Message.warning('该记录缺少可用标识,无法打开详情')
|
|
|
@@ -372,6 +526,10 @@ const openModal = async (record) => {
|
|
|
visible.value = true
|
|
|
loading.value = true
|
|
|
records.value = []
|
|
|
+ officialRecords.value = []
|
|
|
+ officialSummary.value = {}
|
|
|
+ officialPagination.value = { current: 1, pageSize: 10, total: 0 }
|
|
|
+ recordTab.value = 'platform'
|
|
|
|
|
|
try {
|
|
|
const list = await fetchAllRecords(record.student_num)
|
|
|
@@ -446,6 +604,10 @@ defineExpose({ openModal })
|
|
|
color: var(--color-text-3);
|
|
|
}
|
|
|
|
|
|
+.official-record-alert {
|
|
|
+ margin-bottom: 12px;
|
|
|
+}
|
|
|
+
|
|
|
.state {
|
|
|
display: flex;
|
|
|
align-items: center;
|