191 lines
5.4 KiB
Vue
191 lines
5.4 KiB
Vue
<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>
|