style:模具维修,点检,保养,台账,上下模,备件出入库和调拨,物料出入库和调拨筛选框样式调整

master
zhongwenkai 18 hours ago
parent d2ce549c2a
commit 29a9ffe2a5

@ -4,14 +4,6 @@
<!-- 搜索栏 -->
<view class="filter-bar">
<view class="filter-row quick-row">
<picker :range="statusPickerLabels" :value="statusPickerIndex" @change="onStatusFilterChange">
<view class="status-filter">
<text :class="['status-filter-text', selectedStatus === '' ? 'placeholder' : '']">{{ currentStatusLabel }}</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
@ -31,6 +23,14 @@
<uni-icons type="settings" size="24" color="#7b8491"></uni-icons>
</view>
</view>
<view class="filter-row quick-row">
<picker :range="statusPickerLabels" :value="statusPickerIndex" @change="onStatusFilterChange">
<view class="status-filter">
<text :class="['status-filter-text', selectedStatus === '' ? 'placeholder' : '']">{{ currentStatusLabel }}</text>
<uni-icons type="bottom" size="14" color="#a8adb7"></uni-icons>
</view>
</picker>
</view>
</view>
<!-- 筛选抽屉 -->
@ -40,37 +40,23 @@
<text class="drawer-title">更多筛选</text>
</view>
<scroll-view scroll-y class="drawer-body">
<view class="drawer-section">
<view class="drawer-section-head">
<text class="drawer-section-title">物料信息</text>
</view>
<view class="drawer-grid">
<view class="drawer-field drawer-field-wide">
<text class="drawer-label">创建人</text>
<view class="drawer-picker" @click="toggleCreatorPanel">
<text :class="['drawer-picker-text', !selectedCreator ? 'placeholder' : '']">{{ selectedCreatorLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
<scroll-view v-if="creatorPanelOpen" scroll-y class="drawer-option-panel">
<view
v-for="item in creatorOptions"
:key="item.value"
:class="['drawer-option-item', selectedCreator === item.value ? 'active' : '']"
@click="selectCreator(item)"
>
<text class="drawer-option-text">{{ item.label }}</text>
<text v-if="selectedCreator === item.value" class="drawer-option-check"></text>
<view class="drawer-section drawer-fields">
<view class="drawer-field">
<text class="drawer-label">创建人</text>
<picker class="drawer-picker-host" :range="creatorLabels" :value="creatorIndex" @change="onCreatorPickerChange">
<view class="drawer-picker">
<text :class="['drawer-picker-text', !selectedCreator ? 'placeholder' : '']">{{ selectedCreatorLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
</scroll-view>
</picker>
</view>
<view class="drawer-field drawer-field-wide">
<view class="drawer-field">
<text class="drawer-label">入库时间</text>
<view class="drawer-date">
<uni-datetime-picker v-model="inTimeFilter" type="daterange" :clear-icon="true"
start-placeholder="开始时间"
end-placeholder="结束时间" />
</view>
</view>
</view>
</view>
</scroll-view>
@ -213,7 +199,6 @@ const filterPopupRef = ref(null)
const selectedCreator = ref(null)
const inTimeFilter = ref([])
const creatorOptions = ref([])
const creatorPanelOpen = ref(false)
const statusOptions = computed(() => [
{ label: '待入库', value: '0' },
@ -241,6 +226,12 @@ const selectedCreatorLabel = computed(() => {
const found = creatorOptions.value.find((u) => u.value === selectedCreator.value)
return found ? found.label : '创建人'
})
const creatorLabels = computed(() => ['创建人', ...creatorOptions.value.map((o) => o.label)])
const creatorIndex = computed(() => {
if (!selectedCreator.value) return 0
const idx = creatorOptions.value.findIndex((o) => o.value === selectedCreator.value)
return idx >= 0 ? idx + 1 : 0
})
const list = ref([])
const loading = ref(false)
@ -353,13 +344,14 @@ function confirmFilterDrawer() {
fetchList(true)
}
function toggleCreatorPanel() {
creatorPanelOpen.value = !creatorPanelOpen.value
}
function selectCreator(item) {
selectedCreator.value = selectedCreator.value === item.value ? null : item.value
creatorPanelOpen.value = false
function onCreatorPickerChange(event) {
const index = Number(event?.detail?.value || 0)
if (index === 0) {
selectedCreator.value = null
} else {
const item = creatorOptions.value[index - 1]
selectedCreator.value = item ? item.value : null
}
}
async function loadCreatorOptions() {
@ -395,6 +387,7 @@ function resetFilters() {
selectedStatus.value = ''
selectedCreator.value = null
inTimeFilter.value = []
filterPopupRef.value?.close()
fetchList(true)
}
@ -574,7 +567,7 @@ onHide(() => {})
gap: 18rpx;
}
.search-row {
.quick-row {
margin-top: 18rpx;
}
@ -715,169 +708,21 @@ onHide(() => {})
color: #ffffff;
}
.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-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-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-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 { min-width: 0; flex: 1; 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-date { min-width: 0; flex: 1; 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; }
/* ====== 列表 ====== */
.list-scroll {

@ -3,14 +3,6 @@
<NavBar :title="pageTitle" />
<view class="filter-bar">
<view class="filter-row quick-row">
<picker :range="statusPickerLabels" :value="statusPickerIndex" @change="onStatusFilterChange">
<view class="status-filter">
<text :class="['status-filter-text', selectedStatus === '' ? 'placeholder' : '']">{{ currentStatusLabel }}</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
@ -30,6 +22,14 @@
<uni-icons type="settings" size="24" color="#7b8491"></uni-icons>
</view>
</view>
<view class="filter-row quick-row">
<picker :range="statusPickerLabels" :value="statusPickerIndex" @change="onStatusFilterChange">
<view class="status-filter">
<text :class="['status-filter-text', selectedStatus === '' ? 'placeholder' : '']">{{ currentStatusLabel }}</text>
<uni-icons type="bottom" size="14" color="#a8adb7"></uni-icons>
</view>
</picker>
</view>
</view>
<uni-popup ref="filterPopupRef" class="move-filter-popup" type="right" background-color="transparent" :animation="false">
@ -38,30 +38,17 @@
<text class="drawer-title">更多筛选</text>
</view>
<scroll-view scroll-y class="drawer-body">
<view class="drawer-section">
<view class="drawer-section-head">
<text class="drawer-section-title">调拨信息</text>
</view>
<view class="drawer-grid">
<view class="drawer-field drawer-field-wide">
<text class="drawer-label">创建人</text>
<view class="drawer-picker" @click="toggleCreatorPanel">
<text :class="['drawer-picker-text', !selectedCreator ? 'placeholder' : '']">{{ selectedCreatorLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
<scroll-view v-if="creatorPanelOpen" scroll-y class="drawer-option-panel">
<view
v-for="item in creatorOptions"
:key="item.value"
:class="['drawer-option-item', selectedCreator === item.value ? 'active' : '']"
@click="selectCreator(item)"
>
<text class="drawer-option-text">{{ item.label }}</text>
<text v-if="selectedCreator === item.value" class="drawer-option-check"></text>
<view class="drawer-section drawer-fields">
<view class="drawer-field">
<text class="drawer-label">创建人</text>
<picker class="drawer-picker-host" :range="creatorLabels" :value="creatorIndex" @change="onCreatorPickerChange">
<view class="drawer-picker">
<text :class="['drawer-picker-text', !selectedCreator ? 'placeholder' : '']">{{ selectedCreatorLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
</scroll-view>
</picker>
</view>
<view class="drawer-field drawer-field-wide">
<view class="drawer-field">
<text class="drawer-label">调拨时间</text>
<view class="drawer-date">
<uni-datetime-picker
@ -72,7 +59,6 @@
end-placeholder="结束时间"
/>
</view>
</view>
</view>
</view>
</scroll-view>
@ -164,7 +150,6 @@ const filterPopupRef = ref(null)
const selectedCreator = ref(null)
const moveTimeFilter = ref([])
const creatorOptions = ref([])
const creatorPanelOpen = ref(false)
const categoryType = ref(2)
const categoryNameMap = {
@ -197,6 +182,12 @@ const selectedCreatorLabel = computed(() => {
const found = creatorOptions.value.find((item) => item.value === selectedCreator.value)
return found ? found.label : '创建人'
})
const creatorLabels = computed(() => ['创建人', ...creatorOptions.value.map((o) => o.label)])
const creatorIndex = computed(() => {
if (!selectedCreator.value) return 0
const idx = creatorOptions.value.findIndex((o) => o.value === selectedCreator.value)
return idx >= 0 ? idx + 1 : 0
})
const list = ref([])
const loading = ref(false)
@ -315,12 +306,14 @@ function confirmFilterDrawer() {
filterPopupRef.value?.close()
fetchList(true)
}
function toggleCreatorPanel() {
creatorPanelOpen.value = !creatorPanelOpen.value
}
function selectCreator(item) {
selectedCreator.value = selectedCreator.value === item.value ? null : item.value
creatorPanelOpen.value = false
function onCreatorPickerChange(event) {
const index = Number(event?.detail?.value || 0)
if (index === 0) {
selectedCreator.value = null
} else {
const item = creatorOptions.value[index - 1]
selectedCreator.value = item ? item.value : null
}
}
async function loadCreatorOptions() {
if (creatorOptions.value.length) return
@ -339,6 +332,7 @@ function resetFilters() {
selectedStatus.value = ''
selectedCreator.value = null
moveTimeFilter.value = []
filterPopupRef.value?.close()
fetchList(true)
}
async function loadMore() {
@ -421,7 +415,7 @@ onUnload(() => {
.page-container { min-height: 100vh; background: #f4f5f7; }
.filter-bar { padding: 18rpx 14rpx 20rpx; background: #f3f4f6; }
.filter-row { display: flex; align-items: center; gap: 18rpx; }
.search-row { margin-top: 18rpx; }
.quick-row { margin-top: 18rpx; }
.quick-row > picker { min-width: 0; flex: 1; }
.keyword-wrap, .status-filter, .icon-filter-btn { height: 66rpx; border: 1rpx solid #d9dde5; background: #ffffff; box-sizing: border-box; }
.keyword-wrap { min-width: 0; flex: 1; display: flex; align-items: center; }
@ -440,24 +434,16 @@ onUnload(() => {
.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; }
.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-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-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 { min-width: 0; flex: 1; width: 100%; min-height: 74rpx; 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: 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-date { width: 100%; min-height: 74rpx; border-radius: 8rpx; background: #f7f8fb; box-sizing: border-box; display: flex; align-items: center; padding: 0 12rpx; }
.drawer-date { min-width: 0; flex: 1; width: 100%; min-height: 74rpx; 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--x), .drawer-date :deep(.uni-date-x) { border: 0; padding: 0; background: transparent; }

@ -3,6 +3,13 @@
<NavBar :title="t('materialOutbound.moduleName')" />
<view class="filter-bar">
<view class="filter-row search-row">
<view class="keyword-wrap">
<input v-model="searchKeyword" class="keyword-input" type="text" :placeholder="t('materialOutbound.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 class="filter-row quick-row">
<picker :range="statusPickerLabels" :value="statusPickerIndex" @change="onStatusFilterChange">
<view class="status-filter">
@ -11,38 +18,24 @@
</view>
</picker>
</view>
<view class="filter-row search-row">
<view class="keyword-wrap">
<input v-model="searchKeyword" class="keyword-input" type="text" :placeholder="t('materialOutbound.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>
<uni-popup ref="filterPopupRef" class="material-outbound-filter-popup" type="right" background-color="transparent" :animation="false">
<view class="filter-drawer">
<view class="drawer-header"><text class="drawer-title">{{ t('functionCommon.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('materialOutbound.materialInfo') }}</text></view>
<view class="drawer-grid">
<view class="drawer-field drawer-field-wide"><text class="drawer-label">{{ t('materialOutbound.creator') }}</text>
<view class="drawer-picker" @click="toggleCreatorPanel">
<text :class="['drawer-picker-text', !selectedCreator ? 'placeholder' : '']">{{ selectedCreatorLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
<scroll-view v-if="creatorPanelOpen" scroll-y class="drawer-option-panel">
<view v-for="item in creatorOptions" :key="item.value" :class="['drawer-option-item', selectedCreator === item.value ? 'active' : '']" @click="selectCreator(item)">
<text class="drawer-option-text">{{ item.label }}</text>
<text v-if="selectedCreator === item.value" class="drawer-option-check"></text>
<view class="drawer-section drawer-fields">
<view class="drawer-field"><text class="drawer-label">{{ t('materialOutbound.creator') }}</text>
<picker class="drawer-picker-host" :range="creatorLabels" :value="creatorIndex" @change="onCreatorPickerChange">
<view class="drawer-picker">
<text :class="['drawer-picker-text', !selectedCreator ? 'placeholder' : '']">{{ selectedCreatorLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
</scroll-view>
</picker>
</view>
<view class="drawer-field drawer-field-wide">
<view class="drawer-field">
<text class="drawer-label">{{ t('materialOutbound.outboundTime') }}</text>
<view class="drawer-date"><uni-datetime-picker v-model="inTimeFilter" type="daterange" :clear-icon="true" :start-placeholder="t('materialOutbound.startTime')" :end-placeholder="t('materialOutbound.endTime')" /></view>
</view>
</view>
</view>
</scroll-view>
@ -139,7 +132,6 @@ const filterPopupRef = ref(null)
const selectedCreator = ref(null)
const inTimeFilter = ref([])
const creatorOptions = ref([])
const creatorPanelOpen = ref(false)
const statusOptions = computed(() => [
{ label: t('materialOutbound.tabPending'), value: '0' },
@ -151,6 +143,8 @@ const statusPickerLabels = computed(() => [t('materialOutbound.allStatus'), ...s
const statusPickerIndex = computed(() => { if (selectedStatus.value === '') return 0; const idx = statusOptions.value.findIndex(i => i.value === selectedStatus.value); return idx >= 0 ? idx + 1 : 0 })
const currentStatusLabel = computed(() => { if (selectedStatus.value === '') return t('materialOutbound.allStatus'); const cur = statusOptions.value.find(i => i.value === selectedStatus.value); return cur ? cur.label : t('materialOutbound.allStatus') })
const selectedCreatorLabel = computed(() => { if (!selectedCreator.value) return t('materialOutbound.creator'); const found = creatorOptions.value.find(u => u.value === selectedCreator.value); return found ? found.label : t('materialOutbound.creator') })
const creatorLabels = computed(() => [t('materialOutbound.creator'), ...creatorOptions.value.map(o => o.label)])
const creatorIndex = computed(() => { if (!selectedCreator.value) return 0; const idx = creatorOptions.value.findIndex(o => o.value === selectedCreator.value); return idx >= 0 ? idx + 1 : 0 })
const list = ref([])
const loading = ref(false)
const loadingMore = ref(false)
@ -204,11 +198,10 @@ async function fetchList(reset) {
function onStatusFilterChange(event) { const index = Number(event?.detail?.value || 0); if (index === 0) { selectedStatus.value = '' } else { const item = statusOptions.value[index - 1]; selectedStatus.value = item ? item.value : '' }; fetchList(true) }
function handleSearch() { clearSearchTimer(); uni.hideKeyboard(); fetchList(true) }
function handleKeywordInput() { clearSearchTimer(); searchTimer = setTimeout(() => fetchList(true), 300) }
function resetFilters() { clearSearchTimer(); searchKeyword.value = ''; selectedStatus.value = ''; selectedCreator.value = null; inTimeFilter.value = []; fetchList(true) }
function resetFilters() { clearSearchTimer(); searchKeyword.value = ''; selectedStatus.value = ''; selectedCreator.value = null; inTimeFilter.value = []; filterPopupRef.value?.close(); fetchList(true) }
function openFilterDrawer() { loadCreatorOptions(); filterPopupRef.value?.open() }
function confirmFilterDrawer() { filterPopupRef.value?.close(); fetchList(true) }
function toggleCreatorPanel() { creatorPanelOpen.value = !creatorPanelOpen.value }
function selectCreator(item) { selectedCreator.value = selectedCreator.value === item.value ? null : item.value; creatorPanelOpen.value = false }
function onCreatorPickerChange(event) { const index = Number(event?.detail?.value || 0); if (index === 0) { selectedCreator.value = null } else { const item = creatorOptions.value[index - 1]; selectedCreator.value = item ? item.value : null } }
async function loadCreatorOptions() { if (creatorOptions.value.length) return; try { const res = await getSimpleUserList(); const data = Array.isArray(res) ? res : (Array.isArray(res?.data) ? res.data : []); creatorOptions.value = data.map(u => ({ value: u.id || u.userId, label: u.nickname || u.userName || u.name || String(u.id || '') })) } catch (e) {} }
async function loadMore() { if (loading.value || loadingMore.value || finished.value) return; pageNo.value += 1; await fetchList(false) }
function openDetail(item) { if (!item?.id) { uni.showToast({ title: t('functionCommon.noIdView'), icon: 'none' }); return }; uni.navigateTo({ url: `/pages_function/pages/materialOutbound/detail?id=${encodeURIComponent(String(item.id))}` }) }
@ -260,7 +253,7 @@ onHide(() => {})
.page-container { min-height: 100vh; background: #f4f5f7; }
.filter-bar { padding: 18rpx 14rpx 20rpx; background: #f3f4f6; }
.filter-row { display: flex; align-items: center; gap: 18rpx; }
.search-row { margin-top: 18rpx; }
.quick-row { margin-top: 18rpx; }
.quick-row > picker { min-width: 0; flex: 1; }
.keyword-wrap, .status-filter, .icon-filter-btn { height: 66rpx; border: 1rpx solid #d9dde5; background: #ffffff; box-sizing: border-box; }
.keyword-wrap { min-width: 0; flex: 1; display: flex; align-items: center; }
@ -280,24 +273,16 @@ onHide(() => {})
.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; }
.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-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-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 { min-width: 0; flex: 1; 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: 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-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 { min-width: 0; flex: 1; 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; }

@ -3,14 +3,6 @@
<NavBar :title="t('moldCheck.moduleName')" />
<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
@ -30,6 +22,14 @@
<uni-icons type="settings" size="24" color="#7b8491"></uni-icons>
</view>
</view>
<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>
<scroll-view scroll-y class="list-scroll" :scroll-top="scrollTop" @scroll="onScroll" @scrolltolower="loadMore"
@ -96,29 +96,15 @@
<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">
<view class="drawer-section drawer-fields">
<view class="drawer-field">
<text class="drawer-label">{{ t('moldCheck.jobResult') }}</text>
<picker class="drawer-picker-host" :range="jobResultLabels" :value="jobResultIndex" @change="onJobResultPickerChange">
<view class="drawer-picker">
<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>
</picker>
</view>
</view>
</scroll-view>
@ -144,7 +130,6 @@ const { t } = useI18n()
const searchKeyword = ref('')
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'
@ -192,6 +177,13 @@ const selectedJobResultLabel = computed(() => {
return opt ? opt.label : t('moldCheck.jobResult')
})
const jobResultLabels = computed(() => [t('moldCheck.jobResult'), ...jobResultOptions.value.map((o) => o.label)])
const jobResultIndex = computed(() => {
if (!selectedJobResult.value) return 0
const idx = jobResultOptions.value.findIndex((o) => o.value === selectedJobResult.value)
return idx >= 0 ? idx + 1 : 0
})
onLoad(async () => {
await initAllDict()
await fetchList(true)
@ -281,13 +273,14 @@ function openFilterDrawer() {
filterPopupRef.value?.open()
}
function toggleJobResultPanel() {
jobResultPanelOpen.value = !jobResultPanelOpen.value
}
function selectJobResult(value) {
selectedJobResult.value = value
jobResultPanelOpen.value = false
function onJobResultPickerChange(event) {
const index = Number(event?.detail?.value || 0)
if (index === 0) {
selectedJobResult.value = ''
} else {
const item = jobResultOptions.value[index - 1]
selectedJobResult.value = item ? item.value : ''
}
}
function confirmFilterDrawer() {
@ -300,6 +293,7 @@ async function resetFilters() {
searchKeyword.value = ''
selectedJobStatus.value = ''
selectedJobResult.value = ''
filterPopupRef.value?.close()
await fetchList(true)
}
@ -420,7 +414,7 @@ function formatDateTime(value) {
gap: 18rpx;
}
.search-row {
.quick-row {
margin-top: 18rpx;
}
@ -528,51 +522,54 @@ function formatDateTime(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:last-child {
border-bottom: 0;
}
.drawer-field-wide {
grid-column: 1 / -1;
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 {
min-width: 0;
flex: 1;
width: 100%;
min-height: 74rpx;
border: 0;
@ -582,29 +579,29 @@ function formatDateTime(value) {
}
.drawer-input {
height: 74rpx;
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 {

@ -3,14 +3,6 @@
<NavBar :title="t('moldLedger.moduleName')" />
<view class="filter-bar">
<view class="filter-row quick-row">
<picker :range="statusPickerLabels" :value="statusPickerIndex" @change="onStatusFilterChange">
<view class="status-filter">
<text :class="['status-filter-text', selectedStatus === '' ? 'placeholder' : '']">{{ selectedStatusLabel }}</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
@ -30,6 +22,14 @@
<uni-icons type="settings" size="24" color="#7b8491"></uni-icons>
</view>
</view>
<view class="filter-row quick-row">
<picker :range="statusPickerLabels" :value="statusPickerIndex" @change="onStatusFilterChange">
<view class="status-filter">
<text :class="['status-filter-text', selectedStatus === '' ? 'placeholder' : '']">{{ selectedStatusLabel }}</text>
<uni-icons type="bottom" size="14" color="#a8adb7"></uni-icons>
</view>
</picker>
</view>
</view>
<scroll-view
@ -86,47 +86,24 @@
<text class="drawer-title">{{ t('moldLedger.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('moldLedger.basicInfo') }}</text>
</view>
<view class="drawer-grid">
<view class="drawer-field">
<text class="drawer-label">{{ t('moldLedger.productModel') }}</text>
<view class="drawer-picker" @click="toggleProductPanel">
<view class="drawer-section drawer-fields">
<view class="drawer-field">
<text class="drawer-label">{{ t('moldLedger.productModel') }}</text>
<picker class="drawer-picker-host" :range="productPickerLabels" :value="productPickerIndex" @change="onProductPickerChange">
<view class="drawer-picker">
<text :class="['drawer-picker-text', selectedProductId == null ? 'placeholder' : '']">{{ selectedProductLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
<scroll-view v-if="productPanelOpen" scroll-y class="drawer-option-panel">
<view
v-for="item in productOptions"
:key="item.id"
:class="['drawer-option-item', selectedProductId === item.id ? 'active' : '']"
@click="selectProduct(item)"
>
<text class="drawer-option-text">{{ item.name }}</text>
<text v-if="selectedProductId === item.id" class="drawer-option-check"></text>
</view>
</scroll-view>
</view>
<view class="drawer-field">
<text class="drawer-label">{{ t('moldLedger.currentDevice') }}</text>
<view class="drawer-picker" @click="toggleDevicePanel">
</picker>
</view>
<view class="drawer-field">
<text class="drawer-label">{{ t('moldLedger.currentDevice') }}</text>
<picker class="drawer-picker-host" :range="devicePickerLabels" :value="devicePickerIndex" @change="onDevicePickerChange">
<view class="drawer-picker">
<text :class="['drawer-picker-text', !selectedCurrentDevice ? '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="item in deviceOptions"
:key="item.id"
:class="['drawer-option-item', selectedCurrentDevice === item.deviceName ? 'active' : '']"
@click="selectDevice(item)"
>
<text class="drawer-option-text">{{ item.deviceName }}{{ item.deviceCode }}</text>
<text v-if="selectedCurrentDevice === item.deviceName" class="drawer-option-check"></text>
</view>
</scroll-view>
</view>
</picker>
</view>
</view>
</scroll-view>
@ -165,9 +142,6 @@ const productOptions = ref([])
const deviceOptions = ref([])
const selectedProductId = ref(null)
const selectedCurrentDevice = ref('')
//
const productPanelOpen = ref(false)
const devicePanelOpen = ref(false)
const scrollTop = ref(0)
const showGoTop = ref(false)
const focusNoKeyboardRef = ref(null)
@ -207,6 +181,20 @@ const selectedDeviceLabel = computed(() => {
return found ? `${found.deviceName}${found.deviceCode}` : selectedCurrentDevice.value
})
// picker range & index
const productPickerLabels = computed(() => [t('moldLedger.productModel'), ...productOptions.value.map((p) => p.name)])
const productPickerIndex = computed(() => {
if (selectedProductId.value == null) return 0
const idx = productOptions.value.findIndex((p) => p.id === selectedProductId.value)
return idx >= 0 ? idx + 1 : 0
})
const devicePickerLabels = computed(() => [t('moldLedger.currentDevice'), ...deviceOptions.value.map((d) => `${d.deviceName}${d.deviceCode}`)])
const devicePickerIndex = computed(() => {
if (!selectedCurrentDevice.value) return 0
const idx = deviceOptions.value.findIndex((d) => d.deviceName === selectedCurrentDevice.value)
return idx >= 0 ? idx + 1 : 0
})
onLoad(async () => {
await initAllDict()
await Promise.all([fetchProductOptions(), fetchDeviceOptions()])
@ -248,24 +236,24 @@ function openFilterDrawer() {
filterPopupRef.value?.open()
}
function toggleProductPanel() {
productPanelOpen.value = !productPanelOpen.value
devicePanelOpen.value = false
}
function toggleDevicePanel() {
devicePanelOpen.value = !devicePanelOpen.value
productPanelOpen.value = false
}
function selectProduct(item) {
selectedProductId.value = selectedProductId.value === item.id ? null : item.id
productPanelOpen.value = false
function onProductPickerChange(event) {
const index = Number(event?.detail?.value || 0)
if (index === 0) {
selectedProductId.value = null
} else {
const item = productOptions.value[index - 1]
selectedProductId.value = item ? item.id : null
}
}
function selectDevice(item) {
selectedCurrentDevice.value = item.deviceName
devicePanelOpen.value = false
function onDevicePickerChange(event) {
const index = Number(event?.detail?.value || 0)
if (index === 0) {
selectedCurrentDevice.value = ''
} else {
const item = deviceOptions.value[index - 1]
selectedCurrentDevice.value = item ? item.deviceName : ''
}
}
function confirmFilterDrawer() {
@ -278,6 +266,7 @@ async function resetFilters() {
selectedStatus.value = ''
selectedProductId.value = null
selectedCurrentDevice.value = ''
filterPopupRef.value?.close()
await fetchList(true)
}
@ -445,7 +434,7 @@ function formatDateTime(value) {
gap: 18rpx;
}
.search-row {
.quick-row {
margin-top: 18rpx;
}
@ -697,51 +686,54 @@ function formatDateTime(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:last-child {
border-bottom: 0;
}
.drawer-field-wide {
grid-column: 1 / -1;
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 {
min-width: 0;
flex: 1;
width: 100%;
min-height: 74rpx;
border: 0;
@ -751,29 +743,29 @@ function formatDateTime(value) {
}
.drawer-input {
height: 74rpx;
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 {

@ -3,14 +3,6 @@
<NavBar :title="t('moldMaintain.moduleName')" />
<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
@ -30,6 +22,14 @@
<uni-icons type="settings" size="24" color="#7b8491"></uni-icons>
</view>
</view>
<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>
<scroll-view scroll-y class="list-scroll" :scroll-top="scrollTop" @scroll="onScroll" @scrolltolower="loadMore"
@ -96,29 +96,15 @@
<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">
<view class="drawer-section drawer-fields">
<view class="drawer-field">
<text class="drawer-label">{{ t('moldMaintain.jobResult') }}</text>
<picker class="drawer-picker-host" :range="jobResultLabels" :value="jobResultIndex" @change="onJobResultPickerChange">
<view class="drawer-picker">
<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>
</picker>
</view>
</view>
</scroll-view>
@ -144,7 +130,6 @@ const { t } = useI18n()
const searchKeyword = ref('')
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'
@ -191,6 +176,13 @@ const selectedJobResultLabel = computed(() => {
return opt ? opt.label : t('moldMaintain.jobResult')
})
const jobResultLabels = computed(() => [t('moldMaintain.jobResult'), ...jobResultOptions.value.map((o) => o.label)])
const jobResultIndex = computed(() => {
if (!selectedJobResult.value) return 0
const idx = jobResultOptions.value.findIndex((o) => o.value === selectedJobResult.value)
return idx >= 0 ? idx + 1 : 0
})
onLoad(async () => {
await initAllDict()
await fetchList(true)
@ -280,13 +272,14 @@ function openFilterDrawer() {
filterPopupRef.value?.open()
}
function toggleJobResultPanel() {
jobResultPanelOpen.value = !jobResultPanelOpen.value
}
function selectJobResult(value) {
selectedJobResult.value = value
jobResultPanelOpen.value = false
function onJobResultPickerChange(event) {
const index = Number(event?.detail?.value || 0)
if (index === 0) {
selectedJobResult.value = ''
} else {
const item = jobResultOptions.value[index - 1]
selectedJobResult.value = item ? item.value : ''
}
}
function confirmFilterDrawer() {
@ -299,6 +292,7 @@ async function resetFilters() {
searchKeyword.value = ''
selectedJobStatus.value = ''
selectedJobResult.value = ''
filterPopupRef.value?.close()
await fetchList(true)
}
@ -419,7 +413,7 @@ function formatDateTime(value) {
gap: 18rpx;
}
.search-row {
.quick-row {
margin-top: 18rpx;
}
@ -527,71 +521,79 @@ function formatDateTime(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:last-child {
border-bottom: 0;
}
.drawer-field-wide {
grid-column: 1 / -1;
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 {
min-width: 0;
flex: 1;
width: 100%;
min-height: 74rpx;
border: 0;
border-radius: 8rpx;
background: #f7f8fb;
box-sizing: border-box;
}
.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 {

@ -3,14 +3,6 @@
<NavBar :title="t('moldRepair.moduleName')" />
<view class="filter-bar">
<view class="filter-row quick-row">
<picker :range="statusLabels" :value="statusPickerIndex" @change="onStatusFilterChange">
<view class="status-filter">
<text :class="['status-filter-text', selectedStatus === '' ? 'placeholder' : '']">{{ selectedStatusLabel }}</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
@ -34,6 +26,14 @@
<uni-icons type="settings" size="24" color="#7b8491"></uni-icons>
</view>
</view>
<view class="filter-row quick-row">
<picker :range="statusLabels" :value="statusPickerIndex" @change="onStatusFilterChange">
<view class="status-filter">
<text :class="['status-filter-text', selectedStatus === '' ? 'placeholder' : '']">{{ selectedStatusLabel }}</text>
<uni-icons type="bottom" size="14" color="#a8adb7"></uni-icons>
</view>
</picker>
</view>
</view>
<uni-popup ref="filterPopupRef" class="repair-filter-popup" type="right" background-color="transparent" :animation="false">
@ -42,70 +42,54 @@
<text class="drawer-title">{{ t('functionCommon.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('moldRepair.basicInfo') }}</text>
<view class="drawer-section drawer-fields">
<view class="drawer-field">
<text class="drawer-label">{{ t('moldRepair.repairCode') }}</text>
<input v-model="filterRepairCode" class="drawer-input" type="text" :placeholder="t('moldRepair.repairCode')" />
</view>
<view class="drawer-grid">
<view class="drawer-field">
<text class="drawer-label">{{ t('moldRepair.repairCode') }}</text>
<input v-model="filterRepairCode" class="drawer-input" type="text" :placeholder="t('moldRepair.repairCode')" />
</view>
<view class="drawer-field">
<text class="drawer-label">{{ t('moldRepair.repairName') }}</text>
<input v-model="filterRepairName" class="drawer-input" type="text" :placeholder="t('moldRepair.repairName')" />
</view>
<view class="drawer-field">
<text class="drawer-label">{{ t('moldRepair.moldCode') }}</text>
<input v-model="filterMoldCode" class="drawer-input" type="text" :placeholder="t('moldRepair.moldCode')" />
</view>
<view class="drawer-field">
<text class="drawer-label">{{ t('moldRepair.moldName') }}</text>
<input v-model="filterMoldName" class="drawer-input" type="text" :placeholder="t('moldRepair.moldName')" />
</view>
<view class="drawer-field">
<text class="drawer-label">{{ t('moldRepair.acceptedBy') }}</text>
<input v-model="filterAcceptedBy" class="drawer-input" type="text" :placeholder="t('moldRepair.acceptedBy')" />
</view>
<view class="drawer-field">
<text class="drawer-label">{{ t('moldRepair.status') }}</text>
<picker :range="drawerStatusLabels" :value="drawerStatusIndex" @change="onDrawerStatusChange">
<view class="drawer-input" style="display:flex;align-items:center;justify-content:center;">
<text :class="filterDrawerStatus === '' ? 'drawer-input-text placeholder' : 'drawer-input-text'">{{ drawerStatusLabel }}</text>
</view>
</picker>
</view>
<view class="drawer-field">
<text class="drawer-label">{{ t('moldRepair.repairName') }}</text>
<input v-model="filterRepairName" class="drawer-input" type="text" :placeholder="t('moldRepair.repairName')" />
</view>
</view>
<view class="drawer-section">
<view class="drawer-section-head">
<text class="drawer-section-title">{{ t('moldRepair.requireDate') }}</text>
<view class="drawer-field">
<text class="drawer-label">{{ t('moldRepair.moldCode') }}</text>
<input v-model="filterMoldCode" class="drawer-input" type="text" :placeholder="t('moldRepair.moldCode')" />
</view>
<view class="drawer-field">
<text class="drawer-label">{{ t('moldRepair.moldName') }}</text>
<input v-model="filterMoldName" class="drawer-input" type="text" :placeholder="t('moldRepair.moldName')" />
</view>
<view class="drawer-field">
<text class="drawer-label">{{ t('moldRepair.acceptedBy') }}</text>
<input v-model="filterAcceptedBy" class="drawer-input" type="text" :placeholder="t('moldRepair.acceptedBy')" />
</view>
<view class="drawer-field drawer-field-wide">
<view class="drawer-field">
<text class="drawer-label">{{ t('moldRepair.status') }}</text>
<picker class="drawer-picker-host" :range="drawerStatusLabels" :value="drawerStatusIndex" @change="onDrawerStatusChange">
<view class="drawer-picker">
<text :class="['drawer-picker-text', filterDrawerStatus === '' ? 'placeholder' : '']">{{ drawerStatusLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
</picker>
</view>
<view class="drawer-field">
<text class="drawer-label">{{ t('moldRepair.requireDate') }}</text>
<view class="drawer-date">
<uni-datetime-picker v-model="filterRequireDate" type="daterange" :clear-icon="true"
:start-placeholder="t('moldRepair.startTime')"
:end-placeholder="t('moldRepair.endTime')" />
</view>
</view>
</view>
<view class="drawer-section">
<view class="drawer-section-head">
<text class="drawer-section-title">{{ t('moldRepair.finishDate') }}</text>
</view>
<view class="drawer-field drawer-field-wide">
<view class="drawer-field">
<text class="drawer-label">{{ t('moldRepair.finishDate') }}</text>
<view class="drawer-date">
<uni-datetime-picker v-model="filterFinishDate" type="daterange" :clear-icon="true"
:start-placeholder="t('moldRepair.startTime')"
:end-placeholder="t('moldRepair.endTime')" />
</view>
</view>
</view>
<view class="drawer-section">
<view class="drawer-section-head">
<text class="drawer-section-title">{{ t('moldRepair.confirmDate') }}</text>
</view>
<view class="drawer-field drawer-field-wide">
<view class="drawer-field">
<text class="drawer-label">{{ t('moldRepair.confirmDate') }}</text>
<view class="drawer-date">
<uni-datetime-picker v-model="filterConfirmDate" type="daterange" :clear-icon="true"
:start-placeholder="t('moldRepair.startTime')"
@ -370,6 +354,7 @@ async function resetFilters() {
filterRequireDate.value = []
filterFinishDate.value = []
filterConfirmDate.value = []
filterPopupRef.value?.close()
activateKeywordFocus()
await fetchList(true)
}
@ -541,7 +526,7 @@ function textValue(value) {
gap: 18rpx;
}
.search-row {
.quick-row {
margin-top: 18rpx;
}
@ -688,60 +673,68 @@ 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:last-child {
border-bottom: 0;
}
.drawer-field-wide {
grid-column: 1 / -1;
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-input {
.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;
border-radius: 8rpx;
background: #f7f8fb;
box-sizing: border-box;
}
.drawer-input {
padding: 0 18rpx;
font-size: 26rpx;
color: #111827;
text-align: center;
text-align: right;
}
.drawer-input-text {
@ -753,13 +746,30 @@ function textValue(value) {
color: #a8adb7;
}
.drawer-picker {
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-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;

@ -122,11 +122,8 @@
<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">
<view class="drawer-section drawer-fields">
<view class="drawer-field">
<text class="drawer-label">{{ t('moldOperate.operateTime') }}</text>
<view class="drawer-date">
<uni-datetime-picker v-model="operateTimeFilter" type="daterange" :clear-icon="true"
@ -723,43 +720,43 @@ onShow(async () => {
.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;
color: #1f2937;
font-weight: 700;
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-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-date {
width: 100%;
min-width: 0;
flex: 1;
min-height: 74rpx;
border: 0;
border-radius: 8rpx;

@ -4,14 +4,6 @@
<!-- 搜索栏 -->
<view class="filter-bar">
<view class="filter-row quick-row">
<picker :range="statusPickerLabels" :value="statusPickerIndex" @change="onStatusFilterChange">
<view class="status-filter">
<text :class="['status-filter-text', selectedStatus === '' ? 'placeholder' : '']">{{ currentStatusLabel }}</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
@ -31,6 +23,14 @@
<uni-icons type="settings" size="24" color="#7b8491"></uni-icons>
</view>
</view>
<view class="filter-row quick-row">
<picker :range="statusPickerLabels" :value="statusPickerIndex" @change="onStatusFilterChange">
<view class="status-filter">
<text :class="['status-filter-text', selectedStatus === '' ? 'placeholder' : '']">{{ currentStatusLabel }}</text>
<uni-icons type="bottom" size="14" color="#a8adb7"></uni-icons>
</view>
</picker>
</view>
</view>
<!-- 筛选抽屉 -->
@ -40,36 +40,22 @@
<text class="drawer-title">{{ t('functionCommon.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('sparepartInbound.sparepartInfo') }}</text>
</view>
<view class="drawer-grid">
<view class="drawer-field drawer-field-wide">
<text class="drawer-label">{{ t('sparepartInbound.creator') }}</text>
<view class="drawer-picker" @click="toggleCreatorPanel">
<view class="drawer-section drawer-fields">
<view class="drawer-field">
<text class="drawer-label">{{ t('sparepartInbound.creator') }}</text>
<picker class="drawer-picker-host" :range="creatorLabels" :value="creatorIndex" @change="onCreatorPickerChange">
<view class="drawer-picker">
<text :class="['drawer-picker-text', !selectedCreator ? 'placeholder' : '']">{{ selectedCreatorLabel }}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
<scroll-view v-if="creatorPanelOpen" scroll-y class="drawer-option-panel">
<view
v-for="item in creatorOptions"
:key="item.value"
:class="['drawer-option-item', selectedCreator === item.value ? 'active' : '']"
@click="selectCreator(item)"
>
<text class="drawer-option-text">{{ item.label }}</text>
<text v-if="selectedCreator === item.value" class="drawer-option-check"></text>
</view>
</scroll-view>
</view>
<view class="drawer-field drawer-field-wide">
<text class="drawer-label">{{ t('sparepartInbound.inboundTime') }}</text>
<view class="drawer-date">
<uni-datetime-picker v-model="inTimeFilter" type="daterange" :clear-icon="true"
:start-placeholder="t('sparepartInbound.startTime')"
:end-placeholder="t('sparepartInbound.endTime')" />
</view>
</picker>
</view>
<view class="drawer-field">
<text class="drawer-label">{{ t('sparepartInbound.inboundTime') }}</text>
<view class="drawer-date">
<uni-datetime-picker v-model="inTimeFilter" type="daterange" :clear-icon="true"
:start-placeholder="t('sparepartInbound.startTime')"
:end-placeholder="t('sparepartInbound.endTime')" />
</view>
</view>
</view>
@ -216,7 +202,6 @@ const filterPopupRef = ref(null)
const selectedCreator = ref(null)
const inTimeFilter = ref([])
const creatorOptions = ref([])
const creatorPanelOpen = ref(false)
const statusOptions = computed(() => [
{ label: t('sparepartInbound.tabPending'), value: '0' },
@ -245,6 +230,13 @@ const selectedCreatorLabel = computed(() => {
return found ? found.label : t('sparepartInbound.creator')
})
const creatorLabels = computed(() => [t('sparepartInbound.creator'), ...creatorOptions.value.map((o) => o.label)])
const creatorIndex = computed(() => {
if (!selectedCreator.value) return 0
const idx = creatorOptions.value.findIndex((o) => o.value === selectedCreator.value)
return idx >= 0 ? idx + 1 : 0
})
const list = ref([])
const loading = ref(false)
const loadingMore = ref(false)
@ -356,13 +348,14 @@ function confirmFilterDrawer() {
fetchList(true)
}
function toggleCreatorPanel() {
creatorPanelOpen.value = !creatorPanelOpen.value
}
function selectCreator(item) {
selectedCreator.value = selectedCreator.value === item.value ? null : item.value
creatorPanelOpen.value = false
function onCreatorPickerChange(event) {
const index = Number(event?.detail?.value || 0)
if (index === 0) {
selectedCreator.value = null
} else {
const item = creatorOptions.value[index - 1]
selectedCreator.value = item ? item.value : null
}
}
async function loadCreatorOptions() {
@ -398,6 +391,7 @@ function resetFilters() {
selectedStatus.value = ''
selectedCreator.value = null
inTimeFilter.value = []
filterPopupRef.value?.close()
fetchList(true)
}
@ -576,7 +570,7 @@ onHide(() => {})
gap: 18rpx;
}
.search-row {
.quick-row {
margin-top: 18rpx;
}
@ -719,46 +713,49 @@ onHide(() => {})
.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:last-child {
border-bottom: 0;
}
.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-picker {
min-width: 0;
flex: 1;
width: 100%;
min-height: 74rpx;
border: 0;
@ -767,71 +764,29 @@ onHide(() => {})
box-sizing: border-box;
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 {
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 {
.drawer-date {
min-width: 0;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 26rpx;
color: #1f2937;
}
.drawer-field-wide {
grid-column: 1 / -1;
}
.drawer-date {
width: 100%;
min-height: 74rpx;
border: 0;

@ -3,15 +3,6 @@
<NavBar :title="t('sparepartOutbound.moduleName')" />
<view class="filter-bar">
<view class="filter-row quick-row">
<picker :range="statusPickerLabels" :value="statusPickerIndex" @change="onStatusFilterChange">
<view class="status-filter">
<text :class="['status-filter-text', selectedStatus === '' ? 'placeholder' : '']">{{ currentStatusLabel
}}</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"
@ -23,6 +14,15 @@
<view class="icon-filter-btn" @click="openFilterDrawer"><uni-icons type="settings" size="24"
color="#7b8491"></uni-icons></view>
</view>
<view class="filter-row quick-row">
<picker :range="statusPickerLabels" :value="statusPickerIndex" @change="onStatusFilterChange">
<view class="status-filter">
<text :class="['status-filter-text', selectedStatus === '' ? 'placeholder' : '']">{{ currentStatusLabel
}}</text>
<uni-icons type="bottom" size="14" color="#a8adb7"></uni-icons>
</view>
</picker>
</view>
</view>
<uni-popup ref="filterPopupRef" class="outbound-filter-popup" type="right" background-color="transparent"
@ -30,33 +30,23 @@
<view class="filter-drawer">
<view class="drawer-header"><text class="drawer-title">{{ t('functionCommon.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('sparepartOutbound.sparepartInfo')
}}</text></view>
<view class="drawer-grid">
<view class="drawer-field drawer-field-wide"><text class="drawer-label">{{ t('sparepartOutbound.creator')
<view class="drawer-section drawer-fields">
<view class="drawer-field"><text class="drawer-label">{{ t('sparepartOutbound.creator')
}}</text>
<view class="drawer-picker" @click="toggleCreatorPanel">
<text :class="['drawer-picker-text', !selectedCreator ? 'placeholder' : '']">{{ selectedCreatorLabel
}}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
<scroll-view v-if="creatorPanelOpen" scroll-y class="drawer-option-panel">
<view v-for="item in creatorOptions" :key="item.value"
:class="['drawer-option-item', selectedCreator === item.value ? 'active' : '']"
@click="selectCreator(item)">
<text class="drawer-option-text">{{ item.label }}</text>
<text v-if="selectedCreator === item.value" class="drawer-option-check"></text>
<picker class="drawer-picker-host" :range="creatorLabels" :value="creatorIndex" @change="onCreatorPickerChange">
<view class="drawer-picker">
<text :class="['drawer-picker-text', !selectedCreator ? 'placeholder' : '']">{{ selectedCreatorLabel
}}</text>
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
</view>
</scroll-view>
</picker>
</view>
<view class="drawer-field drawer-field-wide">
<view class="drawer-field">
<text class="drawer-label">{{ t('sparepartOutbound.outboundTime') }}</text>
<view class="drawer-date"><uni-datetime-picker v-model="inTimeFilter" type="daterange"
:clear-icon="true" :start-placeholder="t('sparepartOutbound.startTime')"
:end-placeholder="t('sparepartOutbound.endTime')" /></view>
</view>
</view>
</view>
</scroll-view>
<view class="drawer-actions">
@ -165,7 +155,6 @@ const filterPopupRef = ref(null)
const selectedCreator = ref(null)
const inTimeFilter = ref([])
const creatorOptions = ref([])
const creatorPanelOpen = ref(false)
const statusOptions = computed(() => [
{ label: t('sparepartOutbound.tabPending'), value: '0' },
@ -177,6 +166,8 @@ const statusPickerLabels = computed(() => [t('sparepartOutbound.allStatus'), ...
const statusPickerIndex = computed(() => { if (selectedStatus.value === '') return 0; const idx = statusOptions.value.findIndex(i => i.value === selectedStatus.value); return idx >= 0 ? idx + 1 : 0 })
const currentStatusLabel = computed(() => { if (selectedStatus.value === '') return t('sparepartOutbound.allStatus'); const cur = statusOptions.value.find(i => i.value === selectedStatus.value); return cur ? cur.label : t('sparepartOutbound.allStatus') })
const selectedCreatorLabel = computed(() => { if (!selectedCreator.value) return t('sparepartOutbound.creator'); const found = creatorOptions.value.find(u => u.value === selectedCreator.value); return found ? found.label : t('sparepartOutbound.creator') })
const creatorLabels = computed(() => [t('sparepartOutbound.creator'), ...creatorOptions.value.map(o => o.label)])
const creatorIndex = computed(() => { if (!selectedCreator.value) return 0; const idx = creatorOptions.value.findIndex(o => o.value === selectedCreator.value); return idx >= 0 ? idx + 1 : 0 })
const list = ref([])
const loading = ref(false)
const loadingMore = ref(false)
@ -230,11 +221,18 @@ async function fetchList(reset) {
function onStatusFilterChange(event) { const index = Number(event?.detail?.value || 0); if (index === 0) { selectedStatus.value = '' } else { const item = statusOptions.value[index - 1]; selectedStatus.value = item ? item.value : '' }; fetchList(true) }
function handleSearch() { clearSearchTimer(); uni.hideKeyboard(); fetchList(true) }
function handleKeywordInput() { clearSearchTimer(); searchTimer = setTimeout(() => fetchList(true), 300) }
function resetFilters() { clearSearchTimer(); searchKeyword.value = ''; selectedStatus.value = ''; selectedCreator.value = null; inTimeFilter.value = []; fetchList(true) }
function resetFilters() { clearSearchTimer(); searchKeyword.value = ''; selectedStatus.value = ''; selectedCreator.value = null; inTimeFilter.value = []; filterPopupRef.value?.close(); fetchList(true) }
function openFilterDrawer() { loadCreatorOptions(); filterPopupRef.value?.open() }
function confirmFilterDrawer() { filterPopupRef.value?.close(); fetchList(true) }
function toggleCreatorPanel() { creatorPanelOpen.value = !creatorPanelOpen.value }
function selectCreator(item) { selectedCreator.value = selectedCreator.value === item.value ? null : item.value; creatorPanelOpen.value = false }
function onCreatorPickerChange(event) {
const index = Number(event?.detail?.value || 0)
if (index === 0) {
selectedCreator.value = null
} else {
const item = creatorOptions.value[index - 1]
selectedCreator.value = item ? item.value : null
}
}
async function loadCreatorOptions() { if (creatorOptions.value.length) return; try { const res = await getSimpleUserList(); const data = Array.isArray(res) ? res : (Array.isArray(res?.data) ? res.data : []); creatorOptions.value = data.map(u => ({ value: u.id || u.userId, label: u.nickname || u.userName || u.name || String(u.id || '') })) } catch (e) { } }
async function loadMore() { if (loading.value || loadingMore.value || finished.value) return; pageNo.value += 1; await fetchList(false) }
function openDetail(item) { if (!item?.id) { uni.showToast({ title: t('functionCommon.noIdView'), icon: 'none' }); return }; uni.navigateTo({ url: `/pages_function/pages/sparepartOutbound/detail?id=${encodeURIComponent(String(item.id))}` }) }
@ -301,7 +299,7 @@ onHide(() => { })
gap: 18rpx;
}
.search-row {
.quick-row {
margin-top: 18rpx;
}
@ -443,50 +441,49 @@ onHide(() => { })
.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-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-picker {
min-width: 0;
flex: 1;
width: 100%;
min-height: 74rpx;
border: 0;
@ -495,74 +492,29 @@ onHide(() => { })
box-sizing: border-box;
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 {
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 {
.drawer-date {
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-date {
width: 100%;
min-height: 74rpx;
border: 0;

Loading…
Cancel
Save