Merge remote-tracking branch 'origin/dev_宁夏_英泽防锈' into dev_宁夏_英泽防锈
# Conflicts:
# multiple/config.json
# src/api/basicData/customer.js
# src/api/inventoryManagement/stockInventory.js
# src/api/procurementManagement/purchase_return_order.js
# src/api/salesManagement/deliveryLedger.js
# src/assets/styles/element-ui.scss
# src/assets/styles/index.scss
# src/assets/styles/sidebar.scss
# src/assets/styles/variables.module.scss
# src/components/AIChatSidebar/index.vue
# src/components/Breadcrumb/index.vue
# src/components/Dialog/FileList.vue
# src/components/ProcessParamListDialog.vue
# src/components/PurchaseAIChatSidebar/index.vue
# src/layout/components/AppMain.vue
# src/layout/components/Navbar.vue
# src/layout/components/Sidebar/Logo.vue
# src/layout/components/Sidebar/index.vue
# src/layout/components/TagsView/ScrollPane.vue
# src/layout/components/TagsView/index.vue
# src/layout/index.vue
# src/router/index.js
# src/store/modules/permission.js
# src/store/modules/user.js
# src/views/basicData/customerFile/index.vue
# src/views/basicData/customerFileOpenSea/index.vue
# src/views/basicData/product/index.vue
# src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
# src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
# src/views/collaborativeApproval/approvalProcess/index.vue
# src/views/customerService/expiryAfterSales/index.vue
# src/views/customerService/feedbackRegistration/components/formDia.vue
# src/views/equipmentManagement/inspectionManagement/components/viewFiles.vue
# src/views/equipmentManagement/repair/Modal/RepairModal.vue
# src/views/equipmentManagement/repair/index.vue
# src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue
# src/views/equipmentManagement/upkeep/Form/PlanModal.vue
# src/views/equipmentManagement/upkeep/index.vue
# src/views/financialManagement/assets/fixedAssets.vue
# src/views/financialManagement/assets/intangibleAssets.vue
# src/views/financialManagement/generalLedger/index.vue
# src/views/financialManagement/payable/purchaseIn.vue
# src/views/financialManagement/receivable/salesOut.vue
# src/views/financialManagement/receivable/salesReturn.vue
# src/views/financialManagement/voucher/detailLedger.vue
# src/views/financialManagement/voucher/generalLedger.vue
# src/views/financialManagement/voucher/index.vue
# src/views/index.vue
# src/views/inventoryManagement/dispatchLog/Record.vue
# src/views/inventoryManagement/receiptManagement/Record.vue
# src/views/inventoryManagement/stockManagement/Record.vue
# src/views/login.vue
# src/views/oaSystem/projectManagement/components/milestoneList.vue
# src/views/oaSystem/projectManagement/components/taskTree.vue
# src/views/oaSystem/projectManagement/index.vue
# src/views/oaSystem/projectManagement/projectDetail.vue
# src/views/personnelManagement/dimission/components/formDia.vue
# src/views/personnelManagement/employeeRecord/index.vue
# src/views/procurementManagement/procurementLedger/index.vue
# src/views/procurementManagement/purchaseReturnOrder/New.vue
# src/views/procurementManagement/purchaseReturnOrder/index.vue
# src/views/productionManagement/processRoute/index.vue
# src/views/productionManagement/processRoute/processRouteItem/index.vue
# src/views/productionManagement/productStructure/Detail/index.vue
# src/views/productionManagement/productionCosting/index.vue
# src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
# src/views/productionManagement/productionOrder/index.vue
# src/views/productionManagement/productionProcess/index.vue
# src/views/productionManagement/productionTraceability/index.vue
# src/views/productionManagement/workOrderEdit/index.vue
# src/views/productionManagement/workOrderManagement/index.vue
# src/views/productionPlan/productionPlan/index.vue
# src/views/qualityManagement/finalInspection/index.vue
# src/views/safeProduction/safeWorkApproval/components/infoFormDia.vue
# src/views/salesManagement/deliveryLedger/index.vue
# src/views/salesManagement/returnOrder/components/formDia.vue
# src/views/salesManagement/returnOrder/index.vue
# src/views/salesManagement/salesLedger/index.vue
# src/views/systemArchitecture/index.vue
已添加76个文件
已修改156个文件
已删除10个文件
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # è´¢å¡ç®¡çåç«¯ææ¡£ï¼ä»
è´è´£æ¨¡åï¼ |
| | | |
| | | æ´æ°æ¶é´ï¼2026-05-12 |
| | | éç¨èå´ï¼ä»
ä»¥ä¸ 6 个模åï¼ï¼ |
| | | 1. åºå®èµäº§ï¼`/financial/fixed-assets`ï¼ |
| | | 2. æ å½¢èµäº§ï¼`/financial/intangible-assets`ï¼ |
| | | 3. æ»è´¦ç§ç®ï¼`/financial/general-ledger`ï¼ |
| | | 4. åè¯ï¼`/financial/voucher`ï¼ |
| | | 5. ç§ç®æ»è´¦ï¼`/financial/voucher-general-ledger`ï¼ |
| | | 6. ç§ç®æç»è´¦ï¼`/financial/voucher-detail-ledger`ï¼ |
| | | |
| | | --- |
| | | |
| | | ## 1. ç»ä¸çº¦å® |
| | | |
| | | ### 1.1 ååºç»æ |
| | | ```json |
| | | { |
| | | "code": 200, |
| | | "msg": "success", |
| | | "data": {} |
| | | } |
| | | ``` |
| | | |
| | | ### 1.2 åé¡µç»æï¼å¦ææ¯å页æ¥å£ï¼ |
| | | 请æ±åæ°å»ºè®®ï¼ |
| | | - `current`ï¼é¡µç ï¼ |
| | | - `size`ï¼æ¯é¡µæ¡æ°ï¼ |
| | | |
| | | ååºå»ºè®®ï¼ |
| | | ```json |
| | | { |
| | | "code": 200, |
| | | "data": { |
| | | "records": [], |
| | | "total": 0 |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ### 1.3 éé¢ä¸ç²¾åº¦ |
| | | - éé¢å段建议 `decimal(18,2)`ã |
| | | - åå端ç»ä¸ä¿ç两ä½å°æ°ã |
| | | |
| | | --- |
| | | |
| | | ## 2. 模åä¸ï¼æ»è´¦ç§ç®ï¼å·²æ¥çå® APIï¼ |
| | | |
| | | å端æä»¶ï¼`src/views/financialManagement/generalLedger/index.vue` |
| | | API æä»¶ï¼`src/api/financialManagement/accountSubject.js` |
| | | |
| | | ### 2.1 æ¥å£ç°ç¶ |
| | | - `GET /accountSubject/list` |
| | | - `POST /accountSubject/add` |
| | | - `PUT /accountSubject/edit` |
| | | - `DELETE /accountSubject/remove/{ids}` |
| | | - `POST /accountSubject/export` |
| | | |
| | | ### 2.2 åæ®µæ¨¡å |
| | | - `id` |
| | | - `subjectCode`ï¼ç§ç®ç¼ç ï¼ |
| | | - `subjectName`ï¼ç§ç®åç§°ï¼ |
| | | - `subjectType`ï¼ç§ç®ç±»åï¼ |
| | | - `balanceDirection`ï¼ä½é¢æ¹åï¼åæ¹/è´·æ¹ï¼ |
| | | - `status`ï¼0 å¯ç¨ï¼1 ç¦ç¨ï¼ |
| | | - `remark` |
| | | |
| | | ### 2.3 ä¸å¡è§å |
| | | - `subjectCode`ã`subjectName`ã`subjectType` å¿
å¡«ã |
| | | - å é¤éè¦åå¼ç¨æ ¡éªï¼è¥å·²è¢«åè¯åå½å¼ç¨ï¼ä¸å
许å é¤ï¼ã |
| | | |
| | | --- |
| | | |
| | | ## 3. 模åäºï¼åºå®èµäº§ï¼å½åå端为 mockï¼å¾
å端å®ç°ï¼ |
| | | |
| | | å端æä»¶ï¼`src/views/financialManagement/assets/fixedAssets.vue` |
| | | |
| | | ### 3.1 建议æ¥å£ |
| | | - `GET /financial/fixedAsset/page` |
| | | - `POST /financial/fixedAsset/add` |
| | | - `PUT /financial/fixedAsset/update` |
| | | - `DELETE /financial/fixedAsset/delete` |
| | | - `POST /financial/fixedAsset/depreciate`ï¼ææè®¡æï¼ |
| | | |
| | | ### 3.2 åæ®µæ¨¡å |
| | | - `id, assetCode, assetName, category, specification` |
| | | - `purchaseDate, originalValue, usefulLife, residualRate` |
| | | - `accumulatedDepreciation, netValue` |
| | | - `location, department, keeper, status, remark` |
| | | |
| | | ### 3.3 æ ¸å¿å
¬å¼ï¼å¿
é¡»ä¸è´ï¼ |
| | | - `monthlyDepreciation = originalValue * (1 - residualRate/100) / (usefulLife*12)` |
| | | - `accumulatedDepreciation += monthlyDepreciation` |
| | | - `netValue = originalValue - accumulatedDepreciation` |
| | | |
| | | ### 3.4 ç¶æå»ºè®® |
| | | - `in_use`ï¼å¨ç¨ï¼ |
| | | - `idle`ï¼é²ç½®ï¼ |
| | | - `repair`ï¼ç»´ä¿®ä¸ï¼ |
| | | - `scrapped`ï¼æ¥åºï¼ |
| | | |
| | | --- |
| | | |
| | | ## 4. 模åä¸ï¼æ å½¢èµäº§ï¼å½åå端为 mockï¼å¾
å端å®ç°ï¼ |
| | | |
| | | å端æä»¶ï¼`src/views/financialManagement/assets/intangibleAssets.vue` |
| | | |
| | | ### 4.1 建议æ¥å£ |
| | | - `GET /financial/intangibleAsset/page` |
| | | - `POST /financial/intangibleAsset/add` |
| | | - `PUT /financial/intangibleAsset/update` |
| | | - `DELETE /financial/intangibleAsset/delete` |
| | | - `POST /financial/intangibleAsset/amortize`ï¼æææéï¼ |
| | | |
| | | ### 4.2 åæ®µæ¨¡å |
| | | - `id, assetCode, assetName, category, certificateNo` |
| | | - `acquisitionDate, originalValue, amortizationPeriod, residualRate` |
| | | - `accumulatedAmortization, netValue` |
| | | - `validityDate, status, description, remark` |
| | | |
| | | ### 4.3 æ ¸å¿å
¬å¼ï¼å¿
é¡»ä¸è´ï¼ |
| | | - `monthlyAmortization = originalValue * (1 - residualRate/100) / (amortizationPeriod*12)` |
| | | - `accumulatedAmortization += monthlyAmortization` |
| | | - `netValue = originalValue - accumulatedAmortization` |
| | | - å½ `netValue <= 0`ï¼ |
| | | - `netValue = 0` |
| | | - `status = amortized` |
| | | |
| | | ### 4.4 ç¶æå»ºè®® |
| | | - `in_use`ï¼å¨ç¨ï¼ |
| | | - `expired`ï¼å°æï¼ |
| | | - `amortized`ï¼å·²æéå®ï¼ |
| | | |
| | | --- |
| | | |
| | | ## 5. 模ååï¼åè¯ï¼å½åå端为 mockï¼å¾
å端å®ç°ï¼ |
| | | |
| | | å端æä»¶ï¼`src/views/financialManagement/voucher/index.vue` |
| | | |
| | | ### 5.1 建议æ¥å£ |
| | | - `GET /financial/voucher/page` |
| | | - `POST /financial/voucher/add` |
| | | - `PUT /financial/voucher/update` |
| | | - `POST /financial/voucher/post`ï¼è¿è´¦ï¼ |
| | | - `POST /financial/voucher/cancel`ï¼ä½åºï¼ |
| | | - `GET /financial/voucher/detail/{id}` |
| | | |
| | | ### 5.2 ä¸»è¡¨åæ®µ |
| | | - `id, voucherNo, voucherDate, summary` |
| | | - `debit, credit, creator, status, attachmentCount, remark` |
| | | |
| | | ### 5.3 åå½å段 |
| | | - `subjectCode, subjectName, summary, debit, credit` |
| | | |
| | | ### 5.4 å
³é®æ ¡éª |
| | | - åå½è³å°ä¸æ¡ææè¡ï¼ç§ç®ä¸ç©ºï¼ä¸åæ¹æè´·æ¹ > 0ï¼ã |
| | | - å贷平衡ï¼`sum(debit) == sum(credit)` ä¸ > 0ï¼ä¸æ»¡è¶³ç¦æ¢ä¿åã |
| | | |
| | | ### 5.5 ç¶ææµè½¬ |
| | | - `unposted -> posted` |
| | | - `unposted -> cancelled` |
| | | |
| | | --- |
| | | |
| | | ## 6. 模åäºï¼ç§ç®æ»è´¦ï¼å½åå端为 mockï¼å¾
å端å®ç°ï¼ |
| | | |
| | | å端æä»¶ï¼`src/views/financialManagement/voucher/generalLedger.vue` |
| | | |
| | | ### 6.1 建议æ¥å£ |
| | | - `GET /financial/ledger/general` |
| | | |
| | | ### 6.2 请æ±åæ° |
| | | - `subjectCode`ï¼æ«çº§ææå®ç§ç®ï¼ |
| | | - `startMonth`ï¼YYYY-MMï¼ |
| | | - `endMonth`ï¼YYYY-MMï¼ |
| | | |
| | | ### 6.3 ååºå段 |
| | | - `date, voucherNo, summary` |
| | | - `debit, credit, direction, balance` |
| | | |
| | | ### 6.4 è§å |
| | | - ä»
å¨éæ©ç§ç®åè¿åæ°æ®ã |
| | | - æ¯æâæåä½é¢ / æ¬æå计 / æ¬å¹´ç´¯è®¡âè¡ï¼å¯éè¿ `rowType` åæ®µåºåï¼ã |
| | | |
| | | --- |
| | | |
| | | ## 7. 模åå
ï¼ç§ç®æç»è´¦ï¼å½åå端为 mockï¼å¾
å端å®ç°ï¼ |
| | | |
| | | å端æä»¶ï¼`src/views/financialManagement/voucher/detailLedger.vue` |
| | | |
| | | ### 7.1 建议æ¥å£ |
| | | - `GET /financial/ledger/detail` |
| | | |
| | | ### 7.2 请æ±åæ° |
| | | - `subjectCode` |
| | | - `auxiliaryType`ï¼customer/supplier/department/employee/projectï¼ |
| | | - `auxiliaryId` |
| | | - `startMonth`ï¼YYYY-MMï¼ |
| | | - `endMonth`ï¼YYYY-MMï¼ |
| | | |
| | | ### 7.3 ååºå段 |
| | | - `date, voucherNo, summary` |
| | | - `debit, credit, direction, balance` |
| | | |
| | | ### 7.4 è§å |
| | | - å
éç§ç®ï¼åæ¥æç»ã |
| | | - è¾
婿 ¸ç®æ¡ä»¶ä¸ºå¯éï¼ä½å»ºè®®åç«¯æ¯æç»´åº¦è¿æ»¤ã |
| | | |
| | | --- |
| | | |
| | | ## 8. æ¨èæå°è¡¨è®¾è®¡ï¼ä»
æ¬èå´ï¼ |
| | | |
| | | - `fin_account_subject` |
| | | - `fin_fixed_asset` |
| | | - `fin_intangible_asset` |
| | | - `fin_voucher` |
| | | - `fin_voucher_entry` |
| | | - `fin_ledger_snapshot_general`ï¼å¯éï¼åæ§è½ä¼åï¼ |
| | | - `fin_ledger_snapshot_detail`ï¼å¯éï¼åæ§è½ä¼åï¼ |
| | | |
| | | --- |
| | | |
| | | ## 9. AI çæå端任å¡é¡ºåºï¼å»ºè®®ï¼ |
| | | |
| | | 1. å
宿 **æ»è´¦ç§ç®**ï¼å·²æ APIï¼æç¨³å®ï¼ã |
| | | 2. 宿 **åè¯ + åå½ + åè´·å¹³è¡¡æ ¡éª + ç¶ææµè½¬**ã |
| | | 3. å®ç° **ç§ç®æ»è´¦ / ç§ç®æç»è´¦** æ¥è¯¢ã |
| | | 4. å®ç° **åºå®èµäº§ææ§** ä¸ **æ å½¢èµäº§æé**ã |
| | | 5. è¡¥æµè¯ï¼ |
| | | - åè´·å¹³è¡¡æ ¡éª |
| | | - ææ§/æéå
¬å¼ |
| | | - ç§ç®è¢«å¼ç¨ç¦æ¢å é¤ |
| | | |
| | |
| | | "env": { |
| | | "VITE_APP_TITLE": "è¯å¯¼äºï¼ç®¡çä¿¡æ¯ç³»ç»ï¼" |
| | | }, |
| | | "screen": "screen/PCDZView.png", |
| | | "logo": "logo/PCDZLogo.png", |
| | | "favicon": "favicon/PCDZico.ico" |
| | | "logo": "logo/Logo.png", |
| | | "favicon": "favicon/favicon.ico" |
| | | }, |
| | | "TEST": { |
| | | "env": { |
| | | "VITE_APP_TITLE": "ä¿¡æ¯ç®¡ç", |
| | | "VITE_BASE_API": "http://1.15.17.182:9003", |
| | | "VITE_JAVA_API": "http://1.15.17.182:9002" |
| | | "VITE_APP_TITLE": "工忰ååMOMç³»ç»", |
| | | "VITE_BASE_API": "http://1.15.17.182:9048", |
| | | "VITE_JAVA_API": "http://1.15.17.182:9049" |
| | | }, |
| | | "screen": "screen/login-background.png", |
| | | "logo": "logo/PCDZLogo.png", |
| | | "logo": "logo/Logo.png", |
| | | "favicon": "favicon/favicon.ico" |
| | | }, |
| | | "YZFX": { |
| | | "env": { |
| | | "VITE_APP_TITLE": "è±æ³½é²éæ°ææä¿¡æ¯ç®¡ç", |
| | | "VITE_BASE_API": "http://1.15.17.182:9021", |
| | | "VITE_JAVA_API": "http://1.15.17.182:9020" |
| | | "VITE_APP_TITLE": "å®å¤è±æ³½é²éæ°æææéå
¬å¸", |
| | | "VITE_BASE_API": "http://42.63.70.231:9000", |
| | | "VITE_JAVA_API": "http://42.63.70.231:9001" |
| | | }, |
| | | "screen": "screen/login-background.png", |
| | | "logo": "logo/YZFXLogo.png", |
| | | "favicon": "favicon/YZFXico.ico" |
| | | "favicon": "favicon/YZFXfavicon.ico" |
| | | }, |
| | | "screen": "/src/assets/images/login-background.png", |
| | | "logo": "/src/assets/logo/logo.png", |
| | | "favicon": "/public/favicon.ico" |
| | | } |
| | |
| | | import fs from 'fs/promises'; |
| | | import fsSync from 'fs'; |
| | | import path from 'path'; |
| | | import { fileURLToPath } from 'url'; |
| | | import fs from "fs/promises"; |
| | | import fsSync from "fs"; |
| | | import path from "path"; |
| | | import { fileURLToPath } from "url"; |
| | | import { execSync } from "child_process"; |
| | | |
| | | // è·å __dirname |
| | | const __filename = fileURLToPath(import.meta.url); |
| | | const __dirname = path.dirname(__filename); |
| | | |
| | | // 读å JSON é
ç½® |
| | | const data = await fs.readFile(path.join(__dirname, 'config.json'), 'utf-8'); |
| | | const data = await fs.readFile(path.join(__dirname, "config.json"), "utf-8"); |
| | | const config = JSON.parse(data); |
| | | |
| | | // 项ç®è·¯å¾ |
| | | const rootPath = path.resolve(__dirname, '..'); |
| | | const resourcePath = path.join(rootPath, 'multiple', 'assets'); |
| | | const replacePath = path.join(rootPath, 'replace'); |
| | | const rootPath = path.resolve(__dirname, ".."); |
| | | const resourcePath = path.join(rootPath, "multiple", "assets"); |
| | | const replacePath = path.join(rootPath, "replace"); |
| | | const envFilePath = path.join(rootPath, ".env.production.local"); |
| | | |
| | | // è·åå½ä»¤è¡åæ° |
| | | const params = parseArgs(process.argv); |
| | | const company = params["company"] ?? "default"; |
| | | const company = resolveCompany(params); |
| | | const companyMap = config[company]; |
| | | |
| | | const envFilePath = path.join(process.cwd(), '.env.production.local'); |
| | | |
| | | try { |
| | | // 1ï¸â£ çæ .env |
| | | console.log("=======çæ.env======="); |
| | | const envContent = Object.entries(companyMap.env) |
| | | .map(([key, value]) => `${key}='${value}'`) |
| | | .join('\n') + '\n'; |
| | | await fs.writeFile(envFilePath, envContent, 'utf-8'); |
| | | |
| | | // 2ï¸â£ å¤ä»½åå§èµæºå¹¶æ¿æ¢ |
| | | console.log("=======ä¿®æ¹èµæº======="); |
| | | for (const [key, value] of Object.entries(companyMap)) { |
| | | if (key === 'env') continue; |
| | | |
| | | const originFile = path.join(rootPath, config[key]); |
| | | const backupFile = path.join(replacePath, config[key]); |
| | | const replaceFile = path.join(resourcePath, companyMap[key]); |
| | | |
| | | await fs.mkdir(path.dirname(backupFile), { recursive: true }); |
| | | await fs.copyFile(originFile, backupFile); |
| | | await fs.copyFile(replaceFile, originFile); |
| | | } |
| | | |
| | | console.log("=====å¼å§æå
======"); |
| | | execSync("vite build", { stdio: "inherit" }); |
| | | console.log("=====æå
宿======"); |
| | | } finally { |
| | | console.log("=====æ¢å¤èµæº======"); |
| | | |
| | | // å é¤ä¸´æ¶ .env æä»¶ |
| | | if (fsSync.existsSync(envFilePath)) { |
| | | await fs.unlink(envFilePath); |
| | | console.log(`ðï¸ å·²å é¤ ${envFilePath}`); |
| | | } |
| | | |
| | | // æ¢å¤èµæºæä»¶ |
| | | if (fsSync.existsSync(replacePath)) { |
| | | for (const [key, value] of Object.entries(companyMap)) { |
| | | if (key === 'env') continue; |
| | | |
| | | const originFile = path.join(rootPath, config[key]); |
| | | const backupFile = path.join(replacePath, config[key]); |
| | | |
| | | await fs.copyFile(backupFile, originFile); |
| | | } |
| | | await fs.rm(replacePath, { recursive: true, force: true }); |
| | | console.log(`ðï¸ å·²å é¤ ${replacePath}`); |
| | | } |
| | | if (!companyMap) { |
| | | const availableCompanies = Object.entries(config) |
| | | .filter(([, value]) => value && typeof value === "object" && value.env) |
| | | .map(([key]) => key) |
| | | .sort(); |
| | | throw new Error( |
| | | `æªç¥ company: "${company}"ãå¯éå¼: ${availableCompanies.join(", ")}` |
| | | ); |
| | | } |
| | | |
| | | // ç®åå½ä»¤è¡åæ°è§£æ |
| | | function parseArgs(argv) { |
| | | const params = {}; |
| | | for (const arg of argv.slice(2)) { |
| | | if (arg.startsWith('--')) { |
| | | const [key, value] = arg.slice(2).split('='); |
| | | params[key] = value ?? true; |
| | | } |
| | | console.log(`å½å company: ${company}`); |
| | | |
| | | async function copyFileWithOverwrite(src, dest) { |
| | | await fs.mkdir(path.dirname(dest), { recursive: true }); |
| | | if (fsSync.existsSync(dest)) { |
| | | try { |
| | | await fs.chmod(dest, 0o666); |
| | | } catch { |
| | | // Ignore chmod failure and continue. |
| | | } |
| | | return params; |
| | | await fs.rm(dest, { force: true }); |
| | | } |
| | | await fs.copyFile(src, dest); |
| | | } |
| | | |
| | | try { |
| | | console.log("=======çæ.env======="); |
| | | const envContent = |
| | | Object.entries(companyMap.env) |
| | | .map(([key, value]) => `${key}='${value}'`) |
| | | .join("\n") + "\n"; |
| | | await fs.writeFile(envFilePath, envContent, "utf-8"); |
| | | |
| | | console.log("=======ä¿®æ¹èµæº======="); |
| | | for (const [key] of Object.entries(companyMap)) { |
| | | if (key === "env") continue; |
| | | |
| | | const originFile = path.join(rootPath, config[key]); |
| | | const backupFile = path.join(replacePath, config[key]); |
| | | const replaceFile = path.join(resourcePath, companyMap[key]); |
| | | |
| | | await copyFileWithOverwrite(originFile, backupFile); |
| | | await copyFileWithOverwrite(replaceFile, originFile); |
| | | } |
| | | |
| | | console.log("=====å¼å§æå
====="); |
| | | const buildEnv = createBuildEnv(companyMap.env); |
| | | execSync("vite build", { stdio: "inherit", cwd: rootPath, env: buildEnv }); |
| | | console.log("=====æå
宿======"); |
| | | } finally { |
| | | console.log("=====æ¢å¤èµæº======"); |
| | | |
| | | if (fsSync.existsSync(envFilePath)) { |
| | | await fs.unlink(envFilePath); |
| | | console.log(`ðï¸ å·²å é¤ ${envFilePath}`); |
| | | } |
| | | |
| | | if (fsSync.existsSync(replacePath)) { |
| | | for (const [key] of Object.entries(companyMap)) { |
| | | if (key === "env") continue; |
| | | |
| | | const originFile = path.join(rootPath, config[key]); |
| | | const backupFile = path.join(replacePath, config[key]); |
| | | await copyFileWithOverwrite(backupFile, originFile); |
| | | } |
| | | await fs.rm(replacePath, { recursive: true, force: true }); |
| | | console.log(`ðï¸ å·²å é¤ ${replacePath}`); |
| | | } |
| | | } |
| | | |
| | | function parseArgs(argv) { |
| | | const params = {}; |
| | | for (let index = 2; index < argv.length; index++) { |
| | | const arg = argv[index]; |
| | | if (!arg.startsWith("--")) continue; |
| | | |
| | | const normalized = arg.slice(2); |
| | | const equalIndex = normalized.indexOf("="); |
| | | if (equalIndex >= 0) { |
| | | const key = normalized.slice(0, equalIndex); |
| | | const value = normalized.slice(equalIndex + 1); |
| | | params[key] = value || true; |
| | | continue; |
| | | } |
| | | |
| | | const nextArg = argv[index + 1]; |
| | | if (nextArg && !nextArg.startsWith("--")) { |
| | | params[normalized] = nextArg; |
| | | index += 1; |
| | | continue; |
| | | } |
| | | |
| | | params[normalized] = true; |
| | | } |
| | | return params; |
| | | } |
| | | |
| | | function resolveCompany(parsedParams) { |
| | | const fromArg = parseValue(parsedParams.company); |
| | | if (fromArg) return fromArg; |
| | | |
| | | const fromNpmConfig = parseValue(process.env.npm_config_company); |
| | | if (fromNpmConfig) return fromNpmConfig; |
| | | |
| | | const fromEnv = parseValue(process.env.COMPANY ?? process.env.company); |
| | | if (fromEnv) return fromEnv; |
| | | |
| | | return "default"; |
| | | } |
| | | |
| | | function parseValue(value) { |
| | | if (value == null || value === true) return undefined; |
| | | if (typeof value !== "string") return undefined; |
| | | const trimmed = value.trim(); |
| | | if (!trimmed) return undefined; |
| | | return trimmed.replace(/^["']|["']$/g, ""); |
| | | } |
| | | |
| | | function createBuildEnv(companyEnv) { |
| | | const env = { ...process.env }; |
| | | for (const key of Object.keys(env)) { |
| | | if (key.startsWith("VITE_")) { |
| | | delete env[key]; |
| | | } |
| | | } |
| | | return { |
| | | ...env, |
| | | ...companyEnv, |
| | | VITE_APP_ENV: "production", |
| | | }; |
| | | } |
| | |
| | | }, |
| | | "overrides": { |
| | | "quill": "2.0.2" |
| | | } |
| | | }, |
| | | "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" |
| | | } |
| | |
| | | }) |
| | | } |
| | | |
| | | // æµå
¥å
¬æµ· |
| | | export function backCustomer(id) { |
| | | return request({ |
| | | url: '/basic/customer/back/' + id, |
| | | method: 'post' |
| | | }) |
| | | } |
| | | |
| | | export function shareCustomer(data) { |
| | | return request({ |
| | | url: '/basic/customer/together', |
| | |
| | | data, |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * @desc éªæ¶å®¡æ¹ |
| | | * @param {éªæ¶åæ°} data |
| | | * @returns |
| | | */ |
| | | export const repairAcceptance = (data) => { |
| | | return request({ |
| | | url: `/device/repair/acceptance`, |
| | | method: "post", |
| | | data, |
| | | }); |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | /** éè´å
¥åºå页å表 */ |
| | | export const listPageAccountPurchase = (params) => { |
| | | return request({ |
| | | url: "/accountPurchase/listPageAccountPurchase", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | }; |
| | | |
| | | /** éè´éè´§å页å表 */ |
| | | export const listPageAccountPurchaseReturn = (params) => { |
| | | return request({ |
| | | url: "/accountPurchase/listPageAccountPurchaseReturn", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | /** éå®åºåºå页å表 */ |
| | | export const listPageAccountSales = (params) => { |
| | | return request({ |
| | | url: "/accountSales/listPageAccountSales", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | }; |
| | | |
| | | /** éå®éè´§å页å表 */ |
| | | export const listPageAccountSalesReturn = (params) => { |
| | | return request({ |
| | | url: "/accountSales/listPageAccountSalesReturn", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | // æ¥è¯¢æ»å¸ç§ç®å表 |
| | | export function listAccountSubject(query) { |
| | | return request({ |
| | | url: "/accountSubject/list", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | // æ°å¢æ»å¸ç§ç® |
| | | export function addAccountSubject(data) { |
| | | return request({ |
| | | url: "/accountSubject/add", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // ä¿®æ¹æ»å¸ç§ç® |
| | | export function updateAccountSubject(data) { |
| | | return request({ |
| | | url: "/accountSubject/edit", |
| | | method: "put", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // å 餿»å¸ç§ç® |
| | | export function delAccountSubject(ids) { |
| | | return request({ |
| | | url: "/accountSubject/remove/" + ids, |
| | | method: "delete", |
| | | }); |
| | | } |
| | | |
| | | // å¯¼åºæ»å¸ç§ç® |
| | | export function exportAccountSubject(data) { |
| | | return request({ |
| | | url: "/accountSubject/export", |
| | | method: "post", |
| | | data: data, |
| | | responseType: "blob", |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | // åºå®èµäº§å页æ¥è¯¢ï¼current/sizeï¼ |
| | | export function listFixedAssetPage(params) { |
| | | return request({ |
| | | url: "/financial/fixedAsset/page", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | } |
| | | |
| | | // æ°å¢åºå®èµäº§ |
| | | export function addFixedAsset(data) { |
| | | return request({ |
| | | url: "/financial/fixedAsset/add", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // ä¿®æ¹åºå®èµäº§ |
| | | export function updateFixedAsset(data) { |
| | | return request({ |
| | | url: "/financial/fixedAsset/update", |
| | | method: "put", |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // å é¤åºå®èµäº§ï¼åç«¯è¦æ± ids=1&ids=2 å½¢å¼ï¼ |
| | | export function deleteFixedAsset(ids) { |
| | | const idList = Array.isArray(ids) ? ids : [ids]; |
| | | const query = idList |
| | | .filter(id => id !== undefined && id !== null && id !== "") |
| | | .map(id => `ids=${encodeURIComponent(id)}`) |
| | | .join("&"); |
| | | return request({ |
| | | url: `/financial/fixedAsset/delete?${query}`, |
| | | method: "delete", |
| | | }); |
| | | } |
| | | |
| | | // ææ§è®¡æï¼{} 表示å
¨é¨å¨ç¨èµäº§ï¼ |
| | | export function depreciateFixedAsset(data = {}) { |
| | | return request({ |
| | | url: "/financial/fixedAsset/depreciate", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | // æ å½¢èµäº§å页æ¥è¯¢ï¼current/sizeï¼ |
| | | export function listIntangibleAssetPage(params) { |
| | | return request({ |
| | | url: "/financial/intangibleAsset/page", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | } |
| | | |
| | | // æ°å¢æ å½¢èµäº§ |
| | | export function addIntangibleAsset(data) { |
| | | return request({ |
| | | url: "/financial/intangibleAsset/add", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // ä¿®æ¹æ å½¢èµäº§ |
| | | export function updateIntangibleAsset(data) { |
| | | return request({ |
| | | url: "/financial/intangibleAsset/update", |
| | | method: "put", |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // å 餿 å½¢èµäº§ï¼åç«¯è¦æ± ids=1&ids=2 å½¢å¼ï¼ |
| | | export function deleteIntangibleAsset(ids) { |
| | | const idList = Array.isArray(ids) ? ids : [ids]; |
| | | const query = idList |
| | | .filter(id => id !== undefined && id !== null && id !== "") |
| | | .map(id => `ids=${encodeURIComponent(id)}`) |
| | | .join("&"); |
| | | return request({ |
| | | url: `/financial/intangibleAsset/delete?${query}`, |
| | | method: "delete", |
| | | }); |
| | | } |
| | | |
| | | // æé计æï¼{} 表示å
¨é¨å¨ç¨èµäº§ï¼ |
| | | export function amortizeIntangibleAsset(data = {}) { |
| | | return request({ |
| | | url: "/financial/intangibleAsset/amortize", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | // ç§ç®æ»è´¦ |
| | | export function getGeneralLedger(params) { |
| | | return request({ |
| | | url: "/financial/ledger/general", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | } |
| | | |
| | | // ç§ç®æç»è´¦ |
| | | export function getDetailLedger(params) { |
| | | return request({ |
| | | url: "/financial/ledger/detail", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | // åè¯å页æ¥è¯¢ï¼current/size + è¿æ»¤æ¡ä»¶ï¼ |
| | | export function listVoucherPage(params) { |
| | | return request({ |
| | | url: "/financial/voucher/page", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | } |
| | | |
| | | // æ°å¢åè¯ |
| | | export function addVoucher(data) { |
| | | return request({ |
| | | url: "/financial/voucher/add", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // ä¿®æ¹åè¯ï¼ä»
æªè¿è´¦ï¼ |
| | | export function updateVoucher(data) { |
| | | return request({ |
| | | url: "/financial/voucher/update", |
| | | method: "put", |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // è¿è´¦ |
| | | export function postVoucher(data) { |
| | | return request({ |
| | | url: "/financial/voucher/post", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // ä½åº |
| | | export function cancelVoucher(data) { |
| | | return request({ |
| | | url: "/financial/voucher/cancel", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // 详æ
|
| | | export function getVoucherDetail(id) { |
| | | return request({ |
| | | url: `/financial/voucher/detail/${id}`, |
| | | method: "get", |
| | | }); |
| | | } |
| | |
| | | }); |
| | | }; |
| | | |
| | | export const getStockInventoryBatchNoQty = (params) => { |
| | | return request({ |
| | | url: "/stockInventory/getBatchNoQty", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | }; |
| | | |
| | | // å建åºåè®°å½ |
| | | export const createStockInventory = (params) => { |
| | | return request({ |
| | |
| | | import request from '@/utils/request'
|
| | | import request from '@/utils/request' |
| | | import { getToken } from '@/utils/auth' |
| | |
|
| | | // ç»å½æ¹æ³
|
| | | export function login(username, password, code, uuid) {
|
| | |
| | | }
|
| | |
|
| | | // è·åç¨æ·è¯¦ç»ä¿¡æ¯
|
| | | export function getInfo() {
|
| | | return request({
|
| | | url: '/getInfo',
|
| | | method: 'get'
|
| | | })
|
| | | }
|
| | | export function getInfo() { |
| | | const token = getToken() |
| | | return request({ |
| | | url: '/getInfo', |
| | | headers: token ? { Authorization: `Bearer ${token}` } : {}, |
| | | method: 'get' |
| | | }) |
| | | } |
| | |
|
| | | // éåºæ¹æ³
|
| | | export function logout() {
|
| | |
| | | }); |
| | | } |
| | | |
| | | // æ ¹æ®éè´å°è´¦ ID æ¥è¯¢å¯é产åçä¿¡æ¯ |
| | | export function getPurchaseReturnOrderByPurchaseLedgerId(query) { |
| | | return request({ |
| | | url: "/purchaseReturnOrders/getByPurchaseLedgerId", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | // æ¥ç详æ
|
| | | // purchaseReturnOrders/selectById/xxx |
| | | export function getPurchaseReturnOrderDetail(id) { |
| | |
| | | method: "get", |
| | | }); |
| | | } |
| | | // ä¿®æ¹åè´§å°è´¦ |
| | | export function getDeliveryDetailByShippingNo(query) { |
| | | return request({ |
| | | url: "/shippingInfo/getDateilByShippingNo", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | export function addOrUpdateDeliveryLedger(query) { |
| | | return request({ |
| | |
| | | data, |
| | | }); |
| | | } |
| | | |
| | |
| | | method: "get", |
| | | }); |
| | | }; |
| | | |
| | | export const productionOverview = () => { |
| | | return request({ |
| | | url: "/home/productionOverview", |
| | | method: "get", |
| | | headers: { |
| | | handleAuthError: false, |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | export const productionRealtimeBoard = () => { |
| | | return request({ |
| | | url: "/home/productionRealtimeBoard", |
| | | method: "get", |
| | | headers: { |
| | | handleAuthError: false, |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | const HOME_PROGRESS_STATUS_LIST = ["all", "waiting", "inProgress", "completed", "paused", "1", "2", "3", "4"]; |
| | | const HOME_PROGRESS_TAB_LIST = ["all", "inProgress", "completed", "paused"]; |
| | | const HOME_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/; |
| | | |
| | | const normalizeDateParam = (value) => { |
| | | const dateText = typeof value === "string" ? value.trim() : ""; |
| | | return HOME_DATE_PATTERN.test(dateText) ? dateText : undefined; |
| | | }; |
| | | |
| | | export const productionOrderProgress = (params = {}) => { |
| | | const safePageNum = Math.max(1, Number(params.pageNum || 1)); |
| | | const safePageSize = Math.min(50, Math.max(1, Number(params.pageSize || 10))); |
| | | const rawStatus = String(params.status ?? "").trim(); |
| | | const safeStatus = HOME_PROGRESS_STATUS_LIST.includes(rawStatus) ? rawStatus : undefined; |
| | | const safeTab = HOME_PROGRESS_TAB_LIST.includes(params.tab) ? params.tab : "all"; |
| | | const normalizedTab = safeStatus && HOME_PROGRESS_TAB_LIST.includes(safeStatus) ? safeStatus : safeTab; |
| | | return request({ |
| | | url: "/home/productionOrderProgress", |
| | | method: "get", |
| | | params: { |
| | | ...params, |
| | | status: safeStatus, |
| | | tab: normalizedTab, |
| | | bizDate: normalizeDateParam(params.bizDate), |
| | | pageNum: safePageNum, |
| | | pageSize: safePageSize, |
| | | }, |
| | | headers: { |
| | | handleAuthError: false, |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | export const todayProductionPlan = (params = {}) => { |
| | | const safeLimit = Math.min(20, Math.max(1, Number(params.limit || 4))); |
| | | return request({ |
| | | url: "/home/todayProductionPlan", |
| | | method: "get", |
| | | params: { |
| | | ...params, |
| | | limit: safeLimit, |
| | | planDate: normalizeDateParam(params.planDate), |
| | | }, |
| | | headers: { |
| | | handleAuthError: false, |
| | | }, |
| | | }); |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="452" height="285" viewBox="0 0 452 285"><defs><pattern x="0" y="80.0157699584961" width="452" height="204.98422241210938" patternUnits="userSpaceOnUse" id="master_svg0_143_34844"><image x="-0.11198217826978407" y="0" width="452.22396435653957" height="204.98422241210938" xlink:href="data:image/png;base64,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"/></pattern><pattern x="111.42742919921875" y="0" width="206.67991638183594" height="206.78233337402344" patternUnits="userSpaceOnUse" id="master_svg1_143_34837"><image x="-0.05120849609375" y="0" width="206.78233337402344" height="206.78233337402344" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAMgCAYAAADbcAZoAAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAACAASURBVHic7N17nN1ldS/+z2c9371nkpAwyVxygWpQERWrVdSD1nNUilYuggZjJdTaXyNQ5CZarWJfnrHnVw6tRe4WIrRVC1gwKAjGFk6hN6UKre0RBbVCAXOZS+7JzOz9fdY6fzzfPbMnJJm990wyk8x6v155JZnZ+7uf/d179jzr+zxrLcA555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzzjnnnHPOOeecc84555xzE+B0D8A559zM0H3xc1URyWr/t5j+Jglw/K8LM9v7QWT/v1ZIpuMBUNXnfQ0AiDDu+GYGkjAzWN3xzQxUg4ik/+/xvfq/SULNlg1c071h4jPhnHPuQPIAxDnnHLo+0T9fdo9sh9QFA1r3K6IWANRN6PdqggCkFiygLgDBnkGIyWjQQRKqmgIQ4fMDi7oApDbcWrCCuuCldmzStmx8prMbdzE2d4acc85NFQ9AnHPuENB9/n8eSwlXAjhZVUHwQUA/2X/zi386VY+x8Pf/88jS7iOWI68YQ8lopgCw8calj0/VY0yHro/0Lw0ivwDAWmCiJl8ZuGbRb0332JxzbjbyAMQ552a4rgt+fhyVj1DYgWLlgCSi6VYRnjjwZy96crrHeCjo/tjAB6n4S9StoIhkZ276/MJ7p3tszjk3m3gA4pybFTpW/+BrGXEaRKAKTRt2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"/></pattern></defs><rect x="0" y="80.0157699584961" width="452" height="204.98422241210938" rx="0" fill="url(#master_svg0_143_34844)" fill-opacity="1"/><rect x="111.42742919921875" y="0" width="206.67991638183594" height="206.78233337402344" rx="0" fill="url(#master_svg1_143_34837)" fill-opacity="1"/><g><path d="M171.28799999,112L197.784,47.968002L213.431999,47.968002L239.928001,112L223.99200100000002,112L217.751999,97.216003L193.464001,97.216003L187.224001,112L171.28799999,112ZM205.656002,63.424L196.535999,85.792L214.776001,85.792L205.656002,63.424ZM246.840004,112L246.840004,47.968002L260.472,47.968002L260.472,112L246.840004,112Z" fill="#FFFFFF" fill-opacity="1"/><path d="M217.751999,97.216003L223.99200100000002,112L239.928001,112L239.514206,111L213.431999,47.968002L197.784002,47.968002L171.70179313,111L171.28799999,112L187.224003,112L193.464001,97.216003L217.751999,97.216003ZM186.560656,111L192.800652,96.216003L218.41535199999998,96.216003L224.655346,111L238.43197600000002,111L212.763565,48.968002L198.452438,48.968002L172.7840257,111L186.560656,111ZM246.840012,111L246.840012,112L260.472008,112L260.472008,47.968002L246.840012,47.968002L246.840012,111ZM247.840012,111L259.472008,111L259.472008,48.968002L247.840012,48.968002L247.840012,111ZM206.581993,63.046455L204.730011,63.046455L195.048351,86.79200399999999L216.263653,86.79200399999999L206.581993,63.046455ZM205.116039,64.748333L205.656002,63.424004L206.195965,64.748333L214.368279,84.79200399999999L214.776001,85.79200399999999L196.536001,85.79200399999999L196.943726,84.79200399999999L205.116039,64.748333Z" fill-rule="evenodd" fill="#E2E6F7" fill-opacity="1"/></g></svg> |
| | |
| | | left: 0; |
| | | position: relative; |
| | | margin: 0 auto; |
| | | border-radius: 24px; |
| | | border-radius: 16px; |
| | | padding: 0 !important; |
| | | border: 1px solid var(--surface-border); |
| | | box-shadow: var(--shadow-md); |
| | | background: rgba(255, 255, 255, 0.96); |
| | | background: rgba(255, 255, 255, 0.95); |
| | | } |
| | | .el-dialog__header { |
| | | background: linear-gradient(180deg, rgba(247, 250, 248, 0.98), rgba(242, 247, 244, 0.88)); |
| | | background: linear-gradient(180deg, rgba(248, 251, 255, 1), rgba(242, 247, 255, 0.98)); |
| | | padding: 18px 24px 14px; |
| | | border-bottom: 1px solid var(--surface-border); |
| | | border-radius: 24px 24px 0 0; |
| | | border-radius: 14px 14px 0 0; |
| | | } |
| | | .el-dialog__title { |
| | | font-weight: 600; |
| | |
| | | } |
| | | .el-message-box { |
| | | padding: 0 !important; |
| | | border-radius: 22px; |
| | | border-radius: 16px; |
| | | border: 1px solid var(--surface-border); |
| | | box-shadow: var(--shadow-md); |
| | | background: rgba(255, 255, 255, 0.96); |
| | | } |
| | | .el-message-box__header { |
| | | background: linear-gradient(180deg, rgba(247, 250, 248, 0.98), rgba(242, 247, 244, 0.88)); |
| | | background: linear-gradient(180deg, rgba(248, 251, 255, 1), rgba(242, 247, 255, 0.98)); |
| | | padding: 18px 24px 14px; |
| | | border-bottom: 1px solid var(--surface-border); |
| | | border-radius: 22px 22px 0 0; |
| | | border-radius: 14px 14px 0 0; |
| | | } |
| | | .el-message-box__title { |
| | | font-weight: 600; |
| | |
| | | } |
| | | |
| | | .el-button { |
| | | border-radius: 12px; |
| | | border-radius: 8px; |
| | | font-weight: 600; |
| | | box-shadow: none !important; |
| | | } |
| | |
| | | .el-select__wrapper, |
| | | .el-date-editor.el-input__wrapper, |
| | | .el-date-editor .el-input__wrapper { |
| | | border-radius: 12px; |
| | | box-shadow: 0 0 0 1px rgba(216, 225, 219, 0.92) inset !important; |
| | | background: rgba(255, 255, 255, 0.9); |
| | | border-radius: 10px; |
| | | box-shadow: 0 0 0 1px rgba(148, 163, 184, 0.28) inset !important; |
| | | background: rgba(255, 255, 255, 0.92); |
| | | color: var(--text-primary); |
| | | } |
| | | |
| | | .el-input__wrapper.is-focus, |
| | | .el-select__wrapper.is-focused, |
| | | .el-textarea__inner:focus { |
| | | box-shadow: 0 0 0 1px rgba(0, 47, 167, 0.28) inset !important; |
| | | box-shadow: 0 0 0 1px rgba(37, 99, 235, 0.56) inset !important; |
| | | } |
| | | |
| | | .el-card { |
| | | border: 1px solid var(--surface-border); |
| | | box-shadow: var(--shadow-sm); |
| | | background: rgba(255, 255, 255, 0.88); |
| | | background: var(--panel-mask); |
| | | } |
| | | |
| | | .el-table { |
| | | --el-table-border-color: var(--surface-border); |
| | | --el-table-header-bg-color: var(--surface-soft); |
| | | --el-table-row-hover-bg-color: #f1f6f4; |
| | | --el-table-current-row-bg-color: #e9f0ed; |
| | | border-radius: 18px; |
| | | --el-table-header-bg-color: #f2f7ff; |
| | | --el-table-row-hover-bg-color: #f8fbff; |
| | | --el-table-current-row-bg-color: #edf4ff; |
| | | border-radius: 12px; |
| | | background: rgba(255, 255, 255, 0.94) !important; |
| | | } |
| | | |
| | | .el-table th.el-table__cell { |
| | | background: var(--surface-soft) !important; |
| | | color: var(--text-secondary); |
| | | background: #f2f7ff !important; |
| | | color: #3b4f6c; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .el-table tr, |
| | | .el-table td.el-table__cell, |
| | | .el-table__body tr > td.el-table__cell { |
| | | background: var(--surface-base) !important; |
| | | background: rgba(255, 255, 255, 0.92) !important; |
| | | color: var(--text-secondary); |
| | | } |
| | | |
| | | .el-table .el-table__body tr:hover > td.el-table__cell { |
| | |
| | | .el-pagination { |
| | | margin-top: 18px; |
| | | } |
| | | |
| | | .el-empty__description p, |
| | | .el-form-item__label, |
| | | .el-radio-button__inner, |
| | | .el-checkbox__label, |
| | | .el-tabs__item, |
| | | .el-select-dropdown__item, |
| | | .el-dropdown-menu__item { |
| | | color: var(--text-secondary); |
| | | } |
| | | |
| | | .el-date-editor .el-range-input, |
| | | .el-input__inner, |
| | | .el-textarea__inner { |
| | | color: var(--text-primary); |
| | | } |
| | |
| | | @import './btn.scss';
|
| | | @import './ruoyi.scss';
|
| | |
|
| | | body {
|
| | | height: 100%;
|
| | | margin: 0;
|
| | | body { |
| | | height: 100%; |
| | | margin: 0; |
| | | -moz-osx-font-smoothing: grayscale;
|
| | | -webkit-font-smoothing: antialiased;
|
| | | text-rendering: optimizeLegibility;
|
| | | font-family: "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
|
| | | background:
|
| | | radial-gradient(circle at top left, rgba(214, 226, 219, 0.8), transparent 28%),
|
| | | linear-gradient(180deg, #f7faf8 0%, var(--app-bg) 100%);
|
| | | color: var(--text-primary);
|
| | | }
|
| | | text-rendering: optimizeLegibility; |
| | | font-family: "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; |
| | | background: |
| | | radial-gradient(circle at 9% -6%, rgba(59, 130, 246, 0.14), transparent 36%), |
| | | radial-gradient(circle at 88% -8%, rgba(56, 189, 248, 0.12), transparent 30%), |
| | | linear-gradient(165deg, #f3f7fc 0%, #eef5ff 54%, #f8fbff 100%); |
| | | color: var(--text-primary); |
| | | } |
| | |
|
| | | label {
|
| | | font-weight: 600;
|
| | |
| | | height: 100%;
|
| | | }
|
| | |
|
| | | html,
|
| | | body,
|
| | | #app {
|
| | | background-color: var(--app-bg);
|
| | | }
|
| | | html, |
| | | body, |
| | | #app { |
| | | background-color: var(--app-bg); |
| | | } |
| | |
|
| | | *,
|
| | | *:before,
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | aside {
|
| | | background: #eef1f6;
|
| | | padding: 8px 24px;
|
| | | margin-bottom: 20px;
|
| | | border-radius: 2px;
|
| | | aside { |
| | | background: rgba(255, 255, 255, 0.84); |
| | | padding: 8px 24px; |
| | | margin-bottom: 20px; |
| | | border-radius: 12px; |
| | | border: 1px solid var(--surface-border); |
| | | display: block;
|
| | | line-height: 32px;
|
| | | font-size: 16px;
|
| | | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
| | | color: #2c3e50;
|
| | | color: var(--text-secondary); |
| | | -webkit-font-smoothing: antialiased;
|
| | | -moz-osx-font-smoothing: grayscale;
|
| | |
|
| | |
| | | .app-container {
|
| | | padding: 20px 24px 24px;
|
| | | }
|
| | | .search_form {
|
| | | .search_form { |
| | | display: flex;
|
| | | align-items: center;
|
| | | justify-content: space-between;
|
| | | .search_title {
|
| | | .search_title { |
| | | font-size: 14px;
|
| | | font-weight: 600;
|
| | | letter-spacing: 0.04em;
|
| | | color: var(--text-secondary);
|
| | | }
|
| | | }
|
| | | .table_list {
|
| | | background: rgba(255, 255, 255, 0.88);
|
| | | border: 1px solid var(--surface-border);
|
| | | border-radius: var(--radius-md);
|
| | | box-shadow: var(--shadow-sm);
|
| | | padding: 18px;
|
| | | }
|
| | | color: var(--text-secondary); |
| | | } |
| | | } |
| | | .table_list { |
| | | background: var(--panel-mask); |
| | | border: 1px solid var(--surface-border); |
| | | border-radius: var(--radius-md); |
| | | box-shadow: var(--shadow-sm); |
| | | backdrop-filter: blur(12px); |
| | | padding: 18px; |
| | | } |
| | | .components-container {
|
| | | margin: 30px 50px;
|
| | | position: relative;
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | .link-type,
|
| | | .link-type:focus {
|
| | | color: var(--el-color-primary);
|
| | | cursor: pointer;
|
| | |
|
| | | &:hover {
|
| | | color: #165e57;
|
| | | }
|
| | | }
|
| | | .link-type, |
| | | .link-type:focus { |
| | | color: var(--accent-light); |
| | | cursor: pointer; |
| | | |
| | | &:hover { |
| | | color: #2563eb; |
| | | } |
| | | } |
| | |
|
| | | .filter-container {
|
| | | padding-bottom: 10px;
|
| | |
| | | #app {
|
| | | .main-container {
|
| | | min-height: 100%;
|
| | | transition: margin-left 0.28s;
|
| | | margin-left: $base-sidebar-width;
|
| | | min-height: 100vh;
|
| | | margin-left: var(--sidebar-width);
|
| | | transition: margin-left 0.25s ease;
|
| | | position: relative;
|
| | | background: transparent;
|
| | | }
|
| | |
| | | }
|
| | |
|
| | | .sidebar-container {
|
| | | transition: width 0.28s;
|
| | | width: $base-sidebar-width !important;
|
| | | height: 100%;
|
| | | transition: width 0.25s ease;
|
| | | width: var(--sidebar-width) !important;
|
| | | height: 100vh;
|
| | | position: fixed;
|
| | | font-size: 0px;
|
| | | top: 0;
|
| | | bottom: 0;
|
| | | left: 0;
|
| | | z-index: 1001;
|
| | | overflow: hidden;
|
| | | padding: 12px 0 16px 16px;
|
| | | background: transparent;
|
| | | box-shadow: none;
|
| | | padding: 0;
|
| | | font-size: 0;
|
| | | background: var(--sidebar-bg);
|
| | | border-right: 1px solid rgba(255, 255, 255, 0.08);
|
| | | box-shadow: 8px 0 24px rgba(15, 23, 42, 0.08);
|
| | | isolation: isolate;
|
| | |
|
| | | // reset element-ui css
|
| | | &::before {
|
| | | content: "";
|
| | | position: absolute;
|
| | | inset: -28% -52% -18% -38%;
|
| | | z-index: 0;
|
| | | pointer-events: none;
|
| | | background:
|
| | | radial-gradient(circle at 9% 12%, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.62), transparent 44%),
|
| | | radial-gradient(circle at 87% 18%, rgba(56, 189, 248, 0.4), transparent 48%),
|
| | | radial-gradient(circle at 20% 82%, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.3), transparent 43%),
|
| | | radial-gradient(circle at 66% 62%, rgba(125, 211, 252, 0.24), transparent 50%),
|
| | | conic-gradient(
|
| | | from 210deg at 58% 38%,
|
| | | rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.14) 0deg,
|
| | | rgba(56, 189, 248, 0.05) 76deg,
|
| | | rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.16) 180deg,
|
| | | rgba(125, 211, 252, 0.04) 290deg,
|
| | | rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.14) 360deg
|
| | | );
|
| | | filter: blur(7px) saturate(1.24) contrast(1.05);
|
| | | opacity: 0.96;
|
| | | transform: translate3d(0, 0, 0);
|
| | | transform-origin: 44% 58%;
|
| | | animation:
|
| | | sidebarAuroraDrift 17.9s cubic-bezier(0.31, 0.03, 0.18, 0.99) infinite,
|
| | | sidebarAuroraBreath 9.7s ease-in-out infinite,
|
| | | sidebarAuroraSkew 6.9s steps(23, end) infinite;
|
| | | }
|
| | |
|
| | | &::after {
|
| | | content: "";
|
| | | position: absolute;
|
| | | inset: 0;
|
| | | z-index: 0;
|
| | | pointer-events: none;
|
| | | background:
|
| | | linear-gradient(
|
| | | 108deg,
|
| | | transparent 10%,
|
| | | rgba(255, 255, 255, 0.17) 34%,
|
| | | rgba(255, 255, 255, 0.04) 48%,
|
| | | transparent 72%
|
| | | ),
|
| | | linear-gradient(
|
| | | 202deg,
|
| | | rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.24) 0%,
|
| | | transparent 34%,
|
| | | rgba(56, 189, 248, 0.18) 66%,
|
| | | transparent 100%
|
| | | ),
|
| | | radial-gradient(circle at 74% 12%, rgba(125, 211, 252, 0.25), transparent 50%),
|
| | | radial-gradient(circle at 22% 84%, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.14), transparent 56%);
|
| | | background-size: 236% 100%, 186% 186%, 164% 164%, 180% 180%;
|
| | | background-position: 224% 0, 14% 16%, 78% 10%, 18% 82%;
|
| | | opacity: 0.52;
|
| | | transform: translate3d(0, 0, 0);
|
| | | animation:
|
| | | sidebarSheenSweep 13.1s linear infinite,
|
| | | sidebarSheenJitter 4.7s steps(31, end) infinite;
|
| | | }
|
| | |
|
| | | > * {
|
| | | position: relative;
|
| | | z-index: 1;
|
| | | }
|
| | |
|
| | | .horizontal-collapse-transition {
|
| | | transition: 0s width ease-in-out, 0s padding-left ease-in-out,
|
| | | 0s padding-right ease-in-out;
|
| | | transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
|
| | | }
|
| | |
|
| | | .scrollbar-wrapper {
|
| | | overflow-x: hidden !important;
|
| | | overflow-y: auto !important;
|
| | | }
|
| | |
|
| | | .el-scrollbar__bar.is-vertical {
|
| | | right: 0px;
|
| | | right: 2px;
|
| | | }
|
| | |
|
| | | .el-scrollbar {
|
| | |
| | |
|
| | | &.has-logo {
|
| | | .el-scrollbar {
|
| | | height: calc(100% - 72px);
|
| | | margin-top: 10px;
|
| | | height: calc(100% - 78px);
|
| | | }
|
| | | }
|
| | |
|
| | |
| | | overflow: hidden;
|
| | | }
|
| | |
|
| | | .svg-icon {
|
| | | margin-right: 16px;
|
| | | .el-menu {
|
| | | border: none !important;
|
| | | height: 100%;
|
| | | width: 100% !important;
|
| | | padding: 10px 0 16px;
|
| | | border-radius: 0;
|
| | | background: transparent !important;
|
| | | box-shadow: none;
|
| | | backdrop-filter: none;
|
| | | }
|
| | |
|
| | | .el-menu { |
| | | border: none; |
| | | height: 100%; |
| | | width: 100% !important; |
| | | padding: 10px 8px 18px; |
| | | border-radius: 22px; |
| | | background: var(--menu-surface); |
| | | backdrop-filter: blur(18px); |
| | | box-shadow: var(--shadow-sm); |
| | | } |
| | |
|
| | | .el-menu-item,
|
| | | .el-sub-menu__title,
|
| | | .menu-title {
|
| | | overflow: hidden !important;
|
| | | text-overflow: ellipsis !important;
|
| | |
| | | }
|
| | |
|
| | | .el-menu-item .el-menu-tooltip__trigger {
|
| | | display: inline-block !important;
|
| | | display: inline-flex !important;
|
| | | width: 100%;
|
| | | align-items: center;
|
| | | }
|
| | |
|
| | | // menu hover |
| | | .submenu-title-noDropdown, |
| | | .el-sub-menu__title { |
| | | &:hover { |
| | | background-color: var(--menu-hover) !important; |
| | | border-radius: 14px; |
| | | } |
| | | } |
| | | & .theme-light .is-active > .el-sub-menu__title {
|
| | | color: var(--current-color) !important;
|
| | | .submenu-title-noDropdown,
|
| | | .el-sub-menu__title,
|
| | | .el-menu-item {
|
| | | min-width: 0 !important;
|
| | | width: calc(100% - 24px) !important;
|
| | | margin: 0 12px 8px !important;
|
| | | height: 50px;
|
| | | line-height: 50px;
|
| | | border-radius: 14px;
|
| | | padding-left: 16px !important;
|
| | | padding-right: 36px !important;
|
| | | box-sizing: border-box;
|
| | | transition: all 0.28s ease;
|
| | | color: var(--sidebar-text);
|
| | | background: linear-gradient(128deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.01));
|
| | | border: 1px solid rgba(255, 255, 255, 0.06) !important;
|
| | | position: relative;
|
| | | overflow: hidden;
|
| | | }
|
| | |
|
| | | & .nest-menu .el-sub-menu > .el-sub-menu__title, |
| | | & .el-sub-menu .el-menu-item { |
| | | min-width: 0 !important; |
| | | margin: 0 12px 6px; |
| | | width: calc(100% - 24px); |
| | | padding-left: 8px !important; |
| | | padding-right: 8px !important; |
| | | box-sizing: border-box; |
| | | |
| | | &:hover { |
| | | background-color: var(--menu-hover) !important; |
| | | } |
| | | &.is-active { |
| | | background-color: var(--menu-active-bg) !important; |
| | | border-radius: 14px; |
| | | } |
| | | } |
| | | .submenu-title-noDropdown::after,
|
| | | .el-sub-menu__title::after,
|
| | | .el-menu-item::after {
|
| | | content: "";
|
| | | position: absolute;
|
| | | inset: 0;
|
| | | background: linear-gradient(115deg, transparent 12%, rgba(255, 255, 255, 0.16), transparent 78%);
|
| | | transform: translateX(-100%);
|
| | | opacity: 0;
|
| | | transition: transform 0.45s ease, opacity 0.26s ease;
|
| | | pointer-events: none;
|
| | | }
|
| | |
|
| | | & .theme-light .nest-menu .el-sub-menu > .el-sub-menu__title, |
| | | & .theme-light .el-sub-menu .el-menu-item { |
| | | //background-color: transparent; |
| | | |
| | | &:hover { |
| | | background-color: var(--menu-hover) !important; |
| | | border-radius: 14px; |
| | | } |
| | | } |
| | | } |
| | | .submenu-title-noDropdown:hover,
|
| | | .el-sub-menu__title:hover,
|
| | | .el-menu-item:hover {
|
| | | background: linear-gradient(128deg, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.28), rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.08)) !important;
|
| | | border-color: rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.32) !important;
|
| | | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 8px 18px rgba(8, 36, 76, 0.24);
|
| | | transform: translateX(3px);
|
| | | }
|
| | |
|
| | | .hideSidebar { |
| | | .sidebar-container { |
| | | width: 68px !important; |
| | | padding-left: 0; |
| | | padding-right: 0; |
| | | } |
| | | |
| | | .main-container { |
| | | margin-left: 84px; |
| | | } |
| | | .submenu-title-noDropdown:hover::after,
|
| | | .el-sub-menu__title:hover::after,
|
| | | .el-menu-item:hover::after,
|
| | | .el-menu-item.is-active::after,
|
| | | .el-sub-menu.is-active > .el-sub-menu__title::after {
|
| | | transform: translateX(100%);
|
| | | opacity: 1;
|
| | | }
|
| | |
|
| | | .submenu-title-noDropdown { |
| | | padding: 0 !important; |
| | | position: relative; |
| | | display: flex !important; |
| | | align-items: center; |
| | | justify-content: center; |
| | | |
| | | .svg-icon { |
| | | margin-right: 0; |
| | | } |
| | | |
| | | .el-tooltip { |
| | | padding: 0 !important; |
| | | display: inline-flex !important; |
| | | align-items: center; |
| | | justify-content: center; |
| | | width: 100%; |
| | | |
| | | .svg-icon { |
| | | margin-left: 0; |
| | | } |
| | | } |
| | | |
| | | .el-menu-tooltip__trigger { |
| | | width: 100%; |
| | | display: inline-flex !important; |
| | | align-items: center; |
| | | justify-content: center; |
| | | |
| | | .svg-icon { |
| | | width: 18px; |
| | | height: 18px; |
| | | margin-right: 0; |
| | | flex-shrink: 0; |
| | | } |
| | | } |
| | | } |
| | | .el-sub-menu { |
| | | overflow: hidden; |
| | | |
| | | & > .el-sub-menu__title { |
| | | padding: 0 !important; |
| | | display: flex !important; |
| | | align-items: center; |
| | | justify-content: center; |
| | | |
| | | .svg-icon { |
| | | margin-left: 0; |
| | | margin-right: 0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .el-menu--collapse { |
| | | width: 100% !important; |
| | | padding: 10px 6px 18px; |
| | | |
| | | > .el-menu-item, |
| | | .el-sub-menu { |
| | | & > .el-sub-menu__title, |
| | | &.el-menu-item { |
| | | margin: 0 0 6px; |
| | | width: 100%; |
| | | padding-left: 0 !important; |
| | | padding-right: 0 !important; |
| | | box-sizing: border-box; |
| | | display: flex !important; |
| | | align-items: center; |
| | | justify-content: center; |
| | | |
| | | .svg-icon { |
| | | width: 18px; |
| | | height: 18px; |
| | | margin-right: 0; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | &:hover { |
| | | border-radius: 14px; |
| | | } |
| | | |
| | | & > span { |
| | | height: 0; |
| | | width: 0; |
| | | overflow: hidden; |
| | | visibility: hidden; |
| | | display: inline-block;
|
| | | & .theme-light .is-active > .el-sub-menu__title,
|
| | | & .theme-dark .is-active > .el-sub-menu__title,
|
| | | & .el-menu-item.is-active {
|
| | | color: #fff !important;
|
| | | background: var(--menu-active-bg, linear-gradient(135deg, var(--el-color-primary), var(--el-color-primary-light-3))) !important;
|
| | | background-size: 180% 180%;
|
| | | box-shadow: var(--menu-active-glow, 0 10px 24px rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.34));
|
| | | border-color: rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.5) !important;
|
| | | animation: sidebarActiveFlow 4.6s ease infinite;
|
| | | }
|
| | |
|
| | | & .nest-menu .el-sub-menu > .el-sub-menu__title,
|
| | | & .el-sub-menu .el-menu-item {
|
| | | min-width: 0 !important;
|
| | | width: calc(100% - 24px) !important;
|
| | | margin: 0 12px 8px !important;
|
| | | height: 46px;
|
| | | line-height: 46px;
|
| | | padding-left: 14px !important;
|
| | | padding-right: 14px !important;
|
| | | border-radius: 12px;
|
| | | transition: all 0.24s ease;
|
| | | color: var(--sidebar-text);
|
| | | border: 1px solid rgba(255, 255, 255, 0.06) !important;
|
| | | background: linear-gradient(128deg, rgba(255, 255, 255, 0.04), rgba(255, 255, 255, 0.01));
|
| | |
|
| | | &:hover {
|
| | | background: linear-gradient(128deg, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.24), rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.07)) !important;
|
| | | border-color: rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.3) !important;
|
| | | transform: translateX(2px);
|
| | | }
|
| | |
|
| | | &.is-active {
|
| | | background: var(--menu-active-bg, linear-gradient(135deg, var(--el-color-primary), var(--el-color-primary-light-3))) !important;
|
| | | background-size: 180% 180%;
|
| | | color: #fff !important;
|
| | | font-weight: 500;
|
| | | box-shadow: var(--menu-active-glow, 0 10px 24px rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.34));
|
| | | animation: sidebarActiveFlow 4.6s ease infinite;
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | .hideSidebar {
|
| | | .sidebar-container {
|
| | | width: var(--sidebar-collapsed-width) !important;
|
| | | }
|
| | |
|
| | | .main-container {
|
| | | margin-left: var(--sidebar-collapsed-width);
|
| | | }
|
| | |
|
| | | .submenu-title-noDropdown {
|
| | | padding: 0 !important;
|
| | | position: relative;
|
| | | display: flex !important;
|
| | | align-items: center;
|
| | | justify-content: center;
|
| | |
|
| | | .svg-icon {
|
| | | margin-right: 0;
|
| | | }
|
| | |
|
| | | .el-tooltip {
|
| | | padding: 0 !important;
|
| | | display: inline-flex !important;
|
| | | align-items: center;
|
| | | justify-content: center;
|
| | | width: 100%;
|
| | |
|
| | | .svg-icon {
|
| | | margin-left: 0;
|
| | | }
|
| | | }
|
| | |
|
| | | .el-menu-tooltip__trigger {
|
| | | width: 100%;
|
| | | display: inline-flex !important;
|
| | | align-items: center;
|
| | | justify-content: center;
|
| | |
|
| | | .svg-icon {
|
| | | width: 22px;
|
| | | height: 22px;
|
| | | margin-right: 0;
|
| | | flex-shrink: 0;
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | .el-sub-menu {
|
| | | overflow: hidden;
|
| | |
|
| | | & > .el-sub-menu__title {
|
| | | padding: 0 !important;
|
| | | display: flex !important;
|
| | | align-items: center;
|
| | | justify-content: center;
|
| | |
|
| | | .svg-icon {
|
| | | margin-left: 0;
|
| | | margin-right: 0;
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | .el-menu--collapse {
|
| | | width: 100% !important;
|
| | | padding: 12px 0 16px;
|
| | |
|
| | | > .el-menu-item,
|
| | | .el-sub-menu {
|
| | | & > .el-sub-menu__title,
|
| | | &.el-menu-item {
|
| | | width: calc(100% - 12px) !important;
|
| | | margin: 0 6px 8px !important;
|
| | | padding-left: 0 !important;
|
| | | padding-right: 0 !important;
|
| | | box-sizing: border-box;
|
| | | display: flex !important;
|
| | | align-items: center;
|
| | | justify-content: center;
|
| | |
|
| | | .svg-icon {
|
| | | width: 22px;
|
| | | height: 22px;
|
| | | margin-right: 0;
|
| | | flex-shrink: 0;
|
| | | }
|
| | | & > i {
|
| | |
|
| | | & > span {
|
| | | height: 0;
|
| | | width: 0;
|
| | | overflow: hidden;
|
| | | visibility: hidden;
|
| | | display: inline-block;
|
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
|
| | | .el-menu--collapse .el-menu .el-sub-menu {
|
| | | min-width: $base-sidebar-width !important;
|
| | | }
|
| | | }
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | // mobile responsive
|
| | | .el-menu--collapse .el-menu .el-sub-menu {
|
| | | min-width: var(--sidebar-width) !important;
|
| | | }
|
| | |
|
| | | .mobile {
|
| | | .main-container {
|
| | | margin-left: 0px;
|
| | | margin-left: 0;
|
| | | }
|
| | |
|
| | | .sidebar-container {
|
| | | transition: transform 0.28s;
|
| | | width: $base-sidebar-width !important;
|
| | | transition: transform 0.25s;
|
| | | width: var(--sidebar-width) !important;
|
| | | }
|
| | |
|
| | | &.hideSidebar {
|
| | | .sidebar-container {
|
| | | pointer-events: none;
|
| | | transition-duration: 0.3s;
|
| | | transform: translate3d(-$base-sidebar-width, 0, 0);
|
| | | transform: translate3d(calc(-1 * var(--sidebar-width)), 0, 0);
|
| | | }
|
| | | }
|
| | | }
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | // when menu collapsed
|
| | | .el-menu--vertical {
|
| | | & > .el-menu {
|
| | | .svg-icon {
|
| | | margin-right: 16px;
|
| | | margin-right: 10px;
|
| | | }
|
| | | }
|
| | |
|
| | | .nest-menu .el-sub-menu > .el-sub-menu__title, |
| | | .el-menu-item { |
| | | min-width: 0 !important; |
| | | margin: 0 12px 6px; |
| | | width: calc(100% - 24px); |
| | | padding-left: 8px !important; |
| | | padding-right: 8px !important; |
| | | box-sizing: border-box; |
| | | |
| | | &:hover { |
| | | // you can use $sub-menuHover |
| | | background-color: var(--menu-hover) !important; |
| | | } |
| | | &.is-active { |
| | | background-color: var(--menu-active-bg) !important; |
| | | border-radius: 14px; |
| | | } |
| | | } |
| | | .nest-menu .el-sub-menu > .el-sub-menu__title,
|
| | | .el-menu-item {
|
| | | min-width: 0 !important;
|
| | | margin: 0 10px 8px;
|
| | | width: calc(100% - 20px);
|
| | | height: 46px;
|
| | | line-height: 46px;
|
| | | padding-left: 12px !important;
|
| | | padding-right: 12px !important;
|
| | | box-sizing: border-box;
|
| | | border-radius: 12px;
|
| | | color: var(--sidebar-text);
|
| | | border: 1px solid rgba(255, 255, 255, 0.06) !important;
|
| | | background: linear-gradient(128deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.01));
|
| | | transition: all 0.24s ease;
|
| | |
|
| | | // the scroll bar appears when the sub-menu is too long
|
| | | &:hover {
|
| | | background: linear-gradient(128deg, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.24), rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.07)) !important;
|
| | | border-color: rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.3) !important;
|
| | | transform: translateX(2px);
|
| | | }
|
| | |
|
| | | &.is-active {
|
| | | background: var(--menu-active-bg, linear-gradient(135deg, var(--el-color-primary), var(--el-color-primary-light-3))) !important;
|
| | | background-size: 180% 180%;
|
| | | color: #fff !important;
|
| | | border-radius: 12px;
|
| | | box-shadow: var(--menu-active-glow, 0 10px 24px rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.34));
|
| | | border-color: rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.5) !important;
|
| | | animation: sidebarActiveFlow 4.6s ease infinite;
|
| | | }
|
| | | }
|
| | |
|
| | | > .el-menu--popup {
|
| | | max-height: 100vh;
|
| | | overflow-y: auto;
|
| | | padding: 8px;
|
| | | border-radius: 18px;
|
| | | border: 1px solid var(--surface-border);
|
| | | box-shadow: var(--shadow-md);
|
| | | overflow: hidden;
|
| | | padding: 10px;
|
| | | border-radius: 14px;
|
| | | position: relative;
|
| | | isolation: isolate;
|
| | | border: 1px solid rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.26);
|
| | | box-shadow:
|
| | | 0 18px 40px rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.16),
|
| | | var(--shadow-md);
|
| | | background: var(--sidebar-bg);
|
| | | backdrop-filter: blur(16px);
|
| | |
|
| | | &::-webkit-scrollbar-track-piece {
|
| | | background: #dfe7e1;
|
| | | &::before {
|
| | | content: "";
|
| | | position: absolute;
|
| | | inset: -28% -52% -18% -38%;
|
| | | z-index: 0;
|
| | | pointer-events: none;
|
| | | background:
|
| | | radial-gradient(circle at 9% 12%, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.62), transparent 44%),
|
| | | radial-gradient(circle at 87% 18%, rgba(56, 189, 248, 0.4), transparent 48%),
|
| | | radial-gradient(circle at 20% 82%, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.3), transparent 43%),
|
| | | radial-gradient(circle at 66% 62%, rgba(125, 211, 252, 0.24), transparent 50%),
|
| | | conic-gradient(
|
| | | from 210deg at 58% 38%,
|
| | | rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.14) 0deg,
|
| | | rgba(56, 189, 248, 0.05) 76deg,
|
| | | rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.16) 180deg,
|
| | | rgba(125, 211, 252, 0.04) 290deg,
|
| | | rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.14) 360deg
|
| | | );
|
| | | filter: blur(7px) saturate(1.24) contrast(1.05);
|
| | | opacity: 0.96;
|
| | | transform: translate3d(0, 0, 0);
|
| | | transform-origin: 44% 58%;
|
| | | animation:
|
| | | sidebarAuroraDrift 17.9s cubic-bezier(0.31, 0.03, 0.18, 0.99) infinite,
|
| | | sidebarAuroraBreath 9.7s ease-in-out infinite,
|
| | | sidebarAuroraSkew 6.9s steps(23, end) infinite;
|
| | | }
|
| | |
|
| | | &::-webkit-scrollbar {
|
| | | width: 6px;
|
| | | &::after {
|
| | | content: "";
|
| | | position: absolute;
|
| | | inset: 0;
|
| | | z-index: 0;
|
| | | pointer-events: none;
|
| | | background:
|
| | | linear-gradient(
|
| | | 108deg,
|
| | | transparent 10%,
|
| | | rgba(255, 255, 255, 0.17) 34%,
|
| | | rgba(255, 255, 255, 0.04) 48%,
|
| | | transparent 72%
|
| | | ),
|
| | | linear-gradient(
|
| | | 202deg,
|
| | | rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.24) 0%,
|
| | | transparent 34%,
|
| | | rgba(56, 189, 248, 0.18) 66%,
|
| | | transparent 100%
|
| | | ),
|
| | | radial-gradient(circle at 74% 12%, rgba(125, 211, 252, 0.25), transparent 50%),
|
| | | radial-gradient(circle at 22% 84%, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.14), transparent 56%);
|
| | | background-size: 236% 100%, 186% 186%, 164% 164%, 180% 180%;
|
| | | background-position: 224% 0, 14% 16%, 78% 10%, 18% 82%;
|
| | | opacity: 0.52;
|
| | | transform: translate3d(0, 0, 0);
|
| | | animation:
|
| | | sidebarSheenSweep 13.1s linear infinite,
|
| | | sidebarSheenJitter 4.7s steps(31, end) infinite;
|
| | | }
|
| | |
|
| | | &::-webkit-scrollbar-thumb {
|
| | | background: #9aa79e;
|
| | | border-radius: 20px;
|
| | | > * {
|
| | | position: relative;
|
| | | z-index: 1;
|
| | | }
|
| | |
|
| | | > .el-menu {
|
| | | max-height: calc(100vh - 20px);
|
| | | overflow-y: auto;
|
| | | overflow-x: hidden;
|
| | |
|
| | | &::-webkit-scrollbar-track-piece {
|
| | | background: var(--surface-muted);
|
| | | }
|
| | |
|
| | | &::-webkit-scrollbar {
|
| | | width: 5px;
|
| | | }
|
| | |
|
| | | &::-webkit-scrollbar-thumb {
|
| | | background: var(--accent-light);
|
| | | border-radius: 10px;
|
| | | }
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | @keyframes sidebarActiveFlow {
|
| | | 0% {
|
| | | background-position: 0% 50%;
|
| | | }
|
| | | 50% {
|
| | | background-position: 100% 50%;
|
| | | }
|
| | | 100% {
|
| | | background-position: 0% 50%;
|
| | | }
|
| | | }
|
| | |
|
| | | @keyframes sidebarAuroraDrift {
|
| | | 0% {
|
| | | transform: translate3d(-6.3%, -1.8%, 0) scale(1.05) rotate(-1.8deg);
|
| | | }
|
| | | 6% {
|
| | | transform: translate3d(2.2%, -4.6%, 0) scale(1.08) rotate(0.7deg);
|
| | | }
|
| | | 17% {
|
| | | transform: translate3d(-3.7%, 4.4%, 0) scale(1.11) rotate(2deg);
|
| | | }
|
| | | 27% {
|
| | | transform: translate3d(5.6%, 1.2%, 0) scale(1.03) rotate(-1deg);
|
| | | }
|
| | | 39% {
|
| | | transform: translate3d(-4.8%, -3.1%, 0) scale(1.09) rotate(1.5deg);
|
| | | }
|
| | | 52% {
|
| | | transform: translate3d(2.9%, 4.8%, 0) scale(1.04) rotate(-1.4deg);
|
| | | }
|
| | | 64% {
|
| | | transform: translate3d(-6.4%, 0.3%, 0) scale(1.08) rotate(0.5deg);
|
| | | }
|
| | | 73% {
|
| | | transform: translate3d(4.8%, -3.9%, 0) scale(1.05) rotate(1.6deg);
|
| | | }
|
| | | 81% {
|
| | | transform: translate3d(-2.4%, 2.9%, 0) scale(1.1) rotate(-0.8deg);
|
| | | }
|
| | | 92% {
|
| | | transform: translate3d(3.7%, -1.7%, 0) scale(1.06) rotate(-1.6deg);
|
| | | }
|
| | | 100% {
|
| | | transform: translate3d(-5.9%, 0.8%, 0) scale(1.08) rotate(1.2deg);
|
| | | }
|
| | | }
|
| | |
|
| | | @keyframes sidebarAuroraBreath {
|
| | | 0% {
|
| | | opacity: 0.76;
|
| | | filter: blur(5px) saturate(1.08);
|
| | | }
|
| | | 15% {
|
| | | opacity: 1;
|
| | | filter: blur(7px) saturate(1.28);
|
| | | }
|
| | | 37% {
|
| | | opacity: 0.84;
|
| | | filter: blur(8px) saturate(1.12);
|
| | | }
|
| | | 61% {
|
| | | opacity: 0.98;
|
| | | filter: blur(6px) saturate(1.24);
|
| | | }
|
| | | 83% {
|
| | | opacity: 0.86;
|
| | | filter: blur(7px) saturate(1.16);
|
| | | }
|
| | | 100% {
|
| | | opacity: 0.94;
|
| | | filter: blur(6px) saturate(1.2);
|
| | | }
|
| | | }
|
| | |
|
| | | @keyframes sidebarAuroraSkew {
|
| | | 0% {
|
| | | transform-origin: 44% 58%;
|
| | | }
|
| | | 21% {
|
| | | transform-origin: 62% 42%;
|
| | | }
|
| | | 43% {
|
| | | transform-origin: 31% 66%;
|
| | | }
|
| | | 66% {
|
| | | transform-origin: 68% 74%;
|
| | | }
|
| | | 100% {
|
| | | transform-origin: 39% 45%;
|
| | | }
|
| | | }
|
| | |
|
| | | @keyframes sidebarSheenSweep {
|
| | | 0% {
|
| | | background-position: 232% 0, 10% 18%, 80% 12%, 20% 82%;
|
| | | }
|
| | | 8% {
|
| | | background-position: 186% 0, 16% 30%, 74% 18%, 28% 74%;
|
| | | }
|
| | | 21% {
|
| | | background-position: 116% 0, 34% 10%, 62% 26%, 18% 64%;
|
| | | }
|
| | | 37% {
|
| | | background-position: 52% 0, 50% 24%, 46% 12%, 32% 58%;
|
| | | }
|
| | | 52% {
|
| | | background-position: -4% 0, 34% 54%, 22% 22%, 12% 46%;
|
| | | }
|
| | | 69% {
|
| | | background-position: -62% 0, 14% 36%, 32% 34%, 24% 56%;
|
| | | }
|
| | | 84% {
|
| | | background-position: -106% 0, 20% 20%, 46% 20%, 34% 70%;
|
| | | }
|
| | | 100% {
|
| | | background-position: -136% 0, 10% 18%, 80% 12%, 20% 82%;
|
| | | }
|
| | | }
|
| | |
|
| | | @keyframes sidebarSheenJitter {
|
| | | 0% {
|
| | | opacity: 0.28;
|
| | | transform: translate3d(0, 0, 0);
|
| | | }
|
| | | 17% {
|
| | | opacity: 0.56;
|
| | | transform: translate3d(1.8%, -0.5%, 0);
|
| | | }
|
| | | 38% {
|
| | | opacity: 0.34;
|
| | | transform: translate3d(-1.2%, 0.8%, 0);
|
| | | }
|
| | | 63% {
|
| | | opacity: 0.6;
|
| | | transform: translate3d(2.3%, -0.3%, 0);
|
| | | }
|
| | | 81% {
|
| | | opacity: 0.3;
|
| | | transform: translate3d(-1.6%, 0.7%, 0);
|
| | | }
|
| | | 100% {
|
| | | opacity: 0.52;
|
| | | transform: translate3d(2%, -0.1%, 0);
|
| | | }
|
| | | }
|
| | |
| | | $yellow: #fec171; |
| | | $panGreen: #30b08f; |
| | | |
| | | // menu palette |
| | | $menuText: #677287; |
| | | $menuActiveText: #1f7a72; |
| | | $menuBg: #f4f7f4; |
| | | $menuHover: #e7eeea; |
| | | // menu palette - 使ç¨ä¸»é¢è² |
| | | $menuText: #5a6478; |
| | | $menuActiveText: #ffffff; |
| | | $menuBg: #f8fafb; |
| | | $menuHover: rgba(var(--el-color-primary-rgb, 13, 148, 136), 0.08); |
| | | |
| | | // light theme |
| | | $menuLightBg: #f4f7f4; |
| | | $menuLightHover: #e7eeea; |
| | | $menuLightText: #3b4658; |
| | | $menuLightActiveText: #1f7a72; |
| | | // light theme - 使ç¨ä¸»é¢è² |
| | | $menuLightBg: #f8fafb; |
| | | $menuLightHover: rgba(var(--el-color-primary-rgb, 13, 148, 136), 0.08); |
| | | $menuLightText: #3d4858; |
| | | $menuLightActiveText: #ffffff; |
| | | |
| | | // layout |
| | | $base-sidebar-width: 216px; |
| | | $base-sidebar-collapsed-width: 72px; |
| | | $sideBarWidth: 216px; |
| | | |
| | | // sidebar |
| | | $base-menu-color: #677287; |
| | | $base-menu-color-active: #1f7a72; |
| | | $base-menu-background: #f4f7f4; |
| | | $base-sub-menu-background: #eef3ef; |
| | | // sidebar - ä¼ååçä¾§è¾¹æ é
è² |
| | | $base-menu-color: #5a6478; |
| | | $base-menu-color-active: #0d9488; |
| | | $base-menu-background: #f8fafb; |
| | | $base-sub-menu-background: #f0f5f4; |
| | | $base-sub-menu-hover: #ffffff; |
| | | |
| | | // component |
| | | $--color-primary: #1f7a72; |
| | | // component - ä¼ååç主é¢è² |
| | | $--color-primary: #0d9488; |
| | | $--color-success: #67c23a; |
| | | $--color-warning: #d89b41; |
| | | $--color-danger: #d25b52; |
| | |
| | | } |
| | | |
| | | :root { |
| | | --sidebar-bg: #{$menuBg}; |
| | | --sidebar-text: #{$menuText}; |
| | | --sidebar-muted: #93a0b1; |
| | | --menu-hover: #{$menuHover}; |
| | | --menu-active-bg: #dfe9e4; |
| | | --menu-surface: rgba(255, 255, 255, 0.72); |
| | | --sidebar-width: 216px; |
| | | --sidebar-collapsed-width: 72px; |
| | | --topbar-height: 64px; |
| | | --tagsbar-height: 40px; |
| | | --content-gap: 16px; |
| | | --content-radius: 16px; |
| | | --layout-header-z: 20; |
| | | |
| | | --app-bg: #eef2ee; |
| | | --app-bg-accent: #dfe8e2; |
| | | --surface-base: #ffffff; |
| | | --surface-soft: #f7faf8; |
| | | --surface-muted: #eff4f1; |
| | | --surface-border: #d8e1db; |
| | | --surface-border-strong: #c9d5ce; |
| | | --text-primary: #21313f; |
| | | --text-secondary: #5f6d7e; |
| | | --text-tertiary: #8a98a8; |
| | | --shadow-sm: 0 10px 30px rgba(31, 49, 38, 0.06); |
| | | --shadow-md: 0 18px 50px rgba(31, 49, 38, 0.1); |
| | | --radius-lg: 24px; |
| | | --radius-md: 18px; |
| | | --el-color-primary: #2563eb; |
| | | --el-color-primary-rgb: 37, 99, 235; |
| | | --el-color-success: #14b8a6; |
| | | --el-color-warning: #f59e0b; |
| | | --el-color-danger: #ef4444; |
| | | |
| | | --sidebar-bg: linear-gradient(180deg, #0e2a4f 0%, #123e69 55%, #0e2a4f 100%); |
| | | --sidebar-text: rgba(234, 242, 255, 0.82); |
| | | --sidebar-muted: rgba(234, 242, 255, 0.82); |
| | | --menu-hover: rgba(147, 197, 253, 0.2); |
| | | --menu-active-bg: linear-gradient(135deg, #2f80ff 0%, #38bdf8 100%); |
| | | --menu-active-text: #f8fbff; |
| | | --menu-surface: linear-gradient(180deg, rgba(13, 43, 79, 0.97) 0%, rgba(8, 28, 52, 0.94) 100%); |
| | | --menu-active-glow: 0 8px 18px rgba(56, 139, 255, 0.28); |
| | | |
| | | --app-bg: #f3f7fc; |
| | | --app-bg-accent: #eef5ff; |
| | | --surface-base: rgba(255, 255, 255, 0.92); |
| | | --surface-soft: rgba(255, 255, 255, 0.88); |
| | | --surface-muted: #f5f9ff; |
| | | --surface-border: rgba(148, 163, 184, 0.18); |
| | | --surface-border-strong: rgba(96, 165, 250, 0.34); |
| | | --text-primary: #1e293b; |
| | | --text-secondary: #334155; |
| | | --text-tertiary: #64748b; |
| | | --shadow-sm: 0 12px 32px rgba(15, 23, 42, 0.06); |
| | | --shadow-md: 0 20px 42px rgba(15, 23, 42, 0.1); |
| | | --shadow-menu: 0 16px 36px rgba(8, 27, 58, 0.26); |
| | | --radius-lg: 20px; |
| | | --radius-md: 16px; |
| | | --radius-sm: 12px; |
| | | --radius-xs: 10px; |
| | | |
| | | --navbar-bg: rgba(255, 255, 255, 0.78); |
| | | --navbar-text: #21313f; |
| | | --navbar-hover: rgba(31, 122, 114, 0.08); |
| | | --navbar-bg: rgba(255, 255, 255, 0.86); |
| | | --navbar-text: #1f3658; |
| | | --navbar-hover: rgba(37, 99, 235, 0.08); |
| | | |
| | | --tags-bg: transparent; |
| | | --tags-item-bg: rgba(255, 255, 255, 0.74); |
| | | --tags-item-border: rgba(201, 213, 206, 0.88); |
| | | --tags-item-text: #5f6d7e; |
| | | --tags-item-hover: rgba(31, 122, 114, 0.08); |
| | | --tags-close-hover: rgba(31, 122, 114, 0.18); |
| | | --tags-item-bg: rgba(255, 255, 255, 0.9); |
| | | --tags-item-border: rgba(148, 163, 184, 0.22); |
| | | --tags-item-text: #334155; |
| | | --tags-item-hover: #f4f8ff; |
| | | --tags-close-hover: rgba(37, 99, 235, 0.16); |
| | | |
| | | --splitpanes-default-bg: #ffffff; |
| | | --accent-primary: #2563eb; |
| | | --accent-light: #3b82f6; |
| | | --accent-lighter: #60a5fa; |
| | | |
| | | --panel-mask: rgba(255, 255, 255, 0.88); |
| | | --panel-glow: inset 0 1px 0 rgba(255, 255, 255, 0.58); |
| | | --splitpanes-default-bg: #f3f7fc; |
| | | } |
| | | |
| | | html.dark { |
| | | --el-bg-color: #141414; |
| | | --el-bg-color-overlay: #1d1e1f; |
| | | --el-text-color-primary: #ffffff; |
| | | --el-text-color-regular: #d0d0d0; |
| | | --el-border-color: #434343; |
| | | --el-border-color-light: #434343; |
| | | --el-bg-color: #f8fbff; |
| | | --el-bg-color-overlay: #f3f7fd; |
| | | --el-text-color-primary: #1e293b; |
| | | --el-text-color-regular: #475569; |
| | | --el-border-color: rgba(148, 163, 184, 0.2); |
| | | --el-border-color-light: rgba(148, 163, 184, 0.18); |
| | | |
| | | --sidebar-bg: #141414; |
| | | --sidebar-text: #ffffff; |
| | | --menu-hover: #2d2d2d; |
| | | --menu-active-text: #{$menuActiveText}; |
| | | --sidebar-bg: linear-gradient(180deg, #0e2a4f 0%, #123e69 55%, #0e2a4f 100%); |
| | | --sidebar-text: rgba(234, 242, 255, 0.82); |
| | | --sidebar-muted: rgba(234, 242, 255, 0.82); |
| | | --menu-hover: rgba(147, 197, 253, 0.2); |
| | | --menu-active-bg: linear-gradient(135deg, #2f80ff 0%, #38bdf8 100%); |
| | | --menu-active-text: #f8fbff; |
| | | --menu-surface: linear-gradient(180deg, rgba(13, 43, 79, 0.97) 0%, rgba(8, 28, 52, 0.94) 100%); |
| | | |
| | | --navbar-bg: #141414; |
| | | --navbar-text: #ffffff; |
| | | --navbar-hover: #141414; |
| | | --text-primary: #1e293b; |
| | | --text-secondary: #334155; |
| | | --text-tertiary: #64748b; |
| | | --accent-primary: #2563eb; |
| | | --accent-light: #3b82f6; |
| | | |
| | | --tags-bg: #141414; |
| | | --tags-item-bg: #1d1e1f; |
| | | --tags-item-border: #303030; |
| | | --tags-item-text: #d0d0d0; |
| | | --tags-item-hover: #2d2d2d; |
| | | --tags-close-hover: #64666a; |
| | | --navbar-bg: rgba(255, 255, 255, 0.86); |
| | | --navbar-text: #1f3658; |
| | | --navbar-hover: rgba(37, 99, 235, 0.08); |
| | | |
| | | --splitpanes-bg: #141414; |
| | | --splitpanes-border: #303030; |
| | | --splitpanes-splitter-bg: #1d1e1f; |
| | | --splitpanes-splitter-hover-bg: #2d2d2d; |
| | | --tags-bg: transparent; |
| | | --tags-item-bg: rgba(255, 255, 255, 0.9); |
| | | --tags-item-border: rgba(148, 163, 184, 0.22); |
| | | --tags-item-text: #334155; |
| | | --tags-item-hover: #f4f8ff; |
| | | --tags-close-hover: rgba(37, 99, 235, 0.16); |
| | | |
| | | --blockquote-bg: #1d1e1f; |
| | | --blockquote-border: #303030; |
| | | --blockquote-text: #d0d0d0; |
| | | --cron-border: #303030; |
| | | --splitpanes-default-bg: #141414; |
| | | --splitpanes-bg: #f3f7fc; |
| | | --splitpanes-border: rgba(148, 163, 184, 0.22); |
| | | --splitpanes-splitter-bg: #e7eef8; |
| | | --splitpanes-splitter-hover-bg: #d9e6f7; |
| | | |
| | | --blockquote-bg: #f3f7ff; |
| | | --blockquote-border: rgba(59, 130, 246, 0.36); |
| | | --blockquote-text: #334155; |
| | | --cron-border: rgba(148, 163, 184, 0.22); |
| | | --splitpanes-default-bg: #f3f7fc; |
| | | |
| | | .sidebar-container { |
| | | .el-menu-item, |
| | | .menu-title { |
| | | color: var(--el-text-color-regular); |
| | | color: var(--sidebar-text); |
| | | } |
| | | |
| | | .el-menu-item.is-active, |
| | | .el-menu-item.is-active .menu-title { |
| | | color: var(--menu-active-text) !important; |
| | | } |
| | | |
| | | & .theme-dark .nest-menu .el-sub-menu > .el-sub-menu__title, |
| | | & .theme-dark .el-sub-menu .el-menu-item { |
| | | background-color: var(--el-bg-color) !important; |
| | | } |
| | | |
| | | & .theme-dark .el-sub-menu .el-menu-item.is-active { |
| | | background-color: var(--menu-active-bg) !important; |
| | | } |
| | | } |
| | | |
| | | .el-menu--horizontal { |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import { Cpu } from '@element-plus/icons-vue' |
| | | |
| | | export const generalAssistant = { |
| | | key: 'general', |
| | | label: 'å¾
åå©ç', |
| | | title: 'å¾
åæºè½å©ç', |
| | | tooltip: 'å¾
å婿', |
| | | icon: Cpu, |
| | | apiBase: '/xiaozhi', |
| | | storageKey: 'ai_chat_uuid', |
| | | placeholder: '请è¾å
¥æ¨çé®é¢... (Enter åé, Shift+Enter æ¢è¡)', |
| | | welcomeMessage: 'ä½ å¥½', |
| | | description: 'æå¯ä»¥åçä½ çé®é¢ï¼ä¸ºä½ æä¾ä¸å¡æ°æ®è§£è¯»ä¿¡æ¯ãå¤ç建议åè¾
å©å³çæ¯æã', |
| | | allowFileUpload: true, |
| | | emptySessionText: 'ææ åå²ä¼è¯', |
| | | quickPrompts: [ |
| | | 'æå½åæåªäºå®¡æ¹å¾
åéè¦å¤çï¼', |
| | | '帮æååºä»å¤©æ°å¢ç审æ¹å¾
åã', |
| | | 'å½åå¾
æå®¡æ¹çåæ®ï¼ææ¶é´ååºååºæ¥ã', |
| | | 'æåèµ·ç审æ¹éï¼åªäºè¿å¨å¤çä¸ï¼', |
| | | 'æ¥è¯¢æµç¨ç¼å· XXX ç审æ¹è¯¦æ
ã', |
| | | 'æµç¨ç¼å· XXX ç°å¨å¡å¨åªä¸ªå®¡æ¹èç¹ï¼å½å审æ¹äººæ¯è°ï¼', |
| | | 'å¸®ææ¥çæµç¨ç¼å· XXX çå®¡æ¹æµè½¬è®°å½ã', |
| | | 'è¿7天æç审æ¹å¾
åç»è®¡æ
嵿乿 ·ï¼', |
| | | 'æ¬ææç审æ¹ä¸ï¼éè¿ã驳åãå¤çä¸åæå¤å°ï¼', |
| | | 'è¿30天åç±»åå®¡æ¹æ°éå叿¯ä»ä¹ï¼', |
| | | '帮æå®¡æ¹éè¿æµç¨ç¼å· XXXï¼å¤æ³¨âåæâã', |
| | | '帮æé©³åæµç¨ç¼å· XXXï¼å¤æ³¨â请补å
说æâã', |
| | | 'æ¤éæåå对æµç¨ç¼å· XXX çå®¡æ¹æä½ã', |
| | | '帮æä¿®æ¹æµç¨ç¼å· XXX ç夿³¨ä¸ºâ已补å
éä»¶âã', |
| | | 'å 餿åèµ·çæµç¨ç¼å· XXXã' |
| | | ] |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import { generalAssistant } from './generalAssistant' |
| | | import { purchaseAssistant } from './purchaseAssistant' |
| | | import { productionAssistant } from './productionAssistant' |
| | | import { salesAssistant } from './salesAssistant' |
| | | |
| | | export { generalAssistant, purchaseAssistant, productionAssistant, salesAssistant } |
| | | |
| | | export const assistantRegistry = { |
| | | general: generalAssistant, |
| | | sales: salesAssistant, |
| | | purchase: purchaseAssistant, |
| | | production: productionAssistant |
| | | } |
| | | |
| | | export const builtInAssistants = [generalAssistant, salesAssistant, purchaseAssistant, productionAssistant] |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import { Operation } from '@element-plus/icons-vue' |
| | | |
| | | export const productionAssistant = { |
| | | key: 'production', |
| | | label: 'ç产å©ç', |
| | | title: 'ç产æºè½å©ç', |
| | | tooltip: 'ç产æºè½å©æ', |
| | | icon: Operation, |
| | | apiBase: '/manufacturing-ai', |
| | | storageKey: 'production_ai_chat_uuid', |
| | | placeholder: '请è¾å
¥ç产ç¸å
³é®é¢... (Enter åé, Shift+Enter æ¢è¡)', |
| | | welcomeMessage: 'ä½ å¥½', |
| | | description: 'æå¯ä»¥å´ç»ç产ç°åºã计åãå·¥åã设å¤ãè´¨éãç©æãå¼å¸¸å¤çæä¾æ¥è¯¢ãé¢è¦ãåæååç建议ã', |
| | | allowFileUpload: false, |
| | | emptySessionText: 'ææ ç产ä¼è¯', |
| | | quickPrompts: [ |
| | | 'æ¥è¯¢æ¬æç产计å', |
| | | 'æ¥çæè¿10æ¡å·¥å', |
| | | 'æ¥è®¾å¤A-01çç»´ä¿®æ
åµ', |
| | | 'æ¥è´¨éä¸åæ ¼è®°å½', |
| | | 'æ¥ä½åºåç©æ', |
| | | 'æ¥è¿7天å¼å¸¸å¤ç', |
| | | 'çæå¶é é¢è¦çæ¿', |
| | | 'åææ¬æçäº§å®æçåå¼å¸¸ç', |
| | | 'ç»åºå·¥å龿å设å¤å¾
ä¿®çåç建议' |
| | | ] |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import { ShoppingCart } from '@element-plus/icons-vue' |
| | | |
| | | export const purchaseAssistant = { |
| | | key: 'purchase', |
| | | label: 'éè´å©ç', |
| | | title: 'éè´æºè½å©ç', |
| | | tooltip: 'éè´æºè½å©ç', |
| | | icon: ShoppingCart, |
| | | apiBase: '/purchase-ai', |
| | | storageKey: 'purchase_ai_chat_uuid', |
| | | placeholder: '请è¾å
¥éè´é®é¢... (Enter åé, Shift+Enter æ¢è¡)', |
| | | welcomeMessage: 'ä½ å¥½', |
| | | description: 'æå¯ä»¥åå©ä½ åæéè´è®¢åãå°è´§è¿åº¦ãä¾åºå表ç°å仿¬¾æ
åµï¼å¸®å©ä½ å¿«éå®ä½éè´å¼å¸¸ã', |
| | | allowFileUpload: true, |
| | | allowMultipleFileUpload: true, |
| | | fileAnalyzeUrl: '/purchase-ai/analyze-files', |
| | | emptySessionText: 'ææ éè´ä¼è¯', |
| | | quickPrompts: [ |
| | | 'æ¬æéè´é颿åååçç©ææåªäºï¼', |
| | | 'åªäºéè´è®¢åè¿æªå
¥åºï¼', |
| | | 'æè¿7天ä¾åºåå°è´§å¼å¸¸æåªäºï¼', |
| | | '帮æç»è®¡å¾
仿¬¾éè´åï¼', |
| | | 'ååºæ¬æéè´éè´§æ
åµ' |
| | | ] |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import { TrendCharts } from '@element-plus/icons-vue' |
| | | |
| | | export const salesAssistant = { |
| | | key: 'sales', |
| | | label: 'éå®å©æ', |
| | | title: 'é宿ºè½å©æ', |
| | | tooltip: 'é宿ºè½å©æ', |
| | | icon: TrendCharts, |
| | | apiBase: '/sales-ai', |
| | | storageKey: 'sales_ai_chat_uuid', |
| | | placeholder: '请è¾å
¥éå®ç¸å
³é®é¢... (Enter åé / Shift+Enter æ¢è¡)', |
| | | welcomeMessage: 'ä½ å¥½', |
| | | description: 'æå¯ä»¥åå©ä½ æ¥è¯¢å®¢æ·æ¡£æ¡ãé宿¥ä»·ãéå®å°è´¦ãéå®éè´§ã客æ·å¾æ¥ãåè´§å°è´¦ï¼å¹¶éç¹åæå®¢æ·æµå¤±é£é©å忬¾/æ¥ä»·çç¥ã', |
| | | allowFileUpload: false, |
| | | emptySessionText: 'ææ éå®ä¼è¯', |
| | | quickPrompts: [ |
| | | 'æ¥è¯¢ç§æµ·å®¢æ·æ¡£æ¡å10æ¡', |
| | | 'æ¥è¯¢å
¬æµ·å®¢æ·æ¡£æ¡', |
| | | 'æ¥è¯¢æ¬æé宿¥ä»·', |
| | | 'æ¥è¯¢æ¬æéå®å°è´¦', |
| | | 'æ¥è¯¢è¿30天éå®éè´§', |
| | | 'æ¥è¯¢è¿30天客æ·åæ¬¾å¾æ¥', |
| | | 'æ¥è¯¢æ¬æåè´§å°è´¦', |
| | | 'æ¥çé宿æ ç»è®¡', |
| | | '帮æåå®¢æ·æµå¤±é£é©åæï¼è¿30天ï¼å20æ¡', |
| | | 'çæåæ¬¾ä¸æ¥ä»·çç¥å»ºè®®ï¼ä¼å
é«é£é©å®¢æ·' |
| | | ] |
| | | } |
| | |
| | | <template> |
| | | <div class="ai-chat-sidebar-wrapper"> |
| | | <!-- æ¬æµ®å¾æ --> |
| | | <div class="ai-chat-trigger" @click="toggleSidebar" v-show="!visible"> |
| | | <div v-if="!hideTrigger" class="ai-chat-trigger" @click="toggleSidebar" v-show="!visible"> |
| | | <el-tooltip :content="currentAssistant.tooltip" placement="left"> |
| | | <div class="trigger-icon"> |
| | | <el-icon :size="30" color="#fff"><component :is="currentAssistant.icon" /></el-icon> |
| | | <el-icon :size="22" color="#fff"><component :is="currentAssistant.icon" /></el-icon> |
| | | </div> |
| | | </el-tooltip> |
| | | </div> |
| | |
| | | <!-- ä¾§è¾¹æ å¯¹è¯æ¡ --> |
| | | <el-drawer |
| | | v-model="visible" |
| | | :size="drawerSize" |
| | | direction="rtl" |
| | | :size="computedDrawerSize" |
| | | :direction="drawerDirection" |
| | | :with-header="true" |
| | | class="ai-chat-drawer" |
| | | :modal="false" |
| | | modal-class="ai-chat-overlay" |
| | | :show-close="false" |
| | | :append-to-body="false" |
| | | :close-on-press-escape="!hideTrigger" |
| | | :close-on-click-modal="!hideTrigger" |
| | | @close="handleClose" |
| | | > |
| | | <template #header> |
| | |
| | | <el-icon :size="18"><Plus /></el-icon> |
| | | </el-button> |
| | | </el-tooltip> |
| | | <div class="action-divider"></div> |
| | | <el-tooltip content="å
³é" placement="bottom"> |
| | | <el-button |
| | | v-if="headerExtraActionText" |
| | | link |
| | | class="header-action-btn header-action-btn--text" |
| | | @click="handleHeaderExtraAction" |
| | | > |
| | | {{ headerExtraActionText }} |
| | | </el-button> |
| | | <div v-if="!hideTrigger" class="action-divider"></div> |
| | | <el-tooltip v-if="!hideTrigger" content="å
³é" placement="bottom"> |
| | | <el-button link class="header-action-btn close-btn" @click="handleManualClose"> |
| | | <el-icon :size="18"><Close /></el-icon> |
| | | </el-button> |
| | |
| | | <div class="assistant-scan-ring"></div> |
| | | <div class="assistant-orbit assistant-orbit-a"></div> |
| | | <div class="assistant-orbit assistant-orbit-b"></div> |
| | | <div class="assistant-bot"> |
| | | <div class="assistant-bot-antenna assistant-bot-antenna-left"></div> |
| | | <div class="assistant-bot-antenna assistant-bot-antenna-right"></div> |
| | | <div class="assistant-bot-head"> |
| | | <div class="assistant-bot-head-glow"></div> |
| | | <div class="assistant-bot-eye assistant-bot-eye-left"></div> |
| | | <div class="assistant-bot-eye assistant-bot-eye-right"></div> |
| | | <div class="assistant-bot-mouth"></div> |
| | | </div> |
| | | <div class="assistant-bot-neck"></div> |
| | | <div class="assistant-bot-body"> |
| | | <div class="assistant-bot-core"> |
| | | <div class="assistant-bot-core-ring"></div> |
| | | <el-icon :size="22"><component :is="currentAssistant.icon" /></el-icon> |
| | | <div class="assistant-model-shell"> |
| | | <div class="assistant-model-cut"> |
| | | <img |
| | | v-if="currentAssistantAvatar" |
| | | class="assistant-model-img" |
| | | :src="currentAssistantAvatar" |
| | | :alt="currentAssistant.label" |
| | | /> |
| | | <div v-else class="assistant-model-fallback"> |
| | | <el-icon :size="30"><component :is="currentAssistant.icon" /></el-icon> |
| | | </div> |
| | | <div class="assistant-bot-arm assistant-bot-arm-left"></div> |
| | | <div class="assistant-bot-arm assistant-bot-arm-right"></div> |
| | | </div> |
| | | </div> |
| | | <div class="assistant-status"> |
| | |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-show="!hasMessages" class="hero-dot-grid" aria-hidden="true"> |
| | | <span v-for="dot in 28" :key="dot"></span> |
| | | </div> |
| | | |
| | | <div class="message-list" ref="messageListRef"> |
| | | <div |
| | | v-for="(message, index) in messages" |
| | |
| | | <div class="message-content"> |
| | | <!-- ææ¬å
容 --> |
| | | <div class="text-box" v-html="message.htmlContent"></div> |
| | | |
| | | <div v-if="message.localUploadFiles?.length" class="message-local-file-list"> |
| | | <div |
| | | v-for="(file, fileIndex) in message.localUploadFiles" |
| | | :key="`${file.previewId || file.name}-${fileIndex}`" |
| | | :class="['message-local-file-item', { clickable: !!file.accessUrl && !file.isImage }]" |
| | | @click="handleMessageFileClick(file)" |
| | | > |
| | | <el-image |
| | | v-if="file.isImage && file.previewUrl" |
| | | :src="file.previewUrl" |
| | | :preview-src-list="getImagePreviewList(message.localUploadFiles)" |
| | | :initial-index="getImagePreviewInitialIndex(message.localUploadFiles, file.previewUrl)" |
| | | :z-index="4000" |
| | | preview-teleported |
| | | fit="cover" |
| | | class="message-local-file-thumb" |
| | | /> |
| | | <el-icon v-else class="message-local-file-icon"><Document /></el-icon> |
| | | <div class="message-local-file-meta"> |
| | | <span |
| | | :class="['message-local-file-name', { clickable: !!file.accessUrl }]" |
| | | :title="file.name" |
| | | @click.stop="openMessageAttachment(file)" |
| | | > |
| | | {{ file.name }} |
| | | </span> |
| | | <small v-if="Number(file.size) > 0" class="message-local-file-size">{{ formatFileSize(file.size) }}</small> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- å¾è¡¨å
容 --> |
| | | <div v-if="message.chartOptions && message.chartRenderReady" class="charts-wrapper"> |
| | |
| | | </el-table> |
| | | </div> |
| | | |
| | | <!-- æåä¸å¨ç» --> |
| | | <div v-if="message.manufacturingData" class="manufacturing-card"> |
| | | <div class="manufacturing-card__title">{{ getManufacturingTypeLabel(message.type) }}</div> |
| | | |
| | | <div |
| | | v-if="message.manufacturingData.summaryEntries?.length || message.manufacturingData.coreMetrics?.length" |
| | | class="manufacturing-summary-grid" |
| | | > |
| | | <div |
| | | v-for="(entry, entryIndex) in message.manufacturingData.summaryEntries" |
| | | :key="`summary-${entry.key}-${entryIndex}`" |
| | | class="manufacturing-summary-item" |
| | | > |
| | | <span class="manufacturing-summary-label">{{ entry.label }}</span> |
| | | <strong class="manufacturing-summary-value">{{ entry.value }}</strong> |
| | | </div> |
| | | <div |
| | | v-for="(metric, metricIndex) in message.manufacturingData.coreMetrics" |
| | | :key="`core-${metric.key}-${metricIndex}`" |
| | | class="manufacturing-summary-item manufacturing-summary-item--core" |
| | | > |
| | | <span class="manufacturing-summary-label">{{ metric.label }}</span> |
| | | <strong class="manufacturing-summary-value">{{ metric.value }}</strong> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-if="message.manufacturingData.warningItems?.length" class="manufacturing-warning-list"> |
| | | <div |
| | | v-for="(warning, warningIndex) in message.manufacturingData.warningItems" |
| | | :key="`warning-${warning.title || warningIndex}`" |
| | | class="manufacturing-warning-item" |
| | | > |
| | | <div class="manufacturing-warning-item__head"> |
| | | <el-tag size="small" :type="getManufacturingWarningLevelType(warning.level)"> |
| | | {{ getManufacturingWarningLevelLabel(warning.level) }} |
| | | </el-tag> |
| | | <strong>{{ warning.title || `é¢è¦ ${warningIndex + 1}` }}</strong> |
| | | <span v-if="warning.count !== '' && warning.count !== null && warning.count !== undefined" class="manufacturing-warning-count"> |
| | | {{ warning.count }} |
| | | </span> |
| | | </div> |
| | | <p v-if="warning.detail" class="manufacturing-warning-detail">{{ warning.detail }}</p> |
| | | </div> |
| | | </div> |
| | | |
| | | <div |
| | | v-if="message.manufacturingData.listItems?.length && message.manufacturingData.columns?.length" |
| | | class="table-wrapper manufacturing-table-wrapper" |
| | | > |
| | | <el-table :data="message.manufacturingData.listItems" border stripe size="small" style="width: 100%"> |
| | | <el-table-column |
| | | v-for="col in message.manufacturingData.columns" |
| | | :key="col" |
| | | :label="getStructuredFieldLabel(col)" |
| | | min-width="140" |
| | | show-overflow-tooltip |
| | | > |
| | | <template #default="{ row }"> |
| | | {{ formatStructuredValue(row[col]) }} |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <div v-if="message.manufacturingData.actionCards?.length" class="manufacturing-action-list"> |
| | | <div |
| | | v-for="(card, cardIndex) in message.manufacturingData.actionCards" |
| | | :key="card.runtimeKey || `${card.code}-${card.targetApi}-${cardIndex}`" |
| | | class="manufacturing-action-card" |
| | | > |
| | | <div class="manufacturing-action-card__head"> |
| | | <strong>{{ card.name || `å¨ä½ ${cardIndex + 1}` }}</strong> |
| | | <el-tag size="small" type="info">{{ getNormalizedRequestMethod(card.method) }}</el-tag> |
| | | </div> |
| | | <div class="manufacturing-action-card__meta"> |
| | | <span>{{ card.code || '--' }}</span> |
| | | <span>{{ card.targetApi || '--' }}</span> |
| | | </div> |
| | | <p v-if="card.description" class="manufacturing-action-card__desc">{{ card.description }}</p> |
| | | <div v-if="card.requiredFields?.length" class="manufacturing-required-fields"> |
| | | <span>å¿
å¡«åæ®µ</span> |
| | | <el-tag |
| | | v-for="field in card.requiredFields" |
| | | :key="field" |
| | | size="small" |
| | | type="warning" |
| | | > |
| | | {{ getStructuredPathLabel(field) }} |
| | | </el-tag> |
| | | </div> |
| | | <el-input |
| | | v-model="card.payloadText" |
| | | type="textarea" |
| | | :rows="6" |
| | | resize="vertical" |
| | | :disabled="card.executing" |
| | | placeholder="请è¾å
¥ JSON 请æ±åæ°" |
| | | /> |
| | | <div class="manufacturing-action-footer"> |
| | | <span |
| | | v-if="card.executeResult" |
| | | :class="['manufacturing-action-result', card.executeError ? 'error' : 'success']" |
| | | > |
| | | {{ card.executeResult }} |
| | | </span> |
| | | <el-button |
| | | type="primary" |
| | | size="small" |
| | | :loading="card.executing" |
| | | @click="executeManufacturingAction(message, card, cardIndex)" |
| | | > |
| | | 确认并æ§è¡ |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-if="message.salesData" class="sales-structured-card"> |
| | | <div class="sales-structured-card__title">{{ getSalesTypeLabel(message.type) }}</div> |
| | | |
| | | <div v-if="message.salesData.summaryEntries?.length" class="sales-summary-grid"> |
| | | <div |
| | | v-for="(entry, entryIndex) in message.salesData.summaryEntries" |
| | | :key="`sales-summary-${entry.key}-${entryIndex}`" |
| | | class="sales-summary-item" |
| | | > |
| | | <span class="sales-summary-label">{{ entry.label }}</span> |
| | | <strong class="sales-summary-value">{{ entry.value }}</strong> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-if="message.type === 'sales_customer_churn_risk' && message.salesData.listItems?.length" class="sales-focus-list"> |
| | | <div |
| | | v-for="(item, itemIndex) in message.salesData.listItems" |
| | | :key="`risk-${item.customerName || itemIndex}`" |
| | | class="sales-focus-item" |
| | | > |
| | | <div class="sales-focus-item__head"> |
| | | <strong>{{ formatStructuredValue(item.customerName) }}</strong> |
| | | <div class="sales-focus-tags"> |
| | | <el-tag size="small" :type="getSalesLevelTagType(item.riskLevel)"> |
| | | {{ getSalesLevelLabel(item.riskLevel, 'risk') }} |
| | | </el-tag> |
| | | <el-tag size="small" type="warning">é£é©å {{ formatStructuredValue(item.riskScore) }}</el-tag> |
| | | </div> |
| | | </div> |
| | | <div class="sales-focus-metrics"> |
| | | <span>å¾
忬¾ï¼{{ formatStructuredValue(item.pendingAmount) }}</span> |
| | | <span>å¾
忬¾å æ¯ï¼{{ formatStructuredValue(item.pendingRate) }}</span> |
| | | <span>è·ä¸æ¬¡ä¸åï¼{{ formatStructuredValue(item.daysSinceLastOrder) }}</span> |
| | | </div> |
| | | <div v-if="toStructuredStringArray(item.riskReasons).length" class="sales-focus-reasons"> |
| | | <el-tag |
| | | v-for="(reason, reasonIndex) in toStructuredStringArray(item.riskReasons)" |
| | | :key="`${item.customerName || itemIndex}-reason-${reasonIndex}`" |
| | | size="small" |
| | | type="danger" |
| | | effect="plain" |
| | | > |
| | | {{ reason }} |
| | | </el-tag> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-if="message.type === 'sales_collection_quote_strategy' && message.salesData.listItems?.length" class="sales-focus-list"> |
| | | <div |
| | | v-for="(item, itemIndex) in message.salesData.listItems" |
| | | :key="`strategy-${item.customerName || itemIndex}`" |
| | | class="sales-focus-item sales-focus-item--strategy" |
| | | > |
| | | <div class="sales-focus-item__head"> |
| | | <strong>{{ formatStructuredValue(item.customerName) }}</strong> |
| | | <div class="sales-focus-tags"> |
| | | <el-tag size="small" :type="getSalesLevelTagType(item.priority)"> |
| | | {{ getSalesLevelLabel(item.priority, 'priority') }} |
| | | </el-tag> |
| | | <el-tag size="small" type="success">转åç {{ formatStructuredValue(item.quoteConversionRate) }}</el-tag> |
| | | </div> |
| | | </div> |
| | | <div class="sales-focus-metrics"> |
| | | <span>å¾
忬¾ï¼{{ formatStructuredValue(item.pendingAmount) }}</span> |
| | | <span v-if="item.nextAction">ä¸ä¸æ¥ï¼{{ formatStructuredValue(item.nextAction) }}</span> |
| | | </div> |
| | | <p v-if="item.collectionStrategy" class="sales-strategy-line"> |
| | | <strong>忬¾çç¥ï¼</strong>{{ formatStructuredValue(item.collectionStrategy) }} |
| | | </p> |
| | | <p v-if="item.quotationStrategy" class="sales-strategy-line"> |
| | | <strong>æ¥ä»·çç¥ï¼</strong>{{ formatStructuredValue(item.quotationStrategy) }} |
| | | </p> |
| | | </div> |
| | | </div> |
| | | |
| | | <div |
| | | v-if="message.salesData.listItems?.length && message.salesData.columns?.length && !isSalesFocusType(message.type)" |
| | | class="table-wrapper manufacturing-table-wrapper" |
| | | > |
| | | <el-table :data="message.salesData.listItems" border stripe size="small" style="width: 100%"> |
| | | <el-table-column |
| | | v-for="col in message.salesData.columns" |
| | | :key="col" |
| | | :label="getStructuredFieldLabel(col)" |
| | | min-width="140" |
| | | show-overflow-tooltip |
| | | > |
| | | <template #default="{ row }"> |
| | | {{ formatStructuredValue(row[col]) }} |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <div v-if="message.salesData.topCustomers?.length && message.salesData.topCustomerColumns?.length" class="table-wrapper manufacturing-table-wrapper"> |
| | | <div class="sales-section-title">éç¹å®¢æ·</div> |
| | | <el-table :data="message.salesData.topCustomers" border stripe size="small" style="width: 100%"> |
| | | <el-table-column |
| | | v-for="col in message.salesData.topCustomerColumns" |
| | | :key="`top-customer-${col}`" |
| | | :label="getStructuredFieldLabel(col)" |
| | | min-width="120" |
| | | show-overflow-tooltip |
| | | > |
| | | <template #default="{ row }"> |
| | | {{ formatStructuredValue(row[col]) }} |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <div v-if="message.salesData.contractTrend?.length && message.salesData.contractTrendColumns?.length" class="table-wrapper manufacturing-table-wrapper"> |
| | | <div class="sales-section-title">ååè¶å¿</div> |
| | | <el-table :data="message.salesData.contractTrend" border stripe size="small" style="width: 100%"> |
| | | <el-table-column |
| | | v-for="col in message.salesData.contractTrendColumns" |
| | | :key="`contract-trend-${col}`" |
| | | :label="getStructuredFieldLabel(col)" |
| | | min-width="120" |
| | | show-overflow-tooltip |
| | | > |
| | | <template #default="{ row }"> |
| | | {{ formatStructuredValue(row[col]) }} |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-if="message.purchaseData" class="sales-structured-card"> |
| | | <div class="sales-structured-card__title">{{ getPurchaseTypeLabel(message.type) }}</div> |
| | | |
| | | <div v-if="message.purchaseData.summaryEntries?.length" class="sales-summary-grid"> |
| | | <div |
| | | v-for="(entry, entryIndex) in message.purchaseData.summaryEntries" |
| | | :key="`purchase-summary-${entry.key}-${entryIndex}`" |
| | | class="sales-summary-item" |
| | | > |
| | | <span class="sales-summary-label">{{ entry.label }}</span> |
| | | <strong class="sales-summary-value">{{ entry.value }}</strong> |
| | | </div> |
| | | </div> |
| | | |
| | | <div |
| | | v-if="message.purchaseData.listItems?.length && message.purchaseData.columns?.length" |
| | | class="table-wrapper manufacturing-table-wrapper" |
| | | > |
| | | <el-table :data="message.purchaseData.listItems" border stripe size="small" style="width: 100%"> |
| | | <el-table-column |
| | | v-for="col in message.purchaseData.columns" |
| | | :key="col" |
| | | :label="getStructuredFieldLabel(col)" |
| | | min-width="140" |
| | | show-overflow-tooltip |
| | | > |
| | | <template #default="{ row }"> |
| | | {{ formatStructuredValue(row[col]) }} |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-if="message.purchaseIntentData?.quickPrompts?.length" class="purchase-intent-quick-prompt-wrap"> |
| | | <div class="purchase-intent-quick-prompt-title">è¯è¯ä»¥ä¸æé®</div> |
| | | <div class="quick-prompt-list purchase-intent-quick-prompt-list"> |
| | | <button |
| | | v-for="prompt in message.purchaseIntentData.quickPrompts" |
| | | :key="`purchase-intent-${prompt}`" |
| | | type="button" |
| | | class="quick-prompt-btn" |
| | | :disabled="isSending" |
| | | @click="sendQuickPrompt(prompt)" |
| | | > |
| | | {{ prompt }} |
| | | </button> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-if="message.purchaseAnalysisData" class="purchase-confirm-card"> |
| | | <div class="purchase-confirm-header"> |
| | | <span>{{ businessTypeLabelMap[message.purchaseAnalysisData.businessType] || message.purchaseAnalysisData.businessType || 'éè´ä¸å¡' }}</span> |
| | |
| | | </div> |
| | | <div class="input-box"> |
| | | <div v-if="selectedFiles.length" class="selected-file-list"> |
| | | <div v-for="(file, fileIndex) in selectedFiles" :key="`${file.name}-${fileIndex}`" class="selected-file-tag"> |
| | | <el-icon><Document /></el-icon> |
| | | <span class="file-name">{{ file.name }}</span> |
| | | <div v-for="(file, fileIndex) in selectedFileSnapshots" :key="`${file.previewId || file.name}-${fileIndex}`" class="selected-file-tag"> |
| | | <el-image |
| | | v-if="file.isImage && file.previewUrl" |
| | | :src="file.previewUrl" |
| | | :preview-src-list="getImagePreviewList(selectedFileSnapshots)" |
| | | :initial-index="getImagePreviewInitialIndex(selectedFileSnapshots, file.previewUrl)" |
| | | :z-index="4000" |
| | | preview-teleported |
| | | fit="cover" |
| | | class="selected-file-thumb" |
| | | /> |
| | | <el-icon v-else><Document /></el-icon> |
| | | <div class="selected-file-meta"> |
| | | <span class="file-name">{{ file.name }}</span> |
| | | <small class="file-size">{{ formatFileSize(file.size) }}</small> |
| | | </div> |
| | | <el-icon class="remove-file" @click="removeSelectedFile(fileIndex)"><Close /></el-icon> |
| | | </div> |
| | | </div> |
| | |
| | | import { ref, onMounted, onUnmounted, nextTick, watch, computed } from 'vue' |
| | | import request from '@/utils/request' |
| | | import * as echarts from 'echarts' |
| | | import { Cpu, User, Plus, Timer, Delete, ChatDotSquare, VideoPause, Upload, Document, Close, ShoppingCart, Promotion, RefreshRight } from '@element-plus/icons-vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import { Cpu, User, Plus, Timer, Delete, ChatDotSquare, VideoPause, Upload, Document, Close, Promotion, RefreshRight } from '@element-plus/icons-vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { builtInAssistants, generalAssistant } from './assistants' |
| | | import todoAssistantAvatar from '@/assets/AI/å¾
å婿.png' |
| | | import salesAssistantAvatar from '@/assets/AI/éå®å©æ.png' |
| | | import purchaseAssistantAvatar from '@/assets/AI/éè´å©æ.png' |
| | | import productionAssistantAvatar from '@/assets/AI/çäº§å©æ.png' |
| | | import financeAssistantAvatar from '@/assets/AI/è´¢å¡å©æ.png' |
| | | import bossAssistantAvatar from '@/assets/AI/å¾
å婿.png' |
| | | |
| | | const emit = defineEmits(['header-extra-action']) |
| | | |
| | | const props = defineProps({ |
| | | assistants: { |
| | |
| | | defaultAssistant: { |
| | | type: String, |
| | | default: '' |
| | | }, |
| | | hideTrigger: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | autoOpen: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | drawerSize: { |
| | | type: [String, Number], |
| | | default: '' |
| | | }, |
| | | drawerDirection: { |
| | | type: String, |
| | | default: 'rtl' |
| | | }, |
| | | headerExtraActionText: { |
| | | type: String, |
| | | default: '' |
| | | } |
| | | }) |
| | | |
| | | const builtInAssistants = [ |
| | | { |
| | | key: 'general', |
| | | label: 'å¾
åå©ç', |
| | | title: 'å¾
åæºè½å©ç', |
| | | tooltip: 'å¾
å婿', |
| | | icon: Cpu, |
| | | apiBase: '/xiaozhi', |
| | | storageKey: 'ai_chat_uuid', |
| | | placeholder: '请è¾å
¥æ¨çé®é¢... (Enter åé, Shift+Enter æ¢è¡)', |
| | | welcomeMessage: 'ä½ å¥½', |
| | | description: 'æå¯ä»¥åçä½ çé®é¢ï¼ä¸ºä½ æä¾ä¸å¡æ°æ®è§£è¯»ä¿¡æ¯ãå¤ç建议åè¾
å©å³çæ¯æã', |
| | | allowFileUpload: true, |
| | | emptySessionText: 'ææ åå²ä¼è¯' |
| | | }, |
| | | { |
| | | key: 'purchase', |
| | | label: 'éè´å©ç', |
| | | title: 'éè´æºè½å©ç', |
| | | tooltip: 'éè´æºè½å©ç', |
| | | icon: ShoppingCart, |
| | | apiBase: '/purchase-ai', |
| | | storageKey: 'purchase_ai_chat_uuid', |
| | | placeholder: '请è¾å
¥éè´é®é¢... (Enter åé, Shift+Enter æ¢è¡)', |
| | | welcomeMessage: 'ä½ å¥½', |
| | | description: 'æå¯ä»¥åå©ä½ åæéè´è®¢åãå°è´§è¿åº¦ãä¾åºå表ç°å仿¬¾æ
åµï¼å¸®å©ä½ å¿«éå®ä½éè´å¼å¸¸ã', |
| | | allowFileUpload: true, |
| | | allowMultipleFileUpload: true, |
| | | fileAnalyzeUrl: '/purchase-ai/analyze-files', |
| | | emptySessionText: 'ææ éè´ä¼è¯' |
| | | } |
| | | ] |
| | | |
| | | const hideTrigger = computed(() => props.hideTrigger) |
| | | const headerExtraActionText = computed(() => String(props.headerExtraActionText || '').trim()) |
| | | const drawerDirection = computed(() => (props.drawerDirection === 'ttb' || props.drawerDirection === 'btt' || props.drawerDirection === 'ltr' || props.drawerDirection === 'rtl') |
| | | ? props.drawerDirection |
| | | : 'rtl') |
| | | const assistants = computed(() => props.assistants?.length ? props.assistants : builtInAssistants) |
| | | const selectedAssistantKey = ref(props.defaultAssistant || assistants.value[0]?.key || 'general') |
| | | const currentAssistant = computed(() => assistants.value.find(item => item.key === selectedAssistantKey.value) || assistants.value[0] || builtInAssistants[0]) |
| | | const showAssistantSwitch = computed(() => assistants.value.length > 1) |
| | | const assistantQuickPromptMap = { |
| | | general: [ |
| | | 'æå½åæåªäºå®¡æ¹å¾
åéè¦å¤çï¼', |
| | | '帮æååºä»å¤©æ°å¢ç审æ¹å¾
åã', |
| | | 'å½åå¾
æå®¡æ¹çåæ®ï¼ææ¶é´ååºååºæ¥ã', |
| | | 'æåèµ·ç审æ¹éï¼åªäºè¿å¨å¤çä¸ï¼', |
| | | 'æ¥è¯¢æµç¨ç¼å· XXX ç审æ¹è¯¦æ
ã', |
| | | 'æµç¨ç¼å· XXX ç°å¨å¡å¨åªä¸ªå®¡æ¹èç¹ï¼å½å审æ¹äººæ¯è°ï¼', |
| | | 'å¸®ææ¥çæµç¨ç¼å· XXX çå®¡æ¹æµè½¬è®°å½ã', |
| | | 'è¿7天æç审æ¹å¾
åç»è®¡æ
嵿乿 ·ï¼', |
| | | 'æ¬ææç审æ¹ä¸ï¼éè¿ã驳åãå¤çä¸åæå¤å°ï¼', |
| | | 'è¿30天åç±»åå®¡æ¹æ°éå叿¯ä»ä¹ï¼', |
| | | '帮æå®¡æ¹éè¿æµç¨ç¼å· XXXï¼å¤æ³¨âåæâã', |
| | | '帮æé©³åæµç¨ç¼å· XXXï¼å¤æ³¨â请补å
说æâã', |
| | | 'æ¤éæåå对æµç¨ç¼å· XXX çå®¡æ¹æä½ã', |
| | | '帮æä¿®æ¹æµç¨ç¼å· XXX ç夿³¨ä¸ºâ已补å
éä»¶âã', |
| | | 'å 餿åèµ·çæµç¨ç¼å· XXXã' |
| | | ], |
| | | purchase: [ |
| | | 'æ¬æéè´é颿åååçç©ææåªäºï¼', |
| | | 'åªäºéè´è®¢åè¿æªå
¥åºï¼', |
| | | 'æè¿7天ä¾åºåå°è´§å¼å¸¸æåªäºï¼', |
| | | '帮æç»è®¡å¾
仿¬¾éè´å', |
| | | 'ååºæ¬æéè´éè´§æ
åµ' |
| | | ] |
| | | const assistantAvatarByKey = { |
| | | general: todoAssistantAvatar, |
| | | todo: todoAssistantAvatar, |
| | | purchase: purchaseAssistantAvatar, |
| | | sales: salesAssistantAvatar, |
| | | production: productionAssistantAvatar, |
| | | finance: financeAssistantAvatar, |
| | | boss: bossAssistantAvatar |
| | | } |
| | | const currentAssistantAvatar = computed(() => { |
| | | const assistant = currentAssistant.value || {} |
| | | return assistant.avatar || assistantAvatarByKey[assistant.key] || '' |
| | | }) |
| | | const showAssistantSwitch = computed(() => assistants.value.length > 1) |
| | | const quickPromptLimit = 3 |
| | | const quickPromptStart = ref(0) |
| | | const quickPrompts = computed(() => { |
| | |
| | | if (Array.isArray(assistant.quickPrompts) && assistant.quickPrompts.length) { |
| | | return assistant.quickPrompts |
| | | } |
| | | return assistantQuickPromptMap[assistant.key] || assistantQuickPromptMap.general |
| | | return generalAssistant.quickPrompts || [] |
| | | }) |
| | | const displayedQuickPrompts = computed(() => { |
| | | const prompts = quickPrompts.value || [] |
| | |
| | | |
| | | const visible = ref(false) |
| | | const windowWidth = ref(window.innerWidth) |
| | | const drawerSize = computed(() => { |
| | | const responsiveDrawerSize = computed(() => { |
| | | if (windowWidth.value < 768) return '100%' |
| | | if (windowWidth.value < 1200) return '50%' |
| | | return '50%' |
| | | }) |
| | | const computedDrawerSize = computed(() => props.drawerSize || responsiveDrawerSize.value) |
| | | const messageListRef = ref(null) |
| | | const isSending = ref(false) |
| | | const currentAbortController = ref(null) |
| | | const inputMessage = ref('') |
| | | const selectedFiles = ref([]) |
| | | const uploadFileList = ref([]) |
| | | const selectedFileSnapshots = ref([]) |
| | | const messages = ref([]) |
| | | const uuid = ref('') |
| | | const chartInstances = ref({}) |
| | |
| | | purchase_return_order: 'éè´éè´§å', |
| | | unknown: 'æªç¥éè´ä¸å¡' |
| | | } |
| | | const salesStructuredTypeSet = new Set([ |
| | | 'sales_customer_profile_list', |
| | | 'sales_quotation_list', |
| | | 'sales_ledger_list', |
| | | 'sales_return_list', |
| | | 'sales_customer_interaction_list', |
| | | 'sales_shipping_list', |
| | | 'sales_dashboard', |
| | | 'sales_customer_churn_risk', |
| | | 'sales_collection_quote_strategy' |
| | | ]) |
| | | const salesFocusTypeSet = new Set([ |
| | | 'sales_customer_churn_risk', |
| | | 'sales_collection_quote_strategy' |
| | | ]) |
| | | const salesTypeLabelMap = { |
| | | sales_customer_profile_list: 'å®¢æ·æ¡£æ¡', |
| | | sales_quotation_list: 'é宿¥ä»·', |
| | | sales_ledger_list: 'éå®å°è´¦', |
| | | sales_return_list: 'éå®éè´§', |
| | | sales_customer_interaction_list: '客æ·å¾æ¥', |
| | | sales_shipping_list: 'åè´§å°è´¦', |
| | | sales_dashboard: 'é宿æ ç»è®¡', |
| | | sales_customer_churn_risk: 'å®¢æ·æµå¤±é£é©åæ', |
| | | sales_collection_quote_strategy: '忬¾ä¸æ¥ä»·çç¥å»ºè®®' |
| | | } |
| | | const purchaseTypeLabelMap = { |
| | | purchase_material_rank: 'éè´ç©æé颿è¡', |
| | | purchase_pending_payment_list: 'å¾
仿¬¾éè´å' |
| | | } |
| | | const manufacturingStructuredTypeSet = new Set([ |
| | | 'manufacturing_site_snapshot', |
| | | 'manufacturing_plan_list', |
| | | 'manufacturing_workorder_list', |
| | | 'manufacturing_device_list', |
| | | 'manufacturing_device_repair_list', |
| | | 'manufacturing_quality_list', |
| | | 'manufacturing_material_list', |
| | | 'manufacturing_exception_list', |
| | | 'manufacturing_warning', |
| | | 'manufacturing_analysis', |
| | | 'manufacturing_action_plan' |
| | | ]) |
| | | const manufacturingListTypeSet = new Set([ |
| | | 'manufacturing_plan_list', |
| | | 'manufacturing_workorder_list', |
| | | 'manufacturing_device_list', |
| | | 'manufacturing_device_repair_list', |
| | | 'manufacturing_quality_list', |
| | | 'manufacturing_material_list', |
| | | 'manufacturing_exception_list' |
| | | ]) |
| | | const manufacturingTypeLabelMap = { |
| | | manufacturing_site_snapshot: 'ç产ç°åºæ¦è§', |
| | | manufacturing_plan_list: 'è®¡åæ¥è¯¢', |
| | | manufacturing_workorder_list: 'å·¥åæ¥è¯¢', |
| | | manufacturing_device_list: 'è®¾å¤æ¥è¯¢', |
| | | manufacturing_device_repair_list: '设å¤ç»´ä¿®è®°å½æ¥è¯¢', |
| | | manufacturing_quality_list: 'è´¨éæ¥è¯¢', |
| | | manufacturing_material_list: 'ç©ææ¥è¯¢', |
| | | manufacturing_exception_list: 'å¼å¸¸æ¥è¯¢', |
| | | manufacturing_warning: 'é¢è¦çæ¿', |
| | | manufacturing_analysis: 'ç»è¥åæ', |
| | | manufacturing_action_plan: 'åç建议' |
| | | } |
| | | const structuredFieldLabelMap = { |
| | | workOrderNo: 'å·¥åå·', |
| | | planEndTime: '计åç»ææ¶é´', |
| | | planStartTime: '计åå¼å§æ¶é´', |
| | | timeRange: 'æ¶é´èå´', |
| | | startDate: 'å¼å§æ¥æ', |
| | | endDate: 'ç»ææ¥æ', |
| | | warningCount: 'é¢è¦æ°é', |
| | | overduePlanCount: 'é¾æè®¡åæ°', |
| | | overdueWorkOrderCount: '龿工忰', |
| | | actionCount: '建议å¨ä½æ°', |
| | | qualityOpenCount: 'è´¨éå¾
å¤çæ°', |
| | | lowStockCount: 'ä½åºåæ°', |
| | | exceptionCount: 'å¼å¸¸æ°', |
| | | userId: 'ç¨æ·ID', |
| | | tenantId: 'ç§æ·ID', |
| | | status: 'ç¶æ', |
| | | deviceName: '设å¤åç§°', |
| | | deviceModel: '设å¤åå·', |
| | | pendingRepairCount: 'å¾
ç»´ä¿®æ°', |
| | | repairTime: 'ç»´ä¿®æ¶é´', |
| | | repairName: 'æ¥ä¿®äºº', |
| | | maintenanceName: '维修人å', |
| | | level: 'é¢è¦ç级', |
| | | title: 'æ é¢', |
| | | count: 'æ°é', |
| | | detail: '详æ
', |
| | | remark: '夿³¨', |
| | | createTime: 'å建æ¶é´', |
| | | updateTime: 'æ´æ°æ¶é´', |
| | | exceptionType: 'å¼å¸¸ç±»å', |
| | | materialName: 'ç©æåç§°', |
| | | stockQty: 'åºåé' |
| | | } |
| | | Object.assign(structuredFieldLabelMap, { |
| | | customerName: '客æ·åç§°', |
| | | riskLevel: 'é£é©ç级', |
| | | riskScore: 'é£é©è¯å', |
| | | riskReasons: 'é£é©åå ', |
| | | pendingAmount: 'å¾
忬¾éé¢', |
| | | pendingRate: 'å¾
忬¾å æ¯', |
| | | daysSinceLastOrder: 'è·ä¸æ¬¡ä¸å天æ°', |
| | | priority: 'ä¼å
级', |
| | | quoteConversionRate: 'æ¥ä»·è½¬åç', |
| | | collectionStrategy: '忬¾çç¥', |
| | | quotationStrategy: 'æ¥ä»·çç¥', |
| | | nextAction: 'ä¸ä¸æ¥å¨ä½', |
| | | contractAmountTotal: 'ååæ»é¢', |
| | | receivedAmountTotal: '已忬¾éé¢', |
| | | pendingAmountTotal: 'å¾
忬¾æ»é¢', |
| | | shipRate: 'åè´§ç', |
| | | pendingOrderCount: 'å¾
仿¬¾è®¢åæ°', |
| | | totalContractAmount: 'å¾
仿¬¾ååæ»é¢', |
| | | totalPaidAmount: '已仿¬¾æ»é¢', |
| | | totalPendingAmount: 'å¾
仿¬¾æ»é¢' |
| | | }) |
| | | const purchasePayloadFieldLabelMap = { |
| | | purchaseLedgers: 'éè´å°è´¦', |
| | | productData: '产åæç»', |
| | |
| | | isInspected: 'isInspected', |
| | | isChecked: 'isInspected' |
| | | } |
| | | const isPlainObject = (value) => value !== null && typeof value === 'object' && !Array.isArray(value) |
| | | |
| | | const stringifyStructuredPayload = (value, spaces = 2) => { |
| | | if (typeof value === 'string') return value |
| | | try { |
| | | return JSON.stringify(value ?? {}, null, spaces) |
| | | } catch (err) { |
| | | return '{}' |
| | | } |
| | | } |
| | | |
| | | const structuredFieldTokenLabelMap = { |
| | | time: 'æ¶é´', |
| | | range: 'èå´', |
| | | start: 'å¼å§', |
| | | end: 'ç»æ', |
| | | date: 'æ¥æ', |
| | | warning: 'é¢è¦', |
| | | overdue: '龿', |
| | | plan: '计å', |
| | | work: 'å·¥', |
| | | order: 'å', |
| | | workorder: 'å·¥å', |
| | | count: 'æ°é', |
| | | quality: 'è´¨é', |
| | | low: 'ä½', |
| | | stock: 'åºå', |
| | | exception: 'å¼å¸¸', |
| | | action: 'å¨ä½', |
| | | user: 'ç¨æ·', |
| | | tenant: 'ç§æ·', |
| | | id: 'ID', |
| | | no: 'ç¼å·', |
| | | number: 'ç¼å·', |
| | | code: 'ç¼ç ', |
| | | name: 'åç§°', |
| | | status: 'ç¶æ', |
| | | level: 'ç级', |
| | | title: 'æ é¢', |
| | | detail: '详æ
', |
| | | total: 'æ»æ°', |
| | | rate: 'æ¯ç', |
| | | type: 'ç±»å', |
| | | pending: 'å¾
', |
| | | repair: 'ç»´ä¿®', |
| | | device: '设å¤', |
| | | material: 'ç©æ' |
| | | } |
| | | |
| | | const convertStructuredFieldKeyToChinese = (fieldKey = '') => { |
| | | const key = String(fieldKey || '').trim() |
| | | if (!key) return '-' |
| | | if (structuredFieldLabelMap[key]) return structuredFieldLabelMap[key] |
| | | if (/[\u4e00-\u9fa5]/.test(key)) return key |
| | | |
| | | const rawTokens = key |
| | | .replace(/([a-z0-9])([A-Z])/g, '$1 $2') |
| | | .replace(/[_-]+/g, ' ') |
| | | .trim() |
| | | .split(/\s+/) |
| | | .filter(Boolean) |
| | | .map(token => token.toLowerCase()) |
| | | |
| | | if (!rawTokens.length) return 'åæ®µ' |
| | | |
| | | const mappedTokens = rawTokens |
| | | .map(token => structuredFieldTokenLabelMap[token] || '') |
| | | .filter(Boolean) |
| | | |
| | | if (mappedTokens.length) { |
| | | return mappedTokens.join('') |
| | | } |
| | | |
| | | return 'åæ®µ' |
| | | } |
| | | |
| | | const getStructuredFieldLabel = (fieldKey = '') => { |
| | | return convertStructuredFieldKeyToChinese(fieldKey) |
| | | } |
| | | |
| | | const getStructuredPathLabel = (fieldPath = '') => { |
| | | const path = String(fieldPath || '').trim() |
| | | if (!path) return '-' |
| | | |
| | | const segments = path |
| | | .replace(/\[(\d+)]/g, '.$1') |
| | | .split('.') |
| | | .filter(Boolean) |
| | | |
| | | if (!segments.length) return getStructuredFieldLabel(path) |
| | | |
| | | return segments.map((segment) => { |
| | | if (/^\d+$/.test(segment)) { |
| | | return `第${Number(segment) + 1}项` |
| | | } |
| | | return getStructuredFieldLabel(segment) |
| | | }).join(' / ') |
| | | } |
| | | |
| | | const formatStructuredValue = (value) => { |
| | | if (value === null || value === undefined || value === '') return '-' |
| | | if (Array.isArray(value)) { |
| | | const preview = value.slice(0, 3).map(item => formatStructuredValue(item)).join('ã') |
| | | return value.length > 3 ? `${preview} ç${value.length}项` : preview |
| | | } |
| | | if (isPlainObject(value)) return stringifyStructuredPayload(value, 0) |
| | | return String(value) |
| | | } |
| | | |
| | | const normalizeManufacturingSummaryEntries = (summary) => { |
| | | if (!isPlainObject(summary)) return [] |
| | | return Object.entries(summary) |
| | | .filter(([, value]) => value !== undefined && value !== null && `${value}`.trim() !== '') |
| | | .map(([key, value]) => ({ |
| | | key, |
| | | label: getStructuredFieldLabel(key), |
| | | value: formatStructuredValue(value) |
| | | })) |
| | | } |
| | | |
| | | const normalizeManufacturingCoreMetrics = (coreMetrics) => { |
| | | if (Array.isArray(coreMetrics)) { |
| | | return coreMetrics.map((item, index) => { |
| | | if (isPlainObject(item)) { |
| | | const label = item.label || item.name || item.key || `ææ ${index + 1}` |
| | | const metricValue = item.value ?? item.metricValue ?? item.data ?? '-' |
| | | const unit = item.unit ? ` ${item.unit}` : '' |
| | | return { |
| | | key: String(item.key || item.name || index), |
| | | label, |
| | | value: `${formatStructuredValue(metricValue)}${unit}`.trim() |
| | | } |
| | | } |
| | | return { |
| | | key: String(index), |
| | | label: `ææ ${index + 1}`, |
| | | value: formatStructuredValue(item) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | if (isPlainObject(coreMetrics)) { |
| | | return Object.entries(coreMetrics).map(([key, value]) => ({ |
| | | key, |
| | | label: getStructuredFieldLabel(key), |
| | | value: formatStructuredValue(value) |
| | | })) |
| | | } |
| | | |
| | | return [] |
| | | } |
| | | |
| | | const normalizeManufacturingWarningItems = (items = []) => { |
| | | if (!Array.isArray(items)) return [] |
| | | return items |
| | | .filter(item => isPlainObject(item)) |
| | | .map(item => ({ |
| | | level: String(item.level || '').toLowerCase(), |
| | | title: item.title || '', |
| | | count: item.count ?? '', |
| | | detail: item.detail ?? '' |
| | | })) |
| | | } |
| | | |
| | | const inferManufacturingColumns = (items = []) => { |
| | | if (!Array.isArray(items) || !items.length) return [] |
| | | const fieldSet = new Set() |
| | | items.forEach((item) => { |
| | | if (!isPlainObject(item)) return |
| | | Object.keys(item).forEach((key) => fieldSet.add(key)) |
| | | }) |
| | | return Array.from(fieldSet) |
| | | } |
| | | |
| | | const getManufacturingActionCardRuntimeKey = (card = {}, index = 0) => { |
| | | const code = String(card?.code || '').trim() |
| | | const api = String(card?.targetApi || '').trim() |
| | | const name = String(card?.name || '').trim() |
| | | return `${code}::${api}::${name}::${index}` |
| | | } |
| | | |
| | | const normalizeManufacturingActionCards = (actionCards = [], previousCards = []) => { |
| | | const previousMap = new Map() |
| | | if (Array.isArray(previousCards)) { |
| | | previousCards.forEach((card, index) => { |
| | | previousMap.set(getManufacturingActionCardRuntimeKey(card, index), card) |
| | | }) |
| | | } |
| | | |
| | | return (Array.isArray(actionCards) ? actionCards : []) |
| | | .filter(card => isPlainObject(card)) |
| | | .map((card, index) => { |
| | | const runtimeKey = getManufacturingActionCardRuntimeKey(card, index) |
| | | const previousCard = previousMap.get(runtimeKey) |
| | | const fallbackPayloadText = stringifyStructuredPayload(card.examplePayload, 2) |
| | | return { |
| | | ...card, |
| | | runtimeKey, |
| | | payloadText: previousCard?.payloadText ?? fallbackPayloadText, |
| | | executing: Boolean(previousCard?.executing), |
| | | executed: Boolean(previousCard?.executed), |
| | | executeResult: previousCard?.executeResult || '', |
| | | executeError: Boolean(previousCard?.executeError) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | const buildManufacturingStructuredData = (parsedData, previousData = null) => { |
| | | const type = String(parsedData?.type || '') |
| | | if (!manufacturingStructuredTypeSet.has(type)) return null |
| | | |
| | | const rawData = isPlainObject(parsedData?.data) ? parsedData.data : {} |
| | | const items = Array.isArray(rawData.items) ? rawData.items.filter(item => isPlainObject(item)) : [] |
| | | const warningItems = type === 'manufacturing_warning' ? normalizeManufacturingWarningItems(items) : [] |
| | | const listItems = manufacturingListTypeSet.has(type) ? items : [] |
| | | const actionCards = type === 'manufacturing_action_plan' |
| | | ? normalizeManufacturingActionCards(rawData.actionCards, previousData?.actionCards) |
| | | : [] |
| | | |
| | | return { |
| | | type, |
| | | summaryEntries: normalizeManufacturingSummaryEntries(parsedData?.summary), |
| | | coreMetrics: normalizeManufacturingCoreMetrics(rawData.coreMetrics), |
| | | listItems, |
| | | columns: inferManufacturingColumns(listItems), |
| | | warningItems, |
| | | actionCards |
| | | } |
| | | } |
| | | |
| | | const getManufacturingTypeLabel = (type = '') => manufacturingTypeLabelMap[String(type || '')] || 'å¶é ç»æ' |
| | | |
| | | const inferSalesColumns = (items = []) => { |
| | | if (!Array.isArray(items) || !items.length) return [] |
| | | const fieldSet = new Set() |
| | | items.forEach((item) => { |
| | | if (!isPlainObject(item)) return |
| | | Object.keys(item).forEach((key) => fieldSet.add(key)) |
| | | }) |
| | | return Array.from(fieldSet) |
| | | } |
| | | |
| | | const normalizeSalesListItems = (items) => { |
| | | if (!Array.isArray(items)) return [] |
| | | return items.filter(item => isPlainObject(item)) |
| | | } |
| | | |
| | | const buildSalesStructuredData = (parsedData) => { |
| | | const type = String(parsedData?.type || '') |
| | | if (!salesStructuredTypeSet.has(type)) return null |
| | | |
| | | const rawData = isPlainObject(parsedData?.data) ? parsedData.data : {} |
| | | const listItems = normalizeSalesListItems(rawData.items) |
| | | const topCustomers = normalizeSalesListItems(rawData.topCustomers) |
| | | const contractTrend = normalizeSalesListItems(rawData.contractTrend) |
| | | |
| | | return { |
| | | type, |
| | | summaryEntries: normalizeManufacturingSummaryEntries(parsedData?.summary), |
| | | listItems, |
| | | columns: inferSalesColumns(listItems), |
| | | topCustomers, |
| | | topCustomerColumns: inferSalesColumns(topCustomers), |
| | | contractTrend, |
| | | contractTrendColumns: inferSalesColumns(contractTrend) |
| | | } |
| | | } |
| | | |
| | | const getSalesTypeLabel = (type = '') => salesTypeLabelMap[String(type || '')] || 'é宿¥è¯¢ç»æ' |
| | | |
| | | const buildPurchaseStructuredData = (parsedData) => { |
| | | if (parsedData?.success !== true) return null |
| | | |
| | | const type = String(parsedData?.type || '') |
| | | if (!type.startsWith('purchase_')) return null |
| | | |
| | | const rawData = isPlainObject(parsedData?.data) ? parsedData.data : {} |
| | | const listItems = normalizeSalesListItems(rawData.items) |
| | | |
| | | return { |
| | | type, |
| | | summaryEntries: normalizeManufacturingSummaryEntries(parsedData?.summary), |
| | | listItems, |
| | | columns: inferSalesColumns(listItems) |
| | | } |
| | | } |
| | | |
| | | const getPurchaseTypeLabel = (type = '') => purchaseTypeLabelMap[String(type || '')] || 'éè´æ¥è¯¢ç»æ' |
| | | |
| | | const isSalesFocusType = (type = '') => salesFocusTypeSet.has(String(type || '')) |
| | | |
| | | const getSalesLevelTagType = (level = '') => { |
| | | const normalizedLevel = String(level || '').toLowerCase() |
| | | if (normalizedLevel === 'high') return 'danger' |
| | | if (normalizedLevel === 'medium') return 'warning' |
| | | if (normalizedLevel === 'low') return 'success' |
| | | return 'info' |
| | | } |
| | | |
| | | const getSalesLevelLabel = (level = '', mode = 'risk') => { |
| | | const normalizedLevel = String(level || '').toLowerCase() |
| | | const suffix = mode === 'priority' ? 'ä¼å
级' : 'é£é©' |
| | | if (normalizedLevel === 'high') return `é«${suffix}` |
| | | if (normalizedLevel === 'medium') return `ä¸${suffix}` |
| | | if (normalizedLevel === 'low') return `ä½${suffix}` |
| | | if (!normalizedLevel) return mode === 'priority' ? 'æªå级' : 'æªè¯ä¼°' |
| | | return normalizedLevel.toUpperCase() |
| | | } |
| | | |
| | | const toStructuredStringArray = (value) => { |
| | | if (Array.isArray(value)) { |
| | | return value.map(item => String(item || '').trim()).filter(Boolean) |
| | | } |
| | | if (typeof value === 'string') { |
| | | return value |
| | | .split(/[,\uFF0C\u3001;\uFF1B\n]/) |
| | | .map(item => item.trim()) |
| | | .filter(Boolean) |
| | | } |
| | | return [] |
| | | } |
| | | |
| | | const normalizePurchaseIntentNotRecognizedData = (parsedData) => { |
| | | if (String(parsedData?.type || '') !== 'purchase_intent_not_recognized') return null |
| | | const quickPrompts = toStructuredStringArray(parsedData?.data?.quickPrompts) |
| | | if (!quickPrompts.length) return null |
| | | return { quickPrompts } |
| | | } |
| | | |
| | | const getManufacturingWarningLevelType = (level = '') => { |
| | | const normalizedLevel = String(level || '').toLowerCase() |
| | | if (normalizedLevel === 'high') return 'danger' |
| | | if (normalizedLevel === 'medium') return 'warning' |
| | | return 'info' |
| | | } |
| | | |
| | | const getManufacturingWarningLevelLabel = (level = '') => { |
| | | const normalizedLevel = String(level || '').toLowerCase() |
| | | if (normalizedLevel === 'high') return 'é«' |
| | | if (normalizedLevel === 'medium') return 'ä¸' |
| | | return normalizedLevel ? normalizedLevel.toUpperCase() : 'ä¸è¬' |
| | | } |
| | | |
| | | const normalizeRequestMethod = (method = 'POST') => { |
| | | const normalized = String(method || 'POST').trim().toUpperCase() |
| | | if (['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(normalized)) return normalized |
| | | return 'POST' |
| | | } |
| | | |
| | | const getNormalizedRequestMethod = (method) => normalizeRequestMethod(method) |
| | | |
| | | const getPayloadValueByPath = (payload, fieldPath = '') => { |
| | | const normalizedPath = String(fieldPath || '').trim() |
| | | if (!normalizedPath || !isPlainObject(payload)) return undefined |
| | | |
| | | const pathSegments = normalizedPath |
| | | .replace(/\[(\d+)]/g, '.$1') |
| | | .split('.') |
| | | .filter(Boolean) |
| | | |
| | | return pathSegments.reduce((current, segment) => { |
| | | if (current === null || current === undefined) return undefined |
| | | if (!['object', 'function'].includes(typeof current)) return undefined |
| | | return current[segment] |
| | | }, payload) |
| | | } |
| | | |
| | | const getMissingRequiredFields = (requiredFields = [], payload = {}) => { |
| | | if (!Array.isArray(requiredFields) || !requiredFields.length) return [] |
| | | return requiredFields.filter((fieldPath) => { |
| | | const value = getPayloadValueByPath(payload, fieldPath) |
| | | return !hasMeaningfulPayloadValue(value) |
| | | }) |
| | | } |
| | | |
| | | const parseManufacturingActionPayload = (payloadText = '') => { |
| | | const text = String(payloadText ?? '').trim() |
| | | if (!text) return {} |
| | | return JSON.parse(text) |
| | | } |
| | | |
| | | const executeManufacturingAction = async (message, actionCard, cardIndex = 0) => { |
| | | if (!message?.manufacturingData || !actionCard || actionCard.executing) return |
| | | |
| | | const actionName = actionCard.name || `å¨ä½ ${cardIndex + 1}` |
| | | const targetApi = String(actionCard.targetApi || '').trim() |
| | | if (!targetApi) { |
| | | actionCard.executeError = true |
| | | actionCard.executeResult = 'ç¼ºå° targetApiï¼æ æ³æ§è¡å¨ä½' |
| | | return |
| | | } |
| | | |
| | | let payload = {} |
| | | try { |
| | | payload = parseManufacturingActionPayload(actionCard.payloadText) |
| | | } catch (err) { |
| | | actionCard.executeError = true |
| | | actionCard.executeResult = '请æ±åæ°ä¸æ¯åæ³ JSONï¼è¯·æ£æ¥åéè¯' |
| | | return |
| | | } |
| | | |
| | | const requiredFields = Array.isArray(actionCard.requiredFields) ? actionCard.requiredFields : [] |
| | | if (requiredFields.length && !isPlainObject(payload)) { |
| | | actionCard.executeError = true |
| | | actionCard.executeResult = 'å¿
å¡«åæ®µæ ¡éªå¤±è´¥ï¼è¯·æ±åæ°å¿
é¡»æ¯ JSON 对象' |
| | | return |
| | | } |
| | | |
| | | const missingFields = getMissingRequiredFields(requiredFields, payload) |
| | | if (missingFields.length) { |
| | | actionCard.executeError = true |
| | | const missingFieldLabels = missingFields.map(field => getStructuredPathLabel(field)) |
| | | actionCard.executeResult = `缺å°å¿
å¡«åæ®µï¼${missingFieldLabels.join('ã')}` |
| | | return |
| | | } |
| | | |
| | | try { |
| | | await ElMessageBox.confirm(`确认æ§è¡ã${actionName}ãåï¼`, 'æ§è¡ç¡®è®¤', { |
| | | confirmButtonText: '确认æ§è¡', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | }) |
| | | } catch (err) { |
| | | return |
| | | } |
| | | |
| | | actionCard.executing = true |
| | | actionCard.executeError = false |
| | | actionCard.executeResult = '' |
| | | |
| | | const method = normalizeRequestMethod(actionCard.method) |
| | | const requestConfig = { |
| | | url: targetApi, |
| | | method: method.toLowerCase() |
| | | } |
| | | |
| | | if (method === 'GET') { |
| | | requestConfig.params = payload |
| | | } else { |
| | | requestConfig.data = payload |
| | | } |
| | | |
| | | try { |
| | | const res = await request(requestConfig) |
| | | const successMsg = res?.msg || `${actionName}æ§è¡æå` |
| | | actionCard.executed = true |
| | | actionCard.executeError = false |
| | | actionCard.executeResult = successMsg |
| | | ElMessage.success(successMsg) |
| | | } catch (err) { |
| | | actionCard.executed = false |
| | | actionCard.executeError = true |
| | | actionCard.executeResult = err?.message || `${actionName}æ§è¡å¤±è´¥ï¼è¯·ç¨åéè¯` |
| | | } finally { |
| | | actionCard.executing = false |
| | | } |
| | | } |
| | | |
| | | // åå²ä¼è¯ç¸å
³ |
| | | const purchaseValueTypeOptions = [ |
| | |
| | | const showHistory = ref(false) |
| | | const sessions = ref([]) |
| | | const loadingSessions = ref(false) |
| | | |
| | | const isImageFileType = (fileType = '') => String(fileType || '').toLowerCase().startsWith('image/') |
| | | const imageFilePathPattern = /\.(png|jpe?g|gif|webp|bmp|svg)$/i |
| | | |
| | | const getPathnameFromFilePath = (filePath = '') => { |
| | | const rawPath = String(filePath || '').trim() |
| | | if (!rawPath) return '' |
| | | try { |
| | | const baseOrigin = typeof window !== 'undefined' ? window.location.origin : 'http://localhost' |
| | | return new URL(rawPath, baseOrigin).pathname || '' |
| | | } catch (err) { |
| | | return rawPath.split('?')[0] |
| | | } |
| | | } |
| | | |
| | | const isImageFilePath = (filePath = '') => { |
| | | const pathname = getPathnameFromFilePath(filePath).toLowerCase() |
| | | return imageFilePathPattern.test(pathname) |
| | | } |
| | | |
| | | const getHistoryFileName = (filePath = '', index = 0) => { |
| | | const pathname = getPathnameFromFilePath(filePath) |
| | | const fileName = pathname.split('/').filter(Boolean).pop() |
| | | if (!fileName) return `file-${index + 1}` |
| | | try { |
| | | return decodeURIComponent(fileName) |
| | | } catch (err) { |
| | | return fileName |
| | | } |
| | | } |
| | | |
| | | const getImagePreviewList = (files = []) => { |
| | | if (!Array.isArray(files)) return [] |
| | | return files |
| | | .filter(item => item?.isImage && item?.previewUrl) |
| | | .map(item => item.previewUrl) |
| | | } |
| | | |
| | | const getImagePreviewInitialIndex = (files = [], previewUrl = '') => { |
| | | const list = getImagePreviewList(files) |
| | | const index = list.indexOf(previewUrl) |
| | | return index >= 0 ? index : 0 |
| | | } |
| | | |
| | | const formatFileSize = (size) => { |
| | | const bytes = Number(size) |
| | | if (!Number.isFinite(bytes) || bytes <= 0) return '0 B' |
| | | if (bytes < 1024) return `${bytes} B` |
| | | if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1).replace(/\.0$/, '')} KB` |
| | | return `${(bytes / (1024 * 1024)).toFixed(1).replace(/\.0$/, '')} MB` |
| | | } |
| | | |
| | | const createLocalFileSnapshot = (file, index = 0) => { |
| | | const rawFile = typeof File !== 'undefined' && file instanceof File ? file : null |
| | | const fileType = rawFile?.type || '' |
| | | const isImage = isImageFileType(fileType) |
| | | const canCreateObjectURL = typeof URL !== 'undefined' && typeof URL.createObjectURL === 'function' |
| | | const previewUrl = isImage && rawFile && canCreateObjectURL ? URL.createObjectURL(rawFile) : '' |
| | | return { |
| | | previewId: `${rawFile?.name || 'file'}-${rawFile?.size || 0}-${rawFile?.lastModified || Date.now()}-${index}`, |
| | | name: rawFile?.name || `file-${index + 1}`, |
| | | size: rawFile?.size || 0, |
| | | type: fileType, |
| | | isImage, |
| | | previewUrl, |
| | | accessUrl: '', |
| | | rawFile, |
| | | isObjectUrl: !!previewUrl |
| | | } |
| | | } |
| | | |
| | | const createHistoryFileSnapshot = (filePath, memoryId = '', messageIndex = 0, fileIndex = 0) => { |
| | | const normalizedPath = String(filePath || '').trim() |
| | | if (!normalizedPath) return null |
| | | const isImage = isImageFilePath(normalizedPath) |
| | | return { |
| | | previewId: `${memoryId || 'history'}-${messageIndex}-${fileIndex}`, |
| | | name: getHistoryFileName(normalizedPath, fileIndex), |
| | | size: 0, |
| | | type: '', |
| | | isImage, |
| | | previewUrl: isImage ? normalizedPath : '', |
| | | accessUrl: normalizedPath, |
| | | rawFile: null, |
| | | isObjectUrl: false |
| | | } |
| | | } |
| | | |
| | | const revokeLocalFileSnapshots = (snapshots = []) => { |
| | | const canRevokeObjectURL = typeof URL !== 'undefined' && typeof URL.revokeObjectURL === 'function' |
| | | if (!canRevokeObjectURL) return |
| | | if (!Array.isArray(snapshots)) return |
| | | snapshots.forEach((snapshot) => { |
| | | if (snapshot?.isObjectUrl && snapshot?.previewUrl) { |
| | | URL.revokeObjectURL(snapshot.previewUrl) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | const mapHistoryFilePathsToSnapshots = (filePaths = [], memoryId = '', messageIndex = 0) => { |
| | | if (!Array.isArray(filePaths)) return [] |
| | | return filePaths |
| | | .map((filePath, fileIndex) => createHistoryFileSnapshot(filePath, memoryId, messageIndex, fileIndex)) |
| | | .filter(Boolean) |
| | | } |
| | | |
| | | const openMessageAttachment = (file) => { |
| | | const accessUrl = String(file?.accessUrl || '').trim() |
| | | if (!accessUrl) return |
| | | if (typeof window === 'undefined' || typeof window.open !== 'function') return |
| | | window.open(accessUrl, '_blank', 'noopener,noreferrer') |
| | | } |
| | | |
| | | const handleMessageFileClick = (file) => { |
| | | if (!file?.accessUrl || file?.isImage) return |
| | | openMessageAttachment(file) |
| | | } |
| | | |
| | | const revokeMessageLocalFileSnapshots = (messageList = []) => { |
| | | if (!Array.isArray(messageList)) return |
| | | messageList.forEach((msg) => { |
| | | if (Array.isArray(msg?.localUploadFiles)) { |
| | | revokeLocalFileSnapshots(msg.localUploadFiles) |
| | | msg.localUploadFiles = [] |
| | | } |
| | | }) |
| | | } |
| | | |
| | | const clearSelectedFiles = ({ releaseSnapshots = true } = {}) => { |
| | | if (releaseSnapshots) { |
| | | revokeLocalFileSnapshots(selectedFileSnapshots.value) |
| | | } |
| | | selectedFiles.value = [] |
| | | uploadFileList.value = [] |
| | | selectedFileSnapshots.value = [] |
| | | } |
| | | |
| | | const abortCurrentRequest = () => { |
| | | if (!currentAbortController.value) return |
| | |
| | | |
| | | const selectSession = async (session) => { |
| | | showHistory.value = false |
| | | clearSelectedFiles() |
| | | uuid.value = session.memoryId |
| | | localStorage.setItem(currentAssistant.value.storageKey, uuid.value) |
| | | |
| | |
| | | try { |
| | | const res = await request.get(`${currentAssistant.value.apiBase}/history/messages/${uuid.value}`) |
| | | if (res.code === 200) { |
| | | revokeMessageLocalFileSnapshots(messages.value) |
| | | disposeCharts() |
| | | messages.value = [] |
| | | const historyMsgs = res.data || [] |
| | |
| | | |
| | | const messageObj = { |
| | | isUser, |
| | | content: msg.content, |
| | | content: msg.content || '', |
| | | htmlContent: '', |
| | | isTyping: false, |
| | | chartOptions: null, |
| | |
| | | type: '', |
| | | tableData: null, |
| | | payloadTreeData: null, |
| | | payloadHiddenData: null |
| | | payloadHiddenData: null, |
| | | purchaseAnalysisData: null, |
| | | manufacturingData: null, |
| | | salesData: null, |
| | | purchaseData: null, |
| | | purchaseIntentData: null, |
| | | localUploadFiles: isUser ? mapHistoryFilePathsToSnapshots(msg.filePaths, uuid.value, idx) : [] |
| | | } |
| | | |
| | | messages.value.push(messageObj) |
| | |
| | | } |
| | | |
| | | // è§£æå岿¶æ¯ä¸ç JSON |
| | | const extracted = extractEmbeddedSuccessJson(msg.content) |
| | | const extracted = extractEmbeddedSuccessJson(msg.content || '') |
| | | if (extracted) { |
| | | applyStructuredMessageData(messageObj, extracted.data, botMsgIndex) |
| | | } |
| | | |
| | | updateOutputState(msg.content, botMsgIndex) |
| | | messageObj.htmlContent = convertStreamOutput(msg.content, botMsgIndex) |
| | | updateOutputState(msg.content || '', botMsgIndex) |
| | | messageObj.htmlContent = convertStreamOutput(msg.content || '', botMsgIndex) |
| | | } else { |
| | | messageObj.htmlContent = convertTextToHtml(msg.content) |
| | | messageObj.htmlContent = convertTextToHtml(msg.content || '') |
| | | } |
| | | }) |
| | | scrollToBottom() |
| | |
| | | } |
| | | |
| | | onMounted(() => { |
| | | initUUID() |
| | | // åå§æ¬¢è¿ |
| | | if (messages.value.length === 0) { |
| | | hello() |
| | | if (props.autoOpen) { |
| | | visible.value = true |
| | | } |
| | | initUUID() |
| | | window.addEventListener('resize', handleWindowResize) |
| | | }) |
| | | |
| | | onUnmounted(() => { |
| | | revokeMessageLocalFileSnapshots(messages.value) |
| | | clearSelectedFiles() |
| | | disposeCharts() |
| | | window.removeEventListener('resize', handleWindowResize) |
| | | }) |
| | |
| | | if (!prevKey || nextKey === prevKey) return |
| | | |
| | | abortCurrentRequest() |
| | | revokeMessageLocalFileSnapshots(messages.value) |
| | | disposeCharts() |
| | | messages.value = [] |
| | | outputState.value = {} |
| | | sessions.value = [] |
| | | showHistory.value = false |
| | | selectedFiles.value = [] |
| | | uploadFileList.value = [] |
| | | clearSelectedFiles() |
| | | inputMessage.value = '' |
| | | quickPromptStart.value = 0 |
| | | initUUID() |
| | | hello() |
| | | }) |
| | | |
| | | watch(() => props.defaultAssistant, (nextKey) => { |
| | | if (!nextKey || nextKey === selectedAssistantKey.value) return |
| | | if (!assistants.value.some(item => item.key === nextKey)) return |
| | | selectedAssistantKey.value = nextKey |
| | | }) |
| | | |
| | | watch(() => props.autoOpen, (nextValue) => { |
| | | if (nextValue) { |
| | | visible.value = true |
| | | } |
| | | }) |
| | | |
| | | const handleWindowResize = () => { |
| | | windowWidth.value = window.innerWidth |
| | | } |
| | | |
| | | const handleHeaderExtraAction = () => { |
| | | emit('header-extra-action') |
| | | } |
| | | |
| | | const toggleSidebar = () => { |
| | |
| | | } |
| | | |
| | | const handleClose = () => { |
| | | if (hideTrigger.value) return |
| | | visible.value = false |
| | | } |
| | | |
| | | const handleManualClose = () => { |
| | | if (hideTrigger.value) return |
| | | if (isSending.value) { |
| | | abortCurrentRequest() |
| | | } |
| | |
| | | uuid.value = storedUUID |
| | | } |
| | | |
| | | const hello = () => { |
| | | sendRequest(currentAssistant.value.welcomeMessage || 'ä½ å¥½') |
| | | } |
| | | |
| | | const newChat = () => { |
| | | revokeMessageLocalFileSnapshots(messages.value) |
| | | disposeCharts() |
| | | messages.value = [] |
| | | outputState.value = {} |
| | | sessions.value = [] |
| | | showHistory.value = false |
| | | selectedFiles.value = [] |
| | | uploadFileList.value = [] |
| | | clearSelectedFiles() |
| | | quickPromptStart.value = 0 |
| | | localStorage.removeItem(currentAssistant.value.storageKey) |
| | | initUUID() |
| | | hello() |
| | | } |
| | | |
| | | const handleNewChat = () => { |
| | |
| | | const candidate = text.slice(i, j + 1) |
| | | try { |
| | | const parsed = JSON.parse(candidate) |
| | | if (parsed?.success === true) { |
| | | if (typeof parsed?.success === 'boolean') { |
| | | return { |
| | | data: parsed, |
| | | startIdx: i, |
| | |
| | | } |
| | | |
| | | const applyStructuredMessageData = (messageObj, parsedData, msgIndex, shouldRenderCharts = true) => { |
| | | if (!messageObj || !parsedData?.success) return |
| | | const isPurchaseIntentNotRecognized = String(parsedData?.type || '') === 'purchase_intent_not_recognized' |
| | | if (!messageObj || (parsedData?.success !== true && !isPurchaseIntentNotRecognized)) return |
| | | |
| | | const previousManufacturingData = messageObj.manufacturingData |
| | | messageObj.type = parsedData.type || '' |
| | | messageObj.tableData = null |
| | | messageObj.purchaseAnalysisData = null |
| | | messageObj.manufacturingData = null |
| | | messageObj.salesData = null |
| | | messageObj.purchaseData = null |
| | | messageObj.purchaseIntentData = null |
| | | |
| | | if (isPurchaseIntentNotRecognized) { |
| | | messageObj.purchaseIntentData = normalizePurchaseIntentNotRecognizedData(parsedData) |
| | | messageObj.chartOptions = null |
| | | messageObj.chartRenderReady = false |
| | | return |
| | | } |
| | | |
| | | if (messageObj.type === 'todo_list' && parsedData.data) { |
| | | messageObj.tableData = parsedData.data |
| | | } |
| | | |
| | | const salesData = buildSalesStructuredData(parsedData) |
| | | if (salesData) { |
| | | messageObj.salesData = salesData |
| | | } |
| | | |
| | | const manufacturingData = buildManufacturingStructuredData(parsedData, previousManufacturingData) |
| | | if (manufacturingData) { |
| | | messageObj.manufacturingData = manufacturingData |
| | | } |
| | | |
| | | const purchaseData = buildPurchaseStructuredData(parsedData) |
| | | if (purchaseData) { |
| | | messageObj.purchaseData = purchaseData |
| | | } |
| | | |
| | | if (parsedData.action === 'confirm_required' && parsedData.businessType) { |
| | | messageObj.type = 'purchase_analysis_confirm' |
| | | messageObj.purchaseAnalysisData = parsedData |
| | | messageObj.manufacturingData = null |
| | | messageObj.salesData = null |
| | | messageObj.purchaseData = null |
| | | if (!Array.isArray(messageObj.payloadTreeData) || !messageObj.payloadTreeData.length) { |
| | | initializePurchasePayloadTree(messageObj, parsedData.payload || {}) |
| | | } |
| | |
| | | } |
| | | |
| | | return null |
| | | } |
| | | |
| | | const getStructuredFallbackText = (parsedData) => { |
| | | if (!parsedData) return 'æ£å¨ä¸ºæ¨å±ç¤ºåæç»æ...' |
| | | if (parsedData.type === 'todo_list') return 'å·²ä¸ºæ¨æ´ç好ç¸å
³æ°æ®ã' |
| | | if (parsedData.type === 'purchase_intent_not_recognized') return 'æªè¯å«å°å¯æ§è¡çéè´æ¥è¯¢æ¡ä»¶ï¼è¯·è¡¥å
æ¥è¯¢æ¡ä»¶ååè¯ã' |
| | | if (salesStructuredTypeSet.has(parsedData.type)) { |
| | | if (parsedData.type === 'sales_customer_churn_risk') return '已为æ¨çæå®¢æ·æµå¤±é£é©åæã' |
| | | if (parsedData.type === 'sales_collection_quote_strategy') return '已为æ¨çæåæ¬¾ä¸æ¥ä»·çç¥å»ºè®®ã' |
| | | if (parsedData.type === 'sales_dashboard') return '已为æ¨çæé宿æ ç»è®¡ã' |
| | | return 'å·²è¿åé宿¥è¯¢ç»æã' |
| | | } |
| | | if (manufacturingStructuredTypeSet.has(parsedData.type)) { |
| | | if (parsedData.type === 'manufacturing_action_plan') return '已为æ¨çæåç建议ï¼è¯·ç¡®è®¤å¨ä½åæ§è¡ã' |
| | | if (parsedData.type === 'manufacturing_warning') return '已为æ¨çæå¶é é¢è¦çæ¿ã' |
| | | if (parsedData.type === 'manufacturing_analysis') return '已为æ¨çæå¶é åæç»æã' |
| | | return 'å·²è¿åå¶é æ¥è¯¢ç»æã' |
| | | } |
| | | if (String(parsedData.type || '').startsWith('purchase_')) return 'å·²è¿åéè´æ¥è¯¢ç»æã' |
| | | if (parsedData.charts && Object.keys(parsedData.charts).length > 0) return '已为æ¨çæåæå¾è¡¨ã' |
| | | return 'æ£å¨ä¸ºæ¨å±ç¤ºåæç»æ...' |
| | | } |
| | | |
| | | const buildPurchaseMaterialRankCharts = (parsedData) => { |
| | |
| | | if (visibleValue === undefined || visibleValue === null) return clonePurchasePayloadValue(hiddenValue) |
| | | |
| | | if (Array.isArray(visibleValue) && Array.isArray(hiddenValue)) { |
| | | const maxLength = Math.max(visibleValue.length, hiddenValue.length) |
| | | const merged = [] |
| | | for (let i = 0; i < maxLength; i++) { |
| | | merged[i] = mergePurchasePayloadWithHidden(visibleValue[i], hiddenValue[i]) |
| | | } |
| | | return merged |
| | | return visibleValue.map((item, index) => mergePurchasePayloadWithHidden(item, hiddenValue[index])) |
| | | } |
| | | |
| | | if ( |
| | |
| | | '审æ¹ç¨æ·IDå表' |
| | | ]) |
| | | |
| | | const purchaseIntegerFieldKeys = new Set([ |
| | | 'id', |
| | | 'supplierId', |
| | | 'recorderId', |
| | | 'salesContractNoId', |
| | | 'salesLedgerId', |
| | | 'Type', |
| | | 'businessPersonId', |
| | | 'productId', |
| | | 'productModelId', |
| | | 'ticketRegistrationId', |
| | | 'type', |
| | | 'approvalStatus', |
| | | 'inventoryWarningQuantity' |
| | | ]) |
| | | |
| | | const purchaseDecimalFieldKeys = new Set([ |
| | | 'invoiceAmount', |
| | | 'contractAmount', |
| | | 'receiptPaymentAmount', |
| | | 'unReceiptPaymentAmount', |
| | | 'quantity', |
| | | 'taxRate', |
| | | 'taxInclusiveUnitPrice', |
| | | 'taxInclusiveTotalPrice', |
| | | 'taxExclusiveTotalPrice', |
| | | 'priceWithTax', |
| | | 'totalPriceWithTax' |
| | | ]) |
| | | |
| | | const purchaseBooleanFieldKeys = new Set([ |
| | | 'hasChildren', |
| | | 'isWhite', |
| | | 'isInspected', |
| | | 'isChecked' |
| | | ]) |
| | | |
| | | const purchaseStringFieldKeys = new Set([ |
| | | 'entryDateStart', |
| | | 'entryDateEnd', |
| | | 'purchaseContractNumber', |
| | | 'supplierName', |
| | | 'recorderName', |
| | | 'salesContractNo', |
| | | 'projectName', |
| | | 'entryDate', |
| | | 'executionDate', |
| | | 'remarks', |
| | | 'attachmentMaterials', |
| | | 'createdAt', |
| | | 'updatedAt', |
| | | 'phoneNumber', |
| | | 'invoiceNumber', |
| | | 'paymentMethod', |
| | | 'templateName', |
| | | 'productCategory', |
| | | 'specificationModel', |
| | | 'unit', |
| | | 'invoiceType' |
| | | ]) |
| | | |
| | | const purchaseGenericArrayFieldKeys = new Set([ |
| | | 'purchaseLedgers', |
| | | 'productData' |
| | | ]) |
| | | |
| | | const purchaseStringArrayFieldKeys = new Set(['tempFileIds']) |
| | | |
| | | const purchaseObjectArrayFieldKeys = new Set(['SalesLedgerFiles']) |
| | | |
| | | const normalizePurchaseProductRecord = (record) => { |
| | | if (!record || typeof record !== 'object' || Array.isArray(record)) return record |
| | | return mapPayloadKeys(record, purchasePayloadFieldKeyMap) |
| | |
| | | '' |
| | | } |
| | | |
| | | const prunePurchaseProductRecord = (record) => { |
| | | if (!record || typeof record !== 'object' || Array.isArray(record)) return null |
| | | const normalizedRecord = normalizePurchaseProductRecord(record) |
| | | const hasVisibleFieldValue = Object.entries(normalizedRecord).some(([key, value]) => { |
| | | if (shouldHidePurchaseField(key)) return false |
| | | return hasMeaningfulPayloadValue(value) |
| | | }) |
| | | return hasVisibleFieldValue ? normalizedRecord : null |
| | | } |
| | | |
| | | const normalizeAndFilterPurchaseProductData = (value) => { |
| | | if (!Array.isArray(value)) return value |
| | | return value |
| | | .map(item => prunePurchaseProductRecord(item)) |
| | | .filter(Boolean) |
| | | } |
| | | |
| | | const mergeLegacyProductDataIntoLedgers = (payload) => { |
| | | if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return payload |
| | | if (!Array.isArray(payload.purchaseLedgers) || !Array.isArray(payload.productData) || !payload.productData.length) { |
| | |
| | | |
| | | const ledgers = payload.purchaseLedgers.map(ledger => ({ |
| | | ...ledger, |
| | | productData: Array.isArray(ledger.productData) |
| | | ? ledger.productData.map(normalizePurchaseProductRecord) |
| | | : [] |
| | | productData: normalizeAndFilterPurchaseProductData(ledger.productData) || [] |
| | | })) |
| | | const unmatchedProducts = [] |
| | | |
| | | payload.productData.map(normalizePurchaseProductRecord).forEach(product => { |
| | | normalizeAndFilterPurchaseProductData(payload.productData).forEach(product => { |
| | | const productMatchKey = getPurchaseProductMatchKey(product) |
| | | const matchedLedger = ledgers.find(ledger => { |
| | | const ledgerKeys = [ |
| | |
| | | if (!record || typeof record !== 'object' || Array.isArray(record)) return record |
| | | const normalizedRecord = { |
| | | ...record, |
| | | productData: Array.isArray(record.productData) |
| | | ? record.productData.map(normalizePurchaseProductRecord) |
| | | : record.productData |
| | | productData: normalizeAndFilterPurchaseProductData(record.productData) |
| | | } |
| | | return Object.entries(normalizedRecord).reduce((result, [key, value]) => { |
| | | if (purchaseLedgerAllowedFieldKeys.has(key)) { |
| | |
| | | }, {}) |
| | | } |
| | | |
| | | const normalizeAttachmentMaterialsValue = (value) => { |
| | | if (value === null || value === undefined) return value |
| | | if (typeof value === 'string') return value |
| | | if (typeof value === 'number' || typeof value === 'boolean') return String(value) |
| | | try { |
| | | return JSON.stringify(value) |
| | | } catch (err) { |
| | | return String(value) |
| | | } |
| | | } |
| | | |
| | | const normalizePurchaseAttachmentMaterialsField = (value) => { |
| | | if (Array.isArray(value)) { |
| | | return value.map(item => normalizePurchaseAttachmentMaterialsField(item)) |
| | | } |
| | | if (value && typeof value === 'object') { |
| | | return Object.entries(value).reduce((result, [key, item]) => { |
| | | if (key === 'attachmentMaterials') { |
| | | result[key] = normalizeAttachmentMaterialsValue(item) |
| | | } else { |
| | | result[key] = normalizePurchaseAttachmentMaterialsField(item) |
| | | } |
| | | return result |
| | | }, {}) |
| | | } |
| | | return value |
| | | } |
| | | |
| | | const normalizePurchaseNumericText = (text = '') => { |
| | | return String(text) |
| | | .replace(/[,\sï¼]/g, '') |
| | | .replace(/[¥¥å
%]/g, '') |
| | | } |
| | | |
| | | const parsePurchaseNumberValue = (value) => { |
| | | if (typeof value === 'number') { |
| | | return Number.isFinite(value) ? value : null |
| | | } |
| | | if (typeof value === 'boolean') { |
| | | return value ? 1 : 0 |
| | | } |
| | | if (typeof value !== 'string') { |
| | | return null |
| | | } |
| | | const text = normalizePurchaseNumericText(value.trim()) |
| | | if (!text) return null |
| | | if (!/^[-+]?\d+(\.\d+)?$/.test(text)) return null |
| | | const numberValue = Number(text) |
| | | return Number.isFinite(numberValue) ? numberValue : null |
| | | } |
| | | |
| | | const normalizePurchaseIntegerFieldValue = (value) => { |
| | | if (value === null || value === undefined) return value |
| | | if (value === '') return null |
| | | const numberValue = parsePurchaseNumberValue(value) |
| | | if (numberValue === null) return null |
| | | return Math.trunc(numberValue) |
| | | } |
| | | |
| | | const normalizePurchaseDecimalFieldValue = (value) => { |
| | | if (value === null || value === undefined) return value |
| | | if (value === '') return null |
| | | const numberValue = parsePurchaseNumberValue(value) |
| | | return numberValue === null ? null : numberValue |
| | | } |
| | | |
| | | const normalizePurchaseBooleanFieldValue = (value) => { |
| | | if (value === null || value === undefined) return value |
| | | if (value === '') return null |
| | | if (typeof value === 'boolean') return value |
| | | if (typeof value === 'number') return value !== 0 |
| | | if (typeof value !== 'string') return null |
| | | |
| | | const text = value.trim().toLowerCase() |
| | | if (!text) return null |
| | | if (['true', '1', 'yes', 'y', 'æ¯', 'å·²', 'checked'].includes(text)) return true |
| | | if (['false', '0', 'no', 'n', 'å¦', 'æª', 'unchecked'].includes(text)) return false |
| | | return null |
| | | } |
| | | |
| | | const normalizePurchaseStringFieldValue = (value) => { |
| | | if (value === null || value === undefined) return value |
| | | if (typeof value === 'string') return value |
| | | if (typeof value === 'number' || typeof value === 'boolean') return String(value) |
| | | try { |
| | | return JSON.stringify(value) |
| | | } catch (err) { |
| | | return String(value) |
| | | } |
| | | } |
| | | |
| | | const normalizePurchaseStringArrayFieldValue = (value) => { |
| | | if (Array.isArray(value)) { |
| | | return value |
| | | .map(item => normalizePurchaseStringFieldValue(item)) |
| | | .filter(item => item !== null && item !== undefined && item !== '') |
| | | } |
| | | if (value === null || value === undefined || value === '') return [] |
| | | if (typeof value === 'string') { |
| | | const text = value.trim() |
| | | if (!text) return [] |
| | | if (/^\[.*\]$/.test(text)) { |
| | | try { |
| | | const parsedValue = JSON.parse(text) |
| | | if (Array.isArray(parsedValue)) { |
| | | return parsedValue |
| | | .map(item => normalizePurchaseStringFieldValue(item)) |
| | | .filter(item => item !== null && item !== undefined && item !== '') |
| | | } |
| | | } catch (err) { |
| | | // Keep as plain text when not valid JSON array. |
| | | } |
| | | } |
| | | const splitValues = text |
| | | .split(/[,\nï¼]/) |
| | | .map(item => item.trim()) |
| | | .filter(Boolean) |
| | | return splitValues.length > 1 ? splitValues : [text] |
| | | } |
| | | const normalizedValue = normalizePurchaseStringFieldValue(value) |
| | | return normalizedValue === null || normalizedValue === undefined || normalizedValue === '' |
| | | ? [] |
| | | : [normalizedValue] |
| | | } |
| | | |
| | | const normalizePurchaseObjectArrayFieldValue = (value) => { |
| | | if (Array.isArray(value)) { |
| | | return value.filter(item => item && typeof item === 'object') |
| | | } |
| | | if (value && typeof value === 'object') { |
| | | return [value] |
| | | } |
| | | return [] |
| | | } |
| | | |
| | | const normalizePurchaseValueByFieldKey = (fieldKey, value) => { |
| | | if (fieldKey === 'attachmentMaterials') return normalizeAttachmentMaterialsValue(value) |
| | | if (purchaseIntegerFieldKeys.has(fieldKey)) return normalizePurchaseIntegerFieldValue(value) |
| | | if (purchaseDecimalFieldKeys.has(fieldKey)) return normalizePurchaseDecimalFieldValue(value) |
| | | if (purchaseBooleanFieldKeys.has(fieldKey)) return normalizePurchaseBooleanFieldValue(value) |
| | | if (purchaseStringArrayFieldKeys.has(fieldKey)) return normalizePurchaseStringArrayFieldValue(value) |
| | | if (purchaseObjectArrayFieldKeys.has(fieldKey)) return normalizePurchaseObjectArrayFieldValue(value) |
| | | if (purchaseStringFieldKeys.has(fieldKey)) return normalizePurchaseStringFieldValue(value) |
| | | return value |
| | | } |
| | | |
| | | const normalizePurchasePayloadFieldTypes = (value, fieldKey = '') => { |
| | | if (purchaseGenericArrayFieldKeys.has(fieldKey)) { |
| | | if (Array.isArray(value)) { |
| | | return value.map(item => normalizePurchasePayloadFieldTypes(item)) |
| | | } |
| | | if (value && typeof value === 'object') { |
| | | return [normalizePurchasePayloadFieldTypes(value)] |
| | | } |
| | | return [] |
| | | } |
| | | |
| | | if (purchaseStringArrayFieldKeys.has(fieldKey)) { |
| | | return normalizePurchaseStringArrayFieldValue(value) |
| | | } |
| | | |
| | | if (purchaseObjectArrayFieldKeys.has(fieldKey)) { |
| | | return normalizePurchaseObjectArrayFieldValue(value) |
| | | } |
| | | |
| | | if (Array.isArray(value)) { |
| | | return value.map(item => normalizePurchasePayloadFieldTypes(item)) |
| | | } |
| | | |
| | | if (value && typeof value === 'object') { |
| | | return Object.entries(value).reduce((result, [key, item]) => { |
| | | result[key] = normalizePurchasePayloadFieldTypes(item, key) |
| | | return result |
| | | }, {}) |
| | | } |
| | | |
| | | return normalizePurchaseValueByFieldKey(fieldKey, value) |
| | | } |
| | | |
| | | const sanitizePurchasePayloadForSubmit = (payload, businessType) => { |
| | | if (businessType !== 'purchase_ledger' || !payload || typeof payload !== 'object') return payload |
| | | |
| | | const sanitized = mergeLegacyProductDataIntoLedgers(Array.isArray(payload) ? [...payload] : { ...payload }) |
| | | let sanitized = mergeLegacyProductDataIntoLedgers(Array.isArray(payload) ? [...payload] : { ...payload }) |
| | | sanitized = normalizePurchaseAttachmentMaterialsField(sanitized) |
| | | sanitized = normalizePurchasePayloadFieldTypes(sanitized) |
| | | if (Array.isArray(sanitized.purchaseLedgers)) { |
| | | sanitized.purchaseLedgers = sanitized.purchaseLedgers.map(filterPurchaseLedgerRecord) |
| | | } |
| | | if (Array.isArray(sanitized.productData)) { |
| | | sanitized.productData = normalizeAndFilterPurchaseProductData(sanitized.productData) |
| | | } |
| | | if (Array.isArray(sanitized.productData) && !sanitized.productData.length) { |
| | | delete sanitized.productData |
| | | } |
| | | |
| | | purchaseApprovalFieldKeys.forEach(key => { |
| | |
| | | return isLt10M |
| | | }) |
| | | |
| | | clearSelectedFiles() |
| | | selectedFiles.value = validFiles |
| | | uploadFileList.value = fileList.filter(item => item.raw && validFiles.includes(item.raw)) |
| | | selectedFileSnapshots.value = validFiles.map((rawFile, index) => createLocalFileSnapshot(rawFile, index)) |
| | | } |
| | | |
| | | const removeSelectedFile = (index) => { |
| | | const [removedSnapshot] = selectedFileSnapshots.value.splice(index, 1) |
| | | revokeLocalFileSnapshots(removedSnapshot ? [removedSnapshot] : []) |
| | | selectedFiles.value.splice(index, 1) |
| | | uploadFileList.value.splice(index, 1) |
| | | } |
| | | |
| | | const analyzeFiles = async (files, message = '') => { |
| | | const analyzeFiles = async (files, message = '', localFileSnapshots = []) => { |
| | | const uploadFiles = Array.isArray(files) ? files : [files].filter(Boolean) |
| | | if (!uploadFiles.length) return |
| | | if (isSending.value) return |
| | |
| | | isUser: true, |
| | | content: userMsg, |
| | | htmlContent: convertTextToHtml(userMsg), |
| | | isTyping: false |
| | | isTyping: false, |
| | | localUploadFiles: Array.isArray(localFileSnapshots) ? localFileSnapshots : [] |
| | | }) |
| | | |
| | | const botMsgIndex = messages.value.length |
| | |
| | | type: '', |
| | | tableData: null, |
| | | payloadTreeData: null, |
| | | payloadHiddenData: null |
| | | payloadHiddenData: null, |
| | | purchaseAnalysisData: null, |
| | | manufacturingData: null, |
| | | salesData: null, |
| | | purchaseData: null, |
| | | purchaseIntentData: null |
| | | }) |
| | | |
| | | outputState.value[botMsgIndex] = { |
| | |
| | | const msg = inputMessage.value?.trim() || '' |
| | | if ((msg || selectedFiles.value.length) && !isSending.value) { |
| | | if (selectedFiles.value.length) { |
| | | analyzeFiles([...selectedFiles.value], msg) |
| | | selectedFiles.value = [] |
| | | uploadFileList.value = [] |
| | | const localFileSnapshots = selectedFileSnapshots.value |
| | | analyzeFiles([...selectedFiles.value], msg, localFileSnapshots) |
| | | clearSelectedFiles({ releaseSnapshots: false }) |
| | | } else { |
| | | sendRequest(msg) |
| | | } |
| | |
| | | type: '', |
| | | tableData: null, |
| | | payloadTreeData: null, |
| | | payloadHiddenData: null |
| | | payloadHiddenData: null, |
| | | purchaseAnalysisData: null, |
| | | manufacturingData: null, |
| | | salesData: null, |
| | | purchaseData: null, |
| | | purchaseIntentData: null |
| | | } |
| | | messages.value.push(botMsg) |
| | | |
| | |
| | | const extracted = extractEmbeddedSuccessJson(fullText) |
| | | if (extracted) { |
| | | applyStructuredMessageData(currentMsg, extracted.data, botMsgIndex) |
| | | } else { |
| | | const extractJson = (text) => { |
| | | const startIdx = text.indexOf('{"success": true') |
| | | if (startIdx === -1) return null |
| | | |
| | | // ä»åå¾åæ¾æåä¸ä¸ª '}' |
| | | const lastBraceIdx = text.lastIndexOf('}') |
| | | if (lastBraceIdx === -1 || lastBraceIdx < startIdx) return null |
| | | |
| | | const potentialJson = text.substring(startIdx, lastBraceIdx + 1) |
| | | try { |
| | | return JSON.parse(potentialJson) |
| | | } catch (err) { |
| | | return null |
| | | } |
| | | } |
| | | |
| | | const parsedData = extractJson(fullText) |
| | | if (parsedData) { |
| | | applyStructuredMessageData(currentMsg, parsedData, botMsgIndex, true) |
| | | } |
| | | |
| | | } |
| | | |
| | | updateOutputState(fullText, botMsgIndex) |
| | |
| | | const extracted = extractEmbeddedSuccessJson(currentMsg.content) |
| | | if (extracted) { |
| | | applyStructuredMessageData(currentMsg, extracted.data, botMsgIndex) |
| | | } else { |
| | | const extractJson = (text) => { |
| | | const startIdx = text.indexOf('{"success": true') |
| | | if (startIdx === -1) return null |
| | | const lastBraceIdx = text.lastIndexOf('}') |
| | | if (lastBraceIdx === -1 || lastBraceIdx < startIdx) return null |
| | | const potentialJson = text.substring(startIdx, lastBraceIdx + 1) |
| | | try { |
| | | return JSON.parse(potentialJson) |
| | | } catch (err) { |
| | | return null |
| | | } |
| | | } |
| | | |
| | | const finalParsed = extractJson(currentMsg.content) |
| | | if (finalParsed) { |
| | | applyStructuredMessageData(currentMsg, finalParsed, botMsgIndex) |
| | | } |
| | | } |
| | | }).catch(err => { |
| | | if (err.name === 'CanceledError' || err.name === 'AbortError') { |
| | |
| | | } |
| | | |
| | | if (!display) { |
| | | if (parsed.type === 'todo_list') { |
| | | display = 'å·²ä¸ºæ¨æ´ç好ç¸å
³æ°æ®ã' |
| | | } else if (parsed.charts && Object.keys(parsed.charts).length > 0) { |
| | | display = '已为æ¨çæåæå¾è¡¨ã' |
| | | } else { |
| | | display = 'æ£å¨ä¸ºæ¨å±ç¤ºåæç»æ...' |
| | | } |
| | | display = getStructuredFallbackText(parsed) |
| | | } |
| | | } else if (startIdx !== -1) { |
| | | const lastBraceIdx = output.lastIndexOf('}') |
| | |
| | | } |
| | | |
| | | if (!display) { |
| | | if (parsed.type === 'todo_list') { |
| | | display = 'å·²ä¸ºæ¨æ´ç好ç¸å
³æ°æ®ï¼' |
| | | } else if (parsed.charts && Object.keys(parsed.charts).length > 0) { |
| | | display = '已为æ¨çæåæå¾è¡¨ï¼' |
| | | } else { |
| | | display = 'æ£å¨ä¸ºæ¨å±ç¤ºåæç»æ...' |
| | | } |
| | | display = getStructuredFallbackText(parsed) |
| | | } |
| | | } catch (e) { |
| | | // è§£æå¤±è´¥ï¼è¯´æ JSON è¿å¨ä¼ è¾ä¸ææ ¼å¼ä¸æ£ç¡® |
| | |
| | | .ai-chat-trigger { |
| | | pointer-events: auto; |
| | | position: fixed; |
| | | right: 24px; |
| | | bottom: 100px; |
| | | width: 56px; |
| | | height: 56px; |
| | | right: 10px; |
| | | bottom: 12px; |
| | | width: 40px; |
| | | height: 40px; |
| | | background: $gradient-dark; |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | cursor: pointer; |
| | | box-shadow: $shadow-deep, 0 0 0 2px rgba(0, 85, 212, 0.3) inset, 0 0 30px rgba(0, 119, 232, 0.2); |
| | | transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); |
| | | z-index: 2001; |
| | | animation: triggerPulse 3s ease-in-out infinite; |
| | | box-shadow: 0 8px 18px rgba(0, 68, 170, 0.32), 0 0 0 1px rgba(0, 136, 232, 0.32) inset; |
| | | transition: transform 0.22s ease, box-shadow 0.22s ease, opacity 0.22s ease; |
| | | z-index: 1020; |
| | | opacity: 0.9; |
| | | |
| | | &::before { |
| | | content: ''; |
| | | position: absolute; |
| | | inset: -6px; |
| | | inset: -4px; |
| | | background: linear-gradient(135deg, rgba(0, 85, 212, 0.4), rgba(0, 136, 232, 0.3), rgba(90, 159, 224, 0.2)); |
| | | border-radius: 50%; |
| | | z-index: -1; |
| | | filter: blur(16px); |
| | | animation: glowPulse 2s ease-in-out infinite alternate; |
| | | filter: blur(10px); |
| | | opacity: 0.35; |
| | | } |
| | | |
| | | &::after { |
| | |
| | | } |
| | | |
| | | &:hover { |
| | | transform: scale(1.12) translateY(-4px); |
| | | box-shadow: $shadow-deep, 0 0 0 3px rgba(0, 136, 232, 0.4) inset, 0 0 50px rgba(0, 136, 232, 0.3); |
| | | |
| | | &::before { |
| | | animation: glowPulse 1s ease-in-out infinite alternate; |
| | | } |
| | | transform: scale(1.05) translateY(-1px); |
| | | box-shadow: 0 10px 22px rgba(0, 68, 170, 0.38), 0 0 0 1px rgba(0, 136, 232, 0.42) inset; |
| | | |
| | | .trigger-icon { |
| | | transform: rotate(-8deg) scale(1.05); |
| | | filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.5)); |
| | | transform: scale(1.03); |
| | | filter: drop-shadow(0 0 6px rgba(255, 255, 255, 0.42)); |
| | | } |
| | | } |
| | | |
| | |
| | | height: 100%; |
| | | } |
| | | :deep(.el-drawer__header) { |
| | | margin-bottom: 0; |
| | | padding: 0; |
| | | margin-bottom: 0 !important; |
| | | padding: 0 !important; |
| | | border-bottom: 1px solid rgba(255, 255, 255, 0.12); |
| | | background: $gradient-dark; |
| | | color: #fff; |
| | | } |
| | |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | width: 100%; |
| | | padding: 18px 20px; |
| | | padding: 12px 18px; |
| | | background: $gradient-dark; |
| | | position: relative; |
| | | overflow: hidden; |
| | |
| | | opacity: 1; |
| | | } |
| | | } |
| | | |
| | | :deep(.header-action-btn--text) { |
| | | width: auto !important; |
| | | min-width: 104px; |
| | | padding: 8px 14px !important; |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | white-space: nowrap; |
| | | } |
| | | } |
| | | |
| | | .assistant-switcher { |
| | |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | height: 240px; |
| | | height: 128px; |
| | | background: linear-gradient(180deg, rgba(0, 85, 212, 0.06) 0%, transparent 100%); |
| | | pointer-events: none; |
| | | } |
| | |
| | | border-radius: 2px; |
| | | } |
| | | } |
| | | |
| | | .message-local-file-list { |
| | | margin-top: 8px; |
| | | display: grid; |
| | | gap: 8px; |
| | | max-width: 100%; |
| | | } |
| | | |
| | | .message-local-file-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 10px; |
| | | padding: 8px 10px; |
| | | border-radius: 10px; |
| | | border: 1px solid rgba(88, 117, 255, 0.2); |
| | | background: rgba(255, 255, 255, 0.9); |
| | | max-width: 100%; |
| | | |
| | | &.clickable { |
| | | cursor: pointer; |
| | | transition: all 0.2s ease; |
| | | |
| | | &:hover { |
| | | border-color: rgba(44, 109, 255, 0.38); |
| | | background: rgba(243, 247, 255, 0.96); |
| | | } |
| | | } |
| | | } |
| | | |
| | | .message-local-file-thumb { |
| | | width: 40px; |
| | | height: 40px; |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | flex-shrink: 0; |
| | | border: 1px solid rgba(124, 148, 255, 0.26); |
| | | background: #f4f7ff; |
| | | cursor: zoom-in; |
| | | |
| | | :deep(.el-image__inner) { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | } |
| | | |
| | | .message-local-file-icon { |
| | | font-size: 20px; |
| | | color: $primary-blue; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .message-local-file-meta { |
| | | min-width: 0; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 2px; |
| | | } |
| | | |
| | | .message-local-file-name { |
| | | font-size: 12px; |
| | | color: #1f2a44; |
| | | font-weight: 600; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | |
| | | &.clickable { |
| | | color: $primary-blue; |
| | | cursor: pointer; |
| | | |
| | | &:hover { |
| | | text-decoration: underline; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .message-local-file-size { |
| | | font-size: 11px; |
| | | color: #7f8ba1; |
| | | line-height: 1.2; |
| | | } |
| | | } |
| | | |
| | | &.bot-message { |
| | |
| | | --el-table-border-color: rgba(0, 122, 255, 0.08); |
| | | --el-table-header-bg-color: $ice-white; |
| | | } |
| | | } |
| | | |
| | | .manufacturing-card { |
| | | margin-top: 12px; |
| | | width: 100%; |
| | | background: #fff; |
| | | border: 1px solid rgba(0, 85, 212, 0.12); |
| | | border-radius: 12px; |
| | | box-shadow: $shadow-card; |
| | | padding: 14px; |
| | | } |
| | | |
| | | .manufacturing-card__title { |
| | | font-size: 14px; |
| | | font-weight: 700; |
| | | color: $deep-blue; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .manufacturing-summary-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); |
| | | gap: 8px; |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .manufacturing-summary-item { |
| | | border-radius: 10px; |
| | | padding: 10px 12px; |
| | | border: 1px solid rgba(0, 85, 212, 0.08); |
| | | background: linear-gradient(180deg, #f8fbff, #f1f7ff); |
| | | min-height: 66px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: space-between; |
| | | gap: 6px; |
| | | } |
| | | |
| | | .manufacturing-summary-item--core { |
| | | border-color: rgba(30, 91, 255, 0.24); |
| | | } |
| | | |
| | | .manufacturing-summary-label { |
| | | font-size: 12px; |
| | | color: #4b5563; |
| | | } |
| | | |
| | | .manufacturing-summary-value { |
| | | font-size: 15px; |
| | | color: #1f2937; |
| | | line-height: 1.4; |
| | | word-break: break-all; |
| | | } |
| | | |
| | | .manufacturing-warning-list { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 8px; |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .manufacturing-warning-item { |
| | | border-radius: 10px; |
| | | border: 1px solid rgba(245, 158, 11, 0.22); |
| | | background: linear-gradient(135deg, rgba(255, 247, 237, 0.9), rgba(255, 255, 255, 0.98)); |
| | | padding: 10px 12px; |
| | | } |
| | | |
| | | .manufacturing-warning-item__head { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | color: #92400e; |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .manufacturing-warning-count { |
| | | margin-left: auto; |
| | | font-weight: 700; |
| | | color: #c2410c; |
| | | } |
| | | |
| | | .manufacturing-warning-detail { |
| | | margin: 8px 0 0; |
| | | font-size: 12px; |
| | | line-height: 1.6; |
| | | color: #7c2d12; |
| | | word-break: break-all; |
| | | } |
| | | |
| | | .manufacturing-table-wrapper { |
| | | margin-top: 10px; |
| | | } |
| | | |
| | | .manufacturing-action-list { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | margin-top: 12px; |
| | | } |
| | | |
| | | .manufacturing-action-card { |
| | | border: 1px solid rgba(0, 85, 212, 0.1); |
| | | border-radius: 10px; |
| | | padding: 10px 12px; |
| | | background: #f8fbff; |
| | | } |
| | | |
| | | .manufacturing-action-card__head { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | gap: 12px; |
| | | font-size: 13px; |
| | | color: #1f2937; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .manufacturing-action-card__meta { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 4px; |
| | | margin-bottom: 8px; |
| | | font-size: 12px; |
| | | color: #64748b; |
| | | word-break: break-all; |
| | | } |
| | | |
| | | .manufacturing-action-card__desc { |
| | | margin: 0 0 8px; |
| | | font-size: 12px; |
| | | line-height: 1.6; |
| | | color: #475467; |
| | | } |
| | | |
| | | .manufacturing-required-fields { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | align-items: center; |
| | | gap: 6px; |
| | | margin-bottom: 8px; |
| | | font-size: 12px; |
| | | color: #7c2d12; |
| | | } |
| | | |
| | | .manufacturing-action-footer { |
| | | margin-top: 8px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: flex-end; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .manufacturing-action-result { |
| | | flex: 1; |
| | | font-size: 12px; |
| | | line-height: 1.5; |
| | | |
| | | &.success { |
| | | color: #1f9d55; |
| | | } |
| | | |
| | | &.error { |
| | | color: #d93025; |
| | | } |
| | | } |
| | | |
| | | .sales-structured-card { |
| | | margin-top: 12px; |
| | | width: 100%; |
| | | background: #fff; |
| | | border: 1px solid rgba(31, 122, 114, 0.2); |
| | | border-radius: 12px; |
| | | box-shadow: $shadow-card; |
| | | padding: 14px; |
| | | } |
| | | |
| | | .sales-structured-card__title { |
| | | font-size: 14px; |
| | | font-weight: 700; |
| | | color: #1f5ddf; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .sales-summary-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); |
| | | gap: 8px; |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .sales-summary-item { |
| | | border-radius: 10px; |
| | | padding: 10px 12px; |
| | | border: 1px solid rgba(30, 91, 255, 0.12); |
| | | background: linear-gradient(180deg, #f7fbff, #edf6ff); |
| | | min-height: 66px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: space-between; |
| | | gap: 6px; |
| | | } |
| | | |
| | | .sales-summary-label { |
| | | font-size: 12px; |
| | | color: #4b5563; |
| | | } |
| | | |
| | | .sales-summary-value { |
| | | font-size: 15px; |
| | | color: #1f2937; |
| | | line-height: 1.4; |
| | | word-break: break-all; |
| | | } |
| | | |
| | | .sales-focus-list { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .sales-focus-item { |
| | | border-radius: 10px; |
| | | border: 1px solid rgba(30, 91, 255, 0.14); |
| | | background: #f8fbff; |
| | | padding: 10px 12px; |
| | | } |
| | | |
| | | .sales-focus-item--strategy { |
| | | border-color: rgba(31, 122, 114, 0.22); |
| | | background: linear-gradient(180deg, #f7fcfb, #edf9f6); |
| | | } |
| | | |
| | | .sales-focus-item__head { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | justify-content: space-between; |
| | | gap: 10px; |
| | | font-size: 13px; |
| | | color: #1f2937; |
| | | } |
| | | |
| | | .sales-focus-tags { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | gap: 6px; |
| | | flex-wrap: wrap; |
| | | justify-content: flex-end; |
| | | } |
| | | |
| | | .sales-focus-metrics { |
| | | margin-top: 8px; |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 10px; |
| | | font-size: 12px; |
| | | color: #475467; |
| | | } |
| | | |
| | | .sales-focus-reasons { |
| | | margin-top: 8px; |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 6px; |
| | | } |
| | | |
| | | .sales-strategy-line { |
| | | margin: 8px 0 0; |
| | | font-size: 12px; |
| | | line-height: 1.6; |
| | | color: #334155; |
| | | } |
| | | |
| | | .sales-section-title { |
| | | margin: 4px 0 8px; |
| | | font-size: 13px; |
| | | font-weight: 700; |
| | | color: $deep-blue; |
| | | } |
| | | |
| | | .purchase-intent-quick-prompt-wrap { |
| | | margin-top: 12px; |
| | | } |
| | | |
| | | .purchase-intent-quick-prompt-title { |
| | | font-size: 12px; |
| | | color: #4b5563; |
| | | } |
| | | |
| | | .purchase-intent-quick-prompt-list { |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .purchase-confirm-card { |
| | |
| | | font-size: 18px; |
| | | } |
| | | |
| | | .selected-file-thumb { |
| | | width: 30px; |
| | | height: 30px; |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | border: 1px solid rgba(0, 85, 212, 0.2); |
| | | flex-shrink: 0; |
| | | cursor: zoom-in; |
| | | |
| | | :deep(.el-image__inner) { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | } |
| | | |
| | | .selected-file-meta { |
| | | min-width: 0; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 2px; |
| | | } |
| | | |
| | | .file-name { |
| | | font-size: 13px; |
| | | color: $deep-blue; |
| | |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .file-size { |
| | | font-size: 11px; |
| | | color: #5f86b4; |
| | | line-height: 1.1; |
| | | } |
| | | |
| | | .remove-file { |
| | |
| | | |
| | | .chat-hero { |
| | | display: grid; |
| | | grid-template-columns: 164px minmax(0, 1fr); |
| | | gap: 18px; |
| | | align-items: start; |
| | | padding: 14px 18px 6px; |
| | | grid-template-columns: 176px minmax(0, 1fr); |
| | | gap: 14px; |
| | | align-items: stretch; |
| | | padding: 8px 18px 4px; |
| | | |
| | | &.compact { |
| | | grid-template-columns: 122px minmax(0, 1fr); |
| | | gap: 12px; |
| | | padding: 8px 18px 2px; |
| | | grid-template-columns: 132px minmax(0, 1fr); |
| | | gap: 10px; |
| | | padding: 4px 18px 2px; |
| | | } |
| | | } |
| | | |
| | | .assistant-stand { |
| | | position: relative; |
| | | min-height: 252px; |
| | | min-height: 206px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | flex-direction: column; |
| | | padding-top: 18px; |
| | | padding-top: 8px; |
| | | overflow: hidden; |
| | | |
| | | &.compact { |
| | | min-height: 176px; |
| | | padding-top: 8px; |
| | | min-height: 160px; |
| | | padding-top: 4px; |
| | | } |
| | | |
| | | &.thinking { |
| | | .assistant-halo { |
| | | opacity: 1; |
| | | transform: scale(1.08); |
| | | filter: blur(8px); |
| | | transform: scale(1.12); |
| | | filter: blur(9px); |
| | | } |
| | | |
| | | .assistant-scan-ring { |
| | | opacity: 1; |
| | | animation-duration: 1.6s; |
| | | opacity: 0.95; |
| | | animation-duration: 1.5s; |
| | | } |
| | | |
| | | .assistant-orbit { |
| | | opacity: 1; |
| | | opacity: 0.76; |
| | | } |
| | | |
| | | .assistant-bot { |
| | | transform: translateY(-4px) scale(1.02); |
| | | .assistant-model-shell { |
| | | transform: translateY(-5px) scale(1.02); |
| | | } |
| | | |
| | | .assistant-bot-head { |
| | | box-shadow: 0 0 30px rgba(80, 157, 255, 0.36); |
| | | .assistant-model-cut { |
| | | animation-duration: 2.2s; |
| | | } |
| | | |
| | | .assistant-bot-eye { |
| | | animation: robotBlinkFast 1.1s infinite; |
| | | box-shadow: 0 0 16px rgba(72, 186, 255, 0.95); |
| | | } |
| | | |
| | | .assistant-bot-mouth { |
| | | width: 28px; |
| | | opacity: 1; |
| | | animation: robotTalk 1.2s ease-in-out infinite; |
| | | } |
| | | |
| | | .assistant-bot-core { |
| | | animation: corePulse 1.4s ease-in-out infinite; |
| | | box-shadow: 0 0 24px rgba(78, 120, 255, 0.26); |
| | | } |
| | | |
| | | .assistant-bot-core-ring { |
| | | animation: coreRotate 3s linear infinite; |
| | | .assistant-model-img { |
| | | filter: saturate(1.06) drop-shadow(0 18px 20px rgba(22, 48, 80, 0.22)); |
| | | } |
| | | |
| | | .assistant-status { |
| | |
| | | animation: thinkingDot 1s ease-in-out infinite; |
| | | } |
| | | |
| | | .assistant-base-lg { |
| | | animation-duration: 1.8s; |
| | | } |
| | | |
| | | .assistant-base-md { |
| | | animation-duration: 1.5s; |
| | | } |
| | | |
| | | .assistant-base-sm { |
| | | box-shadow: 0 0 24px rgba(255, 93, 122, 0.48); |
| | | box-shadow: 0 0 24px rgba(30, 91, 255, 0.36); |
| | | animation-duration: 1.25s; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .assistant-halo { |
| | | position: absolute; |
| | | top: 22px; |
| | | width: 130px; |
| | | height: 130px; |
| | | top: 24px; |
| | | width: 146px; |
| | | height: 146px; |
| | | border-radius: 50%; |
| | | background: radial-gradient(circle, rgba(46, 140, 224, 0.3) 0%, rgba(0, 85, 212, 0.18) 42%, rgba(113, 54, 244, 0.12) 60%, transparent 78%); |
| | | background: radial-gradient(circle, rgba(31, 122, 114, 0.26) 0%, rgba(30, 91, 255, 0.2) 42%, rgba(109, 65, 237, 0.12) 66%, transparent 80%); |
| | | filter: blur(6px); |
| | | opacity: 0.82; |
| | | opacity: 0.78; |
| | | transition: all 0.35s ease; |
| | | } |
| | | |
| | | .assistant-scan-ring { |
| | | position: absolute; |
| | | top: 40px; |
| | | width: 132px; |
| | | height: 132px; |
| | | top: 44px; |
| | | width: 136px; |
| | | height: 136px; |
| | | border-radius: 50%; |
| | | border: 1px solid rgba(90, 159, 224, 0.22); |
| | | border: 1px solid rgba(67, 145, 223, 0.24); |
| | | box-shadow: inset 0 0 16px rgba(255, 255, 255, 0.25); |
| | | opacity: 0.55; |
| | | opacity: 0.52; |
| | | animation: scanRing 4s linear infinite; |
| | | } |
| | | |
| | | .assistant-orbit { |
| | | position: absolute; |
| | | top: 52px; |
| | | width: 150px; |
| | | height: 150px; |
| | | width: 156px; |
| | | height: 156px; |
| | | border-radius: 50%; |
| | | border: 1px dashed rgba(92, 135, 255, 0.22); |
| | | opacity: 0.45; |
| | | border: 1px dashed rgba(92, 135, 255, 0.24); |
| | | opacity: 0.42; |
| | | } |
| | | |
| | | .assistant-orbit-a { |
| | | animation: orbitRotate 8s linear infinite; |
| | | animation: orbitRotate 8.6s linear infinite; |
| | | } |
| | | |
| | | .assistant-orbit-b { |
| | | width: 118px; |
| | | height: 118px; |
| | | width: 124px; |
| | | height: 124px; |
| | | top: 68px; |
| | | border-color: rgba(255, 108, 150, 0.22); |
| | | animation: orbitRotateReverse 5.6s linear infinite; |
| | | border-color: rgba(31, 122, 114, 0.24); |
| | | animation: orbitRotateReverse 6.2s linear infinite; |
| | | } |
| | | |
| | | .assistant-bot { |
| | | .assistant-model-shell { |
| | | position: relative; |
| | | z-index: 1; |
| | | width: 148px; |
| | | height: 178px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | align-items: flex-end; |
| | | justify-content: center; |
| | | margin-top: 12px; |
| | | margin-top: 4px; |
| | | transition: transform 0.35s ease; |
| | | } |
| | | |
| | | .assistant-bot-antenna { |
| | | position: absolute; |
| | | top: -4px; |
| | | width: 4px; |
| | | height: 20px; |
| | | border-radius: 999px; |
| | | background: linear-gradient(180deg, #fefefe, #aac9ff); |
| | | |
| | | &::before { |
| | | content: ''; |
| | | position: absolute; |
| | | top: -6px; |
| | | left: 50%; |
| | | width: 10px; |
| | | height: 10px; |
| | | border-radius: 50%; |
| | | bottom: 2px; |
| | | width: 164px; |
| | | height: 42px; |
| | | transform: translateX(-50%); |
| | | background: linear-gradient(135deg, #54bfff, #7a41ff); |
| | | box-shadow: 0 0 14px rgba(84, 191, 255, 0.65); |
| | | border-radius: 50%; |
| | | background: radial-gradient( |
| | | ellipse at center, |
| | | rgba(43, 126, 211, 0.32) 0%, |
| | | rgba(43, 126, 211, 0.14) 46%, |
| | | rgba(43, 126, 211, 0) 74% |
| | | ); |
| | | filter: blur(2.6px); |
| | | animation: baseGlow 4.6s ease-in-out infinite; |
| | | z-index: 1; |
| | | } |
| | | |
| | | &::after { |
| | | content: ''; |
| | | position: absolute; |
| | | left: 50%; |
| | | bottom: 10px; |
| | | width: 138px; |
| | | height: 28px; |
| | | transform: translateX(-50%); |
| | | border-radius: 50%; |
| | | border: 1px solid rgba(36, 116, 198, 0.6); |
| | | box-shadow: |
| | | inset 0 0 0 1px rgba(255, 255, 255, 0.58), |
| | | 0 0 22px rgba(42, 116, 196, 0.24); |
| | | animation: basePulse 3.2s ease-in-out infinite; |
| | | z-index: 4; |
| | | } |
| | | } |
| | | |
| | | .assistant-bot-antenna-left { |
| | | left: 36px; |
| | | transform: rotate(-14deg); |
| | | } |
| | | |
| | | .assistant-bot-antenna-right { |
| | | right: 36px; |
| | | transform: rotate(14deg); |
| | | } |
| | | |
| | | .assistant-bot-head { |
| | | .assistant-model-cut { |
| | | position: relative; |
| | | width: 132px; |
| | | height: 178px; |
| | | z-index: 6; |
| | | display: flex; |
| | | align-items: flex-end; |
| | | justify-content: center; |
| | | transform-origin: center 84%; |
| | | animation: avatarFloat 3.2s ease-in-out infinite; |
| | | } |
| | | |
| | | .assistant-model-img { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: contain; |
| | | object-position: center bottom; |
| | | display: block; |
| | | filter: saturate(1.03) drop-shadow(0 14px 18px rgba(22, 49, 79, 0.2)); |
| | | transition: filter 0.35s ease; |
| | | } |
| | | |
| | | .assistant-model-fallback { |
| | | width: 92px; |
| | | height: 78px; |
| | | border-radius: 28px; |
| | | background: linear-gradient(180deg, rgba(255, 255, 255, 0.98) 0%, #e8f1ff 100%); |
| | | border: 1px solid rgba(0, 85, 212, 0.14); |
| | | box-shadow: 0 16px 32px rgba(0, 85, 212, 0.14); |
| | | height: 92px; |
| | | border-radius: 24px; |
| | | color: #fff; |
| | | background: linear-gradient(145deg, rgba(31, 122, 114, 0.9), rgba(30, 91, 255, 0.9)); |
| | | border: 1px solid rgba(255, 255, 255, 0.3); |
| | | box-shadow: 0 12px 24px rgba(31, 85, 173, 0.22); |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .assistant-bot-head-glow { |
| | | position: absolute; |
| | | inset: 10px 16px auto; |
| | | height: 20px; |
| | | border-radius: 999px; |
| | | background: linear-gradient(180deg, rgba(0, 85, 212, 0.16), transparent); |
| | | } |
| | | |
| | | .assistant-bot-eye { |
| | | position: absolute; |
| | | top: 30px; |
| | | width: 16px; |
| | | height: 16px; |
| | | border-radius: 50%; |
| | | background: radial-gradient(circle, #8ef0ff 0%, #56c0ff 42%, #2869ff 100%); |
| | | box-shadow: 0 0 12px rgba(72, 186, 255, 0.72); |
| | | animation: robotBlink 3.2s infinite; |
| | | } |
| | | |
| | | .assistant-bot-eye-left { |
| | | left: 22px; |
| | | } |
| | | |
| | | .assistant-bot-eye-right { |
| | | right: 22px; |
| | | } |
| | | |
| | | .assistant-bot-mouth { |
| | | .assistant-base { |
| | | position: absolute; |
| | | left: 50%; |
| | | bottom: 16px; |
| | | width: 22px; |
| | | height: 4px; |
| | | bottom: 8px; |
| | | transform: translateX(-50%); |
| | | border-radius: 999px; |
| | | background: linear-gradient(90deg, rgba(72, 186, 255, 0.2), rgba(72, 186, 255, 0.9), rgba(72, 186, 255, 0.2)); |
| | | } |
| | | |
| | | .assistant-bot-neck { |
| | | width: 16px; |
| | | height: 10px; |
| | | border-radius: 0 0 10px 10px; |
| | | background: linear-gradient(180deg, #dceaff, #bdd5ff); |
| | | margin-top: -2px; |
| | | } |
| | | |
| | | .assistant-bot-body { |
| | | position: relative; |
| | | width: 104px; |
| | | height: 92px; |
| | | margin-top: 2px; |
| | | border-radius: 28px 28px 34px 34px; |
| | | background: linear-gradient(180deg, rgba(255, 255, 255, 0.98) 0%, #e3eeff 100%); |
| | | border: 1px solid rgba(0, 85, 212, 0.14); |
| | | box-shadow: 0 18px 36px rgba(0, 85, 212, 0.16); |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .assistant-bot-arm { |
| | | position: absolute; |
| | | top: 18px; |
| | | width: 16px; |
| | | height: 44px; |
| | | border-radius: 999px; |
| | | background: linear-gradient(180deg, #eff5ff, #c7dbff); |
| | | border: 1px solid rgba(0, 85, 212, 0.12); |
| | | } |
| | | |
| | | .assistant-bot-arm-left { |
| | | left: -10px; |
| | | transform: rotate(16deg); |
| | | } |
| | | |
| | | .assistant-bot-arm-right { |
| | | right: -10px; |
| | | transform: rotate(-16deg); |
| | | } |
| | | |
| | | .assistant-bot-core { |
| | | position: relative; |
| | | width: 46px; |
| | | height: 46px; |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | color: $primary-blue; |
| | | background: radial-gradient(circle, rgba(255, 255, 255, 1) 0%, #dae8ff 55%, #adc7ff 100%); |
| | | } |
| | | |
| | | .assistant-bot-core-ring { |
| | | position: absolute; |
| | | inset: -6px; |
| | | border-radius: 50%; |
| | | border: 1px solid rgba(88, 135, 255, 0.3); |
| | | border-top-color: rgba(255, 96, 139, 0.85); |
| | | border-right-color: rgba(79, 145, 255, 0.9); |
| | | border: 1px solid rgba(36, 116, 198, 0.28); |
| | | background: radial-gradient( |
| | | ellipse at center, |
| | | rgba(255, 255, 255, 0.94) 0%, |
| | | rgba(81, 164, 233, 0.16) 58%, |
| | | rgba(30, 91, 255, 0.06) 100% |
| | | ); |
| | | box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.2); |
| | | } |
| | | |
| | | .assistant-status { |
| | | position: relative; |
| | | z-index: 1; |
| | | margin-top: 14px; |
| | | padding: 6px 12px; |
| | | margin-top: 7px; |
| | | padding: 5px 10px; |
| | | border-radius: 999px; |
| | | font-size: 12px; |
| | | font-size: 11px; |
| | | font-weight: 600; |
| | | color: $deep-blue; |
| | | background: rgba(255, 255, 255, 0.95); |
| | |
| | | } |
| | | |
| | | .assistant-base { |
| | | position: absolute; |
| | | bottom: 0; |
| | | left: 50%; |
| | | transform: translateX(-50%); |
| | | border-radius: 50%; |
| | | border: 2px solid rgba(255, 93, 122, 0.22); |
| | | background: radial-gradient(circle, rgba(255, 255, 255, 0.9) 0%, rgba(255, 111, 145, 0.1) 70%, transparent 100%); |
| | | } |
| | | |
| | | .assistant-base-lg { |
| | | width: 118px; |
| | | height: 30px; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .assistant-base-md { |
| | | bottom: 6px; |
| | | width: 88px; |
| | | height: 20px; |
| | | border-color: rgba(255, 93, 122, 0.34); |
| | | bottom: 15px; |
| | | width: 104px; |
| | | height: 22px; |
| | | border-color: rgba(36, 116, 198, 0.48); |
| | | animation: basePulse 2.8s ease-in-out infinite; |
| | | } |
| | | |
| | | .assistant-base-sm { |
| | | bottom: 11px; |
| | | width: 54px; |
| | | height: 10px; |
| | | background: linear-gradient(90deg, rgba(255, 93, 122, 0.95), rgba(255, 173, 188, 0.9)); |
| | | bottom: 20px; |
| | | width: 68px; |
| | | height: 14px; |
| | | background: linear-gradient(90deg, rgba(31, 122, 114, 0.82), rgba(45, 124, 255, 0.9)); |
| | | border: none; |
| | | box-shadow: 0 0 18px rgba(255, 93, 122, 0.38); |
| | | } |
| | | |
| | | @keyframes robotBlink { |
| | | 0%, 44%, 48%, 100% { |
| | | transform: scaleY(1); |
| | | } |
| | | 46% { |
| | | transform: scaleY(0.14); |
| | | } |
| | | } |
| | | |
| | | @keyframes robotBlinkFast { |
| | | 0%, 100% { |
| | | transform: scaleY(1); |
| | | } |
| | | 50% { |
| | | transform: scaleY(0.3); |
| | | } |
| | | } |
| | | |
| | | @keyframes robotTalk { |
| | | 0%, 100% { |
| | | transform: translateX(-50%) scaleX(1); |
| | | } |
| | | 50% { |
| | | transform: translateX(-50%) scaleX(1.35); |
| | | } |
| | | } |
| | | |
| | | @keyframes corePulse { |
| | | 0%, 100% { |
| | | transform: scale(1); |
| | | filter: brightness(1); |
| | | } |
| | | 50% { |
| | | transform: scale(1.08); |
| | | filter: brightness(1.08); |
| | | } |
| | | } |
| | | |
| | | @keyframes coreRotate { |
| | | from { |
| | | transform: rotate(0deg); |
| | | } |
| | | to { |
| | | transform: rotate(360deg); |
| | | } |
| | | box-shadow: 0 0 18px rgba(45, 124, 255, 0.34); |
| | | animation: basePulse 2.2s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes orbitRotate { |
| | |
| | | } |
| | | } |
| | | |
| | | .assistant-base-lg { |
| | | width: 142px; |
| | | height: 32px; |
| | | animation: basePulse 3.4s ease-in-out infinite; |
| | | |
| | | &::before { |
| | | content: ''; |
| | | position: absolute; |
| | | left: 50%; |
| | | top: 50%; |
| | | width: 130px; |
| | | height: 130px; |
| | | transform: translate(-50%, -50%); |
| | | border-radius: 50%; |
| | | background: conic-gradient( |
| | | from 180deg, |
| | | transparent 0deg, |
| | | rgba(36, 116, 198, 0.65) 48deg, |
| | | transparent 114deg, |
| | | rgba(36, 116, 198, 0.55) 212deg, |
| | | transparent 286deg, |
| | | rgba(31, 122, 114, 0.45) 334deg, |
| | | transparent 360deg |
| | | ); |
| | | -webkit-mask: radial-gradient(circle, transparent 61%, #000 62%, #000 68%, transparent 70%); |
| | | mask: radial-gradient(circle, transparent 61%, #000 62%, #000 68%, transparent 70%); |
| | | opacity: 0.62; |
| | | animation: baseSpin 9s linear infinite; |
| | | } |
| | | } |
| | | |
| | | @keyframes avatarFloat { |
| | | 0%, |
| | | 100% { |
| | | transform: translateY(0); |
| | | } |
| | | 50% { |
| | | transform: translateY(-7px); |
| | | } |
| | | } |
| | | |
| | | @keyframes basePulse { |
| | | 0%, |
| | | 100% { |
| | | transform: translateX(-50%) scale(1); |
| | | opacity: 0.88; |
| | | } |
| | | 50% { |
| | | transform: translateX(-50%) scale(1.05); |
| | | opacity: 0.98; |
| | | } |
| | | } |
| | | |
| | | @keyframes baseSpin { |
| | | from { |
| | | transform: translate(-50%, -50%) rotate(0deg); |
| | | } |
| | | to { |
| | | transform: translate(-50%, -50%) rotate(360deg); |
| | | } |
| | | } |
| | | |
| | | @keyframes baseGlow { |
| | | 0%, |
| | | 100% { |
| | | transform: translateX(-50%) scaleX(1); |
| | | opacity: 0.82; |
| | | } |
| | | 50% { |
| | | transform: translateX(-50%) scaleX(1.06); |
| | | opacity: 0.96; |
| | | } |
| | | } |
| | | |
| | | .welcome-card { |
| | | position: relative; |
| | | padding: 14px 14px 12px; |
| | | align-self: stretch; |
| | | min-height: 206px; |
| | | padding: 9px 10px 8px; |
| | | border-radius: 16px; |
| | | background: |
| | | linear-gradient(#fff, #fff) padding-box, |
| | |
| | | box-shadow: 0 16px 36px rgba(0, 85, 212, 0.12); |
| | | |
| | | &.compact { |
| | | padding: 10px 12px; |
| | | min-height: 160px; |
| | | padding: 8px 9px 7px; |
| | | border-radius: 12px; |
| | | box-shadow: 0 8px 16px rgba(0, 85, 212, 0.07); |
| | | |
| | |
| | | } |
| | | |
| | | .welcome-title { |
| | | font-size: 17px; |
| | | line-height: 1.3; |
| | | font-size: 16px; |
| | | line-height: 1.25; |
| | | |
| | | br { |
| | | display: none; |
| | |
| | | } |
| | | |
| | | .welcome-desc { |
| | | margin-top: 6px; |
| | | font-size: 12px; |
| | | line-height: 1.55; |
| | | margin-top: 4px; |
| | | font-size: 11px; |
| | | line-height: 1.5; |
| | | } |
| | | |
| | | .quick-prompt-list { |
| | | margin-top: 10px; |
| | | gap: 6px; |
| | | margin-top: 8px; |
| | | gap: 5px; |
| | | } |
| | | |
| | | .quick-prompt-btn { |
| | | padding: 8px 10px; |
| | | font-size: 12px; |
| | | padding: 7px 9px; |
| | | font-size: 11px; |
| | | border-radius: 7px; |
| | | } |
| | | |
| | | .more-prompts-btn { |
| | | margin-top: 8px; |
| | | font-size: 12px; |
| | | margin-top: 6px; |
| | | font-size: 11px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .welcome-eyebrow { |
| | | font-size: 11px; |
| | | font-size: 10px; |
| | | font-weight: 700; |
| | | letter-spacing: 2px; |
| | | color: rgba(0, 85, 212, 0.58); |
| | | margin-bottom: 8px; |
| | | margin-bottom: 5px; |
| | | } |
| | | |
| | | .welcome-title { |
| | | margin: 0; |
| | | font-size: 26px; |
| | | line-height: 1.2; |
| | | font-size: 20px; |
| | | line-height: 1.15; |
| | | font-weight: 800; |
| | | color: #172033; |
| | | |
| | | br { |
| | | display: none; |
| | | } |
| | | } |
| | | |
| | | .welcome-desc { |
| | | margin: 10px 0 0; |
| | | font-size: 13px; |
| | | line-height: 1.7; |
| | | margin: 5px 0 0; |
| | | font-size: 12px; |
| | | line-height: 1.5; |
| | | color: #5f6980; |
| | | } |
| | | |
| | | .quick-prompt-list { |
| | | display: grid; |
| | | gap: 8px; |
| | | margin-top: 14px; |
| | | gap: 6px; |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .quick-prompt-btn { |
| | | width: 100%; |
| | | border: none; |
| | | border-radius: 10px; |
| | | padding: 11px 14px; |
| | | border-radius: 9px; |
| | | padding: 7px 10px; |
| | | text-align: left; |
| | | font-size: 13px; |
| | | font-size: 12px; |
| | | font-weight: 600; |
| | | color: #fff; |
| | | cursor: pointer; |
| | |
| | | } |
| | | |
| | | .more-prompts-btn { |
| | | margin-top: 10px; |
| | | padding: 0 12px; |
| | | height: 32px; |
| | | margin-top: 6px; |
| | | padding: 0 10px; |
| | | height: 26px; |
| | | border: 1px solid rgba(208, 65, 81, 0.12); |
| | | border-radius: 999px; |
| | | background: linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(255, 241, 245, 0.96)); |
| | | color: #d04151; |
| | | font-size: 13px; |
| | | font-size: 12px; |
| | | font-weight: 600; |
| | | cursor: pointer; |
| | | display: inline-flex; |
| | |
| | | border-color: transparent; |
| | | color: #fff; |
| | | box-shadow: 0 14px 24px rgba(138, 61, 246, 0.18); |
| | | } |
| | | } |
| | | |
| | | .hero-dot-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(14, 1fr); |
| | | gap: 7px; |
| | | padding: 0 18px 14px; |
| | | |
| | | span { |
| | | display: block; |
| | | width: 100%; |
| | | aspect-ratio: 1; |
| | | border-radius: 2px; |
| | | background: linear-gradient(135deg, rgba(255, 110, 138, 0.95), rgba(255, 190, 201, 0.55)); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | .welcome-title { |
| | | font-size: 21px; |
| | | } |
| | | |
| | | .hero-dot-grid { |
| | | grid-template-columns: repeat(12, 1fr); |
| | | gap: 6px; |
| | | padding: 0 14px 12px; |
| | | } |
| | | |
| | | .message-list { |
| | |
| | |
|
| | | <style lang='scss' scoped>
|
| | | .app-breadcrumb.el-breadcrumb { |
| | | display: inline-block; |
| | | display: inline-flex; |
| | | align-items: center; |
| | | font-size: 14px; |
| | | line-height: 56px; |
| | | line-height: 1; |
| | | margin-left: 8px; |
| | | |
| | | :deep(.el-breadcrumb__inner) { |
| | |
| | | <el-table-column v-if="showActions" |
| | | fixed="right" |
| | | label="æä½" |
| | | :width="120" |
| | | :width="150" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <el-button link |
| | | type="primary" |
| | | size="small" |
| | | class="download-link" |
| | | @click="previewFile(scope.row.previewURL)"> |
| | | é¢è§ |
| | | </el-button> |
| | | <el-button link |
| | | type="primary" |
| | | size="small" |
| | |
| | | </el-table> |
| | | </div> |
| | | </el-dialog> |
| | | <filePreview ref="filePreviewRef" /> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ElMessage } from 'element-plus' |
| | | import { ref, computed, getCurrentInstance, onMounted, watch } from "vue"; |
| | | import AttachmentUpload from "@/components/AttachmentUpload/file/index.vue"; |
| | | import { |
| | |
| | | deleteAttachment, |
| | | createAttachment, |
| | | } from "@/api/basicData/storageAttachment.js"; |
| | | import filePreview from '@/components/filePreview/index.vue' |
| | | const filePreviewRef = ref() |
| | | |
| | | const props = defineProps({ |
| | | visible: { |
| | |
| | | isShow.value = false; |
| | | }; |
| | | |
| | | // é¢è§æä»¶ |
| | | const previewFile = (url) => { |
| | | if (url) { |
| | | filePreviewRef.value.open(url) |
| | | } else { |
| | | ElMessage.warning('æä»¶å°åæ æï¼æ æ³é¢è§') |
| | | } |
| | | } |
| | | |
| | | const handleUpload = () => { |
| | | uploadDialogVisible.value = true; |
| | | }; |
| | |
| | | const saveUpload = async () => { |
| | | // æ£æ¥æ¯å¦ææ°ä¸ä¼ çæä»¶ |
| | | if (newFileList.value.length > 0) { |
| | | try { |
| | | await createAttachment({ |
| | | application: "file", |
| | | recordType: props.recordType, |
| | | recordId: props.recordId, |
| | | storageBlobDTOs: [...newFileList.value, ...tableData.value], |
| | | }); |
| | | newFileList.value = []; |
| | | // å·æ°å表 |
| | | setList(); |
| | | } catch (error) { |
| | | proxy?.$modal?.msgError("ä¸ä¼ 失败"); |
| | | } |
| | | createAttachment({ |
| | | application: "file", |
| | | recordType: props.recordType, |
| | | recordId: props.recordId, |
| | | storageBlobDTOs: [...newFileList.value, ...tableData.value], |
| | | }).then((res) => { |
| | | if (res && res.code === 200) { |
| | | proxy?.$modal?.msgSuccess("ä¸ä¼ æå"); |
| | | newFileList.value = []; |
| | | // å·æ°å表 |
| | | setList(); |
| | | } |
| | | }).finally(() => { |
| | | uploadDialogVisible.value = false; |
| | | }) |
| | | } |
| | | uploadDialogVisible.value = false; |
| | | }; |
| | | } |
| | | |
| | | const closeUpload = () => { |
| | | newFileList.value = []; |
| | |
| | | }; |
| | | |
| | | const handleDelete = async (row, index) => { |
| | | try { |
| | | await deleteAttachment([row.storageAttachmentId]); |
| | | proxy?.$modal?.msgSuccess("å 餿å"); |
| | | setList(); |
| | | } catch (error) { |
| | | proxy?.$modal?.msgError("å é¤å¤±è´¥"); |
| | | } |
| | | deleteAttachment([row.storageAttachmentId]).then((res) => { |
| | | if (res && res.code === 200) { |
| | | proxy?.$modal?.msgSuccess("å 餿å"); |
| | | setList(); |
| | | } |
| | | }) |
| | | }; |
| | | |
| | | const setList = () => { |
| | |
| | | recordType: props.recordType, |
| | | recordId: props.recordId, |
| | | }).then(res => { |
| | | if (res && res.data) { |
| | | tableData.value = res.data || []; |
| | | } |
| | | tableData.value = (res && res.data) || []; |
| | | }); |
| | | }; |
| | | |
| | |
| | | <template>
|
| | | <div style="padding: 0 15px;" @click="toggleClick">
|
| | | <svg
|
| | | :class="{'is-active':isActive}"
|
| | | class="hamburger"
|
| | | <template> |
| | | <div class="hamburger-wrap" @click="toggleClick"> |
| | | <svg |
| | | :class="{'is-active':isActive}" |
| | | class="hamburger" |
| | | viewBox="0 0 1024 1024"
|
| | | xmlns="http://www.w3.org/2000/svg"
|
| | | width="64"
|
| | |
| | | }
|
| | | </script>
|
| | |
|
| | | <style scoped>
|
| | | .hamburger {
|
| | | display: inline-block;
|
| | | vertical-align: middle;
|
| | | width: 20px;
|
| | | height: 20px;
|
| | | }
|
| | |
|
| | | .hamburger.is-active {
|
| | | transform: rotate(180deg);
|
| | | }
|
| | | <style scoped> |
| | | .hamburger-wrap { |
| | | width: 100%; |
| | | height: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .hamburger { |
| | | display: inline-block; |
| | | vertical-align: middle; |
| | | width: 22px; |
| | | height: 22px; |
| | | } |
| | | |
| | | .hamburger.is-active { |
| | | transform: rotate(180deg); |
| | | } |
| | | </style>
|
| | |
| | | <template>
|
| | | <div class="header-search">
|
| | | <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
|
| | | <el-dialog
|
| | | v-model="show"
|
| | | width="600"
|
| | | @close="close"
|
| | | :show-close="false"
|
| | | append-to-body
|
| | | >
|
| | | <el-dialog |
| | | v-model="show" |
| | | width="600" |
| | | @close="close" |
| | | :show-close="true" |
| | | append-to-body |
| | | > |
| | | <el-input
|
| | | v-model="search"
|
| | | ref="headerSearchSelectRef"
|
| | |
| | | </div>
|
| | | </template>
|
| | |
|
| | | <script setup>
|
| | | import Fuse from 'fuse.js'
|
| | | import { getNormalPath } from '@/utils/ruoyi'
|
| | | import { isHttp } from '@/utils/validate'
|
| | | import usePermissionStore from '@/store/modules/permission'
|
| | |
|
| | | const search = ref('')
|
| | | const options = ref([])
|
| | | const searchPool = ref([])
|
| | | const show = ref(false)
|
| | | <script setup> |
| | | import Fuse from 'fuse.js' |
| | | import { getNormalPath } from '@/utils/ruoyi' |
| | | import { isHttp } from '@/utils/validate' |
| | | import usePermissionStore from '@/store/modules/permission' |
| | | |
| | | const props = defineProps({ |
| | | keyword: { |
| | | type: String, |
| | | default: '' |
| | | } |
| | | }) |
| | | |
| | | const search = ref('') |
| | | const options = ref([]) |
| | | const searchPool = ref([]) |
| | | const show = ref(false) |
| | | const fuse = ref(undefined)
|
| | | const headerSearchSelectRef = ref(null)
|
| | | const router = useRouter()
|
| | | const routes = computed(() => usePermissionStore().defaultRoutes)
|
| | |
|
| | | function click() {
|
| | | show.value = !show.value
|
| | | if (show.value) {
|
| | | headerSearchSelectRef.value && headerSearchSelectRef.value.focus()
|
| | | options.value = searchPool.value
|
| | | }
|
| | | }
|
| | | function click() { |
| | | show.value = !show.value |
| | | if (show.value) { |
| | | syncSearchFromKeyword() |
| | | nextTick(() => { |
| | | headerSearchSelectRef.value && headerSearchSelectRef.value.focus() |
| | | }) |
| | | } |
| | | } |
| | | |
| | | function syncSearchFromKeyword() { |
| | | search.value = props.keyword?.trim?.() ?? '' |
| | | querySearch(search.value) |
| | | } |
| | | |
| | | function open(keyword = props.keyword) { |
| | | show.value = true |
| | | search.value = keyword?.trim?.() ?? '' |
| | | querySearch(search.value) |
| | | nextTick(() => { |
| | | headerSearchSelectRef.value && headerSearchSelectRef.value.focus() |
| | | }) |
| | | } |
| | |
|
| | | function close() {
|
| | | headerSearchSelectRef.value && headerSearchSelectRef.value.blur()
|
| | |
| | | searchPool.value = generateRoutes(routes.value)
|
| | | })
|
| | |
|
| | | watch(searchPool, (list) => {
|
| | | initFuse(list)
|
| | | })
|
| | | </script>
|
| | | watch(searchPool, (list) => { |
| | | initFuse(list) |
| | | }) |
| | | |
| | | defineExpose({ |
| | | open |
| | | }) |
| | | </script> |
| | |
|
| | | <style lang='scss' scoped>
|
| | | .header-search {
|
| | |
| | | </el-form-item> |
| | | <el-form-item label="æ åå¼"> |
| | | <el-input v-model="selectedParam.standardValue" |
| | | @input="val => onStandardValueInput(val, selectedParam)" |
| | | placeholder="请è¾å
¥é»è®¤å¼" /> |
| | | </el-form-item> |
| | | <el-form-item label="æ¯å¦å¿
å¡«"> |
| | |
| | | </div> |
| | | </div> |
| | | <template #footer> |
| | | <el-button type="primary" @click="handleParamSelectSubmit">ç¡®å®</el-button> |
| | | <el-button type="primary" |
| | | @click="handleParamSelectSubmit">ç¡®å®</el-button> |
| | | <el-button @click="selectParamDialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </el-dialog> |
| | |
| | | <el-form-item label="æ åå¼" |
| | | prop="standardValue"> |
| | | <el-input v-model="editParamForm.standardValue" |
| | | @input="val => onStandardValueInput(val, editParamForm)" |
| | | placeholder="请è¾å
¥æ åå¼" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button type="primary" @click="handleEditParamSubmit">ç¡®å®</el-button> |
| | | <el-button type="primary" |
| | | @click="handleEditParamSubmit">ç¡®å®</el-button> |
| | | <el-button @click="editParamDialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </el-dialog> |
| | |
| | | paramFormat: "", |
| | | unit: "", |
| | | }); |
| | | |
| | | const onStandardValueInput = (val, target) => { |
| | | const data = target.value || target; |
| | | const type = data.paramType || data.parameterType; |
| | | if (type === 1) { |
| | | // æ°å¼æ ¼å¼ï¼ä¸è½è¾å
¥ä¸ææè±æå符 |
| | | data.standardValue = val.replace(/[a-zA-Z\u4e00-\u9fa5]/g, ""); |
| | | } |
| | | }; |
| | | |
| | | const editParamRules = ref({ |
| | | // standardValue: [{ required: true, message: "请è¾å
¥æ åå¼", trigger: "blur" }], |
| | | standardValue: [ |
| | | { |
| | | validator: (rule, value, callback) => { |
| | | const type = |
| | | editParamForm.value.paramType || editParamForm.value.parameterType; |
| | | if (type === 1 && value) { |
| | | if (/[a-zA-Z\u4e00-\u9fa5]/.test(value)) { |
| | | return callback(new Error("æ°å¼æ ¼å¼ä¸è½å
å«ä¸è±æå符")); |
| | | } |
| | | } |
| | | callback(); |
| | | }, |
| | | trigger: "blur", |
| | | }, |
| | | ], |
| | | }); |
| | | const editParamFormRef = ref(null); |
| | | |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ShoppingCart } from '@element-plus/icons-vue' |
| | | import AIChatSidebar from '@/components/AIChatSidebar/index.vue' |
| | | import { purchaseAssistant } from '@/components/AIChatSidebar/assistants' |
| | | |
| | | const assistants = [ |
| | | { |
| | | key: 'purchase', |
| | | label: 'éè´å©ç', |
| | | title: 'éè´æºè½å©ç', |
| | | tooltip: 'éè´æºè½å©ç', |
| | | icon: ShoppingCart, |
| | | apiBase: '/purchase-ai', |
| | | storageKey: 'purchase_ai_chat_uuid', |
| | | placeholder: '请è¾å
¥éè´é®é¢... (Enter åé, Shift+Enter æ¢è¡)', |
| | | welcomeMessage: 'ä½ å¥½', |
| | | allowFileUpload: true, |
| | | allowMultipleFileUpload: true, |
| | | fileAnalyzeUrl: '/purchase-ai/analyze-files', |
| | | emptySessionText: 'ææ éè´ä¼è¯' |
| | | } |
| | | ] |
| | | const assistants = [purchaseAssistant] |
| | | </script> |
| | |
| | | transformData: (workbookData) => workbookData, |
| | | }); |
| | | |
| | | // 计ç®å±æ§ - 夿æä»¶ç±»å |
| | | // 计ç®å±æ§ - 夿æä»¶ç±»åï¼æ¯æURL带æ¥è¯¢åæ°ï¼ |
| | | const isImage = computed(() => { |
| | | const state = /\.(jpg|jpeg|png|gif)$/i.test(fileUrl.value); |
| | | const state = /\.(jpg|jpeg|png|gif)(\?.*)?$/i.test(fileUrl.value); |
| | | if (state) { |
| | | imgUrl.value = fileUrl.value.replaceAll('word', 'img'); |
| | | } |
| | |
| | | |
| | | const isPdf = computed(() => { |
| | | console.log(fileUrl.value) |
| | | return /\.pdf$/i.test(fileUrl.value); |
| | | return /\.pdf(\?.*)?$/i.test(fileUrl.value); |
| | | }); |
| | | |
| | | const isDoc = computed(() => { |
| | | return /\.(doc|docx)$/i.test(fileUrl.value); |
| | | return /\.(doc|docx)(\?.*)?$/i.test(fileUrl.value); |
| | | }); |
| | | |
| | | const isXls = computed(() => { |
| | | const state = /\.(xls|xlsx)$/i.test(fileUrl.value); |
| | | const state = /\.(xls|xlsx)(\?.*)?$/i.test(fileUrl.value); |
| | | if (state) { |
| | | options.value.xls = /\.(xls)$/i.test(fileUrl.value); |
| | | options.value.xls = /\.(xls)(\?.*)?$/i.test(fileUrl.value); |
| | | } |
| | | return state; |
| | | }); |
| | | |
| | | const isZipOrRar = computed(() => { |
| | | return /\.(zip|rar)$/i.test(fileUrl.value); |
| | | return /\.(zip|rar)(\?.*)?$/i.test(fileUrl.value); |
| | | }); |
| | | |
| | | const isSupported = computed(() => { |
| | |
| | | }; |
| | | |
| | | const open = (url) => { |
| | | fileUrl.value = window.location.protocol+'//'+window.location.host+ url; |
| | | fileUrl.value = url; |
| | | dialogVisible.value = true; |
| | | }; |
| | | const handleClose = () => { |
| | |
| | | </script>
|
| | |
|
| | | <style lang="scss" scoped>
|
| | | .app-main {
|
| | | /* 50= navbar 50 */
|
| | | min-height: calc(100vh - 50px);
|
| | | width: 100%;
|
| | | position: relative;
|
| | | overflow: hidden;
|
| | | background: transparent;
|
| | | }
|
| | |
|
| | | .route-view-wrapper {
|
| | | width: 100%;
|
| | | height: 100%;
|
| | | padding: 120px 16px 24px 0;
|
| | | }
|
| | |
|
| | | .fixed-header + .app-main {
|
| | | padding-top: 0;
|
| | | }
|
| | |
|
| | | .hasTagsView {
|
| | | .app-main {
|
| | | /* 84 = navbar + tags-view = 50 + 34 */
|
| | | min-height: calc(100vh - 84px);
|
| | | }
|
| | | .app-main { |
| | | min-height: calc(100vh - var(--topbar-height)); |
| | | width: 100%; |
| | | position: relative; |
| | | overflow: visible; |
| | | background: transparent; |
| | | } |
| | | |
| | | .route-view-wrapper { |
| | | width: 100%; |
| | | height: 100%; |
| | | padding: var(--content-gap); |
| | | padding-top: 0; |
| | | } |
| | | |
| | | .fixed-header + .app-main { |
| | | padding-top: 0; |
| | | } |
| | | |
| | | .hasTagsView { |
| | | .app-main { |
| | | min-height: calc(100vh - var(--topbar-height) - var(--tagsbar-height)); |
| | | } |
| | |
|
| | | .fixed-header + .app-main {
|
| | | padding-top: 0;
|
| | |
| | | <template>
|
| | | <div class="navbar">
|
| | | <div>
|
| | | <hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container"
|
| | | @toggleClick="toggleSideBar" />
|
| | | <breadcrumb v-if="!settingsStore.topNav" id="breadcrumb-container" class="breadcrumb-container" />
|
| | | <div class="left-zone">
|
| | | <hamburger
|
| | | id="hamburger-container"
|
| | | :is-active="appStore.sidebar.opened"
|
| | | class="hamburger-container"
|
| | | @toggleClick="toggleSideBar"
|
| | | />
|
| | | <breadcrumb
|
| | | v-if="!settingsStore.topNav"
|
| | | id="breadcrumb-container"
|
| | | class="breadcrumb-container"
|
| | | />
|
| | | </div>
|
| | | <!-- <top-nav v-if="settingsStore.topNav" id="topmenu-container" class="topmenu-container" />-->
|
| | |
|
| | | <div class="center-zone">
|
| | | <el-icon class="search-icon" @click="openHeaderSearch"><Search /></el-icon>
|
| | | <el-input
|
| | | v-model="topSearchKeyword"
|
| | | placeholder="æç´¢èå / åè½ / æ°æ®"
|
| | | clearable
|
| | | @keyup.enter="openHeaderSearch"
|
| | | />
|
| | | <header-search
|
| | | ref="headerSearchRef"
|
| | | :keyword="topSearchKeyword"
|
| | | class="search-popup-trigger"
|
| | | />
|
| | | </div>
|
| | |
|
| | | <div class="right-menu">
|
| | | <!-- æ¶æ¯éç¥ -->
|
| | | <el-popover
|
| | | v-model:visible="notificationVisible"
|
| | | :width="500"
|
| | |
| | | <template #reference>
|
| | | <div class="notification-container right-menu-item hover-effect">
|
| | | <el-badge :value="unreadCount" :hidden="unreadCount === 0" class="notification-badge">
|
| | | <el-icon :size="20" style="cursor: pointer;">
|
| | | <el-icon :size="18">
|
| | | <Bell />
|
| | | </el-icon>
|
| | | </el-badge>
|
| | | </div>
|
| | | </template>
|
| | | <NotificationCenter
|
| | | @unreadCountChange="handleUnreadCountChange"
|
| | | ref="notificationCenterRef"
|
| | | />
|
| | | <NotificationCenter @unreadCountChange="handleUnreadCountChange" ref="notificationCenterRef" />
|
| | | </el-popover>
|
| | |
|
| | | <div class="right-menu-item hover-effect screenfull-container">
|
| | | <screenfull />
|
| | | </div>
|
| | |
|
| | | <div class="avatar-container">
|
| | | <el-dropdown @command="handleCommand" class="right-menu-item hover-effect" trigger="click">
|
| | | <div class="avatar-wrapper">
|
| | | <div class="user-summary">
|
| | | <div class="user-name">{{ userStore.nickName || userStore.name || "管çå" }}</div>
|
| | | <div class="user-role">{{ userStore.roleName || "ç³»ç»ç¨æ·" }}</div>
|
| | | </div>
|
| | | <img :src="userStore.avatar" class="user-avatar" />
|
| | | <el-icon><caret-bottom /></el-icon>
|
| | | </div>
|
| | |
| | | </template>
|
| | |
|
| | | <script setup>
|
| | | import { ElMessageBox } from 'element-plus'
|
| | | import { Bell } from '@element-plus/icons-vue'
|
| | | import Breadcrumb from '@/components/Breadcrumb'
|
| | | import TopNav from '@/components/TopNav'
|
| | | import Hamburger from '@/components/Hamburger'
|
| | | import Screenfull from '@/components/Screenfull'
|
| | | import SizeSelect from '@/components/SizeSelect'
|
| | | import HeaderSearch from '@/components/HeaderSearch'
|
| | | import RuoYiGit from '@/components/RuoYi/Git'
|
| | | import RuoYiDoc from '@/components/RuoYi/Doc'
|
| | | import NotificationCenter from './NotificationCenter/index.vue'
|
| | | import useAppStore from '@/store/modules/app'
|
| | | import useUserStore from '@/store/modules/user'
|
| | | import useSettingsStore from '@/store/modules/settings'
|
| | | import { ElMessageBox } from "element-plus";
|
| | | import { Bell, Search } from "@element-plus/icons-vue";
|
| | | import Breadcrumb from "@/components/Breadcrumb";
|
| | | import Hamburger from "@/components/Hamburger";
|
| | | import Screenfull from "@/components/Screenfull";
|
| | | import HeaderSearch from "@/components/HeaderSearch";
|
| | | import NotificationCenter from "./NotificationCenter/index.vue";
|
| | | import useAppStore from "@/store/modules/app";
|
| | | import useUserStore from "@/store/modules/user";
|
| | | import useSettingsStore from "@/store/modules/settings";
|
| | |
|
| | | const appStore = useAppStore()
|
| | | const userStore = useUserStore()
|
| | | const settingsStore = useSettingsStore()
|
| | | const notificationVisible = ref(false)
|
| | | const notificationCenterRef = ref(null)
|
| | | const unreadCount = ref(0)
|
| | | const appStore = useAppStore();
|
| | | const userStore = useUserStore();
|
| | | const settingsStore = useSettingsStore();
|
| | |
|
| | | const topSearchKeyword = ref("");
|
| | | const headerSearchRef = ref(null);
|
| | | const notificationVisible = ref(false);
|
| | | const notificationCenterRef = ref(null);
|
| | | const unreadCount = ref(0);
|
| | |
|
| | | function toggleSideBar() {
|
| | | appStore.toggleSideBar()
|
| | | appStore.toggleSideBar();
|
| | | }
|
| | | // const redirect = ref(undefined)
|
| | | // watch(route, (newRoute) => {
|
| | | // redirect.value = newRoute.query && newRoute.query.redirect
|
| | | // }, { immediate: true })
|
| | |
|
| | | function openHeaderSearch() {
|
| | | headerSearchRef.value?.open(topSearchKeyword.value);
|
| | | }
|
| | |
|
| | | function handleCommand(command) {
|
| | | switch (command) {
|
| | | case "setLayout":
|
| | | setLayout()
|
| | | break
|
| | | setLayout();
|
| | | break;
|
| | | case "logout":
|
| | | logout()
|
| | | break
|
| | | logout();
|
| | | break;
|
| | | default:
|
| | | break
|
| | | break;
|
| | | }
|
| | | }
|
| | |
|
| | | function logout() {
|
| | | ElMessageBox.confirm('ç¡®å®æ³¨éå¹¶éåºç³»ç»åï¼', 'æç¤º', {
|
| | | confirmButtonText: 'ç¡®å®',
|
| | | cancelButtonText: 'åæ¶',
|
| | | type: 'warning'
|
| | | }).then(() => {
|
| | | userStore.logOut().then(() => {
|
| | | location.href = '/index'
|
| | | ElMessageBox.confirm("ç¡®å®æ³¨éå¹¶éåºç³»ç»åï¼", "æç¤º", {
|
| | | confirmButtonText: "ç¡®å®",
|
| | | cancelButtonText: "åæ¶",
|
| | | type: "warning",
|
| | | })
|
| | | .then(() => {
|
| | | userStore.logOut().then(() => {
|
| | | location.href = "/index";
|
| | | });
|
| | | })
|
| | | }).catch(() => { })
|
| | | .catch(() => {});
|
| | | }
|
| | |
|
| | | const emits = defineEmits(['setLayout'])
|
| | | const emits = defineEmits(["setLayout"]);
|
| | | function setLayout() {
|
| | | emits('setLayout')
|
| | | emits("setLayout");
|
| | | }
|
| | |
|
| | | function toggleTheme() {
|
| | | settingsStore.toggleTheme()
|
| | | }
|
| | |
|
| | | // æ¶æ¯éç¥ç¸å
³
|
| | | function handleUnreadCountChange(count) {
|
| | | unreadCount.value = count
|
| | | unreadCount.value = count;
|
| | | }
|
| | |
|
| | | // ç»ä»¶æè½½æ¶å è½½æªè¯»æ°éå宿¶å·æ°
|
| | | let unreadCountTimer = null
|
| | | let unreadCountTimer = null;
|
| | | onMounted(() => {
|
| | | // å»¶è¿å è½½ï¼ç¡®ä¿ç»ä»¶å·²æ¸²æ
|
| | | nextTick(() => {
|
| | | if (notificationCenterRef.value) {
|
| | | notificationCenterRef.value.loadUnreadCount()
|
| | | notificationCenterRef.value.loadUnreadCount();
|
| | | }
|
| | | })
|
| | | // 宿¶å·æ°æªè¯»æ°éï¼æ¯30ç§ï¼
|
| | | });
|
| | |
|
| | | unreadCountTimer = setInterval(() => {
|
| | | if (notificationCenterRef.value) {
|
| | | notificationCenterRef.value.loadUnreadCount()
|
| | | notificationCenterRef.value.loadUnreadCount();
|
| | | }
|
| | | }, 30000)
|
| | | })
|
| | | }, 30000);
|
| | | });
|
| | |
|
| | | // çå¬ popover æ¾ç¤ºç¶æï¼æå¼æ¶å è½½æ¶æ¯å表
|
| | | watch(notificationVisible, (val) => {
|
| | | if (val && notificationCenterRef.value) {
|
| | | nextTick(() => {
|
| | | notificationCenterRef.value.loadMessages()
|
| | | })
|
| | | notificationCenterRef.value.loadMessages();
|
| | | });
|
| | | }
|
| | | })
|
| | | });
|
| | |
|
| | | onUnmounted(() => {
|
| | | if (unreadCountTimer) {
|
| | | clearInterval(unreadCountTimer)
|
| | | clearInterval(unreadCountTimer);
|
| | | }
|
| | | })
|
| | | });
|
| | | </script>
|
| | |
|
| | | <style lang='scss' scoped>
|
| | | .navbar { |
| | | height: 56px; |
| | | overflow: hidden; |
| | | position: relative; |
| | | background: var(--navbar-bg); |
| | | border: 1px solid rgba(216, 225, 219, 0.9); |
| | | border-radius: 22px; |
| | | backdrop-filter: blur(18px); |
| | | box-shadow: var(--shadow-sm); |
| | | padding: 0 18px; |
| | | <style lang="scss" scoped>
|
| | | .navbar {
|
| | | height: var(--topbar-height);
|
| | | display: flex;
|
| | | align-items: center;
|
| | | justify-content: space-between;
|
| | | gap: 14px;
|
| | | background: rgba(255, 255, 255, 0.86);
|
| | | border: 1px solid rgba(148, 163, 184, 0.18);
|
| | | border-radius: var(--content-radius);
|
| | | backdrop-filter: blur(16px);
|
| | | box-shadow: 0 8px 20px rgba(15, 23, 42, 0.05);
|
| | | padding: 0 18px;
|
| | | }
|
| | |
|
| | | .hamburger-container {
|
| | | line-height: 52px; |
| | | height: 100%;
|
| | | float: left;
|
| | | cursor: pointer;
|
| | | transition: background 0.3s;
|
| | | -webkit-tap-highlight-color: transparent;
|
| | | .left-zone {
|
| | | flex: 0 1 420px;
|
| | | min-width: 0;
|
| | | display: flex;
|
| | | align-items: center;
|
| | | gap: 10px;
|
| | | }
|
| | |
|
| | | &:hover {
|
| | | background: var(--navbar-hover); |
| | | }
|
| | | }
|
| | | .hamburger-container {
|
| | | line-height: 36px;
|
| | | height: 36px;
|
| | | width: 36px;
|
| | | border-radius: 10px;
|
| | | display: flex;
|
| | | align-items: center;
|
| | | justify-content: center;
|
| | | color: var(--navbar-text);
|
| | |
|
| | | .breadcrumb-container {
|
| | | float: left;
|
| | | }
|
| | |
|
| | | .topmenu-container {
|
| | | position: absolute;
|
| | | left: 50px;
|
| | | }
|
| | |
|
| | | .errLog-container {
|
| | | display: inline-block;
|
| | | vertical-align: top;
|
| | | }
|
| | |
|
| | | .right-menu { |
| | | float: right; |
| | | height: 100%; |
| | | align-items: center; |
| | | display: flex; |
| | |
|
| | | &:focus {
|
| | | outline: none;
|
| | | }
|
| | |
|
| | | .right-menu-item { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 0 8px; |
| | | height: 100%; |
| | | font-size: 18px; |
| | | color: var(--navbar-text); |
| | | border-radius: 14px; |
| | |
|
| | | &.hover-effect {
|
| | | cursor: pointer;
|
| | | transition: background 0.3s;
|
| | |
|
| | | &:hover {
|
| | | background: var(--navbar-hover); |
| | | }
|
| | | }
|
| | |
|
| | | &.theme-switch-wrapper {
|
| | | display: flex;
|
| | | align-items: center;
|
| | |
|
| | | svg {
|
| | | transition: transform 0.3s;
|
| | |
|
| | | &:hover {
|
| | | transform: scale(1.15);
|
| | | }
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | .notification-container {
|
| | | margin-right: 12px; |
| | | display: flex;
|
| | | align-items: center;
|
| | | cursor: pointer;
|
| | |
|
| | | .notification-badge {
|
| | | :deep(.el-badge__content) {
|
| | | border: none;
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | .avatar-container { |
| | | margin-right: 4px; |
| | | height: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | :deep(.el-dropdown) { |
| | | height: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .avatar-wrapper { |
| | | position: relative; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 10px; |
| | | padding: 6px 10px 6px 6px; |
| | | height: 44px; |
| | | border-radius: 999px; |
| | | background: rgba(247, 250, 248, 0.92); |
| | | border: 1px solid var(--surface-border); |
| | | |
| | | .user-avatar { |
| | | cursor: pointer; |
| | | width: 34px; |
| | | height: 34px; |
| | | border-radius: 50px; |
| | | } |
| | | |
| | | i { |
| | | cursor: pointer; |
| | | position: static; |
| | | font-size: 12px; |
| | | } |
| | | } |
| | | }
|
| | | &:hover {
|
| | | background: var(--navbar-hover);
|
| | | }
|
| | | }
|
| | |
|
| | | .breadcrumb-container {
|
| | | min-width: 0;
|
| | | }
|
| | |
|
| | | .center-zone {
|
| | | width: clamp(360px, 34vw, 560px);
|
| | | min-width: 320px;
|
| | | height: 38px;
|
| | | border-radius: 999px;
|
| | | border: 1px solid rgba(148, 163, 184, 0.24);
|
| | | background: rgba(248, 251, 255, 0.92);
|
| | | display: flex;
|
| | | align-items: center;
|
| | | padding: 0 12px;
|
| | | gap: 8px;
|
| | | }
|
| | |
|
| | | .search-icon {
|
| | | color: #5b86c9;
|
| | | cursor: pointer;
|
| | | }
|
| | |
|
| | | .center-zone :deep(.el-input__wrapper) {
|
| | | border: 0;
|
| | | box-shadow: none !important;
|
| | | background: transparent;
|
| | | padding: 0;
|
| | | }
|
| | |
|
| | | .center-zone :deep(.el-input__inner) {
|
| | | color: #334155;
|
| | | font-size: 13px;
|
| | | }
|
| | |
|
| | | .search-popup-trigger :deep(.search-icon) {
|
| | | color: #5b86c9;
|
| | | font-size: 16px;
|
| | | cursor: pointer;
|
| | | }
|
| | |
|
| | | .right-menu {
|
| | | height: 100%;
|
| | | align-items: center;
|
| | | display: flex;
|
| | | gap: 14px;
|
| | | }
|
| | |
|
| | | .right-menu-item {
|
| | | display: flex;
|
| | | align-items: center;
|
| | | justify-content: center;
|
| | | color: var(--navbar-text);
|
| | | border-radius: 8px;
|
| | | }
|
| | |
|
| | | .hover-effect {
|
| | | cursor: pointer;
|
| | | transition: background 0.2s;
|
| | |
|
| | | &:hover {
|
| | | background: var(--navbar-hover);
|
| | | }
|
| | | }
|
| | |
|
| | | .notification-container,
|
| | | .screenfull-container {
|
| | | width: 36px;
|
| | | height: 36px;
|
| | | }
|
| | |
|
| | | .notification-badge :deep(.el-badge__content) {
|
| | | border: none;
|
| | | }
|
| | |
|
| | | .screenfull-container :deep(.svg-icon) {
|
| | | width: 16px;
|
| | | height: 16px;
|
| | | color: var(--navbar-text);
|
| | | }
|
| | |
|
| | | .avatar-container {
|
| | | height: 100%;
|
| | | display: flex;
|
| | | align-items: center;
|
| | | }
|
| | |
|
| | | .avatar-container :deep(.el-dropdown) {
|
| | | height: 100%;
|
| | | display: flex;
|
| | | align-items: center;
|
| | | }
|
| | |
|
| | | .avatar-wrapper {
|
| | | display: flex;
|
| | | align-items: center;
|
| | | gap: 10px;
|
| | | padding: 4px 10px 4px 8px;
|
| | | height: 44px;
|
| | | border-radius: 22px;
|
| | | background: rgba(255, 255, 255, 0.9);
|
| | | border: 1px solid rgba(148, 163, 184, 0.22);
|
| | | }
|
| | |
|
| | | .user-summary {
|
| | | display: flex;
|
| | | flex-direction: column;
|
| | | align-items: flex-end;
|
| | | gap: 2px;
|
| | | }
|
| | |
|
| | | .user-name {
|
| | | color: var(--text-primary);
|
| | | font-size: 13px;
|
| | | line-height: 1;
|
| | | }
|
| | |
|
| | | .user-role {
|
| | | color: var(--text-tertiary);
|
| | | font-size: 11px;
|
| | | line-height: 1;
|
| | | }
|
| | |
|
| | | .user-avatar {
|
| | | cursor: pointer;
|
| | | width: 36px;
|
| | | height: 36px;
|
| | | border-radius: 50%;
|
| | | border: 1px solid rgba(148, 163, 184, 0.3);
|
| | | }
|
| | |
|
| | | @media (max-width: 1200px) {
|
| | | .center-zone {
|
| | | display: none;
|
| | | }
|
| | |
|
| | | .user-summary {
|
| | | display: none;
|
| | | }
|
| | | }
|
| | | </style>
|
| | |
|
| | | <style lang="scss">
|
| | | .notification-popover { |
| | | padding: 0 !important; |
| | | border-radius: 20px !important; |
| | | border: 1px solid var(--surface-border) !important; |
| | | box-shadow: var(--shadow-md) !important; |
| | | |
| | | .notification-popover {
|
| | | padding: 0 !important;
|
| | | border-radius: 16px !important;
|
| | | border: 1px solid rgba(148, 163, 184, 0.22) !important;
|
| | | box-shadow: 0 18px 40px rgba(15, 23, 42, 0.12) !important;
|
| | | background: rgba(255, 255, 255, 0.94) !important;
|
| | | backdrop-filter: blur(16px);
|
| | |
|
| | | .el-popover__title {
|
| | | display: none;
|
| | | }
|
| | | |
| | |
|
| | | .el-popover__body {
|
| | | padding: 0 !important;
|
| | | }
|
| | | }
|
| | | .el-badge__content.is-fixed{
|
| | | top: 12px;
|
| | |
|
| | | .el-badge__content.is-fixed {
|
| | | top: 8px;
|
| | | }
|
| | | </style>
|
| | |
| | | flex-direction: column; |
| | | width: 500px; |
| | | padding: 16px; |
| | | background: rgba(255, 255, 255, 0.92); |
| | | } |
| | | |
| | | .popover-header { |
| | |
| | | width: 100%; |
| | | margin-bottom: 16px; |
| | | padding-bottom: 12px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | border-bottom: 1px solid var(--surface-border); |
| | | |
| | | .popover-title { |
| | | font-size: 18px; |
| | | font-weight: 500; |
| | | color: #303133; |
| | | color: var(--text-primary); |
| | | } |
| | | } |
| | | |
| | |
| | | .notification-item { |
| | | display: flex; |
| | | padding: 12px 0; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | border-bottom: 1px solid rgba(148, 163, 184, 0.18); |
| | | transition: background-color 0.3s; |
| | | |
| | | &:hover { |
| | | background-color: #f5f7fa; |
| | | background-color: #f8fbff; |
| | | } |
| | | |
| | | &.read { |
| | |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background-color: #f0f9ff; |
| | | background-color: rgba(59, 130, 246, 0.12); |
| | | border-radius: 50%; |
| | | margin-right: 12px; |
| | | } |
| | |
| | | .notification-title { |
| | | font-size: 14px; |
| | | font-weight: 500; |
| | | color: #303133; |
| | | color: var(--text-primary); |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .notification-detail { |
| | | font-size: 13px; |
| | | color: #606266; |
| | | color: var(--text-secondary); |
| | | line-height: 1.5; |
| | | margin-bottom: 8px; |
| | | word-break: break-all; |
| | |
| | | |
| | | .notification-time { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | color: var(--text-tertiary); |
| | | } |
| | | } |
| | | |
| | |
| | | .pagination-wrapper { |
| | | margin-top: 16px; |
| | | padding-top: 16px; |
| | | border-top: 1px solid #f0f0f0; |
| | | border-top: 1px solid var(--surface-border); |
| | | display: flex; |
| | | justify-content: center; |
| | | padding-left: 0; |
| | |
| | | <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/"> |
| | | <img :src="faviconUrl" class="sidebar-logo sidebar-favicon" alt="ç«ç¹å¾æ " /> |
| | | </router-link> |
| | | <router-link v-else key="expand" class="sidebar-logo-link" to="/"> |
| | | <router-link v-else key="expand" class="sidebar-logo-link" :style="expandLogoLinkStyle" to="/"> |
| | | <img v-if="logoUrl" :src="logoUrl" class="sidebar-logo" @error="handleImageError" alt="å
¬å¸Logo" /> |
| | | <h1 v-if="!logoUrl" class="sidebar-title">{{ title }}</h1> |
| | | </router-link> |
| | |
| | | }) |
| | | |
| | | const logoUrl = ref('') |
| | | |
| | | const expandLogoLinkStyle = computed(() => { |
| | | if (!logoUrl.value) { |
| | | return { '--logo-bg-image': 'none' } |
| | | } |
| | | const escaped = String(logoUrl.value).replace(/"/g, '\\"') |
| | | return { '--logo-bg-image': `url("${escaped}")` } |
| | | }) |
| | | |
| | | const updateLogoUrl = () => { |
| | | if (!cleanFactoryName.value) { |
| | |
| | | .sidebar-logo-container { |
| | | position: relative; |
| | | width: 100% !important; |
| | | height: 56px !important; |
| | | line-height: 56px; |
| | | background: rgba(255, 255, 255, 0.78); |
| | | border: 1px solid var(--surface-border); |
| | | border-radius: 22px; |
| | | text-align: center; |
| | | height: 78px !important; |
| | | line-height: 78px; |
| | | background: transparent; |
| | | border-bottom: 1px solid rgba(255, 255, 255, 0.08); |
| | | text-align: left; |
| | | overflow: hidden; |
| | | box-shadow: var(--shadow-sm); |
| | | box-shadow: none; |
| | | backdrop-filter: none; |
| | | transition: all 0.3s ease; |
| | | |
| | | .sidebar-logo-link { |
| | | position: relative; |
| | | isolation: isolate; |
| | | height: 100%; |
| | | width: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 0 18px 0 14px; |
| | | padding: 0; |
| | | |
| | | &::before { |
| | | content: ""; |
| | | position: absolute; |
| | | inset: 0; |
| | | background-image: var(--logo-bg-image); |
| | | background-size: cover; |
| | | background-position: center; |
| | | opacity: 0.26; |
| | | filter: blur(8px) saturate(0.9); |
| | | transform: scale(1.06); |
| | | pointer-events: none; |
| | | z-index: 0; |
| | | } |
| | | |
| | | &::after { |
| | | content: ""; |
| | | position: absolute; |
| | | inset: 0; |
| | | background: linear-gradient(180deg, rgba(16, 49, 89, 0.18), rgba(16, 49, 89, 0.08)); |
| | | pointer-events: none; |
| | | z-index: 0; |
| | | } |
| | | } |
| | | |
| | | .sidebar-logo { |
| | | width: auto; |
| | | max-width: 250px; |
| | | max-height: 50px; |
| | | height: auto; |
| | | width: 100%; |
| | | height: 100%; |
| | | max-width: none; |
| | | max-height: none; |
| | | padding: 6px 10px; |
| | | vertical-align: middle; |
| | | object-fit: contain; |
| | | object-position: center; |
| | | filter: none; |
| | | display: block; |
| | | position: relative; |
| | | z-index: 1; |
| | | } |
| | | |
| | | .sidebar-title { |
| | |
| | | font-size: 14px; |
| | | font-family: "Segoe UI", "PingFang SC", sans-serif; |
| | | vertical-align: middle; |
| | | position: relative; |
| | | z-index: 1; |
| | | } |
| | | |
| | | &.collapse { |
| | | .sidebar-logo-link { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 0; |
| | | |
| | | &::before, |
| | | &::after { |
| | | display: none; |
| | | } |
| | | } |
| | | |
| | | .sidebar-logo { |
| | | max-width: 30px; |
| | | max-height: 30px; |
| | | width: calc(100% - 8px); |
| | | height: calc(100% - 8px); |
| | | max-width: none; |
| | | max-height: none; |
| | | padding: 4px; |
| | | margin: 0 auto; |
| | | filter: none; |
| | | object-fit: contain; |
| | | object-position: center; |
| | | } |
| | | |
| | | .sidebar-favicon { |
| | | width: 24px; |
| | | height: 24px; |
| | | max-width: 24px; |
| | | max-height: 24px; |
| | | width: calc(100% - 8px); |
| | | height: calc(100% - 8px); |
| | | max-width: none; |
| | | max-height: none; |
| | | } |
| | | } |
| | | } |
| | |
| | | <template>
|
| | | <div v-if="!item.hidden">
|
| | | <div v-if="!item.hidden" class="sidebar-item-wrapper">
|
| | | <template v-if="hasOneShowingChild(item.children, item) && (!onlyOneChild.children || onlyOneChild.noShowingChildren) && !item.alwaysShow">
|
| | | <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path, onlyOneChild.query)">
|
| | | <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{ 'submenu-title-noDropdown': !isNest }">
|
| | | <svg-icon :icon-class="onlyOneChild.meta.icon || (item.meta && item.meta.icon)"/>
|
| | | <template #title><span class="menu-title" :title="hasTitle(onlyOneChild.meta.title)">{{ onlyOneChild.meta.title }}</span></template>
|
| | | <svg-icon :icon-class="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" class="menu-icon"/>
|
| | | <template #title>
|
| | | <span class="menu-title" :title="hasTitle(onlyOneChild.meta.title)">{{ onlyOneChild.meta.title }}</span>
|
| | | </template>
|
| | | </el-menu-item>
|
| | | </app-link>
|
| | | </template>
|
| | |
|
| | | <el-sub-menu v-else ref="subMenu" :index="resolvePath(item.path)" teleported>
|
| | | <template v-if="item.meta" #title>
|
| | | <svg-icon :icon-class="item.meta && item.meta.icon" />
|
| | | <svg-icon :icon-class="item.meta && item.meta.icon" class="menu-icon" />
|
| | | <span class="menu-title" :title="hasTitle(item.meta.title)">{{ item.meta.title }}</span>
|
| | | </template>
|
| | |
|
| | |
| | | }
|
| | | }
|
| | | </script>
|
| | |
|
| | | <style lang="scss" scoped>
|
| | | .sidebar-item-wrapper { |
| | | :deep(.menu-icon) { |
| | | width: 26px; |
| | | height: 26px; |
| | | margin-right: 12px; |
| | | display: inline-flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | flex-shrink: 0; |
| | | transition: color 0.2s ease; |
| | | color: var(--sidebar-text); |
| | | opacity: 0.88; |
| | | } |
| | | |
| | | :deep(.el-menu-item:hover .menu-icon), |
| | | :deep(.el-sub-menu__title:hover .menu-icon) { |
| | | color: #ffffff; |
| | | opacity: 1; |
| | | } |
| | | |
| | | :deep(.el-menu-item.is-active .menu-icon) {
|
| | | color: var(--menu-active-text) !important;
|
| | | opacity: 1;
|
| | | }
|
| | | |
| | | :deep(.menu-title) { |
| | | font-weight: 500; |
| | | transition: color 0.2s ease; |
| | | color: var(--sidebar-text); |
| | | opacity: 0.82; |
| | | } |
| | | |
| | | :deep(.el-menu-item:hover .menu-title), |
| | | :deep(.el-sub-menu__title:hover .menu-title) { |
| | | color: #ffffff; |
| | | opacity: 1; |
| | | } |
| | | |
| | | :deep(.el-menu-item.is-active .menu-title) { |
| | | color: var(--menu-active-text) !important; |
| | | opacity: 1; |
| | | } |
| | | |
| | | :deep(.nest-menu) { |
| | | .menu-icon { |
| | | width: 22px; |
| | | height: 22px; |
| | | margin-right: 10px; |
| | | } |
| | | |
| | | .menu-title { font-size: 13px; } |
| | | } |
| | | } |
| | | </style>
|
| | |
| | | <template> |
| | | <div :class="{ 'has-logo': showLogo }" |
| | | class="sidebar-container"> |
| | | <logo v-if="showLogo" |
| | | :collapse="isCollapse" /> |
| | | <div :class="{ 'has-logo': showLogo }" class="sidebar-container"> |
| | | <logo v-if="showLogo" :collapse="isCollapse" /> |
| | | <el-scrollbar wrap-class="scrollbar-wrapper"> |
| | | <el-menu :default-active="activeMenu" |
| | | :collapse="isCollapse" |
| | | :background-color="getMenuBackground" |
| | | :text-color="getMenuTextColor" |
| | | :unique-opened="true" |
| | | :active-text-color="theme" |
| | | :collapse-transition="false" |
| | | mode="vertical" |
| | | :class="sideTheme"> |
| | | <sidebar-item v-for="(route, index) in sidebarRouters" |
| | | :key="route.path + index" |
| | | :item="route" |
| | | :base-path="route.path" /> |
| | | <el-menu |
| | | :default-active="activeMenu" |
| | | :collapse="isCollapse" |
| | | :background-color="getMenuBackground" |
| | | :text-color="getMenuTextColor" |
| | | :unique-opened="true" |
| | | :active-text-color="theme" |
| | | :collapse-transition="false" |
| | | mode="vertical" |
| | | :class="sideTheme" |
| | | > |
| | | <sidebar-item |
| | | v-for="(route, index) in sidebarRouters" |
| | | :key="route.path + index" |
| | | :item="route" |
| | | :base-path="route.path" |
| | | /> |
| | | </el-menu> |
| | | </el-scrollbar> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import Logo from "./Logo"; |
| | | import SidebarItem from "./SidebarItem"; |
| | | import variables from "@/assets/styles/variables.module.scss"; |
| | | import useAppStore from "@/store/modules/app"; |
| | | import useSettingsStore from "@/store/modules/settings"; |
| | | import usePermissionStore from "@/store/modules/permission"; |
| | | import Logo from "./Logo"; |
| | | import SidebarItem from "./SidebarItem"; |
| | | import useAppStore from "@/store/modules/app"; |
| | | import useSettingsStore from "@/store/modules/settings"; |
| | | import usePermissionStore from "@/store/modules/permission"; |
| | | |
| | | const route = useRoute(); |
| | | const appStore = useAppStore(); |
| | | const settingsStore = useSettingsStore(); |
| | | const permissionStore = usePermissionStore(); |
| | | const route = useRoute(); |
| | | const appStore = useAppStore(); |
| | | const settingsStore = useSettingsStore(); |
| | | const permissionStore = usePermissionStore(); |
| | | |
| | | const sidebarRouters = computed(() => permissionStore.sidebarRouters); |
| | | const showLogo = computed(() => settingsStore.sidebarLogo); |
| | | const sideTheme = computed(() => settingsStore.sideTheme); |
| | | const theme = computed(() => settingsStore.theme); |
| | | const isCollapse = computed(() => !appStore.sidebar.opened); |
| | | const sidebarRouters = computed(() => permissionStore.sidebarRouters); |
| | | const showLogo = computed(() => settingsStore.sidebarLogo); |
| | | const sideTheme = computed(() => settingsStore.sideTheme); |
| | | const theme = computed(() => settingsStore.theme); |
| | | const isCollapse = computed(() => !appStore.sidebar.opened); |
| | | |
| | | const getMenuBackground = computed(() => "var(--sidebar-bg)"); |
| | | const getMenuBackground = computed(() => "var(--sidebar-bg)"); |
| | | |
| | | const getMenuTextColor = computed(() => { |
| | | if (settingsStore.isDark) { |
| | | return "var(--sidebar-text)"; |
| | | } |
| | | return sideTheme.value === "theme-dark" |
| | | ? variables.menuText |
| | | : variables.menuLightText; |
| | | }); |
| | | const getMenuTextColor = computed(() => "var(--sidebar-text)"); |
| | | |
| | | const activeMenu = computed(() => { |
| | | const { meta, path } = route; |
| | | if (meta.activeMenu) { |
| | | return meta.activeMenu; |
| | | } |
| | | return path; |
| | | }); |
| | | const activeMenu = computed(() => { |
| | | const { meta, path } = route; |
| | | if (meta.activeMenu) return meta.activeMenu; |
| | | return path; |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .sidebar-container { |
| | | background-color: v-bind(getMenuBackground); |
| | | border-radius: 22px; |
| | | overflow: hidden; |
| | | .sidebar-container { |
| | | background: transparent; |
| | | border-radius: 0; |
| | | overflow: hidden; |
| | | |
| | | .scrollbar-wrapper { |
| | | background-color: v-bind(getMenuBackground); |
| | | .scrollbar-wrapper { |
| | | background: transparent; |
| | | } |
| | | |
| | | .el-menu { |
| | | border: none !important; |
| | | height: 100%; |
| | | width: 100% !important; |
| | | border-radius: 0; |
| | | background: transparent !important; |
| | | |
| | | .el-menu-item, |
| | | .el-sub-menu__title { |
| | | margin-bottom: 8px; |
| | | border-radius: 14px; |
| | | color: v-bind(getMenuTextColor); |
| | | font-size: 14px; |
| | | letter-spacing: 0; |
| | | transition: |
| | | transform 0.18s ease, |
| | | background 0.2s ease, |
| | | box-shadow 0.2s ease, |
| | | color 0.2s ease; |
| | | border: none !important; |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | &:hover { |
| | | background: linear-gradient(128deg, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.28), rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.08)) !important; |
| | | transform: translate3d(2px, 0, 0); |
| | | } |
| | | } |
| | | |
| | | .el-menu { |
| | | border: none; |
| | | height: 100%; |
| | | width: 100% !important; |
| | | border-radius: 22px; |
| | | .el-menu-item { |
| | | color: var(--sidebar-text); |
| | | |
| | | .el-menu-item, |
| | | .el-sub-menu__title { |
| | | margin-bottom: 6px; |
| | | &.is-active { |
| | | background: var(--menu-active-bg, linear-gradient(135deg, var(--el-color-primary), var(--el-color-primary-light-3))) !important; |
| | | color: var(--menu-active-text) !important; |
| | | font-weight: 500; |
| | | border-radius: 14px; |
| | | color: v-bind(getMenuTextColor); |
| | | box-shadow: var(--menu-active-glow, 0 10px 24px rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.34)); |
| | | |
| | | &:hover { |
| | | background-color: var(--menu-hover, rgba(0, 0, 0, 0.06)) !important; |
| | | border-radius: 14px; |
| | | .svg-icon { |
| | | color: var(--menu-active-text) !important; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .el-menu-item { |
| | | &.is-active { |
| | | color: v-bind(theme); |
| | | background-color: var(--menu-active-bg, rgba(0, 0, 0, 0.06)) !important; |
| | | font-weight: 600; |
| | | } |
| | | } |
| | | .el-sub-menu__title { |
| | | color: v-bind(getMenuTextColor); |
| | | } |
| | | |
| | | .el-sub-menu__title { |
| | | color: v-bind(getMenuTextColor); |
| | | } |
| | | :deep(.el-sub-menu__icon-arrow) { |
| | | display: inline-flex !important; |
| | | align-items: center; |
| | | justify-content: center; |
| | | width: 14px; |
| | | height: 14px; |
| | | margin-top: -7px; |
| | | right: 14px; |
| | | font-size: 14px !important; |
| | | color: currentColor !important; |
| | | opacity: 0.7; |
| | | transition: transform 0.2s ease, opacity 0.2s ease; |
| | | } |
| | | |
| | | :deep(.el-sub-menu.is-active > .el-sub-menu__title) { |
| | | color: v-bind(theme) !important; |
| | | font-weight: 600; |
| | | background-color: var(--menu-active-bg, rgba(0, 0, 0, 0.06)) !important; |
| | | border-radius: 14px; |
| | | margin: 0 10px 6px !important; |
| | | // width: calc(100% - 20px) !important; |
| | | padding-left: 10px !important; |
| | | padding-right: 10px !important; |
| | | box-sizing: border-box; |
| | | overflow: hidden; |
| | | background-clip: padding-box; |
| | | } |
| | | :deep(.el-sub-menu.is-opened .el-sub-menu__icon-arrow) { |
| | | transform: rotate(180deg); |
| | | } |
| | | |
| | | :deep(.el-menu-item.is-active) { |
| | | margin: 0 10px 6px !important; |
| | | width: calc(100% - 20px) !important; |
| | | padding-left: 10px !important; |
| | | padding-right: 10px !important; |
| | | box-sizing: border-box; |
| | | overflow: hidden; |
| | | background-clip: padding-box; |
| | | border-radius: 14px; |
| | | } |
| | | :deep(.el-sub-menu.is-active > .el-sub-menu__title) { |
| | | color: var(--menu-active-text) !important; |
| | | font-weight: 500; |
| | | border-radius: 12px; |
| | | margin: 0 12px 6px !important; |
| | | padding-left: 14px !important; |
| | | padding-right: 34px !important; |
| | | box-sizing: border-box; |
| | | overflow: hidden; |
| | | background-clip: padding-box; |
| | | background: var(--menu-active-bg) !important; |
| | | box-shadow: var(--menu-active-glow); |
| | | border: none !important; |
| | | } |
| | | |
| | | :deep(.el-sub-menu.is-active > .el-sub-menu__title .menu-title), |
| | | :deep(.el-sub-menu.is-active > .el-sub-menu__title .svg-icon), |
| | | :deep(.el-menu-item.is-active .menu-title), |
| | | :deep(.el-menu-item.is-active .svg-icon) { |
| | | color: v-bind(theme) !important; |
| | | } |
| | | :deep(.el-menu-item.is-active) { |
| | | margin: 0 12px 6px !important; |
| | | width: calc(100% - 24px) !important; |
| | | padding-left: 14px !important; |
| | | padding-right: 34px !important; |
| | | box-sizing: border-box; |
| | | overflow: hidden; |
| | | background-clip: padding-box; |
| | | border-radius: 12px; |
| | | } |
| | | |
| | | :deep(.el-sub-menu__title:hover), |
| | | :deep(.el-menu-item:hover) { |
| | | border-radius: 14px; |
| | | } |
| | | :deep(.el-sub-menu.is-active > .el-sub-menu__title .menu-title), |
| | | :deep(.el-sub-menu.is-active > .el-sub-menu__title .svg-icon), |
| | | :deep(.el-menu-item.is-active .menu-title) { |
| | | color: var(--menu-active-text) !important; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | :deep(.el-scrollbar__bar) {
|
| | | bottom: 0px;
|
| | | }
|
| | | :deep(.el-scrollbar__wrap) {
|
| | | height: 42px;
|
| | | }
|
| | | }
|
| | | </style> |
| | | :deep(.el-scrollbar__wrap) { |
| | | height: var(--tagsbar-height); |
| | | } |
| | | } |
| | | </style> |
| | |
| | |
|
| | | <style lang="scss" scoped>
|
| | | .tags-view-container { |
| | | height: 42px; |
| | | height: var(--tagsbar-height); |
| | | width: 100%; |
| | | margin-top: 10px; |
| | | padding: 4px 10px; |
| | | background: rgba(255, 255, 255, 0.9); |
| | | border: 1px solid rgba(216, 225, 219, 0.92); |
| | | border-radius: 20px; |
| | | backdrop-filter: blur(18px); |
| | | box-shadow: var(--shadow-sm); |
| | | margin-top: 0; |
| | | padding: 0 2px; |
| | | background: transparent; |
| | | border: none; |
| | | border-radius: 0; |
| | | backdrop-filter: none; |
| | | box-shadow: none; |
| | | |
| | | .tags-view-wrapper { |
| | | display: flex; |
| | | align-items: center; |
| | | min-height: 42px; |
| | | min-height: var(--tagsbar-height); |
| | | |
| | | .tags-view-item { |
| | | display: inline-flex; |
| | |
| | | justify-content: center; |
| | | position: relative; |
| | | cursor: pointer; |
| | | height: 34px; |
| | | height: 30px; |
| | | line-height: 1; |
| | | color: var(--tags-item-text, #4E5463); |
| | | background: var(--tags-item-bg, #E5E7EA); |
| | | border: 1px solid var(--tags-item-border, #d8dce5); |
| | | border-radius: 999px; |
| | | padding: 0 16px; |
| | | padding: 0 14px; |
| | | font-size: 12px; |
| | | margin-right: 8px; |
| | | margin-right: 6px; |
| | | flex-shrink: 0; |
| | | gap: 6px; |
| | | transition: all 0.24s ease; |
| | | |
| | | &:hover { |
| | | background: var(--tags-item-hover, #eee); |
| | | border-color: rgba(31, 122, 114, 0.18); |
| | | border-color: rgba(96, 165, 250, 0.36); |
| | | } |
| | | |
| | | &.active { |
| | | background-color: #FFFFFF !important; |
| | | color: var(--el-color-primary); |
| | | box-shadow: 0 10px 24px rgba(31, 122, 114, 0.12); |
| | | border-color: rgba(31, 122, 114, 0.2) !important; |
| | | background-image: linear-gradient(132deg, rgba(47, 128, 255, 0.95), rgba(56, 189, 248, 0.9)); |
| | | color: #fff; |
| | | box-shadow: 0 10px 20px rgba(37, 99, 235, 0.22); |
| | | border-color: rgba(147, 197, 253, 0.72) !important; |
| | | } |
| | | } |
| | | } |
| | |
| | | @click="handleClickOutside" /> |
| | | <sidebar v-if="!sidebar.hide" |
| | | class="sidebar-container" /> |
| | | <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" |
| | | class="main-container"> |
| | | <div :class="{ 'fixed-header': fixedHeader }"> |
| | | <div :class="{ hasTagsView: showTagsView, sidebarHide: sidebar.hide }" |
| | | class="main-container main-layout"> |
| | | <div :class="{ 'fixed-header': fixedHeader, 'with-tags': showTagsView }"> |
| | | <navbar @setLayout="setLayout" /> |
| | | <tags-view v-if="needTagsView" /> |
| | | <tags-view v-if="showTagsView" /> |
| | | </div> |
| | | <app-main /> |
| | | <settings ref="settingRef" /> |
| | | </div> |
| | | <AIChatSidebar v-if="aiEnabled" /> |
| | | <AIChatSidebar v-if="showGlobalAiChat" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { useWindowSize } from "@vueuse/core"; |
| | | import { useRoute } from "vue-router"; |
| | | import Sidebar from "./components/Sidebar/index.vue"; |
| | | import { AppMain, Navbar, Settings, TagsView } from "./components"; |
| | | import AIChatSidebar from "@/components/AIChatSidebar/index.vue"; |
| | |
| | | import useAppStore from "@/store/modules/app"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import useSettingsStore from "@/store/modules/settings"; |
| | | import useTagsViewStore from "@/store/modules/tagsView"; |
| | | |
| | | const settingsStore = useSettingsStore(); |
| | | const tagsViewStore = useTagsViewStore(); |
| | | const userStore = useUserStore(); |
| | | const route = useRoute(); |
| | | const theme = computed(() => settingsStore.theme); |
| | | const sideTheme = computed(() => settingsStore.sideTheme); |
| | | const sidebar = computed(() => useAppStore().sidebar); |
| | | const device = computed(() => useAppStore().device); |
| | | const needTagsView = computed(() => settingsStore.tagsView); |
| | | const showTagsView = computed(() => needTagsView.value && tagsViewStore.visitedViews.length > 1); |
| | | const fixedHeader = computed(() => settingsStore.fixedHeader); |
| | | const aiEnabled = computed(() => Number(userStore.aiEnabled) === 1); |
| | | const showGlobalAiChat = computed(() => { |
| | | const isIndustrialBrainRoute = String(route.path || "").startsWith("/ai-industrial-brain"); |
| | | return !isIndustrialBrainRoute && aiEnabled.value; |
| | | }); |
| | | |
| | | const classObj = computed(() => ({ |
| | | hideSidebar: !sidebar.value.opened, |
| | |
| | | |
| | | <style lang="scss" scoped> |
| | | @import "@/assets/styles/mixin.scss"; |
| | | @import "@/assets/styles/variables.module.scss"; |
| | | |
| | | .app-wrapper { |
| | | @include clearfix; |
| | | position: relative; |
| | | height: 100%; |
| | | min-height: 100%; |
| | | width: 100%; |
| | | background: radial-gradient( |
| | | circle at top, |
| | | rgba(223, 232, 226, 0.95), |
| | | transparent 32% |
| | | ), |
| | | linear-gradient(180deg, #f7faf8 0%, var(--app-bg) 100%); |
| | | background: |
| | | radial-gradient(circle at 14% -8%, rgba(59, 130, 246, 0.14), transparent 36%), |
| | | radial-gradient(circle at 88% -12%, rgba(56, 189, 248, 0.1), transparent 30%), |
| | | linear-gradient(165deg, #f3f7fc 0%, #eef5ff 56%, #f8fbff 100%); |
| | | |
| | | &.mobile.openSidebar { |
| | | position: fixed; |
| | |
| | | } |
| | | |
| | | .drawer-bg { |
| | | background: #000; |
| | | opacity: 0.3; |
| | | background: rgba(15, 23, 42, 0.22); |
| | | width: 100%; |
| | | top: 0; |
| | | height: 100%; |
| | |
| | | z-index: 999; |
| | | } |
| | | |
| | | .fixed-header { |
| | | position: fixed; |
| | | top: 0px; |
| | | padding-top: 12px; |
| | | right: 16px; |
| | | z-index: 9; |
| | | width: calc(100% - #{$base-sidebar-width} - 32px); |
| | | transition: width 0.28s, right 0.28s; |
| | | padding-bottom: 8px; |
| | | background-color: #f3f6f4; |
| | | } |
| | | .hideSidebar .fixed-header { |
| | | width: calc(100% - 100px); |
| | | .main-layout { |
| | | min-height: 100vh; |
| | | margin-left: var(--sidebar-width); |
| | | transition: margin-left 0.25s ease; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .sidebarHide .fixed-header { |
| | | width: calc(100% - 32px); |
| | | .fixed-header { |
| | | position: sticky; |
| | | top: 0; |
| | | z-index: var(--layout-header-z); |
| | | width: 100%; |
| | | padding: 8px var(--content-gap) 0; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 6px; |
| | | background: transparent; |
| | | backdrop-filter: none; |
| | | } |
| | | |
| | | .fixed-header.with-tags { |
| | | padding-bottom: 6px; |
| | | } |
| | | |
| | | .hideSidebar .fixed-header { |
| | | width: 100%; |
| | | } |
| | | |
| | | .hideSidebar .main-layout { |
| | | margin-left: var(--sidebar-collapsed-width); |
| | | } |
| | | |
| | | .mobile .fixed-header { |
| | | width: 100%; |
| | | padding: 8px 10px 0; |
| | | } |
| | | |
| | | .mobile .main-layout, |
| | | .sidebarHide.main-layout { |
| | | margin-left: 0; |
| | | } |
| | | </style> |
| | |
| | | saveAs(text, name, opts) {
|
| | | saveAs(text, name, opts);
|
| | | },
|
| | | byUrl(url, filename) {
|
| | | // å°URLä¸çpreviewæ¿æ¢ædownload
|
| | | const downloadUrl = url.replace(/preview/g, 'download')
|
| | | const link = document.createElement('a')
|
| | | link.href = downloadUrl
|
| | | link.download = filename || ''
|
| | | document.body.appendChild(link)
|
| | | link.click()
|
| | | document.body.removeChild(link)
|
| | | },
|
| | | async printErrMsg(data) {
|
| | | const resText = await data.text();
|
| | | const rspObj = JSON.parse(resText);
|
| | |
| | | component: () => import("@/views/register"), |
| | | hidden: true, |
| | | }, |
| | | // ç³»ç»æ¶æå¾ |
| | | // { |
| | | // path: "/system-architecture", |
| | | // component: Layout, |
| | | // redirect: "/system-architecture/index", |
| | | // children: [ |
| | | // { |
| | | // path: "index", |
| | | // component: () => import("@/views/systemArchitecture/index.vue"), |
| | | // name: "SystemArchitecture", |
| | | // meta: { title: "ç³»ç»æ¶æå¾", icon: "tree" }, |
| | | // }, |
| | | // ], |
| | | // }, |
| | | { |
| | | path: "/:pathMatch(.*)*", |
| | | component: () => import("@/views/error/404"), |
| | |
| | | }, |
| | | ], |
| | | }, |
| | | // ç³»ç»æ¶æå¾ |
| | | { |
| | | path: "/system-architecture", |
| | | component: Layout, |
| | | redirect: "/system-architecture/index", |
| | | children: [ |
| | | { |
| | | path: "index", |
| | | component: () => import("@/views/systemArchitecture/index.vue"), |
| | | name: "SystemArchitecture", |
| | | meta: { title: "ç³»ç»æ¶æå¾", icon: "tree" }, |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | path: "/ai-industrial-brain", |
| | | component: Layout, |
| | | children: [ |
| | | { |
| | | path: "index", |
| | | component: () => import("@/views/aiIndustrialBrain/index.vue"), |
| | | name: "AiIndustrialBrain", |
| | | meta: { title: "AIå·¥ä¸å¤§è", icon: "skill" }, |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | path: "/user", |
| | | component: Layout, |
| | |
| | | hidden: true, |
| | | name: "DeviceInfo", |
| | | meta: { title: "设å¤ä¿¡æ¯", icon: "monitor" }, |
| | | }, |
| | | // æ·»å 项ç®è¯¦æ
页é¢è·¯ç±é
ç½® |
| | | { |
| | | path: "/oaSystem/projectManagement/projectDetail", |
| | | component: Layout, |
| | | hidden: true, |
| | | children: [ |
| | | { |
| | | path: ":projectId", |
| | | component: () => import("@/views/oaSystem/projectManagement/projectDetail.vue"), |
| | | name: "ProjectDetail", |
| | | meta: { title: "项ç®è¯¦æ
", activeMenu: "/oaSystem/projectManagement" }, |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | path: "/projectManagement/Management/detail", |
| | |
| | | // meta: { title: "è´¢å¡ç®¡ç", icon: "money" }, |
| | | // children: [ |
| | | // { |
| | | // path: "general-ledger", |
| | | // component: () => import("@/views/financialManagement/generalLedger/index.vue"), |
| | | // name: "GeneralLedger", |
| | | // meta: { title: "æ»å¸ç§ç®" }, |
| | | // }, |
| | | // { |
| | | // path: "sales-out", |
| | | // component: () => import("@/views/financialManagement/receivable/salesOut.vue"), |
| | | // name: "SalesOut", |
| | |
| | | // name: "SalesReturn", |
| | | // meta: { title: "éå®éè´§" }, |
| | | // }, |
| | | // { |
| | | // path: "receivable-reconciliation", |
| | | // component: () => import("@/views/financialManagement/receivable/reconciliation.vue"), |
| | | // name: "ReceivableReconciliation", |
| | | // meta: { title: "åºæ¶å¯¹è´¦" }, |
| | | // }, |
| | | // |
| | | // { |
| | | // path: "invoice-apply", |
| | | // component: () => import("@/views/financialManagement/receivable/invoiceApply.vue"), |
| | |
| | | // meta: { title: "æ¶æ¬¾å" }, |
| | | // }, |
| | | // { |
| | | // path: "receivable-reconciliation", |
| | | // component: () => import("@/views/financialManagement/receivable/reconciliation.vue"), |
| | | // name: "ReceivableReconciliation", |
| | | // meta: { title: "åºæ¶å¯¹è´¦" }, |
| | | // }, |
| | | // { |
| | | // path: "purchase-in", |
| | | // component: () => import("@/views/financialManagement/payable/purchaseIn.vue"), |
| | | // name: "PurchaseIn", |
| | | // meta: { title: "éè´å
¥åº" }, |
| | | // }, |
| | | // { |
| | | // path: "payable-reconciliation", |
| | | // component: () => import("@/views/financialManagement/payable/reconciliation.vue"), |
| | | // name: "PayableReconciliation", |
| | | // meta: { title: "åºä»å¯¹è´¦" }, |
| | | // path: "purchase-return", |
| | | // component: () => import("@/views/financialManagement/payable/purchaseReturn.vue"), |
| | | // name: "PurchaseReturn", |
| | | // meta: { title: "éè´éè´§" }, |
| | | // }, |
| | | // { |
| | | // path: "input-invoice", |
| | |
| | | // name: "PaymentApply", |
| | | // meta: { title: "仿¬¾ç³è¯·" }, |
| | | // }, |
| | | // |
| | | // { |
| | | // path: "payment", |
| | | // component: () => import("@/views/financialManagement/payable/payment.vue"), |
| | | // name: "Payment", |
| | | // meta: { title: "仿¬¾å" }, |
| | | // }, |
| | | // { |
| | | // path: "payable-reconciliation", |
| | | // component: () => import("@/views/financialManagement/payable/reconciliation.vue"), |
| | | // name: "PayableReconciliation", |
| | | // meta: { title: "åºä»å¯¹è´¦" }, |
| | | // }, |
| | | // { |
| | | // path: "fixed-assets", |
| | |
| | | // meta: { title: "æ å½¢èµäº§" }, |
| | | // }, |
| | | // { |
| | | // path: "general-ledger", |
| | | // component: () => import("@/views/financialManagement/generalLedger/index.vue"), |
| | | // name: "GeneralLedger", |
| | | // meta: { title: "æ»å¸ç§ç®" }, |
| | | // }, |
| | | // { |
| | | // path: "voucher", |
| | | // component: () => import("@/views/financialManagement/voucher/index.vue"), |
| | | // name: "Voucher", |
| | |
| | | /**
|
| | | * ä¾§è¾¹æ ä¸»é¢ æ·±è²ä¸»é¢theme-darkï¼æµ
è²ä¸»é¢theme-light
|
| | | */
|
| | | sideTheme: 'theme-light',
|
| | | sideTheme: 'theme-dark', |
| | | /**
|
| | | * æ¯å¦ç³»ç»å¸å±é
ç½®
|
| | | */
|
| | |
| | | /**
|
| | | * 䏻颿¨¡å¼ autoè·éç³»ç»ï¼lightæµ
è²ï¼darkæ·±è²
|
| | | */
|
| | | darkMode: "auto",
|
| | | darkMode: "light", |
| | |
|
| | | /**
|
| | | * @type {string | array} 'production' | ['production', 'development']
|
| | |
| | | const defaultData = JSON.parse(JSON.stringify(rawRoutes)) |
| | | const sidebarRoutes = filterAsyncRouter(sdata)
|
| | | const rewriteRoutes = filterAsyncRouter(rdata, false, true)
|
| | | const defaultRoutes = filterAsyncRouter(defaultData)
|
| | | const asyncRoutes = filterDynamicRoutes(dynamicRoutes)
|
| | | asyncRoutes.forEach(route => { router.addRoute(route) })
|
| | | this.setRoutes(rewriteRoutes)
|
| | | // å°è´¢å¡ç®¡çè·¯ç±åå¹¶å°ä¾§è¾¹æ
|
| | | this.setSidebarRouters(constantRoutes.concat(sidebarRoutes))
|
| | | this.setDefaultRoutes(sidebarRoutes)
|
| | | this.setTopbarRoutes(defaultRoutes)
|
| | | resolve(rewriteRoutes)
|
| | | })
|
| | | })
|
| | | const defaultRoutes = filterAsyncRouter(defaultData) |
| | | const asyncRoutes = filterDynamicRoutes(dynamicRoutes) |
| | | asyncRoutes.forEach(route => { router.addRoute(route) }) |
| | | this.setRoutes(rewriteRoutes) |
| | | const constantSidebarRoutes = filterAiFeatureRoutes(constantRoutes, aiEnabled) |
| | | // å°è´¢å¡ç®¡çè·¯ç±åå¹¶å°ä¾§è¾¹æ |
| | | this.setSidebarRouters(constantSidebarRoutes.concat(sidebarRoutes)) |
| | | this.setDefaultRoutes(sidebarRoutes) |
| | | this.setTopbarRoutes(defaultRoutes) |
| | | resolve(rewriteRoutes) |
| | | }) |
| | | }) |
| | | }
|
| | | }
|
| | | })
|
| | |
| | | })
|
| | | }
|
| | |
|
| | | function filterChildren(childrenMap, lastRouter = false) {
|
| | | function filterChildren(childrenMap, lastRouter = false) { |
| | | var children = []
|
| | | childrenMap.forEach(el => {
|
| | | el.path = lastRouter ? lastRouter.path + '/' + el.path : el.path
|
| | |
| | | children.push(el)
|
| | | }
|
| | | })
|
| | | return children
|
| | | }
|
| | |
|
| | | // å¨æè·¯ç±éåï¼éªè¯æ¯å¦å
·å¤æé
|
| | | export function filterDynamicRoutes(routes) {
|
| | | return children |
| | | } |
| | | |
| | | // å¨æè·¯ç±éåï¼éªè¯æ¯å¦å
·å¤æé |
| | | export function filterDynamicRoutes(routes) { |
| | | const res = []
|
| | | routes.forEach(route => {
|
| | | if (route.permissions) {
|
| | |
| | | const useUserStore = defineStore(
|
| | | 'user',
|
| | | {
|
| | | state: () => ({ |
| | | token: getToken(), |
| | | id: '', |
| | | name: '', |
| | | avatar: '', |
| | | roles: [], |
| | | permissions: [], |
| | | aiEnabled: 0 |
| | | state: () => ({
|
| | | token: getToken(),
|
| | | id: '',
|
| | | name: '',
|
| | | avatar: '',
|
| | | roles: [],
|
| | | permissions: [],
|
| | | aiEnabled: 0
|
| | | }),
|
| | | actions: {
|
| | | // ç»å½
|
| | |
| | | const uuid = userInfo.uuid
|
| | | return new Promise((resolve, reject) => {
|
| | | login(username, password, code, uuid).then(res => {
|
| | | setToken(res.token)
|
| | | this.token = res.token
|
| | | const token = res?.token || res?.data?.token
|
| | | if (!token) {
|
| | | reject(new Error('æªè·åå°ç»å½ä»¤ç'))
|
| | | return
|
| | | }
|
| | | setToken(token)
|
| | | this.token = token
|
| | | resolve()
|
| | | }).catch(error => {
|
| | | reject(error)
|
| | |
| | | getInfo() {
|
| | | return new Promise((resolve, reject) => {
|
| | | getInfo().then(res => {
|
| | | const user = res.user
|
| | | res = res.data
|
| | | const user = res.user || {}
|
| | | let avatar = user.avatar || ""
|
| | | avatar = import.meta.env.VITE_APP_BASE_API + '/profile/' + avatar
|
| | | if (res.roles && res.roles.length > 0) { // éªè¯è¿åçrolesæ¯å¦æ¯ä¸ä¸ªé空æ°ç»
|
| | |
| | | } else {
|
| | | this.roles = ['ROLE_DEFAULT']
|
| | | }
|
| | | this.id = user.userId
|
| | | this.name = user.userName
|
| | | this.id = user.userId || ''
|
| | | this.name = user.userName || ''
|
| | | this.avatar = avatar
|
| | | this.currentFactoryName = user.currentFactoryName |
| | | this.nickName = user.nickName |
| | | this.roleName = user.roles[0].roleName |
| | | this.currentDeptId = user.tenantId |
| | | this.currentLoginTime = this.getCurrentTime() |
| | | this.aiEnabled = Number(res.aiEnabled) === 1 ? 1 : 0 |
| | | resolve(res) |
| | | }).catch(error => { |
| | | reject(error) |
| | | }) |
| | | }) |
| | | this.currentFactoryName = user.currentFactoryName || ''
|
| | | this.nickName = user.nickName || ''
|
| | | this.roleName = Array.isArray(user.roles) && user.roles.length > 0 ? (user.roles[0].roleName || '') : ''
|
| | | this.currentDeptId = user.tenantId || ''
|
| | | this.currentLoginTime = this.getCurrentTime()
|
| | | this.aiEnabled = Number(res.aiEnabled) === 1 ? 1 : 0
|
| | | resolve(res)
|
| | | }).catch(error => {
|
| | | reject(error)
|
| | | })
|
| | | })
|
| | | },
|
| | | // éåºç³»ç»
|
| | | logOut() {
|
| | | return new Promise((resolve, reject) => {
|
| | | logout(this.token).then(() => {
|
| | | this.token = '' |
| | | this.roles = [] |
| | | this.permissions = [] |
| | | this.aiEnabled = 0 |
| | | removeToken() |
| | | resolve() |
| | | }).catch(error => { |
| | | reject(error) |
| | | }) |
| | | this.token = ''
|
| | | this.roles = []
|
| | | this.permissions = []
|
| | | this.aiEnabled = 0
|
| | | removeToken()
|
| | | resolve()
|
| | | }).catch(error => {
|
| | | reject(error)
|
| | | })
|
| | | })
|
| | | },
|
| | | // ç»å½æ ¡éª
|
| | |
| | | const password = userInfo.password
|
| | | return new Promise((resolve, reject) => {
|
| | | loginCheckFactory(username, password).then(res => {
|
| | | setToken(res.token)
|
| | | this.token = res.token
|
| | | const token = res?.token || res?.data?.token
|
| | | if (!token) {
|
| | | reject(new Error('æªè·åå°ç»å½ä»¤ç'))
|
| | | return
|
| | | }
|
| | | setToken(token)
|
| | | this.token = token
|
| | | resolve()
|
| | | }).catch(error => {
|
| | | reject(error)
|
| | |
| | | return new Promise((resolve, reject) => {
|
| | | tideLogin(code)
|
| | | .then((res) => {
|
| | | setToken(res.token);
|
| | | this.token = res.token
|
| | | const token = res?.token || res?.data?.token
|
| | | if (!token) {
|
| | | reject(new Error('æªè·åå°ç»å½ä»¤ç'))
|
| | | return
|
| | | }
|
| | | setToken(token);
|
| | | this.token = token
|
| | | Vue.prototype.uploadHeader = {
|
| | | Authorization: "Bearer " + res.token,
|
| | | Authorization: "Bearer " + token,
|
| | | };
|
| | | resolve();
|
| | | })
|
| | |
| | | })
|
| | |
|
| | | // requestæ¦æªå¨
|
| | | service.interceptors.request.use(config => {
|
| | | service.interceptors.request.use(config => { |
| | | config.headers = config.headers || {} |
| | | // æ¯å¦éè¦è®¾ç½® token
|
| | | const isToken = (config.headers || {}).isToken === false
|
| | | const isToken = config.headers.isToken === false |
| | | // æ¯å¦éè¦é²æ¢æ°æ®éå¤æäº¤
|
| | | const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
|
| | | const isRepeatSubmit = config.headers.repeatSubmit === false |
| | | if (getToken() && !isToken) {
|
| | | config.headers['Authorization'] = 'Bearer ' + getToken() // 让æ¯ä¸ªè¯·æ±æºå¸¦èªå®ä¹token è¯·æ ¹æ®å®é
æ
åµèªè¡ä¿®æ¹
|
| | | }
|
| | |
| | | }
|
| | | }
|
| | | return config
|
| | | }, error => {
|
| | | console.log(error)
|
| | | Promise.reject(error)
|
| | | })
|
| | | }, error => { |
| | | console.log(error) |
| | | return Promise.reject(error) |
| | | }) |
| | |
|
| | | // ååºæ¦æªå¨
|
| | | service.interceptors.response.use(res => {
|
| | | // æªè®¾ç½®ç¶æç åé»è®¤æåç¶æ
|
| | | const code = res.data.code || 200
|
| | | const code = res.data.code || 200 |
| | | const handleAuthError = (res.config && res.config.headers && res.config.headers.handleAuthError) !== false |
| | | // è·åé误信æ¯
|
| | | const msg = errorCode[code] || res.data.msg || errorCode['default']
|
| | | // äºè¿å¶æ°æ®åç´æ¥è¿å
|
| | | if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
|
| | | return res.data
|
| | | }
|
| | | if (code === 401) {
|
| | | if (!isRelogin.show) {
|
| | | if (code === 401) { |
| | | if (!handleAuthError) { |
| | | return Promise.reject(new Error(msg)) |
| | | } |
| | | if (!isRelogin.show) { |
| | | isRelogin.show = true
|
| | | ElMessageBox.confirm('ç»å½ç¶æå·²è¿æï¼æ¨å¯ä»¥ç»§ç»çå¨è¯¥é¡µé¢ï¼æè
éæ°ç»å½', 'ç³»ç»æç¤º', { confirmButtonText: 'éæ°ç»å½', cancelButtonText: 'åæ¶', type: 'warning' }).then(() => {
|
| | | isRelogin.show = false
|
| | |
| | | // å¤ç䏻颿 ·å¼ |
| | | export function handleThemeStyle(theme) { |
| | | document.documentElement.style.setProperty('--el-color-primary', theme) |
| | | const primary = normalizeHex(theme) |
| | | const [r, g, b] = hexToRgb(primary) |
| | | const light2 = getLightColor(primary, 0.2) |
| | | const light3 = getLightColor(primary, 0.3) |
| | | const light5 = getLightColor(primary, 0.5) |
| | | |
| | | document.documentElement.style.setProperty('--el-color-primary', primary) |
| | | document.documentElement.style.setProperty('--el-color-primary-rgb', `${r}, ${g}, ${b}`) |
| | | for (let i = 1; i <= 9; i++) { |
| | | document.documentElement.style.setProperty(`--el-color-primary-light-${i}`, `${getLightColor(theme, i / 10)}`) |
| | | document.documentElement.style.setProperty(`--el-color-primary-light-${i}`, `${getLightColor(primary, i / 10)}`) |
| | | } |
| | | for (let i = 1; i <= 9; i++) { |
| | | document.documentElement.style.setProperty(`--el-color-primary-dark-${i}`, `${getDarkColor(theme, i / 10)}`) |
| | | document.documentElement.style.setProperty(`--el-color-primary-dark-${i}`, `${getDarkColor(primary, i / 10)}`) |
| | | } |
| | | |
| | | // ç³»ç»ä¸»é¢èå¨å°ä¾§è¾¹æ é䏿ä¸é«äº® |
| | | document.documentElement.style.setProperty('--menu-active-bg', `linear-gradient(135deg, ${primary} 0%, ${light3} 100%)`) |
| | | document.documentElement.style.setProperty('--menu-active-glow', `0 10px 24px rgba(${r}, ${g}, ${b}, 0.32)`) |
| | | document.documentElement.style.setProperty('--menu-hover', `rgba(${r}, ${g}, ${b}, 0.2)`) |
| | | document.documentElement.style.setProperty('--accent-primary', primary) |
| | | document.documentElement.style.setProperty('--accent-light', light2) |
| | | document.documentElement.style.setProperty('--accent-lighter', light5) |
| | | } |
| | | |
| | | // hexé¢è²è½¬rgbé¢è² |
| | | export function hexToRgb(str) { |
| | | str = str.replace('#', '') |
| | | let hexs = str.match(/../g) |
| | | str = normalizeHex(str).replace('#', '') |
| | | const hexs = str.match(/../g) || ['40', '9e', 'ff'] |
| | | for (let i = 0; i < 3; i++) { |
| | | hexs[i] = parseInt(hexs[i], 16) |
| | | } |
| | | return hexs |
| | | } |
| | | |
| | | // rgbé¢è²è½¬Hexé¢è² |
| | | // rgbé¢è²è½¬hexé¢è² |
| | | export function rgbToHex(r, g, b) { |
| | | let hexs = [r.toString(16), g.toString(16), b.toString(16)] |
| | | const hexs = [r.toString(16), g.toString(16), b.toString(16)] |
| | | for (let i = 0; i < 3; i++) { |
| | | if (hexs[i].length == 1) { |
| | | if (hexs[i].length === 1) { |
| | | hexs[i] = `0${hexs[i]}` |
| | | } |
| | | } |
| | |
| | | |
| | | // åæµ
é¢è²å¼ |
| | | export function getLightColor(color, level) { |
| | | let rgb = hexToRgb(color) |
| | | const rgb = hexToRgb(color) |
| | | for (let i = 0; i < 3; i++) { |
| | | rgb[i] = Math.floor((255 - rgb[i]) * level + rgb[i]) |
| | | } |
| | |
| | | |
| | | // åæ·±é¢è²å¼ |
| | | export function getDarkColor(color, level) { |
| | | let rgb = hexToRgb(color) |
| | | const rgb = hexToRgb(color) |
| | | for (let i = 0; i < 3; i++) { |
| | | rgb[i] = Math.floor(rgb[i] * (1 - level)) |
| | | } |
| | | return rgbToHex(rgb[0], rgb[1], rgb[2]) |
| | | } |
| | | |
| | | function normalizeHex(color) { |
| | | if (!color || typeof color !== 'string') return '#409eff' |
| | | let value = color.trim().replace('#', '') |
| | | if (value.length === 3) { |
| | | value = value.split('').map((s) => s + s).join('') |
| | | } |
| | | if (!/^[0-9a-fA-F]{6}$/.test(value)) return '#409eff' |
| | | return `#${value.toLowerCase()}` |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # AIå·¥ä¸å¤§èç»´æ¤è§å |
| | | |
| | | 1. å½ `src/views/aiIndustrialBrain/index.vue` æ°å¢æºè½ä½ï¼`agents`ï¼é»è¾æ¶ï¼å¿
é¡»åæ¥ç¡®è®¤å¼¹çªå©æå¯ç¨æ§ã |
| | | 2. å¼¹çªå©æç± `src/components/AIChatSidebar/assistants/index.js` ç `assistantRegistry` ç»ä¸æ³¨åã |
| | | 3. æ°å¢æºè½ä½ç `key` è¥è¦å¨å¼¹çªä¸å¯ç¨ï¼å¿
é¡»å¨ `assistantRegistry` 䏿ä¾ååé
ç½®ã |
| | | 4. æªå¨ `assistantRegistry` 注åçæºè½ä½ä¼å¨å¼¹çªä¸æ¾ç¤ºä¸º `pending`ï¼å¼åä¸ï¼æã |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <transition name="fade"> |
| | | <section v-if="visible" class="assistant-workspace"> |
| | | <div class="assistant-workspace__panel"> |
| | | <button |
| | | v-if="assistantMode === 'pending'" |
| | | type="button" |
| | | class="workspace-back-btn" |
| | | @click="$emit('close')" |
| | | > |
| | | <el-icon><ArrowLeftBold /></el-icon> |
| | | <span>è¿åå·¥ä¸å¤§å±</span> |
| | | </button> |
| | | |
| | | <div class="assistant-workspace__body"> |
| | | <AIChatSidebar |
| | | v-if="assistantMode !== 'pending'" |
| | | :key="assistantMode" |
| | | class="workspace-chat" |
| | | :assistants="resolvedAssistants" |
| | | :default-assistant="assistantMode" |
| | | :hide-trigger="true" |
| | | :auto-open="true" |
| | | drawer-size="100%" |
| | | drawer-direction="ttb" |
| | | header-extra-action-text="è¿åå·¥ä¸å¤§å±" |
| | | @header-extra-action="$emit('close')" |
| | | /> |
| | | |
| | | <div v-else class="workspace-pending"> |
| | | <div class="workspace-pending__content"> |
| | | <h3>{{ agentTitle }}</h3> |
| | | <p>æ£å¨å¼åï¼æ¬è¯·æå¾
......</p> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </section> |
| | | </transition> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed } from "vue"; |
| | | import { ArrowLeftBold } from "@element-plus/icons-vue"; |
| | | import AIChatSidebar from "@/components/AIChatSidebar/index.vue"; |
| | | import { assistantRegistry } from "@/components/AIChatSidebar/assistants"; |
| | | |
| | | const props = defineProps({ |
| | | visible: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | agent: { |
| | | type: Object, |
| | | default: () => ({}), |
| | | }, |
| | | }); |
| | | |
| | | defineEmits(["close"]); |
| | | |
| | | const agentKey = computed(() => String(props.agent?.key || "")); |
| | | const agentTitle = computed(() => String(props.agent?.name || "AI婿")); |
| | | |
| | | /** |
| | | * ç»´æ¤è§åï¼ |
| | | * AIå·¥ä¸å¤§èæ°å¢æºè½ä½æ¶ï¼è¥å¸æå³ä¾§å¼¹çªå¯ç¨ï¼éä¿è¯æºè½ä½ key å¨ assistantRegistry 䏿ååé
ç½®ã |
| | | * æªé
ç½®æ¶ä¼è¿å
¥ pendingï¼å¼åä¸ï¼æï¼ä½ä¸ºæ¾å¼æéã |
| | | */ |
| | | const resolvedAssistant = computed(() => assistantRegistry[agentKey.value] || null); |
| | | const assistantMode = computed(() => { |
| | | return resolvedAssistant.value ? agentKey.value : "pending"; |
| | | }); |
| | | const resolvedAssistants = computed(() => (resolvedAssistant.value ? [resolvedAssistant.value] : [])); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .assistant-workspace { |
| | | position: fixed; |
| | | inset: 0; |
| | | z-index: 2100; |
| | | padding: 12px; |
| | | background: rgba(33, 49, 63, 0.24); |
| | | backdrop-filter: blur(2px); |
| | | } |
| | | |
| | | .assistant-workspace__panel { |
| | | position: relative; |
| | | height: 100%; |
| | | border-radius: 22px; |
| | | border: 1px solid var(--surface-border); |
| | | background: linear-gradient(180deg, #f9fcfb 0%, #f0f5f2 100%); |
| | | box-shadow: var(--shadow-md); |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .assistant-workspace__body { |
| | | height: 100%; |
| | | min-height: 100%; |
| | | } |
| | | |
| | | .workspace-back-btn { |
| | | position: absolute; |
| | | top: 16px; |
| | | right: 20px; |
| | | z-index: 5; |
| | | height: 36px; |
| | | padding: 0 14px; |
| | | border: 1px solid rgba(38, 112, 183, 0.3); |
| | | border-radius: 10px; |
| | | background: rgba(255, 255, 255, 0.92); |
| | | color: #25528f; |
| | | display: inline-flex; |
| | | align-items: center; |
| | | gap: 6px; |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | cursor: pointer; |
| | | transition: all 0.2s ease; |
| | | } |
| | | |
| | | .workspace-back-btn:hover { |
| | | border-color: rgba(31, 122, 114, 0.45); |
| | | color: #1f5ddf; |
| | | box-shadow: 0 8px 16px rgba(31, 122, 114, 0.14); |
| | | transform: translateY(-1px); |
| | | } |
| | | |
| | | .workspace-chat { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .workspace-chat :deep(.ai-chat-sidebar-wrapper) { |
| | | height: 100%; |
| | | } |
| | | |
| | | .workspace-chat :deep(.ai-chat-drawer) { |
| | | height: 100%; |
| | | } |
| | | |
| | | .workspace-chat :deep(.el-drawer) { |
| | | height: 100% !important; |
| | | width: 100% !important; |
| | | } |
| | | |
| | | .workspace-pending { |
| | | height: 100%; |
| | | display: grid; |
| | | place-items: center; |
| | | padding: 20px; |
| | | color: var(--text-secondary); |
| | | } |
| | | |
| | | .workspace-pending__content { |
| | | display: grid; |
| | | gap: 12px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .workspace-pending__content h3 { |
| | | margin: 0; |
| | | font-size: 36px; |
| | | color: var(--text-primary); |
| | | } |
| | | |
| | | .workspace-pending__content p { |
| | | margin: 0; |
| | | font-size: 24px; |
| | | } |
| | | |
| | | .fade-enter-active, |
| | | .fade-leave-active { |
| | | transition: opacity 0.2s ease; |
| | | } |
| | | |
| | | .fade-enter-from, |
| | | .fade-leave-to { |
| | | opacity: 0; |
| | | } |
| | | |
| | | @media (max-width: 1600px) { |
| | | .workspace-back-btn { |
| | | top: 12px; |
| | | right: 14px; |
| | | height: 32px; |
| | | padding: 0 12px; |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .workspace-pending__content h3 { |
| | | font-size: 30px; |
| | | } |
| | | |
| | | .workspace-pending__content p { |
| | | font-size: 20px; |
| | | } |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div ref="screenRef" class="ai-brain-screen"> |
| | | <section class="brain-stage"> |
| | | <header class="brain-head"> |
| | | <div class="head-date"> |
| | | <p>{{ weekLabel }}</p> |
| | | <p>{{ dateLabel }}</p> |
| | | </div> |
| | | |
| | | <div class="head-title"> |
| | | <span>AIå·¥ä¸å¤§è</span> |
| | | </div> |
| | | |
| | | <div class="head-actions"> |
| | | <button type="button" class="head-back-btn" @click="goBack"> |
| | | <el-icon><ArrowLeftBold /></el-icon> |
| | | <span>è¿å</span> |
| | | </button> |
| | | </div> |
| | | </header> |
| | | |
| | | <section class="brain-intro"> |
| | | <h2>å·¥ä¸AIæ°ååå·¥ï¼èµè½æºé æ°çºªå
</h2> |
| | | <p>å
大AI婿ååä¼ä¸ç®¡çãéå®ãéè´ãç产ãè´¢å¡åæ°æ®å
¨é¾è·¯</p> |
| | | <div class="intro-sign">é¿éäº Ã åé®å¤§æ¨¡å à æºè½ä½AI</div> |
| | | </section> |
| | | |
| | | <section class="carousel-area"> |
| | | <button type="button" class="nav-btn nav-btn--left" @click="prevCard"> |
| | | <el-icon><ArrowLeftBold /></el-icon> |
| | | </button> |
| | | |
| | | <div class="carousel-track"> |
| | | <article |
| | | v-for="card in visibleCards" |
| | | :key="card.agent.key" |
| | | class="agent-card" |
| | | :class="{ 'agent-card--active': card.offset === 0 }" |
| | | :style="getCardStyle(card.offset)" |
| | | @click="openAssistant(card.realIndex)" |
| | | > |
| | | <div class="agent-card__head" :class="{ 'agent-card__head--active': card.offset === 0 }"> |
| | | {{ card.agent.name }} |
| | | </div> |
| | | |
| | | <div class="agent-card__body" :class="{ 'agent-card__body--active': card.offset === 0 }"> |
| | | <div class="avatar-shell" :class="{ 'avatar-shell--active': card.offset === 0 }"> |
| | | <div class="avatar-base"></div> |
| | | <div class="avatar-cut"> |
| | | <img v-if="card.agent.avatar" class="avatar-cut__img" :src="card.agent.avatar" :alt="card.agent.name" /> |
| | | </div> |
| | | </div> |
| | | <div v-if="card.offset === 0" class="highlight-list"> |
| | | <div |
| | | v-for="highlight in card.agent.highlights" |
| | | :key="highlight" |
| | | class="highlight-item" |
| | | > |
| | | {{ highlight }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </article> |
| | | </div> |
| | | |
| | | <button type="button" class="nav-btn nav-btn--right" @click="nextCard"> |
| | | <el-icon><ArrowRightBold /></el-icon> |
| | | </button> |
| | | </section> |
| | | |
| | | <section class="brain-footer"> |
| | | <div class="footer-grid-overlay"></div> |
| | | |
| | | <div class="footer-metrics"> |
| | | <article class="footer-metric"> |
| | | <span class="footer-metric__label">å¨çº¿æºè½ä½</span> |
| | | <strong class="footer-metric__value">{{ agents.length }}个</strong> |
| | | <small class="footer-metric__hint">å
¨é¾è·¯ååè¿è¡</small> |
| | | </article> |
| | | |
| | | <article class="footer-metric footer-metric--focus"> |
| | | <span class="footer-metric__label">å½åç¦ç¹</span> |
| | | <strong class="footer-metric__value">{{ getFooterAgentName(focusAgent.name) }}</strong> |
| | | <small class="footer-metric__hint">{{ focusAgent.highlights?.[0] || "æºè½åæèå¨" }}</small> |
| | | </article> |
| | | |
| | | <article class="footer-metric footer-metric--period"> |
| | | <span class="footer-metric__label">è½®æå¨æ</span> |
| | | <strong class="footer-metric__value">{{ carouselSecondsText }}</strong> |
| | | <div class="footer-period-control"> |
| | | <button type="button" class="period-btn" @click="adjustCarouselSeconds(-0.5)">-</button> |
| | | <input |
| | | v-model.number="carouselSeconds" |
| | | class="period-input" |
| | | type="number" |
| | | min="2" |
| | | max="12" |
| | | step="0.5" |
| | | /> |
| | | <span class="period-unit">s</span> |
| | | <button type="button" class="period-btn" @click="adjustCarouselSeconds(0.5)">+</button> |
| | | </div> |
| | | <input |
| | | v-model.number="carouselSeconds" |
| | | class="footer-period-slider" |
| | | type="range" |
| | | min="2" |
| | | max="12" |
| | | step="0.5" |
| | | /> |
| | | <small class="footer-metric__hint">坿å¨è®¾ç½® 2.0s - 12.0s</small> |
| | | </article> |
| | | </div> |
| | | |
| | | <div class="footer-rail"> |
| | | <div class="footer-rail__line"> |
| | | <span class="footer-rail__flow"></span> |
| | | </div> |
| | | <div class="footer-rail__nodes"> |
| | | <button |
| | | v-for="node in footerNodes" |
| | | :key="node.key" |
| | | type="button" |
| | | class="footer-node" |
| | | :class="{ 'footer-node--active': node.index === carouselIndex }" |
| | | @click="openAssistant(node.index)" |
| | | > |
| | | <span class="footer-node__dot"></span> |
| | | <span class="footer-node__name">{{ getFooterAgentName(node.name) }}</span> |
| | | </button> |
| | | </div> |
| | | </div> |
| | | </section> |
| | | </section> |
| | | |
| | | <AiAssistantWorkspace |
| | | :visible="fullscreenVisible" |
| | | :agent="currentAgent" |
| | | @close="closeFullscreen" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue"; |
| | | import { useRouter } from "vue-router"; |
| | | import { ArrowLeftBold, ArrowRightBold } from "@element-plus/icons-vue"; |
| | | import AiAssistantWorkspace from "./components/AiAssistantWorkspace.vue"; |
| | | import todoAvatar from "@/assets/AI/å¾
å婿.png"; |
| | | import salesAvatar from "@/assets/AI/éå®å©æ.png"; |
| | | import purchaseAvatar from "@/assets/AI/éè´å©æ.png"; |
| | | import productionAvatar from "@/assets/AI/çäº§å©æ.png"; |
| | | import financeAvatar from "@/assets/AI/è´¢å¡å©æ.png"; |
| | | |
| | | const router = useRouter(); |
| | | |
| | | // ç»´æ¤çº¦å®è§ï¼src/views/aiIndustrialBrain/MAINTAIN_RULES.md |
| | | const agents = [ |
| | | { |
| | | key: "general", |
| | | name: "AIå¾
å婿", |
| | | highlights: ["è·¨æ¨¡åæµç¨è¯æ", "ç»è¥é£é©æºè½æé"], |
| | | }, |
| | | { |
| | | key: "sales", |
| | | name: "AIéå®å©æ", |
| | | highlights: ["å®¢æ·æµå¤±é£é©åæ", "忬¾ä¸æ¥ä»·çç¥å»ºè®®"], |
| | | }, |
| | | { |
| | | key: "purchase", |
| | | name: "AIéè´å©æ", |
| | | highlights: ["ä¾åºé¾ææ åæ", "éè´è®¢åæºè½çæ"], |
| | | }, |
| | | { |
| | | key: "production", |
| | | name: "AIçäº§å©æ", |
| | | highlights: ["å·¥åºç¶é¢å®ä½", "产è½ä¸æ¥åºæºè½é¢è¦"], |
| | | }, |
| | | { |
| | | key: "finance", |
| | | name: "AIè´¢å¡å©æ", |
| | | highlights: ["ç°éæµååé¢å¤", "è´¹ç¨ç»ææºè½åæ"], |
| | | }, |
| | | ]; |
| | | |
| | | const avatarByAgentKey = { |
| | | general: todoAvatar, |
| | | sales: salesAvatar, |
| | | purchase: purchaseAvatar, |
| | | production: productionAvatar, |
| | | finance: financeAvatar, |
| | | }; |
| | | |
| | | for (let i = agents.length - 1; i >= 0; i -= 1) { |
| | | const agent = agents[i]; |
| | | const avatar = avatarByAgentKey[agent.key]; |
| | | if (!avatar) { |
| | | agents.splice(i, 1); |
| | | continue; |
| | | } |
| | | agent.avatar = avatar; |
| | | } |
| | | |
| | | const carouselIndex = ref(Math.min(2, Math.max(agents.length - 1, 0))); |
| | | const fullscreenVisible = ref(false); |
| | | const screenRef = ref(null); |
| | | const carouselIntervalMs = ref(4500); |
| | | |
| | | let carouselTimer = null; |
| | | |
| | | const fallbackAgent = { |
| | | key: "fallback", |
| | | name: "AI婿", |
| | | avatar: "", |
| | | highlights: [], |
| | | }; |
| | | |
| | | const currentAgent = computed(() => agents[carouselIndex.value] || agents[0] || fallbackAgent); |
| | | const focusAgent = computed(() => currentAgent.value || fallbackAgent); |
| | | const footerNodes = computed(() => |
| | | agents.map((agent, index) => ({ |
| | | key: agent.key, |
| | | name: agent.name, |
| | | index, |
| | | })) |
| | | ); |
| | | const carouselSeconds = computed({ |
| | | get: () => Number((carouselIntervalMs.value / 1000).toFixed(1)), |
| | | set: (value) => { |
| | | const next = Number(value); |
| | | if (!Number.isFinite(next)) return; |
| | | const clamped = Math.max(2, Math.min(12, Math.round(next * 2) / 2)); |
| | | carouselIntervalMs.value = Math.round(clamped * 1000); |
| | | }, |
| | | }); |
| | | const carouselSecondsText = computed(() => `${carouselSeconds.value.toFixed(1)}s`); |
| | | |
| | | const weekLabel = computed(() => { |
| | | const weekMap = ["æææ¥", "ææä¸", "ææäº", "ææä¸", "ææå", "ææäº", "ææå
"]; |
| | | return weekMap[new Date().getDay()]; |
| | | }); |
| | | |
| | | const dateLabel = computed(() => { |
| | | const now = new Date(); |
| | | const year = now.getFullYear(); |
| | | const month = String(now.getMonth() + 1).padStart(2, "0"); |
| | | const day = String(now.getDate()).padStart(2, "0"); |
| | | return `${year}å¹´${month}æ${day}æ¥`; |
| | | }); |
| | | |
| | | const visibleCards = computed(() => { |
| | | const total = agents.length; |
| | | return agents |
| | | .map((agent, index) => { |
| | | let offset = index - carouselIndex.value; |
| | | if (offset > total / 2) offset -= total; |
| | | if (offset < -total / 2) offset += total; |
| | | return { agent, offset, realIndex: index }; |
| | | }) |
| | | .filter((item) => Math.abs(item.offset) <= 2) |
| | | .sort((a, b) => a.offset - b.offset); |
| | | }); |
| | | |
| | | function getCardStyle(offset) { |
| | | const distance = Math.abs(offset); |
| | | const scale = distance === 0 ? 1 : distance === 1 ? 0.88 : 0.78; |
| | | const opacity = distance === 0 ? 1 : distance === 1 ? 0.92 : 0.76; |
| | | return { |
| | | transform: `translateX(${offset * 340}px) scale(${scale})`, |
| | | zIndex: String(50 - distance), |
| | | opacity, |
| | | }; |
| | | } |
| | | |
| | | function getFooterAgentName(name) { |
| | | return String(name || "AI婿").replace(/^AI/, ""); |
| | | } |
| | | |
| | | function adjustCarouselSeconds(delta) { |
| | | carouselSeconds.value = carouselSeconds.value + delta; |
| | | } |
| | | |
| | | function prevCard() { |
| | | const total = agents.length; |
| | | if (!total) return; |
| | | carouselIndex.value = (carouselIndex.value - 1 + total) % total; |
| | | } |
| | | |
| | | function nextCard() { |
| | | const total = agents.length; |
| | | if (!total) return; |
| | | carouselIndex.value = (carouselIndex.value + 1) % total; |
| | | } |
| | | |
| | | async function enterBrowserFullscreen() { |
| | | if (document.fullscreenElement) return; |
| | | const target = screenRef.value || document.documentElement; |
| | | if (!target || typeof target.requestFullscreen !== "function") return; |
| | | try { |
| | | await target.requestFullscreen(); |
| | | } catch (error) { |
| | | // Ignore: browser may block fullscreen when there is no direct user activation. |
| | | } |
| | | } |
| | | |
| | | async function exitBrowserFullscreen() { |
| | | if (!document.fullscreenElement || typeof document.exitFullscreen !== "function") return; |
| | | try { |
| | | await document.exitFullscreen(); |
| | | } catch (error) { |
| | | // Ignore fullscreen exit failures. |
| | | } |
| | | } |
| | | |
| | | function goBack() { |
| | | closeFullscreen(); |
| | | exitBrowserFullscreen(); |
| | | if (window.history.length > 1) { |
| | | router.back(); |
| | | return; |
| | | } |
| | | router.push("/index"); |
| | | } |
| | | |
| | | function openAssistant(index) { |
| | | if (!agents.length) return; |
| | | carouselIndex.value = index; |
| | | fullscreenVisible.value = true; |
| | | } |
| | | |
| | | function closeFullscreen() { |
| | | fullscreenVisible.value = false; |
| | | } |
| | | |
| | | function startCarousel() { |
| | | stopCarousel(); |
| | | if (fullscreenVisible.value) return; |
| | | carouselTimer = window.setInterval(() => { |
| | | nextCard(); |
| | | }, carouselIntervalMs.value); |
| | | } |
| | | |
| | | function stopCarousel() { |
| | | if (carouselTimer) { |
| | | window.clearInterval(carouselTimer); |
| | | carouselTimer = null; |
| | | } |
| | | } |
| | | |
| | | function handleEscClose(event) { |
| | | if (event.key === "Escape" && fullscreenVisible.value) { |
| | | closeFullscreen(); |
| | | } |
| | | } |
| | | |
| | | watch( |
| | | () => fullscreenVisible.value, |
| | | (opened) => { |
| | | if (opened) { |
| | | stopCarousel(); |
| | | } else { |
| | | startCarousel(); |
| | | } |
| | | } |
| | | ); |
| | | |
| | | watch( |
| | | () => carouselIntervalMs.value, |
| | | () => { |
| | | if (!fullscreenVisible.value) { |
| | | startCarousel(); |
| | | } |
| | | } |
| | | ); |
| | | |
| | | onMounted(() => { |
| | | startCarousel(); |
| | | window.addEventListener("keydown", handleEscClose); |
| | | window.requestAnimationFrame(() => { |
| | | enterBrowserFullscreen(); |
| | | }); |
| | | }); |
| | | |
| | | onBeforeUnmount(() => { |
| | | stopCarousel(); |
| | | window.removeEventListener("keydown", handleEscClose); |
| | | exitBrowserFullscreen(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .ai-brain-screen { |
| | | position: fixed; |
| | | inset: 0; |
| | | z-index: 1900; |
| | | padding: 10px; |
| | | overflow: hidden; |
| | | background: var(--app-bg); |
| | | } |
| | | |
| | | .brain-stage { |
| | | position: relative; |
| | | height: 100%; |
| | | min-height: 100%; |
| | | border-radius: 22px; |
| | | border: 1px solid var(--surface-border); |
| | | background: |
| | | radial-gradient(circle at 14% 8%, rgba(31, 122, 114, 0.14), transparent 40%), |
| | | radial-gradient(circle at 86% 12%, rgba(30, 91, 255, 0.1), transparent 42%), |
| | | linear-gradient(180deg, rgba(255, 255, 255, 0.95), rgba(245, 249, 247, 0.94)), |
| | | repeating-linear-gradient( |
| | | 135deg, |
| | | rgba(255, 255, 255, 0.05) 0, |
| | | rgba(255, 255, 255, 0.05) 14px, |
| | | rgba(31, 122, 114, 0.03) 14px, |
| | | rgba(31, 122, 114, 0.03) 28px |
| | | ); |
| | | box-shadow: var(--shadow-sm); |
| | | } |
| | | |
| | | .brain-head { |
| | | display: grid; |
| | | grid-template-columns: 220px minmax(0, 1fr) 180px; |
| | | align-items: center; |
| | | padding: 12px 18px 0; |
| | | } |
| | | |
| | | .head-date { |
| | | color: var(--text-secondary); |
| | | font-size: 24px; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .head-date p { |
| | | margin: 0; |
| | | line-height: 1.2; |
| | | } |
| | | |
| | | .head-title { |
| | | justify-self: center; |
| | | width: min(760px, 95%); |
| | | height: 68px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | border-radius: 0 0 46px 46px; |
| | | color: #fff; |
| | | font-size: 42px; |
| | | font-style: italic; |
| | | font-weight: 700; |
| | | letter-spacing: 1px; |
| | | background: linear-gradient(135deg, #1f7a72 0%, #1e5bff 100%); |
| | | box-shadow: 0 16px 30px rgba(31, 122, 114, 0.24); |
| | | } |
| | | |
| | | .head-actions { |
| | | justify-self: end; |
| | | } |
| | | |
| | | .head-back-btn { |
| | | height: 40px; |
| | | padding: 0 14px; |
| | | display: inline-flex; |
| | | align-items: center; |
| | | gap: 4px; |
| | | border: none; |
| | | border-radius: 999px; |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: var(--colorPrimary); |
| | | background: var(--surface-base); |
| | | box-shadow: 0 8px 18px rgba(31, 49, 38, 0.12); |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .brain-intro { |
| | | text-align: center; |
| | | margin-top: 34px; |
| | | } |
| | | |
| | | .brain-intro h2 { |
| | | margin: 0; |
| | | font-size: 44px; |
| | | font-style: italic; |
| | | font-weight: 700; |
| | | color: var(--text-primary); |
| | | } |
| | | |
| | | .brain-intro p { |
| | | margin: 12px 0 10px; |
| | | font-size: 28px; |
| | | color: var(--text-secondary); |
| | | } |
| | | |
| | | .intro-sign { |
| | | display: inline-block; |
| | | padding: 6px 18px; |
| | | border-radius: 999px; |
| | | font-size: 24px; |
| | | font-weight: 700; |
| | | color: #1e5bff; |
| | | background: rgba(255, 255, 255, 0.82); |
| | | border: 1px solid rgba(30, 91, 255, 0.18); |
| | | } |
| | | |
| | | .carousel-area { |
| | | position: relative; |
| | | margin-top: 34px; |
| | | padding: 0 72px 12px; |
| | | } |
| | | |
| | | .carousel-track { |
| | | position: relative; |
| | | height: 500px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .brain-footer { |
| | | position: relative; |
| | | margin: 0 72px; |
| | | height: clamp(226px, 25vh,0); |
| | | border-radius: 18px; |
| | | border: 1px solid rgba(31, 122, 114, 0.28); |
| | | background: |
| | | linear-gradient(120deg, rgba(31, 122, 114, 0.14), rgba(30, 91, 255, 0.14)), |
| | | linear-gradient(180deg, rgba(255, 255, 255, 0.92), rgba(236, 244, 249, 0.9)); |
| | | box-shadow: |
| | | 0 16px 34px rgba(31, 81, 131, 0.12), |
| | | inset 0 1px 0 rgba(255, 255, 255, 0.72); |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .brain-footer::before { |
| | | content: ""; |
| | | position: absolute; |
| | | left: -22%; |
| | | bottom: -120%; |
| | | width: 52%; |
| | | height: 260%; |
| | | background: radial-gradient(ellipse at center, rgba(30, 91, 255, 0.2) 0%, rgba(30, 91, 255, 0) 72%); |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .brain-footer::after { |
| | | content: ""; |
| | | position: absolute; |
| | | inset: 0; |
| | | background: linear-gradient(110deg, transparent 12%, rgba(255, 255, 255, 0.24) 38%, transparent 64%); |
| | | transform: translateX(-120%); |
| | | animation: footerSweep 5.8s linear infinite; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .footer-grid-overlay { |
| | | position: absolute; |
| | | inset: 0; |
| | | background: |
| | | repeating-linear-gradient( |
| | | 90deg, |
| | | rgba(31, 122, 114, 0.07) 0, |
| | | rgba(31, 122, 114, 0.07) 1px, |
| | | transparent 1px, |
| | | transparent 36px |
| | | ), |
| | | repeating-linear-gradient( |
| | | 0deg, |
| | | rgba(30, 91, 255, 0.06) 0, |
| | | rgba(30, 91, 255, 0.06) 1px, |
| | | transparent 1px, |
| | | transparent 28px |
| | | ); |
| | | opacity: 0.72; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .footer-metrics { |
| | | position: relative; |
| | | z-index: 2; |
| | | padding: 14px 20px 72px; |
| | | display: grid; |
| | | grid-template-columns: repeat(3, minmax(0, 1fr)); |
| | | gap: 12px; |
| | | } |
| | | |
| | | .footer-metric { |
| | | min-height: 76px; |
| | | border-radius: 12px; |
| | | padding: 10px 14px; |
| | | border: 1px solid rgba(37, 124, 188, 0.2); |
| | | background: linear-gradient(180deg, rgba(255, 255, 255, 0.88), rgba(245, 250, 255, 0.82)); |
| | | box-shadow: 0 10px 18px rgba(29, 83, 134, 0.08); |
| | | display: grid; |
| | | grid-template-rows: auto auto 1fr; |
| | | gap: 4px; |
| | | } |
| | | |
| | | .footer-metric--focus { |
| | | border-color: rgba(38, 122, 194, 0.34); |
| | | box-shadow: |
| | | 0 12px 22px rgba(30, 91, 255, 0.12), |
| | | inset 0 0 0 1px rgba(85, 148, 232, 0.2); |
| | | } |
| | | |
| | | .footer-metric__label { |
| | | font-size: 14px; |
| | | color: rgba(38, 72, 108, 0.88); |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .footer-metric__value { |
| | | font-size: 30px; |
| | | line-height: 1; |
| | | font-style: italic; |
| | | font-weight: 700; |
| | | color: #1f5ddf; |
| | | text-shadow: 0 3px 10px rgba(30, 91, 255, 0.18); |
| | | } |
| | | |
| | | .footer-metric__hint { |
| | | margin-top: auto; |
| | | font-size: 13px; |
| | | color: rgba(52, 89, 128, 0.82); |
| | | } |
| | | |
| | | .footer-metric--period .footer-metric__hint { |
| | | margin-top: 0; |
| | | line-height: 1.25; |
| | | } |
| | | |
| | | .footer-metric--period { |
| | | min-height: 122px; |
| | | grid-template-rows: auto auto auto auto auto; |
| | | gap: 6px; |
| | | } |
| | | |
| | | .footer-period-control { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .period-btn { |
| | | width: 22px; |
| | | height: 22px; |
| | | border-radius: 50%; |
| | | border: 1px solid rgba(38, 112, 183, 0.28); |
| | | background: rgba(255, 255, 255, 0.9); |
| | | color: #2054c9; |
| | | font-size: 14px; |
| | | font-weight: 700; |
| | | line-height: 1; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .period-input { |
| | | width: 56px; |
| | | height: 24px; |
| | | border-radius: 8px; |
| | | border: 1px solid rgba(38, 112, 183, 0.24); |
| | | background: rgba(255, 255, 255, 0.94); |
| | | color: #1f5ddf; |
| | | font-size: 13px; |
| | | font-weight: 600; |
| | | text-align: center; |
| | | padding: 0 4px; |
| | | } |
| | | |
| | | .period-unit { |
| | | font-size: 12px; |
| | | font-weight: 600; |
| | | color: rgba(40, 80, 117, 0.86); |
| | | } |
| | | |
| | | .footer-period-slider { |
| | | width: min(250px, 100%); |
| | | height: 3px; |
| | | accent-color: #2a6ded; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .footer-rail { |
| | | position: absolute; |
| | | left: 20px; |
| | | right: 20px; |
| | | bottom: 18px; |
| | | z-index: 2; |
| | | } |
| | | |
| | | .footer-rail__line { |
| | | position: relative; |
| | | height: 2px; |
| | | border-radius: 999px; |
| | | background: linear-gradient(90deg, rgba(31, 122, 114, 0.12), rgba(30, 91, 255, 0.6), rgba(31, 122, 114, 0.12)); |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .footer-rail__flow { |
| | | position: absolute; |
| | | top: -1px; |
| | | left: -18%; |
| | | width: 22%; |
| | | height: 4px; |
| | | border-radius: 999px; |
| | | background: linear-gradient(90deg, rgba(31, 122, 114, 0), rgba(59, 146, 244, 0.92), rgba(30, 91, 255, 0)); |
| | | filter: blur(0.2px); |
| | | animation: railFlow 3.1s ease-in-out infinite; |
| | | } |
| | | |
| | | .footer-rail__nodes { |
| | | margin-top: 12px; |
| | | display: grid; |
| | | grid-template-columns: repeat(5, minmax(0, 1fr)); |
| | | gap: 8px; |
| | | } |
| | | |
| | | .footer-node { |
| | | height: 34px; |
| | | border: 1px solid rgba(38, 112, 183, 0.18); |
| | | border-radius: 999px; |
| | | background: rgba(255, 255, 255, 0.76); |
| | | display: inline-flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 8px; |
| | | color: rgba(40, 80, 117, 0.92); |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | cursor: pointer; |
| | | transition: all 0.26s ease; |
| | | } |
| | | |
| | | .footer-node:hover { |
| | | transform: translateY(-1px); |
| | | border-color: rgba(31, 122, 114, 0.34); |
| | | box-shadow: 0 8px 14px rgba(31, 122, 114, 0.14); |
| | | } |
| | | |
| | | .footer-node--active { |
| | | color: #fff; |
| | | border-color: transparent; |
| | | background: linear-gradient(135deg, rgba(31, 122, 114, 0.94), rgba(30, 91, 255, 0.94)); |
| | | box-shadow: 0 10px 18px rgba(30, 91, 255, 0.28); |
| | | } |
| | | |
| | | .footer-node__dot { |
| | | width: 8px; |
| | | height: 8px; |
| | | border-radius: 50%; |
| | | background: rgba(30, 91, 255, 0.72); |
| | | box-shadow: 0 0 10px rgba(30, 91, 255, 0.52); |
| | | } |
| | | |
| | | .footer-node--active .footer-node__dot { |
| | | background: #fff; |
| | | box-shadow: 0 0 12px rgba(255, 255, 255, 0.72); |
| | | animation: nodePulse 1.4s ease-in-out infinite; |
| | | } |
| | | |
| | | .agent-card { |
| | | position: absolute; |
| | | left: 50%; |
| | | top: 0; |
| | | width: 460px; |
| | | margin-left: -230px; |
| | | cursor: pointer; |
| | | transform-origin: center bottom; |
| | | transition: transform 0.35s ease, opacity 0.35s ease; |
| | | } |
| | | |
| | | .agent-card__head { |
| | | height: 56px; |
| | | border-radius: 12px 12px 0 0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 28px; |
| | | color: #fff; |
| | | font-weight: 700; |
| | | background: linear-gradient(135deg, #1f7a72 0%, #1e5bff 100%); |
| | | } |
| | | |
| | | .agent-card__head--active { |
| | | box-shadow: |
| | | 0 12px 22px rgba(30, 91, 255, 0.26), |
| | | inset 0 0 0 1px rgba(255, 255, 255, 0.28); |
| | | position: relative; |
| | | } |
| | | |
| | | .agent-card__head--active::after { |
| | | content: ""; |
| | | position: absolute; |
| | | left: 12px; |
| | | right: 12px; |
| | | bottom: 6px; |
| | | height: 3px; |
| | | border-radius: 999px; |
| | | background: linear-gradient(90deg, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0.96), rgba(255, 255, 255, 0.22)); |
| | | } |
| | | |
| | | .agent-card__body { |
| | | position: relative; |
| | | height: 430px; |
| | | border: 1px solid var(--surface-border-strong); |
| | | border-top: none; |
| | | border-radius: 0 0 20px 20px; |
| | | background: rgba(255, 255, 255, 0.96); |
| | | overflow: hidden; |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: flex-end; |
| | | isolation: isolate; |
| | | box-shadow: 0 12px 24px rgba(31, 49, 38, 0.1); |
| | | } |
| | | |
| | | .agent-card__body--active { |
| | | background: linear-gradient(180deg, rgba(248, 252, 251, 0.96), rgba(225, 241, 250, 0.9)); |
| | | border-color: rgba(31, 122, 114, 0.35); |
| | | } |
| | | |
| | | .agent-card__body--active::after { |
| | | content: ""; |
| | | position: absolute; |
| | | inset: 0; |
| | | background: linear-gradient(108deg, transparent 28%, rgba(255, 255, 255, 0.34) 50%, transparent 72%); |
| | | transform: translateX(-125%); |
| | | animation: bodySweep 3.6s linear infinite; |
| | | pointer-events: none; |
| | | z-index: 1; |
| | | } |
| | | |
| | | .avatar-shell { |
| | | position: relative; |
| | | width: 248px; |
| | | height: 430px; |
| | | display: flex; |
| | | align-items: flex-end; |
| | | justify-content: center; |
| | | --base-core: rgba(53, 143, 222, 0.4); |
| | | --base-ring: rgba(39, 122, 201, 0.62); |
| | | --base-glow: rgba(46, 133, 214, 0.28); |
| | | } |
| | | |
| | | .avatar-shell::before { |
| | | content: ""; |
| | | position: absolute; |
| | | left: 50%; |
| | | bottom: -10px; |
| | | width: 268px; |
| | | height: 58px; |
| | | transform: translateX(-50%); |
| | | border-radius: 50%; |
| | | background: radial-gradient( |
| | | ellipse at center, |
| | | rgba(55, 140, 219, 0.22) 0%, |
| | | rgba(55, 140, 219, 0.11) 46%, |
| | | rgba(55, 140, 219, 0) 74% |
| | | ); |
| | | filter: blur(2.4px); |
| | | animation: baseGlow 4.6s ease-in-out infinite; |
| | | z-index: 1; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .avatar-shell::after { |
| | | content: ""; |
| | | position: absolute; |
| | | left: 50%; |
| | | bottom: 0; |
| | | width: 248px; |
| | | height: 46px; |
| | | transform: translateX(-50%); |
| | | border-radius: 50%; |
| | | border: 2px solid var(--base-ring); |
| | | box-shadow: |
| | | inset 0 0 0 1px rgba(255, 255, 255, 0.64), |
| | | 0 0 24px var(--base-glow); |
| | | animation: basePulse 3.1s ease-in-out infinite; |
| | | z-index: 4; |
| | | } |
| | | |
| | | .avatar-base { |
| | | position: absolute; |
| | | left: 50%; |
| | | bottom: 2px; |
| | | width: 224px; |
| | | height: 38px; |
| | | transform: translateX(-50%); |
| | | z-index: 2; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .avatar-base::before { |
| | | content: ""; |
| | | position: absolute; |
| | | inset: 0; |
| | | border-radius: 50%; |
| | | background: |
| | | radial-gradient( |
| | | ellipse at center, |
| | | rgba(255, 255, 255, 0.96) 0%, |
| | | rgba(255, 255, 255, 0.92) 36%, |
| | | var(--base-core) 68%, |
| | | rgba(38, 118, 195, 0.08) 100% |
| | | ); |
| | | box-shadow: |
| | | 0 0 30px var(--base-core), |
| | | 0 0 10px rgba(255, 255, 255, 0.34) inset; |
| | | z-index: 3; |
| | | } |
| | | |
| | | .avatar-base::after { |
| | | content: ""; |
| | | position: absolute; |
| | | left: 50%; |
| | | top: 50%; |
| | | width: 194px; |
| | | height: 194px; |
| | | transform: translate(-50%, -50%); |
| | | border-radius: 50%; |
| | | background: |
| | | conic-gradient( |
| | | from 180deg, |
| | | transparent 0deg, |
| | | var(--base-ring) 48deg, |
| | | transparent 112deg, |
| | | var(--base-ring) 208deg, |
| | | transparent 284deg, |
| | | rgba(33, 114, 191, 0.48) 332deg, |
| | | transparent 360deg |
| | | ); |
| | | -webkit-mask: radial-gradient(circle, transparent 61%, #000 62%, #000 68%, transparent 70%); |
| | | mask: radial-gradient(circle, transparent 61%, #000 62%, #000 68%, transparent 70%); |
| | | opacity: 0.62; |
| | | animation: baseRotate 10.5s linear infinite; |
| | | z-index: 2; |
| | | } |
| | | |
| | | .avatar-shell--active { |
| | | --base-core: rgba(50, 141, 217, 0.52); |
| | | --base-ring: rgba(42, 127, 205, 0.76); |
| | | --base-glow: rgba(38, 130, 211, 0.38); |
| | | } |
| | | |
| | | .avatar-cut { |
| | | position: relative; |
| | | width: 220px; |
| | | height: 430px; |
| | | z-index: 6; |
| | | display: flex; |
| | | align-items: flex-end; |
| | | justify-content: center; |
| | | filter: saturate(1.04) drop-shadow(0 14px 18px rgba(24, 44, 66, 0.14)); |
| | | transform-origin: center 82%; |
| | | animation: avatarFloat 3.2s ease-in-out infinite; |
| | | } |
| | | |
| | | .avatar-cut__img { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: contain; |
| | | object-position: center bottom; |
| | | display: block; |
| | | } |
| | | |
| | | .agent-card--active .avatar-cut { |
| | | animation-duration: 2.6s; |
| | | } |
| | | |
| | | .highlight-list { |
| | | position: absolute; |
| | | right: 10px; |
| | | top: 14px; |
| | | display: grid; |
| | | gap: 8px; |
| | | width: 220px; |
| | | z-index: 16; |
| | | } |
| | | |
| | | .highlight-item { |
| | | border-radius: 10px; |
| | | padding: 8px 10px; |
| | | font-size: 18px; |
| | | line-height: 1.4; |
| | | color: #fff; |
| | | background: rgba(33, 49, 63, 0.92); |
| | | box-shadow: 0 8px 16px rgba(21, 30, 40, 0.22); |
| | | } |
| | | |
| | | .agent-card--active .highlight-item { |
| | | background: rgba(31, 122, 114, 0.9); |
| | | } |
| | | |
| | | .nav-btn { |
| | | position: absolute; |
| | | top: 212px; |
| | | z-index: 80; |
| | | width: 50px; |
| | | height: 50px; |
| | | border-radius: 50%; |
| | | border: none; |
| | | font-size: 30px; |
| | | color: var(--colorPrimary); |
| | | background: var(--surface-base); |
| | | box-shadow: 0 10px 20px rgba(31, 49, 38, 0.16); |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .nav-btn--left { |
| | | left: 14px; |
| | | } |
| | | |
| | | .nav-btn--right { |
| | | right: 14px; |
| | | } |
| | | |
| | | .ai-fullscreen { |
| | | position: fixed; |
| | | inset: 0; |
| | | z-index: 2100; |
| | | padding: 12px; |
| | | background: rgba(33, 49, 63, 0.24); |
| | | backdrop-filter: blur(2px); |
| | | } |
| | | |
| | | .ai-panel { |
| | | height: 100%; |
| | | border-radius: 22px; |
| | | border: 1px solid var(--surface-border); |
| | | background: linear-gradient(180deg, #f9fcfb 0%, #f0f5f2 100%); |
| | | display: grid; |
| | | grid-template-rows: 62px minmax(0, 1fr) 110px; |
| | | box-shadow: var(--shadow-md); |
| | | } |
| | | |
| | | .ai-panel__top { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 0 24px; |
| | | } |
| | | |
| | | .ai-brand { |
| | | font-size: 34px; |
| | | color: var(--text-primary); |
| | | font-weight: 700; |
| | | } |
| | | |
| | | .ai-close { |
| | | width: 40px; |
| | | height: 40px; |
| | | border: none; |
| | | border-radius: 50%; |
| | | background: transparent; |
| | | font-size: 30px; |
| | | color: var(--text-secondary); |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .ai-panel__center { |
| | | padding: 8px 20px 10px; |
| | | display: grid; |
| | | grid-template-rows: 120px 290px minmax(0, 1fr); |
| | | gap: 10px; |
| | | min-height: 0; |
| | | } |
| | | |
| | | .welcome-card { |
| | | border-radius: 14px; |
| | | background: linear-gradient(135deg, rgba(232, 244, 242, 0.95), rgba(230, 237, 250, 0.9)); |
| | | padding: 16px 18px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | gap: 12px; |
| | | border: 1px solid var(--surface-border); |
| | | } |
| | | |
| | | .welcome-card__text h3 { |
| | | margin: 0; |
| | | font-size: 28px; |
| | | color: var(--text-primary); |
| | | } |
| | | |
| | | .welcome-card__text p { |
| | | margin: 8px 0 0; |
| | | font-size: 20px; |
| | | color: var(--text-secondary); |
| | | } |
| | | |
| | | .mini-avatar { |
| | | width: 120px; |
| | | height: 120px; |
| | | border-radius: 14px; |
| | | border: 1px solid var(--surface-border); |
| | | background-color: #fff; |
| | | background-clip: border-box; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .mini-avatar__img { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: contain; |
| | | object-position: center bottom; |
| | | display: block; |
| | | } |
| | | |
| | | .recommend-card { |
| | | border-radius: 14px; |
| | | border: 1px solid var(--surface-border); |
| | | background: rgba(255, 255, 255, 0.86); |
| | | padding: 12px 14px; |
| | | } |
| | | |
| | | .recommend-card__head { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-bottom: 10px; |
| | | color: var(--text-primary); |
| | | font-size: 24px; |
| | | font-weight: 700; |
| | | } |
| | | |
| | | .refresh-btn { |
| | | border: none; |
| | | background: transparent; |
| | | color: var(--text-secondary); |
| | | font-size: 18px; |
| | | display: inline-flex; |
| | | align-items: center; |
| | | gap: 4px; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .recommend-grid { |
| | | display: grid; |
| | | grid-template-columns: 1fr 1fr; |
| | | gap: 8px 18px; |
| | | } |
| | | |
| | | .recommend-item { |
| | | border: 1px solid var(--surface-border); |
| | | border-radius: 8px; |
| | | text-align: left; |
| | | padding: 8px 10px; |
| | | font-size: 18px; |
| | | color: var(--text-secondary); |
| | | background: #fff; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .recommend-item:hover { |
| | | background: rgba(31, 122, 114, 0.08); |
| | | color: var(--colorPrimary); |
| | | } |
| | | |
| | | .chat-card { |
| | | border-radius: 14px; |
| | | border: 1px solid var(--surface-border); |
| | | background: #fff; |
| | | min-height: 0; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .chat-empty { |
| | | height: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | color: var(--text-tertiary); |
| | | font-size: 18px; |
| | | } |
| | | |
| | | .chat-messages { |
| | | height: 100%; |
| | | overflow-y: auto; |
| | | padding: 14px; |
| | | display: grid; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .chat-row { |
| | | display: flex; |
| | | } |
| | | |
| | | .chat-row--assistant { |
| | | justify-content: flex-start; |
| | | } |
| | | |
| | | .chat-row--user { |
| | | justify-content: flex-end; |
| | | } |
| | | |
| | | .chat-bubble { |
| | | max-width: 72%; |
| | | border-radius: 12px; |
| | | padding: 10px 12px; |
| | | font-size: 18px; |
| | | line-height: 1.5; |
| | | white-space: pre-wrap; |
| | | color: var(--text-primary); |
| | | background: var(--surface-soft); |
| | | border: 1px solid var(--surface-border); |
| | | } |
| | | |
| | | .chat-row--user .chat-bubble { |
| | | color: #fff; |
| | | background: linear-gradient(135deg, #1f7a72 0%, #1e5bff 100%); |
| | | border: none; |
| | | } |
| | | |
| | | .ai-panel__input { |
| | | display: grid; |
| | | grid-template-columns: minmax(0, 1fr) 130px; |
| | | gap: 12px; |
| | | padding: 14px 20px 18px; |
| | | } |
| | | |
| | | .ask-input :deep(.el-input__wrapper) { |
| | | height: 74px; |
| | | border-radius: 18px; |
| | | box-shadow: 0 0 0 1px var(--surface-border) inset; |
| | | background: #fff; |
| | | } |
| | | |
| | | .ask-input :deep(.el-input__inner) { |
| | | font-size: 20px; |
| | | } |
| | | |
| | | .send-btn { |
| | | align-self: center; |
| | | height: 56px; |
| | | font-size: 20px; |
| | | min-width: 98px; |
| | | } |
| | | |
| | | .fade-enter-active, |
| | | .fade-leave-active { |
| | | transition: opacity 0.2s ease; |
| | | } |
| | | |
| | | .fade-enter-from, |
| | | .fade-leave-to { |
| | | opacity: 0; |
| | | } |
| | | |
| | | @keyframes avatarFloat { |
| | | 0%, |
| | | 100% { |
| | | transform: translateY(0); |
| | | } |
| | | 50% { |
| | | transform: translateY(-8px); |
| | | } |
| | | } |
| | | |
| | | @keyframes basePulse { |
| | | 0%, |
| | | 100% { |
| | | transform: translateX(-50%) scale(1); |
| | | opacity: 0.88; |
| | | } |
| | | 50% { |
| | | transform: translateX(-50%) scale(1.045); |
| | | opacity: 0.95; |
| | | } |
| | | } |
| | | |
| | | @keyframes baseRotate { |
| | | from { |
| | | transform: translate(-50%, -50%) rotate(0deg); |
| | | } |
| | | to { |
| | | transform: translate(-50%, -50%) rotate(360deg); |
| | | } |
| | | } |
| | | |
| | | @keyframes baseGlow { |
| | | 0%, |
| | | 100% { |
| | | transform: translateX(-50%) scaleX(1); |
| | | opacity: 0.84; |
| | | } |
| | | 50% { |
| | | transform: translateX(-50%) scaleX(1.06); |
| | | opacity: 0.96; |
| | | } |
| | | } |
| | | |
| | | @keyframes bodySweep { |
| | | 0% { |
| | | transform: translateX(-125%); |
| | | } |
| | | 100% { |
| | | transform: translateX(135%); |
| | | } |
| | | } |
| | | |
| | | @keyframes footerSweep { |
| | | 0% { |
| | | transform: translateX(-120%); |
| | | } |
| | | 100% { |
| | | transform: translateX(140%); |
| | | } |
| | | } |
| | | |
| | | @keyframes railFlow { |
| | | 0% { |
| | | transform: translateX(0); |
| | | opacity: 0; |
| | | } |
| | | 20% { |
| | | opacity: 1; |
| | | } |
| | | 80% { |
| | | opacity: 1; |
| | | } |
| | | 100% { |
| | | transform: translateX(520%); |
| | | opacity: 0; |
| | | } |
| | | } |
| | | |
| | | @keyframes nodePulse { |
| | | 0%, |
| | | 100% { |
| | | transform: scale(1); |
| | | } |
| | | 50% { |
| | | transform: scale(1.25); |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 1600px) { |
| | | .head-title { |
| | | font-size: 34px; |
| | | height: 60px; |
| | | } |
| | | |
| | | .brain-intro h2 { |
| | | font-size: 36px; |
| | | } |
| | | |
| | | .brain-intro p { |
| | | font-size: 22px; |
| | | } |
| | | |
| | | .intro-sign { |
| | | font-size: 20px; |
| | | } |
| | | |
| | | .agent-card { |
| | | width: 380px; |
| | | margin-left: -190px; |
| | | } |
| | | |
| | | .agent-card__head { |
| | | font-size: 24px; |
| | | height: 54px; |
| | | } |
| | | |
| | | .agent-card__body { |
| | | height: 390px; |
| | | } |
| | | |
| | | .highlight-list { |
| | | width: 184px; |
| | | } |
| | | |
| | | .highlight-item { |
| | | font-size: 15px; |
| | | } |
| | | |
| | | .avatar-shell { |
| | | width: 220px; |
| | | height: 390px; |
| | | } |
| | | |
| | | .avatar-cut { |
| | | width: 202px; |
| | | height: 390px; |
| | | } |
| | | |
| | | .avatar-base { |
| | | width: 194px; |
| | | height: 34px; |
| | | } |
| | | |
| | | .avatar-base::after { |
| | | width: 164px; |
| | | height: 164px; |
| | | } |
| | | |
| | | .avatar-shell::before { |
| | | width: 236px; |
| | | height: 48px; |
| | | bottom: -9px; |
| | | } |
| | | |
| | | .avatar-shell::after { |
| | | width: 220px; |
| | | height: 40px; |
| | | bottom: 0; |
| | | } |
| | | |
| | | .brain-footer { |
| | | margin: 0 52px; |
| | | height: clamp(210px, 23vh, 264px); |
| | | } |
| | | |
| | | .footer-metrics { |
| | | padding: 12px 14px 66px; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .footer-metric { |
| | | min-height: 66px; |
| | | padding: 8px 10px; |
| | | } |
| | | |
| | | .footer-metric--period { |
| | | min-height: 108px; |
| | | gap: 4px; |
| | | } |
| | | |
| | | .footer-metric__label { |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .footer-metric__value { |
| | | font-size: 24px; |
| | | } |
| | | |
| | | .footer-metric__hint { |
| | | font-size: 11px; |
| | | } |
| | | |
| | | .footer-period-control { |
| | | gap: 6px; |
| | | } |
| | | |
| | | .period-btn { |
| | | width: 20px; |
| | | height: 20px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .period-input { |
| | | width: 50px; |
| | | height: 22px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .footer-period-slider { |
| | | width: 100%; |
| | | } |
| | | |
| | | .footer-rail { |
| | | left: 14px; |
| | | right: 14px; |
| | | bottom: 14px; |
| | | } |
| | | |
| | | .footer-rail__nodes { |
| | | margin-top: 10px; |
| | | gap: 6px; |
| | | } |
| | | |
| | | .footer-node { |
| | | height: 30px; |
| | | font-size: 12px; |
| | | gap: 6px; |
| | | } |
| | | |
| | | .footer-node__dot { |
| | | width: 7px; |
| | | height: 7px; |
| | | } |
| | | |
| | | .ai-brand { |
| | | font-size: 28px; |
| | | } |
| | | |
| | | .welcome-card__text h3, |
| | | .recommend-card__head { |
| | | font-size: 22px; |
| | | } |
| | | |
| | | .welcome-card__text p, |
| | | .recommend-item, |
| | | .chat-bubble, |
| | | .refresh-btn, |
| | | .chat-empty, |
| | | .ask-input :deep(.el-input__inner), |
| | | .send-btn { |
| | | font-size: 16px; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <div> |
| | | <el-button type="primary" |
| | | @click="openForm('add')">æ°å¢å®¢æ·</el-button> |
| | | <el-button type="primary" |
| | | plain |
| | | @click="back">æµå
¥å
¬æµ·</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="info" |
| | | plain |
| | |
| | | addReturnVisit, |
| | | getReturnVisit, |
| | | } from "@/api/basicData/customerFile.js"; |
| | | import {listCustomer, getCustomer, addCustomer, updateCustomer, delCustomer} from "@/api/basicData/customer.js"; |
| | | import {listCustomer, getCustomer, addCustomer, updateCustomer, delCustomer, backCustomer} from "@/api/basicData/customer.js"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | |
| | | }); |
| | | }; |
| | | |
| | | const back = () => { |
| | | if (selectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | const ids = selectedRows.value.map(item => item.id); |
| | | ElMessageBox.confirm("éä¸ç客æ·å°æµå
¥å
¬æµ·ï¼æ¯å¦ç¡®è®¤ï¼", "æµå
¥å
¬æµ·æç¤º", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | tableLoading.value = true; |
| | | return Promise.all(ids.map(id => backCustomer(id))) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("æµå
¥å
¬æµ·æå"); |
| | | selectedRows.value = []; |
| | | getList(); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }) |
| | | .catch(error => { |
| | | if (error === "cancel" || error === "close") { |
| | | proxy.$modal.msg("已忶"); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // æå¼å访æéå¼¹çª |
| | | const openReminderDialog = row => { |
| | | currentCustomerId.value = row.id; |
| | |
| | | const downloadAttachment = row => { |
| | | if (row.url) { |
| | | // proxy.download(row.url, {}, row.name); |
| | | proxy.$download.name(row.url); |
| | | proxy.$download.byUrl(row.url, row.originalFilename); |
| | | } else { |
| | | proxy.$modal.msgError("ä¸è½½é¾æ¥ä¸åå¨"); |
| | | } |
| | |
| | | const downloadAttachment = row => { |
| | | if (row.url) { |
| | | // proxy.download(row.url, {}, row.name); |
| | | proxy.$download.name(row.url); |
| | | proxy.$download.byUrl(row.url, row.originalFilename); |
| | | } else { |
| | | proxy.$modal.msgError("ä¸è½½é¾æ¥ä¸åå¨"); |
| | | } |
| | |
| | | <el-input v-model="search" |
| | | style="width: 210px" |
| | | placeholder="è¾å
¥å
³é®åè¿è¡æç´¢" |
| | | @change="searchFilter" |
| | | @input="debouncedSearch" |
| | | @clear="searchFilter" |
| | | clearable |
| | | prefix-icon="Search" /> |
| | |
| | | <el-button type="primary" |
| | | link |
| | | :disabled="isTopLevelNode(data, node)" |
| | | @click="openProDia('edit', data)"> |
| | | @click="openProDia('edit', data, node)"> |
| | | ç¼è¾ |
| | | </el-button> |
| | | <el-button type="primary" |
| | | link |
| | | @click="openProDia('add', data)"> |
| | | @click="openProDia('add', data, node)"> |
| | | æ·»å 产å |
| | | </el-button> |
| | | <el-button v-if="!node.childNodes.length" |
| | |
| | | const search = ref(""); |
| | | const currentId = ref(""); |
| | | const currentParentId = ref(""); |
| | | /** 产åå¼¹çªï¼add åç¶èç¹ idï¼edit åå½åèç¹ id ä¸ parentIdï¼ä¸ä¾èµæ éä¸é¡¹ï¼ */ |
| | | const productDialogTarget = ref(null); |
| | | const operationType = ref(""); |
| | | const treeLoad = ref(false); |
| | | const list = ref([]); |
| | |
| | | return [null, undefined, "", 0, "0"].includes(data?.parentId); |
| | | }; |
| | | // æå¼äº§åå¼¹æ¡ |
| | | const openProDia = (type, data) => { |
| | | if (data && type === "edit" && isTopLevelNode(data)) { |
| | | const openProDia = (type, data, node) => { |
| | | if (data && type === "edit" && isTopLevelNode(data, node)) { |
| | | proxy.$modal.msgWarning("ä¸çº§èç¹ä¸è½ç¼è¾æå é¤"); |
| | | return; |
| | | } |
| | | operationType.value = type; |
| | | productDia.value = true; |
| | | form.value.productName = ""; |
| | | if (type === "edit") { |
| | | form.value.productName = data.productName; |
| | | productDialogTarget.value = null; |
| | | if (type === "add" && data) { |
| | | productDialogTarget.value = { parentId: data.id }; |
| | | } else if (type === "edit" && data) { |
| | | let parentId = data.parentId; |
| | | if ( |
| | | [null, undefined, ""].includes(parentId) && |
| | | node?.parent?.data?.id != null |
| | | ) { |
| | | parentId = node.parent.data.id; |
| | | } |
| | | productDialogTarget.value = { id: data.id, parentId }; |
| | | } |
| | | productDia.value = true; |
| | | form.value.productName = |
| | | type === "edit" && data ? data.productName : ""; |
| | | }; |
| | | // æå¼è§æ ¼åå·å¼¹æ¡ |
| | | const openModelDia = (type, data) => { |
| | |
| | | proxy.$refs.formRef.validate(valid => { |
| | | if (valid) { |
| | | if (operationType.value === "add") { |
| | | form.value.parentId = currentId.value; |
| | | form.value.parentId = |
| | | productDialogTarget.value?.parentId ?? currentId.value; |
| | | form.value.id = ""; |
| | | } else if (operationType.value === "addOne") { |
| | | form.value.id = ""; |
| | | form.value.parentId = ""; |
| | | } else { |
| | | form.value.id = currentId.value; |
| | | form.value.parentId = ""; |
| | | form.value.id = |
| | | productDialogTarget.value?.id ?? currentId.value; |
| | | form.value.parentId = productDialogTarget.value?.parentId ?? ""; |
| | | } |
| | | addOrEditProduct(form.value).then(res => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | |
| | | // å
³é产åå¼¹æ¡ |
| | | const closeProDia = () => { |
| | | proxy.$refs.formRef.resetFields(); |
| | | productDialogTarget.value = null; |
| | | productDia.value = false; |
| | | }; |
| | | |
| | |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | // è°ç¨treeè¿æ»¤æ¹æ³ 䏿è±è¿æ»¤ |
| | | const filterNode = (value, data, node) => { |
| | | if (!value) { |
| | | //å¦ææ°æ®ä¸ºç©ºï¼åè¿åtrue,æ¾ç¤ºææçæ°æ®é¡¹ |
| | | return true; |
| | | } |
| | | // æ¥è¯¢å表æ¯å¦æå¹é
æ°æ®ï¼å°å¼å°åï¼å¹é
è±ææ°æ® |
| | | let val = value.toLowerCase(); |
| | | return chooseNode(val, data, node); // è°ç¨è¿æ»¤äºå±æ¹æ³ |
| | | const debounce = (fn, delay = 300) => { |
| | | let timer; |
| | | return (...args) => { |
| | | clearTimeout(timer); |
| | | timer = setTimeout(() => fn(...args), delay); |
| | | }; |
| | | }; |
| | | // è¿æ»¤ç¶èç¹ / åèç¹ (妿è¾å
¥çåæ°æ¯ç¶èç¹ä¸è½å¹é
ï¼åè¿å该èç¹ä»¥åå
¶ä¸çææåèç¹ï¼å¦æåæ°æ¯åèç¹ï¼åè¿å该èç¹çç¶èç¹ãnameæ¯ä¸æå符ï¼enNameæ¯è±æå符. |
| | | const chooseNode = (value, data, node) => { |
| | | if (data.label.indexOf(value) !== -1) { |
| | | |
| | | const debouncedSearch = debounce(() => { |
| | | searchFilter(); |
| | | }, 300); |
| | | |
| | | const filterNode = (value, data) => { |
| | | if (!value) return true; |
| | | return chooseNode(value.toLowerCase(), data); |
| | | }; |
| | | |
| | | const chooseNode = (value, data) => { |
| | | const label = (data.label || '').toLowerCase(); |
| | | if (label.indexOf(value) !== -1) { |
| | | return true; |
| | | } |
| | | const level = node.level; |
| | | // å¦æä¼ å
¥çèç¹æ¬èº«å°±æ¯ä¸çº§èç¹å°±ä¸ç¨æ ¡éªäº |
| | | if (level === 1) { |
| | | return false; |
| | | if (data.children && data.children.length > 0) { |
| | | return data.children.some(child => chooseNode(value, child)); |
| | | } |
| | | // å
åå½åèç¹çç¶èç¹ |
| | | let parentData = node.parent; |
| | | // éåå½åèç¹çç¶èç¹ |
| | | let index = 0; |
| | | while (index < level - 1) { |
| | | // 妿å¹é
å°ç´æ¥è¿åï¼æ¤å¤name弿¯ä¸æå符ï¼enNameæ¯è±æå符ã夿å¹é
ä¸è±æè¿æ»¤ |
| | | if (parentData.data.label.indexOf(value) !== -1) { |
| | | return true; |
| | | } |
| | | // å¦åçè¯åå¾ä¸ä¸å±åå¹é
|
| | | parentData = parentData.parent; |
| | | index++; |
| | | } |
| | | // 没å¹é
å°è¿åfalse |
| | | return false; |
| | | }; |
| | | getProductTreeList(); |
| | |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <files-dia ref="filesDia"></files-dia> |
| | | <FileList v-if="fileListDialogVisible" |
| | | v-model:visible="fileListDialogVisible" |
| | | record-type="supplier_manage" |
| | | :record-id="recordId" /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | } from "@/api/basicData/supplierManageFile.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { getToken } from "@/utils/auth.js"; |
| | | import FilesDia from "../filesDia.vue"; |
| | | const FileList = defineAsyncComponent(() => |
| | | import("@/components/Dialog/FileList.vue") |
| | | ); |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore(); |
| | | |
| | |
| | | name: "èµè´¨æä»¶", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | openFilesFormDia(row) |
| | | openFileDialog(row) |
| | | } |
| | | } |
| | | ], |
| | |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | const filesDia = ref() |
| | | const fileListDialogVisible = ref(false); |
| | | const recordId = ref(); |
| | | // ç¨æ·ä¿¡æ¯è¡¨åå¼¹æ¡æ°æ® |
| | | const operationType = ref(""); |
| | | const dialogFormVisible = ref(false); |
| | |
| | | return `${year}-${month}-${day}`; |
| | | } |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFilesFormDia = (row) => { |
| | | nextTick(() => { |
| | | filesDia.value?.openDialog(row) |
| | | }) |
| | | const openFileDialog = async row => { |
| | | recordId.value = row.id; |
| | | fileListDialogVisible.value = true; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <files-dia ref="filesDia"></files-dia> |
| | | <FileList v-if="fileListDialogVisible" |
| | | v-model:visible="fileListDialogVisible" |
| | | record-type="supplier_manage" |
| | | :record-id="recordId" /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | } from "@/api/basicData/supplierManageFile.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { getToken } from "@/utils/auth.js"; |
| | | import FilesDia from "../filesDia.vue"; |
| | | const FileList = defineAsyncComponent(() => |
| | | import("@/components/Dialog/FileList.vue") |
| | | ); |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore(); |
| | | |
| | |
| | | name: "èµè´¨æä»¶", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | openFilesFormDia(row) |
| | | openFileDialog(row) |
| | | } |
| | | } |
| | | ], |
| | |
| | | const selectedRows = ref([]); |
| | | const userList = ref([]); |
| | | const tableLoading = ref(false); |
| | | const fileListDialogVisible = ref(false); |
| | | const recordId = ref(); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | const filesDia = ref() |
| | | // ç¨æ·ä¿¡æ¯è¡¨åå¼¹æ¡æ°æ® |
| | | const operationType = ref(""); |
| | | const dialogFormVisible = ref(false); |
| | |
| | | return `${year}-${month}-${day}`; |
| | | } |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFilesFormDia = (row) => { |
| | | nextTick(() => { |
| | | filesDia.value?.openDialog(row) |
| | | }) |
| | | const openFileDialog = async row => { |
| | | recordId.value = row.id; |
| | | fileListDialogVisible.value = true; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | |
| | | } |
| | | // ä¸è½½éä»¶ |
| | | const downLoadFile = (row) => { |
| | | proxy.$download.name(row.url); |
| | | proxy.$download.byUrl(row.url, row.originalFilename); |
| | | } |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog |
| | | v-model="dialogFormVisible" |
| | | :title="operationType === 'approval' ? '审æ¹' : '详æ
'" |
| | | width="700px" |
| | | @close="closeDia" |
| | | > |
| | | <el-form :model="form" label-width="140px" label-position="top" ref="formRef"> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="æµç¨ç¼å·ï¼" prop="approveId"> |
| | | <el-input v-model="form.approveId" placeholder="èªå¨ç¼å·" clearable disabled/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="ç³è¯·é¨é¨ï¼"> |
| | | <el-select |
| | | disabled |
| | | v-model="form.approveDeptId" |
| | | placeholder="éæ©é¨é¨" |
| | | > |
| | | <el-option |
| | | v-for="user in productOptions" |
| | | :key="user.deptId" |
| | | :label="user.deptName" |
| | | :value="user.deptId" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row v-if="!isQuotationApproval && !isPurchaseApproval"> |
| | | <el-col :span="24"> |
| | | <el-form-item :label="props.approveType == 5 ? 'éè´ååå·ï¼' : '审æ¹äºç±ï¼'" prop="approveReason"> |
| | | <el-input v-model="form.approveReason" placeholder="请è¾å
¥" clearable type="textarea" disabled/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | |
| | | <el-dialog v-model="dialogFormVisible" |
| | | :title="operationType === 'approval' ? '审æ¹' : '详æ
'" |
| | | width="700px" |
| | | @close="closeDia"> |
| | | <el-form :model="form" |
| | | label-width="140px" |
| | | label-position="top" |
| | | ref="formRef"> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="æµç¨ç¼å·ï¼" |
| | | prop="approveId"> |
| | | <el-input v-model="form.approveId" |
| | | placeholder="èªå¨ç¼å·" |
| | | clearable |
| | | disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="ç³è¯·é¨é¨ï¼"> |
| | | <el-select disabled |
| | | v-model="form.approveDeptId" |
| | | placeholder="éæ©é¨é¨"> |
| | | <el-option v-for="user in productOptions" |
| | | :key="user.deptId" |
| | | :label="user.deptName" |
| | | :value="user.deptId" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row v-if="!isQuotationApproval && !isPurchaseApproval"> |
| | | <el-col :span="24"> |
| | | <el-form-item :label="props.approveType == 5 ? 'éè´ååå·ï¼' : '审æ¹äºç±ï¼'" |
| | | prop="approveReason"> |
| | | <el-input v-model="form.approveReason" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | type="textarea" |
| | | disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <!-- æ¥ä»·å®¡æ¹ï¼å±ç¤ºæ¥ä»·è¯¦æ
ï¼å¤ç¨é宿¥ä»·"æ¥ç详æ
å¯¹è¯æ¡"å
å®¹ç»æï¼ --> |
| | | <div v-if="isQuotationApproval" style="margin: 10px 0 18px;"> |
| | | <div v-if="isQuotationApproval" |
| | | style="margin: 10px 0 18px;"> |
| | | <el-divider content-position="left">æ¥ä»·è¯¦æ
</el-divider> |
| | | <el-skeleton :loading="quotationLoading" animated> |
| | | <el-skeleton :loading="quotationLoading" |
| | | animated> |
| | | <template #template> |
| | | <el-skeleton-item variant="h3" style="width: 30%" /> |
| | | <el-skeleton-item variant="text" style="width: 100%" /> |
| | | <el-skeleton-item variant="text" style="width: 100%" /> |
| | | <el-skeleton-item variant="h3" |
| | | style="width: 30%" /> |
| | | <el-skeleton-item variant="text" |
| | | style="width: 100%" /> |
| | | <el-skeleton-item variant="text" |
| | | style="width: 100%" /> |
| | | </template> |
| | | <template #default> |
| | | <el-empty v-if="!currentQuotation || !currentQuotation.quotationNo" description="æªæ¥è¯¢å°å¯¹åºæ¥ä»·è¯¦æ
" /> |
| | | <el-empty v-if="!currentQuotation || !currentQuotation.quotationNo" |
| | | description="æªæ¥è¯¢å°å¯¹åºæ¥ä»·è¯¦æ
" /> |
| | | <template v-else> |
| | | <el-descriptions :column="2" border> |
| | | <el-descriptions :column="2" |
| | | border> |
| | | <el-descriptions-item label="æ¥ä»·åå·">{{ currentQuotation.quotationNo }}</el-descriptions-item> |
| | | <el-descriptions-item label="客æ·åç§°">{{ currentQuotation.customer }}</el-descriptions-item> |
| | | <el-descriptions-item label="ä¸å¡å">{{ currentQuotation.salesperson }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ¥ä»·æ¥æ">{{ currentQuotation.quotationDate }}</el-descriptions-item> |
| | | <el-descriptions-item label="æææè³">{{ currentQuotation.validDate }}</el-descriptions-item> |
| | | <el-descriptions-item label="仿¬¾æ¹å¼">{{ currentQuotation.paymentMethod }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ¥ä»·æ»é¢" :span="2"> |
| | | <el-descriptions-item label="æ¥ä»·æ»é¢" |
| | | :span="2"> |
| | | <span style="font-size: 18px; color: #e6a23c; font-weight: bold;"> |
| | | ¥{{ Number(currentQuotation.totalAmount ?? 0).toFixed(2) }} |
| | | </span> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | |
| | | <div style="margin-top: 20px;"> |
| | | <h4>产åæç»</h4> |
| | | <el-table :data="currentQuotation.products || []" border style="width: 100%"> |
| | | <el-table-column prop="product" label="产ååç§°" /> |
| | | <el-table-column prop="specification" label="è§æ ¼åå·" /> |
| | | <el-table-column prop="unit" label="åä½" /> |
| | | <el-table-column prop="unitPrice" label="åä»·"> |
| | | <el-table :data="currentQuotation.products || []" |
| | | border |
| | | style="width: 100%"> |
| | | <el-table-column prop="product" |
| | | label="产ååç§°" /> |
| | | <el-table-column prop="specification" |
| | | label="è§æ ¼åå·" /> |
| | | <el-table-column prop="unit" |
| | | label="åä½" /> |
| | | <el-table-column prop="unitPrice" |
| | | label="åä»·"> |
| | | <template #default="scope">Â¥{{ Number(scope.row.unitPrice ?? 0).toFixed(2) }}</template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <div v-if="currentQuotation.remark" style="margin-top: 20px;"> |
| | | <div v-if="currentQuotation.remark" |
| | | style="margin-top: 20px;"> |
| | | <h4>夿³¨</h4> |
| | | <p>{{ currentQuotation.remark }}</p> |
| | | </div> |
| | |
| | | </template> |
| | | </el-skeleton> |
| | | </div> |
| | | |
| | | <!-- éè´å®¡æ¹ï¼å±ç¤ºéè´è¯¦æ
--> |
| | | <div v-if="isPurchaseApproval" style="margin: 10px 0 18px;"> |
| | | <div v-if="isPurchaseApproval" |
| | | style="margin: 10px 0 18px;"> |
| | | <el-divider content-position="left">éè´è¯¦æ
</el-divider> |
| | | <el-skeleton :loading="purchaseLoading" animated> |
| | | <el-skeleton :loading="purchaseLoading" |
| | | animated> |
| | | <template #template> |
| | | <el-skeleton-item variant="h3" style="width: 30%" /> |
| | | <el-skeleton-item variant="text" style="width: 100%" /> |
| | | <el-skeleton-item variant="text" style="width: 100%" /> |
| | | <el-skeleton-item variant="h3" |
| | | style="width: 30%" /> |
| | | <el-skeleton-item variant="text" |
| | | style="width: 100%" /> |
| | | <el-skeleton-item variant="text" |
| | | style="width: 100%" /> |
| | | </template> |
| | | <template #default> |
| | | <el-empty v-if="!currentPurchase || !currentPurchase.purchaseContractNumber" description="æªæ¥è¯¢å°å¯¹åºéè´è¯¦æ
" /> |
| | | <el-empty v-if="!currentPurchase || !currentPurchase.purchaseContractNumber" |
| | | description="æªæ¥è¯¢å°å¯¹åºéè´è¯¦æ
" /> |
| | | <template v-else> |
| | | <el-descriptions :column="2" border> |
| | | <el-descriptions :column="2" |
| | | border> |
| | | <el-descriptions-item label="éè´ååå·">{{ currentPurchase.purchaseContractNumber }}</el-descriptions-item> |
| | | <el-descriptions-item label="ä¾åºååç§°">{{ currentPurchase.supplierName }}</el-descriptions-item> |
| | | <el-descriptions-item label="项ç®åç§°">{{ currentPurchase.projectName }}</el-descriptions-item> |
| | |
| | | <el-descriptions-item label="ç¾è®¢æ¥æ">{{ currentPurchase.executionDate }}</el-descriptions-item> |
| | | <el-descriptions-item label="å½å
¥æ¥æ">{{ currentPurchase.entryDate }}</el-descriptions-item> |
| | | <el-descriptions-item label="仿¬¾æ¹å¼">{{ currentPurchase.paymentMethod }}</el-descriptions-item> |
| | | <el-descriptions-item label="ååéé¢" :span="2"> |
| | | <el-descriptions-item label="ååéé¢" |
| | | :span="2"> |
| | | <span style="font-size: 18px; color: #e6a23c; font-weight: bold;"> |
| | | ¥{{ Number(currentPurchase.contractAmount ?? 0).toFixed(2) }} |
| | | </span> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | |
| | | <div style="margin-top: 20px;"> |
| | | <h4>产åæç»</h4> |
| | | <el-table :data="currentPurchase.productData || []" border style="width: 100%"> |
| | | <el-table-column prop="productCategory" label="产ååç§°" /> |
| | | <el-table-column prop="specificationModel" label="è§æ ¼åå·" /> |
| | | <el-table-column prop="unit" label="åä½" /> |
| | | <el-table-column prop="quantity" label="æ°é" /> |
| | | <el-table-column prop="taxInclusiveUnitPrice" label="å«ç¨åä»·"> |
| | | <el-table :data="currentPurchase.productData || []" |
| | | border |
| | | style="width: 100%"> |
| | | <el-table-column prop="productCategory" |
| | | label="产ååç§°" /> |
| | | <el-table-column prop="specificationModel" |
| | | label="è§æ ¼åå·" /> |
| | | <el-table-column prop="unit" |
| | | label="åä½" /> |
| | | <el-table-column prop="quantity" |
| | | label="æ°é" /> |
| | | <el-table-column prop="taxInclusiveUnitPrice" |
| | | label="å«ç¨åä»·"> |
| | | <template #default="scope">Â¥{{ Number(scope.row.taxInclusiveUnitPrice ?? 0).toFixed(2) }}</template> |
| | | </el-table-column> |
| | | <el-table-column prop="taxInclusiveTotalPrice" label="å«ç¨æ»ä»·"> |
| | | <el-table-column prop="taxInclusiveTotalPrice" |
| | | label="å«ç¨æ»ä»·"> |
| | | <template #default="scope">Â¥{{ Number(scope.row.taxInclusiveTotalPrice ?? 0).toFixed(2) }}</template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | </template> |
| | | </el-skeleton> |
| | | </div> |
| | | |
| | | <el-form :model="{ activities }" ref="formRef" label-position="top"> |
| | | <el-steps :active="getActiveStep()" finish-status="success" process-status="process" align-center direction="vertical"> |
| | | <el-step |
| | | v-for="(activity, index) in activities" |
| | | :key="index" |
| | | finish-status="success" |
| | | :title="getNodeTitle(index, activities.length)" |
| | | :description="activity.approveNodeUser" |
| | | :icon="getNodeIcon(activity, index)" |
| | | > |
| | | <template #icon> |
| | | <el-icon v-if="activity.approveNodeStatus === 2" color="red" :size="22"><WarningFilled /></el-icon> |
| | | <el-icon v-else-if="activity.isShen" color="#1890ff" :size="22"><Edit /></el-icon> |
| | | <el-icon v-else-if="activity.approveNodeStatus === 1" color="#67C23A" :size="26"><Check /></el-icon> |
| | | <el-icon v-else color="#C0C4CC" :size="22"><MoreFilled /></el-icon> |
| | | </template> |
| | | <!-- å货审æ¹ï¼å±ç¤ºå货详æ
--> |
| | | <div v-if="isDeliveryApproval" |
| | | style="margin: 10px 0 18px;"> |
| | | <el-divider content-position="left">å货详æ
</el-divider> |
| | | <el-skeleton :loading="deliveryLoading" |
| | | animated> |
| | | <template #template> |
| | | <el-skeleton-item variant="h3" |
| | | style="width: 30%" /> |
| | | <el-skeleton-item variant="text" |
| | | style="width: 100%" /> |
| | | <el-skeleton-item variant="text" |
| | | style="width: 100%" /> |
| | | </template> |
| | | <template #default> |
| | | <el-empty v-if="!currentDelivery || !currentDelivery.shippingInfo" |
| | | description="æªæ¥è¯¢å°å¯¹åºå货详æ
" /> |
| | | <template v-else> |
| | | <el-descriptions :column="2" |
| | | border> |
| | | <el-descriptions-item label="éå®è®¢å">{{ currentDelivery.shippingInfo.salesContractNo || '--' }}</el-descriptions-item> |
| | | <el-descriptions-item label="å货订åå·">{{ currentDelivery.shippingInfo.shippingNo || '--' }}</el-descriptions-item> |
| | | <el-descriptions-item label="客æ·åç§°">{{ currentDelivery.shippingInfo.customerName || '--' }}</el-descriptions-item> |
| | | <el-descriptions-item label="åè´§ç±»å">{{ currentDelivery.shippingInfo.type || '--' }}</el-descriptions-item> |
| | | <el-descriptions-item label="åè´§æ¥æ">{{ currentDelivery.shippingInfo.shippingDate || '--' }}</el-descriptions-item> |
| | | <el-descriptions-item label="å®¡æ ¸ç¶æ">{{ currentDelivery.shippingInfo.status || '--' }}</el-descriptions-item> |
| | | <el-descriptions-item label="å货车çå·">{{ currentDelivery.shippingInfo.shippingCarNumber || '--' }}</el-descriptions-item> |
| | | <el-descriptions-item label="å¿«éå
¬å¸">{{ currentDelivery.shippingInfo.expressCompany || '--' }}</el-descriptions-item> |
| | | <el-descriptions-item label="å¿«éåå·" |
| | | :span="2">{{ currentDelivery.shippingInfo.expressNumber || '--' }}</el-descriptions-item> |
| | | </el-descriptions> |
| | | <div style="margin-top: 20px;"> |
| | | <h4>产åæç»</h4> |
| | | <el-table :data="deliveryProductList" |
| | | border |
| | | size="small" |
| | | style="width: 100%"> |
| | | <el-table-column prop="batchNo" |
| | | label="æ¹å·" |
| | | show-overflow-tooltip /> |
| | | <el-table-column prop="productName" |
| | | label="产ååç§°" |
| | | show-overflow-tooltip /> |
| | | <el-table-column prop="specificationModel" |
| | | label="è§æ ¼åå·" |
| | | show-overflow-tooltip /> |
| | | <el-table-column prop="deliveryQuantity" |
| | | label="åè´§æ°é" |
| | | align="center" /> |
| | | </el-table> |
| | | </div> |
| | | <div v-if="currentDelivery.shippingInfo.storageBlobVOs && currentDelivery.shippingInfo.storageBlobVOs.length" |
| | | style="margin-top: 20px;"> |
| | | <h4>åè´§å¾ç</h4> |
| | | <ImagePreview :file-list="currentDelivery.shippingInfo.storageBlobVOs" /> |
| | | </div> |
| | | </template> |
| | | </template> |
| | | </el-skeleton> |
| | | </div> |
| | | <el-form :model="{ activities }" |
| | | ref="formRef" |
| | | label-position="top"> |
| | | <el-steps :active="getActiveStep()" |
| | | finish-status="success" |
| | | process-status="process" |
| | | align-center |
| | | direction="vertical"> |
| | | <el-step v-for="(activity, index) in activities" |
| | | :key="index" |
| | | finish-status="success" |
| | | :title="getNodeTitle(index, activities.length)" |
| | | :description="activity.approveNodeUser" |
| | | :icon="getNodeIcon(activity, index)"> |
| | | <template #icon> |
| | | <el-icon v-if="activity.approveNodeStatus === 2" |
| | | color="red" |
| | | :size="22"> |
| | | <WarningFilled /> |
| | | </el-icon> |
| | | <el-icon v-else-if="activity.isShen" |
| | | color="#1890ff" |
| | | :size="22"> |
| | | <Edit /> |
| | | </el-icon> |
| | | <el-icon v-else-if="activity.approveNodeStatus === 1" |
| | | color="#67C23A" |
| | | :size="26"> |
| | | <Check /> |
| | | </el-icon> |
| | | <el-icon v-else |
| | | color="#C0C4CC" |
| | | :size="22"> |
| | | <MoreFilled /> |
| | | </el-icon> |
| | | </template> |
| | | <template #title> |
| | | <span style="color: #000000">{{ getNodeTitle(index, activities.length) }}</span> |
| | | </template> |
| | | <template #description> |
| | | <div class="node-user"> |
| | | <div class="avatar-wrapper"> |
| | | <img :src="userStore.avatar" class="user-avatar" alt=""/> |
| | | <img :src="userStore.avatar" |
| | | class="user-avatar" |
| | | alt="" /> |
| | | </div> |
| | | <span style="color: #000000">{{ activity.approveNodeUser }}-{{activity.isApproval}}</span> |
| | | </div> |
| | | <div v-if="!activity.isShen" class="node-reason"> |
| | | <div v-if="!activity.isShen" |
| | | class="node-reason"> |
| | | <span>å®¡æ¹æè§ï¼</span>{{ activity.approveNodeReason }} |
| | | </div> |
| | | <div v-else-if="activity.isShen"> |
| | | <el-form-item |
| | | :prop="'activities.' + index + '.approveNodeReason'" |
| | | :rules="[{ required: true, message: 'å®¡æ¹æè§ä¸è½ä¸ºç©º', trigger: 'blur' }]" |
| | | > |
| | | <el-input v-model="activity.approveNodeReason" clearable type="textarea" :disabled="operationType === 'view'"></el-input> |
| | | <el-form-item :prop="'activities.' + index + '.approveNodeReason'" |
| | | :rules="[{ required: true, message: 'å®¡æ¹æè§ä¸è½ä¸ºç©º', trigger: 'blur' }]"> |
| | | <el-input v-model="activity.approveNodeReason" |
| | | clearable |
| | | type="textarea" |
| | | :disabled="operationType === 'view'"></el-input> |
| | | </el-form-item> |
| | | </div> |
| | | </template> |
| | | </el-step> |
| | | </el-steps> |
| | | </el-form> |
| | | <template #footer v-if="operationType === 'approval'"> |
| | | <template #footer |
| | | v-if="operationType === 'approval'"> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitForm(2)">ä¸éè¿</el-button> |
| | | <el-button type="primary" @click="submitForm(1)">éè¿</el-button> |
| | | <el-button type="primary" |
| | | @click="submitForm(2)">ä¸éè¿</el-button> |
| | | <el-button type="primary" |
| | | @click="submitForm(1)">éè¿</el-button> |
| | | <el-button @click="closeDia">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, getCurrentInstance, nextTick, reactive, ref, toRefs } from "vue"; |
| | | import { |
| | | approveProcessDetails, |
| | | getDept, |
| | | updateApproveNode |
| | | } from "@/api/collaborativeApproval/approvalProcess.js"; |
| | | import useUserStore from "@/store/modules/user.js"; |
| | | import { WarningFilled, Edit, Check, MoreFilled } from '@element-plus/icons-vue' |
| | | import { getQuotationList } from "@/api/salesManagement/salesQuotation.js"; |
| | | import { getPurchaseByCode } from "@/api/procurementManagement/procurementLedger.js"; |
| | | const emit = defineEmits(['close']) |
| | | const { proxy } = getCurrentInstance() |
| | | import { |
| | | computed, |
| | | getCurrentInstance, |
| | | nextTick, |
| | | reactive, |
| | | ref, |
| | | toRefs, |
| | | } from "vue"; |
| | | import { |
| | | approveProcessDetails, |
| | | getDept, |
| | | updateApproveNode, |
| | | } from "@/api/collaborativeApproval/approvalProcess.js"; |
| | | import useUserStore from "@/store/modules/user.js"; |
| | | import { |
| | | WarningFilled, |
| | | Edit, |
| | | Check, |
| | | MoreFilled, |
| | | } from "@element-plus/icons-vue"; |
| | | import { getQuotationList } from "@/api/salesManagement/salesQuotation.js"; |
| | | import { getPurchaseByCode } from "@/api/procurementManagement/procurementLedger.js"; |
| | | import { getDeliveryDetailByShippingNo } from "@/api/salesManagement/deliveryLedger.js"; |
| | | import ImagePreview from "@/components/AttachmentPreview/image/index.vue"; |
| | | const emit = defineEmits(["close"]); |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | const props = defineProps({ |
| | | approveType: { |
| | | type: [Number, String], |
| | | default: 0 |
| | | } |
| | | }) |
| | | |
| | | const dialogFormVisible = ref(false); |
| | | const operationType = ref('') |
| | | const activities = ref([]) |
| | | const formRef = ref(null); |
| | | const userStore = useUserStore() |
| | | const productOptions = ref([]); |
| | | const quotationLoading = ref(false) |
| | | const currentQuotation = ref({}) |
| | | const purchaseLoading = ref(false) |
| | | const currentPurchase = ref({}) |
| | | const isQuotationApproval = computed(() => Number(props.approveType) === 6) |
| | | const isPurchaseApproval = computed(() => Number(props.approveType) === 5) |
| | | |
| | | const data = reactive({ |
| | | form: { |
| | | approveId: "", |
| | | approveDeptId: "", |
| | | approveReason: "", |
| | | checkResult: "", |
| | | }, |
| | | }); |
| | | const { form } = toRefs(data); |
| | | |
| | | // èç¹æ é¢ |
| | | const getNodeTitle = (index, len) => { |
| | | if (index === len - 1) return 'ç»æ'; |
| | | return '审æ¹'; |
| | | }; |
| | | |
| | | // è·åå½åæ¿æ´»æ¥éª¤ |
| | | const getActiveStep = () => { |
| | | // å¦æææ isShen é½ä¸º falseï¼è¿åæåä¸ä¸ªæ¥éª¤ï¼å
¨é¨å®æï¼ |
| | | const hasActive = activities.value.some(a => a.isShen === true); |
| | | if (!hasActive) return activities.value.length; |
| | | // å½åèç¹ç´¢å¼ |
| | | return activities.value.findIndex(a => a.isShen == true); |
| | | }; |
| | | // æ¥éª¤icon |
| | | const getNodeIcon = (activity, index) => { |
| | | if (activity.approveNodeStatus === 2) return 'el-icon-warning'; // ä¸éè¿ |
| | | if (activity.isShen) return 'Edit'; |
| | | return ''; |
| | | }; |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const openDialog = (type, row) => { |
| | | operationType.value = type; |
| | | dialogFormVisible.value = true; |
| | | currentQuotation.value = {} |
| | | currentPurchase.value = {} |
| | | form.value = {...row} |
| | | // ç«å³æ¸
é¤è¡¨åéªè¯ç¶æï¼å ä¸ºåæ®µæ¯disabledçï¼ä¸éè¦éªè¯ï¼ |
| | | nextTick(() => { |
| | | if (formRef.value) { |
| | | formRef.value.clearValidate(); |
| | | } |
| | | }); |
| | | // ç¡®ä¿é项å è½½å®æååå¹é
å¼ç±»å |
| | | getProductOptions().then(() => { |
| | | // ç¡®ä¿å¼ç±»åå¹é
ï¼å¦æé项已å è½½ï¼ |
| | | if (productOptions.value.length > 0 && form.value.approveDeptId) { |
| | | const matchedOption = productOptions.value.find(opt => |
| | | opt.deptId == form.value.approveDeptId || |
| | | String(opt.deptId) === String(form.value.approveDeptId) |
| | | ); |
| | | if (matchedOption) { |
| | | form.value.approveDeptId = matchedOption.deptId; |
| | | } |
| | | } |
| | | // 忬¡æ¸
é¤éªè¯ï¼ç¡®ä¿é项å è½½åå¼å¹é
æ£ç¡® |
| | | nextTick(() => { |
| | | if (formRef.value) { |
| | | formRef.value.clearValidate(); |
| | | } |
| | | }); |
| | | }); |
| | | |
| | | // æ¥ä»·å®¡æ¹ï¼ç¨å®¡æ¹äºç±å段æ¿è½½ç"æ¥ä»·åå·"廿¥æ¥ä»·å表 |
| | | if (isQuotationApproval.value) { |
| | | const quotationNo = row?.approveReason; |
| | | if (quotationNo) { |
| | | quotationLoading.value = true |
| | | getQuotationList({ quotationNo }).then((res) => { |
| | | const records = res?.data?.records || [] |
| | | currentQuotation.value = records[0] || {} |
| | | }).finally(() => { |
| | | quotationLoading.value = false |
| | | }) |
| | | } |
| | | } |
| | | |
| | | // éè´å®¡æ¹ï¼ç¨å®¡æ¹äºç±å段æ¿è½½ç"éè´ååå·"廿¥éè´è¯¦æ
|
| | | if (isPurchaseApproval.value) { |
| | | const purchaseContractNumber = row?.approveReason; |
| | | if (purchaseContractNumber) { |
| | | purchaseLoading.value = true |
| | | getPurchaseByCode({ purchaseContractNumber }).then((res) => { |
| | | currentPurchase.value = res |
| | | }).catch((err) => { |
| | | console.error('æ¥è¯¢éè´è¯¦æ
失败:', err) |
| | | proxy.$modal.msgError('æ¥è¯¢éè´è¯¦æ
失败') |
| | | }).finally(() => { |
| | | purchaseLoading.value = false |
| | | }) |
| | | } |
| | | } |
| | | |
| | | approveProcessDetails(row.approveId).then((res) => { |
| | | activities.value = res.data |
| | | // å¢å isApprovalåæ®µ |
| | | activities.value.forEach(item => { |
| | | if (item.url && item.url.includes('word')) { |
| | | item.urlTem = item.url.replaceAll('word', 'img') |
| | | } else { |
| | | item.urlTem = item.url |
| | | } |
| | | if (item.approveNodeStatus === 2) { |
| | | item.isApproval = '已驳å'; |
| | | } else if (item.approveNodeStatus === 1) { |
| | | item.isApproval = 'å·²åæ'; |
| | | } else { |
| | | item.isApproval = 'æªå®¡æ¹'; |
| | | } |
| | | }) |
| | | }) |
| | | } |
| | | const getProductOptions = () => { |
| | | return getDept().then((res) => { |
| | | productOptions.value = res.data; |
| | | }); |
| | | }; |
| | | // æäº¤å®¡æ¹ |
| | | const submitForm = (status) => { |
| | | const filteredActivities = activities.value.filter(activity => activity.isShen); |
| | | if (!filteredActivities || filteredActivities.length === 0) { |
| | | proxy.$modal.msgError("æªæ¾å°å¾
审æ¹çèç¹"); |
| | | return; |
| | | } |
| | | const currentActivity = filteredActivities[0]; |
| | | if (!currentActivity) { |
| | | proxy.$modal.msgError("æªæ¾å°å¾
审æ¹çèç¹"); |
| | | return; |
| | | } |
| | | currentActivity.approveNodeStatus = status; |
| | | // 夿æ¯å¦ä¸ºæå䏿¥ |
| | | const isLast = activities.value.findIndex(a => a.isShen) === activities.value.length-1; |
| | | updateApproveNode({ ...currentActivity, isLast }).then(() => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | const props = defineProps({ |
| | | approveType: { |
| | | type: [Number, String], |
| | | default: 0, |
| | | }, |
| | | }); |
| | | }; |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | quotationLoading.value = false |
| | | currentQuotation.value = {} |
| | | purchaseLoading.value = false |
| | | currentPurchase.value = {} |
| | | emit('close') |
| | | }; |
| | | defineExpose({ |
| | | openDialog, |
| | | }); |
| | | |
| | | const dialogFormVisible = ref(false); |
| | | const operationType = ref(""); |
| | | const activities = ref([]); |
| | | const formRef = ref(null); |
| | | const userStore = useUserStore(); |
| | | const productOptions = ref([]); |
| | | const quotationLoading = ref(false); |
| | | const currentQuotation = ref({}); |
| | | const purchaseLoading = ref(false); |
| | | const currentPurchase = ref({}); |
| | | const deliveryLoading = ref(false); |
| | | const currentDelivery = ref({}); |
| | | const deliveryProductList = ref([]); |
| | | const isQuotationApproval = computed(() => Number(props.approveType) === 6); |
| | | const isPurchaseApproval = computed(() => Number(props.approveType) === 5); |
| | | const isDeliveryApproval = computed(() => Number(props.approveType) === 7); |
| | | |
| | | const data = reactive({ |
| | | form: { |
| | | approveId: "", |
| | | approveDeptId: "", |
| | | approveReason: "", |
| | | checkResult: "", |
| | | }, |
| | | }); |
| | | const { form } = toRefs(data); |
| | | |
| | | // èç¹æ é¢ |
| | | const getNodeTitle = (index, len) => { |
| | | if (index === len - 1) return "ç»æ"; |
| | | return "审æ¹"; |
| | | }; |
| | | |
| | | // è·åå½åæ¿æ´»æ¥éª¤ |
| | | const getActiveStep = () => { |
| | | // å¦æææ isShen é½ä¸º falseï¼è¿åæåä¸ä¸ªæ¥éª¤ï¼å
¨é¨å®æï¼ |
| | | const hasActive = activities.value.some(a => a.isShen === true); |
| | | if (!hasActive) return activities.value.length; |
| | | // å½åèç¹ç´¢å¼ |
| | | return activities.value.findIndex(a => a.isShen == true); |
| | | }; |
| | | // æ¥éª¤icon |
| | | const getNodeIcon = (activity, index) => { |
| | | if (activity.approveNodeStatus === 2) return "el-icon-warning"; // ä¸éè¿ |
| | | if (activity.isShen) return "Edit"; |
| | | return ""; |
| | | }; |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const openDialog = (type, row) => { |
| | | operationType.value = type; |
| | | dialogFormVisible.value = true; |
| | | currentQuotation.value = {}; |
| | | currentPurchase.value = {}; |
| | | form.value = { ...row }; |
| | | // ç«å³æ¸
é¤è¡¨åéªè¯ç¶æï¼å ä¸ºåæ®µæ¯disabledçï¼ä¸éè¦éªè¯ï¼ |
| | | nextTick(() => { |
| | | if (formRef.value) { |
| | | formRef.value.clearValidate(); |
| | | } |
| | | }); |
| | | // ç¡®ä¿é项å è½½å®æååå¹é
å¼ç±»å |
| | | getProductOptions().then(() => { |
| | | // ç¡®ä¿å¼ç±»åå¹é
ï¼å¦æé项已å è½½ï¼ |
| | | if (productOptions.value.length > 0 && form.value.approveDeptId) { |
| | | const matchedOption = productOptions.value.find( |
| | | opt => |
| | | opt.deptId == form.value.approveDeptId || |
| | | String(opt.deptId) === String(form.value.approveDeptId) |
| | | ); |
| | | if (matchedOption) { |
| | | form.value.approveDeptId = matchedOption.deptId; |
| | | } |
| | | } |
| | | // 忬¡æ¸
é¤éªè¯ï¼ç¡®ä¿é项å è½½åå¼å¹é
æ£ç¡® |
| | | nextTick(() => { |
| | | if (formRef.value) { |
| | | formRef.value.clearValidate(); |
| | | } |
| | | }); |
| | | }); |
| | | |
| | | // æ¥ä»·å®¡æ¹ï¼ç¨å®¡æ¹äºç±å段æ¿è½½ç"æ¥ä»·åå·"廿¥æ¥ä»·å表 |
| | | if (isQuotationApproval.value) { |
| | | const quotationNo = row?.approveReason; |
| | | if (quotationNo) { |
| | | quotationLoading.value = true; |
| | | getQuotationList({ quotationNo }) |
| | | .then(res => { |
| | | const records = res?.data?.records || []; |
| | | currentQuotation.value = records[0] || {}; |
| | | }) |
| | | .finally(() => { |
| | | quotationLoading.value = false; |
| | | }); |
| | | } |
| | | } |
| | | |
| | | // éè´å®¡æ¹ï¼ç¨å®¡æ¹äºç±å段æ¿è½½ç"éè´ååå·"廿¥éè´è¯¦æ
|
| | | if (isPurchaseApproval.value) { |
| | | const purchaseContractNumber = row?.approveReason; |
| | | if (purchaseContractNumber) { |
| | | purchaseLoading.value = true; |
| | | getPurchaseByCode({ purchaseContractNumber }) |
| | | .then(res => { |
| | | currentPurchase.value = res; |
| | | }) |
| | | .catch(err => { |
| | | console.error("æ¥è¯¢éè´è¯¦æ
失败:", err); |
| | | proxy.$modal.msgError("æ¥è¯¢éè´è¯¦æ
失败"); |
| | | }) |
| | | .finally(() => { |
| | | purchaseLoading.value = false; |
| | | }); |
| | | } |
| | | } |
| | | // å货审æ¹ï¼ç¨å®¡æ¹äºç±å段æ¿è½½ç"åè´§åå·"廿¥å货详æ
|
| | | if (isDeliveryApproval.value) { |
| | | const deliveryNo = row?.approveReason; |
| | | if (deliveryNo) { |
| | | deliveryLoading.value = true; |
| | | currentDelivery.value = {}; |
| | | deliveryProductList.value = []; |
| | | getDeliveryDetailByShippingNo({ shippingNo: deliveryNo }) |
| | | .then(res => { |
| | | const detailData = res?.data || res || {}; |
| | | currentDelivery.value = detailData; |
| | | deliveryProductList.value = |
| | | detailData.shippingProductDetailDtoList || []; |
| | | }) |
| | | .catch(err => { |
| | | console.error("æ¥è¯¢å货详æ
失败:", err); |
| | | proxy.$modal.msgError("æ¥è¯¢å货详æ
失败"); |
| | | }) |
| | | .finally(() => { |
| | | deliveryLoading.value = false; |
| | | }); |
| | | } |
| | | } |
| | | |
| | | approveProcessDetails(row.approveId).then(res => { |
| | | activities.value = res.data; |
| | | // å¢å isApprovalåæ®µ |
| | | activities.value.forEach(item => { |
| | | if (item.url && item.url.includes("word")) { |
| | | item.urlTem = item.url.replaceAll("word", "img"); |
| | | } else { |
| | | item.urlTem = item.url; |
| | | } |
| | | if (item.approveNodeStatus === 2) { |
| | | item.isApproval = "已驳å"; |
| | | } else if (item.approveNodeStatus === 1) { |
| | | item.isApproval = "å·²åæ"; |
| | | } else { |
| | | item.isApproval = "æªå®¡æ¹"; |
| | | } |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | const getDeliveryProductInfoList = () => { |
| | | const row = currentDelivery.value; |
| | | if (!row) return []; |
| | | const normalizeBatchNoList = value => { |
| | | if (Array.isArray(value)) return value; |
| | | if (typeof value === "string" && value.includes(",")) { |
| | | return value |
| | | .split(",") |
| | | .map(item => item.trim()) |
| | | .filter(Boolean); |
| | | } |
| | | return value ? [value] : []; |
| | | }; |
| | | const detailList = deliveryProductList.value.length |
| | | ? deliveryProductList.value |
| | | : [ |
| | | row.batchNoDetailList, |
| | | row.batchNoList, |
| | | row.shippingBatchList, |
| | | row.shippingInfoDetailList, |
| | | row.detailList, |
| | | row.batchDetailList, |
| | | ].find(value => Array.isArray(value) && value.length); |
| | | const batchNoList = normalizeBatchNoList(row.batchNo); |
| | | const toTableRow = (item = {}) => ({ |
| | | batchNo: |
| | | typeof item === "string" || typeof item === "number" |
| | | ? item |
| | | : item.batchNo ?? item.batchNumber ?? row.batchNo ?? "--", |
| | | productName: item.productName ?? row.productName ?? "--", |
| | | specificationModel: |
| | | item.specificationModel ?? item.model ?? row.specificationModel ?? "--", |
| | | deliveryQuantity: |
| | | item.deliveryQuantity ?? |
| | | item.quantity ?? |
| | | item.shippingQuantity ?? |
| | | row.deliveryQuantity ?? |
| | | row.quantity ?? |
| | | "--", |
| | | }); |
| | | if (detailList?.length) { |
| | | return detailList.map(toTableRow); |
| | | } |
| | | if (batchNoList.length) { |
| | | return batchNoList.map(batchNo => toTableRow({ batchNo })); |
| | | } |
| | | return [toTableRow()]; |
| | | }; |
| | | const getApprovalStatusText = status => { |
| | | const statusMap = { |
| | | 0: "å¾
å®¡æ ¸", |
| | | 1: "å®¡æ ¸éè¿", |
| | | 2: "å®¡æ ¸æç»", |
| | | 3: "å®¡æ ¸ä¸", |
| | | }; |
| | | return statusMap[status] || "å¾
å®¡æ ¸"; |
| | | }; |
| | | |
| | | const getProductOptions = () => { |
| | | return getDept().then(res => { |
| | | productOptions.value = res.data; |
| | | }); |
| | | }; |
| | | // æäº¤å®¡æ¹ |
| | | const submitForm = status => { |
| | | const filteredActivities = activities.value.filter( |
| | | activity => activity.isShen |
| | | ); |
| | | if (!filteredActivities || filteredActivities.length === 0) { |
| | | proxy.$modal.msgError("æªæ¾å°å¾
审æ¹çèç¹"); |
| | | return; |
| | | } |
| | | const currentActivity = filteredActivities[0]; |
| | | if (!currentActivity) { |
| | | proxy.$modal.msgError("æªæ¾å°å¾
审æ¹çèç¹"); |
| | | return; |
| | | } |
| | | currentActivity.approveNodeStatus = status; |
| | | // 夿æ¯å¦ä¸ºæå䏿¥ |
| | | const isLast = |
| | | activities.value.findIndex(a => a.isShen) === activities.value.length - 1; |
| | | updateApproveNode({ ...currentActivity, isLast }).then(() => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | }); |
| | | }; |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | quotationLoading.value = false; |
| | | currentQuotation.value = {}; |
| | | purchaseLoading.value = false; |
| | | currentPurchase.value = {}; |
| | | emit("close"); |
| | | }; |
| | | defineExpose({ |
| | | openDialog, |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | |
| | | .node-user { |
| | | margin: 10px 0; |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | .node-status { |
| | | color: #1890ff; |
| | | margin-left: 8px; |
| | | font-size: 14px; |
| | | } |
| | | .node-reason { |
| | | font-size: 15px; |
| | | color: #333; |
| | | margin: 10px 0; |
| | | } |
| | | .user-avatar { |
| | | cursor: pointer; |
| | | width: 30px; |
| | | height: 30px; |
| | | border-radius: 50px; |
| | | } |
| | | .signImg { |
| | | cursor: pointer; |
| | | width: 200px; |
| | | height: 60px; |
| | | } |
| | | .node-user { |
| | | margin: 10px 0; |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | .node-status { |
| | | color: #1890ff; |
| | | margin-left: 8px; |
| | | font-size: 14px; |
| | | } |
| | | .node-reason { |
| | | font-size: 15px; |
| | | color: #333; |
| | | margin: 10px 0; |
| | | } |
| | | .user-avatar { |
| | | cursor: pointer; |
| | | width: 30px; |
| | | height: 30px; |
| | | border-radius: 50px; |
| | | } |
| | | .signImg { |
| | | cursor: pointer; |
| | | width: 200px; |
| | | height: 60px; |
| | | } |
| | | </style> |
| | |
| | | startDate: "", // 请åå¼å§æ¶é´ |
| | | endDate: "", // 请åç»ææ¶é´ |
| | | price: null, // æ¥ééé¢ |
| | | location: "" // åºå·®å°ç¹ |
| | | location: "", // åºå·®å°ç¹ |
| | | storageBlobDTOS: [] |
| | | }, |
| | | rules: { |
| | | approveId: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | |
| | | return |
| | | } |
| | | } |
| | | form.value.storageBlobDTOList = fileList.value |
| | | form.value.storageBlobDTOS = fileList.value |
| | | |
| | | proxy.$refs.formRef.validate(valid => { |
| | | if (valid) { |
| | |
| | | tableData.value = list |
| | | } |
| | | const downLoadFile = (row) => { |
| | | proxy.$download.name(row.url); |
| | | |
| | | proxy.$download.byUrl(row.url, row.originalFilename); |
| | | } |
| | | const lookFile = (row) => { |
| | | filePreviewRef.value.open(row.url) |
| | |
| | | <!-- å¼¹çªç»ä»¶ --> |
| | | <info-form-dia ref="infoFormDia" @close="handleQuery" :approveType="currentApproveType"></info-form-dia> |
| | | <approval-dia ref="approvalDia" @close="handleQuery" :approveType="currentApproveType"></approval-dia> |
| | | <FileList ref="fileListRef" /> |
| | | <FileList v-if="fileDialogVisible" |
| | | v-model:visible="fileDialogVisible" |
| | | record-type="approve_process" |
| | | :record-id="recordId" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import FileList from "./fileList.vue"; |
| | | import { Search, Plus, Delete, Download, RefreshRight, DocumentChecked } from "@element-plus/icons-vue"; |
| | | import {onMounted, ref, computed, reactive, toRefs, nextTick, getCurrentInstance} from "vue"; |
| | | import {onMounted, ref, computed, reactive, toRefs, nextTick, getCurrentInstance, defineAsyncComponent} from "vue"; |
| | | import {ElMessageBox} from "element-plus"; |
| | | import { useRoute } from 'vue-router'; |
| | | import InfoFormDia from "@/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue"; |
| | | import ApprovalDia from "@/views/collaborativeApproval/approvalProcess/components/approvalDia.vue"; |
| | | import {approveProcessDelete, approveProcessListPage} from "@/api/collaborativeApproval/approvalProcess.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue")); |
| | | |
| | | const userStore = useUserStore(); |
| | | const route = useRoute(); |
| | |
| | | name: "éä»¶", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | downLoadFile(row); |
| | | openFilesFormDia(row); |
| | | }, |
| | | }); |
| | | } |
| | |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const fileListRef = ref(null) |
| | | const downLoadFile = (row) => { |
| | | fileListRef.value.open(row.commonFileList) |
| | | |
| | | // æå¼éä»¶å¼¹çª |
| | | const recordId =ref(0) |
| | | const fileDialogVisible = ref(false) |
| | | |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFilesFormDia = async (row) => { |
| | | recordId.value = row.id |
| | | fileDialogVisible.value = true |
| | | } |
| | | |
| | | const pagination = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | |
| | | </el-form-item> |
| | | <el-form-item label="ç´§æ¥ç¨åº¦" prop="urgency"> |
| | | <el-radio-group v-model="sealForm.urgency"> |
| | | <el-radio label="normal">æ®é</el-radio> |
| | | <el-radio label="urgent">ç´§æ¥</el-radio> |
| | | <el-radio label="very-urgent">ç¹æ¥</el-radio> |
| | | <el-radio value="normal">æ®é</el-radio> |
| | | <el-radio value="urgent">ç´§æ¥</el-radio> |
| | | <el-radio value="very-urgent">ç¹æ¥</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="éä»¶ä¸ä¼ "> |
| | | <AttachmentUploadFile |
| | | v-model:fileList="sealForm.storageBlobDTOs" |
| | | :limit="10" |
| | | :fileSize="50" |
| | | buttonText="ç¹å»ä¸ä¼ éä»¶" |
| | | /> |
| | | </el-form-item> |
| | | </el-form> |
| | | </FormDialog> |
| | |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="ç³è¯·åå " :span="2">{{ currentSealDetail.reason }}</el-descriptions-item> |
| | | </el-descriptions> |
| | | <!-- éä»¶å表 --> |
| | | <div v-if="currentSealDetail.storageBlobVOList?.length || currentSealDetail.storageBlobDTOs?.length" class="attachment-section"> |
| | | <div class="attachment-title">éä»¶å表ï¼</div> |
| | | <el-table :data="currentSealDetail.storageBlobVOList || currentSealDetail.storageBlobDTOs" border class="attachment-table"> |
| | | <el-table-column label="éä»¶åç§°" show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | {{ scope.row.originalFilename || scope.row.name || scope.row.fileName || 'æªå½åæä»¶' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column fixed="right" label="æä½" width="150" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" @click="previewFile(scope.row)">é¢è§</el-button> |
| | | <el-button link type="primary" size="small" @click="downloadFile(scope.row)">ä¸è½½</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | </FormDialog> |
| | | <!-- æä»¶é¢è§ç»ä»¶ --> |
| | | <FilePreview ref="filePreviewRef" /> |
| | | |
| | | </div> |
| | | </template> |
| | |
| | | import useUserStore from '@/store/modules/user' |
| | | import FormDialog from '@/components/Dialog/FormDialog.vue' |
| | | import PIMTable from '@/components/PIMTable/PIMTable.vue' |
| | | import AttachmentUploadFile from '@/components/AttachmentUpload/file/index.vue' |
| | | import FilePreview from '@/components/filePreview/index.vue' |
| | | import download from '@/plugins/download.js' |
| | | |
| | | // ååºå¼æ°æ® |
| | | // ç¨å°ç³è¯·ç¸å
³ |
| | |
| | | const tableLoading = ref(false) |
| | | const showSealDetailDialog = ref(false) |
| | | const currentSealDetail = ref(null) |
| | | const filePreviewRef = ref(null) |
| | | const sealFormRef = ref() |
| | | const userList = ref([]) |
| | | const sealForm = reactive({ |
| | |
| | | reason: '', |
| | | approveUserId: '', |
| | | urgency: 'normal', |
| | | status: 'pending' |
| | | status: 'pending', |
| | | storageBlobDTOs: [] |
| | | }) |
| | | |
| | | const sealRules = { |
| | |
| | | reason: '', |
| | | approveUserId: '', |
| | | urgency: 'normal', |
| | | status: 'pending' |
| | | status: 'pending', |
| | | storageBlobDTOs: [] |
| | | }) |
| | | } |
| | | }).catch(err => { |
| | |
| | | reason: '', |
| | | approveUserId: '', |
| | | urgency: 'normal', |
| | | status: 'pending' |
| | | status: 'pending', |
| | | storageBlobDTOs: [] |
| | | }) |
| | | // æ¸
é¤è¡¨åéªè¯ç¶æ |
| | | if (sealFormRef.value) { |
| | |
| | | const viewSealDetail = (row) => { |
| | | currentSealDetail.value = row |
| | | showSealDetailDialog.value = true |
| | | } |
| | | |
| | | // é¢è§æä»¶ |
| | | const previewFile = (row) => { |
| | | const url = row.previewURL || row.previewUrl || row.url |
| | | if (url && filePreviewRef.value) { |
| | | filePreviewRef.value.open(url) |
| | | } else { |
| | | ElMessage.warning('æä»¶å°åæ æï¼æ æ³é¢è§') |
| | | } |
| | | } |
| | | |
| | | // ä¸è½½æä»¶ |
| | | const downloadFile = (row) => { |
| | | const url = row.downloadURL || row.downloadUrl || row.url |
| | | if (url) { |
| | | const filename = row.originalFilename || row.name || row.fileName || 'download' |
| | | download.byUrl(url, filename) |
| | | } else { |
| | | ElMessage.warning('æä»¶å°åæ æï¼æ æ³ä¸è½½') |
| | | } |
| | | } |
| | | // 审æ¹ç¨å°ç³è¯· |
| | | const approveSeal = (row) => { |
| | |
| | | .ml-10 { |
| | | margin-left: 10px; |
| | | } |
| | | |
| | | .attachment-section { |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | .attachment-title { |
| | | font-size: 14px; |
| | | color: #606266; |
| | | margin-bottom: 10px; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .attachment-table { |
| | | border-radius: 4px; |
| | | } |
| | | </style> |
| | |
| | | tableData.value = list |
| | | } |
| | | const downLoadFile = (row) => { |
| | | proxy.$download.name(row.url); |
| | | |
| | | proxy.$download.byUrl(row.url, row.originalFilename); |
| | | } |
| | | const lookFile = (row) => { |
| | | filePreviewRef.value.open(row.url) |
| | |
| | | v-model="form.productName" |
| | | placeholder="请è¾å
¥äº§ååç§°" |
| | | clearable |
| | | :disabled="operationType === 'view'" |
| | | :disabled="isFieldDisabled('productName')" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | v-model="form.batchNumber" |
| | | placeholder="请è¾å
¥äº§åæ¹å·" |
| | | clearable |
| | | :disabled="operationType === 'view'" |
| | | :disabled="isFieldDisabled('batchNumber')" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | type="date" |
| | | placeholder="è¯·éæ©ä¸´ææ¥æ" |
| | | clearable |
| | | :disabled="operationType === 'view'" |
| | | :disabled="isFieldDisabled('expiryDate')" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | :min="0" |
| | | placeholder="请è¾å
¥åºåæ°é" |
| | | style="width: 100%" |
| | | :disabled="operationType === 'view'" |
| | | :disabled="isFieldDisabled('stockQuantity')" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | v-model="form.customerName" |
| | | placeholder="请è¾å
¥å®¢æ·åç§°" |
| | | clearable |
| | | :disabled="operationType === 'view'" |
| | | :disabled="isFieldDisabled('customerName')" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | v-model="form.contactPhone" |
| | | placeholder="请è¾å
¥èç³»çµè¯" |
| | | clearable |
| | | :disabled="operationType === 'view'" |
| | | :disabled="isFieldDisabled('contactPhone')" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | v-model="form.problemDesc" |
| | | placeholder="请è¾å
¥é®é¢æè¿°" |
| | | clearable |
| | | :disabled="operationType === 'view'" |
| | | :disabled="isFieldDisabled('problemDesc')" |
| | | type="textarea" |
| | | :rows="3" |
| | | /> |
| | |
| | | v-model="form.handlerId" |
| | | placeholder="è¯·éæ©å¤ç人" |
| | | clearable |
| | | :disabled="operationType === 'view'" |
| | | :disabled="isFieldDisabled('handlerId')" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | |
| | | type="date" |
| | | placeholder="è¯·éæ©å¤çæ¥æ" |
| | | clearable |
| | | :disabled="operationType === 'view'" |
| | | :disabled="isFieldDisabled('handleDate')" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | v-model="form.handleResult" |
| | | placeholder="请è¾å
¥å¤çç»æ" |
| | | clearable |
| | | :disabled="operationType === 'view'" |
| | | :disabled="isFieldDisabled('handleResult')" |
| | | type="textarea" |
| | | :rows="3" |
| | | /> |
| | |
| | | return 'æ°å¢ä¸´æå®å'; |
| | | case 'edit': |
| | | return 'ç¼è¾ä¸´æå®å'; |
| | | case 'handle': |
| | | return 'å¤ç临æå®å'; |
| | | case 'view': |
| | | return 'æ¥ç临æå®å'; |
| | | default: |
| | |
| | | }) |
| | | const { form, rules } = toRefs(data); |
| | | const userList = ref([]) |
| | | const handleEditableFields = ["handlerId", "handleDate", "handleResult"]; |
| | | |
| | | const isFieldDisabled = (field) => { |
| | | if (operationType.value === "view") return true; |
| | | if (operationType.value === "handle") return !handleEditableFields.includes(field); |
| | | return false; |
| | | }; |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const openDialog = (type, row) => { |
| | |
| | | } else { |
| | | // ç¼è¾ææ¥çæ¶å¡«å
æ°æ® |
| | | form.value = { ...row }; |
| | | if (type === 'edit' && !form.value.handlerId) { |
| | | if (type === 'handle' && !form.value.handlerId) { |
| | | form.value.handlerId = userStore.id; |
| | | form.value.handleDate = getCurrentDate(); |
| | | } |
| | |
| | | } |
| | | |
| | | const submitForm = () => { |
| | | if (operationType.value === "handle") { |
| | | if (!form.value.handlerId || !form.value.handleDate || !form.value.handleResult) { |
| | | proxy.$modal.msgWarning("请填åå¤ç人ãå¤çæ¥æåå¤çç»æ"); |
| | | return; |
| | | } |
| | | handleSubmit(); |
| | | return; |
| | | } |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | | const submitData = { |
| | | id: form.value.id, |
| | | productName: form.value.productName, |
| | | batchNumber: form.value.batchNumber, |
| | | expireDate: form.value.expiryDate, |
| | | stockQuantity: form.value.stockQuantity, |
| | | customerName: form.value.customerName, |
| | | contactPhone: form.value.contactPhone, |
| | | disRes: form.value.problemDesc, |
| | | status: form.value.status, |
| | | disposeUserId: form.value.handlerId, |
| | | disposeNickName: userList.value.find(item => item.userId === form.value.handlerId)?.nickName, |
| | | disposeResult: form.value.handleResult, |
| | | disDate: form.value.handleDate |
| | | }; |
| | | |
| | | const apiCall = operationType.value === 'add' ? expiryAfterSalesAdd : expiryAfterSalesUpdate; |
| | | apiCall(submitData).then(() => { |
| | | proxy.$modal.msgSuccess(operationType.value === 'add' ? "æ°å¢æå" : "æ´æ°æå"); |
| | | closeDia(); |
| | | }).catch(error => { |
| | | console.error('æäº¤æ°æ®å¤±è´¥:', error); |
| | | proxy.$modal.msgError('æäº¤æ°æ®å¤±è´¥ï¼è¯·ç¨åéè¯'); |
| | | }); |
| | | handleSubmit(); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | const handleSubmit = () => { |
| | | const submitData = { |
| | | id: form.value.id, |
| | | productName: form.value.productName, |
| | | batchNumber: form.value.batchNumber, |
| | | expireDate: form.value.expiryDate, |
| | | stockQuantity: form.value.stockQuantity, |
| | | customerName: form.value.customerName, |
| | | contactPhone: form.value.contactPhone, |
| | | disRes: form.value.problemDesc, |
| | | status: operationType.value === "handle" ? 2 : form.value.status, |
| | | disposeUserId: form.value.handlerId, |
| | | disposeNickName: userList.value.find(item => item.userId === form.value.handlerId)?.nickName, |
| | | disposeResult: form.value.handleResult, |
| | | disDate: form.value.handleDate |
| | | }; |
| | | |
| | | const apiCall = operationType.value === 'add' ? expiryAfterSalesAdd : expiryAfterSalesUpdate; |
| | | apiCall(submitData).then(() => { |
| | | const successText = operationType.value === "add" ? "æ°å¢æå" : operationType.value === "handle" ? "å¤çæå" : "æ´æ°æå"; |
| | | proxy.$modal.msgSuccess(successText); |
| | | closeDia(); |
| | | }).catch(error => { |
| | | console.error('æäº¤æ°æ®å¤±è´¥:', error); |
| | | proxy.$modal.msgError('æäº¤æ°æ®å¤±è´¥ï¼è¯·ç¨åéè¯'); |
| | | }); |
| | | } |
| | | |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | |
| | | <el-button type="danger" @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | |
| | | |
| | | <div class="table_list"> |
| | | <PIMTable |
| | | rowKey="id" |
| | |
| | | |
| | | <template #operation="{ row }"> |
| | | <el-button type="primary" link @click="openForm('view', row)">æ¥ç</el-button> |
| | | <el-button type="primary" link @click="openForm('edit', row)" v-if="row.status === 1">ç¼è¾</el-button> |
| | | <el-button type="primary" link @click="openForm('handle', row)" v-if="row.status === 1">å¤ç</el-button> |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | |
| | | current: page.value.current, |
| | | size: page.value.size |
| | | }; |
| | | |
| | | |
| | | expiryAfterSalesListPage(queryParams).then(res => { |
| | | // æ å°å端è¿åæ°æ®å°åç«¯è¡¨æ ¼ |
| | | tableData.value = res.data.records.map(item => ({ |
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog |
| | | v-model="dialogFormVisible" |
| | | title="æ°å¢å®åå" |
| | | width="90%" |
| | | @close="closeDia" |
| | | > |
| | | <el-dialog v-model="dialogFormVisible" |
| | | title="æ°å¢å®åå" |
| | | width="90%" |
| | | @close="closeDia"> |
| | | <div> |
| | | <span class="descriptions">åºç¡èµæ</span> |
| | | <el-form |
| | | :model="form" |
| | | label-width="140px" |
| | | label-position="top" |
| | | :rules="rules" |
| | | ref="formRef" |
| | | > |
| | | <el-form :model="form" |
| | | label-width="140px" |
| | | label-position="top" |
| | | :rules="rules" |
| | | ref="formRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="4"> |
| | | <el-form-item label="客æ·åç§°ï¼" prop="customerName"> |
| | | <el-select |
| | | v-model="form.customerName" |
| | | filterable |
| | | @change="customerNameChange" |
| | | > |
| | | <el-option |
| | | v-for="item in customerNameOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | <el-form-item label="客æ·åç§°ï¼" |
| | | prop="customerName"> |
| | | <el-select v-model="form.customerName" |
| | | filterable |
| | | @change="customerNameChange"> |
| | | <el-option v-for="item in customerNameOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="å®åç±»åï¼" prop="serviceType"> |
| | | <el-select |
| | | v-model="form.serviceType" |
| | | filterable |
| | | > |
| | | <el-option |
| | | v-for="dict in serviceTypeOptions" |
| | | :key="dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" |
| | | /> |
| | | <el-form-item label="å®åç±»åï¼" |
| | | prop="serviceType"> |
| | | <el-select v-model="form.serviceType" |
| | | filterable> |
| | | <el-option v-for="dict in serviceTypeOptions" |
| | | :key="dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="å
³èéå®åå·ï¼" prop="salesContractNo"> |
| | | <el-select |
| | | v-model="form.salesContractNo" |
| | | @change="associatedSalesOrderNumberChange" |
| | | filterable |
| | | > |
| | | <el-option |
| | | v-for="item in associatedSalesOrderNumberOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | <el-form-item label="å
³èéå®åå·ï¼" |
| | | prop="salesContractNo"> |
| | | <el-select v-model="form.salesContractNo" |
| | | @change="associatedSalesOrderNumberChange" |
| | | filterable> |
| | | <el-option v-for="item in associatedSalesOrderNumberOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="ç´§æ¥ç¨åº¦ï¼" prop="urgency"> |
| | | <el-select |
| | | v-model="form.urgency" |
| | | filterable |
| | | > |
| | | <el-option |
| | | v-for="dict in urgencyOptions" |
| | | :key="dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" |
| | | /> |
| | | <el-form-item label="ç´§æ¥ç¨åº¦ï¼" |
| | | prop="urgency"> |
| | | <el-select v-model="form.urgency" |
| | | filterable> |
| | | <el-option v-for="dict in urgencyOptions" |
| | | :key="dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="é®é¢æè¿°ï¼" prop="proDesc"> |
| | | <el-input |
| | | v-model="form.proDesc" |
| | | placeholder="请è¾å
¥é®é¢æè¿°" |
| | | /> |
| | | <el-form-item label="é®é¢æè¿°ï¼" |
| | | prop="proDesc"> |
| | | <el-input v-model="form.proDesc" |
| | | placeholder="请è¾å
¥é®é¢æè¿°" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <hr> |
| | | <div style="padding-top: 20px"> |
| | | <div style="display: flex; justify-content: space-between"> |
| | | <span class="descriptions">å
³è产å</span> |
| | | <el-button |
| | | type="primary" |
| | | style="margin-right: 12px; margin-bottom: 10px" |
| | | @click="isShowProductSelectDialog = true" |
| | | > |
| | | <div style="padding-top: 20px"> |
| | | <div style="display: flex; justify-content: space-between"> |
| | | <span class="descriptions">å
³è产å</span> |
| | | <el-button type="primary" |
| | | style="margin-right: 12px; margin-bottom: 10px" |
| | | @click="isShowProductSelectDialog = true"> |
| | | éæ©äº§å |
| | | </el-button> |
| | | </div> |
| | | <PIMTable |
| | | :isShowPagination="false" |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | > |
| | | <template #approveStatus="{ row }"> |
| | | <el-tag :type="getApproveStatusType(row)" size="small"> |
| | | {{ getApproveStatusText(row) }} |
| | | </el-tag> |
| | | </template> |
| | | <template #shippingStatus="{ row }"> |
| | | <el-tag :type="getShippingStatusType(row)" size="small"> |
| | | {{ getShippingStatusText(row) }} |
| | | </el-tag> |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | | <PIMTable :isShowPagination="false" |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData"> |
| | | <template #approveStatus="{ row }"> |
| | | <el-tag :type="getApproveStatusType(row)" |
| | | size="small"> |
| | | {{ getApproveStatusText(row) }} |
| | | </el-tag> |
| | | </template> |
| | | <template #shippingStatus="{ row }"> |
| | | <el-tag :type="getShippingStatusType(row)" |
| | | size="small"> |
| | | {{ getShippingStatusText(row) }} |
| | | </el-tag> |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | | </div> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitForm">确认</el-button> |
| | | <el-button @click="closeDia">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" |
| | | @click="submitForm">确认</el-button> |
| | | <el-button @click="closeDia">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- éæ©äº§åå¼¹çª --> |
| | | <ProductSelectDialog |
| | | v-model="isShowProductSelectDialog" |
| | | :products="currentSalesOrderProducts" |
| | | :selected-ids="currentSelectedProductIds" |
| | | @confirm="handleSelectProducts" |
| | | /> |
| | | <ProductSelectDialog v-model="isShowProductSelectDialog" |
| | | :products="currentSalesOrderProducts" |
| | | :selected-ids="currentSelectedProductIds" |
| | | @confirm="handleSelectProducts" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, toRefs, getCurrentInstance, computed } from "vue"; |
| | | import ProductSelectDialog from "./ProductSelectDialog.vue"; |
| | | import useUserStore from "@/store/modules/user.js"; |
| | | import {userListNoPageByTenantId} from "@/api/system/user.js"; |
| | | import {afterSalesServiceAdd, afterSalesServiceUpdate, getAllCustomerList, getSalesLedger } from "@/api/customerService/index.js"; |
| | | import { getCurrentDate } from "@/utils/index.js"; |
| | | const { proxy } = getCurrentInstance() |
| | | const emit = defineEmits(['close']) |
| | | const dialogFormVisible = ref(false); |
| | | const operationType = ref('') |
| | | const formRef = ref(null) |
| | | const customerNameOptions = ref([]) |
| | | const userStore = useUserStore(); |
| | | import { ref, reactive, toRefs, getCurrentInstance, computed } from "vue"; |
| | | import ProductSelectDialog from "./ProductSelectDialog.vue"; |
| | | import useUserStore from "@/store/modules/user.js"; |
| | | import { userListNoPageByTenantId } from "@/api/system/user.js"; |
| | | import { |
| | | afterSalesServiceAdd, |
| | | afterSalesServiceUpdate, |
| | | getAllCustomerList, |
| | | getSalesLedger, |
| | | } from "@/api/customerService/index.js"; |
| | | import { getCurrentDate } from "@/utils/index.js"; |
| | | const { proxy } = getCurrentInstance(); |
| | | const emit = defineEmits(["close"]); |
| | | const dialogFormVisible = ref(false); |
| | | const operationType = ref(""); |
| | | const formRef = ref(null); |
| | | const customerNameOptions = ref([]); |
| | | const userStore = useUserStore(); |
| | | |
| | | const data = reactive({ |
| | | form: { |
| | | topic: "", |
| | | serviceType: "", |
| | | urgency: "", |
| | | salesLedgerId: null, |
| | | productModelIds: "", |
| | | customerId: null, |
| | | salesContractNo: "", |
| | | proDesc: "", |
| | | customerName: "" |
| | | }, |
| | | rules: { |
| | | customerName: [{required: true, message: "è¯·éæ©å®¢æ·åç§°", trigger: "change"}], |
| | | serviceType: [{required: true, message: "è¯·éæ©å®åç±»å", trigger: "change"}], |
| | | urgency: [{required: true, message: "è¯·éæ©ç´§æ¥ç¨åº¦", trigger: "change"}], |
| | | feedbackDate: [{required: true, message: "è¯·éæ©", trigger: "change"}], |
| | | } |
| | | }) |
| | | |
| | | // èªå®ä¹æ ¡éªå½æ°ï¼å¤ææ¯å¦éè¦æ ¡éªå®åç¼å· |
| | | |
| | | const { form, rules } = toRefs(data); |
| | | const userList = ref([]) |
| | | |
| | | const formatCurrency = (val) => { |
| | | if (val === null || val === undefined || val === '') return '-' |
| | | const num = Number(val) |
| | | return Number.isFinite(num) ? num.toFixed(2) : '-' |
| | | } |
| | | |
| | | const { post_sale_waiting_list, degree_of_urgency } = proxy.useDict( |
| | | "post_sale_waiting_list", |
| | | "degree_of_urgency" |
| | | ); |
| | | |
| | | const serviceTypeOptions = computed(() => post_sale_waiting_list?.value || []); |
| | | const urgencyOptions = computed(() => degree_of_urgency?.value || []); |
| | | |
| | | const getProductRowId = (row) => { |
| | | return row?.id ?? row?.productModelId ?? row?.modelId ?? `${row?.productCategory || row?.productName || ""}-${row?.specificationModel || row?.model || ""}-${row?.unit || ""}` |
| | | } |
| | | |
| | | const normalizeProductRow = (row) => { |
| | | return { |
| | | ...row, |
| | | id: getProductRowId(row), |
| | | productCategory: row?.productCategory ?? row?.productName ?? '', |
| | | specificationModel: row?.specificationModel ?? row?.model ?? '', |
| | | unit: row?.unit ?? '', |
| | | approveStatus: row?.approveStatus ?? null, |
| | | shippingStatus: row?.shippingStatus ?? '', |
| | | expressCompany: row?.expressCompany ?? '', |
| | | expressNumber: row?.expressNumber ?? '', |
| | | shippingCarNumber: row?.shippingCarNumber ?? '', |
| | | shippingDate: row?.shippingDate ?? '', |
| | | quantity: row?.quantity ?? 0, |
| | | taxRate: row?.taxRate ?? 0, |
| | | taxInclusiveUnitPrice: row?.taxInclusiveUnitPrice ?? 0, |
| | | taxInclusiveTotalPrice: row?.taxInclusiveTotalPrice ?? 0, |
| | | taxExclusiveTotalPrice: row?.taxExclusiveTotalPrice ?? 0, |
| | | noQuantity: row?.noQuantity ?? 0, |
| | | } |
| | | } |
| | | |
| | | const tableColumn = ref([ |
| | | { label: "产å大类", prop: "productCategory" }, |
| | | { label: "è§æ ¼åå·", prop: "specificationModel" }, |
| | | { label: "åä½", prop: "unit" }, |
| | | { |
| | | label: "产åç¶æ", |
| | | prop: "approveStatus", |
| | | width: 100, |
| | | align: "center", |
| | | dataType: "slot", |
| | | slot: "approveStatus", |
| | | }, |
| | | { |
| | | label: "åè´§ç¶æ", |
| | | align: "center", |
| | | width: 140, |
| | | dataType: "slot", |
| | | slot: "shippingStatus", |
| | | }, |
| | | { label: "å¿«éå
¬å¸", prop: "expressCompany", width: 140 }, |
| | | { label: "å¿«éåå·", prop: "expressNumber", width: 160 }, |
| | | { label: "å货车ç", prop: "shippingCarNumber", minWidth: 100, align: "center" }, |
| | | { label: "åè´§æ¥æ", prop: "shippingDate", minWidth: 100, align: "center" }, |
| | | { label: "æ°é", prop: "quantity", width: 100 }, |
| | | { label: "ç¨ç(%)", prop: "taxRate", width: 100 }, |
| | | { |
| | | label: "å«ç¨åä»·(å
)", |
| | | prop: "taxInclusiveUnitPrice", |
| | | width: 160, |
| | | formatData: formatCurrency, |
| | | }, |
| | | { |
| | | label: "å«ç¨æ»ä»·(å
)", |
| | | prop: "taxInclusiveTotalPrice", |
| | | width: 160, |
| | | formatData: formatCurrency, |
| | | }, |
| | | { |
| | | label: "ä¸å«ç¨æ»ä»·(å
)", |
| | | prop: "taxExclusiveTotalPrice", |
| | | width: 160, |
| | | formatData: formatCurrency, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: 'right', |
| | | operation: [ |
| | | { |
| | | name: "å é¤", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | tableData.value = tableData.value.filter(i => getProductRowId(i) !== getProductRowId(row)) |
| | | }, |
| | | |
| | | }, |
| | | ], |
| | | }, |
| | | ]) |
| | | const tableData = ref([]) |
| | | // éæ©äº§åå¼¹çª |
| | | const isShowProductSelectDialog = ref(false) |
| | | const handleSelectProducts = (rows) => { |
| | | if (!Array.isArray(rows)) return |
| | | const existingIds = new Set(tableData.value.map(i => String(getProductRowId(i)))) |
| | | const mapped = rows |
| | | .map(normalizeProductRow) |
| | | .filter(r => !existingIds.has(String(getProductRowId(r)))) |
| | | tableData.value = tableData.value.concat(mapped) |
| | | } |
| | | const currentSelectedProductIds = computed(() => { |
| | | return tableData.value.map(item => getProductRowId(item)).filter(item => item !== undefined && item !== null && item !== '') |
| | | }) |
| | | |
| | | const associatedSalesOrderNumberChange = () => { |
| | | const opt = associatedSalesOrderNumberOptions.value.find( |
| | | (item) => item.value === form.value.salesContractNo |
| | | ) |
| | | tableData.value = (opt?.productData || []).map(normalizeProductRow) |
| | | form.value.salesLedgerId = opt?.id || null |
| | | } |
| | | |
| | | const associatedSalesOrderNumberOptions = ref([]) |
| | | |
| | | const currentSalesOrderProducts = computed(() => { |
| | | const opt = associatedSalesOrderNumberOptions.value.find( |
| | | (item) => item.value === form.value.salesContractNo |
| | | ) |
| | | return (opt?.productData || []).map(normalizeProductRow) |
| | | }) |
| | | |
| | | const customerNameChange = (val) => { |
| | | form.value.salesContractNo = ""; |
| | | form.value.salesLedgerId = null; |
| | | tableData.value = []; |
| | | associatedSalesOrderNumberOptions.value = []; |
| | | const opt = customerNameOptions.value.find(item => item.value === val); |
| | | if (opt) { |
| | | form.value.customerId = opt.id; |
| | | } else { |
| | | form.value.customerId = null; |
| | | } |
| | | getSalesLedger({ |
| | | customerName: form.value.customerName |
| | | }).then(res => { |
| | | if(res.code === 200){ |
| | | associatedSalesOrderNumberOptions.value = res.data.records.map(item => ({ |
| | | label: item.salesContractNo, |
| | | value: item.salesContractNo, |
| | | productData:item.productData, |
| | | id: item.id |
| | | })) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | const getApproveStatusText = (row) => { |
| | | if (!row) return 'ä¸è¶³' |
| | | if (row.approveStatus === 1 && (!row.shippingDate || !row.shippingCarNumber)) { |
| | | return 'å
è¶³' |
| | | } |
| | | if (row.approveStatus === 0 && (row.shippingDate || row.shippingCarNumber)) { |
| | | return 'å·²åºåº' |
| | | } |
| | | return 'ä¸è¶³' |
| | | } |
| | | |
| | | const getApproveStatusType = (row) => { |
| | | const statusText = getApproveStatusText(row) |
| | | return statusText === 'ä¸è¶³' ? 'danger' : 'success' |
| | | } |
| | | |
| | | const getShippingStatusText = (row) => { |
| | | if (!row) return 'å¾
åè´§' |
| | | if (row.shippingDate || row.shippingCarNumber) { |
| | | return 'å·²åè´§' |
| | | } |
| | | const status = row.shippingStatus |
| | | if (status === null || status === undefined || status === '') { |
| | | return 'å¾
åè´§' |
| | | } |
| | | const map = { |
| | | 'å¾
åè´§': 'å¾
åè´§', |
| | | 'å¾
å®¡æ ¸': 'å¾
å®¡æ ¸', |
| | | 'å®¡æ ¸ä¸': 'å®¡æ ¸ä¸', |
| | | 'å®¡æ ¸æç»': 'å®¡æ ¸æç»', |
| | | 'å®¡æ ¸éè¿': 'å®¡æ ¸éè¿', |
| | | 'å·²åè´§': 'å·²åè´§' |
| | | } |
| | | return map[String(status).trim()] || 'å¾
åè´§' |
| | | } |
| | | |
| | | const getShippingStatusType = (row) => { |
| | | if (!row) return 'info' |
| | | if (row.shippingDate || row.shippingCarNumber) { |
| | | return 'success' |
| | | } |
| | | const status = row.shippingStatus |
| | | if (status === null || status === undefined || status === '') { |
| | | return 'info' |
| | | } |
| | | const map = { |
| | | 'å¾
åè´§': 'info', |
| | | 'å¾
å®¡æ ¸': 'warning', |
| | | 'å®¡æ ¸ä¸': 'warning', |
| | | 'å®¡æ ¸æç»': 'danger', |
| | | 'å®¡æ ¸éè¿': 'success', |
| | | 'å·²åè´§': 'success' |
| | | } |
| | | return map[String(status).trim()] || 'info' |
| | | } |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const openDialog =async (type, row) => { |
| | | // 请æ±å¤ä¸ªæ¥å£ï¼è·åæ°æ® |
| | | let res = await getAllCustomerList({ |
| | | current: 1, |
| | | size: 1000, |
| | | total: 0, |
| | | const data = reactive({ |
| | | form: { |
| | | topic: "", |
| | | serviceType: "", |
| | | urgency: "", |
| | | salesLedgerId: null, |
| | | productModelIds: "", |
| | | customerId: null, |
| | | salesContractNo: "", |
| | | proDesc: "", |
| | | customerName: "", |
| | | }, |
| | | rules: { |
| | | customerName: [ |
| | | { required: true, message: "è¯·éæ©å®¢æ·åç§°", trigger: "change" }, |
| | | ], |
| | | serviceType: [ |
| | | { required: true, message: "è¯·éæ©å®åç±»å", trigger: "change" }, |
| | | ], |
| | | urgency: [{ required: true, message: "è¯·éæ©ç´§æ¥ç¨åº¦", trigger: "change" }], |
| | | feedbackDate: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | }, |
| | | }); |
| | | if(res.records){ |
| | | customerNameOptions.value = res.records.map(item => ({ |
| | | label: item.customerName, |
| | | value: item.customerName, |
| | | id: item.id |
| | | })); |
| | | } |
| | | |
| | | // èªå®ä¹æ ¡éªå½æ°ï¼å¤ææ¯å¦éè¦æ ¡éªå®åç¼å· |
| | | |
| | | operationType.value = type; |
| | | dialogFormVisible.value = true; |
| | | form.value = {} |
| | | proxy.resetForm("formRef"); |
| | | form.value.checkUserId = userStore.id; |
| | | form.value.feedbackDate = getCurrentDate(); |
| | | // æ°å¢æ¶æ¸
空已éå
³è产å |
| | | if (type === "add") { |
| | | tableData.value = [] |
| | | } |
| | | userListNoPageByTenantId().then((res) => { |
| | | userList.value = res.data; |
| | | }); |
| | | if (type === "edit") { |
| | | form.value = {...row} |
| | | if (form.value.customerName) { |
| | | const res = await getSalesLedger({ customerName: form.value.customerName }) |
| | | if (res?.code === 200) { |
| | | console.log(res) |
| | | associatedSalesOrderNumberOptions.value = (res.data?.records || []).map(item => ({ |
| | | const { form, rules } = toRefs(data); |
| | | const userList = ref([]); |
| | | |
| | | const formatCurrency = val => { |
| | | if (val === null || val === undefined || val === "") return "-"; |
| | | const num = Number(val); |
| | | return Number.isFinite(num) ? num.toFixed(2) : "-"; |
| | | }; |
| | | |
| | | const { post_sale_waiting_list, degree_of_urgency } = proxy.useDict( |
| | | "post_sale_waiting_list", |
| | | "degree_of_urgency" |
| | | ); |
| | | |
| | | const serviceTypeOptions = computed(() => post_sale_waiting_list?.value || []); |
| | | const urgencyOptions = computed(() => degree_of_urgency?.value || []); |
| | | |
| | | const getProductRowId = row => { |
| | | return ( |
| | | row?.id ?? |
| | | row?.productModelId ?? |
| | | row?.modelId ?? |
| | | `${row?.productCategory || row?.productName || ""}-${ |
| | | row?.specificationModel || row?.model || "" |
| | | }-${row?.unit || ""}` |
| | | ); |
| | | }; |
| | | |
| | | const normalizeProductRow = row => { |
| | | return { |
| | | ...row, |
| | | id: getProductRowId(row), |
| | | productCategory: row?.productCategory ?? row?.productName ?? "", |
| | | specificationModel: row?.specificationModel ?? row?.model ?? "", |
| | | unit: row?.unit ?? "", |
| | | approveStatus: row?.approveStatus ?? null, |
| | | shippingStatus: row?.shippingStatus ?? "", |
| | | expressCompany: row?.expressCompany ?? "", |
| | | expressNumber: row?.expressNumber ?? "", |
| | | shippingCarNumber: row?.shippingCarNumber ?? "", |
| | | shippingDate: row?.shippingDate ?? "", |
| | | quantity: row?.quantity ?? 0, |
| | | taxRate: row?.taxRate ?? 0, |
| | | taxInclusiveUnitPrice: row?.taxInclusiveUnitPrice ?? 0, |
| | | taxInclusiveTotalPrice: row?.taxInclusiveTotalPrice ?? 0, |
| | | taxExclusiveTotalPrice: row?.taxExclusiveTotalPrice ?? 0, |
| | | noQuantity: row?.noQuantity ?? 0, |
| | | }; |
| | | }; |
| | | |
| | | const tableColumn = ref([ |
| | | { label: "产å大类", prop: "productCategory" }, |
| | | { label: "è§æ ¼åå·", prop: "specificationModel" }, |
| | | { label: "åä½", prop: "unit" }, |
| | | { |
| | | label: "产åç¶æ", |
| | | prop: "approveStatus", |
| | | width: 100, |
| | | align: "center", |
| | | dataType: "slot", |
| | | slot: "approveStatus", |
| | | }, |
| | | { |
| | | label: "åè´§ç¶æ", |
| | | align: "center", |
| | | width: 140, |
| | | dataType: "slot", |
| | | slot: "shippingStatus", |
| | | }, |
| | | { label: "å¿«éå
¬å¸", prop: "expressCompany", width: 140 }, |
| | | { label: "å¿«éåå·", prop: "expressNumber", width: 160 }, |
| | | { |
| | | label: "å货车ç", |
| | | prop: "shippingCarNumber", |
| | | minWidth: 100, |
| | | align: "center", |
| | | }, |
| | | { label: "åè´§æ¥æ", prop: "shippingDate", minWidth: 100, align: "center" }, |
| | | { label: "æ°é", prop: "quantity", width: 100 }, |
| | | { label: "ç¨ç(%)", prop: "taxRate", width: 100 }, |
| | | { |
| | | label: "å«ç¨åä»·(å
)", |
| | | prop: "taxInclusiveUnitPrice", |
| | | width: 160, |
| | | formatData: formatCurrency, |
| | | }, |
| | | { |
| | | label: "å«ç¨æ»ä»·(å
)", |
| | | prop: "taxInclusiveTotalPrice", |
| | | width: 160, |
| | | formatData: formatCurrency, |
| | | }, |
| | | { |
| | | label: "ä¸å«ç¨æ»ä»·(å
)", |
| | | prop: "taxExclusiveTotalPrice", |
| | | width: 160, |
| | | formatData: formatCurrency, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: "right", |
| | | operation: [ |
| | | { |
| | | name: "å é¤", |
| | | type: "text", |
| | | clickFun: row => { |
| | | tableData.value = tableData.value.filter( |
| | | i => getProductRowId(i) !== getProductRowId(row) |
| | | ); |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | // éæ©äº§åå¼¹çª |
| | | const isShowProductSelectDialog = ref(false); |
| | | const handleSelectProducts = rows => { |
| | | if (!Array.isArray(rows)) return; |
| | | const existingIds = new Set( |
| | | tableData.value.map(i => String(getProductRowId(i))) |
| | | ); |
| | | const mapped = rows |
| | | .map(normalizeProductRow) |
| | | .filter(r => !existingIds.has(String(getProductRowId(r)))); |
| | | tableData.value = tableData.value.concat(mapped); |
| | | }; |
| | | const currentSelectedProductIds = computed(() => { |
| | | return tableData.value |
| | | .map(item => getProductRowId(item)) |
| | | .filter(item => item !== undefined && item !== null && item !== ""); |
| | | }); |
| | | |
| | | const associatedSalesOrderNumberChange = () => { |
| | | const opt = associatedSalesOrderNumberOptions.value.find( |
| | | item => item.value === form.value.salesContractNo |
| | | ); |
| | | tableData.value = (opt?.productData || []).map(normalizeProductRow); |
| | | form.value.salesLedgerId = opt?.id || null; |
| | | }; |
| | | |
| | | const associatedSalesOrderNumberOptions = ref([]); |
| | | |
| | | const currentSalesOrderProducts = computed(() => { |
| | | const opt = associatedSalesOrderNumberOptions.value.find( |
| | | item => item.value === form.value.salesContractNo |
| | | ); |
| | | return (opt?.productData || []).map(normalizeProductRow); |
| | | }); |
| | | |
| | | const customerNameChange = val => { |
| | | form.value.salesContractNo = ""; |
| | | form.value.salesLedgerId = null; |
| | | tableData.value = []; |
| | | associatedSalesOrderNumberOptions.value = []; |
| | | const opt = customerNameOptions.value.find(item => item.value === val); |
| | | if (opt) { |
| | | form.value.customerId = opt.id; |
| | | } else { |
| | | form.value.customerId = null; |
| | | } |
| | | getSalesLedger({ |
| | | customerName: form.value.customerName, |
| | | }).then(res => { |
| | | if (res.code === 200) { |
| | | associatedSalesOrderNumberOptions.value = res.data.records.map(item => ({ |
| | | label: item.salesContractNo, |
| | | value: item.salesContractNo, |
| | | productData: item.productData, |
| | | id: item.id |
| | | })) |
| | | id: item.id, |
| | | })); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const getApproveStatusText = row => { |
| | | if (!row) return "ä¸è¶³"; |
| | | if ( |
| | | row.approveStatus === 1 && |
| | | (!row.shippingDate || !row.shippingCarNumber) |
| | | ) { |
| | | return "å
è¶³"; |
| | | } |
| | | console.log(form.value) |
| | | } |
| | | } |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | | // å¹é
产ååå·IDs |
| | | form.value.productModelIds = tableData.value.map(item => item.id).join(",") |
| | | if (operationType.value === "add") { |
| | | afterSalesServiceAdd(form.value).then(response => { |
| | | proxy.$modal.msgSuccess("æ°å¢æå") |
| | | closeDia() |
| | | }) |
| | | } else { |
| | | afterSalesServiceUpdate(form.value).then(response => { |
| | | proxy.$modal.msgSuccess("ä¿®æ¹æå") |
| | | closeDia() |
| | | }) |
| | | } |
| | | } |
| | | }) |
| | | } |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | emit('close') |
| | | }; |
| | | defineExpose({ |
| | | openDialog, |
| | | }); |
| | | if (row.approveStatus === 0 && (row.shippingDate || row.shippingCarNumber)) { |
| | | return "å·²åºåº"; |
| | | } |
| | | return "ä¸è¶³"; |
| | | }; |
| | | |
| | | const getApproveStatusType = row => { |
| | | const statusText = getApproveStatusText(row); |
| | | return statusText === "ä¸è¶³" ? "danger" : "success"; |
| | | }; |
| | | |
| | | const getShippingStatusText = row => { |
| | | if (!row) return "å¾
åè´§"; |
| | | if (row.shippingDate || row.shippingCarNumber) { |
| | | return "å·²åè´§"; |
| | | } |
| | | const status = row.shippingStatus; |
| | | if (status === null || status === undefined || status === "") { |
| | | return "å¾
åè´§"; |
| | | } |
| | | const map = { |
| | | å¾
åè´§: "å¾
åè´§", |
| | | å¾
å®¡æ ¸: "å¾
å®¡æ ¸", |
| | | å®¡æ ¸ä¸: "å®¡æ ¸ä¸", |
| | | å®¡æ ¸æç»: "å®¡æ ¸æç»", |
| | | å®¡æ ¸éè¿: "å®¡æ ¸éè¿", |
| | | å·²åè´§: "å·²åè´§", |
| | | }; |
| | | return map[String(status).trim()] || "å¾
åè´§"; |
| | | }; |
| | | |
| | | const getShippingStatusType = row => { |
| | | if (!row) return "info"; |
| | | if (row.shippingDate || row.shippingCarNumber) { |
| | | return "success"; |
| | | } |
| | | const status = row.shippingStatus; |
| | | if (status === null || status === undefined || status === "") { |
| | | return "info"; |
| | | } |
| | | const map = { |
| | | å¾
åè´§: "info", |
| | | å¾
å®¡æ ¸: "warning", |
| | | å®¡æ ¸ä¸: "warning", |
| | | å®¡æ ¸æç»: "danger", |
| | | å®¡æ ¸éè¿: "success", |
| | | å·²åè´§: "success", |
| | | }; |
| | | return map[String(status).trim()] || "info"; |
| | | }; |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const openDialog = async (type, row) => { |
| | | // 请æ±å¤ä¸ªæ¥å£ï¼è·åæ°æ® |
| | | let res = await getAllCustomerList({ |
| | | current: 1, |
| | | size: 1000, |
| | | total: 0, |
| | | }); |
| | | console.log(res, "res"); |
| | | |
| | | if (res.data.records) { |
| | | customerNameOptions.value = res.data.records.map(item => ({ |
| | | label: item.customerName, |
| | | value: item.customerName, |
| | | id: item.id, |
| | | })); |
| | | } else { |
| | | } |
| | | |
| | | operationType.value = type; |
| | | dialogFormVisible.value = true; |
| | | form.value = {}; |
| | | proxy.resetForm("formRef"); |
| | | form.value.checkUserId = userStore.id; |
| | | form.value.feedbackDate = getCurrentDate(); |
| | | // æ°å¢æ¶æ¸
空已éå
³è产å |
| | | if (type === "add") { |
| | | tableData.value = []; |
| | | } |
| | | userListNoPageByTenantId().then(res => { |
| | | userList.value = res.data; |
| | | }); |
| | | if (type === "edit") { |
| | | form.value = { ...row }; |
| | | if (form.value.customerName) { |
| | | const res = await getSalesLedger({ |
| | | customerName: form.value.customerName, |
| | | }); |
| | | if (res?.code === 200) { |
| | | console.log(res); |
| | | associatedSalesOrderNumberOptions.value = (res.data?.records || []).map( |
| | | item => ({ |
| | | label: item.salesContractNo, |
| | | value: item.salesContractNo, |
| | | productData: item.productData, |
| | | id: item.id, |
| | | }) |
| | | ); |
| | | } |
| | | } |
| | | console.log(form.value); |
| | | } |
| | | }; |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | | // å¹é
产ååå·IDs |
| | | form.value.productModelIds = tableData.value |
| | | .map(item => item.id) |
| | | .join(","); |
| | | if (operationType.value === "add") { |
| | | afterSalesServiceAdd(form.value).then(response => { |
| | | proxy.$modal.msgSuccess("æ°å¢æå"); |
| | | closeDia(); |
| | | }); |
| | | } else { |
| | | afterSalesServiceUpdate(form.value).then(response => { |
| | | proxy.$modal.msgSuccess("ä¿®æ¹æå"); |
| | | closeDia(); |
| | | }); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | emit("close"); |
| | | }; |
| | | defineExpose({ |
| | | openDialog, |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .descriptions { |
| | | margin-bottom: 20px; |
| | | display: inline-block; |
| | | font-size: 1rem; |
| | | font-weight: 600; |
| | | padding-left: 12px; |
| | | position: relative; |
| | | } |
| | | .descriptions { |
| | | margin-bottom: 20px; |
| | | display: inline-block; |
| | | font-size: 1rem; |
| | | font-weight: 600; |
| | | padding-left: 12px; |
| | | position: relative; |
| | | } |
| | | |
| | | .descriptions::before { |
| | | content: ""; |
| | | position: absolute; |
| | | left: 0; |
| | | top: 50%; |
| | | transform: translateY(-50%); |
| | | width: 4px; |
| | | height: 1rem; |
| | | background-color: #002FA7; /* Element é»è®¤çº¢è² */ |
| | | border-radius: 2px; |
| | | } |
| | | .descriptions::before { |
| | | content: ""; |
| | | position: absolute; |
| | | left: 0; |
| | | top: 50%; |
| | | transform: translateY(-50%); |
| | | width: 4px; |
| | | height: 1rem; |
| | | background-color: #002fa7; /* Element é»è®¤çº¢è² */ |
| | | border-radius: 2px; |
| | | } |
| | | </style> |
| | |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å·¡æ£é¡¹ç®" prop="inspectionProject"> |
| | | <el-input v-model="form.inspectionProject" placeholder="请è¾å
¥å·¡æ£é¡¹ç®" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¯å¦å¯ç¨" prop="isEnabled"> |
| | | <el-radio-group v-model="form.isEnabled"> |
| | | <el-radio :value="1">æ¯</el-radio> |
| | | <el-radio :value="0">å¦</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="夿³¨" prop="remarks"> |
| | | <el-input v-model="form.remarks" placeholder="请è¾å
¥å¤æ³¨" type="textarea" /> |
| | | </el-form-item> |
| | |
| | | taskName: undefined, |
| | | inspector: '', |
| | | inspectorIds: '', |
| | | inspectionProject: '', |
| | | isEnabled: 1, |
| | | remarks: '', |
| | | frequencyType: '', |
| | | frequencyDetail: '', |
| | |
| | | taskName: undefined, |
| | | inspector: '', |
| | | inspectorIds: '', |
| | | inspectionProject: '', |
| | | isEnabled: 1, |
| | | remarks: '', |
| | | frequencyType: '', |
| | | frequencyDetail: '', |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <FormDialog |
| | | v-model="dialogVisible" |
| | | title="ä¸ä¼ å·¡æ£è®°å½" |
| | | width="980px" |
| | | @close="handleClose" |
| | | @cancel="handleClose" |
| | | > |
| | | <main class="upload-content"> |
| | | <el-card v-if="taskInfo" class="section-card"> |
| | | <el-descriptions :column="1" border> |
| | | <el-descriptions-item label="å·¡æ£ä»»å¡åç§°"> |
| | | {{ taskInfo.taskName || "-" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="å·¡æ£é¡¹ç®"> |
| | | {{ taskInfo.inspectionProject || "-" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="夿³¨"> |
| | | {{ taskInfo.remarks || "-" }} |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | </el-card> |
| | | |
| | | <el-card class="section-card"> |
| | | <h3>å·¡æ£ç¶æ</h3> |
| | | <el-radio-group v-model="hasException"> |
| | | <el-radio-button :value="false">æ£å¸¸</el-radio-button> |
| | | <el-radio-button :value="true">åå¨å¼å¸¸</el-radio-button> |
| | | </el-radio-group> |
| | | </el-card> |
| | | |
| | | <el-card v-if="hasException === true" class="section-card"> |
| | | <h3>å¼å¸¸æè¿°</h3> |
| | | <el-input |
| | | v-model="abnormalDescription" |
| | | type="textarea" |
| | | maxlength="500" |
| | | show-word-limit |
| | | :rows="4" |
| | | placeholder="请æè¿°å¼å¸¸æ
åµ..." |
| | | /> |
| | | </el-card> |
| | | |
| | | <el-card v-if="hasException === true" class="section-card"> |
| | | <el-tabs v-model="currentUploadType"> |
| | | <el-tab-pane label="ç产å" name="before" /> |
| | | <el-tab-pane label="ç产ä¸" name="after" /> |
| | | <el-tab-pane label="ç产å" name="issue" /> |
| | | </el-tabs> |
| | | |
| | | <div class="upload-buttons"> |
| | | <el-upload |
| | | :show-file-list="false" |
| | | :http-request="uploadFile" |
| | | :disabled="getCurrentFiles().length >= uploadConfig.limit || uploading" |
| | | accept="image/*" |
| | | > |
| | | <el-button type="primary" :loading="uploading"> |
| | | <el-icon><Camera /></el-icon> |
| | | éæ©å¾ç |
| | | </el-button> |
| | | </el-upload> |
| | | |
| | | <el-upload |
| | | :show-file-list="false" |
| | | :http-request="uploadFile" |
| | | :disabled="getCurrentFiles().length >= uploadConfig.limit || uploading" |
| | | accept="video/*" |
| | | > |
| | | <el-button type="success" :loading="uploading"> |
| | | <el-icon><VideoCamera /></el-icon> |
| | | éæ©è§é¢ |
| | | </el-button> |
| | | </el-upload> |
| | | </div> |
| | | |
| | | <el-progress |
| | | v-if="uploading" |
| | | :percentage="uploadProgress" |
| | | class="upload-progress" |
| | | /> |
| | | |
| | | <div v-if="getCurrentFiles().length" class="file-list"> |
| | | <div |
| | | v-for="(file, index) in getCurrentFiles()" |
| | | :key="file.uid || file.id || index" |
| | | class="file-item" |
| | | > |
| | | <div class="file-preview-container"> |
| | | <el-image |
| | | v-if="file.type === 'image' || !file.type" |
| | | :src="file.url || file.tempFilePath || file.path || file.downloadUrl" |
| | | fit="cover" |
| | | class="file-preview" |
| | | :preview-src-list="[file.url || file.tempFilePath || file.path || file.downloadUrl]" |
| | | preview-teleported |
| | | /> |
| | | |
| | | <div v-else class="video-preview" @click="previewVideo(file)"> |
| | | <el-icon><VideoCamera /></el-icon> |
| | | <span>è§é¢</span> |
| | | </div> |
| | | |
| | | <el-button |
| | | class="delete-btn" |
| | | type="danger" |
| | | circle |
| | | size="small" |
| | | @click="removeFile(index)" |
| | | > |
| | | <el-icon><Close /></el-icon> |
| | | </el-button> |
| | | </div> |
| | | |
| | | <div class="file-info"> |
| | | <div class="file-name"> |
| | | {{ file.bucketFilename || file.name || (file.type === "image" ? "å¾ç" : "è§é¢") }} |
| | | </div> |
| | | <div class="file-size">{{ formatFileSize(file.size) }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <el-empty |
| | | v-else |
| | | :description="`è¯·éæ©è¦ä¸ä¼ ç${getUploadTypeText()}å¾çæè§é¢`" |
| | | /> |
| | | |
| | | <el-alert |
| | | class="upload-summary" |
| | | type="info" |
| | | :closable="false" |
| | | :title="`ç产åï¼${beforeModelValue.length}个æä»¶ | ç产ä¸ï¼${afterModelValue.length}个æä»¶ | ç产åï¼${issueModelValue.length}个æä»¶`" |
| | | /> |
| | | </el-card> |
| | | |
| | | <el-result |
| | | v-if="hasException === false" |
| | | icon="success" |
| | | title="设å¤è¿è¡æ£å¸¸" |
| | | sub-title="æ éä¸ä¼ ç
§ç" |
| | | /> |
| | | </main> |
| | | |
| | | <template #footer> |
| | | <footer class="footer-buttons"> |
| | | <el-button type="primary" @click="submitUpload">æäº¤</el-button> |
| | | <el-button v-if="hasException === true" type="warning" @click="goToRepair"> |
| | | æ°å¢æ¥ä¿® |
| | | </el-button> |
| | | <el-button @click="handleClose">åæ¶</el-button> |
| | | </footer> |
| | | </template> |
| | | </FormDialog> |
| | | |
| | | <el-dialog |
| | | v-model="showVideoDialog" |
| | | :title="currentVideoFile?.originalFilename || currentVideoFile?.name || 'è§é¢é¢è§'" |
| | | width="720px" |
| | | > |
| | | <video |
| | | v-if="currentVideoFile" |
| | | :src="currentVideoFile.url || currentVideoFile.downloadUrl" |
| | | class="video-player" |
| | | controls |
| | | autoplay |
| | | /> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, ref } from "vue"; |
| | | import { useRouter } from "vue-router"; |
| | | import { ElLoading, ElMessage, ElMessageBox } from "element-plus"; |
| | | import { Camera, Close, VideoCamera } from "@element-plus/icons-vue"; |
| | | import axios from "axios"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { uploadInspectionTask } from "@/api/inspectionManagement/index.js"; |
| | | import { getToken } from "@/utils/auth"; |
| | | |
| | | const emit = defineEmits(["closeDia", "success"]); |
| | | const router = useRouter(); |
| | | |
| | | const dialogVisible = ref(false); |
| | | const taskInfo = ref(null); |
| | | const uploading = ref(false); |
| | | const uploadProgress = ref(0); |
| | | |
| | | const beforeModelValue = ref([]); |
| | | const afterModelValue = ref([]); |
| | | const issueModelValue = ref([]); |
| | | |
| | | const currentUploadType = ref("before"); |
| | | const hasException = ref(null); |
| | | const abnormalDescription = ref(""); |
| | | |
| | | const showVideoDialog = ref(false); |
| | | const currentVideoFile = ref(null); |
| | | |
| | | const uploadConfig = { |
| | | action: "/common/upload", |
| | | limit: 10, |
| | | fileSize: 50, |
| | | fileType: ["jpg", "jpeg", "png", "mp4", "mov"], |
| | | }; |
| | | |
| | | const uploadFileUrl = computed( |
| | | () => `${import.meta.env.VITE_APP_BASE_API}${uploadConfig.action}` |
| | | ); |
| | | |
| | | const processFileUrl = fileUrl => { |
| | | if (!fileUrl) return ""; |
| | | |
| | | let currentUrl = String(fileUrl); |
| | | if (currentUrl.includes("\\")) { |
| | | const uploadsIndex = currentUrl.toLowerCase().indexOf("uploads"); |
| | | if (uploadsIndex > -1) { |
| | | currentUrl = `/${currentUrl.substring(uploadsIndex).replace(/\\/g, "/")}`; |
| | | } else { |
| | | const fileName = currentUrl.split("\\").pop(); |
| | | currentUrl = `/uploads/${fileName}`; |
| | | } |
| | | } |
| | | |
| | | if (currentUrl && !currentUrl.startsWith("http")) { |
| | | if (!currentUrl.startsWith("/")) { |
| | | currentUrl = `/${currentUrl}`; |
| | | } |
| | | currentUrl = __BASE_API__ + currentUrl; |
| | | } |
| | | |
| | | return currentUrl; |
| | | }; |
| | | |
| | | const normalizeList = (list, fileType) => { |
| | | if (!Array.isArray(list)) return []; |
| | | |
| | | return list.filter(Boolean).map(item => { |
| | | let currentType = item.type; |
| | | if (!currentType && item.contentType) { |
| | | currentType = item.contentType.startsWith("video") ? "video" : "image"; |
| | | } else if (!currentType) { |
| | | currentType = fileType || "image"; |
| | | } |
| | | |
| | | return { |
| | | ...item, |
| | | url: processFileUrl(item.url || item.previewURL || item.downloadUrl || item.path || ""), |
| | | downloadUrl: processFileUrl( |
| | | item.downloadUrl || item.url || item.previewURL || item.path || "" |
| | | ), |
| | | name: item.name || item.originalFilename || item.bucketFilename, |
| | | tempId: item.tempId || item.id || item.tempFileId, |
| | | tempFileId: item.tempFileId || item.tempId || item.id, |
| | | size: item.size || item.byteSize || 0, |
| | | type: currentType, |
| | | status: "success", |
| | | uid: item.uid || `${Date.now()}-${Math.random()}`, |
| | | }; |
| | | }); |
| | | }; |
| | | |
| | | const resetState = () => { |
| | | taskInfo.value = null; |
| | | beforeModelValue.value = []; |
| | | afterModelValue.value = []; |
| | | issueModelValue.value = []; |
| | | currentUploadType.value = "before"; |
| | | hasException.value = null; |
| | | abnormalDescription.value = ""; |
| | | uploading.value = false; |
| | | uploadProgress.value = 0; |
| | | showVideoDialog.value = false; |
| | | currentVideoFile.value = null; |
| | | }; |
| | | |
| | | const openDialog = row => { |
| | | const raw = JSON.parse(JSON.stringify(row?.__raw || row || {})); |
| | | taskInfo.value = raw; |
| | | |
| | | beforeModelValue.value = normalizeList( |
| | | raw.commonFileListBeforeVO || raw.commonFileListBefore || [], |
| | | "image" |
| | | ); |
| | | afterModelValue.value = normalizeList( |
| | | raw.commonFileListVO || raw.commonFileList || [], |
| | | "image" |
| | | ); |
| | | issueModelValue.value = normalizeList( |
| | | raw.commonFileListAfterVO || raw.commonFileListAfter || [], |
| | | "image" |
| | | ); |
| | | |
| | | abnormalDescription.value = raw.abnormalDescription || ""; |
| | | |
| | | if (raw.hasException !== undefined && raw.hasException !== null) { |
| | | hasException.value = raw.hasException; |
| | | } else if (raw.inspectionResult !== undefined && raw.inspectionResult !== null) { |
| | | hasException.value = String(raw.inspectionResult) === "0"; |
| | | } else { |
| | | hasException.value = null; |
| | | } |
| | | |
| | | if ( |
| | | hasException.value !== true && |
| | | (beforeModelValue.value.length || afterModelValue.value.length || issueModelValue.value.length) |
| | | ) { |
| | | hasException.value = true; |
| | | } |
| | | |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const handleClose = () => { |
| | | dialogVisible.value = false; |
| | | resetState(); |
| | | emit("closeDia"); |
| | | }; |
| | | |
| | | const getCurrentFiles = () => { |
| | | if (currentUploadType.value === "before") return beforeModelValue.value; |
| | | if (currentUploadType.value === "after") return afterModelValue.value; |
| | | if (currentUploadType.value === "issue") return issueModelValue.value; |
| | | return []; |
| | | }; |
| | | |
| | | const getUploadTypeText = () => { |
| | | if (currentUploadType.value === "before") return "ç产å"; |
| | | if (currentUploadType.value === "after") return "ç产ä¸"; |
| | | if (currentUploadType.value === "issue") return "ç产å"; |
| | | return ""; |
| | | }; |
| | | |
| | | const getTabType = () => { |
| | | if (currentUploadType.value === "before") return 10; |
| | | if (currentUploadType.value === "after") return 11; |
| | | if (currentUploadType.value === "issue") return 12; |
| | | return 10; |
| | | }; |
| | | |
| | | const previewVideo = file => { |
| | | currentVideoFile.value = file; |
| | | showVideoDialog.value = true; |
| | | }; |
| | | |
| | | const uploadFile = async uploadRequest => { |
| | | const rawFile = uploadRequest.file; |
| | | |
| | | if (getCurrentFiles().length >= uploadConfig.limit) { |
| | | ElMessage.warning(`æå¤åªè½éæ©${uploadConfig.limit}个æä»¶`); |
| | | return; |
| | | } |
| | | |
| | | const ext = rawFile.name.split(".").pop()?.toLowerCase(); |
| | | if (!uploadConfig.fileType.includes(ext)) { |
| | | ElMessage.warning(`æä»¶æ ¼å¼ä¸æ¯æï¼è¯·ä¸ä¼ ${uploadConfig.fileType.join("/")} æ ¼å¼`); |
| | | return; |
| | | } |
| | | |
| | | if (rawFile.size > uploadConfig.fileSize * 1024 * 1024) { |
| | | ElMessage.warning(`æä»¶å¤§å°ä¸è½è¶
è¿ ${uploadConfig.fileSize}MB`); |
| | | return; |
| | | } |
| | | |
| | | const token = getToken(); |
| | | if (!token) { |
| | | ElMessage.warning("ç¨æ·æªç»å½"); |
| | | return; |
| | | } |
| | | |
| | | const formData = new FormData(); |
| | | formData.append("files", rawFile); |
| | | formData.append("type", getTabType()); |
| | | |
| | | uploading.value = true; |
| | | uploadProgress.value = 0; |
| | | |
| | | try { |
| | | const { data } = await axios.post(uploadFileUrl.value, formData, { |
| | | headers: { |
| | | Authorization: `Bearer ${token}`, |
| | | "Content-Type": "multipart/form-data", |
| | | }, |
| | | onUploadProgress: event => { |
| | | if (event.total) { |
| | | uploadProgress.value = Math.round((event.loaded / event.total) * 100); |
| | | } |
| | | }, |
| | | }); |
| | | |
| | | if (data.code !== 200) { |
| | | ElMessage.error(data.msg || "ä¸ä¼ 失败"); |
| | | return; |
| | | } |
| | | |
| | | const resultData = Array.isArray(data.data) ? data.data[0] : data.data; |
| | | const finalUrl = processFileUrl( |
| | | resultData.url || resultData.previewURL || resultData.downloadUrl || "" |
| | | ); |
| | | const finalName = resultData.name || resultData.originalFilename || resultData.bucketFilename; |
| | | const finalId = resultData.tempId || resultData.id || resultData.tempFileId; |
| | | |
| | | const uploadedFile = { |
| | | ...resultData, |
| | | url: finalUrl, |
| | | downloadUrl: finalUrl, |
| | | name: finalName, |
| | | tempId: finalId, |
| | | tempFileId: resultData.tempFileId || finalId, |
| | | size: rawFile.size || resultData.size || resultData.byteSize || 0, |
| | | type: rawFile.type?.startsWith("video") ? "video" : "image", |
| | | status: "success", |
| | | uid: `${Date.now()}-${Math.random()}`, |
| | | }; |
| | | |
| | | getCurrentFiles().push(uploadedFile); |
| | | ElMessage.success("ä¸ä¼ æå"); |
| | | } catch (error) { |
| | | ElMessage.error(error?.message || "ä¸ä¼ 失败"); |
| | | } finally { |
| | | uploading.value = false; |
| | | } |
| | | }; |
| | | |
| | | const buildFileItem = item => ({ |
| | | id: item?.id, |
| | | tempId: item?.tempId, |
| | | tempFileId: item?.tempFileId, |
| | | url: item?.downloadUrl || item?.url || "", |
| | | downloadUrl: item?.downloadUrl || item?.url || "", |
| | | name: item?.name, |
| | | bucketFilename: item?.bucketFilename || item?.name, |
| | | originalFilename: item?.originalFilename || item?.name, |
| | | size: item?.size || 0, |
| | | byteSize: item?.byteSize || item?.size || 0, |
| | | contentType: item?.contentType || "", |
| | | type: item?.type, |
| | | }); |
| | | |
| | | const submitUpload = async () => { |
| | | if (hasException.value === null) { |
| | | ElMessage.warning("è¯·éæ©å·¡æ£ç¶æ"); |
| | | return; |
| | | } |
| | | |
| | | if (hasException.value === true) { |
| | | const totalFiles = |
| | | beforeModelValue.value.length + |
| | | afterModelValue.value.length + |
| | | issueModelValue.value.length; |
| | | |
| | | if (!totalFiles) { |
| | | ElMessage.warning("请ä¸ä¼ å¼å¸¸ç
§çæè§é¢"); |
| | | return; |
| | | } |
| | | |
| | | if (!abnormalDescription.value.trim()) { |
| | | ElMessage.warning("请填åå¼å¸¸æè¿°"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | const loading = ElLoading.service({ |
| | | text: "æäº¤ä¸...", |
| | | background: "rgba(0, 0, 0, 0.3)", |
| | | }); |
| | | |
| | | try { |
| | | const allFiles = [ |
| | | ...beforeModelValue.value, |
| | | ...afterModelValue.value, |
| | | ...issueModelValue.value, |
| | | ]; |
| | | |
| | | const tempFileIds = allFiles |
| | | .map(item => item?.tempId ?? item?.tempFileId ?? item?.id) |
| | | .filter(Boolean); |
| | | |
| | | const { |
| | | createTime, |
| | | updateTime, |
| | | storageBlobDTO, |
| | | commonFileListAfterVO, |
| | | commonFileListVO, |
| | | commonFileListBeforeVO, |
| | | commonFileListAfter, |
| | | commonFileList, |
| | | commonFileListBefore, |
| | | __raw, |
| | | ...baseTaskInfo |
| | | } = taskInfo.value || {}; |
| | | |
| | | const submitData = { |
| | | ...baseTaskInfo, |
| | | commonFileListBeforeDTO: beforeModelValue.value.map(buildFileItem), |
| | | commonFileListDTO: afterModelValue.value.map(buildFileItem), |
| | | commonFileListAfterDTO: issueModelValue.value.map(buildFileItem), |
| | | hasException: hasException.value, |
| | | inspectionResult: hasException.value ? 0 : 1, |
| | | abnormalDescription: abnormalDescription.value, |
| | | tempFileIds, |
| | | }; |
| | | |
| | | const result = await uploadInspectionTask(submitData); |
| | | |
| | | if (result && (result.code === 200 || result.success)) { |
| | | ElMessage.success("æäº¤æå"); |
| | | dialogVisible.value = false; |
| | | resetState(); |
| | | emit("success"); |
| | | emit("closeDia"); |
| | | } else { |
| | | ElMessage.error(result?.msg || result?.message || "æäº¤å¤±è´¥"); |
| | | } |
| | | } catch (error) { |
| | | ElMessage.error(error?.message || "æäº¤å¤±è´¥"); |
| | | } finally { |
| | | loading.close(); |
| | | } |
| | | }; |
| | | |
| | | const removeFile = async index => { |
| | | try { |
| | | await ElMessageBox.confirm("ç¡®å®è¦å é¤è¿ä¸ªæä»¶åï¼", "确认å é¤", { |
| | | type: "warning", |
| | | }); |
| | | getCurrentFiles().splice(index, 1); |
| | | } catch {} |
| | | }; |
| | | |
| | | const goToRepair = () => { |
| | | const taskData = { |
| | | taskId: taskInfo.value?.taskId || taskInfo.value?.id, |
| | | taskName: taskInfo.value?.taskName, |
| | | inspectionLocation: taskInfo.value?.inspectionLocation, |
| | | inspector: taskInfo.value?.inspector, |
| | | hasException: hasException.value, |
| | | inspectionResult: hasException.value ? 0 : 1, |
| | | commonFileListBeforeDTO: beforeModelValue.value.map(buildFileItem), |
| | | commonFileListDTO: afterModelValue.value.map(buildFileItem), |
| | | commonFileListAfterDTO: issueModelValue.value.map(buildFileItem), |
| | | uploadedFiles: { |
| | | before: beforeModelValue.value, |
| | | after: afterModelValue.value, |
| | | issue: issueModelValue.value, |
| | | }, |
| | | }; |
| | | |
| | | sessionStorage.setItem("repairTaskInfo", JSON.stringify(taskData)); |
| | | router.push("/equipmentManagement/repair/add"); |
| | | }; |
| | | |
| | | const formatFileSize = size => { |
| | | if (!size) return "0 B"; |
| | | |
| | | const units = ["B", "KB", "MB", "GB"]; |
| | | let index = 0; |
| | | let fileSize = size; |
| | | |
| | | while (fileSize >= 1024 && index < units.length - 1) { |
| | | fileSize /= 1024; |
| | | index += 1; |
| | | } |
| | | |
| | | return `${fileSize.toFixed(2)} ${units[index]}`; |
| | | }; |
| | | |
| | | defineExpose({ |
| | | openDialog, |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .inspection-upload-page { |
| | | min-height: 70vh; |
| | | background: #f5f7fa; |
| | | padding: 20px 20px 90px; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .upload-content { |
| | | max-width: 960px; |
| | | margin: 20px auto 0; |
| | | } |
| | | |
| | | .section-card { |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .section-card h3 { |
| | | margin: 0 0 16px; |
| | | font-size: 16px; |
| | | } |
| | | |
| | | .upload-buttons { |
| | | display: flex; |
| | | gap: 12px; |
| | | margin: 16px 0; |
| | | } |
| | | |
| | | .upload-progress { |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .file-list { |
| | | display: grid; |
| | | grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); |
| | | gap: 12px; |
| | | } |
| | | |
| | | .file-preview-container { |
| | | position: relative; |
| | | aspect-ratio: 1; |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | background: #f2f3f5; |
| | | } |
| | | |
| | | .file-preview { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .video-preview { |
| | | width: 100%; |
| | | height: 100%; |
| | | background: #303133; |
| | | color: #fff; |
| | | display: flex; |
| | | gap: 6px; |
| | | align-items: center; |
| | | justify-content: center; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .delete-btn { |
| | | position: absolute; |
| | | top: 6px; |
| | | right: 6px; |
| | | } |
| | | |
| | | .file-info { |
| | | margin-top: 6px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .file-name { |
| | | color: #606266; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .file-size { |
| | | color: #909399; |
| | | margin-top: 2px; |
| | | } |
| | | |
| | | .upload-summary { |
| | | margin-top: 16px; |
| | | } |
| | | |
| | | .footer-buttons { |
| | | position: sticky; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | padding: 14px 20px 0; |
| | | background: #f5f7fa; |
| | | display: flex; |
| | | justify-content: center; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .video-player { |
| | | width: 100%; |
| | | max-height: 70vh; |
| | | background: #000; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog title="æ¥çéä»¶" |
| | | v-model="dialogVisitable" width="800px" @close="cancel"> |
| | | <el-dialog title="æ¥çéä»¶" v-model="dialogVisitable" width="800px" @close="cancel"> |
| | | <div class="upload-container"> |
| | | <!-- ç产å --> |
| | | <div class="form-container"> |
| | | <div class="title">ç产å</div> |
| | | |
| | | <!-- å¾çå表 --> |
| | | <div style="display: flex; flex-wrap: wrap;"> |
| | | <img v-for="(item, index) in beforeProductionImgs" :key="index" |
| | | @click="showMedia(beforeProductionImgs, index, 'image')" |
| | | :src="item" style="max-width: 100px; height: 100px; margin: 5px;" alt=""> |
| | | |
| | | <div class="media-list"> |
| | | <img |
| | | v-for="(item, index) in beforeProductionImgs" |
| | | :key="`before-img-${index}`" |
| | | :src="item" |
| | | alt="" |
| | | class="media-image" |
| | | @click="showMedia(beforeProductionImgs, index, 'image')" |
| | | /> |
| | | </div> |
| | | |
| | | <!-- è§é¢å表 --> |
| | | <div style="display: flex; flex-wrap: wrap;"> |
| | | |
| | | <div class="media-list"> |
| | | <div |
| | | v-for="(videoUrl, index) in beforeProductionVideos" |
| | | :key="index" |
| | | @click="showMedia(beforeProductionVideos, index, 'video')" |
| | | style="position: relative; margin: 10px; cursor: pointer;" |
| | | v-for="(videoUrl, index) in beforeProductionVideos" |
| | | :key="`before-video-${index}`" |
| | | class="video-item" |
| | | @click="showMedia(beforeProductionVideos, index, 'video')" |
| | | > |
| | | <div style="width: 160px; height: 90px; background-color: #333; display: flex; align-items: center; justify-content: center;"> |
| | | <img src="@/assets/images/video.png" alt="ææ¾" style="width: 30px; height: 30px; opacity: 0.8;" /> |
| | | <div class="video-thumb"> |
| | | <img src="@/assets/images/video.png" alt="ææ¾" class="video-icon" /> |
| | | </div> |
| | | <div style="text-align: center; font-size: 12px; color: #666;">ç¹å»ææ¾</div> |
| | | <div class="video-text">ç¹å»ææ¾</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- ç产å --> |
| | | |
| | | <div class="form-container"> |
| | | <div class="title">ç产ä¸</div> |
| | | |
| | | <div class="media-list"> |
| | | <img |
| | | v-for="(item, index) in afterProductionImgs" |
| | | :key="`during-img-${index}`" |
| | | :src="item" |
| | | alt="" |
| | | class="media-image" |
| | | @click="showMedia(afterProductionImgs, index, 'image')" |
| | | /> |
| | | </div> |
| | | |
| | | <div class="media-list"> |
| | | <div |
| | | v-for="(videoUrl, index) in afterProductionVideos" |
| | | :key="`during-video-${index}`" |
| | | class="video-item" |
| | | @click="showMedia(afterProductionVideos, index, 'video')" |
| | | > |
| | | <div class="video-thumb"> |
| | | <img src="@/assets/images/video.png" alt="ææ¾" class="video-icon" /> |
| | | </div> |
| | | <div class="video-text">ç¹å»ææ¾</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="form-container"> |
| | | <div class="title">ç产å</div> |
| | | |
| | | <!-- å¾çå表 --> |
| | | <div style="display: flex; flex-wrap: wrap;"> |
| | | <img v-for="(item, index) in afterProductionImgs" :key="index" |
| | | @click="showMedia(afterProductionImgs, index, 'image')" |
| | | :src="item" style="max-width: 100px; height: 100px; margin: 5px;" alt=""> |
| | | |
| | | <div class="media-list"> |
| | | <img |
| | | v-for="(item, index) in productionIssuesImgs" |
| | | :key="`after-img-${index}`" |
| | | :src="item" |
| | | alt="" |
| | | class="media-image" |
| | | @click="showMedia(productionIssuesImgs, index, 'image')" |
| | | /> |
| | | </div> |
| | | |
| | | <!-- è§é¢å表 --> |
| | | <div style="display: flex; flex-wrap: wrap;"> |
| | | |
| | | <div class="media-list"> |
| | | <div |
| | | v-for="(videoUrl, index) in afterProductionVideos" |
| | | :key="index" |
| | | @click="showMedia(afterProductionVideos, index, 'video')" |
| | | style="position: relative; margin: 10px; cursor: pointer;" |
| | | v-for="(videoUrl, index) in productionIssuesVideos" |
| | | :key="`after-video-${index}`" |
| | | class="video-item" |
| | | @click="showMedia(productionIssuesVideos, index, 'video')" |
| | | > |
| | | <div style="width: 160px; height: 90px; background-color: #333; display: flex; align-items: center; justify-content: center;"> |
| | | <img src="@/assets/images/video.png" alt="ææ¾" style="width: 30px; height: 30px; opacity: 0.8;" /> |
| | | <div class="video-thumb"> |
| | | <img src="@/assets/images/video.png" alt="ææ¾" class="video-icon" /> |
| | | </div> |
| | | <div style="text-align: center; font-size: 12px; color: #666;">ç¹å»ææ¾</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- ç产é®é¢ --> |
| | | <div class="form-container"> |
| | | <div class="title">ç产é®é¢</div> |
| | | |
| | | <!-- å¾çå表 --> |
| | | <div style="display: flex; flex-wrap: wrap;"> |
| | | <img v-for="(item, index) in productionIssuesImgs" :key="index" |
| | | @click="showMedia(productionIssuesImgs, index, 'image')" |
| | | :src="item" style="max-width: 100px; height: 100px; margin: 5px;" alt=""> |
| | | </div> |
| | | |
| | | <!-- è§é¢å表 --> |
| | | <div style="display: flex; flex-wrap: wrap;"> |
| | | <div |
| | | v-for="(videoUrl, index) in productionIssuesVideos" |
| | | :key="index" |
| | | @click="showMedia(productionIssuesVideos, index, 'video')" |
| | | style="position: relative; margin: 10px; cursor: pointer;" |
| | | > |
| | | <div style="width: 160px; height: 90px; background-color: #333; display: flex; align-items: center; justify-content: center;"> |
| | | <img src="@/assets/images/video.png" alt="ææ¾" style="width: 30px; height: 30px; opacity: 0.8;" /> |
| | | </div> |
| | | <div style="text-align: center; font-size: 12px; color: #666;">ç¹å»ææ¾</div> |
| | | <div class="video-text">ç¹å»ææ¾</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-dialog> |
| | | |
| | | <!-- ç»ä¸åªä½æ¥çå¨ --> |
| | | |
| | | <div v-if="isMediaViewerVisible" class="media-viewer-overlay" @click.self="closeMediaViewer"> |
| | | <div class="media-viewer-content" @click.stop> |
| | | <!-- å¾ç --> |
| | | <vue-easy-lightbox |
| | | v-if="mediaType === 'image'" |
| | | :visible="isMediaViewerVisible" |
| | | :imgs="mediaList" |
| | | :index="currentMediaIndex" |
| | | @hide="closeMediaViewer" |
| | | ></vue-easy-lightbox> |
| | | |
| | | <!-- è§é¢ --> |
| | | <div v-else-if="mediaType === 'video'" style="position: relative;"> |
| | | <video |
| | | :src="mediaList[currentMediaIndex]" |
| | | autoplay |
| | | controls |
| | | style="max-width: 90vw; max-height: 80vh;" |
| | | /> |
| | | v-if="mediaType === 'image'" |
| | | :visible="isMediaViewerVisible" |
| | | :imgs="mediaList" |
| | | :index="currentMediaIndex" |
| | | @hide="closeMediaViewer" |
| | | /> |
| | | |
| | | <div v-else-if="mediaType === 'video'" class="video-player-wrap"> |
| | | <video :src="mediaList[currentMediaIndex]" autoplay controls class="video-player" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <script setup> |
| | | import { ref } from 'vue'; |
| | | import VueEasyLightbox from 'vue-easy-lightbox'; |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | // æ§å¶å¼¹çªæ¾ç¤º |
| | | <script setup> |
| | | import { ref } from "vue"; |
| | | import VueEasyLightbox from "vue-easy-lightbox"; |
| | | |
| | | const dialogVisitable = ref(false); |
| | | |
| | | // å¾çæ°ç» |
| | | const beforeProductionImgs = ref([]); |
| | | const afterProductionImgs = ref([]); |
| | | const productionIssuesImgs = ref([]); |
| | | |
| | | // è§é¢æ°ç» |
| | | const beforeProductionVideos = ref([]); |
| | | const afterProductionVideos = ref([]); |
| | | const productionIssuesVideos = ref([]); |
| | | |
| | | // åªä½æ¥çå¨ç¶æ |
| | | const isMediaViewerVisible = ref(false); |
| | | const currentMediaIndex = ref(0); |
| | | const mediaList = ref([]); // åå¨å½åè¦æ¥ççåªä½å表ï¼å«å¾çåè§é¢å¯¹è±¡ï¼ |
| | | const mediaType = ref('image'); // image | video |
| | | const mediaList = ref([]); |
| | | const mediaType = ref("image"); |
| | | |
| | | // å¤çæ¯ä¸ç±»æ°æ®ï¼å离å¾çåè§é¢ |
| | | function processItems(items) { |
| | | const processFileUrl = fileUrl => { |
| | | if (!fileUrl) return ""; |
| | | |
| | | let currentUrl = String(fileUrl); |
| | | if (currentUrl.includes("\\")) { |
| | | const uploadsIndex = currentUrl.toLowerCase().indexOf("uploads"); |
| | | if (uploadsIndex > -1) { |
| | | currentUrl = `/${currentUrl.substring(uploadsIndex).replace(/\\/g, "/")}`; |
| | | } else { |
| | | const fileName = currentUrl.split("\\").pop(); |
| | | currentUrl = `/uploads/${fileName}`; |
| | | } |
| | | } |
| | | |
| | | if (currentUrl && !currentUrl.startsWith("http")) { |
| | | if (!currentUrl.startsWith("/")) { |
| | | currentUrl = `/${currentUrl}`; |
| | | } |
| | | currentUrl = __BASE_API__ + currentUrl; |
| | | } |
| | | |
| | | return currentUrl; |
| | | }; |
| | | |
| | | const processItems = items => { |
| | | const images = []; |
| | | const videos = []; |
| | | |
| | | // æ£æ¥ items æ¯å¦åå¨ä¸ä¸ºæ°ç» |
| | | if (!items || !Array.isArray(items)) { |
| | | |
| | | if (!Array.isArray(items)) { |
| | | return { images, videos }; |
| | | } |
| | | |
| | | |
| | | items.forEach(item => { |
| | | if (!item || !item.previewURL || !item.contentType) return; |
| | | if (!item) return; |
| | | |
| | | |
| | | // å¤çæä»¶ URL |
| | | const fileUrl = item.previewURL; |
| | | const contentType = String(item.contentType).toLowerCase(); |
| | | const fileUrl = processFileUrl( |
| | | item.previewURL || item.url || item.downloadUrl || item.path || "" |
| | | ); |
| | | const contentType = String(item.contentType || "").toLowerCase(); |
| | | |
| | | // æ ¹æ® contentType 夿æ¯å¾çè¿æ¯è§é¢ |
| | | if (contentType.startsWith('image/')) { |
| | | images.push(fileUrl); |
| | | } else if (contentType.startsWith('video/')) { |
| | | if (!fileUrl) return; |
| | | |
| | | if (contentType.startsWith("video/")) { |
| | | videos.push(fileUrl); |
| | | return; |
| | | } |
| | | }); |
| | | |
| | | return { images, videos }; |
| | | } |
| | | |
| | | // æå¼å¼¹çªå¹¶å è½½æ°æ® |
| | | const openDialog = async (row) => { |
| | | // ä½¿ç¨æ£ç¡®çåæ®µåï¼commonFileListBefore, commonFileListAfter |
| | | const { images: beforeImgs, videos: beforeVids } = processItems(row.commonFileListBeforeVO || []); |
| | | const { images: afterImgs, videos: afterVids } = processItems(row.commonFileListAfterVO || []); |
| | | const { images: issueImgs, videos: issueVids } = processItems(row.commonFileListVO || []); |
| | | |
| | | images.push(fileUrl); |
| | | }); |
| | | |
| | | return { images, videos }; |
| | | }; |
| | | |
| | | const openDialog = row => { |
| | | const { images: beforeImgs, videos: beforeVids } = processItems( |
| | | row.commonFileListBeforeVO || [] |
| | | ); |
| | | const { images: afterImgs, videos: afterVids } = processItems( |
| | | row.commonFileListVO || [] |
| | | ); |
| | | const { images: issueImgs, videos: issueVids } = processItems( |
| | | row.commonFileListAfterVO || [] |
| | | ); |
| | | |
| | | beforeProductionImgs.value = beforeImgs; |
| | | beforeProductionVideos.value = beforeVids; |
| | | |
| | | afterProductionImgs.value = afterImgs; |
| | | afterProductionVideos.value = afterVids; |
| | | |
| | | productionIssuesImgs.value = issueImgs; |
| | | productionIssuesVideos.value = issueVids; |
| | | |
| | | dialogVisitable.value = true; |
| | | }; |
| | | |
| | | // æ¾ç¤ºåªä½ï¼å¾ç or è§é¢ï¼ |
| | | function showMedia(mediaArray, index, type) { |
| | | mediaList.value = mediaArray; |
| | | const showMedia = (items, index, type) => { |
| | | mediaList.value = items; |
| | | currentMediaIndex.value = index; |
| | | mediaType.value = type; |
| | | isMediaViewerVisible.value = true; |
| | | } |
| | | }; |
| | | |
| | | // å
³éåªä½æ¥çå¨ |
| | | function closeMediaViewer() { |
| | | const closeMediaViewer = () => { |
| | | isMediaViewerVisible.value = false; |
| | | mediaList.value = []; |
| | | mediaType.value = 'image'; |
| | | } |
| | | mediaType.value = "image"; |
| | | }; |
| | | |
| | | // 表åå
³éæ¹æ³ |
| | | const cancel = () => { |
| | | dialogVisitable.value = false; |
| | | }; |
| | | |
| | | defineExpose({ openDialog }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .upload-container { |
| | | display: flex; |
| | |
| | | padding: 20px; |
| | | border: 1px solid #dcdfe6; |
| | | box-sizing: border-box; |
| | | |
| | | |
| | | .form-container { |
| | | flex: 1; |
| | | width: 100%; |
| | |
| | | padding-left: 10px; |
| | | position: relative; |
| | | margin: 6px 0; |
| | | |
| | | |
| | | &::before { |
| | | content: ""; |
| | | position: absolute; |
| | |
| | | } |
| | | } |
| | | |
| | | .media-list { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .media-image { |
| | | max-width: 100px; |
| | | height: 100px; |
| | | margin: 5px; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .video-item { |
| | | position: relative; |
| | | margin: 10px; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .video-thumb { |
| | | width: 160px; |
| | | height: 90px; |
| | | background-color: #333; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .video-icon { |
| | | width: 30px; |
| | | height: 30px; |
| | | opacity: 0.8; |
| | | } |
| | | |
| | | .video-text { |
| | | text-align: center; |
| | | font-size: 12px; |
| | | color: #666; |
| | | } |
| | | |
| | | .media-viewer-overlay { |
| | | position: fixed; |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | inset: 0; |
| | | background-color: rgba(0, 0, 0, 0.8); |
| | | z-index: 9999; |
| | | display: flex; |
| | |
| | | max-height: 90vh; |
| | | overflow: hidden; |
| | | } |
| | | </style> |
| | | |
| | | .video-player-wrap { |
| | | position: relative; |
| | | } |
| | | |
| | | .video-player { |
| | | max-width: 90vw; |
| | | max-height: 80vh; |
| | | } |
| | | </style> |
| | |
| | | class="no-data">--</span> |
| | | </div> |
| | | </template> |
| | | <template #isEnabled="{ row }"> |
| | | <el-tag :type="row.isEnabled === 1 ? 'success' : 'danger'" |
| | | size="small"> |
| | | {{ row.isEnabled == 1 ? 'æ¯' : 'å¦' }} |
| | | </el-tag> |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | | </el-card> |
| | | <form-dia ref="formDia" |
| | | @closeDia="handleQuery"></form-dia> |
| | | <view-files ref="viewFiles"></view-files> |
| | | <upload-files ref="uploadFiles" |
| | | @success="handleQuery" |
| | | @closeDia="handleQuery"></upload-files> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | // ç»ä»¶å¼å
¥ |
| | | import PIMTable from "@/components/PIMTable/PIMTable.vue"; |
| | | import FormDia from "@/views/equipmentManagement/inspectionManagement/components/formDia.vue"; |
| | | import UploadFiles from "@/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue"; |
| | | import ViewFiles from "@/views/equipmentManagement/inspectionManagement/components/viewFiles.vue"; |
| | | |
| | | // æ¥å£å¼å
¥ |
| | |
| | | const { proxy } = getCurrentInstance(); |
| | | const formDia = ref(); |
| | | const viewFiles = ref(); |
| | | const uploadFiles = ref(); |
| | | |
| | | // æ¥è¯¢åæ° |
| | | const queryParams = reactive({ |
| | |
| | | // åé
ç½® |
| | | const columns = ref([ |
| | | { prop: "taskName", label: "å·¡æ£ä»»å¡åç§°", minWidth: 160 }, |
| | | { prop: "inspectionProject", label: "å·¡æ£é¡¹ç®", minWidth: 150 }, |
| | | { prop: "remarks", label: "夿³¨", minWidth: 150 }, |
| | | { prop: "inspector", label: "æ§è¡å·¡æ£äºº", minWidth: 150, slot: "inspector" }, |
| | | { |
| | | prop: "isEnabled", |
| | | label: "æ¯å¦å¯ç¨", |
| | | minWidth: 100, |
| | | dataType: "slot", |
| | | slot: "isEnabled", |
| | | }, |
| | | { |
| | | prop: "frequencyType", |
| | | label: "颿¬¡", |
| | |
| | | }, |
| | | { prop: "registrant", label: "ç»è®°äºº", minWidth: 100 }, |
| | | { prop: "createTime", label: "ç»è®°æ¥æ", minWidth: 100 }, |
| | | { |
| | | prop: "inspectionResult", |
| | | label: "å·¡æ£ç»æ", |
| | | minWidth: 100, |
| | | dataType: "tag", |
| | | formatData: val => { |
| | | return val == 1 ? "æ£å¸¸" : "å¼å¸¸"; |
| | | }, |
| | | formatType: val => { |
| | | return val == 1 ? "success" : "danger"; |
| | | }, |
| | | }, |
| | | { prop: "abnormalDescription", label: "å¼å¸¸æè¿°", minWidth: 100 }, |
| | | ]); |
| | | |
| | | // æä½åé
ç½® |
| | |
| | | |
| | | const operationConfig = { |
| | | label: "æä½", |
| | | width: 130, |
| | | width: operations.length > 1 ? 180 : 130, |
| | | fixed: "right", |
| | | align: 'center', |
| | | dataType: "action", |
| | | operation: operations |
| | | .map(op => { |
| | |
| | | return { |
| | | name: "ç¼è¾", |
| | | clickFun: handleAdd, |
| | | color: "#409EFF", |
| | | }; |
| | | case "upload": |
| | | return { |
| | | name: "ä¸ä¼ ", |
| | | clickFun: openUploadDialog, |
| | | color: "#409EFF", |
| | | }; |
| | | case "viewFile": |
| | |
| | | ]; |
| | | operationsArr.value = ["edit"]; |
| | | } else if (value === "task") { |
| | | const operationColumn = getOperationColumn(["viewFile"]); |
| | | const operationColumn = getOperationColumn(["upload", "viewFile"]); |
| | | // 宿¶ä»»å¡è®°å½ä¸å±ç¤º"æ¯å¦å¯ç¨"å |
| | | const taskColumns = columns.value.filter(col => col.prop !== "isEnabled"); |
| | | tableColumns.value = [ |
| | | ...columns.value, |
| | | ...taskColumns, |
| | | ...(operationColumn ? [operationColumn] : []), |
| | | ]; |
| | | operationsArr.value = ["viewFile"]; |
| | | operationsArr.value = ["upload", "viewFile"]; |
| | | } |
| | | pageNum.value = 1; |
| | | pageSize.value = 10; |
| | |
| | | // å¤ç inspector åæ®µï¼å°å符串转æ¢ä¸ºæ°ç»ï¼éç¨äºæææ
åµï¼ |
| | | tableData.value = rawData.map(item => { |
| | | const processedItem = { ...item }; |
| | | processedItem.__raw = { ...item }; |
| | | |
| | | // å¤ç inspector åæ®µ |
| | | if (processedItem.inspector) { |
| | |
| | | const viewFile = row => { |
| | | nextTick(() => { |
| | | viewFiles.value?.openDialog(row); |
| | | }); |
| | | }; |
| | | |
| | | const openUploadDialog = row => { |
| | | nextTick(() => { |
| | | uploadFiles.value?.openDialog(row); |
| | | }); |
| | | }; |
| | | |
| | |
| | | color: #909399; |
| | | font-size: 14px; |
| | | } |
| | | </style> |
| | | </style> |
| | |
| | | const showQRCode = async (row) => { |
| | | // ç´æ¥ä½¿ç¨URLï¼ä¸è¦ç¨JSON.stringifyå
è£
|
| | | const qrContent = proxy.javaApi + '/device-info?deviceId=' + row.id; |
| | | qrCodeUrl.value = await QRCode.toDataURL(qrContent); |
| | | const qrDataUrl = await QRCode.toDataURL(qrContent, { width: 200, margin: 2 }); |
| | | |
| | | // å建canvasåæå¸¦åç§°çäºç»´ç å¾ç |
| | | const canvas = document.createElement('canvas'); |
| | | const ctx = canvas.getContext('2d'); |
| | | const qrSize = 200; |
| | | const textHeight = 30; |
| | | const padding = 10; |
| | | canvas.width = qrSize + padding * 2; |
| | | canvas.height = qrSize + textHeight + padding * 2; |
| | | |
| | | // å¡«å
ç½è²èæ¯ |
| | | ctx.fillStyle = '#ffffff'; |
| | | ctx.fillRect(0, 0, canvas.width, canvas.height); |
| | | |
| | | // ç»å¶äºç»´ç |
| | | const qrImg = new Image(); |
| | | qrImg.src = qrDataUrl; |
| | | await new Promise((resolve) => { qrImg.onload = resolve; }); |
| | | ctx.drawImage(qrImg, padding, padding, qrSize, qrSize); |
| | | |
| | | // ç»å¶è®¾å¤åç§° |
| | | ctx.fillStyle = '#333333'; |
| | | ctx.font = 'bold 14px Arial'; |
| | | ctx.textAlign = 'center'; |
| | | ctx.fillText(row.deviceName || '', canvas.width / 2, qrSize + padding + 20); |
| | | |
| | | qrCodeUrl.value = canvas.toDataURL('image/png'); |
| | | qrRowData.value = row; |
| | | qrDialogVisible.value = true; |
| | | }; |
| | |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å®è£
ä½ç½®ï¼" prop="instationLocation"> |
| | | <el-input |
| | | v-model="form.instationLocation" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£å®åä½ï¼" prop="unit"> |
| | | <el-input |
| | | v-model="form.unit" |
| | |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è¯ä¹¦ç¼å·ï¼" prop="model"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è¯ä¹¦ç¼å·ï¼" prop="model"> |
| | | <el-input |
| | | v-model="form.model" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ææ°é´å®æ¥æï¼" prop="mostDate"> |
| | | <el-date-picker |
| | |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æææ¥æ(天)ï¼" prop="valid"> |
| | | <el-input |
| | |
| | | > |
| | | <template #append>æ¥</template> |
| | | </el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£å®å¨æï¼" prop="cycle"> |
| | | <el-input |
| | | v-model="form.cycle" |
| | | placeholder="请è¾å
¥æ£å®å¨æ" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | form: { |
| | | code: "", |
| | | name: "", |
| | | instationLocation: "", |
| | | mostDate:"", |
| | | model: "", |
| | | cycle:"", |
| | | validDate: "", |
| | | nextDate: "", |
| | | userId: "", |
| | |
| | | nextDate: [{required: true, message: "è¯·éæ©", trigger: "change"}], |
| | | userId: [{required: true, message: "è¯·éæ©", trigger: "change"}], |
| | | recordDate: [{required: true, message: "è¯·éæ©", trigger: "change"}], |
| | | instationLocation: [{required: true, message: "请è¾å
¥", trigger: "blur"}], |
| | | mostDate: [{required: true, message: "è¯·éæ©", trigger: "change"}], |
| | | cycle: [{required: true, message: "è¯·éæ©", trigger: "blur"}], |
| | | valid: [ |
| | | {required: true, message: "请è¾å
¥", trigger: "blur"}, |
| | | { |
| | |
| | | } |
| | | // ä¸è½½éä»¶ |
| | | const downLoadFile = (row) => { |
| | | proxy.$download.name(row.url); |
| | | proxy.$download.byUrl(row.url, row.originalFilename); |
| | | } |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | :dbRowClick="dbRowClick" |
| | | :rowClassName="rowClassName" |
| | | ></PIMTable> |
| | | </div> |
| | | <form-dia ref="formDia" @close="handleQuery"></form-dia> |
| | |
| | | align: "center", |
| | | }, |
| | | { |
| | | label: "å®è£
ä½ç½®", |
| | | prop: "instationLocation", |
| | | width: 150, |
| | | align:"center" |
| | | }, |
| | | { |
| | | label: "æ£å®åä½", |
| | | prop: "unit", |
| | | width: 200, |
| | |
| | | width: 130, |
| | | align:"center" |
| | | }, |
| | | { |
| | | label: "æ£å®å¨æ(天)", |
| | | prop: "cycle", |
| | | width: 130, |
| | | align:"center" |
| | | }, |
| | | { |
| | | label: "ç¶æ", |
| | | prop: "status", |
| | |
| | | |
| | | const dbRowClick = (row)=>{ |
| | | rowClickData.value?.openDialog(row) |
| | | } |
| | | |
| | | // è¡æ ·å¼ï¼å¿«å°æï¼7天å
ï¼æé¾ææ 红 |
| | | const rowClassName = ({ row }) => { |
| | | console.log('rowClassName called:', row); |
| | | // valid æ¯ææå¤©æ°ï¼mostDate æ¯ææ°æ£å®æ¥æ |
| | | if (row.valid && row.mostDate) { |
| | | const mostDate = new Date(row.mostDate); |
| | | // 计ç®å°ææ¥æ = æ£å®æ¥æ + ææå¤©æ° |
| | | const validDays = parseInt(row.valid) || 0; |
| | | const expireDate = new Date(mostDate); |
| | | expireDate.setDate(expireDate.getDate() + validDays); |
| | | |
| | | const now = new Date(); |
| | | const diffDays = Math.ceil((expireDate - now) / (1000 * 60 * 60 * 24)); |
| | | console.log('row:', row.code, 'validDays:', validDays, 'expireDate:', expireDate, 'diffDays:', diffDays); |
| | | // 7天å
å°ææå·²é¾æé½æ 红 |
| | | if (diffDays <= 7) { |
| | | console.log('return warning-row'); |
| | | return 'warning-row'; |
| | | } |
| | | } else { |
| | | console.log('row missing valid or mostDate:', row.valid, row.mostDate); |
| | | } |
| | | return ''; |
| | | } |
| | | |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | |
| | | </script> |
| | | |
| | | <style scoped> |
| | | |
| | | :deep(.el-table .warning-row) { |
| | | background-color: #fef0f0 !important; |
| | | } |
| | | :deep(.el-table .warning-row:hover > td) { |
| | | background-color: #f9d5d5 !important; |
| | | } |
| | | :deep(.el-table .el-table__body tr.warning-row td) { |
| | | background-color: #fef0f0 !important; |
| | | } |
| | | </style> |
| | |
| | | align="center" |
| | | > |
| | | <template #default="scope"> |
| | | {{ scope.row.runtimeDuration || '-' }} |
| | | {{ getRuntimeDurationDisplay(scope.row) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, computed } from 'vue' |
| | | import { ref, onMounted, onUnmounted, computed } from 'vue' |
| | | import dayjs from 'dayjs' |
| | | import { ElMessage } from 'element-plus' |
| | | import { |
| | | VideoPlay, |
| | |
| | | |
| | | return filtered |
| | | }) |
| | | |
| | | // è¿è¡ä¸æ ç»ææ¶é´æ¶ï¼è¿è¡æ¶é¿ééå½åæ¶é´ååï¼ç¨ tick è§¦åæ¨¡æ¿éç® |
| | | const runtimeDisplayTick = ref(0) |
| | | |
| | | /** åå端å¯è½ä½¿ç¨çå¼å§/ç»ææ¶é´å段 */ |
| | | const pickStartTime = (row) => row?.startRuntimeTime ?? row?.startTime ?? row?.start_time |
| | | const pickEndTime = (row) => row?.endRuntimeTime ?? row?.endTime ?? row?.end_time |
| | | |
| | | /** |
| | | * è§£ææ¥å£/å端åå
¥çåç±»æ¶é´ï¼æ¶é´æ³ãISO å符串ãyyyy-MM-dd HH:mm:ssãJackson æ°ç» [y,M,d,h,m,s]ãå«ä¸æç toLocaleString ç |
| | | */ |
| | | const parseDeviceTime = (input) => { |
| | | if (input === null || input === undefined || input === '') return null |
| | | if (typeof input === 'number' && !Number.isNaN(input)) { |
| | | const d = dayjs(input) |
| | | return d.isValid() ? d.toDate() : null |
| | | } |
| | | if (Array.isArray(input)) { |
| | | const [y, mo, day, h = 0, mi = 0, se = 0] = input |
| | | if (y == null || y === '') return null |
| | | const d = dayjs() |
| | | .year(Number(y)) |
| | | .month(Number(mo || 1) - 1) |
| | | .date(Number(day || 1)) |
| | | .hour(Number(h) || 0) |
| | | .minute(Number(mi) || 0) |
| | | .second(Number(se) || 0) |
| | | return d.isValid() ? d.toDate() : null |
| | | } |
| | | const s = String(input).trim() |
| | | if (!s || s === '-') return null |
| | | let d = dayjs(s) |
| | | if (d.isValid()) return d.toDate() |
| | | d = dayjs(s.replace(/-/g, '/')) |
| | | if (d.isValid()) return d.toDate() |
| | | d = dayjs(s.replace(/\//g, '-')) |
| | | if (d.isValid()) return d.toDate() |
| | | return null |
| | | } |
| | | |
| | | const formatDurationMs = (durationMs) => { |
| | | if (durationMs == null || Number.isNaN(durationMs) || durationMs < 0) return '-' |
| | | const hours = Math.floor(durationMs / (1000 * 60 * 60)) |
| | | const minutes = Math.floor((durationMs % (1000 * 60 * 60)) / (1000 * 60)) |
| | | if (hours === 0 && minutes === 0) return 'ä¸è¶³1åé' |
| | | return `${hours}å°æ¶${minutes}åé` |
| | | } |
| | | |
| | | const hasMeaningfulEnd = (endRaw) => |
| | | endRaw !== null && |
| | | endRaw !== undefined && |
| | | String(endRaw).trim() !== '' && |
| | | String(endRaw).trim() !== '-' |
| | | |
| | | const formatStoredDuration = (row) => { |
| | | const rd = row?.runtimeDuration |
| | | if (rd === null || rd === undefined) return '' |
| | | const t = String(rd).trim() |
| | | return t === '' || t === '-' ? '' : String(rd) |
| | | } |
| | | |
| | | /** è¿è¡ä¸ï¼å§ç»ç¨ãå½åæ¶é´ - å¼å§æ¶é´ãï¼å·²åæ¢ï¼ä¼å
æ¥å£ runtimeDurationï¼å¦åç¨ç»æ-å¼å§ï¼æ ç»æå¯çå·²åæ¶é¿æå¨ææ¨ç® */ |
| | | const getRuntimeDurationDisplay = (row) => { |
| | | void runtimeDisplayTick.value |
| | | const start = parseDeviceTime(pickStartTime(row)) |
| | | if (!start) { |
| | | return formatStoredDuration(row) || '-' |
| | | } |
| | | |
| | | const statusStr = String(row?.status ?? '').trim() |
| | | const isRunning = statusStr === 'è¿è¡ä¸' || statusStr === '1' |
| | | const endRaw = pickEndTime(row) |
| | | const hasEnd = hasMeaningfulEnd(endRaw) |
| | | |
| | | // æ ç»ææ¶é´ï¼è¿è¡ä¸ä¸å®å¨æç®ï¼å·²åæ¢åä¼å
å±ç¤ºåç«¯å·²åæ¶é¿ï¼æ²¡æåæå½åæ¶é´æ¨ç® |
| | | if (!hasEnd) { |
| | | if (isRunning) return formatDurationMs(Date.now() - start.getTime()) |
| | | const stored = formatStoredDuration(row) |
| | | if (stored) return stored |
| | | return formatDurationMs(Date.now() - start.getTime()) |
| | | } |
| | | |
| | | if (isRunning) { |
| | | return formatDurationMs(Date.now() - start.getTime()) |
| | | } |
| | | |
| | | const end = parseDeviceTime(endRaw) |
| | | const stored = formatStoredDuration(row) |
| | | if (stored) return stored |
| | | if (end) return formatDurationMs(end.getTime() - start.getTime()) |
| | | return '-' |
| | | } |
| | | |
| | | // æ£æ¥è®¾å¤æ¯å¦è¶
æ¶æªå¯å¨ |
| | | const isOverdue = (device) => { |
| | |
| | | device.endRuntimeTime = currentTime |
| | | // 计ç®è¿è¡æ¶é¿ |
| | | if (device.startRuntimeTime) { |
| | | const startTime = new Date(device.startRuntimeTime) |
| | | const endTime = new Date(currentTime) |
| | | const duration = endTime - startTime |
| | | const hours = Math.floor(duration / (1000 * 60 * 60)) |
| | | const minutes = Math.floor((duration % (1000 * 60 * 60)) / (1000 * 60)) |
| | | device.runtimeDuration = `${hours}å°æ¶${minutes}åé` |
| | | const startTime = parseDeviceTime(device.startRuntimeTime) |
| | | const endTime = parseDeviceTime(currentTime) |
| | | if (startTime && endTime) { |
| | | device.runtimeDuration = formatDurationMs(endTime.getTime() - startTime.getTime()) |
| | | } |
| | | } |
| | | } |
| | | const params = { |
| | |
| | | |
| | | |
| | | |
| | | // ç»ä»¶æè½½æ¶åå§åæ°æ® |
| | | const POLL_MS = 60 * 1000 |
| | | const RUNTIME_TICK_MS = 30 * 1000 |
| | | let listPollTimer = null |
| | | let runtimeTickTimer = null |
| | | |
| | | // ç»ä»¶æè½½æ¶æåæ°æ®ï¼å¹¶æ¯åéå·æ°ä¸æ¬¡å表ï¼è¿è¡ä¸æ¶é¿æ¯ 30 ç§å·æ°æ¾ç¤º |
| | | onMounted(() => { |
| | | getList() |
| | | listPollTimer = setInterval(() => { |
| | | getList() |
| | | }, POLL_MS) |
| | | runtimeTickTimer = setInterval(() => { |
| | | runtimeDisplayTick.value++ |
| | | }, RUNTIME_TICK_MS) |
| | | }) |
| | | |
| | | onUnmounted(() => { |
| | | if (listPollTimer != null) { |
| | | clearInterval(listPollTimer) |
| | | listPollTimer = null |
| | | } |
| | | if (runtimeTickTimer != null) { |
| | | clearInterval(runtimeTickTimer) |
| | | runtimeTickTimer = null |
| | | } |
| | | }) |
| | | </script> |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <FormDialog |
| | | v-model="visible" |
| | | title="éªæ¶å®¡æ¹" |
| | | width="500px" |
| | | @confirm="submitForm" |
| | | @cancel="handleCancel" |
| | | @close="handleCancel" |
| | | > |
| | | <el-form :model="form" :rules="rules" label-width="100px"> |
| | | <el-form-item label="éªæ¶äºº" prop="acceptanceName"> |
| | | <el-select |
| | | v-model="form.acceptanceName" |
| | | placeholder="è¯·éæ©éªæ¶äºº" |
| | | filterable |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="item in userList" |
| | | :key="item.userId" |
| | | :label="item.nickName" |
| | | :value="item.nickName" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="éªæ¶æ¶é´" prop="acceptanceTime"> |
| | | <el-date-picker |
| | | v-model="form.acceptanceTime" |
| | | type="datetime" |
| | | placeholder="è¯·éæ©éªæ¶æ¶é´" |
| | | format="YYYY-MM-DD HH:mm:ss" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="éªæ¶å¤æ³¨" prop="acceptanceRemark"> |
| | | <el-input |
| | | v-model="form.acceptanceRemark" |
| | | type="textarea" |
| | | :rows="3" |
| | | placeholder="请è¾å
¥éªæ¶å¤æ³¨" |
| | | /> |
| | | </el-form-item> |
| | | </el-form> |
| | | </FormDialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { ref, reactive } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { userListNoPageByTenantId } from "@/api/system/user.js"; |
| | | import { repairAcceptance } from "@/api/equipmentManagement/repair"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | defineOptions({ |
| | | name: "éªæ¶å®¡æ¹å¼¹çª", |
| | | }); |
| | | |
| | | const emits = defineEmits(["ok"]); |
| | | |
| | | const visible = ref(false); |
| | | const loading = ref(false); |
| | | const repairId = ref(null); |
| | | const userList = ref([]); |
| | | |
| | | const form = reactive({ |
| | | acceptanceName: undefined, |
| | | acceptanceTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), |
| | | acceptanceRemark: undefined, |
| | | }); |
| | | |
| | | const rules = { |
| | | acceptanceName: [ |
| | | { required: true, message: "è¯·éæ©éªæ¶äºº", trigger: "change" }, |
| | | ], |
| | | acceptanceTime: [ |
| | | { required: true, message: "è¯·éæ©éªæ¶æ¶é´", trigger: "change" }, |
| | | ], |
| | | acceptanceRemark: [ |
| | | { required: true, message: "请è¾å
¥éªæ¶å¤æ³¨", trigger: "blur" }, |
| | | ], |
| | | }; |
| | | |
| | | // å è½½ç¨æ·å表 |
| | | const loadUserList = async () => { |
| | | const { data } = await userListNoPageByTenantId(); |
| | | userList.value = data; |
| | | }; |
| | | |
| | | // æå¼å¼¹çª |
| | | const open = async (row) => { |
| | | repairId.value = row.id; |
| | | visible.value = true; |
| | | // é置表å |
| | | form.acceptanceName = undefined; |
| | | form.acceptanceTime = dayjs().format("YYYY-MM-DD HH:mm:ss"); |
| | | form.acceptanceRemark = undefined; |
| | | await loadUserList(); |
| | | }; |
| | | |
| | | // æäº¤è¡¨å |
| | | const submitForm = async () => { |
| | | if (!form.acceptanceName) { |
| | | ElMessage.warning("è¯·éæ©éªæ¶äºº"); |
| | | return; |
| | | } |
| | | if (!form.acceptanceTime) { |
| | | ElMessage.warning("è¯·éæ©éªæ¶æ¶é´"); |
| | | return; |
| | | } |
| | | if (!form.acceptanceRemark) { |
| | | ElMessage.warning("请è¾å
¥éªæ¶å¤æ³¨"); |
| | | return; |
| | | } |
| | | |
| | | loading.value = true; |
| | | try { |
| | | const { code } = await repairAcceptance({ |
| | | id: repairId.value, |
| | | acceptanceName: form.acceptanceName, |
| | | acceptanceTime: form.acceptanceTime, |
| | | acceptanceRemark: form.acceptanceRemark, |
| | | }); |
| | | if (code === 200) { |
| | | ElMessage.success("éªæ¶éè¿"); |
| | | visible.value = false; |
| | | emits("ok"); |
| | | } |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | |
| | | const handleCancel = () => { |
| | | visible.value = false; |
| | | }; |
| | | |
| | | defineExpose({ |
| | | open, |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="项ç®"> |
| | | <el-input v-model="form.machineryCategory" placeholder="请è¾å
¥é¡¹ç®" /> |
| | | <el-form-item label="æ¥ä¿®æ¥ä¿®é¡¹ç®"> |
| | | <el-input v-model="form.machineryCategory" placeholder="请è¾å
¥æ¥ä¿®æ¥ä¿®é¡¹ç®" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="维修人"> |
| | | <el-input v-model="form.maintenanceName" placeholder="请è¾å
¥ç»´ä¿®äººå§å" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row v-if="id"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¥ä¿®ç¶æ"> |
| | | <el-select v-model="form.status"> |
| | | <el-select v-model="form.status" disabled> |
| | | <el-option label="å¾
ç»´ä¿®" :value="0"></el-option> |
| | | <el-option label="å®ç»" :value="1"></el-option> |
| | | <el-option label="å·²éªæ¶" :value="1"></el-option> |
| | | <el-option label="失败" :value="2"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <!-- éªæ¶ä¿¡æ¯å±ç¤º --> |
| | | <el-row v-if="id && form.status === 1"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éªæ¶äºº"> |
| | | <el-input v-model="form.acceptanceName" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éªæ¶æ¶é´"> |
| | | <el-input v-model="form.acceptanceTime" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="éªæ¶å¤æ³¨"> |
| | | <el-input v-model="form.acceptanceRemark" type="textarea" :rows="2" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | status: 0, // æ¥ä¿®ç¶æ |
| | | machineryCategory: undefined, |
| | | storageBlobDTOs: [], |
| | | maintenanceName: undefined, // 维修人 |
| | | }); |
| | | |
| | | const setDeviceModel = (deviceId) => { |
| | |
| | | form.status = data.status; |
| | | form.machineryCategory = data.machineryCategory; |
| | | form.storageBlobDTOs = data.storageBlobVOs || []; |
| | | form.maintenanceName = data.maintenanceName; |
| | | form.acceptanceName = data.acceptanceName; |
| | | form.acceptanceTime = data.acceptanceTime; |
| | | form.acceptanceRemark = data.acceptanceRemark; |
| | | }; |
| | | |
| | | const sendForm = async () => { |
| | |
| | | <template #statusRef="{ row }"> |
| | | <el-tag v-if="row.status === 2" type="danger">失败</el-tag> |
| | | <el-tag v-if="row.status === 1" type="success">å®ç»</el-tag> |
| | | <el-tag v-if="row.status === 3" type="info">å¾
éªæ¶</el-tag> |
| | | <el-tag v-if="row.status === 0" type="warning">å¾
ç»´ä¿®</el-tag> |
| | | </template> |
| | | <template #operation="{ row }"> |
| | | <el-button |
| | | type="primary" |
| | | link |
| | | :disabled="row.status === 1" |
| | | :disabled="row.status === 1 || row.status === 3" |
| | | @click="editRepair(row.id)" |
| | | > |
| | | ç¼è¾ |
| | |
| | | <el-button |
| | | type="success" |
| | | link |
| | | :disabled="row.status === 1" |
| | | :disabled="row.status !== 0" |
| | | @click="addMaintain(row)" |
| | | > |
| | | ç»´ä¿® |
| | | </el-button> |
| | | <el-button |
| | | type="warning" |
| | | link |
| | | :disabled="row.status !== 3" |
| | | @click="openAcceptance(row)" |
| | | > |
| | | éªæ¶ |
| | | </el-button> |
| | | <el-button |
| | | type="danger" |
| | | link |
| | | :disabled="row.status === 1" |
| | | :disabled="row.status === 1 || row.status === 3" |
| | | @click="delRepairByIds(row.id)" |
| | | > |
| | | å é¤ |
| | |
| | | </div> |
| | | <RepairModal ref="repairModalRef" @ok="getTableData"/> |
| | | <MaintainModal ref="maintainModalRef" @ok="getTableData"/> |
| | | <AcceptanceModal ref="acceptanceModalRef" @ok="getTableData"/> |
| | | <FileList v-if="fileDialogVisible" v-model:visible="fileDialogVisible" :record-type="'device_repair'" :record-id="recordId" /> |
| | | </div> |
| | | </template> |
| | |
| | | import {ElMessageBox, ElMessage} from "element-plus"; |
| | | import dayjs from "dayjs"; |
| | | import MaintainModal from "./Modal/MaintainModal.vue"; |
| | | import AcceptanceModal from "./Modal/AcceptanceModal.vue"; |
| | | const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue")); |
| | | |
| | | defineOptions({ |
| | |
| | | // æ¨¡ææ¡å®ä¾ |
| | | const repairModalRef = ref(); |
| | | const maintainModalRef = ref(); |
| | | const acceptanceModalRef = ref(); |
| | | |
| | | // è¡¨æ ¼å¤éæ¡éä¸é¡¹ |
| | | const multipleList = ref([]); |
| | |
| | | prop: "deviceModel", |
| | | }, |
| | | { |
| | | label: "项ç®", |
| | | label: "æ¥ä¿®é¡¹ç®", |
| | | align: "center", |
| | | prop: "machineryCategory", |
| | | }, |
| | |
| | | align: "center", |
| | | prop: "maintenanceTime", |
| | | formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD") : ""), |
| | | }, |
| | | { |
| | | label: "éªæ¶äºº", |
| | | align: "center", |
| | | prop: "acceptanceName", |
| | | }, |
| | | { |
| | | label: "éªæ¶æ¶é´", |
| | | align: "center", |
| | | prop: "acceptanceTime", |
| | | formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD HH:mm:ss") : ""), |
| | | }, |
| | | { |
| | | label: "ç¶æ", |
| | |
| | | maintainModalRef.value.open(row.id, row); |
| | | }; |
| | | |
| | | // æå¼éªæ¶å¼¹çª |
| | | const openAcceptance = (row) => { |
| | | acceptanceModalRef.value.open(row); |
| | | }; |
| | | |
| | | const changePage = ({page, limit}) => { |
| | | pagination.currentPage = page; |
| | | pagination.pageSize = limit; |
| | |
| | | <template> |
| | | <FormDialog |
| | | v-model="visible" |
| | | :title="'设å¤ä¿å
»'" |
| | | width="500px" |
| | | @confirm="sendForm" |
| | | @cancel="handleCancel" |
| | | @close="handleClose" |
| | | > |
| | | <el-form :model="form" label-width="100px"> |
| | | <FormDialog v-model="visible" |
| | | :title="'设å¤ä¿å
»'" |
| | | width="500px" |
| | | @confirm="sendForm" |
| | | @cancel="handleCancel" |
| | | @close="handleClose"> |
| | | <el-form :model="form" |
| | | label-width="100px"> |
| | | <el-form-item label="å®é
ä¿å
»äºº"> |
| | | <el-input |
| | | v-model="form.maintenanceActuallyName" |
| | | placeholder="请è¾å
¥å®é
ä¿å
»äºº" |
| | | ></el-input> |
| | | <el-input v-model="form.maintenanceActuallyName" |
| | | placeholder="请è¾å
¥å®é
ä¿å
»äºº"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="å®é
ä¿å
»æ¥æ"> |
| | | <el-date-picker |
| | | v-model="form.maintenanceActuallyTime" |
| | | placeholder="è¯·éæ©å®é
ä¿å
»æ¥æ" |
| | | format="YYYY-MM-DD HH:mm:ss" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | type="datetime" |
| | | clearable |
| | | style="width: 100%" |
| | | /> |
| | | <el-date-picker v-model="form.maintenanceActuallyTime" |
| | | placeholder="è¯·éæ©å®é
ä¿å
»æ¥æ" |
| | | format="YYYY-MM-DD HH:mm:ss" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | type="datetime" |
| | | clearable |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | <el-form-item label="ä¿å
»ç¶æ"> |
| | | <el-select v-model="form.status"> |
| | | <el-option label="å¾
ä¿å
»" :value="0"></el-option> |
| | | <el-option label="å®ç»" :value="1"></el-option> |
| | | <el-option label="失败" :value="2"></el-option> |
| | | <el-option label="å¾
ä¿å
»" |
| | | :value="0"></el-option> |
| | | <el-option label="å®ç»" |
| | | :value="1"></el-option> |
| | | <el-option label="失败" |
| | | :value="2"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="ä¿å
ȍȾ"> |
| | | <el-input |
| | | v-model="form.maintenanceResult" |
| | | placeholder="请è¾å
¥ä¿å
ȍȾ" |
| | | type="text" /> |
| | | <el-input v-model="form.maintenanceResult" |
| | | placeholder="请è¾å
¥ä¿å
ȍȾ" |
| | | type="text" /> |
| | | </el-form-item> |
| | | <el-form-item label="设å¤å¤ä»¶"> |
| | | <el-select v-model="form.sparePartsIds" :loading="loadingSparePartOptions" placeholder="è¯·éæ©è®¾å¤å¤ä»¶" multiple filterable> |
| | | <el-option |
| | | v-for="item in sparePartOptions" |
| | | :key="item.id" |
| | | :label="item.name" |
| | | :value="item.id" |
| | | /> |
| | | <el-select v-model="form.sparePartsIds" |
| | | :loading="loadingSparePartOptions" |
| | | placeholder="è¯·éæ©è®¾å¤å¤ä»¶" |
| | | multiple |
| | | filterable> |
| | | <el-option v-for="item in sparePartOptions" |
| | | :key="item.id" |
| | | :label="item.name" |
| | | :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item v-if="selectedSpareParts.length" label="é¢ç¨æ°é"> |
| | | <el-form-item v-if="selectedSpareParts.length" |
| | | label="é¢ç¨æ°é"> |
| | | <div style="width: 100%"> |
| | | <div |
| | | v-for="item in selectedSpareParts" |
| | | :key="item.id" |
| | | style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px;" |
| | | > |
| | | <div v-for="item in selectedSpareParts" |
| | | :key="item.id" |
| | | style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px;"> |
| | | <div style="flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"> |
| | | {{ item.name }} |
| | | <span v-if="item.quantity !== null && item.quantity !== undefined" style="color: #909399;"> |
| | | <span v-if="item.quantity !== null && item.quantity !== undefined" |
| | | style="color: #909399;"> |
| | | ï¼åºåï¼{{ item.quantity }}ï¼ |
| | | </span> |
| | | </div> |
| | | <el-input-number |
| | | v-model="sparePartQtyMap[item.id]" |
| | | :min="1" |
| | | :max="item.quantity !== null && item.quantity !== undefined ? Number(item.quantity) : undefined" |
| | | :step="1" |
| | | controls-position="right" |
| | | style="width: 180px" |
| | | /> |
| | | <el-input-number v-model="sparePartQtyMap[item.id]" |
| | | :min="1" |
| | | :max="item.quantity !== null && item.quantity !== undefined ? Number(item.quantity) : undefined" |
| | | :step="1" |
| | | controls-position="right" |
| | | style="width: 180px" /> |
| | | </div> |
| | | </div> |
| | | </el-form-item> |
| | | <el-form-item label="éä»¶"> |
| | | <FileUpload v-model:file-list="form.storageBlobDTOs" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | </FormDialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { addMaintenance } from "@/api/equipmentManagement/upkeep"; |
| | | import useFormData from "@/hooks/useFormData"; |
| | | import dayjs from "dayjs"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { ElMessage } from "element-plus"; |
| | | import {computed, ref} from "vue"; |
| | | import {getSparePartsList} from "@/api/equipmentManagement/spareParts.js"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import FileUpload from "@/components/AttachmentUpload/file/index.vue"; |
| | | import { addMaintenance } from "@/api/equipmentManagement/upkeep"; |
| | | import useFormData from "@/hooks/useFormData"; |
| | | import dayjs from "dayjs"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { computed, ref, nextTick, getCurrentInstance } from "vue"; |
| | | import { getSparePartsList } from "@/api/equipmentManagement/spareParts.js"; |
| | | |
| | | defineOptions({ |
| | | name: "ä¿å
»æ¨¡ææ¡", |
| | | }); |
| | | defineOptions({ |
| | | name: "ä¿å
»æ¨¡ææ¡", |
| | | }); |
| | | |
| | | const emits = defineEmits(["ok"]); |
| | | const emits = defineEmits(["ok"]); |
| | | |
| | | // ä¿å计åä¿å
»è®°å½çid |
| | | const planId = ref(); |
| | | const visible = ref(false); |
| | | const loading = ref(false); |
| | | const userStore = useUserStore(); |
| | | const { proxy } = getCurrentInstance(); |
| | | // ä¿å计åä¿å
»è®°å½çid |
| | | const planId = ref(); |
| | | const visible = ref(false); |
| | | const loading = ref(false); |
| | | const userStore = useUserStore(); |
| | | |
| | | const { form, resetForm } = useFormData({ |
| | | maintenanceActuallyName: undefined, // å®é
ä¿å
»äºº |
| | | maintenanceActuallyTime: undefined, // å®é
ä¿å
»æ¥æ |
| | | maintenanceResult: undefined, // ä¿å
ȍȾ |
| | | status: 0, // ä¿å
»ç¶æ |
| | | sparePartsIds: [], |
| | | }); |
| | | const { form, resetForm } = useFormData({ |
| | | maintenanceActuallyName: undefined, // å®é
ä¿å
»äºº |
| | | maintenanceActuallyTime: undefined, // å®é
ä¿å
»æ¥æ |
| | | maintenanceResult: undefined, // ä¿å
ȍȾ |
| | | status: 0, // ä¿å
»ç¶æ |
| | | sparePartsIds: [], |
| | | storageBlobDTOs: [], |
| | | }); |
| | | |
| | | const sparePartOptions = ref([]) |
| | | const loadingSparePartOptions = ref(true) |
| | | const sparePartQtyMap = ref({}) |
| | | const sparePartOptions = ref([]); |
| | | const loadingSparePartOptions = ref(true); |
| | | const sparePartQtyMap = ref({}); |
| | | |
| | | const selectedSpareParts = computed(() => { |
| | | const ids = Array.isArray(form.sparePartsIds) ? form.sparePartsIds : []; |
| | | const set = new Set(ids.map((i) => String(i))); |
| | | return (sparePartOptions.value || []).filter((p) => set.has(String(p.id))); |
| | | }); |
| | | const selectedSpareParts = computed(() => { |
| | | const ids = Array.isArray(form.sparePartsIds) ? form.sparePartsIds : []; |
| | | const set = new Set(ids.map(i => String(i))); |
| | | return (sparePartOptions.value || []).filter(p => set.has(String(p.id))); |
| | | }); |
| | | |
| | | const setForm = (data) => { |
| | | form.maintenanceActuallyName = |
| | | data.maintenanceActuallyName ?? userStore.nickName; |
| | | form.maintenanceActuallyTime = |
| | | data.maintenanceActuallyTime |
| | | const setForm = data => { |
| | | form.maintenanceActuallyName = |
| | | data.maintenanceActuallyName ?? userStore.nickName; |
| | | form.maintenanceActuallyTime = data.maintenanceActuallyTime |
| | | ? dayjs(data.maintenanceActuallyTime).format("YYYY-MM-DD HH:mm:ss") |
| | | : dayjs().format("YYYY-MM-DD HH:mm:ss"); |
| | | form.maintenanceResult = data.maintenanceResult; |
| | | form.status = 1; // é»è®¤ç¶æä¸ºå®ç» |
| | | // multiple éæ©å¨è¦æ±æ°ç»ï¼å端常è¿å "1,2,3" |
| | | if (Array.isArray(data?.sparePartsIds)) { |
| | | form.sparePartsIds = data.sparePartsIds.map((v) => Number(v)).filter((v) => Number.isFinite(v)); |
| | | } else if (typeof data?.sparePartsIds === "string") { |
| | | form.sparePartsIds = data.sparePartsIds |
| | | form.maintenanceResult = data.maintenanceResult; |
| | | form.status = 1; // é»è®¤ç¶æä¸ºå®ç» |
| | | // multiple éæ©å¨è¦æ±æ°ç»ï¼å端常è¿å "1,2,3" |
| | | if (Array.isArray(data?.sparePartsIds)) { |
| | | form.sparePartsIds = data.sparePartsIds |
| | | .map(v => Number(v)) |
| | | .filter(v => Number.isFinite(v)); |
| | | } else if (typeof data?.sparePartsIds === "string") { |
| | | form.sparePartsIds = data.sparePartsIds |
| | | .split(",") |
| | | .map((s) => Number(String(s).trim())) |
| | | .filter((v) => Number.isFinite(v)); |
| | | } else if (typeof data?.sparePartsIds === "number") { |
| | | form.sparePartsIds = [data.sparePartsIds]; |
| | | } else { |
| | | form.sparePartsIds = []; |
| | | } |
| | | }; |
| | | .map(s => Number(String(s).trim())) |
| | | .filter(v => Number.isFinite(v)); |
| | | } else if (typeof data?.sparePartsIds === "number") { |
| | | form.sparePartsIds = [data.sparePartsIds]; |
| | | } else { |
| | | form.sparePartsIds = []; |
| | | } |
| | | form.storageBlobDTOs = data.storageBlobVOs || []; |
| | | }; |
| | | |
| | | /** |
| | | * @desc ä¿åä¿å
» |
| | | */ |
| | | const sendForm = async () => { |
| | | loading.value = true; |
| | | try { |
| | | // é¢ç¨æ°éæ ¡éª |
| | | if (Array.isArray(form.sparePartsIds) && form.sparePartsIds.length > 0) { |
| | | for (const partId of form.sparePartsIds) { |
| | | const qty = Number(sparePartQtyMap.value?.[partId]); |
| | | if (!Number.isFinite(qty) || qty <= 0) { |
| | | proxy?.$modal?.msgError?.("请填åå¤ä»¶é¢ç¨æ°é"); |
| | | return; |
| | | } |
| | | const part = sparePartOptions.value.find((p) => String(p.id) === String(partId)); |
| | | const stock = part?.quantity; |
| | | if (stock !== null && stock !== undefined && Number.isFinite(Number(stock))) { |
| | | if (qty > Number(stock)) { |
| | | proxy?.$modal?.msgError?.(`å¤ä»¶ã${part?.name || ""}ãé¢ç¨æ°éä¸è½è¶
è¿åºåï¼${stock}ï¼`); |
| | | /** |
| | | * @desc ä¿åä¿å
» |
| | | */ |
| | | const sendForm = async () => { |
| | | loading.value = true; |
| | | try { |
| | | // é¢ç¨æ°éæ ¡éª |
| | | if (Array.isArray(form.sparePartsIds) && form.sparePartsIds.length > 0) { |
| | | for (const partId of form.sparePartsIds) { |
| | | const qty = Number(sparePartQtyMap.value?.[partId]); |
| | | if (!Number.isFinite(qty) || qty <= 0) { |
| | | proxy?.$modal?.msgError?.("请填åå¤ä»¶é¢ç¨æ°é"); |
| | | return; |
| | | } |
| | | const part = sparePartOptions.value.find( |
| | | p => String(p.id) === String(partId) |
| | | ); |
| | | const stock = part?.quantity; |
| | | if ( |
| | | stock !== null && |
| | | stock !== undefined && |
| | | Number.isFinite(Number(stock)) |
| | | ) { |
| | | if (qty > Number(stock)) { |
| | | proxy?.$modal?.msgError?.( |
| | | `å¤ä»¶ã${part?.name || ""}ãé¢ç¨æ°éä¸è½è¶
è¿åºåï¼${stock}ï¼` |
| | | ); |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | const data = { |
| | | id: planId.value, |
| | | ...form, |
| | | sparePartsIds: form.sparePartsIds ? form.sparePartsIds.join(",") : "", |
| | | sparePartsQty: form.sparePartsIds |
| | | ? form.sparePartsIds.map((id) => sparePartQtyMap.value?.[id] ?? 1).join(",") |
| | | const data = { |
| | | id: planId.value, |
| | | ...form, |
| | | sparePartsIds: form.sparePartsIds ? form.sparePartsIds.join(",") : "", |
| | | sparePartsQty: form.sparePartsIds |
| | | ? form.sparePartsIds |
| | | .map(id => sparePartQtyMap.value?.[id] ?? 1) |
| | | .join(",") |
| | | : "", |
| | | sparePartsUseList: form.sparePartsIds |
| | | ? form.sparePartsIds.map((id) => ({ id, quantity: sparePartQtyMap.value?.[id] ?? 1 })) |
| | | sparePartsUseList: form.sparePartsIds |
| | | ? form.sparePartsIds.map(id => ({ |
| | | id, |
| | | quantity: sparePartQtyMap.value?.[id] ?? 1, |
| | | })) |
| | | : [], |
| | | }; |
| | | const { code } = await addMaintenance(data); |
| | | if (code == 200) { |
| | | ElMessage.success("ä¿å
»æå"); |
| | | emits("ok"); |
| | | resetForm(); |
| | | sparePartQtyMap.value = {}; |
| | | visible.value = false; |
| | | } |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | const { code } = await addMaintenance(data); |
| | | if (code == 200) { |
| | | ElMessage.success("ä¿å
»æå"); |
| | | emits("ok"); |
| | | resetForm(); |
| | | sparePartQtyMap.value = {}; |
| | | visible.value = false; |
| | | } |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | }; |
| | | |
| | | const fetchSparePartOptions = () => { |
| | | loadingSparePartOptions.value = true; |
| | | // åå¤ä»¶ç®¡ç页ä¸è´ï¼/spareParts/listPage â res.data.records |
| | | getSparePartsList({ current: 1, size: 1000 }) |
| | | .then((res) => { |
| | | const fetchSparePartOptions = () => { |
| | | loadingSparePartOptions.value = true; |
| | | // åå¤ä»¶ç®¡ç页ä¸è´ï¼/spareParts/listPage â res.data.records |
| | | getSparePartsList({ current: 1, size: 1000 }) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | sparePartOptions.value = res?.data?.records || []; |
| | | } else { |
| | |
| | | .finally(() => { |
| | | loadingSparePartOptions.value = false; |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | const handleCancel = () => { |
| | | resetForm(); |
| | | sparePartQtyMap.value = {}; |
| | | visible.value = false; |
| | | }; |
| | | const handleCancel = () => { |
| | | resetForm(); |
| | | sparePartQtyMap.value = {}; |
| | | visible.value = false; |
| | | }; |
| | | |
| | | const handleClose = () => { |
| | | resetForm(); |
| | | sparePartQtyMap.value = {}; |
| | | visible.value = false; |
| | | }; |
| | | const handleClose = () => { |
| | | resetForm(); |
| | | sparePartQtyMap.value = {}; |
| | | visible.value = false; |
| | | }; |
| | | |
| | | const open = async (id, row) => { |
| | | planId.value = id; // ä¿å计åä¿å
»è®°å½çid |
| | | visible.value = true; |
| | | await nextTick(); |
| | | fetchSparePartOptions() |
| | | setForm(row); |
| | | }; |
| | | const open = async (id, row) => { |
| | | planId.value = id; // ä¿å计åä¿å
»è®°å½çid |
| | | visible.value = true; |
| | | await nextTick(); |
| | | fetchSparePartOptions(); |
| | | setForm(row); |
| | | }; |
| | | |
| | | defineExpose({ |
| | | open, |
| | | }); |
| | | defineExpose({ |
| | | open, |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |
| | |
| | | disabled |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="项ç®"> |
| | | <el-form-item label="ä¿å
»é¡¹ç®"> |
| | | <el-input |
| | | v-model="form.machineryCategory" |
| | | placeholder="请è¾å
¥é¡¹ç®" |
| | | placeholder="请è¾å
¥ä¿å
»é¡¹ç®" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="å½å
¥äºº"> |
| | |
| | | <el-option label="å®ç»" :value="1"></el-option> |
| | | <el-option label="失败" :value="2"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="ä¿å
»äºº"> |
| | | <el-input |
| | | v-model="form.maintenancePerson" |
| | | placeholder="请è¾å
¥ä¿å
»äººå§å" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="计åä¿å
»æ¥æ"> |
| | | <el-date-picker |
| | |
| | | status: 0, //ä¿ä¿®ç¶æ |
| | | machineryCategory: undefined, |
| | | storageBlobDTOs: [], |
| | | maintenancePerson: undefined, // ä¿å
»äºº |
| | | }); |
| | | |
| | | const setDeviceModel = (deviceId) => { |
| | |
| | | form.createUser = Number(data.createUser); |
| | | form.status = data.status; |
| | | form.machineryCategory = data.machineryCategory; |
| | | form.maintenancePerson = data.maintenancePerson; |
| | | if (data.maintenancePlanTime) { |
| | | form.maintenancePlanTime = dayjs(data.maintenancePlanTime).format( |
| | | "YYYY-MM-DD HH:mm:ss" |
| | |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¿å
»é¡¹ç®" prop="machineryCategory"> |
| | | <el-input |
| | | v-model.trim="form.machineryCategory" |
| | | placeholder="请è¾å
¥ä¿å
»é¡¹ç®" |
| | | maxlength="100" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¿å
»äºº" prop="maintenancePerson"> |
| | | <el-input |
| | | v-model.trim="form.maintenancePerson" |
| | | placeholder="请è¾å
¥ä¿å
»äººå§å" |
| | | maxlength="100" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä»»å¡é¢ç" prop="frequencyType"> |
| | | <el-select v-model="form.frequencyType" placeholder="è¯·éæ©" clearable> |
| | | <el-option label="æ¯æ¥" value="DAILY"/> |
| | |
| | | taskName: undefined, |
| | | // å½å
¥äººï¼åéä¸ä¸ªç¨æ· id |
| | | inspector: undefined, |
| | | machineryCategory: "", |
| | | remarks: '', |
| | | frequencyType: '', |
| | | frequencyDetail: '', |
| | | week: '', |
| | | time: '', |
| | | deviceModel: undefined, // è§æ ¼åå· |
| | | registrationDate: '' |
| | | registrationDate: '', |
| | | maintenancePerson: '' // ä¿å
»äºº |
| | | }, |
| | | rules: { |
| | | taskId: [{ required: true, message: "è¯·éæ©è®¾å¤", trigger: "change" },], |
| | | inspector: [{ required: true, message: "è¯·éæ©å½å
¥äºº", trigger: "blur" },], |
| | | registrationDate: [{ required: true, message: "è¯·éæ©ç»è®°æ¶é´", trigger: "change" }] |
| | | registrationDate: [{ required: true, message: "è¯·éæ©ç»è®°æ¶é´", trigger: "change" }], |
| | | machineryCategory: [{ required: true, message: "请è¾å
¥ä¿å
»é¡¹ç®", trigger: "blur" }] |
| | | } |
| | | }) |
| | | const { form, rules } = toRefs(data) |
| | |
| | | taskId: undefined, |
| | | taskName: undefined, |
| | | inspector: undefined, |
| | | inspector: undefined, |
| | | machineryCategory: "", |
| | | remarks: '', |
| | | frequencyType: '', |
| | | frequencyDetail: '', |
| | | week: '', |
| | | time: '', |
| | | deviceModel: undefined, |
| | | registrationDate: '' |
| | | registrationDate: '', |
| | | maintenancePerson: '' |
| | | } |
| | | } |
| | | |
| | |
| | | <div class="app-container"> |
| | | <el-tabs v-model="activeTab" |
| | | @tab-change="handleTabChange"> |
| | | <!-- 宿¶ä»»å¡ç®¡çtab --> |
| | | <el-tab-pane label="宿¶ä»»å¡ç®¡ç" |
| | | <!-- ä¿å
»ä»»å¡tab --> |
| | | <el-tab-pane label="ä¿å
»ä»»å¡" |
| | | name="scheduled"> |
| | | <div class="search_form"> |
| | | <el-form :model="scheduledFilters" |
| | |
| | | <div class="table_list"> |
| | | <div class="actions"> |
| | | <el-text class="mx-1" |
| | | size="large">宿¶ä»»å¡ç®¡ç</el-text> |
| | | size="large">ä¿å
»ä»»å¡</el-text> |
| | | <div> |
| | | <el-button type="primary" |
| | | icon="Plus" |
| | |
| | | </PIMTable> |
| | | </div> |
| | | </el-tab-pane> |
| | | <!-- ä»»å¡è®°å½tabï¼å设å¤ä¿å
»é¡µé¢ï¼ --> |
| | | <el-tab-pane label="ä»»å¡è®°å½" |
| | | <!-- ä¿å
»è®°å½tabï¼å设å¤ä¿å
»é¡µé¢ï¼ --> |
| | | <el-tab-pane label="ä¿å
»è®°å½" |
| | | name="record"> |
| | | <div class="search_form"> |
| | | <el-form :model="filters" |
| | |
| | | <div class="table_list"> |
| | | <div class="actions"> |
| | | <el-text class="mx-1" |
| | | size="large">ä»»å¡è®°å½</el-text> |
| | | size="large">ä¿å
»è®°å½</el-text> |
| | | <div> |
| | | <el-button type="success" |
| | | icon="Van" |
| | |
| | | const fileDialogVisible = ref(false); |
| | | const currentMaintenanceTaskId = ref(null); |
| | | |
| | | // ä»»å¡è®°å½tabï¼å设å¤ä¿å
»é¡µé¢ï¼ç¸å
³åé |
| | | // ä¿å
»è®°å½tabï¼å设å¤ä¿å
»é¡µé¢ï¼ç¸å
³åé |
| | | const filters = reactive({ |
| | | deviceName: "", |
| | | maintenancePlanTime: "", |
| | |
| | | }); |
| | | const multipleList = ref([]); |
| | | |
| | | // 宿¶ä»»å¡ç®¡çtabç¸å
³åé |
| | | // ä¿å
»ä»»å¡tabç¸å
³åé |
| | | const scheduledFilters = reactive({ |
| | | taskName: "", |
| | | status: "", |
| | |
| | | }); |
| | | const scheduledMultipleList = ref([]); |
| | | |
| | | // 宿¶ä»»å¡ç®¡çè¡¨æ ¼åé
ç½® |
| | | // ä¿å
»ä»»å¡è¡¨æ ¼åé
ç½® |
| | | const scheduledColumns = ref([ |
| | | { prop: "taskName", label: "设å¤åç§°" }, |
| | | { |
| | | label: "è§æ ¼åå·", |
| | | prop: "deviceModel", |
| | | }, |
| | | { |
| | | label: "ä¿å
»é¡¹ç®", |
| | | prop: "machineryCategory", |
| | | minWidth: 120, |
| | | formatData: cell => cell || "--", |
| | | }, |
| | | { |
| | | prop: "frequencyType", |
| | |
| | | ); |
| | | }, |
| | | }, |
| | | { prop: "maintenancePerson", label: "ä¿å
»äºº", minWidth: 100 }, |
| | | { prop: "registrant", label: "ç»è®°äºº", minWidth: 100 }, |
| | | { prop: "registrationDate", label: "ç»è®°æ¥æ", minWidth: 100 }, |
| | | { |
| | |
| | | }, |
| | | ]); |
| | | |
| | | // ä»»å¡è®°å½è¡¨æ ¼åé
ç½®ï¼å设å¤ä¿å
»è¡¨æ ¼åï¼ |
| | | // ä¿å
»è®°å½è¡¨æ ¼åé
ç½®ï¼å设å¤ä¿å
»è¡¨æ ¼åï¼ |
| | | const columns = ref([ |
| | | { |
| | | label: "设å¤åç§°", |
| | |
| | | label: "计åä¿å
»æ¥æ", |
| | | align: "center", |
| | | prop: "maintenancePlanTime", |
| | | formatData: cell => dayjs(cell).format("YYYY-MM-DD"), |
| | | formatData: cell => { |
| | | return cell == null ? "-" : dayjs(cell).format("YYYY-MM-DD"); |
| | | }, |
| | | }, |
| | | { |
| | | label: "å½å
¥äºº", |
| | |
| | | prop: "createUserName", |
| | | }, |
| | | { |
| | | label: "项ç®", |
| | | label: "ä¿å
»é¡¹ç®", |
| | | align: "center", |
| | | prop: "machineryCategory", |
| | | formatData: cell => cell || "--", |
| | | }, |
| | | // { |
| | | // label: "å½å
¥æ¥æ", |
| | |
| | | } |
| | | }; |
| | | |
| | | // 宿¶ä»»å¡ç®¡çç¸å
³æ¹æ³ |
| | | // ä¿å
»ä»»å¡ç¸å
³æ¹æ³ |
| | | const getScheduledTableData = async () => { |
| | | try { |
| | | const params = { |
| | |
| | | ElMessage.info("导åºå®æ¶ä»»å¡åè½å¾
å®ç°"); |
| | | }; |
| | | |
| | | // ä»»å¡è®°å½ç¸å
³æ¹æ³ï¼å设å¤ä¿å
»é¡µé¢æ¹æ³ï¼ |
| | | // ä¿å
»è®°å½ç¸å
³æ¹æ³ï¼å设å¤ä¿å
»é¡µé¢æ¹æ³ï¼ |
| | | const getTableData = async () => { |
| | | try { |
| | | const params = { |
| | |
| | | <div> |
| | | <el-button type="primary" @click="add" icon="Plus">æ°å¢èµäº§</el-button> |
| | | <el-button type="warning" @click="handleDepreciation" icon="Money">ææ§è®¡æ</el-button> |
| | | <el-button @click="handleOut" icon="Download">导åº</el-button> |
| | | <!-- <el-button @click="handleOut" icon="Download">导åº</el-button> --> |
| | | </div> |
| | | </div> |
| | | <PIMTable |
| | | rowKey="id" |
| | | isSelection |
| | | :column="columns" |
| | | :tableData="dataList" |
| | | :page="{ |
| | |
| | | size: pagination.pageSize, |
| | | total: pagination.total, |
| | | }" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="changePage" |
| | | > |
| | | <template #originalValue="{ row }"> |
| | |
| | | </div> |
| | | |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="120px"> |
| | | <el-form :model="form" :rules="rules" :disabled="isView" ref="formRef" label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="èµäº§ç¼å·" prop="assetCode"> |
| | |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button v-if="!isView" type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </FormDialog> |
| | |
| | | import { ref, reactive, onMounted, computed } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { |
| | | listFixedAssetPage, |
| | | addFixedAsset, |
| | | updateFixedAsset, |
| | | deleteFixedAsset, |
| | | depreciateFixedAsset, |
| | | } from "@/api/financialManagement/fixedAsset"; |
| | | |
| | | defineOptions({ |
| | | name: "åºå®èµäº§", |
| | |
| | | const columns = [ |
| | | { label: "èµäº§ç¼å·", prop: "assetCode", width: "130" }, |
| | | { label: "èµäº§åç§°", prop: "assetName", width: "150" }, |
| | | { label: "èµäº§ç±»å«", prop: "category", slot: "category" }, |
| | | { label: "èµäº§ç±»å«", prop: "category", dataType: "slot", slot: "category" }, |
| | | { label: "è§æ ¼åå·", prop: "specification", width: "120" }, |
| | | { label: "èµäº§åå¼", prop: "originalValue", slot: "originalValue" }, |
| | | { label: "ç´¯è®¡ææ§", prop: "accumulatedDepreciation", slot: "accumulatedDepreciation" }, |
| | | { label: "èµäº§åå¼", prop: "netValue", slot: "netValue" }, |
| | | { label: "ç¶æ", prop: "status", slot: "status" }, |
| | | { label: "æä½", prop: "operation", slot: "operation", width: "180", fixed: "right" }, |
| | | { label: "èµäº§åå¼", prop: "originalValue", dataType: "slot", slot: "originalValue" }, |
| | | { label: "ç´¯è®¡ææ§", prop: "accumulatedDepreciation", dataType: "slot", slot: "accumulatedDepreciation" }, |
| | | { label: "èµäº§åå¼", prop: "netValue", dataType: "slot", slot: "netValue" }, |
| | | { label: "ç¶æ", prop: "status", dataType: "slot", slot: "status" }, |
| | | { label: "æä½", prop: "operation", dataType: "slot", slot: "operation", width: "180", fixed: "right" }, |
| | | ]; |
| | | |
| | | const dataList = ref([]); |
| | | const multipleList = ref([]); |
| | | const dialogVisible = ref(false); |
| | | const dialogTitle = ref(""); |
| | | const formRef = ref(null); |
| | | const isEdit = ref(false); |
| | | const isView = ref(false); |
| | | const currentId = ref(null); |
| | | const selectedIds = computed(() => |
| | | multipleList.value |
| | | .map(item => item?.id) |
| | | .filter(id => id !== undefined && id !== null && id !== "") |
| | | ); |
| | | |
| | | const form = reactive({ |
| | | const createDefaultForm = () => ({ |
| | | assetCode: "", |
| | | assetName: "", |
| | | category: "", |
| | |
| | | remark: "", |
| | | }); |
| | | |
| | | const form = reactive({ |
| | | ...createDefaultForm(), |
| | | }); |
| | | |
| | | const rules = { |
| | | assetName: [{ required: true, message: "请è¾å
¥èµäº§åç§°", trigger: "blur" }], |
| | | category: [{ required: true, message: "è¯·éæ©èµäº§ç±»å«", trigger: "change" }], |
| | |
| | | originalValue: [{ required: true, message: "请è¾å
¥èµäº§åå¼", trigger: "blur" }], |
| | | usefulLife: [{ required: true, message: "请è¾å
¥ä½¿ç¨å¹´é", trigger: "blur" }], |
| | | }; |
| | | |
| | | const mockData = [ |
| | | { id: 1, assetCode: "GD2024001", assetName: "åå
¬çµè", category: "electronic", specification: "èæ³ThinkPad X1", purchaseDate: "2023-01-15", originalValue: 8000, usefulLife: 5, residualRate: 5, accumulatedDepreciation: 1520, netValue: 6480, location: "åå
¬å®¤", department: "è´¢å¡é¨", keeper: "å¼ ä¸", status: "in_use", remark: "" }, |
| | | { id: 2, assetCode: "GD2024002", assetName: "æå°æº", category: "electronic", specification: "æ æ®M479fdw", purchaseDate: "2023-03-20", originalValue: 3500, usefulLife: 5, residualRate: 5, accumulatedDepreciation: 532, netValue: 2968, location: "æå°å®¤", department: "è¡æ¿é¨", keeper: "æå", status: "in_use", remark: "" }, |
| | | { id: 3, assetCode: "GD2024003", assetName: "åå
¬æ¡æ¤
", category: "furniture", specification: "宿¨åå
¬æ¡", purchaseDate: "2023-06-10", originalValue: 2500, usefulLife: 10, residualRate: 5, accumulatedDepreciation: 118.75, netValue: 2381.25, location: "åå
¬å®¤", department: "éå®é¨", keeper: "çäº", status: "in_use", remark: "" }, |
| | | { id: 4, assetCode: "GD2024004", assetName: "åå¡è½¦", category: "vehicle", specification: "å«å
GL8", purchaseDate: "2022-08-01", originalValue: 280000, usefulLife: 10, residualRate: 5, accumulatedDepreciation: 53200, netValue: 226800, location: "å车åº", department: "è¡æ¿é¨", keeper: "èµµå
", status: "in_use", remark: "" }, |
| | | ]; |
| | | |
| | | const totalOriginalValue = computed(() => { |
| | | return dataList.value.reduce((sum, item) => sum + Number(item.originalValue), 0); |
| | |
| | | }; |
| | | |
| | | const getStatusLabel = (status) => { |
| | | const map = { in_use: "å¨ç¨", idle: "é²ç½®", scrapped: "æ¥åº" }; |
| | | return map[status] || status; |
| | | const key = String(status || "").toLowerCase(); |
| | | const map = { in_use: "å¨ç¨", idle: "é²ç½®", repair: "ç»´ä¿®ä¸", scrapped: "æ¥åº" }; |
| | | return map[key] || status; |
| | | }; |
| | | |
| | | const getStatusType = (status) => { |
| | | const map = { in_use: "success", idle: "warning", scrapped: "info" }; |
| | | return map[status] || ""; |
| | | const key = String(status || "").toLowerCase(); |
| | | const map = { in_use: "success", idle: "warning", repair: "warning", scrapped: "info" }; |
| | | return map[key] || ""; |
| | | }; |
| | | |
| | | const calculateNetValue = () => { |
| | | form.netValue = Number((form.originalValue - form.accumulatedDepreciation).toFixed(2)); |
| | | const originalValue = Number(form.originalValue || 0); |
| | | const accumulatedDepreciation = Number(form.accumulatedDepreciation || 0); |
| | | form.netValue = Number((originalValue - accumulatedDepreciation).toFixed(2)); |
| | | }; |
| | | |
| | | const getTableData = () => { |
| | | let result = [...mockData]; |
| | | if (filters.assetCode) { |
| | | result = result.filter(item => item.assetCode.includes(filters.assetCode)); |
| | | // èè°çº¦å®ï¼å页忰åºå®ä¸º current/sizeï¼è¿å data.records/data.total |
| | | const getTableData = async () => { |
| | | try { |
| | | const { data } = await listFixedAssetPage({ |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | assetCode: filters.assetCode, |
| | | assetName: filters.assetName, |
| | | category: filters.category, |
| | | status: filters.status, |
| | | }); |
| | | dataList.value = data?.records || []; |
| | | multipleList.value = []; |
| | | pagination.total = Number(data?.total || 0); |
| | | } catch (error) { |
| | | // æç¤ºç±å
¨å±è¯·æ±æ¦æªå¨å¤çï¼è¿éä»
鲿¢æªæè·å¼å¸¸ |
| | | } |
| | | if (filters.assetName) { |
| | | result = result.filter(item => item.assetName.includes(filters.assetName)); |
| | | } |
| | | if (filters.category) { |
| | | result = result.filter(item => item.category === filters.category); |
| | | } |
| | | if (filters.status) { |
| | | result = result.filter(item => item.status === filters.status); |
| | | } |
| | | pagination.total = result.length; |
| | | dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize); |
| | | }; |
| | | |
| | | const handleSelectionChange = (selectionList) => { |
| | | multipleList.value = selectionList; |
| | | }; |
| | | |
| | | const resetFilters = () => { |
| | |
| | | getTableData(); |
| | | }; |
| | | |
| | | const buildAssetCode = () => `GD${Date.now().toString().slice(-10)}`; |
| | | |
| | | const add = () => { |
| | | isEdit.value = false; |
| | | isView.value = false; |
| | | currentId.value = null; |
| | | dialogTitle.value = "æ°å¢åºå®èµäº§"; |
| | | Object.assign(form, { |
| | | assetCode: "GD" + Date.now().toString().slice(-8), |
| | | assetName: "", |
| | | category: "", |
| | | specification: "", |
| | | Object.assign(form, createDefaultForm(), { |
| | | assetCode: buildAssetCode(), |
| | | purchaseDate: new Date().toISOString().split('T')[0], |
| | | originalValue: 0, |
| | | usefulLife: 5, |
| | | residualRate: 5, |
| | | accumulatedDepreciation: 0, |
| | | netValue: 0, |
| | | location: "", |
| | | department: "", |
| | | keeper: "", |
| | | status: "in_use", |
| | | remark: "", |
| | | }); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const edit = (row) => { |
| | | isEdit.value = true; |
| | | isView.value = false; |
| | | currentId.value = row.id; |
| | | dialogTitle.value = "ç¼è¾åºå®èµäº§"; |
| | | Object.assign(form, row); |
| | | Object.assign(form, createDefaultForm(), row); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const view = (row) => { |
| | | ElMessage.info(`æ¥çèµäº§: ${row.assetName}`); |
| | | edit(row); |
| | | isView.value = true; |
| | | }; |
| | | |
| | | const handleDelete = (row) => { |
| | |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }).then(() => { |
| | | const index = mockData.findIndex(item => item.id === row.id); |
| | | if (index !== -1) { |
| | | mockData.splice(index, 1); |
| | | }).then(async () => { |
| | | // èè°çº¦å®ï¼å 餿¥å£ä½¿ç¨ ids=1&ids=2 |
| | | await deleteFixedAsset([row.id]); |
| | | if (dataList.value.length === 1 && pagination.currentPage > 1) { |
| | | pagination.currentPage -= 1; |
| | | } |
| | | ElMessage.success("å 餿å"); |
| | | getTableData(); |
| | | await getTableData(); |
| | | }); |
| | | }; |
| | | |
| | | const handleDepreciation = () => { |
| | | ElMessageBox.confirm("确认è¿è¡æ¬æææ§è®¡æåï¼", "æç¤º", { |
| | | const ids = selectedIds.value; |
| | | const confirmText = ids.length |
| | | ? `确认对éä¸ç ${ids.length} æ¡èµäº§è¿è¡æ¬æææ§è®¡æåï¼` |
| | | : "确认è¿è¡æ¬æææ§è®¡æåï¼"; |
| | | ElMessageBox.confirm(confirmText, "æç¤º", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "info", |
| | | }).then(() => { |
| | | mockData.forEach(item => { |
| | | if (item.status === "in_use") { |
| | | const monthlyDepreciation = (item.originalValue * (1 - item.residualRate / 100)) / (item.usefulLife * 12); |
| | | item.accumulatedDepreciation = Number((item.accumulatedDepreciation + monthlyDepreciation).toFixed(2)); |
| | | item.netValue = Number((item.originalValue - item.accumulatedDepreciation).toFixed(2)); |
| | | } |
| | | }); |
| | | }).then(async () => { |
| | | await depreciateFixedAsset({ ids }); |
| | | ElMessage.success("ææ§è®¡æå®æ"); |
| | | getTableData(); |
| | | await getTableData(); |
| | | }); |
| | | }; |
| | | |
| | |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | formRef.value.validate((valid) => { |
| | | if (isView.value) { |
| | | dialogVisible.value = false; |
| | | return; |
| | | } |
| | | formRef.value.validate(async valid => { |
| | | if (valid) { |
| | | calculateNetValue(); |
| | | if (isEdit.value) { |
| | | const index = mockData.findIndex(item => item.id === currentId.value); |
| | | if (index !== -1) { |
| | | mockData[index] = { ...mockData[index], ...form }; |
| | | try { |
| | | calculateNetValue(); |
| | | const payload = { ...form }; |
| | | if (isEdit.value) { |
| | | payload.id = currentId.value; |
| | | await updateFixedAsset(payload); |
| | | ElMessage.success("ç¼è¾æå"); |
| | | } else { |
| | | await addFixedAsset(payload); |
| | | ElMessage.success("æ°å¢æå"); |
| | | } |
| | | ElMessage.success("ç¼è¾æå"); |
| | | } else { |
| | | const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1; |
| | | mockData.push({ id: newId, ...form }); |
| | | ElMessage.success("æ°å¢æå"); |
| | | dialogVisible.value = false; |
| | | await getTableData(); |
| | | } catch (error) { |
| | | // æç¤ºç±å
¨å±è¯·æ±æ¦æªå¨å¤çï¼è¿éä»
鲿¢æªæè·å¼å¸¸ |
| | | } |
| | | dialogVisible.value = false; |
| | | getTableData(); |
| | | } |
| | | }); |
| | | }; |
| | |
| | | <div> |
| | | <el-button type="primary" @click="add" icon="Plus">æ°å¢èµäº§</el-button> |
| | | <el-button type="warning" @click="handleAmortization" icon="Money">æé计æ</el-button> |
| | | <el-button @click="handleOut" icon="Download">导åº</el-button> |
| | | <!-- <el-button @click="handleOut" icon="Download">导åº</el-button> --> |
| | | </div> |
| | | </div> |
| | | <PIMTable |
| | | rowKey="id" |
| | | isSelection |
| | | :column="columns" |
| | | :tableData="dataList" |
| | | :page="{ |
| | |
| | | size: pagination.pageSize, |
| | | total: pagination.total, |
| | | }" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="changePage" |
| | | > |
| | | <template #originalValue="{ row }"> |
| | |
| | | </div> |
| | | |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="120px"> |
| | | <el-form :model="form" :rules="rules" :disabled="isView" ref="formRef" label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="èµäº§ç¼å·" prop="assetCode"> |
| | |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button v-if="!isView" type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </FormDialog> |
| | |
| | | import { ref, reactive, onMounted, computed } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { |
| | | listIntangibleAssetPage, |
| | | addIntangibleAsset, |
| | | updateIntangibleAsset, |
| | | deleteIntangibleAsset, |
| | | amortizeIntangibleAsset, |
| | | } from "@/api/financialManagement/intangibleAsset"; |
| | | |
| | | defineOptions({ |
| | | name: "æ å½¢èµäº§", |
| | |
| | | const columns = [ |
| | | { label: "èµäº§ç¼å·", prop: "assetCode", width: "130" }, |
| | | { label: "èµäº§åç§°", prop: "assetName", width: "150" }, |
| | | { label: "èµäº§ç±»å«", prop: "category", slot: "category" }, |
| | | { label: "èµäº§ç±»å«", prop: "category", dataType: "slot", slot: "category" }, |
| | | { label: "è¯ä¹¦ç¼å·", prop: "certificateNo", width: "150" }, |
| | | { label: "èµäº§åå¼", prop: "originalValue", slot: "originalValue" }, |
| | | { label: "累计æé", prop: "accumulatedAmortization", slot: "accumulatedAmortization" }, |
| | | { label: "èµäº§åå¼", prop: "netValue", slot: "netValue" }, |
| | | { label: "ç¶æ", prop: "status", slot: "status" }, |
| | | { label: "æä½", prop: "operation", slot: "operation", width: "180", fixed: "right" }, |
| | | { label: "èµäº§åå¼", prop: "originalValue", dataType: "slot", slot: "originalValue" }, |
| | | { label: "累计æé", prop: "accumulatedAmortization", dataType: "slot", slot: "accumulatedAmortization" }, |
| | | { label: "èµäº§åå¼", prop: "netValue", dataType: "slot", slot: "netValue" }, |
| | | { label: "ç¶æ", prop: "status", dataType: "slot", slot: "status" }, |
| | | { label: "æä½", prop: "operation", dataType: "slot", slot: "operation", width: "180", fixed: "right" }, |
| | | ]; |
| | | |
| | | const dataList = ref([]); |
| | | const multipleList = ref([]); |
| | | const dialogVisible = ref(false); |
| | | const dialogTitle = ref(""); |
| | | const formRef = ref(null); |
| | | const isEdit = ref(false); |
| | | const isView = ref(false); |
| | | const currentId = ref(null); |
| | | const selectedIds = computed(() => |
| | | multipleList.value |
| | | .map(item => item?.id) |
| | | .filter(id => id !== undefined && id !== null && id !== "") |
| | | ); |
| | | |
| | | const form = reactive({ |
| | | const createDefaultForm = () => ({ |
| | | assetCode: "", |
| | | assetName: "", |
| | | category: "", |
| | |
| | | remark: "", |
| | | }); |
| | | |
| | | const form = reactive({ |
| | | ...createDefaultForm(), |
| | | }); |
| | | |
| | | const rules = { |
| | | assetName: [{ required: true, message: "请è¾å
¥èµäº§åç§°", trigger: "blur" }], |
| | | category: [{ required: true, message: "è¯·éæ©èµäº§ç±»å«", trigger: "change" }], |
| | |
| | | originalValue: [{ required: true, message: "请è¾å
¥èµäº§åå¼", trigger: "blur" }], |
| | | amortizationPeriod: [{ required: true, message: "请è¾å
¥æéå¹´é", trigger: "blur" }], |
| | | }; |
| | | |
| | | const mockData = [ |
| | | { id: 1, assetCode: "WX2024001", assetName: "ERP软件许å¯", category: "software", certificateNo: "SW-2023-001", acquisitionDate: "2023-01-01", originalValue: 50000, amortizationPeriod: 10, residualRate: 0, accumulatedAmortization: 5000, netValue: 45000, validityDate: "2033-01-01", status: "in_use", description: "ä¼ä¸èµæºè®¡å管çç³»ç»", remark: "" }, |
| | | { id: 2, assetCode: "WX2024002", assetName: "åæä¸å©", category: "patent", certificateNo: "ZL202210123456.7", acquisitionDate: "2022-06-15", originalValue: 100000, amortizationPeriod: 20, residualRate: 0, accumulatedAmortization: 3750, netValue: 96250, validityDate: "2042-06-15", status: "in_use", description: "ä¸ç§æ°åç产工èº", remark: "" }, |
| | | { id: 3, assetCode: "WX2024003", assetName: "åæ æ", category: "trademark", certificateNo: "TM-2023-008", acquisitionDate: "2023-03-10", originalValue: 20000, amortizationPeriod: 10, residualRate: 0, accumulatedAmortization: 1500, netValue: 18500, validityDate: "2033-03-10", status: "in_use", description: "å
¬å¸åçåæ ", remark: "" }, |
| | | { id: 4, assetCode: "WX2024004", assetName: "åå°ä½¿ç¨æ", category: "land", certificateNo: "åå½ç¨(2023)第001å·", acquisitionDate: "2023-07-01", originalValue: 500000, amortizationPeriod: 50, residualRate: 0, accumulatedAmortization: 5000, netValue: 495000, validityDate: "2073-07-01", status: "in_use", description: "å·¥ä¸ç¨å°ä½¿ç¨æ", remark: "" }, |
| | | ]; |
| | | |
| | | const totalOriginalValue = computed(() => { |
| | | return dataList.value.reduce((sum, item) => sum + Number(item.originalValue), 0); |
| | |
| | | }; |
| | | |
| | | const getStatusLabel = (status) => { |
| | | const map = { in_use: "å¨ç¨", idle: "é²ç½®", amortized: "å·²æé宿¯" }; |
| | | return map[status] || status; |
| | | const key = String(status || "").toLowerCase(); |
| | | const map = { |
| | | in_use: "å¨ç¨", |
| | | idle: "é²ç½®", |
| | | expired: "已尿", |
| | | amortized: "å·²æé宿¯", |
| | | }; |
| | | return map[key] || status; |
| | | }; |
| | | |
| | | const getStatusType = (status) => { |
| | | const map = { in_use: "success", idle: "warning", amortized: "info" }; |
| | | return map[status] || ""; |
| | | const key = String(status || "").toLowerCase(); |
| | | const map = { in_use: "success", idle: "warning", expired: "warning", amortized: "info" }; |
| | | return map[key] || ""; |
| | | }; |
| | | |
| | | const calculateNetValue = () => { |
| | | form.netValue = Number((form.originalValue - form.accumulatedAmortization).toFixed(2)); |
| | | const originalValue = Number(form.originalValue || 0); |
| | | const accumulatedAmortization = Number(form.accumulatedAmortization || 0); |
| | | form.netValue = Number((originalValue - accumulatedAmortization).toFixed(2)); |
| | | }; |
| | | |
| | | const getTableData = () => { |
| | | let result = [...mockData]; |
| | | if (filters.assetCode) { |
| | | result = result.filter(item => item.assetCode.includes(filters.assetCode)); |
| | | // èè°çº¦å®ï¼å页忰åºå®ä¸º current/sizeï¼è¿å data.records/data.total |
| | | const getTableData = async () => { |
| | | try { |
| | | const { data } = await listIntangibleAssetPage({ |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | assetCode: filters.assetCode, |
| | | assetName: filters.assetName, |
| | | category: filters.category, |
| | | status: filters.status, |
| | | }); |
| | | dataList.value = data?.records || []; |
| | | multipleList.value = []; |
| | | pagination.total = Number(data?.total || 0); |
| | | } catch (error) { |
| | | // æç¤ºç±å
¨å±è¯·æ±æ¦æªå¨å¤çï¼è¿éä»
鲿¢æªæè·å¼å¸¸ |
| | | } |
| | | if (filters.assetName) { |
| | | result = result.filter(item => item.assetName.includes(filters.assetName)); |
| | | } |
| | | if (filters.category) { |
| | | result = result.filter(item => item.category === filters.category); |
| | | } |
| | | if (filters.status) { |
| | | result = result.filter(item => item.status === filters.status); |
| | | } |
| | | pagination.total = result.length; |
| | | dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize); |
| | | }; |
| | | |
| | | const handleSelectionChange = (selectionList) => { |
| | | multipleList.value = selectionList; |
| | | }; |
| | | |
| | | const resetFilters = () => { |
| | |
| | | getTableData(); |
| | | }; |
| | | |
| | | const buildAssetCode = () => `WX${Date.now().toString().slice(-10)}`; |
| | | |
| | | const add = () => { |
| | | isEdit.value = false; |
| | | isView.value = false; |
| | | currentId.value = null; |
| | | dialogTitle.value = "æ°å¢æ å½¢èµäº§"; |
| | | Object.assign(form, { |
| | | assetCode: "WX" + Date.now().toString().slice(-8), |
| | | assetName: "", |
| | | category: "", |
| | | certificateNo: "", |
| | | Object.assign(form, createDefaultForm(), { |
| | | assetCode: buildAssetCode(), |
| | | acquisitionDate: new Date().toISOString().split('T')[0], |
| | | originalValue: 0, |
| | | amortizationPeriod: 10, |
| | | residualRate: 0, |
| | | accumulatedAmortization: 0, |
| | | netValue: 0, |
| | | validityDate: "", |
| | | status: "in_use", |
| | | description: "", |
| | | remark: "", |
| | | }); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const edit = (row) => { |
| | | isEdit.value = true; |
| | | isView.value = false; |
| | | currentId.value = row.id; |
| | | dialogTitle.value = "ç¼è¾æ å½¢èµäº§"; |
| | | Object.assign(form, row); |
| | | Object.assign(form, createDefaultForm(), row); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const view = (row) => { |
| | | ElMessage.info(`æ¥çèµäº§: ${row.assetName}`); |
| | | edit(row); |
| | | isView.value = true; |
| | | }; |
| | | |
| | | const handleDelete = (row) => { |
| | |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }).then(() => { |
| | | const index = mockData.findIndex(item => item.id === row.id); |
| | | if (index !== -1) { |
| | | mockData.splice(index, 1); |
| | | }).then(async () => { |
| | | // èè°çº¦å®ï¼å 餿¥å£ä½¿ç¨ ids=1&ids=2 |
| | | await deleteIntangibleAsset([row.id]); |
| | | if (dataList.value.length === 1 && pagination.currentPage > 1) { |
| | | pagination.currentPage -= 1; |
| | | } |
| | | ElMessage.success("å 餿å"); |
| | | getTableData(); |
| | | await getTableData(); |
| | | }); |
| | | }; |
| | | |
| | | const handleAmortization = () => { |
| | | ElMessageBox.confirm("确认è¿è¡æ¬ææé计æåï¼", "æç¤º", { |
| | | const ids = selectedIds.value; |
| | | const confirmText = ids.length |
| | | ? `确认对éä¸ç ${ids.length} æ¡èµäº§è¿è¡æ¬ææé计æåï¼` |
| | | : "确认è¿è¡æ¬ææé计æåï¼"; |
| | | ElMessageBox.confirm(confirmText, "æç¤º", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "info", |
| | | }).then(() => { |
| | | mockData.forEach(item => { |
| | | if (item.status === "in_use") { |
| | | const monthlyAmortization = (item.originalValue * (1 - item.residualRate / 100)) / (item.amortizationPeriod * 12); |
| | | item.accumulatedAmortization = Number((item.accumulatedAmortization + monthlyAmortization).toFixed(2)); |
| | | item.netValue = Number((item.originalValue - item.accumulatedAmortization).toFixed(2)); |
| | | if (item.netValue <= 0) { |
| | | item.status = "amortized"; |
| | | item.netValue = 0; |
| | | } |
| | | } |
| | | }); |
| | | }).then(async () => { |
| | | await amortizeIntangibleAsset({ ids }); |
| | | ElMessage.success("æé计æå®æ"); |
| | | getTableData(); |
| | | await getTableData(); |
| | | }); |
| | | }; |
| | | |
| | |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | formRef.value.validate((valid) => { |
| | | if (isView.value) { |
| | | dialogVisible.value = false; |
| | | return; |
| | | } |
| | | formRef.value.validate(async valid => { |
| | | if (valid) { |
| | | calculateNetValue(); |
| | | if (isEdit.value) { |
| | | const index = mockData.findIndex(item => item.id === currentId.value); |
| | | if (index !== -1) { |
| | | mockData[index] = { ...mockData[index], ...form }; |
| | | try { |
| | | calculateNetValue(); |
| | | const payload = { ...form }; |
| | | if (isEdit.value) { |
| | | payload.id = currentId.value; |
| | | await updateIntangibleAsset(payload); |
| | | ElMessage.success("ç¼è¾æå"); |
| | | } else { |
| | | await addIntangibleAsset(payload); |
| | | ElMessage.success("æ°å¢æå"); |
| | | } |
| | | ElMessage.success("ç¼è¾æå"); |
| | | } else { |
| | | const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1; |
| | | mockData.push({ id: newId, ...form }); |
| | | ElMessage.success("æ°å¢æå"); |
| | | dialogVisible.value = false; |
| | | await getTableData(); |
| | | } catch (error) { |
| | | // æç¤ºç±å
¨å±è¯·æ±æ¦æªå¨å¤çï¼è¿éä»
鲿¢æªæè·å¼å¸¸ |
| | | } |
| | | dialogVisible.value = false; |
| | | getTableData(); |
| | | } |
| | | }); |
| | | }; |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-form :model="filters" :inline="true"> |
| | | <el-form :model="filters" |
| | | :inline="true"> |
| | | <el-form-item label="ç§ç®ç¼ç :"> |
| | | <el-input v-model="filters.subjectCode" placeholder="请è¾å
¥ç§ç®ç¼ç " clearable style="width: 200px;" /> |
| | | <el-input v-model="filters.subjectCode" |
| | | placeholder="请è¾å
¥ç§ç®ç¼ç " |
| | | clearable |
| | | style="width: 200px;" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç§ç®åç§°:"> |
| | | <el-input v-model="filters.subjectName" placeholder="请è¾å
¥ç§ç®åç§°" clearable style="width: 200px;" /> |
| | | <el-input v-model="filters.subjectName" |
| | | placeholder="请è¾å
¥ç§ç®åç§°" |
| | | clearable |
| | | style="width: 200px;" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç§ç®ç±»å:"> |
| | | <el-select v-model="filters.subjectType" placeholder="è¯·éæ©" clearable style="width: 200px;"> |
| | | <el-option label="èµäº§ç±»" value="asset" /> |
| | | <el-option label="è´åºç±»" value="liability" /> |
| | | <el-option label="æçç±»" value="equity" /> |
| | | <el-option label="ææ¬ç±»" value="cost" /> |
| | | <el-option label="æçç±»" value="profit_loss" /> |
| | | <el-select v-model="filters.subjectType" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 200px;"> |
| | | <el-option label="èµäº§ç±»" |
| | | value="èµäº§ç±»" /> |
| | | <el-option label="è´åºç±»" |
| | | value="è´åºç±»" /> |
| | | <el-option label="æçç±»" |
| | | value="æçç±»" /> |
| | | <el-option label="ææ¬ç±»" |
| | | value="ææ¬ç±»" /> |
| | | <el-option label="æçç±»" |
| | | value="æçç±»" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getTableData">æç´¢</el-button> |
| | | <el-button type="primary" |
| | | @click="getTableData">æç´¢</el-button> |
| | | <el-button @click="resetFilters">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | |
| | | <div class="actions"> |
| | | <div></div> |
| | | <div> |
| | | <el-button type="primary" @click="add" icon="Plus">æ°å¢</el-button> |
| | | <el-button @click="handleOut" icon="Download">导åº</el-button> |
| | | <el-button type="primary" |
| | | @click="add" |
| | | icon="Plus">æ°å¢</el-button> |
| | | <!-- <el-button @click="handleOut" |
| | | icon="Download">导åº</el-button> --> |
| | | </div> |
| | | </div> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="columns" |
| | | :tableData="dataList" |
| | | :page="{ |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | total: pagination.total, |
| | | }" |
| | | @pagination="changePage" |
| | | > |
| | | <template #subjectType="{ row }"> |
| | | <el-tag :type="getSubjectTypeType(row.subjectType)">{{ getSubjectTypeLabel(row.subjectType) }}</el-tag> |
| | | </template> |
| | | <template #balanceDirection="{ row }"> |
| | | <el-tag :type="row.balanceDirection === 'debit' ? 'success' : 'danger'"> |
| | | {{ row.balanceDirection === 'debit' ? 'åæ¹' : 'è´·æ¹' }} |
| | | </el-tag> |
| | | </template> |
| | | <template #status="{ row }"> |
| | | <el-tag :type="row.status === 'active' ? 'success' : 'info'"> |
| | | {{ row.status === 'active' ? 'å¯ç¨' : 'ç¦ç¨' }} |
| | | </el-tag> |
| | | </template> |
| | | <template #operation="{ row }"> |
| | | <el-button type="primary" link @click="edit(row)">ç¼è¾</el-button> |
| | | <el-button type="danger" link @click="handleDelete(row)">å é¤</el-button> |
| | | </template> |
| | | </PIMTable> |
| | | <el-table ref="tableRef" |
| | | v-loading="loading" |
| | | :data="dataList" |
| | | row-key="id" |
| | | :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" |
| | | height="calc(100vh - 280px)" |
| | | border |
| | | stripe |
| | | highlight-current-row |
| | | class="subject-table"> |
| | | <el-table-column label="ç§ç®ç¼ç " prop="subjectCode" width="140"> |
| | | <template #default="scope"> |
| | | <span class="subject-code">{{ scope.row.subjectCode }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç§ç®åç§°" prop="subjectName" min-width="180"> |
| | | <template #default="scope"> |
| | | <span class="subject-name" :class="{ 'is-parent': scope.row.children?.length > 0 }"> |
| | | {{ scope.row.subjectName }} |
| | | </span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç§ç®ç±»å" prop="subjectType" width="100" align="center"> |
| | | <template #default="scope"> |
| | | <el-tag size="small" :type="getSubjectTypeType(scope.row.subjectType)"> |
| | | {{ scope.row.subjectType }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ä½é¢æ¹å" prop="balanceDirection" width="100" align="center"> |
| | | <template #default="scope"> |
| | | <el-tag size="small" :type="scope.row.balanceDirection === 'åæ¹' ? 'primary' : 'danger'"> |
| | | {{ scope.row.balanceDirection }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç¶æ" prop="status" width="80" align="center"> |
| | | <template #default="scope"> |
| | | <el-tag size="small" :type="scope.row.status === 0 || scope.row.status === '0' ? 'success' : 'info'"> |
| | | {{ scope.row.status === 0 || scope.row.status === '0' ? 'å¯ç¨' : 'ç¦ç¨' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="夿³¨" prop="remark" show-overflow-tooltip min-width="150" /> |
| | | <el-table-column label="æä½" align="center" fixed="right" width="240"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" icon="Plus" @click="addChild(scope.row)">æ°å¢</el-button> |
| | | <el-button link type="primary" icon="Edit" @click="edit(scope.row)">ç¼è¾</el-button> |
| | | <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="600px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="100px"> |
| | | <el-form-item label="ç§ç®ç¼ç " prop="subjectCode"> |
| | | <el-input v-model="form.subjectCode" placeholder="请è¾å
¥ç§ç®ç¼ç " /> |
| | | <FormDialog :title="dialogTitle" |
| | | v-model="dialogVisible" |
| | | width="600px" |
| | | @confirm="submitForm" |
| | | @cancel="dialogVisible = false"> |
| | | <el-form :model="form" |
| | | :rules="rules" |
| | | ref="formRef" |
| | | label-width="100px"> |
| | | <el-form-item label="ç¶çº§ç§ç®"> |
| | | <el-input :model-value="parentSubjectLabel" |
| | | disabled /> |
| | | </el-form-item> |
| | | <el-form-item label="ç§ç®åç§°" prop="subjectName"> |
| | | <el-input v-model="form.subjectName" placeholder="请è¾å
¥ç§ç®åç§°" /> |
| | | <el-form-item label="ç§ç®ç¼ç " |
| | | prop="subjectCode"> |
| | | <el-input v-model="form.subjectCode" |
| | | placeholder="请è¾å
¥ç§ç®ç¼ç " /> |
| | | </el-form-item> |
| | | <el-form-item label="ç§ç®ç±»å" prop="subjectType"> |
| | | <el-select v-model="form.subjectType" placeholder="è¯·éæ©ç§ç®ç±»å" style="width: 100%;"> |
| | | <el-option label="èµäº§ç±»" value="asset" /> |
| | | <el-option label="è´åºç±»" value="liability" /> |
| | | <el-option label="æçç±»" value="equity" /> |
| | | <el-option label="ææ¬ç±»" value="cost" /> |
| | | <el-option label="æçç±»" value="profit_loss" /> |
| | | <el-form-item label="ç§ç®åç§°" |
| | | prop="subjectName"> |
| | | <el-input v-model="form.subjectName" |
| | | placeholder="请è¾å
¥ç§ç®åç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç§ç®ç±»å" |
| | | prop="subjectType"> |
| | | <el-select v-model="form.subjectType" |
| | | placeholder="è¯·éæ©ç§ç®ç±»å" |
| | | style="width: 100%;"> |
| | | <el-option label="èµäº§ç±»" |
| | | value="èµäº§ç±»" /> |
| | | <el-option label="è´åºç±»" |
| | | value="è´åºç±»" /> |
| | | <el-option label="æçç±»" |
| | | value="æçç±»" /> |
| | | <el-option label="ææ¬ç±»" |
| | | value="ææ¬ç±»" /> |
| | | <el-option label="æçç±»" |
| | | value="æçç±»" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="ä½é¢æ¹å" prop="balanceDirection"> |
| | | <el-form-item label="ä½é¢æ¹å" |
| | | prop="balanceDirection"> |
| | | <el-radio-group v-model="form.balanceDirection"> |
| | | <el-radio label="debit">åæ¹</el-radio> |
| | | <el-radio label="credit">è´·æ¹</el-radio> |
| | | <el-radio label="åæ¹">åæ¹</el-radio> |
| | | <el-radio label="è´·æ¹">è´·æ¹</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æ" prop="status"> |
| | | <el-form-item label="ç¶æ" |
| | | prop="status"> |
| | | <el-radio-group v-model="form.status"> |
| | | <el-radio label="active">å¯ç¨</el-radio> |
| | | <el-radio label="inactive">ç¦ç¨</el-radio> |
| | | <el-radio :label="0">å¯ç¨</el-radio> |
| | | <el-radio :label="1">ç¦ç¨</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="夿³¨" prop="remark"> |
| | | <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请è¾å
¥å¤æ³¨" /> |
| | | <el-form-item label="夿³¨" |
| | | prop="remark"> |
| | | <el-input v-model="form.remark" |
| | | type="textarea" |
| | | :rows="3" |
| | | placeholder="请è¾å
¥å¤æ³¨" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button type="primary" |
| | | @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </FormDialog> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { ref, reactive, onMounted, getCurrentInstance, nextTick } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { |
| | | listAccountSubject, |
| | | addAccountSubject, |
| | | updateAccountSubject, |
| | | delAccountSubject, |
| | | exportAccountSubject, |
| | | } from "@/api/financialManagement/accountSubject"; |
| | | |
| | | defineOptions({ |
| | | name: "æ»å¸ç§ç®", |
| | | }); |
| | | defineOptions({ |
| | | name: "æ»å¸ç§ç®", |
| | | }); |
| | | |
| | | const filters = reactive({ |
| | | subjectCode: "", |
| | | subjectName: "", |
| | | subjectType: "", |
| | | }); |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | const pagination = reactive({ |
| | | currentPage: 1, |
| | | pageSize: 10, |
| | | total: 0, |
| | | }); |
| | | |
| | | const columns = [ |
| | | { label: "ç§ç®ç¼ç ", prop: "subjectCode", width: "120" }, |
| | | { label: "ç§ç®åç§°", prop: "subjectName", width: "150" }, |
| | | { label: "ç§ç®ç±»å", prop: "subjectType", slot: "subjectType" }, |
| | | { label: "ä½é¢æ¹å", prop: "balanceDirection", slot: "balanceDirection" }, |
| | | { label: "ç¶æ", prop: "status", slot: "status" }, |
| | | { label: "夿³¨", prop: "remark", showOverflowTooltip: true }, |
| | | { label: "æä½", prop: "operation", slot: "operation", width: "150", fixed: "right" }, |
| | | ]; |
| | | |
| | | const dataList = ref([]); |
| | | const dialogVisible = ref(false); |
| | | const dialogTitle = ref(""); |
| | | const formRef = ref(null); |
| | | const isEdit = ref(false); |
| | | const currentId = ref(null); |
| | | |
| | | const form = reactive({ |
| | | subjectCode: "", |
| | | subjectName: "", |
| | | subjectType: "", |
| | | balanceDirection: "debit", |
| | | status: "active", |
| | | remark: "", |
| | | }); |
| | | |
| | | const rules = { |
| | | subjectCode: [{ required: true, message: "请è¾å
¥ç§ç®ç¼ç ", trigger: "blur" }], |
| | | subjectName: [{ required: true, message: "请è¾å
¥ç§ç®åç§°", trigger: "blur" }], |
| | | subjectType: [{ required: true, message: "è¯·éæ©ç§ç®ç±»å", trigger: "change" }], |
| | | }; |
| | | |
| | | const mockData = [ |
| | | { id: 1, subjectCode: "1001", subjectName: "åºåç°é", subjectType: "asset", balanceDirection: "debit", status: "active", remark: "" }, |
| | | { id: 2, subjectCode: "1002", subjectName: "é¶è¡å款", subjectType: "asset", balanceDirection: "debit", status: "active", remark: "" }, |
| | | { id: 3, subjectCode: "1122", subjectName: "åºæ¶è´¦æ¬¾", subjectType: "asset", balanceDirection: "debit", status: "active", remark: "" }, |
| | | { id: 4, subjectCode: "2202", subjectName: "åºä»è´¦æ¬¾", subjectType: "liability", balanceDirection: "credit", status: "active", remark: "" }, |
| | | { id: 5, subjectCode: "4001", subjectName: "宿¶èµæ¬", subjectType: "equity", balanceDirection: "credit", status: "active", remark: "" }, |
| | | { id: 6, subjectCode: "5001", subjectName: "çäº§ææ¬", subjectType: "cost", balanceDirection: "debit", status: "active", remark: "" }, |
| | | { id: 7, subjectCode: "6001", subjectName: "主è¥ä¸å¡æ¶å
¥", subjectType: "profit_loss", balanceDirection: "credit", status: "active", remark: "" }, |
| | | { id: 8, subjectCode: "6401", subjectName: "主è¥ä¸å¡ææ¬", subjectType: "profit_loss", balanceDirection: "debit", status: "active", remark: "" }, |
| | | ]; |
| | | |
| | | const getSubjectTypeLabel = (type) => { |
| | | const map = { |
| | | asset: "èµäº§ç±»", |
| | | liability: "è´åºç±»", |
| | | equity: "æçç±»", |
| | | cost: "ææ¬ç±»", |
| | | profit_loss: "æçç±»", |
| | | }; |
| | | return map[type] || type; |
| | | }; |
| | | |
| | | const getSubjectTypeType = (type) => { |
| | | const map = { |
| | | asset: "success", |
| | | liability: "danger", |
| | | equity: "warning", |
| | | cost: "info", |
| | | profit_loss: "primary", |
| | | }; |
| | | return map[type] || ""; |
| | | }; |
| | | |
| | | const getTableData = () => { |
| | | let result = [...mockData]; |
| | | if (filters.subjectCode) { |
| | | result = result.filter(item => item.subjectCode.includes(filters.subjectCode)); |
| | | } |
| | | if (filters.subjectName) { |
| | | result = result.filter(item => item.subjectName.includes(filters.subjectName)); |
| | | } |
| | | if (filters.subjectType) { |
| | | result = result.filter(item => item.subjectType === filters.subjectType); |
| | | } |
| | | pagination.total = result.length; |
| | | dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize); |
| | | }; |
| | | |
| | | const resetFilters = () => { |
| | | filters.subjectCode = ""; |
| | | filters.subjectName = ""; |
| | | filters.subjectType = ""; |
| | | pagination.currentPage = 1; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const changePage = ({ current, size }) => { |
| | | pagination.currentPage = current; |
| | | pagination.pageSize = size; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const add = () => { |
| | | isEdit.value = false; |
| | | dialogTitle.value = "æ°å¢ç§ç®"; |
| | | Object.assign(form, { |
| | | const filters = reactive({ |
| | | subjectCode: "", |
| | | subjectName: "", |
| | | subjectType: "", |
| | | balanceDirection: "debit", |
| | | status: "active", |
| | | }); |
| | | |
| | | const pagination = reactive({ |
| | | currentPage: 1, |
| | | pageSize: 10, |
| | | total: 0, |
| | | }); |
| | | |
| | | const columns = [ |
| | | { label: "ç§ç®ç¼ç ", prop: "subjectCode", width: "120" }, |
| | | { label: "ç§ç®åç§°", prop: "subjectName", width: "150" }, |
| | | { label: "ç§ç®ç±»å", prop: "subjectType" }, |
| | | { |
| | | label: "ä½é¢æ¹å", |
| | | prop: "balanceDirection", |
| | | dataType: "tag", |
| | | formatData: value => { |
| | | if (value === "åæ¹") { |
| | | return "åæ¹"; |
| | | } |
| | | return "è´·æ¹"; |
| | | }, |
| | | formatType: value => { |
| | | if (value === "åæ¹") { |
| | | return "primary"; |
| | | } |
| | | return "danger"; |
| | | }, |
| | | }, |
| | | { |
| | | label: "ç¶æ", |
| | | prop: "status", |
| | | dataType: "tag", |
| | | formatData: value => { |
| | | if (value === 0 || value === "0") { |
| | | return "å¯ç¨"; |
| | | } |
| | | return "ç¦ç¨"; |
| | | }, |
| | | formatType: value => { |
| | | if (value === 0 || value === "0") { |
| | | return "success"; |
| | | } |
| | | return "info"; |
| | | }, |
| | | }, |
| | | |
| | | { label: "夿³¨", prop: "remark", showOverflowTooltip: true }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: "220", |
| | | operation: [ |
| | | { |
| | | name: "æ°å¢", |
| | | type: "primary", |
| | | clickFun: row => { |
| | | addChild(row); |
| | | }, |
| | | }, |
| | | { |
| | | name: "ç¼è¾", |
| | | type: "primary", |
| | | clickFun: row => { |
| | | edit(row); |
| | | }, |
| | | }, |
| | | { |
| | | name: "å é¤", |
| | | type: "danger", |
| | | clickFun: row => { |
| | | handleDelete(row); |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | ]; |
| | | |
| | | const dataList = ref([]); |
| | | const dialogVisible = ref(false); |
| | | const dialogTitle = ref(""); |
| | | const parentSubjectLabel = ref("顶级ç§ç®"); |
| | | const formRef = ref(null); |
| | | const tableRef = ref(null); |
| | | const isEdit = ref(false); |
| | | const loading = ref(false); |
| | | |
| | | const form = reactive({ |
| | | id: undefined, |
| | | parentId: null, |
| | | subjectCode: "", |
| | | subjectName: "", |
| | | subjectType: "", |
| | | balanceDirection: "åæ¹", |
| | | status: 0, |
| | | remark: "", |
| | | }); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const edit = (row) => { |
| | | isEdit.value = true; |
| | | currentId.value = row.id; |
| | | dialogTitle.value = "ç¼è¾ç§ç®"; |
| | | Object.assign(form, row); |
| | | dialogVisible.value = true; |
| | | }; |
| | | const rules = { |
| | | subjectCode: [{ required: true, message: "请è¾å
¥ç§ç®ç¼ç ", trigger: "blur" }], |
| | | subjectName: [{ required: true, message: "请è¾å
¥ç§ç®åç§°", trigger: "blur" }], |
| | | subjectType: [ |
| | | { required: true, message: "è¯·éæ©ç§ç®ç±»å", trigger: "change" }, |
| | | ], |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | formRef.value.validate((valid) => { |
| | | if (valid) { |
| | | if (isEdit.value) { |
| | | const index = mockData.findIndex(item => item.id === currentId.value); |
| | | if (index !== -1) { |
| | | mockData[index] = { ...mockData[index], ...form }; |
| | | } |
| | | ElMessage.success("ç¼è¾æå"); |
| | | } else { |
| | | const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1; |
| | | mockData.push({ id: newId, ...form }); |
| | | ElMessage.success("æ°å¢æå"); |
| | | const getSubjectTypeType = type => { |
| | | const map = { |
| | | èµäº§ç±»: "success", |
| | | è´åºç±»: "danger", |
| | | æçç±»: "warning", |
| | | ææ¬ç±»: "info", |
| | | æçç±»: "primary", |
| | | }; |
| | | return map[type] || ""; |
| | | }; |
| | | |
| | | const getTableData = () => { |
| | | loading.value = true; |
| | | const query = { |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | ...filters, |
| | | }; |
| | | listAccountSubject(query).then(response => { |
| | | dataList.value = response.data.records || []; |
| | | loading.value = false; |
| | | }).catch(() => { |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const resetFilters = () => { |
| | | filters.subjectCode = ""; |
| | | filters.subjectName = ""; |
| | | filters.subjectType = ""; |
| | | pagination.currentPage = 1; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const changePage = obj => { |
| | | pagination.currentPage = obj.page; |
| | | pagination.pageSize = obj.limit; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const buildParentSubjectLabel = parentRow => { |
| | | if (!parentRow) { |
| | | return "顶级ç§ç®"; |
| | | } |
| | | const code = parentRow.subjectCode || ""; |
| | | const name = parentRow.subjectName || ""; |
| | | return `${code} ${name}`.trim(); |
| | | }; |
| | | |
| | | const resetForm = ({ parentId = null, parentRow = null } = {}) => { |
| | | Object.assign(form, { |
| | | id: undefined, |
| | | parentId, |
| | | subjectCode: "", |
| | | subjectName: "", |
| | | subjectType: "", |
| | | balanceDirection: "åæ¹", |
| | | status: 0, |
| | | remark: "", |
| | | }); |
| | | parentSubjectLabel.value = buildParentSubjectLabel(parentRow); |
| | | }; |
| | | |
| | | const add = () => { |
| | | isEdit.value = false; |
| | | dialogTitle.value = "æ°å¢ç§ç®"; |
| | | resetForm({ parentId: null, parentRow: null }); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const addChild = row => { |
| | | isEdit.value = false; |
| | | dialogTitle.value = "æ°å¢åç§ç®"; |
| | | resetForm({ parentId: row.id, parentRow: row }); |
| | | form.subjectType = row.subjectType || ""; |
| | | form.balanceDirection = row.balanceDirection || "åæ¹"; |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const findSubjectById = (nodes, id) => { |
| | | for (const item of nodes || []) { |
| | | if (item.id === id) { |
| | | return item; |
| | | } |
| | | dialogVisible.value = false; |
| | | getTableData(); |
| | | if (item.children && item.children.length > 0) { |
| | | const found = findSubjectById(item.children, id); |
| | | if (found) { |
| | | return found; |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | return null; |
| | | }; |
| | | |
| | | const handleDelete = (row) => { |
| | | ElMessageBox.confirm("确认å é¤è¯¥ç§ç®åï¼", "æç¤º", { |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }).then(() => { |
| | | const index = mockData.findIndex(item => item.id === row.id); |
| | | if (index !== -1) { |
| | | mockData.splice(index, 1); |
| | | } |
| | | ElMessage.success("å 餿å"); |
| | | const edit = row => { |
| | | isEdit.value = true; |
| | | dialogTitle.value = "ç¼è¾ç§ç®"; |
| | | Object.assign(form, row); |
| | | form.parentId = row.parentId ?? null; |
| | | const parentRow = |
| | | row.parentId === null || row.parentId === undefined |
| | | ? null |
| | | : findSubjectById(dataList.value, row.parentId); |
| | | parentSubjectLabel.value = parentRow |
| | | ? buildParentSubjectLabel(parentRow) |
| | | : row.parentId |
| | | ? `ä¸çº§ID: ${row.parentId}` |
| | | : buildParentSubjectLabel(null); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | formRef.value.validate(valid => { |
| | | if (valid) { |
| | | if (isEdit.value) { |
| | | updateAccountSubject(form).then(() => { |
| | | ElMessage.success("ç¼è¾æå"); |
| | | dialogVisible.value = false; |
| | | getTableData(); |
| | | }); |
| | | } else { |
| | | addAccountSubject(form).then(() => { |
| | | ElMessage.success("æ°å¢æå"); |
| | | dialogVisible.value = false; |
| | | getTableData(); |
| | | }); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const handleDelete = row => { |
| | | const ids = row.id; |
| | | ElMessageBox.confirm("确认å é¤è¯¥ç§ç®åï¼", "æç¤º", { |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | return delAccountSubject(ids); |
| | | }) |
| | | .then(() => { |
| | | ElMessage.success("å 餿å"); |
| | | getTableData(); |
| | | }); |
| | | }; |
| | | |
| | | const handleOut = () => { |
| | | proxy.download( |
| | | "accountSubject/export", |
| | | { |
| | | ...filters, |
| | | }, |
| | | `account_subject_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getTableData(); |
| | | }); |
| | | }; |
| | | |
| | | const handleOut = () => { |
| | | ElMessage.success("å¯¼åºæå"); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getTableData(); |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .actions { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-bottom: 15px; |
| | | } |
| | | .actions { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .subject-table { |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | |
| | | :deep(.el-table__row) { |
| | | transition: background-color 0.3s; |
| | | } |
| | | |
| | | :deep(.el-table__row:hover) { |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | .subject-code { |
| | | color: #606266; |
| | | } |
| | | |
| | | .subject-name { |
| | | font-weight: 500; |
| | | |
| | | &.is-parent { |
| | | color: #409eff; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <!-- éè´å
¥åº --> |
| | | <div class="app-container"> |
| | | <el-form :model="filters" :inline="true"> |
| | | <el-form-item label="å
¥åºåå·:"> |
| | | <el-input v-model="filters.inCode" placeholder="请è¾å
¥å
¥åºåå·" clearable style="width: 200px;" /> |
| | | <el-input v-model="filters.inboundBatches" placeholder="请è¾å
¥å
¥åºåå·" clearable style="width: 200px;" /> |
| | | </el-form-item> |
| | | <el-form-item label="ä¾åºå:"> |
| | | <el-select v-model="filters.supplierId" placeholder="è¯·éæ©ä¾åºå" clearable style="width: 200px;"> |
| | | <el-option v-for="item in supplierList" :key="item.id" :label="item.name" :value="item.id" /> |
| | | </el-select> |
| | | <el-input v-model="filters.supplierName" placeholder="请è¾å
¥ä¾åºå" clearable style="width: 200px;" /> |
| | | </el-form-item> |
| | | <el-form-item label="å
¥åºæ¥æ:"> |
| | | <el-date-picker v-model="filters.dateRange" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange" range-separator="è³" start-placeholder="å¼å§æ¥æ" end-placeholder="ç»ææ¥æ" clearable /> |
| | | <el-date-picker |
| | | v-model="filters.dateRange" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="daterange" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getTableData">æç´¢</el-button> |
| | | <el-button type="primary" @click="onSearch">æç´¢</el-button> |
| | | <el-button @click="resetFilters">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | |
| | | rowKey="id" |
| | | :column="columns" |
| | | :tableData="dataList" |
| | | :tableLoading="tableLoading" |
| | | :page="{ |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | |
| | | }" |
| | | @pagination="changePage" |
| | | > |
| | | <template #amount="{ row }"> |
| | | <span class="text-primary">Â¥{{ formatMoney(row.amount) }}</span> |
| | | </template> |
| | | <template #status="{ row }"> |
| | | <el-tag :type="getStatusType(row.status)">{{ getStatusLabel(row.status) }}</el-tag> |
| | | </template> |
| | | <template #operation="{ row }"> |
| | | <el-button type="primary" link @click="view(row)">æ¥ç</el-button> |
| | | <el-button type="primary" link @click="edit(row)" v-if="row.status === 'pending'">ç¼è¾</el-button> |
| | | <el-button type="danger" link @click="handleDelete(row)" v-if="row.status === 'pending'">å é¤</el-button> |
| | | <template #inboundDate="{ row }"> |
| | | {{ row.InboundDate || row.inboundDate || "" }} |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="100px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å
¥åºåå·" prop="inCode"> |
| | | <el-input v-model="form.inCode" placeholder="请è¾å
¥å
¥åºåå·" :disabled="isEdit" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¾åºå" prop="supplierId"> |
| | | <el-select v-model="form.supplierId" placeholder="è¯·éæ©ä¾åºå" style="width: 100%;" :disabled="isEdit"> |
| | | <el-option v-for="item in supplierList" :key="item.id" :label="item.name" :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å
¥åºæ¥æ" prop="inDate"> |
| | | <el-date-picker v-model="form.inDate" type="date" placeholder="éæ©æ¥æ" value-format="YYYY-MM-DD" style="width: 100%;" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å
¥åºéé¢" prop="amount"> |
| | | <el-input-number v-model="form.amount" :min="0" :precision="2" style="width: 100%;" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-form-item label="å
¥åºæç»" prop="details"> |
| | | <el-table :data="form.details" border style="width: 100%"> |
| | | <el-table-column prop="materialName" label="ç©æåç§°" width="150"> |
| | | <template #default="{ $index }"> |
| | | <el-input v-model="form.details[$index].materialName" placeholder="ç©æåç§°" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="spec" label="è§æ ¼" width="120"> |
| | | <template #default="{ $index }"> |
| | | <el-input v-model="form.details[$index].spec" placeholder="è§æ ¼" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="quantity" label="æ°é" width="100"> |
| | | <template #default="{ $index }"> |
| | | <el-input-number v-model="form.details[$index].quantity" :min="0" style="width: 100%;" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="unitPrice" label="åä»·" width="120"> |
| | | <template #default="{ $index }"> |
| | | <el-input-number v-model="form.details[$index].unitPrice" :min="0" :precision="2" style="width: 100%;" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="total" label="éé¢" width="120"> |
| | | <template #default="{ row }"> |
| | | <span>Â¥{{ formatMoney(row.quantity * row.unitPrice) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" width="80"> |
| | | <template #default="{ $index }"> |
| | | <el-button type="danger" link @click="removeDetail($index)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <el-button type="primary" link @click="addDetail" style="margin-top: 10px;">+ æ·»å æç»</el-button> |
| | | </el-form-item> |
| | | <el-form-item label="夿³¨" prop="remark"> |
| | | <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请è¾å
¥å¤æ³¨" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { ref, reactive, onMounted, getCurrentInstance } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { listPageAccountPurchase } from "@/api/financialManagement/accountPurchase"; |
| | | |
| | | defineOptions({ |
| | | name: "éè´å
¥åº", |
| | | }); |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | const filters = reactive({ |
| | | inCode: "", |
| | | supplierId: "", |
| | | inboundBatches: "", |
| | | supplierName: "", |
| | | dateRange: [], |
| | | }); |
| | | |
| | |
| | | }); |
| | | |
| | | const columns = [ |
| | | { label: "å
¥åºåå·", prop: "inCode", width: "150" }, |
| | | { label: "ä¾åºå", prop: "supplierName", width: "180" }, |
| | | { label: "å
¥åºæ¥æ", prop: "inDate", width: "120" }, |
| | | { label: "å
¥åºéé¢", prop: "amount", slot: "amount" }, |
| | | { label: "ç¶æ", prop: "status", slot: "status" }, |
| | | { label: "夿³¨", prop: "remark", showOverflowTooltip: true }, |
| | | { label: "æä½", prop: "operation", slot: "operation", width: "200", fixed: "right" }, |
| | | { label: "å
¥åºåå·", prop: "inboundBatches", minWidth: "150" }, |
| | | { label: "ä¾åºå", prop: "supplierName", minWidth: "180" }, |
| | | { |
| | | label: "å
¥åºæ¥æ", |
| | | prop: "InboundDate", |
| | | minWidth: "170", |
| | | dataType: "slot", |
| | | slot: "inboundDate", |
| | | }, |
| | | { label: "产ååç§°", prop: "productName", minWidth: "140" }, |
| | | { label: "产åè§æ ¼", prop: "specificationModel", minWidth: "140" }, |
| | | { label: "éè´è®¢åå·", prop: "purchaseContractNumber", minWidth: "150" }, |
| | | ]; |
| | | |
| | | const dataList = ref([]); |
| | | const dialogVisible = ref(false); |
| | | const dialogTitle = ref(""); |
| | | const formRef = ref(null); |
| | | const isEdit = ref(false); |
| | | const currentId = ref(null); |
| | | const tableLoading = ref(false); |
| | | |
| | | const supplierList = [ |
| | | { id: 1, name: "åäº¬åææä¾åºå" }, |
| | | { id: 2, name: "䏿µ·çµåå
å¨ä»¶å
¬å¸" }, |
| | | { id: 3, name: "广å·å
è£
ææå" }, |
| | | { id: 4, name: "æ·±å³äºéé
ä»¶å
¬å¸" }, |
| | | ]; |
| | | function buildFilterParams() { |
| | | const params = { |
| | | inboundBatches: filters.inboundBatches || undefined, |
| | | supplierName: filters.supplierName || undefined, |
| | | }; |
| | | if (filters.dateRange && filters.dateRange.length === 2) { |
| | | params.startDate = filters.dateRange[0]; |
| | | params.endDate = filters.dateRange[1]; |
| | | } |
| | | return params; |
| | | } |
| | | |
| | | const form = reactive({ |
| | | inCode: "", |
| | | supplierId: "", |
| | | inDate: "", |
| | | amount: 0, |
| | | details: [], |
| | | remark: "", |
| | | }); |
| | | |
| | | const rules = { |
| | | inCode: [{ required: true, message: "请è¾å
¥å
¥åºåå·", trigger: "blur" }], |
| | | supplierId: [{ required: true, message: "è¯·éæ©ä¾åºå", trigger: "change" }], |
| | | inDate: [{ required: true, message: "è¯·éæ©å
¥åºæ¥æ", trigger: "change" }], |
| | | amount: [{ required: true, message: "请è¾å
¥å
¥åºéé¢", trigger: "blur" }], |
| | | }; |
| | | |
| | | const mockData = [ |
| | | { id: 1, inCode: "RK2024001", supplierId: 1, supplierName: "åäº¬åææä¾åºå", inDate: "2024-01-10", amount: 8000, status: "approved", details: [{ materialName: "颿", spec: "Q235", quantity: 10, unitPrice: 500 }], remark: "" }, |
| | | { id: 2, inCode: "RK2024002", supplierId: 2, supplierName: "䏿µ·çµåå
å¨ä»¶å
¬å¸", inDate: "2024-01-12", amount: 12000, status: "pending", details: [{ materialName: "è¯ç", spec: "STM32", quantity: 100, unitPrice: 80 }], remark: "" }, |
| | | { id: 3, inCode: "RK2024003", supplierId: 3, supplierName: "广å·å
è£
ææå", inDate: "2024-01-15", amount: 3500, status: "approved", details: [{ materialName: "纸箱", spec: "50*40*30", quantity: 500, unitPrice: 5 }], remark: "" }, |
| | | ]; |
| | | |
| | | const formatMoney = (value) => { |
| | | if (value === undefined || value === null) return "0.00"; |
| | | return Number(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ","); |
| | | }; |
| | | |
| | | const getStatusLabel = (status) => { |
| | | const map = { pending: "å¾
å®¡æ ¸", approved: "å·²å®¡æ ¸", rejected: "已驳å" }; |
| | | return map[status] || status; |
| | | }; |
| | | |
| | | const getStatusType = (status) => { |
| | | const map = { pending: "warning", approved: "success", rejected: "danger" }; |
| | | return map[status] || ""; |
| | | const onSearch = () => { |
| | | pagination.currentPage = 1; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const getTableData = () => { |
| | | let result = [...mockData]; |
| | | if (filters.inCode) { |
| | | result = result.filter(item => item.inCode.includes(filters.inCode)); |
| | | } |
| | | if (filters.supplierId) { |
| | | result = result.filter(item => item.supplierId === filters.supplierId); |
| | | } |
| | | if (filters.dateRange && filters.dateRange.length === 2) { |
| | | result = result.filter(item => item.inDate >= filters.dateRange[0] && item.inDate <= filters.dateRange[1]); |
| | | } |
| | | pagination.total = result.length; |
| | | dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize); |
| | | tableLoading.value = true; |
| | | listPageAccountPurchase({ |
| | | ...buildFilterParams(), |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | }) |
| | | .then((res) => { |
| | | const ok = res.code === 200 || res.code === 0; |
| | | if (ok && res.data) { |
| | | pagination.total = res.data.total ?? 0; |
| | | dataList.value = res.data.records ?? []; |
| | | } else { |
| | | ElMessage.error(res.msg || "æ¥è¯¢å¤±è´¥"); |
| | | dataList.value = []; |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | dataList.value = []; |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const resetFilters = () => { |
| | | filters.inCode = ""; |
| | | filters.supplierId = ""; |
| | | filters.inboundBatches = ""; |
| | | filters.supplierName = ""; |
| | | filters.dateRange = []; |
| | | pagination.currentPage = 1; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const changePage = ({ current, size }) => { |
| | | pagination.currentPage = current; |
| | | pagination.pageSize = size; |
| | | const changePage = ({ page, limit }) => { |
| | | pagination.currentPage = page; |
| | | pagination.pageSize = limit; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const addDetail = () => { |
| | | form.details.push({ materialName: "", spec: "", quantity: 0, unitPrice: 0 }); |
| | | }; |
| | | |
| | | const removeDetail = (index) => { |
| | | form.details.splice(index, 1); |
| | | }; |
| | | |
| | | const add = () => { |
| | | isEdit.value = false; |
| | | dialogTitle.value = "æ°å¢å
¥åº"; |
| | | Object.assign(form, { |
| | | inCode: "RK" + Date.now().toString().slice(-8), |
| | | supplierId: "", |
| | | inDate: new Date().toISOString().split('T')[0], |
| | | amount: 0, |
| | | details: [{ materialName: "", spec: "", quantity: 0, unitPrice: 0 }], |
| | | remark: "", |
| | | }); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const edit = (row) => { |
| | | isEdit.value = true; |
| | | currentId.value = row.id; |
| | | dialogTitle.value = "ç¼è¾å
¥åº"; |
| | | Object.assign(form, row); |
| | | if (!form.details || form.details.length === 0) { |
| | | form.details = [{ materialName: "", spec: "", quantity: 0, unitPrice: 0 }]; |
| | | } |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const view = (row) => { |
| | | ElMessage.info(`æ¥çå
¥åºå: ${row.inCode}`); |
| | | }; |
| | | |
| | | const handleDelete = (row) => { |
| | | ElMessageBox.confirm("确认å é¤è¯¥å
¥åºååï¼", "æç¤º", { |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }).then(() => { |
| | | const index = mockData.findIndex(item => item.id === row.id); |
| | | if (index !== -1) { |
| | | mockData.splice(index, 1); |
| | | } |
| | | ElMessage.success("å 餿å"); |
| | | getTableData(); |
| | | }); |
| | | }; |
| | | |
| | | const handleOut = () => { |
| | | ElMessage.success("å¯¼åºæå"); |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | formRef.value.validate((valid) => { |
| | | if (valid) { |
| | | const supplier = supplierList.find(item => item.id === form.supplierId); |
| | | if (isEdit.value) { |
| | | const index = mockData.findIndex(item => item.id === currentId.value); |
| | | if (index !== -1) { |
| | | mockData[index] = { ...mockData[index], ...form, supplierName: supplier?.name }; |
| | | } |
| | | ElMessage.success("ç¼è¾æå"); |
| | | } else { |
| | | const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1; |
| | | mockData.push({ id: newId, ...form, supplierName: supplier?.name, status: "pending" }); |
| | | ElMessage.success("æ°å¢æå"); |
| | | } |
| | | dialogVisible.value = false; |
| | | getTableData(); |
| | | } |
| | | }); |
| | | proxy.download( |
| | | "/accountPurchase/exportAccountPurchaseInbound", |
| | | buildFilterParams(), |
| | | `éè´å
¥åº_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .text-primary { |
| | | color: #409eff; |
| | | font-weight: bold; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <!-- éè´éè´§ --> |
| | | |
| | | <div class="app-container"> |
| | | <el-form :model="filters" :inline="true"> |
| | | <el-form-item label="éè´§åå·:"> |
| | | <el-input |
| | | v-model="filters.returnNo" |
| | | placeholder="请è¾å
¥éè´§åå·" |
| | | clearable |
| | | style="width: 200px" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="ä¾åºå:"> |
| | | <el-input |
| | | v-model="filters.supplierName" |
| | | placeholder="请è¾å
¥ä¾åºå" |
| | | clearable |
| | | style="width: 200px" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="éè´§æ¥æ:"> |
| | | <el-date-picker |
| | | v-model="filters.dateRange" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="daterange" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item> |
| | | <el-button type="primary" @click="onSearch">æç´¢</el-button> |
| | | |
| | | <el-button @click="resetFilters">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <div class="table_list"> |
| | | <div class="actions"> |
| | | <div></div> |
| | | |
| | | <div> |
| | | <el-button @click="handleOut" icon="Download">导åº</el-button> |
| | | </div> |
| | | </div> |
| | | |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="columns" |
| | | :tableData="dataList" |
| | | :tableLoading="tableLoading" |
| | | :page="{ |
| | | current: pagination.currentPage, |
| | | |
| | | size: pagination.pageSize, |
| | | |
| | | total: pagination.total, |
| | | }" |
| | | @pagination="changePage" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, getCurrentInstance } from "vue"; |
| | | |
| | | import { ElMessage } from "element-plus"; |
| | | |
| | | import { listPageAccountPurchaseReturn } from "@/api/financialManagement/accountPurchase"; |
| | | |
| | | defineOptions({ |
| | | name: "éè´éè´§", |
| | | }); |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | const filters = reactive({ |
| | | returnNo: "", |
| | | |
| | | supplierName: "", |
| | | |
| | | dateRange: [], |
| | | }); |
| | | |
| | | const pagination = reactive({ |
| | | currentPage: 1, |
| | | |
| | | pageSize: 10, |
| | | |
| | | total: 0, |
| | | }); |
| | | |
| | | const columns = [ |
| | | { label: "éè´§åå·", prop: "returnNo", minWidth: "150" }, |
| | | |
| | | { label: "ä¾åºå", prop: "supplierName", minWidth: "180" }, |
| | | |
| | | { label: "å
³èå
¥åºåå·", prop: "inboundBatches", minWidth: "150" }, |
| | | |
| | | { label: "éè´§æ¥æ", prop: "preparedAt", minWidth: "170" }, |
| | | |
| | | { |
| | | label: "鿬¾æ»é¢", |
| | | |
| | | prop: "totalAmount", |
| | | |
| | | minWidth: "150", |
| | | |
| | | align: "right", |
| | | |
| | | formatData: (val) => |
| | | val === null || val === undefined || val === "" |
| | | ? "" |
| | | : Number(val).toLocaleString("zh-CN", { |
| | | minimumFractionDigits: 2, |
| | | maximumFractionDigits: 2, |
| | | }), |
| | | }, |
| | | |
| | | { label: "éè´§æ¹å¼", prop: "returnType", minWidth: "150" }, |
| | | |
| | | { label: "éè´è®¢åå·", prop: "purchaseContractNumber", minWidth: "150" }, |
| | | ]; |
| | | |
| | | const dataList = ref([]); |
| | | |
| | | const tableLoading = ref(false); |
| | | |
| | | function buildFilterParams() { |
| | | const params = { |
| | | returnNo: filters.returnNo || undefined, |
| | | |
| | | supplierName: filters.supplierName || undefined, |
| | | }; |
| | | |
| | | if (filters.dateRange && filters.dateRange.length === 2) { |
| | | params.startDate = filters.dateRange[0]; |
| | | |
| | | params.endDate = filters.dateRange[1]; |
| | | } |
| | | |
| | | return params; |
| | | } |
| | | |
| | | const onSearch = () => { |
| | | pagination.currentPage = 1; |
| | | |
| | | getTableData(); |
| | | }; |
| | | |
| | | const getTableData = () => { |
| | | tableLoading.value = true; |
| | | |
| | | listPageAccountPurchaseReturn({ |
| | | ...buildFilterParams(), |
| | | |
| | | current: pagination.currentPage, |
| | | |
| | | size: pagination.pageSize, |
| | | }) |
| | | .then((res) => { |
| | | const ok = res.code === 200 || res.code === 0; |
| | | |
| | | if (ok && res.data) { |
| | | pagination.total = res.data.total ?? 0; |
| | | |
| | | dataList.value = res.data.records ?? []; |
| | | } else { |
| | | ElMessage.error(res.msg || "æ¥è¯¢å¤±è´¥"); |
| | | |
| | | dataList.value = []; |
| | | } |
| | | }) |
| | | |
| | | .catch(() => { |
| | | dataList.value = []; |
| | | }) |
| | | |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const resetFilters = () => { |
| | | filters.returnNo = ""; |
| | | |
| | | filters.supplierName = ""; |
| | | |
| | | filters.dateRange = []; |
| | | |
| | | pagination.currentPage = 1; |
| | | |
| | | getTableData(); |
| | | }; |
| | | |
| | | const changePage = ({ page, limit }) => { |
| | | pagination.currentPage = page; |
| | | |
| | | pagination.pageSize = limit; |
| | | |
| | | getTableData(); |
| | | }; |
| | | |
| | | const handleOut = () => { |
| | | proxy.download( |
| | | "/accountPurchase/exportAccountPurchaseReturn", |
| | | |
| | | buildFilterParams(), |
| | | |
| | | `éè´éè´§_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getTableData(); |
| | | }); |
| | | </script> |
| | | |
| | | |
| | | |
| | | <style lang="scss" scoped> |
| | | .actions { |
| | | display: flex; |
| | | |
| | | justify-content: space-between; |
| | | |
| | | margin-bottom: 15px; |
| | | } |
| | | </style> |
| | | |
| | |
| | | <template> |
| | | <!-- éå®åºåº --> |
| | | <div class="app-container"> |
| | | <el-form :model="filters" :inline="true"> |
| | | <el-form-item label="åºåºåå·:"> |
| | | <el-input v-model="filters.outCode" placeholder="请è¾å
¥åºåºåå·" clearable style="width: 200px;" /> |
| | | <el-input v-model="filters.outboundBatches" placeholder="请è¾å
¥åºåºåå·" clearable style="width: 200px;" /> |
| | | </el-form-item> |
| | | <el-form-item label="客æ·:"> |
| | | <el-select v-model="filters.customerId" placeholder="è¯·éæ©å®¢æ·" clearable style="width: 200px;"> |
| | | <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" /> |
| | | </el-select> |
| | | <el-form-item label="客æ·åç§°:"> |
| | | <el-input v-model="filters.customerName" placeholder="请è¾å
¥å®¢æ·åç§°" clearable style="width: 200px;" /> |
| | | </el-form-item> |
| | | <el-form-item label="åºåºæ¥æ:"> |
| | | <el-date-picker v-model="filters.dateRange" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange" range-separator="è³" start-placeholder="å¼å§æ¥æ" end-placeholder="ç»ææ¥æ" clearable /> |
| | | <el-date-picker |
| | | v-model="filters.dateRange" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="daterange" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getTableData">æç´¢</el-button> |
| | | <el-button type="primary" @click="onSearch">æç´¢</el-button> |
| | | <el-button @click="resetFilters">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | |
| | | rowKey="id" |
| | | :column="columns" |
| | | :tableData="dataList" |
| | | :tableLoading="tableLoading" |
| | | :page="{ |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | total: pagination.total, |
| | | }" |
| | | @pagination="changePage" |
| | | > |
| | | <template #status="{ row }"> |
| | | <el-tag :type="getStatusType(row.status)">{{ getStatusLabel(row.status) }}</el-tag> |
| | | </template> |
| | | <template #operation="{ row }"> |
| | | <el-button type="primary" link @click="view(row)">æ¥ç</el-button> |
| | | <el-button type="primary" link @click="edit(row)" v-if="row.status === 'pending'">ç¼è¾</el-button> |
| | | <el-button type="danger" link @click="handleDelete(row)" v-if="row.status === 'pending'">å é¤</el-button> |
| | | </template> |
| | | </PIMTable> |
| | | /> |
| | | </div> |
| | | |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="100px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åºåºåå·" prop="outCode"> |
| | | <el-input v-model="form.outCode" placeholder="请è¾å
¥åºåºåå·" :disabled="isEdit" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="客æ·" prop="customerId"> |
| | | <el-select v-model="form.customerId" placeholder="è¯·éæ©å®¢æ·" style="width: 100%;" :disabled="isEdit"> |
| | | <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åºåºæ¥æ" prop="outDate"> |
| | | <el-date-picker v-model="form.outDate" type="date" placeholder="éæ©æ¥æ" value-format="YYYY-MM-DD" style="width: 100%;" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éé¢" prop="amount"> |
| | | <el-input-number v-model="form.amount" :min="0" :precision="2" style="width: 100%;" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-form-item label="夿³¨" prop="remark"> |
| | | <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请è¾å
¥å¤æ³¨" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { ref, reactive, onMounted, getCurrentInstance } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { listPageAccountSales } from "@/api/financialManagement/accountSales"; |
| | | |
| | | defineOptions({ |
| | | name: "éå®åºåº", |
| | | }); |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | const filters = reactive({ |
| | | outCode: "", |
| | | customerId: "", |
| | | outboundBatches: "", |
| | | customerName: "", |
| | | dateRange: [], |
| | | }); |
| | | |
| | |
| | | }); |
| | | |
| | | const columns = [ |
| | | { label: "åºåºåå·", prop: "outCode", width: "150" }, |
| | | { label: "客æ·åç§°", prop: "customerName", width: "180" }, |
| | | { label: "åºåºæ¥æ", prop: "outDate", width: "120" }, |
| | | { label: "éé¢", prop: "amount", width: "120" }, |
| | | { label: "ç¶æ", prop: "status", slot: "status" }, |
| | | { label: "夿³¨", prop: "remark", showOverflowTooltip: true }, |
| | | { label: "æä½", prop: "operation", slot: "operation", width: "200", fixed: "right" }, |
| | | { label: "åºåºåå·", prop: "outboundBatches", minWidth: "150" }, |
| | | { label: "客æ·åç§°", prop: "customerName", minWidth: "180" }, |
| | | { label: "åºåºæ¥æ", prop: "shippingDate", width: "170" }, |
| | | { label: "产ååç§°", prop: "productName", minWidth: "140" }, |
| | | { label: "产åè§æ ¼", prop: "specificationModel", minWidth: "140" }, |
| | | { |
| | | label: "éé¢", |
| | | prop: "outboundAmount", |
| | | minWidth: "120", |
| | | align: "right", |
| | | formatData: (val) => (val === null || val === undefined || val === "" ? "" : Number(val).toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2 })), |
| | | }, |
| | | { label: "åè´§ç¼å·", prop: "shippingNo", minWidth: "140" }, |
| | | { label: "éå®è®¢åå·", prop: "salesContractNo", minWidth: "150" }, |
| | | ]; |
| | | |
| | | const dataList = ref([]); |
| | | const dialogVisible = ref(false); |
| | | const dialogTitle = ref(""); |
| | | const formRef = ref(null); |
| | | const isEdit = ref(false); |
| | | const currentId = ref(null); |
| | | const tableLoading = ref(false); |
| | | |
| | | const customerList = [ |
| | | { id: 1, name: "åäº¬ç§ææéå
¬å¸" }, |
| | | { id: 2, name: "䏿µ·è´¸æå
¬å¸" }, |
| | | { id: 3, name: "广å·å®ä¸æéå
¬å¸" }, |
| | | { id: 4, name: "æ·±å³çµåå
¬å¸" }, |
| | | ]; |
| | | function buildFilterParams() { |
| | | const params = { |
| | | outboundBatches: filters.outboundBatches || undefined, |
| | | customerName: filters.customerName || undefined, |
| | | }; |
| | | if (filters.dateRange && filters.dateRange.length === 2) { |
| | | params.startDate = filters.dateRange[0]; |
| | | params.endDate = filters.dateRange[1]; |
| | | } |
| | | return params; |
| | | } |
| | | |
| | | const form = reactive({ |
| | | outCode: "", |
| | | customerId: "", |
| | | outDate: "", |
| | | amount: 0, |
| | | remark: "", |
| | | }); |
| | | |
| | | const rules = { |
| | | outCode: [{ required: true, message: "请è¾å
¥åºåºåå·", trigger: "blur" }], |
| | | customerId: [{ required: true, message: "è¯·éæ©å®¢æ·", trigger: "change" }], |
| | | outDate: [{ required: true, message: "è¯·éæ©åºåºæ¥æ", trigger: "change" }], |
| | | amount: [{ required: true, message: "请è¾å
¥éé¢", trigger: "blur" }], |
| | | }; |
| | | |
| | | const mockData = [ |
| | | { id: 1, outCode: "CK2024001", customerId: 1, customerName: "åäº¬ç§ææéå
¬å¸", outDate: "2024-01-15", amount: 5000, status: "approved", remark: "" }, |
| | | { id: 2, outCode: "CK2024002", customerId: 2, customerName: "䏿µ·è´¸æå
¬å¸", outDate: "2024-01-16", amount: 8000, status: "pending", remark: "" }, |
| | | { id: 3, outCode: "CK2024003", customerId: 3, customerName: "广å·å®ä¸æéå
¬å¸", outDate: "2024-01-18", amount: 12000, status: "approved", remark: "" }, |
| | | { id: 4, outCode: "CK2024004", customerId: 4, customerName: "æ·±å³çµåå
¬å¸", outDate: "2024-01-20", amount: 3500, status: "pending", remark: "" }, |
| | | ]; |
| | | |
| | | const getStatusLabel = (status) => { |
| | | const map = { pending: "å¾
å®¡æ ¸", approved: "å·²å®¡æ ¸", rejected: "已驳å" }; |
| | | return map[status] || status; |
| | | }; |
| | | |
| | | const getStatusType = (status) => { |
| | | const map = { pending: "warning", approved: "success", rejected: "danger" }; |
| | | return map[status] || ""; |
| | | const onSearch = () => { |
| | | pagination.currentPage = 1; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const getTableData = () => { |
| | | let result = [...mockData]; |
| | | if (filters.outCode) { |
| | | result = result.filter(item => item.outCode.includes(filters.outCode)); |
| | | } |
| | | if (filters.customerId) { |
| | | result = result.filter(item => item.customerId === filters.customerId); |
| | | } |
| | | if (filters.dateRange && filters.dateRange.length === 2) { |
| | | result = result.filter(item => item.outDate >= filters.dateRange[0] && item.outDate <= filters.dateRange[1]); |
| | | } |
| | | pagination.total = result.length; |
| | | dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize); |
| | | tableLoading.value = true; |
| | | listPageAccountSales({ |
| | | ...buildFilterParams(), |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | }) |
| | | .then((res) => { |
| | | const ok = res.code === 200 || res.code === 0; |
| | | if (ok && res.data) { |
| | | pagination.total = res.data.total ?? 0; |
| | | dataList.value = res.data.records ?? []; |
| | | } else { |
| | | ElMessage.error(res.msg || "æ¥è¯¢å¤±è´¥"); |
| | | dataList.value = []; |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | dataList.value = []; |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const resetFilters = () => { |
| | | filters.outCode = ""; |
| | | filters.customerId = ""; |
| | | filters.outboundBatches = ""; |
| | | filters.customerName = ""; |
| | | filters.dateRange = []; |
| | | pagination.currentPage = 1; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const changePage = ({ current, size }) => { |
| | | pagination.currentPage = current; |
| | | pagination.pageSize = size; |
| | | const changePage = ({ page, limit }) => { |
| | | pagination.currentPage = page; |
| | | pagination.pageSize = limit; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const add = () => { |
| | | isEdit.value = false; |
| | | dialogTitle.value = "æ°å¢åºåº"; |
| | | Object.assign(form, { |
| | | outCode: "CK" + Date.now(), |
| | | customerId: "", |
| | | outDate: "", |
| | | amount: 0, |
| | | remark: "", |
| | | }); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const edit = (row) => { |
| | | isEdit.value = true; |
| | | currentId.value = row.id; |
| | | dialogTitle.value = "ç¼è¾åºåº"; |
| | | Object.assign(form, row); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const view = (row) => { |
| | | ElMessage.info(`æ¥çåºåºå: ${row.outCode}`); |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | formRef.value.validate((valid) => { |
| | | if (valid) { |
| | | const customer = customerList.find(item => item.id === form.customerId); |
| | | if (isEdit.value) { |
| | | const index = mockData.findIndex(item => item.id === currentId.value); |
| | | if (index !== -1) { |
| | | mockData[index] = { ...mockData[index], ...form, customerName: customer?.name }; |
| | | } |
| | | ElMessage.success("ç¼è¾æå"); |
| | | } else { |
| | | const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1; |
| | | mockData.push({ id: newId, ...form, customerName: customer?.name, status: "pending" }); |
| | | ElMessage.success("æ°å¢æå"); |
| | | } |
| | | dialogVisible.value = false; |
| | | getTableData(); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const handleDelete = (row) => { |
| | | ElMessageBox.confirm("确认å é¤è¯¥åºåºååï¼", "æç¤º", { |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }).then(() => { |
| | | const index = mockData.findIndex(item => item.id === row.id); |
| | | if (index !== -1) { |
| | | mockData.splice(index, 1); |
| | | } |
| | | ElMessage.success("å 餿å"); |
| | | getTableData(); |
| | | }); |
| | | }; |
| | | |
| | | const handleOut = () => { |
| | | ElMessage.success("å¯¼åºæå"); |
| | | proxy.download( |
| | | "/accountSales/exportAccountSalesOutbound", |
| | | buildFilterParams(), |
| | | `éå®åºåº_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | |
| | | <template> |
| | | <!-- éå®éè´§ --> |
| | | <div class="app-container"> |
| | | <el-form :model="filters" :inline="true"> |
| | | <el-form-item label="éè´§åå·:"> |
| | | <el-input v-model="filters.returnCode" placeholder="请è¾å
¥éè´§åå·" clearable style="width: 200px;" /> |
| | | <el-input v-model="filters.returnNo" placeholder="请è¾å
¥éè´§åå·" clearable style="width: 200px;" /> |
| | | </el-form-item> |
| | | <el-form-item label="客æ·:"> |
| | | <el-select v-model="filters.customerId" placeholder="è¯·éæ©å®¢æ·" clearable style="width: 200px;"> |
| | | <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" /> |
| | | </el-select> |
| | | <el-form-item label="客æ·åç§°:"> |
| | | <el-input v-model="filters.customerName" placeholder="请è¾å
¥å®¢æ·åç§°" clearable style="width: 200px;" /> |
| | | </el-form-item> |
| | | <el-form-item label="éè´§æ¥æ:"> |
| | | <el-date-picker v-model="filters.dateRange" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange" range-separator="è³" start-placeholder="å¼å§æ¥æ" end-placeholder="ç»ææ¥æ" clearable /> |
| | | <el-date-picker |
| | | v-model="filters.dateRange" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="daterange" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getTableData">æç´¢</el-button> |
| | | <el-button type="primary" @click="onSearch">æç´¢</el-button> |
| | | <el-button @click="resetFilters">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | |
| | | rowKey="id" |
| | | :column="columns" |
| | | :tableData="dataList" |
| | | :tableLoading="tableLoading" |
| | | :page="{ |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | total: pagination.total, |
| | | }" |
| | | @pagination="changePage" |
| | | > |
| | | <template #status="{ row }"> |
| | | <el-tag :type="getStatusType(row.status)">{{ getStatusLabel(row.status) }}</el-tag> |
| | | </template> |
| | | <template #operation="{ row }"> |
| | | <el-button type="primary" link @click="view(row)">æ¥ç</el-button> |
| | | <el-button type="primary" link @click="edit(row)" v-if="row.status === 'pending'">ç¼è¾</el-button> |
| | | <el-button type="success" link @click="handleAudit(row)" v-if="row.status === 'pending'">å®¡æ ¸</el-button> |
| | | </template> |
| | | </PIMTable> |
| | | /> |
| | | </div> |
| | | |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éè´§åå·" prop="returnCode"> |
| | | <el-input v-model="form.returnCode" placeholder="请è¾å
¥éè´§åå·" :disabled="isEdit" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å
³èåºåºå" prop="outCode"> |
| | | <el-select v-model="form.outCode" placeholder="è¯·éæ©åºåºå" style="width: 100%;" :disabled="isEdit"> |
| | | <el-option v-for="item in outList" :key="item.outCode" :label="item.outCode" :value="item.outCode" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="客æ·" prop="customerId"> |
| | | <el-select v-model="form.customerId" placeholder="è¯·éæ©å®¢æ·" style="width: 100%;" :disabled="isEdit"> |
| | | <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éè´§æ¥æ" prop="returnDate"> |
| | | <el-date-picker v-model="form.returnDate" type="date" placeholder="éæ©æ¥æ" value-format="YYYY-MM-DD" style="width: 100%;" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éè´§éé¢" prop="amount"> |
| | | <el-input-number v-model="form.amount" :min="0" :precision="2" style="width: 100%;" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éè´§åå " prop="reason"> |
| | | <el-input v-model="form.reason" placeholder="请è¾å
¥éè´§åå " /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-form-item label="夿³¨" prop="remark"> |
| | | <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请è¾å
¥å¤æ³¨" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { ref, reactive, onMounted, getCurrentInstance } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { listPageAccountSalesReturn } from "@/api/financialManagement/accountSales"; |
| | | |
| | | defineOptions({ |
| | | name: "éå®éè´§", |
| | | }); |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | const filters = reactive({ |
| | | returnCode: "", |
| | | customerId: "", |
| | | returnNo: "", |
| | | customerName: "", |
| | | dateRange: [], |
| | | }); |
| | | |
| | |
| | | }); |
| | | |
| | | const columns = [ |
| | | { label: "éè´§åå·", prop: "returnCode", width: "150" }, |
| | | { label: "客æ·åç§°", prop: "customerName", width: "180" }, |
| | | { label: "å
³èåºåºå", prop: "outCode", width: "150" }, |
| | | { label: "éè´§æ¥æ", prop: "returnDate", width: "120" }, |
| | | { label: "éè´§éé¢", prop: "amount", width: "120" }, |
| | | { label: "éè´§åå ", prop: "reason", width: "150", showOverflowTooltip: true }, |
| | | { label: "ç¶æ", prop: "status", slot: "status" }, |
| | | { label: "æä½", prop: "operation", slot: "operation", width: "200", fixed: "right" }, |
| | | { label: "éè´§åå·", prop: "returnNo", minWidth: "150" }, |
| | | { label: "客æ·åç§°", prop: "customerName", minWidth: "180" }, |
| | | { label: "å
³èåè´§åå·", prop: "shippingNo", minWidth: "150" }, |
| | | { label: "éè´§æ¥æ", prop: "makeTime", minWidth: "170" }, |
| | | { |
| | | label: "鿬¾æ»é¢", |
| | | prop: "refundAmount", |
| | | minWidth: "120", |
| | | align: "right", |
| | | formatData: (val) => |
| | | val === null || val === undefined || val === "" |
| | | ? "" |
| | | : Number(val).toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2 }), |
| | | }, |
| | | { label: "éè´§åå ", prop: "returnReason", minWidth: "150", showOverflowTooltip: true }, |
| | | { label: "éå®è®¢åå·", prop: "salesContractNo", minWidth: "150" }, |
| | | ]; |
| | | |
| | | const dataList = ref([]); |
| | | const dialogVisible = ref(false); |
| | | const dialogTitle = ref(""); |
| | | const formRef = ref(null); |
| | | const isEdit = ref(false); |
| | | const currentId = ref(null); |
| | | const tableLoading = ref(false); |
| | | |
| | | const customerList = [ |
| | | { id: 1, name: "åäº¬ç§ææéå
¬å¸" }, |
| | | { id: 2, name: "䏿µ·è´¸æå
¬å¸" }, |
| | | { id: 3, name: "广å·å®ä¸æéå
¬å¸" }, |
| | | { id: 4, name: "æ·±å³çµåå
¬å¸" }, |
| | | ]; |
| | | function buildFilterParams() { |
| | | const params = { |
| | | returnNo: filters.returnNo || undefined, |
| | | customerName: filters.customerName || undefined, |
| | | }; |
| | | if (filters.dateRange && filters.dateRange.length === 2) { |
| | | params.startDate = filters.dateRange[0]; |
| | | params.endDate = filters.dateRange[1]; |
| | | } |
| | | return params; |
| | | } |
| | | |
| | | const outList = [ |
| | | { outCode: "CK2024001", customerId: 1 }, |
| | | { outCode: "CK2024002", customerId: 2 }, |
| | | { outCode: "CK2024003", customerId: 3 }, |
| | | ]; |
| | | |
| | | const form = reactive({ |
| | | returnCode: "", |
| | | outCode: "", |
| | | customerId: "", |
| | | returnDate: "", |
| | | amount: 0, |
| | | reason: "", |
| | | remark: "", |
| | | }); |
| | | |
| | | const rules = { |
| | | returnCode: [{ required: true, message: "请è¾å
¥éè´§åå·", trigger: "blur" }], |
| | | outCode: [{ required: true, message: "è¯·éæ©å
³èåºåºå", trigger: "change" }], |
| | | customerId: [{ required: true, message: "è¯·éæ©å®¢æ·", trigger: "change" }], |
| | | returnDate: [{ required: true, message: "è¯·éæ©éè´§æ¥æ", trigger: "change" }], |
| | | amount: [{ required: true, message: "请è¾å
¥éè´§éé¢", trigger: "blur" }], |
| | | }; |
| | | |
| | | const mockData = [ |
| | | { id: 1, returnCode: "TH2024001", outCode: "CK2024001", customerId: 1, customerName: "åäº¬ç§ææéå
¬å¸", returnDate: "2024-01-20", amount: 1000, reason: "è´¨éé®é¢", status: "approved", remark: "" }, |
| | | { id: 2, returnCode: "TH2024002", outCode: "CK2024002", customerId: 2, customerName: "䏿µ·è´¸æå
¬å¸", returnDate: "2024-01-22", amount: 500, reason: "è§æ ¼ä¸ç¬¦", status: "pending", remark: "" }, |
| | | ]; |
| | | |
| | | const getStatusLabel = (status) => { |
| | | const map = { pending: "å¾
å®¡æ ¸", approved: "å·²å®¡æ ¸", rejected: "已驳å" }; |
| | | return map[status] || status; |
| | | }; |
| | | |
| | | const getStatusType = (status) => { |
| | | const map = { pending: "warning", approved: "success", rejected: "danger" }; |
| | | return map[status] || ""; |
| | | const onSearch = () => { |
| | | pagination.currentPage = 1; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const getTableData = () => { |
| | | let result = [...mockData]; |
| | | if (filters.returnCode) { |
| | | result = result.filter(item => item.returnCode.includes(filters.returnCode)); |
| | | } |
| | | if (filters.customerId) { |
| | | result = result.filter(item => item.customerId === filters.customerId); |
| | | } |
| | | if (filters.dateRange && filters.dateRange.length === 2) { |
| | | result = result.filter(item => item.returnDate >= filters.dateRange[0] && item.returnDate <= filters.dateRange[1]); |
| | | } |
| | | pagination.total = result.length; |
| | | dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize); |
| | | tableLoading.value = true; |
| | | listPageAccountSalesReturn({ |
| | | ...buildFilterParams(), |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | }) |
| | | .then((res) => { |
| | | const ok = res.code === 200 || res.code === 0; |
| | | if (ok && res.data) { |
| | | pagination.total = res.data.total ?? 0; |
| | | dataList.value = res.data.records ?? []; |
| | | } else { |
| | | ElMessage.error(res.msg || "æ¥è¯¢å¤±è´¥"); |
| | | dataList.value = []; |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | dataList.value = []; |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const resetFilters = () => { |
| | | filters.returnCode = ""; |
| | | filters.customerId = ""; |
| | | filters.returnNo = ""; |
| | | filters.customerName = ""; |
| | | filters.dateRange = []; |
| | | pagination.currentPage = 1; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const changePage = ({ current, size }) => { |
| | | pagination.currentPage = current; |
| | | pagination.pageSize = size; |
| | | const changePage = ({ page, limit }) => { |
| | | pagination.currentPage = page; |
| | | pagination.pageSize = limit; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const add = () => { |
| | | isEdit.value = false; |
| | | dialogTitle.value = "æ°å¢éè´§"; |
| | | Object.assign(form, { |
| | | returnCode: "TH" + Date.now(), |
| | | outCode: "", |
| | | customerId: "", |
| | | returnDate: "", |
| | | amount: 0, |
| | | reason: "", |
| | | remark: "", |
| | | }); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const edit = (row) => { |
| | | isEdit.value = true; |
| | | currentId.value = row.id; |
| | | dialogTitle.value = "ç¼è¾éè´§"; |
| | | Object.assign(form, row); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const view = (row) => { |
| | | ElMessage.info(`æ¥çéè´§å: ${row.returnCode}`); |
| | | }; |
| | | |
| | | const handleAudit = (row) => { |
| | | ElMessageBox.confirm("ç¡®è®¤å®¡æ ¸éè¿è¯¥éè´§ååï¼", "æç¤º", { |
| | | confirmButtonText: "éè¿", |
| | | cancelButtonText: "驳å", |
| | | distinguishCancelAndClose: true, |
| | | type: "warning", |
| | | }).then(() => { |
| | | const index = mockData.findIndex(item => item.id === row.id); |
| | | if (index !== -1) { |
| | | mockData[index].status = "approved"; |
| | | } |
| | | ElMessage.success("å®¡æ ¸éè¿"); |
| | | getTableData(); |
| | | }).catch((action) => { |
| | | if (action === "cancel") { |
| | | const index = mockData.findIndex(item => item.id === row.id); |
| | | if (index !== -1) { |
| | | mockData[index].status = "rejected"; |
| | | } |
| | | ElMessage.warning("已驳å"); |
| | | getTableData(); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | formRef.value.validate((valid) => { |
| | | if (valid) { |
| | | const customer = customerList.find(item => item.id === form.customerId); |
| | | if (isEdit.value) { |
| | | const index = mockData.findIndex(item => item.id === currentId.value); |
| | | if (index !== -1) { |
| | | mockData[index] = { ...mockData[index], ...form, customerName: customer?.name }; |
| | | } |
| | | ElMessage.success("ç¼è¾æå"); |
| | | } else { |
| | | const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1; |
| | | mockData.push({ id: newId, ...form, customerName: customer?.name, status: "pending" }); |
| | | ElMessage.success("æ°å¢æå"); |
| | | } |
| | | dialogVisible.value = false; |
| | | getTableData(); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const handleOut = () => { |
| | | ElMessage.success("å¯¼åºæå"); |
| | | proxy.download( |
| | | "/accountSales/exportAccountSalesReturn", |
| | | buildFilterParams(), |
| | | `éå®éè´§_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-form :model="filters" :inline="true"> |
| | | <el-form-item label="ä¼è®¡ç§ç®:"> |
| | | <el-cascader v-model="filters.subject" :options="subjectOptions" :props="{ label: 'name', value: 'code' }" placeholder="è¯·éæ©ä¼è®¡ç§ç®" clearable style="width: 250px;" filterable /> |
| | | </el-form-item> |
| | | <el-form-item label="è¾
婿 ¸ç®:"> |
| | | <el-select v-model="filters.auxiliary" placeholder="è¯·éæ©è¾
婿 ¸ç®" clearable style="width: 180px;"> |
| | | <el-option label="客æ·" value="customer" /> |
| | | <el-option label="ä¾åºå" value="supplier" /> |
| | | <el-option label="é¨é¨" value="department" /> |
| | | <el-option label="åå·¥" value="employee" /> |
| | | <el-option label="项ç®" value="project" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="æ ¸ç®å¯¹è±¡:"> |
| | | <el-select v-model="filters.auxiliaryItem" placeholder="è¯·éæ©æ ¸ç®å¯¹è±¡" clearable style="width: 200px;" :disabled="!filters.auxiliary"> |
| | | <el-option v-for="item in auxiliaryItems" :key="item.value" :label="item.label" :value="item.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="æé´:"> |
| | | <el-date-picker v-model="filters.startMonth" type="month" placeholder="å¼å§æä»½" value-format="YYYY-MM" style="width: 140px;" /> |
| | | <span style="margin: 0 10px;">è³</span> |
| | | <el-date-picker v-model="filters.endMonth" type="month" placeholder="ç»ææä»½" value-format="YYYY-MM" style="width: 140px;" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getTableData">æ¥è¯¢</el-button> |
| | | <el-button @click="resetFilters">éç½®</el-button> |
| | | <el-button @click="handlePrint" icon="Printer">æå°</el-button> |
| | | <el-button @click="handleOut" icon="Download">导åº</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div class="app-container ledger-page"> |
| | | <div class="ledger-layout"> |
| | | <aside class="subject-panel"> |
| | | <el-input v-model="subjectKeyword" placeholder="请è¾å
¥ç§ç®åç§°/ç¼å·" clearable prefix-icon="Search" /> |
| | | <el-scrollbar class="subject-tree-scroll"> |
| | | <el-tree |
| | | ref="subjectTreeRef" |
| | | :data="subjectOptions" |
| | | node-key="code" |
| | | :props="{ label: 'name', children: 'children' }" |
| | | highlight-current |
| | | default-expand-all |
| | | :expand-on-click-node="false" |
| | | :filter-node-method="filterSubjectNode" |
| | | @node-click="handleSubjectClick" |
| | | > |
| | | <template #default="{ data }"> |
| | | <span class="subject-node">{{ data.code }} {{ data.name }}</span> |
| | | </template> |
| | | </el-tree> |
| | | </el-scrollbar> |
| | | </aside> |
| | | |
| | | <div class="ledger-header" v-if="currentSubject"> |
| | | <h2>ç§ç®æç»è´¦</h2> |
| | | <p>ç§ç®: {{ currentSubject.code }} {{ currentSubject.name }}</p> |
| | | <p v-if="filters.auxiliary && filters.auxiliaryItem">è¾
婿 ¸ç®: {{ getAuxiliaryLabel() }}</p> |
| | | <p>æé´: {{ filters.startMonth }} è³ {{ filters.endMonth }}</p> |
| | | <section class="ledger-content"> |
| | | <el-form :model="filters" :inline="true" class="filter-form"> |
| | | <el-form-item label="æé´:"> |
| | | <el-date-picker v-model="filters.startMonth" type="month" placeholder="å¼å§æä»½" value-format="YYYY-MM" style="width: 140px;" /> |
| | | <span style="margin: 0 10px;">è³</span> |
| | | <el-date-picker v-model="filters.endMonth" type="month" placeholder="ç»ææä»½" value-format="YYYY-MM" style="width: 140px;" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getTableData">æ¥è¯¢</el-button> |
| | | <el-button @click="resetFilters">éç½®</el-button> |
| | | <!-- <el-button @click="handlePrint" icon="Printer">æå°</el-button>--> |
| | | <el-button @click="handleOut" icon="Download">导åº</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <div class="table_list"> |
| | | <el-table :data="dataList" border style="width: 100%"> |
| | | <el-table-column prop="date" label="æ¥æ" width="120" /> |
| | | <el-table-column prop="voucherNo" label="åè¯åå·" width="120" /> |
| | | <el-table-column prop="summary" label="æè¦" min-width="200" show-overflow-tooltip /> |
| | | <el-table-column prop="debit" label="åæ¹" width="150"> |
| | | <template #default="{ row }"> |
| | | <span v-if="row.debit > 0" class="text-danger">Â¥{{ formatMoney(row.debit) }}</span> |
| | | <span v-else>-</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="credit" label="è´·æ¹" width="150"> |
| | | <template #default="{ row }"> |
| | | <span v-if="row.credit > 0" class="text-success">Â¥{{ formatMoney(row.credit) }}</span> |
| | | <span v-else>-</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ¹å" width="80"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.direction === 'å' ? 'success' : 'danger'" size="small">{{ row.direction }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ä½é¢" width="150"> |
| | | <template #default="{ row }"> |
| | | <span :class="row.balance >= 0 ? 'text-primary' : 'text-warning'">Â¥{{ formatMoney(Math.abs(row.balance)) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <el-empty v-if="!currentSubject" description="è¯·éæ©ä¼è®¡ç§ç®æ¥è¯¢" style="margin-top: 50px;" /> |
| | | </section> |
| | | </div> |
| | | |
| | | <div class="table_list"> |
| | | <el-table :data="dataList" border style="width: 100%" show-summary :summary-method="getSummaries"> |
| | | <el-table-column prop="date" label="æ¥æ" width="120" /> |
| | | <el-table-column prop="voucherNo" label="åè¯åå·" width="120" /> |
| | | <el-table-column prop="summary" label="æè¦" min-width="200" show-overflow-tooltip /> |
| | | <el-table-column label="åæ¹" width="150"> |
| | | <template #default="{ row }"> |
| | | <span v-if="row.debit > 0" class="text-danger">Â¥{{ formatMoney(row.debit) }}</span> |
| | | <span v-else>-</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="è´·æ¹" width="150"> |
| | | <template #default="{ row }"> |
| | | <span v-if="row.credit > 0" class="text-success">Â¥{{ formatMoney(row.credit) }}</span> |
| | | <span v-else>-</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ¹å" width="80"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.direction === 'å' ? 'success' : 'danger'" size="small">{{ row.direction }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ä½é¢" width="150"> |
| | | <template #default="{ row }"> |
| | | <span :class="row.balance >= 0 ? 'text-primary' : 'text-warning'">Â¥{{ formatMoney(Math.abs(row.balance)) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <el-empty v-if="!currentSubject" description="è¯·éæ©ä¼è®¡ç§ç®æ¥è¯¢" style="margin-top: 50px;" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, computed, watch } from "vue"; |
| | | import { ref, reactive, onMounted, computed, watch, nextTick } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { listAccountSubject } from "@/api/financialManagement/accountSubject"; |
| | | import { getDetailLedger } from "@/api/financialManagement/ledger"; |
| | | |
| | | defineOptions({ |
| | | name: "ç§ç®æç»è´¦", |
| | | }); |
| | | |
| | | const filters = reactive({ |
| | | subject: [], |
| | | auxiliary: "", |
| | | auxiliaryItem: "", |
| | | startMonth: "2024-01", |
| | | endMonth: "2024-03", |
| | | subject: "", |
| | | startMonth: "", |
| | | endMonth: "", |
| | | }); |
| | | |
| | | const dataList = ref([]); |
| | | const subjectOptions = ref([]); |
| | | const subjectKeyword = ref(""); |
| | | const subjectTreeRef = ref(); |
| | | |
| | | const subjectOptions = [ |
| | | { |
| | | code: "1122", |
| | | name: "åºæ¶è´¦æ¬¾", |
| | | children: [ |
| | | { code: "112201", name: "åäº¬ç§ææéå
¬å¸" }, |
| | | { code: "112202", name: "䏿µ·è´¸æå
¬å¸" }, |
| | | { code: "112203", name: "广å·å®ä¸æéå
¬å¸" }, |
| | | ], |
| | | }, |
| | | { |
| | | code: "2202", |
| | | name: "åºä»è´¦æ¬¾", |
| | | children: [ |
| | | { code: "220201", name: "åäº¬åææä¾åºå" }, |
| | | { code: "220202", name: "䏿µ·çµåå
å¨ä»¶å
¬å¸" }, |
| | | { code: "220203", name: "广å·å
è£
ææå" }, |
| | | ], |
| | | }, |
| | | { |
| | | code: "6602", |
| | | name: "管çè´¹ç¨", |
| | | children: [ |
| | | { code: "660201", name: "åå
¬è´¹" }, |
| | | { code: "660202", name: "å·®æ
è´¹" }, |
| | | { code: "660203", name: "ä¸å¡æå¾
è´¹" }, |
| | | ], |
| | | }, |
| | | const getPreviousMonth = () => { |
| | | const date = new Date(); |
| | | date.setDate(1); |
| | | date.setMonth(date.getMonth() - 1); |
| | | const year = date.getFullYear(); |
| | | const month = String(date.getMonth() + 1).padStart(2, "0"); |
| | | return `${year}-${month}`; |
| | | }; |
| | | |
| | | const defaultMonth = getPreviousMonth(); |
| | | filters.startMonth = defaultMonth; |
| | | filters.endMonth = defaultMonth; |
| | | |
| | | const fallbackSubjects = [ |
| | | { code: "1122", name: "åºæ¶è´¦æ¬¾" }, |
| | | { code: "2202", name: "åºä»è´¦æ¬¾" }, |
| | | { code: "6602", name: "管çè´¹ç¨" }, |
| | | ]; |
| | | |
| | | const auxiliaryItems = computed(() => { |
| | | const map = { |
| | | customer: [ |
| | | { value: "1", label: "åäº¬ç§ææéå
¬å¸" }, |
| | | { value: "2", label: "䏿µ·è´¸æå
¬å¸" }, |
| | | { value: "3", label: "广å·å®ä¸æéå
¬å¸" }, |
| | | ], |
| | | supplier: [ |
| | | { value: "1", label: "åäº¬åææä¾åºå" }, |
| | | { value: "2", label: "䏿µ·çµåå
å¨ä»¶å
¬å¸" }, |
| | | { value: "3", label: "广å·å
è£
ææå" }, |
| | | ], |
| | | department: [ |
| | | { value: "1", label: "è´¢å¡é¨" }, |
| | | { value: "2", label: "éå®é¨" }, |
| | | { value: "3", label: "éè´é¨" }, |
| | | ], |
| | | employee: [ |
| | | { value: "1", label: "å¼ ä¸" }, |
| | | { value: "2", label: "æå" }, |
| | | { value: "3", label: "çäº" }, |
| | | ], |
| | | project: [ |
| | | { value: "1", label: "项ç®A" }, |
| | | { value: "2", label: "项ç®B" }, |
| | | { value: "3", label: "项ç®C" }, |
| | | ], |
| | | }; |
| | | return map[filters.auxiliary] || []; |
| | | }); |
| | | |
| | | watch(() => filters.auxiliary, () => { |
| | | filters.auxiliaryItem = ""; |
| | | }); |
| | | |
| | | const currentSubject = computed(() => { |
| | | if (!filters.subject || filters.subject.length === 0) return null; |
| | | const code = filters.subject[filters.subject.length - 1]; |
| | | return findSubject(subjectOptions, code); |
| | | }); |
| | | const toTree = (nodes = []) => |
| | | nodes |
| | | .filter(item => item.subjectCode && item.subjectName) |
| | | .map(item => ({ |
| | | code: item.subjectCode, |
| | | name: item.subjectName, |
| | | children: toTree(item.children || []), |
| | | })); |
| | | |
| | | const findSubject = (options, code) => { |
| | | for (const item of options) { |
| | |
| | | return null; |
| | | }; |
| | | |
| | | const getAuxiliaryLabel = () => { |
| | | const item = auxiliaryItems.value.find(i => i.value === filters.auxiliaryItem); |
| | | return item ? item.label : ""; |
| | | const currentSubject = computed(() => { |
| | | if (!filters.subject) return null; |
| | | return findSubject(subjectOptions.value, filters.subject); |
| | | }); |
| | | |
| | | const getFirstSubjectCode = (nodes = []) => { |
| | | for (const item of nodes) { |
| | | if (item.code) return item.code; |
| | | if (item.children && item.children.length > 0) { |
| | | const childCode = getFirstSubjectCode(item.children); |
| | | if (childCode) return childCode; |
| | | } |
| | | } |
| | | return ""; |
| | | }; |
| | | |
| | | const setDefaultSubjectSelection = async () => { |
| | | const firstCode = getFirstSubjectCode(subjectOptions.value); |
| | | if (!firstCode) { |
| | | filters.subject = ""; |
| | | subjectTreeRef.value?.setCurrentKey(null); |
| | | return; |
| | | } |
| | | filters.subject = firstCode; |
| | | await nextTick(); |
| | | subjectTreeRef.value?.setCurrentKey(firstCode); |
| | | }; |
| | | |
| | | const filterSubjectNode = (value, data) => { |
| | | const keyword = value?.trim(); |
| | | if (!keyword) return true; |
| | | return `${data.code}${data.name}`.includes(keyword); |
| | | }; |
| | | |
| | | watch(subjectKeyword, (value) => { |
| | | subjectTreeRef.value?.filter(value || ""); |
| | | }); |
| | | |
| | | const handleSubjectClick = async (data) => { |
| | | filters.subject = data.code; |
| | | await getTableData(); |
| | | }; |
| | | |
| | | const loadSubjectOptions = async () => { |
| | | let options = []; |
| | | try { |
| | | const { data } = await listAccountSubject({ |
| | | current: 1, |
| | | size: 1000, |
| | | }); |
| | | options = toTree(data?.records || []); |
| | | } catch (error) { |
| | | // å
¨å±æ¦æªå¨å·²æç¤ºï¼ä¸é¢èµ°å
åºç§ç® |
| | | } |
| | | if (options.length === 0) { |
| | | options = fallbackSubjects.map(item => ({ ...item, children: [] })); |
| | | } |
| | | subjectOptions.value = options; |
| | | await setDefaultSubjectSelection(); |
| | | if (filters.subject) { |
| | | await getTableData(); |
| | | } |
| | | }; |
| | | |
| | | const formatMoney = (value) => { |
| | |
| | | return Number(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ","); |
| | | }; |
| | | |
| | | const mockData = [ |
| | | { date: "2024-01-01", voucherNo: "-", summary: "æåä½é¢", debit: 0, credit: 0, direction: "å", balance: 10000 }, |
| | | { date: "2024-01-05", voucherNo: "è®°-0001", summary: "éå®åºåº", debit: 5000, credit: 0, direction: "å", balance: 15000 }, |
| | | { date: "2024-01-10", voucherNo: "è®°-0002", summary: "æ¶å°è´§æ¬¾", debit: 0, credit: 3000, direction: "å", balance: 12000 }, |
| | | { date: "2024-01-15", voucherNo: "è®°-0003", summary: "éå®åºåº", debit: 8000, credit: 0, direction: "å", balance: 20000 }, |
| | | { date: "2024-01-20", voucherNo: "è®°-0004", summary: "éå®éè´§", debit: 0, credit: 2000, direction: "å", balance: 18000 }, |
| | | { date: "2024-01-25", voucherNo: "è®°-0005", summary: "æ¶å°è´§æ¬¾", debit: 0, credit: 5000, direction: "å", balance: 13000 }, |
| | | { date: "2024-01-31", voucherNo: "-", summary: "æ¬æå计", debit: 13000, credit: 10000, direction: "å", balance: 13000 }, |
| | | { date: "2024-02-01", voucherNo: "-", summary: "æåä½é¢", debit: 0, credit: 0, direction: "å", balance: 13000 }, |
| | | { date: "2024-02-10", voucherNo: "è®°-0006", summary: "éå®åºåº", debit: 6000, credit: 0, direction: "å", balance: 19000 }, |
| | | { date: "2024-02-15", voucherNo: "è®°-0007", summary: "æ¶å°è´§æ¬¾", debit: 0, credit: 4000, direction: "å", balance: 15000 }, |
| | | { date: "2024-02-28", voucherNo: "-", summary: "æ¬æå计", debit: 6000, credit: 4000, direction: "å", balance: 15000 }, |
| | | { date: "2024-03-01", voucherNo: "-", summary: "æåä½é¢", debit: 0, credit: 0, direction: "å", balance: 15000 }, |
| | | { date: "2024-03-05", voucherNo: "è®°-0008", summary: "éå®åºåº", debit: 7000, credit: 0, direction: "å", balance: 22000 }, |
| | | { date: "2024-03-10", voucherNo: "è®°-0009", summary: "æ¶å°è´§æ¬¾", debit: 0, credit: 6000, direction: "å", balance: 16000 }, |
| | | { date: "2024-03-31", voucherNo: "-", summary: "æ¬æå计", debit: 7000, credit: 6000, direction: "å", balance: 16000 }, |
| | | { date: "2024-03-31", voucherNo: "-", summary: "æ¬å¹´ç´¯è®¡", debit: 26000, credit: 20000, direction: "å", balance: 16000 }, |
| | | ]; |
| | | |
| | | const getTableData = () => { |
| | | // èè°çº¦å®ï¼æç»è´¦æç§ç®ä¸æé´è¿æ»¤ |
| | | const getTableData = async () => { |
| | | if (!currentSubject.value) { |
| | | dataList.value = []; |
| | | return; |
| | | } |
| | | dataList.value = [...mockData]; |
| | | try { |
| | | const { data } = await getDetailLedger({ |
| | | subjectCode: currentSubject.value.code, |
| | | startMonth: filters.startMonth, |
| | | endMonth: filters.endMonth, |
| | | }); |
| | | dataList.value = Array.isArray(data) ? data : data?.records || []; |
| | | } catch (error) { |
| | | // æç¤ºç±å
¨å±è¯·æ±æ¦æªå¨å¤çï¼è¿éä»
鲿¢æªæè·å¼å¸¸ |
| | | } |
| | | }; |
| | | |
| | | const resetFilters = () => { |
| | | filters.subject = []; |
| | | filters.auxiliary = ""; |
| | | filters.auxiliaryItem = ""; |
| | | filters.startMonth = "2024-01"; |
| | | filters.endMonth = "2024-03"; |
| | | const resetFilters = async () => { |
| | | filters.startMonth = defaultMonth; |
| | | filters.endMonth = defaultMonth; |
| | | dataList.value = []; |
| | | }; |
| | | |
| | | const getSummaries = (param) => { |
| | | const { columns, data } = param; |
| | | const sums = []; |
| | | columns.forEach((column, index) => { |
| | | if (index === 0) { |
| | | sums[index] = "å计"; |
| | | return; |
| | | } |
| | | if (column.property === "debit") { |
| | | const values = data.map(item => Number(item.debit)); |
| | | const sum = values.reduce((prev, curr) => prev + curr, 0); |
| | | sums[index] = "Â¥" + formatMoney(sum); |
| | | } else if (column.property === "credit") { |
| | | const values = data.map(item => Number(item.credit)); |
| | | const sum = values.reduce((prev, curr) => prev + curr, 0); |
| | | sums[index] = "Â¥" + formatMoney(sum); |
| | | } else { |
| | | sums[index] = ""; |
| | | } |
| | | }); |
| | | return sums; |
| | | subjectKeyword.value = ""; |
| | | subjectTreeRef.value?.filter(""); |
| | | await setDefaultSubjectSelection(); |
| | | if (filters.subject) { |
| | | await getTableData(); |
| | | } |
| | | }; |
| | | |
| | | const handlePrint = () => { |
| | |
| | | ElMessage.success("å¯¼åºæå"); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | // é»è®¤ä¸å è½½æ°æ®ï¼éè¦éæ©ç§ç® |
| | | onMounted(async () => { |
| | | await loadSubjectOptions(); |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .ledger-header { |
| | | text-align: center; |
| | | margin-bottom: 20px; |
| | | h2 { |
| | | margin: 0 0 10px 0; |
| | | } |
| | | p { |
| | | color: #606266; |
| | | margin: 5px 0; |
| | | } |
| | | .ledger-layout { |
| | | display: flex; |
| | | gap: 16px; |
| | | } |
| | | |
| | | .subject-panel { |
| | | width: 260px; |
| | | flex-shrink: 0; |
| | | padding: 12px; |
| | | border: 1px solid #e4e7ed; |
| | | border-radius: 8px; |
| | | background-color: #fff; |
| | | } |
| | | |
| | | .subject-tree-scroll { |
| | | height: 600px; |
| | | margin-top: 12px; |
| | | } |
| | | |
| | | .subject-node { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .ledger-content { |
| | | flex: 1; |
| | | min-width: 0; |
| | | } |
| | | |
| | | .filter-form { |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .text-primary { |
| | |
| | | color: #e6a23c; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .subject-panel :deep(.el-tree-node__content) { |
| | | height: 34px; |
| | | } |
| | | |
| | | .subject-panel :deep(.el-tree-node.is-current > .el-tree-node__content) { |
| | | background-color: #f0f7ff; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-form :model="filters" :inline="true"> |
| | | <el-form-item label="ä¼è®¡ç§ç®:"> |
| | | <el-cascader v-model="filters.subject" :options="subjectOptions" :props="{ label: 'name', value: 'code' }" placeholder="è¯·éæ©ä¼è®¡ç§ç®" clearable style="width: 250px;" filterable /> |
| | | </el-form-item> |
| | | <el-form-item label="æé´:"> |
| | | <el-date-picker v-model="filters.startMonth" type="month" placeholder="å¼å§æä»½" value-format="YYYY-MM" style="width: 140px;" /> |
| | | <span style="margin: 0 10px;">è³</span> |
| | | <el-date-picker v-model="filters.endMonth" type="month" placeholder="ç»ææä»½" value-format="YYYY-MM" style="width: 140px;" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getTableData">æ¥è¯¢</el-button> |
| | | <el-button @click="resetFilters">éç½®</el-button> |
| | | <el-button @click="handlePrint" icon="Printer">æå°</el-button> |
| | | <el-button @click="handleOut" icon="Download">导åº</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div class="app-container ledger-page"> |
| | | <div class="ledger-layout"> |
| | | <aside class="subject-panel"> |
| | | <el-input v-model="subjectKeyword" placeholder="请è¾å
¥ç§ç®åç§°/ç¼å·" clearable prefix-icon="Search" /> |
| | | <el-scrollbar class="subject-tree-scroll"> |
| | | <el-tree |
| | | ref="subjectTreeRef" |
| | | :data="subjectOptions" |
| | | node-key="code" |
| | | :props="{ label: 'name', children: 'children' }" |
| | | highlight-current |
| | | default-expand-all |
| | | :expand-on-click-node="false" |
| | | :filter-node-method="filterSubjectNode" |
| | | @node-click="handleSubjectClick" |
| | | > |
| | | <template #default="{ data }"> |
| | | <span class="subject-node">{{ data.code }} {{ data.name }}</span> |
| | | </template> |
| | | </el-tree> |
| | | </el-scrollbar> |
| | | </aside> |
| | | |
| | | <div class="ledger-header" v-if="currentSubject"> |
| | | <h2>ç§ç®æ»è´¦</h2> |
| | | <p>ç§ç®: {{ currentSubject.code }} {{ currentSubject.name }}</p> |
| | | <p>æé´: {{ filters.startMonth }} è³ {{ filters.endMonth }}</p> |
| | | <section class="ledger-content"> |
| | | <el-form :model="filters" :inline="true" class="filter-form"> |
| | | <el-form-item label="æé´:"> |
| | | <el-date-picker v-model="filters.startMonth" type="month" placeholder="å¼å§æä»½" value-format="YYYY-MM" style="width: 140px;" /> |
| | | <span style="margin: 0 10px;">è³</span> |
| | | <el-date-picker v-model="filters.endMonth" type="month" placeholder="ç»ææä»½" value-format="YYYY-MM" style="width: 140px;" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getTableData">æ¥è¯¢</el-button> |
| | | <el-button @click="resetFilters">éç½®</el-button> |
| | | <!-- <el-button @click="handlePrint" icon="Printer">æå°</el-button>--> |
| | | <!-- <el-button @click="handleOut" icon="Download">导åº</el-button> --> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <div class="table_list"> |
| | | <el-table :data="dataList" border style="width: 100%"> |
| | | <el-table-column prop="date" label="æ¥æ"/> |
| | | <!-- <el-table-column prop="voucherNo" label="åè¯åå·" width="120" /> --> |
| | | <!-- <el-table-column prop="summary" label="æè¦" min-width="200" show-overflow-tooltip /> --> |
| | | <el-table-column prop="debit" label="åæ¹"> |
| | | <template #default="{ row }"> |
| | | <span v-if="row.debit > 0" class="text-danger">Â¥{{ formatMoney(row.debit) }}</span> |
| | | <span v-else>-</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="credit" label="è´·æ¹"> |
| | | <template #default="{ row }"> |
| | | <span v-if="row.credit > 0" class="text-success">Â¥{{ formatMoney(row.credit) }}</span> |
| | | <span v-else>-</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ¹å"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.direction === 'å' ? 'success' : 'danger'" size="small">{{ row.direction }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ä½é¢"> |
| | | <template #default="{ row }"> |
| | | <span :class="row.balance >= 0 ? 'text-primary' : 'text-warning'">Â¥{{ formatMoney(Math.abs(row.balance)) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <el-empty v-if="!currentSubject" description="è¯·éæ©ä¼è®¡ç§ç®æ¥è¯¢" style="margin-top: 50px;" /> |
| | | </section> |
| | | </div> |
| | | |
| | | <div class="table_list"> |
| | | <el-table :data="dataList" border style="width: 100%" show-summary :summary-method="getSummaries"> |
| | | <el-table-column prop="date" label="æ¥æ" width="120" /> |
| | | <el-table-column prop="voucherNo" label="åè¯åå·" width="120" /> |
| | | <el-table-column prop="summary" label="æè¦" min-width="200" show-overflow-tooltip /> |
| | | <el-table-column label="åæ¹" width="150"> |
| | | <template #default="{ row }"> |
| | | <span v-if="row.debit > 0" class="text-danger">Â¥{{ formatMoney(row.debit) }}</span> |
| | | <span v-else>-</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="è´·æ¹" width="150"> |
| | | <template #default="{ row }"> |
| | | <span v-if="row.credit > 0" class="text-success">Â¥{{ formatMoney(row.credit) }}</span> |
| | | <span v-else>-</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ¹å" width="80"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.direction === 'å' ? 'success' : 'danger'" size="small">{{ row.direction }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ä½é¢" width="150"> |
| | | <template #default="{ row }"> |
| | | <span :class="row.balance >= 0 ? 'text-primary' : 'text-warning'">Â¥{{ formatMoney(Math.abs(row.balance)) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <el-empty v-if="!currentSubject" description="è¯·éæ©ä¼è®¡ç§ç®æ¥è¯¢" style="margin-top: 50px;" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, computed } from "vue"; |
| | | import { ref, reactive, onMounted, computed, watch, nextTick } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { listAccountSubject } from "@/api/financialManagement/accountSubject"; |
| | | import { getGeneralLedger } from "@/api/financialManagement/ledger"; |
| | | |
| | | defineOptions({ |
| | | name: "ç§ç®æ»è´¦", |
| | | }); |
| | | |
| | | const filters = reactive({ |
| | | subject: [], |
| | | startMonth: "2024-01", |
| | | endMonth: "2024-03", |
| | | subject: "", |
| | | startMonth: "", |
| | | endMonth: "", |
| | | }); |
| | | |
| | | const dataList = ref([]); |
| | | const subjectOptions = ref([]); |
| | | const subjectKeyword = ref(""); |
| | | const subjectTreeRef = ref(); |
| | | |
| | | const subjectOptions = [ |
| | | { |
| | | code: "1001", |
| | | name: "åºåç°é", |
| | | children: [], |
| | | }, |
| | | { |
| | | code: "1002", |
| | | name: "é¶è¡å款", |
| | | children: [ |
| | | { code: "100201", name: "å·¥åé¶è¡" }, |
| | | { code: "100202", name: "建设é¶è¡" }, |
| | | ], |
| | | }, |
| | | { |
| | | code: "1122", |
| | | name: "åºæ¶è´¦æ¬¾", |
| | | children: [], |
| | | }, |
| | | { |
| | | code: "2202", |
| | | name: "åºä»è´¦æ¬¾", |
| | | children: [], |
| | | }, |
| | | { |
| | | code: "6001", |
| | | name: "主è¥ä¸å¡æ¶å
¥", |
| | | children: [], |
| | | }, |
| | | const getPreviousMonth = () => { |
| | | const date = new Date(); |
| | | date.setDate(1); |
| | | date.setMonth(date.getMonth() - 1); |
| | | const year = date.getFullYear(); |
| | | const month = String(date.getMonth() + 1).padStart(2, "0"); |
| | | return `${year}-${month}`; |
| | | }; |
| | | |
| | | const defaultMonth = getPreviousMonth(); |
| | | filters.startMonth = defaultMonth; |
| | | filters.endMonth = defaultMonth; |
| | | |
| | | const fallbackSubjects = [ |
| | | { code: "1001", name: "åºåç°é" }, |
| | | { code: "1002", name: "é¶è¡å款" }, |
| | | { code: "1122", name: "åºæ¶è´¦æ¬¾" }, |
| | | { code: "2202", name: "åºä»è´¦æ¬¾" }, |
| | | { code: "6001", name: "主è¥ä¸å¡æ¶å
¥" }, |
| | | ]; |
| | | |
| | | const currentSubject = computed(() => { |
| | | if (!filters.subject || filters.subject.length === 0) return null; |
| | | const code = filters.subject[filters.subject.length - 1]; |
| | | return findSubject(subjectOptions, code); |
| | | }); |
| | | const toTree = (nodes = []) => |
| | | nodes |
| | | .filter(item => item.subjectCode && item.subjectName) |
| | | .map(item => ({ |
| | | code: item.subjectCode, |
| | | name: item.subjectName, |
| | | children: toTree(item.children || []), |
| | | })); |
| | | |
| | | const findSubject = (options, code) => { |
| | | for (const item of options) { |
| | |
| | | return null; |
| | | }; |
| | | |
| | | const currentSubject = computed(() => { |
| | | if (!filters.subject) return null; |
| | | return findSubject(subjectOptions.value, filters.subject); |
| | | }); |
| | | |
| | | const getFirstSubjectCode = (nodes = []) => { |
| | | for (const item of nodes) { |
| | | if (item.code) return item.code; |
| | | if (item.children && item.children.length > 0) { |
| | | const childCode = getFirstSubjectCode(item.children); |
| | | if (childCode) return childCode; |
| | | } |
| | | } |
| | | return ""; |
| | | }; |
| | | |
| | | const setDefaultSubjectSelection = async () => { |
| | | const firstCode = getFirstSubjectCode(subjectOptions.value); |
| | | if (!firstCode) { |
| | | filters.subject = ""; |
| | | subjectTreeRef.value?.setCurrentKey(null); |
| | | return; |
| | | } |
| | | filters.subject = firstCode; |
| | | await nextTick(); |
| | | subjectTreeRef.value?.setCurrentKey(firstCode); |
| | | }; |
| | | |
| | | const filterSubjectNode = (value, data) => { |
| | | const keyword = value?.trim(); |
| | | if (!keyword) return true; |
| | | return `${data.code}${data.name}`.includes(keyword); |
| | | }; |
| | | |
| | | watch(subjectKeyword, (value) => { |
| | | subjectTreeRef.value?.filter(value || ""); |
| | | }); |
| | | |
| | | const handleSubjectClick = async (data) => { |
| | | filters.subject = data.code; |
| | | await getTableData(); |
| | | }; |
| | | |
| | | const loadSubjectOptions = async () => { |
| | | let options = []; |
| | | try { |
| | | const { data } = await listAccountSubject({ |
| | | current: 1, |
| | | size: 1000, |
| | | status: 0, |
| | | }); |
| | | options = toTree(data?.records || []); |
| | | } catch (error) { |
| | | // å
¨å±æ¦æªå¨å·²æç¤ºï¼ä¸é¢èµ°å
åºç§ç® |
| | | } |
| | | if (options.length === 0) { |
| | | options = fallbackSubjects.map(item => ({ ...item, children: [] })); |
| | | } |
| | | subjectOptions.value = options; |
| | | await setDefaultSubjectSelection(); |
| | | if (filters.subject) { |
| | | await getTableData(); |
| | | } |
| | | }; |
| | | |
| | | const formatMoney = (value) => { |
| | | if (value === undefined || value === null) return "0.00"; |
| | | return Number(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ","); |
| | | }; |
| | | |
| | | const mockData = [ |
| | | { date: "2024-01-01", voucherNo: "-", summary: "æåä½é¢", debit: 0, credit: 0, direction: "å", balance: 100000 }, |
| | | { date: "2024-01-05", voucherNo: "è®°-0001", summary: "é宿¶å
¥", debit: 5650, credit: 0, direction: "å", balance: 105650 }, |
| | | { date: "2024-01-10", voucherNo: "è®°-0002", summary: "éè´æ¯åº", debit: 0, credit: 8000, direction: "å", balance: 97650 }, |
| | | { date: "2024-01-15", voucherNo: "è®°-0003", summary: "æ¶å°è´§æ¬¾", debit: 10000, credit: 0, direction: "å", balance: 107650 }, |
| | | { date: "2024-01-20", voucherNo: "è®°-0004", summary: "æ¯ä»è´¹ç¨", debit: 0, credit: 5000, direction: "å", balance: 102650 }, |
| | | { date: "2024-01-31", voucherNo: "-", summary: "æ¬æå计", debit: 15650, credit: 13000, direction: "å", balance: 102650 }, |
| | | { date: "2024-02-01", voucherNo: "-", summary: "æåä½é¢", debit: 0, credit: 0, direction: "å", balance: 102650 }, |
| | | { date: "2024-02-10", voucherNo: "è®°-0005", summary: "é宿¶å
¥", debit: 8000, credit: 0, direction: "å", balance: 110650 }, |
| | | { date: "2024-02-15", voucherNo: "è®°-0006", summary: "éè´æ¯åº", debit: 0, credit: 12000, direction: "å", balance: 98650 }, |
| | | { date: "2024-02-28", voucherNo: "-", summary: "æ¬æå计", debit: 8000, credit: 12000, direction: "å", balance: 98650 }, |
| | | { date: "2024-03-01", voucherNo: "-", summary: "æåä½é¢", debit: 0, credit: 0, direction: "å", balance: 98650 }, |
| | | { date: "2024-03-05", voucherNo: "è®°-0007", summary: "é宿¶å
¥", debit: 12000, credit: 0, direction: "å", balance: 110650 }, |
| | | { date: "2024-03-10", voucherNo: "è®°-0008", summary: "æ¯ä»å·¥èµ", debit: 0, credit: 15000, direction: "å", balance: 95650 }, |
| | | { date: "2024-03-31", voucherNo: "-", summary: "æ¬æå计", debit: 12000, credit: 15000, direction: "å", balance: 95650 }, |
| | | { date: "2024-03-31", voucherNo: "-", summary: "æ¬å¹´ç´¯è®¡", debit: 35650, credit: 40000, direction: "å", balance: 95650 }, |
| | | ]; |
| | | |
| | | const getTableData = () => { |
| | | // èè°çº¦å®ï¼æ»è´¦æ¥å£è¿åè¡æ°ç»ï¼rowType/date/voucherNo/summary/debit/credit/direction/balanceï¼ |
| | | const getTableData = async () => { |
| | | if (!currentSubject.value) { |
| | | dataList.value = []; |
| | | return; |
| | | } |
| | | dataList.value = [...mockData]; |
| | | try { |
| | | const { data } = await getGeneralLedger({ |
| | | subjectCode: currentSubject.value.code, |
| | | startMonth: filters.startMonth, |
| | | endMonth: filters.endMonth, |
| | | }); |
| | | dataList.value = Array.isArray(data) ? data : data?.records || []; |
| | | } catch (error) { |
| | | // æç¤ºç±å
¨å±è¯·æ±æ¦æªå¨å¤çï¼è¿éä»
鲿¢æªæè·å¼å¸¸ |
| | | } |
| | | }; |
| | | |
| | | const resetFilters = () => { |
| | | filters.subject = []; |
| | | filters.startMonth = "2024-01"; |
| | | filters.endMonth = "2024-03"; |
| | | const resetFilters = async () => { |
| | | filters.startMonth = defaultMonth; |
| | | filters.endMonth = defaultMonth; |
| | | dataList.value = []; |
| | | }; |
| | | |
| | | const getSummaries = (param) => { |
| | | const { columns, data } = param; |
| | | const sums = []; |
| | | columns.forEach((column, index) => { |
| | | if (index === 0) { |
| | | sums[index] = "å计"; |
| | | return; |
| | | } |
| | | if (column.property === "debit") { |
| | | const values = data.map(item => Number(item.debit)); |
| | | const sum = values.reduce((prev, curr) => prev + curr, 0); |
| | | sums[index] = "Â¥" + formatMoney(sum); |
| | | } else if (column.property === "credit") { |
| | | const values = data.map(item => Number(item.credit)); |
| | | const sum = values.reduce((prev, curr) => prev + curr, 0); |
| | | sums[index] = "Â¥" + formatMoney(sum); |
| | | } else { |
| | | sums[index] = ""; |
| | | } |
| | | }); |
| | | return sums; |
| | | subjectKeyword.value = ""; |
| | | subjectTreeRef.value?.filter(""); |
| | | await setDefaultSubjectSelection(); |
| | | if (filters.subject) { |
| | | await getTableData(); |
| | | } |
| | | }; |
| | | |
| | | const handlePrint = () => { |
| | |
| | | ElMessage.success("å¯¼åºæå"); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | // é»è®¤ä¸å è½½æ°æ®ï¼éè¦éæ©ç§ç® |
| | | onMounted(async () => { |
| | | await loadSubjectOptions(); |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .ledger-header { |
| | | text-align: center; |
| | | margin-bottom: 20px; |
| | | h2 { |
| | | margin: 0 0 10px 0; |
| | | } |
| | | p { |
| | | color: #606266; |
| | | margin: 5px 0; |
| | | } |
| | | .ledger-layout { |
| | | display: flex; |
| | | gap: 16px; |
| | | } |
| | | |
| | | .subject-panel { |
| | | width: 260px; |
| | | flex-shrink: 0; |
| | | padding: 12px; |
| | | border: 1px solid #e4e7ed; |
| | | border-radius: 8px; |
| | | background-color: #fff; |
| | | } |
| | | |
| | | .subject-tree-scroll { |
| | | height: 600px; |
| | | margin-top: 12px; |
| | | } |
| | | |
| | | .subject-node { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .ledger-content { |
| | | flex: 1; |
| | | min-width: 0; |
| | | } |
| | | |
| | | .filter-form { |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .text-primary { |
| | |
| | | color: #e6a23c; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .subject-panel :deep(.el-tree-node__content) { |
| | | height: 34px; |
| | | } |
| | | |
| | | .subject-panel :deep(.el-tree-node.is-current > .el-tree-node__content) { |
| | | background-color: #f0f7ff; |
| | | } |
| | | </style> |
| | |
| | | </el-form-item> |
| | | <el-form-item label="å¶å人:"> |
| | | <el-select v-model="filters.creator" placeholder="è¯·éæ©å¶å人" clearable style="width: 150px;"> |
| | | <el-option label="å¼ ä¸" value="å¼ ä¸" /> |
| | | <el-option label="æå" value="æå" /> |
| | | <el-option label="çäº" value="çäº" /> |
| | | <el-option |
| | | v-for="item in creatorOptions" |
| | | :key="item" |
| | | :label="item" |
| | | :value="item" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æ:"> |
| | |
| | | <div class="table_list"> |
| | | <div class="actions"> |
| | | <div> |
| | | <el-statistic title="åæ¹å计" :value="totalDebit" precision="2" prefix="Â¥" /> |
| | | <el-statistic title="è´·æ¹å计" :value="totalCredit" precision="2" prefix="Â¥" style="margin-left: 30px;" /> |
| | | <el-statistic title="åæ¹å计" :value="totalDebit" :precision="2" prefix="Â¥" /> |
| | | <el-statistic title="è´·æ¹å计" :value="totalCredit" :precision="2" prefix="Â¥" style="margin-left: 30px;" /> |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" @click="add" icon="Plus">æ°å¢åè¯</el-button> |
| | | <el-button @click="handleImport" icon="Upload">导å
¥</el-button> |
| | | <el-button @click="handleOut" icon="Download">导åº</el-button> |
| | | <!-- <el-button @click="handleImport" icon="Upload">导å
¥</el-button> --> |
| | | <!-- <el-button @click="handleOut" icon="Download">导åº</el-button> --> |
| | | </div> |
| | | </div> |
| | | <PIMTable |
| | |
| | | </template> |
| | | <template #operation="{ row }"> |
| | | <el-button type="primary" link @click="view(row)">æ¥ç</el-button> |
| | | <el-button type="primary" link @click="edit(row)" v-if="row.status === 'unposted'">ç¼è¾</el-button> |
| | | <el-button type="success" link @click="handlePost(row)" v-if="row.status === 'unposted'">è¿è´¦</el-button> |
| | | <el-button type="danger" link @click="handleCancel(row)" v-if="row.status === 'unposted'">ä½åº</el-button> |
| | | <el-button type="primary" link @click="edit(row)" v-if="canEditVoucher(row.status)">ç¼è¾</el-button> |
| | | <el-button type="success" link @click="handlePost(row)" v-if="canEditVoucher(row.status)">è¿è´¦</el-button> |
| | | <el-button type="danger" link @click="handleCancel(row)" v-if="canEditVoucher(row.status)">ä½åº</el-button> |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | |
| | | <h2 class="voucher-title">è®°è´¦åè¯</h2> |
| | | <div class="voucher-period">{{ form.voucherDate ? form.voucherDate.substring(0, 7) + 'æ' : '' }}</div> |
| | | </div> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="0"> |
| | | <el-form :model="form" :rules="rules" :disabled="isViewMode" ref="formRef" label-width="0"> |
| | | <div class="voucher-info"> |
| | | <div class="voucher-no-section"> |
| | | <span class="label">åè¯åï¼</span> |
| | | <el-select v-model="form.voucherPrefix" style="width: 70px;"> |
| | | <el-select v-model="form.voucherPrefix" :disabled="isViewMode" style="width: 70px;"> |
| | | <el-option label="è®°" value="è®°" /> |
| | | <el-option label="ç°" value="ç°" /> |
| | | <el-option label="é¶" value="é¶" /> |
| | | <el-option label="转" value="转" /> |
| | | <el-option label="æ¶" value="æ¶" /> |
| | | <el-option label="ä»" value="ä»" /> |
| | | </el-select> |
| | | <el-input v-model="form.voucherNum" style="width: 60px;" /> |
| | | <el-input v-model="form.voucherNum" :disabled="isViewMode" style="width: 60px;" /> |
| | | <span class="label" style="margin-left: 5px;">å·</span> |
| | | </div> |
| | | <div class="voucher-date-section"> |
| | | <span class="label">æ¥æï¼</span> |
| | | <el-date-picker v-model="form.voucherDate" type="date" placeholder="éæ©æ¥æ" value-format="YYYY-MM-DD" style="width: 140px;" /> |
| | | <el-date-picker v-model="form.voucherDate" :disabled="isViewMode" type="date" placeholder="éæ©æ¥æ" value-format="YYYY-MM-DD" style="width: 140px;" /> |
| | | </div> |
| | | <div class="voucher-attachment-section"> |
| | | <span class="label">éä»¶ï¼</span> |
| | | <el-input-number v-model="form.attachmentCount" :min="0" :controls="false" style="width: 60px;" /> |
| | | <el-input-number v-model="form.attachmentCount" :disabled="isViewMode" :min="0" :controls="false" style="width: 60px;" /> |
| | | <span class="label" style="margin-left: 5px;">å¼ </span> |
| | | <el-button type="primary" link style="margin-left: 10px;">ä¸ä¼ æä»¶</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="voucher-table"> |
| | |
| | | <tbody> |
| | | <tr v-for="(entry, rowIndex) in form.entries" :key="rowIndex" @click="selectRow(rowIndex)" :class="{ 'selected-row': selectedRowIndex === rowIndex }"> |
| | | <td class="col-summary"> |
| | | <el-input v-model="entry.summary" placeholder="请è¾å
¥æè¦" @focus="selectRow(rowIndex)" /> |
| | | <el-input v-model="entry.summary" :disabled="isViewMode" placeholder="请è¾å
¥æè¦" @focus="selectRow(rowIndex)" /> |
| | | </td> |
| | | <td class="col-subject"> |
| | | <el-select v-model="entry.subjectCode" placeholder="éæ©ç§ç®" filterable @change="(val) => handleSubjectChange(val, rowIndex)" @focus="selectRow(rowIndex)"> |
| | | <el-option v-for="item in subjectList" :key="item.code" :label="item.code + item.name" :value="item.code" /> |
| | | </el-select> |
| | | <div class="subject-name">{{ entry.subjectName }}</div> |
| | | <el-tree-select |
| | | v-model="entry.subjectCode" |
| | | :data="subjectTreeOptions" |
| | | :props="subjectTreeSelectProps" |
| | | :disabled="isViewMode" |
| | | placeholder="éæ©ç§ç®" |
| | | filterable |
| | | check-strictly |
| | | clearable |
| | | :render-after-expand="false" |
| | | @change="(val) => handleSubjectChange(val, rowIndex)" |
| | | @focus="selectRow(rowIndex)" |
| | | /> |
| | | <!-- <div class="subject-name">{{ entry.subjectName }}</div> --> |
| | | </td> |
| | | <!-- åæ¹11å --> |
| | | <template v-if="editingCell.row === rowIndex && editingCell.type === 'debit'"> |
| | | <td colspan="11" class="debit-input-cell"> |
| | | <el-input-number ref="amountInputRef" v-model="entry.debit" :min="0" :precision="2" :controls="false" size="small" @blur="finishEdit" class="full-width-input" /> |
| | | <el-input-number ref="amountInputRef" v-model="entry.debit" :disabled="isViewMode" :min="0" :precision="2" :controls="false" :value-on-clear="undefined" size="small" @blur="finishEdit" class="full-width-input" /> |
| | | </td> |
| | | </template> |
| | | <template v-else> |
| | |
| | | <!-- è´·æ¹11å --> |
| | | <template v-if="editingCell.row === rowIndex && editingCell.type === 'credit'"> |
| | | <td colspan="11" class="credit-input-cell"> |
| | | <el-input-number ref="amountInputRef" v-model="entry.credit" :min="0" :precision="2" :controls="false" size="small" @blur="finishEdit" class="full-width-input" /> |
| | | <el-input-number ref="amountInputRef" v-model="entry.credit" :disabled="isViewMode" :min="0" :precision="2" :controls="false" :value-on-clear="undefined" size="small" @blur="finishEdit" class="full-width-input" /> |
| | | </td> |
| | | </template> |
| | | <template v-else> |
| | |
| | | </td> |
| | | </template> |
| | | <td class="col-action"> |
| | | <el-button type="danger" link size="small" @click="removeEntry(rowIndex)" icon="Delete" :disabled="form.entries.length <= 2">å é¤</el-button> |
| | | <el-button type="danger" link size="small" @click="removeEntry(rowIndex)" icon="Delete" :disabled="isViewMode || form.entries.length <= 2">å é¤</el-button> |
| | | </td> |
| | | </tr> |
| | | <tr class="total-row"> |
| | |
| | | </table> |
| | | </div> |
| | | <div class="voucher-toolbar"> |
| | | <el-button type="primary" link @click="addEntry" icon="Plus">æ°å¢è¡</el-button> |
| | | <el-button type="primary" link @click="addEntry" icon="Plus" :disabled="isViewMode">æ°å¢è¡</el-button> |
| | | </div> |
| | | <div class="voucher-footer"> |
| | | <div class="creator-section"> |
| | | <span class="label">å¶å人ï¼{{ form.creator }}</span> |
| | | <span class="label">å¶å人ï¼</span> |
| | | <el-select |
| | | v-model="form.creator" |
| | | :disabled="isViewMode" |
| | | placeholder="è¯·éæ©å¶å人" |
| | | filterable |
| | | clearable |
| | | style="width: 200px;" |
| | | > |
| | | <el-option |
| | | v-for="item in creatorOptions" |
| | | :key="item" |
| | | :label="item" |
| | | :value="item" |
| | | /> |
| | | </el-select> |
| | | </div> |
| | | </div> |
| | | <!-- ç¼è¾æ¨¡å¼ï¼ä½¿ç¨ AttachmentUploadFile ä¸ä¼ ç»ä»¶ --> |
| | | <div class="voucher-attachment-upload" v-if="!isViewMode"> |
| | | <div class="attachment-label">éä»¶ä¸ä¼ ï¼</div> |
| | | <AttachmentUploadFile |
| | | v-model:fileList="form.attachments" |
| | | :disabled="isViewMode" |
| | | :limit="10" |
| | | :fileSize="50" |
| | | buttonText="ç¹å»ä¸ä¼ éä»¶" |
| | | @change="handleAttachmentChange" |
| | | /> |
| | | </div> |
| | | </el-form> |
| | | <!-- æ¥ç模å¼ï¼å±ç¤ºéä»¶åè¡¨ï¼æ¾å¨ el-form å¤é¢ï¼é¿å
被 disabledï¼ --> |
| | | <div class="voucher-attachment-upload" v-if="isViewMode && form.attachments?.length"> |
| | | <div class="attachment-label">éä»¶å表ï¼</div> |
| | | <el-table :data="form.attachments" border class="attachment-table"> |
| | | <el-table-column label="éä»¶åç§°" show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | {{ scope.row.originalFilename || scope.row.name || scope.row.fileName || 'æªå½åæä»¶' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column fixed="right" label="æä½" width="150" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" @click="previewFile(scope.row)">é¢è§</el-button> |
| | | <el-button link type="primary" size="small" @click="downloadFile(scope.row)">ä¸è½½</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | <template #footer> |
| | | <div> |
| | | <el-button type="primary" @click="submitForm" :disabled="!isBalanced">ä¿å</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button v-if="!isViewMode" type="primary" @click="submitForm" :disabled="!isBalanced">ä¿å</el-button> |
| | | <el-button @click="dialogVisible = false">{{ isViewMode ? 'å
³é' : 'åæ¶' }}</el-button> |
| | | </div> |
| | | </template> |
| | | </FormDialog> |
| | | <!-- æä»¶é¢è§ç»ä»¶ --> |
| | | <FilePreview ref="filePreviewRef" /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import { ref, reactive, onMounted, computed, nextTick } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import AttachmentUploadFile from "@/components/AttachmentUpload/file/index.vue"; |
| | | import FileList from "@/components/Dialog/FileList.vue"; |
| | | import FilePreview from "@/components/filePreview/index.vue"; |
| | | import download from "@/plugins/download.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { userListNoPageByTenantId } from "@/api/system/user"; |
| | | import { listAccountSubject } from "@/api/financialManagement/accountSubject"; |
| | | import { |
| | | listVoucherPage, |
| | | addVoucher, |
| | | updateVoucher, |
| | | postVoucher, |
| | | cancelVoucher, |
| | | getVoucherDetail, |
| | | } from "@/api/financialManagement/voucher"; |
| | | |
| | | defineOptions({ |
| | | name: "åè¯ç®¡ç", |
| | | }); |
| | | |
| | | const userStore = useUserStore(); |
| | | const getDefaultCreator = () => userStore.nickName || userStore.name || "å¼ ä¸"; |
| | | |
| | | const filters = reactive({ |
| | | voucherNo: "", |
| | |
| | | { label: "åè¯åå·", prop: "voucherNo", width: "120" }, |
| | | { label: "åè¯æ¥æ", prop: "voucherDate", width: "120" }, |
| | | { label: "æè¦", prop: "summary", showOverflowTooltip: true }, |
| | | { label: "åæ¹éé¢", prop: "debit", slot: "debit" }, |
| | | { label: "è´·æ¹éé¢", prop: "credit", slot: "credit" }, |
| | | { label: "åæ¹éé¢", prop: "debit", dataType: "slot", slot: "debit" }, |
| | | { label: "è´·æ¹éé¢", prop: "credit", dataType: "slot", slot: "credit" }, |
| | | { label: "å¶å人", prop: "creator", width: "100" }, |
| | | { label: "ç¶æ", prop: "status", slot: "status" }, |
| | | { label: "æä½", prop: "operation", slot: "operation", width: "220", fixed: "right" }, |
| | | { label: "ç¶æ", prop: "status", dataType: "slot", slot: "status" }, |
| | | { label: "æä½", prop: "operation", dataType: "slot", slot: "operation", width: "220", fixed: "right" }, |
| | | ]; |
| | | |
| | | const dataList = ref([]); |
| | | const dialogVisible = ref(false); |
| | | const dialogTitle = ref(""); |
| | | const formRef = ref(null); |
| | | const dialogMode = ref("add"); |
| | | const isEdit = ref(false); |
| | | const currentId = ref(null); |
| | | const isViewMode = computed(() => dialogMode.value === "view"); |
| | | const filePreviewRef = ref(null); |
| | | |
| | | const subjectList = [ |
| | | { code: "1001", name: "åºåç°é" }, |
| | | { code: "1002", name: "é¶è¡å款" }, |
| | | { code: "1122", name: "åºæ¶è´¦æ¬¾" }, |
| | | { code: "2202", name: "åºä»è´¦æ¬¾" }, |
| | | { code: "5001", name: "çäº§ææ¬" }, |
| | | { code: "6001", name: "主è¥ä¸å¡æ¶å
¥" }, |
| | | { code: "6401", name: "主è¥ä¸å¡ææ¬" }, |
| | | const fallbackSubjectTree = [ |
| | | { subjectCode: "1001", subjectName: "åºåç°é", balanceDirection: "åæ¹", children: [] }, |
| | | { subjectCode: "1002", subjectName: "é¶è¡å款", balanceDirection: "åæ¹", children: [] }, |
| | | { subjectCode: "1122", subjectName: "åºæ¶è´¦æ¬¾", balanceDirection: "åæ¹", children: [] }, |
| | | { subjectCode: "2202", subjectName: "åºä»è´¦æ¬¾", balanceDirection: "è´·æ¹", children: [] }, |
| | | { subjectCode: "5001", subjectName: "çäº§ææ¬", balanceDirection: "åæ¹", children: [] }, |
| | | { subjectCode: "6001", subjectName: "主è¥ä¸å¡æ¶å
¥", balanceDirection: "è´·æ¹", children: [] }, |
| | | { subjectCode: "6401", subjectName: "主è¥ä¸å¡ææ¬", balanceDirection: "åæ¹", children: [] }, |
| | | ]; |
| | | |
| | | const form = reactive({ |
| | | const subjectTreeOptions = ref([]); |
| | | const subjectList = ref([]); |
| | | const subjectTreeSelectProps = { |
| | | children: "children", |
| | | label: "label", |
| | | value: "value", |
| | | }; |
| | | |
| | | const buildSubjectTreeOptions = (nodes = [], flatList = []) => |
| | | (nodes || []) |
| | | .filter(item => item.subjectCode && item.subjectName) |
| | | .map(item => { |
| | | const balanceDirection = item.balanceDirection || ""; |
| | | const flatItem = { |
| | | code: item.subjectCode, |
| | | name: item.subjectName, |
| | | balanceDirection, |
| | | }; |
| | | flatList.push(flatItem); |
| | | return { |
| | | value: flatItem.code, |
| | | label: `${flatItem.code} ${flatItem.name}${balanceDirection ? ` [${balanceDirection}]` : ""}`, |
| | | children: buildSubjectTreeOptions(item.children || [], flatList), |
| | | }; |
| | | }); |
| | | |
| | | const createEmptyEntry = () => ({ |
| | | subjectCode: "", |
| | | subjectName: "", |
| | | balanceDirection: "", |
| | | summary: "", |
| | | debit: undefined, |
| | | credit: undefined, |
| | | }); |
| | | |
| | | const createDefaultForm = () => ({ |
| | | voucherNo: "", |
| | | voucherPrefix: "è®°", |
| | | voucherNum: "", |
| | | voucherDate: "", |
| | | attachmentCount: 0, |
| | | entries: [], |
| | | creator: "å¼ ä¸", |
| | | attachments: [], |
| | | entries: [createEmptyEntry(), createEmptyEntry()], |
| | | creator: getDefaultCreator(), |
| | | remark: "", |
| | | }); |
| | | |
| | | const form = reactive({ |
| | | ...createDefaultForm(), |
| | | }); |
| | | |
| | | const userOptions = ref([]); |
| | | |
| | | const creatorOptions = computed(() => { |
| | | const source = [ |
| | | ...userOptions.value.map(item => item.nickName || item.userName || item.name), |
| | | getDefaultCreator(), |
| | | form.creator, |
| | | filters.creator, |
| | | ]; |
| | | return [...new Set(source.filter(Boolean))]; |
| | | }); |
| | | |
| | | const selectedRowIndex = ref(-1); |
| | |
| | | const rules = { |
| | | voucherDate: [{ required: true, message: "è¯·éæ©åè¯æ¥æ", trigger: "change" }], |
| | | }; |
| | | |
| | | const mockData = [ |
| | | { id: 1, voucherNo: "è®°-0001", voucherDate: "2024-01-15", summary: "é宿¶å
¥", debit: 5650, credit: 5650, creator: "å¼ ä¸", status: "posted", entries: [{ subjectCode: "1002", subjectName: "é¶è¡å款", summary: "é宿¶å
¥", debit: 5650, credit: 0 }, { subjectCode: "6001", subjectName: "主è¥ä¸å¡æ¶å
¥", summary: "é宿¶å
¥", debit: 0, credit: 5000 }, { subjectCode: "2221", subjectName: "åºäº¤ç¨è´¹", summary: "é项ç¨é¢", debit: 0, credit: 650 }] }, |
| | | { id: 2, voucherNo: "è®°-0002", voucherDate: "2024-01-16", summary: "éè´åææ", debit: 9040, credit: 9040, creator: "æå", status: "unposted", entries: [{ subjectCode: "5001", subjectName: "çäº§ææ¬", summary: "éè´åææ", debit: 8000, credit: 0 }, { subjectCode: "2221", subjectName: "åºäº¤ç¨è´¹", summary: "è¿é¡¹ç¨é¢", debit: 1040, credit: 0 }, { subjectCode: "2202", subjectName: "åºä»è´¦æ¬¾", summary: "éè´åææ", debit: 0, credit: 9040 }] }, |
| | | { id: 3, voucherNo: "è®°-0003", voucherDate: "2024-01-18", summary: "æ¯ä»è´§æ¬¾", debit: 5000, credit: 5000, creator: "å¼ ä¸", status: "posted", entries: [{ subjectCode: "2202", subjectName: "åºä»è´¦æ¬¾", summary: "æ¯ä»è´§æ¬¾", debit: 5000, credit: 0 }, { subjectCode: "1002", subjectName: "é¶è¡å款", summary: "æ¯ä»è´§æ¬¾", debit: 0, credit: 5000 }] }, |
| | | ]; |
| | | |
| | | const totalDebit = computed(() => { |
| | | return dataList.value.reduce((sum, item) => sum + Number(item.debit), 0); |
| | |
| | | return Number(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ","); |
| | | }; |
| | | |
| | | const normalizeVoucherStatus = status => String(status || "").toLowerCase(); |
| | | |
| | | const canEditVoucher = status => { |
| | | const key = normalizeVoucherStatus(status); |
| | | return key === "unposted" || status === "æªè¿è´¦"; |
| | | }; |
| | | |
| | | const getStatusLabel = (status) => { |
| | | const key = normalizeVoucherStatus(status); |
| | | const map = { unposted: "æªè¿è´¦", posted: "å·²è¿è´¦", cancelled: "å·²ä½åº" }; |
| | | return map[status] || status; |
| | | return map[key] || status; |
| | | }; |
| | | |
| | | const getStatusType = (status) => { |
| | | const key = normalizeVoucherStatus(status); |
| | | const map = { unposted: "warning", posted: "success", cancelled: "info" }; |
| | | return map[status] || ""; |
| | | return map[key] || ""; |
| | | }; |
| | | |
| | | const getTableData = () => { |
| | | let result = [...mockData]; |
| | | if (filters.voucherNo) { |
| | | result = result.filter(item => item.voucherNo.includes(filters.voucherNo)); |
| | | // èè°çº¦å®ï¼åé¡µåæ°ä½¿ç¨ current/sizeï¼æ¥æèå´æå为 startDate/endDate |
| | | const getTableData = async () => { |
| | | try { |
| | | const [startDate, endDate] = |
| | | filters.dateRange && filters.dateRange.length === 2 ? filters.dateRange : ["", ""]; |
| | | const { data } = await listVoucherPage({ |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | voucherNo: filters.voucherNo, |
| | | creator: filters.creator, |
| | | status: filters.status, |
| | | startDate, |
| | | endDate, |
| | | }); |
| | | dataList.value = data?.records || []; |
| | | pagination.total = Number(data?.total || 0); |
| | | } catch (error) { |
| | | // æç¤ºç±å
¨å±è¯·æ±æ¦æªå¨å¤çï¼è¿éä»
鲿¢æªæè·å¼å¸¸ |
| | | } |
| | | if (filters.dateRange && filters.dateRange.length === 2) { |
| | | result = result.filter(item => item.voucherDate >= filters.dateRange[0] && item.voucherDate <= filters.dateRange[1]); |
| | | }; |
| | | |
| | | // åè¯åå½éçç§ç®ä¸æä¸æ»è´¦ç§ç®ä¿æä¸è´ï¼é¿å
æäº¤ä¸åå¨ç§ç® |
| | | const loadSubjectList = async () => { |
| | | try { |
| | | const { data } = await listAccountSubject({ |
| | | current: 1, |
| | | size: 1000, |
| | | status: 0 |
| | | }); |
| | | const flatList = []; |
| | | const treeOptions = buildSubjectTreeOptions(data?.records || [], flatList); |
| | | if (treeOptions.length > 0) { |
| | | subjectTreeOptions.value = treeOptions; |
| | | subjectList.value = flatList; |
| | | return; |
| | | } |
| | | const fallbackFlatList = []; |
| | | subjectTreeOptions.value = buildSubjectTreeOptions(fallbackSubjectTree, fallbackFlatList); |
| | | subjectList.value = fallbackFlatList; |
| | | } catch (error) { |
| | | // å
¨å±æ¦æªå¨å·²æç¤ºé误ï¼è¿éä¿çé»è®¤ç§ç®ä½ä¸ºå
åº |
| | | const fallbackFlatList = []; |
| | | subjectTreeOptions.value = buildSubjectTreeOptions(fallbackSubjectTree, fallbackFlatList); |
| | | subjectList.value = fallbackFlatList; |
| | | } |
| | | if (filters.creator) { |
| | | result = result.filter(item => item.creator === filters.creator); |
| | | }; |
| | | |
| | | const loadUserOptions = async () => { |
| | | try { |
| | | const { data } = await userListNoPageByTenantId(); |
| | | userOptions.value = Array.isArray(data) ? data : []; |
| | | } catch (error) { |
| | | userOptions.value = []; |
| | | } |
| | | if (filters.status) { |
| | | result = result.filter(item => item.status === filters.status); |
| | | } |
| | | pagination.total = result.length; |
| | | dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize); |
| | | }; |
| | | |
| | | const resetFilters = () => { |
| | |
| | | }; |
| | | |
| | | const addEntry = () => { |
| | | form.entries.push({ subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 }); |
| | | if (isViewMode.value) { |
| | | return; |
| | | } |
| | | form.entries.push(createEmptyEntry()); |
| | | }; |
| | | |
| | | const handleAttachmentChange = (fileList) => { |
| | | form.attachmentCount = fileList?.length || 0; |
| | | }; |
| | | |
| | | // 使ç¨é¡¹ç®å°è£
ç filePreview ç»ä»¶é¢è§æä»¶ |
| | | const previewFile = (row) => { |
| | | const url = row.previewURL || row.previewUrl || row.url; |
| | | if (url && filePreviewRef.value) { |
| | | filePreviewRef.value.open(url); |
| | | } else { |
| | | ElMessage.warning('æä»¶å°åæ æï¼æ æ³é¢è§'); |
| | | } |
| | | }; |
| | | |
| | | // 使ç¨é¡¹ç®å°è£
ç download æä»¶ä¸è½½æä»¶ |
| | | const downloadFile = (row) => { |
| | | const url = row.downloadURL || row.downloadUrl || row.url; |
| | | if (url) { |
| | | const filename = row.originalFilename || row.name || row.fileName || 'download'; |
| | | download.byUrl(url, filename); |
| | | } else { |
| | | ElMessage.warning('æä»¶å°åæ æï¼æ æ³ä¸è½½'); |
| | | } |
| | | }; |
| | | |
| | | const selectRow = (index) => { |
| | |
| | | }; |
| | | |
| | | const openAmountInput = (index, type) => { |
| | | if (isViewMode.value) { |
| | | return; |
| | | } |
| | | editingCell.row = index; |
| | | editingCell.type = type; |
| | | nextTick(() => { |
| | |
| | | }; |
| | | |
| | | const removeEntry = (index) => { |
| | | if (isViewMode.value) { |
| | | return; |
| | | } |
| | | if (form.entries.length <= 2) { |
| | | return; |
| | | } |
| | | form.entries.splice(index, 1); |
| | | calculateTotal(); |
| | | }; |
| | | |
| | | const handleSubjectChange = (val, index) => { |
| | | const subject = subjectList.find(item => item.code === val); |
| | | const subject = subjectList.value.find(item => item.code === val); |
| | | if (subject) { |
| | | form.entries[index].subjectName = subject.name; |
| | | form.entries[index].balanceDirection = subject.balanceDirection || ""; |
| | | } else { |
| | | form.entries[index].subjectName = ""; |
| | | form.entries[index].balanceDirection = ""; |
| | | } |
| | | }; |
| | | |
| | | const calculateTotal = () => { |
| | | // èªå¨è®¡ç®ï¼ç±computed屿§å¤ç |
| | | }; |
| | | |
| | | const add = () => { |
| | | dialogMode.value = "add"; |
| | | isEdit.value = false; |
| | | currentId.value = null; |
| | | dialogTitle.value = "æ°å¢åè¯"; |
| | | const nextNum = String(mockData.length + 1).padStart(2, "0"); |
| | | Object.assign(form, { |
| | | voucherNo: "è®°-" + nextNum, |
| | | const nextNum = String((pagination.total || 0) + 1).padStart(4, "0"); |
| | | Object.assign(form, createDefaultForm(), { |
| | | voucherPrefix: "è®°", |
| | | voucherNum: nextNum, |
| | | voucherNo: `è®°-${nextNum}`, |
| | | voucherDate: new Date().toISOString().split('T')[0], |
| | | attachmentCount: 0, |
| | | entries: [ |
| | | { subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 }, |
| | | { subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 }, |
| | | { subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 }, |
| | | { subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 }, |
| | | ], |
| | | creator: "å¼ ä¸", |
| | | remark: "", |
| | | }); |
| | | selectedRowIndex.value = 0; |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const edit = (row) => { |
| | | isEdit.value = true; |
| | | currentId.value = row.id; |
| | | dialogTitle.value = "ç¼è¾åè¯"; |
| | | const parts = row.voucherNo.split('-'); |
| | | Object.assign(form, { |
| | | ...row, |
| | | voucherPrefix: parts[0] || 'è®°', |
| | | voucherNum: parts[1] || '', |
| | | }); |
| | | if (form.entries.length < 4) { |
| | | while (form.entries.length < 4) { |
| | | form.entries.push({ subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 }); |
| | | const openVoucherDialog = async (row, mode = "edit") => { |
| | | try { |
| | | dialogMode.value = mode; |
| | | isEdit.value = mode === "edit"; |
| | | currentId.value = row.id; |
| | | dialogTitle.value = mode === "view" ? "æ¥çåè¯" : "ç¼è¾åè¯"; |
| | | const { data } = await getVoucherDetail(row.id); |
| | | const detail = data || row; |
| | | const parts = (detail.voucherNo || "").split("-"); |
| | | const attachments = detail.storageBlobVOList || detail.storageBlobDTOs || detail.attachments || []; |
| | | Object.assign(form, createDefaultForm(), { |
| | | ...detail, |
| | | voucherPrefix: parts[0] || "è®°", |
| | | voucherNum: parts[1] || "", |
| | | creator: detail.creator || getDefaultCreator(), |
| | | attachments, |
| | | entries: |
| | | detail.entries?.map(item => ({ |
| | | subjectCode: item.subjectCode || "", |
| | | subjectName: item.subjectName || "", |
| | | balanceDirection: item.balanceDirection || "", |
| | | summary: item.summary || "", |
| | | debit: Number(item.debit || 0), |
| | | credit: Number(item.credit || 0), |
| | | })) || [], |
| | | }); |
| | | if (form.entries.length < 2) { |
| | | while (form.entries.length < 2) { |
| | | form.entries.push(createEmptyEntry()); |
| | | } |
| | | } |
| | | selectedRowIndex.value = 0; |
| | | dialogVisible.value = true; |
| | | } catch (error) { |
| | | // æç¤ºç±å
¨å±è¯·æ±æ¦æªå¨å¤çï¼è¿éä»
鲿¢æªæè·å¼å¸¸ |
| | | } |
| | | selectedRowIndex.value = 0; |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const view = (row) => { |
| | | ElMessage.info(`æ¥çåè¯: ${row.voucherNo}`); |
| | | const edit = async row => { |
| | | await openVoucherDialog(row, "edit"); |
| | | }; |
| | | |
| | | const view = async row => { |
| | | await openVoucherDialog(row, "view"); |
| | | }; |
| | | |
| | | const handlePost = (row) => { |
| | |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "info", |
| | | }).then(() => { |
| | | const index = mockData.findIndex(item => item.id === row.id); |
| | | if (index !== -1) { |
| | | mockData[index].status = "posted"; |
| | | } |
| | | }).then(async () => { |
| | | await postVoucher({ id: row.id }); |
| | | ElMessage.success("è¿è´¦æå"); |
| | | getTableData(); |
| | | await getTableData(); |
| | | }); |
| | | }; |
| | | |
| | |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }).then(() => { |
| | | const index = mockData.findIndex(item => item.id === row.id); |
| | | if (index !== -1) { |
| | | mockData[index].status = "cancelled"; |
| | | } |
| | | }).then(async () => { |
| | | await cancelVoucher({ id: row.id }); |
| | | ElMessage.success("ä½åºæå"); |
| | | getTableData(); |
| | | await getTableData(); |
| | | }); |
| | | }; |
| | | |
| | |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | formRef.value.validate((valid) => { |
| | | if (isViewMode.value) { |
| | | dialogVisible.value = false; |
| | | return; |
| | | } |
| | | formRef.value.validate(async valid => { |
| | | if (valid) { |
| | | // åç½®æ ¡éªï¼ä¸å端è§å对é½ï¼åå°æ æè¯·æ± |
| | | if (!isBalanced.value) { |
| | | ElMessage.error("åè´·ä¸å¹³è¡¡ï¼è¯·æ£æ¥åå½"); |
| | | return; |
| | | } |
| | | |
| | | const validEntries = form.entries.filter(e => e.subjectCode && (e.debit > 0 || e.credit > 0)); |
| | | const validEntries = form.entries.filter( |
| | | entry => entry.subjectCode && (Number(entry.debit) > 0 || Number(entry.credit) > 0) |
| | | ); |
| | | if (validEntries.length === 0) { |
| | | ElMessage.error("请è³å°å¡«å䏿¡ææåå½"); |
| | | return; |
| | | } |
| | | |
| | | const invalidEntry = validEntries.find( |
| | | entry => Number(entry.debit) > 0 && Number(entry.credit) > 0 |
| | | ); |
| | | if (invalidEntry) { |
| | | ElMessage.error("åä¸åå½ä¸è½åæ¶å¡«ååæ¹åè´·æ¹"); |
| | | return; |
| | | } |
| | | |
| | | const summary = validEntries.find(e => e.debit > 0)?.summary || ""; |
| | | |
| | | const voucherNo = `${form.voucherPrefix}-${form.voucherNum}`; |
| | | const dataToSave = { |
| | | ...form, |
| | | voucherNo, |
| | | voucherDate: form.voucherDate, |
| | | summary, |
| | | creator: form.creator, |
| | | attachmentCount: Number(form.attachmentCount || 0), |
| | | remark: form.remark, |
| | | debit: totalDebitEntry.value, |
| | | credit: totalCreditEntry.value, |
| | | entries: validEntries, |
| | | storageBlobDTOs: form.attachments || [], |
| | | entries: validEntries.map(entry => ({ |
| | | subjectCode: entry.subjectCode, |
| | | subjectName: entry.subjectName, |
| | | summary: entry.summary, |
| | | debit: Number(entry.debit || 0), |
| | | credit: Number(entry.credit || 0), |
| | | })), |
| | | }; |
| | | |
| | | if (isEdit.value) { |
| | | const index = mockData.findIndex(item => item.id === currentId.value); |
| | | if (index !== -1) { |
| | | mockData[index] = { ...mockData[index], ...dataToSave }; |
| | | try { |
| | | if (isEdit.value) { |
| | | await updateVoucher({ |
| | | id: currentId.value, |
| | | ...dataToSave, |
| | | }); |
| | | ElMessage.success("ç¼è¾æå"); |
| | | } else { |
| | | await addVoucher(dataToSave); |
| | | ElMessage.success("æ°å¢æå"); |
| | | } |
| | | ElMessage.success("ç¼è¾æå"); |
| | | } else { |
| | | const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1; |
| | | mockData.push({ id: newId, ...dataToSave, status: "unposted" }); |
| | | ElMessage.success("æ°å¢æå"); |
| | | dialogVisible.value = false; |
| | | await getTableData(); |
| | | } catch (error) { |
| | | // æç¤ºç±å
¨å±è¯·æ±æ¦æªå¨å¤çï¼è¿éä»
鲿¢æªæè·å¼å¸¸ |
| | | } |
| | | dialogVisible.value = false; |
| | | getTableData(); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getTableData(); |
| | | onMounted(async () => { |
| | | await loadUserOptions(); |
| | | await loadSubjectList(); |
| | | await getTableData(); |
| | | }); |
| | | </script> |
| | | |
| | |
| | | .voucher-attachment-section { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | } |
| | | |
| | | .voucher-attachment-upload { |
| | | margin-top: 15px; |
| | | padding: 0 10px; |
| | | |
| | | .attachment-label { |
| | | font-size: 14px; |
| | | color: #606266; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .attachment-table { |
| | | border-radius: 4px; |
| | | } |
| | | } |
| | | |
| | |
| | | .col-subject { |
| | | position: relative; |
| | | |
| | | .el-select { |
| | | .el-select, |
| | | .el-tree-select { |
| | | .el-input input { |
| | | font-size: 12px; |
| | | } |
| | |
| | | <template> |
| | | <div class="dashboard"> |
| | | <!-- 顶鍿¨ªå两æ --> |
| | | <div class="dashboard-top"> |
| | | <!-- å·¦ï¼ä¼ä¸ä¿¡æ¯+ä¸å¤§æ°æ®å¡çï¼ä¸ä¸æåï¼ --> |
| | | <div class="top-left"> |
| | | <div class="company-info"> |
| | | <!-- é¡¶é¨é®åæ¡ --> |
| | | <div class="welcome-banner"> |
| | | <div class="welcome-title"> |
| | | <span class="welcome-user">{{ userStore.nickName || 'ç³»ç»ç®¡çå' }}</span> |
| | | <span> æ¨å¥½ï¼ç¥æ¨å¼å¿æ¯ä¸å¤©</span> |
| | | </div> |
| | | <div class="welcome-time">ç»å½äº: {{ userStore.currentLoginTime }}</div> |
| | | <div class="dashboard-cockpit"> |
| | | <section class="cockpit-panel welcome-panel"> |
| | | <div class="welcome-user"> |
| | | <el-avatar :src="welcomeAvatar" class="avatar" @error="handleWelcomeAvatarError"> |
| | | <el-icon><UserFilled /></el-icon> |
| | | </el-avatar> |
| | | <div class="welcome-text"> |
| | | <div class="welcome-title"> |
| | | {{ greetingText }}ï¼{{ userStore.nickName || userStore.name || "è¶
级管çå" }} ð |
| | | </div> |
| | | <div class="welcome-subtitle">䏿³¨å·¥ä¸æ°ååï¼å©åæºé å级</div> |
| | | </div> |
| | | </div> |
| | | <div class="welcome-meta"> |
| | | <div class="meta-time digital-number">{{ nowTime }}</div> |
| | | <div class="meta-tip">MES / MOM ç产è¿è¥é©¾é©¶è±</div> |
| | | </div> |
| | | </section> |
| | | |
| | | <!-- ç¨æ·ä¿¡æ¯å¡ç --> |
| | | <div class="user-card"> |
| | | <img :src="userStore.avatar" class="avatar" alt="" /> |
| | | <div class="user-card-main"> |
| | | <div class="user-name">{{ userStore.name }}</div> |
| | | <div class="user-role">{{ userStore.roleName }}</div> |
| | | <div class="user-meta"> |
| | | <span>{{ userStore.phoneNumber || '123456789' }}</span> |
| | | <span class="sep">|</span> |
| | | <span>{{ userStore.deptName || 'ç»ç»æ¶æ' }}</span> |
| | | <span class="sep">|</span> |
| | | <span>{{ userStore.postName || 'å²ä½å' }}</span> |
| | | <section v-if="dashboardCards.length > 0" class="top-row"> |
| | | <div class="stats-grid"> |
| | | <article |
| | | v-for="card in dashboardCards" |
| | | :key="card.key" |
| | | class="stat-card" |
| | | :class="card.key" |
| | | > |
| | | <div class="stat-header"> |
| | | <div class="stat-title-wrap"> |
| | | <div class="stat-title">{{ card.title }}</div> |
| | | <div class="stat-desc">{{ card.desc }}</div> |
| | | </div> |
| | | <div class="stat-icon-orb"> |
| | | <el-icon> |
| | | <component :is="card.icon" /> |
| | | </el-icon> |
| | | </div> |
| | | </div> |
| | | <div class="stat-value digital-number">{{ card.value }}</div> |
| | | <div class="stat-footer"> |
| | | <span>{{ card.subLabel }}</span> |
| | | <strong class="digital-number">{{ card.subValue }}</strong> |
| | | </div> |
| | | <div class="stat-trend">{{ card.trend }}</div> |
| | | <div class="stat-wave" aria-hidden="true"></div> |
| | | </article> |
| | | </div> |
| | | </section> |
| | | |
| | | <section v-if="hasVisiblePanels" class="main-grid"> |
| | | <div v-if="hasLeftPanels" class="left-column"> |
| | | <div v-if="visiblePanels.process" class="cockpit-panel process-panel"> |
| | | <div class="panel-title-row"> |
| | | <div class="panel-title">å·¥åºæ°æ®ç产ç»è®¡æç»</div> |
| | | <div class="panel-actions"> |
| | | <el-button type="primary" size="small" plain @click="openProcessDialog">鿩工åº</el-button> |
| | | <el-button size="small" plain @click="resetProcessFilter">éç½®</el-button> |
| | | <el-radio-group v-model="processRange" size="small" @change="refreshProcessStats"> |
| | | <el-radio-button :value="1">æ¥</el-radio-button> |
| | | <el-radio-button :value="2">å¨</el-radio-button> |
| | | <el-radio-button :value="3">æ</el-radio-button> |
| | | </el-radio-group> |
| | | </div> |
| | | </div> |
| | | <div class="process-body"> |
| | | <div class="process-chart" :class="{ empty: !hasProcessData }"> |
| | | <Echarts |
| | | :options="chartBaseOptions" |
| | | :chartStyle="{ width: '100%', height: '100%' }" |
| | | :grid="processGrid" |
| | | :series="processSeries" |
| | | :tooltip="processTooltip" |
| | | :xAxis="processXAxis" |
| | | :yAxis="processYAxis" |
| | | :style="{ height: hasProcessData ? '340px' : '280px' }" |
| | | @click="handleChartClick" |
| | | /> |
| | | <div v-if="!hasProcessData" class="chart-empty"> |
| | | <el-icon><DataAnalysis /></el-icon> |
| | | <div class="chart-empty-title">ææ å·¥åºæ°æ®</div> |
| | | <div class="chart-empty-desc">çå¾
ç产æ¥å·¥æ°æ®æ¥å
¥åèªå¨çæç»è®¡å¾è¡¨</div> |
| | | <div class="chart-empty-actions"> |
| | | <el-button size="small" @click="refreshProcessStats">å·æ°æ°æ®</el-button> |
| | | <el-button size="small" type="primary" plain @click="openProcessDialog">鿩工åº</el-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="process-aside"> |
| | | <div class="process-legend"> |
| | | <div class="process-name">{{ processAside.processName }}</div> |
| | | <div class="process-legend-item"><span class="dot dot-blue"></span>æå
¥é</div> |
| | | <div class="process-legend-item"><span class="dot dot-orange"></span>æ¥åºé</div> |
| | | <div class="process-legend-item"><span class="dot dot-cyan"></span>产åºé</div> |
| | | </div> |
| | | <div class="process-card"> |
| | | <div class="process-label">ç´¯è®¡æ»æå
¥</div> |
| | | <div class="process-value digital-number">{{ formatAmount(processAside.totalInput) }}</div> |
| | | </div> |
| | | <div class="process-card"> |
| | | <div class="process-label">ç´¯è®¡æ»æ¥åº</div> |
| | | <div class="process-value digital-number">{{ formatAmount(processAside.totalScrap) }}</div> |
| | | </div> |
| | | <div class="process-card"> |
| | | <div class="process-label">累计æ»äº§åº</div> |
| | | <div class="process-value digital-number">{{ formatAmount(processAside.totalOutput) }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="data-cards"> |
| | | <div class="data-card sales"> |
| | | <div class="data-title">é宿°æ®</div> |
| | | <div class="data-num"> |
| | | <div> |
| | | <div class="data-desc">æ¬æéå®é¢/å
</div> |
| | | <div class="data-value">{{ businessInfo.monthSaleMoney }}</div> |
| | | </div> |
| | | <div> |
| | | <div class="data-desc">æªå¼ç¥¨éé¢/å
</div> |
| | | <div class="data-value">{{ businessInfo.monthSaleHaveMoney }}</div> |
| | | </div> |
| | | </div> |
| | | |
| | | </div> |
| | | <div class="data-card purchase"> |
| | | <div class="data-title">éè´æ°æ®</div> |
| | | <div class="data-num"> |
| | | <div> |
| | | <div class="data-desc">æ¬æéè´é¢/å
</div> |
| | | <div class="data-value">{{ businessInfo.monthPurchaseMoney }}</div> |
| | | </div> |
| | | <div> |
| | | <div class="data-desc">å¾
仿¬¾éé¢/å
</div> |
| | | <div class="data-value">{{ businessInfo.monthPurchaseHaveMoney }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="data-card inventory"> |
| | | <div class="data-title">åºåæ°æ®</div> |
| | | <div class="data-num"> |
| | | <div> |
| | | <div class="data-desc">å½ååºåæ»é/ä»¶</div> |
| | | <div class="data-value">{{ businessInfo.inventoryNum }}</div> |
| | | </div> |
| | | <div> |
| | | <div class="data-desc">仿¥å
¥åº/ä»¶</div> |
| | | <div class="data-value">{{ businessInfo.todayInventoryNum }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <!-- å³ï¼å¾
åäºé¡¹ --> |
| | | <div class="todo-panel"> |
| | | <div class="section-title">å¾
åäºé¡¹</div> |
| | | <ul class="todo-list" v-if="todoList.length > 0"> |
| | | <li v-for="item in todoList" :key="item.id"> |
| | | <div style="display: flex;flex-direction: column;justify-content: space-between;width: 100%;gap: 20px"> |
| | | <div style="display: flex;justify-content: space-between;align-items: center;"> |
| | | <div class="todo-title">å¾
åç¼å·ï¼{{ item.approveId }}</div> |
| | | <div class="todo-division">é¨é¨ï¼{{ item.approveDeptName }}</div> |
| | | <div class="todo-time">{{ item.approveTime }}</div> |
| | | </div> |
| | | <div class="todo-division">å¾
åäºç±ï¼{{ item.approveReason }}</div> |
| | | </div> |
| | | </li> |
| | | </ul> |
| | | <div v-else style="text-align: center"> |
| | | ææ æ°æ® |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="dashboard-row"> |
| | | <div class="main-panel process-panel"> |
| | | <div class="process-panel__header"> |
| | | <div class="section-title">å·¥åºæ°æ®ç产ç»è®¡æç»</div> |
| | | <div style="display: flex; gap: 10px; align-items: center;"> |
| | | <el-button type="primary" size="small" plain icon="Filter" @click="openProcessDialog">鿩工åº</el-button> |
| | | <el-button type="info" size="small" plain icon="Refresh" @click="resetProcessFilter">éç½®</el-button> |
| | | <el-radio-group v-model="processRange" size="small" @change="refreshProcessStats"> |
| | | <el-radio-button :value="1">æ¥</el-radio-button> |
| | | <el-radio-button :value="2">å¨</el-radio-button> |
| | | <el-radio-button :value="3">æ</el-radio-button> |
| | | <div v-if="visiblePanels.order" class="cockpit-panel order-panel"> |
| | | <div class="panel-title-row"> |
| | | <div class="panel-title">ç产订åè¿åº¦</div> |
| | | <el-radio-group v-model="orderFilter" size="small"> |
| | | <el-radio-button label="all">å
¨é¨({{ orderProgressMeta.total }})</el-radio-button> |
| | | <el-radio-button label="waiting">å¾
å¼å§({{ orderProgressMeta.waitingCount }})</el-radio-button> |
| | | <el-radio-button label="inProgress">è¿è¡ä¸({{ orderProgressMeta.inProgressCount }})</el-radio-button> |
| | | <el-radio-button label="completed">已宿({{ orderProgressMeta.completedCount }})</el-radio-button> |
| | | <el-radio-button label="paused">å·²æå({{ orderProgressMeta.pausedCount }})</el-radio-button> |
| | | </el-radio-group> |
| | | </div> |
| | | <el-table :data="filteredOrders" stripe> |
| | | <el-table-column prop="orderNo" label="订åç¼å·" min-width="150" /> |
| | | <el-table-column prop="productName" label="产ååç§°" min-width="120" /> |
| | | <el-table-column prop="planQty" label="è®¡åæ°é" min-width="90" /> |
| | | <el-table-column prop="completedQty" label="已宿" min-width="90" /> |
| | | <el-table-column label="宿ç" min-width="180"> |
| | | <template #default="{ row }"> |
| | | <div class="table-progress"> |
| | | <el-progress |
| | | :stroke-width="8" |
| | | :percentage="row.completionRate" |
| | | :show-text="false" |
| | | status="success" |
| | | /> |
| | | <span>{{ row.completionRate }}%</span> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="deliveryDate" label="交æ" min-width="110" /> |
| | | <el-table-column label="ç¶æ" min-width="90"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getOrderStatusType(row.status)" effect="light"> |
| | | {{ row.statusLabel || getOrderStatusText(row.status) }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <div class="process-panel__body"> |
| | | <div class="process-panel__chart"> |
| | | <Echarts :chartStyle="{ width: '100%', height: '100%' }" :grid="processGrid" :series="processSeries" |
| | | :tooltip="processTooltip" :xAxis="processXAxis" :yAxis="processYAxis" style="height: 100%" |
| | | @click="handleChartClick" /> |
| | | </div> |
| | | |
| | | <div class="process-panel__aside"> |
| | | <div class="process-legend"> |
| | | <div class="process-legend__item"> |
| | | <span class="dot dot-blue"></span><span>æå
¥é</span> |
| | | </div> |
| | | <div class="process-legend__item"> |
| | | <span class="dot dot-yellow"></span><span>æ¥åºé</span> |
| | | </div> |
| | | <div class="process-legend__item"> |
| | | <span class="dot dot-teal"></span><span>产åºé</span> |
| | | <div v-if="visiblePanels.contract" class="cockpit-panel contract-panel"> |
| | | <div class="panel-title">客æ·ååéé¢åæ</div> |
| | | <div class="contract-summary"> |
| | | <div class="contract-card"> |
| | | <div class="contract-name">æ»ååéé¢(å
)</div> |
| | | <div class="contract-main digital-number">{{ formatNumber(sum) }}</div> |
| | | <div class="contract-compare"> |
| | | 忝 |
| | | <span class="rise">{{ trendText(yny) }}</span> |
| | | ç¯æ¯ |
| | | <span class="rise">{{ trendText(chain) }}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="process-card process-card--name">{{ processAside.processName }}</div> |
| | | |
| | | <div class="process-card"> |
| | | <div class="process-card__label">ç´¯è®¡æ»æå
¥</div> |
| | | <div class="process-card__value">{{ formatAmount(processAside.totalInput) }} |
| | | </div> |
| | | </div> |
| | | <div class="process-card"> |
| | | <div class="process-card__label">ç´¯è®¡æ»æ¥åº</div> |
| | | <div class="process-card__value">{{ formatAmount(processAside.totalScrap) }} |
| | | </div> |
| | | </div> |
| | | <div class="process-card"> |
| | | <div class="process-card__label">累计æ»äº§åº</div> |
| | | <div class="process-card__value">{{ formatAmount(processAside.totalOutput) }} |
| | | </div> |
| | | <div class="contract-chart-wrap"> |
| | | <Echarts |
| | | :options="chartBaseOptions" |
| | | :legend="pieLegend" |
| | | :chartStyle="chartStylePie" |
| | | :series="materialPieSeries" |
| | | :tooltip="pieTooltip" |
| | | /> |
| | | </div> |
| | | </div> |
| | | <ul class="contract-list"> |
| | | <li v-for="item in materialPieSeries[0].data" :key="item.name"> |
| | | <span class="legend-dot" :style="{ backgroundColor: item.itemStyle?.color }"></span> |
| | | <span class="contract-item-name">{{ item.name }}</span> |
| | | <span class="contract-item-rate">{{ item.rate }}%</span> |
| | | <span class="contract-item-value digital-number">Â¥{{ formatNumber(item.value) }}</span> |
| | | </li> |
| | | </ul> |
| | | </div> |
| | | |
| | | <div v-if="visiblePanels.quality" class="cockpit-panel quality-panel"> |
| | | <div class="panel-title-row"> |
| | | <div class="panel-title">è´¨éç»è®¡</div> |
| | | <el-radio-group v-model="qualityRange" size="small" @change="qualityStatisticsInfo"> |
| | | <el-radio-button :value="1">å¨</el-radio-button> |
| | | <el-radio-button :value="2">æ</el-radio-button> |
| | | <el-radio-button :value="3">å£åº¦</el-radio-button> |
| | | </el-radio-group> |
| | | </div> |
| | | <div class="quality-cards"> |
| | | <div class="quality-card one">åææå·²æ£æ°é <span>{{ qualityStatisticsObject.supplierNum }}ä»¶</span></div> |
| | | <div class="quality-card two">è¿ç¨æ£éªæ°é <span>{{ qualityStatisticsObject.processNum }}ä»¶</span></div> |
| | | <div class="quality-card three">åºåå·²æ£æ°é <span>{{ qualityStatisticsObject.factoryNum }}ä»¶</span></div> |
| | | </div> |
| | | <Echarts |
| | | :options="chartBaseOptions" |
| | | :chartStyle="chartStyle" |
| | | :grid="grid" |
| | | :legend="barLegend" |
| | | :series="barSeries1" |
| | | :tooltip="tooltip" |
| | | :xAxis="xAxis1" |
| | | :yAxis="yAxis1" |
| | | style="height: 270px" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- å·¥åºéæ©å¼¹çª --> |
| | | <div v-if="hasRightPanels" class="right-column"> |
| | | <div v-if="visiblePanels.todo" class="cockpit-panel todo-panel"> |
| | | <div class="panel-title-row"> |
| | | <div class="panel-title">å¾
åäºé¡¹</div> |
| | | <span class="panel-more">æ´å¤</span> |
| | | </div> |
| | | <ul class="todo-list" v-if="todoList.length > 0"> |
| | | <li v-for="item in todoList" :key="item.id" class="todo-item"> |
| | | <div class="todo-head"> |
| | | <span class="todo-no">å¾
åç¼å·ï¼{{ item.approveId }}</span> |
| | | <span class="todo-time">{{ item.approveTime }}</span> |
| | | </div> |
| | | <div class="todo-desc">é¨é¨ï¼{{ item.approveDeptName }}</div> |
| | | <div class="todo-desc">äºç±ï¼{{ item.approveReason }}</div> |
| | | </li> |
| | | </ul> |
| | | <div v-else class="panel-empty">ææ æ°æ®</div> |
| | | </div> |
| | | |
| | | <div v-if="visiblePanels.realtime" class="cockpit-panel realtime-panel"> |
| | | <div class="panel-title-row"> |
| | | <div class="panel-title">çäº§å®æ¶çæ¿</div> |
| | | <span class="panel-more">æ´å¤</span> |
| | | </div> |
| | | <div class="realtime-grid"> |
| | | <div class="realtime-item" v-for="item in realtimeBoard" :key="item.key"> |
| | | <el-progress |
| | | type="circle" |
| | | :percentage="item.percent" |
| | | :stroke-width="10" |
| | | :width="94" |
| | | :color="item.color" |
| | | > |
| | | <template #default> |
| | | <div class="realtime-value digital-number">{{ item.display }}</div> |
| | | </template> |
| | | </el-progress> |
| | | <div class="realtime-label">{{ item.label }}</div> |
| | | <div class="realtime-delta" :class="item.trend">{{ item.delta }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-if="visiblePanels.quick" class="cockpit-panel quick-panel"> |
| | | <div class="panel-title-row"> |
| | | <div class="panel-title">å¿«æ·åè½</div> |
| | | </div> |
| | | <div class="quick-grid"> |
| | | <button |
| | | v-for="item in quickEntries" |
| | | :key="item.label" |
| | | class="quick-item" |
| | | type="button" |
| | | @click="goToQuick(item.path)" |
| | | > |
| | | <span class="quick-icon"> |
| | | <el-icon> |
| | | <component :is="item.icon" /> |
| | | </el-icon> |
| | | </span> |
| | | <span>{{ item.label }}</span> |
| | | </button> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-if="visiblePanels.plan" class="cockpit-panel plan-panel"> |
| | | <div class="panel-title-row"> |
| | | <div class="panel-title">仿¥ç产计å</div> |
| | | <span class="panel-more">{{ todayPlanTotal }}项</span> |
| | | </div> |
| | | <ul class="plan-list"> |
| | | <li v-for="item in todayPlanList" :key="item.orderNo" class="plan-item"> |
| | | <div class="plan-main"> |
| | | <span class="plan-order">{{ item.orderNo }}</span> |
| | | <span class="plan-name">{{ item.productName }}</span> |
| | | </div> |
| | | <div class="plan-meta"> |
| | | <span>计å {{ item.planQty }}</span> |
| | | <span>交æ {{ item.deliveryDate }}</span> |
| | | </div> |
| | | </li> |
| | | </ul> |
| | | </div> |
| | | |
| | | <div v-if="visiblePanels.receipt" class="cockpit-panel receipt-panel"> |
| | | <div class="panel-title">忬¾ä¸å¼ç¥¨åæ</div> |
| | | <Echarts |
| | | :options="chartBaseOptions" |
| | | :chartStyle="chartStyle" |
| | | :grid="grid" |
| | | :legend="lineLegend" |
| | | :series="lineSeries" |
| | | :tooltip="tooltipLine" |
| | | :xAxis="xAxis2" |
| | | :yAxis="yAxis2" |
| | | style="height: 300px" |
| | | /> |
| | | </div> |
| | | |
| | | </div> |
| | | </section> |
| | | |
| | | <section v-else class="cockpit-panel empty-home-panel"> |
| | | å½åè´¦å·æ²¡æå¯å±ç¤ºçé¦é¡µæ¨¡å |
| | | </section> |
| | | |
| | | <el-dialog v-model="processDialogVisible" title="鿩工åº" width="500px" append-to-body> |
| | | <div class="process-selection-wrapper"> |
| | | <el-checkbox-group v-model="tempProcessIds"> |
| | |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- ä¸é¨æ¨ªå两æ --> |
| | | <div class="dashboard-row"> |
| | | <div class="main-panel"> |
| | | <div class="section-title">客æ·ååéé¢åæ</div> |
| | | <div class="contract-summary"> |
| | | <div class="contract-info"> |
| | | <img src="../assets/images/khtitle.png" alt="" style="width: 42px" /> |
| | | <div class="contract-card"> |
| | | <div class="contract-name">æ»ååéé¢(å
)</div> |
| | | <div class="contract-meta"> |
| | | <div class="main-amount">{{ sum }}</div> |
| | | <div>å¨åæ¯: <span class="up">{{ yny }}% </span> æ¥ç¯æ¯: <span class="up">{{ chain }}% </span></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div |
| | | style="display: flex;align-items: center;gap: 20px;justify-content: space-evenly;height: 180px;margin-top: 20px"> |
| | | <div> |
| | | <Echarts ref="chart" :legend="pieLegend" :chartStyle="chartStylePie" :series="materialPieSeries" |
| | | :tooltip="pieTooltip"></Echarts> |
| | | </div> |
| | | <ul class="contract-list"> |
| | | <li v-for="item in materialPieSeries[0].data" :key="item.name"> |
| | | <div style="display: flex;align-items: center;justify-content: space-between;width: 100%"> |
| | | <div class="line" :style="{ color: item.itemStyle.color }">â{{ item.name }}</div> |
| | | <div style="width: 70px">{{ item.rate }}%</div> |
| | | <div>ï¿¥{{ item.value }}</div> |
| | | </div> |
| | | </li> |
| | | </ul> |
| | | </div> |
| | | </div> |
| | | <div class="main-panel"> |
| | | <div style="display: flex;justify-content: space-between;"> |
| | | <div class="section-title">åºæ¶åºä»ç»è®¡</div> |
| | | <!-- <el-radio-group v-model="radio1" size="large" @change="statisticsReceivable">--> |
| | | <!-- <el-radio-button label="æå¨" :value="1" />--> |
| | | <!-- <el-radio-button label="ææ" :value="2" />--> |
| | | <!-- <el-radio-button label="æå£åº¦" :value="3" />--> |
| | | <!-- </el-radio-group>--> |
| | | </div> |
| | | <Echarts ref="chart" :color="barColors2" :chartStyle="chartStyle" :grid="grid" :series="barSeries" |
| | | :tooltip="tooltip" :xAxis="xAxis" :yAxis="yAxis" style="height: 260px"></Echarts> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- åºé¨æ¨ªå两æ --> |
| | | <div class="dashboard-row"> |
| | | <div class="main-panel"> |
| | | <div style="display: flex;justify-content: space-between;align-items: center;margin-bottom: 10px;"> |
| | | <div class="section-title" style="margin-bottom: 0;">è´¨éç»è®¡</div> |
| | | <el-radio-group v-model="qualityRange" size="small" @change="qualityStatisticsInfo"> |
| | | <el-radio-button :value="1">å¨</el-radio-button> |
| | | <el-radio-button :value="2">æ</el-radio-button> |
| | | <el-radio-button :value="3">å£åº¦</el-radio-button> |
| | | </el-radio-group> |
| | | </div> |
| | | <div class="quality-cards"> |
| | | <div class="quality-card one">åææå·²æ£æµæ° <span>{{ qualityStatisticsObject.supplierNum }}ä»¶</span></div> |
| | | <div class="quality-card two">è¿ç¨æ£éªæ°é <span>{{ qualityStatisticsObject.processNum }}ä»¶</span></div> |
| | | <div class="quality-card three">åºåå·²æ£æ°é <span>{{ qualityStatisticsObject.factoryNum }}ä»¶</span></div> |
| | | </div> |
| | | <Echarts ref="chart" :chartStyle="chartStyle" :grid="grid" :legend="barLegend" :series="barSeries1" |
| | | :tooltip="tooltip" :xAxis="xAxis1" :yAxis="yAxis1" style="height: 260px"></Echarts> |
| | | </div> |
| | | |
| | | <div class="main-panel"> |
| | | <div class="section-title">忬¾ä¸å¼ç¥¨åæ</div> |
| | | <Echarts ref="invoiceChart" :chartStyle="chartStyle" :grid="grid" :legend="lineLegend" :series="lineSeries" |
| | | :tooltip="tooltipLine" :xAxis="xAxis2" :yAxis="yAxis2" style="height: 270px;" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, computed, reactive } from 'vue' |
| | | import { ref, onMounted, onUnmounted, computed, reactive, watch } from "vue"; |
| | | import { useRouter } from "vue-router"; |
| | | import dayjs from "dayjs"; |
| | | import * as echarts from "echarts"; |
| | | import { |
| | | Box, |
| | | Calendar, |
| | | Checked, |
| | | DataAnalysis, |
| | | DataLine, |
| | | EditPen, |
| | | Operation, |
| | | Search, |
| | | ShoppingCartFull, |
| | | Tickets, |
| | | Tools, |
| | | UserFilled, |
| | | } from "@element-plus/icons-vue"; |
| | | import Echarts from "@/components/Echarts/echarts.vue"; |
| | | import * as echarts from 'echarts'; |
| | | import usePermissionStore from "@/store/modules/permission"; |
| | | import useUserStore from "@/store/modules/user.js"; |
| | | import { |
| | | analysisCustomerContractAmounts, getAmountHalfYear, |
| | | analysisCustomerContractAmounts, |
| | | getAmountHalfYear, |
| | | getBusiness, |
| | | homeTodos, |
| | | processDataProductionStatistics, |
| | | productionOrderProgress, |
| | | productionOverview, |
| | | productionRealtimeBoard, |
| | | qualityInspectionStatistics, |
| | | statisticsReceivablePayable, |
| | | qualityInspectionStatistics |
| | | todayProductionPlan, |
| | | } from "@/api/viewIndex.js"; |
| | | import { list } from '@/api/productionManagement/productionProcess'; |
| | | import { list } from "@/api/productionManagement/productionProcess"; |
| | | |
| | | const router = useRouter(); |
| | | const userStore = useUserStore(); |
| | | const permissionStore = usePermissionStore(); |
| | | const defaultWelcomeAvatar = new URL("../assets/images/profile.jpg", import.meta.url).href; |
| | | |
| | | const userStore = useUserStore() |
| | | const nowTime = ref(""); |
| | | const welcomeAvatarLoadFailed = ref(false); |
| | | let clockTimer = null; |
| | | const weatherText = "å¤äº 28°C"; |
| | | |
| | | const processOptions = ref([]) |
| | | const selectedProcessIds = ref([]) |
| | | const tempProcessIds = ref([]) |
| | | const processDialogVisible = ref(false) |
| | | const activeProcessIndex = ref(0) |
| | | const nowDate = computed(() => (nowTime.value ? nowTime.value.slice(0, 10) : dayjs().format("YYYY-MM-DD"))); |
| | | |
| | | const greetingText = computed(() => { |
| | | const hour = dayjs().hour(); |
| | | if (hour < 6) return "忍好"; |
| | | if (hour < 9) return "æ©ä¸å¥½"; |
| | | if (hour < 12) return "ä¸å好"; |
| | | if (hour < 14) return "ä¸å好"; |
| | | if (hour < 18) return "ä¸å好"; |
| | | return "æä¸å¥½"; |
| | | }); |
| | | |
| | | const welcomeAvatar = computed(() => |
| | | welcomeAvatarLoadFailed.value || !userStore.avatar ? defaultWelcomeAvatar : userStore.avatar |
| | | ); |
| | | |
| | | const handleWelcomeAvatarError = () => { |
| | | if (welcomeAvatar.value !== defaultWelcomeAvatar) { |
| | | welcomeAvatarLoadFailed.value = true; |
| | | } |
| | | }; |
| | | |
| | | watch( |
| | | () => userStore.avatar, |
| | | () => { |
| | | welcomeAvatarLoadFailed.value = false; |
| | | } |
| | | ); |
| | | |
| | | const axisTextColor = "#5f6f86"; |
| | | const axisLineColor = "rgba(148, 163, 184, 0.45)"; |
| | | const splitLineColor = "rgba(148, 163, 184, 0.18)"; |
| | | |
| | | const chartBaseOptions = reactive({ |
| | | backgroundColor: "transparent", |
| | | textStyle: { color: axisTextColor }, |
| | | }); |
| | | |
| | | const processOptions = ref([]); |
| | | const selectedProcessIds = ref([]); |
| | | const tempProcessIds = ref([]); |
| | | const processDialogVisible = ref(false); |
| | | const activeProcessIndex = ref(0); |
| | | |
| | | const businessInfo = ref({ |
| | | inventoryNum: 0, |
| | |
| | | monthSaleHaveMoney: 0, |
| | | monthSaleMoney: 0, |
| | | todayInventoryNum: 0, |
| | | }) |
| | | }); |
| | | |
| | | const qualityStatisticsObject = ref({ |
| | | supplierNum: 0, |
| | | processNum: 0, |
| | | factoryNum: 0, |
| | | }) |
| | | const sum = ref(0) |
| | | const yny = ref(0) |
| | | const chain = ref(0) |
| | | }); |
| | | |
| | | const pieLegend = reactive({ |
| | | show: false, |
| | | }) |
| | | const productionOverviewData = ref({ |
| | | totalOutput: 0, |
| | | totalScrap: 0, |
| | | yieldRate: 0, |
| | | }); |
| | | |
| | | const realtimeBoardData = ref({ |
| | | deviceOee: { value: 0, compareYesterday: 0 }, |
| | | orderAchievementRate: { value: 0, compareYesterday: 0 }, |
| | | defectRate: { value: 0, compareYesterday: 0 }, |
| | | }); |
| | | |
| | | const orderProgressMeta = ref({ |
| | | status: "all", |
| | | tab: "all", |
| | | bizDate: null, |
| | | total: 0, |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | waitingCount: 0, |
| | | inProgressCount: 0, |
| | | completedCount: 0, |
| | | pausedCount: 0, |
| | | }); |
| | | |
| | | const todayPlanList = ref([]); |
| | | const todayPlanTotal = ref(0); |
| | | |
| | | const sum = ref(0); |
| | | const yny = ref(0); |
| | | const chain = ref(0); |
| | | |
| | | const pieLegend = reactive({ show: false }); |
| | | const piePalette = ["#2563eb", "#14b8a6", "#7c3aed", "#f97316", "#38bdf8", "#f43f5e"]; |
| | | |
| | | const chartStyle = { |
| | | width: "100%", |
| | | height: "100%", |
| | | }; |
| | | |
| | | const chartStylePie = { |
| | | width: "100%", |
| | | height: "200px", |
| | | }; |
| | | |
| | | const grid = { |
| | | left: "3%", |
| | | right: "4%", |
| | | bottom: "2%", |
| | | top: "12%", |
| | | containLabel: true, |
| | | }; |
| | | |
| | | const tooltip = { |
| | | trigger: "axis", |
| | | axisPointer: { type: "shadow" }, |
| | | backgroundColor: "rgba(255, 255, 255, 0.97)", |
| | | borderColor: "rgba(148, 163, 184, 0.26)", |
| | | textStyle: { color: "#334155" }, |
| | | }; |
| | | |
| | | const barColors2 = ["#2563eb", "#14b8a6"]; |
| | | |
| | | const xAxis = [ |
| | | { |
| | | type: "value", |
| | | axisLine: { lineStyle: { color: axisLineColor } }, |
| | | splitLine: { lineStyle: { color: splitLineColor } }, |
| | | axisLabel: { color: axisTextColor }, |
| | | }, |
| | | ]; |
| | | |
| | | const yAxis = [ |
| | | { |
| | | type: "category", |
| | | data: ["åºä»è´¦æ¬¾", "åºæ¶è´¦æ¬¾"], |
| | | axisTick: { show: false }, |
| | | axisLine: { lineStyle: { color: axisLineColor } }, |
| | | axisLabel: { color: axisTextColor }, |
| | | }, |
| | | ]; |
| | | |
| | | const barSeries = ref([ |
| | | { |
| | | type: 'bar', |
| | | type: "bar", |
| | | barWidth: 22, |
| | | itemStyle: { borderRadius: [0, 8, 8, 0] }, |
| | | label: { show: true, position: "right", color: "#334155" }, |
| | | data: [], |
| | | label: { |
| | | show: true, |
| | | } |
| | | }, |
| | | ]) |
| | | ]); |
| | | |
| | | const barLegend = { |
| | | show: true, |
| | | textStyle: { color: axisTextColor }, |
| | | data: ["åææä¸åæ ¼æ°", "è¿ç¨ä¸åæ ¼æ°", "åºåä¸åæ ¼æ°"], |
| | | }; |
| | | |
| | | const xAxis1 = ref([ |
| | | { |
| | | type: "category", |
| | | axisTick: { show: false }, |
| | | axisLine: { lineStyle: { color: axisLineColor } }, |
| | | axisLabel: { color: axisTextColor }, |
| | | data: [], |
| | | }, |
| | | ]); |
| | | |
| | | const yAxis1 = [ |
| | | { |
| | | type: "value", |
| | | splitLine: { lineStyle: { color: splitLineColor } }, |
| | | axisLine: { lineStyle: { color: axisLineColor } }, |
| | | axisLabel: { color: axisTextColor }, |
| | | }, |
| | | ]; |
| | | |
| | | const barSeries1 = ref([ |
| | | { |
| | | name: 'åææä¸åæ ¼æ°', |
| | | type: 'bar', |
| | | name: "åææä¸åæ ¼æ°", |
| | | type: "bar", |
| | | barGap: 0, |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: [] |
| | | itemStyle: { color: "#2563eb", borderRadius: [6, 6, 0, 0] }, |
| | | emphasis: { focus: "series" }, |
| | | data: [], |
| | | }, |
| | | { |
| | | name: 'è¿ç¨ä¸åæ ¼æ°', |
| | | type: 'bar', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: [] |
| | | name: "è¿ç¨ä¸åæ ¼æ°", |
| | | type: "bar", |
| | | itemStyle: { color: "#14b8a6", borderRadius: [6, 6, 0, 0] }, |
| | | emphasis: { focus: "series" }, |
| | | data: [], |
| | | }, |
| | | { |
| | | name: 'åºåä¸åæ ¼æ°', |
| | | type: 'bar', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: [] |
| | | name: "åºåä¸åæ ¼æ°", |
| | | type: "bar", |
| | | itemStyle: { color: "#f59e0b", borderRadius: [6, 6, 0, 0] }, |
| | | emphasis: { focus: "series" }, |
| | | data: [], |
| | | }, |
| | | ]) |
| | | const chartStyle = { |
| | | width: '100%', |
| | | height: '100%' // 设置å¾è¡¨å®¹å¨çé«åº¦ |
| | | } |
| | | const chartStylePie = { |
| | | width: '140%', |
| | | height: '140%' // 设置å¾è¡¨å®¹å¨çé«åº¦ |
| | | } |
| | | const grid = { |
| | | left: '3%', |
| | | right: '4%', |
| | | bottom: '3%', |
| | | containLabel: true |
| | | } |
| | | const barLegend = { |
| | | show: true, |
| | | data: ['åææä¸åæ ¼æ°', 'è¿ç¨ä¸åæ ¼æ°', 'åºåä¸åæ ¼æ°'] |
| | | } |
| | | const barLegend1 = { |
| | | show: true, |
| | | data: ['é¢ä»è´¦æ¬¾', 'åºä»è´¦æ¬¾', '颿¶è´¦æ¬¾', 'åºæ¶è´¦æ¬¾'] |
| | | } |
| | | ]); |
| | | |
| | | const lineLegend = { |
| | | show: true, |
| | | data: ['å¼ç¥¨', '忬¾'] |
| | | } |
| | | const tooltip = { |
| | | trigger: 'axis', |
| | | axisPointer: { |
| | | type: 'shadow' |
| | | } |
| | | } |
| | | const xAxis = [{ |
| | | type: 'value', |
| | | }] |
| | | const xAxis1 = ref([{ |
| | | type: 'category', |
| | | axisTick: { show: false }, |
| | | data: [] |
| | | }]) |
| | | const yAxis = [{ |
| | | type: 'category', |
| | | data: ['åºä»è´¦æ¬¾', 'åºæ¶è´¦æ¬¾',] |
| | | }] |
| | | const yAxis1 = [{ |
| | | type: 'value' |
| | | }] |
| | | const pieTooltip = reactive({ |
| | | trigger: 'item', |
| | | formatter: function (params) { |
| | | // å¨æçææç¤ºä¿¡æ¯ï¼åºäºæ°æ®é¡¹ç name 屿§ |
| | | const description = params.name === 'æ¬æåæ¬¾éé¢' ? 'æ¬æåæ¬¾éé¢' : 'åºæ¶æ¬¾éé¢'; |
| | | return `${description} ${formatNumber(params.value)}å
${params.percent}%`; |
| | | }, |
| | | position: 'right' |
| | | }) |
| | | const materialPieSeries = ref([ |
| | | { |
| | | type: 'pie', |
| | | radius: ['66%', '90%'], |
| | | avoidLabelOverlap: false, |
| | | itemStyle: { |
| | | borderColor: '#fff', |
| | | borderWidth: 2 |
| | | }, |
| | | label: { |
| | | show: false |
| | | }, |
| | | data: [] |
| | | } |
| | | ]) |
| | | const lineSeries = ref([ |
| | | { |
| | | type: 'line', |
| | | data: [], |
| | | label: { |
| | | show: true |
| | | }, |
| | | showSymbol: true, // æ¾ç¤ºåç¹ |
| | | }, |
| | | ]) |
| | | const tooltipLine = { |
| | | trigger: 'axis', |
| | | } |
| | | const yAxis2 = ref([ |
| | | { |
| | | type: 'value', |
| | | } |
| | | ]) |
| | | textStyle: { color: axisTextColor }, |
| | | data: ["å¼ç¥¨", "忬¾"], |
| | | }; |
| | | |
| | | const xAxis2 = ref([ |
| | | { |
| | | type: 'category', |
| | | type: "category", |
| | | data: [], |
| | | axisLine: { lineStyle: { color: axisLineColor } }, |
| | | axisLabel: { |
| | | color: axisTextColor, |
| | | interval: 0, |
| | | formatter: function (value) { |
| | | return value.replace(/~/g, '\n'); |
| | | }, |
| | | } |
| | | } |
| | | ]) |
| | | |
| | | // å¾
åäºé¡¹ |
| | | const todoList = ref([]) |
| | | const radio1 = ref(1) |
| | | const qualityRange = ref(1) |
| | | |
| | | // å¾è¡¨å¼ç¨ |
| | | const barChart = ref(null) |
| | | const lineChart = ref(null) |
| | | const barColors2 = ['#5181DB', '#D369E0', '#F2CA6D', '#60CCA8'] |
| | | |
| | | // éæºé¢è²çæå½æ° |
| | | const getRandomColor = () => { |
| | | return '#' + Math.floor(Math.random() * 0xffffff).toString(16).padStart(6, '0'); |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getBusinessData() |
| | | analysisCustomer() |
| | | todoInfoS() |
| | | statisticsReceivable() |
| | | qualityStatisticsInfo() |
| | | getAmountHalfYearNum() |
| | | getProcessList() |
| | | }) |
| | | // æ°æ®ç»è®¡ |
| | | const getBusinessData = () => { |
| | | getBusiness().then((res) => { |
| | | businessInfo.value = { ...res.data } |
| | | }) |
| | | } |
| | | // ååéé¢ |
| | | const analysisCustomer = () => { |
| | | analysisCustomerContractAmounts().then((res) => { |
| | | sum.value = res.data.sum |
| | | yny.value = res.data.yny |
| | | chain.value = res.data.chain |
| | | // 为æ¯ä¸ªæ°æ®é¡¹åé
éæºé¢è² |
| | | materialPieSeries.value[0].data = res.data.item.map(item => ({ |
| | | ...item, |
| | | itemStyle: { color: getRandomColor() } |
| | | })) |
| | | }) |
| | | } |
| | | // å¾
åäºé¡¹ |
| | | const todoInfoS = () => { |
| | | homeTodos().then((res) => { |
| | | todoList.value = res.data |
| | | }) |
| | | } |
| | | // è·åå·¥åºå表 |
| | | const getProcessList = () => { |
| | | list().then(res => { |
| | | processOptions.value = res.data |
| | | }) |
| | | } |
| | | |
| | | const openProcessDialog = () => { |
| | | tempProcessIds.value = [...selectedProcessIds.value] |
| | | processDialogVisible.value = true |
| | | } |
| | | |
| | | const handleProcessDialogConfirm = () => { |
| | | selectedProcessIds.value = [...tempProcessIds.value] |
| | | processDialogVisible.value = false |
| | | refreshProcessStats() |
| | | } |
| | | |
| | | const resetProcessFilter = () => { |
| | | selectedProcessIds.value = [] |
| | | tempProcessIds.value = [] |
| | | refreshProcessStats() |
| | | } |
| | | |
| | | const handleChartClick = (params) => { |
| | | if (params && params.dataIndex !== undefined) { |
| | | activeProcessIndex.value = params.dataIndex |
| | | } |
| | | } |
| | | // åºä»åºæ¶ç»è®¡ |
| | | const statisticsReceivable = () => { |
| | | statisticsReceivablePayable({ type: radio1.value }).then((res) => { |
| | | barSeries.value[0].data = [ |
| | | // { value: res.data.prepayMoney, itemStyle: { color: barColors2[0] } }, |
| | | { value: res.data.payableMoney, itemStyle: { color: barColors2[0] } }, |
| | | // { value: res.data.advanceMoney, itemStyle: { color: barColors2[2] } }, |
| | | { value: res.data.receivableMoney, itemStyle: { color: barColors2[1] } } |
| | | ] |
| | | }) |
| | | } |
| | | // è´¨æ£ç»è®¡ |
| | | const qualityStatisticsInfo = () => { |
| | | qualityInspectionStatistics({ type: qualityRange.value }).then((res) => { |
| | | xAxis1.value[0].data = [] |
| | | barSeries1.value[0].data = [] |
| | | barSeries1.value[1].data = [] |
| | | barSeries1.value[2].data = [] |
| | | res.data.item.forEach(item => { |
| | | xAxis1.value[0].data.push(item.date) |
| | | barSeries1.value[0].data.push(item.supplierNum) |
| | | barSeries1.value[1].data.push(item.processNum) |
| | | barSeries1.value[2].data.push(item.factoryNum) |
| | | }) |
| | | qualityStatisticsObject.value.supplierNum = res.data.supplierNum |
| | | qualityStatisticsObject.value.processNum = res.data.processNum |
| | | qualityStatisticsObject.value.factoryNum = res.data.factoryNum |
| | | }) |
| | | } |
| | | const getAmountHalfYearNum = async () => { |
| | | const res = await getAmountHalfYear() |
| | | console.log(res) |
| | | const monthName = [] |
| | | const receiptAmount = [] |
| | | const invoiceAmount = [] |
| | | res.data.forEach(item => { |
| | | monthName.push(item.month) |
| | | receiptAmount.push(item.receiptAmount) |
| | | invoiceAmount.push(item.invoiceAmount) |
| | | }) |
| | | // æ£ç¡®ååºå¼èµå¼ï¼å建æ°ç xAxis å series 对象 |
| | | xAxis2.value[0].data = monthName |
| | | xAxis2.value[0].data = monthName.map(item => item.replace(/~/g, '\n~')); |
| | | lineSeries.value = [ |
| | | { |
| | | name: 'å¼ç¥¨', |
| | | type: 'line', |
| | | data: invoiceAmount, |
| | | stack: 'Total', |
| | | areaStyle: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | offset: 0, |
| | | color: 'rgba(131, 207, 255, 1)' |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: 'rgba(186, 228, 255, 1)' |
| | | } |
| | | ]) |
| | | }, |
| | | itemStyle: { |
| | | color: '#2D99FF', |
| | | borderColor: '#2D99FF' |
| | | }, |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | lineStyle: { |
| | | width: 0 |
| | | }, |
| | | showSymbol: true, |
| | | formatter: (value) => value.replace(/~/g, "\n"), |
| | | }, |
| | | { |
| | | name: '忬¾', |
| | | type: 'line', |
| | | data: receiptAmount, |
| | | stack: 'Total', |
| | | lineStyle: { |
| | | width: 0 |
| | | }, |
| | | itemStyle: { |
| | | color: '#83CFFF', |
| | | borderColor: '#83CFFF' |
| | | }, |
| | | showSymbol: true, |
| | | areaStyle: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | offset: 0, |
| | | color: 'rgba(54, 153, 255, 1)' |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: 'rgba(89, 169, 254, 1)' |
| | | } |
| | | ]) |
| | | }, |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | } |
| | | ] |
| | | } |
| | | }, |
| | | ]); |
| | | |
| | | // å·¥åºæ°æ®ç产ç»è®¡æç»ï¼åæ°æ® + å¾è¡¨ï¼ |
| | | const processRange = ref(1) |
| | | const processChartData = ref([]) |
| | | const yAxis2 = ref([ |
| | | { |
| | | type: "value", |
| | | splitLine: { lineStyle: { color: splitLineColor } }, |
| | | axisLine: { lineStyle: { color: axisLineColor } }, |
| | | axisLabel: { color: axisTextColor }, |
| | | }, |
| | | ]); |
| | | |
| | | const tooltipLine = { |
| | | trigger: "axis", |
| | | backgroundColor: "rgba(255, 255, 255, 0.97)", |
| | | borderColor: "rgba(148, 163, 184, 0.26)", |
| | | textStyle: { color: "#334155" }, |
| | | }; |
| | | |
| | | const lineSeries = ref([ |
| | | { |
| | | name: "å¼ç¥¨", |
| | | type: "line", |
| | | data: [], |
| | | smooth: true, |
| | | itemStyle: { color: "#2563eb" }, |
| | | lineStyle: { width: 2, color: "#2563eb" }, |
| | | showSymbol: true, |
| | | areaStyle: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { offset: 0, color: "rgba(37, 99, 235, 0.24)" }, |
| | | { offset: 1, color: "rgba(37, 99, 235, 0.02)" }, |
| | | ]), |
| | | }, |
| | | }, |
| | | { |
| | | name: "忬¾", |
| | | type: "line", |
| | | data: [], |
| | | smooth: true, |
| | | itemStyle: { color: "#14b8a6" }, |
| | | lineStyle: { width: 2, color: "#14b8a6" }, |
| | | showSymbol: true, |
| | | areaStyle: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { offset: 0, color: "rgba(20, 184, 166, 0.2)" }, |
| | | { offset: 1, color: "rgba(20, 184, 166, 0.02)" }, |
| | | ]), |
| | | }, |
| | | }, |
| | | ]); |
| | | |
| | | const pieTooltip = reactive({ |
| | | trigger: "item", |
| | | backgroundColor: "rgba(255, 255, 255, 0.97)", |
| | | borderColor: "rgba(148, 163, 184, 0.26)", |
| | | textStyle: { color: "#334155" }, |
| | | formatter: (params) => `${params.name} ${formatNumber(params.value)}å
${params.percent}%`, |
| | | }); |
| | | |
| | | const materialPieSeries = ref([ |
| | | { |
| | | type: "pie", |
| | | radius: ["62%", "88%"], |
| | | avoidLabelOverlap: false, |
| | | itemStyle: { |
| | | borderColor: "rgba(255, 255, 255, 0.95)", |
| | | borderWidth: 2, |
| | | }, |
| | | label: { show: false }, |
| | | data: [], |
| | | }, |
| | | ]); |
| | | |
| | | const todoList = ref([]); |
| | | const qualityRange = ref(1); |
| | | const processRange = ref(1); |
| | | const processChartData = ref([]); |
| | | |
| | | const processXAxis = ref([ |
| | | { |
| | | nameTextStyle: { color: 'rgba(0,0,0,0.35)', fontSize: 12 }, |
| | | axisLabel: { color: 'rgba(0,0,0,0.35)' }, |
| | | splitLine: { lineStyle: { color: 'rgba(0,0,0,0.06)', type: 'dashed' } }, |
| | | type: "value", |
| | | axisLine: { lineStyle: { color: axisLineColor } }, |
| | | splitLine: { lineStyle: { color: splitLineColor, type: "dashed" } }, |
| | | axisLabel: { color: axisTextColor }, |
| | | }, |
| | | ]) |
| | | ]); |
| | | |
| | | const processYAxis = ref([ |
| | | { |
| | | type: 'category', |
| | | type: "category", |
| | | axisTick: { show: false }, |
| | | axisLine: { show: false }, |
| | | axisLabel: { color: 'rgba(0,0,0,0.45)' }, |
| | | axisLabel: { color: axisTextColor }, |
| | | data: [], |
| | | }, |
| | | ]) |
| | | ]); |
| | | |
| | | const processGrid = reactive({ left: 0, right: 100, top: 30, bottom: 20, containLabel: true }) |
| | | const processGrid = reactive({ left: "4%", right: "4%", top: 20, bottom: 18, containLabel: true }); |
| | | |
| | | const processTooltip = reactive({ |
| | | trigger: 'axis', |
| | | axisPointer: { type: 'shadow' }, |
| | | trigger: "axis", |
| | | axisPointer: { type: "shadow" }, |
| | | backgroundColor: "rgba(255, 255, 255, 0.97)", |
| | | borderColor: "rgba(148, 163, 184, 0.26)", |
| | | textStyle: { color: "#334155" }, |
| | | formatter: (params) => { |
| | | const name = params?.[0]?.name ?? '' |
| | | const list = Array.isArray(params) ? params : [] |
| | | const name = params?.[0]?.name ?? ""; |
| | | const list = Array.isArray(params) ? params : []; |
| | | const lines = list |
| | | .map((p) => { |
| | | const colorBox = `<span style="display:inline-block;margin-right:6px;border-radius:2px;width:10px;height:10px;background:${p.color}"></span>` |
| | | return `${colorBox}${p.seriesName} <b style="float:right;">${Number(p.value || 0).toFixed(2)}</b>` |
| | | }) |
| | | .join('<br/>') |
| | | return `<div style="min-width:140px;"><div style="font-weight:700;margin-bottom:6px;">${name}</div>${lines}</div>` |
| | | .map((p) => { |
| | | const colorBox = `<span style="display:inline-block;margin-right:6px;border-radius:2px;width:10px;height:10px;background:${p.color}"></span>`; |
| | | return `${colorBox}${p.seriesName}<b style="float:right;">${Number(p.value || 0).toFixed(2)}</b>`; |
| | | }) |
| | | .join("<br/>"); |
| | | return `<div style="min-width:140px;"><div style="font-weight:700;margin-bottom:6px;">${name}</div>${lines}</div>`; |
| | | }, |
| | | }) |
| | | }); |
| | | |
| | | const processSeries = computed(() => { |
| | | const input = processChartData.value.map((i) => i.input) |
| | | const scrap = processChartData.value.map((i) => i.scrap) |
| | | const output = processChartData.value.map((i) => i.output) |
| | | |
| | | const input = processChartData.value.map((item) => item.input); |
| | | const scrap = processChartData.value.map((item) => item.scrap); |
| | | const output = processChartData.value.map((item) => item.output); |
| | | return [ |
| | | { |
| | | name: 'æå
¥é', |
| | | type: 'bar', |
| | | stack: 'total', |
| | | barWidth: 22, |
| | | itemStyle: { color: '#1E5BFF', borderRadius: [6, 0, 0, 6] }, |
| | | name: "æå
¥é", |
| | | type: "bar", |
| | | stack: "total", |
| | | barWidth: 18, |
| | | itemStyle: { color: "#2563eb", borderRadius: [8, 0, 0, 8] }, |
| | | data: input, |
| | | }, |
| | | { |
| | | name: 'æ¥åºé', |
| | | type: 'bar', |
| | | stack: 'total', |
| | | barWidth: 22, |
| | | itemStyle: { color: '#F7B500' }, |
| | | name: "æ¥åºé", |
| | | type: "bar", |
| | | stack: "total", |
| | | barWidth: 18, |
| | | itemStyle: { color: "#f59e0b" }, |
| | | data: scrap, |
| | | }, |
| | | { |
| | | name: '产åºé', |
| | | type: 'bar', |
| | | stack: 'total', |
| | | barWidth: 22, |
| | | itemStyle: { color: '#19C6C6', borderRadius: [0, 6, 6, 0] }, |
| | | name: "产åºé", |
| | | type: "bar", |
| | | stack: "total", |
| | | barWidth: 18, |
| | | itemStyle: { color: "#14b8a6", borderRadius: [0, 8, 8, 0] }, |
| | | data: output, |
| | | }, |
| | | ] |
| | | }) |
| | | ]; |
| | | }); |
| | | |
| | | const processAside = computed(() => { |
| | | const list = processChartData.value |
| | | const item = list[activeProcessIndex.value] || {} |
| | | const listData = processChartData.value; |
| | | const item = listData[activeProcessIndex.value] || {}; |
| | | return { |
| | | processName: item.name || 'ææ æ°æ®', |
| | | processName: item.name || "ææ æ°æ®", |
| | | totalInput: item.input || 0, |
| | | totalScrap: item.scrap || 0, |
| | | totalOutput: item.output || 0, |
| | | }; |
| | | }); |
| | | |
| | | const processTotals = computed(() => |
| | | processChartData.value.reduce( |
| | | (acc, cur) => { |
| | | acc.input += Number(cur.input || 0); |
| | | acc.scrap += Number(cur.scrap || 0); |
| | | acc.output += Number(cur.output || 0); |
| | | return acc; |
| | | }, |
| | | { input: 0, scrap: 0, output: 0 } |
| | | ) |
| | | ); |
| | | |
| | | const hasProcessData = computed(() => { |
| | | if (!processChartData.value.length) return false; |
| | | return processChartData.value.some((item) => { |
| | | const input = Number(item.input || 0); |
| | | const scrap = Number(item.scrap || 0); |
| | | const output = Number(item.output || 0); |
| | | return input > 0 || scrap > 0 || output > 0; |
| | | }); |
| | | }); |
| | | |
| | | const dashboardCards = computed(() => [ |
| | | { |
| | | key: "sales", |
| | | title: "é宿°æ®", |
| | | desc: "æ¬æéå®é¢(å
)", |
| | | value: formatNumber(businessInfo.value.monthSaleMoney), |
| | | subLabel: "æªå¼ç¥¨éé¢", |
| | | subValue: formatNumber(businessInfo.value.monthSaleHaveMoney), |
| | | trend: `å æ¯ ${ratioText(businessInfo.value.monthSaleHaveMoney, businessInfo.value.monthSaleMoney)}`, |
| | | icon: DataLine, |
| | | visible: visibleModules.value.sales, |
| | | }, |
| | | { |
| | | key: "purchase", |
| | | title: "éè´æ°æ®", |
| | | desc: "æ¬æéè´é¢(å
)", |
| | | value: formatNumber(businessInfo.value.monthPurchaseMoney), |
| | | subLabel: "å¾
仿¬¾éé¢", |
| | | subValue: formatNumber(businessInfo.value.monthPurchaseHaveMoney), |
| | | trend: `å æ¯ ${ratioText( |
| | | businessInfo.value.monthPurchaseHaveMoney, |
| | | businessInfo.value.monthPurchaseMoney |
| | | )}`, |
| | | icon: ShoppingCartFull, |
| | | visible: visibleModules.value.procurement, |
| | | }, |
| | | { |
| | | key: "inventory", |
| | | title: "åºåæ°æ®", |
| | | desc: "å½ååºåæ»é(ä»¶)", |
| | | value: formatNumber(businessInfo.value.inventoryNum), |
| | | subLabel: "仿¥å
¥åº", |
| | | subValue: formatNumber(businessInfo.value.todayInventoryNum), |
| | | trend: "åºåç»ææç»ä¼å", |
| | | icon: Box, |
| | | visible: visibleModules.value.inventory, |
| | | }, |
| | | { |
| | | key: "production", |
| | | title: "ç产æ»è§", |
| | | desc: "累计产åº(ä»¶)", |
| | | value: formatNumber(productionOverviewData.value.totalOutput), |
| | | subLabel: "累计æ¥åº", |
| | | subValue: formatNumber(productionOverviewData.value.totalScrap), |
| | | trend: `è¯ç ${Number(productionOverviewData.value.yieldRate || 0).toFixed(2)}%`, |
| | | icon: Operation, |
| | | visible: visibleModules.value.production, |
| | | }, |
| | | ].filter((item) => item.visible)); |
| | | |
| | | const productionOrders = ref([]); |
| | | |
| | | const orderFilterOptions = ["all", "waiting", "inProgress", "completed", "paused"]; |
| | | const orderFilterAliasMap = { |
| | | 1: "waiting", |
| | | 2: "inProgress", |
| | | 3: "completed", |
| | | 4: "paused", |
| | | }; |
| | | const orderFilter = ref("all"); |
| | | const filteredOrders = computed(() => productionOrders.value); |
| | | |
| | | const normalizeOrderFilter = (value, fallback = "all") => { |
| | | const safeFallback = orderFilterOptions.includes(fallback) ? fallback : "all"; |
| | | const text = String(value ?? "").trim(); |
| | | if (orderFilterAliasMap[text]) { |
| | | return orderFilterAliasMap[text]; |
| | | } |
| | | }) |
| | | return orderFilterOptions.includes(text) ? text : safeFallback; |
| | | }; |
| | | |
| | | const formatAmount = (n) => { |
| | | const num = Number(n || 0) |
| | | return num.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) |
| | | } |
| | | const parseCount = (value) => { |
| | | if (value === null || value === undefined || value === "") return null; |
| | | const num = Number(value); |
| | | return Number.isFinite(num) ? num : null; |
| | | }; |
| | | |
| | | const refreshProcessStats = () => { |
| | | processDataProductionStatistics({ |
| | | const resolveProgressCount = (rawValue, currentStatus, targetStatus, total) => { |
| | | const count = parseCount(rawValue); |
| | | if (count !== null) return count; |
| | | return currentStatus === targetStatus ? total : 0; |
| | | }; |
| | | |
| | | const getCompareTrend = (value) => { |
| | | const num = Number(value || 0); |
| | | if (num > 0) return "up"; |
| | | if (num < 0) return "down"; |
| | | return "flat"; |
| | | }; |
| | | |
| | | const getCompareText = (value) => { |
| | | const num = Number(value || 0); |
| | | const abs = Math.abs(num).toFixed(2); |
| | | if (num > 0) return `è¾æ¨æ¥ â ${abs}%`; |
| | | if (num < 0) return `è¾æ¨æ¥ â ${abs}%`; |
| | | return "è¾æ¨æ¥ æå¹³"; |
| | | }; |
| | | |
| | | const realtimeBoard = computed(() => { |
| | | const oee = Number(realtimeBoardData.value.deviceOee?.value || 0); |
| | | const orderAchievement = Number(realtimeBoardData.value.orderAchievementRate?.value || 0); |
| | | const defectRate = Number(realtimeBoardData.value.defectRate?.value || 0); |
| | | const oeeCompare = Number(realtimeBoardData.value.deviceOee?.compareYesterday || 0); |
| | | const orderCompare = Number(realtimeBoardData.value.orderAchievementRate?.compareYesterday || 0); |
| | | const defectCompare = Number(realtimeBoardData.value.defectRate?.compareYesterday || 0); |
| | | return [ |
| | | { |
| | | key: "oee", |
| | | label: "è®¾å¤ OEE", |
| | | percent: clampPercent(oee), |
| | | display: `${oee.toFixed(2)}%`, |
| | | delta: getCompareText(oeeCompare), |
| | | trend: getCompareTrend(oeeCompare), |
| | | color: "#2d8cff", |
| | | }, |
| | | { |
| | | key: "order", |
| | | label: "订åè¾¾æç", |
| | | percent: clampPercent(orderAchievement), |
| | | display: `${orderAchievement.toFixed(2)}%`, |
| | | delta: getCompareText(orderCompare), |
| | | trend: getCompareTrend(orderCompare), |
| | | color: "#31d2ff", |
| | | }, |
| | | { |
| | | key: "defect", |
| | | label: "ä¸è¯ç", |
| | | percent: clampPercent(defectRate), |
| | | display: `${defectRate.toFixed(2)}%`, |
| | | delta: getCompareText(defectCompare), |
| | | trend: getCompareTrend(defectCompare), |
| | | color: "#f6a23f", |
| | | }, |
| | | ]; |
| | | }); |
| | | |
| | | const warningList = ref([ |
| | | { |
| | | id: 1, |
| | | level: "device", |
| | | title: "设å¤é¢è¦", |
| | | desc: "CNC-001 è®¾å¤æ¯å¨å¼å¸¸", |
| | | time: "10:24:32", |
| | | }, |
| | | { |
| | | id: 2, |
| | | level: "quality", |
| | | title: "è´¨éé¢è¦", |
| | | desc: "订å SO-20260517 ä¸è¯çè¶
æ ", |
| | | time: "09:15:47", |
| | | }, |
| | | { |
| | | id: 3, |
| | | level: "material", |
| | | title: "ç©æé¢è¦", |
| | | desc: "ç©æ 1002001 åºåä¸è¶³", |
| | | time: "08:47:21", |
| | | }, |
| | | ]); |
| | | |
| | | const quickEntryConfigs = [ |
| | | { label: "主ç产计å", icon: Calendar, titles: ["主ç产计å"], fallbackPath: "/productionPlan/productionPlan" }, |
| | | { label: "ç产订å", icon: Tickets, titles: ["ç产订å"], fallbackPath: "/productionManagement/productionOrder" }, |
| | | { label: "ç产æ¥å·¥", icon: EditPen, titles: ["ç产æ¥å·¥"], fallbackPath: "/productionManagement/productionReporting" }, |
| | | { label: "设å¤å°è´¦", icon: Tools, titles: ["设å¤å°è´¦"], fallbackPath: "/equipmentManagement/ledger" }, |
| | | { label: "éå®å°è´¦", icon: DataLine, titles: ["éå®å°è´¦"], fallbackPath: "/salesManagement/salesLedger" }, |
| | | { label: "éè´å°è´¦", icon: ShoppingCartFull, titles: ["éè´å°è´¦"], fallbackPath: "/procurementManagement/procurementLedger" }, |
| | | { label: "åå·¥å°è´¦", icon: UserFilled, titles: ["åå·¥å°è´¦", "å¨èåå·¥å°è´¦"], fallbackPath: "/personnelManagement/employeeRecord" }, |
| | | { label: "åºå管ç", icon: Box, titles: ["åºå管ç"], fallbackPath: "/inventoryManagement/stockManage" }, |
| | | ]; |
| | | |
| | | const normalizeMenuTitle = (title) => String(title || "").replace(/\s+/g, "").trim(); |
| | | const normalizeRoutePath = (path) => |
| | | String(path || "") |
| | | .trim() |
| | | .replace(/\/+/g, "/") |
| | | .replace(/\/$/, "") |
| | | .toLowerCase(); |
| | | |
| | | const resolveRoutePath = (route, parentPath = "") => { |
| | | const currentPath = String(route?.path || "").trim(); |
| | | if (!currentPath) return parentPath || ""; |
| | | if (/^(https?:)?\/\//.test(currentPath)) return currentPath; |
| | | if (currentPath.startsWith("/")) return currentPath; |
| | | const basePath = parentPath && parentPath !== "/" ? parentPath.replace(/\/$/, "") : ""; |
| | | return `${basePath}/${currentPath}`.replace(/\/+/g, "/"); |
| | | }; |
| | | |
| | | const collectAccessibleRoutes = (routes = [], parentPath = "") => { |
| | | const items = []; |
| | | (routes || []).forEach((route) => { |
| | | if (!route) return; |
| | | const fullPath = resolveRoutePath(route, parentPath); |
| | | const title = route.meta?.title ?? route.title ?? ""; |
| | | if (title && fullPath && !String(route.redirect || "").includes("noRedirect")) { |
| | | items.push({ |
| | | title: normalizeMenuTitle(title), |
| | | path: normalizeRoutePath(fullPath), |
| | | }); |
| | | } |
| | | if (Array.isArray(route.children) && route.children.length > 0) { |
| | | items.push(...collectAccessibleRoutes(route.children, fullPath)); |
| | | } |
| | | }); |
| | | return items; |
| | | }; |
| | | |
| | | const accessibleMenuRoutes = computed(() => { |
| | | const routePool = |
| | | permissionStore.defaultRoutes?.length > 0 |
| | | ? permissionStore.defaultRoutes |
| | | : permissionStore.sidebarRouters?.length > 0 |
| | | ? permissionStore.sidebarRouters |
| | | : permissionStore.routes; |
| | | return collectAccessibleRoutes(routePool || []); |
| | | }); |
| | | |
| | | const moduleAccessConfig = { |
| | | sales: { |
| | | titles: ["éå®ç®¡ç", "éå®å°è´¦"], |
| | | pathPrefixes: ["/salesmanagement"], |
| | | }, |
| | | procurement: { |
| | | titles: ["éè´ç®¡ç", "éè´å°è´¦"], |
| | | pathPrefixes: ["/procurementmanagement"], |
| | | }, |
| | | inventory: { |
| | | titles: ["åºå管ç"], |
| | | pathPrefixes: ["/inventorymanagement"], |
| | | }, |
| | | production: { |
| | | titles: ["ç产管ç", "主ç产计å", "ç产订å", "ç产æ¥å·¥"], |
| | | pathPrefixes: ["/productionmanagement", "/productionplan"], |
| | | }, |
| | | quality: { |
| | | titles: ["è´¨é管ç"], |
| | | pathPrefixes: ["/qualitymanagement"], |
| | | }, |
| | | equipment: { |
| | | titles: ["设å¤ç®¡ç", "设å¤å°è´¦"], |
| | | pathPrefixes: ["/equipmentmanagement"], |
| | | }, |
| | | personnel: { |
| | | titles: ["人äºç®¡ç", "åå·¥å°è´¦", "å¨èåå·¥å°è´¦"], |
| | | pathPrefixes: ["/personnelmanagement"], |
| | | }, |
| | | approval: { |
| | | titles: ["åå审æ¹", "å¾
åäºé¡¹"], |
| | | pathPrefixes: ["/collaborativeapproval"], |
| | | }, |
| | | finance: { |
| | | titles: ["è´¢å¡ç®¡ç", "è´¢å¡åæ", "忬¾ç®¡ç", "å¼ç¥¨ç®¡ç"], |
| | | pathPrefixes: ["/financesuite", "/financialmanagement"], |
| | | }, |
| | | }; |
| | | |
| | | const hasModuleAccess = (config) => |
| | | accessibleMenuRoutes.value.some((route) => { |
| | | const matchedTitle = (config.titles || []).some((title) => route.title === normalizeMenuTitle(title)); |
| | | const matchedPath = (config.pathPrefixes || []).some( |
| | | (prefix) => route.path === prefix || route.path.startsWith(`${prefix}/`) |
| | | ); |
| | | return matchedTitle || matchedPath; |
| | | }); |
| | | |
| | | const visibleModules = computed(() => ({ |
| | | sales: hasModuleAccess(moduleAccessConfig.sales), |
| | | procurement: hasModuleAccess(moduleAccessConfig.procurement), |
| | | inventory: hasModuleAccess(moduleAccessConfig.inventory), |
| | | production: hasModuleAccess(moduleAccessConfig.production), |
| | | quality: hasModuleAccess(moduleAccessConfig.quality), |
| | | equipment: hasModuleAccess(moduleAccessConfig.equipment), |
| | | personnel: hasModuleAccess(moduleAccessConfig.personnel), |
| | | approval: hasModuleAccess(moduleAccessConfig.approval), |
| | | finance: hasModuleAccess(moduleAccessConfig.finance), |
| | | })); |
| | | |
| | | const visiblePanels = computed(() => ({ |
| | | process: visibleModules.value.production, |
| | | order: visibleModules.value.production, |
| | | contract: visibleModules.value.sales, |
| | | quality: visibleModules.value.quality, |
| | | todo: visibleModules.value.approval, |
| | | realtime: visibleModules.value.production, |
| | | quick: quickEntries.value.length > 0, |
| | | plan: visibleModules.value.production, |
| | | receipt: visibleModules.value.sales || visibleModules.value.finance, |
| | | })); |
| | | |
| | | const hasLeftPanels = computed( |
| | | () => visiblePanels.value.process || visiblePanels.value.order || visiblePanels.value.contract || visiblePanels.value.quality |
| | | ); |
| | | const hasRightPanels = computed( |
| | | () => visiblePanels.value.todo || visiblePanels.value.realtime || visiblePanels.value.quick || visiblePanels.value.plan || visiblePanels.value.receipt |
| | | ); |
| | | const hasVisiblePanels = computed(() => hasLeftPanels.value || hasRightPanels.value); |
| | | |
| | | const quickEntries = computed(() => |
| | | quickEntryConfigs |
| | | .map((item) => { |
| | | const targetRoute = accessibleMenuRoutes.value.find((route) => |
| | | item.titles.some((title) => route.title === normalizeMenuTitle(title)) |
| | | ); |
| | | const resolvedPath = targetRoute?.path || ""; |
| | | return resolvedPath |
| | | ? { |
| | | label: item.label, |
| | | icon: item.icon, |
| | | path: resolvedPath, |
| | | } |
| | | : null; |
| | | }) |
| | | .filter(Boolean) |
| | | ); |
| | | |
| | | const updateNowTime = () => { |
| | | nowTime.value = dayjs().format("YYYY-MM-DD HH:mm:ss"); |
| | | }; |
| | | |
| | | const formatNumber = (value) => { |
| | | const num = Number(value || 0); |
| | | return num.toLocaleString(undefined, { |
| | | minimumFractionDigits: 2, |
| | | maximumFractionDigits: 2, |
| | | }); |
| | | }; |
| | | |
| | | const formatAmount = (value) => { |
| | | const num = Number(value || 0); |
| | | return num.toLocaleString(undefined, { |
| | | minimumFractionDigits: 2, |
| | | maximumFractionDigits: 2, |
| | | }); |
| | | }; |
| | | |
| | | const trendText = (value) => { |
| | | const num = Number(value || 0); |
| | | const flag = num >= 0 ? "â" : "â"; |
| | | return `${flag} ${Math.abs(num).toFixed(1)}%`; |
| | | }; |
| | | |
| | | const ratioNumber = (numerator, denominator) => { |
| | | const n = Number(numerator || 0); |
| | | const d = Number(denominator || 0); |
| | | if (!d) return 0; |
| | | return (n / d) * 100; |
| | | }; |
| | | |
| | | const ratioText = (numerator, denominator) => `${ratioNumber(numerator, denominator).toFixed(1)}%`; |
| | | |
| | | const clampPercent = (val) => Math.max(0, Math.min(100, Number(val || 0))); |
| | | |
| | | const getOrderStatusText = (status) => { |
| | | const mapping = { |
| | | 1: "å¾
å¼å§", |
| | | 2: "è¿è¡ä¸", |
| | | 3: "已宿", |
| | | 4: "å·²æå", |
| | | }; |
| | | return mapping[status] || "æªç¥"; |
| | | }; |
| | | |
| | | const getOrderStatusType = (status) => { |
| | | const mapping = { |
| | | 1: "info", |
| | | 2: "success", |
| | | 3: "primary", |
| | | 4: "warning", |
| | | }; |
| | | return mapping[status] || "info"; |
| | | }; |
| | | |
| | | const formatDueDate = (value) => { |
| | | if (!value) return "--"; |
| | | const date = dayjs(value); |
| | | return date.isValid() ? date.format("YYYY-MM-DD") : "--"; |
| | | }; |
| | | |
| | | const mapOrderProgressRecord = (item = {}) => ({ |
| | | orderNo: item.orderNo || "--", |
| | | productName: item.productName || "--", |
| | | planQty: Number(item.plannedQuantity || 0), |
| | | completedQty: Number(item.completedQuantity || 0), |
| | | completionRate: clampPercent(Number(item.completionRate || 0)), |
| | | deliveryDate: formatDueDate(item.dueDate), |
| | | status: Number(item.status || 0), |
| | | statusLabel: item.statusLabel || "", |
| | | }); |
| | | |
| | | const mapTodayPlanRecord = (item = {}) => ({ |
| | | orderNo: item.orderNo || "--", |
| | | productName: item.productName || "--", |
| | | planQty: Number(item.plannedQuantity || 0), |
| | | deliveryDate: formatDueDate(item.dueDate), |
| | | status: Number(item.status || 0), |
| | | statusLabel: item.statusLabel || "", |
| | | }); |
| | | |
| | | const refreshProductionOverview = async () => { |
| | | try { |
| | | const res = await productionOverview(); |
| | | const data = res?.data || {}; |
| | | productionOverviewData.value = { |
| | | totalOutput: Number(data.totalOutput || 0), |
| | | totalScrap: Number(data.totalScrap || 0), |
| | | yieldRate: Number(data.yieldRate || 0), |
| | | }; |
| | | } catch { |
| | | productionOverviewData.value = { |
| | | totalOutput: 0, |
| | | totalScrap: 0, |
| | | yieldRate: 0, |
| | | }; |
| | | } |
| | | }; |
| | | |
| | | const refreshProductionRealtimeBoard = async () => { |
| | | try { |
| | | const res = await productionRealtimeBoard(); |
| | | const data = res?.data || {}; |
| | | realtimeBoardData.value = { |
| | | deviceOee: { |
| | | value: Number(data.deviceOee?.value || 0), |
| | | compareYesterday: Number(data.deviceOee?.compareYesterday || 0), |
| | | }, |
| | | orderAchievementRate: { |
| | | value: Number(data.orderAchievementRate?.value || 0), |
| | | compareYesterday: Number(data.orderAchievementRate?.compareYesterday || 0), |
| | | }, |
| | | defectRate: { |
| | | value: Number(data.defectRate?.value || 0), |
| | | compareYesterday: Number(data.defectRate?.compareYesterday || 0), |
| | | }, |
| | | }; |
| | | } catch { |
| | | realtimeBoardData.value = { |
| | | deviceOee: { value: 0, compareYesterday: 0 }, |
| | | orderAchievementRate: { value: 0, compareYesterday: 0 }, |
| | | defectRate: { value: 0, compareYesterday: 0 }, |
| | | }; |
| | | } |
| | | }; |
| | | |
| | | const refreshProductionOrderProgress = async () => { |
| | | try { |
| | | const res = await productionOrderProgress({ |
| | | status: orderFilter.value, |
| | | tab: orderFilter.value, |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | }); |
| | | const data = res?.data || {}; |
| | | const statusValue = normalizeOrderFilter(data.status, orderFilter.value); |
| | | const total = Number(data.total || 0); |
| | | orderProgressMeta.value = { |
| | | status: statusValue, |
| | | tab: data.tab || orderFilter.value, |
| | | bizDate: data.bizDate || null, |
| | | total, |
| | | pageNum: Number(data.pageNum || 1), |
| | | pageSize: Number(data.pageSize || 10), |
| | | waitingCount: resolveProgressCount(data.waitingCount, statusValue, "waiting", total), |
| | | inProgressCount: resolveProgressCount(data.inProgressCount, statusValue, "inProgress", total), |
| | | completedCount: resolveProgressCount(data.completedCount, statusValue, "completed", total), |
| | | pausedCount: resolveProgressCount(data.pausedCount, statusValue, "paused", total), |
| | | }; |
| | | productionOrders.value = (data.records || []).map(mapOrderProgressRecord); |
| | | } catch { |
| | | orderProgressMeta.value = { |
| | | status: orderFilter.value, |
| | | tab: orderFilter.value, |
| | | bizDate: null, |
| | | total: 0, |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | waitingCount: 0, |
| | | inProgressCount: 0, |
| | | completedCount: 0, |
| | | pausedCount: 0, |
| | | }; |
| | | productionOrders.value = []; |
| | | } |
| | | }; |
| | | |
| | | const refreshTodayProductionPlan = async () => { |
| | | try { |
| | | const res = await todayProductionPlan({ |
| | | limit: 4, |
| | | planDate: nowDate.value, |
| | | }); |
| | | const data = res?.data || {}; |
| | | todayPlanTotal.value = Number(data.total || 0); |
| | | todayPlanList.value = (data.records || []).map(mapTodayPlanRecord); |
| | | } catch { |
| | | todayPlanTotal.value = 0; |
| | | todayPlanList.value = []; |
| | | } |
| | | }; |
| | | |
| | | const getBusinessData = async () => { |
| | | const res = await getBusiness(); |
| | | businessInfo.value = { ...res.data }; |
| | | }; |
| | | |
| | | const analysisCustomer = async () => { |
| | | const res = await analysisCustomerContractAmounts(); |
| | | sum.value = res.data.sum; |
| | | yny.value = res.data.yny; |
| | | chain.value = res.data.chain; |
| | | materialPieSeries.value[0].data = (res.data.item || []).map((item, index) => ({ |
| | | ...item, |
| | | rate: Number(item.rate || 0), |
| | | itemStyle: { color: piePalette[index % piePalette.length] }, |
| | | })); |
| | | }; |
| | | |
| | | const todoInfoS = async () => { |
| | | const res = await homeTodos(); |
| | | todoList.value = res.data || []; |
| | | }; |
| | | |
| | | const statisticsReceivable = async () => { |
| | | const res = await statisticsReceivablePayable({ type: 1 }); |
| | | barSeries.value[0].data = [ |
| | | { value: res.data.payableMoney, itemStyle: { color: barColors2[0] } }, |
| | | { value: res.data.receivableMoney, itemStyle: { color: barColors2[1] } }, |
| | | ]; |
| | | }; |
| | | |
| | | const qualityStatisticsInfo = async () => { |
| | | const res = await qualityInspectionStatistics({ type: qualityRange.value }); |
| | | xAxis1.value[0].data = []; |
| | | barSeries1.value[0].data = []; |
| | | barSeries1.value[1].data = []; |
| | | barSeries1.value[2].data = []; |
| | | (res.data.item || []).forEach((item) => { |
| | | xAxis1.value[0].data.push(item.date); |
| | | barSeries1.value[0].data.push(item.supplierNum); |
| | | barSeries1.value[1].data.push(item.processNum); |
| | | barSeries1.value[2].data.push(item.factoryNum); |
| | | }); |
| | | qualityStatisticsObject.value.supplierNum = res.data.supplierNum; |
| | | qualityStatisticsObject.value.processNum = res.data.processNum; |
| | | qualityStatisticsObject.value.factoryNum = res.data.factoryNum; |
| | | }; |
| | | |
| | | const getAmountHalfYearNum = async () => { |
| | | const res = await getAmountHalfYear(); |
| | | const monthName = []; |
| | | const receiptAmount = []; |
| | | const invoiceAmount = []; |
| | | (res.data || []).forEach((item) => { |
| | | monthName.push(item.month); |
| | | receiptAmount.push(item.receiptAmount); |
| | | invoiceAmount.push(item.invoiceAmount); |
| | | }); |
| | | |
| | | xAxis2.value[0].data = monthName.map((item) => item.replace(/~/g, "\n~")); |
| | | lineSeries.value[0].data = invoiceAmount; |
| | | lineSeries.value[1].data = receiptAmount; |
| | | }; |
| | | |
| | | const getProcessList = async () => { |
| | | const res = await list(); |
| | | processOptions.value = res.data.records || []; |
| | | }; |
| | | |
| | | const refreshProcessStats = async () => { |
| | | const res = await processDataProductionStatistics({ |
| | | type: processRange.value, |
| | | processIds: selectedProcessIds.value.length > 0 ? selectedProcessIds.value.join(',') : null |
| | | }).then(res => { |
| | | processChartData.value = res.data.map(item => ({ |
| | | name: item.processName, |
| | | input: item.totalInput, |
| | | scrap: item.totalScrap, |
| | | output: item.totalOutput |
| | | })) |
| | | processYAxis.value[0].data = processChartData.value.map((i) => i.name) |
| | | activeProcessIndex.value = 0 |
| | | }) |
| | | } |
| | | processIds: selectedProcessIds.value.length > 0 ? selectedProcessIds.value.join(",") : null, |
| | | }); |
| | | processChartData.value = (res.data || []).map((item) => ({ |
| | | name: item.processName, |
| | | input: item.totalInput, |
| | | scrap: item.totalScrap, |
| | | output: item.totalOutput, |
| | | })); |
| | | processYAxis.value[0].data = processChartData.value.map((item) => item.name); |
| | | activeProcessIndex.value = 0; |
| | | }; |
| | | |
| | | const openProcessDialog = () => { |
| | | tempProcessIds.value = [...selectedProcessIds.value]; |
| | | processDialogVisible.value = true; |
| | | }; |
| | | |
| | | const handleProcessDialogConfirm = () => { |
| | | selectedProcessIds.value = [...tempProcessIds.value]; |
| | | processDialogVisible.value = false; |
| | | refreshProcessStats(); |
| | | }; |
| | | |
| | | const resetProcessFilter = () => { |
| | | selectedProcessIds.value = []; |
| | | tempProcessIds.value = []; |
| | | refreshProcessStats(); |
| | | }; |
| | | |
| | | const handleChartClick = (params) => { |
| | | if (params && params.dataIndex !== undefined) { |
| | | activeProcessIndex.value = params.dataIndex; |
| | | } |
| | | }; |
| | | |
| | | const goToQuick = (path) => { |
| | | if (!path) return; |
| | | router.push(path).catch(() => {}); |
| | | }; |
| | | |
| | | watch(orderFilter, () => { |
| | | if (visiblePanels.value.order) { |
| | | refreshProductionOrderProgress(); |
| | | } |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | getBusinessData() |
| | | analysisCustomer() |
| | | todoInfoS() |
| | | statisticsReceivable() |
| | | qualityStatisticsInfo() |
| | | getAmountHalfYearNum() |
| | | refreshProcessStats() |
| | | }) |
| | | updateNowTime(); |
| | | clockTimer = setInterval(updateNowTime, 1000); |
| | | if (dashboardCards.value.length > 0) { |
| | | getBusinessData(); |
| | | } |
| | | if (visibleModules.value.production) { |
| | | refreshProductionOverview(); |
| | | } |
| | | if (visiblePanels.value.contract) { |
| | | analysisCustomer(); |
| | | } |
| | | if (visiblePanels.value.todo) { |
| | | todoInfoS(); |
| | | } |
| | | if (visiblePanels.value.quality) { |
| | | qualityStatisticsInfo(); |
| | | } |
| | | if (visiblePanels.value.receipt) { |
| | | statisticsReceivable(); |
| | | getAmountHalfYearNum(); |
| | | } |
| | | if (visiblePanels.value.process) { |
| | | getProcessList(); |
| | | refreshProcessStats(); |
| | | } |
| | | if (visiblePanels.value.order) { |
| | | refreshProductionOrderProgress(); |
| | | } |
| | | if (visiblePanels.value.realtime) { |
| | | refreshProductionRealtimeBoard(); |
| | | } |
| | | if (visiblePanels.value.plan) { |
| | | refreshTodayProductionPlan(); |
| | | } |
| | | }); |
| | | |
| | | onUnmounted(() => { |
| | | if (clockTimer) { |
| | | clearInterval(clockTimer); |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .dashboard { |
| | | min-height: 100vh; |
| | | padding: 20px; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .dashboard-top { |
| | | display: flex; |
| | | gap: 20px; |
| | | margin-bottom: 20px; |
| | | align-items: flex-start; |
| | | justify-content: space-evenly; |
| | | } |
| | | |
| | | .company-info { |
| | | .dashboard-cockpit { |
| | | min-height: calc(100vh - var(--topbar-height) - var(--tagsbar-height)); |
| | | width: 100%; |
| | | min-width: 0; |
| | | padding: 0; |
| | | overflow: hidden; |
| | | border-radius: 12px; |
| | | background: #fff; |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 16px; |
| | | overflow-x: clip; |
| | | margin-top: 10px; |
| | | } |
| | | |
| | | .welcome-banner { |
| | | padding: 10px 10px; |
| | | background: linear-gradient(135deg, rgba(229, 240, 255, 0.9), rgba(214, 232, 255, 0.7), rgba(207, 236, 255, 0.9)); |
| | | .digital-number { |
| | | font-family: "DIN Alternate Bold", "Segoe UI", "PingFang SC", sans-serif; |
| | | letter-spacing: 0; |
| | | } |
| | | |
| | | .welcome-title { |
| | | font-size: 18px; |
| | | font-weight: 700; |
| | | color: #222; |
| | | line-height: 1.3; |
| | | .cockpit-panel { |
| | | position: relative; |
| | | background: rgba(255, 255, 255, 0.9); |
| | | border: 1px solid rgba(148, 163, 184, 0.18); |
| | | border-radius: 16px; |
| | | box-shadow: 0 12px 32px rgba(15, 23, 42, 0.06); |
| | | backdrop-filter: blur(12px); |
| | | padding: 16px; |
| | | } |
| | | |
| | | .welcome-panel { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | min-height: 92px; |
| | | padding: 18px 22px; |
| | | background: |
| | | radial-gradient(circle at 8% 20%, rgba(59, 130, 246, 0.12), transparent 32%), |
| | | linear-gradient(135deg, rgba(255, 255, 255, 0.94), rgba(239, 246, 255, 0.88)); |
| | | } |
| | | |
| | | .welcome-user { |
| | | margin-right: 6px; |
| | | } |
| | | |
| | | .welcome-time { |
| | | margin-top: 10px; |
| | | font-size: 16px; |
| | | color: rgba(0, 0, 0, 0.55); |
| | | } |
| | | |
| | | .user-card { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 10px; |
| | | padding: 18px 22px; |
| | | } |
| | | |
| | | .user-card-main { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 5px; |
| | | min-width: 0; |
| | | } |
| | | |
| | | .user-name { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | color: #111; |
| | | letter-spacing: 1px; |
| | | } |
| | | |
| | | .user-role { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | height: 20px; |
| | | padding: 5px 10px; |
| | | background: rgba(245, 246, 248, 1); |
| | | color: #333; |
| | | width: fit-content; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .user-meta { |
| | | font-size: 12px; |
| | | color: rgba(0, 0, 0, 0.55); |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | |
| | | .user-meta .sep { |
| | | margin: 0 10px; |
| | | color: rgba(0, 0, 0, 0.25); |
| | | gap: 12px; |
| | | } |
| | | |
| | | .avatar { |
| | | width: 90px; |
| | | height: 90px; |
| | | border-radius: 50%; |
| | | width: 52px; |
| | | height: 52px; |
| | | border: 1px solid rgba(147, 197, 253, 0.42); |
| | | background: linear-gradient(145deg, #ffffff, #eef5ff); |
| | | box-shadow: 0 8px 20px rgba(37, 99, 235, 0.14); |
| | | } |
| | | |
| | | .avatar :deep(img) { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: cover; |
| | | flex: 0 0 auto; |
| | | } |
| | | |
| | | .data-cards { |
| | | width: 50%; |
| | | display: flex; |
| | | gap: 16px; |
| | | justify-content: flex-start; |
| | | background: #ffffff; |
| | | border-radius: 12px; |
| | | padding: 20px; |
| | | .avatar :deep(.el-icon) { |
| | | font-size: 24px; |
| | | color: #3b82f6; |
| | | } |
| | | |
| | | .data-title { |
| | | .welcome-title { |
| | | font-size: 28px; |
| | | font-weight: 700; |
| | | font-size: 26px; |
| | | color: #FFFFFF; |
| | | color: #1e3a5f; |
| | | line-height: 1.08; |
| | | } |
| | | |
| | | .data-num { |
| | | .welcome-subtitle { |
| | | margin-top: 6px; |
| | | color: #64748b; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .welcome-meta { |
| | | text-align: right; |
| | | } |
| | | |
| | | .meta-time { |
| | | font-size: 28px; |
| | | color: #1f3658; |
| | | font-weight: 700; |
| | | } |
| | | |
| | | .meta-extra { |
| | | margin-top: 6px; |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | gap: 14px; |
| | | color: #64748b; |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .meta-tip { |
| | | margin-top: 4px; |
| | | color: #7a8ca6; |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .top-row { |
| | | display: block; |
| | | } |
| | | |
| | | .stats-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(4, minmax(0, 1fr)); |
| | | gap: 14px; |
| | | } |
| | | |
| | | .stat-card { |
| | | position: relative; |
| | | border-radius: 18px; |
| | | padding: 18px 20px 22px; |
| | | min-height: 182px; |
| | | height: auto; |
| | | overflow: hidden; |
| | | border: 1px solid rgba(148, 163, 184, 0.2); |
| | | box-shadow: 0 10px 26px rgba(15, 23, 42, 0.06); |
| | | transition: transform 0.22s ease, box-shadow 0.22s ease; |
| | | } |
| | | |
| | | .stat-card:hover { |
| | | transform: translateY(-2px); |
| | | box-shadow: 0 18px 40px rgba(37, 99, 235, 0.1); |
| | | } |
| | | |
| | | .stat-card.sales { |
| | | background: linear-gradient(135deg, #ffffff 0%, #eaf3ff 100%); |
| | | } |
| | | |
| | | .stat-card.purchase { |
| | | background: linear-gradient(135deg, #ffffff 0%, #e8fffb 100%); |
| | | } |
| | | |
| | | .stat-card.inventory { |
| | | background: linear-gradient(135deg, #ffffff 0%, #f2edff 100%); |
| | | } |
| | | |
| | | .stat-card.production { |
| | | background: linear-gradient(135deg, #ffffff 0%, #fff4e6 100%); |
| | | } |
| | | |
| | | .stat-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: flex-start; |
| | | position: relative; |
| | | z-index: 2; |
| | | } |
| | | |
| | | .stat-title { |
| | | font-size: 16px; |
| | | font-weight: 700; |
| | | } |
| | | |
| | | .stat-card.sales .stat-title { |
| | | color: #1d4ed8; |
| | | } |
| | | |
| | | .stat-card.purchase .stat-title { |
| | | color: #0f766e; |
| | | } |
| | | |
| | | .stat-card.inventory .stat-title { |
| | | color: #6d28d9; |
| | | } |
| | | |
| | | .stat-card.production .stat-title { |
| | | color: #c2410c; |
| | | } |
| | | |
| | | .stat-desc { |
| | | margin-top: 6px; |
| | | color: #64748b; |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .stat-icon-orb { |
| | | width: 52px; |
| | | height: 52px; |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-top: 20px; |
| | | justify-content: center; |
| | | font-size: 22px; |
| | | color: #fff; |
| | | } |
| | | |
| | | .data-card { |
| | | background: #fff; |
| | | border-radius: 12px; |
| | | padding: 14px 10px 10px 10px; |
| | | min-width: 160px; |
| | | box-shadow: 0 2px 8px #eee; |
| | | display: flex; |
| | | flex-direction: column; |
| | | width: 32%; |
| | | height: 140px; |
| | | .stat-card.sales .stat-icon-orb { |
| | | background: linear-gradient(135deg, #2563eb, #60a5fa); |
| | | box-shadow: 0 10px 24px rgba(37, 99, 235, 0.32); |
| | | } |
| | | |
| | | .data-card.sales { |
| | | background-image: url("../assets/images/xioashoushuju.png"); |
| | | background-size: cover; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | .stat-card.purchase .stat-icon-orb { |
| | | background: linear-gradient(135deg, #14b8a6, #5eead4); |
| | | box-shadow: 0 10px 24px rgba(20, 184, 166, 0.3); |
| | | } |
| | | |
| | | .data-card.purchase { |
| | | background-image: url("../assets/images/caigou.png"); |
| | | background-size: cover; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | .stat-card.inventory .stat-icon-orb { |
| | | background: linear-gradient(135deg, #7c3aed, #a78bfa); |
| | | box-shadow: 0 10px 24px rgba(124, 58, 237, 0.28); |
| | | } |
| | | |
| | | .data-card.inventory { |
| | | background-image: url("../assets/images/kucun.png"); |
| | | background-size: cover; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | .stat-card.production .stat-icon-orb { |
| | | background: linear-gradient(135deg, #f97316, #fdba74); |
| | | box-shadow: 0 10px 24px rgba(249, 115, 22, 0.3); |
| | | } |
| | | |
| | | .data-desc { |
| | | font-weight: 500; |
| | | .stat-value { |
| | | margin-top: 14px; |
| | | font-size: 30px; |
| | | line-height: 1.08; |
| | | font-weight: 700; |
| | | color: #0f172a; |
| | | position: relative; |
| | | z-index: 2; |
| | | } |
| | | |
| | | .stat-footer { |
| | | margin-top: 8px; |
| | | color: #64748b; |
| | | font-size: 13px; |
| | | color: #FFFFFF; |
| | | } |
| | | |
| | | .data-value { |
| | | font-size: 18px; |
| | | font-weight: 500; |
| | | margin: 10px 0; |
| | | color: #FFFFFF; |
| | | } |
| | | |
| | | .top-left { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 20px; |
| | | height: 180px; |
| | | width: 20%; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | position: relative; |
| | | z-index: 2; |
| | | } |
| | | |
| | | .stat-trend { |
| | | margin-top: 6px; |
| | | color: #0ea5a4; |
| | | font-size: 13px; |
| | | line-height: 1.25; |
| | | font-weight: 600; |
| | | position: relative; |
| | | z-index: 2; |
| | | } |
| | | |
| | | .stat-wave { |
| | | position: absolute; |
| | | left: 10px; |
| | | right: 10px; |
| | | bottom: 6px; |
| | | height: 30px; |
| | | opacity: 0.62; |
| | | z-index: 1; |
| | | pointer-events: none; |
| | | background: |
| | | url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 340 40' preserveAspectRatio='none'%3E%3Cpath d='M0 31C20 16 44 36 66 24C87 12 107 31 129 18C148 8 169 28 193 16C214 5 237 25 259 14C280 3 306 19 340 8' fill='none' stroke='%236ea4ee' stroke-width='1.5'/%3E%3C/svg%3E") |
| | | center / 100% 100% no-repeat; |
| | | } |
| | | |
| | | .todo-panel { |
| | | background: #fff; |
| | | border-radius: 12px; |
| | | padding: 20px; |
| | | height: 180px; |
| | | width: 30%; |
| | | padding: 12px; |
| | | } |
| | | |
| | | .panel-title-row { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .panel-title { |
| | | font-size: 18px; |
| | | font-weight: 700; |
| | | color: #1f3658; |
| | | position: relative; |
| | | padding-left: 12px; |
| | | } |
| | | |
| | | .panel-title::before { |
| | | content: ""; |
| | | position: absolute; |
| | | left: 0; |
| | | top: 50%; |
| | | transform: translateY(-50%); |
| | | width: 4px; |
| | | height: 18px; |
| | | border-radius: 4px; |
| | | background: linear-gradient(180deg, #2563eb, #38bdf8); |
| | | } |
| | | |
| | | .panel-more { |
| | | font-size: 14px; |
| | | color: #2563eb; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .todo-list { |
| | | height: 100px; |
| | | list-style: none; |
| | | margin: 10px 0 0; |
| | | padding: 0; |
| | | margin: 0; |
| | | font-size: 15px; |
| | | list-style: none; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 8px; |
| | | max-height: 230px; |
| | | overflow-y: auto; |
| | | } |
| | | |
| | | .todo-list li { |
| | | border-radius: 8px; |
| | | margin-bottom: 12px; |
| | | padding: 8px 20px; |
| | | height: 74px; |
| | | .todo-item { |
| | | border: 1px solid rgba(148, 163, 184, 0.2); |
| | | border-radius: 12px; |
| | | background: #f7fbff; |
| | | padding: 10px 12px; |
| | | } |
| | | |
| | | .todo-head { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | background: rgba(225, 227, 250, 0.62); |
| | | } |
| | | |
| | | .todo-title { |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #000000; |
| | | position: relative; |
| | | } |
| | | |
| | | .todo-title::before { |
| | | content: ''; |
| | | /* å¿
éï¼è¡¨ç¤ºè¿éæä¸ä¸ªå
容 */ |
| | | position: absolute; |
| | | left: -10px; |
| | | /* å®ä½å°å·¦ä¾§ */ |
| | | top: 50%; |
| | | /* åç´å±
ä¸ */ |
| | | transform: translateY(-50%); |
| | | /* å¾®è°åç´å±
ä¸ */ |
| | | width: 6px; |
| | | /* åçç´å¾ */ |
| | | height: 6px; |
| | | /* åçç´å¾ */ |
| | | background: #498CEB; |
| | | border-radius: 50%; |
| | | /* 让å
¶åæåå½¢ */ |
| | | } |
| | | |
| | | .todo-division { |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #000000; |
| | | } |
| | | |
| | | .todo-time { |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #000000; |
| | | } |
| | | |
| | | .todo-meta { |
| | | color: #888; |
| | | gap: 10px; |
| | | color: #334155; |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .dashboard-row { |
| | | display: flex; |
| | | gap: 20px; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .main-panel { |
| | | background: #fff; |
| | | border-radius: 12px; |
| | | padding: 20px; |
| | | flex: 1; |
| | | min-width: 0; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .section-title { |
| | | position: relative; |
| | | font-size: 18px; |
| | | color: #333; |
| | | padding-left: 10px; |
| | | margin-bottom: 10px; |
| | | font-weight: 700; |
| | | } |
| | | |
| | | .section-title::before { |
| | | position: absolute; |
| | | left: 0; |
| | | top: 4px; |
| | | content: ''; |
| | | width: 4px; |
| | | height: 18px; |
| | | background-color: #002FA7; |
| | | border-radius: 2px; |
| | | } |
| | | |
| | | .contract-info { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 20px; |
| | | height: 90px; |
| | | background: rgba(245, 245, 245, 0.59); |
| | | width: 100%; |
| | | border-radius: 10px; |
| | | padding: 10px 30px; |
| | | } |
| | | |
| | | .contract-summary { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 30px; |
| | | } |
| | | |
| | | .contract-card { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .contract-name { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #050505; |
| | | } |
| | | |
| | | .contract-meta { |
| | | display: flex; |
| | | align-items: center; |
| | | width: 100%; |
| | | gap: 80px; |
| | | } |
| | | |
| | | .main-amount { |
| | | font-size: 24px; |
| | | color: rgba(51, 50, 50, 0.85); |
| | | } |
| | | |
| | | .up { |
| | | color: #e57373; |
| | | } |
| | | |
| | | .contract-list { |
| | | margin-top: 16px; |
| | | font-size: 14px; |
| | | color: #666; |
| | | list-style: none; |
| | | padding: 0; |
| | | height: 190px; |
| | | overflow-y: auto; |
| | | width: 460px; |
| | | } |
| | | |
| | | .line { |
| | | position: relative; |
| | | width: 230px; |
| | | } |
| | | |
| | | .line::after { |
| | | content: ''; |
| | | position: absolute; |
| | | right: 2px; |
| | | top: 0; |
| | | bottom: 0; |
| | | width: 1px; |
| | | background-color: #C9C5C5; |
| | | border-radius: 2px; |
| | | } |
| | | |
| | | .contract-list li { |
| | | margin-top: 10px; |
| | | } |
| | | |
| | | .quality-cards { |
| | | display: flex; |
| | | gap: 12px; |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .quality-card { |
| | | border-radius: 8px; |
| | | padding: 15px 10px 10px 50px; |
| | | font-weight: 400; |
| | | .todo-desc { |
| | | margin-top: 6px; |
| | | color: #64748b; |
| | | font-size: 12px; |
| | | color: rgba(0, 0, 0, 0.67); |
| | | width: 236px; |
| | | height: 49px; |
| | | background-size: cover; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | line-height: 1.45; |
| | | } |
| | | |
| | | .quality-card.one { |
| | | background-image: url("../assets/images/yuancailiao.png"); |
| | | .todo-no { |
| | | color: #1f3658; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .quality-card.two { |
| | | background-image: url("../assets/images/guocheng.png"); |
| | | .panel-empty { |
| | | min-height: 140px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | color: var(--text-tertiary); |
| | | } |
| | | |
| | | .quality-card.three { |
| | | background-image: url("../assets/images/chuchang.png"); |
| | | |
| | | .empty-home-panel { |
| | | min-height: 220px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | color: #64748b; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .quality-card span { |
| | | color: #4fc3f7; |
| | | font-weight: bold; |
| | | margin-left: 6px; |
| | | .main-grid { |
| | | display: grid; |
| | | grid-template-columns: minmax(0, 1fr) 400px; |
| | | gap: 16px; |
| | | align-items: start; |
| | | } |
| | | |
| | | .chart { |
| | | width: 100%; |
| | | height: 220px; |
| | | margin-top: 10px; |
| | | .left-column, |
| | | .right-column { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 16px; |
| | | min-width: 0; |
| | | } |
| | | |
| | | .process-panel { |
| | | padding-bottom: 10px; |
| | | padding-bottom: 12px; |
| | | } |
| | | |
| | | .process-panel__header { |
| | | .panel-actions { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | gap: 8px; |
| | | align-items: center; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .process-panel__body { |
| | | display: flex; |
| | | gap: 24px; |
| | | align-items: stretch; |
| | | .process-body { |
| | | margin-top: 10px; |
| | | display: grid; |
| | | grid-template-columns: minmax(0, 1fr) 232px; |
| | | gap: 12px; |
| | | align-items: stretch; |
| | | min-height: 0; |
| | | } |
| | | |
| | | .process-panel__chart { |
| | | flex: 1; |
| | | min-width: 0; |
| | | padding: 6px 0; |
| | | .process-chart { |
| | | position: relative; |
| | | border: 1px solid rgba(148, 163, 184, 0.24); |
| | | border-radius: 14px; |
| | | background: |
| | | linear-gradient(180deg, rgba(255, 255, 255, 0.92), rgba(244, 249, 255, 0.9)), |
| | | repeating-linear-gradient( |
| | | to right, |
| | | rgba(148, 163, 184, 0.07) 0, |
| | | rgba(148, 163, 184, 0.07) 1px, |
| | | transparent 1px, |
| | | transparent 48px |
| | | ), |
| | | repeating-linear-gradient( |
| | | to bottom, |
| | | rgba(148, 163, 184, 0.06) 0, |
| | | rgba(148, 163, 184, 0.06) 1px, |
| | | transparent 1px, |
| | | transparent 34px |
| | | ); |
| | | overflow: hidden; |
| | | padding: 10px; |
| | | } |
| | | |
| | | .process-panel__aside { |
| | | width: 260px; |
| | | .process-chart.empty :deep(canvas) { |
| | | opacity: 0.2; |
| | | } |
| | | |
| | | .chart-empty { |
| | | position: absolute; |
| | | inset: 0; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 12px; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 8px; |
| | | color: #64748b; |
| | | font-size: 14px; |
| | | text-align: center; |
| | | pointer-events: auto; |
| | | padding: 12px; |
| | | } |
| | | |
| | | .chart-empty .el-icon { |
| | | color: #2563eb; |
| | | font-size: 28px; |
| | | } |
| | | |
| | | .chart-empty-title { |
| | | font-size: 16px; |
| | | font-weight: 700; |
| | | color: #334155; |
| | | } |
| | | |
| | | .chart-empty-desc { |
| | | font-size: 13px; |
| | | color: #64748b; |
| | | } |
| | | |
| | | .chart-empty-actions { |
| | | margin-top: 4px; |
| | | display: flex; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .process-aside { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .process-legend, |
| | | .process-card { |
| | | border: 1px solid rgba(148, 163, 184, 0.22); |
| | | border-radius: 12px; |
| | | background: rgba(255, 255, 255, 0.84); |
| | | padding: 10px 12px; |
| | | } |
| | | |
| | | .process-card { |
| | | min-height: 74px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .process-legend { |
| | | min-height: 74px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | align-items: flex-start; |
| | | padding: 8px 6px; |
| | | gap: 6px; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .process-legend__item { |
| | | .process-legend-item { |
| | | color: #475569; |
| | | font-size: 12px; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | font-size: 13px; |
| | | color: rgba(0, 0, 0, 0.55); |
| | | } |
| | | |
| | | .dot { |
| | | width: 10px; |
| | | height: 10px; |
| | | border-radius: 2px; |
| | | border-radius: 3px; |
| | | display: inline-block; |
| | | } |
| | | |
| | | .dot-blue { |
| | | background: #1E5BFF; |
| | | background: #2563eb; |
| | | } |
| | | |
| | | .dot-yellow { |
| | | background: #F7B500; |
| | | .dot-orange { |
| | | background: #f59e0b; |
| | | } |
| | | |
| | | .dot-teal { |
| | | background: #19C6C6; |
| | | .dot-cyan { |
| | | background: #14b8a6; |
| | | } |
| | | |
| | | .process-card { |
| | | background: rgba(245, 247, 250, 0.9); |
| | | border-radius: 10px; |
| | | padding: 16px 16px; |
| | | } |
| | | |
| | | .process-card--name { |
| | | background: rgba(235, 242, 255, 1); |
| | | color: #1E5BFF; |
| | | font-weight: 800; |
| | | .process-name { |
| | | color: #2563eb; |
| | | font-weight: 700; |
| | | font-size: 14px; |
| | | line-height: 1.2; |
| | | margin-bottom: 2px; |
| | | } |
| | | |
| | | .process-card__label { |
| | | font-size: 13px; |
| | | color: rgba(0, 0, 0, 0.55); |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .process-card__value { |
| | | font-size: 24px; |
| | | font-weight: 800; |
| | | color: rgba(0, 0, 0, 0.8); |
| | | } |
| | | |
| | | .process-card__value .unit { |
| | | .process-label { |
| | | font-size: 12px; |
| | | color: #64748b; |
| | | } |
| | | |
| | | .process-value { |
| | | margin-top: 4px; |
| | | font-size: 24px; |
| | | color: #0f172a; |
| | | font-weight: 700; |
| | | } |
| | | |
| | | .chart-row { |
| | | display: grid; |
| | | grid-template-columns: repeat(2, minmax(0, 1fr)); |
| | | gap: 16px; |
| | | } |
| | | |
| | | .contract-summary { |
| | | display: grid; |
| | | grid-template-columns: 1fr 190px; |
| | | gap: 12px; |
| | | align-items: center; |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .contract-card { |
| | | border-radius: 14px; |
| | | border: 1px solid rgba(148, 163, 184, 0.2); |
| | | background: #f8fbff; |
| | | padding: 12px; |
| | | } |
| | | |
| | | .contract-name { |
| | | color: #64748b; |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .contract-main { |
| | | margin-top: 8px; |
| | | font-size: 34px; |
| | | font-weight: 700; |
| | | color: #0f172a; |
| | | } |
| | | |
| | | .contract-compare { |
| | | margin-top: 8px; |
| | | font-size: 13px; |
| | | color: #64748b; |
| | | display: flex; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .rise { |
| | | color: #0ea5a4; |
| | | font-weight: 600; |
| | | color: rgba(0, 0, 0, 0.45); |
| | | } |
| | | |
| | | .contract-list { |
| | | margin: 8px 0 0; |
| | | padding: 0; |
| | | list-style: none; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .contract-list li { |
| | | display: grid; |
| | | grid-template-columns: 12px minmax(0, 1fr) 56px auto; |
| | | align-items: center; |
| | | gap: 8px; |
| | | color: #475569; |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .legend-dot { |
| | | width: 8px; |
| | | height: 8px; |
| | | border-radius: 50%; |
| | | } |
| | | |
| | | .contract-item-name { |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .contract-item-rate { |
| | | text-align: right; |
| | | color: #64748b; |
| | | } |
| | | |
| | | .contract-item-value { |
| | | color: #1f3658; |
| | | text-align: right; |
| | | } |
| | | |
| | | .quality-cards { |
| | | margin: 8px 0 10px; |
| | | display: grid; |
| | | grid-template-columns: repeat(3, minmax(0, 1fr)); |
| | | gap: 10px; |
| | | } |
| | | |
| | | .quality-card { |
| | | border-radius: 12px; |
| | | border: 1px solid rgba(148, 163, 184, 0.2); |
| | | padding: 10px 12px; |
| | | color: #475569; |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .quality-card.one { |
| | | background: linear-gradient(135deg, #ffffff, #edf4ff); |
| | | } |
| | | |
| | | .quality-card.two { |
| | | background: linear-gradient(135deg, #ffffff, #ebfffc); |
| | | } |
| | | |
| | | .quality-card.three { |
| | | background: linear-gradient(135deg, #ffffff, #fff3e6); |
| | | } |
| | | |
| | | .quality-card span { |
| | | color: #0f172a; |
| | | font-weight: 700; |
| | | margin-left: 6px; |
| | | } |
| | | |
| | | @media (max-width: 1200px) { |
| | | .process-panel__body { |
| | | flex-direction: column; |
| | | } |
| | | .realtime-grid { |
| | | margin-top: 10px; |
| | | display: grid; |
| | | grid-template-columns: repeat(3, minmax(0, 1fr)); |
| | | gap: 10px; |
| | | } |
| | | |
| | | .process-panel__aside { |
| | | width: 100%; |
| | | flex-direction: row; |
| | | flex-wrap: wrap; |
| | | } |
| | | .realtime-item { |
| | | border: 1px solid rgba(148, 163, 184, 0.2); |
| | | border-radius: 12px; |
| | | background: #f8fbff; |
| | | padding: 10px 8px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .process-card { |
| | | flex: 1; |
| | | min-width: 220px; |
| | | } |
| | | .realtime-value { |
| | | font-size: 26px; |
| | | color: #0f172a; |
| | | font-weight: 700; |
| | | } |
| | | |
| | | .realtime-label { |
| | | margin-top: 8px; |
| | | font-size: 12px; |
| | | color: #475569; |
| | | } |
| | | |
| | | .realtime-delta { |
| | | margin-top: 4px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .realtime-delta.up { |
| | | color: #0ea5a4; |
| | | } |
| | | |
| | | .realtime-delta.down { |
| | | color: #f59e0b; |
| | | } |
| | | |
| | | .realtime-delta.flat { |
| | | color: #64748b; |
| | | } |
| | | |
| | | .warning-list { |
| | | margin-top: 10px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 8px; |
| | | max-height: 300px; |
| | | overflow-y: auto; |
| | | } |
| | | |
| | | .warning-item { |
| | | display: grid; |
| | | grid-template-columns: 10px minmax(0, 1fr) 72px; |
| | | align-items: center; |
| | | gap: 10px; |
| | | border: 1px solid rgba(148, 163, 184, 0.2); |
| | | border-radius: 12px; |
| | | background: #f8fbff; |
| | | padding: 10px; |
| | | } |
| | | |
| | | .warning-dot { |
| | | width: 8px; |
| | | height: 8px; |
| | | border-radius: 50%; |
| | | display: block; |
| | | } |
| | | |
| | | .warning-dot.device { |
| | | background: #ef4444; |
| | | } |
| | | |
| | | .warning-dot.quality { |
| | | background: #f59e0b; |
| | | } |
| | | |
| | | .warning-dot.material { |
| | | background: #3b82f6; |
| | | } |
| | | |
| | | .warning-title { |
| | | color: #334155; |
| | | font-size: 13px; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .warning-desc { |
| | | color: #64748b; |
| | | font-size: 12px; |
| | | margin-top: 4px; |
| | | } |
| | | |
| | | .warning-time { |
| | | color: #64748b; |
| | | font-size: 12px; |
| | | text-align: right; |
| | | } |
| | | |
| | | .order-panel { |
| | | min-height: 0; |
| | | } |
| | | |
| | | .quick-panel { |
| | | min-height: 0; |
| | | } |
| | | |
| | | .table-progress { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .table-progress span { |
| | | font-size: 12px; |
| | | color: #475569; |
| | | } |
| | | |
| | | .quick-grid { |
| | | margin-top: 10px; |
| | | display: grid; |
| | | grid-template-columns: repeat(2, minmax(0, 1fr)); |
| | | grid-auto-rows: 58px; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .quick-item { |
| | | border: 1px solid rgba(148, 163, 184, 0.22); |
| | | background: rgba(255, 255, 255, 0.92); |
| | | border-radius: 12px; |
| | | color: #334155; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | padding: 0 10px; |
| | | font-size: 12px; |
| | | cursor: pointer; |
| | | transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease; |
| | | } |
| | | |
| | | .plan-panel { |
| | | min-height: 236px; |
| | | } |
| | | |
| | | .quality-panel { |
| | | min-height: 0; |
| | | } |
| | | |
| | | .receipt-panel { |
| | | min-height: 340px; |
| | | } |
| | | |
| | | .plan-list { |
| | | margin: 10px 0 0; |
| | | padding: 0; |
| | | list-style: none; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .plan-item { |
| | | border: 1px solid rgba(148, 163, 184, 0.18); |
| | | border-radius: 12px; |
| | | background: #f8fbff; |
| | | padding: 10px 12px; |
| | | } |
| | | |
| | | .plan-main { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | gap: 10px; |
| | | align-items: center; |
| | | } |
| | | |
| | | .plan-order { |
| | | font-size: 13px; |
| | | color: #1f3658; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .plan-name { |
| | | font-size: 13px; |
| | | color: #334155; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .plan-meta { |
| | | margin-top: 6px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | gap: 8px; |
| | | font-size: 12px; |
| | | color: #64748b; |
| | | } |
| | | |
| | | .quick-item:hover { |
| | | transform: translateY(-2px); |
| | | border-color: rgba(96, 165, 250, 0.45); |
| | | box-shadow: 0 14px 28px rgba(37, 99, 235, 0.1); |
| | | } |
| | | |
| | | .quick-icon { |
| | | width: 30px; |
| | | height: 30px; |
| | | border-radius: 8px; |
| | | background: linear-gradient(135deg, #2563eb, #38bdf8); |
| | | display: inline-flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 16px; |
| | | color: #fff; |
| | | } |
| | | |
| | | .quick-item:nth-child(2) .quick-icon, |
| | | .quick-item:nth-child(6) .quick-icon { |
| | | background: linear-gradient(135deg, #14b8a6, #5eead4); |
| | | } |
| | | |
| | | .quick-item:nth-child(3) .quick-icon, |
| | | .quick-item:nth-child(5) .quick-icon { |
| | | background: linear-gradient(135deg, #7c3aed, #a78bfa); |
| | | } |
| | | |
| | | .quick-item:nth-child(4) .quick-icon, |
| | | .quick-item:nth-child(7) .quick-icon { |
| | | background: linear-gradient(135deg, #f97316, #fdba74); |
| | | } |
| | | |
| | | .process-selection-wrapper { |
| | | max-height: 400px; |
| | | overflow-y: auto; |
| | | padding: 10px; |
| | | padding: 8px; |
| | | } |
| | | |
| | | .process-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); |
| | | gap: 12px; |
| | | gap: 10px; |
| | | } |
| | | |
| | | :deep(.el-checkbox.is-bordered) { |
| | | margin-left: 0 !important; |
| | | width: 100%; |
| | | } |
| | | </style> |
| | | |
| | | :deep(.el-radio-button__inner) { |
| | | border-radius: 10px !important; |
| | | background: #f8fbff; |
| | | border-color: rgba(148, 163, 184, 0.22) !important; |
| | | color: #475569 !important; |
| | | } |
| | | |
| | | :deep(.el-radio-button__original-radio:checked + .el-radio-button__inner) { |
| | | background: linear-gradient(135deg, #2f80ff, #38bdf8) !important; |
| | | border-color: transparent !important; |
| | | color: #fff !important; |
| | | } |
| | | |
| | | :deep(.el-progress-circle__track) { |
| | | stroke: rgba(148, 163, 184, 0.3); |
| | | } |
| | | |
| | | :deep(.el-progress-bar__outer) { |
| | | background-color: rgba(148, 163, 184, 0.2); |
| | | } |
| | | |
| | | :deep(.order-panel .el-progress-bar__inner) { |
| | | background: linear-gradient(90deg, #2563eb, #38bdf8) !important; |
| | | } |
| | | |
| | | :deep(.order-panel .el-table) { |
| | | border-radius: 14px; |
| | | } |
| | | |
| | | :deep(.order-panel .el-table th.el-table__cell) { |
| | | background: #f2f7ff !important; |
| | | } |
| | | |
| | | :deep(.order-panel .el-table__body tr:hover > td.el-table__cell) { |
| | | background: #f8fbff !important; |
| | | } |
| | | |
| | | :deep(.order-panel .el-tag--success) { |
| | | color: #0f766e; |
| | | background: #e9fdf7; |
| | | border-color: #b7f2e0; |
| | | } |
| | | |
| | | :deep(.order-panel .el-tag--warning) { |
| | | color: #b45309; |
| | | background: #fff6e8; |
| | | border-color: #fde0b8; |
| | | } |
| | | |
| | | :deep(.order-panel .el-tag--primary) { |
| | | color: #2563eb; |
| | | background: #eaf2ff; |
| | | border-color: #b8d2ff; |
| | | } |
| | | |
| | | @media (max-width: 1600px) { |
| | | .main-grid { |
| | | grid-template-columns: minmax(0, 1fr) 380px; |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 1366px) { |
| | | .main-grid { |
| | | grid-template-columns: minmax(0, 1fr) 340px; |
| | | } |
| | | |
| | | .stats-grid { |
| | | grid-template-columns: repeat(2, minmax(0, 1fr)); |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 1200px) { |
| | | .main-grid { |
| | | grid-template-columns: 1fr; |
| | | } |
| | | |
| | | .right-column { |
| | | display: grid; |
| | | grid-template-columns: repeat(2, minmax(0, 1fr)); |
| | | gap: 14px; |
| | | } |
| | | |
| | | .chart-row { |
| | | grid-template-columns: 1fr; |
| | | } |
| | | |
| | | .process-body { |
| | | grid-template-columns: 1fr; |
| | | } |
| | | |
| | | .realtime-grid { |
| | | grid-template-columns: repeat(3, minmax(0, 1fr)); |
| | | } |
| | | |
| | | .quality-cards { |
| | | grid-template-columns: 1fr; |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 768px) { |
| | | .welcome-panel { |
| | | flex-direction: column; |
| | | align-items: flex-start; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .welcome-meta { |
| | | text-align: left; |
| | | } |
| | | |
| | | .meta-extra { |
| | | justify-content: flex-start; |
| | | } |
| | | |
| | | .stats-grid { |
| | | grid-template-columns: repeat(2, minmax(0, 1fr)); |
| | | } |
| | | |
| | | .right-column { |
| | | grid-template-columns: 1fr; |
| | | } |
| | | |
| | | .realtime-grid { |
| | | grid-template-columns: 1fr; |
| | | } |
| | | } |
| | | </style> |
| src/views/inventoryManagement/dispatchLog/Record.vue
src/views/inventoryManagement/receiptManagement/Record.vue
src/views/inventoryManagement/stockManagement/BatchNoQtyDetail.vue
src/views/inventoryManagement/stockManagement/Record.vue
src/views/inventoryManagement/stockReport/index.vue
src/views/lavorissue/ledger/filesDia.vue
src/views/login.vue
src/views/oaSystem/projectManagement/components/milestoneList.vue (已删除)
src/views/oaSystem/projectManagement/components/phaseGoalList.vue (已删除)
src/views/oaSystem/projectManagement/components/projectForm.vue (已删除)
src/views/oaSystem/projectManagement/components/taskTree.vue (已删除)
src/views/oaSystem/projectManagement/index.vue (已删除)
src/views/oaSystem/projectManagement/projectDetail.vue (已删除)
src/views/personnelManagement/contractManagement/filesDia.vue
src/views/personnelManagement/contractManagement/index.vue
src/views/personnelManagement/dimission/components/formDia.vue
src/views/personnelManagement/employeeRecord/index.vue
src/views/procurementManagement/procurementLedger/fileList.vue
src/views/procurementManagement/procurementLedger/index.vue
src/views/procurementManagement/purchaseReturnOrder/New.vue
src/views/procurementManagement/purchaseReturnOrder/ProductList.vue
src/views/procurementManagement/purchaseReturnOrder/index.vue
src/views/productionManagement/processRoute/index.vue
src/views/productionManagement/processRoute/processRouteItem/index.vue
src/views/productionManagement/productStructure/Detail/index.vue
src/views/productionManagement/productionCosting/index.vue
src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
src/views/productionManagement/productionOrder/index.vue
src/views/productionManagement/productionProcess/index.vue
src/views/productionManagement/productionReporting/index.vue
src/views/productionManagement/productionTraceability/index.vue
src/views/productionManagement/workOrder/components/filesDia.vue
src/views/productionManagement/workOrderEdit/index.vue
src/views/productionManagement/workOrderManagement/components/filesDia.vue
src/views/productionManagement/workOrderManagement/index.vue
src/views/productionPlan/productionPlan/index.vue
src/views/projectManagement/Management/components/formDia.vue
src/views/projectManagement/Management/projectDetail.vue
src/views/projectManagement/projectType/index.vue
src/views/qualityManagement/finalInspection/components/filesDia.vue
src/views/qualityManagement/finalInspection/components/formDia.vue
src/views/qualityManagement/finalInspection/index.vue
src/views/qualityManagement/nonconformingManagement/components/formDia.vue
src/views/qualityManagement/nonconformingManagement/index.vue
src/views/qualityManagement/processInspection/components/filesDia.vue
src/views/qualityManagement/processInspection/components/formDia.vue
src/views/qualityManagement/processInspection/index.vue
src/views/qualityManagement/rawMaterialInspection/components/filesDia.vue
src/views/qualityManagement/rawMaterialInspection/components/formDia.vue
src/views/qualityManagement/rawMaterialInspection/index.vue
src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue
src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue
src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue
src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue
src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue
src/views/reportAnalysis/PSIDataAnalysis/index.vue
src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue
src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue
src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue
src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue
src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue
src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue
src/views/reportAnalysis/dataDashboard/index.vue
src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue
src/views/reportAnalysis/productionAnalysis/components/center-center.vue
src/views/reportAnalysis/productionAnalysis/components/center-top.vue
src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue
src/views/reportAnalysis/productionAnalysis/components/left-top.vue
src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue
src/views/reportAnalysis/productionAnalysis/components/right-top.vue
src/views/reportAnalysis/productionAnalysis/index.vue
src/views/safeProduction/safeWorkApproval/components/infoFormDia.vue
src/views/safeProduction/safeWorkApproval/fileList.vue
src/views/salesManagement/deliveryLedger/index.vue
src/views/salesManagement/invoiceLedger/index.vue
src/views/salesManagement/returnOrder/components/detailDia.vue
src/views/salesManagement/returnOrder/components/formDia.vue
src/views/salesManagement/returnOrder/index.vue
src/views/salesManagement/salesLedger/fileList.vue
src/views/salesManagement/salesLedger/index.vue
src/views/salesManagement/salesQuotation/index.vue
src/views/systemArchitecture/index.vue |