|
|
@@ -0,0 +1,278 @@
|
|
|
+<template>
|
|
|
+
|
|
|
+ <div class="container">
|
|
|
+ <Breadcrumb :items="['校园乐跑', '乐跑记录']" />
|
|
|
+ <a-card title="乐跑记录">
|
|
|
+ <a-row>
|
|
|
+ <a-col :flex="'1000px'">
|
|
|
+ <a-form :model="queryData" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }"
|
|
|
+ label-align="left">
|
|
|
+ <a-row :gutter="16">
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item field="name" label="账号名称">
|
|
|
+ <a-input v-model="queryData.name" placeholder="请输入账号名称" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item field="lepao_account" label="学号">
|
|
|
+ <a-input-number v-model="queryData.lepao_account" placeholder="请输入学号" :step="1" :precision="0" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item field="email" label="通知邮箱">
|
|
|
+ <a-input v-model="queryData.email" placeholder="请输入通知邮箱" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+ </a-form>
|
|
|
+ </a-col>
|
|
|
+ <a-divider style="height: 84px" direction="vertical" />
|
|
|
+ <a-col :flex="1" >
|
|
|
+ <a-space direction="vertical" :size="18">
|
|
|
+ <a-button type="primary" @click="search">
|
|
|
+ <template #icon>
|
|
|
+ <icon-search />
|
|
|
+ </template>
|
|
|
+ 搜索
|
|
|
+ </a-button>
|
|
|
+ <a-button @click="reset">
|
|
|
+ <template #icon>
|
|
|
+ <icon-refresh />
|
|
|
+ </template>
|
|
|
+ 重置
|
|
|
+ </a-button>
|
|
|
+ </a-space>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+
|
|
|
+ <a-table :data="data" stripe hoverable column-resizable class="table" :loading="loading" :pagination="{
|
|
|
+ showPageSize: true,
|
|
|
+ showJumper: true,
|
|
|
+ showTotal: true,
|
|
|
+ pageSize: pagination.pagesize,
|
|
|
+ current: pagination.current,
|
|
|
+ total: pagination.total
|
|
|
+ }" @page-change="handlePageChange" @page-size-change="handlePageSizeChange">
|
|
|
+
|
|
|
+ <template #name-filter="{ filterValue, setFilterValue, handleFilterConfirm, handleFilterReset }">
|
|
|
+ <div class="custom-filter">
|
|
|
+ <a-space direction="vertical">
|
|
|
+ <a-input :model-value="filterValue[0]" @input="(value) => setFilterValue([value])" />
|
|
|
+ <div class="custom-filter-footer">
|
|
|
+ <a-button @click="handleFilterReset">重置</a-button>
|
|
|
+ <a-button @click="handleFilterConfirm">确定</a-button>
|
|
|
+ </div>
|
|
|
+ </a-space>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template #columns>
|
|
|
+ <a-table-column title="学号" :width="120" data-index="lepao_account" ellipsis tooltip :filterable="{
|
|
|
+ filter: (value, record) => (record.lepao_account ?? '').includes(value),
|
|
|
+ slotName: 'name-filter',
|
|
|
+ icon: () => h(IconSearch)
|
|
|
+ }"></a-table-column>
|
|
|
+ <a-table-column title="账号名称" :filterable="{
|
|
|
+ filter: (value, record) => (record.name ?? '').includes(value),
|
|
|
+ slotName: 'name-filter',
|
|
|
+ icon: () => h(IconSearch)
|
|
|
+ }">
|
|
|
+ <template #cell="{ record }">
|
|
|
+ {{ record.name }}
|
|
|
+ </template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="状态" ellipsis tooltip>
|
|
|
+ <template #cell="{ record }">
|
|
|
+ <div v-if="record.result.record_failed_reason === ''" class="state">
|
|
|
+ <div class="circle one"></div>正常
|
|
|
+ </div>
|
|
|
+ <div v-else class="state">
|
|
|
+ <div class="circle else"></div>{{ record.result.record_failed_reason }}
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="跑区" :filterable="{
|
|
|
+ filter: (value, record) => (record.result.pass_tit ?? '').includes(value),
|
|
|
+ slotName: 'name-filter',
|
|
|
+ icon: () => h(IconSearch)
|
|
|
+ }">
|
|
|
+ <template #cell="{ record }">
|
|
|
+ {{ record.result.pass_tit }}
|
|
|
+ </template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="乐跑距离" :width="120" ellipsis tooltip>
|
|
|
+ <template #cell="{ record }">
|
|
|
+ {{ record.result.distance }} Km
|
|
|
+ </template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="跑步时长" :width="120" ellipsis tooltip>
|
|
|
+ <template #cell="{ record }">
|
|
|
+ {{ formatSecondsToMinSec(record.result.time) }}
|
|
|
+ </template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="平均配速" :width="120" ellipsis tooltip>
|
|
|
+ <template #cell="{ record }">
|
|
|
+ {{ calculatePace(record.result.time, record.result.distance) }}
|
|
|
+ </template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="乐跑时间" :width="170" ellipsis tooltip>
|
|
|
+ <template #cell="{ record }">
|
|
|
+ {{ stramptoTime(record.time) }}
|
|
|
+ </template>
|
|
|
+ </a-table-column>
|
|
|
+ <a-table-column title="操作" :width="170" ellipsis tooltip>
|
|
|
+ <template #cell="{ record }">
|
|
|
+ <a-button @click="$router.push(`/admin/lepaoRecords/${record.id}`)">查看详情</a-button>
|
|
|
+ </template>
|
|
|
+ </a-table-column>
|
|
|
+ </template>
|
|
|
+ </a-table>
|
|
|
+ </a-card>
|
|
|
+ </div>
|
|
|
+
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, reactive, h } from 'vue'
|
|
|
+import { adminLepaoRecords } from '@/api/lepao'
|
|
|
+import { Notification } from '@arco-design/web-vue'
|
|
|
+import { IconSearch } from '@arco-design/web-vue/es/icon'
|
|
|
+
|
|
|
+const data = ref([])
|
|
|
+const loading = ref(false)
|
|
|
+
|
|
|
+const queryData = reactive({
|
|
|
+ name: '',
|
|
|
+ lepao_account: '',
|
|
|
+ email: ''
|
|
|
+})
|
|
|
+
|
|
|
+const pagination = reactive({
|
|
|
+ total: 0,
|
|
|
+ current: 1,
|
|
|
+ pagesize: 20
|
|
|
+})
|
|
|
+
|
|
|
+const search = () => {
|
|
|
+ pagination.current = 1
|
|
|
+ getRecords()
|
|
|
+}
|
|
|
+
|
|
|
+const reset = () => {
|
|
|
+ pagination.current = 1
|
|
|
+ queryData.name = ''
|
|
|
+ queryData.lepao_account = ''
|
|
|
+ queryData.email = ''
|
|
|
+ queryData.area = ''
|
|
|
+ getRecords()
|
|
|
+}
|
|
|
+
|
|
|
+const getRecords = async () => {
|
|
|
+ try {
|
|
|
+ loading.value = true
|
|
|
+ const reqData = {
|
|
|
+ ...queryData,
|
|
|
+ pagesize: pagination.pagesize,
|
|
|
+ current: pagination.current
|
|
|
+ }
|
|
|
+ const res = await adminLepaoRecords(reqData)
|
|
|
+ if (!res || res.code !== 0)
|
|
|
+ return Notification.error({
|
|
|
+ title: '获取乐跑记录失败!',
|
|
|
+ content: res?.msg ?? '请稍后再试'
|
|
|
+ })
|
|
|
+ data.value = res.data
|
|
|
+ pagination.total = res.pagination.total
|
|
|
+ } catch (error) {
|
|
|
+ Notification.error({
|
|
|
+ title: '获取乐跑记录失败!',
|
|
|
+ content: error.message || '请稍后再试'
|
|
|
+ })
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 分页 - 页码变化
|
|
|
+const handlePageChange = (page) => {
|
|
|
+ pagination.current = page
|
|
|
+ getPathList()
|
|
|
+}
|
|
|
+
|
|
|
+// 分页 - 每页条数变化
|
|
|
+const handlePageSizeChange = (size) => {
|
|
|
+ pagination.pagesize = size
|
|
|
+ pagination.current = 1 // 页大小变化后回到第一页
|
|
|
+ getPathList()
|
|
|
+}
|
|
|
+
|
|
|
+const stramptoTime = (time) => {
|
|
|
+ return new Date(time).toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' })
|
|
|
+}
|
|
|
+
|
|
|
+function calculatePace(seconds, kilometers) {
|
|
|
+ const paceInSeconds = seconds / kilometers;
|
|
|
+ const minutes = Math.floor(paceInSeconds / 60);
|
|
|
+ const remainingSeconds = Math.round(paceInSeconds % 60);
|
|
|
+
|
|
|
+ return `${minutes}'${remainingSeconds.toString().padStart(2, '0')}''`;
|
|
|
+}
|
|
|
+
|
|
|
+function formatSecondsToMinSec(totalSeconds) {
|
|
|
+ const minutes = Math.floor(totalSeconds / 60);
|
|
|
+ const seconds = totalSeconds % 60;
|
|
|
+
|
|
|
+ return `${minutes}分${seconds.toString().padStart(2, '0')}秒`;
|
|
|
+}
|
|
|
+
|
|
|
+getRecords()
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="less">
|
|
|
+.container {
|
|
|
+ padding: 0 20px 20px 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.table {
|
|
|
+ margin-top: 15px;
|
|
|
+
|
|
|
+ .state {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ .circle {
|
|
|
+ border-radius: 50%;
|
|
|
+ height: 8px;
|
|
|
+ min-height: 8px;
|
|
|
+ width: 8px;
|
|
|
+ min-width: 8px;
|
|
|
+ margin-right: 5px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .zero {
|
|
|
+ background-color: rgb(var(--orange-6));
|
|
|
+ }
|
|
|
+
|
|
|
+ .one {
|
|
|
+ background-color: rgb(var(--green-6));
|
|
|
+ }
|
|
|
+
|
|
|
+ .else {
|
|
|
+ background-color: rgb(var(--red-6));
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.custom-filter {
|
|
|
+ padding: 20px;
|
|
|
+ background: var(--color-bg-5);
|
|
|
+ border: 1px solid var(--color-neutral-3);
|
|
|
+ border-radius: var(--border-radius-medium);
|
|
|
+ box-shadow: 0 2px 5px rgb(0 0 0 / 10%);
|
|
|
+}
|
|
|
+
|
|
|
+.custom-filter-footer {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+}
|
|
|
+</style>
|