123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- <template>
- <up-popup :show="showPopup" mode="center" round="20" @close="handleClose">
- <view class="album-popup">
- <view class="album-title">
- <view class="name">
- 果树相册
- <view class="sub-name">无人机实时监测生长情况</view>
- </view>
- <image class="icon" :src="`${config.BASIC_IMG}img/treePage/drone-icon-popup.png`"></image>
- </view>
- <view class="album-cont">
- <view class="time-line-scroll">
- <scroll-view class="time-line-container" scroll-x :scroll-into-view="scrollIntoViewId" scroll-with-animation>
- <view class="time-line">
- <view class="time-item" v-for="(item,index) in dateList" :key="index" :id="`d-${item.dateStr}`" @click="handleDateClick(item.dateStr)">
- <text :style="{color:(selectedDateStr===item.dateStr)?'#2199F8':'#777777'}">{{item.display}}</text>
- <view class="dot" :style="{background:(selectedDateStr===item.dateStr)?'#2199F8':'#777777'}"></view>
- <text class="today" v-if="item.isToday">今</text>
- <text v-if="item.showYear" class="year-flag">{{ item.year }}</text>
- </view>
- </view>
- </scroll-view>
- <!-- 中间竖线标志 -->
- <view class="center-line"></view>
- </view>
- <view class="swiper-wrap">
- <swiper class="swiper">
- <swiper-item v-for="(item,index) in photoList" :key="index">
- <image class="img" :src="getImageUrl(item.filename)"></image>
- </swiper-item>
- </swiper>
- <!-- <view class="arrow left">
- <up-icon name="arrow-left" bold color="#F0D09C" size="22"></up-icon>
- </view>
- <view class="arrow right">
- <up-icon name="arrow-right" bold color="#F0D09C" size="22"></up-icon>
- </view> -->
- </view>
- </view>
- </view>
- </up-popup>
- </template>
- <script setup>
- import config from "@/api/config.js"
- import TREE from '@/api/tree.js'
- import {
- ref,
- watch,
- nextTick
- } from "vue";
- const resize = "?x-oss-process=image/resize,w_1000";
- const props = defineProps({
- show: {
- type: Boolean,
- defalut: false,
- },
- farmBuyId: {
- type: [String, Number],
- default: ''
- },
- sampleId: {
- type: [String, Number],
- default: 110939
- }
- });
-
- const showPopup = ref(false);
- const handleClose = ()=>{
- showPopup.value = false
- }
- const dateList = ref([])
- const scrollIntoViewId = ref('')
- const selectedDateStr = ref('')
- const formatToDisplay = (dateStr)=>{
- // dateStr: YYYY-MM-DD
- const [y,m,d] = dateStr.split('-')
- return `${m}/${d}`
- }
- const getTodayStr = ()=>{
- const d = new Date()
- const mm = `${d.getMonth()+1}`.padStart(2,'0')
- const dd = `${d.getDate()}`.padStart(2,'0')
- return `${d.getFullYear()}-${mm}-${dd}`
- }
- const fetchHasImageDates = async ()=>{
- if(!props.farmBuyId) return
- try{
- const {data} = await TREE.findHasImagesDate({farmBuyId: props.farmBuyId})
- const today = getTodayStr()
- const arr = Array.isArray(data) ? data : []
- const mapped = arr.map(ds=>{
- const dateStr = (typeof ds === 'string') ? ds.split(' ')[0] : ''
- const isToday = dateStr === today
- const [y,m,d] = dateStr.split('-')
- return {
- dateStr,
- display: dateStr ? formatToDisplay(dateStr) : '',
- isToday,
- year: y,
- month: m,
- day: d
- }
- }).filter(i=>i.dateStr)
- mapped.sort((a,b)=> a.dateStr.localeCompare(b.dateStr))
-
- // 只显示月份第一天和中间/下月第一天
- const filteredDates = []
- let currentMonth = ''
- let currentYear = ''
-
- for(let i=0;i<mapped.length;i++){
- const item = mapped[i]
- const monthKey = `${item.year}-${item.month}`
-
- if(monthKey !== currentMonth){
- // 新月份的第一天
- item.showYear = monthKey.split('-')[0] !== currentYear
- filteredDates.push(item)
- currentMonth = monthKey
- currentYear = item.year
- } else {
- // 检查是否是当前月份的中间日期或下个月第一天
- const day = parseInt(item.day)
- if(day === 15 || day === 1){
- item.showYear = false
- filteredDates.push(item)
- }
- }
- }
-
- dateList.value = filteredDates
- if(dateList.value.length){
- const last = dateList.value[dateList.value.length-1]
- selectedDateStr.value = last.dateStr
- // 强制等渲染后再滚动到最右端
- scrollIntoViewId.value = ''
- await nextTick()
- scrollIntoViewId.value = `d-${last.dateStr}`
- }else{
- selectedDateStr.value = ''
- scrollIntoViewId.value = ''
- }
- }catch(e){
- // 静默失败
- }
- }
- const fetchTreeImages = async (dateStr)=>{
- try{
- const params = {
- page: 1,
- limit: 1,
- // treeId: Number(props.sampleId),
- treeId: 110939,
- date: dateStr,
- }
- const {data} = await TREE.treeImageList(params)
- photoList.value = data || []
- }catch(err){
- console.log('treeImageList error:', err)
- }
- }
- const getImageUrl = (filename) => {
- if (filename.startsWith("https")) {
- return filename; // 直接使用完整 URL
- } else {
- return config.BASE_IMG_URL + filename + resize; // 拼接基础 URL
- }
- };
-
- const handleDateClick = (dateStr)=>{
- selectedDateStr.value = dateStr
- scrollIntoViewId.value = `d-${dateStr}`
- fetchTreeImages(dateStr)
- }
- const photoList = ref([]);
-
- watch(
- () => props.show,
- async (val) => {
- showPopup.value = val;
- if(val){
- await fetchHasImageDates()
- const today = getTodayStr()
- fetchTreeImages(today)
- }
- }
- );
- watch(
- () => props.farmBuyId,
- (val) => {
- if(showPopup.value && val){
- fetchHasImageDates()
- }
- }
- )
- </script>
- <style lang="scss" scoped>
- .album-popup {
- width: 92vw;
- .album-title {
- padding: 30rpx 0 46rpx 30rpx;
- position: relative;
- background-image: linear-gradient(120deg, #79C4FF 13%, #FFFFFF 66%);
- border-radius: 40rpx 40rpx 0 0;
- line-height: 44rpx;
- .name {
- color: #004275;
- font-size: 48rpx;
- font-family: 'PangMenZhengDao';
- .sub-name {
- font-size: 24rpx;
- }
- }
- .icon {
- position: absolute;
- top: -100rpx;
- right: -26rpx;
- width: 364rpx;
- height: 300rpx;
- }
- }
- .album-cont {
- position: relative;
- z-index: 2;
- margin-top: -34rpx;
- padding: 32rpx 0 20rpx;
- background: #fff;
- border-radius: 40rpx;
- .time-line-scroll{
- margin-bottom: 16rpx;
- width: 100%;
- position: relative;
- }
- .time-line-container{
- width: 100%;
- white-space: nowrap;
- }
- .time-line{
- display: flex;
- padding: 0 20rpx;
- position: relative;
- }
- .center-line{
- position: absolute;
- left: 50%;
- top: 0;
- bottom: 0;
- width: 2rpx;
- background: #2199F8;
- z-index: 10;
- transform: translateX(-50%);
- pointer-events: none;
- }
- .time-item{
- min-width: 120rpx;
- font-size: 24rpx;
- color: #777777;
- display: flex;
- flex-direction: column;
- align-items: center;
- position: relative;
- padding: 0 12rpx;
- cursor: pointer;
-
- &::before{
- content: '';
- position: absolute;
- top: 44%;
- left: 0;
- right: 0;
- height: 2rpx;
- background: rgba(136, 136, 136, 0.1);
- }
- .dot{
- width: 14rpx;
- height: 14rpx;
- background: #777777;
- border-radius: 50%;
- position: relative;
- z-index: 5;
- }
- .today{
- color: #2199F8;
- margin-top: 8rpx;
- }
- .year-flag{
- font-size: 18rpx;
- color: #999;
- margin-top: 6rpx;
- }
- }
- .swiper-wrap{
- position: relative;
- padding: 0 20rpx;
- .swiper {
- width: 100%;
- height: 496rpx;
-
- .img{
- width: 100%;
- height: 100%;
- border-radius: 16rpx;
- }
- }
- .arrow{
- position: absolute;
- top: calc(50% - 40rpx);
- width: 80rpx;
- height: 80rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 50%;
- background: rgba(0, 0, 0, .6);
- }
- .left{
- left: 32rpx;
- }
- .right{
- right: 32rpx;
- }
- }
- }
- }
- </style>
|