Commit 60defb7c by wusiyi

feat: 订单添加质检流程 #1009863

parent 9bf605b9
...@@ -12,58 +12,42 @@ declare module 'vue' { ...@@ -12,58 +12,42 @@ declare module 'vue' {
DatePicker: typeof import('./src/components/Form/DatePicker.vue')['default'] DatePicker: typeof import('./src/components/Form/DatePicker.vue')['default']
DateRangePicker: typeof import('./src/components/Form/DateRangePicker.vue')['default'] DateRangePicker: typeof import('./src/components/Form/DateRangePicker.vue')['default']
ElButton: typeof import('element-plus/es')['ElButton'] ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard']
ElCarousel: typeof import('element-plus/es')['ElCarousel']
ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
ElCascader: typeof import('element-plus/es')['ElCascader'] ElCascader: typeof import('element-plus/es')['ElCascader']
ElCascaderPanel: typeof import('element-plus/es')['ElCascaderPanel'] ElCascaderPanel: typeof import('element-plus/es')['ElCascaderPanel']
ElCarousel: typeof import('element-plus/es')['ElCarousel']
ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElCarousel: typeof import('element-plus/es')['ElCarousel']
ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup'] ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
ElCol: typeof import('element-plus/es')['ElCol']
ElCollapse: typeof import('element-plus/es')['ElCollapse']
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
ElDialog: typeof import('element-plus/es')['ElDialog'] ElDialog: typeof import('element-plus/es')['ElDialog']
ElDivider: typeof import('element-plus/es')['ElDivider']
ElDrawer: typeof import('element-plus/es')['ElDrawer'] ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElDropdown: typeof import('element-plus/es')['ElDropdown'] ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
ElEmpty: typeof import('element-plus/es')['ElEmpty']
ElForm: typeof import('element-plus/es')['ElForm'] ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElIcon: typeof import('element-plus/es')['ElIcon'] ElIcon: typeof import('element-plus/es')['ElIcon']
ElImage: typeof import('element-plus/es')['ElImage']
ElInput: typeof import('element-plus/es')['ElInput'] ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber'] ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElLink: typeof import('element-plus/es')['ElLink']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElOption: typeof import('element-plus/es')['ElOption'] ElOption: typeof import('element-plus/es')['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElPopover: typeof import('element-plus/es')['ElPopover'] ElPopover: typeof import('element-plus/es')['ElPopover']
ElRadio: typeof import('element-plus/es')['ElRadio'] ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioButton: typeof import('element-plus/es')['ElRadioButton'] ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElRow: typeof import('element-plus/es')['ElRow']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('element-plus/es')['ElSelect'] ElSelect: typeof import('element-plus/es')['ElSelect']
ElStep: typeof import('element-plus/es')['ElStep']
ElSteps: typeof import('element-plus/es')['ElSteps']
ElSwitch: typeof import('element-plus/es')['ElSwitch'] ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable'] ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag'] 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'] ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTree: typeof import('element-plus/es')['ElTree'] ElTree: typeof import('element-plus/es')['ElTree']
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect'] ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
ElUpload: typeof import('element-plus/es')['ElUpload']
Icon: typeof import('./src/components/Icon.vue')['default'] Icon: typeof import('./src/components/Icon.vue')['default']
ImageView: typeof import('./src/components/ImageView.vue')['default'] ImageView: typeof import('./src/components/ImageView.vue')['default']
LeftRightLayout: typeof import('./src/components/leftRightLayout.vue')['default'] LeftRightLayout: typeof import('./src/components/leftRightLayout.vue')['default']
......
...@@ -8,6 +8,8 @@ import type { ...@@ -8,6 +8,8 @@ import type {
OrderInventoryData, OrderInventoryData,
PickCompleteData, PickCompleteData,
ProductListData, ProductListData,
QualityParams,
QualityTypeItem,
RestockData, RestockData,
SearchForm, SearchForm,
StatusTreeNode, StatusTreeNode,
...@@ -94,6 +96,27 @@ export function getPodOrderAcceptedStatisticsApi( ...@@ -94,6 +96,27 @@ export function getPodOrderAcceptedStatisticsApi(
}) })
} }
// 待质检 数量统计
export function getPodOrderQualityCountApi(
data: SearchForm,
pageSize: number,
status?: string,
) {
return axios.post<
never,
BaseRespData<{
qualityCount?: number
noQualityCount?: number
totalCount?: number
}>
>('factory/podOrderOperation/quality-count', {
...normalizePodOrderQueryPayload({ ...data } as Record<string, unknown>),
currentPage: 1,
pageSize,
status,
})
}
export function getFactoryOrderNewDetailApi(id: number | string) { export function getFactoryOrderNewDetailApi(id: number | string) {
return axios.get<never, BaseRespData<ProductListData[]>>( return axios.get<never, BaseRespData<ProductListData[]>>(
'factory/podOrderProduct/getListByPodOrderId', 'factory/podOrderProduct/getListByPodOrderId',
...@@ -568,6 +591,16 @@ export function getByOperationNoLogApi(operationNo: string) { ...@@ -568,6 +591,16 @@ export function getByOperationNoLogApi(operationNo: string) {
) )
} }
// 快捷质检 查询
export function getQualityScanByOperationNoApi(operationNo: string) {
return axios.get<never, BaseRespData<operateOrderListData>>(
'factory/podOrderOperation/qualityByOperationNo',
{
params: { operationNo },
},
)
}
// 校验库存 // 校验库存
export function checkInventoryApi(id: number | string, status: string) { export function checkInventoryApi(id: number | string, status: string) {
return axios.get<never, BaseRespData<never>>( return axios.get<never, BaseRespData<never>>(
...@@ -707,3 +740,28 @@ export function deliveryCompleteApi(data: { id: number; version?: number }[]) { ...@@ -707,3 +740,28 @@ export function deliveryCompleteApi(data: { id: number; version?: number }[]) {
{ orderParamList: data }, { orderParamList: data },
) )
} }
/** 重新生产 */
export function remanufactureApi(data: {
updateParams: { id: number; version?: number }[]
}) {
return axios.post<never, BaseRespData<void>>(
'factory/podOrderOperation/remanufacture',
data,
)
}
/** 质检通过 / 质检不通过 */
export function qualityPodOrderOperationApi(data: QualityParams) {
return axios.post<never, BaseRespData<never>>(
'factory/podOrderOperation/quality',
data,
)
}
/** 质检不通过原因下拉 */
export function getQualityTypeApi() {
return axios.get<never, BaseRespData<QualityTypeItem[]>>(
'factory/podOrderOperation/quality-type',
)
}
...@@ -51,6 +51,8 @@ export interface SearchForm { ...@@ -51,6 +51,8 @@ export interface SearchForm {
/** list_page 排序方向:asc 正序,desc 倒序 */ /** list_page 排序方向:asc 正序,desc 倒序 */
order?: 'asc' | 'desc' order?: 'asc' | 'desc'
customerNo?: string // 客户交运单号 customerNo?: string // 客户交运单号
/** 待质检子 tab:true 待质检,false 质检不通过 */
qualityPassed?: boolean
} }
export interface FactoryOrderNewListData { export interface FactoryOrderNewListData {
...@@ -304,3 +306,18 @@ export interface OrderInventoryData { ...@@ -304,3 +306,18 @@ export interface OrderInventoryData {
variantImage?: string variantImage?: string
inventoryStatus?: number inventoryStatus?: number
} }
/** 质检操作参数 */
export interface QualityParams {
updateParams: { id: number; version?: number }[]
qualityIssues: string
qualifyProblemType: number | string
qualityPassed: boolean
source?: number // 0 列表页,1 快捷质检
}
/** 质检不通过原因 */
export interface QualityTypeItem {
key: number | string
value: string
}
...@@ -57,6 +57,8 @@ export interface SearchForm { ...@@ -57,6 +57,8 @@ export interface SearchForm {
/** list_page 排序方向:asc 正序,desc 倒序 */ /** list_page 排序方向:asc 正序,desc 倒序 */
order?: 'asc' | 'desc' order?: 'asc' | 'desc'
customerNo?: string // 客户交运单号 customerNo?: string // 客户交运单号
/** 待质检子 tab:true 待质检,false 质检不通过 */
qualityPassed?: boolean
} }
export interface FactoryOrderNewListData { export interface FactoryOrderNewListData {
......
...@@ -46,9 +46,12 @@ ...@@ -46,9 +46,12 @@
<div class="right"> <div class="right">
<div <div
v-if=" v-if="
['fastProduction', 'fastReceipt', 'productionScan'].includes( [
fastKey, 'fastProduction',
) 'fastReceipt',
'productionScan',
'qualityScan',
].includes(fastKey)
" "
class="input" class="input"
> >
...@@ -59,13 +62,44 @@ ...@@ -59,13 +62,44 @@
style="width: 660px; margin-right: 10px" style="width: 660px; margin-right: 10px"
clearable clearable
@keydown.enter="trackCodeInput()" @keydown.enter="trackCodeInput()"
></el-input> />
<el-button type="primary" @click="trackCodeInput()"> <el-button type="primary" @click="trackCodeInput()">
查询 查询
</el-button> </el-button>
</div> </div>
<div v-if="fastKey === 'qualityScan'" class="input">
<el-select
v-model="printDevice"
placeholder="请选择打印机"
clearable
filterable
@change="handlePrinterChange"
>
<el-option
v-for="(item, i) in printList"
:key="i"
:label="item"
:value="item"
></el-option>
</el-select>
<el-button
style="margin-left: 5px"
type="primary"
@click="printPdf"
>
打印操作单
</el-button>
<el-checkbox
v-model="isPrint"
:disabled="!printDevice"
style="margin-left: 10px"
>
自动打印
</el-checkbox>
</div>
<div class="div-text"> <div class="div-text">
<div class="div-content"> <div v-if="fastKey !== 'qualityScan'" class="div-content">
<div :title="String(detail?.userMark)" class="div-item"> <div :title="String(detail?.userMark)" class="div-item">
<span class="div-item-label" style="font-size: 18px" <span class="div-item-label" style="font-size: 18px"
>客户:</span >客户:</span
...@@ -97,8 +131,8 @@ ...@@ -97,8 +131,8 @@
</div> </div>
</div> </div>
<div class="div-text"> <div class="div-text">
<b v-if="!showOperationNoRow">生产单信息</b> <b v-if="showOperationNoRow">操作单信息</b>
<b v-else>操作单信息</b> <b v-else>生产单信息</b>
<div class="div-content"> <div class="div-content">
<div <div
v-if="showOperationNoRow" v-if="showOperationNoRow"
...@@ -106,7 +140,18 @@ ...@@ -106,7 +140,18 @@
class="div-item" class="div-item"
> >
<span class="div-item-label">操作单号:</span> <span class="div-item-label">操作单号:</span>
<div class="div-item-value">{{ operationNoDisplay }}</div> <div class="div-item-value with-copy">
<span class="div-item-value-text">{{
operationNoDisplay
}}</span>
<el-icon
v-if="operationNoDisplay"
class="copy-icon"
@click="copy(operationNoDisplay)"
>
<DocumentCopy />
</el-icon>
</div>
</div> </div>
<div <div
v-else v-else
...@@ -119,16 +164,32 @@ ...@@ -119,16 +164,32 @@
</div> </div>
</div> </div>
<div <div
v-if="fastKey === 'fastReceipt'" v-if="fastKey !== 'fastReceipt'"
:title="setProductMark(String(detail.productMark))" :title="detail?.shopNumber ?? ''"
class="div-item" class="div-item"
> >
<span class="div-item-label">类型:</span> <span class="div-item-label">店铺单号:</span>
<div <div class="div-item-value with-copy">
class="div-item-value" <span class="div-item-value-text">{{
style="font-weight: bold; color: red" detail?.shopNumber ?? ''
> }}</span>
{{ setProductMark(String(detail.productMark)) }} <el-icon
v-if="detail?.shopNumber"
class="copy-icon"
@click="copy(String(detail.shopNumber))"
>
<DocumentCopy />
</el-icon>
</div>
</div>
<div
v-if="fastKey === 'qualityScan'"
:title="String(detail?.batchArrangeNumber) || ''"
class="div-item"
>
<span class="div-item-label">批次号:</span>
<div class="div-item-value">
{{ detail?.batchArrangeNumber }}
</div> </div>
</div> </div>
<div <div
...@@ -137,7 +198,9 @@ ...@@ -137,7 +198,9 @@
class="div-item" class="div-item"
> >
<span class="div-item-label">商品名称:</span> <span class="div-item-label">商品名称:</span>
<div class="div-item-value">{{ detail.productName || '' }}</div> <div class="div-item-value">
{{ detail.productName || '' }}
</div>
</div> </div>
<div <div
v-if="fastKey === 'fastReceipt'" v-if="fastKey === 'fastReceipt'"
...@@ -176,20 +239,27 @@ ...@@ -176,20 +239,27 @@
</div> </div>
</div> </div>
<div <div
v-if="fastKey !== 'fastReceipt'" v-if="fastKey !== 'fastReceipt' && fastKey !== 'qualityScan'"
:title="detail?.baseSku" :title="detail?.baseSku"
class="div-item" class="div-item"
> >
<span class="div-item-label">基版:</span> <span class="div-item-label">基版:</span>
<div class="div-item-value">{{ detail?.baseSku }}</div> <div class="div-item-value">{{ detail?.baseSku }}</div>
</div> </div>
<div
<div :title="detail?.variantSku" class="div-item"> v-if="fastKey === 'qualityScan'"
:title="detail?.baseSku"
class="div-item"
>
<span class="div-item-label">库存SKU:</span>
<div class="div-item-value">{{ detail?.thirdSkuCode }}</div>
</div>
<div v-else :title="detail?.variantSku" class="div-item">
<span class="div-item-label">变体SKU:</span> <span class="div-item-label">变体SKU:</span>
<div class="div-item-value">{{ detail?.variantSku }}</div> <div class="div-item-value">{{ detail?.variantSku }}</div>
</div> </div>
<div <div
v-if="fastKey !== 'fastReceipt'" v-if="fastKey !== 'fastReceipt' && fastKey !== 'qualityScan'"
:title=" :title="
String(showOperationNoRow ? detail?.quantity : detail?.num) String(showOperationNoRow ? detail?.quantity : detail?.num)
" "
...@@ -202,8 +272,8 @@ ...@@ -202,8 +272,8 @@
</div> </div>
<div <div
v-if="fastKey !== 'fastReceipt'" v-if="fastKey !== 'fastReceipt' && fastKey !== 'qualityScan'"
:title="String(detail?.size)" :title="String(detail?.size || '')"
class="div-item" class="div-item"
> >
<span class="div-item-label">尺寸:</span> <span class="div-item-label">尺寸:</span>
...@@ -211,7 +281,7 @@ ...@@ -211,7 +281,7 @@
</div> </div>
<div <div
v-if="detail?.sizeType && fastKey !== 'fastReceipt'" v-if="detail?.sizeType && fastKey !== 'fastReceipt'"
:title="String(detail?.sizeType)" :title="String(detail?.sizeType || '')"
class="div-item" class="div-item"
> >
<span class="div-item-label">尺码类型:</span> <span class="div-item-label">尺码类型:</span>
...@@ -219,16 +289,16 @@ ...@@ -219,16 +289,16 @@
{{ sizeList.find((i) => i.value === detail.sizeType)?.name }} {{ sizeList.find((i) => i.value === detail.sizeType)?.name }}
</div> </div>
</div> </div>
<div <div
v-if="fastKey !== 'fastReceipt'" v-if="fastKey === 'qualityScan'"
:title="detail?.shopNumber ?? ''" :title="String(detail?.statusName || '')"
class="div-item" class="div-item"
> >
<span class="div-item-label">店铺单号:</span> <span class="div-item-label">操作单状态:</span>
<div class="div-item-value">{{ detail?.shopNumber ?? '' }}</div> <div class="div-item-value" style="color: red">
{{ detail?.statusName }}
</div>
</div> </div>
<div :title="detail?.createTime" class="div-item"> <div :title="detail?.createTime" class="div-item">
<span class="div-item-label">创建时间:</span> <span class="div-item-label">创建时间:</span>
<div class="div-item-value">{{ detail?.createTime }}</div> <div class="div-item-value">{{ detail?.createTime }}</div>
...@@ -243,6 +313,7 @@ ...@@ -243,6 +313,7 @@
'fastProduction', 'fastProduction',
'fastReceipt', 'fastReceipt',
'productionScan', 'productionScan',
'qualityScan',
].includes(fastKey) ].includes(fastKey)
? 'visible' ? 'visible'
: 'hidden', : 'hidden',
...@@ -253,19 +324,35 @@ ...@@ -253,19 +324,35 @@
style="width: 100%; height: 100%; font-size: 18px" style="width: 100%; height: 100%; font-size: 18px"
size="large" size="large"
type="success" type="success"
@click="changeStatus" @click="
fastKey === 'qualityScan'
? handleQuality(true)
: changeStatus()
"
> >
{{ {{ sureButtonText }}
['fastProduction', 'productionScan'].includes(fastKey)
? '生产完成'
: '快捷入库'
}}
</el-button> </el-button>
<div class="check"> <div class="check">
<el-checkbox v-model="isAutoSure"> 自动完成上一单 </el-checkbox> <el-checkbox v-model="isAutoSure">
{{
fastKey === 'qualityScan'
? '自动质检通过上一单'
: '自动完成上一单'
}}
</el-checkbox>
</div> </div>
</div> </div>
<div v-if="fastKey !== 'fastReceipt'" class="btn-down"> <div v-if="fastKey === 'qualityScan'" class="btn-down">
<el-button
style="width: 100%; height: 100%; font-size: 18px"
type="danger"
size="large"
@click="handleQuality(false)"
>
质检不通过
</el-button>
</div>
<div v-else-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">
扫码下载素材 扫码下载素材
...@@ -311,6 +398,11 @@ ...@@ -311,6 +398,11 @@
</div> </div>
</div> </div>
</div> </div>
<QualityFailDialog
v-if="fastKey === 'qualityScan'"
ref="qualityFailDialogRef"
@success="handleQualitySuccess"
/>
</el-dialog> </el-dialog>
</template> </template>
<script setup lang="tsx"> <script setup lang="tsx">
...@@ -320,22 +412,44 @@ import { ...@@ -320,22 +412,44 @@ import {
downloadMaterialApi, downloadMaterialApi,
} from '@/api/podCnOrder' } from '@/api/podCnOrder'
import { cardImages, PodOrderRes } from '@/types/api/podCnOrder' import { cardImages, PodOrderRes } from '@/types/api/podCnOrder'
import { checkInventoryApi } from '@/api/factoryOrderNew' import {
checkInventoryApi,
qualityPodOrderOperationApi,
} from '@/api/factoryOrderNew'
import { showConfirm } from '@/utils/ui' import { showConfirm } from '@/utils/ui'
import { filePath } from '@/api/axios' import { filePath } from '@/api/axios'
import { computed, ref, watch } from 'vue' import { computed, ref, watch } from 'vue'
import { BaseRespData } from '@/types/api' import { BaseRespData } from '@/types/api'
import useLodop from '@/utils/hooks/useLodop'
import { print } from '@/components/print'
import { DocumentCopy } from '@element-plus/icons-vue'
import QualityFailDialog from '@/views/order/factoryOrderNew/component/QualityFailDialog.vue'
interface HistoryDataItem { interface HistoryDataItem {
orderNumber: string orderNumber: string
finished: boolean finished: boolean
} }
const title = computed(() => { const title = computed(() => {
if (['fastProduction', 'productionScan'].includes(props.fastKey)) { switch (props.fastKey) {
return '快捷生产' case 'fastProduction':
} else if (props.fastKey === 'fastReceipt') { case 'productionScan':
return props.dialogTitle return '快捷生产'
} else { case 'fastReceipt':
return '查看详情' return props.dialogTitle
case 'qualityScan':
return '快捷质检'
default:
return '查看详情'
}
})
const sureButtonText = computed(() => {
switch (props.fastKey) {
case 'fastProduction':
case 'productionScan':
return '生产完成'
case 'qualityScan':
return '质检通过'
default:
return '快捷入库'
} }
}) })
export type FastProductionDetail = PodOrderRes & { export type FastProductionDetail = PodOrderRes & {
...@@ -354,6 +468,10 @@ const placeholderText = ref('') ...@@ -354,6 +468,10 @@ const placeholderText = ref('')
const sendNum = ref(0) const sendNum = ref(0)
const isDownloadImage = ref(false) const isDownloadImage = ref(false)
const isAutoSure = ref(true) const isAutoSure = ref(true)
const printDevice = ref('')
const isPrint = ref(false)
const printList = ref<string[]>([])
const { getCLodop } = useLodop()
const emptyDetail = (): FastProductionDetail => ({ const emptyDetail = (): FastProductionDetail => ({
id: -1, id: -1,
podJomallOrderCnId: -1, podJomallOrderCnId: -1,
...@@ -402,6 +520,7 @@ const props = withDefaults( ...@@ -402,6 +520,7 @@ const props = withDefaults(
downloadApi?: ( downloadApi?: (
ids: number[], ids: number[],
) => Promise<{ code?: number; message?: string }> ) => Promise<{ code?: number; message?: string }>
printApi?: (id: number) => Promise<{ code?: number; message?: string }>
defaultAutoSure?: boolean defaultAutoSure?: boolean
showOperationNoRow?: boolean showOperationNoRow?: boolean
notFoundMessage?: string notFoundMessage?: string
...@@ -434,11 +553,14 @@ const props = withDefaults( ...@@ -434,11 +553,14 @@ const props = withDefaults(
completeApi: (ids: number[], detailData: Record<string, unknown>) => 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), downloadApi: (ids: number[]) => downloadMaterialApi(ids),
printApi: undefined,
dialogTitle: '', dialogTitle: '',
}, },
) )
const emit = defineEmits(['update:detailVisible', 'close', 'onSuccess']) const emit = defineEmits(['update:detailVisible', 'close', 'onSuccess'])
const qualityFailDialogRef = ref<InstanceType<typeof QualityFailDialog>>()
const historyKeyFromDetail = (d: FastProductionDetail): string => { const historyKeyFromDetail = (d: FastProductionDetail): string => {
const raw = d as unknown as Record<string, unknown> const raw = d as unknown as Record<string, unknown>
const op = raw.operationNo const op = raw.operationNo
...@@ -455,6 +577,12 @@ const operationNoDisplay = computed(() => { ...@@ -455,6 +577,12 @@ const operationNoDisplay = computed(() => {
return String(v) return String(v)
}) })
const copy = (text: string) => {
if (!text) return
navigator.clipboard.writeText(text)
ElMessage.success('复制成功')
}
const parseImages = (value: unknown): cardImages[] => { const parseImages = (value: unknown): cardImages[] => {
if (!value) return [] if (!value) return []
if (Array.isArray(value)) { if (Array.isArray(value)) {
...@@ -507,7 +635,8 @@ const normalizeDetail = (value: unknown): FastProductionDetail => { ...@@ -507,7 +635,8 @@ const normalizeDetail = (value: unknown): FastProductionDetail => {
} }
} }
if (!Array.isArray(d.note)) d.note = [] if (!Array.isArray(d.note)) d.note = []
const imageSource = d.imageAry || d.designImages || d.imgList || d.variantImage const imageSource =
d.imageAry || d.designImages || d.imgList || d.variantImage
d.imgList = parseImages(imageSource) d.imgList = parseImages(imageSource)
return d as unknown as FastProductionDetail return d as unknown as FastProductionDetail
} }
...@@ -520,26 +649,65 @@ watch( ...@@ -520,26 +649,65 @@ watch(
if (newVal) { if (newVal) {
const history = localStorage.getItem(props.historyStorageKey) const history = localStorage.getItem(props.historyStorageKey)
historyData.value = history ? JSON.parse(history) : [] historyData.value = history ? JSON.parse(history) : []
// 防止消息提示数量不全
const len = historyData.value const historyList = [...historyData.value]
if ( if (
len.length > 0 && historyList.length > 0 &&
['fastProduction', 'fastReceipt', 'productionScan'].includes( ['fastProduction', 'fastReceipt', 'productionScan'].includes(
props.fastKey, props.fastKey,
) )
) { ) {
confirmQuery(len, 0) confirmQuery(historyList, 0)
} }
placeholderText.value = props.trackingPlaceholder placeholderText.value = props.trackingPlaceholder
trackingNumberRef.value && trackingNumberRef.value.focus() trackingNumberRef.value && trackingNumberRef.value.focus()
TrackingNumber.value = '' TrackingNumber.value = ''
isAutoSure.value = props.defaultAutoSure isAutoSure.value = true
sendNum.value = 0 sendNum.value = 0
if (props.fastKey === 'qualityScan') {
initPrintDevice()
}
} }
}, },
) )
const initPrintDevice = () => {
const lodop = getCLodop(null, null)
if (!lodop) {
printList.value = []
return
}
const arr: string[] = []
const length = lodop.GET_PRINTER_COUNT()
for (let i = 0; i < length; i++) {
const name = lodop.GET_PRINTER_NAME(i)
if (name) arr.push(name)
}
printList.value = arr
}
const getPrintData = async () => {
if (!detail.value || detail.value.id === -1 || !props.printApi) return
const res = await props.printApi(detail.value.id)
if (!res.message) return
print(filePath + res.message, printDevice.value)
}
const printPdf = () => {
if (!printDevice.value) return ElMessage.warning('请选择打印机')
if (!detail.value || detail.value.id === -1) {
return ElMessage.warning(props.pleaseScanTip)
}
getPrintData()
}
const handlePrinterChange = (value: string) => {
printDevice.value = value
if (!value) isPrint.value = false
}
watch( watch(
() => props.detailData, () => props.detailData,
(newVal) => { (newVal) => {
...@@ -556,12 +724,30 @@ watch( ...@@ -556,12 +724,30 @@ watch(
) )
const confirmQuery = (len: HistoryDataItem[], i: number) => { const confirmQuery = (len: HistoryDataItem[], i: number) => {
const el = len[i] const el = len[i]
const pendingText = (() => {
switch (props.fastKey) {
case 'fastProduction':
case 'productionScan':
return '未生产'
case 'qualityScan':
return '未质检'
default:
return '未入库'
}
})()
const successText = (() => {
switch (props.fastKey) {
case 'fastProduction':
case 'productionScan':
return '生产完成'
case 'qualityScan':
return '质检通过'
default:
return '入库完成'
}
})()
showConfirm( showConfirm(
`${props.pendingOrderLabel} ${el.orderNumber} ${ `${props.pendingOrderLabel} ${el.orderNumber} ${pendingText}完成,取消则不提醒?`,
['fastProduction', 'productionScan'].includes(props.fastKey)
? '未生产'
: '未入库'
}完成,取消则不提醒?`,
{ {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
...@@ -572,13 +758,7 @@ const confirmQuery = (len: HistoryDataItem[], i: number) => { ...@@ -572,13 +758,7 @@ const confirmQuery = (len: HistoryDataItem[], i: number) => {
TrackingNumber.value = el.orderNumber TrackingNumber.value = el.orderNumber
await trackCodeInput() await trackCodeInput()
await setData(el.orderNumber) await setData(el.orderNumber)
ElMessage.success( ElMessage.success(successText)
`${
['fastProduction', 'productionScan'].includes(props.fastKey)
? '生产完成'
: '入库完成'
}`,
)
if (len[i + 1]) { if (len[i + 1]) {
confirmQuery(len, i + 1) confirmQuery(len, i + 1)
} }
...@@ -605,18 +785,22 @@ const changeStatus = async () => { ...@@ -605,18 +785,22 @@ const changeStatus = async () => {
if (!detail.value || Object.keys(detail.value).length <= 1) { if (!detail.value || Object.keys(detail.value).length <= 1) {
return ElMessage.warning(props.pleaseScanTip) return ElMessage.warning(props.pleaseScanTip)
} }
showConfirm( const confirmText = (() => {
`确定${ switch (props.fastKey) {
['fastProduction', 'productionScan'].includes(props.fastKey) case 'fastProduction':
? '生产完成' case 'productionScan':
: '入库完成' return '生产完成'
}?`, case 'qualityScan':
{ return '质检通过'
confirmButtonText: '确定', default:
cancelButtonText: '取消', return '入库完成'
type: 'warning', }
}, })()
).then(() => { showConfirm(`确定${confirmText}?`, {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
setData(historyKeyFromDetail(detail.value)) setData(historyKeyFromDetail(detail.value))
}) })
} }
...@@ -627,18 +811,30 @@ const setData = async ( ...@@ -627,18 +811,30 @@ const setData = async (
if (!detail.value || detail.value?.id === -1) return if (!detail.value || detail.value?.id === -1) return
try { try {
const id = detail.value.id const id = detail.value.id
const res = (await props.completeApi( if (props.fastKey === 'qualityScan') {
[id], const res = await qualityPodOrderOperationApi({
detail.value as unknown as Record<string, unknown>, updateParams: [{ id, version: detail.value.version }],
trigger, qualityIssues: '',
)) as unknown as BaseRespData< qualifyProblemType: '',
{ qualityPassed: true,
factoryOrderNumber?: number source: 1,
id: number })
message?: string if (res.code !== 200) return
status?: boolean } else {
}[] const res = (await props.completeApi(
> [id],
detail.value as unknown as Record<string, unknown>,
trigger,
)) as unknown as BaseRespData<
{
factoryOrderNumber?: number
id: number
message?: string
status?: boolean
}[]
>
emit('onSuccess', res.data)
}
if (orderNumber) { if (orderNumber) {
const index = historyData.value.findIndex( const index = historyData.value.findIndex(
(el: HistoryDataItem) => el.orderNumber === orderNumber, (el: HistoryDataItem) => el.orderNumber === orderNumber,
...@@ -652,19 +848,17 @@ const setData = async ( ...@@ -652,19 +848,17 @@ const setData = async (
) )
} }
} }
emit('onSuccess', res.data)
playAudio('weight_success') playAudio('weight_success')
if (trigger === 'auto') { // if (trigger === 'auto') {
// new 快捷生产:扫码后直接将订单流转至生产中
localStorage.setItem(props.historyStorageKey, JSON.stringify([])) // } else {
} else { // detail.value = {
detail.value = { // id: -1,
id: -1, // podJomallOrderCnId: -1,
podJomallOrderCnId: -1, // imgList: [] as cardImages[],
imgList: [] as cardImages[], // }
} // }
}
TrackingNumber.value = '' TrackingNumber.value = ''
isDownloadImage.value = false isDownloadImage.value = false
trackingNumberRef.value && trackingNumberRef.value.focus() trackingNumberRef.value && trackingNumberRef.value.focus()
...@@ -711,6 +905,41 @@ const handleDownload = () => { ...@@ -711,6 +905,41 @@ const handleDownload = () => {
} }
download() download()
} }
const handleQuality = (passed: boolean) => {
if (
!detail.value ||
Object.keys(detail.value).length <= 1 ||
detail.value.id == -1
) {
return ElMessage.warning(props.pleaseScanTip)
}
qualityFailDialogRef.value?.open(
[{ id: detail.value.id, version: detail.value.version }],
passed,
1,
)
}
const handleQualitySuccess = () => {
const orderNumber = historyKeyFromDetail(detail.value)
if (orderNumber) {
const index = historyData.value.findIndex(
(el: HistoryDataItem) => el.orderNumber === orderNumber,
)
if (index >= 0) {
historyData.value.splice(index, 1)
localStorage.setItem(
props.historyStorageKey,
JSON.stringify(historyData.value),
)
}
}
detail.value = emptyDetail()
TrackingNumber.value = ''
trackingNumberRef.value && trackingNumberRef.value.focus()
emit('onSuccess', [{ id: 0, status: true }])
}
const download = async () => { const download = async () => {
if (detail.value && detail.value?.id != -1) { if (detail.value && detail.value?.id != -1) {
try { try {
...@@ -775,20 +1004,6 @@ const trackCodeInput = async () => { ...@@ -775,20 +1004,6 @@ const trackCodeInput = async () => {
trackingNumberRef.value && trackingNumberRef.value.focus() trackingNumberRef.value && trackingNumberRef.value.focus()
return return
} }
const item = historyData.value.find(
(el: HistoryDataItem) => el.orderNumber === TrackingNumber.value,
)
if (!item) {
// 记录扫单
historyData.value.push({
orderNumber: TrackingNumber.value,
finished: false,
})
localStorage.setItem(
props.historyStorageKey,
JSON.stringify(historyData.value),
)
}
const orderNumber = TrackingNumber.value const orderNumber = TrackingNumber.value
...@@ -833,10 +1048,6 @@ const trackCodeInput = async () => { ...@@ -833,10 +1048,6 @@ const trackCodeInput = async () => {
} }
} }
if (isDownloadImage.value) {
download()
}
// 工厂订单new 校验库存 生产扫码 // 工厂订单new 校验库存 生产扫码
if (props.fastKey === 'productionScan') { if (props.fastKey === 'productionScan') {
try { try {
...@@ -873,8 +1084,37 @@ const trackCodeInput = async () => { ...@@ -873,8 +1084,37 @@ const trackCodeInput = async () => {
} }
throw inventoryErr throw inventoryErr
} }
}
// 查询成功后再写入缓存
const item = historyData.value.find(
(el: HistoryDataItem) => el.orderNumber === orderNumber,
)
if (!item) {
historyData.value.push({
orderNumber,
finished: false,
})
localStorage.setItem(
props.historyStorageKey,
JSON.stringify(historyData.value),
)
}
if (isDownloadImage.value) {
download()
}
if (props.fastKey === 'qualityScan' && printDevice.value && isPrint.value) {
await getPrintData()
}
if (props.fastKey === 'productionScan') {
await setData(detail.value.id.toString(), 'auto') await setData(detail.value.id.toString(), 'auto')
} }
if (props.fastKey === 'qualityScan') {
emit('onSuccess', [{ id: detail.value.id, status: true }])
}
playAudio('weight_search_success') playAudio('weight_search_success')
trackingNumberRef.value && trackingNumberRef.value.focus() trackingNumberRef.value && trackingNumberRef.value.focus()
...@@ -888,82 +1128,20 @@ const trackCodeInput = async () => { ...@@ -888,82 +1128,20 @@ const trackCodeInput = async () => {
const onOpened = () => { const onOpened = () => {
trackingNumberRef.value && trackingNumberRef.value.focus() trackingNumberRef.value && trackingNumberRef.value.focus()
} }
function setProductMark(productMark: string) { // function setProductMark(productMark: string) {
if (!productMark) return '' // if (!productMark) return ''
if (productMark === 'custom_normal') return 'CB' // if (productMark === 'custom_normal') return 'CB'
if (productMark === 'normal') return 'G' // if (productMark === 'normal') return 'G'
return '' // return ''
} // }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.sure-btn {
position: absolute;
right: 62px;
top: 14px;
}
.detail-div { .detail-div {
display: flex; display: flex;
height: 100%; height: 100%;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
.detail-images {
.scroll-list {
background: #ececec;
display: flex;
height: 100px;
width: 100%;
padding: 5px;
.scroll-content {
margin-left: 10px;
overflow-x: auto;
overflow-y: hidden;
flex: 1;
display: flex;
flex-wrap: nowrap;
flex-shrink: 0;
.scroll-item {
height: 100%;
min-width: 100px;
background: white;
margin-right: 5px;
}
}
.img-title {
display: flex;
flex-direction: column;
justify-content: center;
background: white;
padding: 10px;
b {
text-align: center;
color: black;
font-weight: bold;
font-size: 16px;
margin-bottom: 15px;
}
.id {
display: flex;
align-items: center;
padding: 3px 5px;
background: #ececec;
justify-content: center;
img {
width: 15px;
margin-right: 8px;
}
}
}
}
}
.detail-content { .detail-content {
display: flex; display: flex;
width: 100%; width: 100%;
...@@ -974,6 +1152,8 @@ function setProductMark(productMark: string) { ...@@ -974,6 +1152,8 @@ function setProductMark(productMark: string) {
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 30px;
padding: 30px 0;
.btn { .btn {
margin: 20px 0; margin: 20px 0;
...@@ -1031,6 +1211,27 @@ function setProductMark(productMark: string) { ...@@ -1031,6 +1211,27 @@ function setProductMark(productMark: string) {
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
&.with-copy {
display: flex;
align-items: center;
min-width: 0;
}
.div-item-value-text {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.copy-icon {
flex-shrink: 0;
margin-left: 6px;
cursor: pointer;
color: #909399;
}
} }
} }
} }
...@@ -1050,7 +1251,6 @@ function setProductMark(productMark: string) { ...@@ -1050,7 +1251,6 @@ function setProductMark(productMark: string) {
.input { .input {
display: flex; display: flex;
align-items: center; align-items: center;
margin: 30px 0;
} }
} }
...@@ -1102,23 +1302,18 @@ function setProductMark(productMark: string) { ...@@ -1102,23 +1302,18 @@ function setProductMark(productMark: string) {
:deep(.el-carousel__container) { :deep(.el-carousel__container) {
height: 100%; height: 100%;
} }
:deep(.el-dialog__title) {
font-weight: bold;
font-size: 37px;
color: black;
position: relative;
left: 47%;
top: 13px;
}
} }
.btn { .btn {
position: relative; position: relative;
:deep(.el-button) { .btn-sure,
span { .btn-down {
position: relative; &:has(.check) {
left: -30px; :deep(.el-button span) {
position: relative;
left: -30px;
}
} }
} }
...@@ -1141,11 +1336,4 @@ function setProductMark(productMark: string) { ...@@ -1141,11 +1336,4 @@ function setProductMark(productMark: string) {
} }
} }
} }
.warning {
font-size: 18px;
font-weight: bold;
color: #ff9900;
margin-left: 10px;
cursor: pointer;
}
</style> </style>
<template> <template>
<div class="page card h-100 flex-gap-10 overflow-hidden flex flex-column"> <div class="page-wrap">
<div class="flow-steps"> <div class="page card h-100 overflow-hidden">
<div <div class="flow-config-container">
v-for="item in showFlowConfigList" <div class="flow-steps">
:key="item.code" <div
class="flow-step" v-for="item in showFlowConfigList"
> :key="item.code"
{{ item.name }} class="flow-step"
>
{{ item.name }}
</div>
</div>
<div class="step-button mt-10">
<el-checkbox v-model="draftSkipInspect">
跳过质检流程 (跳过后生产完成到待配货状态)
</el-checkbox>
</div>
</div> </div>
</div> </div>
<div class="flex-1 mt-10">
<el-checkbox v-model="draftSkipInspect">
跳过质检流程 (跳过后生产完成到待配货状态)
</el-checkbox>
</div>
<div class="footer-actions"> <div class="footer-actions">
<el-button type="primary" @click="updateConfig"> 保存 </el-button> <el-button type="primary" @click="updateConfig"> 保存 </el-button>
</div> </div>
...@@ -25,10 +29,12 @@ import { ...@@ -25,10 +29,12 @@ import {
updateFactoryOrderFlowConfigApi, updateFactoryOrderFlowConfigApi,
getFactoryOrderFlowConfigApi, getFactoryOrderFlowConfigApi,
} from '@/api/order' } from '@/api/order'
import { getPodOrderQualityCountApi } from '@/api/factoryOrderNew'
import type { import type {
FactoryOrderFlowConfigItem, FactoryOrderFlowConfigItem,
FactoryOrderFlowConfig, FactoryOrderFlowConfig,
} from '@/types/api/order' } from '@/types/api/order'
import type { SearchForm } from '@/types/api/factoryOrderNew'
const flowConfigList = ref<FactoryOrderFlowConfigItem[]>([]) const flowConfigList = ref<FactoryOrderFlowConfigItem[]>([])
const factoryOrderFlowConfig = ref<FactoryOrderFlowConfig>() const factoryOrderFlowConfig = ref<FactoryOrderFlowConfig>()
...@@ -36,7 +42,7 @@ const factoryOrderFlowConfig = ref<FactoryOrderFlowConfig>() ...@@ -36,7 +42,7 @@ const factoryOrderFlowConfig = ref<FactoryOrderFlowConfig>()
const draftSkipInspect = ref(false) const draftSkipInspect = ref(false)
const showFlowConfigList = computed(() => const showFlowConfigList = computed(() =>
factoryOrderFlowConfig.value?.skipQualityInspect ?? false draftSkipInspect.value
? flowConfigList.value.filter((item) => item.code !== 'INSPECTION') ? flowConfigList.value.filter((item) => item.code !== 'INSPECTION')
: flowConfigList.value, : flowConfigList.value,
) )
...@@ -61,6 +67,40 @@ const getList = async () => { ...@@ -61,6 +67,40 @@ const getList = async () => {
// 更新配置 // 更新配置
const updateConfig = async () => { const updateConfig = async () => {
try { try {
const prevSkip = factoryOrderFlowConfig.value?.skipQualityInspect ?? false
// 从未勾选改为勾选时,先查询待质检数量
if (!prevSkip && draftSkipInspect.value) {
const res = await getPodOrderQualityCountApi(
{} as SearchForm,
20,
'PENDING_QUALITY',
)
if (res.data?.totalCount) {
await ElMessageBox.confirm(
`有操作单仍在待质检状态,跳过质检流程将不展示待质检页面,但不影响操作单配货,<br/>
<span style="color: red; margin: 15px 0">是否确定跳过质检流程?</span>`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
dangerouslyUseHTMLString: true,
type: 'warning',
},
)
} else {
await ElMessageBox.confirm(`是否确定保存`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
}
} else {
await ElMessageBox.confirm(`是否确定保存`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
}
await updateFactoryOrderFlowConfigApi({ await updateFactoryOrderFlowConfigApi({
id: factoryOrderFlowConfig.value?.id ?? 0, id: factoryOrderFlowConfig.value?.id ?? 0,
skipQualityInspect: draftSkipInspect.value, skipQualityInspect: draftSkipInspect.value,
...@@ -78,9 +118,35 @@ onMounted(async () => { ...@@ -78,9 +118,35 @@ onMounted(async () => {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.page-wrap {
position: relative;
height: 100%;
}
.page {
width: 1200px;
margin: 0 auto;
}
.flow-config-container {
display: flex;
flex-direction: column;
align-items: flex-start;
width: max-content;
min-width: 900px;
margin: 50px auto 0;
}
.footer-actions { .footer-actions {
position: absolute;
bottom: -10px;
left: -10px;
right: -50px;
z-index: 1;
display: flex; display: flex;
justify-content: center; justify-content: center;
padding: 16px 0;
background: rgba(144, 147, 153, 0.2);
} }
.flow-steps { .flow-steps {
......
<template>
<ElDialog
v-model="visible"
:title="qualityPassed ? '质检通过' : '质检不通过'"
width="450px"
top="30vh"
:close-on-click-modal="false"
:destroy-on-close="true"
@close="handleClose"
>
<div class="confirm-body">
<ElIcon class="confirm-tip__icon" :size="24">
<WarningFilled />
</ElIcon>
<ElForm ref="formRef" :model="form" :rules="rules" class="confirm-form">
<div class="confirm-tip">
{{ qualityPassed ? '确定质检通过吗?' : '确定质检不通过吗?' }}
</div>
<ElFormItem
v-if="!qualityPassed"
label="原因"
prop="qualifyProblemType"
>
<ElSelect
v-model="form.qualifyProblemType"
placeholder="请选择不通过原因"
style="width: 100%"
clearable
filterable
@change="handleReasonChange"
>
<ElOption
v-for="item in reasonOptions"
:key="item.key"
:label="item.value"
:value="item.key"
/>
</ElSelect>
</ElFormItem>
<ElFormItem
v-if="!qualityPassed && form.qualifyProblemType === 5"
label="具体原因"
prop="qualityIssues"
>
<ElInput
v-model="form.qualityIssues"
placeholder="请输入不通过原因"
maxlength="50"
show-word-limit
clearable
/>
</ElFormItem>
</ElForm>
</div>
<template #footer>
<div class="dialog-footer" style="text-align: center">
<ElButton @click="visible = false">取消</ElButton>
<ElButton type="primary" :loading="submitLoading" @click="handleSubmit">
确认
</ElButton>
</div>
</template>
</ElDialog>
</template>
<script setup lang="ts">
import { computed, reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
import { WarningFilled } from '@element-plus/icons-vue'
import {
getQualityTypeApi,
qualityPodOrderOperationApi,
} from '@/api/factoryOrderNew'
import type { QualityTypeItem } from '@/types/api/factoryOrderNew'
const emit = defineEmits<{
success: []
}>()
const visible = ref(false)
const submitLoading = ref(false)
const qualityPassed = ref(true)
const source = ref(0) // 0 列表页,1 快捷质检
const formRef = ref<FormInstance>()
const updateParams = ref<{ id: number; version?: number }[]>([])
const reasonOptions = ref<QualityTypeItem[]>([])
const form = reactive<{
qualifyProblemType: number | string
qualityIssues: string
}>({
qualifyProblemType: '',
qualityIssues: '',
})
const rules = computed<FormRules>(() => {
if (qualityPassed.value) return {}
const result: FormRules = {
qualifyProblemType: [
{ required: true, message: '请选择不通过原因', trigger: 'change' },
],
}
if (form.qualifyProblemType && form.qualifyProblemType === 5) {
result.qualityIssues = [
{ required: true, message: '请输入不通过原因', trigger: 'change' },
]
}
return result
})
const loadReasons = async () => {
try {
const res = await getQualityTypeApi()
reasonOptions.value = res.data || []
} catch (e) {
console.error(e)
reasonOptions.value = []
}
}
const handleReasonChange = () => {
form.qualityIssues =
form.qualifyProblemType === 5
? ''
: reasonOptions.value.find((item) => item.key === form.qualifyProblemType)
?.value || ''
formRef.value?.clearValidate('qualityIssues')
}
const open = (
rows: { id: number; version?: number }[],
passed: boolean,
sourceType: number = 0,
) => {
updateParams.value = rows.map((row) => ({
id: row.id,
version: row.version,
}))
qualityPassed.value = passed
source.value = sourceType
form.qualifyProblemType = ''
form.qualityIssues = ''
visible.value = true
if (!passed) void loadReasons()
}
const handleClose = () => {
formRef.value?.resetFields()
reasonOptions.value = []
}
const handleSubmit = async () => {
if (!formRef.value) return
if (!qualityPassed.value) {
await formRef.value.validate()
}
submitLoading.value = true
try {
const params = {
...form,
updateParams: updateParams.value,
qualityPassed: qualityPassed.value,
source: source.value,
}
const res = await qualityPodOrderOperationApi(params)
if (res.code !== 200) return
if (source.value !== 1) {
ElMessage.success('操作成功')
}
visible.value = false
emit('success')
} catch (e) {
console.error(e)
} finally {
submitLoading.value = false
}
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
.confirm-body {
display: flex;
gap: 12px;
}
.confirm-form {
flex: 1;
min-width: 0;
}
.confirm-tip {
margin-bottom: 12px;
line-height: 24px;
}
.confirm-tip__icon {
flex-shrink: 0;
color: var(--el-color-warning);
}
</style>
...@@ -2,6 +2,7 @@ import { computed, ref, nextTick } from 'vue' ...@@ -2,6 +2,7 @@ import { computed, ref, nextTick } from 'vue'
import { import {
getCancelledOrderStatisticsApi, getCancelledOrderStatisticsApi,
getPodOrderAcceptedStatisticsApi, getPodOrderAcceptedStatisticsApi,
getPodOrderQualityCountApi,
getPodOrderStateGroupListApi, getPodOrderStateGroupListApi,
getSuspendStatisticsApi, getSuspendStatisticsApi,
} from '@/api/factoryOrderNew' } from '@/api/factoryOrderNew'
...@@ -24,6 +25,7 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) { ...@@ -24,6 +25,7 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
'PENDING_REPLENISH', 'PENDING_REPLENISH',
'IN_PRODUCTION', 'IN_PRODUCTION',
'PENDING_PACKING', 'PENDING_PACKING',
'PENDING_QUALITY',
] ]
const specialLayoutStatuses = ['BATCH_MANAGE', 'AWAITING_RESTOCK'] const specialLayoutStatuses = ['BATCH_MANAGE', 'AWAITING_RESTOCK']
...@@ -34,6 +36,8 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) { ...@@ -34,6 +36,8 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
PENDING_REPLENISH: '件', PENDING_REPLENISH: '件',
IN_PRODUCTION: '件', IN_PRODUCTION: '件',
PENDING_PACKING: '件', PENDING_PACKING: '件',
PENDING_RECEIVE: '件',
PENDING_QUALITY: '件',
BATCH_MANAGE: '批', BATCH_MANAGE: '批',
AWAITING_RESTOCK: '个', AWAITING_RESTOCK: '个',
} }
...@@ -51,6 +55,15 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) { ...@@ -51,6 +55,15 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
pendingCount: 0, pendingCount: 0,
acceptedOutOfStockCount: 0, acceptedOutOfStockCount: 0,
}) })
/** 待质检子 tab:待质检 / 质检不通过 */
const qualitySubTab = ref<'PENDING_QUALITY' | 'NO_QUALITY'>('PENDING_QUALITY')
const qualityCounts = ref<{
qualityCount?: number
noQualityCount?: number
}>({
qualityCount: 0,
noQualityCount: 0,
})
const suspendedTabs = ref([ const suspendedTabs = ref([
{ {
label: '客户拦截-取消订单', label: '客户拦截-取消订单',
...@@ -87,6 +100,12 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) { ...@@ -87,6 +100,12 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
: 2 : 2
: undefined : undefined
// 待质检子 tab:待质检 / 质检不通过
const getListPageQualitySubStatus = () =>
status.value === 'PENDING_QUALITY'
? qualitySubTab.value === 'PENDING_QUALITY'
: undefined
const getPendingReceiveCounts = async () => { const getPendingReceiveCounts = async () => {
try { try {
const res = await getPodOrderAcceptedStatisticsApi( const res = await getPodOrderAcceptedStatisticsApi(
...@@ -105,6 +124,23 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) { ...@@ -105,6 +124,23 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
} }
} }
const getQualityCounts = async () => {
try {
const res = await getPodOrderQualityCountApi(
getQueryPayload() as SearchForm,
pageSize.value,
status.value,
)
if (res.code !== 200) return
qualityCounts.value = res.data || {
qualityCount: 0,
noQualityCount: 0,
}
} catch (e) {
console.error(e)
}
}
const getSuspendCounts = async () => { const getSuspendCounts = async () => {
try { try {
const res = await getSuspendStatisticsApi( const res = await getSuspendStatisticsApi(
...@@ -195,6 +231,15 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) { ...@@ -195,6 +231,15 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
refreshTableList() refreshTableList()
} }
const handleQualityTabClick = (
tab: 'PENDING_QUALITY' | 'NO_QUALITY',
refreshList: () => void,
) => {
if (qualitySubTab.value === tab) return
qualitySubTab.value = tab
refreshList()
}
const toggleExpand = (node: { expanded?: boolean }) => { const toggleExpand = (node: { expanded?: boolean }) => {
node.expanded = !node.expanded node.expanded = !node.expanded
} }
...@@ -206,6 +251,8 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) { ...@@ -206,6 +251,8 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
status, status,
pendingAcceptSubTab, pendingAcceptSubTab,
pendingAcceptCounts, pendingAcceptCounts,
qualitySubTab,
qualityCounts,
suspendedTabs, suspendedTabs,
suspendedSubTab, suspendedSubTab,
cancelledTabs, cancelledTabs,
...@@ -215,11 +262,14 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) { ...@@ -215,11 +262,14 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
isSpecialLayout, isSpecialLayout,
isTableLayout, isTableLayout,
getListPageAcceptedSubStatus, getListPageAcceptedSubStatus,
getListPageQualitySubStatus,
getPendingReceiveCounts, getPendingReceiveCounts,
getQualityCounts,
getSuspendCounts, getSuspendCounts,
getCancelledCounts, getCancelledCounts,
loadStatusTreeCounts, loadStatusTreeCounts,
handlePendingAcceptTabClick, handlePendingAcceptTabClick,
handleQualityTabClick,
toggleExpand, toggleExpand,
} }
} }
...@@ -571,17 +571,42 @@ ...@@ -571,17 +571,42 @@
</ElDropdownMenu> </ElDropdownMenu>
</template> </template>
</ElDropdown> </ElDropdown>
<!-- 待质检 -->
<span v-if="status === 'PENDING_QUALITY'" class="item">
<ElButton
type="primary"
@click="handleQuickProduction('qualityScan')"
>
快捷质检
</ElButton>
</span>
<span v-if="status === 'PENDING_QUALITY'" class="item">
<ElButton type="success" @click="handleQuality(true)">
质检通过
</ElButton>
</span>
<span
v-if="
status === 'PENDING_QUALITY' && qualitySubTab === 'PENDING_QUALITY'
"
class="item"
>
<ElButton type="danger" @click="handleQuality(false)">
质检不通过
</ElButton>
</span>
<span <span
v-if=" v-if="
status === 'PENDING_PICK' || status === 'PENDING_PICK' ||
status === 'PENDING_REPLENISH' || status === 'PENDING_REPLENISH' ||
status === 'IN_PRODUCTION' status === 'IN_PRODUCTION' ||
status === 'PENDING_QUALITY'
" "
class="item" class="item"
> >
<ElButton type="success" @click="handlePrintProductionOrder" <ElButton type="success" @click="handlePrintProductionOrder">
>打印生产单</ElButton 打印操作单
> </ElButton>
</span> </span>
<span v-if="status === 'PENDING_PICK'" class="item"> <span v-if="status === 'PENDING_PICK'" class="item">
<ElButton type="warning" @click="handlePrintPickOrder" <ElButton type="warning" @click="handlePrintPickOrder"
...@@ -607,16 +632,16 @@ ...@@ -607,16 +632,16 @@
>补胚失败</ElButton >补胚失败</ElButton
> >
</span> </span>
<span v-if="status === 'IN_PRODUCTION' && isEnableSorting" class="item"> <span
v-if="status === 'PENDING_PACKING' && isEnableSorting"
class="item"
>
<ElButton type="primary" @click="handleSeedingWall('sort')" <ElButton type="primary" @click="handleSeedingWall('sort')"
>配货分拣</ElButton >配货分拣</ElButton
> >
</span> </span>
<span <span
v-if=" v-if="status === 'PENDING_PACKING' || !isEnableSorting"
status === 'PENDING_PACKING' ||
(status === 'IN_PRODUCTION' && !isEnableSorting)
"
class="item" class="item"
> >
<ElButton type="success" @click="handleSeedingWall('print')" <ElButton type="success" @click="handleSeedingWall('print')"
...@@ -630,15 +655,29 @@ ...@@ -630,15 +655,29 @@
</span> </span>
<span <span
v-if="status === 'IN_PRODUCTION' || status === 'PENDING_PACKING'" v-if="
status === 'IN_PRODUCTION' ||
status === 'PENDING_PACKING' ||
(status === 'PENDING_QUALITY' && qualitySubTab === 'NO_QUALITY')
"
class="item" class="item"
> >
<ElButton type="warning" @click="handleApplyReplenish" <ElButton type="warning" @click="handleApplyReplenish"
>申请补胚</ElButton >申请补胚</ElButton
> >
</span> </span>
<span
v-if="status === 'PENDING_QUALITY' && qualitySubTab === 'NO_QUALITY'"
class="item"
>
<ElButton type="warning" @click="handleRemanufacture">
重新生产
</ElButton>
</span>
<span v-if="['IN_PRODUCTION'].includes(status)" class="item"> <span v-if="['IN_PRODUCTION'].includes(status)" class="item">
<ElButton type="success" @click="handleQuickProduction()" <ElButton
type="success"
@click="handleQuickProduction('productionScan')"
>快捷生产</ElButton >快捷生产</ElButton
> >
</span> </span>
...@@ -720,13 +759,16 @@ ...@@ -720,13 +759,16 @@
</span> </span>
<span <span
v-if=" v-if="
status === 'PENDING_SCHEDULE' || [
status === 'PENDING_REPLENISH' || 'PENDING_SCHEDULE',
status === 'IN_PRODUCTION' || 'PENDING_REPLENISH',
status === 'PENDING_DELIVERY' || 'IN_PRODUCTION',
status === 'SUSPEND' || 'PENDING_DELIVERY',
status === 'PENDING_PICK' || 'SUSPEND',
status === 'PENDING_PACKING' 'PENDING_PICK',
'PENDING_PACKING',
'PENDING_QUALITY',
].includes(status)
" "
class="item" class="item"
> >
...@@ -744,6 +786,7 @@ ...@@ -744,6 +786,7 @@
'PENDING_REPLENISH', 'PENDING_REPLENISH',
'IN_PRODUCTION', 'IN_PRODUCTION',
'PENDING_PACKING', 'PENDING_PACKING',
'PENDING_QUALITY',
].includes(status) ].includes(status)
" "
class="item" class="item"
...@@ -808,6 +851,23 @@ ...@@ -808,6 +851,23 @@
</span> </span>
</div> </div>
</div> </div>
<div v-if="status === 'PENDING_QUALITY'" class="status-subtabs">
<div
class="status-subtab"
:class="{ active: qualitySubTab === 'PENDING_QUALITY' }"
@click="handleQualityTabClick('PENDING_QUALITY')"
>
待质检<span> ({{ qualityCounts.qualityCount || 0 }}) </span>
</div>
<div
class="status-subtab"
:class="{ active: qualitySubTab === 'NO_QUALITY' }"
@click="handleQualityTabClick('NO_QUALITY')"
>
质检不通过<span> ({{ qualityCounts.noQualityCount || 0 }}) </span>
</div>
</div>
<!-- 批次管理 --> <!-- 批次管理 -->
<BatchManageTable v-if="status === 'BATCH_MANAGE'" ref="batchManageRef" /> <BatchManageTable v-if="status === 'BATCH_MANAGE'" ref="batchManageRef" />
...@@ -1050,6 +1110,10 @@ ...@@ -1050,6 +1110,10 @@
ref="pickFailDialogRef" ref="pickFailDialogRef"
@success="() => refreshCurrentView({ isRefreshTree: true })" @success="() => refreshCurrentView({ isRefreshTree: true })"
/> />
<QualityFailDialog
ref="qualityFailDialogRef"
@success="() => refreshCurrentView({ isRefreshTree: true })"
/>
<CreateLogisticDialog <CreateLogisticDialog
ref="createLogisticDialogRef" ref="createLogisticDialogRef"
...@@ -1086,11 +1150,12 @@ ...@@ -1086,11 +1150,12 @@
pending-order-label="操作单号" pending-order-label="操作单号"
please-scan-tip="请扫码操作单号" please-scan-tip="请扫码操作单号"
search-input-audio-tip="请录入操作单号" search-input-audio-tip="请录入操作单号"
history-storage-key="historyFactoryOrderNewData" :history-storage-key="fastHistoryStorageKey"
tracking-placeholder="扫描枪输入操作单号" tracking-placeholder="扫描枪输入操作单号"
:query-api="getOperationByNo" :query-api="getOperationByNo"
:complete-api="completeOperationById" :complete-api="completeOperationById"
:download-api="downloadOperationById" :download-api="downloadOperationById"
:print-api="printOperationById"
@on-success="handleFastProductionSuccess" @on-success="handleFastProductionSuccess"
@close="fastClose" @close="fastClose"
/> />
...@@ -1310,6 +1375,7 @@ import { ...@@ -1310,6 +1375,7 @@ import {
completeDeliveryApi, completeDeliveryApi,
productionScanApi, productionScanApi,
getByOperationNoLogApi, getByOperationNoLogApi,
getQualityScanByOperationNoApi,
listByNoPodOrderApi, listByNoPodOrderApi,
orderWeighingPodOrderApi, orderWeighingPodOrderApi,
finishShipmentPodOrderApi, finishShipmentPodOrderApi,
...@@ -1323,8 +1389,10 @@ import { ...@@ -1323,8 +1389,10 @@ import {
interceptSuccessApi, interceptSuccessApi,
deliveryCompleteApi, deliveryCompleteApi,
getStatusPushApi, getStatusPushApi,
remanufactureApi,
} from '@/api/factoryOrderNew' } from '@/api/factoryOrderNew'
import { getConfigApi } from '@/api/order' import { getConfigApi } from '@/api/order'
import { printProductionQrCode } from '@/api/podOrder'
import { getLogisticsWayApi } from '@/api/podUsOrder' import { getLogisticsWayApi } from '@/api/podUsOrder'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import { filePath } from '@/api/axios' import { filePath } from '@/api/axios'
...@@ -1337,6 +1405,7 @@ import CancelOrderDialog from './component/CancelOrderDialog.vue' ...@@ -1337,6 +1405,7 @@ import CancelOrderDialog from './component/CancelOrderDialog.vue'
import SuspendDialog from './component/SuspendDialog.vue' import SuspendDialog from './component/SuspendDialog.vue'
import PickCompleteDialog from './component/PickCompleteDialog.vue' import PickCompleteDialog from './component/PickCompleteDialog.vue'
import PickFailDialog from './component/PickFailDialog.vue' import PickFailDialog from './component/PickFailDialog.vue'
import QualityFailDialog from './component/QualityFailDialog.vue'
import CardLayout from './component/CardLayout.vue' import CardLayout from './component/CardLayout.vue'
import BatchManageTable from './component/BatchManageTable.vue' import BatchManageTable from './component/BatchManageTable.vue'
import WaitingRestockTable from './component/WaitingRestockTable.vue' import WaitingRestockTable from './component/WaitingRestockTable.vue'
...@@ -1437,6 +1506,8 @@ const { ...@@ -1437,6 +1506,8 @@ const {
status, status,
pendingAcceptSubTab, pendingAcceptSubTab,
pendingAcceptCounts, pendingAcceptCounts,
qualitySubTab,
qualityCounts,
suspendedTabs, suspendedTabs,
suspendedSubTab, suspendedSubTab,
// cancelledTabs, // cancelledTabs,
...@@ -1446,11 +1517,14 @@ const { ...@@ -1446,11 +1517,14 @@ const {
isSpecialLayout, isSpecialLayout,
isTableLayout, isTableLayout,
getListPageAcceptedSubStatus, getListPageAcceptedSubStatus,
getListPageQualitySubStatus,
getPendingReceiveCounts, getPendingReceiveCounts,
getQualityCounts,
getSuspendCounts, getSuspendCounts,
// getCancelledCounts, // getCancelledCounts,
loadStatusTreeCounts, loadStatusTreeCounts,
handlePendingAcceptTabClick: handlePendingAcceptTabClickRaw, handlePendingAcceptTabClick: handlePendingAcceptTabClickRaw,
handleQualityTabClick: handleQualityTabClickRaw,
toggleExpand, toggleExpand,
} = useOrderStatusTree({ } = useOrderStatusTree({
getQueryPayload, getQueryPayload,
...@@ -1520,13 +1594,17 @@ const getListQueryPayload = () => { ...@@ -1520,13 +1594,17 @@ const getListQueryPayload = () => {
payload.prop = defaultSort.prop payload.prop = defaultSort.prop
payload.order = defaultSort.order payload.order = defaultSort.order
} }
const qualityPassed = getListPageQualitySubStatus()
if (qualityPassed !== undefined) {
payload.qualityPassed = qualityPassed
}
return payload return payload
} }
const getCraft = async () => { const getCraft = async () => {
const res = await getPodOrderCraftApi() const res = await getPodOrderCraftApi()
const data: CraftListData[] = res.data const data: CraftListData[] = res.data
podCraftList.value = data.map((item:CraftListData) => ({ podCraftList.value = data.map((item: CraftListData) => ({
id: item.craftCode, id: item.craftCode,
name: item.craftName, name: item.craftName,
warehouseName: processTypeMap[item.craftType] ?? '其他', warehouseName: processTypeMap[item.craftType] ?? '其他',
...@@ -1629,6 +1707,11 @@ const refreshCurrentView = (options?: { isRefreshTree?: boolean }) => { ...@@ -1629,6 +1707,11 @@ const refreshCurrentView = (options?: { isRefreshTree?: boolean }) => {
return return
} }
if (isCardLayout.value) { if (isCardLayout.value) {
if (status.value === 'PENDING_QUALITY') {
statusCurrentPageRef.value = currentPage.value
statusPageSizeRef.value = pageSize.value
void getQualityCounts()
}
cardLayoutRef.value?.clearSelection() cardLayoutRef.value?.clearSelection()
nextTick(() => { nextTick(() => {
cardLayoutRef.value?.refresh(true) cardLayoutRef.value?.refresh(true)
...@@ -1741,6 +1824,9 @@ const handleStatusNodeClick = (node: { status: string }) => { ...@@ -1741,6 +1824,9 @@ const handleStatusNodeClick = (node: { status: string }) => {
if (node.status !== 'PENDING_RECEIVE') { if (node.status !== 'PENDING_RECEIVE') {
pendingAcceptSubTab.value = 'PENDING_RECEIVE' pendingAcceptSubTab.value = 'PENDING_RECEIVE'
} }
if (node.status !== 'PENDING_QUALITY') {
qualitySubTab.value = 'PENDING_QUALITY'
}
if (node.status !== 'SUSPEND') { if (node.status !== 'SUSPEND') {
suspendedSubTab.value = 1 suspendedSubTab.value = 1
} }
...@@ -1773,6 +1859,14 @@ const handlePendingAcceptTabClick = ( ...@@ -1773,6 +1859,14 @@ const handlePendingAcceptTabClick = (
tab: 'PENDING_RECEIVE' | 'ACCEPT_FAIL_OUT_OF_STOCK', tab: 'PENDING_RECEIVE' | 'ACCEPT_FAIL_OUT_OF_STOCK',
) => handlePendingAcceptTabClickRaw(tab, refreshTableList) ) => handlePendingAcceptTabClickRaw(tab, refreshTableList)
const handleQualityTabClick = (tab: 'PENDING_QUALITY' | 'NO_QUALITY') =>
handleQualityTabClickRaw(tab, () => {
cardLayoutRef.value?.clearSelection()
nextTick(() => {
cardLayoutRef.value?.refresh(true)
})
})
const handleSuspendTabClick = (value: number) => { const handleSuspendTabClick = (value: number) => {
if (suspendedSubTab.value === value) return if (suspendedSubTab.value === value) return
suspendedSubTab.value = value suspendedSubTab.value = value
...@@ -1930,19 +2024,19 @@ const mainColumns = computed(() => [ ...@@ -1930,19 +2024,19 @@ const mainColumns = computed(() => [
}, },
{ {
prop: 'statusName', prop: 'statusName',
label:'挂起前状态', label: '挂起前状态',
minWidth: 120, minWidth: 120,
hidden:status.value !== 'SUSPEND', hidden: status.value !== 'SUSPEND',
align: 'center' align: 'center',
}, },
{ {
prop: 'statusName', prop: 'statusName',
hidden:status.value === 'SUSPEND', hidden: status.value === 'SUSPEND',
label: '订单状态', label: '订单状态',
minWidth: 120, minWidth: 120,
align: 'center', align: 'center',
render: (row: FactoryOrderNewListData) => { render: (row: FactoryOrderNewListData) => {
return <span>{ row.pause ? '挂起' : row.statusName}</span> return <span>{row.pause ? '挂起' : row.statusName}</span>
}, },
}, },
{ {
...@@ -2549,6 +2643,7 @@ const cancelOrderDialogRef = ref<InstanceType<typeof CancelOrderDialog>>() ...@@ -2549,6 +2643,7 @@ const cancelOrderDialogRef = ref<InstanceType<typeof CancelOrderDialog>>()
const suspendDialogRef = ref<InstanceType<typeof SuspendDialog>>() const suspendDialogRef = ref<InstanceType<typeof SuspendDialog>>()
const pickCompleteDialogRef = ref<InstanceType<typeof PickCompleteDialog>>() const pickCompleteDialogRef = ref<InstanceType<typeof PickCompleteDialog>>()
const pickFailDialogRef = ref<InstanceType<typeof PickFailDialog>>() const pickFailDialogRef = ref<InstanceType<typeof PickFailDialog>>()
const qualityFailDialogRef = ref<InstanceType<typeof QualityFailDialog>>()
const operateDetailsDialogRef = ref() const operateDetailsDialogRef = ref()
const arrangeDialogRef = ref<InstanceType<typeof ArrangeDialog>>() const arrangeDialogRef = ref<InstanceType<typeof ArrangeDialog>>()
const createLogisticDialogRef = ref() const createLogisticDialogRef = ref()
...@@ -2558,6 +2653,11 @@ const updateCustomsDialogVisible = ref(false) ...@@ -2558,6 +2653,11 @@ const updateCustomsDialogVisible = ref(false)
const weightDialogRef = ref() const weightDialogRef = ref()
const detailVisible = ref(false) const detailVisible = ref(false)
const fastKey = ref('') const fastKey = ref('')
const fastHistoryStorageKey = computed(() =>
fastKey.value === 'qualityScan'
? 'historyFactoryOrderNewQualityData'
: 'historyFactoryOrderNewData',
)
const detailData = ref<Record<string, unknown>>({}) const detailData = ref<Record<string, unknown>>({})
const { ensureSelection, executeBatchAction } = useOrderBatchActions({ const { ensureSelection, executeBatchAction } = useOrderBatchActions({
getIds: getSelectedIds, getIds: getSelectedIds,
...@@ -2927,10 +3027,7 @@ const handleSeedingWall = (type: 'print' | 'sort') => { ...@@ -2927,10 +3027,7 @@ const handleSeedingWall = (type: 'print' | 'sort') => {
/** LODOP 单例不可并发,打印串行 */ /** LODOP 单例不可并发,打印串行 */
let printOrderChain: Promise<void> = Promise.resolve() let printOrderChain: Promise<void> = Promise.resolve()
const printOrder = ( const printOrder = (data: OrderData, callback: (status: boolean) => void) => {
data: OrderData,
callback: (status: boolean) => void,
) => {
const run = async () => { const run = async () => {
const lodop = getCLodop(null, null) const lodop = getCLodop(null, null)
if (!lodop) { if (!lodop) {
...@@ -3238,7 +3335,7 @@ const handlePickComplete = () => { ...@@ -3238,7 +3335,7 @@ const handlePickComplete = () => {
} }
const handleDeliveryComplete = () => { const handleDeliveryComplete = () => {
if (!ensureSelection()) return if (!ensureSelection()) return
ElMessageBox.confirm('确定完成发货吗?', '提示', { ElMessageBox.confirm('确定配货完成吗?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
}) })
...@@ -3281,6 +3378,45 @@ const handleApplyReplenish = async () => { ...@@ -3281,6 +3378,45 @@ const handleApplyReplenish = async () => {
refreshTree: true, refreshTree: true,
}) })
} }
const handleRemanufacture = () => {
if (!ensureSelection()) return
const rows = isCardLayout.value ? cardSelectList.value : selectedRows.value
ElMessageBox.confirm(
`<div>确定重新生产吗?</br>
<span>确定后操作单状态返回生产中</span>
</div>`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
dangerouslyUseHTMLString: true,
},
)
.then(async () => {
const loading = ElLoading.service({
fullscreen: true,
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
try {
const res = await remanufactureApi({
updateParams: rows.map((row) => ({
id: row.id,
version: row.version,
})),
})
if (res.code !== 200) return
ElMessage.success('重新生产成功')
refreshCurrentView({ isRefreshTree: true })
} catch (e) {
console.error(e)
} finally {
loading.close()
}
})
.catch(() => {})
}
const adjustPickOrderSuccess = async ( const adjustPickOrderSuccess = async (
_: unknown, _: unknown,
selectionOperationIds: number[], selectionOperationIds: number[],
...@@ -3396,7 +3532,9 @@ const handleReplenishFail = () => { ...@@ -3396,7 +3532,9 @@ const handleReplenishFail = () => {
}) })
} }
const getOperationByNo = (operationNo: string) => const getOperationByNo = (operationNo: string) =>
getByOperationNoLogApi(operationNo) as Promise<{ data?: unknown }> (fastKey.value === 'qualityScan'
? getQualityScanByOperationNoApi(operationNo)
: getByOperationNoLogApi(operationNo)) as Promise<{ data?: unknown }>
const completeOperationById = ( const completeOperationById = (
ids: number[], ids: number[],
detailData?: Record<string, unknown>, detailData?: Record<string, unknown>,
...@@ -3411,8 +3549,15 @@ const completeOperationById = ( ...@@ -3411,8 +3549,15 @@ const completeOperationById = (
const downloadOperationById = (ids: number[]) => const downloadOperationById = (ids: number[]) =>
downloadOperationMaterialApi(ids) downloadOperationMaterialApi(ids)
const printOperationById = (id: number) => {
return printProductionQrCode(id, 'NEWP') as Promise<{
code?: number
message?: string
}>
}
const handleFastProductionSuccess = (data: ResultInfoDataItem[]) => { const handleFastProductionSuccess = (data: ResultInfoDataItem[]) => {
if (fastKey.value === 'productionScan') { if (fastKey.value === 'productionScan' || fastKey.value === 'qualityScan') {
ElMessage.success('操作成功') ElMessage.success('操作成功')
return return
} }
...@@ -3465,11 +3610,11 @@ const handleViewDetail = async (item: operateOrderListData) => { ...@@ -3465,11 +3610,11 @@ const handleViewDetail = async (item: operateOrderListData) => {
} }
} }
const isLimitScan = ref(false) const isLimitScan = ref(false)
const handleQuickProduction = () => { const handleQuickProduction = (key: string) => {
detailVisible.value = true fastKey.value = key
fastKey.value = 'productionScan'
isLimitScan.value = true isLimitScan.value = true
detailData.value = {} detailData.value = {}
detailVisible.value = true
} }
const handleSinglePrint = () => { const handleSinglePrint = () => {
podDistributionOrderVisible.value = true podDistributionOrderVisible.value = true
...@@ -3573,6 +3718,13 @@ const handleInterceptionFail = async (row?: FactoryOrderNewListData) => { ...@@ -3573,6 +3718,13 @@ const handleInterceptionFail = async (row?: FactoryOrderNewListData) => {
const handleGetOrderInventoryDetail = async () => { const handleGetOrderInventoryDetail = async () => {
orderInventoryDetailVisible.value = true orderInventoryDetailVisible.value = true
} }
const handleQuality = (qualityPassed: boolean) => {
if (!ensureSelection()) return
const rows = isCardLayout.value ? cardSelectList.value : selectedRows.value
qualityFailDialogRef.value?.open(rows, qualityPassed, 0)
}
const isEnableSorting = ref(false) const isEnableSorting = ref(false)
// 获取功能开关 // 获取功能开关
const getFunctionSwitch = async () => { const getFunctionSwitch = async () => {
...@@ -3600,6 +3752,8 @@ onMounted(() => { ...@@ -3600,6 +3752,8 @@ onMounted(() => {
void tableRef.value void tableRef.value
if (status.value === 'PENDING_RECEIVE') { if (status.value === 'PENDING_RECEIVE') {
getPendingReceiveCounts() getPendingReceiveCounts()
} else if (status.value === 'PENDING_QUALITY') {
void getQualityCounts()
} }
}) })
</script> </script>
......
...@@ -426,6 +426,7 @@ const operationStatusMap: Record<string, string> = { ...@@ -426,6 +426,7 @@ const operationStatusMap: Record<string, string> = {
PENDING_REPLENISH: '待补胚', PENDING_REPLENISH: '待补胚',
PENDING_PICK: '待拣胚', PENDING_PICK: '待拣胚',
IN_PRODUCTION: '生产中', IN_PRODUCTION: '生产中',
PENDING_QUALITY: '待质检',
PACKING_COMPLETED: '配货完成', PACKING_COMPLETED: '配货完成',
COMPLETED: '已完成', COMPLETED: '已完成',
CANCELLED: '已取消', CANCELLED: '已取消',
...@@ -454,6 +455,7 @@ const operationStatusTagMap: Record< ...@@ -454,6 +455,7 @@ const operationStatusTagMap: Record<
borderColor: '#409EFF', borderColor: '#409EFF',
}, },
}, },
PENDING_QUALITY: { type: 'warning' },
IN_PRODUCTION: { type: 'primary' }, IN_PRODUCTION: { type: 'primary' },
PACKING_COMPLETED: { type: 'success' }, PACKING_COMPLETED: { type: 'success' },
COMPLETED: { type: 'success' }, COMPLETED: { type: 'success' },
......
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