update:运动馆
This commit is contained in:
parent
a5e185e551
commit
e8ecf2c0fc
@ -7,7 +7,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, maximum-scale=1.0, minimum-scale=1.0, initial-scale=1.0, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, maximum-scale=1.0, minimum-scale=1.0, initial-scale=1.0, user-scalable=no" />
|
||||||
<meta name="keywords" content=".netccore,dotnet core,vue,element,element plus,vue3" />
|
<meta name="keywords" content=".netccore,dotnet core,vue,element,element plus,vue3" />
|
||||||
<meta name="description" content="智慧系统" />
|
<meta name="description" content="智慧系统" />
|
||||||
<!-- <link rel="icon" href="<%= BASE_URL %>favicon.ico"> -->
|
<link rel="icon" href="favicon.ico">
|
||||||
<title>智慧系统</title>
|
<title>智慧系统</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 195 KiB |
@ -595,6 +595,14 @@ const routes = [{
|
|||||||
name: 'sportsHallClass',
|
name: 'sportsHallClass',
|
||||||
component: () => import('@/views/sportsHall/classManage/index.vue'),
|
component: () => import('@/views/sportsHall/classManage/index.vue'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/sportHallReport', //运动馆/体测报告
|
||||||
|
name: 'sportHallReport',
|
||||||
|
component: () => import('@/views/sportHallReport/index.vue'),
|
||||||
|
meta: {
|
||||||
|
keepAlive: false
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/openReservation', //学校管理/开放预约
|
path: '/openReservation', //学校管理/开放预约
|
||||||
name: 'openReservation',
|
name: 'openReservation',
|
||||||
|
|||||||
841
src/views/sportHallReport/index.vue
Normal file
841
src/views/sportHallReport/index.vue
Normal file
@ -0,0 +1,841 @@
|
|||||||
|
<template>
|
||||||
|
<div class="sport-hall-report">
|
||||||
|
|
||||||
|
<!-- 搜索区域 -->
|
||||||
|
<div class="search-card">
|
||||||
|
<div class="search-row">
|
||||||
|
<div class="search-item">
|
||||||
|
<span class="label">项目:</span>
|
||||||
|
<el-select v-model="query.project" placeholder="全部" clearable style="width: 160px">
|
||||||
|
<el-option label="全部" value="" />
|
||||||
|
<el-option v-for="item in projectOptions" :key="item.id" :label="item.itemTypeName" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="search-item">
|
||||||
|
<span class="label">年级-班级:</span>
|
||||||
|
<el-cascader
|
||||||
|
v-model="query.gradeClass"
|
||||||
|
:options="gradeClassOptions"
|
||||||
|
:props="{ checkStrictly: true }"
|
||||||
|
clearable
|
||||||
|
placeholder="全部"
|
||||||
|
style="width: 200px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="search-item">
|
||||||
|
<span class="label">性别:</span>
|
||||||
|
<el-select v-model="query.gender" placeholder="全部" style="width: 130px">
|
||||||
|
<el-option label="全部" value="" />
|
||||||
|
<el-option label="男" :value="1" />
|
||||||
|
<el-option label="女" :value="2" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="search-item">
|
||||||
|
<span class="label">等级:</span>
|
||||||
|
<el-select v-model="query.rank" placeholder="全部" style="width: 130px">
|
||||||
|
<el-option label="全部" value="" />
|
||||||
|
<el-option label="优秀" value="优秀" />
|
||||||
|
<el-option label="良好" value="良好" />
|
||||||
|
<el-option label="及格" value="及格" />
|
||||||
|
<el-option label="不及格" value="不及格" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="search-row">
|
||||||
|
<div class="search-item">
|
||||||
|
<span class="label">测试时间:</span>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="query.dateRange"
|
||||||
|
type="daterange"
|
||||||
|
format="YYYY-MM-DD"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
range-separator="~"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
style="width: 260px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="search-actions">
|
||||||
|
<el-button class="btn-reset" @click="handleReset">重置</el-button>
|
||||||
|
<el-button class="btn-search" type="primary" @click="handleSearch">查询</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 操作栏 -->
|
||||||
|
<div class="table-toolbar">
|
||||||
|
<div class="toolbar-right">
|
||||||
|
<el-tooltip content="将本次成绩推送至运动馆—家长端—【统计】—体测报告" placement="top">
|
||||||
|
<el-button class="action-btn import-btn" @click="handleImport">
|
||||||
|
导入成绩
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="本次成绩推送至运动馆—家长端—【统计】—一体测报告" placement="top">
|
||||||
|
<el-button class="action-btn send-btn" @click="handleSendScore">
|
||||||
|
成绩推送
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 数据表格 -->
|
||||||
|
<div class="table-card">
|
||||||
|
<el-table
|
||||||
|
:data="tableData"
|
||||||
|
v-loading="loading"
|
||||||
|
style="width: 100%"
|
||||||
|
:header-cell-style="{
|
||||||
|
background: '#f5f7fa',
|
||||||
|
color: '#606266',
|
||||||
|
fontWeight: '600',
|
||||||
|
fontSize: '13px',
|
||||||
|
padding: '12px 0'
|
||||||
|
}"
|
||||||
|
:row-style="{ height: '52px' }"
|
||||||
|
stripe
|
||||||
|
border
|
||||||
|
>
|
||||||
|
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||||
|
<el-table-column prop="studentName" label="学生姓名" min-width="100" align="center" />
|
||||||
|
<el-table-column prop="gradeAndClass" label="年级-班级" min-width="140" align="center" />
|
||||||
|
<el-table-column prop="gender" label="性别" width="70" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="row.gender === 1 ? 'primary' : 'danger'" size="small" effect="light">
|
||||||
|
{{ row.gender === 1 ? '男' : '女' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="bmi" label="体质指数(BMI)" min-width="130" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span>{{ row.bmi ?? '/' }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="lungCapacity" label="肺活量(ml)" min-width="110" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span>{{ row.lungCapacity ?? '/' }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="sitAndReach" label="坐位体前屈(cm)" min-width="140" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span>{{ row.sitAndReach ?? '/' }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="ropeSkipping" label="一分钟跳绳(个)" min-width="140" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span>{{ row.ropeSkipping ?? '/' }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="sitUp" label="一分钟仰卧起坐(个)" min-width="160" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span>{{ row.sitUp ?? '/' }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="standingLongJump" label="立定跳远(cm)" min-width="130" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span>{{ row.standingLongJump ?? '/' }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="testTime" label="测试时间" min-width="160" align="center" />
|
||||||
|
<el-table-column label="操作" width="100" align="center">
|
||||||
|
<template #default="{ row }" width="100">
|
||||||
|
<el-button type="primary" link @click="handleEdit(row)">成绩修正</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<!-- 分页 -->
|
||||||
|
<div class="pagination-wrap">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="pagination.pageIndex"
|
||||||
|
v-model:page-size="pagination.pageSize"
|
||||||
|
:total="pagination.total"
|
||||||
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
background
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 导入成绩弹窗 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="importDialog.visible"
|
||||||
|
title="导入成绩"
|
||||||
|
width="640px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
class="import-dialog"
|
||||||
|
>
|
||||||
|
<div class="import-content">
|
||||||
|
<!-- 说明区域 -->
|
||||||
|
<div class="import-tips">
|
||||||
|
<p><span class="tip-num">1.</span>上传前请先下载标准Excel模板并按照标准模板中的说明编辑文件</p>
|
||||||
|
<p><span class="tip-num">2.</span>一次最多上传10000行数据,文件大小不能超过10M</p>
|
||||||
|
<p><span class="tip-num">3.</span>支持上传xlsx格式文件</p>
|
||||||
|
<p><span class="tip-num">4.</span>最新数据覆盖上次数据</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 上传区域 -->
|
||||||
|
<div class="upload-area">
|
||||||
|
<el-upload
|
||||||
|
ref="uploadRef"
|
||||||
|
class="upload-dragger"
|
||||||
|
drag
|
||||||
|
:action="uploadUrl"
|
||||||
|
:headers="uploadHeaders"
|
||||||
|
:before-upload="beforeUpload"
|
||||||
|
:on-success="onUploadSuccess"
|
||||||
|
:on-error="onUploadError"
|
||||||
|
:show-file-list="false"
|
||||||
|
accept=".xlsx"
|
||||||
|
>
|
||||||
|
<div class="upload-inner">
|
||||||
|
<img src="@/assets/images/excel-icon.png" class="excel-icon" @error="onIconError" alt="Excel" />
|
||||||
|
<div class="upload-text">
|
||||||
|
将模板拖拽到此区域 或
|
||||||
|
<span class="upload-link">点击上传</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-upload>
|
||||||
|
|
||||||
|
<div class="download-btn-wrap">
|
||||||
|
<el-button class="btn-download" @click="downloadTemplate">
|
||||||
|
下载标准Excel模板
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="importDialog.visible = false">关闭</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 成绩修正弹窗 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="editDialog.visible"
|
||||||
|
title="成绩修正"
|
||||||
|
width="560px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
|
<el-form ref="editFormRef" :model="editForm" label-width="160px" size="default">
|
||||||
|
<el-form-item label="学生姓名">
|
||||||
|
<el-input :value="editForm.studentName" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="体质指数(BMI)">
|
||||||
|
<el-input v-model="editForm.bmi" placeholder="请输入" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="肺活量(ml)">
|
||||||
|
<el-input v-model="editForm.lungCapacity" placeholder="请输入" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="坐位体前屈(cm)">
|
||||||
|
<el-input v-model="editForm.sitAndReach" placeholder="请输入" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="一分钟跳绳(个)">
|
||||||
|
<el-input v-model="editForm.ropeSkipping" placeholder="请输入" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="一分钟仰卧起坐(个)">
|
||||||
|
<el-input v-model="editForm.sitUp" placeholder="请输入" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="立定跳远(cm)">
|
||||||
|
<el-input v-model="editForm.standingLongJump" placeholder="请输入" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="editDialog.visible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleEditConfirm">保存</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, onMounted } from 'vue'
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
// ===================== 查询参数 =====================
|
||||||
|
const query = reactive({
|
||||||
|
project: '',
|
||||||
|
gradeClass: [],
|
||||||
|
gender: '',
|
||||||
|
rank: '',
|
||||||
|
dateRange: [] as string[]
|
||||||
|
})
|
||||||
|
|
||||||
|
// ===================== 下拉数据 =====================
|
||||||
|
const projectOptions = ref<any[]>([])
|
||||||
|
const gradeClassOptions = ref<any[]>([])
|
||||||
|
|
||||||
|
// ===================== 表格数据 =====================
|
||||||
|
const loading = ref(false)
|
||||||
|
const tableData = ref<any[]>([])
|
||||||
|
|
||||||
|
const pagination = reactive({
|
||||||
|
pageIndex: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// ===================== 模拟数据(接口接入后替换) =====================
|
||||||
|
const mockData = [
|
||||||
|
{
|
||||||
|
id: 1, studentName: '崔政豪', gradeAndClass: '运动馆-周一班', gender: 1,
|
||||||
|
bmi: '178/140/28', lungCapacity: 2344, sitAndReach: null, ropeSkipping: 200, sitUp: 200, standingLongJump: null, testTime: '2024-08-09 12:00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2, studentName: '金辰恺', gradeAndClass: '运动馆-周一班', gender: 2,
|
||||||
|
bmi: '178/140/28', lungCapacity: null, sitAndReach: 12, ropeSkipping: 180, sitUp: 180, standingLongJump: 12, testTime: '2024-08-09 12:00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3, studentName: '樊鸣轩', gradeAndClass: '运动馆-周一班', gender: 1,
|
||||||
|
bmi: '178/140/28', lungCapacity: 5643, sitAndReach: 10, ropeSkipping: null, sitUp: null, standingLongJump: 10, testTime: '2024-08-09 12:00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4, studentName: '陈睿鸿', gradeAndClass: '运动馆-周一班', gender: 2,
|
||||||
|
bmi: '178/140/28', lungCapacity: null, sitAndReach: null, ropeSkipping: 230, sitUp: 230, standingLongJump: null, testTime: '2024-08-09 12:00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5, studentName: '俞鑫安', gradeAndClass: '运动馆-周一班', gender: 1,
|
||||||
|
bmi: '178/140/28', lungCapacity: 2345, sitAndReach: null, ropeSkipping: 109, sitUp: 109, standingLongJump: null, testTime: '2024-08-09 12:00'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// ===================== 获取列表 =====================
|
||||||
|
const fetchList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
// TODO: 替换为实际接口
|
||||||
|
// const res = await getSportHallReport({ ...query, ...pagination })
|
||||||
|
// tableData.value = res.data.datas
|
||||||
|
// pagination.total = res.data.total
|
||||||
|
|
||||||
|
// 使用模拟数据
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300))
|
||||||
|
tableData.value = mockData
|
||||||
|
pagination.total = 400
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error('获取数据失败')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== 获取下拉选项 =====================
|
||||||
|
const fetchOptions = async () => {
|
||||||
|
try {
|
||||||
|
// TODO: 替换为实际接口获取项目列表和年级班级列表
|
||||||
|
gradeClassOptions.value = [
|
||||||
|
{
|
||||||
|
value: '1',
|
||||||
|
label: '运动馆',
|
||||||
|
children: [
|
||||||
|
{ value: '1-1', label: '周一班' },
|
||||||
|
{ value: '1-2', label: '周二班' },
|
||||||
|
{ value: '1-3', label: '周三班' },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
} catch (e) {
|
||||||
|
console.error('获取下拉选项失败', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== 搜索/重置 =====================
|
||||||
|
const handleSearch = () => {
|
||||||
|
pagination.pageIndex = 1
|
||||||
|
fetchList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleReset = () => {
|
||||||
|
query.project = ''
|
||||||
|
query.gradeClass = []
|
||||||
|
query.gender = ''
|
||||||
|
query.rank = ''
|
||||||
|
query.dateRange = []
|
||||||
|
pagination.pageIndex = 1
|
||||||
|
fetchList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== 分页 =====================
|
||||||
|
const handleSizeChange = (size: number) => {
|
||||||
|
pagination.pageSize = size
|
||||||
|
pagination.pageIndex = 1
|
||||||
|
fetchList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePageChange = (page: number) => {
|
||||||
|
pagination.pageIndex = page
|
||||||
|
fetchList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== 导入成绩 =====================
|
||||||
|
const importDialog = reactive({ visible: false })
|
||||||
|
const uploadRef = ref()
|
||||||
|
|
||||||
|
const uploadUrl = `${import.meta.env.VITE_APP_BASE_API || ''}/api/sportHall/importScore`
|
||||||
|
const uploadHeaders = reactive({
|
||||||
|
Authorization: `Bearer ${localStorage.getItem('token') || ''}`
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleImport = () => {
|
||||||
|
importDialog.visible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const beforeUpload = (file: File) => {
|
||||||
|
const isXlsx = file.name.endsWith('.xlsx')
|
||||||
|
if (!isXlsx) {
|
||||||
|
ElMessage.error('只支持上传 .xlsx 格式文件')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const isLt10M = file.size / 1024 / 1024 < 10
|
||||||
|
if (!isLt10M) {
|
||||||
|
ElMessage.error('文件大小不能超过 10MB')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const onUploadSuccess = (response: any) => {
|
||||||
|
if (response?.code === 200) {
|
||||||
|
ElMessage.success('导入成功')
|
||||||
|
importDialog.visible = false
|
||||||
|
fetchList()
|
||||||
|
} else {
|
||||||
|
ElMessage.error(response?.message || '导入失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onUploadError = () => {
|
||||||
|
ElMessage.error('文件上传失败,请重试')
|
||||||
|
}
|
||||||
|
|
||||||
|
const onIconError = (e: Event) => {
|
||||||
|
const img = e.target as HTMLImageElement
|
||||||
|
img.style.display = 'none'
|
||||||
|
}
|
||||||
|
|
||||||
|
const downloadTemplate = async () => {
|
||||||
|
try {
|
||||||
|
// TODO: 替换为实际模板下载接口
|
||||||
|
ElMessage.info('正在下载模板...')
|
||||||
|
// const res = await axios.get('/api/sportHall/downloadTemplate', { responseType: 'blob' })
|
||||||
|
// const url = window.URL.createObjectURL(new Blob([res.data]))
|
||||||
|
// const link = document.createElement('a')
|
||||||
|
// link.href = url
|
||||||
|
// link.setAttribute('download', '体测成绩导入模板.xlsx')
|
||||||
|
// document.body.appendChild(link)
|
||||||
|
// link.click()
|
||||||
|
// document.body.removeChild(link)
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error('模板下载失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== 成绩推送 =====================
|
||||||
|
const handleSendScore = () => {
|
||||||
|
ElMessageBox.confirm(
|
||||||
|
'确认将本次成绩推送至运动馆—家长端—【统计】—一体测报告?',
|
||||||
|
'成绩推送',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确认推送',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
// TODO: 调用推送接口
|
||||||
|
ElMessage.success('推送成功')
|
||||||
|
}).catch(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== 成绩修正 =====================
|
||||||
|
const editDialog = reactive({ visible: false })
|
||||||
|
const editFormRef = ref()
|
||||||
|
const editForm = reactive({
|
||||||
|
id: null as any,
|
||||||
|
studentName: '',
|
||||||
|
bmi: '' as any,
|
||||||
|
lungCapacity: '' as any,
|
||||||
|
sitAndReach: '' as any,
|
||||||
|
ropeSkipping: '' as any,
|
||||||
|
sitUp: '' as any,
|
||||||
|
standingLongJump: '' as any
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleEdit = (row: any) => {
|
||||||
|
Object.assign(editForm, {
|
||||||
|
id: row.id,
|
||||||
|
studentName: row.studentName,
|
||||||
|
bmi: row.bmi ?? '',
|
||||||
|
lungCapacity: row.lungCapacity ?? '',
|
||||||
|
sitAndReach: row.sitAndReach ?? '',
|
||||||
|
ropeSkipping: row.ropeSkipping ?? '',
|
||||||
|
sitUp: row.sitUp ?? '',
|
||||||
|
standingLongJump: row.standingLongJump ?? ''
|
||||||
|
})
|
||||||
|
editDialog.visible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleEditConfirm = async () => {
|
||||||
|
try {
|
||||||
|
// TODO: 调用成绩修正接口
|
||||||
|
// await updateSportHallScore(editForm)
|
||||||
|
ElMessage.success('修正成功')
|
||||||
|
editDialog.visible = false
|
||||||
|
fetchList()
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error('操作失败,请重试')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== 初始化 =====================
|
||||||
|
onMounted(() => {
|
||||||
|
fetchOptions()
|
||||||
|
fetchList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.sport-hall-report {
|
||||||
|
width: calc(100% - 32px);
|
||||||
|
min-height: calc(100vh - 100px);
|
||||||
|
margin: 16px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
// 面包屑
|
||||||
|
.breadcrumb {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 14px 20px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
|
||||||
|
|
||||||
|
:deep(.el-breadcrumb__inner) {
|
||||||
|
color: #606266;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-breadcrumb__item:last-child .el-breadcrumb__inner) {
|
||||||
|
color: #303133;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索卡片
|
||||||
|
.search-card {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 18px 20px 10px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
|
||||||
|
|
||||||
|
.search-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px 20px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
.search-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #606266;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-left: auto;
|
||||||
|
|
||||||
|
.btn-reset {
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px 20px;
|
||||||
|
color: #606266;
|
||||||
|
border-color: #dcdfe6;
|
||||||
|
background: #fff;
|
||||||
|
font-size: 13px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #409eff;
|
||||||
|
border-color: #c6e2ff;
|
||||||
|
background: #ecf5ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-search {
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px 24px;
|
||||||
|
font-size: 13px;
|
||||||
|
background: linear-gradient(135deg, #409eff 0%, #337ecc 100%);
|
||||||
|
border: none;
|
||||||
|
box-shadow: 0 2px 6px rgba(64, 158, 255, 0.4);
|
||||||
|
transition: all 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: linear-gradient(135deg, #66b1ff 0%, #409eff 100%);
|
||||||
|
box-shadow: 0 4px 10px rgba(64, 158, 255, 0.5);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 操作工具栏
|
||||||
|
.table-toolbar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 4px;
|
||||||
|
|
||||||
|
.toolbar-right {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
position: relative;
|
||||||
|
padding: 8px 24px 8px 30px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.25s;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
.btn-badge {
|
||||||
|
position: absolute;
|
||||||
|
top: -7px;
|
||||||
|
left: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
font-size: 11px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 700;
|
||||||
|
border: 2px solid #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-btn {
|
||||||
|
background: linear-gradient(135deg, #409eff 0%, #337ecc 100%);
|
||||||
|
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.45);
|
||||||
|
|
||||||
|
.btn-badge {
|
||||||
|
background: #fff;
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: linear-gradient(135deg, #66b1ff 0%, #409eff 100%);
|
||||||
|
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.55);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.send-btn {
|
||||||
|
background: linear-gradient(135deg, #67c23a 0%, #529b2e 100%);
|
||||||
|
box-shadow: 0 2px 8px rgba(103, 194, 58, 0.45);
|
||||||
|
|
||||||
|
.btn-badge {
|
||||||
|
background: #fff;
|
||||||
|
color: #67c23a;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: linear-gradient(135deg, #85ce61 0%, #67c23a 100%);
|
||||||
|
box-shadow: 0 4px 12px rgba(103, 194, 58, 0.55);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表格卡片
|
||||||
|
.table-card {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
:deep(.el-table) {
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table th) {
|
||||||
|
background: #f5f7fa !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table--striped .el-table__body tr.el-table__row--striped td) {
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-button.is-link) {
|
||||||
|
color: #409eff;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-wrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 16px;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导入弹窗
|
||||||
|
.import-dialog {
|
||||||
|
:deep(.el-dialog__header) {
|
||||||
|
padding: 20px 24px 12px;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
.el-dialog__title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-dialog__body) {
|
||||||
|
padding: 20px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-dialog__footer) {
|
||||||
|
padding: 12px 24px 20px;
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-content {
|
||||||
|
.import-tips {
|
||||||
|
background: #f0f7ff;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 16px 18px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #495464;
|
||||||
|
line-height: 2;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
.tip-num {
|
||||||
|
color: #409eff;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-area {
|
||||||
|
border: 1px dashed #d9d9d9;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 24px;
|
||||||
|
background: #fafafa;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-dragger {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
:deep(.el-upload) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-upload-dragger) {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
padding: 24px 0;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-inner {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.excel-icon {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
|
||||||
|
.upload-link {
|
||||||
|
color: #409eff;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-btn-wrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 16px;
|
||||||
|
|
||||||
|
.btn-download {
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 9px 24px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #409eff;
|
||||||
|
border: 1px solid #c6e2ff;
|
||||||
|
background: #ecf5ff;
|
||||||
|
transition: all 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #409eff;
|
||||||
|
box-shadow: 0 3px 8px rgba(64, 158, 255, 0.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user