tmsSign.html 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  1. <!doctype html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <meta content="yes" name="apple-mobile-web-app-capable">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  7. <title>Hello APP</title>
  8. <link rel="stylesheet" type="text/css" href="../../../../../css/api.css" />
  9. <link rel="stylesheet" type="text/css" href="../../../../../css/aui-win.css" />
  10. <link rel="stylesheet" type="text/css" href="../../../../../css/css/vant-ui.css" />
  11. <link rel="stylesheet" type="text/css" href="../../../../../css/css/iconfont.css">
  12. <script src="../../../../../script/js/vue.js"></script>
  13. <script src="../../../../../script/js/vant-ui.js"></script>
  14. <script src="../../../../../script/js/auto-size.js"></script>
  15. <script src="../../../../../script/js/pdfjs-2.5.207-es5-dist/build/pdf.js"></script>
  16. <script src="../../../../../script/js/pdf_plugins.js"></script>
  17. <style>
  18. .flex{
  19. display: flex;
  20. }
  21. #app{}
  22. #aui-header{
  23. background: linear-gradient(to right,#1474E4,#14A7E4);
  24. justify-content: space-between;
  25. align-items: center;
  26. }
  27. #scrollcontaier{
  28. overflow-y: auto;
  29. }
  30. .aui-btn-info{
  31. border: 0
  32. }
  33. .title{
  34. padding: 10px 12px;
  35. color: #ffffff;
  36. }
  37. .image-icon{
  38. width: .66rem;
  39. height: .66rem;
  40. margin-right: 19px;
  41. }
  42. img{
  43. width: 100%;
  44. height: 100%;
  45. }
  46. .nav{
  47. width: 10.1rem;
  48. height: 1.44rem;
  49. margin: .28rem auto 0;
  50. justify-content: space-between;
  51. align-items: center;
  52. background: url("../../../../../image/icon/hedui.png") no-repeat 0 0;
  53. background-size: 100% auto;
  54. }
  55. .details-btn{
  56. height: .96rem;
  57. line-height: .96rem;
  58. padding: 0 .38rem;
  59. border-radius: 0.08rem;
  60. background: #1474E4;
  61. color: #ffffff;
  62. margin-right: .24rem;
  63. }
  64. .details-wrap{
  65. background: #ffffff;
  66. box-sizing: border-box;
  67. width: 10.1rem;
  68. margin: 0.36rem auto 0;
  69. border-radius: 0.08rem;
  70. padding: .4rem;
  71. }
  72. .canvas-container{
  73. position: relative;
  74. }
  75. #canvas{
  76. width: 9.45rem;
  77. height: 2.39rem;
  78. background: url("../../../../../image/icon/noimage.png") #e1e5e2 no-repeat 0 0;
  79. background-size: 100% auto;
  80. }
  81. .scale-btn{
  82. position: absolute;
  83. top: 0;
  84. right: -.13rem;
  85. width: 0;
  86. height: 0;
  87. border-bottom: .8rem solid transparent;
  88. border-right: .8rem solid #1474E4;
  89. border-left: .8rem solid transparent;
  90. }
  91. .scale-btn span{
  92. display: inline-block;
  93. width: .32rem;
  94. height: .32rem;
  95. position: absolute;
  96. top: 0;
  97. right: -.7rem;
  98. }
  99. .scale-btn span img{
  100. width: 100%;
  101. height: 100%;
  102. }
  103. .text-msg{
  104. color: #595959;
  105. }
  106. .field-container{
  107. background: #F5F5F5;
  108. }
  109. .signature{
  110. /*height: 3.2rem;*/
  111. width: 100%;
  112. }
  113. .signature p{
  114. color: #595959;
  115. }
  116. .esign-box{
  117. background: rgba(236,236,236,.5) url(../../../../../image/icon/qianming.png) no-repeat 50%;
  118. width: 9.42rem;
  119. height: 4.54rem;
  120. }
  121. .esigh-btns{
  122. margin-top: 10px;
  123. }
  124. .confirm-btn-container{
  125. justify-content: center;
  126. width: 10.1rem;
  127. margin: .4rem auto;
  128. }
  129. .confirm-btn{
  130. background: linear-gradient(to right, #F09623, #FFCF4C);
  131. /*padding: 0 1.18rem;*/
  132. height: .96rem;
  133. width: 10.1rem;
  134. line-height: .96rem;
  135. border-radius: .48rem;
  136. color: #ffffff;
  137. font-size: .42rem;
  138. text-align: center;
  139. margin: .42rem auto;
  140. }
  141. </style>
  142. </head>
  143. <style>
  144. </style>
  145. <body>
  146. <div id="app">
  147. <header class="flex flex-between" id="aui-header">
  148. <a class="aui-btn aui-btn-info aui-pull-left" tapmode onclick="closeWin()"> <span class="aui-iconfont aui-icon-left"></span> </a>
  149. <div class="title">签收</div>
  150. <div class="image-icon" @click="handleGoInstructions"><img src="../../../../../image/icon/zhiyinshuoming.png" alt=""></div>
  151. </header>
  152. <div id="scrollcontaier" ref="scrollcontaier">
  153. <div class="nav flex"><span></span><span class="details-btn" @click="handleGo">核对明细<van-icon name="arrow" /></span></div>
  154. <div class="details-wrap">
  155. <div class="canvas-container">
  156. <div id="canvas" ref="canvas"></div>
  157. <div class="scale-btn"><span @click='handleScale'><img src="../../../../../image/icon/fangda.png" alt="放大"></span></div>
  158. </div>
  159. <van-divider ></van-divider>
  160. <div class="signature">
  161. <p>请在空白处签名~</p>
  162. <div class="esign-box" ref="esignbox">
  163. <canvas ref="signcanvas" id="signcanvas" width="300" height="300"
  164. @mousedown="mouseDown"
  165. @mousemove="mouseMove"
  166. @mouseup="mouseUp"
  167. @touchstart="touchStart"
  168. @touchmove="touchMove"
  169. @touchend="touchEnd"></canvas>
  170. </div>
  171. <div class="esigh-btns">
  172. <button @click="reset">清空画板</button>
  173. </div>
  174. </div>
  175. <van-divider ></van-divider>
  176. <p class="text-msg">若您收到的货物与订单存在差异,可上传相关图片及描述,我们会及时处理。</p>
  177. <van-row class="image-container" gutter="20">
  178. <van-uploader v-model="fileList" multiple="true"/>
  179. </van-row>
  180. <van-field
  181. class="field-container"
  182. v-model="remark"
  183. rows="2"
  184. autosize
  185. type="textarea"
  186. maxlength="50"
  187. placeholder="请输入备注~"
  188. show-word-limit
  189. ref="remark"
  190. ></van-field>
  191. </div>
  192. <div class="list-item-row confirm-btn-container flex">
  193. <van-button color="linear-gradient(to right, #F09623, #FFCF4C)" :block="true" round :loading="submitLoading" type="info" loading-type="spinner" loading-text="加载中..." v-on:click="handleSubmit">提交</van-button>
  194. </div>
  195. </div>
  196. </div>
  197. </body>
  198. <script type="text/javascript" src="../../../../../script/aui_compress.min.js"></script>
  199. <script type="text/javascript" src="../../../../../script/api.js"></script>
  200. <link rel="stylesheet" href="../../../../../script/mescroll/mescroll.min.css">
  201. <script type="text/javascript" src="../../../../../script/mescroll/mescroll.min.js"></script>
  202. <script type="text/javascript" src="../../../js/httpRequest_sub.js"></script>
  203. <script type="text/javascript" src="../../../js/vue_plugins_sub.js"></script>
  204. <script type="text/javascript" src="../../../../../script/jquery-1.11.0.min.js"></script>
  205. <script type="text/javascript">
  206. function closeWin() {
  207. api.closeWin({
  208. });
  209. }
  210. apiready = function() {
  211. api.parseTapmode();
  212. var header = $api.byId('aui-header');
  213. $api.fixStatusBar(header);
  214. var headerPos = $api.offset(header);
  215. var body_h = $api.offset($api.dom('body')).h;
  216. document.getElementById("scrollcontaier").style.height = $api.offset($api.dom('body')).h - headerPos.h + "px";
  217. var tknum = api.pageParam.tknum;
  218. var kunnrWe = api.pageParam.kunnrWe;
  219. var vbelnList = api.pageParam.vbelnList;
  220. var kunnrWeName = api.pageParam.kunnrWeName;
  221. var wallBillDriver = api.pageParam.wallBillDriver;
  222. var grossWeight = api.pageParam.grossWeight;
  223. var lifmg = api.pageParam.lifmg;
  224. new Vue({
  225. el: '#app',
  226. data: {
  227. token: $api.getStorage('loginToken'),
  228. tknum: tknum,
  229. kunnrWe: kunnrWe,
  230. vbelnList: vbelnList,
  231. kunnrWeName:kunnrWeName,
  232. wallBillDriver:wallBillDriver,
  233. grossWeight: grossWeight,
  234. lifmg: lifmg,
  235. remark: "",
  236. formdata: new FormData(),
  237. pdfReader: "",
  238. imageUrls: "",
  239. imageList: [],
  240. fileList: [],
  241. message: "",
  242. submitLoading: false,
  243. width:300,
  244. height: 300,
  245. lineWidth: 6,
  246. lineColor: '#000000',
  247. bgColor: '',
  248. isCrop: false,
  249. hasDrew: false,
  250. resultImg: '',
  251. points: [],
  252. canvasTxt: null,
  253. startX: 0,
  254. startY: 0,
  255. isDrawing: false,
  256. sratio: 1
  257. },
  258. computed: {
  259. ratio () {
  260. return this.height / this.width
  261. },
  262. stageInfo () {
  263. return this.$refs.signcanvas.getBoundingClientRect()
  264. },
  265. myBg () {
  266. return this.bgColor ? this.bgColor : 'rgba(255, 255, 255, 0)'
  267. }
  268. },
  269. watch: {
  270. 'myBg': function (newVal) {
  271. this.$refs.signcanvas.style.background = newVal
  272. }
  273. },
  274. beforeMount () {
  275. window.addEventListener('resize', this.$_resizeHandler)
  276. },
  277. beforeDestroy () {
  278. window.removeEventListener('resize', this.$_resizeHandler)
  279. },
  280. filters:{
  281. },
  282. mounted: function() {
  283. //月度pdf文件
  284. this.pdfReader = api.require('pdfReader');
  285. // pdf展示成图片
  286. var canvasWidth=this.$refs.canvas.offsetWidth,canvasHeight=this.$refs.canvas.offsetHeight;
  287. if (this.wallBillDriver) {
  288. $canvasPdf.loadPDF(this.wallBillDriver,canvasWidth,canvasHeight);
  289. }
  290. // 电子签名
  291. this.width = this.$refs.esignbox.offsetWidth;
  292. this.height = this.$refs.esignbox.offsetHeight;
  293. var canvas = this.$refs.signcanvas;
  294. canvas.height = this.height;
  295. canvas.width = this.width;
  296. canvas.style.background = this.myBg;
  297. this.$_resizeHandler();
  298. // 在画板以外松开鼠标后冻结画笔
  299. document.onmouseup = function() {
  300. this.isDrawing = false;
  301. }
  302. },
  303. methods:{
  304. handleScale: function(){
  305. var _this = this;
  306. this.pdfReader.open({
  307. path: _this.wallBillDriver,//"https://srmapi.sailuntire.com/Files/20201221/20200000000186-3000100-8379-Out.pdf",
  308. hidden: {
  309. print: true,
  310. export: true,
  311. bookmark: true,
  312. email: true
  313. },
  314. backBtn: {
  315. size: { //JSON对象;左上角按钮的大小配置
  316. w: 20, //数字类型;左上角按钮的宽;默认:60
  317. h: 20 //数字类型;左上角按钮的高;默认:40
  318. },
  319. title: { //JSON对象;按钮标题配置
  320. text: "返回", //字符串类型;标题文本;默认:‘’
  321. },
  322. corner: 5 //数字类型;左上角按钮圆角大小;默认值:5.0
  323. }
  324. });
  325. },
  326. handleSubmit: function(){
  327. this.generate();
  328. if(this.resultImg==""||this.resultImg==null){
  329. api.toast({
  330. msg: '您还没签名!',
  331. duration: 2000,
  332. location: 'bottom'
  333. });
  334. return;
  335. };
  336. if(this.fileList.length>0){
  337. for(var i=0; i<this.fileList.length; i++){
  338. this.formdata.append('upload',this.fileList[i].file);
  339. }
  340. };
  341. this.formdata.append("token", this.token);
  342. this.formdata.append("signImg", this.resultImg);
  343. this.formdata.append("tknum", this.tknum);
  344. this.formdata.append("kunnrWe", this.kunnrWe);
  345. this.formdata.append("remark", this.remark);
  346. var _this = this;
  347. this.submitLoading = true;
  348. //测试地址:https://b2bcnapi.sailuntire.com/api/test/b2bapi/action/api/tms/signOperate.xhtml
  349. // 正式地址:测试地址:https://b2bcnapi.sailuntire.com/api/b2bapi/action/api/tms/signOperate.xhtml
  350. $.ajax({
  351. url: "https://b2bcnapi.sailuntire.com/api/b2bapi/action/api/tms/signOperate.xhtml",
  352. type: "POST",
  353. data: _this.formdata,
  354. processData: false, // 告诉jQuery不要去处理发送的数据
  355. contentType: false, // 告诉jQuery不要去设置Content-Type请求头
  356. success: function(ret, status, xhr) {
  357. // api.hideProgress();
  358. _this.submitLoading = false;
  359. if (ret.code == 1 || ret.code == '1') {
  360. api.toast({
  361. msg: '上传成功'
  362. });
  363. api.sendEvent({
  364. name: 'refusuTmsList'
  365. });
  366. api.closeWin();
  367. } else {
  368. api.toast({
  369. msg: ret.message
  370. });
  371. }
  372. }
  373. });
  374. },
  375. handleGo: function(){
  376. var params = {
  377. tknum: this.tknum,
  378. vbelnList: this.vbelnList,
  379. kunnrWeName: this.kunnrWeName,
  380. grossWeight: this.grossWeight,
  381. lifmg: this.lifmg
  382. };
  383. this.goWin("tmsdetails","./tmsDetails.html",params);
  384. },
  385. handleGoInstructions: function(){
  386. var _this = this;
  387. // this.goWin("tmsinstructions","./tmsInstructions.html");//操作视频
  388. this.pdfReader.open({
  389. path: "https://b2bcnfile.sailuntire.com/upload/TMS/operationManual/TMS销售出库单签收的操作手册.pdf",//"https://srmapi.sailuntire.com/Files/20201221/20200000000186-3000100-8379-Out.pdf",
  390. hidden: {
  391. print: true,
  392. export: true,
  393. bookmark: true,
  394. email: true
  395. },
  396. backBtn: {
  397. size: { //JSON对象;左上角按钮的大小配置
  398. w: 20, //数字类型;左上角按钮的宽;默认:60
  399. h: 20 //数字类型;左上角按钮的高;默认:40
  400. },
  401. title: { //JSON对象;按钮标题配置
  402. text: "返回", //字符串类型;标题文本;默认:‘’
  403. },
  404. corner: 5 //数字类型;左上角按钮圆角大小;默认值:5.0
  405. }
  406. });
  407. },
  408. $_resizeHandler () {
  409. var canvas = this.$refs.signcanvas;
  410. canvas.style.width = this.width + "px"
  411. var realw = parseFloat(window.getComputedStyle(canvas).width)
  412. canvas.style.height = this.ratio * realw + "px";
  413. this.canvasTxt = canvas.getContext('2d')
  414. this.canvasTxt.scale(1 * this.sratio, 1 * this.sratio)
  415. this.sratio = realw / this.width
  416. this.canvasTxt.scale(1 / this.sratio, 1 / this.sratio)
  417. },
  418. // pc
  419. mouseDown (e) {
  420. e = e || event
  421. e.preventDefault()
  422. this.isDrawing = true
  423. this.hasDrew = true
  424. var obj = {
  425. x: e.offsetX,
  426. y: e.offsetY
  427. }
  428. this.drawStart(obj)
  429. },
  430. mouseMove (e) {
  431. e = e || event
  432. e.preventDefault()
  433. if (this.isDrawing) {
  434. var obj = {
  435. x: e.offsetX,
  436. y: e.offsetY
  437. }
  438. this.drawMove(obj)
  439. }
  440. },
  441. mouseUp (e) {
  442. e = e || event
  443. e.preventDefault()
  444. var obj = {
  445. x: e.offsetX,
  446. y: e.offsetY
  447. }
  448. this.drawEnd(obj)
  449. this.isDrawing = false
  450. },
  451. // mobile
  452. touchStart (e) {
  453. this.$refs.remark.blur();
  454. e = e || event
  455. e.preventDefault()
  456. this.hasDrew = true
  457. if (e.touches.length === 1) {
  458. var obj = {
  459. x: e.targetTouches[0].clientX - this.$refs.signcanvas.getBoundingClientRect().left,
  460. y: e.targetTouches[0].clientY - this.$refs.signcanvas.getBoundingClientRect().top
  461. }
  462. this.drawStart(obj)
  463. }
  464. },
  465. touchMove (e) {
  466. e = e || event
  467. e.preventDefault()
  468. if (e.touches.length === 1) {
  469. var obj = {
  470. x: e.targetTouches[0].clientX - this.$refs.signcanvas.getBoundingClientRect().left,
  471. y: e.targetTouches[0].clientY - this.$refs.signcanvas.getBoundingClientRect().top
  472. }
  473. this.drawMove(obj)
  474. }
  475. },
  476. touchEnd (e) {
  477. e = e || event
  478. e.preventDefault()
  479. if (e.touches.length === 1) {
  480. var obj = {
  481. x: e.targetTouches[0].clientX - this.$refs.signcanvas.getBoundingClientRect().left,
  482. y: e.targetTouches[0].clientY - this.$refs.signcanvas.getBoundingClientRect().top
  483. }
  484. this.drawEnd(obj)
  485. }
  486. },
  487. // 绘制
  488. drawStart (obj) {
  489. this.startX = obj.x
  490. this.startY = obj.y
  491. this.canvasTxt.beginPath()
  492. this.canvasTxt.moveTo(this.startX, this.startY)
  493. this.canvasTxt.lineTo(obj.x, obj.y)
  494. this.canvasTxt.lineCap = 'round'
  495. this.canvasTxt.lineJoin = 'round'
  496. this.canvasTxt.lineWidth = this.lineWidth * this.sratio;
  497. this.canvasTxt.stroke()
  498. this.canvasTxt.closePath()
  499. this.points.push(obj)
  500. },
  501. drawMove (obj) {
  502. this.canvasTxt.beginPath()
  503. this.canvasTxt.moveTo(this.startX, this.startY)
  504. this.canvasTxt.lineTo(obj.x, obj.y)
  505. this.canvasTxt.strokeStyle = this.lineColor
  506. this.canvasTxt.lineWidth = this.lineWidth * this.sratio
  507. this.canvasTxt.lineCap = 'round'
  508. this.canvasTxt.lineJoin = 'round'
  509. this.canvasTxt.stroke()
  510. this.canvasTxt.closePath()
  511. this.startY = obj.y
  512. this.startX = obj.x
  513. this.points.push(obj)
  514. },
  515. drawEnd (obj) {
  516. this.canvasTxt.beginPath()
  517. this.canvasTxt.moveTo(this.startX, this.startY)
  518. this.canvasTxt.lineTo(obj.x, obj.y)
  519. this.canvasTxt.lineCap = 'round'
  520. this.canvasTxt.lineJoin = 'round'
  521. this.canvasTxt.stroke()
  522. this.canvasTxt.closePath()
  523. this.points.push(obj)
  524. this.points.push({x: -1, y: -1})
  525. },
  526. // 操作
  527. generate () {
  528. var pm = new Promise((resolve, reject) => {
  529. if (!this.hasDrew) {
  530. reject(`Warning: Not Signned!`)
  531. return
  532. }
  533. var resImgData = this.canvasTxt.getImageData(0, 0, this.$refs.signcanvas.width, this.$refs.signcanvas.height)
  534. this.canvasTxt.globalCompositeOperation = "destination-over"
  535. this.canvasTxt.fillStyle = this.myBg
  536. this.canvasTxt.fillRect(0,0,this.$refs.signcanvas.width ,this.$refs.signcanvas.height)
  537. this.resultImg = this.$refs.signcanvas.toDataURL()
  538. var resultImg = this.resultImg
  539. this.canvasTxt.clearRect(0, 0, this.$refs.signcanvas.width ,this.$refs.signcanvas.height)
  540. this.canvasTxt.putImageData(resImgData, 0, 0)
  541. this.canvasTxt.globalCompositeOperation = "source-over"
  542. if (this.isCrop) {
  543. var crop_area = this.getCropArea(resImgData.data)
  544. var crop_canvas = document.createElement('canvas')
  545. var crop_ctx = crop_canvas.getContext('2d')
  546. crop_canvas.width = crop_area[2] - crop_area[0]
  547. crop_canvas.height = crop_area[3] - crop_area[1]
  548. var crop_imgData = this.canvasTxt.getImageData(...crop_area)
  549. crop_ctx.globalCompositeOperation = "destination-over"
  550. crop_ctx.putImageData(crop_imgData, 0, 0)
  551. crop_ctx.fillStyle = this.myBg
  552. crop_ctx.fillRect(0, 0, crop_canvas.width , crop_canvas.height)
  553. resultImg = crop_canvas.toDataURL()
  554. crop_canvas = null
  555. }
  556. resolve(resultImg)
  557. })
  558. return pm
  559. },
  560. reset () {
  561. this.canvasTxt.clearRect(
  562. 0,
  563. 0,
  564. this.$refs.signcanvas.width,
  565. this.$refs.signcanvas.height
  566. )
  567. this.$emit('update:bgColor', '')
  568. this.$refs.signcanvas.style.background = 'rgba(255, 255, 255, 0)'
  569. this.points = []
  570. this.hasDrew = false
  571. this.resultImg = ''
  572. },
  573. getCropArea (imgData) {
  574. var topX = this.$refs.signcanvas.width; var btmX = 0; var topY = this.$refs.signcanvas.height; var btnY = 0
  575. for (var i = 0; i < this.$refs.signcanvas.width; i++) {
  576. for (var j = 0; j < this.$refs.signcanvas.height; j++) {
  577. var pos = (i + this.$refs.signcanvas.width * j) * 4
  578. if (imgData[pos] > 0 || imgData[pos + 1] > 0 || imgData[pos + 2] || imgData[pos + 3] > 0) {
  579. btnY = Math.max(j, btnY)
  580. btmX = Math.max(i, btmX)
  581. topY = Math.min(j, topY)
  582. topX = Math.min(i, topX)
  583. }
  584. }
  585. }
  586. topX++
  587. btmX++
  588. topY++
  589. btnY++
  590. var data = [topX, topY, btmX, btnY]
  591. return data
  592. }
  593. }
  594. })
  595. };
  596. </script>
  597. </html>