Wechat applet api + front-end implementation to generate sharing posters

1. Look at the effect picture first, click the share poster button, and then the share poster will pop up

 2. Front-end code

The components used here include the vant component library and canvas_drawer (a canvas component)

Canvas_drawer download address https://github.com/kuckboy1994/mp_canvas_drawer

Copy the canvasdrawer in components to your own project, and then quote it in app.json, as follows

"usingComponents": {

    "canvasdrawer": "/static/canvasdrawer/canvasdrawer"

  }

Notice! Notice! Notice! The painting attribute of canvas_drawer cannot use local pictures in the canvas, otherwise it will not be displayed!

The data sources that need to be used

data () {
    return {
      isschb: true,
      xsxyid: 0,
      painting: null,
      showSharePosterPopup: false,
      sharePosterImg: '',
      xssptp: '', //现实的商品图片路径
      nickname: ''
    }
  },

The sharing poster I clicked here is an icon of a vant component library

<view style="position: fixed;bottom: 15%;left: 86%;">
        <view v-if="isschb">
          <van-icon name="photo-o" size="40px" style="margin-bottom: 10px;" color="#87CEEB"
            @click="generateSharePoster" />
        </view>
      </view>

Then the pop-up window also uses the Popup pop-up layer in vant

<!-- 预览海报弹窗 -->
      <van-popup :show="showSharePosterPopup" :close-on-click-overlay="true" round position="bottom"
        custom-style="height:80%;" @close="handleSharePosterPopupClose">
        <view style="height:50px;background:#eee;">
          <van-row>
            <van-col span="22">
              <view style="line-height:50px;" class="margin-left text-xl">保存到相册</view>
            </van-col>
            <van-col span="2">
              <van-icon custom-class="margin-top-sm" size="25" name="cross" @click="handleSharePosterPopupClose">
              </van-icon>
            </van-col>
          </van-row>
        </view>
        <img :src="sharePosterImg"
          style="width:70%;height:70%;margin-left:15%;margin-top:10px;border:1px solid #ddd;" />
        <view class="margin-lr margin-tb">
          <van-button type="danger" block @click="savePosterImg">保存图片</van-button>
        </view>
        <view class="margin-bottom text-center text-gray">保存图片到手机相册后,将图片分享到您的圈子</view>
        <canvasdrawer :painting="painting" @getImage="sharePosterImage" />
      </van-popup>

Then there is the method in Js

// 生成分享海报
    generateSharePoster () {
      let that = this
      wx.downloadFile({
        url: that.bzyrtx.replace('https://thirdwx.qlogo.cn', 'https://wx.qlogo.cn'),
        success: (res) => {
          var picurl = res.tempFilePath
          wx.showLoading({
            title: '海报生成中..',
            mask: true
          })
          let url = 'api/Xys/create/xcxcode?api-version=1&xyid=' + that.xsxyid
          that.$http
            .get(url)
            .then((res) => {
              if (res) {
                console.log(that.xssptp)
                console.log(that.$http.config.baseURL + '/' + res.data.Result)
                that.painting = {}
                that.painting = {
                  width: 375,
                  height: 555,
                  views: [
                    {
                      type: 'image',
                      url: 'https://pic1.zhimg.com/v2-fd0c04a3a78a4cc98831ba147a1de101_r.jpg?source=1940ef5c',//背景图片
                      top: 0,
                      left: 0,
                      width: 375,
                      height: 555
                    },
                    {
                      type: 'image',
                      url: picurl, // 微信头像
                      top: 27.5,
                      left: 29,
                      width: 55,
                      height: 55
                    },
                    {
                      type: 'text',
                      content: '您的好友【' + that.nickname + '】',// 微信昵称
                      fontSize: 16,
                      color: '#402D16',
                      textAlign: 'left',
                      top: 33,
                      left: 96,
                      bolder: true
                    },
                    {
                      type: 'text',
                      content: '请您帮其助愿',
                      fontSize: 15,
                      color: '#563D20',
                      textAlign: 'left',
                      top: 59.5,
                      left: 96
                    },
                    {
                      type: 'image',
                      url: that.xssptp,// 中间显示的商品图片
                      top: 100,
                      left: 10,
                      width: 350,
                      height: 290
                    },
                    {
                      type: 'image',
                      url: that.$http.config.baseURL + '/' + res.data.Result, // 小程序码
                      top: 453,
                      left: 25,
                      width: 80,
                      height: 80
                    },
                    {
                      type: 'text',
                      content: '一份心愿,一丝情意',
                      fontSize: 16,
                      lineHeight: 21,
                      color: '#383549',
                      textAlign: 'left',
                      top: 406,
                      left: 44,
                      width: 287,
                      MaxLineNumber: 2,
                      breakWord: true,
                      bolder: true
                    },
                    {
                      type: 'text',
                      content: '小程序名称',
                      fontSize: 16,
                      color: '#000',
                      textAlign: 'left',
                      top: 470,
                      left: 110.5,
                      lineHeight: 20,
                      MaxLineNumber: 2,
                      breakWord: true,
                      width: 125
                    },
                    {
                      type: 'text',
                      content: '长按识别,去逛逛',
                      fontSize: 14,
                      color: '#383549',
                      textAlign: 'left',
                      top: 495,
                      left: 110.5,
                      lineHeight: 20,
                      MaxLineNumber: 2,
                      breakWord: true,
                      width: 125
                    }
                  ]
                }

                that.showSharePosterPopup = true
              }
            })
        }
      })
    },
    // 关闭弹出层
    handleSharePosterPopupClose () {
      this.showSharePosterPopup = false
    },
    // 画布生成的图片
    sharePosterImage (event) {
      this.sharePosterImg = event.mp.detail.tempFilePath
      wx.hideLoading()
    },
    // 保存图片
    savePosterImg () {
      let that = this
      wx.saveImageToPhotosAlbum({
        filePath: that.sharePosterImg,
        success (res) {
          wx.showToast({
            title: '已保存到相册,可以去发朋友圈啦~',
            icon: 'none',
            duration: 2000
          })
        },
        fail (res) {
          wx.showToast({
            title: '保存失败',
            icon: 'none',
            duration: 2000
          })
        }
      })
    }

2. Backend api code (this is to obtain the small program code)

page is the interface to enter by scanning the code. Note that the applet must be published, and there is this interface . The parameters passed are the parameters to be passed on the page entered by scanning the code, and can only be placed in the scene. For more information, please refer to the official website . document

controller layer

/// <summary>
        /// 创建小程序码
        /// </summary>
        /// <param name="xyid"></param>
        /// <returns></returns>
        [Route("api/Xys/create/xcxcode")]
        [AllowAnonymous]
        [HttpGet]
        public Response GenerateWxxcxCode([FromUri] int xyid)
        {
            return xysBLL.CreateXcxCode(xyid);
        }

wxAppId is the appid of the applet, and wxSecret is the key of the applet, which must be configured in the web.config configuration file

web.config file configuration

<add key="wxAppId" value="(小程序appid)" />
	  <add key="wxSecret" value="(小程序密钥)" />

The classes used in the business logic layer and the methods in them

 WxHelper

public class WxHelper
    {

        /// <summary>
        /// 获取请求凭据
        /// </summary>
        /// <returns></returns>
        public static string GetAccessToken(string appId, string secret)
        {
            var token = RedisHelper.StringGet("access_token");
            if (string.IsNullOrWhiteSpace(token))
            {
                lock (locker)
                {
                    if (string.IsNullOrWhiteSpace(token))
                    {
                        HttpClient client = new HttpClient();
                        string url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";

                        url = string.Format(url, appId, secret);
                        var result = client.GetStringAsync(url).Result;
                        var rsp = JsonConvert.DeserializeObject<RspAccessToken>(result);
                        if (string.IsNullOrWhiteSpace(rsp.Errmsg))
                        {
                            //提前5分钟失效
                            DateTime expireTime = DateTime.Now.AddSeconds(rsp.Expires_in - 300);
                            TimeSpan expireTs = new TimeSpan(expireTime.Ticks);
                            TimeSpan nowTs = new TimeSpan(DateTime.Now.Ticks);

                            RedisHelper.StringSet("access_token", rsp.Access_token, expireTs.Subtract(nowTs));
                            token = rsp.Access_token;
                        }
                        else
                        {
                            throw new Exception("获取微信请求凭据失败!" + rsp.Errmsg);
                        }
                    }
                }
            }
            return token;
        }

    }

 RspAccessToken

 public class RspAccessToken
    {
        public string Access_token
        {
            get;
            set;
        }
        public int Expires_in
        {
            get;
            set;
        }
        public int Errcode
        {
            get;
            set;
        }
        public string Errmsg
        {
            get;
            set;
        }
    }

 RedisHelper

public static class RedisHelper
    {
        private static readonly string redisConn = ConfigurationManager.AppSettings["redis"];
        private static readonly string redisHost = ConfigurationManager.AppSettings["redisHost"];
        private static readonly string redisPort = ConfigurationManager.AppSettings["redisPort"];
        private static readonly string redisPwd = ConfigurationManager.AppSettings["redisPwd"];
        private static readonly string dbNumber = ConfigurationManager.AppSettings["redisDbNumber"];

        private static readonly object locker = new object();
        private static ConnectionMultiplexer connectionMultiplexer;
        private static IDatabase database;

        private static IDatabase GetDatabase()
        {
            if(database == null)
            {
                lock (locker)
                {
                    if(connectionMultiplexer == null || !connectionMultiplexer.IsConnected)
                    {
                        //string connStr = "{0}:{1},allowAdmin = true,password = {2}";
                        //connStr = string.Format(connStr, redisHost, redisPort, redisPwd);
                        //connectionMultiplexer = ConnectionMultiplexer.Connect(connStr);
                        connectionMultiplexer = ConnectionMultiplexer.Connect(redisConn);
                        database = connectionMultiplexer.GetDatabase(int.Parse(dbNumber));
                    }
                }
            }
            return database;         
        }

        /// <summary>
        /// 保存自增字符串
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="redisValue"></param>
        /// <param name="expiry"></param>
        /// <returns></returns>
        public static long StringIncrementSet(string redisKey, long redisValue)
        {
            return GetDatabase().StringIncrement(redisKey, redisValue);
        }

        /// <summary>
        /// 保存字符串
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="redisValue"></param>
        /// <param name="expiry"></param>
        /// <returns></returns>
        public static bool StringSet(string redisKey, string redisValue, TimeSpan? expiry)
        {
            return GetDatabase().StringSet(redisKey, redisValue, expiry);
        }

        /// <summary>
        /// 保存一个对象,该对象会被序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="redisKey"></param>
        /// <param name="redisValue"></param>
        /// <param name="exipry"></param>
        /// <returns></returns>
        public static bool StringSet<T>(string redisKey, T redisValue, TimeSpan? exipry)
        {
            string rValue = Newtonsoft.Json.JsonConvert.SerializeObject(redisValue);
            return GetDatabase().StringSet(redisKey, rValue, exipry);
        }

        /// <summary>
        /// 删除指定字符串
        /// </summary>
        /// <param name="redisKey"></param>
        /// <returns></returns>
        public static bool KeyDelete(string redisKey)
        {
            return GetDatabase().KeyDelete(redisKey);
        }

        /// <summary>
        /// 获取字符串
        /// </summary>
        /// <param name="redisKey"></param>
        /// <returns></returns>
        public static string StringGet(string redisKey)
        {
            return GetDatabase().StringGet(redisKey);
        }

        /// <summary>
        /// 获取一个对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="redisKey"></param>
        /// <returns></returns>
        public static T StringGet<T>(string redisKey)
        {
            var objct = GetDatabase().StringGet(redisKey);

            return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(objct);
        }
    }

 business logic layer

private static readonly string AppId = ConfigurationManager.AppSettings["wxAppId"];
        private static readonly string Secret = ConfigurationManager.AppSettings["wxSecret"];

        private static readonly HttpClient httpClient = new HttpClient();
        private static readonly string CREATE_XCXCODE_PATH = "upload/wx/xcxcode/";
/// <summary>
        /// 生成小程序码
        /// </summary>
        /// <returns></returns>
        public Response CreateXcxCode(int xyid)
        {
            string token = WxHelper.GetAccessToken(AppId, Secret);


            string url2 = $"https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={token}";
            string page = "";
            page = "pages/xyjbzy/main";
            var obj = new
            {
                page = page,
                scene = xyid
            };
            var jsonStr = JsonConvert.SerializeObject(obj);
            Logger logger = LogManager.GetCurrentClassLogger();
            WebRequestHandler handler = new WebRequestHandler();
            logger.Info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            logger.Info(jsonStr);
            logger.Info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            HttpResponseMessage response = httpClient.PostAsJsonAsync(url2, obj).Result;
            response.EnsureSuccessStatusCode();

            string fileFullPath = "";
            using (var stream = response.Content.ReadAsStreamAsync().GetAwaiter().GetResult())
            {
                string basePath = AppDomain.CurrentDomain.BaseDirectory;

                string filePath = CREATE_XCXCODE_PATH + DateTime.Now.ToString("yyyyMMdd") + "/";

                if (!Directory.Exists(basePath + filePath))
                {
                    Directory.CreateDirectory(basePath + filePath);
                }
                string fileName = Guid.NewGuid().ToString("N") + ".jpeg";

                fileFullPath = filePath + fileName;


                using (BinaryReader binreader = new BinaryReader(stream))
                {
                    byte[] bytes = binreader.ReadBytes(Convert.ToInt32(stream.Length));

                    using (var streamSub = new MemoryStream(bytes))
                    {
                        var img = Image.FromStream(stream);
                        img.Save(basePath + fileFullPath, System.Drawing.Imaging.ImageFormat.Jpeg);
                    }
                }
                
                   

                return new Response
                {
                    Result = fileFullPath
                };
            }
        }

The above are all the steps, it may not be very detailed, but I have tried my best, I hope it will be helpful to you

Guess you like

Origin blog.csdn.net/growb/article/details/126299602