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

246 lines
6.6 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 report-nav--tab-root nav-gradient" :style="navSafeStyle">
<view class="nav-placeholder"></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>
<!-- 仅商家/员工可新建报告;客户仅查看列表 -->
<view
v-if="userInfo.role !== 'customer'"
class="fab-new-report"
@click="openFillReport"
hover-class="fab-new-report--hover"
>
<text class="fab-new-report-icon">+</text>
</view>
<TabBar current-page="report" @change="goPage" />
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import AppIcon from '../../components/AppIcon.vue'
import TabBar from '../../components/TabBar.vue'
import { useNavigator } from '../../composables/useNavigator.js'
import { getReportList, imgUrl, API_ORIGIN } from '../../api/index.js'
import { getStoreSession, getUserSession } from '../../utils/session.js'
const { goPage } = useNavigator()
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, page: 1, pageSize: 50 }
: { userId: userInfo.id, page: 1, pageSize: 50 }
const res = await getReportList(params)
loading.value = false
if (res.code === 200) reportList.value = res.data
}
const openFillReport = () => {
uni.navigateTo({ url: '/pages/report/Report' })
}
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())
onShow(() => loadReports())
</script>
<style scoped>
.my-reports-page {
padding: 0 0 calc(76px + env(safe-area-inset-bottom));
box-sizing: border-box;
}
.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;
}
.report-nav--tab-root .nav-title {
flex: 1;
text-align: center;
max-width: 72%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
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;
}
/* 新建报告(与首页新建预约 FAB 对齐z-index 高于 TabBar */
.fab-new-report {
position: fixed;
right: 20px;
bottom: calc(56px + env(safe-area-inset-bottom) + 20px);
width: 56px;
height: 56px;
border-radius: 28px;
background: #2db96d;
box-shadow: 0 6px 20px rgba(45, 185, 109, 0.42);
display: flex;
align-items: center;
justify-content: center;
z-index: 1002;
}
.fab-new-report--hover {
opacity: 0.92;
transform: scale(0.96);
}
.fab-new-report-icon {
color: #fff;
font-size: 32px;
font-weight: 300;
line-height: 1;
margin-top: -2px;
}
</style>