style:设备维修/点检任务/点检记录-筛选框优化

master
黄伟杰 1 day ago
parent 55dfe8ac4d
commit d2ce549c2a

@ -90,22 +90,19 @@
<text class="drawer-title">{{ t('equipmentInspectionRecord.moreFilter') }}</text>
</view>
<scroll-view scroll-y class="drawer-body">
<view class="drawer-section">
<view class="drawer-section-head">
<text class="drawer-section-title">{{ t('equipmentInspectionRecord.filterScope') }}</text>
</view>
<view class="drawer-field drawer-field-wide">
<view class="drawer-section drawer-fields">
<view class="drawer-field">
<text class="drawer-label">{{ t('equipmentInspectionRecord.taskType') }}</text>
<picker mode="selector" :range="taskTypeLabels" :value="taskTypeIndex" @change="onTaskTypeChange">
<picker class="drawer-picker-host" mode="selector" :range="taskTypeLabels" :value="taskTypeIndex" @change="onTaskTypeChange">
<view class="drawer-picker">
<text :class="['drawer-picker-text', selectedTaskType === '' ? 'placeholder' : '']">{{ currentTaskTypeLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
</picker>
</view>
<view class="drawer-field drawer-field-wide drawer-field-gap">
<view class="drawer-field">
<text class="drawer-label">{{ t('equipmentInspectionRecord.jobResult') }}</text>
<picker mode="selector" :range="jobResultLabels" :value="jobResultIndex" @change="onJobResultChange">
<picker class="drawer-picker-host" mode="selector" :range="jobResultLabels" :value="jobResultIndex" @change="onJobResultChange">
<view class="drawer-picker">
<text :class="['drawer-picker-text', selectedJobResult === '' ? 'placeholder' : '']">{{ currentJobResultLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
@ -197,8 +194,8 @@ const jobStatusOptions = computed(() => {
.map((item) => ({ label: item.label, value: String(item.value) }))
})
const jobResultOptions = computed(() => [
{ label: t('equipmentInspectionRecord.jobResultOk'), value: 'OK' },
{ label: t('equipmentInspectionRecord.jobResultNg'), value: 'NG' }
{ label: t('equipmentInspectionRecord.jobResultOk'), value: '1' },
{ label: t('equipmentInspectionRecord.jobResultNg'), value: '2' }
])
const taskTypeLabels = computed(() => taskTypeOptions.value.map((item) => item.label))
@ -584,15 +581,15 @@ function formatDateTime(value) {
.drawer-header { height: 104rpx; padding: 18rpx 34rpx 0; background: #ffffff; display: flex; align-items: center; box-sizing: border-box; }
.drawer-title { color: #1f2937; font-size: 34rpx; line-height: 1.3; font-weight: 700; }
.drawer-body { flex: 1; min-height: 0; padding-bottom: 40rpx; box-sizing: border-box; }
.drawer-section { margin-bottom: 18rpx; padding: 28rpx 28rpx 30rpx; border-radius: 24rpx; background: #ffffff; box-sizing: border-box; }
.drawer-section-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 24rpx; }
.drawer-section-title { font-size: 32rpx; line-height: 1.3; color: #1f2937; font-weight: 700; }
.drawer-field { min-width: 0; }
.drawer-field-wide { grid-column: 1 / -1; }
.drawer-field-gap { margin-top: 22rpx; }
.drawer-label { display: block; margin-bottom: 12rpx; font-size: 24rpx; line-height: 1.3; color: #4b5563; font-weight: 500; }
.drawer-picker { width: 100%; min-height: 74rpx; border: 0; border-radius: 8rpx; background: #f7f8fb; box-sizing: border-box; display: flex; align-items: center; justify-content: center; padding: 0 18rpx; gap: 8rpx; }
.drawer-picker-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 26rpx; color: #111827; text-align: center; }
.drawer-section { margin-bottom: 18rpx; padding: 8rpx 28rpx; border-radius: 24rpx; background: #ffffff; box-sizing: border-box; }
.drawer-fields { display: flex; flex-direction: column; }
.drawer-field { min-width: 0; min-height: 98rpx; display: flex; align-items: center; gap: 20rpx; border-bottom: 1rpx solid #eceff3; box-sizing: border-box; }
.drawer-field:last-child { border-bottom: 0; }
.drawer-field-wide { grid-column: auto; }
.drawer-label { width: 160rpx; flex: 0 0 160rpx; font-size: 24rpx; line-height: 1.3; color: #4b5563; font-weight: 500; }
.drawer-picker-host { min-width: 0; flex: 1; display: block; }
.drawer-picker { width: 100%; min-height: 74rpx; border: 0; border-radius: 8rpx; background: #f7f8fb; box-sizing: border-box; display: flex; align-items: center; justify-content: flex-end; padding: 0 18rpx; gap: 8rpx; }
.drawer-picker-text { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 26rpx; color: #111827; text-align: right; }
.drawer-picker-text.placeholder { color: #9ca3af; }
.drawer-actions { height: 126rpx; padding: 18rpx 28rpx 24rpx; box-sizing: border-box; display: flex; align-items: center; gap: 0; background: #ffffff; box-shadow: 0 -8rpx 24rpx rgba(17, 24, 39, 0.06); }
.drawer-action { flex: 1; height: 72rpx; display: flex; align-items: center; justify-content: center; font-size: 28rpx; font-weight: 600; border: 2rpx solid #174b78; box-sizing: border-box; }

@ -85,37 +85,24 @@
<text class="drawer-title">{{ t('equipmentInspectionTasks.moreFilter') }}</text>
</view>
<scroll-view scroll-y class="drawer-body">
<view class="drawer-section">
<view class="drawer-section-head">
<text class="drawer-section-title">{{ t('equipmentInspectionTasks.filterScope') }}</text>
</view>
<view class="drawer-field drawer-field-wide">
<view class="drawer-section drawer-fields">
<view class="drawer-field">
<text class="drawer-label">{{ t('equipmentInspectionTasks.projectFormName') }}</text>
<view class="drawer-picker" @click="togglePlanPanel">
<text :class="['drawer-picker-text', selectedPlanIds.length ? '' : 'placeholder']">{{ selectedPlanLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
<scroll-view v-if="planPanelOpen" scroll-y class="drawer-option-panel">
<view v-for="option in drawerPlanOptions" :key="option.id" :class="['drawer-option-item', selectedPlanIds.includes(String(option.id)) ? 'active' : '']" @click="togglePlanOption(option)">
<text class="drawer-option-text">{{ option.name }}</text>
<uni-icons v-if="selectedPlanIds.includes(String(option.id))" type="checkmarkempty" size="18" color="#174b78"></uni-icons>
<picker class="drawer-picker-host" mode="selector" :range="planPickerOptions" range-key="label" :value="planPickerIndex" @change="onPlanPickerChange">
<view class="drawer-picker">
<text :class="['drawer-picker-text', selectedPlanIds.length ? '' : 'placeholder']">{{ selectedPlanLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
<view v-if="!drawerPlanOptions.length" class="drawer-option-empty">{{ t('equipmentInspectionTasks.noPlanData') }}</view>
</scroll-view>
</picker>
</view>
<view class="drawer-field drawer-field-wide drawer-field-gap">
<view class="drawer-field">
<text class="drawer-label">{{ t('equipmentInspectionTasks.deviceList') }}</text>
<view class="drawer-picker" @click="toggleDevicePanel">
<text :class="['drawer-picker-text', selectedDeviceIds.length ? '' : 'placeholder']">{{ selectedDeviceLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
<scroll-view v-if="devicePanelOpen" scroll-y class="drawer-option-panel">
<view v-for="option in drawerDeviceOptions" :key="option.id" :class="['drawer-option-item', selectedDeviceIds.includes(String(option.id)) ? 'active' : '']" @click="toggleDeviceOption(option)">
<text class="drawer-option-text">{{ option.label }}</text>
<uni-icons v-if="selectedDeviceIds.includes(String(option.id))" type="checkmarkempty" size="18" color="#174b78"></uni-icons>
<picker class="drawer-picker-host" mode="selector" :range="devicePickerOptions" range-key="label" :value="devicePickerIndex" @change="onDevicePickerChange">
<view class="drawer-picker">
<text :class="['drawer-picker-text', selectedDeviceIds.length ? '' : 'placeholder']">{{ selectedDeviceLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
<view v-if="!drawerDeviceOptions.length" class="drawer-option-empty">{{ t('equipmentInspectionTasks.noDeviceData') }}</view>
</scroll-view>
</picker>
</view>
</view>
</scroll-view>
@ -160,8 +147,6 @@ const selectedTaskType = ref('')
const selectedPlanIds = ref([])
const selectedDeviceIds = ref([])
const planOptions = ref([])
const planPanelOpen = ref(false)
const devicePanelOpen = ref(false)
const filterPopupRef = ref(null)
const list = ref([])
const loading = ref(false)
@ -226,7 +211,22 @@ const drawerDeviceOptions = computed(() => deviceOptions.value.map((item) => ({
const selectedPlanLabel = computed(() => formatSelectedSummary(selectedPlanIds.value, drawerPlanOptions.value, 'name', t('equipmentInspectionTasks.placeholderProjectForm')))
const selectedDeviceLabel = computed(() => formatSelectedSummary(selectedDeviceIds.value, drawerDeviceOptions.value, 'label', t('equipmentInspectionTasks.placeholderDeviceList')))
const planPickerOptions = computed(() => [
{ id: '', label: t('functionCommon.all') },
...drawerPlanOptions.value.map((item) => ({
id: item.id,
label: formatPickerOptionLabel(selectedPlanIds.value, item.id, item.name)
}))
])
const devicePickerOptions = computed(() => [
{ id: '', label: t('functionCommon.all') },
...drawerDeviceOptions.value.map((item) => ({
id: item.id,
label: formatPickerOptionLabel(selectedDeviceIds.value, item.id, item.label)
}))
])
const planPickerIndex = computed(() => getPickerIndex(planPickerOptions.value, selectedPlanIds.value))
const devicePickerIndex = computed(() => getPickerIndex(devicePickerOptions.value, selectedDeviceIds.value))
onLoad(async () => {
activateKeywordFocus()
await Promise.all([loadLineTree(), ensurePlanOptionsLoaded(), ensureDeviceOptionsLoaded()])
@ -411,28 +411,26 @@ function closeFilterDrawer() {
}
async function confirmFilterDrawer() {
planPanelOpen.value = false
devicePanelOpen.value = false
closeFilterDrawer()
await fetchList(true)
}
function togglePlanPanel() {
planPanelOpen.value = !planPanelOpen.value
devicePanelOpen.value = false
function onPlanPickerChange(event) {
handleMultiPickerChange(planPickerOptions.value, selectedPlanIds, event)
}
function toggleDevicePanel() {
devicePanelOpen.value = !devicePanelOpen.value
planPanelOpen.value = false
function onDevicePickerChange(event) {
handleMultiPickerChange(devicePickerOptions.value, selectedDeviceIds, event)
}
function togglePlanOption(option) {
toggleStringSelection(selectedPlanIds, option?.id)
}
function toggleDeviceOption(option) {
toggleStringSelection(selectedDeviceIds, option?.id)
function handleMultiPickerChange(options, targetRef, event) {
const index = Number(event?.detail?.value || 0)
const option = options[index]
if (!option || option.id === '') {
targetRef.value = []
return
}
toggleStringSelection(targetRef, option.id)
}
function toggleStringSelection(targetRef, value) {
@ -442,6 +440,18 @@ function toggleStringSelection(targetRef, value) {
targetRef.value = current.includes(id) ? current.filter((item) => item !== id) : [...current, id]
}
function getPickerIndex(options, selectedIds) {
const selected = Array.isArray(selectedIds) ? selectedIds.map((item) => String(item)) : []
if (!selected.length) return 0
const index = options.findIndex((item) => selected.includes(String(item.id)))
return index >= 0 ? index : 0
}
function formatPickerOptionLabel(selectedIds, id, label) {
const selected = (Array.isArray(selectedIds) ? selectedIds : []).map((item) => String(item))
return `${selected.includes(String(id)) ? '[x]' : '[ ]'} ${label}`
}
function formatSelectedSummary(ids, options, labelKey, placeholder) {
const selected = Array.isArray(ids) ? ids : []
if (!selected.length) return placeholder
@ -471,8 +481,6 @@ async function resetFilters() {
selectedTaskType.value = ''
selectedPlanIds.value = []
selectedDeviceIds.value = []
planPanelOpen.value = false
devicePanelOpen.value = false
closeFilterDrawer()
resetLineFilter()
activateKeywordFocus()
@ -626,23 +634,16 @@ function formatDate(value) {
.drawer-header { height: 104rpx; padding: 18rpx 34rpx 0; background: #ffffff; display: flex; align-items: center; box-sizing: border-box; }
.drawer-title { color: #1f2937; font-size: 34rpx; line-height: 1.3; font-weight: 700; }
.drawer-body { flex: 1; min-height: 0; padding-bottom: 40rpx; box-sizing: border-box; }
.drawer-section { margin-bottom: 18rpx; padding: 28rpx 28rpx 30rpx; border-radius: 24rpx; background: #ffffff; box-sizing: border-box; }
.drawer-section-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 24rpx; }
.drawer-section-title { font-size: 32rpx; line-height: 1.3; color: #1f2937; font-weight: 700; }
.drawer-field { min-width: 0; }
.drawer-field-wide { grid-column: 1 / -1; }
.drawer-field-gap { margin-top: 22rpx; }
.drawer-label { display: block; margin-bottom: 12rpx; font-size: 24rpx; line-height: 1.3; color: #4b5563; font-weight: 500; }
.drawer-picker { width: 100%; min-height: 74rpx; border: 0; border-radius: 8rpx; background: #f7f8fb; box-sizing: border-box; display: flex; align-items: center; justify-content: center; padding: 0 18rpx; gap: 8rpx; }
.drawer-picker-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 26rpx; color: #111827; text-align: center; }
.drawer-section { margin-bottom: 18rpx; padding: 8rpx 28rpx; border-radius: 24rpx; background: #ffffff; box-sizing: border-box; }
.drawer-fields { display: flex; flex-direction: column; }
.drawer-field { min-width: 0; min-height: 98rpx; display: flex; align-items: center; gap: 20rpx; border-bottom: 1rpx solid #eceff3; box-sizing: border-box; }
.drawer-field:last-child { border-bottom: 0; }
.drawer-field-wide { grid-column: auto; }
.drawer-label { width: 160rpx; flex: 0 0 160rpx; font-size: 24rpx; line-height: 1.3; color: #4b5563; font-weight: 500; }
.drawer-picker-host { min-width: 0; flex: 1; display: block; }
.drawer-picker { width: 100%; min-height: 74rpx; border: 0; border-radius: 8rpx; background: #f7f8fb; box-sizing: border-box; display: flex; align-items: center; justify-content: flex-end; padding: 0 18rpx; gap: 8rpx; }
.drawer-picker-text { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 26rpx; color: #111827; text-align: right; }
.drawer-picker-text.placeholder { color: #9ca3af; }
.drawer-option-panel { max-height: 420rpx; margin-top: 12rpx; border-radius: 12rpx; background: #f7f8fb; overflow: hidden; }
.drawer-option-item { min-height: 72rpx; padding: 0 24rpx; display: flex; align-items: center; gap: 12rpx; border-bottom: 1rpx solid #eceff3; box-sizing: border-box; }
.drawer-option-item:last-child { border-bottom: 0; }
.drawer-option-item.active { background: rgba(23, 75, 120, 0.1); }
.drawer-option-item.active .drawer-option-text { color: #174b78; font-weight: 600; }
.drawer-option-text { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 26rpx; color: #1f2937; }
.drawer-option-empty { padding: 28rpx 0; text-align: center; font-size: 26rpx; color: #9ca3af; }
.drawer-actions { height: 126rpx; padding: 18rpx 28rpx 24rpx; box-sizing: border-box; display: flex; align-items: center; gap: 0; background: #ffffff; box-shadow: 0 -8rpx 24rpx rgba(17, 24, 39, 0.06); }
.drawer-action { flex: 1; height: 72rpx; display: flex; align-items: center; justify-content: center; font-size: 28rpx; font-weight: 600; border: 2rpx solid #174b78; box-sizing: border-box; }
.drawer-action.reset { border-radius: 12rpx 0 0 12rpx; background: #ffffff; color: #174b78; }

@ -103,39 +103,28 @@
<text class="drawer-title">{{ t('equipmentMaintenance.moreFilter') }}</text>
</view>
<scroll-view scroll-y class="drawer-body">
<view class="drawer-section">
<view class="drawer-section-head">
<text class="drawer-section-title">{{ t('equipmentMaintenance.basicInfo') }}</text>
<view class="drawer-section drawer-fields">
<view class="drawer-field">
<text class="drawer-label">{{ t('equipmentMaintenance.repairName') }}</text>
<input
v-model="repairNameFilter"
class="drawer-input"
type="text"
:placeholder="t('equipmentMaintenance.placeholderRepairName')"
/>
</view>
<view class="drawer-grid">
<view class="drawer-field">
<text class="drawer-label">{{ t('equipmentMaintenance.repairName') }}</text>
<input
v-model="repairNameFilter"
class="drawer-input"
type="text"
:placeholder="t('equipmentMaintenance.placeholderRepairName')"
/>
</view>
<view class="drawer-field">
<text class="drawer-label">{{ t('equipmentMaintenance.acceptedBy') }}</text>
<input
v-model="acceptedByFilter"
class="drawer-input"
type="text"
:placeholder="t('equipmentMaintenance.placeholderAcceptedBy')"
/>
</view>
<view class="drawer-field">
<text class="drawer-label">{{ t('equipmentMaintenance.acceptedBy') }}</text>
<input
v-model="acceptedByFilter"
class="drawer-input"
type="text"
:placeholder="t('equipmentMaintenance.placeholderAcceptedBy')"
/>
</view>
</view>
<view class="drawer-section">
<view class="drawer-section-head">
<text class="drawer-section-title">{{ t('equipmentMaintenance.statusFilter') }}</text>
</view>
<view class="drawer-field drawer-field-wide">
<view class="drawer-field">
<text class="drawer-label">{{ t('equipmentMaintenance.status') }}</text>
<picker :range="documentStatusLabels" :value="documentStatusPickerIndex" @change="onDocumentStatusChange">
<picker class="drawer-picker-host" :range="documentStatusLabels" :value="documentStatusPickerIndex" @change="onDocumentStatusChange">
<view class="drawer-picker">
<text :class="['drawer-picker-text', selectedDocumentStatus === '' ? 'placeholder' : '']">
{{ selectedDocumentStatusLabel }}
@ -144,13 +133,7 @@
</view>
</picker>
</view>
</view>
<view class="drawer-section">
<view class="drawer-section-head">
<text class="drawer-section-title">{{ t('equipmentMaintenance.dateFilter') }}</text>
</view>
<view class="drawer-field drawer-field-wide">
<view class="drawer-field">
<text class="drawer-label">{{ t('equipmentMaintenance.requireDate') }}</text>
<view class="drawer-date">
<uni-datetime-picker
@ -162,7 +145,7 @@
/>
</view>
</view>
<view class="drawer-field drawer-field-wide drawer-field-gap">
<view class="drawer-field">
<text class="drawer-label">{{ t('equipmentMaintenance.finishDate') }}</text>
<view class="drawer-date">
<uni-datetime-picker
@ -174,7 +157,7 @@
/>
</view>
</view>
<view class="drawer-field drawer-field-wide drawer-field-gap">
<view class="drawer-field">
<text class="drawer-label">{{ t('equipmentMaintenance.confirmDate') }}</text>
<view class="drawer-date">
<uni-datetime-picker
@ -799,56 +782,55 @@ function textValue(value) {
.drawer-section {
margin-bottom: 18rpx;
padding: 28rpx 28rpx 30rpx;
padding: 8rpx 28rpx;
border-radius: 24rpx;
background: #ffffff;
box-sizing: border-box;
}
.drawer-section-head {
.drawer-fields {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 24rpx;
}
.drawer-section-title {
font-size: 32rpx;
line-height: 1.3;
color: #1f2937;
font-weight: 700;
}
.drawer-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 22rpx 20rpx;
flex-direction: column;
}
.drawer-field {
min-width: 0;
min-height: 98rpx;
display: flex;
align-items: center;
gap: 20rpx;
border-bottom: 1rpx solid #eceff3;
box-sizing: border-box;
}
.drawer-field-wide {
grid-column: 1 / -1;
.drawer-field:last-child {
border-bottom: 0;
}
.drawer-field-gap {
margin-top: 22rpx;
.drawer-field-wide {
grid-column: auto;
}
.drawer-label {
display: block;
margin-bottom: 12rpx;
width: 160rpx;
flex: 0 0 160rpx;
font-size: 24rpx;
line-height: 1.3;
color: #4b5563;
font-weight: 500;
}
.drawer-picker-host {
min-width: 0;
flex: 1;
display: block;
}
.drawer-input,
.drawer-picker,
.drawer-date {
min-width: 0;
flex: 1;
width: 100%;
min-height: 74rpx;
border: 0;
@ -862,25 +844,26 @@ function textValue(value) {
padding: 0 18rpx;
font-size: 26rpx;
color: #111827;
text-align: center;
text-align: right;
}
.drawer-picker {
display: flex;
align-items: center;
justify-content: center;
justify-content: flex-end;
padding: 0 18rpx;
gap: 8rpx;
}
.drawer-picker-text {
min-width: 0;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 26rpx;
color: #111827;
text-align: center;
text-align: right;
}
.drawer-picker-text.placeholder {
@ -892,7 +875,6 @@ function textValue(value) {
align-items: center;
padding: 0 12rpx;
}
.drawer-date :deep(.uni-date),
.drawer-date :deep(.uni-date-editor),
.drawer-date :deep(.uni-date-editor--x),

Loading…
Cancel
Save