Commit ba93e883 by zhuzhequan

Merge remote-tracking branch 'origin/zzq_bill_order' into zzq_bill_order

# Conflicts:
#	src/api/warehouse.ts
parents 2583792b e63ec0ef
......@@ -4,19 +4,20 @@ import {
warehouseSearchForm,
InterWarehousePage,
InterWarehouseTree,
InterWarehouseDetail,
InterskuList,
InterWarehouseList,
ILocation,
InRecordEditForm,
} from '@/types/api/warehouse'
export interface LogListData{
createTime:string
description:string
export interface LogListData {
createTime: string
description: string
}
export interface PrintData{
code:string
list:{
locationName:string,
locationName:string;
pickingLocation?:string
skuName?:string
warehouseSku?:string
......@@ -28,9 +29,9 @@ export interface factoryWarehouseInfo {
pageSize: number
currentPage: number
total?: number
warehouseId?: string;
locationName?: string;
remark?: string;
warehouseId?: string
locationName?: string
remark?: string
}
export interface WarehouseInventory {
......@@ -54,55 +55,54 @@ export interface WarehouseInventory {
}
export interface UpdateDefaulted {
id?: number | string;
defaulted: number;
id?: number | string
defaulted: number
}
export interface UpdateStatus {
id?: number;
status: number | undefined;
id?: number
status: number | undefined
}
export interface warehouseInfo {
id?: number | string;
name: string;
code: string;
sort: string;
defaulted: number;
factoryId?: number;
factoryCode?: string;
id?: number | string
name: string
code: string
sort: string
defaulted: number
factoryId?: number
factoryCode?: string
remarks: string
}
export interface WarehouseWarning {
id: number | string;
locationCode: string;
id: number | string
locationCode: string
skuName: string;
warehouseSku: string;
productNumber: string;
number: string;
locationName: string;
locationName: string
}
export interface positionInfo {
id?: number;
warehouseId?: string | number;
locationName: string;
pickingOrder: string;
locationCode: string;
warehouseName?: string;
status?: number;
id?: number
warehouseId?: string | number
locationName: string
pickingOrder: string
locationCode: string
warehouseName?: string
status?: number
remark: string
}
export interface positionFormInfo {
id?: number;
warehouseId?: number | string;
locationName: string;
pickingOrder: string;
locationCode: string;
warehouseName: string;
id?: number
warehouseId?: number | string
locationName: string
pickingOrder: string
locationCode: string
warehouseName: string
remark: string
status: number
}
......@@ -165,10 +165,10 @@ export function factoryLogWarehouseLog(id: number | string | undefined) {
)
}
export function factoryWarehouseInfoPrint(data:PrintData) {
export function factoryWarehouseInfoPrint(data: PrintData) {
return axios.post<never, BaseRespData<never[]>>(
'/factoryWarehouseInfo/print',
data
data,
)
}
......@@ -260,7 +260,7 @@ export function deleteWarehouseInventory(ids: string) {
// 入库单
export function warehouseInRecordListPage(
export function warehouseInRecordListPageApi(
data: warehouseSearchForm,
currentPage: number,
pageSize: number,
......@@ -276,19 +276,24 @@ export function warehouseInRecordListPage(
}
export function addInRecordApi(form: InRecordEditForm) {
return axios.post<never, BaseRespData<never>>('factory/warehouseInRecord/add', {
...form,
})
return axios.post<never, BaseRespData<never>>(
'factory/warehouseInRecord/add',
{
...form,
},
)
}
export function updateInRecordApi(form: InRecordEditForm) {
return axios.post<never, BaseRespData<never>>('factory/warehouseInRecord/update', {
...form,
})
return axios.post<never, BaseRespData<never>>(
'factory/warehouseInRecord/update',
{
...form,
},
)
}
export function getWarehouseInRecordDetail(id: number) {
return axios.get<never, BaseRespData<never>>(
export function getWarehouseInRecordDetailApi(id: number) {
return axios.get<never, BaseRespData<InterWarehouseDetail[]>>(
'factory/warehouseInRecord/get',
{
params: {
......@@ -297,8 +302,7 @@ export function getWarehouseInRecordDetail(id: number) {
},
)
}
export function getBySku(warehouseId: number, sku: string | null) {
export function getBySkuApi(warehouseId: number, sku: string | null) {
return axios.get<never, BaseRespData<InterskuList[]>>(
'customProductItem/getBySku',
{
......@@ -309,8 +313,10 @@ export function getBySku(warehouseId: number, sku: string | null) {
},
)
}
export function getByWareHouseIdAndCode(wareHouseId: number, code: string | null) {
export function getByWareHouseIdAndCodeApi(
wareHouseId: number,
code: string | null,
) {
return axios.get<never, BaseRespData<ILocation[]>>(
'factoryWarehouseLocation/getByWareHouseIdAndCode',
{
......@@ -321,8 +327,7 @@ export function getByWareHouseIdAndCode(wareHouseId: number, code: string | null
},
)
}
export function getWarehouseStatusTree() {
export function getInRecordStatusTree() {
return axios.get<never, BaseRespData<InterWarehouseTree[]>>(
'factory/warehouseInRecord/status_tree',
)
......@@ -333,3 +338,51 @@ export function getWarehouseListApi() {
'factoryWarehouseInfo/getAll',
)
}
interface WarehouseParams {
id: number
dataVersion: number
}
export function auditOrderApi(url: string, data: WarehouseParams[]) {
return axios.post(url, data)
}
export function deleteWarehouseInRecordApi(ids: string) {
return axios.get<never, BaseRespData<never>>(
'factory/warehouseInRecord/delete',
{
params: { ids },
},
)
}
export function getInRecordLogApi(inRecordId?: number) {
return axios.get<never, BaseRespData<LogListData[]>>(
`factory/warehouseInRecord/log/${inRecordId}`,
)
}
// 出库单
export function getOutRecordStatusTree() {
return axios.get<never, BaseRespData<InterWarehouseTree[]>>(
'factory/warehouseOutRecord/status_tree',
)
}
export function warehouseOutRecordListPage(
data: warehouseSearchForm,
currentPage: number,
pageSize: number,
) {
return axios.post<never, BasePaginationData<InterWarehousePage>>(
'factory/warehouseOutRecord/list_page',
{
...data,
currentPage,
pageSize,
},
)
}
export function deleteWarehouseOutRecordApi(ids: string) {
return axios.get<never, BaseRespData<never>>(
'factory/warehouseOutRecord/delete',
{
params: { ids },
},
)
}
<template>
<div
class="image-view"
ref="imageViewRef"
class="image-view"
@mouseover="(ev) => mouseoverImg(ev, src)"
@mouseleave="mouseleaveImg"
>
......
......@@ -7,8 +7,23 @@ export interface warehouseSearchForm {
sku?: string
warehouseId?: number
}
// 主表列表ts,看新增时是不是一样
export interface InterWarehousePage {
export interface InterProductList {
createTime?: string
id?: number
inId?: number
productNo?: string | null //custom的货号
buyStored?: number | null
remark?: string | null
skuImage?: string
skuName?: string
costPrice?: number | null
totalPrice?: number | null
updateTime?: string
warehouseSku?: string
locationId?: number | null
locationCode?: string | null
}
export interface InterWarehouseBase {
id: number
factoryId?: number
factoryCode?: string
......@@ -16,28 +31,20 @@ export interface InterWarehousePage {
warehouseName?: string
inNo?: string
shipmentNumber?: string
skuAmount?: string
skuAmount?: number
total?: number
totalPrice?: number
billStatus?: string
remark?: string
productList?: InterProductList[]
remark?: string | null
dataVersion?: number
createTime?: string | null
updateTime?: string | null
}
export interface InterWarehouseDetail {
id?: string
inId?: string
productNo?: string
warehouseSku?: string
skuImage?: string
skuName?: string
buyStored?: string
totalPrice?: number
rejectsAmount?: string
rejectsReason?: string
remark?: string
factoryId?: number
createTime?: string
updateTime?: string
// 主表列表ts
export interface InterWarehousePage extends InterWarehouseBase {}
// 子表列表ts
export interface InterWarehouseDetail extends InterWarehouseBase {
productList: InterProductList[]
}
export interface InterWarehouseTree {
id: number
......@@ -49,14 +56,13 @@ export interface InterWarehouseTree {
}
export interface InterProductList {
createTime?: string
factoryId?: number
id?: number
inId?: number
productNo?: string | null //货号
buyStored?: number | null //入库数量
rejectsAmount?: number
rejectsReason?: string
remark?: string
// rejectsAmount?: number
// rejectsReason?: string
remark?: string | null
skuImage?: string
skuName?: string
costPrice?: number | null
......
......@@ -10,8 +10,34 @@ export default function useImagePreview() {
img.style.width = '300px'
div.appendChild(img)
document.body.appendChild(div)
let currentTarget: HTMLElement | null = null
const mousemoveHandler = (ev: MouseEvent) => {
if (!currentTarget) return
const rect = currentTarget.getBoundingClientRect()
const inOrigin =
ev.clientX >= rect.left &&
ev.clientX <= rect.right &&
ev.clientY >= rect.top &&
ev.clientY <= rect.bottom
const divRect = div.getBoundingClientRect()
const inPreview =
ev.clientX >= divRect.left &&
ev.clientX <= divRect.right &&
ev.clientY >= divRect.top &&
ev.clientY <= divRect.bottom
if (!inOrigin && !inPreview) {
div.style.display = 'none'
show.value = false
window.removeEventListener('mousemove', mousemoveHandler)
currentTarget = null
}
}
const mouseoverImg = (ev: MouseEvent, url: string) => {
console.log(url, ev.clientY, ev.clientX)
ev.preventDefault()
if (show.value === true) return
img.src = url
......@@ -30,12 +56,16 @@ export default function useImagePreview() {
div.style.top = y + 'px'
div.style.display = 'block'
show.value = true
currentTarget = ev.currentTarget as HTMLElement
window.addEventListener('mousemove', mousemoveHandler)
}
}
const mouseleaveImg = () => {
if (show.value === false) return
div.style.display = 'none'
show.value = false
}
return { mouseoverImg, mouseleaveImg }
}
......@@ -9,14 +9,17 @@
:highlight-current="true"
node-key="code"
:data="treeData"
:props="{ children: 'children', label: 'remark' }"
:props="{ children: 'children', label: 'name' }"
@node-click="nodeClick"
>
<template #default="{ data }">
<div class="tree-node">
<div class="tree-node-label">{{ data.remark }}</div>
<div v-if="data.count || data.count === 0" class="tree-node-count">
{{ `(${data.count})` }}
<div class="tree-node-label">{{ data.name }}</div>
<div
v-if="data.countQuantity || data.countQuantity === 0"
class="tree-node-count"
>
{{ `(${data.countQuantity})` }}
</div>
</div>
</template>
......@@ -28,9 +31,25 @@
<template #top>
<div class="header-filter-form">
<ElForm :model="searchForm" inline>
<ElFormItem label="账期">
<ElFormItem label="采购仓库">
<ElSelect
v-model="searchForm.warehouseId"
clearable
placeholder="请选择仓库"
style="width: 160px"
>
<ElOption
v-for="item in warehouseList"
:key="item.id"
:label="item.name"
:value="item.id"
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="入库时间">
<el-date-picker
v-model="dateRange"
v-model="tradingTime"
:shortcuts="pickerOptions.shortcuts"
:default-time="[
new Date(0, 0, 0, 0, 0, 0),
new Date(0, 0, 0, 23, 59, 59),
......@@ -44,28 +63,27 @@
value-format="YYYY-MM-DD HH:mm:ss"
/>
</ElFormItem>
<ElFormItem label="对账单号">
<ElFormItem label="单号">
<ElInput
v-model="searchForm.recNumber"
v-model="searchForm.orderNumber"
clearable
placeholder="对账单号"
placeholder="请输入入库单号"
style="width: 160px"
/>
</ElFormItem>
<ElFormItem label="货单号">
<ElFormItem label="货单号">
<ElInput
v-model="searchForm.billNumber"
v-model="searchForm.batchNumber"
clearable
placeholder="货单号"
placeholder="请输入交货单号"
style="width: 160px"
/>
</ElFormItem>
<ElFormItem style="margin-right: 10px" label="订单号">
<ElFormItem style="margin-right: 10px" label="SKU">
<ElInput
v-model="searchForm.orderNumber"
v-model="searchForm.sku"
clearable
placeholder="订单号"
placeholder="请输入SKU"
style="width: 160px"
/>
</ElFormItem>
......@@ -79,26 +97,22 @@
</ElForm>
</div>
<div class="btn-list">
<el-button
v-if="nodeId === 10"
type="primary"
@click="confirmOrder"
>
确认对账单
</el-button>
<el-button
v-if="nodeId === 10"
type="warning"
@click="rejectOrder"
>
驳回
<el-button type="primary" @click="addDialog(1)"> 新增 </el-button>
<el-button type="danger" @click="rejectOrder"> 驳回 </el-button>
<el-button type="danger" @click="handleBatchDelete">
删除
</el-button>
<el-button type="warning" @click="importExcel"> 导入 </el-button>
<el-button type="success" @click="exportExcel"> 导出 </el-button>
<el-button
v-if="nodeId === 30"
type="danger"
@click="auditOrder('archive')"
>
<el-button type="primary" @click="exportExcel">
打印SKU标签
</el-button>
<el-button type="warning" @click="exportExcel"> 审核 </el-button>
<el-button type="success" @click="exportExcel">
提交审核
</el-button>
<el-button type="danger" @click="rejectOrder"> 作废 </el-button>
<el-button type="success" @click="auditOrder('archive')">
归档
</el-button>
</div>
......@@ -110,8 +124,6 @@
ref="singleTableRef"
highlight-current-row
:data="tableData"
show-summary
:summary-method="getSummaries"
default-expand-all
size="small"
style="width: 100%; height: 100%"
......@@ -134,164 +146,91 @@
align="center"
></ElTableColumn>
<ElTableColumn
label="编码"
label="入库单号"
show-overflow-tooltip
prop="name"
width="200"
prop="inNo"
width="110"
header-align="center"
align="center"
></ElTableColumn>
<!-- <ElTableColumn
label="客户"
show-overflow-tooltip
prop="user_mark"
width="200"
header-align="center"
align="center"
></ElTableColumn> -->
<ElTableColumn
label="对账单号"
label="单据状态"
show-overflow-tooltip
prop="rec_number"
min-width="200"
prop="billStatus"
width="80"
header-align="center"
align="center"
></ElTableColumn>
<!-- <ElTableColumn
label="订单号"
show-overflow-tooltip
prop="order_number"
width="200"
header-align="center"
align="center"
></ElTableColumn> -->
<!-- <ElTableColumn
label="ERP总价格"
show-overflow-tooltip
width="130"
prop="erp_total_amount"
header-align="center"
align="center"
></ElTableColumn> -->
<el-table-column
label="账期"
header-align="center"
align="center"
min-width="340"
>
<template #default="scope">
{{ scope.row.start_time }} - {{ scope.row.end_time }}
</template>
</el-table-column>
<el-table-column
label="商品总价格(¥)"
header-align="center"
prop="product_total_amount"
width="130"
align="center"
show-overflow-tooltip
>
</el-table-column>
<!-- <el-table-column
label="ERP总价格"
header-align="center"
prop="erp_total_amount"
width="120"
align="center"
show-overflow-tooltip
>
</el-table-column> -->
<el-table-column
label="物流总价(¥)"
header-align="center"
prop="carriage_total_amount"
width="130"
align="center"
<ElTableColumn
label="仓库名称"
show-overflow-tooltip
></el-table-column>
<el-table-column
label="应付金额(¥)"
prop="warehouseName"
min-width="100"
header-align="center"
width="130"
align="center"
show-overflow-tooltip
>
<template #default="{ row }">
<span>{{
row.carriage_total_amount + row.product_total_amount
}}</span>
</template>
</el-table-column>
<el-table-column
label="实付金额(¥)"
header-align="center"
prop="actual_amount"
width="130"
align="center"
></ElTableColumn>
<ElTableColumn
label="工厂编号"
show-overflow-tooltip
></el-table-column>
<el-table-column
label="水单"
prop="factoryCode"
min-width="100"
header-align="center"
prop="water_list"
width="100"
align="center"
show-overflow-tooltip
>
<template #default="{ row }">
<ImageView :src="row.water_list" />
</template>
</el-table-column>
></ElTableColumn>
<ElTableColumn
label="发货数量(件)"
label="物流单号"
show-overflow-tooltip
width="100"
prop="carriage_total_amount"
prop="shipmentNumber"
width="200"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="总发货数量(件)"
label="总金额(¥)"
show-overflow-tooltip
prop="num"
width="130"
width="120"
prop="totalPrice"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="质检通过数量(件)"
show-overflow-tooltip
prop="pass_num"
width="130"
label="SKU数量"
header-align="center"
prop="skuAmount"
width="130"
align="center"
></ElTableColumn>
<!-- <ElTableColumn
label="ERP状态"
show-overflow-tooltip
width="130"
prop="erp_status"
>
</ElTableColumn>
<ElTableColumn
label="总数量"
header-align="center"
prop="total"
width="120"
align="center"
></ElTableColumn> -->
show-overflow-tooltip
>
</ElTableColumn>
<ElTableColumn
label="质检未通过数量(件)"
label="备注"
show-overflow-tooltip
width="140"
prop="not_pass_num"
width="240"
prop="remark"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="创建时间"
show-overflow-tooltip
width="200"
prop="create_time"
header-align="center"
width="100"
align="center"
></ElTableColumn>
header-align="center"
label="操作"
>
<template #default="{ row }">
<ElButton type="primary" link @click="addDialog(2, row)"
>编辑
</ElButton>
</template>
</ElTableColumn>
</ElTable>
</div>
<ElPagination
......@@ -309,39 +248,7 @@
</template>
<template #bottom>
<el-tabs v-model="tabsValue" @tab-click="tabsClick">
<el-tab-pane name="0" label="发货单详情">
<el-form :model="detailForm" inline>
<el-form-item label="发货单号">
<el-input
v-model="detailForm.billNumber"
placeholder="请输入发货单号"
clearable
style="width: 130px"
/>
</el-form-item>
<el-form-item label="订单号">
<el-input
v-model="detailForm.orderNumber"
placeholder="请输入订单号"
clearable
style="width: 130px"
/>
</el-form-item>
<el-form-item label="生产单号">
<el-input
v-model="detailForm.subOrderNumber"
placeholder="请输入订单号"
clearable
style="width: 130px"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="searchDetail"
>查询</el-button
>
</el-form-item>
</el-form>
<el-tab-pane name="0" label="入库商品">
<div class="table-wrap">
<ElTable size="small" :data="detailList" height="100%" border>
<ElTableColumn
......@@ -354,77 +261,74 @@
<ElTableColumn
show-overflow-tooltip
align="center"
label="单号"
label="SKU图片"
prop="factory_order_number"
/>
<!-- <ElTableColumn
show-overflow-tooltip
align="center"
label="ERP单号"
prop="erp_order_number"
/> -->
>
<template #default="{ row }">
<ImageView
:src="row.skuImage"
width="80px"
height="80px"
/>
</template>
</ElTableColumn>
<ElTableColumn
show-overflow-tooltip
align="center"
label="发货单号"
prop="bill_number"
label="商品SKU"
prop="warehouseSku"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="发货数(件)"
prop="num"
label="SKU名称"
prop="skuName"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="质检通过(件)"
prop="pass_num"
label="入库数量"
prop="buyStored"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="质检不通过(件)"
prop="not_pass_num"
label="总成本(¥)"
prop="buyStored"
/>
<!-- <ElTableColumn
show-overflow-tooltip
align="center"
label="ERP价格"
prop="erp_price"
/> -->
<ElTableColumn
show-overflow-tooltip
align="center"
label="成本价(¥)"
prop="price"
label="不良品数量"
prop="rejectsAmount"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="物流价格(¥)"
prop="carriage_amount"
label="不良品原因"
prop="rejectsAeason"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="发货时间"
prop="shipment_time"
width="240"
label="备注"
prop="remark"
/>
<ElTableColumn
width="100"
show-overflow-tooltip
align="center"
header-align="center"
label="操作"
>
<template #default="{ row }">
<ElButton type="primary" link @click="onDetail(row)"
>查看详情
</ElButton>
</template>
</ElTableColumn>
label="创建时间"
prop="createTime"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="更新时间"
prop="updateTime"
/>
</ElTable>
</div>
......@@ -440,7 +344,7 @@
@current-change="handleCurrentChange"
></ElPagination>
</el-tab-pane>
<el-tab-pane name="1" label="操作日志">
<!-- <el-tab-pane name="1" label="操作日志">
<ul
style="
color: #333;
......@@ -455,125 +359,515 @@
style="display: flex"
>
<span style="display: inline-block">
{{ item.create_time }}
{{ item.createdTime }}
</span>
<span style="margin: 0 5px 0 20px">{{
item.employee_account
}}</span>
<span style="display: inline-block">{{
item.description
}}</span>
</li>
</ul>
</el-tab-pane>
<el-tab-pane name="2" label="物流轨迹">
<ul
v-if="logisticsData.length > 0"
style="
color: #333;
font-size: 12px;
height: 100%;
overflow: auto;
"
>
<li v-for="(item, index) in logisticsData" :key="index">
<span class="log-desc">
{{ item.time + ' ' + item.context }}
</span>
</li>
</ul>
<div v-else class="empty">{{ $t('暂无数据') }}</div>
</el-tab-pane> -->
</el-tabs>
</template>
</splitDiv>
</div>
</div>
</div>
<ElDrawer
v-model="shipmentOrderDetailDrawerVisible"
title="发货单详情"
size="50%"
>
<shipmentOrderDetailInfo :detail="shipmentOrderDetail" />
</ElDrawer>
<ElDialog
v-model="confirmOrderVisible"
title="确认对账单"
v-model="importDialogVisible"
title="导入"
width="500px"
:close-on-click-modal="false"
>
<ElForm ref="auditFormRef" :model="auditForm" label-width="80px">
<ElFormItem
label="意见"
prop="pass"
:rules="[{ required: true, message: '请选择' }]"
>
<ElRadioGroup v-model="auditForm.pass">
<ElRadio :label="1">通过</ElRadio>
<ElRadio :label="0">不通过</ElRadio>
</ElRadioGroup>
</ElFormItem>
<ElFormItem
label="审核意见"
prop="description"
:rules="
auditForm.pass === 0
? [{ required: true, message: '请输入审核意见' }]
: []
"
>
<ElInput v-model="auditForm.description" type="textarea" />
</ElFormItem>
</ElForm>
<div class="import-dialog">
<div class="import-header">
<el-button type="primary" link @click="downloadTemplate">
<el-icon><Download /></el-icon>
下载模板
</el-button>
</div>
<div class="import-content">
<UploadExcel v-model="importedFileUrl" />
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="confirmOrderVisible = false">取消</el-button>
<el-button @click="importDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitConfirmOrder">确认</el-button>
</span>
</template>
</ElDialog>
<ElDialog
v-model="newDialogVisible"
:title="formId ? '编辑' : '新增'"
width="80%"
:close-on-click-modal="false"
>
<div class="dialog-form">
<ElForm
ref="editFormRef"
:model="editForm"
:rules="rules"
inline
label-width="90px"
>
<ElFormItem label="入库单号" prop="account">
<ElInput v-model="editForm.inNo" clearable disabled />
</ElFormItem>
<ElFormItem label="仓库" prop="warehouseId" required>
<ElSelect
v-model="editForm.warehouseId"
clearable
placeholder="请选择仓库"
style="width: 160px"
>
<ElOption
v-for="item in warehouseList"
:key="item.id"
:label="item.name"
:value="item.id"
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="工厂:" prop="factoryCode">
<span>{{ editForm.factoryCode }}</span>
</ElFormItem>
<ElFormItem label="备注" prop="remark" style="width: 45%">
<ElInput
v-model="editForm.remark"
placeholder="请输入备注"
clearable
/>
</ElFormItem>
</ElForm>
<ElTable
size="small"
:data="otherPurchaseData"
height="500px"
border
@selection-change="productSelectionChange"
>
<ElTableColumn
type="selection"
width="70"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
show-overflow-tooltip
align="center"
width="100"
label="SKU图片"
prop="skuImage"
>
<template #default="{ row }">
<ImageView :src="row.skuImage" width="40px" height="40px" />
</template>
</ElTableColumn>
<ElTableColumn
show-overflow-tooltip
align="center"
label="商品SKU"
prop="warehouseSku"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="SKU名称"
prop="skuName"
/>
<ElTableColumn align="center" label="入库数量" prop="buyStored">
<template #default="{ row }">
<el-input
v-model.number="row.buyStored"
placeholder="入库数量"
style="width: 120px"
clearable
size="small"
@input="setCostPrice(row)"
></el-input>
</template>
</ElTableColumn>
<ElTableColumn
width="100"
align="center"
label="成本价(¥)"
prop="costPrice"
/>
<ElTableColumn
align="center"
width="100"
label="总成本(¥)"
prop="totalPrice"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="不良品数量"
prop="rejectsAmount"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="不良品原因"
prop="rejectsAeason"
/>
<ElTableColumn align="center" label="库位" prop="loacationCode">
<template #default="{ row }">
<!-- +后有就正常展示,没有则通过搜索接口自己添加 -->
<span v-if="row.loacationCode">{{ row.loacationCode }}</span>
<ElSelect
v-else
v-model="row.locationId"
clearable
placeholder="请输入库位"
style="width: 120px"
filterable
remote
:remote-method="(query) => handleLocationSearch(query, row)"
:loading="locationLoading"
@change="(val) => handleLocationChange(val, row)"
>
<ElOption
v-for="item in locationList"
:key="item.locationId"
:label="item.locationCode"
:value="item.locationId"
></ElOption>
</ElSelect>
</template>
</ElTableColumn>
<ElTableColumn
show-overflow-tooltip
align="center"
width="240"
label="备注"
prop="remark"
/>
</ElTable>
</div>
<template #footer>
<div class="product-dialog-footer">
<div>
<el-input
v-model="selectSku"
placeholder="商品SKU"
style="width: 200px; margin: 0 10px"
clearable
size="small"
></el-input>
<el-popover placement="top-start" width="900" trigger="click">
<div v-if="skuData.length > 0" style="height: 50vh">
<ElTable size="small" :data="skuData" height="100%" border>
<ElTableColumn
show-overflow-tooltip
width="60"
align="center"
label="序号"
type="index"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="SKU图片"
width="100"
prop="image"
>
<template #default="{ row }">
<ImageView :src="row.image" width="40px" height="40px" />
</template>
</ElTableColumn>
<ElTableColumn
show-overflow-tooltip
align="center"
label="商品SKU"
width="200"
prop="skuName"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
width="200"
label="SKU名称"
prop="sku"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="成本价(¥)"
width="100"
prop="factoryPrice"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="库位"
prop="loacationCode"
/>
<ElTableColumn
width="100"
align="center"
header-align="center"
label="操作"
>
<template #default="{ row }">
<el-icon :size="32" color="#67C23A"
><CirclePlusFilled @click="skudblclick(row)"
/></el-icon>
</template>
</ElTableColumn>
</ElTable>
</div>
<template #reference>
<el-button
type="primary"
size="small"
style="width: 90px"
@click="selectbySku()"
>
查询
</el-button>
</template>
</el-popover>
<el-button
style="margin-left: 6px"
type="success"
size="small"
@click="addPurchase"
>
批量新增
</el-button>
<el-button
type="danger"
style="margin-left: 10px"
size="small"
@click="deleteOtherWarehousing()"
>
删除
</el-button>
<el-button
type="primary"
style="margin-left: 10px"
size="small"
@click="importData"
>
导入
</el-button>
</div>
<div>
<el-button
size="small"
style="margin-left: 10px"
@click="newDialogVisible = false"
>
取消
</el-button>
<el-button type="primary" size="small" @click="addOtherCurrency()">
保存
</el-button>
</div>
</div>
</template>
</ElDialog>
</template>
<script setup lang="ts">
import { ElMessage, ElRadioGroup, ElTree, TableColumnCtx } from 'element-plus'
import { Download, CirclePlusFilled } from '@element-plus/icons-vue'
import splitDiv from '@/components/splitDiv/splitDiv.vue'
import { ElTable } from 'element-plus'
import usePageList from '@/utils/hooks/usePageList'
import { useValue } from '@/utils/hooks/useValue'
import {
customJomallReconciliation,
getReconciliationAmount,
getShipmentDetailsById,
auditOrderApi,
getShipmentOrderDetailById,
confirmOrderApi,
rejectOrderApi,
getLogListApi,
exportExcelApi,
} from '@/api/order'
import {
getOutRecordStatusTree,
warehouseOutRecordListPage,
getWarehouseInRecordDetailApi,
getBySkuApi,
getWarehouseListApi,
getByWareHouseIdAndCodeApi,
addInRecordApi,
updateInRecordApi,
deleteWarehouseOutRecordApi,
} from '@/api/warehouse'
import BigNumber from 'bignumber.js'
import { ref, onMounted, watch, nextTick } from 'vue'
import 'element-plus/dist/index.css'
import { LogList } from '@/types/api/billOrder.ts'
import {
CountStatus,
AccountStatementNote,
ItemList,
LogList,
AccountStatementNoteSearchForm,
} from '@/types/api/billOrder.ts'
import { DetailForm, ShipmentOrderDetailData } from '@/types/api/deliveryNote'
import shipmentOrderDetailInfo from '@/components/ShipmentOrderDetail.vue'
warehouseSearchForm,
InterWarehousePage,
InterWarehouseDetail,
InterWarehouseTree,
InterProductList,
InterskuList,
InterWarehouseList,
ILocation,
} from '@/types/api/warehouse'
import ImageView from '@/components/ImageView.vue'
import { showConfirm } from '@/utils/ui'
// import { getUserMarkList } from '@/api/auth.ts'
interface Tree {
remark?: string
count?: number
code?: string
children?: Tree[]
import UploadExcel from '@/components/UploadExcel.vue'
import { debounce } from 'lodash-es'
// import UploadExcel from '@/components/INgoVopy.vue'
const warehouseList = ref<InterWarehouseList[]>([])
const pickerOptions = {
shortcuts: [
{
text: '今日',
value: () => {
const start = new Date(new Date(getStartTime()).getTime())
const end = new Date()
return [start, end]
},
},
{
text: '昨天',
value: () => {
const start = new Date()
const end = new Date(new Date(getStartTime()).getTime() - 1)
start.setTime(end.getTime() - 3600 * 1000 * 24 * 1 + 1)
return [start, end]
},
},
{
text: '最近7天',
value: () => {
const end = new Date()
const start = new Date(getStartTime())
start.setTime(start.getTime() - 3600 * 1000 * 24 * 6)
return [start, end]
},
},
{
text: '最近14天',
value: () => {
const end = new Date()
const start = new Date(getStartTime())
start.setTime(start.getTime() - 3600 * 1000 * 24 * 13)
return [start, end]
},
},
{
text: '最近30天',
value: () => {
const end = new Date()
const start = new Date(getStartTime())
start.setTime(start.getTime() - 3600 * 1000 * 24 * 29)
return [start, end]
},
},
{
text: '本星期',
value: () => {
const end = new Date()
const start = new Date()
const nowDay = new Date().getDay() - 1
start.setTime(
new Date(getStartTime()).getTime() - 3600 * 1000 * 24 * nowDay,
)
return [start, end]
},
},
{
text: '上星期',
value: () => {
const end = new Date()
const start = new Date()
const nowDay = new Date().getDay() - 1
end.setTime(
new Date(getStartTime()).getTime() - 3600 * 1000 * 24 * nowDay - 1,
)
start.setTime(end.getTime() - 3600 * 1000 * 24 * 7 + 1)
return [start, end]
},
},
{
text: '这个月',
value: () => {
const end = new Date()
const start = new Date()
const nowDate = new Date().getDate() - 1
start.setTime(
new Date(getStartTime()).getTime() - 3600 * 1000 * 24 * nowDate,
)
return [start, end]
},
},
{
text: '上个月',
value: () => {
const date = new Date()
let year = date.getFullYear()
let month = date.getMonth()
const end = new Date(
new Date(`${year}-${month + 1}-1 00:00:00`).getTime() - 1,
)
if (month === 0) {
month = 12
year = year - 1
}
const start = new Date(
new Date(`${year}-${month}-1 00:00:00`).getTime(),
)
return [start, end]
},
},
{
text: '历史',
value: () => {
return ['', '']
},
},
],
}
interface SummaryMethodProps<T = AccountStatementNote> {
columns: TableColumnCtx<T>[]
data: T[]
function getStartTime() {
const date = new Date()
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
return `${year}-${month}-${day} 00:00:00`
}
// const nameSpaceList = ref<string[]>([])
const treeData = ref<CountStatus[]>()
const [searchForm, resetSearchForm] = useValue<AccountStatementNoteSearchForm>(
{},
)
const selectSku = ref('')
const treeData = ref<InterWarehouseTree[]>()
const [searchForm, resetSearchForm] = useValue<warehouseSearchForm>({})
const dateRange = ref<string[]>([])
const selections = ref<AccountStatementNote[]>([])
const detailList = ref<ItemList[]>([])
const tradingTime = ref<string[]>([])
const selections = ref<InterWarehousePage[]>([])
const detailList = ref<InterWarehouseDetail[]>([])
const tabsValue = ref<string>('0')
const singleTableRef = ref<InstanceType<typeof ElTable>>()
const currentRow = ref<AccountStatementNote | null>(null)
const currentRow = ref<InterWarehousePage | null>(null)
const logList = ref<LogList[]>([])
const rules = {
warehouseId: [{ required: true, message: '请选择仓库', trigger: 'change' }],
}
const nodeId = ref<number | string>(10)
const treeRef = ref<InstanceType<typeof ElTree>>()
......@@ -587,36 +881,31 @@ const {
onPageSizeChange: handleSizeChange,
} = usePageList({
query: (page, pageSize) =>
customJomallReconciliation(
warehouseOutRecordListPage(
{
...searchForm.value,
status: nodeId.value === -1 ? null : nodeId.value,
start_time: dateRange.value && dateRange.value[0],
end_time: dateRange.value && dateRange.value[1],
billStatus: nodeId.value === -1 ? null : nodeId.value,
createTimeStart: tradingTime.value && tradingTime.value[0],
createTimeEnd: tradingTime.value && tradingTime.value[1],
},
page,
pageSize,
).then((res) => res.data) as never,
})
onMounted(() => {
// getNameSpaceList()
})
// const dialogVisible = ref<boolean>(false)
// const getNameSpaceList = async () => {
// try {
// const res = await getUserMarkList()
// nameSpaceList.value = res.data
// } catch (e) {
// // showError(e)
// }
// }
const setCostPrice = (item: InterProductList) => {
if (!item.costPrice) {
ElMessage.warning('商品成本价为空,请完善商品成本价')
return
}
const amount = new BigNumber(item.buyStored)
.multipliedBy(item.costPrice)
.toFixed(2)
item.totalPrice = Number(amount)
}
const getTreeNum = async () => {
try {
const res = await getReconciliationAmount()
res.data = [{ code: -1, remark: '全部', children: res.data }]
const res = await getOutRecordStatusTree()
res.data = [{ code: -1, name: '全部', children: res.data }]
treeData.value = res.data
await nextTick(() => {
treeRef.value!.setCurrentKey(nodeId.value, true)
......@@ -625,14 +914,68 @@ const getTreeNum = async () => {
console.error(e)
}
}
const rowClick = (row: AccountStatementNote) => {
const getWarehouseList = async () => {
try {
const res = await getWarehouseListApi()
warehouseList.value = res.data
await nextTick(() => {
treeRef.value!.setCurrentKey(nodeId.value, true)
})
} catch (e) {
console.error(e)
}
}
const rowClick = (row: InterWarehousePage) => {
if (!row) {
currentRow.value = null
}
currentRow.value = row
tabsClick()
}
const skuData = ref<InterskuList[]>([])
const selectbySku = async () => {
if (!editForm.value.warehouseId) return ElMessage.error('请选择仓库')
try {
const res = await getBySkuApi(editForm.value.warehouseId, selectSku.value)
skuData.value = res.data || []
fetchLocationList('') //获取该仓库下的所有库位
} catch (e) {
console.error(e)
}
}
const skudblclick = (val: InterskuList) => {
// 使用可选链和空值合并运算符处理可能的null值
const {
locationCode = '',
factoryPrice = 0,
productNo = '',
sku = '',
skuName = '',
image = '',
locationId = '',
} = val || {}
otherPurchaseData.value = [
...otherPurchaseData.value,
{
skuImage: image,
warehouseSku: sku,
skuName,
productNo,
locationCode: locationCode ?? '', // 确保空值处理
locationId: locationId ?? '', // 确保空值处理
costPrice: factoryPrice, ////添加时成本价字段是啥?要提交吗?
buyStored: null,
totalPrice: null,
},
]
// 使用filter代替forEach+splice,时间复杂度从O(n^2)降到O(n)
const skuSet = new Set(
otherPurchaseData.value.map((item: InterProductList) => item.warehouseSku),
)
skuData.value = skuData.value.filter(
(item: InterskuList) => !skuSet.has(item.sku),
)
}
const tabsClick = async () => {
if (!currentRow.value) {
detailList.value = []
......@@ -642,49 +985,72 @@ const tabsClick = async () => {
await nextTick()
if (tabsValue.value === '0') {
searchDetail()
} else {
} else if (tabsValue.value === '1') {
getLogList()
} else {
getLogisticsData()
}
}
const handleSelectionChange = (v: AccountStatementNote[]) => {
const [editForm, resetEditForm] = useValue({
inNo: '',
warehouseId: '',
remark: '',
factoryCode: '',
factoryId: '',
})
const newDialogVisible = ref(false)
const editFormRef = ref()
const editForm2 = ref({})
const formId = ref<number | undefined>(undefined)
const otherPurchaseData = ref<InterProductList[]>([])
const addDialog = async (i: number, v: InterWarehousePage) => {
if (i === 2) {
if (v) formId.value = v.id
// getProduct(v.id)
if (!formId.value) return ElMessage('请勾选至少一条记录')
// v.inWarehouseId = v.warehouseId
// v.inType = v.type
// v.handleUserId = v.makerUserId
editForm.value = JSON.parse(JSON.stringify(v))
} else {
await nextTick()
editForm.value = JSON.parse(JSON.stringify(editForm2.value))
resetEditForm()
const userJson = localStorage.getItem('user')
if (userJson) {
try {
const userData = JSON.parse(userJson)
editForm.value.factoryCode = userData.factoryCode || ''
editForm.value.factoryId = userData.factoryId || 0
} catch {
// ignore
}
}
otherPurchaseData.value = []
formId.value = undefined
}
newDialogVisible.value = true
}
// const getProduct = (id: number) => {
// let url = `otherInWarehouseProductDetails/getProductList?otherOutWarehouseId=${id}`
// get(url).then((res) => {
// if (res.code == 200) {
// otherPurchaseData.value = res.data;
// productData.value = res.data;
// } else {
// this.$alert(res.message, this.$t('错误提示'), {
// dangerouslyUseHTMLString: true,
// })
// }
// })
// }
const handleSelectionChange = (v: InterWarehousePage[]) => {
selections.value = v
}
const getSummaries = (param: SummaryMethodProps) => {
const { columns, data } = param
const sums: string[] = []
columns.forEach(
(column: TableColumnCtx<AccountStatementNote>, index: number) => {
if (index === 0) {
sums[index] = '合计'
return
}
const values = data.map((item: AccountStatementNote) => {
return Number(item[column.property as keyof AccountStatementNote])
})
if (!values.every((value: number) => !isNaN(value))) {
return
}
sums[index] = values
.reduce((prev: number, curr: number) => {
const value = Number(curr)
if (!isNaN(value)) {
return prev + curr
} else {
return prev
}
}, 0)
.toString()
},
)
return sums
const otherWarehouseSelection = ref<InterProductList[]>([])
const productSelectionChange = (v: InterProductList[]) => {
otherWarehouseSelection.value = v
}
const confirmOrderVisible = ref<boolean>(false)
const auditForm = ref({
pass: 1,
description: '',
})
const auditFormRef = ref()
const auditOrder = (key: string) => {
let url = ''
let text = ''
......@@ -737,63 +1103,6 @@ const rejectOrder = () => {
}
})
}
const confirmOrder = async () => {
if (selections.value.length === 0) {
return ElMessage.warning('请选择要操作的数据')
}
try {
await showConfirm('是否确认对账单?', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
} catch {
return
}
const ids = selections.value.map((el) => el.id).join(',')
try {
await confirmOrderApi({
ids,
})
confirmOrderVisible.value = false
ElMessage.success('操作成功')
search()
await getTreeNum()
} catch (e) {
console.error(e)
}
// confirmOrderVisible.value = true
// auditForm.value = {
// pass: 1,
// description: '',
// }
// await nextTick()
// auditFormRef.value!.clearValidate()
}
const submitConfirmOrder = async () => {
try {
await auditFormRef.value?.validate()
} catch {
return
}
const ids = selections.value.map((el) => el.id).join(',')
await confirmOrderApi({
...auditForm.value,
pass: auditForm.value.pass === 0 ? 0 : undefined,
description:
auditForm.value.description === ''
? undefined
: auditForm.value.description,
ids,
})
confirmOrderVisible.value = false
ElMessage.success('操作成功')
search()
await getTreeNum()
if (singleTableRef.value) {
singleTableRef.value!.setCurrentRow(currentRow.value)
}
}
watch(
() => tableData.value,
() => {
......@@ -808,22 +1117,142 @@ watch(
},
{ immediate: true },
)
const nodeClick = (data: Tree) => {
nodeId.value = data.code ?? ''
search()
const addOtherCurrency = async () => {
try {
await editFormRef.value?.validate()
} catch {
return
}
const arr = otherPurchaseData.value
if (arr.length === 0) {
ElMessage.error('请至少选择一条数据')
return
}
for (let i = 0; i < arr.length; i++) {
if (!arr[i].buyStored) {
ElMessage.error('请输入入库数量')
return
}
if (!arr[i].locationId) {
ElMessage.error('请选择库位')
return
}
}
// 看新增后要不要打印标签
// try {
// if (!editId.value) {
// await addUserApi({
// ...editForm.value,
// supperMark: Number(editForm.value.supperMark),
// status: Number(editForm.value.status),
// })
// } else {
// await updateUserApi({
// ...editForm.value,
// supperMark: Number(editForm.value.supperMark),
// status: Number(editForm.value.status),
// })
// }
// ElMessage({
// message: '保存成功',
// type: 'success',
// offset: window.innerHeight / 2,
// })
// newDialogVisible.value = false
// search()
// } catch (e) {
// return
// }
if (!formId.value) {
addSection()
} else {
upSection()
}
}
const shipmentOrderDetailDrawerVisible = ref(false)
const shipmentOrderDetail = ref({} as ShipmentOrderDetailData)
const onDetail = async (row: ItemList) => {
const addSection = async () => {
const params = { ...editForm.value }
params.productList = otherPurchaseData.value
try {
const res = await getShipmentOrderDetailById(row.shipment_id)
shipmentOrderDetail.value = res.data
shipmentOrderDetailDrawerVisible.value = true
await addInRecordApi(params)
ElMessage.success('保存成功')
newDialogVisible.value = false
search()
await getTreeNum()
} catch (e) {
console.error(e)
}
// post(url, params).then((res: any) => {
// if (res.code === 200) {
// otherDialogVisible.value = false;
// ElConfirm('保存成功,是否打印标签?', '提示', {
// confirmButtonText: '确定',
// cancelButtonText: '取消',
// type: 'warning',
// })
// .then(() => {
// if (res.message) {
// getPrintData(res.message, true);
// } else {
// ElMessage.warning('入口单号为空,无法打印');
// }
// })
// .catch((e: any) => {
// console.error(e);
// });
// getList();
// getStatusAmount();
// } else {
// ElAlert(res.message, '错误提示', {
// dangerouslyUseHTMLString: true,
// });
// }
// });
}
const upSection = async () => {
const params = { ...editForm.value }
params.productList = otherPurchaseData.value
try {
await updateInRecordApi(params)
newDialogVisible.value = false
ElMessage.success('修改成功')
search()
await getTreeNum()
} catch (e) {
console.error(e)
}
}
const addPurchase = async () => {
if (!editForm.value.warehouseId) return ElMessage.error('请选择仓库')
}
const deleteOtherWarehousing = () => {
const arr = otherWarehouseSelection.value
if (arr.length === 0) return
const idList = arr.map((v: InterProductList) => v.warehouseSku)
otherPurchaseData.value = otherPurchaseData.value.filter(
(item: InterProductList) => !idList.includes(item.warehouseSku),
)
}
const importData = async () => {
if (!editForm.value.warehouseId) return ElMessage.error('请选择仓库')
}
const handleBatchDelete = async () => {
if (!selections.value.length) {
return ElMessage.warning('请选择要删除的数据')
}
await ElMessageBox.confirm('确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
const str = selections.value.map((el: InterWarehousePage) => el.id).join(',')
await deleteWarehouseOutRecordApi(str)
ElMessage.success('删除成功')
await search()
}
const nodeClick = (data: InterWarehouseTree) => {
nodeId.value = data.code ?? ''
search()
}
const detailForm = ref({} as DetailForm)
const detailPager = ref({
page: 1,
rows: 100,
......@@ -831,15 +1260,9 @@ const detailPager = ref({
})
const searchDetail = async () => {
try {
const res = await getShipmentDetailsById({
...detailForm.value,
page: detailPager.value.page,
rows: detailPager.value.rows,
infoId: currentRow.value?.id,
})
const res = await getWarehouseInRecordDetailApi(currentRow.value?.id)
detailList.value = res.data.records || []
detailPager.value.total = res.data.total
// logList.value = res.data.logList || []
} catch (e) {
console.error(e)
}
......@@ -848,11 +1271,31 @@ const getLogList = async () => {
try {
const res = await getLogListApi(currentRow.value?.id)
logList.value = res.data
// logList.value = res.data.logList || []
} catch (e) {
console.error(e)
}
}
// const logisticsData = ref([])
const getLogisticsData = async () => {
// try {
// const res = await getLogisticsDataApi(currentRow.value?.id)
// logisticsData.value = res.data
// } catch (e) {
// console.error(e)
// }
}
const importDialogVisible = ref(false)
const importedFileUrl = ref('')
const importExcel = () => {
importDialogVisible.value = true
}
const downloadTemplate = () => {
// TODO: 实现下载模板功能
window.open('/api/template/download')
}
const exportExcel = async () => {
if (selections.value.length === 0) {
return ElMessage.warning('请选择要操作的数据')
......@@ -865,19 +1308,64 @@ const exportExcel = async () => {
console.error(e)
}
}
const locationList = ref<ILocation[]>([])
const locationLoading = ref(false)
const fetchLocationList = async (query: string) => {
// if (!query) {
// locationList.value = []
// return
// }
locationLoading.value = true
try {
const res = await getByWareHouseIdAndCodeApi(
editForm.value.warehouseId,
query,
)
const result = res.data || []
locationList.value = result.map((item: ILocation) => {
return {
locationId: item.id,
locationCode: item.locationCode,
}
})
} catch (e) {
locationList.value = []
} finally {
locationLoading.value = false
}
}
// 输入2秒后再调用接口(节流)
const handleLocationSearch = debounce(fetchLocationList, 2000)
const handleLocationChange = (val: number, row: InterProductList) => {
const found = locationList.value.find(
(item: InterProductList) => item.locationId === val,
)
row.locationCode = found ? found.locationCode : ''
}
onMounted(() => {
getTreeNum()
getWarehouseList()
})
</script>
<style lang="scss" scoped>
.dialog-footer {
display: inline-block;
width: 500px;
text-align: center;
}
.header-filter-form {
:deep(.el-form-item) {
margin-right: 14px;
margin-bottom: 10px;
}
}
.product-dialog-footer {
display: flex;
justify-content: space-between;
margin: 8px 0;
}
$border: solid 1px #ddd;
.send-order-list {
......@@ -917,10 +1405,6 @@ $border: solid 1px #ddd;
width: 100px;
}
.dialog-footer {
text-align: center;
}
.delivery-note-list {
:deep(.vertical-align-top) {
vertical-align: top;
......@@ -1060,4 +1544,42 @@ $border: solid 1px #ddd;
height: 100%;
}
}
.import-dialog {
.import-header {
display: flex;
justify-content: flex-end;
}
.import-content {
padding: 20px 0;
}
}
.import-success {
text-align: center;
padding: 20px 0;
.success-icon {
font-size: 48px;
margin-bottom: 16px;
}
.success-text {
font-size: 16px;
color: #67c23a;
margin-bottom: 16px;
}
.file-link {
a {
color: #409eff;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
}
</style>
......@@ -97,20 +97,64 @@
</ElForm>
</div>
<div class="btn-list">
<el-button type="primary" @click="addDialog(1)"> 新增 </el-button>
<el-button type="danger" @click="rejectOrder"> 驳回 </el-button>
<el-button type="danger" @click="rejectOrder"> 删除 </el-button>
<el-button type="warning" @click="importExcel"> 导入 </el-button>
<el-button type="success" @click="exportExcel"> 导出 </el-button>
<el-button
v-if="nodeCode === 'PENDING_SUBMIT'"
type="primary"
@click="addDialog(1)"
>
新增
</el-button>
<el-button
v-if="nodeCode === 'PENDING_AUDIT'"
type="danger"
@click="auditOrder('rejected')"
>
驳回
</el-button>
<el-button
v-if="nodeCode === 'PENDING_SUBMIT'"
type="danger"
@click="handleBatchDelete"
>
删除
</el-button>
<el-button
v-if="nodeCode === 'PENDING_SUBMIT'"
type="warning"
@click="importExcel"
>
导入
</el-button>
<el-button type="success" @click="handleExport"> 导出 </el-button>
<el-button type="primary" @click="exportExcel">
打印SKU标签
</el-button>
<el-button type="warning" @click="exportExcel"> 审核 </el-button>
<el-button type="success" @click="exportExcel">
<el-button
v-if="nodeCode === 'PENDING_AUDIT'"
type="warning"
@click="auditOrder('audit')"
>
审核
</el-button>
<el-button
v-if="nodeCode === 'PENDING_SUBMIT'"
type="success"
@click="auditOrder('submitAudit')"
>
提交审核
</el-button>
<el-button type="danger" @click="rejectOrder"> 作废 </el-button>
<el-button type="success" @click="auditOrder('archive')">
<el-button
v-if="nodeCode === 'PENDING_AUDIT'"
type="danger"
@click="auditOrder('invalid')"
>
作废
</el-button>
<el-button
v-if="nodeCode === 'COMPLETED'"
type="success"
@click="auditOrder('archiving')"
>
归档
</el-button>
</div>
......@@ -147,15 +191,14 @@
label="入库单号"
show-overflow-tooltip
prop="inNo"
width="110"
width="130"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="单据状态"
show-overflow-tooltip
width="130"
prop="billStatus"
width="80"
header-align="center"
align="center"
></ElTableColumn>
......@@ -163,7 +206,7 @@
label="仓库名称"
show-overflow-tooltip
prop="warehouseName"
min-width="100"
width="130"
header-align="center"
align="center"
></ElTableColumn>
......@@ -171,7 +214,7 @@
label="工厂编号"
show-overflow-tooltip
prop="factoryCode"
min-width="100"
width="90"
header-align="center"
align="center"
></ElTableColumn>
......@@ -195,7 +238,7 @@
label="SKU数量"
header-align="center"
prop="skuAmount"
width="130"
width="90"
align="center"
show-overflow-tooltip
>
......@@ -204,7 +247,7 @@
label="总数量"
header-align="center"
prop="total"
width="120"
width="90"
align="center"
show-overflow-tooltip
>
......@@ -212,7 +255,6 @@
<ElTableColumn
label="备注"
show-overflow-tooltip
width="240"
prop="remark"
header-align="center"
align="center"
......@@ -259,14 +301,15 @@
<ElTableColumn
show-overflow-tooltip
align="center"
width="100"
label="SKU图片"
prop="factory_order_number"
>
<template #default="{ row }">
<ImageView
:src="row.skuImage"
width="80px"
height="80px"
width="40px"
height="40px"
/>
</template>
</ElTableColumn>
......@@ -293,12 +336,18 @@
<ElTableColumn
show-overflow-tooltip
align="center"
label="总成本(¥)"
prop="buyStored"
label="成本价(¥)"
prop="costPrice"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="总成本(¥)"
prop="totalPrice"
/>
<!-- <ElTableColumn
show-overflow-tooltip
align="center"
label="不良品数量"
prop="rejectsAmount"
/>
......@@ -307,7 +356,7 @@
align="center"
label="不良品原因"
prop="rejectsAeason"
/>
/> -->
<ElTableColumn
show-overflow-tooltip
align="center"
......@@ -330,7 +379,7 @@
</ElTable>
</div>
<ElPagination
<!-- <ElPagination
v-model:current-page="detailPager.page"
v-model:page-size="detailPager.rows"
:page-sizes="[100, 200, 300, 400, 500]"
......@@ -340,9 +389,9 @@
style="margin: 10px auto 0; text-align: right"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
></ElPagination>
></ElPagination> -->
</el-tab-pane>
<!-- <el-tab-pane name="1" label="操作日志">
<el-tab-pane name="1" label="操作日志">
<ul
style="
color: #333;
......@@ -365,24 +414,6 @@
</li>
</ul>
</el-tab-pane>
<el-tab-pane name="2" label="物流轨迹">
<ul
v-if="logisticsData.length > 0"
style="
color: #333;
font-size: 12px;
height: 100%;
overflow: auto;
"
>
<li v-for="(item, index) in logisticsData" :key="index">
<span class="log-desc">
{{ item.time + ' ' + item.context }}
</span>
</li>
</ul>
<div v-else class="empty">{{ $t('暂无数据') }}</div>
</el-tab-pane> -->
</el-tabs>
</template>
</splitDiv>
......@@ -430,6 +461,9 @@
<ElFormItem label="入库单号" prop="account">
<ElInput v-model="editForm.inNo" clearable disabled />
</ElFormItem>
<ElFormItem label="工厂:" prop="factoryCode">
<span>{{ editForm.factoryCode }}</span>
</ElFormItem>
<ElFormItem label="仓库" prop="warehouseId" required>
<ElSelect
v-model="editForm.warehouseId"
......@@ -445,9 +479,6 @@
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="工厂:" prop="factoryCode">
<span>{{ editForm.factoryCode }}</span>
</ElFormItem>
<ElFormItem label="备注" prop="remark" style="width: 45%">
<ElInput
v-model="editForm.remark"
......@@ -498,11 +529,11 @@
<template #default="{ row }">
<el-input
v-model.number="row.buyStored"
@input="setCostPrice(row)"
placeholder="入库数量"
style="width: 120px"
clearable
size="small"
@input="setCostPrice(row)"
></el-input>
</template>
</ElTableColumn>
......@@ -518,18 +549,6 @@
label="总成本(¥)"
prop="totalPrice"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="不良品数量"
prop="rejectsAmount"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="不良品原因"
prop="rejectsAeason"
/>
<ElTableColumn align="center" label="库位" prop="loacationCode">
<template #default="{ row }">
<!-- +后有就正常展示,没有则通过搜索接口自己添加 -->
......@@ -631,7 +650,7 @@
label="操作"
>
<template #default="{ row }">
<el-icon :size="32" color="#67C23A"
<el-icon :size="32" color="#67C23A" class="cursor-pointer"
><CirclePlusFilled @click="skudblclick(row)"
/></el-icon>
</template>
......@@ -689,6 +708,31 @@
</div>
</template>
</ElDialog>
<ElDialog
v-model="exportVisible"
title="导出选项"
width="500px"
:close-on-click-modal="false"
>
<el-form :model="exportForm" label-width="80px">
<el-form-item label="" prop="resource">
<el-radio-group v-model="exportForm.resource">
<el-radio :label="0">导出本页</el-radio>
<el-radio :label="1">导出选中</el-radio>
<el-radio :label="2">全部</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="">
<el-checkbox v-model="exportForm.delivery"> 包含详情 </el-checkbox>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="exportVisible = false">取消</el-button>
<el-button type="primary" @click="submitExportForm">确认</el-button>
</span>
</template>
</ElDialog>
</template>
<script setup lang="ts">
......@@ -698,21 +742,19 @@ import splitDiv from '@/components/splitDiv/splitDiv.vue'
import { ElTable } from 'element-plus'
import usePageList from '@/utils/hooks/usePageList'
import { useValue } from '@/utils/hooks/useValue'
import { exportExcelApi } from '@/api/order'
import {
auditOrderApi,
rejectOrderApi,
getLogListApi,
exportExcelApi,
} from '@/api/order'
import {
getWarehouseStatusTree,
warehouseInRecordListPage,
getWarehouseInRecordDetail,
getBySku,
getInRecordStatusTree,
warehouseInRecordListPageApi,
getWarehouseInRecordDetailApi,
getBySkuApi,
getWarehouseListApi,
getByWareHouseIdAndCode,
getByWareHouseIdAndCodeApi,
addInRecordApi,
updateInRecordApi,
deleteWarehouseInRecordApi,
auditOrderApi,
getInRecordLogApi,
} from '@/api/warehouse'
import BigNumber from 'bignumber.js'
import { ref, onMounted, watch, nextTick } from 'vue'
......@@ -721,7 +763,6 @@ import { LogList } from '@/types/api/billOrder.ts'
import {
warehouseSearchForm,
InterWarehousePage,
InterWarehouseDetail,
InterWarehouseTree,
InterProductList,
InterskuList,
......@@ -851,19 +892,13 @@ function getStartTime() {
const day = date.getDate()
return `${year}-${month}-${day} 00:00:00`
}
interface Tree {
remark?: string
count?: number
code?: string
children?: Tree[]
}
const selectSku = ref('')
const treeData = ref<InterWarehouseTree[]>()
const [searchForm, resetSearchForm] = useValue<warehouseSearchForm>({})
const tradingTime = ref<string[]>([])
const selections = ref<InterWarehousePage[]>([])
const detailList = ref<InterWarehouseDetail[]>([])
const detailList = ref<InterProductList[]>([])
const tabsValue = ref<string>('0')
const singleTableRef = ref<InstanceType<typeof ElTable>>()
const currentRow = ref<InterWarehousePage | null>(null)
......@@ -871,7 +906,7 @@ const logList = ref<LogList[]>([])
const rules = {
warehouseId: [{ required: true, message: '请选择仓库', trigger: 'change' }],
}
const nodeId = ref<number | string>(10)
const nodeCode = ref<string | null>('all')
const treeRef = ref<InstanceType<typeof ElTree>>()
const {
......@@ -884,10 +919,10 @@ const {
onPageSizeChange: handleSizeChange,
} = usePageList({
query: (page, pageSize) =>
warehouseInRecordListPage(
warehouseInRecordListPageApi(
{
...searchForm.value,
// status: nodeId.value === -1 ? null : nodeId.value,
billStatus: nodeCode.value == 'all' ? 'all' : nodeCode.value,
createTimeStart: tradingTime.value && tradingTime.value[0],
createTimeEnd: tradingTime.value && tradingTime.value[1],
},
......@@ -907,22 +942,126 @@ const setCostPrice = (item: InterProductList) => {
}
const getTreeNum = async () => {
try {
const res = await getWarehouseStatusTree()
res.data = [{ code: -1, name: '全部', children: res.data }]
const res = await getInRecordStatusTree()
res.data = [{ code: 'all', name: '全部', children: res.data }]
treeData.value = res.data
await nextTick(() => {
treeRef.value!.setCurrentKey(nodeId.value, true)
treeRef.value!.setCurrentKey(nodeCode.value, true)
})
} catch (e) {
console.error(e)
}
}
const exportVisible = ref(false)
const exportForm = ref({
delivery: false,
resource: '',
})
const handleExport = () => {
exportVisible.value = true
// exportForm.value.delivery = false
// exportForm.value.resource = ''
}
// const submitExportForm = () => {
// if (exportForm.value.resource === '') {
// return ElMessage.error('请选择导出类型')
// }
// let purchaseIds = [],
// otherIds = [],
// total = 0,
// params = {}
// if (exportForm.value.resource === 0) {
// purchaseIds = userData.value
// .filter((el) => el.dataType === 0)
// .map((el) => el.id)
// .join(',')
// otherIds = userData.value
// .filter((el) => el.dataType === 1)
// .map((el) => el.id)
// .join(',')
// } else if (exportForm.value.resource === 1) {
// purchaseIds = selections.value
// .filter((el) => el.dataType === 0)
// .map((el) => el.id)
// .join(',')
// otherIds = selections.value
// .filter((el) => el.dataType === 1)
// .map((el) => el.id)
// .join(',')
// } else {
// purchaseIds = ''
// otherIds = ''
// // total = this.paginationOptions.total
// }
// params = {
// purchaseIds,
// otherIds,
// total,
// }
// if (exportForm.value.resource !== 2) {
// delete params.total
// } else {
// // params.billStatus = this.billStatus
// // params.type = this.treeType || ''
// // params.otherStatus = this.otherStatus
// if (
// this.treeLabel.indexOf(this.$t('待入库')) !== -1 ||
// this.treeLabel.indexOf(this.$t('已入库')) !== -1
// ) {
// params.purchaseAll = true
// params.otherAll = true
// }
// if (
// this.treeLabel.indexOf(this.$t('采购')) !== -1 ||
// this.treeLabel.indexOf(this.$t('生产')) !== -1
// ) {
// params.purchaseAll = true
// }
// if (this.treeLabel.indexOf(this.$t('其他')) !== -1) {
// params.otherAll = true
// }
// if (this.treeLabel.indexOf(this.$t('归档')) !== -1) {
// params.purchaseAll = true
// }
// if (this.treeLabel.indexOf(this.$t('作废')) !== -1) {
// params.purchaseAll = true
// params.otherAll = true
// }
// }
// const loading = this.$loading({
// background: 'rgba(0, 0, 0, 0.3)',
// })
// Axios.post(
// window.apiHostSetting.VUE_APP_API_URL +
// 'api/purchaseStoreBill/exportPurchaseExcel',
// {
// includeSku: exportForm.value.delivery,
// ...params,
// ...this.searchForm,
// },
// {
// headers: {
// 'jwt-token': localStorage.getItem('token'),
// },
// },
// )
// .then((res) => {
// console.log(filePath)
// window.open(filePath + res.data.message)
// exportVisible.value = false
// })
// .finally(() => {
// loading.close()
// })
// }
const getWarehouseList = async () => {
try {
const res = await getWarehouseListApi()
warehouseList.value = res.data
await nextTick(() => {
treeRef.value!.setCurrentKey(nodeId.value, true)
treeRef.value!.setCurrentKey(nodeCode.value, true)
})
} catch (e) {
console.error(e)
......@@ -939,9 +1078,8 @@ const skuData = ref<InterskuList[]>([])
const selectbySku = async () => {
if (!editForm.value.warehouseId) return ElMessage.error('请选择仓库')
try {
const res = await getBySku(editForm.value.warehouseId, selectSku.value)
const res = await getBySkuApi(editForm.value.warehouseId, selectSku.value)
skuData.value = res.data || []
fetchLocationList('') //获取该仓库下的所有库位
} catch (e) {
console.error(e)
}
......@@ -966,7 +1104,7 @@ const skudblclick = (val: InterskuList) => {
productNo,
locationCode: locationCode ?? '', // 确保空值处理
locationId: locationId ?? '', // 确保空值处理
costPrice: factoryPrice, ////添加时成本价字段是啥?要提交吗?
costPrice: factoryPrice,
buyStored: null,
totalPrice: null,
},
......@@ -990,8 +1128,6 @@ const tabsClick = async () => {
searchDetail()
} else if (tabsValue.value === '1') {
getLogList()
} else {
getLogisticsData()
}
}
const [editForm, resetEditForm] = useValue({
......@@ -1009,11 +1145,8 @@ const otherPurchaseData = ref<InterProductList[]>([])
const addDialog = async (i: number, v: InterWarehousePage) => {
if (i === 2) {
if (v) formId.value = v.id
// getProduct(v.id)
getProduct(v.id)
if (!formId.value) return ElMessage('请勾选至少一条记录')
// v.inWarehouseId = v.warehouseId
// v.inType = v.type
// v.handleUserId = v.makerUserId
editForm.value = JSON.parse(JSON.stringify(v))
} else {
await nextTick()
......@@ -1032,80 +1165,97 @@ const addDialog = async (i: number, v: InterWarehousePage) => {
otherPurchaseData.value = []
formId.value = undefined
}
fetchLocationList('') //获取该仓库下的所有库位
newDialogVisible.value = true
}
// const getProduct = (id: number) => {
// let url = `otherInWarehouseProductDetails/getProductList?otherOutWarehouseId=${id}`
// get(url).then((res) => {
// if (res.code == 200) {
// otherPurchaseData.value = res.data;
// productData.value = res.data;
// } else {
// this.$alert(res.message, this.$t('错误提示'), {
// dangerouslyUseHTMLString: true,
// })
// }
// })
// }
const getProduct = async (id: number) => {
try {
const res = await getWarehouseInRecordDetailApi(id)
otherPurchaseData.value = res.data.productList || []
} catch (e) {
console.error(e)
}
}
const handleSelectionChange = (v: InterWarehousePage[]) => {
selections.value = v
}
const productSelection = ref<InterProductList[]>([])
const otherWarehouseSelection = ref<InterProductList[]>([])
const productSelectionChange = (v: InterProductList[]) => {
productSelection.value = v
otherWarehouseSelection.value = v
}
const auditOrder = (key: string) => {
let url = ''
let text = ''
switch (key) {
case 'pay':
url = 'reconciliation/payment'
text = '确认付款'
case 'rejected':
url = 'factory/warehouseInRecord/turnDown'
text = '驳回'
break
case 'invalid':
url = 'factory/warehouseInRecord/invalid'
text = '作废'
break
case 'archiving':
url = 'factory/warehouseInRecord/archive'
text = '归档'
break
case 'submitAudit':
url = 'factory/warehouseInRecord/submitAudit'
text = '提交审核'
break
case 'archive':
url = 'reconciliation/archiving'
text = '确认归档'
case 'audit':
url = 'factory/warehouseInRecord/audit'
text = '审核'
break
}
if (selections.value.length === 0) {
return ElMessage.warning('请选择要操作的数据')
}
ElMessageBox.confirm(`${text}对账单?`, '重要提示', {
const confimText =
key === 'audit'
? '确定进行审核?点“确定”将会直接更改库存数量,请在审核前确认数量是否正确。'
: `确定对选中的信息进行${text}?`
ElMessageBox.confirm(confimText, '重要提示', {
confirmButtonText: '确定',
type: 'warning',
}).then(async () => {
const ids = selections.value.map((el) => el.id).join(',')
await auditOrderApi(url, ids)
const data = selections.value.map(
({ id, dataVersion }: InterWarehousePage) => ({
id,
dataVersion,
}),
)
await auditOrderApi(url, data)
ElMessage.success('操作成功')
search()
await getTreeNum()
})
}
const rejectOrder = () => {
if (selections.value.length === 0) {
return ElMessage.warning('请选择要操作的数据')
}
ElMessageBox.prompt('请输入驳回原因', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
inputPattern: /.+/,
customClass: 'reject',
inputErrorMessage: '请输入驳回原因',
inputPlaceholder: '驳回原因',
}).then(async ({ value }) => {
const ids = selections.value.map((el) => el.id).join(',')
try {
await rejectOrderApi({ ids: ids, description: value, pass: 0 })
ElMessage.success('操作成功')
search()
await getTreeNum()
} catch (e) {
console.error(e)
}
})
}
// const rejectOrder = () => {
// if (selections.value.length === 0) {
// return ElMessage.warning('请选择要操作的数据')
// }
// ElMessageBox.prompt('请输入驳回原因', '提示', {
// confirmButtonText: '确定',
// cancelButtonText: '取消',
// type: 'warning',
// inputPattern: /.+/,
// customClass: 'reject',
// inputErrorMessage: '请输入驳回原因',
// inputPlaceholder: '驳回原因',
// }).then(async ({ value }) => {
// const ids = selections.value.map((el) => el.id).join(',')
// try {
// await rejectOrderApi({ ids: ids, description: value, pass: 0 })
// ElMessage.success('操作成功')
// search()
// await getTreeNum()
// } catch (e) {
// console.error(e)
// }
// })
// }
watch(
() => tableData.value,
() => {
......@@ -1224,13 +1374,36 @@ const upSection = async () => {
console.error(e)
}
}
const addPurchase = async () => {}
const deleteOtherWarehousing = async () => {}
const addPurchase = async () => {
if (!editForm.value.warehouseId) return ElMessage.error('请选择仓库')
}
const deleteOtherWarehousing = () => {
const arr = otherWarehouseSelection.value
if (arr.length === 0) return
const idList = arr.map((v: InterProductList) => v.warehouseSku)
otherPurchaseData.value = otherPurchaseData.value.filter(
(item: InterProductList) => !idList.includes(item.warehouseSku),
)
}
const importData = async () => {
if (!editForm.value.warehouseId) return ElMessage.error('请选择仓库')
}
const nodeClick = (data: Tree) => {
nodeId.value = data.code ?? ''
const handleBatchDelete = async () => {
if (!selections.value.length) {
return ElMessage.warning('请选择要删除的数据')
}
await ElMessageBox.confirm('确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
const str = selections.value.map((el: InterWarehousePage) => el.id).join(',')
await deleteWarehouseInRecordApi(str)
ElMessage.success('删除成功')
await search()
}
const nodeClick = (data: InterWarehouseTree) => {
nodeCode.value = data.code ?? ''
search()
}
const detailPager = ref({
......@@ -1240,30 +1413,21 @@ const detailPager = ref({
})
const searchDetail = async () => {
try {
const res = await getWarehouseInRecordDetail(currentRow.value?.id)
detailList.value = res.data.records || []
detailPager.value.total = res.data.total
const res = await getWarehouseInRecordDetailApi(currentRow.value?.id)
detailList.value = res.data.productList || []
// detailPager.value.total = res.data.total
} catch (e) {
console.error(e)
}
}
const getLogList = async () => {
try {
const res = await getLogListApi(currentRow.value?.id)
const res = await getInRecordLogApi(currentRow.value?.id)
logList.value = res.data
} catch (e) {
console.error(e)
}
}
const logisticsData = ref([])
const getLogisticsData = async () => {
// try {
// const res = await getLogisticsDataApi(currentRow.value?.id)
// logisticsData.value = res.data
// } catch (e) {
// console.error(e)
// }
}
const importDialogVisible = ref(false)
const importedFileUrl = ref('')
......@@ -1298,7 +1462,10 @@ const fetchLocationList = async (query: string) => {
// }
locationLoading.value = true
try {
const res = await getByWareHouseIdAndCode(editForm.value.warehouseId, query)
const res = await getByWareHouseIdAndCodeApi(
editForm.value.warehouseId,
query,
)
const result = res.data || []
locationList.value = result.map((item: ILocation) => {
return {
......@@ -1332,6 +1499,9 @@ onMounted(() => {
width: 500px;
text-align: center;
}
.cursor-pointer {
cursor: pointer;
}
.header-filter-form {
:deep(.el-form-item) {
margin-right: 14px;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment