Easyui 实现订单拆分开票功能

Easyui 实现订单拆分开票功能

需求

1、实现一个订单开具多分发票功能;
2、支持拆行;
3、支持拆数量;

流程设计

1、操作页面展示订订单头信息,订单明细信息
2、点击新增发票按钮弹出一个弹出框用于创建一张拆分发票,弹出框可以选择商品明细输入数量。每次添加一张
3、点击弹出框的保存功能实现订单拆分
4、提交到后台之后,生成多张发票

页面设计依次如下

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

核心代码如下

<!-- 新增发票按钮-->
<span class="span_title"><a href="javascript:void(0)" style="color: red;font-weight: bold" onclick="addTicketDialog()">新增发票</a></span><!-- tablesContainer为添加发票的容器 -->
<div id="extInfoBtn" class="div_detail_margin_left_right div_button div_button_detail"><div class="div_button_title"><span id="extInfoTitle" class="spanTitleImgOpen" onClick="hideshow('extInfo','extInfoTitle','divExtInfoBtn')"/></div><div class="div_button_title"><span class="span_title">开票明细</span></div>
</div>
<div id="extInfo" class="div_detail_margin_left_right"><div style="margin-top:10px;margin-bottom:10px;"><div id="tablesContainer" ></div></div>
</div><!-- 弹出框 -->
<div id="addDialog" class="easyui-dialog" style="width:70%;height:500px" data-options="title:'拆分开票',toolbar:'#addToolbar',buttons:'#bb',modal:true,closed: true"><table class="easyui-datagrid" id="addTable" style="width:100%;height:365px;"data-options="singleSelect:true,collapsible:true,fitColumns:true"><thead><tr><th data-options="field:'id',width:80" formatter="formatOpt">操作</th><th data-options="field:'customerLineItem',width:80">项目行号</th><th data-options="field:'taxCode',width:120" formatter="formatTaxCode">税收编码</th><th data-options="field:'projectName',width:300" formatter="formatterProjectName">商品发票名称</th><th data-options="field:'model',width:120" formatter="formatterModel">发票型号</th><th data-options="field:'quantity',width:50,align:'right'">订单数量</th><th data-options="field:'thisTimeQuantity',width:50,align:'right'">本次开票数量</th><th data-options="field:'productUnit',width:50">单位</th><th data-options="field:'feeSku',width:80,align:'right'">含税单价</th><th data-options="field:'tax',width:80,align:'right'" formatter="formatterTax">税率</th><th data-options="field:'feeTotal',width:80">含税总价</th></tr></thead></table><div id="addRemark" style="padding:2px 5px;">开票栏备注: <input class="easyui-textbox" id="remark" class="remark" name="remark" style="width:90%"></div>
</div>
<div id="bb" style="font-size: 12px;"><div style="float: left">订单金额:<input id="orderAmount" class="easyui-textbox" disabled/>发票金额:<input id="invoiceAmount" class="easyui-textbox" disabled/></div><a href="javascript:void(0)" onclick="saveOne()" class="easyui-linkbutton">保存</a><a href="javascript:void(0)" class="easyui-linkbutton">关闭</a>
</div>
<div id="addToolbar" style="padding:2px 5px;font-size: 12px;">开票商品: <select class="easyui-combobox" id="addItem" style="width:300px"></select>可开票数量: <input class="easyui-numberbox" id="maxQty" disabled panelHeight="auto" style="width:110px"></input>本次开票数量: <input class="easyui-numberbox" id="quantity" name="qty" style="width:110px" data-options="min:0,precision:0"/><a href="javascript:void(0)" class="easyui-linkbutton" onclick="addRow()" iconCls="icon-add">添加</a>
</div>

js核心代码

 /*新增发票编辑窗口*/
function addTicketDialog(){endEdit();orderItems = $('#detailTable').datagrid('getRows');orderItems = orderItems.map(item => ({...item, leftQuantity: item.quantity }));// 设置值$('#addItem').combobox({valueField: 'customerLineItem',textField: 'projectName',data:orderItems,panelHeight:'auto',onSelect:handleOnSelect});$("#orderAmount").textbox('setValue',invoice.orderFee)$('#addDialog').dialog('open');
}function handleOnSelect(rec){$('#maxQty').numberbox('setValue',rec.leftQuantity);$('#quantity').numberbox({ max:rec.leftQuantity });selectedRow = rec
}/*添加行*/
function addRow(){let dg = $('#addTable');let rows = dg.datagrid('getRows');let thisTimeQuantity = $('#quantity').numberbox('getValue');if(thisTimeQuantity == null || thisTimeQuantity == 0){$.messager.alert('操作提示','请输入本次开票数量','info')return;}if(rows.some(item => item.itemId === selectedRow.itemId)){$.messager.alert('操作提示','此商品已添加,如需修改数量请删除后重新添加','info')return;}selectedRow.thisTimeQuantity = thisTimeQuantityselectedRow.thisTimeAmount = thisTimeQuantity * selectedRow.feeSkuselectedRow.leftQuantity = selectedRow.leftQuantity - thisTimeQuantity// 插入行dg.datagrid('insertRow',{index:rows.length+1,row:selectedRow});// 设置发票金额rows = dg.datagrid('getRows');let invoiceAmount = rows.reduce((acc, current) => acc + current.feeSku * current.thisTimeQuantity, 0)$("#invoiceAmount").textbox('setValue',invoiceAmount)// 更新列表展示$('#detailTable').datagrid('loadData',orderItems);
}/*删除行*/
function deleteRow(index){let dg = $('#addTable');// 从数据源中删除该行数据let dataSource = dg.datagrid('getData');let deleteOne = dataSource.rows[index]updateOrderItems(deleteOne,true);dataSource.rows.splice(index, 1);dg.datagrid('loadData', dataSource);// 重新设置formatter相关逻辑,更新索引dg.datagrid('getColumnOption', 'id').formatter = function(value, row, index){return '<a href="javascript:void(0)" οnclick="deleteRow('+index+')"><font color="blue" style="text-decoration:underline">删除</font></a> ';};$('#detailTable').datagrid('loadData',orderItems);
}function updateOrderItems(one,isAdd){let newArray = [];for(let i=0;i<orderItems.length;i++){let item = orderItems[i]if(one.itemId === item.itemId){if(isAdd){item.leftQuantity = item.leftQuantity + one.thisTimeQuantity}else{item.leftQuantity = item.leftQuantity - one.thisTimeQuantity}}newArray.push(item)}orderItems = newArray;
}/**保存一个**/
function saveOne(){let dg = $('#addTable');// 从数据源中删除该行数据let dataSource = dg.datagrid('getRows');if(dataSource === null || dataSource.length ===0){$.messager.alert('操作提示','请您添加开票明细!','info')return;}//获取数据let one = {}one.id = splitList.length;one.items = dataSourceone.remark = $('#remark').textbox('getValue');splitList.push(one);// 清除数据dg.datagrid('loadData', []);drewTables();// 清空内容$('#remark').textbox('setValue','')$('#quantity').numberbox('setValue',null)$('#addDialog').dialog('close');
}/**绘制表格**/
function drewTables(){let container = $('#tablesContainer');container.empty();if(splitList.length ===0){return;}for(let i=0;i<splitList.length;i++){let one = splitList[i];let j = i+1;let mainDivStart = '<div  id="ip-'+i+'" style="margin-bottom: 10px;border: 1px solid #cccccc;padding: 2px;">'let deleteButton = '发票'+j+' <span style="color: red;font-weight: bold;cursor: pointer" οnclick="removeInvoice('+i+')">删除此发票</span>'let table = '<table class="easyui-datagrid" id="ip-table-'+i+'" style="width:100%;" data-options="singleSelect:true,collapsible:true,fitColumns:true">'+       '<thead>'+       '<tr>'+       '<th data-options="field:\'customerLineItem\',width:80">项目行号</th>'+   '<th data-options="field:\'skuCodeProj\',width:150">项目商品编码</th>'+   '<th data-options="field:\'skuNameProj\',width:300">商品名称</th>'+   '<th data-options="field:\'specificationInvoice\',width:120">商品型号</th>'+   '<th data-options="field:\'taxCode\',width:120" formatter="formatTaxCode">税收编码</th>'+   '<th data-options="field:\'projectName\',width:300" formatter="formatterProjectName">商品发票名称</th>'+   '<th data-options="field:\'model\',width:120" formatter="formatterModel">发票型号</th>'+   '<th data-options="field:\'thisTimeQuantity\',width:50,align:\'right\'">数量</th>'+   '<th data-options="field:\'productUnit\',width:50">单位</th>'+   '<th data-options="field:\'feeSku\',width:80,align:\'right\'">含税单价</th>'+   '<th data-options="field:\'tax\',width:80,align:\'right\'" formatter="formatterTax">税率</th>'+   '<th data-options="field:\'thisTimeAmount\',width:80">含税总价</th>'+'</tr>'+'</thead>'+'</table>'let remark = '<div style="padding:2px 5px;">开票栏备注: <input class="easyui-textbox" class="remark" disabled name="remark" value="'+one.remark+'" style="width:90%"></div>'let mainDivEnd = '</div>'let $allHtml = mainDivStart + deleteButton + table + remark + mainDivEndcontainer.append($allHtml);let oneTable = $('#ip-table-' + i);oneTable.datagrid({ data:one.items });}
}function removeInvoice(index){// 删除元素$.messager.confirm('删除提示', '您确认要删除此发票吗?', function(r){if (r){splitList.splice(index, 1);let newArray = []for(let i=0;i<splitList.length;i++){let one = splitList[i];one.id = inewArray.push(one)}splitList = newArray;//重新渲染drewTables();}});}function endEdit(){// 取消编辑if (lastIndex !== null) {$('#detailTable').datagrid('endEdit', lastIndex);lastIndex = null;}
}

总结

此方案的优势就是在单独弹出框处理拆分,然后动态的渲染表格,新增一个表格然后再表格中进行行编辑要简单许多

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/887503.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux中的“块”是什么

在Linux系统中&#xff0c;块&#xff08;block&#xff09;是文件系统存储数据的基本单位&#xff0c;以下是关于Linux中块的概念和使用场景的详细解释&#xff1a; 一、块的概念 定义&#xff1a;块是多个连续性的扇区&#xff08;sector&#xff09;组成&#xff0c;扇区是…

解决 java -jar 报错:xxx.jar 中没有主清单属性

问题复现 在使用 java -jar xxx.jar 命令运行 Java 应用程序时&#xff0c;遇到了以下错误&#xff1a; xxx.jar 中没有主清单属性这个错误表示 JAR 文件缺少必要的启动信息&#xff0c;Java 虚拟机无法找到应用程序的入口点。本文将介绍该错误的原因以及如何通过修改 pom.xm…

推荐一款龙迅HDMI2.0转LVDS芯片 LT6211UX LT6211UXC

龙迅的HDMI2.0转LVDS芯片LT6211UX和LT6211UXC是两款高性能的转换器芯片&#xff0c;它们在功能和应用上有所差异&#xff0c;同时也存在一些共同点。以下是对这两款芯片的详细比较和分析&#xff1a; 一、LT6211UX 主要特性&#xff1a; HDMI2.0至LVDS和MIPI转换器。HDMI2.0输…

flink学习(7)——window

概述 窗口的长度(大小): 决定了要计算最近多长时间的数据 窗口的间隔: 决定了每隔多久计算一次 举例&#xff1a;每隔10min,计算最近24h的热搜词&#xff0c;24小时是长度&#xff0c;每隔10分钟是间隔。 窗口的分类 1、根据window前是否调用keyBy分为键控窗口和非键控窗口…

C语言解析命令行参数

原文地址&#xff1a;C语言解析命令行参数 – 无敌牛 欢迎参观我的个人博客&#xff1a;无敌牛 – 技术/著作/典籍/分享等 C语言有一个 getopt 函数&#xff0c;可以对命令行进行解析&#xff0c;下面给出一个示例&#xff0c;用的时候可以直接copy过去修改&#xff0c;很方便…

深入解析 ArrayList 源码:从动态扩容到高效存取的秘密

全文目录&#xff1a; 开篇语目录&#x1f31f; 前言&#x1f9e9; ArrayList 概述&#x1f3d7;️ ArrayList 的底层实现&#x1f4d0; 构造函数详解&#x1f3d7;️ 数组的动态扩容机制 ⚙️ 核心方法源码解析➕ add() 方法的实现➖ remove() 方法的实现&#x1f50d; get() …

Amazon AWS公司介绍

Amazon Web Services&#xff08;AWS&#xff09;是亚马逊公司&#xff08;Amazon&#xff09;的子公司&#xff0c;提供广泛的云计算服务&#xff0c;包括弹性计算、存储解决方案、数据库服务、机器学习、物联网&#xff08;IoT&#xff09;和企业应用等。以下是AWS的一些关键…

精密工装夹具加工:打造高精度产品

在现代制造业中&#xff0c;精密工装夹具加工扮演着关键角色&#xff0c;是打造高精度产品不可缺少的环节。 精密工装夹具的设计与制造&#xff0c;首先依赖于对加工工艺的深入理解与精准把握。工程师们需要根据待加工产品的形状、尺寸、精度要求以及加工设备的特性&#xff0c…

使用client-go在命令空间test里面对pod进行操作

目录 一、获取使用restApi调用的token信息 二、client-go操作pod示例 1、获取到客户端 2、创建pod 3、获取test命令空间的所有pod 4、获取某个具体pod的详细信息 5、更新pod 6、删除pod 三、总结 官方参考地址&#xff1a;https://kubernetes.io/docs/reference/kuber…

C++ 优先算法 —— 无重复字符的最长子串(滑动窗口)

目录 题目&#xff1a; 无重复字符的最长子串 1. 题目解析 2. 算法原理 Ⅰ. 暴力枚举 Ⅱ. 滑动窗口&#xff08;同向双指针&#xff09; 3. 代码实现 Ⅰ. 暴力枚举 Ⅱ. 滑动窗口 题目&#xff1a; 无重复字符的最长子串 1. 题目解析 题目截图&#xff1a; 此题所说的…

huggingface使用

import warnings warnings.filterwarnings("ignore") from transformers import pipeline#用人家设计好的流程完成一些简单的任务 classifier pipeline("sentiment-analysis") classifier( [ "Ive been waiting for a HuggingFace cours…

qt 读写文本、xml文件

写txt文件 QString fileName ui->lineEdit->text(); QString fileContent ui->textEdit->toPlainText(); qDebug()<<"test:"<<fileContent; QFile file(fileName); if(!file.open(QFile::WriteOnly|QFile::Text)) { …

第六届机器人、智能控制与人工智能国际(RICAI 2024)

会议信息 会议时间与地点&#xff1a;2024年12月6-8日&#xff0c;中国南京 会议官网&#xff1a;www.ic-ricai.org &#xff08;点击了解大会参会等详细内容&#xff09; 会议简介 第六届机器人、智能控制与人工智能国际学术会议&#xff08;RICAI 2024&#xff09;将于20…

【设计模式】创建型模式之单例模式(饿汉式 懒汉式 Golang实现)

定义 一个类只允许创建一个对象或实例&#xff0c;而且自行实例化并向整个系统提供该实例&#xff0c;这个类就是一个单例类&#xff0c;它提供全局访问的方法。这种设计模式叫单例设计模式&#xff0c;简称单例模式。 单例模式的要点&#xff1a; 某个类只能有一个实例必须…

C++11特性(详解)

目录 1.C11简介 2.列表初始化 3.声明 1.auto 2.decltype 3.nullptr 4.范围for循环 5.智能指针 6.STL的一些变化 7.右值引用和移动语义 1.左值引用和右值引用 2.左值引用和右值引用的比较 3.右值引用的使用场景和意义 4.右值引用引用左值及其一些更深入的使用场景分…

C++-右值引用和移动构造

目录 1. 两种引用方式: 1.1 左值引用&#xff1a; 1.2右值引用 1.3如何判断左右值&#xff1a; 1.4左值引用与右值引用比较 2. 浅拷贝、深拷贝 3.1右值引用的意义&#xff1a; 函数参数传递 函数返还值传递 万能引用 引用折叠 完美转发 std::forward &#x1f33c;&…

React-useState的使用

useState 是 React 提供的一个 Hook&#xff0c;允许你在函数组件中添加和管理状态&#xff08;state&#xff09;。在类组件中&#xff0c;状态管理通常是通过 this.state 和 this.setState 来实现的&#xff0c;而在函数组件中&#xff0c;useState 提供了类似的功能。 基本…

嵌入式硬件设计:从概念到实现的全流程

嵌入式硬件设计是现代电子技术中一个至关重要的领域&#xff0c;涉及从硬件架构设计到硬件调试的各个方面。它为我们日常生活中的各类智能设备、家电、工业控制系统等提供了强大的支持。本文将介绍嵌入式硬件设计的基本流程、关键技术、常用工具以及常见的挑战和解决方案&#…

新能源汽车充电插口类型识别-YOLO标记,可识别Type1,ccs2的充电标准

前言: CCS标准定义的Type-2 CCS汽车充电端口&#xff0c;右侧装有直流充电枪的插头。汽车的充电端口设计巧妙地将交流部分&#xff08;上半部分&#xff09;与直流部分&#xff08;下半部分的两个粗大的接口&#xff09;集于一体。在交流和直流充电过程中&#xff0c;电动汽车…

Pytest使用Jpype调用jar包报错:Windows fatal exception: access violation

问题描述 ​   之前我们有讲过如何使用Jpype调用jar包&#xff0c;在成功调用jar包后&#xff0c;接着在Pytest框架下编写自动测试用例。但是在Pytest下使用Jpype加载jar包&#xff0c;并调用其中的方法会以下提示信息&#xff1a; ​   虽然提示信息显示有Windows显示致命…