前端部分:
@{
ViewData["Title"] = "Index";
Layout = "~/Views/Shared/_Index.cshtml";
}
<style type="text/css">
html, body {
margin: 0;
padding: 0;
}
.saveimg {
text-align: center;
}
.saveimgs span {
display: inline-block;
margin-top: 5px;
}
</style>
<div align="center">
<canvas id="myCanvas" width="500" height="300" style="border:1px dotted #6699cc"></canvas>
<div class="control-ops control">
<button type="button" class="btn btn-primary" onclick="javascript:clearArea();return false;">重写</button>
<select style="display:none" id="selWidth" onchange="aaa()">
<option value="1">1</option>
<option value="3" selected="selected">3</option>
<option value="5">5</option>
<option value="7">7</option>
<option value="9">9</option>
<option value="11">11</option>
</select>
<select id="selColor" onchange="aaa2()">
<option value="black" selected="selected">黑色笔</option>
<option value="blue">蓝色笔</option>
<option value="red">红色笔</option>
<option value="green">绿色笔</option>
<option value="yellow">黄色笔</option>
<option value="gray">深灰笔</option>
</select>
<button type="button" class="saveimg" onclick="javascript:saveImageInfo();return false;">提交</button>
</div>
<div class="saveimgs"></div>
</div>
<script src="~/js/jquery-3.5.1.min.js"></script>
<script type="text/javascript">
var fileId = '@ViewBag.fileId';
var mousePressed = false;
var lastX, lastY;
var ctx = document.getElementById('myCanvas').getContext("2d");
var c = document.getElementById("myCanvas");
var control = document.getElementsByClassName("control")[0];
var saveimgs = document.getElementsByClassName("saveimgs")[0];
window.onload = function () {
document.getElementById('myCanvas').setAttribute("width", $(window).width() - 5);
InitThis();
}
function saveImageInfo() {
debugger;
var imageurl = c.toDataURL("image/png");
AjaxPostRequest("@Url.Action("SignatureSave")", { imageurl: imageurl, fileId: fileId }, function (result) {
if (result.code == 0) {
layer.alert("签名成功", function () {
window.parent.location.reload();//刷新父页面
parent.layer.close();//关闭弹出层
});
} else {
popUp.FailMsg(result.message);
}
}, false, false);
return;
}
var selected1, selected2;
function aaa() {
var sel = document.getElementById('selWidth');
var value = sel.selectedIndex;
return selected1 = sel[value].value;
}
function aaa2() {
var sel2 = document.getElementById('selColor');
var value = sel2.selectedIndex;
return selected2 = sel2[value].value;
}
function InitThis() {
// 触摸屏
c.addEventListener('touchstart', function (event) {
console.log(1)
if (event.targetTouches.length == 1) {
event.preventDefault();// 阻止浏览器默认事件,重要
var touch = event.targetTouches[0];
mousePressed = true;
Draw(touch.pageX - this.offsetLeft, touch.pageY - this.offsetTop, false);
}
}, false);
c.addEventListener('touchmove', function (event) {
console.log(2)
if (event.targetTouches.length == 1) {
event.preventDefault();// 阻止浏览器默认事件,重要
var touch = event.targetTouches[0];
if (mousePressed) {
Draw(touch.pageX - this.offsetLeft, touch.pageY - this.offsetTop, true);
}
}
}, false);
c.addEventListener('touchend', function (event) {
console.log(3)
if (event.targetTouches.length == 1) {
event.preventDefault();// 阻止浏览器默认事件,防止手写的时候拖动屏幕,重要
mousePressed = false;
}
}, false);
/*c.addEventListener('touchcancel', function (event) {
console.log(4)
mousePressed = false;
},false);*/
// 鼠标
c.onmousedown = function (event) {
mousePressed = true;
Draw(event.pageX - this.offsetLeft, event.pageY - this.offsetTop, false);
};
c.onmousemove = function (event) {
if (mousePressed) {
Draw(event.pageX - this.offsetLeft, event.pageY - this.offsetTop, true);
}
};
c.onmouseup = function (event) {
mousePressed = false;
};
}
function Draw(x, y, isDown) {
if (isDown) {
ctx.beginPath();
ctx.strokeStyle = selected2;
ctx.lineWidth = selected1;
ctx.lineJoin = "round";
ctx.moveTo(lastX, lastY);
ctx.lineTo(x, y);
ctx.closePath();
ctx.stroke();
}
lastX = x; lastY = y;
}
function clearArea() {
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
// 清除签名图片
if (saveimgs.getElementsByTagName('span').length >= 1) {
var clearImg = saveimgs.getElementsByTagName('span')[0];
saveimgs.removeChild(clearImg);
}
}
</script>
后端部分
/// <summary>
/// 签名页面
/// </summary>
/// <param name="fileId">文件Id</param>
/// <returns></returns>
public IActionResult Signature(string fileId)
{
ViewBag.fileId = fileId;
return View();
}
/// <summary>
/// 保存签名
/// </summary>
/// <param name="imageurl">签名</param>
/// <param name="fileId">pdf文件id</param>
/// <returns></returns>
public IActionResult SignatureSave(string imageurl, string fileId)
{
string mtfilename = (_webEnv.ContentRootPath + AppSetting.GetFilePath() + System.Guid.NewGuid().ToString()).Replace("\\", "/") + ".jpg";
string dummyData = imageurl.Trim().Replace("data:image/png;base64,", "");
//获取签名
Base64StringToImage(dummyData, mtfilename);
if (System.IO.File.Exists(mtfilename) == false)
{
return Json(RongboResult<int>.Successed("保存手写图片失败,请重试并提交", 1));
}
System.Drawing.Image img = System.Drawing.Image.FromFile(mtfilename);
var model = _schoolReport.GetSchoolReport(fileId).Data;//获取pdf文件
if (model == null || string.IsNullOrEmpty(model.Id))
{
return Json(RongboResult<string>.Failed(-1, "文件不存在"));
}
string savePath = (_webEnv.ContentRootPath + AppSetting.GetFilePath() + model.FileName).Replace("\\", "/");
#region 将阿里云文件保存到本地
if (System.IO.File.Exists(savePath))
{
var fs = new FileStream(savePath, FileMode.Open, FileAccess.Read);
}
else
{
var aliossConfig = _fileService.GetAliOSSConfig();
OssClient client = new OssClient(aliossConfig.Endpoint, aliossConfig.AccessKeyId, aliossConfig.AccessKeySecret);
if (client.DoesObjectExist(aliossConfig.BucketName, model.FilePath))
{
var obj = client.GetObject(aliossConfig.BucketName, model.FilePath);
var requestStream = obj.Content;
// 使用FileStream将stream的内容写入到文件
using (var fileStream = new FileStream(savePath, FileMode.Create))
{
requestStream.CopyTo(fileStream);
}
}
else if (client.DoesObjectExist(aliossConfig.BucketName, model.DistrictCode + "/" + model.FilePath))
{
var obj = client.GetObject(aliossConfig.BucketName, model.DistrictCode + "/" + model.FilePath);
var requestStream = obj.Content;
// 使用FileStream将stream的内容写入到文件
using (FileStream fileStream = new FileStream(savePath, FileMode.Create))
{
// 将stream的内容复制到FileStream中
requestStream.CopyTo(fileStream);
}
}
}
#endregion
// 加载图片文件
XImage image = XImage.FromFile(mtfilename);
// 将 文件转换为 PDF 文档
PdfDocument document = PdfReader.Open(savePath, PdfDocumentOpenMode.Modify);
// 获取 PDF 最后一页
PdfPage page = document.Pages[document.Pages.Count - 1];
try
{
//查询该文件时间是否已经签名
var qmInfoNum = _schoolReportQm.GetDataCountByExpression(a => a.SchoolId == model.SchoolId && a.TaskId == model.TaskId && a.FileId == model.Id && a.IsQm == 1).Data;
if (qmInfoNum == 0)
{
// 添加一页到 PDF 文档
page = document.Pages.Add();
page.Width = XUnit.FromMillimeter(210);
page.Height = XUnit.FromMillimeter(297);
}
// 将图片绘制到 PDF 页面上
float width = 100;
float height = 50;
float x = 0;
float y = 0;
HasDataAtPosition(model.TaskId, out x, out y);
//加载图片,并调用DrawImage()方法在指定位置绘入图片
XGraphics gfx = XGraphics.FromPdfPage(page);
XRect rect = new XRect(x, y, width, height);
// 在页面上添加图像
gfx.DrawImage(image, rect);
img.Dispose();//释放
System.IO.File.Delete(mtfilename);//删除签名文件(手写板的图片)
System.IO.File.Delete(savePath);//删除从阿里云下的文件临时文件(不带签名的源文件)
// 保存 带有签名的 PDF 文档到文件
var attachSignatureUrl = (_webEnv.ContentRootPath + AppSetting.GetFilePath() + model.FileName).Replace("\\", "/");
document.Save(attachSignatureUrl);
var deleteflag = DeleteFile(fileId);//删除 阿里云和学校评估文件
if (deleteflag)
{
#region 上传带有签名的文件
var UploadType = int.Parse(_baseConfigService.GetSingle(UserInfo.DistrictCode, SystemId, BaseConfigKeyEnum.UploadType.ToString())?.Value ?? "1");
if (UploadType == 1)
{
var aliossConfig = _fileService.GetAliOSSConfig();
OssClient client = new OssClient(aliossConfig.Endpoint, aliossConfig.AccessKeyId, aliossConfig.AccessKeySecret);
using var stream = new FileStream(attachSignatureUrl, FileMode.Open, FileAccess.Read);
var aliresult = client.PutObject(aliossConfig.BucketName, model.FilePath, stream);
}
var newmode = new SchoolReportFileEntity()
{
Id = model.Id,
Year = SystemYear,
SchoolId = model.SchoolId,
DistrictCode = _schoolService.GetDataByExpressionFirst(s => s.Id == model.SchoolId && s.SystemId == SystemIdInt).Data.DistrictCode,
FileName = model.FileName,
NewFileName = model.NewFileName,
FileSize = model.FileSize,
FileType = model.FileType,
FilePath = model.FilePath,
CreateUser = UserInfo.Guid,
CreateTime = DateTime.Now,
UpdateUser = UserInfo.Guid,
UpdateTime = DateTime.Now,
ObjectType = int.Parse(SystemId),
PlanId = model.PlanId,
TaskId = model.TaskId
};
_schoolReport.AddReport(newmode);
var modelQm = new SchoolReportFileQmEntity()
{
Id = Guid.NewGuid().ToString(),
SchoolId = model.SchoolId,
FileId = newmode.Id,
FileName = model.FileName,
UserId = UserInfo.Guid,
PlanId = model.PlanId,
TaskId = model.TaskId,
CreateId = UserInfo.Guid,
CreateTime = DateTime.Now,
IsQm = 1
};
_schoolReportQm.AddReport(modelQm);
#endregion
document.Dispose();//释放文档
System.IO.File.Delete(attachSignatureUrl);//删除临时文件
}
// 关闭文档
document.Close();
}
catch (Exception)
{
img.Dispose();//释放
System.IO.File.Delete(mtfilename);//删除签名文件(手写板的图片)
System.IO.File.Delete(savePath);//删除从阿里云下的文件临时文件(不带签名的源文件)
if (page == null || document.Pages.Count >= 9)
{
document.Close(); // 关闭文档
return Json(RongboResult<int>.Failed(-101, "请确保,签字的PDF文件页数在8页以内"));
}
}
return Json(RongboResult<int>.Successed("", 1));
}
/// <summary>
/// 根据人员排序 确定签名位置
/// </summary>
/// <param name="taskId"></param>
/// <param name="x"></param>
/// <param name="y"></param>
public void HasDataAtPosition(string taskId,out float x, out float y)
{
var taskUserlst = _assessorsBll.GetPgUserByTaskId(taskId, "").Data.Select(a=>a.UserId).ToList();
int indexOfCurrentProgram = taskUserlst.IndexOf(UserInfo.Guid);
var ys = indexOfCurrentProgram % 5;//余数
var bs = indexOfCurrentProgram / 5;//倍数(每一行只能最多签名五个人)
x = 120 * ys;
y = 100 * bs;
}
/// <summary>
/// base64数据转化为图片文件
/// </summary>
/// <param name="strbase64"></param>
/// <param name="outputFilename"></param>
/// <returns></returns>
public bool Base64StringToImage(string strbase64, string outputFilename)
{
byte[] arr = Convert.FromBase64String(strbase64);
MemoryStream ms = new MemoryStream(arr);
System.Drawing.Image img = System.Drawing.Image.FromStream(ms);
img.Save(outputFilename);
img.Dispose();
if (System.IO.File.Exists(outputFilename))
{
return true;
}
return false;
}
/// <summary>
/// 删除阿里云文件
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public bool DeleteFile(string id)
{
var flag = false;
var model = _schoolReport.GetSchoolReport(id).Data;
var result = _schoolReport.DelReport(id);
//删除服务器上文件
if (result.Code == 0 && model != null && !string.IsNullOrEmpty(model.Id))
{
string savePath = (_webEnv.ContentRootPath + AppSetting.GetFilePath() + model.FilePath).Replace("\\", "/");
if (System.IO.File.Exists(savePath))
{
System.IO.File.Delete(savePath);
flag = true;
}
else
{
var aliossConfig = _fileService.GetAliOSSConfig();
OssClient client = new OssClient(aliossConfig.Endpoint, aliossConfig.AccessKeyId, aliossConfig.AccessKeySecret);
if (client.DoesObjectExist(aliossConfig.BucketName, model.FilePath))
{
client.DeleteObject(aliossConfig.BucketName, model.FilePath);
flag = true;
}
else if (client.DoesObjectExist(aliossConfig.BucketName, model.DistrictCode + "/" + model.FilePath))
{
client.DeleteObject(aliossConfig.BucketName, model.DistrictCode + "/" + model.FilePath);
flag = true;
}
}
}
return flag;
}