feat: 完成了物料总表,生产发料,入料,以及部分采购计划。

This commit is contained in:
c
2026-03-06 15:04:57 +08:00
parent 219eef4729
commit b12b758be2
27 changed files with 3681 additions and 685 deletions

View File

@@ -18,12 +18,596 @@ export default {
[SERVER_ERROR_NAME]: "404",
[GATEWAY_TIMEOUT_NAME]: "500",
[HOME_NAME]: "Workbenches",
[TEST_NAME]: "summary table",
SYS: "SystemManage",
SYSUSER: "UserManage",
[TEST_NAME]: "Summary Table",
ErrorLog: "Error Logger",
SYS: "System Manage",
SYSUSER: "User Manage",
warehouse: "Warehouse",
warehouse_item: "Warehouse Item",
stock_by_type: "Stock By Type",
stock_by_brand: "Stock By Brand",
stock_by_warehouse: "Stock By Warehouse",
stock_transfer_order: "Stock Transfer Order",
warehouse_receipt: "Warehouse Receipt",
inventory_count: "Inventory Count",
production: "Production",
bom: "BOM",
production_plan: "Production Plan",
production_issue: "Production Issue",
production_return: "Production Return",
finished_product_receipt: "Finished Product Receipt",
finished_product_shipment: "Finished Product Shipment",
purchase: "Purchase",
purchase_plan: "Purchase Plan",
purchase_order: "Purchase Order",
sale: "Sale",
sale_order: "Sale Order",
device_sn: "Device SN",
repair_record: "Repair Record",
systemset: "System Setting",
syschannel: "Channel",
key_account: "Key Account",
vendor: "Vendor",
store: "Store",
sysrecord: "Record",
sysrole: "Role",
},
_prop: {
common: {
tel: "Tel",
address: "Address",
createDate: "Create Date",
status: "Status",
operate: "Operate",
remark: "Remark",
startdate: "Start Date",
enddate: "End Date",
},
warehouse: {
warehouse: {
storeMark: "Remark",
storeName: "Store Name",
},
warehouse_item: {
productPacking: "Min Packing",
productPackSize: "Pack Size",
productBrand: "Brand",
productMark: "Remark",
createUserName: "Creator",
partNumber: "Part Number",
productSpecs: "Specs",
productType: "Type",
productPrice: "Price",
availableVendors: "Available Vendors",
selectedVendors: "Selected Vendors",
vendorName: "Vendor Name",
costPrice: "Cost Price",
procureDate: "Last Procure Date",
},
stock: {
productCount: "Count",
},
stocktransferorder: {
outStoreName: "Out Store",
formCode: "Form Code",
formName: "Form Name",
formMark: "Form Mark",
storeName: "In Store",
storeId: "In Store",
outStoreId: "Out Store",
createDate: "Create Date",
},
warehousereceipt: {
formCode: "Form Code",
formName: "Form Name",
formMark: "Form Mark",
storeName: "Store Name",
storeId: "Store",
},
inventorycount: {
formCode: "Form Code",
formName: "Form Name",
formMark: "Form Mark",
storeName: "Store Name",
storeId: "Store",
},
},
production: {
bom: {
brandName: "Brand Name",
bomNo: "BOM No",
formMark: "BOM Mark",
bomName: "BOM Name",
customerName: "Customer Name",
spec: "Spec",
manufacturer: "Manufacturer",
searchCode: "BOM No / Name",
},
bom_item: {
productPackSize: "Pack Size",
productBrand: "Brand",
productMark: "Remark",
manufactureCount: "Count",
partNumber: "Part Number",
productSpecs: "Specs",
productType: "Type",
itemPosition: "Position",
sameUseCount: "Same Use Count",
sameUseNum: "Same Use",
},
production_plan: {
storeNo: "Store No",
productionNote: "Note",
storeName: "Store Name",
productionCount: "Count",
projectName: "Project Name",
projectId: "Project Id",
productionMark: "Mark",
productionNum: "Form No",
requiredQty: "Required Qty",
stockQty: "Stock Qty",
diffQty: "Diff Qty",
outStoreNo: "Out Store",
actualQty: "Actual Qty",
},
production_issue: {
formCode: "Form Code",
formStatus: "Status",
formMark: "Mark",
storeName: "Store",
requiredQty: "Required Qty",
actualQty: "Actual Qty",
expectedReturnQty: "Expected Return",
actualReturnQty: "Actual Return",
},
production_return: {
formCode: "Form Code",
formStatus: "Status",
formMark: "Mark",
storeName: "Store",
returnQty: "Return Qty",
},
finishedproductreceipt: {
totalValue: "Total Value",
formCode: "Form Code",
formName: "Form Name",
formMark: "Form Mark",
storeName: "Store",
},
},
purchase: {
purchase_plan: {
planNo: "Plan No",
remask: "Remark",
planName: "Plan Name",
planStatus: "Status",
storeName: "Store",
vendorName: "Vendor",
baseTitle: "Basic Info",
tableTitle: "Details",
generateOrder: "Generate Order",
model: "Model",
defaultVendor: "Default Vendor",
demandQuantity: "Demand Qty",
packQuantity: "Pack Qty",
purchaseQuantity: "Purchase Qty",
unitPrice: "Unit Price",
totalPrice: "Total Price",
purchaseStatus: "Status",
},
purchase_plan_item: {
partNumber: "Part Number",
purchaseCount: "Count",
completeCount: "Complete",
price: "Price",
currentCount: "Current",
input_partNumber: "Enter Part Number",
input_purchaseCount: "Enter Count",
input_price: "Enter Price",
input_currentCount: "Enter Current",
},
purchaseorder: {
totalValue: "Total Value",
formCode: "Form Code",
formMark: "Mark",
formStatus: "Status",
vendorName: "Vendor",
},
finishedproductshipment: {
formCode: "Form Code",
formName: "Form Name",
formMark: "Mark",
storeName: "Store",
},
},
sale: {
saleorder: {
totalValue: "Total Value",
formCode: "Form Code",
formName: "Form Name",
formMark: "Mark",
formStatus: "Status",
customerName: "Customer",
},
devicesn: {
softVersion: "Soft Version",
AlVersion: "AL Version",
serialNum: "Serial Num",
productSn: "Product SN",
repairMark: "Repair Mark",
outProductDate: "Out Date",
productType: "Type",
mac: "MAC",
},
repairrecord: {
productSn: "Product SN",
repairMark: "Repair Mark",
outProductDate: "Out Date",
repairDate: "Repair Date",
productType: "Type",
mac: "MAC",
},
},
systemset: {
vendor: {
vendorName: "Vendor Name",
contactPerson: "Contact",
vendorMark: "Remark",
},
store: {
storeMark: "Remark",
storeName: "Store Name",
},
keyaccount: {
contactPerson: "Contact",
keyAccountMark: "Remark",
keyAccountName: "Account Name",
},
syschannel: {
iconName: "Icon",
show: "Show",
eventName: "Event Name",
channelName: "Channel Name",
className: "Class",
channelType: "Type",
sort: "Sort",
channelLink: "Link",
viewLink: "View Link",
},
sysrecord: {
recordType: "Type",
ip: "IP",
linkUrl: "URL",
channelName: "Channel",
remark: "Remark",
createUserName: "Operator",
isSuccess: "Status",
createDate: "Date",
},
sysrole: {
roleName: "Role Name",
roleType: "Role Type",
},
},
},
_button: {
add: "Add",
edit: "Edit",
remove: "Delete",
batchRemove: "Batch Delete",
submit: "Submit",
confirm: "Confirm",
cancel: "Cancel",
reset: "Reset",
enable: "Enable",
disable: "Disable",
search: "Search",
save: "Save",
showItem: "Show Details",
generatePurchasePlan: "Generate Purchase Plan",
generateProductionIssue: "Generate Issue",
generateTransferOrder: "Generate Transfer",
viewMaterialShortage: "View Shortage",
viewLossRate: "View Loss Rate",
shortageFilterButton: "Shortage Data",
unfilterButton: "All Data",
approve: "Approve",
reject: "Reject",
productionReturn: "Return",
generatePurchaseOrder: "Generate Order",
download: "Download",
print: "Print",
vendorList: "Vendor List",
printQrCode: "Print QR Code",
},
_message: {
common: {
input_tel: "Enter Tel",
type_tel: "Tel must be number",
input_address: "Enter Address",
input_remark: "Enter Remark",
select_status: "Select Status",
add_success: "Add Success!",
add_failure: "Add Failed: ",
edit_success: "Update Success!",
edit_failure: "Update Failed: ",
delete_confirm: "Confirm Delete",
delete_success: "Delete Success!",
delete_failure: "Delete Failed: ",
delete_cannel: "Delete Cancelled",
generate_document_mark_prefix: "System [",
generate_document_mark_suffix: "]",
approve_confirm: "Confirm Approve",
approve_success: "Approve Success",
approve_fail: "Approve Failed",
approve_cannel: "Approve Cancelled",
reject_confirm: "Confirm Reject",
reject_success: "Reject Success",
reject_fail: "Reject Failed",
reject_cannel: "Reject Cancelled",
},
warehouse: {
warehouse_item: {
input_productNumber: "Enter Part Number",
input_productSpec: "Enter Specs",
input_productType: "Enter Type",
input_productBrand: "Enter Brand",
input_productPackSize: "Enter Pack Size",
input_productPacking: "Enter Min Packing",
input_productMark: "Enter Remark",
input_partNumber: "Enter Part Number",
input_productSpecs: "Enter Specs",
input_costPrice: "Enter Cost Price",
select_vendor: "Select Vendor",
select_procureDate: "Select Procure Date",
search_vendor: "Search Vendor",
delete_message: "Delete Warehouse Item",
not_exist_partNumber: "Part Number Not Exist",
no_qrcode_content: "No QR Code Content",
vendor_duplicate: "Vendor cannot be duplicated",
},
stocktransferorder: {
input_storeId: "Enter In Store",
input_outStoreId: "Enter Out Store",
input_formName: "Enter Form Name",
input_formMark: "Enter Form Mark",
delete_message: "Delete Transfer Order",
},
warehousereceipt: {
select_storeId: "Select Store",
input_formName: "Enter Form Name",
input_formMark: "Enter Form Mark",
delete_message: "Delete Receipt",
},
inventorycount: {
select_storeId: "Select Store",
input_formName: "Enter Form Name",
input_formMark: "Enter Form Mark",
delete_message: "Delete Count",
},
},
production: {
bom: {
input_bomNo: "Enter BOM No",
input_bomName: "Enter BOM Name",
input_manufacturer: "Enter Manufacturer",
input_spec: "Enter Spec",
input_brandName: "Enter Brand",
input_formMark: "Enter BOM Mark",
delete_message: "Delete BOM",
upload_bomitems: "Upload BOM Items",
input_manufactureCount: "Enter Count",
input_itemPosition: "Enter Position",
unpair_manufactureCount_itemPosition: "Count not match Position",
},
production_plan: {
select_projectId: "Select BOM",
input_productionNum: "Enter Form No",
select_storeNo: "Select Store",
input_productionCount: "Enter Count",
input_productionMark: "Enter Mark",
input_productionNote: "Enter Note",
delete_message: "Delete Plan",
select_production_plan: "Select Plan",
duplicate_store_no: "Only one store supported",
generate_purchase_plan_confirm: "Generate Purchase Plan?",
generate_purchase_plan_mark_suffix: "] Generate Plan [",
generate_purchase_plan_name_suffix: " Shortage",
generate_purchase_plan_success: "Generate Success",
generate_purchase_plan_fail: "Generate Failed: ",
generate_transfer_order_confirm: "Generate Transfer?",
generate_transfer_order_mark_suffix: "] Generate Transfer [",
generate_transfer_order_name_suffix: " Transfer",
generate_transfer_order_success: "Generate Success",
generate_transfer_order_fail: "Generate Failed: ",
generate_production_issue_confirm: "Generate Issue?",
generate_production_issue_mark_suffix: "] Generate Issue [",
generate_production_issue_name_suffix: " Issue",
generate_production_issue_success: "Generate Success",
generate_production_issue_fail: "Generate Failed: ",
error_production_status: "Only incomplete plans",
},
production_issue: {
only_approved_can_return: "Only approved can return",
get_detail_failed: "Get detail failed",
no_return_data: "No return data",
enter_valid_return_qty: "Enter valid return qty",
return_order_created: "Return order created",
create_return_order_failed: "Create failed",
generate_return_confirm: "Generate Return?",
generate_return_mark_suffix: "] Generate Return [",
generate_return_name_suffix: " Return",
generate_return_success: "Generate Success",
generate_return_fail: "Generate Failed: ",
},
production_return: {},
finishedproductreceipt: {
delete_message: "Delete Receipt",
},
},
purchase: {
purchase_plan: {
delete_message: "Delete Plan",
input_planName: "Enter Plan Name",
select_vendor: "Select Vendor",
select_store: "Select Store",
input_remask: "Enter Remark",
upload_planItems: "Upload Items",
get_items_error: "Get items failed",
select_items: "Select items",
generate_order_success: "Generate Success",
generate_order_error: "Generate Failed",
vendor_priority_tip: "Priority",
},
purchaseorder: {
delete_message: "Delete Order",
},
finishedproductshipment: {
delete_message: "Delete Shipment",
},
},
sale: {
saleorder: {
delete_message: "Delete Order",
},
},
systemset: {
vendor: {
input_vendorName: "Enter Vendor Name",
input_contactPerson: "Enter Contact",
input_vendorMark: "Enter Remark",
delete_message: "Delete Vendor",
},
store: {
input_storeName: "Enter Store Name",
input_storeMark: "Enter Remark",
delete_message: "Delete Store",
},
keyaccount: {
input_keyAccountName: "Enter Account Name",
input_contactPerson: "Enter Contact",
input_keyAccountMark: "Enter Remark",
delete_message: "Delete Account",
},
syschannel: {
input_channelName: "Enter Channel Name",
input_channelLink: "Enter Link",
input_eventName: "Enter Event",
input_className: "Enter Class",
input_iconName: "Enter Icon",
input_channelType: "Select Type",
input_sort: "Enter Sort",
input_show: "Select Show",
input_viewLink: "Enter View Link",
delete_message: "Delete Channel",
},
sysrole: {
input_roleName: "Enter Role Name",
select_roleType: "Select Type",
delete_message: "Delete Role",
},
},
},
_title: {
warehouse: {
warehouseitem: {
add: "Add Warehouse Item",
edit: "Edit Warehouse Item",
vendorList: "Vendor List",
printQrCode: "Print QR Code",
},
stocktransferorder: {
add: "Add Transfer",
edit: "Edit Transfer",
},
warehousereceipt: {
add: "Add Receipt",
edit: "Edit Receipt",
},
inventorycount: {
add: "Add Count",
edit: "Edit Count",
},
},
production: {
bom: {
add: "Add BOM",
edit: "Edit BOM",
showItem: "BOM Items",
baseTitle: "BOM Info",
tableTitle: "BOM Details",
},
production_plan: {
add: "Add Plan",
edit: "Edit Plan",
dialog: "Shortage View",
issueDialog: "Issue Edit",
},
production_issue: {
returnDialog: "Return Edit",
},
finishedproductreceipt: {
add: "Add Receipt",
edit: "Edit Receipt",
},
finishedproductshipment: {
add: "Add Shipment",
edit: "Edit Shipment",
},
},
purchase: {
purchase_plan: {
add: "Add Plan",
edit: "Edit Plan",
generateOrder: "Generate Order",
model: "Model",
defaultVendor: "Default Vendor",
demandQuantity: "Demand Qty",
packQuantity: "Pack Qty",
purchaseQuantity: "Purchase Qty",
unitPrice: "Unit Price",
totalPrice: "Total Price",
purchaseStatus: "Status",
},
purchaseorder: {
add: "Add Order",
edit: "Edit Order",
},
},
sale: {
saleorder: {
add: "Add Order",
edit: "Edit Order",
},
},
systemset: {
vendor: {
add: "Add Vendor",
edit: "Edit Vendor",
},
store: {
add: "Add Store",
edit: "Edit Store",
},
keyaccount: {
add: "Add Account",
edit: "Edit Account",
},
syschannel: {
add: "Add Channel",
edit: "Edit Channel",
},
sysrole: {
add: "Add Role",
edit: "Edit Role",
},
},
},
_tabNav: {
refresh: "Refresh Page",
@@ -40,7 +624,7 @@ export default {
},
_headerBar: {
search: "Search",
changeLanguage: "Successfully modified the language",
changeLanguage: "Successfully modified the language!",
profile: "My Profile",
setting: "My Setting",
messageCenter: "My Message",
@@ -232,4 +816,42 @@ export default {
selectKeydown: "Select",
closeKeyDown: " Close",
},
_base_info: {
unknown: "-",
status: {
enable: "Enable",
disable: "Disable",
},
production: {
production_plan: {
no_complete: "Not Complete",
completed: "Completed",
approving: "Approving",
reviewed: "Reviewed",
},
},
purchase: {
purchase_plan: {
pending: "Pending",
in_progress: "In Progress",
completed: "Completed",
},
purchase_plan_item: {
no_start: "Not Purchased",
ordered: "Purchasing",
completed: "Purchased",
},
},
form_status: {
no_approve: "Not Approved",
approve: "Approved",
reject: "Rejected",
no_complete: "Not Complete",
complete: "Completed",
receipting: "Receiving",
imported: "Imported",
approving: "Approving",
returned: "Returned",
},
},
};

View File

@@ -84,6 +84,11 @@ export default {
productSpecs: "型号",
productType: "规格名称",
productPrice: "参考价格",
availableVendors: "可选供应商",
selectedVendors: "已选供应商",
vendorName: "供应商名称",
costPrice: "成本价",
procureDate: "最后采购日期",
},
stock: {
productCount: "数量",
@@ -97,6 +102,11 @@ export default {
storeId: "入货仓库",
outStoreId: "出货仓库",
createDate: "创建时间",
formStatus: "单据状态",
partNumber: "物料编号",
productSpec: "物料规格",
productCount: "调拨数量",
demandCount: "库存数量",
},
warehousereceipt: {
formCode: "单据编号",
@@ -104,6 +114,11 @@ export default {
formMark: "单据备注",
storeName: "仓库名称",
storeId: "仓库",
formStatus: "单据状态",
partNumber: "物料编号",
productSpec: "物料规格",
productCount: "入库数量",
createDate: "创建时间",
},
inventorycount: {
formCode: "单据编号",
@@ -111,6 +126,16 @@ export default {
formMark: "单据备注",
storeName: "仓库名称",
storeId: "仓库",
partNumber: "物料编号",
productSpec: "物料规格",
productCount: "盘点数量",
originalProductCount: "原始数量",
diffCount: "差异数量",
stockTakingMark: "盘点备注",
reserve1: "预留字段1",
reserve2: "预留字段2",
createDate: "创建时间",
formStatus: "单据状态",
},
},
production: {
@@ -151,17 +176,22 @@ export default {
outStoreNo: "发料仓库",
actualQty: "实发数量",
},
productionissue: {
production_issue: {
formCode: "单据编号",
formStatus: "单据状态",
formMark: "单据备注",
storeName: "仓库",
requiredQty: "需求数量",
actualQty: "实发数量",
expectedReturnQty: "应退数量",
actualReturnQty: "实退数量",
},
productionreturn: {
production_return: {
formCode: "单据编号",
formStatus: "单据状态",
formMark: "单据备注",
storeName: "仓库",
returnQty: "退料数量",
},
finishedproductreceipt: {
totalValue: "入库数量",
@@ -169,15 +199,51 @@ export default {
formName: "单据名称",
formMark: "单据备注",
storeName: "仓库",
storeId: "仓库",
formStatus: "单据状态",
productType: "型号",
productSn: "SN号",
mac: "MAC地址",
serialNum: "序列号",
softVersion: "软件版本",
alVersion: "算法版本",
alNum: "算法标志",
alTxt: "激活状态",
manufacturingDate: "时间",
mark: "备注",
createDate: "创建时间",
},
},
purchase: {
purchaseplan: {
purchase_plan: {
planNo: "采购计划号",
remask: "备注",
planName: "计划单名称",
planStatus: "计划状态",
storeName: "入库仓库",
vendorName: "供应商",
baseTitle: "采购计划基本信息",
tableTitle: "采购明细",
generateOrder: "生成采购订单",
model: "型号",
defaultVendor: "默认供应商",
demandQuantity: "需求量",
packQuantity: "包装数量",
purchaseQuantity: "采购数量",
unitPrice: "单价",
totalPrice: "总价",
purchaseStatus: "采购状态",
},
purchase_plan_item: {
partNumber: "商品编号",
purchaseCount: "计划数量",
completeCount: "已完成数量",
price: "单价",
currentCount: "本次采购数量",
input_partNumber: "请输入商品编号",
input_purchaseCount: "请输入计划数量",
input_price: "请输入单价",
input_currentCount: "请输入本次采购数量",
},
purchaseorder: {
totalValue: "订单总额",
@@ -191,6 +257,19 @@ export default {
formName: "单据名称",
formMark: "单据备注",
storeName: "仓库",
storeId: "仓库",
formStatus: "单据状态",
productType: "型号",
productSn: "SN号",
mac: "MAC地址",
serialNum: "序列号",
softVersion: "软件版本",
alVersion: "算法版本",
alNum: "算法标志",
alTxt: "激活状态",
manufacturingDate: "时间",
mark: "备注",
createDate: "创建时间",
},
},
sale: {
@@ -201,6 +280,14 @@ export default {
formMark: "单据备注",
formStatus: "审核状态",
customerName: "客户名称",
customerId: "客户",
partNumber: "物料编号",
saleCount: "销售数量",
price: "单价",
totalPrice: "总价",
sendCount: "出库数量",
surplusCount: "剩余量",
saleMark: "备注",
},
devicesn: {
softVersion: "软件版本",
@@ -211,6 +298,12 @@ export default {
outProductDate: "出货时间",
productType: "型号",
mac: "MAC 地址",
alNum: "算法标志",
alStatus: "激活状态",
mark: "备注",
keyAccountId: "客户",
keyAccountName: "客户名称",
outStatus: "出货状态",
},
repairrecord: {
productSn: "SN 号",
@@ -219,6 +312,10 @@ export default {
repairDate: "维修日期",
productType: "型号",
mac: "MAC 地址",
repairStatus: "维修状态",
manufacturingDate: "生产日期",
mark: "备注",
keyAccountId: "客户",
},
},
systemset: {
@@ -275,6 +372,7 @@ export default {
enable: "启用",
disable: "禁用",
search: "查询",
save: "保存",
showItem: "展示明细",
generatePurchasePlan: "生成采购计划",
generateProductionIssue: "生成发料单",
@@ -283,6 +381,14 @@ export default {
viewLossRate: "查看损耗率",
shortageFilterButton: "缺料数据",
unfilterButton: "全部数据",
approve: "审核",
reject: "反审",
productionReturn: "退料",
generatePurchaseOrder: "生成采购订单",
download: "下载",
print: "打印",
editVendors: "供应商列表",
printQrCode: "打印二维码",
},
_message: {
common: {
@@ -295,11 +401,20 @@ export default {
add_failure: "添加失败!失败信息:",
edit_success: "更新成功!",
edit_failure: "更新失败!失败信息:",
delete_confirm: "是否删除",
delete_success: "删除成功!",
delete_failure: "删除失败!失败信息:",
delete_cannel: "取消删除!",
generate_document_mark_prefix: "系统由【",
generate_document_mark_suffix: "】",
approve_confirm: "是否审核通过",
approve_success: "审核成功",
approve_fail: "审核失败",
approve_cannel: "审核取消",
reject_confirm: "是否需要反审",
reject_success: "反审成功",
reject_fail: "反审失败",
reject_cannel: "反审取消",
},
warehouse: {
warehouse_item: {
@@ -307,11 +422,21 @@ export default {
input_productSpec: "请输入物料型号",
input_productType: "请输入物料规格",
input_productBrand: "请输入品牌",
input_productPackSize: "请输入最小包装数量",
input_productPacking: "请输入封装",
input_productMark: "请输入说明",
input_productPackSize: "请输入封装",
input_productPacking: "请输入最小包装数量",
input_productMark: "请输入备注",
input_partNumber: "请输入物料编号",
input_productSpecs: "请输入物料型号",
input_costPrice: "请输入成本价",
select_vendor: "请选择供应商",
select_procureDate: "请选择采购日期",
search_vendor: "搜索供应商",
delete_message: "删除物料信息",
not_exist_partNumber: "物料不存在",
no_qrcode_content: "无二维码内容",
vendor_duplicate: "供应商不能重复",
save_vendors_success: "保存供应商成功",
save_vendors_fail: "保存供应商失败",
},
stocktransferorder: {
input_storeId: "请输入入货仓库",
@@ -319,17 +444,66 @@ export default {
input_formName: "请输入单据名称",
input_formMark: "请输入单据备注",
delete_message: "删除调拨单",
input_formCode: "请输入单据编号",
select_storeId: "请选择入货仓库",
select_outStoreId: "请选择出货仓库",
approve_confirm: "是否审核通过",
approve_success: "审核成功",
approve_fail: "审核失败",
reject_confirm: "是否需要反审",
reject_success: "反审成功",
reject_fail: "反审失败",
same_warehouse: "入库仓库和出库仓库不能相同",
insufficient_stock: "物料库存不足",
already_approved: "调拨单已经审核",
not_approved: "调拨单不是已审核状态,不能反审",
no_materials: "调拨单没有明细",
import_success: "导入成功",
import_fail: "导入失败",
input_productCount: "请输入调拨数量",
productCount_min_1: "调拨数量必须大于等于1",
},
warehousereceipt: {
select_storeId: "请选择仓库",
input_formName: "请输入单据名称",
input_formMark: "请输入单据备注",
delete_message: "删除入库单",
input_formCode: "请输入单据编号",
approve_confirm: "是否审核通过",
approve_success: "审核成功",
approve_fail: "审核失败",
reject_confirm: "是否需要反审",
reject_success: "反审成功",
reject_fail: "反审失败",
already_approved: "入库单已经审核",
not_approved: "入库单不是已审核状态,不能反审",
no_materials: "入库单没有明细",
import_success: "导入成功",
import_fail: "导入失败",
},
inventorycount: {
select_storeId: "请选择仓库",
input_formName: "请输入单据名称",
input_formMark: "请输入单据备注",
input_formCode: "请输入单据编号",
input_partNumber: "请输入物料编号",
input_productSpec: "请输入物料规格",
input_productCount: "请输入盘点数量",
input_originalProductCount: "请输入原始数量",
input_diffCount: "请输入差异数量",
input_stockTakingMark: "请输入盘点备注",
approve_confirm: "是否审核通过",
approve_success: "审核成功",
approve_fail: "审核失败",
reject_confirm: "是否需要反审",
reject_success: "反审成功",
reject_fail: "反审失败",
already_approved: "盘点单已经审核",
not_approved: "盘点单不是已审核状态,不能反审",
no_items: "盘点单没有明细",
init_already_exists: "当前仓库已经有初始库存单",
import_success: "导入成功",
import_fail: "导入失败",
delete_message: "删除盘点单",
},
},
@@ -374,23 +548,168 @@ export default {
generate_production_issue_fail: "生成出料单失败,失败信息:",
error_production_status: "只能选择未完成的计划",
},
production_issue: {
only_approved_can_return: "只有审核通过的发料单才能生成退料单",
get_detail_failed: "获取发料单明细失败",
no_return_data: "没有退料数据",
enter_valid_return_qty: "请输入有效的退料数量",
return_order_created: "退料单创建成功",
create_return_order_failed: "创建退料单失败",
generate_return_confirm: "是否生成退料单",
generate_return_mark_suffix: "】生成退料单【",
generate_return_name_suffix: " 退料",
generate_return_success: "生成退料单成功",
generate_return_fail: "生成退料单失败,失败信息:",
},
production_return: {},
finishedproductreceipt: {
select_storeId: "请选择仓库",
input_formName: "请输入单据名称",
input_formMark: "请输入单据备注",
input_formCode: "请输入单据编号",
input_productType: "请输入型号",
input_productSn: "请输入SN号",
input_mac: "请输入MAC地址",
input_serialNum: "请输入序列号",
input_softVersion: "请输入软件版本",
input_alVersion: "请输入算法版本",
input_alNum: "请输入算法标志",
input_alTxt: "请输入激活状态",
input_manufacturingDate: "请输入时间",
input_mark: "请输入备注",
approve_confirm: "是否审核通过",
approve_success: "审核成功",
approve_fail: "审核失败",
reject_confirm: "是否需要反审",
reject_success: "反审成功",
reject_fail: "反审失败",
already_approved: "成品入库单已经审核",
not_approved: "成品入库单不是已审核状态,不能反审",
no_module_sn_items: "成品入库单没有明细",
duplicate_sn_in_request: "导入数据中存在重复SN号",
invalid_activation_status: "存在未激活的SN号",
sn_already_exists: "系统中已存在的SN号",
cannot_unapprove_with_shipped: "成品入库单已出货,不能反审",
import_success: "导入成功",
import_fail: "导入失败",
delete_message: "删除成品入库单",
},
finishedproductshipment: {
select_storeId: "请选择仓库",
input_formName: "请输入单据名称",
input_formMark: "请输入单据备注",
input_formCode: "请输入单据编号",
input_productType: "请输入型号",
input_productSn: "请输入SN号",
input_mac: "请输入MAC地址",
input_serialNum: "请输入序列号",
input_softVersion: "请输入软件版本",
input_alVersion: "请输入算法版本",
input_alNum: "请输入算法标志",
input_alTxt: "请输入激活状态",
input_manufacturingDate: "请输入时间",
input_mark: "请输入备注",
approve_confirm: "是否审核通过",
approve_success: "审核成功",
approve_fail: "审核失败",
reject_confirm: "是否需要反审",
reject_success: "反审成功",
reject_fail: "反审失败",
already_approved: "成品出库单已经审核",
not_approved: "成品出库单不是已审核状态,不能反审",
no_module_sn_items: "成品出库单没有明细",
duplicate_sn_in_request: "导入数据中存在重复SN号",
sn_not_found: "系统中不存在的SN号",
sn_already_shipped: "已经出货的SN号",
import_success: "导入成功",
import_fail: "导入失败",
delete_message: "删除成品出货单",
},
devicesn: {
input_productSn: "请输入SN号",
input_mac: "请输入MAC地址",
},
repairrecord: {
input_productSn: "请输入SN号",
input_mac: "请输入MAC地址",
input_repairStatus: "请选择维修状态",
input_repairDate: "请输入维修日期",
input_manufacturingDate: "请输入生产日期",
input_mark: "请输入备注",
input_repairMark: "请输入返修记录",
},
},
purchase: {
purchaseplan: {
purchase_plan: {
delete_message: "删除采购计划",
input_planName: "请输入计划单名称",
select_vendor: "请选择供应商",
select_store: "请选择入库仓库",
input_remask: "请输入备注",
upload_planItems: "请上传采购明细",
get_items_error: "获取采购计划明细失败",
select_items: "请选择要采购的物料",
generate_order_success: "生成采购订单成功",
generate_order_error: "生成采购订单失败",
vendor_priority_tip: "优先",
},
purchaseorder: {
delete_message: "删除采购订单",
},
finishedproductshipment: {
select_storeId: "请选择仓库",
input_formName: "请输入单据名称",
input_formMark: "请输入单据备注",
input_formCode: "请输入单据编号",
input_productType: "请输入型号",
input_productSn: "请输入SN号",
input_mac: "请输入MAC地址",
input_serialNum: "请输入序列号",
input_softVersion: "请输入软件版本",
input_alVersion: "请输入算法版本",
input_alNum: "请输入算法标志",
input_alTxt: "请输入激活状态",
input_manufacturingDate: "请输入时间",
input_mark: "请输入备注",
approve_confirm: "是否审核通过",
approve_success: "审核成功",
approve_fail: "审核失败",
reject_confirm: "是否需要反审",
reject_success: "反审成功",
reject_fail: "反审失败",
already_approved: "成品出库单已经审核",
not_approved: "成品出库单不是已审核状态,不能反审",
no_module_sn_items: "成品出库单没有明细",
duplicate_sn_in_request: "导入数据中存在重复SN号",
sn_not_found: "系统中不存在的SN号",
sn_already_shipped: "已经出货的SN号",
import_success: "导入成功",
import_fail: "导入失败",
delete_message: "删除成品出货单",
},
},
sale: {
saleorder: {
select_customerId: "请选择客户",
input_formName: "请输入单据名称",
input_formMark: "请输入单据备注",
input_formCode: "请输入单据编号",
input_partNumber: "请输入物料编号",
input_saleCount: "请输入销售数量",
input_price: "请输入单价",
input_saleMark: "请输入备注",
approve_confirm: "是否审核通过",
approve_success: "审核成功",
approve_fail: "审核失败",
reject_confirm: "是否需要反审",
reject_success: "反审成功",
reject_fail: "反审失败",
already_approved: "销售订单已经审核",
not_approved: "销售订单不是已审核状态,不能反审",
no_sale_order_items: "销售订单没有明细",
cannot_unapprove_with_shipped: "销售订单已出货,不能反审",
import_success: "导入成功",
import_fail: "导入失败",
delete_message: "删除销售订单",
},
},
@@ -436,10 +755,15 @@ export default {
warehouseitem: {
add: "添加物料信息",
edit: "编辑物料信息",
vendorList: "供应商列表",
printQrCode: "打印二维码",
},
stocktransferorder: {
add: "添加调拨单",
edit: "编辑调拨单",
showItem: "调拨明细",
baseTitle: "调拨单基本信息",
tableTitle: "调拨明细",
},
warehousereceipt: {
add: "添加入库单",
@@ -448,6 +772,9 @@ export default {
inventorycount: {
add: "添加盘点单",
edit: "编辑盘点单",
showItem: "盘点明细",
baseTitle: "盘点单基本信息",
tableTitle: "盘点明细",
},
},
production: {
@@ -464,19 +791,44 @@ export default {
dialog: "缺料查看",
issueDialog: "发料编辑",
},
production_issue: {
returnDialog: "退料编辑",
},
finishedproductreceipt: {
add: "添加成品入库单",
edit: "编辑成品入库单",
showItem: "成品明细",
baseTitle: "成品入库单基本信息",
tableTitle: "成品明细",
},
finishedproductshipment: {
add: "添加成品出货单",
edit: "编辑成品出货单",
showItem: "成品明细",
baseTitle: "成品出货单基本信息",
tableTitle: "成品明细",
},
saleorder: {
add: "添加销售订单",
edit: "编辑销售订单",
showItem: "销售明细",
baseTitle: "销售订单基本信息",
tableTitle: "销售明细",
},
},
purchase: {
purchaseplan: {
purchase_plan: {
add: "新建采购计划",
edit: "编辑采购计划",
generateOrder: "生成采购订单",
model: "型号",
defaultVendor: "默认供应商",
demandQuantity: "需求量",
packQuantity: "包装数量",
purchaseQuantity: "采购数量",
unitPrice: "单价",
totalPrice: "总价",
purchaseStatus: "采购状态",
},
purchaseorder: {
add: "新建采购订单",
@@ -739,5 +1091,28 @@ export default {
reviewed: "已审核",
},
},
purchase: {
purchase_plan: {
pending: "待采购",
in_progress: "采购中",
completed: "已完成",
},
purchase_plan_item: {
no_start: "未采购",
ordered: "采购中",
completed: "已采购",
},
},
form_status: {
no_approve: "未审核",
approve: "已审核",
reject: "驳回",
no_complete: "未完成",
complete: "已完成",
receipting: "入库中",
imported: "已导入",
approving: "审批中",
returned: "已退料",
},
},
};

View File

@@ -27,5 +27,58 @@ export const useStatus = () => {
return key ? t(key) : t(unknown);
};
return { commonStatusKeyMap, getCommonStatusLabel, productionPlanStatusKeyMap, getProductionPlanStatusLabel };
const formStatusKeyMap: Record<number, string> = {
0: "_base_info.form_status.no_approve",
1: "_base_info.form_status.approve",
2: "_base_info.form_status.reject",
3: "_base_info.form_status.no_complete",
4: "_base_info.form_status.complete",
5: "_base_info.form_status.receipting",
6: "_base_info.form_status.imported",
7: "_base_info.form_status.approving",
8: "_base_info.form_status.returned",
};
const getFormStatusLabel = (code: number | null): string => {
if (code === null || code === undefined) return "";
const key = formStatusKeyMap[code];
return key ? t(key) : t(unknown);
};
const purchasePlanItemStatusKeyMap: Record<number, string> = {
0: "_base_info.purchase.purchase_plan_item.no_start",
1: "_base_info.purchase.purchase_plan_item.ordered",
2: "_base_info.purchase.purchase_plan_item.completed",
};
const getPurchasePlanItemStatusLabel = (code: number | null): string => {
if (code === null || code === undefined) return "";
const key = purchasePlanItemStatusKeyMap[code];
return key ? t(key) : t(unknown);
};
const purchasePlanStatusKeyMap: Record<number, string> = {
0: "_base_info.purchase.purchase_plan.pending",
1: "_base_info.purchase.purchase_plan.in_progress",
2: "_base_info.purchase.purchase_plan.completed",
};
const getPurchasePlanStatusLabel = (code: number | null): string => {
if (code === null || code === undefined) return "";
const key = purchasePlanStatusKeyMap[code];
return key ? t(key) : t(unknown);
};
return {
commonStatusKeyMap,
getCommonStatusLabel,
productionPlanStatusKeyMap,
getProductionPlanStatusLabel,
formStatusKeyMap,
getFormStatusLabel,
purchasePlanItemStatusKeyMap,
getPurchasePlanItemStatusLabel,
purchasePlanStatusKeyMap,
getPurchasePlanStatusLabel,
};
};

View File

@@ -69,7 +69,6 @@ defineExpose({
tableMainRef.value?.toggleRowExpansion(row, expanded);
},
sort: (field: string, order: string) => {
console.log(tableMainRef.value?.tableRef);
tableMainRef.value?.tableRef?.sort(field, order);
},
});
@@ -78,6 +77,7 @@ onMounted(loadData);
</script>
<template>
<TableHeader
v-if="searchers !== undefined"
:searchers="searchers"
:tool-buttons="toolButtons"
v-model:searcher-params="searcherParams"

View File

@@ -0,0 +1,188 @@
<script lang="ts" setup>
import QRCode from "qrcode";
const props = defineProps({
title: {
type: String,
default: "",
},
qrCodeContent: {
type: String,
default: "",
},
qrCodeSize: {
type: Number,
default: 200,
},
showLabel: {
type: Boolean,
default: true,
},
label: {
type: String,
default: "",
},
});
const visible = defineModel<boolean>("visible");
const qrCodeDataUrl = ref("");
const loading = ref(false);
const generateQrCode = async () => {
if (!props.qrCodeContent) {
return;
}
loading.value = true;
try {
qrCodeDataUrl.value = await QRCode.toDataURL(props.qrCodeContent, {
width: props.qrCodeSize,
margin: 2,
color: {
dark: "#000000",
light: "#ffffff",
},
});
} catch (error) {
console.error("Generate QR code failed:", error);
} finally {
loading.value = false;
}
};
const handlePrint = () => {
const printWindow = window.open("", "_blank");
if (!printWindow) {
return;
}
const imgHtml = `
<!DOCTYPE html>
<html>
<head>
<title>${props.title || "QR Code"}</title>
<style>
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px;
}
img {
max-width: 100%;
}
.label {
margin-top: 10px;
font-size: 16px;
font-weight: bold;
text-align: center;
}
@media print {
body {
padding: 0;
}
}
</style>
</head>
<body>
<img src="${qrCodeDataUrl.value}" alt="QR Code" />
${props.showLabel ? `<div class="label">${props.label || props.qrCodeContent}</div>` : ""}
</body>
</html>
`;
printWindow.document.write(imgHtml);
printWindow.document.close();
printWindow.focus();
setTimeout(() => {
printWindow.print();
printWindow.close();
}, 250);
};
const handleDownload = () => {
const link = document.createElement("a");
link.download = `${props.label || props.qrCodeContent || "qrcode"}.png`;
link.href = qrCodeDataUrl.value;
link.click();
};
watch(
() => props.qrCodeContent,
() => {
if (visible.value && props.qrCodeContent) {
generateQrCode();
}
}
);
watch(visible, newVal => {
if (newVal && props.qrCodeContent) {
generateQrCode();
}
});
</script>
<template>
<el-dialog
:title="title"
v-model="visible"
width="400px"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<div v-loading="loading" class="qrcode-container">
<div v-if="qrCodeDataUrl" class="qrcode-display">
<img :src="qrCodeDataUrl" alt="QR Code" />
<div v-if="showLabel" class="qrcode-label">{{ label || qrCodeContent }}</div>
</div>
<div v-else class="qrcode-placeholder">
{{ $t("_message.warehouse.warehouse_item.no_qrcode_content") }}
</div>
</div>
<template #footer>
<el-button @click="visible = false">{{ $t("_button.cancel") }}</el-button>
<el-button type="primary" @click="handleDownload" :disabled="!qrCodeDataUrl">
{{ $t("_button.download") }}
</el-button>
<el-button type="success" @click="handlePrint" :disabled="!qrCodeDataUrl">
{{ $t("_button.print") }}
</el-button>
</template>
</el-dialog>
</template>
<style scoped>
.qrcode-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 200px;
}
.qrcode-display {
display: flex;
flex-direction: column;
align-items: center;
}
.qrcode-display img {
max-width: 100%;
height: auto;
}
.qrcode-label {
margin-top: 10px;
font-size: 14px;
font-weight: bold;
text-align: center;
word-break: break-all;
}
.qrcode-placeholder {
font-size: 14px;
color: #909399;
}
</style>

View File

@@ -0,0 +1,263 @@
<script lang="ts" setup>
import { $t } from "@/common/languages";
import { ElMessage, type FormInstance, type FormRules } from "element-plus";
import { get, post } from "@/common/http/request";
import { Delete, Edit, Plus } from "@element-plus/icons-vue";
const props = defineProps({
title: {
type: String,
default: "",
},
warehouseItemId: {
type: Number,
default: null,
},
selectedVendorUrl: {
type: String,
default: "",
},
saveVendorUrl: {
type: String,
default: "",
},
});
const emit = defineEmits<{
"update:visible": [value: boolean];
saved: [];
}>();
const visible = defineModel<boolean>("visible");
const loading = ref(false);
const saving = ref(false);
const formRef = ref<FormInstance>();
const vendorList = ref<any[]>([]);
const allVendors = ref<any[]>([]);
const rules = reactive<FormRules>({
vendorId: [{ required: true, message: $t("_message.warehouse.warehouse_item.select_vendor"), trigger: "change" }],
costPrice: [{ required: true, message: $t("_message.warehouse.warehouse_item.input_costPrice"), trigger: "blur" }],
});
const loadVendorList = async () => {
if (!props.warehouseItemId) {
return;
}
loading.value = true;
try {
const response = await get(props.selectedVendorUrl, { warehouseItemId: props.warehouseItemId });
vendorList.value = response.data || [];
} catch (error) {
console.error("Load vendor list failed:", error);
} finally {
loading.value = false;
}
};
const loadAllVendors = async () => {
try {
const response = await get("/systemset/vendor/getVendorPage", { current: 1, size: 1000 });
allVendors.value = response.data.records || [];
} catch (error) {
console.error("Load all vendors failed:", error);
}
};
const addRow = () => {
vendorList.value.push({
id: null,
vendorId: null,
vendorName: "",
costPrice: null,
procureDate: null,
});
};
const editRow = (row: any) => {
row.isEditing = true;
};
const deleteRow = (index: number) => {
vendorList.value.splice(index, 1);
};
const saveRow = (row: any) => {
row.isEditing = false;
};
const cancelEdit = (row: any, originalRow: any) => {
row.vendorId = originalRow.vendorId;
row.costPrice = originalRow.costPrice;
row.procureDate = originalRow.procureDate;
row.isEditing = false;
};
const handleSave = async () => {
if (!formRef.value) {
return;
}
try {
await formRef.value.validate();
} catch (error) {
return;
}
if (vendorList.value.length === 0) {
ElMessage.warning($t("_message.warehouse.warehouse_item.select_vendor"));
return;
}
saving.value = true;
try {
const vendorListData = vendorList.value.map(item => ({
vendorId: item.vendorId,
costPrice: item.costPrice,
procureDate: item.procureDate,
}));
await post(props.saveVendorUrl, {
warehouseItemId: props.warehouseItemId,
vendorList: vendorListData,
});
ElMessage.success($t("_message.common.edit_success"));
visible.value = false;
emit("saved");
} catch (error) {
console.error("Save vendor list failed:", error);
} finally {
saving.value = false;
}
};
const getVendorName = (vendorId: number) => {
const vendor = allVendors.value.find(v => v.id === vendorId);
return vendor ? vendor.vendorName : "";
};
watch(
() => visible.value,
val => {
if (val) {
loadVendorList();
loadAllVendors();
}
}
);
</script>
<template>
<el-dialog
:title="title"
v-model="visible"
width="900px"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<el-form ref="formRef" :model="{ vendorList }" label-width="120px">
<el-table :data="vendorList" border style="width: 100%" max-height="50vh" v-loading="loading">
<el-table-column :label="$t('_prop.warehouse.warehouse_item.vendorName')" width="200">
<template #default="{ row, $index }">
<el-form-item v-if="row.isEditing" :prop="`vendorList.${$index}.vendorId`" :rules="rules.vendorId">
<el-select
v-model="row.vendorId"
:placeholder="$t('_message.warehouse.warehouse_item.select_vendor')"
filterable
style="width: 100%"
>
<el-option
v-for="vendor in allVendors"
:key="vendor.id"
:label="vendor.vendorName"
:value="vendor.id"
/>
</el-select>
</el-form-item>
<span v-else>{{ getVendorName(row.vendorId) }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.warehouse.warehouse_item.costPrice')" width="150">
<template #default="{ row, $index }">
<el-form-item v-if="row.isEditing" :prop="`vendorList.${$index}.costPrice`" :rules="rules.costPrice">
<el-input-number
v-model="row.costPrice"
:min="0"
:precision="2"
:placeholder="$t('_message.warehouse.warehouse_item.input_costPrice')"
style="width: 100%"
/>
</el-form-item>
<span v-else>{{ row.costPrice }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.warehouse.warehouse_item.procureDate')" width="200">
<template #default="{ row, $index }">
<el-form-item v-if="row.isEditing" :prop="`vendorList.${$index}.procureDate`">
<el-date-picker
v-model="row.procureDate"
type="datetime"
:placeholder="$t('_message.warehouse.warehouse_item.select_procureDate')"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
<span v-else>{{ row.procureDate }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.common.operate')" width="150" align="center">
<template #default="{ row, $index }">
<template v-if="row.isEditing">
<el-button type="primary" link size="small" @click="saveRow(row)">
{{ $t("_button.confirm") }}
</el-button>
<el-button link size="small" @click="cancelEdit(row, { ...row })">
{{ $t("_button.cancel") }}
</el-button>
</template>
<template v-else>
<el-button type="primary" link size="small" @click="editRow(row)">
<el-icon><Edit /></el-icon>
</el-button>
<el-button type="danger" link size="small" @click="deleteRow($index)">
<el-icon><Delete /></el-icon>
</el-button>
</template>
</template>
</el-table-column>
</el-table>
</el-form>
<div class="table-actions">
<el-button type="primary" @click="addRow">
<el-icon><Plus /></el-icon>
{{ $t("_button.add") }}
</el-button>
</div>
<template #footer>
<el-button @click="visible = false">{{ $t("_button.cancel") }}</el-button>
<el-button type="primary" @click="handleSave" :loading="saving">
{{ $t("_button.confirm") }}
</el-button>
</template>
</el-dialog>
</template>
<style scoped>
.table-actions {
margin-top: 10px;
text-align: right;
}
.el-form-item {
margin-bottom: 0;
}
</style>

View File

@@ -1,22 +1,34 @@
<script lang="ts" setup>
import { $t } from "@/common/languages";
const props = defineProps({
authShowFunc: Function,
});
const emit = defineEmits<{ "operate-button-click": [eventName: string, row: any] }>();
const buttonList = useRoute().meta.toolButtonAuth ?? [];
const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
if (props.authShowFunc !== undefined) {
return props.authShowFunc(row, button);
}
return true;
};
</script>
<template>
<el-table-column :label="$t('_prop.common.operate')" v-if="buttonList?.length !== 0">
<template #default="scope">
<el-button
v-for="button of buttonList"
:key="button.buttonName"
:type="button.colorType || 'primary'"
@click="emit('operate-button-click', button.eventName, scope.row)"
link
>
{{ $t("_button." + button.eventName) }}
</el-button>
<template #default="{ row }">
<template v-for="button of buttonList" :key="button.buttonName">
<el-button
v-if="authShowFunc(row, button)"
:type="button.colorType || 'primary'"
@click="emit('operate-button-click', button.eventName, row)"
link
>
{{ $t("_button." + button.eventName) }}
</el-button>
</template>
</template>
</el-table-column>
</template>

View File

@@ -1,37 +1,36 @@
<script lang="ts" setup>
import { post } from "@/common/http/request";
import StatusSwitch from "../base-switch/StatusSwitch.vue";
import { ElMessage } from "element-plus";
import { $t } from "@/common/languages";
import { useStatus } from "@/common/languages/mapping/base-info-mapping";
const props = defineProps({
url: String,
tableEl: ref,
statusLabelMapping: Function,
statusParamName: {
type: String,
default: "status",
},
switchOnValue: {
type: Number,
default: 0,
},
switchOffValue: {
type: Number,
default: 1,
},
});
const emit = defineEmits<{
change: [val: any, row: any];
}>();
const { getCommonStatusLabel } = useStatus();
const buttonList = useRoute().meta.statusButtonAuth ?? [];
const change = (val: any, row: any) => {
if (props.url !== undefined)
post(props.url, { id: row.id, status: val })
.then(res => {
if (res.code === 0) {
ElMessage.success((val === 1 ? $t("_button.enable") : $t("_button.disable")) + "成功");
} else {
ElMessage.error((val === 1 ? $t("_button.enable") : $t("_button.disable")) + "失败,信息为:" + res.msg);
}
})
.catch(err => {
ElMessage.error((val === 1 ? $t("_button.enable") : $t("_button.disable")) + "失败,信息为:" + err);
});
emit("change", val, row);
};
const getLabel = (code: number | null) => {
@@ -49,7 +48,10 @@ const getLabel = (code: number | null) => {
<StatusSwitch
v-model="scope.row[statusParamName]"
@change="val => change(val, scope.row)"
v-if="button.buttonType === 'switch'"
v-if="
(button.eventName === 'enable' && scope.row[statusParamName] === switchOffValue) ||
(button.eventName === 'disable' && scope.row[statusParamName] === switchOnValue)
"
/>
</template>
</template>

View File

@@ -186,7 +186,7 @@ const wrappedParse = (rawData: any) => {
defineExpose({
reload: () => {
baseTableRef.value?.reload;
baseTableRef.value?.reload();
},
});
</script>
@@ -236,18 +236,19 @@ defineExpose({
<style scoped>
.item-container {
min-height: 50px;
padding: 16px;
background-color: #fafafa;
border-radius: 4px;
min-height: 50px;
}
.loading-state,
.empty-state {
display: flex;
gap: 8px;
align-items: center;
justify-content: center;
color: #909399;
font-size: 14px;
gap: 8px;
color: #909399;
}
</style>

View File

@@ -38,8 +38,6 @@ export const useRouteFn = () => {
const isFrontendMode = !routeAccessMode || routeAccessMode === "frontend";
const isBackendMode = routeAccessMode === "backend";
const isMixedMode = routeAccessMode === "mixed";
console.log(routeAccessMode);
console.log(isBackendMode);
// 前端控制模式
if (isFrontendMode) routeList = authRoutes || [];
// 后端控制模式

View File

@@ -1,21 +0,0 @@
// import { useUserStore } from "@/pinia";
export const useAuth = () => {
// const buttonAuths = useUserStore().buttonAuth;
/**
*
* @param authCode 判断按钮是否有权限
* @returns
*/
// const hasAuthButton = (authCode: string): boolean => buttonAuths.has(authCode);
const hasAuthButton = (authCode: string): boolean => {
console.log(authCode);
return true;
};
return {
hasAuthButton,
};
};

View File

@@ -40,8 +40,15 @@ export const usePage = (
postForm(url, form, visible, "edit");
};
const useRemove = (url: string, id: number, i18nMessage: string) => {
ElMessageBox.confirm($t(i18nMessage), $t("_level.warning"), {
const postId = (
url: string,
id: number,
confirmMessage: string,
successMessage: string,
failMessage: string,
cancelMessage: string
) => {
ElMessageBox.confirm($t(confirmMessage), $t("_level.warning"), {
confirmButtonText: $t("_button.confirm"),
cancelButtonText: $t("_button.cancel"),
type: "warning",
@@ -52,31 +59,62 @@ export const usePage = (
if (res.code === 0) {
ElMessage({
type: "success",
message: $t("_message.common.delete_success"),
message: successMessage,
});
tableRef.value?.reload();
} else {
ElMessage({
type: "error",
message: $t("_message.common.delete_failure") + ": " + res.msg,
message: failMessage + ": " + res.msg,
});
}
})
.catch(error => {
ElMessage({
type: "error",
message: $t("_message.common.delete_failure") + ": " + error,
message: failMessage + ": " + error,
});
});
})
.catch(() => {
ElMessage({
type: "info",
message: $t("_message.common.delete_cannel"),
message: cancelMessage,
});
});
};
const useRemove = (url: string, id: number, i18nMessage?: string) => {
postId(
url,
id,
$t(i18nMessage ?? "_message.common.delete_confirm"),
$t("_message.common.delete_success"),
$t("_message.common.delete_failure"),
$t("_message.common.delete_cannel")
);
};
const useApprove = (url: string, id: number, i18nMessage?: string) => {
postId(
url,
id,
$t(i18nMessage ?? "_message.common.approve_confirm"),
$t("_message.common.approve_success"),
$t("_message.common.approve_fail"),
$t("_message.common.approve_cannel")
);
};
const useReject = (url: string, id: number, i18nMessage?: string) => {
postId(
url,
id,
$t(i18nMessage ?? "_message.common.reject_confirm"),
$t("_message.common.reject_success"),
$t("_message.common.reject_fail"),
$t("_message.common.reject_cannel")
);
};
const useGeneralPageRef = () => {
/**
* dialog 标题
@@ -117,5 +155,7 @@ export const usePage = (
useEdit,
useRemove,
useGeneralPageRef,
useApprove,
useReject,
};
};

View File

@@ -193,7 +193,6 @@ const validateManufactureCount = (index: number) => {
if (!value) {
callback($t("_message.production.bom.input_manufactureCount"));
}
console.log(form.value["bomItems"][index].itemPosition.split(",").length, value);
if (
form.value["bomItems"][index].itemPosition === undefined ||
form.value["bomItems"][index].itemPosition.split(",").length !== Number(value)

View File

@@ -2,11 +2,17 @@
import BasePageableTable from "@/components/base/base-pageable-table/BasePageableTable.vue";
import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue";
import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue";
import DefaultStatusSwitchColumn from "@/components/base/default-column/DefaultStatusSwitchColumn.vue";
import { usePage } from "@/composables/use-page";
import BaseForm from "@/components/base/base-form/BaseForm.vue";
import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue";
import { $t } from "@/common/languages";
import type { FormInstance, FormRules } from "element-plus";
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from "element-plus";
import { formatDate } from "@/common/utils/format-utils";
import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.vue";
import BaseSelect from "@/components/base/base-select/BaseSelect.vue";
import { generateDucumentNo } from "@/common/utils/document-no-generator/document-no-generator";
import { get, post } from "@/common/http/request";
import { useStatus } from "@/common/languages/mapping/base-info-mapping";
/**
* 必须要的变量
@@ -16,13 +22,48 @@ const getPageUrl = "/production/finishedproductreceipt/getFinishedProductReceipt
const addUrl = "/production/finishedproductreceipt/addFinishedProductReceipt";
const editUrl = "/production/finishedproductreceipt/updateFinishedProductReceipt";
const removeUrl = "/production/finishedproductreceipt/deleteFinishedProductReceipt";
const rules = reactive<FormRules>({});
const approveUrl = "/production/finishedproductreceipt/approveFinishedProductReceipt";
const unapproveUrl = "/production/finishedproductreceipt/unapproveFinishedProductReceipt";
const getDetailUrl = "/production/finishedproductreceipt/getFinishedProductReceiptDetail";
const importItemsUrl = "/production/finishedproductreceipt/importFinishedProductReceiptItems";
const getWarehouseSelectListUrl = "/warehouse/warehouse/getWarehouseSelectList";
const itemArrayName = "deviceItems";
const searchers = [
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.production.finishedproductreceipt.formCode") },
{ name: "formName", type: "text" as const, placeholder: $t("_prop.production.finishedproductreceipt.formName") },
];
const rules = reactive<FormRules>({
formCode: [
{ required: true, message: $t("_message.production.finishedproductreceipt.input_formCode"), trigger: "blur" },
],
formName: [
{ required: true, message: $t("_message.production.finishedproductreceipt.input_formName"), trigger: "blur" },
],
storeNo: [
{ required: true, message: $t("_message.production.finishedproductreceipt.select_storeId"), trigger: "blur" },
],
deviceItems: [
{
required: true,
validator: (rule, value, callback) => {
if (value === undefined || value.length === 0) {
callback($t("_message.production.finishedproductreceipt.no_module_sn_items"));
}
callback();
},
trigger: "change",
},
],
});
/**
* 基本不变通用变量
*/
const tableRef = ref<InstanceType<typeof BasePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
const { title, visible, formType, form } = useGeneralPageRef();
const { title, visible, formType, form, itemVisible, itemParentId } = useGeneralPageRef();
const baseFormWithTableRef = ref<InstanceType<typeof BaseFormWithTable>>();
const warehouseSelectRef = ref<InstanceType<typeof BaseSelect>>();
const { getFormStatusLabel } = useStatus();
/**
* 可以自定义的变量
*/
@@ -30,6 +71,7 @@ const { title, visible, formType, form } = useGeneralPageRef();
const add = () => {
form.value = {};
title.value = "_title.production.finishedproductreceipt.add";
form.value["formCode"] = generateDucumentNo("CPRK");
visible.value = true;
formType.value = false;
};
@@ -42,7 +84,42 @@ const edit = (row: any) => {
const remove = (row: any) => {
useRemove(removeUrl, row.id, "_message.production.finishedproductreceipt.delete_message");
};
const approve = (row: any) => {
ElMessageBox.confirm($t("_message.production.finishedproductreceipt.approve_confirm"), $t("_level.warning"), {
confirmButtonText: $t("_button.confirm"),
cancelButtonText: $t("_button.cancel"),
type: "warning",
}).then(async () => {
try {
await post(approveUrl, { id: row.id });
ElMessage.success($t("_message.production.finishedproductreceipt.approve_success"));
tableRef.value?.reload();
} catch (err: any) {
ElMessage.error($t("_message.production.finishedproductreceipt.approve_fail") + err);
}
});
};
const unapprove = (row: any) => {
ElMessageBox.confirm($t("_message.production.finishedproductreceipt.reject_confirm"), $t("_level.warning"), {
confirmButtonText: $t("_button.confirm"),
cancelButtonText: $t("_button.cancel"),
type: "warning",
}).then(async () => {
try {
await post(unapproveUrl, { id: row.id });
ElMessage.success($t("_message.production.finishedproductreceipt.reject_success"));
tableRef.value?.reload();
} catch (err: any) {
ElMessage.error($t("_message.production.finishedproductreceipt.reject_fail") + err);
}
});
};
const showItem = (row: any) => {
itemParentId.value = row.id;
itemVisible.value = true;
};
const submit = (form: any, formRef: FormInstance | undefined) => {
setName();
if (formRef !== undefined) {
formRef.validate(valid => {
if (valid) {
@@ -67,8 +144,23 @@ const operateButtonClick = (eventName: string, row: any) => {
case "remove":
remove(row);
break;
case "approve":
approve(row);
break;
case "unapprove":
unapprove(row);
break;
case "showItem":
showItem(row);
break;
}
};
const setName = () => {
form.value["storeName"] = warehouseSelectRef.value?.getLabel();
};
const handleReset = () => {
form.value["formCode"] = generateDucumentNo("CPRK");
};
</script>
<template>
<BasePageableTable :url="getPageUrl" :searchers="searchers" ref="tableRef">
@@ -76,20 +168,196 @@ const operateButtonClick = (eventName: string, row: any) => {
<DefaultToolButton @top-button-click="topButtonClick" />
</template>
<template #columns>
<el-table-column prop="id" type="hidden" width="40" />
<el-table-column :label="$t('_prop.production.finishedproductreceipt.formCode')" prop="formCode" />
<el-table-column :label="$t('_prop.production.finishedproductreceipt.formStatus')" prop="formStatus" />
<el-table-column :label="$t('_prop.production.finishedproductreceipt.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.production.finishedproductreceipt.formName')" prop="formName" />
<el-table-column :label="$t('_prop.production.finishedproductreceipt.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.production.finishedproductreceipt.formMark')" prop="formMark" />
<el-table-column :label="$t('_prop.production.finishedproductreceipt.totalValue')" prop="totalValue" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<DefaultStatusSwitchColumn status-param-name="formStatus" :status-label-mapping="getFormStatusLabel" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
</template>
</BasePageableTable>
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules">
<BaseFormWithTable
ref="baseFormWithTableRef"
v-model:visible="visible"
@submit="submit"
v-model:form="form"
:title="$t(title)"
:rules="rules"
:base-title="$t('_title.production.finishedproductreceipt.baseTitle')"
:table-title="$t('_title.production.finishedproductreceipt.tableTitle')"
:item-array-name="itemArrayName"
upload-desc="设备信息"
:import-url="importItemsUrl"
@reset="handleReset"
>
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
<el-form-item prop="storeName" v-if="false"><el-input v-model="form.storeName" /></el-form-item>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item :label="$t('_prop.production.finishedproductreceipt.formCode')" prop="formCode">
<el-input
v-model="form.formCode"
:placeholder="$t('_message.production.finishedproductreceipt.input_formCode')"
disabled
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="$t('_prop.production.finishedproductreceipt.formName')" prop="formName">
<el-input
v-model="form.formName"
:placeholder="$t('_message.production.finishedproductreceipt.input_formName')"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item :label="$t('_prop.production.finishedproductreceipt.storeNo')" prop="storeNo">
<BaseSelect v-model="form.storeNo" :url="getWarehouseSelectListUrl" ref="warehouseSelectRef" />
</el-form-item>
</el-col>
</el-row>
<el-form-item :label="$t('_prop.production.finishedproductreceipt.formMark')" prop="formMark">
<el-input
v-model="form.formMark"
:placeholder="$t('_message.production.finishedproductreceipt.input_formMark')"
type="textarea"
autosize
/>
</el-form-item>
</template>
</BaseForm>
<template #form-table-columns>
<el-table-column :label="$t('_prop.production.finishedproductreceipt.productType')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.productType`">
<el-input
v-model="row.productType"
size="small"
:placeholder="$t('_message.production.finishedproductreceipt.input_productType')"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.production.finishedproductreceipt.productSn')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.productSn`">
<el-input
v-model="row.productSn"
size="small"
:placeholder="$t('_message.production.finishedproductreceipt.input_productSn')"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.production.finishedproductreceipt.mac')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.mac`">
<el-input
v-model="row.mac"
size="small"
:placeholder="$t('_message.production.finishedproductreceipt.input_mac')"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.production.finishedproductreceipt.serialNum')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.serialNum`">
<el-input
v-model="row.serialNum"
size="small"
:placeholder="$t('_message.production.finishedproductreceipt.input_serialNum')"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.production.finishedproductreceipt.softVersion')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.softVersion`">
<el-input
v-model="row.softVersion"
size="small"
:placeholder="$t('_message.production.finishedproductreceipt.input_softVersion')"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.production.finishedproductreceipt.alVersion')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.alVersion`">
<el-input
v-model="row.alVersion"
size="small"
:placeholder="$t('_message.production.finishedproductreceipt.input_alVersion')"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.production.finishedproductreceipt.alNum')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.alNum`">
<el-input
v-model="row.alNum"
size="small"
:placeholder="$t('_message.production.finishedproductreceipt.input_alNum')"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.production.finishedproductreceipt.alTxt')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.alTxt`">
<el-input
v-model="row.alTxt"
size="small"
:placeholder="$t('_message.production.finishedproductreceipt.input_alTxt')"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.production.finishedproductreceipt.mark')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.mark`">
<el-input
v-model="row.mark"
size="small"
:placeholder="$t('_message.production.finishedproductreceipt.input_mark')"
/>
</el-form-item>
</template>
</el-table-column>
</template>
</BaseFormWithTable>
<BaseItemDialog
:title="$t('_title.production.finishedproductreceipt.showItem')"
v-model:visible="itemVisible"
:url="getDetailUrl"
parent-param-name="id"
v-model:parent-param-value="itemParentId"
>
<template #columns>
<el-table-column :label="$t('_prop.production.finishedproductreceipt.productType')" prop="productType" />
<el-table-column :label="$t('_prop.production.finishedproductreceipt.productSn')" prop="productSn" />
<el-table-column :label="$t('_prop.production.finishedproductreceipt.mac')" prop="mac" />
<el-table-column :label="$t('_prop.production.finishedproductreceipt.serialNum')" prop="serialNum" />
<el-table-column :label="$t('_prop.production.finishedproductreceipt.softVersion')" prop="softVersion" />
<el-table-column :label="$t('_prop.production.finishedproductreceipt.alVersion')" prop="alVersion" />
<el-table-column :label="$t('_prop.production.finishedproductreceipt.alNum')" prop="alNum" />
<el-table-column :label="$t('_prop.production.finishedproductreceipt.alTxt')" prop="alTxt" />
<el-table-column :label="$t('_prop.production.finishedproductreceipt.mark')" prop="mark" />
</template>
</BaseItemDialog>
</template>

View File

@@ -2,11 +2,17 @@
import BasePageableTable from "@/components/base/base-pageable-table/BasePageableTable.vue";
import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue";
import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue";
import DefaultStatusSwitchColumn from "@/components/base/default-column/DefaultStatusSwitchColumn.vue";
import { usePage } from "@/composables/use-page";
import BaseForm from "@/components/base/base-form/BaseForm.vue";
import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue";
import { $t } from "@/common/languages";
import type { FormInstance, FormRules } from "element-plus";
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from "element-plus";
import { formatDate } from "@/common/utils/format-utils";
import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.vue";
import BaseSelect from "@/components/base/base-select/BaseSelect.vue";
import { generateDucumentNo } from "@/common/utils/document-no-generator/document-no-generator";
import { get, post } from "@/common/http/request";
import { useStatus } from "@/common/languages/mapping/base-info-mapping";
/**
* 必须要的变量
@@ -16,13 +22,48 @@ const getPageUrl = "/production/finishedproductshipment/getFinishedProductShipme
const addUrl = "/production/finishedproductshipment/addFinishedProductShipment";
const editUrl = "/production/finishedproductshipment/updateFinishedProductShipment";
const removeUrl = "/production/finishedproductshipment/deleteFinishedProductShipment";
const rules = reactive<FormRules>({});
const approveUrl = "/production/finishedproductshipment/approveFinishedProductShipment";
const unapproveUrl = "/production/finishedproductshipment/unapproveFinishedProductShipment";
const getDetailUrl = "/production/finishedproductshipment/getFinishedProductShipmentDetail";
const importItemsUrl = "/production/finishedproductshipment/importFinishedProductShipmentItems";
const getWarehouseSelectListUrl = "/warehouse/warehouse/getWarehouseSelectList";
const itemArrayName = "deviceItems";
const searchers = [
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.production.finishedproductshipment.formCode") },
{ name: "formName", type: "text" as const, placeholder: $t("_prop.production.finishedproductshipment.formName") },
];
const rules = reactive<FormRules>({
formCode: [
{ required: true, message: $t("_message.production.finishedproductshipment.input_formCode"), trigger: "blur" },
],
formName: [
{ required: true, message: $t("_message.production.finishedproductshipment.input_formName"), trigger: "blur" },
],
storeNo: [
{ required: true, message: $t("_message.production.finishedproductshipment.select_storeId"), trigger: "blur" },
],
deviceItems: [
{
required: true,
validator: (rule, value, callback) => {
if (value === undefined || value.length === 0) {
callback($t("_message.production.finishedproductshipment.no_module_sn_items"));
}
callback();
},
trigger: "change",
},
],
});
/**
* 基本不变通用变量
*/
const tableRef = ref<InstanceType<typeof BasePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
const { title, visible, formType, form } = useGeneralPageRef();
const { title, visible, formType, form, itemVisible, itemParentId } = useGeneralPageRef();
const baseFormWithTableRef = ref<InstanceType<typeof BaseFormWithTable>>();
const warehouseSelectRef = ref<InstanceType<typeof BaseSelect>>();
const { getFormStatusLabel } = useStatus();
/**
* 可以自定义的变量
*/
@@ -30,6 +71,7 @@ const { title, visible, formType, form } = useGeneralPageRef();
const add = () => {
form.value = {};
title.value = "_title.production.finishedproductshipment.add";
form.value["formCode"] = generateDucumentNo("CPCK");
visible.value = true;
formType.value = false;
};
@@ -42,7 +84,42 @@ const edit = (row: any) => {
const remove = (row: any) => {
useRemove(removeUrl, row.id, "_message.production.finishedproductshipment.delete_message");
};
const approve = (row: any) => {
ElMessageBox.confirm($t("_message.production.finishedproductshipment.approve_confirm"), $t("_level.warning"), {
confirmButtonText: $t("_button.confirm"),
cancelButtonText: $t("_button.cancel"),
type: "warning",
}).then(async () => {
try {
await post(approveUrl, { id: row.id });
ElMessage.success($t("_message.production.finishedproductshipment.approve_success"));
tableRef.value?.reload();
} catch (err: any) {
ElMessage.error($t("_message.production.finishedproductshipment.approve_fail") + err);
}
});
};
const unapprove = (row: any) => {
ElMessageBox.confirm($t("_message.production.finishedproductshipment.reject_confirm"), $t("_level.warning"), {
confirmButtonText: $t("_button.confirm"),
cancelButtonText: $t("_button.cancel"),
type: "warning",
}).then(async () => {
try {
await post(unapproveUrl, { id: row.id });
ElMessage.success($t("_message.production.finishedproductshipment.reject_success"));
tableRef.value?.reload();
} catch (err: any) {
ElMessage.error($t("_message.production.finishedproductshipment.reject_fail") + err);
}
});
};
const showItem = (row: any) => {
itemParentId.value = row.id;
itemVisible.value = true;
};
const submit = (form: any, formRef: FormInstance | undefined) => {
setName();
if (formRef !== undefined) {
formRef.validate(valid => {
if (valid) {
@@ -67,8 +144,23 @@ const operateButtonClick = (eventName: string, row: any) => {
case "remove":
remove(row);
break;
case "approve":
approve(row);
break;
case "unapprove":
unapprove(row);
break;
case "showItem":
showItem(row);
break;
}
};
const setName = () => {
form.value["storeName"] = warehouseSelectRef.value?.getLabel();
};
const handleReset = () => {
form.value["formCode"] = generateDucumentNo("CPCK");
};
</script>
<template>
<BasePageableTable :url="getPageUrl" :searchers="searchers" ref="tableRef">
@@ -76,19 +168,196 @@ const operateButtonClick = (eventName: string, row: any) => {
<DefaultToolButton @top-button-click="topButtonClick" />
</template>
<template #columns>
<el-table-column prop="id" type="hidden" width="40" />
<el-table-column :label="$t('_prop.production.finishedproductshipment.formCode')" prop="formCode" />
<el-table-column :label="$t('_prop.production.finishedproductshipment.formStatus')" prop="formStatus" />
<el-table-column :label="$t('_prop.production.finishedproductshipment.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.production.finishedproductshipment.formName')" prop="formName" />
<el-table-column :label="$t('_prop.production.finishedproductshipment.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.production.finishedproductshipment.formMark')" prop="formMark" />
<el-table-column :label="$t('_prop.production.finishedproductshipment.totalValue')" prop="totalValue" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<DefaultStatusSwitchColumn status-param-name="formStatus" :status-label-mapping="getFormStatusLabel" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
</template>
</BasePageableTable>
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules">
<BaseFormWithTable
ref="baseFormWithTableRef"
v-model:visible="visible"
@submit="submit"
v-model:form="form"
:title="$t(title)"
:rules="rules"
:base-title="$t('_title.production.finishedproductshipment.baseTitle')"
:table-title="$t('_title.production.finishedproductshipment.tableTitle')"
:item-array-name="itemArrayName"
upload-desc="设备信息"
:import-url="importItemsUrl"
@reset="handleReset"
>
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
<el-form-item prop="storeName" v-if="false"><el-input v-model="form.storeName" /></el-form-item>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item :label="$t('_prop.production.finishedproductshipment.formCode')" prop="formCode">
<el-input
v-model="form.formCode"
:placeholder="$t('_message.production.finishedproductshipment.input_formCode')"
disabled
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="$t('_prop.production.finishedproductshipment.formName')" prop="formName">
<el-input
v-model="form.formName"
:placeholder="$t('_message.production.finishedproductshipment.input_formName')"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item :label="$t('_prop.production.finishedproductshipment.storeNo')" prop="storeNo">
<BaseSelect v-model="form.storeNo" :url="getWarehouseSelectListUrl" ref="warehouseSelectRef" />
</el-form-item>
</el-col>
</el-row>
<el-form-item :label="$t('_prop.production.finishedproductshipment.formMark')" prop="formMark">
<el-input
v-model="form.formMark"
:placeholder="$t('_message.production.finishedproductshipment.input_formMark')"
type="textarea"
autosize
/>
</el-form-item>
</template>
</BaseForm>
<template #form-table-columns>
<el-table-column :label="$t('_prop.production.finishedproductshipment.productType')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.productType`">
<el-input
v-model="row.productType"
size="small"
:placeholder="$t('_message.production.finishedproductshipment.input_productType')"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.production.finishedproductshipment.productSn')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.productSn`">
<el-input
v-model="row.productSn"
size="small"
:placeholder="$t('_message.production.finishedproductshipment.input_productSn')"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.production.finishedproductshipment.mac')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.mac`">
<el-input
v-model="row.mac"
size="small"
:placeholder="$t('_message.production.finishedproductshipment.input_mac')"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.production.finishedproductshipment.serialNum')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.serialNum`">
<el-input
v-model="row.serialNum"
size="small"
:placeholder="$t('_message.production.finishedproductshipment.input_serialNum')"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.production.finishedproductshipment.softVersion')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.softVersion`">
<el-input
v-model="row.softVersion"
size="small"
:placeholder="$t('_message.production.finishedproductshipment.input_softVersion')"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.production.finishedproductshipment.alVersion')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.alVersion`">
<el-input
v-model="row.alVersion"
size="small"
:placeholder="$t('_message.production.finishedproductshipment.input_alVersion')"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.production.finishedproductshipment.alNum')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.alNum`">
<el-input
v-model="row.alNum"
size="small"
:placeholder="$t('_message.production.finishedproductshipment.input_alNum')"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.production.finishedproductshipment.alTxt')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.alTxt`">
<el-input
v-model="row.alTxt"
size="small"
:placeholder="$t('_message.production.finishedproductshipment.input_alTxt')"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.production.finishedproductshipment.mark')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.mark`">
<el-input
v-model="row.mark"
size="small"
:placeholder="$t('_message.production.finishedproductshipment.input_mark')"
/>
</el-form-item>
</template>
</el-table-column>
</template>
</BaseFormWithTable>
<BaseItemDialog
:title="$t('_title.production.finishedproductshipment.showItem')"
v-model:visible="itemVisible"
:url="getDetailUrl"
parent-param-name="id"
v-model:parent-param-value="itemParentId"
>
<template #columns>
<el-table-column :label="$t('_prop.production.finishedproductshipment.productType')" prop="productType" />
<el-table-column :label="$t('_prop.production.finishedproductshipment.productSn')" prop="productSn" />
<el-table-column :label="$t('_prop.production.finishedproductshipment.mac')" prop="mac" />
<el-table-column :label="$t('_prop.production.finishedproductshipment.serialNum')" prop="serialNum" />
<el-table-column :label="$t('_prop.production.finishedproductshipment.softVersion')" prop="softVersion" />
<el-table-column :label="$t('_prop.production.finishedproductshipment.alVersion')" prop="alVersion" />
<el-table-column :label="$t('_prop.production.finishedproductshipment.alNum')" prop="alNum" />
<el-table-column :label="$t('_prop.production.finishedproductshipment.alTxt')" prop="alTxt" />
<el-table-column :label="$t('_prop.production.finishedproductshipment.mark')" prop="mark" />
</template>
</BaseItemDialog>
</template>

View File

@@ -1,93 +1,204 @@
<script lang="ts" setup>
import BasePageableTable from "@/components/base/base-pageable-table/BasePageableTable.vue";
import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue";
import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue";
import { usePage } from "@/composables/use-page";
import BaseForm from "@/components/base/base-form/BaseForm.vue";
import { $t } from "@/common/languages";
import type { FormInstance, FormRules } from "element-plus";
import BaseTableForm from "@/components/base/base-table-form/BaseTableForm.vue";
import { formatDate } from "@/common/utils/format-utils";
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
import DefaultStatusSwitchColumn from "@/components/base/default-column/DefaultStatusSwitchColumn.vue";
import { useStatus } from "@/common/languages/mapping/base-info-mapping";
import { usePage } from "@/composables/use-page";
import { get, post } from "@/common/http/request";
import { ElMessage, ElMessageBox } from "element-plus";
import { ref } from "vue";
import { generateDucumentNo } from "@/common/utils/document-no-generator/document-no-generator";
import { DocumentType } from "@/common/enums/DocumentType";
/**
* 必须要的变量
*/
const getPageUrl = "/production/productionissue/getProductionIssuePage";
const addUrl = "/production/productionissue/addProductionIssue";
const editUrl = "/production/productionissue/updateProductionIssue";
const removeUrl = "/production/productionissue/deleteProductionIssue";
const rules = reactive<FormRules>({});
const getItemUrl = "/production/productionissue/getProductionIssueItemList";
const approveUrl = "/production/productionissue/approvingProductionIssue";
const rejectUrl = "/production/productionissue/rejectProductionIssue";
const generateProductionReturnUrl = "/production/productionissue/productionReturn";
/**
* 基本不变通用变量
*/
const tableRef = ref<InstanceType<typeof BasePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
const { title, visible, formType, form } = useGeneralPageRef();
const tableRef = ref<InstanceType<typeof ExpandablePageableTable> | null>(null);
const { getFormStatusLabel } = useStatus();
const { useApprove, useReject } = usePage(tableRef);
const productionReturnRef = ref<InstanceType<typeof BaseTableForm>>();
const productionReturnVisible = ref(false);
const productionReturnTableData = ref([]);
const currentIssueId = ref();
const currentIssueRow = ref<any>({});
/**
* 可以自定义的变量
*/
const add = () => {
form.value = {};
title.value = "_title.production.productionissue.add";
visible.value = true;
formType.value = false;
const approve = (row: any) => {
useApprove(approveUrl, row.id);
};
const edit = (row: any) => {
title.value = "_title.production.productionissue.edit";
form.value = { ...row };
visible.value = true;
formType.value = true;
const reject = (row: any) => {
useReject(rejectUrl, row.id);
};
const remove = (row: any) => {
useRemove(removeUrl, row.id, "_message.production.productionissue.delete_message");
};
const submit = (form: any, formRef: FormInstance | undefined) => {
if (formRef !== undefined) {
formRef.validate(valid => {
if (valid) {
if (formType.value) useEdit(editUrl, form, visible);
else useAdd(addUrl, form, visible);
}
});
}
};
const topButtonClick = (eventName: string) => {
switch (eventName) {
case "add":
add();
break;
const productionReturn = async (row: any) => {
// 检查发料单状态,只有审核通过的才能生成退料单
if (row.formStatus !== 1) {
ElMessage.warning($t("_message.production.production_issue.only_approved_can_return"));
return;
}
currentIssueId.value = row.id;
currentIssueRow.value = row;
try {
const rowData = await get(getItemUrl, { issueId: row.id }).then(res => res.data);
productionReturnTableData.value = rowData.map((item: any) => ({
partNumber: item.partNumber,
productSpecs: item.productSpecs,
expectedReturnQty: item.actualQty - item.requiredQty > 0 ? item.actualQty - item.requiredQty : 0,
actualReturnQty: item.actualQty - item.requiredQty > 0 ? item.actualQty - item.requiredQty : 0,
}));
productionReturnVisible.value = true;
} catch (error) {
ElMessage.error($t("_message.production.production_issue.get_detail_failed"));
console.error("获取发料单明细失败:", error);
}
};
const operateButtonClick = (eventName: string, row: any) => {
switch (eventName) {
case "edit":
edit(row);
case "approve":
approve(row);
break;
case "remove":
remove(row);
case "reject":
reject(row);
break;
case "productionReturn":
productionReturn(row);
break;
}
};
const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
if (row.formStatus === 0 && button.eventName === "reject") return false;
if (row.formStatus === 1 && button.eventName === "approve") return false;
if (
row.formStatus === 8 &&
(button.eventName === "approve" || button.eventName === "reject" || button.eventName === "productionReturn")
)
return false;
return true;
};
const generateProductionReturn = async () => {
if (!productionReturnTableData.value || productionReturnTableData.value.length === 0) {
ElMessage.warning($t("_message.production.production_issue.no_return_data"));
return;
}
const hasValidReturn = productionReturnTableData.value.some((item: any) => item.actualReturnQty > 0);
if (!hasValidReturn) {
ElMessage.warning($t("_message.production.production_issue.enter_valid_return_qty"));
return;
}
ElMessageBox.confirm($t("_message.production.production_issue.generate_return_confirm"), $t("_level.warning"), {
confirmButtonText: $t("_button.confirm"),
cancelButtonText: $t("_button.cancel"),
type: "warning",
}).then(async () => {
try {
const formCode = generateDucumentNo(DocumentType.ProductionReturn);
const formMark =
$t("_message.common.generate_document_mark_prefix") +
currentIssueRow.value.formCode +
$t("_message.production.production_issue.generate_return_mark_suffix") +
formCode +
$t("_message.common.generate_document_mark_suffix");
const requestData = {
formCode,
formMark,
storeNo: currentIssueRow.value.storeNo,
storeName: currentIssueRow.value.storeName,
items: productionReturnTableData.value
.filter((item: any) => item.actualReturnQty > 0)
.map((item: any) => ({
partNumber: item.partNumber,
storeNo: currentIssueRow.value.storeNo,
productCount: item.actualReturnQty,
demandCount: item.expectedReturnQty - item.actualReturnQty,
})),
};
const res = await post(generateProductionReturnUrl + "?id=" + currentIssueId.value, requestData);
if (res.code === 0) {
ElMessage.success($t("_message.production.production_issue.generate_return_success"));
productionReturnVisible.value = false;
tableRef.value?.reload();
} else {
ElMessage.error($t("_message.production.production_issue.generate_return_fail") + res.msg);
}
} catch (error) {
ElMessage.error($t("_message.production.production_issue.generate_return_fail") + error);
console.error("生成退料单失败:", error);
}
});
};
</script>
<template>
<BasePageableTable :url="getPageUrl" ref="tableRef">
<ExpandablePageableTable
:url="getPageUrl"
ref="tableRef"
:item-url="getItemUrl"
item-id-key="id"
item-id-name="issueId"
item-field-name="issueItems"
>
<template #tool-button>
<DefaultToolButton @top-button-click="topButtonClick" />
<DefaultToolButton />
</template>
<template #columns>
<el-table-column prop="id" type="hidden" width="40" />
<el-table-column :label="$t('_prop.production.productionissue.formCode')" prop="formCode" />
<el-table-column :label="$t('_prop.production.productionissue.formStatus')" prop="formStatus" />
<el-table-column :label="$t('_prop.production.productionissue.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.production.productionissue.formMark')" prop="formMark" />
<el-table-column :label="$t('_prop.production.production_issue.formCode')" prop="formCode" />
<el-table-column :label="$t('_prop.production.production_issue.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.production.production_issue.formMark')" prop="formMark" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
<DefaultStatusSwitchColumn status-param-name="formStatus" :status-label-mapping="getFormStatusLabel" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" :auth-show-func="authShowFunc" />
</template>
</BasePageableTable>
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules">
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
<template #item-content="{ itemData }">
<el-table :data="itemData" size="small" border stripe>
<el-table-column :label="$t('_prop.warehouse.warehouse_item.partNumber')" prop="partNumber" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productSpecs')" prop="productSpecs" />
<el-table-column :label="$t('_prop.production.production_issue.requiredQty')" prop="requiredQty" />
<el-table-column :label="$t('_prop.production.production_issue.actualQty')" prop="actualQty" />
</el-table>
</template>
</BaseForm>
</ExpandablePageableTable>
<BaseTableForm
ref="productionReturnRef"
v-model:visible="productionReturnVisible"
:title="$t('_title.production.production_issue.returnDialog')"
:tableData="productionReturnTableData"
:selectable="false"
:useAuth="false"
>
<template #table-columns>
<el-table-column :label="$t('_prop.production.bom_item.partNumber')" prop="partNumber" />
<el-table-column :label="$t('_prop.production.bom_item.productSpecs')" prop="productSpecs" />
<el-table-column :label="$t('_prop.production.production_issue.expectedReturnQty')" prop="expectedReturnQty" />
<el-table-column :label="$t('_prop.production.production_issue.actualReturnQty')" prop="actualReturnQty">
<template #default="{ row }">
<el-input-number v-model="row.actualReturnQty" :min="0" :max="row.expectedReturnQty" />
</template>
</el-table-column>
</template>
<template #attachment>
<el-button type="primary" @click="generateProductionReturn">
{{ $t("_button.submit") }}
</el-button>
</template>
</BaseTableForm>
</template>

View File

@@ -294,7 +294,7 @@ const _generateProductionIssue = async () => {
name: formName,
} = buildDocumentInfo(
rows,
DocumentType.StockTransferOrder,
DocumentType.ProductionIssue,
"_message.production.production_plan.generate_production_issue_mark_suffix",
"_message.production.production_plan.generate_production_issue_name_suffix"
);

View File

@@ -1,93 +1,80 @@
<script lang="ts" setup>
import BasePageableTable from "@/components/base/base-pageable-table/BasePageableTable.vue";
import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue";
import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue";
import { usePage } from "@/composables/use-page";
import BaseForm from "@/components/base/base-form/BaseForm.vue";
import { $t } from "@/common/languages";
import type { FormInstance, FormRules } from "element-plus";
import { formatDate } from "@/common/utils/format-utils";
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
import DefaultStatusSwitchColumn from "@/components/base/default-column/DefaultStatusSwitchColumn.vue";
import { useStatus } from "@/common/languages/mapping/base-info-mapping";
import { usePage } from "@/composables/use-page";
import { ref } from "vue";
/**
* 必须要的变量
*/
const getPageUrl = "/production/productionreturn/getProductionReturnPage";
const addUrl = "/production/productionreturn/addProductionReturn";
const editUrl = "/production/productionreturn/updateProductionReturn";
const removeUrl = "/production/productionreturn/deleteProductionReturn";
const rules = reactive<FormRules>({});
const getItemUrl = "/production/productionreturn/getProductionReturnItemList";
const approveUrl = "/production/productionreturn/approvingProductionReturn";
const rejectUrl = "/production/productionreturn/rejectProductionReturn";
/**
* 基本不变通用变量
*/
const tableRef = ref<InstanceType<typeof BasePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
const { title, visible, formType, form } = useGeneralPageRef();
const tableRef = ref<InstanceType<typeof ExpandablePageableTable> | null>(null);
const { getFormStatusLabel } = useStatus();
const { useApprove, useReject } = usePage(tableRef);
/**
* 可以自定义的变量
*/
const add = () => {
form.value = {};
title.value = "_title.production.productionreturn.add";
visible.value = true;
formType.value = false;
const approve = (row: any) => {
useApprove(approveUrl, row.id);
};
const edit = (row: any) => {
title.value = "_title.production.productionreturn.edit";
form.value = { ...row };
visible.value = true;
formType.value = true;
};
const remove = (row: any) => {
useRemove(removeUrl, row.id, "_message.production.productionreturn.delete_message");
};
const submit = (form: any, formRef: FormInstance | undefined) => {
if (formRef !== undefined) {
formRef.validate(valid => {
if (valid) {
if (formType.value) useEdit(editUrl, form, visible);
else useAdd(addUrl, form, visible);
}
});
}
};
const topButtonClick = (eventName: string) => {
switch (eventName) {
case "add":
add();
break;
}
const reject = (row: any) => {
useReject(rejectUrl, row.id);
};
const operateButtonClick = (eventName: string, row: any) => {
switch (eventName) {
case "edit":
edit(row);
case "approve":
approve(row);
break;
case "remove":
remove(row);
case "reject":
reject(row);
break;
}
};
const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
if (row.formStatus === 0 && button.eventName === "reject") return false;
if (row.formStatus === 1 && button.eventName === "approve") return false;
return true;
};
</script>
<template>
<BasePageableTable :url="getPageUrl" :searchers="searchers" ref="tableRef">
<ExpandablePageableTable
:url="getPageUrl"
ref="tableRef"
:item-url="getItemUrl"
item-id-key="id"
item-id-name="returnId"
item-field-name="returnItems"
>
<template #tool-button>
<DefaultToolButton @top-button-click="topButtonClick" />
<DefaultToolButton />
</template>
<template #columns>
<el-table-column prop="id" type="hidden" width="40" />
<el-table-column :label="$t('_prop.production.productionreturn.formCode')" prop="formCode" />
<el-table-column :label="$t('_prop.production.productionreturn.formStatus')" prop="formStatus" />
<el-table-column :label="$t('_prop.production.productionreturn.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.production.productionreturn.formMark')" prop="formMark" />
<el-table-column :label="$t('_prop.production.production_return.formCode')" prop="formCode" />
<el-table-column :label="$t('_prop.production.production_return.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.production.production_return.formMark')" prop="formMark" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
<DefaultStatusSwitchColumn status-param-name="formStatus" :status-label-mapping="getFormStatusLabel" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" :auth-show-func="authShowFunc" />
</template>
</BasePageableTable>
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules">
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
<template #item-content="{ itemData }">
<el-table :data="itemData" size="small" border stripe>
<el-table-column :label="$t('_prop.warehouse.warehouse_item.partNumber')" prop="partNumber" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productSpecs')" prop="productSpecs" />
<el-table-column :label="$t('_prop.production.production_return.returnQty')" prop="returnQty" />
</el-table>
</template>
</BaseForm>
</ExpandablePageableTable>
</template>

View File

@@ -2,11 +2,20 @@
import BasePageableTable from "@/components/base/base-pageable-table/BasePageableTable.vue";
import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue";
import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue";
import DefaultStatusSwitchColumn from "@/components/base/default-column/DefaultStatusSwitchColumn.vue";
import { usePage } from "@/composables/use-page";
import BaseForm from "@/components/base/base-form/BaseForm.vue";
import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue";
import BaseSelect from "@/components/base/base-select/BaseSelect.vue";
import BaseTableForm from "@/components/base/base-table-form/BaseTableForm.vue";
import { $t } from "@/common/languages";
import type { FormInstance, FormRules } from "element-plus";
import { formatDate } from "@/common/utils/format-utils";
import { get, post } from "@/common/http/request";
import { ElMessage } from "element-plus";
import type { FieldMappingConfig } from "@/components/base/base-form-with-table/type";
import { ref } from "vue";
import { useStatus } from "@/common/languages/mapping/base-info-mapping";
import Decimal from "decimal.js";
/**
* 必须要的变量
@@ -16,34 +25,65 @@ const getPageUrl = "/purchase/purchaseplan/getPurchasePlanPage";
const addUrl = "/purchase/purchaseplan/addPurchasePlan";
const editUrl = "/purchase/purchaseplan/updatePurchasePlan";
const removeUrl = "/purchase/purchaseplan/deletePurchasePlan";
const getItemsUrl = "/purchase/purchaseplan/getPurchasePlanItemsWithVendorSuggestions";
const generateOrderUrl = "/purchase/purchaseplan/generatePurchaseOrder";
const searchers = [
{ name: "vendorName", type: "text" as const, placeholder: $t("_prop.purchase.purchaseplan.vendorName") },
{ name: "vendorName", type: "text" as const, placeholder: $t("_prop.purchase.purchase_plan.vendorName") },
];
const rules = reactive<FormRules>({});
const { getPurchasePlanStatusLabel, getPurchasePlanItemStatusLabel } = useStatus();
const rules = reactive<FormRules>({
planName: [{ required: true, message: $t("_message.purchase.purchase_plan.input_planName"), trigger: "blur" }],
vendorId: [{ required: true, message: $t("_message.purchase.purchase_plan.select_vendor"), trigger: "blur" }],
storeNo: [{ required: true, message: $t("_message.purchase.purchase_plan.select_store"), trigger: "blur" }],
planItems: [
{
required: true,
validator: (rule, value, callback) => {
if (value === undefined || value.length === 0) {
callback($t("_message.purchase.purchase_plan.upload_planItems"));
}
callback();
},
trigger: "change",
},
],
});
const itemArrayName = "planItems";
/**
* 基本不变通用变量
*/
const tableRef = ref<InstanceType<typeof BasePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
const { title, visible, formType, form } = useGeneralPageRef();
/**
* 可以自定义的变量
*/
const baseFormWithTableRef = ref<InstanceType<typeof BaseFormWithTable>>();
const generateOrderVisible = ref(false);
const generateOrderForm = reactive({
planId: 0,
planStatus: 0,
});
const planItems = ref([] as any[]);
const allVendors = ref([] as any[]);
const partVendorMappings = ref([] as any[]);
const NOT_PURCHASE_VENDOR_ID = -1;
const add = () => {
form.value = {};
title.value = "_title.purchase.purchaseplan.add";
form.value = {
planItems: [],
};
title.value = "_title.purchase.purchase_plan.add";
visible.value = true;
formType.value = false;
};
const edit = (row: any) => {
title.value = "_title.purchase.purchaseplan.edit";
title.value = "_title.purchase.purchase_plan.edit";
form.value = { ...row };
visible.value = true;
formType.value = true;
};
const remove = (row: any) => {
useRemove(removeUrl, row.id, "_message.purchase.purchaseplan.delete_message");
useRemove(removeUrl, row.id, "_message.purchase.purchase_plan.delete_message");
};
const submit = (form: any, formRef: FormInstance | undefined) => {
if (formRef !== undefined) {
@@ -62,6 +102,14 @@ const topButtonClick = (eventName: string) => {
break;
}
};
const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
if (row.planStatus === 2 && button.eventName === "generatePurchaseOrder") {
return false;
}
return true;
};
const operateButtonClick = (eventName: string, row: any) => {
switch (eventName) {
case "edit":
@@ -70,8 +118,240 @@ const operateButtonClick = (eventName: string, row: any) => {
case "remove":
remove(row);
break;
case "generatePurchaseOrder":
showGenerateOrderDialog(row);
break;
}
};
const buildVendorSuggestions = (item: any) => {
const suggestions: any[] = [];
const addedVendorIds = new Set<number>();
const vendorCode1 = item.vendorCode1;
const vendorCode2 = item.vendorCode2;
const vendorCode3 = item.vendorCode3;
const vendorCodes = [vendorCode1, vendorCode2, vendorCode3];
for (let i = 0; i < vendorCodes.length; i++) {
if (vendorCodes[i] != null && !addedVendorIds.has(vendorCodes[i])) {
const vendor = allVendors.value.find((v: any) => v.vendorId === vendorCodes[i]);
if (vendor) {
const mapping = partVendorMappings.value.find(
(m: any) => m.partNumber === item.partNumber && m.vendorId === vendor.vendorId
);
suggestions.push({
vendorId: vendor.vendorId,
vendorName: vendor.vendorName,
priority: i + 1,
price: mapping?.costPrice || 0,
});
addedVendorIds.add(vendor.vendorId);
}
}
}
const itemMappings = partVendorMappings.value.filter((m: any) => m.partNumber === item.partNumber);
for (const mapping of itemMappings) {
if (!addedVendorIds.has(mapping.vendorId)) {
const vendor = allVendors.value.find((v: any) => v.vendorId === mapping.vendorId);
if (vendor) {
suggestions.push({
vendorId: vendor.vendorId,
vendorName: vendor.vendorName,
priority: 2,
price: mapping.costPrice || 0,
});
addedVendorIds.add(vendor.vendorId);
}
}
}
for (const vendor of allVendors.value) {
if (!addedVendorIds.has(vendor.vendorId)) {
suggestions.push({
vendorId: vendor.vendorId,
vendorName: vendor.vendorName,
priority: 3,
price: 0,
});
addedVendorIds.add(vendor.vendorId);
}
}
suggestions.push({
vendorId: NOT_PURCHASE_VENDOR_ID,
vendorName: "暂不采购",
priority: 99,
price: 0,
});
return suggestions;
};
const showGenerateOrderDialog = async (row: any) => {
generateOrderForm.planId = row.id;
generateOrderForm.planStatus = row.planStatus;
try {
const response = await get(getItemsUrl, { planId: row.id });
const data = response.data;
allVendors.value = data.allVendors || [];
partVendorMappings.value = data.partVendorMappings || [];
planItems.value = (data.items || []).map((item: any) => {
const currentCount = item.currentCount || item.purchaseCount || 1;
const price = item.price || 0;
return {
...item,
currentCount,
price,
total: new Decimal(currentCount).mul(price).toNumber(),
vendorSuggestions: [],
calculateTotal: function () {
this.total = new Decimal(this.currentCount).mul(this.price).toNumber();
},
};
});
for (const item of planItems.value) {
item.vendorSuggestions = buildVendorSuggestions(item);
if (item.completeStatus === 0 && item.vendorSuggestions.length > 0) {
const firstSuggestion = item.vendorSuggestions[0];
if (firstSuggestion.vendorId !== NOT_PURCHASE_VENDOR_ID) {
item.vendorId = firstSuggestion.vendorId;
item.price = firstSuggestion.price || 0;
item.calculateTotal();
}
} else if (item.completeStatus !== 0 && item.vendorId) {
const vendor = allVendors.value.find((v: any) => v.vendorId === item.vendorId);
if (vendor) {
item.vendorName = vendor.vendorName;
}
}
}
planItems.value.sort((a, b) => a.completeStatus - b.completeStatus);
generateOrderVisible.value = true;
} catch (error) {
ElMessage.error($t("_message.purchase.purchase_plan.get_items_error") + error);
}
};
const onVendorChange = (item: any, vendorId: number) => {
if (item.vendorSuggestions && item.vendorSuggestions.length > 0) {
const selectedVendor = item.vendorSuggestions.find((v: any) => v.vendorId === vendorId);
if (selectedVendor) {
if (selectedVendor.vendorId !== NOT_PURCHASE_VENDOR_ID) {
item.price = selectedVendor.price || 0;
}
item.calculateTotal();
}
}
};
const generatePurchaseOrder = async () => {
const validItems = planItems.value.filter(
item => item.vendorId && item.vendorId !== NOT_PURCHASE_VENDOR_ID && item.completeStatus === 0
);
if (validItems.length === 0) {
ElMessage.warning($t("_message.purchase.purchase_plan.select_vendor"));
return;
}
try {
const vendorGroups = new Map<number, any[]>();
validItems.forEach(item => {
if (!vendorGroups.has(item.vendorId)) {
vendorGroups.set(item.vendorId, []);
}
vendorGroups.get(item.vendorId)!.push(item);
});
const now = new Date();
const baseFormCode =
"PO" +
now.getFullYear() +
String(now.getMonth() + 1).padStart(2, "0") +
String(now.getDate()).padStart(2, "0") +
String(now.getHours()).padStart(2, "0") +
String(now.getMinutes()).padStart(2, "0") +
String(now.getSeconds()).padStart(2, "0");
const promises: Promise<any>[] = [];
let orderIndex = 1;
vendorGroups.forEach((items, vendorId) => {
const vendor = allVendors.value.find((v: any) => v.vendorId === vendorId);
const vendorName = vendor ? vendor.vendorName : "";
const formCode = baseFormCode + String(orderIndex).padStart(2, "0");
const formName = `采购订单-${vendorName}-${formCode}`;
const formMark = `采购计划【${generateOrderForm.planNo}】生成`;
const totalValue = items.reduce((sum, item) => {
return new Decimal(sum).add(new Decimal(item.currentCount).mul(item.price)).toNumber();
}, 0);
const data = {
planId: generateOrderForm.planId,
vendorId: vendorId,
vendorName: vendorName,
formCode: formCode,
formName: formName,
formMark: formMark,
totalValue: totalValue,
selectedItems: items,
};
promises.push(post(generateOrderUrl, data));
orderIndex++;
});
await Promise.all(promises);
ElMessage.success($t("_message.purchase.purchase_plan.generate_order_success"));
generateOrderVisible.value = false;
tableRef.value?.reload();
} catch (err: any) {
ElMessage.error(err.response?.data?.message || $t("_message.purchase.purchase_plan.generate_order_error"));
}
};
const mappingConfig: FieldMappingConfig = {
partNumber: {
sourceKey: "商品编号",
defaultValue: "",
},
purchaseCount: {
sourceKey: "计划数量",
defaultValue: 0,
transform: (val: any) => {
const num = Number(val);
return isNaN(num) ? 0 : num;
},
},
price: {
sourceKey: "单价",
defaultValue: 0,
transform: (val: any) => {
const num = Number(val);
return isNaN(num) ? 0 : num;
},
},
currentCount: {
sourceKey: "本次采购数量",
defaultValue: 0,
transform: (val: any) => {
const num = Number(val);
return isNaN(num) ? 0 : num;
},
},
};
</script>
<template>
<BasePageableTable :url="getPageUrl" :searchers="searchers" ref="tableRef">
@@ -79,19 +359,223 @@ const operateButtonClick = (eventName: string, row: any) => {
<DefaultToolButton @top-button-click="topButtonClick" />
</template>
<template #columns>
<el-table-column prop="id" type="hidden" width="40" />
<el-table-column :label="$t('_prop.purchase.purchaseplan.planNo')" prop="planNo" />
<el-table-column :label="$t('_prop.purchase.purchaseplan.planName')" prop="planName" />
<el-table-column :label="$t('_prop.purchase.purchaseplan.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.purchase.purchaseplan.planStatus')" prop="planStatus" />
<el-table-column :label="$t('_prop.purchase.purchaseplan.remask')" prop="remask" />
<el-table-column :label="$t('_prop.purchase.purchase_plan.planNo')" prop="planNo" />
<el-table-column :label="$t('_prop.purchase.purchase_plan.planName')" prop="planName" />
<el-table-column :label="$t('_prop.purchase.purchase_plan.storeName')" prop="storeName" />
<DefaultStatusSwitchColumn status-param-name="planStatus" :status-label-mapping="getPurchasePlanStatusLabel" />
<el-table-column :label="$t('_prop.purchase.purchase_plan.remask')" prop="remask" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" :auth-show-func="authShowFunc" />
</template>
</BasePageableTable>
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules">
<BaseFormWithTable
ref="baseFormWithTableRef"
v-model:visible="visible"
@submit="submit"
v-model:form="form"
:title="$t(title)"
:rules="rules"
:base-title="$t('_title.purchase.purchase_plan.baseTitle')"
:table-title="$t('_title.purchase.purchase_plan.tableTitle')"
item-array-name="planItems"
upload-desc="采购明细"
:mapping-config="mappingConfig"
>
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item :label="$t('_prop.purchase.purchase_plan.planName')" prop="planName">
<el-input v-model="form.planName" :placeholder="$t('_message.purchase.purchase_plan.input_planName')" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('_prop.purchase.purchase_plan.vendorName')" prop="vendorId">
<BaseSelect
v-model="form.vendorId"
:url="'/sys/vendor/getVendorList'"
name="id"
label="vendorName"
:placeholder="$t('_message.purchase.purchase_plan.select_vendor')"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('_prop.purchase.purchase_plan.storeName')" prop="storeNo">
<BaseSelect
v-model="form.storeNo"
:url="'/warehouse/store/getStoreList'"
name="storeNo"
label="storeName"
:placeholder="$t('_message.purchase.purchase_plan.select_store')"
/>
</el-form-item>
</el-col>
</el-row>
<el-form-item :label="$t('_prop.purchase.purchase_plan.remask')" prop="remask">
<el-input
v-model="form.remask"
:placeholder="$t('_message.purchase.purchase_plan.input_remask')"
type="textarea"
autosize
/>
</el-form-item>
</template>
</BaseForm>
<template #form-table-columns>
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.partNumber')" width="150">
<template #default="{ row, $index }">
<el-form-item
:prop="`${itemArrayName}.${$index}.partNumber`"
:rules="[
{ required: true, message: $t('_message.purchase.purchase_plan_item.input_partNumber'), trigger: 'blur' },
]"
>
<el-input v-model="row.partNumber" size="small" />
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.purchaseCount')" width="150">
<template #default="{ row, $index }">
<el-form-item
:prop="`${itemArrayName}.${$index}.purchaseCount`"
:rules="[
{
required: true,
message: $t('_message.purchase.purchase_plan_item.input_purchaseCount'),
trigger: 'blur',
},
]"
>
<el-input-number v-model="row.purchaseCount" size="small" :min="1" />
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.price')" width="150">
<template #default="{ row, $index }">
<el-form-item
:prop="`${itemArrayName}.${$index}.price`"
:rules="[
{ required: true, message: $t('_message.purchase.purchase_plan_item.input_price'), trigger: 'blur' },
]"
>
<el-input-number v-model="row.price" size="small" :min="0" :step="0.01" />
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.currentCount')" width="150">
<template #default="{ row, $index }">
<el-form-item
:prop="`${itemArrayName}.${$index}.currentCount`"
:rules="[
{
required: true,
message: $t('_message.purchase.purchase_plan_item.input_currentCount'),
trigger: 'blur',
},
]"
>
<el-input-number v-model="row.currentCount" size="small" :min="1" />
</el-form-item>
</template>
</el-table-column>
</template>
</BaseFormWithTable>
<!-- 生成采购订单对话框 -->
<BaseTableForm
v-model:visible="generateOrderVisible"
:title="$t('_title.purchase.purchase_plan.generateOrder')"
:table-data="planItems"
:show-summary="false"
:selectable="false"
:use-auth="false"
>
<!-- 自定义表格列 -->
<template #table-columns>
<el-table-column :label="$t('_prop.purchase.purchase_plan_item.partNumber')" prop="partNumber" width="150" />
<el-table-column :label="$t('_prop.purchase.purchase_plan.model')" prop="productSpecs" width="150" />
<el-table-column :label="$t('_prop.purchase.purchase_plan.vendorName')" width="180">
<template #default="{ row }">
<template v-if="row.completeStatus === 0">
<el-select
v-model="row.vendorId"
:placeholder="$t('_message.purchase.purchase_plan.select_vendor')"
style="width: 100%"
@change="onVendorChange(row, row.vendorId)"
:disabled="row.completeStatus !== 0"
>
<el-option
v-for="vendor in row.vendorSuggestions"
:key="vendor.vendorId"
:label="vendor.vendorName"
:value="vendor.vendorId"
>
<span>{{ vendor.vendorName }}</span>
<span v-if="vendor.priority === 1" style="margin-left: 8px; color: #67c23a">(优先)</span>
<span v-if="vendor.priority === 99" style="margin-left: 8px; color: #909399">(跳过)</span>
<span
v-if="vendor.price && vendor.price > 0 && vendor.priority !== 99"
style="margin-left: 8px; color: #909399"
>
¥{{ vendor.price }}
</span>
</el-option>
</el-select>
</template>
<template v-else>
<span>{{ row.vendorName }}</span>
</template>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.purchase.purchase_plan.demandQuantity')" prop="purchaseCount" width="120" />
<el-table-column :label="$t('_prop.purchase.purchase_plan.packQuantity')" prop="productPacking" width="120" />
<el-table-column :label="$t('_prop.purchase.purchase_plan.purchaseQuantity')" width="150">
<template #default="{ row }">
<el-input-number
v-model="row.currentCount"
:min="1"
@change="row.calculateTotal()"
style="width: 100%"
:disabled="row.completeStatus !== 0"
/>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.purchase.purchase_plan.unitPrice')" width="130">
<template #default="{ row }">
<el-input-number
v-model="row.price"
:min="0"
:step="0.01"
@change="row.calculateTotal()"
style="width: 100%"
:disabled="row.completeStatus !== 0"
/>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.purchase.purchase_plan.totalPrice')" prop="total" width="120" />
<el-table-column :label="$t('_prop.purchase.purchase_plan.purchaseStatus')" width="120">
<template #default="{ row }">
<span>{{ getPurchasePlanItemStatusLabel(row.completeStatus) }}</span>
</template>
</el-table-column>
</template>
<!-- 底部附加内容自定义按钮 -->
<template #attachment>
<el-button
type="primary"
:disabled="
!planItems.some(
item => item.vendorId && item.vendorId !== NOT_PURCHASE_VENDOR_ID && item.completeStatus === 0
)
"
@click="generatePurchaseOrder"
>
{{ $t("_button.confirm") }}
</el-button>
</template>
</BaseTableForm>
</template>

View File

@@ -1,96 +1,42 @@
<script lang="ts" setup>
import BasePageableTable from "@/components/base/base-pageable-table/BasePageableTable.vue";
import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue";
import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue";
import { usePage } from "@/composables/use-page";
import BaseForm from "@/components/base/base-form/BaseForm.vue";
import TreeSidePageableTable from "@/components/base/treeside-pageable-table/TreeSidePageableTable.vue";
import { $t } from "@/common/languages";
import type { FormInstance, FormRules } from "element-plus";
/**
* 必须要的变量
*/
const getPageUrl = "/sale/devicesn/getdevicesnPage";
const addUrl = "/sale/devicesn/adddevicesn";
const editUrl = "/sale/devicesn/updatedevicesn";
const removeUrl = "/sale/devicesn/deletedevicesn";
const searchers = [{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.sale.devicesn.searchCode") }];
const rules = reactive<FormRules>({});
/**
* 基本不变通用变量
*/
const tableRef = ref<InstanceType<typeof BasePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
const { title, visible, formType, form } = useGeneralPageRef();
/**
* 可以自定义的变量
*/
const add = () => {
form.value = {};
title.value = "_title.sale.devicesn.add";
visible.value = true;
formType.value = false;
};
const edit = (row: any) => {
title.value = "_title.sale.devicesn.edit";
form.value = { ...row };
visible.value = true;
formType.value = true;
};
const remove = (row: any) => {
useRemove(removeUrl, row.id, "_message.sale.devicesn.delete_message");
};
const submit = (form: any, formRef: FormInstance | undefined) => {
if (formRef !== undefined) {
formRef.validate(valid => {
if (valid) {
if (formType.value) useEdit(editUrl, form, visible);
else useAdd(addUrl, form, visible);
}
});
}
};
const topButtonClick = (eventName: string) => {
switch (eventName) {
case "add":
add();
break;
}
};
const operateButtonClick = (eventName: string, row: any) => {
switch (eventName) {
case "edit":
edit(row);
break;
case "remove":
remove(row);
break;
}
};
const getPageUrl = "/sale/device/getDevicePage";
const treeSideUrl = "/sale/device/getKeyAccount";
const searchers = [
{
name: "searchCode",
type: "text" as const,
placeholder: $t("_prop.sale.device.searchCode"),
},
];
</script>
<template>
<BasePageableTable :url="getPageUrl" :searchers="searchers" ref="tableRef">
<template #tool-button>
<DefaultToolButton @top-button-click="topButtonClick" />
</template>
<TreeSidePageableTable
:url="getPageUrl"
:searchers="searchers"
ref="tableRef"
:tree-side-url="treeSideUrl"
tree-side-node-name="keyAccountId"
tree-side-param-name="keyAccountId"
tree-side-title="所有客户"
>
<template #columns>
<el-table-column prop="id" type="hidden" width="40" />
<el-table-column :label="$t('_prop.sale.devicesn.productType')" prop="productType" />
<el-table-column :label="$t('_prop.sale.devicesn.productSn')" prop="productSn" />
<el-table-column :label="$t('_prop.sale.devicesn.mac')" prop="mac" />
<el-table-column :label="$t('_prop.sale.devicesn.serialNum')" prop="serialNum" />
<el-table-column :label="$t('_prop.sale.devicesn.softVersion')" prop="softVersion" />
<el-table-column :label="$t('_prop.sale.devicesn.AlVersion')" prop="AlVersion" />
<el-table-column :label="$t('_prop.sale.devicesn.outProductDate')" prop="outProductDate" />
<el-table-column :label="$t('_prop.sale.devicesn.repairMark')" prop="repairMark" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
<el-table-column :label="$t('_prop.sale.device.productType')" prop="productType" />
<el-table-column :label="$t('_prop.sale.device.productSn')" prop="productSn" />
<el-table-column :label="$t('_prop.sale.device.mac')" prop="mac" />
<el-table-column :label="$t('_prop.sale.device.serialNum')" prop="serialNum" />
<el-table-column :label="$t('_prop.sale.device.softVersion')" prop="softVersion" />
<el-table-column :label="$t('_prop.sale.device.alVersion')" prop="alVersion" />
<el-table-column :label="$t('_prop.sale.device.alNum')" prop="alNum" />
<el-table-column :label="$t('_prop.sale.device.outStatus')" prop="outStatus" />
<el-table-column :label="$t('_prop.sale.device.outProductDate')" prop="outProductDate" />
<el-table-column :label="$t('_prop.sale.device.repairMark')" prop="repairMark" />
</template>
</BasePageableTable>
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules">
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
</template>
</BaseForm>
</TreeSidePageableTable>
</template>

View File

@@ -1,97 +1,105 @@
<script lang="ts" setup>
import BasePageableTable from "@/components/base/base-pageable-table/BasePageableTable.vue";
import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue";
import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue";
import { usePage } from "@/composables/use-page";
import BaseForm from "@/components/base/base-form/BaseForm.vue";
import { $t } from "@/common/languages";
import type { FormInstance, FormRules } from "element-plus";
import TreeSidePageableTable from "@/components/base/tree-side-pageable-table/TreeSidePageableTable.vue";
import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue";
import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue";
import { usePage } from "@/composables/use-page";
import BaseForm from "@/components/base/base-form/BaseForm.vue";
import { $t } from "@/common/languages";
import type { FormInstance, FormRules } from "element-plus";
/**
* 必须要的变量
*/
/**
* 必须要的变量
*/
const getPageUrl = "/sale/repairrecord/getRepairRecordPage";
const addUrl = "/sale/repairrecord/addRepairRecord";
const editUrl = "/sale/repairrecord/updateRepairRecord";
const removeUrl = "/sale/repairrecord/deleteRepairRecord";
const searchers = [
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.sale.repairrecord.searchCode") },
];
const rules = reactive<FormRules>({
const getPageUrl = "/sale/repairrecord/getRepairRecordPage";
const addUrl = "/sale/repairrecord/addRepairRecord";
const editUrl = "/sale/repairrecord/updateRepairRecord";
const removeUrl = "/sale/repairrecord/deleteRepairRecord";
const treeSideUrl = "/sale/repairrecord/getKeyAccount";
const searchers = [
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.sale.repairrecord.searchCode") },
];
const rules = reactive<FormRules>({});
/**
* 基本不变通用变量
*/
const tableRef = ref<InstanceType<typeof TreeSidePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
const { title, visible, formType, form } = useGeneralPageRef();
/**
* 可以自定义的变量
*/
const add = () => {
form.value = {};
title.value = "_title.sale.repairrecord.add";
visible.value = true;
formType.value = false;
};
const edit = (row: any) => {
title.value = "_title.sale.repairrecord.edit";
form.value = { ...row };
visible.value = true;
formType.value = true;
};
const remove = (row: any) => {
useRemove(removeUrl, row.id, "_message.sale.repairrecord.delete_message");
};
const submit = (form: any, formRef: FormInstance | undefined) => {
if (formRef !== undefined) {
formRef.validate(valid => {
if (valid) {
if (formType.value) useEdit(editUrl, form, visible);
else useAdd(addUrl, form, visible);
}
});
/**
* 基本不变通用变量
*/
const tableRef = ref<InstanceType<typeof BasePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
const { title, visible, formType, form } = useGeneralPageRef();
/**
* 可以自定义的变量
*/
const add = () => {
form.value = {};
title.value = "_title.sale.repairrecord.add";
visible.value = true;
formType.value = false;
};
const edit = (row: any) => {
title.value = "_title.sale.repairrecord.edit";
form.value = { ...row };
visible.value = true;
formType.value = true;
};
const remove = (row: any) => {
useRemove(removeUrl, row.id, "_message.sale.repairrecord.delete_message");
};
const submit = (form: any, formRef: FormInstance | undefined) => {
if (formRef !== undefined) {
formRef.validate(valid => {
if (valid) {
if (formType.value) useEdit(editUrl, form, visible);
else useAdd(addUrl, form, visible);
}
});
}
};
const topButtonClick = (eventName: string) => {
switch (eventName) {
case "add":
add();
break;
}
};
const operateButtonClick = (eventName: string, row: any) => {
switch (eventName) {
case "edit":
edit(row);
break;
case "remove":
remove(row);
break;
}
};
}
};
const topButtonClick = (eventName: string) => {
switch (eventName) {
case "add":
add();
break;
}
};
const operateButtonClick = (eventName: string, row: any) => {
switch (eventName) {
case "edit":
edit(row);
break;
case "remove":
remove(row);
break;
}
};
</script>
<template>
<BasePageableTable :url="getPageUrl" :searchers="searchers" ref="tableRef">
<template #tool-button>
<DefaultToolButton @top-button-click="topButtonClick" />
</template>
<template #columns>
<el-table-column prop="id" type="hidden" width="40" />
<el-table-column :label="$t('_prop.sale.repairrecord.productType')" prop="productType" />
<el-table-column :label="$t('_prop.sale.repairrecord.productSn')" prop="productSn" />
<el-table-column :label="$t('_prop.sale.repairrecord.mac')" prop="mac" />
<el-table-column :label="$t('_prop.sale.repairrecord.outProductDate')" prop="outProductDate" />
<el-table-column :label="$t('_prop.sale.repairrecord.repairDate')" prop="repairDate" />
<el-table-column :label="$t('_prop.sale.repairrecord.repairMark')" prop="repairMark" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
</template>
</BasePageableTable>
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules">
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
</template>
</BaseForm>
<TreeSidePageableTable
:url="getPageUrl"
:searchers="searchers"
ref="tableRef"
:tree-side-url="treeSideUrl"
tree-side-node-name="keyAccountId"
tree-side-param-name="keyAccountId"
tree-side-title="所有客户"
>
<template #tool-button>
<DefaultToolButton @top-button-click="topButtonClick" />
</template>
<template #columns>
<el-table-column prop="id" type="hidden" width="40" />
<el-table-column :label="$t('_prop.sale.repairrecord.productType')" prop="productType" />
<el-table-column :label="$t('_prop.sale.repairrecord.productSn')" prop="productSn" />
<el-table-column :label="$t('_prop.sale.repairrecord.mac')" prop="mac" />
<el-table-column :label="$t('_prop.sale.repairrecord.outProductDate')" prop="outProductDate" />
<el-table-column :label="$t('_prop.sale.repairrecord.repairDate')" prop="repairDate" />
<el-table-column :label="$t('_prop.sale.repairrecord.repairMark')" prop="repairMark" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
</template>
</TreeSidePageableTable>
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules">
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
</template>
</BaseForm>
</template>

View File

@@ -1,115 +1,109 @@
<script lang="ts" setup>
import BasePageableTable from "@/components/base/base-pageable-table/BasePageableTable.vue";
import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue";
import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue";
import { usePage } from "@/composables/use-page";
import BaseForm from "@/components/base/base-form/BaseForm.vue";
import { $t } from "@/common/languages";
import type { FormInstance, FormRules } from "element-plus";
import { formatDate } from "@/common/utils/format-utils";
import BasePageableTable from "@/components/base/base-pageable-table/BasePageableTable.vue";
import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue";
import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue";
import { usePage } from "@/composables/use-page";
import BaseForm from "@/components/base/base-form/BaseForm.vue";
import { $t } from "@/common/languages";
import type { FormInstance, FormRules } from "element-plus";
import { formatDate } from "@/common/utils/format-utils";
/**
* 必须要的变量
*/
/**
* 必须要的变量
*/
const getPageUrl = "/warehouse/inventorycount/getInventoryCountPage";
const addUrl = "/warehouse/inventorycount/addInventoryCount";
const editUrl = "/warehouse/inventorycount/updateInventoryCount";
const removeUrl = "/warehouse/inventorycount/deleteInventoryCount";
const searchers = [
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.warehouse.inventorycount.searchCode") },
];
const rules = reactive<FormRules>({
storeId: [{ required: true, message: $t("_message.warehouse.inventorycount.input_storeId"), trigger: "blur" }],
formName: [{ required: true, message: $t("_message.warehouse.inventorycount.input_formName"), trigger: "blur" }],
formMark: [{ required: true, message: $t("_message.warehouse.inventorycount.input_formMark"), trigger: "blur" }],
const getPageUrl = "/warehouse/inventorycount/getInventoryCountPage";
const addUrl = "/warehouse/inventorycount/addInventoryCount";
const editUrl = "/warehouse/inventorycount/updateInventoryCount";
const removeUrl = "/warehouse/inventorycount/deleteInventoryCount";
const searchers = [
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.warehouse.inventorycount.searchCode") },
];
const rules = reactive<FormRules>({
storeId: [{ required: true, message: $t("_message.warehouse.inventorycount.input_storeId"), trigger: "blur" }],
formName: [{ required: true, message: $t("_message.warehouse.inventorycount.input_formName"), trigger: "blur" }],
formMark: [{ required: true, message: $t("_message.warehouse.inventorycount.input_formMark"), trigger: "blur" }],
});
/**
* 基本不变通用变量
*/
const tableRef = ref<InstanceType<typeof BasePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
const { title, visible, formType, form } = useGeneralPageRef();
/**
* 可以自定义的变量
*/
const add = () => {
form.value = {};
title.value = "_title.warehouse.inventorycount.add";
visible.value = true;
formType.value = false;
};
const edit = (row: any) => {
title.value = "_title.warehouse.inventorycount.edit";
form.value = { ...row };
visible.value = true;
formType.value = true;
};
const remove = (row: any) => {
useRemove(removeUrl, row.id, "_message.warehouse.inventorycount.delete_message");
};
const submit = (form: any, formRef: FormInstance | undefined) => {
if (formRef !== undefined) {
formRef.validate(valid => {
if (valid) {
if (formType.value) useEdit(editUrl, form, visible);
else useAdd(addUrl, form, visible);
}
});
/**
* 基本不变通用变量
*/
const tableRef = ref<InstanceType<typeof BasePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
const { title, visible, formType, form } = useGeneralPageRef();
/**
* 可以自定义的变量
*/
const add = () => {
form.value = {};
title.value = "_title.warehouse.inventorycount.add";
visible.value = true;
formType.value = false;
};
const edit = (row: any) => {
title.value = "_title.warehouse.inventorycount.edit";
form.value = { ...row };
visible.value = true;
formType.value = true;
};
const remove = (row: any) => {
useRemove(removeUrl, row.id, "_message.warehouse.inventorycount.delete_message");
};
const submit = (form: any, formRef: FormInstance | undefined) => {
if (formRef !== undefined) {
formRef.validate(valid => {
if (valid) {
if (formType.value) useEdit(editUrl, form, visible);
else useAdd(addUrl, form, visible);
}
});
}
};
const topButtonClick = (eventName: string) => {
switch (eventName) {
case "add":
add();
break;
}
};
const operateButtonClick = (eventName: string, row: any) => {
switch (eventName) {
case "edit":
edit(row);
break;
case "remove":
remove(row);
break;
}
};
}
};
const topButtonClick = (eventName: string) => {
switch (eventName) {
case "add":
add();
break;
}
};
const operateButtonClick = (eventName: string, row: any) => {
switch (eventName) {
case "edit":
edit(row);
break;
case "remove":
remove(row);
break;
}
};
</script>
<template>
<BasePageableTable :url="getPageUrl" :searchers="searchers" ref="tableRef">
<template #tool-button>
<DefaultToolButton @top-button-click="topButtonClick" />
</template>
<template #columns>
<el-table-column prop="id" type="hidden" width="40" />
<el-table-column :label="$t('_prop.warehouse.inventorycount.formCode')" prop="formCode" />
<el-table-column :label="$t('_prop.warehouse.inventorycount.formName')" prop="formName" />
<el-table-column :label="$t('_prop.warehouse.inventorycount.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.warehouse.inventorycount.formMark')" prop="formMark" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
</template>
</BasePageableTable>
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules">
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
<el-form-item :label="$t('_prop.warehouse.inventorycount.storeId')" prop="storeId">
<el-input v-model="form.storeId"
:placeholder="$t('_message.warehouse.inventorycount.input_storeId')"
/>
</el-form-item>
<el-form-item :label="$t('_prop.warehouse.inventorycount.formName')" prop="formName">
<el-input v-model="form.formName"
:placeholder="$t('_message.warehouse.inventorycount.input_formName')"
/>
</el-form-item>
<el-form-item :label="$t('_prop.warehouse.inventorycount.formMark')" prop="formMark">
<el-input v-model="form.formMark"
:placeholder="$t('_message.warehouse.inventorycount.input_formMark')"
/>
</el-form-item>
</template>
</BaseForm>
<BasePageableTable :url="getPageUrl" :searchers="searchers" ref="tableRef">
<template #tool-button>
<DefaultToolButton @top-button-click="topButtonClick" />
</template>
<template #columns>
<el-table-column prop="id" type="hidden" width="40" />
<el-table-column :label="$t('_prop.warehouse.inventorycount.formCode')" prop="formCode" />
<el-table-column :label="$t('_prop.warehouse.inventorycount.formName')" prop="formName" />
<el-table-column :label="$t('_prop.warehouse.inventorycount.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.warehouse.inventorycount.formMark')" prop="formMark" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
</template>
</BasePageableTable>
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules">
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
<el-form-item :label="$t('_prop.warehouse.inventorycount.storeId')" prop="storeId">
<el-input v-model="form.storeId" :placeholder="$t('_message.warehouse.inventorycount.input_storeId')" />
</el-form-item>
<el-form-item :label="$t('_prop.warehouse.inventorycount.formName')" prop="formName">
<el-input v-model="form.formName" :placeholder="$t('_message.warehouse.inventorycount.input_formName')" />
</el-form-item>
<el-form-item :label="$t('_prop.warehouse.inventorycount.formMark')" prop="formMark">
<el-input v-model="form.formMark" :placeholder="$t('_message.warehouse.inventorycount.input_formMark')" />
</el-form-item>
</template>
</BaseForm>
</template>

View File

@@ -7,17 +7,20 @@ import BaseForm from "@/components/base/base-form/BaseForm.vue";
import { $t } from "@/common/languages";
import type { FormInstance, FormRules } from "element-plus";
import { formatDate } from "@/common/utils/format-utils";
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
/**
* 必须要的变量
*/
const getPageUrl = "/warehouse/stocktransferorder/getStockTransferOrderPage";
const getItemUrl = "/warehouse/stocktransferorder/getStockTransferOrderItem";
const addUrl = "/warehouse/stocktransferorder/addStockTransferOrder";
const editUrl = "/warehouse/stocktransferorder/updateStockTransferOrder";
const removeUrl = "/warehouse/stocktransferorder/deleteStockTransferOrder";
const searchers = [
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.warehouse.stocktransferorder.searchCode") },
{ name: "partNumber", type: "text" as const, placeholder: $t("_prop.warehouse.stocktransferorder.partNumber") },
];
const rules = reactive<FormRules>({
storeId: [{ required: true, message: $t("_message.warehouse.stocktransferorder.input_storeId"), trigger: "blur" }],
@@ -81,12 +84,19 @@ const operateButtonClick = (eventName: string, row: any) => {
};
</script>
<template>
<BasePageableTable :url="getPageUrl" :searchers="searchers" ref="tableRef">
<ExpandablePageableTable
:url="getPageUrl"
:searchers="searchers"
ref="tableRef"
:item-url="getItemUrl"
item-id-key="id"
item-id-name="orderId"
itemFieldName="orderItems"
>
<template #tool-button>
<DefaultToolButton @top-button-click="topButtonClick" />
</template>
<template #columns>
<el-table-column prop="id" type="hidden" width="40" />
<el-table-column :label="$t('_prop.warehouse.stocktransferorder.formCode')" prop="formCode" />
<el-table-column :label="$t('_prop.warehouse.stocktransferorder.formName')" prop="formName" />
<el-table-column :label="$t('_prop.warehouse.stocktransferorder.storeName')" prop="storeName" />
@@ -95,7 +105,15 @@ const operateButtonClick = (eventName: string, row: any) => {
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
</template>
</BasePageableTable>
<template #item-content="{ itemData }">
<el-table :data="itemData" size="small" border stripe>
<el-table-column :label="$t('_prop.production.bom_item.partNumber')" prop="partNumber" width="150" />
<el-table-column :label="$t('_prop.production.bom_item.productSpecs')" prop="productSpecs" width="200" />
<el-table-column :label="$t('_prop.production.bom_item.productCount')" prop="productCount" width="200" />
<el-table-column :label="$t('_prop.production.bom_item.demandCount')" prop="demandCount" width="200" />
</el-table>
</template>
</ExpandablePageableTable>
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules">
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>

View File

@@ -5,46 +5,74 @@ import DefaultOperateButtonColumn from "@/components/base/default-column/Default
import { usePage } from "@/composables/use-page";
import BaseForm from "@/components/base/base-form/BaseForm.vue";
import { $t } from "@/common/languages";
import type { FormInstance, FormRules } from "element-plus";
import { ElMessage, type FormInstance, type FormRules } from "element-plus";
import { formatDate } from "@/common/utils/format-utils";
/**
* 必须要的变量
*/
import { get, post } from "@/common/http/request";
import BaseTableForm from "@/components/base/base-table-form/BaseTableForm.vue";
import QrCodeDialog from "@/components/base/base-qrcode/QrCodeDialog.vue";
import { Delete, Edit, Plus } from "@element-plus/icons-vue";
const getPageUrl = "/warehouse/warehouseitem/getWarehouseItemPage";
const addUrl = "/warehouse/warehouseitem/addWarehouseItem";
const editUrl = "/warehouse/warehouseitem/updateWarehouseItem";
const removeUrl = "/warehouse/warehouseitem/deleteWarehouseItem";
const getPartNumberUrl = "/warehouse/warehouseitem/getPartNumberForQrCode";
const getVendorListUrl = "/warehouse/warehouseitem/getVendorList";
const saveVendorListUrl = "/warehouse/warehouseitem/saveVendorList";
const getVendorSelectListUrl = "/sys/vendor/getVendorList";
const searchers = [
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.warehouse.warehouseitem.searchCode") },
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.warehouse.warehouse_item.partNumber") },
];
const rules = reactive<FormRules>({
productNumber: [
{ required: true, message: $t("_message.warehouse.warehouseitem.input_productNumber"), trigger: "blur" },
partNumber: [{ required: true, message: $t("_message.warehouse.warehouse_item.input_partNumber"), trigger: "blur" }],
productType: [
{ required: true, message: $t("_message.warehouse.warehouse_item.input_productType"), trigger: "blur" },
],
productSpec: [{ required: true, message: $t("_message.warehouse.warehouseitem.input_productSpec"), trigger: "blur" }],
productType: [{ required: true, message: $t("_message.warehouse.warehouseitem.input_productType"), trigger: "blur" }],
productBrand: [
{ required: true, message: $t("_message.warehouse.warehouseitem.input_productBrand"), trigger: "blur" },
productSpecs: [
{ required: true, message: $t("_message.warehouse.warehouse_item.input_productSpecs"), trigger: "blur" },
],
productPackSize: [
{ required: true, message: $t("_message.warehouse.warehouseitem.input_productPackSize"), trigger: "blur" },
],
productPacking: [
{ required: true, message: $t("_message.warehouse.warehouseitem.input_productPacking"), trigger: "blur" },
],
productMark: [{ required: true, message: $t("_message.warehouse.warehouseitem.input_productMark"), trigger: "blur" }],
});
/**
* 基本不变通用变量
*/
const tableRef = ref<InstanceType<typeof BasePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
const { title, visible, formType, form } = useGeneralPageRef();
/**
* 可以自定义的变量
*/
const vendorDialogVisible = ref(false);
const vendorDialogTitle = ref("");
const currentWarehouseItemId = ref<number>();
const dialogTableData = ref([] as any[]);
const allVendors = ref([] as any[]);
const vendorFormRef = ref<FormInstance>();
const vendorFormRules = reactive<FormRules>({
vendorId: [
{ required: true, message: () => $t("_message.warehouse.warehouse_item.select_vendor"), trigger: "change" },
{
validator: (rule: any, value: any, callback: any) => {
if (!value) {
callback();
return;
}
const duplicateCount = dialogTableData.value.filter((item: any) => item.vendorId === value).length;
if (duplicateCount > 1) {
callback(new Error($t("_message.warehouse.warehouse_item.vendor_duplicate")));
} else {
callback();
}
},
trigger: "change",
},
],
costPrice: [
{ required: true, message: () => $t("_message.warehouse.warehouse_item.input_costPrice"), trigger: "blur" },
{ type: "number", min: 0, message: () => $t("_message.warehouse.warehouse_item.input_costPrice"), trigger: "blur" },
],
});
const qrCodeDialogVisible = ref(false);
const qrCodeContent = ref("");
const qrCodeLabel = ref("");
const add = () => {
form.value = {};
@@ -52,15 +80,47 @@ const add = () => {
visible.value = true;
formType.value = false;
};
const edit = (row: any) => {
title.value = "_title.warehouse.warehouseitem.edit";
form.value = { ...row };
visible.value = true;
formType.value = true;
};
const remove = (row: any) => {
useRemove(removeUrl, row.id, "_message.warehouse.warehouseitem.delete_message");
useRemove(removeUrl, row.id, "_message.warehouse.warehouse_item.delete_message");
};
const editVendors = async (row: any) => {
currentWarehouseItemId.value = row.id;
vendorDialogTitle.value = $t("_title.warehouse.warehouseitem.vendorList");
vendorDialogVisible.value = true;
try {
const [vendorListResponse, allVendorResponse] = await Promise.all([
get(getVendorListUrl, { warehouseItemId: row.id }),
get(getVendorSelectListUrl),
]);
dialogTableData.value = vendorListResponse.data || [];
allVendors.value = allVendorResponse.data || [];
} catch (error) {
console.error("Load vendor list failed:", error);
}
};
const printQrCode = async (row: any) => {
try {
const partNumber = await get(getPartNumberUrl, { warehouseItemId: row.id }).then(res => res.data);
qrCodeContent.value = partNumber;
qrCodeLabel.value = partNumber;
qrCodeDialogVisible.value = true;
} catch (error) {
console.error("Get part number failed:", error);
}
};
const submit = (form: any, formRef: FormInstance | undefined) => {
if (formRef !== undefined) {
formRef.validate(valid => {
@@ -71,6 +131,7 @@ const submit = (form: any, formRef: FormInstance | undefined) => {
});
}
};
const topButtonClick = (eventName: string) => {
switch (eventName) {
case "add":
@@ -78,6 +139,7 @@ const topButtonClick = (eventName: string) => {
break;
}
};
const operateButtonClick = (eventName: string, row: any) => {
switch (eventName) {
case "edit":
@@ -86,64 +148,286 @@ const operateButtonClick = (eventName: string, row: any) => {
case "remove":
remove(row);
break;
case "editVendors":
editVendors(row);
break;
case "printQrCode":
printQrCode(row);
break;
}
};
const saveVendorList = async () => {
if (!vendorFormRef.value) return;
try {
await vendorFormRef.value.validate();
} catch (error) {
console.error("Validation failed:", error);
return;
}
const validVendors = dialogTableData.value.filter(v => v.vendorId !== null && v.vendorId !== undefined);
if (validVendors.length === 0) {
return;
}
const vendorList = validVendors.map(v => ({
vendorId: v.vendorId,
costPrice: v.costPrice,
}));
await post(saveVendorListUrl, {
warehouseItemId: currentWarehouseItemId.value,
vendorList,
})
.then(res => {
if (res.code === 0) {
ElMessage.info($t("_message.warehouse.warehouse_item.save_vendors_success"));
vendorDialogVisible.value = false;
tableRef.value?.reload();
} else {
ElMessage.error($t("_message.warehouse.warehouse_item.save_vendors_success") + res.msg);
}
})
.catch(err => {
ElMessage.error($t("_message.warehouse.warehouse_item.save_vendors_success") + err);
});
};
const addVendorRow = () => {
dialogTableData.value.push({
id: null,
vendorId: null,
vendorName: "",
costPrice: null,
procureDate: null,
isEditing: true,
});
};
const editVendorRow = (row: any) => {
row.isEditing = true;
};
const deleteVendorRow = (index: number) => {
dialogTableData.value.splice(index, 1);
};
const saveVendorRow = async (row: any) => {
if (!vendorFormRef.value) return;
const rowIndex = dialogTableData.value.indexOf(row);
if (rowIndex === -1) return;
try {
await vendorFormRef.value.validateField(`dialogTableData[${rowIndex}].vendorId`);
await vendorFormRef.value.validateField(`dialogTableData[${rowIndex}].costPrice`);
row.isEditing = false;
} catch (error) {
console.error("Validation failed:", error);
}
};
const cancelVendorEdit = (row: any, originalRow: any) => {
row.vendorId = originalRow.vendorId;
row.costPrice = originalRow.costPrice;
row.procureDate = originalRow.procureDate;
row.isEditing = false;
};
</script>
<template>
<BasePageableTable :url="getPageUrl" :searchers="searchers" ref="tableRef">
<template #tool-button>
<DefaultToolButton @top-button-click="topButtonClick" />
</template>
<template #columns>
<el-table-column prop="id" type="hidden" width="40" />
<el-table-column :label="$t('_prop.warehouse.warehouseitem.productType')" prop="productType" />
<el-table-column :label="$t('_prop.warehouse.warehouseitem.partNumber')" prop="partNumber" />
<el-table-column :label="$t('_prop.warehouse.warehouseitem.productSpec')" prop="productSpec" />
<el-table-column :label="$t('_prop.warehouse.warehouseitem.productPacking')" prop="productPacking" />
<el-table-column :label="$t('_prop.warehouse.warehouseitem.productBrand')" prop="productBrand" />
<el-table-column :label="$t('_prop.warehouse.warehouseitem.productPackSize')" prop="productPackSize" />
<el-table-column :label="$t('_prop.warehouse.warehouseitem.productPrice')" prop="productPrice" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.partNumber')" prop="partNumber" width="150" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productType')" prop="productType" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productSpecs')" prop="productSpecs" width="150" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productBrand')" prop="productBrand" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productPacking')" prop="productPacking" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productPackSize')" prop="productPackSize" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.productPrice')" prop="productPrice" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<el-table-column :label="$t('_prop.warehouse.warehouseitem.createUserName')" prop="createUserName" />
<el-table-column :label="$t('_prop.warehouse.warehouse_item.createUserName')" prop="createUserName" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
</template>
</BasePageableTable>
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules">
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
<el-form-item :label="$t('_prop.warehouse.warehouseitem.productNumber')" prop="productNumber">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item :label="$t('_prop.warehouse.warehouse_item.partNumber')" prop="partNumber">
<el-input
v-model="form.partNumber"
:placeholder="$t('_message.warehouse.warehouse_item.input_partNumber')"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="$t('_prop.warehouse.warehouse_item.productSpecs')" prop="productSpecs">
<el-input
v-model="form.productSpecs"
:placeholder="$t('_message.warehouse.warehouse_item.input_productSpecs')"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item :label="$t('_prop.warehouse.warehouse_item.productType')" prop="productType">
<el-input
v-model="form.productType"
:placeholder="$t('_message.warehouse.warehouse_item.input_productType')"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="$t('_prop.warehouse.warehouse_item.productBrand')" prop="productBrand">
<el-input
v-model="form.productBrand"
:placeholder="$t('_message.warehouse.warehouse_item.input_productBrand')"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item :label="$t('_prop.warehouse.warehouse_item.productPacking')" prop="productPacking">
<el-input-number
v-model="form.productPacking"
:min="1"
:placeholder="$t('_message.warehouse.warehouse_item.input_productPacking')"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="$t('_prop.warehouse.warehouse_item.productPackSize')" prop="productPackSize">
<el-input
v-model="form.productPackSize"
:placeholder="$t('_message.warehouse.warehouse_item.input_productPackSize')"
/>
</el-form-item>
</el-col>
</el-row>
<el-form-item :label="$t('_prop.warehouse.warehouse_item.productMark')" prop="productMark">
<el-input
v-model="form.productNumber"
:placeholder="$t('_message.warehouse.warehouseitem.input_productNumber')"
v-model="form.productMark"
type="textarea"
:rows="2"
:placeholder="$t('_message.warehouse.warehouse_item.input_productMark')"
/>
</el-form-item>
<el-form-item :label="$t('_prop.warehouse.warehouseitem.productSpec')" prop="productSpec">
<el-input v-model="form.productSpec" :placeholder="$t('_message.warehouse.warehouseitem.input_productSpec')" />
</el-form-item>
<el-form-item :label="$t('_prop.warehouse.warehouseitem.productType')" prop="productType">
<el-input v-model="form.productType" :placeholder="$t('_message.warehouse.warehouseitem.input_productType')" />
</el-form-item>
<el-form-item :label="$t('_prop.warehouse.warehouseitem.productBrand')" prop="productBrand">
<el-input
v-model="form.productBrand"
:placeholder="$t('_message.warehouse.warehouseitem.input_productBrand')"
/>
</el-form-item>
<el-form-item :label="$t('_prop.warehouse.warehouseitem.productPackSize')" prop="productPackSize">
<el-input
v-model="form.productPackSize"
:placeholder="$t('_message.warehouse.warehouseitem.input_productPackSize')"
/>
</el-form-item>
<el-form-item :label="$t('_prop.warehouse.warehouseitem.productPacking')" prop="productPacking">
<el-input
v-model="form.productPacking"
:placeholder="$t('_message.warehouse.warehouseitem.input_productPacking')"
/>
</el-form-item>
<el-form-item :label="$t('_prop.warehouse.warehouseitem.productMark')" prop="productMark">
<el-input v-model="form.productMark" :placeholder="$t('_message.warehouse.warehouseitem.input_productMark')" />
</el-form-item>
</template>
</BaseForm>
<el-dialog v-model="vendorDialogVisible" :title="vendorDialogTitle" width="80%" :close-on-click-modal="false">
<el-form ref="vendorFormRef" :model="{ dialogTableData }" :rules="vendorFormRules">
<el-table :data="dialogTableData" border stripe style="width: 100%" max-height="50vh">
<el-table-column :label="$t('_prop.warehouse.warehouse_item.vendorName')" width="250" show-overflow-tooltip>
<template #default="{ row, $index }">
<el-form-item
v-if="row.isEditing"
:prop="`dialogTableData[${$index}].vendorId`"
:rules="vendorFormRules.vendorId"
>
<el-select
v-model="row.vendorId"
:placeholder="$t('_message.warehouse.warehouse_item.select_vendor')"
filterable
style="width: 100%"
@change="
value => {
const vendor = allVendors.find(v => v.value === value);
if (vendor) {
row.vendorName = vendor.label;
}
}
"
>
<el-option
v-for="vendor in allVendors"
:key="vendor.value"
:label="vendor.label"
:value="vendor.value"
/>
</el-select>
</el-form-item>
<span v-else>{{ row.vendorName }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.warehouse.warehouse_item.costPrice')" width="150">
<template #default="{ row, $index }">
<el-form-item
v-if="row.isEditing"
:prop="`dialogTableData[${$index}].costPrice`"
:rules="vendorFormRules.costPrice"
>
<el-input-number
v-model="row.costPrice"
:min="0"
:precision="2"
:placeholder="$t('_message.warehouse.warehouse_item.input_costPrice')"
style="width: 100%"
/>
</el-form-item>
<span v-else>{{ row.costPrice }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.warehouse.warehouse_item.procureDate')" width="200">
<template #default="{ row }">
<span>{{ row.procureDate }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.common.operate')" width="150" align="center">
<template #default="{ row, $index }">
<template v-if="row.isEditing">
<el-button type="primary" link size="small" @click="saveVendorRow(row)">
{{ $t("_button.confirm") }}
</el-button>
<el-button link size="small" @click="cancelVendorEdit(row, { ...row })">
{{ $t("_button.cancel") }}
</el-button>
</template>
<template v-else>
<el-button type="primary" link size="small" @click="editVendorRow(row)">
<el-icon><Edit /></el-icon>
</el-button>
<el-button type="danger" link size="small" @click="deleteVendorRow($index)">
<el-icon><Delete /></el-icon>
</el-button>
</template>
</template>
</el-table-column>
</el-table>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="addVendorRow">
<el-icon><Plus /></el-icon>
{{ $t("_button.add") }}
</el-button>
<el-button type="success" @click="saveVendorList">
<el-icon><Edit /></el-icon>
{{ $t("_button.save") }}
</el-button>
<el-button @click="vendorDialogVisible = false">
{{ $t("_button.cancel") }}
</el-button>
</div>
</template>
</el-dialog>
<QrCodeDialog
v-model:visible="qrCodeDialogVisible"
:title="$t('_title.warehouse.warehouseitem.printQrCode')"
:qr-code-content="qrCodeContent"
:label="qrCodeLabel"
/>
</template>

View File

@@ -1,115 +1,109 @@
<script lang="ts" setup>
import BasePageableTable from "@/components/base/base-pageable-table/BasePageableTable.vue";
import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue";
import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue";
import { usePage } from "@/composables/use-page";
import BaseForm from "@/components/base/base-form/BaseForm.vue";
import { $t } from "@/common/languages";
import type { FormInstance, FormRules } from "element-plus";
import { formatDate } from "@/common/utils/format-utils";
import BasePageableTable from "@/components/base/base-pageable-table/BasePageableTable.vue";
import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue";
import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue";
import { usePage } from "@/composables/use-page";
import BaseForm from "@/components/base/base-form/BaseForm.vue";
import { $t } from "@/common/languages";
import type { FormInstance, FormRules } from "element-plus";
import { formatDate } from "@/common/utils/format-utils";
/**
* 必须要的变量
*/
/**
* 必须要的变量
*/
const getPageUrl = "/warehouse/warehousereceipt/getWarehouseReceiptPage";
const addUrl = "/warehouse/warehousereceipt/addWarehouseReceipt";
const editUrl = "/warehouse/warehousereceipt/updateWarehouseReceipt";
const removeUrl = "/warehouse/warehousereceipt/deleteWarehouseReceipt";
const searchers = [
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.warehouse.warehousereceipt.searchCode") },
];
const rules = reactive<FormRules>({
storeId: [{ required: true, message: $t("_message.warehouse.warehousereceipt.input_storeId"), trigger: "blur" }],
formName: [{ required: true, message: $t("_message.warehouse.warehousereceipt.input_formName"), trigger: "blur" }],
formMark: [{ required: true, message: $t("_message.warehouse.warehousereceipt.input_formMark"), trigger: "blur" }],
const getPageUrl = "/warehouse/warehousereceipt/getWarehouseReceiptPage";
const addUrl = "/warehouse/warehousereceipt/addWarehouseReceipt";
const editUrl = "/warehouse/warehousereceipt/updateWarehouseReceipt";
const removeUrl = "/warehouse/warehousereceipt/deleteWarehouseReceipt";
const searchers = [
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.warehouse.warehousereceipt.searchCode") },
];
const rules = reactive<FormRules>({
storeId: [{ required: true, message: $t("_message.warehouse.warehousereceipt.input_storeId"), trigger: "blur" }],
formName: [{ required: true, message: $t("_message.warehouse.warehousereceipt.input_formName"), trigger: "blur" }],
formMark: [{ required: true, message: $t("_message.warehouse.warehousereceipt.input_formMark"), trigger: "blur" }],
});
/**
* 基本不变通用变量
*/
const tableRef = ref<InstanceType<typeof BasePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
const { title, visible, formType, form } = useGeneralPageRef();
/**
* 可以自定义的变量
*/
const add = () => {
form.value = {};
title.value = "_title.warehouse.warehousereceipt.add";
visible.value = true;
formType.value = false;
};
const edit = (row: any) => {
title.value = "_title.warehouse.warehousereceipt.edit";
form.value = { ...row };
visible.value = true;
formType.value = true;
};
const remove = (row: any) => {
useRemove(removeUrl, row.id, "_message.warehouse.warehousereceipt.delete_message");
};
const submit = (form: any, formRef: FormInstance | undefined) => {
if (formRef !== undefined) {
formRef.validate(valid => {
if (valid) {
if (formType.value) useEdit(editUrl, form, visible);
else useAdd(addUrl, form, visible);
}
});
/**
* 基本不变通用变量
*/
const tableRef = ref<InstanceType<typeof BasePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
const { title, visible, formType, form } = useGeneralPageRef();
/**
* 可以自定义的变量
*/
const add = () => {
form.value = {};
title.value = "_title.warehouse.warehousereceipt.add";
visible.value = true;
formType.value = false;
};
const edit = (row: any) => {
title.value = "_title.warehouse.warehousereceipt.edit";
form.value = { ...row };
visible.value = true;
formType.value = true;
};
const remove = (row: any) => {
useRemove(removeUrl, row.id, "_message.warehouse.warehousereceipt.delete_message");
};
const submit = (form: any, formRef: FormInstance | undefined) => {
if (formRef !== undefined) {
formRef.validate(valid => {
if (valid) {
if (formType.value) useEdit(editUrl, form, visible);
else useAdd(addUrl, form, visible);
}
});
}
};
const topButtonClick = (eventName: string) => {
switch (eventName) {
case "add":
add();
break;
}
};
const operateButtonClick = (eventName: string, row: any) => {
switch (eventName) {
case "edit":
edit(row);
break;
case "remove":
remove(row);
break;
}
};
}
};
const topButtonClick = (eventName: string) => {
switch (eventName) {
case "add":
add();
break;
}
};
const operateButtonClick = (eventName: string, row: any) => {
switch (eventName) {
case "edit":
edit(row);
break;
case "remove":
remove(row);
break;
}
};
</script>
<template>
<BasePageableTable :url="getPageUrl" :searchers="searchers" ref="tableRef">
<template #tool-button>
<DefaultToolButton @top-button-click="topButtonClick" />
</template>
<template #columns>
<el-table-column prop="id" type="hidden" width="40" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.formCode')" prop="formCode" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.formName')" prop="formName" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.formMark')" prop="formMark" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
</template>
</BasePageableTable>
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules">
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
<el-form-item :label="$t('_prop.warehouse.warehousereceipt.storeId')" prop="storeId">
<el-input v-model="form.storeId"
:placeholder="$t('_message.warehouse.warehousereceipt.input_storeId')"
/>
</el-form-item>
<el-form-item :label="$t('_prop.warehouse.warehousereceipt.formName')" prop="formName">
<el-input v-model="form.formName"
:placeholder="$t('_message.warehouse.warehousereceipt.input_formName')"
/>
</el-form-item>
<el-form-item :label="$t('_prop.warehouse.warehousereceipt.formMark')" prop="formMark">
<el-input v-model="form.formMark"
:placeholder="$t('_message.warehouse.warehousereceipt.input_formMark')"
/>
</el-form-item>
</template>
</BaseForm>
<BasePageableTable :url="getPageUrl" :searchers="searchers" ref="tableRef">
<template #tool-button>
<DefaultToolButton @top-button-click="topButtonClick" />
</template>
<template #columns>
<el-table-column prop="id" type="hidden" width="40" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.formCode')" prop="formCode" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.formName')" prop="formName" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.formMark')" prop="formMark" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
</template>
</BasePageableTable>
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules">
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
<el-form-item :label="$t('_prop.warehouse.warehousereceipt.storeId')" prop="storeId">
<el-input v-model="form.storeId" :placeholder="$t('_message.warehouse.warehousereceipt.input_storeId')" />
</el-form-item>
<el-form-item :label="$t('_prop.warehouse.warehousereceipt.formName')" prop="formName">
<el-input v-model="form.formName" :placeholder="$t('_message.warehouse.warehousereceipt.input_formName')" />
</el-form-item>
<el-form-item :label="$t('_prop.warehouse.warehousereceipt.formMark')" prop="formMark">
<el-input v-model="form.formMark" :placeholder="$t('_message.warehouse.warehousereceipt.input_formMark')" />
</el-form-item>
</template>
</BaseForm>
</template>