1.此操作,前端是自定义页面解析上传文件,将文件转为json格式上传至后台,
后端为action:将提取json文件的内容进行添加操作!直接上代码!
前端:注意要要引用两个文件
jQuery
<script src="xlsx.full.min.js"></script>——》解析上传的excel文件
<script src="es5-shim.js"></script>——》可以让一些低版本的浏览器支持es5语法
<div id="page"> <p>数据导入</p> <form id="from-upFile" name="form" method="post" enctype="multipart/form-data"> <input type="file" name="file" id="upFile" style="display: none;" /> </form> <span>文件地址:</span><input type="text" id="fileurl" value="" /> <input type="button" id="changefile" value="选择文件" /> <input type="button" id="btnSubmit" value="上传" onclick="myfunction()" /> <script> //页面美化 function Urlfile(e) { var url = null; if (window.URL != null) { url = window.URL.createObjectURL(e); } else if (window.createObjectURL != null) { url = window.createObjectURL(e); } else if (window.webkitURL != null) { url = window.webkitURL.createObjectURL(e); } return url; }; document.getElementById("changefile").onclick = function () { document.getElementById("upFile").click(); document.getElementById("upFile").onchange = function () { var url = Urlfile(document.getElementById("upFile").files[0]); $("#fileurl").val(url); }; }; //组合:供应商+零件编码 function myfunction() { //获取到选中的文件进行文件格式判断 var file = document.querySelector("#upFile").files[0]; var type = file.name.split('.'); if (type[type.length - 1] !== 'xlsx' && type[type.length - 1] !== 'xls') { alert('只能选择excel文件导入'); return false; } //读取上传文件并开始解析文件数据 var reader = new FileReader(); var result = []; var fileData = []; //这是个回调,相当于异步操作 reader.onload = (e) => { var data = e.target.result;//获取上传文件的内容 var zzexcel = window.XLS.read(data, { type: 'binary' }); //获取数据 for (var i = 0; i < zzexcel.SheetNames.length; i++) {//循环表 //将表种的内容全部添加至result集合中 var newData = window.XLS.utils.sheet_to_json(zzexcel.Sheets[zzexcel.SheetNames[i]]); result.push(...newData)//三个点(...)真名叫扩展运算符,是在ES6中新增加的内容,它可以在函数调用/数组构造时,将数组表达式或者string在语法层面展开;还可以在构造字面量对象时将对象表达式按照key-value的方式展开 } //换列得标题(因为传到后端列名不能为中文,所以在此处做一个处理) for (var i = 0; i < result.length; i++) { if (result[i]["零件编码"] == null || result[i]["供应商"] == null || result[i]["收货数量"] == null || parseInt(result[i]["收货数量"]) <= 0) { alert("文件列内容存在空值或收货数量小于0!请检查并修改文件后再次添加!"); return false; } var fileobject = {}; fileobject.jk_partcode = result[i]["零件编码"]; fileobject.jk_supplier = result[i]["供应商"]; fileobject.jk_quantity = result[i]["收货数量"]; fileData.push(fileobject); } //获取当前实体id var DialogArguments = window.getDialogArguments(); if (!DialogArguments) { return; } var entity = new Object(); entity["jk_receiptID"] = DialogArguments.id; entity["jk_receiptitemEntityData"] = JSON.stringify(fileData); console.log(entity["jk_receiptID"]); console.log(entity["jk_receiptitemEntityData"]); $.ajax({ url: "/api/data/v8.2/mcs_OfficialReceiptsDataImportAction219a75685461eb11b02000505699ebb1", data: JSON.stringify(entity), type: "POST", async: false, dataType: "json", contentType: "application/json;charset=utf-8", success: function (data) { alert(data.DataUploadTheResult); console.log(data); }, error: function (data) { alert(data.DataUploadTheResult); console.log(data); } }); } reader.readAsBinaryString(file); } </script> </div>
后端(方法一)
public class OfficialReceiptsDataImportAction : IPlugin { public void Execute(IServiceProvider serviceProvider) { IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId); //获取传入信息 当前实体名称(jk_receipt) 需要添加信息得实体名称(jk_receiptitem) Guid EntityID = Guid.Parse(context.InputParameters["jk_receiptID"].ToString()); string[] EntityInfo = context.InputParameters["jk_receiptitemEntityData"].ToString().Replace("\", "").Replace(""", "").Replace("[", "").Replace("]", "").Replace("{", "").Replace("}", "").Split(','); try { List<jk_receiptitem> ls = new List<jk_receiptitem>(); for (int i = 0; i < EntityInfo.Length; i += 3) { jk_receiptitem b = new jk_receiptitem() { jk_partcode = EntityInfo[i].Split(':')[1].ToString(), jk_supplier = EntityInfo[i + 1].Split(':')[1].ToString(), jk_quantity = double.Parse(EntityInfo[i + 2].Split(':')[1]) }; ls.Add(b); } string ErrorMessage = ""; int count = 1; List<string> vlist = new List<string>(); //查询已有数据 QueryExpression q3 = new QueryExpression(); q3.EntityName = "jk_receiptitem"; q3.ColumnSet = new ColumnSet(true); q3.Criteria.AddCondition("jk_receiptno", ConditionOperator.Equal, EntityID); EntityCollection ec3 = service.RetrieveMultiple(q3); if (ec3.Entities.Count != 0) { for (int i = 0; i< ec3.Entities.Count; i++) { string repeatcount = ""; if (ec3.Entities[i].Contains("jk_supplier")==true&& ec3.Entities[i].Contains("jk_partcode")==true) { EntityReference gongy_id = (EntityReference)ec3.Entities[i].Attributes["jk_supplier"]; repeatcount = gongy_id.Id.ToString() + ec3.Entities[i].Attributes["jk_partcode"].ToString(); } else if(ec3.Entities[i].Contains("jk_supplier") != true && ec3.Entities[i].Contains("jk_partcode") == true) { repeatcount = "" + ec3.Entities[i].Attributes["jk_partcode"].ToString(); } else { EntityReference gongy_id = (EntityReference)ec3.Entities[i].Attributes["jk_supplier"]; repeatcount = gongy_id.Id.ToString() +""; } vlist.Add(repeatcount); } } foreach (var item in ls) { //查询供应商id QueryExpression q = new QueryExpression(); q.EntityName = "mcs_spmsupplierinfo"; q.ColumnSet = new ColumnSet(true); q.Criteria.AddCondition("mcs_supplierinfocode", ConditionOperator.Equal, item.jk_supplier); EntityCollection ec = service.RetrieveMultiple(q); //零件查询 QueryExpression q2 = new QueryExpression(); q2.EntityName = "mcs_parts"; q2.ColumnSet = new ColumnSet(true); q2.Criteria.AddCondition("mcs_name", ConditionOperator.Equal, item.jk_partcode); EntityCollection ec2 = service.RetrieveMultiple(q2); if (ec.Entities.Count == 0|| ec2.Entities.Count==0) { ErrorMessage = $"上传的信息中,第{count}行存在错误!"; break; } else if (ec.Entities.Count != 0 || ec2.Entities.Count != 0) { string repeatcount = ec.Entities[0].Id.ToString() + ec2.Entities[0].Attributes["mcs_name"].ToString(); vlist.Add(repeatcount); } count++; } //判断是否数据重复! bool HaveDuplicates = vlist.GroupBy(i => i).Where(g => g.Count() > 1).Count() >= 1; if (HaveDuplicates) { ErrorMessage = "重复数据!请检查后在试!"; //throw new Exception("错误提示!"); } //返回结果 if (ErrorMessage != "") { context.OutputParameters["DataUploadTheResult"] = ErrorMessage; } else { //添加数据 foreach (var item in ls) { //查的是供应商 QueryExpression q = new QueryExpression(); q.EntityName = "mcs_spmsupplierinfo"; q.ColumnSet = new ColumnSet(true); q.Criteria.AddCondition("mcs_supplierinfocode", ConditionOperator.Equal, item.jk_supplier); EntityCollection ec = service.RetrieveMultiple(q); //零件查询 QueryExpression q2 = new QueryExpression(); q2.EntityName = "mcs_parts"; q2.ColumnSet = new ColumnSet(true); q2.Criteria.AddCondition("mcs_name", ConditionOperator.Equal, item.jk_partcode); EntityCollection ec2 = service.RetrieveMultiple(q2); Entity e = new Entity(); e.LogicalName = "jk_receiptitem"; e.Attributes["jk_partname"] = ec2.Entities[0].Attributes["mcs_partscode"]; e["jk_partcode"] = item.jk_partcode; e["jk_supplier"] = new EntityReference("jk_receiptitem", ec.Entities[0].Id); e["jk_quantity"] = item.jk_quantity; e["jk_receiptno"] = new EntityReference("jk_receiptitem", EntityID); service.Create(e); } context.OutputParameters["DataUploadTheResult"] = "数据添加成功!"; } } catch (Exception e) { context.OutputParameters["DataUploadTheResult"] = "数据添加失败!详细信息如下:" + e.ToString(); } } 后端还有一个类 public class jk_receiptitem { public string jk_partcode { get; set; } public string jk_supplier { get; set; } public double jk_quantity { get; set; } }
方法二
using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Query; using Newtonsoft.Json.Linq; using System; using System.Linq; public void Execute(IServiceProvider serviceProvider) { IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId); //获取传入信息 当前实体名称(new_contract) 需要添加信息得实体名称(new_pay_plan) Guid EntityID = Guid.Parse(context.InputParameters["EntityID"].ToString()); string EntitiesInfo = "{info:" + context.InputParameters["EntityInfo"].ToString() + "}"; var EntityData = JObject.Parse(EntitiesInfo); try { //查询信息 QueryExpression q = new QueryExpression(); q.EntityName = "new_pay_plan"; q.ColumnSet = new ColumnSet(true); q.Criteria.AddCondition("new_contractid", ConditionOperator.Equal, EntityID); EntityCollection e2 = service.RetrieveMultiple(q);//获取实体信息 int num = e2.Entities.Count(); //添加信息 foreach (var item in EntityData["info"]) { num++; string num2 = ""; if (num<9) { num2 = "0" + num; } else { num2 = num.ToString(); } Entity PayPlan = new Entity(); PayPlan.LogicalName = "new_pay_plan"; PayPlan["new_name"] = "周期性"; PayPlan["new_plan_type"] =new OptionSetValue(30); PayPlan["new_seq"] = num2; PayPlan["new_payment_year"] = item["new_payment_year"].ToString(); PayPlan["new_contractid"] = new EntityReference("new_contract", EntityID); PayPlan["new_payment_month"] = item["new_payment_month"].ToString(); PayPlan["new_pay_amount"] =Convert.ToDecimal(item["new_pay_amount"]); PayPlan["new_remark"] = item["new_remark"] == null ? null : item["new_remark"].ToString(); service.Create(PayPlan); } context.OutputParameters["PromptMessage"] = "数据导入完毕!"; } catch (Exception e) { context.OutputParameters["PromptMessage"] = "数据导入失败,详细情况如下: " + e.ToString(); }
数据导出(做数据导入的时候呐!我们会提供一个导入模板,用户根据模板来进行数据的添加,导入!)
//html <input type="button" id="btn_ExcelDownload" value="模板下载" class="btn_class" onclick="downloadExl(jsono)" /> <p><a href="" download="厅店采购申请数据导入模板.xlsx" id="hf"></a></p> //模板下载(导出数据可以获取数据,将数据传入jsono中生成相应的规则) var jsono = [{ //测试数据 "零件编码": "", "零件数量": "", "备注": "" }]; var tmpDown; //导出的二进制对象 function downloadExl(json, type) { var tmpdata = json[0]; json.unshift({}); var keyMap = []; //获取keys //keyMap =Object.keys(json[0]); for (var k in tmpdata) { keyMap.push(k); json[0][k] = k; } var tmpdata = [];//用来保存转换好的json json.map((v, i) => keyMap.map((k, j) => Object.assign({}, { v: v[k], position: (j > 25 ? getCharCol(j) : String.fromCharCode(65 + j)) + (i + 1) }))).reduce((prev, next) => prev.concat(next)).forEach((v, i) => tmpdata[v.position] = { v: v.v }); var outputPos = Object.keys(tmpdata); //设置区域,比如表格从A1到D10 var tmpWB = { SheetNames: ['mySheet'], //保存的表标题 Sheets: { 'mySheet': Object.assign({}, tmpdata, //内容 { '!ref': outputPos[0] + ':' + outputPos[outputPos.length - 1] //设置填充区域 }) } }; tmpDown = new Blob([s2ab(XLSX.write(tmpWB, { bookType: (type == undefined ? 'xlsx' : type), bookSST: false, type: 'binary' }//这里的数据是用来定义导出的格式类型 ))], { type: "" }); //创建二进制对象写入转换好的字节流 var href = URL.createObjectURL(tmpDown); //创建对象超链接 document.getElementById("hf").href = href; //绑定a标签 document.getElementById("hf").click(); //模拟点击实现下载 setTimeout(function () { //延时释放 URL.revokeObjectURL(tmpDown); //用URL.revokeObjectURL()来释放这个object URL }, 100); } function s2ab(s) { //字符串转字符流 var buf = new ArrayBuffer(s.length); var view = new Uint8Array(buf); for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF; return buf; } // 将指定的自然数转换为26进制表示。映射关系:[0-25] -> [A-Z]。 function getCharCol(n) { let temCol = '', s = '', m = 0 while (n > 0) { m = n % 26 + 1 s = String.fromCharCode(m + 64) + s n = (n - m) / 26 } return s }
补充,将前端的json(对象数组)格式的字符串解析后将信息放到list集合中,其中需要对应json字符串中的对象写一个类文件,类型对应一下就可以了!
//需要引用Newtonsoft.Json文件(如果该文件不可用,就使用上面方法,碰到前面excel列可为空时,给一个“该值为空”传递到后台做判断!判断获取到的信息是否为“该值为空”的文本,是就不添加改列信息,否就添加上传信息) List<jk_receiptitem> ls1 = JsonConvert.DeserializeObject<List<jk_receiptitem>>("前端传入的字符串"); //判断list集合中是否存在重复值vlist.GroupBy(i => i).Where(g => g.Count() > 1)返回的是一个重复数据集合 bool HaveDuplicates = vlist.GroupBy(i => i).Where(g => g.Count() > 1).Count() >= 1; //存在重复值就返回true,不存在重复值就返回false
当excel文件有时间列时需要注意了,excel页面输入的是一个时间格式,但是通过xlsx解析后呢!就变成了一个数字,这个数字是获取到的日期距离1900年1月1日有多少天!不知道这个日期有什么含义!所以将xlsx解析的数字放到下面的方法中就可以返回一个excel中填写的日期!
//在转化之前需要判断获取到的时间是否为空,还有就是是不是日期格式的 if (result[i]["期待到货时间"] != null) { if (isNaN(result[i]["期待到货时间"]) && isNaN(Date.parse(result[i]["期待到货时间"]))) { alert("上传文件中第" + (i + 1) + "行存在填写日期格式不正确!"); return false; } } //日期转化 function formatDate(numb, format = "-") { let time = new Date((numb - 1) * 24 * 3600000 + 1) time.setYear(time.getFullYear() - 70) let year = time.getFullYear() + '' let month = time.getMonth() + 1 + '' let date = time.getDate() + '' if (format && format.length === 1) { return year + format + month + format + date } return year + (month < 10 ? '0' + month : month) + (date < 10 ? '0' + date : date) }
判断获取的内容是否为数字
//正则判断是否填入是数字 function checkNum(input) { var reg = /^[0-9]+.?[0-9]*$/; //判断字符串是否为数字 ,判断正整数用/^[1-9]+[0-9]*]*$/ if (!reg.test(input)) { return false; } } if (checkNum(result[i]["采购数量"]) == false) { alert("上传文件中第" + (i + 1) + "行存在采购数量类型不正确!"); return false; }