|
|
@@ -0,0 +1,332 @@
|
|
|
+<template>
|
|
|
+ <div class="push-system">
|
|
|
+ <!-- 顶部区域:高度 240px -->
|
|
|
+ <div class="ps-top">
|
|
|
+ <div class="ps-top-inner">
|
|
|
+ <div class="ps-title">信息中心不可移动文物资源数据库数据推送系统</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 内容区域 -->
|
|
|
+ <div class="ps-content w1100">
|
|
|
+ <!-- 上传区域:仅允许 .xls 文件 -->
|
|
|
+ <div class="upload-wrapper">
|
|
|
+ <el-upload
|
|
|
+ v-if="!selectedFileName"
|
|
|
+ class="upload"
|
|
|
+ drag
|
|
|
+ action="#"
|
|
|
+ :auto-upload="false"
|
|
|
+ accept=".xls"
|
|
|
+ :show-file-list="true"
|
|
|
+ :before-upload="beforeUpload"
|
|
|
+ :on-change="onFileChange"
|
|
|
+ ref="uploadRef"
|
|
|
+ >
|
|
|
+ <img class="upload-icon" src="@/assets/img/Inbox.svg" alt="">
|
|
|
+ <div class="el-upload__text">点击或拖拽文件到此处上传</div>
|
|
|
+ <div class="el-upload__tip">支持扩展名:.xls</div>
|
|
|
+ </el-upload>
|
|
|
+ <div v-else class="file-bar">
|
|
|
+ <div class="file-info">
|
|
|
+ <el-icon class="file-icon"><Document /></el-icon>
|
|
|
+ <span class="file-name">{{ selectedFileName }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="file-actions">
|
|
|
+ <div text @click="clearSelectedFile" class="clear-btn">
|
|
|
+ <img src="@/assets/img/DeleteOutlined.svg" alt="">
|
|
|
+ </div>
|
|
|
+ <span class="action-divider"></span>
|
|
|
+ <div link class="push-btn" @click="startPush">
|
|
|
+ <img src="@/assets/img/push.svg" alt="">
|
|
|
+ <span class="push-text">开始推送</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 推送内容:切换推送中 / 已完成 -->
|
|
|
+ <el-tabs v-model="activeTab" class="ps-tabs">
|
|
|
+ <el-tab-pane :label="`推送中(${runningList.length})`" name="running">
|
|
|
+ <ul class="task-list">
|
|
|
+ <li v-for="(item, idx) in runningPageItems" :key="idx" class="task-item">
|
|
|
+ <div class="task-left">
|
|
|
+ <div class="task-title">{{ item.title }} | {{ item.code }}</div>
|
|
|
+ <div class="task-status">{{ item.statusText }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="task-right">
|
|
|
+ <el-button link type="danger" @click="onCancel(item)">取消</el-button>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ <div v-if="!runningList.length" class="empty">暂无推送任务</div>
|
|
|
+ <div class="pagination">
|
|
|
+ <el-pagination
|
|
|
+ background
|
|
|
+ layout="prev, pager, next"
|
|
|
+ v-model:current-page="runningPageNum"
|
|
|
+ :page-size="runningPageSize"
|
|
|
+ :total="runningList.length"
|
|
|
+ @current-change="onRunningPageChange"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+ <el-tab-pane :label="`已完成(${doneList.length})`" name="done">
|
|
|
+ <ul class="task-list">
|
|
|
+ <li v-for="(item, idx) in donePageItems" :key="idx" class="task-item">
|
|
|
+ <div class="task-left">
|
|
|
+ <div class="task-title">{{ item.title }} | {{ item.code }}</div>
|
|
|
+ <div class="task-status">推送时间:{{ item.pushedAt }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="task-right">
|
|
|
+ <el-button link type="primary">查看</el-button>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ <div v-if="!doneList.length" class="empty">暂无已完成任务</div>
|
|
|
+ <div class="pagination">
|
|
|
+ <el-pagination
|
|
|
+ background
|
|
|
+ layout="prev, pager, next"
|
|
|
+ v-model:current-page="donePageNum"
|
|
|
+ :page-size="donePageSize"
|
|
|
+ :total="doneList.length"
|
|
|
+ @current-change="onDonePageChange"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, computed } from 'vue'
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
+
|
|
|
+const activeTab = ref('running')
|
|
|
+const uploadRef = ref()
|
|
|
+const selectedFileName = ref('')
|
|
|
+const runningList = ref([
|
|
|
+ { title: '场景标识', code: 'SG-392HHJ89', statusText: '推送中' },
|
|
|
+ { title: '场景标识', code: 'SG-392HHJ90', statusText: '等待中' }
|
|
|
+])
|
|
|
+const doneList = ref([
|
|
|
+ { title: '场景标识', code: 'SG-JD83NFUD', pushedAt: '2025-08-26 12:12' }
|
|
|
+])
|
|
|
+// 分页:推送中
|
|
|
+const runningPageNum = ref(1)
|
|
|
+const runningPageSize = 10
|
|
|
+const runningPageItems = computed(() => {
|
|
|
+ const start = (runningPageNum.value - 1) * runningPageSize
|
|
|
+ return runningList.value.slice(start, start + runningPageSize)
|
|
|
+})
|
|
|
+function onRunningPageChange(page) {
|
|
|
+ runningPageNum.value = page
|
|
|
+}
|
|
|
+
|
|
|
+// 分页:已完成
|
|
|
+const donePageNum = ref(1)
|
|
|
+const donePageSize = 10
|
|
|
+const donePageItems = computed(() => {
|
|
|
+ const start = (donePageNum.value - 1) * donePageSize
|
|
|
+ return doneList.value.slice(start, start + donePageSize)
|
|
|
+})
|
|
|
+function onDonePageChange(page) {
|
|
|
+ donePageNum.value = page
|
|
|
+}
|
|
|
+
|
|
|
+function beforeUpload(file) {
|
|
|
+ // 仅允许 .xls 文件
|
|
|
+ const isXls = /\.xls$/i.test(file.name)
|
|
|
+ if (!isXls) {
|
|
|
+ ElMessage.error('仅支持 .xls 文件上传')
|
|
|
+ }
|
|
|
+ return isXls
|
|
|
+}
|
|
|
+
|
|
|
+function onFileChange(file, fileList) {
|
|
|
+ // 示例:文件加入后把任务放到“推送中”列表
|
|
|
+ if (file && /\.xls$/i.test(file.name)) {
|
|
|
+ selectedFileName.value = file.name
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function onCancel(item) {
|
|
|
+ const idx = runningList.value.indexOf(item)
|
|
|
+ if (idx > -1) runningList.value.splice(idx, 1)
|
|
|
+}
|
|
|
+
|
|
|
+function clearSelectedFile() {
|
|
|
+ selectedFileName.value = ''
|
|
|
+ if (uploadRef.value) uploadRef.value.clearFiles()
|
|
|
+}
|
|
|
+
|
|
|
+function startPush() {
|
|
|
+ if (!selectedFileName.value) {
|
|
|
+ ElMessage.warning('请先上传 .xls 文件')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const code = selectedFileName.value.replace(/\.xls$/i, '')
|
|
|
+ runningList.value.unshift({ title: '场景标识', code, statusText: '推送中' })
|
|
|
+ ElMessage.success('已开始推送')
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.push-system {
|
|
|
+ background: #f5f0ea;
|
|
|
+ min-height: 100vh;
|
|
|
+}
|
|
|
+
|
|
|
+.ps-top {
|
|
|
+ height: 240px;
|
|
|
+ background-image: url('@/assets/img/home-bg.png');
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ background-position: right top;
|
|
|
+ background-size: auto 100%;
|
|
|
+
|
|
|
+ .ps-top-inner {
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ps-title {
|
|
|
+ width: 671px;
|
|
|
+ height: 106px;
|
|
|
+ font-family: Microsoft YaHei, Microsoft YaHei;
|
|
|
+ font-weight: bold;
|
|
|
+ font-size: 40px;
|
|
|
+ color: #781C0B;
|
|
|
+ letter-spacing: 4px;
|
|
|
+ text-align: center;
|
|
|
+ font-style: normal;
|
|
|
+ text-transform: none;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.ps-content {
|
|
|
+ padding: 0px 0 40px;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-wrapper {
|
|
|
+ width: 1100px;
|
|
|
+ height: 156px;
|
|
|
+ margin: 0 0 24px;
|
|
|
+ :deep(.el-upload-dragger) {
|
|
|
+ width: 1100px;
|
|
|
+ border: none;
|
|
|
+ }
|
|
|
+ :deep(.el-upload){
|
|
|
+ --el-upload-dragger-padding-horizontal: 34px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.upload {
|
|
|
+ .upload-icon {
|
|
|
+ width: 32px;
|
|
|
+ height: 32px;
|
|
|
+ }
|
|
|
+ .el-upload__text {
|
|
|
+ font-size: 16px;
|
|
|
+ color: rgba(0,0,0,0.85);
|
|
|
+ }
|
|
|
+ .el-upload__tip {
|
|
|
+ font-size: 14px;
|
|
|
+ color: rgba(0,0,0,0.45);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.file-bar {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ background: #fff;
|
|
|
+ padding: 0 0 0 64px;
|
|
|
+ border-radius: 6px;
|
|
|
+ height: 158px;
|
|
|
+ .file-actions {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+ .push-btn {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 264px;
|
|
|
+ color: #a46a4b;
|
|
|
+ padding: 0 8px;
|
|
|
+ cursor: pointer;
|
|
|
+ span{
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .push-btn :deep(.el-icon) {
|
|
|
+ font-size: 32px;
|
|
|
+ color: #a46a4b;
|
|
|
+ margin-right: 8px;
|
|
|
+ }
|
|
|
+}
|
|
|
+.file-info {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+}
|
|
|
+.file-icon { color: #a46a4b; }
|
|
|
+.file-name { color: #333; }
|
|
|
+.push-text { color: #666; font-size: 16px; vertical-align: middle; }
|
|
|
+.clear-btn { color: #a46a4b; margin-right: 54px;cursor: pointer; }
|
|
|
+.action-divider { width: 2px; height: 158px; background: #FAFAFA; display: inline-block; }
|
|
|
+
|
|
|
+.ps-tabs {
|
|
|
+ background: #fff;
|
|
|
+ padding: 40px 64px;
|
|
|
+ border-radius: 6px;
|
|
|
+ :deep(.el-tabs__nav-wrap:after) {
|
|
|
+ height: 1px;
|
|
|
+ background-color: #f5f5f5;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.task-list {
|
|
|
+ margin: 0;
|
|
|
+ padding: 0;
|
|
|
+ list-style: none;
|
|
|
+}
|
|
|
+.task-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 16px 8px;
|
|
|
+ border-bottom: 1px solid #F5F5F5;
|
|
|
+}
|
|
|
+.task-title {
|
|
|
+ font-size: 15px;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+.task-status {
|
|
|
+ margin-top: 4px;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #8c8c8c;
|
|
|
+}
|
|
|
+.empty {
|
|
|
+ padding: 24px;
|
|
|
+ color: #9c9c9c;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.pagination {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ padding-top: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.w1100 {
|
|
|
+ width: 1100px;
|
|
|
+ margin: 0 auto;
|
|
|
+}
|
|
|
+</style>
|