| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request' |
| | | |
| | | // èæå
¥åºç®¡ç-æ¥è¯¢å
¥åºè®°å½å表 |
| | | export const getConsumablesInRecordListPage = (params) => { |
| | | return request({ |
| | | url: '/consumablesInRecord/listPage', |
| | | method: 'get', |
| | | params |
| | | }) |
| | | } |
| | | |
| | | // ç¼è¾èæå
¥åºï¼ä»
ç¨äºå°è´¦ç¼è¾ï¼ |
| | | export const editStockInStock = (data) => { |
| | | return request({ |
| | | url: '/consumablesInRecord/editStockInStock', |
| | | method: 'post', |
| | | data |
| | | }) |
| | | } |
| | | |
| | | // æ¹éå é¤å
¥åºè®°å½ |
| | | export const batchDeleteConsumablesInRecords = (ids) => { |
| | | return request({ |
| | | url: '/consumablesInRecord', |
| | | method: 'delete', |
| | | data: ids |
| | | }) |
| | | } |
| | | |
| | |
| | | }); |
| | | }; |
| | | |
| | | // ç¼è¾èæåºåºï¼ä»
ç¨äºå°è´¦ç¼è¾ï¼ |
| | | export const editStockOut = (data) => { |
| | | return request({ |
| | | url: "/consumablesOutRecord/editStockOut", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | }; |
| | | |
| | |
| | | </view> |
| | | </view> |
| | | <view class="card-actions"> |
| | | <view class="btn-delete" @click.stop="handleDeleteSingle(item)">å é¤</view> |
| | | <view v-if="hasCDispatchEdit" class="btn-edit" @click.stop="handleEdit(item)">ç¼è¾</view> |
| | | <view v-if="hasCDispatchCancel" 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> |
| | | </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 } from "vue"; |
| | | import { computed, reactive, ref, toRefs } from "vue"; |
| | | import { onReachBottom, onShow } from "@dcloudio/uni-app"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { getConsumablesOutRecordPage, delConsumablesOutRecord } from "@/api/consumablesLogistics/consumablesOutRecord.js"; |
| | | import { getConsumablesOutRecordPage, delConsumablesOutRecord, editStockOut } from "@/api/consumablesLogistics/consumablesOutRecord.js"; |
| | | import { findAllQualifiedStockOutRecordTypeOptions } from "@/api/basicData/enum.js"; |
| | | import { checkPermi } from "@/utils/permission"; |
| | | |
| | | const hasCDispatchEdit = computed(() => checkPermi(["c_dispatch_edit"])); |
| | | const hasCDispatchCancel = computed(() => checkPermi(["c_dispatch_cancel"])); |
| | | |
| | | const stockRecordTypeOptions = ref([]); |
| | | const tableData = ref([]); |
| | |
| | | |
| | | const handleDeleteSingle = (item) => { |
| | | if (!item?.id) return; |
| | | if (!hasCDispatchCancel.value) return; |
| | | uni.showModal({ |
| | | title: "å é¤", |
| | | content: "确认å é¤è¯¥æ¡åºåºè®°å½ï¼", |
| | |
| | | }); |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | // ---------------- ç¼è¾åºåº ---------------- |
| | | const showEditModal = ref(false); |
| | | const editForm = reactive({ |
| | | id: null, |
| | | qualitity: "", |
| | | }); |
| | | |
| | | const handleEdit = (row) => { |
| | | if (!hasCDispatchEdit.value) return; |
| | | editForm.id = row?.id ?? null; |
| | | editForm.qualitity = row?.qualitity ?? row?.stockOutNum ?? ""; |
| | | showEditModal.value = true; |
| | | }; |
| | | |
| | | const handleEditSubmit = () => { |
| | | if (!hasCDispatchEdit.value) return; |
| | | const q = Number(editForm.qualitity); |
| | | if (!Number.isFinite(q) || q <= 0) { |
| | | uni.showToast({ title: "请è¾å
¥æ£ç¡®æ°é", icon: "none" }); |
| | | return; |
| | | } |
| | | uni.showLoading({ title: "ä¿åä¸...", mask: true }); |
| | | editStockOut({ |
| | | id: editForm.id, |
| | | qualitity: q, |
| | | }) |
| | | .then(() => { |
| | | uni.showToast({ title: "ç¼è¾æå", icon: "success" }); |
| | | showEditModal.value = false; |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | uni.showToast({ title: "ç¼è¾å¤±è´¥", icon: "none" }); |
| | | }) |
| | | .finally(() => { |
| | | uni.hideLoading(); |
| | | }); |
| | | }; |
| | | |
| | | const goBack = () => uni.navigateBack(); |
| | |
| | | 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; |
| | | margin: 0 auto; |
| | | display: inline-flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | .btn-delete { |
| | | color: #f56c6c; |
| | | font-size: 28rpx; |
| | | padding: 12rpx 36rpx; |
| | | padding: 12rpx 32rpx; |
| | | 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; |
| | | border: 1rpx solid rgba(245, 108, 108, 0.55); |
| | | background: rgba(245, 108, 108, 0.08); |
| | | 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; } |
| | |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px">æç´¢</el-button> |
| | | </div> |
| | | <div> |
| | | <el-button type="danger" plain @click="handleDelete">å é¤</el-button> |
| | | <el-button |
| | | v-if="hasCReceiptCancel" |
| | | type="danger" |
| | | plain |
| | | @click="handleDelete" |
| | | >å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | |
| | |
| | | <el-table-column label="产ååç§°" prop="productName" min-width="160" show-overflow-tooltip /> |
| | | <el-table-column label="è§æ ¼åå·" prop="model" min-width="160" show-overflow-tooltip /> |
| | | <el-table-column label="åä½" prop="unit" width="100" show-overflow-tooltip /> |
| | | <el-table-column label="å
¥åºæ°é" prop="stockInNum" width="110" show-overflow-tooltip /> |
| | | <el-table-column label="å
¥åºæ°é" prop="qualitity" width="110" show-overflow-tooltip /> |
| | | <el-table-column label="å
¥åºäºº" prop="createBy" width="120" show-overflow-tooltip /> |
| | | <el-table-column label="æ¥æº" prop="recordType" width="140" show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | {{ getRecordType(scope.row.recordType) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" width="120" align="center"> |
| | | <template #default="scope"> |
| | | <el-button |
| | | v-if="hasCReceiptEdit" |
| | | type="primary" |
| | | size="mini" |
| | | @click="handleEdit(scope.row)" |
| | | >ç¼è¾</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | @pagination="paginationChange" |
| | | /> |
| | | </div> |
| | | |
| | | <el-dialog |
| | | v-model="isShowEditModal" |
| | | title="ç¼è¾å
¥åº" |
| | | width="600" |
| | | @close="closeEditModal" |
| | | > |
| | | <el-form |
| | | label-width="100px" |
| | | :model="editForm" |
| | | label-position="top" |
| | | ref="editFormRef" |
| | | > |
| | | <el-form-item |
| | | label="æ°é" |
| | | prop="qualitity" |
| | | :rules="[{ required: true, message: '请è¾å
¥æ°é', trigger: ['blur', 'change'] }]" |
| | | > |
| | | <el-input-number |
| | | v-model="editForm.qualitity" |
| | | :min="0" |
| | | :step="1" |
| | | :precision="0" |
| | | controls-position="right" |
| | | style="width: 100%" |
| | | placeholder="请è¾å
¥æ°é" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="éè´å" |
| | | prop="purchaser" |
| | | :rules="[{ required: true, message: '请è¾å
¥éè´å', trigger: ['blur', 'change'] }]" |
| | | > |
| | | <el-input v-model="editForm.purchaser" placeholder="请è¾å
¥éè´å" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="handleEditSubmit">确认</el-button> |
| | | <el-button @click="closeEditModal">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { onMounted, reactive, ref, toRefs, watch } from "vue"; |
| | | import { computed, onMounted, reactive, ref, toRefs, watch } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import Pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { |
| | | batchDeleteConsumablesInRecords, |
| | | getConsumablesInRecordListPage, |
| | | editStockInStock, |
| | | } from "@/api/consumablesLogistics/consumablesInRecord.js"; |
| | | import { |
| | | findAllQualifiedStockInRecordTypeOptions, |
| | | } from "@/api/basicData/enum.js"; |
| | | import { checkPermi } from "@/utils/permission.js"; |
| | | |
| | | const props = defineProps({ |
| | | type: { |
| | |
| | | default: "0", |
| | | }, |
| | | }); |
| | | |
| | | const hasCReceiptEdit = computed(() => checkPermi(['c_receipt_edit'])) |
| | | const hasCReceiptCancel = computed(() => checkPermi(['c_receipt_cancel'])) |
| | | |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | |
| | | }; |
| | | |
| | | const handleDelete = () => { |
| | | if (!hasCReceiptCancel.value) return |
| | | const ids = selectedRows.value.map(i => i.id).filter(Boolean); |
| | | if (ids.length === 0) { |
| | | ElMessage.warning("è¯·éæ©æ°æ®"); |
| | |
| | | .catch(() => {}); |
| | | }; |
| | | |
| | | // ç¼è¾å
¥åº |
| | | const isShowEditModal = ref(false); |
| | | const editFormRef = ref(null); |
| | | const editForm = ref({}); |
| | | |
| | | const handleEdit = (row) => { |
| | | if (!hasCReceiptEdit.value) return |
| | | editForm.value = { |
| | | id: row?.id, |
| | | qualitity: row?.qualitity, |
| | | purchaser: row?.purchaser, |
| | | }; |
| | | isShowEditModal.value = true; |
| | | }; |
| | | |
| | | const closeEditModal = () => { |
| | | isShowEditModal.value = false; |
| | | editForm.value = {}; |
| | | editFormRef.value?.clearValidate?.(); |
| | | }; |
| | | |
| | | const handleEditSubmit = () => { |
| | | editFormRef.value?.validate?.((valid) => { |
| | | if (!valid) return; |
| | | editStockInStock(editForm.value).then(() => { |
| | | closeEditModal(); |
| | | ElMessage.success("ç¼è¾æå"); |
| | | getList(); |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | watch( |
| | | () => props.type, |
| | | () => { |
| | |
| | | <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 } 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 } from "@/api/basicData/enum.js"; |
| | | import { checkPermi } from "@/utils/permission"; |
| | | import { editStockInStock } from "@/api/consumablesLogistics/consumablesInRecord.js"; |
| | | |
| | | const hasCReceiptEdit = computed(() => checkPermi(['c_receipt_edit'])) |
| | | const hasCReceiptCancel = computed(() => checkPermi(['c_receipt_cancel'])) |
| | | |
| | | const stockRecordTypeOptions = ref([]); |
| | | const tableData = ref([]); |
| | |
| | | |
| | | 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(); |
| | | |
| | |
| | | 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 36rpx; |
| | | 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; } |
| | |
| | | </view> |
| | | <view class="detail-row detail-row-highlight"> |
| | | <text class="label">å
¥åºæ°é</text> |
| | | <text class="value value-num">{{ detail.stockInNum ?? '-' }}</text> |
| | | <text class="value value-num">{{ detail.qualitity ?? detail.stockInNum ?? '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="label">å
¥åºäºº</text> |
| | |
| | | model: d.model, |
| | | unit: d.unit, |
| | | stockInNum: d.stockInNum, |
| | | qualitity: d.qualitity, |
| | | createBy: d.createBy, |
| | | recordType: d.recordType, |
| | | purchaser: d.purchaser, |
| | |
| | | <text>{{ t.label }}</text> |
| | | </view> |
| | | </view> |
| | | <!-- æ¶é´éæ©åºå --> |
| | | <view class="search-section"> |
| | | <!-- æ¥æ¥ï¼éæ©å¹´ææ¥ --> |
| | | <view v-if="searchForm.reportType === 'daily'" class="search-row"> |
| | | <view class="date-picker" @click="openDatePicker('single')"> |
| | | <text>{{ searchForm.singleDate || 'è¯·éæ©æ¥æ' }}</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- ææ¥ï¼éæ©å¹´æ --> |
| | | <view v-else-if="searchForm.reportType === 'monthly'" class="search-row"> |
| | | <view class="date-picker" @click="openDatePicker('startMonth')"> |
| | | <text>{{ searchForm.startMonth || 'è¯·éæ©å¼å§æä»½' }}</text> |
| | | </view> |
| | | ~ |
| | | <view class="date-picker" @click="openDatePicker('endMonth')"> |
| | | <text>{{ searchForm.endMonth || 'è¯·éæ©ç»ææä»½' }}</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- è¿åºåï¼éæ©å¹´ææ¥æ¶é´èå´ --> |
| | | <view v-else-if="searchForm.reportType === 'inout'" class="search-row"> |
| | | <view class="date-picker" @click="openDatePicker('startDate')"> |
| | | <text>{{ searchForm.startDate || 'è¯·éæ©å¼å§æ¥æ' }}</text> |
| | | </view> |
| | | ~ |
| | | <view class="date-picker" @click="openDatePicker('endDate')"> |
| | | <text>{{ searchForm.endDate || 'è¯·éæ©ç»ææ¥æ' }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view class="list-section"> |
| | | <view class="section-header"> |
| | | <text class="table-title">{{ tableTitle }}</text> |
| | |
| | | </view> |
| | | <view v-else class="no-data">ææ æ°æ®</view> |
| | | </view> |
| | | <up-popup :show="showDatePicker" mode="bottom" @close="showDatePicker = false"> |
| | | <up-datetime-picker |
| | | v-model="dateValue" |
| | | :mode="datePickerMode" |
| | | @confirm="onDateConfirm" |
| | | @cancel="showDatePicker = false" |
| | | /> |
| | | </up-popup> |
| | | <up-datetime-picker |
| | | v-model="dateValue" |
| | | :mode="datePickerMode" |
| | | :show="showDatePicker" |
| | | @confirm="onDateConfirm" |
| | | @cancel="showDatePicker = false" |
| | | /> |
| | | </view> |
| | | </template> |
| | | |
| | |
| | | import { ref, reactive, toRefs, computed, watch } from "vue"; |
| | | import dayjs from "dayjs"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { formatDateToYMD } from "@/utils/ruoyi"; |
| | | import { onShow, onReachBottom } from "@dcloudio/uni-app"; |
| | | import { getConsumablesInReportList, getConsumablesInInAndOutReportList } from "@/api/consumablesLogistics/consumablesIn.js"; |
| | | import { |
| | |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | const datePickerMode = computed(() => { |
| | | if (datePickerTarget.value === "startMonth" || datePickerTarget.value === "endMonth") return "month"; |
| | | if (datePickerTarget.value === "startMonth" || datePickerTarget.value === "endMonth") return "year-month"; |
| | | return "date"; |
| | | }); |
| | | |
| | |
| | | if (searchForm.value.reportType === "daily") { |
| | | p.reportDate = searchForm.value.singleDate; |
| | | } else if (searchForm.value.reportType === "monthly") { |
| | | p.startMonth = searchForm.value.startMonth; |
| | | p.endMonth = searchForm.value.endMonth; |
| | | } else if (searchForm.value.reportType === "monthly") { |
| | | p.startMonth = searchForm.value.startMonth; |
| | | p.endMonth = searchForm.value.endMonth; |
| | | p.startMonth = searchForm.value.startMonth ? `${searchForm.value.startMonth}-01` : ""; |
| | | p.endMonth = searchForm.value.endMonth ? `${searchForm.value.endMonth}-01` : ""; |
| | | } else { |
| | | p.startDate = searchForm.value.startDate; |
| | | p.endDate = searchForm.value.endDate; |
| | |
| | | getList(); |
| | | }; |
| | | |
| | | const toPickerTimestamp = (val, target) => { |
| | | if (!val) return Date.now(); |
| | | let parsed; |
| | | if (target === "startMonth" || target === "endMonth") { |
| | | parsed = dayjs(`${val}-01`).valueOf(); |
| | | } else { |
| | | parsed = dayjs(val).valueOf(); |
| | | } |
| | | return Number.isNaN(parsed) ? Date.now() : parsed; |
| | | }; |
| | | |
| | | const formatPickerDate = (value, isMonth) => { |
| | | const parsed = dayjs(value); |
| | | if (!parsed.isValid()) return ""; |
| | | return parsed.format(isMonth ? "YYYY-MM" : "YYYY-MM-DD"); |
| | | }; |
| | | |
| | | const openDatePicker = (target) => { |
| | | datePickerTarget.value = target; |
| | | let val = ""; |
| | | if (target === "single") val = searchForm.value.singleDate; |
| | | else if (target === "startMonth") val = searchForm.value.startMonth; |
| | | else if (target === "endMonth") val = searchForm.value.endMonth; |
| | | dateValue.value = val ? new Date(val).getTime() : Date.now(); |
| | | else if (target === "startDate") val = searchForm.value.startDate; |
| | | else if (target === "endDate") val = searchForm.value.endDate; |
| | | dateValue.value = toPickerTimestamp(val, target); |
| | | showDatePicker.value = true; |
| | | }; |
| | | |
| | | const onDateConfirm = (e) => { |
| | | const isMonth = datePickerTarget.value === "startMonth" || datePickerTarget.value === "endMonth"; |
| | | const str = isMonth ? dayjs(e.value).format("YYYY-MM") : formatDateToYMD(e.value); |
| | | if (datePickerTarget.value === "single") searchForm.value.singleDate = str; |
| | | else if (datePickerTarget.value === "startMonth") searchForm.value.startMonth = str; |
| | | else if (datePickerTarget.value === "endMonth") searchForm.value.endMonth = str; |
| | | showDatePicker.value = false; |
| | | handleQuery(); |
| | | const str = formatPickerDate(e.value, isMonth); |
| | | if (!str) { |
| | | showDatePicker.value = false; |
| | | uni.showToast({ title: "æ¥ææ ¼å¼æ æ", icon: "none" }); |
| | | return; |
| | | } |
| | | if (datePickerTarget.value === "single") { |
| | | searchForm.value.singleDate = str; |
| | | showDatePicker.value = false; |
| | | handleQuery(); |
| | | } else if (datePickerTarget.value === "startMonth") { |
| | | searchForm.value.startMonth = str; |
| | | showDatePicker.value = false; |
| | | setTimeout(() => { |
| | | openDatePicker("endMonth"); |
| | | }, 300); |
| | | } else if (datePickerTarget.value === "endMonth") { |
| | | searchForm.value.endMonth = str; |
| | | showDatePicker.value = false; |
| | | handleQuery(); |
| | | } else if (datePickerTarget.value === "startDate") { |
| | | searchForm.value.startDate = str; |
| | | showDatePicker.value = false; |
| | | setTimeout(() => { |
| | | openDatePicker("endDate"); |
| | | }, 300); |
| | | } else if (datePickerTarget.value === "endDate") { |
| | | searchForm.value.endDate = str; |
| | | showDatePicker.value = false; |
| | | handleQuery(); |
| | | } |
| | | }; |
| | | |
| | | const initDefaultDates = () => { |
| | |
| | | searchForm.value.singleDate = today.format("YYYY-MM-DD"); |
| | | } |
| | | if (!searchForm.value.startMonth || !searchForm.value.endMonth) { |
| | | const startOfMonth = today.startOf("month").format("YYYY-MM-DD"); |
| | | const endOfMonth = today.endOf("month").format("YYYY-MM-DD"); |
| | | searchForm.value.startMonth = startOfMonth; |
| | | searchForm.value.endMonth = endOfMonth; |
| | | searchForm.value.startMonth = today.format("YYYY-MM"); |
| | | searchForm.value.endMonth = today.add(1, "month").format("YYYY-MM"); |
| | | } |
| | | if (!searchForm.value.startDate || !searchForm.value.endDate) { |
| | | searchForm.value.endDate = today.format("YYYY-MM-DD"); |
| | | searchForm.value.startDate = today.subtract(6, "day").format("YYYY-MM-DD"); |
| | | } |
| | | if (!datePickerTarget.value) { |
| | | dateValue.value = toPickerTimestamp(searchForm.value.singleDate, "single"); |
| | | } |
| | | }; |
| | | |
| | |
| | | fetchStockRecordTypeOptions(); |
| | | }); |
| | | |
| | | initDefaultDates(); |
| | | |
| | | onReachBottom(() => loadMore()); |
| | | |
| | | const goBack = () => uni.navigateBack(); |
| | |
| | | <view v-else class="no-data">ææ æ°æ®</view> |
| | | </view> |
| | | |
| | | <up-popup :show="showDatePicker" mode="bottom" @close="showDatePicker = false"> |
| | | <up-datetime-picker |
| | | v-model="dateValue" |
| | | :mode="datePickerMode" |
| | | :show="showDatePicker" |
| | | @confirm="onDateConfirm" |
| | | @cancel="showDatePicker = false" |
| | | /> |
| | | </up-popup> |
| | | <up-datetime-picker |
| | | v-model="dateValue" |
| | | :mode="datePickerMode" |
| | | :show="showDatePicker" |
| | | @confirm="onDateConfirm" |
| | | @cancel="showDatePicker = false" |
| | | /> |
| | | </view> |
| | | </template> |
| | | |
| | |
| | | import { ref, reactive, toRefs, computed, watch } from 'vue' |
| | | import dayjs from 'dayjs' |
| | | import PageHeader from '@/components/PageHeader.vue' |
| | | import { formatDateToYMD } from '@/utils/ruoyi' |
| | | import { onShow } from '@dcloudio/uni-app' |
| | | import { |
| | | getStockInventoryReportList, |
| | |
| | | getList() |
| | | } |
| | | |
| | | const toPickerTimestamp = (val, target) => { |
| | | if (!val) return Date.now() |
| | | let parsed |
| | | if (target === 'startMonth' || target === 'endMonth') { |
| | | parsed = dayjs(`${val}-01`).valueOf() |
| | | } else { |
| | | parsed = dayjs(val).valueOf() |
| | | } |
| | | return Number.isNaN(parsed) ? Date.now() : parsed |
| | | } |
| | | |
| | | const formatPickerDate = (value, isMonth) => { |
| | | const parsed = dayjs(value) |
| | | if (!parsed.isValid()) return '' |
| | | return parsed.format(isMonth ? 'YYYY-MM' : 'YYYY-MM-DD') |
| | | } |
| | | |
| | | const openDatePicker = (target) => { |
| | | let val = '' |
| | | datePickerTarget.value = target |
| | |
| | | val = searchForm.value.endDate |
| | | break |
| | | } |
| | | dateValue.value = val ? new Date(val).getTime() : Date.now() |
| | | dateValue.value = toPickerTimestamp(val, target) |
| | | showDatePicker.value = true |
| | | } |
| | | |
| | | const onDateConfirm = (e) => { |
| | | const isMonth = datePickerTarget.value === 'startMonth' || datePickerTarget.value === 'endMonth' |
| | | const str = isMonth ? dayjs(e.value).format('YYYY-MM') : formatDateToYMD(e.value) |
| | | const str = formatPickerDate(e.value, isMonth) |
| | | if (!str) { |
| | | showDatePicker.value = false |
| | | uni.showToast({ title: 'æ¥ææ ¼å¼æ æ', icon: 'none' }) |
| | | return |
| | | } |
| | | |
| | | if (datePickerTarget.value === 'single') { |
| | | searchForm.value.singleDate = str |
| | |
| | | searchForm.value.endDate = today.format('YYYY-MM-DD') |
| | | searchForm.value.startDate = today.subtract(6, 'day').format('YYYY-MM-DD') |
| | | } |
| | | if (!datePickerTarget.value) { |
| | | dateValue.value = toPickerTimestamp(searchForm.value.singleDate, 'single') |
| | | } |
| | | } |
| | | |
| | | watch( |
| | |
| | | fetchStockRecordTypeOptions() |
| | | }) |
| | | |
| | | initDefaultDates() |
| | | |
| | | const goBack = () => uni.navigateBack() |
| | | </script> |
| | | |
| | |
| | | id: d.id, |
| | | productId: d.productId, |
| | | productName: d.productName, |
| | | productModelId: d.productModelId, |
| | | productModelId: d.productModelId ?? d.modelId ?? d.productModeId ?? '', |
| | | model: d.model, |
| | | unit: d.unit, |
| | | batchNo: d.batchNo, |
| | |
| | | |
| | | const validate = () => { |
| | | if (!form.productId) return toast('è¯·éæ©äº§ååç§°'), false |
| | | if (!form.productModelId) return toast('è¯·éæ©è§æ ¼åå·'), false |
| | | // å¯¹é½ PC 端ï¼ç¼è¾æå
许ä»
åæ¾åå·ææ¬ï¼å岿°æ®å¯è½ç¼ºå° productModelIdï¼ |
| | | if (!isEdit.value && !form.productModelId) return toast('è¯·éæ©è§æ ¼åå·'), false |
| | | if (isEdit.value && !form.productModelId && !form.model) return toast('è¯·éæ©è§æ ¼åå·'), false |
| | | if (!form.batchNo) return toast('请è¾å
¥æ¹å·'), false |
| | | if (form.checkType === undefined || form.checkType === '') return toast('è¯·éæ©æ£éªç±»å'), false |
| | | if (!form.checkName) return toast('è¯·éæ©æ£éªå'), false |
| | |
| | | </view> |
| | | <view class="card-actions"> |
| | | <view class="btn-link btn-link-primary" v-if="item.inspectState == 0" @click.stop="openDealDialog(item)">å¤ç</view> |
| | | <view class="btn-link btn-link-plain" v-if="item.inspectState == 0" @click.stop="openForm('edit', item)">ç¼è¾</view> |
| | | <view class="btn-link btn-link-warn" v-if="item.inspectState == 0" @click.stop="handleDelete(item)">å é¤</view> |
| | | <view class="btn-link btn-link-plain" v-if="hasNonconformingEdit" @click.stop="openForm('edit', item)">ç¼è¾</view> |
| | | <view class="btn-link btn-link-warn" v-if="hasNonconformingCancel" @click.stop="handleDelete(item)">å é¤</view> |
| | | </view> |
| | | </view> |
| | | <view class="load-more-wrap"> |
| | |
| | | <up-datetime-picker |
| | | :show="showEntryStartPicker" |
| | | v-model="entryStartValue" |
| | | mode="date" |
| | | mode="year-month" |
| | | @confirm="confirmEntryStart" |
| | | @cancel="showEntryStartPicker = false" |
| | | /> |
| | |
| | | <up-datetime-picker |
| | | :show="showEntryEndPicker" |
| | | v-model="entryEndValue" |
| | | mode="date" |
| | | mode="year-month" |
| | | @confirm="confirmEntryEnd" |
| | | @cancel="showEntryEndPicker = false" |
| | | /> |
| | |
| | | import dayjs from 'dayjs'; |
| | | import PageHeader from '@/components/PageHeader.vue' |
| | | import { onReachBottom, onShow } from '@dcloudio/uni-app' |
| | | import { checkPermi } from '@/utils/permission' |
| | | |
| | | const hasNonconformingEdit = computed(() => checkPermi(['nonconforming_edit'])) |
| | | const hasNonconformingCancel = computed(() => checkPermi(['nonconforming_cancel'])) |
| | | |
| | | const searchForm = reactive({ |
| | | productName: '', |
| | |
| | | }; |
| | | |
| | | const openDateRange = () => { |
| | | entryStartValue.value = searchForm.entryDateStart ? dayjs(searchForm.entryDateStart, 'YYYY-MM-DD').valueOf() : Date.now() |
| | | entryStartValue.value = searchForm.entryDateStart ? dayjs(searchForm.entryDateStart).valueOf() : Date.now() |
| | | showEntryStartPicker.value = true |
| | | } |
| | | const confirmEntryStart = (e) => { |
| | | const ts = e?.value ?? entryStartValue.value |
| | | searchForm.entryDateStart = dayjs(ts).format('YYYY-MM-DD') |
| | | searchForm.entryDateStart = `${dayjs(ts).format('YYYY-MM')}-01` |
| | | showEntryStartPicker.value = false |
| | | entryEndValue.value = searchForm.entryDateEnd ? dayjs(searchForm.entryDateEnd, 'YYYY-MM-DD').valueOf() : Date.now() |
| | | entryEndValue.value = searchForm.entryDateEnd ? dayjs(searchForm.entryDateEnd).valueOf() : Date.now() |
| | | showEntryEndPicker.value = true |
| | | } |
| | | const confirmEntryEnd = (e) => { |
| | | const ts = e?.value ?? entryEndValue.value |
| | | searchForm.entryDateEnd = dayjs(ts).format('YYYY-MM-DD') |
| | | searchForm.entryDateEnd = `${dayjs(ts).format('YYYY-MM')}-01` |
| | | showEntryEndPicker.value = false |
| | | handleQuery() |
| | | } |
| | |
| | | }; |
| | | |
| | | const handleDelete = (row) => { |
| | | if (!hasNonconformingCancel.value) return |
| | | showConfirm('确认å é¤è¯¥ä¸åæ ¼è®°å½åï¼').then(async res => { |
| | | if (!res.confirm) return |
| | | await qualityUnqualifiedDel([row.id]) |
| | |
| | | }; |
| | | |
| | | const openForm = (type, row) => { |
| | | if (type === 'edit' && !hasNonconformingEdit.value) return |
| | | if (type !== 'add' && row?.inspectState == 1) { |
| | | toast('å·²å¤ççæ°æ®ä¸è½åç¼è¾') |
| | | return |
| | |
| | | <up-button v-if="item.inspectState != 1" type="primary" size="mini" @click.stop="openForm('edit', item)">ç¼è¾</up-button> |
| | | <up-button type="info" size="mini" @click.stop="openFiles(item)">éä»¶</up-button> |
| | | <up-button v-if="item.inspectState != 1" type="success" size="mini" @click.stop="handleConfirmSubmit(item)">æäº¤</up-button> |
| | | <up-button type="error" size="mini" @click.stop="handleDelete(item)">å é¤</up-button> |
| | | <up-button v-if="hasRawCancel" type="error" size="mini" @click.stop="handleDelete(item)">å é¤</up-button> |
| | | </view> |
| | | </view> |
| | | <view class="pagination-container"> |
| | |
| | | } from '@/api/qualityManagement/rawMaterial.js'; |
| | | import { toast, showConfirm } from '@/utils/common'; |
| | | import useUserStore from '@/store/modules/user'; |
| | | import { checkPermi } from '@/utils/permission'; |
| | | |
| | | const userStore = useUserStore(); |
| | | const hasRawCancel = computed(() => checkPermi(['raw_cancel'])); |
| | | |
| | | const searchForm = reactive({ |
| | | batchNo: '', |
| | |
| | | }; |
| | | |
| | | const openForm = (type, item) => { |
| | | if (type === 'edit' && !hasRawEdit.value) return |
| | | const id = item?.id |
| | | uni.navigateTo({ |
| | | url: `/pages/qualityManagement/rawMaterial/form?type=${type}${id ? `&id=${id}` : ''}` |
| | |
| | | }; |
| | | |
| | | const handleDelete = (row) => { |
| | | if (!hasRawCancel.value) return |
| | | showConfirm('确认å é¤è¯¥è®°å½åï¼').then(res => { |
| | | if (res.confirm) { |
| | | // å¯¹é½ PC 端ï¼å 餿¥å£æ¥æ¶ id æ°ç» |
| | |
| | | let date; |
| | | // å¤çï¼å¦ææ¯æ¶é´æ³ï¼å
转为Date对象 |
| | | if (typeof dateSource === 'number') { |
| | | date = new Date(dateSource); |
| | | const timestamp = dateSource.toString().length === 10 ? dateSource * 1000 : dateSource; |
| | | date = new Date(timestamp); |
| | | } |
| | | // å¤çï¼å¦ææ¯Date对象ï¼ç´æ¥ä½¿ç¨ |
| | | else if (dateSource instanceof Date) { |
| | | date = dateSource; |
| | | } |
| | | // å¤çï¼å¦ææ¯å符串ï¼åå
¼å®¹è½¬æ¢ |
| | | else if (typeof dateSource === 'string') { |
| | | const raw = dateSource.trim(); |
| | | if (!raw) return ''; |
| | | if (/^[0-9]+$/.test(raw)) { |
| | | const n = parseInt(raw, 10); |
| | | const timestamp = raw.length === 10 ? n * 1000 : n; |
| | | date = new Date(timestamp); |
| | | } else { |
| | | // iOS / é¨å WebView 对 YYYY-MM-DD å
¼å®¹è¾å·®ï¼ç»ä¸è½¬ / |
| | | const normalized = raw |
| | | .replace(new RegExp(/-/gm), '/') |
| | | .replace('T', ' ') |
| | | .replace(new RegExp(/\.[\d]{3}/gm), ''); |
| | | date = new Date(normalized); |
| | | } |
| | | } |
| | | // å¼å¸¸æ
åµï¼è¿å空 |
| | | else { |
| | | return ''; |
| | | } |
| | | |
| | | if (!(date instanceof Date) || Number.isNaN(date.getTime())) return ''; |
| | | |
| | | // è¡¥é¶å½æ°ï¼ç¡®ä¿æ/æ¥æ¯ä¸¤ä½æ° |
| | | const padZero = (num) => num.toString().padStart(2, '0'); |