| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '@vben/request'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace CrmCancellationApi { |
| | | export interface Cancellation { |
| | | id?: number; |
| | | cancellationNo?: string; |
| | | customerId?: number; |
| | | customerName?: string; |
| | | contractId?: number; |
| | | contractNo?: string; |
| | | cancellationType?: string; |
| | | cancelReason?: string; |
| | | expectedCancelDate?: string; |
| | | actualCancelDate?: string; |
| | | refundAmount?: number; |
| | | applyUserId?: number; |
| | | applyUserName?: string; |
| | | applyTime?: string; |
| | | auditStatus?: number; |
| | | processInstanceId?: string; |
| | | remark?: string; |
| | | createTime?: string; |
| | | } |
| | | export interface PageParams extends PageParam { |
| | | cancellationNo?: string; |
| | | customerId?: number; |
| | | cancellationType?: string; |
| | | auditStatus?: number; |
| | | } |
| | | } |
| | | |
| | | /** æ¥è¯¢éæ·ç³è¯·å页 */ |
| | | export function getCancellationPage( |
| | | params: CrmCancellationApi.PageParams, |
| | | ) { |
| | | return requestClient.get<PageResult<CrmCancellationApi.Cancellation>>( |
| | | '/crm/cancellation/page', |
| | | { params }, |
| | | ); |
| | | } |
| | | |
| | | /** æ¥è¯¢éæ·ç³è¯·è¯¦æ
*/ |
| | | export function getCancellation(id: number) { |
| | | return requestClient.get<CrmCancellationApi.Cancellation>( |
| | | `/crm/cancellation/get?id=${id}`, |
| | | ); |
| | | } |
| | | |
| | | /** æ°å¢éæ·ç³è¯· */ |
| | | export function createCancellation(data: CrmCancellationApi.Cancellation) { |
| | | return requestClient.post('/crm/cancellation/create', data); |
| | | } |
| | | |
| | | /** ä¿®æ¹éæ·ç³è¯· */ |
| | | export function updateCancellation(data: CrmCancellationApi.Cancellation) { |
| | | return requestClient.put('/crm/cancellation/update', data); |
| | | } |
| | | |
| | | /** 审æ¹éæ·ç³è¯· */ |
| | | export function auditCancellation(data: { |
| | | id: number; |
| | | auditStatus: number; |
| | | }) { |
| | | return requestClient.put('/crm/cancellation/audit', data); |
| | | } |
| | | |
| | | /** å é¤éæ·ç³è¯· */ |
| | | export function deleteCancellation(id: number) { |
| | | return requestClient.delete(`/crm/cancellation/delete?id=${id}`); |
| | | } |
| | | |
| | | /** 导åºéæ·ç³è¯· */ |
| | | export function exportCancellation(params: Record<string, unknown>) { |
| | | return requestClient.download('/crm/cancellation/export-excel', { params }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '@vben/request'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace CrmContractCommandApi { |
| | | export interface ContractCommand { |
| | | id?: number; |
| | | contractId?: number; |
| | | contractNo?: string; |
| | | commandType?: string; |
| | | targetModule?: string; |
| | | targetId?: number; |
| | | bizNo?: string; |
| | | operatorId?: number; |
| | | operatorName?: string; |
| | | operateTime?: string; |
| | | status?: number; |
| | | remark?: string; |
| | | createTime?: string; |
| | | } |
| | | export interface PageParams extends PageParam { |
| | | contractId?: number; |
| | | commandType?: string; |
| | | status?: number; |
| | | bizNo?: string; |
| | | } |
| | | } |
| | | |
| | | /** æ¥è¯¢ååæä»¤å页 */ |
| | | export function getContractCommandPage( |
| | | params: CrmContractCommandApi.PageParams, |
| | | ) { |
| | | return requestClient.get<PageResult<CrmContractCommandApi.ContractCommand>>( |
| | | '/crm/contract-command/page', |
| | | { params }, |
| | | ); |
| | | } |
| | | |
| | | /** æ°å¢ååæä»¤ */ |
| | | export function createContractCommand( |
| | | data: CrmContractCommandApi.ContractCommand, |
| | | ) { |
| | | return requestClient.post('/crm/contract-command/create', data); |
| | | } |
| | | |
| | | /** æ´æ°ååæä»¤ */ |
| | | export function updateContractCommand( |
| | | data: CrmContractCommandApi.ContractCommand, |
| | | ) { |
| | | return requestClient.put('/crm/contract-command/update', data); |
| | | } |
| | | |
| | | /** æ§è¡ååæä»¤ */ |
| | | export function executeContractCommand(id: number) { |
| | | return requestClient.put(`/crm/contract-command/execute?id=${id}`); |
| | | } |
| | | |
| | | /** åæ¶ååæä»¤ */ |
| | | export function cancelContractCommand(id: number) { |
| | | return requestClient.put(`/crm/contract-command/cancel?id=${id}`); |
| | | } |
| | | |
| | | /** å é¤ååæä»¤ */ |
| | | export function deleteContractCommand(id: number) { |
| | | return requestClient.delete(`/crm/contract-command/delete?id=${id}`); |
| | | } |
| | |
| | | contactName?: string; |
| | | orderId?: number; // å
³è ERP éå®è®¢åç¼å· |
| | | orderNo?: string; // ERP éå®è®¢ååå· |
| | | contractType?: string; // ååç±»åï¼ä¾ç¨çµ/è½æºæå¡çï¼ |
| | | voltageLevel?: string; // çµåç级 |
| | | electricityType?: string; // ç¨çµç±»å |
| | | contractCapacity?: number; // åå容éï¼kVAï¼ |
| | | tariffMode?: string; // çµä»·æ¨¡å¼ |
| | | meterMode?: string; // è®¡éæ¹å¼ |
| | | payCycle?: number; // ç¼´è´¹å¨æï¼æï¼ |
| | | commandCount?: number; // æä»¤æ°é |
| | | } |
| | | |
| | | /** åå产åä¿¡æ¯ */ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '@vben/request'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace CrmCreditRatingApi { |
| | | export interface CreditRating { |
| | | id?: number; |
| | | customerId?: number; |
| | | customerName?: string; |
| | | level?: string; |
| | | score?: number; |
| | | evalType?: string; |
| | | evalReason?: string; |
| | | operatorId?: number; |
| | | operatorName?: string; |
| | | operateTime?: string; |
| | | validUntil?: string; |
| | | remark?: string; |
| | | createTime?: string; |
| | | } |
| | | export interface PageParams extends PageParam { |
| | | customerId?: number; |
| | | level?: string; |
| | | evalType?: string; |
| | | } |
| | | } |
| | | |
| | | /** æ¥è¯¢ä¿¡ç¨è¯çº§å页 */ |
| | | export function getCreditRatingPage( |
| | | params: CrmCreditRatingApi.PageParams, |
| | | ) { |
| | | return requestClient.get<PageResult<CrmCreditRatingApi.CreditRating>>( |
| | | '/crm/credit-rating/page', |
| | | { params }, |
| | | ); |
| | | } |
| | | |
| | | /** æ¥è¯¢ä¿¡ç¨è¯çº§è¯¦æ
*/ |
| | | export function getCreditRating(id: number) { |
| | | return requestClient.get<CrmCreditRatingApi.CreditRating>( |
| | | `/crm/credit-rating/get?id=${id}`, |
| | | ); |
| | | } |
| | | |
| | | /** æ°å¢ä¿¡ç¨è¯çº§ */ |
| | | export function createCreditRating(data: CrmCreditRatingApi.CreditRating) { |
| | | return requestClient.post('/crm/credit-rating/create', data); |
| | | } |
| | | |
| | | /** ä¿®æ¹ä¿¡ç¨è¯çº§ */ |
| | | export function updateCreditRating(data: CrmCreditRatingApi.CreditRating) { |
| | | return requestClient.put('/crm/credit-rating/update', data); |
| | | } |
| | | |
| | | /** å é¤ä¿¡ç¨è¯çº§ */ |
| | | export function deleteCreditRating(id: number) { |
| | | return requestClient.delete(`/crm/credit-rating/delete?id=${id}`); |
| | | } |
| | | |
| | | /** 导åºä¿¡ç¨è¯çº§ */ |
| | | export function exportCreditRating(params: Record<string, unknown>) { |
| | | return requestClient.download('/crm/credit-rating/export-excel', { params }); |
| | | } |
| | |
| | | createTime: Date; // å建æ¶é´ |
| | | updateTime: Date; // æ´æ°æ¶é´ |
| | | poolDay?: number; // è·ç¦»è¿å
¥å
¬æµ·å¤©æ° |
| | | customerType?: string; // 客æ·åç±»ï¼æ¿ä¼/å·¥ä¸/å±
æ°çï¼ |
| | | creditLevel?: string; // å½åä¿¡ç¨ç级 |
| | | creditScore?: number; // å½åä¿¡ç¨å |
| | | overdueAmount?: number; // æ¬ è´¹éé¢ï¼æªå款+é¾æï¼ |
| | | overdueCount?: number; // æ¬ è´¹ç¬æ° |
| | | } |
| | | |
| | | /** 客æ·å¯¼å
¥è¯·æ± */ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '@vben/request'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace CrmRefundApi { |
| | | export interface Refund { |
| | | id?: number; |
| | | refundNo?: string; |
| | | customerId?: number; |
| | | customerName?: string; |
| | | contractId?: number; |
| | | contractNo?: string; |
| | | refundType?: string; |
| | | refundAmount?: number; |
| | | refundReason?: string; |
| | | applyUserId?: number; |
| | | applyUserName?: string; |
| | | applyTime?: string; |
| | | auditStatus?: number; |
| | | processInstanceId?: string; |
| | | remark?: string; |
| | | createTime?: string; |
| | | } |
| | | export interface PageParams extends PageParam { |
| | | refundNo?: string; |
| | | customerId?: number; |
| | | refundType?: string; |
| | | auditStatus?: number; |
| | | } |
| | | } |
| | | |
| | | /** æ¥è¯¢éè´¹åå页 */ |
| | | export function getRefundPage(params: CrmRefundApi.PageParams) { |
| | | return requestClient.get<PageResult<CrmRefundApi.Refund>>( |
| | | '/crm/refund/page', |
| | | { params }, |
| | | ); |
| | | } |
| | | |
| | | /** æ¥è¯¢éè´¹å详æ
*/ |
| | | export function getRefund(id: number) { |
| | | return requestClient.get<CrmRefundApi.Refund>(`/crm/refund/get?id=${id}`); |
| | | } |
| | | |
| | | /** æ°å¢éè´¹å */ |
| | | export function createRefund(data: CrmRefundApi.Refund) { |
| | | return requestClient.post('/crm/refund/create', data); |
| | | } |
| | | |
| | | /** ä¿®æ¹éè´¹å */ |
| | | export function updateRefund(data: CrmRefundApi.Refund) { |
| | | return requestClient.put('/crm/refund/update', data); |
| | | } |
| | | |
| | | /** 审æ¹éè´¹å */ |
| | | export function auditRefund(data: { id: number; auditStatus: number }) { |
| | | return requestClient.put('/crm/refund/audit', data); |
| | | } |
| | | |
| | | /** å é¤éè´¹å */ |
| | | export function deleteRefund(id: number) { |
| | | return requestClient.delete(`/crm/refund/delete?id=${id}`); |
| | | } |
| | | |
| | | /** 导åºéè´¹å */ |
| | | export function exportRefund(params: Record<string, unknown>) { |
| | | return requestClient.download('/crm/refund/export-excel', { params }); |
| | | } |
| | |
| | | createTime?: Date; |
| | | updateTime?: Date; |
| | | items?: SaleQuotationItem[]; |
| | | quotationType?: string; // æ¥ä»·ç±»åï¼general/power/energyï¼ |
| | | capacity?: number; // åå容éï¼kVAï¼ |
| | | maxDemand?: number; // æå¤§ééï¼kWï¼ |
| | | unitPrice?: number; // çµåº¦åä»·ï¼å
/kWhï¼ |
| | | tariffMode?: string; // çµä»·æ¨¡å¼ |
| | | powerFactorFee?: number; // åè°çµè´¹ï¼å
ï¼ |
| | | billingCycle?: number; // ç»ç®å¨æï¼æï¼ |
| | | } |
| | | |
| | | /** æ¥ä»·åç©ææç» */ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '@vben/request'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace ErpPurchasePlanApi { |
| | | /** éè´è®¡åä¿¡æ¯ */ |
| | | export interface PurchasePlan { |
| | | id?: number; // ç¼å· |
| | | no?: string; // 计ååå· |
| | | name?: string; // 计ååç§° |
| | | status?: number; // ç¶æï¼0æªæäº¤ 10审æ¹ä¸ 20å®¡æ ¸éè¿ 30å®¡æ ¸ä¸éè¿ 40已忶 |
| | | processInstanceId?: string; // 工使µç¼å· |
| | | demandSource?: number; // éæ±æ¥æºï¼1åºåé¢è¦ 2è¿ç»´/ç产计å |
| | | demandSourceName?: string; // éæ±æ¥æºåç§° |
| | | planDate?: string; // è®¡åæ¥æ |
| | | planUserId?: number; // ç¼å¶äººç¼å· |
| | | planUserName?: string; // ç¼å¶äººå§å |
| | | planDeptId?: number; // ç¼å¶é¨é¨ç¼å· |
| | | planDeptName?: string; // ç¼å¶é¨é¨åç§° |
| | | supplierId?: number; // ä¾åºåç¼å· |
| | | supplierName?: string; // ä¾åºååç§° |
| | | totalCount?: number; // å计æ°é |
| | | generatedFlag?: boolean; // æ¯å¦å·²çæéè´ç³è¯· |
| | | remark?: string; // 夿³¨ |
| | | productNames?: string; // 产ååç§°å表 |
| | | items?: PurchasePlanItem[]; // 计åæç» |
| | | createTime?: string; // å建æ¶é´ |
| | | } |
| | | |
| | | /** éè´è®¡åæç» */ |
| | | export interface PurchasePlanItem { |
| | | id?: number; // ç¼å· |
| | | productId: number; // 产åç¼å· |
| | | productName?: string; // 产ååç§° |
| | | productUnitId?: number; // 产ååä½ç¼å· |
| | | productUnitName?: string; // 产ååä½åç§° |
| | | count: number; // 计åéè´æ°é |
| | | demandTime?: string; // éæ±æ¥æ |
| | | remark?: string; // 夿³¨ |
| | | } |
| | | } |
| | | |
| | | /** å建éè´è®¡å */ |
| | | export function createPurchasePlan(data: ErpPurchasePlanApi.PurchasePlan) { |
| | | return requestClient.post('/erp/purchase-plan/create', data); |
| | | } |
| | | |
| | | /** æ´æ°éè´è®¡å */ |
| | | export function updatePurchasePlan(data: ErpPurchasePlanApi.PurchasePlan) { |
| | | return requestClient.put('/erp/purchase-plan/update', data); |
| | | } |
| | | |
| | | /** æäº¤éè´è®¡åå®¡æ¹ */ |
| | | export function submitPurchasePlan(id: number, processDefinitionKey: string) { |
| | | return requestClient.put('/erp/purchase-plan/submit', null, { |
| | | params: { id, processDefinitionKey }, |
| | | }); |
| | | } |
| | | |
| | | /** æ ¹æ®åºåé¢è¦çæéè´è®¡å */ |
| | | export function generatePlanFromStockAlert(params: { name?: string; supplierId?: number }) { |
| | | return requestClient.post<number>('/erp/purchase-plan/generate-from-stock-alert', null, { |
| | | params, |
| | | }); |
| | | } |
| | | |
| | | /** çæéè´ç³è¯· */ |
| | | export function generatePurchaseRequests(id: number) { |
| | | return requestClient.post<number[]>('/erp/purchase-plan/generate-requests', null, { |
| | | params: { id }, |
| | | }); |
| | | } |
| | | |
| | | /** å é¤éè´è®¡å */ |
| | | export function deletePurchasePlan(ids: number[]) { |
| | | return requestClient.delete('/erp/purchase-plan/delete', { params: { ids: ids.join(',') } }); |
| | | } |
| | | |
| | | /** è·åéè´è®¡å详æ
*/ |
| | | export function getPurchasePlan(id: number) { |
| | | return requestClient.get<ErpPurchasePlanApi.PurchasePlan>( |
| | | `/erp/purchase-plan/get?id=${id}`, |
| | | ); |
| | | } |
| | | |
| | | /** è·åéè´è®¡åå页 */ |
| | | export function getPurchasePlanPage(params: PageParam) { |
| | | return requestClient.get<PageResult<ErpPurchasePlanApi.PurchasePlan>>( |
| | | '/erp/purchase-plan/page', |
| | | { params }, |
| | | ); |
| | | } |
| | | |
| | | /** 导åºéè´è®¡å Excel */ |
| | | export function exportPurchasePlan(params: any) { |
| | | return requestClient.download('/erp/purchase-plan/export-excel', { params }); |
| | | } |
| | | |
| | | /** è·åå®¡æ¹æµç¨å表 */ |
| | | export function getApproveProcessList(id: number) { |
| | | return requestClient.get(`/erp/purchase-plan/approve-process-list`, { params: { id } }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '@vben/request'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace HrmCertificateApi { |
| | | /** è¯ä¹¦èµè´¨ */ |
| | | export interface Certificate { |
| | | id?: number; |
| | | employeeId?: number; // åå·¥ç¼å· |
| | | employeeName?: string; // åå·¥å§å |
| | | certType?: number; // è¯ä¹¦ç±»åï¼1ç¹ç§ä½ä¸ 2ä»ä¸èµè´¨ 3æè½ç级 4å®å
¨å¹è® |
| | | certTypeName?: string; // è¯ä¹¦ç±»ååç§° |
| | | certName?: string; // è¯ä¹¦åç§° |
| | | certNo?: string; // è¯ä¹¦ç¼å· |
| | | issueOrg?: string; // åè¯æºæ |
| | | issueDate?: string; // åè¯æ¥æ |
| | | expireDate?: string; // æææè³ |
| | | expireStatus?: number; // å°æç¶æï¼0ææ 1å³å°å°æ 2å·²è¿æ |
| | | remark?: string; // 夿³¨ |
| | | createTime?: string; |
| | | } |
| | | } |
| | | |
| | | /** å建è¯ä¹¦èµè´¨ */ |
| | | export function createCertificate(data: HrmCertificateApi.Certificate) { |
| | | return requestClient.post('/hrm/certificate/create', data); |
| | | } |
| | | |
| | | /** æ´æ°è¯ä¹¦èµè´¨ */ |
| | | export function updateCertificate(data: HrmCertificateApi.Certificate) { |
| | | return requestClient.put('/hrm/certificate/update', data); |
| | | } |
| | | |
| | | /** å é¤è¯ä¹¦èµè´¨ */ |
| | | export function deleteCertificate(ids: number[]) { |
| | | return requestClient.delete('/hrm/certificate/delete', { params: { ids: ids.join(',') } }); |
| | | } |
| | | |
| | | /** è·åè¯ä¹¦èµè´¨è¯¦æ
*/ |
| | | export function getCertificate(id: number) { |
| | | return requestClient.get<HrmCertificateApi.Certificate>( |
| | | `/hrm/certificate/get?id=${id}`, |
| | | ); |
| | | } |
| | | |
| | | /** è·åè¯ä¹¦èµè´¨å页 */ |
| | | export function getCertificatePage(params: PageParam) { |
| | | return requestClient.get<PageResult<HrmCertificateApi.Certificate>>( |
| | | '/hrm/certificate/page', |
| | | { params }, |
| | | ); |
| | | } |
| | |
| | | export interface Machinery { |
| | | id?: number; // 设å¤ç¼å· |
| | | code?: string; // 设å¤ç¼ç |
| | | tbDeviceId?: string; // æ°é设å¤IDï¼å¤é¨æ°é tbDeviceIdï¼ |
| | | name?: string; // 设å¤åç§° |
| | | brand?: string; // åç |
| | | specification?: string; // è§æ ¼åå· |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace MesDvStatisticsApi { |
| | | /** 设å¤ç»è®¡æ±æ» */ |
| | | export interface StatisticsSummary { |
| | | totalMachinery?: number; // è®¾å¤æ»æ° |
| | | producingCount?: number; // çäº§ä¸ |
| | | stoppedCount?: number; // åæº |
| | | maintainingCount?: number; // ç»´æ¤ä¸ |
| | | faultRate?: number; // æ
éç% |
| | | totalRepair?: number; // ç»´ä¿®åæ»æ° |
| | | processingRepair?: number; // ç»´ä¿®ä¸/å¾
éªæ¶ |
| | | finishedRepair?: number; // 已确认维修 |
| | | totalMainten?: number; // ä¿å
»è®°å½æ»æ° |
| | | finishedMainten?: number; // 已宿ä¿å
» |
| | | typeDistribution?: TypeItem[]; // æè®¾å¤ç±»ååå¸ |
| | | } |
| | | |
| | | /** 设å¤ç±»ååå¸é¡¹ */ |
| | | export interface TypeItem { |
| | | machineryTypeId?: number; |
| | | machineryTypeName?: string; |
| | | count?: number; |
| | | } |
| | | } |
| | | |
| | | /** 设å¤ç»è®¡æ±æ» */ |
| | | export function getDvStatisticsSummary() { |
| | | return requestClient.get<MesDvStatisticsApi.StatisticsSummary>( |
| | | '/mes/dv/statistics/summary', |
| | | ); |
| | | } |
| | |
| | | safeStockFlag?: boolean; // æ¯å¦å¯ç¨å®å
¨åºå |
| | | minStock?: number; // æä½åºåé |
| | | maxStock?: number; // æé«åºåé |
| | | materialCategory?: number; // çµåç©èµåç±» |
| | | highValue?: boolean; // æ¯å¦é«å¼ç©æ |
| | | batchFlag?: boolean; // æ¯å¦å¯ç¨æ¹æ¬¡ç®¡ç |
| | | remark?: string; // 夿³¨ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '@vben/request'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace MesPdCtcReelApi { |
| | | /** æ¢ä½å¯¼çº¿çå
·è®¡ç® */ |
| | | export interface CtcReel { |
| | | id?: number; // ç¼å· |
| | | ctcId?: number; // æ¢ä½å¯¼çº¿äº§åID |
| | | ctcOrderSpec?: string; // æ¢ä½å¯¼çº¿è®¢è´§è§æ ¼ |
| | | reelType?: string; // çå
፱Ȍ |
| | | reelOuterDiameter?: number; // çå
·å¤å¾ mm |
| | | reelInnerDiameter?: number; // çè¯å
å¾ mm |
| | | reelWidth?: number; // ç宽 mm |
| | | maxCapacity?: number; // æå¤§å®¹é km |
| | | recommendedLength?: number; // æ¨èæ¯çé¿åº¦ km |
| | | netWeight?: number; // åé kg |
| | | grossWeight?: number; // æ¯é kg |
| | | calcFormula?: string; // 计ç®å
¬å¼ |
| | | remark?: string; // 夿³¨ |
| | | createTime?: Date; // å建æ¶é´ |
| | | } |
| | | } |
| | | |
| | | /** æ¥è¯¢çå
·è®¡ç®å页 */ |
| | | export function getCtcReelPage(params: PageParam) { |
| | | return requestClient.get<PageResult<MesPdCtcReelApi.CtcReel>>( |
| | | '/mes/pd/ctc-reel/page', |
| | | { params }, |
| | | ); |
| | | } |
| | | |
| | | /** æ¥è¯¢çå
·è®¡ç®è¯¦æ
*/ |
| | | export function getCtcReel(id: number) { |
| | | return requestClient.get<MesPdCtcReelApi.CtcReel>( |
| | | `/mes/pd/ctc-reel/get?id=${id}`, |
| | | ); |
| | | } |
| | | |
| | | /** æ¥è¯¢æå®æ¢ä½å¯¼çº¿äº§åççå
·å表 */ |
| | | export function getCtcReelListByCtcId(ctcId: number) { |
| | | return requestClient.get<MesPdCtcReelApi.CtcReel[]>( |
| | | `/mes/pd/ctc-reel/list-by-ctc?ctcId=${ctcId}`, |
| | | ); |
| | | } |
| | | |
| | | /** æ°å¢çå
·è®¡ç®è®°å½ */ |
| | | export function createCtcReel(data: MesPdCtcReelApi.CtcReel) { |
| | | return requestClient.post('/mes/pd/ctc-reel/create', data); |
| | | } |
| | | |
| | | /** ä¿®æ¹çå
·è®¡ç®è®°å½ */ |
| | | export function updateCtcReel(data: MesPdCtcReelApi.CtcReel) { |
| | | return requestClient.put('/mes/pd/ctc-reel/update', data); |
| | | } |
| | | |
| | | /** å é¤çå
·è®¡ç®è®°å½ */ |
| | | export function deleteCtcReel(id: number) { |
| | | return requestClient.delete(`/mes/pd/ctc-reel/delete?id=${id}`); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '@vben/request'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace MesPdCtcApi { |
| | | /** æ¢ä½å¯¼çº¿äº§åææ¯åæ° */ |
| | | export interface Ctc { |
| | | id?: number; // ç¼å· |
| | | itemId?: number; // ç©æID |
| | | itemName?: string; // ç©æåç§° |
| | | itemCode?: string; // ç©æç¼ç |
| | | orderSpec?: string; // è®¢è´§è§æ ¼ |
| | | bareConductorSpec?: string; // è£¸å¯¼çº¿è§æ ¼ |
| | | enameledSpec?: string; // æ¼å
çº¿è§æ ¼ |
| | | transpositionSpec?: string; // æ¢ä½è§æ ¼ |
| | | conductorType?: string; // 导ä½ç±»å |
| | | crossSection?: number; // æªé¢ç§¯ mm² |
| | | outerDiameter?: number; // å¤å¾ mm |
| | | resistance20c?: number; // 20âç´æµçµé» Ω/km |
| | | wrappingAngle?: number; // ç»å
è§åº¦ ° |
| | | insulationThickness?: number; // ç»ç¼å度 mm |
| | | ratedVoltage?: string; // é¢å®çµå kV |
| | | testVoltage?: string; // è¯éªçµå kV |
| | | minBendingRadius?: number; // æå°å¼¯æ²åå¾ mm |
| | | weightPerKm?: number; // æ¯å
¬ééé kg/km |
| | | standardCode?: string; // æ§è¡æ åä»£å· |
| | | remark?: string; // 夿³¨ |
| | | createTime?: Date; // å建æ¶é´ |
| | | } |
| | | |
| | | /** ç»å
è§åº¦è®¡ç® */ |
| | | export interface AngleCalcReq { |
| | | conductorThickness?: number; // 导ä½å度 mm |
| | | conductorWidth?: number; // 导ä½å®½åº¦ mm |
| | | cornerRadius?: number; // åè§åå¾ mm |
| | | insulationThickness?: number; // ç»ç¼å度 mm |
| | | tapeWidth?: number; // 纸带宽度 mm |
| | | overlapWidth?: number; // éå 宽度 mm |
| | | } |
| | | |
| | | /** ç»å
è§åº¦è®¡ç®ç»æ */ |
| | | export interface AngleCalcResp { |
| | | circumference?: number; // 导线å¨é¿ mm |
| | | wrappingAngle?: number; // ç»å
è§åº¦ ° |
| | | wrappingPitch?: number; // ç»å
èè· mm |
| | | } |
| | | |
| | | /** ç´æµçµé»è®¡ç® */ |
| | | export interface ResistanceCalcReq { |
| | | conductorThickness?: number; // 导ä½å度 mm |
| | | conductorWidth?: number; // 导ä½å®½åº¦ mm |
| | | temperature?: number; // è®¡ç®æ¸©åº¦ â |
| | | material?: string; // å¯¼ä½æè´¨ |
| | | } |
| | | |
| | | /** ç´æµçµé»è®¡ç®ç»æ */ |
| | | export interface ResistanceCalcResp { |
| | | crossSection?: number; // æªé¢ç§¯ mm² |
| | | resistance20cKm?: number; // 20âç´æµçµé» Ω/km |
| | | resistanceAtTemp?: number; // æå®æ¸©åº¦ç´æµçµé» Ω/m |
| | | resistanceAtTempKm?: number; // æå®æ¸©åº¦ç´æµçµé» Ω/km |
| | | } |
| | | |
| | | /** çå
·å®¹éè®¡ç® */ |
| | | export interface ReelCalcReq { |
| | | reelOuterDiameter?: number; // çå
·å¤å¾ d1 mm |
| | | reelInnerDiameter?: number; // çè¯å
å¾ d2 mm |
| | | reelWidth?: number; // ç宽 l2 mm |
| | | ctcThickness?: number; // CTC æå¤§é«åº¦ mm |
| | | ctcWidth?: number; // CTC æå¤§å®½åº¦ mm |
| | | } |
| | | |
| | | /** çå
·å®¹é计ç®ç»æ */ |
| | | export interface ReelCalcResp { |
| | | capacityMeter?: number; // æ¯çé¿åº¦ m |
| | | capacityKm?: number; // æ¯çé¿åº¦ km |
| | | } |
| | | } |
| | | |
| | | /** æ¥è¯¢æ¢ä½å¯¼çº¿äº§åææ¯åæ°å页 */ |
| | | export function getCtcPage(params: PageParam) { |
| | | return requestClient.get<PageResult<MesPdCtcApi.Ctc>>('/mes/pd/ctc/page', { |
| | | params, |
| | | }); |
| | | } |
| | | |
| | | /** æ¥è¯¢æ¢ä½å¯¼çº¿äº§åææ¯åæ°è¯¦æ
*/ |
| | | export function getCtc(id: number) { |
| | | return requestClient.get<MesPdCtcApi.Ctc>(`/mes/pd/ctc/get?id=${id}`); |
| | | } |
| | | |
| | | /** æ°å¢æ¢ä½å¯¼çº¿äº§åææ¯åæ° */ |
| | | export function createCtc(data: MesPdCtcApi.Ctc) { |
| | | return requestClient.post('/mes/pd/ctc/create', data); |
| | | } |
| | | |
| | | /** ä¿®æ¹æ¢ä½å¯¼çº¿äº§åææ¯åæ° */ |
| | | export function updateCtc(data: MesPdCtcApi.Ctc) { |
| | | return requestClient.put('/mes/pd/ctc/update', data); |
| | | } |
| | | |
| | | /** å 餿¢ä½å¯¼çº¿äº§åææ¯åæ° */ |
| | | export function deleteCtc(id: number) { |
| | | return requestClient.delete(`/mes/pd/ctc/delete?id=${id}`); |
| | | } |
| | | |
| | | /** å¯¼åºæ¢ä½å¯¼çº¿äº§åææ¯åæ° */ |
| | | export function exportCtc(params: any) { |
| | | return requestClient.download('/mes/pd/ctc/export-excel', { params }); |
| | | } |
| | | |
| | | /** ç»å
è§åº¦è®¡ç® */ |
| | | export function calcCtcAngle(data: MesPdCtcApi.AngleCalcReq) { |
| | | return requestClient.post<MesPdCtcApi.AngleCalcResp>('/mes/pd/ctc/calc-angle', data); |
| | | } |
| | | |
| | | /** ç´æµçµé»è®¡ç® */ |
| | | export function calcCtcResistance(data: MesPdCtcApi.ResistanceCalcReq) { |
| | | return requestClient.post<MesPdCtcApi.ResistanceCalcResp>( |
| | | '/mes/pd/ctc/calc-resistance', |
| | | data, |
| | | ); |
| | | } |
| | | |
| | | /** çå
·å®¹éè®¡ç® */ |
| | | export function calcCtcReel(data: MesPdCtcApi.ReelCalcReq) { |
| | | return requestClient.post<MesPdCtcApi.ReelCalcResp>('/mes/pd/ctc/calc-reel', data); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '@vben/request'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace MesPdTechConfirmApi { |
| | | /** äº§åææ¯ç¡®è®¤å½ */ |
| | | export interface TechConfirm { |
| | | id?: number; // ç¼å· |
| | | confirmNo?: string; // 确认å½ç¼å· |
| | | customerId?: number; // 客æ·ID |
| | | customerName?: string; // 客æ·åç§° |
| | | productName?: string; // 产ååç§° |
| | | specification?: string; // è§æ ¼åå· |
| | | techParams?: string; // ææ¯åæ° JSON |
| | | templateType?: string; // 模æ¿ç±»å |
| | | drafterId?: number; // ç¼å¶äººID |
| | | drafterName?: string; // ç¼å¶äººå§å |
| | | draftTime?: Date; // ç¼å¶æ¶é´ |
| | | reviewerId?: number; // å®¡æ ¸äººID |
| | | reviewerName?: string; // å®¡æ ¸äººå§å |
| | | reviewTime?: Date; // å®¡æ ¸æ¶é´ |
| | | customerConfirmUser?: string; // 客æ·ç¡®è®¤äºº |
| | | customerConfirmTime?: Date; // 客æ·ç¡®è®¤æ¶é´ |
| | | status?: number; // ç¶æ |
| | | remark?: string; // 夿³¨ |
| | | createTime?: Date; // å建æ¶é´ |
| | | } |
| | | } |
| | | |
| | | /** æ¥è¯¢äº§åææ¯ç¡®è®¤å½å页 */ |
| | | export function getTechConfirmPage(params: PageParam) { |
| | | return requestClient.get<PageResult<MesPdTechConfirmApi.TechConfirm>>( |
| | | '/mes/pd/tech-confirm/page', |
| | | { params }, |
| | | ); |
| | | } |
| | | |
| | | /** æ¥è¯¢äº§åææ¯ç¡®è®¤å½è¯¦æ
*/ |
| | | export function getTechConfirm(id: number) { |
| | | return requestClient.get<MesPdTechConfirmApi.TechConfirm>( |
| | | `/mes/pd/tech-confirm/get?id=${id}`, |
| | | ); |
| | | } |
| | | |
| | | /** æ°å¢äº§åææ¯ç¡®è®¤å½ */ |
| | | export function createTechConfirm(data: MesPdTechConfirmApi.TechConfirm) { |
| | | return requestClient.post('/mes/pd/tech-confirm/create', data); |
| | | } |
| | | |
| | | /** ä¿®æ¹äº§åææ¯ç¡®è®¤å½ */ |
| | | export function updateTechConfirm(data: MesPdTechConfirmApi.TechConfirm) { |
| | | return requestClient.put('/mes/pd/tech-confirm/update', data); |
| | | } |
| | | |
| | | /** å é¤äº§åææ¯ç¡®è®¤å½ */ |
| | | export function deleteTechConfirm(id: number) { |
| | | return requestClient.delete(`/mes/pd/tech-confirm/delete?id=${id}`); |
| | | } |
| | | |
| | | /** 导åºäº§åææ¯ç¡®è®¤å½ */ |
| | | export function exportTechConfirm(params: any) { |
| | | return requestClient.download('/mes/pd/tech-confirm/export-excel', { params }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '@vben/request'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace MesProEmergencyPlanApi { |
| | | /** åºæ¥å¤ç½®é¢æ¡ */ |
| | | export interface EmergencyPlan { |
| | | id?: number; |
| | | code?: string; // 颿¡ç¼ç |
| | | name?: string; // 颿¡åç§° |
| | | planType?: number; // 颿¡ç±»åï¼1åçµ 2è®¾å¤æ
é 3ç«ç¾ 4èªç¶ç¾å®³ 5å
¶ä» |
| | | content?: string; // å¤ç½®å
容 |
| | | orgUnit?: string; // 责任åä½ |
| | | status?: number; // ç¶æï¼0è稿 10å·²åå¸ |
| | | remark?: string; // 夿³¨ |
| | | createTime?: string; |
| | | } |
| | | } |
| | | |
| | | /** åå»ºåºæ¥å¤ç½®é¢æ¡ */ |
| | | export function createPlan(data: MesProEmergencyPlanApi.EmergencyPlan) { |
| | | return requestClient.post('/mes/pro/emergency-plan/create', data); |
| | | } |
| | | |
| | | /** æ´æ°åºæ¥å¤ç½®é¢æ¡ */ |
| | | export function updatePlan(data: MesProEmergencyPlanApi.EmergencyPlan) { |
| | | return requestClient.put('/mes/pro/emergency-plan/update', data); |
| | | } |
| | | |
| | | /** å é¤åºæ¥å¤ç½®é¢æ¡ */ |
| | | export function deletePlan(ids: number[]) { |
| | | return requestClient.delete('/mes/pro/emergency-plan/delete', { params: { ids: ids.join(',') } }); |
| | | } |
| | | |
| | | /** è·ååºæ¥å¤ç½®é¢æ¡ */ |
| | | export function getPlan(id: number) { |
| | | return requestClient.get<MesProEmergencyPlanApi.EmergencyPlan>( |
| | | `/mes/pro/emergency-plan/get?id=${id}`, |
| | | ); |
| | | } |
| | | |
| | | /** è·ååºæ¥å¤ç½®é¢æ¡å页 */ |
| | | export function getPlanPage(params: PageParam) { |
| | | return requestClient.get<PageResult<MesProEmergencyPlanApi.EmergencyPlan>>( |
| | | '/mes/pro/emergency-plan/page', |
| | | { params }, |
| | | ); |
| | | } |
| | | |
| | | /** åå¸åºæ¥å¤ç½®é¢æ¡ */ |
| | | export function publishPlan(id: number) { |
| | | return requestClient.put(`/mes/pro/emergency-plan/publish?id=${id}`); |
| | | } |
| | |
| | | `/mes/pro/feedback/list-by-task?taskId=${taskId}`, |
| | | ); |
| | | } |
| | | |
| | | /** ä½ä¸æææ±æ»é¡¹ï¼æå·¥åç±»åï¼ */ |
| | | export interface WorkResultTypeItem { |
| | | workOrderType?: number; |
| | | workOrderTypeName?: string; |
| | | feedbackQuantity?: number; |
| | | qualifiedQuantity?: number; |
| | | feedbackCount?: number; |
| | | } |
| | | |
| | | /** ä½ä¸æææ±æ»é¡¹ï¼ææ¥æï¼ */ |
| | | export interface WorkResultDateItem { |
| | | date?: string; |
| | | feedbackQuantity?: number; |
| | | qualifiedQuantity?: number; |
| | | feedbackCount?: number; |
| | | } |
| | | |
| | | /** ä½ä¸æææ±æ» */ |
| | | export interface WorkResultSummary { |
| | | totalFeedbackQuantity?: number; |
| | | totalQualifiedQuantity?: number; |
| | | totalFeedbackCount?: number; |
| | | byType?: WorkResultTypeItem[]; |
| | | byDate?: WorkResultDateItem[]; |
| | | } |
| | | |
| | | /** ä½ä¸æææ±æ»ç»è®¡ */ |
| | | export function getFeedbackSummary(params: { |
| | | beginDate?: string; |
| | | endDate?: string; |
| | | workOrderType?: number; |
| | | }) { |
| | | return requestClient.get<WorkResultSummary>('/mes/pro/feedback/summary', { |
| | | params, |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '@vben/request'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace MesProMaintenancePlanApi { |
| | | /** çµåä½ä¸è®¡å */ |
| | | export interface MaintenancePlan { |
| | | id?: number; // ç¼å· |
| | | code?: string; // 计åç¼ç |
| | | name?: string; // 计ååç§° |
| | | planType?: number; // 计åç±»åï¼1çµç½è¿è¡ 2åçµ 3åçµè¿ç»´ 4线路æ£ä¿® |
| | | station?: string; // ç«ç¹ |
| | | line?: string; // 线路 |
| | | teamId?: number; // çç»ç¼å· |
| | | teamName?: string; // çç»åç§° |
| | | planDate?: string; // è®¡åæ¥æ |
| | | status?: number; // ç¶æï¼0è稿 10å·²ä¸å 20已宿 30已忶 |
| | | workOrderId?: number; // çæçå·¥åç¼å· |
| | | workOrderCode?: string; // çæçå·¥åç¼ç |
| | | remark?: string; // 夿³¨ |
| | | items?: PlanItem[]; // å¤ä»¶éæ±æç» |
| | | createTime?: string; // å建æ¶é´ |
| | | } |
| | | |
| | | /** å¤ä»¶éæ±æç» */ |
| | | export interface PlanItem { |
| | | id?: number; // ç¼å· |
| | | itemId: number; // ç©æ/å¤ä»¶ç¼å· |
| | | itemName?: string; // ç©æåç§° |
| | | itemCode?: string; // ç©æç¼ç |
| | | unitMeasureName?: string; // 计éåä½åç§° |
| | | quantity: number; // éæ±æ°é |
| | | remark?: string; // 夿³¨ |
| | | } |
| | | } |
| | | |
| | | /** å建çµåä½ä¸è®¡å */ |
| | | export function createPlan(data: MesProMaintenancePlanApi.MaintenancePlan) { |
| | | return requestClient.post('/mes/pro/maintenance-plan/create', data); |
| | | } |
| | | |
| | | /** æ´æ°çµåä½ä¸è®¡å */ |
| | | export function updatePlan(data: MesProMaintenancePlanApi.MaintenancePlan) { |
| | | return requestClient.put('/mes/pro/maintenance-plan/update', data); |
| | | } |
| | | |
| | | /** å é¤çµåä½ä¸è®¡å */ |
| | | export function deletePlan(ids: number[]) { |
| | | return requestClient.delete('/mes/pro/maintenance-plan/delete', { params: { ids: ids.join(',') } }); |
| | | } |
| | | |
| | | /** è·åçµåä½ä¸è®¡å详æ
*/ |
| | | export function getPlan(id: number) { |
| | | return requestClient.get<MesProMaintenancePlanApi.MaintenancePlan>( |
| | | `/mes/pro/maintenance-plan/get?id=${id}`, |
| | | ); |
| | | } |
| | | |
| | | /** è·åçµåä½ä¸è®¡åå页 */ |
| | | export function getPlanPage(params: PageParam) { |
| | | return requestClient.get<PageResult<MesProMaintenancePlanApi.MaintenancePlan>>( |
| | | '/mes/pro/maintenance-plan/page', |
| | | { params }, |
| | | ); |
| | | } |
| | | |
| | | /** 导åºçµåä½ä¸è®¡å */ |
| | | export function exportPlan(params: any) { |
| | | return requestClient.download('/mes/pro/maintenance-plan/export-excel', { params }); |
| | | } |
| | | |
| | | /** ä¸åçµåä½ä¸è®¡å */ |
| | | export function issuePlan(id: number) { |
| | | return requestClient.put(`/mes/pro/maintenance-plan/issue?id=${id}`); |
| | | } |
| | | |
| | | /** 宿çµåä½ä¸è®¡å */ |
| | | export function finishPlan(id: number) { |
| | | return requestClient.put(`/mes/pro/maintenance-plan/finish?id=${id}`); |
| | | } |
| | | |
| | | /** æ ¹æ®å¤ä»¶éæ±çæéè´è®¡å */ |
| | | export function generatePurchasePlan(id: number) { |
| | | return requestClient.post<number>(`/mes/pro/maintenance-plan/generate-purchase-plan?id=${id}`); |
| | | } |
| | | |
| | | /** çæè¿ç»´/åçµ/æ£ä¿®å·¥å */ |
| | | export function generateWorkOrder(id: number) { |
| | | return requestClient.post<number>(`/mes/pro/maintenance-plan/generate-work-order?id=${id}`); |
| | | } |
| | |
| | | id?: number; |
| | | code?: string; |
| | | name?: string; |
| | | type?: number; // çµåå·¥èºåç±» |
| | | attention?: string; |
| | | status?: number; |
| | | remark?: string; |
| | |
| | | workstationId?: number; // å·¥ä½ç«ç¼å· |
| | | workstationCode?: string; // å·¥ä½ç«ç¼ç |
| | | workstationName?: string; // å·¥ä½ç«åç§° |
| | | teamId?: number; // çç»ç¼å· |
| | | teamName?: string; // çç»åç§° |
| | | routeId?: number; // å·¥èºè·¯çº¿ç¼å· |
| | | processId?: number; // å·¥åºç¼å· |
| | | processName?: string; // å·¥åºåç§° |
| | |
| | | clientId?: number; // 客æ·ç¼å· |
| | | clientCode?: string; // 客æ·ç¼ç |
| | | clientName?: string; // 客æ·åç§° |
| | | saleOrderId?: number; // å
³èè¥é订åï¼ERPéå®è®¢åï¼ç¼å· |
| | | saleOrderNo?: string; // å
³èè¥é订åï¼ERPéå®è®¢åï¼åå· |
| | | vendorId?: number; // ä¾åºåç¼å· |
| | | vendorName?: string; // ä¾åºååç§° |
| | | vendorCode?: string; // ä¾åºåç¼ç |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '@vben/request'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace MesQcOutsourceTestApi { |
| | | /** å§å¤æ£æµ/è¯éªå */ |
| | | export interface OutsourceTest { |
| | | id?: number; |
| | | code?: string; // åæ®ç¼ç |
| | | name?: string; // åæ®åç§° |
| | | testType?: number; // æ£æµç±»åï¼1ç¬¬ä¸æ¹æ£æµ 2å§å¤è¯éª |
| | | itemId?: number; // æ£æµå¯¹è±¡ç¼å· |
| | | itemName?: string; // æ£æµå¯¹è±¡åç§° |
| | | testOrg?: string; // æ£æµæºæ |
| | | testDate?: string; // æ£æµæ¥æ |
| | | result?: number; // æ£æµç»æï¼1åæ ¼ 2ä¸åæ ¼ |
| | | reportNo?: string; // æ£æµæ¥åç¼å· |
| | | status?: number; // ç¶æï¼0è稿 10å·²æäº¤ 20已宿 |
| | | remark?: string; // 夿³¨ |
| | | blobIds?: number[]; // éä»¶ |
| | | attachmentList?: { id: number; name?: string; url?: string }[]; |
| | | createTime?: string; |
| | | } |
| | | } |
| | | |
| | | /** å建å§å¤æ£æµ/è¯éªå */ |
| | | export function createTest(data: MesQcOutsourceTestApi.OutsourceTest) { |
| | | return requestClient.post('/mes/qc/outsource-test/create', data); |
| | | } |
| | | |
| | | /** æ´æ°å§å¤æ£æµ/è¯éªå */ |
| | | export function updateTest(data: MesQcOutsourceTestApi.OutsourceTest) { |
| | | return requestClient.put('/mes/qc/outsource-test/update', data); |
| | | } |
| | | |
| | | /** å é¤å§å¤æ£æµ/è¯éªå */ |
| | | export function deleteTest(ids: number[]) { |
| | | return requestClient.delete('/mes/qc/outsource-test/delete', { params: { ids: ids.join(',') } }); |
| | | } |
| | | |
| | | /** è·åå§å¤æ£æµ/è¯éªå详æ
*/ |
| | | export function getTest(id: number) { |
| | | return requestClient.get<MesQcOutsourceTestApi.OutsourceTest>( |
| | | `/mes/qc/outsource-test/get?id=${id}`, |
| | | ); |
| | | } |
| | | |
| | | /** è·åå§å¤æ£æµ/è¯éªåå页 */ |
| | | export function getTestPage(params: PageParam) { |
| | | return requestClient.get<PageResult<MesQcOutsourceTestApi.OutsourceTest>>( |
| | | '/mes/qc/outsource-test/page', |
| | | { params }, |
| | | ); |
| | | } |
| | | |
| | | /** æäº¤å§å¤æ£æµ/è¯éªå */ |
| | | export function submitTest(id: number) { |
| | | return requestClient.put(`/mes/qc/outsource-test/submit?id=${id}`); |
| | | } |
| | | |
| | | /** 宿å§å¤æ£æµ/è¯éªå */ |
| | | export function finishTest(id: number) { |
| | | return requestClient.put(`/mes/qc/outsource-test/finish?id=${id}`); |
| | | } |
| | |
| | | clientCode?: string; // 客æ·ç¼ç |
| | | clientName?: string; // 客æ·åç§° |
| | | requiredTime?: number; // éæ±æ¶é´ |
| | | issueType?: number; // åæ®ç±»åï¼1=æ£å¸¸é¢æï¼2=ç´§æ¥è¡¥æï¼ |
| | | status?: number; // åæ®ç¶æ |
| | | remark?: string; // 夿³¨ |
| | | createTime?: Date; // å建æ¶é´ |
| | |
| | | >('/mes/wm/stocktaking-task-line/page', { params }); |
| | | } |
| | | |
| | | /** ä¸è½½çç¹å®çæ°å¯¼å
¥æ¨¡æ¿ */ |
| | | export function importStockTakingQuantityTemplate() { |
| | | return requestClient.download('/mes/wm/stocktaking-task-line/get-import-template'); |
| | | } |
| | | |
| | | /** 导å
¥çç¹å®çæ°é */ |
| | | export function importStockTakingQuantity(taskId: number, file: File) { |
| | | return requestClient.upload<{ |
| | | successCount?: number; |
| | | failureCount?: number; |
| | | failureMessages?: string[]; |
| | | }>(`/mes/wm/stocktaking-task-line/import-excel?taskId=${taskId}`, { file }); |
| | | } |
| | | |
| | | /** æ¥è¯¢çç¹ä»»å¡è¡ç²¾ç®å表 */ |
| | | export function getStockTakingTaskLineSimpleList(taskId: number) { |
| | | return requestClient.get<WlsStockTakingTaskLineApi.StockTakingTaskLine[]>( |
| | |
| | | id?: number; // åºä½ç¼å· |
| | | code?: string; // åºä½ç¼ç |
| | | name?: string; // åºä½åç§° |
| | | type?: number; // åºåºç±»å |
| | | warehouseId?: number; // ä»åºç¼å· |
| | | warehouseName?: string; // ä»åºåç§° |
| | | locationId?: number; // åºåºç¼å· |
| | |
| | | id?: number; // ä»åºç¼å· |
| | | code?: string; // ä»åºç¼ç |
| | | name?: string; // ä»åºåç§° |
| | | type?: number; // ä»åºç±»å |
| | | address?: string; // å°å |
| | | area?: number; // é¢ç§¯ |
| | | chargeUserId?: number; // è´è´£äºº |
| | |
| | | CLOSE: 'lucide:x', |
| | | BOOK: 'lucide:book', |
| | | AUDIT: 'lucide:file-check', |
| | | CALC: 'lucide:calculator', |
| | | }; |
| | |
| | | SELF: 1, // èªè¡ç产 |
| | | OUTSOURCE: 2, // 代工 |
| | | PURCHASE: 3, // éè´ |
| | | POWER_OPERATION: 4, // çµåè¿ç»´ |
| | | POWER_GENERATION: 5, // åçµ |
| | | POWER_MAINTENANCE: 6, // æ£ä¿® |
| | | } as const; |
| | | |
| | | /** MES 工忥æºç±»åæä¸¾ */ |
| | | export const MesProWorkOrderSourceTypeEnum = { |
| | | ORDER: 1, // 客æ·è®¢å |
| | | STORE: 2, // åºåå¤è´§ |
| | | MAINTENANCE_PLAN: 3, // è¿ç»´è®¡å |
| | | } as const; |
| | | |
| | | /** MES ç产任å¡ç¶ææä¸¾ */ |
| | |
| | | CRM_SALES_TARGET_PERIOD_TYPE: 'crm_sales_target_period_type', // CRM éå®ç®æ å¨æç±»å |
| | | CRM_SALES_TARGET_DIMENSION: 'crm_sales_target_dimension', // CRM éå®ç®æ 维度 |
| | | CRM_SALES_TARGET_STATUS: 'crm_sales_target_status', // CRM éå®ç®æ ç¶æ |
| | | CRM_CUSTOMER_TYPE: 'crm_customer_type', // CRM 客æ·åç±»ï¼çµåï¼ |
| | | CRM_CREDIT_LEVEL: 'crm_credit_level', // CRM 客æ·ä¿¡ç¨ç级 |
| | | CRM_QUOTATION_TYPE: 'crm_quotation_type', // CRM æ¥ä»·åç±»å |
| | | CRM_TARIFF_MODE: 'crm_tariff_mode', // CRM çµä»·æ¨¡å¼ |
| | | CRM_CONTRACT_TYPE: 'crm_contract_type', // CRM ååç±»å |
| | | CRM_VOLTAGE_LEVEL: 'crm_voltage_level', // CRM çµåç级 |
| | | CRM_ELECTRICITY_TYPE: 'crm_electricity_type', // CRM ç¨çµç±»å |
| | | CRM_METER_MODE: 'crm_meter_mode', // CRM è®¡éæ¹å¼ |
| | | CRM_COMMAND_TYPE: 'crm_command_type', // CRM ååæä»¤ç±»å |
| | | CRM_COMMAND_STATUS: 'crm_command_status', // CRM ååæä»¤ç¶æ |
| | | CRM_REFUND_TYPE: 'crm_refund_type', // CRM é费类å |
| | | CRM_CANCELLATION_TYPE: 'crm_cancellation_type', // CRM éæ·ç±»å |
| | | } as const; |
| | | |
| | | /** ========== AFTERSALES - å®åæå¡æ¨¡å ========== */ |
| | |
| | | /** ========== MES - å¶é æ§è¡æ¨¡å ========== */ |
| | | const MES_DICT = { |
| | | MES_MD_ITEM_OR_PRODUCT: 'mes_md_item_or_product', // MES ç©æ/äº§åæ è¯ |
| | | MES_MATERIAL_CATEGORY: 'mes_material_category', // MES çµåç©èµåç±» |
| | | MES_PRO_MAINTENANCE_PLAN_TYPE: 'mes_pro_maintenance_plan_type', // MES çµåä½ä¸è®¡åç±»å |
| | | MES_PRO_MAINTENANCE_PLAN_STATUS: 'mes_pro_maintenance_plan_status', // MES çµåä½ä¸è®¡åç¶æ |
| | | MES_QC_OUTSOURCE_TEST_TYPE: 'mes_qc_outsource_test_type', // MES å§å¤æ£æµç±»å |
| | | MES_QC_OUTSOURCE_TEST_RESULT: 'mes_qc_outsource_test_result', // MES å§å¤æ£æµç»æ |
| | | MES_PRO_PROCESS_TYPE: 'mes_pro_process_type', // MES çµåå·¥èºåç±» |
| | | MES_PRO_EMERGENCY_PLAN_TYPE: 'mes_pro_emergency_plan_type', // MES åºæ¥å¤ç½®é¢æ¡ç±»å |
| | | MES_MD_AUTO_CODE_CYCLE_METHOD: 'mes_md_auto_code_cycle_method', // MES ç¼ç è§åå¾ªç¯æ¹å¼ |
| | | MES_MD_AUTO_CODE_PADDED_METHOD: 'mes_md_auto_code_padded_method', // MES ç¼ç è§åè¡¥é½æ¹å¼ |
| | | MES_MD_AUTO_CODE_PART_TYPE: 'mes_md_auto_code_part_type', // MES ç¼ç è§ååæ®µç±»å |
| | |
| | | MES_PD_VERSION_CHANGE_TYPE: 'mes_pd_version_change_type', // MES çæ¬åæ´ç±»å |
| | | MES_PD_DOCUMENT_TYPE: 'mes_pd_document_type', // MES è®¾è®¡èµæç±»å |
| | | MES_PD_ARCHIVE_STATUS: 'mes_pd_archive_status', // MES è®¾è®¡å½æ¡£ç¶æ |
| | | PRODUCT_CONDUCTOR_TYPE: 'product_conductor_type', // æ¢ä½å¯¼çº¿å¯¼ä½ç±»å |
| | | PRODUCT_REEL_TYPE: 'product_reel_type', // æ¢ä½å¯¼çº¿çå
፱Ȍ |
| | | PRODUCT_TECH_CONFIRM_TEMPLATE: 'product_tech_confirm_template', // ææ¯ç¡®è®¤å½æ¨¡æ¿ç±»å |
| | | PRODUCT_TECH_CONFIRM_STATUS: 'product_tech_confirm_status', // ææ¯ç¡®è®¤å½ç¶æ |
| | | MES_PRO_FEEDBACK_CHANNEL: 'mes_pro_feedback_channel', // MES ç产æ¥å·¥éå¾ |
| | | MES_PRO_ANDON_STATUS: 'mes_pro_andon_status', // MES å®ç¯å¤ç½®ç¶æ |
| | | MES_PRO_ANDON_LEVEL: 'mes_pro_andon_level', // MES å®ç¯çº§å« |
| | |
| | | MES_WM_BARCODE_FORMAT: 'mes_wm_barcode_format', // MES æ¡ç æ ¼å¼ |
| | | MES_WM_PACKAGE_STATUS: 'mes_wm_package_status', // MES è£
ç®±åç¶æ |
| | | MES_WM_PRODUCT_SALES_STATUS: 'mes_wm_product_sales_status', // MES éå®åºåºåç¶æ |
| | | MES_WM_WAREHOUSE_TYPE: 'mes_wm_warehouse_type', // MES ä»åº/åºåºç±»å |
| | | MES_WM_QUALITY_STATUS: 'mes_wm_quality_status', // MES è´¨éç¶æ |
| | | MES_WM_MISC_ISSUE_TYPE: 'mes_wm_misc_issue_type', // MES æé¡¹åºåºç±»å |
| | | MES_WM_MISC_ISSUE_STATUS: 'mes_wm_misc_issue_status', // MES æé¡¹åºåºåç¶æ |
| | |
| | | MES_WM_RETURN_ISSUE_STATUS: 'mes_wm_return_issue_status', // MES ç产éæåç¶æ |
| | | MES_WM_RETURN_ISSUE_TYPE: 'mes_wm_return_issue_type', // MES éæç±»å |
| | | MES_WM_PRODUCT_ISSUE_STATUS: 'mes_wm_product_issue_status', // MES 颿åºåºåç¶æ |
| | | MES_WM_PRODUCT_ISSUE_TYPE: 'mes_wm_product_issue_type', // MES çäº§é¢æåæ®ç±»å |
| | | MES_WM_PRODUCT_RECEIPT_STATUS: 'mes_wm_product_receipt_status', // MES 产åå
¥åºåç¶æ |
| | | MES_WM_STOCK_TAKING_TYPE: 'mes_wm_stock_taking_type', // MES çç¹ç±»å |
| | | MES_WM_STOCK_TAKING_TASK_STATUS: 'mes_wm_stock_taking_task_status', // MES çç¹ä»»å¡ç¶æ |
| | |
| | | MES_PD_TEMPLATE_TYPE: 'mes_pd_template_type', // MES å·¥èºæ¨¡æ¿ç±»å |
| | | MES_NCR_STATUS: 'mes_ncr_status', // MES ä¸åæ ¼åå¤çåç¶æ |
| | | MES_NCR_DISPOSITION: 'mes_ncr_disposition', // MES ä¸åæ ¼åå¤ç½®æ¹å¼ |
| | | MES_PD_PRODUCT_ARCHIVE_TYPE: 'mes_pd_product_archive_type', // MES äº§åæ¡£æ¡ç±»å |
| | | MES_PD_AUDIT_STATUS: 'mes_pd_audit_status', // MES 产å设计审æ¹ç¶æ |
| | | MES_PD_PRODUCT_STATUS: 'mes_pd_product_status', // MES äº§åæ¡£æ¡å¯ç¨ç¶æ |
| | | MES_PD_PRICE_OBJECT_TYPE: 'mes_pd_price_object_type', // MES å®ä»·å¯¹è±¡ç±»å |
| | | MES_PD_DISCOUNT_POLICY_TYPE: 'mes_pd_discount_policy_type', // MES 伿 çç¥ç±»å |
| | | MES_PD_TIERED_PRICE_STATUS: 'mes_pd_tiered_price_status', // MES é¶æ¢¯çµä»·å¯ç¨ç¶æ |
| | | } as const; |
| | | |
| | | /** ========== WMS - ä»å¨ç®¡ç模å ========== */ |
| | |
| | | const HRM_DICT = { |
| | | HRM_DEGREE: 'hrm_degree', // HRM å¦å |
| | | HRM_EMPLOYEE_STATUS: 'hrm_employee_status', // HRM åå·¥ç¶æ |
| | | HRM_CERTIFICATE_TYPE: 'hrm_certificate_type', // HRM è¯ä¹¦èµè´¨ç±»å |
| | | HRM_GENDER: 'hrm_gender', // HRM æ§å« |
| | | HRM_AUDIT_STATUS: 'hrm_audit_status', // HRM 审æ¹ç¶æ |
| | | HRM_LEAVE_TYPE: 'hrm_leave_type', // HRM 请åç±»å |
| | |
| | | { label: 'ä¸è¬é®é¢', value: 1 }, |
| | | { label: 'ç»´ä¿®é®é¢', value: 2 }, |
| | | { label: 'éè´§é®é¢', value: 3 }, |
| | | { label: 'åçµæ¥ä¿®', value: 4 }, |
| | | { label: 'ç¨çµæ
é', value: 5 }, |
| | | { label: 'æå¡æè¯', value: 6 }, |
| | | { label: 'ä¾çµè´¨éå¼è®®', value: 7 }, |
| | | ]; |
| | | |
| | | /** 严éç¨åº¦é项 */ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { CrmCancellationApi } from '#/api/crm/cancellation'; |
| | | import type { CrmCustomerApi } from '#/api/crm/customer'; |
| | | |
| | | import { markRaw } from 'vue'; |
| | | |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | |
| | | import CrmCustomerSelect from '#/components/crm-customer-select.vue'; |
| | | |
| | | /** æ°å¢/ä¿®æ¹éæ·ç³è¯· */ |
| | | export function useFormSchema( |
| | | formApi?: VbenFormApi, |
| | | ): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | | component: 'Input', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'cancellationNo', |
| | | label: 'éæ·ç¼å·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: 'ä¸å¡«åèªå¨çæ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'customerId', |
| | | label: '客æ·', |
| | | component: markRaw(CrmCustomerSelect), |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©å®¢æ·', |
| | | onChange: (item?: CrmCustomerApi.Customer) => { |
| | | formApi?.setFieldValue('customerName', item?.name); |
| | | }, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'customerName', |
| | | label: '客æ·åç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '客æ·åç§°', |
| | | readonly: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'cancellationType', |
| | | label: 'éæ·ç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.CRM_CANCELLATION_TYPE), |
| | | placeholder: 'è¯·éæ©éæ·ç±»å', |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'contractNo', |
| | | label: 'ååç¼å·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å
³èååç¼å·', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'expectedCancelDate', |
| | | label: 'é¢è®¡éæ·æ¥æ', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | format: 'YYYY-MM-DD', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'actualCancelDate', |
| | | label: 'å®é
éæ·æ¥æ', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | format: 'YYYY-MM-DD', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'refundAmount', |
| | | label: 'éè´¹éé¢', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: 'w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥éè´¹éé¢ï¼å
ï¼', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'applyUserName', |
| | | label: 'ç³è¯·äºº', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥ç³è¯·äººå§å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'applyTime', |
| | | label: 'ç³è¯·æ¶é´', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | format: 'YYYY-MM-DD HH:mm:ss', |
| | | showTime: true, |
| | | valueFormat: 'YYYY-MM-DD HH:mm:ss', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'cancelReason', |
| | | label: 'éæ·åå ', |
| | | component: 'Textarea', |
| | | formItemClass: 'col-span-2', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥éæ·åå ', |
| | | rows: 2, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | | formItemClass: 'col-span-2', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å¤æ³¨', |
| | | rows: 2, |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çæç´¢è¡¨å */ |
| | | export function useGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'cancellationNo', |
| | | label: 'éæ·ç¼å·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | allowClear: true, |
| | | placeholder: '请è¾å
¥éæ·ç¼å·', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'cancellationType', |
| | | label: 'éæ·ç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.CRM_CANCELLATION_TYPE), |
| | | placeholder: 'è¯·éæ©éæ·ç±»å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'auditStatus', |
| | | label: '审æ¹ç¶æ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.CRM_AUDIT_STATUS, 'number'), |
| | | placeholder: 'è¯·éæ©å®¡æ¹ç¶æ', |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çåæ®µ */ |
| | | export function useGridColumns(): VxeTableGridOptions<CrmCancellationApi.Cancellation>['columns'] { |
| | | return [ |
| | | { field: 'cancellationNo', title: 'éæ·ç¼å·', minWidth: 170 }, |
| | | { field: 'customerName', title: '客æ·åç§°', minWidth: 180 }, |
| | | { |
| | | field: 'cancellationType', |
| | | title: 'éæ·ç±»å', |
| | | width: 110, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.CRM_CANCELLATION_TYPE }, |
| | | }, |
| | | }, |
| | | { field: 'contractNo', title: 'ååç¼å·', minWidth: 140 }, |
| | | { |
| | | field: 'expectedCancelDate', |
| | | title: 'é¢è®¡éæ·æ¥æ', |
| | | width: 120, |
| | | formatter: 'formatDate', |
| | | }, |
| | | { |
| | | field: 'actualCancelDate', |
| | | title: 'å®é
éæ·æ¥æ', |
| | | width: 120, |
| | | formatter: 'formatDate', |
| | | }, |
| | | { field: 'refundAmount', title: 'éè´¹éé¢', width: 120 }, |
| | | { field: 'applyUserName', title: 'ç³è¯·äºº', width: 100 }, |
| | | { |
| | | field: 'auditStatus', |
| | | title: '审æ¹ç¶æ', |
| | | width: 110, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.CRM_AUDIT_STATUS }, |
| | | }, |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | width: 200, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { CrmCancellationApi } from '#/api/crm/cancellation'; |
| | | |
| | | import { Page, useVbenModal } from '@vben/common-ui'; |
| | | import { downloadFileFromBlobPart } from '@vben/utils'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | auditCancellation, |
| | | deleteCancellation, |
| | | exportCancellation, |
| | | getCancellationPage, |
| | | } from '#/api/crm/cancellation'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | /** å·æ°è¡¨æ ¼ */ |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** 导åºè¡¨æ ¼ */ |
| | | async function handleExport() { |
| | | const formValues = await gridApi.formApi.getValues(); |
| | | const data = await exportCancellation(formValues); |
| | | downloadFileFromBlobPart({ fileName: 'éæ·ç³è¯·.xls', source: data }); |
| | | } |
| | | |
| | | /** æ°å¢ */ |
| | | function handleCreate() { |
| | | formModalApi.setData(null).open(); |
| | | } |
| | | |
| | | /** ç¼è¾ */ |
| | | function handleEdit(row: CrmCancellationApi.Cancellation) { |
| | | formModalApi.setData({ cancellation: row }).open(); |
| | | } |
| | | |
| | | /** å é¤ */ |
| | | async function handleDelete(row: CrmCancellationApi.Cancellation) { |
| | | const hideLoading = message.loading({ |
| | | content: $t('ui.actionMessage.deleting', [row.cancellationNo ?? '']), |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await deleteCancellation(row.id!); |
| | | message.success( |
| | | $t('ui.actionMessage.deleteSuccess', [row.cancellationNo ?? '']), |
| | | ); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** 审æ¹ï¼éè¿/驳åï¼ */ |
| | | async function handleAudit( |
| | | row: CrmCancellationApi.Cancellation, |
| | | pass: boolean, |
| | | ) { |
| | | const hideLoading = message.loading({ |
| | | content: pass ? '审æ¹éè¿ä¸...' : '审æ¹é©³åä¸...', |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await auditCancellation({ id: row.id!, auditStatus: pass ? 20 : 30 }); |
| | | message.success(pass ? '审æ¹éè¿' : '审æ¹é©³å'); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useGridColumns(), |
| | | height: 'auto', |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => |
| | | await getCancellationPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }), |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<CrmCancellationApi.Cancellation>, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <FormModal @success="handleRefresh" /> |
| | | <Grid table-title="éæ·ç³è¯·å表"> |
| | | <template #toolbar-tools> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('ui.actionTitle.create', ['éæ·ç³è¯·']), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['crm:cancellation:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | { |
| | | label: $t('ui.actionTitle.export'), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | | auth: ['crm:cancellation:export'], |
| | | onClick: handleExport, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: 'éè¿', |
| | | type: 'link', |
| | | icon: ACTION_ICON.AUDIT, |
| | | auth: ['crm:cancellation:update'], |
| | | ifShow: row.auditStatus === 0 || row.auditStatus === 10, |
| | | popConfirm: { |
| | | title: '确认审æ¹éè¿è¯¥éæ·ç³è¯·ï¼', |
| | | confirm: handleAudit.bind(null, row, true), |
| | | }, |
| | | }, |
| | | { |
| | | label: '驳å', |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.AUDIT, |
| | | auth: ['crm:cancellation:update'], |
| | | ifShow: row.auditStatus === 0 || row.auditStatus === 10, |
| | | popConfirm: { |
| | | title: '确认驳åè¯¥éæ·ç³è¯·ï¼', |
| | | confirm: handleAudit.bind(null, row, false), |
| | | }, |
| | | }, |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['crm:cancellation:update'], |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['crm:cancellation:delete'], |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [ |
| | | row.cancellationNo ?? '', |
| | | ]), |
| | | confirm: handleDelete.bind(null, row), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { CrmCancellationApi } from '#/api/crm/cancellation'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenForm, useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { |
| | | createCancellation, |
| | | getCancellation, |
| | | updateCancellation, |
| | | } from '#/api/crm/cancellation'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useFormSchema } from '../data'; |
| | | |
| | | type CancellationFormModalData = { |
| | | cancellation?: Pick<CrmCancellationApi.Cancellation, 'id'>; |
| | | }; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formData = ref<Partial<CrmCancellationApi.Cancellation>>(); |
| | | const getTitle = computed(() => { |
| | | return formData.value?.id |
| | | ? $t('ui.actionTitle.edit', ['éæ·ç³è¯·']) |
| | | : $t('ui.actionTitle.create', ['éæ·ç³è¯·']); |
| | | }); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | labelWidth: 110, |
| | | }, |
| | | wrapperClass: 'grid-cols-2', |
| | | layout: 'horizontal', |
| | | schema: [], |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | const data = |
| | | (await formApi.getValues()) as CrmCancellationApi.Cancellation; |
| | | if (formData.value?.id) { |
| | | data.id = formData.value.id; |
| | | } |
| | | try { |
| | | await (formData.value?.id |
| | | ? updateCancellation(data) |
| | | : createCancellation(data)); |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | return; |
| | | } |
| | | formApi.setState({ schema: useFormSchema(formApi) }); |
| | | await formApi.resetForm(); |
| | | const data = modalApi.getData() as null | CancellationFormModalData; |
| | | if (!data?.cancellation?.id) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | formData.value = await getCancellation(data.cancellation.id); |
| | | if (formData.value) { |
| | | await formApi.setValues(formData.value as any); |
| | | } |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal :title="getTitle" class="w-3/5"> |
| | | <Form class="mx-4" /> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; |
| | | |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | |
| | | /** æ°å¢/ä¿®æ¹ååæä»¤ */ |
| | | export function useFormSchema( |
| | | formApi?: VbenFormApi, |
| | | ): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | | component: 'Input', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'contractId', |
| | | label: 'ååID', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: 'w-full', |
| | | precision: 0, |
| | | placeholder: 'ååID', |
| | | }, |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'contractNo', |
| | | label: 'ååç¼å·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: 'ååç¼å·', |
| | | readonly: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'commandType', |
| | | label: 'æä»¤ç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.CRM_COMMAND_TYPE), |
| | | placeholder: 'è¯·éæ©æä»¤ç±»å', |
| | | allowClear: true, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'targetModule', |
| | | label: 'ç®æ 模å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: [ |
| | | { label: 'MES å·¥å', value: 'mes-work-order' }, |
| | | { label: 'MES æè¡¨', value: 'mes-metering' }, |
| | | { label: 'SRM æå¡å', value: 'srm-service' }, |
| | | ], |
| | | placeholder: 'è¯·éæ©ç®æ 模å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'bizNo', |
| | | label: 'ä¸å¡åå·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥ä¸å¡åå·', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'operatorName', |
| | | label: 'æä½äºº', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥æä½äººå§å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'operateTime', |
| | | label: 'æä½æ¶é´', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | format: 'YYYY-MM-DD HH:mm:ss', |
| | | showTime: true, |
| | | valueFormat: 'YYYY-MM-DD HH:mm:ss', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | | formItemClass: 'col-span-2', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å¤æ³¨', |
| | | rows: 2, |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { CrmContractCommandApi } from '#/api/crm/contract-command'; |
| | | |
| | | import { ref } from 'vue'; |
| | | |
| | | import { useVbenForm, useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { |
| | | createContractCommand, |
| | | updateContractCommand, |
| | | } from '#/api/crm/contract-command'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useFormSchema } from './command-form-data'; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | |
| | | const formData = ref<Partial<CrmContractCommandApi.ContractCommand>>(); |
| | | const getTitle = () => { |
| | | return formData.value?.id |
| | | ? $t('ui.actionTitle.edit', ['æä»¤']) |
| | | : $t('ui.actionTitle.create', ['æä»¤']); |
| | | }; |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | labelWidth: 110, |
| | | }, |
| | | wrapperClass: 'grid-cols-2', |
| | | layout: 'horizontal', |
| | | schema: [], |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | const data = |
| | | (await formApi.getValues()) as CrmContractCommandApi.ContractCommand; |
| | | if (formData.value?.id) { |
| | | data.id = formData.value.id; |
| | | } |
| | | try { |
| | | await (formData.value?.id |
| | | ? updateContractCommand(data) |
| | | : createContractCommand(data)); |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | return; |
| | | } |
| | | formApi.setState({ schema: useFormSchema(formApi) }); |
| | | await formApi.resetForm(); |
| | | const data = modalApi.getData() as null | { |
| | | command?: CrmContractCommandApi.ContractCommand; |
| | | contractNo?: string; |
| | | }; |
| | | if (data?.contractNo) { |
| | | await formApi.setFieldValue('contractNo', data.contractNo); |
| | | } |
| | | if (!data?.command?.id) { |
| | | return; |
| | | } |
| | | formData.value = data.command; |
| | | await formApi.setValues(formData.value as any); |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal :title="getTitle()" class="w-2/3"> |
| | | <Form class="mx-4" /> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { CrmContractCommandApi } from '#/api/crm/contract-command'; |
| | | |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | |
| | | /** ååæä»¤è¯¦æ
åè¡¨åæ®µ */ |
| | | export function useDetailListColumns(): VxeTableGridOptions<CrmContractCommandApi.ContractCommand>['columns'] { |
| | | return [ |
| | | { |
| | | field: 'commandType', |
| | | title: 'æä»¤ç±»å', |
| | | width: 120, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.CRM_COMMAND_TYPE }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'targetModule', |
| | | title: 'ç®æ 模å', |
| | | width: 130, |
| | | }, |
| | | { |
| | | field: 'bizNo', |
| | | title: 'ä¸å¡åå·', |
| | | minWidth: 140, |
| | | }, |
| | | { |
| | | field: 'operatorName', |
| | | title: 'æä½äºº', |
| | | width: 100, |
| | | }, |
| | | { |
| | | field: 'operateTime', |
| | | title: 'æä½æ¶é´', |
| | | minWidth: 160, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | field: 'status', |
| | | title: 'ç¶æ', |
| | | width: 100, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.CRM_COMMAND_STATUS }, |
| | | }, |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | width: 220, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <!-- ååæä»¤ä¸åå表ï¼ç¨äºãååã详æ
Tabï¼å±ç¤ºå¹¶ä¸å/æ§è¡/åæ¶ååæä»¤ --> |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { CrmContractCommandApi } from '#/api/crm/contract-command'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | cancelContractCommand, |
| | | deleteContractCommand, |
| | | executeContractCommand, |
| | | getContractCommandPage, |
| | | } from '#/api/crm/contract-command'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import CommandForm from './command-form.vue'; |
| | | import { useDetailListColumns } from './command-list-data'; |
| | | |
| | | const props = defineProps<{ |
| | | contractId?: number; // ååç¼å· |
| | | contractNo?: string; // åååå· |
| | | }>(); |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: CommandForm, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | /** å·æ°è¡¨æ ¼ */ |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** å建æä»¤ */ |
| | | function handleCreate() { |
| | | formModalApi |
| | | .setData({ contractNo: props.contractNo }) |
| | | .open(); |
| | | } |
| | | |
| | | /** ç¼è¾æä»¤ */ |
| | | function handleEdit(row: CrmContractCommandApi.ContractCommand) { |
| | | formModalApi.setData({ command: row }).open(); |
| | | } |
| | | |
| | | /** æ§è¡æä»¤ */ |
| | | async function handleExecute(row: CrmContractCommandApi.ContractCommand) { |
| | | const hideLoading = message.loading({ content: 'æä»¤æ§è¡ä¸...', duration: 0 }); |
| | | try { |
| | | await executeContractCommand(row.id!); |
| | | message.success('æä»¤æ§è¡å®æ'); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** åæ¶æä»¤ */ |
| | | async function handleCancel(row: CrmContractCommandApi.ContractCommand) { |
| | | const hideLoading = message.loading({ content: 'æä»¤åæ¶ä¸...', duration: 0 }); |
| | | try { |
| | | await cancelContractCommand(row.id!); |
| | | message.success('æä»¤å·²åæ¶'); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** å 餿令 */ |
| | | async function handleDelete(row: CrmContractCommandApi.ContractCommand) { |
| | | const hideLoading = message.loading({ |
| | | content: $t('ui.actionMessage.deleting', [row.bizNo ?? '']), |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await deleteContractCommand(row.id!); |
| | | message.success($t('ui.actionMessage.deleteSuccess', [row.bizNo ?? ''])); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | gridOptions: { |
| | | columns: useDetailListColumns(), |
| | | height: 400, |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }) => { |
| | | if (!props.contractId) { |
| | | return { list: [], total: 0 }; |
| | | } |
| | | return await getContractCommandPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | contractId: props.contractId, |
| | | }); |
| | | }, |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: false, |
| | | }, |
| | | } as VxeTableGridOptions<CrmContractCommandApi.ContractCommand>, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <div> |
| | | <FormModal @success="handleRefresh" /> |
| | | <Grid> |
| | | <template #toolbar-tools> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: 'ä¸åæä»¤', |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['crm:contract-command:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: 'æ§è¡', |
| | | type: 'link', |
| | | icon: ACTION_ICON.AUDIT, |
| | | auth: ['crm:contract-command:update'], |
| | | ifShow: row.status === 0 || row.status === 10, |
| | | popConfirm: { |
| | | title: '确认æ§è¡è¯¥æä»¤ï¼', |
| | | confirm: handleExecute.bind(null, row), |
| | | }, |
| | | }, |
| | | { |
| | | label: 'åæ¶', |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.CLOSE, |
| | | auth: ['crm:contract-command:update'], |
| | | ifShow: row.status === 0 || row.status === 10, |
| | | popConfirm: { |
| | | title: 'ç¡®è®¤åæ¶è¯¥æä»¤ï¼', |
| | | confirm: handleCancel.bind(null, row), |
| | | }, |
| | | }, |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['crm:contract-command:update'], |
| | | ifShow: row.status === 0, |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['crm:contract-command:delete'], |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [ |
| | | row.bizNo ?? '', |
| | | ]), |
| | | confirm: handleDelete.bind(null, row), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </div> |
| | | </template> |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | import { useUserStore } from '@vben/stores'; |
| | | import { erpPriceInputFormatter, erpPriceMultiply } from '@vben/utils'; |
| | | |
| | |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'contractType', |
| | | label: 'ååç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.CRM_CONTRACT_TYPE), |
| | | placeholder: 'è¯·éæ©ååç±»å', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'voltageLevel', |
| | | label: 'çµåç级', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.CRM_VOLTAGE_LEVEL), |
| | | placeholder: 'è¯·éæ©çµåç级', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'electricityType', |
| | | label: 'ç¨çµç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.CRM_ELECTRICITY_TYPE), |
| | | placeholder: 'è¯·éæ©ç¨çµç±»å', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'contractCapacity', |
| | | label: 'åå容éï¼kVAï¼', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥åå容é', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'tariffMode', |
| | | label: 'çµä»·æ¨¡å¼', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.CRM_TARIFF_MODE), |
| | | placeholder: 'è¯·éæ©çµä»·æ¨¡å¼', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'meterMode', |
| | | label: 'è®¡éæ¹å¼', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.CRM_METER_MODE), |
| | | placeholder: 'è¯·éæ©è®¡éæ¹å¼', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'payCycle', |
| | | label: 'ç¼´è´¹å¨æï¼æï¼', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 1, |
| | | precision: 0, |
| | | placeholder: '请è¾å
¥ç¼´è´¹å¨æ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | |
| | | slots: { default: 'businessName' }, |
| | | }, |
| | | { |
| | | title: 'ååç±»å', |
| | | field: 'contractType', |
| | | minWidth: 110, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.CRM_CONTRACT_TYPE }, |
| | | }, |
| | | }, |
| | | { |
| | | title: 'çµåç级', |
| | | field: 'voltageLevel', |
| | | minWidth: 90, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.CRM_VOLTAGE_LEVEL }, |
| | | }, |
| | | }, |
| | | { |
| | | title: 'åå容é', |
| | | field: 'contractCapacity', |
| | | minWidth: 100, |
| | | }, |
| | | { |
| | | title: 'æä»¤æ°', |
| | | field: 'commandCount', |
| | | minWidth: 80, |
| | | }, |
| | | { |
| | | title: 'ååéé¢ï¼å
ï¼', |
| | | field: 'totalPrice', |
| | | minWidth: 140, |
| | |
| | | import Form from '../modules/form.vue'; |
| | | import { useDetailSchema } from './data'; |
| | | import ContractDetailsInfo from './modules/info.vue'; |
| | | import CommandDetailsList from '../components/command-list.vue'; |
| | | |
| | | const props = defineProps<{ id?: number }>(); |
| | | |
| | |
| | | <Tabs.TabPane tab="æä½æ¥å¿" key="6" :force-render="true"> |
| | | <OperateLog :log-list="logList" /> |
| | | </Tabs.TabPane> |
| | | <Tabs.TabPane tab="æä»¤ä¸å" key="7" :force-render="true"> |
| | | <CommandDetailsList |
| | | v-if="contractId" |
| | | :contract-id="contractId" |
| | | :contract-no="contract.no" |
| | | /> |
| | | </Tabs.TabPane> |
| | | </Tabs> |
| | | </Card> |
| | | </Page> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { CrmCustomerApi } from '#/api/crm/customer'; |
| | | import type { CrmCreditRatingApi } from '#/api/crm/credit-rating'; |
| | | |
| | | import { markRaw } from 'vue'; |
| | | |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | |
| | | import CrmCustomerSelect from '#/components/crm-customer-select.vue'; |
| | | |
| | | /** æ°å¢/ä¿®æ¹ä¿¡ç¨è¯çº§ */ |
| | | export function useFormSchema( |
| | | formApi?: VbenFormApi, |
| | | ): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | | component: 'Input', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'customerId', |
| | | label: '客æ·', |
| | | component: markRaw(CrmCustomerSelect), |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©å®¢æ·', |
| | | onChange: (item?: CrmCustomerApi.Customer) => { |
| | | formApi?.setFieldValue('customerName', item?.name); |
| | | }, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'customerName', |
| | | label: '客æ·åç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '客æ·åç§°', |
| | | readonly: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'level', |
| | | label: 'ä¿¡ç¨ç级', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.CRM_CREDIT_LEVEL), |
| | | placeholder: 'è¯·éæ©ä¿¡ç¨ç级', |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'score', |
| | | label: 'ä¿¡ç¨å', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: 'w-full', |
| | | min: 0, |
| | | max: 100, |
| | | precision: 0, |
| | | placeholder: '0-100', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'evalType', |
| | | label: 'è¯å®ç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: [ |
| | | { label: 'åè¯', value: 'INITIAL' }, |
| | | { label: 'å¤è¯', value: 'REVIEW' }, |
| | | { label: 'å¨æè°æ´', value: 'ADJUST' }, |
| | | ], |
| | | placeholder: 'è¯·éæ©è¯å®ç±»å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'evalReason', |
| | | label: 'è¯å®çç±', |
| | | component: 'Textarea', |
| | | formItemClass: 'col-span-2', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è¯å®çç±', |
| | | rows: 2, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'operateTime', |
| | | label: 'è¯å®æ¶é´', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | format: 'YYYY-MM-DD HH:mm:ss', |
| | | showTime: true, |
| | | valueFormat: 'YYYY-MM-DD HH:mm:ss', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'validUntil', |
| | | label: 'æææè³', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | format: 'YYYY-MM-DD', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'operatorName', |
| | | label: 'è¯å®äºº', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è¯å®äººå§å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | | formItemClass: 'col-span-2', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å¤æ³¨', |
| | | rows: 2, |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çæç´¢è¡¨å */ |
| | | export function useGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'level', |
| | | label: 'ä¿¡ç¨ç级', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.CRM_CREDIT_LEVEL), |
| | | placeholder: 'è¯·éæ©ä¿¡ç¨ç级', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'evalType', |
| | | label: 'è¯å®ç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: [ |
| | | { label: 'åè¯', value: 'INITIAL' }, |
| | | { label: 'å¤è¯', value: 'REVIEW' }, |
| | | { label: 'å¨æè°æ´', value: 'ADJUST' }, |
| | | ], |
| | | placeholder: 'è¯·éæ©è¯å®ç±»å', |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çåæ®µ */ |
| | | export function useGridColumns(): VxeTableGridOptions<CrmCreditRatingApi.CreditRating>['columns'] { |
| | | return [ |
| | | { field: 'customerName', title: '客æ·åç§°', minWidth: 180 }, |
| | | { |
| | | field: 'level', |
| | | title: 'ä¿¡ç¨ç级', |
| | | width: 100, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.CRM_CREDIT_LEVEL }, |
| | | }, |
| | | }, |
| | | { field: 'score', title: 'ä¿¡ç¨å', width: 90 }, |
| | | { |
| | | field: 'evalType', |
| | | title: 'è¯å®ç±»å', |
| | | width: 120, |
| | | slots: { default: 'evalType' }, |
| | | }, |
| | | { field: 'evalReason', title: 'è¯å®çç±', minWidth: 200, showOverflow: true }, |
| | | { field: 'operatorName', title: 'è¯å®äºº', width: 100 }, |
| | | { |
| | | field: 'operateTime', |
| | | title: 'è¯å®æ¶é´', |
| | | width: 170, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | field: 'validUntil', |
| | | title: 'æææè³', |
| | | width: 120, |
| | | formatter: 'formatDate', |
| | | }, |
| | | { |
| | | field: 'createTime', |
| | | title: 'å建æ¶é´', |
| | | width: 170, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | width: 160, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { CrmCreditRatingApi } from '#/api/crm/credit-rating'; |
| | | |
| | | import { Page, useVbenModal } from '@vben/common-ui'; |
| | | import { downloadFileFromBlobPart } from '@vben/utils'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | deleteCreditRating, |
| | | exportCreditRating, |
| | | getCreditRatingPage, |
| | | } from '#/api/crm/credit-rating'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | /** å·æ°è¡¨æ ¼ */ |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** 导åºè¡¨æ ¼ */ |
| | | async function handleExport() { |
| | | const formValues = await gridApi.formApi.getValues(); |
| | | const data = await exportCreditRating(formValues); |
| | | downloadFileFromBlobPart({ fileName: '客æ·ä¿¡ç¨è¯çº§.xls', source: data }); |
| | | } |
| | | |
| | | /** æ°å¢ */ |
| | | function handleCreate() { |
| | | formModalApi.setData(null).open(); |
| | | } |
| | | |
| | | /** ç¼è¾ */ |
| | | function handleEdit(row: CrmCreditRatingApi.CreditRating) { |
| | | formModalApi.setData({ creditRating: row }).open(); |
| | | } |
| | | |
| | | /** å é¤ */ |
| | | async function handleDelete(row: CrmCreditRatingApi.CreditRating) { |
| | | const hideLoading = message.loading({ |
| | | content: $t('ui.actionMessage.deleting', [row.customerName ?? '']), |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await deleteCreditRating(row.id!); |
| | | message.success( |
| | | $t('ui.actionMessage.deleteSuccess', [row.customerName ?? '']), |
| | | ); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useGridColumns(), |
| | | height: 'auto', |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => |
| | | await getCreditRatingPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }), |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<CrmCreditRatingApi.CreditRating>, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <FormModal @success="handleRefresh" /> |
| | | <Grid table-title="客æ·ä¿¡ç¨è¯çº§å表"> |
| | | <template #toolbar-tools> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('ui.actionTitle.create', ['ä¿¡ç¨è¯çº§']), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['crm:credit-rating:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | { |
| | | label: $t('ui.actionTitle.export'), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | | auth: ['crm:credit-rating:export'], |
| | | onClick: handleExport, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #evalType="{ row }"> |
| | | {{ |
| | | row.evalType === 'INITIAL' |
| | | ? 'åè¯' |
| | | : row.evalType === 'REVIEW' |
| | | ? 'å¤è¯' |
| | | : 'å¨æè°æ´' |
| | | }} |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['crm:credit-rating:update'], |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['crm:credit-rating:delete'], |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [ |
| | | row.customerName ?? '', |
| | | ]), |
| | | confirm: handleDelete.bind(null, row), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { CrmCreditRatingApi } from '#/api/crm/credit-rating'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenForm, useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { |
| | | createCreditRating, |
| | | getCreditRating, |
| | | updateCreditRating, |
| | | } from '#/api/crm/credit-rating'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useFormSchema } from '../data'; |
| | | |
| | | type CreditRatingFormModalData = { |
| | | creditRating?: Pick<CrmCreditRatingApi.CreditRating, 'id'>; |
| | | }; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formData = ref<Partial<CrmCreditRatingApi.CreditRating>>(); |
| | | const getTitle = computed(() => { |
| | | return formData.value?.id |
| | | ? $t('ui.actionTitle.edit', ['ä¿¡ç¨è¯çº§']) |
| | | : $t('ui.actionTitle.create', ['ä¿¡ç¨è¯çº§']); |
| | | }); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | labelWidth: 110, |
| | | }, |
| | | wrapperClass: 'grid-cols-2', |
| | | layout: 'horizontal', |
| | | schema: [], |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | const data = (await formApi.getValues()) as CrmCreditRatingApi.CreditRating; |
| | | if (formData.value?.id) { |
| | | data.id = formData.value.id; |
| | | } |
| | | try { |
| | | await (formData.value?.id |
| | | ? updateCreditRating(data) |
| | | : createCreditRating(data)); |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | return; |
| | | } |
| | | formApi.setState({ schema: useFormSchema(formApi) }); |
| | | await formApi.resetForm(); |
| | | const data = modalApi.getData() as null | CreditRatingFormModalData; |
| | | if (!data?.creditRating?.id) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | formData.value = await getCreditRating(data.creditRating.id); |
| | | if (formData.value) { |
| | | await formApi.setValues(formData.value as any); |
| | | } |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal :title="getTitle" class="w-3/5"> |
| | | <Form class="mx-4" /> |
| | | </Modal> |
| | | </template> |
| | |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'customerType', |
| | | label: '客æ·åç±»', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.CRM_CUSTOMER_TYPE), |
| | | placeholder: 'è¯·éæ©å®¢æ·åç±»', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'mobile', |
| | | label: 'ææº', |
| | | component: 'Input', |
| | |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'customerType', |
| | | label: '客æ·åç±»', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.CRM_CUSTOMER_TYPE), |
| | | placeholder: 'è¯·éæ©å®¢æ·åç±»', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'creditLevel', |
| | | label: 'ä¿¡ç¨ç级', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.CRM_CREDIT_LEVEL), |
| | | placeholder: 'è¯·éæ©ä¿¡ç¨ç级', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'createTime', |
| | | label: 'å建æ¶é´', |
| | | component: 'RangePicker', |
| | |
| | | }, |
| | | }, |
| | | { |
| | | field: 'customerType', |
| | | title: '客æ·åç±»', |
| | | minWidth: 100, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.CRM_CUSTOMER_TYPE }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'creditLevel', |
| | | title: 'ä¿¡ç¨ç级', |
| | | minWidth: 100, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.CRM_CREDIT_LEVEL }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'creditScore', |
| | | title: 'ä¿¡ç¨å', |
| | | minWidth: 90, |
| | | }, |
| | | { |
| | | field: 'overdueAmount', |
| | | title: 'æ¬ è´¹éé¢', |
| | | minWidth: 110, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | field: 'overdueCount', |
| | | title: 'æ¬ è´¹ç¬æ°', |
| | | minWidth: 90, |
| | | }, |
| | | { |
| | | field: 'mobile', |
| | | title: 'ææº', |
| | | minWidth: 120, |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { CrmCustomerApi } from '#/api/crm/customer'; |
| | | import type { CrmRefundApi } from '#/api/crm/refund'; |
| | | |
| | | import { markRaw } from 'vue'; |
| | | |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | |
| | | import CrmCustomerSelect from '#/components/crm-customer-select.vue'; |
| | | |
| | | /** æ°å¢/ä¿®æ¹éè´¹å */ |
| | | export function useFormSchema( |
| | | formApi?: VbenFormApi, |
| | | ): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | | component: 'Input', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'refundNo', |
| | | label: 'éè´¹åå·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: 'ä¸å¡«åèªå¨çæ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'customerId', |
| | | label: '客æ·', |
| | | component: markRaw(CrmCustomerSelect), |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©å®¢æ·', |
| | | onChange: (item?: CrmCustomerApi.Customer) => { |
| | | formApi?.setFieldValue('customerName', item?.name); |
| | | }, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'customerName', |
| | | label: '客æ·åç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '客æ·åç§°', |
| | | readonly: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'refundType', |
| | | label: 'é费类å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.CRM_REFUND_TYPE), |
| | | placeholder: 'è¯·éæ©é费类å', |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'refundAmount', |
| | | label: 'éè´¹éé¢', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: 'w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥éè´¹éé¢ï¼å
ï¼', |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'contractNo', |
| | | label: 'ååç¼å·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å
³èååç¼å·', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'applyUserName', |
| | | label: 'ç³è¯·äºº', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥ç³è¯·äººå§å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'applyTime', |
| | | label: 'ç³è¯·æ¶é´', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | format: 'YYYY-MM-DD HH:mm:ss', |
| | | showTime: true, |
| | | valueFormat: 'YYYY-MM-DD HH:mm:ss', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'refundReason', |
| | | label: 'éè´¹åå ', |
| | | component: 'Textarea', |
| | | formItemClass: 'col-span-2', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥éè´¹åå ', |
| | | rows: 2, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | | formItemClass: 'col-span-2', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å¤æ³¨', |
| | | rows: 2, |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çæç´¢è¡¨å */ |
| | | export function useGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'refundNo', |
| | | label: 'éè´¹åå·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | allowClear: true, |
| | | placeholder: '请è¾å
¥éè´¹åå·', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'refundType', |
| | | label: 'é费类å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.CRM_REFUND_TYPE), |
| | | placeholder: 'è¯·éæ©é费类å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'auditStatus', |
| | | label: '审æ¹ç¶æ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.CRM_AUDIT_STATUS, 'number'), |
| | | placeholder: 'è¯·éæ©å®¡æ¹ç¶æ', |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çåæ®µ */ |
| | | export function useGridColumns(): VxeTableGridOptions<CrmRefundApi.Refund>['columns'] { |
| | | return [ |
| | | { field: 'refundNo', title: 'éè´¹åå·', minWidth: 170 }, |
| | | { field: 'customerName', title: '客æ·åç§°', minWidth: 180 }, |
| | | { |
| | | field: 'refundType', |
| | | title: 'é费类å', |
| | | width: 110, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.CRM_REFUND_TYPE }, |
| | | }, |
| | | }, |
| | | { field: 'refundAmount', title: 'éè´¹éé¢', width: 120 }, |
| | | { field: 'contractNo', title: 'ååç¼å·', minWidth: 140 }, |
| | | { field: 'applyUserName', title: 'ç³è¯·äºº', width: 100 }, |
| | | { |
| | | field: 'applyTime', |
| | | title: 'ç³è¯·æ¶é´', |
| | | width: 170, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | field: 'auditStatus', |
| | | title: '审æ¹ç¶æ', |
| | | width: 110, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.CRM_AUDIT_STATUS }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'createTime', |
| | | title: 'å建æ¶é´', |
| | | width: 170, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | width: 200, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { CrmRefundApi } from '#/api/crm/refund'; |
| | | |
| | | import { Page, useVbenModal } from '@vben/common-ui'; |
| | | import { downloadFileFromBlobPart } from '@vben/utils'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | auditRefund, |
| | | deleteRefund, |
| | | exportRefund, |
| | | getRefundPage, |
| | | } from '#/api/crm/refund'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | /** å·æ°è¡¨æ ¼ */ |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** 导åºè¡¨æ ¼ */ |
| | | async function handleExport() { |
| | | const formValues = await gridApi.formApi.getValues(); |
| | | const data = await exportRefund(formValues); |
| | | downloadFileFromBlobPart({ fileName: 'éè´¹å.xls', source: data }); |
| | | } |
| | | |
| | | /** æ°å¢ */ |
| | | function handleCreate() { |
| | | formModalApi.setData(null).open(); |
| | | } |
| | | |
| | | /** ç¼è¾ */ |
| | | function handleEdit(row: CrmRefundApi.Refund) { |
| | | formModalApi.setData({ refund: row }).open(); |
| | | } |
| | | |
| | | /** å é¤ */ |
| | | async function handleDelete(row: CrmRefundApi.Refund) { |
| | | const hideLoading = message.loading({ |
| | | content: $t('ui.actionMessage.deleting', [row.refundNo ?? '']), |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await deleteRefund(row.id!); |
| | | message.success($t('ui.actionMessage.deleteSuccess', [row.refundNo ?? ''])); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** 审æ¹ï¼éè¿/驳åï¼ */ |
| | | async function handleAudit(row: CrmRefundApi.Refund, pass: boolean) { |
| | | const hideLoading = message.loading({ |
| | | content: pass ? '审æ¹éè¿ä¸...' : '审æ¹é©³åä¸...', |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await auditRefund({ id: row.id!, auditStatus: pass ? 20 : 30 }); |
| | | message.success(pass ? '审æ¹éè¿' : '审æ¹é©³å'); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useGridColumns(), |
| | | height: 'auto', |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => |
| | | await getRefundPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }), |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<CrmRefundApi.Refund>, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <FormModal @success="handleRefresh" /> |
| | | <Grid table-title="éè´¹åå表"> |
| | | <template #toolbar-tools> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('ui.actionTitle.create', ['éè´¹å']), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['crm:refund:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | { |
| | | label: $t('ui.actionTitle.export'), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | | auth: ['crm:refund:export'], |
| | | onClick: handleExport, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: 'éè¿', |
| | | type: 'link', |
| | | icon: ACTION_ICON.AUDIT, |
| | | auth: ['crm:refund:update'], |
| | | ifShow: row.auditStatus === 0 || row.auditStatus === 10, |
| | | popConfirm: { |
| | | title: '确认审æ¹éè¿è¯¥éè´¹åï¼', |
| | | confirm: handleAudit.bind(null, row, true), |
| | | }, |
| | | }, |
| | | { |
| | | label: '驳å', |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.AUDIT, |
| | | auth: ['crm:refund:update'], |
| | | ifShow: row.auditStatus === 0 || row.auditStatus === 10, |
| | | popConfirm: { |
| | | title: '确认驳å该éè´¹åï¼', |
| | | confirm: handleAudit.bind(null, row, false), |
| | | }, |
| | | }, |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['crm:refund:update'], |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['crm:refund:delete'], |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [ |
| | | row.refundNo ?? '', |
| | | ]), |
| | | confirm: handleDelete.bind(null, row), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { CrmRefundApi } from '#/api/crm/refund'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenForm, useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { |
| | | createRefund, |
| | | getRefund, |
| | | updateRefund, |
| | | } from '#/api/crm/refund'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useFormSchema } from '../data'; |
| | | |
| | | type RefundFormModalData = { |
| | | refund?: Pick<CrmRefundApi.Refund, 'id'>; |
| | | }; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formData = ref<Partial<CrmRefundApi.Refund>>(); |
| | | const getTitle = computed(() => { |
| | | return formData.value?.id |
| | | ? $t('ui.actionTitle.edit', ['éè´¹å']) |
| | | : $t('ui.actionTitle.create', ['éè´¹å']); |
| | | }); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | labelWidth: 110, |
| | | }, |
| | | wrapperClass: 'grid-cols-2', |
| | | layout: 'horizontal', |
| | | schema: [], |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | const data = (await formApi.getValues()) as CrmRefundApi.Refund; |
| | | if (formData.value?.id) { |
| | | data.id = formData.value.id; |
| | | } |
| | | try { |
| | | await (formData.value?.id ? updateRefund(data) : createRefund(data)); |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | return; |
| | | } |
| | | formApi.setState({ schema: useFormSchema(formApi) }); |
| | | await formApi.resetForm(); |
| | | const data = modalApi.getData() as null | RefundFormModalData; |
| | | if (!data?.refund?.id) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | formData.value = await getRefund(data.refund.id); |
| | | if (formData.value) { |
| | | await formApi.setValues(formData.value as any); |
| | | } |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal :title="getTitle" class="w-3/5"> |
| | | <Form class="mx-4" /> |
| | | </Modal> |
| | | </template> |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | |
| | | import { erpPriceMultiply } from '#/packages/utils/src'; |
| | | |
| | | import { z } from '#/adapter/form'; |
| | |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'quotationType', |
| | | label: 'æ¥ä»·ç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.CRM_QUOTATION_TYPE), |
| | | placeholder: 'è¯·éæ©æ¥ä»·ç±»å', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'capacity', |
| | | label: 'åå容éï¼kVAï¼', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥åå容é', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'maxDemand', |
| | | label: 'æå¤§ééï¼kWï¼', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥æå¤§éé', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'unitPrice', |
| | | label: 'çµåº¦åä»·ï¼å
/kWhï¼', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 4, |
| | | placeholder: '请è¾å
¥çµåº¦åä»·', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'tariffMode', |
| | | label: 'çµä»·æ¨¡å¼', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.CRM_TARIFF_MODE), |
| | | placeholder: 'è¯·éæ©çµä»·æ¨¡å¼', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'powerFactorFee', |
| | | label: 'åè°çµè´¹ï¼å
ï¼', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥åè°çµè´¹', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'billingCycle', |
| | | label: 'ç»ç®å¨æï¼æï¼', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 1, |
| | | precision: 0, |
| | | placeholder: '请è¾å
¥ç»ç®å¨æ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | |
| | | fixed: 'left', |
| | | }, |
| | | { |
| | | field: 'quotationType', |
| | | title: 'æ¥ä»·ç±»å', |
| | | minWidth: 100, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.CRM_QUOTATION_TYPE }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'customerName', |
| | | title: '客æ·åç§°', |
| | | minWidth: 120, |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | |
| | | import { getSupplierSimpleList } from '#/api/srm/supplier'; |
| | | import { getRangePickerDefaultProps } from '#/utils'; |
| | | |
| | | /** 表åç±»å */ |
| | | export type FormType = 'create' | 'detail' | 'edit'; |
| | | |
| | | /** ç¶æå¸¸é */ |
| | | export const PURCHASE_PLAN_STATUS = { |
| | | DRAFT: 0, // æªæäº¤ï¼èç¨¿ï¼ |
| | | PROCESSING: 10, // 审æ¹ä¸ |
| | | APPROVED: 20, // å®¡æ ¸éè¿ |
| | | REJECTED: 30, // å®¡æ ¸ä¸éè¿ |
| | | CANCELLED: 40, // 已忶 |
| | | }; |
| | | |
| | | /** éæ±æ¥æºå¸¸é */ |
| | | export const DEMAND_SOURCE = { |
| | | STOCK_ALERT: 1, // åºåé¢è¦ |
| | | PLAN: 2, // è¿ç»´/ç产计å |
| | | }; |
| | | |
| | | /** 表åçé
置项 */ |
| | | export function useFormSchema(formType: FormType): VbenFormSchema[] { |
| | | const isReadonly = formType === 'detail'; |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | | component: 'Input', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'no', |
| | | label: '计ååå·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: 'ç³»ç»èªå¨çæ', |
| | | disabled: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'name', |
| | | label: '计ååç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è®¡ååç§°', |
| | | disabled: isReadonly, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'planDate', |
| | | label: 'è®¡åæ¥æ', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | placeholder: 'éæ©è®¡åæ¥æ', |
| | | showTime: true, |
| | | format: 'YYYY-MM-DD HH:mm:ss', |
| | | valueFormat: 'YYYY-MM-DD HH:mm:ss', |
| | | disabled: isReadonly, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'demandSource', |
| | | label: 'éæ±æ¥æº', |
| | | component: 'Select', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©éæ±æ¥æº', |
| | | allowClear: true, |
| | | options: getDictOptions('erp_purchase_plan_demand_source', 'number'), |
| | | disabled: isReadonly, |
| | | }, |
| | | }, |
| | | { |
| | | label: 'ä¾åºå', |
| | | fieldName: 'supplierId', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©ä¾åºå', |
| | | allowClear: true, |
| | | showSearch: true, |
| | | api: getSupplierSimpleList, |
| | | labelField: 'name', |
| | | valueField: 'id', |
| | | disabled: isReadonly, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å¤æ³¨', |
| | | autoSize: { minRows: 1, maxRows: 1 }, |
| | | disabled: isReadonly, |
| | | }, |
| | | formItemClass: 'col-span-2', |
| | | }, |
| | | { |
| | | fieldName: 'items', |
| | | label: '计åæç»', |
| | | component: 'Input', |
| | | formItemClass: 'col-span-3', |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çæç´¢è¡¨å */ |
| | | export function useGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'no', |
| | | label: '计ååå·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è®¡ååå·', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'name', |
| | | label: '计ååç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è®¡ååç§°', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'demandSource', |
| | | label: 'éæ±æ¥æº', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions('erp_purchase_plan_demand_source', 'number'), |
| | | placeholder: 'è¯·éæ©éæ±æ¥æº', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'status', |
| | | label: 'ç¶æ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: [ |
| | | { label: 'æªæäº¤', value: PURCHASE_PLAN_STATUS.DRAFT }, |
| | | { label: '审æ¹ä¸', value: PURCHASE_PLAN_STATUS.PROCESSING }, |
| | | { label: 'å®¡æ ¸éè¿', value: PURCHASE_PLAN_STATUS.APPROVED }, |
| | | { label: 'å®¡æ ¸ä¸éè¿', value: PURCHASE_PLAN_STATUS.REJECTED }, |
| | | { label: '已忶', value: PURCHASE_PLAN_STATUS.CANCELLED }, |
| | | ], |
| | | placeholder: 'è¯·éæ©ç¶æ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'planDate', |
| | | label: 'è®¡åæ¥æ', |
| | | component: 'RangePicker', |
| | | componentProps: getRangePickerDefaultProps(), |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çè¡¨æ ¼å */ |
| | | export function useGridColumns(): VxeTableGridOptions['columns'] { |
| | | return [ |
| | | { type: 'checkbox', width: 50 }, |
| | | { type: 'seq', title: 'åºå·', width: 60 }, |
| | | { |
| | | field: 'no', |
| | | title: '计ååå·', |
| | | minWidth: 140, |
| | | }, |
| | | { |
| | | field: 'name', |
| | | title: '计ååç§°', |
| | | minWidth: 180, |
| | | }, |
| | | { |
| | | field: 'demandSourceName', |
| | | title: 'éæ±æ¥æº', |
| | | width: 110, |
| | | }, |
| | | { |
| | | field: 'planUserName', |
| | | title: 'ç¼å¶äºº', |
| | | width: 110, |
| | | }, |
| | | { |
| | | field: 'planDeptName', |
| | | title: 'ç¼å¶é¨é¨', |
| | | width: 120, |
| | | }, |
| | | { |
| | | field: 'supplierName', |
| | | title: 'ä¾åºå', |
| | | minWidth: 130, |
| | | }, |
| | | { |
| | | field: 'productNames', |
| | | title: '产å', |
| | | minWidth: 180, |
| | | }, |
| | | { |
| | | field: 'totalCount', |
| | | title: 'å计æ°é', |
| | | width: 100, |
| | | formatter: 'formatAmount3', |
| | | }, |
| | | { |
| | | field: 'planDate', |
| | | title: 'è®¡åæ¥æ', |
| | | width: 170, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | field: 'status', |
| | | title: 'ç¶æ', |
| | | width: 100, |
| | | slots: { default: 'status' }, |
| | | }, |
| | | { |
| | | field: 'createTime', |
| | | title: 'å建æ¶é´', |
| | | width: 170, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | field: 'action', |
| | | title: 'æä½', |
| | | width: 280, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { ErpPurchasePlanApi } from '#/api/erp/purchase/plan'; |
| | | |
| | | import { ref } from 'vue'; |
| | | import { useRouter } from 'vue-router'; |
| | | |
| | | import { confirm, Page, useVbenModal } from '@vben/common-ui'; |
| | | import { downloadFileFromBlobPart, isEmpty } from '@vben/utils'; |
| | | |
| | | import { message, Tag } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | deletePurchasePlan, |
| | | exportPurchasePlan, |
| | | generatePlanFromStockAlert, |
| | | generatePurchaseRequests, |
| | | getApproveProcessList, |
| | | getPurchasePlanPage, |
| | | } from '#/api/erp/purchase/plan'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | import ProcessSelectModal from './modules/process-select-modal.vue'; |
| | | |
| | | /** ERP éè´è®¡åå表 */ |
| | | defineOptions({ name: 'ErpPurchasePlan' }); |
| | | |
| | | const router = useRouter(); |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | const [ProcessModal, processModalApi] = useVbenModal({ |
| | | connectedComponent: ProcessSelectModal, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | /** å·æ°è¡¨æ ¼ */ |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** 导åºè¡¨æ ¼ */ |
| | | async function handleExport() { |
| | | const data = await exportPurchasePlan(await gridApi.formApi.getValues()); |
| | | downloadFileFromBlobPart({ fileName: 'éè´è®¡å.xls', source: data }); |
| | | } |
| | | |
| | | /** æ°å¢éè´è®¡å */ |
| | | function handleCreate() { |
| | | formModalApi.setData({ formType: 'create' }).open(); |
| | | } |
| | | |
| | | /** ç¼è¾éè´è®¡å */ |
| | | function handleEdit(row: ErpPurchasePlanApi.PurchasePlan) { |
| | | formModalApi.setData({ formType: 'edit', id: row.id }).open(); |
| | | } |
| | | |
| | | /** å é¤éè´è®¡å */ |
| | | async function handleDelete(ids: number[]) { |
| | | const hideLoading = message.loading({ |
| | | content: $t('ui.actionMessage.deleting'), |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await deletePurchasePlan(ids); |
| | | message.success($t('ui.actionMessage.deleteSuccess')); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** åºåé¢è¦çæéè´è®¡å */ |
| | | async function handleGenerateFromStockAlert() { |
| | | const hideLoading = message.loading({ |
| | | content: 'æ£å¨æ ¹æ®åºåé¢è¦çæéè´è®¡å...', |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | const planId = await generatePlanFromStockAlert({}); |
| | | hideLoading(); |
| | | message.success(`å·²çæéè´è®¡åï¼ç¼å· ${planId}ï¼ï¼è¯·æ ¸å¯¹æç»åæäº¤å®¡æ¹`); |
| | | handleRefresh(); |
| | | } catch { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** æäº¤å®¡æ¹ - å
è·åæµç¨å表 */ |
| | | async function handleSubmit(row: ErpPurchasePlanApi.PurchasePlan) { |
| | | const hideLoading = message.loading({ |
| | | content: 'è·åå®¡æ¹æµç¨...', |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | const processList = await getApproveProcessList(row.id!); |
| | | hideLoading(); |
| | | if (!processList || processList.length === 0) { |
| | | message.warning('ææ å¯ç¨å®¡æ¹æµç¨ï¼è¯·å
é
ç½® BPM æµç¨'); |
| | | return; |
| | | } |
| | | processModalApi.setData({ id: row.id, processList }).open(); |
| | | } catch { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** çæéè´ç³è¯· */ |
| | | function handleGenerateRequests(row: ErpPurchasePlanApi.PurchasePlan) { |
| | | confirm({ |
| | | content: `ç¡®è®¤æ ¹æ®è®¡åã${row.name}ãçæéè´ç³è¯·ï¼`, |
| | | }).then(() => { |
| | | const hideLoading = message.loading({ |
| | | content: 'æ£å¨çæéè´ç³è¯·...', |
| | | duration: 0, |
| | | }); |
| | | generatePurchaseRequests(row.id!) |
| | | .then((requestIds) => { |
| | | message.success(`å·²çæéè´ç³è¯·ï¼ç¼å· ${requestIds.join(', ')}ï¼`); |
| | | handleRefresh(); |
| | | }) |
| | | .finally(() => { |
| | | hideLoading(); |
| | | }); |
| | | }); |
| | | } |
| | | |
| | | const checkedIds = ref<number[]>([]); |
| | | function handleRowCheckboxChange({ |
| | | records, |
| | | }: { |
| | | records: ErpPurchasePlanApi.PurchasePlan[]; |
| | | }) { |
| | | checkedIds.value = records.map((item) => item.id!); |
| | | } |
| | | |
| | | /** æ¥ç详æ
*/ |
| | | function handleDetail(row: ErpPurchasePlanApi.PurchasePlan) { |
| | | formModalApi.setData({ formType: 'detail', id: row.id }).open(); |
| | | } |
| | | |
| | | /** æ¥ç审æ¹è¯¦æ
*/ |
| | | function handleViewProcess(row: ErpPurchasePlanApi.PurchasePlan) { |
| | | if (!row.processInstanceId) { |
| | | message.warning('该计åå°æªæäº¤å®¡æ¹'); |
| | | return; |
| | | } |
| | | router.push({ name: 'BpmProcessInstanceDetail', query: { id: row.processInstanceId } }); |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useGridColumns(), |
| | | height: 'auto', |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => { |
| | | return await getPurchasePlanPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }); |
| | | }, |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<ErpPurchasePlanApi.PurchasePlan>, |
| | | gridEvents: { |
| | | checkboxAll: handleRowCheckboxChange, |
| | | checkboxChange: handleRowCheckboxChange, |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <FormModal @success="handleRefresh" /> |
| | | <ProcessModal @success="handleRefresh" /> |
| | | <Grid table-title="éè´è®¡åå表"> |
| | | <template #toolbar-tools> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('ui.actionTitle.create', ['éè´è®¡å']), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['erp:purchase-plan:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | { |
| | | label: 'åºåé¢è¦çæ', |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['erp:purchase-plan:create'], |
| | | popConfirm: { |
| | | title: 'æ ¹æ®å®å
¨åºå缺éèªå¨çæè稿éè´è®¡åï¼', |
| | | confirm: handleGenerateFromStockAlert, |
| | | }, |
| | | }, |
| | | { |
| | | label: $t('ui.actionTitle.export'), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | | auth: ['erp:purchase-plan:export'], |
| | | onClick: handleExport, |
| | | }, |
| | | { |
| | | label: 'æ¹éå é¤', |
| | | type: 'primary', |
| | | danger: true, |
| | | disabled: isEmpty(checkedIds), |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['erp:purchase-plan:delete'], |
| | | popConfirm: { |
| | | title: `æ¯å¦å 餿é䏿°æ®ï¼`, |
| | | confirm: handleDelete.bind(null, checkedIds), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #status="{ row }"> |
| | | <Tag v-if="row.status === 0" color="default">æªæäº¤</Tag> |
| | | <Tag v-else-if="row.status === 10" color="processing">审æ¹ä¸</Tag> |
| | | <Tag v-else-if="row.status === 20" color="success">å®¡æ ¸éè¿</Tag> |
| | | <Tag v-else-if="row.status === 30" color="error">å®¡æ ¸ä¸éè¿</Tag> |
| | | <Tag v-else-if="row.status === 40" color="warning">已忶</Tag> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['erp:purchase-plan:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['erp:purchase-plan:update'], |
| | | ifShow: () => row.status === 0, |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: 'æäº¤', |
| | | type: 'link', |
| | | ifShow: () => row.status === 0 || row.status === 30, |
| | | onClick: handleSubmit.bind(null, row), |
| | | }, |
| | | { |
| | | label: 'çæç³è¯·', |
| | | type: 'link', |
| | | auth: ['erp:purchase-plan:generate-request'], |
| | | ifShow: () => row.status === 20 && !row.generatedFlag, |
| | | onClick: handleGenerateRequests.bind(null, row), |
| | | }, |
| | | { |
| | | label: 'æ¥ç审æ¹', |
| | | type: 'link', |
| | | ifShow: () => row.status !== 0, |
| | | onClick: handleViewProcess.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['erp:purchase-plan:delete'], |
| | | ifShow: () => row.status === 0, |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [row.no]), |
| | | confirm: handleDelete.bind(null, [row.id!]), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { ErpPurchasePlanApi } from '#/api/erp/purchase/plan'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { Button, DatePicker, Input, InputNumber, message } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { |
| | | createPurchasePlan, |
| | | getPurchasePlan, |
| | | updatePurchasePlan, |
| | | } from '#/api/erp/purchase/plan'; |
| | | import { MdmItemSelect } from '#/views/basicData/mdm/components'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import type { FormType } from '../data'; |
| | | import { useFormSchema } from '../data'; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formData = ref<ErpPurchasePlanApi.PurchasePlan>(); |
| | | const formType = ref<FormType>('create'); |
| | | const items = ref<ErpPurchasePlanApi.PurchasePlanItem[]>([]); |
| | | |
| | | const getTitle = computed(() => { |
| | | if (formType.value === 'create') { |
| | | return $t('ui.actionTitle.create', ['éè´è®¡å']); |
| | | } else if (formType.value === 'edit') { |
| | | return $t('ui.actionTitle.edit', ['éè´è®¡å']); |
| | | } else { |
| | | return 'éè´è®¡å详æ
'; |
| | | } |
| | | }); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | labelWidth: 120, |
| | | }, |
| | | wrapperClass: 'grid-cols-3', |
| | | layout: 'vertical', |
| | | schema: useFormSchema(formType.value), |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | function handleAddItem() { |
| | | items.value.push({ |
| | | productId: undefined as unknown as number, |
| | | productName: '', |
| | | productUnitId: undefined as unknown as number, |
| | | productUnitName: '', |
| | | count: 1, |
| | | demandTime: undefined, |
| | | remark: '', |
| | | }); |
| | | } |
| | | |
| | | function handleRemoveItem(index: number) { |
| | | items.value.splice(index, 1); |
| | | } |
| | | |
| | | function handleItemSelect(index: number, item: any) { |
| | | const row = items.value[index]; |
| | | if (!row) { |
| | | return; |
| | | } |
| | | row.productId = item?.id; |
| | | row.productName = item?.name; |
| | | row.productUnitId = item?.unitMeasureId; |
| | | row.productUnitName = item?.unitMeasureName; |
| | | } |
| | | |
| | | /** åå»ºææ´æ°éè´è®¡å */ |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | if (!items.value.length) { |
| | | message.error('请è³å°æ·»å 䏿¡è®¡åæç»'); |
| | | return; |
| | | } |
| | | if (items.value.some((item) => !item.productId || !item.count)) { |
| | | message.error('请å®å计åæç»ç产å䏿°é'); |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | const data = |
| | | (await formApi.getValues()) as ErpPurchasePlanApi.PurchasePlan; |
| | | data.items = items.value.map((item) => ({ |
| | | productId: item.productId, |
| | | productUnitId: item.productUnitId, |
| | | count: item.count, |
| | | demandTime: item.demandTime, |
| | | remark: item.remark, |
| | | })); |
| | | try { |
| | | await (formType.value === 'create' |
| | | ? createPurchasePlan(data) |
| | | : updatePurchasePlan(data)); |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | items.value = []; |
| | | return; |
| | | } |
| | | const data = modalApi.getData<{ formType: FormType; id?: number }>(); |
| | | formType.value = data.formType; |
| | | formApi.setDisabled(formType.value === 'detail'); |
| | | formApi.updateSchema(useFormSchema(formType.value)); |
| | | if (!data || !data.id) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | formData.value = await getPurchasePlan(data.id); |
| | | await formApi.setValues(formData.value); |
| | | items.value = (formData.value.items ?? []).map((item) => ({ |
| | | ...item, |
| | | })); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal |
| | | :title="getTitle" |
| | | class="w-3/4" |
| | | :show-confirm-button="formType !== 'detail'" |
| | | > |
| | | <Form class="mx-3"> |
| | | <template #items> |
| | | <div class="mt-2"> |
| | | <div v-if="formType !== 'detail'" class="mb-2"> |
| | | <Button type="dashed" @click="handleAddItem">+ æ·»å æç»</Button> |
| | | </div> |
| | | <table class="w-full border-collapse border border-gray-200 text-sm"> |
| | | <thead> |
| | | <tr class="bg-gray-100"> |
| | | <th class="border border-gray-200 px-2 py-1 w-12">åºå·</th> |
| | | <th class="border border-gray-200 px-2 py-1">产å</th> |
| | | <th class="border border-gray-200 px-2 py-1 w-20">åä½</th> |
| | | <th class="border border-gray-200 px-2 py-1 w-32">æ°é</th> |
| | | <th class="border border-gray-200 px-2 py-1 w-40">éæ±æ¥æ</th> |
| | | <th class="border border-gray-200 px-2 py-1">夿³¨</th> |
| | | <th |
| | | v-if="formType !== 'detail'" |
| | | class="border border-gray-200 px-2 py-1 w-16" |
| | | > |
| | | æä½ |
| | | </th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr v-for="(item, index) in items" :key="index"> |
| | | <td class="border border-gray-200 px-2 py-1 text-center"> |
| | | {{ index + 1 }} |
| | | </td> |
| | | <td class="border border-gray-200 px-2 py-1"> |
| | | <MdmItemSelect |
| | | v-if="formType !== 'detail'" |
| | | :model-value="item.productId" |
| | | placeholder="è¯·éæ©äº§å" |
| | | @change="handleItemSelect(index, $event)" |
| | | /> |
| | | <span v-else>{{ item.productName }}</span> |
| | | </td> |
| | | <td class="border border-gray-200 px-2 py-1 text-center"> |
| | | {{ item.productUnitName || '-' }} |
| | | </td> |
| | | <td class="border border-gray-200 px-2 py-1"> |
| | | <InputNumber |
| | | v-if="formType !== 'detail'" |
| | | v-model:value="item.count" |
| | | class="!w-full" |
| | | :min="0.01" |
| | | :precision="2" |
| | | /> |
| | | <span v-else>{{ item.count }}</span> |
| | | </td> |
| | | <td class="border border-gray-200 px-2 py-1"> |
| | | <DatePicker |
| | | v-if="formType !== 'detail'" |
| | | v-model:value="item.demandTime" |
| | | class="!w-full" |
| | | value-format="YYYY-MM-DD" |
| | | /> |
| | | <span v-else>{{ item.demandTime || '-' }}</span> |
| | | </td> |
| | | <td class="border border-gray-200 px-2 py-1"> |
| | | <Input |
| | | v-if="formType !== 'detail'" |
| | | v-model:value="item.remark" |
| | | placeholder="夿³¨" |
| | | /> |
| | | <span v-else>{{ item.remark || '-' }}</span> |
| | | </td> |
| | | <td |
| | | v-if="formType !== 'detail'" |
| | | class="border border-gray-200 px-2 py-1 text-center" |
| | | > |
| | | <Button type="link" danger @click="handleRemoveItem(index)"> |
| | | å é¤ |
| | | </Button> |
| | | </td> |
| | | </tr> |
| | | <tr v-if="!items.length"> |
| | | <td |
| | | :colspan="formType === 'detail' ? 6 : 7" |
| | | class="border border-gray-200 px-2 py-4 text-center text-gray-400" |
| | | > |
| | | ææ æç»ï¼è¯·æ·»å |
| | | </td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | </template> |
| | | </Form> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message, Select } from 'ant-design-vue'; |
| | | |
| | | import { submitPurchasePlan } from '#/api/erp/purchase/plan'; |
| | | |
| | | interface ProcessDefinition { |
| | | id: string; |
| | | name: string; |
| | | version: number; |
| | | key: string; |
| | | } |
| | | |
| | | const emit = defineEmits(['success']); |
| | | |
| | | const planId = ref<number>(); |
| | | const processList = ref<ProcessDefinition[]>([]); |
| | | const selectedProcessKey = ref<string>(''); |
| | | |
| | | const processOptions = computed(() => { |
| | | return processList.value.map((p) => ({ |
| | | label: `${p.name} (V${p.version})`, |
| | | value: p.key, |
| | | })); |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | if (!selectedProcessKey.value) { |
| | | message.warning('è¯·éæ©å®¡æ¹æµç¨'); |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | await submitPurchasePlan(planId.value!, selectedProcessKey.value); |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success('æäº¤æå'); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | planId.value = undefined; |
| | | selectedProcessKey.value = ''; |
| | | processList.value = []; |
| | | return; |
| | | } |
| | | const data = modalApi.getData<{ id: number; processList: ProcessDefinition[] }>(); |
| | | if (!data) { |
| | | return; |
| | | } |
| | | planId.value = data.id; |
| | | processList.value = data.processList || []; |
| | | // é»è®¤éæ©ç¬¬ä¸ä¸ªæµç¨ |
| | | if (processList.value.length > 0) { |
| | | selectedProcessKey.value = processList.value[0]?.key ?? ''; |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal title="éæ©å®¡æ¹æµç¨" class="w-1/3"> |
| | | <div class="mb-4"> |
| | | <span class="mr-2">å®¡æ¹æµç¨ï¼</span> |
| | | <Select |
| | | v-model:value="selectedProcessKey" |
| | | :options="processOptions" |
| | | style="width: 200px" |
| | | placeholder="è¯·éæ©å®¡æ¹æµç¨" |
| | | /> |
| | | </div> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | |
| | | import { markRaw } from 'vue'; |
| | | |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | |
| | | import { HrmEmployeeSelect } from '#/views/hrm/employee/components'; |
| | | |
| | | /** 表åç±»å */ |
| | | export type FormType = 'create' | 'detail' | 'edit'; |
| | | |
| | | /** 表åçé
置项 */ |
| | | export function useFormSchema(formType: FormType): VbenFormSchema[] { |
| | | const isReadonly = formType === 'detail'; |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | | component: 'Input', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'employeeId', |
| | | label: 'åå·¥', |
| | | component: markRaw(HrmEmployeeSelect), |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©åå·¥', |
| | | disabled: isReadonly, |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'certType', |
| | | label: 'è¯ä¹¦ç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.HRM_CERTIFICATE_TYPE, 'number'), |
| | | placeholder: 'è¯·éæ©è¯ä¹¦ç±»å', |
| | | disabled: isReadonly, |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'certName', |
| | | label: 'è¯ä¹¦åç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è¯ä¹¦åç§°', |
| | | disabled: isReadonly, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'certNo', |
| | | label: 'è¯ä¹¦ç¼å·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è¯ä¹¦ç¼å·', |
| | | disabled: isReadonly, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'issueOrg', |
| | | label: 'åè¯æºæ', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥åè¯æºæ', |
| | | disabled: isReadonly, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'issueDate', |
| | | label: 'åè¯æ¥æ', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | placeholder: 'éæ©åè¯æ¥æ', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | disabled: isReadonly, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'expireDate', |
| | | label: 'æææè³', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | placeholder: 'éæ©æææè³', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | disabled: isReadonly, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å¤æ³¨', |
| | | autoSize: { minRows: 1, maxRows: 1 }, |
| | | disabled: isReadonly, |
| | | }, |
| | | formItemClass: 'col-span-2', |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çæç´¢è¡¨å */ |
| | | export function useGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'employeeId', |
| | | label: 'åå·¥', |
| | | component: markRaw(HrmEmployeeSelect), |
| | | componentProps: { |
| | | allowClear: true, |
| | | placeholder: 'è¯·éæ©åå·¥', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'certType', |
| | | label: 'è¯ä¹¦ç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.HRM_CERTIFICATE_TYPE, 'number'), |
| | | placeholder: 'è¯·éæ©è¯ä¹¦ç±»å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'certName', |
| | | label: 'è¯ä¹¦åç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è¯ä¹¦åç§°', |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çè¡¨æ ¼å */ |
| | | export function useGridColumns(): VxeTableGridOptions['columns'] { |
| | | return [ |
| | | { type: 'checkbox', width: 50 }, |
| | | { type: 'seq', title: 'åºå·', width: 60 }, |
| | | { |
| | | field: 'employeeName', |
| | | title: 'åå·¥', |
| | | minWidth: 120, |
| | | }, |
| | | { |
| | | field: 'certType', |
| | | title: 'è¯ä¹¦ç±»å', |
| | | width: 120, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.HRM_CERTIFICATE_TYPE }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'certName', |
| | | title: 'è¯ä¹¦åç§°', |
| | | minWidth: 200, |
| | | }, |
| | | { |
| | | field: 'certNo', |
| | | title: 'è¯ä¹¦ç¼å·', |
| | | minWidth: 130, |
| | | }, |
| | | { |
| | | field: 'issueOrg', |
| | | title: 'åè¯æºæ', |
| | | minWidth: 140, |
| | | }, |
| | | { |
| | | field: 'expireDate', |
| | | title: 'æææè³', |
| | | width: 120, |
| | | formatter: 'formatDate', |
| | | }, |
| | | { |
| | | field: 'expireStatus', |
| | | title: 'å°æç¶æ', |
| | | width: 100, |
| | | slots: { default: 'expireStatus' }, |
| | | }, |
| | | { |
| | | field: 'action', |
| | | title: 'æä½', |
| | | width: 200, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { HrmCertificateApi } from '#/api/hrm/certificate'; |
| | | |
| | | import { ref } from 'vue'; |
| | | |
| | | import { Page, useVbenModal } from '@vben/common-ui'; |
| | | import { isEmpty } from '@vben/utils'; |
| | | |
| | | import { message, Tag } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { deleteCertificate, getCertificatePage } from '#/api/hrm/certificate'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | |
| | | /** HRM è¯ä¹¦èµè´¨å表 */ |
| | | defineOptions({ name: 'HrmCertificate' }); |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | function handleCreate() { |
| | | formModalApi.setData({ formType: 'create' }).open(); |
| | | } |
| | | |
| | | function handleEdit(row: HrmCertificateApi.Certificate) { |
| | | formModalApi.setData({ formType: 'edit', id: row.id }).open(); |
| | | } |
| | | |
| | | function handleDetail(row: HrmCertificateApi.Certificate) { |
| | | formModalApi.setData({ formType: 'detail', id: row.id }).open(); |
| | | } |
| | | |
| | | async function handleDelete(ids: number[]) { |
| | | const hideLoading = message.loading({ |
| | | content: $t('ui.actionMessage.deleting'), |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await deleteCertificate(ids); |
| | | message.success($t('ui.actionMessage.deleteSuccess')); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | const checkedIds = ref<number[]>([]); |
| | | function handleRowCheckboxChange({ |
| | | records, |
| | | }: { |
| | | records: HrmCertificateApi.Certificate[]; |
| | | }) { |
| | | checkedIds.value = records.map((item) => item.id!); |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useGridColumns(), |
| | | height: 'auto', |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => { |
| | | return await getCertificatePage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }); |
| | | }, |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<HrmCertificateApi.Certificate>, |
| | | gridEvents: { |
| | | checkboxAll: handleRowCheckboxChange, |
| | | checkboxChange: handleRowCheckboxChange, |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <FormModal @success="handleRefresh" /> |
| | | <Grid table-title="è¯ä¹¦èµè´¨å表"> |
| | | <template #toolbar-tools> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('ui.actionTitle.create', ['è¯ä¹¦èµè´¨']), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['hrm:certificate:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | { |
| | | label: 'æ¹éå é¤', |
| | | type: 'primary', |
| | | danger: true, |
| | | disabled: isEmpty(checkedIds), |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['hrm:certificate:delete'], |
| | | popConfirm: { |
| | | title: `æ¯å¦å 餿é䏿°æ®ï¼`, |
| | | confirm: handleDelete.bind(null, checkedIds), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #expireStatus="{ row }"> |
| | | <Tag v-if="row.expireStatus === 0" color="success">ææ</Tag> |
| | | <Tag v-else-if="row.expireStatus === 1" color="warning">å³å°å°æ</Tag> |
| | | <Tag v-else-if="row.expireStatus === 2" color="error">å·²è¿æ</Tag> |
| | | <Tag v-else color="default">-</Tag> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['hrm:certificate:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['hrm:certificate:update'], |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['hrm:certificate:delete'], |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [row.certName]), |
| | | confirm: handleDelete.bind(null, [row.id!]), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { HrmCertificateApi } from '#/api/hrm/certificate'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { createCertificate, getCertificate, updateCertificate } from '#/api/hrm/certificate'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import type { FormType } from '../data'; |
| | | import { useFormSchema } from '../data'; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formData = ref<HrmCertificateApi.Certificate>(); |
| | | const formType = ref<FormType>('create'); |
| | | |
| | | const getTitle = computed(() => { |
| | | if (formType.value === 'create') { |
| | | return $t('ui.actionTitle.create', ['è¯ä¹¦èµè´¨']); |
| | | } else if (formType.value === 'edit') { |
| | | return $t('ui.actionTitle.edit', ['è¯ä¹¦èµè´¨']); |
| | | } else { |
| | | return 'è¯ä¹¦èµè´¨è¯¦æ
'; |
| | | } |
| | | }); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | labelWidth: 120, |
| | | }, |
| | | wrapperClass: 'grid-cols-3', |
| | | layout: 'vertical', |
| | | schema: useFormSchema(formType.value), |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | const data = |
| | | (await formApi.getValues()) as HrmCertificateApi.Certificate; |
| | | try { |
| | | await (formType.value === 'create' |
| | | ? createCertificate(data) |
| | | : updateCertificate(data)); |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | return; |
| | | } |
| | | const data = modalApi.getData<{ formType: FormType; id?: number }>(); |
| | | formType.value = data.formType; |
| | | formApi.setDisabled(formType.value === 'detail'); |
| | | formApi.updateSchema(useFormSchema(formType.value)); |
| | | if (!data || !data.id) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | formData.value = await getCertificate(data.id); |
| | | await formApi.setValues(formData.value); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal :title="getTitle" class="w-2/3" :show-confirm-button="formType !== 'detail'"> |
| | | <Form class="mx-3" /> |
| | | </Modal> |
| | | </template> |
| | |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'tbDeviceId', |
| | | label: 'æ°é设å¤ID', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥æ°é设å¤IDï¼å¤é¨æ°é tbDeviceIdï¼', |
| | | }, |
| | | help: '䏿°éç³»ç»è®¾å¤ID对åºï¼ç¨äºå
³è设å¤å®æ¶æ°æ®', |
| | | }, |
| | | { |
| | | fieldName: 'brand', |
| | | label: 'åç', |
| | | component: 'Input', |
| | |
| | | import CheckRecordList from "./check-record-list.vue"; |
| | | import MaintenRecordList from "./mainten-record-list.vue"; |
| | | import RepairList from "./repair-list.vue"; |
| | | import TelemetryList from "./telemetry-list.vue"; |
| | | |
| | | const emit = defineEmits(["success"]); |
| | | const formType = ref<FormType>("create"); // è¡¨åæ¨¡å¼ |
| | |
| | | tab="维修记å½"> |
| | | <RepairList :machinery-id="formData.id" /> |
| | | </Tabs.TabPane> |
| | | <Tabs.TabPane key="telemetry" |
| | | tab="æ°éæ°æ®" |
| | | :disabled="!formData.tbDeviceId"> |
| | | <TelemetryList :tb-device-id="formData.tbDeviceId" /> |
| | | </Tabs.TabPane> |
| | | </Tabs> |
| | | <template #prepend-footer> |
| | | <div class="flex flex-auto items-center"> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { MesDvStatisticsApi } from '#/api/mes/dv/statistics'; |
| | | |
| | | import { onMounted, ref } from 'vue'; |
| | | |
| | | import { Page } from '@vben/common-ui'; |
| | | |
| | | import { Card, Col, Row, Table, Tag } from 'ant-design-vue'; |
| | | |
| | | import { getDvStatisticsSummary } from '#/api/mes/dv/statistics'; |
| | | |
| | | defineOptions({ name: 'MesDvStatistics' }); |
| | | |
| | | const loading = ref(false); |
| | | const summary = ref<MesDvStatisticsApi.StatisticsSummary>({}); |
| | | |
| | | async function loadSummary() { |
| | | loading.value = true; |
| | | try { |
| | | summary.value = await getDvStatisticsSummary(); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | } |
| | | |
| | | onMounted(loadSummary); |
| | | </script> |
| | | |
| | | <template> |
| | | <Page> |
| | | <Row :gutter="16" class="mb-4"> |
| | | <Col :span="4"> |
| | | <Card :loading="loading"> |
| | | <div class="text-sm text-gray-500">è®¾å¤æ»æ°</div> |
| | | <div class="mt-2 text-2xl font-bold"> |
| | | {{ summary.totalMachinery ?? 0 }} |
| | | </div> |
| | | </Card> |
| | | </Col> |
| | | <Col :span="5"> |
| | | <Card :loading="loading"> |
| | | <div class="text-sm text-gray-500">çäº§ä¸ / åæº / ç»´æ¤ä¸</div> |
| | | <div class="mt-2 text-2xl font-bold"> |
| | | <span class="text-green-600">{{ summary.producingCount ?? 0 }}</span> |
| | | <span class="mx-1 text-gray-400">/</span> |
| | | <span class="text-red-600">{{ summary.stoppedCount ?? 0 }}</span> |
| | | <span class="mx-1 text-gray-400">/</span> |
| | | <span class="text-orange-600">{{ summary.maintainingCount ?? 0 }}</span> |
| | | </div> |
| | | </Card> |
| | | </Col> |
| | | <Col :span="5"> |
| | | <Card :loading="loading"> |
| | | <div class="text-sm text-gray-500">è®¾å¤æ
éç</div> |
| | | <div class="mt-2 text-2xl font-bold text-red-600"> |
| | | {{ (summary.faultRate ?? 0).toFixed(1) }}% |
| | | </div> |
| | | </Card> |
| | | </Col> |
| | | <Col :span="5"> |
| | | <Card :loading="loading"> |
| | | <div class="text-sm text-gray-500">ç»´ä¿®åï¼æ»æ° / å¾
å¤çï¼</div> |
| | | <div class="mt-2 text-2xl font-bold"> |
| | | {{ summary.totalRepair ?? 0 }} |
| | | <span class="text-sm text-gray-400"> |
| | | / {{ summary.processingRepair ?? 0 }} |
| | | </span> |
| | | </div> |
| | | </Card> |
| | | </Col> |
| | | <Col :span="5"> |
| | | <Card :loading="loading"> |
| | | <div class="text-sm text-gray-500">ä¿å
»è®°å½ï¼æ»æ° / 已宿ï¼</div> |
| | | <div class="mt-2 text-2xl font-bold"> |
| | | {{ summary.totalMainten ?? 0 }} |
| | | <span class="text-sm text-gray-400"> |
| | | / {{ summary.finishedMainten ?? 0 }} |
| | | </span> |
| | | </div> |
| | | </Card> |
| | | </Col> |
| | | </Row> |
| | | |
| | | <Card title="æè®¾å¤ç±»ååå¸" :loading="loading"> |
| | | <Table |
| | | row-key="machineryTypeId" |
| | | :data-source="summary.typeDistribution ?? []" |
| | | :pagination="false" |
| | | size="middle" |
| | | > |
| | | <Table.Column title="设å¤ç±»å" data-index="machineryTypeName"> |
| | | <template #default="{ record }"> |
| | | <Tag color="blue">{{ record.machineryTypeName || 'æªåç±»' }}</Tag> |
| | | </template> |
| | | </Table.Column> |
| | | <Table.Column title="è®¾å¤æ°é" data-index="count" align="right" /> |
| | | <Table.Column title="å æ¯" align="right"> |
| | | <template #default="{ record }"> |
| | | {{ |
| | | summary.totalMachinery |
| | | ? ((record.count / summary.totalMachinery) * 100).toFixed(1) |
| | | : 0 |
| | | }}% |
| | | </template> |
| | | </Table.Column> |
| | | </Table> |
| | | </Card> |
| | | </Page> |
| | | </template> |
| | |
| | | rules: z.number().default(0), |
| | | }, |
| | | { |
| | | fieldName: 'materialCategory', |
| | | label: 'ç©èµåç±»', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.MES_MATERIAL_CATEGORY, 'number'), |
| | | placeholder: 'è¯·éæ©ç©èµåç±»', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | |
| | | }, |
| | | }, |
| | | { |
| | | field: 'materialCategory', |
| | | title: 'ç©èµåç±»', |
| | | width: 120, |
| | | align: 'center', |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_MATERIAL_CATEGORY }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'safeStockFlag', |
| | | title: 'å®å
¨åºå', |
| | | width: 120, |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesPdCtcReelApi } from '#/api/mes/pd/ctc-reel'; |
| | | |
| | | import { markRaw } from 'vue'; |
| | | |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | |
| | | import { PdCtcSelect } from '#/views/mes/pd/ctc/components'; |
| | | |
| | | /** 表åç±»å */ |
| | | export type FormType = 'create' | 'detail' | 'update'; |
| | | |
| | | /** æ°å¢/ä¿®æ¹çå
·è®¡ç®è®°å½ */ |
| | | export function useFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | | component: 'Input', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'ctcId', |
| | | label: 'æ¢ä½å¯¼çº¿äº§å', |
| | | component: markRaw(PdCtcSelect), |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©æ¢ä½å¯¼çº¿äº§å', |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'reelType', |
| | | label: 'çå
፱Ȍ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.PRODUCT_REEL_TYPE, 'string'), |
| | | placeholder: 'è¯·éæ©çå
፱Ȍ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'reelOuterDiameter', |
| | | label: 'çå
·å¤å¾(mm)', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 0, |
| | | placeholder: '请è¾å
¥çå
·å¤å¾ d1', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'reelInnerDiameter', |
| | | label: 'çè¯å
å¾(mm)', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 0, |
| | | placeholder: '请è¾å
¥çè¯å
å¾ d2', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'reelWidth', |
| | | label: 'ç宽(mm)', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 0, |
| | | placeholder: '请è¾å
¥ç宽 l2', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'maxCapacity', |
| | | label: 'æå¤§å®¹é(km)', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 4, |
| | | placeholder: '请è¾å
¥æå¤§å®¹é', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'recommendedLength', |
| | | label: 'æ¨èæ¯çé¿åº¦(km)', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥æ¨èæ¯çé¿åº¦', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'netWeight', |
| | | label: 'åé(kg)', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥åé', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'grossWeight', |
| | | label: 'æ¯é(kg)', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥æ¯é', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'calcFormula', |
| | | label: '计ç®å
¬å¼', |
| | | component: 'Textarea', |
| | | formItemClass: 'col-span-3', |
| | | componentProps: { |
| | | placeholder: '((d1-60)+(d2+10))ÃINT(l2/(宽+1))Ã(d1-d2-70)/(é«+0.2)/1274', |
| | | rows: 2, |
| | | }, |
| | | help: '容é计ç®ï¼((d1-60)+(d2+10))ÃINT(l2/(CTC宽+1))Ã(d1-d2-70)/(CTCé«+0.2)/1274', |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | | formItemClass: 'col-span-3', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å¤æ³¨', |
| | | rows: 2, |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çæç´¢è¡¨å */ |
| | | export function useGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'ctcId', |
| | | label: 'æ¢ä½å¯¼çº¿äº§å', |
| | | component: markRaw(PdCtcSelect), |
| | | componentProps: { |
| | | allowClear: true, |
| | | placeholder: 'è¯·éæ©æ¢ä½å¯¼çº¿äº§å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'reelType', |
| | | label: 'çå
፱Ȍ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.PRODUCT_REEL_TYPE, 'string'), |
| | | placeholder: 'è¯·éæ©çå
፱Ȍ', |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çåæ®µ */ |
| | | export function useGridColumns(): VxeTableGridOptions<MesPdCtcReelApi.CtcReel>['columns'] { |
| | | return [ |
| | | { field: 'ctcOrderSpec', title: 'æ¢ä½å¯¼çº¿è§æ ¼', minWidth: 160 }, |
| | | { |
| | | field: 'reelType', |
| | | title: 'çå
፱Ȍ', |
| | | width: 100, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.PRODUCT_REEL_TYPE }, |
| | | }, |
| | | }, |
| | | { field: 'reelOuterDiameter', title: 'çå
·å¤å¾(mm)', width: 110 }, |
| | | { field: 'reelInnerDiameter', title: 'çè¯å
å¾(mm)', width: 110 }, |
| | | { field: 'reelWidth', title: 'ç宽(mm)', width: 100 }, |
| | | { field: 'maxCapacity', title: 'æå¤§å®¹é(km)', width: 120 }, |
| | | { field: 'recommendedLength', title: 'æ¨èé¿åº¦(km)', width: 120 }, |
| | | { field: 'netWeight', title: 'åé(kg)', width: 100 }, |
| | | { field: 'grossWeight', title: 'æ¯é(kg)', width: 100 }, |
| | | { |
| | | field: 'createTime', |
| | | title: 'å建æ¶é´', |
| | | width: 170, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | width: 220, |
| | | fixed: 'right', |
| | | slots: { |
| | | default: 'actions', |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesPdCtcReelApi } from '#/api/mes/pd/ctc-reel'; |
| | | |
| | | import { ref } from 'vue'; |
| | | |
| | | import { Page, useVbenModal } from '@vben/common-ui'; |
| | | import { $t } from '@vben/locales'; |
| | | |
| | | import { Button, message } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | deleteCtcReel, |
| | | getCtcReelPage, |
| | | } from '#/api/mes/pd/ctc-reel'; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | /** å·æ°è¡¨æ ¼ */ |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** æ°å¢ */ |
| | | function handleCreate() { |
| | | formModalApi.setData({ formType: 'create' }).open(); |
| | | } |
| | | |
| | | /** æ¥ç */ |
| | | function handleDetail(row: MesPdCtcReelApi.CtcReel) { |
| | | formModalApi.setData({ id: row.id, formType: 'detail' }).open(); |
| | | } |
| | | |
| | | /** ç¼è¾ */ |
| | | function handleEdit(row: MesPdCtcReelApi.CtcReel) { |
| | | formModalApi.setData({ id: row.id, formType: 'update' }).open(); |
| | | } |
| | | |
| | | /** å é¤ */ |
| | | async function handleDelete(row: MesPdCtcReelApi.CtcReel) { |
| | | const hideLoading = message.loading({ |
| | | content: $t('ui.actionMessage.deleting', [row.ctcOrderSpec ?? '']), |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await deleteCtcReel(row.id!); |
| | | message.success( |
| | | $t('ui.actionMessage.deleteSuccess', [row.ctcOrderSpec ?? '']), |
| | | ); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useGridColumns(), |
| | | height: 'auto', |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => |
| | | await getCtcReelPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }), |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<MesPdCtcReelApi.CtcReel>, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <FormModal @success="handleRefresh" /> |
| | | <Grid table-title="æ¢ä½å¯¼çº¿çå
·è®¡ç®å表"> |
| | | <template #toolbar-tools> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('ui.actionTitle.create', ['çå
·è®¡ç®']), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['mes:pd-ctc-reel:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #ctcOrderSpec="{ row }"> |
| | | <Button type="link" @click="handleDetail(row)"> |
| | | {{ row.ctcOrderSpec }} |
| | | </Button> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['mes:pd-ctc-reel:update'], |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['mes:pd-ctc-reel:delete'], |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [ |
| | | row.ctcOrderSpec ?? '', |
| | | ]), |
| | | confirm: handleDelete.bind(null, row), |
| | | }, |
| | | }, |
| | | { |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['mes:pd-ctc-reel:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { FormType } from '../data'; |
| | | |
| | | import type { MesPdCtcReelApi } from '#/api/mes/pd/ctc-reel'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | import { $t } from '@vben/locales'; |
| | | |
| | | import { Button, message } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { |
| | | createCtcReel, |
| | | getCtcReel, |
| | | updateCtcReel, |
| | | } from '#/api/mes/pd/ctc-reel'; |
| | | import { CalcModal } from '#/views/mes/pd/ctc/modules'; |
| | | |
| | | import { useFormSchema } from '../data'; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formType = ref<FormType>('create'); // è¡¨åæ¨¡å¼ |
| | | const formData = ref<MesPdCtcReelApi.CtcReel>(); |
| | | const isDetail = computed(() => formType.value === 'detail'); // æ¯å¦æ¥çæ¨¡å¼ |
| | | const getTitle = computed(() => { |
| | | if (formType.value === 'detail') { |
| | | return 'æ¥ççå
·è®¡ç®'; |
| | | } |
| | | return formType.value === 'update' ? 'ä¿®æ¹çå
·è®¡ç®' : 'æ°å¢çå
·è®¡ç®'; |
| | | }); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | formItemClass: 'col-span-1', |
| | | labelWidth: 130, |
| | | }, |
| | | wrapperClass: 'grid-cols-3', |
| | | layout: 'horizontal', |
| | | schema: [], |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [CalcModal, calcModalApi] = useVbenModal({ |
| | | connectedComponent: CalcModal, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | /** æå¼å®¹é计ç®å·¥å
· */ |
| | | function handleOpenCalc() { |
| | | calcModalApi.open(); |
| | | } |
| | | |
| | | /** åå¡«æå¤§å®¹éï¼kmï¼ */ |
| | | function handleFillReel(value: { capacityKm: number }) { |
| | | formApi.setFieldValue('maxCapacity', value.capacityKm); |
| | | } |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | if (isDetail.value) { |
| | | await modalApi.close(); |
| | | return; |
| | | } |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | // æäº¤è¡¨å |
| | | const data = (await formApi.getValues()) as MesPdCtcReelApi.CtcReel; |
| | | try { |
| | | await (data.id ? updateCtcReel(data) : createCtcReel(data)); |
| | | // å
³éå¹¶æç¤º |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | return; |
| | | } |
| | | // å è½½æ°æ® |
| | | const data = modalApi.getData<{ formType: FormType; id?: number }>(); |
| | | formType.value = data.formType; |
| | | formApi.setState({ schema: useFormSchema() }); |
| | | formApi.setDisabled(formType.value === 'detail'); |
| | | modalApi.setState({ showConfirmButton: formType.value !== 'detail' }); |
| | | if (!data?.id) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | formData.value = await getCtcReel(data.id); |
| | | // è®¾ç½®å° values |
| | | await formApi.setValues(formData.value); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal :title="getTitle" class="w-4/5"> |
| | | <Form class="mx-4" /> |
| | | <template #prepend-footer> |
| | | <Button |
| | | v-if="!isDetail" |
| | | type="default" |
| | | @click="handleOpenCalc" |
| | | > |
| | | 容éè®¡ç® |
| | | </Button> |
| | | </template> |
| | | <CalcModal @reel="handleFillReel" /> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | export { default as PdCtcSelect } from './select.vue'; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import { onMounted, ref } from 'vue'; |
| | | |
| | | import { Select } from 'ant-design-vue'; |
| | | |
| | | import { getCtcPage } from '#/api/mes/pd/ctc'; |
| | | |
| | | defineOptions({ name: 'PdCtcSelect', inheritAttrs: false }); |
| | | |
| | | const props = withDefaults( |
| | | defineProps<{ |
| | | allowClear?: boolean; |
| | | disabled?: boolean; |
| | | modelValue?: number; |
| | | placeholder?: string; |
| | | }>(), |
| | | { |
| | | allowClear: true, |
| | | disabled: false, |
| | | modelValue: undefined, |
| | | placeholder: 'è¯·éæ©æ¢ä½å¯¼çº¿äº§å', |
| | | }, |
| | | ); |
| | | |
| | | const emit = defineEmits<{ |
| | | 'update:modelValue': [value: number | undefined]; |
| | | }>(); |
| | | |
| | | const options = ref<{ label: string; value: number }[]>([]); |
| | | const searchText = ref(''); |
| | | |
| | | async function load() { |
| | | const data = await getCtcPage({ |
| | | pageNo: 1, |
| | | pageSize: 100, |
| | | orderSpec: searchText.value || undefined, |
| | | }); |
| | | options.value = (data.list ?? []).map((item) => ({ |
| | | label: `${item.orderSpec ?? ''}${item.itemName ? `ï¼${item.itemName}ï¼` : ''}`, |
| | | value: item.id!, |
| | | })); |
| | | } |
| | | |
| | | onMounted(load); |
| | | |
| | | function handleSearch(val: string) { |
| | | searchText.value = val; |
| | | load(); |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <Select |
| | | :model-value="modelValue" |
| | | :options="options" |
| | | :disabled="disabled" |
| | | :placeholder="placeholder" |
| | | :allow-clear="allowClear" |
| | | show-search |
| | | :filter-option="false" |
| | | @update:value="(v: number | undefined) => emit('update:modelValue', v)" |
| | | @search="handleSearch" |
| | | /> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesPdCtcApi } from '#/api/mes/pd/ctc'; |
| | | |
| | | import { markRaw } from 'vue'; |
| | | |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | |
| | | import { MdItemSelect } from '#/views/mes/md/item/components'; |
| | | |
| | | /** 表åç±»å */ |
| | | export type FormType = 'create' | 'detail' | 'update'; |
| | | |
| | | /** æ°å¢/ä¿®æ¹æ¢ä½å¯¼çº¿äº§åææ¯åæ° */ |
| | | export function useFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | | component: 'Input', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'itemId', |
| | | label: 'ç©æ', |
| | | component: markRaw(MdItemSelect), |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©æ¢ä½å¯¼çº¿ç©æ', |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'orderSpec', |
| | | label: 'è®¢è´§è§æ ¼', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è®¢è´§è§æ ¼', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'bareConductorSpec', |
| | | label: 'è£¸å¯¼çº¿è§æ ¼', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è£¸å¯¼çº¿è§æ ¼', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'enameledSpec', |
| | | label: 'æ¼å
çº¿è§æ ¼', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥æ¼å
çº¿è§æ ¼', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'transpositionSpec', |
| | | label: 'æ¢ä½è§æ ¼', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥æ¢ä½è§æ ¼', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'conductorType', |
| | | label: '导ä½ç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.PRODUCT_CONDUCTOR_TYPE, 'string'), |
| | | placeholder: 'è¯·éæ©å¯¼ä½ç±»å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'crossSection', |
| | | label: 'æªé¢ç§¯(mm²)', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥æªé¢ç§¯', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'outerDiameter', |
| | | label: 'å¤å¾(mm)', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥å¤å¾', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'resistance20c', |
| | | label: '20âç´æµçµé»(Ω/km)', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 6, |
| | | placeholder: '请è¾å
¥20âç´æµçµé»', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'wrappingAngle', |
| | | label: 'ç»å
è§åº¦(°)', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥ç»å
è§åº¦', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'insulationThickness', |
| | | label: 'ç»ç¼å度(mm)', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥ç»ç¼å度', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'ratedVoltage', |
| | | label: 'é¢å®çµå(kV)', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥é¢å®çµå', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'testVoltage', |
| | | label: 'è¯éªçµå(kV)', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è¯éªçµå', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'minBendingRadius', |
| | | label: 'æå°å¼¯æ²åå¾(mm)', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥æå°å¼¯æ²åå¾', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'weightPerKm', |
| | | label: 'æ¯å
¬ééé(kg/km)', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥æ¯å
¬ééé', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'standardCode', |
| | | label: 'æ§è¡æ å', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥æ§è¡æ å代å·', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | | formItemClass: 'col-span-3', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å¤æ³¨', |
| | | rows: 2, |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çæç´¢è¡¨å */ |
| | | export function useGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'itemId', |
| | | label: 'ç©æ', |
| | | component: markRaw(MdItemSelect), |
| | | componentProps: { |
| | | allowClear: true, |
| | | placeholder: 'è¯·éæ©æ¢ä½å¯¼çº¿ç©æ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'orderSpec', |
| | | label: 'è®¢è´§è§æ ¼', |
| | | component: 'Input', |
| | | componentProps: { |
| | | allowClear: true, |
| | | placeholder: '请è¾å
¥è®¢è´§è§æ ¼', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'conductorType', |
| | | label: '导ä½ç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.PRODUCT_CONDUCTOR_TYPE, 'string'), |
| | | placeholder: 'è¯·éæ©å¯¼ä½ç±»å', |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çåæ®µ */ |
| | | export function useGridColumns(): VxeTableGridOptions<MesPdCtcApi.Ctc>['columns'] { |
| | | return [ |
| | | { field: 'itemName', title: 'ç©æåç§°', minWidth: 140 }, |
| | | { field: 'itemCode', title: 'ç©æç¼ç ', minWidth: 120 }, |
| | | { field: 'orderSpec', title: 'è®¢è´§è§æ ¼', minWidth: 140 }, |
| | | { field: 'transpositionSpec', title: 'æ¢ä½è§æ ¼', minWidth: 120 }, |
| | | { |
| | | field: 'conductorType', |
| | | title: '导ä½ç±»å', |
| | | width: 100, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.PRODUCT_CONDUCTOR_TYPE }, |
| | | }, |
| | | }, |
| | | { field: 'crossSection', title: 'æªé¢ç§¯(mm²)', width: 110 }, |
| | | { field: 'outerDiameter', title: 'å¤å¾(mm)', width: 100 }, |
| | | { field: 'resistance20c', title: '20âçµé»(Ω/km)', width: 140 }, |
| | | { field: 'wrappingAngle', title: 'ç»å
è§åº¦(°)', width: 110 }, |
| | | { field: 'ratedVoltage', title: 'é¢å®çµå(kV)', width: 110 }, |
| | | { field: 'standardCode', title: 'æ§è¡æ å', minWidth: 140 }, |
| | | { |
| | | field: 'createTime', |
| | | title: 'å建æ¶é´', |
| | | width: 170, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | width: 220, |
| | | fixed: 'right', |
| | | slots: { |
| | | default: 'actions', |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesPdCtcApi } from '#/api/mes/pd/ctc'; |
| | | |
| | | import { ref } from 'vue'; |
| | | |
| | | import { Page, useVbenModal } from '@vben/common-ui'; |
| | | import { $t } from '@vben/locales'; |
| | | import { downloadFileFromBlobPart } from '@vben/utils'; |
| | | |
| | | import { Button, message } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | deleteCtc, |
| | | exportCtc, |
| | | getCtcPage, |
| | | } from '#/api/mes/pd/ctc'; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | /** å·æ°è¡¨æ ¼ */ |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** æ°å¢ */ |
| | | function handleCreate() { |
| | | formModalApi.setData({ formType: 'create' }).open(); |
| | | } |
| | | |
| | | /** æ¥ç */ |
| | | function handleDetail(row: MesPdCtcApi.Ctc) { |
| | | formModalApi.setData({ id: row.id, formType: 'detail' }).open(); |
| | | } |
| | | |
| | | /** ç¼è¾ */ |
| | | function handleEdit(row: MesPdCtcApi.Ctc) { |
| | | formModalApi.setData({ id: row.id, formType: 'update' }).open(); |
| | | } |
| | | |
| | | /** å é¤ */ |
| | | async function handleDelete(row: MesPdCtcApi.Ctc) { |
| | | const hideLoading = message.loading({ |
| | | content: $t('ui.actionMessage.deleting', [row.orderSpec ?? '']), |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await deleteCtc(row.id!); |
| | | message.success($t('ui.actionMessage.deleteSuccess', [row.orderSpec ?? ''])); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** å¯¼åº */ |
| | | async function handleExport() { |
| | | const data = await exportCtc(await gridApi.formApi.getValues()); |
| | | downloadFileFromBlobPart({ fileName: 'æ¢ä½å¯¼çº¿ææ¯åæ°.xls', source: data }); |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useGridColumns(), |
| | | height: 'auto', |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => |
| | | await getCtcPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }), |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<MesPdCtcApi.Ctc>, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <FormModal @success="handleRefresh" /> |
| | | <Grid table-title="æ¢ä½å¯¼çº¿ææ¯åæ°å表"> |
| | | <template #toolbar-tools> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('ui.actionTitle.create', ['æ¢ä½å¯¼çº¿ææ¯åæ°']), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['mes:pd-ctc:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | { |
| | | label: $t('ui.actionTitle.export'), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | | auth: ['mes:pd-ctc:export'], |
| | | onClick: handleExport, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #orderSpec="{ row }"> |
| | | <Button type="link" @click="handleDetail(row)"> |
| | | {{ row.orderSpec || row.itemName }} |
| | | </Button> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['mes:pd-ctc:update'], |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['mes:pd-ctc:delete'], |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [row.orderSpec ?? '']), |
| | | confirm: handleDelete.bind(null, row), |
| | | }, |
| | | }, |
| | | { |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['mes:pd-ctc:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import { reactive, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | import { $t } from '@vben/locales'; |
| | | |
| | | import { |
| | | Button, |
| | | Descriptions, |
| | | DescriptionsItem, |
| | | InputNumber, |
| | | message, |
| | | Select, |
| | | Tabs, |
| | | } from 'ant-design-vue'; |
| | | |
| | | import { |
| | | calcCtcAngle, |
| | | calcCtcResistance, |
| | | calcCtcReel, |
| | | } from '#/api/mes/pd/ctc'; |
| | | |
| | | const emit = defineEmits<{ |
| | | angle: [value: { wrappingAngle: number }]; |
| | | resistance: [value: { resistance20c: number }]; |
| | | reel: [value: { capacityKm: number }]; |
| | | }>(); |
| | | |
| | | /** ç»å
è§åº¦è®¡ç®è¡¨å */ |
| | | const angleForm = reactive<{ |
| | | conductorThickness?: number; |
| | | conductorWidth?: number; |
| | | cornerRadius?: number; |
| | | insulationThickness?: number; |
| | | tapeWidth?: number; |
| | | overlapWidth?: number; |
| | | }>({}); |
| | | const angleResult = ref<{ |
| | | circumference?: number; |
| | | wrappingAngle?: number; |
| | | wrappingPitch?: number; |
| | | }>(); |
| | | |
| | | /** ç´æµçµé»è®¡ç®è¡¨å */ |
| | | const resistanceForm = reactive<{ |
| | | conductorThickness?: number; |
| | | conductorWidth?: number; |
| | | temperature?: number; |
| | | material?: string; |
| | | }>({ temperature: 75, material: 'copper' }); |
| | | const resistanceResult = ref<{ |
| | | crossSection?: number; |
| | | resistance20cKm?: number; |
| | | resistanceAtTemp?: number; |
| | | resistanceAtTempKm?: number; |
| | | }>(); |
| | | |
| | | /** çå
·å®¹é计ç®è¡¨å */ |
| | | const reelForm = reactive<{ |
| | | reelOuterDiameter?: number; |
| | | reelInnerDiameter?: number; |
| | | reelWidth?: number; |
| | | ctcThickness?: number; |
| | | ctcWidth?: number; |
| | | }>({}); |
| | | const reelResult = ref<{ |
| | | capacityMeter?: number; |
| | | capacityKm?: number; |
| | | }>(); |
| | | |
| | | /** ç»å
è§åº¦è®¡ç® */ |
| | | async function handleCalcAngle() { |
| | | const data = await calcCtcAngle(angleForm); |
| | | angleResult.value = data; |
| | | } |
| | | |
| | | /** ç´æµçµé»è®¡ç® */ |
| | | async function handleCalcResistance() { |
| | | const data = await calcCtcResistance(resistanceForm); |
| | | resistanceResult.value = data; |
| | | } |
| | | |
| | | /** çå
·å®¹éè®¡ç® */ |
| | | async function handleCalcReel() { |
| | | const data = await calcCtcReel(reelForm); |
| | | reelResult.value = data; |
| | | } |
| | | |
| | | /** åå¡«ç»å
è§åº¦ */ |
| | | function handleFillAngle() { |
| | | if (angleResult.value?.wrappingAngle == null) { |
| | | message.warning('请å
æ§è¡ç»å
è§åº¦è®¡ç®'); |
| | | return; |
| | | } |
| | | emit('angle', { wrappingAngle: angleResult.value.wrappingAngle }); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } |
| | | |
| | | /** åå¡«ç´æµçµé» */ |
| | | function handleFillResistance() { |
| | | if (resistanceResult.value?.resistance20cKm == null) { |
| | | message.warning('请å
æ§è¡ç´æµçµé»è®¡ç®'); |
| | | return; |
| | | } |
| | | emit('resistance', { resistance20c: resistanceResult.value.resistance20cKm }); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } |
| | | |
| | | /** åå¡«çå
·å®¹é */ |
| | | function handleFillReel() { |
| | | if (reelResult.value?.capacityKm == null) { |
| | | message.warning('请å
æ§è¡çå
·å®¹é计ç®'); |
| | | return; |
| | | } |
| | | emit('reel', { capacityKm: reelResult.value.capacityKm }); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | angleResult.value = undefined; |
| | | resistanceResult.value = undefined; |
| | | reelResult.value = undefined; |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal title="æ¢ä½å¯¼çº¿è®¡ç®å·¥å
·" class="w-2/3"> |
| | | <Tabs> |
| | | <Tabs.TabPane key="angle" tab="ç»å
è§åº¦"> |
| | | <div class="grid grid-cols-3 gap-4"> |
| | | <div class="flex items-center gap-2"> |
| | | <span class="w-28 text-right">导ä½å度(mm)</span> |
| | | <InputNumber |
| | | v-model:value="angleForm.conductorThickness" |
| | | class="!flex-1" |
| | | :min="0" |
| | | :precision="2" |
| | | placeholder="å¦ 19.08" |
| | | /> |
| | | </div> |
| | | <div class="flex items-center gap-2"> |
| | | <span class="w-28 text-right">导ä½å®½åº¦(mm)</span> |
| | | <InputNumber |
| | | v-model:value="angleForm.conductorWidth" |
| | | class="!flex-1" |
| | | :min="0" |
| | | :precision="2" |
| | | placeholder="å¦ 12.6" |
| | | /> |
| | | </div> |
| | | <div class="flex items-center gap-2"> |
| | | <span class="w-28 text-right">åè§åå¾(mm)</span> |
| | | <InputNumber |
| | | v-model:value="angleForm.cornerRadius" |
| | | class="!flex-1" |
| | | :min="0" |
| | | :precision="2" |
| | | placeholder="å¦ 1" |
| | | /> |
| | | </div> |
| | | <div class="flex items-center gap-2"> |
| | | <span class="w-28 text-right">ç»ç¼å度(mm)</span> |
| | | <InputNumber |
| | | v-model:value="angleForm.insulationThickness" |
| | | class="!flex-1" |
| | | :min="0" |
| | | :precision="2" |
| | | placeholder="å¦ 0.75" |
| | | /> |
| | | </div> |
| | | <div class="flex items-center gap-2"> |
| | | <span class="w-28 text-right">纸带宽度(mm)</span> |
| | | <InputNumber |
| | | v-model:value="angleForm.tapeWidth" |
| | | class="!flex-1" |
| | | :min="0" |
| | | :precision="2" |
| | | placeholder="å¦ 22" |
| | | /> |
| | | </div> |
| | | <div class="flex items-center gap-2"> |
| | | <span class="w-28 text-right">éå 宽度(mm)</span> |
| | | <InputNumber |
| | | v-model:value="angleForm.overlapWidth" |
| | | class="!flex-1" |
| | | :min="0" |
| | | :precision="2" |
| | | placeholder="å¦ 2" |
| | | /> |
| | | </div> |
| | | </div> |
| | | <div class="mt-4 flex gap-2"> |
| | | <Button type="primary" @click="handleCalcAngle">计ç®</Button> |
| | | <Button @click="handleFillAngle">åå¡«ç»å
è§åº¦</Button> |
| | | </div> |
| | | <Descriptions v-if="angleResult" class="mt-4" :column="3" bordered> |
| | | <DescriptionsItem label="导线å¨é¿(mm)"> |
| | | {{ angleResult.circumference }} |
| | | </DescriptionsItem> |
| | | <DescriptionsItem label="ç»å
è§åº¦(°)"> |
| | | {{ angleResult.wrappingAngle }} |
| | | </DescriptionsItem> |
| | | <DescriptionsItem label="ç»å
èè·(mm)"> |
| | | {{ angleResult.wrappingPitch }} |
| | | </DescriptionsItem> |
| | | </Descriptions> |
| | | </Tabs.TabPane> |
| | | |
| | | <Tabs.TabPane key="resistance" tab="ç´æµçµé»"> |
| | | <div class="grid grid-cols-3 gap-4"> |
| | | <div class="flex items-center gap-2"> |
| | | <span class="w-28 text-right">导ä½å度(mm)</span> |
| | | <InputNumber |
| | | v-model:value="resistanceForm.conductorThickness" |
| | | class="!flex-1" |
| | | :min="0" |
| | | :precision="2" |
| | | placeholder="å¦ 1.27" |
| | | /> |
| | | </div> |
| | | <div class="flex items-center gap-2"> |
| | | <span class="w-28 text-right">导ä½å®½åº¦(mm)</span> |
| | | <InputNumber |
| | | v-model:value="resistanceForm.conductorWidth" |
| | | class="!flex-1" |
| | | :min="0" |
| | | :precision="2" |
| | | placeholder="å¦ 5.7" |
| | | /> |
| | | </div> |
| | | <div class="flex items-center gap-2"> |
| | | <span class="w-28 text-right">è®¡ç®æ¸©åº¦(â)</span> |
| | | <InputNumber |
| | | v-model:value="resistanceForm.temperature" |
| | | class="!flex-1" |
| | | :min="0" |
| | | :precision="0" |
| | | /> |
| | | </div> |
| | | <div class="flex items-center gap-2"> |
| | | <span class="w-28 text-right">å¯¼ä½æè´¨</span> |
| | | <Select |
| | | v-model:value="resistanceForm.material" |
| | | class="!flex-1" |
| | | :options="[ |
| | | { label: 'é', value: 'copper' }, |
| | | { label: 'é', value: 'aluminum' }, |
| | | ]" |
| | | /> |
| | | </div> |
| | | </div> |
| | | <div class="mt-4 flex gap-2"> |
| | | <Button type="primary" @click="handleCalcResistance">计ç®</Button> |
| | | <Button @click="handleFillResistance">åå¡«20âçµé»</Button> |
| | | </div> |
| | | <Descriptions v-if="resistanceResult" class="mt-4" :column="2" bordered> |
| | | <DescriptionsItem label="æªé¢ç§¯(mm²)"> |
| | | {{ resistanceResult.crossSection }} |
| | | </DescriptionsItem> |
| | | <DescriptionsItem label="20âçµé»(Ω/km)"> |
| | | {{ resistanceResult.resistance20cKm }} |
| | | </DescriptionsItem> |
| | | <DescriptionsItem label="è®¡ç®æ¸©åº¦çµé»(Ω/m)"> |
| | | {{ resistanceResult.resistanceAtTemp }} |
| | | </DescriptionsItem> |
| | | <DescriptionsItem label="è®¡ç®æ¸©åº¦çµé»(Ω/km)"> |
| | | {{ resistanceResult.resistanceAtTempKm }} |
| | | </DescriptionsItem> |
| | | </Descriptions> |
| | | </Tabs.TabPane> |
| | | |
| | | <Tabs.TabPane key="reel" tab="çå
·å®¹é"> |
| | | <div class="grid grid-cols-3 gap-4"> |
| | | <div class="flex items-center gap-2"> |
| | | <span class="w-28 text-right">çå
·å¤å¾ d1(mm)</span> |
| | | <InputNumber |
| | | v-model:value="reelForm.reelOuterDiameter" |
| | | class="!flex-1" |
| | | :min="0" |
| | | :precision="0" |
| | | placeholder="å¦ 1600" |
| | | /> |
| | | </div> |
| | | <div class="flex items-center gap-2"> |
| | | <span class="w-28 text-right">çè¯å
å¾ d2(mm)</span> |
| | | <InputNumber |
| | | v-model:value="reelForm.reelInnerDiameter" |
| | | class="!flex-1" |
| | | :min="0" |
| | | :precision="0" |
| | | placeholder="å¦ 1100" |
| | | /> |
| | | </div> |
| | | <div class="flex items-center gap-2"> |
| | | <span class="w-28 text-right">ç宽 l2(mm)</span> |
| | | <InputNumber |
| | | v-model:value="reelForm.reelWidth" |
| | | class="!flex-1" |
| | | :min="0" |
| | | :precision="0" |
| | | placeholder="å¦ 500" |
| | | /> |
| | | </div> |
| | | <div class="flex items-center gap-2"> |
| | | <span class="w-28 text-right">CTCé«åº¦(mm)</span> |
| | | <InputNumber |
| | | v-model:value="reelForm.ctcThickness" |
| | | class="!flex-1" |
| | | :min="0" |
| | | :precision="2" |
| | | placeholder="å¦ 19.08" |
| | | /> |
| | | </div> |
| | | <div class="flex items-center gap-2"> |
| | | <span class="w-28 text-right">CTC宽度(mm)</span> |
| | | <InputNumber |
| | | v-model:value="reelForm.ctcWidth" |
| | | class="!flex-1" |
| | | :min="0" |
| | | :precision="2" |
| | | placeholder="å¦ 12.6" |
| | | /> |
| | | </div> |
| | | </div> |
| | | <div class="mt-4 flex gap-2"> |
| | | <Button type="primary" @click="handleCalcReel">计ç®</Button> |
| | | <Button @click="handleFillReel">åå¡«æå¤§å®¹é</Button> |
| | | </div> |
| | | <Descriptions v-if="reelResult" class="mt-4" :column="2" bordered> |
| | | <DescriptionsItem label="æ¯çé¿åº¦(m)"> |
| | | {{ reelResult.capacityMeter }} |
| | | </DescriptionsItem> |
| | | <DescriptionsItem label="æ¯çé¿åº¦(km)"> |
| | | {{ reelResult.capacityKm }} |
| | | </DescriptionsItem> |
| | | </Descriptions> |
| | | </Tabs.TabPane> |
| | | </Tabs> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { FormType } from '../data'; |
| | | |
| | | import type { MesPdCtcApi } from '#/api/mes/pd/ctc'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | import { $t } from '@vben/locales'; |
| | | |
| | | import { Button, message } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { |
| | | createCtc, |
| | | getCtc, |
| | | updateCtc, |
| | | } from '#/api/mes/pd/ctc'; |
| | | |
| | | import { useFormSchema } from '../data'; |
| | | import CalcModal from './calc-modal.vue'; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formType = ref<FormType>('create'); // è¡¨åæ¨¡å¼ |
| | | const formData = ref<MesPdCtcApi.Ctc>(); |
| | | const isDetail = computed(() => formType.value === 'detail'); // æ¯å¦æ¥çæ¨¡å¼ |
| | | const getTitle = computed(() => { |
| | | if (formType.value === 'detail') { |
| | | return 'æ¥çæ¢ä½å¯¼çº¿ææ¯åæ°'; |
| | | } |
| | | return formType.value === 'update' ? 'ä¿®æ¹æ¢ä½å¯¼çº¿ææ¯åæ°' : 'æ°å¢æ¢ä½å¯¼çº¿ææ¯åæ°'; |
| | | }); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | formItemClass: 'col-span-1', |
| | | labelWidth: 130, |
| | | }, |
| | | wrapperClass: 'grid-cols-3', |
| | | layout: 'horizontal', |
| | | schema: [], |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [CalcModal, calcModalApi] = useVbenModal({ |
| | | connectedComponent: CalcModal, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | /** æå¼è®¡ç®å·¥å
· */ |
| | | function handleOpenCalc() { |
| | | calcModalApi.open(); |
| | | } |
| | | |
| | | /** åå¡«ç»å
è§åº¦ */ |
| | | function handleFillAngle(value: { wrappingAngle: number }) { |
| | | formApi.setFieldValue('wrappingAngle', value.wrappingAngle); |
| | | } |
| | | |
| | | /** åå¡«ç´æµçµé» */ |
| | | function handleFillResistance(value: { resistance20c: number }) { |
| | | formApi.setFieldValue('resistance20c', value.resistance20c); |
| | | } |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | if (isDetail.value) { |
| | | await modalApi.close(); |
| | | return; |
| | | } |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | // æäº¤è¡¨å |
| | | const data = (await formApi.getValues()) as MesPdCtcApi.Ctc; |
| | | try { |
| | | await (data.id ? updateCtc(data) : createCtc(data)); |
| | | // å
³éå¹¶æç¤º |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | return; |
| | | } |
| | | // å è½½æ°æ® |
| | | const data = modalApi.getData<{ formType: FormType; id?: number }>(); |
| | | formType.value = data.formType; |
| | | formApi.setState({ schema: useFormSchema() }); |
| | | formApi.setDisabled(formType.value === 'detail'); |
| | | modalApi.setState({ showConfirmButton: formType.value !== 'detail' }); |
| | | if (!data?.id) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | formData.value = await getCtc(data.id); |
| | | // è®¾ç½®å° values |
| | | await formApi.setValues(formData.value); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal :title="getTitle" class="w-4/5"> |
| | | <Form class="mx-4" /> |
| | | <template #prepend-footer> |
| | | <Button |
| | | v-if="!isDetail" |
| | | type="default" |
| | | @click="handleOpenCalc" |
| | | > |
| | | 计ç®å·¥å
· |
| | | </Button> |
| | | </template> |
| | | <CalcModal |
| | | @angle="handleFillAngle" |
| | | @resistance="handleFillResistance" |
| | | /> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | export { default as CalcModal } from './calc-modal.vue'; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { CrmCustomerApi } from '#/api/crm/customer'; |
| | | import type { MesPdTechConfirmApi } from '#/api/mes/pd/tech-confirm'; |
| | | |
| | | import { markRaw } from 'vue'; |
| | | |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | |
| | | import CrmCustomerSelect from '#/components/crm-customer-select.vue'; |
| | | |
| | | /** 表åç±»å */ |
| | | export type FormType = 'create' | 'detail' | 'update'; |
| | | |
| | | /** æ°å¢/ä¿®æ¹äº§åææ¯ç¡®è®¤å½ */ |
| | | export function useFormSchema( |
| | | formApi?: VbenFormApi, |
| | | ): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | | component: 'Input', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'confirmNo', |
| | | label: '确认å½ç¼å·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥ç¡®è®¤å½ç¼å·', |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'customerId', |
| | | label: '客æ·', |
| | | component: markRaw(CrmCustomerSelect), |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©å®¢æ·', |
| | | onChange: (item?: CrmCustomerApi.Customer) => { |
| | | formApi?.setFieldValue('customerName', item?.name); |
| | | }, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'customerName', |
| | | label: '客æ·åç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å®¢æ·åç§°', |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'productName', |
| | | label: '产ååç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥äº§ååç§°', |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'specification', |
| | | label: 'è§æ ¼åå·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è§æ ¼åå·', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'techParams', |
| | | label: 'ææ¯åæ°(JSON)', |
| | | component: 'Textarea', |
| | | formItemClass: 'col-span-3', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥ææ¯åæ° JSONï¼å¦ {"thickness":"1.27","width":"5.7"}', |
| | | rows: 4, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'templateType', |
| | | label: '模æ¿ç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.PRODUCT_TECH_CONFIRM_TEMPLATE, 'string'), |
| | | placeholder: 'è¯·éæ©æ¨¡æ¿ç±»å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'status', |
| | | label: 'ç¶æ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.PRODUCT_TECH_CONFIRM_STATUS, 'number'), |
| | | placeholder: 'è¯·éæ©ç¶æ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'drafterName', |
| | | label: 'ç¼å¶äºº', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥ç¼å¶äººå§å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'draftTime', |
| | | label: 'ç¼å¶æ¶é´', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | format: 'YYYY-MM-DD HH:mm:ss', |
| | | showTime: true, |
| | | valueFormat: 'YYYY-MM-DD HH:mm:ss', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'reviewerName', |
| | | label: 'å®¡æ ¸äºº', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å®¡æ ¸äººå§å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'reviewTime', |
| | | label: 'å®¡æ ¸æ¶é´', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | format: 'YYYY-MM-DD HH:mm:ss', |
| | | showTime: true, |
| | | valueFormat: 'YYYY-MM-DD HH:mm:ss', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'customerConfirmUser', |
| | | label: '客æ·ç¡®è®¤äºº', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å®¢æ·ç¡®è®¤äºº', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'customerConfirmTime', |
| | | label: '客æ·ç¡®è®¤æ¶é´', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | format: 'YYYY-MM-DD HH:mm:ss', |
| | | showTime: true, |
| | | valueFormat: 'YYYY-MM-DD HH:mm:ss', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | | formItemClass: 'col-span-3', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å¤æ³¨', |
| | | rows: 2, |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çæç´¢è¡¨å */ |
| | | export function useGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'confirmNo', |
| | | label: '确认å½ç¼å·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | allowClear: true, |
| | | placeholder: '请è¾å
¥ç¡®è®¤å½ç¼å·', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'productName', |
| | | label: '产ååç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | allowClear: true, |
| | | placeholder: '请è¾å
¥äº§ååç§°', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'templateType', |
| | | label: '模æ¿ç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.PRODUCT_TECH_CONFIRM_TEMPLATE, 'string'), |
| | | placeholder: 'è¯·éæ©æ¨¡æ¿ç±»å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'status', |
| | | label: 'ç¶æ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.PRODUCT_TECH_CONFIRM_STATUS, 'number'), |
| | | placeholder: 'è¯·éæ©ç¶æ', |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çåæ®µ */ |
| | | export function useGridColumns(): VxeTableGridOptions<MesPdTechConfirmApi.TechConfirm>['columns'] { |
| | | return [ |
| | | { field: 'confirmNo', title: '确认å½ç¼å·', minWidth: 160 }, |
| | | { field: 'customerName', title: '客æ·åç§°', minWidth: 180 }, |
| | | { field: 'productName', title: '产ååç§°', minWidth: 140 }, |
| | | { field: 'specification', title: 'è§æ ¼åå·', minWidth: 140 }, |
| | | { |
| | | field: 'templateType', |
| | | title: '模æ¿ç±»å', |
| | | width: 110, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.PRODUCT_TECH_CONFIRM_TEMPLATE }, |
| | | }, |
| | | }, |
| | | { field: 'drafterName', title: 'ç¼å¶äºº', width: 90 }, |
| | | { |
| | | field: 'status', |
| | | title: 'ç¶æ', |
| | | width: 110, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.PRODUCT_TECH_CONFIRM_STATUS }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'createTime', |
| | | title: 'å建æ¶é´', |
| | | width: 170, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | width: 260, |
| | | fixed: 'right', |
| | | slots: { |
| | | default: 'actions', |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesPdTechConfirmApi } from '#/api/mes/pd/tech-confirm'; |
| | | |
| | | import { ref } from 'vue'; |
| | | |
| | | import { Page, useVbenModal } from '@vben/common-ui'; |
| | | import { $t } from '@vben/locales'; |
| | | import { downloadFileFromBlobPart } from '@vben/utils'; |
| | | |
| | | import { Button, message } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | deleteTechConfirm, |
| | | exportTechConfirm, |
| | | getTechConfirmPage, |
| | | updateTechConfirm, |
| | | } from '#/api/mes/pd/tech-confirm'; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | /** å·æ°è¡¨æ ¼ */ |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** æ°å¢ */ |
| | | function handleCreate() { |
| | | formModalApi.setData({ formType: 'create' }).open(); |
| | | } |
| | | |
| | | /** æ¥ç */ |
| | | function handleDetail(row: MesPdTechConfirmApi.TechConfirm) { |
| | | formModalApi.setData({ id: row.id, formType: 'detail' }).open(); |
| | | } |
| | | |
| | | /** ç¼è¾ */ |
| | | function handleEdit(row: MesPdTechConfirmApi.TechConfirm) { |
| | | formModalApi.setData({ id: row.id, formType: 'update' }).open(); |
| | | } |
| | | |
| | | /** å é¤ */ |
| | | async function handleDelete(row: MesPdTechConfirmApi.TechConfirm) { |
| | | const hideLoading = message.loading({ |
| | | content: $t('ui.actionMessage.deleting', [row.confirmNo ?? '']), |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await deleteTechConfirm(row.id!); |
| | | message.success($t('ui.actionMessage.deleteSuccess', [row.confirmNo ?? ''])); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** ç¶ææµè½¬ */ |
| | | async function handleStatus(row: MesPdTechConfirmApi.TechConfirm, next: number) { |
| | | const hideLoading = message.loading({ content: 'ç¶ææ´æ°ä¸...', duration: 0 }); |
| | | try { |
| | | await updateTechConfirm({ ...row, status: next }); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** å¯¼åº */ |
| | | async function handleExport() { |
| | | const data = await exportTechConfirm(await gridApi.formApi.getValues()); |
| | | downloadFileFromBlobPart({ fileName: 'äº§åææ¯ç¡®è®¤å½.xls', source: data }); |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useGridColumns(), |
| | | height: 'auto', |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => |
| | | await getTechConfirmPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }), |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<MesPdTechConfirmApi.TechConfirm>, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <FormModal @success="handleRefresh" /> |
| | | <Grid table-title="äº§åææ¯ç¡®è®¤å½å表"> |
| | | <template #toolbar-tools> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('ui.actionTitle.create', ['ææ¯ç¡®è®¤å½']), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['mes:pd-tech-confirm:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | { |
| | | label: $t('ui.actionTitle.export'), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | | auth: ['mes:pd-tech-confirm:export'], |
| | | onClick: handleExport, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #confirmNo="{ row }"> |
| | | <Button type="link" @click="handleDetail(row)"> |
| | | {{ row.confirmNo }} |
| | | </Button> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: 'æäº¤å®¡æ ¸', |
| | | type: 'link', |
| | | icon: ACTION_ICON.AUDIT, |
| | | auth: ['mes:pd-tech-confirm:update'], |
| | | ifShow: row.status === 0, |
| | | onClick: handleStatus.bind(null, row, 1), |
| | | }, |
| | | { |
| | | label: 'å®¡æ ¸éè¿', |
| | | type: 'link', |
| | | icon: ACTION_ICON.AUDIT, |
| | | auth: ['mes:pd-tech-confirm:update'], |
| | | ifShow: row.status === 1, |
| | | onClick: handleStatus.bind(null, row, 2), |
| | | }, |
| | | { |
| | | label: '客æ·ç¡®è®¤', |
| | | type: 'link', |
| | | icon: ACTION_ICON.AUDIT, |
| | | auth: ['mes:pd-tech-confirm:update'], |
| | | ifShow: row.status === 2, |
| | | onClick: handleStatus.bind(null, row, 3), |
| | | }, |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['mes:pd-tech-confirm:update'], |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['mes:pd-tech-confirm:delete'], |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [row.confirmNo ?? '']), |
| | | confirm: handleDelete.bind(null, row), |
| | | }, |
| | | }, |
| | | { |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['mes:pd-tech-confirm:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { FormType } from '../data'; |
| | | |
| | | import type { MesPdTechConfirmApi } from '#/api/mes/pd/tech-confirm'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | import { $t } from '@vben/locales'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { |
| | | createTechConfirm, |
| | | getTechConfirm, |
| | | updateTechConfirm, |
| | | } from '#/api/mes/pd/tech-confirm'; |
| | | |
| | | import { useFormSchema } from '../data'; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formType = ref<FormType>('create'); // è¡¨åæ¨¡å¼ |
| | | const formData = ref<MesPdTechConfirmApi.TechConfirm>(); |
| | | const isDetail = computed(() => formType.value === 'detail'); // æ¯å¦æ¥çæ¨¡å¼ |
| | | const getTitle = computed(() => { |
| | | if (formType.value === 'detail') { |
| | | return 'æ¥çææ¯ç¡®è®¤å½'; |
| | | } |
| | | return formType.value === 'update' ? 'ä¿®æ¹ææ¯ç¡®è®¤å½' : 'æ°å¢ææ¯ç¡®è®¤å½'; |
| | | }); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | formItemClass: 'col-span-1', |
| | | labelWidth: 130, |
| | | }, |
| | | wrapperClass: 'grid-cols-3', |
| | | layout: 'horizontal', |
| | | schema: [], |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | if (isDetail.value) { |
| | | await modalApi.close(); |
| | | return; |
| | | } |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | // æäº¤è¡¨å |
| | | const data = (await formApi.getValues()) as MesPdTechConfirmApi.TechConfirm; |
| | | try { |
| | | await (data.id ? updateTechConfirm(data) : createTechConfirm(data)); |
| | | // å
³éå¹¶æç¤º |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | return; |
| | | } |
| | | // å è½½æ°æ® |
| | | const data = modalApi.getData<{ formType: FormType; id?: number }>(); |
| | | formType.value = data.formType; |
| | | formApi.setState({ schema: useFormSchema(formApi) }); |
| | | formApi.setDisabled(formType.value === 'detail'); |
| | | modalApi.setState({ showConfirmButton: formType.value !== 'detail' }); |
| | | if (!data?.id) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | formData.value = await getTechConfirm(data.id); |
| | | // è®¾ç½®å° values |
| | | await formApi.setValues(formData.value); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal :title="getTitle" class="w-4/5"> |
| | | <Form class="mx-4" /> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | |
| | | /** 表åç±»å */ |
| | | export type FormType = 'create' | 'detail' | 'edit'; |
| | | |
| | | /** ç¶æå¸¸é */ |
| | | export const PLAN_STATUS = { |
| | | DRAFT: 0, |
| | | PUBLISHED: 10, |
| | | }; |
| | | |
| | | /** 表åçé
置项 */ |
| | | export function useFormSchema(formType: FormType): VbenFormSchema[] { |
| | | const isReadonly = formType === 'detail'; |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | | component: 'Input', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'code', |
| | | label: '颿¡ç¼ç ', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: 'ç³»ç»èªå¨çæ', |
| | | disabled: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'name', |
| | | label: '颿¡åç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥é¢æ¡åç§°', |
| | | disabled: isReadonly, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'planType', |
| | | label: '颿¡ç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.MES_PRO_EMERGENCY_PLAN_TYPE, 'number'), |
| | | placeholder: 'è¯·éæ©é¢æ¡ç±»å', |
| | | disabled: isReadonly, |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'orgUnit', |
| | | label: '责任åä½', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è´£ä»»åä½/é¨é¨', |
| | | disabled: isReadonly, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'content', |
| | | label: 'å¤ç½®å
容', |
| | | component: 'Textarea', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥åºæ¥å¤ç½®å
容', |
| | | rows: 4, |
| | | disabled: isReadonly, |
| | | }, |
| | | formItemClass: 'col-span-3', |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å¤æ³¨', |
| | | autoSize: { minRows: 1, maxRows: 1 }, |
| | | disabled: isReadonly, |
| | | }, |
| | | formItemClass: 'col-span-3', |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çæç´¢è¡¨å */ |
| | | export function useGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'code', |
| | | label: '颿¡ç¼ç ', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥é¢æ¡ç¼ç ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'name', |
| | | label: '颿¡åç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥é¢æ¡åç§°', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'planType', |
| | | label: '颿¡ç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.MES_PRO_EMERGENCY_PLAN_TYPE, 'number'), |
| | | placeholder: 'è¯·éæ©é¢æ¡ç±»å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'status', |
| | | label: 'ç¶æ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: [ |
| | | { label: 'è稿', value: PLAN_STATUS.DRAFT }, |
| | | { label: 'å·²åå¸', value: PLAN_STATUS.PUBLISHED }, |
| | | ], |
| | | placeholder: 'è¯·éæ©ç¶æ', |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çè¡¨æ ¼å */ |
| | | export function useGridColumns(): VxeTableGridOptions['columns'] { |
| | | return [ |
| | | { type: 'checkbox', width: 50 }, |
| | | { type: 'seq', title: 'åºå·', width: 60 }, |
| | | { |
| | | field: 'code', |
| | | title: '颿¡ç¼ç ', |
| | | minWidth: 150, |
| | | slots: { default: 'code' }, |
| | | }, |
| | | { |
| | | field: 'name', |
| | | title: '颿¡åç§°', |
| | | minWidth: 200, |
| | | }, |
| | | { |
| | | field: 'planType', |
| | | title: '颿¡ç±»å', |
| | | width: 110, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_PRO_EMERGENCY_PLAN_TYPE }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'orgUnit', |
| | | title: '责任åä½', |
| | | minWidth: 140, |
| | | }, |
| | | { |
| | | field: 'status', |
| | | title: 'ç¶æ', |
| | | width: 100, |
| | | slots: { default: 'status' }, |
| | | }, |
| | | { |
| | | field: 'createTime', |
| | | title: 'å建æ¶é´', |
| | | width: 170, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | field: 'action', |
| | | title: 'æä½', |
| | | width: 260, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesProEmergencyPlanApi } from '#/api/mes/pro/emergencyplan'; |
| | | |
| | | import { ref } from 'vue'; |
| | | |
| | | import { Page, useVbenModal } from '@vben/common-ui'; |
| | | import { isEmpty } from '@vben/utils'; |
| | | |
| | | import { message, Tag } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { deletePlan, getPlanPage, publishPlan } from '#/api/mes/pro/emergencyplan'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { PLAN_STATUS, useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | |
| | | /** MES åºæ¥å¤ç½®é¢æ¡å表 */ |
| | | defineOptions({ name: 'MesProEmergencyPlan' }); |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | function handleCreate() { |
| | | formModalApi.setData({ formType: 'create' }).open(); |
| | | } |
| | | |
| | | function handleEdit(row: MesProEmergencyPlanApi.EmergencyPlan) { |
| | | formModalApi.setData({ formType: 'edit', id: row.id }).open(); |
| | | } |
| | | |
| | | function handleDetail(row: MesProEmergencyPlanApi.EmergencyPlan) { |
| | | formModalApi.setData({ formType: 'detail', id: row.id }).open(); |
| | | } |
| | | |
| | | async function handleDelete(ids: number[]) { |
| | | const hideLoading = message.loading({ |
| | | content: $t('ui.actionMessage.deleting'), |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await deletePlan(ids); |
| | | message.success($t('ui.actionMessage.deleteSuccess')); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | async function handlePublish(row: MesProEmergencyPlanApi.EmergencyPlan) { |
| | | await publishPlan(row.id!); |
| | | message.success('å·²åå¸'); |
| | | handleRefresh(); |
| | | } |
| | | |
| | | const checkedIds = ref<number[]>([]); |
| | | function handleRowCheckboxChange({ |
| | | records, |
| | | }: { |
| | | records: MesProEmergencyPlanApi.EmergencyPlan[]; |
| | | }) { |
| | | checkedIds.value = records.map((item) => item.id!); |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useGridColumns(), |
| | | height: 'auto', |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => { |
| | | return await getPlanPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }); |
| | | }, |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<MesProEmergencyPlanApi.EmergencyPlan>, |
| | | gridEvents: { |
| | | checkboxAll: handleRowCheckboxChange, |
| | | checkboxChange: handleRowCheckboxChange, |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <FormModal @success="handleRefresh" /> |
| | | <Grid table-title="åºæ¥å¤ç½®é¢æ¡å表"> |
| | | <template #toolbar-tools> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('ui.actionTitle.create', ['åºæ¥å¤ç½®é¢æ¡']), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['mes:pro-emergency-plan:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | { |
| | | label: 'æ¹éå é¤', |
| | | type: 'primary', |
| | | danger: true, |
| | | disabled: isEmpty(checkedIds), |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['mes:pro-emergency-plan:delete'], |
| | | popConfirm: { |
| | | title: `æ¯å¦å 餿é䏿°æ®ï¼`, |
| | | confirm: handleDelete.bind(null, checkedIds), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #code="{ row }"> |
| | | <a class="link" @click="handleDetail(row)">{{ row.code }}</a> |
| | | </template> |
| | | <template #status="{ row }"> |
| | | <Tag v-if="row.status === PLAN_STATUS.DRAFT" color="default">è稿</Tag> |
| | | <Tag v-else-if="row.status === PLAN_STATUS.PUBLISHED" color="success">å·²åå¸</Tag> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['mes:pro-emergency-plan:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['mes:pro-emergency-plan:update'], |
| | | ifShow: row.status === PLAN_STATUS.DRAFT, |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: 'åå¸', |
| | | type: 'link', |
| | | auth: ['mes:pro-emergency-plan:update'], |
| | | ifShow: row.status === PLAN_STATUS.DRAFT, |
| | | popConfirm: { |
| | | title: '确认åå¸è¯¥é¢æ¡ï¼', |
| | | confirm: handlePublish.bind(null, row), |
| | | }, |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['mes:pro-emergency-plan:delete'], |
| | | ifShow: row.status === PLAN_STATUS.DRAFT, |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [row.code]), |
| | | confirm: handleDelete.bind(null, [row.id!]), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { MesProEmergencyPlanApi } from '#/api/mes/pro/emergencyplan'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { createPlan, getPlan, updatePlan } from '#/api/mes/pro/emergencyplan'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import type { FormType } from '../data'; |
| | | import { useFormSchema } from '../data'; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formData = ref<MesProEmergencyPlanApi.EmergencyPlan>(); |
| | | const formType = ref<FormType>('create'); |
| | | |
| | | const getTitle = computed(() => { |
| | | if (formType.value === 'create') { |
| | | return $t('ui.actionTitle.create', ['åºæ¥å¤ç½®é¢æ¡']); |
| | | } else if (formType.value === 'edit') { |
| | | return $t('ui.actionTitle.edit', ['åºæ¥å¤ç½®é¢æ¡']); |
| | | } else { |
| | | return 'åºæ¥å¤ç½®é¢æ¡è¯¦æ
'; |
| | | } |
| | | }); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | labelWidth: 120, |
| | | }, |
| | | wrapperClass: 'grid-cols-3', |
| | | layout: 'vertical', |
| | | schema: useFormSchema(formType.value), |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | const data = |
| | | (await formApi.getValues()) as MesProEmergencyPlanApi.EmergencyPlan; |
| | | try { |
| | | await (formType.value === 'create' |
| | | ? createPlan(data) |
| | | : updatePlan(data)); |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | return; |
| | | } |
| | | const data = modalApi.getData<{ formType: FormType; id?: number }>(); |
| | | formType.value = data.formType; |
| | | formApi.setDisabled(formType.value === 'detail'); |
| | | formApi.updateSchema(useFormSchema(formType.value)); |
| | | if (!data || !data.id) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | formData.value = await getPlan(data.id); |
| | | await formApi.setValues(formData.value); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal :title="getTitle" class="w-2/3" :show-confirm-button="formType !== 'detail'"> |
| | | <Form class="mx-3" /> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | |
| | | import { getRangePickerDefaultProps } from '#/utils'; |
| | | |
| | | /** 表åç±»å */ |
| | | export type FormType = 'create' | 'detail' | 'edit'; |
| | | |
| | | /** 计åç¶æå¸¸é */ |
| | | export const PLAN_STATUS = { |
| | | DRAFT: 0, |
| | | ISSUED: 10, |
| | | FINISHED: 20, |
| | | CANCELLED: 30, |
| | | }; |
| | | |
| | | /** 表åçé
置项 */ |
| | | export function useFormSchema(formType: FormType): VbenFormSchema[] { |
| | | const isReadonly = formType === 'detail'; |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | | component: 'Input', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'code', |
| | | label: '计åç¼ç ', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: 'ç³»ç»èªå¨çæ', |
| | | disabled: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'name', |
| | | label: '计ååç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è®¡ååç§°', |
| | | disabled: isReadonly, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'planType', |
| | | label: '计åç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.MES_PRO_MAINTENANCE_PLAN_TYPE, 'number'), |
| | | placeholder: 'è¯·éæ©è®¡åç±»å', |
| | | disabled: isReadonly, |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'station', |
| | | label: 'ç«ç¹', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥ç«ç¹', |
| | | disabled: isReadonly, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'line', |
| | | label: '线路', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥çº¿è·¯', |
| | | disabled: isReadonly, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'planDate', |
| | | label: 'è®¡åæ¥æ', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | placeholder: 'éæ©è®¡åæ¥æ', |
| | | showTime: true, |
| | | format: 'YYYY-MM-DD HH:mm:ss', |
| | | valueFormat: 'YYYY-MM-DD HH:mm:ss', |
| | | disabled: isReadonly, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'teamId', |
| | | label: 'çç»', |
| | | component: 'Input', |
| | | componentProps: { |
| | | disabled: true, |
| | | placeholder: 'ç±è®¡åæ§è¡åé
', |
| | | }, |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å¤æ³¨', |
| | | autoSize: { minRows: 1, maxRows: 1 }, |
| | | disabled: isReadonly, |
| | | }, |
| | | formItemClass: 'col-span-2', |
| | | }, |
| | | { |
| | | fieldName: 'items', |
| | | label: 'å¤ä»¶/ç©èµéæ±', |
| | | component: 'Input', |
| | | formItemClass: 'col-span-3', |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çæç´¢è¡¨å */ |
| | | export function useGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'code', |
| | | label: '计åç¼ç ', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è®¡åç¼ç ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'name', |
| | | label: '计ååç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è®¡ååç§°', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'planType', |
| | | label: '计åç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.MES_PRO_MAINTENANCE_PLAN_TYPE, 'number'), |
| | | placeholder: 'è¯·éæ©è®¡åç±»å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'status', |
| | | label: 'ç¶æ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: [ |
| | | { label: 'è稿', value: PLAN_STATUS.DRAFT }, |
| | | { label: 'å·²ä¸å', value: PLAN_STATUS.ISSUED }, |
| | | { label: '已宿', value: PLAN_STATUS.FINISHED }, |
| | | { label: '已忶', value: PLAN_STATUS.CANCELLED }, |
| | | ], |
| | | placeholder: 'è¯·éæ©ç¶æ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'planDate', |
| | | label: 'è®¡åæ¥æ', |
| | | component: 'RangePicker', |
| | | componentProps: getRangePickerDefaultProps(), |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çè¡¨æ ¼å */ |
| | | export function useGridColumns(): VxeTableGridOptions['columns'] { |
| | | return [ |
| | | { type: 'checkbox', width: 50 }, |
| | | { type: 'seq', title: 'åºå·', width: 60 }, |
| | | { |
| | | field: 'code', |
| | | title: '计åç¼ç ', |
| | | minWidth: 150, |
| | | slots: { default: 'code' }, |
| | | }, |
| | | { |
| | | field: 'name', |
| | | title: '计ååç§°', |
| | | minWidth: 180, |
| | | }, |
| | | { |
| | | field: 'planType', |
| | | title: '计åç±»å', |
| | | width: 110, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_PRO_MAINTENANCE_PLAN_TYPE }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'station', |
| | | title: 'ç«ç¹', |
| | | minWidth: 140, |
| | | }, |
| | | { |
| | | field: 'line', |
| | | title: '线路', |
| | | minWidth: 140, |
| | | }, |
| | | { |
| | | field: 'teamName', |
| | | title: 'çç»', |
| | | width: 110, |
| | | }, |
| | | { |
| | | field: 'planDate', |
| | | title: 'è®¡åæ¥æ', |
| | | width: 170, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | field: 'status', |
| | | title: 'ç¶æ', |
| | | width: 100, |
| | | slots: { default: 'status' }, |
| | | }, |
| | | { |
| | | field: 'workOrderCode', |
| | | title: 'çæçå·¥å', |
| | | minWidth: 150, |
| | | }, |
| | | { |
| | | field: 'action', |
| | | title: 'æä½', |
| | | width: 300, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesProMaintenancePlanApi } from '#/api/mes/pro/maintenance-plan'; |
| | | |
| | | import { ref } from 'vue'; |
| | | |
| | | import { Page, useVbenModal } from '@vben/common-ui'; |
| | | import { downloadFileFromBlobPart, isEmpty } from '@vben/utils'; |
| | | |
| | | import { message, Tag } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | deletePlan, |
| | | exportPlan, |
| | | finishPlan, |
| | | generatePurchasePlan, |
| | | generateWorkOrder, |
| | | getPlanPage, |
| | | issuePlan, |
| | | } from '#/api/mes/pro/maintenance-plan'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { PLAN_STATUS, useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | |
| | | /** MES çµåä½ä¸è®¡åå表 */ |
| | | defineOptions({ name: 'MesProMaintenancePlan' }); |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | async function handleExport() { |
| | | const data = await exportPlan(await gridApi.formApi.getValues()); |
| | | downloadFileFromBlobPart({ fileName: 'çµåä½ä¸è®¡å.xls', source: data }); |
| | | } |
| | | |
| | | function handleCreate() { |
| | | formModalApi.setData({ formType: 'create' }).open(); |
| | | } |
| | | |
| | | function handleEdit(row: MesProMaintenancePlanApi.MaintenancePlan) { |
| | | formModalApi.setData({ formType: 'edit', id: row.id }).open(); |
| | | } |
| | | |
| | | function handleDetail(row: MesProMaintenancePlanApi.MaintenancePlan) { |
| | | formModalApi.setData({ formType: 'detail', id: row.id }).open(); |
| | | } |
| | | |
| | | async function handleDelete(ids: number[]) { |
| | | const hideLoading = message.loading({ |
| | | content: $t('ui.actionMessage.deleting'), |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await deletePlan(ids); |
| | | message.success($t('ui.actionMessage.deleteSuccess')); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | async function handleIssue(row: MesProMaintenancePlanApi.MaintenancePlan) { |
| | | await issuePlan(row.id!); |
| | | message.success('å·²ä¸å'); |
| | | handleRefresh(); |
| | | } |
| | | |
| | | async function handleFinish(row: MesProMaintenancePlanApi.MaintenancePlan) { |
| | | await finishPlan(row.id!); |
| | | message.success('已宿'); |
| | | handleRefresh(); |
| | | } |
| | | |
| | | async function handleGeneratePurchasePlan( |
| | | row: MesProMaintenancePlanApi.MaintenancePlan, |
| | | ) { |
| | | const hideLoading = message.loading({ |
| | | content: 'æ£å¨æ ¹æ®å¤ä»¶éæ±çæéè´è®¡å...', |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | const planId = await generatePurchasePlan(row.id!); |
| | | message.success(`å·²çæéè´è®¡åï¼ç¼å· ${planId}ï¼ï¼è¯·å¨éè´ç®¡ç䏿 ¸å¯¹æäº¤å®¡æ¹`); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | async function handleGenerateWorkOrder( |
| | | row: MesProMaintenancePlanApi.MaintenancePlan, |
| | | ) { |
| | | const hideLoading = message.loading({ |
| | | content: 'æ£å¨çæå·¥å...', |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | const workOrderId = await generateWorkOrder(row.id!); |
| | | message.success(`å·²çæå·¥åï¼ç¼å· ${workOrderId}ï¼ï¼å¯å¨ç产订å䏿¥ç`); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | const checkedIds = ref<number[]>([]); |
| | | function handleRowCheckboxChange({ |
| | | records, |
| | | }: { |
| | | records: MesProMaintenancePlanApi.MaintenancePlan[]; |
| | | }) { |
| | | checkedIds.value = records.map((item) => item.id!); |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useGridColumns(), |
| | | height: 'auto', |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => { |
| | | return await getPlanPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }); |
| | | }, |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<MesProMaintenancePlanApi.MaintenancePlan>, |
| | | gridEvents: { |
| | | checkboxAll: handleRowCheckboxChange, |
| | | checkboxChange: handleRowCheckboxChange, |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <FormModal @success="handleRefresh" /> |
| | | <Grid table-title="çµåä½ä¸è®¡åå表"> |
| | | <template #toolbar-tools> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('ui.actionTitle.create', ['çµåä½ä¸è®¡å']), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['mes:pro-maintenance-plan:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | { |
| | | label: $t('ui.actionTitle.export'), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | | auth: ['mes:pro-maintenance-plan:export'], |
| | | onClick: handleExport, |
| | | }, |
| | | { |
| | | label: 'æ¹éå é¤', |
| | | type: 'primary', |
| | | danger: true, |
| | | disabled: isEmpty(checkedIds), |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['mes:pro-maintenance-plan:delete'], |
| | | popConfirm: { |
| | | title: `æ¯å¦å 餿é䏿°æ®ï¼`, |
| | | confirm: handleDelete.bind(null, checkedIds), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #code="{ row }"> |
| | | <a class="link" @click="handleDetail(row)">{{ row.code }}</a> |
| | | </template> |
| | | <template #status="{ row }"> |
| | | <Tag v-if="row.status === PLAN_STATUS.DRAFT" color="default">è稿</Tag> |
| | | <Tag v-else-if="row.status === PLAN_STATUS.ISSUED" color="processing">å·²ä¸å</Tag> |
| | | <Tag v-else-if="row.status === PLAN_STATUS.FINISHED" color="success">已宿</Tag> |
| | | <Tag v-else-if="row.status === PLAN_STATUS.CANCELLED" color="warning">已忶</Tag> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['mes:pro-maintenance-plan:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['mes:pro-maintenance-plan:update'], |
| | | ifShow: row.status === PLAN_STATUS.DRAFT, |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: 'ä¸å', |
| | | type: 'link', |
| | | auth: ['mes:pro-maintenance-plan:update'], |
| | | ifShow: row.status === PLAN_STATUS.DRAFT, |
| | | popConfirm: { |
| | | title: '确认ä¸å该计åï¼', |
| | | confirm: handleIssue.bind(null, row), |
| | | }, |
| | | }, |
| | | { |
| | | label: 'çæéè´è®¡å', |
| | | type: 'link', |
| | | auth: ['mes:pro-maintenance-plan:generate-purchase-plan'], |
| | | ifShow: row.status === PLAN_STATUS.ISSUED, |
| | | onClick: handleGeneratePurchasePlan.bind(null, row), |
| | | }, |
| | | { |
| | | label: 'çæå·¥å', |
| | | type: 'link', |
| | | auth: ['mes:pro-maintenance-plan:generate-work-order'], |
| | | ifShow: row.status === PLAN_STATUS.ISSUED && !row.workOrderId, |
| | | onClick: handleGenerateWorkOrder.bind(null, row), |
| | | }, |
| | | { |
| | | label: '宿', |
| | | type: 'link', |
| | | auth: ['mes:pro-maintenance-plan:update'], |
| | | ifShow: row.status === PLAN_STATUS.ISSUED, |
| | | popConfirm: { |
| | | title: 'ç¡®è®¤å®æè¯¥è®¡åï¼', |
| | | confirm: handleFinish.bind(null, row), |
| | | }, |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['mes:pro-maintenance-plan:delete'], |
| | | ifShow: row.status === PLAN_STATUS.DRAFT, |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [row.code]), |
| | | confirm: handleDelete.bind(null, [row.id!]), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { MesProMaintenancePlanApi } from '#/api/mes/pro/maintenance-plan'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { Button, DatePicker, Input, InputNumber, message } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { |
| | | createPlan, |
| | | getPlan, |
| | | updatePlan, |
| | | } from '#/api/mes/pro/maintenance-plan'; |
| | | import { MdItemSelect } from '#/views/mes/md/item/components'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import type { FormType } from '../data'; |
| | | import { useFormSchema } from '../data'; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formData = ref<MesProMaintenancePlanApi.MaintenancePlan>(); |
| | | const formType = ref<FormType>('create'); |
| | | const items = ref<MesProMaintenancePlanApi.PlanItem[]>([]); |
| | | |
| | | const getTitle = computed(() => { |
| | | if (formType.value === 'create') { |
| | | return $t('ui.actionTitle.create', ['çµåä½ä¸è®¡å']); |
| | | } else if (formType.value === 'edit') { |
| | | return $t('ui.actionTitle.edit', ['çµåä½ä¸è®¡å']); |
| | | } else { |
| | | return 'çµåä½ä¸è®¡å详æ
'; |
| | | } |
| | | }); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | labelWidth: 120, |
| | | }, |
| | | wrapperClass: 'grid-cols-3', |
| | | layout: 'vertical', |
| | | schema: useFormSchema(formType.value), |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | function handleAddItem() { |
| | | items.value.push({ |
| | | itemId: undefined as unknown as number, |
| | | itemName: '', |
| | | itemCode: '', |
| | | unitMeasureName: '', |
| | | quantity: 1, |
| | | remark: '', |
| | | }); |
| | | } |
| | | |
| | | function handleRemoveItem(index: number) { |
| | | items.value.splice(index, 1); |
| | | } |
| | | |
| | | function handleItemSelect(index: number, item: any) { |
| | | const row = items.value[index]; |
| | | if (!row) { |
| | | return; |
| | | } |
| | | row.itemId = item?.id; |
| | | row.itemName = item?.name; |
| | | row.itemCode = item?.code; |
| | | row.unitMeasureName = item?.unitMeasureName; |
| | | } |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | if (!items.value.length) { |
| | | message.error('请è³å°æ·»å 䏿¡å¤ä»¶/ç©èµéæ±'); |
| | | return; |
| | | } |
| | | if (items.value.some((item) => !item.itemId || !item.quantity)) { |
| | | message.error('请å®åå¤ä»¶éæ±ç产å䏿°é'); |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | const data = |
| | | (await formApi.getValues()) as MesProMaintenancePlanApi.MaintenancePlan; |
| | | data.items = items.value.map((item) => ({ |
| | | itemId: item.itemId, |
| | | quantity: item.quantity, |
| | | remark: item.remark, |
| | | })); |
| | | try { |
| | | await (formType.value === 'create' |
| | | ? createPlan(data) |
| | | : updatePlan(data)); |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | items.value = []; |
| | | return; |
| | | } |
| | | const data = modalApi.getData<{ formType: FormType; id?: number }>(); |
| | | formType.value = data.formType; |
| | | formApi.setDisabled(formType.value === 'detail'); |
| | | formApi.updateSchema(useFormSchema(formType.value)); |
| | | if (!data || !data.id) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | formData.value = await getPlan(data.id); |
| | | await formApi.setValues(formData.value); |
| | | items.value = (formData.value.items ?? []).map((item) => ({ ...item })); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal |
| | | :title="getTitle" |
| | | class="w-3/4" |
| | | :show-confirm-button="formType !== 'detail'" |
| | | > |
| | | <Form class="mx-3"> |
| | | <template #items> |
| | | <div class="mt-2"> |
| | | <div v-if="formType !== 'detail'" class="mb-2"> |
| | | <Button type="dashed" @click="handleAddItem">+ æ·»å å¤ä»¶éæ±</Button> |
| | | </div> |
| | | <table class="w-full border-collapse border border-gray-200 text-sm"> |
| | | <thead> |
| | | <tr class="bg-gray-100"> |
| | | <th class="border border-gray-200 px-2 py-1 w-12">åºå·</th> |
| | | <th class="border border-gray-200 px-2 py-1">ç©æ/å¤ä»¶</th> |
| | | <th class="border border-gray-200 px-2 py-1 w-20">åä½</th> |
| | | <th class="border border-gray-200 px-2 py-1 w-32">éæ±æ°é</th> |
| | | <th class="border border-gray-200 px-2 py-1">夿³¨</th> |
| | | <th |
| | | v-if="formType !== 'detail'" |
| | | class="border border-gray-200 px-2 py-1 w-16" |
| | | > |
| | | æä½ |
| | | </th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr v-for="(item, index) in items" :key="index"> |
| | | <td class="border border-gray-200 px-2 py-1 text-center"> |
| | | {{ index + 1 }} |
| | | </td> |
| | | <td class="border border-gray-200 px-2 py-1"> |
| | | <MdItemSelect |
| | | v-if="formType !== 'detail'" |
| | | :model-value="item.itemId" |
| | | placeholder="è¯·éæ©ç©æ/å¤ä»¶" |
| | | @change="handleItemSelect(index, $event)" |
| | | /> |
| | | <span v-else>{{ item.itemName }}</span> |
| | | </td> |
| | | <td class="border border-gray-200 px-2 py-1 text-center"> |
| | | {{ item.unitMeasureName || '-' }} |
| | | </td> |
| | | <td class="border border-gray-200 px-2 py-1"> |
| | | <InputNumber |
| | | v-if="formType !== 'detail'" |
| | | v-model:value="item.quantity" |
| | | class="!w-full" |
| | | :min="0.01" |
| | | :precision="2" |
| | | /> |
| | | <span v-else>{{ item.quantity }}</span> |
| | | </td> |
| | | <td class="border border-gray-200 px-2 py-1"> |
| | | <Input |
| | | v-if="formType !== 'detail'" |
| | | v-model:value="item.remark" |
| | | placeholder="夿³¨" |
| | | /> |
| | | <span v-else>{{ item.remark || '-' }}</span> |
| | | </td> |
| | | <td |
| | | v-if="formType !== 'detail'" |
| | | class="border border-gray-200 px-2 py-1 text-center" |
| | | > |
| | | <Button type="link" danger @click="handleRemoveItem(index)"> |
| | | å é¤ |
| | | </Button> |
| | | </td> |
| | | </tr> |
| | | <tr v-if="!items.length"> |
| | | <td |
| | | :colspan="formType === 'detail' ? 5 : 6" |
| | | class="border border-gray-200 px-2 py-4 text-center text-gray-400" |
| | | > |
| | | ææ å¤ä»¶éæ±ï¼è¯·æ·»å |
| | | </td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | </template> |
| | | </Form> |
| | | </Modal> |
| | | </template> |
| | |
| | | import { getRangePickerDefaultProps } from '#/utils'; |
| | | import { MdItemSelect } from '#/views/mes/md/item/components'; |
| | | import { MdWorkstationSelect } from '#/views/mes/md/workstation/components'; |
| | | import { CalTeamSelect } from '#/views/mes/cal/team/components'; |
| | | import { ProProcessSelect } from '#/views/mes/process-design/process/components'; |
| | | import { RouteColorPicker } from '#/views/mes/process-design/route/components'; |
| | | import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components'; |
| | |
| | | width: 120, |
| | | }, |
| | | { |
| | | field: 'teamName', |
| | | title: 'çç»', |
| | | width: 120, |
| | | }, |
| | | { |
| | | field: 'quantity', |
| | | title: 'æäº§æ°é', |
| | | width: 100, |
| | |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'teamId', |
| | | label: 'çç»', |
| | | component: markRaw(CalTeamSelect), |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©çç»', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'quantity', |
| | | label: 'æäº§æ°é', |
| | | component: 'InputNumber', |
| | |
| | | import type { MesProWorkOrderApi } from '#/api/mes/pro/workorder'; |
| | | import type { MesProWorkOrderBomApi } from '#/api/mes/pro/workorder/bom'; |
| | | import type { MesProWorkOrderProcessApi } from '#/api/mes/pro/workorder/process'; |
| | | import type { ErpSaleOrderApi } from '#/api/erp/sale/order'; |
| | | |
| | | import { h, markRaw } from 'vue'; |
| | | |
| | |
| | | MdItemSelect, |
| | | } from '#/views/mes/md/item/components'; |
| | | import { MdVendorSelect } from '#/views/mes/md/vendor/components'; |
| | | import { ErpSaleOrderSelect } from '#/views/erp/sale/order/components'; |
| | | |
| | | /** 表åç±»å */ |
| | | export type FormType = 'confirm' | 'create' | 'detail' | 'finish' | 'update'; |
| | |
| | | componentProps: { |
| | | disabled: headerReadonly, |
| | | placeholder: 'è¯·éæ©å®¢æ·', |
| | | }, |
| | | dependencies: { |
| | | triggerFields: ['orderSourceType'], |
| | | show: (values) => |
| | | values.orderSourceType === MesProWorkOrderSourceTypeEnum.ORDER, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'saleOrderId', |
| | | label: 'è¥é订å', |
| | | component: markRaw(ErpSaleOrderSelect), |
| | | componentProps: { |
| | | disabled: headerReadonly, |
| | | placeholder: 'è¯·éæ©è¥é订åï¼ERPéå®è®¢åï¼', |
| | | // éä¸è¥é订ååèªå¨å¸¦å
¥å®¢æ· |
| | | onChange: async (item?: ErpSaleOrderApi.SaleOrder) => { |
| | | if (!item) { |
| | | return; |
| | | } |
| | | const values = (await formApi?.getValues()) ?? {}; |
| | | if (values.clientId == null && item.customerId) { |
| | | await formApi?.setFieldValue('clientId', item.customerId); |
| | | } |
| | | }, |
| | | }, |
| | | dependencies: { |
| | | triggerFields: ['orderSourceType'], |
| | |
| | | width: 120, |
| | | }, |
| | | { |
| | | field: 'saleOrderNo', |
| | | title: 'è¥é订åå·', |
| | | width: 140, |
| | | }, |
| | | { |
| | | field: 'requestDate', |
| | | title: 'éæ±æ¥æ', |
| | | width: 180, |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { WorkResultSummary } from '#/api/mes/pro/feedback'; |
| | | |
| | | import { onMounted, reactive, ref } from 'vue'; |
| | | |
| | | import { Page } from '@vben/common-ui'; |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | |
| | | import { |
| | | Button, |
| | | Card, |
| | | Col, |
| | | DatePicker, |
| | | Row, |
| | | Select, |
| | | Space, |
| | | Table, |
| | | Tag, |
| | | } from 'ant-design-vue'; |
| | | |
| | | import { getFeedbackSummary } from '#/api/mes/pro/feedback'; |
| | | |
| | | defineOptions({ name: 'MesWorkResultSummary' }); |
| | | |
| | | const loading = ref(false); |
| | | const summary = ref<WorkResultSummary>({}); |
| | | |
| | | const queryForm = reactive<{ |
| | | beginDate?: string; |
| | | endDate?: string; |
| | | workOrderType?: number; |
| | | }>({}); |
| | | |
| | | const workOrderTypeOptions = getDictOptions( |
| | | DICT_TYPE.MES_PRO_WORK_ORDER_TYPE, |
| | | 'number', |
| | | ).map((option) => ({ label: option.label, value: option.value as number })); |
| | | |
| | | async function loadSummary() { |
| | | loading.value = true; |
| | | try { |
| | | summary.value = await getFeedbackSummary({ |
| | | beginDate: queryForm.beginDate, |
| | | endDate: queryForm.endDate, |
| | | workOrderType: queryForm.workOrderType, |
| | | }); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | } |
| | | |
| | | function handleRangeChange(_: unknown, dateStrings: string[]) { |
| | | queryForm.beginDate = dateStrings[0] || undefined; |
| | | queryForm.endDate = dateStrings[1] || undefined; |
| | | } |
| | | |
| | | function resetQuery() { |
| | | queryForm.beginDate = undefined; |
| | | queryForm.endDate = undefined; |
| | | queryForm.workOrderType = undefined; |
| | | loadSummary(); |
| | | } |
| | | |
| | | onMounted(loadSummary); |
| | | </script> |
| | | |
| | | <template> |
| | | <Page> |
| | | <Card class="mb-4"> |
| | | <Space wrap> |
| | | <DatePicker.RangePicker |
| | | :placeholder="['å¼å§æ¥æ', 'ç»ææ¥æ']" |
| | | value-format="YYYY-MM-DD" |
| | | @change="handleRangeChange" |
| | | /> |
| | | <Select |
| | | v-model:value="queryForm.workOrderType" |
| | | allow-clear |
| | | :options="workOrderTypeOptions" |
| | | placeholder="å·¥åç±»å" |
| | | style="width: 160px" |
| | | /> |
| | | <Button type="primary" :loading="loading" @click="loadSummary"> |
| | | æ¥è¯¢ |
| | | </Button> |
| | | <Button @click="resetQuery">éç½®</Button> |
| | | </Space> |
| | | </Card> |
| | | |
| | | <Row :gutter="16" class="mb-4"> |
| | | <Col :span="8"> |
| | | <Card> |
| | | <div class="text-sm text-gray-500">累计æ¥å·¥æ°é</div> |
| | | <div class="mt-2 text-2xl font-bold"> |
| | | {{ summary.totalFeedbackQuantity ?? 0 }} |
| | | </div> |
| | | </Card> |
| | | </Col> |
| | | <Col :span="8"> |
| | | <Card> |
| | | <div class="text-sm text-gray-500">ç´¯è®¡åæ ¼æ°é</div> |
| | | <div class="mt-2 text-2xl font-bold text-green-600"> |
| | | {{ summary.totalQualifiedQuantity ?? 0 }} |
| | | </div> |
| | | </Card> |
| | | </Col> |
| | | <Col :span="8"> |
| | | <Card> |
| | | <div class="text-sm text-gray-500">累计æ¥å·¥åæ°</div> |
| | | <div class="mt-2 text-2xl font-bold text-blue-600"> |
| | | {{ summary.totalFeedbackCount ?? 0 }} |
| | | </div> |
| | | </Card> |
| | | </Col> |
| | | </Row> |
| | | |
| | | <Card class="mb-4" title="æå·¥åç±»åæ±æ»"> |
| | | <Table |
| | | row-key="workOrderType" |
| | | :data-source="summary.byType ?? []" |
| | | :loading="loading" |
| | | :pagination="false" |
| | | size="middle" |
| | | > |
| | | <Table.Column title="å·¥åç±»å" data-index="workOrderTypeName"> |
| | | <template #default="{ record }"> |
| | | <Tag color="blue">{{ record.workOrderTypeName }}</Tag> |
| | | </template> |
| | | </Table.Column> |
| | | <Table.Column |
| | | title="æ¥å·¥æ°é" |
| | | data-index="feedbackQuantity" |
| | | align="right" |
| | | /> |
| | | <Table.Column |
| | | title="åæ ¼æ°é" |
| | | data-index="qualifiedQuantity" |
| | | align="right" |
| | | /> |
| | | <Table.Column title="æ¥å·¥åæ°" data-index="feedbackCount" align="right" /> |
| | | </Table> |
| | | </Card> |
| | | |
| | | <Card title="ææ¥ææ±æ»"> |
| | | <Table |
| | | row-key="date" |
| | | :data-source="summary.byDate ?? []" |
| | | :loading="loading" |
| | | :pagination="false" |
| | | size="middle" |
| | | > |
| | | <Table.Column title="æ¥æ" data-index="date" /> |
| | | <Table.Column |
| | | title="æ¥å·¥æ°é" |
| | | data-index="feedbackQuantity" |
| | | align="right" |
| | | /> |
| | | <Table.Column |
| | | title="åæ ¼æ°é" |
| | | data-index="qualifiedQuantity" |
| | | align="right" |
| | | /> |
| | | <Table.Column title="æ¥å·¥åæ°" data-index="feedbackCount" align="right" /> |
| | | </Table> |
| | | </Card> |
| | | </Page> |
| | | </template> |
| | |
| | | rules: z.string().min(1, 'å·¥åºåç§°ä¸è½ä¸ºç©º').max(100), |
| | | }, |
| | | { |
| | | fieldName: 'type', |
| | | label: 'çµåå·¥èºåç±»', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.MES_PRO_PROCESS_TYPE, 'number'), |
| | | placeholder: 'è¯·éæ©çµåå·¥èºåç±»', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'status', |
| | | label: 'ç¶æ', |
| | | component: 'RadioGroup', |
| | |
| | | }, |
| | | { field: 'name', title: 'å·¥åºåç§°', minWidth: 180 }, |
| | | { |
| | | field: 'type', |
| | | title: 'çµåå·¥èºåç±»', |
| | | width: 120, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_PRO_PROCESS_TYPE }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'status', |
| | | title: 'ç¶æ', |
| | | width: 100, |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | |
| | | import { getRangePickerDefaultProps } from '#/utils'; |
| | | |
| | | /** 表åç±»å */ |
| | | export type FormType = 'create' | 'detail' | 'edit'; |
| | | |
| | | /** ç¶æå¸¸é */ |
| | | export const TEST_STATUS = { |
| | | DRAFT: 0, |
| | | SUBMITTED: 10, |
| | | FINISHED: 20, |
| | | }; |
| | | |
| | | /** 表åçé
置项 */ |
| | | export function useFormSchema(formType: FormType): VbenFormSchema[] { |
| | | const isReadonly = formType === 'detail'; |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | | component: 'Input', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'code', |
| | | label: 'åæ®ç¼ç ', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: 'ç³»ç»èªå¨çæ', |
| | | disabled: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'name', |
| | | label: 'åæ®åç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥åæ®åç§°', |
| | | disabled: isReadonly, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'testType', |
| | | label: 'æ£æµç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.MES_QC_OUTSOURCE_TEST_TYPE, 'number'), |
| | | placeholder: 'è¯·éæ©æ£æµç±»å', |
| | | disabled: isReadonly, |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'itemId', |
| | | label: 'æ£æµå¯¹è±¡', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: 'æ£æµå¯¹è±¡ï¼ç©æ/设å¤ï¼', |
| | | disabled: isReadonly, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'testOrg', |
| | | label: 'æ£æµæºæ', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥æ£æµæºæ', |
| | | disabled: isReadonly, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'testDate', |
| | | label: 'æ£æµæ¥æ', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | placeholder: 'éæ©æ£æµæ¥æ', |
| | | showTime: true, |
| | | format: 'YYYY-MM-DD HH:mm:ss', |
| | | valueFormat: 'YYYY-MM-DD HH:mm:ss', |
| | | disabled: isReadonly, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'result', |
| | | label: 'æ£æµç»æ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.MES_QC_OUTSOURCE_TEST_RESULT, 'number'), |
| | | placeholder: 'è¯·éæ©æ£æµç»æ', |
| | | disabled: isReadonly, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'reportNo', |
| | | label: 'æ¥åç¼å·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥æ£æµæ¥åç¼å·', |
| | | disabled: isReadonly, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å¤æ³¨', |
| | | autoSize: { minRows: 1, maxRows: 1 }, |
| | | disabled: isReadonly, |
| | | }, |
| | | formItemClass: 'col-span-2', |
| | | }, |
| | | { |
| | | fieldName: 'blobIds', |
| | | label: 'æ£æµæ¥å/èµè´¨æä»¶', |
| | | component: 'FileUpload', |
| | | componentProps: { |
| | | valueKey: 'id', |
| | | maxNumber: 10, |
| | | multiple: true, |
| | | disabled: isReadonly, |
| | | }, |
| | | formItemClass: 'col-span-3', |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çæç´¢è¡¨å */ |
| | | export function useGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'code', |
| | | label: 'åæ®ç¼ç ', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥åæ®ç¼ç ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'name', |
| | | label: 'åæ®åç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥åæ®åç§°', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'testType', |
| | | label: 'æ£æµç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.MES_QC_OUTSOURCE_TEST_TYPE, 'number'), |
| | | placeholder: 'è¯·éæ©æ£æµç±»å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'result', |
| | | label: 'æ£æµç»æ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.MES_QC_OUTSOURCE_TEST_RESULT, 'number'), |
| | | placeholder: 'è¯·éæ©æ£æµç»æ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'status', |
| | | label: 'ç¶æ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: [ |
| | | { label: 'è稿', value: TEST_STATUS.DRAFT }, |
| | | { label: 'å·²æäº¤', value: TEST_STATUS.SUBMITTED }, |
| | | { label: '已宿', value: TEST_STATUS.FINISHED }, |
| | | ], |
| | | placeholder: 'è¯·éæ©ç¶æ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'testDate', |
| | | label: 'æ£æµæ¥æ', |
| | | component: 'RangePicker', |
| | | componentProps: getRangePickerDefaultProps(), |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çè¡¨æ ¼å */ |
| | | export function useGridColumns(): VxeTableGridOptions['columns'] { |
| | | return [ |
| | | { type: 'checkbox', width: 50 }, |
| | | { type: 'seq', title: 'åºå·', width: 60 }, |
| | | { |
| | | field: 'code', |
| | | title: 'åæ®ç¼ç ', |
| | | minWidth: 150, |
| | | slots: { default: 'code' }, |
| | | }, |
| | | { |
| | | field: 'name', |
| | | title: 'åæ®åç§°', |
| | | minWidth: 180, |
| | | }, |
| | | { |
| | | field: 'testType', |
| | | title: 'æ£æµç±»å', |
| | | width: 110, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_QC_OUTSOURCE_TEST_TYPE }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'itemName', |
| | | title: 'æ£æµå¯¹è±¡', |
| | | minWidth: 140, |
| | | }, |
| | | { |
| | | field: 'testOrg', |
| | | title: 'æ£æµæºæ', |
| | | minWidth: 160, |
| | | }, |
| | | { |
| | | field: 'testDate', |
| | | title: 'æ£æµæ¥æ', |
| | | width: 170, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | field: 'result', |
| | | title: 'æ£æµç»æ', |
| | | width: 100, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_QC_OUTSOURCE_TEST_RESULT }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'status', |
| | | title: 'ç¶æ', |
| | | width: 100, |
| | | slots: { default: 'status' }, |
| | | }, |
| | | { |
| | | field: 'action', |
| | | title: 'æä½', |
| | | width: 260, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesQcOutsourceTestApi } from '#/api/mes/qc/outsourcetest'; |
| | | |
| | | import { ref } from 'vue'; |
| | | |
| | | import { Page, useVbenModal } from '@vben/common-ui'; |
| | | import { isEmpty } from '@vben/utils'; |
| | | |
| | | import { message, Tag } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | deleteTest, |
| | | finishTest, |
| | | getTestPage, |
| | | submitTest, |
| | | } from '#/api/mes/qc/outsourcetest'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { TEST_STATUS, useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | |
| | | /** MES å§å¤æ£æµ/è¯éªåå表 */ |
| | | defineOptions({ name: 'MesQcOutsourceTest' }); |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | function handleCreate() { |
| | | formModalApi.setData({ formType: 'create' }).open(); |
| | | } |
| | | |
| | | function handleEdit(row: MesQcOutsourceTestApi.OutsourceTest) { |
| | | formModalApi.setData({ formType: 'edit', id: row.id }).open(); |
| | | } |
| | | |
| | | function handleDetail(row: MesQcOutsourceTestApi.OutsourceTest) { |
| | | formModalApi.setData({ formType: 'detail', id: row.id }).open(); |
| | | } |
| | | |
| | | async function handleDelete(ids: number[]) { |
| | | const hideLoading = message.loading({ |
| | | content: $t('ui.actionMessage.deleting'), |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await deleteTest(ids); |
| | | message.success($t('ui.actionMessage.deleteSuccess')); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | async function handleSubmit(row: MesQcOutsourceTestApi.OutsourceTest) { |
| | | await submitTest(row.id!); |
| | | message.success('å·²æäº¤'); |
| | | handleRefresh(); |
| | | } |
| | | |
| | | async function handleFinish(row: MesQcOutsourceTestApi.OutsourceTest) { |
| | | await finishTest(row.id!); |
| | | message.success('已宿'); |
| | | handleRefresh(); |
| | | } |
| | | |
| | | const checkedIds = ref<number[]>([]); |
| | | function handleRowCheckboxChange({ |
| | | records, |
| | | }: { |
| | | records: MesQcOutsourceTestApi.OutsourceTest[]; |
| | | }) { |
| | | checkedIds.value = records.map((item) => item.id!); |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useGridColumns(), |
| | | height: 'auto', |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => { |
| | | return await getTestPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }); |
| | | }, |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<MesQcOutsourceTestApi.OutsourceTest>, |
| | | gridEvents: { |
| | | checkboxAll: handleRowCheckboxChange, |
| | | checkboxChange: handleRowCheckboxChange, |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <FormModal @success="handleRefresh" /> |
| | | <Grid table-title="å§å¤æ£æµ/è¯éªåå表"> |
| | | <template #toolbar-tools> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('ui.actionTitle.create', ['å§å¤æ£æµ/è¯éªå']), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['mes:qc-outsource-test:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | { |
| | | label: 'æ¹éå é¤', |
| | | type: 'primary', |
| | | danger: true, |
| | | disabled: isEmpty(checkedIds), |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['mes:qc-outsource-test:delete'], |
| | | popConfirm: { |
| | | title: `æ¯å¦å 餿é䏿°æ®ï¼`, |
| | | confirm: handleDelete.bind(null, checkedIds), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #code="{ row }"> |
| | | <a class="link" @click="handleDetail(row)">{{ row.code }}</a> |
| | | </template> |
| | | <template #status="{ row }"> |
| | | <Tag v-if="row.status === TEST_STATUS.DRAFT" color="default">è稿</Tag> |
| | | <Tag v-else-if="row.status === TEST_STATUS.SUBMITTED" color="processing">å·²æäº¤</Tag> |
| | | <Tag v-else-if="row.status === TEST_STATUS.FINISHED" color="success">已宿</Tag> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['mes:qc-outsource-test:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['mes:qc-outsource-test:update'], |
| | | ifShow: row.status === TEST_STATUS.DRAFT, |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: 'æäº¤', |
| | | type: 'link', |
| | | auth: ['mes:qc-outsource-test:update'], |
| | | ifShow: row.status === TEST_STATUS.DRAFT, |
| | | popConfirm: { |
| | | title: '确认æäº¤è¯¥åæ®ï¼', |
| | | confirm: handleSubmit.bind(null, row), |
| | | }, |
| | | }, |
| | | { |
| | | label: '宿', |
| | | type: 'link', |
| | | auth: ['mes:qc-outsource-test:update'], |
| | | ifShow: row.status === TEST_STATUS.SUBMITTED, |
| | | popConfirm: { |
| | | title: 'ç¡®è®¤å®æè¯¥åæ®ï¼', |
| | | confirm: handleFinish.bind(null, row), |
| | | }, |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['mes:qc-outsource-test:delete'], |
| | | ifShow: row.status === TEST_STATUS.DRAFT, |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [row.code]), |
| | | confirm: handleDelete.bind(null, [row.id!]), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { MesQcOutsourceTestApi } from '#/api/mes/qc/outsourcetest'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { createTest, getTest, updateTest } from '#/api/mes/qc/outsourcetest'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import type { FormType } from '../data'; |
| | | import { useFormSchema } from '../data'; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formData = ref<MesQcOutsourceTestApi.OutsourceTest>(); |
| | | const formType = ref<FormType>('create'); |
| | | |
| | | const getTitle = computed(() => { |
| | | if (formType.value === 'create') { |
| | | return $t('ui.actionTitle.create', ['å§å¤æ£æµ/è¯éªå']); |
| | | } else if (formType.value === 'edit') { |
| | | return $t('ui.actionTitle.edit', ['å§å¤æ£æµ/è¯éªå']); |
| | | } else { |
| | | return 'å§å¤æ£æµ/è¯éªå详æ
'; |
| | | } |
| | | }); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | labelWidth: 140, |
| | | }, |
| | | wrapperClass: 'grid-cols-3', |
| | | layout: 'vertical', |
| | | schema: useFormSchema(formType.value), |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | const data = |
| | | (await formApi.getValues()) as MesQcOutsourceTestApi.OutsourceTest; |
| | | try { |
| | | await (formType.value === 'create' |
| | | ? createTest(data) |
| | | : updateTest(data)); |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | return; |
| | | } |
| | | const data = modalApi.getData<{ formType: FormType; id?: number }>(); |
| | | formType.value = data.formType; |
| | | formApi.setDisabled(formType.value === 'detail'); |
| | | formApi.updateSchema(useFormSchema(formType.value)); |
| | | if (!data || !data.id) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | formData.value = await getTest(data.id); |
| | | await formApi.setValues(formData.value); |
| | | if (formData.value?.attachmentList?.length) { |
| | | const blobIds = formData.value.attachmentList.map((item) => ({ |
| | | uid: String(item.id), |
| | | name: item.name || '', |
| | | url: item.url || '', |
| | | status: 'done', |
| | | id: item.id, |
| | | })); |
| | | await formApi.setFieldValue('blobIds', blobIds); |
| | | } |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal :title="getTitle" class="w-2/3" :show-confirm-button="formType !== 'detail'"> |
| | | <Form class="mx-3" /> |
| | | </Modal> |
| | | </template> |
| | |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'issueType', |
| | | label: 'åæ®ç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.MES_WM_PRODUCT_ISSUE_TYPE, 'number'), |
| | | placeholder: 'è¯·éæ©åæ®ç±»å', |
| | | }, |
| | | dependencies: { |
| | | triggerFields: ['status'], |
| | | show: (values) => values.status === undefined || values.status === 0, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'requiredTime', |
| | | label: 'éæ±æ¶é´', |
| | | component: 'DatePicker', |
| | |
| | | minWidth: 150, |
| | | }, |
| | | { |
| | | field: 'issueType', |
| | | title: 'åæ®ç±»å', |
| | | width: 100, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_WM_PRODUCT_ISSUE_TYPE }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'workOrderCode', |
| | | title: 'ç产订å', |
| | | minWidth: 140, |
| | |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesWmStockTakingTaskApi } from '#/api/mes/wm/stocktaking/task'; |
| | | |
| | | import { ref } from 'vue'; |
| | | |
| | | import { Page, useVbenModal } from '@vben/common-ui'; |
| | | import { MesWmStockTakingTaskStatusEnum } from '@vben/constants'; |
| | | import { downloadFileFromBlobPart } from '@vben/utils'; |
| | |
| | | exportStockTaking, |
| | | getStockTakingPage, |
| | | } from '#/api/mes/wm/stocktaking/task'; |
| | | import { |
| | | importStockTakingQuantity, |
| | | importStockTakingQuantityTemplate, |
| | | } from '#/api/wls/stocktaking/task/line'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | |
| | | downloadFileFromBlobPart({ fileName: 'çç¹ä»»å¡.xls', source: data }); |
| | | } |
| | | |
| | | /** ä¸è½½çç¹å¯¼å
¥æ¨¡æ¿ */ |
| | | async function handleImportTemplate() { |
| | | const data = await importStockTakingQuantityTemplate(); |
| | | downloadFileFromBlobPart({ fileName: 'çç¹å®çæ°å¯¼å
¥æ¨¡æ¿.xls', source: data }); |
| | | } |
| | | |
| | | const importFileRef = ref<HTMLInputElement>(); |
| | | const importTaskId = ref<number>(); |
| | | |
| | | /** 触å导å
¥æä»¶éæ© */ |
| | | function handleImport(row: MesWmStockTakingTaskApi.StockTakingTask) { |
| | | importTaskId.value = row.id!; |
| | | importFileRef.value?.click(); |
| | | } |
| | | |
| | | /** 导å
¥å®çæ°æä»¶éæ©åä¸ä¼ */ |
| | | async function handleImportFileChange(event: Event) { |
| | | const file = (event.target as HTMLInputElement).files?.[0]; |
| | | if (!file || !importTaskId.value) { |
| | | return; |
| | | } |
| | | const hideLoading = message.loading({ content: 'æ£å¨å¯¼å
¥å®çæ°...', duration: 0 }); |
| | | try { |
| | | const result = await importStockTakingQuantity(importTaskId.value, file); |
| | | message.success(`导å
¥å®æï¼æå ${result.successCount ?? 0} æ¡ï¼å¤±è´¥ ${result.failureCount ?? 0} æ¡`); |
| | | if (result.failureMessages?.length) { |
| | | message.warning(result.failureMessages.slice(0, 5).join('ï¼')); |
| | | } |
| | | handleRefresh(); |
| | | } finally { |
| | | (event.target as HTMLInputElement).value = ''; |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | |
| | | auth: ['mes:wm-stock-taking-task:export'], |
| | | onClick: handleExport, |
| | | }, |
| | | { |
| | | label: '导å
¥æ¨¡æ¿', |
| | | type: 'primary', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | | auth: ['mes:wm-stock-taking-task:query'], |
| | | onClick: handleImportTemplate, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | |
| | | onClick: handleExecute.bind(null, row), |
| | | }, |
| | | { |
| | | label: '导å
¥å®çæ°', |
| | | type: 'link', |
| | | icon: ACTION_ICON.UPLOAD, |
| | | auth: ['mes:wm-stock-taking-task:update'], |
| | | ifShow: row.status === StatusEnum.APPROVING, |
| | | onClick: handleImport.bind(null, row), |
| | | }, |
| | | { |
| | | label: 'åæ¶', |
| | | type: 'link', |
| | | danger: true, |
| | |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | <input |
| | | ref="importFileRef" |
| | | class="hidden" |
| | | type="file" |
| | | accept=".xls,.xlsx" |
| | | @change="handleImportFileChange" |
| | | /> |
| | | </Page> |
| | | </template> |
| | |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'type', |
| | | label: 'åºåºç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.MES_WM_WAREHOUSE_TYPE, 'number'), |
| | | placeholder: 'è¯·éæ©åºåºç±»å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'area', |
| | | label: 'é¢ç§¯ï¼ã¡ï¼', |
| | | component: 'InputNumber', |
| | |
| | | minWidth: 160, |
| | | }, |
| | | { |
| | | field: 'type', |
| | | title: 'åºåºç±»å', |
| | | width: 110, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_WM_WAREHOUSE_TYPE }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'area', |
| | | title: 'é¢ç§¯ï¼ã¡ï¼', |
| | | width: 100, |
| | |
| | | import { h } from 'vue'; |
| | | |
| | | import { DICT_TYPE, MesAutoCodeRuleCode } from '@vben/constants'; |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | |
| | | import { Button } from 'ant-design-vue'; |
| | | |
| | |
| | | placeholder: '请è¾å
¥ä»åºåç§°', |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'type', |
| | | label: 'ä»åºç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.MES_WM_WAREHOUSE_TYPE, 'number'), |
| | | placeholder: 'è¯·éæ©ä»åºç±»å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'chargeUserId', |
| | |
| | | minWidth: 160, |
| | | }, |
| | | { |
| | | field: 'type', |
| | | title: 'ä»åºç±»å', |
| | | width: 110, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_WM_WAREHOUSE_TYPE }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'address', |
| | | title: 'ä»åºå°å', |
| | | minWidth: 180, |
| | |
| | | proxy: { |
| | | "/admin-api": { |
| | | changeOrigin: true, |
| | | target: "http://192.168.0.10:48080", |
| | | target: "http://127.0.0.1:48080", |
| | | ws: true, |
| | | }, |
| | | }, |