style: 模具点检,保养搜索框样式优化

master
zhongwenkai 2 days ago
parent 2db4fce017
commit 8905d18558

@ -1180,6 +1180,8 @@ export default {
searchPlaceholder: 'Enter inspection No.',
empty: 'No inspection records',
add: 'Add',
basicInfo: 'Basic Info',
jobResult: 'Result',
moldName: 'Mold Name',
moldCode: 'Mold Code',
product: 'Product',
@ -1239,7 +1241,9 @@ export default {
submit: 'Submit Inspection',
submitSuccess: 'Inspection submitted successfully',
submitFailed: 'Failed to submit inspection',
reInspect: 'Re-inspect'
reInspect: 'Re-inspect',
allStatus: 'Job Status',
moreFilter: 'More Filters'
},
moldMaintain: {
moduleName: 'Mold Maintenance',
@ -1248,6 +1252,10 @@ export default {
searchPlaceholder: 'Enter maintenance No.',
empty: 'No maintenance records',
add: 'Add',
allStatus: 'Job Status',
moreFilter: 'More Filters',
basicInfo: 'Basic Info',
jobResult: 'Result',
moldName: 'Mold Name',
moldCode: 'Mold Code',
product: 'Product',

@ -1240,7 +1240,9 @@ export default {
submit: '提交点检',
submitSuccess: '点检提交成功',
submitFailed: '点检提交失败',
reInspect: '再次点检'
reInspect: '再次点检',
allStatus: '作业状态',
moreFilter: '更多筛选'
},
moldMaintain: {
moduleName: '模具保养',
@ -1249,6 +1251,10 @@ export default {
searchPlaceholder: '请输入保养单号',
empty: '暂无保养记录',
add: '新增',
allStatus: '作业状态',
moreFilter: '更多筛选',
basicInfo: '基础信息',
jobResult: '结果',
moldName: '模具名称',
moldCode: '模具编号',
product: '产品',

@ -2,20 +2,35 @@
<view class="page-container">
<NavBar :title="t('moldCheck.moduleName')" />
<view class="filter-bar">
<view class="keyword-box">
<input id="mold-check-keyword-input" v-model="searchKeyword" class="keyword-input" :placeholder="t('moldCheck.searchPlaceholder')"
:focus="keywordFocus" confirm-type="search" @blur="keywordFocus = false" @input="handleKeywordInput"
@confirm="handleSearch" />
</view>
<picker mode="selector" :range="jobStatusLabels" :value="jobStatusIndex" @change="onJobStatusChange">
<view class="status-box">
<text class="status-box-text">{{ currentJobStatusLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
</picker>
<view class="reset-filter-btn" @click="resetFilters">{{ t('functionCommon.reset') }}</view>
<view class="filter-bar">
<view class="filter-row quick-row">
<picker :range="jobStatusLabels" :value="jobStatusIndex" @change="onJobStatusChange">
<view class="status-filter">
<text :class="['status-filter-text', selectedJobStatus === '' ? 'placeholder' : '']">{{ currentJobStatusLabel }}</text>
<uni-icons type="bottom" size="14" color="#a8adb7"></uni-icons>
</view>
</picker>
</view>
<view class="filter-row search-row">
<view class="keyword-wrap">
<input
v-model="searchKeyword"
class="keyword-input"
type="text"
:placeholder="t('moldCheck.searchPlaceholder')"
confirm-type="search"
@input="handleKeywordInput"
@confirm="handleSearch"
/>
</view>
<view class="icon-filter-btn" @click="resetFilters">
<uni-icons type="refresh" size="24" color="#7b8491"></uni-icons>
</view>
<view class="icon-filter-btn" @click="openFilterDrawer">
<uni-icons type="settings" size="24" color="#7b8491"></uni-icons>
</view>
</view>
</view>
<scroll-view scroll-y class="list-scroll" :scroll-top="scrollTop" @scroll="onScroll" @scrolltolower="loadMore"
:lower-threshold="80">
@ -73,12 +88,51 @@
<text class="add-icon">+</text>
</view>
<sv-focus-no-keyboard ref="focusNoKeyboardRef"></sv-focus-no-keyboard>
</view>
<sv-focus-no-keyboard ref="focusNoKeyboardRef"></sv-focus-no-keyboard>
<uni-popup ref="filterPopupRef" class="mold-check-filter-popup" type="right" background-color="transparent" :animation="false">
<view class="filter-drawer">
<view class="drawer-header">
<text class="drawer-title">{{ t('moldCheck.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('moldCheck.basicInfo') }}</text>
</view>
<view class="drawer-grid">
<view class="drawer-field drawer-field-wide">
<text class="drawer-label">{{ t('moldCheck.jobResult') }}</text>
<view class="drawer-picker" @click="toggleJobResultPanel">
<text :class="['drawer-picker-text', !selectedJobResult ? 'placeholder' : '']">{{ selectedJobResultLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
<scroll-view v-if="jobResultPanelOpen" scroll-y class="drawer-option-panel">
<view
v-for="item in jobResultOptions"
:key="item.value"
:class="['drawer-option-item', selectedJobResult === item.value ? 'active' : '']"
@click="selectJobResult(item.value)"
>
<text class="drawer-option-text">{{ item.label }}</text>
<text v-if="selectedJobResult === item.value" class="drawer-option-check"></text>
</view>
</scroll-view>
</view>
</view>
</view>
</scroll-view>
<view class="drawer-actions">
<view class="drawer-action reset" @click="resetFilters">{{ t('functionCommon.reset') }}</view>
<view class="drawer-action confirm" @click="confirmFilterDrawer">{{ t('functionCommon.confirm') }}</view>
</view>
</view>
</uni-popup>
</view>
</template>
<script setup>
import { computed, nextTick, ref } from 'vue'
import { computed, ref, nextTick } from 'vue'
import { onLoad, onReady, onReachBottom, onShow, onUnload } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import NavBar from '@/components/common/NavBar.vue'
@ -88,7 +142,12 @@ import { DICT_TYPE, getDictLabel, initAllDict, useDict } from '@/utils/dict'
const { t } = useI18n()
const searchKeyword = ref('')
const selectedJobStatus = ref('0')
const selectedJobStatus = ref('')
const selectedJobResult = ref('')
const jobResultPanelOpen = ref(false)
const filterPopupRef = ref(null)
const focusNoKeyboardRef = ref(null)
const keywordInputSelector = '.keyword-input input, input.keyword-input'
const list = ref([])
const loading = ref(false)
const loadingMore = ref(false)
@ -97,9 +156,6 @@ const pageNo = ref(1)
const pageSize = ref(10)
const scrollTop = ref(0)
const showGoTop = ref(false)
const keywordFocus = ref(false)
const focusNoKeyboardRef = ref(null)
const keywordInputSelector = '#mold-check-keyword-input input, input#mold-check-keyword-input'
let searchTimer = null
@ -120,8 +176,20 @@ const jobStatusIndex = computed(() => {
return index >= 0 ? index : 0
})
const currentJobStatusLabel = computed(() => {
if (selectedJobStatus.value === '') return t('moldCheck.allStatus')
const current = jobStatusOptions.value.find((item) => item.value === selectedJobStatus.value)
return current ? current.label : t('functionCommon.all')
return current ? current.label : t('moldCheck.allStatus')
})
const jobResultOptions = computed(() => [
{ label: t('moldCheck.jobResultOk'), value: '1' },
{ label: t('moldCheck.jobResultNg'), value: '2' }
])
const selectedJobResultLabel = computed(() => {
if (!selectedJobResult.value) return t('moldCheck.jobResult')
const opt = jobResultOptions.value.find((o) => o.value === selectedJobResult.value)
return opt ? opt.label : t('moldCheck.jobResult')
})
onLoad(async () => {
@ -130,7 +198,11 @@ onLoad(async () => {
})
onReady(() => {
focusKeywordNoKeyboard()
nextTick(() => {
setTimeout(() => {
focusNoKeyboardRef.value?.focus(keywordInputSelector)
}, 200)
})
})
onShow(() => {
@ -176,7 +248,8 @@ async function fetchList(reset) {
pageSize: pageSize.value,
planNo: searchKeyword.value.trim() || undefined,
planType: '1',
jobStatus: selectedJobStatus.value || undefined
jobStatus: selectedJobStatus.value || undefined,
jobResult: selectedJobResult.value || undefined
}
const res = await getMoldCheckPage(params)
const page = normalizePageData(res)
@ -204,12 +277,29 @@ function handleKeywordInput() {
}, 300)
}
function openFilterDrawer() {
filterPopupRef.value?.open()
}
function toggleJobResultPanel() {
jobResultPanelOpen.value = !jobResultPanelOpen.value
}
function selectJobResult(value) {
selectedJobResult.value = value
jobResultPanelOpen.value = false
}
function confirmFilterDrawer() {
filterPopupRef.value?.close()
fetchList(true)
}
async function resetFilters() {
clearSearchTimer()
searchKeyword.value = ''
selectedJobStatus.value = '0'
activateKeywordFocus()
await nextTick()
selectedJobStatus.value = ''
selectedJobResult.value = ''
await fetchList(true)
}
@ -250,21 +340,6 @@ function goTop() {
scrollTop.value = 0
}
function activateKeywordFocus() {
keywordFocus.value = false
nextTick(() => {
keywordFocus.value = true
})
}
function focusKeywordNoKeyboard() {
nextTick(() => {
setTimeout(() => {
focusNoKeyboardRef.value?.focus(keywordInputSelector)
}, 80)
})
}
function clearSearchTimer() {
if (searchTimer) {
clearTimeout(searchTimer)
@ -335,56 +410,288 @@ function formatDateTime(value) {
}
.filter-bar {
padding: 18rpx 14rpx 20rpx;
background: #f3f4f6;
}
.filter-row {
display: flex;
align-items: center;
gap: 12rpx;
padding: 18rpx 4rpx 0rpx;
gap: 18rpx;
}
.keyword-box,
.status-box,
.reset-filter-btn {
min-width:100rpx;
.search-row {
margin-top: 18rpx;
}
.quick-row>picker {
min-width: 0;
flex: 1;
}
.keyword-wrap,
.status-filter,
.icon-filter-btn {
height: 66rpx;
background: #ffffff;
border: 1rpx solid #d9dde5;
background: #ffffff;
box-sizing: border-box;
display: flex;
align-items: center;
}
.keyword-box {
flex: 1;
.keyword-wrap {
min-width: 0;
padding: 0 28rpx;
flex: 1;
display: flex;
align-items: center;
}
.keyword-input {
width: 100%;
font-size: 24rpx;
height: 64rpx;
padding: 0 20rpx;
font-size: 26rpx;
color: #374151;
}
.status-box {
flex-shrink: 0;
.status-filter {
min-width: 0;
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 28rpx;
min-width: 160rpx;
padding: 0 18rpx 0 26rpx;
}
.status-box-text {
font-size: 24rpx;
color: #374151;
min-width: 0;
.status-filter-text {
min-width: 0rpx;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 26rpx;
color: #374151;
}
.status-filter-text.placeholder {
color: #a8adb7;
}
.reset-filter-btn {
.icon-filter-btn {
width: 66rpx;
flex: 0 0 66rpx;
display: flex;
align-items: center;
justify-content: center;
border-color: transparent;
background: transparent;
}
//
::deep(.mold-check-filter-popup.right .uni-popup__content-transition) {
transform: none !important;
}
.filter-drawer {
width: 630rpx;
height: calc(100vh - var(--status-bar-height));
margin-top: var(--status-bar-height);
background: #f5f5f7;
display: flex;
flex-direction: column;
overflow: hidden;
border-radius: 28rpx 0 0 28rpx;
}
.drawer-header {
height: 104rpx;
padding: 18rpx 34rpx 0;
background: #ffffff;
display: flex;
align-items: center;
justify-content: flex-start;
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-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 22rpx 20rpx;
}
.drawer-field {
min-width: 0;
}
.drawer-field-wide {
grid-column: 1 / -1;
}
.drawer-label {
display: block;
margin-bottom: 12rpx;
font-size: 24rpx;
line-height: 1.3;
color: #4b5563;
font-weight: 500;
}
.drawer-input,
.drawer-picker {
width: 100%;
min-height: 74rpx;
border: 0;
border-radius: 8rpx;
background: #f7f8fb;
box-sizing: border-box;
}
.drawer-input {
height: 74rpx;
padding: 0 18rpx;
font-size: 26rpx;
color: #111827;
text-align: center;
}
.drawer-picker {
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-picker-text.placeholder {
color: #9ca3af;
}
.drawer-option-panel {
max-height: 360rpx;
margin-top: 12rpx;
border-radius: 12rpx;
background: #f7f8fb;
overflow: hidden;
}
.drawer-option-item {
min-height: 72rpx;
padding: 0 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
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-check {
flex-shrink: 0;
font-size: 28rpx;
color: #174b78;
margin-left: 16rpx;
}
.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;
}
.drawer-action.confirm {
border-radius: 0 12rpx 12rpx 0;
background: #174b78;
color: #ffffff;
}
.list-scroll {

@ -78,6 +78,8 @@
<text class="go-top-icon"></text>
</view>
<sv-focus-no-keyboard ref="focusNoKeyboardRef"></sv-focus-no-keyboard>
<uni-popup ref="filterPopupRef" class="mold-filter-popup" type="right" background-color="transparent" :animation="false">
<view class="filter-drawer">
<view class="drawer-header">
@ -139,8 +141,8 @@
</template>
<script setup>
import { ref, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { ref, computed, nextTick } from 'vue'
import { onLoad, onReady } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import NavBar from '@/components/common/NavBar.vue'
import { deleteMoldBrand, getMoldBrandPage } from '@/api/mes/mold'
@ -168,6 +170,8 @@ const productPanelOpen = ref(false)
const devicePanelOpen = ref(false)
const scrollTop = ref(0)
const showGoTop = ref(false)
const focusNoKeyboardRef = ref(null)
const keywordInputSelector = '#mold-ledger-keyword-input input, input#mold-ledger-keyword-input'
const statusOptions = computed(() => {
const options = []
@ -206,9 +210,17 @@ const selectedDeviceLabel = computed(() => {
})
onLoad(async () => {
await initAllDict()
await Promise.all([fetchProductOptions(), fetchDeviceOptions()])
await fetchList(true)
await initAllDict()
await Promise.all([fetchProductOptions(), fetchDeviceOptions()])
await fetchList(true)
})
onReady(() => {
nextTick(() => {
setTimeout(() => {
focusNoKeyboardRef.value?.focus(keywordInputSelector)
}, 200)
})
})
async function fetchProductOptions() {

@ -2,20 +2,35 @@
<view class="page-container">
<NavBar :title="t('moldMaintain.moduleName')" />
<view class="filter-bar">
<view class="keyword-box">
<input id="mold-maintain-keyword-input" v-model="searchKeyword" class="keyword-input" :placeholder="t('moldMaintain.searchPlaceholder')"
:focus="keywordFocus" confirm-type="search" @blur="keywordFocus = false" @input="handleKeywordInput"
@confirm="handleSearch" />
</view>
<picker mode="selector" :range="jobStatusLabels" :value="jobStatusIndex" @change="onJobStatusChange">
<view class="status-box">
<text class="status-box-text">{{ currentJobStatusLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
</picker>
<view class="reset-filter-btn" @click="resetFilters">{{ t('functionCommon.reset') }}</view>
<view class="filter-bar">
<view class="filter-row quick-row">
<picker :range="jobStatusLabels" :value="jobStatusIndex" @change="onJobStatusChange">
<view class="status-filter">
<text :class="['status-filter-text', selectedJobStatus === '' ? 'placeholder' : '']">{{ currentJobStatusLabel }}</text>
<uni-icons type="bottom" size="14" color="#a8adb7"></uni-icons>
</view>
</picker>
</view>
<view class="filter-row search-row">
<view class="keyword-wrap">
<input
v-model="searchKeyword"
class="keyword-input"
type="text"
:placeholder="t('moldMaintain.searchPlaceholder')"
confirm-type="search"
@input="handleKeywordInput"
@confirm="handleSearch"
/>
</view>
<view class="icon-filter-btn" @click="resetFilters">
<uni-icons type="refresh" size="24" color="#7b8491"></uni-icons>
</view>
<view class="icon-filter-btn" @click="openFilterDrawer">
<uni-icons type="settings" size="24" color="#7b8491"></uni-icons>
</view>
</view>
</view>
<scroll-view scroll-y class="list-scroll" :scroll-top="scrollTop" @scroll="onScroll" @scrolltolower="loadMore"
:lower-threshold="80">
@ -73,12 +88,51 @@
<text class="add-icon">+</text>
</view>
<sv-focus-no-keyboard ref="focusNoKeyboardRef"></sv-focus-no-keyboard>
</view>
<sv-focus-no-keyboard ref="focusNoKeyboardRef"></sv-focus-no-keyboard>
<uni-popup ref="filterPopupRef" class="mold-maintain-filter-popup" type="right" background-color="transparent" :animation="false">
<view class="filter-drawer">
<view class="drawer-header">
<text class="drawer-title">{{ t('moldMaintain.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('moldMaintain.basicInfo') }}</text>
</view>
<view class="drawer-grid">
<view class="drawer-field drawer-field-wide">
<text class="drawer-label">{{ t('moldMaintain.jobResult') }}</text>
<view class="drawer-picker" @click="toggleJobResultPanel">
<text :class="['drawer-picker-text', !selectedJobResult ? 'placeholder' : '']">{{ selectedJobResultLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
<scroll-view v-if="jobResultPanelOpen" scroll-y class="drawer-option-panel">
<view
v-for="item in jobResultOptions"
:key="item.value"
:class="['drawer-option-item', selectedJobResult === item.value ? 'active' : '']"
@click="selectJobResult(item.value)"
>
<text class="drawer-option-text">{{ item.label }}</text>
<text v-if="selectedJobResult === item.value" class="drawer-option-check"></text>
</view>
</scroll-view>
</view>
</view>
</view>
</scroll-view>
<view class="drawer-actions">
<view class="drawer-action reset" @click="resetFilters">{{ t('functionCommon.reset') }}</view>
<view class="drawer-action confirm" @click="confirmFilterDrawer">{{ t('functionCommon.confirm') }}</view>
</view>
</view>
</uni-popup>
</view>
</template>
<script setup>
import { computed, nextTick, ref } from 'vue'
import { computed, ref, nextTick } from 'vue'
import { onLoad, onReady, onReachBottom, onShow, onUnload } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import NavBar from '@/components/common/NavBar.vue'
@ -88,7 +142,12 @@ import { DICT_TYPE, getDictLabel, initAllDict, useDict } from '@/utils/dict'
const { t } = useI18n()
const searchKeyword = ref('')
const selectedJobStatus = ref('0')
const selectedJobStatus = ref('')
const selectedJobResult = ref('')
const jobResultPanelOpen = ref(false)
const filterPopupRef = ref(null)
const focusNoKeyboardRef = ref(null)
const keywordInputSelector = '.keyword-input input, input.keyword-input'
const list = ref([])
const loading = ref(false)
const loadingMore = ref(false)
@ -97,13 +156,9 @@ const pageNo = ref(1)
const pageSize = ref(10)
const scrollTop = ref(0)
const showGoTop = ref(false)
const keywordFocus = ref(false)
const focusNoKeyboardRef = ref(null)
const keywordInputSelector = '#mold-maintain-keyword-input input, input#mold-maintain-keyword-input'
let searchTimer = null
//
const { job_status: jobStatusDictOptions } = useDict(DICT_TYPE.JOB_STATUS)
const jobStatusOptions = computed(() => {
@ -120,8 +175,20 @@ const jobStatusIndex = computed(() => {
return index >= 0 ? index : 0
})
const currentJobStatusLabel = computed(() => {
if (selectedJobStatus.value === '') return t('moldMaintain.allStatus')
const current = jobStatusOptions.value.find((item) => item.value === selectedJobStatus.value)
return current ? current.label : t('functionCommon.all')
return current ? current.label : t('moldMaintain.allStatus')
})
const jobResultOptions = computed(() => [
{ label: t('moldMaintain.jobResultOk'), value: '1' },
{ label: t('moldMaintain.jobResultNg'), value: '2' }
])
const selectedJobResultLabel = computed(() => {
if (!selectedJobResult.value) return t('moldMaintain.jobResult')
const opt = jobResultOptions.value.find((o) => o.value === selectedJobResult.value)
return opt ? opt.label : t('moldMaintain.jobResult')
})
onLoad(async () => {
@ -130,7 +197,11 @@ onLoad(async () => {
})
onReady(() => {
focusKeywordNoKeyboard()
nextTick(() => {
setTimeout(() => {
focusNoKeyboardRef.value?.focus(keywordInputSelector)
}, 200)
})
})
onShow(() => {
@ -176,7 +247,8 @@ async function fetchList(reset) {
pageSize: pageSize.value,
planNo: searchKeyword.value.trim() || undefined,
planType: '2',
jobStatus: selectedJobStatus.value || undefined
jobStatus: selectedJobStatus.value || undefined,
jobResult: selectedJobResult.value || undefined
}
const res = await getMoldCheckPage(params)
const page = normalizePageData(res)
@ -204,12 +276,29 @@ function handleKeywordInput() {
}, 300)
}
function openFilterDrawer() {
filterPopupRef.value?.open()
}
function toggleJobResultPanel() {
jobResultPanelOpen.value = !jobResultPanelOpen.value
}
function selectJobResult(value) {
selectedJobResult.value = value
jobResultPanelOpen.value = false
}
function confirmFilterDrawer() {
filterPopupRef.value?.close()
fetchList(true)
}
async function resetFilters() {
clearSearchTimer()
searchKeyword.value = ''
selectedJobStatus.value = '0'
activateKeywordFocus()
await nextTick()
selectedJobStatus.value = ''
selectedJobResult.value = ''
await fetchList(true)
}
@ -250,21 +339,6 @@ function goTop() {
scrollTop.value = 0
}
function activateKeywordFocus() {
keywordFocus.value = false
nextTick(() => {
keywordFocus.value = true
})
}
function focusKeywordNoKeyboard() {
nextTick(() => {
setTimeout(() => {
focusNoKeyboardRef.value?.focus(keywordInputSelector)
}, 80)
})
}
function clearSearchTimer() {
if (searchTimer) {
clearTimeout(searchTimer)
@ -335,56 +409,276 @@ function formatDateTime(value) {
}
.filter-bar {
padding: 18rpx 14rpx 20rpx;
background: #f3f4f6;
}
.filter-row {
display: flex;
align-items: center;
gap: 12rpx;
padding: 18rpx 4rpx 0rpx;
gap: 18rpx;
}
.search-row {
margin-top: 18rpx;
}
.quick-row>picker {
min-width: 0;
flex: 1;
}
.keyword-box,
.status-box,
.reset-filter-btn {
min-width:100rpx;
.keyword-wrap,
.status-filter,
.icon-filter-btn {
height: 66rpx;
background: #ffffff;
border: 1rpx solid #d9dde5;
background: #ffffff;
box-sizing: border-box;
display: flex;
align-items: center;
}
.keyword-box {
flex: 1;
.keyword-wrap {
min-width: 0;
padding: 0 28rpx;
flex: 1;
display: flex;
align-items: center;
}
.keyword-input {
width: 100%;
font-size: 24rpx;
height: 64rpx;
padding: 0 20rpx;
font-size: 26rpx;
color: #374151;
}
.status-box {
flex-shrink: 0;
.status-filter {
min-width: 0;
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 28rpx;
min-width: 160rpx;
padding: 0 18rpx 0 26rpx;
}
.status-box-text {
font-size: 24rpx;
color: #374151;
min-width: 0;
.status-filter-text {
min-width: 0rpx;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 26rpx;
color: #374151;
}
.reset-filter-btn {
.status-filter-text.placeholder {
color: #a8adb7;
}
.icon-filter-btn {
width: 66rpx;
flex: 0 0 66rpx;
display: flex;
align-items: center;
justify-content: center;
border-color: transparent;
background: transparent;
}
//
::deep(.mold-maintain-filter-popup.right .uni-popup__content-transition) {
transform: none !important;
}
.filter-drawer {
width: 630rpx;
height: calc(100vh - var(--status-bar-height));
margin-top: var(--status-bar-height);
background: #f5f5f7;
display: flex;
flex-direction: column;
overflow: hidden;
border-radius: 28rpx 0 0 28rpx;
}
.drawer-header {
height: 104rpx;
padding: 18rpx 34rpx 0;
background: #ffffff;
display: flex;
align-items: center;
justify-content: flex-start;
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-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 22rpx 20rpx;
}
.drawer-field {
min-width: 0;
}
.drawer-field-wide {
grid-column: 1 / -1;
}
.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-picker-text.placeholder {
color: #9ca3af;
}
.drawer-option-panel {
max-height: 360rpx;
margin-top: 12rpx;
border-radius: 12rpx;
background: #f7f8fb;
overflow: hidden;
}
.drawer-option-item {
min-height: 72rpx;
padding: 0 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
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-check {
flex-shrink: 0;
font-size: 28rpx;
color: #174b78;
margin-left: 16rpx;
}
.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;
}
.drawer-action.confirm {
border-radius: 0 12rpx 12rpx 0;
background: #174b78;
color: #ffffff;
}
.list-scroll {

Loading…
Cancel
Save