diff --git a/src/locales/en-US.js b/src/locales/en-US.js index 9b75f6e..1a1dc0b 100644 --- a/src/locales/en-US.js +++ b/src/locales/en-US.js @@ -1493,7 +1493,10 @@ export default { inboundInfo: 'Inbound Info', inboundTime: 'Inbound Time', selectInboundTime: 'Select inbound time', + placeholderInboundStartTime: 'Start time', + placeholderInboundEndTime: 'End time', operator: 'Operator', + creator: 'Creator', selectOperator: 'Select operator', inboundQuantity: 'Inbound Quantity', reviewer: 'Reviewer', @@ -1730,7 +1733,10 @@ export default { outboundInfo: 'Outbound Info', outboundTime: 'Outbound Time', selectOutboundTime: 'Select outbound time', + placeholderOutboundStartTime: 'Start time', + placeholderOutboundEndTime: 'End time', operator: 'Operator', + creator: 'Creator', selectOperator: 'Select operator', outboundQuantity: 'Outbound Qty', reviewer: 'Reviewer', diff --git a/src/locales/zh-CN.js b/src/locales/zh-CN.js index c19499e..d19e168 100644 --- a/src/locales/zh-CN.js +++ b/src/locales/zh-CN.js @@ -1471,6 +1471,7 @@ export default { inboundStatus: '入库状态', reset: '重置', clear: '清空', + moreFilter: '更多筛选', loading: '加载中...', loadingMore: '加载更多...', noMoreData: '没有更多数据', @@ -1496,7 +1497,10 @@ export default { inboundInfo: '入库信息', inboundTime: '入库时间', selectInboundTime: '请选择入库时间', + placeholderInboundStartTime: '开始时间', + placeholderInboundEndTime: '结束时间', operator: '经办人', + creator: '创建人', selectOperator: '请选择经办人', inboundQuantity: '入库数量', reviewer: '审核人', @@ -1710,6 +1714,7 @@ export default { outboundStatus: '出库状态', reset: '重置', clear: '清空', + moreFilter: '更多筛选', loading: '加载中...', loadingMore: '加载更多...', noMoreData: '没有更多数据', @@ -1731,7 +1736,10 @@ export default { outboundInfo: '出库信息', outboundTime: '出库时间', selectOutboundTime: '请选择出库时间', + placeholderOutboundStartTime: '开始时间', + placeholderOutboundEndTime: '结束时间', operator: '经办人', + creator: '创建人', selectOperator: '请选择经办人', outboundQuantity: '出库数量', reviewer: '审核人', diff --git a/src/pages_function/pages/productInbound/index.vue b/src/pages_function/pages/productInbound/index.vue index 6e05507..71d1677 100644 --- a/src/pages_function/pages/productInbound/index.vue +++ b/src/pages_function/pages/productInbound/index.vue @@ -3,25 +3,42 @@ - - + + + + {{ selectedProductLabel }} + + + + + + {{ selectedStatusLabel || t('productInbound.inboundStatus') }} + + + - - {{ selectedStatusLabel || t('productInbound.inboundStatus') }} - + + + + + + + + + + - {{ t('productInbound.reset') }} - - - - {{ t('productInbound.selectInboundStatus') }} - - {{ t('productInbound.clear') }} - + + + + {{ t('productInbound.moreFilter') }} - - - {{ option.label }} - + + + + {{ t('productInbound.inboundTime') }} + + + + + + {{ t('productInbound.warehouse') }} + + + {{ selectedWarehouseLabel }} + + + + + + {{ t('productInbound.creator') }} + + + {{ selectedCreatorLabel }} + + + + + + {{ t('productInbound.remark') }} + + + + {{ t('productInbound.reset') }} + {{ t('productInbound.confirm') }} + @@ -144,20 +200,85 @@ import { onReady, onShow, onUnload } from '@dcloudio/uni-app' import { useI18n } from 'vue-i18n' import NavBar from '@/components/common/NavBar.vue' import { auditProductInbound, getProductInboundPage, submitProductInbound } from '@/api/mes/productInbound' +import { getProductSimpleList } from '@/api/erp/productInfo' +import { getWarehouseSimpleList } from '@/api/mes/moldget' +import { getSimpleUserList } from '@/api/system/user' const { t } = useI18n() const selectedStatus = ref('') +const selectedProductId = ref('') +const selectedWarehouseId = ref('') +const selectedCreatorId = ref('') const searchKeyword = ref('') -const statusPickerRef = ref(null) +const inTimeFilter = ref([]) +const remarkFilter = ref('') +const filterPopupRef = ref(null) +const productList = ref([]) +const warehouseList = ref([]) +const creatorList = ref([]) +const filterOptionsLoaded = ref(false) const statusOptions = computed(() => [ + { label: t('functionCommon.all'), value: '' }, { label: t('productInbound.statusPending'), value: '0' }, + { label: t('productInbound.statusRejected'), value: '1' }, { label: t('productInbound.statusAuditing'), value: '10' }, { label: t('productInbound.statusStored'), value: '20' } ]) +const statusLabels = computed(() => statusOptions.value.map((item) => item.label)) +const statusPickerIndex = computed(() => { + const index = statusOptions.value.findIndex((item) => String(item.value) === String(selectedStatus.value)) + return index >= 0 ? index : 0 +}) const selectedStatusLabel = computed(() => { - const current = statusOptions.value.find((item) => item.value === selectedStatus.value) + if (selectedStatus.value === '') return '' + const current = statusOptions.value.find((item) => String(item.value) === String(selectedStatus.value)) return current ? current.label : '' }) +const productPickerOptions = computed(() => [ + { label: t('functionCommon.all'), value: '' }, + ...productList.value.map((item) => ({ + label: item.name || item.productName || item.code || String(item.id || ''), + value: item.id + })) +]) +const productPickerIndex = computed(() => { + const index = productPickerOptions.value.findIndex((item) => String(item.value) === String(selectedProductId.value)) + return index >= 0 ? index : 0 +}) +const selectedProductLabel = computed(() => { + if (selectedProductId.value === '') return t('productInbound.product') + return productPickerOptions.value.find((item) => String(item.value) === String(selectedProductId.value))?.label || t('productInbound.product') +}) +const warehousePickerOptions = computed(() => [ + { label: t('functionCommon.all'), value: '' }, + ...warehouseList.value.map((item) => ({ + label: item.name || item.warehouseName || item.code || String(item.id || ''), + value: item.id + })) +]) +const warehousePickerIndex = computed(() => { + const index = warehousePickerOptions.value.findIndex((item) => String(item.value) === String(selectedWarehouseId.value)) + return index >= 0 ? index : 0 +}) +const selectedWarehouseLabel = computed(() => { + if (selectedWarehouseId.value === '') return t('functionCommon.all') + return warehousePickerOptions.value.find((item) => String(item.value) === String(selectedWarehouseId.value))?.label || t('functionCommon.all') +}) +const creatorPickerOptions = computed(() => [ + { label: t('functionCommon.all'), value: '' }, + ...creatorList.value.map((item) => ({ + label: item.nickname || item.userName || item.name || String(item.id || ''), + value: item.id + })) +]) +const creatorPickerIndex = computed(() => { + const index = creatorPickerOptions.value.findIndex((item) => String(item.value) === String(selectedCreatorId.value)) + return index >= 0 ? index : 0 +}) +const selectedCreatorLabel = computed(() => { + if (selectedCreatorId.value === '') return t('functionCommon.all') + return creatorPickerOptions.value.find((item) => String(item.value) === String(selectedCreatorId.value))?.label || t('functionCommon.all') +}) const list = ref([]) const loading = ref(false) const loadingMore = ref(false) @@ -220,6 +341,39 @@ function normalizePageData(res) { } } +function normalizeListResponse(res) { + const root = res && res.data !== undefined ? res.data : res + return Array.isArray(root) ? root : (Array.isArray(root?.list) ? root.list : []) +} + +function formatQueryDate(value, isEnd) { + if (!value) return undefined + const text = String(value).trim() + if (!text) return undefined + if (text.includes(':')) return text + return text + ' ' + (isEnd ? '23:59:59' : '00:00:00') +} + +async function ensureFilterOptions() { + if (filterOptionsLoaded.value) return + filterOptionsLoaded.value = true + try { + const [productRes, warehouseRes, creatorRes] = await Promise.all([ + getProductSimpleList({ categoryType: 1 }), + getWarehouseSimpleList(), + getSimpleUserList() + ]) + productList.value = normalizeListResponse(productRes) + warehouseList.value = normalizeListResponse(warehouseRes) + creatorList.value = normalizeListResponse(creatorRes) + } catch (e) { + filterOptionsLoaded.value = false + productList.value = [] + warehouseList.value = [] + creatorList.value = [] + } +} + async function fetchList(reset) { if (reset) { pageNo.value = 1 @@ -229,11 +383,19 @@ async function fetchList(reset) { else loadingMore.value = true try { const keyword = searchKeyword.value.trim() + const remark = remarkFilter.value.trim() + const inTimeRange = Array.isArray(inTimeFilter.value) ? inTimeFilter.value : [] const res = await getProductInboundPage({ pageNo: pageNo.value, pageSize: pageSize.value, no: keyword || undefined, - status: selectedStatus.value || undefined + productId: selectedProductId.value === '' ? undefined : selectedProductId.value, + warehouseId: selectedWarehouseId.value === '' ? undefined : selectedWarehouseId.value, + creator: selectedCreatorId.value === '' ? undefined : selectedCreatorId.value, + statusList: selectedStatus.value === '' ? undefined : [Number(selectedStatus.value)], + remark: remark || undefined, + 'inTime[0]': formatQueryDate(inTimeRange[0], false), + 'inTime[1]': formatQueryDate(inTimeRange[1], true) }) const page = normalizePageData(res) list.value = reset ? page.list : [...list.value, ...page.list] @@ -246,7 +408,6 @@ async function fetchList(reset) { loadingMore.value = false } } - async function handleSearch() { clearSearchTimer() uni.hideKeyboard() @@ -269,22 +430,43 @@ async function resetFilters() { clearSearchTimer() searchKeyword.value = '' selectedStatus.value = '' + selectedProductId.value = '' + selectedWarehouseId.value = '' + selectedCreatorId.value = '' + inTimeFilter.value = [] + remarkFilter.value = '' + closeFilterDrawer() activateKeywordFocus() await fetchList(true) } -function openStatusPicker() { - statusPickerRef.value?.open() +function openFilterDrawer() { + filterPopupRef.value?.open() } -async function selectStatus(option) { - selectedStatus.value = option.value - statusPickerRef.value?.close() +function closeFilterDrawer() { + filterPopupRef.value?.close() +} +async function confirmFilterDrawer() { + closeFilterDrawer() await fetchList(true) } -async function resetStatus() { - selectedStatus.value = '' - statusPickerRef.value?.close() +async function onProductFilterChange(event) { + const index = Number(event?.detail?.value || 0) + selectedProductId.value = productPickerOptions.value[index]?.value === '' ? '' : String(productPickerOptions.value[index]?.value ?? '') await fetchList(true) } +async function onStatusFilterChange(event) { + const index = Number(event?.detail?.value || 0) + selectedStatus.value = statusOptions.value[index]?.value ?? '' + await fetchList(true) +} +function onWarehouseFilterChange(event) { + const index = Number(event?.detail?.value || 0) + selectedWarehouseId.value = warehousePickerOptions.value[index]?.value === '' ? '' : String(warehousePickerOptions.value[index]?.value ?? '') +} +function onCreatorFilterChange(event) { + const index = Number(event?.detail?.value || 0) + selectedCreatorId.value = creatorPickerOptions.value[index]?.value === '' ? '' : String(creatorPickerOptions.value[index]?.value ?? '') +} async function loadMore() { if (loading.value || loadingMore.value || finished.value) return pageNo.value += 1 @@ -408,27 +590,72 @@ onReady(() => { focusKeywordNoKeyboard() }) -onShow(() => { +onShow(async () => { consumeSelectedAuditor() - fetchList(true) + await ensureFilterOptions() + await fetchList(true) }) onUnload(() => clearSearchTimer()) diff --git a/src/pages_function/pages/productOutbound/index.vue b/src/pages_function/pages/productOutbound/index.vue index 7afe907..9286730 100644 --- a/src/pages_function/pages/productOutbound/index.vue +++ b/src/pages_function/pages/productOutbound/index.vue @@ -3,25 +3,42 @@ - - + + + + {{ selectedProductLabel }} + + + + + + {{ selectedStatusLabel || t('productOutbound.outboundStatus') }} + + + - - {{ selectedStatusLabel || t('productOutbound.outboundStatus') }} - + + + + + + + + + + - {{ t('productOutbound.reset') }} - - - - {{ t('productOutbound.selectOutboundStatus') }} - - {{ t('productOutbound.clear') }} - + + + + {{ t('productOutbound.moreFilter') }} - - - {{ option.label }} - + + + + {{ t('productOutbound.outboundTime') }} + + + + + + {{ t('productOutbound.warehouse') }} + + + {{ selectedWarehouseLabel }} + + + + + + {{ t('productOutbound.creator') }} + + + {{ selectedCreatorLabel }} + + + + + + {{ t('productOutbound.remark') }} + + + + {{ t('productOutbound.reset') }} + {{ t('productOutbound.confirm') }} + @@ -144,21 +200,85 @@ import { onReady, onShow, onUnload } from '@dcloudio/uni-app' import { useI18n } from 'vue-i18n' import NavBar from '@/components/common/NavBar.vue' import { auditProductOutbound, getProductOutboundPage, submitProductOutbound } from '@/api/mes/productOutbound' +import { getProductSimpleList } from '@/api/erp/productInfo' +import { getWarehouseSimpleList } from '@/api/mes/moldget' +import { getSimpleUserList } from '@/api/system/user' const { t } = useI18n() const selectedStatus = ref('') +const selectedProductId = ref('') +const selectedWarehouseId = ref('') +const selectedCreatorId = ref('') const searchKeyword = ref('') -const statusPickerRef = ref(null) +const outTimeFilter = ref([]) +const remarkFilter = ref('') +const filterPopupRef = ref(null) +const productList = ref([]) +const warehouseList = ref([]) +const creatorList = ref([]) +const filterOptionsLoaded = ref(false) const statusOptions = computed(() => [ + { label: t('functionCommon.all'), value: '' }, { label: t('productOutbound.statusPending'), value: '0' }, + { label: t('productOutbound.statusRejected'), value: '1' }, { label: t('productOutbound.statusAuditing'), value: '10' }, - { label: t('productOutbound.statusStored'), value: '20' }, - { label: t('productOutbound.statusRejected'), value: '1' } + { label: t('productOutbound.statusStored'), value: '20' } ]) +const statusLabels = computed(() => statusOptions.value.map((item) => item.label)) +const statusPickerIndex = computed(() => { + const index = statusOptions.value.findIndex((item) => String(item.value) === String(selectedStatus.value)) + return index >= 0 ? index : 0 +}) const selectedStatusLabel = computed(() => { - const current = statusOptions.value.find((item) => item.value === selectedStatus.value) + if (selectedStatus.value === '') return '' + const current = statusOptions.value.find((item) => String(item.value) === String(selectedStatus.value)) return current ? current.label : '' }) +const productPickerOptions = computed(() => [ + { label: t('functionCommon.all'), value: '' }, + ...productList.value.map((item) => ({ + label: item.name || item.productName || item.code || String(item.id || ''), + value: item.id + })) +]) +const productPickerIndex = computed(() => { + const index = productPickerOptions.value.findIndex((item) => String(item.value) === String(selectedProductId.value)) + return index >= 0 ? index : 0 +}) +const selectedProductLabel = computed(() => { + if (selectedProductId.value === '') return t('productOutbound.product') + return productPickerOptions.value.find((item) => String(item.value) === String(selectedProductId.value))?.label || t('productOutbound.product') +}) +const warehousePickerOptions = computed(() => [ + { label: t('functionCommon.all'), value: '' }, + ...warehouseList.value.map((item) => ({ + label: item.name || item.warehouseName || item.code || String(item.id || ''), + value: item.id + })) +]) +const warehousePickerIndex = computed(() => { + const index = warehousePickerOptions.value.findIndex((item) => String(item.value) === String(selectedWarehouseId.value)) + return index >= 0 ? index : 0 +}) +const selectedWarehouseLabel = computed(() => { + if (selectedWarehouseId.value === '') return t('functionCommon.all') + return warehousePickerOptions.value.find((item) => String(item.value) === String(selectedWarehouseId.value))?.label || t('functionCommon.all') +}) +const creatorPickerOptions = computed(() => [ + { label: t('functionCommon.all'), value: '' }, + ...creatorList.value.map((item) => ({ + label: item.nickname || item.userName || item.name || String(item.id || ''), + value: item.id + })) +]) +const creatorPickerIndex = computed(() => { + const index = creatorPickerOptions.value.findIndex((item) => String(item.value) === String(selectedCreatorId.value)) + return index >= 0 ? index : 0 +}) +const selectedCreatorLabel = computed(() => { + if (selectedCreatorId.value === '') return t('functionCommon.all') + return creatorPickerOptions.value.find((item) => String(item.value) === String(selectedCreatorId.value))?.label || t('functionCommon.all') +}) const list = ref([]) const loading = ref(false) const loadingMore = ref(false) @@ -222,6 +342,39 @@ function normalizePageData(res) { } } +function normalizeListResponse(res) { + const root = res && res.data !== undefined ? res.data : res + return Array.isArray(root) ? root : (Array.isArray(root?.list) ? root.list : []) +} + +function formatQueryDate(value, isEnd) { + if (!value) return undefined + const text = String(value).trim() + if (!text) return undefined + if (text.includes(':')) return text + return text + ' ' + (isEnd ? '23:59:59' : '00:00:00') +} + +async function ensureFilterOptions() { + if (filterOptionsLoaded.value) return + filterOptionsLoaded.value = true + try { + const [productRes, warehouseRes, creatorRes] = await Promise.all([ + getProductSimpleList({ categoryType: 1 }), + getWarehouseSimpleList(), + getSimpleUserList() + ]) + productList.value = normalizeListResponse(productRes) + warehouseList.value = normalizeListResponse(warehouseRes) + creatorList.value = normalizeListResponse(creatorRes) + } catch (e) { + filterOptionsLoaded.value = false + productList.value = [] + warehouseList.value = [] + creatorList.value = [] + } +} + async function fetchList(reset) { if (reset) { pageNo.value = 1 @@ -231,11 +384,19 @@ async function fetchList(reset) { else loadingMore.value = true try { const keyword = searchKeyword.value.trim() + const remark = remarkFilter.value.trim() + const outTimeRange = Array.isArray(outTimeFilter.value) ? outTimeFilter.value : [] const res = await getProductOutboundPage({ pageNo: pageNo.value, pageSize: pageSize.value, no: keyword || undefined, - statusList: selectedStatus.value !== '' ? [Number(selectedStatus.value)] : undefined + productId: selectedProductId.value === '' ? undefined : selectedProductId.value, + warehouseId: selectedWarehouseId.value === '' ? undefined : selectedWarehouseId.value, + creator: selectedCreatorId.value === '' ? undefined : selectedCreatorId.value, + statusList: selectedStatus.value !== '' ? [Number(selectedStatus.value)] : undefined, + remark: remark || undefined, + 'outTime[0]': formatQueryDate(outTimeRange[0], false), + 'outTime[1]': formatQueryDate(outTimeRange[1], true) }) const page = normalizePageData(res) list.value = reset ? page.list : [...list.value, ...page.list] @@ -248,7 +409,6 @@ async function fetchList(reset) { loadingMore.value = false } } - async function handleSearch() { clearSearchTimer() uni.hideKeyboard() @@ -271,22 +431,43 @@ async function resetFilters() { clearSearchTimer() searchKeyword.value = '' selectedStatus.value = '' + selectedProductId.value = '' + selectedWarehouseId.value = '' + selectedCreatorId.value = '' + outTimeFilter.value = [] + remarkFilter.value = '' + closeFilterDrawer() activateKeywordFocus() await fetchList(true) } -function openStatusPicker() { - statusPickerRef.value?.open() +function openFilterDrawer() { + filterPopupRef.value?.open() } -async function selectStatus(option) { - selectedStatus.value = option.value - statusPickerRef.value?.close() +function closeFilterDrawer() { + filterPopupRef.value?.close() +} +async function confirmFilterDrawer() { + closeFilterDrawer() await fetchList(true) } -async function resetStatus() { - selectedStatus.value = '' - statusPickerRef.value?.close() +async function onProductFilterChange(event) { + const index = Number(event?.detail?.value || 0) + selectedProductId.value = productPickerOptions.value[index]?.value === '' ? '' : String(productPickerOptions.value[index]?.value ?? '') await fetchList(true) } +async function onStatusFilterChange(event) { + const index = Number(event?.detail?.value || 0) + selectedStatus.value = statusOptions.value[index]?.value ?? '' + await fetchList(true) +} +function onWarehouseFilterChange(event) { + const index = Number(event?.detail?.value || 0) + selectedWarehouseId.value = warehousePickerOptions.value[index]?.value === '' ? '' : String(warehousePickerOptions.value[index]?.value ?? '') +} +function onCreatorFilterChange(event) { + const index = Number(event?.detail?.value || 0) + selectedCreatorId.value = creatorPickerOptions.value[index]?.value === '' ? '' : String(creatorPickerOptions.value[index]?.value ?? '') +} async function loadMore() { if (loading.value || loadingMore.value || finished.value) return pageNo.value += 1 @@ -410,27 +591,72 @@ onReady(() => { focusKeywordNoKeyboard() }) -onShow(() => { +onShow(async () => { consumeSelectedAuditor() - fetchList(true) + await ensureFilterOptions() + await fetchList(true) }) onUnload(() => clearSearchTimer())