Browse Source

✨ feat: 增加官方乐跑记录查看接口

Pchen. 3 weeks ago
parent
commit
4f015224e5

+ 18 - 0
src/api/lepao.js

@@ -8,10 +8,12 @@ const api = {
   CountLedgerMyList: '/Lepao/Count/Ledger/MyList',
   CountLedgerAdminList: '/Admin/Lepao/Count/Ledger/List',
   Records: '/Lepao/Records',
+  OfficialTermRecords: '/Lepao/OfficialTermRecords',
   ChangeAutoRun: '/Lepao/ChangeAutoRun',
   SingleRun: '/Lepao/SingleRun',
   GetRecordDetail: '/Lepao/GetRecordDetail',
   AdminRecords: '/Admin/Lepao/Records',
+  AdminOfficialTermRecords: '/Admin/Lepao/OfficialTermRecords',
   AdminGetRecordDetail: '/Admin/Lepao/GetRecordDetail',
   BeginFaceReco: '/Face/BeginFaceReco',
   BindAuditList: '/Lepao/BindAudit/List',
@@ -88,6 +90,22 @@ export function adminLepaoRecords (parameter) {
   })
 }
 
+export function officialTermRecords (parameter) {
+  return request({
+    url: api.OfficialTermRecords,
+    method: 'get',
+    params: parameter
+  })
+}
+
+export function adminOfficialTermRecords (parameter) {
+  return request({
+    url: api.AdminOfficialTermRecords,
+    method: 'get',
+    params: parameter
+  })
+}
+
 export function changeAutoRun (parameter) {
   return request({
     url: api.ChangeAutoRun,

+ 210 - 48
src/components/LepaoAccountCard/accountDetailCard.vue

@@ -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;

+ 10 - 1
src/components/Map/MapContainer.vue

@@ -27,6 +27,15 @@ let props = defineProps({
 
 let map = null
 
+const getInitialCenter = () => {
+  if (props.pathData?.length > 0) return props.pathData[Math.floor(props.pathData.length / 2)]
+  if (props.point_list?.length > 0) {
+    const point = props.point_list[0]
+    return [point.longtitude, point.latitude]
+  }
+  return [106.5799475868821, 29.504864472181577]
+}
+
 onMounted(() => {
   AMapLoader.load({
     key: "d1f123693def8a412c976184daa4b60e",
@@ -41,7 +50,7 @@ onMounted(() => {
         zoom: 18, //初始化地图层级
         rotation: -15, //初始地图顺时针旋转的角度
         zooms: [3, 20], //地图显示的缩放级别范围
-        center: props.pathData?.length > 0 ? props.pathData[Math.floor(props.pathData.length / 2)] : [106.5799475868821, 29.504864472181577],
+        center: getInitialCenter(),
       })
 
       // 添加折线