10分钟

任务 3 编写云函数逻辑

任务目的

编写补充云函数逻辑,并添加相关配置文件。

任务步骤

1.下载并解压代码资源

下载代码资源,下载地址为 https://course-public-resources-1252758970.cos.ap-chengdu.myqcloud.com/%E5%AE%9E%E6%88%98%E8%AF%BE/%E5%9F%BA%E4%BA%8E%E8%85%BE%E8%AE%AF%E4%BA%91%E4%BA%91%E5%87%BD%E6%95%B0%E5%BF%AB%E9%80%9F%E6%90%AD%E5%BB%BA%E7%96%AB%E6%83%85%E5%9C%B0%E5%9B%BE/yiqing.rar ,将地址复制粘贴在浏览器中,浏览器会自动下载。

下载后格式为 rar 的压缩文件,文件中包含文件如图所示。文件具体作用后文会进行解释。

代码资源文件

2.替换 index.js 内容

复制 index.js 文件中内容到云函数中的 index.js,注意:不可直接替换 index.js 文件,需要将压缩文件中的 index.js 中的代码复制至云函数的 index.js 。

'use strict';
const axios = require('axios');
const fs = require('fs');
const path = require('path');
const render = require('./render');

exports.main_handler = async (event, context, callback) => {
  // 1. 接受链接上的query参数api,用于判断是输出html,还是输出数据
  let api = event.queryString.api || false;

  // 2. 请求疫情数据
  let result = await axios.get(
    `https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5`
  );

  // 3. 中国地图数据
  let china_map = JSON.stringify(require('./china.json'));

  // 4. 解析并渲染 html 页面
  let html = fs.readFileSync(path.resolve(__dirname, './index.html'), {
    encoding: 'utf-8'
  });
  html = render(html, { disease_data: result.data.data, china_map });

  if (!api) {
    return {
      isBase64Encoded: false,
      statusCode: 200,
      headers: { 'Content-Type': 'text/html' },
      body: html
    };
  }
  
  // 5. 输出疫情数据
  return {
    isBase64Encoded: false,
    statusCode: 200,
    headers: { 'Content-Type': 'application/json' },
    body: result.data.data
  };
};

index.js 文件首先引入依赖。在云函数主体中,首先从云函数参数中判断输出html还是数据,然后请求疫情数据,本数据来自腾讯接口,返回 json 数据,然后获取中国地图数据,中国地图数据在下一步中放入云函数文件夹。接着将中国地图数据渲染成 html 页面。最后通过判断决定输出的是 json 数据或是 html 页面。具体步骤解析可参考代码中注释。

3.添加其他数据文件

将压缩文件夹中的其他文件添加到云函数文件夹中。

代码资源文件

其中 china.json 是 ECharts 生成地图的模板文件。具体写法可以参考ECharts文档进行编写,本实验无需改写。

index.html 是疫情地图的前端html页面、样式及Javascript脚本。Javascript重要部分如下所示。

let dom = document.getElementById('container');
let myChart = echarts.init(dom);
let app = {};
myChart.showLoading();

// 1. 填充地图模板变量

let china_map = ${china_map} || null;

function updateMap() {
  $.get('?api=true', function(disease_data) {
    // 2. 填充确诊、疑似、治愈、死亡数据

    let chinaTotal = disease_data.chinaTotal;
    let chinaAdd = disease_data.chinaAdd;

    $('.confirm .add span').html(`+${chinaAdd.confirm}`);
    $('.suspect .add span').html(`+${chinaAdd.suspect}`);
    $('.cure .add span').html(`+${chinaAdd.heal}`);
    $('.dead .add span').html(`+${chinaAdd.dead}`);

    $('.confirm .number').html(`${chinaTotal.confirm}`);
    $('.suspect .number').html(`${chinaTotal.suspect}`);
    $('.cure .number').html(`${chinaTotal.heal}`);
    $('.dead .number').html(`${chinaTotal.dead}`);

    // 3. 处理疫情地图中的确诊数据格式
    /**
     * 需要 {name: 'xxx', value: 'xxx'} 这样的格式
     */

    let province = disease_data.areaTree[0].children;
    let confirmData = province.map(function(item) {
      return {
        name: item.name,
        value: item.total.confirm
      };
    });

    myChart.hideLoading();

    echarts.registerMap('China', china_map);
    let option = {
      // 4. 给疫情地图添加标题

      title: {
          text: '疫情地图',
          subtext: `${disease_data.lastUpdateTime} 更新`,
          left: 'right'
      },

      tooltip: {
        trigger: 'item',
        showDelay: 0,
        transitionDuration: 0.2,
        formatter: function(params) {
          var value = (params.value + '').split('.');
          value = value[0].replace(
            /(\d{1,3})(?=(?:\d{3})+(?!\d))/g,
            '$1,'
          );
          return params.seriesName + '<br/>' + params.name + ': ' + value;
        }
      },
      visualMap: {
        type: 'piecewise',
        left: 'right',
        // 5. 添加数据分段
        pieces: [
            { min: 10000, label: '10000人及以上' },
            { min: 1000, max: 9999, label: '1000-9999人' },
            { min: 500, max: 999, label: '500-999人' },
            { min: 100, max: 499, label: '100-499人' },
            { min: 10, max: 99, label: '10-99人' },
            { min: 1, max: 9, label: '1-9人' }
        ],
        showLabel: true,
        itemHeight: 20,
        itemWidth: 10,
        itemGap: 5,
        itemSymbol: 'rect',
        inRange: {
          color: [
            '#FFEFD7',
            '#FFD2A0',
            '#FE8664',
            '#E64B47',
            '#C91014',
            '#9C0A0D'
          ]
        },
        text: ['最高', '最低']
      },
      // 6. 填写疫情地图的数据及悬浮框的展示信息
      series: [
        {
          name: '确诊病例',
          type: 'map',
          roam: true,
          map: 'china',
          label: {
            show: true
          },
          emphasis: {
            label: {
              show: true
            }
          },
          data: confirmData
        }
      ];
    };

    myChart.setOption(option);

    if (option && typeof option === 'object') {
      myChart.setOption(option, true);
    }
  });
}

updateMap();

// 7. 定时拉取
setInterval(function() {
  updateMap();
}, 60000);

脚本中最重要的是updateMap()函数,这个函数首先填充地图模板变量,然后填充确诊、疑似、治愈、死亡的数据,接下来将数据转化为所需的格式,添加标题,添加数据分段,填写疫情地图的数据集悬浮框。最后再运行时调用这个函数,并设置定时拉取信息即可。此处设置的时间为1分钟。具体可参考代码中注释。

package.json 和 package-lock.json 是 Node.js 的配置文件,包含项目的信息和项目所需依赖,后期会根据配置文件安装依赖。render.js 包含一个方法,在 index.js 里会引用到其中的方法。

4.安装依赖

在 yiqing 文件夹点击右键,点击 Reveal in File Explorer,进入 yiqing 文件夹,按住 Shift 点击有右键,点击“在此处打开 Powershell 窗口”。

打开 Powershell

使用 “npm i” 命令安装所需依赖

安装所需依赖

5.上传云函数

点击本地函数的右侧“上传到云端”的按钮

上传云函数

选择所属地域,这里选择广州

选择所属地域

最后选择命名空间即可上传云函数。

选择命名空间

看到控制台显示上传日志,说明上传成功。

上传日志

如果第一次使用云函数需要在访问管理中完成授权,登录腾讯云控制台搜索“云函数”,点击【立即使用】,会出现服务授权的弹窗,点击【前往访问管理】按钮

服务授权提示

进入【服务授权】页面,点击【同意授权】按钮即可。

服务授权页面

如果没有进行授权,上传云函数会出现授权角色不存在的警告,而无法上传。

未授权无法上传云函数

如果出现这个问题,也可以将template.yaml文件中的Role字段删除,如果此字段缺省,将为函数创建一个默认的角色 QCS_SCFExcuteRole。

template.yaml