公司产品项目,使用的架构是比较老的,使用打印插件工具是OCX,这个局限性比较大,只能使用IE浏览器,连EDGE浏览器都不支持,并且需要调整IE浏览器的安全配置。
基于以上的原因,项目决定更换打印的模式,使用html模板,研发进行编写模板。js的赋值处理,不需要重复编写,需要写的通用。主要js如下:
<script type="text/javascript">
/*
//step0 之前获取数据的,现在数据从参数中获取。以后的数据都是直接传递的
EtcomWebAjax(getMessage, 222, 2, formData($("#list")), function(data) {
}, function() {
});
console.log(digitUppercase(-109.41))
console.log(digitUppercase(200.55))
console.log(digitUppercase(87))
//console.log(execMathExpress("20.1+0.88*5"))
//console.log(execMathExpress("20.1"))
//console.log(test("22+11"))
//console.log(test("11.88/aa"))
console.log(execMathExpress("20.1"))
*/
$(function() {
//step1 准备使用浏览器的打印,前提已经引入jquery.jqprint-0.3.js。准备工作,用到的所有通用函数都在:yem.js中
jQuery.browser={};
(function(){
jQuery.browser.msie=false;
jQuery.browser.version=0;
if(navigator.userAgent.match(/MSIE ([0-9]+)./)){
jQuery.browser.msie=true;
jQuery.browser.version=RegExp.$1;
}
})();
//console.log($(".mfee1*mfee2"))
//step2 接收传递过来的数据
var printData = getUrlParam('printData');
data = printData;
data={mfee1:10.8,mfee2:0.88};
//step3 处理打印数据,如果数据为空进行提示,不为空,处理数据,执行进行打印
if (data != "" && data != null && data != undefined && data != "null" ) {
//step4 处理页面中所有的h5标签的class。
for(var i=0; i<$("#list h5").length; i++){
var classAttr="";
var classAttr2="";
var classNum="";
var bigFlag = false;//是否大写
var orFlag = false;//数据中是否存在
var timeFlag = false;//是否是固定的时间规则
var classObj = null;
classAttr = $.trim($($("#list h5")[i]).attr("class"));
classObj = $($("#list h5")[i])
//step4.5 处理几个固定的规则,时间和非数据库数据
if(classAttr==""){//规则之一如果是空的,则未绑定数据库数据
continue;
}
//规则之一如果是sysdatetime 当前时间yyyy-mm-dd hh:nn:ss、sysdate yyyy-mm-dd、systime hh:nn:ss
//sysyear yyyy、sysmonth mm 、sysday dd
var nowtime = new Date();
var year = nowtime.getFullYear();
var month = padleft0(nowtime.getMonth() + 1);
var day = padleft0(nowtime.getDate());
var hour = padleft0(nowtime.getHours());
var minute = padleft0(nowtime.getMinutes());
var second = padleft0(nowtime.getSeconds());
if(classAttr=="sysdatetime"){
timeFlag = true;
classNum = year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
}else if(classAttr=="sysdate"){
timeFlag = true;
classNum = year + "-" + month + "-" + day;
}else if(classAttr=="systime"){
timeFlag = true;
classNum = hour+":"+minute+":"+second;
}else if(classAttr=="sysyear"){
timeFlag = true;
classNum = year;
}else if(classAttr=="sysmonth"){
timeFlag = true;
classNum = month;
}else if(classAttr=="sysday"){
timeFlag = true;
classNum = day;
}
if(timeFlag){
var html = $("." + classAttr).html();
$("." + classAttr).html(html + " " + classNum);
continue;
}
//step5 首先判断class中是否存在大写标识,如果存在标识,最后要将计算好的数字进行大写转换。
if(classAttr.indexOf("^")>-1){
bigFlag=true;
//如果存在要将大写标识去除掉
classAttr2 = classAttr.replace("^","");
}else{
classAttr2 = classAttr;
bigFlag=false;
}
//step6 替换class中匹配结果集中的每一个字段。即:mfee1+mfee2 替换成 20.1+0.8
for ( var key in data) {
if(classAttr2.indexOf(key)>-1){
if(classAttr2.indexOf(key.toString())==0){
//防止某个字段包含另外一个字段,所以替换之前要判断该信息的前后必须是空或者是运算符
var lastStr = classAttr2.substr(key.toString().length,classAttr2.length-1);
if(lastStr=="" || lastStr.indexOf("+")==0 || lastStr.indexOf("-")==0 || lastStr.indexOf("*")==0 || lastStr.indexOf("/")==0){
classAttr2 = classAttr2.replace(key.toString(),data[key].toString());
}
}else{
var preStr = classAttr2.substr(0,classAttr2.indexOf(key.toString()));
var lastStr = classAttr2.substr(classAttr2.indexOf(key.toString())+key.toString().length,classAttr2.length-1);
if((lastStr=="" || lastStr.indexOf("+")==0 || lastStr.indexOf("-")==0 || lastStr.indexOf("*")==0 || lastStr.indexOf("/")==0)
&& (preStr=="" || preStr.indexOf("+")==preStr.length-1 || preStr.indexOf("-")==preStr.length-1 || preStr.indexOf("*")==preStr.length-1 || preStr.indexOf("/")==preStr.length-1)){
classAttr2 = classAttr2.replace(key.toString(),data[key].toString());
}
}
}
}
//step7 得到最后的计算表达式,先进行判断是否可以进行运算,然后进行解析四则运算
if(test(classAttr2)){
var returnRes = execMathExpress(classAttr2);
classNum = accDivCoupon(returnRes["num"],returnRes["den"])
//如果大写则进行大写
if(bigFlag){
classNum = digitUppercase(classNum)
}
}
//step8 赋值页面内容。
var html = classObj.html();
classObj.html(html + " " + classNum);
}
//$(".money").html($(".money").html()+" "+data["mtotal"] + " 元")
}
$("#print").jqprint();
})
function print(){
$("#print").jqprint();
}
</script>
其中比较重要的几个方法:
1、准备工作几乎是必须的,js文件要引入;
2、getUrlParam获取url中参数的方法;
3、padleft0补全方法;
4、execMathExpress解析四则运算的方法;
5、accDivCoupon 除法,加减乘等方法;
6、digitUppercase将数据转成大写方法;
7、$("#print").jqprint(); 直接打印方法;
8、主要的验证是否可以进行四则运算的方法,test(classAttr2)
主要的方法js如下:
//获取url中的参数
function getUrlParam(name){
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
var r = window.location.search.substr(1).match(reg); //匹配目标参数
if (r != null) return unescape(r[2]); return null; //返回参数值
}
/**
* 将数字转换成人民币大写的方法
*/
function digitUppercase (n) {
var fraction = ['角', '分'];
var digit = [
'零', '壹', '贰', '叁', '肆',
'伍', '陆', '柒', '捌', '玖'
];
var unit = [
['元', '万', '亿'],
['', '拾', '佰', '仟']
];
var IsNum = Number(n);
if (!isNaN(IsNum)) {
var head = n < 0 ? '(负)' : '';
n = Math.abs(n);
var s = '';
for (var i = 0; i < fraction.length; i++) {
s += (digit[Math.floor(n * 100/10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, '');
}
s = s || '整';
n = Math.floor(n);
for (var i = 0; i < unit[0].length && n > 0; i++) {
var p = '';
for (var j = 0; j < unit[1].length && n > 0; j++) {
p = digit[n % 10] + unit[1][j] + p;
n = Math.floor(n / 10);
}
s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s;
}
return head + s.replace(/(零.)*零元/, '元')
.replace(/(零.)+/g, '零')
.replace(/^整$/, '零元整');
}
else {
return "";
}
};
/**
* 加法
* @param arg1
* @param arg2
* @returns
*/
function accAdd(arg1,arg2){
var r1,r2,m;
try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0};
try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0};
m=Math.pow(10,Math.max(r1,r2));
return (arg1*m+arg2*m)/m;
}
/**
* 减法
* @param arg1
* @param arg2
* @returns
*/
function accSubtr(arg1,arg2){
var r1,r2,m,n;
try{r1=arg1.toString().split(".")[1].length;}catch(e){r1=0;}
try{r2=arg2.toString().split(".")[1].length;}catch(e){r2=0;}
m=Math.pow(10,Math.max(r1,r2));
//动态控制精度长度
n=(r1>=r2)?r1:r2;
return ((arg1*m-arg2*m)/m).toFixed(n);
}
/***
* 乘法,获取精确乘法的结果值
* @param arg1
* @param arg2
* @returns
*/
function accMul(arg1,arg2)
{
var m=0,s1=arg1.toString(),s2=arg2.toString();
try{m+=s1.split(".")[1].length}catch(e){};
try{m+=s2.split(".")[1].length}catch(e){};
return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m);
}
/***
* 除法,获取精确乘法的结果值
* @param arg1
* @param arg2
* @returns
*/
function accDivCoupon(arg1,arg2){
var t1=0,t2=0,r1,r2;
try{t1=arg1.toString().split(".")[1].length;}catch(e){}
try{t2=arg2.toString().split(".")[1].length;}catch(e){}
with(Math){
r1=Number(arg1.toString().replace(".",""));
r2=Number(arg2.toString().replace(".",""));
return (r1/r2)*pow(10,t2-t1);
}
}
/***
* 判断是否可以做四则运算。
*/
function test(s){
var reg=/[\d\.\+\-\*\/\(\)]+/;
try{
return reg.test(s)&&!isNaN(eval("("+s+")"));
}catch(e){
return false;
}
}
//欧几里得算法 求两个数a、b的最大公约数
function gcd(a,b){
return b===0?a:gcd(b,a%b)
}
//分数类 分子,分母
class Fraction{
static create(num,den=1) {
if(num instanceof Fraction){
return num;
}else if(/(-?\d+)\/(\d+)/.test(num)){
return new Fraction(parseInt(RegExp.$1),parseInt(RegExp.$2))
}else{
if(/\.(\d+)/.test(num)){
num=num*Math.pow(10,RegExp.$1.length);
den=den*Math.pow(10,RegExp.$1.length);
}
if(/\.(\d+)/.test(den)){
num=num*Math.pow(10,RegExp.$1.length);
den=den*Math.pow(10,RegExp.$1.length);
}
return new Fraction(num,den)
}
}
constructor(num=0,den=1){
if(den<0){
num=-num;
den=-den;
}
if(den===0){
throw '分母不能为0'
}
let g=gcd(Math.abs(num),den)
this.num=num/g;
this.den=den/g;
}
//加
add(o){
return new Fraction(this.num*o.den+this.den*o.num,this.den*o.den)
}
//减
sub(o){
return new Fraction(this.num*o.den-this.den*o.num,this.den*o.den)
}
//乘
multiply(o){
return new Fraction(this.num*o.num,this.den*o.den);
}
//除
divide(o){
return new Fraction(this.num*o.den,this.den*o.num);
}
//小于
lessThan(o){
return this.num*o.den<this.den*o.num;
}
//等于
equal(o){
return this.num*o.den===this.den*o.num;
}
toString() {
return this.num+'/'+this.den;
}
}
//解析数学表达式
function execMathExpress(formula,obj){
//局部变量
const tempObj=Object.assign({
_0:0
},obj);
//计算缓存
const keyCache={};
let index=1;
formula=formula.replace(/ /g,'');//清理空格
//解析数字
formula=formula.replace(/(^|[(*+/-])(\d+\.\d+|\d+)/g,function (m,p1,p2) {
if(keyCache[p2]){
return p1+keyCache[p2];
}
const key=keyCache[p2]='_'+index++;
tempObj[key]=Fraction.create(p2);
return p1+key;
})
function getKey(p1,p2,p3) {
const keyC=p1+p2+p3;
if(keyCache[keyC]){
return keyCache[keyC];
}
const key=keyCache[keyC]='_'+index++;
const fA=Fraction.create(tempObj[p1])
const fB=Fraction.create(tempObj[p3])
if(p2==='*'){
tempObj[key]=fA.multiply(fB);
}else if(p2==='/'){
tempObj[key]=fA.divide(fB);
}else if(p2==='+'){
tempObj[key]=fA.add(fB);
}else if(p2==='-'){
tempObj[key]=fA.sub(fB);
}
return key;
}
function run(s) {
//子表达式
if(/\(([^\(]+?)\)/.test(s)){
s=s.replace(/\(([^\(]+?)\)/g,function (m,p1,p2) {
return run(p1);
})
}
//负号
s=s.replace(/([*/+]|^)-(\w+)/g,function (m,p1,p2) {
return getKey('_0','-',p2);
})
//返回
if(/(^\w+$)/.test(s)){
return RegExp.$1;
}
//乘法、除法、加法、减法
const expArr=['*','/','+','-'];
for(let i=0;i<expArr.length;i++){
const p=expArr[i];
const reg=new RegExp('(\\w+)['+p+'](\\w+)');
while (reg.test(s)){
s=s.replace(reg,function (m,p1,p2) {
return getKey(p1,p,p2);
})
}
}
//返回
if(/(^\w+$)/.test(s)){
return RegExp.$1;
}
return run(s);
}
return tempObj[run(formula)]
}
//module.exports=execMathExpress;
附带模板html文件和配置的通用方法的js文件:
链接: https://pan.baidu.com/s/1Y2RJZQLxkSI83yHlkNAeVQ 提取码: 66m7 复制这段内容后打开百度网盘手机App,操作更方便哦
–来自百度网盘超级会员v3的分享
总结:
1、使用 ( " . m f e e 1 " ) 这 个 j q 的 获 取 对 象 的 时 候 , 是 不 允 许 的 , 最 后 处 理 : 使 用 的 是 档 期 要 赋 值 的 (".^mfee1")这个jq的获取对象的时候,是不允许的,最后处理:使用的是档期要赋值的 (".mfee1")这个jq的获取对象的时候,是不允许的,最后处理:使用的是档期要赋值的("#list h5")中的某一个对象。
2、注意处理,mfee12 等包含字段的情况。也就是说,if indexOf 是>-1.的 防止某个字段包含另外一个字段,所以替换之前要判断该信息的前后必须是空或者是运算符。
3、参数的printData的获取需要调整很多使用的页面的传值的方法,或者使用中间的一个页面去获取数据再传递。
**4、最后解析四则运算的方法,最后的结果是一个num den 的数组。计算结果=num/den **
5、shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
最后附带参考的文章地址:
Js简单判断四则运算是否可用 https://www.iteye.com/blog/zzc1684-2003167 https://blog.csdn.net/zzc1684/article/details/84519582
js解析数学运算公式 https://www.cnblogs.com/caoke/p/11053253.html 最后使用的是这个。
https://blog.csdn.net/wcqwert/article/details/103166690 这个解析没有测试
https://www.cnblogs.com/liuyihao1456/articles/5658547.html 这个解析存在问题 getResult方法不存在,如果能写出这个方法,或者找到这个方法,这个也可以用。但是对于小数不友好
js 中加减乘除 比较精确的算法,js本身有些运算会出错,这里给出较精确的算法
https://blog.csdn.net/yucaifu1989/article/details/22670253
https://www.cnblogs.com/rockyan/p/10196640.html
js 将数字转换成人民币大写的方法 https://www.cnblogs.com/wangfuyou/p/7426472.html