本文主要是介绍教你怎么用程序代码开发Excel功能,搞定办公室小姐姐--将handsontable控件整合进自己一直开发完成的WEB进销存系统的心得体会(走了不少弯路,值得大家借鉴),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
大家好,我是诚一
几天前,一家使用我的进销存系统10年的客户找到我,想让我给他们系统增加类似于Excel表格的配方表管理子功能。
老客户有需求那还有什么好说的,立马答应下来并着手准备开工做。
一顿资料搜索后发现handsontable控件可以实现这样的需求,于是进一步阅读官网资料(全英文)并上网查找handsontable控件的相关文章。
废话少说,进入正题:
一、上github下载控件文件包
https://github.com/handsontable/handsontable
二、复制所需要的相关文件
1、解压后打开 dist 文件夹将文件handsontable.full.min.css复制到自己项目的css目录中,将handsontable.full.min.js文件复制到项目的js目录中。
2、将 languages文件夹中 zh-CN.js(如果希望菜单使用其他语言则复制对应语言文件,本例为简体中文)文件复制到js目录中。
3、将 test\lib 文件夹中 jquery.min.js 文件
在项目的js目录新建common.js和excel.js文件,此时js目录内容如下
4、在css目录中新建 handsontable.formula.css 文件,用于设置 formula 效果的样式
三、开始写代码(本项目后端使用的是asp开发语言用于读默认excel表格和保存表格,前端使用html,数据库为access,也可很方便自行改为其他类型数据库)
1、新建index.html文件,文件内容如下
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Handsontable简易样例程序</title>
<link rel="stylesheet" href="css/handsontable.full.min.css" />
<link rel="stylesheet" href="css/handsontable.formula.css" />
<script language="javascript" type="text/javascript" src="js/jquery.min.js"></script>
<script src="js/handsontable.full.min.js" type="text/javascript" language="javascript"></script>
<script src="js/zh-CN.js" type="text/javascript" language="javascript"></script>
<script src="js/common.js" type="text/javascript" language="javascript"></script>
<script src="js/excel.js" type="text/javascript" language="javascript"></script>
</head>
<body>
<div id="exceltable"></div>
<br />
<input type="button" class="button" id="btnSave" value="保存" />
</body>
</html>
我建的index.html文件为utf-8编码,如果不是些编码请将第 10 行改为以下内容(增加 charset="utf-8"),否则右键菜单将出现乱码。
<script src="js/zh-CN.js" type="text/javascript" language="javascript" charset="utf-8"></script>
2、修改css/handsontable.formula.css文件,内容如下
formula为公式正常记算后的单元格样式,formula-error为公式计算出错或单元格数据类型错误时样式。
td.formula {background-color:#d7d765;
}
td.formula-error {background-color:#d65e5e;color:white;
}
3、编写js/excel.js文件内容如下
var hot,formulaDatas;
var queryFirst,queryPrice,querySoft,queryHard,queryCost,queryBase;
let upValues=[];
var firstVal="物料",priceVal="一箱价格",softVal="软支",hardVal="硬支",costVal="单价",baseVal="基料",opsucess="操作成功",operror="操作失败";;
var btnSave,contextmenu,action;
contextmenu=true;//显示全部右键菜单
//也可使用 ["row_above", "row_below", "undo", "redo"]; 设置自定义菜单//判断是否为空
function isEmpty(s)
{if (s == null || s=="undefined" || s.length == 0)return true;return !/\S/.test(s);
}
//通过特定文字找到单元格
function SearchKey(val)
{var search = hot.getPlugin("search");return search.query(val);
}function CheckWuliaoIsAtFirst()
{var chk=false,query=queryFirst;if(!isEmpty(queryFirst)){if(query.length>0){if(query[0].row==0&&query[0].col==0){chk=true;}else{alert("第1行第1列必须为[物料]");return false; }}else{alert("第1行第1列必须为[物料]");return false;}}return chk;
}function CheckSoftOrHard()
{var newSoftVal,newHardVal;newSoftVal=querySoft;newHardVal=queryHard;if(isEmpty(newSoftVal)||isEmpty(newHardVal)){alert("没有软支或硬支一箱价");return false;}else{return true;}
}
//根据第一列选中的物料ID更新单价
function ChangeSelect(row,value,atOnce)
{var newAry=FindAry(value,formulaDatas);if(newAry!=-1){var query=queryCost;var newVal=newAry[1];var newVal2=newAry[2];if(query.length>0){var col=query[0].col;if(atOnce){hot.setDataAtCell(row,col,newVal);}else{upValues.push(new Array(row,col,newVal));}//更新基料列col=queryBase[0].col;var celData=hot.getDataAtCell(row,col);if(isEmpty(celData))//为空则更新基料列{if(atOnce){hot.setDataAtCell(row,col,newVal2);}else{upValues.push(new Array(row,col,newVal));}}}else{if(atOnce){hot.setDataAtCell(row,1,newVal2);hot.setDataAtCell(row,2,newVal);}else{upValues.push(new Array(row,1,newVal));upValues.push(new Array(row,1,newVal));}}}
}function UpdatePrice(atOnce)
{var firstCol=hot.getDataAtCol(0);for(var i=1;i<firstCol.length;i++){var celVal=firstCol[i];if(!isEmpty(celVal)){if(celVal.length>0){ChangeSelect(i,celVal,atOnce);}}}if(!atOnce){hot.batchRender(() =>{for(var i=0;i<upValues.length;i++){hot.setDataAtCell(upValues[i][0],upValues[i][1],upValues[i][2]);}});upValues.length=0;}
}function FindAry(target,array)
{if(!isEmpty(array)){var i,j;for(i=0;i<array.length;i++){for(j=0;j<array[0].length;j++){if(array[i][j]==target){return array[i];}}}}return -1;
}function GetData()
{var paraData="action="+action;$.ajax({type: "POST",url: "handler.asp",timeout: 10000,data:paraData,cache:false,dataType:"html",success:function(res){},complete:function(res){var result=res.responseText;if(result.indexOf("[[")>=0){var datas=result.split("$$$"),data1;if(isEmpty(datas[0])||datas[0].length<10)//如果是空{data1=Handsontable.helper.createSpreadsheetData(32,16);//创建一个32行16列的空表}else{data1=JSON.parse(datas[0]);}var Columns;if(datas[1].length>2){Columns=eval("("+datas[1]+")");//Columns=JSON.parse(datas[1]);//因为返回的是嵌套JSON不能使用JSON.parse转换}if(datas[2].length>2){formulaDatas=JSON.parse(datas[2]);//与第一列联动的名称和单价数组}var exceltable = document.getElementById("exceltable");hot = new Handsontable(exceltable,{data:data1,//表格中的数据项colHeaders: true,//当值为true时显示列头,当值为数组时,列头为数组的值rowHeaders: true,//当值为true时显示行头,当值为数组时,行头为数组的值contextMenu:contextmenu,//右键菜单manualColumnResize: true,//调整列大小allowInsertRow: true,//允许插入行allowInsertColumn: true,//允许插入列fillHandle:true,//当值为true时,允许拖动单元格右下角,将其值自动填充到选中的单元格search:true,//查询单元格的值 查询单元格的值需要3个步骤:a.设置hot的属性search为true b.创建比对函数 c.渲染比对结果columns:Columns,//列设置fixedRowsTop:1,//固定第一行fillHandle:true,//拖动单元格时自动增加新行language:"zh-CN",//中文licenseKey:"6f673-f83c5-43005-a9f45-ecab9",//授权码formulas:true,//使用公式afterChange:function(changes,source){if (source === "edit"){changes.forEach(function (item){var row = item[0],col = item[1],prevValue = item[2],value = item[3];if(col==0&&prevValue!== value)//改变的是第1列{ChangeSelect(row,value,true);}});}},afterUpdateSettings:function(){queryFirst=SearchKey(firstVal);queryPrice=SearchKey(priceVal);querySoft=SearchKey(softVal);queryHard=SearchKey(hardVal);queryCost=SearchKey(costVal);queryBase=SearchKey(baseVal);UpdatePrice(false);}});if(!hot.isEmptyRow(0))//第一行不为空{//设置只读 非编辑基础模板时要设置下hot.updateSettings({cells:function (row,col,prop){var cellProperties = {};if(row==0){//0行if(col==0||col==1||col==3){cellProperties.readOnly = true;}}else if(row==22&&col==5){cellProperties.readOnly = true; }else if(row==17){if(col==8||col==9){cellProperties.readOnly = true;}}else if(col==3){cellProperties.readOnly = true;}//格式化公式var instance=this.instance;var value=instance.getSourceDataAtCell(row,col);//好象不能取到原始公式数据if(!isEmpty(value)){if(value[0]=="=")//公式{if(isEmpty(cellProperties.className)){cellProperties.className = "formula";}else{cellProperties.className = cellProperties.className+" formula";}cellProperties.type="numeric";//必须设置type为numeric才会格式化cellProperties.numericFormat={pattern:"0.00"};cellProperties.correctFormat=true;}}return cellProperties;}});}}}, error: function(e){}})
}function SaveData()
{queryFirst=SearchKey(firstVal);queryPrice=SearchKey(priceVal);querySoft=SearchKey(softVal);queryHard=SearchKey(hardVal);queryCost=SearchKey(costVal);queryBase=SearchKey(baseVal);var canSave=false,paraData="action=savedata",alldata;canSave=CheckWuliaoIsAtFirst();//判断是否含有某些特殊内容(正式配方表项目中才会使用到)if(canSave){canSave=CheckSoftOrHard();//判断是否含有硬支、软支价格(正式配方表项目中才会使用到)}if(canSave&&(action=="new"||action=="edit"||action=="copy")){canSave=CheckClass();//判断是否选择了所属分类(正式配方表项目中才会使用到)if(canSave){canSave=CheckInput();//判断是否输入了配方表名称和编码(正式配方表项目中才会使用到)}if(canSave){alldata=hot.getSourceData();//一定要使用getSourceData不能使用getData,否则公式无法保存}}else{alldata=hot.getSourceData();//一定要使用getSourceData不能使用getData,否则公式无法保存hot.loadData(alldata);}if(canSave&&!isEmpty(alldata)){var hotdata=JSON.stringify(alldata);var datas=escape(hotdata).replace(/\+/g,"%2B");//将+号转换为%2BparaData+="&data="+datas;$.ajax({type: "POST",url: "handler.asp",timeout: 10000,data:paraData,cache:false,dataType:"html",success:function(res){},complete:function(res){var txt=res.responseText.split("$$$");if(txt[0]=="1"){alert(opsucess);}else{alert(txt[1]);}}, error:function(e){}});}
}function btnClick()
{SaveData();
}$(document).ready(function()
{action="";GetData();btnSave=document.getElementById("btnSave");Handsontable.dom.addEvent(btnSave,"click",function(){SaveData();});
});
excel.js文件中需要特别注意以下几个地方
A、Handsontable的Setting options中 language 项根据实际需要的语言填写,默认为英文,此项目为 zh-CN
B、Handsontable的Setting options中 licenseKey 项如果不填写或填写错误将会显示如下版权信息(建议商用购买正式版)
C、hot.updateSettings代码串为设置表格的列属性和formula属性
4、编写后端数据处理asp程序(handler.asp),内容如下
<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%><!--#include file="conn.asp"--><%Response.Clear()
Response.Expires=0
Response.CharSet="utf-8"
Response.ContentType="text/html"
Response.Buffer=true
Dim data,val,action,result,idx,i,aryLength,dataAry,Columns,dataAry2,formulaDatas,cols,sql,rs,bomCode,bomName,bomPrice,nowid
Dim formulaCode,formulaName,formulaData,softPrice,hardPrice,useType,fromID,sessionName,msg,fatherID
sessionName="handdata"
Set rs=Server.CreateObject("Adodb.RecordSet")
rs.CursorLocation=3
result="0"
action=Request.Form("action")
Select Case actionCase "savedata"data=Request.Form("data")idx=InStr(data,":[[""")if idx>0 thendata=Right(data,Len(data)-idx)data=Left(data,Len(data)-1)end ifCall SetadminInfo(sessionName,Trim(data))result="1"Case "default",""Session(sessionName)=""Call GetadminInfo(sessionName)data=Session(sessionName)&""if(Len(data))<10 thenSession("default")=""Call GetadminInfo("default")data=Session("default")end ifif(Len(data))>10 thendataAry=Split(data,"],[")dataAry2=Split(dataAry(1),",")aryLength=UBound(dataAry2)Call GetformulaDatas()end ifresult=data&""&splitstr3&""&Columns&""&splitstr3&""&formulaDatas
End Select
Set rs=Nothing
conn.Close()
Set conn=Nothing
Response.Write(result)
Response.Flush()
Response.End()Function Ceil(val)Dim returnreturn = int(val)Cei2=val-returnif Cei2>0 thenCeil = return + 1elseCeil=val+0End If
End FunctionSub GetformulaDatas()dataAry=Split(data,"],[")dataAry2=Split(dataAry(1),",")aryLength=UBound(dataAry2)Dim rs1,idx1idx1=1cols="["formulaDatas="["sql="Select bomCode,bomName,bomPrice From bom"Set rs1=Server.CreateObject("Adodb.RecordSet")rs1.Open sql,conn,1,1Do While Not rs1.EofbomCode=rs1("bomCode")bomName=rs1("bomName")bomPrice=FormatMoney(rs1("bomPrice"))if idx1<rs1.RecordCount thencols=cols&"{""编码"":"""&bomCode&""",""名称"":"""&bomName&""",""单价"":"""&bomPrice&"""},"formulaDatas=formulaDatas&"["""&bomCode&""","""&bomPrice&""","""&bomName&"""],"elsecols=cols&"{""编码"":"""&bomCode&""",""名称"":"""&bomName&""",""单价"":"""&bomPrice&"""}"formulaDatas=formulaDatas&"["""&bomCode&""","""&bomPrice&""","""&bomName&"""]"end ifidx1=idx1+1rs1.MoveNext()Loop rs1.Close()Set rs1=Nothingcols=cols&"]"formulaDatas=formulaDatas&"]"Columns="["for i=0 to aryLengthif i=0 thenColumns=Columns&"{""type"":""handsontable"",""handsontable"":{"Columns=Columns&"""colHeaders"":[""编码"",""名称"",""单价""],"Columns=Columns&"""autoColumnSize"":""true"","Columns=Columns&"data:"&cols&","Columns=Columns&"getValue:function(){var selection = this.getSelectedLast();return this.getSourceDataAtRow(Math.max(selection[0],0)).编码;}"Columns=Columns&"}},"'生成第一列的handsontable联动选择内容elseif i=2 or i=4 or i=12 thenColumns=Columns&"{""type"":""numeric""},"elseif i=aryLength thenColumns=Columns&"{}"elseColumns=Columns&"{},"end ifnextColumns=Columns&"]"
end SubSub GetadminInfo(username)
Dim sqla,rsa
if Len(Session(username)&"")=0 then
sqla="Select password From admin Where username='"&username&"'"
Set rsa=conn.Execute(sqla)
if not rsa.Eof then
admininfo=rsa(0)
Session(username)=admininfo
end if
Set rsa=Nothing
end if
End SubSub SetadminInfo(username,psw)
Dim sqla,rsa
Set rsa=Server.CreateObject("Adodb.RecordSet")
sqla="Select * From admin Where username='"&username&"'"
rsa.CursorLocation=3
rsa.Open sqla,conn,1,3
if rsa.Eof then
rsa.AddNew()
rsa("username")=username
end if
rsa("password")=psw
if username="batteryidx" or username="group" then
rsa("time")=Now()
end if
rsa.UpDate()
rsa.Close()
Session(username)=psw
Set rsa=Nothing
End SubFunction FormatMoney(mm)
if mm&""="" then
mm="0"
end if
if MoneyModel="0" then
FormatMoney=FormatNumber(mm,MoneyDecimal,-1,0,0)
else
FormatMoney=FormatNumber(mm,MoneyDecimal,-1,0,-1)
end if
End Function
%>
5、编写数据库连接asp文件(conn.asp),代码如下
<%Dim DBname,ItemRecT,ItemRecF,ItemRecNow,conn,connstr,FuncLen
ItemRecT="True"
ItemRecF="False"
DateStr="'"
Const splitstr3="$$$"
connstr="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath("data/nbyzs#oa.mdb") & ";Persist Security Info=False"
'以下为mssql数据库连接字符串
'connstr="Provider=SQLOLEDB.1;server=.\SQL2005;uid=sa;pwd=88888888;database=luyuan"
Session("ConnStr")=connstr
Set conn=Server.CreateObject("Adodb.Connection")
conn.Open connstrfunction connClose
if LCase(TypeName(conn))="connection" then
Conn.Close()
Set conn=Nothing
end if
End Function%>
至此大功告成,速速围观整体效果如下图
如果在此基础上增加每个Excel表格的增加、修改、删除、查看权限控制是不是就特别方便帮办公室小姐姐实现在线excel表格管理功能呢?
这样即能实现数据共享又可以很方便地进行表格管理,还不用担心数据丢失。
本文完整代码下载链接 https://download.csdn.net/download/chenagen/18241896
不过,我已经开发出了完整的这种功能,有需要的可以查看以下演示(Excel配方表系统)
http://jxc.51lego.net/ 账号密码均为 lj
这篇关于教你怎么用程序代码开发Excel功能,搞定办公室小姐姐--将handsontable控件整合进自己一直开发完成的WEB进销存系统的心得体会(走了不少弯路,值得大家借鉴)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!