| | |
| | | <view class="card-body"> |
| | | <view class="row"><text class="l">规格型号</text><text class="r">{{ item.model }}</text></view> |
| | | <view class="row"><text class="l">单位</text><text class="r">{{ item.unit }}</text></view> |
| | | <view class="row"><text class="l">出库数量</text><text class="r highlight">{{ item.stockOutNum }}</text></view> |
| | | <view class="row"><text class="l">出库人</text><text class="r">{{ item.createBy }}</text></view> |
| | | <view class="row"><text class="l">出库数量</text><text class="r highlight">{{ item.netWeight }}</text></view> |
| | | <view class="row"><text class="l">采购员</text><text class="r">{{ item.purchaser || item.createBy }}</text></view> |
| | | <view class="row" v-if="item.recordType !== undefined"><text class="l">来源</text><text class="r">{{ getRecordType(item.recordType) || item.recordType }}</text></view> |
| | | <view class="row"><text class="l">毛重(吨)</text><text class="r">{{ item.grossWeight ?? '-' }}</text></view> |
| | | <view class="row"><text class="l">皮重(吨)</text><text class="r">{{ item.tareWeight ?? '-' }}</text></view> |
| | | <view class="row"><text class="l">净重(吨)</text><text class="r">{{ item.netWeight ?? '-' }}</text></view> |
| | | <view class="row"><text class="l">过磅日期</text><text class="r">{{ item.weighingDate || '-' }}</text></view> |
| | | <view class="row"><text class="l">过磅员</text><text class="r">{{ item.weighingOperator || '-' }}</text></view> |
| | | </view> |
| | | </view> |
| | | <view class="card-actions"> |
| | | <view class="btn-delete" @click.stop="handleDeleteSingle(item)">删除</view> |
| | | <view |
| | | v-if="isQualifiedRow(item) && hasDispatchEdit" |
| | | class="btn-edit" |
| | | @click.stop="handleEdit(item)" |
| | | > |
| | | 编辑 |
| | | </view> |
| | | <view |
| | | v-if="hasDispatchCancel" |
| | | class="btn-delete" |
| | | @click.stop="handleDeleteSingle(item)" |
| | | > |
| | | 删除 |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | <view class="load-more-wrap" v-if="tableData.length > 0"> |
| | | <u-loadmore :status="loadStatus" @loadmore="loadMore" /> |
| | | </view> |
| | | |
| | | <!-- 编辑弹窗(参照 PC) --> |
| | | <up-popup :show="showEditModal" mode="bottom" @close="showEditModal = false"> |
| | | <view class="edit-popup"> |
| | | <view class="popup-header"> |
| | | <text class="popup-title">编辑出库</text> |
| | | </view> |
| | | <scroll-view scroll-y class="popup-body"> |
| | | <view class="form-row"> |
| | | <text class="form-label required">车牌号</text> |
| | | <up-input v-model="editForm.licensePlateNo" placeholder="请输入车牌号" /> |
| | | </view> |
| | | |
| | | <view class="form-row"> |
| | | <text class="form-label required">毛重(吨)</text> |
| | | <up-input |
| | | v-model="editForm.grossWeight" |
| | | type="digit" |
| | | placeholder="请输入毛重" |
| | | @blur="computeNetWeightEdit" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-row"> |
| | | <text class="form-label required">皮重(吨)</text> |
| | | <up-input |
| | | v-model="editForm.tareWeight" |
| | | type="digit" |
| | | placeholder="请输入皮重" |
| | | @blur="computeNetWeightEdit" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-row"> |
| | | <text class="form-label required">净重(吨)</text> |
| | | <up-input v-model="editForm.netWeight" type="digit" placeholder="自动计算" disabled /> |
| | | </view> |
| | | |
| | | <view class="form-row"> |
| | | <text class="form-label required">过磅日期</text> |
| | | <view class="selector-trigger" @click="openWeighingDatePicker"> |
| | | <text class="selector-text" :class="{ placeholder: !editForm.weighingDate }"> |
| | | {{ editForm.weighingDate || '请选择过磅日期' }} |
| | | </text> |
| | | <up-icon name="calendar" size="16" color="#999" /> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="form-row"> |
| | | <text class="form-label required">过磅员</text> |
| | | <up-input v-model="editForm.weighingOperator" placeholder="请输入过磅员" /> |
| | | </view> |
| | | |
| | | <view class="form-row"> |
| | | <text class="form-label">备注</text> |
| | | <up-input v-model="editForm.remark" type="textarea" placeholder="选填" /> |
| | | </view> |
| | | </scroll-view> |
| | | |
| | | <view class="popup-footer"> |
| | | <view class="btn-cancel" @click="showEditModal = false">取消</view> |
| | | <view class="btn-ok" @click="handleEditSubmit">确认</view> |
| | | </view> |
| | | |
| | | <up-popup :show="showWeighingDatePicker" mode="bottom" @close="showWeighingDatePicker = false"> |
| | | <up-datetime-picker |
| | | :show="true" |
| | | v-model="weighingDateValue" |
| | | mode="datetime" |
| | | @confirm="onWeighingDateConfirm" |
| | | @cancel="showWeighingDatePicker = false" |
| | | /> |
| | | </up-popup> |
| | | </view> |
| | | </up-popup> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, toRefs } from 'vue' |
| | | import { computed, ref, reactive, toRefs, watch } from 'vue' |
| | | import { onShow, onReachBottom } from '@dcloudio/uni-app' |
| | | import PageHeader from '@/components/PageHeader.vue' |
| | | import { getStockOutPage, delStockOut } from '@/api/inventoryManagement/stockOutRecord.js' |
| | | import dayjs from 'dayjs' |
| | | import { checkPermi } from '@/utils/permission' |
| | | import { getStockOutPage, delStockOut, editStockOut } from '@/api/inventoryManagement/stockOutRecord.js' |
| | | import { |
| | | findAllQualifiedStockOutRecordTypeOptions |
| | | } from '@/api/basicData/enum.js' |
| | |
| | | }) |
| | | const { searchForm } = toRefs(data) |
| | | |
| | | // 权限控制(参照 PC) |
| | | const hasDispatchEdit = computed(() => checkPermi(['dispatch_edit'])) |
| | | const hasDispatchCancel = computed(() => checkPermi(['dispatch_cancel'])) |
| | | |
| | | function getRecordType(recordType) { |
| | | if (recordType == null || recordType === '') return '' |
| | | return stockRecordTypeOptions.value.find(item => item.value === recordType)?.label || '' |
| | |
| | | .catch(() => { |
| | | stockRecordTypeOptions.value = [] |
| | | }) |
| | | } |
| | | |
| | | function isQualifiedRow(row) { |
| | | return row?.recordType === 0 || row?.recordType === '0' |
| | | } |
| | | |
| | | const getList = () => { |
| | |
| | | } |
| | | |
| | | const handleDeleteSingle = (item) => { |
| | | if (!hasDispatchCancel.value) return |
| | | uni.showModal({ |
| | | title: '删除', |
| | | content: '确认删除该条出库记录?', |
| | |
| | | } |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // ---------------- 编辑 ---------------- |
| | | const showEditModal = ref(false) |
| | | const showWeighingDatePicker = ref(false) |
| | | const weighingDateValue = ref(Date.now()) |
| | | |
| | | const editForm = reactive({ |
| | | id: null, |
| | | licensePlateNo: '', |
| | | grossWeight: '', |
| | | tareWeight: '', |
| | | netWeight: '', |
| | | weighingDate: '', |
| | | weighingOperator: '', |
| | | remark: '' |
| | | }) |
| | | |
| | | const computeNetWeightEdit = () => { |
| | | const gross = Number(editForm.grossWeight) |
| | | const tare = Number(editForm.tareWeight) |
| | | if (Number.isFinite(gross) && Number.isFinite(tare)) { |
| | | const net = gross - tare |
| | | const safeNet = Number(net.toFixed(2)) |
| | | editForm.netWeight = safeNet > 0 ? safeNet : 0 |
| | | } |
| | | } |
| | | |
| | | watch( |
| | | () => [showEditModal.value, editForm.grossWeight, editForm.tareWeight], |
| | | () => { |
| | | if (showEditModal.value) computeNetWeightEdit() |
| | | } |
| | | ) |
| | | |
| | | const openWeighingDatePicker = () => { |
| | | weighingDateValue.value = editForm.weighingDate |
| | | ? dayjs(editForm.weighingDate).valueOf() |
| | | : Date.now() |
| | | showWeighingDatePicker.value = true |
| | | } |
| | | |
| | | const onWeighingDateConfirm = (e) => { |
| | | editForm.weighingDate = dayjs(e.value).format('YYYY-MM-DD HH:mm:ss') |
| | | showWeighingDatePicker.value = false |
| | | } |
| | | |
| | | const handleEdit = (row) => { |
| | | Object.assign(editForm, row || {}) |
| | | // 以当前毛重/皮重为准计算净重 |
| | | computeNetWeightEdit() |
| | | showEditModal.value = true |
| | | } |
| | | |
| | | const handleEditSubmit = () => { |
| | | if (!hasDispatchEdit.value) return |
| | | if (!editForm.licensePlateNo) return uni.showToast({ title: '请输入车牌号', icon: 'none' }) |
| | | if (!editForm.grossWeight && editForm.grossWeight !== 0) return uni.showToast({ title: '请输入毛重', icon: 'none' }) |
| | | if (!editForm.tareWeight && editForm.tareWeight !== 0) return uni.showToast({ title: '请输入皮重', icon: 'none' }) |
| | | if (!editForm.weighingDate) return uni.showToast({ title: '请选择过磅日期', icon: 'none' }) |
| | | if (!editForm.weighingOperator) return uni.showToast({ title: '请输入过磅员', icon: 'none' }) |
| | | |
| | | uni.showLoading({ title: '保存中...', mask: true }) |
| | | const { stockOutNum, ...payload } = editForm |
| | | editStockOut(payload) |
| | | .then(() => { |
| | | uni.showToast({ title: '编辑成功', icon: 'success' }) |
| | | showEditModal.value = false |
| | | getList() |
| | | }) |
| | | .catch(() => { |
| | | uni.showToast({ title: '编辑失败', icon: 'none' }) |
| | | }) |
| | | .finally(() => { |
| | | uni.hideLoading() |
| | | }) |
| | | } |
| | | |
| | | const goBack = () => uni.navigateBack() |
| | |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | width: 100%; |
| | | text-align: center; |
| | | } |
| | | .btn-delete { |
| | | font-size: 28rpx; |
| | | color: #f56c6c; |
| | | padding: 12rpx 32rpx; |
| | | margin: 0 auto; |
| | | display: inline-flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | .btn-edit { |
| | | font-size: 28rpx; |
| | | color: #2979ff; |
| | | padding: 12rpx 32rpx; |
| | | margin: 0 auto; |
| | | display: inline-flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | .no-data { |
| | | text-align: center; |
| | |
| | | font-size: 28rpx; |
| | | } |
| | | .load-more-wrap { padding: 24rpx 0 40rpx; } |
| | | |
| | | /* 编辑弹窗样式 */ |
| | | .edit-popup { |
| | | background: #fff; |
| | | border-radius: 24rpx 24rpx 0 0; |
| | | padding-bottom: env(safe-area-inset-bottom); |
| | | } |
| | | .popup-header { |
| | | padding: 24rpx; |
| | | border-bottom: 1rpx solid #eee; |
| | | text-align: center; |
| | | } |
| | | .popup-title { |
| | | font-size: 30rpx; |
| | | font-weight: 500; |
| | | color: #333; |
| | | } |
| | | .popup-body { |
| | | padding: 24rpx 24rpx 0; |
| | | max-height: 60vh; |
| | | } |
| | | .popup-footer { |
| | | display: flex; |
| | | gap: 24rpx; |
| | | padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom)); |
| | | border-top: 1rpx solid #eee; |
| | | } |
| | | .btn-cancel, |
| | | .btn-ok { |
| | | flex: 1; |
| | | height: 88rpx; |
| | | border-radius: 999rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 30rpx; |
| | | } |
| | | .btn-cancel { |
| | | background: #f0f0f0; |
| | | color: #666; |
| | | } |
| | | .btn-ok { |
| | | background: #2979ff; |
| | | color: #fff; |
| | | } |
| | | .form-row { |
| | | margin-bottom: 24rpx; |
| | | } |
| | | .form-label { |
| | | display: block; |
| | | font-size: 26rpx; |
| | | color: #666; |
| | | margin-bottom: 12rpx; |
| | | } |
| | | .form-label.required:before { |
| | | content: '*'; |
| | | color: #f56c6c; |
| | | margin-right: 6rpx; |
| | | } |
| | | .selector-trigger { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 20rpx 24rpx; |
| | | background: #f5f5f5; |
| | | border-radius: 12rpx; |
| | | } |
| | | .selector-text { |
| | | font-size: 28rpx; |
| | | color: #333; |
| | | } |
| | | .selector-text.placeholder { |
| | | color: #999; |
| | | } |
| | | </style> |