Files
en-edu/enlish-vue/src/pages/uploadpng.vue
lbw fb29acc145 feat(ui): 提升界面响应式支持和移动端适配体验
- 新增移动端全屏对话框支持及标签宽度和位置动态调整,优化新增班级、年级和学生弹窗布局
- 所有对话框增加屏幕宽度监听,实现自动切换移动端和桌面端样式
- 表格组件增加移动端列表视图,隐藏侧边栏并改进分页和按钮自适应,提升小屏幕浏览体验
- Dialog及详情弹窗添加最大高度限制并启用滚动,防止移动端显示区域拥挤
- 登录页增加安全区域内边距,保证iOS等设备显示完整性
- 新增移动端菜单抽屉组件,支持手机端侧边栏交互显示
- 学生详情页调整词汇热力图列数,实现移动端更合理布局
- 表格和按钮统一增设触控友好大尺寸区域,提升移动端操作便利性
- 修正后端空词汇ID查询问题,避免空列表导致查询异常
- 统一隐藏小屏幕时的固定侧边栏,避免界面混乱和重复显示
- 搜索页和上传页表格添加移动端适配样式和展开收起逻辑,提升列表浏览灵活性
2026-01-05 18:47:50 +08:00

213 lines
9.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="common-layout">
<el-container class="min-h-screen">
<el-header>
<Header></Header>
</el-header>
<el-container class="pt-4">
<el-aside width="200px" class="hidden md:block sidebar-fixed">
<Sidebar />
</el-aside>
<el-main class="">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div class="panel-shell p-6">
<div class="text-lg font-semibold mb-4">上传图片</div>
<el-upload :show-file-list="false" :http-request="doUpload" accept="image/*">
<el-button type="primary" class="w-full sm:w-auto touch-target">选择图片并上传</el-button>
</el-upload>
</div>
<div class="panel-shell p-6">
<div class="text-lg font-semibold mb-4">结果集</div>
<div class="hidden sm:block">
<el-form :inline="true" class="mb-4">
<el-form-item label="班级">
<el-select v-model="classId" placeholder="选择班级" clearable filterable
@change="onClassChange" style="min-width: 220px">
<el-option v-for="item in classOptions" :key="item.id"
:label="`${item.title}${item.gradeName ? '' + item.gradeName + '' : ''}`"
:value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="年级">
<el-select v-model="gradeId" placeholder="选择年级" clearable filterable
style="min-width: 220px">
<el-option v-for="g in gradeOptions" :key="g.id" :label="g.title"
:value="g.id" />
</el-select>
</el-form-item>
<el-form-item label="学生姓名">
<el-input v-model="studentName" placeholder="学生姓名" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
</div>
<div class="hidden sm:block overflow-x-auto">
<el-table :data="list" border class="min-w-[800px]" v-loading="loading"
@row-click="handleRowClick">
<el-table-column prop="studentName" label="学生姓名" min-width="120" />
<el-table-column prop="examWordsTitle" label="试题名称" min-width="160" />
<el-table-column prop="correctWordCount" label="正确词数" width="120" />
<el-table-column prop="wrongWordCount" label="错误词数" width="120" />
<el-table-column label="完成状态" width="120">
<template #default="{ row }">
<el-tag :type="row.isFinished === 1 ? 'success' : 'info'">
{{ row.isFinished === 1 ? '已完成' : '未完成' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="startDate" label="开始时间" min-width="160">
<template #default="{ row }">
{{ row.startDate.replace('T', ' ') }}
</template>
</el-table-column>
<el-table-column prop="msg" label="判卷结算" min-width="180" />
</el-table>
</div>
<div class="sm:hidden space-y-3">
<div class="mb-3 grid grid-cols-1 gap-3">
<el-select v-model="classId" placeholder="选择班级" clearable filterable @change="onClassChange" />
<el-select v-model="gradeId" placeholder="选择年级" clearable filterable />
<el-input v-model="studentName" placeholder="学生姓名" clearable />
<div class="flex gap-2">
<el-button type="primary" class="flex-1" @click="handleSearch">查询</el-button>
<el-button class="flex-1" @click="handleReset">重置</el-button>
</div>
</div>
<div v-for="row in list" :key="row.id" class="panel-shell p-4">
<div class="text-base font-semibold mb-1">{{ row.studentName }}</div>
<div class="text-sm mb-1">试题{{ row.examWordsTitle }}</div>
<div class="text-sm mb-1">正确{{ row.correctWordCount }}错误{{ row.wrongWordCount }}</div>
<div class="text-sm mb-1">开始{{ row.startDate.replace('T', ' ') }}</div>
<div class="text-sm mb-2">结算{{ row.msg }}</div>
<div class="flex items-center justify-between">
<el-tag :type="row.isFinished === 1 ? 'success' : 'info'">
{{ row.isFinished === 1 ? '已完成' : '未完成' }}
</el-tag>
<el-button size="small" type="primary" @click="handleRowClick(row)">查看详情</el-button>
</div>
</div>
</div>
<div class="mt-4 flex justify-end">
<el-pagination background layout="prev, pager, next, sizes, total" :total="totalCount"
:page-size="pageSize" :current-page="pageNo" @current-change="handlePageChange"
@size-change="handleSizeChange" />
</div>
</div>
</div>
<ExamWordsDetailCard v-model="showDetail" :id="selectedId" />
</el-main>
</el-container>
</el-container>
</div>
</template>
<script setup>
import Header from '@/layouts/components/Header.vue'
import ExamWordsDetailCard from '@/layouts/components/ExamWordsDetailCard.vue'
import { ref, onMounted } from 'vue'
import { uploadExamWordsPng, getExamWordsResult } from '@/api/exam'
import { getClassList } from '@/api/class'
import { getGradeList } from '@/api/grade'
import Sidebar from '@/layouts/components/Sidebar.vue'
const list = ref([])
const pageNo = ref(1)
const pageSize = ref(10)
const totalCount = ref(0)
const loading = ref(false)
const showDetail = ref(false)
const selectedId = ref(null)
const classId = ref(null)
const gradeId = ref(null)
const studentName = ref('')
const classOptions = ref([])
const gradeOptions = ref([])
async function fetchList() {
loading.value = true
try {
const res = await getExamWordsResult(
pageNo.value,
pageSize.value,
classId.value,
gradeId.value,
studentName.value
)
const d = res.data
list.value = Array.isArray(d.data) ? d.data : []
totalCount.value = d.totalCount || 0
pageNo.value = d.pageNo || pageNo.value
pageSize.value = d.pageSize || pageSize.value
} finally {
loading.value = false
}
}
async function fetchClassOptions() {
const res = await getClassList(1, 200)
const d = res.data
classOptions.value = Array.isArray(d.data) ? d.data : []
}
async function fetchGradeOptions() {
const res = await getGradeList(1, 200)
const d = res.data
gradeOptions.value = Array.isArray(d.data) ? d.data : []
}
function handlePageChange(p) {
pageNo.value = p
fetchList()
}
function handleSizeChange(s) {
pageSize.value = s
pageNo.value = 1
fetchList()
}
async function doUpload(options) {
const file = options.file
const formData = new FormData()
formData.append('file', file)
await uploadExamWordsPng(formData)
ElMessage.success('上传成功,已开始生成结果')
fetchList()
}
function handleRowClick(row) {
selectedId.value = row.id
showDetail.value = true
}
function handleSearch() {
pageNo.value = 1
fetchList()
}
function handleReset() {
classId.value = null
gradeId.value = null
studentName.value = ''
pageNo.value = 1
fetchList()
}
function onClassChange(val) {
const item = classOptions.value.find(i => i.id === val)
gradeId.value = item ? item.gradeId : null
}
onMounted(() => {
fetchList()
fetchClassOptions()
fetchGradeOptions()
})
</script>
<style scoped></style>