血透系统pad前端

ElectronicSignature.vue 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. <template>
  2. <div class="mainBox">
  3. <side-bar :active_index="3"></side-bar>
  4. <div class="mainContent">
  5. <h1 class="title">
  6. <div class="GoBack" @click="$router.go(-1)">
  7. <span class="iconfont">&#xe720;</span>返回
  8. </div>
  9. <span class="name">电子签名</span>
  10. <div class="GoBack"></div>
  11. </h1>
  12. <div class="information">
  13. <div class="blueBorder"></div>
  14. <div class="name" v-show="showpan=='canvas'">
  15. <canvas
  16. id="canvas"
  17. class="fl"
  18. width="600"
  19. height="400"
  20. @mousedown="canvasDown($event)"
  21. @mouseup="canvasUp($event)"
  22. @mousemove="canvasMove($event)"
  23. @touchstart="canvasDown($event)"
  24. @touchend="canvasUp($event)"
  25. @touchmove="canvasMove($event)"
  26. ></canvas>
  27. </div>
  28. <div class="imagename" v-show="showpan=='image'">
  29. <img :src="electronicsignature" alt="" srcset="">
  30. </div>
  31. <div class="set">
  32. <el-row>
  33. <el-button @click="clearCanvas">重写签名</el-button>
  34. <el-button :disabled="nobeginAction" type="primary" @click="getImageAction">上传签名</el-button>
  35. </el-row>
  36. </div>
  37. </div>
  38. </div>
  39. <el-dialog
  40. title="提示"
  41. :visible.sync="centerDialogVisible"
  42. width="70%"
  43. v-loading="loading"
  44. element-loading-text="正在保存签名图片"
  45. element-loading-spinner="el-icon-loading"
  46. center>
  47. <vue-cropper
  48. ref="cropper"
  49. :src="imgUrl"
  50. alt="Source Image"
  51. :cropmove="cropImage"
  52. >
  53. </vue-cropper>
  54. <span slot="footer" class="dialog-footer">
  55. <el-button @click="centerDialogVisible = false">取 消</el-button>
  56. <el-button type="primary" @click="uploadImage">确 定</el-button>
  57. </span>
  58. </el-dialog>
  59. </div>
  60. </template>
  61. <script>
  62. import SideBar from "@/pages/layout/SideBar";
  63. import { getToken } from "@/api/qiniu";
  64. import { GetElectronicSignature, SaveElectronicSignature } from "@/api/admin_user";
  65. import VueCropper from 'vue-cropperjs';
  66. import { Toast } from 'vant';
  67. export default {
  68. name: "ElectronicSignature",
  69. components: {
  70. VueCropper,
  71. SideBar,
  72. },
  73. data() {
  74. return {
  75. showpan:'',
  76. nobeginAction:true,
  77. loading:false,
  78. electronicsignature:'',
  79. uptoken:"",
  80. avatarUrl2: null,
  81. centerDialogVisible:false,
  82. cropper: '',
  83. centerDialogVisible: false,
  84. colors: [
  85. "#fef4ac",
  86. "#0018ba",
  87. "#ffc200",
  88. "#f32f15",
  89. "#cccccc",
  90. "#5ab639"
  91. ],
  92. brushs: [
  93. {
  94. className: "small fa fa-paint-brush",
  95. lineWidth: 3
  96. },
  97. {
  98. className: "middle fa fa-paint-brush",
  99. lineWidth: 6
  100. },
  101. {
  102. className: "big fa fa-paint-brush",
  103. lineWidth: 12
  104. }
  105. ],
  106. context: {},
  107. imgUrl: "",
  108. uploadImgUrl:'',
  109. canvasMoveUse: false,
  110. // 存储当前表面状态数组-上一步
  111. preDrawAry: [],
  112. // 存储当前表面状态数组-下一步
  113. nextDrawAry: [],
  114. // 中间数组
  115. middleAry: [],
  116. // 配置参数
  117. config: {
  118. lineWidth: 15,
  119. lineColor: "#000",
  120. shadowBlur: 1,
  121. fillStyle: "#fff"
  122. }
  123. };
  124. },
  125. created() {
  126. this.getToken();
  127. this.GetElectronicSignature();
  128. },
  129. mounted() {
  130. const canvas = document.querySelector("#canvas");
  131. this.context = canvas.getContext("2d");
  132. this.context.fillStyle = this.config.fillStyle;
  133. this.context.fillRect(0, 0, 600, 400);
  134. this.initDraw();
  135. this.setCanvasStyle();
  136. },
  137. destroyed() {},
  138. computed: {
  139. controls() {
  140. return [
  141. {
  142. title: "上一步",
  143. action: "prev",
  144. className: this.preDrawAry.length
  145. ? "active fa fa-reply"
  146. : "fa fa-reply"
  147. },
  148. {
  149. title: "下一步",
  150. action: "next",
  151. className: this.nextDrawAry.length
  152. ? "active fa fa-share"
  153. : "fa fa-share"
  154. },
  155. {
  156. title: "清除",
  157. action: "clear",
  158. className:
  159. this.preDrawAry.length || this.nextDrawAry.length
  160. ? "active fa fa-trash"
  161. : "fa fa-trash"
  162. }
  163. ];
  164. }
  165. },
  166. methods: {
  167. GetElectronicSignature(){
  168. GetElectronicSignature().then(response=>{
  169. if(response.data.state==1 && response.data.data.state==1) {
  170. this.electronicsignature = response.data.data.electronic_signature.url;
  171. this.showpan = 'image';
  172. }else {
  173. this.showpan = 'canvas';
  174. }
  175. });
  176. },
  177. getToken(){
  178. getToken().then(response => {
  179. if(response.data.state==1) {
  180. this.uptoken = response.data.data.uptoken;
  181. }
  182. });
  183. },
  184. cropImage(event){
  185. var dataurl = this.$refs.cropper.getCroppedCanvas();
  186. var rectImage = dataurl.toDataURL('image/png');
  187. this.uploadImgUrl = rectImage;
  188. },
  189. isPc() {
  190. const userAgentInfo = navigator.userAgent;
  191. const Agents = [
  192. "Android",
  193. "iPhone",
  194. "SymbianOS",
  195. "Windows Phone",
  196. "iPad",
  197. "iPod"
  198. ];
  199. let flag = true;
  200. for (let v = 0; v < Agents.length; v++) {
  201. if (userAgentInfo.indexOf(Agents[v]) > 0) {
  202. flag = false;
  203. break;
  204. }
  205. }
  206. return flag;
  207. },
  208. removeImg(src) {
  209. this.imgUrl = "";
  210. },
  211. initDraw() {
  212. const preData = this.context.getImageData(0, 0, 600, 400);
  213. // 空绘图表面进栈
  214. this.middleAry.push(preData);
  215. },
  216. canvasMove(e) {
  217. if (this.canvasMoveUse) {
  218. const t = e.target;
  219. let canvasX;
  220. let canvasY;
  221. if (this.isPc()) {
  222. canvasX = e.clientX - t.parentNode.offsetLeft;
  223. canvasY = e.clientY - t.parentNode.offsetTop;
  224. } else {
  225. canvasX = e.changedTouches[0].clientX - t.parentNode.offsetLeft;
  226. canvasY = e.changedTouches[0].clientY - t.parentNode.offsetTop;
  227. }
  228. this.context.lineTo(canvasX, canvasY);
  229. this.context.stroke();
  230. }
  231. },
  232. beginPath(e) {
  233. const canvas = document.querySelector("#canvas");
  234. if (e.target !== canvas) {
  235. this.context.beginPath();
  236. }
  237. },
  238. // mouseup
  239. canvasUp(e) {
  240. const preData = this.context.getImageData(0, 0, 600, 400);
  241. if (!this.nextDrawAry.length) {
  242. // 当前绘图表面进栈
  243. this.middleAry.push(preData);
  244. } else {
  245. this.middleAry = [];
  246. this.middleAry = this.middleAry.concat(this.preDrawAry);
  247. this.middleAry.push(preData);
  248. this.nextDrawAry = [];
  249. }
  250. this.canvasMoveUse = false;
  251. this.nobeginAction = false;
  252. },
  253. // mousedown
  254. canvasDown(e) {
  255. this.canvasMoveUse = true;
  256. this.nobeginAction = false;
  257. // client是基于整个页面的坐标
  258. // offset是cavas距离顶部以及左边的距离
  259. const canvasX = e.clientX - e.target.parentNode.offsetLeft;
  260. const canvasY = e.clientY - e.target.parentNode.offsetTop;
  261. this.setCanvasStyle();
  262. // 清除子路径
  263. this.context.beginPath();
  264. this.context.moveTo(canvasX, canvasY);
  265. // 当前绘图表面状态
  266. const preData = this.context.getImageData(0, 0, 600, 400);
  267. // 当前绘图表面进栈
  268. this.preDrawAry.push(preData);
  269. },
  270. // 设置颜色
  271. setColor(color) {
  272. this.config.lineColor = color;
  273. },
  274. // 设置笔刷大小
  275. setBrush(type) {
  276. this.config.lineWidth = type;
  277. },
  278. // 操作
  279. clearCanvas() {
  280. this.context.clearRect(
  281. 0,
  282. 0,
  283. this.context.canvas.width,
  284. this.context.canvas.height
  285. );
  286. this.context.fillStyle = this.config.fillStyle;
  287. this.context.fillRect(0, 0, 600, 400);
  288. this.preDrawAry = [];
  289. this.nextDrawAry = [];
  290. this.middleAry = [this.middleAry[0]];
  291. this.nobeginAction = true;
  292. this.showpan = 'canvas';
  293. },
  294. getImageAction() {
  295. this.getImage();
  296. this.centerDialogVisible = true;
  297. if(typeof(this.$refs.cropper)!= 'undefined') {
  298. this.$refs.cropper.replace(this.imgUrl);
  299. }
  300. },
  301. uploadImage(){
  302. var dataurl = this.$refs.cropper.getCroppedCanvas();
  303. var rectImage = dataurl.toDataURL('image/png');
  304. this.uploadImgUrl = rectImage;
  305. if(typeof(this.uploadImgUrl) == 'undefined') {
  306. Toast.fail('获取截图资源失败');
  307. return false;
  308. }
  309. if(this.uptoken == '') {
  310. Toast.fail('七牛上传token无效,无法上传');
  311. return false;
  312. }
  313. this.loading = true;
  314. var _this=this;
  315. var pic = this.uploadImgUrl.split(',')[1];
  316. var url = "https://upload.qiniup.com/putb64/-1";
  317. var xhr = new XMLHttpRequest();
  318. xhr.onreadystatechange = function() {
  319. if (xhr.readyState == 4) {
  320. var returnData = JSON.parse(xhr.responseText);
  321. SaveElectronicSignature(returnData).then(response=>{
  322. if(response.data.state==1) {
  323. _this.electronicsignature = response.data.data.electronic_signature.url;
  324. _this.showpan = 'image';
  325. _this.nobeginAction = true;
  326. _this.centerDialogVisible = false;
  327. Toast.success('成功');
  328. // _this.$router.push({path: "/my"})
  329. }else {
  330. Toast.fail('保存图片时失败');
  331. }
  332. });
  333. _this.loading = false;
  334. }
  335. }
  336. xhr.open("POST", url, true);
  337. xhr.setRequestHeader("Content-Type", "application/octet-stream");
  338. xhr.setRequestHeader("Authorization", "UpToken " + _this.uptoken);
  339. xhr.send(pic);
  340. },
  341. // 生成图片
  342. getImage() {
  343. const canvas = document.querySelector("#canvas");
  344. const src = canvas.toDataURL("image/png");
  345. this.imgUrl = src;
  346. // if (!this.isPc()) {
  347. // // window.open(`data:text/plain,${src}`)
  348. // window.location.href = src
  349. // }
  350. },
  351. // 设置绘画配置
  352. setCanvasStyle() {
  353. this.context.lineWidth = this.config.lineWidth;
  354. this.context.shadowBlur = this.config.shadowBlur;
  355. this.context.shadowColor = this.config.lineColor;
  356. this.context.strokeStyle = this.config.lineColor;
  357. }
  358. }
  359. };
  360. </script>
  361. <style style="stylesheet/scss" lang="scss" scoped>
  362. .showpanner {
  363. text-align: center;
  364. }
  365. .mainContent {
  366. .title {
  367. font-size: 0.36rem;
  368. padding: 0.3rem 0.37rem;
  369. color: $title-color;
  370. @include align-items-center;
  371. @include display-flex;
  372. @include justify-content-between;
  373. @include text-align;
  374. background: #fff;
  375. .GoBack {
  376. color: $main-color;
  377. font-size: 0.36rem;
  378. @include display-flex;
  379. .iconfont {
  380. color: $main-color;
  381. font-size: 0.5rem;
  382. }
  383. }
  384. }
  385. .information {
  386. width: 100%;
  387. margin: 0 auto;
  388. .imagename{
  389. width: 600px;
  390. margin: 0 auto;
  391. text-align: center;
  392. padding: 10px 0;
  393. background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC');
  394. }
  395. .name {
  396. background: #fff;
  397. width: 600px;
  398. height: 400px;
  399. margin: 0 auto;
  400. border-radius: 4px;
  401. .item {
  402. padding: 0.37rem 0.4rem;
  403. @include align-items-center;
  404. @include display-flex;
  405. @include justify-content-between;
  406. @include text-align;
  407. height: 500px;
  408. .tx {
  409. @include display-flex;
  410. @include align-items-center;
  411. @include text-align;
  412. img {
  413. width: 1.24rem;
  414. height: 1.24rem;
  415. border-radius: 50%;
  416. display: inline-block;
  417. margin-right: 0.26rem;
  418. }
  419. }
  420. }
  421. h2 {
  422. color: #34495e;
  423. font-size: 0.34rem;
  424. }
  425. }
  426. .set {
  427. width: 70%;
  428. margin: 0 auto;
  429. border-radius: 4px;
  430. margin-top: 0.3rem;
  431. text-align: center;
  432. }
  433. }
  434. }
  435. </style>