| src/pages.json | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages/inventoryManagement/receiptManagement/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages/inventoryManagement/scanIn/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages/inventoryManagement/scanOut/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages/works.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/pages.json
@@ -747,6 +747,20 @@ } }, { "path": "pages/inventoryManagement/scanIn/index", "style": { "navigationBarTitleText": "æ«ç å ¥åº", "navigationStyle": "custom" } }, { "path": "pages/inventoryManagement/scanOut/index", "style": { "navigationBarTitleText": "æ«ç åºåº", "navigationStyle": "custom" } }, { "path": "pages/safeProduction/safeQualifications/index", "style": { "navigationBarTitleText": "è§ç¨ä¸èµè´¨", @@ -1337,4 +1351,4 @@ "navigationBarTitleText": "RuoYi", "navigationBarBackgroundColor": "#FFFFFF" } } } src/pages/inventoryManagement/receiptManagement/index.vue
@@ -1,34 +1,42 @@ <template> <view class="stock-in-page"> <PageHeader title="èªå®ä¹å ¥åº" @back="goBack" /> <PageHeader title="èªå®ä¹å ¥åº" @back="goBack" /> <!-- æç´¢åºå --> <view class="search-section"> <view class="search-bar"> <view class="search-input"> <up-input v-model="searchForm.supplierName" placeholder="请è¾å ¥ä¾åºååç§°" clearable /> <up-input v-model="searchForm.supplierName" placeholder="请è¾å ¥ä¾åºååç§°" clearable /> </view> <view class="search-button" @click="handleQuery"> <up-icon name="search" size="24" color="#999"></up-icon> <view class="search-button" @click="handleQuery"> <up-icon name="search" size="24" color="#999"></up-icon> </view> </view> <view class="date-filter" @click="openDatePickerHandler"> <view class="date-filter" @click="openDatePickerHandler"> <text class="date-text">{{ searchForm.timeStr || 'éæ©æ¥æ' }}</text> <up-icon name="calendar" size="18" color="#999"></up-icon> <up-icon name="calendar" size="18" color="#999"></up-icon> </view> </view> <!-- å表 --> <view class="stock-list" v-if="tableData.length > 0"> <view v-for="(item, index) in tableData" :key="index" class="stock-item"> <view class="stock-list" v-if="tableData.length > 0"> <view v-for="(item, index) in tableData" :key="index" class="stock-item"> <view class="item-header"> <view class="item-left"> <view class="batch-icon"> <up-icon name="file-text" size="16" color="#ffffff"></up-icon> <up-icon name="file-text" size="16" color="#ffffff"></up-icon> </view> <text class="batch-text">{{ item.inboundBatches }}</text> </view> @@ -37,7 +45,6 @@ </view> </view> <up-divider></up-divider> <view class="item-details"> <view class="detail-row"> <text class="detail-label">ä¾åºååç§°</text> @@ -76,331 +83,341 @@ <text class="detail-value">{{ item.createBy }}</text> </view> </view> <view class="item-actions"> <u-button type="primary" size="small" @click="handleEdit(item)">ç¼è¾</u-button> <u-button type="error" size="small" plain @click="handleDeleteSingle(item)">å é¤</u-button> <u-button type="primary" size="small" @click="handleEdit(item)">ç¼è¾</u-button> <u-button type="error" size="small" plain @click="handleDeleteSingle(item)">å é¤</u-button> </view> </view> </view> <view v-else class="no-data"> <view v-else class="no-data"> <text>ææ æ°æ®</text> </view> <!-- æµ®å¨æä½æé® --> <view class="fab-button" @click="handleAdd"> <up-icon name="plus" size="24" color="#ffffff"></up-icon> <view class="fab-button" @click="handleAdd"> <up-icon name="plus" size="24" color="#ffffff"></up-icon> </view> <!-- æ¥æéæ©å¨ --> <up-popup :show="showDatePicker" mode="bottom" @close="showDatePicker = false"> <up-datetime-picker :show="true" v-model="dateValue" @confirm="onDateConfirm" @cancel="showDatePicker = false" mode="date" /> <up-popup :show="showDatePicker" mode="bottom" @close="showDatePicker = false"> <up-datetime-picker :show="true" v-model="dateValue" @confirm="onDateConfirm" @cancel="showDatePicker = false" mode="date" /> </up-popup> <!-- 表åå¼¹çª --> <form-dia-manual ref="formDiaManual" @close="getList" @success="getList" /> <form-dia-manual ref="formDiaManual" @close="getList" @success="getList" /> </view> </template> <script setup> import { ref, reactive, toRefs, onMounted } from 'vue' import { onShow } from '@dcloudio/uni-app' import dayjs from 'dayjs' import PageHeader from '@/components/PageHeader.vue' import FormDiaManual from './components/formDiaManual.vue' import useUserStore from '@/store/modules/user' import { formatDateToYMD } from '@/utils/ruoyi' import { getInPageByCustom, delStockInCustom } from "@/api/inventoryManagement/stockIn.js" import { ref, reactive, toRefs, onMounted } from "vue"; import { onShow } from "@dcloudio/uni-app"; import dayjs from "dayjs"; import PageHeader from "@/components/PageHeader.vue"; import FormDiaManual from "./components/formDiaManual.vue"; import useUserStore from "@/store/modules/user"; import { formatDateToYMD } from "@/utils/ruoyi"; import { getInPageByCustom, delStockInCustom, } from "@/api/inventoryManagement/stockIn.js"; const userStore = useUserStore() const userStore = useUserStore(); const tableData = ref([]) const showDatePicker = ref(false) const dateValue = ref(new Date().getTime()) const formDiaManual = ref(null) const tableData = ref([]); const showDatePicker = ref(false); const dateValue = ref(new Date().getTime()); const formDiaManual = ref(null); const page = reactive({ current: 1, size: 20, }) const total = ref(0) const page = reactive({ current: 1, size: 20, }); const total = ref(0); const data = reactive({ searchForm: { supplierName: '', timeStr: '', }, }) const { searchForm } = toRefs(data) const data = reactive({ searchForm: { supplierName: "", timeStr: "", }, }); const { searchForm } = toRefs(data); // ç»ä¸ç¨ dayjs è¾åº YYYY-MM-DD const formatYMDLocal = (ts) => dayjs(Number(ts)).format('YYYY-MM-DD') // ç»ä¸ç¨ dayjs è¾åº YYYY-MM-DD const formatYMDLocal = ts => dayjs(Number(ts)).format("YYYY-MM-DD"); // è¿åä¸ä¸é¡µ const goBack = () => { uni.navigateBack() } // è¿åä¸ä¸é¡µ const goBack = () => { uni.navigateBack(); }; // æ¥è¯¢å表 const handleQuery = () => { page.current = 1 getList() } // æ¥è¯¢å表 const handleQuery = () => { page.current = 1; getList(); }; const getList = () => { uni.showLoading({ title: 'å è½½ä¸...', mask: true }) const params = { ...page, supplierName: searchForm.value.supplierName, timeStr: searchForm.value.timeStr } getInPageByCustom(params).then(res => { uni.hideLoading() tableData.value = res.data.records || [] total.value = res.data.total || 0 }).catch(() => { uni.hideLoading() uni.showToast({ title: 'å 载失败', icon: 'none' }) }) } const getList = () => { uni.showLoading({ title: "å è½½ä¸...", mask: true, }); // æå¼æ¥æéæ©å¨ï¼ç®åå¯é ï¼ const openDatePickerHandler = () => { // è¥å·²æé䏿¥æï¼ç¨å®åå§åï¼å¦åç¨ä»å¤© dateValue.value = searchForm.value.timeStr ? dayjs(searchForm.value.timeStr, 'YYYY-MM-DD').valueOf() : Date.now() showDatePicker.value = true } const params = { ...page, supplierName: searchForm.value.supplierName, timeStr: searchForm.value.timeStr, }; // æ¥æéæ©ç¡®è®¤ï¼ä¸å ¶ä»é¡µä¸è´ï¼æ¿æ¶é´æ³ -> YYYY-MM-DDï¼ const onDateConfirm = (e) => { searchForm.value.timeStr = formatDateToYMD(e.value) showDatePicker.value = false handleQuery() } getInPageByCustom(params) .then(res => { uni.hideLoading(); tableData.value = res.data.records || []; total.value = res.data.total || 0; }) .catch(() => { uni.hideLoading(); uni.showToast({ title: "å 载失败", icon: "none", }); }); }; // æ°å¢å ¥åº const handleAdd = () => { formDiaManual.value?.openDialog('add') } // æå¼æ¥æéæ©å¨ï¼ç®åå¯é ï¼ const openDatePickerHandler = () => { // è¥å·²æé䏿¥æï¼ç¨å®åå§åï¼å¦åç¨ä»å¤© dateValue.value = searchForm.value.timeStr ? dayjs(searchForm.value.timeStr, "YYYY-MM-DD").valueOf() : Date.now(); showDatePicker.value = true; }; // ç¼è¾ const handleEdit = (item) => { formDiaManual.value?.openDialog('edit', item) } // æ¥æéæ©ç¡®è®¤ï¼ä¸å ¶ä»é¡µä¸è´ï¼æ¿æ¶é´æ³ -> YYYY-MM-DDï¼ const onDateConfirm = e => { searchForm.value.timeStr = formatDateToYMD(e.value); showDatePicker.value = false; handleQuery(); }; // å é¤åæ¡ const handleDeleteSingle = (item) => { // æ£æ¥æ¯å¦æ¯æ¬äººå建 if (item.createBy !== userStore.nickName) { uni.showToast({ title: 'ä¸å¯å é¤ä»äººç»´æ¤çæ°æ®', icon: 'none' }) return } uni.showModal({ title: 'å é¤', content: '确认å é¤è¯¥å ¥åºè®°å½åï¼', success: (res) => { if (res.confirm) { delStockInCustom({ ids: [item.id] }).then(() => { uni.showToast({ title: 'å 餿å', icon: 'success' }) getList() }).catch(() => { uni.showToast({ title: 'å é¤å¤±è´¥', icon: 'none' }) }) } // æ°å¢å ¥åº const handleAdd = () => { formDiaManual.value?.openDialog("add"); }; // ç¼è¾ const handleEdit = item => { formDiaManual.value?.openDialog("edit", item); }; // å é¤åæ¡ const handleDeleteSingle = item => { // æ£æ¥æ¯å¦æ¯æ¬äººå建 if (item.createBy !== userStore.nickName) { uni.showToast({ title: "ä¸å¯å é¤ä»äººç»´æ¤çæ°æ®", icon: "none", }); return; } }) } onShow(() => { getList() }) uni.showModal({ title: "å é¤", content: "确认å é¤è¯¥å ¥åºè®°å½åï¼", success: res => { if (res.confirm) { delStockInCustom({ ids: [item.id] }) .then(() => { uni.showToast({ title: "å 餿å", icon: "success", }); getList(); }) .catch(() => { uni.showToast({ title: "å é¤å¤±è´¥", icon: "none", }); }); } }, }); }; onShow(() => { getList(); }); </script> <style scoped lang="scss"> .stock-in-page { min-height: 100vh; background: #f5f5f5; padding-bottom: 80px; } .stock-in-page { min-height: 100vh; background: #f5f5f5; padding-bottom: 80px; } .search-section { background: #fff; padding: 16px; margin-bottom: 12px; } .search-section { background: #fff; padding: 16px; margin-bottom: 12px; } .search-bar { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; } .search-bar { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; } .search-input { flex: 1; } .search-input { flex: 1; } .search-button { width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; background: #f5f5f5; border-radius: 8px; } .search-button { width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; background: #f5f5f5; border-radius: 8px; } .date-filter { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; background: #f5f5f5; border-radius: 8px; } .date-filter { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; background: #f5f5f5; border-radius: 8px; } .date-text { font-size: 14px; color: #666; } .date-text { font-size: 14px; color: #666; } .stock-list { padding: 0 16px; } .stock-list { padding: 0 16px; } .stock-item { background: #fff; border-radius: 12px; padding: 16px; margin-bottom: 12px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); } .stock-item { background: #fff; border-radius: 12px; padding: 16px; margin-bottom: 12px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); } .item-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; } .item-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; } .item-left { display: flex; align-items: center; gap: 8px; } .item-left { display: flex; align-items: center; gap: 8px; } .batch-icon { width: 32px; height: 32px; background: #2979ff; border-radius: 8px; display: flex; align-items: center; justify-content: center; } .batch-icon { width: 32px; height: 32px; background: #2979ff; border-radius: 8px; display: flex; align-items: center; justify-content: center; } .batch-text { font-size: 14px; font-weight: 500; color: #333; } .batch-text { font-size: 14px; font-weight: 500; color: #333; } .time-text { font-size: 12px; color: #999; } .time-text { font-size: 12px; color: #999; } .item-details { margin: 12px 0; } .item-details { margin: 12px 0; } .detail-row { display: flex; align-items: center; justify-content: space-between; padding: 8px 0; } .detail-row { display: flex; align-items: center; justify-content: space-between; padding: 8px 0; } .detail-label { font-size: 14px; color: #666; } .detail-label { font-size: 14px; color: #666; } .detail-value { font-size: 14px; color: #333; text-align: right; flex: 1; margin-left: 12px; } .detail-value { font-size: 14px; color: #333; text-align: right; flex: 1; margin-left: 12px; } .detail-value.highlight { color: #2979ff; font-weight: 500; } .detail-value.highlight { color: #2979ff; font-weight: 500; } .detail-value.price { color: #ff6b00; font-weight: 500; } .detail-value.price { color: #ff6b00; font-weight: 500; } .item-actions { display: flex; gap: 12px; margin-top: 12px; padding-top: 12px; border-top: 1px solid #f5f5f5; } .item-actions { display: flex; gap: 12px; margin-top: 12px; padding-top: 12px; border-top: 1px solid #f5f5f5; } .no-data { text-align: center; padding: 60px 0; color: #999; font-size: 14px; } .no-data { text-align: center; padding: 60px 0; color: #999; font-size: 14px; } .fab-button { position: fixed; right: 20px; bottom: 80px; width: 56px; height: 56px; background: #2979ff; border-radius: 50%; display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 12px rgba(41, 121, 255, 0.4); z-index: 999; } .fab-button { position: fixed; right: 20px; bottom: 80px; width: 56px; height: 56px; background: #2979ff; border-radius: 50%; display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 12px rgba(41, 121, 255, 0.4); z-index: 999; } </style> src/pages/inventoryManagement/scanIn/index.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,307 @@ <template> <view class="scan-container"> <PageHeader title="æ«ç å ¥åº" @back="goBack" /> <view class="module-selector" v-if="!showForm"> <view class="module-card" @click="startScan('qualified')"> <view class="module-icon qualified"> <u-icon name="checkbox-mark" color="#fff" size="40"></u-icon> </view> <view class="module-info"> <text class="module-label">åæ ¼å ¥åº</text> <text class="module-desc">æ«æåæ ¼äº§åä¿¡æ¯</text> </view> </view> <view class="module-card" @click="startScan('unqualified')"> <view class="module-icon unqualified"> <u-icon name="close" color="#fff" size="40"></u-icon> </view> <view class="module-info"> <text class="module-label">ä¸åæ ¼å ¥åº</text> <text class="module-desc">å½å ¥ä¸åæ ¼åè®°å½</text> </view> </view> </view> <view class="form-content" v-if="showForm"> <u-form ref="formRef" :model="form" :rules="formRules" label-width="100px"> <u-form-item label="å ¥åºç±»å" border-bottom> <u-tag :text="type === 'qualified' ? 'åæ ¼å ¥åº' : 'ä¸åæ ¼å ¥åº'" :type="type === 'qualified' ? 'success' : 'error'"></u-tag> </u-form-item> <u-form-item label="产ååç§°" border-bottom> <u-input v-model="form.productName" readonly border="none"></u-input> </u-form-item> <u-form-item label="è§æ ¼åå·" border-bottom> <u-input v-model="form.productModelName" readonly border="none"></u-input> </u-form-item> <u-form-item label="åä½" border-bottom> <u-input v-model="form.unit" readonly border="none"></u-input> </u-form-item> <u-form-item label="å ¥åºæ°é" prop="qualitity" required border-bottom> <u-number-box v-model="form.qualitity" :min="1" :step="1"></u-number-box> </u-form-item> <u-form-item label="é¢è¦æ°é" prop="warnNum" v-if="type === 'qualified'" border-bottom> <u-number-box v-model="form.warnNum" :min="0" :step="1"></u-number-box> </u-form-item> <u-form-item label="夿³¨" prop="remark" border-bottom> <u-textarea v-model="form.remark" placeholder="请è¾å ¥å¤æ³¨" count></u-textarea> </u-form-item> </u-form> <view class="footer-btns"> <u-button class="cancel-btn" @click="cancelForm">åæ¶</u-button> <u-button class="save-btn" @click="handleSubmit" :loading="loading">ç¡®è®¤å ¥åº</u-button> </view> </view> </view> </template> <script setup> import { ref, reactive } from "vue"; import PageHeader from "@/components/PageHeader.vue"; import { createStockInventory, getStockInventoryListPage, } from "@/api/inventoryManagement/stockInventory.js"; import { createStockUnInventory, getStockUninventoryListPage, } from "@/api/inventoryManagement/stockUninventory.js"; import modal from "@/plugins/modal"; const showForm = ref(false); const type = ref("qualified"); // qualified | unqualified const loading = ref(false); const formRef = ref(null); const form = ref({ productId: undefined, productModelId: undefined, productName: "", productModelName: "", unit: "", qualitity: 1, warnNum: 0, remark: "", }); const formRules = { qualitity: [ { required: true, type: "number", message: "请è¾å ¥å ¥åºæ°é", trigger: ["blur", "change"], }, ], }; const goBack = () => { if (showForm.value) { showForm.value = false; } else { uni.navigateBack(); } }; const cancelForm = () => { showForm.value = false; }; const startScan = scanType => { type.value = scanType; uni.scanCode({ success: res => { handleScanResult(res.result); }, fail: err => { modal.msgError("æ«ç 失败"); }, }); }; const handleScanResult = async result => { try { // è§£æäºç»´ç æ°æ® const scanData = JSON.parse(result); if (!scanData.id) { modal.msgError("æ æçäºç»´ç æ°æ®"); return; } // ç´æ¥ä»äºç»´ç ä¿¡æ¯ä¸è·å产å详æ form.value.productId = scanData.productId; // 妿äºç»´ç 䏿 productId form.value.productName = scanData.productName; form.value.productModelId = scanData.id; // äºç»´ç ä¸ç id æ¯äº§ååå· ID form.value.productModelName = scanData.model; form.value.unit = scanData.unit; form.value.qualitity = 1; form.value.warnNum = 0; form.value.remark = ""; showForm.value = true; } catch (error) { console.error("è§£æäºç»´ç 失败", error); modal.msgError("è§£æäºç»´ç 失败ï¼è¯·ç¡®ä¿æ«ç å 容æ£ç¡®"); } }; const handleSubmit = async () => { try { const valid = await formRef.value.validate(); if (!valid) return; loading.value = true; const apiCall = type.value === "qualified" ? createStockInventory : createStockUnInventory; const res = await apiCall(form.value); if (res.code === 200) { modal.msgSuccess("å ¥åºæå"); setTimeout(() => { showForm.value = false; }, 1500); } } catch (error) { console.error("æäº¤å¤±è´¥", error); } finally { loading.value = false; } }; </script> <style scoped lang="scss"> .scan-container { min-height: 100vh; background-color: #f5f7fa; } .module-selector { display: flex; flex-direction: column; padding: 40rpx; height: 80vh; justify-content: center; } .module-card { display: flex; align-items: center; background-color: #fff; padding: 80rpx 50rpx; border-radius: 32rpx; box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.05); margin-bottom: 50rpx; transition: all 0.3s ease; border: 2rpx solid transparent; &:active { transform: scale(0.98); background-color: #f9f9f9; } } .module-icon { width: 140rpx; height: 140rpx; border-radius: 32rpx; display: flex; justify-content: center; align-items: center; margin-right: 40rpx; &.qualified { background: linear-gradient(135deg, #52c41a, #73d13d); box-shadow: 0 10rpx 20rpx rgba(82, 196, 26, 0.2); } &.unqualified { background: linear-gradient(135deg, #ff4d4f, #ff7875); box-shadow: 0 10rpx 20rpx rgba(255, 77, 79, 0.2); } } .module-info { display: flex; flex-direction: column; } .module-label { font-size: 40rpx; font-weight: 700; color: #1a1a1a; margin-bottom: 12rpx; } .module-desc { font-size: 28rpx; color: #999; } .form-content { background-color: #fff; margin: 20rpx; padding: 30rpx; border-radius: 16rpx; } .footer-btns { margin-top: 60rpx; display: flex; justify-content: space-between; padding-bottom: 40rpx; } .cancel-btn { width: 30%; background-color: #f5f5f5; color: #666; border: none; } .save-btn { width: 65%; background: linear-gradient(140deg, #00baff 0%, #006cfb 100%); color: #fff; border: none; } </style> src/pages/inventoryManagement/scanOut/index.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,339 @@ <template> <view class="scan-container"> <PageHeader title="æ«ç åºåº" @back="goBack" /> <view class="module-selector" v-if="!showForm"> <view class="module-card" @click="startScan('qualified')"> <view class="module-icon qualified"> <u-icon name="checkbox-mark" color="#fff" size="40"></u-icon> </view> <view class="module-info"> <text class="module-label">åæ ¼åºåº</text> <text class="module-desc">æ«æåæ ¼åè¿è¡é¢ç¨åºåº</text> </view> </view> <view class="module-card" @click="startScan('unqualified')"> <view class="module-icon unqualified"> <u-icon name="close" color="#fff" size="40"></u-icon> </view> <view class="module-info"> <text class="module-label">ä¸åæ ¼åºåº</text> <text class="module-desc">è®°å½ä¸åæ ¼åçåºåºæµå</text> </view> </view> </view> <view class="form-content" v-if="showForm"> <u-form ref="formRef" :model="form" :rules="formRules" label-width="100px"> <u-form-item label="åºåºç±»å" border-bottom> <u-tag :text="type === 'qualified' ? 'åæ ¼åºåº' : 'ä¸åæ ¼åºåº'" :type="type === 'qualified' ? 'success' : 'error'"></u-tag> </u-form-item> <u-form-item label="产ååç§°" border-bottom> <u-input v-model="form.productName" readonly border="none"></u-input> </u-form-item> <u-form-item label="è§æ ¼åå·" border-bottom> <u-input v-model="form.model" readonly border="none"></u-input> </u-form-item> <u-form-item label="å¯ç¨åºå" border-bottom> <u-input v-model="form.unLockedQuantity" readonly border="none"></u-input>{{form.unit}} </u-form-item> <u-form-item label="åºåºæ°é" prop="qualitity" required border-bottom> <u-number-box v-model="form.qualitity" :min="1" :max="form.unLockedQuantity" :step="1"></u-number-box> <text class="limit-tip">æå¤§å¯é¢ç¨: {{form.unLockedQuantity}}</text> </u-form-item> <u-form-item label="夿³¨" prop="remark" border-bottom> <u-textarea v-model="form.remark" placeholder="请è¾å ¥å¤æ³¨" count></u-textarea> </u-form-item> </u-form> <view class="footer-btns"> <u-button class="cancel-btn" @click="cancelForm">åæ¶</u-button> <u-button class="save-btn" @click="handleSubmit" :loading="loading">确认åºåº</u-button> </view> </view> </view> </template> <script setup> import { ref, reactive } from "vue"; import PageHeader from "@/components/PageHeader.vue"; import { subtractStockInventory, getStockInventoryListPage, } from "@/api/inventoryManagement/stockInventory.js"; import { subtractStockUnInventory, getStockUninventoryListPage, } from "@/api/inventoryManagement/stockUninventory.js"; import modal from "@/plugins/modal"; const showForm = ref(false); const type = ref("qualified"); // qualified | unqualified const loading = ref(false); const formRef = ref(null); const form = ref({ id: undefined, productId: undefined, productModelId: undefined, productName: "", model: "", unit: "", qualitity: 1, unLockedQuantity: 0, remark: "", }); const formRules = { qualitity: [ { required: true, type: "number", message: "请è¾å ¥åºåºæ°é", trigger: ["blur", "change"], }, { validator: (rule, value, callback) => { if (value > form.value.unLockedQuantity) { callback(new Error("ä¸è½è¶ è¿å¯ç¨åºå")); } else { callback(); } }, trigger: ["blur", "change"], }, ], }; const goBack = () => { if (showForm.value) { showForm.value = false; } else { uni.navigateBack(); } }; const cancelForm = () => { showForm.value = false; }; const startScan = scanType => { type.value = scanType; uni.scanCode({ success: res => { handleScanResult(res.result); }, fail: err => { modal.msgError("æ«ç 失败"); }, }); }; const handleScanResult = async result => { try { // è§£æäºç»´ç æ°æ® const scanData = JSON.parse(result); if (!scanData.id) { modal.msgError("æ æçäºç»´ç æ°æ®"); return; } // è·å宿¶åºå详æ modal.loading("è·å产ååºå详æ ..."); const apiCall = type.value === "qualified" ? getStockInventoryListPage : getStockUninventoryListPage; const res = await apiCall({ productModelId: scanData.id }); modal.closeLoading(); if (res.code === 200 && res.data.records && res.data.records.length > 0) { const detail = res.data.records[0]; form.value.id = detail.id; form.value.productId = detail.productId; form.value.productName = detail.productName; form.value.productModelId = detail.productModelId; form.value.model = detail.model; form.value.unit = detail.unit; form.value.unLockedQuantity = detail.unLockedQuantity; form.value.qualitity = 1; form.value.remark = ""; if (form.value.unLockedQuantity <= 0) { modal.msgError("å½ååºåä¸è¶³ï¼æ æ³åºåº"); return; } showForm.value = true; } else { modal.msgError("æªæ¾å°è¯¥äº§ååå·çåºåè®°å½"); } } catch (error) { modal.closeLoading(); console.error("å¤çæ«ç ç»æå¤±è´¥", error); modal.msgError("æ«ç å¤ç失败ï¼è¯·éè¯"); } }; const handleSubmit = async () => { try { const valid = await formRef.value.validate(); if (!valid) return; loading.value = true; const apiCall = type.value === "qualified" ? subtractStockInventory : subtractStockUnInventory; const res = await apiCall(form.value); if (res.code === 200) { modal.msgSuccess("åºåºæå"); setTimeout(() => { showForm.value = false; }, 1500); } } catch (error) { console.error("æäº¤å¤±è´¥", error); } finally { loading.value = false; } }; </script> <style scoped lang="scss"> .scan-container { min-height: 100vh; background-color: #f5f7fa; } .module-selector { display: flex; flex-direction: column; padding: 40rpx; height: 80vh; justify-content: center; } .module-card { display: flex; align-items: center; background-color: #fff; padding: 80rpx 50rpx; border-radius: 32rpx; box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.05); margin-bottom: 50rpx; transition: all 0.3s ease; border: 2rpx solid transparent; &:active { transform: scale(0.98); background-color: #f9f9f9; } } .module-icon { width: 140rpx; height: 140rpx; border-radius: 32rpx; display: flex; justify-content: center; align-items: center; margin-right: 40rpx; &.qualified { background: linear-gradient(135deg, #52c41a, #73d13d); box-shadow: 0 10rpx 20rpx rgba(82, 196, 26, 0.2); } &.unqualified { background: linear-gradient(135deg, #ff4d4f, #ff7875); box-shadow: 0 10rpx 20rpx rgba(255, 77, 79, 0.2); } } .module-info { display: flex; flex-direction: column; } .module-label { font-size: 40rpx; font-weight: 700; color: #1a1a1a; margin-bottom: 12rpx; } .module-desc { font-size: 28rpx; color: #999; } .form-content { background-color: #fff; margin: 20rpx; padding: 30rpx; border-radius: 16rpx; } .limit-tip { font-size: 24rpx; color: #999; margin-left: 20rpx; } .footer-btns { margin-top: 60rpx; display: flex; justify-content: space-between; padding-bottom: 40rpx; } .cancel-btn { width: 30%; background-color: #f5f5f5; color: #666; border: none; } .save-btn { width: 65%; background: linear-gradient(140deg, #00baff 0%, #006cfb 100%); color: #fff; border: none; } </style> src/pages/works.vue
@@ -15,7 +15,8 @@ :key="index" @click="handleCommonItemClick(item)"> <view class="icon-container"> <image :src="item.icon" class="item-icon"></image> <image :src="item.icon" class="item-icon"></image> </view> <text class="item-label">{{item.label}}</text> </up-grid-item> @@ -37,7 +38,8 @@ :key="index" @click="handleCommonItemClick(item)"> <view class="icon-container"> <image :src="item.icon" class="item-icon"></image> <image :src="item.icon" class="item-icon"></image> </view> <text class="item-label">{{item.label}}</text> </up-grid-item> @@ -59,7 +61,8 @@ :key="index" @click="handleCommonItemClick(item)"> <view class="icon-container"> <image :src="item.icon" class="item-icon"></image> <image :src="item.icon" class="item-icon"></image> </view> <text class="item-label">{{item.label}}</text> </up-grid-item> @@ -81,9 +84,24 @@ :key="index" @click="handleCommonItemClick(item)"> <view class="icon-container"> <image :src="item.icon" class="item-icon"></image> <image :src="item.icon" class="item-icon"></image> </view> <text class="item-label">{{item.label}}</text> </up-grid-item> <up-grid-item @click="jumpUrl('/pages/inventoryManagement/scanIn/index')"> <view class="icon-container"> <image src="/static/images/icon/xiaoshoutaizhang.svg" class="item-icon"></image> </view> <text class="item-label">æ«ç å ¥åº</text> </up-grid-item> <up-grid-item @click="jumpUrl('/pages/inventoryManagement/scanOut/index')"> <view class="icon-container"> <image src="/static/images/icon/xiaoshoutaizhang.svg" class="item-icon"></image> </view> <text class="item-label">æ«ç åºåº</text> </up-grid-item> </up-grid> </view> @@ -149,7 +167,8 @@ :key="index" @click="handleCommonItemClick(item)"> <view class="icon-container"> <image :src="item.icon" class="item-icon"></image> <image :src="item.icon" class="item-icon"></image> </view> <text class="item-label">{{item.label}}</text> </up-grid-item> @@ -171,7 +190,8 @@ :key="index" @click="handleCommonItemClick(item)"> <view class="icon-container"> <image :src="item.icon" class="item-icon"></image> <image :src="item.icon" class="item-icon"></image> </view> <text class="item-label">{{item.label}}</text> </up-grid-item> @@ -193,7 +213,8 @@ :key="index" @click="handleCommonItemClick(item)"> <view class="icon-container"> <image :src="item.icon" class="item-icon"></image> <image :src="item.icon" class="item-icon"></image> </view> <text class="item-label">{{item.label}}</text> </up-grid-item> @@ -215,7 +236,8 @@ :key="index" @click="handleCommonItemClick(item)"> <view class="icon-container"> <image :src="item.icon" class="item-icon"></image> <image :src="item.icon" class="item-icon"></image> </view> <text class="item-label">{{item.label}}</text> </up-grid-item> @@ -237,7 +259,8 @@ :key="index" @click="handleCommonItemClick(item)"> <view class="icon-container"> <image :src="item.icon" class="item-icon"></image> <image :src="item.icon" class="item-icon"></image> </view> <text class="item-label">{{item.label}}</text> </up-grid-item> @@ -259,7 +282,8 @@ :key="index" @click="handleCommonItemClick(item)"> <view class="icon-container"> <image :src="item.icon" class="item-icon"></image> <image :src="item.icon" class="item-icon"></image> </view> <text class="item-label">{{item.label}}</text> </up-grid-item> @@ -532,8 +556,8 @@ // 设å¤ç®¡çåè½æ°æ® const equipmentItems = reactive([ { icon: '/static/images/icon/shengchanbaogong.svg', label: '设å¤å°è´¦', icon: "/static/images/icon/shengchanbaogong.svg", label: "设å¤å°è´¦", }, { icon: "/static/images/icon/yunxingguanli.svg", @@ -912,6 +936,11 @@ }); } }; const jumpUrl = url => { uni.navigateTo({ url: url, }); }; // å建对åç»ä»¶çå¼ç¨ const uToastRef = ref(null); @@ -1092,10 +1121,16 @@ // å®ä¹èåé ç½®æ å° const menuMapping = { collaboration: { target: collaborationItems, specialMapping: { "è§ç« å¶åº¦": "è§ç« å¶åº¦ç®¡ç" } }, archiveManagement: { target: archiveManagementItems, specialMapping: { "ä¾åºåæ¡£æ¡": "ä¾åºå管ç" } }, collaboration: { target: collaborationItems, specialMapping: { è§ç« å¶åº¦: "è§ç« å¶åº¦ç®¡ç" }, }, archiveManagement: { target: archiveManagementItems, specialMapping: { ä¾åºåæ¡£æ¡: "ä¾åºå管ç" }, }, }; console.log(allowedMenuTitles) console.log(allowedMenuTitles); // éç¨è¿æ»¤å½æ° const filterArray = (targetArray, specialMapping) => { const filtered = targetArray.filter(item => { @@ -1112,7 +1147,10 @@ filterArray(marketingItems); filterArray(purchaseItems); filterArray(financeManagementItems); filterArray(archiveManagementItems, menuMapping.archiveManagement.specialMapping); filterArray( archiveManagementItems, menuMapping.archiveManagement.specialMapping ); filterArray(collaborationItems, menuMapping.collaboration.specialMapping); filterArray(safetyItems); filterArray(humanResourcesItems); @@ -1125,14 +1163,22 @@ // æ£æ¥æ¨¡åæ¯å¦æèå项éè¦æ¾ç¤º const hasMarketingItems = computed(() => marketingItems.length > 0); const hasPurchaseItems = computed(() => purchaseItems.length > 0); const hasFinanceManagementItems = computed(() => financeManagementItems.length > 0); const hasArchiveManagementItems = computed(() => archiveManagementItems.length > 0); const hasAfterSalesServiceItems = computed(() => afterSalesServiceItems.length > 0); const hasFinanceManagementItems = computed( () => financeManagementItems.length > 0 ); const hasArchiveManagementItems = computed( () => archiveManagementItems.length > 0 ); const hasAfterSalesServiceItems = computed( () => afterSalesServiceItems.length > 0 ); const hasCollaborationItems = computed(() => collaborationItems.length > 0); const hasSafetyItems = computed(() => safetyItems.length > 0); const hasQualityItems = computed(() => qualityItems.length > 0); // const hasHumanResourcesItems = computed(() => humanResourcesItems.length > 0); const hasWarehouseLogisticsItems = computed(() => warehouseLogisticsItems.length > 0); const hasWarehouseLogisticsItems = computed( () => warehouseLogisticsItems.length > 0 ); // const hasProductionItems = computed(() => productionItems.length > 0); const hasEquipmentItems = computed(() => equipmentItems.length > 0);