You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
7.0 KiB
Vue

<template>
<view class="page-container">
<NavBar :title="t('productInbound.selectTaskTitle')" />
<view class="search-bar">
<view class="search-input-wrap">
<uni-icons type="search" size="18" color="#9ca3af"></uni-icons>
<input
v-model="searchText"
class="search-input"
:placeholder="t('productInbound.searchTaskPlaceholder')"
placeholder-class="search-placeholder"
confirm-type="search"
@confirm="loadTasks"
/>
<view v-if="searchText" class="search-clear" @click="clearSearch">
<uni-icons type="closeempty" size="18" color="#9ca3af"></uni-icons>
</view>
</view>
</view>
<scroll-view scroll-y class="task-list" v-if="taskList.length">
<view
v-for="item in taskList"
:key="item.id"
:class="['task-card', isSelected(item) ? 'active' : '']"
@click="selectedId = item.id"
>
<view class="task-header">
<view class="task-title-wrap">
<text class="task-name">{{ textValue(item.code) }}</text>
<text class="task-date">{{ formatDateTime(item.orderDate || item.createTime) }}</text>
</view>
<view class="check-badge">
<uni-icons v-if="isSelected(item)" type="checkmarkempty" size="16" color="#ffffff"></uni-icons>
</view>
</view>
<view class="info-grid">
<view class="info-cell">
<text class="info-label">{{ t('productInbound.deliveryDate') }}</text>
<text class="info-value">{{ formatDateTime(item.deliveryDate) }}</text>
</view>
<view class="info-cell">
<text class="info-label">{{ t('productInbound.remark') }}</text>
<text class="info-value">{{ textValue(item.remark) }}</text>
</view>
</view>
</view>
</scroll-view>
<view v-else class="empty-wrap">
<uni-icons type="info" size="30" color="#cbd5e1"></uni-icons>
<text>{{ loading ? t('productInbound.loading') : t('productInbound.emptyTask') }}</text>
</view>
<view class="action-bar">
<view :class="['action-btn', selectedId ? '' : 'action-btn-disabled']" @click="handleConfirm">{{ t('productInbound.confirm') }}</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import NavBar from '@/components/common/NavBar.vue'
import { getTaskPage } from '@/api/mes/productInbound'
const { t } = useI18n()
const taskList = ref([])
const selectedId = ref(null)
const searchText = ref('')
const loading = ref(false)
onLoad((options) => {
selectedId.value = options?.selectedId ? String(options.selectedId) : null
})
function textValue(v) {
if (v === 0) return '0'
if (v == null) return '-'
const s = String(v).trim()
return s || '-'
}
function formatDateTime(value) {
if (!value) return '-'
if (Array.isArray(value) && value.length >= 3) {
const [year, month, day] = value
const pad = (n) => String(n).padStart(2, '0')
return `${year}-${pad(month)}-${pad(day)}`
}
const date = new Date(Number(value))
if (Number.isNaN(date.getTime())) return String(value)
const pad = (n) => String(n).padStart(2, '0')
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
}
function isSelected(item) {
return String(selectedId.value) === String(item.id)
}
function clearSearch() {
searchText.value = ''
}
function normalizeList(res) {
const root = res && res.data !== undefined ? res.data : res
return Array.isArray(root) ? root : (root?.list || root?.rows || root?.records || [])
}
async function loadTasks() {
loading.value = true
try {
const res = await getTaskPage({ pageNo: 1, pageSize: 50, code: searchText.value.trim() || undefined })
taskList.value = normalizeList(res)
} catch (e) {
uni.showToast({ title: t('productInbound.loadFailed'), icon: 'none' })
} finally {
loading.value = false
}
}
function handleConfirm() {
if (!selectedId.value) {
uni.showToast({ title: t('productInbound.selectTask'), icon: 'none' })
return
}
const task = taskList.value.find((d) => String(d.id) === String(selectedId.value))
if (!task) return
getApp().globalData._productInboundTaskSelectResult = task
uni.navigateBack()
}
onShow(loadTasks)
</script>
<style lang="scss" scoped>
.page-container { min-height: 100vh; background: #f5f7fb; padding-bottom: calc(120rpx + env(safe-area-inset-bottom)); }
.search-bar { padding: 18rpx 24rpx; background: #ffffff; box-shadow: 0 4rpx 16rpx rgba(15, 23, 42, 0.03); }
.search-input-wrap { display: flex; align-items: center; gap: 12rpx; height: 76rpx; padding: 0 22rpx; background: #f8fafc; border: 1rpx solid #e5e7eb; border-radius: 14rpx; box-sizing: border-box; }
.search-input { flex: 1; min-width: 0; font-size: 28rpx; color: #374151; }
.search-placeholder { color: #9ca3af; }
.search-clear { width: 44rpx; height: 44rpx; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.task-list { height: calc(100vh - 294rpx); }
.task-card { margin: 18rpx 24rpx 0; padding: 24rpx; background: #ffffff; border: 1rpx solid #eef2f7; border-radius: 20rpx; box-shadow: 0 6rpx 18rpx rgba(15, 23, 42, 0.04); }
.task-card.active { border-color: #bfdbfe; background: #f9fbff; box-shadow: 0 8rpx 22rpx rgba(31, 124, 255, 0.08); }
.task-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 18rpx; }
.task-title-wrap { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8rpx; }
.task-name { font-size: 30rpx; font-weight: 600; color: #1f2937; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.task-date { font-size: 24rpx; color: #8a94a6; }
.check-badge { width: 36rpx; height: 36rpx; border-radius: 18rpx; border: 1rpx solid #d1d5db; background: #ffffff; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.task-card.active .check-badge { border-color: #1f7cff; background: #1f7cff; }
.info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14rpx; margin-top: 20rpx; padding-top: 18rpx; border-top: 1rpx solid #f1f5f9; }
.info-cell { min-width: 0; display: flex; flex-direction: column; gap: 6rpx; }
.info-label { font-size: 23rpx; color: #9ca3af; }
.info-value { font-size: 27rpx; color: #374151; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.empty-wrap { height: calc(100vh - 294rpx); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14rpx; color: #94a3b8; font-size: 27rpx; }
.action-bar { position: fixed; left: 0; right: 0; bottom: 0; padding: 18rpx 24rpx calc(18rpx + env(safe-area-inset-bottom)); background: #ffffff; box-shadow: 0 -8rpx 24rpx rgba(15, 23, 42, 0.06); z-index: 99; }
.action-btn { height: 84rpx; border-radius: 16rpx; background: #1f4b79; color: #ffffff; display: flex; align-items: center; justify-content: center; font-size: 30rpx; font-weight: 600; }
.action-btn-disabled { background: #94a3b8; }
</style>