style:备件和物料盘点执行列表-操作按钮逻辑

master
zhongwenkai 11 hours ago
parent a7290f1803
commit 071097c555

@ -78,12 +78,12 @@
<text class="value">{{ textValue(item.remark) }}</text>
</view>
</view>
<view class="card-actions" v-if="showActions(item)">
<view v-if="Number(item.status) === 10" class="action-btn approve-btn" @click.stop="handleApprove(item)"></view>
<view v-if="Number(item.status) === 10" class="action-btn reject-btn" @click.stop="handleReject(item)"></view>
<view v-if="showSubmit(item)" class="action-btn submit-btn" @click.stop="openSubmitDialog(item)"></view>
<view v-if="showCheck(item)" class="action-btn execute-btn" @click.stop="goExecute(item)"></view>
<view v-if="Number(item.status) !== 20" class="action-btn delete-btn" @click.stop="handleDelete(item)"></view>
<view class="card-actions" v-if="hasActions(item)">
<view v-if="canAudit(item)" class="action-btn approve-btn" @click.stop="handleApprove(item)"></view>
<view v-if="canAudit(item)" class="action-btn reject-btn" @click.stop="handleReject(item)"></view>
<view v-if="canSubmitAudit(item)" class="action-btn submit-btn" @click.stop="openSubmitDialog(item)"></view>
<view v-if="shouldShowExecute(item)" :class="['action-btn', 'execute-btn', isExecuteDisabled(item) ? 'action-btn-disabled' : '']" @click.stop="handleExecute(item)"></view>
<view v-if="canDelete(item)" class="action-btn delete-btn" @click.stop="handleDelete(item)"></view>
</view>
</view>
@ -110,7 +110,7 @@
<text class="modal-close" @click="closeSubmitDialog"></text>
</view>
<view class="modal-body">
<view class="modal-field">
<view v-if="!isAuditDisabled" class="modal-field">
<text class="modal-label"><text class="required">*</text>审核人</text>
<view class="modal-dropdown" @click="toggleSubmitAuditorDropdown">
<text :class="{ placeholder: !selectedSubmitAuditor }">{{ selectedSubmitAuditor ? selectedSubmitAuditor.label : '请选择' }}</text>
@ -146,18 +146,26 @@ import NavBar from '@/components/common/NavBar.vue'
import { getMaterialCheckPage, deleteMaterialCheck, submitMaterialCheck, auditMaterialCheck } from '@/api/mes/materialCheck'
import { getWarehouseSimpleList } from '@/api/mes/sparepart'
import { getSimpleUserList } from '@/api/mes/moldget'
import { getConfigPage } from '@/api/infra/config'
import { DICT_TYPE, useDict } from '@/utils/dict'
const selectedStatus = ref('')
const searchKeyword = ref('')
const materialWarehouseId = ref('')
const statusOptions = computed(() => [
{ label: '全部', value: '' },
{ label: '待提交', value: '0' },
{ label: '审核中', value: '10' },
{ label: '已通过', value: '20' },
{ label: '已驳回', 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) }))
if (dictOptions.length) return [{ label: '全部', value: '' }, ...dictOptions]
return [
{ label: '全部', value: '' },
{ label: '待提交', value: '0' },
{ label: '审核中', value: '10' },
{ label: '已通过', value: '20' },
{ label: '已驳回', value: '1' }
]
})
const statusLabels = computed(() => statusOptions.value.map((item) => item.label))
const statusIndex = computed(() => {
@ -179,6 +187,22 @@ const showGoTop = ref(false)
let searchTimer = null
//
const isAuditDisabled = ref(false)
const { erp_audit_status } = useDict(DICT_TYPE.ERP_AUDIT_STATUS)
async function loadAuditConfig() {
try {
const res = await getConfigPage({ pageNo: 1, pageSize: 10, key: 'inventoryAudit' })
const root = res && res.data !== undefined ? res.data : res
const rows = root?.list || root?.rows || root?.records || []
const config = Array.isArray(rows) ? rows.find((item) => item?.key === 'inventoryAudit') : null
isAuditDisabled.value = config?.value === '0'
} catch (e) {
isAuditDisabled.value = false
}
}
async function loadMaterialWarehouse() {
try {
const res = await getWarehouseSimpleList()
@ -230,10 +254,8 @@ function statusClass(s) {
return ''
}
const CHECK_STATUS_MAP = { 0: '未盘点', 1: '已盘点' }
function checkStatusText(s) {
const num = Number(s)
return CHECK_STATUS_MAP[num] || textValue(num)
return Number(s) === 1 ? '已盘点' : '未盘点'
}
function checkStatusClass(s) {
const num = Number(s)
@ -326,29 +348,47 @@ function openDetail(item) {
})
}
function showActions(item) {
if (!item) return false
const status = Number(item.status)
const checkStatus = Number(item.checkStatus)
if (status === 10) return true
if ((status === 0 || status === 1) && checkStatus === 1) return true
if (checkStatus !== 1 && status !== 20) return true
if (status !== 20) return true
return false
function statusValue(item) {
return Number(item?.status)
}
function isChecked(item) {
return Number(item?.checkStatus) === 1
}
function shouldShowExecute(item) {
return !isChecked(item) || statusValue(item) === 1
}
function isExecuteDisabled(item) {
return statusValue(item) === 20
}
function canExecute(item) {
return shouldShowExecute(item) && !isExecuteDisabled(item)
}
function canSubmitAudit(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 showSubmit(item) {
if (!item) return false
const status = Number(item.status)
const checkStatus = Number(item.checkStatus)
return (status === 0 || status === 1) && checkStatus === 1
function canDelete(item) {
return statusValue(item) !== 20
}
function showCheck(item) {
if (!item) return false
const checkStatus = Number(item.checkStatus)
const status = Number(item.status)
return checkStatus !== 1 && status !== 20
function hasActions(item) {
return shouldShowExecute(item) || canSubmitAudit(item) || canAudit(item) || canDelete(item)
}
function handleExecute(item) {
if (!canExecute(item)) return
goExecute(item)
}
const showSubmitModal = ref(false)
@ -396,13 +436,25 @@ async function loadSubmitAuditorOptions() {
}
async function confirmSubmitAudit() {
if (!selectedSubmitAuditor.value) {
if (!currentSubmitItem.value?.id) return
if (!isAuditDisabled.value && !selectedSubmitAuditor.value) {
uni.showToast({ title: '请选择审核人', icon: 'none' })
return
}
if (!currentSubmitItem.value?.id) return
try {
uni.showLoading({ title: '提交中...', mask: true })
if (isAuditDisabled.value) {
await auditMaterialCheck({
id: currentSubmitItem.value.id,
status: 20,
remark: submitRemark.value || undefined
})
uni.hideLoading()
uni.showToast({ title: '提交成功', icon: 'success' })
closeSubmitDialog()
fetchList(true)
return
}
await submitMaterialCheck({
id: currentSubmitItem.value.id,
auditUserId: selectedSubmitAuditor.value.value,
@ -520,6 +572,7 @@ function clearSearchTimer() {
onShow(async () => {
await loadMaterialWarehouse()
loadAuditConfig()
fetchList(true)
})
@ -723,6 +776,11 @@ onUnload(() => {
color: #dc2626;
}
&.action-btn-disabled {
background: #f1f5f7;
color: #94a3b8;
}
&:active {
opacity: 0.8;
}

@ -242,7 +242,7 @@
</template>
<script setup>
import { computed, reactive, ref, nextTick, watch } from 'vue'
import { computed, reactive, ref, nextTick } from 'vue'
import { onLoad, onReady, onShow } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import NavBar from '@/components/common/NavBar.vue'
@ -268,17 +268,6 @@ const moldCodeSearch = ref('')
const focusNoKeyboardRef = ref(null)
const keywordInputSelector = '#mold-repair-scan-input input, input#mold-repair-scan-input'
//
let scanTimer = null
watch(moldCodeSearch, (val) => {
if (readonlyBase.value) return
if (!val || !val.trim()) return
clearTimeout(scanTimer)
// 100ms300ms
scanTimer = setTimeout(() => {
doMoldCodeSearch(val.trim())
}, 300)
})
const today = getTodayDate()
const formData = reactive({
@ -485,49 +474,35 @@ function onMoldCodeSearch(event) {
async function doMoldCodeSearch(rawCode) {
if (readonlyBase.value) return
if (!rawCode) return
if (scanTimer) clearTimeout(scanTimer)
// JSONID
const scan = parseScanMoldResult(rawCode)
let code = scan.code || ''
let moldId = scan.id || ''
// typeMOLD
if (scan.type && scan.type !== 'MOLD') {
// JSONtype=MOLD MOLD-xxx / MOLD:xxx
if (!scan.type) {
uni.showToast({ title: t('moldRepair.moldNotFound'), icon: 'none' })
reFocusScanInput()
return
}
// IDcode
if (!moldId && !code) {
code = rawCode.trim()
if (scan.type !== 'MOLD') {
uni.showToast({ title: t('moldRepair.moldNotFound'), icon: 'none' })
reFocusScanInput()
return
}
// code
if (!code) code = rawCode.trim()
const lower = code.toLowerCase()
// moldIdcode
if (!moldId) {
if (code.toUpperCase().startsWith('MOLD-') || code.toUpperCase().startsWith('MOLD:')) {
moldId = code.replace(/MOLD[-:]/i, '')
} else {
const idMatch = code.match(/(\d+)$/)
if (idMatch) moldId = idMatch[1]
}
}
// 1. ID
let matched = moldOptions.value.find((item) => String(item.value) === String(moldId))
// 2. ID /
// 2. ID
if (!matched) {
matched = moldOptions.value.find((item) => {
const itemCode = String(item.raw?.code ?? item.raw?.moldCode ?? item.raw?.brandCode ?? '').trim().toLowerCase()
const itemName = String(item.raw?.name ?? item.raw?.moldName ?? item.raw?.brandName ?? '').trim().toLowerCase()
const itemLabel = String(item.label || '').toLowerCase()
return itemCode === lower || String(item.value) === code || itemCode.includes(lower) || itemName.includes(lower) || itemLabel.includes(lower)
return itemCode === lower || String(item.value) === code
})
}

@ -81,17 +81,16 @@
</view>
</view>
<!-- 操作按钮 -->
<view class="card-actions" v-if="showActions(item)">
<!-- 审核通过status=10时显示 -->
<view v-if="Number(item.status) === 10" class="action-btn approve-btn" @click.stop="handleApprove(item)"></view>
<!-- 审核驳回status=10时显示 -->
<view v-if="Number(item.status) === 10" class="action-btn reject-btn" @click.stop="handleReject(item)"></view>
<!-- 提交status=0|1 checkStatus=1 -->
<view v-if="showSubmit(item)" class="action-btn submit-btn" @click.stop="openSubmitDialog(item)"></view>
<!-- 盘点checkStatus1 status20 -->
<view v-if="showCheck(item)" class="action-btn execute-btn" @click.stop="goExecute(item)"></view>
<!-- 删除status20 -->
<view v-if="Number(item.status) !== 20" class="action-btn delete-btn" @click.stop="handleDelete(item)"></view>
<view class="card-actions" v-if="hasActions(item)">
<!-- 审核通过/驳回status=10 canAudit -->
<view v-if="canAudit(item)" class="action-btn approve-btn" @click.stop="handleApprove(item)"></view>
<view v-if="canAudit(item)" class="action-btn reject-btn" @click.stop="handleReject(item)"></view>
<!-- 提交canSubmitAudit -->
<view v-if="canSubmitAudit(item)" class="action-btn submit-btn" @click.stop="openSubmitDialog(item)"></view>
<!-- 盘点shouldShowExecute -->
<view v-if="shouldShowExecute(item)" :class="['action-btn', 'execute-btn', isExecuteDisabled(item) ? 'action-btn-disabled' : '']" @click.stop="handleExecute(item)"></view>
<!-- 删除canDelete -->
<view v-if="canDelete(item)" class="action-btn delete-btn" @click.stop="handleDelete(item)"></view>
</view>
</view>
@ -120,7 +119,7 @@
<text class="modal-close" @click="closeSubmitDialog"></text>
</view>
<view class="modal-body">
<view class="modal-field">
<view v-if="!isAuditDisabled" class="modal-field">
<text class="modal-label"><text class="required">*</text>审核人</text>
<view class="modal-dropdown" @click="toggleSubmitAuditorDropdown">
<text :class="{ placeholder: !selectedSubmitAuditor }">{{ selectedSubmitAuditor ? selectedSubmitAuditor.label : '请选择' }}</text>
@ -156,18 +155,26 @@ import NavBar from '@/components/common/NavBar.vue'
import { getSparepartCheckPage, deleteSparepartCheck, submitSparepartCheck, auditSparepartCheck } from '@/api/mes/sparepartCheck'
import { getWarehouseSimpleList } from '@/api/mes/sparepart'
import { getSimpleUserList } from '@/api/mes/moldget'
import { getConfigPage } from '@/api/infra/config'
import { DICT_TYPE, useDict } from '@/utils/dict'
const selectedStatus = ref('')
const searchKeyword = ref('')
const sparepartWarehouseId = ref('')
const statusOptions = computed(() => [
{ label: '全部', value: '' },
{ label: '待提交', value: '0' },
{ label: '审核中', value: '10' },
{ label: '已通过', value: '20' },
{ label: '已驳回', 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) }))
if (dictOptions.length) return [{ label: '全部', value: '' }, ...dictOptions]
return [
{ label: '全部', value: '' },
{ label: '待提交', value: '0' },
{ label: '审核中', value: '10' },
{ label: '已通过', value: '20' },
{ label: '已驳回', value: '1' }
]
})
const statusLabels = computed(() => statusOptions.value.map((item) => item.label))
const statusIndex = computed(() => {
@ -189,6 +196,22 @@ const showGoTop = ref(false)
let searchTimer = null
//
const isAuditDisabled = ref(false)
const { erp_audit_status } = useDict(DICT_TYPE.ERP_AUDIT_STATUS)
async function loadAuditConfig() {
try {
const res = await getConfigPage({ pageNo: 1, pageSize: 10, key: 'inventoryAudit' })
const root = res && res.data !== undefined ? res.data : res
const rows = root?.list || root?.rows || root?.records || []
const config = Array.isArray(rows) ? rows.find((item) => item?.key === 'inventoryAudit') : null
isAuditDisabled.value = config?.value === '0'
} catch (e) {
isAuditDisabled.value = false
}
}
async function loadSparepartWarehouse() {
try {
const res = await getWarehouseSimpleList()
@ -240,10 +263,8 @@ function statusClass(s) {
return ''
}
const CHECK_STATUS_MAP = { 0: '未盘点', 1: '已盘点' }
function checkStatusText(s) {
const num = Number(s)
return CHECK_STATUS_MAP[num] || textValue(num)
return Number(s) === 1 ? '已盘点' : '未盘点'
}
function checkStatusClass(s) {
const num = Number(s)
@ -335,33 +356,47 @@ function openDetail(item) {
})
}
function showActions(item) {
if (!item) return false
const status = Number(item.status)
const checkStatus = Number(item.checkStatus)
// +
if (status === 10) return true
// /
if ((status === 0 || status === 1) && checkStatus === 1) return true
//
if (checkStatus !== 1 && status !== 20) return true
//
if (status !== 20) return true
return false
function statusValue(item) {
return Number(item?.status)
}
function isChecked(item) {
return Number(item?.checkStatus) === 1
}
function shouldShowExecute(item) {
return !isChecked(item) || statusValue(item) === 1
}
function isExecuteDisabled(item) {
return statusValue(item) === 20
}
function canExecute(item) {
return shouldShowExecute(item) && !isExecuteDisabled(item)
}
function canSubmitAudit(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 showSubmit(item) {
if (!item) return false
const status = Number(item.status)
const checkStatus = Number(item.checkStatus)
return (status === 0 || status === 1) && checkStatus === 1
function canDelete(item) {
return statusValue(item) !== 20
}
function showCheck(item) {
if (!item) return false
const checkStatus = Number(item.checkStatus)
const status = Number(item.status)
return checkStatus !== 1 && status !== 20
function hasActions(item) {
return shouldShowExecute(item) || canSubmitAudit(item) || canAudit(item) || canDelete(item)
}
function handleExecute(item) {
if (!canExecute(item)) return
goExecute(item)
}
//
@ -410,13 +445,25 @@ async function loadSubmitAuditorOptions() {
}
async function confirmSubmitAudit() {
if (!selectedSubmitAuditor.value) {
if (!currentSubmitItem.value?.id) return
if (!isAuditDisabled.value && !selectedSubmitAuditor.value) {
uni.showToast({ title: '请选择审核人', icon: 'none' })
return
}
if (!currentSubmitItem.value?.id) return
try {
uni.showLoading({ title: '提交中...', mask: true })
if (isAuditDisabled.value) {
await auditSparepartCheck({
id: currentSubmitItem.value.id,
status: 20,
remark: submitRemark.value || undefined
})
uni.hideLoading()
uni.showToast({ title: '提交成功', icon: 'success' })
closeSubmitDialog()
fetchList(true)
return
}
await submitSparepartCheck({
id: currentSubmitItem.value.id,
auditUserId: selectedSubmitAuditor.value.value,
@ -557,6 +604,7 @@ function clearSearchTimer() {
onShow(async () => {
await loadSparepartWarehouse()
loadAuditConfig()
fetchList(true)
})
@ -763,6 +811,11 @@ onUnload(() => {
color: #dc2626;
}
&.action-btn-disabled {
background: #f1f5f7;
color: #94a3b8;
}
&:active {
opacity: 0.8;
}

Loading…
Cancel
Save