online_agree.html 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>在线签署</title>
  6. <meta content="IE=edge" http-equiv="X-UA-Compatible" />
  7. <meta content="yes" name="apple-mobile-web-app-capable" />
  8. <meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1">
  9. <meta content="black" name="apple-mobile-web-app-status-bar-style" />
  10. <link href="base.css" rel="stylesheet" type="text/css">
  11. <link href="layer/need/layer.css" rel="stylesheet" type="text/css">
  12. <script src="layer/layer.js" type="text/javascript"></script>
  13. <style>
  14. body, html {
  15. overflow: hidden;
  16. position: fixed;
  17. width: 100%;
  18. top: 0;
  19. left: 0;
  20. }
  21. canvas {
  22. background: white;
  23. border: 1px dashed black;
  24. position: absolute;
  25. top: 0;
  26. left: 0;
  27. }
  28. .top_bars {
  29. position: fixed;
  30. width: 40px;
  31. background: #f1f1f1;
  32. right: 0;
  33. top: 0
  34. }
  35. .tools {
  36. position: absolute;
  37. width: 1.3rem;
  38. height: .5rem;
  39. left: -18px;
  40. background: #495060;
  41. color: white;
  42. line-height: .5rem;
  43. text-align: center;
  44. transform: rotateZ(90deg);
  45. }
  46. .clearCanvas {
  47. bottom: 1.9rem;
  48. }
  49. .pencilOrMove {
  50. bottom: .5rem;
  51. }
  52. .finish {
  53. width: 1.3rem;
  54. bottom: 47%;
  55. background: #0590ff;
  56. }
  57. .reload {
  58. top: .5rem;
  59. }
  60. .tips {
  61. font-size: .32rem;
  62. text-align: center;
  63. position: fixed;
  64. top: 50%;
  65. left: -2.3rem;
  66. transform: rotate(90deg);
  67. z-index: 10;
  68. }
  69. .secondState {
  70. transform: rotate(90deg);
  71. z-index: 10;
  72. position: fixed;
  73. top: 50%;
  74. width: 8.4rem;
  75. left: 52px;
  76. font-size: 0.25rem;
  77. }
  78. .btn_put {
  79. border: 0;
  80. padding: 10px;
  81. color: white;
  82. border-radius: 4px;
  83. outline: none;
  84. }
  85. .btn_success {
  86. background: #58c73d;
  87. }
  88. .btn_fail {
  89. background: #d63c3c;
  90. }
  91. .flex_bottom {
  92. position: fixed;
  93. bottom: 10px;
  94. z-index: 90;
  95. display: flex;
  96. justify-content: space-around;
  97. align-items: center;
  98. width: 100%;
  99. }
  100. .mask {
  101. position: fixed;
  102. top: 0;
  103. left: 0;
  104. background: white;
  105. width: 100%;
  106. height: 100%;
  107. z-index: 40;
  108. }
  109. #canvas2 {
  110. width: 2480px;
  111. height: 3507px;
  112. }
  113. #resultImg{
  114. position:absolute;
  115. left:0;
  116. top:0;
  117. z-index: 50;
  118. }
  119. </style>
  120. </head>
  121. <body>
  122. <img src="" id="resultImg" width="100%" alt="" style="display: none" />
  123. <div class="mask" id="mask" style="display: none"></div>
  124. <canvas id="canvas2" width="2480" height="3507" style="display: none">无</canvas>
  125. <p class="tips" id="tips">(第一步)请在空白虚线区域内手写您的姓名</p>
  126. <div class="top_bars" id="top">
  127. <div class="tools clearCanvas" id="clear">清除文字</div>
  128. <div class="tools pencilOrMove" id="isUsePencil">移动签字板</div>
  129. <div class="tools finish" id="finish">提交签名</div>
  130. <div class="tools reload" id="reload">重新签署</div>
  131. </div>
  132. <div class="flex_bottom" style="visibility: hidden" id="flex_bottom">
  133. <button class="btn_put btn_success" id="btn_success">提交审核</button>
  134. <button class="btn_put btn_fail" id="btn_fail">重新签署</button>
  135. </div>
  136. <p class="secondState" id="secondState" style="display: none">"以上&lt;&lt;xxxxxxxx&gt;&gt;的各项内容,本人已阅读并确认无异议"</p>
  137. <canvas id="canvas" style="top:0">您的手机不支持在线签署</canvas>
  138. <script>
  139. var NAME = 0;//签名状态
  140. var STATEMENT = 1;//抄写状态
  141. var supportsPassive = false;
  142. var canvasPaint = {};//画布相关状态变量
  143. var events = null;//是移动端还是pc端
  144. var state = NAME;
  145. try {
  146. var opts = Object.defineProperty({}, 'passive', {
  147. get: function () {
  148. supportsPassive = true;
  149. }
  150. });
  151. window.addEventListener("test", null, opts);
  152. } catch (e) {
  153. }
  154. window.onload = function () {
  155. show_msg('请使用手机模式预览DEMO');
  156. canvasPaint.canPaint = true;//是否可以写字
  157. canvasPaint.piece = 17;//canvas的高度乘以了17倍(拖动画布功能)
  158. canvasPaint.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  159. canvasPaint.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
  160. document.getElementById("top").style.height = canvasPaint.height + 'px';
  161. canvasPaint.width = canvasPaint.width - 40;//预留工具栏宽度
  162. canvasPaint.clearBtn = document.getElementById("clear");
  163. canvasPaint.pencilBtn = document.getElementById("isUsePencil");
  164. canvasPaint.finish = document.getElementById("finish");
  165. canvasPaint.tips = document.getElementById("tips");
  166. canvasPaint.reload = document.getElementById("reload");
  167. canvasPaint.secondState = document.getElementById("secondState");
  168. canvasPaint.back = document.getElementById("back");
  169. canvasPaint.btn_success = document.getElementById("btn_success");
  170. canvasPaint.btn_fail = document.getElementById("btn_fail");
  171. if (state === NAME) {
  172. //签名模式隐藏拖动画布按钮
  173. canvasPaint.pencilBtn.style.display = 'none';
  174. }
  175. try {
  176. canvasPaint.canvas = document.getElementById("canvas");
  177. canvasPaint.ctx = document.getElementById("canvas").getContext("2d");
  178. canvasPaint.canvas.width = canvasPaint.width;
  179. canvasPaint.canvas.height = canvasPaint.height * canvasPaint.piece;
  180. canvasPaint.canvas.style.width = canvasPaint.canvas.width + 'px';
  181. canvasPaint.canvas.style.height = canvasPaint.canvas.height + 'px';
  182. } catch (e) {
  183. layer.open({
  184. content: '您的手机版本过低,不支持在线签署,请使用打印方式签字'
  185. , btn: ['确定'],
  186. shadeClose: false
  187. , yes: function (index) {
  188. layer.close(index);
  189. location.reload();
  190. }
  191. });
  192. }
  193. canvasPaint.ctx.lineCap = 'round';
  194. canvasPaint.ctx.lineJoin = 'round';
  195. canvasPaint.ctx.strokeWidth = 8;
  196. canvasPaint.ctx.lineWidth = 8;
  197. canvasPaint.isSupportTouch = ("ontouchstart" in document);
  198. events = ('ontouchstart' in window) ? ['touchstart', 'touchmove', 'touchend'] : ['mousedown', 'mousemove', 'mouseup'];
  199. canvasPaint.canvas.addEventListener(events[0], startEventHandler, supportsPassive ? {passive: false} : false);
  200. canvasPaint.clearBtn.addEventListener(events[0], clearCanvas, false);
  201. canvasPaint.pencilBtn.addEventListener(events[0], togglePencil, false);
  202. canvasPaint.finish.addEventListener(events[0], finish, false);
  203. canvasPaint.reload.addEventListener(events[0], reload, false);
  204. canvasPaint.btn_fail.addEventListener(events[0], reload, false);
  205. canvasPaint.btn_success.addEventListener(events[0], putImg, false);
  206. };
  207. //清除画布
  208. function clearCanvas() {
  209. canvasPaint.ctx.clearRect(0, 0, canvasPaint.canvas.width, canvasPaint.canvas.height);
  210. }
  211. //根据base64加载图片
  212. function preLoadImg(source, callBack, args) {
  213. var pr = [];
  214. for (var i = 0; i < source.length; i++) {
  215. var p = loadImage(source[i])
  216. .then(function (img) {
  217. return img;
  218. })
  219. .catch(function (err) {
  220. alert("绘制失败,您的手机不支持在线签署");
  221. });
  222. pr.push(p);
  223. }
  224. Promise.all(pr)
  225. .then(function (imgArray) {
  226. callBack(imgArray, args);
  227. });
  228. }
  229. function loadImage(url) {
  230. return new Promise((resolve, reject) => {
  231. var img = new Image();
  232. img.onload = function () {
  233. resolve(img);
  234. };
  235. img.onerror = reject;
  236. img.src = url;
  237. });
  238. }
  239. //点击完成时的逻辑处理函数
  240. function finish() {
  241. canvasPaint.layerIndex = layer.open({type: 2, shadeClose: false});//遮罩
  242. if (state === NAME) {
  243. //加载模板图和签的字,回调函数是result函数
  244. preLoadImg(['agree.jpg', canvasPaint.canvas.toDataURL()], result);
  245. }
  246. if (state === STATEMENT) {
  247. //加载抄的字,回调函数是stateResult函数
  248. preLoadImg([canvasPaint.canvas.toDataURL()], stateResult);
  249. }
  250. }
  251. function stateResult(imgArr) {
  252. try {
  253. statementDraw(imgArr);
  254. canvasPaint.canvas.removeEventListener(events[0], startEventHandler, false);
  255. document.removeEventListener(events[0], documentStartEventHandler, false);
  256. layer.close(canvasPaint.layerIndex);
  257. } catch (e) {
  258. layer.close(canvasPaint.layerIndex);
  259. alert('绘制失败');
  260. }
  261. }
  262. function result(imgArr) {
  263. try {
  264. drawName(imgArr);
  265. layer.close(canvasPaint.layerIndex);
  266. } catch (e) {
  267. layer.close(canvasPaint.layerIndex);
  268. alert('绘制失败');
  269. }
  270. }
  271. //绘制抄写的句子的方法
  272. function statementDraw(imgArr) {
  273. canvasPaint.context2.save();
  274. canvasPaint.context2.translate(490, 3085);
  275. canvasPaint.context2.rotate(270 * Math.PI / 180);
  276. canvasPaint.context2.drawImage(imgArr[0], 80, 50, 80, 80 * canvasPaint.ratio);//画反转后的名字
  277. canvasPaint.context2.restore();
  278. // console.log(canvasPaint.canvas2.toDataURL());
  279. document.getElementById('resultImg').setAttribute('src', canvasPaint.canvas2.toDataURL());
  280. document.getElementById('resultImg').style.display = "block";
  281. document.getElementById('mask').style.display = "block";
  282. document.getElementById('flex_bottom').style.visibility = "visible";
  283. canvasPaint.imgResult = canvasPaint.canvas2.toDataURL();
  284. console.warn(canvasPaint.imgResult);
  285. show_msg('到控制台拷贝Base64到浏览器地址可查看大图');
  286. }
  287. //抄句子前的预处理
  288. function prevDrawStatement() {
  289. clearCanvas();//清除名字
  290. canvasPaint.finish.innerHTML = "提交抄写";
  291. canvasPaint.pencilBtn.style.display = 'block';
  292. canvasPaint.secondState.style.display = 'block';
  293. canvasPaint.tips.innerHTML = "(最后一步)请抄写屏幕上方引号内的确认语句";
  294. canvasPaint.tips.style.color = 'red';
  295. setTimeout(function () {
  296. canvasPaint.tips.style.color = '#666';
  297. }, 2000);
  298. state = STATEMENT;//开始写句子
  299. }
  300. //写名字的函数
  301. function drawName(imgArr) {
  302. //绘制名字和底部的名字和日期
  303. canvasPaint.canvas2 = document.getElementById('canvas2');
  304. canvasPaint.context2 = canvasPaint.canvas2.getContext('2d');
  305. canvasPaint.ratio = canvasPaint.canvas.height / canvasPaint.canvas.width;
  306. canvasPaint.context2.drawImage(imgArr[0], 0, 0, 2480, 3507);//img0是底图原合同
  307. canvasPaint.context2.save();
  308. canvasPaint.context2.translate(455, 612);//1
  309. canvasPaint.context2.rotate(270 * Math.PI / 180);
  310. canvasPaint.context2.drawImage(imgArr[1], 80, 50, 70, 70 * canvasPaint.ratio);//画反转后的名字
  311. canvasPaint.context2.restore();
  312. canvasPaint.context2.save();
  313. canvasPaint.context2.translate(550, 3210);//下方的字 2
  314. canvasPaint.context2.rotate(270 * Math.PI / 180);
  315. canvasPaint.context2.drawImage(imgArr[1], 80, 50, 70, 70 * canvasPaint.ratio);//画反转后的名字
  316. canvasPaint.context2.restore();
  317. canvasPaint.context2.save();
  318. canvasPaint.context2.translate(1920, 3100);//下方的字
  319. canvasPaint.context2.font = "32px bold 微软雅黑";
  320. canvasPaint.context2.fillStyle = "#000";
  321. canvasPaint.context2.textAlign = "center";
  322. canvasPaint.context2.textBaseline = "middle";
  323. var date = new Date();
  324. var Y = date.getFullYear() + '/';
  325. var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '/';
  326. var D = date.getDate();
  327. canvasPaint.context2.fillText((Y + M + D), 0, 0);
  328. canvasPaint.context2.restore();
  329. prevDrawStatement();
  330. }
  331. //是否写字的逻辑(拖动画布)
  332. function togglePencil() {
  333. if (canvasPaint.canPaint) {
  334. canvasPaint.canPaint = false;
  335. canvasPaint.pencilBtn.innerText = "使用签字笔";
  336. //不能签字时应该把开始事件去掉,同时加上document事件
  337. canvasPaint.canvas.removeEventListener(events[0], startEventHandler, false);
  338. document.addEventListener(events[0], documentStartEventHandler, supportsPassive ? {passive: false} : false);
  339. } else {
  340. canvasPaint.canPaint = true;
  341. canvasPaint.pencilBtn.innerText = "移动签字板";
  342. //能签字时应该把开始事件绑定上去,同时去掉document事件
  343. canvasPaint.canvas.addEventListener(events[0], startEventHandler, supportsPassive ? {passive: false} : false);
  344. document.removeEventListener(events[0], documentStartEventHandler, false);
  345. }
  346. }
  347. function reload() {
  348. location.reload();
  349. }
  350. function documentStartEventHandler(event) {
  351. event.preventDefault();
  352. var evt = canvasPaint.isSupportTouch ? event.touches[0] : event;
  353. canvasPaint.y = evt.clientY;
  354. canvasPaint.top = parseFloat(canvasPaint.canvas.style.top);
  355. document.addEventListener(events[1], documentMoveEventHandler, supportsPassive ? {passive: false} : false);
  356. document.addEventListener(events[2], documentEndEventHandler, supportsPassive ? {passive: false} : false);
  357. }
  358. function documentMoveEventHandler(event) {
  359. event.preventDefault();
  360. var evt = canvasPaint.isSupportTouch ? event.touches[0] : event;
  361. canvasPaint.newY = evt.clientY - canvasPaint.y;
  362. if (canvasPaint.canPaint === false) {
  363. //边界的判断
  364. canvasPaint.canvas.style.top = canvasPaint.newY + canvasPaint.top + 'px';
  365. if (parseFloat(canvasPaint.canvas.style.top) > 0) {
  366. canvasPaint.canvas.style.top = 0 + 'px';
  367. }
  368. if (Math.abs(parseFloat(canvasPaint.canvas.style.top)) > canvasPaint.canvas.height - canvasPaint.canvas.height / canvasPaint.piece) {
  369. canvasPaint.canvas.style.top = -(canvasPaint.canvas.height - canvasPaint.canvas.height / canvasPaint.piece) + 'px';
  370. }
  371. }
  372. }
  373. function documentEndEventHandler(event) {
  374. event.preventDefault();
  375. }
  376. function startEventHandler(event) {
  377. event.preventDefault();
  378. canvasPaint.ctx.beginPath();
  379. canvasPaint.canvas.addEventListener(events[1], moveEventHandler, supportsPassive ? {passive: false} : false);
  380. canvasPaint.canvas.addEventListener(events[2], endEventHandler, supportsPassive ? {passive: false} : false);
  381. }
  382. function moveEventHandler(event) {
  383. event.preventDefault();
  384. var evt = canvasPaint.isSupportTouch ? event.touches[0] : event;
  385. var coverPos = canvasPaint.canvas.getBoundingClientRect();
  386. canvasPaint.mouseX = evt.clientX - coverPos.left;
  387. canvasPaint.mouseY = evt.clientY - coverPos.top;
  388. if (canvasPaint.canPaint === true) {
  389. //根据坐标绘制
  390. canvasPaint.ctx.lineTo(
  391. canvasPaint.mouseX,
  392. canvasPaint.mouseY
  393. );
  394. canvasPaint.ctx.stroke();
  395. }
  396. }
  397. function endEventHandler(event) {
  398. event.preventDefault();
  399. canvasPaint.canvas.removeEventListener(events[1], moveEventHandler, false);
  400. canvasPaint.canvas.removeEventListener(events[2], endEventHandler, false);
  401. }
  402. //提交图片
  403. function putImg() {
  404. canvasPaint.layerIndex = layer.open({type: 2, shadeClose: false});
  405. var formData = new FormData();
  406. var file = canvasPaint.imgResult;
  407. formData.append('record', file);
  408. console.log('模拟成功');
  409. layer.open({
  410. content: '上传成功,请等待审核'
  411. , btn: ['确定'],
  412. shadeClose: false
  413. , yes: function (index) {
  414. location.reload();
  415. layer.close(index);
  416. },
  417. });
  418. layer.close(canvasPaint.layerIndex);
  419. /*$.ajax({
  420. url: "agreement_img",
  421. type: 'POST',
  422. data: formData,
  423. processData: false,
  424. contentType: false,
  425. success: function (data) {
  426. layer.close(canvasPaint.layerIndex);
  427. if (data.code === 200) {
  428. layer.open({
  429. content: '上传成功,请等待审核'
  430. , btn: ['确定'],
  431. shadeClose: false
  432. , yes: function (index) {
  433. location.reload();
  434. layer.close(index);
  435. },
  436. });
  437. } else {
  438. layer.close(canvasPaint.layerIndex);
  439. show_msg('上传失败,请重试');
  440. }
  441. },
  442. error: function (error) {
  443. layer.close(canvasPaint.layerIndex);
  444. show_msg('上传失败,请重试');
  445. }
  446. });*/
  447. }
  448. function show_msg(content) {
  449. layer.open({
  450. content: content
  451. , skin: 'msg'
  452. , time: 5
  453. });
  454. }
  455. </script>
  456. </body>
  457. </html>