Files
crm_uiapp/src/pages-erp/stock-record/index.vue

294 lines
9.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="yd-page-container erp-page">
<!-- 顶部导航栏 -->
<wd-navbar
title="库存记录"
left-arrow placeholder safe-area-inset-top fixed
@click-left="handleBack"
/>
<!-- 搜索组件 -->
<view @click="searchVisible = true">
<wd-search :placeholder="searchPlaceholder" hide-cancel disabled />
</view>
<!-- 库存记录列表 -->
<view class="px-24rpx">
<view
v-for="item in list"
:key="item.id"
class="mb-20rpx overflow-hidden rounded-12rpx bg-white shadow-sm"
>
<view class="p-24rpx">
<!-- 头部业务单号 + 业务类型 -->
<view class="mb-16rpx flex items-center justify-between">
<view class="text-28rpx text-[#333] font-semibold">
{{ item.bizNo || '-' }}
</view>
<view
class="rounded-8rpx px-16rpx py-4rpx text-24rpx"
:class="getBizTypeClass(item.bizType)"
>
{{ getBizTypeLabel(item.bizType) }}
</view>
</view>
<!-- 产品 -->
<view class="mb-8rpx flex items-center justify-between text-26rpx text-[#666]">
<text class="text-[#999]">产品</text>
<text>{{ item.productName || '-' }}</text>
</view>
<!-- 分类 -->
<view class="mb-8rpx flex items-center justify-between text-26rpx text-[#666]">
<text class="text-[#999]">分类</text>
<text>{{ item.categoryName || '-' }}</text>
</view>
<!-- 仓库 -->
<view class="mb-8rpx flex items-center justify-between text-26rpx text-[#666]">
<text class="text-[#999]">仓库</text>
<text>{{ item.warehouseName || '-' }}</text>
</view>
<!-- 出入库日期 -->
<view class="mb-8rpx flex items-center justify-between text-26rpx text-[#666]">
<text class="text-[#999]">出入库日期</text>
<text>{{ formatDate(item.createTime) }}</text>
</view>
<!-- 操作人 -->
<view class="mb-12rpx flex items-center justify-between text-26rpx text-[#666]">
<text class="text-[#999]">操作人</text>
<text>{{ item.creatorName || '-' }}</text>
</view>
<!-- 数量区域 -->
<view class="flex items-center justify-around mt-12rpx pt-16rpx border-t border-[#f0f0f0]">
<view class="text-center">
<view
class="text-32rpx font-semibold"
:class="(item.count ?? 0) >= 0 ? 'text-[#52c41a]' : 'text-[#f5222d]'"
>
{{ formatCount(item.count) }}
</view>
<view class="text-22rpx text-[#999] mt-4rpx">出入库数量</view>
</view>
<view class="text-center">
<view class="text-32rpx text-[#1890ff] font-semibold">{{ formatCount(item.totalCount) }}</view>
<view class="text-22rpx text-[#999] mt-4rpx">库存量</view>
</view>
</view>
</view>
</view>
<!-- 加载更多 -->
<view v-if="loadMoreState !== 'loading' && list.length === 0" class="py-100rpx text-center">
<wd-status-tip image="content" tip="暂无库存记录" />
</view>
<wd-loadmore
v-if="list.length > 0"
:state="loadMoreState"
@reload="loadMore"
/>
</view>
<!-- 搜索弹窗 -->
<wd-popup v-model="searchVisible" position="top" @close="searchVisible = false">
<view class="yd-search-form-container" :style="{ paddingTop: `${getNavbarHeight()}px` }">
<view class="yd-search-form-item">
<view class="yd-search-form-label">业务单号</view>
<wd-input v-model="searchForm.bizNo" placeholder="请输入业务单号" clearable />
</view>
<view class="yd-search-form-item">
<view class="yd-search-form-label">操作类型</view>
<wd-picker
v-model="searchForm.bizType"
:columns="bizTypeColumns"
label=""
placeholder="请选择操作类型"
@confirm="onBizTypeConfirm"
/>
</view>
<view class="yd-search-form-item">
<view class="yd-search-form-label">仓库</view>
<wd-picker
v-model="searchForm.warehouseId"
:columns="warehouseColumns"
label=""
placeholder="请选择仓库"
@confirm="onWarehouseConfirm"
/>
</view>
<view class="yd-search-form-actions">
<wd-button class="flex-1" plain @click="handleReset">重置</wd-button>
<wd-button class="flex-1" type="primary" @click="handleSearch">搜索</wd-button>
</view>
</view>
</wd-popup>
</view>
</template>
<script lang="ts" setup>
import type { StockRecord } from '@/api/erp/stock-record'
import type { LoadMoreState } from '@/http/types'
import { onReachBottom } from '@dcloudio/uni-app'
import { computed, onMounted, reactive, ref } from 'vue'
import { BIZ_TYPE_OPTIONS, getStockRecordPage } from '@/api/erp/stock-record'
import { getWarehouseSimpleList } from '@/api/erp/warehouse'
import { getNavbarHeight, navigateBackPlus } from '@/utils'
definePage({
style: {
navigationBarTitleText: '',
navigationStyle: 'custom',
},
})
const total = ref(0)
const list = ref<StockRecord[]>([])
const loadMoreState = ref<LoadMoreState>('loading')
const queryParams = ref<{ pageNo: number; pageSize: number } & Record<string, any>>({
pageNo: 1,
pageSize: 10,
})
// 搜索相关
const searchVisible = ref(false)
const searchForm = reactive({
bizNo: undefined as string | undefined,
bizType: undefined as number | undefined,
warehouseId: undefined as number | undefined,
})
// 仓库列表
const warehouseList = ref<{ id?: number, name?: string }[]>([])
/** 业务类型下拉列 */
const bizTypeColumns = computed(() => [
[{ value: '', label: '全部' }, ...BIZ_TYPE_OPTIONS.map(v => ({ value: v.value, label: v.label }))],
])
/** 仓库下拉列 */
const warehouseColumns = computed(() => [
[{ value: '', label: '全部' }, ...warehouseList.value.map(v => ({ value: v.id, label: v.name }))],
])
/** 业务类型选择回调 */
function onBizTypeConfirm({ value }: any) {
searchForm.bizType = value?.[0] || undefined
}
/** 仓库选择回调 */
function onWarehouseConfirm({ value }: any) {
searchForm.warehouseId = value?.[0] || undefined
}
/** 搜索条件 placeholder */
const searchPlaceholder = computed(() => {
const conditions: string[] = []
if (searchForm.bizNo) conditions.push(`单号:${searchForm.bizNo}`)
if (searchForm.bizType !== undefined) {
const bizTypeLabel = BIZ_TYPE_OPTIONS.find(o => o.value === searchForm.bizType)?.label
if (bizTypeLabel) conditions.push(`类型:${bizTypeLabel}`)
}
if (searchForm.warehouseId) {
const warehouse = warehouseList.value.find(w => w.id === searchForm.warehouseId)
if (warehouse) conditions.push(`仓库:${warehouse.name}`)
}
return conditions.length > 0 ? conditions.join(' | ') : '搜索库存记录'
})
/** 获取业务类型标签 */
function getBizTypeLabel(bizType?: number) {
if (bizType === undefined) return '-'
return BIZ_TYPE_OPTIONS.find(o => o.value === bizType)?.label || '-'
}
/** 获取业务类型样式 */
function getBizTypeClass(bizType?: number) {
if (bizType === undefined) return 'bg-[#f0f0f0] text-[#666]'
// 入库类型:绿色
if ([1, 4, 10].includes(bizType)) return 'bg-[#f6ffed] text-[#52c41a]'
// 出库类型:红色
if ([2, 3, 11].includes(bizType)) return 'bg-[#fff1f0] text-[#f5222d]'
// 其他:蓝色
return 'bg-[#e6f7ff] text-[#1890ff]'
}
/** 格式化数量 */
function formatCount(count?: number) {
if (count === undefined || count === null) return '-'
return count >= 0 ? `+${count.toFixed(2)}` : count.toFixed(2)
}
/** 格式化日期 */
function formatDate(timestamp?: number) {
if (!timestamp) return '-'
const d = new Date(timestamp)
const pad = (n: number) => n.toString().padStart(2, '0')
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`
}
/** 返回上一页 */
function handleBack() {
navigateBackPlus()
}
/** 查询库存记录列表 */
async function getList() {
loadMoreState.value = 'loading'
try {
const params = { ...queryParams.value }
if (searchForm.bizNo) params.bizNo = searchForm.bizNo
if (searchForm.bizType !== undefined) params.bizType = searchForm.bizType
if (searchForm.warehouseId) params.warehouseId = searchForm.warehouseId
const data = await getStockRecordPage(params)
list.value = [...list.value, ...data.list]
total.value = data.total
loadMoreState.value = list.value.length >= total.value ? 'finished' : 'loading'
} catch {
queryParams.value.pageNo = queryParams.value.pageNo > 1 ? queryParams.value.pageNo - 1 : 1
loadMoreState.value = 'error'
}
}
/** 搜索 */
function handleSearch() {
searchVisible.value = false
queryParams.value = {
pageNo: 1,
pageSize: queryParams.value.pageSize,
}
list.value = []
getList()
}
/** 重置 */
function handleReset() {
searchForm.bizNo = undefined
searchForm.bizType = undefined
searchForm.warehouseId = undefined
searchVisible.value = false
queryParams.value = { pageNo: 1, pageSize: 10 }
list.value = []
getList()
}
/** 加载更多 */
function loadMore() {
if (loadMoreState.value === 'finished') return
queryParams.value.pageNo++
getList()
}
/** 触底加载更多 */
onReachBottom(() => {
loadMore()
})
/** 初始化 */
onMounted(async () => {
getList()
// 加载仓库列表
warehouseList.value = await getWarehouseSimpleList()
})
</script>
<style lang="scss" scoped>
</style>