petstore-frontend/src/pages/mine/MyReports.vue

191 lines
5.4 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="page-shell my-reports-page">
<!-- 顶部导航 -->
<view class="report-nav nav-gradient" :style="navSafeStyle">
<view class="nav-back" @click="goBackToMine"><AppIcon name="back" :size="18" color="#ffffff" /></view>
<text class="nav-title">我的报告</text>
<view class="nav-placeholder"></view>
</view>
<view class="page-section reports-hero">
<view class="hero-title">服务成果回顾</view>
<view class="hero-sub">已生成 <text class="hero-count">{{ reportList.length }}</text> 份报告点击卡片可查看详情并分享</view>
</view>
<!-- 网格相册 -->
<div v-if="reportList.length > 0" class="page-section section-gap gallery-grid">
<div
v-for="r in reportList"
:key="r.id"
class="gallery-item"
@click="viewReport(r)"
>
<div class="gallery-cover">
<img
v-if="r.beforePhoto"
:src="imgUrl(r.beforePhoto)"
class="cover-img"
/>
<div v-else class="cover-placeholder">
<span class="placeholder-icon"><AppIcon name="camera" :size="18" color="#94a3b8" /></span>
</div>
<div class="gallery-overlay">
<div class="overlay-name">{{ r.petName }}</div>
<div class="overlay-service">{{ r.serviceType }}</div>
</div>
</div>
<div class="gallery-meta">
<span class="meta-chip">
<AppIcon name="report" :size="11" color="#64748b" />
<text>查看报告</text>
</span>
</div>
</div>
</div>
<view v-if="!loading && reportList.length === 0" class="empty"><text>暂无报告</text></view>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import AppIcon from '../../components/AppIcon.vue'
import { navigateTo } from '../../utils/globalState.js'
import { getReportList, imgUrl, API_ORIGIN } from '../../api/index.js'
import { getStoreSession, getUserSession } from '../../utils/session.js'
const emit = defineEmits(['change-page'])
const userInfo = getUserSession()
const storeInfo = getStoreSession()
const navSafeStyle = (() => {
const statusBarHeight = uni.getSystemInfoSync?.().statusBarHeight || 20
let navHeight = statusBarHeight + 44
const menuRect = uni.getMenuButtonBoundingClientRect?.()
if (menuRect && menuRect.top && menuRect.height) {
const verticalGap = Math.max(menuRect.top - statusBarHeight, 4)
navHeight = statusBarHeight + verticalGap * 2 + menuRect.height
}
return `padding-top:${statusBarHeight}px;height:${navHeight}px;`
})()
const loading = ref(false)
const reportList = ref([])
const loadReports = async () => {
loading.value = true
const params = userInfo.role === 'boss'
? { storeId: storeInfo.id }
: { userId: userInfo.id }
const res = await getReportList(params)
loading.value = false
if (res.code === 200) reportList.value = res.data
}
const goBackToMine = () => {
const pages = getCurrentPages()
if (pages.length > 1) {
uni.navigateBack()
return
}
navigateTo('mine')
}
const viewReport = (r) => {
let origin = API_ORIGIN
// #ifdef H5
origin = window.location.origin
// #endif
const url = `${origin}/report.html?token=${r.reportToken}`
// #ifdef H5
window.location.href = url
// #endif
// #ifndef H5
uni.navigateTo({ url: `/pages/report-view/reportView?token=${r.reportToken}` })
// #endif
}
onMounted(() => loadReports())
</script>
<style scoped>
.my-reports-page { padding: 0 0 120rpx; }
.nav-placeholder { width: 32px; }
.reports-hero {
margin-top: 12px;
padding: 14px 16px;
border: 1px solid #dcefe3;
border-radius: 14px;
background: linear-gradient(135deg, #f3fff7 0%, #ecfbf3 100%);
}
.hero-title { font-size: 16px; font-weight: 700; color: #166534; }
.hero-sub { margin-top: 4px; font-size: 12px; color: #4b5563; line-height: 1.45; }
.hero-count { font-weight: 700; color: #2db96d; }
.placeholder-icon {
width: 36px;
height: 36px;
border-radius: 10px;
background: #e2e8f0;
display: inline-flex;
align-items: center;
justify-content: center;
}
.report-nav {
padding: 14px 16px;
display: flex; align-items: center; justify-content: space-between;
position: sticky; top: 0; z-index: 10;
}
.nav-back { font-size: 20px; color: #fff; }
.nav-title { font-size: 18px; font-weight: 700; color: #fff; }
.gallery-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
padding-top: 14px;
}
.gallery-item {
border-radius: 14px;
overflow: hidden;
cursor: pointer;
background: #fff;
border: 1px solid #e8edf4;
box-shadow: 0 8px 18px rgba(15, 23, 42, 0.06);
}
.gallery-cover {
position: relative;
width: 100%;
aspect-ratio: 1;
overflow: hidden;
}
.cover-img { width: 100%; height: 100%; object-fit: cover; }
.cover-placeholder {
width: 100%;
height: 100%;
background: #f0ede8;
display: flex;
align-items: center;
justify-content: center;
}
.gallery-overlay {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 8px 10px;
background: linear-gradient(transparent, rgba(0,0,0,0.65));
color: #fff;
}
.overlay-name { font-size: 13px; font-weight: 600; }
.overlay-service { font-size: 11px; opacity: 0.9; margin-top: 2px; }
.gallery-meta { padding: 8px 10px 10px; background: #fff; }
.meta-chip {
display: inline-flex;
align-items: center;
gap: 4px;
height: 22px;
padding: 0 8px;
border-radius: 999px;
background: #f1f5f9;
color: #64748b;
font-size: 11px;
}
</style>