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
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>
|