Commit 1fca53ff by qinjianhui

Merge branch 'dev_new_order_intercept' into optimize_code

parents a89226e3 001dd868
import axios from './axios'
import type { BasePaginationData } from '@/types/api'
import type { operateOrderListData } from '@/types/api/factoryOrderNew'
function normalizePodOrderQueryPayload(
data: Record<string, unknown>,
): Record<string, unknown> {
const { receiverCountry, ...rest } = data
if (!Array.isArray(receiverCountry)) {
return data
}
return {
...rest,
...(receiverCountry.length
? { receiverCountry: receiverCountry.join(',') }
: {}),
}
}
export function getCancelOrderProcessListApi(
data: Record<string, unknown>,
currentPage: number,
pageSize: number,
) {
const body = normalizePodOrderQueryPayload({ ...data })
return axios.post<never, BasePaginationData<operateOrderListData>>(
'factory/podOrderOperation/list_page',
{ ...body, status: 'PENDING_SCHEDULE', currentPage, pageSize },
)
}
...@@ -6,12 +6,11 @@ import type { ...@@ -6,12 +6,11 @@ import type {
LogListData, LogListData,
operateOrderListData, operateOrderListData,
PickCompleteData, PickCompleteData,
PickFailData,
ProductListData, ProductListData,
RestockData, RestockData,
SearchForm, SearchForm,
StatusTreeNode, StatusTreeNode,
} from '@/types/api/factoryOrderNew/factoryOrderNew' } from '@/types/api/factoryOrderNew'
import { ResultInfoDataItem } from '@/types/api/order/common' import { ResultInfoDataItem } from '@/types/api/order/common'
import { ExportParams } from '@/types/api/order/factoryOrderNew' import { ExportParams } from '@/types/api/order/factoryOrderNew'
import type { OrderData } from '@/types/api/podMakeOrder' import type { OrderData } from '@/types/api/podMakeOrder'
...@@ -44,6 +43,7 @@ export function getFactoryOrderNewListApi( ...@@ -44,6 +43,7 @@ export function getFactoryOrderNewListApi(
status?: string, status?: string,
subStatus?: number, subStatus?: number,
pauseReason?: number, pauseReason?: number,
cancelSubType?: number,
) { ) {
const body = normalizePodOrderQueryPayload({ ...data } as Record< const body = normalizePodOrderQueryPayload({ ...data } as Record<
string, string,
...@@ -58,6 +58,7 @@ export function getFactoryOrderNewListApi( ...@@ -58,6 +58,7 @@ export function getFactoryOrderNewListApi(
status, status,
acceptedStatus: subStatus, acceptedStatus: subStatus,
pauseReason, pauseReason,
cancelSubType,
}, },
) )
} }
...@@ -112,6 +113,14 @@ export function getFactoryOrderNewLogApi(id: number | string) { ...@@ -112,6 +113,14 @@ export function getFactoryOrderNewLogApi(id: number | string) {
}, },
) )
} }
export function getOperationOrderByIdApi(id: number | string) {
return axios.get<never, BaseRespData<operateOrderListData[]>>(
'factory/podOrderOperation/getByPodOrderId',
{
params: { podOrderId: id },
},
)
}
export function refreshProductInfoApi(data: { export function refreshProductInfoApi(data: {
orderIds?: number | string orderIds?: number | string
...@@ -257,13 +266,6 @@ export function replenishmentCompleteApi(ids: (number | string)[]) { ...@@ -257,13 +266,6 @@ export function replenishmentCompleteApi(ids: (number | string)[]) {
) )
} }
export function pickFailApi(ids: (number | string)[]) {
return axios.post<never, BaseRespData<PickFailData[]>>(
'factory/podOrderOperation/listByIds',
{ ids },
)
}
export function getCardLayoutListApi( export function getCardLayoutListApi(
data: Record<string, unknown>, data: Record<string, unknown>,
currentPage: number, currentPage: number,
...@@ -308,6 +310,23 @@ export function getSuspendStatisticsApi( ...@@ -308,6 +310,23 @@ export function getSuspendStatisticsApi(
) )
} }
/** 已取消列表子 tab 数量统计(与挂起 suspendStatistics 用法一致) */
export function getCancelledOrderStatisticsApi(
data: SearchForm,
currentPage: number,
pageSize: number,
cancelSubType?: number,
) {
const body = normalizePodOrderQueryPayload({ ...data } as Record<
string,
unknown
>)
return axios.post<never, BaseRespData<Record<string, number>>>(
'factory/podOrder/cancelledStatistics',
{ ...body, currentPage, pageSize, cancelSubType },
)
}
export function getSuspendDetailApi(id: number | string) { export function getSuspendDetailApi(id: number | string) {
return axios.get<never, BaseRespData<ProductListData[]>>( return axios.get<never, BaseRespData<ProductListData[]>>(
'factory/podOrderPauseControl/get', 'factory/podOrderPauseControl/get',
...@@ -590,3 +609,19 @@ export function exportFactoryOrderInfo(data: ExportParams) { ...@@ -590,3 +609,19 @@ export function exportFactoryOrderInfo(data: ExportParams) {
data, data,
) )
} }
export function interceptUpdateApi(ids: (string | number)[]) {
return axios.post<never, BaseRespData<ResultInfoDataItem[]>>(
'factory/podOrder/factoryOrderUnblock',
ids,
)
}
export function interceptSuccessApi(
data: { factoryOrderNumber: string; suspendSussessType: number }[],
) {
return axios.post<never, BaseRespData<ResultInfoDataItem[]>>(
'factory/podOrder/factoryOrderBlockSuccess',
data,
)
}
...@@ -107,6 +107,14 @@ const router = createRouter({ ...@@ -107,6 +107,14 @@ const router = createRouter({
import('@/views/order/factoryOrderNew/index.vue'), import('@/views/order/factoryOrderNew/index.vue'),
}, },
{ {
path:'/order/cancel-order-process',
meta: {
title: '取消后订单处理',
},
component: () =>
import('@/views/order/cancelOrderProcess/index.vue'),
},
{
path: '/pod-cn-order/orderTracking', path: '/pod-cn-order/orderTracking',
meta: { meta: {
title: 'POD(CN)订单跟踪', title: 'POD(CN)订单跟踪',
......
...@@ -151,6 +151,11 @@ const menu: MenuItem[] = [ ...@@ -151,6 +151,11 @@ const menu: MenuItem[] = [
id: 12, id: 12,
label: '工厂订单(NEW)', label: '工厂订单(NEW)',
}, },
{
index: '/order/cancel-order-process',
id: 13,
label: '取消后订单处理',
},
], ],
}, },
{ {
......
import type { PaginationData } from '@/types/api'
export interface StatusTreeNode { export interface StatusTreeNode {
status: string status: string
statusName: string statusName: string
...@@ -269,3 +270,9 @@ export interface PickFailData { ...@@ -269,3 +270,9 @@ export interface PickFailData {
afterOutOccupied?: number afterOutOccupied?: number
afterOutAvailable?: number afterOutAvailable?: number
} }
export type CardLayoutListFetcher = (
payload: Record<string, unknown>,
currentPage: number,
pageSize: number,
) => Promise<PaginationData<operateOrderListData>>
<template>
<div class="page card h-100 flex-gap-10 overflow-hidden flex">
<div class="order-status">
<div
class="order-status-item"
:class="{ 'order-status-item-active': currentStatus === 'processed' }"
@click="handleOrderStatusClick('processed')"
>
<span>已处理</span>
<span>({{ orderStatus.processed }})</span>
</div>
<div
class="order-status-item"
:class="{ 'order-status-item-active': currentStatus === 'unprocessed' }"
@click="handleOrderStatusClick('unprocessed')"
>
<span>未处理</span>
<span>({{ orderStatus.unprocessed }})</span>
</div>
</div>
<div class="order-content flex-1 flex-column overflow-hidden">
<div class="header">
<div class="header-filter-form">
<ElForm
class="search-form"
:model="searchForm"
:inline="true"
label-width="70px"
>
<ElFormItem label="平台">
<ElSelect
v-model="searchForm.platform"
placeholder="请选择"
clearable
filterable
popper-class="customize-select-style"
style="width: 140px"
>
<ElOption
v-for="(item, index) in platformJson"
:key="index"
:label="item.type"
:value="item.type"
style="width: 160px"
>
<img
:src="`/images/icon/${item.icon.split('/').pop()}`"
style="height: 20px; margin: 5px 10px 0 0"
/>
<span :title="item.type">{{ item.type }}</span>
</ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="工艺">
<LogisticsWaySelect
v-model="searchForm.craftCode"
:company-list="craftList"
:start-width="'150px'"
search-placeholder="搜索工艺名称"
start-placeholder="请选择工艺名称"
></LogisticsWaySelect>
</ElFormItem>
<ElFormItem label="库存SKU">
<ElInput
v-model.trim="searchForm.thirdSkuCode"
placeholder="库存SKU"
clearable
style="width: 140px"
/>
</ElFormItem>
<ElFormItem label="店铺单号">
<ElInput
v-model.trim="searchForm.shopNumber"
placeholder="店铺单号"
clearable
style="width: 150px"
/>
</ElFormItem>
<ElFormItem label="批次号">
<ElInput
v-model.trim="searchForm.batchArrangeNumber"
placeholder="批次号"
clearable
style="width: 140px"
/>
</ElFormItem>
<ElFormItem label="操作单号">
<ElInput
v-model.trim="searchForm.operationNo"
placeholder="操作单号"
clearable
style="width: 140px"
/>
</ElFormItem>
<ElFormItem label="商品类型">
<ProductTypeFilter
v-model="searchForm.productMarkList"
:options="productTypeGroups"
:multiple="true"
placeholder="请选择商品类型"
width="140px"
/>
</ElFormItem>
<ElFormItem label="数量">
<el-radio-group v-model="searchForm.multi">
<el-radio-button :value="false" @click="toggleMulti(false)"
>单件</el-radio-button
>
<el-radio-button :value="true" @click="toggleMulti(true)"
>多件</el-radio-button
>
</el-radio-group>
</ElFormItem>
<ElFormItem>
<ElPopover placement="bottom" width="600" trigger="click">
<ElForm
ref="searchFormPopoverRef"
:model="searchForm"
size="default"
inline
label-width="100px"
>
<ElFormItem style="width: 100%; padding-right: 40px">
<div style="width: 100%; display: flex; flex-wrap: nowrap">
<el-select
v-model="searchForm.timeType"
clearable
:teleported="false"
placeholder="时间类型"
style="flex: 1; margin-right: 10px"
>
<el-option :value="1" label="创建时间"></el-option>
<el-option :value="2" label="确认时间"></el-option>
<el-option :value="3" label="完成时间"></el-option>
</el-select>
<el-date-picker
v-model="dateRange"
:teleported="false"
:default-time="[
new Date(0, 0, 0, 0, 0, 0),
new Date(0, 0, 0, 23, 59, 59),
]"
value-format="YYYY-MM-DD HH:mm:ss"
type="datetimerange"
style="width: 280px"
:shortcuts="pickerOptions.shortcuts"
start-placeholder="开始时间"
end-placeholder="结束时间"
clearable
/>
</div>
</ElFormItem>
<ElFormItem label="订单号">
<ElInput
v-model.trim="searchForm.factoryOrderNumber"
placeholder="订单号"
clearable
style="width: 150px"
/>
</ElFormItem>
<ElFormItem label="客户">
<el-select
v-model="searchForm.userMark"
clearable
filterable
:teleported="false"
style="width: 150px"
placeholder="客户"
>
<el-option
v-for="item in userMarkList"
:key="item"
:value="item"
:label="item"
></el-option>
</el-select>
</ElFormItem>
<ElFormItem label="Variant SKU">
<ElInput
v-model.trim="searchForm.sku"
placeholder="Variant SKU"
clearable
style="width: 150px"
/>
</ElFormItem>
<ElFormItem label="款号">
<ElInput
v-model.trim="searchForm.supplierProductNo"
placeholder="款号"
clearable
style="width: 150px"
/>
</ElFormItem>
<ElFormItem label="物流跟踪号">
<ElInput
v-model.trim="searchForm.trackingNumber"
placeholder="物流跟踪号"
clearable
style="width: 150px"
/>
</ElFormItem>
<ElFormItem label="物流类型">
<ElSelect
v-model="searchForm.shipmentType"
placeholder="物流类型"
clearable
:teleported="false"
style="width: 150px"
>
<ElOption
v-for="(item, index) in [
'自有物流',
'九猫统筹物流',
'自提',
]"
:key="index"
:value="index"
:label="item"
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="客户标签">
<ElSelect
v-model="searchForm.tagsIdArr"
placeholder="请选择客户标签"
clearable
filterable
multiple
collapse-tags
collapse-tags-tooltip
:teleported="false"
style="width: 150px"
>
<ElOption
v-for="item in customTagList"
:key="item.id"
:value="item.id"
:label="item.name"
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="自有物流公司">
<ElSelect
v-model="searchForm.logisticsCompanyCode"
placeholder="请选择"
clearable
filterable
:teleported="false"
style="width: 150px"
>
<ElOption
v-for="(item, index) in allCodelist"
:key="index"
:value="item.code"
:label="item.basicsName"
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="规范素材">
<ElSelect
v-model="searchForm.newStandard"
placeholder="请选择"
clearable
filterable
style="width: 150px"
>
<ElOption
v-for="(_, index) in ['否', '是']"
:key="index"
:value="index"
:label="index === 0 ? '否' : '是'"
></ElOption>
</ElSelect>
</ElFormItem>
</ElForm>
<template #reference>
<el-button
type="warning"
@click="searchVisible = !searchVisible"
>
<el-icon v-if="searchVisible">
<CaretTop />
</el-icon>
<el-icon v-else>
<CaretBottom />
</el-icon>
</el-button>
</template>
</ElPopover>
</ElFormItem>
<ElFormItem>
<ElButton type="primary" @click="search"> 查询 </ElButton>
<ElButton @click="reset"> 重置 </ElButton>
</ElFormItem>
</ElForm>
</div>
</div>
<div class="operation-list">
<span v-if="currentStatus === 'processed'" class="item">
<ElButton type="primary" @click="handleEmbryoInStock"
>胚衣入库</ElButton
>
</span>
<span v-if="currentStatus === 'processed'" class="item">
<ElButton type="success" @click="handleProductionCompleteInStock"
>生产完成入库</ElButton
>
</span>
</div>
<div class="card-content">
<CardLayout
ref="cardLayoutRef"
:query-payload="getQueryPayload()"
:fetch-list="fetchCardList"
@selection-change="handleCardSelectionChange"
@view-detail="handleViewDetail"
/>
</div>
</div>
</div>
<FastProduction
v-model:detail-visible="detailVisible"
:is-new-order="true"
:detail-data="detailData"
:fast-key="fastKey"
:default-auto-sure="true"
:show-operation-no-row="true"
not-found-message="操作单不存在"
pending-order-label="操作单号"
please-scan-tip="请扫码操作单号"
search-input-audio-tip="请录入操作单号"
history-storage-key="historyFactoryNewOrderFastReceipt"
tracking-placeholder="扫描枪输入操作单号"
:query-api="getOperationByNo"
:complete-api="completeOperationById"
@on-success="handleFastProductionSuccess"
@close="fastClose"
/>
<ReceiptProductDialog
ref="receiptProductDialogRef"
v-model:visible="receiptDialogVisible"
v-model:user-mark="receiptUserMark"
v-model:select-sku="receiptSelectSku"
title="创建入库单"
:disable-warehouse="true"
:show-user-mark-filter="false"
:show-query-button="false"
:show-batch-add-button="false"
:show-import-button="false"
:edit-form="receiptEditForm"
:rules="receiptRules"
:warehouse-list="warehouseList"
:other-purchase-data="otherPurchaseData"
:location-list="locationList"
:user-mark-list="receiptUserMarkList"
:sku-data="skuData"
:filter-sku-data="filterSkuData"
@warehouse-change="handleReceiptWarehouseChange"
@selection-change="handleReceiptProductSelectionChange"
@set-cost-price="setCostPrice"
@location-change="handleReceiptLocationChange"
@update:remark="updateReceiptRemark"
@update:warehouse-id="updateReceiptWarehouseId"
@delete="deleteReceiptProducts"
@save="handleReceiptSave"
/>
<!-- 快捷入库 -->
</template>
<script setup lang="ts">
import { nextTick, onMounted, ref } from 'vue'
import CardLayout from '../factoryOrderNew/component/CardLayout.vue'
import platformJson from '../../../json/platform.json'
import { useOrderDictionaries } from '../factoryOrderNew/hooks/useOrderDictionaries'
import { operateOrderListData } from '@/types/api/factoryOrderNew'
import {
completeDeliveryApi,
getByOperationNoLogApi,
getFactoryOrderNewOperateDetailApi,
} from '@/api/factoryOrderNew'
import { getCancelOrderProcessListApi } from '@/api/cancelOrderProcess'
import type { CardLayoutListFetcher } from '@/types/api/factoryOrderNew'
import LogisticsWaySelect from '@/views/logistics/components/LogisticsWaySelect'
import { SearchForm } from '@/types/api/order/factoryOrderNew'
import ProductTypeFilter from '../factoryOrderNew/component/ProductTypeFilter.vue'
import { CaretBottom, CaretTop } from '@element-plus/icons-vue'
import { normalizeProductMarkListForQuery } from '../factoryOrderNew/utils/productMarkQuery'
import FastProduction from '../components/FastProduction.vue'
import { ResultInfoDataItem } from '@/types/api/order/common'
import { ElButton } from 'element-plus'
import ReceiptProductDialog from '@/views/warehouse/components/ReceiptProductDialog.vue'
import { useValue } from '@/utils/hooks/useValue'
import {
ILocation,
InterProductList,
InterskuList,
InterWarehouseDetail,
} from '@/types/api/warehouse'
import { useReceiptProductDialog } from '@/views/warehouse/hooks/useReceiptProductDialog'
import {
addInRecordApi,
getBySkuAndUserMarkApi,
getByWareHouseIdAndCodeApi,
warehouseInfo,
warehouseInfoGetAll,
} from '@/api/warehouse'
const cardLayoutRef = ref()
const fetchCardList: CardLayoutListFetcher = async (payload, current, size) => {
const res = await getCancelOrderProcessListApi(payload, current, size)
return res.data
}
const searchForm = ref<SearchForm>({})
const dateRange = ref<[string, string]>(['', ''])
const searchVisible = ref(false)
const pickerOptions = {
shortcuts: [
{
text: '今日',
value: () => {
const start = new Date()
start.setHours(0, 0, 0, 0)
const end = new Date()
end.setHours(23, 59, 59, 999)
return [start, end]
},
},
{
text: '最近7天',
value: () => {
const end = new Date()
end.setHours(23, 59, 59, 999)
const start = new Date()
start.setDate(start.getDate() - 6)
start.setHours(0, 0, 0, 0)
return [start, end]
},
},
{
text: '最近30天',
value: () => {
const end = new Date()
end.setHours(23, 59, 59, 999)
const start = new Date()
start.setDate(start.getDate() - 29)
start.setHours(0, 0, 0, 0)
return [start, end]
},
},
],
}
const toggleMulti = (value: boolean) => {
searchForm.value.multi = value
}
const getQueryPayload = () => {
const { productMarkList, tagsIdArr, ...rest } = searchForm.value
return {
...rest,
...normalizeProductMarkListForQuery(productMarkList),
...(Array.isArray(tagsIdArr) && tagsIdArr.length
? { tagsId: tagsIdArr.join(',') }
: {}),
startTime: dateRange.value?.[0] || null,
endTime: dateRange.value?.[1] || null,
}
}
const reset = () => {
searchForm.value = {}
dateRange.value = ['', '']
searchVisible.value = false
nextTick(() => {
search()
})
}
const search = () => {
cardLayoutRef.value?.clearSelection()
nextTick(() => {
cardLayoutRef.value?.refresh()
})
}
const cardSelectList = ref<operateOrderListData[]>([])
const handleCardSelectionChange = (items: operateOrderListData[]) => {
cardSelectList.value = items
}
const detailVisible = ref(false)
const fastKey = ref('')
const detailData = ref<Record<string, unknown>>({})
const handleViewDetail = async (item: operateOrderListData) => {
const loading = ElLoading.service({
fullscreen: true,
text: '加载中...',
background: 'rgba(0, 0, 0, 0.3)',
})
try {
const res = await getFactoryOrderNewOperateDetailApi(item.id)
if (res.code !== 200) return
detailData.value = res.data
fastKey.value = 'detail'
detailVisible.value = true
} catch (e) {
console.error(e)
} finally {
loading.close()
}
}
const getOperationByNo = (operationNo: string) =>
getByOperationNoLogApi(operationNo) as Promise<{ data?: unknown }>
const completeOperationById = (ids: number[]) => completeDeliveryApi(ids)
const handleFastProductionSuccess = (data: ResultInfoDataItem[]) => {
const result = data[0]
if (!result.status) {
ElMessageBox.alert(
`操作单号 ${result.factoryOrderNumber} ${result.message}`,
'提示',
{
type: 'error',
},
)
return
}
}
const fastClose = () => {
detailVisible.value = false
if (fastKey.value === 'detail') return
search()
}
const {
userMarkList,
customTagList,
allCodelist,
craftList,
productTypeGroups,
loadAllDictionaries,
} = useOrderDictionaries()
const orderStatus = ref<{
processed: number
unprocessed: number
}>({
processed: 0,
unprocessed: 0,
})
const currentStatus = ref<'processed' | 'unprocessed'>('processed')
const handleOrderStatusClick = (status: 'processed' | 'unprocessed') => {
currentStatus.value = status
search()
}
const receiptDialogVisible = ref(false)
const receiptUserMark = ref(0)
const receiptSelectSku = ref('')
const otherPurchaseData = ref<InterProductList[]>([])
const [receiptEditForm, resetReceiptEditForm] = useValue<InterWarehouseDetail>({
inNo: '',
warehouseId: '',
warehouseName: '',
remark: '',
factoryCode: '',
factoryId: 0,
productList: [],
})
const receiptRules = {
warehouseId: [{ required: true, message: '请选择仓库', trigger: 'change' }],
}
const batchUserMark = ref(0)
const importUserMark = ref(0)
const receiptUserMarkList = ref<
{ userId: number; userMark: string; userName: string }[]
>([{ userId: 0, userMark: '', userName: '' }])
const warehouseList = ref<warehouseInfo[]>([])
const locationList = ref<ILocation[]>([])
const otherReceiptSelection = ref<InterProductList[]>([])
const receiptProductDialogRef = ref()
const { skuData, setCostPrice, filterSkuData } = useReceiptProductDialog({
editForm: receiptEditForm,
otherPurchaseData,
userMark: receiptUserMark,
batchUserMark,
importUserMark,
selectSku: receiptSelectSku,
userMarkList: receiptUserMarkList,
})
function mapInterskuToProduct(val: InterskuList): InterProductList {
const warehouseSku = val.warehouseSku || val.sku || ''
const skuNameVal = val.skuName || val.productName || ''
let customerId: number | null = null
if (val.customerId != null && val.customerId !== '') {
const n = Number(val.customerId)
if (!Number.isNaN(n)) customerId = n
}
return {
skuImage: val.skuImage || val.image || '',
warehouseSku,
skuName: skuNameVal,
productNo: val.productNo ?? null,
locationCode: val.locationCode ?? '',
locationId: val.locationId ?? null,
costPrice: val.costPrice ?? null,
buyStored: null,
totalPrice: null,
currencyName: val.currencyName ?? null,
currencyCode: val.currencyCode ?? null,
customerId,
customerName: val.customerName ?? null,
userMark: val.userMark ?? null,
}
}
const handleEmbryoInStock = async () => {
if (cardSelectList.value.length !== 0) {
handleEmbryoInStockByCard()
} else {
handleEmbryoInFastStock()
}
}
const handleEmbryoInFastStock = async () => {
fastKey.value = 'fastReceipt'
detailVisible.value = true
detailData.value = {}
}
const handleEmbryoInStockByCard = async () => {
const firstWid = cardSelectList.value[0].warehouseId
if (cardSelectList.value.some((r) => r.warehouseId !== firstWid)) {
return ElMessage.error('请选择相同仓库的库存SKU!')
}
resetReceiptEditForm()
otherPurchaseData.value = []
receiptUserMark.value = 0
receiptSelectSku.value = ''
skuData.value = []
otherReceiptSelection.value = []
const userJson = localStorage.getItem('user')
if (userJson) {
try {
const userData = JSON.parse(userJson)
receiptEditForm.value.factoryCode = userData.factoryCode || ''
receiptEditForm.value.factoryId = userData.factoryId || 0
} catch {
// ignore
}
}
receiptEditForm.value.warehouseId = firstWid
receiptEditForm.value.warehouseName = cardSelectList.value[0]
.warehouseName as string
const wh = warehouseList.value.find((w) => w.id == firstWid)
if (wh) {
receiptEditForm.value.warehouseName = wh.name
}
const loading = ElLoading.service({
text: '加载中...',
background: 'rgba(0, 0, 0, 0.3)',
})
try {
const skus = cardSelectList.value.map((r) => r.thirdSkuCode as string)
const res = await getBySkuAndUserMarkApi(firstWid, skus.join(','), null)
if (res.code !== 200) return
otherPurchaseData.value = res.data.map((item: InterskuList) =>
mapInterskuToProduct(item),
)
await fetchReceiptLocationList('')
const listRes = await warehouseInfoGetAll()
warehouseList.value = listRes.data || []
receiptDialogVisible.value = true
} catch (e) {
console.error(e)
} finally {
loading.close()
}
}
const fetchReceiptLocationList = async (query: string) => {
if (!receiptEditForm.value.warehouseId) return
try {
const res = await getByWareHouseIdAndCodeApi(
receiptEditForm.value.warehouseId,
query,
)
const result = res.data || []
locationList.value = result.map((item: ILocation) => ({
locationId: item.id,
locationCode: item.locationCode,
}))
} catch (e) {
console.error(e)
}
}
const handleReceiptWarehouseChange = (val: number | string | undefined) => {
const found = warehouseList.value.find(
(item: warehouseInfo) => item.id === val,
)
receiptEditForm.value.warehouseName = found ? found.name : ''
}
const handleReceiptProductSelectionChange = (v: InterProductList[]) => {
otherReceiptSelection.value = v
}
const handleReceiptLocationChange = (
val: number | null | undefined,
row: InterProductList,
) => {
const found = locationList.value.find(
(item: ILocation) => item.locationId === val,
)
row.locationCode = found ? found.locationCode : ''
}
const updateReceiptRemark = (value: string) => {
receiptEditForm.value.remark = value
}
const updateReceiptWarehouseId = (value: number | string | undefined) => {
receiptEditForm.value.warehouseId = value
}
const deleteReceiptProducts = () => {
const arr = otherReceiptSelection.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 handleReceiptSave = async () => {
try {
await receiptProductDialogRef.value?.validateForm()
} 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
}
const found = locationList.value.find(
(item: ILocation) => item.locationId === arr[i].locationId,
)
if (!arr[i].locationCode) {
arr[i].locationCode = found ? found?.locationCode : ''
}
}
const params = {
...receiptEditForm.value,
productList: otherPurchaseData.value,
}
const loading = ElLoading.service({
text: '保存中...',
background: 'rgba(0, 0, 0, 0.3)',
})
try {
await addInRecordApi(params)
ElMessage.success('保存成功')
receiptDialogVisible.value = false
} catch (e) {
console.error(e)
} finally {
loading.close()
}
}
const handleProductionCompleteInStock = () => {
// 客户定制的单子不能操作生产完成入库,提示:客户定制商品,不能入库!
if (cardSelectList.value.length !== 0) {
handleEmbryoInStockByCard()
} else {
handleEmbryoInFastStock()
}
}
onMounted(() => {
void loadAllDictionaries()
search()
})
</script>
<style scoped lang="scss">
.order-status {
width: 180px;
}
.order-status-item {
font-size: 14px;
cursor: pointer;
padding-left: 10px;
height: 30px;
line-height: 30px;
color: #333;
font-weight: 500;
&:hover {
background-color: #f5f7fa;
}
&.order-status-item-active {
background-color: #f5f7fa;
color: #409eff;
}
}
.card-content {
flex: 1;
margin-top: 10px;
overflow: hidden;
}
.header-filter-form {
width: 100%;
min-width: 0;
}
.search-form {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0;
min-width: 0;
:deep(.el-form-item) {
margin-right: 10px;
margin-bottom: 10px;
}
:deep(.el-form-item__content) {
min-width: 0;
}
}
</style>
...@@ -85,7 +85,7 @@ import { ...@@ -85,7 +85,7 @@ import {
} from '@/api/logistics' } from '@/api/logistics'
import { createLogisticsOrdersApi } from '@/api/podCnOrder' import { createLogisticsOrdersApi } from '@/api/podCnOrder'
import { FactoryOrderNewListData } from '@/types/api/factoryOrderNew/factoryOrderNew' import { FactoryOrderNewListData } from '@/types/api/factoryOrderNew'
const createLogisticDialogVisible = ref(false) const createLogisticDialogVisible = ref(false)
const props = defineProps<{ const props = defineProps<{
......
<template> <template>
<el-dialog <el-dialog
v-model="dialogVisible" v-model="dialogVisible"
:title="fastKey === 'detail' ? '查看详情' : '快捷生产'" :title="title"
top="140px" top="140px"
:fullscreen="true" :fullscreen="true"
:close-on-click-modal="false" :close-on-click-modal="false"
...@@ -44,7 +44,10 @@ ...@@ -44,7 +44,10 @@
</div> </div>
</div> </div>
<div class="right"> <div class="right">
<div v-if="fastKey === 'fastProduction'" class="input"> <div
v-if="['fastProduction', 'fastReceipt'].includes(fastKey)"
class="input"
>
<el-input <el-input
ref="trackingNumberRef" ref="trackingNumberRef"
v-model="TrackingNumber" v-model="TrackingNumber"
...@@ -60,20 +63,35 @@ ...@@ -60,20 +63,35 @@
<div class="div-text"> <div class="div-text">
<div class="div-content"> <div class="div-content">
<div :title="String(detail?.userMark)" class="div-item"> <div :title="String(detail?.userMark)" class="div-item">
<span style="font-size: 18px">客户</span> <span class="div-item-label" style="font-size: 18px"
<p style="color: red; font-size: 30px"> >客户:</span
>
<div class="div-item-value" style="color: red; font-size: 30px">
{{ detail?.userMark }} {{ detail?.userMark }}
</p> </div>
</div> </div>
<div <div
:title="String(detail?.factoryOrderNumber)" :title="String(detail?.factoryOrderNumber)"
class="div-item" class="div-item"
style="margin-top: 14px"
> >
<span style="font-size: 18px">订单号</span> <span class="div-item-label" style="font-size: 18px"
<p style="color: red; font-size: 22px"> >订单号:</span
>
<div class="div-item-value" style="color: red; font-size: 22px">
{{ detail?.factoryOrderNumber }} {{ detail?.factoryOrderNumber }}
</p> </div>
</div>
<div
v-if="fastKey === 'fastReceipt'"
:title="String(detail?.shopNumber)"
class="div-item"
>
<span class="div-item-label" style="font-size: 18px"
>店铺单号:</span
>
<div class="div-item-value" style="color: red; font-size: 22px">
{{ detail?.shopNumber }}
</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -86,77 +104,132 @@ ...@@ -86,77 +104,132 @@
:title="String(operationNoDisplay)" :title="String(operationNoDisplay)"
class="div-item" class="div-item"
> >
<span>操作单号</span> <span class="div-item-label">操作单号:</span>
<p>{{ operationNoDisplay }}</p> <div class="div-item-value">{{ operationNoDisplay }}</div>
</div> </div>
<div <div
v-else v-else
:title="detail?.factorySubOrderNumber" :title="detail?.factorySubOrderNumber"
class="div-item" class="div-item"
> >
<span>生产单号</span> <span class="div-item-label">生产单号:</span>
<p> <div class="div-item-value">
{{ detail?.factorySubOrderNumber }} {{ detail?.factorySubOrderNumber }}
</p> </div>
</div>
<div
v-if="fastKey === 'fastReceipt'"
:title="setProductMark(String(detail.productMark))"
class="div-item"
>
<span class="div-item-label">类型:</span>
<div
class="div-item-value"
style="font-weight: bold; color: red"
>
{{ setProductMark(String(detail.productMark)) }}
</div>
</div>
<div
v-if="fastKey === 'fastReceipt'"
:title="String(detail.productName) || ''"
class="div-item"
>
<span class="div-item-label">商品名称:</span>
<div class="div-item-value">{{ detail.productName || '' }}</div>
</div>
<div
v-if="fastKey === 'fastReceipt'"
:title="String(detail.statusName || '')"
class="div-item"
>
<span class="div-item-label">挂起前状态:</span>
<div class="div-item-value">
<ElTag v-if="detail.statusName" type="primary">{{ detail.statusName || '' }}</ElTag
>
</div>
</div>
<div
v-if="fastKey === 'fastReceipt'"
:title="String(detail.thirdSkuCode)"
class="div-item"
>
<span class="div-item-label">库存SKU:</span>
<div class="div-item-value">{{ detail.thirdSkuCode }}</div>
</div> </div>
<div <div
v-if="!showOperationNoRow" v-if="!showOperationNoRow"
:title="detail?.thirdSubOrderNumber || ''" :title="detail?.thirdSubOrderNumber || ''"
class="div-item" class="div-item"
> >
<span>第三方生产单号</span> <span class="div-item-label">第三方生产单号:</span>
<p> <div class="div-item-value">
{{ detail?.thirdSubOrderNumber }} {{ detail?.thirdSubOrderNumber }}
</p> </div>
</div> </div>
<div :title="String(detail?.craftName)" class="div-item"> <div :title="String(detail?.craftName)" class="div-item">
<span>生产工艺</span> <span class="div-item-label">生产工艺:</span>
<p> <div class="div-item-value">
{{ detail?.craftName }} {{ detail?.craftName }}
</p> </div>
</div> </div>
<div :title="detail?.baseSku" class="div-item"> <div
<span>基版</span> v-if="fastKey !== 'fastReceipt'"
<p>{{ detail?.baseSku }}</p> :title="detail?.baseSku"
class="div-item"
>
<span class="div-item-label">基版:</span>
<div class="div-item-value">{{ detail?.baseSku }}</div>
</div> </div>
<div :title="detail?.variantSku" class="div-item"> <div :title="detail?.variantSku" class="div-item">
<span>变体SKU</span> <span class="div-item-label">变体SKU:</span>
<p>{{ detail?.variantSku }}</p> <div class="div-item-value">{{ detail?.variantSku }}</div>
</div> </div>
<div <div
v-if="fastKey !== 'fastReceipt'"
:title=" :title="
String(showOperationNoRow ? detail?.quantity : detail?.num) String(showOperationNoRow ? detail?.quantity : detail?.num)
" "
class="div-item" class="div-item"
> >
<span>数量</span> <span class="div-item-label">数量:</span>
<p>{{ showOperationNoRow ? detail?.quantity : detail?.num }}</p> <div class="div-item-value">
{{ showOperationNoRow ? detail?.quantity : detail?.num }}
</div>
</div> </div>
<div :title="String(detail?.size)" class="div-item"> <div
<span>尺寸</span> v-if="fastKey !== 'fastReceipt'"
<p>{{ detail?.size }}</p> :title="String(detail?.size)"
class="div-item"
>
<span class="div-item-label">尺寸:</span>
<div class="div-item-value">{{ detail?.size }}</div>
</div> </div>
<div <div
v-if="detail?.sizeType" v-if="detail?.sizeType && fastKey !== 'fastReceipt'"
:title="String(detail?.sizeType)" :title="String(detail?.sizeType)"
class="div-item" class="div-item"
> >
<span>尺码类型</span> <span class="div-item-label">尺码类型:</span>
<p> <div class="div-item-value">
{{ sizeList.find((i) => i.value === detail.sizeType)?.name }} {{ sizeList.find((i) => i.value === detail.sizeType)?.name }}
</p> </div>
</div> </div>
<div :title="detail?.shopNumber ?? ''" class="div-item"> <div
<span>店铺单号</span> v-if="fastKey !== 'fastReceipt'"
<p>{{ detail?.shopNumber ?? '' }}</p> :title="detail?.shopNumber ?? ''"
class="div-item"
>
<span class="div-item-label">店铺单号:</span>
<div class="div-item-value">{{ detail?.shopNumber ?? '' }}</div>
</div> </div>
<div :title="detail?.createTime" class="div-item"> <div :title="detail?.createTime" class="div-item">
<span>创建时间</span> <span class="div-item-label">创建时间:</span>
<p>{{ detail?.createTime }}</p> <div class="div-item-value">{{ detail?.createTime }}</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -164,7 +237,10 @@ ...@@ -164,7 +237,10 @@
<div class="btn"> <div class="btn">
<div <div
:style="{ :style="{
visibility: fastKey === 'fastProduction' ? 'visible' : 'hidden', visibility:
fastKey === 'fastProduction' || fastKey === 'fastReceipt'
? 'visible'
: 'hidden',
}" }"
class="btn-sure" class="btn-sure"
> >
...@@ -174,13 +250,13 @@ ...@@ -174,13 +250,13 @@
type="success" type="success"
@click="changeStatus" @click="changeStatus"
> >
生产完成 {{ fastKey === 'fastProduction' ? '生产完成' : '快捷入库' }}
</el-button> </el-button>
<div class="check"> <div class="check">
<el-checkbox v-model="isAutoSure"> 自动完成上一单 </el-checkbox> <el-checkbox v-model="isAutoSure"> 自动完成上一单 </el-checkbox>
</div> </div>
</div> </div>
<div class="btn-down"> <div v-if="fastKey !== 'fastReceipt'" class="btn-down">
<div class="check"> <div class="check">
<el-checkbox v-model="isDownloadImage" size="large"> <el-checkbox v-model="isDownloadImage" size="large">
扫码下载素材 扫码下载素材
...@@ -243,12 +319,21 @@ interface HistoryDataItem { ...@@ -243,12 +319,21 @@ interface HistoryDataItem {
orderNumber: string orderNumber: string
finished: boolean finished: boolean
} }
const title = computed(() => {
if (props.fastKey === 'fastProduction') {
return '快捷生产'
} else if (props.fastKey === 'fastReceipt') {
return '快捷入库'
} else {
return '查看详情'
}
})
export type FastProductionDetail = PodOrderRes & { export type FastProductionDetail = PodOrderRes & {
operationNo?: string | null operationNo?: string | null
quantity?: number | null quantity?: number | null
podOrderNo?: string | null podOrderNo?: string | null
podOrderProductId?: number | null podOrderProductId?: number | null
statusName?: string | null
} }
const trackingNumberRef = ref() const trackingNumberRef = ref()
const historyData = ref<HistoryDataItem[]>([]) const historyData = ref<HistoryDataItem[]>([])
...@@ -422,7 +507,10 @@ watch( ...@@ -422,7 +507,10 @@ watch(
historyData.value = history ? JSON.parse(history) : [] historyData.value = history ? JSON.parse(history) : []
const len = historyData.value const len = historyData.value
if (len.length > 0 && props.fastKey === 'fastProduction') { if (
len.length > 0 &&
(props.fastKey === 'fastProduction' || props.fastKey === 'fastReceipt')
) {
confirmQuery(len, 0) confirmQuery(len, 0)
} }
placeholderText.value = props.trackingPlaceholder placeholderText.value = props.trackingPlaceholder
...@@ -452,7 +540,9 @@ watch( ...@@ -452,7 +540,9 @@ watch(
const confirmQuery = (len: HistoryDataItem[], i: number) => { const confirmQuery = (len: HistoryDataItem[], i: number) => {
const el = len[i] const el = len[i]
showConfirm( showConfirm(
`${props.pendingOrderLabel} ${el.orderNumber} 未生产完成,取消则不提醒?`, `${props.pendingOrderLabel} ${el.orderNumber} ${
props.fastKey === 'fastProduction' ? '未生产' : '未入库'
}完成,取消则不提醒?`,
{ {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
...@@ -562,7 +652,7 @@ const download = async () => { ...@@ -562,7 +652,7 @@ const download = async () => {
if (detail.value && detail.value?.id != -1) { if (detail.value && detail.value?.id != -1) {
try { try {
const id = props.isNewOrder const id = props.isNewOrder
? detail.value.podOrderProductId as number ? (detail.value.podOrderProductId as number)
: detail.value.id : detail.value.id
if (id !== undefined) { if (id !== undefined) {
try { try {
...@@ -668,6 +758,12 @@ const trackCodeInput = async () => { ...@@ -668,6 +758,12 @@ const trackCodeInput = async () => {
const onOpened = () => { const onOpened = () => {
trackingNumberRef.value && trackingNumberRef.value.focus() trackingNumberRef.value && trackingNumberRef.value.focus()
} }
function setProductMark(productMark: string) {
if (!productMark) return ''
if (productMark === 'custom_normal') return 'CB'
if (productMark === 'normal') return 'G'
return ''
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.sure-btn { .sure-btn {
...@@ -784,27 +880,27 @@ const onOpened = () => { ...@@ -784,27 +880,27 @@ const onOpened = () => {
align-items: flex-start; align-items: flex-start;
padding: 15px 10px; padding: 15px 10px;
box-sizing: border-box; box-sizing: border-box;
position: relative;
border: 1px solid #ececec;
.div-item { .div-item {
width: 50%; width: 50%;
margin-bottom: 10px; margin-bottom: 10px;
display: flex; display: flex;
align-items: center; align-items: center;
height: 36px;
line-height: 36px;
p { .div-item-label {
font-weight: 400;
color: black;
}
span {
display: inline-block; display: inline-block;
text-align: right; text-align: right;
width: 120px; width: 120px;
} }
.div-item-value {
span::after { flex: 1;
content: ':'; text-overflow: ellipsis;
margin: 0 3px; overflow: hidden;
white-space: nowrap;
} }
} }
} }
...@@ -819,11 +915,6 @@ const onOpened = () => { ...@@ -819,11 +915,6 @@ const onOpened = () => {
color: black; color: black;
z-index: 3; z-index: 3;
} }
.div-content {
position: relative;
border: 1px solid #ececec;
}
} }
.input { .input {
......
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { updateCustomDeclarationInfoApi } from '@/api/podCnOrder' import { updateCustomDeclarationInfoApi } from '@/api/podCnOrder'
import { FactoryOrderNewListData } from '@/types/api/factoryOrderNew/factoryOrderNew' import { FactoryOrderNewListData } from '@/types/api/factoryOrderNew'
import { import {
CustomDeclarationInfoForm, CustomDeclarationInfoForm,
PodCnOrderListData, PodCnOrderListData,
......
...@@ -196,7 +196,7 @@ import { ...@@ -196,7 +196,7 @@ import {
printPickPdfByBatchNumberApi, printPickPdfByBatchNumberApi,
printProductionPdfByBatchNumberApi, printProductionPdfByBatchNumberApi,
} from '@/api/factoryOrderNew' } from '@/api/factoryOrderNew'
import type { BatchManageData } from '@/types/api/factoryOrderNew/factoryOrderNew' import type { BatchManageData } from '@/types/api/factoryOrderNew'
import type { PaginationData } from '@/types/api' import type { PaginationData } from '@/types/api'
import TableView from '@/components/TableView.vue' import TableView from '@/components/TableView.vue'
import ArrangeDialog from './ArrangeDialog.vue' import ArrangeDialog from './ArrangeDialog.vue'
......
...@@ -293,19 +293,32 @@ import { ...@@ -293,19 +293,32 @@ import {
getFactoryOrderNewLogApi, getFactoryOrderNewLogApi,
} from '@/api/factoryOrderNew' } from '@/api/factoryOrderNew'
import type { PaginationData } from '@/types/api' import type { PaginationData } from '@/types/api'
import type { CardLayoutListFetcher } from '@/types/api/factoryOrderNew'
import usePageList from '@/utils/hooks/usePageList' import usePageList from '@/utils/hooks/usePageList'
import { operateOrderListData } from '@/types/api/factoryOrderNew/factoryOrderNew' import { operateOrderListData } from '@/types/api/factoryOrderNew'
import type { LogListData } from '@/types/api/order' import type { LogListData } from '@/types/api/order'
import LogList from '@/components/LogList.vue' import LogList from '@/components/LogList.vue'
import RightClickMenu from '@/components/RightClickMenu.vue' import RightClickMenu from '@/components/RightClickMenu.vue'
import platformJson from '../../../../json/platform.json' import platformJson from '../../../../json/platform.json'
const props = defineProps<{ const props = defineProps<{
status: string status?: string
queryPayload: Record<string, unknown> queryPayload?: Record<string, unknown>
initPageSize?: number initPageSize?: number
fetchList?: CardLayoutListFetcher
}>() }>()
const buildListPayload = () => {
const payload = { ...props.queryPayload }
if (props.fetchList || props.status === undefined) {
return payload
}
return {
...payload,
status: props.status === 'ALL' ? undefined : props.status,
}
}
const emit = defineEmits<{ const emit = defineEmits<{
'selection-change': [items: operateOrderListData[]] 'selection-change': [items: operateOrderListData[]]
'view-detail': [item: operateOrderListData] 'view-detail': [item: operateOrderListData]
...@@ -324,9 +337,9 @@ const { ...@@ -324,9 +337,9 @@ const {
initPageSize: props.initPageSize || 100, initPageSize: props.initPageSize || 100,
initLoad: false, initLoad: false,
query: async (current, size) => { query: async (current, size) => {
const payload = { const payload = buildListPayload()
...props.queryPayload, if (props.fetchList) {
status: props.status === 'ALL' ? undefined : props.status, return props.fetchList(payload, current, size)
} }
const res = await getCardLayoutListApi(payload, current, size) const res = await getCardLayoutListApi(payload, current, size)
return res.data as unknown as PaginationData<operateOrderListData> return res.data as unknown as PaginationData<operateOrderListData>
...@@ -411,13 +424,20 @@ const rightChange = (code: string) => { ...@@ -411,13 +424,20 @@ const rightChange = (code: string) => {
const openLogDialog = async (item: operateOrderListData) => { const openLogDialog = async (item: operateOrderListData) => {
if (!item.podOrderId) return if (!item.podOrderId) return
const loading = ElLoading.service({
fullscreen: true,
text: '加载中...',
background: 'rgba(0, 0, 0, 0.3)',
})
try { try {
const res = await getFactoryOrderNewLogApi(item.podOrderId as number) const res = await getFactoryOrderNewLogApi(item.podOrderId as number)
logList.value = (res.data || []) as unknown as LogListData[] logList.value = (res.data || []) as unknown as LogListData[]
logVisible.value = true logVisible.value = true
} catch (e) { } catch (e) {
// ignore // ignore
} } finally {
loading.close()
}
} }
const clearSelection = () => { const clearSelection = () => {
......
...@@ -257,7 +257,7 @@ import platformJson from '../../../../json/platform.json' ...@@ -257,7 +257,7 @@ import platformJson from '../../../../json/platform.json'
import type { import type {
operateOrderListData, operateOrderListData,
PickCompleteData, PickCompleteData,
} from '@/types/api/factoryOrderNew/factoryOrderNew' } from '@/types/api/factoryOrderNew'
const emit = defineEmits(['adjustPickOrderSuccess']) const emit = defineEmits(['adjustPickOrderSuccess'])
const props = defineProps<{ const props = defineProps<{
......
...@@ -123,7 +123,7 @@ import { ...@@ -123,7 +123,7 @@ import {
replenishmentCompleteApi, replenishmentCompleteApi,
markStockOutOfApi, markStockOutOfApi,
} from '@/api/factoryOrderNew' } from '@/api/factoryOrderNew'
import type { PickCompleteData } from '@/types/api/factoryOrderNew/factoryOrderNew' import type { PickCompleteData } from '@/types/api/factoryOrderNew'
import type { BaseRespData } from '@/types/api' import type { BaseRespData } from '@/types/api'
import type { import type {
InterProductList, InterProductList,
......
...@@ -71,7 +71,7 @@ import { ref } from 'vue' ...@@ -71,7 +71,7 @@ import { ref } from 'vue'
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus' import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import { pickCompleteByIdsDataApi } from '@/api/factoryOrderNew' import { pickCompleteByIdsDataApi } from '@/api/factoryOrderNew'
import type { PickCompleteData } from '@/types/api/factoryOrderNew/factoryOrderNew' import type { PickCompleteData } from '@/types/api/factoryOrderNew'
import TableView from '@/components/TableView.vue' import TableView from '@/components/TableView.vue'
import _ from 'lodash' import _ from 'lodash'
import CreateOutboundDialog from './CreateOutboundDialog.vue' import CreateOutboundDialog from './CreateOutboundDialog.vue'
......
...@@ -63,7 +63,7 @@ const formRef = ref<FormInstance>() ...@@ -63,7 +63,7 @@ const formRef = ref<FormInstance>()
const orderIds = ref<(number | string)[]>([]) const orderIds = ref<(number | string)[]>([])
const suspendReasons = [ const suspendReasons = [
{ label: '客户拦截', value: 1 }, // { label: '客户拦截', value: 1 },
{ label: '地址异常', value: 2 }, { label: '地址异常', value: 2 },
{ label: '素材异常', value: 3 }, { label: '素材异常', value: 3 },
{ label: '其他', value: 4 }, { label: '其他', value: 4 },
......
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
import { reactive } from 'vue' import { reactive } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { getRestockListApi, restockCheckApi } from '@/api/factoryOrderNew' import { getRestockListApi, restockCheckApi } from '@/api/factoryOrderNew'
import type { RestockData } from '@/types/api/factoryOrderNew/factoryOrderNew' import type { RestockData } from '@/types/api/factoryOrderNew'
import TableView from '@/components/TableView.vue' import TableView from '@/components/TableView.vue'
import usePageList from '@/utils/hooks/usePageList' import usePageList from '@/utils/hooks/usePageList'
......
...@@ -50,8 +50,11 @@ export function useOrderBatchActions(options: UseOrderBatchActionsOptions) { ...@@ -50,8 +50,11 @@ export function useOrderBatchActions(options: UseOrderBatchActionsOptions) {
const res = await action.api(ids) const res = await action.api(ids)
if (res.code !== 200) return if (res.code !== 200) return
if (action.successText) ElMessage.success(action.successText) if (action.successText) ElMessage.success(action.successText)
if (action.onSuccess) await action.onSuccess(res) if (action.onSuccess) {
await refreshCurrentView({ isRefreshTree: !!action.refreshTree }) await action.onSuccess(res)
} else {
await refreshCurrentView({ isRefreshTree: !!action.refreshTree })
}
if (action.onAfter) await action.onAfter() if (action.onAfter) await action.onAfter()
} catch (e) { } catch (e) {
console.error(e) console.error(e)
......
...@@ -141,8 +141,6 @@ export function useOrderDictionaries() { ...@@ -141,8 +141,6 @@ export function useOrderDictionaries() {
getUserMark(), getUserMark(),
getCustomTagList(), getCustomTagList(),
getLogisticsCompanyAllCodelist(), getLogisticsCompanyAllCodelist(),
getReceiverCountryList(),
loadWarehouseList(),
]) ])
} }
......
...@@ -5,8 +5,9 @@ import { ...@@ -5,8 +5,9 @@ import {
getFactoryOrderNewDetailApi, getFactoryOrderNewDetailApi,
getFactoryOrderNewListApi, getFactoryOrderNewListApi,
getFactoryOrderNewLogApi, getFactoryOrderNewLogApi,
getOperationOrderByIdApi,
} from '@/api/factoryOrderNew' } from '@/api/factoryOrderNew'
import type { SearchForm } from '@/types/api/factoryOrderNew/factoryOrderNew' import type { SearchForm } from '@/types/api/factoryOrderNew'
import type { import type {
FactoryOrderNewListData, FactoryOrderNewListData,
LogListData, LogListData,
...@@ -21,6 +22,7 @@ interface UseOrderListAndDetailOptions { ...@@ -21,6 +22,7 @@ interface UseOrderListAndDetailOptions {
getQueryPayload: () => Record<string, unknown> getQueryPayload: () => Record<string, unknown>
getListPageAcceptedSubStatus: () => number | undefined getListPageAcceptedSubStatus: () => number | undefined
suspendedSubTab: Ref<number> suspendedSubTab: Ref<number>
cancelledSubTab: Ref<number>
} }
export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) { export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) {
...@@ -31,11 +33,13 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) { ...@@ -31,11 +33,13 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) {
getQueryPayload, getQueryPayload,
getListPageAcceptedSubStatus, getListPageAcceptedSubStatus,
suspendedSubTab, suspendedSubTab,
cancelledSubTab,
} = options } = options
const subLoading = ref(false) const subLoading = ref(false)
const activeTab = ref<'product' | 'log'>('product') const activeTab = ref<'product' | 'operation' | 'log'>('product')
const productList = ref<ProductListData[]>([]) const productList = ref<ProductListData[]>([])
const operationOrderList = ref<operateOrderListData[]>([])
const logList = ref<LogListData[]>([]) const logList = ref<LogListData[]>([])
const tableRef = ref() const tableRef = ref()
const currentRow = ref<FactoryOrderNewListData | null>(null) const currentRow = ref<FactoryOrderNewListData | null>(null)
...@@ -70,6 +74,7 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) { ...@@ -70,6 +74,7 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) {
} = usePageList<FactoryOrderNewListData>({ } = usePageList<FactoryOrderNewListData>({
query: (page, size) => { query: (page, size) => {
const isSuspend = status.value === 'SUSPEND' const isSuspend = status.value === 'SUSPEND'
const isCancelled = status.value === 'CANCELLED'
return getFactoryOrderNewListApi( return getFactoryOrderNewListApi(
buildListQueryBody(), buildListQueryBody(),
page, page,
...@@ -77,6 +82,7 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) { ...@@ -77,6 +82,7 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) {
status.value === 'ALL' ? undefined : status.value, status.value === 'ALL' ? undefined : status.value,
getListPageAcceptedSubStatus(), getListPageAcceptedSubStatus(),
isSuspend ? suspendedSubTab.value : undefined, isSuspend ? suspendedSubTab.value : undefined,
isCancelled ? cancelledSubTab.value : undefined,
).then(async (res) => { ).then(async (res) => {
const records = res.data.records || [] const records = res.data.records || []
await nextTick(() => { await nextTick(() => {
...@@ -98,6 +104,7 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) { ...@@ -98,6 +104,7 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) {
selectedRows.value = [] selectedRows.value = []
cardSelectList.value = [] cardSelectList.value = []
productList.value = [] productList.value = []
operationOrderList.value = []
logList.value = [] logList.value = []
currentRow.value = null currentRow.value = null
listSortProp.value = null listSortProp.value = null
...@@ -133,7 +140,8 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) { ...@@ -133,7 +140,8 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) {
) { ) {
return return
} }
const sortProp = LIST_SORT_PROP_BY_COLUMN[prop as keyof typeof LIST_SORT_PROP_BY_COLUMN] const sortProp =
LIST_SORT_PROP_BY_COLUMN[prop as keyof typeof LIST_SORT_PROP_BY_COLUMN]
if (order === 'ascending') { if (order === 'ascending') {
listSortProp.value = sortProp listSortProp.value = sortProp
listSortOrder.value = 'asc' listSortOrder.value = 'asc'
...@@ -156,9 +164,12 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) { ...@@ -156,9 +164,12 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) {
cardSelectList.value = items cardSelectList.value = items
} }
const getOrderDetailsById = async (tabName?: 'product' | 'log') => { const getOrderDetailsById = async (
tabName?: 'product' | 'operation' | 'log',
) => {
if (!currentRow.value) { if (!currentRow.value) {
productList.value = [] productList.value = []
operationOrderList.value = []
logList.value = [] logList.value = []
return return
} }
...@@ -177,6 +188,11 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) { ...@@ -177,6 +188,11 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) {
productList.value = Array.isArray(productRes.data) productList.value = Array.isArray(productRes.data)
? productRes.data ? productRes.data
: [] : []
} else if (effectiveTab === 'operation') {
operationOrderList.value = []
const opRes = await getOperationOrderByIdApi(id)
if (opRes.code !== 200) return
operationOrderList.value = opRes.data
} else { } else {
logList.value = [] logList.value = []
// const logRes = isSuspend // const logRes = isSuspend
...@@ -196,6 +212,7 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) { ...@@ -196,6 +212,7 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) {
watch(currentRow, (row) => { watch(currentRow, (row) => {
if (!row) { if (!row) {
productList.value = [] productList.value = []
operationOrderList.value = []
logList.value = [] logList.value = []
return return
} }
...@@ -213,7 +230,7 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) { ...@@ -213,7 +230,7 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) {
const handleTabClick = (tab: TabsPaneContext) => { const handleTabClick = (tab: TabsPaneContext) => {
if (!currentRow.value) return if (!currentRow.value) return
const name = tab?.props?.name as 'product' | 'log' | undefined const name = tab?.props?.name as 'product' | 'operation' | 'log' | undefined
void getOrderDetailsById(name) void getOrderDetailsById(name)
} }
...@@ -221,6 +238,7 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) { ...@@ -221,6 +238,7 @@ export function useOrderListAndDetail(options: UseOrderListAndDetailOptions) {
subLoading, subLoading,
activeTab, activeTab,
productList, productList,
operationOrderList,
logList, logList,
tableRef, tableRef,
currentRow, currentRow,
......
import { computed, ref, nextTick } from 'vue' import { computed, ref, nextTick } from 'vue'
import { import {
getCancelledOrderStatisticsApi,
getPodOrderAcceptedStatisticsApi, getPodOrderAcceptedStatisticsApi,
getPodOrderStateGroupListApi, getPodOrderStateGroupListApi,
getSuspendStatisticsApi, getSuspendStatisticsApi,
} from '@/api/factoryOrderNew' } from '@/api/factoryOrderNew'
import type { StatusTreeNode } from '@/types/api/order/factoryOrderNew' import type { StatusTreeNode } from '@/types/api/order/factoryOrderNew'
import type { SearchForm } from '@/types/api/factoryOrderNew'
interface UseOrderStatusTreeOptions { interface UseOrderStatusTreeOptions {
getQueryPayload: () => Record<string, unknown> getQueryPayload: () => Record<string, unknown>
currentPage: { value: number } currentPage: { value: number }
pageSize: { value: number } pageSize: { value: number }
onClearTableState: () => void
onRefreshCurrentView: () => void
} }
export function useOrderStatusTree(options: UseOrderStatusTreeOptions) { export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
...@@ -19,8 +19,6 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) { ...@@ -19,8 +19,6 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
getQueryPayload, getQueryPayload,
currentPage, currentPage,
pageSize, pageSize,
onClearTableState,
onRefreshCurrentView,
} = options } = options
const cardLayoutStatuses = [ const cardLayoutStatuses = [
...@@ -46,12 +44,19 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) { ...@@ -46,12 +44,19 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
acceptedOutOfStockCount: 0, acceptedOutOfStockCount: 0,
}) })
const suspendedTabs = ref([ const suspendedTabs = ref([
{ label: '客户拦截', key: 'customerInterceptCount', value: 1, count: 0 }, { label: '客户拦截-取消订单', key: 'customerInterceptCount', value: 1, count: 0 },
{ label: '地址异常', key: 'addressExceptionCount', value: 2, count: 0 }, { label: '地址异常', key: 'addressExceptionCount', value: 2, count: 0 },
{ label: '素材异常', key: 'materialExceptionCount', value: 3, count: 0 }, { label: '素材异常', key: 'materialExceptionCount', value: 3, count: 0 },
{ label: '其他', key: 'otherReasonCount', value: 4, count: 0 }, { label: '其他', key: 'otherReasonCount', value: 4, count: 0 },
]) ])
const suspendedSubTab = ref(1) const suspendedSubTab = ref(1)
/** 已取消:子 tab 与 list_page 的 cancelSubType 取值 1/2/3 对应 */
const cancelledTabs = ref([
{ label: '客户拦截', key: 'customerInterceptCount', value: 1, count: 0 },
{ label: '协商取消', key: 'mutualAgreeCancelCount', value: 2, count: 0 },
{ label: '其他', key: 'otherReasonCount', value: 3, count: 0 },
])
const cancelledSubTab = ref(1)
const treeRef = ref() const treeRef = ref()
const isCardLayout = computed(() => cardLayoutStatuses.includes(status.value)) const isCardLayout = computed(() => cardLayoutStatuses.includes(status.value))
...@@ -107,6 +112,25 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) { ...@@ -107,6 +112,25 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
} }
} }
const getCancelledCounts = async () => {
try {
const res = await getCancelledOrderStatisticsApi(
getQueryPayload() as SearchForm,
currentPage.value,
pageSize.value,
cancelledSubTab.value,
)
if (res.code !== 200 || !res.data) return
const data = res.data || {}
cancelledTabs.value = cancelledTabs.value.map((tab) => ({
...tab,
count: data[String(tab.key)] ?? 0,
}))
} catch (e) {
console.error(e)
}
}
const loadStatusTreeCounts = async () => { const loadStatusTreeCounts = async () => {
try { try {
const res = await getPodOrderStateGroupListApi() const res = await getPodOrderStateGroupListApi()
...@@ -121,22 +145,6 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) { ...@@ -121,22 +145,6 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
} }
} }
const handleStatusNodeClick = (node: StatusTreeNode) => {
status.value = node.status
if (node.status !== 'PENDING_RECEIVE') {
pendingAcceptSubTab.value = 'PENDING_RECEIVE'
}
if (node.status !== 'SUSPEND') {
suspendedSubTab.value = 1
}
onClearTableState()
if (!isSpecialLayout.value) {
onRefreshCurrentView()
}
if (node.status === 'SUSPEND') {
void getSuspendCounts()
}
}
const handlePendingAcceptTabClick = ( const handlePendingAcceptTabClick = (
tab: 'PENDING_RECEIVE' | 'ACCEPT_FAIL_OUT_OF_STOCK', tab: 'PENDING_RECEIVE' | 'ACCEPT_FAIL_OUT_OF_STOCK',
...@@ -160,6 +168,8 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) { ...@@ -160,6 +168,8 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
pendingAcceptCounts, pendingAcceptCounts,
suspendedTabs, suspendedTabs,
suspendedSubTab, suspendedSubTab,
cancelledTabs,
cancelledSubTab,
treeRef, treeRef,
isCardLayout, isCardLayout,
isSpecialLayout, isSpecialLayout,
...@@ -167,9 +177,9 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) { ...@@ -167,9 +177,9 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
getListPageAcceptedSubStatus, getListPageAcceptedSubStatus,
getPendingReceiveCounts, getPendingReceiveCounts,
getSuspendCounts, getSuspendCounts,
getCancelledCounts,
loadStatusTreeCounts, loadStatusTreeCounts,
handleStatusNodeClick,
handlePendingAcceptTabClick, handlePendingAcceptTabClick,
toggleExpand, toggleExpand
} }
} }
...@@ -384,10 +384,7 @@ ...@@ -384,10 +384,7 @@
}} }}
</ElButton> </ElButton>
</span> </span>
<span <span v-if="status === 'PENDING_RECEIVE'" class="item">
v-if="status === 'PENDING_RECEIVE' || status === 'SUSPEND'"
class="item"
>
<ElButton type="danger" @click="handleCancelOrder">取消订单</ElButton> <ElButton type="danger" @click="handleCancelOrder">取消订单</ElButton>
</span> </span>
...@@ -571,6 +568,16 @@ ...@@ -571,6 +568,16 @@
> >
</span> </span>
<span class="item"> <span class="item">
<ElButton type="success" @click="() => handleInterceptionSuccess()"
>拦截成功</ElButton
>
</span>
<span class="item">
<ElButton type="danger" @click="() => handleInterceptionFail()"
>拦截失败</ElButton
>
</span>
<span class="item">
<ElButton type="primary" @click="handleSyncAddress" <ElButton type="primary" @click="handleSyncAddress"
>同步收货地址</ElButton >同步收货地址</ElButton
> >
...@@ -640,6 +647,18 @@ ...@@ -640,6 +647,18 @@
</div> </div>
</div> </div>
<!-- <div v-if="status === 'CANCELLED'" class="status-subtabs">
<div
v-for="tab in cancelledTabs"
:key="tab.value"
class="status-subtab"
:class="{ active: cancelledSubTab === tab.value }"
@click="handleCancelledTabClick(tab.value)"
>
{{ tab.label }}({{ tab.count || 0 }})
</div>
</div> -->
<div v-if="status === 'PENDING_RECEIVE'" class="status-subtabs"> <div v-if="status === 'PENDING_RECEIVE'" class="status-subtabs">
<div <div
class="status-subtab" class="status-subtab"
...@@ -742,6 +761,24 @@ ...@@ -742,6 +761,24 @@
> >
取消挂起 取消挂起
</ElButton> </ElButton>
<ElButton
v-if="status === 'SUSPEND'"
type="primary"
link
size="small"
@click.stop="handleInterceptionSuccess(row)"
>
拦截成功
</ElButton>
<ElButton
v-if="status === 'SUSPEND'"
type="primary"
link
size="small"
@click.stop="handleInterceptionFail(row)"
>
拦截失败
</ElButton>
</div> </div>
</template> </template>
</TableView> </TableView>
...@@ -784,6 +821,19 @@ ...@@ -784,6 +821,19 @@
/> />
</div> </div>
</el-tab-pane> </el-tab-pane>
<el-tab-pane name="operation" label="操作单">
<div
v-loading="subLoading"
element-loading-text="加载中..."
class="sub-table-wrapper"
>
<TableView
:paginated-data="operationOrderList"
:columns="operationOrderColumns"
serial-numberable
/>
</div>
</el-tab-pane>
<el-tab-pane name="log" label="操作日志"> <el-tab-pane name="log" label="操作日志">
<div <div
v-loading="subLoading" v-loading="subLoading"
...@@ -916,6 +966,53 @@ ...@@ -916,6 +966,53 @@
@success="() => refreshCurrentView({ isRefreshTree: true })" @success="() => refreshCurrentView({ isRefreshTree: true })"
/> />
<ElDialog <ElDialog
v-model="interceptSuccessDialogVisible"
title="拦截成功"
width="480px"
:close-on-click-modal="false"
>
<ElForm ref="interceptSuccessFormRef" :model="interceptSuccessForm">
<ElFormItem
label="拦截成功类型"
prop="suspendSussessType"
:rules="[
{
required: true,
message: '请选择拦截成功类型',
trigger: 'change',
},
]"
>
<ElSelect
v-model="interceptSuccessForm.suspendSussessType"
placeholder="请选择"
style="width: 100%"
clearable
>
<ElOption
v-for="opt in interceptSuccessTypeOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</ElSelect>
</ElFormItem>
</ElForm>
<p style="padding-left: 12px">
拦截成功,订单会流转到已取消,确认是否通过拦截申请?
</p>
<template #footer>
<div class="dialog-footer" style="text-align: center">
<ElButton @click="interceptSuccessDialogVisible = false"
>取消</ElButton
>
<ElButton type="primary" @click="submitInterceptSuccess"
>确定</ElButton
>
</div>
</template>
</ElDialog>
<ElDialog
v-model="exportVisible" v-model="exportVisible"
title="导出选项" title="导出选项"
width="500px" width="500px"
...@@ -989,6 +1086,8 @@ import { ...@@ -989,6 +1086,8 @@ import {
statusPushApi, statusPushApi,
arrangeFinishApi, arrangeFinishApi,
exportFactoryOrderInfo, exportFactoryOrderInfo,
interceptUpdateApi,
interceptSuccessApi,
} from '@/api/factoryOrderNew' } from '@/api/factoryOrderNew'
import { getLogisticsWayApi } from '@/api/podUsOrder' import { getLogisticsWayApi } from '@/api/podUsOrder'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
...@@ -1035,6 +1134,17 @@ const exportForm = ref({ ...@@ -1035,6 +1134,17 @@ const exportForm = ref({
resource: '', resource: '',
}) })
const interceptSuccessDialogVisible = ref(false)
const interceptSuccessFormRef = ref()
const interceptSuccessTypeOptions = [
{ label: '生产拦截成功', value: 1 },
{ label: '发货拦截成功', value: 2 },
]
const interceptSuccessForm = ref<{ suspendSussessType: number | undefined }>({
suspendSussessType: undefined,
})
const interceptSuccessRows = ref<FactoryOrderNewListData[]>([])
const { const {
userMarkList, userMarkList,
receiverCountryList, receiverCountryList,
...@@ -1043,6 +1153,8 @@ const { ...@@ -1043,6 +1153,8 @@ const {
craftList, craftList,
warehouseList, warehouseList,
productTypeGroups, productTypeGroups,
getReceiverCountryList,
loadWarehouseList,
loadAllDictionaries, loadAllDictionaries,
} = useOrderDictionaries() } = useOrderDictionaries()
...@@ -1076,6 +1188,8 @@ const { ...@@ -1076,6 +1188,8 @@ const {
pendingAcceptCounts, pendingAcceptCounts,
suspendedTabs, suspendedTabs,
suspendedSubTab, suspendedSubTab,
// cancelledTabs,
cancelledSubTab,
treeRef, treeRef,
isCardLayout, isCardLayout,
isSpecialLayout, isSpecialLayout,
...@@ -1083,6 +1197,7 @@ const { ...@@ -1083,6 +1197,7 @@ const {
getListPageAcceptedSubStatus, getListPageAcceptedSubStatus,
getPendingReceiveCounts, getPendingReceiveCounts,
getSuspendCounts, getSuspendCounts,
// getCancelledCounts,
loadStatusTreeCounts, loadStatusTreeCounts,
handlePendingAcceptTabClick: handlePendingAcceptTabClickRaw, handlePendingAcceptTabClick: handlePendingAcceptTabClickRaw,
toggleExpand, toggleExpand,
...@@ -1090,8 +1205,6 @@ const { ...@@ -1090,8 +1205,6 @@ const {
getQueryPayload, getQueryPayload,
currentPage: statusCurrentPageRef, currentPage: statusCurrentPageRef,
pageSize: statusPageSizeRef, pageSize: statusPageSizeRef,
onClearTableState: () => {},
onRefreshCurrentView: () => {},
}) })
getFactoryOrderSearchVisibilityContext = () => ({ getFactoryOrderSearchVisibilityContext = () => ({
status: status.value, status: status.value,
...@@ -1102,6 +1215,7 @@ const { ...@@ -1102,6 +1215,7 @@ const {
subLoading, subLoading,
activeTab, activeTab,
productList, productList,
operationOrderList,
logList, logList,
tableRef, tableRef,
selectedRows, selectedRows,
...@@ -1129,6 +1243,7 @@ const { ...@@ -1129,6 +1243,7 @@ const {
getQueryPayload, getQueryPayload,
getListPageAcceptedSubStatus, getListPageAcceptedSubStatus,
suspendedSubTab, suspendedSubTab,
cancelledSubTab,
}) })
statusCurrentPageRef.value = currentPage.value statusCurrentPageRef.value = currentPage.value
statusPageSizeRef.value = pageSize.value statusPageSizeRef.value = pageSize.value
...@@ -1203,6 +1318,9 @@ const refreshCurrentView = (options?: { isRefreshTree?: boolean }) => { ...@@ -1203,6 +1318,9 @@ const refreshCurrentView = (options?: { isRefreshTree?: boolean }) => {
if (status.value === 'SUSPEND') { if (status.value === 'SUSPEND') {
void getSuspendCounts() void getSuspendCounts()
} }
// if (status.value === 'CANCELLED') {
// void getCancelledCounts()
// }
refreshTableList() refreshTableList()
} }
refreshCurrentViewProxy.value = () => refreshCurrentView() refreshCurrentViewProxy.value = () => refreshCurrentView()
...@@ -1276,6 +1394,9 @@ const handleStatusNodeClick = (node: { status: string }) => { ...@@ -1276,6 +1394,9 @@ const handleStatusNodeClick = (node: { status: string }) => {
if (node.status !== 'SUSPEND') { if (node.status !== 'SUSPEND') {
suspendedSubTab.value = 1 suspendedSubTab.value = 1
} }
if (node.status !== 'CANCELLED') {
cancelledSubTab.value = 1
}
clearTableState() clearTableState()
if (!isSpecialLayout.value) { if (!isSpecialLayout.value) {
refreshCurrentView() refreshCurrentView()
...@@ -1292,6 +1413,13 @@ const handleSuspendTabClick = (value: number) => { ...@@ -1292,6 +1413,13 @@ const handleSuspendTabClick = (value: number) => {
statusCurrentPageRef.value = 1 statusCurrentPageRef.value = 1
refreshTableList() refreshTableList()
} }
// const handleCancelledTabClick = (value: number) => {
// if (cancelledSubTab.value === value) return
// cancelledSubTab.value = value
// currentPage.value = 1
// statusCurrentPageRef.value = 1
// refreshTableList()
// }
const mainColumns = computed(() => [ const mainColumns = computed(() => [
{ {
prop: 'factoryOrderNumber', prop: 'factoryOrderNumber',
...@@ -1446,7 +1574,7 @@ const mainColumns = computed(() => [ ...@@ -1446,7 +1574,7 @@ const mainColumns = computed(() => [
{ {
prop: 'operation', prop: 'operation',
label: '操作', label: '操作',
minWidth: 200, minWidth: 220,
align: 'center', align: 'center',
slot: 'operation', slot: 'operation',
fixed: 'right', fixed: 'right',
...@@ -1458,6 +1586,134 @@ const showProductInventoryColumns = computed( ...@@ -1458,6 +1586,134 @@ const showProductInventoryColumns = computed(
status.value == 'PENDING_RECEIVE' && status.value == 'PENDING_RECEIVE' &&
pendingAcceptSubTab.value !== 'PENDING_RECEIVE', pendingAcceptSubTab.value !== 'PENDING_RECEIVE',
) )
function parseOperationOrderImageAry(
imageAry?: string | null | unknown,
): { url: string; title?: string }[] {
if (typeof imageAry !== 'string' || !imageAry.trim()) return []
try {
const list = JSON.parse(imageAry) as { url?: string; title?: string }[]
if (!Array.isArray(list)) return []
return list
.filter((x) => x?.url)
.map((x) => ({ url: x.url as string, title: x.title }))
} catch {
return []
}
}
function getOperationOrderMarkLabel(row: operateOrderListData): string {
const mark = row.customizedQuantity
if (mark === 1) return '单面'
if (mark === 2) return '双面'
return ''
}
const operationOrderColumns = [
{
key: 'operationNo',
prop: 'operationNo',
label: '操作单号',
minWidth: 160,
align: 'center',
showOverflowTooltip: true,
},
{
key: 'imageAry',
prop: 'imageAry',
label: '商品图片',
minWidth: 100,
align: 'center',
render: (row: operateOrderListData) => {
const list = parseOperationOrderImageAry(row.imageAry)
if (!list.length) {
return <span />
}
const urls = list.map((i) => i.url)
return (
<div style="display:flex;flex-wrap:wrap;gap:4px;justify-content:center">
{list.map((img, idx) => (
<el-image
key={idx}
src={img.url}
previewSrcList={urls}
previewTeleported={true}
style="width:50px;height:50px"
title={img.title ?? ''}
/>
))}
</div>
)
},
},
{
key: 'productName',
prop: 'productName',
label: '商品名称',
minWidth: 180,
align: 'left',
showOverflowTooltip: true,
},
{
key: 'variantSku',
prop: 'variantSku',
label: '变体SKU',
minWidth: 140,
align: 'center',
showOverflowTooltip: true,
},
{
key: 'thirdSkuCode',
prop: 'thirdSkuCode',
label: '库存SKU',
minWidth: 140,
align: 'center',
showOverflowTooltip: true,
},
{
key: 'productMark',
prop: 'productMark',
label: '类型',
width: 72,
align: 'center',
render: (row: operateOrderListData) => {
const label = getOperationOrderMarkLabel(row)
if (!label) return <span />
return <ElTag type="primary">{label}</ElTag>
},
},
{
key: 'statusName',
prop: 'statusName',
label: '挂起前状态',
minWidth: 120,
align: 'center',
showOverflowTooltip: true,
},
{
key: 'craftName',
prop: 'craftName',
label: '工艺',
minWidth: 100,
align: 'center',
showOverflowTooltip: true,
},
{
key: 'supplierProductNo',
prop: 'supplierProductNo',
label: '款号',
minWidth: 120,
align: 'center',
showOverflowTooltip: true,
},
{
key: 'batchArrangeNumber',
prop: 'batchArrangeNumber',
label: '批次号',
minWidth: 120,
align: 'center',
showOverflowTooltip: true,
},
]
const baseProductColumns = computed(() => [ const baseProductColumns = computed(() => [
{ {
...@@ -1998,7 +2254,6 @@ const handlePrinterChange = (value: string) => { ...@@ -1998,7 +2254,6 @@ const handlePrinterChange = (value: string) => {
const handleWarehouseIdChange = (value: string) => { const handleWarehouseIdChange = (value: string) => {
localStorage.setItem('localNewWarehouseId', JSON.stringify(value)) localStorage.setItem('localNewWarehouseId', JSON.stringify(value))
} }
// 复用 podCN 的单件打单组件:为 factoryOrderNew 注入差异部分
const mapOrderParamListToSubmitItems = ( const mapOrderParamListToSubmitItems = (
orderParamList: { id: number; dataVersion?: number }[], orderParamList: { id: number; dataVersion?: number }[],
) => orderParamList.map((item) => ({ id: item.id })) ) => orderParamList.map((item) => ({ id: item.id }))
...@@ -2358,19 +2613,11 @@ const handleProductionComplete = async () => { ...@@ -2358,19 +2613,11 @@ const handleProductionComplete = async () => {
getIds: getSelectedIds, getIds: getSelectedIds,
api: completeDeliveryApi, api: completeDeliveryApi,
confirmText: '确定生产完成吗?', confirmText: '确定生产完成吗?',
refreshTree: true,
onSuccess: (res) => { onSuccess: (res) => {
const data = Array.isArray(res.data) const data = Array.isArray(res.data)
? (res.data as ResultInfoDataItem[]) ? (res.data as ResultInfoDataItem[])
: [] : []
const hasFailed = data.some((item) => !item.status) openResultInfoDialog(data)
if (hasFailed) {
resultInfo.value = data.filter((item) => !item.status)
resultRefs.value?.showDialog()
} else {
ElMessage.success('操作成功')
refreshCurrentView({ isRefreshTree: true })
}
}, },
}) })
} }
...@@ -2509,11 +2756,82 @@ const getLogisticsWay = async () => { ...@@ -2509,11 +2756,82 @@ const getLogisticsWay = async () => {
const { data } = await getLogisticsWayApi() const { data } = await getLogisticsWayApi()
logisticsWayList.value = data logisticsWayList.value = data
} }
const handleInterceptionSuccess = (row?: FactoryOrderNewListData) => {
if (row) {
interceptSuccessRows.value = [row]
} else {
if (!ensureSelection()) return
interceptSuccessRows.value = [...selectedRows.value]
}
interceptSuccessForm.value.suspendSussessType = undefined
interceptSuccessDialogVisible.value = true
nextTick(() => interceptSuccessFormRef.value?.clearValidate())
}
const submitInterceptSuccess = async () => {
const form = interceptSuccessFormRef.value
if (!form) return
try {
await form.validate()
} catch {
return
}
const suspendSussessType = interceptSuccessForm.value.suspendSussessType
if (suspendSussessType === undefined) return
const loading = ElLoading.service({
fullscreen: true,
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
const rows = interceptSuccessRows.value
const data = rows.map((item: FactoryOrderNewListData) => {
return {
factoryOrderNumber: item.factoryOrderNumber as string,
suspendSussessType,
}
}) as { factoryOrderNumber: string; suspendSussessType: number }[]
try {
const res = await interceptSuccessApi(data)
if (res.code !== 200) return
interceptSuccessDialogVisible.value = false
const resultData = Array.isArray(res.data)
? (res.data as ResultInfoDataItem[])
: []
openResultInfoDialog(resultData)
} catch (e) {
console.error(e)
} finally {
loading.close()
}
}
const handleInterceptionFail = async (row?: FactoryOrderNewListData) => {
await executeBatchAction({
getIds: () =>
row
? [row.factoryOrderNumber as string]
: selectedRows.value.map(
(item: FactoryOrderNewListData) =>
item.factoryOrderNumber as string,
),
api: (ids) => interceptUpdateApi(ids as string[]),
confirmText: '拦截失败,订单会恢复到拦截前的状态,确认是否拒绝拦截申请?',
onSuccess: (res) => {
const data = Array.isArray(res.data)
? (res.data as ResultInfoDataItem[])
: []
openResultInfoDialog(data)
},
})
}
onMounted(() => { onMounted(() => {
loadStatusTreeCounts() loadStatusTreeCounts()
loadAllDictionaries() loadAllDictionaries()
getLogisticsWay() getLogisticsWay()
// 仅用于消除 TS 插件的 unused-vars 警告:template refs 会绑定这两个变量 getReceiverCountryList()
loadWarehouseList()
void treeRef.value void treeRef.value
void tableRef.value void tableRef.value
if (status.value === 'PENDING_RECEIVE') { if (status.value === 'PENDING_RECEIVE') {
......
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