小程序分享朋友圈峭竣、好友、圖片分享

小程序分享的三種方式

小程序分享基本就三種:分享好友晃虫、小程序碼圖片分享以及朋友圈分享皆撩,日常開發(fā)比較常見的是分享好友;

由于第一次做小程序分享哲银,網(wǎng)上又大多只有好友分享扛吞,或者只有零星的分享攻略,所以踩了n多坑后荆责,自己整理一下鞏固的同時(shí)能希望幫到其他人吧滥比,畢竟百度上暫時(shí)還找不到這么全的攻略。
希望能幫助到大家

分享好友

1做院、喚起分享好友有兩種方式盲泛,頁面右上角...和屬性openType="share"的Button組件濒持。
2、兩種喚起分享的方式都會(huì)觸發(fā)頁面的onShareAppMessage的方法寺滚,方法返回的參數(shù)中from字段返回表示分享的途徑:按鈕button或者非按鈕(右上角分享)柑营。

這里有點(diǎn)小技巧,如果通過按鈕分享并且按鈕是封裝在子組件中村视,可以通過button的id屬性傳遞一些數(shù)據(jù)給頁面

1官套、按鈕分享

<!-- 通過id可以傳遞參數(shù) -->
<Button
   className="flex ali-item-center jus-content-center share"
   openType="share"
   id={props.shareInfo.shareParam || 'share'}
>
  <Text className="iconfont icon-wechat" />
</Button>

2、參數(shù)獲取

// 參數(shù)獲取
 onShareAppMessage(share) {
    console.error('from', share);
    let shareObj = {},
      target;
    if (share.from === 'button') {
      target = share.target.id; // 這個(gè)id獲取到的就是上面button的id屬性值蚁孔,也就是 props.shareInfo.shareParam || 'share'
    } else {
      target = `classId=${this.state.classId}&dynamicId=${this.state.dynamicId}`;
    }
    shareObj = {
      title: default_share_Title,// 分享標(biāo)題
      // desc: '分享描述',
      path: `/分享地址?${target}`,
      imageUrl: default_share_circle, // 分享封面圖
    };
    shareObj = {
      ...shareObj,
      success: (res) => {
        console.error('分享成功', res);
      },
      fail: (error) => {
        console.error('分享失敗', error);
      },
    };
    console.error('shareObj', shareObj);
    return shareObj;
  }

3奶赔、注意??

需要注意的是,小程序首頁底部欄的幾個(gè)tab頁面公用的是同一個(gè)頁面也就是index頁面杠氢,但我們通常是一個(gè)tab對(duì)應(yīng)一個(gè)路由頁面纺阔,所以底部欄所有的tab頁面對(duì)應(yīng)按鈕分享和右上角分享,觸發(fā)的都是index頁面的onShareAppMessage修然。

小程序碼分享

主要是先通過調(diào)用后端接口獲取小程序碼笛钝,然后用canvas繪圖,保存繪制的圖片最后分享圖片愕宋。

1玻靡、獲取小程序碼

  • 后端調(diào)用小程序的api后返回文檔流或者base64數(shù)據(jù)流,如果是返回文檔流中贝,在請(qǐng)求接口的時(shí)候需要把responseType設(shè)置為arraybuffer
let option = {
        isShowLoading: false,
        loadingText: '正在加載',
        url: isBaseUrl ? base + requestUrl : requestUrl,
        data: data,
        method: method,
        responseType: responseType || 'text', // 默認(rèn)是text囤捻,如果請(qǐng)求文檔流,設(shè)置為arraybuffer
        header: {
          'Content-Type': contentType,
          'Access-Control-Allow-Origin': '*',
          token: txtInfo.unionId
            ? txtInfo.unionId + '@@@' + Taro.getStorageSync('accountId')
            : '@@@',
        },

2邻寿、然后解析:如果是文檔流蝎土,需要調(diào)用wx的api轉(zhuǎn)base64

  /** 獲取小程序碼 */
  getMiniCode({scene, pagePath}) {
    return new Promise((resolve, reject) => {
      wx.showLoading({
        title: '生成圖片中...',
      });
      const accountId = Taro.getStorageSync('accountId');
      $Request
        .getMiniCodeUnlimit({
          accountId,
          scene,
          page: pagePath,
        })
        .then((res) => {
          // 獲取小程序碼(圖片流),轉(zhuǎn)base64 ==> const qrcode = wx.arrayBufferToBase64(res);
          if (res.data && res.success) {
            const base64 = 'data:image/jpg;base64,' + res.data;
            resolve(base64);
          } else {
            setTimeout(() => {
              WxActions.fnShowToast(res.errorMsg);
            }, 300);
          }
          setTimeout(() => {
            wx.hideLoading();
          }, 300);
        })
        .catch((err) => {
          console.log('請(qǐng)求失敗', err);
          setTimeout(() => {
            wx.hideLoading();
            WxActions.fnShowToast('獲取小程序碼失敗');
          }, 300);
          reject(err);
        });
    });
  },

3绣否、獲取到對(duì)應(yīng)到base64碼后誊涯,繪制canvas,當(dāng)然繪制之前還有很多信息要處理:

const {classId, dynamic} = this.props;
    WxActions.getMiniCode({
      scene: `dynamicId=${dynamic.id}&classId=${classId}&v=1`,
      pagePath: 'pages/schoolCircleDetail/schoolCircleDetail',
    }).then((base64) => {
      wx.showLoading({
        title: '生成圖片中...',
      });
      const canvas: any = WxActions.getShareCanvas(
        {
          shareFrom: this.state.shareFrom,
          shareCode: base64,
          shareTitle: '你的好友邀請(qǐng)你一起參與',
          shareCover: this.state.coverImg,
        },
        'shareCanvas',
        this.$scope,
      );
      canvas
        .then((canvasSrc) => {
          setTimeout(() => {
            wx.hideLoading();
          }, 300);
          this.setState({
            isShowModal: true,
            canvasSrc: canvasSrc,
          });
        })
        .catch(() => {
          setTimeout(() => {
            wx.hideLoading();
          }, 300);
        });
    });

其中生成canvas圖片邏輯如下:
(獲取圖片信息蒜撮,由于后來后端同事?lián)Q成二進(jìn)制編碼返回暴构,所以要處理)

const fsm = wx.getFileSystemManager();
const FILE_BASE_NAME = 'tmp_base64src';

const base64src = function(base64data) {
  return new Promise((resolve, reject) => {
    const [format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64data) || [];
    if (!format) {
      reject(new Error('ERROR_BASE64SRC_PARSE'));
    }
    const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}`;
    const buffer = wx.base64ToArrayBuffer(bodyData);
    fsm.writeFile({
      filePath,
      data: buffer,
      encoding: 'binary',
      success() {
        resolve(filePath);
      },
      fail() {
        reject(new Error('ERROR_BASE64SRC_WRITE'));
      },
    });
  });
};

// 。段磨。取逾。。苹支。砾隅。。

  /** 分享canvas */
  initTime: 1, // 獲取圖片信息可能會(huì)失敗债蜜,所以失敗后可以再次獲取晴埂,最多獲取canvasObj.maxTime或3次
  getShareCanvas(canvasObj, canvasId, otx) {
    WxActions.initTime = 1; // 每次點(diǎn)擊分享究反,重置當(dāng)前次數(shù)為默認(rèn)值1.
    return new Promise((resolve, reject) => {
      WxActions.getCanvasInfo(canvasObj, canvasId, otx)
        .then((res) => {
          resolve(res);
        })
        .catch((err) => {
          reject(err);
        });
    });
  },

  /** 獲取小程序碼的imageinfo */
  async getCanvasInfo(canvasObj, canvasId, otx) {
    return new Promise((resolve, reject) => {
      let drawWidth;
      // 
      wx.getSystemInfo({
        success: async (sys) => {
          console.error('getSystemInfo', sys);
          const rapito = 0.71;
          const startX = 2,
            startY = 80;
          drawWidth = (await sys.screenWidth) * rapito;
          let drawHeight = (drawWidth * 4) / 5;
          console.error('drawWidth', drawWidth, drawHeight);
          drawHeight = drawHeight > 150 ? 150 : drawHeight;
          const src = await base64src(canvasObj.shareCode);
          wx.getImageInfo({
            src,
            success: (codeInfo) => {
              // console.error('1111', codeInfo);
              wx.getImageInfo({
                src: canvasObj.shareCover,
                success: (res) => {
                  console.error('圖片信息', res);
                  let cutWidth = res.width,
                    cutHeight = (res.width * 4) / 5;
                  cutHeight = cutHeight > res.height ? res.height : cutHeight;
                  console.error('圖片信息===', res.width, cutHeight);
                  WxActions.initTime = 1;
                  // console.error('獲取封面圖成功', res);
                  //res.path是網(wǎng)絡(luò)圖片的本地地址
                  const canvasCtx = wx.createCanvasContext(canvasId, otx);
                  // console.error('canvasCtx', canvasCtx);
                  
                  // canvas的繪制看自己情況定制
                  //繪制背景 ...
                  canvasCtx.fillStyle = '#fff';
                  canvasCtx.fillRect(0, 0, sys.screenWidth, sys.screenWidth);
                  //繪制分享的標(biāo)題文字
                  canvasCtx.setFontSize(17);
                  canvasCtx.setFillStyle('#333');
                  canvasCtx.fillText(canvasObj.shareTitle, 15, 35);
                  //繪制分享的第二行標(biāo)題文字
                  canvasCtx.setFontSize(13);
                  canvasCtx.setFillStyle('#999');
                  canvasCtx.fillText(`來自:${canvasObj.shareFrom}`, 15, 60);
                  //繪制圖片
                  // drawImage(imageResource, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
                  // (圖片地址, 繪制圖片在畫布的起始x,  繪制圖片在畫布的起始y, 截取圖的寬度(原), 截取圖的高度(原), 圖片放置位置x, 圖片放置位置y, 在canva上繪制的長(zhǎng)度,在canvas上繪制的高度)
                  canvasCtx.drawImage(
                    res.path,
                    startX,
                    startY,
                    cutWidth,
                    cutHeight, //res.height,
                    startX,
                    startY,
                    drawWidth,
                    drawHeight,
                  );
                  //繪制小程序碼
                  // canvasCtx.drawImage(canvasObj.shareCode, 15, 250, 60, 60);
                  canvasCtx.drawImage(codeInfo.path, 15, drawHeight + 90, 60, 60);
                  //繪制分享的說明
                  canvasCtx.setFontSize(13);
                  canvasCtx.setFillStyle('#333');
                  canvasCtx.fillText('長(zhǎng)按小程序碼看詳情', 85, drawHeight + 130);
                  canvasCtx.stroke();
                  canvasCtx.draw(false, () => {
                    wx.canvasToTempFilePath(
                      {
                        canvasId: canvasId,
                        success: (ctx) => {
                          // console.error('save的canvas圖片', ctx);
                          // 獲得圖片臨時(shí)路徑,用來保存到本地
                          return resolve(ctx.tempFilePath);
                        },
                        fail: (err) => {
                          //失敗回調(diào)
                          console.error('save的canvas圖片失敗', err);
                          WxActions.fnShowToast('獲取小程序碼失敗');
                          return reject();
                        },
                      },
                      otx, // 必須要有當(dāng)前文檔的實(shí)例
                    );
                  });
                },
                fail: (res) => {
                  //失敗回調(diào)
                  console.error('獲取封面圖失敗', res);
                  if (WxActions.initTime < 3) {
                    WxActions.initTime++;
                    // 獲取失敗后再次調(diào)用自身邑时,重新獲取奴紧,最多次數(shù)為canvasObj.maxTime或3次
                    WxActions.getCanvasInfo(canvasObj, canvasId, otx);
                  } else {
                    setTimeout(() => {
                      WxActions.fnShowToast('獲取封面圖失敗');
                    }, 350);
                  }
                  return reject();
                },
              });
            },
            fail: (res) => {
              //失敗回調(diào)
              console.error('2222', res);
            },
          });
        },
        fail: (err) => {
          return reject(err);
        },
      });
    });
  },


4、最后保存圖片

 WxActions.fnWxSetting('scope.writePhotosAlbum').then((/** 授權(quán) */) => {
      this.setState({
        canvasSrc: '',
        isShowShare: false,
      });
      WxActions.fnSaveImageToAlbum(this.state.canvasSrc).then(() => {
        this.onCancelModal();
      });
    });

// 晶丘。黍氮。。浅浮。沫浆。。滚秩。专执。


  /** 保存圖片到本地相冊(cè) */
  fnSaveImageToAlbum(filePath) {
    return new Promise((resolve, reject) => {
      wx.saveImageToPhotosAlbum({
        filePath,
        success(yes) {
          console.log(yes.errMsg);
          WxActions.fnShowToast('保存圖片成功');
          return resolve();
        },
        fail(error) {
          console.log(error.errMsg);
          WxActions.fnShowToast('保存圖片失敗');
          return reject();
        },
      });
    });
  },

到此,基本完成小程序碼生成canvas并保存圖片到手機(jī)相冊(cè)到需求郁油,由于時(shí)間比較緊本股,很多細(xì)節(jié)沒處理好。

5桐腌、掃碼進(jìn)入的參數(shù)獲取

接下來就是大坑了
在正常的小程序里面拄显,掃碼進(jìn)入后獲取參數(shù)是這樣的

onLoad:function(options){
  if(options.scene){
    let scene=decodeURIComponent(options.scene);
    //&是我們定義的參數(shù)鏈接方式
    let userId=scene.split("&")[0];
    let recommendId=scene.split('&')[1];
    //其他邏輯處理。案站。躬审。。蟆盐。
  }
}

但由于本項(xiàng)目用的是taro承边,也就是用react編寫,由于查找了網(wǎng)上的攻略石挂,于是先入為主的一直想要獲取scene參數(shù)博助,找到一片文章說在componentWillMount生命周期里獲取

 componentWillMount(ops: any) {
    console.error('ops', ops);
    if (ops && ops.scene) {
      let shareOps = WxActions.getMiniCodeScene(ops.scene);
      this.setState({
        isScene: true,
        shareScene: shareOps,
      });
    }
  }

結(jié)果發(fā)現(xiàn)這是不對(duì)的!不對(duì)的誊稚!不對(duì)的O枋肌!里伯!必須要在componentdidmount里面獲取,并且要通過this.$router.params.scene獲取才是正常的渤闷,所以如果正常的頁面和分享后掃碼進(jìn)入的是同一個(gè)頁面疾瓮,就要區(qū)分參數(shù)的獲取了。

componentDidMount() {
    if (this.$router.params.scene) {
      // 掃碼進(jìn)入
  }else{
    // 正常小程序頁面進(jìn)入
  }
}

朋友圈分享

分享朋友圈飒箭,微信暫時(shí)沒有提供可以直接的分享方式狼电,都是通過客服會(huì)話返回h5鏈接實(shí)現(xiàn)的蜒灰,相當(dāng)于曲線救國(guó),下面是相關(guān)邏輯肩碟。

1强窖、html代碼,喚起客服會(huì)話

ps:h5地址域名必須是https的

<Button
  sendMessageTitle={shareInfo.shareTitle ? shareInfo.shareTitle : '分享朋友圈'} // 分享的客服會(huì)話標(biāo)題
  sendMessageImg={shareInfo.shareImg ? shareInfo.shareImg : default_share_circle} // 分享的客服會(huì)話的封面圖
  sendMessagePath={shareInfo.sharePath || default_share_CircleUrl} // 對(duì)應(yīng)的需要分享到朋友圈的h5鏈接
  sessionFrom={'wkbbapp'} // 暫時(shí)發(fā)現(xiàn)沒啥用
  openType="contact" // 必填削祈,表示喚起客服會(huì)話
  showMessageCard // 必填翅溺,喚起會(huì)話右下角的截圖彈出
  plain
  className="flex ali-item-center jus-content-center share"
  style={{border: 'none'}}
  onContact={(res) => {
    console.error('onContact', res);
  }}
  >
  <Text className="iconfont icon-quan" />
</Button>

2、后端推送會(huì)話卡片

前端只需要上面的button對(duì)應(yīng)的代碼髓抑,后端會(huì)獲取到wx對(duì)應(yīng)的推送咙崎,然后根據(jù)推送返回的內(nèi)容,再由后端推送卡片消息到會(huì)話窗口吨拍,用戶只要點(diǎn)擊對(duì)應(yīng)的窗口褪猛,就能進(jìn)入對(duì)應(yīng)的鏈接地址(其實(shí)就是一個(gè)h5地址,點(diǎn)擊后會(huì)進(jìn)入微信瀏覽器)羹饰,然后點(diǎn)擊右上角伊滋,分享朋友圈。

3队秩、H5頁面分享處理

顯然笑旺,這已經(jīng)是另外一個(gè)項(xiàng)目了。
這個(gè)項(xiàng)目要做的刹碾,就是平時(shí)公眾號(hào)要做的事情了燥撞。

  • 首先是在html頁面引入微信sdk
<script type="text/javascript" src="https://res2.wx.qq.com/open/js/jweixin-1.6.0.js"></script>

  • 然后是注冊(cè)(封裝)
//微信分享
export function wxShare(_option: {
  title: string; // 分享標(biāo)題
  desc: string; // 分享描述
  link: string; // 分享鏈接
  imgUrl: string; // 分享圖標(biāo)
  success?: any;
  cancel?: any;
}) {
  configWxApi()
    .then((res: any) => {
      console.log('_option', _option);
      console.log(res);
      wx.config(res.data);
      wx.ready(function() {
        //分享給朋友
        wx.onMenuShareAppMessage(_option);
        // wx.updateAppMessageShareData(_option); //(1.4.0)
        //分享到朋友圈
        wx.onMenuShareTimeline(_option);
        // wx.updateTimelineShareData(_option); //(1.4.0)
      });
      wx.error((error: any) => {
        console.error(error);
        Toast.info(`${error.errMsg}`, 3);
        // config信息驗(yàn)證失敗會(huì)執(zhí)行error函數(shù),如簽名過期導(dǎo)致驗(yàn)證失敗迷帜,具體錯(cuò)誤信息可以打開config的debug模式查看物舒,也可以在返回的res參數(shù)中查看,對(duì)于SPA可以在這里更新簽名戏锹。
        // alert("接口驗(yàn)證失敗冠胯,詳細(xì)信息:\n" + JSON.stringify(error));
      });
      //  提示服務(wù)器異常暫時(shí)取反
    })
    .catch((err: any) => {
      console.log(err);
    });
}

  • 頁面分享:
async componentDidMount() {
  wxShare({
    title: this.props.noticeDetail.title || default_circle_title, // 分享標(biāo)題
    desc: default_share_desc, // 分享描述
    link: window.location.href, // 分享鏈接
    imgUrl: this.props.noticeDetail.coverUrl || default_share_notice, // 分享圖標(biāo)
  });
}

ps:注冊(cè)微信分享失敗的問題基本是簽名錯(cuò)誤獲取域名不在合法域名列表,在此不再多描述了锦针。

總結(jié)

開始公司沒同事做過相關(guān)業(yè)務(wù)荠察,網(wǎng)上資料也不全,前后端都摸著石頭過河奈搜,走了很多彎路悉盆,所以把這整套流程走通很不容易,
也正因如此馋吗,完成后得到的成就感也是最大的焕盟。
最后,本文是原創(chuàng)宏粤,希望對(duì)你有所幫助~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末脚翘,一起剝皮案震驚了整個(gè)濱河市灼卢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌来农,老刑警劉巖鞋真,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異沃于,居然都是意外死亡涩咖,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門揽涮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來抠藕,“玉大人,你說我怎么就攤上這事蒋困《芩疲” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵雪标,是天一觀的道長(zhǎng)零院。 經(jīng)常有香客問我,道長(zhǎng)村刨,這世上最難降的妖魔是什么告抄? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮嵌牺,結(jié)果婚禮上打洼,老公的妹妹穿的比我還像新娘。我一直安慰自己逆粹,他們只是感情好募疮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著僻弹,像睡著了一般阿浓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蹋绽,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天芭毙,我揣著相機(jī)與錄音,去河邊找鬼卸耘。 笑死退敦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蚣抗。 我是一名探鬼主播苛聘,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼忠聚!你這毒婦竟也來了设哗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤两蟀,失蹤者是張志新(化名)和其女友劉穎网梢,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赂毯,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡战虏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了党涕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片烦感。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖膛堤,靈堂內(nèi)的尸體忽然破棺而出手趣,到底是詐尸還是另有隱情,我是刑警寧澤肥荔,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布绿渣,位于F島的核電站,受9級(jí)特大地震影響燕耿,放射性物質(zhì)發(fā)生泄漏中符。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一誉帅、第九天 我趴在偏房一處隱蔽的房頂上張望淀散。 院中可真熱鬧,春花似錦蚜锨、人聲如沸档插。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽阀捅。三九已至,卻和暖如春针余,著一層夾襖步出監(jiān)牢的瞬間饲鄙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工圆雁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留忍级,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓伪朽,卻偏偏與公主長(zhǎng)得像轴咱,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354