<!-- eslint-disable no-console -->
<!--
* @Author: Ashun
* @Date: 2022-07-19 20:08:49
* @LastEditors: zzd993
* @LastEditTime: 2022-07-26 18:21:36
* @FilePath: \elabnote-front-main\src\views\inventory\components\out-in-stock\query-detail\components\WillRecallStockTable.vue
* Copyright (c) 2022 by BMY, All Rights Reserved.
-->
<template>
<div>
<div class="will-recall-stock-table">
<BasicTable
ref="tableRef"
rowKey="id"
:loading="loading"
:columns="columns"
:data="(data as any)"
:pagination="pagination"
:rowSelection="rowSelection"
v-model:selectedRowKeys="selectedKeys"
v-model:selectedRows="selectedRows"
:scroll="{
y: 630
}"
column-resizable
:bordered="{ headerCell: true }"
>
<template #customTitle>
<div v-if="true" class="custom-title-box">
<a-space>
已选定 {{ selectedKeys.length }} 个
<a-button size="small" @click="confirmRecallStock">返库</a-button>
</a-space>
</div>
</template>
<!-- 个性化展示的列👇 -->
<!-- 序号 -->
<template #serialNumber="{ item }">
{{ computedShowSerialNumber(item.record.index + 1) }}
</template>
<!-- 容量 -->
<template #applyCapacity="{ item }"> {{ item.record.applyCapacity }}{{ item.record.unitName }} </template>
<!-- 内容物 -->
<template #embedInfo="{ item }">
<EmbedInfo :record="item.record.embedInfo" isShowTooltip />
</template>
<!-- operates -->
<template #operates>
<a-link> 返库 </a-link>
</template>
<!-- 预计返库时间 -->
<template #col_time_recallDate="{ item }">
<span>
{{ handleShowDynamicParam({ type: ParameterType.MOMENT, value: item.record.recallDate }) }}
</span>
</template>
<!-- 返库申请时间 -->
<template #col_time_recallApplyTime="{ item }">
<span>
{{ handleShowDynamicParam({ type: ParameterType.MOMENT, value: item.record.recallApplyTime }) }}
</span>
</template>
</BasicTable>
</div>
<ConfirmRecallStockModal ref="ConfirmRecallStockModalRef" @refreshTable="handleRefreshTable" />
</div>
</template>
<script lang="ts">
type tooltipPosition =
| 'lb'
| 'left'
| 'right'
| 'bottom'
| 'top'
| 'tl'
| 'tr'
| 'bl'
| 'br'
| 'rt'
| 'lt'
| 'rb'
| undefined
//一些表格配置
const rowSelection = {
showCheckedAll: true
}
</script>
<script lang="ts" setup>
import ConfirmRecallStockModal from './ConfirmRecallStockModal.vue'
//components
import EmbedInfo from '@/components/EmbedInfo/index.vue'
//api
import { getWarehouseInventorynList } from '@/api/material'
//utils
import { watch, ref, reactive, computed, nextTick } from 'vue'
import { useFetch } from '@/hooks/useFetch'
import { handleShowDynamicParam } from '@/util/tools/showDynamicParam'
import { StockSearchColumns, formatTableData } from '@/views/inventory/components/out-in-stock/utils'
//types
import { ParameterType } from '@/common/enum'
//store
import { useOutInStockStore } from '@/store/modules/inventory/out-in-stock'
import { TableData } from '@arco-design/web-vue'
const outInStockStore = useOutInStockStore()
const Emiter = defineEmits(['changePagination'])
const data = ref([])
const columns = ref<[]>(StockSearchColumns[outInStockStore.currentNodeType] as [])
const selectedKeys = ref<string[]>([])
const initialSelectedKeys = () => {
selectedKeys.value = []
tableRef?.value?.clearSelectedKeysCache?.()
}
const ConfirmRecallStockModalRef = ref<InstanceType<typeof ConfirmRecallStockModal> | null>(null)
const tableRef = ref()
const {
loading,
fetchResource: refreshTable,
result: refreshTableRes
} = useFetch(getWarehouseInventorynList, { isLazy: true })
/**
* 获取消费、返库列表
* @param {{pageIndex: number, pageSize: number, recallStatus?: number, keyword?: string}} data
* @returns {Object}
*/
refreshTable(outInStockStore.willRecallStockSearchInfo)
//获取最新的列表数据
watch(refreshTableRes, () => {
data.value = Array.from(formatTableData(refreshTableRes.value?.data))
console.log(data.value)
})
/**
* 侦听全局维护的 searchTriggerNum 的改变,刷新列表
*/
watch(
() => outInStockStore.searchTriggerNum,
async () => {
if (isInitialPresetPagination.value) {
const searchInfo = outInStockStore.willRecallStockSearchInfo
await refreshTable(searchInfo)
} else {
initialPresetPagination()
}
initialSelectedKeys()
refreshTableScroll()
}
)
/**
* 初始化表格的滚动条
*/
function refreshTableScroll() {
nextTick(() => {
const tableBody = document.querySelector('will-recall-stock-table .arco-table-body')
tableBody?.scroll({ top: 0, left: 1, behavior: 'smooth' })
})
}
/**
* 分页相关
*/
let paginationInfo = reactive({
pageNum: 1,
pageSize: 10
})
const isInitialPresetPagination = computed(() => {
return paginationInfo.pageNum === 1 && paginationInfo.pageSize === 10
})
function initialPresetPagination() {
paginationInfo.pageNum = 1
paginationInfo.pageSize = 10
}
const pagination = computed(() => {
const { pageNum, pageSize } = paginationInfo
return {
total: refreshTableRes.value?.totalRecords,
showPageSize: true,
current: pageNum,
pageSize,
//页码改变时触发
onChange: (current) => {
paginationInfo.pageNum = current
Emiter('changePagination', { paginationInfo })
},
//数据条数改变时触发
onPageSizeChange: (pageSize) => {
paginationInfo.pageNum = 1
paginationInfo.pageSize = pageSize
Emiter('changePagination', { paginationInfo })
}
}
})
//侦听分页信息,刷新列表数据
watch(paginationInfo, (newPagination) => {
const { pageNum, pageSize } = newPagination
const newSearchInfo = { ...outInStockStore.willRecallStockSearchInfo, pageIndex: pageNum, pageSize }
outInStockStore.coverWillRecallStockSearchInfo({ searchInfo: newSearchInfo })
// //触发搜索Trigger
// outInStockStore.searchTrigger()
refreshTable(outInStockStore.willRecallStockSearchInfo)
})
/**
* 个性化展示列相关逻辑
*/
//合理展示序号列
function computedShowSerialNumber(num) {
const { pageNum, pageSize } = paginationInfo
const showNum = (pageNum - 1) * pageSize + num
return showNum
}
const tooltipPosition: tooltipPosition = 'lb'
/**
* 确认返库相关业务
*/
const selectedRows = ref<TableData[] | undefined>(void 0)
function confirmRecallStock() {
ConfirmRecallStockModalRef.value?.openModal(
selectedKeys.value,
selectedRows.value as Exclude<TableData[] | undefined, undefined>
)
}
const handleRefreshTable = () => {
outInStockStore.searchTrigger()
}
</script>
<style scoped lang="scss"></style>


<!--
* @Author: Ashun
* @Date: 2022-07-19 20:08:15
* @LastEditors: zzd993
* @LastEditTime: 2022-07-27 18:16:19
* @FilePath: \elabnote-front-main\src\views\inventory\components\out-in-stock\query-detail\components\WillOutStockTable.vue
* Copyright (c) 2022 by BMY, All Rights Reserved.
-->
<template>
<div class="will-out-stock-table">
// 自己封装的表单组件
<BasicTable
ref="tableRef"
rowKey="id"
:loading="loading"
:columns="columns" // 展示的每一列的表头信息
:data="(data as any)" // 表格数据
:pagination="pagination"
:rowSelection="rowSelection"
v-model:selectedRowKeys="selectedKeys"
v-model:selectedRows="selectedRows"
:scroll="{
y: 630
}"
column-resizable
:bordered="{ headerCell: true }"
>
<template #customTitle>
<div v-if="true" class="custom-title-box">
<a-space>
已选定{{ selectedKeys.length }}个 <a-button size="mini" @click="confirmRecallStock">确认出库</a-button>
<a-button size="mini" @click="revokeRecallStock">撤销出库</a-button>
</a-space>
</div>
</template>
<!-- 个性化展示的列👇 -->
<!-- 序号 -->
<template #serialNumber="{ item }"> // item表示数据中的每一列数据,是子组件通过作用域插槽传递来的
{{ computedShowSerialNumber(item.record.index + 1) }}
</template>
<!-- 状态 -->
<template #col_status="{ item }">
<a-tag :color="showStatus(item.record.statusId)?.color">
{{ showStatus(item.record.statusId)?.label }}
</a-tag>
</template>
<!-- 库存编号 -->
<template #col_stockNo="{ item }">
<a-link> {{ item.record.entityCode }} </a-link>
</template>
<!-- 注册&批次信息 -->
<template #col_productAndBatchInfo="{ item }">
<a-tooltip :position="tooltipPosition">
<template #content>{{ item.record.productName }} </template>
<a-tag> {{ item.record.productName }} </a-tag>
</a-tooltip>
</template>
<!-- 存储容器 -->
<template #col_locationPath="{ item }">
<a-link> {{ item.record.locationPath }} </a-link>
</template>
<!-- 位置 -->
<template #col_location="{ item }">
<a-link> {{ item.record.location }} </a-link>
</template>
<!-- 入库时间 -->
<template #col_time_confirmTime="{ item }">
<span>
{{ handleShowDynamicParam({ type: ParameterType.MOMENT, value: item.record.confirmTime }) }}
</span>
</template>
<!-- 截止日期 -->
<template #col_time_expirationDate="{ item }">
<span>
{{ handleShowDynamicParam({ type: ParameterType.MOMENT, value: item.record.expirationDate }) }}
</span>
</template>
</BasicTable>
<StockOutModal ref="StockOutModalRef" @ok="confirmRecallStockOk" :confirm="true" />
<RevokeOutModal ref="RevokeOutModalRef" @ok="revokeRecallStockOk" :confirm="true" />
</div>
</template>
<script lang="ts">
type tooltipPosition =
| 'lb'
| 'left'
| 'right'
| 'bottom'
| 'top'
| 'tl'
| 'tr'
| 'bl'
| 'br'
| 'rt'
| 'lt'
| 'rb'
| undefined
//一些表格配置
const rowSelection = {
showCheckedAll: true
}
</script>
<script lang="ts" setup>
//api
import { queryInventoryGoods } from '@/api/material'
//utils
import { computed, reactive, ref, watch, nextTick } from 'vue'
import { useFetch } from '@/hooks/useFetch' // 调接封装的函数
import { EntityStatusLabelTypeEnumStatus } from '@/common/constant'
import { handleShowDynamicParam } from '@/util/tools/showDynamicParam'
import { StockSearchColumns, formatTableData } from '@/views/inventory/components/out-in-stock/utils'
import { TabKeys } from '@/views/inventory/components/out-in-stock/type'
//types
// import { TabKeys } from '@/views/inventory/components/out-in-stock/type'
import { ParameterType } from '@/common/enum'
//store
import { useOutInStockStore } from '@/store/modules/inventory/out-in-stock'
import StockOutModal from '@/views/inventory/components/StockOutModal.vue'
import RevokeOutModal from '@/views/inventory/components/RevokeOutModal.vue'
import { TableData } from '@arco-design/web-vue'
const outInStockStore = useOutInStockStore() // pinia实例
// ref
const StockOutModalRef = ref<InstanceType<typeof StockOutModal> | null>(null)
const RevokeOutModalRef = ref<InstanceType<typeof RevokeOutModal> | null>(null)
const Emiter = defineEmits(['changePagination'])
// const Props = defineProps<{
// currentTabKey: WarehouseInventoryActionTypeEnum
// }>()
const data = ref([])
//请求表格数据的接口
const {
loading,
result: refreshTableRes,
fetchResource: refreshTable
} = useFetch(queryInventoryGoods, {
isLazy: true
})
// refreshTable(outInStockStore.willOutStockSearchInfo)
const columns = ref<[]>(StockSearchColumns[outInStockStore.currentNodeType] as []) // 表格表头信息
const selectedKeys = ref<string[]>([])
const initialSelectedKeys = () => {
selectedKeys.value = []
tableRef?.value?.clearSelectedKeysCache?.()
}
const selectedRows = ref<Array<TableData>>()
const tableRef = ref()
//获取最新的列表数据
watch(refreshTableRes, (res) => {
data.value = Array.from(formatTableData((res as any).data))
})
/**
* 侦听全局维护的 searchTriggerNum 的改变,刷新列表
*/
watch(
() => outInStockStore.searchTriggerNum,
async () => {
if (outInStockStore.currentNodeType !== Number(TabKeys.WILL_OUT_STOCK)) return
if (isInitialPresetPagination.value) {
// const currentNodeType = outInStockStore.currentNodeType
// const searchInfoName = stockStatusMapSearchInfoName[currentNodeType]
// const searchInfo = outInStockStore[searchInfoName]
const searchInfo = outInStockStore.willOutStockSearchInfo
await refreshTable(searchInfo)
} else {
initialPresetPagination()
}
initialSelectedKeys()
refreshTableScroll()
}
)
/**
* 初始化表格的滚动条
*/
function refreshTableScroll() {
nextTick(() => {
const tableBody = document.querySelector('will-in-stock-table .arco-table-body')
tableBody?.scroll({ top: 0, left: 1, behavior: 'smooth' })
})
}
/**
* 分页相关
*/
let paginationInfo = reactive({
pageNum: 1,
pageSize: 10
})
const isInitialPresetPagination = computed(() => {
return paginationInfo.pageNum === 1 && paginationInfo.pageSize === 10
})
function initialPresetPagination() {
paginationInfo.pageNum = 1
paginationInfo.pageSize = 10
}
const pagination = computed(() => {
const { pageNum, pageSize } = paginationInfo
return {
total: refreshTableRes.value?.totalRecords,
showPageSize: true,
current: pageNum,
pageSize,
//页码改变时触发
onChange: (current) => {
paginationInfo.pageNum = current
Emiter('changePagination', { paginationInfo })
},
//数据条数改变时触发
onPageSizeChange: (pageSize) => {
paginationInfo.pageNum = 1
paginationInfo.pageSize = pageSize
Emiter('changePagination', { paginationInfo })
}
}
})
//侦听分页信息,刷新列表数据
watch(paginationInfo, (newPagination) => {
const { pageNum, pageSize } = newPagination
const newSearchInfo = { ...outInStockStore.willOutStockSearchInfo, pageNum, pageSize }
outInStockStore.coverWillOutStockSearchInfo({ searchInfo: newSearchInfo })
// //触发搜索Trigger
// outInStockStore.searchTrigger()
refreshTable(outInStockStore.willOutStockSearchInfo)
})
/**
* 个性化展示列相关逻辑
*/
//合理展示序号列
function computedShowSerialNumber(num) {
const { pageNum, pageSize } = paginationInfo
const showNum = (pageNum - 1) * pageSize + num
return showNum
}
//合理展示状态
function showStatus(statusNum) {
return EntityStatusLabelTypeEnumStatus[statusNum]
}
const tooltipPosition: tooltipPosition = 'lb'
/**
* 确认返库
*/
async function confirmRecallStock() {
StockOutModalRef.value?.openModal(selectedRows.value!)
}
/**
* 撤销出库
*/
async function revokeRecallStock() {
RevokeOutModalRef.value?.openModal(selectedRows.value!)
}
/**
* 确认返库成功后的操作
*/
const confirmRecallStockOk = async () => {
outInStockStore.searchTrigger()
outInStockStore.coverStockStatusTotalNum()
}
const revokeRecallStockOk = async () => {
outInStockStore.searchTrigger()
outInStockStore.coverStockStatusTotalNum()
}
</script>
<style scoped lang="scss"></style>
<!--
* @Author: zhangy
* @Date: 2022-07-21 17:38:07
* @LastEditors: zzd993
* @LastEditTime: 2022-07-27 18:00:54
* @FilePath: \elabnote-front-main\src\views\inventory\components\StockOutModal.vue
* Copyright (c) 2022 by BMY, All Rights Reserved.
-->
<template>
<a-modal
:width="900"
:visible="visible"
title-align="start"
:title="Props.confirm ? '出库确认' : '出库'"
@cancel="handleCancel"
@ok="handleOk"
:okText="Props.confirm ? '确认出库' : '确认'"
>
<BasicTable :columns="columns" :data="data" :pagination="false">
<template #capacity="{ item }" v-if="!Props.confirm">
<a-input-number :min="0" :max="item.record.capacity" type="text" v-model="item.record.actualCapacity" />
</template>
<template #productName="{ item }">
<a-tag> {{ item.record[item.column.dataIndex] }} </a-tag>
</template>
<template #isStocked="{ item }">
<span>{{
item.record[item.column.dataIndex] ? showRetainOriginStocks(item.record[item.column.dataIndex]) : ''
}}</span>
</template>
</BasicTable>
<a-form v-if="!Props.confirm" ref="FormRef" :model="form" :style="{ width: '200px' }" layout="vertical">
<a-form-item field="recallDate" label="如果需要返库,请选择返库时间">
<a-date-picker v-model="form.recallDate" style="width: 100%" />
</a-form-item>
<a-form-item field="isLocaked" label="请确认是否保留原库位" validate-trigger="change" :rules="retainRules">
<a-select v-model="form.isLocaked" allow-clear style="width: 100%" placeholder="请选择是否保留">
<a-option :key="item.value" :value="item.value" v-for="item in RetainOriginStocks">{{ item.label }}</a-option>
</a-select>
</a-form-item>
</a-form>
</a-modal>
</template>
<script setup lang="ts">
import { StockActionTypeEnum, SystemYesNoEnum } from '@/common/enum'
import { computed, reactive, readonly, ref } from 'vue'
import type { TableColumnData, TableData, Form } from '@arco-design/web-vue'
import { commitStock, outStock } from '@/api/material'
const visible = ref<boolean>(false)
const Props = withDefaults(defineProps<{ confirm?: boolean }>(), {
confirm: false
})
const FormRef = ref<InstanceType<typeof Form> | null>(null)
const RetainOriginStocks = readonly([
{
label: '是',
value: SystemYesNoEnum.YES
},
{
label: '否',
value: SystemYesNoEnum.NO
}
])
const form = reactive<{ recallDate: Date | string; isLocaked: SystemYesNoEnum }>({
recallDate: undefined as unknown as Date,
isLocaked: undefined as unknown as SystemYesNoEnum
})
const retainRules = computed(() => {
if (form.recallDate) {
return [{ required: true, message: '必填' }]
}
return []
})
const STOCK_COLUMNS: Array<TableColumnData> = [
{
title: '序号',
width: 80,
render: ({ rowIndex }) => rowIndex + 1
},
{
title: '位置',
dataIndex: 'location',
width: 80,
ellipsis: true,
tooltip: true
},
{
title: '存储容器',
dataIndex: 'locationPath',
width: 80,
ellipsis: true,
tooltip: true
},
{
title: '出库量',
dataIndex: 'capacity',
slotName: 'capacity',
width: 80,
ellipsis: true,
tooltip: true
},
{
title: '量单位',
dataIndex: 'unitName',
width: 80,
ellipsis: true,
tooltip: true
},
{
title: '库存编号',
dataIndex: 'entityCode',
width: 80,
ellipsis: true,
tooltip: true
},
{
title: '注册编号',
dataIndex: 'prefix',
width: 80,
ellipsis: true,
tooltip: true
},
{
title: '注册&批次信息',
dataIndex: 'productName',
slotName: 'productName',
width: 130,
ellipsis: true,
tooltip: true
}
]
const CONFIRM_STOCK_COLUMNS: Array<TableColumnData> = [
{
title: '是否保留原库位',
dataIndex: 'isStocked',
slotName: 'isStocked',
width: 130,
ellipsis: true,
tooltip: true
}
// {
// title: '预计返库时间',
// dataIndex: 'recallDate',
// slotName: 'recallDate',
// width: 130,
// ellipsis: true,
// tooltip: true
// }
]
const columns = computed(() => {
if (Props.confirm) {
return ([] as Array<TableColumnData>).concat(STOCK_COLUMNS).concat(CONFIRM_STOCK_COLUMNS)
}
return STOCK_COLUMNS
})
const data = ref<Array<TableData>>([])
const handleCancel = () => {
visible.value = false
}
/**
* 是否保留原库位
*/
const showRetainOriginStocks = (isLocaked: SystemYesNoEnum) => {
return RetainOriginStocks.find((item) => item.value === isLocaked)?.label
}
/**
* 确定
*/
const handleOk = async () => {
if (!Props.confirm) {
FormRef.value!.validate()
const stockOutConsumers = data.value.map((item) => {
return {
productEntityId: item.id as string,
actualCapacity: item.actualCapacity as number,
recallDate: form.recallDate as unknown as string
}
})
await outStock({ stockOutConsumers, isLocked: form.isLocaked })
} else {
await commitStock({ productEntityIds: data.value.map((item) => item.id), actionType: StockActionTypeEnum.OUT })
}
handleCancel()
Emits('ok')
}
interface IEmitType {
(e: 'ok'): void
}
const Emits = defineEmits<IEmitType>()
defineExpose({
openModal: (list: Array<TableData>) => {
data.value = list.map((item) => ({ ...item, actualCapacity: item.capacity ?? 0 }))
visible.value = true
}
})
</script>
<style scoped lang="scss">
:deep(.arco-form-item-label) {
color: $font3Color;
font-size: 14px;
margin-top: 8px;
}
:deep(.arco-form-item) {
margin-bottom: 0;
}
</style>