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,一经查实,立即删除!

相关文章

解决 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;很方便…

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

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

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…

第六届机器人、智能控制与人工智能国际(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;&…

新能源汽车充电插口类型识别-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显示致命…

Netty基本原理

目录 前言 原生NIO VS Netty 原生NIO存在的问题 Netty的优点 线程模型 传统阻塞 I/O (Blocking I/O) 2. 非阻塞 I/O (Non-blocking I/O) 3. 多路复用 I/O (Multiplexed I/O) 4. Reactor 模式 常见的 Reactor 模式的变体&#xff1a; Netty线程模型 工作原理 前言 N…

MySQL系列之数据类型(Numeric)

导览 前言一、数值类型综述二、数值类型详解1. NUMERIC1.1 UNSIGNED或SIGNED1.2 数据类型划分 2. Integer类型取值和存储要求3. Fixed-Point类型取值和存储要求4. Floating-Point类型取值和存储要求 结语精彩回放 前言 MySQL系列最近三篇均关注了和我们日常工作或学习密切相关…

一学就废|Python基础碎片,格式化F-string

Python 3.6 中引入了 f-string语法&#xff0c;提供了一种简洁直观的方法来将表达式和变量直接嵌入到字符串中进行字符串格式化&#xff0c;f -string背后的想法是使字符串插值更简单。 要创建 f -string&#xff0c;在字符串前加上字母 “f”即可&#xff0c;与字符串本身的格…

在 Mac(ARM 架构)上安装 JDK 8 环境

文章目录 步骤 1&#xff1a;检查系统版本步骤 2&#xff1a;下载支持 ARM 的 JDK 8步骤 3&#xff1a;安装 JDK步骤 4&#xff1a;配置环境变量步骤 5&#xff1a;验证安装步骤 6&#xff1a;注意事项步骤7&#xff1a;查看Java的安装路径 在 Mac&#xff08;ARM 架构&#xf…

【AI绘画】Midjourney进阶:色调详解(上)

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AI绘画 | Midjourney 文章目录 &#x1f4af;前言&#x1f4af;Midjourney中的色彩控制为什么要控制色彩&#xff1f;为什么要在Midjourney中控制色彩&#xff1f; &#x1f4af;色调白色调淡色调明色调 &#x1f4af…

【C++】LeetCode:LCR 023. 相交链表

题干 LCR 023. 相交链表 的头节点 headA 和 headB &#xff0c;请找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;函数返回结果…

【Linux学习】【Ubuntu入门】2-5 shell脚本入门

1.shell脚本就是将连续执行的命令携程一个文件 2.第一个shell脚本写法 shell脚本是个纯文本文件&#xff0c;命令从上而下&#xff0c;一行一行开始执行&#xff0c;其扩展名为.sh&#xff0c;shell脚本第一行一定要为&#xff1a;#!/bin/bash&#xff0c;表示使用bash。echo…