feat(frontend): 为前端添加完整移动端响应式适配
- 新增响应式工具函数与全局移动端样式,统一适配≤768px屏幕 - 添加移动端底部导航组件,替代桌面端侧边栏菜单 - 为经销商、客户、报备列表页新增移动端卡片视图替换表格布局 - 调整所有页面的表单、弹窗与布局适配移动端尺寸 - 优化移动端viewport配置,适配全面屏安全区域 - 修复密码哈希工具,在非安全上下文下回退使用js-sha256库 - 更新依赖包,新增@vueuse/core与js-sha256
This commit is contained in:
1 parent
4c6970c32d
commit
fd89c31640
16 files changed
+613
-62
No files matched your search
+104
-10
@@ -17,7 +17,7 @@
|
||||
</template>
|
||||
|
||||
<!-- 查询表单 -->
|
||||
<el-form :inline="true" :model="queryForm" class="query-form">
|
||||
<el-form :inline="!isMobile" :model="queryForm" class="query-form">
|
||||
<el-form-item label="学校名称">
|
||||
<el-input v-model="queryForm.customerName" placeholder="请输入学校名称" clearable />
|
||||
</el-form-item>
|
||||
@@ -40,7 +40,7 @@
|
||||
</el-form>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-table :data="tableData" border stripe v-loading="loading">
|
||||
<el-table v-if="!isMobile" :data="tableData" border stripe v-loading="loading">
|
||||
<el-table-column prop="dealerName" label="经销商" v-if="userStore.isAdmin"/>
|
||||
<el-table-column prop="schoolName" label="学校名称" />
|
||||
<el-table-column prop="product" label="所属产品" show-overflow-tooltip />
|
||||
@@ -102,6 +102,36 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 移动端卡片视图 -->
|
||||
<div v-if="isMobile" class="mobile-card-list" v-loading="loading">
|
||||
<div v-for="row in tableData" :key="row.id" class="mobile-card">
|
||||
<div class="card-top">
|
||||
<span class="card-title">{{ row.schoolName }}</span>
|
||||
<el-tag v-if="row.status === 0" type="warning" size="small">待审核</el-tag>
|
||||
<el-tag v-else-if="row.status === 1" type="success" size="small">已通过</el-tag>
|
||||
<el-tag v-else-if="row.status === 2" type="danger" size="small">已驳回</el-tag>
|
||||
<el-tag v-else-if="row.status === 3" type="info" size="small">已失效</el-tag>
|
||||
<el-tag v-else-if="row.status === 4" type="warning" size="small">已作废</el-tag>
|
||||
</div>
|
||||
<div v-if="userStore.isAdmin" class="card-row"><span class="label">经销商</span><span class="val">{{ row.dealerName || '-' }}</span></div>
|
||||
<div class="card-row"><span class="label">所属产品</span><span class="val">{{ row.product || '-' }}</span></div>
|
||||
<div class="card-row"><span class="label">项目类型</span><span class="val">{{ row.projectType || '-' }}</span></div>
|
||||
<div class="card-row"><span class="label">负责人</span><span class="val">{{ row.contactPerson || '-' }}</span></div>
|
||||
<div class="card-row"><span class="label">负责人电话</span><span class="val">{{ row.contactPhone || '-' }}</span></div>
|
||||
<div class="card-row"><span class="label">报备说明</span><span class="val">{{ row.description || '-' }}</span></div>
|
||||
<div class="card-row"><span class="label">保护期截止</span><span class="val">{{ formatDate(row.protectEndDate) }}</span></div>
|
||||
<div class="card-row"><span class="label">创建时间</span><span class="val">{{ row.createdAt }}</span></div>
|
||||
<div class="card-actions">
|
||||
<el-button link type="primary" @click="handleView(row)">查看</el-button>
|
||||
<el-button v-if="row.status === 1" link type="info" @click="handleShowProgress(row)">进展</el-button>
|
||||
<el-button v-if="userStore.isAdmin && row.status === 0" link type="success" @click="handleAudit(row)">审核</el-button>
|
||||
<el-button v-if="userStore.isAdmin && row.status === 1" link type="warning" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button v-if="!userStore.isAdmin && row.status === 0" link type="danger" @click="handleWithdraw(row)">撤回</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-if="!loading && tableData.length === 0" description="暂无报备数据" />
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<el-config-provider :locale="zhCn">
|
||||
<el-pagination
|
||||
@@ -109,18 +139,18 @@
|
||||
v-model:page-size="queryForm.size"
|
||||
:total="total"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:layout="isMobile ? 'prev, pager, next' : 'total, sizes, prev, pager, next, jumper'"
|
||||
prev-text="上一页"
|
||||
next-text="下一页"
|
||||
@size-change="fetchData"
|
||||
@current-change="fetchData"
|
||||
style="margin-top: 20px; justify-content: flex-end"
|
||||
:style="{ marginTop: '20px', justifyContent: isMobile ? 'center' : 'flex-end' }"
|
||||
/>
|
||||
</el-config-provider>
|
||||
</el-card>
|
||||
|
||||
<!-- 提交报备对话框 -->
|
||||
<el-dialog v-model="dialogVisible" title="提交报备" width="650px" @close="handleDialogClose">
|
||||
<el-dialog v-model="dialogVisible" title="提交报备" :width="isMobile ? '92%' : '650px'" @close="handleDialogClose">
|
||||
<el-form ref="formRef" :model="formData" :rules="rules" label-width="100px">
|
||||
<el-form-item label="学校" prop="schoolName">
|
||||
<el-autocomplete
|
||||
@@ -183,7 +213,7 @@
|
||||
</el-dialog>
|
||||
|
||||
<!-- 审核对话框 -->
|
||||
<el-dialog v-model="auditDialogVisible" title="审核报备" width="600px">
|
||||
<el-dialog v-model="auditDialogVisible" title="审核报备" :width="isMobile ? '92%' : '600px'">
|
||||
<el-form :model="auditForm" label-width="100px">
|
||||
<el-form-item label="审核结果">
|
||||
<el-radio-group v-model="auditForm.approved">
|
||||
@@ -207,7 +237,7 @@
|
||||
</el-dialog>
|
||||
|
||||
<!-- 编辑报备对话框 -->
|
||||
<el-dialog v-model="editDialogVisible" title="编辑报备" width="600px" @close="handleEditDialogClose">
|
||||
<el-dialog v-model="editDialogVisible" title="编辑报备" :width="isMobile ? '92%' : '600px'" @close="handleEditDialogClose">
|
||||
<el-form ref="editFormRef" :model="editFormData" :rules="editRules" label-width="100px">
|
||||
<el-form-item label="学校名称">
|
||||
<el-input :model-value="currentReport?.schoolName" disabled />
|
||||
@@ -270,8 +300,8 @@
|
||||
</el-dialog>
|
||||
|
||||
<!-- 报备详情对话框 -->
|
||||
<el-dialog v-model="detailDialogVisible" title="报备详情" width="700px">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-dialog v-model="detailDialogVisible" title="报备详情" :width="isMobile ? '92%' : '700px'">
|
||||
<el-descriptions :column="isMobile ? 1 : 2" border>
|
||||
<el-descriptions-item label="经销商">
|
||||
{{ currentReport?.dealerName || '-' }}
|
||||
</el-descriptions-item>
|
||||
@@ -330,7 +360,7 @@
|
||||
</el-dialog>
|
||||
|
||||
<!-- 进展记录对话框 -->
|
||||
<el-dialog v-model="progressDialogVisible" title="报备进展记录" width="1000px" @close="handleProgressDialogClose">
|
||||
<el-dialog v-model="progressDialogVisible" title="报备进展记录" :width="isMobile ? '92%' : '1000px'" :fullscreen="isMobile" @close="handleProgressDialogClose">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
@@ -387,11 +417,13 @@ import { getProgressByReportId, createProgress, updateProgress } from '@/api/rep
|
||||
import { searchSchoolByName } from '@/api/school'
|
||||
import { getConfigValue } from '@/api/system'
|
||||
import type { Report, ReportForm, ReportProgress, ReportProgressForm, ReportUpdateForm } from '@/types'
|
||||
import { useResponsive } from '@/composables/useResponsive'
|
||||
|
||||
const route = useRoute()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const protectDays = ref<number>(90)
|
||||
const { isMobile } = useResponsive()
|
||||
|
||||
const loading = ref(false)
|
||||
const tableData = ref<Report[]>([])
|
||||
@@ -792,4 +824,66 @@ onMounted(() => {
|
||||
:deep(.el-descriptions__content) {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* ===== 移动端卡片视图 ===== */
|
||||
.mobile-card-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.mobile-card {
|
||||
background: #fff;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.card-top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.card-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.card-row .label {
|
||||
width: 80px;
|
||||
flex-shrink: 0;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.card-row .val {
|
||||
flex: 1;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-top: 8px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.card-header {
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user