material-download.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. <template>
  2. <view class="poster_page">
  3. <mp-swiper :list="list"></mp-swiper>
  4. <!-- <swiper class="poster_swiper" previous-margin="110rpx" circular :current="swiperIndex" next-margin="110rpx" @change="onSwiperChange">
  5. <swiper-item v-for="(item, index) of list" :key="index">
  6. <view class="goods_info_box" :class="{ active: swiperIndex == index }">
  7. <image class="goods_image" :src="item.image" mode="scaleToFill"></image>
  8. </view>
  9. </swiper-item>
  10. </swiper> -->
  11. <!-- <canvas canvas-id="poster" class="poster_canvas"></canvas> -->
  12. <!-- <view class="share_save_box">
  13. <view class="push_button" @click="onSaveImg">
  14. <text style="font-size: 28rpx;">保存图片</text>
  15. </view>
  16. </view> -->
  17. </view>
  18. </template>
  19. <script>
  20. // 文字换行
  21. function drawtext(text, maxWidth) {
  22. let textArr = text.split("");
  23. let len = textArr.length;
  24. // 上个节点
  25. let previousNode = 0;
  26. // 记录节点宽度
  27. let nodeWidth = 0;
  28. // 文本换行数组
  29. let rowText = [];
  30. // 如果是字母,侧保存长度
  31. let letterWidth = 0;
  32. // 汉字宽度
  33. let chineseWidth = 21;
  34. // otherFont宽度
  35. let otherWidth = 10.5;
  36. for (let i = 0; i < len; i++) {
  37. if (/[\u4e00-\u9fa5]|[\uFE30-\uFFA0]/g.test(textArr[i])) {
  38. if(letterWidth > 0){
  39. if(nodeWidth + chineseWidth + letterWidth * otherWidth > maxWidth){
  40. rowText.push({
  41. type: "text",
  42. content: text.substring(previousNode, i)
  43. });
  44. previousNode = i;
  45. nodeWidth = chineseWidth;
  46. letterWidth = 0;
  47. } else {
  48. nodeWidth += chineseWidth + letterWidth * otherWidth;
  49. letterWidth = 0;
  50. }
  51. } else {
  52. if(nodeWidth + chineseWidth > maxWidth){
  53. rowText.push({
  54. type: "text",
  55. content: text.substring(previousNode, i)
  56. });
  57. previousNode = i;
  58. nodeWidth = chineseWidth;
  59. }else{
  60. nodeWidth += chineseWidth;
  61. }
  62. }
  63. } else {
  64. if(/\n/g.test(textArr[i])){
  65. rowText.push({
  66. type: "break",
  67. content: text.substring(previousNode, i)
  68. });
  69. previousNode = i + 1;
  70. nodeWidth = 0;
  71. letterWidth = 0;
  72. }else if(textArr[i] == "\\" && textArr[i + 1] == "n"){
  73. rowText.push({
  74. type: "break",
  75. content: text.substring(previousNode, i)
  76. });
  77. previousNode = i + 2;
  78. nodeWidth = 0;
  79. letterWidth = 0;
  80. }else if(/[a-zA-Z0-9]/g.test(textArr[i])){
  81. letterWidth += 1;
  82. if(nodeWidth + letterWidth * otherWidth > maxWidth){
  83. rowText.push({
  84. type: "text",
  85. content: text.substring(previousNode, i + 1 - letterWidth)
  86. });
  87. previousNode = i + 1 - letterWidth;
  88. nodeWidth = letterWidth * otherWidth;
  89. letterWidth = 0;
  90. }
  91. } else{
  92. if(nodeWidth + otherWidth > maxWidth){
  93. rowText.push({
  94. type: "text",
  95. content: text.substring(previousNode, i)
  96. });
  97. previousNode = i;
  98. nodeWidth = otherWidth;
  99. }else{
  100. nodeWidth += otherWidth;
  101. }
  102. }
  103. }
  104. }
  105. if (previousNode < len) {
  106. rowText.push({
  107. type: "text",
  108. content: text.substring(previousNode, len)
  109. });
  110. }
  111. return rowText;
  112. }
  113. let settingWritePhotosAlbum = false;
  114. import mpSwiper from "./comps/mp-swiper.vue"
  115. export default {
  116. components:{
  117. mpSwiper
  118. },
  119. data() {
  120. return {
  121. type:'',
  122. list:[
  123. {
  124. title:'麻辣烫',
  125. image:'/static/icon/wuliao1.png'
  126. },
  127. {
  128. title:'麻辣烫',
  129. image:'/static/icon/wuliao1.png'
  130. },
  131. {
  132. title:'麻辣烫',
  133. image:'/static/icon/wuliao1.png'
  134. },
  135. {
  136. title:'麻辣烫',
  137. image:'/static/icon/wuliao1.png'
  138. },
  139. {
  140. title:'麻辣烫',
  141. image:'/static/icon/wuliao1.png'
  142. }
  143. ],
  144. cardCur:0,
  145. //平台
  146. platformName: "联兑通",
  147. recommendCodeGoods: "",
  148. //二维码
  149. swiperIndex: 0,
  150. posterImgs: [],
  151. h5SaveImg: ""
  152. };
  153. },
  154. onLoad(options) {
  155. },
  156. computed: {
  157. },
  158. //方法
  159. methods: {
  160. cardSwiper(e){
  161. console.log(e);
  162. },
  163. fetchData1(id){
  164. this.$request.get(myApi.live.page,{params:{size:300,id:id}}).then(res=>{
  165. this.list=[]
  166. res.data.records.forEach(item=>{
  167. let obj={}
  168. obj.headImgs=item.pic
  169. if(item.account>-0.000001&&item.account<0.000001){
  170. obj.goodsPrice="免费观看"
  171. }else{
  172. obj.goodsPrice=item.account
  173. }
  174. obj.goodsName=item.title
  175. obj.id=item.id
  176. this.list.push(obj)
  177. })
  178. this.getAccessToken()
  179. })
  180. },
  181. // 轮播图变化
  182. onSwiperChange(e) {
  183. this.swiperIndex = e.detail.current;
  184. this.getAccessToken()
  185. },
  186. // 创建海报
  187. createPoster() {
  188. return new Promise((resolve, reject) => {
  189. uni.showLoading({
  190. title: '海报生成中'
  191. });
  192. const ctx = uni.createCanvasContext('poster');
  193. ctx.fillRect(0, 0, 375, 673);
  194. ctx.setFillStyle("#FFF");
  195. ctx.fillRect(0, 0, 375, 673);
  196. uni.downloadFile({
  197. url: this.list[this.swiperIndex].headImgs,
  198. success: (res) => {
  199. if (res.statusCode === 200) {
  200. ctx.drawImage(res.tempFilePath, 0, 0, 375, 375);
  201. uni.downloadFile({
  202. url: this.recommendCodeGoods,
  203. success: (res2) => {
  204. if (res.statusCode === 200) {
  205. // 商品标题
  206. ctx.setFontSize(16);
  207. ctx.setFillStyle('#333');
  208. let drawtextList = drawtext(this.list[this.swiperIndex].goodsName, 420);
  209. let textTop = 0;
  210. drawtextList.forEach((item,index) => {
  211. if(index < 2){
  212. textTop = 380 + (index + 1) * 28;
  213. if(index==0){
  214. ctx.fillText(item.content, 22, textTop);
  215. }else{
  216. if(item.content.length>20){
  217. ctx.fillText(item.content+"...", 22, textTop);
  218. }else{
  219. ctx.fillText(item.content, 22, textTop);
  220. }
  221. }
  222. }
  223. });
  224. // 商品价格
  225. ctx.setFontSize(20);
  226. ctx.setFillStyle('#f00');
  227. ctx.fillText(this.list[this.swiperIndex].goodsPrice, 17, textTop + 47);
  228. // 商品分割线
  229. ctx.beginPath();
  230. ctx.setLineWidth(1);
  231. ctx.moveTo(17, textTop + 70);
  232. ctx.lineTo(358, textTop + 70);
  233. ctx.setStrokeStyle('#eee');
  234. ctx.stroke();
  235. // 长按识别二维码访问
  236. ctx.setFontSize(14);
  237. ctx.setFillStyle('#333');
  238. ctx.fillText("扫描二维码访问", 17, textTop + 136);
  239. // 平台名称
  240. ctx.setFontSize(12);
  241. ctx.setFillStyle('#999');
  242. ctx.fillText(this.platformName, 17, textTop + 170);
  243. // 二维码
  244. ctx.drawImage(res2.tempFilePath, 238, textTop + 88, 120, 120);
  245. ctx.draw(true, () => {
  246. // canvas画布转成图片并返回图片地址
  247. uni.canvasToTempFilePath({
  248. canvasId: 'poster',
  249. width: 375,
  250. height: 673,
  251. success: (res) => {
  252. if(this.posterImgs[this.swiperIndex]){
  253. this.posterImgs[this.swiperIndex].temporary = res.tempFilePath;
  254. }else{
  255. this.posterImgs[this.swiperIndex] = {
  256. temporary: res.tempFilePath
  257. };
  258. }
  259. console.log("海报制作成功!");
  260. resolve(res.tempFilePath);
  261. },
  262. fail: () => {
  263. uni.hideLoading();
  264. reject();
  265. }
  266. })
  267. });
  268. } else {
  269. uni.hideLoading();
  270. uni.showToast({
  271. title: '海报制作失败,图片下载失败',
  272. icon: 'none'
  273. });
  274. }
  275. },
  276. fail: err => {
  277. uni.hideLoading();
  278. uni.showToast({
  279. title: '海报制作失败,图片下载失败',
  280. icon: 'none'
  281. });
  282. }
  283. });
  284. } else {
  285. uni.hideLoading();
  286. uni.showToast({
  287. title: '海报制作失败,图片下载失败',
  288. icon: 'none'
  289. });
  290. }
  291. },
  292. fail: err => {
  293. uni.hideLoading();
  294. uni.showToast({
  295. title: '海报制作失败,图片下载失败',
  296. icon: 'none'
  297. });
  298. }
  299. });
  300. });
  301. },
  302. // 保存图片
  303. async onSaveImg() {
  304. let imgUrl = "";
  305. if(this.posterImgs[this.swiperIndex] && this.posterImgs[this.swiperIndex].temporary){
  306. imgUrl = await this.posterImgs[this.swiperIndex].temporary;
  307. }else{
  308. imgUrl = await this.createPoster();
  309. }
  310. // #ifdef H5
  311. this.h5SaveImg = imgUrl;
  312. uni.hideLoading();
  313. // #endif
  314. // #ifdef MP-WEIXIN
  315. uni.showLoading({
  316. title: '海报下载中'
  317. });
  318. if (settingWritePhotosAlbum) {
  319. uni.getSetting({
  320. success: res => {
  321. if (res.authSetting['scope.writePhotosAlbum']) {
  322. uni.saveImageToPhotosAlbum({
  323. filePath: imgUrl,
  324. success: () => {
  325. uni.showToast({
  326. title: '保存成功'
  327. });
  328. },
  329. complete: () => {
  330. uni.hideLoading();
  331. }
  332. });
  333. } else {
  334. uni.showModal({
  335. title: '提示',
  336. content: '请先在设置页面打开“保存相册”使用权限',
  337. confirmText: '去设置',
  338. cancelText: '算了',
  339. success: data => {
  340. if (data.confirm) {
  341. uni.openSetting();
  342. }
  343. },
  344. complete: () => {
  345. uni.hideLoading();
  346. }
  347. });
  348. }
  349. },
  350. complete: () => {
  351. uni.hideLoading();
  352. }
  353. });
  354. } else {
  355. settingWritePhotosAlbum = true;
  356. uni.authorize({
  357. scope: 'scope.writePhotosAlbum',
  358. success: () => {
  359. uni.saveImageToPhotosAlbum({
  360. filePath: imgUrl,
  361. success: () => {
  362. uni.showToast({
  363. title: '保存成功'
  364. });
  365. },
  366. complete: () => {
  367. uni.hideLoading();
  368. }
  369. });
  370. },
  371. complete: () => {
  372. uni.hideLoading();
  373. }
  374. });
  375. }
  376. // #endif
  377. // #ifdef APP-PLUS
  378. uni.showLoading({
  379. title: '海报下载中'
  380. });
  381. uni.saveImageToPhotosAlbum({
  382. filePath: imgUrl,
  383. success: () => {
  384. uni.hideLoading();
  385. uni.showToast({
  386. title: '保存成功'
  387. });
  388. }
  389. });
  390. // #endif
  391. }
  392. }
  393. };
  394. </script>
  395. <style lang="scss" scoped>
  396. .poster_page {
  397. min-height: 100vh;
  398. background-color: #f5f5f5;
  399. }
  400. .poster_canvas {
  401. width: 750rpx;
  402. height: 1324rpx;
  403. position: fixed;
  404. top: -10000rpx;
  405. left: 0rpx;
  406. }
  407. .poster_swiper {
  408. height: 950rpx;
  409. width: 100%;
  410. swiper-item {
  411. box-sizing: border-box;
  412. display: flex;
  413. align-items: center;
  414. .goods_info_box {
  415. width: 100%;
  416. height: 100%;
  417. transform: scale(0.88);
  418. transition: all 0.4s;
  419. position: relative;
  420. overflow: hidden;
  421. background-color: #FFFFFF;
  422. &.active {
  423. transform: scale(1);
  424. }
  425. .goods_image {
  426. width: 100%;
  427. height: calc(100vw - 220rpx);
  428. }
  429. .goods_info {
  430. padding: 24rpx;
  431. .goods_name {
  432. color: #333;
  433. font-size: 30rpx;
  434. overflow: hidden;
  435. text-overflow: ellipsis;
  436. display: -webkit-box;
  437. -webkit-line-clamp: 2;
  438. -webkit-box-orient: vertical;
  439. }
  440. .price_box {
  441. margin-top: 24rpx;
  442. display: flex;
  443. align-items: center;
  444. .price {
  445. font-size: 38rpx;
  446. color: red;
  447. }
  448. .store_price {
  449. margin-left: 30rpx;
  450. font-size: 26rpx;
  451. color: #999;
  452. text-decoration: line-through;
  453. }
  454. }
  455. .poster_info {
  456. border-top: 2rpx solid #f1f1f1;
  457. padding-top: 24rpx;
  458. margin-top: 24rpx;
  459. display: flex;
  460. align-items: center;
  461. justify-content: space-between;
  462. .info {
  463. display: flex;
  464. flex-direction: column;
  465. view {
  466. color: #333;
  467. font-size: 28rpx;
  468. }
  469. text {
  470. color: #999;
  471. font-size: 24rpx;
  472. margin-top: 20rpx;
  473. }
  474. }
  475. .poster_code_image {
  476. width: 170rpx;
  477. height: 170rpx;
  478. flex-shrink: 0;
  479. }
  480. }
  481. }
  482. }
  483. }
  484. }
  485. .push_button{
  486. position:relative;
  487. color:#FFF;
  488. display:block;
  489. text-decoration:none;
  490. margin:0 auto;
  491. border-radius:40rpx;
  492. text-align:center;
  493. padding:12rpx 80rpx;
  494. -webkit-transition: all 0.1s;
  495. -moz-transition: all 0.1s;
  496. transition: all 0.1s;
  497. background-color: rgba(232, 0, 0,.7);
  498. -webkit-box-shadow: 2px 4px 2px rgba(232, 0, 0,.5);
  499. -moz-box-shadow: 2px 4px 2px rgba(232, 0, 0,.5);
  500. box-shadow: 2px 4px 2px rgba(232, 0, 0,.5);
  501. }
  502. .push_button:active{
  503. -webkit-box-shadow: 0px 2px 0px rgba(232, 0, 0,.5);
  504. -moz-box-shadow: 0px 2px 0px rgba(232, 0, 0,.5);
  505. box-shadow: 0px 2px 0px rgba(232, 0, 0,.5);
  506. position:relative;
  507. top:7px;
  508. }
  509. .share_save_box {
  510. position: fixed;
  511. bottom: calc((100vh - 950rpx - 140rpx) / 4);
  512. left: 0;
  513. z-index: 6;
  514. width: 100%;
  515. display: flex;
  516. }
  517. </style>