TimeSelect.vue 6.26 KB
<template>
  <view class="time-select">
    <!-- 触发器部分 -->
    <view class="time-trigger" @click="openPopup">
      <view class="setting-item">
        <view class="setting-left">
          <text class="setting-title">{{ title }}</text>
        </view>
        <view class="setting-right">
          <text class="time-text">{{ selectedTime }}</text>
          <uv-icon name="arrow-right" color="#90949D" size="28rpx" />
        </view>
      </view>
    </view>

    <!-- 弹出层 -->
    <uv-popup ref="timeSelectRef" mode="bottom" @close="closePopup" round="10" safe-area-inset-bottom>
      <view class="time-picker-container">
        <view class="time-picker-header">
          <text class="cancel-btn" @click="closePopup">{{ t('button.cancel') }}</text>
          <!-- <text class="title-text">{{ title }}</text> -->
          <text class="confirm-btn" @click="confirmSelect">{{ t("message.confirm") }}</text>
        </view>
        
        <view class="picker-view-wrapper">
          <picker-view class="time-picker-view" :value="pickerValue" @change="onPickerChange" :indicator-style="indicatorStyle">
            <picker-view-column>
              <view class="picker-item" v-for="(hour, index) in hours" :key="'hour-'+index">
                <text class="picker-text">{{ hour }}</text>
              </view>
            </picker-view-column>
            <picker-view-column>
              <view class="picker-item" v-for="(minute, index) in minutes" :key="'minute-'+index">
                <text class="picker-text">{{ minute }}</text>
              </view>
            </picker-view-column>
          </picker-view>
        </view>
      </view>
    </uv-popup>
  </view>
</template>

<script setup>
import { ref, computed, onMounted, watch } from 'vue';
import { t } from '@/plugins/index.js';

// Props
const props = defineProps({ 
  title: {
    type: String,
    default: ''
  },
  value: {
    type: String,
    default: '00:00'
  },
  start: {
    type: String,
    default: '00:00'
  },
  end: {
    type: String,
    default: '23:59'
  }
});

// 处理初始值,支持 00:00:00 格式
// const formatInitialValue = (value) => {
//   if (!value) return '00:00';
//   // 如果是 00:00:00 格式,截取前5位
//   if (value.length > 5) {
//     return value.substring(0, 5);
//   }
//   return value;
// };

const emit = defineEmits(['change']);

// 弹出层控制
const timeSelectRef = ref(null);
const openPopup = () => {
  timeSelectRef.value.open();
};
const closePopup = () => {
  timeSelectRef.value.close();
};

// 时间数据
const hours = ref([]);
const minutes = ref([]);
const selectedTime = ref();
const pickerValue = ref([0, 0]);
const indicatorStyle = "height: 40px; border-top: 1px solid #f2f2f2; border-bottom: 1px solid #f2f2f2;";

// 初始化时间数据
onMounted(() => {
  initTimeData();
  initPickerValue();
});

// 初始化小时和分钟数据
const initTimeData = () => {
  // 生成小时数据 (00-23)
  for (let i = 0; i < 24; i++) {
    hours.value.push(i.toString().padStart(2, '0'));
  }
  
  // 生成分钟数据 (00-59)
  for (let i = 0; i < 60; i++) {
    minutes.value.push(i.toString().padStart(2, '0'));
  }
};

// 初始化选择器的值
const initPickerValue = () => {
  if (selectedTime.value) {
    // 处理可能的 00:00:00 格式,支持接口回显
    const timeParts = selectedTime.value.split(':');
    const hour = timeParts[0];
    const minute = timeParts[1];
    pickerValue.value = [parseInt(hour), parseInt(minute)];
  }
};
watch(() => props.value, (newVal) => {
  if (newVal) {
    selectedTime.value = newVal;
    console.log(selectedTime.value,'selectedTime.valu11e');
    initPickerValue();
  }
}, { immediate: true });
// 选择器变化事件
const onPickerChange = (e) => {
  const values = e.detail.value;
  pickerValue.value = values;
};

// 确认选择
const confirmSelect = () => {
  const hour = hours.value[pickerValue.value[0]];
  const minute = minutes.value[pickerValue.value[1]];
  selectedTime.value = `${hour}:${minute}`;
  console.log(selectedTime.value,'selectedTime.value');
  
  emit('change', selectedTime.value);
  closePopup();
};

// // 格式化时间显示,根据语言环境
const formatTimeByLocale = (timeString) => {
  console.log(timeString,'timeString');
  
  // const locale = uni.getLocale();
  // // 如果是英文环境,转换为12小时制
  // if (locale.startsWith('en')) {
  //   const [hours, minutes] = timeString.split(':');
  //   const hour = parseInt(hours, 10);
  //   const period = hour >= 12 ? 'PM' : 'AM';
  //   const hour12 = hour % 12 || 12; // 0点显示为12点
  //   return `${hour12}:${minutes} ${period}`;
  // }
  // 其他语言环境保持24小时制
  return timeString;
};
</script>

<style lang="scss" scoped>
.time-select {
  width: 100%;
}

.time-trigger {
  width: 100%;
}

.setting-item {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  padding: 30rpx 0;
}

.setting-left {
  display: flex;
  flex-direction: column;
}

.setting-title {
  font-size: 28rpx;
  color: #262626;
  font-weight: 500;
}

.setting-right {
  display: flex;
  flex-direction: row;
  align-items: center;
}

.time-text {
  font-size: 28rpx;
  color: #90949d;
}

.arrow-right {
  font-size: 36rpx;
  color: #90949d;
  margin-left: 10rpx;
}

.time-picker-container {
  background-color: #ffffff;
  padding-bottom: 20rpx;
}

.time-picker-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 30rpx;
  border-bottom: 1px solid #f2f2f2;
}

.cancel-btn {
  color: #90949d;
  font-size: 28rpx;
  width: 80rpx;
  text-align: left;
}

.title-text {
  color: #262626;
  font-size: 30rpx;
  font-weight: 500;
  flex: 1;
  text-align: center;
}

.confirm-btn {
  color: #387CF5;
  font-size: 28rpx;
  width: 80rpx;
  text-align: right;
  padding-right: 20rpx;
}

.picker-view-wrapper {
  width: 100%;
  height: 400rpx;
  position: relative;
  padding: 20rpx 0 0 0;
}

.time-picker-view {
  width: 100%;
  height: 400rpx;
}

// 必须用line-height 不然会出问题 真机上 配合indicatorStyle属性
.picker-item {
  display: flex;
  justify-content: center;
  align-items: center;
  line-height:80rpx;
}

.picker-text {
  font-size: 32rpx;
  color: #262626;
  text-align: center;
}

.border-line {
  display: flex;
  justify-content: center;
  align-items: center;
}
</style>