ecert.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. <!--
  2. 电子证书
  3. http://localhost:5173/card/#/pages/achievement/ecert/ecert
  4. https://oss-mbh5.colormaprun.com/card/#/pages/achievement/ecert/ecert
  5. -->
  6. <template>
  7. <view class="main">
  8. <my-topbar :mcName="ecertConfig.title" class="mytopbar" :showRule="false" @btnBackClick="btnBack"></my-topbar>
  9. <!-- <text class="title" v-html="ecertConfig.title"></text> -->
  10. <image v-if="canvasReady" ref="ecertImg" class="ecertImg" :style="getEcertImageStyle()" mode="aspectFit" :src="ecertUrl" @click="previewCert"></image>
  11. <div v-else class="loading-animation"></div>
  12. <view class="btnlist uni-row uni-jcse">
  13. <text v-if="isCertCreate == 0" class="btnlist-item" @click="modify">修改姓名</text>
  14. <text class="btnlist-item" @click="previewCert">预览证书</text>
  15. <text class="btnlist-item" @click="downloadCert">下载证书</text>
  16. <!-- <text class="btnlist-item" @click="shareWx">打开微信</text> -->
  17. </view>
  18. <!-- <br>
  19. <a :href="'action://down_file?filename='+encodeURIComponent('图片下载_xfl.png')+'&url='+encodeURIComponent('https://oss-mbh5.colormaprun.com/card/static/logo/xfl.png')">下载图片</a>
  20. &nbsp;
  21. <a :href="'action://down_file?filename='+encodeURIComponent('文件下载_index.html')+'&url='+encodeURIComponent('https://oss-mbh5.colormaprun.com/card/index.html')">下载文件</a>
  22. &nbsp;
  23. <a :href="'action://down_file?filename='+encodeURIComponent('音频下载_1.mp3')+'&url='+encodeURIComponent('https://oss-mbh5.colormaprun.com/card/static/audio/1.mp3')">下载音频</a>
  24. &nbsp;
  25. <br>
  26. <a :href="'action://down_file?filename='+encodeURIComponent('小视频下载_Walk_to_image_room.mp4')+'&url='+encodeURIComponent('https://oss-mbh5.colormaprun.com/card/Walk_to_image_room.mp4')">下载小视频</a>
  27. &nbsp;
  28. <a :href="'action://down_file?filename='+encodeURIComponent('大视频下载_wifidigger.mp4')+'&url='+encodeURIComponent('https://oss-mbh5.colormaprun.com/card/wifidigger.mp4')">下载大视频</a>
  29. &nbsp; -->
  30. <!-- <a href="tel:13335119550">拨打电话</a> &nbsp; -->
  31. <canvas v-if="canvasReady" canvas-id="ecert" id="ecert" class="ecert" :style="getEcertCanvasStyle()"></canvas>
  32. <uni-popup ref="modifyDialog" type="dialog">
  33. <uni-popup-dialog type="warn" mode="base" title="修改姓名" @confirm="modifyDialogConfirm">
  34. <view class="dialogView uni-column uni-jcse">
  35. <input class="uni-input" maxlength="12" placeholder="请输入姓名" placeholder-style="font-size: 14px;" v-model="newName" />
  36. <view class="dialogView-memo">( 注:姓名<span style="color: red;">只能修改一次</span> )</view>
  37. </view>
  38. </uni-popup-dialog>
  39. </uni-popup>
  40. <uni-popup ref="confirmDialog" type="dialog">
  41. <uni-popup-dialog type="warn" cancelText="取消" confirmText="确定" title="提示" :content="confirmContent"
  42. @confirm="confirmDialogConfirm"></uni-popup-dialog>
  43. </uni-popup>
  44. <!-- <movable-area :scale-area="true" class="movable-area">
  45. <movable-view class="movable-view" direction="all" :inertia="true" :scale-min="0.5" :scale-max="10" :scale="true" :out-of-bounds="true">
  46. <canvas canvas-id="ecert" id="ecert" class="ecert" :style="getEcertStyle()"></canvas>
  47. </movable-view>
  48. </movable-area> -->
  49. </view>
  50. </template>
  51. <script>
  52. import tools from '/common/tools';
  53. import {
  54. token,
  55. apiCertStyleQuery,
  56. apiUserBaseQueryInCertificate,
  57. apiCertificateCreateByUserAi,
  58. checkResCode
  59. } from '/common/api';
  60. export default {
  61. data() {
  62. return {
  63. pageName: "ecert",
  64. queryObj: {},
  65. queryString: "",
  66. token: "",
  67. certStyleType: "", // 证书样式类型 比如 "shanda1"
  68. oarId: 0, // 成就记录id
  69. dpr: 1, // 设备像素比
  70. windowWidth: uni.getSystemInfoSync().windowWidth, // 可视区域宽度
  71. // windowHeight: uni.getSystemInfoSync().windowHeight, // 可视区域高度
  72. ecertWidth: 0,
  73. ecertHeight: 0,
  74. ecertUrl: "",
  75. btnCertText: "确认生成证书",
  76. nickName: '',
  77. coiId: 0, // 报名单位id
  78. coiName: "", // 报名单位名称
  79. teamNum: 0, // 队伍
  80. compName: "", // 赛事名称
  81. certificateName: "", // 奖项名称
  82. compBt: 0, // 赛事开始时间戳
  83. compEt: 0, // 赛事结束时间戳
  84. totalSysPoint: 0, // 个人总积分
  85. totalDistance: 0, // 个人总里程,单位米
  86. isCertCreate: 0, // 是否已经生成证书(生成后不能修改昵称) 0 未生成 1 已生成
  87. ecertConfig: {},
  88. canvasReady: false,
  89. newName: "",
  90. confirmContent: ""
  91. }
  92. },
  93. onLoad(query) {
  94. // console.log(query);
  95. this.queryObj = query;
  96. this.queryString = tools.objectToQueryString(this.queryObj);
  97. // console.log(queryString);
  98. this.token = query["token"] ?? token;
  99. this.certStyleType = query["certStyleType"] ?? "";
  100. this.oarId = query["oarId"] ?? 0;
  101. this.init();
  102. },
  103. onReady() {
  104. // this.test();
  105. },
  106. methods: {
  107. init() {
  108. let that = this;
  109. uni.getSystemInfo({
  110. success: function(res) {
  111. that.dpr = res.pixelRatio;
  112. // console.log('设备像素比:', that.dpr);
  113. that.userBaseQueryInCertificate();
  114. }
  115. });
  116. },
  117. // 格式化 距离
  118. fmtDistanct(val) {
  119. return Math.round(val * 100 / 1000) / 100;
  120. },
  121. getEcertImageStyle() {
  122. if (this.ecertWidth == 0) {
  123. return "";
  124. }
  125. const ratio = 0.9;
  126. const width = this.windowWidth * ratio;
  127. const height = Math.round(this.windowWidth / this.ecertWidth * this.ecertHeight) * ratio;
  128. let style = "";
  129. style += "width: " + width + "px;";
  130. style += "height: " + height + "px;";
  131. // console.log("[getEcertImageStyle]", style);
  132. return style;
  133. },
  134. getEcertCanvasStyle() {
  135. let style = "";
  136. style += "width: " + this.ecertWidth + "px;";
  137. style += "height: " + this.ecertHeight + "px;";
  138. // console.log("[getEcertCanvasStyle]", style);
  139. return style;
  140. },
  141. getParamValue(paramName) {
  142. let value = null;
  143. if (paramName == "nickName") {
  144. value = this.nickName;
  145. } else if (paramName == "coiName") {
  146. value = "(" + this.coiName + ")";
  147. } else if (paramName == "totalDistance") {
  148. value = this.fmtDistanct(this.totalDistance);
  149. } else if (paramName == "totalSysPoint") {
  150. value = this.totalSysPoint;
  151. }
  152. return value;
  153. },
  154. drawText(param, text, context) {
  155. if (param.font != undefined) {
  156. const font = param.font;
  157. if (font.align != undefined && font.align.length > 0) {
  158. context.setTextAlign(font.align);
  159. }
  160. if (font.size != undefined && font.size > 0) {
  161. const font_family = (font.family != undefined && font.family.length > 0) ? font.family : "Arial";
  162. const font_size = Math.round(font.size / this.dpr);
  163. let style = `${font_size}px ${font_family}`;
  164. if (font.preStyle != undefined && font.preStyle.length > 0) {
  165. style = `${font.preStyle} ${style}`;
  166. }
  167. // console.log(style);
  168. context.font = style;
  169. }
  170. // if (font.size != undefined && font.size > 0) {
  171. // context.setFontSize(font.size / this.dpr);
  172. // }
  173. if (font.color != undefined && font.color.length > 0) {
  174. context.fillStyle = font.color;
  175. }
  176. }
  177. context.fillText(text, param.position.x / this.dpr, param.position.y / this.dpr);
  178. },
  179. makeCert() {
  180. let that = this;
  181. // console.log("[makeCert]", that.ecertConfig.tplUrl);
  182. const ctx = uni.createCanvasContext('ecert');
  183. ctx.drawImage(that.ecertConfig.tplUrl, 0, 0, that.ecertWidth, that.ecertHeight);
  184. for (var i = 0; i < that.ecertConfig.paramList.length; i++) {
  185. const param = that.ecertConfig.paramList[i];
  186. const text = that.getParamValue(param.paramName);
  187. that.drawText(param, text, ctx);
  188. }
  189. ctx.draw(true, () => {
  190. // 在这里调用uni.canvasToTempFilePath,确保绘制完成
  191. uni.canvasToTempFilePath({
  192. canvasId: 'ecert',
  193. success: function(res) {
  194. // 在H5平台下,tempFilePath 为 base64
  195. // console.log(res.tempFilePath);
  196. let imageData = res.tempFilePath;
  197. that.ecertUrl = imageData;
  198. }
  199. });
  200. });
  201. },
  202. // 查询电子证书样式
  203. certStyleQuery() {
  204. uni.request({
  205. url: apiCertStyleQuery,
  206. header: {
  207. "Content-Type": "application/x-www-form-urlencoded",
  208. "token": this.token,
  209. },
  210. method: "POST",
  211. data: {
  212. "certStyleType": this.certStyleType
  213. },
  214. success: (res) => {
  215. // console.log("certStyleQuery", res);
  216. if (res.data.code == 0) {
  217. const data = res.data.data;
  218. const ecertConfig = data.configJson != "" ? JSON.parse(data.configJson) : "";
  219. this.ecertConfig = ecertConfig;
  220. /* this.ecertConfig = {
  221. "title": "完赛证书",
  222. "tplUrl": "/static/ecert/shanda/youxiujiang.jpg",
  223. "width": 2000,
  224. "height": 2828,
  225. "paramList": [{
  226. "paramName": "nickName",
  227. "font": {
  228. "preStyle": "bold",
  229. "size": 56,
  230. "family": "",
  231. "color": "#000000",
  232. "align": "center"
  233. },
  234. "position": {
  235. "x": 1000,
  236. "y": 2120
  237. }
  238. },
  239. {
  240. "paramName": "coiName",
  241. "font": {
  242. "preStyle": "",
  243. "size": 46,
  244. "family": "",
  245. "color": "#646363",
  246. "align": "center"
  247. },
  248. "position": {
  249. "x": 1000,
  250. "y": 2200
  251. }
  252. },
  253. {
  254. "paramName": "totalDistance",
  255. "font": {
  256. "preStyle": "",
  257. "size": 40,
  258. "family": "",
  259. "color": "#fe0000",
  260. "align": "center"
  261. },
  262. "position": {
  263. "x": 910,
  264. "y": 1704
  265. }
  266. },
  267. {
  268. "paramName": "totalSysPoint",
  269. "font": {
  270. "preStyle": "",
  271. "size": 40,
  272. "family": "",
  273. "color": "#fe0000",
  274. "align": "left"
  275. },
  276. "position": {
  277. "x": 1320,
  278. "y": 1704
  279. }
  280. }
  281. ]
  282. }; */
  283. // console.log("ecertConfig:", this.ecertConfig);
  284. this.ecertWidth = Math.round(this.ecertConfig.width / this.dpr);
  285. this.ecertHeight = Math.round(this.ecertConfig.height / this.dpr);
  286. // console.log("[certStyleQuery] ecertWidth ecertHeight:", this.ecertWidth, this.ecertHeight);
  287. this.canvasReady = true;
  288. this.$nextTick(() => {
  289. this.makeCert();
  290. });
  291. }
  292. },
  293. fail: (err) => {
  294. console.log("certStyleQuery err", err);
  295. },
  296. });
  297. },
  298. // 查询电子证书成就对应用户基本信息
  299. userBaseQueryInCertificate() {
  300. uni.request({
  301. url: apiUserBaseQueryInCertificate,
  302. header: {
  303. "Content-Type": "application/x-www-form-urlencoded",
  304. "token": this.token,
  305. },
  306. method: "POST",
  307. data: {
  308. "oarId": this.oarId
  309. },
  310. success: (res) => {
  311. // console.log("userBaseQueryInCertificate", res);
  312. if (res.data.code == 0) {
  313. const data = res.data.data;
  314. this.nickName = data.nickName;
  315. this.coiId = data.coiId;
  316. this.coiName = data.coiName;
  317. this.teamNum = data.teamNum;
  318. this.compName = data.compName;
  319. this.certificateName = data.certificateName;
  320. this.compBt = data.compBt;
  321. this.compEt = data.compEt;
  322. this.totalSysPoint = data.totalSysPoint;
  323. this.totalDistance = data.totalDistance;
  324. this.isCertCreate = data.isCertCreate;
  325. this.certStyleQuery();
  326. }
  327. },
  328. fail: (err) => {
  329. console.log("userBaseQueryInCertificate err", err);
  330. },
  331. });
  332. },
  333. // 根据成就信息确认生成电子证书
  334. certificateCreateByUserAi() {
  335. uni.request({
  336. url: apiCertificateCreateByUserAi,
  337. header: {
  338. "Content-Type": "application/x-www-form-urlencoded",
  339. "token": this.token,
  340. },
  341. method: "POST",
  342. data: {
  343. "oarId": this.oarId,
  344. "coiName": this.coiName,
  345. "coiId": this.coiId,
  346. "teamNum": this.teamNum,
  347. "nickName": this.nickName,
  348. },
  349. success: (res) => {
  350. // console.log("certificateCreateByUserAi", res);
  351. if (checkResCode(res)) {
  352. uni.showToast({
  353. icon: "none",
  354. title: "姓名修改成功",
  355. duration: 3000
  356. });
  357. }
  358. this.userBaseQueryInCertificate();
  359. },
  360. fail: (err) => {
  361. console.log("certificateCreateByUserAi err", err);
  362. uni.showToast({
  363. icon: "none",
  364. title: "姓名修改失败:" + err.message
  365. });
  366. this.userBaseQueryInCertificate();
  367. },
  368. });
  369. },
  370. modify() {
  371. if (this.isCertCreate) {
  372. uni.showToast({
  373. icon: "none",
  374. title: "不能再次修改姓名"
  375. });
  376. return;
  377. }
  378. this.newName = this.nickName;
  379. this.$refs.modifyDialog.open();
  380. },
  381. modifyDialogConfirm() {
  382. this.newName = this.newName.trim();
  383. if (this.newName.length == 0) {
  384. uni.showToast({
  385. icon: "none",
  386. title: "请输入姓名"
  387. });
  388. return;
  389. }
  390. if (this.newName != this.nickName) {
  391. this.confirmContent = `姓名:${this.newName}\r\n\r\n只能修改一次,确定要修改吗?`;
  392. this.$refs.confirmDialog.open();
  393. } else {
  394. uni.showToast({
  395. icon: "none",
  396. title: "姓名未修改,操作取消"
  397. });
  398. return;
  399. }
  400. },
  401. confirmDialogConfirm() {
  402. this.nickName = this.newName.trim();
  403. this.certificateCreateByUserAi();
  404. },
  405. previewCert() {
  406. uni.previewImage({
  407. showmenu: true,
  408. urls: [this.ecertUrl] // 需要预览的图片 HTTP 链接列表
  409. });
  410. },
  411. downloadCert() {
  412. let data = {
  413. name: `${this.compName}_${this.certificateName}_ecert.png`,
  414. content: this.ecertUrl,
  415. type: "image"
  416. };
  417. data = JSON.stringify(data);
  418. // console.log(data);
  419. save_base64.postMessage(data);
  420. /* let filename = `${this.compName}_${this.certificateName}_ecert`;
  421. // console.log("filename:", filename);
  422. filename = encodeURIComponent(filename);
  423. let fileurl = this.ecertUrl;
  424. // console.log("fileurl:", fileurl);
  425. fileurl = encodeURIComponent(fileurl);
  426. const url = `action://down_pic_base64?filename=${filename}&url=${fileurl}`;
  427. tools.appAction(url); */
  428. /* uni.downloadFile({
  429. // url: this.ecertConfig.tplUrl,
  430. // url: this.$refs.ecertImg.src,
  431. url: this.ecertUrl,
  432. success: function(downloadResult) {
  433. if (downloadResult.statusCode === 200) {
  434. // 下载成功后,尝试保存图片到本地相册
  435. uni.saveImageToPhotosAlbum({
  436. filePath: downloadResult.tempFilePath,
  437. success: function() {
  438. console.log('图片保存成功');
  439. uni.showToast({
  440. icon: "none",
  441. title: "图片保存成功",
  442. duration: 2000
  443. });
  444. },
  445. fail: function(err) {
  446. console.log('保存图片失败', err);
  447. uni.showToast({
  448. icon: "none",
  449. title: "保存图片失败:" + err.errMsg,
  450. duration: 5000
  451. });
  452. }
  453. });
  454. }
  455. },
  456. fail: function(err) {
  457. console.log('下载图片失败', err);
  458. uni.showToast({
  459. icon: "none",
  460. title: "下载图片失败:" + err.errMsg,
  461. duration: 5000
  462. });
  463. }
  464. }); */
  465. },
  466. shareWx() {
  467. let data = {
  468. title: "彩图奔跑商家版",
  469. url: "https://oss-mbh5.colormaprun.com/shop/",
  470. image: "https://oss-mbh5.colormaprun.com/shop/static/logo.png",
  471. scene: "session" // session:分享到对话 timeline:分享到朋友圈 favorite:分享到收藏
  472. };
  473. data = JSON.stringify(data);
  474. // console.log(data);
  475. share_wx.postMessage(data);
  476. },
  477. btnCert() {
  478. this.makeCert();
  479. },
  480. btnBack() {
  481. window.history.back();
  482. /* const url = `action://to_home/`;
  483. tools.appAction(url); */
  484. },
  485. test() {
  486. // var ctx = uni.createCanvasContext('firstCanvas')
  487. var ctx = uni.createCanvasContext('ecert')
  488. // ctx.scale(this.dpr, this.dpr);
  489. ctx.setStrokeStyle("#00ff00")
  490. ctx.setLineWidth(5)
  491. ctx.rect(0, 0, 200, 200)
  492. ctx.stroke()
  493. ctx.setStrokeStyle("red");
  494. // ctx.setLineWidth(5);
  495. ctx.moveTo(150, 20);
  496. ctx.lineTo(150, 170);
  497. ctx.stroke();
  498. ctx.setFontSize(15);
  499. ctx.setTextAlign('left');
  500. ctx.fillText('textAlign=left', 150, 60);
  501. ctx.setTextAlign('center');
  502. ctx.fillText('textAlign=center', 150, 80);
  503. ctx.setTextAlign('right');
  504. ctx.fillText('textAlign=right', 150, 100);
  505. ctx.draw()
  506. },
  507. }
  508. }
  509. </script>
  510. <style>
  511. .main {
  512. width: 100vw;
  513. height: 100vh;
  514. overflow: hidden;
  515. text-align: center;
  516. }
  517. .mytopbar {
  518. padding-top: 40px;
  519. padding-bottom: 20px;
  520. margin-left: auto;
  521. margin-right: auto;
  522. }
  523. /* .title {
  524. display: block;
  525. margin-top: 35px;
  526. margin-bottom: 15px;
  527. font-size: 22px;
  528. font-weight: 550;
  529. color: #333333;
  530. } */
  531. .loading-animation {
  532. margin: 200px auto;
  533. border: 6px solid #f3f3f3;
  534. border-top: 6px solid #3498db;
  535. border-radius: 50%;
  536. width: 50px;
  537. height: 50px;
  538. animation: spin 1s linear infinite;
  539. }
  540. @keyframes spin {
  541. 0% {
  542. transform: rotate(0deg);
  543. }
  544. 100% {
  545. transform: rotate(360deg);
  546. }
  547. }
  548. .ecertImg {
  549. margin-top: 6px;
  550. margin-bottom: 20px;
  551. border: #bfbfbf solid 1px;
  552. box-shadow: 3px 3px 8px #b9b9b9;
  553. /* -webkit-touch-callout: default; */
  554. }
  555. .btnlist {
  556. width: 80%;
  557. /* height: 30px; */
  558. margin: 0px auto;
  559. /* background-color: #3498db; */
  560. }
  561. .btnlist-item {
  562. font-size: 14px;
  563. font-weight: 500;
  564. color: #383838;
  565. text-decoration: underline;
  566. }
  567. .ecert {
  568. visibility: hidden;
  569. /* width: 100vw;
  570. height: 100vh; */
  571. /* transform: scale(0.5); */
  572. }
  573. .dialogView {
  574. width: 90%;
  575. }
  576. .dialogView-memo {
  577. font-size: 12px;
  578. font-weight: 400;
  579. color: #808080;
  580. }
  581. .uni-input {
  582. width: 100%;
  583. height: 34px;
  584. margin-bottom: 10px;
  585. border: 1px solid #dcdfe6;
  586. border-radius: 4px;
  587. font-size: 14px;
  588. }
  589. ::v-deep #u-a-p > div {
  590. top: 30px !important;
  591. }
  592. /* .info {
  593. max-width: fit-content;
  594. margin-left: auto;
  595. margin-right: auto;
  596. margin-top: 30px;
  597. }
  598. .info-text {
  599. font-size: 16px;
  600. font-weight: 500;
  601. color: #333333;
  602. line-height: 30px;
  603. }
  604. .info-memo {
  605. font-size: 12px;
  606. font-weight: 400;
  607. color: #808080;
  608. line-height: 25px;
  609. }
  610. .btnCert {
  611. width: 289px;
  612. height: 53px;
  613. margin-top: 30px;
  614. margin-bottom: 20px;
  615. border-radius: 27px;
  616. background: #a43a07;
  617. color: #ffffff;
  618. line-height: 53px;
  619. } */
  620. /* .movable-area {
  621. width: 100vw;
  622. height: 80vh;
  623. background-color: #ddd;
  624. overflow: hidden;
  625. align-items: center;
  626. }
  627. .movable-view {
  628. width: 100%;
  629. height: 50%;
  630. transform: scale(0.1) !important;
  631. } */
  632. </style>