Commit a38597cf by wusiyi

feat: 添加质检流程 #1009863

parent 9bf605b9
......@@ -8,6 +8,8 @@ import type {
OrderInventoryData,
PickCompleteData,
ProductListData,
QualityParams,
QualityTypeItem,
RestockData,
SearchForm,
StatusTreeNode,
......@@ -94,6 +96,26 @@ export function getPodOrderAcceptedStatisticsApi(
})
}
// 待质检 数量统计
export function getPodOrderQualityCountApi(
data: SearchForm,
pageSize: number,
status?: string,
) {
return axios.post<
never,
BaseRespData<{
qualityCount?: number
noQualityCount?: number
}>
>('factory/podOrderOperation/quality-count', {
...normalizePodOrderQueryPayload({ ...data } as Record<string, unknown>),
currentPage: 1,
pageSize,
status,
})
}
export function getFactoryOrderNewDetailApi(id: number | string) {
return axios.get<never, BaseRespData<ProductListData[]>>(
'factory/podOrderProduct/getListByPodOrderId',
......@@ -707,3 +729,18 @@ export function deliveryCompleteApi(data: { id: number; version?: number }[]) {
{ orderParamList: 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 {
/** list_page 排序方向:asc 正序,desc 倒序 */
order?: 'asc' | 'desc'
customerNo?: string // 客户交运单号
/** 待质检子 tab:true 待质检,false 质检不通过 */
qualityPassed?: boolean
}
export interface FactoryOrderNewListData {
......@@ -304,3 +306,17 @@ export interface OrderInventoryData {
variantImage?: string
inventoryStatus?: number
}
/** 质检操作参数 */
export interface QualityParams {
updateParams: { id: number; version?: number }[]
qualityIssues: string
qualify_problem_type: number | string
qualityPassed: boolean
}
/** 质检不通过原因 */
export interface QualityTypeItem {
key: number | string
value: string
}
......@@ -57,6 +57,8 @@ export interface SearchForm {
/** list_page 排序方向:asc 正序,desc 倒序 */
order?: 'asc' | 'desc'
customerNo?: string // 客户交运单号
/** 待质检子 tab:true 待质检,false 质检不通过 */
qualityPassed?: boolean
}
export interface FactoryOrderNewListData {
......
<template>
<ElDialog
v-model="visible"
:title="qualityPassed ? '质检通过' : '质检不通过'"
width="450px"
:close-on-click-modal="false"
:destroy-on-close="true"
@close="handleClose"
>
<ElForm ref="formRef" :model="form" :rules="rules">
<div class="mb-10">
{{ qualityPassed ? '确定质检通过吗?' : '确定质检不通过吗?' }}
</div>
<ElFormItem v-if="!qualityPassed" label="原因" prop="reasonKey">
<ElSelect
v-model="form.reasonKey"
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.reasonKey === 5"
label="具体原因"
prop="qualify_problem_type"
>
<ElInput
v-model="form.qualify_problem_type"
placeholder="请输入不通过原因"
clearable
/>
</ElFormItem>
</ElForm>
<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 {
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 formRef = ref<FormInstance>()
const updateParams = ref<{ id: number; version?: number }[]>([])
const reasonOptions = ref<QualityTypeItem[]>([])
const form = reactive<{
reasonKey: number | string | undefined
qualify_problem_type: string
}>({
reasonKey: undefined,
qualify_problem_type: '',
})
const rules = computed<FormRules>(() => {
if (qualityPassed.value) return {}
const result: FormRules = {
reasonKey: [
{ required: true, message: '请选择不通过原因', trigger: 'change' },
],
}
if (form.reasonKey && form.reasonKey === 5) {
result.qualify_problem_type = [
{ required: true, message: '请输入不通过原因', trigger: 'blur' },
]
}
return result
})
const loadReasons = async () => {
try {
const res = await getQualityTypeApi()
reasonOptions.value = res.data || []
} catch (e) {
console.error(e)
reasonOptions.value = []
}
}
const handleReasonChange = () => {
form.qualify_problem_type = ''
formRef.value?.clearValidate('qualify_problem_type')
}
/** qualityPassed: true 质检通过,false 质检不通过 */
const open = (rows: { id: number; version?: number }[], passed: boolean) => {
updateParams.value = rows.map((row) => ({
id: row.id,
version: row.version,
}))
qualityPassed.value = passed
form.reasonKey = undefined
form.qualify_problem_type = ''
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()
}
const selected = reasonOptions.value.find(
(item) => item.key === form.reasonKey,
)
submitLoading.value = true
try {
const params = {
updateParams: updateParams.value,
qualityIssues: qualityPassed.value ? '' : selected?.value || '',
qualify_problem_type: qualityPassed.value
? ''
: form.reasonKey === 5
? form.qualify_problem_type
: (form.reasonKey as number | string),
qualityPassed: qualityPassed.value,
}
console.log(params)
return
const res = await qualityPodOrderOperationApi(params)
if (res.code !== 200) return
ElMessage.success('操作成功')
visible.value = false
emit('success')
} catch (e) {
console.error(e)
} finally {
submitLoading.value = false
}
}
defineExpose({ open })
</script>
......@@ -2,6 +2,7 @@ import { computed, ref, nextTick } from 'vue'
import {
getCancelledOrderStatisticsApi,
getPodOrderAcceptedStatisticsApi,
getPodOrderQualityCountApi,
getPodOrderStateGroupListApi,
getSuspendStatisticsApi,
} from '@/api/factoryOrderNew'
......@@ -24,6 +25,7 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
'PENDING_REPLENISH',
'IN_PRODUCTION',
'PENDING_PACKING',
'PENDING_QUALITY',
]
const specialLayoutStatuses = ['BATCH_MANAGE', 'AWAITING_RESTOCK']
......@@ -34,6 +36,7 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
PENDING_REPLENISH: '件',
IN_PRODUCTION: '件',
PENDING_PACKING: '件',
PENDING_RECEIVE: '件',
BATCH_MANAGE: '批',
AWAITING_RESTOCK: '个',
}
......@@ -51,6 +54,15 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
pendingCount: 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([
{
label: '客户拦截-取消订单',
......@@ -87,6 +99,12 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
: 2
: undefined
// 待质检子 tab:待质检 / 质检不通过
const getListPageQualitySubStatus = () =>
status.value === 'PENDING_QUALITY'
? qualitySubTab.value === 'PENDING_QUALITY'
: undefined
const getPendingReceiveCounts = async () => {
try {
const res = await getPodOrderAcceptedStatisticsApi(
......@@ -105,6 +123,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 () => {
try {
const res = await getSuspendStatisticsApi(
......@@ -195,6 +230,15 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
refreshTableList()
}
const handleQualityTabClick = (
tab: 'PENDING_QUALITY' | 'NO_QUALITY',
refreshList: () => void,
) => {
if (qualitySubTab.value === tab) return
qualitySubTab.value = tab
refreshList()
}
const toggleExpand = (node: { expanded?: boolean }) => {
node.expanded = !node.expanded
}
......@@ -206,6 +250,8 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
status,
pendingAcceptSubTab,
pendingAcceptCounts,
qualitySubTab,
qualityCounts,
suspendedTabs,
suspendedSubTab,
cancelledTabs,
......@@ -215,11 +261,14 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
isSpecialLayout,
isTableLayout,
getListPageAcceptedSubStatus,
getListPageQualitySubStatus,
getPendingReceiveCounts,
getQualityCounts,
getSuspendCounts,
getCancelledCounts,
loadStatusTreeCounts,
handlePendingAcceptTabClick,
handleQualityTabClick,
toggleExpand,
}
}
......@@ -763,6 +763,32 @@
>订单库存明细</ElButton
>
</span>
<!-- 待质检 -->
<span v-if="status === 'PENDING_QUALITY'" class="item">
<ElButton type="primary" @click="handleGetOrderInventoryDetail">
质检
</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 v-if="status === 'PENDING_QUALITY'" class="item">
<ElButton type="success" @click="handleGetOrderInventoryDetail">
打印操作单
</ElButton>
</span>
</div>
<div v-if="status === 'SUSPEND'" class="status-subtabs">
<div
......@@ -808,6 +834,23 @@
</span>
</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" />
......@@ -1050,6 +1093,10 @@
ref="pickFailDialogRef"
@success="() => refreshCurrentView({ isRefreshTree: true })"
/>
<QualityFailDialog
ref="qualityFailDialogRef"
@success="() => refreshCurrentView({ isRefreshTree: true })"
/>
<CreateLogisticDialog
ref="createLogisticDialogRef"
......@@ -1337,6 +1384,7 @@ import CancelOrderDialog from './component/CancelOrderDialog.vue'
import SuspendDialog from './component/SuspendDialog.vue'
import PickCompleteDialog from './component/PickCompleteDialog.vue'
import PickFailDialog from './component/PickFailDialog.vue'
import QualityFailDialog from './component/QualityFailDialog.vue'
import CardLayout from './component/CardLayout.vue'
import BatchManageTable from './component/BatchManageTable.vue'
import WaitingRestockTable from './component/WaitingRestockTable.vue'
......@@ -1437,6 +1485,8 @@ const {
status,
pendingAcceptSubTab,
pendingAcceptCounts,
qualitySubTab,
qualityCounts,
suspendedTabs,
suspendedSubTab,
// cancelledTabs,
......@@ -1446,11 +1496,14 @@ const {
isSpecialLayout,
isTableLayout,
getListPageAcceptedSubStatus,
getListPageQualitySubStatus,
getPendingReceiveCounts,
getQualityCounts,
getSuspendCounts,
// getCancelledCounts,
loadStatusTreeCounts,
handlePendingAcceptTabClick: handlePendingAcceptTabClickRaw,
handleQualityTabClick: handleQualityTabClickRaw,
toggleExpand,
} = useOrderStatusTree({
getQueryPayload,
......@@ -1520,6 +1573,10 @@ const getListQueryPayload = () => {
payload.prop = defaultSort.prop
payload.order = defaultSort.order
}
const qualityPassed = getListPageQualitySubStatus()
if (qualityPassed !== undefined) {
payload.qualityPassed = qualityPassed
}
return payload
}
......@@ -1629,6 +1686,11 @@ const refreshCurrentView = (options?: { isRefreshTree?: boolean }) => {
return
}
if (isCardLayout.value) {
if (status.value === 'PENDING_QUALITY') {
statusCurrentPageRef.value = currentPage.value
statusPageSizeRef.value = pageSize.value
void getQualityCounts()
}
cardLayoutRef.value?.clearSelection()
nextTick(() => {
cardLayoutRef.value?.refresh(true)
......@@ -1741,6 +1803,9 @@ const handleStatusNodeClick = (node: { status: string }) => {
if (node.status !== 'PENDING_RECEIVE') {
pendingAcceptSubTab.value = 'PENDING_RECEIVE'
}
if (node.status !== 'PENDING_QUALITY') {
qualitySubTab.value = 'PENDING_QUALITY'
}
if (node.status !== 'SUSPEND') {
suspendedSubTab.value = 1
}
......@@ -1773,6 +1838,14 @@ const handlePendingAcceptTabClick = (
tab: 'PENDING_RECEIVE' | 'ACCEPT_FAIL_OUT_OF_STOCK',
) => handlePendingAcceptTabClickRaw(tab, refreshTableList)
const handleQualityTabClick = (tab: 'PENDING_QUALITY' | 'NO_QUALITY') =>
handleQualityTabClickRaw(tab, () => {
cardLayoutRef.value?.clearSelection()
nextTick(() => {
cardLayoutRef.value?.refresh(true)
})
})
const handleSuspendTabClick = (value: number) => {
if (suspendedSubTab.value === value) return
suspendedSubTab.value = value
......@@ -2549,6 +2622,7 @@ const cancelOrderDialogRef = ref<InstanceType<typeof CancelOrderDialog>>()
const suspendDialogRef = ref<InstanceType<typeof SuspendDialog>>()
const pickCompleteDialogRef = ref<InstanceType<typeof PickCompleteDialog>>()
const pickFailDialogRef = ref<InstanceType<typeof PickFailDialog>>()
const qualityFailDialogRef = ref<InstanceType<typeof QualityFailDialog>>()
const operateDetailsDialogRef = ref()
const arrangeDialogRef = ref<InstanceType<typeof ArrangeDialog>>()
const createLogisticDialogRef = ref()
......@@ -3573,6 +3647,12 @@ const handleInterceptionFail = async (row?: FactoryOrderNewListData) => {
const handleGetOrderInventoryDetail = async () => {
orderInventoryDetailVisible.value = true
}
const handleQuality = (qualityPassed: boolean) => {
if (!ensureSelection()) return
const rows = isCardLayout.value ? cardSelectList.value : selectedRows.value
qualityFailDialogRef.value?.open(rows, qualityPassed)
}
const isEnableSorting = ref(false)
// 获取功能开关
const getFunctionSwitch = async () => {
......@@ -3600,6 +3680,8 @@ onMounted(() => {
void tableRef.value
if (status.value === 'PENDING_RECEIVE') {
getPendingReceiveCounts()
} else if (status.value === 'PENDING_QUALITY') {
void getQualityCounts()
}
})
</script>
......
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