大數據

打造小程序版本公號和自託管的公號(2):利用mini-blog將你的blog做到微信

本文關鍵字:合併多個cloudfuncions為一個

在《打造小程序版本公號和自託管的公號(1)》中,我們談到了建立blog小程序的一些理論基礎和必要條件,現在,我們選擇一個這類小程序的源碼,來實踐一下:

我們選擇的是https://github.com/CavinCao/mini-blog/commit/7921a126122f4a980e1270475aeb22bb2d50c3d0,積分功能v2版本後面的一個修復版,為什麼選mini blog,因為它小。該有的都有,不該有的也沒有。很容易看清這類實踐的基本套路和這類程序的技術手法,下載源碼後打開微信開發IDE,掃碼IDE左上角小程序(開發社區號)綁定微信,,用IDE導入正確路徑下源碼,appid填你註冊過的小程序appid,因為miniblog使用的騰訊雲cloudbase託管的雲函數後端(當然miniblog還用了cb的數據庫),在點擊雲開發按鈕新建第一個數據庫或雲函數之前,它會自動幫你註冊或綁定已有的一個騰訊雲帳號,為了達到在已有帳號裡操作的效果,請保證預先處理你綁定IDE用的微信,它背後的某個騰訊雲號已有綁定該小程序作為登錄方式之一,這樣新建雲函或數據庫會自動在你已有的騰訊雲的cloudbase下進行,如果你使用了自動生成的騰訊雲號,那麼會得到一個新帳號已綁有小程序登錄但未綁定微信,需要二次登錄(先微信後小程序)才能進入帳號,解決方法是在那個新帳號裡綁定一次微信。

IDE打開,我們發現源碼有cloudfunctions雲函和miniprogram小程序,點雲開發,新建一個clodubase環境包月免費自動續費,登錄web版會發現用IDE建的是隻讀的而且與網頁端申請的那個免費可以共存,。接下來就是miniblog的安裝:有12個庫(access_token,mini_posts,mini_comments,mini_posts_related,mini_config,mini_logs,mini_formids,mini_member,mini_sign_detail,mini_point_detail,mini_subcribute,mini_share_detail),和8個函數,安裝12庫比較簡單,記得把權限全設為所有隻讀僅管理員和創造者修改,如果稍後你發現編出的小程序有各種BUG,那麼可能是12庫少安裝了某個或某些,或漏了權限沒改過來。然後在IDE裡定位到正確的cb部署環境,在IDE文件瀏覽器下點擊各個函數對應的文件夾,右擊部署(包括安裝node modules方式),一一給函數的版本管理->配置處添加Env:cb名的環境變量項,其中syncservice還需要提供內容同步的公號的AppId和AppSecret,adminservice還需要author:你的管理者微信的openid串(可在稍後調出小程序界面後切到/index/index/從ide的console中直接輸出的信息複製得到),miniprogram只需改下utils/config.js裡的env id到正確的cb名,還需要在IDE文件管理器中右擊index/posts/detail打到命令行安裝一個客端模塊:npm install wxa-plugin-canvas --production (設置,項目設置處勾上使用npm模塊),至於源碼用的各種templateid,由於是公共ID,所以不用修改。小程序前後端基本能一起工作起來了,執行一次synservices拉取一些測試文章(根據錯誤添加IP白名單)。

下面,我們來深度定製它:

將8個雲函數合併

由於部署8個雲函數帶來了管理上的困難,也顯得零散,所以我們把它合併成一個叫mini的雲函數中去,思路是先在cloudfunctions下新建mini,把各xxxservices中的config.json,package.json合併去除重複部分放到這,package-lock.json可刪掉,如以下修改:

config.json(json不允許註釋用時需要去掉//後的內容,下同)

{
  "triggers": [
    {
      "name": "myTrigger",
      "type": "timer",
      "config": "0 30 8 * * * *"
    }
  ],
  "permissions": {
    "openapi": [
      "wxacode.getUnlimited",
      "templateMessage.send",
      "templateMessage.addTemplate",
      "templateMessage.deleteTemplate",
      "templateMessage.getTemplateList",
      "templateMessage.getTemplateLibraryById",
      "templateMessage.getTemplateLibraryList",
      "subscribeMessage.send",
      "subscribeMessage.getTemplateList",

      "security.msgSecCheck"   //注意這個
    ]
  }
}

package.json:

{
  "name": "mini",
  "version": "1.0.0",
  "runtime": "Nodejs8.9",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "date-utils": "^1.2.21",
    "request-promise": "^4.2.4",
    "towxml": "^2.1.4",
    "hydrogen-js-sdk": "^2.2.0",
    "request": "^2.88.0",
    "wx-server-sdk": "^1.8.2"   //注意這裡,提到了最高版
  }
}

然後是重點整合部分,把各個index.js整成/mini下總的index.js(login/index.js已被如下融合,除外):

//////以下從各個index.js頭部整合到的全局變量
const cloud = require('wx-server-sdk')
cloud.init({ env: process.env.Env })
const rp = require('request-promise');
const dateUtils = require('date-utils')
const db = cloud.database()
const _ = db.command
const RELEASE_LOG_KEY = 'releaseLogKey'
const APPLY_TEMPLATE_ID = 'DI_AuJDmFXnNuME1vpX_hY2yw1pR6kFXPZ7ZAQ0uLOY'
//收到評論通知
const template = 'cwYd6eGpQ8y7xcVsYWuTSC-FAsAyv5KOAVGvjJIdI9Q'
const Towxml = require('towxml');
const towxml = new Towxml();
const COMMENT_TEMPLATE_ID = 'BxVtrR681icGxgVJOfJ8xdze6TsZiXdSmmUUXnd_9Zg'

//////以下整合的main,用了自建的route分發,實際上就是折分二個return:event,openid

exports.main = (event, context) => {
  console.log(event)
  console.log(context)

  //註釋掉
  //return {
  //  event,
  //  openid: wxContext.OPENID,
  //  appid: wxContext.APPID,
  //  unionid: wxContext.UNIONID,
  //}

  //這句重要
  return router(event)

}

async function router(event) {

  //從main中移到這裡
  const wxContext = cloud.getWXContext()

  //不需要了
  //if (event.action !== 'checkAuthor' && event.action !== 'getLabelList' && event.action !== 'getClassifyList' && event.action !== 'getAdvertConfig') {
  //  let result = await checkAuthor(event)
  //  if (!result) {
  //    return false;
  //  }
  //}

  switch (event.action) {

    //postsservices
    case 'getPostsDetail': {
      return getPostsDetail(event)
    }
    case 'addPostComment': {
      return addPostComment(event)
    }
    case 'addPostChildComment': {
      return addPostChildComment(event)
    }
    case 'addPostCollection': {
      return addPostCollection(event)
    }
    case 'deletePostCollectionOrZan': {
      return deletePostCollectionOrZan(event)
    }
    case 'addPostZan': {
      return addPostZan(event)
    }
    case 'addPostQrCode': {
      return addPostQrCode(event)
    }
    case 'checkPostComment': {
      return checkPostComment(event)
    }

    //按葫蘆造樣,把memberservices,messageservices,adminservices,scheduleservices,syncservices,syncTokenservices其它case部分也弄到這

    //注意這句
    case default : return {openid: wxContext.OPENID}
  }
}

  .....
  //再接下來就是從各個原xxxservice/index.js中移過來不包括開頭變量和main()的代碼的部分,直接複製即可。

然後就可以刪掉所有xxxservices文件夾了,客戶端修求主要集中在utils/api.js和app.js中。將它們改為全部callfunction("mini"),完工!!

將主題集成到首頁

由於主題被做成了一個與文章首頁和我的(後臺)並列的項。不爽。將其歸到首頁“最新,熱門,標籤”後的“主題”文章部分。

index.wxml,從topics.wxml中提取到這裡,介於搜索欄和文章列表之間

<!-- 專題列表 -->
<view class="cu-list menu card-menu margin-top" wx:for="{{classifyList}}" wx:key="idx" wx:for-index="idx" wx:for-item="item"  id="{{item._id}}" data-tname="{{item.value.classifyName}}" bindtap='openTopicPosts'>
    <view class="cu-item">
        <view class="content padding-tb-sm">
            <view>
                <text class="cuIcon-title text-orange "></text>
                {{item.value.classifyName}}
            </view>
            <view class="text-gray text-sm">
                {{item.value.classifyDesc}}
            </view>
        </view>
    </view>
</view>

由於展示是依靠js的,所以index.js:

data: {
  classifyList: [],
  posts: [],
  .....
  navItems: [{ name: '最新', index: 1 }, { name: '熱門', index: 2 }, { name: '標籤', index: 3 }, { name: '專題', index: 4 }],
  .....
}
.....

// 如下設置內容,避免UI塊重疊
tabSelect: async function (e) {
......
  case 1,2,3: {
    that.setData({
      .....
      showHot: false,
      classifyList: [],
      showLabels: false,  //case3時為true
      posts: [],
      ......
    })
  .....
  }

  case 4: {
    that.setData({
      ......
      showHot: false,
      showLabels: false,
      classifyList: [],
      posts: [], 
      .....
    })
        
    let task = that.getClassifyList()
    await task

    break
  }
}

把函數getClassifyList: async function ()從/topics/topics.js中移到這,可把topiclist文件夾也移過來到index/下,修改相關路徑,之後可以刪掉topics文件夾了,

你還可以修改一些硬編碼的東西。

app.json:    "navigationBarTitleText":
syncservice/index.js:          totalComments: 0,//總的點評數 totalVisits: 100,//總的訪問數 totalZans: 50,//總的點贊數
pages/mine/mine.js,申請vip的提示語等

一些未來改進建議:

後臺管理,留言可以加一個是否開啟審核,“程序有一點點小異常,操作失敗啦',這類消息提示可以更精確。因為一般都是數據庫權限或templateid問題。

templateid位置:

adminservice/index.js : APPLY_TEMPLATE_ID
postservices/index.js評論:COMMENT_TEMPLATE_ID
utils/config.js:subcributeTemplateId
messageservice/index.js, template 評論被回覆模板ID
scheduleservice/index.js簽到提醒:SIGN_TEMPLATE_ID
mine/sign/sign.js:tempalteId
pages/mine/mine.js申請vip: tempalteId

整個過程都是在IDE模擬器中不斷的修改,調試,再調試。之後就是提交體驗了,提交體驗版本然後微信瀏覽基本接近以發佈後效果而IDE中的模擬器較之有一些效果體現不出來,還有,審核的時候有可能會說你動態網站不能通過很奇葩,那麼以cloudbase為後端意義何在?

下文我們將用fodi分開前後端的方式來劃分onemanager將它做成miniblog小程序的內容源或者給miniblog直接弄一個PC網站前端和pc網站後端寫作模塊。其實小程序和onemanger非常像。因為後者也是雲函數為後端,只不過一個定位網站前端,一個定位小程序前端。後端都是api服務。mini blog for wechat是直接利用cloudbase sdk調用雲函,天然鑑權請求,而onemanager的前端是利用普通網站提交,基於url route提交請求。fodi前後端利用更高級的ajax。這三者都有相似之處,其實cloudbase也可用於google flatter和mobile apps。


(此處不設回覆,掃碼到微信參與留言,或直接點擊到原文)

qrcode.png

Leave a Reply

Your email address will not be published. Required fields are marked *