style: 上下模搜索框样式优化

master
zhongwenkai 2 days ago
parent 1603133b04
commit 3a28dad83c

@ -386,6 +386,11 @@ export default {
filterToday: 'Today',
filterWeek: 'This Week',
historyEmpty: 'No history records',
moreFilter: 'More Filters',
dateFilter: 'Date Filter',
operateTime: 'Operate Time',
startTime: 'Start Date',
endTime: 'End Date',
totalPrefix: 'Total: ',
totalSuffix: '',
confirmDeleteHistory: 'Confirm delete this history record?',

@ -386,6 +386,11 @@ export default {
filterToday: '今天',
filterWeek: '本周',
historyEmpty: '暂无历史记录',
moreFilter: '更多筛选',
dateFilter: '日期筛选',
operateTime: '操作时间',
startTime: '开始日期',
endTime: '结束日期',
totalPrefix: '共 ',
totalSuffix: ' 条',
confirmDeleteHistory: '确认删除该历史记录吗?',
@ -1181,6 +1186,8 @@ export default {
searchPlaceholder: '请输入点检单号',
empty: '暂无点检记录',
add: '新增',
basicInfo: '基础信息',
jobResult: '结果',
moldName: '模具名称',
moldCode: '模具编号',
product: '产品',

@ -22,8 +22,17 @@
>
<view class="device-card-header">
<text class="device-name">{{ textValue(device.deviceName) }}</text>
<view class="device-status-tag" :class="getStatusClass(device.deviceStatus)">
{{ getStatusLabel(device) }}
<view class="device-card-header-right">
<view
v-if="fromType === 'up' && hasMoldOnDevice(device)"
class="dismount-btn"
@click.stop="handleDismount(device)"
>
<text class="dismount-btn-text">{{ t('moldOperate.tabDown') }}</text>
</view>
<view class="device-status-tag" :class="getStatusClass(device.deviceStatus)">
{{ getStatusLabel(device) }}
</view>
</view>
</view>
<view class="device-card-body">
@ -64,7 +73,7 @@
<script setup>
import { ref, computed } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import NavBar from '@/components/common/NavBar.vue'
import { getDeviceLedgerList } from '@/api/mes/moldoperate'
@ -78,6 +87,9 @@ const selectedId = ref(null)
const searchText = ref('')
const loading = ref(false)
// 'up' 'down'
const fromType = ref('up')
const lineInfoMap = ref(new Map())
function textValue(v) {
@ -141,6 +153,30 @@ function getCurrentMold(device) {
return textValue(device.currentMold || device.moldName) || t('moldOperate.noMoldOnDevice')
}
//
function hasMoldOnDevice(device) {
if (!device) return false
const deviceName = device.deviceName
//
if (deviceName && deviceMoldMap.value.has(deviceName)) {
const names = deviceMoldMap.value.get(deviceName) || []
return names.length > 0
}
// fallback
const staticMold = textValue(device.currentMold || device.moldName)
return staticMold !== '-' && staticMold !== t('moldOperate.noMoldOnDevice')
}
//
function handleDismount(device) {
if (!device) return
// globalData onShow
getApp().globalData._deviceSelectResult = { ...device }
uni.navigateTo({
url: '/pages_function/pages/moldoperate/dismount'
})
}
function flattenLineTree(nodes, parentId) {
if (!Array.isArray(nodes)) return
for (const node of nodes) {
@ -194,8 +230,15 @@ async function loadLineTree() {
const filteredList = computed(() => {
const keyword = searchText.value.trim().toLowerCase()
if (!keyword) return deviceList.value
return deviceList.value.filter((d) => {
let list = deviceList.value
//
if (fromType.value === 'down') {
list = list.filter((d) => hasMoldOnDevice(d))
}
if (!keyword) return list
return list.filter((d) => {
return (d.deviceName || '').toLowerCase().includes(keyword) ||
(d.deviceCode || '').toLowerCase().includes(keyword) ||
(getTopLineName(d.deviceLine) || '').toLowerCase().includes(keyword)
@ -246,6 +289,10 @@ function handleConfirm() {
onShow(async () => {
await Promise.allSettled([loadDevices(), loadLineTree(), loadDeviceMolds()])
})
onLoad((options) => {
fromType.value = options?.fromType === 'down' ? 'down' : 'up'
})
</script>
<style lang="scss" scoped>
@ -323,6 +370,26 @@ onShow(async () => {
color: #1a1a1a;
}
.device-card-header-right {
display: flex;
align-items: center;
gap: 12rpx;
flex-shrink: 0;
}
.dismount-btn {
padding: 6rpx 16rpx;
border-radius: 8rpx;
background: #1f4b79;
}
.dismount-btn-text {
font-size: 22rpx;
font-weight: 500;
color: #ffffff;
white-space: nowrap;
}
.device-status-tag {
padding: 4rpx 16rpx;
border-radius: 6rpx;

@ -452,7 +452,7 @@ function selectDevice(device) {
}
}
function openDevicePicker() {
uni.navigateTo({ url: '/pages_function/pages/moldoperate/deviceSelect' })
uni.navigateTo({ url: '/pages_function/pages/moldoperate/deviceSelect?fromType=down' })
}

@ -24,40 +24,24 @@
</view>
<!-- 搜索区域 -->
<view class="search-bar">
<view class="search-input-wrap">
<input
v-model="searchKeyword"
class="search-input"
:placeholder="t('moldOperate.searchPlaceholder')"
placeholder-class="search-placeholder"
confirm-type="search"
@confirm="handleSearch"
/>
</view>
<view class="search-select" @click="toggleFilter">
<text class="select-text">{{ filterLabel }}</text>
<text class="select-arrow">&#9662;</text>
</view>
<view class="search-btn reset" @click="handleReset">
<text>{{ t('functionCommon.reset') }}</text>
</view>
<view class="search-btn filter" @click="toggleFilter">
<text class="filter-icon">&#9776;</text>
</view>
</view>
<!-- 筛选条件弹层 -->
<view v-if="showFilter" class="filter-dropdown">
<view
v-for="opt in filterOptions"
:key="opt.key"
class="filter-option"
:class="{ active: filterType === opt.key }"
@click="selectFilter(opt.key)"
>
<text>{{ opt.label }}</text>
<text v-if="filterType === opt.key" class="check-mark">&#10003;</text>
<view class="filter-bar">
<view class="filter-row">
<view class="keyword-wrap">
<input
v-model="searchKeyword"
class="keyword-input"
type="text"
:placeholder="t('moldOperate.searchPlaceholder')"
confirm-type="search"
@confirm="handleSearch"
/>
</view>
<view class="icon-filter-btn" @click="handleReset">
<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>
@ -131,6 +115,33 @@
</view>
</view>
</scroll-view>
<uni-popup ref="filterPopupRef" class="mold-history-filter-popup" type="right" background-color="transparent" :animation="false">
<view class="filter-drawer">
<view class="drawer-header">
<text class="drawer-title">{{ t('moldOperate.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('moldOperate.dateFilter') }}</text>
</view>
<view class="drawer-field drawer-field-wide">
<text class="drawer-label">{{ t('moldOperate.operateTime') }}</text>
<view class="drawer-date">
<uni-datetime-picker v-model="operateTimeFilter" type="daterange" :clear-icon="true"
:start-placeholder="t('moldOperate.startTime')"
:end-placeholder="t('moldOperate.endTime')" />
</view>
</view>
</view>
</scroll-view>
<view class="drawer-actions">
<view class="drawer-action reset" @click="handleReset">{{ t('functionCommon.reset') }}</view>
<view class="drawer-action confirm" @click="confirmFilterDrawer">{{ t('functionCommon.confirm') }}</view>
</view>
</view>
</uni-popup>
</view>
</template>
@ -148,7 +159,8 @@ const pageType = ref('')
const activeTab = ref('up')
const searchKeyword = ref('')
const filterType = ref('all')
const showFilter = ref(false)
const operateTimeFilter = ref([])
const filterPopupRef = ref(null)
const allList = ref([])
const loading = ref(false)
@ -162,18 +174,21 @@ const deviceMap = ref(new Map())
const total = computed(() => filteredList.value.length)
const totalPages = computed(() => Math.ceil(total.value / pageSize.value) || 1)
const filterLabel = computed(() => {
if (filterType.value === 'all') return t('moldOperate.filterAll')
if (filterType.value === 'today') return t('moldOperate.filterToday')
if (filterType.value === 'week') return t('moldOperate.filterWeek')
return t('moldOperate.filterAll')
})
const filterTimeOptions = computed(() => [
{ label: t('moldOperate.filterAll'), value: 'all' },
{ label: t('moldOperate.filterToday'), value: 'today' },
{ label: t('moldOperate.filterWeek'), value: 'week' }
])
const filterOptions = [
{ key: 'all', label: t('moldOperate.filterAll') },
{ key: 'today', label: t('moldOperate.filterToday') },
{ key: 'week', label: t('moldOperate.filterWeek') }
]
const filterTimeLabels = computed(() => filterTimeOptions.value.map((item) => item.label))
const filterTimeIndex = computed(() => {
const idx = filterTimeOptions.value.findIndex((item) => item.value === filterType.value)
return idx >= 0 ? idx : 0
})
const filterTimeLabel = computed(() => {
const current = filterTimeOptions.value.find((item) => item.value === filterType.value)
return current ? current.label : t('moldOperate.filterAll')
})
const filteredList = computed(() => {
let list = allList.value
@ -191,6 +206,18 @@ const filteredList = computed(() => {
return d && new Date(d) >= weekAgo
})
}
//
if (operateTimeFilter.value && operateTimeFilter.value.length === 2) {
const [start, end] = operateTimeFilter.value
const endOfDay = new Date(end)
endOfDay.setHours(23, 59, 59, 999)
list = list.filter(item => {
const d = item.operateTime || item.createTime
if (!d) return false
const date = new Date(d)
return date >= new Date(start) && date <= endOfDay
})
}
if (searchKeyword.value.trim()) {
const kw = searchKeyword.value.trim().toLowerCase()
list = list.filter(item => {
@ -334,14 +361,12 @@ function switchTab(tab) {
fetchAll()
}
function toggleFilter() {
showFilter.value = !showFilter.value
function openFilterDrawer() {
filterPopupRef.value?.open()
}
function selectFilter(key) {
filterType.value = key
showFilter.value = false
pageNo.value = 1
function confirmFilterDrawer() {
filterPopupRef.value?.close()
}
function handleSearch() {
@ -351,7 +376,9 @@ function handleSearch() {
function handleReset() {
searchKeyword.value = ''
filterType.value = 'all'
operateTimeFilter.value = []
pageNo.value = 1
filterPopupRef.value?.close()
}
function changePage(p) {
@ -458,108 +485,72 @@ onShow(async () => {
}
/* ====== 搜索区域 ====== */
.search-bar {
.filter-bar {
padding: 18rpx 14rpx 20rpx;
background: #f3f4f6;
}
.filter-row {
display: flex;
align-items: center;
padding: 12rpx 16rpx;
background: #fff;
gap: 8rpx;
.search-input-wrap {
flex: 1;
height: 64rpx;
background: #f5f6f8;
border-radius: 32rpx;
padding: 0 24rpx;
display: flex;
align-items: center;
}
.search-input {
flex: 1;
font-size: 26rpx;
height: 100%;
}
.search-placeholder {
color: #999;
}
.search-select {
display: flex;
align-items: center;
padding: 0 16rpx;
height: 64rpx;
border-radius: 32rpx;
background: #f5f6f8;
gap: 4rpx;
}
.select-text {
font-size: 24rpx;
color: #666;
}
.select-arrow {
font-size: 18rpx;
color: #999;
}
gap: 18rpx;
}
.search-btn {
height: 64rpx;
line-height: 64rpx;
padding: 0 20rpx;
border-radius: 32rpx;
font-size: 24rpx;
.search-row {
margin-top: 18rpx;
}
&.reset {
background: #fff;
color: #666;
border: 1rpx solid #ddd;
}
.quick-row>picker {
min-width: 0;
flex: 1;
}
&.filter {
background: #2563eb;
color: #fff;
.keyword-wrap,
.status-filter,
.icon-filter-btn {
height: 66rpx;
border: 1rpx solid #d9dde5;
background: #ffffff;
box-sizing: border-box;
}
.filter-icon {
font-size: 28rpx;
}
}
}
.keyword-wrap {
min-width: 0;
flex: 1;
display: flex;
align-items: center;
}
/* ====== 筛选下拉 ====== */
.filter-dropdown {
position: absolute;
top: 176rpx;
right: 16rpx;
background: #fff;
border-radius: 8rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.12);
z-index: 99;
overflow: hidden;
.keyword-input {
width: 100%;
height: 64rpx;
padding: 0 20rpx;
font-size: 26rpx;
color: #374151;
}
.filter-option {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 32rpx;
font-size: 26rpx;
color: #333;
min-width: 160rpx;
.status-filter {
min-width: 0;
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 18rpx 0 26rpx;
}
&.active {
color: #2563eb;
background: #f0f5ff;
font-weight: 500;
}
.status-filter-text {
font-size: 26rpx;
color: #374151;
}
.check-mark {
color: #2563eb;
font-size: 24rpx;
}
}
.icon-filter-btn {
width: 66rpx;
flex: 0 0 66rpx;
display: flex;
align-items: center;
justify-content: center;
border-color: transparent;
background: transparent;
}
/* ====== 列表 ====== */
@ -691,4 +682,156 @@ onShow(async () => {
}
}
}
/* ====== 筛选抽屉 ====== */
::deep(.mold-history-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;
box-sizing: border-box;
}
.drawer-title {
color: #1f2937;
font-size: 34rpx;
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;
color: #1f2937;
font-weight: 700;
}
.drawer-field {
min-width: 0;
}
.drawer-field-wide {
grid-column: 1 / -1;
}
.drawer-label {
display: block;
margin-bottom: 12rpx;
font-size: 24rpx;
color: #4b5563;
font-weight: 500;
}
.drawer-date {
width: 100%;
min-height: 74rpx;
border: 0;
border-radius: 8rpx;
background: #f7f8fb;
box-sizing: border-box;
display: flex;
align-items: center;
padding: 0 12rpx;
}
.drawer-date :deep(.uni-date),
.drawer-date :deep(.uni-date-editor),
.drawer-date :deep(.uni-date-editor--x),
.drawer-date :deep(.uni-date-x) {
width: 100%;
}
.drawer-date :deep(.uni-date-editor),
.drawer-date :deep(.uni-date-editor--x),
.drawer-date :deep(.uni-date-x) {
min-height: 74rpx;
}
.drawer-date :deep(.uni-date-editor--x),
.drawer-date :deep(.uni-date-x) {
border: 0;
padding: 0;
background: transparent;
}
.drawer-date :deep(.uni-date-range) {
display: flex;
align-items: center;
}
.drawer-date :deep(.uni-date__x-input) {
text-align: center;
font-size: 26rpx;
color: #111827;
}
.drawer-actions {
height: 126rpx;
padding: 18rpx 28rpx 24rpx;
box-sizing: border-box;
display: flex;
align-items: center;
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;
}
</style>

@ -354,7 +354,7 @@ function selectDevice(device) {
}
function openDevicePicker() {
uni.navigateTo({ url: '/pages_function/pages/moldoperate/deviceSelect' })
uni.navigateTo({ url: '/pages_function/pages/moldoperate/deviceSelect?fromType=up' })
}

Loading…
Cancel
Save