Compare commits
5 Commits
xzh
...
7b962b0bfa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b962b0bfa | ||
|
|
34a6c03720 | ||
|
|
a9efd88267 | ||
| bd52bb055a | |||
| 1c49c222d5 |
@@ -0,0 +1,15 @@
|
||||
package org.nl.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties("printer")
|
||||
public class PrinterProperties {
|
||||
|
||||
private String ip = "192.168.1.100";
|
||||
|
||||
private int port = 9100;
|
||||
}
|
||||
@@ -64,16 +64,17 @@ public class InboundEasSyncServiceImpl implements InboundEasSyncService {
|
||||
|
||||
easMst.setBill_status(PurchaseBillStatus.CREATED.getCode());
|
||||
easMst.setModify_date(DateUtil.now());
|
||||
purchasemstMapper.insert(easMst);
|
||||
|
||||
for (Purchasedtl dtl : easDtlList) {
|
||||
purchasedtlMapper.insert(dtl);
|
||||
if (dtl.getHouse_code().contains("ZDLK")){
|
||||
//中鼎立库
|
||||
easMst.setForwardZD(1);
|
||||
//TODO 转发中鼎参数待确定
|
||||
wmsToZDWmdService.syncPurchaseReceiving(new JSONObject());
|
||||
}
|
||||
}
|
||||
purchasemstMapper.insert(easMst);
|
||||
|
||||
log.info("EAS采购入库单同步完成, billId: {}, 明细数: {}", billId, easDtlList.size());
|
||||
JSONObject result = new JSONObject();
|
||||
|
||||
@@ -83,8 +83,8 @@ public class PurchaseFormListenerHandler extends BaseFormListenerHandler<Purchas
|
||||
easAuditRequestDto.setData(easAuditDataDto);
|
||||
|
||||
final PmStockReturn stockReturn = new PmStockReturn();
|
||||
String stringId = IdUtil.getStringId();
|
||||
stockReturn.setRequest_Id(stringId);
|
||||
// String stringId = IdUtil.getStringId();
|
||||
stockReturn.setRequest_Id(params.getBillId());
|
||||
stockReturn.setCreate_time(DateUtil.now());
|
||||
stockReturn.setRequest_type(IOSEnum.BILL_TYPE.code("采购入库"));
|
||||
stockReturn.setStatus(StockReturnStatusEnum.TODO.getCode());
|
||||
@@ -95,11 +95,11 @@ public class PurchaseFormListenerHandler extends BaseFormListenerHandler<Purchas
|
||||
wmsToErpService.uploadErp(new JSONObject((JSONObject)JSON.toJSON(easAuditRequestDto)));
|
||||
pmStockReturnService.lambdaUpdate()
|
||||
.set(PmStockReturn::getStatus,StockReturnStatusEnum.SUCESS.getCode())
|
||||
.eq(PmStockReturn::getRequest_Id, stringId);
|
||||
.eq(PmStockReturn::getRequest_Id, params.getBillId());
|
||||
} catch (Exception e) {
|
||||
pmStockReturnService.lambdaUpdate()
|
||||
.set(PmStockReturn::getStatus,StockReturnStatusEnum.FAIL.getCode())
|
||||
.eq(PmStockReturn::getRequest_Id, stringId);
|
||||
.eq(PmStockReturn::getRequest_Id, params.getBillId());
|
||||
}
|
||||
}else {
|
||||
//更新单据状态执行中
|
||||
|
||||
@@ -63,4 +63,11 @@ public class PurchaseController {
|
||||
purchaseService.issueReturnBill(ids);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@PostMapping("/print")
|
||||
@Log("打印采购入库单")
|
||||
public ResponseEntity<Object> print(@RequestBody Set<String> ids) {
|
||||
purchaseService.print(ids);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,5 +32,7 @@ public interface PurchaseService extends IService<Purchasemst> {
|
||||
|
||||
List<Purchasedtl> selectListByBillId(String billId);
|
||||
|
||||
void print(Set<String> ids);
|
||||
|
||||
List<PurchaseMatInfoVo> selectPdaInMat(HashMap of);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ public class Purchasemst implements Serializable {
|
||||
|
||||
private String order_type;
|
||||
|
||||
private Integer forwardZD;
|
||||
|
||||
private String supplier_code;
|
||||
|
||||
private String supplier_name;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
m.bill_id,
|
||||
m.order_no,
|
||||
m.order_type,
|
||||
m.forwardZD,
|
||||
m.supplier_code,
|
||||
m.supplier_name,
|
||||
m.creator,
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.nl.wms.pm_manage.purchase.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
@@ -11,6 +12,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.nl.common.domain.query.PageQuery;
|
||||
import org.nl.common.exception.BadRequestException;
|
||||
import org.nl.common.utils.SecurityUtils;
|
||||
import org.nl.wms.ext_manage.service.WmsToErpService;
|
||||
import org.nl.wms.pda_manage.ios_manage.purchase.service.vo.PurchaseMatInfoVo;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.nl.common.utils.IdUtil;
|
||||
@@ -26,10 +28,15 @@ import org.nl.wms.warehouse_manage.enums.IOSEnum;
|
||||
import org.nl.wms.warehouse_manage.stockReturn.service.IPmStockReturnService;
|
||||
import org.nl.wms.warehouse_manage.stockReturn.service.dao.PmStockReturn;
|
||||
import org.nl.wms.warehouse_manage.stockReturn.service.enums.StockReturnStatusEnum;
|
||||
import org.nl.config.PrinterProperties;
|
||||
import org.nl.wms.pm_manage.purchase.util.ZplUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
@Slf4j
|
||||
@@ -45,6 +52,12 @@ public class PurchaseServiceImpl extends ServiceImpl<PurchasemstMapper, Purchase
|
||||
@Autowired
|
||||
private IPmStockReturnService pmStockReturnService;
|
||||
|
||||
@Autowired
|
||||
private WmsToErpService wmsToErpService;
|
||||
|
||||
@Autowired
|
||||
private PrinterProperties printerProperties;
|
||||
|
||||
@Override
|
||||
public IPage<PurchasemstListVo> queryAll(Map whereJson, PageQuery page) {
|
||||
return purchasemstMapper.queryAllByPage(
|
||||
@@ -164,18 +177,61 @@ public class PurchaseServiceImpl extends ServiceImpl<PurchasemstMapper, Purchase
|
||||
data.setBillNo(mst.getOrder_no());
|
||||
data.setEntrys(entryList);
|
||||
dto.setData(data);
|
||||
|
||||
PmStockReturn stockReturn = new PmStockReturn();
|
||||
stockReturn.setRequest_Id(IdUtil.getStringId());
|
||||
stockReturn.setRequest_Id(mst.getBill_id());
|
||||
stockReturn.setCreate_time(cn.hutool.core.date.DateUtil.now());
|
||||
stockReturn.setRequest_type(IOSEnum.BILL_TYPE.code("采购入库"));
|
||||
stockReturn.setStatus(StockReturnStatusEnum.TODO.getCode());
|
||||
stockReturn.setRequest_data(JSON.toJSONString(dto));
|
||||
pmStockReturnService.save(stockReturn);
|
||||
//回传erp
|
||||
JSONObject result = wmsToErpService.uploadErp((JSONObject) JSONObject.toJSON(dto));
|
||||
if (!result.getBoolean("status")){
|
||||
pmStockReturnService.lambdaUpdate()
|
||||
.set(PmStockReturn::getStatus, StockReturnStatusEnum.FAIL.getCode())
|
||||
.eq(PmStockReturn::getRequest_Id, mst.getBill_id());
|
||||
}else {
|
||||
pmStockReturnService.lambdaUpdate()
|
||||
.set(PmStockReturn::getStatus, StockReturnStatusEnum.SUCESS.getCode())
|
||||
.eq(PmStockReturn::getRequest_Id, mst.getBill_id());
|
||||
}
|
||||
|
||||
log.info("下发回传单成功, billId: {}, requestId: {}, 明细数: {}", mst.getBill_id(), stockReturn.getRequest_Id(), dtlList.size());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(Set<String> ids) {
|
||||
List<Purchasemst> mstList = purchasemstMapper.selectBatchIds(ids);
|
||||
if (ObjectUtil.isEmpty(mstList)) {
|
||||
throw new BadRequestException("未找到选中的单据");
|
||||
}
|
||||
StringBuilder allZpl = new StringBuilder();
|
||||
int labelCount = 0;
|
||||
for (Purchasemst mst : mstList) {
|
||||
List<Purchasedtl> dtlList = purchasedtlMapper.selectList(
|
||||
new LambdaQueryWrapper<Purchasedtl>()
|
||||
.eq(Purchasedtl::getBill_id, mst.getBill_id()));
|
||||
for (Purchasedtl dtl : dtlList) {
|
||||
String zpl = ZplUtil.generateLabel(
|
||||
dtl.getSku_name(), dtl.getSku_code(),
|
||||
dtl.getQty() != null ? dtl.getQty().stripTrailingZeros().toPlainString() : "0",
|
||||
dtl.getUnit(), mst.getBill_id(), dtl.getItem_no());
|
||||
allZpl.append(zpl);
|
||||
labelCount++;
|
||||
}
|
||||
}
|
||||
try (Socket socket = new Socket(printerProperties.getIp(), printerProperties.getPort());
|
||||
OutputStream out = socket.getOutputStream()) {
|
||||
out.write(allZpl.toString().getBytes(StandardCharsets.UTF_8));
|
||||
out.flush();
|
||||
} catch (Exception e) {
|
||||
log.error("打印失败, 打印机: {}:{}, 标签数: {}", printerProperties.getIp(), printerProperties.getPort(), labelCount, e);
|
||||
throw new BadRequestException("打印机连接失败: " + e.getMessage());
|
||||
}
|
||||
log.info("打印成功, 打印机: {}:{}, 标签数: {}", printerProperties.getIp(), printerProperties.getPort(), labelCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PurchaseMatInfoVo> pdaInboundSelectMatInfo(Map whereJson) {
|
||||
return purchasemstMapper.selectPdaInMat(whereJson);
|
||||
|
||||
@@ -13,6 +13,8 @@ public class PurchasemstListVo {
|
||||
|
||||
private String order_type;
|
||||
|
||||
private Integer forwardZD;
|
||||
|
||||
private String supplier_code;
|
||||
|
||||
private String supplier_name;
|
||||
|
||||
@@ -96,13 +96,14 @@
|
||||
|
||||
<insert id="insertAllData">
|
||||
INSERT INTO md_pb_groupplate(
|
||||
group_id,storagevehicle_code,material_id,pcsn,qty,qty_unit_id,qty_unit_name,ext_code,load_port,create_id,create_name,create_time
|
||||
group_id,storagevehicle_code,material_id,material_code,pcsn,qty,qty_unit_id,qty_unit_name,ext_code,load_port,create_id,create_name,create_time
|
||||
) values
|
||||
<foreach collection="data" item="item" separator=",">
|
||||
(
|
||||
#{item.group_id},
|
||||
#{item.storagevehicle_code},
|
||||
#{item.material_id},
|
||||
#{item.material_code},
|
||||
#{item.pcsn},
|
||||
#{item.qty},
|
||||
#{item.qty_unit_id},
|
||||
|
||||
@@ -58,6 +58,7 @@ public class ProductGroupServiceImpl implements IProductGroupService {
|
||||
json.put("load_port", dto.getLoadPort());
|
||||
json.put("storagevehicle_code", dto.getPalletCode());
|
||||
json.put("material_id", bomData.getMaterialCode());
|
||||
json.put("material_code", bomData.getMaterialCode());
|
||||
json.put("pcsn", "");
|
||||
json.put("qty_unit_id", bomData.getUnit());
|
||||
json.put("qty_unit_name", bomData.getUnit());
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
</div>
|
||||
<crudOperation :permission="permission">
|
||||
<el-button slot="right" class="filter-item" type="warning" icon="el-icon-s-promotion" size="mini" :disabled="audit_flag" @click="issueReturnBill">下发回传单</el-button>
|
||||
<el-button slot="right" class="filter-item" type="primary" icon="el-icon-printer" size="mini" :disabled="audit_flag" @click="printBill">打印</el-button>
|
||||
</crudOperation>
|
||||
<el-table ref="table" v-loading="crud.loading" size="mini" :data="crud.data" highlight-current-row style="width: 100%;" @selection-change="crud.selectionChangeHandler" @current-change="handleCurrentChange" @select="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" />
|
||||
@@ -47,6 +48,35 @@
|
||||
<el-table-column label="明细数" align="center" prop="dtl_count" width="80" />
|
||||
<el-table-column label="单据总数" align="center" prop="total_qty" width="80" />
|
||||
<el-table-column label="入库数量" align="center" prop="instock_qty" width="80" />
|
||||
<el-table-column label="转发中鼎" align="center" prop="forwardZD" width="80">
|
||||
<template slot-scope="scope">
|
||||
<p v-if="scope.row.forwardZD == '0'">-</p>
|
||||
<template v-else-if="scope.row.forwardZD == '1'">
|
||||
<el-popconfirm
|
||||
confirm-button-text='是'
|
||||
cancel-button-text='否'
|
||||
icon="el-icon-info"
|
||||
icon-color="red"
|
||||
title="是否重新转发中鼎?"
|
||||
@confirm="toForwardZD"
|
||||
>
|
||||
<a slot="reference" style="color: red;text-decoration: underline">失败</a>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
<!-- <a style="color: red;text-decoration: underline" v-else-if="scope.row.forwardZD == '1'">-->
|
||||
<!-- <el-popconfirm-->
|
||||
<!-- class="box-item"-->
|
||||
<!-- title="是否重新转发?"-->
|
||||
<!-- placement="top-start"-->
|
||||
<!-- >-->
|
||||
<!-- <template #reference>-->
|
||||
<!-- 失败-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-popconfirm>-->
|
||||
<!-- </a>-->
|
||||
<p v-else>成功</p>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column show-overflow-tooltip prop="supplier_code" width="120" label="供应商编码" />
|
||||
<el-table-column show-overflow-tooltip prop="supplier_name" width="150" label="供应商名称" />
|
||||
<el-table-column show-overflow-tooltip prop="creator" width="100" label="创建人" />
|
||||
@@ -136,6 +166,9 @@ export default {
|
||||
const s = String(d.getSeconds()).padStart(2, '0')
|
||||
return y + '-' + m + '-' + day + ' ' + h + ':' + min + ':' + s
|
||||
},
|
||||
toForwardZD(){
|
||||
console.log(123)
|
||||
},
|
||||
toView(index, row) {
|
||||
this.mstrow = row
|
||||
this.viewShow = true
|
||||
@@ -182,6 +215,26 @@ export default {
|
||||
this.crud.notify('下发失败', CRUD.NOTIFICATION_TYPE.ERROR)
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
printBill() {
|
||||
const selections = this.crud.selections
|
||||
if (!selections || selections.length === 0) {
|
||||
this.crud.notify('请至少选择一条单据', CRUD.NOTIFICATION_TYPE.INFO)
|
||||
return
|
||||
}
|
||||
const ids = selections.map(s => s.id)
|
||||
const billIds = selections.map(s => s.bill_id).join('、')
|
||||
this.$confirm('确认打印以下单据的物料标签?\n' + billIds, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
crudPurchase.print(ids).then(() => {
|
||||
this.crud.notify('打印指令已发送', CRUD.NOTIFICATION_TYPE.SUCCESS)
|
||||
}).catch(() => {
|
||||
this.crud.notify('打印失败', CRUD.NOTIFICATION_TYPE.ERROR)
|
||||
})
|
||||
}).catch(() => {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,4 +39,12 @@ export function issueReturnBill(data) {
|
||||
})
|
||||
}
|
||||
|
||||
export default { add, edit, del, get, issueReturnBill }
|
||||
export function print(ids) {
|
||||
return request({
|
||||
url: '/api/purchasemst/print',
|
||||
method: 'post',
|
||||
data: ids
|
||||
})
|
||||
}
|
||||
|
||||
export default { add, edit, del, get, issueReturnBill, print }
|
||||
|
||||
@@ -26,7 +26,8 @@ const zh = {
|
||||
'平库库存查询',
|
||||
'库位绑定/解绑',
|
||||
'平库调拨出库',
|
||||
'线边领料出库'
|
||||
'线边领料出库',
|
||||
'配盘出库',
|
||||
// '空托上架/下架/注册/呼叫',
|
||||
// 'AGV配送',
|
||||
// '人工盘点',
|
||||
@@ -148,6 +149,35 @@ const zh = {
|
||||
complete: '完成',
|
||||
completeSuccess: '操作成功',
|
||||
},
|
||||
productGroup: {
|
||||
title: '配盘出库',
|
||||
workSect: '工作区',
|
||||
workSectPlaceholder: '请选择工作区',
|
||||
workSectRequired: '请选择工作区',
|
||||
palletCode: '托盘码',
|
||||
palletCodePlaceholder: '请扫描或输入托盘码',
|
||||
palletCodeRequired: '请输入托盘码',
|
||||
workOrder: '工单',
|
||||
workOrderPlaceholder: '请选择工单',
|
||||
workOrderRequired: '请选择工单',
|
||||
loadPort: '上料口',
|
||||
loadPortPlaceholder: '请选择上料口',
|
||||
loadPortRequired: '请选择上料口',
|
||||
total: '共{0}条',
|
||||
noData: '暂无物料',
|
||||
noOrder: '暂无工单',
|
||||
noPort: '请先选择工单',
|
||||
materialCode: '物料编码',
|
||||
materialName: '物料名称',
|
||||
bomQty: '需求数量',
|
||||
useBomQty: '已用数量',
|
||||
planQty: '待配数量',
|
||||
inputQty: '配盘数量',
|
||||
inputQtyPlaceholder: '请输入数量',
|
||||
unit: '单位',
|
||||
confirm: '确定',
|
||||
submitSuccess: '提交成功',
|
||||
},
|
||||
}
|
||||
|
||||
const en = {
|
||||
@@ -175,8 +205,9 @@ const en = {
|
||||
'Putaway',
|
||||
'Inventory Query',
|
||||
'Bind/Unbind',
|
||||
'Picking Hall',
|
||||
'Containerless Receive',
|
||||
'Flat Outbound',
|
||||
'Line Picking',
|
||||
'Product Group',
|
||||
'Empty Pallet Ops',
|
||||
'AGV Delivery',
|
||||
'Manual Inventory',
|
||||
@@ -299,6 +330,35 @@ const en = {
|
||||
complete: 'Complete',
|
||||
completeSuccess: 'Success',
|
||||
},
|
||||
productGroup: {
|
||||
title: 'Product Group',
|
||||
workSect: 'Work Area',
|
||||
workSectPlaceholder: 'Select work area',
|
||||
workSectRequired: 'Work area is required',
|
||||
palletCode: 'Pallet Code',
|
||||
palletCodePlaceholder: 'Scan or enter pallet code',
|
||||
palletCodeRequired: 'Pallet code is required',
|
||||
workOrder: 'Work Order',
|
||||
workOrderPlaceholder: 'Select work order',
|
||||
workOrderRequired: 'Work order is required',
|
||||
loadPort: 'Load Port',
|
||||
loadPortPlaceholder: 'Select load port',
|
||||
loadPortRequired: 'Load port is required',
|
||||
total: 'Total {0} items',
|
||||
noData: 'No materials',
|
||||
noOrder: 'No work orders',
|
||||
noPort: 'Please select work order first',
|
||||
materialCode: 'Material Code',
|
||||
materialName: 'Material Name',
|
||||
bomQty: 'BOM Qty',
|
||||
useBomQty: 'Used Qty',
|
||||
planQty: 'Pending Qty',
|
||||
inputQty: 'Group Qty',
|
||||
inputQtyPlaceholder: 'Enter qty',
|
||||
unit: 'Unit',
|
||||
confirm: 'Confirm',
|
||||
submitSuccess: 'Submitted successfully',
|
||||
},
|
||||
}
|
||||
|
||||
const messages = {zh, en}
|
||||
|
||||
@@ -55,6 +55,12 @@ const routes = [
|
||||
component: () => import('@/views/FlatOutBound.vue'),
|
||||
meta: { requiresAuth: true },
|
||||
},
|
||||
{
|
||||
path: '/product-group',
|
||||
name: 'ProductGroup',
|
||||
component: () => import('@/views/ProductGroup.vue'),
|
||||
meta: { requiresAuth: true },
|
||||
},
|
||||
{
|
||||
path: '/developing',
|
||||
name: 'Developing',
|
||||
|
||||
@@ -41,9 +41,6 @@ const menuIcons = [
|
||||
'gift-o',
|
||||
'bag-o',
|
||||
'apps-o',
|
||||
'records',
|
||||
'todo-list-o',
|
||||
'records',
|
||||
]
|
||||
|
||||
const menuRoutes = {
|
||||
@@ -54,7 +51,8 @@ const menuRoutes = {
|
||||
4: '/inventory',
|
||||
5: '/bind-unbind',
|
||||
6: '/flat-outbound',
|
||||
7: '/flat-outbound',
|
||||
7: '/developing',
|
||||
8: '/product-group',
|
||||
}
|
||||
|
||||
function onMenuClick(index) {
|
||||
|
||||
408
pda/pda/src/views/ProductGroup.vue
Normal file
408
pda/pda/src/views/ProductGroup.vue
Normal file
@@ -0,0 +1,408 @@
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<van-nav-bar
|
||||
:title="t('productGroup.title')"
|
||||
left-arrow
|
||||
@click-left="router.push('/')"
|
||||
/>
|
||||
<div class="page-content">
|
||||
<van-form ref="formRef">
|
||||
<van-field
|
||||
v-model="workSectText"
|
||||
is-link
|
||||
readonly
|
||||
:label="t('productGroup.workSect')"
|
||||
:placeholder="t('productGroup.workSectPlaceholder')"
|
||||
:rules="[{ required: true, message: t('productGroup.workSectRequired') }]"
|
||||
name="workSect"
|
||||
@click="showWorkSectPicker = true"
|
||||
/>
|
||||
<van-field
|
||||
v-model="palletCode"
|
||||
:label="t('productGroup.palletCode')"
|
||||
:placeholder="t('productGroup.palletCodePlaceholder')"
|
||||
:rules="[{ required: true, message: t('productGroup.palletCodeRequired') }]"
|
||||
name="palletCode"
|
||||
clearable
|
||||
>
|
||||
<template #right-icon>
|
||||
<van-icon name="scan" class="scan-icon" @click="onScanPallet" />
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field
|
||||
v-model="workOrderText"
|
||||
is-link
|
||||
readonly
|
||||
:label="t('productGroup.workOrder')"
|
||||
:placeholder="t('productGroup.workOrderPlaceholder')"
|
||||
:rules="[{ required: true, message: t('productGroup.workOrderRequired') }]"
|
||||
name="workOrder"
|
||||
@click="onWorkOrderClick"
|
||||
/>
|
||||
<van-field
|
||||
v-model="loadPortText"
|
||||
is-link
|
||||
readonly
|
||||
:label="t('productGroup.loadPort')"
|
||||
:placeholder="t('productGroup.loadPortPlaceholder')"
|
||||
:rules="[{ required: true, message: t('productGroup.loadPortRequired') }]"
|
||||
name="loadPort"
|
||||
@click="onLoadPortClick"
|
||||
/>
|
||||
</van-form>
|
||||
|
||||
<div class="detail-section">
|
||||
<div class="detail-header">
|
||||
<span class="detail-header-text">{{ t('productGroup.total', bomList.length) }}</span>
|
||||
</div>
|
||||
<div v-if="!bomList.length" class="detail-empty">
|
||||
<van-empty :description="t('productGroup.noData')" image="search" />
|
||||
</div>
|
||||
<div v-else class="card-list">
|
||||
<div
|
||||
v-for="(item, idx) in bomList"
|
||||
:key="idx"
|
||||
class="detail-card"
|
||||
>
|
||||
<div class="card-header">
|
||||
<span class="card-index">#{{ idx + 1 }}</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-row">
|
||||
<span class="card-label">{{ t('productGroup.materialCode') }}</span>
|
||||
<span class="card-value">{{ item.MaterialCode }}</span>
|
||||
</div>
|
||||
<div class="card-row">
|
||||
<span class="card-label">{{ t('productGroup.materialName') }}</span>
|
||||
<span class="card-value">{{ item.MaterialName }}</span>
|
||||
</div>
|
||||
<div class="card-row">
|
||||
<span class="card-label">{{ t('productGroup.bomQty') }}</span>
|
||||
<span class="card-value card-value--num">{{ item.BomQty }}</span>
|
||||
</div>
|
||||
<div class="card-row">
|
||||
<span class="card-label">{{ t('productGroup.useBomQty') }}</span>
|
||||
<span class="card-value">{{ item.UseBomQty }}</span>
|
||||
</div>
|
||||
<div class="card-row">
|
||||
<span class="card-label">{{ t('productGroup.planQty') }}</span>
|
||||
<span class="card-value card-value--num">{{ item.defaultQty }}</span>
|
||||
</div>
|
||||
<div class="card-row card-row--input">
|
||||
<span class="card-label">{{ t('productGroup.inputQty') }}</span>
|
||||
<van-field
|
||||
v-model="item.inputQty"
|
||||
type="number"
|
||||
class="card-input"
|
||||
:placeholder="t('productGroup.inputQtyPlaceholder')"
|
||||
/>
|
||||
</div>
|
||||
<div class="card-row">
|
||||
<span class="card-label">{{ t('productGroup.unit') }}</span>
|
||||
<span class="card-value">{{ item.Unit }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<van-popup v-model:show="showWorkSectPicker" round position="bottom">
|
||||
<van-picker
|
||||
:columns="workSectOptions"
|
||||
@confirm="onWorkSectConfirm"
|
||||
@cancel="showWorkSectPicker = false"
|
||||
/>
|
||||
</van-popup>
|
||||
|
||||
<van-popup v-model:show="showWorkOrderPicker" round position="bottom">
|
||||
<van-picker
|
||||
:columns="workOrderOptions"
|
||||
@confirm="onWorkOrderConfirm"
|
||||
@cancel="showWorkOrderPicker = false"
|
||||
/>
|
||||
</van-popup>
|
||||
|
||||
<van-popup v-model:show="showLoadPortPicker" round position="bottom">
|
||||
<van-picker
|
||||
:columns="loadPortOptions"
|
||||
@confirm="onLoadPortConfirm"
|
||||
@cancel="showLoadPortPicker = false"
|
||||
/>
|
||||
</van-popup>
|
||||
|
||||
<BottomButton :text="t('productGroup.confirm')" :loading="submitting" @click="onSubmit" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { showToast } from 'vant'
|
||||
import { useI18n } from '@/i18n'
|
||||
import BottomButton from '@/components/BottomButton.vue'
|
||||
import request from '@/utils/request'
|
||||
|
||||
const router = useRouter()
|
||||
const { t } = useI18n()
|
||||
|
||||
const workSect = ref('')
|
||||
const workSectText = ref('')
|
||||
const palletCode = ref('')
|
||||
const selectedOrderCode = ref('')
|
||||
const workOrderText = ref('')
|
||||
const selectedLoadPort = ref('')
|
||||
const loadPortText = ref('')
|
||||
const bomList = ref([])
|
||||
const formRef = ref()
|
||||
const submitting = ref(false)
|
||||
|
||||
const orderList = ref([])
|
||||
const currentOrder = ref(null)
|
||||
|
||||
const showWorkSectPicker = ref(false)
|
||||
const showWorkOrderPicker = ref(false)
|
||||
const showLoadPortPicker = ref(false)
|
||||
|
||||
const workSectOptions = [
|
||||
{ text: 'work1', value: 'work1' },
|
||||
{ text: 'work2', value: 'work2' },
|
||||
]
|
||||
|
||||
const workOrderOptions = computed(() =>
|
||||
orderList.value.map((item) => ({
|
||||
text: item.OrderCode,
|
||||
value: item.OrderCode,
|
||||
}))
|
||||
)
|
||||
|
||||
const loadPortOptions = computed(() => {
|
||||
if (!currentOrder.value || !currentOrder.value.PortList) return []
|
||||
return currentOrder.value.PortList.map((p) => ({
|
||||
text: p.Port,
|
||||
value: p.Port,
|
||||
}))
|
||||
})
|
||||
|
||||
async function fetchWorkOrders() {
|
||||
try {
|
||||
const res = await request.get('/api/workOrder', { params: { status: 2 } })
|
||||
orderList.value = res.content || []
|
||||
} catch {
|
||||
// error handled by interceptor
|
||||
}
|
||||
}
|
||||
|
||||
function onWorkSectConfirm({ selectedOptions }) {
|
||||
const opt = selectedOptions[0]
|
||||
workSect.value = opt.value
|
||||
workSectText.value = opt.text
|
||||
showWorkSectPicker.value = false
|
||||
}
|
||||
|
||||
function onWorkOrderClick() {
|
||||
if (!workOrderOptions.value.length) {
|
||||
showToast({ message: t('productGroup.noOrder'), type: 'fail' })
|
||||
return
|
||||
}
|
||||
showWorkOrderPicker.value = true
|
||||
}
|
||||
|
||||
function onWorkOrderConfirm({ selectedOptions }) {
|
||||
const opt = selectedOptions[0]
|
||||
selectedOrderCode.value = opt.value
|
||||
workOrderText.value = opt.text
|
||||
currentOrder.value = orderList.value.find((o) => o.OrderCode === opt.value) || null
|
||||
selectedLoadPort.value = ''
|
||||
loadPortText.value = ''
|
||||
bomList.value = []
|
||||
showWorkOrderPicker.value = false
|
||||
}
|
||||
|
||||
function onLoadPortClick() {
|
||||
if (!currentOrder.value || !loadPortOptions.value.length) {
|
||||
showToast({ message: t('productGroup.noPort'), type: 'fail' })
|
||||
return
|
||||
}
|
||||
showLoadPortPicker.value = true
|
||||
}
|
||||
|
||||
function onLoadPortConfirm({ selectedOptions }) {
|
||||
const opt = selectedOptions[0]
|
||||
selectedLoadPort.value = opt.value
|
||||
loadPortText.value = opt.text
|
||||
filterBomList()
|
||||
showLoadPortPicker.value = false
|
||||
}
|
||||
|
||||
function filterBomList() {
|
||||
if (!currentOrder.value || !selectedLoadPort.value) {
|
||||
bomList.value = []
|
||||
return
|
||||
}
|
||||
const allBom = currentOrder.value.WorkOrderBomList || []
|
||||
bomList.value = allBom
|
||||
.filter((item) => item.LoadPort === selectedLoadPort.value)
|
||||
.map((item) => ({
|
||||
...item,
|
||||
defaultQty: item.BomQty - item.UseBomQty,
|
||||
inputQty: String(item.BomQty - item.UseBomQty),
|
||||
}))
|
||||
}
|
||||
|
||||
function onScanPallet() {
|
||||
palletCode.value = 'PLT' + Date.now().toString().slice(-6)
|
||||
}
|
||||
|
||||
async function onSubmit() {
|
||||
try {
|
||||
await formRef.value?.validate()
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
if (!bomList.value.length) {
|
||||
showToast({ message: t('productGroup.noData'), type: 'fail' })
|
||||
return
|
||||
}
|
||||
const bomDataList = bomList.value.map((item) => ({
|
||||
id: item.Id,
|
||||
materialCode: item.MaterialCode,
|
||||
unit: item.Unit,
|
||||
useBomQty: Number(item.inputQty) || 0,
|
||||
}))
|
||||
submitting.value = true
|
||||
try {
|
||||
const res = await request.post('/api/productGroup', {
|
||||
workSect: workSect.value,
|
||||
workOrder: selectedOrderCode.value,
|
||||
palletCode: palletCode.value,
|
||||
loadPort: selectedLoadPort.value,
|
||||
bomDataList,
|
||||
})
|
||||
showToast({
|
||||
message: t('productGroup.submitSuccess'),
|
||||
type: 'success',
|
||||
})
|
||||
workSect.value = ''
|
||||
workSectText.value = ''
|
||||
palletCode.value = ''
|
||||
selectedOrderCode.value = ''
|
||||
workOrderText.value = ''
|
||||
selectedLoadPort.value = ''
|
||||
loadPortText.value = ''
|
||||
currentOrder.value = null
|
||||
bomList.value = []
|
||||
} catch {
|
||||
// error handled by interceptor
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchWorkOrders()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.detail-section {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.detail-header-text {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.detail-empty {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.card-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.detail-card {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 12px;
|
||||
background: var(--primary-gradient);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.card-index {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.card-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 4px 0;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.card-row--input {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card-label {
|
||||
flex-shrink: 0;
|
||||
width: 80px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.card-value {
|
||||
flex: 1;
|
||||
color: #333;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.card-value--num {
|
||||
color: var(--primary-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.card-input {
|
||||
flex: 1;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.card-input :deep(.van-field__control) {
|
||||
font-size: 14px;
|
||||
color: var(--primary-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.card-input :deep(.van-field__body) {
|
||||
padding: 2px 8px;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
}
|
||||
</style>
|
||||
@@ -34,3 +34,5 @@ CREATE TABLE IF NOT EXISTS `st_ivt_purchasedtl` (
|
||||
`instock_qty` DECIMAL(18,6) DEFAULT 0 COMMENT '已入库数量'
|
||||
)COMMENT='采购入库单分录信息表';
|
||||
|
||||
ALTER TABLE `wms_nlwq`.`st_ivt_purchasemst`
|
||||
ADD COLUMN `forwardZD` tinyint(1) NULL DEFAULT 0 COMMENT '0否 1是' AFTER `audit_msg`;
|
||||
Reference in New Issue
Block a user