Browse Source

fix: 修复ios下时间选择器弹窗多弹窗层级问题

cuiyalong 1 năm trước cách đây
mục cha
commit
5e3bb7b231

+ 6 - 0
src/components/search/result/list/index.vue

@@ -64,6 +64,7 @@
     </slot>
     <SearchPowerTipDialog v-model="dialog.freeTip" />
     <ToLoginDialog v-model="dialog.toLogin" @confirm-success="afterLoginSuccess" />
+    <DateTimePopup />
   </div>
 </template>
 
@@ -76,6 +77,7 @@ import { getBiddingZBXMSearchList } from '@/api/modules/search'
 import { InfoTypeTransform } from '@/utils/transform/info-type-transform'
 import SearchPowerTipDialog from '@/components/dialog/SearchPowerTipDialog'
 import ToLoginDialog from '@/components/dialog/ToLoginDialog.vue'
+import DateTimePopup from '@/components/selector/date-time-group/date-time-popup'
 import dayjs from 'dayjs'
 import Taro from '@tarojs/taro'
 import { mapActions, mapGetters } from 'vuex'
@@ -89,6 +91,7 @@ export default {
     [ProjectCell.name]: ProjectCell,
     SearchPowerTipDialog,
     ToLoginDialog,
+    DateTimePopup,
     Filters
   },
   props: {
@@ -613,6 +616,9 @@ export default {
       const { filters } = this.$refs
       if (filters) {
         filters.resetFilters()
+        this.$nextTick(() => {
+          this.doSearch()
+        })
       }
     },
     onFilterCancel() {

+ 318 - 0
src/components/selector/date-time-group/date-time-popup.vue

@@ -0,0 +1,318 @@
+<template>
+  <div class="date-time-popup-list" v-if="isIOS">
+    <van-popup
+      v-model="popupShow.start"
+      round
+      class="date-time-select-popup"
+      :position="popup.position"
+      :safe-area-inset-bottom="true"
+      get-container="body"
+      :style="popup.style"
+    >
+      <PopupLayout
+        title="请选择开始时间"
+        @closeIconClick="popupShow.start = false"
+      >
+        <div slot="default">
+          <van-datetime-picker
+            class="date-time-picker highlight-active"
+            ref="startDateTimePicker"
+            v-model="start.currentDate"
+            :key="start.timestamp + 'start'"
+            :show-toolbar="picker.showToolBar"
+            :swipe-duration="picker.swipeDuration"
+            :type="picker.type"
+            :min-date="start.minDate"
+            :max-date="start.maxDate"
+            :formatter="formatter"
+          />
+        </div>
+        <div slot="footer" class="j-button-group height40">
+          <button class="j-button-cancel" @click="resetPopup('start')">
+            重置
+          </button>
+          <button class="j-button-confirm" @click="confirmPicker('start')">
+            确定
+          </button>
+        </div>
+      </PopupLayout>
+    </van-popup>
+    <van-popup
+      v-model="popupShow.end"
+      round
+      class="date-time-select-popup"
+      :position="popup.position"
+      :safe-area-inset-bottom="true"
+      get-container="body"
+      :style="popup.style"
+    >
+      <PopupLayout
+        title="请选择结束时间"
+        @closeIconClick="popupShow.end = false"
+      >
+        <div slot="default">
+          <van-datetime-picker
+            class="date-time-picker highlight-active"
+            ref="endDateTimePicker"
+            v-model="end.currentDate"
+            :key="end.timestamp + 'end'"
+            :show-toolbar="picker.showToolBar"
+            :swipe-duration="picker.swipeDuration"
+            :type="picker.type"
+            :min-date="end.minDate"
+            :max-date="end.maxDate"
+            :formatter="formatter"
+          />
+        </div>
+        <div slot="footer" class="j-button-group height40">
+          <button class="j-button-cancel" @click="resetPopup('end')">
+            重置
+          </button>
+          <button class="j-button-confirm" @click="confirmPicker('end')">
+            确定
+          </button>
+        </div>
+      </PopupLayout>
+    </van-popup>
+  </div>
+</template>
+<script>
+import PopupLayout from '@/components/common/PopupLayout'
+import { DatetimePicker, Popup } from 'vant'
+import { dateFormatter, getDeviceInfo } from '@/utils/'
+import dayjs from 'dayjs'
+import EventBus from '@/utils/event'
+
+export default {
+  name: 'DateTimePopup',
+  components: {
+    [DatetimePicker.name]: DatetimePicker,
+    [Popup.name]: Popup,
+    PopupLayout
+  },
+  props: {
+    startTimeRemap: {
+      // 初始重置时间
+      type: Number,
+      default: 0
+    },
+    endTimeRemap: {
+      type: Number,
+      default: 0
+    }
+  },
+  data() {
+    return {
+      debug: true,
+      picker: {
+        type: 'date',
+        showToolBar: false,
+        swipeDuration: 300
+      },
+      popup: {
+        position: 'bottom',
+        style: {}
+      },
+      start: {
+        value: '',
+        valueStamp: '',
+        placeholder: '开始时间',
+        currentDate: new Date(),
+        minDate: new Date(2010, 0, 1),
+        maxDate: new Date()
+      },
+      end: {
+        value: '',
+        valueStamp: '',
+        placeholder: '结束时间',
+        currentDate: new Date(),
+        minDate: new Date(2010, 0, 1),
+        maxDate: new Date()
+      },
+      popupShow: {
+        start: false,
+        end: false
+      },
+      isIOS: true,
+      deviceInfo: {},
+    }
+  },
+  created() {
+    this.calcPlatform()
+    if (this.isIOS) {
+      this.registerEventBus()
+    }
+  },
+  methods: {
+    calcPlatform() {
+      this.deviceInfo = getDeviceInfo()
+      const system = this.deviceInfo.system
+      if (system) {
+        this.isIOS = system.toLowerCase().includes('ios')
+        console.log('是否ios',this.isIOS)
+      }
+    },
+    registerEventBus() {
+      // 先移除监听
+      EventBus.off('dateTime:popup:sendValueToPopup')
+
+      EventBus.on('dateTime:popup:sendValueToPopup', (payload) => {
+        const { start, end, popupShow } = payload
+        Object.assign(this.start, start)
+        Object.assign(this.end, end)
+        Object.assign(this.popupShow, popupShow)
+      })
+    },
+    sendValueToGroup() {
+      const payload = {
+        start: this.start,
+        end: this.end,
+        popupShow: this.popupShow,
+      }
+      EventBus.trigger('dateTime:popup:sendValueToGroup', payload)
+    },
+    startSyncValue() {
+      if (this.isIOS) {
+        this.sendValueToGroup()
+      }
+    },
+    formatter(type, val) {
+      if (type === 'year') {
+        return val + '年'
+      }
+      if (type === 'month') {
+        return val + '月'
+      }
+      if (type === 'day') {
+        return val + '日'
+      }
+      return val
+    },
+    clickField(type) {
+      this.popupState(type, true)
+    },
+    setInputState(type) {
+      this[type].valueStamp = this[type].currentDate.getTime()
+      this[type].value = dateFormatter(this[type].currentDate, 'yyyy-MM-dd')
+      this[type].timestamp = Date.now()
+      if (type === 'start') {
+        this.end.minDate = this.start.currentDate
+      } else if (type === 'end') {
+        this.start.maxDate = this.end.currentDate
+      }
+      this.startSyncValue()
+    },
+    popupState(type, state) {
+      this.popupShow[type] = state
+      this.startSyncValue()
+    },
+    resetAll() {
+      this.resetPicker('start')
+      this.resetPicker('end')
+    },
+    resetPicker(type) {
+      if (type === 'start') {
+        this[type].value = this.startTimeRemap
+          ? dateFormatter(this.startTimeRemap, 'yyyy-MM-dd')
+          : ''
+        this[type].valueStamp = this.startTimeRemap ? this.startTimeRemap : ''
+      } else if (type === 'end') {
+        this[type].value = this.endTimeRemap
+          ? dateFormatter(this.endTimeRemap, 'yyyy-MM-dd')
+          : ''
+        this[type].valueStamp = this.endTimeRemap ? this.endTimeRemap : ''
+      }
+      // 重置最大值和最小值
+      if (type === 'start') {
+        this.end.minDate = new Date(2015, 0, 1)
+      } else if (type === 'end') {
+        this.start.maxDate = new Date()
+      }
+      if (type === 'start') {
+        this[type].currentDate = this.startTimeRemap
+          ? new Date(this.startTimeRemap)
+          : new Date()
+        this[type].timestamp = this.startTimeRemap
+          ? this.startTimeRemap
+          : Date.now()
+      } else if (type === 'end') {
+        this[type].currentDate = this.endTimeRemap
+          ? new Date(this.endTimeRemap)
+          : new Date()
+        this[type].timestamp = this.endTimeRemap
+          ? this.endTimeRemap
+          : Date.now()
+      }
+      // this[type].currentDate = new Date()
+      // this[type].timestamp = Date.now()
+      this.startSyncValue()
+    },
+    resetPopup(type) {
+      this.resetPicker(type)
+      this.popupState(type, false)
+      this.onChange()
+    },
+    confirmPicker(type) {
+      this.setInputState(type)
+      this.popupState(type, false)
+      if (type === 'start') {
+        // 如果结束时间为空,则弹出结束时间选择
+        if (!this.end.value) {
+          this.popupShow.end = true
+        }
+      }
+      this.startSyncValue()
+      this.onChange()
+    },
+    onChange() {
+      const value = this.getState()
+      // if (this.debug) {
+      //   console.table({
+      //     start: dateFormatter(value.start),
+      //     end: dateFormatter(value.end)
+      //   })
+      // }
+      const payload = {
+        value
+      }
+      if (this.isIOS) {
+        EventBus.trigger('dateTime:popup:change')
+      }
+      this.$emit('change', payload)
+    },
+    getState() {
+      const start = this.start.value ? this.start.valueStamp : ''
+      const end = this.end.value ? this.end.valueStamp : ''
+
+      const startValue = dayjs(start).startOf('day').valueOf() // 取当天0点时间戳
+      const endValue = dayjs(end).endOf('day').valueOf() // 取当天23:59:59时间戳
+
+      return {
+        start: isNaN(startValue) ? 0 : startValue,
+        end: isNaN(endValue) ? 0 : endValue
+      }
+    },
+    setState(data) {
+      if (data.start) {
+        this.start.currentDate = new Date(data.start)
+        this.setInputState('start')
+      } else {
+        const { start } = this.$options.data()
+        Object.assign(this.start, start)
+      }
+      if (data.end) {
+        this.end.currentDate = new Date(data.end)
+        this.setInputState('end')
+      } else {
+        const { end } = this.$options.data()
+        Object.assign(this.end, end)
+      }
+      this.startSyncValue()
+    }
+  }
+}
+</script>
+
+<style lang="scss">
+.date-time-button-group {}
+</style>

+ 128 - 74
src/components/selector/date-time-group/index.vue

@@ -18,88 +18,91 @@
       @click="clickField('end')"
       :readonly="true"
     />
-    <van-popup
-      v-model="popupShow.start"
-      round
-      class="date-time-select-popup"
-      :position="popup.position"
-      :safe-area-inset-bottom="true"
-      get-container="body"
-      :style="popup.style"
-    >
-      <PopupLayout
-        title="请选择开始时间"
-        @closeIconClick="popupShow.start = false"
+    <template v-if="!isIOS">
+      <van-popup
+        v-model="popupShow.start"
+        round
+        class="date-time-select-popup"
+        :position="popup.position"
+        :safe-area-inset-bottom="true"
+        get-container="body"
+        :style="popup.style"
       >
-        <div slot="default">
-          <van-datetime-picker
-            class="date-time-picker highlight-active"
-            ref="startDateTimePicker"
-            v-model="start.currentDate"
-            :key="start.timestamp + 'start'"
-            :show-toolbar="picker.showToolBar"
-            :swipe-duration="picker.swipeDuration"
-            :type="picker.type"
-            :min-date="start.minDate"
-            :max-date="start.maxDate"
-            :formatter="formatter"
-          />
-        </div>
-        <div slot="footer" class="j-button-group height40">
-          <button class="j-button-cancel" @click="resetPopup('start')">
-            重置
-          </button>
-          <button class="j-button-confirm" @click="confirmPicker('start')">
-            确定
-          </button>
-        </div>
-      </PopupLayout>
-    </van-popup>
-    <van-popup
-      v-model="popupShow.end"
-      round
-      class="date-time-select-popup"
-      :position="popup.position"
-      :safe-area-inset-bottom="true"
-      get-container="body"
-      :style="popup.style"
-    >
-      <PopupLayout
-        title="请选择结束时间"
-        @closeIconClick="popupShow.end = false"
+        <PopupLayout
+          title="请选择开始时间"
+          @closeIconClick="popupShow.start = false"
+        >
+          <div slot="default">
+            <van-datetime-picker
+              class="date-time-picker highlight-active"
+              ref="startDateTimePicker"
+              v-model="start.currentDate"
+              :key="start.timestamp + 'start'"
+              :show-toolbar="picker.showToolBar"
+              :swipe-duration="picker.swipeDuration"
+              :type="picker.type"
+              :min-date="start.minDate"
+              :max-date="start.maxDate"
+              :formatter="formatter"
+            />
+          </div>
+          <div slot="footer" class="j-button-group height40">
+            <button class="j-button-cancel" @click="resetPopup('start')">
+              重置
+            </button>
+            <button class="j-button-confirm" @click="confirmPicker('start')">
+              确定
+            </button>
+          </div>
+        </PopupLayout>
+      </van-popup>
+      <van-popup
+        v-model="popupShow.end"
+        round
+        class="date-time-select-popup"
+        :position="popup.position"
+        :safe-area-inset-bottom="true"
+        get-container="body"
+        :style="popup.style"
       >
-        <div slot="default">
-          <van-datetime-picker
-            class="date-time-picker highlight-active"
-            ref="endDateTimePicker"
-            v-model="end.currentDate"
-            :key="end.timestamp + 'end'"
-            :show-toolbar="picker.showToolBar"
-            :swipe-duration="picker.swipeDuration"
-            :type="picker.type"
-            :min-date="end.minDate"
-            :max-date="end.maxDate"
-            :formatter="formatter"
-          />
-        </div>
-        <div slot="footer" class="j-button-group height40">
-          <button class="j-button-cancel" @click="resetPopup('end')">
-            重置
-          </button>
-          <button class="j-button-confirm" @click="confirmPicker('end')">
-            确定
-          </button>
-        </div>
-      </PopupLayout>
-    </van-popup>
+        <PopupLayout
+          title="请选择结束时间"
+          @closeIconClick="popupShow.end = false"
+        >
+          <div slot="default">
+            <van-datetime-picker
+              class="date-time-picker highlight-active"
+              ref="endDateTimePicker"
+              v-model="end.currentDate"
+              :key="end.timestamp + 'end'"
+              :show-toolbar="picker.showToolBar"
+              :swipe-duration="picker.swipeDuration"
+              :type="picker.type"
+              :min-date="end.minDate"
+              :max-date="end.maxDate"
+              :formatter="formatter"
+            />
+          </div>
+          <div slot="footer" class="j-button-group height40">
+            <button class="j-button-cancel" @click="resetPopup('end')">
+              重置
+            </button>
+            <button class="j-button-confirm" @click="confirmPicker('end')">
+              确定
+            </button>
+          </div>
+        </PopupLayout>
+      </van-popup>
+    </template>
   </div>
 </template>
 <script>
 import PopupLayout from '@/components/common/PopupLayout'
 import { DatetimePicker, Popup } from 'vant'
 import { inputDiv } from '@/ui/'
-import { dateFormatter } from '@/utils/'
+import { dateFormatter, getDeviceInfo } from '@/utils/'
 import dayjs from 'dayjs'
+import EventBus from '@/utils/event'
 
 export default {
   name: 'DateTimeGroup',
@@ -162,7 +165,9 @@ export default {
       popupShow: {
         start: false,
         end: false
-      }
+      },
+      isIOS: true,
+      deviceInfo: {},
     }
   },
   computed: {
@@ -174,7 +179,51 @@ export default {
       }
     }
   },
+  created() {
+    this.calcPlatform()
+    if (this.isIOS) {
+      this.registerEventBus()
+    }
+  },
   methods: {
+    calcPlatform() {
+      this.deviceInfo = getDeviceInfo()
+      const system = this.deviceInfo.system
+      if (system) {
+        this.isIOS = system.toLowerCase().includes('ios')
+        console.log('是否ios',this.isIOS)
+      }
+    },
+    registerEventBus() {
+      // 先移除监听
+      EventBus.off('dateTime:popup:sendValueToGroup')
+      EventBus.off('dateTime:popup:change')
+
+      EventBus.on('dateTime:popup:sendValueToGroup', (payload) => {
+        const { start, end, popupShow } = payload
+        Object.assign(this.start, start)
+        Object.assign(this.end, end)
+        Object.assign(this.popupShow, popupShow)
+      })
+      EventBus.on('dateTime:popup:change', () => {
+        this.onChange()
+      })
+    },
+    // 同步数据
+    sendValueToPopup() {
+      const payload = {
+        start: this.start,
+        end: this.end,
+        popupShow: this.popupShow,
+      }
+      EventBus.trigger('dateTime:popup:sendValueToPopup', payload)
+    },
+    startSyncValue() {
+      if (this.isIOS) {
+        this.registerEventBus() // 重新监听,兼容页面同时存在多组DateTimeGroup的情况
+        this.sendValueToPopup()
+      }
+    },
     formatter(type, val) {
       if (type === 'year') {
         return val + '年'
@@ -199,9 +248,11 @@ export default {
       } else if (type === 'end') {
         this.start.maxDate = this.end.currentDate
       }
+      this.startSyncValue()
     },
     popupState(type, state) {
       this.popupShow[type] = state
+      this.startSyncValue()
     },
     resetAll() {
       this.resetPicker('start')
@@ -242,6 +293,7 @@ export default {
       }
       // this[type].currentDate = new Date()
       // this[type].timestamp = Date.now()
+      this.startSyncValue()
     },
     resetPopup(type) {
       this.resetPicker(type)
@@ -257,6 +309,7 @@ export default {
           this.popupShow.end = true
         }
       }
+      this.startSyncValue()
       this.onChange()
     },
     onChange() {
@@ -299,6 +352,7 @@ export default {
         const { end } = this.$options.data()
         Object.assign(this.end, end)
       }
+      this.startSyncValue()
     }
   }
 }

+ 5 - 0
src/utils/event/index.js

@@ -0,0 +1,5 @@
+import Taro, { Events } from '@tarojs/taro'
+
+const events = new Events()
+
+export default events

+ 4 - 0
src/utils/taro.js

@@ -1,6 +1,10 @@
 import Taro from '@tarojs/taro'
 import { GLOBAL_STATE_LISTEN_NAME } from "@/data/constant";
 
+export function getDeviceInfo() {
+  return Taro.getDeviceInfo()
+}
+
 export function callPhone (phone) {
   Taro.makePhoneCall({
     phoneNumber: phone