| | |
| | | VITE_APP_PORT = 4096 |
| | | |
| | | # API åºç¡è·¯å¾ï¼å¼åç¯å¢ä¸ç请æ±åç¼ |
| | | VITE_APP_BASE_API = 'http://114.132.189.42:7002/mes' |
| | | # VITE_APP_BASE_API = 'http://114.132.189.42:7002/mes' |
| | | VITE_APP_BASE_API = 'http://114.132.189.42:7002/mes' |
| | | # VITE_APP_BASE_API = 'http://192.168.10.119:7002/mes' # é¹è£ |
| | | # VITE_APP_BASE_API = 'http://192.168.100.131:7002/mes' # |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | import { BaseResult } from "@/models/base"; |
| | | |
| | | const BASE = "/inventory/operation"; |
| | | |
| | | /** åºåæä½ï¼æåæç / ç»çº¿å¤ç»ï¼ */ |
| | | const InventoryOperationApi = { |
| | | // æ°å¢æä½å |
| | | createOperation(data: any) { |
| | | return request<BaseResult<any>>({ |
| | | url: `${BASE}/create`, |
| | | method: "POST", |
| | | data, |
| | | }); |
| | | }, |
| | | |
| | | // åºåçå·æç´¢ï¼æå/åæåï¼ï¼keyword æ¯æçå·/è§æ ¼åå· |
| | | searchStock(data: { |
| | | keyword?: string; |
| | | materialType?: string; |
| | | ncReturnFlag?: string; |
| | | model?: string; |
| | | current?: number; |
| | | size?: number; |
| | | }) { |
| | | return request<BaseResult<any>>({ |
| | | url: `${BASE}/searchStock`, |
| | | method: "POST", |
| | | data, |
| | | }); |
| | | }, |
| | | }; |
| | | |
| | | export default InventoryOperationApi; |
| | |
| | | }); |
| | | }, |
| | | |
| | | // çå
·ç§°éå°è´¦å页æ¥è¯¢ï¼æ«ç é¢ç¨çå
·æ¶æç§°éç¼å·åå°è´¦æ°æ®ï¼ |
| | | queryBobbinWeighingPage(params: { |
| | | current?: number; |
| | | size?: number; |
| | | weighingCode?: string; |
| | | specificationModel?: string; |
| | | diskMaterial?: string; |
| | | received?: number | string; |
| | | }) { |
| | | return request<BaseResult<any>>({ |
| | | url: "/bobbinWeighing/queryPage", |
| | | method: "GET", |
| | | data: params, |
| | | }); |
| | | }, |
| | | |
| | | saveAge(data: any) { |
| | | return request<BaseResult<any>>({ |
| | | url: "/app/ageing", |
| | |
| | | }, |
| | | |
| | | /** |
| | | * 人å䏿å表ï¼ä¸ PC 端 getUserSelect å䏿¥å£ï¼ |
| | | * è¿å [{ nickName / nickname / userName, ... }] |
| | | */ |
| | | getUserSelect() { |
| | | return request<any>({ |
| | | url: "/team/getUser", |
| | | method: "GET", |
| | | }); |
| | | }, |
| | | |
| | | /** |
| | | * è·åç¨æ·å页å表 |
| | | * |
| | | * @param queryParams æ¥è¯¢åæ° |
| | |
| | | "name" : "线ç¼ä¸æ¥", |
| | | "appid" : "__UNI__F64E0A4", |
| | | "description" : "", |
| | | "versionName" : "1.0.30", |
| | | "versionName" : "1.0.37", |
| | | "versionCode" : "100", |
| | | "transformPx" : false, |
| | | /* 5+Appç¹æç¸å
³ */ |
| | |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/production/inventory/index", |
| | | "style": { |
| | | "navigationBarTitleText": "åºåæä½" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/production/inventory/form", |
| | | "style": { |
| | | "navigationBarTitleText": "åºåæä½åç" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/timely/index", |
| | | "style": { |
| | | "navigationBarTitleText": "æ¶æä»»å¡" |
| | |
| | | // prem: "sys:user:query", |
| | | // }, |
| | | { |
| | | icon: "/static/icons/user.png", |
| | | icon: "/static/icons/production.png", |
| | | title: "ç产管ç", |
| | | url: "/pages/production/index", |
| | | show: false, |
| | |
| | | // show: false, |
| | | // }, |
| | | { |
| | | icon: "/static/icons/routingInspection.png", |
| | | icon: "/static/icons/inspection.png", |
| | | title: "å·¡æ£", |
| | | url: "/pages/routingInspection/index", |
| | | show: false, |
| | | }, |
| | | { |
| | | icon: "/static/icons/log.png", |
| | | icon: "/static/icons/outbound.png", |
| | | title: "åºåº", |
| | | url: "/pages/outbound/index", |
| | | show: false, |
| | | }, |
| | | { |
| | | icon: "/static/icons/log.png", |
| | | icon: "/static/icons/inventoryOperation.png", |
| | | title: "åºåæä½", |
| | | url: "/pages/production/inventory/index", |
| | | show: false, |
| | | }, |
| | | { |
| | | icon: "/static/icons/timely.png", |
| | | title: "æ¶æ", |
| | | url: "/pages/timely/index", |
| | | show: false, |
| | |
| | | const canAccessTimely = deviceGroupName.includes("æ¶æ") || isAdmin.value; |
| | | const productionNav = navList.find((item) => item.url === "/pages/production/index"); |
| | | const timelyNav = navList.find((item) => item.url === "/pages/timely/index"); |
| | | // åºåæä½ï¼æåæç / ç»çº¿å¤ç»ï¼ï¼æéä¸ãç产管çãä¸è´ |
| | | const inventoryNav = navList.find( |
| | | (item) => item.url === "/pages/production/inventory/index" |
| | | ); |
| | | if (productionNav) productionNav.show = canAccessProduction; |
| | | if (timelyNav) timelyNav.show = canAccessTimely; |
| | | if (inventoryNav) { |
| | | inventoryNav.show = canAccessProduction; |
| | | } |
| | | console.log("isInspector.value", isInspector.value); |
| | | if (isInspector.value || isAdmin.value) { |
| | | // 妿æ¯å·¡æ£åï¼æ¾ç¤ºå·¡æ£èå |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="form-page"> |
| | | <CardTitle :title="pageTitle" :hideAction="false" /> |
| | | |
| | | <!-- æºçï¼ä¸ä¸æ¥å·²æ«ç é¢ç¨ï¼è¿éåªåå±ç¤º --> |
| | | <view class="section"> |
| | | <view class="section-title">æºçï¼æåï¼</view> |
| | | <view class="card source-card"> |
| | | <view class="kv"> |
| | | <text class="kv-label">çå·</text> |
| | | <text class="kv-value">{{ source.batchCode || "-" }}</text> |
| | | </view> |
| | | <view class="kv"> |
| | | <text class="kv-label">è§æ ¼åå·</text> |
| | | <text class="kv-value">{{ source.model || "-" }}</text> |
| | | </view> |
| | | <view class="kv"> |
| | | <text class="kv-label">é¿åº¦(m)</text> |
| | | <text class="kv-value">{{ source.currentLength ?? "-" }}</text> |
| | | </view> |
| | | <view class="kv"> |
| | | <text class="kv-label">éé(kg)</text> |
| | | <text class="kv-value">{{ source.currentWeight ?? "-" }}</text> |
| | | </view> |
| | | <view class="kv"> |
| | | <text class="kv-label">ç±³é(kg/km)</text> |
| | | <text class="kv-value">{{ source.meterWeight ?? "-" }}</text> |
| | | </view> |
| | | <view class="kv"> |
| | | <text class="kv-label">ç¶æ</text> |
| | | <text class="kv-value ok"> |
| | | {{ source.qualityStatus || "-" }} · {{ source.enableStatus || "-" }} |
| | | </text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- åç / ç®æ ç --> |
| | | <view class="section"> |
| | | <view class="section-title">{{ isRewind ? "ç®æ ç" : "åç" }}</view> |
| | | |
| | | <view v-for="(target, index) in targets" :key="index" class="card target-card"> |
| | | <view class="row"> |
| | | <text class="row-label">{{ isRewind ? "ç®æ ç" : `åç${index + 1}` }}</text> |
| | | <view class="row-value"> |
| | | <wd-input v-model="target.length" type="number" no-border placeholder="请è¾å
¥é¿åº¦(m)" /> |
| | | </view> |
| | | <text class="row-unit">ç±³</text> |
| | | <view v-if="!isRewind" class="row-btns"> |
| | | <wd-button size="small" plain :round="false" type="error" @click="removeTarget(index)"> |
| | | å é¤ |
| | | </wd-button> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="row"> |
| | | <text class="row-label">é¢ç¨çå
·</text> |
| | | <view class="row-value"> |
| | | <wd-input |
| | | v-model="target.codeInput" |
| | | no-border |
| | | clearable |
| | | :placeholder="dishPlaceholder" |
| | | /> |
| | | </view> |
| | | </view> |
| | | <view class="row-btns"> |
| | | <wd-button size="small" plain :round="false" @click="scanDish(index)"> |
| | | æ«ç éæ©çå
· |
| | | </wd-button> |
| | | <wd-button size="small" plain :round="false" @click="searchDish(index)">æ¥è¯¢</wd-button> |
| | | </view> |
| | | |
| | | <view v-if="target.dishCode" class="kv"> |
| | | <text class="kv-label">çå
·è§æ ¼</text> |
| | | <text class="kv-value"> |
| | | {{ target.dishModel || "-" }} |
| | | <text v-if="target.dishWeight !== undefined && target.dishWeight !== null"> |
| | | · {{ target.dishWeight }}kg |
| | | </text> |
| | | </text> |
| | | </view> |
| | | <view class="kv"> |
| | | <text class="kv-label">{{ isRewind ? "ç®æ çå·" : "åççå·" }}</text> |
| | | <view class="chip-switch"> |
| | | <view |
| | | v-for="opt in batchCodeOptions" |
| | | :key="String(opt.value)" |
| | | class="chip-item" |
| | | :class="{ 'chip-item-active': target.useCurrentBatchCode === opt.value }" |
| | | @click="selectBatchCodeMode(index, opt.value)" |
| | | > |
| | | {{ opt.label }} |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view class="kv"> |
| | | <text class="kv-label">å®é
çå·</text> |
| | | <text class="kv-value">{{ targetBatchCode(index) || "æäº¤åèªå¨çæ" }}</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <view v-if="!isRewind" class="add-target" @click="addTarget">+ æ·»å åç</view> |
| | | </view> |
| | | |
| | | <!-- æä½äºº --> |
| | | <view class="section"> |
| | | <view class="section-title">æä½äºº</view> |
| | | <view class="card"> |
| | | <wd-select-picker |
| | | v-model="operatorName" |
| | | type="radio" |
| | | :columns="userOptions" |
| | | label="æä½äºº" |
| | | label-width="100px" |
| | | filterable |
| | | filter-placeholder="æç´¢äººå" |
| | | placeholder="è¯·éæ©æä½äºº" |
| | | :loading="userLoading" |
| | | :z-index="30" |
| | | /> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 夿³¨ --> |
| | | <view class="section"> |
| | | <view class="section-title">夿³¨</view> |
| | | <view class="card"> |
| | | <wd-textarea v-model="remark" placeholder="å¯é夿³¨" :maxlength="200" show-word-limit /> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="footer"> |
| | | <wd-button block :round="false" :loading="submitting" @click="submit"> |
| | | <text class="text-[#fff]">æäº¤</text> |
| | | </wd-button> |
| | | </view> |
| | | |
| | | <Scan ref="scanRef" emitName="scanInventoryDish" /> |
| | | <wd-toast /> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import CardTitle from "@/components/card-title/index.vue"; |
| | | import Scan from "@/components/scan/index.vue"; |
| | | import { useToast } from "wot-design-uni"; |
| | | import { onLoad, onUnload, onShow, onHide } from "@dcloudio/uni-app"; |
| | | import InventoryOperationApi from "@/api/product/inventoryOperation"; |
| | | import UserAPI from "@/api/system/user"; |
| | | import { useUserStore } from "@/store/modules/user"; |
| | | import { MOCK_BOBBIN, MOCK_ENABLED } from "./mock"; |
| | | import { |
| | | DISH_CODE_KEYS, |
| | | MATERIAL_TYPE_FG, |
| | | OP_SPLIT, |
| | | OP_STRAND_REWIND, |
| | | SOURCE_STORAGE_KEY, |
| | | findBobbin, |
| | | isBobbinReceived, |
| | | parseScanCode, |
| | | pickValue, |
| | | } from "./shared"; |
| | | |
| | | interface TargetItem { |
| | | /** ç®æ é¿åº¦(m) */ |
| | | length: any; |
| | | /** é¢ç¨çå
·ç¼å·ï¼çå
·ç§°éå°è´¦çç§°éç¼å·ï¼ */ |
| | | dishCode: string; |
| | | dishModel: string; |
| | | dishWeight: any; |
| | | /** çå
·ç¼å·è¾å
¥æ¡ */ |
| | | codeInput: string; |
| | | /** è¯¥çæ¯å¦æ²¿ç¨åçå·ï¼æçæ¶æå¤ä¸çå¯ä»¥æ²¿ç¨ï¼ */ |
| | | useCurrentBatchCode: boolean; |
| | | } |
| | | |
| | | const createTarget = (length: any = "", useCurrentBatchCode = false): TargetItem => ({ |
| | | length, |
| | | dishCode: "", |
| | | dishModel: "", |
| | | dishWeight: undefined, |
| | | codeInput: "", |
| | | useCurrentBatchCode, |
| | | }); |
| | | |
| | | const toast = useToast(); |
| | | const scanRef = ref(); |
| | | const operationType = ref(OP_SPLIT); |
| | | const isRewind = computed(() => operationType.value === OP_STRAND_REWIND); |
| | | const pageTitle = computed(() => (isRewind.value ? "ç»çº¿å¤ç»" : "æåæç")); |
| | | |
| | | /** æºçï¼æ¥èªä¸ä¸æ¥æ«ç é¢ç¨ */ |
| | | const source = ref<any>({}); |
| | | // 第ä¸ä¸ªçé»è®¤æ²¿ç¨åçå·ï¼å¤ç»æ´ç沿ç¨ï¼ï¼åç»æ·»å çåçé»è®¤çææ°çå· |
| | | const targets = ref<TargetItem[]>([createTarget("", true)]); |
| | | /** çå·æ¨¡å¼ï¼æ¯ä¸ªçåç¬é */ |
| | | const batchCodeOptions = [ |
| | | { label: "沿ç¨åçå·", value: true }, |
| | | { label: "çææ°çå·", value: false }, |
| | | ]; |
| | | const remark = ref(""); |
| | | const submitting = ref(false); |
| | | const isPageVisible = ref(true); |
| | | |
| | | /* ==================== æä½äºº ==================== */ |
| | | const userStore = useUserStore(); |
| | | /** æä½äººï¼é»è®¤å½åç»å½äººï¼å¯æ¹æå
¶å®äººå */ |
| | | const operatorName = ref(""); |
| | | const userOptions = ref<{ label: string; value: string }[]>([]); |
| | | const userLoading = ref(false); |
| | | |
| | | const loadUserOptions = async () => { |
| | | if (userLoading.value) return; |
| | | userLoading.value = true; |
| | | try { |
| | | const { code, data } = await UserAPI.getUserSelect(); |
| | | if (code === 200) { |
| | | const names = (data || []) |
| | | .map((item: any) => String(item?.nickName || item?.nickname || item?.userName || "").trim()) |
| | | .filter(Boolean); |
| | | userOptions.value = Array.from(new Set<string>(names)).map((name) => ({ |
| | | label: name, |
| | | value: name, |
| | | })); |
| | | } |
| | | } catch (error) { |
| | | // äººåæ¥å£å¼å¸¸æ¶ä¸é»å¡åçï¼æä½äººä»ä¿çå½åç»å½äºº |
| | | } finally { |
| | | userLoading.value = false; |
| | | } |
| | | }; |
| | | |
| | | /** æ¨¡ææ¨¡å¼ä¸é»è®¤å¸¦åºä¸æ¡çå
·ï¼è¾å
¥æ¡éç»åºé»è®¤çå
·ç¼å·æç¤º */ |
| | | const dishPlaceholder = computed(() => |
| | | MOCK_ENABLED ? `æ«ç æè¾å
¥çå
·ç¼å·ï¼å¦ ${MOCK_BOBBIN.weighingCode}` : "æ«ç æè¾å
¥çå
·ç¼å·" |
| | | ); |
| | | |
| | | /** æ«ç ç®æ ï¼æä¸ªç®æ ç/åççé¢ç¨çå
· */ |
| | | const scanDishIndex = ref<number | null>(null); |
| | | |
| | | /* ==================== é¢ç¨çå
· ==================== */ |
| | | const applyDishCode = async (index: number, code: string, options: { silent?: boolean } = {}) => { |
| | | const target = targets.value[index]; |
| | | if (!target) return false; |
| | | |
| | | if (targets.value.some((item, i) => i !== index && String(item.dishCode ?? "") === code)) { |
| | | toast.error("该çå
·å·²è¢«æ¬åå
¶å®ç使ç¨ï¼è¯·æ´æ¢çå
·"); |
| | | return false; |
| | | } |
| | | |
| | | const { record, mocked } = await findBobbin(code); |
| | | if (!record) { |
| | | toast.error("çå
·ç§°éå°è´¦ä¸æªæ¾å°è¯¥çå
·ï¼è¯·å
å¨çå
·ç§°éå°è´¦ä¸ç§°é"); |
| | | return false; |
| | | } |
| | | if (isBobbinReceived(record)) { |
| | | toast.error("该çå
·å·²è¢«é¢ç¨ï¼è¯·æ´æ¢çå
·"); |
| | | return false; |
| | | } |
| | | |
| | | target.dishCode = String(record.weighingCode ?? code).trim(); |
| | | target.dishModel = record.specificationModel ?? ""; |
| | | target.dishWeight = record.weight; |
| | | target.codeInput = target.dishCode; |
| | | if (!options.silent) { |
| | | toast.success(mocked ? "æªåå°ç宿°æ®ï¼ä½¿ç¨æ¨¡æçå
·æ°æ®" : "çå
·å·²éæ©"); |
| | | } |
| | | return true; |
| | | }; |
| | | |
| | | const searchDish = async (index: number) => { |
| | | const code = String(targets.value[index]?.codeInput ?? "").trim(); |
| | | if (!code) { |
| | | toast.error("请è¾å
¥ææ«æçå
·ç¼å·"); |
| | | return; |
| | | } |
| | | try { |
| | | await applyDishCode(index, code); |
| | | } catch (error) { |
| | | // 请æ±å±å·²ç»ä¸æç¤º |
| | | } |
| | | }; |
| | | |
| | | const scanDish = (index: number) => { |
| | | scanDishIndex.value = index; |
| | | // #ifdef APP-PLUS |
| | | scanRef.value?.triggerScan(); |
| | | // #endif |
| | | // #ifndef APP-PLUS |
| | | toast.warning("å½åç¯å¢ä¸æ¯æç¡¬ä»¶æ«ç ï¼è¯·ç¨è¾å
¥æ¡æå¨æ¥è¯¢çå
·ç¼å·"); |
| | | // #endif |
| | | }; |
| | | |
| | | /* ==================== ç®æ ç ==================== */ |
| | | /** 该ççå·ï¼éäºã沿ç¨åçå·ãå°±ç¨æºççå·ï¼å¦åæäº¤ç©ºå¼ç±åç«¯çææ°çå· */ |
| | | const targetBatchCode = (index: number) => { |
| | | const target = targets.value[index]; |
| | | return target?.useCurrentBatchCode ? source.value?.batchCode || "" : ""; |
| | | }; |
| | | |
| | | /** 沿ç¨åçå·æå¤åªè½æä¸çï¼æä¸çéäºï¼å
¶å®çèªå¨æ¹åçææ°çå· */ |
| | | const selectBatchCodeMode = (index: number, value: boolean) => { |
| | | const target = targets.value[index]; |
| | | if (!target) return; |
| | | target.useCurrentBatchCode = value; |
| | | if (!value) return; |
| | | targets.value.forEach((item, i) => { |
| | | if (i !== index) item.useCurrentBatchCode = false; |
| | | }); |
| | | }; |
| | | |
| | | const addTarget = () => { |
| | | // æ°å¢çåçé»è®¤ãçææ°çå·ã |
| | | targets.value.push(createTarget()); |
| | | }; |
| | | |
| | | const removeTarget = (index: number) => { |
| | | targets.value.splice(index, 1); |
| | | if (targets.value.length === 0) { |
| | | targets.value.push(createTarget("", true)); |
| | | } |
| | | }; |
| | | |
| | | /* ==================== æ«ç åè°ï¼åªå¤ççå
·ï¼ ==================== */ |
| | | const getScanCode = async (payload: any) => { |
| | | if (!isPageVisible.value) return; |
| | | const index = scanDishIndex.value; |
| | | if (index === null) return; |
| | | |
| | | const parsed = parseScanCode(payload); |
| | | if (!parsed) { |
| | | toast.error("æ«ç å
容为空ï¼è¯·éæ°æ«ç "); |
| | | return; |
| | | } |
| | | const code = pickValue(parsed, DISH_CODE_KEYS); |
| | | if (!code) { |
| | | toast.error("äºç»´ç æ æ³è¯å«çå
·ç¼å·ï¼è¯·æ´æ¢äºç»´ç "); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | await applyDishCode(index, code); |
| | | } catch (error) { |
| | | // 请æ±å±å·²ç»ä¸æç¤º |
| | | } finally { |
| | | scanDishIndex.value = null; |
| | | } |
| | | }; |
| | | |
| | | /* ==================== æäº¤ ==================== */ |
| | | const submit = async () => { |
| | | if (!source.value?.batchCode) { |
| | | toast.error("æªè·åå°æºçä¿¡æ¯ï¼è¯·è¿åéæ°æ«ç "); |
| | | return; |
| | | } |
| | | if (targets.value.length === 0) { |
| | | toast.error(isRewind.value ? "请添å ç®æ ç" : "请è³å°æ·»å ä¸ä¸ªåç"); |
| | | return; |
| | | } |
| | | if (isRewind.value && targets.value.length > 1) { |
| | | toast.error("ç»çº¿å¤ç»åªçæä¸ç"); |
| | | return; |
| | | } |
| | | |
| | | for (let i = 0; i < targets.value.length; i++) { |
| | | const target = targets.value[i]; |
| | | const label = isRewind.value ? "ç®æ ç" : `åç${i + 1}`; |
| | | if (!target.length || Number(target.length) <= 0) { |
| | | toast.error(`${label}ï¼è¯·è¾å
¥é¿åº¦`); |
| | | return; |
| | | } |
| | | // æ¯ä¸ä¸ªæ°çï¼åç/ç®æ çï¼é½å¿
须鿩é¢ç¨çå
· |
| | | if (!target.dishCode) { |
| | | toast.error(`${label}ï¼è¯·æ«ç éæ©é¢ç¨çå
·`); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | const totalLength = targets.value.reduce((sum, item) => sum + Number(item.length || 0), 0); |
| | | const sourceLength = Number(source.value?.currentLength || 0); |
| | | if (sourceLength > 0 && totalLength > sourceLength) { |
| | | toast.error( |
| | | isRewind.value |
| | | ? `ç®æ çé¿åº¦(${totalLength})ä¸è½è¶
è¿æºçé¿åº¦(${sourceLength})` |
| | | : `åçé¿åº¦ä¹å(${totalLength})è¶
è¿æºçé¿åº¦(${sourceLength})` |
| | | ); |
| | | return; |
| | | } |
| | | |
| | | const sources = [ |
| | | { |
| | | batchCode: source.value.batchCode, |
| | | materialType: MATERIAL_TYPE_FG, |
| | | model: source.value.model, |
| | | length: sourceLength || undefined, |
| | | weight: source.value.currentWeight || undefined, |
| | | meterWeight: source.value.meterWeight, |
| | | sortOrder: 1, |
| | | }, |
| | | ]; |
| | | const targetDtos = targets.value.map((item, index) => ({ |
| | | // åçå¯é沿ç¨åçå·ï¼å
¶ä½æäº¤ç©ºå¼ç±åç«¯çææ°çå· |
| | | batchCode: targetBatchCode(index), |
| | | // é¢ç¨ççå
·ç¼å· |
| | | dishCode: String(item.dishCode ?? "").trim(), |
| | | materialType: MATERIAL_TYPE_FG, |
| | | model: source.value.model, |
| | | length: Number(item.length), |
| | | meterWeight: source.value.meterWeight, |
| | | sortOrder: index + 1, |
| | | })); |
| | | |
| | | submitting.value = true; |
| | | try { |
| | | const { code, msg } = await InventoryOperationApi.createOperation({ |
| | | operationType: operationType.value, |
| | | remark: remark.value, |
| | | // æä½äººï¼äººåéæ©ï¼é»è®¤å½åç»å½äººï¼ |
| | | createUserName: operatorName.value, |
| | | sources, |
| | | targets: targetDtos, |
| | | }); |
| | | if (code === 200) { |
| | | toast.success("æäº¤æå"); |
| | | uni.removeStorageSync(SOURCE_STORAGE_KEY); |
| | | setTimeout(() => uni.navigateBack(), 600); |
| | | } else { |
| | | toast.error(msg || "æäº¤å¤±è´¥"); |
| | | } |
| | | } catch (error) { |
| | | // 请æ±å±å·²ç»ä¸æç¤º |
| | | } finally { |
| | | submitting.value = false; |
| | | } |
| | | }; |
| | | |
| | | onLoad(async (options: any) => { |
| | | operationType.value = options?.type === OP_STRAND_REWIND ? OP_STRAND_REWIND : OP_SPLIT; |
| | | |
| | | // æä½äººé»è®¤å½åç»å½äººï¼äººååè¡¨å¼æ¥å è½½å坿¹é |
| | | const info: any = userStore.userInfo; |
| | | operatorName.value = info?.nickname || info?.nickName || info?.userName || ""; |
| | | loadUserOptions(); |
| | | |
| | | const cached = uni.getStorageSync(SOURCE_STORAGE_KEY); |
| | | if (cached && cached.batchCode) { |
| | | source.value = { ...cached }; |
| | | // ç»çº¿å¤ç»æ¯æ´çå¤ç»ï¼ç®æ çé¿åº¦é»è®¤ä¸æºçä¸è´ |
| | | if (isRewind.value) { |
| | | targets.value[0].length = cached.currentLength ?? ""; |
| | | } |
| | | // æ¨¡ææ¨¡å¼ä¸é»è®¤å¸¦åºä¸æ¡çå
·æ°æ®ï¼æ¹ä¾¿ç´æ¥è·éæäº¤ |
| | | if (MOCK_ENABLED && MOCK_BOBBIN.weighingCode) { |
| | | await applyDishCode(0, MOCK_BOBBIN.weighingCode, { silent: true }); |
| | | } |
| | | } else { |
| | | toast.error("æªè·åå°æºçä¿¡æ¯ï¼è¯·è¿åéæ°æ«ç é¢ç¨"); |
| | | setTimeout(() => uni.navigateBack(), 1000); |
| | | } |
| | | |
| | | uni.$off("scanInventoryDish", getScanCode); |
| | | uni.$on("scanInventoryDish", getScanCode); |
| | | }); |
| | | |
| | | onShow(() => { |
| | | isPageVisible.value = true; |
| | | }); |
| | | |
| | | onHide(() => { |
| | | isPageVisible.value = false; |
| | | }); |
| | | |
| | | onUnload(() => { |
| | | uni.$off("scanInventoryDish", getScanCode); |
| | | isPageVisible.value = false; |
| | | // 离å¼åç页峿¸
ææºçç¼åï¼ä¸æ¬¡ä»éç±»åéæ°å¼å§ |
| | | uni.removeStorageSync(SOURCE_STORAGE_KEY); |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .form-page { |
| | | min-height: 100vh; |
| | | padding: 12px 12px 96px; |
| | | background: #f3f9f8; |
| | | } |
| | | |
| | | .section { |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .section-title { |
| | | margin-bottom: 8px; |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #252525; |
| | | } |
| | | |
| | | .card { |
| | | padding: 12px; |
| | | background: #ffffff; |
| | | border: 1px solid #e6e6e6; |
| | | border-radius: 6px; |
| | | } |
| | | |
| | | .source-card { |
| | | border-color: #0d867f; |
| | | } |
| | | |
| | | .target-card { |
| | | margin-bottom: 10px; |
| | | border-color: #cfe8e5; |
| | | } |
| | | |
| | | .row { |
| | | display: flex; |
| | | align-items: center; |
| | | min-height: 40px; |
| | | } |
| | | |
| | | .row-label { |
| | | flex-shrink: 0; |
| | | width: 72px; |
| | | font-size: 13px; |
| | | color: #646874; |
| | | } |
| | | |
| | | .row-value { |
| | | flex: 1; |
| | | min-width: 0; |
| | | } |
| | | |
| | | .row-unit { |
| | | margin-left: 4px; |
| | | font-size: 13px; |
| | | color: #646874; |
| | | } |
| | | |
| | | .row-btns { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | margin-top: 6px; |
| | | |
| | | :deep(.wd-button) { |
| | | margin-left: 8px; |
| | | } |
| | | } |
| | | |
| | | .kv { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-top: 6px; |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .kv-label { |
| | | width: 88px; |
| | | color: #646874; |
| | | } |
| | | |
| | | .kv-value { |
| | | flex: 1; |
| | | color: #252525; |
| | | } |
| | | |
| | | .ok { |
| | | color: #0d867f; |
| | | } |
| | | |
| | | .batch-code-mode { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .chip-switch { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .chip-item { |
| | | margin-right: 8px; |
| | | padding: 5px 14px; |
| | | font-size: 13px; |
| | | line-height: 20px; |
| | | color: #0d867f; |
| | | background: #ffffff; |
| | | border: 1px solid #0d867f; |
| | | border-radius: 16px; |
| | | |
| | | &:last-child { |
| | | margin-right: 0; |
| | | } |
| | | } |
| | | |
| | | .chip-item-active { |
| | | color: #ffffff; |
| | | background: #0d867f; |
| | | } |
| | | |
| | | .mode-hint { |
| | | margin-bottom: 10px; |
| | | font-size: 12px; |
| | | color: #8a8a8a; |
| | | } |
| | | |
| | | .add-target { |
| | | height: 36px; |
| | | font-size: 14px; |
| | | line-height: 36px; |
| | | color: #0d867f; |
| | | text-align: center; |
| | | border: 1px dashed #0d867f; |
| | | border-radius: 6px; |
| | | } |
| | | |
| | | .footer { |
| | | position: fixed; |
| | | right: 0; |
| | | bottom: 0; |
| | | left: 0; |
| | | z-index: 20; |
| | | padding: 8px 12px calc(8px + env(safe-area-inset-bottom)); |
| | | background: #ffffff; |
| | | border-top: 1px solid #eeeeee; |
| | | box-shadow: 0 -2px 10px rgb(0 0 0 / 6%); |
| | | |
| | | :deep(.wd-button) { |
| | | --wot-button-primary-bg-color: #0d867f; |
| | | } |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="choose-page"> |
| | | <CardTitle title="åºåæä½" :hideAction="false" /> |
| | | |
| | | <!-- 两个大æé®ï¼æåæç / ç»çº¿å¤ç» --> |
| | | <view |
| | | v-for="opt in OPERATION_TYPES" |
| | | :key="opt.value" |
| | | class="type-card" |
| | | :class="{ 'type-card-active': pendingType === opt.value }" |
| | | @click="chooseType(opt.value)" |
| | | > |
| | | <view class="type-icon"> |
| | | <wd-icon :name="opt.icon" size="26px" color="#0D867F"></wd-icon> |
| | | </view> |
| | | <view class="type-body"> |
| | | <view class="type-title">{{ opt.label }}</view> |
| | | <view class="type-desc">{{ opt.desc }}</view> |
| | | </view> |
| | | <wd-icon name="arrow-right" size="16px" color="#C8C8C8"></wd-icon> |
| | | </view> |
| | | |
| | | <!-- æ«ç é¢ç¨æºç --> |
| | | <view class="scan-panel"> |
| | | <view v-if="pendingType" class="scan-status"> |
| | | <wd-icon name="scan" size="16px" color="#0D867F"></wd-icon> |
| | | <text class="scan-text">æ£å¨æ«ç é¢ç¨æºçï¼{{ currentTypeLabel }}ï¼ï¼æ«å°åè¿å
¥åç</text> |
| | | </view> |
| | | <view v-else class="scan-status"> |
| | | <wd-icon name="scan" size="16px" color="#9A9A9A"></wd-icon> |
| | | <text class="scan-text scan-text-idle">ç¹å»ä¸æ¹æé®åç´æ¥æ«ç é¢ç¨æºç</text> |
| | | </view> |
| | | |
| | | <!-- æ«ç æªä¸å¯ç¨æ¶çæå¨å
åº --> |
| | | <view class="manual-row"> |
| | | <view class="manual-input"> |
| | | <wd-input |
| | | v-model="manualCode" |
| | | no-border |
| | | clearable |
| | | placeholder="ææå¨è¾å
¥æåçå·ï¼å¦ 74082609001" |
| | | /> |
| | | </view> |
| | | </view> |
| | | <view class="manual-btns"> |
| | | <wd-button size="small" plain :round="false" @click="scanSource">æ«ç </wd-button> |
| | | <wd-button size="small" plain :round="false" @click="searchManual">æ¥è¯¢å¹¶è¿å
¥</wd-button> |
| | | </view> |
| | | </view> |
| | | |
| | | <Scan ref="scanRef" emitName="scanInventorySource" /> |
| | | <wd-toast /> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import CardTitle from "@/components/card-title/index.vue"; |
| | | import Scan from "@/components/scan/index.vue"; |
| | | import { useToast } from "wot-design-uni"; |
| | | import { onLoad, onUnload, onShow, onHide } from "@dcloudio/uni-app"; |
| | | import { |
| | | OPERATION_TYPES, |
| | | OP_SPLIT, |
| | | REEL_CODE_KEYS, |
| | | SOURCE_STORAGE_KEY, |
| | | findSourceStock, |
| | | parseScanCode, |
| | | pickValue, |
| | | } from "./shared"; |
| | | |
| | | const toast = useToast(); |
| | | const scanRef = ref(); |
| | | /** å·²éä¸çæä½ç±»åï¼ä¸ºç©ºè¡¨ç¤ºè¿æ²¡ç¹æé® */ |
| | | const pendingType = ref(""); |
| | | const manualCode = ref(""); |
| | | /** 鲿¢æ«ç éå¤è§¦å */ |
| | | const submitting = ref(false); |
| | | const isPageVisible = ref(true); |
| | | |
| | | const currentTypeLabel = computed( |
| | | () => OPERATION_TYPES.find((opt) => opt.value === pendingType.value)?.label || "" |
| | | ); |
| | | |
| | | /** ç¹å»å¤§æé®ï¼è®°å½ç±»åå¹¶ç«å³æ«ç é¢ç¨æºç */ |
| | | const chooseType = (type: string) => { |
| | | pendingType.value = type; |
| | | manualCode.value = ""; |
| | | scanSource(); |
| | | }; |
| | | |
| | | const scanSource = () => { |
| | | if (!pendingType.value) { |
| | | toast.warning("请å
éæ©æåæçæç»çº¿å¤ç»"); |
| | | return; |
| | | } |
| | | // #ifdef APP-PLUS |
| | | scanRef.value?.triggerScan(); |
| | | // #endif |
| | | // #ifndef APP-PLUS |
| | | toast.warning("å½åç¯å¢ä¸æ¯æç¡¬ä»¶æ«ç ï¼è¯·ç¨ä¸æ¹è¾å
¥æ¡æå¨æ¥è¯¢"); |
| | | // #endif |
| | | }; |
| | | |
| | | const searchManual = () => { |
| | | const code = String(manualCode.value ?? "").trim(); |
| | | if (!code) { |
| | | toast.error("请è¾å
¥æåçå·"); |
| | | return; |
| | | } |
| | | applySourceCode(code); |
| | | }; |
| | | |
| | | /** é¢ç¨æºçï¼æ ¡éªéè¿åå¸¦çæºçä¿¡æ¯è¿å
¥åç页 */ |
| | | const applySourceCode = async (code: string) => { |
| | | if (submitting.value) return; |
| | | submitting.value = true; |
| | | try { |
| | | const { record, mocked } = await findSourceStock(code); |
| | | if (!record) { |
| | | toast.error(`æªæ¾å°æåçå· ${code} çåºå`); |
| | | return; |
| | | } |
| | | if (!(record.enableStatus === "å¯ç¨" && record.qualityStatus === "åæ ¼")) { |
| | | toast.error( |
| | | `该çç¶æä¸å¯ç¨ï¼${record.qualityStatus || "-"}·${record.enableStatus || "-"}ï¼ï¼è¯·æ´æ¢æºç` |
| | | ); |
| | | return; |
| | | } |
| | | |
| | | // æºçä¿¡æ¯éè¿æ¬å°ç¼åä¼ ç»åç页 |
| | | uni.setStorageSync(SOURCE_STORAGE_KEY, { ...record, code, mocked }); |
| | | if (mocked) { |
| | | toast.success("æ¥å£æªèè°ï¼ä½¿ç¨æ¨¡ææºçæ°æ®"); |
| | | } else { |
| | | toast.success("æºçé¢ç¨æå"); |
| | | } |
| | | setTimeout(() => { |
| | | uni.navigateTo({ |
| | | url: `/pages/production/inventory/form?type=${pendingType.value || OP_SPLIT}`, |
| | | }); |
| | | }, 300); |
| | | } catch (error) { |
| | | // 请æ±å±å·²ç»ä¸æç¤º |
| | | } finally { |
| | | submitting.value = false; |
| | | } |
| | | }; |
| | | |
| | | /** æ«ç åè°ï¼ææ«å°çå
容彿æºççå· */ |
| | | const getScanCode = async (payload: any) => { |
| | | if (!isPageVisible.value || !pendingType.value) return; |
| | | const parsed = parseScanCode(payload); |
| | | if (!parsed) { |
| | | toast.error("æ«ç å
容为空ï¼è¯·éæ°æ«ç "); |
| | | return; |
| | | } |
| | | const code = pickValue(parsed, REEL_CODE_KEYS); |
| | | if (!code) { |
| | | toast.error("äºç»´ç æ æ³è¯å«çå·ï¼è¯·æ´æ¢äºç»´ç "); |
| | | return; |
| | | } |
| | | await applySourceCode(code); |
| | | }; |
| | | |
| | | onLoad(() => { |
| | | // æ¯æ¬¡è¿æ¥é½ä»ãæªéç±»åãå¼å§ï¼é¿å
ç¨å°ä¸ä¸æ¬¡çç¼å |
| | | uni.removeStorageSync(SOURCE_STORAGE_KEY); |
| | | uni.$off("scanInventorySource", getScanCode); |
| | | uni.$on("scanInventorySource", getScanCode); |
| | | }); |
| | | |
| | | onShow(() => { |
| | | isPageVisible.value = true; |
| | | }); |
| | | |
| | | onHide(() => { |
| | | isPageVisible.value = false; |
| | | }); |
| | | |
| | | onUnload(() => { |
| | | uni.$off("scanInventorySource", getScanCode); |
| | | isPageVisible.value = false; |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .choose-page { |
| | | min-height: 100vh; |
| | | padding: 12px; |
| | | background: #f3f9f8; |
| | | } |
| | | |
| | | .type-card { |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 20px 16px; |
| | | margin-bottom: 14px; |
| | | background: #ffffff; |
| | | border: 1px solid #e2ecea; |
| | | border-radius: 10px; |
| | | box-shadow: 0 2px 8px rgb(13 134 127 / 6%); |
| | | } |
| | | |
| | | .type-card-active { |
| | | border-color: #0d867f; |
| | | box-shadow: 0 2px 12px rgb(13 134 127 / 18%); |
| | | } |
| | | |
| | | .type-icon { |
| | | display: flex; |
| | | flex-shrink: 0; |
| | | align-items: center; |
| | | justify-content: center; |
| | | width: 48px; |
| | | height: 48px; |
| | | margin-right: 14px; |
| | | background: #e7f4f2; |
| | | border-radius: 50%; |
| | | } |
| | | |
| | | .type-body { |
| | | flex: 1; |
| | | min-width: 0; |
| | | } |
| | | |
| | | .type-title { |
| | | font-size: 17px; |
| | | font-weight: 600; |
| | | color: #252525; |
| | | } |
| | | |
| | | .type-desc { |
| | | margin-top: 4px; |
| | | font-size: 12px; |
| | | color: #8a8a8a; |
| | | } |
| | | |
| | | .scan-panel { |
| | | padding: 14px 16px; |
| | | background: #ffffff; |
| | | border: 1px solid #e2ecea; |
| | | border-radius: 10px; |
| | | } |
| | | |
| | | .scan-status { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .scan-text { |
| | | margin-left: 6px; |
| | | font-size: 13px; |
| | | color: #0d867f; |
| | | } |
| | | |
| | | .scan-text-idle { |
| | | color: #9a9a9a; |
| | | } |
| | | |
| | | .manual-row { |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .manual-input { |
| | | display: flex; |
| | | align-items: center; |
| | | height: 36px; |
| | | padding: 0 10px; |
| | | background: #f7faf9; |
| | | border: 1px solid #e2ecea; |
| | | border-radius: 6px; |
| | | } |
| | | |
| | | .manual-btns { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | margin-top: 8px; |
| | | |
| | | :deep(.wd-button) { |
| | | margin-left: 8px; |
| | | } |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | /** |
| | | * ä¸´æ¶æ¨¡ææ°æ® |
| | | * |
| | | * èæ¯ï¼ãåºåæä½ãï¼æåæç / ç»çº¿å¤ç»ï¼ä¾èµçæååºåãçå
·ç§°éå°è´¦æ¥å£ |
| | | * å°æªèè°å®æï¼è¿éå
ç»ä¸æ¡æºç + 䏿¡çå
·çæ¨¡ææ°æ®ï¼ç¨æ¥æ |
| | | * ãé¦é¡µ â éç±»å â æ«ç é¢ç¨æºç â åçåç/çå
· â æäº¤ãæ´æ¡æµç¨è·éã |
| | | * |
| | | * èè°å®æåï¼æ MOCK_ENABLED æ¹æ falseï¼æå 餿¬æä»¶å¹¶æ¸
ç shared.ts ä¸çå¼ç¨ï¼ã |
| | | */ |
| | | export const MOCK_ENABLED = true; |
| | | |
| | | /** æ¨¡ææºçï¼æååºåï¼ï¼æ«ç æªä¸å¯ç¨æ¶ï¼å¯ç¨è¿ä¸ªç巿卿¥è¯¢ */ |
| | | export const MOCK_SOURCE_STOCK = { |
| | | batchCode: "74082609001", |
| | | materialType: "æå", |
| | | model: "JL3-GIA-630-45", |
| | | materialName: "ç»çº¿æå", |
| | | currentLength: 5000, |
| | | currentWeight: 1268.5, |
| | | meterWeight: 253.7, |
| | | qualityStatus: "åæ ¼", |
| | | enableStatus: "å¯ç¨", |
| | | ncReturnFlag: "Y", |
| | | createUserName: "admin", |
| | | }; |
| | | |
| | | /** |
| | | * 模æçå
·ï¼çå
·ç§°éå°è´¦ï¼ï¼ |
| | | * - è¿å
¥åç页æ¶é»è®¤å¸¦åºè¿ä¸æ¡çå
·ï¼å¯ç´æ¥æäº¤ï¼ |
| | | * - æè¾/æ«å°å
¶å®ç¼å·æ¶ï¼é¤ç¼å·å¤çåæ®µæ²¿ç¨æ¬æ¡ï¼æ¹ä¾¿ä¸ä¸ªååæµå¤ä¸ªçå
·ï¼ã |
| | | */ |
| | | export const MOCK_BOBBIN = { |
| | | id: 900001, |
| | | weighingCode: "260922-1", |
| | | specificationModel: "JLB1A-3.73", |
| | | diskMaterial: "é¢è´¨", |
| | | weight: 1820.5, |
| | | weighingTime: "2026-09-22 09:15:00", |
| | | received: 0, |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import InventoryOperationApi from "@/api/product/inventoryOperation"; |
| | | import TwistApi from "@/api/product/twist"; |
| | | import { MOCK_BOBBIN, MOCK_ENABLED, MOCK_SOURCE_STOCK } from "./mock"; |
| | | |
| | | /** æä½ç±»å */ |
| | | export const OP_SPLIT = "SPLIT"; |
| | | export const OP_STRAND_REWIND = "STRAND_REWIND"; |
| | | |
| | | /** ç©æç±»åï¼æºçä¸ç®æ çé½èµ°ãæåãï¼ä¸ PC 端æåæçä¸è´ï¼ */ |
| | | export const MATERIAL_TYPE_FG = "æå"; |
| | | |
| | | /** ä¸ä¸æ¥æ«ç é¢ç¨å°çæºçï¼éè¿æ¬å°ç¼åä¼ ç»åç页 */ |
| | | export const SOURCE_STORAGE_KEY = "inventoryOperationSourceReel"; |
| | | |
| | | /** å¯éçä¸¤ç§æä½ */ |
| | | export const OPERATION_TYPES = [ |
| | | { |
| | | value: OP_SPLIT, |
| | | label: "æåæç", |
| | | desc: "ä¸ä¸ªæºçææå¤ä¸ªåç", |
| | | icon: "fork", |
| | | }, |
| | | { |
| | | value: OP_STRAND_REWIND, |
| | | label: "ç»çº¿å¤ç»", |
| | | desc: "æ´çå¤ç»ï¼å¯æ²¿ç¨åçå·æçææ°çå·", |
| | | icon: "rotate", |
| | | }, |
| | | ]; |
| | | |
| | | /** æ«ç å
容éå¯è½è¡¨ç¤ºãçå·ãçåæ®µ */ |
| | | export const REEL_CODE_KEYS = [ |
| | | "batchCode", |
| | | "dishNo", |
| | | "monofilamentNumber", |
| | | "systemNo", |
| | | "code", |
| | | "çå·", |
| | | "æ¹æ¬¡å·", |
| | | ]; |
| | | |
| | | /** æ«ç å
容éå¯è½è¡¨ç¤ºãçå
·ç¼å·ãçåæ®µ */ |
| | | export const DISH_CODE_KEYS = [ |
| | | "weighingCode", |
| | | "weighingNo", |
| | | "dishCode", |
| | | "receiveDishNo", |
| | | "code", |
| | | "ç§°éç¼å·", |
| | | "çå
·ç¼å·", |
| | | ]; |
| | | |
| | | /** è§£ææ«ç å
容ï¼å
¼å®¹ JSON ä¸çº¯ææ¬ */ |
| | | export function parseScanCode(payload: any) { |
| | | const raw = payload?.code ?? payload; |
| | | if (raw === undefined || raw === null) return null; |
| | | if (typeof raw === "object") return raw; |
| | | const text = String(raw).trim(); |
| | | if (!text) return null; |
| | | if (text.startsWith("{")) { |
| | | try { |
| | | return JSON.parse(text); |
| | | } catch { |
| | | // JSON è§£æå¤±è´¥æ¶æçº¯ææ¬ç¼å·å¤ç |
| | | } |
| | | } |
| | | return { code: text }; |
| | | } |
| | | |
| | | /** ä»è§£æåç对象éæåéåæ®µåç¼å· */ |
| | | export function pickValue(data: any, keys: string[]) { |
| | | for (const key of keys) { |
| | | const value = data?.[key]; |
| | | if (value !== undefined && value !== null && String(value).trim() !== "") { |
| | | return String(value).trim(); |
| | | } |
| | | } |
| | | return ""; |
| | | } |
| | | |
| | | /** ç»ä¸ä»å页/æ°ç»ååºéåå表 */ |
| | | function pickRecords(data: any): any[] { |
| | | const pageData: any = data ?? {}; |
| | | return ( |
| | | pageData?.records ?? |
| | | pageData?.list ?? |
| | | pageData?.rows ?? |
| | | (Array.isArray(pageData) ? pageData : []) |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * æºçï¼æååºåï¼æ¥è¯¢ï¼ç宿¥å£ä¼å
ï¼æ¥å£æªèè°/æ¥ä¸å°æ¶åè½æ¨¡ææ°æ®ã |
| | | * æ¨¡ææ¨¡å¼ä¸çå·åæ«ç /è¾å
¥çå¼ï¼æ¹ä¾¿è¿ç»æµè¯ã |
| | | * @returns record 为 null è¡¨ç¤ºç¡®å®æ¥ä¸å° |
| | | */ |
| | | export async function findSourceStock(code: string) { |
| | | try { |
| | | const { data } = await InventoryOperationApi.searchStock({ |
| | | keyword: code, |
| | | materialType: MATERIAL_TYPE_FG, |
| | | ncReturnFlag: "Y", |
| | | }); |
| | | const records = pickRecords(data); |
| | | const exact = (records || []).find((row: any) => String(row?.batchCode ?? "").trim() === code); |
| | | const record = exact ?? (records?.length === 1 ? records[0] : null); |
| | | if (record) return { record, mocked: false }; |
| | | } catch { |
| | | // æ¥å£æªå°±ç»ªï¼èµ°ä¸é¢çæ¨¡ææ°æ® |
| | | } |
| | | if (!MOCK_ENABLED) return { record: null, mocked: false }; |
| | | return { record: { ...MOCK_SOURCE_STOCK, batchCode: code }, mocked: true }; |
| | | } |
| | | |
| | | /** |
| | | * çå
·ï¼çå
·ç§°éå°è´¦ï¼æ¥è¯¢ï¼ç宿¥å£ä¼å
ï¼æ¥å£æªèè°/æ¥ä¸å°æ¶åè½æ¨¡ææ°æ®ã |
| | | * æ¨¡ææ¨¡å¼ä¸çå
·ç¼å·åæ«ç /è¾å
¥çå¼ï¼æ¹ä¾¿ä¸ä¸ªååéæµè¯å¤ä¸ªçå
·ã |
| | | * @returns record 为 null è¡¨ç¤ºç¡®å®æ¥ä¸å° |
| | | */ |
| | | export async function findBobbin(code: string) { |
| | | try { |
| | | const { data } = await TwistApi.queryBobbinWeighingPage({ |
| | | current: 1, |
| | | size: 50, |
| | | weighingCode: code, |
| | | }); |
| | | const records = pickRecords(data); |
| | | const exact = (records || []).find( |
| | | (row: any) => String(row?.weighingCode ?? "").trim() === code |
| | | ); |
| | | const record = exact ?? (records?.length === 1 ? records[0] : null); |
| | | if (record) return { record, mocked: false }; |
| | | } catch { |
| | | // æ¥å£æªå°±ç»ªï¼èµ°ä¸é¢çæ¨¡ææ°æ® |
| | | } |
| | | if (!MOCK_ENABLED) return { record: null, mocked: false }; |
| | | return { record: { ...MOCK_BOBBIN, weighingCode: code }, mocked: true }; |
| | | } |
| | | |
| | | /** çå
·æ¯å¦å·²è¢«é¢ç¨ */ |
| | | export function isBobbinReceived(row: any) { |
| | | const value = row?.received ?? row?.isReceived; |
| | | return [true, 1, "1", "true", "æ¯"].includes(value); |
| | | } |
| | |
| | | > |
| | | <wd-card> |
| | | <wd-cell-group :border="true"> |
| | | <wd-cell title="åä¸ç¼å·" :value="data.monofilamentNumber" /> |
| | | <wd-cell title="ç论é¿åº¦" :value="data.amount + ' (m)'" /> |
| | | <wd-cell title="ç产é¿åº¦" :value="data.actuallyLength + ' (m)'" /> |
| | | <wd-cell title="éé" :value="data.actuallyWeight + ' (kg)'" /> |
| | | <wd-cell title="åä¸ç¼å·" :value="data.monofilamentNumber || '-'" /> |
| | | <wd-cell title="åä¸çé¿åº¦" :value="reelLengthText" /> |
| | | <wd-cell title="ç»å±" :value="layerText" /> |
| | | <wd-cell title="è§æ ¼åå·" :value="specificationText" /> |
| | | <wd-cell title="ç论é¿åº¦" :value="amountText" /> |
| | | <wd-cell title="éé" :value="weightText" /> |
| | | </wd-cell-group> |
| | | </wd-card> |
| | | </view> |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { ref } from "vue"; |
| | | import { ref, computed } from "vue"; |
| | | |
| | | const props = defineProps({ |
| | | data: { |
| | |
| | | }, |
| | | }); |
| | | |
| | | /** æå¼ææ¼åä½ï¼ç©ºå¼æ¾ç¤º "-"ï¼é¿å
åºç° "undefined (m)" */ |
| | | const withUnit = (value: any, unit: string) => |
| | | value === undefined || value === null || value === "" ? "-" : `${value} (${unit})`; |
| | | |
| | | /** åä¸çé¿åº¦ï¼å¯¹åºåæ¥çå®é
é¿åº¦ actuallyLength */ |
| | | const reelLengthText = computed(() => withUnit(props.data?.actuallyLength, "m")); |
| | | const amountText = computed(() => withUnit(props.data?.amount, "m")); |
| | | const weightText = computed(() => withUnit(props.data?.actuallyWeight, "kg")); |
| | | /** ç»å±ï¼ä¼å
twistedLayerï¼å
åº layer */ |
| | | const layerText = computed(() => props.data?.twistedLayer || props.data?.layer || "-"); |
| | | /** è§æ ¼åå·ï¼ä¼å
specificationModelï¼å
åº model */ |
| | | const specificationText = computed( |
| | | () => props.data?.specificationModel || props.data?.model || "-" |
| | | ); |
| | | |
| | | const emit = defineEmits(["delete", "swipe-open"]); |
| | | |
| | | const translateX = ref(0); |
| | |
| | | /> |
| | | <wd-input |
| | | v-model="model.model" |
| | | label="尺寸" |
| | | label="è§æ ¼åå·" |
| | | label-width="100px" |
| | | prop="model" |
| | | clearable |
| | | placeholder="请è¾å
¥å°ºå¯¸" |
| | | placeholder="请è¾å
¥è§æ ¼åå·" |
| | | /> |
| | | <wd-input |
| | | v-model="model.amount" |
| | |
| | | placeholder="è¯·éæ©åä½" |
| | | clearable |
| | | @confirm="handleUnitChange" |
| | | /> |
| | | <wd-picker |
| | | v-model="model.supplier" |
| | | :columns="supplierOptions" |
| | | label="åå®¶" |
| | | label-width="100px" |
| | | prop="supplier" |
| | | placeholder="è¯·éæ©åå®¶" |
| | | clearable |
| | | @confirm="handleSupplierChange" |
| | | /> |
| | | </wd-cell-group> |
| | | <wd-toast /> |
| | |
| | | model: undefined, // 尺寸 |
| | | amount: undefined, // æ°é |
| | | unit: "åª", // åä½ï¼é»è®¤å¼ä¸º"åª" |
| | | supplier: undefined, |
| | | type: "çå
·", |
| | | }); |
| | | |
| | |
| | | |
| | | // åä½åå
¸æ°æ® |
| | | const unitOptions = ref<Array<{ label: string; value: string }>>([]); |
| | | |
| | | // åå®¶åå
¸æ°æ® |
| | | const supplierOptions = ref<Array<{ label: string; value: string }>>([]); |
| | | |
| | | // å è½½çå
·ç±»ååå
¸æ°æ® |
| | | const loadDiskMaterialDict = async () => { |
| | |
| | | } |
| | | }; |
| | | |
| | | // å è½½åå®¶åå
¸æ°æ® |
| | | const loadSupplierDict = async () => { |
| | | try { |
| | | const res = await ManageApi.dictAPI("reel_factory"); |
| | | if (res.data && Array.isArray(res.data)) { |
| | | supplierOptions.value = res.data.map((item: any) => ({ |
| | | label: item.dictLabel || "", |
| | | value: item.dictValue || "", |
| | | })); |
| | | } |
| | | } catch (error) { |
| | | // å è½½åå
¸å¤±è´¥ï¼éé»å¤ç |
| | | } |
| | | }; |
| | | |
| | | // å¤ççå
·ç±»åéæ© |
| | | const handleDiskMaterialChange = (val: any) => { |
| | | model.diskMaterial = val.value; |
| | |
| | | // å¤çåä½éæ© |
| | | const handleUnitChange = (val: any) => { |
| | | model.unit = val.value; |
| | | }; |
| | | |
| | | // å¤çåå®¶éæ© |
| | | const handleSupplierChange = (val: any) => { |
| | | model.supplier = val.value; |
| | | }; |
| | | |
| | | // çå¬ model.diskMaterial ååï¼åæ¥éæ©å¨æ¾ç¤º |
| | |
| | | // æ´æ°å表ä¸å¯¹åºçæ°æ®é¡¹ |
| | | const updatedList = currentList.map((item) => { |
| | | if (item.id === currentId) { |
| | | // ä¿çåææ°æ®ï¼ç¶åæ´æ°ä¿®æ¹çåæ®µ |
| | | // ä¿çåææ°æ®ï¼å«åå®¶çåå²å段ï¼ï¼åªæ´æ°å¯ç¼è¾å段 |
| | | const updatedItem = { |
| | | ...item, // å
ä¿çåæçæææ°æ® |
| | | ...item, |
| | | diskMaterial: model.diskMaterial, |
| | | model: model.model, |
| | | amount: model.amount, |
| | | unit: model.unit, |
| | | supplier: model.supplier, |
| | | type: model.type, |
| | | }; |
| | | return updatedItem; |
| | |
| | | model.model = currentItem.model; |
| | | model.amount = currentItem.amount; |
| | | model.unit = currentItem.unit || "åª"; |
| | | model.supplier = currentItem.supplier; |
| | | model.type = currentItem.type || "çå
·"; |
| | | // 设置çå
·ç±»åçåæ¾å¼ |
| | | diskMaterialValue.value = currentItem.diskMaterial || ""; |
| | |
| | | onMounted(async () => { |
| | | await loadDiskMaterialDict(); |
| | | await loadUnitDict(); |
| | | await loadSupplierDict(); |
| | | }); |
| | | |
| | | // çå¬ç¼è¾æ°æ®ååï¼èªå¨åæ¾ |
| | |
| | | model.model = newData.model || ""; |
| | | model.amount = newData.amount || ""; |
| | | model.unit = newData.unit || "åª"; |
| | | model.supplier = newData.supplier || ""; |
| | | model.type = newData.type || "çå
·"; |
| | | diskMaterialValue.value = newData.diskMaterial || ""; |
| | | } |
| | |
| | | model.model = undefined; |
| | | model.amount = undefined; |
| | | model.unit = "åª"; |
| | | model.supplier = undefined; |
| | | model.type = "çå
·"; |
| | | diskMaterialValue.value = ""; |
| | | }; |
| | |
| | | <template> |
| | | <view class="list"> |
| | | <view class="list_box"> |
| | | <z-paging |
| | | ref="pagingRef" |
| | | v-model="cardList" |
| | | v-model="plateData" |
| | | :fixed="false" |
| | | :auto-show-back-to-top="true" |
| | | :loading-more-enabled="false" |
| | | @query="getList" |
| | | > |
| | | <template #top> |
| | | <CardTitle title="çå
·é¢ç¨" :hideAction="true" :full="false" @action="addReport" /> |
| | | </template> |
| | | <wd-card v-for="(item, index) in cardList" :key="index" type="rectangle" custom-class="round"> |
| | | <template #title> |
| | | <view class="flex justify-between"> |
| | | <view> |
| | | <wd-icon name="a-rootlist" color="#0D867F"></wd-icon> |
| | | <text class="text-[#252525] ml-2 font-medium">{{ item.diskMaterial }}</text> |
| | | <CardTitle title="çå
·é¢ç¨" :hideAction="false"> |
| | | <template #action> |
| | | <view class="action-wrap"> |
| | | <!-- å·¥åè¦æ±ççå
·è§æ ¼åå· / æè´¨ï¼å±ç¤ºå¨æ«ç ï¼æ°å¢ï¼æé®æ --> |
| | | <view class="reel-defaults"> |
| | | <text class="reel-default-item">è§æ ¼åå·ï¼{{ defaultDishModel || "-" }}</text> |
| | | <text class="reel-default-item">æè´¨ï¼{{ defaultDishMaterial || "-" }}</text> |
| | | </view> |
| | | <wd-button type="icon" icon="scan" color="#0D867F" @click="openScan"></wd-button> |
| | | </view> |
| | | <view class="text-[#A8A8A8]" @click="toEdit(item.id)">ç¼è¾</view> |
| | | </view> |
| | | </template> |
| | | <ProductionCard :data="cardAttr" :value="item" color="#0D867F" /> |
| | | </wd-card> |
| | | </z-paging> |
| | | <wd-popup v-model="addDialog.visible" position="bottom" custom-class="yl-popup"> |
| | | <view class="action px-3"> |
| | | <wd-button type="text" @click="cancelAdd">åæ¶</wd-button> |
| | | <wd-button type="text" @click="submitAdd">ç¡®å®</wd-button> |
| | | </template> |
| | | </CardTitle> |
| | | <view class="scan-tip">è¯·æ«æçå
·æ ç¾äºç»´ç é¢ç¨çå
·ï¼çå
·éå
å¨çå
·ç§°éå°è´¦ä¸ç§°éï¼</view> |
| | | </template> |
| | | |
| | | <view class="content"> |
| | | <wd-card |
| | | v-for="(item, index) in plateData" |
| | | :key="item.id ?? item.dishCode ?? index" |
| | | type="rectangle" |
| | | custom-class="round" |
| | | > |
| | | <template #title> |
| | | <view class="flex justify-between"> |
| | | <view> |
| | | <wd-icon name="a-rootlist" color="#0D867F"></wd-icon> |
| | | <text class="text-[#252525] ml-2 font-medium">{{ item.diskMaterial }}</text> |
| | | </view> |
| | | <view class="flex items-center"> |
| | | <text v-if="!item.id" class="text-[#E6A23C] mr-3 text-[12px]">å¾
ä¿å</text> |
| | | <view v-if="!item.id" class="text-[#A8A8A8]" @click="removeDish(item)">ç§»é¤</view> |
| | | <view v-else class="text-[#A8A8A8]" @click="toEdit(item)">ç¼è¾</view> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | <ProductionCard :data="cardAttr" :value="item" color="#0D867F" /> |
| | | </wd-card> |
| | | </view> |
| | | <PlateForm ref="addFormRef" mode="add" @refresh="reloadList" /> |
| | | </wd-popup> |
| | | <wd-popup v-model="editDialog.visible" position="bottom" custom-class="yl-popup"> |
| | | </z-paging> |
| | | |
| | | <view class="save-footer"> |
| | | <wd-button block @click="save"> |
| | | <text class="text-[#fff]">ä¿å</text> |
| | | </wd-button> |
| | | </view> |
| | | |
| | | <wd-popup v-model="editDialog.visible" position="bottom" custom-class="yl-popup" :z-index="30"> |
| | | <view class="action px-3"> |
| | | <wd-button type="text" @click="cancelEdit">åæ¶</wd-button> |
| | | <wd-button type="text" @click="submitEdit">ç¡®å®</wd-button> |
| | |
| | | @refresh="reloadList" |
| | | /> |
| | | </wd-popup> |
| | | |
| | | <Scan ref="scanRef" emitName="scanPlate" /> |
| | | <wd-toast /> |
| | | </view> |
| | | </template> |
| | |
| | | import ProductionCard from "../../../components/ProductionCard.vue"; |
| | | import { useToast } from "wot-design-uni"; |
| | | import PlateForm from "./form.vue"; |
| | | import { onLoad, onShow } from "@dcloudio/uni-app"; |
| | | import { onLoad, onUnload, onShow, onHide } from "@dcloudio/uni-app"; |
| | | import ManageApi from "@/api/product/manage"; |
| | | import TwistApi from "@/api/product/twist"; |
| | | import zPaging from "@/components/z-paging/z-paging.vue"; |
| | | import Scan from "@/components/scan/index.vue"; |
| | | |
| | | const paramsId = ref(); |
| | | const pagingRef = ref(); |
| | | const addFormRef = ref(); |
| | | const editFormRef = ref(); |
| | | const scanRef = ref(); |
| | | const toast = useToast(); |
| | | const addDialog = reactive({ |
| | | visible: false, |
| | | }); |
| | | const editDialog = reactive({ |
| | | visible: false, |
| | | currentItem: null as any, |
| | | editId: undefined as number | undefined, |
| | | }); |
| | | const cardList = ref<any[]>([]); |
| | | const plateData = ref<any[]>([]); |
| | | |
| | | const isPageVisible = ref(true); |
| | | |
| | | /** å·¥åè¦æ±ççå
·è§æ ¼åå· / æè´¨ï¼å±ç¤ºå¨æ°å¢æé®æï¼é¢ç¨åä½ä¸ºè§æ ¼åå·é»è®¤å¼ï¼ */ |
| | | const defaultDishModel = ref(""); |
| | | const defaultDishMaterial = ref(""); |
| | | |
| | | const cardAttr = ref<any[]>([ |
| | | { |
| | | label: "尺寸", |
| | | label: "çå
·ç¼å·", |
| | | prop: "dishCode", |
| | | }, |
| | | { |
| | | label: "è§æ ¼åå·", |
| | | prop: "model", |
| | | }, |
| | | { |
| | |
| | | label: "åä½", |
| | | prop: "unit", |
| | | }, |
| | | { |
| | | label: "åå®¶", |
| | | prop: "supplier", |
| | | span: 14, |
| | | }, |
| | | ]); |
| | | |
| | | const toEdit = (id: number) => { |
| | | // æ¾å°éè¦ç¼è¾ç项 |
| | | const itemToEdit = cardList.value.find((item) => item.id === id); |
| | | if (itemToEdit) { |
| | | editDialog.currentItem = itemToEdit; |
| | | editDialog.editId = id; |
| | | editDialog.visible = true; |
| | | } |
| | | /** ç»ä¸çå
·æ°æ®ï¼çå
·ç¼å·å
¼å®¹ weighingCodeï¼æ°é/åä½è¡¥é»è®¤å¼ */ |
| | | const normalizeDish = (item: any) => ({ |
| | | ...item, |
| | | dishCode: item?.dishCode ?? item?.weighingCode ?? "", |
| | | weighingCode: item?.weighingCode ?? item?.dishCode ?? "", |
| | | amount: item?.amount ?? 1, |
| | | unit: item?.unit ?? "åª", |
| | | }); |
| | | |
| | | /** æ¯å¦å·²è¢«é¢ç¨ï¼å
¼å®¹ 1/"1"/true/"æ¯" */ |
| | | const isReceived = (row: any) => { |
| | | const value = row?.received ?? row?.isReceived; |
| | | return [true, 1, "1", "true", "æ¯"].includes(value); |
| | | }; |
| | | |
| | | const addReport = () => { |
| | | // éç½®è¡¨åæ°æ® |
| | | if (addFormRef.value) { |
| | | addFormRef.value.resetFormData(); |
| | | } |
| | | addDialog.visible = true; |
| | | const toEdit = (item: any) => { |
| | | editDialog.currentItem = item; |
| | | editDialog.editId = item?.id; |
| | | editDialog.visible = true; |
| | | }; |
| | | |
| | | const submitAdd = async () => { |
| | | toast.show("æäº¤"); |
| | | const success = await addFormRef.value.submit(); |
| | | if (success) { |
| | | addDialog.visible = false; |
| | | /** ç§»é¤å°æªä¿åçæ«ç è®°å½ */ |
| | | const removeDish = (item: any) => { |
| | | const index = plateData.value.findIndex((row) => row.dishCode === item.dishCode && !row.id); |
| | | if (index > -1) { |
| | | plateData.value.splice(index, 1); |
| | | } |
| | | }; |
| | | |
| | | const cancelAdd = () => { |
| | | toast.show("åæ¶"); |
| | | addDialog.visible = false; |
| | | // æ¸
ç©ºè¡¨åæ°æ® |
| | | addFormRef.value?.$refs?.form?.resetFields(); |
| | | }; |
| | | |
| | | const submitEdit = async () => { |
| | | const success = await editFormRef.value.submitEdit(cardList.value, editDialog.editId); |
| | | const success = await editFormRef.value.submitEdit(plateData.value, editDialog.editId); |
| | | if (success) { |
| | | editDialog.visible = false; |
| | | reloadList(); |
| | |
| | | }; |
| | | |
| | | const cancelEdit = () => { |
| | | toast.show("åæ¶"); |
| | | editDialog.visible = false; |
| | | }; |
| | | |
| | | const reloadList = () => { |
| | | pagingRef.value.refresh(); |
| | | pagingRef.value?.refresh(); |
| | | }; |
| | | |
| | | const getList = async () => { |
| | | const { code, data } = await ManageApi.getStrandedWireDish({ |
| | | wireId: paramsId.value, |
| | | type: "çå
·", |
| | | }); |
| | | if (code == 200) { |
| | | pagingRef.value.complete(data); |
| | | try { |
| | | const { code, data } = await ManageApi.getStrandedWireDish({ |
| | | wireId: paramsId.value, |
| | | type: "çå
·", |
| | | }); |
| | | if (code == 200) { |
| | | const list = (Array.isArray(data) ? data : []).map(normalizeDish); |
| | | pagingRef.value.complete(list); |
| | | } else { |
| | | pagingRef.value.complete([]); |
| | | } |
| | | } catch (error) { |
| | | pagingRef.value.complete([]); |
| | | } |
| | | }; |
| | | |
| | | // ============ æ«ç æ°å¢çå
· ============ |
| | | /** è§£ææ«ç å
容ï¼å
¼å®¹ JSON ä¸çº¯ææ¬ç§°éç¼å· */ |
| | | const parseScanCode = (payload: any) => { |
| | | const raw = payload?.code ?? payload; |
| | | if (raw === undefined || raw === null) return null; |
| | | if (typeof raw === "object") return raw; |
| | | const text = String(raw).trim(); |
| | | if (!text) return null; |
| | | if (text.startsWith("{")) { |
| | | try { |
| | | return JSON.parse(text); |
| | | } catch { |
| | | // JSON è§£æå¤±è´¥æ¶æçº¯ææ¬ç§°éç¼å·å¤ç |
| | | } |
| | | } |
| | | return { weighingCode: text }; |
| | | }; |
| | | |
| | | /** 仿«ç å
容éåçå
·ï¼ç§°éï¼ç¼å· */ |
| | | const pickWeighingCode = (data: any) => { |
| | | const keys = [ |
| | | "weighingCode", |
| | | "weighingNo", |
| | | "dishCode", |
| | | "receiveDishNo", |
| | | "batchCode", |
| | | "code", |
| | | "ç§°éç¼å·", |
| | | "çå
·ç¼å·", |
| | | "çå·", |
| | | ]; |
| | | for (const key of keys) { |
| | | const value = data?.[key]; |
| | | if (value !== undefined && value !== null && String(value).trim() !== "") { |
| | | return String(value).trim(); |
| | | } |
| | | } |
| | | return ""; |
| | | }; |
| | | |
| | | /** å°è´¦è¡ â çå
·é¢ç¨è¡ */ |
| | | const buildDishFromLedger = (record: any) => |
| | | normalizeDish({ |
| | | wireId: paramsId.value, |
| | | diskMaterial: record?.diskMaterial ?? undefined, |
| | | // è§æ ¼åå·å该çå
·å¨ç§°éå°è´¦éçè§æ ¼åå· |
| | | model: record?.specificationModel ?? undefined, |
| | | weight: record?.weight ?? undefined, |
| | | amount: 1, |
| | | unit: "åª", |
| | | dishCode: String(record?.weighingCode ?? "").trim(), |
| | | weighingCode: String(record?.weighingCode ?? "").trim(), |
| | | type: "çå
·", |
| | | }); |
| | | |
| | | const getScanCode = async (payload: any) => { |
| | | if (!isPageVisible.value) return; |
| | | |
| | | const parsed = parseScanCode(payload); |
| | | if (!parsed) { |
| | | toast.error("æ«ç å
容为空ï¼è¯·éæ°æ«ç "); |
| | | return; |
| | | } |
| | | |
| | | const code = pickWeighingCode(parsed); |
| | | if (!code) { |
| | | toast.error("äºç»´ç æ æ³è¯å«çå
·ç¼å·ï¼è¯·æ´æ¢äºç»´ç "); |
| | | return; |
| | | } |
| | | |
| | | if (plateData.value.some((item) => String(item.dishCode ?? item.weighingCode ?? "") === code)) { |
| | | toast.error("该çå
·å·²å¨æ¬åé¢ç¨å表ä¸ï¼è¯·å¿é夿«ç "); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | const { data } = await TwistApi.queryBobbinWeighingPage({ |
| | | current: 1, |
| | | size: 50, |
| | | weighingCode: code, |
| | | }); |
| | | const pageData: any = data ?? {}; |
| | | const records = |
| | | pageData?.records ?? |
| | | pageData?.list ?? |
| | | pageData?.rows ?? |
| | | (Array.isArray(pageData) ? pageData : []); |
| | | const exact = (records || []).find((row: any) => String(row?.weighingCode ?? "") === code); |
| | | const record = exact ?? (records?.length === 1 ? records[0] : null); |
| | | |
| | | if (!record) { |
| | | toast.error("çå
·ç§°éå°è´¦ä¸æªæ¾å°è¯¥çå
·ï¼è¯·å
å¨çå
·ç§°éå°è´¦ä¸ç§°é"); |
| | | return; |
| | | } |
| | | if (isReceived(record)) { |
| | | toast.error("该çå
·å·²è¢«é¢ç¨ï¼è¯·æ´æ¢çå
·"); |
| | | return; |
| | | } |
| | | |
| | | plateData.value.push(buildDishFromLedger(record)); |
| | | toast.success("æ«ç æåï¼è¯·ç¹å»ä¿åæäº¤"); |
| | | } catch (error) { |
| | | // 请æ±å±å·²ç»ä¸æç¤ºå¤±è´¥åå |
| | | } |
| | | }; |
| | | |
| | | const openScan = () => { |
| | | scanRef.value?.triggerScan(); |
| | | }; |
| | | |
| | | // ============ ä¿å ============ |
| | | const isNewDish = (item: any) => item?.id === undefined || item?.id === null; |
| | | |
| | | const save = () => { |
| | | const newCount = plateData.value.filter(isNewDish).length; |
| | | if (!newCount) { |
| | | toast.error("æ²¡ææ°æ«ç ççå
·éè¦ä¿å"); |
| | | return; |
| | | } |
| | | uni.showModal({ |
| | | title: "æç¤º", |
| | | content: `确认ä¿å ${newCount} æ¡çå
·é¢ç¨æ°æ®åï¼`, |
| | | success: async (res) => { |
| | | if (res.confirm) { |
| | | await handleConfirmSave(); |
| | | } |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | const handleConfirmSave = async () => { |
| | | const newData = plateData.value.filter(isNewDish); |
| | | if (newData.length === 0) { |
| | | toast.error("æ²¡ææ°æ«ç ççå
·éè¦ä¿å"); |
| | | return; |
| | | } |
| | | const invalid = newData.find((item) => !item.dishCode || !item.diskMaterial); |
| | | if (invalid) { |
| | | toast.error(`${invalid.dishCode || "çå
·"}ï¼çå
·æ°æ®ä¸å®æ´ï¼è¯·éæ°æ«ç `); |
| | | return; |
| | | } |
| | | |
| | | const { code, msg } = await TwistApi.addStrandedWireDish(newData); |
| | | if (code == 200) { |
| | | toast.success(msg || "ä¿åæå"); |
| | | pagingRef.value?.refresh(); |
| | | } else { |
| | | toast.error(msg || "ä¿å失败"); |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * åå·¥åè¦æ±ççå
·åå· / çå
·æè´¨ï¼å±ç¤ºå¨æ«ç æé®æï¼ |
| | | * åªåçå
·ç¸å
³å段 diskModel / diskMaterialï¼ä¸æ¿äº§åè§æ ¼ model å
åº |
| | | */ |
| | | const loadDishDefaults = async () => { |
| | | if (!paramsId.value) return; |
| | | try { |
| | | const { data } = await TwistApi.getTwistDetailById({ id: paramsId.value }); |
| | | defaultDishModel.value = data?.diskModel || ""; |
| | | defaultDishMaterial.value = data?.diskMaterial || ""; |
| | | } catch (error) { |
| | | // åä¸å°å°±å±ç¤º "-"ï¼ä¸é»å¡é¢ç¨ |
| | | } |
| | | }; |
| | | |
| | | onLoad((options: any) => { |
| | | paramsId.value = options.id; |
| | | uni.$off("scanPlate", getScanCode); |
| | | uni.$on("scanPlate", getScanCode); |
| | | paramsId.value = options?.id; |
| | | loadDishDefaults(); |
| | | }); |
| | | |
| | | // çå
·é¢ç¨æ¯ãè¯çº¿/åä¸/çå
·ã页ç¾ä¹ä¸ï¼ç»ä»¶å¯è½æäºé¡µé¢ onShow ææè½½ï¼ |
| | | // è¿éå
åºç½®ä¸ºå¯è§ï¼é¿å
æ«ç 被误å¤ä¸ºä¸å¯è§èéé»ä¸¢å¼ã |
| | | onMounted(() => { |
| | | isPageVisible.value = true; |
| | | }); |
| | | |
| | | onShow(() => { |
| | | isPageVisible.value = true; |
| | | }); |
| | | |
| | | onHide(() => { |
| | | isPageVisible.value = false; |
| | | }); |
| | | |
| | | onUnload(() => { |
| | | uni.$off("scanPlate", getScanCode); |
| | | isPageVisible.value = false; |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .list { |
| | | height: calc(100vh - 120px); |
| | | padding: 12px; |
| | | .list_box { |
| | | height: calc(100vh - 160px); |
| | | background: #f3f9f8; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .action { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | :deep(.wd-button__content) { |
| | | color: #0d867f; |
| | | } |
| | | |
| | | .scan-tip { |
| | | padding: 0 12px 8px; |
| | | font-size: 12px; |
| | | color: #8a8a8a; |
| | | } |
| | | |
| | | .action-wrap { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .reel-defaults { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: flex-end; |
| | | margin-right: 8px; |
| | | } |
| | | |
| | | .reel-default-item { |
| | | font-size: 11px; |
| | | line-height: 16px; |
| | | color: #646874; |
| | | } |
| | | |
| | | .content { |
| | | width: 100%; |
| | | padding-bottom: 76px; |
| | | box-sizing: border-box; |
| | | |
| | | :deep() { |
| | | .round { |
| | |
| | | } |
| | | } |
| | | |
| | | .action { |
| | | .save-footer { |
| | | position: fixed; |
| | | right: 0; |
| | | bottom: 0; |
| | | left: 0; |
| | | z-index: 20; |
| | | padding: 8px 12px calc(8px + env(safe-area-inset-bottom)); |
| | | background: #ffffff; |
| | | border-top: 1px solid #eeeeee; |
| | | box-shadow: 0 -2px 10px rgb(0 0 0 / 6%); |
| | | } |
| | | |
| | | :deep(.zp-paging-container) { |
| | | background: transparent !important; |
| | | flex: 1; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | :deep(.zp-paging-container-content) { |
| | | background: transparent !important; |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | :deep(.zp-paging-container-top) { |
| | | flex-shrink: 0; |
| | | } |
| | | </style> |
| | |
| | | } |
| | | }; |
| | | |
| | | // å¿
é¡»æçå
·é¢ç¨è®°å½æè½æ¥å·¥ï¼æ¥å£å¼å¸¸æ¶ä¸æ¦æªï¼é¿å
ç½ç»é®é¢é»æç产ï¼ï¼ |
| | | // åªææç¡®æ¥è¯¢æå䏿²¡æä»»ä½çå
·é¢ç¨æ¶ææ¦æªã |
| | | const ensureReelDish = async () => { |
| | | try { |
| | | const { code, data } = await ManageApi.getStrandedWireDish({ |
| | | wireId: paramsId.value, |
| | | type: "çå
·", |
| | | }); |
| | | if (code !== 200) return true; |
| | | const list = Array.isArray(data) ? data : []; |
| | | if (list.length === 0) { |
| | | toast.warning("请å
å¨ãçå
·é¢ç¨ã䏿«ç é¢ç¨çå
·ï¼åè¿è¡ç»çº¿æ¥å·¥"); |
| | | return false; |
| | | } |
| | | return true; |
| | | } catch (error) { |
| | | return true; |
| | | } |
| | | }; |
| | | |
| | | const addReport = async () => { |
| | | // å¿
é¡»æçå
·é¢ç¨è®°å½æè½ç»çº¿æ¥å·¥ |
| | | if (!(await ensureReelDish())) return; |
| | | // æ£æ¥æ¯å¦æææ°æ®é½å·²ä¿åï¼é½æidï¼ |
| | | if (twistReportList.value.length > 0 && twistReportList.value.every((item) => item.id)) { |
| | | // ç¡®ä¿ä¸»è¡¨æ°æ®å·²è·å |