初始提交:彩票推测系统前端代码
This commit is contained in:
789
src/views/admin/ExcelImportManagement.vue
Normal file
789
src/views/admin/ExcelImportManagement.vue
Normal file
@@ -0,0 +1,789 @@
|
||||
<template>
|
||||
<div class="excel-import-management">
|
||||
<!-- 页面头部 -->
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<h1>📊 Excel数据导入系统</h1>
|
||||
<p>管理员专用 - {{ currentLotteryTypeName }}Excel文件数据批量导入</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 权限检查中 -->
|
||||
<div v-if="permissionChecking" class="permission-checking">
|
||||
<div class="checking-content">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>正在验证权限...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主要内容 - 只有有权限时才显示 -->
|
||||
<div v-else-if="hasPermission" class="import-container">
|
||||
<!-- 功能区域 -->
|
||||
<div class="function-area">
|
||||
<el-row :gutter="20">
|
||||
<!-- 完整数据导入 -->
|
||||
<el-col :span="8">
|
||||
<el-card class="function-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<el-icon><Document /></el-icon>
|
||||
<span>完整数据导入</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="card-desc">
|
||||
<p>上传包含T1-T7工作表的Excel文件,导入红球、蓝球、接续系数和组合系数数据</p>
|
||||
</div>
|
||||
|
||||
<div class="upload-section">
|
||||
<div class="file-input-container">
|
||||
<input
|
||||
type="file"
|
||||
ref="fullDataFileInput"
|
||||
@change="handleFileSelect($event, 'fullData')"
|
||||
accept=".xlsx,.xls"
|
||||
class="file-input"
|
||||
id="fullDataFile"
|
||||
/>
|
||||
<label for="fullDataFile" class="file-label">
|
||||
<el-icon class="file-icon"><FolderOpened /></el-icon>
|
||||
<span class="file-text">
|
||||
{{ fullDataFile ? fullDataFile.name : '选择Excel文件(包含T1-T7工作表)' }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="uploadFullData"
|
||||
:disabled="!fullDataFile || fullDataUploading"
|
||||
:loading="fullDataUploading"
|
||||
style="width: 100%; margin-top: 16px"
|
||||
>
|
||||
{{ fullDataUploading ? '导入中...' : '开始导入' }}
|
||||
</el-button>
|
||||
|
||||
<div v-if="fullDataResult" class="result-message" :class="fullDataResult.type">
|
||||
{{ fullDataResult.message }}
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<!-- 开奖数据导入(覆盖) -->
|
||||
<el-col :span="8">
|
||||
<el-card class="function-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<el-icon><Warning /></el-icon>
|
||||
<span>开奖数据导入(覆盖)</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="card-desc">
|
||||
<p>上传包含T10工作表的Excel文件,清空并重新导入开奖数据</p>
|
||||
</div>
|
||||
|
||||
<div class="upload-section">
|
||||
<div class="file-input-container">
|
||||
<input
|
||||
type="file"
|
||||
ref="lotteryFileInput"
|
||||
@change="handleFileSelect($event, 'lottery')"
|
||||
accept=".xlsx,.xls"
|
||||
class="file-input"
|
||||
id="lotteryFile"
|
||||
/>
|
||||
<label for="lotteryFile" class="file-label">
|
||||
<el-icon class="file-icon"><FolderOpened /></el-icon>
|
||||
<span class="file-text">
|
||||
{{ lotteryFile ? lotteryFile.name : '选择Excel文件(包含T10工作表)' }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<el-button
|
||||
type="warning"
|
||||
@click="uploadLotteryData"
|
||||
:disabled="!lotteryFile || lotteryUploading"
|
||||
:loading="lotteryUploading"
|
||||
style="width: 100%; margin-top: 16px"
|
||||
>
|
||||
{{ lotteryUploading ? '导入中...' : '覆盖导入' }}
|
||||
</el-button>
|
||||
|
||||
<div v-if="lotteryResult" class="result-message" :class="lotteryResult.type">
|
||||
{{ lotteryResult.message }}
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<!-- 开奖数据追加 -->
|
||||
<el-col :span="8">
|
||||
<el-card class="function-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<el-icon><Plus /></el-icon>
|
||||
<span>开奖数据追加</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="card-desc">
|
||||
<p>上传包含T10工作表的Excel文件,追加导入开奖数据(跳过重复期号)</p>
|
||||
</div>
|
||||
|
||||
<div class="upload-section">
|
||||
<div class="file-input-container">
|
||||
<input
|
||||
type="file"
|
||||
ref="appendFileInput"
|
||||
@change="handleFileSelect($event, 'append')"
|
||||
accept=".xlsx,.xls"
|
||||
class="file-input"
|
||||
id="appendFile"
|
||||
/>
|
||||
<label for="appendFile" class="file-label">
|
||||
<el-icon class="file-icon"><FolderOpened /></el-icon>
|
||||
<span class="file-text">
|
||||
{{ appendFile ? appendFile.name : '选择Excel文件(包含T10工作表)' }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<el-button
|
||||
type="success"
|
||||
@click="appendLotteryData"
|
||||
:disabled="!appendFile || appendUploading"
|
||||
:loading="appendUploading"
|
||||
style="width: 100%; margin-top: 16px"
|
||||
>
|
||||
{{ appendUploading ? '追加中...' : '追加导入' }}
|
||||
</el-button>
|
||||
|
||||
<div v-if="appendResult" class="result-message" :class="appendResult.type">
|
||||
{{ appendResult.message }}
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<!-- 导入说明 -->
|
||||
<el-card class="info-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<el-icon><InfoFilled /></el-icon>
|
||||
<span>导入说明</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="info-content">
|
||||
<div class="info-item">
|
||||
<h4>📋 完整数据导入:</h4>
|
||||
<p>• 需要包含T1、T2、T3、T4、T5、T6、T7工作表的Excel文件</p>
|
||||
<p>• 导入红球、蓝球、接续系数和组合系数数据到相应的数据库表</p>
|
||||
<p>• 适用于系统初始化或全量数据更新</p>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<h4>🎯 开奖数据导入(覆盖):</h4>
|
||||
<p>• 需要包含T10工作表的Excel文件</p>
|
||||
<p>• 清空lottery_draws表的现有数据,重新导入</p>
|
||||
<p>• 适用于完全替换开奖数据</p>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<h4>➕ 开奖数据追加:</h4>
|
||||
<p>• 需要包含T10工作表的Excel文件</p>
|
||||
<p>• 保留现有数据,只添加新的开奖记录</p>
|
||||
<p>• 自动跳过重复的期号,适用于增量更新</p>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 错误提示弹窗 -->
|
||||
<div v-if="showErrorModal" class="modal-overlay" @click="hideErrorModal">
|
||||
<div class="modal-content error-modal" @click.stop>
|
||||
<h3>❌ 导入失败</h3>
|
||||
<p>{{ errorMessage }}</p>
|
||||
<button class="btn btn-primary" @click="hideErrorModal">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { lotteryApi } from '../../api/index.js'
|
||||
import { userStore } from '../../store/user.js'
|
||||
import {
|
||||
ElCard,
|
||||
ElRow,
|
||||
ElCol,
|
||||
ElButton,
|
||||
ElIcon
|
||||
} from 'element-plus'
|
||||
import {
|
||||
Document,
|
||||
Warning,
|
||||
Plus,
|
||||
InfoFilled,
|
||||
FolderOpened
|
||||
} from '@element-plus/icons-vue'
|
||||
|
||||
export default {
|
||||
name: 'AdminExcelImportManagement',
|
||||
components: {
|
||||
ElCard,
|
||||
ElRow,
|
||||
ElCol,
|
||||
ElButton,
|
||||
ElIcon,
|
||||
Document,
|
||||
Warning,
|
||||
Plus,
|
||||
InfoFilled,
|
||||
FolderOpened
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 权限验证
|
||||
hasPermission: false,
|
||||
permissionChecking: true,
|
||||
|
||||
// 文件对象
|
||||
fullDataFile: null,
|
||||
lotteryFile: null,
|
||||
appendFile: null,
|
||||
|
||||
// 上传状态
|
||||
fullDataUploading: false,
|
||||
lotteryUploading: false,
|
||||
appendUploading: false,
|
||||
|
||||
// 结果信息
|
||||
fullDataResult: null,
|
||||
lotteryResult: null,
|
||||
appendResult: null,
|
||||
|
||||
// 错误处理
|
||||
showErrorModal: false,
|
||||
errorMessage: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 当前彩票类型名称
|
||||
currentLotteryTypeName() {
|
||||
const routePath = this.$route.path
|
||||
if (routePath.includes('/ssq')) {
|
||||
return '双色球 - '
|
||||
} else if (routePath.includes('/dlt')) {
|
||||
return '大乐透 - '
|
||||
}
|
||||
return ''
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
await this.checkPermission()
|
||||
},
|
||||
methods: {
|
||||
// 检查用户权限
|
||||
async checkPermission() {
|
||||
try {
|
||||
const response = await lotteryApi.getLoginUser()
|
||||
|
||||
if (response && response.success && response.data) {
|
||||
const userRole = response.data.userRole
|
||||
if (userRole === 'admin' || userRole === 'superAdmin') {
|
||||
this.hasPermission = true
|
||||
} else {
|
||||
this.showError('无权限访问此页面,仅限管理员或超级管理员使用')
|
||||
// 3秒后跳转到管理员登录页
|
||||
setTimeout(() => {
|
||||
this.$router.push('/cpzsadmin/login')
|
||||
}, 3000)
|
||||
}
|
||||
} else {
|
||||
this.showError('获取用户信息失败,请重新登录')
|
||||
setTimeout(() => {
|
||||
this.$router.push('/cpzsadmin/login')
|
||||
}, 3000)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('权限检查失败:', error)
|
||||
this.showError('权限验证失败,请重新登录')
|
||||
setTimeout(() => {
|
||||
this.$router.push('/cpzsadmin/login')
|
||||
}, 3000)
|
||||
} finally {
|
||||
this.permissionChecking = false
|
||||
}
|
||||
},
|
||||
|
||||
// 文件选择处理
|
||||
handleFileSelect(event, type) {
|
||||
const file = event.target.files[0]
|
||||
if (!file) return
|
||||
|
||||
// 验证文件类型
|
||||
if (!this.validateFileType(file)) {
|
||||
this.showError('请选择.xlsx或.xls格式的Excel文件')
|
||||
event.target.value = ''
|
||||
return
|
||||
}
|
||||
|
||||
// 验证文件大小(限制50MB)
|
||||
if (file.size > 50 * 1024 * 1024) {
|
||||
this.showError('文件大小不能超过50MB')
|
||||
event.target.value = ''
|
||||
return
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 'fullData':
|
||||
this.fullDataFile = file
|
||||
this.fullDataResult = null
|
||||
break
|
||||
case 'lottery':
|
||||
this.lotteryFile = file
|
||||
this.lotteryResult = null
|
||||
break
|
||||
case 'append':
|
||||
this.appendFile = file
|
||||
this.appendResult = null
|
||||
break
|
||||
}
|
||||
},
|
||||
|
||||
// 验证文件类型
|
||||
validateFileType(file) {
|
||||
const allowedTypes = [
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
|
||||
'application/vnd.ms-excel' // .xls
|
||||
]
|
||||
return allowedTypes.includes(file.type) ||
|
||||
file.name.endsWith('.xlsx') ||
|
||||
file.name.endsWith('.xls')
|
||||
},
|
||||
|
||||
// 上传完整数据
|
||||
async uploadFullData() {
|
||||
if (!this.fullDataFile) return
|
||||
|
||||
this.fullDataUploading = true
|
||||
|
||||
try {
|
||||
const response = await lotteryApi.uploadExcelFile(this.fullDataFile)
|
||||
this.fullDataResult = {
|
||||
type: 'success',
|
||||
message: '✅ ' + (response || '完整数据导入成功!')
|
||||
}
|
||||
|
||||
// 清空文件选择
|
||||
this.fullDataFile = null
|
||||
this.$refs.fullDataFileInput.value = ''
|
||||
|
||||
} catch (error) {
|
||||
console.error('完整数据导入失败:', error)
|
||||
this.fullDataResult = {
|
||||
type: 'error',
|
||||
message: '❌ ' + (error?.response?.data || error?.message || '导入失败,请重试')
|
||||
}
|
||||
|
||||
} finally {
|
||||
this.fullDataUploading = false
|
||||
}
|
||||
},
|
||||
|
||||
// 上传开奖数据(覆盖)
|
||||
async uploadLotteryData() {
|
||||
if (!this.lotteryFile) return
|
||||
|
||||
this.lotteryUploading = true
|
||||
|
||||
try {
|
||||
const response = await lotteryApi.uploadLotteryDrawsFile(this.lotteryFile)
|
||||
this.lotteryResult = {
|
||||
type: 'success',
|
||||
message: '✅ ' + (response || '开奖数据导入成功!')
|
||||
}
|
||||
|
||||
// 清空文件选择
|
||||
this.lotteryFile = null
|
||||
this.$refs.lotteryFileInput.value = ''
|
||||
|
||||
} catch (error) {
|
||||
console.error('开奖数据导入失败:', error)
|
||||
this.lotteryResult = {
|
||||
type: 'error',
|
||||
message: '❌ ' + (error?.response?.data || error?.message || '导入失败,请重试')
|
||||
}
|
||||
|
||||
} finally {
|
||||
this.lotteryUploading = false
|
||||
}
|
||||
},
|
||||
|
||||
// 追加开奖数据
|
||||
async appendLotteryData() {
|
||||
if (!this.appendFile) return
|
||||
|
||||
this.appendUploading = true
|
||||
|
||||
try {
|
||||
const response = await lotteryApi.appendLotteryDrawsFile(this.appendFile)
|
||||
this.appendResult = {
|
||||
type: 'success',
|
||||
message: '✅ ' + (response || '开奖数据追加成功!')
|
||||
}
|
||||
|
||||
// 清空文件选择
|
||||
this.appendFile = null
|
||||
this.$refs.appendFileInput.value = ''
|
||||
|
||||
} catch (error) {
|
||||
console.error('开奖数据追加失败:', error)
|
||||
this.appendResult = {
|
||||
type: 'error',
|
||||
message: '❌ ' + (error?.response?.data || error?.message || '追加失败,请重试')
|
||||
}
|
||||
|
||||
} finally {
|
||||
this.appendUploading = false
|
||||
}
|
||||
},
|
||||
|
||||
// 显示错误信息
|
||||
showError(message) {
|
||||
this.errorMessage = message
|
||||
this.showErrorModal = true
|
||||
},
|
||||
|
||||
// 隐藏错误弹窗
|
||||
hideErrorModal() {
|
||||
this.showErrorModal = false
|
||||
this.errorMessage = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.excel-import-management {
|
||||
min-height: 100vh;
|
||||
background: #f5f5f5;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
/* 页面头部 */
|
||||
.page-header {
|
||||
text-align: center;
|
||||
background: linear-gradient(135deg, #3a7bd5, #00d2ff);
|
||||
padding: 30px;
|
||||
border-radius: 8px;
|
||||
color: white;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
/* 权限检查样式 */
|
||||
.permission-checking {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.checking-content {
|
||||
text-align: center;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.checking-content p {
|
||||
margin-top: 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 4px solid rgba(255, 255, 255, 0.3);
|
||||
border-top: 4px solid white;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.header-content h1 {
|
||||
font-size: 32px;
|
||||
margin-bottom: 10px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.header-content p {
|
||||
font-size: 16px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* 主容器 */
|
||||
.import-container {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* 功能区域 */
|
||||
.function-area {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.function-card {
|
||||
border: none;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.card-header .el-icon {
|
||||
font-size: 18px;
|
||||
color: #409EFF;
|
||||
}
|
||||
|
||||
.card-desc {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card-desc p {
|
||||
color: #666;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* 上传区域 */
|
||||
.upload-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.file-input-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.file-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.file-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
border: 2px dashed #dcdfe6;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
background: #fafafa;
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
.file-label:hover {
|
||||
border-color: #409eff;
|
||||
background: #ecf5ff;
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
font-size: 20px;
|
||||
margin-right: 12px;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.file-text {
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
flex: 1;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
/* 减少卡片内边距 */
|
||||
:deep(.el-card__body) {
|
||||
padding: 16px !important;
|
||||
}
|
||||
|
||||
/* 结果消息 */
|
||||
.result-message {
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.result-message.success {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.result-message.error {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
|
||||
/* 信息卡片 */
|
||||
.info-card {
|
||||
border: none;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* 信息说明 */
|
||||
.info-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.info-item h4 {
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.info-item p {
|
||||
color: #666;
|
||||
margin: 2px 0;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* 模态框 */
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 12px;
|
||||
max-width: 400px;
|
||||
width: 90%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.error-modal h3 {
|
||||
color: #dc3545;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.error-modal p {
|
||||
margin-bottom: 20px;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: #409eff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 1200px) {
|
||||
.function-area .el-col {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.excel-import-management {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.function-area .el-row {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.function-area .el-col {
|
||||
flex: 0 0 100%;
|
||||
max-width: 100%;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.page-header h1 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.card-header span {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.card-desc {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.card-desc p {
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.file-label {
|
||||
padding: 8px 10px;
|
||||
min-height: 45px;
|
||||
}
|
||||
|
||||
.file-text {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
font-size: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.upload-section {
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.info-item h4 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.info-item p {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user