From 1b8ed4768feeb6433cef55ea8e7c4ad7070c151c Mon Sep 17 00:00:00 2001 From: 啊鑫 <t2856754968@163.com> Date: 星期三, 16 七月 2025 13:42:13 +0800 Subject: [PATCH] OQC检验 --- pages/QC/OQC/Add.vue | 843 ++++++++++++ pages/QC/OQC/ImageItem.vue | 234 +++ pages/QC/OQC/ScanCode.vue | 745 ++++++++++ CLAUDE.md | 174 ++ pages.json | 192 +- pages/QC/OQC/List.vue | 1090 +++++++++++++++ pages/QC/OQC/detail.vue | 828 ++++++++++++ store/index.js | 30 8 files changed, 4,033 insertions(+), 103 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..e6c8d79 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,174 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +This is a uni-app based mobile application for quality control (QC) and warehouse management in a MES (Manufacturing Execution System) environment. The app is specifically designed for PDA devices and supports both Android and iOS platforms. + +**App Details:** +- Name: GS-MES-AP (骞挎繁绉戞妧 MES Application) +- Framework: uni-app with Vue 2 +- Version: 1.1.1.4 +- Company: 骞挎繁绉戞妧 (Guangshen Technology) + +## Architecture + +### Core Structure +- **Frontend Framework**: Vue 2 with uni-app cross-platform framework +- **State Management**: Vuex store for application state +- **Routing**: uni-app page-based routing defined in `pages.json` +- **Entry Point**: `main.js` - contains global configurations, prototypes, and app initialization + +### Key Directories +- `pages/` - All application pages organized by functionality: + - `BasePages/` - Core app pages (login, main, user, messages) + - `QC/` - Quality control modules (XJ-宸℃, SJ-棣栨, RKJ-鍏ュ簱妫�, LLJ-鏉ユ枡妫�) + - `Warehouse/` - Warehouse management (inventory, purchases, returns) + - `Test/` - Testing and development pages + - `Allocation/` - Transfer operations (in/out) +- `components/` - Reusable UI components and third-party components +- `static/` - Static assets (images, CSS, audio files) +- `store/` - Vuex state management +- `common/` - Shared utilities and mixins +- `utils/` - Utility functions + +### Main Functionality Areas +1. **Quality Control (QC)**: + - 宸℃ (XJ) - Patrol Inspection + - 棣栨 (SJ) - First Article Inspection + - 鍏ュ簱妫� (RKJ) - Incoming Inspection + - 鏉ユ枡妫� (LLJ) - Material Inspection + +2. **Warehouse Management**: + - Purchase inventory management + - Material receipt and returns + - Location changes and transfers + - Barcode printing and scanning + +3. **User Management**: + - Login/logout functionality + - User profile and settings + - Message center for notifications + +## Development Environment + +This is a uni-app project with no traditional package.json build scripts. Development and building should be done through: + +1. **HBuilderX IDE** (recommended uni-app development environment) +2. **uni-app CLI** if using command line + +### Build Commands +Since this is a uni-app project without npm scripts, use: +- Development: Open project in HBuilderX and use built-in dev server +- Build for production: Use HBuilderX build tools or uni-app CLI +- No traditional lint/test commands found in the codebase + +### Key Configuration Files +- `manifest.json` - App configuration, permissions, and platform settings +- `pages.json` - Page routing and navigation configuration +- `uni.scss` - Global SCSS variables +- `App.vue` - Root component with global styles + +### Development Workflow +1. **Project Setup**: Open the project in HBuilderX IDE +2. **Development**: Use HBuilderX's built-in development server for hot reload +3. **Building**: Use HBuilderX's build tools to generate platform-specific builds +4. **Testing**: Manual testing on real devices or emulators (no automated test suite) + +## API and Data Flow + +### Server Configuration +Server endpoints are configured in `store/index.js`: +- Local development: `http://localhost:10054/api` +- Internal network: `http://192.168.11.251:10054` +- Current active API: `http://localhost:10054/api` (configured in `serverAPI`) + +### Network Environment Switching +The app supports switching between internal and external network environments via the `networkFlag` state in the Vuex store. + +### Request Methods +Global request methods available on Vue prototype: +- `this.$get()` - GET requests with loading indicators +- `this.$post()` - POST requests with loading indicators +- `this.$postSyncPost()` - Synchronous POST requests +- `this.$toERP()` - ERP system requests +- `this.$uni_request()` - Core request wrapper +- `this.$uni_requestNew()` - Alternative request method +- `this.$sendPostRequest()` - Wrapper for ERP POST requests + +### Global Utility Methods +Additional utility methods available on Vue prototype: +- `this.$camera()` - Camera and image selection functionality +- `this.$fileUpload()` - File upload with base64 encoding +- `this.$getDate()` - Date formatting utility +- `this.$getUrlParams()` - URL parameter extraction +- `this.$showMessage()` - Toast notification display +- `this.$showDialog()` - Modal dialog display +- `this.$setTitle()` - Navigation title setting +- `this.$getUserMenu()` - User menu retrieval + +### Authentication +User authentication managed through: +- Login info stored in `this.$loginInfo` prototype +- User data persisted in uni.storage +- Forced login required (`forcedLogin: true`) +- Global authentication check via `globalMixin.js` (currently commented out) +- Session management with `this.$login()` and `this.$logout()` methods + +## Mobile-Specific Features + +### Hardware Integration +- **Camera**: Photo capture for QC inspections (configured in `manifest.json`) +- **Barcode Scanner**: For inventory and QC operations (Barcode module enabled) +- **Printer**: Bluetooth printing for labels and barcodes (via `kk-printer` component) +- **Audio**: Sound notifications for OK/NG status (located in `static/audio/`) + +### Device Permissions +Configured in `manifest.json` for Android: +- Camera access for photo capture +- Storage access for file operations +- Network access for API communications +- Bluetooth for printer connectivity + +### Platform Support +- Android permissions configured in `manifest.json` +- iOS configuration included +- Cross-platform compatibility via uni-app + +## Common Patterns + +### Page Navigation +Pages use uni-app navigation with parameters passed via URL query strings. Use `this.$getUrlParams(url)` to extract parameters. + +### Data Validation +QC modules include image upload functionality for inspection records with base64 encoding. + +### State Management +Vuex store maintains server configuration and app state. Network settings can be switched between internal/external environments. + +### Error Handling +Global error handling through unified request methods with toast notifications for user feedback. + +### Component Organization +- **Third-party Components**: Located in `components/` directory + - `kk-printer` - Bluetooth printer integration + - `uni-*` - Official uni-app UI components + - `mpvue-*` - Vue-based utility components +- **Custom Components**: Project-specific components in `components/` + - `page-head` and `page-foot` - Layout components + - `product.vue` - Product display component + +### Code Style and Conventions +- Vue 2 syntax with Options API +- Chinese comments and variable names for business logic +- Prototype-based method attachment for global utilities +- Base64 encoding for image uploads +- Toast notifications for user feedback +- Modal dialogs for confirmations + +### File Structure Conventions +- QC pages follow pattern: `List.vue` 鈫� `Add.vue` 鈫� `detail.vue` 鈫� `ImageItem.vue` +- Each QC module (XJ, SJ, RKJ, LLJ) has identical structure +- Warehouse operations follow similar patterns +- Test pages in `Test/` directory for development \ No newline at end of file diff --git a/pages.json b/pages.json index e94a155..ae02587 100644 --- a/pages.json +++ b/pages.json @@ -29,7 +29,7 @@ "backgroundColor": "#fbf9fe" }, "pages": [ - + //pages鏁扮粍涓涓�椤硅〃绀哄簲鐢ㄥ惎鍔ㄩ〉锛屽弬鑰冿細https://uniapp.dcloud.io/collocation/pages { "path": "pages/BasePages/login", @@ -150,7 +150,7 @@ "navigationBarTitleText": "鍏ュ簱妫�" } }, - + { "path": "pages/QC/RKJ/Add", "style": { @@ -273,145 +273,161 @@ } }, { - "path" : "pages/Warehouse/PurchaseInventory/PurchaseInventory", - "style" : - { - "navigationBarTitleText" : "閲囪喘鍏ュ簱" + "path": "pages/Warehouse/PurchaseInventory/PurchaseInventory", + "style": { + "navigationBarTitleText": "閲囪喘鍏ュ簱" } }, { - "path" : "pages/Warehouse/PurchaseInventory/Cgrk", - "style" : - { - "navigationBarTitleText" : "閲囪喘鍏ュ簱鍗�" + "path": "pages/Warehouse/PurchaseInventory/Cgrk", + "style": { + "navigationBarTitleText": "閲囪喘鍏ュ簱鍗�" } }, { - "path" : "pages/Warehouse/PurchaseInventory/Add", - "style" : - { - "navigationBarTitleText" : "閲囪喘鍏ュ簱鍗曟槑缁�" + "path": "pages/Warehouse/PurchaseInventory/Add", + "style": { + "navigationBarTitleText": "閲囪喘鍏ュ簱鍗曟槑缁�" } }, { - "path" : "pages/Test/scanTest", - "style" : - { - "navigationBarTitleText" : "鎵爜娴嬭瘯" + "path": "pages/Test/scanTest", + "style": { + "navigationBarTitleText": "鎵爜娴嬭瘯" } }, { - "path" : "pages/Warehouse/PurchaseReturn/Cgth", - "style" : - { - "navigationBarTitleText" : "閲囪喘閫�璐�" + "path": "pages/Warehouse/PurchaseReturn/Cgth", + "style": { + "navigationBarTitleText": "閲囪喘閫�璐�" } }, { - "path" : "pages/Warehouse/PurchaseReturn/Add", - "style" : - { - "navigationBarTitleText" : "娣诲姞閲囪喘閫�鏂欏崟" + "path": "pages/Warehouse/PurchaseReturn/Add", + "style": { + "navigationBarTitleText": "娣诲姞閲囪喘閫�鏂欏崟" } }, { - "path" : "pages/Warehouse/PurchaseReturn/PurchaseReturn", - "style" : - { - "navigationBarTitleText" : "閲囪喘閫�鏂欐壂鐮�" + "path": "pages/Warehouse/PurchaseReturn/PurchaseReturn", + "style": { + "navigationBarTitleText": "閲囪喘閫�鏂欐壂鐮�" } }, { - "path" : "pages/BasePages/information", - "style" : - { - "navigationBarTitleText" : "淇℃伅璇︽儏" + "path": "pages/BasePages/information", + "style": { + "navigationBarTitleText": "淇℃伅璇︽儏" } }, { - "path" : "pages/Warehouse/OpeningReceipt/OpeningReceipt", - "style" : - { - "navigationBarTitleText" : "鏈熷垵鍏ュ簱鎵爜" + "path": "pages/Warehouse/OpeningReceipt/OpeningReceipt", + "style": { + "navigationBarTitleText": "鏈熷垵鍏ュ簱鎵爜" } }, { - "path" : "pages/Allocation/In", - "style" : - { - "navigationBarTitleText" : "璋冩嫧鍏ュ簱" + "path": "pages/Allocation/In", + "style": { + "navigationBarTitleText": "璋冩嫧鍏ュ簱" } }, { - "path" : "pages/Allocation/Out", - "style" : - { - "navigationBarTitleText" : "璋冩嫧鍑哄簱" + "path": "pages/Allocation/Out", + "style": { + "navigationBarTitleText": "璋冩嫧鍑哄簱" } }, { - "path" : "pages/Warehouse/ChangeOfLocation/ChangeOfLocation", - "style" : - { - "navigationBarTitleText" : "搴撲綅鍙樻洿" + "path": "pages/Warehouse/ChangeOfLocation/ChangeOfLocation", + "style": { + "navigationBarTitleText": "搴撲綅鍙樻洿" } }, { - "path" : "pages/Test/testPrint", - "style" : - { - "navigationBarTitleText" : "鎵撳嵃娴嬭瘯" + "path": "pages/Test/testPrint", + "style": { + "navigationBarTitleText": "鎵撳嵃娴嬭瘯" } }, { - "path" : "pages/BarcodePrint/BarcodePrint", - "style" : - { - "navigationBarTitleText" : "鏈熷垵鏉$爜鎵撳嵃" + "path": "pages/BarcodePrint/BarcodePrint", + "style": { + "navigationBarTitleText": "鏈熷垵鏉$爜鎵撳嵃" } }, { - "path" : "pages/Warehouse/MaterialReceipt/MaterialReceipt", - "style" : - { - "navigationBarTitleText" : "鐗╂枡鎺ユ敹" + "path": "pages/Warehouse/MaterialReceipt/MaterialReceipt", + "style": { + "navigationBarTitleText": "鐗╂枡鎺ユ敹" } }, { - "path" : "pages/Warehouse/ProductionPick/ProductionPick", - "style" : - { - "navigationBarTitleText" : "鐢熶骇棰嗘枡" + "path": "pages/Warehouse/ProductionPick/ProductionPick", + "style": { + "navigationBarTitleText": "鐢熶骇棰嗘枡" } }, { - "path" : "pages/Warehouse/ProductionPick/List", - "style" : - { - "navigationBarTitleText" : "鐢熶骇棰嗘枡鍗�" + "path": "pages/Warehouse/ProductionPick/List", + "style": { + "navigationBarTitleText": "鐢熶骇棰嗘枡鍗�" } }, { - "path" : "pages/Warehouse/ProductionPick/Add", - "style" : - { - "navigationBarTitleText" : "鐢熶骇棰嗘枡鍗�" + "path": "pages/Warehouse/ProductionPick/Add", + "style": { + "navigationBarTitleText": "鐢熶骇棰嗘枡鍗�" } }, { - "path" : "pages/BasePages/treated", - "style" : - { - "navigationBarTitleText" : "寰呭鐞�" - } - }, - { - "path": "pages/Device/Spotcheck", - "style": { - "navigationBarTitleText": "璁惧鐐规", - "enablePullDownRefresh": false - } - } - + "path": "pages/BasePages/treated", + "style": { + "navigationBarTitleText": "寰呭鐞�" + } + }, + { + "path" : "pages/QC/OQC/List", + "style" : + { + "navigationBarTitleText" : "OQC妫�楠�" + } + }, + { + "path" : "pages/QC/OQC/ScanCode", + "style" : + { + "navigationBarTitleText" : "OQC妫�楠�" + } + }, + { + "path" : "pages/QC/OQC/Add", + "style" : + { + "navigationBarTitleText" : "" + } + }, + { + "path" : "pages/QC/OQC/ImageItem", + "style" : + { + "navigationBarTitleText" : "鍥剧墖鏌ョ湅" + } + }, + { + "path" : "pages/QC/OQC/detail", + "style" : + { + "navigationBarTitleText" : "妫�楠岃鎯�" + } + } + // { + // "path": "pages/Device/Spotcheck", + // "style": { + // "navigationBarTitleText": "璁惧鐐规", + // "enablePullDownRefresh": false + // } + // } + ] } \ No newline at end of file diff --git a/pages/QC/OQC/Add.vue b/pages/QC/OQC/Add.vue new file mode 100644 index 0000000..08bdf0b --- /dev/null +++ b/pages/QC/OQC/Add.vue @@ -0,0 +1,843 @@ +<template> + <view class="page-container"> + <!-- 琛ㄥ崟瀹瑰櫒 --> + <view class="form-card"> + <form :modelValue="formData"> + <view class="form-group"> + <label class="form-label">妫�楠屽崟鍙�:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.releaseNo" /> + </view> + <view class="form-group"> + <label class="form-label">鐗╂枡缂栫爜:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.itemNo" /> + </view> + <view class="form-group"> + <label class="form-label">鐗╂枡鍚嶇О:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.itemName" /> + </view> + <view class="form-group"> + <label class="form-label">鐗╂枡瑙勬牸:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.itemModel" /> + </view> + <view class="form-group"> + <label class="form-label">璁㈠崟缂栧彿:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.saleOrderNo" /> + </view> + <view class="form-group"> + <label class="form-label">閫佹鏁伴噺:</label> + <input class="form-input" disabled="true" type="number" v-model="formData.planQty" /> + </view> + <view class="form-group"> + <label class="form-label">鍒涘缓鏃堕棿:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.createDate" /> + </view> + <view class="form-group"> + <label class="form-label">鍒涘缓浜�:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.createUser" /> + </view> + <view class="form-group"> + <label class="form-label">涓嶈壇鎻忚堪:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.remeke" /> + </view> + </form> + </view> + + <!-- 妫�楠岄」鐩崱鐗� --> + <view class="inspection-card"> + <view class="card-header"> + <view class="header-icon">馃攳</view> + <text class="header-title">妫�楠岄」鐩�</text> + <view class="header-badge">{{ tableData.length }}</view> + </view> + + <view class="inspection-list" v-if="tableData.length > 0"> + <view v-for="(item, index) in tableData" :key="index" class="inspection-item" + :class="{ 'item-completed': item.fcheckResu === '鍚堟牸', 'item-failed': item.fcheckResu === '涓嶅悎鏍�' }"> + + <!-- 宸︿晶鐘舵�佹寚绀哄櫒 --> + <view class="status-indicator" + :class="{ 'status-pass': item.fcheckResu === '鍚堟牸', 'status-fail': item.fcheckResu === '涓嶅悎鏍�', 'status-pending': item.fcheckResu === '鏈楠�' }"> + </view> + + <!-- 涓昏鍐呭鍖哄煙 --> + <view class="item-content"> + <view class="item-header"> + <view class="item-title">{{ item.fcheckItem }}</view> + <view class="status-badge" + :class="{ 'badge-pass': item.fcheckResu === '鍚堟牸', 'badge-fail': item.fcheckResu === '涓嶅悎鏍�', 'badge-pending': item.fcheckResu === '鏈楠�' }"> + <text class="status-icon">{{ item.fcheckResu === '鍚堟牸' ? '鉁�' : item.fcheckResu === '涓嶅悎鏍�' ? '鉁�' : '鈼�' }}</text> + <text class="status-text">{{ item.fcheckResu }}</text> + </view> + </view> + + <view class="item-description" v-if="item.fcheckItemDesc"> + <text class="description-text">{{ item.fcheckItemDesc }}</text> + </view> + + <view class="item-footer"> + <view class="progress-info"> + <text class="progress-label">妫�楠岃繘搴�:</text> + <view class="progress-bar"> + <view class="progress-fill" + :style="{ width: (item.fenterQty / item.checkQyt * 100) + '%' }" + :class="{ 'progress-complete': item.fenterQty >= item.checkQyt, 'progress-incomplete': item.fenterQty < item.checkQyt }"> + </view> + </view> + <text class="progress-text">{{ item.fenterQty }}/{{ item.checkQyt }}</text> + </view> + + <view class="action-button" @click="toDetail(item)" + :class="{ 'btn-complete': item.fenterQty >= item.checkQyt, 'btn-incomplete': item.fenterQty < item.checkQyt }"> + <text class="btn-text">{{ item.fenterQty >= item.checkQyt ? '鏌ョ湅璇︽儏' : '寮�濮嬫楠�' }}</text> + <text class="btn-icon">鈫�</text> + </view> + </view> + </view> + </view> + </view> + + <!-- 绌虹姸鎬� --> + <view v-else class="empty-state"> + <view class="empty-icon">馃搵</view> + <text class="empty-text">鏆傛棤妫�楠岄」鐩�</text> + <text class="empty-desc">璇峰厛鐢熸垚妫�楠岄」鐩�</text> + </view> + </view> + + <!-- 鎿嶄綔鎸夐挳鍖哄煙 --> + <view class="action-buttons"> + <button class="btn btn-primary" @click="submitInspection">鎻愪氦</button> + <button class="secondary-btn" @click="uploadImages">涓婁紶/鏌ョ湅鍥剧墖</button> + <button class="btn btn-secondary" @click="addDefectDescription">娣诲姞涓嶅悎鏍兼弿杩�</button> + </view> + + + <!-- 涓嶅悎鏍兼弿杩板脊鍑哄眰 --> + <view v-if="remarksPopup" class="overlay active"> + <view class="popup" :class="{ 'popup-scale': isPopupAnimated }" @animationend="isPopupAnimated = false"> + <view class="popup-header"> + <h3 class="popup-title">淇敼涓嶅悎鏍兼弿杩�</h3> + <view class="close-btn" @click="remarksPopup = !remarksPopup">脳</view> + </view> + <form> + <view class="form-group"> + <label class="form-label">涓嶅悎鏍兼弿杩�:</label> + <input class="form-input" type="text" v-model="remarks" /> + </view> + <view class="button-group popup-buttons"> + <button :class="['action-btn', 'btn-danger']" @click="editRemarks"> + 淇敼 + </button> + <button :class="['action-btn', 'btn-light']" @click="remarksPopup = !remarksPopup"> + 鍙栨秷 + </button> + </view> + </form> + </view> + </view> + </view> +</template> + +<script> + export default { + data() { + return { + formData: {}, + tableData: [], + remarks: "", + remarksPopup: false, + isPopupAnimated: false, + } + }, + onLoad(options) { + //options涓寘鍚簡url闄勫甫鐨勫弬鏁� + let params = options; + + if (params["id"]) { + this.formData.id = params["id"]; + this.init(); + } + }, + methods: { + init() { + let userName = this.$loginInfo.account; + this.$post({ + url: "/MesOqcItemsDetect02/getPage", + data: { + id: this.formData.id, + createUser: userName, + pageIndex: 1, + limit: 1, + } + }).then(res => { + let data = res.data[0]; + if (data) { + this.formData = data; + this.getDetail5(); + } + }); + }, + + getDetail5() { + let userName = this.$loginInfo.account; + this.$post({ + url: "/MesOqcItemsDetect02/GetDetail5", + data: { + id: this.formData.id, + createUser: userName, + releaseNo: this.formData.releaseNo, + } + }).then(res => { + let data = res.data; + this.tableData = data; + }); + }, + uploadImages() { + // 涓婁紶/鏌ョ湅鍥剧墖鐨勯�昏緫 + uni.navigateTo({ + url: 'ImageItem?id=' + this.formData.releaseNo + }); + }, + addDefectDescription() { + // 纭繚琛ㄥ崟鏁版嵁瀛樺湪 + if (!this.formData) return; + + this.remarksPopup = !this.remarksPopup; + this.remarks = this.formData.remeke || ''; + this.isPopupAnimated = true; + }, + toDetail(item) { + + uni.navigateTo({ + url: 'detail?mainId=' + item.id + '&releaseNo=' + this.formData + .releaseNo + }); + + }, + submitInspection() { + // 妫�楠屾彁浜ょ殑閫昏緫 + this.$post({ + url: "/MesOqcItemsDetect02/IqcQaSubmit", + data: { + userNo: this.$loginInfo.account, + releaseNo: this.formData.releaseNo + } + }).then(res => { + if (res.status == 0) { + + uni.showToast({ + title: res.message.toString(), + icon: 'success', + duration: 2000 + }) + // 濡傛灉鏈夐〉闈㈣烦杞紝闇�瑕佺敤瀹氭椂鍣ㄥ欢杩� + setTimeout(() => { + uni.navigateTo({ + url: 'List' + }); + }, 2000); // 淇濇寔涓� duration 鐩稿悓鐨勬椂闀� + + } else { + uni.showModal({ + title: "鎻愮ず", + content: res.message.toString(), + confirmText: "纭畾", + showCancel: false, + success: (res) => { + + } + }) + } + }) + }, + editRemarks() { + if (this.remarks && this.formData.id) { + this.$post({ + url: "/MesOqcItemsDetect02/saveRemarksGid", + data: { + gid: this.formData.id, + remarks: this.remarks, + releaseNo: this.formData.releaseNo, + } + }).then(res => { + if (res.data.tbBillList > 0) { + this.formData.remarks = this.remarks; + this.remarksPopup = false; + this.$showMessage("淇濆瓨鎴愬姛"); + this.init(); + } else { + this.$showMessage("淇濆瓨澶辫触"); + } + }).catch(() => { + this.$showMessage("淇濆瓨澶辫触锛岃閲嶈瘯"); + }); + } else if (!this.formData.id) { + this.$showMessage("璇峰厛鐢熸垚妫�楠屽崟"); + } else { + this.$showMessage("璇疯緭鍏ヤ笉鍚堟牸鎻忚堪"); + } + }, + } + } +</script> + +<style scoped> +.page-container { + padding: 20px; + background-color: #f5f5f5; + min-height: 100vh; +} + +/* 琛ㄥ崟鍗$墖 */ +.form-card { + background-color: #fff; + border-radius: 12px; + padding: 20px; + margin-bottom: 20px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +/* 琛ㄥ崟缁� */ +.form-group { + display: flex; + align-items: center; + margin-bottom: 15px; +} + +.form-group:last-child { + margin-bottom: 0; +} + +/* 鏍囩鏍峰紡 */ +.form-label { + width: 120px; + color: #333; + font-size: 14px; + font-weight: 500; + flex-shrink: 0; +} + +/* 杈撳叆妗嗘牱寮� */ +.form-input { + flex: 1; + height: 40px; + padding: 0 10px; + border: 1px solid #e0e0e0; + border-radius: 8px; + background-color: #f8f8f8; + color: #666; + font-size: 14px; + transition: all 0.3s ease; +} + +.form-input:disabled { + background-color: #e9e9e9; +} + +.form-input:focus { + border-color: #007AFF; + outline: none; +} + +/* 鎿嶄綔鎸夐挳鍖哄煙 */ +.action-buttons { + display: flex; + justify-content: space-between; + gap: 15px; + padding: 15px 0; +} + +.btn { + flex: 1; + height: 45px; + border-radius: 8px; + border: none; + color: #fff; + font-size: 14px; + font-weight: 500; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: background-color 0.3s ease; +} + +.btn-primary { + background-color: #007AFF; +} + +.btn-primary:hover { + background-color: #0056CC; +} + +.secondary-btn { + background-color: #8E8E93; +} + +.secondary-btn:hover { + background-color: #6D6D70; +} + +.btn-secondary { + background-color: #8E8E93; +} + +.btn-secondary:hover { + background-color: #6D6D70; +} + +/* 妫�楠岄」鐩崱鐗� */ +.inspection-card { + background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%); + border-radius: 16px; + padding: 0; + margin-bottom: 24px; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08); + border: 1px solid #e2e8f0; + overflow: hidden; +} + +/* 鍗$墖澶撮儴 */ +.card-header { + background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%); + padding: 20px 24px; + display: flex; + align-items: center; + justify-content: space-between; + position: relative; +} + +.card-header::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(45deg, rgba(255,255,255,0.1) 0%, transparent 100%); + pointer-events: none; +} + +.header-icon { + font-size: 24px; + margin-right: 12px; +} + +.header-title { + color: white; + font-size: 18px; + font-weight: 600; + flex: 1; +} + +.header-badge { + background: rgba(255, 255, 255, 0.2); + color: white; + padding: 6px 12px; + border-radius: 20px; + font-size: 14px; + font-weight: 500; + backdrop-filter: blur(10px); +} + +/* 妫�楠屽垪琛� */ +.inspection-list { + padding: 24px; +} + +.inspection-item { + background: white; + border-radius: 12px; + margin-bottom: 16px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); + border: 1px solid #e2e8f0; + overflow: hidden; + transition: all 0.3s ease; + position: relative; +} + +.inspection-item:hover { + transform: translateY(-2px); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); +} + +.inspection-item:last-child { + margin-bottom: 0; +} + +.inspection-item.item-completed { + border-left: 4px solid #10b981; + background: linear-gradient(135deg, #ffffff 0%, #f0fdf4 100%); +} + +.inspection-item.item-failed { + border-left: 4px solid #ef4444; + background: linear-gradient(135deg, #ffffff 0%, #fef2f2 100%); +} + +/* 鐘舵�佹寚绀哄櫒 */ +.status-indicator { + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 4px; + background: #e2e8f0; +} + +.status-indicator.status-pass { + background: linear-gradient(180deg, #10b981 0%, #059669 100%); +} + +.status-indicator.status-fail { + background: linear-gradient(180deg, #ef4444 0%, #dc2626 100%); +} + +.status-indicator.status-pending { + background: linear-gradient(180deg, #f59e0b 0%, #d97706 100%); +} + +/* 椤圭洰鍐呭 */ +.item-content { + padding: 20px 24px; + margin-left: 4px; +} + +.item-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 12px; +} + +.item-title { + font-size: 16px; + font-weight: 600; + color: #1e293b; + flex: 1; +} + +.status-badge { + display: flex; + align-items: center; + padding: 6px 12px; + border-radius: 20px; + font-size: 12px; + font-weight: 500; +} + +.status-badge.badge-pass { + background: linear-gradient(135deg, #dcfce7 0%, #bbf7d0 100%); + color: #166534; + border: 1px solid #86efac; +} + +.status-badge.badge-fail { + background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%); + color: #991b1b; + border: 1px solid #fca5a5; +} + +.status-badge.badge-pending { + background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%); + color: #92400e; + border: 1px solid #fcd34d; +} + +.status-icon { + margin-right: 6px; + font-weight: bold; +} + +/* 椤圭洰鎻忚堪 */ +.item-description { + margin-bottom: 16px; +} + +.description-text { + color: #64748b; + font-size: 14px; + line-height: 1.5; + background: #f8fafc; + padding: 12px 16px; + border-radius: 8px; + border-left: 3px solid #e2e8f0; +} + +/* 椤圭洰搴曢儴 */ +.item-footer { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; +} + +.progress-info { + display: flex; + align-items: center; + gap: 12px; + flex: 1; +} + +.progress-label { + font-size: 14px; + color: #64748b; + font-weight: 500; + white-space: nowrap; +} + +.progress-bar { + flex: 1; + height: 8px; + background: #e2e8f0; + border-radius: 4px; + overflow: hidden; + position: relative; +} + +.progress-fill { + height: 100%; + border-radius: 4px; + transition: all 0.3s ease; + position: relative; +} + +.progress-fill.progress-complete { + background: linear-gradient(90deg, #10b981 0%, #059669 100%); +} + +.progress-fill.progress-incomplete { + background: linear-gradient(90deg, #f59e0b 0%, #d97706 100%); +} + +.progress-text { + font-size: 14px; + color: #374151; + font-weight: 600; + white-space: nowrap; +} + +/* 鎿嶄綔鎸夐挳 */ +.action-button { + display: flex; + align-items: center; + gap: 8px; + padding: 10px 16px; + border-radius: 8px; + cursor: pointer; + transition: all 0.3s ease; + font-size: 14px; + font-weight: 500; + white-space: nowrap; +} + +.action-button.btn-complete { + background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%); + color: #1e40af; + border: 1px solid #93c5fd; +} + +.action-button.btn-complete:hover { + background: linear-gradient(135deg, #bfdbfe 0%, #93c5fd 100%); + transform: translateX(4px); +} + +.action-button.btn-incomplete { + background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%); + color: #92400e; + border: 1px solid #fcd34d; +} + +.action-button.btn-incomplete:hover { + background: linear-gradient(135deg, #fde68a 0%, #fcd34d 100%); + transform: translateX(4px); +} + +.btn-text { + font-size: 14px; +} + +.btn-icon { + font-size: 16px; + transition: transform 0.3s ease; +} + +.action-button:hover .btn-icon { + transform: translateX(4px); +} + +/* 绌虹姸鎬� */ +.empty-state { + padding: 60px 24px; + text-align: center; + background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%); +} + +.empty-icon { + font-size: 48px; + margin-bottom: 16px; + opacity: 0.6; +} + +.empty-text { + font-size: 18px; + color: #64748b; + font-weight: 500; + margin-bottom: 8px; + display: block; +} + +.empty-desc { + font-size: 14px; + color: #94a3b8; + display: block; +} + +/* 鍝嶅簲寮忚璁� */ +@media (max-width: 768px) { + .inspection-card { + margin: 0 -8px 24px -8px; + border-radius: 12px; + } + + .card-header { + padding: 16px 20px; + } + + .header-title { + font-size: 16px; + } + + .inspection-list { + padding: 16px 20px; + } + + .item-content { + padding: 16px 20px; + } + + .item-header { + flex-direction: column; + align-items: flex-start; + gap: 8px; + } + + .item-footer { + flex-direction: column; + align-items: stretch; + gap: 12px; + } + + .progress-info { + flex-direction: column; + align-items: stretch; + gap: 8px; + } + + .action-button { + justify-content: center; + } +} + +/* 杈撳叆妗嗕腑鏄剧ず鐨勫伐鍏锋彁绀� */ +.value-with-tooltip { + position: relative; +} + +.value-with-tooltip .tooltip { + position: absolute; + top: -30px; + left: 0; + background-color: rgba(0, 0, 0, 0.6); + color: #fff; + font-size: 12px; + padding: 5px; + border-radius: 4px; +} + +/* 寮瑰嚭灞傛牱寮� */ +.overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; + opacity: 0; + transition: opacity 0.3s ease; +} + +.overlay.active { + opacity: 1; +} + +.popup { + background-color: #fff; + border-radius: 12px; + width: 90%; + max-width: 500px; + padding: 20px; + transform: scale(0.8); + transition: transform 0.3s ease; +} + +.popup-scale { + transform: scale(1); +} + +.popup-header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.popup-title { + font-size: 16px; + font-weight: 600; + color: #333; +} + +.close-btn { + font-size: 20px; + color: #333; + cursor: pointer; +} + +.button-group { + display: flex; + justify-content: space-between; + margin-top: 20px; +} + +.action-btn { + width: 48%; + padding: 10px; + border-radius: 8px; + border: none; + font-size: 14px; + font-weight: 500; +} + +.btn-danger { + background-color: #dc3545; + color: #fff; +} + +.btn-light { + background-color: #f8f8f8; + color: #333; +} + +.btn-danger:hover { + background-color: #c82333; +} + +.btn-light:hover { + background-color: #e9e9e9; +} + +</style> \ No newline at end of file diff --git a/pages/QC/OQC/ImageItem.vue b/pages/QC/OQC/ImageItem.vue new file mode 100644 index 0000000..293fd14 --- /dev/null +++ b/pages/QC/OQC/ImageItem.vue @@ -0,0 +1,234 @@ +<template> + <!-- #ifdef APP --> + <scroll-view class="page-scroll-view"> + <!-- #endif --> + <view> + <view class="uni-common-mt"> + <view class="uni-list list-pd" style="padding: 15px;"> + <view class="uni-flex" style="margin-bottom: 10px;"> + <view class="uni-list-cell-left">鐐瑰嚮鍙瑙堥�夊ソ鐨勫浘鐗�</view> + <view style="margin-left: auto;"> + <view class="click-t">鍏辨湁{{ qsImage.length }}寮犲浘鐗�</view> + </view> + </view> + <view class="uni-flex" style="flex-wrap: wrap;"> + <view v-for="(image,index) in qsImage" :key="index" class="uni-uploader__input-box" + style="position: relative; border: 0;"> + <image :src="image.img" :data-src="image.img" + @tap="previewImage(index)"></image> + <image src="/static/plus.png" class="image-remove" @click="removeImage(index,image.id)"></image> + </view> + <image class="uni-uploader__input-box" @tap="chooseImage" src="/static/plus.png"></image> + </view> + </view> + </view> + <view class="plus-button"> + <button type="primary" class="upImg" @click="save">涓婁紶鍥剧墖</button> + </view> + </view> + <!-- #ifdef APP --> + </scroll-view> + <!-- #endif --> +</template> + +<script> + +import {pathToBase64, base64ToPath} from '../../../js_sdk/mmmm-image-tools/index' + +var sourceTypeArray = [ + ['camera'], + ['album'], + ['camera', 'album'] +] +var sizeTypeArray = [ + ['compressed'], + ['original'], + ['compressed', 'original'] +] +export default { + data() { + return { + title: 'choose/previewImage', + sourceTypeIndex: 2, + sourceType: ['鎷嶇収', '鐩稿唽', '鎷嶇収鎴栫浉鍐�'], + sizeTypeIndex: 2, + sizeType: ['鍘嬬缉', '鍘熷浘', '鍘嬬缉鎴栧師鍥�'], + countIndex: 8, + count: [1, 2, 3, 4, 5, 6, 7, 8, 9], + isCrop: false, + cropPercent: 80, + cropWidth: 100, + cropHeight: 100, + cropResize: false, + qsImage: [], + fid: 0, + qsType : 5, + } + }, + onLoad(options) { + //options涓寘鍚簡url闄勫甫鐨勫弬鏁� + + let params = options; + + if (params["id"]) { + this.fid = params["id"]; + //getQaItemXj02 + this.init(); + } + }, + onUnload() { + this.qsImage = []; + this.sourceTypeIndex = 2 + this.sourceType = ['鎷嶇収', '鐩稿唽', '鎷嶇収鎴栫浉鍐�'] + this.sizeTypeIndex = 2 + this.sizeType = ['鍘嬬缉', '鍘熷浘', '鍘嬬缉鎴栧師鍥�'] + this.countIndex = 8 + }, + methods: { + removeImage(index, id) { + this.qsImage.splice(index, 1); + if (id) { + this.$post({ + url: "/Base/removeImage", + data: { + id: id + } + }).then(res => { + }); + } + }, + chooseImage() { + if (this.qsImage.length >= 9) { + uni.showToast({ + position: "bottom", + title: "宸茬粡鏈�9寮犲浘鐗囦簡锛岃鍒犻櫎閮ㄥ垎鍥剧墖涔嬪悗閲嶆柊閫夋嫨" + }); + return; + } + + uni.chooseImage({ + sourceType: sourceTypeArray[this.sourceTypeIndex], + sizeType: sizeTypeArray[this.sizeTypeIndex], + crop: this.isCrop ? { + "quality": this.cropPercent, + "width": this.cropWidth, + "height": this.cropHeight, + "resize": this.cropResize + } : null, + count: this.qsImage.length + this.count[this.countIndex] > 9 ? 9 - this.qsImage.length : this.count[this.countIndex], + success: (res) => { + let url = res.tempFilePaths[0]; + pathToBase64(url) + .then(base64 => { + // 鎵惧埌鏈�鍚庝竴涓枩鏉犵殑浣嶇疆 + let lastSlashIndex = url.lastIndexOf("/"); + // 鎻愬彇鏂囦欢鍚� + let fileName = url.substring(lastSlashIndex + 1); + let entity = {}; + entity.img = base64; + entity.Picturename = fileName; + entity.fid = this.fid; + entity.qsType = this.qsType; + entity.base64Date = base64.split(',')[1]; + + this.qsImage.push(entity); + }) + .catch(error => { + console.error(error) + }) + }, + fail: (err) => { + console.log("err: ", JSON.stringify(err)); + } + }); + }, + previewImage(index) { + // uni.previewImage({ + // current: index, // 璁剧疆褰撳墠鏄剧ず鍥剧墖鐨勯摼鎺� + // urls: this.qsImage.map(s=>s.img), // 闇�瑕侀瑙堢殑鍥剧墖閾炬帴鍒楄〃 + // loop: false, // 鏄惁寮�鍚浘鐗囪疆鎾紝榛樿涓� false + // indicator: 'default',// 鍥剧墖鎸囩ず鍣ㄧ被鍨嬶紝鍙�夊�间负 "default"銆�"number"銆�"pointer"锛岄粯璁や负 "default" + // }); + }, + init() { + this.$post({ + url: "/Base/getLljAllImgByFid", + data: { + id: this.fid, + qsType: this.qsType + } + }).then(res => { + let tableData = res.data.tbBillList; + this.qsImage = tableData; + this.qsImage.forEach(s => { + s.img = 'data:image/png;base64,' + s.base64Date; + }); + }); + }, + save() { + this.$post({ + url: "/Base/saveImage", + data: { + entity: this.qsImage + } + }).then(res => { + this.init(); + this.$showMessage("淇濆瓨鎴愬姛"); + }); + } + } +} +</script> + +<style> +.click-t { + color: darkgray; +} + +.list-pd { + margin-top: 25px; +} + +.uni-uploader__input-box { + margin: 5px; + border: 1px solid #D9D9D9; +} + +.image-remove { + transform: rotate(45deg); + width: 25px; + height: 25px; + position: absolute; + top: 0; + right: 0; + border-radius: 13px; + background-color: #FF0000; +} + +.uni-common-mt { + background-color: #ffffff; + /* 绾㈣壊鑳屾櫙 */ +} + +.plus-button { + position: fixed; + left: 0; + bottom: 0; + width: 100%; + background-color: #ffffff; /* 鑳屾櫙棰滆壊 */ + /* padding: 10px; */ + box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.1); /* 娣诲姞搴曢儴闃村奖鏁堟灉 */ + z-index: 999; /* 纭繚鎸夐挳浣嶄簬椤跺眰 */ +} + +.uni-flex { + max-height: calc(100vh - 240px); /* 灞忓箷楂樺害鍑忓幓涓婁紶鎸夐挳楂樺害 */ + overflow-y: auto; /* 褰撳唴瀹硅秴鍑洪珮搴︽椂鍑虹幇鍨傜洿婊氬姩鏉� */ +} +.upImg{ + + background-color: #3498db; + color: white; + +} +</style> \ No newline at end of file diff --git a/pages/QC/OQC/List.vue b/pages/QC/OQC/List.vue new file mode 100644 index 0000000..14ab0dc --- /dev/null +++ b/pages/QC/OQC/List.vue @@ -0,0 +1,1090 @@ +<template> + <view class="page-container"> + <!-- 鍒锋柊鎻愮ず妗� --> + <view class="success-toast" :class="{ 'show': tipShow }"> + <view class="toast-icon">鉁�</view> + <text class="toast-text">鍒锋柊鎴愬姛</text> + </view> + + <!-- 澶撮儴鍖哄煙 --> + <view class="header-section"> + <!-- 椤甸潰鏍囬 --> + <view class="page-header"> + <view class="header-content"> + <view class="title-section"> + <text class="page-title">OQC妫�楠屽崟</text> + <text class="page-subtitle">璐ㄩ噺妫�楠岀鐞�</text> + </view> + <view class="stats-badge"> + <text class="stats-number">{{ totalCount }}</text> + <text class="stats-label">鎬昏</text> + </view> + </view> + </view> + + <!-- 鎼滅储鏍� --> + <!-- <view class="search-section"> --> + <!-- <view class="search-container"> + <view class="search-input-wrapper"> + <uni-icons type="search" size="18" color="#94a3b8"></uni-icons> + <input class="search-input" type="text" v-model="searchValue" + @confirm="getInputValue" placeholder="鎼滅储妫�楠屽崟鍙枫�佺墿鏂欑紪鐮�..." /> + <view v-if="searchValue" class="clear-btn" @tap="clearSearch"> + <uni-icons type="clear" size="16" color="#94a3b8"></uni-icons> + </view> + </view> + <view class="filter-btn" @tap="toggleFilter"> + <uni-icons type="tune" size="18" color="#4f46e5"></uni-icons> + </view> + </view> --> + + <!-- 绛涢�夊櫒 --> + <!-- <view v-if="showFilter" class="filter-panel"> + <picker mode="selector" :range="searchOptions" v-model="selectedOption" @change="onPickerChange"> + <view class="filter-option"> + <text class="filter-label">绛涢�夋潯浠�</text> + <text class="filter-value">{{ searchOptions[selectedOption] }}</text> + <uni-icons type="arrowdown" size="14" color="#64748b"></uni-icons> + </view> + </picker> + </view> --> + <!-- </view> --> + + <!-- 閫夐」鍗� --> + <view class="tab-section"> + <view class="custom-tabs"> + <view v-for="(item, index) in items" :key="index" + class="tab-item" :class="{ 'active': current === index }" + @tap="onClickItem({ currentIndex: index })"> + <text class="tab-text">{{ item }}</text> + <view class="tab-indicator" v-if="current === index"></view> + </view> + </view> + </view> + </view> + + <!-- 鍐呭鍖哄煙 --> + <view class="content-container"> + <view v-show="current === 0"> + <!-- 鍔犺浇鐘舵�� --> + <view v-if="isLoading" class="loading-state"> + <view class="loading-spinner"></view> + <text class="loading-text">鍔犺浇涓�...</text> + </view> + + <!-- 绌虹姸鎬� --> + <view v-else-if="data.length === 0" class="empty-state"> + <view class="empty-icon">馃搵</view> + <text class="empty-title">鏆傛棤妫�楠屽崟</text> + <text class="empty-desc">鐐瑰嚮鍙充笅瑙掓寜閽垱寤烘柊鐨勬楠屽崟</text> + </view> + + <!-- 妫�楠屽崟鍒楄〃 --> + <view v-else class="inspection-list"> + <view v-for="item in data" :key="item.id || item.releaseNo" + class="inspection-card" @tap="navigateToDetail(item)"> + + <!-- 鍗$墖澶撮儴 --> + <view class="card-header"> + <view class="header-left"> + <view class="inspection-number"> + <text class="number-label">妫�楠屽崟鍙�</text> + <text class="number-value">{{ item.releaseNo }}</text> + </view> + <view class="material-info"> + <text class="material-code">{{ item.itemNo }}</text> + <text class="material-name">{{ item.itemName || '鏈煡鐗╂枡' }}</text> + </view> + </view> + <view class="header-right"> + <view class="status-badge" + :class="{ + 'status-submitted': item.fsubmit == 1, + 'status-pending': item.fsubmit != 1 + }"> + <view class="status-dot"></view> + <text class="status-text">{{ item.fsubmit == 1 ? '宸叉彁浜�' : '寰呮彁浜�' }}</text> + </view> + </view> + </view> + + <!-- 妫�楠岀粨鏋滃尯鍩� --> + <view class="inspection-result"> + <view class="result-item"> + <view class="result-icon" + :class="{ + 'icon-pass': item.fcheckResu === '鍚堟牸', + 'icon-fail': item.fcheckResu === '涓嶅悎鏍�', + 'icon-pending': !item.fcheckResu || item.fcheckResu === '鏈楠�' + }"> + <text class="result-symbol">{{ + item.fcheckResu === '鍚堟牸' ? '鉁�' : + item.fcheckResu === '涓嶅悎鏍�' ? '鉁�' : '鈼�' + }}</text> + </view> + <view class="result-content"> + <text class="result-label">妫�楠岀粨鏋�</text> + <text class="result-value" + :class="{ + 'value-pass': item.fcheckResu === '鍚堟牸', + 'value-fail': item.fcheckResu === '涓嶅悎鏍�', + 'value-pending': !item.fcheckResu || item.fcheckResu === '鏈楠�' + }"> + {{ item.fcheckResu || '鏈楠�' }} + </text> + </view> + </view> + + <view class="inspector-info"> + <text class="inspector-label">妫�楠屼汉</text> + <text class="inspector-name">{{ item.modify1By || '寰呭垎閰�' }}</text> + </view> + </view> + + <!-- 璇︾粏淇℃伅 --> + <view class="card-details"> + <view class="detail-grid"> + <view class="detail-item"> + <text class="detail-label">鍒涘缓鏃堕棿</text> + <text class="detail-value">{{ item.createDate }}</text> + </view> + <view class="detail-item"> + <text class="detail-label">鏁伴噺</text> + <text class="detail-value">{{ item.planQty }}</text> + </view> + <view class="detail-item"> + <text class="detail-label">鍒涘缓浜�</text> + <text class="detail-value">{{ item.createUser }}</text> + </view> + <view class="detail-item"> + <text class="detail-label">閫佹浜�</text> + <text class="detail-value">{{ item.fcheckUser || '-' }}</text> + </view> + </view> + </view> + + <!-- 鎿嶄綔鎸囩ず鍣� --> + <view class="action-indicator"> + <uni-icons type="arrowright" size="16" color="#94a3b8"></uni-icons> + </view> + </view> + </view> + </view> + <!-- 绗簩涓�夐」鍗″唴瀹� - 宸叉楠� --> + <view v-show="current === 1"> + <!-- 鍔犺浇鐘舵�� --> + <view v-if="isLoading" class="loading-state"> + <view class="loading-spinner"></view> + <text class="loading-text">鍔犺浇涓�...</text> + </view> + + <!-- 绌虹姸鎬� --> + <view v-else-if="data.length === 0" class="empty-state"> + <view class="empty-icon">鉁�</view> + <text class="empty-title">鏆傛棤宸叉楠屽崟鎹�</text> + <text class="empty-desc">瀹屾垚妫�楠岀殑鍗曟嵁灏嗘樉绀哄湪杩欓噷</text> + </view> + + <!-- 妫�楠屽崟鍒楄〃 --> + <view v-else class="inspection-list"> + <view v-for="item in data" :key="item.id || item.releaseNo" + class="inspection-card completed" @tap="navigateToDetail(item)"> + + <!-- 鍗$墖澶撮儴 --> + <view class="card-header"> + <view class="header-left"> + <view class="inspection-number"> + <text class="number-label">妫�楠屽崟鍙�</text> + <text class="number-value">{{ item.releaseNo }}</text> + </view> + <view class="material-info"> + <text class="material-code">{{ item.itemNo }}</text> + <text class="material-name">{{ item.itemName || '鏈煡鐗╂枡' }}</text> + </view> + </view> + <view class="header-right"> + <view class="status-badge status-completed"> + <view class="status-dot"></view> + <text class="status-text">宸插畬鎴�</text> + </view> + </view> + </view> + + <!-- 妫�楠岀粨鏋滃尯鍩� --> + <view class="inspection-result"> + <view class="result-item"> + <view class="result-icon" + :class="{ + 'icon-pass': item.fcheckResu === '鍚堟牸', + 'icon-fail': item.fcheckResu === '涓嶅悎鏍�' + }"> + <text class="result-symbol">{{ + item.fcheckResu === '鍚堟牸' ? '鉁�' : '鉁�' + }}</text> + </view> + <view class="result-content"> + <text class="result-label">鏈�缁堢粨鏋�</text> + <text class="result-value" + :class="{ + 'value-pass': item.fcheckResu === '鍚堟牸', + 'value-fail': item.fcheckResu === '涓嶅悎鏍�' + }"> + {{ item.fcheckResu }} + </text> + </view> + </view> + + <view class="inspector-info"> + <text class="inspector-label">妫�楠屼汉</text> + <text class="inspector-name">{{ item.modify1By }}</text> + </view> + </view> + + <!-- 璇︾粏淇℃伅 --> + <view class="card-details"> + <view class="detail-grid"> + <view class="detail-item"> + <text class="detail-label">妫�楠屾椂闂�</text> + <text class="detail-value">{{ item.modify1Date }}</text> + </view> + <view class="detail-item"> + <text class="detail-label">鏁伴噺</text> + <text class="detail-value">{{ item.planQty }}</text> + </view> + <view class="detail-item"> + <text class="detail-label">鍒涘缓浜�</text> + <text class="detail-value">{{ item.createUser }}</text> + </view> + <view class="detail-item"> + <text class="detail-label">閫佹浜�</text> + <text class="detail-value">{{ item.fcheckUser || '-' }}</text> + </view> + </view> + </view> + + <!-- 鎿嶄綔鎸囩ず鍣� --> + <view class="action-indicator"> + <uni-icons type="arrowright" size="16" color="#94a3b8"></uni-icons> + </view> + </view> + </view> + </view> + </view> + + <!-- 娴姩鎿嶄綔鎸夐挳 --> + <view class="fab-container"> + <view class="fab-button" @tap="handleFabClick"> + <uni-icons type="plus" size="24" color="#ffffff"></uni-icons> + </view> + </view> + </view> +</template> + +<script> + export default { + components: {}, + data() { + return { + items: ['鏈楠�', '宸叉楠�'], + current: 0, + data: [], + pageIndex: 1, + limit: 20, + totalPage: 0, + totalCount: 0, + noData: false, + isLoading: false, + tipShow: false, + searchOptions: ['鐗╂枡缂栧彿', '瑙勬牸', '鐗╂枡鍚嶇О', '渚涘簲鍟�', '閫佹浜�', '妫�楠屽崟鍙�'], + selectedOption: 0, + searchValue: '', + copiedText: '', + headerHeight: 0, + showFilter: false, // 鎺у埗绛涢�夐潰鏉挎樉绀� + }; + }, + onLoad() { + this.init(); + }, + onShow() { + // 椤甸潰鏄剧ず鏃跺埛鏂版暟鎹� + this.pageIndex = 1; + this.loadData(); + }, + methods: { + onPickerChange(e) { + this.selectedOption = e.detail.value; + }, + getInputValue() { + this.pageIndex = 1; // 鎼滅储鏃堕噸缃〉鐮� + this.loadData(); // 璋冪敤缁熶竴鐨勬暟鎹姞杞芥柟娉� + }, + loadData() { + let result = "鏈畬鎴�"; + if (this.current === 1) { + result = "宸插畬鎴�"; + } + + if (this.isLoading) return; + + this.isLoading = true; + + let userName = this.$loginInfo.account; + let url = "/MesOqcItemsDetect02/getPage"; // 榛樿璋冪敤getPage + let requestData = { + pageIndex: this.pageIndex, + limit: this.limit, + createUser: userName, + result: result + }; + + console.log("璇锋眰鍙傛暟:", requestData); + console.log("褰撳墠閫夐」鍗�:", this.current); + console.log("result鐘舵��:", result); + + // 鍒ゆ柇鎼滅储妗嗘槸鍚︽湁鍊� + if (this.searchValue != null && this.searchValue.trim() !== '') { + // 鏍规嵁閫夋嫨鐨勬悳绱㈤�夐」璁剧疆鎼滅储鏉′欢 + switch (this.selectedOption) { + case 0: + requestData.ItemNo = this.searchValue; + break; + case 1: + requestData.SalesOrder = this.searchValue; + break; + case 2: + requestData.ItemName = this.searchValue; + break; + case 3: + requestData.SuppNameContains = this.searchValue; + break; + case 4: + requestData.SongJ = this.searchValue; + break; + case 5: + requestData.SongNo = this.searchValue; + break; + } + } + + this.$post({ + url: url, + data: requestData + }).then(res => { + console.log("API杩斿洖瀹屾暣鏁版嵁:", JSON.stringify(res, null, 2)); + console.log("res缁撴瀯:", res); + console.log("res.data:", res.data); + console.log("res.totalCount:", res.totalCount); + + // 鏍规嵁鍝嶅簲鏍煎紡.json锛屾纭殑鏁版嵁缁撴瀯鏄細 + // res.data 鏄暟缁勶紝res.totalCount 鏄�绘暟 + let dataList = null; + let totalCount = 0; + + if (res.data && Array.isArray(res.data)) { + // 姝g‘鐨勬暟鎹粨鏋勶細data鏄暟缁� + dataList = res.data; + totalCount = res.totalCount || 0; + } else if (res.tbBillList) { + // 澶囩敤缁撴瀯锛堝吋瀹瑰叾浠栨帴鍙o級 + dataList = res.tbBillList; + totalCount = res.totalCount || 0; + } else { + console.error("鏃犳硶瑙f瀽鐨勬暟鎹粨鏋�:", res); + console.error("鏈熸湜鐨勫瓧娈� data (鏁扮粍) 涓嶅瓨鍦�"); + this.$showMessage("鏁版嵁鏍煎紡閿欒锛岃鑱旂郴鎶�鏈敮鎸�"); + this.isLoading = false; + return; + } + + console.log("瑙f瀽鍚庣殑dataList:", dataList); + console.log("dataList闀垮害:", dataList ? dataList.length : 0); + + if (this.pageIndex === 1) { + this.data = dataList || []; + } else { + if (dataList && dataList.length > 0) { + this.data = [...this.data, ...dataList]; + } + } + + console.log("澶勭悊鍚庣殑data:", this.data); + console.log("data闀垮害:", this.data.length); + + this.totalCount = totalCount; + this.totalPage = Math.ceil(this.totalCount / this.limit); + + this.noData = this.pageIndex >= this.totalPage; + this.isLoading = false; + }).catch((error) => { + console.error("API璇锋眰澶辫触:", error); + this.isLoading = false; + this.searchValue = ''; + this.$showMessage("璇锋眰澶辫触锛岃閲嶈瘯"); + }); + }, + init() { + this.loadData(); // 缁熶竴璋冪敤loadData鏂规硶 + }, + handleFabClick() { + uni.navigateTo({ + url: 'ScanCode' + }); + }, + onClickItem(index) { + if (this.current !== index.currentIndex) { + this.current = index.currentIndex; + this.data = []; + this.pageIndex = 1; + this.loadData(); // 閫夐」鍗″垏鎹㈡椂璋冪敤loadData + } + }, + copyText(text) { + uni.setClipboardData({ + data: text, + success: () => { + this.copiedText = text; + this.tipShow = true; + setTimeout(() => { + this.tipShow = false; + }, 1000); + } + }); + }, + // 鏂板鏂规硶 + navigateToDetail(item) { + uni.navigateTo({ + url: 'Add?id=' + item.id + }); + }, + toggleFilter() { + this.showFilter = !this.showFilter; + }, + clearSearch() { + this.searchValue = ''; + this.pageIndex = 1; + this.loadData(); + } + }, + onPullDownRefresh() { + this.pageIndex = 1; + this.loadData(); + this.tipShow = true; + uni.stopPullDownRefresh(); + + setTimeout(() => { + this.tipShow = false; + }, 1000); + }, + onReachBottom() { + if (this.noData || this.isLoading) return; + this.pageIndex++; + this.loadData(); // 涓婃媺鍔犺浇鏃惰皟鐢╨oadData + } + }; +</script> + +<style> +/* 椤甸潰瀹瑰櫒 */ +.page-container { + min-height: 100vh; + background: #f5f5f5; + padding: 0; + display: flex; + flex-direction: column; +} + +/* 鎴愬姛鎻愮ず妗� */ +.success-toast { + position: fixed; + top: 20px; + left: 50%; + transform: translateX(-50%) translateY(-100px); + background: #28a745; + color: white; + padding: 8px 16px; + border-radius: 6px; + display: flex; + align-items: center; + gap: 6px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); + z-index: 1000; + opacity: 0; + transition: all 0.3s ease; +} + +.success-toast.show { + opacity: 1; + transform: translateX(-50%) translateY(0); +} + +.toast-icon { + font-size: 14px; + font-weight: bold; +} + +.toast-text { + font-size: 14px; +} + +/* 澶撮儴鍖哄煙 */ +.header-section { + background: white; + padding: 16px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} + +/* 椤甸潰鏍囬 */ +.page-header { + margin-bottom: 16px; +} + +.header-content { + display: flex; + justify-content: space-between; + align-items: center; +} + +.title-section { + flex: 1; +} + +.page-title { + font-size: 20px; + font-weight: 600; + color: #333; + margin-bottom: 2px; + display: block; +} + +.page-subtitle { + font-size: 13px; + color: #666; + display: block; +} + +.stats-badge { + background: #007AFF; + color: white; + padding: 8px 12px; + border-radius: 8px; + text-align: center; + min-width: 60px; +} + +.stats-number { + font-size: 16px; + font-weight: 600; + display: block; + line-height: 1; +} + +.stats-label { + font-size: 11px; + display: block; + margin-top: 2px; +} + +/* 鎼滅储鍖哄煙 */ +.search-section { + margin-bottom: 16px; +} + +.search-container { + display: flex; + gap: 8px; + align-items: center; +} + +.search-input-wrapper { + flex: 1; + position: relative; + display: flex; + align-items: center; + background: #f8f8f8; + border: 1px solid #ddd; + border-radius: 8px; + padding: 0 12px; +} + +.search-input-wrapper:focus-within { + border-color: #007AFF; + background: white; +} + +.search-input { + flex: 1; + height: 40px; + border: none; + background: transparent; + font-size: 14px; + color: #333; + margin-left: 8px; + outline: none; +} + +.search-input::placeholder { + color: #999; +} + +.clear-btn { + padding: 4px; + cursor: pointer; +} + +.filter-btn { + width: 40px; + height: 40px; + background: #f0f0f0; + border: 1px solid #ddd; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; +} + +.filter-btn:active { + background: #e0e0e0; +} + +/* 绛涢�夐潰鏉� */ +.filter-panel { + margin-top: 8px; + background: white; + border: 1px solid #ddd; + border-radius: 8px; + padding: 12px; +} + +.filter-option { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px 0; + cursor: pointer; +} + +.filter-label { + font-size: 14px; + color: #666; +} + +.filter-value { + font-size: 14px; + color: #333; + font-weight: 500; +} + +/* 閫夐」鍗� */ +.tab-section { + margin-bottom: 0; +} + +.custom-tabs { + display: flex; + background: #f0f0f0; + border-radius: 8px; + padding: 2px; +} + +.tab-item { + flex: 1; + position: relative; + padding: 10px 16px; + text-align: center; + cursor: pointer; + border-radius: 6px; +} + +.tab-item.active { + background: white; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} + +.tab-text { + font-size: 14px; + font-weight: 500; + color: #666; +} + +.tab-item.active .tab-text { + color: #007AFF; + font-weight: 600; +} + +/* 鍐呭鍖哄煙 */ +.content-container { + flex: 1; + padding: 20px 16px; +} + +/* 鍔犺浇鐘舵�� */ +.loading-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 60px 20px; +} + +.loading-spinner { + width: 40px; + height: 40px; + border: 3px solid #e2e8f0; + border-top: 3px solid #4f46e5; + border-radius: 50%; + animation: spin 1s linear infinite; + margin-bottom: 16px; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +.loading-text { + font-size: 14px; + color: #64748b; +} + +/* 绌虹姸鎬� */ +.empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 80px 20px; + text-align: center; +} + +.empty-icon { + font-size: 64px; + margin-bottom: 20px; + opacity: 0.6; +} + +.empty-title { + font-size: 18px; + font-weight: 600; + color: #374151; + margin-bottom: 8px; + display: block; +} + +.empty-desc { + font-size: 14px; + color: #9ca3af; + display: block; +} + +/* 妫�楠屽崟鍒楄〃 */ +.inspection-list { + display: flex; + flex-direction: column; + gap: 12px; +} + +.inspection-card { + background: white; + border-radius: 8px; + padding: 16px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + border: 1px solid #e0e0e0; + cursor: pointer; + position: relative; +} + +.inspection-card:active { + background: #f8f8f8; +} + +/* 鍗$墖澶撮儴 */ +.card-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 16px; +} + +.header-left { + flex: 1; +} + +.inspection-number { + margin-bottom: 8px; +} + +.number-label { + font-size: 12px; + color: #64748b; + display: block; + margin-bottom: 4px; +} + +.number-value { + font-size: 16px; + font-weight: 700; + color: #1e293b; + display: block; +} + +.material-info { + display: flex; + flex-direction: column; + gap: 2px; +} + +.material-code { + font-size: 13px; + color: #4f46e5; + font-weight: 600; +} + +.material-name { + font-size: 12px; + color: #64748b; + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.header-right { + margin-left: 16px; +} + +/* 鐘舵�佸窘绔� */ +.status-badge { + display: flex; + align-items: center; + gap: 4px; + padding: 4px 8px; + border-radius: 4px; + font-size: 12px; + font-weight: 500; + white-space: nowrap; +} + +.status-badge.status-submitted { + background: #e8f5e8; + color: #2e7d32; + border: 1px solid #c8e6c9; +} + +.status-badge.status-pending { + background: #fff3e0; + color: #f57c00; + border: 1px solid #ffcc02; +} + +.status-badge.status-completed { + background: #e8f5e8; + color: #2e7d32; + border: 1px solid #c8e6c9; +} + +.status-dot { + width: 6px; + height: 6px; + border-radius: 50%; + background: currentColor; +} + +.status-text { + font-size: 12px; + font-weight: 500; +} + +/* 妫�楠岀粨鏋滃尯鍩� */ +.inspection-result { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 12px; + padding: 8px; + background: #f8f8f8; + border-radius: 6px; +} + +.result-item { + display: flex; + align-items: center; + gap: 8px; + flex: 1; +} + +.result-icon { + width: 24px; + height: 24px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + font-size: 12px; +} + +.result-icon.icon-pass { + background: #28a745; + color: white; +} + +.result-icon.icon-fail { + background: #dc3545; + color: white; +} + +.result-icon.icon-pending { + background: #ffc107; + color: white; +} + +.result-content { + flex: 1; +} + +.result-label { + font-size: 12px; + color: #666; + display: block; + margin-bottom: 2px; +} + +.result-value { + font-size: 14px; + font-weight: 500; + display: block; +} + +.result-value.value-pass { + color: #28a745; +} + +.result-value.value-fail { + color: #dc3545; +} + +.result-value.value-pending { + color: #ffc107; +} + +.inspector-info { + text-align: right; +} + +.inspector-label { + font-size: 12px; + color: #666; + display: block; + margin-bottom: 2px; +} + +.inspector-name { + font-size: 13px; + font-weight: 500; + color: #333; + display: block; +} + +/* 璇︾粏淇℃伅 */ +.card-details { + margin-bottom: 8px; +} + +.detail-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 8px; +} + +.detail-item { + background: #f8f8f8; + padding: 6px 8px; + border-radius: 4px; +} + +.detail-label { + font-size: 11px; + color: #666; + display: block; + margin-bottom: 2px; +} + +.detail-value { + font-size: 12px; + font-weight: 500; + color: #333; + display: block; +} + +/* 鎿嶄綔鎸囩ず鍣� */ +.action-indicator { + position: absolute; + top: 50%; + right: 12px; + transform: translateY(-50%); + opacity: 0.3; +} + +/* 娴姩鎿嶄綔鎸夐挳 */ +.fab-container { + position: fixed; + bottom: 20px; + right: 20px; + z-index: 1000; +} + +.fab-button { + width: 50px; + height: 50px; + background: #007AFF; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); + cursor: pointer; +} + +.fab-button:active { + transform: scale(0.95); +} + +/* 鍝嶅簲寮忚璁� */ +@media (max-width: 768px) { + .header-content { + flex-direction: column; + align-items: flex-start; + gap: 12px; + } + + .stats-badge { + align-self: flex-end; + } + + .search-container { + flex-direction: column; + gap: 8px; + } + + .filter-btn { + align-self: flex-end; + } + + .detail-grid { + grid-template-columns: 1fr; + } + + .inspection-result { + flex-direction: column; + align-items: flex-start; + gap: 12px; + } + + .inspector-info { + text-align: left; + width: 100%; + } +} +</style> \ No newline at end of file diff --git a/pages/QC/OQC/ScanCode.vue b/pages/QC/OQC/ScanCode.vue new file mode 100644 index 0000000..aec1edf --- /dev/null +++ b/pages/QC/OQC/ScanCode.vue @@ -0,0 +1,745 @@ +<template> + <view class="container"> + <!-- 琛ㄥ崟鍖哄煙 --> + <view class="form-container card"> + <form :modelValue="formData"> + <view class="form-grid"> + <view class="form-group col-2"> + <label class="form-label">鐗╂枡鏉$爜:</label> + <view class="input-with-scan"> + <input class="form-input scan-input" type="text" v-model="formData.ItemBarcode" + @confirm="addItemBarCode" + placeholder="杈撳叆鍚庣寮�鎴栨寜鍥炶溅" /> + <view class="scan-button" @tap="startScan"> + <uni-icons type="scan" size="24" color="#007bff"></uni-icons> + <text class="scan-text">鎵爜</text> + </view> + </view> + </view> + <view class="form-group col-2"> + <label class="form-label">浜у搧鍚嶇О:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.itemName" /> + </view> + <view class="form-group col-2"> + <label class="form-label">浜у搧缂栫爜:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.itemNo" /> + </view> + <view class="form-group col-2"> + <label class="form-label">璁㈠崟缂栧彿:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.taskNo" /> + </view> + <view class="form-group col-2"> + <label class="form-label">宸叉壂鏁伴噺:</label> + <input class="form-input" disabled="true" type="text" v-model="quantity" /> + </view> + </view> + </form> + </view> + + <!-- 寰呮鏉$爜琛ㄦ牸鍖哄煙 --> + <view class="table-container card"> + <view class="table-header"> + <text class="section-title">寰呮鏉$爜鍒楄〃</text> + <view class="table-tip"> + <text class="tip-text">馃憟 宸﹀彸婊戝姩鏌ョ湅鏇村淇℃伅</text> + </view> + </view> + <view class="table-wrapper"> + <scroll-view class="table-scroll" scroll-x="true" show-scrollbar="true"> + <uni-table ref="table" border emptyText="鏆傛棤鏇村鏁版嵁" class="custom-table"> + <uni-tr class="table-header-row"> + <uni-th align="center" class="th" width="80">搴忓彿</uni-th> + <uni-th align="center" class="th" width="160">鐗╂枡鏉$爜</uni-th> + <uni-th align="center" class="th" width="140">璁㈠崟缂栧彿</uni-th> + <uni-th align="center" class="th" width="140">浜у搧缂栫爜</uni-th> + <uni-th align="center" class="th" width="160">浜у搧鍚嶇О</uni-th> + <uni-th align="center" class="th" width="100">鏉$爜鏁伴噺</uni-th> + <uni-th align="center" class="th" width="80">銆�</uni-th> + </uni-tr> + <uni-tr v-for="(item, index) in tableData" :key="index" class="table-row"> + <uni-td align="center" width="80"> + <view class="description-text">{{ index + 1 }}</view> + </uni-td> + <uni-td align="center" width="160"> + <view class="cell-content">{{ item.itemBarcode }}</view> + </uni-td> + <uni-td align="center" width="140"> + <view class="cell-content">{{ item.taskNo || '-' }}</view> + </uni-td> + <uni-td align="center" width="140"> + <view class="cell-content">{{ item.itemNo }}</view> + </uni-td> + <uni-td align="center" width="160"> + <view class="cell-content" :title="item.itemName">{{ item.itemName }}</view> + </uni-td> + <uni-td align="center" width="100"> + <view class="cell-content quantity">{{ item.quantity }}</view> + </uni-td> + <uni-td align="center" width="80"> + <view class="cell-content">銆�</view> + </uni-td> + </uni-tr> + </uni-table> + </scroll-view> + + <!-- 鍙冲浐瀹氭偓娴垹闄ゆ寜閽垪 --> + <view class="fixed-delete-column"> + <view class="fixed-header"> + <text class="fixed-header-text">鎿嶄綔</text> + </view> + <view class="fixed-content"> + <view v-for="(item, index) in tableData" :key="index" class="fixed-delete-item" + :class="{ 'even': index % 2 === 1 }"> + <view @click="deleteItem(index)" class="delete-icon"> + <uni-icons type="trash" size="24"></uni-icons> + </view> + </view> + </view> + </view> + </view> + </view> + + <!-- 鎿嶄綔鎸夐挳鍖哄煙 --> + <view class="action-buttons-container button-group"> + <view class="plus-button" :class="{ 'submitting': isSubmitting }" @tap="handleSubmit"> + <text>{{ isSubmitting ? '鎻愪氦涓�...' : '鐢熸垚OQC妫�楠屽崟' }}</text> + </view> + </view> + </view> +</template> + +<script> + export default { + data() { + return { + formData: {}, + tableData: [], + quantity: 0, + isSubmitting: false, // 闃叉閲嶅鎻愪氦 + isProcessing: false, // 闃叉閲嶅澶勭悊鏉$爜 + } + }, + methods: { + // 鍚姩鎵爜鍔熻兘 + startScan() { + // 妫�鏌ユ槸鍚︽鍦ㄥ鐞嗘潯鐮侊紝闃叉閲嶅鎵爜 + if (this.isProcessing) { + this.$showMessage("姝e湪澶勭悊鏉$爜锛岃绋嶅��"); + return; + } + + uni.scanCode({ + scanType: ['barCode', 'qrCode'], // 鏀寔鏉$爜鍜屼簩缁寸爜 + success: (res) => { + console.log('鎵爜鎴愬姛:', res); + // 灏嗘壂鐮佺粨鏋滆缃埌杈撳叆妗� + this.formData.ItemBarcode = res.result; + // 鑷姩澶勭悊鎵爜缁撴灉 + this.addItemBarCode(); + }, + fail: (err) => { + console.log('鎵爜澶辫触:', err); + if (err.errMsg && err.errMsg.indexOf('cancel') === -1) { + this.$showMessage("鎵爜澶辫触锛岃閲嶈瘯"); + } + } + }); + }, + + addItemBarCode() { + // 闃叉閲嶅澶勭悊 + if (this.isProcessing) { + return; + } + + // 鏍¢獙鐗╂枡鏉$爜鏄惁涓虹┖ + if (!this.formData.ItemBarcode || this.formData.ItemBarcode.trim() === '') { + this.$showMessage("璇疯緭鍏ョ墿鏂欐潯鐮�"); + return; + } + + // 妫�鏌ョ墿鏂欐潯鐮佹槸鍚﹀凡瀛樺湪浜� tableData 涓� + const isDuplicate = this.tableData.some(item => item.itemBarcode === this.formData.ItemBarcode); + if (isDuplicate) { + this.$showMessage("璇ョ墿鏂欐潯鐮佸凡瀛樺湪锛岃妫�鏌ワ紒"); + return; + } + + // 璁剧疆澶勭悊鐘舵�� + this.isProcessing = true; + + // 濡傛灉閫氳繃浜嗕笂杩版牎楠岋紝鍙戦�佽姹傚苟鏇存柊鏁版嵁 + this.$post({ + url: "/MesOqcItemsDetect02/GetItemBarCode", + data: { + ItemCode: this.formData.ItemBarcode + } + }).then(res => { + let fr = res.data.tbBillList; + + // 鏁版嵁瀹屾暣鎬ф牎楠� + if (!fr) { + this.$showMessage("鑾峰彇鏉$爜淇℃伅澶辫触锛岃閲嶈瘯"); + return; + } + + if (!fr.itemId || !fr.itemName || !fr.itemNo) { + this.$showMessage("鏉$爜淇℃伅涓嶅畬鏁达紝璇锋鏌ユ潯鐮�"); + return; + } + + if (fr.quantity <= 0) { + this.$showMessage("鏉$爜鏁伴噺涓�0锛岃纭"); + return; + } + + //闇�瑕侀獙璇� + //鎵殑鐮佺殑itemId蹇呴』鏄拰tableData涓殑itemId鐩稿悓 蹇呴』鐨勬潯浠� + //鎵殑鐮佺殑TaskNo涔熷繀椤绘槸鍜宼ableData涓殑TaskNo鐩稿悓 + //TaskNo涓虹┖鐨勫彧鑳藉拰TaskNo涓虹┖鐨勪竴璧锋壂 + + // 濡傛灉tableData涓凡鏈夋暟鎹紝闇�瑕侀獙璇乮temId鍜孴askNo鐨勪竴鑷存�� + if (this.tableData.length > 0) { + const firstItem = this.tableData[0]; + + // 楠岃瘉itemId鏄惁鐩稿悓锛堝繀椤绘潯浠讹級 + if (fr.itemId !== firstItem.itemId) { + this.$showMessage("鐗╂枡缂栫爜涓嶄竴鑷达紝璇锋壂鎻忕浉鍚岀墿鏂欑殑鏉$爜"); + return; + } + + // 楠岃瘉TaskNo鏄惁鐩稿悓 + if (fr.taskNo !== firstItem.taskNo) { + this.$showMessage("璁㈠崟缂栧彿涓嶄竴鑷达紝璇锋壂鎻忕浉鍚岃鍗曠殑鏉$爜"); + return; + } + + // 楠岃瘉绌篢askNo鐨勬儏鍐碉細TaskNo涓虹┖鐨勫彧鑳藉拰TaskNo涓虹┖鐨勪竴璧锋壂 + if ((fr.taskNo === '' || fr.taskNo === null || fr.taskNo === undefined) && + (firstItem.taskNo !== '' && firstItem.taskNo !== null && firstItem.taskNo !== undefined)) { + this.$showMessage("璁㈠崟缂栧彿涓嶅尮閰嶏紝绌鸿鍗曠紪鍙峰彧鑳戒笌绌鸿鍗曠紪鍙蜂竴璧锋壂鎻�"); + return; + } + + if ((fr.taskNo !== '' && fr.taskNo !== null && fr.taskNo !== undefined) && + (firstItem.taskNo === '' || firstItem.taskNo === null || firstItem.taskNo === undefined)) { + this.$showMessage("璁㈠崟缂栧彿涓嶅尮閰嶏紝鏈夎鍗曠紪鍙风殑鏉$爜鍙兘涓庢湁璁㈠崟缂栧彿鐨勬潯鐮佷竴璧锋壂鎻�"); + return; + } + } + + this.formData = fr; + this.tableData.push(fr); // 灏嗘柊鏁版嵁娣诲姞鍒拌〃鏍� + this.quantity = this.tableData.reduce(function(accumulator, current) { + return accumulator + current["quantity"]; + }, 0); + + // 娓呯┖杈撳叆妗� + this.formData.ItemBarcode = ''; + }).catch(error => { + this.$showMessage("鑾峰彇鏉$爜淇℃伅澶辫触锛岃閲嶈瘯"); + }).finally(() => { + // 閲嶇疆澶勭悊鐘舵�� + this.isProcessing = false; + }); + }, + + // 鍒犻櫎鎿嶄綔锛氬垹闄� tableData 涓寚瀹氱储寮曠殑鏁版嵁 + deleteItem(index) { + this.tableData.splice(index, 1); // 鍒犻櫎璇ヨ鏁版嵁 + this.quantity = this.tableData.reduce(function(accumulator, current) { + return accumulator + current["quantity"]; + }, 0); // 鏇存柊鏉$爜鏁伴噺 + + if (this.tableData.length <= 0) { + this.formData = {}; + } + }, + + handleSubmit() { + console.log("handleSubmit鏂规硶琚皟鐢紝isSubmitting:", this.isSubmitting); + console.log("tableData闀垮害:", this.tableData.length); + console.log("quantity:", this.quantity); + this.submit(); + }, + + submit() { + console.log("submit鏂规硶琚皟鐢�"); + + // 闃叉閲嶅鎻愪氦 + if (this.isSubmitting) { + this.$showMessage("姝e湪鎻愪氦涓紝璇峰嬁閲嶅鎿嶄綔"); + return; + } + + // 鏍¢獙鐢ㄦ埛鐧诲綍鐘舵�� + if (!this.$loginInfo.account) { + this.$showMessage("鐢ㄦ埛鏈櫥褰曪紝璇烽噸鏂扮櫥褰�"); + return; + } + + // 鏍¢獙鏉$爜鏁伴噺鏄惁鏈夋晥 + if (this.quantity <= 0) { + this.$showMessage("鏉$爜鏁伴噺蹇呴』澶т簬0"); + return; + } + + // 鏍¢獙鏄惁鏈夋暟鎹� + if (this.tableData.length === 0) { + this.$showMessage("璇锋壂鎻忔潯鐮�"); + return; + } + + let userName = this.$loginInfo.account; + this.isSubmitting = true; // 璁剧疆鎻愪氦鐘舵�� + + // 鍙戦�佽姹� + this.$post({ + url: "/MesOqcItemsDetect02/ItemBarCodeSubmit", + data: { + itemBarCodeData: this.tableData, + CreateUser: userName + } + }).then(response => { + if(response.status == 0){ + // 璇锋眰鎴愬姛鍚庢樉绀洪�夋嫨妗� + uni.showModal({ + title: "鎿嶄綔鎴愬姛", + content: "宸茬粡鎴愬姛鐢熸垚妫�楠屽崟", + showCancel: true, + cancelText: "缁х画鎵爜", + confirmText: "璺宠浆鍒版楠屽崟", + success: (res) => { + if (res.confirm) { + // 鐢ㄦ埛鐐瑰嚮浜�"璺宠浆鍒版楠屽崟" + uni.navigateTo({ + url: '/pages/QC/OQC/Add?id=' + response.data + }); + } else if (res.cancel) { + // 鐢ㄦ埛鐐瑰嚮浜�"缁х画鎵爜" + this.clearData(); + } + } + }); + }else{ + this.$showMessage(response.message); + } + + }).catch(error => { + // 璇锋眰澶辫触鏃剁殑澶勭悊 + this.$showMessage("璇锋眰澶辫触锛岃绋嶅悗閲嶈瘯"); + }).finally(() => { + // 鏃犺鎴愬姛杩樻槸澶辫触閮介噸缃彁浜ょ姸鎬� + this.isSubmitting = false; + }); + }, + + // 娓呯┖琛ㄦ牸鍜岃〃鍗曟暟鎹� + clearData() { + this.tableData = []; + this.formData = {}; + this.quantity = 0; + this.isSubmitting = false; + this.isProcessing = false; + } + + } + } +</script> + +<style> + .container { + padding: 24rpx; + background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); + min-height: 100vh; + display: flex; + flex-direction: column; + } + + /* 鍗$墖閫氱敤鏍峰紡 */ + .card { + background: #ffffff; + border-radius: 12rpx; + box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08); + margin-bottom: 24rpx; + padding: 32rpx; + border: 1rpx solid #e9ecef; + } + + /* 琛ㄥ崟鍖哄煙 */ + .form-container { + .form-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 24rpx 16rpx; + } + + .form-group { + display: flex; + flex-direction: column; + gap: 16rpx; + + .form-label { + font-size: 28rpx; + color: #495057; + font-weight: 600; + padding-left: 4rpx; + position: relative; + + &::after { + content: ""; + position: absolute; + left: 0; + bottom: -4rpx; + width: 24rpx; + height: 3rpx; + background: #007bff; + border-radius: 2rpx; + } + } + + .form-input { + height: 92rpx; + padding: 0 24rpx; + border: 2rpx solid #dee2e6; + border-radius: 8rpx; + font-size: 28rpx; + color: #212529; + background: #ffffff; + transition: all 0.3s ease; + + &[disabled] { + background: #f8f9fa; + color: #6c757d; + border-color: #e9ecef; + } + + &:focus { + border-color: #007bff; + box-shadow: 0 0 0 4rpx rgba(0, 123, 255, 0.1); + outline: none; + } + + &::placeholder { + color: #adb5bd; + } + } + } + } + + /* 琛ㄦ牸浼樺寲 */ + .table-container { + .table-header { + margin-bottom: 24rpx; + padding-bottom: 16rpx; + border-bottom: 2rpx solid #e9ecef; + display: flex; + justify-content: space-between; + align-items: center; + + .section-title { + font-size: 32rpx; + color: #212529; + font-weight: 700; + position: relative; + padding-left: 24rpx; + + &::before { + content: ""; + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + width: 4rpx; + height: 28rpx; + background: linear-gradient(135deg, #007bff, #0056b3); + border-radius: 2rpx; + } + } + + .table-tip { + .tip-text { + font-size: 22rpx; + color: #6c757d; + background: #f8f9fa; + padding: 8rpx 16rpx; + border-radius: 16rpx; + border: 1rpx solid #e9ecef; + } + } + } + + .table-wrapper { + position: relative; + border-radius: 8rpx; + overflow: hidden; + border: 1rpx solid #dee2e6; + } + + .table-scroll { + width: calc(100% - 80rpx); /* 鍑忓幓鍥哄畾鍒楀搴� */ + white-space: nowrap; + } + + .custom-table { + border: none; + min-width: 780rpx; + + .table-header-row { + background: linear-gradient(135deg, #f8f9fa, #e9ecef); + + .th { + font-size: 26rpx; + color: #495057; + font-weight: 600; + padding: 20rpx 12rpx; + background: transparent !important; + border-right: 1rpx solid #dee2e6; + white-space: nowrap; + min-width: 80rpx; + + &:last-child { + border-right: none; + } + } + } + + .table-row { + transition: background-color 0.2s ease; + + &:nth-child(even) { + background: #f8f9fa; + } + + &:hover { + background: #e3f2fd; + } + + .uni-td { + padding: 16rpx 12rpx; + border-color: #dee2e6 !important; + border-right: 1rpx solid #dee2e6; + white-space: nowrap; + min-width: 80rpx; + + &:last-child { + border-right: none; + } + + .cell-content { + font-size: 24rpx; + color: #495057; + line-height: 1.4; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + + &.quantity { + font-weight: 600; + color: #007bff; + background: linear-gradient(135deg, #e3f2fd, #bbdefb); + padding: 8rpx 16rpx; + border-radius: 12rpx; + display: inline-block; + min-width: 60rpx; + text-align: center; + } + } + + .description-text { + font-size: 24rpx; + color: #6c757d; + font-weight: 500; + } + } + } + } + + /* 鍙冲浐瀹氭偓娴垹闄ゅ垪 */ + .fixed-delete-column { + position: absolute; + top: 0; + right: 0; + width: 80rpx; + background: #ffffff; + border-left: 1rpx solid #dee2e6; + box-shadow: -4rpx 0 8rpx rgba(0, 0, 0, 0.05); + z-index: 10; + + .fixed-header { + height: 60rpx; + background: linear-gradient(135deg, #f8f9fa, #e9ecef); + display: flex; + align-items: center; + justify-content: center; + border-bottom: 1rpx solid #dee2e6; + + .fixed-header-text { + font-size: 26rpx; + color: #495057; + font-weight: 600; + } + } + + .fixed-content { + .fixed-delete-item { + height: 48rpx; + display: flex; + align-items: center; + justify-content: center; + border-bottom: 1rpx solid #dee2e6; + transition: background-color 0.2s ease; + + &.even { + background: #f8f9fa; + } + + &:hover { + background: #e3f2fd; + } + + &:last-child { + border-bottom: none; + } + } + } + } + } + + /* 鍒犻櫎鍥炬爣浼樺寲 */ + .delete-icon { + cursor: pointer; + color: #dc3545; + transition: all 0.3s ease; + padding: 12rpx; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + min-width: 48rpx; + min-height: 48rpx; + + &:hover { + color: #c82333; + background: rgba(220, 53, 69, 0.1); + transform: scale(1.1); + } + + &:active { + transform: scale(0.95); + background: rgba(220, 53, 69, 0.2); + } + } + + /* 鎸夐挳浼樺寲 */ + .action-buttons-container { + display: flex; + justify-content: center; + margin-top: 48rpx; + padding: 0 24rpx; + + .plus-button { + width: 100%; + max-width: 600rpx; + height: 96rpx; + background: linear-gradient(135deg, #007bff, #0056b3); + border-radius: 48rpx; + display: flex; + justify-content: center; + align-items: center; + color: #ffffff; + font-size: 32rpx; + font-weight: 600; + box-shadow: 0 8rpx 24rpx rgba(0, 123, 255, 0.3); + transition: all 0.3s ease; + border: none; + position: relative; + overflow: hidden; + + &::before { + content: ""; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); + transition: left 0.5s ease; + } + + &:active { + transform: scale(0.98); + box-shadow: 0 4rpx 12rpx rgba(0, 123, 255, 0.4); + + &::before { + left: 100%; + } + } + + &.submitting { + background: linear-gradient(135deg, #6c757d, #5a6268); + cursor: not-allowed; + + &::before { + display: none; + } + } + } + } + + /* 鏁伴噺鏄剧ず浼樺寲 */ + .form-group { + &:nth-child(5) .form-input { + font-weight: 600; + color: #007bff; + background: linear-gradient(135deg, #e3f2fd, #bbdefb); + border: 2rpx solid #007bff; + text-align: center; + } + } + + /* 鎵爜杈撳叆妗嗘牱寮� */ + .input-with-scan { + display: flex; + align-items: center; + gap: 16rpx; + + .scan-input { + flex: 1; + } + + .scan-button { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 16rpx 20rpx; + background: linear-gradient(135deg, #e3f2fd, #bbdefb); + border: 2rpx solid #007bff; + border-radius: 8rpx; + min-width: 120rpx; + height: 92rpx; + cursor: pointer; + transition: all 0.3s ease; + + &:hover { + background: linear-gradient(135deg, #bbdefb, #90caf9); + transform: translateY(-2rpx); + box-shadow: 0 4rpx 12rpx rgba(0, 123, 255, 0.2); + } + + &:active { + transform: translateY(0); + box-shadow: 0 2rpx 6rpx rgba(0, 123, 255, 0.3); + } + + .scan-text { + font-size: 22rpx; + color: #007bff; + font-weight: 600; + margin-top: 4rpx; + } + } + } + +</style> \ No newline at end of file diff --git a/pages/QC/OQC/detail.vue b/pages/QC/OQC/detail.vue new file mode 100644 index 0000000..d1af774 --- /dev/null +++ b/pages/QC/OQC/detail.vue @@ -0,0 +1,828 @@ +<template> + <view class="page-container"> + <!-- 妫�楠岄」鐩〃鍗曞崱鐗� --> + <view class="form-card"> + <view class="form-title"> + <view class="title-icon">馃搵</view> + <span>妫�楠岄」鐩鎯�</span> + </view> + <view class="form-container"> + <!-- 鍩烘湰淇℃伅妯″潡 --> + <view class="form-section"> + <view class="section-title">鍩烘湰淇℃伅</view> + <view class="form-grid"> + <view class="form-group"> + <label class="form-label">椤圭洰鍚嶇О:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.fcheckItem" /> + </view> + <view class="form-group"> + <label class="form-label">瑙勬牸瑕佹眰:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.fspecRequ" /> + </view> + <view class="form-group"> + <label class="form-label">妫�楠屾柟娉�:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.inspectionMethod" /> + </view> + <view class="form-group"> + <label class="form-label">妫�楠屽伐鍏�:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.fcheckTool" /> + </view> + </view> + </view> + + <!-- 涓変釜妯″潡骞跺垪瀹瑰櫒 --> + <view class="three-modules-container"> + <!-- 妫�楠屽弬鏁版ā鍧� --> + <view class="module-item"> + <view class="module-header"> + <text class="module-title">妫�楠屽弬鏁�</text> + </view> + <view class="module-content"> + <view class="form-grid"> + <view class="form-group"> + <label class="form-label">妫�楠屾暟:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.checkQyt" /> + </view> + <view class="form-group"> + <label class="form-label">妫�楠屾爣鍑嗙紪鐮�:</label> + <input class="form-input" disabled="true" type="text" + v-model="formData.sampleSizeNo" /> + </view> + <view class="form-group"> + <label class="form-label">妫�楠屾按骞�:</label> + <input class="form-input" disabled="true" type="text" + v-model="formData.fcheckLevel" /> + </view> + <view class="form-group"> + <label class="form-label">鎺ユ敹姘村钩:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.facLevel" /> + </view> + </view> + </view> + </view> + + <!-- 鏁板�兼爣鍑嗘ā鍧� --> + <view class="module-item"> + <view class="module-header"> + <text class="module-title">鏁板�兼爣鍑�</text> + </view> + <view class="module-content"> + <view class="form-grid"> + <view class="form-group"> + <label class="form-label">涓嬮檺:</label> + <input class="form-input" disabled="true" type="text" + v-model="formData.fdownAllow" /> + </view> + <view class="form-group"> + <label class="form-label">鏍囧噯鍊�:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.fstand" /> + </view> + <view class="form-group"> + <label class="form-label">涓婇檺:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.fupAllow" /> + </view> + </view> + </view> + </view> + + <!-- 鍒ゅ畾鏍囧噯妯″潡 --> + <view class="module-item"> + <view class="module-header"> + <text class="module-title">鍒ゅ畾鏍囧噯</text> + </view> + <view class="module-content"> + <view class="form-grid"> + <view class="form-group"> + <label class="form-label">AC鏁�:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.facQty" /> + </view> + <view class="form-group"> + <label class="form-label">RE鏁�:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.freQty" /> + </view> + <view class="form-group"> + <label class="form-label">涓嶅悎鏍兼暟:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.fngQty" /> + </view> + <view class="form-group"> + <label class="form-label">棰勮缁撴灉:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.fcheckResu" /> + </view> + </view> + </view> + </view> + </view> + + <!-- 澶囨敞淇℃伅妯″潡 --> + <!-- <view class="form-section"> + <view class="section-title">澶囨敞淇℃伅</view> + <view class="form-grid"> + <view class="form-group"> + <label class="form-label">涓嶅悎鏍兼弿杩�:</label> + <input class="form-input" disabled="true" type="text" v-model="formData.remarks" /> + </view> + </view> + </view> --> + + <!-- 妫�娴嬬粨鏋滃尯鍩� --> + <view class="form-section"> + <view class="section-title">妫�娴嬬粨鏋�</view> + <view class="form-grid"> + <view class="form-group"> + <label class="form-label">妫�娴嬬粨鏋�:</label> + <input class="form-input" type="number" v-model="fcheckResuK" /> + </view> + + <!-- 鎻愮ず璇嶄綔涓烘娴嬬粨鏋滅殑鎻愮ず --> + <view class="form-group tip-group"> + <view class="tip-box"> + <view class="tip-icon">鈿狅笍</view> + <view class="tip-text">娌℃湁鏈�澶у�煎拰鏈�灏忓�兼椂濉啓<span class="highlight">0锛堟湭閫氳繃妫�楠岋級</span>鎴�<span + class="highlight">1锛堥�氳繃妫�楠岋級</span></view> + </view> + </view> + </view> + </view> + + <button :class="['action-btn', 'btn-primary', { 'btn-loading': isLoading }]" + v-if="tableData.length < formData.checkQyt" @click="submit" :disabled="isLoading"> + {{ isLoading ? '淇濆瓨涓�...' : '淇濆瓨' }} + </button> + </view> + </view> + + <!-- 妫�楠岀粨鏋滆〃鏍煎崱鐗� --> + <view class="table-card"> + <view class="table-title"> + <view class="title-icon">馃搳</view> + <span>妫�楠岀粨鏋滃垪琛�</span> + </view> + <view class="list-container"> + <uni-table ref="table" border emptyText="鏆傛棤鏇村鏁版嵁"> + <uni-tr> + <uni-th width="80" align="center" class="th">缂栧彿</uni-th> + <uni-th width="120" align="center" class="th">鍒ゅ畾鏍囪瘑</uni-th> + <uni-th width="100" align="center" class="th">妫�楠岀粨鏋�</uni-th> + <uni-th width="120" align="center" class="th">鎿嶄綔</uni-th> + </uni-tr> + <uni-tr v-for="(item, index) in tableData" :key="index" class="table-row" + :class="{ 'hover-effect': isHoveringRow === index }" @mouseenter="isHoveringRow = index" + @mouseleave="isHoveringRow = -1"> + <uni-td align="center"> + {{ index + 1 }} + </uni-td> + <uni-td align="center"> + <input class="form-input" disabled="true" type="text" v-model="item.fstand" /> + </uni-td> + <uni-td align="center"> + <span class="result-badge" + :class="{ 'pass': item.fcheckResu === 'OK', 'fail': item.fcheckResu === 'NG' }"> + {{ item.fcheckResu || '鏈楠�' }} + </span> + </uni-td> + <uni-td align="center"> + <view class="action-group"> + <button :class="['action-btn', 'btn-sm', 'btn-warn', { 'btn-disabled': isLoading }]" + v-if="isNumber" @click="toDetail(item)" :disabled="isLoading"> + {{ isLoading ? '澶勭悊涓�...' : '淇敼' }} + </button> + <button :class="['action-btn', 'btn-sm', 'btn-warn', { 'btn-disabled': isLoading }]" + v-if="!isNumber" @click="numberEdit(item)" :disabled="isLoading"> + {{ isLoading ? '澶勭悊涓�...' : editResult(item.fcheckResu) }} + </button> + </view> + </uni-td> + </uni-tr> + </uni-table> + </view> + </view> + + <!-- 鎿嶄綔鎸夐挳 --> + <view class="action-buttons"> + <view class="button-group"> + <button :class="['action-btn', 'btn-warn', { 'btn-disabled': isLoading }]" @click="saveRemarks" + :disabled="isLoading"> + {{ isLoading ? '澶勭悊涓�...' : '娣诲姞涓嶅悎鏍兼弿杩�' }} + </button> + </view> + </view> + + <!-- 淇敼妫�楠岀粨鏋滃脊鍑哄眰 --> + <view v-if="showPopup" class="overlay active"> + <view class="popup" :class="{ 'popup-scale': isPopupAnimated }" @animationend="isPopupAnimated = false"> + <view class="popup-header"> + <h3 class="popup-title">淇敼妫�楠岀粨鏋�</h3> + <view class="close-btn" @click="showPopup = !showPopup">脳</view> + </view> + <form :modelValue="editData"> + <view class="form-group"> + <label class="form-label">妫�楠岀粨鏋�:</label> + <input class="form-input" type="text" v-model="editData.fcheckResu" /> + </view> + <view class="button-group"> + <button :class="['action-btn', 'btn-warn', { 'btn-loading': isEditLoading }]" @click="eidt" + :disabled="isEditLoading"> + {{ isEditLoading ? '淇敼涓�...' : '淇敼' }} + </button> + <button @click="showPopup = !showPopup"> + 鍙栨秷 + </button> + </view> + </form> + </view> + </view> + + <!-- 淇敼涓嶅悎鏍兼弿杩板脊鍑哄眰 --> + <view v-if="remarksPopup" class="overlay active"> + <view class="popup" :class="{ 'popup-scale': isPopupAnimated }" @animationend="isPopupAnimated = false"> + <view class="popup-header"> + <h3 class="popup-title">淇敼涓嶅悎鏍兼弿杩�</h3> + <view class="close-btn" @click="remarksPopup = !remarksPopup">脳</view> + </view> + <form> + <view class="form-group"> + <label class="form-label">涓嶅悎鏍兼弿杩�:</label> + <input class="form-input" type="text" v-model="remarks" /> + </view> + <view class="button-group"> + <button :class="['action-btn', 'btn-warn', { 'btn-loading': isRemarksLoading }]" + @click="editRemarks" :disabled="isRemarksLoading"> + {{ isRemarksLoading ? '淇濆瓨涓�...' : '淇敼' }} + </button> + <button @click="remarksPopup = !remarksPopup"> + 鍙栨秷 + </button> + </view> + </form> + </view> + </view> + </view> +</template> + +<script> + export default { + data() { + return { + formData: {}, + releaseNo: "", + isNumber: false, + checkItem: "", + id: 0, + gid: 0, + billNo: "", + showPopup: false, + editData: {}, + tableData: [], + remarks: "", + remarksPopup: false, + fcheckResuK: "", + isLoading: false, + isEditLoading: false, + isRemarksLoading: false, + isHoveringRow: -1, + isPopupAnimated: false + }; + }, + methods: { + editResult(fcheckResu) { + if (fcheckResu == "OK") { + return "鏀逛负涓嶅悎鏍�"; + } else { + return "鏀逛负鍚堟牸"; + } + }, + submit() { + this.isLoading = true; + let count = this.formData.checkQyt; + let fstand = "鈭�"; + if (Number(this.formData.fupAllow) && Number(this.formData.fdownAllow)) { + if (!this.fcheckResuK) { + this.$showMessage("璇疯緭鍏ユ楠屽��"); + this.isLoading = false; + return; + } + if ( + Number(this.fcheckResuK) >= Number(this.formData.fdownAllow) && + Number(this.fcheckResuK) <= Number(this.formData.fupAllow) + ) { + fstand = "鈭�"; + } else { + fstand = "脳"; + } + count = 1; + } else { + if (!this.fcheckResuK) { + this.formData.fcheckResu = 1; + } + if (this.fcheckResuK == 0 || this.fcheckResuK == 1) { + this.formData.isPass = this.fcheckResuK; + } else { + this.$showMessage("鏃犳爣鍑嗗�兼椂锛屾楠岀粨鏋滃彧鑳戒负0鎴�1!"); + this.isLoading = false; + return; + } + count = count - this.tableData.length; + } + this.formData.updater = this.$loginInfo.account; + this.$post({ + url: "/LLJ/SetQSItemDetail", + data: { + mainId: this.formData.id, + releaseNo: this.formData.releaseNo, + fstand: fstand, + fcheckResu: this.fcheckResuK, + LastupdateBy: this.$loginInfo.account, + count: count + } + }).then((res) => { + this.formData.fcheckResu = null; + this.$showMessage("淇濆瓨鎴愬姛"); + this.refreshResult(); + this.isLoading = false; + }).catch(() => { + this.$showMessage("淇濆瓨澶辫触锛岃閲嶈瘯"); + this.isLoading = false; + }); + }, + refreshResult() { + this.isLoading = true; + this.$post({ + url: "/MesOqcItemsDetect02/getXjDetail02ById", + data: { + id: this.id + } + }).then((res) => { + this.formData = res.data.tbBillList.itemXj01; + this.tableData = res.data.tbBillList.itemXj02s; + + if (this.formData.fupAllow && this.formData.fdownAllow && this.formData.fstand) { + this.isNumber = true; + } else { + this.isNumber = false; + } + this.isLoading = false; + }).catch(() => { + this.$showMessage("鑾峰彇鏁版嵁澶辫触"); + this.isLoading = false; + }); + }, + toDetail(item) { + this.showPopup = true; + this.editData = { + ...item + }; + }, + eidt() { + this.isEditLoading = true; + if (!this.editData.fcheckResu) { + this.$showMessage("璇疯緭鍏ユ楠岀粨鏋�"); + this.isEditLoading = false; + return; + } + if (this.formData.fcheckResu == this.editData.fcheckResu) { + this.$showMessage("淇敼鎴愬姛"); + this.showPopup = false; + this.isEditLoading = false; + return; + } + let fstand = "鈭�"; + if (this.formData.fupAllow && this.formData.fdownAllow) { + if (!this.editData.fcheckResu) { + this.$showMessage("璇疯緭鍏ユ楠屽��"); + this.isEditLoading = false; + return; + } + if ( + Number(this.editData.fcheckResu) >= Number(this.formData.fdownAllow) && + Number(this.editData.fcheckResu) <= Number(this.formData.fupAllow) + ) { + this.editData.isPass = 1; + fstand = "鈭�"; + } else { + this.editData.isPass = 0; + fstand = "脳"; + } + } else { + if (!this.editData.fcheckResu) { + this.editData.fcheckResu = 1; + } + if (this.editData.fcheckResu == 0 || this.editData.fcheckResu == 1) { + if (this.editData.fcheckResu == 0) { + fstand = "脳"; + } + } else { + this.$showMessage("鏃犳爣鍑嗗�兼椂锛屾楠岀粨鏋滃彧鑳戒负0鎴�1!"); + this.isEditLoading = false; + return; + } + } + this.editData.updater = this.$loginInfo.account; + this.$post({ + url: "/MesOqcItemsDetect02/UpdateQSItemDetail", + data: { + id: this.editData.id, + mainId: this.formData.id, + releaseNo: this.formData.releaseNo, + fstand: fstand, + fcheckResu: this.editData.fcheckResu, + lastupdateBy: this.$loginInfo.account + } + }).then((res) => { + this.showPopup = false; + this.$showMessage("淇敼鎴愬姛"); + this.refreshResult(); + this.isEditLoading = false; + }).catch(() => { + this.$showMessage("淇敼澶辫触锛岃閲嶈瘯"); + this.isEditLoading = false; + }); + }, + numberEdit(item) { + this.isLoading = true; + let fstand = "鈭�"; + let fcheckResu = "OK"; + if (item.fcheckResu == "OK") { + fstand = "脳"; + fcheckResu = "NG"; + } + this.$post({ + url: "/MesOqcItemsDetect02/UpdateQSItemDetail", + data: { + id: item.id, + mainId: this.formData.id, + releaseNo: this.formData.releaseNo, + fstand: fstand, + fcheckResu: fcheckResu, + lastupdateBy: this.$loginInfo.account + } + }).then((res) => { + this.$showMessage("淇敼鎴愬姛"); + this.refreshResult(); + this.isLoading = false; + }).catch(() => { + this.$showMessage("淇敼澶辫触锛岃閲嶈瘯"); + this.isLoading = false; + }); + }, + saveRemarks() { + this.remarksPopup = true; + this.remarks = this.formData.remarks || ""; + }, + editRemarks() { + this.isRemarksLoading = true; + if (this.remarks) { + this.$post({ + url: "/MesOqcItemsDetect02/saveRemarksPid", + data: { + pid: this.formData.id, + remarks: this.remarks + } + }).then((res) => { + if (res.data.tbBillList > 0) { + this.formData.remarks = this.remarks; + this.remarksPopup = false; + this.$showMessage("淇濆瓨鎴愬姛"); + } else { + this.$showMessage("淇濆瓨澶辫触"); + } + this.isRemarksLoading = false; + }).catch(() => { + this.$showMessage("淇濆瓨澶辫触锛岃閲嶈瘯"); + this.isRemarksLoading = false; + }); + } else { + this.$showMessage("璇疯緭鍏ヤ笉鍚堟牸鎻忚堪"); + this.isRemarksLoading = false; + } + } + }, + onLoad(options) { + let params = options; + this.id = params["mainId"]; + this.releaseNo = params["releaseNo"]; + this.refreshResult(); + } + }; +</script> + +<style> + /* 椤甸潰瀹瑰櫒 */ + .page-container { + padding: 20px; + background-color: #f5f5f5; + min-height: 100vh; + } + + /* 琛ㄥ崟鍗$墖 */ + .form-card { + background-color: #fff; + border-radius: 12px; + padding: 20px; + margin-bottom: 20px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + } + + /* 琛ㄥ崟鏍囬 */ + .form-title { + display: flex; + align-items: center; + font-size: 18px; + color: #333; + margin-bottom: 15px; + } + + .title-icon { + font-size: 22px; + margin-right: 10px; + } + + /* 琛ㄥ崟瀹瑰櫒 */ + .form-container { + padding-top: 10px; + } + + /* 琛ㄥ崟妯″潡鏍囬 */ + .form-section { + margin-bottom: 20px; + } + + .section-title { + font-size: 16px; + font-weight: 600; + color: #333; + margin-bottom: 10px; + } + + /* 琛ㄦ牸甯冨眬 */ + .form-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 15px; + } + + /* 琛ㄥ崟椤� */ + .form-group { + display: flex; + align-items: center; + } + + .form-label { + width: 130px; + color: #333; + font-size: 14px; + font-weight: 500; + } + + .form-input { + flex: 1; + height: 40px; + padding: 0 10px; + border: 1px solid #e0e0e0; + border-radius: 8px; + background-color: #f8f8f8; + color: #666; + font-size: 14px; + } + + .form-input:disabled { + background-color: #e9e9e9; + } + + .form-input:focus { + border-color: #007AFF; + outline: none; + } + + /* 妫�楠岀粨鏋滃尯鍩� */ + .tip-group { + margin-top: 15px; + } + + .tip-box { + display: flex; + align-items: center; + background-color: #fff5d1; + padding: 10px; + border-radius: 8px; + border: 1px solid #f0e0a7; + } + + .tip-icon { + font-size: 20px; + color: #f39c12; + margin-right: 10px; + } + + .tip-text { + font-size: 14px; + color: #333; + } + + .highlight { + color: #007AFF; + font-weight: 600; + } + + /* 鎸夐挳鏍峰紡 */ + .action-btn { + width: 100%; + padding: 12px; + border-radius: 8px; + border: none; + color: #fff; + font-size: 16px; + font-weight: 500; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: background-color 0.3s ease; + } + + .btn-primary { + background-color: #007AFF; + } + + .btn-primary:hover { + background-color: #0056CC; + } + + .btn-warn { + background-color: #f1b344; + } + + .btn-warn:hover { + background-color: #e6a135; + } + + .btn-disabled { + background-color: #c0c0c0; + cursor: not-allowed; + } + + /* 寮瑰嚭灞傛牱寮� */ + .overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; + opacity: 0; + transition: opacity 0.3s ease; + } + + .overlay.active { + opacity: 1; + } + + .popup { + background-color: #fff; + border-radius: 12px; + width: 90%; + max-width: 500px; + padding: 20px; + transform: scale(0.8); + transition: transform 0.3s ease; + } + + .popup-scale { + transform: scale(1); + } + + .popup-header { + display: flex; + justify-content: space-between; + align-items: center; + } + + .popup-title { + font-size: 16px; + font-weight: 600; + color: #333; + } + + .close-btn { + font-size: 20px; + color: #333; + cursor: pointer; + } + + /* 鎿嶄綔鎸夐挳缁� */ + .button-group { + display: flex; + justify-content: space-between; + margin-top: 20px; + } + + .button-group button { + width: 48%; + padding: 10px; + border-radius: 8px; + border: none; + font-size: 14px; + font-weight: 500; + cursor: pointer; + } + + /* 妫�楠岀粨鏋滆〃鏍煎崱鐗� */ + .table-card { + background-color: #fff; + border-radius: 12px; + padding: 20px; + margin-bottom: 20px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + } + + /* 琛ㄦ牸鏍囬 */ + .table-title { + display: flex; + align-items: center; + font-size: 16px; + color: #333; + font-weight: 600; + margin-bottom: 15px; + } + + .title-icon { + font-size: 22px; + margin-right: 10px; + } + + /* 琛ㄦ牸鏍峰紡 */ + .uni-table { + width: 100%; + border-collapse: collapse; + } + + .uni-th, + .uni-td { + padding: 12px; + text-align: center; + } + + .uni-th { + background-color: #f5f5f5; + font-size: 14px; + color: #666; + font-weight: 500; + } + + .table-row { + background-color: #fff; + border-bottom: 1px solid #e0e0e0; + } + + .table-row:hover { + background-color: #f9f9f9; + } + + .result-badge { + padding: 5px 12px; + font-size: 12px; + border-radius: 10px; + color: #fff; + display: inline-block; + } + + .pass { + background-color: #28a745; + } + + .fail { + background-color: #dc3545; + } + + .pending { + background-color: #f1b344; + } + + .action-group { + display: flex; + gap: 10px; + } + + .action-btn.btn-sm { + width: auto; + padding: 6px 12px; + font-size: 12px; + } + + /* 鎻愮ず淇℃伅 */ + .hover-effect:hover { + background-color: #f9f9f9; + } + + .btn-sm { + font-size: 14px; + } + + .btn-loading { + background-color: #c0c0c0; + cursor: not-allowed; + } +</style> \ No newline at end of file diff --git a/store/index.js b/store/index.js index fb8e2fe..9f088a0 100644 --- a/store/index.js +++ b/store/index.js @@ -2,31 +2,31 @@ import Vuex from 'vuex' //寮曞叆vuex鎻掍欢 杩涜鐘舵�佺鐞� -Vue.use(Vuex) +Vue.use(Vuex) const store = new Vuex.Store({ - state: { + state: { id: 'id', - serverInfo:{//鏈嶅姟淇℃伅 - networkFlag:'鍐呯綉', - serverURLInt:'http://192.168.11.251:10054',//鏈嶅姟鍣ㄤ綋妫� 10.0.1.104:10054 - serverURL:'http://localhost:10054',//鏈湴璋冭瘯鍦板潃 - serverAPI:'http://localhost:5184/api',//褰撳墠姝e湪浣跨敤鏈湴 - // serverAPI:'http://192.168.1.92:10054/api',//褰撳墠姝e湪浣跨敤鐨勬湇鍔″櫒 + serverInfo: { //鏈嶅姟淇℃伅 + networkFlag: '鍐呯綉', + serverURLInt: 'http://192.168.11.251:10054', //鏈嶅姟鍣ㄤ綋妫� 10.0.1.104:10054 + serverURL: 'http://localhost:10054', //鏈湴璋冭瘯鍦板潃 + serverAPI:'http://localhost:10054/api',//褰撳墠姝e湪浣跨敤鏈湴 + //serverAPI: 'http://192.168.1.92:10054/api', //褰撳墠姝e湪浣跨敤鐨勬湇鍔″櫒 } }, mutations: { - test(state,id){ + test(state, id) { state.id = id; } }, - getters:{ - currentColor(state){ - return state.colorList[state.colorIndex] - } - }, + getters: { + currentColor(state) { + return state.colorList[state.colorIndex] + } + }, actions: { // lazy loading openid } }) -export default store +export default store \ No newline at end of file -- Gitblit v1.9.3