教你怎么用程序代码开发Excel功能,搞定办公室小姐姐--将handsontable控件整合进自己一直开发完成的WEB进销存系统的心得体会(走了不少弯路,值得大家借鉴)

本文介绍如何使用Handsontable控件为老客户开发一个配方表管理子功能,实现类似Excel的在线表格。通过前端html、后端asp以及数据库交互,完成数据的读取、编辑和保存。同时,提供了详细的代码示例,包括前端HTML、CSS、JavaScript和后端ASP文件,以及数据库连接文件。项目实现了数据共享和表格管理,避免数据丢失,适合办公室场景。
摘要由CSDN通过智能技术生成

大家好,我是诚一

几天前,一家使用我的进销存系统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");//将+号转换为%2B
		paraData+="&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 action
	Case "savedata"
		data=Request.Form("data")
		idx=InStr(data,":[[""")
		if idx>0 then
			data=Right(data,Len(data)-idx)
			data=Left(data,Len(data)-1)
		end if
		Call SetadminInfo(sessionName,Trim(data))
		result="1"
	Case "default",""
		Session(sessionName)=""
		Call GetadminInfo(sessionName)
		data=Session(sessionName)&""
		if(Len(data))<10 then
			Session("default")=""
			Call GetadminInfo("default")
			data=Session("default")
		end if
		if(Len(data))>10 then
			dataAry=Split(data,"],[")
			dataAry2=Split(dataAry(1),",")
			aryLength=UBound(dataAry2)
			Call GetformulaDatas()
		end if
		result=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 return
    return = int(val)
    Cei2=val-return
    if Cei2>0 then
        Ceil = return + 1
    else
        Ceil=val+0
    End If
End Function

Sub GetformulaDatas()
	dataAry=Split(data,"],[")
	dataAry2=Split(dataAry(1),",")
	aryLength=UBound(dataAry2)
	Dim rs1,idx1
	idx1=1
	cols="["
	formulaDatas="["
	sql="Select bomCode,bomName,bomPrice From bom"
	Set rs1=Server.CreateObject("Adodb.RecordSet")
	rs1.Open sql,conn,1,1
	Do While Not rs1.Eof
		bomCode=rs1("bomCode")
		bomName=rs1("bomName")
		bomPrice=FormatMoney(rs1("bomPrice"))
		if idx1<rs1.RecordCount then
			cols=cols&"{""编码"":"""&bomCode&""",""名称"":"""&bomName&""",""单价"":"""&bomPrice&"""},"
			formulaDatas=formulaDatas&"["""&bomCode&""","""&bomPrice&""","""&bomName&"""],"
		else
			cols=cols&"{""编码"":"""&bomCode&""",""名称"":"""&bomName&""",""单价"":"""&bomPrice&"""}"
			formulaDatas=formulaDatas&"["""&bomCode&""","""&bomPrice&""","""&bomName&"""]"
		end if
		idx1=idx1+1
		rs1.MoveNext()
	Loop		
	rs1.Close()
	Set rs1=Nothing
	cols=cols&"]"
	formulaDatas=formulaDatas&"]"
	Columns="["
	for i=0 to aryLength
		if i=0 then
			Columns=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 then
			Columns=Columns&"{""type"":""numeric""},"
		elseif i=aryLength then
			Columns=Columns&"{}"
		else
			Columns=Columns&"{},"
		end if
	next
	Columns=Columns&"]"
end Sub

Sub 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 Sub

Sub 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 Sub

Function 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 connstr

function 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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chenagen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值