掌上报销单据头附件二开方案

【应用场景】
客户在PC端单据头增加了附件字段,需要在掌上报销单据头也额外增加相关功能
【案例演示】
PC端费用报销与掌上报销单据头与单据体的映射关系:https://vip.kingdee.com/article/439370655386174720?productLineId=1&isKnowledge=2
【实现步骤】
1、 更新了多选附件(文件服务)控件的相关示例代码。
2、 本文示例代码以勾选【上传按钮】为基础来实现。如果需要勾选【自动上传】,需要自行调整UploadAttachFiles的逻辑。
掌上报销单据头附件二开步骤主要分为三步:
一、BOS设计器往掌上报销移动表单:掌上报销V3_费用报销单ER_MBReimb_ExpReimbV3里面添加附件上传控件,自行调整样式,勾选【上传按钮】


二、往PC端单据:费用报销单ER_ExpReimbursement增加附件字段,以多选附件(文件服务)为例,往单据头添加多选附件(文件服务)控件

三、需要处理:移动端上传的附件,直接保存到pc单据对应的字段中,pc端上传的单据头附件,在移动端显示。
二开掌上报销移动表单插件:掌上报销V3_费用报销单ER_MBReimb_ExpReimbV3,重写下面方法AfterBindData、AfterMobileUpload(根据移动端控件标识判断是否调用基类方法)
步骤一:单独针对移动端单据头,能够正常显示下载PC端上传的附件。
移动端绑定历史上传附件:
/// <summary>
/// 文件FileId与移动端附件控件展示时用的文件名的映射(附件(数据库)专用)
/// </summary>
Dictionary<string, string> FieIdToDisplayFileName = new Dictionary<string, string>();
/// <summary>
/// 多选附件(文件服务)存储在数据库里的文件信息
/// </summary>
JSONArray Files = new JSONArray();
private SubmitType submitType;
public override void AfterBindData(EventArgs e)
{
base.AfterBindData(e);
BindValue();
}
private void BindValue()
{
var pkValue = BillView.Model.GetPKValue();
if (pkValue.IsEmptyPrimaryKey())
{
return;
}
string _FormId = "ER_ExpReimbursement"; // 目标单据唯一标识,即formid
string _InterID = pkValue.ToString(); // 单据内码,这个ID将作为我们下载的识别标识
//string controlKey = "F_MOB_FileServer"; //单据中附件(文件服务)控件的字段名
//string controlKey = "F_MOB_FileDatabase"; //单据中附件(数据库)控件的字段名
//string controlKey = "F_MOB_ImageServer"; //单据中图片(文件服务)控件的字段名
//string controlKey = "F_MOB_ImageDatabase"; //单据中图片(数据库)控件的字段名
//string controlKey = "F_MOB_FileServerMulti"; //单据中多选附件(文件服务)控件的字段名
string controlKey = "F_MOB_FileServerMulti";
var businessInfo = ((FormMetadata)MetaDataServiceHelper.Load(this.Context, _FormId)).BusinessInfo;
var dyn = BusinessDataServiceHelper.LoadSingle(this.Context, _InterID, businessInfo.GetDynamicObjectType());
if (dyn == null) return;
var dynFile = dyn[controlKey];
if (dynFile == null) return;
List<File> files = new List<File>();
string path = HttpContext.Current.Request.PhysicalApplicationPath + KeyConst.TEMPFILEPATH; // 获取文件上传的临时目录
// 下面是pc端不同附件字段对应的移动端显示附件的方式,可根据业务需要来选择
if (controlKey == "F_MOB_FileDatabase") //pc单据对应的控件类型为附件(数据库)
{
FieIdToDisplayFileName = new Dictionary<string, string>();
string fieldValue = dynFile.ToString(); //附件(数据库),实际存储的是转成base64字符串的json数组
JSONArray fileArray = fieldValue.IsEmpty() ? new JSONArray() : SerializatonUtil.DeserializeFromBase64<JSONArray>(fieldValue);
foreach (JSONObject json in fileArray)
{
string fileId = string.Empty;
string serverFileName = json.GetString("ServerFileName");
string fileName = json.GetString("FileName");
string fileType = fileName.Substring(fileName.LastIndexOf(".") + 1);
//附件(数据库)储存方式,根据byte数据组保存文件到临时目录,返回文件名给前端,前端根据文件名获取数据
int length = serverFileName.IndexOf(" ") > -1 ? serverFileName.IndexOf(" ") : serverFileName.Length;
fileId = serverFileName.Substring(0, length); //附件(数据库),serverFileName为fileid+空格+文件名+后缀,需要截取
fileName = CommonFunctionUtil.FilterOpSysInvalidCharacterForFileName(fileName);
var displayFileName = CommonFunctionUtil.GetFileName(this.Context, fileId, fileName); //附件控件展示时用的文件名
string filePath = System.IO.Path.Combine(path, displayFileName);
//输出原始文件
if (filePath == "" || !System.IO.File.Exists(filePath))
{
byte[] fileBytes = json.GetValue<Byte[]>("FileContent");
if (fileBytes != null)
{
CreateFile(fileBytes, filePath);
}
}
files.Add(new File() { FileID = fileId, Name = fileName, Type = fileType, IsFieldFile = true });
FieIdToDisplayFileName.Add(fileId, displayFileName);
}
}
else if (controlKey == "F_MOB_FileServerMulti") //pc单据对应的控件类型为多选附件(文件服务)
{
string fieldValue = dynFile.ToString();
JSONArray fileArray = fieldValue.IsEmpty() ? new JSONArray() : JSONArray.Parse(fieldValue);
Files = new JSONArray();
List<string> fileIds = new List<string>();
foreach (Dictionary<string, object> json in fileArray)
{
JSONObject fileObject = JSONObject.Parse(KDObjectConverter.SerializeObject(json));
Files.Add(fileObject);
fileIds.Add(fileObject.GetString("ServerFileName"));
}
var existFiles = FileServerHelper.FindByIds(this.Context, fileIds);
if (existFiles == null || !existFiles.Any()) return;
foreach (JSONObject fileObject in Files)
{
string fileId = fileObject.GetString("ServerFileName");
string fileName = fileObject.GetString("FileName");
var file = existFiles.Find(item => item.ID == fileId);
if (file == null) continue;
string fileType = file.suffix;
files.Add(new File() { FileID = fileId, Name = fileName, Type = fileType, IsFieldFile = true });
}
}
else if (controlKey == "F_MOB_FileServer" || controlKey == "F_MOB_ImageServer") //pc单据对应的控件类型为附件(文件服务)或图片(文件服务)
{
string fileId = dynFile.ToString(); //附件(文件服务)和图片(文件服务),实际存储的是文件服务器中的fileid
var file = FileServerHelper.GetKDFileById(this.Context, fileId);
if (file == null) return;
string fileName = file.Name;
string fileType = file.suffix;
files.Add(new File() { FileID = fileId, Name = fileName, Type = fileType, IsFieldFile = true });
}
else if (controlKey == "F_MOB_ImageDatabase") //pc单据对应的控件类型为图片(数据库)库
{
string fileId = string.Empty; //图片(数据库),实际存储的是图片的byte数组
string fileType = ".webp";
Random random = new Random();
string fileName = string.Format("{0}{1}{2}{3}{4}", DateTime.Now.ToString("yyyyMMddHHmmssfff"), this.Context.UserId,
System.Threading.Thread.CurrentThread.ManagedThreadId, random.Next(int.MaxValue), fileType);
string filePath = System.IO.Path.Combine(path, fileName);
//输出原始文件
if (filePath == "" || !System.IO.File.Exists(filePath))
{
byte[] fileBytes = (byte[])dynFile;
if (fileBytes != null)
{
CreateFile(fileBytes, filePath);
}
}
files.Add(new File() { FileID = fileId, Name = fileName, Type = fileType, IsFieldFile = true });
}
AccessoryData data = new AccessoryData()
{
FormId = _FormId,
BillId = _InterID,
Data = files
};
// 根据不同pc端字段,给移动端对应附件控件绑定附件信息
// 可以一个pc端字段对应移动端一个附件控件
if (controlKey == "F_MOB_FileDatabase" || controlKey == "F_MOB_FileServer")
{
this.View.GetControl("FFileUpload").SetValue(data.ToJsonString());
}
if (controlKey == "F_MOB_ImageDatabase" || controlKey == "F_MOB_ImageServer")
{
this.View.GetControl("FImageUpload").SetValue(data.ToJsonString());
}
if (controlKey == "F_MOB_FileServerMulti")
{
this.View.GetControl("FFileUploadMulti").SetValue(data.ToJsonString());
}
}
/// <summary>
/// 根据二进制文件,创建临时文件
/// </summary>
private void CreateFile(byte[] fileBytes, string filePath)
{
try
{
if (!System.IO.File.Exists(filePath) && fileBytes != null && fileBytes.Length > 0)
{
using (System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.Read))
using (System.IO.BinaryWriter bw = new System.IO.BinaryWriter(fs))
{
bw.Write(fileBytes);
}
}
}
catch { }
}步骤二:移动端单据头上传附件,并且绑定附件信息到PC端附件字段上面去
/// <summary>
/// 移动端上传附件至临时目录,并且绑定到PC端控件字段上面去
/// </summary>
/// <param name="e"></param>
public override void AfterMobileUpload(BOS.Mobile.PlugIn.Args.MobileUploadEventArgs e)
{
if (e.Key.EqualsIgnoreCase("FImageUpload") || e.Key.EqualsIgnoreCase("FFileUpload") || e.Key.EqualsIgnoreCase("FFileUploadMulti"))
{
var pkValue = BillView.Model.GetPKValue();
if (pkValue.IsEmptyPrimaryKey())
{
// 单据不存在,需要先暂存
if (Draft(true, true))
{
pkValue = BillView.Model.GetPKValue();
this.UploadAttachFiles(e, pkValue.ToString());
}
}
else
{
this.UploadAttachFiles(e, pkValue.ToString());
}
}
else
{
base.AfterMobileUpload(e);
}
}
/// <summary>
/// 上传附件
/// </summary>
/// <param name="e"></param>
/// <param name="pkValue">单据内码</param>
private void UploadAttachFiles(BOS.Mobile.PlugIn.Args.MobileUploadEventArgs e, string pkValue)
{
// 获取文件上传的临时目录
string tempDirPath = HttpContext.Current.Request.PhysicalApplicationPath + KeyConst.TEMPFILEPATH;
// 仅附件(数据库)、多选附件(文件服务)支持上传多个文件,其他仅支持上传一个文件
// 下面是pc端不同附件字段对应的附件上传方式,可根据业务需要来选择
submitType = SubmitType.FileServerMulti;
if (submitType == SubmitType.FileDatabase) //上传附件至数据库
{
StringBuilder sb = new StringBuilder();
JSONArray fileArray = new JSONArray();
foreach (FiledUploadEntity file in e.FileNameArray)
{
if (!file.IsSuccess) continue; // 检查文件是否上传成功
var filePath = string.Empty;
// 检查文件是否存在
if (file.isNewFile)
{
// 新上传的文件,用控件提供的临时文件名查找文件
filePath = System.IO.Path.Combine(tempDirPath, file.FileName);
if (!System.IO.File.Exists(filePath)) continue;
}
else
{
// 已有的文件,用BindValue方法中动态提供的displayFileName查找文件
string displayFileName = FieIdToDisplayFileName[file.FileId];
filePath = System.IO.Path.Combine(tempDirPath, displayFileName);
if (!System.IO.File.Exists(filePath)) continue;
}
JSONObject fileObject = new JSONObject();
var dataBuff = System.IO.File.ReadAllBytes(filePath);
// 新上传的文件需生成FileId,已有的文件用现有的FileId
string fileName = file.isNewFile ? Guid.NewGuid().ToString() + " " + file.OldName : file.FileId + " " + file.OldName;
fileObject.Put("ServerFileName", fileName);
fileObject.Put("FileName", file.OldName);
fileObject.Put("FileLength", dataBuff.Length);
fileObject.Put("FileBytesLength", dataBuff.Length);
fileObject.Put("FileContent", dataBuff);
fileArray.Add(fileObject);
}
if (fileArray.Count == 0) return;
this.SaveFilesToBillInfo(pkValue, SerializatonUtil.SerializeToBase64(fileArray));
sb.AppendLine();
sb.AppendLine("上传成功");
this.Model.SetValue("FFileLog", sb.ToString());
}
else if (submitType == SubmitType.FileServerMulti) //多选附件上传至文件服务器
{
StringBuilder sb = new StringBuilder();
JSONArray successFiles = new JSONArray();掌上报销单据头附件二开方案
【应用场景】客户在PC端单据头增加了附件字段,需要在掌上报销单据头也额外增加相关功能【案例演示】PC端费用报销与掌上报销单据头与单据体...
点击下载文档文档为doc格式
声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。如若本站内容侵犯了原著者的合法权益,可联系本站删除。
上一篇
已经是第一篇



