|
|
@@ -54,14 +54,22 @@
|
|
|
/>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
+ <!-- 回到顶部 -->
|
|
|
+ <transition name="fade">
|
|
|
+ <button v-if="showBackToTop" class="back-to-top" @click="scrollToTop" title="回到顶部">
|
|
|
+ <el-icon :size="20"><Top /></el-icon>
|
|
|
+ </button>
|
|
|
+ </transition>
|
|
|
</div>
|
|
|
|
|
|
<!-- 导入对话框(从订单页触发) -->
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { ref, onMounted } from 'vue'
|
|
|
+import { ref, onMounted, onUnmounted } from 'vue'
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
+import { Top } from '@element-plus/icons-vue'
|
|
|
import {
|
|
|
setToken, getToken, removeToken,
|
|
|
queryOrders, exportExcel, importLogistics, downloadTemplate, queryLogs, getStats
|
|
|
@@ -100,6 +108,15 @@ const logData = ref([])
|
|
|
const logTotal = ref(0)
|
|
|
const logLoading = ref(false)
|
|
|
|
|
|
+// 回到顶部
|
|
|
+const showBackToTop = ref(false)
|
|
|
+function handleScroll() {
|
|
|
+ showBackToTop.value = window.scrollY > 300
|
|
|
+}
|
|
|
+function scrollToTop() {
|
|
|
+ window.scrollTo({ top: 0, behavior: 'smooth' })
|
|
|
+}
|
|
|
+
|
|
|
// 初始化
|
|
|
onMounted(() => {
|
|
|
const token = getToken()
|
|
|
@@ -112,6 +129,11 @@ onMounted(() => {
|
|
|
handleQuery()
|
|
|
loadStats()
|
|
|
}
|
|
|
+ window.addEventListener('scroll', handleScroll)
|
|
|
+})
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ window.removeEventListener('scroll', handleScroll)
|
|
|
})
|
|
|
|
|
|
function handleLoginSuccess(data) {
|
|
|
@@ -282,4 +304,30 @@ function handleRefresh() {
|
|
|
width: 100%;
|
|
|
margin: 0 auto;
|
|
|
}
|
|
|
+
|
|
|
+.back-to-top {
|
|
|
+ position: fixed;
|
|
|
+ right: 32px;
|
|
|
+ bottom: 32px;
|
|
|
+ width: 44px;
|
|
|
+ height: 44px;
|
|
|
+ border: none;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: var(--primary-600, #2563eb);
|
|
|
+ color: #fff;
|
|
|
+ cursor: pointer;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ box-shadow: 0 4px 12px rgba(37, 99, 235, 0.35);
|
|
|
+ transition: transform 0.2s, box-shadow 0.2s;
|
|
|
+ z-index: 1000;
|
|
|
+}
|
|
|
+.back-to-top:hover {
|
|
|
+ transform: translateY(-2px);
|
|
|
+ box-shadow: 0 6px 16px rgba(37, 99, 235, 0.45);
|
|
|
+}
|
|
|
+
|
|
|
+.fade-enter-active, .fade-leave-active { transition: opacity 0.25s; }
|
|
|
+.fade-enter-from, .fade-leave-to { opacity: 0; }
|
|
|
</style>
|