| | |
| | | <template> |
| | | <view class="receipt-page"> |
| | | <PageHeader title="入库管理" @back="goBack" /> |
| | | <view class="tabs-wrap"> |
| | | <view |
| | | v-for="tab in tabs" |
| | | :key="tab.name" |
| | | class="tab-item" |
| | | :class="{ active: activeTab === tab.name }" |
| | | @click="activeTab = tab.name" |
| | | > |
| | | <text>{{ tab.label }}</text> |
| | | </view> |
| | | </view> |
| | | <view class="search-section"> |
| | | <view class="search-row"> |
| | | <view class="search-input-wrap"> |
| | |
| | | <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.stockInNum }}</text></view> |
| | | <view class="row"><text class="l">入库数量</text><text class="r highlight">{{ item.qualitity ?? item.stockInNum }}</text></view> |
| | | <view class="row"><text class="l">采购员</text><text class="r">{{ item.purchaser || '-' }}</text></view> |
| | | <view class="row"><text class="l">入库人</text><text class="r">{{ 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> |
| | | </view> |
| | | <view class="card-actions"> |
| | | <view class="btn-delete" @click.stop="handleDeleteSingle(item)">删除</view> |
| | | <view v-if="hasCReceiptEdit" class="btn-edit" @click.stop="handleEdit(item)">编辑</view> |
| | | <view v-if="hasCReceiptCancel" 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> |
| | | |
| | | <!-- 编辑弹窗 --> |
| | | <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 class="popup-body" scroll-y> |
| | | <view class="form-row"> |
| | | <text class="form-label required">数量</text> |
| | | <up-input v-model="editForm.qualitity" type="number" placeholder="请输入数量" /> |
| | | </view> |
| | | <view class="form-row"> |
| | | <text class="form-label required">采购员</text> |
| | | <up-input v-model="editForm.purchaser" placeholder="请输入采购员" /> |
| | | </view> |
| | | </scroll-view> |
| | | <view class="popup-footer"> |
| | | <view class="btn-cancel" @click="showEditModal = false">取消</view> |
| | | <view class="btn-ok" @click="handleEditSubmit">确认</view> |
| | | </view> |
| | | </view> |
| | | </up-popup> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { reactive, ref, toRefs, watch } from "vue"; |
| | | import { computed, reactive, ref, toRefs } from "vue"; |
| | | import { onReachBottom, onShow } from "@dcloudio/uni-app"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import request from "@/utils/request"; |
| | | import { findAllQualifiedStockInRecordTypeOptions, findAllUnQualifiedStockInRecordTypeOptions } from "@/api/basicData/enum.js"; |
| | | import { findAllQualifiedStockInRecordTypeOptions } from "@/api/basicData/enum.js"; |
| | | import { checkPermi } from "@/utils/permission"; |
| | | import { editStockInStock } from "@/api/consumablesLogistics/consumablesInRecord.js"; |
| | | |
| | | const activeTab = ref("qualified"); |
| | | const hasCReceiptEdit = computed(() => checkPermi(['c_receipt_edit'])) |
| | | const hasCReceiptCancel = computed(() => checkPermi(['c_receipt_cancel'])) |
| | | |
| | | const stockRecordTypeOptions = ref([]); |
| | | const tabs = [ |
| | | { label: "合格入库", name: "qualified", type: "0" }, |
| | | { label: "不合格入库", name: "unqualified", type: "1" }, |
| | | ]; |
| | | const tableData = ref([]); |
| | | const total = ref(0); |
| | | const loadStatus = ref("loadmore"); |
| | | const page = reactive({ current: 1, size: 4 }); |
| | | const data = reactive({ searchForm: { productName: "" } }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | const currentType = () => tabs.find((t) => t.name === activeTab.value)?.type || "0"; |
| | | const currentType = () => "0"; |
| | | |
| | | function getRecordType(recordType) { |
| | | if (recordType == null || recordType === "") return ""; |
| | |
| | | } |
| | | |
| | | function fetchRecordTypeOptions() { |
| | | const api = |
| | | currentType() === "1" |
| | | ? findAllUnQualifiedStockInRecordTypeOptions |
| | | : findAllQualifiedStockInRecordTypeOptions; |
| | | api() |
| | | findAllQualifiedStockInRecordTypeOptions() |
| | | .then((res) => { |
| | | const data = res.data != null ? res.data : res; |
| | | stockRecordTypeOptions.value = Array.isArray(data) ? data : []; |
| | |
| | | getList(); |
| | | }; |
| | | |
| | | watch(activeTab, () => { |
| | | page.current = 1; |
| | | loadStatus.value = "loadmore"; |
| | | stockRecordTypeOptions.value = []; |
| | | getList(); |
| | | }); |
| | | |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | loadStatus.value = "loadmore"; |
| | |
| | | "receiptDetailItem", |
| | | JSON.stringify({ |
| | | item, |
| | | type: currentType(), |
| | | type: "0", |
| | | }) |
| | | ); |
| | | } catch (e) {} |
| | |
| | | |
| | | const handleDeleteSingle = (item) => { |
| | | if (!item?.id) return; |
| | | if (!hasCReceiptCancel.value) return |
| | | uni.showModal({ |
| | | title: "删除", |
| | | content: "确认删除该条入库记录?", |
| | |
| | | }); |
| | | }; |
| | | |
| | | // ---------------- 编辑入库 ---------------- |
| | | const showEditModal = ref(false) |
| | | const editForm = reactive({ |
| | | id: null, |
| | | qualitity: '', |
| | | purchaser: '' |
| | | }) |
| | | |
| | | const handleEdit = (row) => { |
| | | if (!hasCReceiptEdit.value) return |
| | | editForm.id = row?.id ?? null |
| | | editForm.qualitity = row?.qualitity ?? row?.stockInNum ?? '' |
| | | editForm.purchaser = row?.purchaser ?? '' |
| | | showEditModal.value = true |
| | | } |
| | | |
| | | const handleEditSubmit = () => { |
| | | if (!hasCReceiptEdit.value) return |
| | | const q = Number(editForm.qualitity) |
| | | if (!Number.isFinite(q) || q <= 0) { |
| | | uni.showToast({ title: "请输入正确数量", icon: "none" }) |
| | | return |
| | | } |
| | | if (!editForm.purchaser) { |
| | | uni.showToast({ title: "请输入采购员", icon: "none" }) |
| | | return |
| | | } |
| | | |
| | | uni.showLoading({ title: "保存中...", mask: true }) |
| | | editStockInStock({ |
| | | id: editForm.id, |
| | | qualitity: q, |
| | | purchaser: editForm.purchaser |
| | | }) |
| | | .then(() => { |
| | | uni.showToast({ title: "编辑成功", icon: "success" }) |
| | | showEditModal.value = false |
| | | getList() |
| | | }) |
| | | .catch(() => { |
| | | uni.showToast({ title: "编辑失败", icon: "none" }) |
| | | }) |
| | | .finally(() => { |
| | | uni.hideLoading() |
| | | }) |
| | | } |
| | | |
| | | const goBack = () => uni.navigateBack(); |
| | | |
| | | onShow(() => { |
| | |
| | | |
| | | <style lang="scss" scoped> |
| | | .receipt-page { min-height: 100vh; background: #f5f5f5; padding-bottom: 40rpx; } |
| | | .tabs-wrap { display: flex; background: #fff; padding: 24rpx; gap: 24rpx; } |
| | | .tab-item { flex: 1; text-align: center; padding: 20rpx; border-radius: 12rpx; background: #f0f0f0; font-size: 28rpx; color: #666; } |
| | | .tab-item.active { background: #2979ff; color: #fff; } |
| | | .search-section { background: #fff; margin: 24rpx; padding: 24rpx; border-radius: 16rpx; } |
| | | .search-row { display: flex; align-items: center; } |
| | | .search-input-wrap { flex: 1; margin-right: 20rpx; min-width: 0; } |
| | |
| | | .card-body .l { color: #666; } |
| | | .card-body .r { color: #333; } |
| | | .card-body .r.highlight { color: #2979ff; font-weight: 500; } |
| | | .card-actions { display: flex; justify-content: flex-end; margin-top: 12rpx; } |
| | | .btn-delete { color: #f56c6c; font-size: 28rpx; } |
| | | .card-actions { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | margin-top: 16rpx; |
| | | padding-top: 16rpx; |
| | | border-top: 1rpx solid #eee; |
| | | width: 100%; |
| | | text-align: center; |
| | | } |
| | | .btn-edit { |
| | | color: #2979ff; |
| | | font-size: 28rpx; |
| | | padding: 12rpx 32rpx; |
| | | border-radius: 999rpx; |
| | | border: 1rpx solid rgba(41, 121, 255, 0.25); |
| | | background: rgba(41, 121, 255, 0.06); |
| | | margin: 0 auto; |
| | | display: inline-flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | .btn-delete { |
| | | color: #f56c6c; |
| | | font-size: 28rpx; |
| | | padding: 12rpx 32rpx; |
| | | border-radius: 999rpx; |
| | | border: 1rpx solid rgba(245, 108, 108, 0.55); |
| | | background: rgba(245, 108, 108, 0.08); |
| | | margin: 0 auto; |
| | | display: inline-flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | /* 编辑弹窗样式 */ |
| | | .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; |
| | | } |
| | | .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; |
| | | } |
| | | .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; |
| | | } |
| | | .no-data { text-align: center; padding: 60rpx 0; color: #999; font-size: 28rpx; } |
| | | .load-more-wrap { padding: 24rpx 24rpx 8rpx; } |
| | | </style> |