银川
1.物料管理页面批次属性功能联调
2.库存现有量添加自定义出库入库功能
| | |
| | | VITE_BASE=/ |
| | | |
| | | # 请æ±è·¯å¾ |
| | | VITE_BASE_URL=http://127.0.0.1:48080 |
| | | VITE_BASE_URL=http://36.213.180.217:9500 |
| | | # æ¥å£å°å |
| | | VITE_GLOB_API_URL=http://127.0.0.1:48080/admin-api |
| | | VITE_GLOB_API_URL=http://36.213.180.217:9500/admin-api |
| | | # æä»¶ä¸ä¼ ç±»åï¼server - å端ä¸ä¼ ï¼ client - å端ç´è¿ä¸ä¼ ï¼ä»
æ¯æS3æå¡ |
| | | VITE_UPLOAD_TYPE=server |
| | | |
| | |
| | | |
| | | /** è·åç§æ·å表 */ |
| | | export async function getTenantSimpleList() { |
| | | return requestClient.get<AuthApi.TenantResult[]>( |
| | | `/system/tenant/simple-list`, |
| | | ); |
| | | // ç§æ·æ¥å£å·²ç¦ç¨ï¼è¿å空æ°ç» |
| | | return Promise.resolve([]); |
| | | // return requestClient.get<AuthApi.TenantResult[]>( |
| | | // `/system/tenant/simple-list`, |
| | | // ); |
| | | } |
| | | |
| | | /** 使ç¨ç§æ·ååï¼è·å¾ç§æ·ä¿¡æ¯ */ |
| | | export async function getTenantByWebsite(website: string) { |
| | | return requestClient.get<AuthApi.TenantResult>( |
| | | `/system/tenant/get-by-website?website=${website}`, |
| | | ); |
| | | // ç§æ·æ¥å£å·²ç¦ç¨ï¼è¿å空对象 |
| | | return Promise.resolve({} as AuthApi.TenantResult); |
| | | // return requestClient.get<AuthApi.TenantResult>( |
| | | // `/system/tenant/get-by-website?website=${website}`, |
| | | // ); |
| | | } |
| | | |
| | | /** è·åéªè¯ç */ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '#/packages/effects/request/src'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace MdmItemBatchConfigApi { |
| | | /** ç©ææ¹æ¬¡é
ç½®ï¼ä»
ä¿ç7ä¸ªåæ®µï¼ */ |
| | | export interface ItemBatchConfig { |
| | | id?: number; // é
ç½®ID |
| | | itemId: number; // ç©æID |
| | | produceDateFlag?: boolean; // çäº§æ¥æå¿
å¡« |
| | | expireDateFlag?: boolean; // æææå¿
å¡« |
| | | receiptDateFlag?: boolean; // å
¥åºæ¥æå¿
å¡« |
| | | vendorFlag?: boolean; // ä¾åºåå¿
å¡« |
| | | purchaseOrderCodeFlag?: boolean; // éè´è®¢åå·å¿
å¡« |
| | | lotNumberFlag?: boolean; // ç产æ¹å·å¿
å¡« |
| | | qualityStatusFlag?: boolean; // è´¨éç¶æå¿
å¡« |
| | | } |
| | | } |
| | | |
| | | /** æ ¹æ®ç©æIDè·åæ¹æ¬¡é
ç½® */ |
| | | export function getItemBatchConfigByItemId(itemId: number) { |
| | | return requestClient.get<MdmItemBatchConfigApi.ItemBatchConfig | null>( |
| | | '/mes/md/item-batch-config/get-by-item-id', |
| | | { params: { itemId } }, |
| | | ); |
| | | } |
| | | |
| | | /** ä¿åæ¹æ¬¡é
ç½®ï¼æ°å¢/æ´æ°ï¼ */ |
| | | export function saveItemBatchConfig(data: MdmItemBatchConfigApi.ItemBatchConfig) { |
| | | return requestClient.post<number>('/mes/md/item-batch-config/save', data); |
| | | } |
| | | |
| | | /** å 餿¹æ¬¡é
ç½® */ |
| | | export function deleteItemBatchConfig(id: number) { |
| | | return requestClient.delete(`/mes/md/item-batch-config/delete?id=${id}`); |
| | | } |
| | |
| | | vendorId?: number; // ä¾åºåç¼å· |
| | | vendorName?: string; // ä¾åºååç§° |
| | | quantity?: number; // å¨åºæ°é |
| | | frozenQuantity?: number; // å»ç»æ°é |
| | | reservedQuantity?: number; // å ç¨é |
| | | inTransitQuantity?: number; // å¨éé |
| | | availableQuantity?: number; // å¯ç¨é |
| | | receiptTime?: string; // å
¥åºæ¥æ |
| | | frozen?: boolean; // æ¯å¦å»ç» |
| | | createTime?: Date; // å建æ¶é´ |
| | |
| | | params, |
| | | }); |
| | | } |
| | | |
| | | /** åºåè°æ´ï¼èªå®ä¹åºå
¥åºï¼- å
¥åº */ |
| | | export interface MaterialStockAdjustInParams { |
| | | itemId: number; // ç©æID |
| | | warehouseId: number; // ä»åºID |
| | | locationId: number; // åºåºID |
| | | areaId: number; // åºä½ID |
| | | batchId?: number; // æ¹æ¬¡IDï¼éæ©å·²ææ¹æ¬¡æ¶ä¼ å
¥ï¼ |
| | | batchCode?: string; // æ¹æ¬¡å·ï¼æ°å»ºæ¹æ¬¡æ¶ä¼ å
¥ï¼ |
| | | produceDate?: string; // çäº§æ¥æï¼æ°å»ºæ¹æ¬¡æ¶ä¼ å
¥ï¼ |
| | | expireDate?: string; // æææï¼æ°å»ºæ¹æ¬¡æ¶ä¼ å
¥ï¼ |
| | | vendorId?: number; // ä¾åºåID |
| | | quantity: number; // å
¥åºæ°éï¼å¿
须大äº0ï¼ |
| | | reason?: string; // å
¥åºåå |
| | | } |
| | | |
| | | /** åºåè°æ´ï¼èªå®ä¹åºå
¥åºï¼- åºåº */ |
| | | export interface MaterialStockAdjustOutParams { |
| | | itemId: number; // ç©æID |
| | | warehouseId: number; // ä»åºID |
| | | locationId: number; // åºåºID |
| | | areaId: number; // åºä½ID |
| | | batchId?: number; // æ¹æ¬¡ID |
| | | batchCode?: string; // æ¹æ¬¡å· |
| | | vendorId?: number; // ä¾åºåID |
| | | quantity: number; // åºåºæ°éï¼å¿
须大äº0ï¼ |
| | | reason?: string; // åºåºåå |
| | | } |
| | | |
| | | /** èªå®ä¹å
¥åº */ |
| | | export function adjustMaterialStockIn(data: MaterialStockAdjustInParams) { |
| | | return requestClient.post<number>('/mes/wm/material-stock/adjust-in', data); |
| | | } |
| | | |
| | | /** èªå®ä¹åºåº */ |
| | | export function adjustMaterialStockOut(data: MaterialStockAdjustOutParams) { |
| | | return requestClient.post<number>('/mes/wm/material-stock/adjust-out', data); |
| | | } |
| | | |
| | | /** åºåè°æ´ï¼æ£æ°=å
¥åºï¼è´æ°=åºåºï¼- æ§æ¥å£ï¼ä¿çå
¼å®¹ */ |
| | | export interface MaterialStockAdjustParams { |
| | | itemId: number; // ç©æID |
| | | warehouseId: number; // ä»åºID |
| | | locationId: number; // åºåºID |
| | | areaId: number; // åºä½ID |
| | | batchId?: number; // æ¹æ¬¡ID |
| | | batchCode?: string; // æ¹æ¬¡å· |
| | | vendorId?: number; // ä¾åºåID |
| | | quantity: number; // è°æ´æ°éï¼æ£æ°=å
¥åºï¼è´æ°=åºåºï¼ |
| | | reason?: string; // è°æ´åå |
| | | } |
| | | |
| | | /** åºåè°æ´ï¼æ£æ°=å
¥åºï¼è´æ°=åºåºï¼ - æ§æ¥å£ï¼ä¿çå
¼å®¹ */ |
| | | export function adjustMaterialStock(data: MaterialStockAdjustParams) { |
| | | return requestClient.post<number>('/mes/wm/material-stock/adjust', data); |
| | | } |
| | |
| | | id?: number; // è¡ç¼å· |
| | | salesId?: number; // åºåºåç¼å· |
| | | noticeLineId?: number; // åè´§éç¥åè¡ç¼å· |
| | | saleOrderItemId?: number; // éå®è®¢åæç»IDï¼ç¨äºè¿½æº¯ï¼ |
| | | itemId?: number; // ç©æç¼å· |
| | | itemCode?: string; // ç©æç¼ç |
| | | itemName?: string; // ç©æåç§° |
| | |
| | | id?: number; // éç¥åç¼å· |
| | | code?: string; // éç¥åç¼å· |
| | | name?: string; // éç¥ååç§° |
| | | saleOrderId?: number; // éå®è®¢åç¼å· |
| | | salesOrderCode?: string; // éå®è®¢åç¼å· |
| | | clientId?: number; // 客æ·ç¼å· |
| | | clientCode?: string; // 客æ·ç¼ç |
| | |
| | | recipientTelephone?: string; // èç³»æ¹å¼ |
| | | recipientAddress?: string; // æ¶è´§å°å |
| | | status?: number; // åæ®ç¶æ |
| | | outStatus?: number; // åºåºç¶æï¼0-æªåºåºï¼1-é¨ååºåºï¼2-å
¨é¨åºåº |
| | | remark?: string; // 夿³¨ |
| | | createTime?: Date; // å建æ¶é´ |
| | | } |
| | |
| | | params, |
| | | }); |
| | | } |
| | | |
| | | /** ä»éå®è®¢åçæåè´§éç¥å */ |
| | | export function generateFromSaleOrder(saleOrderId: number) { |
| | | return requestClient.post<number>('/mes/wm/sales-notice/generate-from-sale-order', { |
| | | saleOrderId, |
| | | }); |
| | | } |
| | | |
| | | /** ä»åè´§éç¥åçæéå®åºåºå */ |
| | | export function generateProductSales(id: number) { |
| | | return requestClient.post<number>('/mes/wm/sales-notice/generate-product-sales', null, { |
| | | params: { id }, |
| | | }); |
| | | } |
| | |
| | | export interface SalesNoticeLine { |
| | | id?: number; // è¡ç¼å· |
| | | noticeId?: number; // åè´§éç¥åç¼å· |
| | | saleOrderItemId?: number; // éå®è®¢åæç»IDï¼ç¨äºè¿½æº¯ï¼ |
| | | itemId?: number; // ç©æç¼å· |
| | | itemCode?: string; // ç©æç¼ç |
| | | itemName?: string; // ç©æåç§° |
| | |
| | | batchId?: number; // æ¹æ¬¡ç¼å· |
| | | batchCode?: string; // æ¹æ¬¡å· |
| | | quantity?: number; // åè´§æ°é |
| | | outCount?: number; // å·²åºåºæ°é |
| | | oqcCheckFlag?: boolean; // æ¯å¦æ£éª |
| | | remark?: string; // 夿³¨ |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | /** ç§æ·å¥é¤å表 */ |
| | | // ç§æ·å¥é¤æ¥å£å·²ç¦ç¨ |
| | | // /** ç§æ·å¥é¤å表 */ |
| | | // export function getTenantPackagePage(params: PageParam) { |
| | | // return requestClient.get<PageResult<SystemTenantPackageApi.TenantPackage>>( |
| | | // '/system/tenant-package/page', |
| | | // { params }, |
| | | // ); |
| | | // } |
| | | |
| | | // /** æ¥è¯¢ç§æ·å¥é¤è¯¦æ
*/ |
| | | // export function getTenantPackage(id: number) { |
| | | // return requestClient.get(`/system/tenant-package/get?id=${id}`); |
| | | // } |
| | | |
| | | // /** æ°å¢ç§æ·å¥é¤ */ |
| | | // export function createTenantPackage( |
| | | // data: SystemTenantPackageApi.TenantPackage, |
| | | // ) { |
| | | // return requestClient.post('/system/tenant-package/create', data); |
| | | // } |
| | | |
| | | // /** ä¿®æ¹ç§æ·å¥é¤ */ |
| | | // export function updateTenantPackage( |
| | | // data: SystemTenantPackageApi.TenantPackage, |
| | | // ) { |
| | | // return requestClient.put('/system/tenant-package/update', data); |
| | | // } |
| | | |
| | | // /** å é¤ç§æ·å¥é¤ */ |
| | | // export function deleteTenantPackage(id: number) { |
| | | // return requestClient.delete(`/system/tenant-package/delete?id=${id}`); |
| | | // } |
| | | |
| | | // /** æ¹éå é¤ç§æ·å¥é¤ */ |
| | | // export function deleteTenantPackageList(ids: number[]) { |
| | | // return requestClient.delete( |
| | | // `/system/tenant-package/delete-list?ids=${ids.join(',')}`, |
| | | // ); |
| | | // } |
| | | |
| | | // /** è·åç§æ·å¥é¤ç²¾ç®ä¿¡æ¯å表 */ |
| | | // export function getTenantPackageList() { |
| | | // return requestClient.get<SystemTenantPackageApi.TenantPackage[]>( |
| | | // '/system/tenant-package/get-simple-list', |
| | | // ); |
| | | // } |
| | | |
| | | // æä¾ç©ºå½æ°ä»¥é¿å
å¼ç¨é误 |
| | | export function getTenantPackagePage(params: PageParam) { |
| | | return requestClient.get<PageResult<SystemTenantPackageApi.TenantPackage>>( |
| | | '/system/tenant-package/page', |
| | | { params }, |
| | | ); |
| | | return Promise.resolve({ list: [], total: 0 }); |
| | | } |
| | | |
| | | /** æ¥è¯¢ç§æ·å¥é¤è¯¦æ
*/ |
| | | export function getTenantPackage(id: number) { |
| | | return requestClient.get(`/system/tenant-package/get?id=${id}`); |
| | | return Promise.resolve({} as SystemTenantPackageApi.TenantPackage); |
| | | } |
| | | |
| | | /** æ°å¢ç§æ·å¥é¤ */ |
| | | export function createTenantPackage( |
| | | data: SystemTenantPackageApi.TenantPackage, |
| | | ) { |
| | | return requestClient.post('/system/tenant-package/create', data); |
| | | export function createTenantPackage(data: SystemTenantPackageApi.TenantPackage) { |
| | | return Promise.resolve({}); |
| | | } |
| | | |
| | | /** ä¿®æ¹ç§æ·å¥é¤ */ |
| | | export function updateTenantPackage( |
| | | data: SystemTenantPackageApi.TenantPackage, |
| | | ) { |
| | | return requestClient.put('/system/tenant-package/update', data); |
| | | export function updateTenantPackage(data: SystemTenantPackageApi.TenantPackage) { |
| | | return Promise.resolve({}); |
| | | } |
| | | |
| | | /** å é¤ç§æ·å¥é¤ */ |
| | | export function deleteTenantPackage(id: number) { |
| | | return requestClient.delete(`/system/tenant-package/delete?id=${id}`); |
| | | return Promise.resolve({}); |
| | | } |
| | | |
| | | /** æ¹éå é¤ç§æ·å¥é¤ */ |
| | | export function deleteTenantPackageList(ids: number[]) { |
| | | return requestClient.delete( |
| | | `/system/tenant-package/delete-list?ids=${ids.join(',')}`, |
| | | ); |
| | | return Promise.resolve({}); |
| | | } |
| | | |
| | | /** è·åç§æ·å¥é¤ç²¾ç®ä¿¡æ¯å表 */ |
| | | export function getTenantPackageList() { |
| | | return requestClient.get<SystemTenantPackageApi.TenantPackage[]>( |
| | | '/system/tenant-package/get-simple-list', |
| | | ); |
| | | return Promise.resolve([]); |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | /** ç§æ·å表 */ |
| | | // ç§æ·æ¥å£å·²ç¦ç¨ |
| | | // /** ç§æ·å表 */ |
| | | // export function getTenantPage(params: PageParam) { |
| | | // return requestClient.get<PageResult<SystemTenantApi.Tenant>>( |
| | | // '/system/tenant/page', |
| | | // { params }, |
| | | // ); |
| | | // } |
| | | |
| | | // /** è·åç§æ·ç²¾ç®ä¿¡æ¯å表 */ |
| | | // export function getSimpleTenantList() { |
| | | // return requestClient.get<SystemTenantApi.Tenant[]>( |
| | | // '/system/tenant/simple-list', |
| | | // ); |
| | | // } |
| | | |
| | | // /** æ¥è¯¢ç§æ·è¯¦æ
*/ |
| | | // export function getTenant(id: number) { |
| | | // return requestClient.get<SystemTenantApi.Tenant>( |
| | | // `/system/tenant/get?id=${id}`, |
| | | // ); |
| | | // } |
| | | |
| | | // /** è·åç§æ·ç²¾ç®ä¿¡æ¯å表 */ |
| | | // export function getTenantList() { |
| | | // return requestClient.get<SystemTenantApi.Tenant[]>( |
| | | // '/system/tenant/simple-list', |
| | | // ); |
| | | // } |
| | | |
| | | // /** æ°å¢ç§æ· */ |
| | | // export function createTenant(data: SystemTenantApi.Tenant) { |
| | | // return requestClient.post('/system/tenant/create', data); |
| | | // } |
| | | |
| | | // /** ä¿®æ¹ç§æ· */ |
| | | // export function updateTenant(data: SystemTenantApi.Tenant) { |
| | | // return requestClient.put('/system/tenant/update', data); |
| | | // } |
| | | |
| | | // /** å é¤ç§æ· */ |
| | | // export function deleteTenant(id: number) { |
| | | // return requestClient.delete(`/system/tenant/delete?id=${id}`); |
| | | // } |
| | | |
| | | // /** æ¹éå é¤ç§æ· */ |
| | | // export function deleteTenantList(ids: number[]) { |
| | | // return requestClient.delete( |
| | | // `/system/tenant/delete-list?ids=${ids.join(',')}`, |
| | | // ); |
| | | // } |
| | | |
| | | // /** 导åºç§æ· */ |
| | | // export function exportTenant(params: any) { |
| | | // return requestClient.download('/system/tenant/export-excel', { |
| | | // params, |
| | | // }); |
| | | // } |
| | | |
| | | // æä¾ç©ºå½æ°ä»¥é¿å
å¼ç¨é误 |
| | | export function getTenantPage(params: PageParam) { |
| | | return requestClient.get<PageResult<SystemTenantApi.Tenant>>( |
| | | '/system/tenant/page', |
| | | { params }, |
| | | ); |
| | | return Promise.resolve({ list: [], total: 0 }); |
| | | } |
| | | |
| | | /** è·åç§æ·ç²¾ç®ä¿¡æ¯å表 */ |
| | | export function getSimpleTenantList() { |
| | | return requestClient.get<SystemTenantApi.Tenant[]>( |
| | | '/system/tenant/simple-list', |
| | | ); |
| | | return Promise.resolve([]); |
| | | } |
| | | |
| | | /** æ¥è¯¢ç§æ·è¯¦æ
*/ |
| | | export function getTenant(id: number) { |
| | | return requestClient.get<SystemTenantApi.Tenant>( |
| | | `/system/tenant/get?id=${id}`, |
| | | ); |
| | | return Promise.resolve({} as SystemTenantApi.Tenant); |
| | | } |
| | | |
| | | /** è·åç§æ·ç²¾ç®ä¿¡æ¯å表 */ |
| | | export function getTenantList() { |
| | | return requestClient.get<SystemTenantApi.Tenant[]>( |
| | | '/system/tenant/simple-list', |
| | | ); |
| | | return Promise.resolve([]); |
| | | } |
| | | |
| | | /** æ°å¢ç§æ· */ |
| | | export function createTenant(data: SystemTenantApi.Tenant) { |
| | | return requestClient.post('/system/tenant/create', data); |
| | | return Promise.resolve({}); |
| | | } |
| | | |
| | | /** ä¿®æ¹ç§æ· */ |
| | | export function updateTenant(data: SystemTenantApi.Tenant) { |
| | | return requestClient.put('/system/tenant/update', data); |
| | | return Promise.resolve({}); |
| | | } |
| | | |
| | | /** å é¤ç§æ· */ |
| | | export function deleteTenant(id: number) { |
| | | return requestClient.delete(`/system/tenant/delete?id=${id}`); |
| | | return Promise.resolve({}); |
| | | } |
| | | |
| | | /** æ¹éå é¤ç§æ· */ |
| | | export function deleteTenantList(ids: number[]) { |
| | | return requestClient.delete( |
| | | `/system/tenant/delete-list?ids=${ids.join(',')}`, |
| | | ); |
| | | return Promise.resolve({}); |
| | | } |
| | | |
| | | /** 导åºç§æ· */ |
| | | export function exportTenant(params: any) { |
| | | return requestClient.download('/system/tenant/export-excel', { |
| | | params, |
| | | }); |
| | | return Promise.resolve(new Blob()); |
| | | } |
| | |
| | | APPROVED: MesOrderStatusConstants.APPROVED, |
| | | } as const; |
| | | |
| | | /** MES åè´§éç¥ååºåºç¶ææä¸¾ */ |
| | | export const MesWmSalesNoticeOutStatusEnum = { |
| | | NONE: 0, |
| | | PARTIAL: 1, |
| | | ALL: 2, |
| | | } as const; |
| | | |
| | | /** MES éå®éè´§åç¶ææä¸¾ */ |
| | | export const MesWmReturnSalesStatusEnum = { |
| | | PREPARE: MesOrderStatusConstants.DRAFT, |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { MdmItemBatchConfigApi } from '#/api/mes/md/item-batch-config'; |
| | | |
| | | import { computed, ref, watch } from 'vue'; |
| | | |
| | | import { Checkbox, Divider } from 'ant-design-vue'; |
| | | |
| | | import { |
| | | getItemBatchConfigByItemId, |
| | | saveItemBatchConfig, |
| | | } from '#/api/mes/md/item-batch-config'; |
| | | |
| | | const props = defineProps<{ |
| | | itemId?: number; |
| | | isBatchManaged?: boolean; |
| | | }>(); |
| | | |
| | | const emit = defineEmits<{ |
| | | change: [config: Partial<MdmItemBatchConfigApi.ItemBatchConfig>]; |
| | | }>(); |
| | | |
| | | // æ¹æ¬¡é
ç½®æ°æ® |
| | | const config = ref<Partial<MdmItemBatchConfigApi.ItemBatchConfig>>({ |
| | | produceDateFlag: false, |
| | | expireDateFlag: false, |
| | | receiptDateFlag: false, |
| | | vendorFlag: false, |
| | | purchaseOrderCodeFlag: false, |
| | | lotNumberFlag: false, |
| | | qualityStatusFlag: false, |
| | | }); |
| | | |
| | | // æ¯å¦å è½½ä¸ |
| | | const loading = ref(false); |
| | | |
| | | // æ¯å¦æ¾ç¤ºé
ç½®ï¼å¯ç¨æ¹æ¬¡ç®¡çæ¶æ¾ç¤ºï¼ |
| | | const visible = computed(() => props.isBatchManaged === true); |
| | | |
| | | // æ¹æ¬¡é
ç½®é项ï¼ä»
ä¿ç7ä¸ªåæ®µï¼ |
| | | const configOptions = [ |
| | | { key: 'produceDateFlag', label: 'çäº§æ¥æ' }, |
| | | { key: 'expireDateFlag', label: 'æææ' }, |
| | | { key: 'receiptDateFlag', label: 'å
¥åºæ¥æ' }, |
| | | { key: 'vendorFlag', label: 'ä¾åºå' }, |
| | | { key: 'purchaseOrderCodeFlag', label: 'éè´è®¢åå·' }, |
| | | { key: 'lotNumberFlag', label: 'ç产æ¹å·' }, |
| | | { key: 'qualityStatusFlag', label: 'è´¨éç¶æ' }, |
| | | ] as const; |
| | | |
| | | /** å è½½æ¹æ¬¡é
ç½® */ |
| | | async function loadConfig() { |
| | | if (!props.itemId || !props.isBatchManaged) { |
| | | return; |
| | | } |
| | | loading.value = true; |
| | | try { |
| | | const data = await getItemBatchConfigByItemId(props.itemId); |
| | | if (data) { |
| | | config.value = { ...config.value, ...data }; |
| | | } |
| | | } catch { |
| | | // æ é
ç½®æ¶ä¸æ¥é |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | } |
| | | |
| | | /** ä¿åæ¹æ¬¡é
ç½® */ |
| | | async function saveConfig(): Promise<number | undefined> { |
| | | if (!props.itemId || !props.isBatchManaged) { |
| | | return undefined; |
| | | } |
| | | const data: MdmItemBatchConfigApi.ItemBatchConfig = { |
| | | ...config.value as MdmItemBatchConfigApi.ItemBatchConfig, |
| | | itemId: props.itemId, |
| | | }; |
| | | const id = await saveItemBatchConfig(data); |
| | | config.value.id = id; |
| | | return id; |
| | | } |
| | | |
| | | /** è·åå½åé
ç½® */ |
| | | function getConfig(): Partial<MdmItemBatchConfigApi.ItemBatchConfig> { |
| | | return { ...config.value }; |
| | | } |
| | | |
| | | /** éç½®é
ç½® */ |
| | | function resetConfig() { |
| | | config.value = { |
| | | produceDateFlag: false, |
| | | expireDateFlag: false, |
| | | receiptDateFlag: false, |
| | | vendorFlag: false, |
| | | purchaseOrderCodeFlag: false, |
| | | lotNumberFlag: false, |
| | | qualityStatusFlag: false, |
| | | }; |
| | | } |
| | | |
| | | // çå¬ itemId ååï¼å è½½é
ç½® |
| | | watch( |
| | | () => [props.itemId, props.isBatchManaged], |
| | | () => { |
| | | if (props.itemId && props.isBatchManaged) { |
| | | loadConfig(); |
| | | } else { |
| | | resetConfig(); |
| | | } |
| | | }, |
| | | { immediate: true }, |
| | | ); |
| | | |
| | | // çå¬é
ç½®ååï¼è§¦å change äºä»¶ |
| | | watch( |
| | | config, |
| | | () => { |
| | | emit('change', getConfig()); |
| | | }, |
| | | { deep: true }, |
| | | ); |
| | | |
| | | defineExpose({ |
| | | saveConfig, |
| | | getConfig, |
| | | loadConfig, |
| | | resetConfig, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <div v-if="visible" class="mt-4"> |
| | | <Divider orientation="left">æ¹æ¬¡å±æ§é
ç½®</Divider> |
| | | <div class="grid grid-cols-4 gap-4 px-4"> |
| | | <Checkbox |
| | | v-for="option in configOptions" |
| | | :key="option.key" |
| | | v-model:checked="config[option.key]" |
| | | :disabled="loading" |
| | | > |
| | | {{ option.label }} |
| | | </Checkbox> |
| | | </div> |
| | | <p class="mt-2 px-4 text-xs text-gray-500"> |
| | | å¾é表示åå»ºæ¹æ¬¡æ¶è¯¥å段å¿
å¡« |
| | | </p> |
| | | </div> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MdmItemApi } from '#/api/mdm/item'; |
| | | |
| | | import { h } from 'vue'; |
| | | import { Tag } from 'ant-design-vue'; |
| | | |
| | | /** ç©æéæ©å¼¹çªæç´¢è¡¨å */ |
| | | export function useMdmItemSelectGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'code', |
| | | label: 'ç©æç¼ç ', |
| | | component: 'Input', |
| | | componentProps: { |
| | | allowClear: true, |
| | | placeholder: '请è¾å
¥ç©æç¼ç ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'name', |
| | | label: 'ç©æåç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | allowClear: true, |
| | | placeholder: '请è¾å
¥ç©æåç§°', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'itemType', |
| | | label: 'ç©æç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | placeholder: 'è¯·éæ©ç©æç±»å', |
| | | options: [ |
| | | { label: 'åæ', value: 1 }, |
| | | { label: 'åæå', value: 2 }, |
| | | { label: 'æå', value: 3 }, |
| | | { label: 'è¾
æ', value: 4 }, |
| | | ], |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** ç©æç±»åé¢è²æ å° */ |
| | | const itemTypeMap: Record<number, { label: string; color: string }> = { |
| | | 1: { label: 'åæ', color: 'green' }, |
| | | 2: { label: 'åæå', color: 'orange' }, |
| | | 3: { label: 'æå', color: 'blue' }, |
| | | 4: { label: 'è¾
æ', color: 'purple' }, |
| | | }; |
| | | |
| | | /** ç©æéæ©å¼¹çªåè¡¨åæ®µ */ |
| | | export function useMdmItemSelectGridColumns( |
| | | multiple = true, |
| | | ): VxeTableGridOptions<MdmItemApi.Item>['columns'] { |
| | | return [ |
| | | { type: multiple ? 'checkbox' : 'radio', width: 50 }, |
| | | { |
| | | field: 'code', |
| | | title: 'ç©æç¼ç ', |
| | | width: 180, |
| | | }, |
| | | { |
| | | field: 'name', |
| | | title: 'ç©æåç§°', |
| | | minWidth: 160, |
| | | align: 'left', |
| | | }, |
| | | { |
| | | field: 'specification', |
| | | title: 'è§æ ¼åå·', |
| | | minWidth: 140, |
| | | align: 'left', |
| | | }, |
| | | { |
| | | field: 'unitMeasureName', |
| | | title: 'åä½', |
| | | width: 90, |
| | | align: 'center', |
| | | }, |
| | | { |
| | | field: 'itemType', |
| | | title: 'ç©æç±»å', |
| | | width: 110, |
| | | align: 'center', |
| | | formatter: ({ cellValue }: { cellValue: number }) => { |
| | | const type = itemTypeMap[cellValue]; |
| | | return type ? type.label : '-'; |
| | | }, |
| | | }, |
| | | { |
| | | field: 'isBatchManaged', |
| | | title: 'æ¹æ¬¡ç®¡ç', |
| | | width: 110, |
| | | align: 'center', |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: 'infra_boolean_string' }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'createTime', |
| | | title: 'å建æ¶é´', |
| | | width: 180, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | export { default as MdmItemSelect } from './select.vue'; |
| | | export { default as MdmItemSelectDialog } from './select-dialog.vue'; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MdmItemApi } from '#/api/mdm/item'; |
| | | |
| | | import { nextTick, ref } from 'vue'; |
| | | |
| | | import { message, Modal } from 'ant-design-vue'; |
| | | |
| | | import { useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { getItemPage } from '#/api/mdm/item'; |
| | | |
| | | import { |
| | | useMdmItemSelectGridColumns, |
| | | useMdmItemSelectGridFormSchema, |
| | | } from './data'; |
| | | |
| | | defineOptions({ name: 'MdmItemSelectDialog' }); |
| | | |
| | | const emit = defineEmits<{ |
| | | selected: [rows: MdmItemApi.Item[]]; |
| | | }>(); |
| | | |
| | | const open = ref(false); // å¼¹çªæ¯å¦æå¼ |
| | | const multiple = ref(true); // æ¯å¦å¤é |
| | | const selectedRows = ref<MdmItemApi.Item[]>([]); // å·²éç©æå表 |
| | | const preSelectedIds = ref<number[]>([]); // é¢éç©æç¼å·å表 |
| | | |
| | | /** è·åå½åè¡¨æ ¼æ°æ® */ |
| | | function getTableRows() { |
| | | return gridApi.grid.getTableData().fullData as MdmItemApi.Item[]; |
| | | } |
| | | |
| | | /** è·åå¤éè®°å½ï¼å
å« VXE reserve è·¨é¡µè®°å½ */ |
| | | function getMultipleSelectedRows() { |
| | | const selectedMap = new Map<number, MdmItemApi.Item>(); |
| | | const records = [ |
| | | ...(gridApi.grid.getCheckboxReserveRecords?.() ?? []), |
| | | ...(gridApi.grid.getCheckboxRecords?.() ?? []), |
| | | ] as MdmItemApi.Item[]; |
| | | records.forEach((row) => { |
| | | const rowId = row.id; |
| | | if (rowId) { |
| | | selectedMap.set(rowId, row); |
| | | } |
| | | }); |
| | | return [...selectedMap.values()]; |
| | | } |
| | | |
| | | /** å¤çå¾éåå */ |
| | | function handleCheckboxSelectChange() { |
| | | selectedRows.value = getMultipleSelectedRows(); |
| | | } |
| | | |
| | | /** å¤çåéåå */ |
| | | function handleRadioChange(row: MdmItemApi.Item) { |
| | | selectedRows.value = [row]; |
| | | } |
| | | |
| | | /** å¤é模å¼ä¸åæ¢è¡å¾é */ |
| | | async function toggleMultipleRow(row: MdmItemApi.Item) { |
| | | const selected = gridApi.grid.isCheckedByCheckboxRow(row); |
| | | await gridApi.grid.setCheckboxRow(row, !selected); |
| | | selectedRows.value = getMultipleSelectedRows(); |
| | | } |
| | | |
| | | /** å¤çè¡åå» */ |
| | | async function handleCellDblclick({ row }: { row: MdmItemApi.Item }) { |
| | | if (multiple.value) { |
| | | await toggleMultipleRow(row); |
| | | return; |
| | | } |
| | | selectedRows.value = [row]; |
| | | await gridApi.grid.setRadioRow(row); |
| | | handleConfirm(); |
| | | } |
| | | |
| | | /** åæ¾é¢éç©æ */ |
| | | async function applyPreSelection() { |
| | | if (preSelectedIds.value.length === 0) { |
| | | return; |
| | | } |
| | | const rows = getTableRows(); |
| | | for (const row of rows) { |
| | | if ( |
| | | row.id === undefined || |
| | | row.id === null || |
| | | !preSelectedIds.value.includes(row.id) |
| | | ) { |
| | | continue; |
| | | } |
| | | if (multiple.value) { |
| | | await gridApi.grid.setCheckboxRow(row, true); |
| | | } else { |
| | | await gridApi.grid.setRadioRow(row); |
| | | selectedRows.value = [row]; |
| | | return; |
| | | } |
| | | } |
| | | if (multiple.value) { |
| | | selectedRows.value = getMultipleSelectedRows(); |
| | | } |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useMdmItemSelectGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useMdmItemSelectGridColumns(true), |
| | | height: 560, |
| | | keepSource: true, |
| | | checkboxConfig: { |
| | | highlight: true, |
| | | range: true, |
| | | reserve: true, |
| | | }, |
| | | radioConfig: { |
| | | highlight: true, |
| | | trigger: 'row', |
| | | }, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => { |
| | | return await getItemPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }); |
| | | }, |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<MdmItemApi.Item>, |
| | | gridEvents: { |
| | | cellDblclick: handleCellDblclick, |
| | | checkboxAll: handleCheckboxSelectChange, |
| | | checkboxChange: handleCheckboxSelectChange, |
| | | radioChange: ({ row }: { row: MdmItemApi.Item }) => { |
| | | handleRadioChange(row); |
| | | }, |
| | | }, |
| | | }); |
| | | |
| | | /** éç½®æ¥è¯¢åéæ©ç¶æ */ |
| | | async function resetQueryState() { |
| | | selectedRows.value = []; |
| | | await gridApi.grid.clearCheckboxRow(); |
| | | await gridApi.grid.clearCheckboxReserve(); |
| | | await gridApi.grid.clearRadioRow(); |
| | | await gridApi.formApi.resetForm(); |
| | | } |
| | | |
| | | /** æå¼ç©æéæ©å¼¹çª */ |
| | | async function openModal( |
| | | selectedIds?: number[], |
| | | options?: { multiple?: boolean }, |
| | | ) { |
| | | open.value = true; |
| | | multiple.value = options?.multiple ?? true; |
| | | preSelectedIds.value = selectedIds || []; |
| | | await nextTick(); |
| | | gridApi.setGridOptions({ |
| | | columns: useMdmItemSelectGridColumns(multiple.value), |
| | | }); |
| | | await resetQueryState(); |
| | | await gridApi.query(); |
| | | await nextTick(); |
| | | await applyPreSelection(); |
| | | } |
| | | |
| | | /** å
³éç©æéæ©å¼¹çª */ |
| | | async function closeModal() { |
| | | open.value = false; |
| | | await resetQueryState(); |
| | | } |
| | | |
| | | /** ç¡®è®¤éæ©ç©æ */ |
| | | function handleConfirm() { |
| | | const rows = multiple.value ? getMultipleSelectedRows() : selectedRows.value; |
| | | if (rows.length === 0) { |
| | | message.warning(multiple.value ? '请è³å°éæ©ä¸æ¡æ°æ®' : 'è¯·éæ©ä¸æ¡æ°æ®'); |
| | | return; |
| | | } |
| | | emit('selected', multiple.value ? rows : [rows[0]!]); |
| | | open.value = false; |
| | | } |
| | | |
| | | defineExpose({ open: openModal }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal |
| | | v-model:open="open" |
| | | title="ç©æéæ©" |
| | | width="80%" |
| | | :destroy-on-close="true" |
| | | @ok="handleConfirm" |
| | | @cancel="closeModal" |
| | | > |
| | | <Grid table-title="ç©æå表" /> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { MdmItemApi } from '#/api/mdm/item'; |
| | | |
| | | import { computed, ref, useAttrs, watch } from 'vue'; |
| | | |
| | | import { IconifyIcon } from '@vben/icons'; |
| | | |
| | | import { Input, Tooltip } from 'ant-design-vue'; |
| | | |
| | | import { getItem } from '#/api/mdm/item'; |
| | | |
| | | import MdmItemSelectDialog from './select-dialog.vue'; |
| | | |
| | | defineOptions({ name: 'MdmItemSelect', inheritAttrs: false }); |
| | | |
| | | const props = withDefaults( |
| | | defineProps<{ |
| | | allowClear?: boolean; |
| | | disabled?: boolean; |
| | | modelValue?: number; |
| | | placeholder?: string; |
| | | }>(), |
| | | { |
| | | allowClear: true, |
| | | disabled: false, |
| | | modelValue: undefined, |
| | | placeholder: 'è¯·éæ©ç©æ', |
| | | }, |
| | | ); |
| | | const emit = defineEmits<{ |
| | | change: [item: MdmItemApi.Item | undefined]; |
| | | 'update:modelValue': [value: number | undefined]; |
| | | }>(); |
| | | const attrs = useAttrs(); // éä¼ å±æ§ |
| | | const dialogRef = ref<InstanceType<typeof MdmItemSelectDialog>>(); // ç©æéæ©å¼¹çª |
| | | const hovering = ref(false); // æ¯å¦æ¬å |
| | | const selectedItem = ref<MdmItemApi.Item>(); // å½åéä¸ç©æ |
| | | |
| | | const displayLabel = computed(() => selectedItem.value?.name ?? ''); // éæ©å¨å±ç¤ºåç§° |
| | | const showClear = computed( |
| | | () => |
| | | props.allowClear && |
| | | !props.disabled && |
| | | hovering.value && |
| | | props.modelValue !== null, |
| | | ); |
| | | |
| | | /** æ ¹æ®ç©æç¼å·åæ¾éæ©å¨ */ |
| | | async function resolveItemById(id: number | undefined) { |
| | | if (!id) { |
| | | selectedItem.value = undefined; |
| | | return; |
| | | } |
| | | if (selectedItem.value?.id === id) { |
| | | return; |
| | | } |
| | | selectedItem.value = await getItem(id); |
| | | } |
| | | |
| | | watch( |
| | | () => props.modelValue, |
| | | (value) => { |
| | | resolveItemById(value); |
| | | }, |
| | | { immediate: true }, |
| | | ); |
| | | |
| | | /** æ¸
空已éç©æ */ |
| | | function clearSelected() { |
| | | selectedItem.value = undefined; |
| | | emit('update:modelValue', undefined); |
| | | emit('change', undefined); |
| | | } |
| | | |
| | | /** æå¼ç©æéæ©å¼¹çª */ |
| | | function handleClick(event: MouseEvent) { |
| | | if (props.disabled) { |
| | | return; |
| | | } |
| | | const target = event.target as HTMLElement; |
| | | if (showClear.value && target.closest('.ant-input-suffix')) { |
| | | event.stopPropagation(); |
| | | clearSelected(); |
| | | return; |
| | | } |
| | | const selectedIds = ( |
| | | props.modelValue === null ? [] : [props.modelValue] |
| | | ) as number[]; |
| | | dialogRef.value?.open(selectedIds, { multiple: false }); |
| | | } |
| | | |
| | | /** åå¡«éä¸çç©æ */ |
| | | function handleSelected(rows: MdmItemApi.Item[]) { |
| | | const item = rows[0]; |
| | | if (!item) { |
| | | return; |
| | | } |
| | | selectedItem.value = item; |
| | | emit('update:modelValue', item.id); |
| | | emit('change', item); |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <div |
| | | v-bind="attrs" |
| | | class="w-full" |
| | | :class="disabled ? 'cursor-not-allowed' : 'cursor-pointer'" |
| | | @click="handleClick" |
| | | @mouseenter="hovering = true" |
| | | @mouseleave="hovering = false" |
| | | > |
| | | <Tooltip :mouse-enter-delay="0.5" :open="selectedItem ? undefined : false"> |
| | | <template #title> |
| | | <div v-if="selectedItem" class="leading-6"> |
| | | <div>ç¼ç ï¼{{ selectedItem.code || '-' }}</div> |
| | | <div>åç§°ï¼{{ selectedItem.name || '-' }}</div> |
| | | <div>è§æ ¼ï¼{{ selectedItem.specification || '-' }}</div> |
| | | <div>åä½ï¼{{ selectedItem.unitMeasureName || '-' }}</div> |
| | | </div> |
| | | </template> |
| | | <Input |
| | | :disabled="disabled" |
| | | :placeholder="placeholder" |
| | | :value="displayLabel" |
| | | readonly |
| | | > |
| | | <template #suffix> |
| | | <IconifyIcon |
| | | class="size-4" |
| | | :icon="showClear ? 'lucide:circle-x' : 'lucide:search'" |
| | | /> |
| | | </template> |
| | | </Input> |
| | | </Tooltip> |
| | | </div> |
| | | <MdmItemSelectDialog ref="dialogRef" @selected="handleSelected" /> |
| | | </template> |
| | |
| | | |
| | | import { z } from '#/adapter/form'; |
| | | import { getUnitPage } from '#/api/mdm/unit'; |
| | | import { getWarehouseSimpleList } from '#/api/erp/stock/warehouse'; |
| | | |
| | | /** ç©æç±»åé项 */ |
| | | export const ITEM_TYPE_OPTIONS = [ |
| | |
| | | }, |
| | | }, |
| | | { |
| | | component: 'ApiSelect', |
| | | component: 'Input', |
| | | fieldName: 'warehouseId', |
| | | label: 'é»è®¤ä»åº', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©é»è®¤ä»åº', |
| | | allowClear: true, |
| | | api: getWarehouseSimpleList, |
| | | labelField: 'name', |
| | | valueField: 'id', |
| | | placeholder: '请è¾å
¥é»è®¤ä»åºID', |
| | | }, |
| | | }, |
| | | { |
| | |
| | | component: 'Switch', |
| | | fieldName: 'isBatchManaged', |
| | | label: 'æ¹æ¬¡ç®¡ç', |
| | | defaultValue: true, |
| | | componentProps: { |
| | | class: 'w-auto', |
| | | checkedChildren: 'æ¯', |
| | |
| | | <script lang="ts" setup> |
| | | import type { MdmItemApi } from '#/api/mdm/item'; |
| | | import type { MdmItemBatchConfigApi } from '#/api/mes/md/item-batch-config'; |
| | | import type { VbenFormApi } from '#/adapter/form'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | import { computed, ref, watch } from 'vue'; |
| | | |
| | | import { useVbenModal } from '#/packages/effects/common-ui/src'; |
| | | |
| | |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { createItem, getItem, updateItem } from '#/api/mdm/item'; |
| | | import { saveItemBatchConfig } from '#/api/mes/md/item-batch-config'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useFormSchema } from '../data'; |
| | | import ItemBatchConfig from '../components/batch-config.vue'; |
| | | |
| | | defineOptions({ name: 'ItemForm' }); |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formData = ref<MdmItemApi.Item>(); |
| | | const batchConfigRef = ref<InstanceType<typeof ItemBatchConfig>>(); |
| | | const batchConfig = ref<Partial<MdmItemBatchConfigApi.ItemBatchConfig>>({}); |
| | | |
| | | // å½å表åä¸çæ¹æ¬¡ç®¡çå¼å
³å¼ï¼ç¨äºæ§å¶æ¹æ¬¡é
ç½®æ¾ç¤ºï¼ |
| | | const currentIsBatchManaged = ref<boolean>(false); |
| | | |
| | | const getTitle = computed(() => { |
| | | return formData.value?.id |
| | | ? $t('ui.actionTitle.edit', ['ç©æ']) |
| | |
| | | schema: useFormSchema(), |
| | | showDefaultActions: false, |
| | | wrapperClass: 'grid-cols-2', |
| | | // çå¬è¡¨åå¼åå |
| | | handleValuesChange: (values: any) => { |
| | | currentIsBatchManaged.value = values?.isBatchManaged === true; |
| | | }, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | |
| | | modalApi.lock(); |
| | | const data = (await formApi.getValues()) as MdmItemApi.Item; |
| | | try { |
| | | await (formData.value?.id ? updateItem(data) : createItem(data)); |
| | | // ä¿åç©æåºæ¬ä¿¡æ¯ |
| | | const itemId = await (formData.value?.id ? updateItem(data) : createItem(data)); |
| | | const savedItemId = typeof itemId === 'number' ? itemId : data.id; |
| | | |
| | | // 妿å¯ç¨æ¹æ¬¡ç®¡çï¼ä¿åæ¹æ¬¡é
ç½® |
| | | if (data.isBatchManaged && savedItemId) { |
| | | await saveItemBatchConfig({ |
| | | ...batchConfig.value, |
| | | itemId: savedItemId, |
| | | }); |
| | | } |
| | | |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | batchConfig.value = {}; |
| | | currentIsBatchManaged.value = false; |
| | | return; |
| | | } |
| | | const data = modalApi.getData<MdmItemApi.Item>(); |
| | | if (!data || !data.id) { |
| | | return; |
| | | } |
| | | if (data?.id) { |
| | | // ç¼è¾æ¨¡å¼ |
| | | modalApi.lock(); |
| | | try { |
| | | formData.value = await getItem(data.id); |
| | | await formApi.setValues(formData.value); |
| | | currentIsBatchManaged.value = formData.value?.isBatchManaged === true; |
| | | // å è½½æ¹æ¬¡é
ç½® |
| | | if (batchConfigRef.value && currentIsBatchManaged.value) { |
| | | await batchConfigRef.value.loadConfig(); |
| | | } |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | } else { |
| | | // æ°å¢æ¨¡å¼ |
| | | formData.value = undefined; |
| | | await formApi.resetForm(); |
| | | // è·å表åé»è®¤å¼ï¼isBatchManaged é»è®¤ trueï¼ |
| | | const defaultValues = await formApi.getValues(); |
| | | currentIsBatchManaged.value = defaultValues?.isBatchManaged === true; |
| | | } |
| | | }, |
| | | }); |
| | | |
| | | /** å¤çæ¹æ¬¡é
ç½®åå */ |
| | | function handleBatchConfigChange(config: Partial<MdmItemBatchConfigApi.ItemBatchConfig>) { |
| | | batchConfig.value = config; |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal class="w-[1000px]" :title="getTitle"> |
| | | <Form class="mx-4" /> |
| | | <ItemBatchConfig |
| | | ref="batchConfigRef" |
| | | :item-id="formData?.id" |
| | | :is-batch-managed="currentIsBatchManaged" |
| | | @change="handleBatchConfigChange" |
| | | /> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | export { default as ErpSaleOrderSelect } from './select.vue'; |
| | | export { default as ErpSaleOrderSelectDialog } from './select-dialog.vue'; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { ErpSaleOrderApi } from '#/api/erp/sale/order'; |
| | | |
| | | import { nextTick, ref } from 'vue'; |
| | | |
| | | import { message, Modal } from 'ant-design-vue'; |
| | | |
| | | import { useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { getSaleOrderPage } from '#/api/erp/sale/order'; |
| | | |
| | | defineOptions({ name: 'ErpSaleOrderSelectDialog' }); |
| | | |
| | | const emit = defineEmits<{ |
| | | selected: [rows: ErpSaleOrderApi.SaleOrder[]]; |
| | | }>(); |
| | | |
| | | const open = ref(false); |
| | | const multiple = ref(true); |
| | | const status = ref<number | undefined>(undefined); |
| | | const selectedRows = ref<ErpSaleOrderApi.SaleOrder[]>([]); |
| | | const preSelectedIds = ref<number[]>([]); |
| | | |
| | | /** è·åå½åè¡¨æ ¼æ°æ® */ |
| | | function getTableRows() { |
| | | return gridApi.grid.getTableData().fullData as ErpSaleOrderApi.SaleOrder[]; |
| | | } |
| | | |
| | | /** è·åå¤éè®°å½ */ |
| | | function getMultipleSelectedRows() { |
| | | const selectedMap = new Map<number, ErpSaleOrderApi.SaleOrder>(); |
| | | const records = [ |
| | | ...(gridApi.grid.getCheckboxReserveRecords?.() ?? []), |
| | | ...(gridApi.grid.getCheckboxRecords?.() ?? []), |
| | | ] as ErpSaleOrderApi.SaleOrder[]; |
| | | records.forEach((row) => { |
| | | if (row.id) { |
| | | selectedMap.set(row.id, row); |
| | | } |
| | | }); |
| | | return [...selectedMap.values()]; |
| | | } |
| | | |
| | | /** å¤çå¾éåå */ |
| | | function handleCheckboxSelectChange() { |
| | | selectedRows.value = getMultipleSelectedRows(); |
| | | } |
| | | |
| | | /** å¤çåéåå */ |
| | | function handleRadioChange(row: ErpSaleOrderApi.SaleOrder) { |
| | | selectedRows.value = [row]; |
| | | } |
| | | |
| | | /** å¤çè¡åå» */ |
| | | async function handleCellDblclick({ row }: { row: ErpSaleOrderApi.SaleOrder }) { |
| | | if (multiple.value) { |
| | | const selected = gridApi.grid.isCheckedByCheckboxRow(row); |
| | | await gridApi.grid.setCheckboxRow(row, !selected); |
| | | selectedRows.value = getMultipleSelectedRows(); |
| | | return; |
| | | } |
| | | selectedRows.value = [row]; |
| | | await gridApi.grid.setRadioRow(row); |
| | | handleConfirm(); |
| | | } |
| | | |
| | | /** åæ¾é¢ééå®è®¢å */ |
| | | async function applyPreSelection() { |
| | | if (preSelectedIds.value.length === 0) { |
| | | return; |
| | | } |
| | | const rows = getTableRows(); |
| | | for (const row of rows) { |
| | | if (row.id && preSelectedIds.value.includes(row.id)) { |
| | | if (multiple.value) { |
| | | await gridApi.grid.setCheckboxRow(row, true); |
| | | } else { |
| | | await gridApi.grid.setRadioRow(row); |
| | | selectedRows.value = [row]; |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | if (multiple.value) { |
| | | selectedRows.value = getMultipleSelectedRows(); |
| | | } |
| | | } |
| | | |
| | | /** åè¡¨åæ®µ */ |
| | | function useGridColumns(isMultiple: boolean): VxeTableGridOptions<ErpSaleOrderApi.SaleOrder>['columns'] { |
| | | return [ |
| | | { type: isMultiple ? 'checkbox' : 'radio', width: 50 }, |
| | | { field: 'no', title: '订åå·', minWidth: 140 }, |
| | | { field: 'customerName', title: '客æ·', minWidth: 120 }, |
| | | { field: 'orderTime', title: 'è®¢åæ¶é´', width: 120, formatter: 'formatDate' }, |
| | | { field: 'totalCount', title: 'å计æ°é', width: 100 }, |
| | | { field: 'totalPrice', title: 'å计éé¢', width: 100 }, |
| | | ]; |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | gridOptions: { |
| | | columns: useGridColumns(true), |
| | | height: 400, |
| | | keepSource: true, |
| | | checkboxConfig: { |
| | | highlight: true, |
| | | reserve: true, |
| | | }, |
| | | radioConfig: { |
| | | highlight: true, |
| | | trigger: 'row', |
| | | }, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => { |
| | | return await getSaleOrderPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | status: status.value, |
| | | ...formValues, |
| | | }); |
| | | }, |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | } as VxeTableGridOptions<ErpSaleOrderApi.SaleOrder>, |
| | | gridEvents: { |
| | | cellDblclick: handleCellDblclick, |
| | | checkboxAll: handleCheckboxSelectChange, |
| | | checkboxChange: handleCheckboxSelectChange, |
| | | radioChange: ({ row }: { row: ErpSaleOrderApi.SaleOrder }) => { |
| | | handleRadioChange(row); |
| | | }, |
| | | }, |
| | | }); |
| | | |
| | | /** éç½®æ¥è¯¢åéæ©ç¶æ */ |
| | | async function resetQueryState() { |
| | | selectedRows.value = []; |
| | | await gridApi.grid.clearCheckboxRow(); |
| | | await gridApi.grid.clearCheckboxReserve(); |
| | | await gridApi.grid.clearRadioRow(); |
| | | } |
| | | |
| | | /** æå¼éå®è®¢åéæ©å¼¹çª */ |
| | | async function openModal( |
| | | selectedIds?: number[], |
| | | options?: { multiple?: boolean; status?: number }, |
| | | ) { |
| | | open.value = true; |
| | | multiple.value = options?.multiple ?? true; |
| | | status.value = options?.status; |
| | | preSelectedIds.value = selectedIds || []; |
| | | await nextTick(); |
| | | gridApi.setGridOptions({ |
| | | columns: useGridColumns(multiple.value), |
| | | }); |
| | | await resetQueryState(); |
| | | await gridApi.query(); |
| | | await nextTick(); |
| | | await applyPreSelection(); |
| | | } |
| | | |
| | | /** å
³ééå®è®¢åéæ©å¼¹çª */ |
| | | async function closeModal() { |
| | | open.value = false; |
| | | await resetQueryState(); |
| | | } |
| | | |
| | | /** ç¡®è®¤éæ©éå®è®¢å */ |
| | | function handleConfirm() { |
| | | const rows = multiple.value ? getMultipleSelectedRows() : selectedRows.value; |
| | | if (rows.length === 0) { |
| | | message.warning(multiple.value ? '请è³å°éæ©ä¸æ¡æ°æ®' : 'è¯·éæ©ä¸æ¡æ°æ®'); |
| | | return; |
| | | } |
| | | emit('selected', multiple.value ? rows : [rows[0]!]); |
| | | open.value = false; |
| | | } |
| | | |
| | | defineExpose({ open: openModal }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal |
| | | v-model:open="open" |
| | | title="éå®è®¢åéæ©" |
| | | width="70%" |
| | | :destroy-on-close="true" |
| | | @ok="handleConfirm" |
| | | @cancel="closeModal" |
| | | > |
| | | <Grid table-title="éå®è®¢åå表" /> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { ErpSaleOrderApi } from '#/api/erp/sale/order'; |
| | | |
| | | import { computed, ref, useAttrs, watch } from 'vue'; |
| | | |
| | | import { IconifyIcon } from '@vben/icons'; |
| | | |
| | | import { Input, Tooltip } from 'ant-design-vue'; |
| | | |
| | | import { getSaleOrder } from '#/api/erp/sale/order'; |
| | | |
| | | import ErpSaleOrderSelectDialog from './select-dialog.vue'; |
| | | |
| | | defineOptions({ name: 'ErpSaleOrderSelect', inheritAttrs: false }); |
| | | |
| | | const props = withDefaults( |
| | | defineProps<{ |
| | | allowClear?: boolean; |
| | | disabled?: boolean; |
| | | modelValue?: number; |
| | | placeholder?: string; |
| | | status?: number; |
| | | }>(), |
| | | { |
| | | allowClear: true, |
| | | disabled: false, |
| | | modelValue: undefined, |
| | | placeholder: 'è¯·éæ©éå®è®¢å', |
| | | status: undefined, |
| | | }, |
| | | ); |
| | | |
| | | const emit = defineEmits(['change', 'update:modelValue']); |
| | | |
| | | const attrs = useAttrs(); |
| | | const dialogRef = ref<InstanceType<typeof ErpSaleOrderSelectDialog>>(); |
| | | const hovering = ref(false); |
| | | const selectedItem = ref<ErpSaleOrderApi.SaleOrder>(); |
| | | |
| | | const displayLabel = computed(() => selectedItem.value?.no ?? ''); |
| | | const showClear = computed( |
| | | () => |
| | | props.allowClear && |
| | | !props.disabled && |
| | | hovering.value && |
| | | props.modelValue !== null, |
| | | ); |
| | | |
| | | async function resolveItemById(id: number | undefined) { |
| | | if (!id) { |
| | | selectedItem.value = undefined; |
| | | return; |
| | | } |
| | | if (selectedItem.value?.id === id) { |
| | | return; |
| | | } |
| | | selectedItem.value = await getSaleOrder(id); |
| | | } |
| | | |
| | | watch( |
| | | () => props.modelValue, |
| | | (value) => { |
| | | resolveItemById(value); |
| | | }, |
| | | { immediate: true }, |
| | | ); |
| | | |
| | | function clearSelected() { |
| | | selectedItem.value = undefined; |
| | | emit('update:modelValue', undefined); |
| | | emit('change', undefined); |
| | | } |
| | | |
| | | function handleClick(event: MouseEvent) { |
| | | if (props.disabled) { |
| | | return; |
| | | } |
| | | const target = event.target as HTMLElement; |
| | | if (showClear.value && target.closest('.ant-input-suffix')) { |
| | | event.stopPropagation(); |
| | | clearSelected(); |
| | | return; |
| | | } |
| | | const selectedIds = ( |
| | | props.modelValue === null ? [] : [props.modelValue] |
| | | ) as number[]; |
| | | dialogRef.value?.open(selectedIds, { multiple: false, status: props.status }); |
| | | } |
| | | |
| | | function handleSelected(rows: ErpSaleOrderApi.SaleOrder[]) { |
| | | const item = rows[0]; |
| | | if (!item) { |
| | | return; |
| | | } |
| | | selectedItem.value = item; |
| | | emit('update:modelValue', item.id); |
| | | emit('change', item); |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <div |
| | | v-bind="attrs" |
| | | class="w-full" |
| | | :class="disabled ? 'cursor-not-allowed' : 'cursor-pointer'" |
| | | @click="handleClick" |
| | | @mouseenter="hovering = true" |
| | | @mouseleave="hovering = false" |
| | | > |
| | | <Tooltip :mouse-enter-delay="0.5" :open="selectedItem ? undefined : false"> |
| | | <template #title> |
| | | <div v-if="selectedItem" class="leading-6"> |
| | | <div>订åå·ï¼{{ selectedItem.no || '-' }}</div> |
| | | <div>客æ·ï¼{{ selectedItem.customerName || '-' }}</div> |
| | | <div>è®¢åæ¶é´ï¼{{ selectedItem.orderTime || '-' }}</div> |
| | | <div>å计éé¢ï¼{{ selectedItem.totalPrice || '-' }} å
</div> |
| | | </div> |
| | | </template> |
| | | <Input |
| | | :disabled="disabled" |
| | | :placeholder="placeholder" |
| | | :value="displayLabel" |
| | | readonly |
| | | > |
| | | <template #suffix> |
| | | <IconifyIcon |
| | | class="size-4" |
| | | :icon="showClear ? 'lucide:circle-x' : 'lucide:search'" |
| | | /> |
| | | </template> |
| | | </Input> |
| | | </Tooltip> |
| | | </div> |
| | | <ErpSaleOrderSelectDialog ref="dialogRef" @selected="handleSelected" /> |
| | | </template> |
| | |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | width: 50, |
| | | width: 320, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | visible: !disabled, |
| | |
| | | getSaleOrderPage, |
| | | updateSaleOrderStatus, |
| | | } from '#/api/erp/sale/order'; |
| | | import { generateFromSaleOrder } from '#/api/mes/wm/salesnotice'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | |
| | | function handleViewContract(row: ErpSaleOrderApi.SaleOrder) { |
| | | if (row.contractId) { |
| | | router.push({ |
| | | path: '/crm/contract/detail', |
| | | query: { id: row.contractId }, |
| | | path: `/crm/contract/detail/${row.contractId}`, |
| | | }); |
| | | } |
| | | } |
| | | |
| | | /** çæåè´§éç¥å */ |
| | | async function handleGenerateNotice(row: ErpSaleOrderApi.SaleOrder) { |
| | | try { |
| | | const noticeId = await generateFromSaleOrder(row.id!); |
| | | message.success('çæåè´§éç¥åæå'); |
| | | // 跳转å°åè´§éç¥åé¡µé¢ |
| | | router.push({ |
| | | path: '/wls/sales-notice', |
| | | query: { id: noticeId }, |
| | | }); |
| | | } catch (e) { |
| | | console.error(e); |
| | | } |
| | | } |
| | | |
| | |
| | | }, |
| | | }, |
| | | { |
| | | label: 'çæåè´§éç¥å', |
| | | type: 'link', |
| | | icon: 'ant-design:file-protect-outlined', |
| | | auth: ['mes:wm-sales-notice:create'], |
| | | ifShow: () => row.status === 20, |
| | | onClick: handleGenerateNotice.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { MdmItemBatchConfigApi } from '#/api/mes/md/item-batch-config'; |
| | | |
| | | import { computed, ref, watch } from 'vue'; |
| | | |
| | | import { Divider, Tag } from 'ant-design-vue'; |
| | | |
| | | import { getItemBatchConfigByItemId } from '#/api/mes/md/item-batch-config'; |
| | | |
| | | const props = defineProps<{ |
| | | itemId?: number; |
| | | isBatchManaged?: boolean; |
| | | }>(); |
| | | |
| | | // æ¹æ¬¡é
ç½®æ°æ® |
| | | const config = ref<MdmItemBatchConfigApi.ItemBatchConfig | null>(null); |
| | | |
| | | // æ¯å¦å è½½ä¸ |
| | | const loading = ref(false); |
| | | |
| | | // æ¯å¦æ¾ç¤ºï¼å¯ç¨æ¹æ¬¡ç®¡çæ¶æ¾ç¤ºï¼ |
| | | const visible = computed(() => props.isBatchManaged === true); |
| | | |
| | | // å·²å¯ç¨çæ¹æ¬¡å±æ§å表ï¼ä»
ä¿ç7ä¸ªåæ®µï¼ |
| | | const enabledProps = computed(() => { |
| | | if (!config.value) return []; |
| | | const props: { label: string; value: boolean }[] = []; |
| | | if (config.value.produceDateFlag) props.push({ label: 'çäº§æ¥æ', value: true }); |
| | | if (config.value.expireDateFlag) props.push({ label: 'æææ', value: true }); |
| | | if (config.value.receiptDateFlag) props.push({ label: 'å
¥åºæ¥æ', value: true }); |
| | | if (config.value.vendorFlag) props.push({ label: 'ä¾åºå', value: true }); |
| | | if (config.value.purchaseOrderCodeFlag) props.push({ label: 'éè´è®¢åå·', value: true }); |
| | | if (config.value.lotNumberFlag) props.push({ label: 'ç产æ¹å·', value: true }); |
| | | if (config.value.qualityStatusFlag) props.push({ label: 'è´¨éç¶æ', value: true }); |
| | | return props; |
| | | }); |
| | | |
| | | /** å è½½æ¹æ¬¡é
ç½® */ |
| | | async function loadConfig() { |
| | | if (!props.itemId || !props.isBatchManaged) { |
| | | config.value = null; |
| | | return; |
| | | } |
| | | loading.value = true; |
| | | try { |
| | | const data = await getItemBatchConfigByItemId(props.itemId); |
| | | config.value = data; |
| | | } catch { |
| | | config.value = null; |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | } |
| | | |
| | | /** éç½® */ |
| | | function reset() { |
| | | config.value = null; |
| | | loading.value = false; |
| | | } |
| | | |
| | | // çå¬ itemId ååï¼å è½½é
ç½® |
| | | watch( |
| | | () => [props.itemId, props.isBatchManaged], |
| | | () => { |
| | | if (props.itemId && props.isBatchManaged) { |
| | | loadConfig(); |
| | | } else { |
| | | reset(); |
| | | } |
| | | }, |
| | | { immediate: true }, |
| | | ); |
| | | |
| | | defineExpose({ |
| | | loadConfig, |
| | | reset, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <div v-if="visible" class="mt-4 rounded border border-gray-200 bg-gray-50 p-4"> |
| | | <Divider orientation="left">æ¹æ¬¡å±æ§</Divider> |
| | | <div v-if="loading" class="text-center text-gray-500">å è½½ä¸...</div> |
| | | <div v-else-if="enabledProps.length === 0" class="text-center text-gray-500"> |
| | | è¯¥ç©ææªé
ç½®æ¹æ¬¡å±æ§ |
| | | </div> |
| | | <div v-else class="flex flex-wrap gap-2"> |
| | | <Tag v-for="prop in enabledProps" :key="prop.label" color="blue"> |
| | | {{ prop.label }} |
| | | </Tag> |
| | | </div> |
| | | <p class="mt-2 text-xs text-gray-500"> |
| | | 以ä¸å段åå»ºæ¹æ¬¡æ¶å¿
å¡« |
| | | </p> |
| | | </div> |
| | | </template> |
| | |
| | | export { default as WmMaterialStockSelectDialog } from './select-dialog.vue'; |
| | | export { default as WmMaterialStockSelect } from './select.vue'; |
| | | export { default as WmStockAdjustModal } from './stock-adjust-modal.vue'; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { |
| | | MaterialStockAdjustInParams, |
| | | MaterialStockAdjustOutParams, |
| | | } from '#/api/mes/wm/materialstock'; |
| | | import type { MdmItemApi } from '#/api/mdm/item'; |
| | | import type { MdmItemBatchConfigApi } from '#/api/mes/md/item-batch-config'; |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | |
| | | import { ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | import { z } from '#/adapter/form'; |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { message } from 'ant-design-vue'; |
| | | import { markRaw } from 'vue'; |
| | | |
| | | import { |
| | | adjustMaterialStockIn, |
| | | adjustMaterialStockOut, |
| | | } from '#/api/mes/wm/materialstock'; |
| | | import { getItem } from '#/api/mdm/item'; |
| | | import { getItemBatchConfigByItemId } from '#/api/mes/md/item-batch-config'; |
| | | import { MdmItemSelect } from '#/views/basicData/mdm/components'; |
| | | import { MdVendorSelect } from '#/views/mes/md/vendor/components'; |
| | | import BatchConfigDisplay from './batch-config-display.vue'; |
| | | import { |
| | | WmWarehouseAreaSelect, |
| | | WmWarehouseLocationSelect, |
| | | WmWarehouseSelect, |
| | | } from '#/views/wls/warehouse/components'; |
| | | |
| | | const emit = defineEmits<{ |
| | | success: []; |
| | | }>(); |
| | | |
| | | // æä½ç±»åï¼1=å
¥åºï¼2=åºåº |
| | | const operateType = ref<1 | 2>(1); |
| | | const selectedItem = ref<MdmItemApi.Item | null>(null); |
| | | const selectedWarehouse = ref<any>(null); |
| | | const selectedLocation = ref<any>(null); |
| | | |
| | | // æ¯å¦å¯ç¨æ¹æ¬¡ç®¡ç |
| | | const batchEnabled = ref(false); |
| | | // æ¯å¦æå¨å¡«åæ¹æ¬¡å· |
| | | const manualBatchEntry = ref(false); |
| | | // ç©ææ¹æ¬¡é
ç½® |
| | | const batchConfig = ref<MdmItemBatchConfigApi.ItemBatchConfig | null>(null); |
| | | // æ¹æ¬¡é
ç½®å±ç¤ºç»ä»¶å¼ç¨ |
| | | const batchConfigDisplayRef = ref<InstanceType<typeof BatchConfigDisplay>>(); |
| | | |
| | | // æ é¢ |
| | | const modalTitle = ref('åºåè°æ´'); |
| | | |
| | | /** å è½½ç©ææ¹æ¬¡é
ç½®å¹¶æ´æ°å段æ¾ç¤º */ |
| | | async function loadBatchConfigAndUpdateFields(itemId: number) { |
| | | try { |
| | | const config = await getItemBatchConfigByItemId(itemId); |
| | | batchConfig.value = config; |
| | | } catch { |
| | | batchConfig.value = null; |
| | | } |
| | | await updateBatchFields(); |
| | | } |
| | | |
| | | /** æ´æ°æ¹æ¬¡å段æ¾ç¤ºï¼æ ¹æ®é
ç½®å±ç¤ºå·²å¯ç¨ç屿§ï¼ */ |
| | | async function updateBatchFields() { |
| | | const enabled = selectedItem.value?.isBatchManaged === true; |
| | | batchEnabled.value = enabled; |
| | | |
| | | if (!enabled) { |
| | | // éèæææ¹æ¬¡ç¸å
³å段 |
| | | formApi.updateSchema([ |
| | | { fieldName: 'batchCode', dependencies: { show: () => false } }, |
| | | { fieldName: 'produceDate', dependencies: { show: () => false } }, |
| | | { fieldName: 'expireDate', dependencies: { show: () => false } }, |
| | | { fieldName: 'manualBatchEntry', dependencies: { show: () => false } }, |
| | | { fieldName: 'vendorId', dependencies: { show: () => true } }, |
| | | ]); |
| | | return; |
| | | } |
| | | |
| | | // å¯ç¨æ¹æ¬¡ç®¡çï¼æ ¹æ®é
ç½®æ¾ç¤ºå段 |
| | | const config = batchConfig.value; |
| | | const isIn = operateType.value === 1; |
| | | |
| | | // æ¯å¦æå¨å¡«åæ¹æ¬¡å·æ§å¶æ¹æ¬¡å·åæ®µçæ¾ç¤º |
| | | const showBatchCode = manualBatchEntry.value; |
| | | const showProduceDate = isIn && !!config?.produceDateFlag; |
| | | const showExpireDate = isIn && !!config?.expireDateFlag; |
| | | |
| | | formApi.updateSchema([ |
| | | { fieldName: 'batchCode', dependencies: { show: () => showBatchCode } }, |
| | | { fieldName: 'produceDate', dependencies: { show: () => showProduceDate } }, |
| | | { fieldName: 'expireDate', dependencies: { show: () => showExpireDate } }, |
| | | { fieldName: 'manualBatchEntry', dependencies: { show: () => true } }, |
| | | ]); |
| | | } |
| | | |
| | | /** ç©æéæ©åå */ |
| | | async function handleItemChange(item: MdmItemApi.Item | undefined) { |
| | | selectedItem.value = item || null; |
| | | if (item?.id) { |
| | | const itemDetail = await getItem(item.id); |
| | | selectedItem.value = itemDetail; |
| | | // å è½½ç©ææ¹æ¬¡é
ç½®å¹¶æ´æ°å段 |
| | | await loadBatchConfigAndUpdateFields(item.id); |
| | | } else { |
| | | batchConfig.value = null; |
| | | batchEnabled.value = false; |
| | | } |
| | | // æ¸
ç©ºæ¹æ¬¡ç¸å
³å¼ |
| | | await formApi.setFieldValue('batchCode', undefined); |
| | | await formApi.setFieldValue('produceDate', undefined); |
| | | await formApi.setFieldValue('expireDate', undefined); |
| | | await formApi.setFieldValue('manualBatchEntry', false); |
| | | } |
| | | |
| | | /** ä»åºéæ©åå */ |
| | | async function handleWarehouseChange(item: any) { |
| | | selectedWarehouse.value = item; |
| | | await formApi.setFieldValue('locationId', undefined); |
| | | await formApi.setFieldValue('areaId', undefined); |
| | | } |
| | | |
| | | /** åºåºéæ©åå */ |
| | | async function handleLocationChange(item: any) { |
| | | selectedLocation.value = item; |
| | | await formApi.setFieldValue('areaId', undefined); |
| | | } |
| | | |
| | | /** æå¨å¡«åæ¹æ¬¡å·åå */ |
| | | async function handleManualBatchEntryChange(value: boolean) { |
| | | manualBatchEntry.value = value; |
| | | await updateBatchFields(); |
| | | if (!value) { |
| | | await formApi.setFieldValue('batchCode', undefined); |
| | | } |
| | | } |
| | | /** æä½ç±»ååå */ |
| | | async function handleOperateTypeChange(type: 1 | 2) { |
| | | operateType.value = type; |
| | | modalTitle.value = type === 1 ? 'åºåå
¥åº' : 'åºååºåº'; |
| | | await formApi.setFieldValue('operateType', type); |
| | | // æ´æ°æ¹æ¬¡å段æ¾ç¤º |
| | | await updateBatchFields(); |
| | | } |
| | | |
| | | /** è·å表å schema */ |
| | | function getSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'operateType', |
| | | label: 'æä½ç±»å', |
| | | component: 'RadioGroup', |
| | | defaultValue: 1, |
| | | componentProps: { |
| | | options: [ |
| | | { label: 'å
¥åº', value: 1 }, |
| | | { label: 'åºåº', value: 2 }, |
| | | ], |
| | | onChange: handleOperateTypeChange, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'itemId', |
| | | label: 'ç©æ', |
| | | component: markRaw(MdmItemSelect), |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©ç©æ', |
| | | onChange: handleItemChange, |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'warehouseId', |
| | | label: 'ä»åº', |
| | | component: markRaw(WmWarehouseSelect), |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©ä»åº', |
| | | onChange: handleWarehouseChange, |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'locationId', |
| | | label: 'åºåº', |
| | | component: markRaw(WmWarehouseLocationSelect), |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©åºåº', |
| | | warehouseId: selectedWarehouse.value?.id, |
| | | onChange: handleLocationChange, |
| | | }, |
| | | dependencies: { |
| | | triggerFields: ['warehouseId'], |
| | | componentProps: (values: any) => ({ |
| | | placeholder: 'è¯·éæ©åºåº', |
| | | warehouseId: values.warehouseId, |
| | | onChange: handleLocationChange, |
| | | }), |
| | | trigger: (values: any, formApi: any) => { |
| | | if (values.locationId !== undefined) { |
| | | void formApi.setFieldValue('locationId', undefined); |
| | | void formApi.setFieldValue('areaId', undefined); |
| | | } |
| | | }, |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'areaId', |
| | | label: 'åºä½', |
| | | component: markRaw(WmWarehouseAreaSelect), |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©åºä½', |
| | | locationId: selectedLocation.value?.id, |
| | | }, |
| | | dependencies: { |
| | | triggerFields: ['locationId'], |
| | | componentProps: (values: any) => ({ |
| | | placeholder: 'è¯·éæ©åºä½', |
| | | locationId: values.locationId, |
| | | }), |
| | | trigger: (values: any, formApi: any) => { |
| | | if (values.areaId !== undefined) { |
| | | void formApi.setFieldValue('areaId', undefined); |
| | | } |
| | | }, |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | // æ¯å¦æå¨å¡«åæ¹æ¬¡å·ï¼å¯ç¨æ¹æ¬¡ç®¡çæ¶æ¾ç¤ºï¼ |
| | | { |
| | | fieldName: 'manualBatchEntry', |
| | | label: 'æå¨å¡«åæ¹æ¬¡å·', |
| | | component: 'Switch', |
| | | defaultValue: false, |
| | | componentProps: { |
| | | class: 'w-auto', |
| | | checkedChildren: 'æ¯', |
| | | unCheckedChildren: 'å¦', |
| | | onChange: handleManualBatchEntryChange, |
| | | }, |
| | | dependencies: { |
| | | triggerFields: ['itemId'], |
| | | show: () => false, // é»è®¤éèï¼å¯ç¨æ¹æ¬¡ç®¡çæ¶æ¾ç¤º |
| | | }, |
| | | }, |
| | | // æ¹æ¬¡å·ï¼æå¨å¡«åæ¹æ¬¡å·æ¶æ¾ç¤ºï¼ |
| | | { |
| | | fieldName: 'batchCode', |
| | | label: 'æ¹æ¬¡å·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥æ¹æ¬¡å·', |
| | | }, |
| | | dependencies: { |
| | | triggerFields: ['itemId', 'manualBatchEntry'], |
| | | show: () => false, // é»è®¤éèï¼æ ¹æ®æå¨å¡«å设置æ¾ç¤º |
| | | }, |
| | | // æ ¹æ®é
ç½®å³å®æ¯å¦å¿
å¡« |
| | | rules: z.string().optional(), |
| | | }, |
| | | // çäº§æ¥æï¼æ ¹æ®æ¹æ¬¡é
ç½®æ¾ç¤ºï¼ä»
å
¥åºï¼ |
| | | { |
| | | fieldName: 'produceDate', |
| | | label: 'çäº§æ¥æ', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©çäº§æ¥æ', |
| | | format: 'YYYY-MM-DD', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | }, |
| | | dependencies: { |
| | | triggerFields: ['itemId'], |
| | | show: () => false, // é»è®¤éè |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | // æææï¼æ ¹æ®æ¹æ¬¡é
ç½®æ¾ç¤ºï¼ä»
å
¥åºï¼ |
| | | { |
| | | fieldName: 'expireDate', |
| | | label: 'æææè³', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©æææ', |
| | | format: 'YYYY-MM-DD', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | }, |
| | | dependencies: { |
| | | triggerFields: ['itemId'], |
| | | show: () => false, // é»è®¤éè |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'vendorId', |
| | | label: 'ä¾åºå', |
| | | component: markRaw(MdVendorSelect), |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©ä¾åºå', |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'quantity', |
| | | label: 'æ°é', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | placeholder: '请è¾å
¥æ°é', |
| | | precision: 2, |
| | | min: 0.01, |
| | | }, |
| | | rules: z.number().positive('æ°éå¿
须大äº0'), |
| | | }, |
| | | { |
| | | fieldName: 'reason', |
| | | label: 'åå ', |
| | | component: 'Textarea', |
| | | formItemClass: 'col-span-2', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥åå ', |
| | | rows: 3, |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | formItemClass: 'col-span-1', |
| | | labelWidth: 100, |
| | | }, |
| | | wrapperClass: 'grid-cols-2', |
| | | layout: 'horizontal', |
| | | schema: getSchema(), |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | fullscreen: false, |
| | | onCancel: () => { |
| | | modalApi.close(); |
| | | }, |
| | | onConfirm: async () => { |
| | | await handleSubmit(); |
| | | }, |
| | | onOpenChange: async (isOpen: boolean) => { |
| | | if (!isOpen) { |
| | | selectedItem.value = null; |
| | | selectedWarehouse.value = null; |
| | | selectedLocation.value = null; |
| | | batchEnabled.value = false; |
| | | batchConfig.value = null; |
| | | operateType.value = 1; |
| | | modalTitle.value = 'åºåè°æ´'; |
| | | return; |
| | | } |
| | | // é置表å |
| | | await formApi.resetForm(); |
| | | // é»è®¤éèæ¹æ¬¡ç¸å
³å段 |
| | | formApi.updateSchema([ |
| | | { fieldName: 'batchCode', dependencies: { show: () => false } }, |
| | | { fieldName: 'produceDate', dependencies: { show: () => false } }, |
| | | { fieldName: 'expireDate', dependencies: { show: () => false } }, |
| | | { fieldName: 'manualBatchEntry', dependencies: { show: () => false } }, |
| | | ]); |
| | | // éç½®æå¨å¡«åæ¹æ¬¡å·ç¶æ |
| | | manualBatchEntry.value = false; |
| | | // 妿æä¼ å
¥ç©æä¿¡æ¯ï¼å填表å |
| | | const data = modalApi.getData(); |
| | | if (data?.itemId) { |
| | | await formApi.setValues({ |
| | | itemId: data.itemId, |
| | | warehouseId: data.warehouseId, |
| | | locationId: data.locationId, |
| | | areaId: data.areaId, |
| | | }); |
| | | if (data.itemId) { |
| | | const itemDetail = await getItem(data.itemId); |
| | | selectedItem.value = itemDetail; |
| | | await loadBatchConfigAndUpdateFields(data.itemId); |
| | | } |
| | | } |
| | | }, |
| | | title: modalTitle, |
| | | }); |
| | | |
| | | /** æäº¤è¡¨å */ |
| | | async function handleSubmit() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | |
| | | const values = await formApi.getValues(); |
| | | |
| | | const { |
| | | itemId, |
| | | warehouseId, |
| | | locationId, |
| | | areaId, |
| | | batchCode, |
| | | produceDate, |
| | | expireDate, |
| | | vendorId, |
| | | quantity, |
| | | reason, |
| | | } = values; |
| | | |
| | | // å¯ç¨æ¹æ¬¡ç®¡çæ¶çæ ¡éª |
| | | if (batchEnabled.value) { |
| | | // æå¨å¡«åæ¹æ¬¡å·æ¶ï¼æ¹æ¬¡å·å¿
å¡« |
| | | if (manualBatchEntry.value && !batchCode) { |
| | | message.error('请è¾å
¥æ¹æ¬¡å·'); |
| | | return; |
| | | } |
| | | // æ ¹æ®æ¹æ¬¡é
ç½®æ ¡éªå¿
å¡«åæ®µï¼ä»
å
¥åºï¼ |
| | | if (operateType.value === 1) { |
| | | const config = batchConfig.value; |
| | | if (config?.produceDateFlag && !produceDate) { |
| | | message.error('è¯·éæ©çäº§æ¥æ'); |
| | | return; |
| | | } |
| | | if (config?.expireDateFlag && !expireDate) { |
| | | message.error('è¯·éæ©æææ'); |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | |
| | | try { |
| | | const type = operateType.value; |
| | | |
| | | if (type === 1) { |
| | | // å
¥åº |
| | | const params: MaterialStockAdjustInParams = { |
| | | itemId, |
| | | warehouseId, |
| | | locationId, |
| | | areaId, |
| | | batchCode, |
| | | produceDate, |
| | | expireDate, |
| | | vendorId, |
| | | quantity, |
| | | reason, |
| | | }; |
| | | await adjustMaterialStockIn(params); |
| | | message.success('å
¥åºæå'); |
| | | } else { |
| | | // åºåº |
| | | const params: MaterialStockAdjustOutParams = { |
| | | itemId, |
| | | warehouseId, |
| | | locationId, |
| | | areaId, |
| | | batchCode, |
| | | vendorId, |
| | | quantity, |
| | | reason, |
| | | }; |
| | | await adjustMaterialStockOut(params); |
| | | message.success('åºåºæå'); |
| | | } |
| | | |
| | | emit('success'); |
| | | modalApi.close(); |
| | | } catch (error) { |
| | | // é误ç±è¯·æ±æ¦æªå¨å¤ç |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal class="w-3/5"> |
| | | <Form class="mx-4" /> |
| | | <BatchConfigDisplay |
| | | ref="batchConfigDisplayRef" |
| | | :item-id="selectedItem?.id" |
| | | :is-batch-managed="batchEnabled" |
| | | /> |
| | | </Modal> |
| | | </template> |
| | |
| | | width: 100, |
| | | }, |
| | | { |
| | | field: 'frozenQuantity', |
| | | title: 'å»ç»æ°é', |
| | | width: 100, |
| | | formatter: ({ cellValue }: { cellValue: number }) => |
| | | (cellValue || 0).toFixed(2), |
| | | }, |
| | | { |
| | | field: 'reservedQuantity', |
| | | title: 'å ç¨é', |
| | | width: 100, |
| | | formatter: ({ cellValue }: { cellValue: number }) => |
| | | (cellValue || 0).toFixed(2), |
| | | }, |
| | | { |
| | | field: 'inTransitQuantity', |
| | | title: 'å¨éé', |
| | | width: 100, |
| | | formatter: ({ cellValue }: { cellValue: number }) => |
| | | (cellValue || 0).toFixed(2), |
| | | }, |
| | | { |
| | | field: 'availableQuantity', |
| | | title: 'å¯ç¨é', |
| | | width: 100, |
| | | cellRender: { |
| | | name: 'CellText', |
| | | props: { |
| | | class: ({ row }: { row: MesWmMaterialStockApi.MaterialStock }) => |
| | | (row.availableQuantity || 0) < 0 ? 'text-red-500 font-bold' : '', |
| | | formatter: ({ row }: { row: MesWmMaterialStockApi.MaterialStock }) => |
| | | ((row.availableQuantity || 0) as number).toFixed(2), |
| | | }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'unitMeasureName', |
| | | title: 'åä½', |
| | | width: 80, |
| | |
| | | width: 100, |
| | | }, |
| | | { |
| | | field: 'frozenQuantity', |
| | | title: 'å»ç»æ°é', |
| | | width: 100, |
| | | formatter: ({ cellValue }: { cellValue: number }) => |
| | | (cellValue || 0).toFixed(2), |
| | | }, |
| | | { |
| | | field: 'reservedQuantity', |
| | | title: 'å ç¨é', |
| | | width: 100, |
| | | formatter: ({ cellValue }: { cellValue: number }) => |
| | | (cellValue || 0).toFixed(2), |
| | | }, |
| | | { |
| | | field: 'inTransitQuantity', |
| | | title: 'å¨éé', |
| | | width: 100, |
| | | formatter: ({ cellValue }: { cellValue: number }) => |
| | | (cellValue || 0).toFixed(2), |
| | | }, |
| | | { |
| | | field: 'availableQuantity', |
| | | title: 'å¯ç¨é', |
| | | width: 100, |
| | | cellRender: { |
| | | name: 'CellText', |
| | | props: { |
| | | class: ({ row }: { row: MesWmMaterialStockApi.MaterialStock }) => |
| | | (row.availableQuantity || 0) < 0 ? 'text-red-500 font-bold' : '', |
| | | formatter: ({ row }: { row: MesWmMaterialStockApi.MaterialStock }) => |
| | | ((row.availableQuantity || 0) as number).toFixed(2), |
| | | }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'receiptTime', |
| | | title: 'å
¥åºæ¥æ', |
| | | width: 180, |
| | |
| | | import { MdItemTypeTree } from '#/views/mes/md/item/type/components'; |
| | | import { WmBatchDetail } from '#/views/wls/batch/components'; |
| | | import AreaForm from '#/views/wls/warehouse/area/modules/form.vue'; |
| | | import { WmStockAdjustModal } from './components'; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | | |
| | | const [AreaModal, areaModalApi] = useVbenModal({ |
| | | connectedComponent: AreaForm, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | const [StockAdjustModal, stockAdjustModalApi] = useVbenModal({ |
| | | connectedComponent: WmStockAdjustModal, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | |
| | | return; |
| | | } |
| | | areaModalApi.setData({ formType: 'detail', id: row.areaId }).open(); |
| | | } |
| | | |
| | | /** æå¼åºåè°æ´å¼¹çª */ |
| | | function handleOpenStockAdjust() { |
| | | stockAdjustModalApi.setData({}).open(); |
| | | } |
| | | |
| | | /** åºåè°æ´æååè° */ |
| | | function handleStockAdjustSuccess() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** æå¼æ¹æ¬¡è¯¦æ
å¼¹çª */ |
| | |
| | | <template> |
| | | <Page auto-content-height><AreaModal /> |
| | | <WmBatchDetail ref="batchDetailRef" /> |
| | | <StockAdjustModal @success="handleStockAdjustSuccess" /> |
| | | |
| | | <div class="flex h-full w-full"> |
| | | <!-- å·¦ä¾§ç©æåç±»æ --> |
| | |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: 'åºåè°æ´', |
| | | type: 'default', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['mes:wm-material-stock:adjust'], |
| | | onClick: handleOpenStockAdjust, |
| | | }, |
| | | { |
| | | label: $t('ui.actionTitle.export'), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | |
| | | |
| | | import { h, markRaw } from 'vue'; |
| | | |
| | | import { DICT_TYPE, MesAutoCodeRuleCode } from '@vben/constants'; |
| | | import { |
| | | DICT_TYPE, |
| | | MesAutoCodeRuleCode, |
| | | MesWmSalesNoticeOutStatusEnum, |
| | | } from '@vben/constants'; |
| | | |
| | | import { Button } from 'ant-design-vue'; |
| | | import { Button, Tag } from 'ant-design-vue'; |
| | | |
| | | import { z } from '#/adapter/form'; |
| | | import { generateAutoCode } from '#/api/mes/md/autocode/record'; |
| | | import { ErpSaleOrderSelect } from '#/views/erp/sale/order/components'; |
| | | import { MdClientSelect } from '#/views/mes/md/client/components'; |
| | | import { MdItemSelect } from '#/views/mes/md/item/components'; |
| | | |
| | |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'salesOrderCode', |
| | | label: 'éå®è®¢åç¼å·', |
| | | component: 'Input', |
| | | fieldName: 'saleOrderId', |
| | | label: 'éå®è®¢å', |
| | | component: markRaw(ErpSaleOrderSelect), |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥éå®è®¢åç¼å·', |
| | | placeholder: 'è¯·éæ©éå®è®¢å', |
| | | // éæ©éå®è®¢ååï¼èªå¨å填客æ·ä¿¡æ¯ |
| | | onChange: (item: any) => { |
| | | if (item?.customerId && formApi) { |
| | | formApi.setFieldValue('clientId', item.customerId); |
| | | formApi.setFieldValue('clientName', item.customerName); |
| | | } |
| | | }, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'clientName', |
| | | label: '', |
| | | component: 'Input', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | |
| | | component: markRaw(MdClientSelect), |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©å®¢æ·', |
| | | disabled: true, |
| | | }, |
| | | dependencies: { |
| | | triggerFields: ['clientName'], |
| | | componentProps: (values) => ({ |
| | | placeholder: 'è¯·éæ©å®¢æ·', |
| | | disabled: true, |
| | | clientName: values.clientName as string, |
| | | }), |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | |
| | | }, |
| | | }, |
| | | { |
| | | field: 'outStatus', |
| | | title: 'åºåºç¶æ', |
| | | minWidth: 100, |
| | | cellRender: { |
| | | name: 'CellTag', |
| | | props: { |
| | | formatter: ({ row }: { row: MesWmSalesNoticeApi.SalesNotice }) => { |
| | | const statusMap: Record<number, { color: string; label: string }> = { |
| | | [MesWmSalesNoticeOutStatusEnum.NONE]: { color: 'default', label: 'æªåºåº' }, |
| | | [MesWmSalesNoticeOutStatusEnum.PARTIAL]: { color: 'warning', label: 'é¨ååºåº' }, |
| | | [MesWmSalesNoticeOutStatusEnum.ALL]: { color: 'success', label: 'å
¨é¨åºåº' }, |
| | | }; |
| | | const status = statusMap[row.outStatus ?? MesWmSalesNoticeOutStatusEnum.NONE]; |
| | | return { color: status?.color, label: status?.label ?? 'æªåºåº' }; |
| | | }, |
| | | }, |
| | | }, |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | width: 200, |
| | | fixed: 'right', |
| | |
| | | width: 100, |
| | | }, |
| | | { |
| | | field: 'outCount', |
| | | title: 'å·²åºåºæ°é', |
| | | width: 100, |
| | | formatter: ({ cellValue }: { cellValue: number }) => (cellValue || 0).toFixed(2), |
| | | }, |
| | | { |
| | | field: 'outProgress', |
| | | title: 'åºåºè¿åº¦', |
| | | width: 120, |
| | | cellRender: { |
| | | name: 'CellText', |
| | | props: { |
| | | formatter: ({ row }: { row: MesWmSalesNoticeLineApi.SalesNoticeLine }) => { |
| | | const quantity = row.quantity || 0; |
| | | const outCount = row.outCount || 0; |
| | | const percent = quantity > 0 ? Math.round((outCount / quantity) * 100) : 0; |
| | | return `${outCount.toFixed(2)} / ${quantity.toFixed(2)} (${percent}%)`; |
| | | }, |
| | | }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'batchCode', |
| | | title: 'æ¹æ¬¡å·', |
| | | minWidth: 120, |
| | |
| | | |
| | | import { Button, message } from 'ant-design-vue'; |
| | | |
| | | import { useRouter } from 'vue-router'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | deleteSalesNotice, |
| | | exportSalesNotice, |
| | | generateProductSales, |
| | | getSalesNoticePage, |
| | | } from '#/api/mes/wm/salesnotice'; |
| | | import { $t } from '#/locales'; |
| | |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | const router = useRouter(); |
| | | |
| | | /** å·æ°è¡¨æ ¼ */ |
| | | function handleRefresh() { |
| | |
| | | /** æ§è¡åºåº */ |
| | | function handleFinish(row: MesWmSalesNoticeApi.SalesNotice) { |
| | | formModalApi.setData({ formType: 'finish', id: row.id }).open(); |
| | | } |
| | | |
| | | /** çæéå®åºåºå */ |
| | | async function handleGenerateProductSales(row: MesWmSalesNoticeApi.SalesNotice) { |
| | | try { |
| | | const productSalesId = await generateProductSales(row.id!); |
| | | message.success('çæéå®åºåºåæå'); |
| | | // 跳转å°éå®åºåºåé¡µé¢ |
| | | router.push({ |
| | | path: '/wls/product-sales', |
| | | query: { id: productSalesId }, |
| | | }); |
| | | } catch (e) { |
| | | console.error(e); |
| | | } |
| | | } |
| | | |
| | | /** å é¤åè´§éç¥å */ |
| | |
| | | }, |
| | | }, |
| | | { |
| | | label: 'çæåºåºå', |
| | | type: 'link', |
| | | icon: 'ant-design:file-protect-outlined', |
| | | auth: ['mes:wm-product-sales:create'], |
| | | ifShow: row.status === MesWmSalesNoticeStatusEnum.APPROVED, |
| | | onClick: handleGenerateProductSales.bind(null, row), |
| | | }, |
| | | { |
| | | label: 'æ§è¡åºåº', |
| | | type: 'link', |
| | | auth: ['mes:wm-sales-notice:update'], |