feat:下拉框组件更换,用uniapp官方的

master
黄伟杰 3 weeks ago
parent 853472a7da
commit 6ff98266bc

@ -44,10 +44,12 @@
<view class="rate-trend-section">
<view class="rate-trend-header">
<text class="rate-trend-title">{{ t('deviceOverview.rateTrend') }}</text>
<view class="filter-select" @click="showPeriodPicker = true">
<text class="filter-text">{{ currentPeriodLabel }}</text>
<text class="filter-arrow"></text>
</view>
<picker mode="selector" :range="periodRange" range-key="text" :value="periodIndex" @change="onPeriodChange">
<view class="filter-select">
<text class="filter-text">{{ currentPeriodLabel }}</text>
<text class="filter-arrow"></text>
</view>
</picker>
</view>
<view class="switch-bar">
<view class="switch-item">
@ -80,10 +82,12 @@
<view class="rate-trend-section">
<view class="rate-trend-header">
<text class="rate-trend-title">{{ t('deviceOverview.deviceRateTrend') }}</text>
<view class="filter-select" @click="showDevicePicker = true">
<text class="filter-text">{{ selectedDeviceName || t('deviceOverview.selectDevice') }}</text>
<text class="filter-arrow"></text>
</view>
<picker mode="selector" :range="deviceRange" range-key="text" :value="deviceIndex" @change="onDeviceChange">
<view class="filter-select">
<text class="filter-text">{{ selectedDeviceName || t('deviceOverview.selectDevice') }}</text>
<text class="filter-arrow"></text>
</view>
</picker>
</view>
<view class="device-trend-chart-box" v-if="selectedDeviceId">
<qiun-data-charts type="bar" :chartData="deviceTrendChartData" :canvas2d="false" :opts="deviceTrendChartOpts" />
@ -93,10 +97,6 @@
</view>
</view>
<up-picker :show="showPeriodPicker" :columns="periodColumns" @confirm="onPeriodConfirm"
@cancel="showPeriodPicker = false" @close="showPeriodPicker = false" closeOnClickOverlay />
<up-picker :show="showDevicePicker" :columns="deviceColumns" @confirm="onDeviceConfirm"
@cancel="showDevicePicker = false" @close="showDevicePicker = false" closeOnClickOverlay />
</view>
</template>
@ -118,21 +118,23 @@ const deviceData = reactive({
faultRate: '-'
})
const showPeriodPicker = ref(false)
const currentPeriod = ref('LAST_7_DAYS')
const onlyScheduled = ref(true)
const skipHoliday = ref(false)
const periodColumns = computed(() => [
[
{ text: t('deviceOverview.periodLastWeek'), value: 'LAST_WEEK' },
{ text: t('deviceOverview.periodThisWeek'), value: 'THIS_WEEK' },
{ text: t('deviceOverview.periodLast7Days'), value: 'LAST_7_DAYS' },
{ text: t('deviceOverview.periodLastMonth'), value: 'LAST_MONTH' },
{ text: t('deviceOverview.periodThisMonth'), value: 'THIS_MONTH' }
]
const periodRange = computed(() => [
{ text: t('deviceOverview.periodLastWeek'), value: 'LAST_WEEK' },
{ text: t('deviceOverview.periodThisWeek'), value: 'THIS_WEEK' },
{ text: t('deviceOverview.periodLast7Days'), value: 'LAST_7_DAYS' },
{ text: t('deviceOverview.periodLastMonth'), value: 'LAST_MONTH' },
{ text: t('deviceOverview.periodThisMonth'), value: 'THIS_MONTH' }
])
const periodIndex = computed(() => {
const idx = periodRange.value.findIndex(item => item.value === currentPeriod.value)
return idx >= 0 ? idx : 0
})
const periodLabelMap = computed(() => ({
LAST_WEEK: t('deviceOverview.periodLastWeek'),
THIS_WEEK: t('deviceOverview.periodThisWeek'),
@ -200,15 +202,19 @@ const rankingChartHeight = computed(() => {
return `${count * ITEM_HEIGHT_PX + 30}px`
})
const showDevicePicker = ref(false)
const deviceList = ref([])
const selectedDeviceId = ref(null)
const selectedDeviceName = ref('')
const isInitialLoad = ref(true)
const deviceColumns = computed(() => [
const deviceRange = computed(() =>
deviceList.value.map((d) => ({ text: d.deviceName || d.name || '', value: d.id }))
])
)
const deviceIndex = computed(() => {
const idx = deviceRange.value.findIndex(item => item.value === selectedDeviceId.value)
return idx >= 0 ? idx : 0
})
const deviceTrendChartOpts = {
color: ['#1a3a5c', '#18bc37'],
@ -347,18 +353,20 @@ async function loadDeviceRateTrend() {
]
}
function onDeviceConfirm(e) {
const val = e.value[0]
selectedDeviceId.value = val.value
selectedDeviceName.value = val.text
showDevicePicker.value = false
function onDeviceChange(e) {
const idx = e.detail.value
const item = deviceRange.value[idx]
if (!item) return
selectedDeviceId.value = item.value
selectedDeviceName.value = item.text
loadDeviceRateTrend()
}
function onPeriodConfirm(e) {
const val = e.value[0]?.value || e.value[0]
function onPeriodChange(e) {
const idx = e.detail.value
const val = periodRange.value[idx]?.value
if (!val) return
currentPeriod.value = val
showPeriodPicker.value = false
loadRateTrend()
}

@ -7,27 +7,27 @@
</text>
</view>
<view class="filter-bar">
<view class="filter-select" @click="showFilterPicker = true">
<text class="filter-text">{{ currentFilterLabel }}</text>
<text class="filter-arrow"></text>
</view>
<view class="filter-select" @click="showRangePicker = true">
<text class="filter-text">{{ currentRangeLabel }}</text>
<text class="filter-arrow"></text>
</view>
<picker mode="selector" :range="filterRange" range-key="text" :value="filterIndex" @change="onFilterChange">
<view class="filter-select">
<text class="filter-text">{{ currentFilterLabel }}</text>
<text class="filter-arrow"></text>
</view>
</picker>
<picker mode="selector" :range="rangeRange" range-key="text" :value="rangeIndex" @change="onRangeChange">
<view class="filter-select">
<text class="filter-text">{{ currentRangeLabel }}</text>
<text class="filter-arrow"></text>
</view>
</picker>
</view>
<view v-if="currentRange === 'custom'" class="filter-date-wrap">
<view class="date-picker-item">
<up-icon name="calendar" size="18" color="#999" />
<up-datetime-picker ref="startPickerRef" hasInput v-model="dateRange.start" mode="datetime"
:placeholder="t('dashboard.startDate')" :formatter="datetimeFormatter" closeOnClickOverlay
@confirm="onStartDateConfirm" @close="onPickerClose" @cancel="onPickerClose" />
<uni-datetime-picker v-model="dateRange.start" type="datetime"
:placeholder="t('dashboard.startDate')" @change="onStartDateChange" />
</view>
<view class="date-picker-item">
<up-icon name="calendar" size="18" color="#999" />
<up-datetime-picker ref="endPickerRef" hasInput v-model="dateRange.end" mode="datetime"
:placeholder="t('dashboard.endDate')" :formatter="datetimeFormatter" closeOnClickOverlay
@confirm="onEndDateConfirm" @close="onPickerClose" @cancel="onPickerClose" />
<uni-datetime-picker v-model="dateRange.end" type="datetime"
:placeholder="t('dashboard.endDate')" @change="onEndDateChange" />
</view>
</view>
<view v-if="currentFilter === 'product'" class="trend-content">
@ -92,11 +92,6 @@
</view>
</view>
<up-picker :show="showFilterPicker" :columns="filterColumns" @confirm="onFilterConfirm"
@cancel="showFilterPicker = false" @close="showFilterPicker = false" closeOnClickOverlay />
<up-picker :show="showRangePicker" :columns="rangeColumns" @confirm="onRangeConfirm"
@cancel="showRangePicker = false" @close="showRangePicker = false" closeOnClickOverlay />
</view>
</template>
@ -126,35 +121,37 @@ const passRateChartOpts = {
extra: { line: { type: 'straight', width: 2, activeType: 'hollow' } }
}
const showFilterPicker = ref(false)
const showRangePicker = ref(false)
const startPickerRef = ref(null)
const endPickerRef = ref(null)
const currentFilter = ref('task')
const currentRange = ref('year')
const isInitialLoad = ref(true)
const filterColumns = computed(() => [
[
{ text: t('dashboard.filterTask'), value: 'task' },
{ text: t('dashboard.filterProduct'), value: 'product' }
]
const filterRange = computed(() => [
{ text: t('dashboard.filterTask'), value: 'task' },
{ text: t('dashboard.filterProduct'), value: 'product' }
])
const filterIndex = computed(() => {
const idx = filterRange.value.findIndex(item => item.value === currentFilter.value)
return idx >= 0 ? idx : 0
})
const currentFilterLabel = computed(() => {
return currentFilter.value === 'task' ? t('dashboard.filterTask') : t('dashboard.filterProduct')
})
const rangeColumns = computed(() => [
[
{ text: t('dashboard.rangeYear'), value: 'year' },
{ text: t('dashboard.rangeMonth'), value: 'month' },
{ text: t('dashboard.rangeWeek'), value: 'week' },
{ text: t('dashboard.rangeToday'), value: 'today' },
{ text: t('dashboard.rangeCustom'), value: 'custom' }
]
const rangeRange = computed(() => [
{ text: t('dashboard.rangeYear'), value: 'year' },
{ text: t('dashboard.rangeMonth'), value: 'month' },
{ text: t('dashboard.rangeWeek'), value: 'week' },
{ text: t('dashboard.rangeToday'), value: 'today' },
{ text: t('dashboard.rangeCustom'), value: 'custom' }
])
const rangeIndex = computed(() => {
const idx = rangeRange.value.findIndex(item => item.value === currentRange.value)
return idx >= 0 ? idx : 0
})
const rangeLabelMap = computed(() => ({
year: t('dashboard.rangeYear'),
month: t('dashboard.rangeMonth'),
@ -292,21 +289,11 @@ function transformChartData(dayTrend, rangeType) {
}
}
function formatTimestamp(ts) {
const d = new Date(ts)
const pad = (n) => String(n).padStart(2, '0')
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
}
function datetimeFormatter(type, value) {
const unitMap = { year: '年', month: '月', day: '日', hour: '时', minute: '分' }
return value + (unitMap[type] || '')
}
function onFilterConfirm(e) {
const val = e.value[0]?.value || e.value[0]
function onFilterChange(e) {
const idx = e.detail.value
const val = filterRange.value[idx]?.value
if (!val) return
currentFilter.value = val
showFilterPicker.value = false
if (val === 'product') {
loadTrendData()
} else if (val === 'task') {
@ -314,10 +301,11 @@ function onFilterConfirm(e) {
}
}
function onRangeConfirm(e) {
const val = e.value[0]?.value || e.value[0]
function onRangeChange(e) {
const idx = e.detail.value
const val = rangeRange.value[idx]?.value
if (!val) return
currentRange.value = val
showRangePicker.value = false
if (val !== 'custom') {
const range = getDateRange(val)
dateRange.start = range.start
@ -354,33 +342,20 @@ function clearChartData() {
taskChartData.series = [{ name: t('dashboard.taskTrend'), data: [] }]
}
function onStartDateConfirm(e) {
dateRange.start = formatTimestamp(e.value)
function onStartDateChange(val) {
dateRange.start = val
if (dateRange.start && dateRange.end) {
if (currentFilter.value === 'product') {
loadTrendData()
} else if (currentFilter.value === 'task') {
loadTaskTrendData()
}
loadData()
}
}
function onEndDateConfirm(e) {
dateRange.end = formatTimestamp(e.value)
function onEndDateChange(val) {
dateRange.end = val
if (dateRange.start && dateRange.end) {
if (currentFilter.value === 'product') {
loadTrendData()
} else if (currentFilter.value === 'task') {
loadTaskTrendData()
}
loadData()
}
}
function onPickerClose() {
if (startPickerRef.value) startPickerRef.value.showByClickInput = false
if (endPickerRef.value) endPickerRef.value.showByClickInput = false
}
async function loadTrendData() {
const trendTypeMap = { year: 1, month: 2, week: 3, today: 4, custom: 5 }
const params = { trendType: trendTypeMap[currentRange.value] || 2 }
@ -585,21 +560,20 @@ defineExpose({ loadData })
background: #ffffff;
}
:deep(.u-datetime-picker) {
:deep(.uni-date) {
flex: 1;
width: 100%;
.u-input {
padding-left: 40rpx;
background: transparent;
.uni-date-editor--x {
border: none;
background: transparent;
padding: 0;
}
}
.up-icon {
position: absolute;
left: 12rpx;
z-index: 1;
color: #4a90c2;
.uni-date__x-input {
background: transparent;
font-size: 24rpx;
}
}
}

@ -89,7 +89,7 @@ onUnmounted(() => {
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 24rpx rgba(26, 58, 92, 0.3);
z-index: 999;
z-index: 10;
&:active {
transform: scale(0.95);

Loading…
Cancel
Save