| src/api/inventoryManagement/stockInventory.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/basicData/product/ProductSelectDialog.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/inventoryManagement/stockManagement/FrozenAndThaw.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/inventoryManagement/stockManagement/New.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/inventoryManagement/stockManagement/Record.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/inventoryManagement/stockManagement/Subtract.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/inventoryManagement/stockManagement/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/api/inventoryManagement/stockInventory.js
@@ -8,6 +8,15 @@ }); }; // å页æ¥è¯¢èååºåè®°å½å表ï¼å å«ååä¿¡æ¯ï¼ export const getStockInventoryListPageCombined = (params) => { return request({ url: "/stockInventory/pageListCombinedStockInventory", method: "get", params, }); }; // å建åºåè®°å½ export const createStockInventory = (params) => { return request({ src/views/basicData/product/ProductSelectDialog.vue
@@ -55,6 +55,7 @@ const props = defineProps<{ modelValue: boolean; single?: boolean; // æ¯å¦åªè½éæ©ä¸ä¸ªï¼é»è®¤falseï¼å¯éæ©å¤ä¸ªï¼ topProductParentId?: number; // ä¸çº§äº§åid }>(); const emit = defineEmits(['update:modelValue', 'confirm']); @@ -159,6 +160,7 @@ model: query.model.trim(), current: page.pageNum, size: page.pageSize, topProductParentId: props.topProductParentId, }); tableData.value = res.records; total.value = res.total; src/views/inventoryManagement/stockManagement/FrozenAndThaw.vue
@@ -8,10 +8,27 @@ > <el-form label-width="140px" :model="formState" ref="formRef"> <el-form-item label="åºåç±»å" prop="type" :rules="[ { required: true, message: 'è¯·éæ©åºåç±»å', trigger: 'change', } ]" > <el-select v-model="formState.type" placeholder="è¯·éæ©åºåç±»å" @change="handleChangeType"> <el-option label="åæ ¼åºå" value="qualified" :disabled="(operationType === 'frozen' && props.record.qualifiedUnLockedQuantity <= 0) || (operationType === 'thaw' && props.record.qualifiedLockedQuantity <= 0)" /> <el-option label="ä¸åæ ¼åºå" value="unqualified" :disabled="(operationType === 'frozen' && props.record.unQualifiedUnLockedQuantity <= 0) || (operationType === 'thaw' && props.record.unQualifiedLockedQuantity <= 0)" /> </el-select> </el-form-item> <el-form-item :label="operationType === 'frozen' ? 'å»ç»æ°éï¼' : 'è§£å»æ°éï¼'" prop="lockedQuantity" > <el-input-number v-model="formState.lockedQuantity" :step="1" :min="1" precision="0" style="width: 100%" :max="maxCount" /> <el-input-number v-model="formState.lockedQuantity" :step="1" :min="maxCount > 0 ? 1 : 0" precision="0" style="width: 100%" :max="maxCount" :disabled="maxCount < 1" /> </el-form-item> </el-form> @@ -26,7 +43,7 @@ </template> <script setup> import {ref, computed, getCurrentInstance} from "vue"; import {ref, computed, getCurrentInstance, onMounted} from "vue"; import {frozenStockInventory, thawStockInventory} from "@/api/inventoryManagement/stockInventory.js"; import {frozenStockUninventory, thawStockUninventory} from "@/api/inventoryManagement/stockUninventory.js"; @@ -42,12 +59,6 @@ default: 'frozen', }, type: { type: String, required: true, default: 'qualified', }, record: { type: Object, default: () => {}, @@ -58,7 +69,8 @@ // ååºå¼æ°æ®ï¼æ¿ä»£é项å¼ç dataï¼ const formState = ref({ lockedQuantity: 0, type: undefined, lockedQuantity: undefined, }); const isShow = computed({ @@ -76,7 +88,8 @@ const closeModal = () => { // éç½®è¡¨åæ°æ® formState.value = { lockedQuantity: undefined lockedQuantity: undefined, type: undefined, }; isShow.value = false; }; @@ -84,17 +97,32 @@ const maxCount = computed(() => { // å»ç»åºåæå¤§æ°é为æªè§£å»æ°é if (props.operationType === 'frozen') { return props.record.unLockedQuantity // å»ç»åæ ¼åºåæå¤§æ°é为æªè§£å»åæ ¼æ°é if (formState.value.type === 'qualified') { return Math.max(0, props.record.qualifiedUnLockedQuantity || 0) } // å»ç»ä¸åæ ¼åºåæå¤§æ°é为æªè§£å»ä¸åæ ¼æ°é return Math.max(0, props.record.unQualifiedUnLockedQuantity || 0) } // è§£å»åºåæå¤§æ°é为已å»ç»æ°é return props.record.lockedQuantity if (formState.value.type === 'qualified') { // è§£å»åæ ¼åºåæå¤§æ°é为已å»ç»åæ ¼æ°é return Math.max(0, props.record.qualifiedLockedQuantity || 0) } // è§£å»ä¸åæ ¼åºåæå¤§æ°é为已å»ç»ä¸åæ ¼æ°é return Math.max(0, props.record.unQualifiedLockedQuantity || 0) }) const handleChangeType = (type) => { formState.value.lockedQuantity = maxCount.value; } const handleSubmit = () => { proxy.$refs["formRef"].validate(valid => { if (valid) { const data = Object.assign({id: props.record.id}, formState.value); if (props.type === 'qualified') { const data = Object.assign({}, formState.value); if (formState.value.type === 'qualified') { data.id = props.record.qualifiedId; // å»ç» if (props.operationType === 'frozen') { frozenStockInventory(data).then(res => { @@ -122,6 +150,7 @@ }) } } else { data.id = props.record.unQualifiedId; if (props.operationType === 'frozen') { frozenStockUninventory(data).then(res => { if (res.code === 200) { @@ -153,7 +182,6 @@ }; onMounted(() => { formState.value.lockedQuantity = maxCount.value; }) defineExpose({ src/views/inventoryManagement/stockManagement/New.vue
@@ -38,6 +38,23 @@ </el-form-item> <el-form-item label="åºåç±»å" prop="type" :rules="[ { required: true, message: 'è¯·éæ©åºåç±»å', trigger: 'change', } ]" > <el-select v-model="formState.type" placeholder="è¯·éæ©åºåç±»å"> <el-option label="åæ ¼åºå" value="qualified" /> <el-option label="ä¸åæ ¼åºå" value="unqualified" /> </el-select> </el-form-item> <el-form-item label="åºåæ°é" prop="qualitity" > @@ -45,7 +62,7 @@ </el-form-item> <el-form-item v-if="type === 'qualified'" v-if="formState.type === 'qualified'" label="åºåé¢è¦æ°é" prop="warnNum" > @@ -61,6 +78,7 @@ <ProductSelectDialog v-model="showProductSelectDialog" @confirm="handleProductSelect" :top-product-parent-id="props.topProductParentId" single /> <template #footer> @@ -84,12 +102,11 @@ type: Boolean, required: true, }, type: { type: String, required: true, default: 'qualified', }, topProductParentId: { type: Number, default: undefined, required: false, } }); const emit = defineEmits(['update:visible', 'completed']); @@ -101,6 +118,7 @@ productName: "", productModelName: "", unit: "", type: undefined, qualitity: 0, warnNum: 0, remark: '', @@ -158,7 +176,7 @@ proxy.$modal.msgError("è¯·éæ©è§æ ¼"); return; } if (props.type === 'qualified') { if (formState.value.type === 'qualified') { createStockInventory(formState.value).then(res => { // å ³éæ¨¡ææ¡ isShow.value = false; @@ -167,6 +185,7 @@ proxy.$modal.msgSuccess("æäº¤æå"); }) } else { formState.value.warnNum = 0; createStockUnInventory(formState.value).then(res => { // å ³éæ¨¡ææ¡ isShow.value = false; src/views/inventoryManagement/stockManagement/Record.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,222 @@ <template> <div class="app-container"> <div class="search_form"> <div> <span class="search_title ml10">产å大类ï¼</span> <el-input v-model="searchForm.productName" style="width: 240px" placeholder="请è¾å ¥" clearable/> <el-button type="primary" @click="handleQuery" style="margin-left: 10px">æç´¢</el-button> </div> <div> <el-button type="primary" @click="isShowNewModal = true">æ°å¢åºå</el-button> <el-button type="info" plain icon="Upload" @click="isShowImportModal = true"> å¯¼å ¥åºå </el-button> <el-button @click="handleOut">导åº</el-button> </div> </div> <div class="table_list"> <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange" :expand-row-keys="expandedRowKeys" :row-key="(row, index) => index" style="width: 100%" :row-class-name="tableRowClassName" height="calc(100vh - 18.5em)"> <el-table-column align="center" type="selection" width="55" /> <el-table-column align="center" label="åºå·" type="index" width="60" /> <el-table-column label="产å大类" prop="productName" show-overflow-tooltip /> <el-table-column label="è§æ ¼åå·" prop="model" show-overflow-tooltip /> <el-table-column label="åä½" prop="unit" show-overflow-tooltip /> <el-table-column label="åæ ¼åºåæ°é" prop="qualifiedQuantity" show-overflow-tooltip /> <el-table-column label="ä¸åæ ¼åºåæ°é" prop="unQualifiedQuantity" show-overflow-tooltip /> <el-table-column label="åæ ¼å»ç»æ°é" prop="qualifiedLockedQuantity" show-overflow-tooltip /> <el-table-column label="ä¸åæ ¼å»ç»æ°é" prop="unQualifiedLockedQuantity" show-overflow-tooltip /> <el-table-column label="åºåé¢è¦æ°é" prop="warnNum" show-overflow-tooltip /> <el-table-column label="夿³¨" prop="remark" show-overflow-tooltip /> <el-table-column label="æè¿æ´æ°æ¶é´" prop="updateTime" show-overflow-tooltip /> <el-table-column fixed="right" label="æä½" min-width="90" align="center"> <template #default="scope"> <el-button link type="primary" @click="showSubtractModal(scope.row)" :disabled="scope.row.unQualifiedUnLockedQuantity === 0 && scope.row.qualifiedUnLockedQuantity === 0">é¢ç¨</el-button> <el-button link type="primary" v-if="scope.row.unQualifiedUnLockedQuantity > 0 || scope.row.qualifiedUnLockedQuantity > 0" @click="showFrozenModal(scope.row)">å»ç»</el-button> <el-button link type="primary" v-if="scope.row.qualifiedLockedQuantity > 0 || scope.row.unQualifiedLockedQuantity > 0" @click="showThawModal(scope.row)">è§£å»</el-button> </template> </el-table-column> </el-table> <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper" :page="page.current" :limit="page.size" @pagination="paginationChange" /> </div> <new-stock-inventory v-if="isShowNewModal" v-model:visible="isShowNewModal" :top-product-parent-id="props.productId" @completed="handleQuery" /> <subtract-stock-inventory v-if="isShowSubtractModal" v-model:visible="isShowSubtractModal" :record="record" :type="record.stockType" @completed="handleQuery" /> <!-- å¯¼å ¥åºå--> <import-stock-inventory v-if="isShowImportModal" v-model:visible="isShowImportModal" type="qualified" @uploadSuccess="handleQuery" /> <!-- å»ç»/è§£å»åºå--> <frozen-and-thaw-stock-inventory v-if="isShowFrozenAndThawModal" v-model:visible="isShowFrozenAndThawModal" :record="record" :operation-type="operationType" :type="record.stockType" @completed="handleQuery" /> </div> </template> <script setup> import pagination from '@/components/PIMTable/Pagination.vue' import { ref, reactive, toRefs, onMounted, getCurrentInstance } from 'vue' import {ElMessage, ElMessageBox} from "element-plus"; import { getStockInventoryListPageCombined } from "@/api/inventoryManagement/stockInventory.js"; const props = defineProps({ productId: { type: Number, required: true, default: 0 } }); const NewStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/New.vue")); const SubtractStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/Subtract.vue")); const ImportStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/Import.vue")); const FrozenAndThawStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/FrozenAndThaw.vue")); const { proxy } = getCurrentInstance() const tableData = ref([]) const selectedRows = ref([]) const record = ref({}) const tableLoading = ref(false) const page = reactive({ current: 1, size: 100, }) const total = ref(0) // æ¯å¦æ¾ç¤ºæ°å¢å¼¹æ¡ const isShowNewModal = ref(false) // æ¯å¦æ¾ç¤ºé¢ç¨å¼¹æ¡ const isShowSubtractModal = ref(false) // æ¯å¦æ¾ç¤ºå»ç»/è§£å»å¼¹æ¡ const isShowFrozenAndThawModal = ref(false) // æä½ç±»å const operationType = ref('frozen') // æ¯å¦æ¾ç¤ºå¯¼å ¥å¼¹æ¡ const isShowImportModal = ref(false) const data = reactive({ searchForm: { productName: '', topParentProductId: props.productId, } }) const { searchForm } = toRefs(data) // æ¥è¯¢å表 /** æç´¢æé®æä½ */ const handleQuery = () => { page.current = 1 getList() } const paginationChange = (obj) => { page.current = obj.page; page.size = obj.limit; getList() } const getList = () => { tableLoading.value = true getStockInventoryListPageCombined({ ...searchForm.value, ...page }).then(res => { tableLoading.value = false tableData.value = res.data.records total.value = res.data.total // æ°æ®å è½½å®æåæ£æ¥åºå // checkStockAndCreatePurchase(); }).catch(() => { tableLoading.value = false }) } const handleFileSuccess = (response) => { const { code, msg } = response; if (code == 200) { ElMessage({ message: "å¯¼å ¥æå", type: "success" }); upload.open = false; emits("uploadSuccess"); } else { ElMessage({ message: msg, type: "error" }); } }; // ç¹å»é¢ç¨ const showSubtractModal = (row) => { record.value = row isShowSubtractModal.value = true } // ç¹å»å»ç» const showFrozenModal = (row) => { record.value = row isShowFrozenAndThawModal.value = true operationType.value = 'frozen' } // ç¹å»è§£å» const showThawModal = (row) => { record.value = row isShowFrozenAndThawModal.value = true operationType.value = 'thaw' } // è¡¨æ ¼éæ©æ°æ® const handleSelectionChange = (selection) => { // è¿æ»¤æåæ°æ® selectedRows.value = selection.filter(item => item.id); console.log('selection', selectedRows.value) } const expandedRowKeys = ref([]) // è¡¨æ ¼è¡ç±»å const tableRowClassName = ({ row }) => { const stock = Number(row?.qualifiedUnLockedQuantity ?? 0); const warn = Number(row?.warnNum ?? 0); if (!Number.isFinite(stock) || !Number.isFinite(warn)) { return ''; } return stock < warn ? 'row-low-stock' : ''; }; // å¯¼åº const handleOut = () => { ElMessageBox.confirm( 'æ¯å¦ç¡®è®¤å¯¼åºï¼', '导åº', { confirmButtonText: '确认', cancelButtonText: 'åæ¶', type: 'warning', } ).then(() => { proxy.download("/stockInventory/exportStockInventory", {topParentProductId: props.productId}, 'åºåä¿¡æ¯.xlsx') }).catch(() => { proxy.$modal.msg("已忶") }) } onMounted(() => { getList() }) </script> <style scoped lang="scss"> :deep(.row-low-stock td) { background-color: #fde2e2; color: #c45656; } :deep(.row-low-stock:hover > td) { background-color: #fcd4d4; } </style> src/views/inventoryManagement/stockManagement/Subtract.vue
@@ -38,6 +38,23 @@ </el-form-item> <el-form-item label="åºåç±»å" prop="type" :rules="[ { required: true, message: 'è¯·éæ©åºåç±»å', trigger: 'change', } ]" > <el-select v-model="formState.type" placeholder="è¯·éæ©åºåç±»å" @change="handleTypeChange"> <el-option label="åæ ¼åºå" value="qualified" :disabled="props.record.qualifiedUnLockedQuantity <= 0" /> <el-option label="ä¸åæ ¼åºå" value="unqualified" :disabled="props.record.unQualifiedUnLockedQuantity <= 0" /> </el-select> </el-form-item> <el-form-item label="æ°é" prop="qualitity" > @@ -79,12 +96,7 @@ record: { type: Object, default: () => {}, }, type: { type: String, required: true, default: 'qualified', }, } }); const emit = defineEmits(['update:visible', 'completed']); @@ -94,8 +106,19 @@ }) const maxQuality = computed(() => { return props.record.unLockedQuantity ? props.record.unLockedQuantity : 0; let max = 0; if (formState.value.type === 'qualified') { max = props.record.qualifiedUnLockedQuantity ? props.record.qualifiedUnLockedQuantity : 0; } else { max = props.record.unQualifiedUnLockedQuantity ? props.record.unQualifiedUnLockedQuantity : 0; } // ç¡®ä¿ max è³å°ä¸º 1ï¼é¿å min > max çé误 return Math.max(max, 1); }) const handleTypeChange = () => { formState.value.qualitity = undefined; } const initFormData = () => { if (props.record) { @@ -145,7 +168,6 @@ const handleProductSelect = async (products) => { if (products && products.length > 0) { const product = products[0]; console.log(product) formState.value.productId = product.productId; formState.value.productName = product.productName; formState.value.productModelName = product.model; @@ -169,7 +191,7 @@ proxy.$modal.msgError("è¯·éæ©è§æ ¼"); return; } if (props.type === 'qualified') { if (formState.value.type === 'qualified') { subtractStockInventory(formState.value).then(res => { // å ³éæ¨¡ææ¡ isShow.value = false; src/views/inventoryManagement/stockManagement/index.vue
@@ -1,33 +1,44 @@ <template> <div class="app-container"> <el-tabs v-model="activeTab" @tab-change="handleTabChange"> <el-tab-pane v-for="tab in tabs" :label="tab.label" :name="tab.name" :key="tab.name"> <component :is="tab.name === 'qualified' ? QualifiedRecord : UnqualifiedRecord" /> <div v-loading="loading" element-loading-text="å è½½ä¸..." style="min-height: 80vh;"> <el-tabs v-model="activeTab" @tab-change="handleTabChange" v-if="!loading"> <el-tab-pane v-for="tab in products" :label="tab.productName" :name="tab.id" :key="tab.id"> <Record :product-id="tab.id" v-if="tab.id === activeTab" /> </el-tab-pane> </el-tabs> </div> </div> </template> <script setup> import QualifiedRecord from "@/views/inventoryManagement/stockManagement/Qualified.vue"; import UnqualifiedRecord from "@/views/inventoryManagement/stockManagement/Unqualified.vue"; const activeTab = ref('qualified') const tabs = ref([ { label: 'åæ ¼åºå', name: 'qualified' }, { label: 'ä¸åæ ¼åºå', name: 'unqualified' } ]) import { ref, onMounted } from 'vue'; import { productTreeList } from "@/api/basicData/product.js"; import Record from "@/views/inventoryManagement/stockManagement/Record.vue"; const products = ref([]) const activeTab = ref(null) const loading = ref(false) const handleTabChange = (tabName) => { activeTab.value = tabName; } const fetchProducts = async () => { loading.value = true; try { const res = await productTreeList(); products.value = res.filter((item) => item.parentId === null).map(({ id, productName }) => ({ id, productName })); if (products.value.length > 0) { activeTab.value = products.value[0].id; } } finally { loading.value = false; } } onMounted(() => { fetchProducts(); }) </script>