| | |
| | | } |
| | | }, |
| | | { |
| | | "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": "è§ç¨ä¸èµè´¨", |
| | |
| | | <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" |
| | | <up-input v-model="searchForm.supplierName" |
| | | placeholder="请è¾å
¥ä¾åºååç§°" |
| | | clearable |
| | | /> |
| | | 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> |
| | |
| | | </view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¾åºååç§°</text> |
| | |
| | | <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" |
| | | <up-popup :show="showDatePicker" |
| | | mode="bottom" |
| | | @close="showDatePicker = false"> |
| | | <up-datetime-picker :show="true" |
| | | v-model="dateValue" |
| | | @confirm="onDateConfirm" |
| | | @cancel="showDatePicker = false" |
| | | mode="date" |
| | | /> |
| | | 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 { 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" |
| | | 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 total = ref(0); |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | supplierName: '', |
| | | timeStr: '', |
| | | supplierName: "", |
| | | timeStr: "", |
| | | }, |
| | | }) |
| | | const { searchForm } = toRefs(data) |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | // ç»ä¸ç¨ dayjs è¾åº YYYY-MM-DD |
| | | const formatYMDLocal = (ts) => dayjs(Number(ts)).format('YYYY-MM-DD') |
| | | const formatYMDLocal = ts => dayjs(Number(ts)).format("YYYY-MM-DD"); |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack() |
| | | } |
| | | uni.navigateBack(); |
| | | }; |
| | | |
| | | // æ¥è¯¢å表 |
| | | const handleQuery = () => { |
| | | page.current = 1 |
| | | getList() |
| | | } |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const getList = () => { |
| | | uni.showLoading({ |
| | | title: 'å è½½ä¸...', |
| | | mask: true |
| | | }) |
| | | title: "å è½½ä¸...", |
| | | mask: true, |
| | | }); |
| | | |
| | | const params = { |
| | | ...page, |
| | | supplierName: searchForm.value.supplierName, |
| | | timeStr: searchForm.value.timeStr |
| | | } |
| | | timeStr: searchForm.value.timeStr, |
| | | }; |
| | | |
| | | getInPageByCustom(params).then(res => { |
| | | uni.hideLoading() |
| | | tableData.value = res.data.records || [] |
| | | total.value = res.data.total || 0 |
| | | }).catch(() => { |
| | | uni.hideLoading() |
| | | 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' |
| | | }) |
| | | }) |
| | | } |
| | | title: "å 载失败", |
| | | icon: "none", |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | // æå¼æ¥æéæ©å¨ï¼ç®åå¯é ï¼ |
| | | const openDatePickerHandler = () => { |
| | | // è¥å·²æé䏿¥æï¼ç¨å®åå§åï¼å¦åç¨ä»å¤© |
| | | dateValue.value = searchForm.value.timeStr |
| | | ? dayjs(searchForm.value.timeStr, 'YYYY-MM-DD').valueOf() |
| | | : Date.now() |
| | | showDatePicker.value = true |
| | | } |
| | | ? dayjs(searchForm.value.timeStr, "YYYY-MM-DD").valueOf() |
| | | : Date.now(); |
| | | showDatePicker.value = true; |
| | | }; |
| | | |
| | | // æ¥æéæ©ç¡®è®¤ï¼ä¸å
¶ä»é¡µä¸è´ï¼æ¿æ¶é´æ³ -> YYYY-MM-DDï¼ |
| | | const onDateConfirm = (e) => { |
| | | searchForm.value.timeStr = formatDateToYMD(e.value) |
| | | showDatePicker.value = false |
| | | handleQuery() |
| | | } |
| | | const onDateConfirm = e => { |
| | | searchForm.value.timeStr = formatDateToYMD(e.value); |
| | | showDatePicker.value = false; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | // æ°å¢å
¥åº |
| | | const handleAdd = () => { |
| | | formDiaManual.value?.openDialog('add') |
| | | } |
| | | formDiaManual.value?.openDialog("add"); |
| | | }; |
| | | |
| | | // ç¼è¾ |
| | | const handleEdit = (item) => { |
| | | formDiaManual.value?.openDialog('edit', item) |
| | | } |
| | | const handleEdit = item => { |
| | | formDiaManual.value?.openDialog("edit", item); |
| | | }; |
| | | |
| | | // å é¤åæ¡ |
| | | const handleDeleteSingle = (item) => { |
| | | const handleDeleteSingle = item => { |
| | | // æ£æ¥æ¯å¦æ¯æ¬äººå建 |
| | | if (item.createBy !== userStore.nickName) { |
| | | uni.showToast({ |
| | | title: 'ä¸å¯å é¤ä»äººç»´æ¤çæ°æ®', |
| | | icon: 'none' |
| | | }) |
| | | return |
| | | title: "ä¸å¯å é¤ä»äººç»´æ¤çæ°æ®", |
| | | icon: "none", |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | uni.showModal({ |
| | | title: 'å é¤', |
| | | content: '确认å é¤è¯¥å
¥åºè®°å½åï¼', |
| | | success: (res) => { |
| | | title: "å é¤", |
| | | content: "确认å é¤è¯¥å
¥åºè®°å½åï¼", |
| | | success: res => { |
| | | if (res.confirm) { |
| | | delStockInCustom({ ids: [item.id] }).then(() => { |
| | | delStockInCustom({ ids: [item.id] }) |
| | | .then(() => { |
| | | uni.showToast({ |
| | | title: 'å 餿å', |
| | | icon: 'success' |
| | | title: "å 餿å", |
| | | icon: "success", |
| | | }); |
| | | getList(); |
| | | }) |
| | | getList() |
| | | }).catch(() => { |
| | | .catch(() => { |
| | | uni.showToast({ |
| | | title: 'å é¤å¤±è´¥', |
| | | icon: 'none' |
| | | }) |
| | | }) |
| | | title: "å é¤å¤±è´¥", |
| | | icon: "none", |
| | | }); |
| | | }); |
| | | } |
| | | } |
| | | }) |
| | | } |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | onShow(() => { |
| | | getList() |
| | | }) |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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> |
| | |
| | | :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> |
| | |
| | | :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> |
| | |
| | | :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> |
| | |
| | | :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> |
| | |
| | | :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> |
| | |
| | | :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> |
| | |
| | | :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> |
| | |
| | | :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> |
| | |
| | | :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> |
| | |
| | | :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> |
| | |
| | | // 设å¤ç®¡çåè½æ°æ® |
| | | const equipmentItems = reactive([ |
| | | { |
| | | icon: '/static/images/icon/shengchanbaogong.svg', |
| | | label: '设å¤å°è´¦', |
| | | icon: "/static/images/icon/shengchanbaogong.svg", |
| | | label: "设å¤å°è´¦", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/yunxingguanli.svg", |
| | |
| | | }); |
| | | } |
| | | }; |
| | | const jumpUrl = url => { |
| | | uni.navigateTo({ |
| | | url: url, |
| | | }); |
| | | }; |
| | | |
| | | // å建对åç»ä»¶çå¼ç¨ |
| | | const uToastRef = ref(null); |
| | |
| | | |
| | | // å®ä¹èåé
ç½®æ å° |
| | | 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 => { |
| | |
| | | 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); |
| | |
| | | // æ£æ¥æ¨¡åæ¯å¦æèå项éè¦æ¾ç¤º |
| | | 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); |
| | | |