123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- <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">
- <scroll-view class="time-line-scroll" 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 v-if="item.showYear" class="year-flag">{{ item.year }}</text>
- <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>
- </view>
- </view>
- </scroll-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)" mode="aspectFill"></image>
- <!-- <view class="text-wrap">
- <view class="date">{{item.uploadDate}}</view>
- <view class="code">{{item.treeCode}}</view>
- </view> -->
- </swiper-item>
- </swiper>
- <view class="arrow left" @click="handlePrevDay">
- <up-icon name="arrow-left" bold color="#F0D09C" size="22"></up-icon>
- </view>
- <view class="arrow right" @click="handleNextDay">
- <up-icon name="arrow-right" bold color="#F0D09C" size="22"></up-icon>
- </view>
- </view>
- <!-- <time-scale></time-scale> -->
- </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";
- import timeScale from './timeScale.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
- return {
- dateStr,
- display: dateStr ? formatToDisplay(dateStr) : '',
- isToday,
- year: dateStr ? dateStr.slice(0,4) : ''
- }
- }).filter(i=>i.dateStr)
- mapped.sort((a,b)=> a.dateStr.localeCompare(b.dateStr))
- for(let i=0;i<mapped.length;i++){
- mapped[i].showYear = i===0 || mapped[i].year !== mapped[i-1].year
- }
- dateList.value = mapped
- 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) || 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 handlePrevDay = () => {
- if(!selectedDateStr.value) return
-
- const currentDate = new Date(selectedDateStr.value)
- const prevDate = new Date(currentDate)
- prevDate.setDate(currentDate.getDate() - 1)
-
- const prevDateStr = prevDate.toISOString().split('T')[0]
- selectedDateStr.value = prevDateStr
- scrollIntoViewId.value = `d-${prevDateStr}`
- fetchTreeImages(prevDateStr)
- }
-
- const handleNextDay = () => {
- if(!selectedDateStr.value) return
-
- const currentDate = new Date(selectedDateStr.value)
- const nextDate = new Date(currentDate)
- nextDate.setDate(currentDate.getDate() + 1)
-
- const today = new Date()
- const todayStr = today.toISOString().split('T')[0]
-
- // 不能超过当前日期
- if(nextDate.toISOString().split('T')[0] > todayStr) {
- uni.showToast({
- title: '不能超过当前日期',
- icon: 'none',
- duration: 2000
- })
- return
- }
-
- const nextDateStr = nextDate.toISOString().split('T')[0]
- selectedDateStr.value = nextDateStr
- scrollIntoViewId.value = `d-${nextDateStr}`
- fetchTreeImages(nextDateStr)
- }
- 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%;
- white-space: nowrap;
- }
- .time-line{
- display: flex;
- padding: 0 20rpx;
- }
- .time-item{
- min-width: 100rpx;
- font-size: 24rpx;
- color: #777777;
- display: flex;
- flex-direction: column;
- align-items: center;
- position: relative;
- padding: 0 12rpx;
- &::before{
- content: '';
- position: absolute;
- top: 44%;
- left: 0;
- right: 0;
- height: 2rpx;
- background: rgba(136, 136, 136, 0.1);
- }
- .year-flag{
- font-size: 20rpx;
- color: #999;
- margin-bottom: 6rpx;
- }
- .dot{
- width: 14rpx;
- height: 14rpx;
- background: #777777;
- border-radius: 50%;
- }
- .today{
- color: #2199F8;
- margin-top: 8rpx;
- }
- }
- .swiper-wrap{
- position: relative;
- padding: 0 20rpx;
- .swiper {
- width: 100%;
- height: 496rpx;
-
- .img{
- width: 100%;
- height: 100%;
- border-radius: 16rpx;
- }
- .text-wrap{
- position: absolute;
- bottom: 20rpx;
- left: 20rpx;
- font-size: 20rpx;
- color: #fff;
- .date{
- font-size: 40rpx;
- font-family: 'SMILEYSANS';
- }
- }
- }
- .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>
|