Commit 8fd0e150 by qinjianhui

feat: 快捷生产功能完成

parent 0a3ddae3
......@@ -54,7 +54,6 @@ declare module 'vue' {
ElTag: typeof import('element-plus/es')['ElTag']
ElTimeline: typeof import('element-plus/es')['ElTimeline']
ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTree: typeof import('element-plus/es')['ElTree']
ElUpload: typeof import('element-plus/es')['ElUpload']
......
......@@ -20,7 +20,7 @@
<span
class="operation-number"
:title="`操作单号:${item.operationNo}`"
@click.stop="String(item.operationNo)"
@click.stop="copyText(item.operationNo ?? '')"
>
{{ item.operationNo }}
</span>
......
......@@ -821,6 +821,12 @@
v-model:detail-visible="detailVisible"
: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="historyFactoryOrderNewData"
tracking-placeholder="扫描枪输入操作单号,录入下一单本单自动生产完成,最后一单扫两次完成生产"
:query-api="getOperationByNo"
......@@ -1683,7 +1689,9 @@ const openResultInfoDialog = (
nextTick(() => {
const isSuccess = data.every((item) => item.status)
if (!isSuccess) {
resultInfo.value = data.filter((item) => !item.status).map((item) => ({
resultInfo.value = data
.filter((item) => !item.status)
.map((item) => ({
id: item.id,
status: item.status ?? false,
factoryOrderNumber: item.factoryOrderNumber ?? '',
......@@ -1768,7 +1776,9 @@ const handleLogisticsCommand = async (command: string) => {
if (Array.isArray(res.data)) {
const isSuccess = res.data.every((item) => item.status)
if (!isSuccess) {
resultInfo.value = res.data.filter((item) => !item.status).map((item) => ({
resultInfo.value = res.data
.filter((item) => !item.status)
.map((item) => ({
id: item.id,
status: item.status ?? false,
factoryOrderNumber: item.factoryOrderNumber ?? '',
......@@ -2185,9 +2195,28 @@ const handleReplenishFail = () => {
const getOperationByNo = (operationNo: string) =>
getByOperationNoLogApi(operationNo) as Promise<{ data?: unknown }>
const completeOperationById = (ids: number[]) => completeDeliveryApi(ids)
const downloadOperationById = (ids: number[]) => downloadOperationMaterialApi(ids)
const handleFastProductionSuccess = () => {
refreshCurrentView({ isRefreshTree: true })
const downloadOperationById = (ids: number[]) =>
downloadOperationMaterialApi(ids)
const handleFastProductionSuccess = (
data: {
factoryOrderNumber?: number
id: number
message?: string
status?: boolean
}[],
) => {
const isSuccess = data.every((item) => item.status)
if (!isSuccess) {
resultInfo.value = data
.filter((item) => !item.status)
.map((item) => ({
id: item.id,
status: item.status ?? false,
factoryOrderNumber: item.factoryOrderNumber ? String(item.factoryOrderNumber) : '',
message: item.message ?? '',
}))
resultRefs.value?.showDialog()
}
}
const fastClose = () => {
detailVisible.value = false
......
......@@ -78,15 +78,32 @@
</div>
</div>
<div class="div-text">
<b>生产单信息</b>
<b v-if="!showOperationNoRow">生产单信息</b>
<b v-else>操作单信息</b>
<div class="div-content">
<div :title="detail?.factorySubOrderNumber" class="div-item">
<div
v-if="showOperationNoRow"
:title="String(operationNoDisplay)"
class="div-item"
>
<span>操作单号</span>
<p>{{ operationNoDisplay }}</p>
</div>
<div
v-else
:title="detail?.factorySubOrderNumber"
class="div-item"
>
<span>生产单号</span>
<p>
{{ detail?.factorySubOrderNumber }}
</p>
</div>
<div :title="detail?.thirdSubOrderNumber || ''" class="div-item">
<div
v-if="!showOperationNoRow"
:title="detail?.thirdSubOrderNumber || ''"
class="div-item"
>
<span>第三方生产单号</span>
<p>
{{ detail?.thirdSubOrderNumber }}
......@@ -107,9 +124,14 @@
<span>变体SKU</span>
<p>{{ detail?.variantSku }}</p>
</div>
<div :title="String(detail?.num)" class="div-item">
<div
:title="
String(showOperationNoRow ? detail?.quantity : detail?.num)
"
class="div-item"
>
<span>数量</span>
<p>{{ detail?.num }}</p>
<p>{{ showOperationNoRow ? detail?.quantity : detail?.num }}</p>
</div>
<div :title="String(detail?.size)" class="div-item">
......@@ -183,7 +205,11 @@
flex-direction: column;
"
>
<div v-if="detail?.note" style="height: 100%" class="div-content">
<div
v-if="Array.isArray(detail?.note) && detail.note.length"
style="height: 100%"
class="div-content"
>
<b style="position: absolute; top: -12px">客户留言信息</b>
<div
v-for="(item, index) in detail?.note"
......@@ -211,22 +237,30 @@ import {
import { cardImages, PodOrderRes } from '@/types/api/podCnOrder'
import { showConfirm } from '@/utils/ui'
import { filePath } from '@/api/axios'
import { ref, watch } from 'vue'
import { computed, ref, watch } from 'vue'
import { BaseRespData } from '@/types/api'
interface HistoryDataItem {
orderNumber: string
finished: boolean
}
export type FastProductionDetail = PodOrderRes & {
operationNo?: string | null
quantity?: number | null
podOrderNo?: string | null
}
const trackingNumberRef = ref()
const historyData = ref<HistoryDataItem[]>([])
const placeholderText = ref('')
const sendNum = ref(0)
const isDownloadImage = ref(false)
const isAutoSure = ref(true)
const detail = ref<PodOrderRes>({
const emptyDetail = (): FastProductionDetail => ({
id: -1,
podJomallOrderCnId: -1,
imgList: [] as cardImages[],
})
const detail = ref<FastProductionDetail>(emptyDetail())
const dialogVisible = ref(false)
// 尺码类型表
const sizeList = ref<{ name: string; value: number }[]>([
......@@ -260,8 +294,25 @@ const props = withDefaults(
historyStorageKey?: string
trackingPlaceholder?: string
queryApi?: (orderNumber: string) => Promise<{ data?: unknown }>
completeApi?: (ids: number[], detail: Record<string, unknown>) => Promise<unknown>
downloadApi?: (ids: number[]) => Promise<{ code?: number; message?: string }>
completeApi?: (
ids: number[],
detail: Record<string, unknown>,
) => Promise<unknown>
downloadApi?: (
ids: number[],
) => Promise<{ code?: number; message?: string }>
/** 打开弹框时「自动完成上一单」的初始勾选;默认 false,与原有 podCN 快捷生产一致 */
defaultAutoSure?: boolean
/** 为 true 时展示「操作单号」一行,数据字段为 `operationNo`(不影响 podCN 默认) */
showOperationNoRow?: boolean
/** 查询无数据时的提示 */
notFoundMessage?: string
/** 未生产完成提醒里对单号的称呼,如「生产单号」「操作单号」 */
pendingOrderLabel?: string
/** 未扫码时的提示 */
pleaseScanTip?: string
/** 扫码输入为空时音频/提示文案 */
searchInputAudioTip?: string
}>(),
{
type: 0,
......@@ -271,17 +322,36 @@ const props = withDefaults(
historyStorageKey: 'historyCnData',
trackingPlaceholder:
'扫描枪输入生产单号,录入下一单本单自动生产完成,最后一单扫两次完成生产',
defaultAutoSure: false,
showOperationNoRow: false,
notFoundMessage: '生产单不存在',
pendingOrderLabel: '生产单号',
pleaseScanTip: '请扫码生产单号',
searchInputAudioTip: '请录入生产单号',
queryApi: (orderNumber: string) => getSubOrderBySubOrderNumber(orderNumber),
completeApi: (ids: number[], detailData: Record<string, unknown>) =>
productionQueryApi(
ids[0],
Number(detailData.podJomallOrderCnId || -1),
),
productionQueryApi(ids[0], Number(detailData.podJomallOrderCnId || -1)),
downloadApi: (ids: number[]) => downloadMaterialApi(ids),
},
)
const emit = defineEmits(['update:detailVisible', 'close', 'onSuccess'])
const historyKeyFromDetail = (d: FastProductionDetail): string => {
const raw = d as unknown as Record<string, unknown>
const op = raw.operationNo
if (op !== undefined && op !== null && String(op).trim() !== '') {
return String(op)
}
return String(d.factorySubOrderNumber ?? '')
}
const operationNoDisplay = computed(() => {
const raw = detail.value as unknown as Record<string, unknown>
const v = raw.operationNo
if (v === undefined || v === null) return ''
return String(v)
})
const parseImages = (value: unknown): cardImages[] => {
if (!value) return []
if (Array.isArray(value)) {
......@@ -323,7 +393,7 @@ const parseImages = (value: unknown): cardImages[] => {
return []
}
const normalizeDetail = (value: unknown): PodOrderRes => {
const normalizeDetail = (value: unknown): FastProductionDetail => {
const raw = (value || {}) as Record<string, unknown>
const d = JSON.parse(JSON.stringify(raw)) as Record<string, unknown>
if (typeof d.note === 'string') {
......@@ -336,7 +406,7 @@ const normalizeDetail = (value: unknown): PodOrderRes => {
if (!Array.isArray(d.note)) d.note = []
const imageSource = d.imageAry || d.designImages || d.imgList
d.imgList = parseImages(imageSource)
return d as unknown as PodOrderRes
return d as unknown as FastProductionDetail
}
watch(
......@@ -357,7 +427,7 @@ watch(
trackingNumberRef.value && trackingNumberRef.value.focus()
TrackingNumber.value = ''
isAutoSure.value = true
isAutoSure.value = props.defaultAutoSure
sendNum.value = 0
}
},
......@@ -378,11 +448,14 @@ watch(
)
const confirmQuery = (len: HistoryDataItem[], i: number) => {
const el = len[i]
showConfirm(`生产单号 ${el.orderNumber} 未生产完成,取消则不提醒?`, {
showConfirm(
`${props.pendingOrderLabel} ${el.orderNumber} 未生产完成,取消则不提醒?`,
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
},
)
.then(async () => {
TrackingNumber.value = el.orderNumber
await trackCodeInput()
......@@ -412,22 +485,29 @@ const confirmQuery = (len: HistoryDataItem[], i: number) => {
const changeStatus = async () => {
if (!detail.value || Object.keys(detail.value).length <= 1) {
return ElMessage.warning('请扫码生产单号')
return ElMessage.warning(props.pleaseScanTip)
}
showConfirm('确定生产完成?', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
setData(detail.value.factorySubOrderNumber || '')
setData(historyKeyFromDetail(detail.value))
})
}
const setData = async (orderNumber: string) => {
if (!detail.value || detail.value?.id === -1) return
try {
const id = detail.value.id
await props.completeApi([id], detail.value as unknown as Record<string, unknown>)
const res = await props.completeApi(
[id],
detail.value as unknown as Record<string, unknown>,
) as unknown as BaseRespData<{
factoryOrderNumber?: number
id:number
message?:string
status?:boolean
}[]>
if (orderNumber) {
const index = historyData.value.findIndex(
(el: HistoryDataItem) => el.orderNumber === orderNumber,
......@@ -441,7 +521,7 @@ const setData = async (orderNumber: string) => {
)
}
}
emit('onSuccess')
emit('onSuccess', res.data)
playAudio('weight_success')
detail.value = {
id: -1,
......@@ -469,7 +549,7 @@ const handleDownload = () => {
Object.keys(detail.value).length <= 1 ||
detail.value.id == -1
) {
return ElMessage.warning('请扫码生产单号')
return ElMessage.warning(props.pleaseScanTip)
}
download()
}
......@@ -507,7 +587,7 @@ const playAudio = (key: AudioKey, message?: string) => {
text = ''
break
case 'weight_search_error':
text = '请录入生产单号'
text = props.searchInputAudioTip
break
case 'weight_success':
text = ''
......@@ -531,8 +611,7 @@ const playAudio = (key: AudioKey, message?: string) => {
const trackCodeInput = async () => {
if (!TrackingNumber.value) {
// ElMessage.warning('请扫描生产单号')
playAudio('weight_search_error')
playAudio('weight_search_error', props.searchInputAudioTip)
trackingNumberRef.value && trackingNumberRef.value.focus()
return
}
......@@ -545,7 +624,10 @@ const trackCodeInput = async () => {
orderNumber: TrackingNumber.value,
finished: false,
})
localStorage.setItem(props.historyStorageKey, JSON.stringify(historyData.value))
localStorage.setItem(
props.historyStorageKey,
JSON.stringify(historyData.value),
)
}
const orderNumber = TrackingNumber.value
......@@ -559,7 +641,7 @@ const trackCodeInput = async () => {
try {
const res = await props.queryApi(orderNumber)
if (!res.data) {
return ElMessage.error('生产单不存在')
return ElMessage.error(props.notFoundMessage)
}
detail.value = normalizeDetail(res.data)
......
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