|
|
|
|
@ -67,11 +67,19 @@
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
<view v-if="hasActions(item)" class="card-actions">
|
|
|
|
|
<view v-if="canExecute(item)" class="action-btn execute-btn" @click.stop="goExecute(item)">{{ t('productCheck.execute') }}</view>
|
|
|
|
|
<view
|
|
|
|
|
v-if="shouldShowExecute(item)"
|
|
|
|
|
:class="['action-btn', 'execute-btn', isExecuteDisabled(item) ? 'action-btn-disabled' : '']"
|
|
|
|
|
@click.stop="handleExecute(item)"
|
|
|
|
|
>
|
|
|
|
|
{{ t('productCheck.execute') }}
|
|
|
|
|
</view>
|
|
|
|
|
<view v-if="canSubmitAudit(item)" class="action-btn submit-btn" @click.stop="openSubmitAudit(item)">{{ t('productCheck.submitAudit') }}</view>
|
|
|
|
|
<view v-if="Number(item.status) === 10" class="action-btn approve-btn" @click.stop="handleApprove(item)">{{ t('productCheck.auditPass') }}</view>
|
|
|
|
|
<view v-if="Number(item.status) === 10" class="action-btn reject-btn" @click.stop="handleReject(item)">{{ t('productCheck.auditReject') }}</view>
|
|
|
|
|
<view v-if="Number(item.status) !== 20" class="action-btn delete-btn" @click.stop="handleDelete(item)">{{ t('productCheck.delete') }}</view>
|
|
|
|
|
<view v-if="canAudit(item)" class="action-btn approve-btn" @click.stop="handleApprove(item)">{{ t('productCheck.auditPass') }}</view>
|
|
|
|
|
<view v-if="canAudit(item)" class="action-btn reject-btn" @click.stop="handleReject(item)">{{ t('productCheck.auditReject') }}</view>
|
|
|
|
|
<view v-if="canDelete(item)" class="action-btn delete-btn" @click.stop="handleDelete(item)">
|
|
|
|
|
{{ t('productCheck.delete') }}
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
@ -149,19 +157,27 @@ import { useI18n } from 'vue-i18n'
|
|
|
|
|
import NavBar from '@/components/common/NavBar.vue'
|
|
|
|
|
import { auditProductCheck, deleteProductCheck, getProductCheckPage, submitProductCheck } from '@/api/mes/productCheck'
|
|
|
|
|
import { getConfigPage } from '@/api/infra/config'
|
|
|
|
|
import { DICT_TYPE, useDict } from '@/utils/dict'
|
|
|
|
|
|
|
|
|
|
const { t } = useI18n()
|
|
|
|
|
const { erp_audit_status } = useDict(DICT_TYPE.ERP_AUDIT_STATUS)
|
|
|
|
|
const selectedStatus = ref('')
|
|
|
|
|
const searchKeyword = ref('')
|
|
|
|
|
const statusPickerRef = ref(null)
|
|
|
|
|
const statusOptions = computed(() => [
|
|
|
|
|
const fallbackStatusOptions = computed(() => [
|
|
|
|
|
{ label: t('productCheck.statusDraft'), value: '0' },
|
|
|
|
|
{ label: t('productCheck.statusAuditing'), value: '10' },
|
|
|
|
|
{ label: t('productCheck.statusApproved'), value: '20' },
|
|
|
|
|
{ label: t('productCheck.statusRejected'), value: '1' }
|
|
|
|
|
])
|
|
|
|
|
const statusOptions = computed(() => {
|
|
|
|
|
const dictOptions = (erp_audit_status.value || [])
|
|
|
|
|
.filter((item) => item?.label !== undefined && item?.value !== undefined)
|
|
|
|
|
.map((item) => ({ ...item, value: String(item.value) }))
|
|
|
|
|
return dictOptions.length ? dictOptions : fallbackStatusOptions.value
|
|
|
|
|
})
|
|
|
|
|
const selectedStatusLabel = computed(() => {
|
|
|
|
|
const current = statusOptions.value.find((item) => item.value === selectedStatus.value)
|
|
|
|
|
const current = statusOptions.value.find((item) => String(item.value) === String(selectedStatus.value))
|
|
|
|
|
return current ? current.label : ''
|
|
|
|
|
})
|
|
|
|
|
const list = ref([])
|
|
|
|
|
@ -214,13 +230,8 @@ function normalizePageData(res) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function statusText(s) {
|
|
|
|
|
const map = {
|
|
|
|
|
0: t('productCheck.statusDraft'),
|
|
|
|
|
1: t('productCheck.statusRejected'),
|
|
|
|
|
10: t('productCheck.statusAuditing'),
|
|
|
|
|
20: t('productCheck.statusApproved')
|
|
|
|
|
}
|
|
|
|
|
return map[Number(s)] || textValue(s)
|
|
|
|
|
const current = statusOptions.value.find((item) => String(item.value) === String(s))
|
|
|
|
|
return current ? current.label : textValue(s)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function statusClass(s) {
|
|
|
|
|
@ -240,6 +251,10 @@ function checkStatusText(s) {
|
|
|
|
|
return Number(s) === 1 ? t('productCheck.checked') : t('productCheck.unchecked')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function statusValue(item) {
|
|
|
|
|
return Number(item?.status)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getProductNames(item) {
|
|
|
|
|
const items = Array.isArray(item?.items) ? item.items : []
|
|
|
|
|
return [...new Set(items.map((row) => row.productName).filter(Boolean))].join('、')
|
|
|
|
|
@ -250,17 +265,34 @@ function getWarehouseNames(item) {
|
|
|
|
|
return [...new Set(items.map((row) => row.warehouseName).filter(Boolean))].join('、')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function shouldShowExecute(item) {
|
|
|
|
|
return !isChecked(item) || statusValue(item) === 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isExecuteDisabled(item) {
|
|
|
|
|
return statusValue(item) === 20
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function canExecute(item) {
|
|
|
|
|
return Number(item?.status) !== 20 && !isChecked(item)
|
|
|
|
|
return shouldShowExecute(item) && !isExecuteDisabled(item)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function canSubmitAudit(item) {
|
|
|
|
|
const status = Number(item?.status)
|
|
|
|
|
return (status === 0 || status === 1) && isChecked(item)
|
|
|
|
|
const status = statusValue(item)
|
|
|
|
|
const submitStatuses = isAuditDisabled.value ? [0, 1, 10] : [0, 1]
|
|
|
|
|
return submitStatuses.includes(status) && isChecked(item)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function canAudit(item) {
|
|
|
|
|
return !isAuditDisabled.value && statusValue(item) === 10 && isChecked(item)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function canDelete(item) {
|
|
|
|
|
return statusValue(item) !== 20
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function hasActions(item) {
|
|
|
|
|
return canExecute(item) || canSubmitAudit(item) || Number(item?.status) === 10 || Number(item?.status) !== 20
|
|
|
|
|
return shouldShowExecute(item) || canSubmitAudit(item) || canAudit(item) || canDelete(item)
|
|
|
|
|
}
|
|
|
|
|
function hasIncompleteActualCount(item) {
|
|
|
|
|
const rows = Array.isArray(item?.items) ? item.items : []
|
|
|
|
|
@ -340,7 +372,7 @@ function openStatusPicker() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function selectStatus(option) {
|
|
|
|
|
selectedStatus.value = option.value
|
|
|
|
|
selectedStatus.value = String(option.value)
|
|
|
|
|
statusPickerRef.value?.close()
|
|
|
|
|
await fetchList(true)
|
|
|
|
|
}
|
|
|
|
|
@ -366,6 +398,11 @@ function goExecute(item) {
|
|
|
|
|
uni.navigateTo({ url: `/pages_function/pages/productCheck/execute?id=${encodeURIComponent(String(item.id))}` })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleExecute(item) {
|
|
|
|
|
if (!canExecute(item)) return
|
|
|
|
|
goExecute(item)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function goDetail(item) {
|
|
|
|
|
if (!item?.id) return
|
|
|
|
|
uni.navigateTo({ url: `/pages_function/pages/productCheck/execute?id=${encodeURIComponent(String(item.id))}&mode=detail` })
|
|
|
|
|
@ -439,7 +476,7 @@ async function confirmSubmitAudit() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleApprove(item) {
|
|
|
|
|
if (!item?.id) return
|
|
|
|
|
if (!item?.id || !canAudit(item)) return
|
|
|
|
|
uni.showModal({
|
|
|
|
|
title: t('productCheck.tip'),
|
|
|
|
|
content: t('productCheck.confirmAuditPass'),
|
|
|
|
|
@ -458,7 +495,7 @@ async function handleApprove(item) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleReject(item) {
|
|
|
|
|
if (!item?.id) return
|
|
|
|
|
if (!item?.id || !canAudit(item)) return
|
|
|
|
|
uni.showModal({
|
|
|
|
|
title: t('productCheck.tip'),
|
|
|
|
|
content: t('productCheck.confirmAuditReject'),
|
|
|
|
|
@ -477,7 +514,7 @@ async function handleReject(item) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleDelete(item) {
|
|
|
|
|
if (!item?.id) return
|
|
|
|
|
if (!item?.id || !canDelete(item)) return
|
|
|
|
|
uni.showModal({
|
|
|
|
|
title: t('productCheck.tip'),
|
|
|
|
|
content: t('productCheck.confirmDelete'),
|
|
|
|
|
@ -557,6 +594,7 @@ onUnload(() => clearSearchTimer())
|
|
|
|
|
.reject-btn,
|
|
|
|
|
.delete-btn { background: #fee2e2; color: #dc2626; }
|
|
|
|
|
.submit-btn { background: #dbeafe; color: #1d4ed8; }
|
|
|
|
|
.action-btn-disabled { background: #f1f5f9; color: #94a3b8; }
|
|
|
|
|
.record-tag.text-success { color: #15803d; background: #dcfce7; }
|
|
|
|
|
.record-tag.text-danger { color: #dc2626; background: #fee2e2; }
|
|
|
|
|
.record-tag.text-warning { color: #d97706; background: #fef3c7; }
|
|
|
|
|
|