yukangzhe 4 years ago
parent
commit
3f1c33a79a

+ 521 - 0
pages/Components/miniprogram_dist/index/index.js

@@ -0,0 +1,521 @@
+const main = {
+  /**
+   * 渲染块
+   * @param {Object} params
+   */
+  drawBlock({ text, width = 0, height, x, y, paddingLeft = 0, paddingRight = 0, borderWidth, backgroundColor, borderColor, borderRadius = 0, opacity = 1 }) {
+      // 判断是否块内有文字
+      let blockWidth = 0; // 块的宽度
+      let textX = 0;
+      let textY = 0;
+      if (typeof text !== undefined) {
+          // 如果有文字并且块的宽度小于文字宽度,块的宽度为 文字的宽度 + 内边距
+          const textWidth = this._getTextWidth(typeof text.text === 'string' ? text : text.text);
+          blockWidth = textWidth > width ? textWidth : width;
+          blockWidth += paddingLeft + paddingLeft;
+
+          const { textAlign = 'left', text: textCon } = text;
+          textY = height / 2 + y; // 文字的y轴坐标在块中线
+          if (textAlign === 'left') {
+              // 如果是右对齐,那x轴在块的最左边
+              textX = x + paddingLeft;
+          } else if (textAlign === 'center') {
+              textX = blockWidth / 2 + x;
+          } else {
+              textX = x + blockWidth - paddingRight;
+          }
+      } else {
+          blockWidth = width;
+      }
+
+      if (backgroundColor) {
+          // 画面
+          this.ctx.save();
+          this.ctx.setGlobalAlpha(opacity);
+          this.ctx.setFillStyle(backgroundColor);
+          if (borderRadius > 0) {
+              // 画圆角矩形
+              this._drawRadiusRect(x, y, blockWidth, height, borderRadius);
+              this.ctx.fill();
+          } else {
+              this.ctx.fillRect(this.toPx(x), this.toPx(y), this.toPx(blockWidth), this.toPx(height));
+          }
+          this.ctx.restore();
+      }
+      if (borderWidth) {
+          // 画线
+          this.ctx.save();
+          this.ctx.setGlobalAlpha(opacity);
+          this.ctx.setStrokeStyle(borderColor);
+          this.ctx.setLineWidth(this.toPx(borderWidth));
+          if (borderRadius > 0) {
+              // 画圆角矩形边框
+              this._drawRadiusRect(x, y, blockWidth, height, borderRadius);
+              this.ctx.stroke();
+          } else {
+              this.ctx.strokeRect(this.toPx(x), this.toPx(y), this.toPx(blockWidth), this.toPx(height));
+          }
+          this.ctx.restore();
+      }
+
+      if (text) {
+          this.drawText(Object.assign(text, { x: textX, y: textY }))
+      }
+  },
+
+  /**
+   * 渲染文字
+   * @param {Object} params
+   */
+  drawText(params) {
+      const { x, y, fontSize, color, baseLine, textAlign, text, opacity = 1, width, lineNum, lineHeight } = params;
+      if (Object.prototype.toString.call(text) === '[object Array]') {
+          let preText = { x, y, baseLine };
+          text.forEach(item => {
+              preText.x += item.marginLeft || 0;
+              const textWidth = this._drawSingleText(Object.assign(item, {
+                  ...preText,
+              }));
+              preText.x += textWidth + (item.marginRight || 0); // 下一段字的x轴为上一段字x + 上一段字宽度
+          })
+      } else {
+          this._drawSingleText(params);
+      }
+  },
+
+  /**
+   * 渲染图片
+   */
+  drawImage(data) {
+      const { imgPath, x, y, w, h, sx, sy, sw, sh, borderRadius = 0, borderWidth = 0, borderColor } = data;
+      this.ctx.save();
+      if (borderRadius > 0) {
+          this._drawRadiusRect(x, y, w, h, borderRadius);
+          this.ctx.strokeStyle = 'rgba(255,255,255,0)';
+          this.ctx.stroke();
+          this.ctx.clip();
+          this.ctx.drawImage(imgPath, this.toPx(sx), this.toPx(sy), this.toPx(sw), this.toPx(sh), this.toPx(x), this.toPx(y), this.toPx(w), this.toPx(h));
+          if (borderWidth > 0) {
+              this.ctx.setStrokeStyle(borderColor);
+              this.ctx.setLineWidth(this.toPx(borderWidth));
+              this.ctx.stroke();
+          }
+      } else {
+          this.ctx.drawImage(imgPath, this.toPx(sx), this.toPx(sy), this.toPx(sw), this.toPx(sh), this.toPx(x), this.toPx(y), this.toPx(w), this.toPx(h));
+      }
+      this.ctx.restore();
+  },
+  /**
+   * 渲染线
+   * @param {*} param0
+   */
+  drawLine({ startX, startY, endX, endY, color, width }) {
+      this.ctx.save();
+      this.ctx.beginPath();
+      this.ctx.setStrokeStyle(color);
+      this.ctx.setLineWidth(this.toPx(width));
+      this.ctx.moveTo(this.toPx(startX), this.toPx(startY));
+      this.ctx.lineTo(this.toPx(endX), this.toPx(endY));
+      this.ctx.stroke();
+      this.ctx.closePath();
+      this.ctx.restore();
+  },
+  downloadResource({ images = [], pixelRatio = 1 }) {
+      const drawList = [];
+      this.drawArr = [];
+      images.forEach((image, index) => drawList.push(this._downloadImageAndInfo(image, index, pixelRatio)));
+      return Promise.all(drawList);
+  },
+  initCanvas(w, h, debug) {
+      return new Promise((resolve) => {
+          this.setData({
+              pxWidth: this.toPx(w),
+              pxHeight: this.toPx(h),
+              debug,
+          }, resolve);
+      });
+  }
+}
+const handle = {
+  /**
+   * 画圆角矩形
+   */
+  _drawRadiusRect(x, y, w, h, r) {
+      const br = r / 2;
+      this.ctx.beginPath();
+      this.ctx.moveTo(this.toPx(x + br), this.toPx(y));    // 移动到左上角的点
+      this.ctx.lineTo(this.toPx(x + w - br), this.toPx(y));
+      this.ctx.arc(this.toPx(x + w - br), this.toPx(y + br), this.toPx(br), 2 * Math.PI * (3 / 4), 2 * Math.PI * (4 / 4))
+      this.ctx.lineTo(this.toPx(x + w), this.toPx(y + h - br));
+      this.ctx.arc(this.toPx(x + w - br), this.toPx(y + h - br), this.toPx(br), 0, 2 * Math.PI * (1 / 4))
+      this.ctx.lineTo(this.toPx(x + br), this.toPx(y + h));
+      this.ctx.arc(this.toPx(x + br), this.toPx(y + h - br), this.toPx(br), 2 * Math.PI * (1 / 4), 2 * Math.PI * (2 / 4))
+      this.ctx.lineTo(this.toPx(x), this.toPx(y + br));
+      this.ctx.arc(this.toPx(x + br), this.toPx(y + br), this.toPx(br), 2 * Math.PI * (2 / 4), 2 * Math.PI * (3 / 4))
+  },
+  /**
+   * 计算文本长度
+   * @param {Array|Object}} text 数组 或者 对象
+   */
+  _getTextWidth(text) {
+      let texts = [];
+      if (Object.prototype.toString.call(text) === '[object Object]') {
+          texts.push(text);
+      } else {
+          texts = text;
+      }
+      let width = 0;
+      texts.forEach(({ fontSize, text, marginLeft = 0, marginRight = 0 }) => {
+          this.ctx.setFontSize(this.toPx(fontSize));
+          width += this.ctx.measureText(text).width + marginLeft + marginRight;
+      })
+
+      return this.toRpx(width);
+  },
+  /**
+   * 渲染一段文字
+   */
+  _drawSingleText({ x, y, fontSize, color, baseLine, textAlign = 'left', text, opacity = 1, textDecoration = 'none',
+    width, lineNum = 1, lineHeight = 0, fontWeight = 'normal', fontStyle = 'normal', fontFamily = "sans-serif"}) {
+      this.ctx.save();
+      this.ctx.beginPath();
+      this.ctx.font = fontStyle + " " + fontWeight + " " + this.toPx(fontSize, true) + "px " + fontFamily
+      this.ctx.setGlobalAlpha(opacity);
+      // this.ctx.setFontSize(this.toPx(fontSize));
+      this.ctx.setFillStyle(color);
+      this.ctx.setTextBaseline(baseLine);
+      this.ctx.setTextAlign(textAlign);
+      let textWidth = this.toRpx(this.ctx.measureText(text).width);
+      const textArr = [];
+       if (textWidth > width) {
+        // 文本宽度 大于 渲染宽度
+        let fillText = '';
+        let line = 1;
+        for (let i = 0; i <= text.length - 1 ; i++) {  // 将文字转为数组,一行文字一个元素
+          fillText = fillText + text[i];
+          if (this.toRpx(this.ctx.measureText(fillText).width) >= width) {
+            if (line === lineNum) {
+              if (i !== text.length - 1) {
+                fillText = fillText.substring(0, fillText.length - 1) + '...';
+              }
+            }
+            if(line <= lineNum) {
+              textArr.push(fillText);
+            }
+            fillText = '';
+            line++;
+          } else {
+            if(line <= lineNum) {
+              if(i === text.length -1){
+                 textArr.push(fillText);
+              }
+            }
+          }
+        }
+        textWidth = width;
+      } else {
+        textArr.push(text);
+      }
+
+      textArr.forEach((item, index) => {
+          this.ctx.fillText(item, this.toPx(x), this.toPx(y + (lineHeight || fontSize) * index));
+      })
+
+      this.ctx.restore();
+
+      // textDecoration
+      if (textDecoration !== 'none') {
+          let lineY = y;
+          if (textDecoration === 'line-through') {
+              // 目前只支持贯穿线
+              lineY = y;
+
+              // 小程序画布baseLine偏移阈值
+              let threshold = 5;
+
+              // 根据baseLine的不同对贯穿线的Y坐标做相应调整
+              switch (baseLine) {
+                case 'top':
+                  lineY += fontSize / 2 + threshold;
+                  break;
+                case 'middle':
+                  break;
+                case 'bottom':
+                  lineY -= fontSize / 2 + threshold;
+                  break;
+                default:
+                  lineY -= fontSize / 2 - threshold;
+                  break;
+              }
+          }
+          this.ctx.save();
+          this.ctx.moveTo(this.toPx(x), this.toPx(lineY));
+          this.ctx.lineTo(this.toPx(x) + this.toPx(textWidth), this.toPx(lineY));
+          this.ctx.setStrokeStyle(color);
+          this.ctx.stroke();
+          this.ctx.restore();
+      }
+
+      return textWidth;
+  },
+}
+const helper = {
+  /**
+    * 下载图片并获取图片信息
+    */
+  _downloadImageAndInfo(image, index, pixelRatio) {
+      return new Promise((resolve, reject) => {
+          const { x, y, url, zIndex } = image;
+          const imageUrl = url;
+          // 下载图片
+          this._downImage(imageUrl, index)
+              // 获取图片信息
+              .then(imgPath => this._getImageInfo(imgPath, index))
+              .then(({ imgPath, imgInfo }) => {
+                  // 根据画布的宽高计算出图片绘制的大小,这里会保证图片绘制不变形
+                  let sx;
+                  let sy;
+                  const borderRadius = image.borderRadius || 0;
+                  const setWidth = image.width;
+                  const setHeight = image.height;
+                  const width = this.toRpx(imgInfo.width / pixelRatio);
+                  const height = this.toRpx(imgInfo.height / pixelRatio);
+
+                  if (width / height <= setWidth / setHeight) {
+                      sx = 0;
+                      sy = (height - ((width / setWidth) * setHeight)) / 2;
+                  } else {
+                      sy = 0;
+                      sx = (width - ((height / setHeight) * setWidth)) / 2;
+                  }
+                  this.drawArr.push({
+                      type: 'image',
+                      borderRadius,
+                      borderWidth: image.borderWidth,
+                      borderColor: image.borderColor,
+                      zIndex: typeof zIndex !== undefined ? zIndex : index,
+                      imgPath,
+                      sx,
+                      sy,
+                      sw: (width - (sx * 2)),
+                      sh: (height - (sy * 2)),
+                      x,
+                      y,
+                      w: setWidth,
+                      h: setHeight,
+                  });
+                  resolve();
+              })
+              .catch(err => reject(err));
+      });
+  },
+  /**
+   * 下载图片资源
+   * @param {*} imageUrl
+   */
+  _downImage(imageUrl) {
+      return new Promise((resolve, reject) => {
+          if (/^http/.test(imageUrl) && !new RegExp(wx.env.USER_DATA_PATH).test(imageUrl)) {
+              wx.downloadFile({
+                  url: this._mapHttpToHttps(imageUrl),
+                  success: (res) => {
+                      if (res.statusCode === 200) {
+                          resolve(res.tempFilePath);
+                      } else {
+                          reject(res.errMsg);
+                      }
+                  },
+                  fail(err) {
+                      reject(err);
+                  },
+              });
+          } else {
+              // 支持本地地址
+              resolve(imageUrl);
+          }
+      });
+  },
+  /**
+   * 获取图片信息
+   * @param {*} imgPath
+   * @param {*} index
+   */
+  _getImageInfo(imgPath, index) {
+      return new Promise((resolve, reject) => {
+          wx.getImageInfo({
+              src: imgPath,
+              success(res) {
+                  resolve({ imgPath, imgInfo: res, index });
+              },
+              fail(err) {
+                  reject(err);
+              },
+          });
+      });
+  },
+  toPx(rpx, int) {
+    if (int) {
+      return parseInt(rpx * this.factor * this.pixelRatio);
+    }
+    return rpx * this.factor * this.pixelRatio;
+
+  },
+  toRpx(px, int) {
+    if (int) {
+      return parseInt(px / this.factor);
+    }
+    return px / this.factor;
+  },
+  /**
+   * 将http转为https
+   * @param {String}} rawUrl 图片资源url
+   */
+  _mapHttpToHttps(rawUrl) {
+      if (rawUrl.indexOf(':') < 0) {
+          return rawUrl;
+      }
+      const urlComponent = rawUrl.split(':');
+      if (urlComponent.length === 2) {
+          if (urlComponent[0] === 'http') {
+              urlComponent[0] = 'https';
+              return `${urlComponent[0]}:${urlComponent[1]}`;
+          }
+      }
+      return rawUrl;
+  },
+}
+Component({
+  properties: {
+  },
+  created() {
+      const sysInfo = wx.getSystemInfoSync();
+      const screenWidth = sysInfo.screenWidth;
+      this.factor = screenWidth / 750;
+  },
+  methods: Object.assign({
+      /**
+       * 计算画布的高度
+       * @param {*} config
+       */
+      getHeight(config) {
+          const getTextHeight = (text) => {
+              let fontHeight = text.lineHeight || text.fontSize;
+              let height = 0;
+              if (text.baseLine === 'top') {
+                  height = fontHeight;
+              } else if (text.baseLine === 'middle') {
+                  height = fontHeight / 2;
+              } else {
+                  height = 0;
+              }
+              return height;
+          }
+          const heightArr = [];
+          (config.blocks || []).forEach((item) => {
+              heightArr.push(item.y + item.height);
+          });
+          (config.texts  || []).forEach((item) => {
+              let height;
+              if (Object.prototype.toString.call(item.text) === '[object Array]') {
+                  item.text.forEach((i) => {
+                      height = getTextHeight({...i, baseLine: item.baseLine});
+                      heightArr.push(item.y + height);
+                  });
+              } else {
+                  height = getTextHeight(item);
+                  heightArr.push(item.y + height);
+              }
+          });
+          (config.images || []).forEach((item) => {
+              heightArr.push(item.y + item.height);
+          });
+          (config.lines || []).forEach((item) => {
+              heightArr.push(item.startY);
+              heightArr.push(item.endY);
+          });
+          const sortRes = heightArr.sort((a, b) => b - a);
+          let canvasHeight = 0;
+          if (sortRes.length > 0) {
+              canvasHeight = sortRes[0];
+          }
+          if (config.height < canvasHeight || !config.height) {
+              return canvasHeight;
+          } else {
+              return config.height;
+          }
+      },
+      create(config) {
+          this.ctx = wx.createCanvasContext('canvasid', this);
+
+          this.pixelRatio = config.pixelRatio || 1;
+          const height = this.getHeight(config);
+          this.initCanvas(config.width, height, config.debug)
+              .then(() => {
+                  // 设置画布底色
+                  if (config.backgroundColor) {
+                      this.ctx.save();
+                      this.ctx.setFillStyle(config.backgroundColor);
+                      this.ctx.fillRect(0, 0, this.toPx(config.width), this.toPx(height));
+                      this.ctx.restore();
+                  }
+                  const { texts = [], images = [], blocks = [], lines = [] } = config;
+                  const queue = this.drawArr
+                      .concat(texts.map((item) => {
+                          item.type = 'text';
+                          item.zIndex = item.zIndex || 0;
+                          return item;
+                      }))
+                      .concat(blocks.map((item) => {
+                          item.type = 'block';
+                          item.zIndex = item.zIndex || 0;
+                          return item;
+                      }))
+                      .concat(lines.map((item) => {
+                          item.type = 'line';
+                          item.zIndex = item.zIndex || 0;
+                          return item;
+                      }));
+                  // 按照顺序排序
+                  queue.sort((a, b) => a.zIndex - b.zIndex);
+
+                  queue.forEach((item) => {
+                      if (item.type === 'image') {
+                          this.drawImage(item)
+                      } else if (item.type === 'text') {
+                          this.drawText(item)
+                      } else if (item.type === 'block') {
+                          this.drawBlock(item)
+                      } else if (item.type === 'line') {
+                          this.drawLine(item)
+                      }
+                  });
+
+                  const res = wx.getSystemInfoSync();
+                  const platform = res.platform;
+                  let time = 0;
+                  if (platform === 'android') {
+                      // 在安卓平台,经测试发现如果海报过于复杂在转换时需要做延时,要不然样式会错乱
+                      time = 300;
+                  }
+                  this.ctx.draw(false, () => {
+                      setTimeout(() => {
+                          wx.canvasToTempFilePath({
+                              canvasId: 'canvasid',
+                              success: (res) => {
+                                  this.triggerEvent('success', res.tempFilePath);
+                              },
+                              fail: (err) => {
+                                  this.triggerEvent('fail', err);
+                              },
+                          }, this);
+                      }, time);
+                  });
+              })
+              .catch((err) => {
+                  wx.showToast({ icon: 'none', title: err.errMsg || '生成失败' });
+                  console.error(err);
+              });
+      },
+  }, main, handle, helper),
+});
+

+ 3 - 0
pages/Components/miniprogram_dist/index/index.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 4 - 0
pages/Components/miniprogram_dist/index/index.wxml

@@ -0,0 +1,4 @@
+<!--index.wxml-->
+<view class="container">
+  <canvas canvas-id='canvasid' class="canvas {{debug ? 'debug' : 'pro'}}" style='width: {{pxWidth}}px; height: {{pxHeight}}px;'></canvas>
+</view>

+ 16 - 0
pages/Components/miniprogram_dist/index/index.wxss

@@ -0,0 +1,16 @@
+.canvas {
+  width: 750rpx;
+  height: 750rpx;
+}
+.canvas.pro {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  transform: translate3d(-9999rpx, 0, 0);
+}
+.canvas.debug {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  border: 1rpx solid #ccc;
+}

+ 87 - 0
pages/Components/miniprogram_dist/poster/index.js

@@ -0,0 +1,87 @@
+Component({
+  properties: {
+      config: {
+          type: Object,
+          value: {},
+      },
+      preload: {  // 是否预下载图片资源
+          type: Boolean,
+          value: false,
+      },
+      hideLoading: {  // 是否隐藏loading
+          type: Boolean,
+          value: false,
+      }
+  },
+  ready() {
+      if (this.data.preload) {
+          const poster = this.selectComponent('#poster');
+          this.downloadStatus = 'doing';
+          poster.downloadResource(this.data.config).then(() => {
+              this.downloadStatus = 'success';
+              this.trigger('downloadSuccess');
+          }).catch((e) => {
+              this.downloadStatus = 'fail';
+              this.trigger('downloadFail', e);
+          });
+      }
+  },
+  methods: {
+      trigger(event, data) {
+          if (this.listener && typeof this.listener[event] === 'function') {
+              this.listener[event](data);
+          }
+      },
+      once(event, fun) {
+          if (typeof this.listener === 'undefined') {
+              this.listener = {};
+          }
+          this.listener[event] = fun;
+      },
+      downloadResource(reset) {
+          return new Promise((resolve, reject) => {
+              if (reset) {
+                  this.downloadStatus = null;
+              }
+              const poster = this.selectComponent('#poster');
+              if (this.downloadStatus && this.downloadStatus !== 'fail') {
+                  if (this.downloadStatus === 'success') {
+                      resolve();
+                  } else {
+                      this.once('downloadSuccess', () => resolve());
+                      this.once('downloadFail', (e) => reject(e));
+                  }
+              } else {
+                  poster.downloadResource(this.data.config)
+                      .then(() => {
+                          this.downloadStatus = 'success';
+                          resolve();
+                      })
+                      .catch((e) => reject(e));
+              }  
+          })
+      },
+      onCreate(reset = false) {
+          !this.data.hideLoading && wx.showLoading({ mask: true, title: '生成中' });
+          return this.downloadResource(typeof reset === 'boolean' && reset).then(() => {
+              !this.data.hideLoading && wx.hideLoading();
+              const poster = this.selectComponent('#poster');
+              poster.create(this.data.config);
+          })
+          .catch((err) => {
+              !this.data.hideLoading && wx.hideLoading();
+              wx.showToast({ icon: 'none', title: err.errMsg || '生成失败' });
+              console.error(err);
+              this.triggerEvent('fail', err);
+          })
+      },
+      onCreateSuccess(e) {
+          const { detail } = e;
+          this.triggerEvent('success', detail);
+      },
+      onCreateFail(err) {
+          console.error(err);
+          this.triggerEvent('fail', err);
+      }
+  }
+})

+ 6 - 0
pages/Components/miniprogram_dist/poster/index.json

@@ -0,0 +1,6 @@
+{
+  "component": true,
+  "usingComponents": {
+      "we-canvas": "../index/index"
+  }
+}

+ 4 - 0
pages/Components/miniprogram_dist/poster/index.wxml

@@ -0,0 +1,4 @@
+<view bindtap='onCreate'>
+    <slot/>
+</view>
+<we-canvas id="poster" bind:success="onCreateSuccess" bind:fail="onCreateFail"/>

+ 1 - 0
pages/Components/miniprogram_dist/poster/index.wxss

@@ -0,0 +1 @@
+/* pages/Components/miniprogram_dist/poster/index.wxss */

+ 29 - 0
pages/Components/miniprogram_dist/poster/poster.js

@@ -0,0 +1,29 @@
+const defaultOptions = {
+  selector: '#poster'
+};
+
+function Poster(options = {}, that) {
+  options = {
+      ...defaultOptions,
+      ...options,
+  };
+
+  const pages = getCurrentPages();
+  let ctx = pages[pages.length - 1];
+  if (that) ctx = that
+  const poster = ctx.selectComponent(options.selector);
+  delete options.selector;
+
+  return poster;
+};
+
+Poster.create = (reset = false, that) => {
+  const poster  = Poster({}, that);
+  if (!poster) {
+      console.error('请设置组件的id="poster"!!!');
+  } else {
+      return Poster({}, that).onCreate(reset);
+  }
+}
+
+export default Poster;

+ 472 - 0
pages/Components/reservation/reservation.js

@@ -0,0 +1,472 @@
+// pages/Components/reservation/reservation.js
+const app = getApp()
+const util = require('../../../utils/util.js')
+const base64Util = require('../../../utils/base64')
+Component({
+  lifetimes: {
+    attached: function () {
+      // 在组件实例进入页面节点树时执行
+      
+      
+    },
+    ready:function(){
+      this.setData({
+        // 'posterConfig.images[0].url': '',
+        // 'posterConfig.images[1].url': '',
+        // 'posterConfig.texts[0].text': '',
+        // 'posterConfig.texts[1].text': '',
+        campusInfo: wx.getStorageSync('campusInfo'),
+        imageUrl: app.globalData.imageUrl,
+        'object.name':wx.getStorageSync('campusInfo').name,
+        'object.showImg': wx.getStorageSync('shareImg'),
+        // 'object.codeImg': app.globalData.imageUrl + 'excl.jpg',
+      })
+      this.isApple()
+    },
+  },
+  
+  
+  pageLifetimes: {
+    show:function() {
+      
+    },
+  },
+  properties: {
+    buttonText: {
+      type: String,
+      value: '预约试听'
+    },
+    buttonURL: {
+      type: String,
+      value: '/pages/appointmentListen/appointmentListen'
+    },
+    disabled:{
+      type:Boolean,
+      value:false
+    },
+    activeShow:{
+      type:Boolean,
+      value:false 
+    },
+    object:{
+      type:Object,
+      value:{}
+    },
+    isBuy:{
+      type: Boolean,
+      value:false
+    },
+    isBuyText:{
+      type: String,
+      value: '已购买'
+    },
+    isId:{
+      type: String,
+      value: ''
+    },
+    typeId:{
+      type:String,
+      value:''
+    },
+    showText:{
+      type:String,
+      value:''
+    },
+    titleText:{
+      type:String,
+      value:''
+    },
+    shareImg:{
+      type:String,
+      value:''
+    }
+  },
+ 
+  data: {
+    wechatImg:app.globalData.imageUrl + 'wechat0706.png',
+    pyqImg:app.globalData.imageUrl + 'pyq0706.png',
+    codeImg:app.globalData.imageUrl,
+    showSaveImage:false,
+    bgShow: true,
+    bottomFlag: false,
+    phoneList:[
+      'iPhone X' , 
+      'iPhone XR' ,
+      'iPhone XS Max',
+      'iPhone 11' ,
+      'iPhone 11 Pro' ,
+      'iPhone 11 Pro Max'
+    ],
+    posterConfig: {
+      'width': 590,
+      'height': 680,
+      'backgroundColor': '#fff',
+      'debug': false,
+      'preload': true,
+      'hide-loading': true,
+      images: [{
+        x: 24,
+        y: 38,
+        url: '',
+        width: 542,
+        height: 406
+      }, {
+        x: 424,
+        y: 520,
+        url: '',
+        width: 144,
+        height: 144
+      }],
+      texts: [
+        {
+          x: 24,
+          y: 492,
+          baseLine: 'middle',
+          text: '',
+          fontSize: 24,
+          color: '#333333',
+        }, {
+          x: 24,
+          y: 520,
+          baseLine: 'middle',
+          text: '',
+          fontWeight: 'bold',
+          fontSize: 28,
+          color: '#333333',
+        },
+        {
+          x: 303,
+          y: 570,
+          baseLine: 'middle',
+          text: '长按二维码',
+          fontSize: 20,
+          color: '#999999',
+        },
+        {
+          x: 303,
+          y: 600,
+          baseLine: 'middle',
+          text: '查看',
+          fontSize: 20,
+          color: '#999999',
+        }
+      ]
+    },
+  },
+  methods: {
+    isApple:function(){
+      wx.getSystemInfo({//当小程序初始化完成时 获取用户的手机机型 并写出适配ipnone手机安全区域的的适配方案
+        success: (res) => {
+          const phone = res.model.split(" ")
+          this.data.phoneList.forEach(item => {
+              if(item == phone[0]+ ' ' + phone[1]){
+                this.setData({
+                  bottomFlag:true
+                })
+                return false;
+              }
+          });
+        }
+      })
+    },
+    jumpPage(e) {
+      if (this.data.campusInfo.userId) {
+        wx.navigateTo({
+          url: e.currentTarget.dataset.url,
+        })
+      } else {
+        wx.showModal({
+          title: '温馨提示',
+          content: '您还未选择校区,是否要去查看附近的校区?',
+          confirmText: '查看校区',
+          success(res) {
+            if (res.confirm) {
+              wx.navigateTo({
+                url: '/pages/campusDistribution/campusDistribution',
+              })
+            } else if (res.cancel) {
+              console.log('用户点击取消')
+            }
+          }
+        })
+      }
+
+    },
+    backIndexPage() {
+      // wx.switchTab({
+      //   url: '/pages/tabBar/index/index',
+      // })
+      wx.redirectTo({
+        url: '/pages/tabBar/index/index',
+      })
+    },
+    advisory() {
+      if (this.data.campusInfo.userId) {
+        wx.makePhoneCall({
+          phoneNumber: this.data.campusInfo.telephone,
+        })
+        return
+      }
+      wx.showModal({
+        title: '温馨提示',
+        content: '您还未选择校区,是否要去查看附近的校区?',
+        confirmText: '查看校区',
+        success(res) {
+          if (res.confirm) {
+            wx.navigateTo({
+              url: '/pages/campusDistribution/campusDistribution',
+            })
+          } else if (res.cancel) {
+            console.log('用户点击取消')
+          }
+        }
+      })
+    },
+    //请求校区分布列表
+    getCampusDistribution() {
+      let that = this;
+      wx.getStorage({ 
+        key: 'openId',
+        success: (res) => {
+          util.doPost(
+            'orgSchool', {
+              appId: app.globalData.appId,
+              openId: res.data,
+              page: 0,
+              size: 10
+            }
+          ).then(rs => {
+            if (rs.success > 0) {
+            const id = wx.getStorageSync('campusInfo').id
+            let list = {}
+           for(var i = 0 ; i < rs.data.list.length; i++){
+            if(rs.data.list[i].id == id){
+                list = rs.data.list[i]
+                rs.data.list.splice(i,1)
+                break;
+            }
+           }
+            rs.data.list.unshift(list)
+            rs.data.list[0].userId = wx.getStorageSync('openId')
+              that.setData({
+                campusInfo: rs.data.list[0],
+              })
+            } else {
+              console.log(rs.errMsg)
+            }
+          })
+        }
+      })
+    },
+
+    hideBg:function(){
+      if(this.data.bgShow){
+        var animation = wx.createAnimation({
+          duration:200,
+          timingFunction:'linear'
+        }).translateY(0).step()
+         this.setData({
+           bgShow: false,
+         })
+         setTimeout(() => {
+          this.setData({
+            animationDataShare:animation.export(),
+           })
+         }, 100);
+       }else{
+        var animation = wx.createAnimation({
+          duration:200,
+          timingFunction:'linear'
+        }).translateY(331).step()
+        this.setData({
+          animationDataShare:animation.export(),
+         })
+         setTimeout(() => {
+          this.setData({
+            bgShow:true
+          })
+         }, 200);
+       }
+    },
+  
+    showSaveImg:function(){
+      if(!this.data.activeShow){
+        this.hideBg()
+        if(this.data.shareImg == ''){
+          this.setData({
+            shareImg: wx.getStorageSync('shareImg')
+          })
+        }
+        if(this.data.showText == ''){
+          this.setData({
+            'posterConfig.texts[0].text': '我在' + app.globalData.orgTitle,
+          })
+        } else { 
+          this.setData({
+            'posterConfig.texts[0].text': '我在' + app.globalData.orgTitle + '参加了',
+          })
+        }
+        this.setData({
+          
+          'posterConfig.texts[1].text': this.data.titleText,
+          'posterConfig.images[0].url': this.data.shareImg,
+          // 'posterConfig.images[1].url': this.data.object.codeImg,
+        })
+
+        const curPage = getCurrentPages()[getCurrentPages().length - 1].route;
+        if(curPage == 'pages/wcsp/wcsp' || curPage == 'pages/routine/routine'){
+          this.getCode(this.data.isId,curPage,this.data.typeId)
+        } else{
+          this.getCode('','','')
+        }
+        wx.showLoading({
+          title: '正在生成海报',
+          mask: true
+        })
+       
+      } else{
+       
+        var animation = wx.createAnimation({
+          duration:200,
+          timingFunction:'linear'
+        }).translateY(331).step()
+        this.setData({
+          animationDataShare:animation.export(),
+         })
+         setTimeout(() => {
+          this.setData({
+            bgShow:true
+          })
+         }, 200);
+      }
+      this.triggerEvent('callMethod')
+    }, 
+  
+    closeSaveImage() {
+      this.setData({
+        showSaveImage: false
+      })
+      this.triggerEvent('callMethod')
+    },
+
+    parentMethod:function(){
+      this.triggerEvent("callMethod")
+    },
+
+     //生成图片并保存
+  onPosterSuccess(e) {
+    let that = this;
+    let {
+      detail
+    } = e;
+    wx.saveImageToPhotosAlbum({
+      filePath: detail,
+      success(res) {
+        wx.showToast({
+          title: '图片已保存到本地相册',
+          icon:'none'
+        })
+        that.setData({
+          showSaveImage: false
+        })
+        that.triggerEvent("callMethod")
+      },fail(res){
+        that.getSetting()
+      }
+    })
+  },
+
+  getSetting:function(){
+    // 相册授权
+    wx.getSetting({
+     success(res) {
+       // 进行授权检测,未授权则进行弹层授权
+       if (!res.authSetting["scope.writePhotosAlbum"]) {
+           wx.showModal({
+             title: '提示',
+             content: '您未授权相册使用权限,是否重新授权?',
+             success:function(res){
+               if(res.confirm){
+                 wx.openSetting({
+                   success(settingdata) {
+                     if (settingdata.authSetting["scope.writePhotosAlbum"]) {
+                       console.log("获取权限成功,再次点击图片保存到相册")
+                     } else {
+                       console.log("获取权限失败")
+                     }
+                   },fail(res){
+                     console.log(res)
+                   }
+                 })
+               }
+             }
+           })
+         } 
+       },
+       fail(res) {
+         console.log(res);
+       }
+     });
+  },
+
+  changeImg:function(shareImg,showText,titleText){
+    this.setData({
+      shareImg:shareImg,
+      showText:showText,
+      titleText:titleText
+    })
+  },
+
+  getCode:function(id,curPage,typeId){
+    if(typeId != ''){
+      var isParam ={specialId: id,typeId:typeId}
+    }else{
+      var isParam ={id: id}
+    }
+    const codeParams={
+      appId: app.globalData.appId,
+      page: curPage,
+      param: JSON.stringify(isParam)
+    }
+    if(id == ""){
+      delete codeParams.param
+    }
+    if(curPage == ""){
+      delete codeParams.page
+    }
+     util.doPost(
+       'getQrcode',codeParams
+     ).then( res => {
+      wx.hideLoading({
+        success: (res) => {},
+      })
+       if(res != null){
+         let images = res
+         let timestamp = Date.parse(new Date());  
+             timestamp = timestamp / 1000;  
+         base64Util.base64src(images, timestamp,  res => {
+           this.setData({
+            //  'posterConfig.images[0].url': this.data.imgArr[0],
+             'posterConfig.images[1].url': res,
+             base64Img: res
+           })
+         });
+         this.setData({
+          showSaveImage:true,
+        })
+       } else {
+         wx.showToast({
+           title: '海报生成失败',
+         })
+       }
+     })
+   },
+
+  onShareAppMessage:function(){
+    
+  },
+},
+
+  
+
+})

+ 6 - 0
pages/Components/reservation/reservation.json

@@ -0,0 +1,6 @@
+{
+  "component": true,
+  "usingComponents": {
+    "poster": "/pages/Components/miniprogram_dist/poster/index"
+  }
+}

+ 70 - 0
pages/Components/reservation/reservation.wxml

@@ -0,0 +1,70 @@
+<!--pages/Components/reservation/reservation.wxml-->
+<view class="main {{bottomFlag == true?'bottomStyle':''}}">
+	<view class="main-item" catchtap="backIndexPage">
+		<image lazy-load class="mi-icon" mode="aspectFill" src="{{imageUrl ? imageUrl+'home0615.png' : ''}}"></image>
+		<text>主页</text>
+	</view>
+	<view class="main-item" catchtap="advisory">
+		<image lazy-load class="mi-icon" mode="aspectFill" src="{{imageUrl ? imageUrl+'phone0615.png' : ''}}"></image>
+		<text>咨询</text>
+	</view>
+	<view class="main-item" bindtap="hideBg">
+		<image lazy-load class="mi-icon" mode="aspectFill" src="{{imageUrl ? imageUrl+'share0615.png' : ''}}"></image>
+		<text>分享</text>
+	</view>
+	<button class="listen" disabled="{{true}}" hidden="{{!isBuy}}">{{isBuyText}}</button>
+	<button class="listen {{disabled?'disabled':''}}" disabled="{{disabled}}" hidden="{{isBuy}}" catchtap="jumpPage"
+		data-url="{{buttonURL}}">{{buttonText}}</button>
+
+	<view class="bg" hidden="{{bgShow}}" bindtap="hideBg"></view>
+	<view class="btn-view" hidden="{{bgShow}}" animation="{{animationDataShare}}">
+		<view class="share-view">
+			<button open-type="share">
+				<image lazy-load src="{{wechatImg}}" />
+				<view>发送给朋友</view>
+			</button>
+			<button bindtap="showSaveImg">
+				<image lazy-load src="{{pyqImg}}"></image>
+				<view>生成海报</view>
+			</button>
+		</view>
+		<view class="button-line"></view>
+		<button bindtap="hideBg">取消</button>
+	</view>
+
+	<cover-view class="showModel" hidden="{{!showSaveImage}}">
+		<cover-view class="show-top">
+			<cover-image catchtap="closeSaveImage" class="show-close" mode="aspectFill"
+				src="{{codeImg ? codeImg+'close0604.png':''}}" />
+		</cover-view>
+
+		<cover-view class="show-box">
+			<!-- <view class="sb-top">
+					<image class="sb-top-avatar" mode="aspectFill" src="{{codeImg ? codeImg+'202020602-background.png':''}}"></image>
+					<open-data class="avatar" type="userAvatarUrl"></open-data>
+					<view class="sb-right">
+						<view class="sb-right-name">
+							<open-data type="userNickName"></open-data>
+						</view>
+						<view>在艾克思朗参加了</view>
+					</view>
+				</view> -->
+			<cover-view class="show-bottom">
+				<cover-image class="sb-image" mode="aspectFit" src="{{posterConfig.images[0].url}}"></cover-image>
+				<cover-view class="sb-mix_title">{{posterConfig.texts[0].text}}</cover-view>
+				<cover-view class="sb-title">{{posterConfig.texts[1].text}}</cover-view>
+				<cover-view class="sb-QRcode">
+					<cover-image class="QRcode-image" mode="aspectFill" src="{{posterConfig.images[1].url}}"></cover-image>
+					<cover-view class="QR-title">{{posterConfig.texts[2].text}}{{posterConfig.texts[3].text}}</cover-view>
+				</cover-view>
+			</cover-view>
+		</cover-view>
+	</cover-view>
+	<view class="isPosterBg" hidden="{{!showSaveImage}}"></view>
+	<view class="isPoster" hidden="{{!showSaveImage}}">
+		<poster hidden="{{!showSaveImage}}" id="poster" config="{{posterConfig}}" bind:success="onPosterSuccess">
+			<view class="save-image">保存图片</view>
+		</poster>
+	</view>
+
+</view>

+ 298 - 0
pages/Components/reservation/reservation.wxss

@@ -0,0 +1,298 @@
+/* pages/Components/reservation/reservation.wxss */
+.button-init {
+  width:0;
+  margin: 0;
+  padding: 0;
+  font-size: initial;
+  color: initial;
+  text-align: initial;
+  line-height: initial;
+  border-radius: initial;
+  background-color: initial;
+  width: initial;
+}
+
+.button-init::after {
+  width: initial;
+  border-radius: initial;
+  border: initial;
+}
+.main {
+  position: fixed;
+  left: 0;
+  bottom: 0;
+  width: 100%;
+  height: 98rpx;
+  display: flex;
+  align-items: center;
+  background-color: #fff;
+}
+
+.mi-icon {
+  width: 48rpx;
+  height: 48rpx;
+}
+
+.main-item {
+  margin-left: 48rpx;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  font-size: 20rpx;
+  color: #999;
+  width: auto !important;
+}
+/* .button-init {
+  width: auto !important;
+  height: auto !important;
+  margin: 0 !important;
+  margin-left: 48rpx !important;
+  padding: 0;
+  background-color: #fff;
+} */
+
+.listen {
+  margin-right: 30rpx;
+  margin-left: 48rpx;
+  width: 366rpx;
+  height: 64rpx;
+  /* line-height: 64rpx; */
+  text-align: center;
+  /* background: linear-gradient(90deg, rgba(236, 58, 78, 1) 0%, rgba(255, 115, 115, 1) 100%); */
+  background: linear-gradient(90deg, #005033 0%, #11774e 100%);
+  color: #FFF;
+  /* box-shadow: 0rpx 0rpx 12rpx rgba(236, 58, 78, 0.6); */
+  box-shadow: 0rpx 0rpx 12rpx #005033;
+  border-radius: 40rpx;
+  font-size: 28rpx;
+  color: #fff;
+  font-weight: 400;
+}
+
+wx-button[disabled]:not([type]){
+  color: #FFF;
+  background: #c5c5c5;
+  box-shadow: 0rpx 0rpx 12rpx #c5c5c5;
+}
+
+.bottomStyle{
+  padding-bottom: 40rpx;
+}
+
+.bg,.btn-view{
+  position: fixed;
+}
+.bg{
+  background: #000;
+  opacity: 0.4;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 99;
+}
+.btn-view{
+  bottom: 0;
+  width: 100%;
+  z-index: 100;
+}
+.btn-view button{
+  border: none !important;
+  border-radius: 0;
+height: 104rpx;
+line-height: 104rpx;
+width: 750rpx !important;
+font-weight: 400;
+font-size: 32rpx;
+border-bottom: 1px solid #EEE;
+padding: 0;
+
+}
+.button-line{
+  height: 20rpx;
+  background: #EEE;
+  width: 100%;
+}
+
+.showModel {
+  position: fixed;
+  top: 85rpx;
+  left: 0;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  height: 60%;
+  z-index: 999;
+}
+
+.show-close {
+  float: right;
+  width: 48rpx;
+  height: 48rpx;
+}
+
+.show-top {
+  width: 590rpx;
+  margin-bottom: 12rpx;
+}
+
+.show-box {
+  width: 590rpx;
+  height: 660rpx;
+  box-sizing: border-box;
+  background-color: #fff;
+  border-radius: 10rpx;
+  padding: 30rpx 24rpx;
+  position: relative;
+  z-index: 999;
+}
+
+.sb-top-avatar {
+  margin-right: 12rpx;
+  width: 64rpx;
+  height: 64rpx;
+  border-radius: 50%;
+}
+.avatar{
+  margin-right: 12rpx;
+  width: 64rpx;
+  height: 64rpx;
+  border-radius: 50%;
+}
+.avatar image{
+  border-radius: 50%;
+}
+.sb-top {
+  display: flex;
+  font-size: 22rpx;
+  color: #C5C5C5;
+  padding-bottom: 30rpx;
+}
+
+.sb-right-name {
+  font-size: 26rpx;
+  font-weight: 700;
+  color: rgba(51, 51, 51, 1);
+}
+
+.sb-image {
+  width: 542rpx;
+  height: 406rpx;
+}
+
+.QRcode-image {
+  width: 112rpx;
+  height: 112rpx;
+  margin-left: 16rpx;
+}
+
+.sb-mix_title {
+  margin-top: 22rpx;
+  font-size: 24rpx;
+  color: rgba(51, 51, 51, 1);
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.sb-title {
+  padding-bottom: 15rpx;
+  font-size: 28rpx;
+  font-weight: 700;
+  color: rgba(51, 51, 51, 1);
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.sb-QRcode {
+  display: flex;
+  flex-direction: row-reverse;
+  align-items: center;
+
+}
+
+.QR-title {
+  width: 110rpx;
+  height: auto;
+  font-size: 20rpx;
+  color: rgba(153, 153, 153, 1);
+  line-height: 34rpx;
+  white-space: initial;
+}
+
+
+.save-image {
+  font-weight: 600;
+  /* margin-top: 48rpx; */
+  width: 224rpx;
+  height: 64rpx;
+  line-height: 64rpx;
+  text-align: center;
+  border-radius: 40rpx;
+  font-size: 28rpx;
+  color: rgba(255, 255, 255, 1);
+  background: linear-gradient(90deg, rgba(236, 58, 78, 1) 0%, rgba(255, 115, 115, 1) 100%);
+}
+
+.bottom-author{
+  position: fixed;
+  bottom: 0;
+  height: 100rpx;
+  z-index: 999;
+  background: #000;
+  color: #FFF;
+  right: 10rpx;
+  width: 50% !important;
+  opacity: 0;
+}
+
+.share-view{
+  display: flex;
+}
+.share-view>view{
+  width: 50% !important;
+  background: #FFF;
+}
+.share-view>button:first-child{
+  width: 49%;
+  border-right: 1px solid #EEE !important;
+}
+.share-view button{
+  height: 210rpx;
+  line-height: 80rpx;
+  text-align: center;
+  width: 100% !important;
+  padding-top: 24rpx;
+  font-size: 28rpx;
+  border-radius: 0 !important;
+}
+.share-view button view{
+  height: 80rpx;
+  line-height: 80rpx;
+  position: relative;
+  bottom: 20rpx;
+
+}
+.share-view image{
+  width: 80rpx;
+  height: 80rpx;
+  position: relative;
+  top: 20rpx;
+}
+.isPoster{
+  position: fixed;
+  z-index: 999;
+  bottom: 290rpx;
+  left: 50%;
+  margin-left: -112rpx;
+}
+.isPosterBg{
+  position: fixed;
+  background-color: rgba(0, 0, 0, 0.5);
+  width: 100%;
+  height: 100%;
+  top: 0;
+  z-index: 998;
+}